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