1 // SPDX-License-Identifier: GPL-2.0+
3 * Display driver for Allwinner SoCs.
5 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
6 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
13 #include <efi_loader.h>
16 #include <linux/delay.h>
18 #include <asm/arch/clock.h>
19 #include <asm/arch/display.h>
20 #include <asm/arch/lcdc.h>
21 #include <asm/arch/pwm.h>
22 #include <asm/arch/tve.h>
23 #include <asm/global_data.h>
29 #include <fdt_support.h>
33 #include <dm/uclass-internal.h>
34 #include "../videomodes.h"
35 #include "../anx9804.h"
36 #include "../hitachi_tx18d42vm_lcd.h"
37 #include "../ssd2828.h"
38 #include "simplefb_common.h"
40 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
48 DECLARE_GLOBAL_DATA_PTR;
50 /* Maximum LCD size we support */
51 #define LCD_MAX_WIDTH 3840
52 #define LCD_MAX_HEIGHT 2160
53 #define LCD_MAX_LOG2_BPP VIDEO_BPP32
61 sunxi_monitor_composite_pal,
62 sunxi_monitor_composite_ntsc,
63 sunxi_monitor_composite_pal_m,
64 sunxi_monitor_composite_pal_nc,
66 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
68 struct sunxi_display_priv {
69 enum sunxi_monitor monitor;
75 const struct ctfb_res_modes composite_video_modes[2] = {
76 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
77 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
78 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
81 #ifdef CONFIG_VIDEO_HDMI
84 * Wait up to 200ms for value to be set in given part of reg.
86 static int await_completion(u32 *reg, u32 mask, u32 val)
88 unsigned long tmo = timer_get_us() + 200000;
90 while ((readl(reg) & mask) != val) {
91 if (timer_get_us() > tmo) {
92 printf("DDC: timeout reading EDID\n");
99 static int sunxi_hdmi_hpd_detect(int hpd_delay)
101 struct sunxi_ccm_reg * const ccm =
102 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
103 struct sunxi_hdmi_reg * const hdmi =
104 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
105 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
107 /* Set pll3 to 300MHz */
108 clock_set_pll3(300000000);
110 /* Set hdmi parent to pll3 */
111 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
114 /* Set ahb gating to pass */
115 #ifdef CONFIG_SUNXI_GEN_SUN6I
116 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
118 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
121 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
123 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
124 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
126 /* Enable PLLs for eventual DDC */
127 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
129 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
131 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
133 while (timer_get_us() < tmo) {
134 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
141 static void sunxi_hdmi_shutdown(void)
143 struct sunxi_ccm_reg * const ccm =
144 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
145 struct sunxi_hdmi_reg * const hdmi =
146 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
148 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
149 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
150 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
151 #ifdef CONFIG_SUNXI_GEN_SUN6I
152 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
157 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
159 struct sunxi_hdmi_reg * const hdmi =
160 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
162 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
163 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
164 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
165 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
166 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
167 #ifndef CONFIG_MACH_SUN6I
168 writel(n, &hdmi->ddc_byte_count);
169 writel(cmnd, &hdmi->ddc_cmnd);
171 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
173 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
175 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
178 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
180 struct sunxi_hdmi_reg * const hdmi =
181 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
190 if (sunxi_hdmi_ddc_do_command(
191 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
195 for (i = 0; i < n; i++)
196 *buf++ = readb(&hdmi->ddc_fifo_data);
205 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
210 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
213 r = edid_check_checksum(buf);
215 printf("EDID block %d: checksum error%s\n",
216 block, retries ? ", retrying" : "");
218 } while (r && retries--);
223 static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
224 struct ctfb_res_modes *mode,
227 struct edid1_info edid1;
228 struct edid_cea861_info cea681[4];
229 struct edid_detailed_timing *t =
230 (struct edid_detailed_timing *)edid1.monitor_details.timing;
231 struct sunxi_hdmi_reg * const hdmi =
232 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
233 struct sunxi_ccm_reg * const ccm =
234 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
235 int i, r, ext_blocks = 0;
237 /* Reset i2c controller */
238 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
239 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
240 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
241 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
242 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
243 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
246 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
247 #ifndef CONFIG_MACH_SUN6I
248 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
249 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
252 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
254 r = edid_check_info(&edid1);
257 printf("EDID: invalid EDID data\n");
262 ext_blocks = edid1.extension_flag;
265 for (i = 0; i < ext_blocks; i++) {
266 if (sunxi_hdmi_edid_get_block(1 + i,
267 (u8 *)&cea681[i]) != 0) {
274 /* Disable DDC engine, no longer needed */
275 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
276 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
281 /* We want version 1.3 or 1.2 with detailed timing info */
282 if (edid1.version != 1 || (edid1.revision < 3 &&
283 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
284 printf("EDID: unsupported version %d.%d\n",
285 edid1.version, edid1.revision);
289 /* Take the first usable detailed timing */
290 for (i = 0; i < 4; i++, t++) {
291 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
296 printf("EDID: no usable detailed timing found\n");
300 /* Check for basic audio support, if found enable hdmi output */
301 sunxi_display->monitor = sunxi_monitor_dvi;
302 for (i = 0; i < ext_blocks; i++) {
303 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
304 cea681[i].revision < 2)
307 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
308 sunxi_display->monitor = sunxi_monitor_hdmi;
314 #endif /* CONFIG_VIDEO_HDMI */
316 #ifdef CONFIG_MACH_SUN4I
318 * Testing has shown that on sun4i the display backend engine does not have
319 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
320 * fifo underruns. So on sun4i we use the display frontend engine to do the
321 * dma from memory, as the frontend does have deep enough fifo-s.
324 static const u32 sun4i_vert_coef[32] = {
325 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
326 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
327 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
328 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
329 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
330 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
331 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
332 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
335 static const u32 sun4i_horz_coef[64] = {
336 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
337 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
338 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
339 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
340 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
341 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
342 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
343 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
344 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
345 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
346 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
347 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
348 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
349 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
350 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
351 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
354 static void sunxi_frontend_init(void)
356 struct sunxi_ccm_reg * const ccm =
357 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
358 struct sunxi_de_fe_reg * const de_fe =
359 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
363 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
364 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
365 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
367 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
369 for (i = 0; i < 32; i++) {
370 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
371 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
372 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
373 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
374 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
375 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
378 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
381 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
382 unsigned int address)
384 struct sunxi_de_fe_reg * const de_fe =
385 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
387 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
388 writel(CFG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
389 writel(mode->xres * 4, &de_fe->ch0_stride);
390 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
391 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
393 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
395 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
396 &de_fe->ch0_outsize);
397 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
398 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
400 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
402 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
403 &de_fe->ch1_outsize);
404 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
405 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
407 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
410 static void sunxi_frontend_enable(void)
412 struct sunxi_de_fe_reg * const de_fe =
413 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
415 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
418 static void sunxi_frontend_init(void) {}
419 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
420 unsigned int address) {}
421 static void sunxi_frontend_enable(void) {}
424 static bool sunxi_is_composite(enum sunxi_monitor monitor)
427 case sunxi_monitor_none:
428 case sunxi_monitor_dvi:
429 case sunxi_monitor_hdmi:
430 case sunxi_monitor_lcd:
431 case sunxi_monitor_vga:
433 case sunxi_monitor_composite_pal:
434 case sunxi_monitor_composite_ntsc:
435 case sunxi_monitor_composite_pal_m:
436 case sunxi_monitor_composite_pal_nc:
440 return false; /* Never reached */
444 * This is the entity that mixes and matches the different layers and inputs.
445 * Allwinner calls it the back-end, but i like composer better.
447 static void sunxi_composer_init(void)
449 struct sunxi_ccm_reg * const ccm =
450 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
451 struct sunxi_de_be_reg * const de_be =
452 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
455 sunxi_frontend_init();
457 #ifdef CONFIG_SUNXI_GEN_SUN6I
459 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
463 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
464 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
465 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
467 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
469 /* Engine bug, clear registers after reset */
470 for (i = 0x0800; i < 0x1000; i += 4)
471 writel(0, SUNXI_DE_BE0_BASE + i);
473 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
476 static const u32 sunxi_rgb2yuv_coef[12] = {
477 0x00000107, 0x00000204, 0x00000064, 0x00000108,
478 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
479 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
482 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
483 unsigned int address,
484 enum sunxi_monitor monitor)
486 struct sunxi_de_be_reg * const de_be =
487 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
490 sunxi_frontend_mode_set(mode, address);
492 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
494 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
495 &de_be->layer0_size);
496 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
497 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
498 writel(address << 3, &de_be->layer0_addr_low32b);
499 writel(address >> 29, &de_be->layer0_addr_high4b);
501 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
503 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
505 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
506 if (mode->vmode == FB_VMODE_INTERLACED)
507 setbits_le32(&de_be->mode,
508 #ifndef CONFIG_MACH_SUN5I
509 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
511 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
513 if (sunxi_is_composite(monitor)) {
514 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
515 &de_be->output_color_ctrl);
516 for (i = 0; i < 12; i++)
517 writel(sunxi_rgb2yuv_coef[i],
518 &de_be->output_color_coef[i]);
522 static void sunxi_composer_enable(void)
524 struct sunxi_de_be_reg * const de_be =
525 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
527 sunxi_frontend_enable();
529 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
530 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
533 static void sunxi_lcdc_init(void)
535 struct sunxi_ccm_reg * const ccm =
536 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
537 struct sunxi_lcdc_reg * const lcdc =
538 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
541 #ifdef CONFIG_SUNXI_GEN_SUN6I
542 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
544 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
548 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
549 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
550 #ifdef CONFIG_SUNXI_GEN_SUN6I
551 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
553 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
560 static void sunxi_lcdc_panel_enable(void)
565 * Start with backlight disabled to avoid the screen flashing to
566 * white while the lcd inits.
568 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
570 gpio_request(pin, "lcd_backlight_enable");
571 gpio_direction_output(pin, 0);
574 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
576 gpio_request(pin, "lcd_backlight_pwm");
577 gpio_direction_output(pin, PWM_OFF);
580 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
581 if (reset_pin >= 0) {
582 gpio_request(reset_pin, "lcd_reset");
583 gpio_direction_output(reset_pin, 0); /* Assert reset */
586 /* Give the backlight some time to turn off and power up the panel. */
588 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
590 gpio_request(pin, "lcd_power");
591 gpio_direction_output(pin, 1);
595 gpio_direction_output(reset_pin, 1); /* De-assert reset */
598 static void sunxi_lcdc_backlight_enable(void)
603 * We want to have scanned out at least one frame before enabling the
604 * backlight to avoid the screen flashing to white when we enable it.
608 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
610 gpio_direction_output(pin, 1);
612 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
613 #ifdef SUNXI_PWM_PIN0
614 if (pin == SUNXI_PWM_PIN0) {
615 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
616 SUNXI_PWM_CTRL_ENABLE0 |
617 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
618 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
619 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
624 gpio_direction_output(pin, PWM_ON);
627 static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
628 const struct ctfb_res_modes *mode,
629 bool for_ext_vga_dac)
631 struct sunxi_lcdc_reg * const lcdc =
632 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
633 struct sunxi_ccm_reg * const ccm =
634 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
635 int clk_div, clk_double, pin;
636 struct display_timing timing;
638 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
639 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
641 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
643 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
644 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
646 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
647 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
649 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
650 sunxi_gpio_set_drv(pin, 3);
654 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
655 sunxi_is_composite(sunxi_display->monitor));
657 video_ctfb_mode_to_display_timing(mode, &timing);
658 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
659 sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
662 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
663 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
664 int *clk_div, int *clk_double,
665 bool use_portd_hvsync,
666 enum sunxi_monitor monitor)
668 struct sunxi_lcdc_reg * const lcdc =
669 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
670 struct sunxi_ccm_reg * const ccm =
671 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
672 struct display_timing timing;
674 video_ctfb_mode_to_display_timing(mode, &timing);
675 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
676 sunxi_is_composite(monitor));
678 if (use_portd_hvsync) {
679 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
680 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
683 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
684 sunxi_is_composite(monitor));
686 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
688 #ifdef CONFIG_VIDEO_HDMI
690 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
692 struct sunxi_hdmi_reg * const hdmi =
693 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
695 u8 avi_info_frame[17] = {
696 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700 u8 vendor_info_frame[19] = {
701 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707 if (mode->pixclock_khz <= 27000)
708 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
710 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
712 if (mode->xres * 100 / mode->yres < 156)
713 avi_info_frame[5] |= 0x18; /* 4 : 3 */
715 avi_info_frame[5] |= 0x28; /* 16 : 9 */
717 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
718 checksum += avi_info_frame[i];
720 avi_info_frame[3] = 0x100 - checksum;
722 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
723 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
725 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
726 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
728 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
729 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
731 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
732 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
734 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
737 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
738 int clk_div, int clk_double,
739 enum sunxi_monitor monitor)
741 struct sunxi_hdmi_reg * const hdmi =
742 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
745 /* Write clear interrupt status bits */
746 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
748 if (monitor == sunxi_monitor_hdmi)
749 sunxi_hdmi_setup_info_frames(mode);
751 /* Set input sync enable */
752 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
754 /* Init various registers, select pll3 as clock source */
755 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
756 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
757 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
758 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
759 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
761 /* Setup clk div and doubler */
762 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
763 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
765 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
767 /* Setup timing registers */
768 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
771 x = mode->hsync_len + mode->left_margin;
772 y = mode->vsync_len + mode->upper_margin;
773 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
775 x = mode->right_margin;
776 y = mode->lower_margin;
777 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
781 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
783 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
784 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
786 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
787 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
790 static void sunxi_hdmi_enable(void)
792 struct sunxi_hdmi_reg * const hdmi =
793 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
796 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
799 #endif /* CONFIG_VIDEO_HDMI */
801 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
803 static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
805 struct sunxi_ccm_reg * const ccm =
806 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
807 struct sunxi_tve_reg * const tve =
808 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
811 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
813 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
816 case sunxi_monitor_vga:
817 tvencoder_mode_set(tve, tve_mode_vga);
819 case sunxi_monitor_composite_pal_nc:
820 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
822 case sunxi_monitor_composite_pal:
823 tvencoder_mode_set(tve, tve_mode_composite_pal);
825 case sunxi_monitor_composite_pal_m:
826 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
828 case sunxi_monitor_composite_ntsc:
829 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
831 case sunxi_monitor_none:
832 case sunxi_monitor_dvi:
833 case sunxi_monitor_hdmi:
834 case sunxi_monitor_lcd:
839 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
841 static void sunxi_drc_init(void)
843 #ifdef CONFIG_SUNXI_GEN_SUN6I
844 struct sunxi_ccm_reg * const ccm =
845 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
847 /* On sun6i the drc must be clocked even when in pass-through mode */
848 #ifdef CONFIG_MACH_SUN8I_A33
849 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
851 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
852 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
856 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
857 static void sunxi_vga_external_dac_enable(void)
861 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
863 gpio_request(pin, "vga_enable");
864 gpio_direction_output(pin, 1);
867 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
869 #ifdef CONFIG_VIDEO_LCD_SSD2828
870 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
872 struct ssd2828_config cfg = {
873 .csx_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
874 .sck_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
875 .sdi_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
876 .sdo_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
877 .reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
878 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
879 .ssd2828_color_depth = 24,
880 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
881 .mipi_dsi_number_of_data_lanes = 4,
882 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
883 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
884 .mipi_dsi_delay_after_set_display_on_ms = 200
886 #error MIPI LCD panel needs configuration parameters
890 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
891 printf("SSD2828: SPI pins are not properly configured\n");
894 if (cfg.reset_pin == -1) {
895 printf("SSD2828: Reset pin is not properly configured\n");
899 return ssd2828_init(&cfg, mode);
901 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
903 #ifdef CONFIG_VIDEO_LCD_PANEL_I2C
904 static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display)
906 const char *name = CONFIG_VIDEO_LCD_PANEL_I2C_NAME;
907 struct udevice *i2c_bus;
910 ret = uclass_get_device_by_name(UCLASS_I2C, name, &i2c_bus);
914 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
916 * The anx9804 needs 1.8V from eldo3, we do this here
917 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
918 * to avoid turning this on when using hdmi output.
920 axp_set_eldo(3, 1800);
921 anx9804_init(i2c_bus, 4,
922 ANX9804_DATA_RATE_1620M,
923 sunxi_display->depth);
925 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
926 struct udevice *chip;
928 ret = i2c_get_chip(i2c_bus, 0x5c, 1, &chip);
932 dm_i2c_reg_write(chip, 0x04, 0x42); /* Turn on the LCD */
936 static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display) {}
939 static void sunxi_engines_init(void)
941 sunxi_composer_init();
946 static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
947 const struct ctfb_res_modes *mode,
948 unsigned int address)
950 enum sunxi_monitor monitor = sunxi_display->monitor;
951 int __maybe_unused clk_div, clk_double;
952 struct sunxi_lcdc_reg * const lcdc =
953 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
954 struct sunxi_tve_reg * __maybe_unused const tve =
955 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
957 switch (sunxi_display->monitor) {
958 case sunxi_monitor_none:
960 case sunxi_monitor_dvi:
961 case sunxi_monitor_hdmi:
962 #ifdef CONFIG_VIDEO_HDMI
963 sunxi_composer_mode_set(mode, address, monitor);
964 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
965 sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
966 sunxi_composer_enable();
967 lcdc_enable(lcdc, sunxi_display->depth);
971 case sunxi_monitor_lcd:
972 sunxi_lcdc_panel_enable();
973 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
974 mdelay(50); /* Wait for lcd controller power on */
975 hitachi_tx18d42vm_init();
977 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_I2C))
978 sunxi_panel_i2c_init(sunxi_display);
979 sunxi_composer_mode_set(mode, address, monitor);
980 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
981 sunxi_composer_enable();
982 lcdc_enable(lcdc, sunxi_display->depth);
983 #ifdef CONFIG_VIDEO_LCD_SSD2828
984 sunxi_ssd2828_init(mode);
986 sunxi_lcdc_backlight_enable();
988 case sunxi_monitor_vga:
989 #ifdef CONFIG_VIDEO_VGA
990 sunxi_composer_mode_set(mode, address, monitor);
991 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
992 sunxi_tvencoder_mode_set(monitor);
993 sunxi_composer_enable();
994 lcdc_enable(lcdc, sunxi_display->depth);
995 tvencoder_enable(tve);
996 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
997 sunxi_composer_mode_set(mode, address, monitor);
998 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
999 sunxi_composer_enable();
1000 lcdc_enable(lcdc, sunxi_display->depth);
1001 sunxi_vga_external_dac_enable();
1004 case sunxi_monitor_composite_pal:
1005 case sunxi_monitor_composite_ntsc:
1006 case sunxi_monitor_composite_pal_m:
1007 case sunxi_monitor_composite_pal_nc:
1008 #ifdef CONFIG_VIDEO_COMPOSITE
1009 sunxi_composer_mode_set(mode, address, monitor);
1010 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
1011 sunxi_tvencoder_mode_set(monitor);
1012 sunxi_composer_enable();
1013 lcdc_enable(lcdc, sunxi_display->depth);
1014 tvencoder_enable(tve);
1020 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1023 case sunxi_monitor_dvi: return "dvi";
1024 case sunxi_monitor_hdmi: return "hdmi";
1025 case sunxi_monitor_lcd: return "lcd";
1026 case sunxi_monitor_vga: return "vga";
1027 case sunxi_monitor_composite_pal: return "composite-pal";
1028 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1029 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1030 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
1031 case sunxi_monitor_none: /* fall through */
1032 default: return "none";
1036 static bool sunxi_has_hdmi(void)
1038 #ifdef CONFIG_VIDEO_HDMI
1045 static bool sunxi_has_lcd(void)
1047 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1049 return lcd_mode[0] != 0;
1052 static bool sunxi_has_vga(void)
1054 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1061 static bool sunxi_has_composite(void)
1063 #ifdef CONFIG_VIDEO_COMPOSITE
1070 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1072 if (allow_hdmi && sunxi_has_hdmi())
1073 return sunxi_monitor_dvi;
1074 else if (sunxi_has_lcd())
1075 return sunxi_monitor_lcd;
1076 else if (sunxi_has_vga())
1077 return sunxi_monitor_vga;
1078 else if (sunxi_has_composite())
1079 return sunxi_monitor_composite_pal;
1081 return sunxi_monitor_none;
1084 static int sunxi_de_probe(struct udevice *dev)
1086 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
1087 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1088 struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
1089 const struct ctfb_res_modes *mode;
1090 struct ctfb_res_modes custom;
1091 const char *options;
1092 #ifdef CONFIG_VIDEO_HDMI
1093 int hpd, hpd_delay, edid;
1096 int i, overscan_offset, overscan_x, overscan_y;
1097 unsigned int fb_dma_addr;
1099 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1101 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1102 &sunxi_display->depth, &options);
1103 #ifdef CONFIG_VIDEO_HDMI
1104 hpd = video_get_option_int(options, "hpd", 1);
1105 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1106 edid = video_get_option_int(options, "edid", 1);
1108 overscan_x = video_get_option_int(options, "overscan_x", -1);
1109 overscan_y = video_get_option_int(options, "overscan_y", -1);
1110 sunxi_display->monitor = sunxi_get_default_mon(true);
1111 video_get_option_string(options, "monitor", mon, sizeof(mon),
1112 sunxi_get_mon_desc(sunxi_display->monitor));
1113 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1114 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1115 sunxi_display->monitor = i;
1119 if (i > SUNXI_MONITOR_LAST)
1120 printf("Unknown monitor: '%s', falling back to '%s'\n",
1121 mon, sunxi_get_mon_desc(sunxi_display->monitor));
1123 #ifdef CONFIG_VIDEO_HDMI
1124 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1125 if (sunxi_display->monitor == sunxi_monitor_dvi ||
1126 sunxi_display->monitor == sunxi_monitor_hdmi) {
1127 /* Always call hdp_detect, as it also enables clocks, etc. */
1128 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1129 if (hdmi_present && edid) {
1130 printf("HDMI connected: ");
1131 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
1134 hdmi_present = false;
1136 /* Fall back to EDID in case HPD failed */
1137 if (edid && !hdmi_present) {
1138 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
1140 hdmi_present = true;
1143 /* Shut down when display was not found */
1144 if ((hpd || edid) && !hdmi_present) {
1145 sunxi_hdmi_shutdown();
1146 sunxi_display->monitor = sunxi_get_default_mon(false);
1147 } /* else continue with hdmi/dvi without a cable connected */
1151 switch (sunxi_display->monitor) {
1152 case sunxi_monitor_none:
1153 printf("Unknown monitor\n");
1155 case sunxi_monitor_dvi:
1156 case sunxi_monitor_hdmi:
1157 if (!sunxi_has_hdmi()) {
1158 printf("HDMI/DVI not supported on this board\n");
1159 sunxi_display->monitor = sunxi_monitor_none;
1163 case sunxi_monitor_lcd:
1164 if (!sunxi_has_lcd()) {
1165 printf("LCD not supported on this board\n");
1166 sunxi_display->monitor = sunxi_monitor_none;
1169 sunxi_display->depth = video_get_params(&custom, lcd_mode);
1172 case sunxi_monitor_vga:
1173 if (!sunxi_has_vga()) {
1174 printf("VGA not supported on this board\n");
1175 sunxi_display->monitor = sunxi_monitor_none;
1178 sunxi_display->depth = 18;
1180 case sunxi_monitor_composite_pal:
1181 case sunxi_monitor_composite_ntsc:
1182 case sunxi_monitor_composite_pal_m:
1183 case sunxi_monitor_composite_pal_nc:
1184 if (!sunxi_has_composite()) {
1185 printf("Composite video not supported on this board\n");
1186 sunxi_display->monitor = sunxi_monitor_none;
1189 if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
1190 sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
1191 mode = &composite_video_modes[0];
1193 mode = &composite_video_modes[1];
1194 sunxi_display->depth = 24;
1198 /* Yes these defaults are quite high, overscan on composite sucks... */
1199 if (overscan_x == -1)
1200 overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
1201 if (overscan_y == -1)
1202 overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
1204 sunxi_display->fb_size = plat->size;
1205 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1206 /* We want to keep the fb_base for simplefb page aligned, where as
1207 * the sunxi dma engines will happily accept an unaligned address. */
1208 if (overscan_offset)
1209 sunxi_display->fb_size += 0x1000;
1211 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1212 mode->xres, mode->yres,
1213 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1214 sunxi_get_mon_desc(sunxi_display->monitor),
1215 overscan_x, overscan_y);
1217 sunxi_display->fb_addr = plat->base;
1218 sunxi_engines_init();
1220 #ifdef CONFIG_EFI_LOADER
1221 efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
1222 EFI_RESERVED_MEMORY_TYPE);
1225 fb_dma_addr = sunxi_display->fb_addr - CFG_SYS_SDRAM_BASE;
1226 if (overscan_offset) {
1227 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1228 sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
1229 memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
1230 flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
1232 sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
1234 /* The members of struct video_priv to be set by the driver. */
1235 uc_priv->bpix = VIDEO_BPP32;
1236 uc_priv->xsize = mode->xres;
1237 uc_priv->ysize = mode->yres;
1239 video_set_flush_dcache(dev, true);
1244 static int sunxi_de_bind(struct udevice *dev)
1246 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1248 plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
1253 static const struct video_ops sunxi_de_ops = {
1256 U_BOOT_DRIVER(sunxi_de) = {
1259 .ops = &sunxi_de_ops,
1260 .bind = sunxi_de_bind,
1261 .probe = sunxi_de_probe,
1262 .priv_auto = sizeof(struct sunxi_display_priv),
1263 .flags = DM_FLAG_PRE_RELOC,
1266 U_BOOT_DRVINFO(sunxi_de) = {
1273 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1274 int sunxi_simplefb_setup(void *blob)
1276 struct sunxi_display_priv *sunxi_display;
1277 struct video_priv *uc_priv;
1281 const char *pipeline = NULL;
1283 #ifdef CONFIG_MACH_SUN4I
1284 #define PIPELINE_PREFIX "de_fe0-"
1286 #define PIPELINE_PREFIX
1289 ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
1291 printf("DE not present\n");
1293 } else if (!device_active(de)) {
1294 printf("DE is present but not probed\n");
1298 uc_priv = dev_get_uclass_priv(de);
1299 sunxi_display = dev_get_priv(de);
1301 switch (sunxi_display->monitor) {
1302 case sunxi_monitor_none:
1304 case sunxi_monitor_dvi:
1305 case sunxi_monitor_hdmi:
1306 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1308 case sunxi_monitor_lcd:
1309 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1311 case sunxi_monitor_vga:
1312 #ifdef CONFIG_VIDEO_VGA
1313 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1314 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1315 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1318 case sunxi_monitor_composite_pal:
1319 case sunxi_monitor_composite_ntsc:
1320 case sunxi_monitor_composite_pal_m:
1321 case sunxi_monitor_composite_pal_nc:
1322 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1326 offset = sunxi_simplefb_fdt_match(blob, pipeline);
1328 eprintf("Cannot setup simplefb: node not found\n");
1329 return 0; /* Keep older kernels working */
1333 * Do not report the framebuffer as free RAM to the OS, note we cannot
1334 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1335 * and e.g. Linux refuses to iomap RAM on ARM, see:
1336 * linux/arch/arm/mm/ioremap.c around line 301.
1338 start = gd->bd->bi_dram[0].start;
1339 size = sunxi_display->fb_addr - start;
1340 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1342 eprintf("Cannot setup simplefb: Error reserving memory\n");
1346 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
1347 uc_priv->xsize, uc_priv->ysize,
1348 VNBYTES(uc_priv->bpix) * uc_priv->xsize,
1351 eprintf("Cannot setup simplefb: Error setting properties\n");
1355 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */