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