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