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 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
614 if (reset_pin != -1) {
615 gpio_request(reset_pin, "lcd_reset");
616 gpio_direction_output(reset_pin, 0); /* Assert reset */
619 /* Give the backlight some time to turn off and power up the panel. */
621 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
623 gpio_request(pin, "lcd_power");
624 gpio_direction_output(pin, 1);
628 gpio_direction_output(reset_pin, 1); /* De-assert reset */
631 static void sunxi_lcdc_backlight_enable(void)
636 * We want to have scanned out at least one frame before enabling the
637 * backlight to avoid the screen flashing to white when we enable it.
641 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
643 gpio_direction_output(pin, 1);
645 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
647 gpio_direction_output(pin, PWM_ON);
650 static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
654 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
655 return (delay > 30) ? 30 : delay;
658 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
659 bool for_ext_vga_dac)
661 struct sunxi_lcdc_reg * const lcdc =
662 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
663 int bp, clk_delay, clk_div, clk_double, pin, total, val;
665 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
666 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
667 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0);
669 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
670 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0);
673 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
676 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
677 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
679 clk_delay = sunxi_lcdc_get_clk_delay(mode);
680 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
681 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
683 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
684 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
686 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
687 &lcdc->tcon0_timing_active);
689 bp = mode->hsync_len + mode->left_margin;
690 total = mode->xres + mode->right_margin + bp;
691 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
692 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
694 bp = mode->vsync_len + mode->upper_margin;
695 total = mode->yres + mode->lower_margin + bp;
696 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
697 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
699 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
700 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
701 &lcdc->tcon0_timing_sync);
703 writel(0, &lcdc->tcon0_hv_intf);
704 writel(0, &lcdc->tcon0_cpu_intf);
706 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
707 val = (sunxi_display.depth == 18) ? 1 : 0;
708 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf);
711 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
712 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
713 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
714 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
715 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
716 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
717 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
718 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
719 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
720 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
721 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
722 writel(((sunxi_display.depth == 18) ?
723 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
724 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
725 &lcdc->tcon0_frm_ctrl);
728 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
729 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
730 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
731 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
732 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
734 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
738 writel(val, &lcdc->tcon0_io_polarity);
740 writel(0, &lcdc->tcon0_io_tristate);
743 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
744 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
745 int *clk_div, int *clk_double,
746 bool use_portd_hvsync)
748 struct sunxi_lcdc_reg * const lcdc =
749 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
750 int bp, clk_delay, total, val;
753 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
754 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
756 clk_delay = sunxi_lcdc_get_clk_delay(mode);
757 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
758 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
760 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
761 &lcdc->tcon1_timing_source);
762 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
763 &lcdc->tcon1_timing_scale);
764 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
765 &lcdc->tcon1_timing_out);
767 bp = mode->hsync_len + mode->left_margin;
768 total = mode->xres + mode->right_margin + bp;
769 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
770 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
772 bp = mode->vsync_len + mode->upper_margin;
773 total = mode->yres + mode->lower_margin + bp;
774 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
775 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
777 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
778 &lcdc->tcon1_timing_sync);
780 if (use_portd_hvsync) {
781 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD0_LCD0);
782 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD0_LCD0);
785 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
786 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
787 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
788 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
789 writel(val, &lcdc->tcon1_io_polarity);
791 clrbits_le32(&lcdc->tcon1_io_tristate,
792 SUNXI_LCDC_TCON_VSYNC_MASK |
793 SUNXI_LCDC_TCON_HSYNC_MASK);
795 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
797 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
799 #ifdef CONFIG_VIDEO_HDMI
801 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
803 struct sunxi_hdmi_reg * const hdmi =
804 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
806 u8 avi_info_frame[17] = {
807 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 u8 vendor_info_frame[19] = {
812 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 if (mode->pixclock_khz <= 27000)
819 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
821 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
823 if (mode->xres * 100 / mode->yres < 156)
824 avi_info_frame[5] |= 0x18; /* 4 : 3 */
826 avi_info_frame[5] |= 0x28; /* 16 : 9 */
828 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
829 checksum += avi_info_frame[i];
831 avi_info_frame[3] = 0x100 - checksum;
833 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
834 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
836 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
837 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
839 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
840 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
842 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
843 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
845 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
848 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
849 int clk_div, int clk_double)
851 struct sunxi_hdmi_reg * const hdmi =
852 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
855 /* Write clear interrupt status bits */
856 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
858 if (sunxi_display.monitor == sunxi_monitor_hdmi)
859 sunxi_hdmi_setup_info_frames(mode);
861 /* Set input sync enable */
862 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
864 /* Init various registers, select pll3 as clock source */
865 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
866 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
867 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
868 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
869 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
871 /* Setup clk div and doubler */
872 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
873 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
875 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
877 /* Setup timing registers */
878 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
881 x = mode->hsync_len + mode->left_margin;
882 y = mode->vsync_len + mode->upper_margin;
883 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
885 x = mode->right_margin;
886 y = mode->lower_margin;
887 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
891 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
893 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
894 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
896 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
897 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
900 static void sunxi_hdmi_enable(void)
902 struct sunxi_hdmi_reg * const hdmi =
903 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
906 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
909 #endif /* CONFIG_VIDEO_HDMI */
911 #ifdef CONFIG_VIDEO_VGA
913 static void sunxi_vga_mode_set(void)
915 struct sunxi_ccm_reg * const ccm =
916 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
917 struct sunxi_tve_reg * const tve =
918 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
921 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
923 /* Set TVE in VGA mode */
924 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
925 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
926 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
927 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
928 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
929 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
932 static void sunxi_vga_enable(void)
934 struct sunxi_tve_reg * const tve =
935 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
937 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
940 #endif /* CONFIG_VIDEO_VGA */
942 static void sunxi_drc_init(void)
944 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
945 struct sunxi_ccm_reg * const ccm =
946 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
948 /* On sun6i the drc must be clocked even when in pass-through mode */
949 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
950 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
954 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
955 static void sunxi_vga_external_dac_enable(void)
959 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
961 gpio_request(pin, "vga_enable");
962 gpio_direction_output(pin, 1);
965 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
967 #ifdef CONFIG_VIDEO_LCD_SSD2828
968 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
970 struct ssd2828_config cfg = {
971 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
972 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
973 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
974 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
975 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
976 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
977 .ssd2828_color_depth = 24,
978 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
979 .mipi_dsi_number_of_data_lanes = 4,
980 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
981 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
982 .mipi_dsi_delay_after_set_display_on_ms = 200
984 #error MIPI LCD panel needs configuration parameters
988 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
989 printf("SSD2828: SPI pins are not properly configured\n");
992 if (cfg.reset_pin == -1) {
993 printf("SSD2828: Reset pin is not properly configured\n");
997 return ssd2828_init(&cfg, mode);
999 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
1001 static void sunxi_engines_init(void)
1003 sunxi_composer_init();
1008 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
1009 unsigned int address)
1011 int __maybe_unused clk_div, clk_double;
1013 switch (sunxi_display.monitor) {
1014 case sunxi_monitor_none:
1016 case sunxi_monitor_dvi:
1017 case sunxi_monitor_hdmi:
1018 #ifdef CONFIG_VIDEO_HDMI
1019 sunxi_composer_mode_set(mode, address);
1020 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1021 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1022 sunxi_composer_enable();
1023 sunxi_lcdc_enable();
1024 sunxi_hdmi_enable();
1027 case sunxi_monitor_lcd:
1028 sunxi_lcdc_panel_enable();
1029 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1030 mdelay(50); /* Wait for lcd controller power on */
1031 hitachi_tx18d42vm_init();
1033 sunxi_composer_mode_set(mode, address);
1034 sunxi_lcdc_tcon0_mode_set(mode, false);
1035 sunxi_composer_enable();
1036 sunxi_lcdc_enable();
1037 #ifdef CONFIG_VIDEO_LCD_SSD2828
1038 sunxi_ssd2828_init(mode);
1040 sunxi_lcdc_backlight_enable();
1042 case sunxi_monitor_vga:
1043 #ifdef CONFIG_VIDEO_VGA
1044 sunxi_composer_mode_set(mode, address);
1045 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1046 sunxi_vga_mode_set();
1047 sunxi_composer_enable();
1048 sunxi_lcdc_enable();
1050 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1051 sunxi_composer_mode_set(mode, address);
1052 sunxi_lcdc_tcon0_mode_set(mode, true);
1053 sunxi_composer_enable();
1054 sunxi_lcdc_enable();
1055 sunxi_vga_external_dac_enable();
1061 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1064 case sunxi_monitor_none: return "none";
1065 case sunxi_monitor_dvi: return "dvi";
1066 case sunxi_monitor_hdmi: return "hdmi";
1067 case sunxi_monitor_lcd: return "lcd";
1068 case sunxi_monitor_vga: return "vga";
1070 return NULL; /* never reached */
1073 ulong board_get_usable_ram_top(ulong total_size)
1075 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1078 void *video_hw_init(void)
1080 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1081 const struct ctfb_res_modes *mode;
1082 struct ctfb_res_modes custom;
1083 const char *options;
1084 #ifdef CONFIG_VIDEO_HDMI
1085 int ret, hpd, hpd_delay, edid;
1088 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1091 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1093 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1094 &sunxi_display.depth, &options);
1095 #ifdef CONFIG_VIDEO_HDMI
1096 hpd = video_get_option_int(options, "hpd", 1);
1097 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1098 edid = video_get_option_int(options, "edid", 1);
1099 sunxi_display.monitor = sunxi_monitor_dvi;
1100 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1101 sunxi_display.monitor = sunxi_monitor_vga;
1103 sunxi_display.monitor = sunxi_monitor_lcd;
1105 video_get_option_string(options, "monitor", mon, sizeof(mon),
1106 sunxi_get_mon_desc(sunxi_display.monitor));
1107 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1108 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1109 sunxi_display.monitor = i;
1113 if (i > SUNXI_MONITOR_LAST)
1114 printf("Unknown monitor: '%s', falling back to '%s'\n",
1115 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1117 #ifdef CONFIG_VIDEO_HDMI
1118 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1119 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1120 sunxi_display.monitor == sunxi_monitor_hdmi) {
1121 /* Always call hdp_detect, as it also enables clocks, etc. */
1122 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1124 printf("HDMI connected: ");
1125 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1128 sunxi_hdmi_shutdown();
1129 /* Fallback to lcd / vga / none */
1131 sunxi_display.monitor = sunxi_monitor_lcd;
1133 #if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
1134 sunxi_display.monitor = sunxi_monitor_vga;
1136 sunxi_display.monitor = sunxi_monitor_none;
1139 } /* else continue with hdmi/dvi without a cable connected */
1143 switch (sunxi_display.monitor) {
1144 case sunxi_monitor_none:
1146 case sunxi_monitor_dvi:
1147 case sunxi_monitor_hdmi:
1148 #ifdef CONFIG_VIDEO_HDMI
1151 printf("HDMI/DVI not supported on this board\n");
1152 sunxi_display.monitor = sunxi_monitor_none;
1155 case sunxi_monitor_lcd:
1157 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1161 printf("LCD not supported on this board\n");
1162 sunxi_display.monitor = sunxi_monitor_none;
1164 case sunxi_monitor_vga:
1165 #if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
1166 sunxi_display.depth = 18;
1169 printf("VGA not supported on this board\n");
1170 sunxi_display.monitor = sunxi_monitor_none;
1175 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1176 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1177 mode = &res_mode_init[RES_MODE_1024x768];
1179 printf("Setting up a %dx%d %s console\n", mode->xres,
1180 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
1183 sunxi_display.fb_size =
1184 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1185 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1186 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1187 sunxi_display.fb_size >> 10,
1188 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1192 gd->fb_base = gd->bd->bi_dram[0].start +
1193 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1194 sunxi_engines_init();
1195 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
1198 * These are the only members of this structure that are used. All the
1199 * others are driver specific. There is nothing to decribe pitch or
1200 * stride, but we are lucky with our hw.
1202 graphic_device->frameAdrs = gd->fb_base;
1203 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1204 graphic_device->gdfBytesPP = 4;
1205 graphic_device->winSizeX = mode->xres;
1206 graphic_device->winSizeY = mode->yres;
1208 return graphic_device;
1214 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1215 int sunxi_simplefb_setup(void *blob)
1217 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1220 const char *pipeline = NULL;
1222 #ifdef CONFIG_MACH_SUN4I
1223 #define PIPELINE_PREFIX "de_fe0-"
1225 #define PIPELINE_PREFIX
1228 switch (sunxi_display.monitor) {
1229 case sunxi_monitor_none:
1231 case sunxi_monitor_dvi:
1232 case sunxi_monitor_hdmi:
1233 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1235 case sunxi_monitor_lcd:
1236 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1238 case sunxi_monitor_vga:
1239 #ifdef CONFIG_VIDEO_VGA
1240 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1241 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1242 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1247 /* Find a prefilled simpefb node, matching out pipeline config */
1248 offset = fdt_node_offset_by_compatible(blob, -1,
1249 "allwinner,simple-framebuffer");
1250 while (offset >= 0) {
1251 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
1255 offset = fdt_node_offset_by_compatible(blob, offset,
1256 "allwinner,simple-framebuffer");
1259 eprintf("Cannot setup simplefb: node not found\n");
1260 return 0; /* Keep older kernels working */
1264 * Do not report the framebuffer as free RAM to the OS, note we cannot
1265 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1266 * and e.g. Linux refuses to iomap RAM on ARM, see:
1267 * linux/arch/arm/mm/ioremap.c around line 301.
1269 start = gd->bd->bi_dram[0].start;
1270 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1271 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1273 eprintf("Cannot setup simplefb: Error reserving memory\n");
1277 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1278 graphic_device->winSizeX, graphic_device->winSizeY,
1279 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1282 eprintf("Cannot setup simplefb: Error setting properties\n");
1286 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */