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