xref: /openbmc/linux/drivers/gpu/drm/sun4i/sun4i_tcon.c (revision 133f9794)
1 /*
2  * Copyright (C) 2015 Free Electrons
3  * Copyright (C) 2015 NextThing Co
4  *
5  * Maxime Ripard <maxime.ripard@free-electrons.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  */
12 
13 #include <drm/drmP.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_crtc.h>
16 #include <drm/drm_crtc_helper.h>
17 #include <drm/drm_encoder.h>
18 #include <drm/drm_modes.h>
19 #include <drm/drm_of.h>
20 
21 #include <uapi/drm/drm_mode.h>
22 
23 #include <linux/component.h>
24 #include <linux/ioport.h>
25 #include <linux/of_address.h>
26 #include <linux/of_device.h>
27 #include <linux/of_irq.h>
28 #include <linux/regmap.h>
29 #include <linux/reset.h>
30 
31 #include "sun4i_crtc.h"
32 #include "sun4i_dotclock.h"
33 #include "sun4i_drv.h"
34 #include "sun4i_lvds.h"
35 #include "sun4i_rgb.h"
36 #include "sun4i_tcon.h"
37 #include "sunxi_engine.h"
38 
39 static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
40 {
41 	struct drm_connector *connector;
42 	struct drm_connector_list_iter iter;
43 
44 	drm_connector_list_iter_begin(encoder->dev, &iter);
45 	drm_for_each_connector_iter(connector, &iter)
46 		if (connector->encoder == encoder) {
47 			drm_connector_list_iter_end(&iter);
48 			return connector;
49 		}
50 	drm_connector_list_iter_end(&iter);
51 
52 	return NULL;
53 }
54 
55 static int sun4i_tcon_get_pixel_depth(const struct drm_encoder *encoder)
56 {
57 	struct drm_connector *connector;
58 	struct drm_display_info *info;
59 
60 	connector = sun4i_tcon_get_connector(encoder);
61 	if (!connector)
62 		return -EINVAL;
63 
64 	info = &connector->display_info;
65 	if (info->num_bus_formats != 1)
66 		return -EINVAL;
67 
68 	switch (info->bus_formats[0]) {
69 	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
70 		return 18;
71 
72 	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
73 	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
74 		return 24;
75 	}
76 
77 	return -EINVAL;
78 }
79 
80 static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
81 					  bool enabled)
82 {
83 	struct clk *clk;
84 
85 	switch (channel) {
86 	case 0:
87 		WARN_ON(!tcon->quirks->has_channel_0);
88 		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
89 				   SUN4I_TCON0_CTL_TCON_ENABLE,
90 				   enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
91 		clk = tcon->dclk;
92 		break;
93 	case 1:
94 		WARN_ON(!tcon->quirks->has_channel_1);
95 		regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
96 				   SUN4I_TCON1_CTL_TCON_ENABLE,
97 				   enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
98 		clk = tcon->sclk1;
99 		break;
100 	default:
101 		DRM_WARN("Unknown channel... doing nothing\n");
102 		return;
103 	}
104 
105 	if (enabled)
106 		clk_prepare_enable(clk);
107 	else
108 		clk_disable_unprepare(clk);
109 }
110 
111 static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
112 				       const struct drm_encoder *encoder,
113 				       bool enabled)
114 {
115 	if (enabled) {
116 		u8 val;
117 
118 		regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
119 				   SUN4I_TCON0_LVDS_IF_EN,
120 				   SUN4I_TCON0_LVDS_IF_EN);
121 
122 		/*
123 		 * As their name suggest, these values only apply to the A31
124 		 * and later SoCs. We'll have to rework this when merging
125 		 * support for the older SoCs.
126 		 */
127 		regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
128 			     SUN6I_TCON0_LVDS_ANA0_C(2) |
129 			     SUN6I_TCON0_LVDS_ANA0_V(3) |
130 			     SUN6I_TCON0_LVDS_ANA0_PD(2) |
131 			     SUN6I_TCON0_LVDS_ANA0_EN_LDO);
132 		udelay(2);
133 
134 		regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
135 				   SUN6I_TCON0_LVDS_ANA0_EN_MB,
136 				   SUN6I_TCON0_LVDS_ANA0_EN_MB);
137 		udelay(2);
138 
139 		regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
140 				   SUN6I_TCON0_LVDS_ANA0_EN_DRVC,
141 				   SUN6I_TCON0_LVDS_ANA0_EN_DRVC);
142 
143 		if (sun4i_tcon_get_pixel_depth(encoder) == 18)
144 			val = 7;
145 		else
146 			val = 0xf;
147 
148 		regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
149 				  SUN6I_TCON0_LVDS_ANA0_EN_DRVD(0xf),
150 				  SUN6I_TCON0_LVDS_ANA0_EN_DRVD(val));
151 	} else {
152 		regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
153 				   SUN4I_TCON0_LVDS_IF_EN, 0);
154 	}
155 }
156 
157 void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
158 			   const struct drm_encoder *encoder,
159 			   bool enabled)
160 {
161 	bool is_lvds = false;
162 	int channel;
163 
164 	switch (encoder->encoder_type) {
165 	case DRM_MODE_ENCODER_LVDS:
166 		is_lvds = true;
167 		/* Fallthrough */
168 	case DRM_MODE_ENCODER_NONE:
169 		channel = 0;
170 		break;
171 	case DRM_MODE_ENCODER_TMDS:
172 	case DRM_MODE_ENCODER_TVDAC:
173 		channel = 1;
174 		break;
175 	default:
176 		DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
177 		return;
178 	}
179 
180 	if (is_lvds && !enabled)
181 		sun4i_tcon_lvds_set_status(tcon, encoder, false);
182 
183 	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
184 			   SUN4I_TCON_GCTL_TCON_ENABLE,
185 			   enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
186 
187 	if (is_lvds && enabled)
188 		sun4i_tcon_lvds_set_status(tcon, encoder, true);
189 
190 	sun4i_tcon_channel_set_status(tcon, channel, enabled);
191 }
192 
193 void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
194 {
195 	u32 mask, val = 0;
196 
197 	DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
198 
199 	mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
200 	       SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
201 
202 	if (enable)
203 		val = mask;
204 
205 	regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val);
206 }
207 EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
208 
209 /*
210  * This function is a helper for TCON output muxing. The TCON output
211  * muxing control register in earlier SoCs (without the TCON TOP block)
212  * are located in TCON0. This helper returns a pointer to TCON0's
213  * sun4i_tcon structure, or NULL if not found.
214  */
215 static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)
216 {
217 	struct sun4i_drv *drv = drm->dev_private;
218 	struct sun4i_tcon *tcon;
219 
220 	list_for_each_entry(tcon, &drv->tcon_list, list)
221 		if (tcon->id == 0)
222 			return tcon;
223 
224 	dev_warn(drm->dev,
225 		 "TCON0 not found, display output muxing may not work\n");
226 
227 	return NULL;
228 }
229 
230 void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
231 			const struct drm_encoder *encoder)
232 {
233 	int ret = -ENOTSUPP;
234 
235 	if (tcon->quirks->set_mux)
236 		ret = tcon->quirks->set_mux(tcon, encoder);
237 
238 	DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s: %d\n",
239 			 encoder->name, encoder->crtc->name, ret);
240 }
241 
242 static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode,
243 				    int channel)
244 {
245 	int delay = mode->vtotal - mode->vdisplay;
246 
247 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
248 		delay /= 2;
249 
250 	if (channel == 1)
251 		delay -= 2;
252 
253 	delay = min(delay, 30);
254 
255 	DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay);
256 
257 	return delay;
258 }
259 
260 static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
261 					const struct drm_display_mode *mode)
262 {
263 	/* Configure the dot clock */
264 	clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
265 
266 	/* Set the resolution */
267 	regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
268 		     SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
269 		     SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
270 }
271 
272 static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
273 				      const struct drm_encoder *encoder,
274 				      const struct drm_display_mode *mode)
275 {
276 	unsigned int bp;
277 	u8 clk_delay;
278 	u32 reg, val = 0;
279 
280 	WARN_ON(!tcon->quirks->has_channel_0);
281 
282 	tcon->dclk_min_div = 7;
283 	tcon->dclk_max_div = 7;
284 	sun4i_tcon0_mode_set_common(tcon, mode);
285 
286 	/* Adjust clock delay */
287 	clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
288 	regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
289 			   SUN4I_TCON0_CTL_CLK_DELAY_MASK,
290 			   SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
291 
292 	/*
293 	 * This is called a backporch in the register documentation,
294 	 * but it really is the back porch + hsync
295 	 */
296 	bp = mode->crtc_htotal - mode->crtc_hsync_start;
297 	DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
298 			 mode->crtc_htotal, bp);
299 
300 	/* Set horizontal display timings */
301 	regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
302 		     SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) |
303 		     SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
304 
305 	/*
306 	 * This is called a backporch in the register documentation,
307 	 * but it really is the back porch + hsync
308 	 */
309 	bp = mode->crtc_vtotal - mode->crtc_vsync_start;
310 	DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
311 			 mode->crtc_vtotal, bp);
312 
313 	/* Set vertical display timings */
314 	regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
315 		     SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
316 		     SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
317 
318 	reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 |
319 		SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL |
320 		SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL;
321 	if (sun4i_tcon_get_pixel_depth(encoder) == 24)
322 		reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS;
323 	else
324 		reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS;
325 
326 	regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg);
327 
328 	/* Setup the polarity of the various signals */
329 	if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
330 		val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
331 
332 	if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
333 		val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
334 
335 	regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
336 
337 	/* Map output pins to channel 0 */
338 	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
339 			   SUN4I_TCON_GCTL_IOMAP_MASK,
340 			   SUN4I_TCON_GCTL_IOMAP_TCON0);
341 }
342 
343 static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
344 				     const struct drm_display_mode *mode)
345 {
346 	unsigned int bp, hsync, vsync;
347 	u8 clk_delay;
348 	u32 val = 0;
349 
350 	WARN_ON(!tcon->quirks->has_channel_0);
351 
352 	tcon->dclk_min_div = 6;
353 	tcon->dclk_max_div = 127;
354 	sun4i_tcon0_mode_set_common(tcon, mode);
355 
356 	/* Adjust clock delay */
357 	clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
358 	regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
359 			   SUN4I_TCON0_CTL_CLK_DELAY_MASK,
360 			   SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
361 
362 	/*
363 	 * This is called a backporch in the register documentation,
364 	 * but it really is the back porch + hsync
365 	 */
366 	bp = mode->crtc_htotal - mode->crtc_hsync_start;
367 	DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
368 			 mode->crtc_htotal, bp);
369 
370 	/* Set horizontal display timings */
371 	regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
372 		     SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) |
373 		     SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
374 
375 	/*
376 	 * This is called a backporch in the register documentation,
377 	 * but it really is the back porch + hsync
378 	 */
379 	bp = mode->crtc_vtotal - mode->crtc_vsync_start;
380 	DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
381 			 mode->crtc_vtotal, bp);
382 
383 	/* Set vertical display timings */
384 	regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
385 		     SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
386 		     SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
387 
388 	/* Set Hsync and Vsync length */
389 	hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
390 	vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
391 	DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
392 	regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG,
393 		     SUN4I_TCON0_BASIC3_V_SYNC(vsync) |
394 		     SUN4I_TCON0_BASIC3_H_SYNC(hsync));
395 
396 	/* Setup the polarity of the various signals */
397 	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
398 		val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
399 
400 	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
401 		val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
402 
403 	regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
404 			   SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE,
405 			   val);
406 
407 	/* Map output pins to channel 0 */
408 	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
409 			   SUN4I_TCON_GCTL_IOMAP_MASK,
410 			   SUN4I_TCON_GCTL_IOMAP_TCON0);
411 
412 	/* Enable the output on the pins */
413 	regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
414 }
415 
416 static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
417 				 const struct drm_display_mode *mode)
418 {
419 	unsigned int bp, hsync, vsync, vtotal;
420 	u8 clk_delay;
421 	u32 val;
422 
423 	WARN_ON(!tcon->quirks->has_channel_1);
424 
425 	/* Configure the dot clock */
426 	clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
427 
428 	/* Adjust clock delay */
429 	clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
430 	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
431 			   SUN4I_TCON1_CTL_CLK_DELAY_MASK,
432 			   SUN4I_TCON1_CTL_CLK_DELAY(clk_delay));
433 
434 	/* Set interlaced mode */
435 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
436 		val = SUN4I_TCON1_CTL_INTERLACE_ENABLE;
437 	else
438 		val = 0;
439 	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
440 			   SUN4I_TCON1_CTL_INTERLACE_ENABLE,
441 			   val);
442 
443 	/* Set the input resolution */
444 	regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
445 		     SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
446 		     SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
447 
448 	/* Set the upscaling resolution */
449 	regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
450 		     SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
451 		     SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
452 
453 	/* Set the output resolution */
454 	regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
455 		     SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
456 		     SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
457 
458 	/* Set horizontal display timings */
459 	bp = mode->crtc_htotal - mode->crtc_hsync_start;
460 	DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
461 			 mode->htotal, bp);
462 	regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
463 		     SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
464 		     SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
465 
466 	bp = mode->crtc_vtotal - mode->crtc_vsync_start;
467 	DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
468 			 mode->crtc_vtotal, bp);
469 
470 	/*
471 	 * The vertical resolution needs to be doubled in all
472 	 * cases. We could use crtc_vtotal and always multiply by two,
473 	 * but that leads to a rounding error in interlace when vtotal
474 	 * is odd.
475 	 *
476 	 * This happens with TV's PAL for example, where vtotal will
477 	 * be 625, crtc_vtotal 312, and thus crtc_vtotal * 2 will be
478 	 * 624, which apparently confuses the hardware.
479 	 *
480 	 * To work around this, we will always use vtotal, and
481 	 * multiply by two only if we're not in interlace.
482 	 */
483 	vtotal = mode->vtotal;
484 	if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
485 		vtotal = vtotal * 2;
486 
487 	/* Set vertical display timings */
488 	regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG,
489 		     SUN4I_TCON1_BASIC4_V_TOTAL(vtotal) |
490 		     SUN4I_TCON1_BASIC4_V_BACKPORCH(bp));
491 
492 	/* Set Hsync and Vsync length */
493 	hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
494 	vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
495 	DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
496 	regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG,
497 		     SUN4I_TCON1_BASIC5_V_SYNC(vsync) |
498 		     SUN4I_TCON1_BASIC5_H_SYNC(hsync));
499 
500 	/* Map output pins to channel 1 */
501 	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
502 			   SUN4I_TCON_GCTL_IOMAP_MASK,
503 			   SUN4I_TCON_GCTL_IOMAP_TCON1);
504 }
505 
506 void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
507 			 const struct drm_encoder *encoder,
508 			 const struct drm_display_mode *mode)
509 {
510 	switch (encoder->encoder_type) {
511 	case DRM_MODE_ENCODER_LVDS:
512 		sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
513 		break;
514 	case DRM_MODE_ENCODER_NONE:
515 		sun4i_tcon0_mode_set_rgb(tcon, mode);
516 		sun4i_tcon_set_mux(tcon, 0, encoder);
517 		break;
518 	case DRM_MODE_ENCODER_TVDAC:
519 	case DRM_MODE_ENCODER_TMDS:
520 		sun4i_tcon1_mode_set(tcon, mode);
521 		sun4i_tcon_set_mux(tcon, 1, encoder);
522 		break;
523 	default:
524 		DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
525 	}
526 }
527 EXPORT_SYMBOL(sun4i_tcon_mode_set);
528 
529 static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
530 					struct sun4i_crtc *scrtc)
531 {
532 	unsigned long flags;
533 
534 	spin_lock_irqsave(&dev->event_lock, flags);
535 	if (scrtc->event) {
536 		drm_crtc_send_vblank_event(&scrtc->crtc, scrtc->event);
537 		drm_crtc_vblank_put(&scrtc->crtc);
538 		scrtc->event = NULL;
539 	}
540 	spin_unlock_irqrestore(&dev->event_lock, flags);
541 }
542 
543 static irqreturn_t sun4i_tcon_handler(int irq, void *private)
544 {
545 	struct sun4i_tcon *tcon = private;
546 	struct drm_device *drm = tcon->drm;
547 	struct sun4i_crtc *scrtc = tcon->crtc;
548 	struct sunxi_engine *engine = scrtc->engine;
549 	unsigned int status;
550 
551 	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
552 
553 	if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
554 			SUN4I_TCON_GINT0_VBLANK_INT(1))))
555 		return IRQ_NONE;
556 
557 	drm_crtc_handle_vblank(&scrtc->crtc);
558 	sun4i_tcon_finish_page_flip(drm, scrtc);
559 
560 	/* Acknowledge the interrupt */
561 	regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
562 			   SUN4I_TCON_GINT0_VBLANK_INT(0) |
563 			   SUN4I_TCON_GINT0_VBLANK_INT(1),
564 			   0);
565 
566 	if (engine->ops->vblank_quirk)
567 		engine->ops->vblank_quirk(engine);
568 
569 	return IRQ_HANDLED;
570 }
571 
572 static int sun4i_tcon_init_clocks(struct device *dev,
573 				  struct sun4i_tcon *tcon)
574 {
575 	tcon->clk = devm_clk_get(dev, "ahb");
576 	if (IS_ERR(tcon->clk)) {
577 		dev_err(dev, "Couldn't get the TCON bus clock\n");
578 		return PTR_ERR(tcon->clk);
579 	}
580 	clk_prepare_enable(tcon->clk);
581 
582 	if (tcon->quirks->has_channel_0) {
583 		tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
584 		if (IS_ERR(tcon->sclk0)) {
585 			dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
586 			return PTR_ERR(tcon->sclk0);
587 		}
588 	}
589 
590 	if (tcon->quirks->has_channel_1) {
591 		tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
592 		if (IS_ERR(tcon->sclk1)) {
593 			dev_err(dev, "Couldn't get the TCON channel 1 clock\n");
594 			return PTR_ERR(tcon->sclk1);
595 		}
596 	}
597 
598 	return 0;
599 }
600 
601 static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
602 {
603 	clk_disable_unprepare(tcon->clk);
604 }
605 
606 static int sun4i_tcon_init_irq(struct device *dev,
607 			       struct sun4i_tcon *tcon)
608 {
609 	struct platform_device *pdev = to_platform_device(dev);
610 	int irq, ret;
611 
612 	irq = platform_get_irq(pdev, 0);
613 	if (irq < 0) {
614 		dev_err(dev, "Couldn't retrieve the TCON interrupt\n");
615 		return irq;
616 	}
617 
618 	ret = devm_request_irq(dev, irq, sun4i_tcon_handler, 0,
619 			       dev_name(dev), tcon);
620 	if (ret) {
621 		dev_err(dev, "Couldn't request the IRQ\n");
622 		return ret;
623 	}
624 
625 	return 0;
626 }
627 
628 static struct regmap_config sun4i_tcon_regmap_config = {
629 	.reg_bits	= 32,
630 	.val_bits	= 32,
631 	.reg_stride	= 4,
632 	.max_register	= 0x800,
633 };
634 
635 static int sun4i_tcon_init_regmap(struct device *dev,
636 				  struct sun4i_tcon *tcon)
637 {
638 	struct platform_device *pdev = to_platform_device(dev);
639 	struct resource *res;
640 	void __iomem *regs;
641 
642 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
643 	regs = devm_ioremap_resource(dev, res);
644 	if (IS_ERR(regs))
645 		return PTR_ERR(regs);
646 
647 	tcon->regs = devm_regmap_init_mmio(dev, regs,
648 					   &sun4i_tcon_regmap_config);
649 	if (IS_ERR(tcon->regs)) {
650 		dev_err(dev, "Couldn't create the TCON regmap\n");
651 		return PTR_ERR(tcon->regs);
652 	}
653 
654 	/* Make sure the TCON is disabled and all IRQs are off */
655 	regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0);
656 	regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0);
657 	regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0);
658 
659 	/* Disable IO lines and set them to tristate */
660 	regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0);
661 	regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0);
662 
663 	return 0;
664 }
665 
666 /*
667  * On SoCs with the old display pipeline design (Display Engine 1.0),
668  * the TCON is always tied to just one backend. Hence we can traverse
669  * the of_graph upwards to find the backend our tcon is connected to,
670  * and take its ID as our own.
671  *
672  * We can either identify backends from their compatible strings, which
673  * means maintaining a large list of them. Or, since the backend is
674  * registered and binded before the TCON, we can just go through the
675  * list of registered backends and compare the device node.
676  *
677  * As the structures now store engines instead of backends, here this
678  * function in fact searches the corresponding engine, and the ID is
679  * requested via the get_id function of the engine.
680  */
681 static struct sunxi_engine *
682 sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv,
683 				struct device_node *node)
684 {
685 	struct device_node *port, *ep, *remote;
686 	struct sunxi_engine *engine = ERR_PTR(-EINVAL);
687 
688 	port = of_graph_get_port_by_id(node, 0);
689 	if (!port)
690 		return ERR_PTR(-EINVAL);
691 
692 	/*
693 	 * This only works if there is only one path from the TCON
694 	 * to any display engine. Otherwise the probe order of the
695 	 * TCONs and display engines is not guaranteed. They may
696 	 * either bind to the wrong one, or worse, bind to the same
697 	 * one if additional checks are not done.
698 	 *
699 	 * Bail out if there are multiple input connections.
700 	 */
701 	if (of_get_available_child_count(port) != 1)
702 		goto out_put_port;
703 
704 	/* Get the first connection without specifying an ID */
705 	ep = of_get_next_available_child(port, NULL);
706 	if (!ep)
707 		goto out_put_port;
708 
709 	remote = of_graph_get_remote_port_parent(ep);
710 	if (!remote)
711 		goto out_put_ep;
712 
713 	/* does this node match any registered engines? */
714 	list_for_each_entry(engine, &drv->engine_list, list)
715 		if (remote == engine->node)
716 			goto out_put_remote;
717 
718 	/* keep looking through upstream ports */
719 	engine = sun4i_tcon_find_engine_traverse(drv, remote);
720 
721 out_put_remote:
722 	of_node_put(remote);
723 out_put_ep:
724 	of_node_put(ep);
725 out_put_port:
726 	of_node_put(port);
727 
728 	return engine;
729 }
730 
731 /*
732  * The device tree binding says that the remote endpoint ID of any
733  * connection between components, up to and including the TCON, of
734  * the display pipeline should be equal to the actual ID of the local
735  * component. Thus we can look at any one of the input connections of
736  * the TCONs, and use that connection's remote endpoint ID as our own.
737  *
738  * Since the user of this function already finds the input port,
739  * the port is passed in directly without further checks.
740  */
741 static int sun4i_tcon_of_get_id_from_port(struct device_node *port)
742 {
743 	struct device_node *ep;
744 	int ret = -EINVAL;
745 
746 	/* try finding an upstream endpoint */
747 	for_each_available_child_of_node(port, ep) {
748 		struct device_node *remote;
749 		u32 reg;
750 
751 		remote = of_graph_get_remote_endpoint(ep);
752 		if (!remote)
753 			continue;
754 
755 		ret = of_property_read_u32(remote, "reg", &reg);
756 		if (ret)
757 			continue;
758 
759 		ret = reg;
760 	}
761 
762 	return ret;
763 }
764 
765 /*
766  * Once we know the TCON's id, we can look through the list of
767  * engines to find a matching one. We assume all engines have
768  * been probed and added to the list.
769  */
770 static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv,
771 							int id)
772 {
773 	struct sunxi_engine *engine;
774 
775 	list_for_each_entry(engine, &drv->engine_list, list)
776 		if (engine->id == id)
777 			return engine;
778 
779 	return ERR_PTR(-EINVAL);
780 }
781 
782 /*
783  * On SoCs with the old display pipeline design (Display Engine 1.0),
784  * we assumed the TCON was always tied to just one backend. However
785  * this proved not to be the case. On the A31, the TCON can select
786  * either backend as its source. On the A20 (and likely on the A10),
787  * the backend can choose which TCON to output to.
788  *
789  * The device tree binding says that the remote endpoint ID of any
790  * connection between components, up to and including the TCON, of
791  * the display pipeline should be equal to the actual ID of the local
792  * component. Thus we should be able to look at any one of the input
793  * connections of the TCONs, and use that connection's remote endpoint
794  * ID as our own.
795  *
796  * However  the connections between the backend and TCON were assumed
797  * to be always singular, and their endpoit IDs were all incorrectly
798  * set to 0. This means for these old device trees, we cannot just look
799  * up the remote endpoint ID of a TCON input endpoint. TCON1 would be
800  * incorrectly identified as TCON0.
801  *
802  * This function first checks if the TCON node has 2 input endpoints.
803  * If so, then the device tree is a corrected version, and it will use
804  * sun4i_tcon_of_get_id() and sun4i_tcon_get_engine_by_id() from above
805  * to fetch the ID and engine directly. If not, then it is likely an
806  * old device trees, where the endpoint IDs were incorrect, but did not
807  * have endpoint connections between the backend and TCON across
808  * different display pipelines. It will fall back to the old method of
809  * traversing the  of_graph to try and find a matching engine by device
810  * node.
811  *
812  * In the case of single display pipeline device trees, either method
813  * works.
814  */
815 static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
816 						   struct device_node *node)
817 {
818 	struct device_node *port;
819 	struct sunxi_engine *engine;
820 
821 	port = of_graph_get_port_by_id(node, 0);
822 	if (!port)
823 		return ERR_PTR(-EINVAL);
824 
825 	/*
826 	 * Is this a corrected device tree with cross pipeline
827 	 * connections between the backend and TCON?
828 	 */
829 	if (of_get_child_count(port) > 1) {
830 		/* Get our ID directly from an upstream endpoint */
831 		int id = sun4i_tcon_of_get_id_from_port(port);
832 
833 		/* Get our engine by matching our ID */
834 		engine = sun4i_tcon_get_engine_by_id(drv, id);
835 
836 		of_node_put(port);
837 		return engine;
838 	}
839 
840 	/* Fallback to old method by traversing input endpoints */
841 	of_node_put(port);
842 	return sun4i_tcon_find_engine_traverse(drv, node);
843 }
844 
845 static int sun4i_tcon_bind(struct device *dev, struct device *master,
846 			   void *data)
847 {
848 	struct drm_device *drm = data;
849 	struct sun4i_drv *drv = drm->dev_private;
850 	struct sunxi_engine *engine;
851 	struct device_node *remote;
852 	struct sun4i_tcon *tcon;
853 	bool has_lvds_rst, has_lvds_alt, can_lvds;
854 	int ret;
855 
856 	engine = sun4i_tcon_find_engine(drv, dev->of_node);
857 	if (IS_ERR(engine)) {
858 		dev_err(dev, "Couldn't find matching engine\n");
859 		return -EPROBE_DEFER;
860 	}
861 
862 	tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
863 	if (!tcon)
864 		return -ENOMEM;
865 	dev_set_drvdata(dev, tcon);
866 	tcon->drm = drm;
867 	tcon->dev = dev;
868 	tcon->id = engine->id;
869 	tcon->quirks = of_device_get_match_data(dev);
870 
871 	tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
872 	if (IS_ERR(tcon->lcd_rst)) {
873 		dev_err(dev, "Couldn't get our reset line\n");
874 		return PTR_ERR(tcon->lcd_rst);
875 	}
876 
877 	/* Make sure our TCON is reset */
878 	ret = reset_control_reset(tcon->lcd_rst);
879 	if (ret) {
880 		dev_err(dev, "Couldn't deassert our reset line\n");
881 		return ret;
882 	}
883 
884 	/*
885 	 * This can only be made optional since we've had DT nodes
886 	 * without the LVDS reset properties.
887 	 *
888 	 * If the property is missing, just disable LVDS, and print a
889 	 * warning.
890 	 */
891 	tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
892 	if (IS_ERR(tcon->lvds_rst)) {
893 		dev_err(dev, "Couldn't get our reset line\n");
894 		return PTR_ERR(tcon->lvds_rst);
895 	} else if (tcon->lvds_rst) {
896 		has_lvds_rst = true;
897 		reset_control_reset(tcon->lvds_rst);
898 	} else {
899 		has_lvds_rst = false;
900 	}
901 
902 	/*
903 	 * This can only be made optional since we've had DT nodes
904 	 * without the LVDS reset properties.
905 	 *
906 	 * If the property is missing, just disable LVDS, and print a
907 	 * warning.
908 	 */
909 	if (tcon->quirks->has_lvds_alt) {
910 		tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");
911 		if (IS_ERR(tcon->lvds_pll)) {
912 			if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
913 				has_lvds_alt = false;
914 			} else {
915 				dev_err(dev, "Couldn't get the LVDS PLL\n");
916 				return PTR_ERR(tcon->lvds_pll);
917 			}
918 		} else {
919 			has_lvds_alt = true;
920 		}
921 	}
922 
923 	if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {
924 		dev_warn(dev,
925 			 "Missing LVDS properties, Please upgrade your DT\n");
926 		dev_warn(dev, "LVDS output disabled\n");
927 		can_lvds = false;
928 	} else {
929 		can_lvds = true;
930 	}
931 
932 	ret = sun4i_tcon_init_clocks(dev, tcon);
933 	if (ret) {
934 		dev_err(dev, "Couldn't init our TCON clocks\n");
935 		goto err_assert_reset;
936 	}
937 
938 	ret = sun4i_tcon_init_regmap(dev, tcon);
939 	if (ret) {
940 		dev_err(dev, "Couldn't init our TCON regmap\n");
941 		goto err_free_clocks;
942 	}
943 
944 	if (tcon->quirks->has_channel_0) {
945 		ret = sun4i_dclk_create(dev, tcon);
946 		if (ret) {
947 			dev_err(dev, "Couldn't create our TCON dot clock\n");
948 			goto err_free_clocks;
949 		}
950 	}
951 
952 	ret = sun4i_tcon_init_irq(dev, tcon);
953 	if (ret) {
954 		dev_err(dev, "Couldn't init our TCON interrupts\n");
955 		goto err_free_dotclock;
956 	}
957 
958 	tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
959 	if (IS_ERR(tcon->crtc)) {
960 		dev_err(dev, "Couldn't create our CRTC\n");
961 		ret = PTR_ERR(tcon->crtc);
962 		goto err_free_dotclock;
963 	}
964 
965 	/*
966 	 * If we have an LVDS panel connected to the TCON, we should
967 	 * just probe the LVDS connector. Otherwise, just probe RGB as
968 	 * we used to.
969 	 */
970 	remote = of_graph_get_remote_node(dev->of_node, 1, 0);
971 	if (of_device_is_compatible(remote, "panel-lvds"))
972 		if (can_lvds)
973 			ret = sun4i_lvds_init(drm, tcon);
974 		else
975 			ret = -EINVAL;
976 	else
977 		ret = sun4i_rgb_init(drm, tcon);
978 	of_node_put(remote);
979 
980 	if (ret < 0)
981 		goto err_free_dotclock;
982 
983 	if (tcon->quirks->needs_de_be_mux) {
984 		/*
985 		 * We assume there is no dynamic muxing of backends
986 		 * and TCONs, so we select the backend with same ID.
987 		 *
988 		 * While dynamic selection might be interesting, since
989 		 * the CRTC is tied to the TCON, while the layers are
990 		 * tied to the backends, this means, we will need to
991 		 * switch between groups of layers. There might not be
992 		 * a way to represent this constraint in DRM.
993 		 */
994 		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
995 				   SUN4I_TCON0_CTL_SRC_SEL_MASK,
996 				   tcon->id);
997 		regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
998 				   SUN4I_TCON1_CTL_SRC_SEL_MASK,
999 				   tcon->id);
1000 	}
1001 
1002 	list_add_tail(&tcon->list, &drv->tcon_list);
1003 
1004 	return 0;
1005 
1006 err_free_dotclock:
1007 	if (tcon->quirks->has_channel_0)
1008 		sun4i_dclk_free(tcon);
1009 err_free_clocks:
1010 	sun4i_tcon_free_clocks(tcon);
1011 err_assert_reset:
1012 	reset_control_assert(tcon->lcd_rst);
1013 	return ret;
1014 }
1015 
1016 static void sun4i_tcon_unbind(struct device *dev, struct device *master,
1017 			      void *data)
1018 {
1019 	struct sun4i_tcon *tcon = dev_get_drvdata(dev);
1020 
1021 	list_del(&tcon->list);
1022 	if (tcon->quirks->has_channel_0)
1023 		sun4i_dclk_free(tcon);
1024 	sun4i_tcon_free_clocks(tcon);
1025 }
1026 
1027 static const struct component_ops sun4i_tcon_ops = {
1028 	.bind	= sun4i_tcon_bind,
1029 	.unbind	= sun4i_tcon_unbind,
1030 };
1031 
1032 static int sun4i_tcon_probe(struct platform_device *pdev)
1033 {
1034 	struct device_node *node = pdev->dev.of_node;
1035 	struct drm_bridge *bridge;
1036 	struct drm_panel *panel;
1037 	int ret;
1038 
1039 	ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
1040 	if (ret == -EPROBE_DEFER)
1041 		return ret;
1042 
1043 	return component_add(&pdev->dev, &sun4i_tcon_ops);
1044 }
1045 
1046 static int sun4i_tcon_remove(struct platform_device *pdev)
1047 {
1048 	component_del(&pdev->dev, &sun4i_tcon_ops);
1049 
1050 	return 0;
1051 }
1052 
1053 /* platform specific TCON muxing callbacks */
1054 static int sun4i_a10_tcon_set_mux(struct sun4i_tcon *tcon,
1055 				  const struct drm_encoder *encoder)
1056 {
1057 	struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
1058 	u32 shift;
1059 
1060 	if (!tcon0)
1061 		return -EINVAL;
1062 
1063 	switch (encoder->encoder_type) {
1064 	case DRM_MODE_ENCODER_TMDS:
1065 		/* HDMI */
1066 		shift = 8;
1067 		break;
1068 	default:
1069 		return -EINVAL;
1070 	}
1071 
1072 	regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
1073 			   0x3 << shift, tcon->id << shift);
1074 
1075 	return 0;
1076 }
1077 
1078 static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon,
1079 				  const struct drm_encoder *encoder)
1080 {
1081 	u32 val;
1082 
1083 	if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1084 		val = 1;
1085 	else
1086 		val = 0;
1087 
1088 	/*
1089 	 * FIXME: Undocumented bits
1090 	 */
1091 	return regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
1092 }
1093 
1094 static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
1095 			      const struct drm_encoder *encoder)
1096 {
1097 	struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
1098 	u32 shift;
1099 
1100 	if (!tcon0)
1101 		return -EINVAL;
1102 
1103 	switch (encoder->encoder_type) {
1104 	case DRM_MODE_ENCODER_TMDS:
1105 		/* HDMI */
1106 		shift = 8;
1107 		break;
1108 	default:
1109 		/* TODO A31 has MIPI DSI but A31s does not */
1110 		return -EINVAL;
1111 	}
1112 
1113 	regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
1114 			   0x3 << shift, tcon->id << shift);
1115 
1116 	return 0;
1117 }
1118 
1119 static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
1120 	.has_channel_0		= true,
1121 	.has_channel_1		= true,
1122 	.set_mux		= sun4i_a10_tcon_set_mux,
1123 };
1124 
1125 static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
1126 	.has_channel_0		= true,
1127 	.has_channel_1		= true,
1128 	.set_mux		= sun5i_a13_tcon_set_mux,
1129 };
1130 
1131 static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
1132 	.has_channel_0		= true,
1133 	.has_channel_1		= true,
1134 	.has_lvds_alt		= true,
1135 	.needs_de_be_mux	= true,
1136 	.set_mux		= sun6i_tcon_set_mux,
1137 };
1138 
1139 static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
1140 	.has_channel_0		= true,
1141 	.has_channel_1		= true,
1142 	.needs_de_be_mux	= true,
1143 };
1144 
1145 static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
1146 	.has_channel_0		= true,
1147 	.has_channel_1		= true,
1148 	/* Same display pipeline structure as A10 */
1149 	.set_mux		= sun4i_a10_tcon_set_mux,
1150 };
1151 
1152 static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
1153 	.has_channel_0		= true,
1154 	.has_lvds_alt		= true,
1155 };
1156 
1157 static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
1158 	.has_channel_0		= true,
1159 };
1160 
1161 static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
1162 	.has_channel_1		= true,
1163 };
1164 
1165 static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
1166 	.has_channel_0		= true,
1167 };
1168 
1169 /* sun4i_drv uses this list to check if a device node is a TCON */
1170 const struct of_device_id sun4i_tcon_of_table[] = {
1171 	{ .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
1172 	{ .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
1173 	{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
1174 	{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
1175 	{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
1176 	{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
1177 	{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
1178 	{ .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
1179 	{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
1180 	{ }
1181 };
1182 MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
1183 EXPORT_SYMBOL(sun4i_tcon_of_table);
1184 
1185 static struct platform_driver sun4i_tcon_platform_driver = {
1186 	.probe		= sun4i_tcon_probe,
1187 	.remove		= sun4i_tcon_remove,
1188 	.driver		= {
1189 		.name		= "sun4i-tcon",
1190 		.of_match_table	= sun4i_tcon_of_table,
1191 	},
1192 };
1193 module_platform_driver(sun4i_tcon_platform_driver);
1194 
1195 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1196 MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver");
1197 MODULE_LICENSE("GPL");
1198