]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/video/sunxi_display.c
7c1ea8f2f6a903529398e036ac3e66eaffa5c29e
[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-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                              SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
489                              SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
490
491         if (sunxi_is_composite()) {
492                 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
493                        &de_be->output_color_ctrl);
494                 for (i = 0; i < 12; i++)
495                         writel(sunxi_rgb2yuv_coef[i],
496                                &de_be->output_color_coef[i]);
497         }
498 }
499
500 static void sunxi_composer_enable(void)
501 {
502         struct sunxi_de_be_reg * const de_be =
503                 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
504
505         sunxi_frontend_enable();
506
507         setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
508         setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
509 }
510
511 /*
512  * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
513  */
514 static void sunxi_lcdc_pll_set(int tcon, int dotclock,
515                                int *clk_div, int *clk_double)
516 {
517         struct sunxi_ccm_reg * const ccm =
518                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
519         int value, n, m, min_m, max_m, diff;
520         int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
521         int best_double = 0;
522
523         if (tcon == 0) {
524 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
525                 min_m = 6;
526                 max_m = 127;
527 #endif
528 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
529                 min_m = max_m = 7;
530 #endif
531         } else {
532                 min_m = 1;
533                 max_m = 15;
534         }
535
536         /*
537          * Find the lowest divider resulting in a matching clock, if there
538          * is no match, pick the closest lower clock, as monitors tend to
539          * not sync to higher frequencies.
540          */
541         for (m = min_m; m <= max_m; m++) {
542                 n = (m * dotclock) / 3000;
543
544                 if ((n >= 9) && (n <= 127)) {
545                         value = (3000 * n) / m;
546                         diff = dotclock - value;
547                         if (diff < best_diff) {
548                                 best_diff = diff;
549                                 best_m = m;
550                                 best_n = n;
551                                 best_double = 0;
552                         }
553                 }
554
555                 /* These are just duplicates */
556                 if (!(m & 1))
557                         continue;
558
559                 n = (m * dotclock) / 6000;
560                 if ((n >= 9) && (n <= 127)) {
561                         value = (6000 * n) / m;
562                         diff = dotclock - value;
563                         if (diff < best_diff) {
564                                 best_diff = diff;
565                                 best_m = m;
566                                 best_n = n;
567                                 best_double = 1;
568                         }
569                 }
570         }
571
572         debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
573               dotclock, (best_double + 1) * 3000 * best_n / best_m,
574               best_double + 1, best_n, best_m);
575
576         clock_set_pll3(best_n * 3000000);
577
578         if (tcon == 0) {
579                 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
580                        (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
581                                       CCM_LCD_CH0_CTRL_PLL3),
582                        &ccm->lcd0_ch0_clk_cfg);
583         } else {
584                 writel(CCM_LCD_CH1_CTRL_GATE |
585                        (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
586                                       CCM_LCD_CH1_CTRL_PLL3) |
587                        CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
588                 if (sunxi_is_composite())
589                         setbits_le32(&ccm->lcd0_ch1_clk_cfg,
590                                      CCM_LCD_CH1_CTRL_HALF_SCLK1);
591         }
592
593         *clk_div = best_m;
594         *clk_double = best_double;
595 }
596
597 static void sunxi_lcdc_init(void)
598 {
599         struct sunxi_ccm_reg * const ccm =
600                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
601         struct sunxi_lcdc_reg * const lcdc =
602                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
603
604         /* Reset off */
605 #ifdef CONFIG_SUNXI_GEN_SUN6I
606         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
607 #else
608         setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
609 #endif
610
611         /* Clock on */
612         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
613 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
614 #ifdef CONFIG_SUNXI_GEN_SUN6I
615         setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
616 #else
617         setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
618 #endif
619 #endif
620
621         /* Init lcdc */
622         writel(0, &lcdc->ctrl); /* Disable tcon */
623         writel(0, &lcdc->int0); /* Disable all interrupts */
624
625         /* Disable tcon0 dot clock */
626         clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
627
628         /* Set all io lines to tristate */
629         writel(0xffffffff, &lcdc->tcon0_io_tristate);
630         writel(0xffffffff, &lcdc->tcon1_io_tristate);
631 }
632
633 static void sunxi_lcdc_enable(void)
634 {
635         struct sunxi_lcdc_reg * const lcdc =
636                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
637
638         setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
639 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
640         setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
641         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
642 #ifdef CONFIG_SUNXI_GEN_SUN6I
643         udelay(2); /* delay at least 1200 ns */
644         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
645         udelay(2); /* delay at least 1200 ns */
646         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
647         if (sunxi_display.depth == 18)
648                 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
649         else
650                 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
651 #else
652         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
653         udelay(2); /* delay at least 1200 ns */
654         setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
655         udelay(1); /* delay at least 120 ns */
656         setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
657         setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
658 #endif
659 #endif
660 }
661
662 static void sunxi_lcdc_panel_enable(void)
663 {
664         int pin, reset_pin;
665
666         /*
667          * Start with backlight disabled to avoid the screen flashing to
668          * white while the lcd inits.
669          */
670         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
671         if (pin >= 0) {
672                 gpio_request(pin, "lcd_backlight_enable");
673                 gpio_direction_output(pin, 0);
674         }
675
676         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
677         if (pin >= 0) {
678                 gpio_request(pin, "lcd_backlight_pwm");
679                 gpio_direction_output(pin, PWM_OFF);
680         }
681
682         reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
683         if (reset_pin >= 0) {
684                 gpio_request(reset_pin, "lcd_reset");
685                 gpio_direction_output(reset_pin, 0); /* Assert reset */
686         }
687
688         /* Give the backlight some time to turn off and power up the panel. */
689         mdelay(40);
690         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
691         if (pin >= 0) {
692                 gpio_request(pin, "lcd_power");
693                 gpio_direction_output(pin, 1);
694         }
695
696         if (reset_pin >= 0)
697                 gpio_direction_output(reset_pin, 1); /* De-assert reset */
698 }
699
700 static void sunxi_lcdc_backlight_enable(void)
701 {
702         int pin;
703
704         /*
705          * We want to have scanned out at least one frame before enabling the
706          * backlight to avoid the screen flashing to white when we enable it.
707          */
708         mdelay(40);
709
710         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
711         if (pin >= 0)
712                 gpio_direction_output(pin, 1);
713
714         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
715         if (pin >= 0)
716                 gpio_direction_output(pin, PWM_ON);
717 }
718
719 static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
720 {
721         int delay;
722
723         delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
724         if (mode->vmode == FB_VMODE_INTERLACED)
725                 delay /= 2;
726         if (tcon == 1)
727                 delay -= 2;
728
729         return (delay > 30) ? 30 : delay;
730 }
731
732 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
733                                       bool for_ext_vga_dac)
734 {
735         struct sunxi_lcdc_reg * const lcdc =
736                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
737         int bp, clk_delay, clk_div, clk_double, pin, total, val;
738
739         for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
740 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
741                 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
742 #endif
743 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
744                 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
745 #endif
746
747         sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
748
749         /* Use tcon0 */
750         clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
751                         SUNXI_LCDC_CTRL_IO_MAP_TCON0);
752
753         clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
754         writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
755                SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
756
757         writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
758                SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
759
760         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
761                &lcdc->tcon0_timing_active);
762
763         bp = mode->hsync_len + mode->left_margin;
764         total = mode->xres + mode->right_margin + bp;
765         writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
766                SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
767
768         bp = mode->vsync_len + mode->upper_margin;
769         total = mode->yres + mode->lower_margin + bp;
770         writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
771                SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
772
773 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
774         writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
775                &lcdc->tcon0_timing_sync);
776
777         writel(0, &lcdc->tcon0_hv_intf);
778         writel(0, &lcdc->tcon0_cpu_intf);
779 #endif
780 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
781         val = (sunxi_display.depth == 18) ? 1 : 0;
782         writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
783                SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
784 #endif
785
786         if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
787                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
788                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
789                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
790                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
791                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
792                 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
793                 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
794                 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
795                 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
796                 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
797                 writel(((sunxi_display.depth == 18) ?
798                         SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
799                         SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
800                        &lcdc->tcon0_frm_ctrl);
801         }
802
803         val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
804         if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
805                 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
806         if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
807                 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
808
809 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
810         if (for_ext_vga_dac)
811                 val = 0;
812 #endif
813         writel(val, &lcdc->tcon0_io_polarity);
814
815         writel(0, &lcdc->tcon0_io_tristate);
816 }
817
818 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
819 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
820                                       int *clk_div, int *clk_double,
821                                       bool use_portd_hvsync)
822 {
823         struct sunxi_lcdc_reg * const lcdc =
824                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
825         int bp, clk_delay, total, val, yres;
826
827         /* Use tcon1 */
828         clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
829                         SUNXI_LCDC_CTRL_IO_MAP_TCON1);
830
831         clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
832         writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
833                ((mode->vmode == FB_VMODE_INTERLACED) ?
834                         SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
835                SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
836
837         yres = mode->yres;
838         if (mode->vmode == FB_VMODE_INTERLACED)
839                 yres /= 2;
840         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
841                &lcdc->tcon1_timing_source);
842         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
843                &lcdc->tcon1_timing_scale);
844         writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
845                &lcdc->tcon1_timing_out);
846
847         bp = mode->hsync_len + mode->left_margin;
848         total = mode->xres + mode->right_margin + bp;
849         writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
850                SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
851
852         bp = mode->vsync_len + mode->upper_margin;
853         total = mode->yres + mode->lower_margin + bp;
854         if (mode->vmode == FB_VMODE_NONINTERLACED)
855                 total *= 2;
856         writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
857                SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
858
859         writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
860                &lcdc->tcon1_timing_sync);
861
862         if (use_portd_hvsync) {
863                 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
864                 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
865
866                 val = 0;
867                 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
868                         val |= SUNXI_LCDC_TCON_HSYNC_MASK;
869                 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
870                         val |= SUNXI_LCDC_TCON_VSYNC_MASK;
871                 writel(val, &lcdc->tcon1_io_polarity);
872
873                 clrbits_le32(&lcdc->tcon1_io_tristate,
874                              SUNXI_LCDC_TCON_VSYNC_MASK |
875                              SUNXI_LCDC_TCON_HSYNC_MASK);
876         }
877         sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
878 }
879 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
880
881 #ifdef CONFIG_VIDEO_HDMI
882
883 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
884 {
885         struct sunxi_hdmi_reg * const hdmi =
886                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
887         u8 checksum = 0;
888         u8 avi_info_frame[17] = {
889                 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
890                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
891                 0x00
892         };
893         u8 vendor_info_frame[19] = {
894                 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
895                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
896                 0x00, 0x00, 0x00
897         };
898         int i;
899
900         if (mode->pixclock_khz <= 27000)
901                 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
902         else
903                 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
904
905         if (mode->xres * 100 / mode->yres < 156)
906                 avi_info_frame[5] |= 0x18; /* 4 : 3 */
907         else
908                 avi_info_frame[5] |= 0x28; /* 16 : 9 */
909
910         for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
911                 checksum += avi_info_frame[i];
912
913         avi_info_frame[3] = 0x100 - checksum;
914
915         for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
916                 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
917
918         writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
919         writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
920
921         for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
922                 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
923
924         writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
925         writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
926
927         setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
928 }
929
930 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
931                                 int clk_div, int clk_double)
932 {
933         struct sunxi_hdmi_reg * const hdmi =
934                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
935         int x, y;
936
937         /* Write clear interrupt status bits */
938         writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
939
940         if (sunxi_display.monitor == sunxi_monitor_hdmi)
941                 sunxi_hdmi_setup_info_frames(mode);
942
943         /* Set input sync enable */
944         writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
945
946         /* Init various registers, select pll3 as clock source */
947         writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
948         writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
949         writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
950         writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
951         writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
952
953         /* Setup clk div and doubler */
954         clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
955                         SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
956         if (!clk_double)
957                 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
958
959         /* Setup timing registers */
960         writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
961                &hdmi->video_size);
962
963         x = mode->hsync_len + mode->left_margin;
964         y = mode->vsync_len + mode->upper_margin;
965         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
966
967         x = mode->right_margin;
968         y = mode->lower_margin;
969         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
970
971         x = mode->hsync_len;
972         y = mode->vsync_len;
973         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
974
975         if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
976                 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
977
978         if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
979                 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
980 }
981
982 static void sunxi_hdmi_enable(void)
983 {
984         struct sunxi_hdmi_reg * const hdmi =
985                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
986
987         udelay(100);
988         setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
989 }
990
991 #endif /* CONFIG_VIDEO_HDMI */
992
993 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
994
995 static void sunxi_tvencoder_mode_set(void)
996 {
997         struct sunxi_ccm_reg * const ccm =
998                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
999         struct sunxi_tve_reg * const tve =
1000                 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1001
1002         /* Clock on */
1003         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1004
1005         switch (sunxi_display.monitor) {
1006         case sunxi_monitor_vga:
1007                 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1008                        SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1009                        SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
1010                 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1011                 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1012                 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1013                 break;
1014         case sunxi_monitor_composite_pal_nc:
1015                 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1016                 /* Fall through */
1017         case sunxi_monitor_composite_pal:
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) |
1021                        SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1022                 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1023                 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1024                 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1025                 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1026                 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1027                 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1028                 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1029                 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1030                 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1031                 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1032                 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1033                 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1034                 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1035                 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1036                 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1037                 break;
1038         case sunxi_monitor_composite_pal_m:
1039                 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1040                 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1041                 /* Fall through */
1042         case sunxi_monitor_composite_ntsc:
1043                 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1044                        SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1045                        SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1046                        SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1047                 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1048                 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1049                 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1050                 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1051                 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1052                 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1053                 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1054                 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1055                 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1056                 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1057                 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1058                 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1059                 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1060                 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1061                 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1062                 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1063                 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1064                 break;
1065         case sunxi_monitor_none:
1066         case sunxi_monitor_dvi:
1067         case sunxi_monitor_hdmi:
1068         case sunxi_monitor_lcd:
1069                 break;
1070         }
1071 }
1072
1073 static void sunxi_tvencoder_enable(void)
1074 {
1075         struct sunxi_tve_reg * const tve =
1076                 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1077
1078         setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1079 }
1080
1081 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
1082
1083 static void sunxi_drc_init(void)
1084 {
1085 #ifdef CONFIG_SUNXI_GEN_SUN6I
1086         struct sunxi_ccm_reg * const ccm =
1087                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1088
1089         /* On sun6i the drc must be clocked even when in pass-through mode */
1090 #ifdef CONFIG_MACH_SUN8I_A33
1091         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1092 #endif
1093         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1094         clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1095 #endif
1096 }
1097
1098 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
1099 static void sunxi_vga_external_dac_enable(void)
1100 {
1101         int pin;
1102
1103         pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
1104         if (pin >= 0) {
1105                 gpio_request(pin, "vga_enable");
1106                 gpio_direction_output(pin, 1);
1107         }
1108 }
1109 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1110
1111 #ifdef CONFIG_VIDEO_LCD_SSD2828
1112 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1113 {
1114         struct ssd2828_config cfg = {
1115                 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1116                 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1117                 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1118                 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1119                 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1120                 .ssd2828_tx_clk_khz  = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1121                 .ssd2828_color_depth = 24,
1122 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1123                 .mipi_dsi_number_of_data_lanes           = 4,
1124                 .mipi_dsi_bitrate_per_data_lane_mbps     = 513,
1125                 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1126                 .mipi_dsi_delay_after_set_display_on_ms  = 200
1127 #else
1128 #error MIPI LCD panel needs configuration parameters
1129 #endif
1130         };
1131
1132         if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1133                 printf("SSD2828: SPI pins are not properly configured\n");
1134                 return 1;
1135         }
1136         if (cfg.reset_pin == -1) {
1137                 printf("SSD2828: Reset pin is not properly configured\n");
1138                 return 1;
1139         }
1140
1141         return ssd2828_init(&cfg, mode);
1142 }
1143 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
1144
1145 static void sunxi_engines_init(void)
1146 {
1147         sunxi_composer_init();
1148         sunxi_lcdc_init();
1149         sunxi_drc_init();
1150 }
1151
1152 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
1153                            unsigned int address)
1154 {
1155         int __maybe_unused clk_div, clk_double;
1156
1157         switch (sunxi_display.monitor) {
1158         case sunxi_monitor_none:
1159                 break;
1160         case sunxi_monitor_dvi:
1161         case sunxi_monitor_hdmi:
1162 #ifdef CONFIG_VIDEO_HDMI
1163                 sunxi_composer_mode_set(mode, address);
1164                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1165                 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1166                 sunxi_composer_enable();
1167                 sunxi_lcdc_enable();
1168                 sunxi_hdmi_enable();
1169 #endif
1170                 break;
1171         case sunxi_monitor_lcd:
1172                 sunxi_lcdc_panel_enable();
1173                 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1174                         mdelay(50); /* Wait for lcd controller power on */
1175                         hitachi_tx18d42vm_init();
1176                 }
1177                 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1178                         unsigned int orig_i2c_bus = i2c_get_bus_num();
1179                         i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1180                         i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1181                         i2c_set_bus_num(orig_i2c_bus);
1182                 }
1183                 sunxi_composer_mode_set(mode, address);
1184                 sunxi_lcdc_tcon0_mode_set(mode, false);
1185                 sunxi_composer_enable();
1186                 sunxi_lcdc_enable();
1187 #ifdef CONFIG_VIDEO_LCD_SSD2828
1188                 sunxi_ssd2828_init(mode);
1189 #endif
1190                 sunxi_lcdc_backlight_enable();
1191                 break;
1192         case sunxi_monitor_vga:
1193 #ifdef CONFIG_VIDEO_VGA
1194                 sunxi_composer_mode_set(mode, address);
1195                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1196                 sunxi_tvencoder_mode_set();
1197                 sunxi_composer_enable();
1198                 sunxi_lcdc_enable();
1199                 sunxi_tvencoder_enable();
1200 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1201                 sunxi_composer_mode_set(mode, address);
1202                 sunxi_lcdc_tcon0_mode_set(mode, true);
1203                 sunxi_composer_enable();
1204                 sunxi_lcdc_enable();
1205                 sunxi_vga_external_dac_enable();
1206 #endif
1207                 break;
1208         case sunxi_monitor_composite_pal:
1209         case sunxi_monitor_composite_ntsc:
1210         case sunxi_monitor_composite_pal_m:
1211         case sunxi_monitor_composite_pal_nc:
1212 #ifdef CONFIG_VIDEO_COMPOSITE
1213                 sunxi_composer_mode_set(mode, address);
1214                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1215                 sunxi_tvencoder_mode_set();
1216                 sunxi_composer_enable();
1217                 sunxi_lcdc_enable();
1218                 sunxi_tvencoder_enable();
1219 #endif
1220                 break;
1221         }
1222 }
1223
1224 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1225 {
1226         switch (monitor) {
1227         case sunxi_monitor_none:                return "none";
1228         case sunxi_monitor_dvi:                 return "dvi";
1229         case sunxi_monitor_hdmi:                return "hdmi";
1230         case sunxi_monitor_lcd:                 return "lcd";
1231         case sunxi_monitor_vga:                 return "vga";
1232         case sunxi_monitor_composite_pal:       return "composite-pal";
1233         case sunxi_monitor_composite_ntsc:      return "composite-ntsc";
1234         case sunxi_monitor_composite_pal_m:     return "composite-pal-m";
1235         case sunxi_monitor_composite_pal_nc:    return "composite-pal-nc";
1236         }
1237         return NULL; /* never reached */
1238 }
1239
1240 ulong board_get_usable_ram_top(ulong total_size)
1241 {
1242         return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1243 }
1244
1245 static bool sunxi_has_hdmi(void)
1246 {
1247 #ifdef CONFIG_VIDEO_HDMI
1248         return true;
1249 #else
1250         return false;
1251 #endif
1252 }
1253
1254 static bool sunxi_has_lcd(void)
1255 {
1256         char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1257
1258         return lcd_mode[0] != 0;
1259 }
1260
1261 static bool sunxi_has_vga(void)
1262 {
1263 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1264         return true;
1265 #else
1266         return false;
1267 #endif
1268 }
1269
1270 static bool sunxi_has_composite(void)
1271 {
1272 #ifdef CONFIG_VIDEO_COMPOSITE
1273         return true;
1274 #else
1275         return false;
1276 #endif
1277 }
1278
1279 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1280 {
1281         if (allow_hdmi && sunxi_has_hdmi())
1282                 return sunxi_monitor_dvi;
1283         else if (sunxi_has_lcd())
1284                 return sunxi_monitor_lcd;
1285         else if (sunxi_has_vga())
1286                 return sunxi_monitor_vga;
1287         else if (sunxi_has_composite())
1288                 return sunxi_monitor_composite_pal;
1289         else
1290                 return sunxi_monitor_none;
1291 }
1292
1293 void *video_hw_init(void)
1294 {
1295         static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1296         const struct ctfb_res_modes *mode;
1297         struct ctfb_res_modes custom;
1298         const char *options;
1299 #ifdef CONFIG_VIDEO_HDMI
1300         int ret, hpd, hpd_delay, edid;
1301 #endif
1302         int i, overscan_offset, overscan_x, overscan_y;
1303         unsigned int fb_dma_addr;
1304         char mon[16];
1305         char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1306
1307         memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1308
1309         video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1310                                  &sunxi_display.depth, &options);
1311 #ifdef CONFIG_VIDEO_HDMI
1312         hpd = video_get_option_int(options, "hpd", 1);
1313         hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1314         edid = video_get_option_int(options, "edid", 1);
1315 #endif
1316         overscan_x = video_get_option_int(options, "overscan_x", -1);
1317         overscan_y = video_get_option_int(options, "overscan_y", -1);
1318         sunxi_display.monitor = sunxi_get_default_mon(true);
1319         video_get_option_string(options, "monitor", mon, sizeof(mon),
1320                                 sunxi_get_mon_desc(sunxi_display.monitor));
1321         for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1322                 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1323                         sunxi_display.monitor = i;
1324                         break;
1325                 }
1326         }
1327         if (i > SUNXI_MONITOR_LAST)
1328                 printf("Unknown monitor: '%s', falling back to '%s'\n",
1329                        mon, sunxi_get_mon_desc(sunxi_display.monitor));
1330
1331 #ifdef CONFIG_VIDEO_HDMI
1332         /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1333         if (sunxi_display.monitor == sunxi_monitor_dvi ||
1334             sunxi_display.monitor == sunxi_monitor_hdmi) {
1335                 /* Always call hdp_detect, as it also enables clocks, etc. */
1336                 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1337                 if (ret) {
1338                         printf("HDMI connected: ");
1339                         if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1340                                 mode = &custom;
1341                 } else if (hpd) {
1342                         sunxi_hdmi_shutdown();
1343                         sunxi_display.monitor = sunxi_get_default_mon(false);
1344                 } /* else continue with hdmi/dvi without a cable connected */
1345         }
1346 #endif
1347
1348         switch (sunxi_display.monitor) {
1349         case sunxi_monitor_none:
1350                 return NULL;
1351         case sunxi_monitor_dvi:
1352         case sunxi_monitor_hdmi:
1353                 if (!sunxi_has_hdmi()) {
1354                         printf("HDMI/DVI not supported on this board\n");
1355                         sunxi_display.monitor = sunxi_monitor_none;
1356                         return NULL;
1357                 }
1358                 break;
1359         case sunxi_monitor_lcd:
1360                 if (!sunxi_has_lcd()) {
1361                         printf("LCD not supported on this board\n");
1362                         sunxi_display.monitor = sunxi_monitor_none;
1363                         return NULL;
1364                 }
1365                 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1366                 mode = &custom;
1367                 break;
1368         case sunxi_monitor_vga:
1369                 if (!sunxi_has_vga()) {
1370                         printf("VGA not supported on this board\n");
1371                         sunxi_display.monitor = sunxi_monitor_none;
1372                         return NULL;
1373                 }
1374                 sunxi_display.depth = 18;
1375                 break;
1376         case sunxi_monitor_composite_pal:
1377         case sunxi_monitor_composite_ntsc:
1378         case sunxi_monitor_composite_pal_m:
1379         case sunxi_monitor_composite_pal_nc:
1380                 if (!sunxi_has_composite()) {
1381                         printf("Composite video not supported on this board\n");
1382                         sunxi_display.monitor = sunxi_monitor_none;
1383                         return NULL;
1384                 }
1385                 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1386                     sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1387                         mode = &composite_video_modes[0];
1388                 else
1389                         mode = &composite_video_modes[1];
1390                 sunxi_display.depth = 24;
1391                 break;
1392         }
1393
1394         /* Yes these defaults are quite high, overscan on composite sucks... */
1395         if (overscan_x == -1)
1396                 overscan_x = sunxi_is_composite() ? 32 : 0;
1397         if (overscan_y == -1)
1398                 overscan_y = sunxi_is_composite() ? 20 : 0;
1399
1400         sunxi_display.fb_size =
1401                 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1402         overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1403         /* We want to keep the fb_base for simplefb page aligned, where as
1404          * the sunxi dma engines will happily accept an unaligned address. */
1405         if (overscan_offset)
1406                 sunxi_display.fb_size += 0x1000;
1407
1408         if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1409                 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1410                        sunxi_display.fb_size >> 10,
1411                        CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1412                 return NULL;
1413         }
1414
1415         printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1416                mode->xres, mode->yres,
1417                (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1418                sunxi_get_mon_desc(sunxi_display.monitor),
1419                overscan_x, overscan_y);
1420
1421         gd->fb_base = gd->bd->bi_dram[0].start +
1422                       gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1423         sunxi_engines_init();
1424
1425         fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1426         sunxi_display.fb_addr = gd->fb_base;
1427         if (overscan_offset) {
1428                 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1429                 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1430                 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1431                 flush_cache(gd->fb_base, sunxi_display.fb_size);
1432         }
1433         sunxi_mode_set(mode, fb_dma_addr);
1434
1435         /*
1436          * These are the only members of this structure that are used. All the
1437          * others are driver specific. The pitch is stored in plnSizeX.
1438          */
1439         graphic_device->frameAdrs = sunxi_display.fb_addr;
1440         graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1441         graphic_device->gdfBytesPP = 4;
1442         graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1443         graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1444         graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1445
1446         return graphic_device;
1447 }
1448
1449 /*
1450  * Simplefb support.
1451  */
1452 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1453 int sunxi_simplefb_setup(void *blob)
1454 {
1455         static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1456         int offset, ret;
1457         u64 start, size;
1458         const char *pipeline = NULL;
1459
1460 #ifdef CONFIG_MACH_SUN4I
1461 #define PIPELINE_PREFIX "de_fe0-"
1462 #else
1463 #define PIPELINE_PREFIX
1464 #endif
1465
1466         switch (sunxi_display.monitor) {
1467         case sunxi_monitor_none:
1468                 return 0;
1469         case sunxi_monitor_dvi:
1470         case sunxi_monitor_hdmi:
1471                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1472                 break;
1473         case sunxi_monitor_lcd:
1474                 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1475                 break;
1476         case sunxi_monitor_vga:
1477 #ifdef CONFIG_VIDEO_VGA
1478                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1479 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1480                 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1481 #endif
1482                 break;
1483         case sunxi_monitor_composite_pal:
1484         case sunxi_monitor_composite_ntsc:
1485         case sunxi_monitor_composite_pal_m:
1486         case sunxi_monitor_composite_pal_nc:
1487                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1488                 break;
1489         }
1490
1491         /* Find a prefilled simpefb node, matching out pipeline config */
1492         offset = fdt_node_offset_by_compatible(blob, -1,
1493                                                "allwinner,simple-framebuffer");
1494         while (offset >= 0) {
1495                 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
1496                                       pipeline);
1497                 if (ret == 0)
1498                         break;
1499                 offset = fdt_node_offset_by_compatible(blob, offset,
1500                                                "allwinner,simple-framebuffer");
1501         }
1502         if (offset < 0) {
1503                 eprintf("Cannot setup simplefb: node not found\n");
1504                 return 0; /* Keep older kernels working */
1505         }
1506
1507         /*
1508          * Do not report the framebuffer as free RAM to the OS, note we cannot
1509          * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1510          * and e.g. Linux refuses to iomap RAM on ARM, see:
1511          * linux/arch/arm/mm/ioremap.c around line 301.
1512          */
1513         start = gd->bd->bi_dram[0].start;
1514         size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1515         ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1516         if (ret) {
1517                 eprintf("Cannot setup simplefb: Error reserving memory\n");
1518                 return ret;
1519         }
1520
1521         ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1522                         graphic_device->winSizeX, graphic_device->winSizeY,
1523                         graphic_device->plnSizeX, "x8r8g8b8");
1524         if (ret)
1525                 eprintf("Cannot setup simplefb: Error setting properties\n");
1526
1527         return ret;
1528 }
1529 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */