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