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);
448 if (mode->vmode == FB_VMODE_INTERLACED)
449 setbits_le32(&de_be->mode,
450 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
451 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
454 static void sunxi_composer_enable(void)
456 struct sunxi_de_be_reg * const de_be =
457 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
459 sunxi_frontend_enable();
461 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
462 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
466 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
468 static void sunxi_lcdc_pll_set(int tcon, int dotclock,
469 int *clk_div, int *clk_double)
471 struct sunxi_ccm_reg * const ccm =
472 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
473 int value, n, m, min_m, max_m, diff;
474 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
478 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
482 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
491 * Find the lowest divider resulting in a matching clock, if there
492 * is no match, pick the closest lower clock, as monitors tend to
493 * not sync to higher frequencies.
495 for (m = min_m; m <= max_m; m++) {
496 n = (m * dotclock) / 3000;
498 if ((n >= 9) && (n <= 127)) {
499 value = (3000 * n) / m;
500 diff = dotclock - value;
501 if (diff < best_diff) {
509 /* These are just duplicates */
513 n = (m * dotclock) / 6000;
514 if ((n >= 9) && (n <= 127)) {
515 value = (6000 * n) / m;
516 diff = dotclock - value;
517 if (diff < best_diff) {
526 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
527 dotclock, (best_double + 1) * 3000 * best_n / best_m,
528 best_double + 1, best_n, best_m);
530 clock_set_pll3(best_n * 3000000);
533 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
534 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
535 CCM_LCD_CH0_CTRL_PLL3),
536 &ccm->lcd0_ch0_clk_cfg);
538 writel(CCM_LCD_CH1_CTRL_GATE |
539 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
540 CCM_LCD_CH1_CTRL_PLL3) |
541 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
545 *clk_double = best_double;
548 static void sunxi_lcdc_init(void)
550 struct sunxi_ccm_reg * const ccm =
551 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
552 struct sunxi_lcdc_reg * const lcdc =
553 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
556 #ifdef CONFIG_SUNXI_GEN_SUN6I
557 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
559 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
563 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
564 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
565 #ifdef CONFIG_SUNXI_GEN_SUN6I
566 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
568 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
573 writel(0, &lcdc->ctrl); /* Disable tcon */
574 writel(0, &lcdc->int0); /* Disable all interrupts */
576 /* Disable tcon0 dot clock */
577 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
579 /* Set all io lines to tristate */
580 writel(0xffffffff, &lcdc->tcon0_io_tristate);
581 writel(0xffffffff, &lcdc->tcon1_io_tristate);
584 static void sunxi_lcdc_enable(void)
586 struct sunxi_lcdc_reg * const lcdc =
587 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
589 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
590 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
591 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
592 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
593 #ifdef CONFIG_SUNXI_GEN_SUN6I
594 udelay(2); /* delay at least 1200 ns */
595 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
596 udelay(2); /* delay at least 1200 ns */
597 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
598 if (sunxi_display.depth == 18)
599 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
601 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
603 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
604 udelay(2); /* delay at least 1200 ns */
605 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
606 udelay(1); /* delay at least 120 ns */
607 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
608 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
613 static void sunxi_lcdc_panel_enable(void)
618 * Start with backlight disabled to avoid the screen flashing to
619 * white while the lcd inits.
621 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
623 gpio_request(pin, "lcd_backlight_enable");
624 gpio_direction_output(pin, 0);
627 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
629 gpio_request(pin, "lcd_backlight_pwm");
630 gpio_direction_output(pin, PWM_OFF);
633 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
634 if (reset_pin >= 0) {
635 gpio_request(reset_pin, "lcd_reset");
636 gpio_direction_output(reset_pin, 0); /* Assert reset */
639 /* Give the backlight some time to turn off and power up the panel. */
641 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
643 gpio_request(pin, "lcd_power");
644 gpio_direction_output(pin, 1);
648 gpio_direction_output(reset_pin, 1); /* De-assert reset */
651 static void sunxi_lcdc_backlight_enable(void)
656 * We want to have scanned out at least one frame before enabling the
657 * backlight to avoid the screen flashing to white when we enable it.
661 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
663 gpio_direction_output(pin, 1);
665 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
667 gpio_direction_output(pin, PWM_ON);
670 static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
674 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
675 if (mode->vmode == FB_VMODE_INTERLACED)
680 return (delay > 30) ? 30 : delay;
683 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
684 bool for_ext_vga_dac)
686 struct sunxi_lcdc_reg * const lcdc =
687 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
688 int bp, clk_delay, clk_div, clk_double, pin, total, val;
690 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
691 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
692 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
694 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
695 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
698 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
701 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
702 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
704 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
705 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
706 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
708 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
709 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
711 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
712 &lcdc->tcon0_timing_active);
714 bp = mode->hsync_len + mode->left_margin;
715 total = mode->xres + mode->right_margin + bp;
716 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
717 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
719 bp = mode->vsync_len + mode->upper_margin;
720 total = mode->yres + mode->lower_margin + bp;
721 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
722 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
724 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
725 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
726 &lcdc->tcon0_timing_sync);
728 writel(0, &lcdc->tcon0_hv_intf);
729 writel(0, &lcdc->tcon0_cpu_intf);
731 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
732 val = (sunxi_display.depth == 18) ? 1 : 0;
733 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
734 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
737 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
738 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
739 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
740 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
741 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
742 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
743 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
744 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
745 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
746 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
747 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
748 writel(((sunxi_display.depth == 18) ?
749 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
750 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
751 &lcdc->tcon0_frm_ctrl);
754 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
755 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
756 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
757 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
758 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
760 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
764 writel(val, &lcdc->tcon0_io_polarity);
766 writel(0, &lcdc->tcon0_io_tristate);
769 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
770 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
771 int *clk_div, int *clk_double,
772 bool use_portd_hvsync)
774 struct sunxi_lcdc_reg * const lcdc =
775 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
776 int bp, clk_delay, total, val, yres;
779 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
780 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
782 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
783 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
784 ((mode->vmode == FB_VMODE_INTERLACED) ?
785 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
786 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
789 if (mode->vmode == FB_VMODE_INTERLACED)
791 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
792 &lcdc->tcon1_timing_source);
793 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
794 &lcdc->tcon1_timing_scale);
795 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
796 &lcdc->tcon1_timing_out);
798 bp = mode->hsync_len + mode->left_margin;
799 total = mode->xres + mode->right_margin + bp;
800 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
801 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
803 bp = mode->vsync_len + mode->upper_margin;
804 total = mode->yres + mode->lower_margin + bp;
805 if (mode->vmode == FB_VMODE_NONINTERLACED)
807 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
808 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
810 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
811 &lcdc->tcon1_timing_sync);
813 if (use_portd_hvsync) {
814 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
815 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
818 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
819 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
820 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
821 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
822 writel(val, &lcdc->tcon1_io_polarity);
824 clrbits_le32(&lcdc->tcon1_io_tristate,
825 SUNXI_LCDC_TCON_VSYNC_MASK |
826 SUNXI_LCDC_TCON_HSYNC_MASK);
828 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
830 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
832 #ifdef CONFIG_VIDEO_HDMI
834 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
836 struct sunxi_hdmi_reg * const hdmi =
837 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
839 u8 avi_info_frame[17] = {
840 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844 u8 vendor_info_frame[19] = {
845 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
851 if (mode->pixclock_khz <= 27000)
852 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
854 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
856 if (mode->xres * 100 / mode->yres < 156)
857 avi_info_frame[5] |= 0x18; /* 4 : 3 */
859 avi_info_frame[5] |= 0x28; /* 16 : 9 */
861 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
862 checksum += avi_info_frame[i];
864 avi_info_frame[3] = 0x100 - checksum;
866 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
867 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
869 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
870 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
872 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
873 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
875 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
876 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
878 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
881 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
882 int clk_div, int clk_double)
884 struct sunxi_hdmi_reg * const hdmi =
885 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
888 /* Write clear interrupt status bits */
889 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
891 if (sunxi_display.monitor == sunxi_monitor_hdmi)
892 sunxi_hdmi_setup_info_frames(mode);
894 /* Set input sync enable */
895 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
897 /* Init various registers, select pll3 as clock source */
898 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
899 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
900 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
901 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
902 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
904 /* Setup clk div and doubler */
905 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
906 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
908 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
910 /* Setup timing registers */
911 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
914 x = mode->hsync_len + mode->left_margin;
915 y = mode->vsync_len + mode->upper_margin;
916 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
918 x = mode->right_margin;
919 y = mode->lower_margin;
920 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
924 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
926 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
927 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
929 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
930 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
933 static void sunxi_hdmi_enable(void)
935 struct sunxi_hdmi_reg * const hdmi =
936 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
939 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
942 #endif /* CONFIG_VIDEO_HDMI */
944 #ifdef CONFIG_VIDEO_VGA
946 static void sunxi_vga_mode_set(void)
948 struct sunxi_ccm_reg * const ccm =
949 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
950 struct sunxi_tve_reg * const tve =
951 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
954 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
956 /* Set TVE in VGA mode */
957 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
958 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
959 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
960 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
961 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
962 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
965 static void sunxi_vga_enable(void)
967 struct sunxi_tve_reg * const tve =
968 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
970 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
973 #endif /* CONFIG_VIDEO_VGA */
975 static void sunxi_drc_init(void)
977 #ifdef CONFIG_SUNXI_GEN_SUN6I
978 struct sunxi_ccm_reg * const ccm =
979 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
981 /* On sun6i the drc must be clocked even when in pass-through mode */
982 #ifdef CONFIG_MACH_SUN8I_A33
983 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
985 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
986 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
990 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
991 static void sunxi_vga_external_dac_enable(void)
995 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
997 gpio_request(pin, "vga_enable");
998 gpio_direction_output(pin, 1);
1001 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1003 #ifdef CONFIG_VIDEO_LCD_SSD2828
1004 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1006 struct ssd2828_config cfg = {
1007 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1008 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1009 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1010 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1011 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1012 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1013 .ssd2828_color_depth = 24,
1014 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1015 .mipi_dsi_number_of_data_lanes = 4,
1016 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1017 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1018 .mipi_dsi_delay_after_set_display_on_ms = 200
1020 #error MIPI LCD panel needs configuration parameters
1024 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1025 printf("SSD2828: SPI pins are not properly configured\n");
1028 if (cfg.reset_pin == -1) {
1029 printf("SSD2828: Reset pin is not properly configured\n");
1033 return ssd2828_init(&cfg, mode);
1035 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
1037 static void sunxi_engines_init(void)
1039 sunxi_composer_init();
1044 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
1045 unsigned int address)
1047 int __maybe_unused clk_div, clk_double;
1049 switch (sunxi_display.monitor) {
1050 case sunxi_monitor_none:
1052 case sunxi_monitor_dvi:
1053 case sunxi_monitor_hdmi:
1054 #ifdef CONFIG_VIDEO_HDMI
1055 sunxi_composer_mode_set(mode, address);
1056 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1057 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1058 sunxi_composer_enable();
1059 sunxi_lcdc_enable();
1060 sunxi_hdmi_enable();
1063 case sunxi_monitor_lcd:
1064 sunxi_lcdc_panel_enable();
1065 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1066 mdelay(50); /* Wait for lcd controller power on */
1067 hitachi_tx18d42vm_init();
1069 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1070 unsigned int orig_i2c_bus = i2c_get_bus_num();
1071 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1072 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1073 i2c_set_bus_num(orig_i2c_bus);
1075 sunxi_composer_mode_set(mode, address);
1076 sunxi_lcdc_tcon0_mode_set(mode, false);
1077 sunxi_composer_enable();
1078 sunxi_lcdc_enable();
1079 #ifdef CONFIG_VIDEO_LCD_SSD2828
1080 sunxi_ssd2828_init(mode);
1082 sunxi_lcdc_backlight_enable();
1084 case sunxi_monitor_vga:
1085 #ifdef CONFIG_VIDEO_VGA
1086 sunxi_composer_mode_set(mode, address);
1087 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1088 sunxi_vga_mode_set();
1089 sunxi_composer_enable();
1090 sunxi_lcdc_enable();
1092 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1093 sunxi_composer_mode_set(mode, address);
1094 sunxi_lcdc_tcon0_mode_set(mode, true);
1095 sunxi_composer_enable();
1096 sunxi_lcdc_enable();
1097 sunxi_vga_external_dac_enable();
1103 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1106 case sunxi_monitor_none: return "none";
1107 case sunxi_monitor_dvi: return "dvi";
1108 case sunxi_monitor_hdmi: return "hdmi";
1109 case sunxi_monitor_lcd: return "lcd";
1110 case sunxi_monitor_vga: return "vga";
1112 return NULL; /* never reached */
1115 ulong board_get_usable_ram_top(ulong total_size)
1117 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1120 static bool sunxi_has_hdmi(void)
1122 #ifdef CONFIG_VIDEO_HDMI
1129 static bool sunxi_has_lcd(void)
1131 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1133 return lcd_mode[0] != 0;
1136 static bool sunxi_has_vga(void)
1138 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1145 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1147 if (allow_hdmi && sunxi_has_hdmi())
1148 return sunxi_monitor_dvi;
1149 else if (sunxi_has_lcd())
1150 return sunxi_monitor_lcd;
1151 else if (sunxi_has_vga())
1152 return sunxi_monitor_vga;
1154 return sunxi_monitor_none;
1157 void *video_hw_init(void)
1159 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1160 const struct ctfb_res_modes *mode;
1161 struct ctfb_res_modes custom;
1162 const char *options;
1163 #ifdef CONFIG_VIDEO_HDMI
1164 int ret, hpd, hpd_delay, edid;
1167 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1170 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1172 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1173 &sunxi_display.depth, &options);
1174 #ifdef CONFIG_VIDEO_HDMI
1175 hpd = video_get_option_int(options, "hpd", 1);
1176 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1177 edid = video_get_option_int(options, "edid", 1);
1179 sunxi_display.monitor = sunxi_get_default_mon(true);
1180 video_get_option_string(options, "monitor", mon, sizeof(mon),
1181 sunxi_get_mon_desc(sunxi_display.monitor));
1182 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1183 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1184 sunxi_display.monitor = i;
1188 if (i > SUNXI_MONITOR_LAST)
1189 printf("Unknown monitor: '%s', falling back to '%s'\n",
1190 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1192 #ifdef CONFIG_VIDEO_HDMI
1193 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1194 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1195 sunxi_display.monitor == sunxi_monitor_hdmi) {
1196 /* Always call hdp_detect, as it also enables clocks, etc. */
1197 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1199 printf("HDMI connected: ");
1200 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1203 sunxi_hdmi_shutdown();
1204 sunxi_display.monitor = sunxi_get_default_mon(false);
1205 } /* else continue with hdmi/dvi without a cable connected */
1209 switch (sunxi_display.monitor) {
1210 case sunxi_monitor_none:
1212 case sunxi_monitor_dvi:
1213 case sunxi_monitor_hdmi:
1214 if (!sunxi_has_hdmi()) {
1215 printf("HDMI/DVI not supported on this board\n");
1216 sunxi_display.monitor = sunxi_monitor_none;
1220 case sunxi_monitor_lcd:
1221 if (!sunxi_has_lcd()) {
1222 printf("LCD not supported on this board\n");
1223 sunxi_display.monitor = sunxi_monitor_none;
1226 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1229 case sunxi_monitor_vga:
1230 if (!sunxi_has_vga()) {
1231 printf("VGA not supported on this board\n");
1232 sunxi_display.monitor = sunxi_monitor_none;
1235 sunxi_display.depth = 18;
1239 sunxi_display.fb_size =
1240 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1241 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1242 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1243 sunxi_display.fb_size >> 10,
1244 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1248 printf("Setting up a %dx%d%s %s console\n", mode->xres, mode->yres,
1249 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1250 sunxi_get_mon_desc(sunxi_display.monitor));
1252 gd->fb_base = gd->bd->bi_dram[0].start +
1253 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1254 sunxi_engines_init();
1255 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
1258 * These are the only members of this structure that are used. All the
1259 * others are driver specific. There is nothing to decribe pitch or
1260 * stride, but we are lucky with our hw.
1262 graphic_device->frameAdrs = gd->fb_base;
1263 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1264 graphic_device->gdfBytesPP = 4;
1265 graphic_device->winSizeX = mode->xres;
1266 graphic_device->winSizeY = mode->yres;
1268 return graphic_device;
1274 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1275 int sunxi_simplefb_setup(void *blob)
1277 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1280 const char *pipeline = NULL;
1282 #ifdef CONFIG_MACH_SUN4I
1283 #define PIPELINE_PREFIX "de_fe0-"
1285 #define PIPELINE_PREFIX
1288 switch (sunxi_display.monitor) {
1289 case sunxi_monitor_none:
1291 case sunxi_monitor_dvi:
1292 case sunxi_monitor_hdmi:
1293 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1295 case sunxi_monitor_lcd:
1296 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1298 case sunxi_monitor_vga:
1299 #ifdef CONFIG_VIDEO_VGA
1300 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1301 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1302 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1307 /* Find a prefilled simpefb node, matching out pipeline config */
1308 offset = fdt_node_offset_by_compatible(blob, -1,
1309 "allwinner,simple-framebuffer");
1310 while (offset >= 0) {
1311 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
1315 offset = fdt_node_offset_by_compatible(blob, offset,
1316 "allwinner,simple-framebuffer");
1319 eprintf("Cannot setup simplefb: node not found\n");
1320 return 0; /* Keep older kernels working */
1324 * Do not report the framebuffer as free RAM to the OS, note we cannot
1325 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1326 * and e.g. Linux refuses to iomap RAM on ARM, see:
1327 * linux/arch/arm/mm/ioremap.c around line 301.
1329 start = gd->bd->bi_dram[0].start;
1330 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1331 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1333 eprintf("Cannot setup simplefb: Error reserving memory\n");
1337 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1338 graphic_device->winSizeX, graphic_device->winSizeY,
1339 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1342 eprintf("Cannot setup simplefb: Error setting properties\n");
1346 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */