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