drm_fb_helper.c revision 1.8.18.3 1 /* $NetBSD: drm_fb_helper.c,v 1.8.18.3 2020/04/13 08:04:57 martin Exp $ */
2
3 /*
4 * Copyright (c) 2006-2009 Red Hat Inc.
5 * Copyright (c) 2006-2008 Intel Corporation
6 * Copyright (c) 2007 Dave Airlie <airlied (at) linux.ie>
7 *
8 * DRM framebuffer helper functions
9 *
10 * Permission to use, copy, modify, distribute, and sell this software and its
11 * documentation for any purpose is hereby granted without fee, provided that
12 * the above copyright notice appear in all copies and that both that copyright
13 * notice and this permission notice appear in supporting documentation, and
14 * that the name of the copyright holders not be used in advertising or
15 * publicity pertaining to distribution of the software without specific,
16 * written prior permission. The copyright holders make no representations
17 * about the suitability of this software for any purpose. It is provided "as
18 * is" without express or implied warranty.
19 *
20 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
24 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
25 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
26 * OF THIS SOFTWARE.
27 *
28 * Authors:
29 * Dave Airlie <airlied (at) linux.ie>
30 * Jesse Barnes <jesse.barnes (at) intel.com>
31 */
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: drm_fb_helper.c,v 1.8.18.3 2020/04/13 08:04:57 martin Exp $");
34
35 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
36
37 #include <linux/kernel.h>
38 #include <linux/sysrq.h>
39 #include <linux/slab.h>
40 #include <linux/fb.h>
41 #include <linux/module.h>
42 #include <linux/sysrq.h>
43 #include <drm/drmP.h>
44 #include <drm/drm_crtc.h>
45 #include <drm/drm_fb_helper.h>
46 #include <drm/drm_crtc_helper.h>
47 #include <drm/drm_atomic.h>
48 #include <drm/drm_atomic_helper.h>
49
50 static bool drm_fbdev_emulation = true;
51 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
52 MODULE_PARM_DESC(fbdev_emulation,
53 "Enable legacy fbdev emulation [default=true]");
54
55 #ifdef __NetBSD__ /* XXX LIST_HEAD means something else */
56 static struct list_head kernel_fb_helper_list =
57 LIST_HEAD_INIT(kernel_fb_helper_list);
58 #else
59 static LIST_HEAD(kernel_fb_helper_list);
60 #endif
61
62 /**
63 * DOC: fbdev helpers
64 *
65 * The fb helper functions are useful to provide an fbdev on top of a drm kernel
66 * mode setting driver. They can be used mostly independently from the crtc
67 * helper functions used by many drivers to implement the kernel mode setting
68 * interfaces.
69 *
70 * Initialization is done as a four-step process with drm_fb_helper_prepare(),
71 * drm_fb_helper_init(), drm_fb_helper_single_add_all_connectors() and
72 * drm_fb_helper_initial_config(). Drivers with fancier requirements than the
73 * default behaviour can override the third step with their own code.
74 * Teardown is done with drm_fb_helper_fini().
75 *
76 * At runtime drivers should restore the fbdev console by calling
77 * drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callback.
78 * They should also notify the fb helper code from updates to the output
79 * configuration by calling drm_fb_helper_hotplug_event(). For easier
80 * integration with the output polling code in drm_crtc_helper.c the modeset
81 * code provides a ->output_poll_changed callback.
82 *
83 * All other functions exported by the fb helper library can be used to
84 * implement the fbdev driver interface by the driver.
85 *
86 * It is possible, though perhaps somewhat tricky, to implement race-free
87 * hotplug detection using the fbdev helpers. The drm_fb_helper_prepare()
88 * helper must be called first to initialize the minimum required to make
89 * hotplug detection work. Drivers also need to make sure to properly set up
90 * the dev->mode_config.funcs member. After calling drm_kms_helper_poll_init()
91 * it is safe to enable interrupts and start processing hotplug events. At the
92 * same time, drivers should initialize all modeset objects such as CRTCs,
93 * encoders and connectors. To finish up the fbdev helper initialization, the
94 * drm_fb_helper_init() function is called. To probe for all attached displays
95 * and set up an initial configuration using the detected hardware, drivers
96 * should call drm_fb_helper_single_add_all_connectors() followed by
97 * drm_fb_helper_initial_config().
98 */
99
100 /**
101 * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
102 * emulation helper
103 * @fb_helper: fbdev initialized with drm_fb_helper_init
104 *
105 * This functions adds all the available connectors for use with the given
106 * fb_helper. This is a separate step to allow drivers to freely assign
107 * connectors to the fbdev, e.g. if some are reserved for special purposes or
108 * not adequate to be used for the fbcon.
109 *
110 * This function is protected against concurrent connector hotadds/removals
111 * using drm_fb_helper_add_one_connector() and
112 * drm_fb_helper_remove_one_connector().
113 */
114 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
115 {
116 struct drm_device *dev = fb_helper->dev;
117 struct drm_connector *connector;
118 int i;
119
120 if (!drm_fbdev_emulation)
121 return 0;
122
123 mutex_lock(&dev->mode_config.mutex);
124 drm_for_each_connector(connector, dev) {
125 struct drm_fb_helper_connector *fb_helper_connector;
126
127 fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
128 if (!fb_helper_connector)
129 goto fail;
130
131 fb_helper_connector->connector = connector;
132 fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
133 }
134 mutex_unlock(&dev->mode_config.mutex);
135 return 0;
136 fail:
137 for (i = 0; i < fb_helper->connector_count; i++) {
138 kfree(fb_helper->connector_info[i]);
139 fb_helper->connector_info[i] = NULL;
140 }
141 fb_helper->connector_count = 0;
142 mutex_unlock(&dev->mode_config.mutex);
143
144 return -ENOMEM;
145 }
146 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
147
148 int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector)
149 {
150 struct drm_fb_helper_connector **temp;
151 struct drm_fb_helper_connector *fb_helper_connector;
152
153 if (!drm_fbdev_emulation)
154 return 0;
155
156 WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
157 if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) {
158 temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL);
159 if (!temp)
160 return -ENOMEM;
161
162 fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1;
163 fb_helper->connector_info = temp;
164 }
165
166
167 fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
168 if (!fb_helper_connector)
169 return -ENOMEM;
170
171 fb_helper_connector->connector = connector;
172 fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
173 return 0;
174 }
175 EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
176
177 static void remove_from_modeset(struct drm_mode_set *set,
178 struct drm_connector *connector)
179 {
180 int i, j;
181
182 for (i = 0; i < set->num_connectors; i++) {
183 if (set->connectors[i] == connector)
184 break;
185 }
186
187 if (i == set->num_connectors)
188 return;
189
190 for (j = i + 1; j < set->num_connectors; j++) {
191 set->connectors[j - 1] = set->connectors[j];
192 }
193 set->num_connectors--;
194
195 /*
196 * TODO maybe need to makes sure we set it back to !=NULL somewhere?
197 */
198 if (set->num_connectors == 0) {
199 set->fb = NULL;
200 drm_mode_destroy(connector->dev, set->mode);
201 set->mode = NULL;
202 }
203 }
204
205 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
206 struct drm_connector *connector)
207 {
208 struct drm_fb_helper_connector *fb_helper_connector;
209 int i, j;
210
211 if (!drm_fbdev_emulation)
212 return 0;
213
214 WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
215
216 for (i = 0; i < fb_helper->connector_count; i++) {
217 if (fb_helper->connector_info[i]->connector == connector)
218 break;
219 }
220
221 if (i == fb_helper->connector_count)
222 return -EINVAL;
223 fb_helper_connector = fb_helper->connector_info[i];
224
225 for (j = i + 1; j < fb_helper->connector_count; j++) {
226 fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
227 }
228 fb_helper->connector_count--;
229 kfree(fb_helper_connector);
230
231 /* also cleanup dangling references to the connector: */
232 for (i = 0; i < fb_helper->crtc_count; i++)
233 remove_from_modeset(&fb_helper->crtc_info[i].mode_set, connector);
234
235 return 0;
236 }
237 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
238
239 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
240 {
241 uint16_t *r_base, *g_base, *b_base;
242 int i;
243
244 if (helper->funcs->gamma_get == NULL)
245 return;
246
247 r_base = crtc->gamma_store;
248 g_base = r_base + crtc->gamma_size;
249 b_base = g_base + crtc->gamma_size;
250
251 for (i = 0; i < crtc->gamma_size; i++)
252 helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
253 }
254
255 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
256 {
257 uint16_t *r_base, *g_base, *b_base;
258
259 if (crtc->funcs->gamma_set == NULL)
260 return;
261
262 r_base = crtc->gamma_store;
263 g_base = r_base + crtc->gamma_size;
264 b_base = g_base + crtc->gamma_size;
265
266 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
267 }
268
269 /**
270 * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter
271 * @info: fbdev registered by the helper
272 */
273 #ifndef __NetBSD__
274 int drm_fb_helper_debug_enter(struct fb_info *info)
275 {
276 return drm_fb_helper_debug_enter_fb(info->par);
277 }
278 #endif
279
280 int
281 drm_fb_helper_debug_enter_fb(struct drm_fb_helper *helper)
282 {
283 const struct drm_crtc_helper_funcs *funcs;
284 int i;
285
286 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
287 for (i = 0; i < helper->crtc_count; i++) {
288 struct drm_mode_set *mode_set =
289 &helper->crtc_info[i].mode_set;
290
291 if (!mode_set->crtc->enabled)
292 continue;
293
294 funcs = mode_set->crtc->helper_private;
295 drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
296 funcs->mode_set_base_atomic(mode_set->crtc,
297 mode_set->fb,
298 mode_set->x,
299 mode_set->y,
300 ENTER_ATOMIC_MODE_SET);
301 }
302 }
303
304 return 0;
305 }
306 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
307
308 /* Find the real fb for a given fb helper CRTC */
309 static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
310 {
311 struct drm_device *dev = crtc->dev;
312 struct drm_crtc *c;
313
314 drm_for_each_crtc(c, dev) {
315 if (crtc->base.id == c->base.id)
316 return c->primary->fb;
317 }
318
319 return NULL;
320 }
321
322 /**
323 * drm_fb_helper_debug_leave - implementation for ->fb_debug_leave
324 * @info: fbdev registered by the helper
325 */
326 #ifndef __NetBSD__
327 int drm_fb_helper_debug_leave(struct fb_info *info)
328 {
329 return drm_fb_helper_debug_leave_fb(info->par);
330 }
331 #endif
332
333 int
334 drm_fb_helper_debug_leave_fb(struct drm_fb_helper *helper)
335 {
336 struct drm_crtc *crtc;
337 const struct drm_crtc_helper_funcs *funcs;
338 struct drm_framebuffer *fb;
339 int i;
340
341 for (i = 0; i < helper->crtc_count; i++) {
342 struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
343 crtc = mode_set->crtc;
344 funcs = crtc->helper_private;
345 fb = drm_mode_config_fb(crtc);
346
347 if (!crtc->enabled)
348 continue;
349
350 if (!fb) {
351 DRM_ERROR("no fb to restore??\n");
352 continue;
353 }
354
355 drm_fb_helper_restore_lut_atomic(mode_set->crtc);
356 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
357 crtc->y, LEAVE_ATOMIC_MODE_SET);
358 }
359
360 return 0;
361 }
362 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
363
364 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
365 {
366 struct drm_device *dev = fb_helper->dev;
367 struct drm_plane *plane;
368 struct drm_atomic_state *state;
369 int i, ret;
370 unsigned plane_mask;
371
372 state = drm_atomic_state_alloc(dev);
373 if (!state)
374 return -ENOMEM;
375
376 state->acquire_ctx = dev->mode_config.acquire_ctx;
377 retry:
378 plane_mask = 0;
379 drm_for_each_plane(plane, dev) {
380 struct drm_plane_state *plane_state;
381
382 plane_state = drm_atomic_get_plane_state(state, plane);
383 if (IS_ERR(plane_state)) {
384 ret = PTR_ERR(plane_state);
385 goto fail;
386 }
387
388 plane_state->rotation = BIT(DRM_ROTATE_0);
389
390 plane->old_fb = plane->fb;
391 plane_mask |= 1 << drm_plane_index(plane);
392
393 /* disable non-primary: */
394 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
395 continue;
396
397 ret = __drm_atomic_helper_disable_plane(plane, plane_state);
398 if (ret != 0)
399 goto fail;
400 }
401
402 for(i = 0; i < fb_helper->crtc_count; i++) {
403 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
404
405 ret = __drm_atomic_helper_set_config(mode_set, state);
406 if (ret != 0)
407 goto fail;
408 }
409
410 ret = drm_atomic_commit(state);
411
412 fail:
413 drm_atomic_clean_old_fb(dev, plane_mask, ret);
414
415 if (ret == -EDEADLK)
416 goto backoff;
417
418 if (ret != 0)
419 drm_atomic_state_free(state);
420
421 return ret;
422
423 backoff:
424 drm_atomic_state_clear(state);
425 drm_atomic_legacy_backoff(state);
426
427 goto retry;
428 }
429
430 static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
431 {
432 struct drm_device *dev = fb_helper->dev;
433 struct drm_plane *plane;
434 int i;
435
436 drm_warn_on_modeset_not_all_locked(dev);
437
438 if (fb_helper->atomic)
439 return restore_fbdev_mode_atomic(fb_helper);
440
441 drm_for_each_plane(plane, dev) {
442 if (plane->type != DRM_PLANE_TYPE_PRIMARY)
443 drm_plane_force_disable(plane);
444
445 if (dev->mode_config.rotation_property) {
446 drm_mode_plane_set_obj_prop(plane,
447 dev->mode_config.rotation_property,
448 BIT(DRM_ROTATE_0));
449 }
450 }
451
452 for (i = 0; i < fb_helper->crtc_count; i++) {
453 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
454 struct drm_crtc *crtc = mode_set->crtc;
455 int ret;
456
457 if (crtc->funcs->cursor_set2) {
458 ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
459 if (ret)
460 return ret;
461 } else if (crtc->funcs->cursor_set) {
462 ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
463 if (ret)
464 return ret;
465 }
466
467 ret = drm_mode_set_config_internal(mode_set);
468 if (ret)
469 return ret;
470 }
471
472 return 0;
473 }
474
475 /**
476 * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
477 * @fb_helper: fbcon to restore
478 *
479 * This should be called from driver's drm ->lastclose callback
480 * when implementing an fbcon on top of kms using this helper. This ensures that
481 * the user isn't greeted with a black screen when e.g. X dies.
482 *
483 * RETURNS:
484 * Zero if everything went ok, negative error code otherwise.
485 */
486 int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
487 {
488 struct drm_device *dev = fb_helper->dev;
489 bool do_delayed;
490 int ret;
491
492 if (!drm_fbdev_emulation)
493 return -ENODEV;
494
495 drm_modeset_lock_all(dev);
496 ret = restore_fbdev_mode(fb_helper);
497
498 do_delayed = fb_helper->delayed_hotplug;
499 if (do_delayed)
500 fb_helper->delayed_hotplug = false;
501 drm_modeset_unlock_all(dev);
502
503 if (do_delayed)
504 drm_fb_helper_hotplug_event(fb_helper);
505 return ret;
506 }
507 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
508
509 static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
510 {
511 struct drm_device *dev = fb_helper->dev;
512 struct drm_crtc *crtc;
513 int bound = 0, crtcs_bound = 0;
514
515 /* Sometimes user space wants everything disabled, so don't steal the
516 * display if there's a master. */
517 if (dev->primary->master)
518 return false;
519
520 drm_for_each_crtc(crtc, dev) {
521 if (crtc->primary->fb)
522 crtcs_bound++;
523 if (crtc->primary->fb == fb_helper->fb)
524 bound++;
525 }
526
527 if (bound < crtcs_bound)
528 return false;
529
530 return true;
531 }
532
533 #ifdef CONFIG_MAGIC_SYSRQ
534 /*
535 * restore fbcon display for all kms driver's using this helper, used for sysrq
536 * and panic handling.
537 */
538 static bool drm_fb_helper_force_kernel_mode(void)
539 {
540 bool ret, error = false;
541 struct drm_fb_helper *helper;
542
543 if (list_empty(&kernel_fb_helper_list))
544 return false;
545
546 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
547 struct drm_device *dev = helper->dev;
548
549 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
550 continue;
551
552 drm_modeset_lock_all(dev);
553 ret = restore_fbdev_mode(helper);
554 if (ret)
555 error = true;
556 drm_modeset_unlock_all(dev);
557 }
558 return error;
559 }
560
561 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
562 {
563 bool ret;
564 ret = drm_fb_helper_force_kernel_mode();
565 if (ret == true)
566 DRM_ERROR("Failed to restore crtc configuration\n");
567 }
568 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
569
570 static void drm_fb_helper_sysrq(int dummy1)
571 {
572 schedule_work(&drm_fb_helper_restore_work);
573 }
574
575 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
576 .handler = drm_fb_helper_sysrq,
577 .help_msg = "force-fb(V)",
578 .action_msg = "Restore framebuffer console",
579 };
580 #else
581 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
582 #endif
583
584 #ifndef __NetBSD__ /* XXX fb info */
585 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
586 {
587 struct drm_fb_helper *fb_helper = info->par;
588 struct drm_device *dev = fb_helper->dev;
589 struct drm_crtc *crtc;
590 struct drm_connector *connector;
591 int i, j;
592
593 /*
594 * For each CRTC in this fb, turn the connectors on/off.
595 */
596 drm_modeset_lock_all(dev);
597 if (!drm_fb_helper_is_bound(fb_helper)) {
598 drm_modeset_unlock_all(dev);
599 return;
600 }
601
602 for (i = 0; i < fb_helper->crtc_count; i++) {
603 crtc = fb_helper->crtc_info[i].mode_set.crtc;
604
605 if (!crtc->enabled)
606 continue;
607
608 /* Walk the connectors & encoders on this fb turning them on/off */
609 for (j = 0; j < fb_helper->connector_count; j++) {
610 connector = fb_helper->connector_info[j]->connector;
611 connector->funcs->dpms(connector, dpms_mode);
612 drm_object_property_set_value(&connector->base,
613 dev->mode_config.dpms_property, dpms_mode);
614 }
615 }
616 drm_modeset_unlock_all(dev);
617 }
618
619 /**
620 * drm_fb_helper_blank - implementation for ->fb_blank
621 * @blank: desired blanking state
622 * @info: fbdev registered by the helper
623 */
624 int drm_fb_helper_blank(int blank, struct fb_info *info)
625 {
626 if (oops_in_progress)
627 return -EBUSY;
628
629 switch (blank) {
630 /* Display: On; HSync: On, VSync: On */
631 case FB_BLANK_UNBLANK:
632 drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
633 break;
634 /* Display: Off; HSync: On, VSync: On */
635 case FB_BLANK_NORMAL:
636 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
637 break;
638 /* Display: Off; HSync: Off, VSync: On */
639 case FB_BLANK_HSYNC_SUSPEND:
640 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
641 break;
642 /* Display: Off; HSync: On, VSync: Off */
643 case FB_BLANK_VSYNC_SUSPEND:
644 drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
645 break;
646 /* Display: Off; HSync: Off, VSync: Off */
647 case FB_BLANK_POWERDOWN:
648 drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
649 break;
650 }
651 return 0;
652 }
653 EXPORT_SYMBOL(drm_fb_helper_blank);
654 #endif
655
656 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
657 {
658 int i;
659
660 for (i = 0; i < helper->connector_count; i++)
661 kfree(helper->connector_info[i]);
662 kfree(helper->connector_info);
663 for (i = 0; i < helper->crtc_count; i++) {
664 kfree(helper->crtc_info[i].mode_set.connectors);
665 if (helper->crtc_info[i].mode_set.mode)
666 drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
667 }
668 kfree(helper->crtc_info);
669 }
670
671 /**
672 * drm_fb_helper_prepare - setup a drm_fb_helper structure
673 * @dev: DRM device
674 * @helper: driver-allocated fbdev helper structure to set up
675 * @funcs: pointer to structure of functions associate with this helper
676 *
677 * Sets up the bare minimum to make the framebuffer helper usable. This is
678 * useful to implement race-free initialization of the polling helpers.
679 */
680 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
681 const struct drm_fb_helper_funcs *funcs)
682 {
683 INIT_LIST_HEAD(&helper->kernel_fb_list);
684 helper->funcs = funcs;
685 helper->dev = dev;
686 }
687 EXPORT_SYMBOL(drm_fb_helper_prepare);
688
689 /**
690 * drm_fb_helper_init - initialize a drm_fb_helper structure
691 * @dev: drm device
692 * @fb_helper: driver-allocated fbdev helper structure to initialize
693 * @crtc_count: maximum number of crtcs to support in this fbdev emulation
694 * @max_conn_count: max connector count
695 *
696 * This allocates the structures for the fbdev helper with the given limits.
697 * Note that this won't yet touch the hardware (through the driver interfaces)
698 * nor register the fbdev. This is only done in drm_fb_helper_initial_config()
699 * to allow driver writes more control over the exact init sequence.
700 *
701 * Drivers must call drm_fb_helper_prepare() before calling this function.
702 *
703 * RETURNS:
704 * Zero if everything went ok, nonzero otherwise.
705 */
706 int drm_fb_helper_init(struct drm_device *dev,
707 struct drm_fb_helper *fb_helper,
708 int crtc_count, int max_conn_count)
709 {
710 struct drm_crtc *crtc;
711 int i;
712
713 if (!drm_fbdev_emulation)
714 return 0;
715
716 if (!max_conn_count)
717 return -EINVAL;
718
719 fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
720 if (!fb_helper->crtc_info)
721 return -ENOMEM;
722
723 fb_helper->crtc_count = crtc_count;
724 fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
725 if (!fb_helper->connector_info) {
726 kfree(fb_helper->crtc_info);
727 return -ENOMEM;
728 }
729 fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
730 fb_helper->connector_count = 0;
731
732 for (i = 0; i < crtc_count; i++) {
733 fb_helper->crtc_info[i].mode_set.connectors =
734 kcalloc(max_conn_count,
735 sizeof(struct drm_connector *),
736 GFP_KERNEL);
737
738 if (!fb_helper->crtc_info[i].mode_set.connectors)
739 goto out_free;
740 fb_helper->crtc_info[i].mode_set.num_connectors = 0;
741 }
742
743 i = 0;
744 drm_for_each_crtc(crtc, dev) {
745 fb_helper->crtc_info[i].mode_set.crtc = crtc;
746 i++;
747 }
748
749 fb_helper->atomic = !!drm_core_check_feature(dev, DRIVER_ATOMIC);
750
751 return 0;
752 out_free:
753 drm_fb_helper_crtc_free(fb_helper);
754 return -ENOMEM;
755 }
756 EXPORT_SYMBOL(drm_fb_helper_init);
757
758 #ifndef __NetBSD__ /* XXX fb info */
759
760 /**
761 * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members
762 * @fb_helper: driver-allocated fbdev helper
763 *
764 * A helper to alloc fb_info and the members cmap and apertures. Called
765 * by the driver within the fb_probe fb_helper callback function.
766 *
767 * RETURNS:
768 * fb_info pointer if things went okay, pointer containing error code
769 * otherwise
770 */
771 struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
772 {
773 struct device *dev = fb_helper->dev->dev;
774 struct fb_info *info;
775 int ret;
776
777 info = framebuffer_alloc(0, dev);
778 if (!info)
779 return ERR_PTR(-ENOMEM);
780
781 ret = fb_alloc_cmap(&info->cmap, 256, 0);
782 if (ret)
783 goto err_release;
784
785 info->apertures = alloc_apertures(1);
786 if (!info->apertures) {
787 ret = -ENOMEM;
788 goto err_free_cmap;
789 }
790
791 fb_helper->fbdev = info;
792
793 return info;
794
795 err_free_cmap:
796 fb_dealloc_cmap(&info->cmap);
797 err_release:
798 framebuffer_release(info);
799 return ERR_PTR(ret);
800 }
801 EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
802
803 /**
804 * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device
805 * @fb_helper: driver-allocated fbdev helper
806 *
807 * A wrapper around unregister_framebuffer, to release the fb_info
808 * framebuffer device
809 */
810 void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
811 {
812 if (fb_helper && fb_helper->fbdev)
813 unregister_framebuffer(fb_helper->fbdev);
814 }
815 EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
816
817 /**
818 * drm_fb_helper_release_fbi - dealloc fb_info and its members
819 * @fb_helper: driver-allocated fbdev helper
820 *
821 * A helper to free memory taken by fb_info and the members cmap and
822 * apertures
823 */
824 void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper)
825 {
826 if (fb_helper) {
827 struct fb_info *info = fb_helper->fbdev;
828
829 if (info) {
830 if (info->cmap.len)
831 fb_dealloc_cmap(&info->cmap);
832 framebuffer_release(info);
833 }
834
835 fb_helper->fbdev = NULL;
836 }
837 }
838 EXPORT_SYMBOL(drm_fb_helper_release_fbi);
839
840 #endif /* __NetBSD__ */
841
842 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
843 {
844 if (!drm_fbdev_emulation)
845 return;
846
847 if (!list_empty(&fb_helper->kernel_fb_list)) {
848 list_del(&fb_helper->kernel_fb_list);
849 if (list_empty(&kernel_fb_helper_list)) {
850 #ifndef __NetBSD__ /* XXX drm sysrq */
851 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
852 #endif
853 }
854 }
855
856 drm_fb_helper_crtc_free(fb_helper);
857
858 }
859 EXPORT_SYMBOL(drm_fb_helper_fini);
860
861 #ifdef __NetBSD__ /* XXX fb info */
862 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state)
863 {
864 }
865 #else
866 /**
867 * drm_fb_helper_unlink_fbi - wrapper around unlink_framebuffer
868 * @fb_helper: driver-allocated fbdev helper
869 *
870 * A wrapper around unlink_framebuffer implemented by fbdev core
871 */
872 void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
873 {
874 if (fb_helper && fb_helper->fbdev)
875 unlink_framebuffer(fb_helper->fbdev);
876 }
877 EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
878
879 /**
880 * drm_fb_helper_sys_read - wrapper around fb_sys_read
881 * @info: fb_info struct pointer
882 * @buf: userspace buffer to read from framebuffer memory
883 * @count: number of bytes to read from framebuffer memory
884 * @ppos: read offset within framebuffer memory
885 *
886 * A wrapper around fb_sys_read implemented by fbdev core
887 */
888 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
889 size_t count, loff_t *ppos)
890 {
891 return fb_sys_read(info, buf, count, ppos);
892 }
893 EXPORT_SYMBOL(drm_fb_helper_sys_read);
894
895 /**
896 * drm_fb_helper_sys_write - wrapper around fb_sys_write
897 * @info: fb_info struct pointer
898 * @buf: userspace buffer to write to framebuffer memory
899 * @count: number of bytes to write to framebuffer memory
900 * @ppos: write offset within framebuffer memory
901 *
902 * A wrapper around fb_sys_write implemented by fbdev core
903 */
904 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
905 size_t count, loff_t *ppos)
906 {
907 return fb_sys_write(info, buf, count, ppos);
908 }
909 EXPORT_SYMBOL(drm_fb_helper_sys_write);
910
911 /**
912 * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect
913 * @info: fbdev registered by the helper
914 * @rect: info about rectangle to fill
915 *
916 * A wrapper around sys_fillrect implemented by fbdev core
917 */
918 void drm_fb_helper_sys_fillrect(struct fb_info *info,
919 const struct fb_fillrect *rect)
920 {
921 sys_fillrect(info, rect);
922 }
923 EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
924
925 /**
926 * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea
927 * @info: fbdev registered by the helper
928 * @area: info about area to copy
929 *
930 * A wrapper around sys_copyarea implemented by fbdev core
931 */
932 void drm_fb_helper_sys_copyarea(struct fb_info *info,
933 const struct fb_copyarea *area)
934 {
935 sys_copyarea(info, area);
936 }
937 EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
938
939 /**
940 * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit
941 * @info: fbdev registered by the helper
942 * @image: info about image to blit
943 *
944 * A wrapper around sys_imageblit implemented by fbdev core
945 */
946 void drm_fb_helper_sys_imageblit(struct fb_info *info,
947 const struct fb_image *image)
948 {
949 sys_imageblit(info, image);
950 }
951 EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
952
953 /**
954 * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect
955 * @info: fbdev registered by the helper
956 * @rect: info about rectangle to fill
957 *
958 * A wrapper around cfb_imageblit implemented by fbdev core
959 */
960 void drm_fb_helper_cfb_fillrect(struct fb_info *info,
961 const struct fb_fillrect *rect)
962 {
963 cfb_fillrect(info, rect);
964 }
965 EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
966
967 /**
968 * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea
969 * @info: fbdev registered by the helper
970 * @area: info about area to copy
971 *
972 * A wrapper around cfb_copyarea implemented by fbdev core
973 */
974 void drm_fb_helper_cfb_copyarea(struct fb_info *info,
975 const struct fb_copyarea *area)
976 {
977 cfb_copyarea(info, area);
978 }
979 EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
980
981 /**
982 * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit
983 * @info: fbdev registered by the helper
984 * @image: info about image to blit
985 *
986 * A wrapper around cfb_imageblit implemented by fbdev core
987 */
988 void drm_fb_helper_cfb_imageblit(struct fb_info *info,
989 const struct fb_image *image)
990 {
991 cfb_imageblit(info, image);
992 }
993 EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
994
995 /**
996 * drm_fb_helper_set_suspend - wrapper around fb_set_suspend
997 * @fb_helper: driver-allocated fbdev helper
998 * @state: desired state, zero to resume, non-zero to suspend
999 *
1000 * A wrapper around fb_set_suspend implemented by fbdev core
1001 */
1002 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state)
1003 {
1004 if (fb_helper && fb_helper->fbdev)
1005 fb_set_suspend(fb_helper->fbdev, state);
1006 }
1007 EXPORT_SYMBOL(drm_fb_helper_set_suspend);
1008
1009 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
1010 u16 blue, u16 regno, struct fb_info *info)
1011 {
1012 struct drm_fb_helper *fb_helper = info->par;
1013 struct drm_framebuffer *fb = fb_helper->fb;
1014 int pindex;
1015
1016 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
1017 u32 *palette;
1018 u32 value;
1019 /* place color in psuedopalette */
1020 if (regno > 16)
1021 return -EINVAL;
1022 palette = (u32 *)info->pseudo_palette;
1023 red >>= (16 - info->var.red.length);
1024 green >>= (16 - info->var.green.length);
1025 blue >>= (16 - info->var.blue.length);
1026 value = (red << info->var.red.offset) |
1027 (green << info->var.green.offset) |
1028 (blue << info->var.blue.offset);
1029 if (info->var.transp.length > 0) {
1030 u32 mask = (1 << info->var.transp.length) - 1;
1031 mask <<= info->var.transp.offset;
1032 value |= mask;
1033 }
1034 palette[regno] = value;
1035 return 0;
1036 }
1037
1038 /*
1039 * The driver really shouldn't advertise pseudo/directcolor
1040 * visuals if it can't deal with the palette.
1041 */
1042 if (WARN_ON(!fb_helper->funcs->gamma_set ||
1043 !fb_helper->funcs->gamma_get))
1044 return -EINVAL;
1045
1046 pindex = regno;
1047
1048 if (fb->bits_per_pixel == 16) {
1049 pindex = regno << 3;
1050
1051 if (fb->depth == 16 && regno > 63)
1052 return -EINVAL;
1053 if (fb->depth == 15 && regno > 31)
1054 return -EINVAL;
1055
1056 if (fb->depth == 16) {
1057 u16 r, g, b;
1058 int i;
1059 if (regno < 32) {
1060 for (i = 0; i < 8; i++)
1061 fb_helper->funcs->gamma_set(crtc, red,
1062 green, blue, pindex + i);
1063 }
1064
1065 fb_helper->funcs->gamma_get(crtc, &r,
1066 &g, &b,
1067 pindex >> 1);
1068
1069 for (i = 0; i < 4; i++)
1070 fb_helper->funcs->gamma_set(crtc, r,
1071 green, b,
1072 (pindex >> 1) + i);
1073 }
1074 }
1075
1076 if (fb->depth != 16)
1077 fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
1078 return 0;
1079 }
1080
1081 /**
1082 * drm_fb_helper_setcmap - implementation for ->fb_setcmap
1083 * @cmap: cmap to set
1084 * @info: fbdev registered by the helper
1085 */
1086 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1087 {
1088 struct drm_fb_helper *fb_helper = info->par;
1089 struct drm_device *dev = fb_helper->dev;
1090 const struct drm_crtc_helper_funcs *crtc_funcs;
1091 u16 *red, *green, *blue, *transp;
1092 struct drm_crtc *crtc;
1093 int i, j, rc = 0;
1094 int start;
1095
1096 if (oops_in_progress)
1097 return -EBUSY;
1098
1099 drm_modeset_lock_all(dev);
1100 if (!drm_fb_helper_is_bound(fb_helper)) {
1101 drm_modeset_unlock_all(dev);
1102 return -EBUSY;
1103 }
1104
1105 for (i = 0; i < fb_helper->crtc_count; i++) {
1106 crtc = fb_helper->crtc_info[i].mode_set.crtc;
1107 crtc_funcs = crtc->helper_private;
1108
1109 red = cmap->red;
1110 green = cmap->green;
1111 blue = cmap->blue;
1112 transp = cmap->transp;
1113 start = cmap->start;
1114
1115 for (j = 0; j < cmap->len; j++) {
1116 u16 hred, hgreen, hblue, htransp = 0xffff;
1117
1118 hred = *red++;
1119 hgreen = *green++;
1120 hblue = *blue++;
1121
1122 if (transp)
1123 htransp = *transp++;
1124
1125 rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
1126 if (rc)
1127 goto out;
1128 }
1129 if (crtc_funcs->load_lut)
1130 crtc_funcs->load_lut(crtc);
1131 }
1132 out:
1133 drm_modeset_unlock_all(dev);
1134 return rc;
1135 }
1136 EXPORT_SYMBOL(drm_fb_helper_setcmap);
1137
1138 /**
1139 * drm_fb_helper_check_var - implementation for ->fb_check_var
1140 * @var: screeninfo to check
1141 * @info: fbdev registered by the helper
1142 */
1143 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
1144 struct fb_info *info)
1145 {
1146 struct drm_fb_helper *fb_helper = info->par;
1147 struct drm_framebuffer *fb = fb_helper->fb;
1148 int depth;
1149
1150 if (var->pixclock != 0 || in_dbg_master())
1151 return -EINVAL;
1152
1153 /* Need to resize the fb object !!! */
1154 if (var->bits_per_pixel > fb->bits_per_pixel ||
1155 var->xres > fb->width || var->yres > fb->height ||
1156 var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
1157 DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
1158 "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
1159 var->xres, var->yres, var->bits_per_pixel,
1160 var->xres_virtual, var->yres_virtual,
1161 fb->width, fb->height, fb->bits_per_pixel);
1162 return -EINVAL;
1163 }
1164
1165 switch (var->bits_per_pixel) {
1166 case 16:
1167 depth = (var->green.length == 6) ? 16 : 15;
1168 break;
1169 case 32:
1170 depth = (var->transp.length > 0) ? 32 : 24;
1171 break;
1172 default:
1173 depth = var->bits_per_pixel;
1174 break;
1175 }
1176
1177 switch (depth) {
1178 case 8:
1179 var->red.offset = 0;
1180 var->green.offset = 0;
1181 var->blue.offset = 0;
1182 var->red.length = 8;
1183 var->green.length = 8;
1184 var->blue.length = 8;
1185 var->transp.length = 0;
1186 var->transp.offset = 0;
1187 break;
1188 case 15:
1189 var->red.offset = 10;
1190 var->green.offset = 5;
1191 var->blue.offset = 0;
1192 var->red.length = 5;
1193 var->green.length = 5;
1194 var->blue.length = 5;
1195 var->transp.length = 1;
1196 var->transp.offset = 15;
1197 break;
1198 case 16:
1199 var->red.offset = 11;
1200 var->green.offset = 5;
1201 var->blue.offset = 0;
1202 var->red.length = 5;
1203 var->green.length = 6;
1204 var->blue.length = 5;
1205 var->transp.length = 0;
1206 var->transp.offset = 0;
1207 break;
1208 case 24:
1209 var->red.offset = 16;
1210 var->green.offset = 8;
1211 var->blue.offset = 0;
1212 var->red.length = 8;
1213 var->green.length = 8;
1214 var->blue.length = 8;
1215 var->transp.length = 0;
1216 var->transp.offset = 0;
1217 break;
1218 case 32:
1219 var->red.offset = 16;
1220 var->green.offset = 8;
1221 var->blue.offset = 0;
1222 var->red.length = 8;
1223 var->green.length = 8;
1224 var->blue.length = 8;
1225 var->transp.length = 8;
1226 var->transp.offset = 24;
1227 break;
1228 default:
1229 return -EINVAL;
1230 }
1231 return 0;
1232 }
1233 EXPORT_SYMBOL(drm_fb_helper_check_var);
1234 #endif
1235
1236 #ifndef __NetBSD__ /* XXX fb info */
1237 /**
1238 * drm_fb_helper_set_par - implementation for ->fb_set_par
1239 * @info: fbdev registered by the helper
1240 *
1241 * This will let fbcon do the mode init and is called at initialization time by
1242 * the fbdev core when registering the driver, and later on through the hotplug
1243 * callback.
1244 */
1245 int drm_fb_helper_set_par(struct fb_info *info)
1246 {
1247 struct drm_fb_helper *fb_helper = info->par;
1248 struct fb_var_screeninfo *var = &info->var;
1249
1250 if (oops_in_progress)
1251 return -EBUSY;
1252
1253 if (var->pixclock != 0) {
1254 DRM_ERROR("PIXEL CLOCK SET\n");
1255 return -EINVAL;
1256 }
1257
1258 drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
1259
1260 return 0;
1261 }
1262 EXPORT_SYMBOL(drm_fb_helper_set_par);
1263
1264 static int pan_display_atomic(struct fb_var_screeninfo *var,
1265 struct fb_info *info)
1266 {
1267 struct drm_fb_helper *fb_helper = info->par;
1268 struct drm_device *dev = fb_helper->dev;
1269 struct drm_atomic_state *state;
1270 struct drm_plane *plane;
1271 int i, ret;
1272 unsigned plane_mask;
1273
1274 state = drm_atomic_state_alloc(dev);
1275 if (!state)
1276 return -ENOMEM;
1277
1278 state->acquire_ctx = dev->mode_config.acquire_ctx;
1279 retry:
1280 plane_mask = 0;
1281 for(i = 0; i < fb_helper->crtc_count; i++) {
1282 struct drm_mode_set *mode_set;
1283
1284 mode_set = &fb_helper->crtc_info[i].mode_set;
1285
1286 mode_set->x = var->xoffset;
1287 mode_set->y = var->yoffset;
1288
1289 ret = __drm_atomic_helper_set_config(mode_set, state);
1290 if (ret != 0)
1291 goto fail;
1292
1293 plane = mode_set->crtc->primary;
1294 plane_mask |= drm_plane_index(plane);
1295 plane->old_fb = plane->fb;
1296 }
1297
1298 ret = drm_atomic_commit(state);
1299 if (ret != 0)
1300 goto fail;
1301
1302 info->var.xoffset = var->xoffset;
1303 info->var.yoffset = var->yoffset;
1304
1305
1306 fail:
1307 drm_atomic_clean_old_fb(dev, plane_mask, ret);
1308
1309 if (ret == -EDEADLK)
1310 goto backoff;
1311
1312 if (ret != 0)
1313 drm_atomic_state_free(state);
1314
1315 return ret;
1316
1317 backoff:
1318 drm_atomic_state_clear(state);
1319 drm_atomic_legacy_backoff(state);
1320
1321 goto retry;
1322 }
1323
1324 /**
1325 * drm_fb_helper_pan_display - implementation for ->fb_pan_display
1326 * @var: updated screen information
1327 * @info: fbdev registered by the helper
1328 */
1329 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
1330 struct fb_info *info)
1331 {
1332 struct drm_fb_helper *fb_helper = info->par;
1333 struct drm_device *dev = fb_helper->dev;
1334 struct drm_mode_set *modeset;
1335 int ret = 0;
1336 int i;
1337
1338 if (oops_in_progress)
1339 return -EBUSY;
1340
1341 drm_modeset_lock_all(dev);
1342 if (!drm_fb_helper_is_bound(fb_helper)) {
1343 drm_modeset_unlock_all(dev);
1344 return -EBUSY;
1345 }
1346
1347 if (fb_helper->atomic) {
1348 ret = pan_display_atomic(var, info);
1349 goto unlock;
1350 }
1351
1352 for (i = 0; i < fb_helper->crtc_count; i++) {
1353 modeset = &fb_helper->crtc_info[i].mode_set;
1354
1355 modeset->x = var->xoffset;
1356 modeset->y = var->yoffset;
1357
1358 if (modeset->num_connectors) {
1359 ret = drm_mode_set_config_internal(modeset);
1360 if (!ret) {
1361 info->var.xoffset = var->xoffset;
1362 info->var.yoffset = var->yoffset;
1363 }
1364 }
1365 }
1366 unlock:
1367 drm_modeset_unlock_all(dev);
1368 return ret;
1369 }
1370 EXPORT_SYMBOL(drm_fb_helper_pan_display);
1371 #endif
1372
1373 /*
1374 * Allocates the backing storage and sets up the fbdev info structure through
1375 * the ->fb_probe callback and then registers the fbdev and sets up the panic
1376 * notifier.
1377 */
1378 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
1379 int preferred_bpp)
1380 {
1381 int ret = 0;
1382 int crtc_count = 0;
1383 int i;
1384 #ifndef __NetBSD__ /* XXX fb info */
1385 struct fb_info *info;
1386 #endif
1387 struct drm_fb_helper_surface_size sizes;
1388 int gamma_size = 0;
1389
1390 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
1391 sizes.surface_depth = 24;
1392 sizes.surface_bpp = 32;
1393 sizes.fb_width = (unsigned)-1;
1394 sizes.fb_height = (unsigned)-1;
1395
1396 /* if driver picks 8 or 16 by default use that
1397 for both depth/bpp */
1398 if (preferred_bpp != sizes.surface_bpp)
1399 sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
1400
1401 /* first up get a count of crtcs now in use and new min/maxes width/heights */
1402 for (i = 0; i < fb_helper->connector_count; i++) {
1403 struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
1404 struct drm_cmdline_mode *cmdline_mode;
1405
1406 cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
1407
1408 if (cmdline_mode->bpp_specified) {
1409 switch (cmdline_mode->bpp) {
1410 case 8:
1411 sizes.surface_depth = sizes.surface_bpp = 8;
1412 break;
1413 case 15:
1414 sizes.surface_depth = 15;
1415 sizes.surface_bpp = 16;
1416 break;
1417 case 16:
1418 sizes.surface_depth = sizes.surface_bpp = 16;
1419 break;
1420 case 24:
1421 sizes.surface_depth = sizes.surface_bpp = 24;
1422 break;
1423 case 32:
1424 sizes.surface_depth = 24;
1425 sizes.surface_bpp = 32;
1426 break;
1427 }
1428 break;
1429 }
1430 }
1431
1432 crtc_count = 0;
1433 for (i = 0; i < fb_helper->crtc_count; i++) {
1434 struct drm_display_mode *desired_mode;
1435 struct drm_mode_set *mode_set;
1436 int x, y, j;
1437 /* in case of tile group, are we the last tile vert or horiz?
1438 * If no tile group you are always the last one both vertically
1439 * and horizontally
1440 */
1441 bool lastv = true, lasth = true;
1442
1443 desired_mode = fb_helper->crtc_info[i].desired_mode;
1444 mode_set = &fb_helper->crtc_info[i].mode_set;
1445
1446 if (!desired_mode)
1447 continue;
1448
1449 crtc_count++;
1450
1451 x = fb_helper->crtc_info[i].x;
1452 y = fb_helper->crtc_info[i].y;
1453
1454 if (gamma_size == 0)
1455 gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
1456
1457 sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
1458 sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
1459
1460 for (j = 0; j < mode_set->num_connectors; j++) {
1461 struct drm_connector *connector = mode_set->connectors[j];
1462 if (connector->has_tile) {
1463 lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
1464 lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
1465 /* cloning to multiple tiles is just crazy-talk, so: */
1466 break;
1467 }
1468 }
1469
1470 if (lasth)
1471 sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
1472 if (lastv)
1473 sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
1474 }
1475
1476 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1477 /* hmm everyone went away - assume VGA cable just fell out
1478 and will come back later. */
1479 DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
1480 sizes.fb_width = sizes.surface_width = 1024;
1481 sizes.fb_height = sizes.surface_height = 768;
1482 }
1483
1484 /* push down into drivers */
1485 ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
1486 if (ret < 0)
1487 return ret;
1488
1489 #ifndef __NetBSD__ /* XXX fb info */
1490 info = fb_helper->fbdev;
1491 #endif
1492
1493 /*
1494 * Set the fb pointer - usually drm_setup_crtcs does this for hotplug
1495 * events, but at init time drm_setup_crtcs needs to be called before
1496 * the fb is allocated (since we need to figure out the desired size of
1497 * the fb before we can allocate it ...). Hence we need to fix things up
1498 * here again.
1499 */
1500 for (i = 0; i < fb_helper->crtc_count; i++)
1501 if (fb_helper->crtc_info[i].mode_set.num_connectors)
1502 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
1503
1504 #ifndef __NetBSD__ /* XXX fb info */
1505 info->var.pixclock = 0;
1506 if (register_framebuffer(info) < 0)
1507 return -EINVAL;
1508
1509 dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
1510 info->node, info->fix.id);
1511 #endif
1512
1513 if (list_empty(&kernel_fb_helper_list)) {
1514 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
1515 }
1516
1517 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
1518
1519 return 0;
1520 }
1521
1522 #ifndef __NetBSD__ /* XXX fb info */
1523 /**
1524 * drm_fb_helper_fill_fix - initializes fixed fbdev information
1525 * @info: fbdev registered by the helper
1526 * @pitch: desired pitch
1527 * @depth: desired depth
1528 *
1529 * Helper to fill in the fixed fbdev information useful for a non-accelerated
1530 * fbdev emulations. Drivers which support acceleration methods which impose
1531 * additional constraints need to set up their own limits.
1532 *
1533 * Drivers should call this (or their equivalent setup code) from their
1534 * ->fb_probe callback.
1535 */
1536 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
1537 uint32_t depth)
1538 {
1539 info->fix.type = FB_TYPE_PACKED_PIXELS;
1540 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1541 FB_VISUAL_TRUECOLOR;
1542 info->fix.mmio_start = 0;
1543 info->fix.mmio_len = 0;
1544 info->fix.type_aux = 0;
1545 info->fix.xpanstep = 1; /* doing it in hw */
1546 info->fix.ypanstep = 1; /* doing it in hw */
1547 info->fix.ywrapstep = 0;
1548 info->fix.accel = FB_ACCEL_NONE;
1549
1550 info->fix.line_length = pitch;
1551 return;
1552 }
1553 EXPORT_SYMBOL(drm_fb_helper_fill_fix);
1554
1555 /**
1556 * drm_fb_helper_fill_var - initalizes variable fbdev information
1557 * @info: fbdev instance to set up
1558 * @fb_helper: fb helper instance to use as template
1559 * @fb_width: desired fb width
1560 * @fb_height: desired fb height
1561 *
1562 * Sets up the variable fbdev metainformation from the given fb helper instance
1563 * and the drm framebuffer allocated in fb_helper->fb.
1564 *
1565 * Drivers should call this (or their equivalent setup code) from their
1566 * ->fb_probe callback after having allocated the fbdev backing
1567 * storage framebuffer.
1568 */
1569 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
1570 uint32_t fb_width, uint32_t fb_height)
1571 {
1572 struct drm_framebuffer *fb = fb_helper->fb;
1573 info->pseudo_palette = fb_helper->pseudo_palette;
1574 info->var.xres_virtual = fb->width;
1575 info->var.yres_virtual = fb->height;
1576 info->var.bits_per_pixel = fb->bits_per_pixel;
1577 info->var.accel_flags = FB_ACCELF_TEXT;
1578 info->var.xoffset = 0;
1579 info->var.yoffset = 0;
1580 info->var.activate = FB_ACTIVATE_NOW;
1581 info->var.height = -1;
1582 info->var.width = -1;
1583
1584 switch (fb->depth) {
1585 case 8:
1586 info->var.red.offset = 0;
1587 info->var.green.offset = 0;
1588 info->var.blue.offset = 0;
1589 info->var.red.length = 8; /* 8bit DAC */
1590 info->var.green.length = 8;
1591 info->var.blue.length = 8;
1592 info->var.transp.offset = 0;
1593 info->var.transp.length = 0;
1594 break;
1595 case 15:
1596 info->var.red.offset = 10;
1597 info->var.green.offset = 5;
1598 info->var.blue.offset = 0;
1599 info->var.red.length = 5;
1600 info->var.green.length = 5;
1601 info->var.blue.length = 5;
1602 info->var.transp.offset = 15;
1603 info->var.transp.length = 1;
1604 break;
1605 case 16:
1606 info->var.red.offset = 11;
1607 info->var.green.offset = 5;
1608 info->var.blue.offset = 0;
1609 info->var.red.length = 5;
1610 info->var.green.length = 6;
1611 info->var.blue.length = 5;
1612 info->var.transp.offset = 0;
1613 break;
1614 case 24:
1615 info->var.red.offset = 16;
1616 info->var.green.offset = 8;
1617 info->var.blue.offset = 0;
1618 info->var.red.length = 8;
1619 info->var.green.length = 8;
1620 info->var.blue.length = 8;
1621 info->var.transp.offset = 0;
1622 info->var.transp.length = 0;
1623 break;
1624 case 32:
1625 info->var.red.offset = 16;
1626 info->var.green.offset = 8;
1627 info->var.blue.offset = 0;
1628 info->var.red.length = 8;
1629 info->var.green.length = 8;
1630 info->var.blue.length = 8;
1631 info->var.transp.offset = 24;
1632 info->var.transp.length = 8;
1633 break;
1634 default:
1635 break;
1636 }
1637
1638 info->var.xres = fb_width;
1639 info->var.yres = fb_height;
1640 }
1641 EXPORT_SYMBOL(drm_fb_helper_fill_var);
1642 #endif
1643
1644 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
1645 uint32_t maxX,
1646 uint32_t maxY)
1647 {
1648 struct drm_connector *connector;
1649 int count = 0;
1650 int i;
1651
1652 for (i = 0; i < fb_helper->connector_count; i++) {
1653 connector = fb_helper->connector_info[i]->connector;
1654 count += connector->funcs->fill_modes(connector, maxX, maxY);
1655 }
1656
1657 return count;
1658 }
1659
1660 struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
1661 {
1662 struct drm_display_mode *mode;
1663
1664 list_for_each_entry(mode, &fb_connector->connector->modes, head) {
1665 if (mode->hdisplay > width ||
1666 mode->vdisplay > height)
1667 continue;
1668 if (mode->type & DRM_MODE_TYPE_PREFERRED)
1669 return mode;
1670 }
1671 return NULL;
1672 }
1673 EXPORT_SYMBOL(drm_has_preferred_mode);
1674
1675 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
1676 {
1677 return fb_connector->connector->cmdline_mode.specified;
1678 }
1679
1680 struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
1681 int width, int height)
1682 {
1683 struct drm_cmdline_mode *cmdline_mode;
1684 struct drm_display_mode *mode;
1685 bool prefer_non_interlace;
1686
1687 cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
1688 if (cmdline_mode->specified == false)
1689 return NULL;
1690
1691 /* attempt to find a matching mode in the list of modes
1692 * we have gotten so far, if not add a CVT mode that conforms
1693 */
1694 if (cmdline_mode->rb || cmdline_mode->margins)
1695 goto create_mode;
1696
1697 prefer_non_interlace = !cmdline_mode->interlace;
1698 again:
1699 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1700 /* check width/height */
1701 if (mode->hdisplay != cmdline_mode->xres ||
1702 mode->vdisplay != cmdline_mode->yres)
1703 continue;
1704
1705 if (cmdline_mode->refresh_specified) {
1706 if (mode->vrefresh != cmdline_mode->refresh)
1707 continue;
1708 }
1709
1710 if (cmdline_mode->interlace) {
1711 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
1712 continue;
1713 } else if (prefer_non_interlace) {
1714 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1715 continue;
1716 }
1717 return mode;
1718 }
1719
1720 if (prefer_non_interlace) {
1721 prefer_non_interlace = false;
1722 goto again;
1723 }
1724
1725 create_mode:
1726 mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
1727 cmdline_mode);
1728 list_add(&mode->head, &fb_helper_conn->connector->modes);
1729 return mode;
1730 }
1731 EXPORT_SYMBOL(drm_pick_cmdline_mode);
1732
1733 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1734 {
1735 bool enable;
1736
1737 if (strict)
1738 enable = connector->status == connector_status_connected;
1739 else
1740 enable = connector->status != connector_status_disconnected;
1741
1742 return enable;
1743 }
1744
1745 static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
1746 bool *enabled)
1747 {
1748 bool any_enabled = false;
1749 struct drm_connector *connector;
1750 int i = 0;
1751
1752 for (i = 0; i < fb_helper->connector_count; i++) {
1753 connector = fb_helper->connector_info[i]->connector;
1754 enabled[i] = drm_connector_enabled(connector, true);
1755 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
1756 enabled[i] ? "yes" : "no");
1757 any_enabled |= enabled[i];
1758 }
1759
1760 if (any_enabled)
1761 return;
1762
1763 for (i = 0; i < fb_helper->connector_count; i++) {
1764 connector = fb_helper->connector_info[i]->connector;
1765 enabled[i] = drm_connector_enabled(connector, false);
1766 }
1767 }
1768
1769 static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
1770 struct drm_display_mode **modes,
1771 struct drm_fb_offset *offsets,
1772 bool *enabled, int width, int height)
1773 {
1774 int count, i, j;
1775 bool can_clone = false;
1776 struct drm_fb_helper_connector *fb_helper_conn;
1777 struct drm_display_mode *dmt_mode, *mode;
1778
1779 /* only contemplate cloning in the single crtc case */
1780 if (fb_helper->crtc_count > 1)
1781 return false;
1782
1783 count = 0;
1784 for (i = 0; i < fb_helper->connector_count; i++) {
1785 if (enabled[i])
1786 count++;
1787 }
1788
1789 /* only contemplate cloning if more than one connector is enabled */
1790 if (count <= 1)
1791 return false;
1792
1793 /* check the command line or if nothing common pick 1024x768 */
1794 can_clone = true;
1795 for (i = 0; i < fb_helper->connector_count; i++) {
1796 if (!enabled[i])
1797 continue;
1798 fb_helper_conn = fb_helper->connector_info[i];
1799 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1800 if (!modes[i]) {
1801 can_clone = false;
1802 break;
1803 }
1804 for (j = 0; j < i; j++) {
1805 if (!enabled[j])
1806 continue;
1807 if (!drm_mode_equal(modes[j], modes[i]))
1808 can_clone = false;
1809 }
1810 }
1811
1812 if (can_clone) {
1813 DRM_DEBUG_KMS("can clone using command line\n");
1814 return true;
1815 }
1816
1817 /* try and find a 1024x768 mode on each connector */
1818 can_clone = true;
1819 dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
1820
1821 for (i = 0; i < fb_helper->connector_count; i++) {
1822
1823 if (!enabled[i])
1824 continue;
1825
1826 fb_helper_conn = fb_helper->connector_info[i];
1827 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1828 if (drm_mode_equal(mode, dmt_mode))
1829 modes[i] = mode;
1830 }
1831 if (!modes[i])
1832 can_clone = false;
1833 }
1834
1835 if (can_clone) {
1836 DRM_DEBUG_KMS("can clone using 1024x768\n");
1837 return true;
1838 }
1839 DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
1840 return false;
1841 }
1842
1843 static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
1844 struct drm_display_mode **modes,
1845 struct drm_fb_offset *offsets,
1846 int idx,
1847 int h_idx, int v_idx)
1848 {
1849 struct drm_fb_helper_connector *fb_helper_conn;
1850 int i;
1851 int hoffset = 0, voffset = 0;
1852
1853 for (i = 0; i < fb_helper->connector_count; i++) {
1854 fb_helper_conn = fb_helper->connector_info[i];
1855 if (!fb_helper_conn->connector->has_tile)
1856 continue;
1857
1858 if (!modes[i] && (h_idx || v_idx)) {
1859 DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
1860 fb_helper_conn->connector->base.id);
1861 continue;
1862 }
1863 if (fb_helper_conn->connector->tile_h_loc < h_idx)
1864 hoffset += modes[i]->hdisplay;
1865
1866 if (fb_helper_conn->connector->tile_v_loc < v_idx)
1867 voffset += modes[i]->vdisplay;
1868 }
1869 offsets[idx].x = hoffset;
1870 offsets[idx].y = voffset;
1871 DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
1872 return 0;
1873 }
1874
1875 static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
1876 struct drm_display_mode **modes,
1877 struct drm_fb_offset *offsets,
1878 bool *enabled, int width, int height)
1879 {
1880 struct drm_fb_helper_connector *fb_helper_conn;
1881 int i;
1882 uint64_t conn_configured = 0, mask;
1883 int tile_pass = 0;
1884 mask = (1 << fb_helper->connector_count) - 1;
1885 retry:
1886 for (i = 0; i < fb_helper->connector_count; i++) {
1887 fb_helper_conn = fb_helper->connector_info[i];
1888
1889 if (conn_configured & (1 << i))
1890 continue;
1891
1892 if (enabled[i] == false) {
1893 conn_configured |= (1 << i);
1894 continue;
1895 }
1896
1897 /* first pass over all the untiled connectors */
1898 if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
1899 continue;
1900
1901 if (tile_pass == 1) {
1902 if (fb_helper_conn->connector->tile_h_loc != 0 ||
1903 fb_helper_conn->connector->tile_v_loc != 0)
1904 continue;
1905
1906 } else {
1907 if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 &&
1908 fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
1909 /* if this tile_pass doesn't cover any of the tiles - keep going */
1910 continue;
1911
1912 /* find the tile offsets for this pass - need
1913 to find all tiles left and above */
1914 drm_get_tile_offsets(fb_helper, modes, offsets,
1915 i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
1916 }
1917 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
1918 fb_helper_conn->connector->base.id);
1919
1920 /* got for command line mode first */
1921 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1922 if (!modes[i]) {
1923 DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
1924 fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
1925 modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
1926 }
1927 /* No preferred modes, pick one off the list */
1928 if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
1929 list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
1930 break;
1931 }
1932 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
1933 "none");
1934 conn_configured |= (1 << i);
1935 }
1936
1937 if ((conn_configured & mask) != mask) {
1938 tile_pass++;
1939 goto retry;
1940 }
1941 return true;
1942 }
1943
1944 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
1945 struct drm_fb_helper_crtc **best_crtcs,
1946 struct drm_display_mode **modes,
1947 int n, int width, int height)
1948 {
1949 int c, o;
1950 struct drm_connector *connector;
1951 const struct drm_connector_helper_funcs *connector_funcs;
1952 struct drm_encoder *encoder;
1953 int my_score, best_score, score;
1954 struct drm_fb_helper_crtc **crtcs, *crtc;
1955 struct drm_fb_helper_connector *fb_helper_conn;
1956
1957 if (n == fb_helper->connector_count)
1958 return 0;
1959
1960 fb_helper_conn = fb_helper->connector_info[n];
1961 connector = fb_helper_conn->connector;
1962
1963 best_crtcs[n] = NULL;
1964 best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1965 if (modes[n] == NULL)
1966 return best_score;
1967
1968 crtcs = kzalloc(fb_helper->connector_count *
1969 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1970 if (!crtcs)
1971 return best_score;
1972
1973 my_score = 1;
1974 if (connector->status == connector_status_connected)
1975 my_score++;
1976 if (drm_has_cmdline_mode(fb_helper_conn))
1977 my_score++;
1978 if (drm_has_preferred_mode(fb_helper_conn, width, height))
1979 my_score++;
1980
1981 connector_funcs = connector->helper_private;
1982 encoder = connector_funcs->best_encoder(connector);
1983 if (!encoder)
1984 goto out;
1985
1986 /* select a crtc for this connector and then attempt to configure
1987 remaining connectors */
1988 for (c = 0; c < fb_helper->crtc_count; c++) {
1989 crtc = &fb_helper->crtc_info[c];
1990
1991 if ((encoder->possible_crtcs & (1 << c)) == 0)
1992 continue;
1993
1994 for (o = 0; o < n; o++)
1995 if (best_crtcs[o] == crtc)
1996 break;
1997
1998 if (o < n) {
1999 /* ignore cloning unless only a single crtc */
2000 if (fb_helper->crtc_count > 1)
2001 continue;
2002
2003 if (!drm_mode_equal(modes[o], modes[n]))
2004 continue;
2005 }
2006
2007 crtcs[n] = crtc;
2008 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
2009 score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
2010 width, height);
2011 if (score > best_score) {
2012 best_score = score;
2013 memcpy(best_crtcs, crtcs,
2014 fb_helper->connector_count *
2015 sizeof(struct drm_fb_helper_crtc *));
2016 }
2017 }
2018 out:
2019 kfree(crtcs);
2020 return best_score;
2021 }
2022
2023 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
2024 {
2025 struct drm_device *dev = fb_helper->dev;
2026 struct drm_fb_helper_crtc **crtcs;
2027 struct drm_display_mode **modes;
2028 struct drm_fb_offset *offsets;
2029 struct drm_mode_set *modeset;
2030 bool *enabled;
2031 int width, height;
2032 int i;
2033
2034 DRM_DEBUG_KMS("\n");
2035
2036 width = dev->mode_config.max_width;
2037 height = dev->mode_config.max_height;
2038
2039 crtcs = kcalloc(dev->mode_config.num_connector,
2040 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
2041 modes = kcalloc(dev->mode_config.num_connector,
2042 sizeof(struct drm_display_mode *), GFP_KERNEL);
2043 offsets = kcalloc(dev->mode_config.num_connector,
2044 sizeof(struct drm_fb_offset), GFP_KERNEL);
2045 enabled = kcalloc(dev->mode_config.num_connector,
2046 sizeof(bool), GFP_KERNEL);
2047 if (!crtcs || !modes || !enabled || !offsets) {
2048 DRM_ERROR("Memory allocation failed\n");
2049 goto out;
2050 }
2051
2052
2053 drm_enable_connectors(fb_helper, enabled);
2054
2055 if (!(fb_helper->funcs->initial_config &&
2056 fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
2057 offsets,
2058 enabled, width, height))) {
2059 memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
2060 memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
2061 memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0]));
2062
2063 if (!drm_target_cloned(fb_helper, modes, offsets,
2064 enabled, width, height) &&
2065 !drm_target_preferred(fb_helper, modes, offsets,
2066 enabled, width, height))
2067 DRM_ERROR("Unable to find initial modes\n");
2068
2069 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
2070 width, height);
2071
2072 drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
2073 }
2074
2075 /* need to set the modesets up here for use later */
2076 /* fill out the connector<->crtc mappings into the modesets */
2077 for (i = 0; i < fb_helper->crtc_count; i++) {
2078 modeset = &fb_helper->crtc_info[i].mode_set;
2079 modeset->num_connectors = 0;
2080 modeset->fb = NULL;
2081 }
2082
2083 for (i = 0; i < fb_helper->connector_count; i++) {
2084 struct drm_display_mode *mode = modes[i];
2085 struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
2086 struct drm_fb_offset *offset = &offsets[i];
2087
2088 if (mode && fb_crtc) {
2089 modeset = &fb_crtc->mode_set;
2090 DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
2091 mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
2092 fb_crtc->desired_mode = mode;
2093 fb_crtc->x = offset->x;
2094 fb_crtc->y = offset->y;
2095 if (modeset->mode)
2096 drm_mode_destroy(dev, modeset->mode);
2097 modeset->mode = drm_mode_duplicate(dev,
2098 fb_crtc->desired_mode);
2099 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
2100 modeset->fb = fb_helper->fb;
2101 modeset->x = offset->x;
2102 modeset->y = offset->y;
2103 }
2104 }
2105
2106 /* Clear out any old modes if there are no more connected outputs. */
2107 for (i = 0; i < fb_helper->crtc_count; i++) {
2108 modeset = &fb_helper->crtc_info[i].mode_set;
2109 if (modeset->num_connectors == 0) {
2110 BUG_ON(modeset->fb);
2111 if (modeset->mode)
2112 drm_mode_destroy(dev, modeset->mode);
2113 modeset->mode = NULL;
2114 fb_helper->crtc_info[i].desired_mode = NULL;
2115 }
2116 }
2117 out:
2118 kfree(crtcs);
2119 kfree(modes);
2120 kfree(offsets);
2121 kfree(enabled);
2122 }
2123
2124 /**
2125 * drm_fb_helper_initial_config - setup a sane initial connector configuration
2126 * @fb_helper: fb_helper device struct
2127 * @bpp_sel: bpp value to use for the framebuffer configuration
2128 *
2129 * Scans the CRTCs and connectors and tries to put together an initial setup.
2130 * At the moment, this is a cloned configuration across all heads with
2131 * a new framebuffer object as the backing store.
2132 *
2133 * Note that this also registers the fbdev and so allows userspace to call into
2134 * the driver through the fbdev interfaces.
2135 *
2136 * This function will call down into the ->fb_probe callback to let
2137 * the driver allocate and initialize the fbdev info structure and the drm
2138 * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
2139 * drm_fb_helper_fill_fix() are provided as helpers to setup simple default
2140 * values for the fbdev info structure.
2141 *
2142 * RETURNS:
2143 * Zero if everything went ok, nonzero otherwise.
2144 */
2145 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
2146 {
2147 struct drm_device *dev = fb_helper->dev;
2148 int count = 0;
2149
2150 if (!drm_fbdev_emulation)
2151 return 0;
2152
2153 mutex_lock(&dev->mode_config.mutex);
2154 count = drm_fb_helper_probe_connector_modes(fb_helper,
2155 dev->mode_config.max_width,
2156 dev->mode_config.max_height);
2157 mutex_unlock(&dev->mode_config.mutex);
2158 /*
2159 * we shouldn't end up with no modes here.
2160 */
2161 if (count == 0)
2162 dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n");
2163
2164 drm_setup_crtcs(fb_helper);
2165
2166 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
2167 }
2168 EXPORT_SYMBOL(drm_fb_helper_initial_config);
2169
2170 /**
2171 * drm_fb_helper_hotplug_event - respond to a hotplug notification by
2172 * probing all the outputs attached to the fb
2173 * @fb_helper: the drm_fb_helper
2174 *
2175 * Scan the connectors attached to the fb_helper and try to put together a
2176 * setup after *notification of a change in output configuration.
2177 *
2178 * Called at runtime, takes the mode config locks to be able to check/change the
2179 * modeset configuration. Must be run from process context (which usually means
2180 * either the output polling work or a work item launched from the driver's
2181 * hotplug interrupt).
2182 *
2183 * Note that drivers may call this even before calling
2184 * drm_fb_helper_initial_config but only aftert drm_fb_helper_init. This allows
2185 * for a race-free fbcon setup and will make sure that the fbdev emulation will
2186 * not miss any hotplug events.
2187 *
2188 * RETURNS:
2189 * 0 on success and a non-zero error code otherwise.
2190 */
2191 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
2192 {
2193 struct drm_device *dev = fb_helper->dev;
2194 u32 max_width, max_height;
2195
2196 if (!drm_fbdev_emulation)
2197 return 0;
2198
2199 mutex_lock(&fb_helper->dev->mode_config.mutex);
2200 if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
2201 fb_helper->delayed_hotplug = true;
2202 mutex_unlock(&fb_helper->dev->mode_config.mutex);
2203 return 0;
2204 }
2205 DRM_DEBUG_KMS("\n");
2206
2207 max_width = fb_helper->fb->width;
2208 max_height = fb_helper->fb->height;
2209
2210 drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height);
2211 mutex_unlock(&fb_helper->dev->mode_config.mutex);
2212
2213 drm_modeset_lock_all(dev);
2214 drm_setup_crtcs(fb_helper);
2215 drm_modeset_unlock_all(dev);
2216 #ifdef __NetBSD__
2217 drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
2218 #else
2219 drm_fb_helper_set_par(fb_helper->fbdev);
2220 #endif
2221
2222 return 0;
2223 }
2224 EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
2225
2226 /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
2227 * but the module doesn't depend on any fb console symbols. At least
2228 * attempt to load fbcon to avoid leaving the system without a usable console.
2229 */
2230 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
2231 static int __init drm_fb_helper_modinit(void)
2232 {
2233 const char *name = "fbcon";
2234 struct module *fbcon;
2235
2236 mutex_lock(&module_mutex);
2237 fbcon = find_module(name);
2238 mutex_unlock(&module_mutex);
2239
2240 if (!fbcon)
2241 request_module_nowait(name);
2242 return 0;
2243 }
2244
2245 module_init(drm_fb_helper_modinit);
2246 #endif
2247