xref: /openbmc/linux/drivers/gpu/drm/sun4i/sun4i_tv.c (revision d6fc9fcb)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2015 Free Electrons
4  * Copyright (C) 2015 NextThing Co
5  *
6  * Maxime Ripard <maxime.ripard@free-electrons.com>
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/component.h>
11 #include <linux/of_address.h>
12 #include <linux/regmap.h>
13 #include <linux/reset.h>
14 
15 #include <drm/drmP.h>
16 #include <drm/drm_atomic_helper.h>
17 #include <drm/drm_of.h>
18 #include <drm/drm_panel.h>
19 #include <drm/drm_probe_helper.h>
20 
21 #include "sun4i_crtc.h"
22 #include "sun4i_drv.h"
23 #include "sunxi_engine.h"
24 
25 #define SUN4I_TVE_EN_REG		0x000
26 #define SUN4I_TVE_EN_DAC_MAP_MASK		GENMASK(19, 4)
27 #define SUN4I_TVE_EN_DAC_MAP(dac, out)		(((out) & 0xf) << (dac + 1) * 4)
28 #define SUN4I_TVE_EN_ENABLE			BIT(0)
29 
30 #define SUN4I_TVE_CFG0_REG		0x004
31 #define SUN4I_TVE_CFG0_DAC_CONTROL_54M		BIT(26)
32 #define SUN4I_TVE_CFG0_CORE_DATAPATH_54M	BIT(25)
33 #define SUN4I_TVE_CFG0_CORE_CONTROL_54M		BIT(24)
34 #define SUN4I_TVE_CFG0_YC_EN			BIT(17)
35 #define SUN4I_TVE_CFG0_COMP_EN			BIT(16)
36 #define SUN4I_TVE_CFG0_RES(x)			((x) & 0xf)
37 #define SUN4I_TVE_CFG0_RES_480i			SUN4I_TVE_CFG0_RES(0)
38 #define SUN4I_TVE_CFG0_RES_576i			SUN4I_TVE_CFG0_RES(1)
39 
40 #define SUN4I_TVE_DAC0_REG		0x008
41 #define SUN4I_TVE_DAC0_CLOCK_INVERT		BIT(24)
42 #define SUN4I_TVE_DAC0_LUMA(x)			(((x) & 3) << 20)
43 #define SUN4I_TVE_DAC0_LUMA_0_4			SUN4I_TVE_DAC0_LUMA(3)
44 #define SUN4I_TVE_DAC0_CHROMA(x)		(((x) & 3) << 18)
45 #define SUN4I_TVE_DAC0_CHROMA_0_75		SUN4I_TVE_DAC0_CHROMA(3)
46 #define SUN4I_TVE_DAC0_INTERNAL_DAC(x)		(((x) & 3) << 16)
47 #define SUN4I_TVE_DAC0_INTERNAL_DAC_37_5_OHMS	SUN4I_TVE_DAC0_INTERNAL_DAC(3)
48 #define SUN4I_TVE_DAC0_DAC_EN(dac)		BIT(dac)
49 
50 #define SUN4I_TVE_NOTCH_REG		0x00c
51 #define SUN4I_TVE_NOTCH_DAC0_TO_DAC_DLY(dac, x)	((4 - (x)) << (dac * 3))
52 
53 #define SUN4I_TVE_CHROMA_FREQ_REG	0x010
54 
55 #define SUN4I_TVE_PORCH_REG		0x014
56 #define SUN4I_TVE_PORCH_BACK(x)			((x) << 16)
57 #define SUN4I_TVE_PORCH_FRONT(x)		(x)
58 
59 #define SUN4I_TVE_LINE_REG		0x01c
60 #define SUN4I_TVE_LINE_FIRST(x)			((x) << 16)
61 #define SUN4I_TVE_LINE_NUMBER(x)		(x)
62 
63 #define SUN4I_TVE_LEVEL_REG		0x020
64 #define SUN4I_TVE_LEVEL_BLANK(x)		((x) << 16)
65 #define SUN4I_TVE_LEVEL_BLACK(x)		(x)
66 
67 #define SUN4I_TVE_DAC1_REG		0x024
68 #define SUN4I_TVE_DAC1_AMPLITUDE(dac, x)	((x) << (dac * 8))
69 
70 #define SUN4I_TVE_DETECT_STA_REG	0x038
71 #define SUN4I_TVE_DETECT_STA_DAC(dac)		BIT((dac * 8))
72 #define SUN4I_TVE_DETECT_STA_UNCONNECTED		0
73 #define SUN4I_TVE_DETECT_STA_CONNECTED			1
74 #define SUN4I_TVE_DETECT_STA_GROUND			2
75 
76 #define SUN4I_TVE_CB_CR_LVL_REG		0x10c
77 #define SUN4I_TVE_CB_CR_LVL_CR_BURST(x)		((x) << 8)
78 #define SUN4I_TVE_CB_CR_LVL_CB_BURST(x)		(x)
79 
80 #define SUN4I_TVE_TINT_BURST_PHASE_REG	0x110
81 #define SUN4I_TVE_TINT_BURST_PHASE_CHROMA(x)	(x)
82 
83 #define SUN4I_TVE_BURST_WIDTH_REG	0x114
84 #define SUN4I_TVE_BURST_WIDTH_BREEZEWAY(x)	((x) << 16)
85 #define SUN4I_TVE_BURST_WIDTH_BURST_WIDTH(x)	((x) << 8)
86 #define SUN4I_TVE_BURST_WIDTH_HSYNC_WIDTH(x)	(x)
87 
88 #define SUN4I_TVE_CB_CR_GAIN_REG	0x118
89 #define SUN4I_TVE_CB_CR_GAIN_CR(x)		((x) << 8)
90 #define SUN4I_TVE_CB_CR_GAIN_CB(x)		(x)
91 
92 #define SUN4I_TVE_SYNC_VBI_REG		0x11c
93 #define SUN4I_TVE_SYNC_VBI_SYNC(x)		((x) << 16)
94 #define SUN4I_TVE_SYNC_VBI_VBLANK(x)		(x)
95 
96 #define SUN4I_TVE_ACTIVE_LINE_REG	0x124
97 #define SUN4I_TVE_ACTIVE_LINE(x)		(x)
98 
99 #define SUN4I_TVE_CHROMA_REG		0x128
100 #define SUN4I_TVE_CHROMA_COMP_GAIN(x)		((x) & 3)
101 #define SUN4I_TVE_CHROMA_COMP_GAIN_50		SUN4I_TVE_CHROMA_COMP_GAIN(2)
102 
103 #define SUN4I_TVE_12C_REG		0x12c
104 #define SUN4I_TVE_12C_NOTCH_WIDTH_WIDE		BIT(8)
105 #define SUN4I_TVE_12C_COMP_YUV_EN		BIT(0)
106 
107 #define SUN4I_TVE_RESYNC_REG		0x130
108 #define SUN4I_TVE_RESYNC_FIELD			BIT(31)
109 #define SUN4I_TVE_RESYNC_LINE(x)		((x) << 16)
110 #define SUN4I_TVE_RESYNC_PIXEL(x)		(x)
111 
112 #define SUN4I_TVE_SLAVE_REG		0x134
113 
114 #define SUN4I_TVE_WSS_DATA2_REG		0x244
115 
116 struct color_gains {
117 	u16	cb;
118 	u16	cr;
119 };
120 
121 struct burst_levels {
122 	u16	cb;
123 	u16	cr;
124 };
125 
126 struct video_levels {
127 	u16	black;
128 	u16	blank;
129 };
130 
131 struct resync_parameters {
132 	bool	field;
133 	u16	line;
134 	u16	pixel;
135 };
136 
137 struct tv_mode {
138 	char		*name;
139 
140 	u32		mode;
141 	u32		chroma_freq;
142 	u16		back_porch;
143 	u16		front_porch;
144 	u16		line_number;
145 	u16		vblank_level;
146 
147 	u32		hdisplay;
148 	u16		hfront_porch;
149 	u16		hsync_len;
150 	u16		hback_porch;
151 
152 	u32		vdisplay;
153 	u16		vfront_porch;
154 	u16		vsync_len;
155 	u16		vback_porch;
156 
157 	bool		yc_en;
158 	bool		dac3_en;
159 	bool		dac_bit25_en;
160 
161 	const struct color_gains	*color_gains;
162 	const struct burst_levels	*burst_levels;
163 	const struct video_levels	*video_levels;
164 	const struct resync_parameters	*resync_params;
165 };
166 
167 struct sun4i_tv {
168 	struct drm_connector	connector;
169 	struct drm_encoder	encoder;
170 
171 	struct clk		*clk;
172 	struct regmap		*regs;
173 	struct reset_control	*reset;
174 
175 	struct sun4i_drv	*drv;
176 };
177 
178 static const struct video_levels ntsc_video_levels = {
179 	.black = 282,	.blank = 240,
180 };
181 
182 static const struct video_levels pal_video_levels = {
183 	.black = 252,	.blank = 252,
184 };
185 
186 static const struct burst_levels ntsc_burst_levels = {
187 	.cb = 79,	.cr = 0,
188 };
189 
190 static const struct burst_levels pal_burst_levels = {
191 	.cb = 40,	.cr = 40,
192 };
193 
194 static const struct color_gains ntsc_color_gains = {
195 	.cb = 160,	.cr = 160,
196 };
197 
198 static const struct color_gains pal_color_gains = {
199 	.cb = 224,	.cr = 224,
200 };
201 
202 static const struct resync_parameters ntsc_resync_parameters = {
203 	.field = false,	.line = 14,	.pixel = 12,
204 };
205 
206 static const struct resync_parameters pal_resync_parameters = {
207 	.field = true,	.line = 13,	.pixel = 12,
208 };
209 
210 static const struct tv_mode tv_modes[] = {
211 	{
212 		.name		= "NTSC",
213 		.mode		= SUN4I_TVE_CFG0_RES_480i,
214 		.chroma_freq	= 0x21f07c1f,
215 		.yc_en		= true,
216 		.dac3_en	= true,
217 		.dac_bit25_en	= true,
218 
219 		.back_porch	= 118,
220 		.front_porch	= 32,
221 		.line_number	= 525,
222 
223 		.hdisplay	= 720,
224 		.hfront_porch	= 18,
225 		.hsync_len	= 2,
226 		.hback_porch	= 118,
227 
228 		.vdisplay	= 480,
229 		.vfront_porch	= 26,
230 		.vsync_len	= 2,
231 		.vback_porch	= 17,
232 
233 		.vblank_level	= 240,
234 
235 		.color_gains	= &ntsc_color_gains,
236 		.burst_levels	= &ntsc_burst_levels,
237 		.video_levels	= &ntsc_video_levels,
238 		.resync_params	= &ntsc_resync_parameters,
239 	},
240 	{
241 		.name		= "PAL",
242 		.mode		= SUN4I_TVE_CFG0_RES_576i,
243 		.chroma_freq	= 0x2a098acb,
244 
245 		.back_porch	= 138,
246 		.front_porch	= 24,
247 		.line_number	= 625,
248 
249 		.hdisplay	= 720,
250 		.hfront_porch	= 3,
251 		.hsync_len	= 2,
252 		.hback_porch	= 139,
253 
254 		.vdisplay	= 576,
255 		.vfront_porch	= 28,
256 		.vsync_len	= 2,
257 		.vback_porch	= 19,
258 
259 		.vblank_level	= 252,
260 
261 		.color_gains	= &pal_color_gains,
262 		.burst_levels	= &pal_burst_levels,
263 		.video_levels	= &pal_video_levels,
264 		.resync_params	= &pal_resync_parameters,
265 	},
266 };
267 
268 static inline struct sun4i_tv *
269 drm_encoder_to_sun4i_tv(struct drm_encoder *encoder)
270 {
271 	return container_of(encoder, struct sun4i_tv,
272 			    encoder);
273 }
274 
275 static inline struct sun4i_tv *
276 drm_connector_to_sun4i_tv(struct drm_connector *connector)
277 {
278 	return container_of(connector, struct sun4i_tv,
279 			    connector);
280 }
281 
282 /*
283  * FIXME: If only the drm_display_mode private field was usable, this
284  * could go away...
285  *
286  * So far, it doesn't seem to be preserved when the mode is passed by
287  * to mode_set for some reason.
288  */
289 static const struct tv_mode *sun4i_tv_find_tv_by_mode(const struct drm_display_mode *mode)
290 {
291 	int i;
292 
293 	/* First try to identify the mode by name */
294 	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
295 		const struct tv_mode *tv_mode = &tv_modes[i];
296 
297 		DRM_DEBUG_DRIVER("Comparing mode %s vs %s",
298 				 mode->name, tv_mode->name);
299 
300 		if (!strcmp(mode->name, tv_mode->name))
301 			return tv_mode;
302 	}
303 
304 	/* Then by number of lines */
305 	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
306 		const struct tv_mode *tv_mode = &tv_modes[i];
307 
308 		DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)",
309 				 mode->name, tv_mode->name,
310 				 mode->vdisplay, tv_mode->vdisplay);
311 
312 		if (mode->vdisplay == tv_mode->vdisplay)
313 			return tv_mode;
314 	}
315 
316 	return NULL;
317 }
318 
319 static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
320 				      struct drm_display_mode *mode)
321 {
322 	DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name);
323 
324 	mode->type = DRM_MODE_TYPE_DRIVER;
325 	mode->clock = 13500;
326 	mode->flags = DRM_MODE_FLAG_INTERLACE;
327 
328 	mode->hdisplay = tv_mode->hdisplay;
329 	mode->hsync_start = mode->hdisplay + tv_mode->hfront_porch;
330 	mode->hsync_end = mode->hsync_start + tv_mode->hsync_len;
331 	mode->htotal = mode->hsync_end  + tv_mode->hback_porch;
332 
333 	mode->vdisplay = tv_mode->vdisplay;
334 	mode->vsync_start = mode->vdisplay + tv_mode->vfront_porch;
335 	mode->vsync_end = mode->vsync_start + tv_mode->vsync_len;
336 	mode->vtotal = mode->vsync_end  + tv_mode->vback_porch;
337 }
338 
339 static void sun4i_tv_disable(struct drm_encoder *encoder)
340 {
341 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
342 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
343 
344 	DRM_DEBUG_DRIVER("Disabling the TV Output\n");
345 
346 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
347 			   SUN4I_TVE_EN_ENABLE,
348 			   0);
349 
350 	sunxi_engine_disable_color_correction(crtc->engine);
351 }
352 
353 static void sun4i_tv_enable(struct drm_encoder *encoder)
354 {
355 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
356 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
357 
358 	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
359 
360 	sunxi_engine_apply_color_correction(crtc->engine);
361 
362 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
363 			   SUN4I_TVE_EN_ENABLE,
364 			   SUN4I_TVE_EN_ENABLE);
365 }
366 
367 static void sun4i_tv_mode_set(struct drm_encoder *encoder,
368 			      struct drm_display_mode *mode,
369 			      struct drm_display_mode *adjusted_mode)
370 {
371 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
372 	const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
373 
374 	/* Enable and map the DAC to the output */
375 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
376 			   SUN4I_TVE_EN_DAC_MAP_MASK,
377 			   SUN4I_TVE_EN_DAC_MAP(0, 1) |
378 			   SUN4I_TVE_EN_DAC_MAP(1, 2) |
379 			   SUN4I_TVE_EN_DAC_MAP(2, 3) |
380 			   SUN4I_TVE_EN_DAC_MAP(3, 4));
381 
382 	/* Set PAL settings */
383 	regmap_write(tv->regs, SUN4I_TVE_CFG0_REG,
384 		     tv_mode->mode |
385 		     (tv_mode->yc_en ? SUN4I_TVE_CFG0_YC_EN : 0) |
386 		     SUN4I_TVE_CFG0_COMP_EN |
387 		     SUN4I_TVE_CFG0_DAC_CONTROL_54M |
388 		     SUN4I_TVE_CFG0_CORE_DATAPATH_54M |
389 		     SUN4I_TVE_CFG0_CORE_CONTROL_54M);
390 
391 	/* Configure the DAC for a composite output */
392 	regmap_write(tv->regs, SUN4I_TVE_DAC0_REG,
393 		     SUN4I_TVE_DAC0_DAC_EN(0) |
394 		     (tv_mode->dac3_en ? SUN4I_TVE_DAC0_DAC_EN(3) : 0) |
395 		     SUN4I_TVE_DAC0_INTERNAL_DAC_37_5_OHMS |
396 		     SUN4I_TVE_DAC0_CHROMA_0_75 |
397 		     SUN4I_TVE_DAC0_LUMA_0_4 |
398 		     SUN4I_TVE_DAC0_CLOCK_INVERT |
399 		     (tv_mode->dac_bit25_en ? BIT(25) : 0) |
400 		     BIT(30));
401 
402 	/* Configure the sample delay between DAC0 and the other DAC */
403 	regmap_write(tv->regs, SUN4I_TVE_NOTCH_REG,
404 		     SUN4I_TVE_NOTCH_DAC0_TO_DAC_DLY(1, 0) |
405 		     SUN4I_TVE_NOTCH_DAC0_TO_DAC_DLY(2, 0));
406 
407 	regmap_write(tv->regs, SUN4I_TVE_CHROMA_FREQ_REG,
408 		     tv_mode->chroma_freq);
409 
410 	/* Set the front and back porch */
411 	regmap_write(tv->regs, SUN4I_TVE_PORCH_REG,
412 		     SUN4I_TVE_PORCH_BACK(tv_mode->back_porch) |
413 		     SUN4I_TVE_PORCH_FRONT(tv_mode->front_porch));
414 
415 	/* Set the lines setup */
416 	regmap_write(tv->regs, SUN4I_TVE_LINE_REG,
417 		     SUN4I_TVE_LINE_FIRST(22) |
418 		     SUN4I_TVE_LINE_NUMBER(tv_mode->line_number));
419 
420 	regmap_write(tv->regs, SUN4I_TVE_LEVEL_REG,
421 		     SUN4I_TVE_LEVEL_BLANK(tv_mode->video_levels->blank) |
422 		     SUN4I_TVE_LEVEL_BLACK(tv_mode->video_levels->black));
423 
424 	regmap_write(tv->regs, SUN4I_TVE_DAC1_REG,
425 		     SUN4I_TVE_DAC1_AMPLITUDE(0, 0x18) |
426 		     SUN4I_TVE_DAC1_AMPLITUDE(1, 0x18) |
427 		     SUN4I_TVE_DAC1_AMPLITUDE(2, 0x18) |
428 		     SUN4I_TVE_DAC1_AMPLITUDE(3, 0x18));
429 
430 	regmap_write(tv->regs, SUN4I_TVE_CB_CR_LVL_REG,
431 		     SUN4I_TVE_CB_CR_LVL_CB_BURST(tv_mode->burst_levels->cb) |
432 		     SUN4I_TVE_CB_CR_LVL_CR_BURST(tv_mode->burst_levels->cr));
433 
434 	/* Set burst width for a composite output */
435 	regmap_write(tv->regs, SUN4I_TVE_BURST_WIDTH_REG,
436 		     SUN4I_TVE_BURST_WIDTH_HSYNC_WIDTH(126) |
437 		     SUN4I_TVE_BURST_WIDTH_BURST_WIDTH(68) |
438 		     SUN4I_TVE_BURST_WIDTH_BREEZEWAY(22));
439 
440 	regmap_write(tv->regs, SUN4I_TVE_CB_CR_GAIN_REG,
441 		     SUN4I_TVE_CB_CR_GAIN_CB(tv_mode->color_gains->cb) |
442 		     SUN4I_TVE_CB_CR_GAIN_CR(tv_mode->color_gains->cr));
443 
444 	regmap_write(tv->regs, SUN4I_TVE_SYNC_VBI_REG,
445 		     SUN4I_TVE_SYNC_VBI_SYNC(0x10) |
446 		     SUN4I_TVE_SYNC_VBI_VBLANK(tv_mode->vblank_level));
447 
448 	regmap_write(tv->regs, SUN4I_TVE_ACTIVE_LINE_REG,
449 		     SUN4I_TVE_ACTIVE_LINE(1440));
450 
451 	/* Set composite chroma gain to 50 % */
452 	regmap_write(tv->regs, SUN4I_TVE_CHROMA_REG,
453 		     SUN4I_TVE_CHROMA_COMP_GAIN_50);
454 
455 	regmap_write(tv->regs, SUN4I_TVE_12C_REG,
456 		     SUN4I_TVE_12C_COMP_YUV_EN |
457 		     SUN4I_TVE_12C_NOTCH_WIDTH_WIDE);
458 
459 	regmap_write(tv->regs, SUN4I_TVE_RESYNC_REG,
460 		     SUN4I_TVE_RESYNC_PIXEL(tv_mode->resync_params->pixel) |
461 		     SUN4I_TVE_RESYNC_LINE(tv_mode->resync_params->line) |
462 		     (tv_mode->resync_params->field ?
463 		      SUN4I_TVE_RESYNC_FIELD : 0));
464 
465 	regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0);
466 }
467 
468 static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
469 	.disable	= sun4i_tv_disable,
470 	.enable		= sun4i_tv_enable,
471 	.mode_set	= sun4i_tv_mode_set,
472 };
473 
474 static void sun4i_tv_destroy(struct drm_encoder *encoder)
475 {
476 	drm_encoder_cleanup(encoder);
477 }
478 
479 static struct drm_encoder_funcs sun4i_tv_funcs = {
480 	.destroy	= sun4i_tv_destroy,
481 };
482 
483 static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
484 {
485 	int i;
486 
487 	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
488 		struct drm_display_mode *mode;
489 		const struct tv_mode *tv_mode = &tv_modes[i];
490 
491 		mode = drm_mode_create(connector->dev);
492 		if (!mode) {
493 			DRM_ERROR("Failed to create a new display mode\n");
494 			return 0;
495 		}
496 
497 		strcpy(mode->name, tv_mode->name);
498 
499 		sun4i_tv_mode_to_drm_mode(tv_mode, mode);
500 		drm_mode_probed_add(connector, mode);
501 	}
502 
503 	return i;
504 }
505 
506 static int sun4i_tv_comp_mode_valid(struct drm_connector *connector,
507 				    struct drm_display_mode *mode)
508 {
509 	/* TODO */
510 	return MODE_OK;
511 }
512 
513 static struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = {
514 	.get_modes	= sun4i_tv_comp_get_modes,
515 	.mode_valid	= sun4i_tv_comp_mode_valid,
516 };
517 
518 static void
519 sun4i_tv_comp_connector_destroy(struct drm_connector *connector)
520 {
521 	drm_connector_cleanup(connector);
522 }
523 
524 static const struct drm_connector_funcs sun4i_tv_comp_connector_funcs = {
525 	.fill_modes		= drm_helper_probe_single_connector_modes,
526 	.destroy		= sun4i_tv_comp_connector_destroy,
527 	.reset			= drm_atomic_helper_connector_reset,
528 	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
529 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
530 };
531 
532 static struct regmap_config sun4i_tv_regmap_config = {
533 	.reg_bits	= 32,
534 	.val_bits	= 32,
535 	.reg_stride	= 4,
536 	.max_register	= SUN4I_TVE_WSS_DATA2_REG,
537 	.name		= "tv-encoder",
538 };
539 
540 static int sun4i_tv_bind(struct device *dev, struct device *master,
541 			 void *data)
542 {
543 	struct platform_device *pdev = to_platform_device(dev);
544 	struct drm_device *drm = data;
545 	struct sun4i_drv *drv = drm->dev_private;
546 	struct sun4i_tv *tv;
547 	struct resource *res;
548 	void __iomem *regs;
549 	int ret;
550 
551 	tv = devm_kzalloc(dev, sizeof(*tv), GFP_KERNEL);
552 	if (!tv)
553 		return -ENOMEM;
554 	tv->drv = drv;
555 	dev_set_drvdata(dev, tv);
556 
557 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
558 	regs = devm_ioremap_resource(dev, res);
559 	if (IS_ERR(regs)) {
560 		dev_err(dev, "Couldn't map the TV encoder registers\n");
561 		return PTR_ERR(regs);
562 	}
563 
564 	tv->regs = devm_regmap_init_mmio(dev, regs,
565 					 &sun4i_tv_regmap_config);
566 	if (IS_ERR(tv->regs)) {
567 		dev_err(dev, "Couldn't create the TV encoder regmap\n");
568 		return PTR_ERR(tv->regs);
569 	}
570 
571 	tv->reset = devm_reset_control_get(dev, NULL);
572 	if (IS_ERR(tv->reset)) {
573 		dev_err(dev, "Couldn't get our reset line\n");
574 		return PTR_ERR(tv->reset);
575 	}
576 
577 	ret = reset_control_deassert(tv->reset);
578 	if (ret) {
579 		dev_err(dev, "Couldn't deassert our reset line\n");
580 		return ret;
581 	}
582 
583 	tv->clk = devm_clk_get(dev, NULL);
584 	if (IS_ERR(tv->clk)) {
585 		dev_err(dev, "Couldn't get the TV encoder clock\n");
586 		ret = PTR_ERR(tv->clk);
587 		goto err_assert_reset;
588 	}
589 	clk_prepare_enable(tv->clk);
590 
591 	drm_encoder_helper_add(&tv->encoder,
592 			       &sun4i_tv_helper_funcs);
593 	ret = drm_encoder_init(drm,
594 			       &tv->encoder,
595 			       &sun4i_tv_funcs,
596 			       DRM_MODE_ENCODER_TVDAC,
597 			       NULL);
598 	if (ret) {
599 		dev_err(dev, "Couldn't initialise the TV encoder\n");
600 		goto err_disable_clk;
601 	}
602 
603 	tv->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm,
604 								dev->of_node);
605 	if (!tv->encoder.possible_crtcs) {
606 		ret = -EPROBE_DEFER;
607 		goto err_disable_clk;
608 	}
609 
610 	drm_connector_helper_add(&tv->connector,
611 				 &sun4i_tv_comp_connector_helper_funcs);
612 	ret = drm_connector_init(drm, &tv->connector,
613 				 &sun4i_tv_comp_connector_funcs,
614 				 DRM_MODE_CONNECTOR_Composite);
615 	if (ret) {
616 		dev_err(dev,
617 			"Couldn't initialise the Composite connector\n");
618 		goto err_cleanup_connector;
619 	}
620 	tv->connector.interlace_allowed = true;
621 
622 	drm_connector_attach_encoder(&tv->connector, &tv->encoder);
623 
624 	return 0;
625 
626 err_cleanup_connector:
627 	drm_encoder_cleanup(&tv->encoder);
628 err_disable_clk:
629 	clk_disable_unprepare(tv->clk);
630 err_assert_reset:
631 	reset_control_assert(tv->reset);
632 	return ret;
633 }
634 
635 static void sun4i_tv_unbind(struct device *dev, struct device *master,
636 			    void *data)
637 {
638 	struct sun4i_tv *tv = dev_get_drvdata(dev);
639 
640 	drm_connector_cleanup(&tv->connector);
641 	drm_encoder_cleanup(&tv->encoder);
642 	clk_disable_unprepare(tv->clk);
643 }
644 
645 static const struct component_ops sun4i_tv_ops = {
646 	.bind	= sun4i_tv_bind,
647 	.unbind	= sun4i_tv_unbind,
648 };
649 
650 static int sun4i_tv_probe(struct platform_device *pdev)
651 {
652 	return component_add(&pdev->dev, &sun4i_tv_ops);
653 }
654 
655 static int sun4i_tv_remove(struct platform_device *pdev)
656 {
657 	component_del(&pdev->dev, &sun4i_tv_ops);
658 
659 	return 0;
660 }
661 
662 static const struct of_device_id sun4i_tv_of_table[] = {
663 	{ .compatible = "allwinner,sun4i-a10-tv-encoder" },
664 	{ }
665 };
666 MODULE_DEVICE_TABLE(of, sun4i_tv_of_table);
667 
668 static struct platform_driver sun4i_tv_platform_driver = {
669 	.probe		= sun4i_tv_probe,
670 	.remove		= sun4i_tv_remove,
671 	.driver		= {
672 		.name		= "sun4i-tve",
673 		.of_match_table	= sun4i_tv_of_table,
674 	},
675 };
676 module_platform_driver(sun4i_tv_platform_driver);
677 
678 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
679 MODULE_DESCRIPTION("Allwinner A10 TV Encoder Driver");
680 MODULE_LICENSE("GPL");
681