File Index
Files and directories
Sign in
FILE

rcar_du_drv.c

File preview with syntax highlighting.

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