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_drv.h"
30 #include "rcar_du_kms.h"
31 #include "rcar_du_regs.h"
33 /* -----------------------------------------------------------------------------
37 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),
50 [RCAR_DU_OUTPUT_DPAD1] = {
51 .possible_crtcs = BIT(1) | BIT(0),
58 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,
66 * R8A7790 has one RGB output, two LVDS outputs and one
67 * (currently unsupported) TCON output.
69 [RCAR_DU_OUTPUT_DPAD0] = {
70 .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
73 [RCAR_DU_OUTPUT_LVDS0] = {
74 .possible_crtcs = BIT(0),
77 [RCAR_DU_OUTPUT_LVDS1] = {
78 .possible_crtcs = BIT(2) | BIT(1),
85 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
86 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
88 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
89 | 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),
100 [RCAR_DU_OUTPUT_LVDS0] = {
101 .possible_crtcs = BIT(0),
108 static const struct rcar_du_device_info rcar_du_r8a7792_info = {
110 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
111 | RCAR_DU_FEATURE_EXT_CTRL_REGS,
114 /* R8A7792 has two RGB outputs. */
115 [RCAR_DU_OUTPUT_DPAD0] = {
116 .possible_crtcs = BIT(0),
119 [RCAR_DU_OUTPUT_DPAD1] = {
120 .possible_crtcs = BIT(1),
127 static const struct rcar_du_device_info rcar_du_r8a7794_info = {
129 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
130 | RCAR_DU_FEATURE_EXT_CTRL_REGS,
134 * R8A7794 has two RGB outputs and one (currently unsupported)
137 [RCAR_DU_OUTPUT_DPAD0] = {
138 .possible_crtcs = BIT(0),
141 [RCAR_DU_OUTPUT_DPAD1] = {
142 .possible_crtcs = BIT(1),
149 static const struct rcar_du_device_info rcar_du_r8a7795_info = {
151 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
152 | RCAR_DU_FEATURE_EXT_CTRL_REGS
153 | RCAR_DU_FEATURE_VSP1_SOURCE,
157 * R8A7795 has one RGB output, two HDMI outputs and one
160 [RCAR_DU_OUTPUT_DPAD0] = {
161 .possible_crtcs = BIT(3),
164 [RCAR_DU_OUTPUT_HDMI0] = {
165 .possible_crtcs = BIT(1),
168 [RCAR_DU_OUTPUT_HDMI1] = {
169 .possible_crtcs = BIT(2),
172 [RCAR_DU_OUTPUT_LVDS0] = {
173 .possible_crtcs = BIT(0),
178 .dpll_ch = BIT(1) | BIT(2),
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,
189 * R8A7796 has one RGB output, one LVDS output and one HDMI
192 [RCAR_DU_OUTPUT_DPAD0] = {
193 .possible_crtcs = BIT(2),
196 [RCAR_DU_OUTPUT_HDMI0] = {
197 .possible_crtcs = BIT(1),
200 [RCAR_DU_OUTPUT_LVDS0] = {
201 .possible_crtcs = BIT(0),
209 static const struct of_device_id rcar_du_of_table[] = {
210 { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
211 { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
212 { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
213 { .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
214 { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
215 { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
216 { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
217 { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
221 MODULE_DEVICE_TABLE(of, rcar_du_of_table);
223 /* -----------------------------------------------------------------------------
227 static void rcar_du_lastclose(struct drm_device *dev)
229 struct rcar_du_device *rcdu = dev->dev_private;
231 drm_fbdev_cma_restore_mode(rcdu->fbdev);
234 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
236 static struct drm_driver rcar_du_driver = {
237 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
239 .lastclose = rcar_du_lastclose,
240 .gem_free_object_unlocked = drm_gem_cma_free_object,
241 .gem_vm_ops = &drm_gem_cma_vm_ops,
242 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
243 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
244 .gem_prime_import = drm_gem_prime_import,
245 .gem_prime_export = drm_gem_prime_export,
246 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
247 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
248 .gem_prime_vmap = drm_gem_cma_prime_vmap,
249 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
250 .gem_prime_mmap = drm_gem_cma_prime_mmap,
251 .dumb_create = rcar_du_dumb_create,
252 .fops = &rcar_du_fops,
254 .desc = "Renesas R-Car Display Unit",
260 /* -----------------------------------------------------------------------------
264 #ifdef CONFIG_PM_SLEEP
265 static int rcar_du_pm_suspend(struct device *dev)
267 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
269 drm_kms_helper_poll_disable(rcdu->ddev);
270 /* TODO Suspend the CRTC */
275 static int rcar_du_pm_resume(struct device *dev)
277 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
279 /* TODO Resume the CRTC */
281 drm_kms_helper_poll_enable(rcdu->ddev);
286 static const struct dev_pm_ops rcar_du_pm_ops = {
287 SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
290 /* -----------------------------------------------------------------------------
294 static int rcar_du_remove(struct platform_device *pdev)
296 struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
297 struct drm_device *ddev = rcdu->ddev;
299 drm_dev_unregister(ddev);
302 drm_fbdev_cma_fini(rcdu->fbdev);
304 drm_kms_helper_poll_fini(ddev);
305 drm_mode_config_cleanup(ddev);
312 static int rcar_du_probe(struct platform_device *pdev)
314 struct rcar_du_device *rcdu;
315 struct drm_device *ddev;
316 struct resource *mem;
319 /* Allocate and initialize the R-Car device structure. */
320 rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
324 rcdu->dev = &pdev->dev;
325 rcdu->info = of_device_get_match_data(rcdu->dev);
327 platform_set_drvdata(pdev, rcdu);
330 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
331 rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
332 if (IS_ERR(rcdu->mmio))
333 return PTR_ERR(rcdu->mmio);
335 /* DRM/KMS objects */
336 ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
338 return PTR_ERR(ddev);
341 ddev->dev_private = rcdu;
343 ret = rcar_du_modeset_init(rcdu);
345 if (ret != -EPROBE_DEFER)
347 "failed to initialize DRM/KMS (%d)\n", ret);
351 ddev->irq_enabled = 1;
354 * Register the DRM device with the core and the connectors with
357 ret = drm_dev_register(ddev, 0);
361 DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
366 rcar_du_remove(pdev);
371 static struct platform_driver rcar_du_platform_driver = {
372 .probe = rcar_du_probe,
373 .remove = rcar_du_remove,
376 .pm = &rcar_du_pm_ops,
377 .of_match_table = rcar_du_of_table,
381 module_platform_driver(rcar_du_platform_driver);
383 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
384 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
385 MODULE_LICENSE("GPL");