2 * rcar_du_drv.c -- R-Car Display Unit DRM driver
4 * Copyright (C) 2013-2014 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
= {
42 /* R8A7779 has two RGB outputs and one (currently unsupported)
45 [RCAR_DU_OUTPUT_DPAD0
] = {
46 .possible_crtcs
= BIT(0),
47 .encoder_type
= DRM_MODE_ENCODER_NONE
,
50 [RCAR_DU_OUTPUT_DPAD1
] = {
51 .possible_crtcs
= BIT(1) | BIT(0),
52 .encoder_type
= DRM_MODE_ENCODER_NONE
,
59 static const struct rcar_du_device_info rcar_du_r8a7790_info
= {
60 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
61 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
62 .quirks
= RCAR_DU_QUIRK_ALIGN_128B
| RCAR_DU_QUIRK_LVDS_LANES
,
65 /* R8A7790 has one RGB output, two LVDS outputs and one
66 * (currently unsupported) TCON output.
68 [RCAR_DU_OUTPUT_DPAD0
] = {
69 .possible_crtcs
= BIT(2) | BIT(1) | BIT(0),
70 .encoder_type
= DRM_MODE_ENCODER_NONE
,
73 [RCAR_DU_OUTPUT_LVDS0
] = {
74 .possible_crtcs
= BIT(0),
75 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
78 [RCAR_DU_OUTPUT_LVDS1
] = {
79 .possible_crtcs
= BIT(2) | BIT(1),
80 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
87 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
88 static const struct rcar_du_device_info rcar_du_r8a7791_info
= {
89 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
90 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
93 /* R8A779[13] has one RGB output, one LVDS output and one
94 * (currently unsupported) TCON output.
96 [RCAR_DU_OUTPUT_DPAD0
] = {
97 .possible_crtcs
= BIT(1) | BIT(0),
98 .encoder_type
= DRM_MODE_ENCODER_NONE
,
101 [RCAR_DU_OUTPUT_LVDS0
] = {
102 .possible_crtcs
= BIT(0),
103 .encoder_type
= DRM_MODE_ENCODER_LVDS
,
110 static const struct rcar_du_device_info rcar_du_r8a7794_info
= {
111 .features
= RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
112 | RCAR_DU_FEATURE_EXT_CTRL_REGS
,
115 /* R8A7794 has two RGB outputs and one (currently unsupported)
118 [RCAR_DU_OUTPUT_DPAD0
] = {
119 .possible_crtcs
= BIT(0),
120 .encoder_type
= DRM_MODE_ENCODER_NONE
,
123 [RCAR_DU_OUTPUT_DPAD1
] = {
124 .possible_crtcs
= BIT(1),
125 .encoder_type
= DRM_MODE_ENCODER_NONE
,
132 static const struct of_device_id rcar_du_of_table
[] = {
133 { .compatible
= "renesas,du-r8a7779", .data
= &rcar_du_r8a7779_info
},
134 { .compatible
= "renesas,du-r8a7790", .data
= &rcar_du_r8a7790_info
},
135 { .compatible
= "renesas,du-r8a7791", .data
= &rcar_du_r8a7791_info
},
136 { .compatible
= "renesas,du-r8a7793", .data
= &rcar_du_r8a7791_info
},
137 { .compatible
= "renesas,du-r8a7794", .data
= &rcar_du_r8a7794_info
},
141 MODULE_DEVICE_TABLE(of
, rcar_du_of_table
);
143 /* -----------------------------------------------------------------------------
147 static int rcar_du_unload(struct drm_device
*dev
)
149 struct rcar_du_device
*rcdu
= dev
->dev_private
;
152 drm_fbdev_cma_fini(rcdu
->fbdev
);
154 drm_kms_helper_poll_fini(dev
);
155 drm_mode_config_cleanup(dev
);
156 drm_vblank_cleanup(dev
);
158 dev
->irq_enabled
= 0;
159 dev
->dev_private
= NULL
;
164 static int rcar_du_load(struct drm_device
*dev
, unsigned long flags
)
166 struct platform_device
*pdev
= dev
->platformdev
;
167 struct device_node
*np
= pdev
->dev
.of_node
;
168 struct rcar_du_device
*rcdu
;
169 struct resource
*mem
;
173 dev_err(dev
->dev
, "no platform data\n");
177 rcdu
= devm_kzalloc(&pdev
->dev
, sizeof(*rcdu
), GFP_KERNEL
);
179 dev_err(dev
->dev
, "failed to allocate private data\n");
183 init_waitqueue_head(&rcdu
->commit
.wait
);
185 rcdu
->dev
= &pdev
->dev
;
186 rcdu
->info
= of_match_device(rcar_du_of_table
, rcdu
->dev
)->data
;
188 dev
->dev_private
= rcdu
;
191 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
192 rcdu
->mmio
= devm_ioremap_resource(&pdev
->dev
, mem
);
193 if (IS_ERR(rcdu
->mmio
))
194 return PTR_ERR(rcdu
->mmio
);
196 /* Initialize vertical blanking interrupts handling. Start with vblank
197 * disabled for all CRTCs.
199 ret
= drm_vblank_init(dev
, (1 << rcdu
->info
->num_crtcs
) - 1);
201 dev_err(&pdev
->dev
, "failed to initialize vblank\n");
205 /* DRM/KMS objects */
206 ret
= rcar_du_modeset_init(rcdu
);
208 dev_err(&pdev
->dev
, "failed to initialize DRM/KMS (%d)\n", ret
);
212 dev
->irq_enabled
= 1;
214 platform_set_drvdata(pdev
, rcdu
);
223 static void rcar_du_preclose(struct drm_device
*dev
, struct drm_file
*file
)
225 struct rcar_du_device
*rcdu
= dev
->dev_private
;
228 for (i
= 0; i
< rcdu
->num_crtcs
; ++i
)
229 rcar_du_crtc_cancel_page_flip(&rcdu
->crtcs
[i
], file
);
232 static void rcar_du_lastclose(struct drm_device
*dev
)
234 struct rcar_du_device
*rcdu
= dev
->dev_private
;
236 drm_fbdev_cma_restore_mode(rcdu
->fbdev
);
239 static int rcar_du_enable_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
], true);
248 static void rcar_du_disable_vblank(struct drm_device
*dev
, unsigned int pipe
)
250 struct rcar_du_device
*rcdu
= dev
->dev_private
;
252 rcar_du_crtc_enable_vblank(&rcdu
->crtcs
[pipe
], false);
255 static const struct file_operations rcar_du_fops
= {
256 .owner
= THIS_MODULE
,
258 .release
= drm_release
,
259 .unlocked_ioctl
= drm_ioctl
,
261 .compat_ioctl
= drm_compat_ioctl
,
266 .mmap
= drm_gem_cma_mmap
,
269 static struct drm_driver rcar_du_driver
= {
270 .driver_features
= DRIVER_GEM
| DRIVER_MODESET
| DRIVER_PRIME
272 .load
= rcar_du_load
,
273 .unload
= rcar_du_unload
,
274 .preclose
= rcar_du_preclose
,
275 .lastclose
= rcar_du_lastclose
,
276 .set_busid
= drm_platform_set_busid
,
277 .get_vblank_counter
= drm_vblank_no_hw_counter
,
278 .enable_vblank
= rcar_du_enable_vblank
,
279 .disable_vblank
= rcar_du_disable_vblank
,
280 .gem_free_object
= drm_gem_cma_free_object
,
281 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
282 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
283 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
284 .gem_prime_import
= drm_gem_prime_import
,
285 .gem_prime_export
= drm_gem_prime_export
,
286 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
287 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
288 .gem_prime_vmap
= drm_gem_cma_prime_vmap
,
289 .gem_prime_vunmap
= drm_gem_cma_prime_vunmap
,
290 .gem_prime_mmap
= drm_gem_cma_prime_mmap
,
291 .dumb_create
= rcar_du_dumb_create
,
292 .dumb_map_offset
= drm_gem_cma_dumb_map_offset
,
293 .dumb_destroy
= drm_gem_dumb_destroy
,
294 .fops
= &rcar_du_fops
,
296 .desc
= "Renesas R-Car Display Unit",
302 /* -----------------------------------------------------------------------------
306 #ifdef CONFIG_PM_SLEEP
307 static int rcar_du_pm_suspend(struct device
*dev
)
309 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
311 drm_kms_helper_poll_disable(rcdu
->ddev
);
312 /* TODO Suspend the CRTC */
317 static int rcar_du_pm_resume(struct device
*dev
)
319 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
321 /* TODO Resume the CRTC */
323 drm_kms_helper_poll_enable(rcdu
->ddev
);
328 static const struct dev_pm_ops rcar_du_pm_ops
= {
329 SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend
, rcar_du_pm_resume
)
332 /* -----------------------------------------------------------------------------
336 static int rcar_du_probe(struct platform_device
*pdev
)
338 return drm_platform_init(&rcar_du_driver
, pdev
);
341 static int rcar_du_remove(struct platform_device
*pdev
)
343 struct rcar_du_device
*rcdu
= platform_get_drvdata(pdev
);
345 drm_put_dev(rcdu
->ddev
);
350 static struct platform_driver rcar_du_platform_driver
= {
351 .probe
= rcar_du_probe
,
352 .remove
= rcar_du_remove
,
355 .pm
= &rcar_du_pm_ops
,
356 .of_match_table
= rcar_du_of_table
,
360 module_platform_driver(rcar_du_platform_driver
);
362 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
363 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
364 MODULE_LICENSE("GPL");