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