2 * Display driver for Allwinner SoCs.
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
5 * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
7 * SPDX-License-Identifier: GPL-2.0+
12 #include <asm/arch/clock.h>
13 #include <asm/arch/display.h>
14 #include <asm/arch/gpio.h>
15 #include <asm/global_data.h>
20 #include <fdt_support.h>
22 #include "videomodes.h"
23 #include "hitachi_tx18d42vm_lcd.h"
26 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
34 DECLARE_GLOBAL_DATA_PTR;
43 #define SUNXI_MONITOR_LAST sunxi_monitor_vga
45 struct sunxi_display {
46 GraphicDevice graphic_device;
47 enum sunxi_monitor monitor;
52 #ifdef CONFIG_VIDEO_HDMI
55 * Wait up to 200ms for value to be set in given part of reg.
57 static int await_completion(u32 *reg, u32 mask, u32 val)
59 unsigned long tmo = timer_get_us() + 200000;
61 while ((readl(reg) & mask) != val) {
62 if (timer_get_us() > tmo) {
63 printf("DDC: timeout reading EDID\n");
70 static int sunxi_hdmi_hpd_detect(int hpd_delay)
72 struct sunxi_ccm_reg * const ccm =
73 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
74 struct sunxi_hdmi_reg * const hdmi =
75 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
76 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
78 /* Set pll3 to 300MHz */
79 clock_set_pll3(300000000);
81 /* Set hdmi parent to pll3 */
82 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
85 /* Set ahb gating to pass */
86 #ifdef CONFIG_MACH_SUN6I
87 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
89 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
92 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
94 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
95 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
97 while (timer_get_us() < tmo) {
98 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
105 static void sunxi_hdmi_shutdown(void)
107 struct sunxi_ccm_reg * const ccm =
108 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
109 struct sunxi_hdmi_reg * const hdmi =
110 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
112 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
113 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
114 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
115 #ifdef CONFIG_MACH_SUN6I
116 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
121 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
123 struct sunxi_hdmi_reg * const hdmi =
124 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
126 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
127 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
128 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
129 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
130 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
131 #ifndef CONFIG_MACH_SUN6I
132 writel(n, &hdmi->ddc_byte_count);
133 writel(cmnd, &hdmi->ddc_cmnd);
135 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
137 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
139 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
142 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
144 struct sunxi_hdmi_reg * const hdmi =
145 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
154 if (sunxi_hdmi_ddc_do_command(
155 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
159 for (i = 0; i < n; i++)
160 *buf++ = readb(&hdmi->ddc_fifo_data);
169 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
174 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
177 r = edid_check_checksum(buf);
179 printf("EDID block %d: checksum error%s\n",
180 block, retries ? ", retrying" : "");
182 } while (r && retries--);
187 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
189 struct edid1_info edid1;
190 struct edid_cea861_info cea681[4];
191 struct edid_detailed_timing *t =
192 (struct edid_detailed_timing *)edid1.monitor_details.timing;
193 struct sunxi_hdmi_reg * const hdmi =
194 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
195 struct sunxi_ccm_reg * const ccm =
196 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
197 int i, r, ext_blocks = 0;
199 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
200 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
202 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
204 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
206 /* Reset i2c controller */
207 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
208 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
209 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
210 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
211 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
212 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
215 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
216 #ifndef CONFIG_MACH_SUN6I
217 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
218 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
221 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
223 r = edid_check_info(&edid1);
225 printf("EDID: invalid EDID data\n");
230 ext_blocks = edid1.extension_flag;
233 for (i = 0; i < ext_blocks; i++) {
234 if (sunxi_hdmi_edid_get_block(1 + i,
235 (u8 *)&cea681[i]) != 0) {
242 /* Disable DDC engine, no longer needed */
243 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
244 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
249 /* We want version 1.3 or 1.2 with detailed timing info */
250 if (edid1.version != 1 || (edid1.revision < 3 &&
251 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
252 printf("EDID: unsupported version %d.%d\n",
253 edid1.version, edid1.revision);
257 /* Take the first usable detailed timing */
258 for (i = 0; i < 4; i++, t++) {
259 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
264 printf("EDID: no usable detailed timing found\n");
268 /* Check for basic audio support, if found enable hdmi output */
269 sunxi_display.monitor = sunxi_monitor_dvi;
270 for (i = 0; i < ext_blocks; i++) {
271 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
272 cea681[i].revision < 2)
275 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
276 sunxi_display.monitor = sunxi_monitor_hdmi;
282 #endif /* CONFIG_VIDEO_HDMI */
284 #ifdef CONFIG_MACH_SUN4I
286 * Testing has shown that on sun4i the display backend engine does not have
287 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
288 * fifo underruns. So on sun4i we use the display frontend engine to do the
289 * dma from memory, as the frontend does have deep enough fifo-s.
292 static const u32 sun4i_vert_coef[32] = {
293 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
294 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
295 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
296 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
297 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
298 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
299 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
300 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
303 static const u32 sun4i_horz_coef[64] = {
304 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
305 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
306 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
307 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
308 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
309 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
310 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
311 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
312 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
313 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
314 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
315 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
316 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
317 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
318 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
319 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
322 static void sunxi_frontend_init(void)
324 struct sunxi_ccm_reg * const ccm =
325 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
326 struct sunxi_de_fe_reg * const de_fe =
327 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
331 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
332 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
333 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
335 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
337 for (i = 0; i < 32; i++) {
338 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
339 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
340 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
341 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
342 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
343 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
346 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
349 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
350 unsigned int address)
352 struct sunxi_de_fe_reg * const de_fe =
353 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
355 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
356 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
357 writel(mode->xres * 4, &de_fe->ch0_stride);
358 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
359 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
361 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
363 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
364 &de_fe->ch0_outsize);
365 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
366 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
368 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
370 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
371 &de_fe->ch1_outsize);
372 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
373 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
375 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
378 static void sunxi_frontend_enable(void)
380 struct sunxi_de_fe_reg * const de_fe =
381 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
383 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
386 static void sunxi_frontend_init(void) {}
387 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
388 unsigned int address) {}
389 static void sunxi_frontend_enable(void) {}
393 * This is the entity that mixes and matches the different layers and inputs.
394 * Allwinner calls it the back-end, but i like composer better.
396 static void sunxi_composer_init(void)
398 struct sunxi_ccm_reg * const ccm =
399 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
400 struct sunxi_de_be_reg * const de_be =
401 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
404 sunxi_frontend_init();
406 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
408 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
412 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
413 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
414 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
416 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
418 /* Engine bug, clear registers after reset */
419 for (i = 0x0800; i < 0x1000; i += 4)
420 writel(0, SUNXI_DE_BE0_BASE + i);
422 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
425 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
426 unsigned int address)
428 struct sunxi_de_be_reg * const de_be =
429 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
431 sunxi_frontend_mode_set(mode, address);
433 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
435 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
436 &de_be->layer0_size);
437 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
438 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
439 writel(address << 3, &de_be->layer0_addr_low32b);
440 writel(address >> 29, &de_be->layer0_addr_high4b);
442 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
444 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
446 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
449 static void sunxi_composer_enable(void)
451 struct sunxi_de_be_reg * const de_be =
452 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
454 sunxi_frontend_enable();
456 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
457 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
461 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
463 static void sunxi_lcdc_pll_set(int tcon, int dotclock,
464 int *clk_div, int *clk_double)
466 struct sunxi_ccm_reg * const ccm =
467 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
468 int value, n, m, min_m, max_m, diff;
469 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
473 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
477 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
486 * Find the lowest divider resulting in a matching clock, if there
487 * is no match, pick the closest lower clock, as monitors tend to
488 * not sync to higher frequencies.
490 for (m = min_m; m <= max_m; m++) {
491 n = (m * dotclock) / 3000;
493 if ((n >= 9) && (n <= 127)) {
494 value = (3000 * n) / m;
495 diff = dotclock - value;
496 if (diff < best_diff) {
504 /* These are just duplicates */
508 n = (m * dotclock) / 6000;
509 if ((n >= 9) && (n <= 127)) {
510 value = (6000 * n) / m;
511 diff = dotclock - value;
512 if (diff < best_diff) {
521 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
522 dotclock, (best_double + 1) * 3000 * best_n / best_m,
523 best_double + 1, best_n, best_m);
525 clock_set_pll3(best_n * 3000000);
528 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
529 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
530 CCM_LCD_CH0_CTRL_PLL3),
531 &ccm->lcd0_ch0_clk_cfg);
533 writel(CCM_LCD_CH1_CTRL_GATE |
534 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
535 CCM_LCD_CH1_CTRL_PLL3) |
536 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
540 *clk_double = best_double;
543 static void sunxi_lcdc_init(void)
545 struct sunxi_ccm_reg * const ccm =
546 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
547 struct sunxi_lcdc_reg * const lcdc =
548 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
551 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
552 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
554 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
558 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
559 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
560 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
564 writel(0, &lcdc->ctrl); /* Disable tcon */
565 writel(0, &lcdc->int0); /* Disable all interrupts */
567 /* Disable tcon0 dot clock */
568 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
570 /* Set all io lines to tristate */
571 writel(0xffffffff, &lcdc->tcon0_io_tristate);
572 writel(0xffffffff, &lcdc->tcon1_io_tristate);
575 static void sunxi_lcdc_enable(void)
577 struct sunxi_lcdc_reg * const lcdc =
578 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
580 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
581 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
582 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
583 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
584 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
585 udelay(2); /* delay at least 1200 ns */
586 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
587 udelay(1); /* delay at least 120 ns */
588 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
589 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
593 static void sunxi_lcdc_panel_enable(void)
598 * Start with backlight disabled to avoid the screen flashing to
599 * white while the lcd inits.
601 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
603 gpio_request(pin, "lcd_backlight_enable");
604 gpio_direction_output(pin, 0);
607 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
609 gpio_request(pin, "lcd_backlight_pwm");
610 gpio_direction_output(pin, PWM_OFF);
613 /* Give the backlight some time to turn off and power up the panel. */
615 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
617 gpio_request(pin, "lcd_power");
618 gpio_direction_output(pin, 1);
622 static void sunxi_lcdc_backlight_enable(void)
627 * We want to have scanned out at least one frame before enabling the
628 * backlight to avoid the screen flashing to white when we enable it.
632 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
634 gpio_direction_output(pin, 1);
636 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
638 gpio_direction_output(pin, PWM_ON);
641 static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
645 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
646 return (delay > 30) ? 30 : delay;
649 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
650 bool for_ext_vga_dac)
652 struct sunxi_lcdc_reg * const lcdc =
653 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
654 int bp, clk_delay, clk_div, clk_double, pin, total, val;
656 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
657 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
658 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0);
660 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
661 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0);
664 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
667 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
668 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
670 clk_delay = sunxi_lcdc_get_clk_delay(mode);
671 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
672 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
674 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
675 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
677 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
678 &lcdc->tcon0_timing_active);
680 bp = mode->hsync_len + mode->left_margin;
681 total = mode->xres + mode->right_margin + bp;
682 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
683 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
685 bp = mode->vsync_len + mode->upper_margin;
686 total = mode->yres + mode->lower_margin + bp;
687 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
688 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
690 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
691 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
692 &lcdc->tcon0_timing_sync);
694 writel(0, &lcdc->tcon0_hv_intf);
695 writel(0, &lcdc->tcon0_cpu_intf);
697 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
698 val = (sunxi_display.depth == 18) ? 1 : 0;
699 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf);
702 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
703 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
704 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
705 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
706 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
707 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
708 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
709 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
710 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
711 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
712 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
713 writel(((sunxi_display.depth == 18) ?
714 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
715 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
716 &lcdc->tcon0_frm_ctrl);
719 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
720 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
721 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
722 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
723 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
725 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
729 writel(val, &lcdc->tcon0_io_polarity);
731 writel(0, &lcdc->tcon0_io_tristate);
734 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
735 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
736 int *clk_div, int *clk_double,
737 bool use_portd_hvsync)
739 struct sunxi_lcdc_reg * const lcdc =
740 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
741 int bp, clk_delay, total, val;
744 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
745 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
747 clk_delay = sunxi_lcdc_get_clk_delay(mode);
748 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
749 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
751 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
752 &lcdc->tcon1_timing_source);
753 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
754 &lcdc->tcon1_timing_scale);
755 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
756 &lcdc->tcon1_timing_out);
758 bp = mode->hsync_len + mode->left_margin;
759 total = mode->xres + mode->right_margin + bp;
760 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
761 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
763 bp = mode->vsync_len + mode->upper_margin;
764 total = mode->yres + mode->lower_margin + bp;
765 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
766 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
768 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
769 &lcdc->tcon1_timing_sync);
771 if (use_portd_hvsync) {
772 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD0_LCD0);
773 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD0_LCD0);
776 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
777 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
778 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
779 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
780 writel(val, &lcdc->tcon1_io_polarity);
782 clrbits_le32(&lcdc->tcon1_io_tristate,
783 SUNXI_LCDC_TCON_VSYNC_MASK |
784 SUNXI_LCDC_TCON_HSYNC_MASK);
786 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
788 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
790 #ifdef CONFIG_VIDEO_HDMI
792 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
794 struct sunxi_hdmi_reg * const hdmi =
795 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
797 u8 avi_info_frame[17] = {
798 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802 u8 vendor_info_frame[19] = {
803 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 if (mode->pixclock_khz <= 27000)
810 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
812 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
814 if (mode->xres * 100 / mode->yres < 156)
815 avi_info_frame[5] |= 0x18; /* 4 : 3 */
817 avi_info_frame[5] |= 0x28; /* 16 : 9 */
819 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
820 checksum += avi_info_frame[i];
822 avi_info_frame[3] = 0x100 - checksum;
824 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
825 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
827 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
828 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
830 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
831 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
833 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
834 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
836 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
839 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
840 int clk_div, int clk_double)
842 struct sunxi_hdmi_reg * const hdmi =
843 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
846 /* Write clear interrupt status bits */
847 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
849 if (sunxi_display.monitor == sunxi_monitor_hdmi)
850 sunxi_hdmi_setup_info_frames(mode);
852 /* Set input sync enable */
853 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
855 /* Init various registers, select pll3 as clock source */
856 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
857 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
858 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
859 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
860 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
862 /* Setup clk div and doubler */
863 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
864 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
866 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
868 /* Setup timing registers */
869 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
872 x = mode->hsync_len + mode->left_margin;
873 y = mode->vsync_len + mode->upper_margin;
874 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
876 x = mode->right_margin;
877 y = mode->lower_margin;
878 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
882 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
884 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
885 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
887 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
888 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
891 static void sunxi_hdmi_enable(void)
893 struct sunxi_hdmi_reg * const hdmi =
894 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
897 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
900 #endif /* CONFIG_VIDEO_HDMI */
902 #ifdef CONFIG_VIDEO_VGA
904 static void sunxi_vga_mode_set(void)
906 struct sunxi_ccm_reg * const ccm =
907 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
908 struct sunxi_tve_reg * const tve =
909 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
912 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
914 /* Set TVE in VGA mode */
915 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
916 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
917 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
918 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
919 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
920 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
923 static void sunxi_vga_enable(void)
925 struct sunxi_tve_reg * const tve =
926 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
928 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
931 #endif /* CONFIG_VIDEO_VGA */
933 static void sunxi_drc_init(void)
935 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
936 struct sunxi_ccm_reg * const ccm =
937 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
939 /* On sun6i the drc must be clocked even when in pass-through mode */
940 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
941 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
945 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
946 static void sunxi_vga_external_dac_enable(void)
950 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
952 gpio_request(pin, "vga_enable");
953 gpio_direction_output(pin, 1);
956 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
958 #ifdef CONFIG_VIDEO_LCD_SSD2828
959 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
961 struct ssd2828_config cfg = {
962 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
963 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
964 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
965 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
966 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
967 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
968 .ssd2828_color_depth = 24,
969 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
970 .mipi_dsi_number_of_data_lanes = 4,
971 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
972 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
973 .mipi_dsi_delay_after_set_display_on_ms = 200
975 #error MIPI LCD panel needs configuration parameters
979 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
980 printf("SSD2828: SPI pins are not properly configured\n");
983 if (cfg.reset_pin == -1) {
984 printf("SSD2828: Reset pin is not properly configured\n");
988 return ssd2828_init(&cfg, mode);
990 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
992 static void sunxi_engines_init(void)
994 sunxi_composer_init();
999 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
1000 unsigned int address)
1002 int __maybe_unused clk_div, clk_double;
1004 switch (sunxi_display.monitor) {
1005 case sunxi_monitor_none:
1007 case sunxi_monitor_dvi:
1008 case sunxi_monitor_hdmi:
1009 #ifdef CONFIG_VIDEO_HDMI
1010 sunxi_composer_mode_set(mode, address);
1011 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1012 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1013 sunxi_composer_enable();
1014 sunxi_lcdc_enable();
1015 sunxi_hdmi_enable();
1018 case sunxi_monitor_lcd:
1019 sunxi_lcdc_panel_enable();
1020 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1021 mdelay(50); /* Wait for lcd controller power on */
1022 hitachi_tx18d42vm_init();
1024 sunxi_composer_mode_set(mode, address);
1025 sunxi_lcdc_tcon0_mode_set(mode, false);
1026 sunxi_composer_enable();
1027 sunxi_lcdc_enable();
1028 #ifdef CONFIG_VIDEO_LCD_SSD2828
1029 sunxi_ssd2828_init(mode);
1031 sunxi_lcdc_backlight_enable();
1033 case sunxi_monitor_vga:
1034 #ifdef CONFIG_VIDEO_VGA
1035 sunxi_composer_mode_set(mode, address);
1036 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1037 sunxi_vga_mode_set();
1038 sunxi_composer_enable();
1039 sunxi_lcdc_enable();
1041 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1042 sunxi_composer_mode_set(mode, address);
1043 sunxi_lcdc_tcon0_mode_set(mode, true);
1044 sunxi_composer_enable();
1045 sunxi_lcdc_enable();
1046 sunxi_vga_external_dac_enable();
1052 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1055 case sunxi_monitor_none: return "none";
1056 case sunxi_monitor_dvi: return "dvi";
1057 case sunxi_monitor_hdmi: return "hdmi";
1058 case sunxi_monitor_lcd: return "lcd";
1059 case sunxi_monitor_vga: return "vga";
1061 return NULL; /* never reached */
1064 ulong board_get_usable_ram_top(ulong total_size)
1066 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1069 void *video_hw_init(void)
1071 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1072 const struct ctfb_res_modes *mode;
1073 struct ctfb_res_modes custom;
1074 const char *options;
1075 #ifdef CONFIG_VIDEO_HDMI
1076 int ret, hpd, hpd_delay, edid;
1079 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1082 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1084 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1085 &sunxi_display.depth, &options);
1086 #ifdef CONFIG_VIDEO_HDMI
1087 hpd = video_get_option_int(options, "hpd", 1);
1088 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1089 edid = video_get_option_int(options, "edid", 1);
1090 sunxi_display.monitor = sunxi_monitor_dvi;
1091 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1092 sunxi_display.monitor = sunxi_monitor_vga;
1094 sunxi_display.monitor = sunxi_monitor_lcd;
1096 video_get_option_string(options, "monitor", mon, sizeof(mon),
1097 sunxi_get_mon_desc(sunxi_display.monitor));
1098 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1099 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1100 sunxi_display.monitor = i;
1104 if (i > SUNXI_MONITOR_LAST)
1105 printf("Unknown monitor: '%s', falling back to '%s'\n",
1106 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1108 #ifdef CONFIG_VIDEO_HDMI
1109 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1110 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1111 sunxi_display.monitor == sunxi_monitor_hdmi) {
1112 /* Always call hdp_detect, as it also enables clocks, etc. */
1113 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1115 printf("HDMI connected: ");
1116 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1119 sunxi_hdmi_shutdown();
1120 /* Fallback to lcd / vga / none */
1122 sunxi_display.monitor = sunxi_monitor_lcd;
1124 #if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
1125 sunxi_display.monitor = sunxi_monitor_vga;
1127 sunxi_display.monitor = sunxi_monitor_none;
1130 } /* else continue with hdmi/dvi without a cable connected */
1134 switch (sunxi_display.monitor) {
1135 case sunxi_monitor_none:
1137 case sunxi_monitor_dvi:
1138 case sunxi_monitor_hdmi:
1139 #ifdef CONFIG_VIDEO_HDMI
1142 printf("HDMI/DVI not supported on this board\n");
1143 sunxi_display.monitor = sunxi_monitor_none;
1146 case sunxi_monitor_lcd:
1148 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1152 printf("LCD not supported on this board\n");
1153 sunxi_display.monitor = sunxi_monitor_none;
1155 case sunxi_monitor_vga:
1156 #if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
1157 sunxi_display.depth = 18;
1160 printf("VGA not supported on this board\n");
1161 sunxi_display.monitor = sunxi_monitor_none;
1166 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1167 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1168 mode = &res_mode_init[RES_MODE_1024x768];
1170 printf("Setting up a %dx%d %s console\n", mode->xres,
1171 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
1174 sunxi_display.fb_size =
1175 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1176 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1177 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1178 sunxi_display.fb_size >> 10,
1179 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1183 gd->fb_base = gd->bd->bi_dram[0].start +
1184 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1185 sunxi_engines_init();
1186 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
1189 * These are the only members of this structure that are used. All the
1190 * others are driver specific. There is nothing to decribe pitch or
1191 * stride, but we are lucky with our hw.
1193 graphic_device->frameAdrs = gd->fb_base;
1194 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1195 graphic_device->gdfBytesPP = 4;
1196 graphic_device->winSizeX = mode->xres;
1197 graphic_device->winSizeY = mode->yres;
1199 return graphic_device;
1205 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1206 int sunxi_simplefb_setup(void *blob)
1208 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1211 const char *pipeline = NULL;
1213 #ifdef CONFIG_MACH_SUN4I
1214 #define PIPELINE_PREFIX "de_fe0-"
1216 #define PIPELINE_PREFIX
1219 switch (sunxi_display.monitor) {
1220 case sunxi_monitor_none:
1222 case sunxi_monitor_dvi:
1223 case sunxi_monitor_hdmi:
1224 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1226 case sunxi_monitor_lcd:
1227 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1229 case sunxi_monitor_vga:
1230 #ifdef CONFIG_VIDEO_VGA
1231 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1232 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1233 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1238 /* Find a prefilled simpefb node, matching out pipeline config */
1239 offset = fdt_node_offset_by_compatible(blob, -1,
1240 "allwinner,simple-framebuffer");
1241 while (offset >= 0) {
1242 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
1246 offset = fdt_node_offset_by_compatible(blob, offset,
1247 "allwinner,simple-framebuffer");
1250 eprintf("Cannot setup simplefb: node not found\n");
1251 return 0; /* Keep older kernels working */
1255 * Do not report the framebuffer as free RAM to the OS, note we cannot
1256 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1257 * and e.g. Linux refuses to iomap RAM on ARM, see:
1258 * linux/arch/arm/mm/ioremap.c around line 301.
1260 start = gd->bd->bi_dram[0].start;
1261 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1262 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1264 eprintf("Cannot setup simplefb: Error reserving memory\n");
1268 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1269 graphic_device->winSizeX, graphic_device->winSizeY,
1270 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1273 eprintf("Cannot setup simplefb: Error setting properties\n");
1277 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */