1 /*
2  * Display driver for Allwinner SoCs.
3  *
4  * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
5  * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
6  *
7  * SPDX-License-Identifier:	GPL-2.0+
8  */
9 
10 #include <common.h>
11 
12 #include <asm/arch/clock.h>
13 #include <asm/arch/display.h>
14 #include <asm/arch/gpio.h>
15 #include <asm/arch/lcdc.h>
16 #include <asm/arch/pwm.h>
17 #include <asm/arch/tve.h>
18 #include <asm/global_data.h>
19 #include <asm/gpio.h>
20 #include <asm/io.h>
21 #include <axp_pmic.h>
22 #include <errno.h>
23 #include <fdtdec.h>
24 #include <fdt_support.h>
25 #include <i2c.h>
26 #include <malloc.h>
27 #include <video_fb.h>
28 #include "../videomodes.h"
29 #include "../anx9804.h"
30 #include "../hitachi_tx18d42vm_lcd.h"
31 #include "../ssd2828.h"
32 #include "simplefb_common.h"
33 
34 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
35 #define PWM_ON 0
36 #define PWM_OFF 1
37 #else
38 #define PWM_ON 1
39 #define PWM_OFF 0
40 #endif
41 
42 DECLARE_GLOBAL_DATA_PTR;
43 
44 enum sunxi_monitor {
45 	sunxi_monitor_none,
46 	sunxi_monitor_dvi,
47 	sunxi_monitor_hdmi,
48 	sunxi_monitor_lcd,
49 	sunxi_monitor_vga,
50 	sunxi_monitor_composite_pal,
51 	sunxi_monitor_composite_ntsc,
52 	sunxi_monitor_composite_pal_m,
53 	sunxi_monitor_composite_pal_nc,
54 };
55 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
56 
57 struct sunxi_display {
58 	GraphicDevice graphic_device;
59 	enum sunxi_monitor monitor;
60 	unsigned int depth;
61 	unsigned int fb_addr;
62 	unsigned int fb_size;
63 } sunxi_display;
64 
65 const struct ctfb_res_modes composite_video_modes[2] = {
66 	/*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
67 	{ 720,  576, 50, 37037,  27000, 137,   5, 20, 27,   2, 2, 0, FB_VMODE_INTERLACED },
68 	{ 720,  480, 60, 37037,  27000, 116,  20, 16, 27,   2, 2, 0, FB_VMODE_INTERLACED },
69 };
70 
71 #ifdef CONFIG_VIDEO_HDMI
72 
73 /*
74  * Wait up to 200ms for value to be set in given part of reg.
75  */
76 static int await_completion(u32 *reg, u32 mask, u32 val)
77 {
78 	unsigned long tmo = timer_get_us() + 200000;
79 
80 	while ((readl(reg) & mask) != val) {
81 		if (timer_get_us() > tmo) {
82 			printf("DDC: timeout reading EDID\n");
83 			return -ETIME;
84 		}
85 	}
86 	return 0;
87 }
88 
89 static int sunxi_hdmi_hpd_detect(int hpd_delay)
90 {
91 	struct sunxi_ccm_reg * const ccm =
92 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
93 	struct sunxi_hdmi_reg * const hdmi =
94 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
95 	unsigned long tmo = timer_get_us() + hpd_delay * 1000;
96 
97 	/* Set pll3 to 300MHz */
98 	clock_set_pll3(300000000);
99 
100 	/* Set hdmi parent to pll3 */
101 	clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
102 			CCM_HDMI_CTRL_PLL3);
103 
104 	/* Set ahb gating to pass */
105 #ifdef CONFIG_SUNXI_GEN_SUN6I
106 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
107 #endif
108 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
109 
110 	/* Clock on */
111 	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
112 
113 	writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
114 	writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
115 
116 	while (timer_get_us() < tmo) {
117 		if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
118 			return 1;
119 	}
120 
121 	return 0;
122 }
123 
124 static void sunxi_hdmi_shutdown(void)
125 {
126 	struct sunxi_ccm_reg * const ccm =
127 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
128 	struct sunxi_hdmi_reg * const hdmi =
129 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
130 
131 	clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
132 	clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
133 	clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
134 #ifdef CONFIG_SUNXI_GEN_SUN6I
135 	clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
136 #endif
137 	clock_set_pll3(0);
138 }
139 
140 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
141 {
142 	struct sunxi_hdmi_reg * const hdmi =
143 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
144 
145 	setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
146 	writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
147 	       SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
148 	       SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
149 	       SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
150 #ifndef CONFIG_MACH_SUN6I
151 	writel(n, &hdmi->ddc_byte_count);
152 	writel(cmnd, &hdmi->ddc_cmnd);
153 #else
154 	writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
155 #endif
156 	setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
157 
158 	return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
159 }
160 
161 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
162 {
163 	struct sunxi_hdmi_reg * const hdmi =
164 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
165 	int i, n;
166 
167 	while (count > 0) {
168 		if (count > 16)
169 			n = 16;
170 		else
171 			n = count;
172 
173 		if (sunxi_hdmi_ddc_do_command(
174 				SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
175 				offset, n))
176 			return -ETIME;
177 
178 		for (i = 0; i < n; i++)
179 			*buf++ = readb(&hdmi->ddc_fifo_data);
180 
181 		offset += n;
182 		count -= n;
183 	}
184 
185 	return 0;
186 }
187 
188 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
189 {
190 	int r, retries = 2;
191 
192 	do {
193 		r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
194 		if (r)
195 			continue;
196 		r = edid_check_checksum(buf);
197 		if (r) {
198 			printf("EDID block %d: checksum error%s\n",
199 			       block, retries ? ", retrying" : "");
200 		}
201 	} while (r && retries--);
202 
203 	return r;
204 }
205 
206 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
207 {
208 	struct edid1_info edid1;
209 	struct edid_cea861_info cea681[4];
210 	struct edid_detailed_timing *t =
211 		(struct edid_detailed_timing *)edid1.monitor_details.timing;
212 	struct sunxi_hdmi_reg * const hdmi =
213 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
214 	struct sunxi_ccm_reg * const ccm =
215 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
216 	int i, r, ext_blocks = 0;
217 
218 	/* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
219 	writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
220 	       &hdmi->pad_ctrl1);
221 	writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
222 	       &hdmi->pll_ctrl);
223 	writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
224 
225 	/* Reset i2c controller */
226 	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
227 	writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
228 	       SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
229 	       SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
230 	       SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
231 	if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
232 		return -EIO;
233 
234 	writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
235 #ifndef CONFIG_MACH_SUN6I
236 	writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
237 	       SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
238 #endif
239 
240 	r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
241 	if (r == 0) {
242 		r = edid_check_info(&edid1);
243 		if (r) {
244 			printf("EDID: invalid EDID data\n");
245 			r = -EINVAL;
246 		}
247 	}
248 	if (r == 0) {
249 		ext_blocks = edid1.extension_flag;
250 		if (ext_blocks > 4)
251 			ext_blocks = 4;
252 		for (i = 0; i < ext_blocks; i++) {
253 			if (sunxi_hdmi_edid_get_block(1 + i,
254 						(u8 *)&cea681[i]) != 0) {
255 				ext_blocks = i;
256 				break;
257 			}
258 		}
259 	}
260 
261 	/* Disable DDC engine, no longer needed */
262 	clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
263 	clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
264 
265 	if (r)
266 		return r;
267 
268 	/* We want version 1.3 or 1.2 with detailed timing info */
269 	if (edid1.version != 1 || (edid1.revision < 3 &&
270 			!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
271 		printf("EDID: unsupported version %d.%d\n",
272 		       edid1.version, edid1.revision);
273 		return -EINVAL;
274 	}
275 
276 	/* Take the first usable detailed timing */
277 	for (i = 0; i < 4; i++, t++) {
278 		r = video_edid_dtd_to_ctfb_res_modes(t, mode);
279 		if (r == 0)
280 			break;
281 	}
282 	if (i == 4) {
283 		printf("EDID: no usable detailed timing found\n");
284 		return -ENOENT;
285 	}
286 
287 	/* Check for basic audio support, if found enable hdmi output */
288 	sunxi_display.monitor = sunxi_monitor_dvi;
289 	for (i = 0; i < ext_blocks; i++) {
290 		if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
291 		    cea681[i].revision < 2)
292 			continue;
293 
294 		if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
295 			sunxi_display.monitor = sunxi_monitor_hdmi;
296 	}
297 
298 	return 0;
299 }
300 
301 #endif /* CONFIG_VIDEO_HDMI */
302 
303 #ifdef CONFIG_MACH_SUN4I
304 /*
305  * Testing has shown that on sun4i the display backend engine does not have
306  * deep enough fifo-s causing flickering / tearing in full-hd mode due to
307  * fifo underruns. So on sun4i we use the display frontend engine to do the
308  * dma from memory, as the frontend does have deep enough fifo-s.
309  */
310 
311 static const u32 sun4i_vert_coef[32] = {
312 	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
313 	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
314 	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
315 	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
316 	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
317 	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
318 	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
319 	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
320 };
321 
322 static const u32 sun4i_horz_coef[64] = {
323 	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
324 	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
325 	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
326 	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
327 	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
328 	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
329 	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
330 	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
331 	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
332 	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
333 	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
334 	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
335 	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
336 	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
337 	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
338 	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
339 };
340 
341 static void sunxi_frontend_init(void)
342 {
343 	struct sunxi_ccm_reg * const ccm =
344 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
345 	struct sunxi_de_fe_reg * const de_fe =
346 		(struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
347 	int i;
348 
349 	/* Clocks on */
350 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
351 	setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
352 	clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
353 
354 	setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
355 
356 	for (i = 0; i < 32; i++) {
357 		writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
358 		writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
359 		writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
360 		writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
361 		writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
362 		writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
363 	}
364 
365 	setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
366 }
367 
368 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
369 				    unsigned int address)
370 {
371 	struct sunxi_de_fe_reg * const de_fe =
372 		(struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
373 
374 	setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
375 	writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
376 	writel(mode->xres * 4, &de_fe->ch0_stride);
377 	writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
378 	writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
379 
380 	writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
381 	       &de_fe->ch0_insize);
382 	writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
383 	       &de_fe->ch0_outsize);
384 	writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
385 	writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
386 
387 	writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
388 	       &de_fe->ch1_insize);
389 	writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
390 	       &de_fe->ch1_outsize);
391 	writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
392 	writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
393 
394 	setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
395 }
396 
397 static void sunxi_frontend_enable(void)
398 {
399 	struct sunxi_de_fe_reg * const de_fe =
400 		(struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
401 
402 	setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
403 }
404 #else
405 static void sunxi_frontend_init(void) {}
406 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
407 				    unsigned int address) {}
408 static void sunxi_frontend_enable(void) {}
409 #endif
410 
411 static bool sunxi_is_composite(void)
412 {
413 	switch (sunxi_display.monitor) {
414 	case sunxi_monitor_none:
415 	case sunxi_monitor_dvi:
416 	case sunxi_monitor_hdmi:
417 	case sunxi_monitor_lcd:
418 	case sunxi_monitor_vga:
419 		return false;
420 	case sunxi_monitor_composite_pal:
421 	case sunxi_monitor_composite_ntsc:
422 	case sunxi_monitor_composite_pal_m:
423 	case sunxi_monitor_composite_pal_nc:
424 		return true;
425 	}
426 
427 	return false; /* Never reached */
428 }
429 
430 /*
431  * This is the entity that mixes and matches the different layers and inputs.
432  * Allwinner calls it the back-end, but i like composer better.
433  */
434 static void sunxi_composer_init(void)
435 {
436 	struct sunxi_ccm_reg * const ccm =
437 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
438 	struct sunxi_de_be_reg * const de_be =
439 		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
440 	int i;
441 
442 	sunxi_frontend_init();
443 
444 #ifdef CONFIG_SUNXI_GEN_SUN6I
445 	/* Reset off */
446 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
447 #endif
448 
449 	/* Clocks on */
450 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
451 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
452 	setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
453 #endif
454 	clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
455 
456 	/* Engine bug, clear registers after reset */
457 	for (i = 0x0800; i < 0x1000; i += 4)
458 		writel(0, SUNXI_DE_BE0_BASE + i);
459 
460 	setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
461 }
462 
463 static u32 sunxi_rgb2yuv_coef[12] = {
464 	0x00000107, 0x00000204, 0x00000064, 0x00000108,
465 	0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
466 	0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
467 };
468 
469 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
470 				    unsigned int address)
471 {
472 	struct sunxi_de_be_reg * const de_be =
473 		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
474 	int i;
475 
476 	sunxi_frontend_mode_set(mode, address);
477 
478 	writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
479 	       &de_be->disp_size);
480 	writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
481 	       &de_be->layer0_size);
482 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
483 	writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
484 	writel(address << 3, &de_be->layer0_addr_low32b);
485 	writel(address >> 29, &de_be->layer0_addr_high4b);
486 #else
487 	writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
488 #endif
489 	writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
490 
491 	setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
492 	if (mode->vmode == FB_VMODE_INTERLACED)
493 		setbits_le32(&de_be->mode,
494 #ifndef CONFIG_MACH_SUN5I
495 			     SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
496 #endif
497 			     SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
498 
499 	if (sunxi_is_composite()) {
500 		writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
501 		       &de_be->output_color_ctrl);
502 		for (i = 0; i < 12; i++)
503 			writel(sunxi_rgb2yuv_coef[i],
504 			       &de_be->output_color_coef[i]);
505 	}
506 }
507 
508 static void sunxi_composer_enable(void)
509 {
510 	struct sunxi_de_be_reg * const de_be =
511 		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
512 
513 	sunxi_frontend_enable();
514 
515 	setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
516 	setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
517 }
518 
519 static void sunxi_lcdc_init(void)
520 {
521 	struct sunxi_ccm_reg * const ccm =
522 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
523 	struct sunxi_lcdc_reg * const lcdc =
524 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
525 
526 	/* Reset off */
527 #ifdef CONFIG_SUNXI_GEN_SUN6I
528 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
529 #else
530 	setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
531 #endif
532 
533 	/* Clock on */
534 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
535 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
536 #ifdef CONFIG_SUNXI_GEN_SUN6I
537 	setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
538 #else
539 	setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
540 #endif
541 #endif
542 
543 	lcdc_init(lcdc);
544 }
545 
546 static void sunxi_lcdc_panel_enable(void)
547 {
548 	int pin, reset_pin;
549 
550 	/*
551 	 * Start with backlight disabled to avoid the screen flashing to
552 	 * white while the lcd inits.
553 	 */
554 	pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
555 	if (pin >= 0) {
556 		gpio_request(pin, "lcd_backlight_enable");
557 		gpio_direction_output(pin, 0);
558 	}
559 
560 	pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
561 	if (pin >= 0) {
562 		gpio_request(pin, "lcd_backlight_pwm");
563 		gpio_direction_output(pin, PWM_OFF);
564 	}
565 
566 	reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
567 	if (reset_pin >= 0) {
568 		gpio_request(reset_pin, "lcd_reset");
569 		gpio_direction_output(reset_pin, 0); /* Assert reset */
570 	}
571 
572 	/* Give the backlight some time to turn off and power up the panel. */
573 	mdelay(40);
574 	pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
575 	if (pin >= 0) {
576 		gpio_request(pin, "lcd_power");
577 		gpio_direction_output(pin, 1);
578 	}
579 
580 	if (reset_pin >= 0)
581 		gpio_direction_output(reset_pin, 1); /* De-assert reset */
582 }
583 
584 static void sunxi_lcdc_backlight_enable(void)
585 {
586 	int pin;
587 
588 	/*
589 	 * We want to have scanned out at least one frame before enabling the
590 	 * backlight to avoid the screen flashing to white when we enable it.
591 	 */
592 	mdelay(40);
593 
594 	pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
595 	if (pin >= 0)
596 		gpio_direction_output(pin, 1);
597 
598 	pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
599 #ifdef SUNXI_PWM_PIN0
600 	if (pin == SUNXI_PWM_PIN0) {
601 		writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
602 		       SUNXI_PWM_CTRL_ENABLE0 |
603 		       SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
604 		writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
605 		sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
606 		return;
607 	}
608 #endif
609 	if (pin >= 0)
610 		gpio_direction_output(pin, PWM_ON);
611 }
612 
613 static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
614 					      struct display_timing *timing)
615 {
616 	timing->pixelclock.typ = mode->pixclock_khz * 1000;
617 
618 	timing->hactive.typ = mode->xres;
619 	timing->hfront_porch.typ = mode->right_margin;
620 	timing->hback_porch.typ = mode->left_margin;
621 	timing->hsync_len.typ = mode->hsync_len;
622 
623 	timing->vactive.typ = mode->yres;
624 	timing->vfront_porch.typ = mode->lower_margin;
625 	timing->vback_porch.typ = mode->upper_margin;
626 	timing->vsync_len.typ = mode->vsync_len;
627 
628 	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
629 		timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
630 	else
631 		timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
632 	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
633 		timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
634 	else
635 		timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
636 	if (mode->vmode == FB_VMODE_INTERLACED)
637 		timing->flags |= DISPLAY_FLAGS_INTERLACED;
638 }
639 
640 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
641 				      bool for_ext_vga_dac)
642 {
643 	struct sunxi_lcdc_reg * const lcdc =
644 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
645 	struct sunxi_ccm_reg * const ccm =
646 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
647 	int clk_div, clk_double, pin;
648 	struct display_timing timing;
649 
650 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
651 	for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
652 #else
653 	for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
654 #endif
655 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
656 		sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
657 #endif
658 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
659 		sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
660 #endif
661 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
662 		sunxi_gpio_set_drv(pin, 3);
663 #endif
664 	}
665 
666 	lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
667 		     sunxi_is_composite());
668 
669 	sunxi_ctfb_mode_to_display_timing(mode, &timing);
670 	lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
671 			    sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
672 }
673 
674 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
675 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
676 				      int *clk_div, int *clk_double,
677 				      bool use_portd_hvsync)
678 {
679 	struct sunxi_lcdc_reg * const lcdc =
680 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
681 	struct sunxi_ccm_reg * const ccm =
682 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
683 	struct display_timing timing;
684 
685 	sunxi_ctfb_mode_to_display_timing(mode, &timing);
686 	lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
687 			    sunxi_is_composite());
688 
689 	if (use_portd_hvsync) {
690 		sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
691 		sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
692 	}
693 
694 	lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
695 		     sunxi_is_composite());
696 }
697 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
698 
699 #ifdef CONFIG_VIDEO_HDMI
700 
701 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
702 {
703 	struct sunxi_hdmi_reg * const hdmi =
704 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
705 	u8 checksum = 0;
706 	u8 avi_info_frame[17] = {
707 		0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
708 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709 		0x00
710 	};
711 	u8 vendor_info_frame[19] = {
712 		0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
713 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 		0x00, 0x00, 0x00
715 	};
716 	int i;
717 
718 	if (mode->pixclock_khz <= 27000)
719 		avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
720 	else
721 		avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
722 
723 	if (mode->xres * 100 / mode->yres < 156)
724 		avi_info_frame[5] |= 0x18; /* 4 : 3 */
725 	else
726 		avi_info_frame[5] |= 0x28; /* 16 : 9 */
727 
728 	for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
729 		checksum += avi_info_frame[i];
730 
731 	avi_info_frame[3] = 0x100 - checksum;
732 
733 	for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
734 		writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
735 
736 	writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
737 	writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
738 
739 	for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
740 		writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
741 
742 	writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
743 	writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
744 
745 	setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
746 }
747 
748 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
749 				int clk_div, int clk_double)
750 {
751 	struct sunxi_hdmi_reg * const hdmi =
752 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
753 	int x, y;
754 
755 	/* Write clear interrupt status bits */
756 	writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
757 
758 	if (sunxi_display.monitor == sunxi_monitor_hdmi)
759 		sunxi_hdmi_setup_info_frames(mode);
760 
761 	/* Set input sync enable */
762 	writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
763 
764 	/* Init various registers, select pll3 as clock source */
765 	writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
766 	writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
767 	writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
768 	writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
769 	writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
770 
771 	/* Setup clk div and doubler */
772 	clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
773 			SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
774 	if (!clk_double)
775 		setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
776 
777 	/* Setup timing registers */
778 	writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
779 	       &hdmi->video_size);
780 
781 	x = mode->hsync_len + mode->left_margin;
782 	y = mode->vsync_len + mode->upper_margin;
783 	writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
784 
785 	x = mode->right_margin;
786 	y = mode->lower_margin;
787 	writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
788 
789 	x = mode->hsync_len;
790 	y = mode->vsync_len;
791 	writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
792 
793 	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
794 		setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
795 
796 	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
797 		setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
798 }
799 
800 static void sunxi_hdmi_enable(void)
801 {
802 	struct sunxi_hdmi_reg * const hdmi =
803 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
804 
805 	udelay(100);
806 	setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
807 }
808 
809 #endif /* CONFIG_VIDEO_HDMI */
810 
811 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
812 
813 static void sunxi_tvencoder_mode_set(void)
814 {
815 	struct sunxi_ccm_reg * const ccm =
816 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
817 	struct sunxi_tve_reg * const tve =
818 		(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
819 
820 	/* Reset off */
821 	setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
822 	/* Clock on */
823 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
824 
825 	switch (sunxi_display.monitor) {
826 	case sunxi_monitor_vga:
827 		tvencoder_mode_set(tve, tve_mode_vga);
828 		break;
829 	case sunxi_monitor_composite_pal_nc:
830 		tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
831 		break;
832 	case sunxi_monitor_composite_pal:
833 		tvencoder_mode_set(tve, tve_mode_composite_pal);
834 		break;
835 	case sunxi_monitor_composite_pal_m:
836 		tvencoder_mode_set(tve, tve_mode_composite_pal_m);
837 		break;
838 	case sunxi_monitor_composite_ntsc:
839 		tvencoder_mode_set(tve, tve_mode_composite_ntsc);
840 		break;
841 	case sunxi_monitor_none:
842 	case sunxi_monitor_dvi:
843 	case sunxi_monitor_hdmi:
844 	case sunxi_monitor_lcd:
845 		break;
846 	}
847 }
848 
849 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
850 
851 static void sunxi_drc_init(void)
852 {
853 #ifdef CONFIG_SUNXI_GEN_SUN6I
854 	struct sunxi_ccm_reg * const ccm =
855 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
856 
857 	/* On sun6i the drc must be clocked even when in pass-through mode */
858 #ifdef CONFIG_MACH_SUN8I_A33
859 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
860 #endif
861 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
862 	clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
863 #endif
864 }
865 
866 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
867 static void sunxi_vga_external_dac_enable(void)
868 {
869 	int pin;
870 
871 	pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
872 	if (pin >= 0) {
873 		gpio_request(pin, "vga_enable");
874 		gpio_direction_output(pin, 1);
875 	}
876 }
877 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
878 
879 #ifdef CONFIG_VIDEO_LCD_SSD2828
880 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
881 {
882 	struct ssd2828_config cfg = {
883 		.csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
884 		.sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
885 		.sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
886 		.sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
887 		.reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
888 		.ssd2828_tx_clk_khz  = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
889 		.ssd2828_color_depth = 24,
890 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
891 		.mipi_dsi_number_of_data_lanes           = 4,
892 		.mipi_dsi_bitrate_per_data_lane_mbps     = 513,
893 		.mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
894 		.mipi_dsi_delay_after_set_display_on_ms  = 200
895 #else
896 #error MIPI LCD panel needs configuration parameters
897 #endif
898 	};
899 
900 	if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
901 		printf("SSD2828: SPI pins are not properly configured\n");
902 		return 1;
903 	}
904 	if (cfg.reset_pin == -1) {
905 		printf("SSD2828: Reset pin is not properly configured\n");
906 		return 1;
907 	}
908 
909 	return ssd2828_init(&cfg, mode);
910 }
911 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
912 
913 static void sunxi_engines_init(void)
914 {
915 	sunxi_composer_init();
916 	sunxi_lcdc_init();
917 	sunxi_drc_init();
918 }
919 
920 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
921 			   unsigned int address)
922 {
923 	int __maybe_unused clk_div, clk_double;
924 	struct sunxi_lcdc_reg * const lcdc =
925 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
926 	struct sunxi_tve_reg * __maybe_unused const tve =
927 		(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
928 
929 	switch (sunxi_display.monitor) {
930 	case sunxi_monitor_none:
931 		break;
932 	case sunxi_monitor_dvi:
933 	case sunxi_monitor_hdmi:
934 #ifdef CONFIG_VIDEO_HDMI
935 		sunxi_composer_mode_set(mode, address);
936 		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
937 		sunxi_hdmi_mode_set(mode, clk_div, clk_double);
938 		sunxi_composer_enable();
939 		lcdc_enable(lcdc, sunxi_display.depth);
940 		sunxi_hdmi_enable();
941 #endif
942 		break;
943 	case sunxi_monitor_lcd:
944 		sunxi_lcdc_panel_enable();
945 		if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
946 			/*
947 			 * The anx9804 needs 1.8V from eldo3, we do this here
948 			 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
949 			 * to avoid turning this on when using hdmi output.
950 			 */
951 			axp_set_eldo(3, 1800);
952 			anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
953 				     ANX9804_DATA_RATE_1620M,
954 				     sunxi_display.depth);
955 		}
956 		if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
957 			mdelay(50); /* Wait for lcd controller power on */
958 			hitachi_tx18d42vm_init();
959 		}
960 		if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
961 			unsigned int orig_i2c_bus = i2c_get_bus_num();
962 			i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
963 			i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
964 			i2c_set_bus_num(orig_i2c_bus);
965 		}
966 		sunxi_composer_mode_set(mode, address);
967 		sunxi_lcdc_tcon0_mode_set(mode, false);
968 		sunxi_composer_enable();
969 		lcdc_enable(lcdc, sunxi_display.depth);
970 #ifdef CONFIG_VIDEO_LCD_SSD2828
971 		sunxi_ssd2828_init(mode);
972 #endif
973 		sunxi_lcdc_backlight_enable();
974 		break;
975 	case sunxi_monitor_vga:
976 #ifdef CONFIG_VIDEO_VGA
977 		sunxi_composer_mode_set(mode, address);
978 		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
979 		sunxi_tvencoder_mode_set();
980 		sunxi_composer_enable();
981 		lcdc_enable(lcdc, sunxi_display.depth);
982 		tvencoder_enable(tve);
983 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
984 		sunxi_composer_mode_set(mode, address);
985 		sunxi_lcdc_tcon0_mode_set(mode, true);
986 		sunxi_composer_enable();
987 		lcdc_enable(lcdc, sunxi_display.depth);
988 		sunxi_vga_external_dac_enable();
989 #endif
990 		break;
991 	case sunxi_monitor_composite_pal:
992 	case sunxi_monitor_composite_ntsc:
993 	case sunxi_monitor_composite_pal_m:
994 	case sunxi_monitor_composite_pal_nc:
995 #ifdef CONFIG_VIDEO_COMPOSITE
996 		sunxi_composer_mode_set(mode, address);
997 		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
998 		sunxi_tvencoder_mode_set();
999 		sunxi_composer_enable();
1000 		lcdc_enable(lcdc, sunxi_display.depth);
1001 		tvencoder_enable(tve);
1002 #endif
1003 		break;
1004 	}
1005 }
1006 
1007 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1008 {
1009 	switch (monitor) {
1010 	case sunxi_monitor_none:		return "none";
1011 	case sunxi_monitor_dvi:			return "dvi";
1012 	case sunxi_monitor_hdmi:		return "hdmi";
1013 	case sunxi_monitor_lcd:			return "lcd";
1014 	case sunxi_monitor_vga:			return "vga";
1015 	case sunxi_monitor_composite_pal:	return "composite-pal";
1016 	case sunxi_monitor_composite_ntsc:	return "composite-ntsc";
1017 	case sunxi_monitor_composite_pal_m:	return "composite-pal-m";
1018 	case sunxi_monitor_composite_pal_nc:	return "composite-pal-nc";
1019 	}
1020 	return NULL; /* never reached */
1021 }
1022 
1023 ulong board_get_usable_ram_top(ulong total_size)
1024 {
1025 	return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1026 }
1027 
1028 static bool sunxi_has_hdmi(void)
1029 {
1030 #ifdef CONFIG_VIDEO_HDMI
1031 	return true;
1032 #else
1033 	return false;
1034 #endif
1035 }
1036 
1037 static bool sunxi_has_lcd(void)
1038 {
1039 	char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1040 
1041 	return lcd_mode[0] != 0;
1042 }
1043 
1044 static bool sunxi_has_vga(void)
1045 {
1046 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1047 	return true;
1048 #else
1049 	return false;
1050 #endif
1051 }
1052 
1053 static bool sunxi_has_composite(void)
1054 {
1055 #ifdef CONFIG_VIDEO_COMPOSITE
1056 	return true;
1057 #else
1058 	return false;
1059 #endif
1060 }
1061 
1062 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1063 {
1064 	if (allow_hdmi && sunxi_has_hdmi())
1065 		return sunxi_monitor_dvi;
1066 	else if (sunxi_has_lcd())
1067 		return sunxi_monitor_lcd;
1068 	else if (sunxi_has_vga())
1069 		return sunxi_monitor_vga;
1070 	else if (sunxi_has_composite())
1071 		return sunxi_monitor_composite_pal;
1072 	else
1073 		return sunxi_monitor_none;
1074 }
1075 
1076 void *video_hw_init(void)
1077 {
1078 	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1079 	const struct ctfb_res_modes *mode;
1080 	struct ctfb_res_modes custom;
1081 	const char *options;
1082 #ifdef CONFIG_VIDEO_HDMI
1083 	int ret, hpd, hpd_delay, edid;
1084 #endif
1085 	int i, overscan_offset, overscan_x, overscan_y;
1086 	unsigned int fb_dma_addr;
1087 	char mon[16];
1088 	char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1089 
1090 	memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1091 
1092 	video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1093 				 &sunxi_display.depth, &options);
1094 #ifdef CONFIG_VIDEO_HDMI
1095 	hpd = video_get_option_int(options, "hpd", 1);
1096 	hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1097 	edid = video_get_option_int(options, "edid", 1);
1098 #endif
1099 	overscan_x = video_get_option_int(options, "overscan_x", -1);
1100 	overscan_y = video_get_option_int(options, "overscan_y", -1);
1101 	sunxi_display.monitor = sunxi_get_default_mon(true);
1102 	video_get_option_string(options, "monitor", mon, sizeof(mon),
1103 				sunxi_get_mon_desc(sunxi_display.monitor));
1104 	for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1105 		if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1106 			sunxi_display.monitor = i;
1107 			break;
1108 		}
1109 	}
1110 	if (i > SUNXI_MONITOR_LAST)
1111 		printf("Unknown monitor: '%s', falling back to '%s'\n",
1112 		       mon, sunxi_get_mon_desc(sunxi_display.monitor));
1113 
1114 #ifdef CONFIG_VIDEO_HDMI
1115 	/* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1116 	if (sunxi_display.monitor == sunxi_monitor_dvi ||
1117 	    sunxi_display.monitor == sunxi_monitor_hdmi) {
1118 		/* Always call hdp_detect, as it also enables clocks, etc. */
1119 		ret = sunxi_hdmi_hpd_detect(hpd_delay);
1120 		if (ret) {
1121 			printf("HDMI connected: ");
1122 			if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1123 				mode = &custom;
1124 		} else if (hpd) {
1125 			sunxi_hdmi_shutdown();
1126 			sunxi_display.monitor = sunxi_get_default_mon(false);
1127 		} /* else continue with hdmi/dvi without a cable connected */
1128 	}
1129 #endif
1130 
1131 	switch (sunxi_display.monitor) {
1132 	case sunxi_monitor_none:
1133 		return NULL;
1134 	case sunxi_monitor_dvi:
1135 	case sunxi_monitor_hdmi:
1136 		if (!sunxi_has_hdmi()) {
1137 			printf("HDMI/DVI not supported on this board\n");
1138 			sunxi_display.monitor = sunxi_monitor_none;
1139 			return NULL;
1140 		}
1141 		break;
1142 	case sunxi_monitor_lcd:
1143 		if (!sunxi_has_lcd()) {
1144 			printf("LCD not supported on this board\n");
1145 			sunxi_display.monitor = sunxi_monitor_none;
1146 			return NULL;
1147 		}
1148 		sunxi_display.depth = video_get_params(&custom, lcd_mode);
1149 		mode = &custom;
1150 		break;
1151 	case sunxi_monitor_vga:
1152 		if (!sunxi_has_vga()) {
1153 			printf("VGA not supported on this board\n");
1154 			sunxi_display.monitor = sunxi_monitor_none;
1155 			return NULL;
1156 		}
1157 		sunxi_display.depth = 18;
1158 		break;
1159 	case sunxi_monitor_composite_pal:
1160 	case sunxi_monitor_composite_ntsc:
1161 	case sunxi_monitor_composite_pal_m:
1162 	case sunxi_monitor_composite_pal_nc:
1163 		if (!sunxi_has_composite()) {
1164 			printf("Composite video not supported on this board\n");
1165 			sunxi_display.monitor = sunxi_monitor_none;
1166 			return NULL;
1167 		}
1168 		if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1169 		    sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1170 			mode = &composite_video_modes[0];
1171 		else
1172 			mode = &composite_video_modes[1];
1173 		sunxi_display.depth = 24;
1174 		break;
1175 	}
1176 
1177 	/* Yes these defaults are quite high, overscan on composite sucks... */
1178 	if (overscan_x == -1)
1179 		overscan_x = sunxi_is_composite() ? 32 : 0;
1180 	if (overscan_y == -1)
1181 		overscan_y = sunxi_is_composite() ? 20 : 0;
1182 
1183 	sunxi_display.fb_size =
1184 		(mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1185 	overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1186 	/* We want to keep the fb_base for simplefb page aligned, where as
1187 	 * the sunxi dma engines will happily accept an unaligned address. */
1188 	if (overscan_offset)
1189 		sunxi_display.fb_size += 0x1000;
1190 
1191 	if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1192 		printf("Error need %dkB for fb, but only %dkB is reserved\n",
1193 		       sunxi_display.fb_size >> 10,
1194 		       CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1195 		return NULL;
1196 	}
1197 
1198 	printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1199 	       mode->xres, mode->yres,
1200 	       (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1201 	       sunxi_get_mon_desc(sunxi_display.monitor),
1202 	       overscan_x, overscan_y);
1203 
1204 	gd->fb_base = gd->bd->bi_dram[0].start +
1205 		      gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1206 	sunxi_engines_init();
1207 
1208 	fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1209 	sunxi_display.fb_addr = gd->fb_base;
1210 	if (overscan_offset) {
1211 		fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1212 		sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1213 		memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1214 		flush_cache(gd->fb_base, sunxi_display.fb_size);
1215 	}
1216 	sunxi_mode_set(mode, fb_dma_addr);
1217 
1218 	/*
1219 	 * These are the only members of this structure that are used. All the
1220 	 * others are driver specific. The pitch is stored in plnSizeX.
1221 	 */
1222 	graphic_device->frameAdrs = sunxi_display.fb_addr;
1223 	graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1224 	graphic_device->gdfBytesPP = 4;
1225 	graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1226 	graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1227 	graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1228 
1229 	return graphic_device;
1230 }
1231 
1232 /*
1233  * Simplefb support.
1234  */
1235 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1236 int sunxi_simplefb_setup(void *blob)
1237 {
1238 	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1239 	int offset, ret;
1240 	u64 start, size;
1241 	const char *pipeline = NULL;
1242 
1243 #ifdef CONFIG_MACH_SUN4I
1244 #define PIPELINE_PREFIX "de_fe0-"
1245 #else
1246 #define PIPELINE_PREFIX
1247 #endif
1248 
1249 	switch (sunxi_display.monitor) {
1250 	case sunxi_monitor_none:
1251 		return 0;
1252 	case sunxi_monitor_dvi:
1253 	case sunxi_monitor_hdmi:
1254 		pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1255 		break;
1256 	case sunxi_monitor_lcd:
1257 		pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1258 		break;
1259 	case sunxi_monitor_vga:
1260 #ifdef CONFIG_VIDEO_VGA
1261 		pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1262 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1263 		pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1264 #endif
1265 		break;
1266 	case sunxi_monitor_composite_pal:
1267 	case sunxi_monitor_composite_ntsc:
1268 	case sunxi_monitor_composite_pal_m:
1269 	case sunxi_monitor_composite_pal_nc:
1270 		pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1271 		break;
1272 	}
1273 
1274 	offset = sunxi_simplefb_fdt_match(blob, pipeline);
1275 	if (offset < 0) {
1276 		eprintf("Cannot setup simplefb: node not found\n");
1277 		return 0; /* Keep older kernels working */
1278 	}
1279 
1280 	/*
1281 	 * Do not report the framebuffer as free RAM to the OS, note we cannot
1282 	 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1283 	 * and e.g. Linux refuses to iomap RAM on ARM, see:
1284 	 * linux/arch/arm/mm/ioremap.c around line 301.
1285 	 */
1286 	start = gd->bd->bi_dram[0].start;
1287 	size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1288 	ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1289 	if (ret) {
1290 		eprintf("Cannot setup simplefb: Error reserving memory\n");
1291 		return ret;
1292 	}
1293 
1294 	ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1295 			graphic_device->winSizeX, graphic_device->winSizeY,
1296 			graphic_device->plnSizeX, "x8r8g8b8");
1297 	if (ret)
1298 		eprintf("Cannot setup simplefb: Error setting properties\n");
1299 
1300 	return ret;
1301 }
1302 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
1303