Rev 4560 | Rev 5271 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4560 | Rev 5060 | ||
---|---|---|---|
Line 43... | Line 43... | ||
43 | 43 | ||
44 | /** |
44 | /** |
45 | * DOC: fbdev helpers |
45 | * DOC: fbdev helpers |
46 | * |
46 | * |
47 | * The fb helper functions are useful to provide an fbdev on top of a drm kernel |
47 | * The fb helper functions are useful to provide an fbdev on top of a drm kernel |
48 | * mode setting driver. They can be used mostly independantely from the crtc |
48 | * mode setting driver. They can be used mostly independently from the crtc |
49 | * helper functions used by many drivers to implement the kernel mode setting |
49 | * helper functions used by many drivers to implement the kernel mode setting |
50 | * interfaces. |
50 | * interfaces. |
51 | * |
51 | * |
52 | * Initialization is done as a three-step process with drm_fb_helper_init(), |
52 | * Initialization is done as a four-step process with drm_fb_helper_prepare(), |
- | 53 | * drm_fb_helper_init(), drm_fb_helper_single_add_all_connectors() and |
|
53 | * drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config(). |
54 | * drm_fb_helper_initial_config(). Drivers with fancier requirements than the |
54 | * Drivers with fancier requirements than the default beheviour can override the |
55 | * default behaviour can override the third step with their own code. |
55 | * second step with their own code. Teardown is done with drm_fb_helper_fini(). |
56 | * Teardown is done with drm_fb_helper_fini(). |
56 | * |
57 | * |
57 | * At runtime drivers should restore the fbdev console by calling |
58 | * At runtime drivers should restore the fbdev console by calling |
58 | * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They |
59 | * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They |
59 | * should also notify the fb helper code from updates to the output |
60 | * should also notify the fb helper code from updates to the output |
60 | * configuration by calling drm_fb_helper_hotplug_event(). For easier |
61 | * configuration by calling drm_fb_helper_hotplug_event(). For easier |
61 | * integration with the output polling code in drm_crtc_helper.c the modeset |
62 | * integration with the output polling code in drm_crtc_helper.c the modeset |
62 | * code proves a ->output_poll_changed callback. |
63 | * code provides a ->output_poll_changed callback. |
63 | * |
64 | * |
64 | * All other functions exported by the fb helper library can be used to |
65 | * All other functions exported by the fb helper library can be used to |
- | 66 | * implement the fbdev driver interface by the driver. |
|
- | 67 | * |
|
- | 68 | * It is possible, though perhaps somewhat tricky, to implement race-free |
|
- | 69 | * hotplug detection using the fbdev helpers. The drm_fb_helper_prepare() |
|
- | 70 | * helper must be called first to initialize the minimum required to make |
|
- | 71 | * hotplug detection work. Drivers also need to make sure to properly set up |
|
- | 72 | * the dev->mode_config.funcs member. After calling drm_kms_helper_poll_init() |
|
- | 73 | * it is safe to enable interrupts and start processing hotplug events. At the |
|
- | 74 | * same time, drivers should initialize all modeset objects such as CRTCs, |
|
- | 75 | * encoders and connectors. To finish up the fbdev helper initialization, the |
|
- | 76 | * drm_fb_helper_init() function is called. To probe for all attached displays |
|
- | 77 | * and set up an initial configuration using the detected hardware, drivers |
|
- | 78 | * should call drm_fb_helper_single_add_all_connectors() followed by |
|
65 | * implement the fbdev driver interface by the driver. |
79 | * drm_fb_helper_initial_config(). |
Line 66... | Line 80... | ||
66 | */ |
80 | */ |
67 | 81 | ||
68 | /** |
82 | /** |
Line 103... | Line 117... | ||
103 | fb_helper->connector_count = 0; |
117 | fb_helper->connector_count = 0; |
104 | return -ENOMEM; |
118 | return -ENOMEM; |
105 | } |
119 | } |
106 | EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); |
120 | EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); |
Line -... | Line 121... | ||
- | 121 | ||
- | 122 | int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) |
|
- | 123 | { |
|
- | 124 | struct drm_fb_helper_connector **temp; |
|
- | 125 | struct drm_fb_helper_connector *fb_helper_connector; |
|
- | 126 | ||
- | 127 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); |
|
- | 128 | if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { |
|
- | 129 | temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector) * (fb_helper->connector_count + 1), GFP_KERNEL); |
|
- | 130 | if (!temp) |
|
- | 131 | return -ENOMEM; |
|
- | 132 | ||
- | 133 | fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1; |
|
- | 134 | fb_helper->connector_info = temp; |
|
- | 135 | } |
|
- | 136 | ||
- | 137 | ||
- | 138 | fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); |
|
- | 139 | if (!fb_helper_connector) |
|
- | 140 | return -ENOMEM; |
|
- | 141 | ||
- | 142 | fb_helper_connector->connector = connector; |
|
- | 143 | fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; |
|
- | 144 | return 0; |
|
- | 145 | } |
|
- | 146 | EXPORT_SYMBOL(drm_fb_helper_add_one_connector); |
|
- | 147 | ||
- | 148 | int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, |
|
- | 149 | struct drm_connector *connector) |
|
- | 150 | { |
|
- | 151 | struct drm_fb_helper_connector *fb_helper_connector; |
|
- | 152 | int i, j; |
|
- | 153 | ||
- | 154 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); |
|
- | 155 | ||
- | 156 | for (i = 0; i < fb_helper->connector_count; i++) { |
|
- | 157 | if (fb_helper->connector_info[i]->connector == connector) |
|
- | 158 | break; |
|
- | 159 | } |
|
- | 160 | ||
- | 161 | if (i == fb_helper->connector_count) |
|
- | 162 | return -EINVAL; |
|
- | 163 | fb_helper_connector = fb_helper->connector_info[i]; |
|
- | 164 | ||
- | 165 | for (j = i + 1; j < fb_helper->connector_count; j++) { |
|
- | 166 | fb_helper->connector_info[j - 1] = fb_helper->connector_info[j]; |
|
- | 167 | } |
|
- | 168 | fb_helper->connector_count--; |
|
- | 169 | kfree(fb_helper_connector); |
|
- | 170 | return 0; |
|
- | 171 | } |
|
107 | 172 | EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); |
|
108 | static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) |
173 | static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) |
109 | { |
174 | { |
110 | uint16_t *r_base, *g_base, *b_base; |
175 | uint16_t *r_base, *g_base, *b_base; |
Line 134... | Line 199... | ||
134 | 199 | ||
135 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); |
200 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); |
Line -... | Line 201... | ||
- | 201 | } |
|
- | 202 | ||
- | 203 | ||
- | 204 | static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) |
|
- | 205 | { |
|
- | 206 | struct drm_device *dev = fb_helper->dev; |
|
- | 207 | struct drm_plane *plane; |
|
- | 208 | bool error = false; |
|
- | 209 | int i; |
|
- | 210 | ||
- | 211 | drm_warn_on_modeset_not_all_locked(dev); |
|
- | 212 | ||
- | 213 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) |
|
- | 214 | if (plane->type != DRM_PLANE_TYPE_PRIMARY) |
|
- | 215 | drm_plane_force_disable(plane); |
|
- | 216 | ||
- | 217 | for (i = 0; i < fb_helper->crtc_count; i++) { |
|
- | 218 | struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; |
|
- | 219 | struct drm_crtc *crtc = mode_set->crtc; |
|
- | 220 | int ret; |
|
- | 221 | ||
- | 222 | if (crtc->funcs->cursor_set) { |
|
- | 223 | ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0); |
|
- | 224 | if (ret) |
|
- | 225 | error = true; |
|
- | 226 | } |
|
- | 227 | ||
- | 228 | ret = drm_mode_set_config_internal(mode_set); |
|
- | 229 | if (ret) |
|
- | 230 | error = true; |
|
- | 231 | } |
|
- | 232 | return error; |
|
- | 233 | } |
|
- | 234 | /** |
|
- | 235 | * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration |
|
- | 236 | * @fb_helper: fbcon to restore |
|
- | 237 | * |
|
- | 238 | * This should be called from driver's drm ->lastclose callback |
|
- | 239 | * when implementing an fbcon on top of kms using this helper. This ensures that |
|
- | 240 | * the user isn't greeted with a black screen when e.g. X dies. |
|
- | 241 | */ |
|
- | 242 | bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) |
|
- | 243 | { |
|
- | 244 | struct drm_device *dev = fb_helper->dev; |
|
- | 245 | bool ret; |
|
- | 246 | drm_modeset_lock_all(dev); |
|
- | 247 | ret = restore_fbdev_mode(fb_helper); |
|
- | 248 | drm_modeset_unlock_all(dev); |
|
- | 249 | return ret; |
|
136 | } |
250 | } |
137 | 251 | EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); |
|
138 | 252 | ||
139 | static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) |
253 | static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) |
140 | { |
254 | { |
Line 141... | Line 255... | ||
141 | struct drm_device *dev = fb_helper->dev; |
255 | struct drm_device *dev = fb_helper->dev; |
142 | struct drm_crtc *crtc; |
256 | struct drm_crtc *crtc; |
143 | int bound = 0, crtcs_bound = 0; |
257 | int bound = 0, crtcs_bound = 0; |
144 | 258 | ||
145 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
259 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
146 | if (crtc->fb) |
260 | if (crtc->primary->fb) |
Line 147... | Line 261... | ||
147 | crtcs_bound++; |
261 | crtcs_bound++; |
148 | if (crtc->fb == fb_helper->fb) |
262 | if (crtc->primary->fb == fb_helper->fb) |
Line 266... | Line 380... | ||
266 | } |
380 | } |
267 | kfree(helper->crtc_info); |
381 | kfree(helper->crtc_info); |
268 | } |
382 | } |
Line 269... | Line 383... | ||
269 | 383 | ||
- | 384 | /** |
|
- | 385 | * drm_fb_helper_prepare - setup a drm_fb_helper structure |
|
- | 386 | * @dev: DRM device |
|
- | 387 | * @helper: driver-allocated fbdev helper structure to set up |
|
- | 388 | * @funcs: pointer to structure of functions associate with this helper |
|
- | 389 | * |
|
- | 390 | * Sets up the bare minimum to make the framebuffer helper usable. This is |
|
- | 391 | * useful to implement race-free initialization of the polling helpers. |
|
- | 392 | */ |
|
- | 393 | void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, |
|
- | 394 | const struct drm_fb_helper_funcs *funcs) |
|
- | 395 | { |
|
- | 396 | INIT_LIST_HEAD(&helper->kernel_fb_list); |
|
- | 397 | helper->funcs = funcs; |
|
- | 398 | helper->dev = dev; |
|
- | 399 | } |
|
- | 400 | EXPORT_SYMBOL(drm_fb_helper_prepare); |
|
- | 401 | ||
270 | /** |
402 | /** |
271 | * drm_fb_helper_init - initialize a drm_fb_helper structure |
403 | * drm_fb_helper_init - initialize a drm_fb_helper structure |
272 | * @dev: drm device |
404 | * @dev: drm device |
273 | * @fb_helper: driver-allocated fbdev helper structure to initialize |
405 | * @fb_helper: driver-allocated fbdev helper structure to initialize |
274 | * @crtc_count: maximum number of crtcs to support in this fbdev emulation |
406 | * @crtc_count: maximum number of crtcs to support in this fbdev emulation |
Line 277... | Line 409... | ||
277 | * This allocates the structures for the fbdev helper with the given limits. |
409 | * This allocates the structures for the fbdev helper with the given limits. |
278 | * Note that this won't yet touch the hardware (through the driver interfaces) |
410 | * Note that this won't yet touch the hardware (through the driver interfaces) |
279 | * nor register the fbdev. This is only done in drm_fb_helper_initial_config() |
411 | * nor register the fbdev. This is only done in drm_fb_helper_initial_config() |
280 | * to allow driver writes more control over the exact init sequence. |
412 | * to allow driver writes more control over the exact init sequence. |
281 | * |
413 | * |
282 | * Drivers must set fb_helper->funcs before calling |
414 | * Drivers must call drm_fb_helper_prepare() before calling this function. |
283 | * drm_fb_helper_initial_config(). |
- | |
284 | * |
415 | * |
285 | * RETURNS: |
416 | * RETURNS: |
286 | * Zero if everything went ok, nonzero otherwise. |
417 | * Zero if everything went ok, nonzero otherwise. |
287 | */ |
418 | */ |
288 | int drm_fb_helper_init(struct drm_device *dev, |
419 | int drm_fb_helper_init(struct drm_device *dev, |
Line 290... | Line 421... | ||
290 | int crtc_count, int max_conn_count) |
421 | int crtc_count, int max_conn_count) |
291 | { |
422 | { |
292 | struct drm_crtc *crtc; |
423 | struct drm_crtc *crtc; |
293 | int i; |
424 | int i; |
Line 294... | Line 425... | ||
294 | 425 | ||
295 | fb_helper->dev = dev; |
- | |
296 | 426 | if (!max_conn_count) |
|
Line 297... | Line 427... | ||
297 | INIT_LIST_HEAD(&fb_helper->kernel_fb_list); |
427 | return -EINVAL; |
298 | 428 | ||
299 | fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); |
429 | fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); |
Line 304... | Line 434... | ||
304 | fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); |
434 | fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); |
305 | if (!fb_helper->connector_info) { |
435 | if (!fb_helper->connector_info) { |
306 | kfree(fb_helper->crtc_info); |
436 | kfree(fb_helper->crtc_info); |
307 | return -ENOMEM; |
437 | return -ENOMEM; |
308 | } |
438 | } |
- | 439 | fb_helper->connector_info_alloc_count = dev->mode_config.num_connector; |
|
309 | fb_helper->connector_count = 0; |
440 | fb_helper->connector_count = 0; |
Line 310... | Line 441... | ||
310 | 441 | ||
311 | for (i = 0; i < crtc_count; i++) { |
442 | for (i = 0; i < crtc_count; i++) { |
312 | fb_helper->crtc_info[i].mode_set.connectors = |
443 | fb_helper->crtc_info[i].mode_set.connectors = |
Line 564... | Line 695... | ||
564 | * callback. |
695 | * callback. |
565 | */ |
696 | */ |
566 | int drm_fb_helper_set_par(struct fb_info *info) |
697 | int drm_fb_helper_set_par(struct fb_info *info) |
567 | { |
698 | { |
568 | struct drm_fb_helper *fb_helper = info->par; |
699 | struct drm_fb_helper *fb_helper = info->par; |
569 | struct drm_device *dev = fb_helper->dev; |
- | |
570 | struct fb_var_screeninfo *var = &info->var; |
700 | struct fb_var_screeninfo *var = &info->var; |
571 | int ret; |
- | |
572 | int i; |
- | |
Line 573... | Line 701... | ||
573 | 701 | ||
574 | if (var->pixclock != 0) { |
702 | if (var->pixclock != 0) { |
575 | DRM_ERROR("PIXEL CLOCK SET\n"); |
703 | DRM_ERROR("PIXEL CLOCK SET\n"); |
576 | return -EINVAL; |
704 | return -EINVAL; |
Line 577... | Line -... | ||
577 | } |
- | |
578 | - | ||
579 | drm_modeset_lock_all(dev); |
- | |
580 | for (i = 0; i < fb_helper->crtc_count; i++) { |
- | |
581 | ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set); |
- | |
582 | if (ret) { |
- | |
583 | drm_modeset_unlock_all(dev); |
- | |
584 | return ret; |
- | |
585 | } |
705 | } |
Line 586... | Line 706... | ||
586 | } |
706 | |
587 | drm_modeset_unlock_all(dev); |
707 | drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); |
588 | 708 | ||
589 | if (fb_helper->delayed_hotplug) { |
709 | if (fb_helper->delayed_hotplug) { |
Line 768... | Line 888... | ||
768 | info->fix.type_aux = 0; |
888 | info->fix.type_aux = 0; |
769 | info->fix.xpanstep = 1; /* doing it in hw */ |
889 | info->fix.xpanstep = 1; /* doing it in hw */ |
770 | info->fix.ypanstep = 1; /* doing it in hw */ |
890 | info->fix.ypanstep = 1; /* doing it in hw */ |
771 | info->fix.ywrapstep = 0; |
891 | info->fix.ywrapstep = 0; |
772 | info->fix.accel = FB_ACCEL_NONE; |
892 | info->fix.accel = FB_ACCEL_NONE; |
773 | info->fix.type_aux = 0; |
- | |
Line 774... | Line 893... | ||
774 | 893 | ||
775 | info->fix.line_length = pitch; |
894 | info->fix.line_length = pitch; |
776 | return; |
895 | return; |
777 | } |
896 | } |
Line 879... | Line 998... | ||
879 | } |
998 | } |
Line 880... | Line 999... | ||
880 | 999 | ||
881 | return count; |
1000 | return count; |
Line 882... | Line 1001... | ||
882 | } |
1001 | } |
883 | 1002 | ||
884 | static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height) |
1003 | struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height) |
Line 885... | Line 1004... | ||
885 | { |
1004 | { |
886 | struct drm_display_mode *mode; |
1005 | struct drm_display_mode *mode; |
887 | 1006 | ||
888 | list_for_each_entry(mode, &fb_connector->connector->modes, head) { |
1007 | list_for_each_entry(mode, &fb_connector->connector->modes, head) { |
889 | if (drm_mode_width(mode) > width || |
1008 | if (mode->hdisplay > width || |
890 | drm_mode_height(mode) > height) |
1009 | mode->vdisplay > height) |
891 | continue; |
1010 | continue; |
892 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
1011 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
893 | return mode; |
1012 | return mode; |
- | 1013 | } |
|
Line 894... | Line 1014... | ||
894 | } |
1014 | return NULL; |
895 | return NULL; |
1015 | } |
896 | } |
1016 | EXPORT_SYMBOL(drm_has_preferred_mode); |
897 | 1017 | ||
898 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) |
1018 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) |
899 | { |
1019 | { |
Line 900... | Line 1020... | ||
900 | struct drm_cmdline_mode *cmdline_mode; |
1020 | struct drm_cmdline_mode *cmdline_mode; |
901 | cmdline_mode = &fb_connector->cmdline_mode; |
1021 | cmdline_mode = &fb_connector->cmdline_mode; |
902 | return cmdline_mode->specified; |
1022 | return cmdline_mode->specified; |
903 | } |
1023 | } |
904 | 1024 | ||
- | 1025 | struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, |
|
Line 905... | Line 1026... | ||
905 | static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, |
1026 | int width, int height) |
Line 906... | Line 1027... | ||
906 | int width, int height) |
1027 | { |
907 | { |
1028 | struct drm_cmdline_mode *cmdline_mode; |
Line 918... | Line 1039... | ||
918 | * we have gotten so far, if not add a CVT mode that conforms |
1039 | * we have gotten so far, if not add a CVT mode that conforms |
919 | */ |
1040 | */ |
920 | if (cmdline_mode->rb || cmdline_mode->margins) |
1041 | if (cmdline_mode->rb || cmdline_mode->margins) |
921 | goto create_mode; |
1042 | goto create_mode; |
Line -... | Line 1043... | ||
- | 1043 | ||
- | 1044 | prefer_non_interlace = !cmdline_mode->interlace; |
|
922 | 1045 | again: |
|
923 | list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { |
1046 | list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { |
924 | /* check width/height */ |
1047 | /* check width/height */ |
925 | if (mode->hdisplay != cmdline_mode->xres || |
1048 | if (mode->hdisplay != cmdline_mode->xres || |
926 | mode->vdisplay != cmdline_mode->yres) |
1049 | mode->vdisplay != cmdline_mode->yres) |
Line 932... | Line 1055... | ||
932 | } |
1055 | } |
Line 933... | Line 1056... | ||
933 | 1056 | ||
934 | if (cmdline_mode->interlace) { |
1057 | if (cmdline_mode->interlace) { |
935 | if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) |
1058 | if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) |
- | 1059 | continue; |
|
- | 1060 | } else if (prefer_non_interlace) { |
|
- | 1061 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
|
936 | continue; |
1062 | continue; |
937 | } |
1063 | } |
938 | return mode; |
1064 | return mode; |
Line -... | Line 1065... | ||
- | 1065 | } |
|
- | 1066 | ||
- | 1067 | if (prefer_non_interlace) { |
|
- | 1068 | prefer_non_interlace = false; |
|
- | 1069 | goto again; |
|
939 | } |
1070 | } |
940 | 1071 | ||
941 | create_mode: |
1072 | create_mode: |
942 | mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, |
1073 | mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, |
943 | cmdline_mode); |
1074 | cmdline_mode); |
944 | list_add(&mode->head, &fb_helper_conn->connector->modes); |
1075 | list_add(&mode->head, &fb_helper_conn->connector->modes); |
- | 1076 | return mode; |
|
Line 945... | Line 1077... | ||
945 | return mode; |
1077 | } |
946 | } |
1078 | EXPORT_SYMBOL(drm_pick_cmdline_mode); |
947 | 1079 | ||
Line 1284... | Line 1416... | ||
1284 | struct drm_device *dev = fb_helper->dev; |
1416 | struct drm_device *dev = fb_helper->dev; |
1285 | int count = 0; |
1417 | int count = 0; |
Line 1286... | Line 1418... | ||
1286 | 1418 | ||
Line -... | Line 1419... | ||
- | 1419 | // drm_fb_helper_parse_command_line(fb_helper); |
|
1287 | // drm_fb_helper_parse_command_line(fb_helper); |
1420 | |
1288 | 1421 | mutex_lock(&dev->mode_config.mutex); |
|
1289 | count = drm_fb_helper_probe_connector_modes(fb_helper, |
1422 | count = drm_fb_helper_probe_connector_modes(fb_helper, |
- | 1423 | dev->mode_config.max_width, |
|
1290 | dev->mode_config.max_width, |
1424 | dev->mode_config.max_height); |
1291 | dev->mode_config.max_height); |
1425 | mutex_unlock(&dev->mode_config.mutex); |
1292 | /* |
1426 | /* |
1293 | * we shouldn't end up with no modes here. |
1427 | * we shouldn't end up with no modes here. |
1294 | */ |
1428 | */ |
Line 1312... | Line 1446... | ||
1312 | * Called at runtime, takes the mode config locks to be able to check/change the |
1446 | * Called at runtime, takes the mode config locks to be able to check/change the |
1313 | * modeset configuration. Must be run from process context (which usually means |
1447 | * modeset configuration. Must be run from process context (which usually means |
1314 | * either the output polling work or a work item launched from the driver's |
1448 | * either the output polling work or a work item launched from the driver's |
1315 | * hotplug interrupt). |
1449 | * hotplug interrupt). |
1316 | * |
1450 | * |
1317 | * Note that the driver must ensure that this is only called _after_ the fb has |
1451 | * Note that drivers may call this even before calling |
1318 | * been fully set up, i.e. after the call to drm_fb_helper_initial_config. |
1452 | * drm_fb_helper_initial_config but only aftert drm_fb_helper_init. This allows |
- | 1453 | * for a race-free fbcon setup and will make sure that the fbdev emulation will |
|
- | 1454 | * not miss any hotplug events. |
|
1319 | * |
1455 | * |
1320 | * RETURNS: |
1456 | * RETURNS: |
1321 | * 0 on success and a non-zero error code otherwise. |
1457 | * 0 on success and a non-zero error code otherwise. |
1322 | */ |
1458 | */ |
1323 | int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) |
1459 | int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) |
1324 | { |
1460 | { |
1325 | struct drm_device *dev = fb_helper->dev; |
1461 | struct drm_device *dev = fb_helper->dev; |
1326 | u32 max_width, max_height; |
1462 | u32 max_width, max_height; |
Line 1327... | Line -... | ||
1327 | - | ||
1328 | if (!fb_helper->fb) |
- | |
1329 | return 0; |
- | |
1330 | 1463 | ||
1331 | mutex_lock(&fb_helper->dev->mode_config.mutex); |
1464 | mutex_lock(&fb_helper->dev->mode_config.mutex); |
1332 | if (!drm_fb_helper_is_bound(fb_helper)) { |
1465 | if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) { |
1333 | fb_helper->delayed_hotplug = true; |
1466 | fb_helper->delayed_hotplug = true; |
1334 | mutex_unlock(&fb_helper->dev->mode_config.mutex); |
1467 | mutex_unlock(&fb_helper->dev->mode_config.mutex); |
1335 | return 0; |
1468 | return 0; |
1336 | } |
1469 | } |