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;
51 #ifdef CONFIG_VIDEO_HDMI
54 * Wait up to 200ms for value to be set in given part of reg.
56 static int await_completion(u32 *reg, u32 mask, u32 val)
58 unsigned long tmo = timer_get_us() + 200000;
60 while ((readl(reg) & mask) != val) {
61 if (timer_get_us() > tmo) {
62 printf("DDC: timeout reading EDID\n");
69 static int sunxi_hdmi_hpd_detect(int hpd_delay)
71 struct sunxi_ccm_reg * const ccm =
72 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
73 struct sunxi_hdmi_reg * const hdmi =
74 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
75 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
77 /* Set pll3 to 300MHz */
78 clock_set_pll3(300000000);
80 /* Set hdmi parent to pll3 */
81 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
84 /* Set ahb gating to pass */
85 #ifdef CONFIG_MACH_SUN6I
86 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
88 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
91 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
93 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
94 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
96 while (timer_get_us() < tmo) {
97 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
104 static void sunxi_hdmi_shutdown(void)
106 struct sunxi_ccm_reg * const ccm =
107 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
108 struct sunxi_hdmi_reg * const hdmi =
109 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
111 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
112 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
113 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
114 #ifdef CONFIG_MACH_SUN6I
115 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
120 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
122 struct sunxi_hdmi_reg * const hdmi =
123 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
125 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
126 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
127 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
128 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
129 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
130 #ifndef CONFIG_MACH_SUN6I
131 writel(n, &hdmi->ddc_byte_count);
132 writel(cmnd, &hdmi->ddc_cmnd);
134 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
136 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
138 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
141 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
143 struct sunxi_hdmi_reg * const hdmi =
144 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
153 if (sunxi_hdmi_ddc_do_command(
154 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
158 for (i = 0; i < n; i++)
159 *buf++ = readb(&hdmi->ddc_fifo_data);
168 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
173 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
176 r = edid_check_checksum(buf);
178 printf("EDID block %d: checksum error%s\n",
179 block, retries ? ", retrying" : "");
181 } while (r && retries--);
186 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
188 struct edid1_info edid1;
189 struct edid_cea861_info cea681[4];
190 struct edid_detailed_timing *t =
191 (struct edid_detailed_timing *)edid1.monitor_details.timing;
192 struct sunxi_hdmi_reg * const hdmi =
193 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
194 struct sunxi_ccm_reg * const ccm =
195 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
196 int i, r, ext_blocks = 0;
198 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
199 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
201 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
203 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
205 /* Reset i2c controller */
206 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
207 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
208 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
209 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
210 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
211 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
214 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
215 #ifndef CONFIG_MACH_SUN6I
216 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
217 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
220 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
222 r = edid_check_info(&edid1);
224 printf("EDID: invalid EDID data\n");
229 ext_blocks = edid1.extension_flag;
232 for (i = 0; i < ext_blocks; i++) {
233 if (sunxi_hdmi_edid_get_block(1 + i,
234 (u8 *)&cea681[i]) != 0) {
241 /* Disable DDC engine, no longer needed */
242 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
243 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
248 /* We want version 1.3 or 1.2 with detailed timing info */
249 if (edid1.version != 1 || (edid1.revision < 3 &&
250 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
251 printf("EDID: unsupported version %d.%d\n",
252 edid1.version, edid1.revision);
256 /* Take the first usable detailed timing */
257 for (i = 0; i < 4; i++, t++) {
258 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
263 printf("EDID: no usable detailed timing found\n");
267 /* Check for basic audio support, if found enable hdmi output */
268 sunxi_display.monitor = sunxi_monitor_dvi;
269 for (i = 0; i < ext_blocks; i++) {
270 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
271 cea681[i].revision < 2)
274 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
275 sunxi_display.monitor = sunxi_monitor_hdmi;
281 #endif /* CONFIG_VIDEO_HDMI */
283 #ifdef CONFIG_MACH_SUN4I
285 * Testing has shown that on sun4i the display backend engine does not have
286 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
287 * fifo underruns. So on sun4i we use the display frontend engine to do the
288 * dma from memory, as the frontend does have deep enough fifo-s.
291 static const u32 sun4i_vert_coef[32] = {
292 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
293 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
294 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
295 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
296 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
297 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
298 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
299 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
302 static const u32 sun4i_horz_coef[64] = {
303 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
304 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
305 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
306 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
307 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
308 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
309 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
310 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
311 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
312 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
313 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
314 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
315 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
316 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
317 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
318 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
321 static void sunxi_frontend_init(void)
323 struct sunxi_ccm_reg * const ccm =
324 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
325 struct sunxi_de_fe_reg * const de_fe =
326 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
330 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
331 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
332 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
334 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
336 for (i = 0; i < 32; i++) {
337 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
338 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
339 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
340 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
341 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
342 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
345 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
348 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
349 unsigned int address)
351 struct sunxi_de_fe_reg * const de_fe =
352 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
354 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
355 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
356 writel(mode->xres * 4, &de_fe->ch0_stride);
357 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
358 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
360 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
362 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
363 &de_fe->ch0_outsize);
364 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
365 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
367 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
369 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
370 &de_fe->ch1_outsize);
371 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
372 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
374 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
377 static void sunxi_frontend_enable(void)
379 struct sunxi_de_fe_reg * const de_fe =
380 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
382 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
385 static void sunxi_frontend_init(void) {}
386 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
387 unsigned int address) {}
388 static void sunxi_frontend_enable(void) {}
392 * This is the entity that mixes and matches the different layers and inputs.
393 * Allwinner calls it the back-end, but i like composer better.
395 static void sunxi_composer_init(void)
397 struct sunxi_ccm_reg * const ccm =
398 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
399 struct sunxi_de_be_reg * const de_be =
400 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
403 sunxi_frontend_init();
405 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
407 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
411 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
412 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
413 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
415 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
417 /* Engine bug, clear registers after reset */
418 for (i = 0x0800; i < 0x1000; i += 4)
419 writel(0, SUNXI_DE_BE0_BASE + i);
421 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
424 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
425 unsigned int address)
427 struct sunxi_de_be_reg * const de_be =
428 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
430 sunxi_frontend_mode_set(mode, address);
432 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
434 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
435 &de_be->layer0_size);
436 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
437 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
438 writel(address << 3, &de_be->layer0_addr_low32b);
439 writel(address >> 29, &de_be->layer0_addr_high4b);
441 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
443 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
445 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
448 static void sunxi_composer_enable(void)
450 struct sunxi_de_be_reg * const de_be =
451 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
453 sunxi_frontend_enable();
455 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
456 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
460 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
462 static void sunxi_lcdc_pll_set(int tcon, int dotclock,
463 int *clk_div, int *clk_double)
465 struct sunxi_ccm_reg * const ccm =
466 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
467 int value, n, m, min_m, max_m, diff;
468 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
472 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
476 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
485 * Find the lowest divider resulting in a matching clock, if there
486 * is no match, pick the closest lower clock, as monitors tend to
487 * not sync to higher frequencies.
489 for (m = min_m; m <= max_m; m++) {
490 n = (m * dotclock) / 3000;
492 if ((n >= 9) && (n <= 127)) {
493 value = (3000 * n) / m;
494 diff = dotclock - value;
495 if (diff < best_diff) {
503 /* These are just duplicates */
507 n = (m * dotclock) / 6000;
508 if ((n >= 9) && (n <= 127)) {
509 value = (6000 * n) / m;
510 diff = dotclock - value;
511 if (diff < best_diff) {
520 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
521 dotclock, (best_double + 1) * 3000 * best_n / best_m,
522 best_double + 1, best_n, best_m);
524 clock_set_pll3(best_n * 3000000);
527 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
528 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
529 CCM_LCD_CH0_CTRL_PLL3),
530 &ccm->lcd0_ch0_clk_cfg);
532 writel(CCM_LCD_CH1_CTRL_GATE |
533 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
534 CCM_LCD_CH1_CTRL_PLL3) |
535 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
539 *clk_double = best_double;
542 static void sunxi_lcdc_init(void)
544 struct sunxi_ccm_reg * const ccm =
545 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
546 struct sunxi_lcdc_reg * const lcdc =
547 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
550 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
551 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
553 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
557 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
558 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
559 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
563 writel(0, &lcdc->ctrl); /* Disable tcon */
564 writel(0, &lcdc->int0); /* Disable all interrupts */
566 /* Disable tcon0 dot clock */
567 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
569 /* Set all io lines to tristate */
570 writel(0xffffffff, &lcdc->tcon0_io_tristate);
571 writel(0xffffffff, &lcdc->tcon1_io_tristate);
574 static void sunxi_lcdc_enable(void)
576 struct sunxi_lcdc_reg * const lcdc =
577 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
579 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
580 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
581 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
582 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
583 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
584 udelay(2); /* delay at least 1200 ns */
585 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
586 udelay(1); /* delay at least 120 ns */
587 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
588 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
592 static void sunxi_lcdc_panel_enable(void)
597 * Start with backlight disabled to avoid the screen flashing to
598 * white while the lcd inits.
600 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
602 gpio_request(pin, "lcd_backlight_enable");
603 gpio_direction_output(pin, 0);
606 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
608 gpio_request(pin, "lcd_backlight_pwm");
609 gpio_direction_output(pin, PWM_OFF);
612 /* Give the backlight some time to turn off and power up the panel. */
614 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
616 gpio_request(pin, "lcd_power");
617 gpio_direction_output(pin, 1);
621 static void sunxi_lcdc_backlight_enable(void)
626 * We want to have scanned out at least one frame before enabling the
627 * backlight to avoid the screen flashing to white when we enable it.
631 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
633 gpio_direction_output(pin, 1);
635 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
637 gpio_direction_output(pin, PWM_ON);
640 static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
644 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
645 return (delay > 30) ? 30 : delay;
648 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
649 bool for_ext_vga_dac)
651 struct sunxi_lcdc_reg * const lcdc =
652 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
653 int bp, clk_delay, clk_div, clk_double, pin, total, val;
655 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
656 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
657 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0);
659 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
660 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0);
663 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
666 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
667 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
669 clk_delay = sunxi_lcdc_get_clk_delay(mode);
670 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
671 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
673 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
674 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
676 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
677 &lcdc->tcon0_timing_active);
679 bp = mode->hsync_len + mode->left_margin;
680 total = mode->xres + mode->right_margin + bp;
681 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
682 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
684 bp = mode->vsync_len + mode->upper_margin;
685 total = mode->yres + mode->lower_margin + bp;
686 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
687 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
689 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
690 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
691 &lcdc->tcon0_timing_sync);
693 writel(0, &lcdc->tcon0_hv_intf);
694 writel(0, &lcdc->tcon0_cpu_intf);
696 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
697 val = (sunxi_display.depth == 18) ? 1 : 0;
698 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf);
701 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
702 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
703 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
704 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
705 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
706 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
707 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
708 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
709 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
710 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
711 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
712 writel(((sunxi_display.depth == 18) ?
713 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
714 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
715 &lcdc->tcon0_frm_ctrl);
718 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
719 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
720 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
721 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
722 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
724 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
728 writel(val, &lcdc->tcon0_io_polarity);
730 writel(0, &lcdc->tcon0_io_tristate);
733 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
734 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
735 int *clk_div, int *clk_double,
736 bool use_portd_hvsync)
738 struct sunxi_lcdc_reg * const lcdc =
739 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
740 int bp, clk_delay, total, val;
743 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
744 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
746 clk_delay = sunxi_lcdc_get_clk_delay(mode);
747 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
748 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
750 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
751 &lcdc->tcon1_timing_source);
752 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
753 &lcdc->tcon1_timing_scale);
754 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
755 &lcdc->tcon1_timing_out);
757 bp = mode->hsync_len + mode->left_margin;
758 total = mode->xres + mode->right_margin + bp;
759 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
760 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
762 bp = mode->vsync_len + mode->upper_margin;
763 total = mode->yres + mode->lower_margin + bp;
764 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
765 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
767 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
768 &lcdc->tcon1_timing_sync);
770 if (use_portd_hvsync) {
771 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD0_LCD0);
772 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD0_LCD0);
775 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
776 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
777 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
778 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
779 writel(val, &lcdc->tcon1_io_polarity);
781 clrbits_le32(&lcdc->tcon1_io_tristate,
782 SUNXI_LCDC_TCON_VSYNC_MASK |
783 SUNXI_LCDC_TCON_HSYNC_MASK);
785 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
787 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
789 #ifdef CONFIG_VIDEO_HDMI
791 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
793 struct sunxi_hdmi_reg * const hdmi =
794 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
796 u8 avi_info_frame[17] = {
797 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
801 u8 vendor_info_frame[19] = {
802 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808 if (mode->pixclock_khz <= 27000)
809 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
811 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
813 if (mode->xres * 100 / mode->yres < 156)
814 avi_info_frame[5] |= 0x18; /* 4 : 3 */
816 avi_info_frame[5] |= 0x28; /* 16 : 9 */
818 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
819 checksum += avi_info_frame[i];
821 avi_info_frame[3] = 0x100 - checksum;
823 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
824 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
826 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
827 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
829 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
830 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
832 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
833 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
835 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
838 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
839 int clk_div, int clk_double)
841 struct sunxi_hdmi_reg * const hdmi =
842 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
845 /* Write clear interrupt status bits */
846 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
848 if (sunxi_display.monitor == sunxi_monitor_hdmi)
849 sunxi_hdmi_setup_info_frames(mode);
851 /* Set input sync enable */
852 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
854 /* Init various registers, select pll3 as clock source */
855 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
856 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
857 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
858 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
859 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
861 /* Setup clk div and doubler */
862 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
863 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
865 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
867 /* Setup timing registers */
868 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
871 x = mode->hsync_len + mode->left_margin;
872 y = mode->vsync_len + mode->upper_margin;
873 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
875 x = mode->right_margin;
876 y = mode->lower_margin;
877 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
881 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
883 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
884 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
886 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
887 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
890 static void sunxi_hdmi_enable(void)
892 struct sunxi_hdmi_reg * const hdmi =
893 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
896 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
899 #endif /* CONFIG_VIDEO_HDMI */
901 #ifdef CONFIG_VIDEO_VGA
903 static void sunxi_vga_mode_set(void)
905 struct sunxi_ccm_reg * const ccm =
906 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
907 struct sunxi_tve_reg * const tve =
908 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
911 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
913 /* Set TVE in VGA mode */
914 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
915 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
916 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
917 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
918 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
919 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
922 static void sunxi_vga_enable(void)
924 struct sunxi_tve_reg * const tve =
925 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
927 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
930 #endif /* CONFIG_VIDEO_VGA */
932 static void sunxi_drc_init(void)
934 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
935 struct sunxi_ccm_reg * const ccm =
936 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
938 /* On sun6i the drc must be clocked even when in pass-through mode */
939 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
940 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
944 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
945 static void sunxi_vga_external_dac_enable(void)
949 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
951 gpio_request(pin, "vga_enable");
952 gpio_direction_output(pin, 1);
955 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
957 #ifdef CONFIG_VIDEO_LCD_SSD2828
958 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
960 struct ssd2828_config cfg = {
961 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
962 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
963 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
964 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
965 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
966 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
967 .ssd2828_color_depth = 24,
968 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
969 .mipi_dsi_number_of_data_lanes = 4,
970 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
971 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
972 .mipi_dsi_delay_after_set_display_on_ms = 200
974 #error MIPI LCD panel needs configuration parameters
978 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
979 printf("SSD2828: SPI pins are not properly configured\n");
982 if (cfg.reset_pin == -1) {
983 printf("SSD2828: Reset pin is not properly configured\n");
987 return ssd2828_init(&cfg, mode);
989 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
991 static void sunxi_engines_init(void)
993 sunxi_composer_init();
998 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
999 unsigned int address)
1001 int __maybe_unused clk_div, clk_double;
1003 switch (sunxi_display.monitor) {
1004 case sunxi_monitor_none:
1006 case sunxi_monitor_dvi:
1007 case sunxi_monitor_hdmi:
1008 #ifdef CONFIG_VIDEO_HDMI
1009 sunxi_composer_mode_set(mode, address);
1010 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1011 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1012 sunxi_composer_enable();
1013 sunxi_lcdc_enable();
1014 sunxi_hdmi_enable();
1017 case sunxi_monitor_lcd:
1018 sunxi_lcdc_panel_enable();
1019 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1020 mdelay(50); /* Wait for lcd controller power on */
1021 hitachi_tx18d42vm_init();
1023 sunxi_composer_mode_set(mode, address);
1024 sunxi_lcdc_tcon0_mode_set(mode, false);
1025 sunxi_composer_enable();
1026 sunxi_lcdc_enable();
1027 #ifdef CONFIG_VIDEO_LCD_SSD2828
1028 sunxi_ssd2828_init(mode);
1030 sunxi_lcdc_backlight_enable();
1032 case sunxi_monitor_vga:
1033 #ifdef CONFIG_VIDEO_VGA
1034 sunxi_composer_mode_set(mode, address);
1035 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1036 sunxi_vga_mode_set();
1037 sunxi_composer_enable();
1038 sunxi_lcdc_enable();
1040 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1041 sunxi_composer_mode_set(mode, address);
1042 sunxi_lcdc_tcon0_mode_set(mode, true);
1043 sunxi_composer_enable();
1044 sunxi_lcdc_enable();
1045 sunxi_vga_external_dac_enable();
1051 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1054 case sunxi_monitor_none: return "none";
1055 case sunxi_monitor_dvi: return "dvi";
1056 case sunxi_monitor_hdmi: return "hdmi";
1057 case sunxi_monitor_lcd: return "lcd";
1058 case sunxi_monitor_vga: return "vga";
1060 return NULL; /* never reached */
1063 void *video_hw_init(void)
1065 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1066 const struct ctfb_res_modes *mode;
1067 struct ctfb_res_modes custom;
1068 const char *options;
1069 #ifdef CONFIG_VIDEO_HDMI
1070 int ret, hpd, hpd_delay, edid;
1073 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1076 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1078 printf("Reserved %dkB of RAM for Framebuffer.\n",
1079 CONFIG_SUNXI_FB_SIZE >> 10);
1080 gd->fb_base = gd->ram_top;
1082 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1083 &sunxi_display.depth, &options);
1084 #ifdef CONFIG_VIDEO_HDMI
1085 hpd = video_get_option_int(options, "hpd", 1);
1086 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1087 edid = video_get_option_int(options, "edid", 1);
1088 sunxi_display.monitor = sunxi_monitor_dvi;
1089 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1090 sunxi_display.monitor = sunxi_monitor_vga;
1092 sunxi_display.monitor = sunxi_monitor_lcd;
1094 video_get_option_string(options, "monitor", mon, sizeof(mon),
1095 sunxi_get_mon_desc(sunxi_display.monitor));
1096 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1097 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1098 sunxi_display.monitor = i;
1102 if (i > SUNXI_MONITOR_LAST)
1103 printf("Unknown monitor: '%s', falling back to '%s'\n",
1104 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1106 #ifdef CONFIG_VIDEO_HDMI
1107 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1108 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1109 sunxi_display.monitor == sunxi_monitor_hdmi) {
1110 /* Always call hdp_detect, as it also enables clocks, etc. */
1111 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1113 printf("HDMI connected: ");
1114 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1117 sunxi_hdmi_shutdown();
1118 /* Fallback to lcd / vga / none */
1120 sunxi_display.monitor = sunxi_monitor_lcd;
1122 #if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
1123 sunxi_display.monitor = sunxi_monitor_vga;
1125 sunxi_display.monitor = sunxi_monitor_none;
1128 } /* else continue with hdmi/dvi without a cable connected */
1132 switch (sunxi_display.monitor) {
1133 case sunxi_monitor_none:
1135 case sunxi_monitor_dvi:
1136 case sunxi_monitor_hdmi:
1137 #ifdef CONFIG_VIDEO_HDMI
1140 printf("HDMI/DVI not supported on this board\n");
1141 sunxi_display.monitor = sunxi_monitor_none;
1144 case sunxi_monitor_lcd:
1146 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1150 printf("LCD not supported on this board\n");
1151 sunxi_display.monitor = sunxi_monitor_none;
1153 case sunxi_monitor_vga:
1154 #if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
1155 sunxi_display.depth = 18;
1158 printf("VGA not supported on this board\n");
1159 sunxi_display.monitor = sunxi_monitor_none;
1164 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1165 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1166 mode = &res_mode_init[RES_MODE_1024x768];
1168 printf("Setting up a %dx%d %s console\n", mode->xres,
1169 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
1172 sunxi_engines_init();
1173 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
1176 * These are the only members of this structure that are used. All the
1177 * others are driver specific. There is nothing to decribe pitch or
1178 * stride, but we are lucky with our hw.
1180 graphic_device->frameAdrs = gd->fb_base;
1181 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1182 graphic_device->gdfBytesPP = 4;
1183 graphic_device->winSizeX = mode->xres;
1184 graphic_device->winSizeY = mode->yres;
1186 return graphic_device;
1192 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1193 int sunxi_simplefb_setup(void *blob)
1195 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1197 const char *pipeline = NULL;
1199 #ifdef CONFIG_MACH_SUN4I
1200 #define PIPELINE_PREFIX "de_fe0-"
1202 #define PIPELINE_PREFIX
1205 switch (sunxi_display.monitor) {
1206 case sunxi_monitor_none:
1208 case sunxi_monitor_dvi:
1209 case sunxi_monitor_hdmi:
1210 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1212 case sunxi_monitor_lcd:
1213 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1215 case sunxi_monitor_vga:
1216 #ifdef CONFIG_VIDEO_VGA
1217 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1218 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1219 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1224 /* Find a prefilled simpefb node, matching out pipeline config */
1225 offset = fdt_node_offset_by_compatible(blob, -1,
1226 "allwinner,simple-framebuffer");
1227 while (offset >= 0) {
1228 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
1232 offset = fdt_node_offset_by_compatible(blob, offset,
1233 "allwinner,simple-framebuffer");
1236 eprintf("Cannot setup simplefb: node not found\n");
1237 return 0; /* Keep older kernels working */
1240 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1241 graphic_device->winSizeX, graphic_device->winSizeY,
1242 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1245 eprintf("Cannot setup simplefb: Error setting properties\n");
1249 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */