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