xref: /openbsd-src/sys/dev/pci/drm/drm_fb_helper.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: drm_fb_helper.c,v 1.11 2015/09/27 21:28:14 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2006-2009 Red Hat Inc.
4  * Copyright (c) 2006-2008 Intel Corporation
5  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
6  *
7  * DRM framebuffer helper functions
8  *
9  * Permission to use, copy, modify, distribute, and sell this software and its
10  * documentation for any purpose is hereby granted without fee, provided that
11  * the above copyright notice appear in all copies and that both that copyright
12  * notice and this permission notice appear in supporting documentation, and
13  * that the name of the copyright holders not be used in advertising or
14  * publicity pertaining to distribution of the software without specific,
15  * written prior permission.  The copyright holders make no representations
16  * about the suitability of this software for any purpose.  It is provided "as
17  * is" without express or implied warranty.
18  *
19  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
21  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
23  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
24  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
25  * OF THIS SOFTWARE.
26  *
27  * Authors:
28  *      Dave Airlie <airlied@linux.ie>
29  *      Jesse Barnes <jesse.barnes@intel.com>
30  */
31 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
32 
33 #include "drmP.h"
34 #include "drm_crtc.h"
35 #include "drm_fb_helper.h"
36 #include "drm_crtc_helper.h"
37 
38 static DRM_LIST_HEAD(kernel_fb_helper_list);
39 
40 /**
41  * DOC: fbdev helpers
42  *
43  * The fb helper functions are useful to provide an fbdev on top of a drm kernel
44  * mode setting driver. They can be used mostly independantely from the crtc
45  * helper functions used by many drivers to implement the kernel mode setting
46  * interfaces.
47  *
48  * Initialization is done as a three-step process with drm_fb_helper_init(),
49  * drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config().
50  * Drivers with fancier requirements than the default beheviour can override the
51  * second step with their own code.  Teardown is done with drm_fb_helper_fini().
52  *
53  * At runtime drivers should restore the fbdev console by calling
54  * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They
55  * should also notify the fb helper code from updates to the output
56  * configuration by calling drm_fb_helper_hotplug_event(). For easier
57  * integration with the output polling code in drm_crtc_helper.c the modeset
58  * code proves a ->output_poll_changed callback.
59  *
60  * All other functions exported by the fb helper library can be used to
61  * implement the fbdev driver interface by the driver.
62  */
63 
64 /**
65  * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
66  * 					       emulation helper
67  * @fb_helper: fbdev initialized with drm_fb_helper_init
68  *
69  * This functions adds all the available connectors for use with the given
70  * fb_helper. This is a separate step to allow drivers to freely assign
71  * connectors to the fbdev, e.g. if some are reserved for special purposes or
72  * not adequate to be used for the fbcon.
73  *
74  * Since this is part of the initial setup before the fbdev is published, no
75  * locking is required.
76  */
77 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
78 {
79 	struct drm_device *dev = fb_helper->dev;
80 	struct drm_connector *connector;
81 	int i;
82 
83 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
84 		struct drm_fb_helper_connector *fb_helper_connector;
85 
86 		fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
87 		if (!fb_helper_connector)
88 			goto fail;
89 
90 		fb_helper_connector->connector = connector;
91 		fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
92 	}
93 	return 0;
94 fail:
95 	for (i = 0; i < fb_helper->connector_count; i++) {
96 		kfree(fb_helper->connector_info[i]);
97 		fb_helper->connector_info[i] = NULL;
98 	}
99 	fb_helper->connector_count = 0;
100 	return -ENOMEM;
101 }
102 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
103 
104 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
105 {
106 	struct drm_fb_helper_connector *fb_helper_conn;
107 	int i;
108 
109 	for (i = 0; i < fb_helper->connector_count; i++) {
110 		struct drm_cmdline_mode *mode;
111 		struct drm_connector *connector;
112 //		char *option = NULL;
113 
114 		fb_helper_conn = fb_helper->connector_info[i];
115 		connector = fb_helper_conn->connector;
116 		mode = &fb_helper_conn->cmdline_mode;
117 
118 #ifdef notyet
119 		/* do something on return - turn off connector maybe */
120 		if (fb_get_options(drm_get_connector_name(connector), &option))
121 			continue;
122 
123 		if (drm_mode_parse_command_line_for_connector(option,
124 							      connector,
125 							      mode)) {
126 			if (mode->force) {
127 				const char *s;
128 				switch (mode->force) {
129 				case DRM_FORCE_OFF:
130 					s = "OFF";
131 					break;
132 				case DRM_FORCE_ON_DIGITAL:
133 					s = "ON - dig";
134 					break;
135 				default:
136 				case DRM_FORCE_ON:
137 					s = "ON";
138 					break;
139 				}
140 
141 				DRM_INFO("forcing %s connector %s\n",
142 					 drm_get_connector_name(connector), s);
143 				connector->force = mode->force;
144 			}
145 
146 			DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
147 				      drm_get_connector_name(connector),
148 				      mode->xres, mode->yres,
149 				      mode->refresh_specified ? mode->refresh : 60,
150 				      mode->rb ? " reduced blanking" : "",
151 				      mode->margins ? " with margins" : "",
152 				      mode->interlace ?  " interlaced" : "");
153 		}
154 #endif
155 
156 	}
157 	return 0;
158 }
159 
160 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
161 {
162 	uint16_t *r_base, *g_base, *b_base;
163 	int i;
164 
165 	if (helper->funcs->gamma_get == NULL)
166 		return;
167 
168 	r_base = crtc->gamma_store;
169 	g_base = r_base + crtc->gamma_size;
170 	b_base = g_base + crtc->gamma_size;
171 
172 	for (i = 0; i < crtc->gamma_size; i++)
173 		helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
174 }
175 
176 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
177 {
178 	uint16_t *r_base, *g_base, *b_base;
179 
180 	if (crtc->funcs->gamma_set == NULL)
181 		return;
182 
183 	r_base = crtc->gamma_store;
184 	g_base = r_base + crtc->gamma_size;
185 	b_base = g_base + crtc->gamma_size;
186 
187 	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
188 }
189 
190 /**
191  * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter
192  * @info: fbdev registered by the helper
193  */
194 int drm_fb_helper_debug_enter(struct drm_fb_helper *helper)
195 {
196 	struct drm_crtc_helper_funcs *funcs;
197 	int i;
198 
199 	if (list_empty(&kernel_fb_helper_list))
200 		return false;
201 
202 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
203 		for (i = 0; i < helper->crtc_count; i++) {
204 			struct drm_mode_set *mode_set =
205 				&helper->crtc_info[i].mode_set;
206 
207 			if (!mode_set->crtc->enabled)
208 				continue;
209 
210 			funcs =	mode_set->crtc->helper_private;
211 			drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
212 			funcs->mode_set_base_atomic(mode_set->crtc,
213 						    mode_set->fb,
214 						    mode_set->x,
215 						    mode_set->y,
216 						    ENTER_ATOMIC_MODE_SET);
217 		}
218 	}
219 
220 	return 0;
221 }
222 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
223 
224 /* Find the real fb for a given fb helper CRTC */
225 static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
226 {
227 	struct drm_device *dev = crtc->dev;
228 	struct drm_crtc *c;
229 
230 	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
231 		if (crtc->base.id == c->base.id)
232 			return c->fb;
233 	}
234 
235 	return NULL;
236 }
237 
238 /**
239  * drm_fb_helper_debug_leave - implementation for ->fb_debug_leave
240  * @info: fbdev registered by the helper
241  */
242 int drm_fb_helper_debug_leave(struct drm_fb_helper *helper)
243 {
244 	struct drm_crtc *crtc;
245 	struct drm_crtc_helper_funcs *funcs;
246 	struct drm_framebuffer *fb;
247 	int i;
248 
249 	for (i = 0; i < helper->crtc_count; i++) {
250 		struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
251 		crtc = mode_set->crtc;
252 		funcs = crtc->helper_private;
253 		fb = drm_mode_config_fb(crtc);
254 
255 		if (!crtc->enabled)
256 			continue;
257 
258 		if (!fb) {
259 			DRM_ERROR("no fb to restore??\n");
260 			continue;
261 		}
262 
263 		drm_fb_helper_restore_lut_atomic(mode_set->crtc);
264 		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
265 					    crtc->y, LEAVE_ATOMIC_MODE_SET);
266 	}
267 
268 	return 0;
269 }
270 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
271 
272 /**
273  * drm_fb_helper_restore_fbdev_mode - restore fbdev configuration
274  * @fb_helper: fbcon to restore
275  *
276  * This should be called from driver's drm ->lastclose callback
277  * when implementing an fbcon on top of kms using this helper. This ensures that
278  * the user isn't greeted with a black screen when e.g. X dies.
279  */
280 bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
281 {
282 	struct drm_device *dev = fb_helper->dev;
283 	struct drm_plane *plane;
284 	bool error = false;
285 	int i;
286 
287 	drm_warn_on_modeset_not_all_locked(dev);
288 
289 	list_for_each_entry(plane, &dev->mode_config.plane_list, head)
290 		drm_plane_force_disable(plane);
291 
292 	for (i = 0; i < fb_helper->crtc_count; i++) {
293 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
294 		struct drm_crtc *crtc = mode_set->crtc;
295 		int ret;
296 
297 		if (crtc->funcs->cursor_set) {
298 			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
299 			if (ret)
300 				error = true;
301 		}
302 
303 		ret = drm_mode_set_config_internal(mode_set);
304 		if (ret)
305 			error = true;
306 	}
307 	return error;
308 }
309 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
310 
311 #ifdef __linux__
312 /*
313  * restore fbcon display for all kms driver's using this helper, used for sysrq
314  * and panic handling.
315  */
316 static bool drm_fb_helper_force_kernel_mode(void)
317 {
318 	bool ret, error = false;
319 	struct drm_fb_helper *helper;
320 
321 	if (list_empty(&kernel_fb_helper_list))
322 		return false;
323 
324 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
325 #ifdef notyet
326 		if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
327 			continue;
328 #endif
329 
330 		ret = drm_fb_helper_restore_fbdev_mode(helper);
331 		if (ret)
332 			error = true;
333 	}
334 	return error;
335 }
336 
337 static int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
338 			void *panic_str)
339 {
340 	/*
341 	 * It's a waste of time and effort to switch back to text console
342 	 * if the kernel should reboot before panic messages can be seen.
343 	 */
344 	if (panic_timeout < 0)
345 		return 0;
346 
347 	pr_err("panic occurred, switching back to text console\n");
348 	return drm_fb_helper_force_kernel_mode();
349 }
350 
351 static struct notifier_block paniced = {
352 	.notifier_call = drm_fb_helper_panic,
353 };
354 #endif
355 
356 static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
357 {
358 	struct drm_device *dev = fb_helper->dev;
359 	struct drm_crtc *crtc;
360 	int bound = 0, crtcs_bound = 0;
361 
362 	/* Sometimes user space wants everything disabled, so don't steal the
363 	 * display if there's a master. */
364 #ifdef notyet
365 	if (dev->primary->master)
366 		return false;
367 #endif
368 
369 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
370 		if (crtc->fb)
371 			crtcs_bound++;
372 		if (crtc->fb == fb_helper->fb)
373 			bound++;
374 	}
375 
376 	if (bound < crtcs_bound)
377 		return false;
378 
379 	return true;
380 }
381 
382 #ifdef __linux__
383 #ifdef CONFIG_MAGIC_SYSRQ
384 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
385 {
386 	bool ret;
387 	ret = drm_fb_helper_force_kernel_mode();
388 	if (ret == true)
389 		DRM_ERROR("Failed to restore crtc configuration\n");
390 }
391 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
392 
393 static void drm_fb_helper_sysrq(int dummy1)
394 {
395 	schedule_work(&drm_fb_helper_restore_work);
396 }
397 
398 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
399 	.handler = drm_fb_helper_sysrq,
400 	.help_msg = "force-fb(V)",
401 	.action_msg = "Restore framebuffer console",
402 };
403 #else
404 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
405 #endif
406 #endif
407 
408 void drm_fb_helper_dpms(struct drm_fb_helper *fb_helper, int dpms_mode)
409 {
410 	struct drm_device *dev = fb_helper->dev;
411 	struct drm_crtc *crtc;
412 	struct drm_connector *connector;
413 	int i, j;
414 
415 	/*
416 	 * fbdev->blank can be called from irq context in case of a panic.
417 	 * Since we already have our own special panic handler which will
418 	 * restore the fbdev console mode completely, just bail out early.
419 	 */
420 	if (oops_in_progress)
421 		return;
422 
423 	/*
424 	 * For each CRTC in this fb, turn the connectors on/off.
425 	 */
426 	drm_modeset_lock_all(dev);
427 	if (!drm_fb_helper_is_bound(fb_helper)) {
428 		drm_modeset_unlock_all(dev);
429 		return;
430 	}
431 
432 	for (i = 0; i < fb_helper->crtc_count; i++) {
433 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
434 
435 		if (!crtc->enabled)
436 			continue;
437 
438 		/* Walk the connectors & encoders on this fb turning them on/off */
439 		for (j = 0; j < fb_helper->connector_count; j++) {
440 			connector = fb_helper->connector_info[j]->connector;
441 			connector->funcs->dpms(connector, dpms_mode);
442 			drm_object_property_set_value(&connector->base,
443 				dev->mode_config.dpms_property, dpms_mode);
444 		}
445 	}
446 	drm_modeset_unlock_all(dev);
447 }
448 
449 #if 0
450 /**
451  * drm_fb_helper_blank - implementation for ->fb_blank
452  * @blank: desired blanking state
453  * @info: fbdev registered by the helper
454  */
455 int drm_fb_helper_blank(int blank, struct fb_info *info)
456 {
457 	switch (blank) {
458 	/* Display: On; HSync: On, VSync: On */
459 	case FB_BLANK_UNBLANK:
460 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
461 		break;
462 	/* Display: Off; HSync: On, VSync: On */
463 	case FB_BLANK_NORMAL:
464 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
465 		break;
466 	/* Display: Off; HSync: Off, VSync: On */
467 	case FB_BLANK_HSYNC_SUSPEND:
468 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
469 		break;
470 	/* Display: Off; HSync: On, VSync: Off */
471 	case FB_BLANK_VSYNC_SUSPEND:
472 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
473 		break;
474 	/* Display: Off; HSync: Off, VSync: Off */
475 	case FB_BLANK_POWERDOWN:
476 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
477 		break;
478 	}
479 	return 0;
480 }
481 EXPORT_SYMBOL(drm_fb_helper_blank);
482 #endif
483 
484 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
485 {
486 	int i;
487 
488 	for (i = 0; i < helper->connector_count; i++)
489 		kfree(helper->connector_info[i]);
490 	kfree(helper->connector_info);
491 	for (i = 0; i < helper->crtc_count; i++) {
492 		kfree(helper->crtc_info[i].mode_set.connectors);
493 		if (helper->crtc_info[i].mode_set.mode)
494 			drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
495 	}
496 	kfree(helper->crtc_info);
497 }
498 
499 /**
500  * drm_fb_helper_init - initialize a drm_fb_helper structure
501  * @dev: drm device
502  * @fb_helper: driver-allocated fbdev helper structure to initialize
503  * @crtc_count: maximum number of crtcs to support in this fbdev emulation
504  * @max_conn_count: max connector count
505  *
506  * This allocates the structures for the fbdev helper with the given limits.
507  * Note that this won't yet touch the hardware (through the driver interfaces)
508  * nor register the fbdev. This is only done in drm_fb_helper_initial_config()
509  * to allow driver writes more control over the exact init sequence.
510  *
511  * Drivers must set fb_helper->funcs before calling
512  * drm_fb_helper_initial_config().
513  *
514  * RETURNS:
515  * Zero if everything went ok, nonzero otherwise.
516  */
517 int drm_fb_helper_init(struct drm_device *dev,
518 		       struct drm_fb_helper *fb_helper,
519 		       int crtc_count, int max_conn_count)
520 {
521 	struct drm_crtc *crtc;
522 	int i;
523 
524 	fb_helper->dev = dev;
525 
526 	INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
527 
528 	fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
529 	if (!fb_helper->crtc_info)
530 		return -ENOMEM;
531 
532 	fb_helper->crtc_count = crtc_count;
533 	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
534 	if (!fb_helper->connector_info) {
535 		kfree(fb_helper->crtc_info);
536 		return -ENOMEM;
537 	}
538 	fb_helper->connector_count = 0;
539 
540 	for (i = 0; i < crtc_count; i++) {
541 		fb_helper->crtc_info[i].mode_set.connectors =
542 			kcalloc(max_conn_count,
543 				sizeof(struct drm_connector *),
544 				GFP_KERNEL);
545 
546 		if (!fb_helper->crtc_info[i].mode_set.connectors)
547 			goto out_free;
548 		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
549 	}
550 
551 	i = 0;
552 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
553 		fb_helper->crtc_info[i].mode_set.crtc = crtc;
554 		i++;
555 	}
556 
557 	return 0;
558 out_free:
559 	drm_fb_helper_crtc_free(fb_helper);
560 	return -ENOMEM;
561 }
562 EXPORT_SYMBOL(drm_fb_helper_init);
563 
564 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
565 {
566 	if (!list_empty(&fb_helper->kernel_fb_list)) {
567 		list_del(&fb_helper->kernel_fb_list);
568 		if (list_empty(&kernel_fb_helper_list)) {
569 #if 0
570 			pr_info("drm: unregistered panic notifier\n");
571 			atomic_notifier_chain_unregister(&panic_notifier_list,
572 							 &paniced);
573 			unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
574 #endif
575 		}
576 	}
577 
578 	drm_fb_helper_crtc_free(fb_helper);
579 
580 }
581 EXPORT_SYMBOL(drm_fb_helper_fini);
582 
583 #if 0
584 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
585 		     u16 blue, u16 regno, struct fb_info *info)
586 {
587 	struct drm_fb_helper *fb_helper = info->par;
588 	struct drm_framebuffer *fb = fb_helper->fb;
589 	int pindex;
590 
591 	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
592 		u32 *palette;
593 		u32 value;
594 		/* place color in psuedopalette */
595 		if (regno > 16)
596 			return -EINVAL;
597 		palette = (u32 *)info->pseudo_palette;
598 		red >>= (16 - info->var.red.length);
599 		green >>= (16 - info->var.green.length);
600 		blue >>= (16 - info->var.blue.length);
601 		value = (red << info->var.red.offset) |
602 			(green << info->var.green.offset) |
603 			(blue << info->var.blue.offset);
604 		if (info->var.transp.length > 0) {
605 			u32 mask = (1 << info->var.transp.length) - 1;
606 			mask <<= info->var.transp.offset;
607 			value |= mask;
608 		}
609 		palette[regno] = value;
610 		return 0;
611 	}
612 
613 	/*
614 	 * The driver really shouldn't advertise pseudo/directcolor
615 	 * visuals if it can't deal with the palette.
616 	 */
617 	if (WARN_ON(!fb_helper->funcs->gamma_set ||
618 		    !fb_helper->funcs->gamma_get))
619 		return -EINVAL;
620 
621 	pindex = regno;
622 
623 	if (fb->bits_per_pixel == 16) {
624 		pindex = regno << 3;
625 
626 		if (fb->depth == 16 && regno > 63)
627 			return -EINVAL;
628 		if (fb->depth == 15 && regno > 31)
629 			return -EINVAL;
630 
631 		if (fb->depth == 16) {
632 			u16 r, g, b;
633 			int i;
634 			if (regno < 32) {
635 				for (i = 0; i < 8; i++)
636 					fb_helper->funcs->gamma_set(crtc, red,
637 						green, blue, pindex + i);
638 			}
639 
640 			fb_helper->funcs->gamma_get(crtc, &r,
641 						    &g, &b,
642 						    pindex >> 1);
643 
644 			for (i = 0; i < 4; i++)
645 				fb_helper->funcs->gamma_set(crtc, r,
646 							    green, b,
647 							    (pindex >> 1) + i);
648 		}
649 	}
650 
651 	if (fb->depth != 16)
652 		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
653 	return 0;
654 }
655 
656 /**
657  * drm_fb_helper_setcmap - implementation for ->fb_setcmap
658  * @cmap: cmap to set
659  * @info: fbdev registered by the helper
660  */
661 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
662 {
663 	struct drm_fb_helper *fb_helper = info->par;
664 	struct drm_device *dev = fb_helper->dev;
665 	struct drm_crtc_helper_funcs *crtc_funcs;
666 	u16 *red, *green, *blue, *transp;
667 	struct drm_crtc *crtc;
668 	int i, j, rc = 0;
669 	int start;
670 
671 	drm_modeset_lock_all(dev);
672 	if (!drm_fb_helper_is_bound(fb_helper)) {
673 		drm_modeset_unlock_all(dev);
674 		return -EBUSY;
675 	}
676 
677 	for (i = 0; i < fb_helper->crtc_count; i++) {
678 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
679 		crtc_funcs = crtc->helper_private;
680 
681 		red = cmap->red;
682 		green = cmap->green;
683 		blue = cmap->blue;
684 		transp = cmap->transp;
685 		start = cmap->start;
686 
687 		for (j = 0; j < cmap->len; j++) {
688 			u16 hred, hgreen, hblue, htransp = 0xffff;
689 
690 			hred = *red++;
691 			hgreen = *green++;
692 			hblue = *blue++;
693 
694 			if (transp)
695 				htransp = *transp++;
696 
697 			rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
698 			if (rc)
699 				goto out;
700 		}
701 		if (crtc_funcs->load_lut)
702 			crtc_funcs->load_lut(crtc);
703 	}
704  out:
705 	drm_modeset_unlock_all(dev);
706 	return rc;
707 }
708 EXPORT_SYMBOL(drm_fb_helper_setcmap);
709 
710 /**
711  * drm_fb_helper_check_var - implementation for ->fb_check_var
712  * @var: screeninfo to check
713  * @info: fbdev registered by the helper
714  */
715 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
716 			    struct fb_info *info)
717 {
718 	struct drm_fb_helper *fb_helper = info->par;
719 	struct drm_framebuffer *fb = fb_helper->fb;
720 	int depth;
721 
722 	if (var->pixclock != 0 || in_dbg_master())
723 		return -EINVAL;
724 
725 	/* Need to resize the fb object !!! */
726 	if (var->bits_per_pixel > fb->bits_per_pixel ||
727 	    var->xres > fb->width || var->yres > fb->height ||
728 	    var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
729 		DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
730 			  "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
731 			  var->xres, var->yres, var->bits_per_pixel,
732 			  var->xres_virtual, var->yres_virtual,
733 			  fb->width, fb->height, fb->bits_per_pixel);
734 		return -EINVAL;
735 	}
736 
737 	switch (var->bits_per_pixel) {
738 	case 16:
739 		depth = (var->green.length == 6) ? 16 : 15;
740 		break;
741 	case 32:
742 		depth = (var->transp.length > 0) ? 32 : 24;
743 		break;
744 	default:
745 		depth = var->bits_per_pixel;
746 		break;
747 	}
748 
749 	switch (depth) {
750 	case 8:
751 		var->red.offset = 0;
752 		var->green.offset = 0;
753 		var->blue.offset = 0;
754 		var->red.length = 8;
755 		var->green.length = 8;
756 		var->blue.length = 8;
757 		var->transp.length = 0;
758 		var->transp.offset = 0;
759 		break;
760 	case 15:
761 		var->red.offset = 10;
762 		var->green.offset = 5;
763 		var->blue.offset = 0;
764 		var->red.length = 5;
765 		var->green.length = 5;
766 		var->blue.length = 5;
767 		var->transp.length = 1;
768 		var->transp.offset = 15;
769 		break;
770 	case 16:
771 		var->red.offset = 11;
772 		var->green.offset = 5;
773 		var->blue.offset = 0;
774 		var->red.length = 5;
775 		var->green.length = 6;
776 		var->blue.length = 5;
777 		var->transp.length = 0;
778 		var->transp.offset = 0;
779 		break;
780 	case 24:
781 		var->red.offset = 16;
782 		var->green.offset = 8;
783 		var->blue.offset = 0;
784 		var->red.length = 8;
785 		var->green.length = 8;
786 		var->blue.length = 8;
787 		var->transp.length = 0;
788 		var->transp.offset = 0;
789 		break;
790 	case 32:
791 		var->red.offset = 16;
792 		var->green.offset = 8;
793 		var->blue.offset = 0;
794 		var->red.length = 8;
795 		var->green.length = 8;
796 		var->blue.length = 8;
797 		var->transp.length = 8;
798 		var->transp.offset = 24;
799 		break;
800 	default:
801 		return -EINVAL;
802 	}
803 	return 0;
804 }
805 EXPORT_SYMBOL(drm_fb_helper_check_var);
806 #endif
807 
808 /**
809  * drm_fb_helper_set_par - implementation for ->fb_set_par
810  * @info: fbdev registered by the helper
811  *
812  * This will let fbcon do the mode init and is called at initialization time by
813  * the fbdev core when registering the driver, and later on through the hotplug
814  * callback.
815  */
816 int drm_fb_helper_set_par(struct fb_info *info)
817 {
818 	struct drm_fb_helper *fb_helper = info->par;
819 	struct drm_device *dev = fb_helper->dev;
820 	struct fb_var_screeninfo *var = &info->var;
821 	int ret;
822 	int i;
823 
824 	if (var->pixclock != 0) {
825 		DRM_ERROR("PIXEL CLOCK SET\n");
826 		return -EINVAL;
827 	}
828 
829 	drm_modeset_lock_all(dev);
830 	for (i = 0; i < fb_helper->crtc_count; i++) {
831 		ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
832 		if (ret) {
833 			drm_modeset_unlock_all(dev);
834 			return ret;
835 		}
836 	}
837 	drm_modeset_unlock_all(dev);
838 
839 	if (fb_helper->delayed_hotplug) {
840 		fb_helper->delayed_hotplug = false;
841 		drm_fb_helper_hotplug_event(fb_helper);
842 	}
843 	return 0;
844 }
845 EXPORT_SYMBOL(drm_fb_helper_set_par);
846 
847 #ifdef __linux__
848 /**
849  * drm_fb_helper_pan_display - implementation for ->fb_pan_display
850  * @var: updated screen information
851  * @info: fbdev registered by the helper
852  */
853 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
854 			      struct fb_info *info)
855 {
856 	struct drm_fb_helper *fb_helper = info->par;
857 	struct drm_device *dev = fb_helper->dev;
858 	struct drm_mode_set *modeset;
859 	int ret = 0;
860 	int i;
861 
862 	drm_modeset_lock_all(dev);
863 	if (!drm_fb_helper_is_bound(fb_helper)) {
864 		drm_modeset_unlock_all(dev);
865 		return -EBUSY;
866 	}
867 
868 	for (i = 0; i < fb_helper->crtc_count; i++) {
869 		modeset = &fb_helper->crtc_info[i].mode_set;
870 
871 		modeset->x = var->xoffset;
872 		modeset->y = var->yoffset;
873 
874 		if (modeset->num_connectors) {
875 			ret = drm_mode_set_config_internal(modeset);
876 			if (!ret) {
877 				info->var.xoffset = var->xoffset;
878 				info->var.yoffset = var->yoffset;
879 			}
880 		}
881 	}
882 	drm_modeset_unlock_all(dev);
883 	return ret;
884 }
885 EXPORT_SYMBOL(drm_fb_helper_pan_display);
886 #endif
887 
888 /*
889  * Allocates the backing storage and sets up the fbdev info structure through
890  * the ->fb_probe callback and then registers the fbdev and sets up the panic
891  * notifier.
892  */
893 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
894 					 int preferred_bpp)
895 {
896 	int ret = 0;
897 	int crtc_count = 0;
898 	int i;
899 	struct fb_info *info;
900 	struct drm_fb_helper_surface_size sizes;
901 	int gamma_size = 0;
902 
903 	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
904 	sizes.surface_depth = 24;
905 	sizes.surface_bpp = 32;
906 	sizes.fb_width = (unsigned)-1;
907 	sizes.fb_height = (unsigned)-1;
908 
909 	/* if driver picks 8 or 16 by default use that
910 	   for both depth/bpp */
911 	if (preferred_bpp != sizes.surface_bpp)
912 		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
913 
914 	/* first up get a count of crtcs now in use and new min/maxes width/heights */
915 	for (i = 0; i < fb_helper->connector_count; i++) {
916 		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
917 		struct drm_cmdline_mode *cmdline_mode;
918 
919 		cmdline_mode = &fb_helper_conn->cmdline_mode;
920 
921 		if (cmdline_mode->bpp_specified) {
922 			switch (cmdline_mode->bpp) {
923 			case 8:
924 				sizes.surface_depth = sizes.surface_bpp = 8;
925 				break;
926 			case 15:
927 				sizes.surface_depth = 15;
928 				sizes.surface_bpp = 16;
929 				break;
930 			case 16:
931 				sizes.surface_depth = sizes.surface_bpp = 16;
932 				break;
933 			case 24:
934 				sizes.surface_depth = sizes.surface_bpp = 24;
935 				break;
936 			case 32:
937 				sizes.surface_depth = 24;
938 				sizes.surface_bpp = 32;
939 				break;
940 			}
941 			break;
942 		}
943 	}
944 
945 	crtc_count = 0;
946 	for (i = 0; i < fb_helper->crtc_count; i++) {
947 		struct drm_display_mode *desired_mode;
948 		desired_mode = fb_helper->crtc_info[i].desired_mode;
949 
950 		if (desired_mode) {
951 			if (gamma_size == 0)
952 				gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
953 			if (desired_mode->hdisplay < sizes.fb_width)
954 				sizes.fb_width = desired_mode->hdisplay;
955 			if (desired_mode->vdisplay < sizes.fb_height)
956 				sizes.fb_height = desired_mode->vdisplay;
957 			if (desired_mode->hdisplay > sizes.surface_width)
958 				sizes.surface_width = desired_mode->hdisplay;
959 			if (desired_mode->vdisplay > sizes.surface_height)
960 				sizes.surface_height = desired_mode->vdisplay;
961 			crtc_count++;
962 		}
963 	}
964 
965 	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
966 		/* hmm everyone went away - assume VGA cable just fell out
967 		   and will come back later. */
968 		DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
969 		sizes.fb_width = sizes.surface_width = 1024;
970 		sizes.fb_height = sizes.surface_height = 768;
971 	}
972 
973 	/* push down into drivers */
974 	ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
975 	if (ret < 0)
976 		return ret;
977 
978 	info = fb_helper->fbdev;
979 
980 	/*
981 	 * Set the fb pointer - usually drm_setup_crtcs does this for hotplug
982 	 * events, but at init time drm_setup_crtcs needs to be called before
983 	 * the fb is allocated (since we need to figure out the desired size of
984 	 * the fb before we can allocate it ...). Hence we need to fix things up
985 	 * here again.
986 	 */
987 	for (i = 0; i < fb_helper->crtc_count; i++)
988 		if (fb_helper->crtc_info[i].mode_set.num_connectors)
989 			fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
990 
991 
992 	info->var.pixclock = 0;
993 #ifdef __linux__
994 	if (register_framebuffer(info) < 0)
995 		return -EINVAL;
996 
997 	dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
998 			info->node, info->fix.id);
999 
1000 	/* Switch back to kernel console on panic */
1001 	/* multi card linked list maybe */
1002 	if (list_empty(&kernel_fb_helper_list)) {
1003 		dev_info(fb_helper->dev->dev, "registered panic notifier\n");
1004 		atomic_notifier_chain_register(&panic_notifier_list,
1005 					       &paniced);
1006 		register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
1007 	}
1008 #endif
1009 
1010 	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
1011 
1012 	return 0;
1013 }
1014 
1015 #if 0
1016 /**
1017  * drm_fb_helper_fill_fix - initializes fixed fbdev information
1018  * @info: fbdev registered by the helper
1019  * @pitch: desired pitch
1020  * @depth: desired depth
1021  *
1022  * Helper to fill in the fixed fbdev information useful for a non-accelerated
1023  * fbdev emulations. Drivers which support acceleration methods which impose
1024  * additional constraints need to set up their own limits.
1025  *
1026  * Drivers should call this (or their equivalent setup code) from their
1027  * ->fb_probe callback.
1028  */
1029 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
1030 			    uint32_t depth)
1031 {
1032 	info->fix.type = FB_TYPE_PACKED_PIXELS;
1033 	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1034 		FB_VISUAL_TRUECOLOR;
1035 	info->fix.mmio_start = 0;
1036 	info->fix.mmio_len = 0;
1037 	info->fix.type_aux = 0;
1038 	info->fix.xpanstep = 1; /* doing it in hw */
1039 	info->fix.ypanstep = 1; /* doing it in hw */
1040 	info->fix.ywrapstep = 0;
1041 	info->fix.accel = FB_ACCEL_NONE;
1042 	info->fix.type_aux = 0;
1043 
1044 	info->fix.line_length = pitch;
1045 	return;
1046 }
1047 EXPORT_SYMBOL(drm_fb_helper_fill_fix);
1048 
1049 /**
1050  * drm_fb_helper_fill_var - initalizes variable fbdev information
1051  * @info: fbdev instance to set up
1052  * @fb_helper: fb helper instance to use as template
1053  * @fb_width: desired fb width
1054  * @fb_height: desired fb height
1055  *
1056  * Sets up the variable fbdev metainformation from the given fb helper instance
1057  * and the drm framebuffer allocated in fb_helper->fb.
1058  *
1059  * Drivers should call this (or their equivalent setup code) from their
1060  * ->fb_probe callback after having allocated the fbdev backing
1061  * storage framebuffer.
1062  */
1063 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
1064 			    uint32_t fb_width, uint32_t fb_height)
1065 {
1066 	struct drm_framebuffer *fb = fb_helper->fb;
1067 	info->pseudo_palette = fb_helper->pseudo_palette;
1068 	info->var.xres_virtual = fb->width;
1069 	info->var.yres_virtual = fb->height;
1070 	info->var.bits_per_pixel = fb->bits_per_pixel;
1071 	info->var.accel_flags = FB_ACCELF_TEXT;
1072 	info->var.xoffset = 0;
1073 	info->var.yoffset = 0;
1074 	info->var.activate = FB_ACTIVATE_NOW;
1075 	info->var.height = -1;
1076 	info->var.width = -1;
1077 
1078 	switch (fb->depth) {
1079 	case 8:
1080 		info->var.red.offset = 0;
1081 		info->var.green.offset = 0;
1082 		info->var.blue.offset = 0;
1083 		info->var.red.length = 8; /* 8bit DAC */
1084 		info->var.green.length = 8;
1085 		info->var.blue.length = 8;
1086 		info->var.transp.offset = 0;
1087 		info->var.transp.length = 0;
1088 		break;
1089 	case 15:
1090 		info->var.red.offset = 10;
1091 		info->var.green.offset = 5;
1092 		info->var.blue.offset = 0;
1093 		info->var.red.length = 5;
1094 		info->var.green.length = 5;
1095 		info->var.blue.length = 5;
1096 		info->var.transp.offset = 15;
1097 		info->var.transp.length = 1;
1098 		break;
1099 	case 16:
1100 		info->var.red.offset = 11;
1101 		info->var.green.offset = 5;
1102 		info->var.blue.offset = 0;
1103 		info->var.red.length = 5;
1104 		info->var.green.length = 6;
1105 		info->var.blue.length = 5;
1106 		info->var.transp.offset = 0;
1107 		break;
1108 	case 24:
1109 		info->var.red.offset = 16;
1110 		info->var.green.offset = 8;
1111 		info->var.blue.offset = 0;
1112 		info->var.red.length = 8;
1113 		info->var.green.length = 8;
1114 		info->var.blue.length = 8;
1115 		info->var.transp.offset = 0;
1116 		info->var.transp.length = 0;
1117 		break;
1118 	case 32:
1119 		info->var.red.offset = 16;
1120 		info->var.green.offset = 8;
1121 		info->var.blue.offset = 0;
1122 		info->var.red.length = 8;
1123 		info->var.green.length = 8;
1124 		info->var.blue.length = 8;
1125 		info->var.transp.offset = 24;
1126 		info->var.transp.length = 8;
1127 		break;
1128 	default:
1129 		break;
1130 	}
1131 
1132 	info->var.xres = fb_width;
1133 	info->var.yres = fb_height;
1134 }
1135 EXPORT_SYMBOL(drm_fb_helper_fill_var);
1136 #endif
1137 
1138 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
1139 					       uint32_t maxX,
1140 					       uint32_t maxY)
1141 {
1142 	struct drm_connector *connector;
1143 	int count = 0;
1144 	int i;
1145 
1146 	for (i = 0; i < fb_helper->connector_count; i++) {
1147 		connector = fb_helper->connector_info[i]->connector;
1148 		count += connector->funcs->fill_modes(connector, maxX, maxY);
1149 	}
1150 
1151 	return count;
1152 }
1153 
1154 static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
1155 {
1156 	struct drm_display_mode *mode;
1157 
1158 	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
1159 		if (drm_mode_width(mode) > width ||
1160 		    drm_mode_height(mode) > height)
1161 			continue;
1162 		if (mode->type & DRM_MODE_TYPE_PREFERRED)
1163 			return mode;
1164 	}
1165 	return NULL;
1166 }
1167 
1168 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
1169 {
1170 	struct drm_cmdline_mode *cmdline_mode;
1171 	cmdline_mode = &fb_connector->cmdline_mode;
1172 	return cmdline_mode->specified;
1173 }
1174 
1175 static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
1176 						      int width, int height)
1177 {
1178 	struct drm_cmdline_mode *cmdline_mode;
1179 	struct drm_display_mode *mode = NULL;
1180 
1181 	cmdline_mode = &fb_helper_conn->cmdline_mode;
1182 	if (cmdline_mode->specified == false)
1183 		return mode;
1184 
1185 	/* attempt to find a matching mode in the list of modes
1186 	 *  we have gotten so far, if not add a CVT mode that conforms
1187 	 */
1188 	if (cmdline_mode->rb || cmdline_mode->margins)
1189 		goto create_mode;
1190 
1191 	list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1192 		/* check width/height */
1193 		if (mode->hdisplay != cmdline_mode->xres ||
1194 		    mode->vdisplay != cmdline_mode->yres)
1195 			continue;
1196 
1197 		if (cmdline_mode->refresh_specified) {
1198 			if (mode->vrefresh != cmdline_mode->refresh)
1199 				continue;
1200 		}
1201 
1202 		if (cmdline_mode->interlace) {
1203 			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
1204 				continue;
1205 		}
1206 		return mode;
1207 	}
1208 
1209 create_mode:
1210 	mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
1211 						 cmdline_mode);
1212 	list_add(&mode->head, &fb_helper_conn->connector->modes);
1213 	return mode;
1214 }
1215 
1216 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1217 {
1218 	bool enable;
1219 
1220 	if (strict)
1221 		enable = connector->status == connector_status_connected;
1222 	else
1223 		enable = connector->status != connector_status_disconnected;
1224 
1225 	return enable;
1226 }
1227 
1228 static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
1229 				  bool *enabled)
1230 {
1231 	bool any_enabled = false;
1232 	struct drm_connector *connector;
1233 	int i = 0;
1234 
1235 	for (i = 0; i < fb_helper->connector_count; i++) {
1236 		connector = fb_helper->connector_info[i]->connector;
1237 		enabled[i] = drm_connector_enabled(connector, true);
1238 		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
1239 			  enabled[i] ? "yes" : "no");
1240 		any_enabled |= enabled[i];
1241 	}
1242 
1243 	if (any_enabled)
1244 		return;
1245 
1246 	for (i = 0; i < fb_helper->connector_count; i++) {
1247 		connector = fb_helper->connector_info[i]->connector;
1248 		enabled[i] = drm_connector_enabled(connector, false);
1249 	}
1250 }
1251 
1252 static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
1253 			      struct drm_display_mode **modes,
1254 			      bool *enabled, int width, int height)
1255 {
1256 	int count, i, j;
1257 	bool can_clone = false;
1258 	struct drm_fb_helper_connector *fb_helper_conn;
1259 	struct drm_display_mode *dmt_mode, *mode;
1260 
1261 	/* only contemplate cloning in the single crtc case */
1262 	if (fb_helper->crtc_count > 1)
1263 		return false;
1264 
1265 	count = 0;
1266 	for (i = 0; i < fb_helper->connector_count; i++) {
1267 		if (enabled[i])
1268 			count++;
1269 	}
1270 
1271 	/* only contemplate cloning if more than one connector is enabled */
1272 	if (count <= 1)
1273 		return false;
1274 
1275 	/* check the command line or if nothing common pick 1024x768 */
1276 	can_clone = true;
1277 	for (i = 0; i < fb_helper->connector_count; i++) {
1278 		if (!enabled[i])
1279 			continue;
1280 		fb_helper_conn = fb_helper->connector_info[i];
1281 		modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1282 		if (!modes[i]) {
1283 			can_clone = false;
1284 			break;
1285 		}
1286 		for (j = 0; j < i; j++) {
1287 			if (!enabled[j])
1288 				continue;
1289 			if (!drm_mode_equal(modes[j], modes[i]))
1290 				can_clone = false;
1291 		}
1292 	}
1293 
1294 	if (can_clone) {
1295 		DRM_DEBUG_KMS("can clone using command line\n");
1296 		return true;
1297 	}
1298 
1299 	/* try and find a 1024x768 mode on each connector */
1300 	can_clone = true;
1301 	dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
1302 
1303 	for (i = 0; i < fb_helper->connector_count; i++) {
1304 
1305 		if (!enabled[i])
1306 			continue;
1307 
1308 		fb_helper_conn = fb_helper->connector_info[i];
1309 		list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1310 			if (drm_mode_equal(mode, dmt_mode))
1311 				modes[i] = mode;
1312 		}
1313 		if (!modes[i])
1314 			can_clone = false;
1315 	}
1316 
1317 	if (can_clone) {
1318 		DRM_DEBUG_KMS("can clone using 1024x768\n");
1319 		return true;
1320 	}
1321 	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
1322 	return false;
1323 }
1324 
1325 static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
1326 				 struct drm_display_mode **modes,
1327 				 bool *enabled, int width, int height)
1328 {
1329 	struct drm_fb_helper_connector *fb_helper_conn;
1330 	int i;
1331 
1332 	for (i = 0; i < fb_helper->connector_count; i++) {
1333 		fb_helper_conn = fb_helper->connector_info[i];
1334 
1335 		if (enabled[i] == false)
1336 			continue;
1337 
1338 		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
1339 			      fb_helper_conn->connector->base.id);
1340 
1341 		/* got for command line mode first */
1342 		modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1343 		if (!modes[i]) {
1344 			DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
1345 				      fb_helper_conn->connector->base.id);
1346 			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
1347 		}
1348 		/* No preferred modes, pick one off the list */
1349 		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
1350 			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
1351 				break;
1352 		}
1353 		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
1354 			  "none");
1355 	}
1356 	return true;
1357 }
1358 
1359 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
1360 			  struct drm_fb_helper_crtc **best_crtcs,
1361 			  struct drm_display_mode **modes,
1362 			  int n, int width, int height)
1363 {
1364 	int c, o;
1365 	struct drm_device *dev = fb_helper->dev;
1366 	struct drm_connector *connector;
1367 	struct drm_connector_helper_funcs *connector_funcs;
1368 	struct drm_encoder *encoder;
1369 	int my_score, best_score, score;
1370 	struct drm_fb_helper_crtc **crtcs, *crtc;
1371 	struct drm_fb_helper_connector *fb_helper_conn;
1372 
1373 	if (n == fb_helper->connector_count)
1374 		return 0;
1375 
1376 	fb_helper_conn = fb_helper->connector_info[n];
1377 	connector = fb_helper_conn->connector;
1378 
1379 	best_crtcs[n] = NULL;
1380 	best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1381 	if (modes[n] == NULL)
1382 		return best_score;
1383 
1384 	crtcs = kzalloc(dev->mode_config.num_connector *
1385 			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1386 	if (!crtcs)
1387 		return best_score;
1388 
1389 	my_score = 1;
1390 	if (connector->status == connector_status_connected)
1391 		my_score++;
1392 	if (drm_has_cmdline_mode(fb_helper_conn))
1393 		my_score++;
1394 	if (drm_has_preferred_mode(fb_helper_conn, width, height))
1395 		my_score++;
1396 
1397 	connector_funcs = connector->helper_private;
1398 	encoder = connector_funcs->best_encoder(connector);
1399 	if (!encoder)
1400 		goto out;
1401 
1402 	/* select a crtc for this connector and then attempt to configure
1403 	   remaining connectors */
1404 	for (c = 0; c < fb_helper->crtc_count; c++) {
1405 		crtc = &fb_helper->crtc_info[c];
1406 
1407 		if ((encoder->possible_crtcs & (1 << c)) == 0)
1408 			continue;
1409 
1410 		for (o = 0; o < n; o++)
1411 			if (best_crtcs[o] == crtc)
1412 				break;
1413 
1414 		if (o < n) {
1415 			/* ignore cloning unless only a single crtc */
1416 			if (fb_helper->crtc_count > 1)
1417 				continue;
1418 
1419 			if (!drm_mode_equal(modes[o], modes[n]))
1420 				continue;
1421 		}
1422 
1423 		crtcs[n] = crtc;
1424 		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
1425 		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
1426 						  width, height);
1427 		if (score > best_score) {
1428 			best_score = score;
1429 			memcpy(best_crtcs, crtcs,
1430 			       dev->mode_config.num_connector *
1431 			       sizeof(struct drm_fb_helper_crtc *));
1432 		}
1433 	}
1434 out:
1435 	kfree(crtcs);
1436 	return best_score;
1437 }
1438 
1439 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1440 {
1441 	struct drm_device *dev = fb_helper->dev;
1442 	struct drm_fb_helper_crtc **crtcs;
1443 	struct drm_display_mode **modes;
1444 	struct drm_mode_set *modeset;
1445 	bool *enabled;
1446 	int width, height;
1447 	int i;
1448 
1449 	DRM_DEBUG_KMS("\n");
1450 
1451 	width = dev->mode_config.max_width;
1452 	height = dev->mode_config.max_height;
1453 
1454 	crtcs = kcalloc(dev->mode_config.num_connector,
1455 			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1456 	modes = kcalloc(dev->mode_config.num_connector,
1457 			sizeof(struct drm_display_mode *), GFP_KERNEL);
1458 	enabled = kcalloc(dev->mode_config.num_connector,
1459 			  sizeof(bool), GFP_KERNEL);
1460 	if (!crtcs || !modes || !enabled) {
1461 		DRM_ERROR("Memory allocation failed\n");
1462 		goto out;
1463 	}
1464 
1465 
1466 	drm_enable_connectors(fb_helper, enabled);
1467 
1468 	if (!(fb_helper->funcs->initial_config &&
1469 	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
1470 					       enabled, width, height))) {
1471 		memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
1472 		memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
1473 
1474 		if (!drm_target_cloned(fb_helper,
1475 				       modes, enabled, width, height) &&
1476 		    !drm_target_preferred(fb_helper,
1477 					  modes, enabled, width, height))
1478 			DRM_ERROR("Unable to find initial modes\n");
1479 
1480 		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
1481 			      width, height);
1482 
1483 		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
1484 	}
1485 
1486 	/* need to set the modesets up here for use later */
1487 	/* fill out the connector<->crtc mappings into the modesets */
1488 	for (i = 0; i < fb_helper->crtc_count; i++) {
1489 		modeset = &fb_helper->crtc_info[i].mode_set;
1490 		modeset->num_connectors = 0;
1491 		modeset->fb = NULL;
1492 	}
1493 
1494 	for (i = 0; i < fb_helper->connector_count; i++) {
1495 		struct drm_display_mode *mode = modes[i];
1496 		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
1497 		modeset = &fb_crtc->mode_set;
1498 
1499 		if (mode && fb_crtc) {
1500 			DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
1501 				      mode->name, fb_crtc->mode_set.crtc->base.id);
1502 			fb_crtc->desired_mode = mode;
1503 			if (modeset->mode)
1504 				drm_mode_destroy(dev, modeset->mode);
1505 			modeset->mode = drm_mode_duplicate(dev,
1506 							   fb_crtc->desired_mode);
1507 			modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
1508 			modeset->fb = fb_helper->fb;
1509 		}
1510 	}
1511 
1512 	/* Clear out any old modes if there are no more connected outputs. */
1513 	for (i = 0; i < fb_helper->crtc_count; i++) {
1514 		modeset = &fb_helper->crtc_info[i].mode_set;
1515 		if (modeset->num_connectors == 0) {
1516 			BUG_ON(modeset->fb);
1517 			BUG_ON(modeset->num_connectors);
1518 			if (modeset->mode)
1519 				drm_mode_destroy(dev, modeset->mode);
1520 			modeset->mode = NULL;
1521 		}
1522 	}
1523 out:
1524 	kfree(crtcs);
1525 	kfree(modes);
1526 	kfree(enabled);
1527 }
1528 
1529 /**
1530  * drm_fb_helper_initial_config - setup a sane initial connector configuration
1531  * @fb_helper: fb_helper device struct
1532  * @bpp_sel: bpp value to use for the framebuffer configuration
1533  *
1534  * Scans the CRTCs and connectors and tries to put together an initial setup.
1535  * At the moment, this is a cloned configuration across all heads with
1536  * a new framebuffer object as the backing store.
1537  *
1538  * Note that this also registers the fbdev and so allows userspace to call into
1539  * the driver through the fbdev interfaces.
1540  *
1541  * This function will call down into the ->fb_probe callback to let
1542  * the driver allocate and initialize the fbdev info structure and the drm
1543  * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
1544  * drm_fb_helper_fill_fix() are provided as helpers to setup simple default
1545  * values for the fbdev info structure.
1546  *
1547  * RETURNS:
1548  * Zero if everything went ok, nonzero otherwise.
1549  */
1550 bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1551 {
1552 	struct drm_device *dev = fb_helper->dev;
1553 	int count = 0;
1554 
1555 	drm_fb_helper_parse_command_line(fb_helper);
1556 
1557 	count = drm_fb_helper_probe_connector_modes(fb_helper,
1558 						    dev->mode_config.max_width,
1559 						    dev->mode_config.max_height);
1560 	/*
1561 	 * we shouldn't end up with no modes here.
1562 	 */
1563 	if (count == 0)
1564 		dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n");
1565 
1566 	drm_setup_crtcs(fb_helper);
1567 
1568 	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1569 }
1570 EXPORT_SYMBOL(drm_fb_helper_initial_config);
1571 
1572 /**
1573  * drm_fb_helper_hotplug_event - respond to a hotplug notification by
1574  *                               probing all the outputs attached to the fb
1575  * @fb_helper: the drm_fb_helper
1576  *
1577  * Scan the connectors attached to the fb_helper and try to put together a
1578  * setup after *notification of a change in output configuration.
1579  *
1580  * Called at runtime, takes the mode config locks to be able to check/change the
1581  * modeset configuration. Must be run from process context (which usually means
1582  * either the output polling work or a work item launched from the driver's
1583  * hotplug interrupt).
1584  *
1585  * Note that the driver must ensure that this is only called _after_ the fb has
1586  * been fully set up, i.e. after the call to drm_fb_helper_initial_config.
1587  *
1588  * RETURNS:
1589  * 0 on success and a non-zero error code otherwise.
1590  */
1591 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1592 {
1593 	struct drm_device *dev = fb_helper->dev;
1594 	u32 max_width, max_height;
1595 
1596 	if (!fb_helper->fb)
1597 		return 0;
1598 
1599 	mutex_lock(&fb_helper->dev->mode_config.mutex);
1600 	if (!drm_fb_helper_is_bound(fb_helper)) {
1601 		fb_helper->delayed_hotplug = true;
1602 		mutex_unlock(&fb_helper->dev->mode_config.mutex);
1603 		return 0;
1604 	}
1605 	DRM_DEBUG_KMS("\n");
1606 
1607 	max_width = fb_helper->fb->width;
1608 	max_height = fb_helper->fb->height;
1609 
1610 	drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height);
1611 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
1612 
1613 	drm_modeset_lock_all(dev);
1614 	drm_setup_crtcs(fb_helper);
1615 	drm_modeset_unlock_all(dev);
1616 	drm_fb_helper_set_par(fb_helper->fbdev);
1617 
1618 	return 0;
1619 }
1620 EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
1621 
1622 #ifdef __linux__
1623 /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
1624  * but the module doesn't depend on any fb console symbols.  At least
1625  * attempt to load fbcon to avoid leaving the system without a usable console.
1626  */
1627 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
1628 static int __init drm_fb_helper_modinit(void)
1629 {
1630 	const char *name = "fbcon";
1631 	struct module *fbcon;
1632 
1633 	mutex_lock(&module_mutex);
1634 	fbcon = find_module(name);
1635 	mutex_unlock(&module_mutex);
1636 
1637 	if (!fbcon)
1638 		request_module_nowait(name);
1639 	return 0;
1640 }
1641 
1642 module_init(drm_fb_helper_modinit);
1643 #endif
1644 #endif /* __linux__ */
1645