2 * rcar_du_drv.c -- R-Car Display Unit DRM driver
4 * Copyright (C) 2013-2015 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
14 #include <linux/clk.h>
17 #include <linux/module.h>
18 #include <linux/of_device.h>
19 #include <linux/platform_device.h>
21 #include <linux/slab.h>
22 #include <linux/wait.h>
25 #include <drm/drm_atomic_helper.h>
26 #include <drm/drm_crtc_helper.h>
27 #include <drm/drm_fb_cma_helper.h>
28 #include <drm/drm_gem_cma_helper.h>
30 #include "rcar_du_drv.h"
31 #include "rcar_du_kms.h"
32 #include "rcar_du_regs.h"
34 /* -----------------------------------------------------------------------------
38 static const struct rcar_du_device_info rzg1_du_r8a7743_info
= {
40 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
41 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
45 * R8A7743 has one RGB output and one LVDS output
47 [RCAR_DU_OUTPUT_DPAD0
] = {
48 .possible_crtcs
= BIT(1) | BIT(0),
51 [RCAR_DU_OUTPUT_LVDS0
] = {
52 .possible_crtcs
= BIT(0),
59 static const struct rcar_du_device_info rzg1_du_r8a7745_info
= {
61 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
62 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
66 * R8A7745 has two RGB outputs
68 [RCAR_DU_OUTPUT_DPAD0
] = {
69 .possible_crtcs
= BIT(0),
72 [RCAR_DU_OUTPUT_DPAD1
] = {
73 .possible_crtcs
= BIT(1),
80 static const struct rcar_du_device_info rcar_du_r8a7779_info
= {
86 * R8A7779 has two RGB outputs and one (currently unsupported)
89 [RCAR_DU_OUTPUT_DPAD0
] = {
90 .possible_crtcs
= BIT(0),
93 [RCAR_DU_OUTPUT_DPAD1
] = {
94 .possible_crtcs
= BIT(1) | BIT(0),
101 static const struct rcar_du_device_info rcar_du_r8a7790_info
= {
103 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
104 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
105 .quirks
= RCAR_DU_QUIRK_ALIGN_128B
| RCAR_DU_QUIRK_LVDS_LANES
,
109 * R8A7790 has one RGB output, two LVDS outputs and one
110 * (currently unsupported) TCON output.
112 [RCAR_DU_OUTPUT_DPAD0
] = {
113 .possible_crtcs
= BIT(2) | BIT(1) | BIT(0),
116 [RCAR_DU_OUTPUT_LVDS0
] = {
117 .possible_crtcs
= BIT(0),
120 [RCAR_DU_OUTPUT_LVDS1
] = {
121 .possible_crtcs
= BIT(2) | BIT(1),
128 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
129 static const struct rcar_du_device_info rcar_du_r8a7791_info
= {
131 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
132 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
136 * R8A779[13] has one RGB output, one LVDS output and one
137 * (currently unsupported) TCON output.
139 [RCAR_DU_OUTPUT_DPAD0
] = {
140 .possible_crtcs
= BIT(1) | BIT(0),
143 [RCAR_DU_OUTPUT_LVDS0
] = {
144 .possible_crtcs
= BIT(0),
151 static const struct rcar_du_device_info rcar_du_r8a7792_info
= {
153 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
154 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
157 /* R8A7792 has two RGB outputs. */
158 [RCAR_DU_OUTPUT_DPAD0
] = {
159 .possible_crtcs
= BIT(0),
162 [RCAR_DU_OUTPUT_DPAD1
] = {
163 .possible_crtcs
= BIT(1),
170 static const struct rcar_du_device_info rcar_du_r8a7794_info
= {
172 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
173 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
177 * R8A7794 has two RGB outputs and one (currently unsupported)
180 [RCAR_DU_OUTPUT_DPAD0
] = {
181 .possible_crtcs
= BIT(0),
184 [RCAR_DU_OUTPUT_DPAD1
] = {
185 .possible_crtcs
= BIT(1),
192 static const struct rcar_du_device_info rcar_du_r8a7795_info
= {
194 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
195 | RCAR_DU_FEATURE_EXT_CTRL_REGS
196 | RCAR_DU_FEATURE_VSP1_SOURCE
,
200 * R8A7795 has one RGB output, two HDMI outputs and one
203 [RCAR_DU_OUTPUT_DPAD0
] = {
204 .possible_crtcs
= BIT(3),
207 [RCAR_DU_OUTPUT_HDMI0
] = {
208 .possible_crtcs
= BIT(1),
211 [RCAR_DU_OUTPUT_HDMI1
] = {
212 .possible_crtcs
= BIT(2),
215 [RCAR_DU_OUTPUT_LVDS0
] = {
216 .possible_crtcs
= BIT(0),
221 .dpll_ch
= BIT(1) | BIT(2),
224 static const struct rcar_du_device_info rcar_du_r8a7796_info
= {
226 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
227 | RCAR_DU_FEATURE_EXT_CTRL_REGS
228 | RCAR_DU_FEATURE_VSP1_SOURCE
,
232 * R8A7796 has one RGB output, one LVDS output and one HDMI
235 [RCAR_DU_OUTPUT_DPAD0
] = {
236 .possible_crtcs
= BIT(2),
239 [RCAR_DU_OUTPUT_HDMI0
] = {
240 .possible_crtcs
= BIT(1),
243 [RCAR_DU_OUTPUT_LVDS0
] = {
244 .possible_crtcs
= BIT(0),
252 static const struct of_device_id rcar_du_of_table
[] = {
253 { .compatible
= "renesas,du-r8a7743", .data
= &rzg1_du_r8a7743_info
},
254 { .compatible
= "renesas,du-r8a7745", .data
= &rzg1_du_r8a7745_info
},
255 { .compatible
= "renesas,du-r8a7779", .data
= &rcar_du_r8a7779_info
},
256 { .compatible
= "renesas,du-r8a7790", .data
= &rcar_du_r8a7790_info
},
257 { .compatible
= "renesas,du-r8a7791", .data
= &rcar_du_r8a7791_info
},
258 { .compatible
= "renesas,du-r8a7792", .data
= &rcar_du_r8a7792_info
},
259 { .compatible
= "renesas,du-r8a7793", .data
= &rcar_du_r8a7791_info
},
260 { .compatible
= "renesas,du-r8a7794", .data
= &rcar_du_r8a7794_info
},
261 { .compatible
= "renesas,du-r8a7795", .data
= &rcar_du_r8a7795_info
},
262 { .compatible
= "renesas,du-r8a7796", .data
= &rcar_du_r8a7796_info
},
266 MODULE_DEVICE_TABLE(of
, rcar_du_of_table
);
268 /* -----------------------------------------------------------------------------
272 static void rcar_du_lastclose(struct drm_device
*dev
)
274 struct rcar_du_device
*rcdu
= dev
->dev_private
;
276 drm_fbdev_cma_restore_mode(rcdu
->fbdev
);
279 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops
);
281 static struct drm_driver rcar_du_driver
= {
282 .driver_features
= DRIVER_GEM
| DRIVER_MODESET
| DRIVER_PRIME
284 .lastclose
= rcar_du_lastclose
,
285 .gem_free_object_unlocked
= drm_gem_cma_free_object
,
286 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
287 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
288 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
289 .gem_prime_import
= drm_gem_prime_import
,
290 .gem_prime_export
= drm_gem_prime_export
,
291 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
292 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
293 .gem_prime_vmap
= drm_gem_cma_prime_vmap
,
294 .gem_prime_vunmap
= drm_gem_cma_prime_vunmap
,
295 .gem_prime_mmap
= drm_gem_cma_prime_mmap
,
296 .dumb_create
= rcar_du_dumb_create
,
297 .fops
= &rcar_du_fops
,
299 .desc
= "Renesas R-Car Display Unit",
305 /* -----------------------------------------------------------------------------
309 #ifdef CONFIG_PM_SLEEP
310 static int rcar_du_pm_suspend(struct device
*dev
)
312 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
313 struct drm_atomic_state
*state
;
315 drm_kms_helper_poll_disable(rcdu
->ddev
);
316 drm_fbdev_cma_set_suspend_unlocked(rcdu
->fbdev
, true);
318 state
= drm_atomic_helper_suspend(rcdu
->ddev
);
320 drm_fbdev_cma_set_suspend_unlocked(rcdu
->fbdev
, false);
321 drm_kms_helper_poll_enable(rcdu
->ddev
);
322 return PTR_ERR(state
);
325 rcdu
->suspend_state
= state
;
330 static int rcar_du_pm_resume(struct device
*dev
)
332 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
334 drm_atomic_helper_resume(rcdu
->ddev
, rcdu
->suspend_state
);
335 drm_fbdev_cma_set_suspend_unlocked(rcdu
->fbdev
, false);
336 drm_kms_helper_poll_enable(rcdu
->ddev
);
342 static const struct dev_pm_ops rcar_du_pm_ops
= {
343 SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend
, rcar_du_pm_resume
)
346 /* -----------------------------------------------------------------------------
350 static int rcar_du_remove(struct platform_device
*pdev
)
352 struct rcar_du_device
*rcdu
= platform_get_drvdata(pdev
);
353 struct drm_device
*ddev
= rcdu
->ddev
;
355 drm_dev_unregister(ddev
);
358 drm_fbdev_cma_fini(rcdu
->fbdev
);
360 drm_kms_helper_poll_fini(ddev
);
361 drm_mode_config_cleanup(ddev
);
368 static int rcar_du_probe(struct platform_device
*pdev
)
370 struct rcar_du_device
*rcdu
;
371 struct drm_device
*ddev
;
372 struct resource
*mem
;
375 /* Allocate and initialize the R-Car device structure. */
376 rcdu
= devm_kzalloc(&pdev
->dev
, sizeof(*rcdu
), GFP_KERNEL
);
380 rcdu
->dev
= &pdev
->dev
;
381 rcdu
->info
= of_device_get_match_data(rcdu
->dev
);
383 platform_set_drvdata(pdev
, rcdu
);
386 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
387 rcdu
->mmio
= devm_ioremap_resource(&pdev
->dev
, mem
);
388 if (IS_ERR(rcdu
->mmio
))
389 return PTR_ERR(rcdu
->mmio
);
391 /* DRM/KMS objects */
392 ddev
= drm_dev_alloc(&rcar_du_driver
, &pdev
->dev
);
394 return PTR_ERR(ddev
);
397 ddev
->dev_private
= rcdu
;
399 ret
= rcar_du_modeset_init(rcdu
);
401 if (ret
!= -EPROBE_DEFER
)
403 "failed to initialize DRM/KMS (%d)\n", ret
);
407 ddev
->irq_enabled
= 1;
410 * Register the DRM device with the core and the connectors with
413 ret
= drm_dev_register(ddev
, 0);
417 DRM_INFO("Device %s probed\n", dev_name(&pdev
->dev
));
422 rcar_du_remove(pdev
);
427 static struct platform_driver rcar_du_platform_driver
= {
428 .probe
= rcar_du_probe
,
429 .remove
= rcar_du_remove
,
432 .pm
= &rcar_du_pm_ops
,
433 .of_match_table
= rcar_du_of_table
,
437 module_platform_driver(rcar_du_platform_driver
);
439 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
440 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
441 MODULE_LICENSE("GPL");