xref: /linux/drivers/gpu/drm/sti/sti_tvout.c (revision bd628c1bed7902ec1f24ba0fe70758949146abbe)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) STMicroelectronics SA 2014
4  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
5  *          Vincent Abriou <vincent.abriou@st.com>
6  *          for STMicroelectronics.
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/component.h>
11 #include <linux/module.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/reset.h>
15 #include <linux/seq_file.h>
16 
17 #include <drm/drmP.h>
18 #include <drm/drm_crtc_helper.h>
19 
20 #include "sti_crtc.h"
21 #include "sti_drv.h"
22 #include "sti_vtg.h"
23 
24 /* glue registers */
25 #define TVO_CSC_MAIN_M0                  0x000
26 #define TVO_CSC_MAIN_M1                  0x004
27 #define TVO_CSC_MAIN_M2                  0x008
28 #define TVO_CSC_MAIN_M3                  0x00c
29 #define TVO_CSC_MAIN_M4                  0x010
30 #define TVO_CSC_MAIN_M5                  0x014
31 #define TVO_CSC_MAIN_M6                  0x018
32 #define TVO_CSC_MAIN_M7                  0x01c
33 #define TVO_MAIN_IN_VID_FORMAT           0x030
34 #define TVO_CSC_AUX_M0                   0x100
35 #define TVO_CSC_AUX_M1                   0x104
36 #define TVO_CSC_AUX_M2                   0x108
37 #define TVO_CSC_AUX_M3                   0x10c
38 #define TVO_CSC_AUX_M4                   0x110
39 #define TVO_CSC_AUX_M5                   0x114
40 #define TVO_CSC_AUX_M6                   0x118
41 #define TVO_CSC_AUX_M7                   0x11c
42 #define TVO_AUX_IN_VID_FORMAT            0x130
43 #define TVO_VIP_HDF                      0x400
44 #define TVO_HD_SYNC_SEL                  0x418
45 #define TVO_HD_DAC_CFG_OFF               0x420
46 #define TVO_VIP_HDMI                     0x500
47 #define TVO_HDMI_FORCE_COLOR_0           0x504
48 #define TVO_HDMI_FORCE_COLOR_1           0x508
49 #define TVO_HDMI_CLIP_VALUE_B_CB         0x50c
50 #define TVO_HDMI_CLIP_VALUE_Y_G          0x510
51 #define TVO_HDMI_CLIP_VALUE_R_CR         0x514
52 #define TVO_HDMI_SYNC_SEL                0x518
53 #define TVO_HDMI_DFV_OBS                 0x540
54 #define TVO_VIP_DVO                      0x600
55 #define TVO_DVO_SYNC_SEL                 0x618
56 #define TVO_DVO_CONFIG                   0x620
57 
58 #define TVO_IN_FMT_SIGNED                BIT(0)
59 #define TVO_SYNC_EXT                     BIT(4)
60 
61 #define TVO_VIP_REORDER_R_SHIFT          24
62 #define TVO_VIP_REORDER_G_SHIFT          20
63 #define TVO_VIP_REORDER_B_SHIFT          16
64 #define TVO_VIP_REORDER_MASK             0x3
65 #define TVO_VIP_REORDER_Y_G_SEL          0
66 #define TVO_VIP_REORDER_CB_B_SEL         1
67 #define TVO_VIP_REORDER_CR_R_SEL         2
68 
69 #define TVO_VIP_CLIP_SHIFT               8
70 #define TVO_VIP_CLIP_MASK                0x7
71 #define TVO_VIP_CLIP_DISABLED            0
72 #define TVO_VIP_CLIP_EAV_SAV             1
73 #define TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y 2
74 #define TVO_VIP_CLIP_LIMITED_RANGE_CB_CR 3
75 #define TVO_VIP_CLIP_PROG_RANGE          4
76 
77 #define TVO_VIP_RND_SHIFT                4
78 #define TVO_VIP_RND_MASK                 0x3
79 #define TVO_VIP_RND_8BIT_ROUNDED         0
80 #define TVO_VIP_RND_10BIT_ROUNDED        1
81 #define TVO_VIP_RND_12BIT_ROUNDED        2
82 
83 #define TVO_VIP_SEL_INPUT_MASK           0xf
84 #define TVO_VIP_SEL_INPUT_MAIN           0x0
85 #define TVO_VIP_SEL_INPUT_AUX            0x8
86 #define TVO_VIP_SEL_INPUT_FORCE_COLOR    0xf
87 #define TVO_VIP_SEL_INPUT_BYPASS_MASK    0x1
88 #define TVO_VIP_SEL_INPUT_BYPASSED       1
89 
90 #define TVO_SYNC_MAIN_VTG_SET_REF        0x00
91 #define TVO_SYNC_AUX_VTG_SET_REF         0x10
92 
93 #define TVO_SYNC_HD_DCS_SHIFT            8
94 
95 #define TVO_SYNC_DVO_PAD_HSYNC_SHIFT     8
96 #define TVO_SYNC_DVO_PAD_VSYNC_SHIFT     16
97 
98 #define ENCODER_CRTC_MASK                (BIT(0) | BIT(1))
99 
100 #define TVO_MIN_HD_HEIGHT                720
101 
102 /* enum listing the supported output data format */
103 enum sti_tvout_video_out_type {
104 	STI_TVOUT_VIDEO_OUT_RGB,
105 	STI_TVOUT_VIDEO_OUT_YUV,
106 };
107 
108 struct sti_tvout {
109 	struct device *dev;
110 	struct drm_device *drm_dev;
111 	void __iomem *regs;
112 	struct reset_control *reset;
113 	struct drm_encoder *hdmi;
114 	struct drm_encoder *hda;
115 	struct drm_encoder *dvo;
116 	bool debugfs_registered;
117 };
118 
119 struct sti_tvout_encoder {
120 	struct drm_encoder encoder;
121 	struct sti_tvout *tvout;
122 };
123 
124 #define to_sti_tvout_encoder(x) \
125 	container_of(x, struct sti_tvout_encoder, encoder)
126 
127 #define to_sti_tvout(x) to_sti_tvout_encoder(x)->tvout
128 
129 /* preformatter conversion matrix */
130 static const u32 rgb_to_ycbcr_601[8] = {
131 	0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D,
132 	0x0000082E, 0x00002000, 0x00002000, 0x00000000
133 };
134 
135 /* 709 RGB to YCbCr */
136 static const u32 rgb_to_ycbcr_709[8] = {
137 	0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20,
138 	0x0000082F, 0x00002000, 0x00002000, 0x00000000
139 };
140 
141 static u32 tvout_read(struct sti_tvout *tvout, int offset)
142 {
143 	return readl(tvout->regs + offset);
144 }
145 
146 static void tvout_write(struct sti_tvout *tvout, u32 val, int offset)
147 {
148 	writel(val, tvout->regs + offset);
149 }
150 
151 /**
152  * Set the clipping mode of a VIP
153  *
154  * @tvout: tvout structure
155  * @reg: register to set
156  * @cr_r:
157  * @y_g:
158  * @cb_b:
159  */
160 static void tvout_vip_set_color_order(struct sti_tvout *tvout, int reg,
161 				      u32 cr_r, u32 y_g, u32 cb_b)
162 {
163 	u32 val = tvout_read(tvout, reg);
164 
165 	val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT);
166 	val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT);
167 	val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT);
168 	val |= cr_r << TVO_VIP_REORDER_R_SHIFT;
169 	val |= y_g << TVO_VIP_REORDER_G_SHIFT;
170 	val |= cb_b << TVO_VIP_REORDER_B_SHIFT;
171 
172 	tvout_write(tvout, val, reg);
173 }
174 
175 /**
176  * Set the clipping mode of a VIP
177  *
178  * @tvout: tvout structure
179  * @reg: register to set
180  * @range: clipping range
181  */
182 static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, int reg, u32 range)
183 {
184 	u32 val = tvout_read(tvout, reg);
185 
186 	val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT);
187 	val |= range << TVO_VIP_CLIP_SHIFT;
188 	tvout_write(tvout, val, reg);
189 }
190 
191 /**
192  * Set the rounded value of a VIP
193  *
194  * @tvout: tvout structure
195  * @reg: register to set
196  * @rnd: rounded val per component
197  */
198 static void tvout_vip_set_rnd(struct sti_tvout *tvout, int reg, u32 rnd)
199 {
200 	u32 val = tvout_read(tvout, reg);
201 
202 	val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT);
203 	val |= rnd << TVO_VIP_RND_SHIFT;
204 	tvout_write(tvout, val, reg);
205 }
206 
207 /**
208  * Select the VIP input
209  *
210  * @tvout: tvout structure
211  * @reg: register to set
212  * @main_path: main or auxiliary path
213  * @sel_input: selected_input (main/aux + conv)
214  */
215 static void tvout_vip_set_sel_input(struct sti_tvout *tvout,
216 				    int reg,
217 				    bool main_path,
218 				    enum sti_tvout_video_out_type video_out)
219 {
220 	u32 sel_input;
221 	u32 val = tvout_read(tvout, reg);
222 
223 	if (main_path)
224 		sel_input = TVO_VIP_SEL_INPUT_MAIN;
225 	else
226 		sel_input = TVO_VIP_SEL_INPUT_AUX;
227 
228 	switch (video_out) {
229 	case STI_TVOUT_VIDEO_OUT_RGB:
230 		sel_input |= TVO_VIP_SEL_INPUT_BYPASSED;
231 		break;
232 	case STI_TVOUT_VIDEO_OUT_YUV:
233 		sel_input &= ~TVO_VIP_SEL_INPUT_BYPASSED;
234 		break;
235 	}
236 
237 	/* on stih407 chip the sel_input bypass mode logic is inverted */
238 	sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK;
239 
240 	val &= ~TVO_VIP_SEL_INPUT_MASK;
241 	val |= sel_input;
242 	tvout_write(tvout, val, reg);
243 }
244 
245 /**
246  * Select the input video signed or unsigned
247  *
248  * @tvout: tvout structure
249  * @reg: register to set
250  * @in_vid_signed: used video input format
251  */
252 static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout,
253 		int reg, u32 in_vid_fmt)
254 {
255 	u32 val = tvout_read(tvout, reg);
256 
257 	val &= ~TVO_IN_FMT_SIGNED;
258 	val |= in_vid_fmt;
259 	tvout_write(tvout, val, reg);
260 }
261 
262 /**
263  * Set preformatter matrix
264  *
265  * @tvout: tvout structure
266  * @mode: display mode structure
267  */
268 static void tvout_preformatter_set_matrix(struct sti_tvout *tvout,
269 					  struct drm_display_mode *mode)
270 {
271 	unsigned int i;
272 	const u32 *pf_matrix;
273 
274 	if (mode->vdisplay >= TVO_MIN_HD_HEIGHT)
275 		pf_matrix = rgb_to_ycbcr_709;
276 	else
277 		pf_matrix = rgb_to_ycbcr_601;
278 
279 	for (i = 0; i < 8; i++) {
280 		tvout_write(tvout, *(pf_matrix + i),
281 			    TVO_CSC_MAIN_M0 + (i * 4));
282 		tvout_write(tvout, *(pf_matrix + i),
283 			    TVO_CSC_AUX_M0 + (i * 4));
284 	}
285 }
286 
287 /**
288  * Start VIP block for DVO output
289  *
290  * @tvout: pointer on tvout structure
291  * @main_path: true if main path has to be used in the vip configuration
292  *	  else aux path is used.
293  */
294 static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
295 {
296 	u32 tvo_in_vid_format;
297 	int val, tmp;
298 
299 	dev_dbg(tvout->dev, "%s\n", __func__);
300 
301 	if (main_path) {
302 		DRM_DEBUG_DRIVER("main vip for DVO\n");
303 		/* Select the input sync for dvo */
304 		tmp = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_DVO;
305 		val  = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
306 		val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
307 		val |= tmp;
308 		tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
309 		tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
310 	} else {
311 		DRM_DEBUG_DRIVER("aux vip for DVO\n");
312 		/* Select the input sync for dvo */
313 		tmp = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_DVO;
314 		val  = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
315 		val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
316 		val |= tmp;
317 		tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
318 		tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
319 	}
320 
321 	/* Set color channel order */
322 	tvout_vip_set_color_order(tvout, TVO_VIP_DVO,
323 				  TVO_VIP_REORDER_CR_R_SEL,
324 				  TVO_VIP_REORDER_Y_G_SEL,
325 				  TVO_VIP_REORDER_CB_B_SEL);
326 
327 	/* Set clipping mode */
328 	tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, TVO_VIP_CLIP_DISABLED);
329 
330 	/* Set round mode (rounded to 8-bit per component) */
331 	tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED);
332 
333 	/* Set input video format */
334 	tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
335 
336 	/* Input selection */
337 	tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path,
338 				STI_TVOUT_VIDEO_OUT_RGB);
339 }
340 
341 /**
342  * Start VIP block for HDMI output
343  *
344  * @tvout: pointer on tvout structure
345  * @main_path: true if main path has to be used in the vip configuration
346  *	  else aux path is used.
347  */
348 static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
349 {
350 	u32 tvo_in_vid_format;
351 
352 	dev_dbg(tvout->dev, "%s\n", __func__);
353 
354 	if (main_path) {
355 		DRM_DEBUG_DRIVER("main vip for hdmi\n");
356 		/* select the input sync for hdmi */
357 		tvout_write(tvout,
358 			    TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDMI,
359 			    TVO_HDMI_SYNC_SEL);
360 		tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
361 	} else {
362 		DRM_DEBUG_DRIVER("aux vip for hdmi\n");
363 		/* select the input sync for hdmi */
364 		tvout_write(tvout,
365 			    TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDMI,
366 			    TVO_HDMI_SYNC_SEL);
367 		tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
368 	}
369 
370 	/* set color channel order */
371 	tvout_vip_set_color_order(tvout, TVO_VIP_HDMI,
372 				  TVO_VIP_REORDER_CR_R_SEL,
373 				  TVO_VIP_REORDER_Y_G_SEL,
374 				  TVO_VIP_REORDER_CB_B_SEL);
375 
376 	/* set clipping mode */
377 	tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, TVO_VIP_CLIP_DISABLED);
378 
379 	/* set round mode (rounded to 8-bit per component) */
380 	tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED);
381 
382 	/* set input video format */
383 	tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
384 
385 	/* input selection */
386 	tvout_vip_set_sel_input(tvout, TVO_VIP_HDMI, main_path,
387 				STI_TVOUT_VIDEO_OUT_RGB);
388 }
389 
390 /**
391  * Start HDF VIP and HD DAC
392  *
393  * @tvout: pointer on tvout structure
394  * @main_path: true if main path has to be used in the vip configuration
395  *	  else aux path is used.
396  */
397 static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
398 {
399 	u32 tvo_in_vid_format;
400 	int val;
401 
402 	dev_dbg(tvout->dev, "%s\n", __func__);
403 
404 	if (main_path) {
405 		DRM_DEBUG_DRIVER("main vip for HDF\n");
406 		/* Select the input sync for HD analog and HD DCS */
407 		val  = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDDCS;
408 		val  = val << TVO_SYNC_HD_DCS_SHIFT;
409 		val |= TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDF;
410 		tvout_write(tvout, val, TVO_HD_SYNC_SEL);
411 		tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
412 	} else {
413 		DRM_DEBUG_DRIVER("aux vip for HDF\n");
414 		/* Select the input sync for HD analog and HD DCS */
415 		val  = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDDCS;
416 		val  = val << TVO_SYNC_HD_DCS_SHIFT;
417 		val |= TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDF;
418 		tvout_write(tvout, val, TVO_HD_SYNC_SEL);
419 		tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
420 	}
421 
422 	/* set color channel order */
423 	tvout_vip_set_color_order(tvout, TVO_VIP_HDF,
424 				  TVO_VIP_REORDER_CR_R_SEL,
425 				  TVO_VIP_REORDER_Y_G_SEL,
426 				  TVO_VIP_REORDER_CB_B_SEL);
427 
428 	/* set clipping mode */
429 	tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_DISABLED);
430 
431 	/* set round mode (rounded to 10-bit per component) */
432 	tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED);
433 
434 	/* Set input video format */
435 	tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
436 
437 	/* Input selection */
438 	tvout_vip_set_sel_input(tvout, TVO_VIP_HDF, main_path,
439 				STI_TVOUT_VIDEO_OUT_YUV);
440 
441 	/* power up HD DAC */
442 	tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF);
443 }
444 
445 #define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
446 				   readl(tvout->regs + reg))
447 
448 static void tvout_dbg_vip(struct seq_file *s, int val)
449 {
450 	int r, g, b, tmp, mask;
451 	char *const reorder[] = {"Y_G", "Cb_B", "Cr_R"};
452 	char *const clipping[] = {"No", "EAV/SAV", "Limited range RGB/Y",
453 				  "Limited range Cb/Cr", "decided by register"};
454 	char *const round[] = {"8-bit", "10-bit", "12-bit"};
455 	char *const input_sel[] = {"Main (color matrix enabled)",
456 				   "Main (color matrix by-passed)",
457 				   "", "", "", "", "", "",
458 				   "Aux (color matrix enabled)",
459 				   "Aux (color matrix by-passed)",
460 				   "", "", "", "", "", "Force value"};
461 
462 	seq_putc(s, '\t');
463 	mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT;
464 	r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT;
465 	mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT;
466 	g = (val & mask) >> TVO_VIP_REORDER_G_SHIFT;
467 	mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT;
468 	b = (val & mask) >> TVO_VIP_REORDER_B_SHIFT;
469 	seq_printf(s, "%-24s %s->%s %s->%s %s->%s\n", "Reorder:",
470 		   reorder[r], reorder[TVO_VIP_REORDER_CR_R_SEL],
471 		   reorder[g], reorder[TVO_VIP_REORDER_Y_G_SEL],
472 		   reorder[b], reorder[TVO_VIP_REORDER_CB_B_SEL]);
473 	seq_puts(s, "\t\t\t\t\t");
474 	mask = TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT;
475 	tmp = (val & mask) >> TVO_VIP_CLIP_SHIFT;
476 	seq_printf(s, "%-24s %s\n", "Clipping:", clipping[tmp]);
477 	seq_puts(s, "\t\t\t\t\t");
478 	mask = TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT;
479 	tmp = (val & mask) >> TVO_VIP_RND_SHIFT;
480 	seq_printf(s, "%-24s input data rounded to %s per component\n",
481 		   "Round:", round[tmp]);
482 	seq_puts(s, "\t\t\t\t\t");
483 	tmp = (val & TVO_VIP_SEL_INPUT_MASK);
484 	seq_printf(s, "%-24s %s", "Input selection:", input_sel[tmp]);
485 }
486 
487 static void tvout_dbg_hd_dac_cfg(struct seq_file *s, int val)
488 {
489 	seq_printf(s, "\t%-24s %s", "HD DAC:",
490 		   val & 1 ? "disabled" : "enabled");
491 }
492 
493 static int tvout_dbg_show(struct seq_file *s, void *data)
494 {
495 	struct drm_info_node *node = s->private;
496 	struct sti_tvout *tvout = (struct sti_tvout *)node->info_ent->data;
497 	struct drm_crtc *crtc;
498 
499 	seq_printf(s, "TVOUT: (vaddr = 0x%p)", tvout->regs);
500 
501 	seq_puts(s, "\n\n  HDMI encoder: ");
502 	crtc = tvout->hdmi->crtc;
503 	if (crtc) {
504 		seq_printf(s, "connected to %s path",
505 			   sti_crtc_is_main(crtc) ? "main" : "aux");
506 		DBGFS_DUMP(TVO_HDMI_SYNC_SEL);
507 		DBGFS_DUMP(TVO_VIP_HDMI);
508 		tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDMI));
509 	} else {
510 		seq_puts(s, "disabled");
511 	}
512 
513 	seq_puts(s, "\n\n  DVO encoder: ");
514 	crtc = tvout->dvo->crtc;
515 	if (crtc) {
516 		seq_printf(s, "connected to %s path",
517 			   sti_crtc_is_main(crtc) ? "main" : "aux");
518 		DBGFS_DUMP(TVO_DVO_SYNC_SEL);
519 		DBGFS_DUMP(TVO_DVO_CONFIG);
520 		DBGFS_DUMP(TVO_VIP_DVO);
521 		tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_DVO));
522 	} else {
523 		seq_puts(s, "disabled");
524 	}
525 
526 	seq_puts(s, "\n\n  HDA encoder: ");
527 	crtc = tvout->hda->crtc;
528 	if (crtc) {
529 		seq_printf(s, "connected to %s path",
530 			   sti_crtc_is_main(crtc) ? "main" : "aux");
531 		DBGFS_DUMP(TVO_HD_SYNC_SEL);
532 		DBGFS_DUMP(TVO_HD_DAC_CFG_OFF);
533 		tvout_dbg_hd_dac_cfg(s,
534 				     readl(tvout->regs + TVO_HD_DAC_CFG_OFF));
535 		DBGFS_DUMP(TVO_VIP_HDF);
536 		tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDF));
537 	} else {
538 		seq_puts(s, "disabled");
539 	}
540 
541 	seq_puts(s, "\n\n  main path configuration");
542 	DBGFS_DUMP(TVO_CSC_MAIN_M0);
543 	DBGFS_DUMP(TVO_CSC_MAIN_M1);
544 	DBGFS_DUMP(TVO_CSC_MAIN_M2);
545 	DBGFS_DUMP(TVO_CSC_MAIN_M3);
546 	DBGFS_DUMP(TVO_CSC_MAIN_M4);
547 	DBGFS_DUMP(TVO_CSC_MAIN_M5);
548 	DBGFS_DUMP(TVO_CSC_MAIN_M6);
549 	DBGFS_DUMP(TVO_CSC_MAIN_M7);
550 	DBGFS_DUMP(TVO_MAIN_IN_VID_FORMAT);
551 
552 	seq_puts(s, "\n\n  auxiliary path configuration");
553 	DBGFS_DUMP(TVO_CSC_AUX_M0);
554 	DBGFS_DUMP(TVO_CSC_AUX_M2);
555 	DBGFS_DUMP(TVO_CSC_AUX_M3);
556 	DBGFS_DUMP(TVO_CSC_AUX_M4);
557 	DBGFS_DUMP(TVO_CSC_AUX_M5);
558 	DBGFS_DUMP(TVO_CSC_AUX_M6);
559 	DBGFS_DUMP(TVO_CSC_AUX_M7);
560 	DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT);
561 	seq_putc(s, '\n');
562 	return 0;
563 }
564 
565 static struct drm_info_list tvout_debugfs_files[] = {
566 	{ "tvout", tvout_dbg_show, 0, NULL },
567 };
568 
569 static int tvout_debugfs_init(struct sti_tvout *tvout, struct drm_minor *minor)
570 {
571 	unsigned int i;
572 
573 	for (i = 0; i < ARRAY_SIZE(tvout_debugfs_files); i++)
574 		tvout_debugfs_files[i].data = tvout;
575 
576 	return drm_debugfs_create_files(tvout_debugfs_files,
577 					ARRAY_SIZE(tvout_debugfs_files),
578 					minor->debugfs_root, minor);
579 }
580 
581 static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode)
582 {
583 }
584 
585 static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder,
586 				       struct drm_display_mode *mode,
587 				       struct drm_display_mode *adjusted_mode)
588 {
589 }
590 
591 static void sti_tvout_encoder_destroy(struct drm_encoder *encoder)
592 {
593 	struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder);
594 
595 	drm_encoder_cleanup(encoder);
596 	kfree(sti_encoder);
597 }
598 
599 static int sti_tvout_late_register(struct drm_encoder *encoder)
600 {
601 	struct sti_tvout *tvout = to_sti_tvout(encoder);
602 	int ret;
603 
604 	if (tvout->debugfs_registered)
605 		return 0;
606 
607 	ret = tvout_debugfs_init(tvout, encoder->dev->primary);
608 	if (ret)
609 		return ret;
610 
611 	tvout->debugfs_registered = true;
612 	return 0;
613 }
614 
615 static void sti_tvout_early_unregister(struct drm_encoder *encoder)
616 {
617 	struct sti_tvout *tvout = to_sti_tvout(encoder);
618 
619 	if (!tvout->debugfs_registered)
620 		return;
621 
622 	tvout->debugfs_registered = false;
623 }
624 
625 static const struct drm_encoder_funcs sti_tvout_encoder_funcs = {
626 	.destroy = sti_tvout_encoder_destroy,
627 	.late_register = sti_tvout_late_register,
628 	.early_unregister = sti_tvout_early_unregister,
629 };
630 
631 static void sti_dvo_encoder_enable(struct drm_encoder *encoder)
632 {
633 	struct sti_tvout *tvout = to_sti_tvout(encoder);
634 
635 	tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
636 
637 	tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc));
638 }
639 
640 static void sti_dvo_encoder_disable(struct drm_encoder *encoder)
641 {
642 	struct sti_tvout *tvout = to_sti_tvout(encoder);
643 
644 	/* Reset VIP register */
645 	tvout_write(tvout, 0x0, TVO_VIP_DVO);
646 }
647 
648 static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = {
649 	.dpms = sti_tvout_encoder_dpms,
650 	.mode_set = sti_tvout_encoder_mode_set,
651 	.enable = sti_dvo_encoder_enable,
652 	.disable = sti_dvo_encoder_disable,
653 };
654 
655 static struct drm_encoder *
656 sti_tvout_create_dvo_encoder(struct drm_device *dev,
657 			     struct sti_tvout *tvout)
658 {
659 	struct sti_tvout_encoder *encoder;
660 	struct drm_encoder *drm_encoder;
661 
662 	encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
663 	if (!encoder)
664 		return NULL;
665 
666 	encoder->tvout = tvout;
667 
668 	drm_encoder = (struct drm_encoder *)encoder;
669 
670 	drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
671 	drm_encoder->possible_clones = 1 << 0;
672 
673 	drm_encoder_init(dev, drm_encoder,
674 			 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS,
675 			 NULL);
676 
677 	drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs);
678 
679 	return drm_encoder;
680 }
681 
682 static void sti_hda_encoder_enable(struct drm_encoder *encoder)
683 {
684 	struct sti_tvout *tvout = to_sti_tvout(encoder);
685 
686 	tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
687 
688 	tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc));
689 }
690 
691 static void sti_hda_encoder_disable(struct drm_encoder *encoder)
692 {
693 	struct sti_tvout *tvout = to_sti_tvout(encoder);
694 
695 	/* reset VIP register */
696 	tvout_write(tvout, 0x0, TVO_VIP_HDF);
697 
698 	/* power down HD DAC */
699 	tvout_write(tvout, 1, TVO_HD_DAC_CFG_OFF);
700 }
701 
702 static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = {
703 	.dpms = sti_tvout_encoder_dpms,
704 	.mode_set = sti_tvout_encoder_mode_set,
705 	.commit = sti_hda_encoder_enable,
706 	.disable = sti_hda_encoder_disable,
707 };
708 
709 static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev,
710 		struct sti_tvout *tvout)
711 {
712 	struct sti_tvout_encoder *encoder;
713 	struct drm_encoder *drm_encoder;
714 
715 	encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
716 	if (!encoder)
717 		return NULL;
718 
719 	encoder->tvout = tvout;
720 
721 	drm_encoder = (struct drm_encoder *) encoder;
722 
723 	drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
724 	drm_encoder->possible_clones = 1 << 0;
725 
726 	drm_encoder_init(dev, drm_encoder,
727 			&sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL);
728 
729 	drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs);
730 
731 	return drm_encoder;
732 }
733 
734 static void sti_hdmi_encoder_enable(struct drm_encoder *encoder)
735 {
736 	struct sti_tvout *tvout = to_sti_tvout(encoder);
737 
738 	tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
739 
740 	tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc));
741 }
742 
743 static void sti_hdmi_encoder_disable(struct drm_encoder *encoder)
744 {
745 	struct sti_tvout *tvout = to_sti_tvout(encoder);
746 
747 	/* reset VIP register */
748 	tvout_write(tvout, 0x0, TVO_VIP_HDMI);
749 }
750 
751 static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = {
752 	.dpms = sti_tvout_encoder_dpms,
753 	.mode_set = sti_tvout_encoder_mode_set,
754 	.commit = sti_hdmi_encoder_enable,
755 	.disable = sti_hdmi_encoder_disable,
756 };
757 
758 static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev,
759 		struct sti_tvout *tvout)
760 {
761 	struct sti_tvout_encoder *encoder;
762 	struct drm_encoder *drm_encoder;
763 
764 	encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
765 	if (!encoder)
766 		return NULL;
767 
768 	encoder->tvout = tvout;
769 
770 	drm_encoder = (struct drm_encoder *) encoder;
771 
772 	drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
773 	drm_encoder->possible_clones = 1 << 1;
774 
775 	drm_encoder_init(dev, drm_encoder,
776 			&sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
777 
778 	drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs);
779 
780 	return drm_encoder;
781 }
782 
783 static void sti_tvout_create_encoders(struct drm_device *dev,
784 		struct sti_tvout *tvout)
785 {
786 	tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout);
787 	tvout->hda = sti_tvout_create_hda_encoder(dev, tvout);
788 	tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout);
789 }
790 
791 static void sti_tvout_destroy_encoders(struct sti_tvout *tvout)
792 {
793 	if (tvout->hdmi)
794 		drm_encoder_cleanup(tvout->hdmi);
795 	tvout->hdmi = NULL;
796 
797 	if (tvout->hda)
798 		drm_encoder_cleanup(tvout->hda);
799 	tvout->hda = NULL;
800 
801 	if (tvout->dvo)
802 		drm_encoder_cleanup(tvout->dvo);
803 	tvout->dvo = NULL;
804 }
805 
806 static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
807 {
808 	struct sti_tvout *tvout = dev_get_drvdata(dev);
809 	struct drm_device *drm_dev = data;
810 
811 	tvout->drm_dev = drm_dev;
812 
813 	sti_tvout_create_encoders(drm_dev, tvout);
814 
815 	return 0;
816 }
817 
818 static void sti_tvout_unbind(struct device *dev, struct device *master,
819 	void *data)
820 {
821 	struct sti_tvout *tvout = dev_get_drvdata(dev);
822 
823 	sti_tvout_destroy_encoders(tvout);
824 }
825 
826 static const struct component_ops sti_tvout_ops = {
827 	.bind	= sti_tvout_bind,
828 	.unbind	= sti_tvout_unbind,
829 };
830 
831 static int sti_tvout_probe(struct platform_device *pdev)
832 {
833 	struct device *dev = &pdev->dev;
834 	struct device_node *node = dev->of_node;
835 	struct sti_tvout *tvout;
836 	struct resource *res;
837 
838 	DRM_INFO("%s\n", __func__);
839 
840 	if (!node)
841 		return -ENODEV;
842 
843 	tvout = devm_kzalloc(dev, sizeof(*tvout), GFP_KERNEL);
844 	if (!tvout)
845 		return -ENOMEM;
846 
847 	tvout->dev = dev;
848 
849 	/* get memory resources */
850 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg");
851 	if (!res) {
852 		DRM_ERROR("Invalid glue resource\n");
853 		return -ENOMEM;
854 	}
855 	tvout->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
856 	if (!tvout->regs)
857 		return -ENOMEM;
858 
859 	/* get reset resources */
860 	tvout->reset = devm_reset_control_get(dev, "tvout");
861 	/* take tvout out of reset */
862 	if (!IS_ERR(tvout->reset))
863 		reset_control_deassert(tvout->reset);
864 
865 	platform_set_drvdata(pdev, tvout);
866 
867 	return component_add(dev, &sti_tvout_ops);
868 }
869 
870 static int sti_tvout_remove(struct platform_device *pdev)
871 {
872 	component_del(&pdev->dev, &sti_tvout_ops);
873 	return 0;
874 }
875 
876 static const struct of_device_id tvout_of_match[] = {
877 	{ .compatible = "st,stih407-tvout", },
878 	{ /* end node */ }
879 };
880 MODULE_DEVICE_TABLE(of, tvout_of_match);
881 
882 struct platform_driver sti_tvout_driver = {
883 	.driver = {
884 		.name = "sti-tvout",
885 		.owner = THIS_MODULE,
886 		.of_match_table = tvout_of_match,
887 	},
888 	.probe = sti_tvout_probe,
889 	.remove = sti_tvout_remove,
890 };
891 
892 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
893 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
894 MODULE_LICENSE("GPL");
895