• 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_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