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