drm/fb_cma_helper: Add drm_fb_cma_prepare_fb() helper
[linux-block.git] / drivers / gpu / drm / imx / imx-drm-core.c
CommitLineData
e692da4d
SH
1/*
2 * Freescale i.MX drm driver
3 *
4 * Copyright (C) 2011 Sascha Hauer, Pengutronix
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
17b5001b 16#include <linux/component.h>
e692da4d 17#include <linux/device.h>
5f2f9115 18#include <linux/dma-buf.h>
e7d6231e 19#include <linux/module.h>
e692da4d 20#include <linux/platform_device.h>
5f2f9115 21#include <linux/reservation.h>
e692da4d 22#include <drm/drmP.h>
5f2f9115
LY
23#include <drm/drm_atomic.h>
24#include <drm/drm_atomic_helper.h>
e692da4d
SH
25#include <drm/drm_fb_helper.h>
26#include <drm/drm_crtc_helper.h>
e692da4d
SH
27#include <drm/drm_gem_cma_helper.h>
28#include <drm/drm_fb_cma_helper.h>
3cb9ae4f 29#include <drm/drm_plane_helper.h>
6457b971 30#include <drm/drm_of.h>
310944d1 31#include <video/imx-ipu-v3.h>
e692da4d
SH
32
33#include "imx-drm.h"
34
35#define MAX_CRTC 4
36
655b43cc
PZ
37struct imx_drm_component {
38 struct device_node *of_node;
39 struct list_head list;
40};
41
e692da4d
SH
42struct imx_drm_device {
43 struct drm_device *drm;
887eceac 44 struct imx_drm_crtc *crtc[MAX_CRTC];
d2ab8ad9 45 unsigned int pipes;
e692da4d 46 struct drm_fbdev_cma *fbhelper;
5f2f9115 47 struct drm_atomic_state *state;
e692da4d
SH
48};
49
50struct imx_drm_crtc {
51 struct drm_crtc *crtc;
e692da4d 52 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
e692da4d
SH
53};
54
c1ff5a7a 55#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
8acba02f
RK
56static int legacyfb_depth = 16;
57module_param(legacyfb_depth, int, 0444);
c1ff5a7a 58#endif
8acba02f 59
e692da4d
SH
60static void imx_drm_driver_lastclose(struct drm_device *drm)
61{
62 struct imx_drm_device *imxdrm = drm->dev_private;
63
3f3a7280 64 drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
e692da4d
SH
65}
66
88e72717 67static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
e692da4d
SH
68{
69 struct imx_drm_device *imxdrm = drm->dev_private;
88e72717 70 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
e692da4d
SH
71 int ret;
72
e692da4d
SH
73 if (!imx_drm_crtc)
74 return -EINVAL;
75
76 if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
77 return -ENOSYS;
78
79 ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
80 imx_drm_crtc->crtc);
81
82 return ret;
83}
84
88e72717 85static void imx_drm_disable_vblank(struct drm_device *drm, unsigned int pipe)
e692da4d
SH
86{
87 struct imx_drm_device *imxdrm = drm->dev_private;
88e72717 88 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
e692da4d 89
e692da4d
SH
90 if (!imx_drm_crtc)
91 return;
92
93 if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
94 return;
95
96 imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
97}
98
99static const struct file_operations imx_drm_driver_fops = {
100 .owner = THIS_MODULE,
101 .open = drm_open,
102 .release = drm_release,
103 .unlocked_ioctl = drm_ioctl,
104 .mmap = drm_gem_cma_mmap,
105 .poll = drm_poll,
e692da4d
SH
106 .read = drm_read,
107 .llseek = noop_llseek,
108};
109
8a51a33b
RK
110void imx_drm_connector_destroy(struct drm_connector *connector)
111{
34ea3d38 112 drm_connector_unregister(connector);
8a51a33b
RK
113 drm_connector_cleanup(connector);
114}
115EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
116
117void imx_drm_encoder_destroy(struct drm_encoder *encoder)
118{
119 drm_encoder_cleanup(encoder);
120}
121EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
122
3e68439b
RK
123static void imx_drm_output_poll_changed(struct drm_device *drm)
124{
3e68439b
RK
125 struct imx_drm_device *imxdrm = drm->dev_private;
126
127 drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
3e68439b
RK
128}
129
1780999c
LY
130static int imx_drm_atomic_check(struct drm_device *dev,
131 struct drm_atomic_state *state)
132{
133 int ret;
134
135 ret = drm_atomic_helper_check_modeset(dev, state);
136 if (ret)
137 return ret;
138
139 ret = drm_atomic_helper_check_planes(dev, state);
140 if (ret)
141 return ret;
142
143 /*
144 * Check modeset again in case crtc_state->mode_changed is
145 * updated in plane's ->atomic_check callback.
146 */
147 ret = drm_atomic_helper_check_modeset(dev, state);
148 if (ret)
149 return ret;
150
151 return ret;
152}
153
a40e65b7
LS
154static int imx_drm_atomic_commit(struct drm_device *dev,
155 struct drm_atomic_state *state,
156 bool nonblock)
157{
158 struct drm_plane_state *plane_state;
159 struct drm_plane *plane;
160 struct dma_buf *dma_buf;
aee25864 161 struct dma_fence *fence;
a40e65b7
LS
162 int i;
163
164 /*
165 * If the plane fb has an dma-buf attached, fish out the exclusive
166 * fence for the atomic helper to wait on.
167 */
168 for_each_plane_in_state(state, plane, plane_state, i) {
169 if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
170 dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
171 0)->base.dma_buf;
172 if (!dma_buf)
173 continue;
aee25864
GP
174 fence = reservation_object_get_excl_rcu(dma_buf->resv);
175
176 drm_atomic_set_fence_for_plane(plane_state, fence);
a40e65b7
LS
177 }
178 }
179
180 return drm_atomic_helper_commit(dev, state, nonblock);
181}
182
7ae847dd 183static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
1df8b530 184 .fb_create = drm_fb_cma_create,
3e68439b 185 .output_poll_changed = imx_drm_output_poll_changed,
1780999c 186 .atomic_check = imx_drm_atomic_check,
a40e65b7 187 .atomic_commit = imx_drm_atomic_commit,
5f2f9115
LY
188};
189
190static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
191{
192 struct drm_device *dev = state->dev;
5f2f9115
LY
193
194 drm_atomic_helper_commit_modeset_disables(dev, state);
195
2b58e98d 196 drm_atomic_helper_commit_planes(dev, state,
5f4df0c7
LY
197 DRM_PLANE_COMMIT_ACTIVE_ONLY |
198 DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
5f2f9115
LY
199
200 drm_atomic_helper_commit_modeset_enables(dev, state);
201
202 drm_atomic_helper_commit_hw_done(state);
203
204 drm_atomic_helper_wait_for_vblanks(dev, state);
205
206 drm_atomic_helper_cleanup_planes(dev, state);
207}
208
209static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
210 .atomic_commit_tail = imx_drm_atomic_commit_tail,
1df8b530
RK
211};
212
e692da4d
SH
213/*
214 * imx_drm_add_crtc - add a new crtc
e692da4d 215 */
32266b45 216int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
43895599 217 struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
e692da4d 218 const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
655b43cc 219 struct device_node *port)
e692da4d 220{
32266b45 221 struct imx_drm_device *imxdrm = drm->dev_private;
e692da4d 222 struct imx_drm_crtc *imx_drm_crtc;
e692da4d 223
fd6040ed
RK
224 /*
225 * The vblank arrays are dimensioned by MAX_CRTC - we can't
226 * pass IDs greater than this to those functions.
227 */
e7d6231e
RK
228 if (imxdrm->pipes >= MAX_CRTC)
229 return -EINVAL;
fd6040ed 230
e7d6231e
RK
231 if (imxdrm->drm->open_count)
232 return -EBUSY;
e692da4d
SH
233
234 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
e7d6231e
RK
235 if (!imx_drm_crtc)
236 return -ENOMEM;
e692da4d
SH
237
238 imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
e692da4d 239 imx_drm_crtc->crtc = crtc;
e692da4d 240
6457b971
RK
241 crtc->port = port;
242
d4b20e4d 243 imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc;
e692da4d
SH
244
245 *new_crtc = imx_drm_crtc;
246
ec9557d7
RK
247 drm_crtc_helper_add(crtc,
248 imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
249
43895599 250 drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
f9882876 251 imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL);
ec9557d7 252
e692da4d 253 return 0;
e692da4d
SH
254}
255EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
256
257/*
258 * imx_drm_remove_crtc - remove a crtc
259 */
260int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
261{
ccec7f62 262 struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
d4b20e4d 263 unsigned int pipe = drm_crtc_index(imx_drm_crtc->crtc);
e692da4d
SH
264
265 drm_crtc_cleanup(imx_drm_crtc->crtc);
266
d4b20e4d 267 imxdrm->crtc[pipe] = NULL;
e692da4d 268
e692da4d
SH
269 kfree(imx_drm_crtc);
270
271 return 0;
272}
273EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
274
6457b971
RK
275int imx_drm_encoder_parse_of(struct drm_device *drm,
276 struct drm_encoder *encoder, struct device_node *np)
9e2d410d 277{
6457b971 278 uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np);
9e2d410d 279
6457b971
RK
280 /*
281 * If we failed to find the CRTC(s) which this encoder is
282 * supposed to be connected to, it's because the CRTC has
283 * not been registered yet. Defer probing, and hope that
284 * the required CRTC is added later.
285 */
286 if (crtc_mask == 0)
287 return -EPROBE_DEFER;
655b43cc 288
6457b971 289 encoder->possible_crtcs = crtc_mask;
63bc5164 290
6457b971
RK
291 /* FIXME: this is the mask of outputs which can clone this output. */
292 encoder->possible_clones = ~0;
9e2d410d
RK
293
294 return 0;
295}
6457b971 296EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
9e2d410d 297
baa70943 298static const struct drm_ioctl_desc imx_drm_ioctls[] = {
e692da4d
SH
299 /* none so far */
300};
301
302static struct drm_driver imx_drm_driver = {
8535c022
LY
303 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
304 DRIVER_ATOMIC,
e692da4d 305 .lastclose = imx_drm_driver_lastclose,
4b193663 306 .gem_free_object_unlocked = drm_gem_cma_free_object,
e692da4d
SH
307 .gem_vm_ops = &drm_gem_cma_vm_ops,
308 .dumb_create = drm_gem_cma_dumb_create,
309 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
43387b37 310 .dumb_destroy = drm_gem_dumb_destroy,
e692da4d 311
bd3665c9
PZ
312 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
313 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
314 .gem_prime_import = drm_gem_prime_import,
315 .gem_prime_export = drm_gem_prime_export,
316 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
317 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
318 .gem_prime_vmap = drm_gem_cma_prime_vmap,
319 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
320 .gem_prime_mmap = drm_gem_cma_prime_mmap,
b44f8408 321 .get_vblank_counter = drm_vblank_no_hw_counter,
e692da4d
SH
322 .enable_vblank = imx_drm_enable_vblank,
323 .disable_vblank = imx_drm_disable_vblank,
324 .ioctls = imx_drm_ioctls,
325 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
326 .fops = &imx_drm_driver_fops,
327 .name = "imx-drm",
328 .desc = "i.MX DRM graphics",
329 .date = "20120507",
330 .major = 1,
331 .minor = 0,
332 .patchlevel = 0,
333};
334
17b5001b
RK
335static int compare_of(struct device *dev, void *data)
336{
655b43cc 337 struct device_node *np = data;
17b5001b 338
310944d1
PZ
339 /* Special case for DI, dev->of_node may not be set yet */
340 if (strcmp(dev->driver->name, "imx-ipuv3-crtc") == 0) {
341 struct ipu_client_platformdata *pdata = dev->platform_data;
342
343 return pdata->of_node == np;
344 }
345
655b43cc
PZ
346 /* Special case for LDB, one device for two channels */
347 if (of_node_cmp(np->name, "lvds-channel") == 0) {
348 np = of_get_parent(np);
349 of_node_put(np);
17b5001b
RK
350 }
351
655b43cc
PZ
352 return dev->of_node == np;
353}
17b5001b 354
17b5001b
RK
355static int imx_drm_bind(struct device *dev)
356{
54db5dec
LS
357 struct drm_device *drm;
358 struct imx_drm_device *imxdrm;
359 int ret;
360
361 drm = drm_dev_alloc(&imx_drm_driver, dev);
8cca3548
DC
362 if (IS_ERR(drm))
363 return PTR_ERR(drm);
54db5dec
LS
364
365 imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
366 if (!imxdrm) {
367 ret = -ENOMEM;
368 goto err_unref;
369 }
370
371 imxdrm->drm = drm;
372 drm->dev_private = imxdrm;
373
374 /*
375 * enable drm irq mode.
376 * - with irq_enabled = true, we can use the vblank feature.
377 *
378 * P.S. note that we wouldn't use drm irq handler but
379 * just specific driver own one instead because
380 * drm framework supports only one irq handler and
381 * drivers can well take care of their interrupts
382 */
383 drm->irq_enabled = true;
384
385 /*
386 * set max width and height as default value(4096x4096).
387 * this value would be used to check framebuffer size limitation
388 * at drm_mode_addfb().
389 */
390 drm->mode_config.min_width = 64;
391 drm->mode_config.min_height = 64;
392 drm->mode_config.max_width = 4096;
393 drm->mode_config.max_height = 4096;
394 drm->mode_config.funcs = &imx_drm_mode_config_funcs;
395 drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
396
397 drm_mode_config_init(drm);
398
399 ret = drm_vblank_init(drm, MAX_CRTC);
400 if (ret)
401 goto err_kms;
402
403 dev_set_drvdata(dev, drm);
404
405 /* Now try and bind all our sub-components */
406 ret = component_bind_all(dev, drm);
407 if (ret)
408 goto err_vblank;
409
410 drm_mode_config_reset(drm);
411
412 /*
413 * All components are now initialised, so setup the fb helper.
414 * The fb helper takes copies of key hardware information, so the
415 * crtcs/connectors/encoders must not change after this point.
416 */
417#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
418 if (legacyfb_depth != 16 && legacyfb_depth != 32) {
419 dev_warn(dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
420 legacyfb_depth = 16;
421 }
422 imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
423 drm->mode_config.num_crtc, MAX_CRTC);
424 if (IS_ERR(imxdrm->fbhelper)) {
425 ret = PTR_ERR(imxdrm->fbhelper);
426 imxdrm->fbhelper = NULL;
427 goto err_unbind;
428 }
429#endif
430
431 drm_kms_helper_poll_init(drm);
432
433 ret = drm_dev_register(drm, 0);
434 if (ret)
435 goto err_fbhelper;
436
437 return 0;
438
439err_fbhelper:
440 drm_kms_helper_poll_fini(drm);
3e3affe5 441#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
54db5dec
LS
442 if (imxdrm->fbhelper)
443 drm_fbdev_cma_fini(imxdrm->fbhelper);
444err_unbind:
3e3affe5 445#endif
54db5dec
LS
446 component_unbind_all(drm->dev, drm);
447err_vblank:
448 drm_vblank_cleanup(drm);
449err_kms:
450 drm_mode_config_cleanup(drm);
451err_unref:
452 drm_dev_unref(drm);
453
454 return ret;
17b5001b
RK
455}
456
457static void imx_drm_unbind(struct device *dev)
458{
54db5dec
LS
459 struct drm_device *drm = dev_get_drvdata(dev);
460 struct imx_drm_device *imxdrm = drm->dev_private;
461
462 drm_dev_unregister(drm);
463
464 drm_kms_helper_poll_fini(drm);
465
466 if (imxdrm->fbhelper)
467 drm_fbdev_cma_fini(imxdrm->fbhelper);
468
8e3b16e2
LS
469 drm_mode_config_cleanup(drm);
470
54db5dec
LS
471 component_unbind_all(drm->dev, drm);
472 dev_set_drvdata(dev, NULL);
473
54db5dec 474 drm_dev_unref(drm);
17b5001b
RK
475}
476
477static const struct component_master_ops imx_drm_ops = {
17b5001b
RK
478 .bind = imx_drm_bind,
479 .unbind = imx_drm_unbind,
480};
481
e692da4d
SH
482static int imx_drm_platform_probe(struct platform_device *pdev)
483{
9cace32f 484 int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops);
655b43cc 485
9cace32f
LD
486 if (!ret)
487 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
655b43cc 488
9cace32f 489 return ret;
e692da4d
SH
490}
491
492static int imx_drm_platform_remove(struct platform_device *pdev)
493{
17b5001b 494 component_master_del(&pdev->dev, &imx_drm_ops);
e692da4d
SH
495 return 0;
496}
497
bfe945c8
SG
498#ifdef CONFIG_PM_SLEEP
499static int imx_drm_suspend(struct device *dev)
500{
501 struct drm_device *drm_dev = dev_get_drvdata(dev);
5f2f9115 502 struct imx_drm_device *imxdrm;
bfe945c8
SG
503
504 /* The drm_dev is NULL before .load hook is called */
505 if (drm_dev == NULL)
506 return 0;
507
508 drm_kms_helper_poll_disable(drm_dev);
509
5f2f9115
LY
510 imxdrm = drm_dev->dev_private;
511 imxdrm->state = drm_atomic_helper_suspend(drm_dev);
512 if (IS_ERR(imxdrm->state)) {
513 drm_kms_helper_poll_enable(drm_dev);
514 return PTR_ERR(imxdrm->state);
515 }
516
bfe945c8
SG
517 return 0;
518}
519
520static int imx_drm_resume(struct device *dev)
521{
522 struct drm_device *drm_dev = dev_get_drvdata(dev);
5f2f9115 523 struct imx_drm_device *imx_drm;
bfe945c8
SG
524
525 if (drm_dev == NULL)
526 return 0;
527
5f2f9115
LY
528 imx_drm = drm_dev->dev_private;
529 drm_atomic_helper_resume(drm_dev, imx_drm->state);
bfe945c8
SG
530 drm_kms_helper_poll_enable(drm_dev);
531
532 return 0;
533}
534#endif
535
536static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume);
537
17b5001b 538static const struct of_device_id imx_drm_dt_ids[] = {
655b43cc 539 { .compatible = "fsl,imx-display-subsystem", },
17b5001b
RK
540 { /* sentinel */ },
541};
542MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
543
e692da4d
SH
544static struct platform_driver imx_drm_pdrv = {
545 .probe = imx_drm_platform_probe,
99c28f10 546 .remove = imx_drm_platform_remove,
e692da4d 547 .driver = {
e692da4d 548 .name = "imx-drm",
bfe945c8 549 .pm = &imx_drm_pm_ops,
17b5001b 550 .of_match_table = imx_drm_dt_ids,
e692da4d
SH
551 },
552};
b85f2b5d 553module_platform_driver(imx_drm_pdrv);
e692da4d
SH
554
555MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
556MODULE_DESCRIPTION("i.MX drm driver core");
557MODULE_LICENSE("GPL");