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>
23 #include "videomodes.h"
24 #include "hitachi_tx18d42vm_lcd.h"
27 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
35 DECLARE_GLOBAL_DATA_PTR;
44 #define SUNXI_MONITOR_LAST sunxi_monitor_vga
46 struct sunxi_display {
47 GraphicDevice graphic_device;
48 enum sunxi_monitor monitor;
53 #ifdef CONFIG_VIDEO_HDMI
56 * Wait up to 200ms for value to be set in given part of reg.
58 static int await_completion(u32 *reg, u32 mask, u32 val)
60 unsigned long tmo = timer_get_us() + 200000;
62 while ((readl(reg) & mask) != val) {
63 if (timer_get_us() > tmo) {
64 printf("DDC: timeout reading EDID\n");
71 static int sunxi_hdmi_hpd_detect(int hpd_delay)
73 struct sunxi_ccm_reg * const ccm =
74 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
75 struct sunxi_hdmi_reg * const hdmi =
76 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
77 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
79 /* Set pll3 to 300MHz */
80 clock_set_pll3(300000000);
82 /* Set hdmi parent to pll3 */
83 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
86 /* Set ahb gating to pass */
87 #ifdef CONFIG_SUNXI_GEN_SUN6I
88 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
90 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
93 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
95 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
96 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
98 while (timer_get_us() < tmo) {
99 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
106 static void sunxi_hdmi_shutdown(void)
108 struct sunxi_ccm_reg * const ccm =
109 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
110 struct sunxi_hdmi_reg * const hdmi =
111 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
113 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
114 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
115 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
116 #ifdef CONFIG_SUNXI_GEN_SUN6I
117 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
122 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
124 struct sunxi_hdmi_reg * const hdmi =
125 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
127 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
128 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
129 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
130 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
131 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
132 #ifndef CONFIG_MACH_SUN6I
133 writel(n, &hdmi->ddc_byte_count);
134 writel(cmnd, &hdmi->ddc_cmnd);
136 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
138 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
140 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
143 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
145 struct sunxi_hdmi_reg * const hdmi =
146 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
155 if (sunxi_hdmi_ddc_do_command(
156 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
160 for (i = 0; i < n; i++)
161 *buf++ = readb(&hdmi->ddc_fifo_data);
170 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
175 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
178 r = edid_check_checksum(buf);
180 printf("EDID block %d: checksum error%s\n",
181 block, retries ? ", retrying" : "");
183 } while (r && retries--);
188 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
190 struct edid1_info edid1;
191 struct edid_cea861_info cea681[4];
192 struct edid_detailed_timing *t =
193 (struct edid_detailed_timing *)edid1.monitor_details.timing;
194 struct sunxi_hdmi_reg * const hdmi =
195 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
196 struct sunxi_ccm_reg * const ccm =
197 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
198 int i, r, ext_blocks = 0;
200 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
201 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
203 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
205 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
207 /* Reset i2c controller */
208 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
209 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
210 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
211 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
212 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
213 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
216 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
217 #ifndef CONFIG_MACH_SUN6I
218 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
219 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
222 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
224 r = edid_check_info(&edid1);
226 printf("EDID: invalid EDID data\n");
231 ext_blocks = edid1.extension_flag;
234 for (i = 0; i < ext_blocks; i++) {
235 if (sunxi_hdmi_edid_get_block(1 + i,
236 (u8 *)&cea681[i]) != 0) {
243 /* Disable DDC engine, no longer needed */
244 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
245 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
250 /* We want version 1.3 or 1.2 with detailed timing info */
251 if (edid1.version != 1 || (edid1.revision < 3 &&
252 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
253 printf("EDID: unsupported version %d.%d\n",
254 edid1.version, edid1.revision);
258 /* Take the first usable detailed timing */
259 for (i = 0; i < 4; i++, t++) {
260 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
265 printf("EDID: no usable detailed timing found\n");
269 /* Check for basic audio support, if found enable hdmi output */
270 sunxi_display.monitor = sunxi_monitor_dvi;
271 for (i = 0; i < ext_blocks; i++) {
272 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
273 cea681[i].revision < 2)
276 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
277 sunxi_display.monitor = sunxi_monitor_hdmi;
283 #endif /* CONFIG_VIDEO_HDMI */
285 #ifdef CONFIG_MACH_SUN4I
287 * Testing has shown that on sun4i the display backend engine does not have
288 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
289 * fifo underruns. So on sun4i we use the display frontend engine to do the
290 * dma from memory, as the frontend does have deep enough fifo-s.
293 static const u32 sun4i_vert_coef[32] = {
294 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
295 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
296 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
297 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
298 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
299 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
300 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
301 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
304 static const u32 sun4i_horz_coef[64] = {
305 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
306 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
307 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
308 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
309 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
310 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
311 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
312 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
313 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
314 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
315 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
316 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
317 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
318 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
319 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
320 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
323 static void sunxi_frontend_init(void)
325 struct sunxi_ccm_reg * const ccm =
326 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
327 struct sunxi_de_fe_reg * const de_fe =
328 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
332 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
333 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
334 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
336 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
338 for (i = 0; i < 32; i++) {
339 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
340 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
341 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
342 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
343 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
344 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
347 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
350 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
351 unsigned int address)
353 struct sunxi_de_fe_reg * const de_fe =
354 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
356 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
357 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
358 writel(mode->xres * 4, &de_fe->ch0_stride);
359 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
360 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
362 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
364 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
365 &de_fe->ch0_outsize);
366 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
367 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
369 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
371 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
372 &de_fe->ch1_outsize);
373 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
374 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
376 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
379 static void sunxi_frontend_enable(void)
381 struct sunxi_de_fe_reg * const de_fe =
382 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
384 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
387 static void sunxi_frontend_init(void) {}
388 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
389 unsigned int address) {}
390 static void sunxi_frontend_enable(void) {}
394 * This is the entity that mixes and matches the different layers and inputs.
395 * Allwinner calls it the back-end, but i like composer better.
397 static void sunxi_composer_init(void)
399 struct sunxi_ccm_reg * const ccm =
400 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
401 struct sunxi_de_be_reg * const de_be =
402 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
405 sunxi_frontend_init();
407 #ifdef CONFIG_SUNXI_GEN_SUN6I
409 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
413 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
414 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
415 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
417 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
419 /* Engine bug, clear registers after reset */
420 for (i = 0x0800; i < 0x1000; i += 4)
421 writel(0, SUNXI_DE_BE0_BASE + i);
423 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
426 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
427 unsigned int address)
429 struct sunxi_de_be_reg * const de_be =
430 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
432 sunxi_frontend_mode_set(mode, address);
434 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
436 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
437 &de_be->layer0_size);
438 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
439 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
440 writel(address << 3, &de_be->layer0_addr_low32b);
441 writel(address >> 29, &de_be->layer0_addr_high4b);
443 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
445 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
447 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
450 static void sunxi_composer_enable(void)
452 struct sunxi_de_be_reg * const de_be =
453 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
455 sunxi_frontend_enable();
457 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
458 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
462 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
464 static void sunxi_lcdc_pll_set(int tcon, int dotclock,
465 int *clk_div, int *clk_double)
467 struct sunxi_ccm_reg * const ccm =
468 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
469 int value, n, m, min_m, max_m, diff;
470 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
474 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
478 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
487 * Find the lowest divider resulting in a matching clock, if there
488 * is no match, pick the closest lower clock, as monitors tend to
489 * not sync to higher frequencies.
491 for (m = min_m; m <= max_m; m++) {
492 n = (m * dotclock) / 3000;
494 if ((n >= 9) && (n <= 127)) {
495 value = (3000 * n) / m;
496 diff = dotclock - value;
497 if (diff < best_diff) {
505 /* These are just duplicates */
509 n = (m * dotclock) / 6000;
510 if ((n >= 9) && (n <= 127)) {
511 value = (6000 * n) / m;
512 diff = dotclock - value;
513 if (diff < best_diff) {
522 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
523 dotclock, (best_double + 1) * 3000 * best_n / best_m,
524 best_double + 1, best_n, best_m);
526 clock_set_pll3(best_n * 3000000);
529 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
530 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
531 CCM_LCD_CH0_CTRL_PLL3),
532 &ccm->lcd0_ch0_clk_cfg);
534 writel(CCM_LCD_CH1_CTRL_GATE |
535 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
536 CCM_LCD_CH1_CTRL_PLL3) |
537 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
541 *clk_double = best_double;
544 static void sunxi_lcdc_init(void)
546 struct sunxi_ccm_reg * const ccm =
547 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
548 struct sunxi_lcdc_reg * const lcdc =
549 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
552 #ifdef CONFIG_SUNXI_GEN_SUN6I
553 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
555 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
559 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
560 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
561 #ifdef CONFIG_SUNXI_GEN_SUN6I
562 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
564 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
569 writel(0, &lcdc->ctrl); /* Disable tcon */
570 writel(0, &lcdc->int0); /* Disable all interrupts */
572 /* Disable tcon0 dot clock */
573 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
575 /* Set all io lines to tristate */
576 writel(0xffffffff, &lcdc->tcon0_io_tristate);
577 writel(0xffffffff, &lcdc->tcon1_io_tristate);
580 static void sunxi_lcdc_enable(void)
582 struct sunxi_lcdc_reg * const lcdc =
583 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
585 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
586 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
587 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
588 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
589 #ifdef CONFIG_SUNXI_GEN_SUN6I
590 udelay(2); /* delay at least 1200 ns */
591 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
592 udelay(2); /* delay at least 1200 ns */
593 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
594 if (sunxi_display.depth == 18)
595 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
597 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
599 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
600 udelay(2); /* delay at least 1200 ns */
601 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
602 udelay(1); /* delay at least 120 ns */
603 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
604 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
609 static void sunxi_lcdc_panel_enable(void)
614 * Start with backlight disabled to avoid the screen flashing to
615 * white while the lcd inits.
617 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
619 gpio_request(pin, "lcd_backlight_enable");
620 gpio_direction_output(pin, 0);
623 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
625 gpio_request(pin, "lcd_backlight_pwm");
626 gpio_direction_output(pin, PWM_OFF);
629 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
630 if (reset_pin >= 0) {
631 gpio_request(reset_pin, "lcd_reset");
632 gpio_direction_output(reset_pin, 0); /* Assert reset */
635 /* Give the backlight some time to turn off and power up the panel. */
637 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
639 gpio_request(pin, "lcd_power");
640 gpio_direction_output(pin, 1);
644 gpio_direction_output(reset_pin, 1); /* De-assert reset */
647 static void sunxi_lcdc_backlight_enable(void)
652 * We want to have scanned out at least one frame before enabling the
653 * backlight to avoid the screen flashing to white when we enable it.
657 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
659 gpio_direction_output(pin, 1);
661 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
663 gpio_direction_output(pin, PWM_ON);
666 static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
670 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
674 return (delay > 30) ? 30 : delay;
677 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
678 bool for_ext_vga_dac)
680 struct sunxi_lcdc_reg * const lcdc =
681 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
682 int bp, clk_delay, clk_div, clk_double, pin, total, val;
684 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
685 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
686 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
688 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
689 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
692 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
695 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
696 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
698 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
699 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
700 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
702 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
703 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
705 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
706 &lcdc->tcon0_timing_active);
708 bp = mode->hsync_len + mode->left_margin;
709 total = mode->xres + mode->right_margin + bp;
710 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
711 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
713 bp = mode->vsync_len + mode->upper_margin;
714 total = mode->yres + mode->lower_margin + bp;
715 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
716 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
718 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
719 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
720 &lcdc->tcon0_timing_sync);
722 writel(0, &lcdc->tcon0_hv_intf);
723 writel(0, &lcdc->tcon0_cpu_intf);
725 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
726 val = (sunxi_display.depth == 18) ? 1 : 0;
727 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
728 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
731 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
732 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
733 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
734 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
735 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
736 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
737 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
738 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
739 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
740 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
741 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
742 writel(((sunxi_display.depth == 18) ?
743 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
744 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
745 &lcdc->tcon0_frm_ctrl);
748 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
749 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
750 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
751 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
752 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
754 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
758 writel(val, &lcdc->tcon0_io_polarity);
760 writel(0, &lcdc->tcon0_io_tristate);
763 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
764 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
765 int *clk_div, int *clk_double,
766 bool use_portd_hvsync)
768 struct sunxi_lcdc_reg * const lcdc =
769 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
770 int bp, clk_delay, total, val;
773 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
774 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
776 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
777 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
778 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
780 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
781 &lcdc->tcon1_timing_source);
782 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
783 &lcdc->tcon1_timing_scale);
784 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
785 &lcdc->tcon1_timing_out);
787 bp = mode->hsync_len + mode->left_margin;
788 total = mode->xres + mode->right_margin + bp;
789 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
790 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
792 bp = mode->vsync_len + mode->upper_margin;
793 total = mode->yres + mode->lower_margin + bp;
794 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
795 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
797 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
798 &lcdc->tcon1_timing_sync);
800 if (use_portd_hvsync) {
801 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
802 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
805 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
806 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
807 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
808 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
809 writel(val, &lcdc->tcon1_io_polarity);
811 clrbits_le32(&lcdc->tcon1_io_tristate,
812 SUNXI_LCDC_TCON_VSYNC_MASK |
813 SUNXI_LCDC_TCON_HSYNC_MASK);
815 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
817 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
819 #ifdef CONFIG_VIDEO_HDMI
821 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
823 struct sunxi_hdmi_reg * const hdmi =
824 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
826 u8 avi_info_frame[17] = {
827 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 u8 vendor_info_frame[19] = {
832 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
838 if (mode->pixclock_khz <= 27000)
839 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
841 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
843 if (mode->xres * 100 / mode->yres < 156)
844 avi_info_frame[5] |= 0x18; /* 4 : 3 */
846 avi_info_frame[5] |= 0x28; /* 16 : 9 */
848 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
849 checksum += avi_info_frame[i];
851 avi_info_frame[3] = 0x100 - checksum;
853 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
854 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
856 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
857 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
859 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
860 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
862 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
863 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
865 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
868 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
869 int clk_div, int clk_double)
871 struct sunxi_hdmi_reg * const hdmi =
872 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
875 /* Write clear interrupt status bits */
876 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
878 if (sunxi_display.monitor == sunxi_monitor_hdmi)
879 sunxi_hdmi_setup_info_frames(mode);
881 /* Set input sync enable */
882 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
884 /* Init various registers, select pll3 as clock source */
885 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
886 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
887 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
888 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
889 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
891 /* Setup clk div and doubler */
892 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
893 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
895 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
897 /* Setup timing registers */
898 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
901 x = mode->hsync_len + mode->left_margin;
902 y = mode->vsync_len + mode->upper_margin;
903 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
905 x = mode->right_margin;
906 y = mode->lower_margin;
907 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
911 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
913 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
914 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
916 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
917 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
920 static void sunxi_hdmi_enable(void)
922 struct sunxi_hdmi_reg * const hdmi =
923 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
926 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
929 #endif /* CONFIG_VIDEO_HDMI */
931 #ifdef CONFIG_VIDEO_VGA
933 static void sunxi_vga_mode_set(void)
935 struct sunxi_ccm_reg * const ccm =
936 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
937 struct sunxi_tve_reg * const tve =
938 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
941 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
943 /* Set TVE in VGA mode */
944 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
945 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
946 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
947 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
948 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
949 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
952 static void sunxi_vga_enable(void)
954 struct sunxi_tve_reg * const tve =
955 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
957 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
960 #endif /* CONFIG_VIDEO_VGA */
962 static void sunxi_drc_init(void)
964 #ifdef CONFIG_SUNXI_GEN_SUN6I
965 struct sunxi_ccm_reg * const ccm =
966 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
968 /* On sun6i the drc must be clocked even when in pass-through mode */
969 #ifdef CONFIG_MACH_SUN8I_A33
970 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
972 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
973 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
977 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
978 static void sunxi_vga_external_dac_enable(void)
982 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
984 gpio_request(pin, "vga_enable");
985 gpio_direction_output(pin, 1);
988 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
990 #ifdef CONFIG_VIDEO_LCD_SSD2828
991 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
993 struct ssd2828_config cfg = {
994 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
995 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
996 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
997 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
998 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
999 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1000 .ssd2828_color_depth = 24,
1001 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1002 .mipi_dsi_number_of_data_lanes = 4,
1003 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1004 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1005 .mipi_dsi_delay_after_set_display_on_ms = 200
1007 #error MIPI LCD panel needs configuration parameters
1011 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1012 printf("SSD2828: SPI pins are not properly configured\n");
1015 if (cfg.reset_pin == -1) {
1016 printf("SSD2828: Reset pin is not properly configured\n");
1020 return ssd2828_init(&cfg, mode);
1022 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
1024 static void sunxi_engines_init(void)
1026 sunxi_composer_init();
1031 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
1032 unsigned int address)
1034 int __maybe_unused clk_div, clk_double;
1036 switch (sunxi_display.monitor) {
1037 case sunxi_monitor_none:
1039 case sunxi_monitor_dvi:
1040 case sunxi_monitor_hdmi:
1041 #ifdef CONFIG_VIDEO_HDMI
1042 sunxi_composer_mode_set(mode, address);
1043 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1044 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1045 sunxi_composer_enable();
1046 sunxi_lcdc_enable();
1047 sunxi_hdmi_enable();
1050 case sunxi_monitor_lcd:
1051 sunxi_lcdc_panel_enable();
1052 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1053 mdelay(50); /* Wait for lcd controller power on */
1054 hitachi_tx18d42vm_init();
1056 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1057 unsigned int orig_i2c_bus = i2c_get_bus_num();
1058 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1059 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1060 i2c_set_bus_num(orig_i2c_bus);
1062 sunxi_composer_mode_set(mode, address);
1063 sunxi_lcdc_tcon0_mode_set(mode, false);
1064 sunxi_composer_enable();
1065 sunxi_lcdc_enable();
1066 #ifdef CONFIG_VIDEO_LCD_SSD2828
1067 sunxi_ssd2828_init(mode);
1069 sunxi_lcdc_backlight_enable();
1071 case sunxi_monitor_vga:
1072 #ifdef CONFIG_VIDEO_VGA
1073 sunxi_composer_mode_set(mode, address);
1074 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1075 sunxi_vga_mode_set();
1076 sunxi_composer_enable();
1077 sunxi_lcdc_enable();
1079 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1080 sunxi_composer_mode_set(mode, address);
1081 sunxi_lcdc_tcon0_mode_set(mode, true);
1082 sunxi_composer_enable();
1083 sunxi_lcdc_enable();
1084 sunxi_vga_external_dac_enable();
1090 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1093 case sunxi_monitor_none: return "none";
1094 case sunxi_monitor_dvi: return "dvi";
1095 case sunxi_monitor_hdmi: return "hdmi";
1096 case sunxi_monitor_lcd: return "lcd";
1097 case sunxi_monitor_vga: return "vga";
1099 return NULL; /* never reached */
1102 ulong board_get_usable_ram_top(ulong total_size)
1104 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1107 static bool sunxi_has_hdmi(void)
1109 #ifdef CONFIG_VIDEO_HDMI
1116 static bool sunxi_has_lcd(void)
1118 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1120 return lcd_mode[0] != 0;
1123 static bool sunxi_has_vga(void)
1125 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1132 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1134 if (allow_hdmi && sunxi_has_hdmi())
1135 return sunxi_monitor_dvi;
1136 else if (sunxi_has_lcd())
1137 return sunxi_monitor_lcd;
1138 else if (sunxi_has_vga())
1139 return sunxi_monitor_vga;
1141 return sunxi_monitor_none;
1144 void *video_hw_init(void)
1146 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1147 const struct ctfb_res_modes *mode;
1148 struct ctfb_res_modes custom;
1149 const char *options;
1150 #ifdef CONFIG_VIDEO_HDMI
1151 int ret, hpd, hpd_delay, edid;
1154 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1157 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1159 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1160 &sunxi_display.depth, &options);
1161 #ifdef CONFIG_VIDEO_HDMI
1162 hpd = video_get_option_int(options, "hpd", 1);
1163 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1164 edid = video_get_option_int(options, "edid", 1);
1166 sunxi_display.monitor = sunxi_get_default_mon(true);
1167 video_get_option_string(options, "monitor", mon, sizeof(mon),
1168 sunxi_get_mon_desc(sunxi_display.monitor));
1169 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1170 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1171 sunxi_display.monitor = i;
1175 if (i > SUNXI_MONITOR_LAST)
1176 printf("Unknown monitor: '%s', falling back to '%s'\n",
1177 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1179 #ifdef CONFIG_VIDEO_HDMI
1180 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1181 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1182 sunxi_display.monitor == sunxi_monitor_hdmi) {
1183 /* Always call hdp_detect, as it also enables clocks, etc. */
1184 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1186 printf("HDMI connected: ");
1187 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1190 sunxi_hdmi_shutdown();
1191 sunxi_display.monitor = sunxi_get_default_mon(false);
1192 } /* else continue with hdmi/dvi without a cable connected */
1196 switch (sunxi_display.monitor) {
1197 case sunxi_monitor_none:
1199 case sunxi_monitor_dvi:
1200 case sunxi_monitor_hdmi:
1201 if (!sunxi_has_hdmi()) {
1202 printf("HDMI/DVI not supported on this board\n");
1203 sunxi_display.monitor = sunxi_monitor_none;
1207 case sunxi_monitor_lcd:
1208 if (!sunxi_has_lcd()) {
1209 printf("LCD not supported on this board\n");
1210 sunxi_display.monitor = sunxi_monitor_none;
1213 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1216 case sunxi_monitor_vga:
1217 if (!sunxi_has_vga()) {
1218 printf("VGA not supported on this board\n");
1219 sunxi_display.monitor = sunxi_monitor_none;
1222 sunxi_display.depth = 18;
1226 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1227 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1228 mode = &res_mode_init[RES_MODE_1024x768];
1230 printf("Setting up a %dx%d %s console\n", mode->xres,
1231 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
1234 sunxi_display.fb_size =
1235 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1236 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1237 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1238 sunxi_display.fb_size >> 10,
1239 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1243 gd->fb_base = gd->bd->bi_dram[0].start +
1244 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1245 sunxi_engines_init();
1246 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
1249 * These are the only members of this structure that are used. All the
1250 * others are driver specific. There is nothing to decribe pitch or
1251 * stride, but we are lucky with our hw.
1253 graphic_device->frameAdrs = gd->fb_base;
1254 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1255 graphic_device->gdfBytesPP = 4;
1256 graphic_device->winSizeX = mode->xres;
1257 graphic_device->winSizeY = mode->yres;
1259 return graphic_device;
1265 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1266 int sunxi_simplefb_setup(void *blob)
1268 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1271 const char *pipeline = NULL;
1273 #ifdef CONFIG_MACH_SUN4I
1274 #define PIPELINE_PREFIX "de_fe0-"
1276 #define PIPELINE_PREFIX
1279 switch (sunxi_display.monitor) {
1280 case sunxi_monitor_none:
1282 case sunxi_monitor_dvi:
1283 case sunxi_monitor_hdmi:
1284 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1286 case sunxi_monitor_lcd:
1287 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1289 case sunxi_monitor_vga:
1290 #ifdef CONFIG_VIDEO_VGA
1291 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1292 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1293 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1298 /* Find a prefilled simpefb node, matching out pipeline config */
1299 offset = fdt_node_offset_by_compatible(blob, -1,
1300 "allwinner,simple-framebuffer");
1301 while (offset >= 0) {
1302 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
1306 offset = fdt_node_offset_by_compatible(blob, offset,
1307 "allwinner,simple-framebuffer");
1310 eprintf("Cannot setup simplefb: node not found\n");
1311 return 0; /* Keep older kernels working */
1315 * Do not report the framebuffer as free RAM to the OS, note we cannot
1316 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1317 * and e.g. Linux refuses to iomap RAM on ARM, see:
1318 * linux/arch/arm/mm/ioremap.c around line 301.
1320 start = gd->bd->bi_dram[0].start;
1321 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1322 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1324 eprintf("Cannot setup simplefb: Error reserving memory\n");
1328 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1329 graphic_device->winSizeX, graphic_device->winSizeY,
1330 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1333 eprintf("Cannot setup simplefb: Error setting properties\n");
1337 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */