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