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_crtc_helper.h>
26 #include <drm/drm_fb_cma_helper.h>
27 #include <drm/drm_gem_cma_helper.h>
29 #include "rcar_du_crtc.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 rcar_du_r8a7779_info
= {
43 /* R8A7779 has two RGB outputs and one (currently unsupported)
46 [RCAR_DU_OUTPUT_DPAD0
] = {
47 .possible_crtcs
= BIT(0),
48 .encoder_type
= DRM_MODE_ENCODER_NONE
,
51 [RCAR_DU_OUTPUT_DPAD1
] = {
52 .possible_crtcs
= BIT(1) | BIT(0),
53 .encoder_type
= DRM_MODE_ENCODER_NONE
,
60 static const struct rcar_du_device_info rcar_du_r8a7790_info
= {
62 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
63 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
64 .quirks
= RCAR_DU_QUIRK_ALIGN_128B
| RCAR_DU_QUIRK_LVDS_LANES
,
67 /* R8A7790 has one RGB output, two LVDS outputs and one
68 * (currently unsupported) TCON output.
70 [RCAR_DU_OUTPUT_DPAD0
] = {
71 .possible_crtcs
= BIT(2) | BIT(1) | BIT(0),
72 .encoder_type
= DRM_MODE_ENCODER_NONE
,
75 [RCAR_DU_OUTPUT_LVDS0
] = {
76 .possible_crtcs
= BIT(0),
77 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
80 [RCAR_DU_OUTPUT_LVDS1
] = {
81 .possible_crtcs
= BIT(2) | BIT(1),
82 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
89 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
90 static const struct rcar_du_device_info rcar_du_r8a7791_info
= {
92 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
93 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
96 /* R8A779[13] has one RGB output, one LVDS output and one
97 * (currently unsupported) TCON output.
99 [RCAR_DU_OUTPUT_DPAD0
] = {
100 .possible_crtcs
= BIT(1) | BIT(0),
101 .encoder_type
= DRM_MODE_ENCODER_NONE
,
104 [RCAR_DU_OUTPUT_LVDS0
] = {
105 .possible_crtcs
= BIT(0),
106 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
113 static const struct rcar_du_device_info rcar_du_r8a7792_info
= {
115 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
116 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
119 /* R8A7792 has two RGB outputs. */
120 [RCAR_DU_OUTPUT_DPAD0
] = {
121 .possible_crtcs
= BIT(0),
122 .encoder_type
= DRM_MODE_ENCODER_NONE
,
125 [RCAR_DU_OUTPUT_DPAD1
] = {
126 .possible_crtcs
= BIT(1),
127 .encoder_type
= DRM_MODE_ENCODER_NONE
,
134 static const struct rcar_du_device_info rcar_du_r8a7794_info
= {
136 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
137 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
140 /* R8A7794 has two RGB outputs and one (currently unsupported)
143 [RCAR_DU_OUTPUT_DPAD0
] = {
144 .possible_crtcs
= BIT(0),
145 .encoder_type
= DRM_MODE_ENCODER_NONE
,
148 [RCAR_DU_OUTPUT_DPAD1
] = {
149 .possible_crtcs
= BIT(1),
150 .encoder_type
= DRM_MODE_ENCODER_NONE
,
157 static const struct rcar_du_device_info rcar_du_r8a7795_info
= {
159 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
160 | RCAR_DU_FEATURE_EXT_CTRL_REGS
161 | RCAR_DU_FEATURE_VSP1_SOURCE
,
164 /* R8A7795 has one RGB output, one LVDS output and two
165 * (currently unsupported) HDMI outputs.
167 [RCAR_DU_OUTPUT_DPAD0
] = {
168 .possible_crtcs
= BIT(3),
169 .encoder_type
= DRM_MODE_ENCODER_NONE
,
172 [RCAR_DU_OUTPUT_LVDS0
] = {
173 .possible_crtcs
= BIT(0),
174 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
181 static const struct rcar_du_device_info rcar_du_r8a7796_info
= {
183 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
184 | RCAR_DU_FEATURE_EXT_CTRL_REGS
185 | RCAR_DU_FEATURE_VSP1_SOURCE
,
188 /* R8A7796 has one RGB output, one LVDS output and one
189 * (currently unsupported) HDMI output.
191 [RCAR_DU_OUTPUT_DPAD0
] = {
192 .possible_crtcs
= BIT(2),
193 .encoder_type
= DRM_MODE_ENCODER_NONE
,
196 [RCAR_DU_OUTPUT_LVDS0
] = {
197 .possible_crtcs
= BIT(0),
198 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
205 static const struct of_device_id rcar_du_of_table
[] = {
206 { .compatible
= "renesas,du-r8a7779", .data
= &rcar_du_r8a7779_info
},
207 { .compatible
= "renesas,du-r8a7790", .data
= &rcar_du_r8a7790_info
},
208 { .compatible
= "renesas,du-r8a7791", .data
= &rcar_du_r8a7791_info
},
209 { .compatible
= "renesas,du-r8a7792", .data
= &rcar_du_r8a7792_info
},
210 { .compatible
= "renesas,du-r8a7793", .data
= &rcar_du_r8a7791_info
},
211 { .compatible
= "renesas,du-r8a7794", .data
= &rcar_du_r8a7794_info
},
212 { .compatible
= "renesas,du-r8a7795", .data
= &rcar_du_r8a7795_info
},
213 { .compatible
= "renesas,du-r8a7796", .data
= &rcar_du_r8a7796_info
},
217 MODULE_DEVICE_TABLE(of
, rcar_du_of_table
);
219 /* -----------------------------------------------------------------------------
223 static void rcar_du_lastclose(struct drm_device
*dev
)
225 struct rcar_du_device
*rcdu
= dev
->dev_private
;
227 drm_fbdev_cma_restore_mode(rcdu
->fbdev
);
230 static int rcar_du_enable_vblank(struct drm_device
*dev
, unsigned int pipe
)
232 struct rcar_du_device
*rcdu
= dev
->dev_private
;
234 rcar_du_crtc_enable_vblank(&rcdu
->crtcs
[pipe
], true);
239 static void rcar_du_disable_vblank(struct drm_device
*dev
, unsigned int pipe
)
241 struct rcar_du_device
*rcdu
= dev
->dev_private
;
243 rcar_du_crtc_enable_vblank(&rcdu
->crtcs
[pipe
], false);
246 static const struct file_operations rcar_du_fops
= {
247 .owner
= THIS_MODULE
,
249 .release
= drm_release
,
250 .unlocked_ioctl
= drm_ioctl
,
251 .compat_ioctl
= drm_compat_ioctl
,
255 .mmap
= drm_gem_cma_mmap
,
258 static struct drm_driver rcar_du_driver
= {
259 .driver_features
= DRIVER_GEM
| DRIVER_MODESET
| DRIVER_PRIME
261 .lastclose
= rcar_du_lastclose
,
262 .get_vblank_counter
= drm_vblank_no_hw_counter
,
263 .enable_vblank
= rcar_du_enable_vblank
,
264 .disable_vblank
= rcar_du_disable_vblank
,
265 .gem_free_object_unlocked
= drm_gem_cma_free_object
,
266 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
267 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
268 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
269 .gem_prime_import
= drm_gem_prime_import
,
270 .gem_prime_export
= drm_gem_prime_export
,
271 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
272 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
273 .gem_prime_vmap
= drm_gem_cma_prime_vmap
,
274 .gem_prime_vunmap
= drm_gem_cma_prime_vunmap
,
275 .gem_prime_mmap
= drm_gem_cma_prime_mmap
,
276 .dumb_create
= rcar_du_dumb_create
,
277 .dumb_map_offset
= drm_gem_cma_dumb_map_offset
,
278 .dumb_destroy
= drm_gem_dumb_destroy
,
279 .fops
= &rcar_du_fops
,
281 .desc
= "Renesas R-Car Display Unit",
287 /* -----------------------------------------------------------------------------
291 #ifdef CONFIG_PM_SLEEP
292 static int rcar_du_pm_suspend(struct device
*dev
)
294 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
296 drm_kms_helper_poll_disable(rcdu
->ddev
);
297 /* TODO Suspend the CRTC */
302 static int rcar_du_pm_resume(struct device
*dev
)
304 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
306 /* TODO Resume the CRTC */
308 drm_kms_helper_poll_enable(rcdu
->ddev
);
313 static const struct dev_pm_ops rcar_du_pm_ops
= {
314 SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend
, rcar_du_pm_resume
)
317 /* -----------------------------------------------------------------------------
321 static int rcar_du_remove(struct platform_device
*pdev
)
323 struct rcar_du_device
*rcdu
= platform_get_drvdata(pdev
);
324 struct drm_device
*ddev
= rcdu
->ddev
;
326 drm_dev_unregister(ddev
);
329 drm_fbdev_cma_fini(rcdu
->fbdev
);
331 drm_kms_helper_poll_fini(ddev
);
332 drm_mode_config_cleanup(ddev
);
339 static int rcar_du_probe(struct platform_device
*pdev
)
341 struct rcar_du_device
*rcdu
;
342 struct drm_device
*ddev
;
343 struct resource
*mem
;
346 /* Allocate and initialize the R-Car device structure. */
347 rcdu
= devm_kzalloc(&pdev
->dev
, sizeof(*rcdu
), GFP_KERNEL
);
351 init_waitqueue_head(&rcdu
->commit
.wait
);
353 rcdu
->dev
= &pdev
->dev
;
354 rcdu
->info
= of_match_device(rcar_du_of_table
, rcdu
->dev
)->data
;
356 platform_set_drvdata(pdev
, rcdu
);
359 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
360 rcdu
->mmio
= devm_ioremap_resource(&pdev
->dev
, mem
);
361 if (IS_ERR(rcdu
->mmio
))
362 return PTR_ERR(rcdu
->mmio
);
364 /* DRM/KMS objects */
365 ddev
= drm_dev_alloc(&rcar_du_driver
, &pdev
->dev
);
367 return PTR_ERR(ddev
);
370 ddev
->dev_private
= rcdu
;
372 ret
= rcar_du_modeset_init(rcdu
);
374 if (ret
!= -EPROBE_DEFER
)
376 "failed to initialize DRM/KMS (%d)\n", ret
);
380 ddev
->irq_enabled
= 1;
382 /* Register the DRM device with the core and the connectors with
385 ret
= drm_dev_register(ddev
, 0);
389 DRM_INFO("Device %s probed\n", dev_name(&pdev
->dev
));
394 rcar_du_remove(pdev
);
399 static struct platform_driver rcar_du_platform_driver
= {
400 .probe
= rcar_du_probe
,
401 .remove
= rcar_du_remove
,
404 .pm
= &rcar_du_pm_ops
,
405 .of_match_table
= rcar_du_of_table
,
409 module_platform_driver(rcar_du_platform_driver
);
411 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
412 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
413 MODULE_LICENSE("GPL");