1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * rcar_du_drv.c -- R-Car Display Unit DRM driver
4 *
5 * Copyright (C) 2013-2015 Renesas Electronics Corporation
6 *
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8 */
9
10 #include <linux/clk.h>
11 #include <linux/io.h>
12 #include <linux/mm.h>
13 #include <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm.h>
17 #include <linux/slab.h>
18 #include <linux/wait.h>
19
20 #include <drm/drm_atomic_helper.h>
21 #include <drm/drm_drv.h>
22 #include <drm/drm_fb_cma_helper.h>
23 #include <drm/drm_fb_helper.h>
24 #include <drm/drm_gem_cma_helper.h>
25 #include <drm/drm_managed.h>
26 #include <drm/drm_probe_helper.h>
27
28 #include "rcar_du_drv.h"
29 #include "rcar_du_kms.h"
30 #include "rcar_du_of.h"
31 #include "rcar_du_regs.h"
32
33 /* -----------------------------------------------------------------------------
34 * Device Information
35 */
36
37 static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
38 .gen = 2,
39 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
40 | RCAR_DU_FEATURE_INTERLACED
41 | RCAR_DU_FEATURE_TVM_SYNC,
42 .channels_mask = BIT(1) | BIT(0),
43 .routes = {
44 /*
45 * R8A774[34] has one RGB output and one LVDS output
46 */
47 [RCAR_DU_OUTPUT_DPAD0] = {
48 .possible_crtcs = BIT(1) | BIT(0),
49 .port = 0,
50 },
51 [RCAR_DU_OUTPUT_LVDS0] = {
52 .possible_crtcs = BIT(0),
53 .port = 1,
54 },
55 },
56 .num_lvds = 1,
57 };
58
59 static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
60 .gen = 2,
61 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
62 | RCAR_DU_FEATURE_INTERLACED
63 | RCAR_DU_FEATURE_TVM_SYNC,
64 .channels_mask = BIT(1) | BIT(0),
65 .routes = {
66 /*
67 * R8A7745 has two RGB outputs
68 */
69 [RCAR_DU_OUTPUT_DPAD0] = {
70 .possible_crtcs = BIT(0),
71 .port = 0,
72 },
73 [RCAR_DU_OUTPUT_DPAD1] = {
74 .possible_crtcs = BIT(1),
75 .port = 1,
76 },
77 },
78 };
79
80 static const struct rcar_du_device_info rzg1_du_r8a77470_info = {
81 .gen = 2,
82 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
83 | RCAR_DU_FEATURE_INTERLACED
84 | RCAR_DU_FEATURE_TVM_SYNC,
85 .channels_mask = BIT(1) | BIT(0),
86 .routes = {
87 /*
88 * R8A77470 has two RGB outputs, one LVDS output, and
89 * one (currently unsupported) analog video output
90 */
91 [RCAR_DU_OUTPUT_DPAD0] = {
92 .possible_crtcs = BIT(0),
93 .port = 0,
94 },
95 [RCAR_DU_OUTPUT_DPAD1] = {
96 .possible_crtcs = BIT(1),
97 .port = 1,
98 },
99 [RCAR_DU_OUTPUT_LVDS0] = {
100 .possible_crtcs = BIT(0) | BIT(1),
101 .port = 2,
102 },
103 },
104 };
105
106 static const struct rcar_du_device_info rcar_du_r8a774a1_info = {
107 .gen = 3,
108 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
109 | RCAR_DU_FEATURE_VSP1_SOURCE
110 | RCAR_DU_FEATURE_INTERLACED
111 | RCAR_DU_FEATURE_TVM_SYNC,
112 .channels_mask = BIT(2) | BIT(1) | BIT(0),
113 .routes = {
114 /*
115 * R8A774A1 has one RGB output, one LVDS output and one HDMI
116 * output.
117 */
118 [RCAR_DU_OUTPUT_DPAD0] = {
119 .possible_crtcs = BIT(2),
120 .port = 0,
121 },
122 [RCAR_DU_OUTPUT_HDMI0] = {
123 .possible_crtcs = BIT(1),
124 .port = 1,
125 },
126 [RCAR_DU_OUTPUT_LVDS0] = {
127 .possible_crtcs = BIT(0),
128 .port = 2,
129 },
130 },
131 .num_lvds = 1,
132 .dpll_mask = BIT(1),
133 };
134
135 static const struct rcar_du_device_info rcar_du_r8a774b1_info = {
136 .gen = 3,
137 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
138 | RCAR_DU_FEATURE_VSP1_SOURCE
139 | RCAR_DU_FEATURE_INTERLACED
140 | RCAR_DU_FEATURE_TVM_SYNC,
141 .channels_mask = BIT(3) | BIT(1) | BIT(0),
142 .routes = {
143 /*
144 * R8A774B1 has one RGB output, one LVDS output and one HDMI
145 * output.
146 */
147 [RCAR_DU_OUTPUT_DPAD0] = {
148 .possible_crtcs = BIT(2),
149 .port = 0,
150 },
151 [RCAR_DU_OUTPUT_HDMI0] = {
152 .possible_crtcs = BIT(1),
153 .port = 1,
154 },
155 [RCAR_DU_OUTPUT_LVDS0] = {
156 .possible_crtcs = BIT(0),
157 .port = 2,
158 },
159 },
160 .num_lvds = 1,
161 .dpll_mask = BIT(1),
162 };
163
164 static const struct rcar_du_device_info rcar_du_r8a774c0_info = {
165 .gen = 3,
166 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
167 | RCAR_DU_FEATURE_VSP1_SOURCE,
168 .channels_mask = BIT(1) | BIT(0),
169 .routes = {
170 /*
171 * R8A774C0 has one RGB output and two LVDS outputs
172 */
173 [RCAR_DU_OUTPUT_DPAD0] = {
174 .possible_crtcs = BIT(0) | BIT(1),
175 .port = 0,
176 },
177 [RCAR_DU_OUTPUT_LVDS0] = {
178 .possible_crtcs = BIT(0),
179 .port = 1,
180 },
181 [RCAR_DU_OUTPUT_LVDS1] = {
182 .possible_crtcs = BIT(1),
183 .port = 2,
184 },
185 },
186 .num_lvds = 2,
187 .lvds_clk_mask = BIT(1) | BIT(0),
188 };
189
190 static const struct rcar_du_device_info rcar_du_r8a774e1_info = {
191 .gen = 3,
192 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
193 | RCAR_DU_FEATURE_VSP1_SOURCE
194 | RCAR_DU_FEATURE_INTERLACED
195 | RCAR_DU_FEATURE_TVM_SYNC,
196 .channels_mask = BIT(3) | BIT(1) | BIT(0),
197 .routes = {
198 /*
199 * R8A774E1 has one RGB output, one LVDS output and one HDMI
200 * output.
201 */
202 [RCAR_DU_OUTPUT_DPAD0] = {
203 .possible_crtcs = BIT(2),
204 .port = 0,
205 },
206 [RCAR_DU_OUTPUT_HDMI0] = {
207 .possible_crtcs = BIT(1),
208 .port = 1,
209 },
210 [RCAR_DU_OUTPUT_LVDS0] = {
211 .possible_crtcs = BIT(0),
212 .port = 2,
213 },
214 },
215 .num_lvds = 1,
216 .dpll_mask = BIT(1),
217 };
218
219 static const struct rcar_du_device_info rcar_du_r8a7779_info = {
220 .gen = 1,
221 .features = RCAR_DU_FEATURE_INTERLACED
222 | RCAR_DU_FEATURE_TVM_SYNC,
223 .channels_mask = BIT(1) | BIT(0),
224 .routes = {
225 /*
226 * R8A7779 has two RGB outputs and one (currently unsupported)
227 * TCON output.
228 */
229 [RCAR_DU_OUTPUT_DPAD0] = {
230 .possible_crtcs = BIT(0),
231 .port = 0,
232 },
233 [RCAR_DU_OUTPUT_DPAD1] = {
234 .possible_crtcs = BIT(1) | BIT(0),
235 .port = 1,
236 },
237 },
238 };
239
240 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
241 .gen = 2,
242 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
243 | RCAR_DU_FEATURE_INTERLACED
244 | RCAR_DU_FEATURE_TVM_SYNC,
245 .quirks = RCAR_DU_QUIRK_ALIGN_128B,
246 .channels_mask = BIT(2) | BIT(1) | BIT(0),
247 .routes = {
248 /*
249 * R8A7742 and R8A7790 each have one RGB output and two LVDS
250 * outputs. Additionally R8A7790 supports one TCON output
251 * (currently unsupported by the driver).
252 */
253 [RCAR_DU_OUTPUT_DPAD0] = {
254 .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
255 .port = 0,
256 },
257 [RCAR_DU_OUTPUT_LVDS0] = {
258 .possible_crtcs = BIT(0),
259 .port = 1,
260 },
261 [RCAR_DU_OUTPUT_LVDS1] = {
262 .possible_crtcs = BIT(2) | BIT(1),
263 .port = 2,
264 },
265 },
266 .num_lvds = 2,
267 };
268
269 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
270 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
271 .gen = 2,
272 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
273 | RCAR_DU_FEATURE_INTERLACED
274 | RCAR_DU_FEATURE_TVM_SYNC,
275 .channels_mask = BIT(1) | BIT(0),
276 .routes = {
277 /*
278 * R8A779[13] has one RGB output, one LVDS output and one
279 * (currently unsupported) TCON output.
280 */
281 [RCAR_DU_OUTPUT_DPAD0] = {
282 .possible_crtcs = BIT(1) | BIT(0),
283 .port = 0,
284 },
285 [RCAR_DU_OUTPUT_LVDS0] = {
286 .possible_crtcs = BIT(0),
287 .port = 1,
288 },
289 },
290 .num_lvds = 1,
291 };
292
293 static const struct rcar_du_device_info rcar_du_r8a7792_info = {
294 .gen = 2,
295 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
296 | RCAR_DU_FEATURE_INTERLACED
297 | RCAR_DU_FEATURE_TVM_SYNC,
298 .channels_mask = BIT(1) | BIT(0),
299 .routes = {
300 /* R8A7792 has two RGB outputs. */
301 [RCAR_DU_OUTPUT_DPAD0] = {
302 .possible_crtcs = BIT(0),
303 .port = 0,
304 },
305 [RCAR_DU_OUTPUT_DPAD1] = {
306 .possible_crtcs = BIT(1),
307 .port = 1,
308 },
309 },
310 };
311
312 static const struct rcar_du_device_info rcar_du_r8a7794_info = {
313 .gen = 2,
314 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
315 | RCAR_DU_FEATURE_INTERLACED
316 | RCAR_DU_FEATURE_TVM_SYNC,
317 .channels_mask = BIT(1) | BIT(0),
318 .routes = {
319 /*
320 * R8A7794 has two RGB outputs and one (currently unsupported)
321 * TCON output.
322 */
323 [RCAR_DU_OUTPUT_DPAD0] = {
324 .possible_crtcs = BIT(0),
325 .port = 0,
326 },
327 [RCAR_DU_OUTPUT_DPAD1] = {
328 .possible_crtcs = BIT(1),
329 .port = 1,
330 },
331 },
332 };
333
334 static const struct rcar_du_device_info rcar_du_r8a7795_info = {
335 .gen = 3,
336 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
337 | RCAR_DU_FEATURE_VSP1_SOURCE
338 | RCAR_DU_FEATURE_INTERLACED
339 | RCAR_DU_FEATURE_TVM_SYNC,
340 .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
341 .routes = {
342 /*
343 * R8A7795 has one RGB output, two HDMI outputs and one
344 * LVDS output.
345 */
346 [RCAR_DU_OUTPUT_DPAD0] = {
347 .possible_crtcs = BIT(3),
348 .port = 0,
349 },
350 [RCAR_DU_OUTPUT_HDMI0] = {
351 .possible_crtcs = BIT(1),
352 .port = 1,
353 },
354 [RCAR_DU_OUTPUT_HDMI1] = {
355 .possible_crtcs = BIT(2),
356 .port = 2,
357 },
358 [RCAR_DU_OUTPUT_LVDS0] = {
359 .possible_crtcs = BIT(0),
360 .port = 3,
361 },
362 },
363 .num_lvds = 1,
364 .dpll_mask = BIT(2) | BIT(1),
365 };
366
367 static const struct rcar_du_device_info rcar_du_r8a7796_info = {
368 .gen = 3,
369 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
370 | RCAR_DU_FEATURE_VSP1_SOURCE
371 | RCAR_DU_FEATURE_INTERLACED
372 | RCAR_DU_FEATURE_TVM_SYNC,
373 .channels_mask = BIT(2) | BIT(1) | BIT(0),
374 .routes = {
375 /*
376 * R8A7796 has one RGB output, one LVDS output and one HDMI
377 * output.
378 */
379 [RCAR_DU_OUTPUT_DPAD0] = {
380 .possible_crtcs = BIT(2),
381 .port = 0,
382 },
383 [RCAR_DU_OUTPUT_HDMI0] = {
384 .possible_crtcs = BIT(1),
385 .port = 1,
386 },
387 [RCAR_DU_OUTPUT_LVDS0] = {
388 .possible_crtcs = BIT(0),
389 .port = 2,
390 },
391 },
392 .num_lvds = 1,
393 .dpll_mask = BIT(1),
394 };
395
396 static const struct rcar_du_device_info rcar_du_r8a77965_info = {
397 .gen = 3,
398 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
399 | RCAR_DU_FEATURE_VSP1_SOURCE
400 | RCAR_DU_FEATURE_INTERLACED
401 | RCAR_DU_FEATURE_TVM_SYNC,
402 .channels_mask = BIT(3) | BIT(1) | BIT(0),
403 .routes = {
404 /*
405 * R8A77965 has one RGB output, one LVDS output and one HDMI
406 * output.
407 */
408 [RCAR_DU_OUTPUT_DPAD0] = {
409 .possible_crtcs = BIT(2),
410 .port = 0,
411 },
412 [RCAR_DU_OUTPUT_HDMI0] = {
413 .possible_crtcs = BIT(1),
414 .port = 1,
415 },
416 [RCAR_DU_OUTPUT_LVDS0] = {
417 .possible_crtcs = BIT(0),
418 .port = 2,
419 },
420 },
421 .num_lvds = 1,
422 .dpll_mask = BIT(1),
423 };
424
425 static const struct rcar_du_device_info rcar_du_r8a77970_info = {
426 .gen = 3,
427 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
428 | RCAR_DU_FEATURE_VSP1_SOURCE
429 | RCAR_DU_FEATURE_INTERLACED
430 | RCAR_DU_FEATURE_TVM_SYNC,
431 .channels_mask = BIT(0),
432 .routes = {
433 /*
434 * R8A77970 and R8A77980 have one RGB output and one LVDS
435 * output.
436 */
437 [RCAR_DU_OUTPUT_DPAD0] = {
438 .possible_crtcs = BIT(0),
439 .port = 0,
440 },
441 [RCAR_DU_OUTPUT_LVDS0] = {
442 .possible_crtcs = BIT(0),
443 .port = 1,
444 },
445 },
446 .num_lvds = 1,
447 };
448
449 static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
450 .gen = 3,
451 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
452 | RCAR_DU_FEATURE_VSP1_SOURCE,
453 .channels_mask = BIT(1) | BIT(0),
454 .routes = {
455 /*
456 * R8A77990 and R8A77995 have one RGB output and two LVDS
457 * outputs.
458 */
459 [RCAR_DU_OUTPUT_DPAD0] = {
460 .possible_crtcs = BIT(0) | BIT(1),
461 .port = 0,
462 },
463 [RCAR_DU_OUTPUT_LVDS0] = {
464 .possible_crtcs = BIT(0),
465 .port = 1,
466 },
467 [RCAR_DU_OUTPUT_LVDS1] = {
468 .possible_crtcs = BIT(1),
469 .port = 2,
470 },
471 },
472 .num_lvds = 2,
473 .lvds_clk_mask = BIT(1) | BIT(0),
474 };
475
476 static const struct of_device_id rcar_du_of_table[] = {
477 { .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
478 { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
479 { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info },
480 { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
481 { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info },
482 { .compatible = "renesas,du-r8a774a1", .data = &rcar_du_r8a774a1_info },
483 { .compatible = "renesas,du-r8a774b1", .data = &rcar_du_r8a774b1_info },
484 { .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info },
485 { .compatible = "renesas,du-r8a774e1", .data = &rcar_du_r8a774e1_info },
486 { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
487 { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
488 { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
489 { .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
490 { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
491 { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
492 { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
493 { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
494 { .compatible = "renesas,du-r8a77961", .data = &rcar_du_r8a7796_info },
495 { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info },
496 { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
497 { .compatible = "renesas,du-r8a77980", .data = &rcar_du_r8a77970_info },
498 { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
499 { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
500 { }
501 };
502
503 MODULE_DEVICE_TABLE(of, rcar_du_of_table);
504
505 /* -----------------------------------------------------------------------------
506 * DRM operations
507 */
508
509 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
510
511 static const struct drm_driver rcar_du_driver = {
512 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
513 DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(rcar_du_dumb_create),
514 .fops = &rcar_du_fops,
515 .name = "rcar-du",
516 .desc = "Renesas R-Car Display Unit",
517 .date = "20130110",
518 .major = 1,
519 .minor = 0,
520 };
521
522 /* -----------------------------------------------------------------------------
523 * Power management
524 */
525
526 #ifdef CONFIG_PM_SLEEP
rcar_du_pm_suspend(struct device * dev)527 static int rcar_du_pm_suspend(struct device *dev)
528 {
529 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
530
531 return drm_mode_config_helper_suspend(&rcdu->ddev);
532 }
533
rcar_du_pm_resume(struct device * dev)534 static int rcar_du_pm_resume(struct device *dev)
535 {
536 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
537
538 return drm_mode_config_helper_resume(&rcdu->ddev);
539 }
540 #endif
541
542 static const struct dev_pm_ops rcar_du_pm_ops = {
543 SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
544 };
545
546 /* -----------------------------------------------------------------------------
547 * Platform driver
548 */
549
rcar_du_remove(struct platform_device * pdev)550 static int rcar_du_remove(struct platform_device *pdev)
551 {
552 struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
553 struct drm_device *ddev = &rcdu->ddev;
554
555 drm_dev_unregister(ddev);
556 drm_atomic_helper_shutdown(ddev);
557
558 drm_kms_helper_poll_fini(ddev);
559
560 return 0;
561 }
562
rcar_du_shutdown(struct platform_device * pdev)563 static void rcar_du_shutdown(struct platform_device *pdev)
564 {
565 struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
566
567 drm_atomic_helper_shutdown(&rcdu->ddev);
568 }
569
rcar_du_probe(struct platform_device * pdev)570 static int rcar_du_probe(struct platform_device *pdev)
571 {
572 struct rcar_du_device *rcdu;
573 struct resource *mem;
574 int ret;
575
576 /* Allocate and initialize the R-Car device structure. */
577 rcdu = devm_drm_dev_alloc(&pdev->dev, &rcar_du_driver,
578 struct rcar_du_device, ddev);
579 if (IS_ERR(rcdu))
580 return PTR_ERR(rcdu);
581
582 rcdu->dev = &pdev->dev;
583 rcdu->info = of_device_get_match_data(rcdu->dev);
584
585 platform_set_drvdata(pdev, rcdu);
586
587 /* I/O resources */
588 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
589 rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
590 if (IS_ERR(rcdu->mmio))
591 return PTR_ERR(rcdu->mmio);
592
593 /* DRM/KMS objects */
594 ret = rcar_du_modeset_init(rcdu);
595 if (ret < 0) {
596 if (ret != -EPROBE_DEFER)
597 dev_err(&pdev->dev,
598 "failed to initialize DRM/KMS (%d)\n", ret);
599 goto error;
600 }
601
602 /*
603 * Register the DRM device with the core and the connectors with
604 * sysfs.
605 */
606 ret = drm_dev_register(&rcdu->ddev, 0);
607 if (ret)
608 goto error;
609
610 DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
611
612 drm_fbdev_generic_setup(&rcdu->ddev, 32);
613
614 return 0;
615
616 error:
617 drm_kms_helper_poll_fini(&rcdu->ddev);
618 return ret;
619 }
620
621 static struct platform_driver rcar_du_platform_driver = {
622 .probe = rcar_du_probe,
623 .remove = rcar_du_remove,
624 .shutdown = rcar_du_shutdown,
625 .driver = {
626 .name = "rcar-du",
627 .pm = &rcar_du_pm_ops,
628 .of_match_table = rcar_du_of_table,
629 },
630 };
631
rcar_du_init(void)632 static int __init rcar_du_init(void)
633 {
634 rcar_du_of_init(rcar_du_of_table);
635
636 return platform_driver_register(&rcar_du_platform_driver);
637 }
638 module_init(rcar_du_init);
639
rcar_du_exit(void)640 static void __exit rcar_du_exit(void)
641 {
642 platform_driver_unregister(&rcar_du_platform_driver);
643 }
644 module_exit(rcar_du_exit);
645
646 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
647 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
648 MODULE_LICENSE("GPL");
649