1 /*
2  * Copyright (c) 2006-2009 Red Hat Inc.
3  * Copyright (c) 2006-2008 Intel Corporation
4  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
5  *
6  * DRM framebuffer helper functions
7  *
8  * Permission to use, copy, modify, distribute, and sell this software and its
9  * documentation for any purpose is hereby granted without fee, provided that
10  * the above copyright notice appear in all copies and that both that copyright
11  * notice and this permission notice appear in supporting documentation, and
12  * that the name of the copyright holders not be used in advertising or
13  * publicity pertaining to distribution of the software without specific,
14  * written prior permission.  The copyright holders make no representations
15  * about the suitability of this software for any purpose.  It is provided "as
16  * is" without express or implied warranty.
17  *
18  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24  * OF THIS SOFTWARE.
25  *
26  * Authors:
27  *      Dave Airlie <airlied@linux.ie>
28  *      Jesse Barnes <jesse.barnes@intel.com>
29  */
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31 
32 #include <linux/console.h>
33 #include <linux/dma-buf.h>
34 #include <linux/kernel.h>
35 #include <linux/sysrq.h>
36 #include <linux/slab.h>
37 #include <linux/module.h>
38 #include <drm/drmP.h>
39 #include <drm/drm_crtc.h>
40 #include <drm/drm_fb_helper.h>
41 #include <drm/drm_crtc_helper.h>
42 #include <drm/drm_atomic.h>
43 #include <drm/drm_atomic_helper.h>
44 
45 #include "drm_crtc_internal.h"
46 #include "drm_crtc_helper_internal.h"
47 
48 static bool drm_fbdev_emulation = true;
49 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
50 MODULE_PARM_DESC(fbdev_emulation,
51 		 "Enable legacy fbdev emulation [default=true]");
52 
53 static int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
54 module_param(drm_fbdev_overalloc, int, 0444);
55 MODULE_PARM_DESC(drm_fbdev_overalloc,
56 		 "Overallocation of the fbdev buffer (%) [default="
57 		 __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
58 
59 static LIST_HEAD(kernel_fb_helper_list);
60 static DEFINE_MUTEX(kernel_fb_helper_lock);
61 
62 /**
63  * DOC: fbdev helpers
64  *
65  * The fb helper functions are useful to provide an fbdev on top of a drm kernel
66  * mode setting driver. They can be used mostly independently from the crtc
67  * helper functions used by many drivers to implement the kernel mode setting
68  * interfaces.
69  *
70  * Drivers that support a dumb buffer with a virtual address and mmap support,
71  * should try out the generic fbdev emulation using drm_fbdev_generic_setup().
72  *
73  * Setup fbdev emulation by calling drm_fb_helper_fbdev_setup() and tear it
74  * down by calling drm_fb_helper_fbdev_teardown().
75  *
76  * Drivers that need to handle connector hotplugging (e.g. dp mst) can't use
77  * the setup helper and will need to do the whole four-step setup process with
78  * drm_fb_helper_prepare(), drm_fb_helper_init(),
79  * drm_fb_helper_single_add_all_connectors(), enable hotplugging and
80  * drm_fb_helper_initial_config() to avoid a possible race window.
81  *
82  * At runtime drivers should restore the fbdev console by using
83  * drm_fb_helper_lastclose() as their &drm_driver.lastclose callback.
84  * They should also notify the fb helper code from updates to the output
85  * configuration by using drm_fb_helper_output_poll_changed() as their
86  * &drm_mode_config_funcs.output_poll_changed callback.
87  *
88  * For suspend/resume consider using drm_mode_config_helper_suspend() and
89  * drm_mode_config_helper_resume() which takes care of fbdev as well.
90  *
91  * All other functions exported by the fb helper library can be used to
92  * implement the fbdev driver interface by the driver.
93  *
94  * It is possible, though perhaps somewhat tricky, to implement race-free
95  * hotplug detection using the fbdev helpers. The drm_fb_helper_prepare()
96  * helper must be called first to initialize the minimum required to make
97  * hotplug detection work. Drivers also need to make sure to properly set up
98  * the &drm_mode_config.funcs member. After calling drm_kms_helper_poll_init()
99  * it is safe to enable interrupts and start processing hotplug events. At the
100  * same time, drivers should initialize all modeset objects such as CRTCs,
101  * encoders and connectors. To finish up the fbdev helper initialization, the
102  * drm_fb_helper_init() function is called. To probe for all attached displays
103  * and set up an initial configuration using the detected hardware, drivers
104  * should call drm_fb_helper_single_add_all_connectors() followed by
105  * drm_fb_helper_initial_config().
106  *
107  * If &drm_framebuffer_funcs.dirty is set, the
108  * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions will
109  * accumulate changes and schedule &drm_fb_helper.dirty_work to run right
110  * away. This worker then calls the dirty() function ensuring that it will
111  * always run in process context since the fb_*() function could be running in
112  * atomic context. If drm_fb_helper_deferred_io() is used as the deferred_io
113  * callback it will also schedule dirty_work with the damage collected from the
114  * mmap page writes. Drivers can use drm_fb_helper_defio_init() to setup
115  * deferred I/O (coupled with drm_fb_helper_fbdev_teardown()).
116  */
117 
118 #define drm_fb_helper_for_each_connector(fbh, i__) \
119 	for (({ lockdep_assert_held(&(fbh)->lock); }), \
120 	     i__ = 0; i__ < (fbh)->connector_count; i__++)
121 
__drm_fb_helper_add_one_connector(struct drm_fb_helper * fb_helper,struct drm_connector * connector)122 static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
123 					     struct drm_connector *connector)
124 {
125 	struct drm_fb_helper_connector *fb_conn;
126 	struct drm_fb_helper_connector **temp;
127 	unsigned int count;
128 
129 	if (!drm_fbdev_emulation)
130 		return 0;
131 
132 	lockdep_assert_held(&fb_helper->lock);
133 
134 	count = fb_helper->connector_count + 1;
135 
136 	if (count > fb_helper->connector_info_alloc_count) {
137 		size_t size = count * sizeof(fb_conn);
138 
139 		temp = krealloc(fb_helper->connector_info, size, GFP_KERNEL);
140 		if (!temp)
141 			return -ENOMEM;
142 
143 		fb_helper->connector_info_alloc_count = count;
144 		fb_helper->connector_info = temp;
145 	}
146 
147 	fb_conn = kzalloc(sizeof(*fb_conn), GFP_KERNEL);
148 	if (!fb_conn)
149 		return -ENOMEM;
150 
151 	drm_connector_get(connector);
152 	fb_conn->connector = connector;
153 	fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
154 
155 	return 0;
156 }
157 
drm_fb_helper_add_one_connector(struct drm_fb_helper * fb_helper,struct drm_connector * connector)158 int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
159 				    struct drm_connector *connector)
160 {
161 	int err;
162 
163 	if (!fb_helper)
164 		return 0;
165 
166 	mutex_lock(&fb_helper->lock);
167 	err = __drm_fb_helper_add_one_connector(fb_helper, connector);
168 	mutex_unlock(&fb_helper->lock);
169 
170 	return err;
171 }
172 EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
173 
174 /**
175  * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
176  * 					       emulation helper
177  * @fb_helper: fbdev initialized with drm_fb_helper_init, can be NULL
178  *
179  * This functions adds all the available connectors for use with the given
180  * fb_helper. This is a separate step to allow drivers to freely assign
181  * connectors to the fbdev, e.g. if some are reserved for special purposes or
182  * not adequate to be used for the fbcon.
183  *
184  * This function is protected against concurrent connector hotadds/removals
185  * using drm_fb_helper_add_one_connector() and
186  * drm_fb_helper_remove_one_connector().
187  */
drm_fb_helper_single_add_all_connectors(struct drm_fb_helper * fb_helper)188 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
189 {
190 	struct drm_device *dev;
191 	struct drm_connector *connector;
192 	struct drm_connector_list_iter conn_iter;
193 	int i, ret = 0;
194 
195 	if (!drm_fbdev_emulation || !fb_helper)
196 		return 0;
197 
198 	dev = fb_helper->dev;
199 
200 	mutex_lock(&fb_helper->lock);
201 	drm_connector_list_iter_begin(dev, &conn_iter);
202 	drm_for_each_connector_iter(connector, &conn_iter) {
203 		ret = __drm_fb_helper_add_one_connector(fb_helper, connector);
204 		if (ret)
205 			goto fail;
206 	}
207 	goto out;
208 
209 fail:
210 	drm_fb_helper_for_each_connector(fb_helper, i) {
211 		struct drm_fb_helper_connector *fb_helper_connector =
212 			fb_helper->connector_info[i];
213 
214 		drm_connector_put(fb_helper_connector->connector);
215 
216 		kfree(fb_helper_connector);
217 		fb_helper->connector_info[i] = NULL;
218 	}
219 	fb_helper->connector_count = 0;
220 out:
221 	drm_connector_list_iter_end(&conn_iter);
222 	mutex_unlock(&fb_helper->lock);
223 
224 	return ret;
225 }
226 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
227 
__drm_fb_helper_remove_one_connector(struct drm_fb_helper * fb_helper,struct drm_connector * connector)228 static int __drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
229 						struct drm_connector *connector)
230 {
231 	struct drm_fb_helper_connector *fb_helper_connector;
232 	int i, j;
233 
234 	if (!drm_fbdev_emulation)
235 		return 0;
236 
237 	lockdep_assert_held(&fb_helper->lock);
238 
239 	drm_fb_helper_for_each_connector(fb_helper, i) {
240 		if (fb_helper->connector_info[i]->connector == connector)
241 			break;
242 	}
243 
244 	if (i == fb_helper->connector_count)
245 		return -EINVAL;
246 	fb_helper_connector = fb_helper->connector_info[i];
247 	drm_connector_put(fb_helper_connector->connector);
248 
249 	for (j = i + 1; j < fb_helper->connector_count; j++)
250 		fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
251 
252 	fb_helper->connector_count--;
253 	kfree(fb_helper_connector);
254 
255 	return 0;
256 }
257 
drm_fb_helper_remove_one_connector(struct drm_fb_helper * fb_helper,struct drm_connector * connector)258 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
259 				       struct drm_connector *connector)
260 {
261 	int err;
262 
263 	if (!fb_helper)
264 		return 0;
265 
266 	mutex_lock(&fb_helper->lock);
267 	err = __drm_fb_helper_remove_one_connector(fb_helper, connector);
268 	mutex_unlock(&fb_helper->lock);
269 
270 	return err;
271 }
272 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
273 
drm_fb_helper_restore_lut_atomic(struct drm_crtc * crtc)274 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
275 {
276 	uint16_t *r_base, *g_base, *b_base;
277 
278 	if (crtc->funcs->gamma_set == NULL)
279 		return;
280 
281 	r_base = crtc->gamma_store;
282 	g_base = r_base + crtc->gamma_size;
283 	b_base = g_base + crtc->gamma_size;
284 
285 	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
286 			       crtc->gamma_size, NULL);
287 }
288 
289 /**
290  * drm_fb_helper_debug_enter - implementation for &fb_ops.fb_debug_enter
291  * @info: fbdev registered by the helper
292  */
drm_fb_helper_debug_enter(struct fb_info * info)293 int drm_fb_helper_debug_enter(struct fb_info *info)
294 {
295 	struct drm_fb_helper *helper = info->par;
296 	const struct drm_crtc_helper_funcs *funcs;
297 	int i;
298 
299 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
300 		for (i = 0; i < helper->crtc_count; i++) {
301 			struct drm_mode_set *mode_set =
302 				&helper->crtc_info[i].mode_set;
303 
304 			if (!mode_set->crtc->enabled)
305 				continue;
306 
307 			funcs =	mode_set->crtc->helper_private;
308 			if (funcs->mode_set_base_atomic == NULL)
309 				continue;
310 
311 			if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
312 				continue;
313 
314 			funcs->mode_set_base_atomic(mode_set->crtc,
315 						    mode_set->fb,
316 						    mode_set->x,
317 						    mode_set->y,
318 						    ENTER_ATOMIC_MODE_SET);
319 		}
320 	}
321 
322 	return 0;
323 }
324 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
325 
326 /**
327  * drm_fb_helper_debug_leave - implementation for &fb_ops.fb_debug_leave
328  * @info: fbdev registered by the helper
329  */
drm_fb_helper_debug_leave(struct fb_info * info)330 int drm_fb_helper_debug_leave(struct fb_info *info)
331 {
332 	struct drm_fb_helper *helper = info->par;
333 	struct drm_crtc *crtc;
334 	const struct drm_crtc_helper_funcs *funcs;
335 	struct drm_framebuffer *fb;
336 	int i;
337 
338 	for (i = 0; i < helper->crtc_count; i++) {
339 		struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
340 
341 		crtc = mode_set->crtc;
342 		if (drm_drv_uses_atomic_modeset(crtc->dev))
343 			continue;
344 
345 		funcs = crtc->helper_private;
346 		fb = crtc->primary->fb;
347 
348 		if (!crtc->enabled)
349 			continue;
350 
351 		if (!fb) {
352 			DRM_ERROR("no fb to restore??\n");
353 			continue;
354 		}
355 
356 		if (funcs->mode_set_base_atomic == NULL)
357 			continue;
358 
359 		drm_fb_helper_restore_lut_atomic(mode_set->crtc);
360 		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
361 					    crtc->y, LEAVE_ATOMIC_MODE_SET);
362 	}
363 
364 	return 0;
365 }
366 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
367 
restore_fbdev_mode_atomic(struct drm_fb_helper * fb_helper,bool active)368 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
369 {
370 	struct drm_device *dev = fb_helper->dev;
371 	struct drm_plane_state *plane_state;
372 	struct drm_plane *plane;
373 	struct drm_atomic_state *state;
374 	int i, ret;
375 	struct drm_modeset_acquire_ctx ctx;
376 
377 	drm_modeset_acquire_init(&ctx, 0);
378 
379 	state = drm_atomic_state_alloc(dev);
380 	if (!state) {
381 		ret = -ENOMEM;
382 		goto out_ctx;
383 	}
384 
385 	state->acquire_ctx = &ctx;
386 retry:
387 	drm_for_each_plane(plane, dev) {
388 		plane_state = drm_atomic_get_plane_state(state, plane);
389 		if (IS_ERR(plane_state)) {
390 			ret = PTR_ERR(plane_state);
391 			goto out_state;
392 		}
393 
394 		plane_state->rotation = DRM_MODE_ROTATE_0;
395 
396 		/* disable non-primary: */
397 		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
398 			continue;
399 
400 		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
401 		if (ret != 0)
402 			goto out_state;
403 	}
404 
405 	for (i = 0; i < fb_helper->crtc_count; i++) {
406 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
407 		struct drm_plane *primary = mode_set->crtc->primary;
408 
409 		/* Cannot fail as we've already gotten the plane state above */
410 		plane_state = drm_atomic_get_new_plane_state(state, primary);
411 		plane_state->rotation = fb_helper->crtc_info[i].rotation;
412 
413 		ret = __drm_atomic_helper_set_config(mode_set, state);
414 		if (ret != 0)
415 			goto out_state;
416 
417 		/*
418 		 * __drm_atomic_helper_set_config() sets active when a
419 		 * mode is set, unconditionally clear it if we force DPMS off
420 		 */
421 		if (!active) {
422 			struct drm_crtc *crtc = mode_set->crtc;
423 			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
424 
425 			crtc_state->active = false;
426 		}
427 	}
428 
429 	ret = drm_atomic_commit(state);
430 
431 out_state:
432 	if (ret == -EDEADLK)
433 		goto backoff;
434 
435 	drm_atomic_state_put(state);
436 out_ctx:
437 	drm_modeset_drop_locks(&ctx);
438 	drm_modeset_acquire_fini(&ctx);
439 
440 	return ret;
441 
442 backoff:
443 	drm_atomic_state_clear(state);
444 	drm_modeset_backoff(&ctx);
445 
446 	goto retry;
447 }
448 
restore_fbdev_mode_legacy(struct drm_fb_helper * fb_helper)449 static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
450 {
451 	struct drm_device *dev = fb_helper->dev;
452 	struct drm_plane *plane;
453 	int i, ret = 0;
454 
455 	drm_modeset_lock_all(fb_helper->dev);
456 	drm_for_each_plane(plane, dev) {
457 		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
458 			drm_plane_force_disable(plane);
459 
460 		if (plane->rotation_property)
461 			drm_mode_plane_set_obj_prop(plane,
462 						    plane->rotation_property,
463 						    DRM_MODE_ROTATE_0);
464 	}
465 
466 	for (i = 0; i < fb_helper->crtc_count; i++) {
467 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
468 		struct drm_crtc *crtc = mode_set->crtc;
469 
470 		if (crtc->funcs->cursor_set2) {
471 			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
472 			if (ret)
473 				goto out;
474 		} else if (crtc->funcs->cursor_set) {
475 			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
476 			if (ret)
477 				goto out;
478 		}
479 
480 		ret = drm_mode_set_config_internal(mode_set);
481 		if (ret)
482 			goto out;
483 	}
484 out:
485 	drm_modeset_unlock_all(fb_helper->dev);
486 
487 	return ret;
488 }
489 
restore_fbdev_mode(struct drm_fb_helper * fb_helper)490 static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
491 {
492 	struct drm_device *dev = fb_helper->dev;
493 
494 	if (drm_drv_uses_atomic_modeset(dev))
495 		return restore_fbdev_mode_atomic(fb_helper, true);
496 	else
497 		return restore_fbdev_mode_legacy(fb_helper);
498 }
499 
500 /**
501  * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
502  * @fb_helper: driver-allocated fbdev helper, can be NULL
503  *
504  * This should be called from driver's drm &drm_driver.lastclose callback
505  * when implementing an fbcon on top of kms using this helper. This ensures that
506  * the user isn't greeted with a black screen when e.g. X dies.
507  *
508  * RETURNS:
509  * Zero if everything went ok, negative error code otherwise.
510  */
drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper * fb_helper)511 int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
512 {
513 	bool do_delayed;
514 	int ret;
515 
516 	if (!drm_fbdev_emulation || !fb_helper)
517 		return -ENODEV;
518 
519 	if (READ_ONCE(fb_helper->deferred_setup))
520 		return 0;
521 
522 	mutex_lock(&fb_helper->lock);
523 	ret = restore_fbdev_mode(fb_helper);
524 
525 	do_delayed = fb_helper->delayed_hotplug;
526 	if (do_delayed)
527 		fb_helper->delayed_hotplug = false;
528 	mutex_unlock(&fb_helper->lock);
529 
530 	if (do_delayed)
531 		drm_fb_helper_hotplug_event(fb_helper);
532 
533 	return ret;
534 }
535 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
536 
drm_fb_helper_is_bound(struct drm_fb_helper * fb_helper)537 static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
538 {
539 	struct drm_device *dev = fb_helper->dev;
540 	struct drm_crtc *crtc;
541 	int bound = 0, crtcs_bound = 0;
542 
543 	/*
544 	 * Sometimes user space wants everything disabled, so don't steal the
545 	 * display if there's a master.
546 	 */
547 	if (READ_ONCE(dev->master))
548 		return false;
549 
550 	drm_for_each_crtc(crtc, dev) {
551 		drm_modeset_lock(&crtc->mutex, NULL);
552 		if (crtc->primary->fb)
553 			crtcs_bound++;
554 		if (crtc->primary->fb == fb_helper->fb)
555 			bound++;
556 		drm_modeset_unlock(&crtc->mutex);
557 	}
558 
559 	if (bound < crtcs_bound)
560 		return false;
561 
562 	return true;
563 }
564 
565 #ifdef CONFIG_MAGIC_SYSRQ
566 /*
567  * restore fbcon display for all kms driver's using this helper, used for sysrq
568  * and panic handling.
569  */
drm_fb_helper_force_kernel_mode(void)570 static bool drm_fb_helper_force_kernel_mode(void)
571 {
572 	bool ret, error = false;
573 	struct drm_fb_helper *helper;
574 
575 	if (list_empty(&kernel_fb_helper_list))
576 		return false;
577 
578 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
579 		struct drm_device *dev = helper->dev;
580 
581 		if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
582 			continue;
583 
584 		mutex_lock(&helper->lock);
585 		ret = restore_fbdev_mode(helper);
586 		if (ret)
587 			error = true;
588 		mutex_unlock(&helper->lock);
589 	}
590 	return error;
591 }
592 
drm_fb_helper_restore_work_fn(struct work_struct * ignored)593 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
594 {
595 	bool ret;
596 
597 	ret = drm_fb_helper_force_kernel_mode();
598 	if (ret == true)
599 		DRM_ERROR("Failed to restore crtc configuration\n");
600 }
601 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
602 
drm_fb_helper_sysrq(int dummy1)603 static void drm_fb_helper_sysrq(int dummy1)
604 {
605 	schedule_work(&drm_fb_helper_restore_work);
606 }
607 
608 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
609 	.handler = drm_fb_helper_sysrq,
610 	.help_msg = "force-fb(V)",
611 	.action_msg = "Restore framebuffer console",
612 };
613 #else
614 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
615 #endif
616 
dpms_legacy(struct drm_fb_helper * fb_helper,int dpms_mode)617 static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
618 {
619 	struct drm_device *dev = fb_helper->dev;
620 	struct drm_crtc *crtc;
621 	struct drm_connector *connector;
622 	int i, j;
623 
624 	drm_modeset_lock_all(dev);
625 	for (i = 0; i < fb_helper->crtc_count; i++) {
626 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
627 
628 		if (!crtc->enabled)
629 			continue;
630 
631 		/* Walk the connectors & encoders on this fb turning them on/off */
632 		drm_fb_helper_for_each_connector(fb_helper, j) {
633 			connector = fb_helper->connector_info[j]->connector;
634 			connector->funcs->dpms(connector, dpms_mode);
635 			drm_object_property_set_value(&connector->base,
636 				dev->mode_config.dpms_property, dpms_mode);
637 		}
638 	}
639 	drm_modeset_unlock_all(dev);
640 }
641 
drm_fb_helper_dpms(struct fb_info * info,int dpms_mode)642 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
643 {
644 	struct drm_fb_helper *fb_helper = info->par;
645 
646 	/*
647 	 * For each CRTC in this fb, turn the connectors on/off.
648 	 */
649 	mutex_lock(&fb_helper->lock);
650 	if (!drm_fb_helper_is_bound(fb_helper)) {
651 		mutex_unlock(&fb_helper->lock);
652 		return;
653 	}
654 
655 	if (drm_drv_uses_atomic_modeset(fb_helper->dev))
656 		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
657 	else
658 		dpms_legacy(fb_helper, dpms_mode);
659 	mutex_unlock(&fb_helper->lock);
660 }
661 
662 /**
663  * drm_fb_helper_blank - implementation for &fb_ops.fb_blank
664  * @blank: desired blanking state
665  * @info: fbdev registered by the helper
666  */
drm_fb_helper_blank(int blank,struct fb_info * info)667 int drm_fb_helper_blank(int blank, struct fb_info *info)
668 {
669 	if (oops_in_progress)
670 		return -EBUSY;
671 
672 	switch (blank) {
673 	/* Display: On; HSync: On, VSync: On */
674 	case FB_BLANK_UNBLANK:
675 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
676 		break;
677 	/* Display: Off; HSync: On, VSync: On */
678 	case FB_BLANK_NORMAL:
679 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
680 		break;
681 	/* Display: Off; HSync: Off, VSync: On */
682 	case FB_BLANK_HSYNC_SUSPEND:
683 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
684 		break;
685 	/* Display: Off; HSync: On, VSync: Off */
686 	case FB_BLANK_VSYNC_SUSPEND:
687 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
688 		break;
689 	/* Display: Off; HSync: Off, VSync: Off */
690 	case FB_BLANK_POWERDOWN:
691 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
692 		break;
693 	}
694 	return 0;
695 }
696 EXPORT_SYMBOL(drm_fb_helper_blank);
697 
drm_fb_helper_modeset_release(struct drm_fb_helper * helper,struct drm_mode_set * modeset)698 static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
699 					  struct drm_mode_set *modeset)
700 {
701 	int i;
702 
703 	for (i = 0; i < modeset->num_connectors; i++) {
704 		drm_connector_put(modeset->connectors[i]);
705 		modeset->connectors[i] = NULL;
706 	}
707 	modeset->num_connectors = 0;
708 
709 	drm_mode_destroy(helper->dev, modeset->mode);
710 	modeset->mode = NULL;
711 
712 	/* FIXME should hold a ref? */
713 	modeset->fb = NULL;
714 }
715 
drm_fb_helper_crtc_free(struct drm_fb_helper * helper)716 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
717 {
718 	int i;
719 
720 	for (i = 0; i < helper->connector_count; i++) {
721 		drm_connector_put(helper->connector_info[i]->connector);
722 		kfree(helper->connector_info[i]);
723 	}
724 	kfree(helper->connector_info);
725 
726 	for (i = 0; i < helper->crtc_count; i++) {
727 		struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
728 
729 		drm_fb_helper_modeset_release(helper, modeset);
730 		kfree(modeset->connectors);
731 	}
732 	kfree(helper->crtc_info);
733 }
734 
drm_fb_helper_resume_worker(struct work_struct * work)735 static void drm_fb_helper_resume_worker(struct work_struct *work)
736 {
737 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
738 						    resume_work);
739 
740 	console_lock();
741 	fb_set_suspend(helper->fbdev, 0);
742 	console_unlock();
743 }
744 
drm_fb_helper_dirty_blit_real(struct drm_fb_helper * fb_helper,struct drm_clip_rect * clip)745 static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper,
746 					  struct drm_clip_rect *clip)
747 {
748 	struct drm_framebuffer *fb = fb_helper->fb;
749 	unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
750 	size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp;
751 	void *src = fb_helper->fbdev->screen_buffer + offset;
752 	void *dst = fb_helper->buffer->vaddr + offset;
753 	size_t len = (clip->x2 - clip->x1) * cpp;
754 	unsigned int y;
755 
756 	for (y = clip->y1; y < clip->y2; y++) {
757 		memcpy(dst, src, len);
758 		src += fb->pitches[0];
759 		dst += fb->pitches[0];
760 	}
761 }
762 
drm_fb_helper_dirty_work(struct work_struct * work)763 static void drm_fb_helper_dirty_work(struct work_struct *work)
764 {
765 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
766 						    dirty_work);
767 	struct drm_clip_rect *clip = &helper->dirty_clip;
768 	struct drm_clip_rect clip_copy;
769 	unsigned long flags;
770 
771 	spin_lock_irqsave(&helper->dirty_lock, flags);
772 	clip_copy = *clip;
773 	clip->x1 = clip->y1 = ~0;
774 	clip->x2 = clip->y2 = 0;
775 	spin_unlock_irqrestore(&helper->dirty_lock, flags);
776 
777 	/* call dirty callback only when it has been really touched */
778 	if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2) {
779 		/* Generic fbdev uses a shadow buffer */
780 		if (helper->buffer)
781 			drm_fb_helper_dirty_blit_real(helper, &clip_copy);
782 		helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
783 	}
784 }
785 
786 /**
787  * drm_fb_helper_prepare - setup a drm_fb_helper structure
788  * @dev: DRM device
789  * @helper: driver-allocated fbdev helper structure to set up
790  * @funcs: pointer to structure of functions associate with this helper
791  *
792  * Sets up the bare minimum to make the framebuffer helper usable. This is
793  * useful to implement race-free initialization of the polling helpers.
794  */
drm_fb_helper_prepare(struct drm_device * dev,struct drm_fb_helper * helper,const struct drm_fb_helper_funcs * funcs)795 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
796 			   const struct drm_fb_helper_funcs *funcs)
797 {
798 	INIT_LIST_HEAD(&helper->kernel_fb_list);
799 	spin_lock_init(&helper->dirty_lock);
800 	INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
801 	INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
802 	helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
803 	mutex_init(&helper->lock);
804 	helper->funcs = funcs;
805 	helper->dev = dev;
806 }
807 EXPORT_SYMBOL(drm_fb_helper_prepare);
808 
809 /**
810  * drm_fb_helper_init - initialize a &struct drm_fb_helper
811  * @dev: drm device
812  * @fb_helper: driver-allocated fbdev helper structure to initialize
813  * @max_conn_count: max connector count
814  *
815  * This allocates the structures for the fbdev helper with the given limits.
816  * Note that this won't yet touch the hardware (through the driver interfaces)
817  * nor register the fbdev. This is only done in drm_fb_helper_initial_config()
818  * to allow driver writes more control over the exact init sequence.
819  *
820  * Drivers must call drm_fb_helper_prepare() before calling this function.
821  *
822  * RETURNS:
823  * Zero if everything went ok, nonzero otherwise.
824  */
drm_fb_helper_init(struct drm_device * dev,struct drm_fb_helper * fb_helper,int max_conn_count)825 int drm_fb_helper_init(struct drm_device *dev,
826 		       struct drm_fb_helper *fb_helper,
827 		       int max_conn_count)
828 {
829 	struct drm_crtc *crtc;
830 	struct drm_mode_config *config = &dev->mode_config;
831 	int i;
832 
833 	if (!drm_fbdev_emulation) {
834 		dev->fb_helper = fb_helper;
835 		return 0;
836 	}
837 
838 	if (!max_conn_count)
839 		return -EINVAL;
840 
841 	fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
842 	if (!fb_helper->crtc_info)
843 		return -ENOMEM;
844 
845 	fb_helper->crtc_count = config->num_crtc;
846 	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
847 	if (!fb_helper->connector_info) {
848 		kfree(fb_helper->crtc_info);
849 		return -ENOMEM;
850 	}
851 	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
852 	fb_helper->connector_count = 0;
853 
854 	for (i = 0; i < fb_helper->crtc_count; i++) {
855 		fb_helper->crtc_info[i].mode_set.connectors =
856 			kcalloc(max_conn_count,
857 				sizeof(struct drm_connector *),
858 				GFP_KERNEL);
859 
860 		if (!fb_helper->crtc_info[i].mode_set.connectors)
861 			goto out_free;
862 		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
863 		fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
864 	}
865 
866 	i = 0;
867 	drm_for_each_crtc(crtc, dev) {
868 		fb_helper->crtc_info[i].mode_set.crtc = crtc;
869 		i++;
870 	}
871 
872 	dev->fb_helper = fb_helper;
873 
874 	return 0;
875 out_free:
876 	drm_fb_helper_crtc_free(fb_helper);
877 	return -ENOMEM;
878 }
879 EXPORT_SYMBOL(drm_fb_helper_init);
880 
881 /**
882  * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members
883  * @fb_helper: driver-allocated fbdev helper
884  *
885  * A helper to alloc fb_info and the members cmap and apertures. Called
886  * by the driver within the fb_probe fb_helper callback function. Drivers do not
887  * need to release the allocated fb_info structure themselves, this is
888  * automatically done when calling drm_fb_helper_fini().
889  *
890  * RETURNS:
891  * fb_info pointer if things went okay, pointer containing error code
892  * otherwise
893  */
drm_fb_helper_alloc_fbi(struct drm_fb_helper * fb_helper)894 struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
895 {
896 	struct device *dev = fb_helper->dev->dev;
897 	struct fb_info *info;
898 	int ret;
899 
900 	info = framebuffer_alloc(0, dev);
901 	if (!info)
902 		return ERR_PTR(-ENOMEM);
903 
904 	ret = fb_alloc_cmap(&info->cmap, 256, 0);
905 	if (ret)
906 		goto err_release;
907 
908 	info->apertures = alloc_apertures(1);
909 	if (!info->apertures) {
910 		ret = -ENOMEM;
911 		goto err_free_cmap;
912 	}
913 
914 	fb_helper->fbdev = info;
915 
916 	return info;
917 
918 err_free_cmap:
919 	fb_dealloc_cmap(&info->cmap);
920 err_release:
921 	framebuffer_release(info);
922 	return ERR_PTR(ret);
923 }
924 EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
925 
926 /**
927  * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device
928  * @fb_helper: driver-allocated fbdev helper, can be NULL
929  *
930  * A wrapper around unregister_framebuffer, to release the fb_info
931  * framebuffer device. This must be called before releasing all resources for
932  * @fb_helper by calling drm_fb_helper_fini().
933  */
drm_fb_helper_unregister_fbi(struct drm_fb_helper * fb_helper)934 void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
935 {
936 	if (fb_helper && fb_helper->fbdev)
937 		unregister_framebuffer(fb_helper->fbdev);
938 }
939 EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
940 
941 /**
942  * drm_fb_helper_fini - finialize a &struct drm_fb_helper
943  * @fb_helper: driver-allocated fbdev helper, can be NULL
944  *
945  * This cleans up all remaining resources associated with @fb_helper. Must be
946  * called after drm_fb_helper_unlink_fbi() was called.
947  */
drm_fb_helper_fini(struct drm_fb_helper * fb_helper)948 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
949 {
950 	struct fb_info *info;
951 
952 	if (!fb_helper)
953 		return;
954 
955 	fb_helper->dev->fb_helper = NULL;
956 
957 	if (!drm_fbdev_emulation)
958 		return;
959 
960 	cancel_work_sync(&fb_helper->resume_work);
961 	cancel_work_sync(&fb_helper->dirty_work);
962 
963 	info = fb_helper->fbdev;
964 	if (info) {
965 		if (info->cmap.len)
966 			fb_dealloc_cmap(&info->cmap);
967 		framebuffer_release(info);
968 	}
969 	fb_helper->fbdev = NULL;
970 
971 	mutex_lock(&kernel_fb_helper_lock);
972 	if (!list_empty(&fb_helper->kernel_fb_list)) {
973 		list_del(&fb_helper->kernel_fb_list);
974 		if (list_empty(&kernel_fb_helper_list))
975 			unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
976 	}
977 	mutex_unlock(&kernel_fb_helper_lock);
978 
979 	mutex_destroy(&fb_helper->lock);
980 	drm_fb_helper_crtc_free(fb_helper);
981 
982 }
983 EXPORT_SYMBOL(drm_fb_helper_fini);
984 
985 /**
986  * drm_fb_helper_unlink_fbi - wrapper around unlink_framebuffer
987  * @fb_helper: driver-allocated fbdev helper, can be NULL
988  *
989  * A wrapper around unlink_framebuffer implemented by fbdev core
990  */
drm_fb_helper_unlink_fbi(struct drm_fb_helper * fb_helper)991 void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
992 {
993 	if (fb_helper && fb_helper->fbdev)
994 		unlink_framebuffer(fb_helper->fbdev);
995 }
996 EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
997 
drm_fb_helper_dirty(struct fb_info * info,u32 x,u32 y,u32 width,u32 height)998 static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
999 				u32 width, u32 height)
1000 {
1001 	struct drm_fb_helper *helper = info->par;
1002 	struct drm_clip_rect *clip = &helper->dirty_clip;
1003 	unsigned long flags;
1004 
1005 	if (!helper->fb->funcs->dirty)
1006 		return;
1007 
1008 	spin_lock_irqsave(&helper->dirty_lock, flags);
1009 	clip->x1 = min_t(u32, clip->x1, x);
1010 	clip->y1 = min_t(u32, clip->y1, y);
1011 	clip->x2 = max_t(u32, clip->x2, x + width);
1012 	clip->y2 = max_t(u32, clip->y2, y + height);
1013 	spin_unlock_irqrestore(&helper->dirty_lock, flags);
1014 
1015 	schedule_work(&helper->dirty_work);
1016 }
1017 
1018 /**
1019  * drm_fb_helper_deferred_io() - fbdev deferred_io callback function
1020  * @info: fb_info struct pointer
1021  * @pagelist: list of dirty mmap framebuffer pages
1022  *
1023  * This function is used as the &fb_deferred_io.deferred_io
1024  * callback function for flushing the fbdev mmap writes.
1025  */
drm_fb_helper_deferred_io(struct fb_info * info,struct list_head * pagelist)1026 void drm_fb_helper_deferred_io(struct fb_info *info,
1027 			       struct list_head *pagelist)
1028 {
1029 	unsigned long start, end, min, max;
1030 	struct page *page;
1031 	u32 y1, y2;
1032 
1033 	min = ULONG_MAX;
1034 	max = 0;
1035 	list_for_each_entry(page, pagelist, lru) {
1036 		start = page->index << PAGE_SHIFT;
1037 		end = start + PAGE_SIZE - 1;
1038 		min = min(min, start);
1039 		max = max(max, end);
1040 	}
1041 
1042 	if (min < max) {
1043 		y1 = min / info->fix.line_length;
1044 		y2 = min_t(u32, DIV_ROUND_UP(max, info->fix.line_length),
1045 			   info->var.yres);
1046 		drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
1047 	}
1048 }
1049 EXPORT_SYMBOL(drm_fb_helper_deferred_io);
1050 
1051 /**
1052  * drm_fb_helper_defio_init - fbdev deferred I/O initialization
1053  * @fb_helper: driver-allocated fbdev helper
1054  *
1055  * This function allocates &fb_deferred_io, sets callback to
1056  * drm_fb_helper_deferred_io(), delay to 50ms and calls fb_deferred_io_init().
1057  * It should be called from the &drm_fb_helper_funcs->fb_probe callback.
1058  * drm_fb_helper_fbdev_teardown() cleans up deferred I/O.
1059  *
1060  * NOTE: A copy of &fb_ops is made and assigned to &info->fbops. This is done
1061  * because fb_deferred_io_cleanup() clears &fbops->fb_mmap and would thereby
1062  * affect other instances of that &fb_ops.
1063  *
1064  * Returns:
1065  * 0 on success or a negative error code on failure.
1066  */
drm_fb_helper_defio_init(struct drm_fb_helper * fb_helper)1067 int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
1068 {
1069 	struct fb_info *info = fb_helper->fbdev;
1070 	struct fb_deferred_io *fbdefio;
1071 	struct fb_ops *fbops;
1072 
1073 	fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL);
1074 	fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
1075 	if (!fbdefio || !fbops) {
1076 		kfree(fbdefio);
1077 		kfree(fbops);
1078 		return -ENOMEM;
1079 	}
1080 
1081 	info->fbdefio = fbdefio;
1082 	fbdefio->delay = msecs_to_jiffies(50);
1083 	fbdefio->deferred_io = drm_fb_helper_deferred_io;
1084 
1085 	*fbops = *info->fbops;
1086 	info->fbops = fbops;
1087 
1088 	fb_deferred_io_init(info);
1089 
1090 	return 0;
1091 }
1092 EXPORT_SYMBOL(drm_fb_helper_defio_init);
1093 
1094 /**
1095  * drm_fb_helper_sys_read - wrapper around fb_sys_read
1096  * @info: fb_info struct pointer
1097  * @buf: userspace buffer to read from framebuffer memory
1098  * @count: number of bytes to read from framebuffer memory
1099  * @ppos: read offset within framebuffer memory
1100  *
1101  * A wrapper around fb_sys_read implemented by fbdev core
1102  */
drm_fb_helper_sys_read(struct fb_info * info,char __user * buf,size_t count,loff_t * ppos)1103 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
1104 			       size_t count, loff_t *ppos)
1105 {
1106 	return fb_sys_read(info, buf, count, ppos);
1107 }
1108 EXPORT_SYMBOL(drm_fb_helper_sys_read);
1109 
1110 /**
1111  * drm_fb_helper_sys_write - wrapper around fb_sys_write
1112  * @info: fb_info struct pointer
1113  * @buf: userspace buffer to write to framebuffer memory
1114  * @count: number of bytes to write to framebuffer memory
1115  * @ppos: write offset within framebuffer memory
1116  *
1117  * A wrapper around fb_sys_write implemented by fbdev core
1118  */
drm_fb_helper_sys_write(struct fb_info * info,const char __user * buf,size_t count,loff_t * ppos)1119 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
1120 				size_t count, loff_t *ppos)
1121 {
1122 	ssize_t ret;
1123 
1124 	ret = fb_sys_write(info, buf, count, ppos);
1125 	if (ret > 0)
1126 		drm_fb_helper_dirty(info, 0, 0, info->var.xres,
1127 				    info->var.yres);
1128 
1129 	return ret;
1130 }
1131 EXPORT_SYMBOL(drm_fb_helper_sys_write);
1132 
1133 /**
1134  * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect
1135  * @info: fbdev registered by the helper
1136  * @rect: info about rectangle to fill
1137  *
1138  * A wrapper around sys_fillrect implemented by fbdev core
1139  */
drm_fb_helper_sys_fillrect(struct fb_info * info,const struct fb_fillrect * rect)1140 void drm_fb_helper_sys_fillrect(struct fb_info *info,
1141 				const struct fb_fillrect *rect)
1142 {
1143 	sys_fillrect(info, rect);
1144 	drm_fb_helper_dirty(info, rect->dx, rect->dy,
1145 			    rect->width, rect->height);
1146 }
1147 EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
1148 
1149 /**
1150  * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea
1151  * @info: fbdev registered by the helper
1152  * @area: info about area to copy
1153  *
1154  * A wrapper around sys_copyarea implemented by fbdev core
1155  */
drm_fb_helper_sys_copyarea(struct fb_info * info,const struct fb_copyarea * area)1156 void drm_fb_helper_sys_copyarea(struct fb_info *info,
1157 				const struct fb_copyarea *area)
1158 {
1159 	sys_copyarea(info, area);
1160 	drm_fb_helper_dirty(info, area->dx, area->dy,
1161 			    area->width, area->height);
1162 }
1163 EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
1164 
1165 /**
1166  * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit
1167  * @info: fbdev registered by the helper
1168  * @image: info about image to blit
1169  *
1170  * A wrapper around sys_imageblit implemented by fbdev core
1171  */
drm_fb_helper_sys_imageblit(struct fb_info * info,const struct fb_image * image)1172 void drm_fb_helper_sys_imageblit(struct fb_info *info,
1173 				 const struct fb_image *image)
1174 {
1175 	sys_imageblit(info, image);
1176 	drm_fb_helper_dirty(info, image->dx, image->dy,
1177 			    image->width, image->height);
1178 }
1179 EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
1180 
1181 /**
1182  * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect
1183  * @info: fbdev registered by the helper
1184  * @rect: info about rectangle to fill
1185  *
1186  * A wrapper around cfb_fillrect implemented by fbdev core
1187  */
drm_fb_helper_cfb_fillrect(struct fb_info * info,const struct fb_fillrect * rect)1188 void drm_fb_helper_cfb_fillrect(struct fb_info *info,
1189 				const struct fb_fillrect *rect)
1190 {
1191 	cfb_fillrect(info, rect);
1192 	drm_fb_helper_dirty(info, rect->dx, rect->dy,
1193 			    rect->width, rect->height);
1194 }
1195 EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
1196 
1197 /**
1198  * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea
1199  * @info: fbdev registered by the helper
1200  * @area: info about area to copy
1201  *
1202  * A wrapper around cfb_copyarea implemented by fbdev core
1203  */
drm_fb_helper_cfb_copyarea(struct fb_info * info,const struct fb_copyarea * area)1204 void drm_fb_helper_cfb_copyarea(struct fb_info *info,
1205 				const struct fb_copyarea *area)
1206 {
1207 	cfb_copyarea(info, area);
1208 	drm_fb_helper_dirty(info, area->dx, area->dy,
1209 			    area->width, area->height);
1210 }
1211 EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
1212 
1213 /**
1214  * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit
1215  * @info: fbdev registered by the helper
1216  * @image: info about image to blit
1217  *
1218  * A wrapper around cfb_imageblit implemented by fbdev core
1219  */
drm_fb_helper_cfb_imageblit(struct fb_info * info,const struct fb_image * image)1220 void drm_fb_helper_cfb_imageblit(struct fb_info *info,
1221 				 const struct fb_image *image)
1222 {
1223 	cfb_imageblit(info, image);
1224 	drm_fb_helper_dirty(info, image->dx, image->dy,
1225 			    image->width, image->height);
1226 }
1227 EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
1228 
1229 /**
1230  * drm_fb_helper_set_suspend - wrapper around fb_set_suspend
1231  * @fb_helper: driver-allocated fbdev helper, can be NULL
1232  * @suspend: whether to suspend or resume
1233  *
1234  * A wrapper around fb_set_suspend implemented by fbdev core.
1235  * Use drm_fb_helper_set_suspend_unlocked() if you don't need to take
1236  * the lock yourself
1237  */
drm_fb_helper_set_suspend(struct drm_fb_helper * fb_helper,bool suspend)1238 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend)
1239 {
1240 	if (fb_helper && fb_helper->fbdev)
1241 		fb_set_suspend(fb_helper->fbdev, suspend);
1242 }
1243 EXPORT_SYMBOL(drm_fb_helper_set_suspend);
1244 
1245 /**
1246  * drm_fb_helper_set_suspend_unlocked - wrapper around fb_set_suspend that also
1247  *                                      takes the console lock
1248  * @fb_helper: driver-allocated fbdev helper, can be NULL
1249  * @suspend: whether to suspend or resume
1250  *
1251  * A wrapper around fb_set_suspend() that takes the console lock. If the lock
1252  * isn't available on resume, a worker is tasked with waiting for the lock
1253  * to become available. The console lock can be pretty contented on resume
1254  * due to all the printk activity.
1255  *
1256  * This function can be called multiple times with the same state since
1257  * &fb_info.state is checked to see if fbdev is running or not before locking.
1258  *
1259  * Use drm_fb_helper_set_suspend() if you need to take the lock yourself.
1260  */
drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper * fb_helper,bool suspend)1261 void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
1262 					bool suspend)
1263 {
1264 	if (!fb_helper || !fb_helper->fbdev)
1265 		return;
1266 
1267 	/* make sure there's no pending/ongoing resume */
1268 	flush_work(&fb_helper->resume_work);
1269 
1270 	if (suspend) {
1271 		if (fb_helper->fbdev->state != FBINFO_STATE_RUNNING)
1272 			return;
1273 
1274 		console_lock();
1275 
1276 	} else {
1277 		if (fb_helper->fbdev->state == FBINFO_STATE_RUNNING)
1278 			return;
1279 
1280 		if (!console_trylock()) {
1281 			schedule_work(&fb_helper->resume_work);
1282 			return;
1283 		}
1284 	}
1285 
1286 	fb_set_suspend(fb_helper->fbdev, suspend);
1287 	console_unlock();
1288 }
1289 EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
1290 
setcmap_pseudo_palette(struct fb_cmap * cmap,struct fb_info * info)1291 static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
1292 {
1293 	u32 *palette = (u32 *)info->pseudo_palette;
1294 	int i;
1295 
1296 	if (cmap->start + cmap->len > 16)
1297 		return -EINVAL;
1298 
1299 	for (i = 0; i < cmap->len; ++i) {
1300 		u16 red = cmap->red[i];
1301 		u16 green = cmap->green[i];
1302 		u16 blue = cmap->blue[i];
1303 		u32 value;
1304 
1305 		red >>= 16 - info->var.red.length;
1306 		green >>= 16 - info->var.green.length;
1307 		blue >>= 16 - info->var.blue.length;
1308 		value = (red << info->var.red.offset) |
1309 			(green << info->var.green.offset) |
1310 			(blue << info->var.blue.offset);
1311 		if (info->var.transp.length > 0) {
1312 			u32 mask = (1 << info->var.transp.length) - 1;
1313 
1314 			mask <<= info->var.transp.offset;
1315 			value |= mask;
1316 		}
1317 		palette[cmap->start + i] = value;
1318 	}
1319 
1320 	return 0;
1321 }
1322 
setcmap_legacy(struct fb_cmap * cmap,struct fb_info * info)1323 static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
1324 {
1325 	struct drm_fb_helper *fb_helper = info->par;
1326 	struct drm_crtc *crtc;
1327 	u16 *r, *g, *b;
1328 	int i, ret = 0;
1329 
1330 	drm_modeset_lock_all(fb_helper->dev);
1331 	for (i = 0; i < fb_helper->crtc_count; i++) {
1332 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
1333 		if (!crtc->funcs->gamma_set || !crtc->gamma_size)
1334 			return -EINVAL;
1335 
1336 		if (cmap->start + cmap->len > crtc->gamma_size)
1337 			return -EINVAL;
1338 
1339 		r = crtc->gamma_store;
1340 		g = r + crtc->gamma_size;
1341 		b = g + crtc->gamma_size;
1342 
1343 		memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
1344 		memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
1345 		memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
1346 
1347 		ret = crtc->funcs->gamma_set(crtc, r, g, b,
1348 					     crtc->gamma_size, NULL);
1349 		if (ret)
1350 			return ret;
1351 	}
1352 	drm_modeset_unlock_all(fb_helper->dev);
1353 
1354 	return ret;
1355 }
1356 
setcmap_new_gamma_lut(struct drm_crtc * crtc,struct fb_cmap * cmap)1357 static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc,
1358 						       struct fb_cmap *cmap)
1359 {
1360 	struct drm_device *dev = crtc->dev;
1361 	struct drm_property_blob *gamma_lut;
1362 	struct drm_color_lut *lut;
1363 	int size = crtc->gamma_size;
1364 	int i;
1365 
1366 	if (!size || cmap->start + cmap->len > size)
1367 		return ERR_PTR(-EINVAL);
1368 
1369 	gamma_lut = drm_property_create_blob(dev, sizeof(*lut) * size, NULL);
1370 	if (IS_ERR(gamma_lut))
1371 		return gamma_lut;
1372 
1373 	lut = gamma_lut->data;
1374 	if (cmap->start || cmap->len != size) {
1375 		u16 *r = crtc->gamma_store;
1376 		u16 *g = r + crtc->gamma_size;
1377 		u16 *b = g + crtc->gamma_size;
1378 
1379 		for (i = 0; i < cmap->start; i++) {
1380 			lut[i].red = r[i];
1381 			lut[i].green = g[i];
1382 			lut[i].blue = b[i];
1383 		}
1384 		for (i = cmap->start + cmap->len; i < size; i++) {
1385 			lut[i].red = r[i];
1386 			lut[i].green = g[i];
1387 			lut[i].blue = b[i];
1388 		}
1389 	}
1390 
1391 	for (i = 0; i < cmap->len; i++) {
1392 		lut[cmap->start + i].red = cmap->red[i];
1393 		lut[cmap->start + i].green = cmap->green[i];
1394 		lut[cmap->start + i].blue = cmap->blue[i];
1395 	}
1396 
1397 	return gamma_lut;
1398 }
1399 
setcmap_atomic(struct fb_cmap * cmap,struct fb_info * info)1400 static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
1401 {
1402 	struct drm_fb_helper *fb_helper = info->par;
1403 	struct drm_device *dev = fb_helper->dev;
1404 	struct drm_property_blob *gamma_lut = NULL;
1405 	struct drm_modeset_acquire_ctx ctx;
1406 	struct drm_crtc_state *crtc_state;
1407 	struct drm_atomic_state *state;
1408 	struct drm_crtc *crtc;
1409 	u16 *r, *g, *b;
1410 	int i, ret = 0;
1411 	bool replaced;
1412 
1413 	drm_modeset_acquire_init(&ctx, 0);
1414 
1415 	state = drm_atomic_state_alloc(dev);
1416 	if (!state) {
1417 		ret = -ENOMEM;
1418 		goto out_ctx;
1419 	}
1420 
1421 	state->acquire_ctx = &ctx;
1422 retry:
1423 	for (i = 0; i < fb_helper->crtc_count; i++) {
1424 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
1425 
1426 		if (!gamma_lut)
1427 			gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
1428 		if (IS_ERR(gamma_lut)) {
1429 			ret = PTR_ERR(gamma_lut);
1430 			gamma_lut = NULL;
1431 			goto out_state;
1432 		}
1433 
1434 		crtc_state = drm_atomic_get_crtc_state(state, crtc);
1435 		if (IS_ERR(crtc_state)) {
1436 			ret = PTR_ERR(crtc_state);
1437 			goto out_state;
1438 		}
1439 
1440 		replaced  = drm_property_replace_blob(&crtc_state->degamma_lut,
1441 						      NULL);
1442 		replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
1443 		replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
1444 						      gamma_lut);
1445 		crtc_state->color_mgmt_changed |= replaced;
1446 	}
1447 
1448 	ret = drm_atomic_commit(state);
1449 	if (ret)
1450 		goto out_state;
1451 
1452 	for (i = 0; i < fb_helper->crtc_count; i++) {
1453 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
1454 
1455 		r = crtc->gamma_store;
1456 		g = r + crtc->gamma_size;
1457 		b = g + crtc->gamma_size;
1458 
1459 		memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
1460 		memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
1461 		memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
1462 	}
1463 
1464 out_state:
1465 	if (ret == -EDEADLK)
1466 		goto backoff;
1467 
1468 	drm_property_blob_put(gamma_lut);
1469 	drm_atomic_state_put(state);
1470 out_ctx:
1471 	drm_modeset_drop_locks(&ctx);
1472 	drm_modeset_acquire_fini(&ctx);
1473 
1474 	return ret;
1475 
1476 backoff:
1477 	drm_atomic_state_clear(state);
1478 	drm_modeset_backoff(&ctx);
1479 	goto retry;
1480 }
1481 
1482 /**
1483  * drm_fb_helper_setcmap - implementation for &fb_ops.fb_setcmap
1484  * @cmap: cmap to set
1485  * @info: fbdev registered by the helper
1486  */
drm_fb_helper_setcmap(struct fb_cmap * cmap,struct fb_info * info)1487 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1488 {
1489 	struct drm_fb_helper *fb_helper = info->par;
1490 	int ret;
1491 
1492 	if (oops_in_progress)
1493 		return -EBUSY;
1494 
1495 	mutex_lock(&fb_helper->lock);
1496 
1497 	if (!drm_fb_helper_is_bound(fb_helper)) {
1498 		ret = -EBUSY;
1499 		goto out;
1500 	}
1501 
1502 	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
1503 		ret = setcmap_pseudo_palette(cmap, info);
1504 	else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
1505 		ret = setcmap_atomic(cmap, info);
1506 	else
1507 		ret = setcmap_legacy(cmap, info);
1508 
1509 out:
1510 	mutex_unlock(&fb_helper->lock);
1511 
1512 	return ret;
1513 }
1514 EXPORT_SYMBOL(drm_fb_helper_setcmap);
1515 
1516 /**
1517  * drm_fb_helper_ioctl - legacy ioctl implementation
1518  * @info: fbdev registered by the helper
1519  * @cmd: ioctl command
1520  * @arg: ioctl argument
1521  *
1522  * A helper to implement the standard fbdev ioctl. Only
1523  * FBIO_WAITFORVSYNC is implemented for now.
1524  */
drm_fb_helper_ioctl(struct fb_info * info,unsigned int cmd,unsigned long arg)1525 int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
1526 			unsigned long arg)
1527 {
1528 	struct drm_fb_helper *fb_helper = info->par;
1529 	struct drm_mode_set *mode_set;
1530 	struct drm_crtc *crtc;
1531 	int ret = 0;
1532 
1533 	mutex_lock(&fb_helper->lock);
1534 	if (!drm_fb_helper_is_bound(fb_helper)) {
1535 		ret = -EBUSY;
1536 		goto unlock;
1537 	}
1538 
1539 	switch (cmd) {
1540 	case FBIO_WAITFORVSYNC:
1541 		/*
1542 		 * Only consider the first CRTC.
1543 		 *
1544 		 * This ioctl is supposed to take the CRTC number as
1545 		 * an argument, but in fbdev times, what that number
1546 		 * was supposed to be was quite unclear, different
1547 		 * drivers were passing that argument differently
1548 		 * (some by reference, some by value), and most of the
1549 		 * userspace applications were just hardcoding 0 as an
1550 		 * argument.
1551 		 *
1552 		 * The first CRTC should be the integrated panel on
1553 		 * most drivers, so this is the best choice we can
1554 		 * make. If we're not smart enough here, one should
1555 		 * just consider switch the userspace to KMS.
1556 		 */
1557 		mode_set = &fb_helper->crtc_info[0].mode_set;
1558 		crtc = mode_set->crtc;
1559 
1560 		/*
1561 		 * Only wait for a vblank event if the CRTC is
1562 		 * enabled, otherwise just don't do anythintg,
1563 		 * not even report an error.
1564 		 */
1565 		ret = drm_crtc_vblank_get(crtc);
1566 		if (!ret) {
1567 			drm_crtc_wait_one_vblank(crtc);
1568 			drm_crtc_vblank_put(crtc);
1569 		}
1570 
1571 		ret = 0;
1572 		goto unlock;
1573 	default:
1574 		ret = -ENOTTY;
1575 	}
1576 
1577 unlock:
1578 	mutex_unlock(&fb_helper->lock);
1579 	return ret;
1580 }
1581 EXPORT_SYMBOL(drm_fb_helper_ioctl);
1582 
drm_fb_pixel_format_equal(const struct fb_var_screeninfo * var_1,const struct fb_var_screeninfo * var_2)1583 static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1,
1584 				      const struct fb_var_screeninfo *var_2)
1585 {
1586 	return var_1->bits_per_pixel == var_2->bits_per_pixel &&
1587 	       var_1->grayscale == var_2->grayscale &&
1588 	       var_1->red.offset == var_2->red.offset &&
1589 	       var_1->red.length == var_2->red.length &&
1590 	       var_1->red.msb_right == var_2->red.msb_right &&
1591 	       var_1->green.offset == var_2->green.offset &&
1592 	       var_1->green.length == var_2->green.length &&
1593 	       var_1->green.msb_right == var_2->green.msb_right &&
1594 	       var_1->blue.offset == var_2->blue.offset &&
1595 	       var_1->blue.length == var_2->blue.length &&
1596 	       var_1->blue.msb_right == var_2->blue.msb_right &&
1597 	       var_1->transp.offset == var_2->transp.offset &&
1598 	       var_1->transp.length == var_2->transp.length &&
1599 	       var_1->transp.msb_right == var_2->transp.msb_right;
1600 }
1601 
1602 /**
1603  * drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var
1604  * @var: screeninfo to check
1605  * @info: fbdev registered by the helper
1606  */
drm_fb_helper_check_var(struct fb_var_screeninfo * var,struct fb_info * info)1607 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
1608 			    struct fb_info *info)
1609 {
1610 	struct drm_fb_helper *fb_helper = info->par;
1611 	struct drm_framebuffer *fb = fb_helper->fb;
1612 
1613 	if (var->pixclock != 0 || in_dbg_master())
1614 		return -EINVAL;
1615 
1616 	/*
1617 	 * Changes struct fb_var_screeninfo are currently not pushed back
1618 	 * to KMS, hence fail if different settings are requested.
1619 	 */
1620 	if (var->bits_per_pixel != fb->format->cpp[0] * 8 ||
1621 	    var->xres > fb->width || var->yres > fb->height ||
1622 	    var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
1623 		DRM_DEBUG("fb requested width/height/bpp can't fit in current fb "
1624 			  "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
1625 			  var->xres, var->yres, var->bits_per_pixel,
1626 			  var->xres_virtual, var->yres_virtual,
1627 			  fb->width, fb->height, fb->format->cpp[0] * 8);
1628 		return -EINVAL;
1629 	}
1630 
1631 	/*
1632 	 * drm fbdev emulation doesn't support changing the pixel format at all,
1633 	 * so reject all pixel format changing requests.
1634 	 */
1635 	if (!drm_fb_pixel_format_equal(var, &info->var)) {
1636 		DRM_DEBUG("fbdev emulation doesn't support changing the pixel format\n");
1637 		return -EINVAL;
1638 	}
1639 
1640 	return 0;
1641 }
1642 EXPORT_SYMBOL(drm_fb_helper_check_var);
1643 
1644 /**
1645  * drm_fb_helper_set_par - implementation for &fb_ops.fb_set_par
1646  * @info: fbdev registered by the helper
1647  *
1648  * This will let fbcon do the mode init and is called at initialization time by
1649  * the fbdev core when registering the driver, and later on through the hotplug
1650  * callback.
1651  */
drm_fb_helper_set_par(struct fb_info * info)1652 int drm_fb_helper_set_par(struct fb_info *info)
1653 {
1654 	struct drm_fb_helper *fb_helper = info->par;
1655 	struct fb_var_screeninfo *var = &info->var;
1656 
1657 	if (oops_in_progress)
1658 		return -EBUSY;
1659 
1660 	if (var->pixclock != 0) {
1661 		DRM_ERROR("PIXEL CLOCK SET\n");
1662 		return -EINVAL;
1663 	}
1664 
1665 	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
1666 
1667 	return 0;
1668 }
1669 EXPORT_SYMBOL(drm_fb_helper_set_par);
1670 
pan_set(struct drm_fb_helper * fb_helper,int x,int y)1671 static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
1672 {
1673 	int i;
1674 
1675 	for (i = 0; i < fb_helper->crtc_count; i++) {
1676 		struct drm_mode_set *mode_set;
1677 
1678 		mode_set = &fb_helper->crtc_info[i].mode_set;
1679 
1680 		mode_set->x = x;
1681 		mode_set->y = y;
1682 	}
1683 }
1684 
pan_display_atomic(struct fb_var_screeninfo * var,struct fb_info * info)1685 static int pan_display_atomic(struct fb_var_screeninfo *var,
1686 			      struct fb_info *info)
1687 {
1688 	struct drm_fb_helper *fb_helper = info->par;
1689 	int ret;
1690 
1691 	pan_set(fb_helper, var->xoffset, var->yoffset);
1692 
1693 	ret = restore_fbdev_mode_atomic(fb_helper, true);
1694 	if (!ret) {
1695 		info->var.xoffset = var->xoffset;
1696 		info->var.yoffset = var->yoffset;
1697 	} else
1698 		pan_set(fb_helper, info->var.xoffset, info->var.yoffset);
1699 
1700 	return ret;
1701 }
1702 
pan_display_legacy(struct fb_var_screeninfo * var,struct fb_info * info)1703 static int pan_display_legacy(struct fb_var_screeninfo *var,
1704 			      struct fb_info *info)
1705 {
1706 	struct drm_fb_helper *fb_helper = info->par;
1707 	struct drm_mode_set *modeset;
1708 	int ret = 0;
1709 	int i;
1710 
1711 	drm_modeset_lock_all(fb_helper->dev);
1712 	for (i = 0; i < fb_helper->crtc_count; i++) {
1713 		modeset = &fb_helper->crtc_info[i].mode_set;
1714 
1715 		modeset->x = var->xoffset;
1716 		modeset->y = var->yoffset;
1717 
1718 		if (modeset->num_connectors) {
1719 			ret = drm_mode_set_config_internal(modeset);
1720 			if (!ret) {
1721 				info->var.xoffset = var->xoffset;
1722 				info->var.yoffset = var->yoffset;
1723 			}
1724 		}
1725 	}
1726 	drm_modeset_unlock_all(fb_helper->dev);
1727 
1728 	return ret;
1729 }
1730 
1731 /**
1732  * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display
1733  * @var: updated screen information
1734  * @info: fbdev registered by the helper
1735  */
drm_fb_helper_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)1736 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
1737 			      struct fb_info *info)
1738 {
1739 	struct drm_fb_helper *fb_helper = info->par;
1740 	struct drm_device *dev = fb_helper->dev;
1741 	int ret;
1742 
1743 	if (oops_in_progress)
1744 		return -EBUSY;
1745 
1746 	mutex_lock(&fb_helper->lock);
1747 	if (!drm_fb_helper_is_bound(fb_helper)) {
1748 		mutex_unlock(&fb_helper->lock);
1749 		return -EBUSY;
1750 	}
1751 
1752 	if (drm_drv_uses_atomic_modeset(dev))
1753 		ret = pan_display_atomic(var, info);
1754 	else
1755 		ret = pan_display_legacy(var, info);
1756 	mutex_unlock(&fb_helper->lock);
1757 
1758 	return ret;
1759 }
1760 EXPORT_SYMBOL(drm_fb_helper_pan_display);
1761 
1762 /*
1763  * Allocates the backing storage and sets up the fbdev info structure through
1764  * the ->fb_probe callback.
1765  */
drm_fb_helper_single_fb_probe(struct drm_fb_helper * fb_helper,int preferred_bpp)1766 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
1767 					 int preferred_bpp)
1768 {
1769 	int ret = 0;
1770 	int crtc_count = 0;
1771 	int i;
1772 	struct drm_fb_helper_surface_size sizes;
1773 	int gamma_size = 0;
1774 
1775 	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
1776 	sizes.surface_depth = 24;
1777 	sizes.surface_bpp = 32;
1778 	sizes.fb_width = (u32)-1;
1779 	sizes.fb_height = (u32)-1;
1780 
1781 	/* if driver picks 8 or 16 by default use that for both depth/bpp */
1782 	if (preferred_bpp != sizes.surface_bpp)
1783 		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
1784 
1785 	/* first up get a count of crtcs now in use and new min/maxes width/heights */
1786 	drm_fb_helper_for_each_connector(fb_helper, i) {
1787 		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
1788 		struct drm_cmdline_mode *cmdline_mode;
1789 
1790 		cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
1791 
1792 		if (cmdline_mode->bpp_specified) {
1793 			switch (cmdline_mode->bpp) {
1794 			case 8:
1795 				sizes.surface_depth = sizes.surface_bpp = 8;
1796 				break;
1797 			case 15:
1798 				sizes.surface_depth = 15;
1799 				sizes.surface_bpp = 16;
1800 				break;
1801 			case 16:
1802 				sizes.surface_depth = sizes.surface_bpp = 16;
1803 				break;
1804 			case 24:
1805 				sizes.surface_depth = sizes.surface_bpp = 24;
1806 				break;
1807 			case 32:
1808 				sizes.surface_depth = 24;
1809 				sizes.surface_bpp = 32;
1810 				break;
1811 			}
1812 			break;
1813 		}
1814 	}
1815 
1816 	crtc_count = 0;
1817 	for (i = 0; i < fb_helper->crtc_count; i++) {
1818 		struct drm_display_mode *desired_mode;
1819 		struct drm_mode_set *mode_set;
1820 		int x, y, j;
1821 		/* in case of tile group, are we the last tile vert or horiz?
1822 		 * If no tile group you are always the last one both vertically
1823 		 * and horizontally
1824 		 */
1825 		bool lastv = true, lasth = true;
1826 
1827 		desired_mode = fb_helper->crtc_info[i].desired_mode;
1828 		mode_set = &fb_helper->crtc_info[i].mode_set;
1829 
1830 		if (!desired_mode)
1831 			continue;
1832 
1833 		crtc_count++;
1834 
1835 		x = fb_helper->crtc_info[i].x;
1836 		y = fb_helper->crtc_info[i].y;
1837 
1838 		if (gamma_size == 0)
1839 			gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
1840 
1841 		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
1842 		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
1843 
1844 		for (j = 0; j < mode_set->num_connectors; j++) {
1845 			struct drm_connector *connector = mode_set->connectors[j];
1846 
1847 			if (connector->has_tile) {
1848 				lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
1849 				lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
1850 				/* cloning to multiple tiles is just crazy-talk, so: */
1851 				break;
1852 			}
1853 		}
1854 
1855 		if (lasth)
1856 			sizes.fb_width  = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
1857 		if (lastv)
1858 			sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
1859 	}
1860 
1861 	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1862 		DRM_INFO("Cannot find any crtc or sizes\n");
1863 
1864 		/* First time: disable all crtc's.. */
1865 		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
1866 			restore_fbdev_mode(fb_helper);
1867 		return -EAGAIN;
1868 	}
1869 
1870 	/* Handle our overallocation */
1871 	sizes.surface_height *= drm_fbdev_overalloc;
1872 	sizes.surface_height /= 100;
1873 
1874 	/* push down into drivers */
1875 	ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
1876 	if (ret < 0)
1877 		return ret;
1878 
1879 	strcpy(fb_helper->fb->comm, "[fbcon]");
1880 	return 0;
1881 }
1882 
1883 /**
1884  * drm_fb_helper_fill_fix - initializes fixed fbdev information
1885  * @info: fbdev registered by the helper
1886  * @pitch: desired pitch
1887  * @depth: desired depth
1888  *
1889  * Helper to fill in the fixed fbdev information useful for a non-accelerated
1890  * fbdev emulations. Drivers which support acceleration methods which impose
1891  * additional constraints need to set up their own limits.
1892  *
1893  * Drivers should call this (or their equivalent setup code) from their
1894  * &drm_fb_helper_funcs.fb_probe callback.
1895  */
drm_fb_helper_fill_fix(struct fb_info * info,uint32_t pitch,uint32_t depth)1896 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
1897 			    uint32_t depth)
1898 {
1899 	info->fix.type = FB_TYPE_PACKED_PIXELS;
1900 	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1901 		FB_VISUAL_TRUECOLOR;
1902 	info->fix.mmio_start = 0;
1903 	info->fix.mmio_len = 0;
1904 	info->fix.type_aux = 0;
1905 	info->fix.xpanstep = 1; /* doing it in hw */
1906 	info->fix.ypanstep = 1; /* doing it in hw */
1907 	info->fix.ywrapstep = 0;
1908 	info->fix.accel = FB_ACCEL_NONE;
1909 
1910 	info->fix.line_length = pitch;
1911 }
1912 EXPORT_SYMBOL(drm_fb_helper_fill_fix);
1913 
1914 /**
1915  * drm_fb_helper_fill_var - initalizes variable fbdev information
1916  * @info: fbdev instance to set up
1917  * @fb_helper: fb helper instance to use as template
1918  * @fb_width: desired fb width
1919  * @fb_height: desired fb height
1920  *
1921  * Sets up the variable fbdev metainformation from the given fb helper instance
1922  * and the drm framebuffer allocated in &drm_fb_helper.fb.
1923  *
1924  * Drivers should call this (or their equivalent setup code) from their
1925  * &drm_fb_helper_funcs.fb_probe callback after having allocated the fbdev
1926  * backing storage framebuffer.
1927  */
drm_fb_helper_fill_var(struct fb_info * info,struct drm_fb_helper * fb_helper,uint32_t fb_width,uint32_t fb_height)1928 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
1929 			    uint32_t fb_width, uint32_t fb_height)
1930 {
1931 	struct drm_framebuffer *fb = fb_helper->fb;
1932 
1933 	info->pseudo_palette = fb_helper->pseudo_palette;
1934 	info->var.xres_virtual = fb->width;
1935 	info->var.yres_virtual = fb->height;
1936 	info->var.bits_per_pixel = fb->format->cpp[0] * 8;
1937 	info->var.accel_flags = FB_ACCELF_TEXT;
1938 	info->var.xoffset = 0;
1939 	info->var.yoffset = 0;
1940 	info->var.activate = FB_ACTIVATE_NOW;
1941 
1942 	switch (fb->format->depth) {
1943 	case 8:
1944 		info->var.red.offset = 0;
1945 		info->var.green.offset = 0;
1946 		info->var.blue.offset = 0;
1947 		info->var.red.length = 8; /* 8bit DAC */
1948 		info->var.green.length = 8;
1949 		info->var.blue.length = 8;
1950 		info->var.transp.offset = 0;
1951 		info->var.transp.length = 0;
1952 		break;
1953 	case 15:
1954 		info->var.red.offset = 10;
1955 		info->var.green.offset = 5;
1956 		info->var.blue.offset = 0;
1957 		info->var.red.length = 5;
1958 		info->var.green.length = 5;
1959 		info->var.blue.length = 5;
1960 		info->var.transp.offset = 15;
1961 		info->var.transp.length = 1;
1962 		break;
1963 	case 16:
1964 		info->var.red.offset = 11;
1965 		info->var.green.offset = 5;
1966 		info->var.blue.offset = 0;
1967 		info->var.red.length = 5;
1968 		info->var.green.length = 6;
1969 		info->var.blue.length = 5;
1970 		info->var.transp.offset = 0;
1971 		break;
1972 	case 24:
1973 		info->var.red.offset = 16;
1974 		info->var.green.offset = 8;
1975 		info->var.blue.offset = 0;
1976 		info->var.red.length = 8;
1977 		info->var.green.length = 8;
1978 		info->var.blue.length = 8;
1979 		info->var.transp.offset = 0;
1980 		info->var.transp.length = 0;
1981 		break;
1982 	case 32:
1983 		info->var.red.offset = 16;
1984 		info->var.green.offset = 8;
1985 		info->var.blue.offset = 0;
1986 		info->var.red.length = 8;
1987 		info->var.green.length = 8;
1988 		info->var.blue.length = 8;
1989 		info->var.transp.offset = 24;
1990 		info->var.transp.length = 8;
1991 		break;
1992 	default:
1993 		break;
1994 	}
1995 
1996 	info->var.xres = fb_width;
1997 	info->var.yres = fb_height;
1998 }
1999 EXPORT_SYMBOL(drm_fb_helper_fill_var);
2000 
drm_fb_helper_probe_connector_modes(struct drm_fb_helper * fb_helper,uint32_t maxX,uint32_t maxY)2001 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
2002 						uint32_t maxX,
2003 						uint32_t maxY)
2004 {
2005 	struct drm_connector *connector;
2006 	int i, count = 0;
2007 
2008 	drm_fb_helper_for_each_connector(fb_helper, i) {
2009 		connector = fb_helper->connector_info[i]->connector;
2010 		count += connector->funcs->fill_modes(connector, maxX, maxY);
2011 	}
2012 
2013 	return count;
2014 }
2015 
drm_has_preferred_mode(struct drm_fb_helper_connector * fb_connector,int width,int height)2016 struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
2017 {
2018 	struct drm_display_mode *mode;
2019 
2020 	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
2021 		if (mode->hdisplay > width ||
2022 		    mode->vdisplay > height)
2023 			continue;
2024 		if (mode->type & DRM_MODE_TYPE_PREFERRED)
2025 			return mode;
2026 	}
2027 	return NULL;
2028 }
2029 EXPORT_SYMBOL(drm_has_preferred_mode);
2030 
drm_has_cmdline_mode(struct drm_fb_helper_connector * fb_connector)2031 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
2032 {
2033 	return fb_connector->connector->cmdline_mode.specified;
2034 }
2035 
drm_pick_cmdline_mode(struct drm_fb_helper_connector * fb_helper_conn)2036 struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn)
2037 {
2038 	struct drm_cmdline_mode *cmdline_mode;
2039 	struct drm_display_mode *mode;
2040 	bool prefer_non_interlace;
2041 
2042 	cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
2043 	if (cmdline_mode->specified == false)
2044 		return NULL;
2045 
2046 	/* attempt to find a matching mode in the list of modes
2047 	 *  we have gotten so far, if not add a CVT mode that conforms
2048 	 */
2049 	if (cmdline_mode->rb || cmdline_mode->margins)
2050 		goto create_mode;
2051 
2052 	prefer_non_interlace = !cmdline_mode->interlace;
2053 again:
2054 	list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
2055 		/* check width/height */
2056 		if (mode->hdisplay != cmdline_mode->xres ||
2057 		    mode->vdisplay != cmdline_mode->yres)
2058 			continue;
2059 
2060 		if (cmdline_mode->refresh_specified) {
2061 			if (mode->vrefresh != cmdline_mode->refresh)
2062 				continue;
2063 		}
2064 
2065 		if (cmdline_mode->interlace) {
2066 			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
2067 				continue;
2068 		} else if (prefer_non_interlace) {
2069 			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
2070 				continue;
2071 		}
2072 		return mode;
2073 	}
2074 
2075 	if (prefer_non_interlace) {
2076 		prefer_non_interlace = false;
2077 		goto again;
2078 	}
2079 
2080 create_mode:
2081 	mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
2082 						 cmdline_mode);
2083 	list_add(&mode->head, &fb_helper_conn->connector->modes);
2084 	return mode;
2085 }
2086 EXPORT_SYMBOL(drm_pick_cmdline_mode);
2087 
drm_connector_enabled(struct drm_connector * connector,bool strict)2088 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
2089 {
2090 	bool enable;
2091 
2092 	if (connector->display_info.non_desktop)
2093 		return false;
2094 
2095 	if (strict)
2096 		enable = connector->status == connector_status_connected;
2097 	else
2098 		enable = connector->status != connector_status_disconnected;
2099 
2100 	return enable;
2101 }
2102 
drm_enable_connectors(struct drm_fb_helper * fb_helper,bool * enabled)2103 static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
2104 				  bool *enabled)
2105 {
2106 	bool any_enabled = false;
2107 	struct drm_connector *connector;
2108 	int i = 0;
2109 
2110 	drm_fb_helper_for_each_connector(fb_helper, i) {
2111 		connector = fb_helper->connector_info[i]->connector;
2112 		enabled[i] = drm_connector_enabled(connector, true);
2113 		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
2114 			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
2115 
2116 		any_enabled |= enabled[i];
2117 	}
2118 
2119 	if (any_enabled)
2120 		return;
2121 
2122 	drm_fb_helper_for_each_connector(fb_helper, i) {
2123 		connector = fb_helper->connector_info[i]->connector;
2124 		enabled[i] = drm_connector_enabled(connector, false);
2125 	}
2126 }
2127 
drm_target_cloned(struct drm_fb_helper * fb_helper,struct drm_display_mode ** modes,struct drm_fb_offset * offsets,bool * enabled,int width,int height)2128 static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
2129 			      struct drm_display_mode **modes,
2130 			      struct drm_fb_offset *offsets,
2131 			      bool *enabled, int width, int height)
2132 {
2133 	int count, i, j;
2134 	bool can_clone = false;
2135 	struct drm_fb_helper_connector *fb_helper_conn;
2136 	struct drm_display_mode *dmt_mode, *mode;
2137 
2138 	/* only contemplate cloning in the single crtc case */
2139 	if (fb_helper->crtc_count > 1)
2140 		return false;
2141 
2142 	count = 0;
2143 	drm_fb_helper_for_each_connector(fb_helper, i) {
2144 		if (enabled[i])
2145 			count++;
2146 	}
2147 
2148 	/* only contemplate cloning if more than one connector is enabled */
2149 	if (count <= 1)
2150 		return false;
2151 
2152 	/* check the command line or if nothing common pick 1024x768 */
2153 	can_clone = true;
2154 	drm_fb_helper_for_each_connector(fb_helper, i) {
2155 		if (!enabled[i])
2156 			continue;
2157 		fb_helper_conn = fb_helper->connector_info[i];
2158 		modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
2159 		if (!modes[i]) {
2160 			can_clone = false;
2161 			break;
2162 		}
2163 		for (j = 0; j < i; j++) {
2164 			if (!enabled[j])
2165 				continue;
2166 			if (!drm_mode_match(modes[j], modes[i],
2167 					    DRM_MODE_MATCH_TIMINGS |
2168 					    DRM_MODE_MATCH_CLOCK |
2169 					    DRM_MODE_MATCH_FLAGS |
2170 					    DRM_MODE_MATCH_3D_FLAGS))
2171 				can_clone = false;
2172 		}
2173 	}
2174 
2175 	if (can_clone) {
2176 		DRM_DEBUG_KMS("can clone using command line\n");
2177 		return true;
2178 	}
2179 
2180 	/* try and find a 1024x768 mode on each connector */
2181 	can_clone = true;
2182 	dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
2183 
2184 	drm_fb_helper_for_each_connector(fb_helper, i) {
2185 		if (!enabled[i])
2186 			continue;
2187 
2188 		fb_helper_conn = fb_helper->connector_info[i];
2189 		list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
2190 			if (drm_mode_match(mode, dmt_mode,
2191 					   DRM_MODE_MATCH_TIMINGS |
2192 					   DRM_MODE_MATCH_CLOCK |
2193 					   DRM_MODE_MATCH_FLAGS |
2194 					   DRM_MODE_MATCH_3D_FLAGS))
2195 				modes[i] = mode;
2196 		}
2197 		if (!modes[i])
2198 			can_clone = false;
2199 	}
2200 
2201 	if (can_clone) {
2202 		DRM_DEBUG_KMS("can clone using 1024x768\n");
2203 		return true;
2204 	}
2205 	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
2206 	return false;
2207 }
2208 
drm_get_tile_offsets(struct drm_fb_helper * fb_helper,struct drm_display_mode ** modes,struct drm_fb_offset * offsets,int idx,int h_idx,int v_idx)2209 static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
2210 				struct drm_display_mode **modes,
2211 				struct drm_fb_offset *offsets,
2212 				int idx,
2213 				int h_idx, int v_idx)
2214 {
2215 	struct drm_fb_helper_connector *fb_helper_conn;
2216 	int i;
2217 	int hoffset = 0, voffset = 0;
2218 
2219 	drm_fb_helper_for_each_connector(fb_helper, i) {
2220 		fb_helper_conn = fb_helper->connector_info[i];
2221 		if (!fb_helper_conn->connector->has_tile)
2222 			continue;
2223 
2224 		if (!modes[i] && (h_idx || v_idx)) {
2225 			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
2226 				      fb_helper_conn->connector->base.id);
2227 			continue;
2228 		}
2229 		if (fb_helper_conn->connector->tile_h_loc < h_idx)
2230 			hoffset += modes[i]->hdisplay;
2231 
2232 		if (fb_helper_conn->connector->tile_v_loc < v_idx)
2233 			voffset += modes[i]->vdisplay;
2234 	}
2235 	offsets[idx].x = hoffset;
2236 	offsets[idx].y = voffset;
2237 	DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
2238 	return 0;
2239 }
2240 
drm_target_preferred(struct drm_fb_helper * fb_helper,struct drm_display_mode ** modes,struct drm_fb_offset * offsets,bool * enabled,int width,int height)2241 static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
2242 				 struct drm_display_mode **modes,
2243 				 struct drm_fb_offset *offsets,
2244 				 bool *enabled, int width, int height)
2245 {
2246 	struct drm_fb_helper_connector *fb_helper_conn;
2247 	const u64 mask = BIT_ULL(fb_helper->connector_count) - 1;
2248 	u64 conn_configured = 0;
2249 	int tile_pass = 0;
2250 	int i;
2251 
2252 retry:
2253 	drm_fb_helper_for_each_connector(fb_helper, i) {
2254 		fb_helper_conn = fb_helper->connector_info[i];
2255 
2256 		if (conn_configured & BIT_ULL(i))
2257 			continue;
2258 
2259 		if (enabled[i] == false) {
2260 			conn_configured |= BIT_ULL(i);
2261 			continue;
2262 		}
2263 
2264 		/* first pass over all the untiled connectors */
2265 		if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
2266 			continue;
2267 
2268 		if (tile_pass == 1) {
2269 			if (fb_helper_conn->connector->tile_h_loc != 0 ||
2270 			    fb_helper_conn->connector->tile_v_loc != 0)
2271 				continue;
2272 
2273 		} else {
2274 			if (fb_helper_conn->connector->tile_h_loc != tile_pass - 1 &&
2275 			    fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
2276 			/* if this tile_pass doesn't cover any of the tiles - keep going */
2277 				continue;
2278 
2279 			/*
2280 			 * find the tile offsets for this pass - need to find
2281 			 * all tiles left and above
2282 			 */
2283 			drm_get_tile_offsets(fb_helper, modes, offsets,
2284 					     i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
2285 		}
2286 		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
2287 			      fb_helper_conn->connector->base.id);
2288 
2289 		/* got for command line mode first */
2290 		modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
2291 		if (!modes[i]) {
2292 			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
2293 				      fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
2294 			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
2295 		}
2296 		/* No preferred modes, pick one off the list */
2297 		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
2298 			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
2299 				break;
2300 		}
2301 		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
2302 			  "none");
2303 		conn_configured |= BIT_ULL(i);
2304 	}
2305 
2306 	if ((conn_configured & mask) != mask) {
2307 		tile_pass++;
2308 		goto retry;
2309 	}
2310 	return true;
2311 }
2312 
connector_has_possible_crtc(struct drm_connector * connector,struct drm_crtc * crtc)2313 static bool connector_has_possible_crtc(struct drm_connector *connector,
2314 					struct drm_crtc *crtc)
2315 {
2316 	struct drm_encoder *encoder;
2317 	int i;
2318 
2319 	drm_connector_for_each_possible_encoder(connector, encoder, i) {
2320 		if (encoder->possible_crtcs & drm_crtc_mask(crtc))
2321 			return true;
2322 	}
2323 
2324 	return false;
2325 }
2326 
drm_pick_crtcs(struct drm_fb_helper * fb_helper,struct drm_fb_helper_crtc ** best_crtcs,struct drm_display_mode ** modes,int n,int width,int height)2327 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
2328 			  struct drm_fb_helper_crtc **best_crtcs,
2329 			  struct drm_display_mode **modes,
2330 			  int n, int width, int height)
2331 {
2332 	int c, o;
2333 	struct drm_connector *connector;
2334 	int my_score, best_score, score;
2335 	struct drm_fb_helper_crtc **crtcs, *crtc;
2336 	struct drm_fb_helper_connector *fb_helper_conn;
2337 
2338 	if (n == fb_helper->connector_count)
2339 		return 0;
2340 
2341 	fb_helper_conn = fb_helper->connector_info[n];
2342 	connector = fb_helper_conn->connector;
2343 
2344 	best_crtcs[n] = NULL;
2345 	best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
2346 	if (modes[n] == NULL)
2347 		return best_score;
2348 
2349 	crtcs = kcalloc(fb_helper->connector_count,
2350 			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
2351 	if (!crtcs)
2352 		return best_score;
2353 
2354 	my_score = 1;
2355 	if (connector->status == connector_status_connected)
2356 		my_score++;
2357 	if (drm_has_cmdline_mode(fb_helper_conn))
2358 		my_score++;
2359 	if (drm_has_preferred_mode(fb_helper_conn, width, height))
2360 		my_score++;
2361 
2362 	/*
2363 	 * select a crtc for this connector and then attempt to configure
2364 	 * remaining connectors
2365 	 */
2366 	for (c = 0; c < fb_helper->crtc_count; c++) {
2367 		crtc = &fb_helper->crtc_info[c];
2368 
2369 		if (!connector_has_possible_crtc(connector,
2370 						 crtc->mode_set.crtc))
2371 			continue;
2372 
2373 		for (o = 0; o < n; o++)
2374 			if (best_crtcs[o] == crtc)
2375 				break;
2376 
2377 		if (o < n) {
2378 			/* ignore cloning unless only a single crtc */
2379 			if (fb_helper->crtc_count > 1)
2380 				continue;
2381 
2382 			if (!drm_mode_equal(modes[o], modes[n]))
2383 				continue;
2384 		}
2385 
2386 		crtcs[n] = crtc;
2387 		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
2388 		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
2389 						  width, height);
2390 		if (score > best_score) {
2391 			best_score = score;
2392 			memcpy(best_crtcs, crtcs,
2393 			       fb_helper->connector_count *
2394 			       sizeof(struct drm_fb_helper_crtc *));
2395 		}
2396 	}
2397 
2398 	kfree(crtcs);
2399 	return best_score;
2400 }
2401 
2402 /*
2403  * This function checks if rotation is necessary because of panel orientation
2404  * and if it is, if it is supported.
2405  * If rotation is necessary and supported, its gets set in fb_crtc.rotation.
2406  * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
2407  * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
2408  * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
2409  * the unsupported rotation.
2410  */
drm_setup_crtc_rotation(struct drm_fb_helper * fb_helper,struct drm_fb_helper_crtc * fb_crtc,struct drm_connector * connector)2411 static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
2412 				    struct drm_fb_helper_crtc *fb_crtc,
2413 				    struct drm_connector *connector)
2414 {
2415 	struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
2416 	uint64_t valid_mask = 0;
2417 	int i, rotation;
2418 
2419 	fb_crtc->rotation = DRM_MODE_ROTATE_0;
2420 
2421 	switch (connector->display_info.panel_orientation) {
2422 	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
2423 		rotation = DRM_MODE_ROTATE_180;
2424 		break;
2425 	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
2426 		rotation = DRM_MODE_ROTATE_90;
2427 		break;
2428 	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
2429 		rotation = DRM_MODE_ROTATE_270;
2430 		break;
2431 	default:
2432 		rotation = DRM_MODE_ROTATE_0;
2433 	}
2434 
2435 	/*
2436 	 * TODO: support 90 / 270 degree hardware rotation,
2437 	 * depending on the hardware this may require the framebuffer
2438 	 * to be in a specific tiling format.
2439 	 */
2440 	if (rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) {
2441 		fb_helper->sw_rotations |= rotation;
2442 		return;
2443 	}
2444 
2445 	for (i = 0; i < plane->rotation_property->num_values; i++)
2446 		valid_mask |= (1ULL << plane->rotation_property->values[i]);
2447 
2448 	if (!(rotation & valid_mask)) {
2449 		fb_helper->sw_rotations |= rotation;
2450 		return;
2451 	}
2452 
2453 	fb_crtc->rotation = rotation;
2454 	/* Rotating in hardware, fbcon should not rotate */
2455 	fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
2456 }
2457 
drm_setup_crtcs(struct drm_fb_helper * fb_helper,u32 width,u32 height)2458 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
2459 			    u32 width, u32 height)
2460 {
2461 	struct drm_device *dev = fb_helper->dev;
2462 	struct drm_fb_helper_crtc **crtcs;
2463 	struct drm_display_mode **modes;
2464 	struct drm_fb_offset *offsets;
2465 	bool *enabled;
2466 	int i;
2467 
2468 	DRM_DEBUG_KMS("\n");
2469 	/* prevent concurrent modification of connector_count by hotplug */
2470 	lockdep_assert_held(&fb_helper->lock);
2471 
2472 	crtcs = kcalloc(fb_helper->connector_count,
2473 			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
2474 	modes = kcalloc(fb_helper->connector_count,
2475 			sizeof(struct drm_display_mode *), GFP_KERNEL);
2476 	offsets = kcalloc(fb_helper->connector_count,
2477 			  sizeof(struct drm_fb_offset), GFP_KERNEL);
2478 	enabled = kcalloc(fb_helper->connector_count,
2479 			  sizeof(bool), GFP_KERNEL);
2480 	if (!crtcs || !modes || !enabled || !offsets) {
2481 		DRM_ERROR("Memory allocation failed\n");
2482 		goto out;
2483 	}
2484 
2485 	mutex_lock(&fb_helper->dev->mode_config.mutex);
2486 	if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
2487 		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
2488 	drm_enable_connectors(fb_helper, enabled);
2489 
2490 	if (!(fb_helper->funcs->initial_config &&
2491 	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
2492 					       offsets,
2493 					       enabled, width, height))) {
2494 		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
2495 		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
2496 		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
2497 
2498 		if (!drm_target_cloned(fb_helper, modes, offsets,
2499 				       enabled, width, height) &&
2500 		    !drm_target_preferred(fb_helper, modes, offsets,
2501 					  enabled, width, height))
2502 			DRM_ERROR("Unable to find initial modes\n");
2503 
2504 		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
2505 			      width, height);
2506 
2507 		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
2508 	}
2509 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
2510 
2511 	/* need to set the modesets up here for use later */
2512 	/* fill out the connector<->crtc mappings into the modesets */
2513 	for (i = 0; i < fb_helper->crtc_count; i++)
2514 		drm_fb_helper_modeset_release(fb_helper,
2515 					      &fb_helper->crtc_info[i].mode_set);
2516 
2517 	fb_helper->sw_rotations = 0;
2518 	drm_fb_helper_for_each_connector(fb_helper, i) {
2519 		struct drm_display_mode *mode = modes[i];
2520 		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
2521 		struct drm_fb_offset *offset = &offsets[i];
2522 
2523 		if (mode && fb_crtc) {
2524 			struct drm_mode_set *modeset = &fb_crtc->mode_set;
2525 			struct drm_connector *connector =
2526 				fb_helper->connector_info[i]->connector;
2527 
2528 			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
2529 				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
2530 
2531 			fb_crtc->desired_mode = mode;
2532 			fb_crtc->x = offset->x;
2533 			fb_crtc->y = offset->y;
2534 			modeset->mode = drm_mode_duplicate(dev,
2535 							   fb_crtc->desired_mode);
2536 			drm_connector_get(connector);
2537 			drm_setup_crtc_rotation(fb_helper, fb_crtc, connector);
2538 			modeset->connectors[modeset->num_connectors++] = connector;
2539 			modeset->x = offset->x;
2540 			modeset->y = offset->y;
2541 		}
2542 	}
2543 out:
2544 	kfree(crtcs);
2545 	kfree(modes);
2546 	kfree(offsets);
2547 	kfree(enabled);
2548 }
2549 
2550 /*
2551  * This is a continuation of drm_setup_crtcs() that sets up anything related
2552  * to the framebuffer. During initialization, drm_setup_crtcs() is called before
2553  * the framebuffer has been allocated (fb_helper->fb and fb_helper->fbdev).
2554  * So, any setup that touches those fields needs to be done here instead of in
2555  * drm_setup_crtcs().
2556  */
drm_setup_crtcs_fb(struct drm_fb_helper * fb_helper)2557 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
2558 {
2559 	struct fb_info *info = fb_helper->fbdev;
2560 	int i;
2561 
2562 	for (i = 0; i < fb_helper->crtc_count; i++)
2563 		if (fb_helper->crtc_info[i].mode_set.num_connectors)
2564 			fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
2565 
2566 	mutex_lock(&fb_helper->dev->mode_config.mutex);
2567 	drm_fb_helper_for_each_connector(fb_helper, i) {
2568 		struct drm_connector *connector =
2569 					fb_helper->connector_info[i]->connector;
2570 
2571 		/* use first connected connector for the physical dimensions */
2572 		if (connector->status == connector_status_connected) {
2573 			info->var.width = connector->display_info.width_mm;
2574 			info->var.height = connector->display_info.height_mm;
2575 			break;
2576 		}
2577 	}
2578 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
2579 
2580 	switch (fb_helper->sw_rotations) {
2581 	case DRM_MODE_ROTATE_0:
2582 		info->fbcon_rotate_hint = FB_ROTATE_UR;
2583 		break;
2584 	case DRM_MODE_ROTATE_90:
2585 		info->fbcon_rotate_hint = FB_ROTATE_CCW;
2586 		break;
2587 	case DRM_MODE_ROTATE_180:
2588 		info->fbcon_rotate_hint = FB_ROTATE_UD;
2589 		break;
2590 	case DRM_MODE_ROTATE_270:
2591 		info->fbcon_rotate_hint = FB_ROTATE_CW;
2592 		break;
2593 	default:
2594 		/*
2595 		 * Multiple bits are set / multiple rotations requested
2596 		 * fbcon cannot handle separate rotation settings per
2597 		 * output, so fallback to unrotated.
2598 		 */
2599 		info->fbcon_rotate_hint = FB_ROTATE_UR;
2600 	}
2601 }
2602 
2603 /* Note: Drops fb_helper->lock before returning. */
2604 static int
__drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper * fb_helper,int bpp_sel)2605 __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
2606 					  int bpp_sel)
2607 {
2608 	struct drm_device *dev = fb_helper->dev;
2609 	struct fb_info *info;
2610 	unsigned int width, height;
2611 	int ret;
2612 
2613 	width = dev->mode_config.max_width;
2614 	height = dev->mode_config.max_height;
2615 
2616 	drm_setup_crtcs(fb_helper, width, height);
2617 	ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
2618 	if (ret < 0) {
2619 		if (ret == -EAGAIN) {
2620 			fb_helper->preferred_bpp = bpp_sel;
2621 			fb_helper->deferred_setup = true;
2622 			ret = 0;
2623 		}
2624 		mutex_unlock(&fb_helper->lock);
2625 
2626 		return ret;
2627 	}
2628 	drm_setup_crtcs_fb(fb_helper);
2629 
2630 	fb_helper->deferred_setup = false;
2631 
2632 	info = fb_helper->fbdev;
2633 	info->var.pixclock = 0;
2634 
2635 	/* Need to drop locks to avoid recursive deadlock in
2636 	 * register_framebuffer. This is ok because the only thing left to do is
2637 	 * register the fbdev emulation instance in kernel_fb_helper_list. */
2638 	mutex_unlock(&fb_helper->lock);
2639 
2640 	ret = register_framebuffer(info);
2641 	if (ret < 0)
2642 		return ret;
2643 
2644 	dev_info(dev->dev, "fb%d: %s frame buffer device\n",
2645 		 info->node, info->fix.id);
2646 
2647 	mutex_lock(&kernel_fb_helper_lock);
2648 	if (list_empty(&kernel_fb_helper_list))
2649 		register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
2650 
2651 	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
2652 	mutex_unlock(&kernel_fb_helper_lock);
2653 
2654 	return 0;
2655 }
2656 
2657 /**
2658  * drm_fb_helper_initial_config - setup a sane initial connector configuration
2659  * @fb_helper: fb_helper device struct
2660  * @bpp_sel: bpp value to use for the framebuffer configuration
2661  *
2662  * Scans the CRTCs and connectors and tries to put together an initial setup.
2663  * At the moment, this is a cloned configuration across all heads with
2664  * a new framebuffer object as the backing store.
2665  *
2666  * Note that this also registers the fbdev and so allows userspace to call into
2667  * the driver through the fbdev interfaces.
2668  *
2669  * This function will call down into the &drm_fb_helper_funcs.fb_probe callback
2670  * to let the driver allocate and initialize the fbdev info structure and the
2671  * drm framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
2672  * drm_fb_helper_fill_fix() are provided as helpers to setup simple default
2673  * values for the fbdev info structure.
2674  *
2675  * HANG DEBUGGING:
2676  *
2677  * When you have fbcon support built-in or already loaded, this function will do
2678  * a full modeset to setup the fbdev console. Due to locking misdesign in the
2679  * VT/fbdev subsystem that entire modeset sequence has to be done while holding
2680  * console_lock. Until console_unlock is called no dmesg lines will be sent out
2681  * to consoles, not even serial console. This means when your driver crashes,
2682  * you will see absolutely nothing else but a system stuck in this function,
2683  * with no further output. Any kind of printk() you place within your own driver
2684  * or in the drm core modeset code will also never show up.
2685  *
2686  * Standard debug practice is to run the fbcon setup without taking the
2687  * console_lock as a hack, to be able to see backtraces and crashes on the
2688  * serial line. This can be done by setting the fb.lockless_register_fb=1 kernel
2689  * cmdline option.
2690  *
2691  * The other option is to just disable fbdev emulation since very likely the
2692  * first modeset from userspace will crash in the same way, and is even easier
2693  * to debug. This can be done by setting the drm_kms_helper.fbdev_emulation=0
2694  * kernel cmdline option.
2695  *
2696  * RETURNS:
2697  * Zero if everything went ok, nonzero otherwise.
2698  */
drm_fb_helper_initial_config(struct drm_fb_helper * fb_helper,int bpp_sel)2699 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
2700 {
2701 	int ret;
2702 
2703 	if (!drm_fbdev_emulation)
2704 		return 0;
2705 
2706 	mutex_lock(&fb_helper->lock);
2707 	ret = __drm_fb_helper_initial_config_and_unlock(fb_helper, bpp_sel);
2708 
2709 	return ret;
2710 }
2711 EXPORT_SYMBOL(drm_fb_helper_initial_config);
2712 
2713 /**
2714  * drm_fb_helper_hotplug_event - respond to a hotplug notification by
2715  *                               probing all the outputs attached to the fb
2716  * @fb_helper: driver-allocated fbdev helper, can be NULL
2717  *
2718  * Scan the connectors attached to the fb_helper and try to put together a
2719  * setup after notification of a change in output configuration.
2720  *
2721  * Called at runtime, takes the mode config locks to be able to check/change the
2722  * modeset configuration. Must be run from process context (which usually means
2723  * either the output polling work or a work item launched from the driver's
2724  * hotplug interrupt).
2725  *
2726  * Note that drivers may call this even before calling
2727  * drm_fb_helper_initial_config but only after drm_fb_helper_init. This allows
2728  * for a race-free fbcon setup and will make sure that the fbdev emulation will
2729  * not miss any hotplug events.
2730  *
2731  * RETURNS:
2732  * 0 on success and a non-zero error code otherwise.
2733  */
drm_fb_helper_hotplug_event(struct drm_fb_helper * fb_helper)2734 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
2735 {
2736 	int err = 0;
2737 
2738 	if (!drm_fbdev_emulation || !fb_helper)
2739 		return 0;
2740 
2741 	mutex_lock(&fb_helper->lock);
2742 	if (fb_helper->deferred_setup) {
2743 		err = __drm_fb_helper_initial_config_and_unlock(fb_helper,
2744 				fb_helper->preferred_bpp);
2745 		return err;
2746 	}
2747 
2748 	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
2749 		fb_helper->delayed_hotplug = true;
2750 		mutex_unlock(&fb_helper->lock);
2751 		return err;
2752 	}
2753 
2754 	DRM_DEBUG_KMS("\n");
2755 
2756 	drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height);
2757 	drm_setup_crtcs_fb(fb_helper);
2758 	mutex_unlock(&fb_helper->lock);
2759 
2760 	drm_fb_helper_set_par(fb_helper->fbdev);
2761 
2762 	return 0;
2763 }
2764 EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
2765 
2766 /**
2767  * drm_fb_helper_fbdev_setup() - Setup fbdev emulation
2768  * @dev: DRM device
2769  * @fb_helper: fbdev helper structure to set up
2770  * @funcs: fbdev helper functions
2771  * @preferred_bpp: Preferred bits per pixel for the device.
2772  *                 @dev->mode_config.preferred_depth is used if this is zero.
2773  * @max_conn_count: Maximum number of connectors.
2774  *                  @dev->mode_config.num_connector is used if this is zero.
2775  *
2776  * This function sets up fbdev emulation and registers fbdev for access by
2777  * userspace. If all connectors are disconnected, setup is deferred to the next
2778  * time drm_fb_helper_hotplug_event() is called.
2779  * The caller must to provide a &drm_fb_helper_funcs->fb_probe callback
2780  * function.
2781  *
2782  * See also: drm_fb_helper_initial_config()
2783  *
2784  * Returns:
2785  * Zero on success or negative error code on failure.
2786  */
drm_fb_helper_fbdev_setup(struct drm_device * dev,struct drm_fb_helper * fb_helper,const struct drm_fb_helper_funcs * funcs,unsigned int preferred_bpp,unsigned int max_conn_count)2787 int drm_fb_helper_fbdev_setup(struct drm_device *dev,
2788 			      struct drm_fb_helper *fb_helper,
2789 			      const struct drm_fb_helper_funcs *funcs,
2790 			      unsigned int preferred_bpp,
2791 			      unsigned int max_conn_count)
2792 {
2793 	int ret;
2794 
2795 	if (!preferred_bpp)
2796 		preferred_bpp = dev->mode_config.preferred_depth;
2797 	if (!preferred_bpp)
2798 		preferred_bpp = 32;
2799 
2800 	if (!max_conn_count)
2801 		max_conn_count = dev->mode_config.num_connector;
2802 	if (!max_conn_count) {
2803 		DRM_DEV_ERROR(dev->dev, "No connectors\n");
2804 		return -EINVAL;
2805 	}
2806 
2807 	drm_fb_helper_prepare(dev, fb_helper, funcs);
2808 
2809 	ret = drm_fb_helper_init(dev, fb_helper, max_conn_count);
2810 	if (ret < 0) {
2811 		DRM_DEV_ERROR(dev->dev, "Failed to initialize fbdev helper\n");
2812 		return ret;
2813 	}
2814 
2815 	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
2816 	if (ret < 0) {
2817 		DRM_DEV_ERROR(dev->dev, "Failed to add connectors\n");
2818 		goto err_drm_fb_helper_fini;
2819 	}
2820 
2821 	if (!drm_drv_uses_atomic_modeset(dev))
2822 		drm_helper_disable_unused_functions(dev);
2823 
2824 	ret = drm_fb_helper_initial_config(fb_helper, preferred_bpp);
2825 	if (ret < 0) {
2826 		DRM_DEV_ERROR(dev->dev, "Failed to set fbdev configuration\n");
2827 		goto err_drm_fb_helper_fini;
2828 	}
2829 
2830 	return 0;
2831 
2832 err_drm_fb_helper_fini:
2833 	drm_fb_helper_fini(fb_helper);
2834 
2835 	return ret;
2836 }
2837 EXPORT_SYMBOL(drm_fb_helper_fbdev_setup);
2838 
2839 /**
2840  * drm_fb_helper_fbdev_teardown - Tear down fbdev emulation
2841  * @dev: DRM device
2842  *
2843  * This function unregisters fbdev if not already done and cleans up the
2844  * associated resources including the &drm_framebuffer.
2845  * The driver is responsible for freeing the &drm_fb_helper structure which is
2846  * stored in &drm_device->fb_helper. Do note that this pointer has been cleared
2847  * when this function returns.
2848  *
2849  * In order to support device removal/unplug while file handles are still open,
2850  * drm_fb_helper_unregister_fbi() should be called on device removal and
2851  * drm_fb_helper_fbdev_teardown() in the &drm_driver->release callback when
2852  * file handles are closed.
2853  */
drm_fb_helper_fbdev_teardown(struct drm_device * dev)2854 void drm_fb_helper_fbdev_teardown(struct drm_device *dev)
2855 {
2856 	struct drm_fb_helper *fb_helper = dev->fb_helper;
2857 	struct fb_ops *fbops = NULL;
2858 
2859 	if (!fb_helper)
2860 		return;
2861 
2862 	/* Unregister if it hasn't been done already */
2863 	if (fb_helper->fbdev && fb_helper->fbdev->dev)
2864 		drm_fb_helper_unregister_fbi(fb_helper);
2865 
2866 	if (fb_helper->fbdev && fb_helper->fbdev->fbdefio) {
2867 		fb_deferred_io_cleanup(fb_helper->fbdev);
2868 		kfree(fb_helper->fbdev->fbdefio);
2869 		fbops = fb_helper->fbdev->fbops;
2870 	}
2871 
2872 	drm_fb_helper_fini(fb_helper);
2873 	kfree(fbops);
2874 
2875 	if (fb_helper->fb)
2876 		drm_framebuffer_remove(fb_helper->fb);
2877 }
2878 EXPORT_SYMBOL(drm_fb_helper_fbdev_teardown);
2879 
2880 /**
2881  * drm_fb_helper_lastclose - DRM driver lastclose helper for fbdev emulation
2882  * @dev: DRM device
2883  *
2884  * This function can be used as the &drm_driver->lastclose callback for drivers
2885  * that only need to call drm_fb_helper_restore_fbdev_mode_unlocked().
2886  */
drm_fb_helper_lastclose(struct drm_device * dev)2887 void drm_fb_helper_lastclose(struct drm_device *dev)
2888 {
2889 	drm_fb_helper_restore_fbdev_mode_unlocked(dev->fb_helper);
2890 }
2891 EXPORT_SYMBOL(drm_fb_helper_lastclose);
2892 
2893 /**
2894  * drm_fb_helper_output_poll_changed - DRM mode config \.output_poll_changed
2895  *                                     helper for fbdev emulation
2896  * @dev: DRM device
2897  *
2898  * This function can be used as the
2899  * &drm_mode_config_funcs.output_poll_changed callback for drivers that only
2900  * need to call drm_fb_helper_hotplug_event().
2901  */
drm_fb_helper_output_poll_changed(struct drm_device * dev)2902 void drm_fb_helper_output_poll_changed(struct drm_device *dev)
2903 {
2904 	drm_fb_helper_hotplug_event(dev->fb_helper);
2905 }
2906 EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
2907 
2908 /* @user: 1=userspace, 0=fbcon */
drm_fbdev_fb_open(struct fb_info * info,int user)2909 static int drm_fbdev_fb_open(struct fb_info *info, int user)
2910 {
2911 	struct drm_fb_helper *fb_helper = info->par;
2912 
2913 	if (!try_module_get(fb_helper->dev->driver->fops->owner))
2914 		return -ENODEV;
2915 
2916 	return 0;
2917 }
2918 
drm_fbdev_fb_release(struct fb_info * info,int user)2919 static int drm_fbdev_fb_release(struct fb_info *info, int user)
2920 {
2921 	struct drm_fb_helper *fb_helper = info->par;
2922 
2923 	module_put(fb_helper->dev->driver->fops->owner);
2924 
2925 	return 0;
2926 }
2927 
2928 /*
2929  * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
2930  * unregister_framebuffer() or fb_release().
2931  */
drm_fbdev_fb_destroy(struct fb_info * info)2932 static void drm_fbdev_fb_destroy(struct fb_info *info)
2933 {
2934 	struct drm_fb_helper *fb_helper = info->par;
2935 	struct fb_info *fbi = fb_helper->fbdev;
2936 	struct fb_ops *fbops = NULL;
2937 	void *shadow = NULL;
2938 
2939 	if (fbi->fbdefio) {
2940 		fb_deferred_io_cleanup(fbi);
2941 		shadow = fbi->screen_buffer;
2942 		fbops = fbi->fbops;
2943 	}
2944 
2945 	drm_fb_helper_fini(fb_helper);
2946 
2947 	if (shadow) {
2948 		vfree(shadow);
2949 		kfree(fbops);
2950 	}
2951 
2952 	drm_client_framebuffer_delete(fb_helper->buffer);
2953 	/*
2954 	 * FIXME:
2955 	 * Remove conditional when all CMA drivers have been moved over to using
2956 	 * drm_fbdev_generic_setup().
2957 	 */
2958 	if (fb_helper->client.funcs) {
2959 		drm_client_release(&fb_helper->client);
2960 		kfree(fb_helper);
2961 	}
2962 }
2963 
drm_fbdev_fb_mmap(struct fb_info * info,struct vm_area_struct * vma)2964 static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
2965 {
2966 	struct drm_fb_helper *fb_helper = info->par;
2967 
2968 	if (fb_helper->dev->driver->gem_prime_mmap)
2969 		return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
2970 	else
2971 		return -ENODEV;
2972 }
2973 
2974 static struct fb_ops drm_fbdev_fb_ops = {
2975 	.owner		= THIS_MODULE,
2976 	DRM_FB_HELPER_DEFAULT_OPS,
2977 	.fb_open	= drm_fbdev_fb_open,
2978 	.fb_release	= drm_fbdev_fb_release,
2979 	.fb_destroy	= drm_fbdev_fb_destroy,
2980 	.fb_mmap	= drm_fbdev_fb_mmap,
2981 	.fb_read	= drm_fb_helper_sys_read,
2982 	.fb_write	= drm_fb_helper_sys_write,
2983 	.fb_fillrect	= drm_fb_helper_sys_fillrect,
2984 	.fb_copyarea	= drm_fb_helper_sys_copyarea,
2985 	.fb_imageblit	= drm_fb_helper_sys_imageblit,
2986 };
2987 
2988 static struct fb_deferred_io drm_fbdev_defio = {
2989 	.delay		= HZ / 20,
2990 	.deferred_io	= drm_fb_helper_deferred_io,
2991 };
2992 
2993 /**
2994  * drm_fb_helper_generic_probe - Generic fbdev emulation probe helper
2995  * @fb_helper: fbdev helper structure
2996  * @sizes: describes fbdev size and scanout surface size
2997  *
2998  * This function uses the client API to crate a framebuffer backed by a dumb buffer.
2999  *
3000  * The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect,
3001  * fb_copyarea, fb_imageblit.
3002  *
3003  * Returns:
3004  * Zero on success or negative error code on failure.
3005  */
drm_fb_helper_generic_probe(struct drm_fb_helper * fb_helper,struct drm_fb_helper_surface_size * sizes)3006 int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
3007 				struct drm_fb_helper_surface_size *sizes)
3008 {
3009 	struct drm_client_dev *client = &fb_helper->client;
3010 	struct drm_client_buffer *buffer;
3011 	struct drm_framebuffer *fb;
3012 	struct fb_info *fbi;
3013 	u32 format;
3014 	int ret;
3015 
3016 	DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
3017 		      sizes->surface_width, sizes->surface_height,
3018 		      sizes->surface_bpp);
3019 
3020 	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
3021 	buffer = drm_client_framebuffer_create(client, sizes->surface_width,
3022 					       sizes->surface_height, format);
3023 	if (IS_ERR(buffer))
3024 		return PTR_ERR(buffer);
3025 
3026 	fb_helper->buffer = buffer;
3027 	fb_helper->fb = buffer->fb;
3028 	fb = buffer->fb;
3029 
3030 	fbi = drm_fb_helper_alloc_fbi(fb_helper);
3031 	if (IS_ERR(fbi)) {
3032 		ret = PTR_ERR(fbi);
3033 		goto err_free_buffer;
3034 	}
3035 
3036 	fbi->par = fb_helper;
3037 	fbi->fbops = &drm_fbdev_fb_ops;
3038 	fbi->screen_size = fb->height * fb->pitches[0];
3039 	fbi->fix.smem_len = fbi->screen_size;
3040 	fbi->screen_buffer = buffer->vaddr;
3041 	strcpy(fbi->fix.id, "DRM emulated");
3042 
3043 	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
3044 	drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height);
3045 
3046 	if (fb->funcs->dirty) {
3047 		struct fb_ops *fbops;
3048 		void *shadow;
3049 
3050 		/*
3051 		 * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per
3052 		 * instance version is necessary.
3053 		 */
3054 		fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
3055 		shadow = vzalloc(fbi->screen_size);
3056 		if (!fbops || !shadow) {
3057 			kfree(fbops);
3058 			vfree(shadow);
3059 			ret = -ENOMEM;
3060 			goto err_fb_info_destroy;
3061 		}
3062 
3063 		*fbops = *fbi->fbops;
3064 		fbi->fbops = fbops;
3065 		fbi->screen_buffer = shadow;
3066 		fbi->fbdefio = &drm_fbdev_defio;
3067 
3068 		fb_deferred_io_init(fbi);
3069 	}
3070 
3071 	return 0;
3072 
3073 err_fb_info_destroy:
3074 	drm_fb_helper_fini(fb_helper);
3075 err_free_buffer:
3076 	drm_client_framebuffer_delete(buffer);
3077 
3078 	return ret;
3079 }
3080 EXPORT_SYMBOL(drm_fb_helper_generic_probe);
3081 
3082 static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
3083 	.fb_probe = drm_fb_helper_generic_probe,
3084 };
3085 
drm_fbdev_client_unregister(struct drm_client_dev * client)3086 static void drm_fbdev_client_unregister(struct drm_client_dev *client)
3087 {
3088 	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
3089 
3090 	if (fb_helper->fbdev) {
3091 		drm_fb_helper_unregister_fbi(fb_helper);
3092 		/* drm_fbdev_fb_destroy() takes care of cleanup */
3093 		return;
3094 	}
3095 
3096 	/* Did drm_fb_helper_fbdev_setup() run? */
3097 	if (fb_helper->dev)
3098 		drm_fb_helper_fini(fb_helper);
3099 
3100 	drm_client_release(client);
3101 	kfree(fb_helper);
3102 }
3103 
drm_fbdev_client_restore(struct drm_client_dev * client)3104 static int drm_fbdev_client_restore(struct drm_client_dev *client)
3105 {
3106 	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
3107 
3108 	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
3109 
3110 	return 0;
3111 }
3112 
drm_fbdev_client_hotplug(struct drm_client_dev * client)3113 static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
3114 {
3115 	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
3116 	struct drm_device *dev = client->dev;
3117 	int ret;
3118 
3119 	/* If drm_fb_helper_fbdev_setup() failed, we only try once */
3120 	if (!fb_helper->dev && fb_helper->funcs)
3121 		return 0;
3122 
3123 	if (dev->fb_helper)
3124 		return drm_fb_helper_hotplug_event(dev->fb_helper);
3125 
3126 	if (!dev->mode_config.num_connector)
3127 		return 0;
3128 
3129 	ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_helper_generic_funcs,
3130 					fb_helper->preferred_bpp, 0);
3131 	if (ret) {
3132 		fb_helper->dev = NULL;
3133 		fb_helper->fbdev = NULL;
3134 		return ret;
3135 	}
3136 
3137 	return 0;
3138 }
3139 
3140 static const struct drm_client_funcs drm_fbdev_client_funcs = {
3141 	.owner		= THIS_MODULE,
3142 	.unregister	= drm_fbdev_client_unregister,
3143 	.restore	= drm_fbdev_client_restore,
3144 	.hotplug	= drm_fbdev_client_hotplug,
3145 };
3146 
3147 /**
3148  * drm_fb_helper_generic_fbdev_setup() - Setup generic fbdev emulation
3149  * @dev: DRM device
3150  * @preferred_bpp: Preferred bits per pixel for the device.
3151  *                 @dev->mode_config.preferred_depth is used if this is zero.
3152  *
3153  * This function sets up generic fbdev emulation for drivers that supports
3154  * dumb buffers with a virtual address and that can be mmap'ed.
3155  *
3156  * Restore, hotplug events and teardown are all taken care of. Drivers that do
3157  * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
3158  * Simple drivers might use drm_mode_config_helper_suspend().
3159  *
3160  * Drivers that set the dirty callback on their framebuffer will get a shadow
3161  * fbdev buffer that is blitted onto the real buffer. This is done in order to
3162  * make deferred I/O work with all kinds of buffers.
3163  *
3164  * This function is safe to call even when there are no connectors present.
3165  * Setup will be retried on the next hotplug event.
3166  *
3167  * Returns:
3168  * Zero on success or negative error code on failure.
3169  */
drm_fbdev_generic_setup(struct drm_device * dev,unsigned int preferred_bpp)3170 int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
3171 {
3172 	struct drm_fb_helper *fb_helper;
3173 	int ret;
3174 
3175 	if (!drm_fbdev_emulation)
3176 		return 0;
3177 
3178 	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
3179 	if (!fb_helper)
3180 		return -ENOMEM;
3181 
3182 	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
3183 	if (ret) {
3184 		kfree(fb_helper);
3185 		return ret;
3186 	}
3187 
3188 	drm_client_add(&fb_helper->client);
3189 
3190 	fb_helper->preferred_bpp = preferred_bpp;
3191 
3192 	drm_fbdev_client_hotplug(&fb_helper->client);
3193 
3194 	return 0;
3195 }
3196 EXPORT_SYMBOL(drm_fbdev_generic_setup);
3197 
3198 /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
3199  * but the module doesn't depend on any fb console symbols.  At least
3200  * attempt to load fbcon to avoid leaving the system without a usable console.
3201  */
drm_fb_helper_modinit(void)3202 int __init drm_fb_helper_modinit(void)
3203 {
3204 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
3205 	const char name[] = "fbcon";
3206 	struct module *fbcon;
3207 
3208 	mutex_lock(&module_mutex);
3209 	fbcon = find_module(name);
3210 	mutex_unlock(&module_mutex);
3211 
3212 	if (!fbcon)
3213 		request_module_nowait(name);
3214 #endif
3215 	return 0;
3216 }
3217 EXPORT_SYMBOL(drm_fb_helper_modinit);
3218