2 * Display driver for Allwinner SoCs.
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
5 * (C) Copyright 2014-2015 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/arch/lcdc.h>
16 #include <asm/arch/pwm.h>
17 #include <asm/arch/tve.h>
18 #include <asm/global_data.h>
24 #include <fdt_support.h>
28 #include "../videomodes.h"
29 #include "../anx9804.h"
30 #include "../hitachi_tx18d42vm_lcd.h"
31 #include "../ssd2828.h"
32 #include "simplefb_common.h"
34 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
42 DECLARE_GLOBAL_DATA_PTR;
50 sunxi_monitor_composite_pal,
51 sunxi_monitor_composite_ntsc,
52 sunxi_monitor_composite_pal_m,
53 sunxi_monitor_composite_pal_nc,
55 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
57 struct sunxi_display {
58 GraphicDevice graphic_device;
59 enum sunxi_monitor monitor;
65 const struct ctfb_res_modes composite_video_modes[2] = {
66 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
67 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
68 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
71 #ifdef CONFIG_VIDEO_HDMI
74 * Wait up to 200ms for value to be set in given part of reg.
76 static int await_completion(u32 *reg, u32 mask, u32 val)
78 unsigned long tmo = timer_get_us() + 200000;
80 while ((readl(reg) & mask) != val) {
81 if (timer_get_us() > tmo) {
82 printf("DDC: timeout reading EDID\n");
89 static int sunxi_hdmi_hpd_detect(int hpd_delay)
91 struct sunxi_ccm_reg * const ccm =
92 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
93 struct sunxi_hdmi_reg * const hdmi =
94 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
95 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
97 /* Set pll3 to 300MHz */
98 clock_set_pll3(300000000);
100 /* Set hdmi parent to pll3 */
101 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
104 /* Set ahb gating to pass */
105 #ifdef CONFIG_SUNXI_GEN_SUN6I
106 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
108 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
111 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
113 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
114 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
116 while (timer_get_us() < tmo) {
117 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
124 static void sunxi_hdmi_shutdown(void)
126 struct sunxi_ccm_reg * const ccm =
127 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
128 struct sunxi_hdmi_reg * const hdmi =
129 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
131 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
132 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
133 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
134 #ifdef CONFIG_SUNXI_GEN_SUN6I
135 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
140 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
142 struct sunxi_hdmi_reg * const hdmi =
143 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
145 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
146 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
147 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
148 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
149 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
150 #ifndef CONFIG_MACH_SUN6I
151 writel(n, &hdmi->ddc_byte_count);
152 writel(cmnd, &hdmi->ddc_cmnd);
154 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
156 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
158 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
161 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
163 struct sunxi_hdmi_reg * const hdmi =
164 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
173 if (sunxi_hdmi_ddc_do_command(
174 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
178 for (i = 0; i < n; i++)
179 *buf++ = readb(&hdmi->ddc_fifo_data);
188 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
193 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
196 r = edid_check_checksum(buf);
198 printf("EDID block %d: checksum error%s\n",
199 block, retries ? ", retrying" : "");
201 } while (r && retries--);
206 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
208 struct edid1_info edid1;
209 struct edid_cea861_info cea681[4];
210 struct edid_detailed_timing *t =
211 (struct edid_detailed_timing *)edid1.monitor_details.timing;
212 struct sunxi_hdmi_reg * const hdmi =
213 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
214 struct sunxi_ccm_reg * const ccm =
215 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
216 int i, r, ext_blocks = 0;
218 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
219 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
221 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
223 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
225 /* Reset i2c controller */
226 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
227 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
228 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
229 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
230 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
231 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
234 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
235 #ifndef CONFIG_MACH_SUN6I
236 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
237 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
240 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
242 r = edid_check_info(&edid1);
244 printf("EDID: invalid EDID data\n");
249 ext_blocks = edid1.extension_flag;
252 for (i = 0; i < ext_blocks; i++) {
253 if (sunxi_hdmi_edid_get_block(1 + i,
254 (u8 *)&cea681[i]) != 0) {
261 /* Disable DDC engine, no longer needed */
262 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
263 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
268 /* We want version 1.3 or 1.2 with detailed timing info */
269 if (edid1.version != 1 || (edid1.revision < 3 &&
270 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
271 printf("EDID: unsupported version %d.%d\n",
272 edid1.version, edid1.revision);
276 /* Take the first usable detailed timing */
277 for (i = 0; i < 4; i++, t++) {
278 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
283 printf("EDID: no usable detailed timing found\n");
287 /* Check for basic audio support, if found enable hdmi output */
288 sunxi_display.monitor = sunxi_monitor_dvi;
289 for (i = 0; i < ext_blocks; i++) {
290 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
291 cea681[i].revision < 2)
294 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
295 sunxi_display.monitor = sunxi_monitor_hdmi;
301 #endif /* CONFIG_VIDEO_HDMI */
303 #ifdef CONFIG_MACH_SUN4I
305 * Testing has shown that on sun4i the display backend engine does not have
306 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
307 * fifo underruns. So on sun4i we use the display frontend engine to do the
308 * dma from memory, as the frontend does have deep enough fifo-s.
311 static const u32 sun4i_vert_coef[32] = {
312 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
313 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
314 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
315 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
316 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
317 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
318 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
319 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
322 static const u32 sun4i_horz_coef[64] = {
323 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
324 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
325 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
326 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
327 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
328 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
329 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
330 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
331 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
332 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
333 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
334 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
335 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
336 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
337 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
338 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
341 static void sunxi_frontend_init(void)
343 struct sunxi_ccm_reg * const ccm =
344 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
345 struct sunxi_de_fe_reg * const de_fe =
346 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
350 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
351 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
352 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
354 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
356 for (i = 0; i < 32; i++) {
357 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
358 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
359 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
360 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
361 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
362 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
365 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
368 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
369 unsigned int address)
371 struct sunxi_de_fe_reg * const de_fe =
372 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
374 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
375 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
376 writel(mode->xres * 4, &de_fe->ch0_stride);
377 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
378 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
380 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
382 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
383 &de_fe->ch0_outsize);
384 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
385 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
387 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
389 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
390 &de_fe->ch1_outsize);
391 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
392 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
394 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
397 static void sunxi_frontend_enable(void)
399 struct sunxi_de_fe_reg * const de_fe =
400 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
402 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
405 static void sunxi_frontend_init(void) {}
406 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
407 unsigned int address) {}
408 static void sunxi_frontend_enable(void) {}
411 static bool sunxi_is_composite(void)
413 switch (sunxi_display.monitor) {
414 case sunxi_monitor_none:
415 case sunxi_monitor_dvi:
416 case sunxi_monitor_hdmi:
417 case sunxi_monitor_lcd:
418 case sunxi_monitor_vga:
420 case sunxi_monitor_composite_pal:
421 case sunxi_monitor_composite_ntsc:
422 case sunxi_monitor_composite_pal_m:
423 case sunxi_monitor_composite_pal_nc:
427 return false; /* Never reached */
431 * This is the entity that mixes and matches the different layers and inputs.
432 * Allwinner calls it the back-end, but i like composer better.
434 static void sunxi_composer_init(void)
436 struct sunxi_ccm_reg * const ccm =
437 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
438 struct sunxi_de_be_reg * const de_be =
439 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
442 sunxi_frontend_init();
444 #ifdef CONFIG_SUNXI_GEN_SUN6I
446 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
450 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
451 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
452 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
454 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
456 /* Engine bug, clear registers after reset */
457 for (i = 0x0800; i < 0x1000; i += 4)
458 writel(0, SUNXI_DE_BE0_BASE + i);
460 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
463 static u32 sunxi_rgb2yuv_coef[12] = {
464 0x00000107, 0x00000204, 0x00000064, 0x00000108,
465 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
466 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
469 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
470 unsigned int address)
472 struct sunxi_de_be_reg * const de_be =
473 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
476 sunxi_frontend_mode_set(mode, address);
478 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
480 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
481 &de_be->layer0_size);
482 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
483 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
484 writel(address << 3, &de_be->layer0_addr_low32b);
485 writel(address >> 29, &de_be->layer0_addr_high4b);
487 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
489 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
491 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
492 if (mode->vmode == FB_VMODE_INTERLACED)
493 setbits_le32(&de_be->mode,
494 #ifndef CONFIG_MACH_SUN5I
495 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
497 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
499 if (sunxi_is_composite()) {
500 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
501 &de_be->output_color_ctrl);
502 for (i = 0; i < 12; i++)
503 writel(sunxi_rgb2yuv_coef[i],
504 &de_be->output_color_coef[i]);
508 static void sunxi_composer_enable(void)
510 struct sunxi_de_be_reg * const de_be =
511 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
513 sunxi_frontend_enable();
515 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
516 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
520 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
522 static void sunxi_lcdc_pll_set(int tcon, int dotclock,
523 int *clk_div, int *clk_double)
525 struct sunxi_ccm_reg * const ccm =
526 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
527 int value, n, m, min_m, max_m, diff;
528 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
530 bool use_mipi_pll = false;
533 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
537 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
546 * Find the lowest divider resulting in a matching clock, if there
547 * is no match, pick the closest lower clock, as monitors tend to
548 * not sync to higher frequencies.
550 for (m = min_m; m <= max_m; m++) {
551 n = (m * dotclock) / 3000;
553 if ((n >= 9) && (n <= 127)) {
554 value = (3000 * n) / m;
555 diff = dotclock - value;
556 if (diff < best_diff) {
564 /* These are just duplicates */
568 n = (m * dotclock) / 6000;
569 if ((n >= 9) && (n <= 127)) {
570 value = (6000 * n) / m;
571 diff = dotclock - value;
572 if (diff < best_diff) {
581 #ifdef CONFIG_MACH_SUN6I
583 * Use the MIPI pll if we've been unable to find any matching setting
584 * for PLL3, this happens with high dotclocks because of min_m = 6.
586 if (tcon == 0 && best_n == 0) {
588 best_m = 6; /* Minimum m for tcon0 */
592 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
593 clock_set_mipi_pll(best_m * dotclock * 1000);
594 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
595 dotclock, clock_get_mipi_pll() / best_m / 1000);
599 clock_set_pll3(best_n * 3000000);
600 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
602 (best_double + 1) * clock_get_pll3() / best_m / 1000,
603 best_double + 1, best_n, best_m);
610 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
611 else if (best_double)
612 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
614 pll = CCM_LCD_CH0_CTRL_PLL3;
616 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
617 &ccm->lcd0_ch0_clk_cfg);
619 writel(CCM_LCD_CH1_CTRL_GATE |
620 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
621 CCM_LCD_CH1_CTRL_PLL3) |
622 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
623 if (sunxi_is_composite())
624 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
625 CCM_LCD_CH1_CTRL_HALF_SCLK1);
629 *clk_double = best_double;
632 static void sunxi_lcdc_init(void)
634 struct sunxi_ccm_reg * const ccm =
635 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
636 struct sunxi_lcdc_reg * const lcdc =
637 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
640 #ifdef CONFIG_SUNXI_GEN_SUN6I
641 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
643 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
647 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
648 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
649 #ifdef CONFIG_SUNXI_GEN_SUN6I
650 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
652 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
659 static void sunxi_lcdc_panel_enable(void)
664 * Start with backlight disabled to avoid the screen flashing to
665 * white while the lcd inits.
667 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
669 gpio_request(pin, "lcd_backlight_enable");
670 gpio_direction_output(pin, 0);
673 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
675 gpio_request(pin, "lcd_backlight_pwm");
676 gpio_direction_output(pin, PWM_OFF);
679 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
680 if (reset_pin >= 0) {
681 gpio_request(reset_pin, "lcd_reset");
682 gpio_direction_output(reset_pin, 0); /* Assert reset */
685 /* Give the backlight some time to turn off and power up the panel. */
687 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
689 gpio_request(pin, "lcd_power");
690 gpio_direction_output(pin, 1);
694 gpio_direction_output(reset_pin, 1); /* De-assert reset */
697 static void sunxi_lcdc_backlight_enable(void)
702 * We want to have scanned out at least one frame before enabling the
703 * backlight to avoid the screen flashing to white when we enable it.
707 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
709 gpio_direction_output(pin, 1);
711 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
712 #ifdef SUNXI_PWM_PIN0
713 if (pin == SUNXI_PWM_PIN0) {
714 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
715 SUNXI_PWM_CTRL_ENABLE0 |
716 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
717 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
718 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
723 gpio_direction_output(pin, PWM_ON);
726 static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
727 struct display_timing *timing)
729 timing->pixelclock.typ = mode->pixclock_khz * 1000;
731 timing->hactive.typ = mode->xres;
732 timing->hfront_porch.typ = mode->right_margin;
733 timing->hback_porch.typ = mode->left_margin;
734 timing->hsync_len.typ = mode->hsync_len;
736 timing->vactive.typ = mode->yres;
737 timing->vfront_porch.typ = mode->lower_margin;
738 timing->vback_porch.typ = mode->upper_margin;
739 timing->vsync_len.typ = mode->vsync_len;
741 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
742 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
744 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
745 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
746 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
748 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
749 if (mode->vmode == FB_VMODE_INTERLACED)
750 timing->flags |= DISPLAY_FLAGS_INTERLACED;
753 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
754 bool for_ext_vga_dac)
756 struct sunxi_lcdc_reg * const lcdc =
757 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
758 int clk_div, clk_double, pin;
759 struct display_timing timing;
761 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
762 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
764 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
766 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
767 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
769 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
770 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
772 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
773 sunxi_gpio_set_drv(pin, 3);
777 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
779 sunxi_ctfb_mode_to_display_timing(mode, &timing);
780 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
781 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
784 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
785 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
786 int *clk_div, int *clk_double,
787 bool use_portd_hvsync)
789 struct sunxi_lcdc_reg * const lcdc =
790 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
791 struct display_timing timing;
793 sunxi_ctfb_mode_to_display_timing(mode, &timing);
794 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
795 sunxi_is_composite());
797 if (use_portd_hvsync) {
798 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
799 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
802 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
804 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
806 #ifdef CONFIG_VIDEO_HDMI
808 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
810 struct sunxi_hdmi_reg * const hdmi =
811 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
813 u8 avi_info_frame[17] = {
814 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 u8 vendor_info_frame[19] = {
819 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 if (mode->pixclock_khz <= 27000)
826 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
828 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
830 if (mode->xres * 100 / mode->yres < 156)
831 avi_info_frame[5] |= 0x18; /* 4 : 3 */
833 avi_info_frame[5] |= 0x28; /* 16 : 9 */
835 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
836 checksum += avi_info_frame[i];
838 avi_info_frame[3] = 0x100 - checksum;
840 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
841 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
843 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
844 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
846 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
847 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
849 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
850 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
852 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
855 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
856 int clk_div, int clk_double)
858 struct sunxi_hdmi_reg * const hdmi =
859 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
862 /* Write clear interrupt status bits */
863 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
865 if (sunxi_display.monitor == sunxi_monitor_hdmi)
866 sunxi_hdmi_setup_info_frames(mode);
868 /* Set input sync enable */
869 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
871 /* Init various registers, select pll3 as clock source */
872 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
873 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
874 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
875 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
876 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
878 /* Setup clk div and doubler */
879 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
880 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
882 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
884 /* Setup timing registers */
885 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
888 x = mode->hsync_len + mode->left_margin;
889 y = mode->vsync_len + mode->upper_margin;
890 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
892 x = mode->right_margin;
893 y = mode->lower_margin;
894 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
898 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
900 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
901 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
903 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
904 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
907 static void sunxi_hdmi_enable(void)
909 struct sunxi_hdmi_reg * const hdmi =
910 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
913 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
916 #endif /* CONFIG_VIDEO_HDMI */
918 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
920 static void sunxi_tvencoder_mode_set(void)
922 struct sunxi_ccm_reg * const ccm =
923 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
924 struct sunxi_tve_reg * const tve =
925 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
928 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
930 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
932 switch (sunxi_display.monitor) {
933 case sunxi_monitor_vga:
934 tvencoder_mode_set(tve, tve_mode_vga);
936 case sunxi_monitor_composite_pal_nc:
937 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
939 case sunxi_monitor_composite_pal:
940 tvencoder_mode_set(tve, tve_mode_composite_pal);
942 case sunxi_monitor_composite_pal_m:
943 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
945 case sunxi_monitor_composite_ntsc:
946 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
948 case sunxi_monitor_none:
949 case sunxi_monitor_dvi:
950 case sunxi_monitor_hdmi:
951 case sunxi_monitor_lcd:
956 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
958 static void sunxi_drc_init(void)
960 #ifdef CONFIG_SUNXI_GEN_SUN6I
961 struct sunxi_ccm_reg * const ccm =
962 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
964 /* On sun6i the drc must be clocked even when in pass-through mode */
965 #ifdef CONFIG_MACH_SUN8I_A33
966 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
968 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
969 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
973 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
974 static void sunxi_vga_external_dac_enable(void)
978 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
980 gpio_request(pin, "vga_enable");
981 gpio_direction_output(pin, 1);
984 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
986 #ifdef CONFIG_VIDEO_LCD_SSD2828
987 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
989 struct ssd2828_config cfg = {
990 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
991 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
992 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
993 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
994 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
995 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
996 .ssd2828_color_depth = 24,
997 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
998 .mipi_dsi_number_of_data_lanes = 4,
999 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1000 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1001 .mipi_dsi_delay_after_set_display_on_ms = 200
1003 #error MIPI LCD panel needs configuration parameters
1007 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1008 printf("SSD2828: SPI pins are not properly configured\n");
1011 if (cfg.reset_pin == -1) {
1012 printf("SSD2828: Reset pin is not properly configured\n");
1016 return ssd2828_init(&cfg, mode);
1018 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
1020 static void sunxi_engines_init(void)
1022 sunxi_composer_init();
1027 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
1028 unsigned int address)
1030 int __maybe_unused clk_div, clk_double;
1031 struct sunxi_lcdc_reg * const lcdc =
1032 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
1033 struct sunxi_tve_reg * __maybe_unused const tve =
1034 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
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 lcdc_enable(lcdc, sunxi_display.depth);
1047 sunxi_hdmi_enable();
1050 case sunxi_monitor_lcd:
1051 sunxi_lcdc_panel_enable();
1052 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1054 * The anx9804 needs 1.8V from eldo3, we do this here
1055 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
1056 * to avoid turning this on when using hdmi output.
1058 axp_set_eldo(3, 1800);
1059 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1060 ANX9804_DATA_RATE_1620M,
1061 sunxi_display.depth);
1063 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1064 mdelay(50); /* Wait for lcd controller power on */
1065 hitachi_tx18d42vm_init();
1067 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1068 unsigned int orig_i2c_bus = i2c_get_bus_num();
1069 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1070 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1071 i2c_set_bus_num(orig_i2c_bus);
1073 sunxi_composer_mode_set(mode, address);
1074 sunxi_lcdc_tcon0_mode_set(mode, false);
1075 sunxi_composer_enable();
1076 lcdc_enable(lcdc, sunxi_display.depth);
1077 #ifdef CONFIG_VIDEO_LCD_SSD2828
1078 sunxi_ssd2828_init(mode);
1080 sunxi_lcdc_backlight_enable();
1082 case sunxi_monitor_vga:
1083 #ifdef CONFIG_VIDEO_VGA
1084 sunxi_composer_mode_set(mode, address);
1085 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1086 sunxi_tvencoder_mode_set();
1087 sunxi_composer_enable();
1088 lcdc_enable(lcdc, sunxi_display.depth);
1089 tvencoder_enable(tve);
1090 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1091 sunxi_composer_mode_set(mode, address);
1092 sunxi_lcdc_tcon0_mode_set(mode, true);
1093 sunxi_composer_enable();
1094 lcdc_enable(lcdc, sunxi_display.depth);
1095 sunxi_vga_external_dac_enable();
1098 case sunxi_monitor_composite_pal:
1099 case sunxi_monitor_composite_ntsc:
1100 case sunxi_monitor_composite_pal_m:
1101 case sunxi_monitor_composite_pal_nc:
1102 #ifdef CONFIG_VIDEO_COMPOSITE
1103 sunxi_composer_mode_set(mode, address);
1104 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1105 sunxi_tvencoder_mode_set();
1106 sunxi_composer_enable();
1107 lcdc_enable(lcdc, sunxi_display.depth);
1108 tvencoder_enable(tve);
1114 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1117 case sunxi_monitor_none: return "none";
1118 case sunxi_monitor_dvi: return "dvi";
1119 case sunxi_monitor_hdmi: return "hdmi";
1120 case sunxi_monitor_lcd: return "lcd";
1121 case sunxi_monitor_vga: return "vga";
1122 case sunxi_monitor_composite_pal: return "composite-pal";
1123 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1124 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1125 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
1127 return NULL; /* never reached */
1130 ulong board_get_usable_ram_top(ulong total_size)
1132 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1135 static bool sunxi_has_hdmi(void)
1137 #ifdef CONFIG_VIDEO_HDMI
1144 static bool sunxi_has_lcd(void)
1146 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1148 return lcd_mode[0] != 0;
1151 static bool sunxi_has_vga(void)
1153 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1160 static bool sunxi_has_composite(void)
1162 #ifdef CONFIG_VIDEO_COMPOSITE
1169 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1171 if (allow_hdmi && sunxi_has_hdmi())
1172 return sunxi_monitor_dvi;
1173 else if (sunxi_has_lcd())
1174 return sunxi_monitor_lcd;
1175 else if (sunxi_has_vga())
1176 return sunxi_monitor_vga;
1177 else if (sunxi_has_composite())
1178 return sunxi_monitor_composite_pal;
1180 return sunxi_monitor_none;
1183 void *video_hw_init(void)
1185 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1186 const struct ctfb_res_modes *mode;
1187 struct ctfb_res_modes custom;
1188 const char *options;
1189 #ifdef CONFIG_VIDEO_HDMI
1190 int ret, hpd, hpd_delay, edid;
1192 int i, overscan_offset, overscan_x, overscan_y;
1193 unsigned int fb_dma_addr;
1195 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1197 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1199 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1200 &sunxi_display.depth, &options);
1201 #ifdef CONFIG_VIDEO_HDMI
1202 hpd = video_get_option_int(options, "hpd", 1);
1203 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1204 edid = video_get_option_int(options, "edid", 1);
1206 overscan_x = video_get_option_int(options, "overscan_x", -1);
1207 overscan_y = video_get_option_int(options, "overscan_y", -1);
1208 sunxi_display.monitor = sunxi_get_default_mon(true);
1209 video_get_option_string(options, "monitor", mon, sizeof(mon),
1210 sunxi_get_mon_desc(sunxi_display.monitor));
1211 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1212 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1213 sunxi_display.monitor = i;
1217 if (i > SUNXI_MONITOR_LAST)
1218 printf("Unknown monitor: '%s', falling back to '%s'\n",
1219 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1221 #ifdef CONFIG_VIDEO_HDMI
1222 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1223 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1224 sunxi_display.monitor == sunxi_monitor_hdmi) {
1225 /* Always call hdp_detect, as it also enables clocks, etc. */
1226 ret = sunxi_hdmi_hpd_detect(hpd_delay);
1228 printf("HDMI connected: ");
1229 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1232 sunxi_hdmi_shutdown();
1233 sunxi_display.monitor = sunxi_get_default_mon(false);
1234 } /* else continue with hdmi/dvi without a cable connected */
1238 switch (sunxi_display.monitor) {
1239 case sunxi_monitor_none:
1241 case sunxi_monitor_dvi:
1242 case sunxi_monitor_hdmi:
1243 if (!sunxi_has_hdmi()) {
1244 printf("HDMI/DVI not supported on this board\n");
1245 sunxi_display.monitor = sunxi_monitor_none;
1249 case sunxi_monitor_lcd:
1250 if (!sunxi_has_lcd()) {
1251 printf("LCD not supported on this board\n");
1252 sunxi_display.monitor = sunxi_monitor_none;
1255 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1258 case sunxi_monitor_vga:
1259 if (!sunxi_has_vga()) {
1260 printf("VGA not supported on this board\n");
1261 sunxi_display.monitor = sunxi_monitor_none;
1264 sunxi_display.depth = 18;
1266 case sunxi_monitor_composite_pal:
1267 case sunxi_monitor_composite_ntsc:
1268 case sunxi_monitor_composite_pal_m:
1269 case sunxi_monitor_composite_pal_nc:
1270 if (!sunxi_has_composite()) {
1271 printf("Composite video not supported on this board\n");
1272 sunxi_display.monitor = sunxi_monitor_none;
1275 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1276 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1277 mode = &composite_video_modes[0];
1279 mode = &composite_video_modes[1];
1280 sunxi_display.depth = 24;
1284 /* Yes these defaults are quite high, overscan on composite sucks... */
1285 if (overscan_x == -1)
1286 overscan_x = sunxi_is_composite() ? 32 : 0;
1287 if (overscan_y == -1)
1288 overscan_y = sunxi_is_composite() ? 20 : 0;
1290 sunxi_display.fb_size =
1291 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1292 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1293 /* We want to keep the fb_base for simplefb page aligned, where as
1294 * the sunxi dma engines will happily accept an unaligned address. */
1295 if (overscan_offset)
1296 sunxi_display.fb_size += 0x1000;
1298 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1299 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1300 sunxi_display.fb_size >> 10,
1301 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1305 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1306 mode->xres, mode->yres,
1307 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1308 sunxi_get_mon_desc(sunxi_display.monitor),
1309 overscan_x, overscan_y);
1311 gd->fb_base = gd->bd->bi_dram[0].start +
1312 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1313 sunxi_engines_init();
1315 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1316 sunxi_display.fb_addr = gd->fb_base;
1317 if (overscan_offset) {
1318 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1319 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1320 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1321 flush_cache(gd->fb_base, sunxi_display.fb_size);
1323 sunxi_mode_set(mode, fb_dma_addr);
1326 * These are the only members of this structure that are used. All the
1327 * others are driver specific. The pitch is stored in plnSizeX.
1329 graphic_device->frameAdrs = sunxi_display.fb_addr;
1330 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1331 graphic_device->gdfBytesPP = 4;
1332 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1333 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1334 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1336 return graphic_device;
1342 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1343 int sunxi_simplefb_setup(void *blob)
1345 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1348 const char *pipeline = NULL;
1350 #ifdef CONFIG_MACH_SUN4I
1351 #define PIPELINE_PREFIX "de_fe0-"
1353 #define PIPELINE_PREFIX
1356 switch (sunxi_display.monitor) {
1357 case sunxi_monitor_none:
1359 case sunxi_monitor_dvi:
1360 case sunxi_monitor_hdmi:
1361 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1363 case sunxi_monitor_lcd:
1364 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1366 case sunxi_monitor_vga:
1367 #ifdef CONFIG_VIDEO_VGA
1368 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1369 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1370 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1373 case sunxi_monitor_composite_pal:
1374 case sunxi_monitor_composite_ntsc:
1375 case sunxi_monitor_composite_pal_m:
1376 case sunxi_monitor_composite_pal_nc:
1377 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1381 offset = sunxi_simplefb_fdt_match(blob, pipeline);
1383 eprintf("Cannot setup simplefb: node not found\n");
1384 return 0; /* Keep older kernels working */
1388 * Do not report the framebuffer as free RAM to the OS, note we cannot
1389 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1390 * and e.g. Linux refuses to iomap RAM on ARM, see:
1391 * linux/arch/arm/mm/ioremap.c around line 301.
1393 start = gd->bd->bi_dram[0].start;
1394 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1395 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1397 eprintf("Cannot setup simplefb: Error reserving memory\n");
1401 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1402 graphic_device->winSizeX, graphic_device->winSizeY,
1403 graphic_device->plnSizeX, "x8r8g8b8");
1405 eprintf("Cannot setup simplefb: Error setting properties\n");
1409 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */