Rev 1963 | Rev 2004 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1963 | Rev 1986 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2006-2009 Red Hat Inc. |
2 | * Copyright (c) 2006-2009 Red Hat Inc. |
3 | * Copyright (c) 2006-2008 Intel Corporation |
3 | * Copyright (c) 2006-2008 Intel Corporation |
4 | * Copyright (c) 2007 Dave Airlie |
4 | * Copyright (c) 2007 Dave Airlie |
5 | * |
5 | * |
6 | * DRM framebuffer helper functions |
6 | * DRM framebuffer helper functions |
7 | * |
7 | * |
8 | * Permission to use, copy, modify, distribute, and sell this software and its |
8 | * Permission to use, copy, modify, distribute, and sell this software and its |
9 | * documentation for any purpose is hereby granted without fee, provided that |
9 | * documentation for any purpose is hereby granted without fee, provided that |
10 | * the above copyright notice appear in all copies and that both that copyright |
10 | * the above copyright notice appear in all copies and that both that copyright |
11 | * notice and this permission notice appear in supporting documentation, and |
11 | * notice and this permission notice appear in supporting documentation, and |
12 | * that the name of the copyright holders not be used in advertising or |
12 | * that the name of the copyright holders not be used in advertising or |
13 | * publicity pertaining to distribution of the software without specific, |
13 | * publicity pertaining to distribution of the software without specific, |
14 | * written prior permission. The copyright holders make no representations |
14 | * written prior permission. The copyright holders make no representations |
15 | * about the suitability of this software for any purpose. It is provided "as |
15 | * about the suitability of this software for any purpose. It is provided "as |
16 | * is" without express or implied warranty. |
16 | * is" without express or implied warranty. |
17 | * |
17 | * |
18 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
18 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
19 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
19 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
20 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
20 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
21 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
21 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
22 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
22 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
23 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
23 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
24 | * OF THIS SOFTWARE. |
24 | * OF THIS SOFTWARE. |
25 | * |
25 | * |
26 | * Authors: |
26 | * Authors: |
27 | * Dave Airlie |
27 | * Dave Airlie |
28 | * Jesse Barnes |
28 | * Jesse Barnes |
29 | */ |
29 | */ |
30 | #include |
30 | #include |
31 | #include |
31 | #include |
32 | #include |
32 | #include |
33 | #include |
33 | #include |
34 | #include "drmP.h" |
34 | #include "drmP.h" |
35 | #include "drm_crtc.h" |
35 | #include "drm_crtc.h" |
36 | #include "drm_fb_helper.h" |
36 | #include "drm_fb_helper.h" |
37 | #include "drm_crtc_helper.h" |
37 | #include "drm_crtc_helper.h" |
38 | 38 | ||
39 | MODULE_AUTHOR("David Airlie, Jesse Barnes"); |
39 | MODULE_AUTHOR("David Airlie, Jesse Barnes"); |
40 | MODULE_DESCRIPTION("DRM KMS helper"); |
40 | MODULE_DESCRIPTION("DRM KMS helper"); |
41 | MODULE_LICENSE("GPL and additional rights"); |
41 | MODULE_LICENSE("GPL and additional rights"); |
42 | 42 | ||
43 | static LIST_HEAD(kernel_fb_helper_list); |
43 | static LIST_HEAD(kernel_fb_helper_list); |
44 | 44 | ||
45 | /* simple single crtc case helper function */ |
45 | /* simple single crtc case helper function */ |
46 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
46 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
47 | { |
47 | { |
48 | struct drm_device *dev = fb_helper->dev; |
48 | struct drm_device *dev = fb_helper->dev; |
49 | struct drm_connector *connector; |
49 | struct drm_connector *connector; |
50 | int i; |
50 | int i; |
51 | 51 | ||
52 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
52 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
53 | struct drm_fb_helper_connector *fb_helper_connector; |
53 | struct drm_fb_helper_connector *fb_helper_connector; |
54 | 54 | ||
55 | fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); |
55 | fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); |
56 | if (!fb_helper_connector) |
56 | if (!fb_helper_connector) |
57 | goto fail; |
57 | goto fail; |
58 | 58 | ||
59 | fb_helper_connector->connector = connector; |
59 | fb_helper_connector->connector = connector; |
60 | fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; |
60 | fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; |
61 | } |
61 | } |
62 | return 0; |
62 | return 0; |
63 | fail: |
63 | fail: |
64 | for (i = 0; i < fb_helper->connector_count; i++) { |
64 | for (i = 0; i < fb_helper->connector_count; i++) { |
65 | kfree(fb_helper->connector_info[i]); |
65 | kfree(fb_helper->connector_info[i]); |
66 | fb_helper->connector_info[i] = NULL; |
66 | fb_helper->connector_info[i] = NULL; |
67 | } |
67 | } |
68 | fb_helper->connector_count = 0; |
68 | fb_helper->connector_count = 0; |
69 | return -ENOMEM; |
69 | return -ENOMEM; |
70 | } |
70 | } |
71 | EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); |
71 | EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); |
72 | 72 | ||
73 | static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) |
73 | static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) |
74 | { |
74 | { |
75 | uint16_t *r_base, *g_base, *b_base; |
75 | uint16_t *r_base, *g_base, *b_base; |
76 | int i; |
76 | int i; |
77 | 77 | ||
78 | r_base = crtc->gamma_store; |
78 | r_base = crtc->gamma_store; |
79 | g_base = r_base + crtc->gamma_size; |
79 | g_base = r_base + crtc->gamma_size; |
80 | b_base = g_base + crtc->gamma_size; |
80 | b_base = g_base + crtc->gamma_size; |
81 | 81 | ||
82 | for (i = 0; i < crtc->gamma_size; i++) |
82 | for (i = 0; i < crtc->gamma_size; i++) |
83 | helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i); |
83 | helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i); |
84 | } |
84 | } |
85 | 85 | ||
86 | static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) |
86 | static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) |
87 | { |
87 | { |
88 | uint16_t *r_base, *g_base, *b_base; |
88 | uint16_t *r_base, *g_base, *b_base; |
89 | 89 | ||
90 | r_base = crtc->gamma_store; |
90 | r_base = crtc->gamma_store; |
91 | g_base = r_base + crtc->gamma_size; |
91 | g_base = r_base + crtc->gamma_size; |
92 | b_base = g_base + crtc->gamma_size; |
92 | b_base = g_base + crtc->gamma_size; |
93 | 93 | ||
94 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); |
94 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); |
95 | } |
95 | } |
96 | 96 | ||
97 | 97 | ||
98 | static void drm_fb_helper_on(struct fb_info *info) |
98 | static void drm_fb_helper_on(struct fb_info *info) |
99 | { |
99 | { |
100 | struct drm_fb_helper *fb_helper = info->par; |
100 | struct drm_fb_helper *fb_helper = info->par; |
101 | struct drm_device *dev = fb_helper->dev; |
101 | struct drm_device *dev = fb_helper->dev; |
102 | struct drm_crtc *crtc; |
102 | struct drm_crtc *crtc; |
103 | struct drm_crtc_helper_funcs *crtc_funcs; |
103 | struct drm_crtc_helper_funcs *crtc_funcs; |
104 | struct drm_connector *connector; |
104 | struct drm_connector *connector; |
105 | struct drm_encoder *encoder; |
105 | struct drm_encoder *encoder; |
106 | int i, j; |
106 | int i, j; |
107 | 107 | ||
108 | /* |
108 | /* |
109 | * For each CRTC in this fb, turn the crtc on then, |
109 | * For each CRTC in this fb, turn the crtc on then, |
110 | * find all associated encoders and turn them on. |
110 | * find all associated encoders and turn them on. |
111 | */ |
111 | */ |
112 | mutex_lock(&dev->mode_config.mutex); |
112 | mutex_lock(&dev->mode_config.mutex); |
113 | for (i = 0; i < fb_helper->crtc_count; i++) { |
113 | for (i = 0; i < fb_helper->crtc_count; i++) { |
114 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
114 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
115 | crtc_funcs = crtc->helper_private; |
115 | crtc_funcs = crtc->helper_private; |
116 | 116 | ||
117 | if (!crtc->enabled) |
117 | if (!crtc->enabled) |
118 | continue; |
118 | continue; |
119 | 119 | ||
120 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); |
120 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); |
121 | 121 | ||
122 | /* Walk the connectors & encoders on this fb turning them on */ |
122 | /* Walk the connectors & encoders on this fb turning them on */ |
123 | for (j = 0; j < fb_helper->connector_count; j++) { |
123 | for (j = 0; j < fb_helper->connector_count; j++) { |
124 | connector = fb_helper->connector_info[j]->connector; |
124 | connector = fb_helper->connector_info[j]->connector; |
125 | connector->dpms = DRM_MODE_DPMS_ON; |
125 | connector->dpms = DRM_MODE_DPMS_ON; |
126 | drm_connector_property_set_value(connector, |
126 | drm_connector_property_set_value(connector, |
127 | dev->mode_config.dpms_property, |
127 | dev->mode_config.dpms_property, |
128 | DRM_MODE_DPMS_ON); |
128 | DRM_MODE_DPMS_ON); |
129 | } |
129 | } |
130 | /* Found a CRTC on this fb, now find encoders */ |
130 | /* Found a CRTC on this fb, now find encoders */ |
131 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
131 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
132 | if (encoder->crtc == crtc) { |
132 | if (encoder->crtc == crtc) { |
133 | struct drm_encoder_helper_funcs *encoder_funcs; |
133 | struct drm_encoder_helper_funcs *encoder_funcs; |
134 | 134 | ||
135 | encoder_funcs = encoder->helper_private; |
135 | encoder_funcs = encoder->helper_private; |
136 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); |
136 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); |
137 | } |
137 | } |
138 | } |
138 | } |
139 | } |
139 | } |
140 | mutex_unlock(&dev->mode_config.mutex); |
140 | mutex_unlock(&dev->mode_config.mutex); |
141 | } |
141 | } |
142 | 142 | ||
143 | static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) |
143 | static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) |
144 | { |
144 | { |
145 | struct drm_fb_helper *fb_helper = info->par; |
145 | struct drm_fb_helper *fb_helper = info->par; |
146 | struct drm_device *dev = fb_helper->dev; |
146 | struct drm_device *dev = fb_helper->dev; |
147 | struct drm_crtc *crtc; |
147 | struct drm_crtc *crtc; |
148 | struct drm_crtc_helper_funcs *crtc_funcs; |
148 | struct drm_crtc_helper_funcs *crtc_funcs; |
149 | struct drm_connector *connector; |
149 | struct drm_connector *connector; |
150 | struct drm_encoder *encoder; |
150 | struct drm_encoder *encoder; |
151 | int i, j; |
151 | int i, j; |
152 | 152 | ||
153 | /* |
153 | /* |
154 | * For each CRTC in this fb, find all associated encoders |
154 | * For each CRTC in this fb, find all associated encoders |
155 | * and turn them off, then turn off the CRTC. |
155 | * and turn them off, then turn off the CRTC. |
156 | */ |
156 | */ |
157 | mutex_lock(&dev->mode_config.mutex); |
157 | mutex_lock(&dev->mode_config.mutex); |
158 | for (i = 0; i < fb_helper->crtc_count; i++) { |
158 | for (i = 0; i < fb_helper->crtc_count; i++) { |
159 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
159 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
160 | crtc_funcs = crtc->helper_private; |
160 | crtc_funcs = crtc->helper_private; |
161 | 161 | ||
162 | if (!crtc->enabled) |
162 | if (!crtc->enabled) |
163 | continue; |
163 | continue; |
164 | 164 | ||
165 | /* Walk the connectors on this fb and mark them off */ |
165 | /* Walk the connectors on this fb and mark them off */ |
166 | for (j = 0; j < fb_helper->connector_count; j++) { |
166 | for (j = 0; j < fb_helper->connector_count; j++) { |
167 | connector = fb_helper->connector_info[j]->connector; |
167 | connector = fb_helper->connector_info[j]->connector; |
168 | connector->dpms = dpms_mode; |
168 | connector->dpms = dpms_mode; |
169 | drm_connector_property_set_value(connector, |
169 | drm_connector_property_set_value(connector, |
170 | dev->mode_config.dpms_property, |
170 | dev->mode_config.dpms_property, |
171 | dpms_mode); |
171 | dpms_mode); |
172 | } |
172 | } |
173 | /* Found a CRTC on this fb, now find encoders */ |
173 | /* Found a CRTC on this fb, now find encoders */ |
174 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
174 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
175 | if (encoder->crtc == crtc) { |
175 | if (encoder->crtc == crtc) { |
176 | struct drm_encoder_helper_funcs *encoder_funcs; |
176 | struct drm_encoder_helper_funcs *encoder_funcs; |
177 | 177 | ||
178 | encoder_funcs = encoder->helper_private; |
178 | encoder_funcs = encoder->helper_private; |
179 | encoder_funcs->dpms(encoder, dpms_mode); |
179 | encoder_funcs->dpms(encoder, dpms_mode); |
180 | } |
180 | } |
181 | } |
181 | } |
182 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); |
182 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); |
183 | } |
183 | } |
184 | mutex_unlock(&dev->mode_config.mutex); |
184 | mutex_unlock(&dev->mode_config.mutex); |
185 | } |
185 | } |
186 | 186 | ||
187 | int drm_fb_helper_blank(int blank, struct fb_info *info) |
187 | int drm_fb_helper_blank(int blank, struct fb_info *info) |
188 | { |
188 | { |
189 | switch (blank) { |
189 | switch (blank) { |
190 | /* Display: On; HSync: On, VSync: On */ |
190 | /* Display: On; HSync: On, VSync: On */ |
191 | case FB_BLANK_UNBLANK: |
191 | case FB_BLANK_UNBLANK: |
192 | drm_fb_helper_on(info); |
192 | drm_fb_helper_on(info); |
193 | break; |
193 | break; |
194 | /* Display: Off; HSync: On, VSync: On */ |
194 | /* Display: Off; HSync: On, VSync: On */ |
195 | case FB_BLANK_NORMAL: |
195 | case FB_BLANK_NORMAL: |
196 | drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); |
196 | drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); |
197 | break; |
197 | break; |
198 | /* Display: Off; HSync: Off, VSync: On */ |
198 | /* Display: Off; HSync: Off, VSync: On */ |
199 | case FB_BLANK_HSYNC_SUSPEND: |
199 | case FB_BLANK_HSYNC_SUSPEND: |
200 | drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); |
200 | drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); |
201 | break; |
201 | break; |
202 | /* Display: Off; HSync: On, VSync: Off */ |
202 | /* Display: Off; HSync: On, VSync: Off */ |
203 | case FB_BLANK_VSYNC_SUSPEND: |
203 | case FB_BLANK_VSYNC_SUSPEND: |
204 | drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND); |
204 | drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND); |
205 | break; |
205 | break; |
206 | /* Display: Off; HSync: Off, VSync: Off */ |
206 | /* Display: Off; HSync: Off, VSync: Off */ |
207 | case FB_BLANK_POWERDOWN: |
207 | case FB_BLANK_POWERDOWN: |
208 | drm_fb_helper_off(info, DRM_MODE_DPMS_OFF); |
208 | drm_fb_helper_off(info, DRM_MODE_DPMS_OFF); |
209 | break; |
209 | break; |
210 | } |
210 | } |
211 | return 0; |
211 | return 0; |
212 | } |
212 | } |
213 | EXPORT_SYMBOL(drm_fb_helper_blank); |
213 | EXPORT_SYMBOL(drm_fb_helper_blank); |
214 | 214 | ||
215 | static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) |
215 | static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) |
216 | { |
216 | { |
217 | int i; |
217 | int i; |
218 | 218 | ||
219 | for (i = 0; i < helper->connector_count; i++) |
219 | for (i = 0; i < helper->connector_count; i++) |
220 | kfree(helper->connector_info[i]); |
220 | kfree(helper->connector_info[i]); |
221 | kfree(helper->connector_info); |
221 | kfree(helper->connector_info); |
222 | for (i = 0; i < helper->crtc_count; i++) |
222 | for (i = 0; i < helper->crtc_count; i++) |
223 | kfree(helper->crtc_info[i].mode_set.connectors); |
223 | kfree(helper->crtc_info[i].mode_set.connectors); |
224 | kfree(helper->crtc_info); |
224 | kfree(helper->crtc_info); |
225 | } |
225 | } |
226 | 226 | ||
227 | int drm_fb_helper_init(struct drm_device *dev, |
227 | int drm_fb_helper_init(struct drm_device *dev, |
228 | struct drm_fb_helper *fb_helper, |
228 | struct drm_fb_helper *fb_helper, |
229 | int crtc_count, int max_conn_count) |
229 | int crtc_count, int max_conn_count) |
230 | { |
230 | { |
231 | struct drm_crtc *crtc; |
231 | struct drm_crtc *crtc; |
232 | int ret = 0; |
232 | int ret = 0; |
233 | int i; |
233 | int i; |
234 | 234 | ||
235 | fb_helper->dev = dev; |
235 | fb_helper->dev = dev; |
236 | 236 | ||
237 | INIT_LIST_HEAD(&fb_helper->kernel_fb_list); |
237 | INIT_LIST_HEAD(&fb_helper->kernel_fb_list); |
238 | 238 | ||
239 | fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); |
239 | fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); |
240 | if (!fb_helper->crtc_info) |
240 | if (!fb_helper->crtc_info) |
241 | return -ENOMEM; |
241 | return -ENOMEM; |
242 | 242 | ||
243 | fb_helper->crtc_count = crtc_count; |
243 | fb_helper->crtc_count = crtc_count; |
244 | fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); |
244 | fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); |
245 | if (!fb_helper->connector_info) { |
245 | if (!fb_helper->connector_info) { |
246 | kfree(fb_helper->crtc_info); |
246 | kfree(fb_helper->crtc_info); |
247 | return -ENOMEM; |
247 | return -ENOMEM; |
248 | } |
248 | } |
249 | fb_helper->connector_count = 0; |
249 | fb_helper->connector_count = 0; |
250 | 250 | ||
251 | for (i = 0; i < crtc_count; i++) { |
251 | for (i = 0; i < crtc_count; i++) { |
252 | fb_helper->crtc_info[i].mode_set.connectors = |
252 | fb_helper->crtc_info[i].mode_set.connectors = |
253 | kcalloc(max_conn_count, |
253 | kcalloc(max_conn_count, |
254 | sizeof(struct drm_connector *), |
254 | sizeof(struct drm_connector *), |
255 | GFP_KERNEL); |
255 | GFP_KERNEL); |
256 | 256 | ||
257 | if (!fb_helper->crtc_info[i].mode_set.connectors) { |
257 | if (!fb_helper->crtc_info[i].mode_set.connectors) { |
258 | ret = -ENOMEM; |
258 | ret = -ENOMEM; |
259 | goto out_free; |
259 | goto out_free; |
260 | } |
260 | } |
261 | fb_helper->crtc_info[i].mode_set.num_connectors = 0; |
261 | fb_helper->crtc_info[i].mode_set.num_connectors = 0; |
262 | } |
262 | } |
263 | 263 | ||
264 | i = 0; |
264 | i = 0; |
265 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
265 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
266 | fb_helper->crtc_info[i].crtc_id = crtc->base.id; |
266 | fb_helper->crtc_info[i].crtc_id = crtc->base.id; |
267 | fb_helper->crtc_info[i].mode_set.crtc = crtc; |
267 | fb_helper->crtc_info[i].mode_set.crtc = crtc; |
268 | i++; |
268 | i++; |
269 | } |
269 | } |
270 | fb_helper->conn_limit = max_conn_count; |
270 | fb_helper->conn_limit = max_conn_count; |
271 | return 0; |
271 | return 0; |
272 | out_free: |
272 | out_free: |
273 | drm_fb_helper_crtc_free(fb_helper); |
273 | drm_fb_helper_crtc_free(fb_helper); |
274 | return -ENOMEM; |
274 | return -ENOMEM; |
275 | } |
275 | } |
276 | EXPORT_SYMBOL(drm_fb_helper_init); |
276 | EXPORT_SYMBOL(drm_fb_helper_init); |
277 | 277 | ||
278 | static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, |
278 | static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, |
279 | u16 blue, u16 regno, struct fb_info *info) |
279 | u16 blue, u16 regno, struct fb_info *info) |
280 | { |
280 | { |
281 | struct drm_fb_helper *fb_helper = info->par; |
281 | struct drm_fb_helper *fb_helper = info->par; |
282 | struct drm_framebuffer *fb = fb_helper->fb; |
282 | struct drm_framebuffer *fb = fb_helper->fb; |
283 | int pindex; |
283 | int pindex; |
284 | 284 | ||
285 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { |
285 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { |
286 | u32 *palette; |
286 | u32 *palette; |
287 | u32 value; |
287 | u32 value; |
288 | /* place color in psuedopalette */ |
288 | /* place color in psuedopalette */ |
289 | if (regno > 16) |
289 | if (regno > 16) |
290 | return -EINVAL; |
290 | return -EINVAL; |
291 | palette = (u32 *)info->pseudo_palette; |
291 | palette = (u32 *)info->pseudo_palette; |
292 | red >>= (16 - info->var.red.length); |
292 | red >>= (16 - info->var.red.length); |
293 | green >>= (16 - info->var.green.length); |
293 | green >>= (16 - info->var.green.length); |
294 | blue >>= (16 - info->var.blue.length); |
294 | blue >>= (16 - info->var.blue.length); |
295 | value = (red << info->var.red.offset) | |
295 | value = (red << info->var.red.offset) | |
296 | (green << info->var.green.offset) | |
296 | (green << info->var.green.offset) | |
297 | (blue << info->var.blue.offset); |
297 | (blue << info->var.blue.offset); |
298 | if (info->var.transp.length > 0) { |
298 | if (info->var.transp.length > 0) { |
299 | u32 mask = (1 << info->var.transp.length) - 1; |
299 | u32 mask = (1 << info->var.transp.length) - 1; |
300 | mask <<= info->var.transp.offset; |
300 | mask <<= info->var.transp.offset; |
301 | value |= mask; |
301 | value |= mask; |
302 | } |
302 | } |
303 | palette[regno] = value; |
303 | palette[regno] = value; |
304 | return 0; |
304 | return 0; |
305 | } |
305 | } |
306 | 306 | ||
307 | pindex = regno; |
307 | pindex = regno; |
308 | 308 | ||
309 | if (fb->bits_per_pixel == 16) { |
309 | if (fb->bits_per_pixel == 16) { |
310 | pindex = regno << 3; |
310 | pindex = regno << 3; |
311 | 311 | ||
312 | if (fb->depth == 16 && regno > 63) |
312 | if (fb->depth == 16 && regno > 63) |
313 | return -EINVAL; |
313 | return -EINVAL; |
314 | if (fb->depth == 15 && regno > 31) |
314 | if (fb->depth == 15 && regno > 31) |
315 | return -EINVAL; |
315 | return -EINVAL; |
316 | 316 | ||
317 | if (fb->depth == 16) { |
317 | if (fb->depth == 16) { |
318 | u16 r, g, b; |
318 | u16 r, g, b; |
319 | int i; |
319 | int i; |
320 | if (regno < 32) { |
320 | if (regno < 32) { |
321 | for (i = 0; i < 8; i++) |
321 | for (i = 0; i < 8; i++) |
322 | fb_helper->funcs->gamma_set(crtc, red, |
322 | fb_helper->funcs->gamma_set(crtc, red, |
323 | green, blue, pindex + i); |
323 | green, blue, pindex + i); |
324 | } |
324 | } |
325 | 325 | ||
326 | fb_helper->funcs->gamma_get(crtc, &r, |
326 | fb_helper->funcs->gamma_get(crtc, &r, |
327 | &g, &b, |
327 | &g, &b, |
328 | pindex >> 1); |
328 | pindex >> 1); |
329 | 329 | ||
330 | for (i = 0; i < 4; i++) |
330 | for (i = 0; i < 4; i++) |
331 | fb_helper->funcs->gamma_set(crtc, r, |
331 | fb_helper->funcs->gamma_set(crtc, r, |
332 | green, b, |
332 | green, b, |
333 | (pindex >> 1) + i); |
333 | (pindex >> 1) + i); |
334 | } |
334 | } |
335 | } |
335 | } |
336 | 336 | ||
337 | if (fb->depth != 16) |
337 | if (fb->depth != 16) |
338 | fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); |
338 | fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); |
339 | return 0; |
339 | return 0; |
340 | } |
340 | } |
341 | 341 | ||
342 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) |
342 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) |
343 | { |
343 | { |
344 | struct drm_fb_helper *fb_helper = info->par; |
344 | struct drm_fb_helper *fb_helper = info->par; |
345 | struct drm_crtc_helper_funcs *crtc_funcs; |
345 | struct drm_crtc_helper_funcs *crtc_funcs; |
346 | u16 *red, *green, *blue, *transp; |
346 | u16 *red, *green, *blue, *transp; |
347 | struct drm_crtc *crtc; |
347 | struct drm_crtc *crtc; |
348 | int i, j, rc = 0; |
348 | int i, j, rc = 0; |
349 | int start; |
349 | int start; |
350 | 350 | ||
351 | for (i = 0; i < fb_helper->crtc_count; i++) { |
351 | for (i = 0; i < fb_helper->crtc_count; i++) { |
352 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
352 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
353 | crtc_funcs = crtc->helper_private; |
353 | crtc_funcs = crtc->helper_private; |
354 | 354 | ||
355 | red = cmap->red; |
355 | red = cmap->red; |
356 | green = cmap->green; |
356 | green = cmap->green; |
357 | blue = cmap->blue; |
357 | blue = cmap->blue; |
358 | transp = cmap->transp; |
358 | transp = cmap->transp; |
359 | start = cmap->start; |
359 | start = cmap->start; |
360 | 360 | ||
361 | for (j = 0; j < cmap->len; j++) { |
361 | for (j = 0; j < cmap->len; j++) { |
362 | u16 hred, hgreen, hblue, htransp = 0xffff; |
362 | u16 hred, hgreen, hblue, htransp = 0xffff; |
363 | 363 | ||
364 | hred = *red++; |
364 | hred = *red++; |
365 | hgreen = *green++; |
365 | hgreen = *green++; |
366 | hblue = *blue++; |
366 | hblue = *blue++; |
367 | 367 | ||
368 | if (transp) |
368 | if (transp) |
369 | htransp = *transp++; |
369 | htransp = *transp++; |
370 | 370 | ||
371 | rc = setcolreg(crtc, hred, hgreen, hblue, start++, info); |
371 | rc = setcolreg(crtc, hred, hgreen, hblue, start++, info); |
372 | if (rc) |
372 | if (rc) |
373 | return rc; |
373 | return rc; |
374 | } |
374 | } |
375 | crtc_funcs->load_lut(crtc); |
375 | crtc_funcs->load_lut(crtc); |
376 | } |
376 | } |
377 | return rc; |
377 | return rc; |
378 | } |
378 | } |
379 | EXPORT_SYMBOL(drm_fb_helper_setcmap); |
379 | EXPORT_SYMBOL(drm_fb_helper_setcmap); |
380 | 380 | ||
381 | int drm_fb_helper_check_var(struct fb_var_screeninfo *var, |
381 | int drm_fb_helper_check_var(struct fb_var_screeninfo *var, |
382 | struct fb_info *info) |
382 | struct fb_info *info) |
383 | { |
383 | { |
384 | struct drm_fb_helper *fb_helper = info->par; |
384 | struct drm_fb_helper *fb_helper = info->par; |
385 | struct drm_framebuffer *fb = fb_helper->fb; |
385 | struct drm_framebuffer *fb = fb_helper->fb; |
386 | int depth; |
386 | int depth; |
387 | 387 | ||
388 | if (var->pixclock != 0 || in_dbg_master()) |
388 | if (var->pixclock != 0 || in_dbg_master()) |
389 | return -EINVAL; |
389 | return -EINVAL; |
390 | 390 | ||
391 | /* Need to resize the fb object !!! */ |
391 | /* Need to resize the fb object !!! */ |
392 | if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) { |
392 | if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) { |
393 | DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " |
393 | DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " |
394 | "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, |
394 | "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, |
395 | fb->width, fb->height, fb->bits_per_pixel); |
395 | fb->width, fb->height, fb->bits_per_pixel); |
396 | return -EINVAL; |
396 | return -EINVAL; |
397 | } |
397 | } |
398 | 398 | ||
399 | switch (var->bits_per_pixel) { |
399 | switch (var->bits_per_pixel) { |
400 | case 16: |
400 | case 16: |
401 | depth = (var->green.length == 6) ? 16 : 15; |
401 | depth = (var->green.length == 6) ? 16 : 15; |
402 | break; |
402 | break; |
403 | case 32: |
403 | case 32: |
404 | depth = (var->transp.length > 0) ? 32 : 24; |
404 | depth = (var->transp.length > 0) ? 32 : 24; |
405 | break; |
405 | break; |
406 | default: |
406 | default: |
407 | depth = var->bits_per_pixel; |
407 | depth = var->bits_per_pixel; |
408 | break; |
408 | break; |
409 | } |
409 | } |
410 | 410 | ||
411 | switch (depth) { |
411 | switch (depth) { |
412 | case 8: |
412 | case 8: |
413 | var->red.offset = 0; |
413 | var->red.offset = 0; |
414 | var->green.offset = 0; |
414 | var->green.offset = 0; |
415 | var->blue.offset = 0; |
415 | var->blue.offset = 0; |
416 | var->red.length = 8; |
416 | var->red.length = 8; |
417 | var->green.length = 8; |
417 | var->green.length = 8; |
418 | var->blue.length = 8; |
418 | var->blue.length = 8; |
419 | var->transp.length = 0; |
419 | var->transp.length = 0; |
420 | var->transp.offset = 0; |
420 | var->transp.offset = 0; |
421 | break; |
421 | break; |
422 | case 15: |
422 | case 15: |
423 | var->red.offset = 10; |
423 | var->red.offset = 10; |
424 | var->green.offset = 5; |
424 | var->green.offset = 5; |
425 | var->blue.offset = 0; |
425 | var->blue.offset = 0; |
426 | var->red.length = 5; |
426 | var->red.length = 5; |
427 | var->green.length = 5; |
427 | var->green.length = 5; |
428 | var->blue.length = 5; |
428 | var->blue.length = 5; |
429 | var->transp.length = 1; |
429 | var->transp.length = 1; |
430 | var->transp.offset = 15; |
430 | var->transp.offset = 15; |
431 | break; |
431 | break; |
432 | case 16: |
432 | case 16: |
433 | var->red.offset = 11; |
433 | var->red.offset = 11; |
434 | var->green.offset = 5; |
434 | var->green.offset = 5; |
435 | var->blue.offset = 0; |
435 | var->blue.offset = 0; |
436 | var->red.length = 5; |
436 | var->red.length = 5; |
437 | var->green.length = 6; |
437 | var->green.length = 6; |
438 | var->blue.length = 5; |
438 | var->blue.length = 5; |
439 | var->transp.length = 0; |
439 | var->transp.length = 0; |
440 | var->transp.offset = 0; |
440 | var->transp.offset = 0; |
441 | break; |
441 | break; |
442 | case 24: |
442 | case 24: |
443 | var->red.offset = 16; |
443 | var->red.offset = 16; |
444 | var->green.offset = 8; |
444 | var->green.offset = 8; |
445 | var->blue.offset = 0; |
445 | var->blue.offset = 0; |
446 | var->red.length = 8; |
446 | var->red.length = 8; |
447 | var->green.length = 8; |
447 | var->green.length = 8; |
448 | var->blue.length = 8; |
448 | var->blue.length = 8; |
449 | var->transp.length = 0; |
449 | var->transp.length = 0; |
450 | var->transp.offset = 0; |
450 | var->transp.offset = 0; |
451 | break; |
451 | break; |
452 | case 32: |
452 | case 32: |
453 | var->red.offset = 16; |
453 | var->red.offset = 16; |
454 | var->green.offset = 8; |
454 | var->green.offset = 8; |
455 | var->blue.offset = 0; |
455 | var->blue.offset = 0; |
456 | var->red.length = 8; |
456 | var->red.length = 8; |
457 | var->green.length = 8; |
457 | var->green.length = 8; |
458 | var->blue.length = 8; |
458 | var->blue.length = 8; |
459 | var->transp.length = 8; |
459 | var->transp.length = 8; |
460 | var->transp.offset = 24; |
460 | var->transp.offset = 24; |
461 | break; |
461 | break; |
462 | default: |
462 | default: |
463 | return -EINVAL; |
463 | return -EINVAL; |
464 | } |
464 | } |
465 | return 0; |
465 | return 0; |
466 | } |
466 | } |
467 | EXPORT_SYMBOL(drm_fb_helper_check_var); |
467 | EXPORT_SYMBOL(drm_fb_helper_check_var); |
468 | 468 | ||
469 | /* this will let fbcon do the mode init */ |
469 | /* this will let fbcon do the mode init */ |
470 | int drm_fb_helper_set_par(struct fb_info *info) |
470 | int drm_fb_helper_set_par(struct fb_info *info) |
471 | { |
471 | { |
472 | struct drm_fb_helper *fb_helper = info->par; |
472 | struct drm_fb_helper *fb_helper = info->par; |
473 | struct drm_device *dev = fb_helper->dev; |
473 | struct drm_device *dev = fb_helper->dev; |
474 | struct fb_var_screeninfo *var = &info->var; |
474 | struct fb_var_screeninfo *var = &info->var; |
475 | struct drm_crtc *crtc; |
475 | struct drm_crtc *crtc; |
476 | int ret; |
476 | int ret; |
477 | int i; |
477 | int i; |
478 | 478 | ||
479 | if (var->pixclock != 0) { |
479 | if (var->pixclock != 0) { |
480 | DRM_ERROR("PIXEL CLOCK SET\n"); |
480 | DRM_ERROR("PIXEL CLOCK SET\n"); |
481 | return -EINVAL; |
481 | return -EINVAL; |
482 | } |
482 | } |
483 | 483 | ||
484 | mutex_lock(&dev->mode_config.mutex); |
484 | mutex_lock(&dev->mode_config.mutex); |
485 | for (i = 0; i < fb_helper->crtc_count; i++) { |
485 | for (i = 0; i < fb_helper->crtc_count; i++) { |
486 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
486 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
487 | ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); |
487 | ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); |
488 | if (ret) { |
488 | if (ret) { |
489 | mutex_unlock(&dev->mode_config.mutex); |
489 | mutex_unlock(&dev->mode_config.mutex); |
490 | return ret; |
490 | return ret; |
491 | } |
491 | } |
492 | } |
492 | } |
493 | mutex_unlock(&dev->mode_config.mutex); |
493 | mutex_unlock(&dev->mode_config.mutex); |
494 | 494 | ||
495 | if (fb_helper->delayed_hotplug) { |
495 | if (fb_helper->delayed_hotplug) { |
496 | fb_helper->delayed_hotplug = false; |
496 | fb_helper->delayed_hotplug = false; |
497 | // drm_fb_helper_hotplug_event(fb_helper); |
497 | // drm_fb_helper_hotplug_event(fb_helper); |
498 | } |
498 | } |
499 | return 0; |
499 | return 0; |
500 | } |
500 | } |
501 | EXPORT_SYMBOL(drm_fb_helper_set_par); |
501 | EXPORT_SYMBOL(drm_fb_helper_set_par); |
502 | 502 | ||
503 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, |
503 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, |
504 | struct fb_info *info) |
504 | struct fb_info *info) |
505 | { |
505 | { |
506 | struct drm_fb_helper *fb_helper = info->par; |
506 | struct drm_fb_helper *fb_helper = info->par; |
507 | struct drm_device *dev = fb_helper->dev; |
507 | struct drm_device *dev = fb_helper->dev; |
508 | struct drm_mode_set *modeset; |
508 | struct drm_mode_set *modeset; |
509 | struct drm_crtc *crtc; |
509 | struct drm_crtc *crtc; |
510 | int ret = 0; |
510 | int ret = 0; |
511 | int i; |
511 | int i; |
512 | 512 | ||
513 | mutex_lock(&dev->mode_config.mutex); |
513 | mutex_lock(&dev->mode_config.mutex); |
514 | for (i = 0; i < fb_helper->crtc_count; i++) { |
514 | for (i = 0; i < fb_helper->crtc_count; i++) { |
515 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
515 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
516 | 516 | ||
517 | modeset = &fb_helper->crtc_info[i].mode_set; |
517 | modeset = &fb_helper->crtc_info[i].mode_set; |
518 | 518 | ||
519 | modeset->x = var->xoffset; |
519 | modeset->x = var->xoffset; |
520 | modeset->y = var->yoffset; |
520 | modeset->y = var->yoffset; |
521 | 521 | ||
522 | if (modeset->num_connectors) { |
522 | if (modeset->num_connectors) { |
523 | ret = crtc->funcs->set_config(modeset); |
523 | ret = crtc->funcs->set_config(modeset); |
524 | if (!ret) { |
524 | if (!ret) { |
525 | info->var.xoffset = var->xoffset; |
525 | info->var.xoffset = var->xoffset; |
526 | info->var.yoffset = var->yoffset; |
526 | info->var.yoffset = var->yoffset; |
527 | } |
527 | } |
528 | } |
528 | } |
529 | } |
529 | } |
530 | mutex_unlock(&dev->mode_config.mutex); |
530 | mutex_unlock(&dev->mode_config.mutex); |
531 | return ret; |
531 | return ret; |
532 | } |
532 | } |
533 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
533 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
534 | 534 | ||
535 | int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, |
535 | int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, |
536 | int preferred_bpp) |
536 | int preferred_bpp) |
537 | { |
537 | { |
538 | int new_fb = 0; |
538 | int new_fb = 0; |
539 | int crtc_count = 0; |
539 | int crtc_count = 0; |
540 | int i; |
540 | int i; |
541 | struct fb_info *info; |
541 | struct fb_info *info; |
542 | struct drm_fb_helper_surface_size sizes; |
542 | struct drm_fb_helper_surface_size sizes; |
543 | int gamma_size = 0; |
543 | int gamma_size = 0; |
544 | 544 | ||
545 | memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); |
545 | memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); |
546 | sizes.surface_depth = 24; |
546 | sizes.surface_depth = 24; |
547 | sizes.surface_bpp = 32; |
547 | sizes.surface_bpp = 32; |
548 | sizes.fb_width = (unsigned)-1; |
548 | sizes.fb_width = (unsigned)-1; |
549 | sizes.fb_height = (unsigned)-1; |
549 | sizes.fb_height = (unsigned)-1; |
550 | 550 | ||
551 | sizes.surface_depth = 24; |
551 | sizes.surface_depth = 24; |
552 | sizes.surface_bpp = 32; |
552 | sizes.surface_bpp = 32; |
553 | 553 | ||
554 | crtc_count = 0; |
554 | crtc_count = 0; |
555 | for (i = 0; i < fb_helper->crtc_count; i++) { |
555 | for (i = 0; i < fb_helper->crtc_count; i++) { |
556 | struct drm_display_mode *desired_mode; |
556 | struct drm_display_mode *desired_mode; |
557 | desired_mode = fb_helper->crtc_info[i].desired_mode; |
557 | desired_mode = fb_helper->crtc_info[i].desired_mode; |
558 | 558 | ||
559 | if (desired_mode) { |
559 | if (desired_mode) { |
560 | if (gamma_size == 0) |
560 | if (gamma_size == 0) |
561 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; |
561 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; |
562 | if (desired_mode->hdisplay < sizes.fb_width) |
562 | if (desired_mode->hdisplay < sizes.fb_width) |
563 | sizes.fb_width = desired_mode->hdisplay; |
563 | sizes.fb_width = desired_mode->hdisplay; |
564 | if (desired_mode->vdisplay < sizes.fb_height) |
564 | if (desired_mode->vdisplay < sizes.fb_height) |
565 | sizes.fb_height = desired_mode->vdisplay; |
565 | sizes.fb_height = desired_mode->vdisplay; |
566 | if (desired_mode->hdisplay > sizes.surface_width) |
566 | if (desired_mode->hdisplay > sizes.surface_width) |
567 | sizes.surface_width = desired_mode->hdisplay; |
567 | sizes.surface_width = desired_mode->hdisplay; |
568 | if (desired_mode->vdisplay > sizes.surface_height) |
568 | if (desired_mode->vdisplay > sizes.surface_height) |
569 | sizes.surface_height = desired_mode->vdisplay; |
569 | sizes.surface_height = desired_mode->vdisplay; |
570 | crtc_count++; |
570 | crtc_count++; |
571 | } |
571 | } |
572 | } |
572 | } |
573 | 573 | ||
574 | if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { |
574 | if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { |
575 | /* hmm everyone went away - assume VGA cable just fell out |
575 | /* hmm everyone went away - assume VGA cable just fell out |
576 | and will come back later. */ |
576 | and will come back later. */ |
577 | DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); |
577 | DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); |
578 | sizes.fb_width = sizes.surface_width = 1024; |
578 | sizes.fb_width = sizes.surface_width = 1024; |
579 | sizes.fb_height = sizes.surface_height = 768; |
579 | sizes.fb_height = sizes.surface_height = 768; |
580 | } |
580 | } |
581 | 581 | ||
582 | /* push down into drivers */ |
582 | /* push down into drivers */ |
583 | 583 | ||
584 | DRM_INFO("enter fb probe\n"); |
584 | DRM_INFO("enter fb probe\n"); |
585 | 585 | ||
586 | 586 | ||
587 | new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); |
587 | new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); |
588 | if (new_fb < 0) |
588 | if (new_fb < 0) |
589 | return new_fb; |
589 | return new_fb; |
590 | 590 | ||
591 | info = fb_helper->fbdev; |
591 | info = fb_helper->fbdev; |
592 | - | ||
593 | #if 0 |
- | |
594 | 592 | ||
595 | /* set the fb pointer */ |
593 | /* set the fb pointer */ |
596 | for (i = 0; i < fb_helper->crtc_count; i++) { |
594 | for (i = 0; i < fb_helper->crtc_count; i++) { |
597 | fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; |
595 | fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; |
598 | } |
596 | } |
599 | 597 | ||
600 | if (new_fb) { |
598 | if (new_fb) { |
601 | info->var.pixclock = 0; |
599 | info->var.pixclock = 0; |
602 | 600 | ||
603 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, |
601 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, |
604 | info->fix.id); |
602 | info->fix.id); |
605 | 603 | ||
606 | } else { |
604 | } else { |
607 | drm_fb_helper_set_par(info); |
605 | drm_fb_helper_set_par(info); |
608 | } |
606 | } |
609 | 607 | ||
610 | 608 | ||
611 | if (new_fb) |
609 | if (new_fb) |
612 | list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); |
610 | list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); |
613 | - | ||
614 | #endif |
611 | |
615 | 612 | ||
616 | LEAVE(); |
613 | LEAVE(); |
617 | 614 | ||
618 | return 0; |
615 | return 0; |
619 | } |
616 | } |
620 | EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); |
617 | EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); |
621 | 618 | ||
622 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, |
619 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, |
623 | uint32_t depth) |
620 | uint32_t depth) |
624 | { |
621 | { |
625 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
622 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
626 | info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : |
623 | info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : |
627 | FB_VISUAL_TRUECOLOR; |
624 | FB_VISUAL_TRUECOLOR; |
628 | info->fix.mmio_start = 0; |
625 | info->fix.mmio_start = 0; |
629 | info->fix.mmio_len = 0; |
626 | info->fix.mmio_len = 0; |
630 | info->fix.type_aux = 0; |
627 | info->fix.type_aux = 0; |
631 | info->fix.xpanstep = 1; /* doing it in hw */ |
628 | info->fix.xpanstep = 1; /* doing it in hw */ |
632 | info->fix.ypanstep = 1; /* doing it in hw */ |
629 | info->fix.ypanstep = 1; /* doing it in hw */ |
633 | info->fix.ywrapstep = 0; |
630 | info->fix.ywrapstep = 0; |
634 | info->fix.accel = FB_ACCEL_NONE; |
631 | info->fix.accel = FB_ACCEL_NONE; |
635 | info->fix.type_aux = 0; |
632 | info->fix.type_aux = 0; |
636 | 633 | ||
637 | info->fix.line_length = pitch; |
634 | info->fix.line_length = pitch; |
638 | return; |
635 | return; |
639 | } |
636 | } |
640 | EXPORT_SYMBOL(drm_fb_helper_fill_fix); |
637 | EXPORT_SYMBOL(drm_fb_helper_fill_fix); |
641 | 638 | ||
642 | void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, |
639 | void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, |
643 | uint32_t fb_width, uint32_t fb_height) |
640 | uint32_t fb_width, uint32_t fb_height) |
644 | { |
641 | { |
645 | struct drm_framebuffer *fb = fb_helper->fb; |
642 | struct drm_framebuffer *fb = fb_helper->fb; |
646 | info->pseudo_palette = fb_helper->pseudo_palette; |
643 | info->pseudo_palette = fb_helper->pseudo_palette; |
647 | info->var.xres_virtual = fb->width; |
644 | info->var.xres_virtual = fb->width; |
648 | info->var.yres_virtual = fb->height; |
645 | info->var.yres_virtual = fb->height; |
649 | info->var.bits_per_pixel = fb->bits_per_pixel; |
646 | info->var.bits_per_pixel = fb->bits_per_pixel; |
650 | info->var.accel_flags = FB_ACCELF_TEXT; |
647 | info->var.accel_flags = FB_ACCELF_TEXT; |
651 | info->var.xoffset = 0; |
648 | info->var.xoffset = 0; |
652 | info->var.yoffset = 0; |
649 | info->var.yoffset = 0; |
653 | info->var.activate = FB_ACTIVATE_NOW; |
650 | info->var.activate = FB_ACTIVATE_NOW; |
654 | info->var.height = -1; |
651 | info->var.height = -1; |
655 | info->var.width = -1; |
652 | info->var.width = -1; |
656 | 653 | ||
657 | switch (fb->depth) { |
654 | switch (fb->depth) { |
658 | case 8: |
655 | case 8: |
659 | info->var.red.offset = 0; |
656 | info->var.red.offset = 0; |
660 | info->var.green.offset = 0; |
657 | info->var.green.offset = 0; |
661 | info->var.blue.offset = 0; |
658 | info->var.blue.offset = 0; |
662 | info->var.red.length = 8; /* 8bit DAC */ |
659 | info->var.red.length = 8; /* 8bit DAC */ |
663 | info->var.green.length = 8; |
660 | info->var.green.length = 8; |
664 | info->var.blue.length = 8; |
661 | info->var.blue.length = 8; |
665 | info->var.transp.offset = 0; |
662 | info->var.transp.offset = 0; |
666 | info->var.transp.length = 0; |
663 | info->var.transp.length = 0; |
667 | break; |
664 | break; |
668 | case 15: |
665 | case 15: |
669 | info->var.red.offset = 10; |
666 | info->var.red.offset = 10; |
670 | info->var.green.offset = 5; |
667 | info->var.green.offset = 5; |
671 | info->var.blue.offset = 0; |
668 | info->var.blue.offset = 0; |
672 | info->var.red.length = 5; |
669 | info->var.red.length = 5; |
673 | info->var.green.length = 5; |
670 | info->var.green.length = 5; |
674 | info->var.blue.length = 5; |
671 | info->var.blue.length = 5; |
675 | info->var.transp.offset = 15; |
672 | info->var.transp.offset = 15; |
676 | info->var.transp.length = 1; |
673 | info->var.transp.length = 1; |
677 | break; |
674 | break; |
678 | case 16: |
675 | case 16: |
679 | info->var.red.offset = 11; |
676 | info->var.red.offset = 11; |
680 | info->var.green.offset = 5; |
677 | info->var.green.offset = 5; |
681 | info->var.blue.offset = 0; |
678 | info->var.blue.offset = 0; |
682 | info->var.red.length = 5; |
679 | info->var.red.length = 5; |
683 | info->var.green.length = 6; |
680 | info->var.green.length = 6; |
684 | info->var.blue.length = 5; |
681 | info->var.blue.length = 5; |
685 | info->var.transp.offset = 0; |
682 | info->var.transp.offset = 0; |
686 | break; |
683 | break; |
687 | case 24: |
684 | case 24: |
688 | info->var.red.offset = 16; |
685 | info->var.red.offset = 16; |
689 | info->var.green.offset = 8; |
686 | info->var.green.offset = 8; |
690 | info->var.blue.offset = 0; |
687 | info->var.blue.offset = 0; |
691 | info->var.red.length = 8; |
688 | info->var.red.length = 8; |
692 | info->var.green.length = 8; |
689 | info->var.green.length = 8; |
693 | info->var.blue.length = 8; |
690 | info->var.blue.length = 8; |
694 | info->var.transp.offset = 0; |
691 | info->var.transp.offset = 0; |
695 | info->var.transp.length = 0; |
692 | info->var.transp.length = 0; |
696 | break; |
693 | break; |
697 | case 32: |
694 | case 32: |
698 | info->var.red.offset = 16; |
695 | info->var.red.offset = 16; |
699 | info->var.green.offset = 8; |
696 | info->var.green.offset = 8; |
700 | info->var.blue.offset = 0; |
697 | info->var.blue.offset = 0; |
701 | info->var.red.length = 8; |
698 | info->var.red.length = 8; |
702 | info->var.green.length = 8; |
699 | info->var.green.length = 8; |
703 | info->var.blue.length = 8; |
700 | info->var.blue.length = 8; |
704 | info->var.transp.offset = 24; |
701 | info->var.transp.offset = 24; |
705 | info->var.transp.length = 8; |
702 | info->var.transp.length = 8; |
706 | break; |
703 | break; |
707 | default: |
704 | default: |
708 | break; |
705 | break; |
709 | } |
706 | } |
710 | 707 | ||
711 | info->var.xres = fb_width; |
708 | info->var.xres = fb_width; |
712 | info->var.yres = fb_height; |
709 | info->var.yres = fb_height; |
713 | } |
710 | } |
714 | EXPORT_SYMBOL(drm_fb_helper_fill_var); |
711 | EXPORT_SYMBOL(drm_fb_helper_fill_var); |
715 | 712 | ||
716 | static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper, |
713 | static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper, |
717 | uint32_t maxX, |
714 | uint32_t maxX, |
718 | uint32_t maxY) |
715 | uint32_t maxY) |
719 | { |
716 | { |
720 | struct drm_connector *connector; |
717 | struct drm_connector *connector; |
721 | int count = 0; |
718 | int count = 0; |
722 | int i; |
719 | int i; |
723 | 720 | ||
724 | for (i = 0; i < fb_helper->connector_count; i++) { |
721 | for (i = 0; i < fb_helper->connector_count; i++) { |
725 | connector = fb_helper->connector_info[i]->connector; |
722 | connector = fb_helper->connector_info[i]->connector; |
726 | count += connector->funcs->fill_modes(connector, maxX, maxY); |
723 | count += connector->funcs->fill_modes(connector, maxX, maxY); |
727 | } |
724 | } |
728 | 725 | ||
729 | return count; |
726 | return count; |
730 | } |
727 | } |
731 | 728 | ||
732 | static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height) |
729 | static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height) |
733 | { |
730 | { |
734 | struct drm_display_mode *mode; |
731 | struct drm_display_mode *mode; |
735 | 732 | ||
736 | list_for_each_entry(mode, &fb_connector->connector->modes, head) { |
733 | list_for_each_entry(mode, &fb_connector->connector->modes, head) { |
737 | if (drm_mode_width(mode) > width || |
734 | if (drm_mode_width(mode) > width || |
738 | drm_mode_height(mode) > height) |
735 | drm_mode_height(mode) > height) |
739 | continue; |
736 | continue; |
740 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
737 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
741 | return mode; |
738 | return mode; |
742 | } |
739 | } |
743 | return NULL; |
740 | return NULL; |
744 | } |
741 | } |
745 | 742 | ||
746 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) |
743 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) |
747 | { |
744 | { |
748 | struct drm_cmdline_mode *cmdline_mode; |
745 | struct drm_cmdline_mode *cmdline_mode; |
749 | cmdline_mode = &fb_connector->cmdline_mode; |
746 | cmdline_mode = &fb_connector->cmdline_mode; |
750 | return cmdline_mode->specified; |
747 | return cmdline_mode->specified; |
751 | } |
748 | } |
752 | 749 | ||
753 | 750 | ||
754 | static bool drm_connector_enabled(struct drm_connector *connector, bool strict) |
751 | static bool drm_connector_enabled(struct drm_connector *connector, bool strict) |
755 | { |
752 | { |
756 | bool enable; |
753 | bool enable; |
757 | 754 | ||
758 | if (strict) { |
755 | if (strict) { |
759 | enable = connector->status == connector_status_connected; |
756 | enable = connector->status == connector_status_connected; |
760 | } else { |
757 | } else { |
761 | enable = connector->status != connector_status_disconnected; |
758 | enable = connector->status != connector_status_disconnected; |
762 | } |
759 | } |
763 | return enable; |
760 | return enable; |
764 | } |
761 | } |
765 | 762 | ||
766 | static void drm_enable_connectors(struct drm_fb_helper *fb_helper, |
763 | static void drm_enable_connectors(struct drm_fb_helper *fb_helper, |
767 | bool *enabled) |
764 | bool *enabled) |
768 | { |
765 | { |
769 | bool any_enabled = false; |
766 | bool any_enabled = false; |
770 | struct drm_connector *connector; |
767 | struct drm_connector *connector; |
771 | int i = 0; |
768 | int i = 0; |
772 | 769 | ||
773 | for (i = 0; i < fb_helper->connector_count; i++) { |
770 | for (i = 0; i < fb_helper->connector_count; i++) { |
774 | connector = fb_helper->connector_info[i]->connector; |
771 | connector = fb_helper->connector_info[i]->connector; |
775 | enabled[i] = drm_connector_enabled(connector, true); |
772 | enabled[i] = drm_connector_enabled(connector, true); |
776 | DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, |
773 | DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, |
777 | enabled[i] ? "yes" : "no"); |
774 | enabled[i] ? "yes" : "no"); |
778 | any_enabled |= enabled[i]; |
775 | any_enabled |= enabled[i]; |
779 | } |
776 | } |
780 | 777 | ||
781 | if (any_enabled) |
778 | if (any_enabled) |
782 | return; |
779 | return; |
783 | 780 | ||
784 | for (i = 0; i < fb_helper->connector_count; i++) { |
781 | for (i = 0; i < fb_helper->connector_count; i++) { |
785 | connector = fb_helper->connector_info[i]->connector; |
782 | connector = fb_helper->connector_info[i]->connector; |
786 | enabled[i] = drm_connector_enabled(connector, false); |
783 | enabled[i] = drm_connector_enabled(connector, false); |
787 | } |
784 | } |
788 | } |
785 | } |
789 | 786 | ||
790 | 787 | ||
791 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, |
788 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, |
792 | struct drm_display_mode **modes, |
789 | struct drm_display_mode **modes, |
793 | bool *enabled, int width, int height) |
790 | bool *enabled, int width, int height) |
794 | { |
791 | { |
795 | struct drm_fb_helper_connector *fb_helper_conn; |
792 | struct drm_fb_helper_connector *fb_helper_conn; |
796 | int i; |
793 | int i; |
797 | 794 | ||
798 | for (i = 0; i < fb_helper->connector_count; i++) { |
795 | for (i = 0; i < fb_helper->connector_count; i++) { |
799 | fb_helper_conn = fb_helper->connector_info[i]; |
796 | fb_helper_conn = fb_helper->connector_info[i]; |
800 | 797 | ||
801 | if (enabled[i] == false) |
798 | if (enabled[i] == false) |
802 | continue; |
799 | continue; |
803 | 800 | ||
804 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
801 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
805 | fb_helper_conn->connector->base.id); |
802 | fb_helper_conn->connector->base.id); |
806 | 803 | ||
807 | /* got for command line mode first */ |
804 | /* got for command line mode first */ |
808 | // modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
805 | // modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
809 | 806 | ||
810 | modes[i] = NULL; |
807 | modes[i] = NULL; |
811 | 808 | ||
812 | if (!modes[i]) { |
809 | if (!modes[i]) { |
813 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", |
810 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", |
814 | fb_helper_conn->connector->base.id); |
811 | fb_helper_conn->connector->base.id); |
815 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); |
812 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); |
816 | } |
813 | } |
817 | /* No preferred modes, pick one off the list */ |
814 | /* No preferred modes, pick one off the list */ |
818 | if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) { |
815 | if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) { |
819 | list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head) |
816 | list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head) |
820 | break; |
817 | break; |
821 | } |
818 | } |
822 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
819 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
823 | "none"); |
820 | "none"); |
824 | } |
821 | } |
825 | return true; |
822 | return true; |
826 | } |
823 | } |
827 | 824 | ||
828 | static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, |
825 | static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, |
829 | struct drm_fb_helper_crtc **best_crtcs, |
826 | struct drm_fb_helper_crtc **best_crtcs, |
830 | struct drm_display_mode **modes, |
827 | struct drm_display_mode **modes, |
831 | int n, int width, int height) |
828 | int n, int width, int height) |
832 | { |
829 | { |
833 | int c, o; |
830 | int c, o; |
834 | struct drm_device *dev = fb_helper->dev; |
831 | struct drm_device *dev = fb_helper->dev; |
835 | struct drm_connector *connector; |
832 | struct drm_connector *connector; |
836 | struct drm_connector_helper_funcs *connector_funcs; |
833 | struct drm_connector_helper_funcs *connector_funcs; |
837 | struct drm_encoder *encoder; |
834 | struct drm_encoder *encoder; |
838 | struct drm_fb_helper_crtc *best_crtc; |
835 | struct drm_fb_helper_crtc *best_crtc; |
839 | int my_score, best_score, score; |
836 | int my_score, best_score, score; |
840 | struct drm_fb_helper_crtc **crtcs, *crtc; |
837 | struct drm_fb_helper_crtc **crtcs, *crtc; |
841 | struct drm_fb_helper_connector *fb_helper_conn; |
838 | struct drm_fb_helper_connector *fb_helper_conn; |
842 | 839 | ||
843 | if (n == fb_helper->connector_count) |
840 | if (n == fb_helper->connector_count) |
844 | return 0; |
841 | return 0; |
845 | 842 | ||
846 | fb_helper_conn = fb_helper->connector_info[n]; |
843 | fb_helper_conn = fb_helper->connector_info[n]; |
847 | connector = fb_helper_conn->connector; |
844 | connector = fb_helper_conn->connector; |
848 | 845 | ||
849 | best_crtcs[n] = NULL; |
846 | best_crtcs[n] = NULL; |
850 | best_crtc = NULL; |
847 | best_crtc = NULL; |
851 | best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height); |
848 | best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height); |
852 | if (modes[n] == NULL) |
849 | if (modes[n] == NULL) |
853 | return best_score; |
850 | return best_score; |
854 | 851 | ||
855 | crtcs = kzalloc(dev->mode_config.num_connector * |
852 | crtcs = kzalloc(dev->mode_config.num_connector * |
856 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
853 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
857 | if (!crtcs) |
854 | if (!crtcs) |
858 | return best_score; |
855 | return best_score; |
859 | 856 | ||
860 | my_score = 1; |
857 | my_score = 1; |
861 | if (connector->status == connector_status_connected) |
858 | if (connector->status == connector_status_connected) |
862 | my_score++; |
859 | my_score++; |
863 | if (drm_has_cmdline_mode(fb_helper_conn)) |
860 | if (drm_has_cmdline_mode(fb_helper_conn)) |
864 | my_score++; |
861 | my_score++; |
865 | if (drm_has_preferred_mode(fb_helper_conn, width, height)) |
862 | if (drm_has_preferred_mode(fb_helper_conn, width, height)) |
866 | my_score++; |
863 | my_score++; |
867 | 864 | ||
868 | connector_funcs = connector->helper_private; |
865 | connector_funcs = connector->helper_private; |
869 | encoder = connector_funcs->best_encoder(connector); |
866 | encoder = connector_funcs->best_encoder(connector); |
870 | if (!encoder) |
867 | if (!encoder) |
871 | goto out; |
868 | goto out; |
872 | 869 | ||
873 | /* select a crtc for this connector and then attempt to configure |
870 | /* select a crtc for this connector and then attempt to configure |
874 | remaining connectors */ |
871 | remaining connectors */ |
875 | for (c = 0; c < fb_helper->crtc_count; c++) { |
872 | for (c = 0; c < fb_helper->crtc_count; c++) { |
876 | crtc = &fb_helper->crtc_info[c]; |
873 | crtc = &fb_helper->crtc_info[c]; |
877 | 874 | ||
878 | if ((encoder->possible_crtcs & (1 << c)) == 0) { |
875 | if ((encoder->possible_crtcs & (1 << c)) == 0) { |
879 | continue; |
876 | continue; |
880 | } |
877 | } |
881 | 878 | ||
882 | for (o = 0; o < n; o++) |
879 | for (o = 0; o < n; o++) |
883 | if (best_crtcs[o] == crtc) |
880 | if (best_crtcs[o] == crtc) |
884 | break; |
881 | break; |
885 | 882 | ||
886 | if (o < n) { |
883 | if (o < n) { |
887 | /* ignore cloning unless only a single crtc */ |
884 | /* ignore cloning unless only a single crtc */ |
888 | if (fb_helper->crtc_count > 1) |
885 | if (fb_helper->crtc_count > 1) |
889 | continue; |
886 | continue; |
890 | 887 | ||
891 | if (!drm_mode_equal(modes[o], modes[n])) |
888 | if (!drm_mode_equal(modes[o], modes[n])) |
892 | continue; |
889 | continue; |
893 | } |
890 | } |
894 | 891 | ||
895 | crtcs[n] = crtc; |
892 | crtcs[n] = crtc; |
896 | memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); |
893 | memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); |
897 | score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, |
894 | score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, |
898 | width, height); |
895 | width, height); |
899 | if (score > best_score) { |
896 | if (score > best_score) { |
900 | best_crtc = crtc; |
897 | best_crtc = crtc; |
901 | best_score = score; |
898 | best_score = score; |
902 | memcpy(best_crtcs, crtcs, |
899 | memcpy(best_crtcs, crtcs, |
903 | dev->mode_config.num_connector * |
900 | dev->mode_config.num_connector * |
904 | sizeof(struct drm_fb_helper_crtc *)); |
901 | sizeof(struct drm_fb_helper_crtc *)); |
905 | } |
902 | } |
906 | } |
903 | } |
907 | out: |
904 | out: |
908 | kfree(crtcs); |
905 | kfree(crtcs); |
909 | return best_score; |
906 | return best_score; |
910 | } |
907 | } |
911 | 908 | ||
912 | static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) |
909 | static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) |
913 | { |
910 | { |
914 | struct drm_device *dev = fb_helper->dev; |
911 | struct drm_device *dev = fb_helper->dev; |
915 | struct drm_fb_helper_crtc **crtcs; |
912 | struct drm_fb_helper_crtc **crtcs; |
916 | struct drm_display_mode **modes; |
913 | struct drm_display_mode **modes; |
917 | struct drm_encoder *encoder; |
914 | struct drm_encoder *encoder; |
918 | struct drm_mode_set *modeset; |
915 | struct drm_mode_set *modeset; |
919 | bool *enabled; |
916 | bool *enabled; |
920 | int width, height; |
917 | int width, height; |
921 | int i, ret; |
918 | int i, ret; |
922 | 919 | ||
923 | DRM_DEBUG_KMS("\n"); |
920 | DRM_DEBUG_KMS("\n"); |
924 | 921 | ||
925 | width = dev->mode_config.max_width; |
922 | width = dev->mode_config.max_width; |
926 | height = dev->mode_config.max_height; |
923 | height = dev->mode_config.max_height; |
927 | 924 | ||
928 | /* clean out all the encoder/crtc combos */ |
925 | /* clean out all the encoder/crtc combos */ |
929 | // list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
926 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
930 | // encoder->crtc = NULL; |
927 | // encoder->crtc = NULL; |
931 | // } |
928 | } |
932 | 929 | ||
933 | crtcs = kcalloc(dev->mode_config.num_connector, |
930 | crtcs = kcalloc(dev->mode_config.num_connector, |
934 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
931 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
935 | modes = kcalloc(dev->mode_config.num_connector, |
932 | modes = kcalloc(dev->mode_config.num_connector, |
936 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
933 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
937 | enabled = kcalloc(dev->mode_config.num_connector, |
934 | enabled = kcalloc(dev->mode_config.num_connector, |
938 | sizeof(bool), GFP_KERNEL); |
935 | sizeof(bool), GFP_KERNEL); |
939 | 936 | ||
940 | drm_enable_connectors(fb_helper, enabled); |
937 | drm_enable_connectors(fb_helper, enabled); |
941 | 938 | ||
942 | //ret = drm_target_cloned(fb_helper, modes, enabled, width, height); |
939 | //ret = drm_target_cloned(fb_helper, modes, enabled, width, height); |
943 | 940 | ||
944 | ret = 0; |
941 | ret = 0; |
945 | 942 | ||
946 | if (!ret) { |
943 | if (!ret) { |
947 | ret = drm_target_preferred(fb_helper, modes, enabled, width, height); |
944 | ret = drm_target_preferred(fb_helper, modes, enabled, width, height); |
948 | if (!ret) |
945 | if (!ret) |
949 | DRM_ERROR("Unable to find initial modes\n"); |
946 | DRM_ERROR("Unable to find initial modes\n"); |
950 | } |
947 | } |
951 | 948 | ||
952 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
949 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
953 | 950 | ||
954 | drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); |
951 | drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); |
955 | 952 | ||
956 | /* need to set the modesets up here for use later */ |
953 | /* need to set the modesets up here for use later */ |
957 | /* fill out the connector<->crtc mappings into the modesets */ |
954 | /* fill out the connector<->crtc mappings into the modesets */ |
958 | for (i = 0; i < fb_helper->crtc_count; i++) { |
955 | for (i = 0; i < fb_helper->crtc_count; i++) { |
959 | modeset = &fb_helper->crtc_info[i].mode_set; |
956 | modeset = &fb_helper->crtc_info[i].mode_set; |
960 | modeset->num_connectors = 0; |
957 | modeset->num_connectors = 0; |
961 | } |
958 | } |
962 | 959 | ||
963 | for (i = 0; i < fb_helper->connector_count; i++) { |
960 | for (i = 0; i < fb_helper->connector_count; i++) { |
964 | struct drm_display_mode *mode = modes[i]; |
961 | struct drm_display_mode *mode = modes[i]; |
965 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; |
962 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; |
966 | modeset = &fb_crtc->mode_set; |
963 | modeset = &fb_crtc->mode_set; |
967 | 964 | ||
968 | if (mode && fb_crtc) { |
965 | if (mode && fb_crtc) { |
969 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", |
966 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", |
970 | mode->name, fb_crtc->mode_set.crtc->base.id); |
967 | mode->name, fb_crtc->mode_set.crtc->base.id); |
971 | fb_crtc->desired_mode = mode; |
968 | fb_crtc->desired_mode = mode; |
972 | if (modeset->mode) |
969 | if (modeset->mode) |
973 | drm_mode_destroy(dev, modeset->mode); |
970 | drm_mode_destroy(dev, modeset->mode); |
974 | modeset->mode = drm_mode_duplicate(dev, |
971 | modeset->mode = drm_mode_duplicate(dev, |
975 | fb_crtc->desired_mode); |
972 | fb_crtc->desired_mode); |
976 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; |
973 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; |
977 | } |
974 | } |
978 | } |
975 | } |
979 | 976 | ||
980 | kfree(crtcs); |
977 | kfree(crtcs); |
981 | kfree(modes); |
978 | kfree(modes); |
982 | kfree(enabled); |
979 | kfree(enabled); |
983 | } |
980 | } |
984 | 981 | ||
985 | /** |
982 | /** |
986 | * drm_helper_initial_config - setup a sane initial connector configuration |
983 | * drm_helper_initial_config - setup a sane initial connector configuration |
987 | * @dev: DRM device |
984 | * @dev: DRM device |
988 | * |
985 | * |
989 | * LOCKING: |
986 | * LOCKING: |
990 | * Called at init time, must take mode config lock. |
987 | * Called at init time, must take mode config lock. |
991 | * |
988 | * |
992 | * Scan the CRTCs and connectors and try to put together an initial setup. |
989 | * Scan the CRTCs and connectors and try to put together an initial setup. |
993 | * At the moment, this is a cloned configuration across all heads with |
990 | * At the moment, this is a cloned configuration across all heads with |
994 | * a new framebuffer object as the backing store. |
991 | * a new framebuffer object as the backing store. |
995 | * |
992 | * |
996 | * RETURNS: |
993 | * RETURNS: |
997 | * Zero if everything went ok, nonzero otherwise. |
994 | * Zero if everything went ok, nonzero otherwise. |
998 | */ |
995 | */ |
999 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) |
996 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) |
1000 | { |
997 | { |
1001 | struct drm_device *dev = fb_helper->dev; |
998 | struct drm_device *dev = fb_helper->dev; |
1002 | int count = 0; |
999 | int count = 0; |
1003 | 1000 | ||
1004 | /* disable all the possible outputs/crtcs before entering KMS mode */ |
1001 | /* disable all the possible outputs/crtcs before entering KMS mode */ |
1005 | // drm_helper_disable_unused_functions(fb_helper->dev); |
1002 | // drm_helper_disable_unused_functions(fb_helper->dev); |
1006 | 1003 | ||
1007 | // drm_fb_helper_parse_command_line(fb_helper); |
1004 | // drm_fb_helper_parse_command_line(fb_helper); |
1008 | 1005 | ||
1009 | count = drm_fb_helper_probe_connector_modes(fb_helper, |
1006 | count = drm_fb_helper_probe_connector_modes(fb_helper, |
1010 | dev->mode_config.max_width, |
1007 | dev->mode_config.max_width, |
1011 | dev->mode_config.max_height); |
1008 | dev->mode_config.max_height); |
1012 | /* |
1009 | /* |
1013 | * we shouldn't end up with no modes here. |
1010 | * we shouldn't end up with no modes here. |
1014 | */ |
1011 | */ |
1015 | if (count == 0) { |
1012 | if (count == 0) { |
1016 | printk(KERN_INFO "No connectors reported connected with modes\n"); |
1013 | printk(KERN_INFO "No connectors reported connected with modes\n"); |
1017 | } |
1014 | } |
1018 | drm_setup_crtcs(fb_helper); |
1015 | drm_setup_crtcs(fb_helper); |
1019 | - | ||
1020 | - | ||
1021 | 1016 | ||
1022 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
1017 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
1023 | } |
1018 | } |
1024 | EXPORT_SYMBOL(drm_fb_helper_initial_config);>>->>>><>>>>>>>>>>>>>>>>>>><>=><=>><>><>><>><>>>>>>>>>> |
1019 | EXPORT_SYMBOL(drm_fb_helper_initial_config);>>->>>><>>>>>>>>>>>>>>>>>>><>=><=>><>><>><>><>>>>>>>>>> |