]> git.sur5r.net Git - u-boot/blob - drivers/video/sunxi_display.c
tools: mkimage: Call fclose in error path
[u-boot] / drivers / video / sunxi_display.c
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/pwm.h>
16 #include <asm/global_data.h>
17 #include <asm/gpio.h>
18 #include <asm/io.h>
19 #include <axp_pmic.h>
20 #include <errno.h>
21 #include <fdtdec.h>
22 #include <fdt_support.h>
23 #include <i2c.h>
24 #include <malloc.h>
25 #include <video_fb.h>
26 #include "videomodes.h"
27 #include "anx9804.h"
28 #include "hitachi_tx18d42vm_lcd.h"
29 #include "ssd2828.h"
30
31 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
32 #define PWM_ON 0
33 #define PWM_OFF 1
34 #else
35 #define PWM_ON 1
36 #define PWM_OFF 0
37 #endif
38
39 DECLARE_GLOBAL_DATA_PTR;
40
41 enum sunxi_monitor {
42         sunxi_monitor_none,
43         sunxi_monitor_dvi,
44         sunxi_monitor_hdmi,
45         sunxi_monitor_lcd,
46         sunxi_monitor_vga,
47         sunxi_monitor_composite_pal,
48         sunxi_monitor_composite_ntsc,
49         sunxi_monitor_composite_pal_m,
50         sunxi_monitor_composite_pal_nc,
51 };
52 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
53
54 struct sunxi_display {
55         GraphicDevice graphic_device;
56         enum sunxi_monitor monitor;
57         unsigned int depth;
58         unsigned int fb_addr;
59         unsigned int fb_size;
60 } sunxi_display;
61
62 const struct ctfb_res_modes composite_video_modes[2] = {
63         /*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
64         { 720,  576, 50, 37037,  27000, 137,   5, 20, 27,   2, 2, 0, FB_VMODE_INTERLACED },
65         { 720,  480, 60, 37037,  27000, 116,  20, 16, 27,   2, 2, 0, FB_VMODE_INTERLACED },
66 };
67
68 #ifdef CONFIG_VIDEO_HDMI
69
70 /*
71  * Wait up to 200ms for value to be set in given part of reg.
72  */
73 static int await_completion(u32 *reg, u32 mask, u32 val)
74 {
75         unsigned long tmo = timer_get_us() + 200000;
76
77         while ((readl(reg) & mask) != val) {
78                 if (timer_get_us() > tmo) {
79                         printf("DDC: timeout reading EDID\n");
80                         return -ETIME;
81                 }
82         }
83         return 0;
84 }
85
86 static int sunxi_hdmi_hpd_detect(int hpd_delay)
87 {
88         struct sunxi_ccm_reg * const ccm =
89                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
90         struct sunxi_hdmi_reg * const hdmi =
91                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
92         unsigned long tmo = timer_get_us() + hpd_delay * 1000;
93
94         /* Set pll3 to 300MHz */
95         clock_set_pll3(300000000);
96
97         /* Set hdmi parent to pll3 */
98         clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
99                         CCM_HDMI_CTRL_PLL3);
100
101         /* Set ahb gating to pass */
102 #ifdef CONFIG_SUNXI_GEN_SUN6I
103         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
104 #endif
105         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
106
107         /* Clock on */
108         setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
109
110         writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
111         writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
112
113         while (timer_get_us() < tmo) {
114                 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
115                         return 1;
116         }
117
118         return 0;
119 }
120
121 static void sunxi_hdmi_shutdown(void)
122 {
123         struct sunxi_ccm_reg * const ccm =
124                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
125         struct sunxi_hdmi_reg * const hdmi =
126                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
127
128         clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
129         clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
130         clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
131 #ifdef CONFIG_SUNXI_GEN_SUN6I
132         clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
133 #endif
134         clock_set_pll3(0);
135 }
136
137 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
138 {
139         struct sunxi_hdmi_reg * const hdmi =
140                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
141
142         setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
143         writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
144                SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
145                SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
146                SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
147 #ifndef CONFIG_MACH_SUN6I
148         writel(n, &hdmi->ddc_byte_count);
149         writel(cmnd, &hdmi->ddc_cmnd);
150 #else
151         writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
152 #endif
153         setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
154
155         return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
156 }
157
158 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
159 {
160         struct sunxi_hdmi_reg * const hdmi =
161                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
162         int i, n;
163
164         while (count > 0) {
165                 if (count > 16)
166                         n = 16;
167                 else
168                         n = count;
169
170                 if (sunxi_hdmi_ddc_do_command(
171                                 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
172                                 offset, n))
173                         return -ETIME;
174
175                 for (i = 0; i < n; i++)
176                         *buf++ = readb(&hdmi->ddc_fifo_data);
177
178                 offset += n;
179                 count -= n;
180         }
181
182         return 0;
183 }
184
185 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
186 {
187         int r, retries = 2;
188
189         do {
190                 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
191                 if (r)
192                         continue;
193                 r = edid_check_checksum(buf);
194                 if (r) {
195                         printf("EDID block %d: checksum error%s\n",
196                                block, retries ? ", retrying" : "");
197                 }
198         } while (r && retries--);
199
200         return r;
201 }
202
203 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
204 {
205         struct edid1_info edid1;
206         struct edid_cea861_info cea681[4];
207         struct edid_detailed_timing *t =
208                 (struct edid_detailed_timing *)edid1.monitor_details.timing;
209         struct sunxi_hdmi_reg * const hdmi =
210                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
211         struct sunxi_ccm_reg * const ccm =
212                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
213         int i, r, ext_blocks = 0;
214
215         /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
216         writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
217                &hdmi->pad_ctrl1);
218         writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
219                &hdmi->pll_ctrl);
220         writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
221
222         /* Reset i2c controller */
223         setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
224         writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
225                SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
226                SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
227                SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
228         if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
229                 return -EIO;
230
231         writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
232 #ifndef CONFIG_MACH_SUN6I
233         writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
234                SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
235 #endif
236
237         r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
238         if (r == 0) {
239                 r = edid_check_info(&edid1);
240                 if (r) {
241                         printf("EDID: invalid EDID data\n");
242                         r = -EINVAL;
243                 }
244         }
245         if (r == 0) {
246                 ext_blocks = edid1.extension_flag;
247                 if (ext_blocks > 4)
248                         ext_blocks = 4;
249                 for (i = 0; i < ext_blocks; i++) {
250                         if (sunxi_hdmi_edid_get_block(1 + i,
251                                                 (u8 *)&cea681[i]) != 0) {
252                                 ext_blocks = i;
253                                 break;
254                         }
255                 }
256         }
257
258         /* Disable DDC engine, no longer needed */
259         clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
260         clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
261
262         if (r)
263                 return r;
264
265         /* We want version 1.3 or 1.2 with detailed timing info */
266         if (edid1.version != 1 || (edid1.revision < 3 &&
267                         !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
268                 printf("EDID: unsupported version %d.%d\n",
269                        edid1.version, edid1.revision);
270                 return -EINVAL;
271         }
272
273         /* Take the first usable detailed timing */
274         for (i = 0; i < 4; i++, t++) {
275                 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
276                 if (r == 0)
277                         break;
278         }
279         if (i == 4) {
280                 printf("EDID: no usable detailed timing found\n");
281                 return -ENOENT;
282         }
283
284         /* Check for basic audio support, if found enable hdmi output */
285         sunxi_display.monitor = sunxi_monitor_dvi;
286         for (i = 0; i < ext_blocks; i++) {
287                 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
288                     cea681[i].revision < 2)
289                         continue;
290
291                 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
292                         sunxi_display.monitor = sunxi_monitor_hdmi;
293         }
294
295         return 0;
296 }
297
298 #endif /* CONFIG_VIDEO_HDMI */
299
300 #ifdef CONFIG_MACH_SUN4I
301 /*
302  * Testing has shown that on sun4i the display backend engine does not have
303  * deep enough fifo-s causing flickering / tearing in full-hd mode due to
304  * fifo underruns. So on sun4i we use the display frontend engine to do the
305  * dma from memory, as the frontend does have deep enough fifo-s.
306  */
307
308 static const u32 sun4i_vert_coef[32] = {
309         0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
310         0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
311         0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
312         0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
313         0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
314         0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
315         0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
316         0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
317 };
318
319 static const u32 sun4i_horz_coef[64] = {
320         0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
321         0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
322         0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
323         0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
324         0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
325         0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
326         0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
327         0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
328         0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
329         0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
330         0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
331         0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
332         0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
333         0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
334         0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
335         0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
336 };
337
338 static void sunxi_frontend_init(void)
339 {
340         struct sunxi_ccm_reg * const ccm =
341                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
342         struct sunxi_de_fe_reg * const de_fe =
343                 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
344         int i;
345
346         /* Clocks on */
347         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
348         setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
349         clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
350
351         setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
352
353         for (i = 0; i < 32; i++) {
354                 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
355                 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
356                 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
357                 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
358                 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
359                 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
360         }
361
362         setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
363 }
364
365 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
366                                     unsigned int address)
367 {
368         struct sunxi_de_fe_reg * const de_fe =
369                 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
370
371         setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
372         writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
373         writel(mode->xres * 4, &de_fe->ch0_stride);
374         writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
375         writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
376
377         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
378                &de_fe->ch0_insize);
379         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
380                &de_fe->ch0_outsize);
381         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
382         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
383
384         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
385                &de_fe->ch1_insize);
386         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
387                &de_fe->ch1_outsize);
388         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
389         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
390
391         setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
392 }
393
394 static void sunxi_frontend_enable(void)
395 {
396         struct sunxi_de_fe_reg * const de_fe =
397                 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
398
399         setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
400 }
401 #else
402 static void sunxi_frontend_init(void) {}
403 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
404                                     unsigned int address) {}
405 static void sunxi_frontend_enable(void) {}
406 #endif
407
408 static bool sunxi_is_composite(void)
409 {
410         switch (sunxi_display.monitor) {
411         case sunxi_monitor_none:
412         case sunxi_monitor_dvi:
413         case sunxi_monitor_hdmi:
414         case sunxi_monitor_lcd:
415         case sunxi_monitor_vga:
416                 return false;
417         case sunxi_monitor_composite_pal:
418         case sunxi_monitor_composite_ntsc:
419         case sunxi_monitor_composite_pal_m:
420         case sunxi_monitor_composite_pal_nc:
421                 return true;
422         }
423
424         return false; /* Never reached */
425 }
426
427 /*
428  * This is the entity that mixes and matches the different layers and inputs.
429  * Allwinner calls it the back-end, but i like composer better.
430  */
431 static void sunxi_composer_init(void)
432 {
433         struct sunxi_ccm_reg * const ccm =
434                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
435         struct sunxi_de_be_reg * const de_be =
436                 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
437         int i;
438
439         sunxi_frontend_init();
440
441 #ifdef CONFIG_SUNXI_GEN_SUN6I
442         /* Reset off */
443         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
444 #endif
445
446         /* Clocks on */
447         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
448 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
449         setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
450 #endif
451         clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
452
453         /* Engine bug, clear registers after reset */
454         for (i = 0x0800; i < 0x1000; i += 4)
455                 writel(0, SUNXI_DE_BE0_BASE + i);
456
457         setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
458 }
459
460 static u32 sunxi_rgb2yuv_coef[12] = {
461         0x00000107, 0x00000204, 0x00000064, 0x00000108,
462         0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
463         0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
464 };
465
466 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
467                                     unsigned int address)
468 {
469         struct sunxi_de_be_reg * const de_be =
470                 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
471         int i;
472
473         sunxi_frontend_mode_set(mode, address);
474
475         writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
476                &de_be->disp_size);
477         writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
478                &de_be->layer0_size);
479 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
480         writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
481         writel(address << 3, &de_be->layer0_addr_low32b);
482         writel(address >> 29, &de_be->layer0_addr_high4b);
483 #else
484         writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
485 #endif
486         writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
487
488         setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
489         if (mode->vmode == FB_VMODE_INTERLACED)
490                 setbits_le32(&de_be->mode,
491 #ifndef CONFIG_MACH_SUN5I
492                              SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
493 #endif
494                              SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
495
496         if (sunxi_is_composite()) {
497                 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
498                        &de_be->output_color_ctrl);
499                 for (i = 0; i < 12; i++)
500                         writel(sunxi_rgb2yuv_coef[i],
501                                &de_be->output_color_coef[i]);
502         }
503 }
504
505 static void sunxi_composer_enable(void)
506 {
507         struct sunxi_de_be_reg * const de_be =
508                 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
509
510         sunxi_frontend_enable();
511
512         setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
513         setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
514 }
515
516 /*
517  * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
518  */
519 static void sunxi_lcdc_pll_set(int tcon, int dotclock,
520                                int *clk_div, int *clk_double)
521 {
522         struct sunxi_ccm_reg * const ccm =
523                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
524         int value, n, m, min_m, max_m, diff;
525         int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
526         int best_double = 0;
527         bool use_mipi_pll = false;
528
529         if (tcon == 0) {
530 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
531                 min_m = 6;
532                 max_m = 127;
533 #endif
534 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
535                 min_m = max_m = 7;
536 #endif
537         } else {
538                 min_m = 1;
539                 max_m = 15;
540         }
541
542         /*
543          * Find the lowest divider resulting in a matching clock, if there
544          * is no match, pick the closest lower clock, as monitors tend to
545          * not sync to higher frequencies.
546          */
547         for (m = min_m; m <= max_m; m++) {
548                 n = (m * dotclock) / 3000;
549
550                 if ((n >= 9) && (n <= 127)) {
551                         value = (3000 * n) / m;
552                         diff = dotclock - value;
553                         if (diff < best_diff) {
554                                 best_diff = diff;
555                                 best_m = m;
556                                 best_n = n;
557                                 best_double = 0;
558                         }
559                 }
560
561                 /* These are just duplicates */
562                 if (!(m & 1))
563                         continue;
564
565                 n = (m * dotclock) / 6000;
566                 if ((n >= 9) && (n <= 127)) {
567                         value = (6000 * n) / m;
568                         diff = dotclock - value;
569                         if (diff < best_diff) {
570                                 best_diff = diff;
571                                 best_m = m;
572                                 best_n = n;
573                                 best_double = 1;
574                         }
575                 }
576         }
577
578 #ifdef CONFIG_MACH_SUN6I
579         /*
580          * Use the MIPI pll if we've been unable to find any matching setting
581          * for PLL3, this happens with high dotclocks because of min_m = 6.
582          */
583         if (tcon == 0 && best_n == 0) {
584                 use_mipi_pll = true;
585                 best_m = 6;  /* Minimum m for tcon0 */
586         }
587
588         if (use_mipi_pll) {
589                 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
590                 clock_set_mipi_pll(best_m * dotclock * 1000);
591                 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
592                       dotclock, clock_get_mipi_pll() / best_m / 1000);
593         } else
594 #endif
595         {
596                 clock_set_pll3(best_n * 3000000);
597                 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
598                       dotclock,
599                       (best_double + 1) * clock_get_pll3() / best_m / 1000,
600                       best_double + 1, best_n, best_m);
601         }
602
603         if (tcon == 0) {
604                 u32 pll;
605
606                 if (use_mipi_pll)
607                         pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
608                 else if (best_double)
609                         pll = CCM_LCD_CH0_CTRL_PLL3_2X;
610                 else
611                         pll = CCM_LCD_CH0_CTRL_PLL3;
612
613                 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
614                        &ccm->lcd0_ch0_clk_cfg);
615         } else {
616                 writel(CCM_LCD_CH1_CTRL_GATE |
617                        (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
618                                       CCM_LCD_CH1_CTRL_PLL3) |
619                        CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
620                 if (sunxi_is_composite())
621                         setbits_le32(&ccm->lcd0_ch1_clk_cfg,
622                                      CCM_LCD_CH1_CTRL_HALF_SCLK1);
623         }
624
625         *clk_div = best_m;
626         *clk_double = best_double;
627 }
628
629 static void sunxi_lcdc_init(void)
630 {
631         struct sunxi_ccm_reg * const ccm =
632                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
633         struct sunxi_lcdc_reg * const lcdc =
634                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
635
636         /* Reset off */
637 #ifdef CONFIG_SUNXI_GEN_SUN6I
638         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
639 #else
640         setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
641 #endif
642
643         /* Clock on */
644         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
645 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
646 #ifdef CONFIG_SUNXI_GEN_SUN6I
647         setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
648 #else
649         setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
650 #endif
651 #endif
652
653         /* Init lcdc */
654         writel(0, &lcdc->ctrl); /* Disable tcon */
655         writel(0, &lcdc->int0); /* Disable all interrupts */
656
657         /* Disable tcon0 dot clock */
658         clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
659
660         /* Set all io lines to tristate */
661         writel(0xffffffff, &lcdc->tcon0_io_tristate);
662         writel(0xffffffff, &lcdc->tcon1_io_tristate);
663 }
664
665 static void sunxi_lcdc_enable(void)
666 {
667         struct sunxi_lcdc_reg * const lcdc =
668                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
669
670         setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
671 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
672         setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
673         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
674 #ifdef CONFIG_SUNXI_GEN_SUN6I
675         udelay(2); /* delay at least 1200 ns */
676         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
677         udelay(2); /* delay at least 1200 ns */
678         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
679         if (sunxi_display.depth == 18)
680                 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
681         else
682                 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
683 #else
684         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
685         udelay(2); /* delay at least 1200 ns */
686         setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
687         udelay(1); /* delay at least 120 ns */
688         setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
689         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
690 #endif
691 #endif
692 }
693
694 static void sunxi_lcdc_panel_enable(void)
695 {
696         int pin, reset_pin;
697
698         /*
699          * Start with backlight disabled to avoid the screen flashing to
700          * white while the lcd inits.
701          */
702         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
703         if (pin >= 0) {
704                 gpio_request(pin, "lcd_backlight_enable");
705                 gpio_direction_output(pin, 0);
706         }
707
708         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
709         if (pin >= 0) {
710                 gpio_request(pin, "lcd_backlight_pwm");
711                 gpio_direction_output(pin, PWM_OFF);
712         }
713
714         reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
715         if (reset_pin >= 0) {
716                 gpio_request(reset_pin, "lcd_reset");
717                 gpio_direction_output(reset_pin, 0); /* Assert reset */
718         }
719
720         /* Give the backlight some time to turn off and power up the panel. */
721         mdelay(40);
722         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
723         if (pin >= 0) {
724                 gpio_request(pin, "lcd_power");
725                 gpio_direction_output(pin, 1);
726         }
727
728         if (reset_pin >= 0)
729                 gpio_direction_output(reset_pin, 1); /* De-assert reset */
730 }
731
732 static void sunxi_lcdc_backlight_enable(void)
733 {
734         int pin;
735
736         /*
737          * We want to have scanned out at least one frame before enabling the
738          * backlight to avoid the screen flashing to white when we enable it.
739          */
740         mdelay(40);
741
742         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
743         if (pin >= 0)
744                 gpio_direction_output(pin, 1);
745
746         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
747 #ifdef SUNXI_PWM_PIN0
748         if (pin == SUNXI_PWM_PIN0) {
749                 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
750                        SUNXI_PWM_CTRL_ENABLE0 |
751                        SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
752                 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
753                 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
754                 return;
755         }
756 #endif
757         if (pin >= 0)
758                 gpio_direction_output(pin, PWM_ON);
759 }
760
761 static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
762 {
763         int delay;
764
765         delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
766         if (mode->vmode == FB_VMODE_INTERLACED)
767                 delay /= 2;
768         if (tcon == 1)
769                 delay -= 2;
770
771         return (delay > 30) ? 30 : delay;
772 }
773
774 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
775                                       bool for_ext_vga_dac)
776 {
777         struct sunxi_lcdc_reg * const lcdc =
778                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
779         int bp, clk_delay, clk_div, clk_double, pin, total, val;
780
781 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
782         for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
783 #else
784         for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
785 #endif
786 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
787                 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
788 #endif
789 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
790                 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
791 #endif
792 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
793                 sunxi_gpio_set_drv(pin, 3);
794 #endif
795         }
796
797         sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
798
799         /* Use tcon0 */
800         clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
801                         SUNXI_LCDC_CTRL_IO_MAP_TCON0);
802
803         clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
804         writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
805                SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
806
807         writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
808                SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
809
810         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
811                &lcdc->tcon0_timing_active);
812
813         bp = mode->hsync_len + mode->left_margin;
814         total = mode->xres + mode->right_margin + bp;
815         writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
816                SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
817
818         bp = mode->vsync_len + mode->upper_margin;
819         total = mode->yres + mode->lower_margin + bp;
820         writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
821                SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
822
823 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
824         writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
825                &lcdc->tcon0_timing_sync);
826
827         writel(0, &lcdc->tcon0_hv_intf);
828         writel(0, &lcdc->tcon0_cpu_intf);
829 #endif
830 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
831         val = (sunxi_display.depth == 18) ? 1 : 0;
832         writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
833                SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
834 #endif
835
836         if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
837                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
838                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
839                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
840                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
841                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
842                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
843                 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
844                 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
845                 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
846                 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
847                 writel(((sunxi_display.depth == 18) ?
848                         SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
849                         SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
850                        &lcdc->tcon0_frm_ctrl);
851         }
852
853         val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
854         if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
855                 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
856         if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
857                 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
858
859 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
860         if (for_ext_vga_dac)
861                 val = 0;
862 #endif
863         writel(val, &lcdc->tcon0_io_polarity);
864
865         writel(0, &lcdc->tcon0_io_tristate);
866 }
867
868 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
869 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
870                                       int *clk_div, int *clk_double,
871                                       bool use_portd_hvsync)
872 {
873         struct sunxi_lcdc_reg * const lcdc =
874                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
875         int bp, clk_delay, total, val, yres;
876
877         /* Use tcon1 */
878         clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
879                         SUNXI_LCDC_CTRL_IO_MAP_TCON1);
880
881         clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
882         writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
883                ((mode->vmode == FB_VMODE_INTERLACED) ?
884                         SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
885                SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
886
887         yres = mode->yres;
888         if (mode->vmode == FB_VMODE_INTERLACED)
889                 yres /= 2;
890         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
891                &lcdc->tcon1_timing_source);
892         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
893                &lcdc->tcon1_timing_scale);
894         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
895                &lcdc->tcon1_timing_out);
896
897         bp = mode->hsync_len + mode->left_margin;
898         total = mode->xres + mode->right_margin + bp;
899         writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
900                SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
901
902         bp = mode->vsync_len + mode->upper_margin;
903         total = mode->yres + mode->lower_margin + bp;
904         if (mode->vmode == FB_VMODE_NONINTERLACED)
905                 total *= 2;
906         writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
907                SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
908
909         writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
910                &lcdc->tcon1_timing_sync);
911
912         if (use_portd_hvsync) {
913                 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
914                 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
915
916                 val = 0;
917                 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
918                         val |= SUNXI_LCDC_TCON_HSYNC_MASK;
919                 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
920                         val |= SUNXI_LCDC_TCON_VSYNC_MASK;
921                 writel(val, &lcdc->tcon1_io_polarity);
922
923                 clrbits_le32(&lcdc->tcon1_io_tristate,
924                              SUNXI_LCDC_TCON_VSYNC_MASK |
925                              SUNXI_LCDC_TCON_HSYNC_MASK);
926         }
927
928 #ifdef CONFIG_MACH_SUN5I
929         if (sunxi_is_composite())
930                 clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK,
931                                 SUNXI_LCDC_MUX_CTRL_SRC0(1));
932 #endif
933
934         sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
935 }
936 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
937
938 #ifdef CONFIG_VIDEO_HDMI
939
940 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
941 {
942         struct sunxi_hdmi_reg * const hdmi =
943                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
944         u8 checksum = 0;
945         u8 avi_info_frame[17] = {
946                 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
947                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
948                 0x00
949         };
950         u8 vendor_info_frame[19] = {
951                 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
952                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
953                 0x00, 0x00, 0x00
954         };
955         int i;
956
957         if (mode->pixclock_khz <= 27000)
958                 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
959         else
960                 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
961
962         if (mode->xres * 100 / mode->yres < 156)
963                 avi_info_frame[5] |= 0x18; /* 4 : 3 */
964         else
965                 avi_info_frame[5] |= 0x28; /* 16 : 9 */
966
967         for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
968                 checksum += avi_info_frame[i];
969
970         avi_info_frame[3] = 0x100 - checksum;
971
972         for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
973                 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
974
975         writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
976         writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
977
978         for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
979                 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
980
981         writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
982         writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
983
984         setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
985 }
986
987 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
988                                 int clk_div, int clk_double)
989 {
990         struct sunxi_hdmi_reg * const hdmi =
991                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
992         int x, y;
993
994         /* Write clear interrupt status bits */
995         writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
996
997         if (sunxi_display.monitor == sunxi_monitor_hdmi)
998                 sunxi_hdmi_setup_info_frames(mode);
999
1000         /* Set input sync enable */
1001         writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
1002
1003         /* Init various registers, select pll3 as clock source */
1004         writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
1005         writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
1006         writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
1007         writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
1008         writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
1009
1010         /* Setup clk div and doubler */
1011         clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
1012                         SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
1013         if (!clk_double)
1014                 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
1015
1016         /* Setup timing registers */
1017         writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
1018                &hdmi->video_size);
1019
1020         x = mode->hsync_len + mode->left_margin;
1021         y = mode->vsync_len + mode->upper_margin;
1022         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
1023
1024         x = mode->right_margin;
1025         y = mode->lower_margin;
1026         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
1027
1028         x = mode->hsync_len;
1029         y = mode->vsync_len;
1030         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
1031
1032         if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
1033                 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
1034
1035         if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
1036                 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
1037 }
1038
1039 static void sunxi_hdmi_enable(void)
1040 {
1041         struct sunxi_hdmi_reg * const hdmi =
1042                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
1043
1044         udelay(100);
1045         setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
1046 }
1047
1048 #endif /* CONFIG_VIDEO_HDMI */
1049
1050 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
1051
1052 static void sunxi_tvencoder_mode_set(void)
1053 {
1054         struct sunxi_ccm_reg * const ccm =
1055                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1056         struct sunxi_tve_reg * const tve =
1057                 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1058
1059         /* Reset off */
1060         setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
1061         /* Clock on */
1062         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1063
1064         switch (sunxi_display.monitor) {
1065         case sunxi_monitor_vga:
1066                 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1067                        SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1068                        SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
1069                 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1070                 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1071                 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1072                 break;
1073         case sunxi_monitor_composite_pal_nc:
1074                 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1075                 /* Fall through */
1076         case sunxi_monitor_composite_pal:
1077                 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1078                        SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1079                        SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1080                        SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1081                 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1082                 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1083                 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1084                 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1085                 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1086                 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1087                 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1088                 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1089                 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1090                 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1091                 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1092                 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1093                 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1094                 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1095                 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1096                 break;
1097         case sunxi_monitor_composite_pal_m:
1098                 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1099                 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1100                 /* Fall through */
1101         case sunxi_monitor_composite_ntsc:
1102                 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1103                        SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1104                        SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1105                        SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1106                 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1107                 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1108                 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1109                 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1110                 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1111                 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1112                 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1113                 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1114                 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1115                 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1116                 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1117                 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1118                 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1119                 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1120                 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1121                 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1122                 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1123                 break;
1124         case sunxi_monitor_none:
1125         case sunxi_monitor_dvi:
1126         case sunxi_monitor_hdmi:
1127         case sunxi_monitor_lcd:
1128                 break;
1129         }
1130 }
1131
1132 static void sunxi_tvencoder_enable(void)
1133 {
1134         struct sunxi_tve_reg * const tve =
1135                 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1136
1137         setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1138 }
1139
1140 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
1141
1142 static void sunxi_drc_init(void)
1143 {
1144 #ifdef CONFIG_SUNXI_GEN_SUN6I
1145         struct sunxi_ccm_reg * const ccm =
1146                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1147
1148         /* On sun6i the drc must be clocked even when in pass-through mode */
1149 #ifdef CONFIG_MACH_SUN8I_A33
1150         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1151 #endif
1152         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1153         clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1154 #endif
1155 }
1156
1157 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
1158 static void sunxi_vga_external_dac_enable(void)
1159 {
1160         int pin;
1161
1162         pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
1163         if (pin >= 0) {
1164                 gpio_request(pin, "vga_enable");
1165                 gpio_direction_output(pin, 1);
1166         }
1167 }
1168 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1169
1170 #ifdef CONFIG_VIDEO_LCD_SSD2828
1171 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1172 {
1173         struct ssd2828_config cfg = {
1174                 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1175                 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1176                 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1177                 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1178                 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1179                 .ssd2828_tx_clk_khz  = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1180                 .ssd2828_color_depth = 24,
1181 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1182                 .mipi_dsi_number_of_data_lanes           = 4,
1183                 .mipi_dsi_bitrate_per_data_lane_mbps     = 513,
1184                 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1185                 .mipi_dsi_delay_after_set_display_on_ms  = 200
1186 #else
1187 #error MIPI LCD panel needs configuration parameters
1188 #endif
1189         };
1190
1191         if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1192                 printf("SSD2828: SPI pins are not properly configured\n");
1193                 return 1;
1194         }
1195         if (cfg.reset_pin == -1) {
1196                 printf("SSD2828: Reset pin is not properly configured\n");
1197                 return 1;
1198         }
1199
1200         return ssd2828_init(&cfg, mode);
1201 }
1202 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
1203
1204 static void sunxi_engines_init(void)
1205 {
1206         sunxi_composer_init();
1207         sunxi_lcdc_init();
1208         sunxi_drc_init();
1209 }
1210
1211 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
1212                            unsigned int address)
1213 {
1214         int __maybe_unused clk_div, clk_double;
1215
1216         switch (sunxi_display.monitor) {
1217         case sunxi_monitor_none:
1218                 break;
1219         case sunxi_monitor_dvi:
1220         case sunxi_monitor_hdmi:
1221 #ifdef CONFIG_VIDEO_HDMI
1222                 sunxi_composer_mode_set(mode, address);
1223                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1224                 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1225                 sunxi_composer_enable();
1226                 sunxi_lcdc_enable();
1227                 sunxi_hdmi_enable();
1228 #endif
1229                 break;
1230         case sunxi_monitor_lcd:
1231                 sunxi_lcdc_panel_enable();
1232                 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1233                         /*
1234                          * The anx9804 needs 1.8V from eldo3, we do this here
1235                          * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
1236                          * to avoid turning this on when using hdmi output.
1237                          */
1238                         axp_set_eldo(3, 1800);
1239                         anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1240                                      ANX9804_DATA_RATE_1620M,
1241                                      sunxi_display.depth);
1242                 }
1243                 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1244                         mdelay(50); /* Wait for lcd controller power on */
1245                         hitachi_tx18d42vm_init();
1246                 }
1247                 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1248                         unsigned int orig_i2c_bus = i2c_get_bus_num();
1249                         i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1250                         i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1251                         i2c_set_bus_num(orig_i2c_bus);
1252                 }
1253                 sunxi_composer_mode_set(mode, address);
1254                 sunxi_lcdc_tcon0_mode_set(mode, false);
1255                 sunxi_composer_enable();
1256                 sunxi_lcdc_enable();
1257 #ifdef CONFIG_VIDEO_LCD_SSD2828
1258                 sunxi_ssd2828_init(mode);
1259 #endif
1260                 sunxi_lcdc_backlight_enable();
1261                 break;
1262         case sunxi_monitor_vga:
1263 #ifdef CONFIG_VIDEO_VGA
1264                 sunxi_composer_mode_set(mode, address);
1265                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1266                 sunxi_tvencoder_mode_set();
1267                 sunxi_composer_enable();
1268                 sunxi_lcdc_enable();
1269                 sunxi_tvencoder_enable();
1270 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1271                 sunxi_composer_mode_set(mode, address);
1272                 sunxi_lcdc_tcon0_mode_set(mode, true);
1273                 sunxi_composer_enable();
1274                 sunxi_lcdc_enable();
1275                 sunxi_vga_external_dac_enable();
1276 #endif
1277                 break;
1278         case sunxi_monitor_composite_pal:
1279         case sunxi_monitor_composite_ntsc:
1280         case sunxi_monitor_composite_pal_m:
1281         case sunxi_monitor_composite_pal_nc:
1282 #ifdef CONFIG_VIDEO_COMPOSITE
1283                 sunxi_composer_mode_set(mode, address);
1284                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1285                 sunxi_tvencoder_mode_set();
1286                 sunxi_composer_enable();
1287                 sunxi_lcdc_enable();
1288                 sunxi_tvencoder_enable();
1289 #endif
1290                 break;
1291         }
1292 }
1293
1294 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1295 {
1296         switch (monitor) {
1297         case sunxi_monitor_none:                return "none";
1298         case sunxi_monitor_dvi:                 return "dvi";
1299         case sunxi_monitor_hdmi:                return "hdmi";
1300         case sunxi_monitor_lcd:                 return "lcd";
1301         case sunxi_monitor_vga:                 return "vga";
1302         case sunxi_monitor_composite_pal:       return "composite-pal";
1303         case sunxi_monitor_composite_ntsc:      return "composite-ntsc";
1304         case sunxi_monitor_composite_pal_m:     return "composite-pal-m";
1305         case sunxi_monitor_composite_pal_nc:    return "composite-pal-nc";
1306         }
1307         return NULL; /* never reached */
1308 }
1309
1310 ulong board_get_usable_ram_top(ulong total_size)
1311 {
1312         return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1313 }
1314
1315 static bool sunxi_has_hdmi(void)
1316 {
1317 #ifdef CONFIG_VIDEO_HDMI
1318         return true;
1319 #else
1320         return false;
1321 #endif
1322 }
1323
1324 static bool sunxi_has_lcd(void)
1325 {
1326         char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1327
1328         return lcd_mode[0] != 0;
1329 }
1330
1331 static bool sunxi_has_vga(void)
1332 {
1333 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1334         return true;
1335 #else
1336         return false;
1337 #endif
1338 }
1339
1340 static bool sunxi_has_composite(void)
1341 {
1342 #ifdef CONFIG_VIDEO_COMPOSITE
1343         return true;
1344 #else
1345         return false;
1346 #endif
1347 }
1348
1349 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1350 {
1351         if (allow_hdmi && sunxi_has_hdmi())
1352                 return sunxi_monitor_dvi;
1353         else if (sunxi_has_lcd())
1354                 return sunxi_monitor_lcd;
1355         else if (sunxi_has_vga())
1356                 return sunxi_monitor_vga;
1357         else if (sunxi_has_composite())
1358                 return sunxi_monitor_composite_pal;
1359         else
1360                 return sunxi_monitor_none;
1361 }
1362
1363 void *video_hw_init(void)
1364 {
1365         static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1366         const struct ctfb_res_modes *mode;
1367         struct ctfb_res_modes custom;
1368         const char *options;
1369 #ifdef CONFIG_VIDEO_HDMI
1370         int ret, hpd, hpd_delay, edid;
1371 #endif
1372         int i, overscan_offset, overscan_x, overscan_y;
1373         unsigned int fb_dma_addr;
1374         char mon[16];
1375         char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1376
1377         memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1378
1379         video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1380                                  &sunxi_display.depth, &options);
1381 #ifdef CONFIG_VIDEO_HDMI
1382         hpd = video_get_option_int(options, "hpd", 1);
1383         hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1384         edid = video_get_option_int(options, "edid", 1);
1385 #endif
1386         overscan_x = video_get_option_int(options, "overscan_x", -1);
1387         overscan_y = video_get_option_int(options, "overscan_y", -1);
1388         sunxi_display.monitor = sunxi_get_default_mon(true);
1389         video_get_option_string(options, "monitor", mon, sizeof(mon),
1390                                 sunxi_get_mon_desc(sunxi_display.monitor));
1391         for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1392                 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1393                         sunxi_display.monitor = i;
1394                         break;
1395                 }
1396         }
1397         if (i > SUNXI_MONITOR_LAST)
1398                 printf("Unknown monitor: '%s', falling back to '%s'\n",
1399                        mon, sunxi_get_mon_desc(sunxi_display.monitor));
1400
1401 #ifdef CONFIG_VIDEO_HDMI
1402         /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1403         if (sunxi_display.monitor == sunxi_monitor_dvi ||
1404             sunxi_display.monitor == sunxi_monitor_hdmi) {
1405                 /* Always call hdp_detect, as it also enables clocks, etc. */
1406                 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1407                 if (ret) {
1408                         printf("HDMI connected: ");
1409                         if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1410                                 mode = &custom;
1411                 } else if (hpd) {
1412                         sunxi_hdmi_shutdown();
1413                         sunxi_display.monitor = sunxi_get_default_mon(false);
1414                 } /* else continue with hdmi/dvi without a cable connected */
1415         }
1416 #endif
1417
1418         switch (sunxi_display.monitor) {
1419         case sunxi_monitor_none:
1420                 return NULL;
1421         case sunxi_monitor_dvi:
1422         case sunxi_monitor_hdmi:
1423                 if (!sunxi_has_hdmi()) {
1424                         printf("HDMI/DVI not supported on this board\n");
1425                         sunxi_display.monitor = sunxi_monitor_none;
1426                         return NULL;
1427                 }
1428                 break;
1429         case sunxi_monitor_lcd:
1430                 if (!sunxi_has_lcd()) {
1431                         printf("LCD not supported on this board\n");
1432                         sunxi_display.monitor = sunxi_monitor_none;
1433                         return NULL;
1434                 }
1435                 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1436                 mode = &custom;
1437                 break;
1438         case sunxi_monitor_vga:
1439                 if (!sunxi_has_vga()) {
1440                         printf("VGA not supported on this board\n");
1441                         sunxi_display.monitor = sunxi_monitor_none;
1442                         return NULL;
1443                 }
1444                 sunxi_display.depth = 18;
1445                 break;
1446         case sunxi_monitor_composite_pal:
1447         case sunxi_monitor_composite_ntsc:
1448         case sunxi_monitor_composite_pal_m:
1449         case sunxi_monitor_composite_pal_nc:
1450                 if (!sunxi_has_composite()) {
1451                         printf("Composite video not supported on this board\n");
1452                         sunxi_display.monitor = sunxi_monitor_none;
1453                         return NULL;
1454                 }
1455                 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1456                     sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1457                         mode = &composite_video_modes[0];
1458                 else
1459                         mode = &composite_video_modes[1];
1460                 sunxi_display.depth = 24;
1461                 break;
1462         }
1463
1464         /* Yes these defaults are quite high, overscan on composite sucks... */
1465         if (overscan_x == -1)
1466                 overscan_x = sunxi_is_composite() ? 32 : 0;
1467         if (overscan_y == -1)
1468                 overscan_y = sunxi_is_composite() ? 20 : 0;
1469
1470         sunxi_display.fb_size =
1471                 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1472         overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1473         /* We want to keep the fb_base for simplefb page aligned, where as
1474          * the sunxi dma engines will happily accept an unaligned address. */
1475         if (overscan_offset)
1476                 sunxi_display.fb_size += 0x1000;
1477
1478         if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1479                 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1480                        sunxi_display.fb_size >> 10,
1481                        CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1482                 return NULL;
1483         }
1484
1485         printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1486                mode->xres, mode->yres,
1487                (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1488                sunxi_get_mon_desc(sunxi_display.monitor),
1489                overscan_x, overscan_y);
1490
1491         gd->fb_base = gd->bd->bi_dram[0].start +
1492                       gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1493         sunxi_engines_init();
1494
1495         fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1496         sunxi_display.fb_addr = gd->fb_base;
1497         if (overscan_offset) {
1498                 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1499                 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1500                 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1501                 flush_cache(gd->fb_base, sunxi_display.fb_size);
1502         }
1503         sunxi_mode_set(mode, fb_dma_addr);
1504
1505         /*
1506          * These are the only members of this structure that are used. All the
1507          * others are driver specific. The pitch is stored in plnSizeX.
1508          */
1509         graphic_device->frameAdrs = sunxi_display.fb_addr;
1510         graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1511         graphic_device->gdfBytesPP = 4;
1512         graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1513         graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1514         graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1515
1516         return graphic_device;
1517 }
1518
1519 /*
1520  * Simplefb support.
1521  */
1522 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1523 int sunxi_simplefb_setup(void *blob)
1524 {
1525         static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1526         int offset, ret;
1527         u64 start, size;
1528         const char *pipeline = NULL;
1529
1530 #ifdef CONFIG_MACH_SUN4I
1531 #define PIPELINE_PREFIX "de_fe0-"
1532 #else
1533 #define PIPELINE_PREFIX
1534 #endif
1535
1536         switch (sunxi_display.monitor) {
1537         case sunxi_monitor_none:
1538                 return 0;
1539         case sunxi_monitor_dvi:
1540         case sunxi_monitor_hdmi:
1541                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1542                 break;
1543         case sunxi_monitor_lcd:
1544                 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1545                 break;
1546         case sunxi_monitor_vga:
1547 #ifdef CONFIG_VIDEO_VGA
1548                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1549 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1550                 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1551 #endif
1552                 break;
1553         case sunxi_monitor_composite_pal:
1554         case sunxi_monitor_composite_ntsc:
1555         case sunxi_monitor_composite_pal_m:
1556         case sunxi_monitor_composite_pal_nc:
1557                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1558                 break;
1559         }
1560
1561         /* Find a prefilled simpefb node, matching out pipeline config */
1562         offset = fdt_node_offset_by_compatible(blob, -1,
1563                                                "allwinner,simple-framebuffer");
1564         while (offset >= 0) {
1565                 ret = fdt_stringlist_search(blob, offset, "allwinner,pipeline",
1566                                             pipeline);
1567                 if (ret == 0)
1568                         break;
1569                 offset = fdt_node_offset_by_compatible(blob, offset,
1570                                                "allwinner,simple-framebuffer");
1571         }
1572         if (offset < 0) {
1573                 eprintf("Cannot setup simplefb: node not found\n");
1574                 return 0; /* Keep older kernels working */
1575         }
1576
1577         /*
1578          * Do not report the framebuffer as free RAM to the OS, note we cannot
1579          * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1580          * and e.g. Linux refuses to iomap RAM on ARM, see:
1581          * linux/arch/arm/mm/ioremap.c around line 301.
1582          */
1583         start = gd->bd->bi_dram[0].start;
1584         size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1585         ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1586         if (ret) {
1587                 eprintf("Cannot setup simplefb: Error reserving memory\n");
1588                 return ret;
1589         }
1590
1591         ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1592                         graphic_device->winSizeX, graphic_device->winSizeY,
1593                         graphic_device->plnSizeX, "x8r8g8b8");
1594         if (ret)
1595                 eprintf("Cannot setup simplefb: Error setting properties\n");
1596
1597         return ret;
1598 }
1599 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */