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>
34 #include <dm/uclass-internal.h>
35 #include "../videomodes.h"
36 #include "../anx9804.h"
37 #include "../hitachi_tx18d42vm_lcd.h"
38 #include "../ssd2828.h"
39 #include "simplefb_common.h"
41 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
49 DECLARE_GLOBAL_DATA_PTR;
51 /* Maximum LCD size we support */
52 #define LCD_MAX_WIDTH 3840
53 #define LCD_MAX_HEIGHT 2160
54 #define LCD_MAX_LOG2_BPP VIDEO_BPP32
62 sunxi_monitor_composite_pal,
63 sunxi_monitor_composite_ntsc,
64 sunxi_monitor_composite_pal_m,
65 sunxi_monitor_composite_pal_nc,
67 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
69 struct sunxi_display_priv {
70 enum sunxi_monitor monitor;
76 const struct ctfb_res_modes composite_video_modes[2] = {
77 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
78 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
79 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
82 #ifdef CONFIG_VIDEO_HDMI
85 * Wait up to 200ms for value to be set in given part of reg.
87 static int await_completion(u32 *reg, u32 mask, u32 val)
89 unsigned long tmo = timer_get_us() + 200000;
91 while ((readl(reg) & mask) != val) {
92 if (timer_get_us() > tmo) {
93 printf("DDC: timeout reading EDID\n");
100 static int sunxi_hdmi_hpd_detect(int hpd_delay)
102 struct sunxi_ccm_reg * const ccm =
103 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
104 struct sunxi_hdmi_reg * const hdmi =
105 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
106 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
108 /* Set pll3 to 300MHz */
109 clock_set_pll3(300000000);
111 /* Set hdmi parent to pll3 */
112 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
115 /* Set ahb gating to pass */
116 #ifdef CONFIG_SUNXI_GEN_SUN6I
117 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
119 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
122 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
124 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
125 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
127 /* Enable PLLs for eventual DDC */
128 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
130 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
132 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
134 while (timer_get_us() < tmo) {
135 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
142 static void sunxi_hdmi_shutdown(void)
144 struct sunxi_ccm_reg * const ccm =
145 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
146 struct sunxi_hdmi_reg * const hdmi =
147 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
149 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
150 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
151 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
152 #ifdef CONFIG_SUNXI_GEN_SUN6I
153 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
158 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
160 struct sunxi_hdmi_reg * const hdmi =
161 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
163 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
164 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
165 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
166 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
167 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
168 #ifndef CONFIG_MACH_SUN6I
169 writel(n, &hdmi->ddc_byte_count);
170 writel(cmnd, &hdmi->ddc_cmnd);
172 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
174 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
176 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
179 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
181 struct sunxi_hdmi_reg * const hdmi =
182 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
191 if (sunxi_hdmi_ddc_do_command(
192 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
196 for (i = 0; i < n; i++)
197 *buf++ = readb(&hdmi->ddc_fifo_data);
206 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
211 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
214 r = edid_check_checksum(buf);
216 printf("EDID block %d: checksum error%s\n",
217 block, retries ? ", retrying" : "");
219 } while (r && retries--);
224 static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
225 struct ctfb_res_modes *mode,
228 struct edid1_info edid1;
229 struct edid_cea861_info cea681[4];
230 struct edid_detailed_timing *t =
231 (struct edid_detailed_timing *)edid1.monitor_details.timing;
232 struct sunxi_hdmi_reg * const hdmi =
233 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
234 struct sunxi_ccm_reg * const ccm =
235 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
236 int i, r, ext_blocks = 0;
238 /* Reset i2c controller */
239 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
240 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
241 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
242 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
243 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
244 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
247 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
248 #ifndef CONFIG_MACH_SUN6I
249 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
250 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
253 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
255 r = edid_check_info(&edid1);
258 printf("EDID: invalid EDID data\n");
263 ext_blocks = edid1.extension_flag;
266 for (i = 0; i < ext_blocks; i++) {
267 if (sunxi_hdmi_edid_get_block(1 + i,
268 (u8 *)&cea681[i]) != 0) {
275 /* Disable DDC engine, no longer needed */
276 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
277 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
282 /* We want version 1.3 or 1.2 with detailed timing info */
283 if (edid1.version != 1 || (edid1.revision < 3 &&
284 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
285 printf("EDID: unsupported version %d.%d\n",
286 edid1.version, edid1.revision);
290 /* Take the first usable detailed timing */
291 for (i = 0; i < 4; i++, t++) {
292 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
297 printf("EDID: no usable detailed timing found\n");
301 /* Check for basic audio support, if found enable hdmi output */
302 sunxi_display->monitor = sunxi_monitor_dvi;
303 for (i = 0; i < ext_blocks; i++) {
304 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
305 cea681[i].revision < 2)
308 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
309 sunxi_display->monitor = sunxi_monitor_hdmi;
315 #endif /* CONFIG_VIDEO_HDMI */
317 #ifdef CONFIG_MACH_SUN4I
319 * Testing has shown that on sun4i the display backend engine does not have
320 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
321 * fifo underruns. So on sun4i we use the display frontend engine to do the
322 * dma from memory, as the frontend does have deep enough fifo-s.
325 static const u32 sun4i_vert_coef[32] = {
326 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
327 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
328 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
329 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
330 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
331 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
332 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
333 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
336 static const u32 sun4i_horz_coef[64] = {
337 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
338 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
339 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
340 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
341 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
342 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
343 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
344 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
345 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
346 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
347 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
348 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
349 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
350 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
351 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
352 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
355 static void sunxi_frontend_init(void)
357 struct sunxi_ccm_reg * const ccm =
358 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
359 struct sunxi_de_fe_reg * const de_fe =
360 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
364 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
365 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
366 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
368 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
370 for (i = 0; i < 32; i++) {
371 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
372 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
373 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
374 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
375 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
376 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
379 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
382 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
383 unsigned int address)
385 struct sunxi_de_fe_reg * const de_fe =
386 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
388 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
389 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
390 writel(mode->xres * 4, &de_fe->ch0_stride);
391 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
392 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
394 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
396 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
397 &de_fe->ch0_outsize);
398 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
399 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
401 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
403 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
404 &de_fe->ch1_outsize);
405 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
406 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
408 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
411 static void sunxi_frontend_enable(void)
413 struct sunxi_de_fe_reg * const de_fe =
414 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
416 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
419 static void sunxi_frontend_init(void) {}
420 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
421 unsigned int address) {}
422 static void sunxi_frontend_enable(void) {}
425 static bool sunxi_is_composite(enum sunxi_monitor monitor)
428 case sunxi_monitor_none:
429 case sunxi_monitor_dvi:
430 case sunxi_monitor_hdmi:
431 case sunxi_monitor_lcd:
432 case sunxi_monitor_vga:
434 case sunxi_monitor_composite_pal:
435 case sunxi_monitor_composite_ntsc:
436 case sunxi_monitor_composite_pal_m:
437 case sunxi_monitor_composite_pal_nc:
441 return false; /* Never reached */
445 * This is the entity that mixes and matches the different layers and inputs.
446 * Allwinner calls it the back-end, but i like composer better.
448 static void sunxi_composer_init(void)
450 struct sunxi_ccm_reg * const ccm =
451 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
452 struct sunxi_de_be_reg * const de_be =
453 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
456 sunxi_frontend_init();
458 #ifdef CONFIG_SUNXI_GEN_SUN6I
460 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
464 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
465 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
466 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
468 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
470 /* Engine bug, clear registers after reset */
471 for (i = 0x0800; i < 0x1000; i += 4)
472 writel(0, SUNXI_DE_BE0_BASE + i);
474 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
477 static const u32 sunxi_rgb2yuv_coef[12] = {
478 0x00000107, 0x00000204, 0x00000064, 0x00000108,
479 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
480 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
483 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
484 unsigned int address,
485 enum sunxi_monitor monitor)
487 struct sunxi_de_be_reg * const de_be =
488 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
491 sunxi_frontend_mode_set(mode, address);
493 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
495 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
496 &de_be->layer0_size);
497 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
498 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
499 writel(address << 3, &de_be->layer0_addr_low32b);
500 writel(address >> 29, &de_be->layer0_addr_high4b);
502 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
504 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
506 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
507 if (mode->vmode == FB_VMODE_INTERLACED)
508 setbits_le32(&de_be->mode,
509 #ifndef CONFIG_MACH_SUN5I
510 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
512 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
514 if (sunxi_is_composite(monitor)) {
515 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
516 &de_be->output_color_ctrl);
517 for (i = 0; i < 12; i++)
518 writel(sunxi_rgb2yuv_coef[i],
519 &de_be->output_color_coef[i]);
523 static void sunxi_composer_enable(void)
525 struct sunxi_de_be_reg * const de_be =
526 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
528 sunxi_frontend_enable();
530 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
531 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
534 static void sunxi_lcdc_init(void)
536 struct sunxi_ccm_reg * const ccm =
537 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
538 struct sunxi_lcdc_reg * const lcdc =
539 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
542 #ifdef CONFIG_SUNXI_GEN_SUN6I
543 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
545 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
549 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
550 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
551 #ifdef CONFIG_SUNXI_GEN_SUN6I
552 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
554 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
561 static void sunxi_lcdc_panel_enable(void)
566 * Start with backlight disabled to avoid the screen flashing to
567 * white while the lcd inits.
569 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
571 gpio_request(pin, "lcd_backlight_enable");
572 gpio_direction_output(pin, 0);
575 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
577 gpio_request(pin, "lcd_backlight_pwm");
578 gpio_direction_output(pin, PWM_OFF);
581 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
582 if (reset_pin >= 0) {
583 gpio_request(reset_pin, "lcd_reset");
584 gpio_direction_output(reset_pin, 0); /* Assert reset */
587 /* Give the backlight some time to turn off and power up the panel. */
589 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
591 gpio_request(pin, "lcd_power");
592 gpio_direction_output(pin, 1);
596 gpio_direction_output(reset_pin, 1); /* De-assert reset */
599 static void sunxi_lcdc_backlight_enable(void)
604 * We want to have scanned out at least one frame before enabling the
605 * backlight to avoid the screen flashing to white when we enable it.
609 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
611 gpio_direction_output(pin, 1);
613 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
614 #ifdef SUNXI_PWM_PIN0
615 if (pin == SUNXI_PWM_PIN0) {
616 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
617 SUNXI_PWM_CTRL_ENABLE0 |
618 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
619 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
620 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
625 gpio_direction_output(pin, PWM_ON);
628 static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
629 const struct ctfb_res_modes *mode,
630 bool for_ext_vga_dac)
632 struct sunxi_lcdc_reg * const lcdc =
633 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
634 struct sunxi_ccm_reg * const ccm =
635 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
636 int clk_div, clk_double, pin;
637 struct display_timing timing;
639 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
640 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
642 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
644 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
645 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
647 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
648 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
650 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
651 sunxi_gpio_set_drv(pin, 3);
655 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
656 sunxi_is_composite(sunxi_display->monitor));
658 video_ctfb_mode_to_display_timing(mode, &timing);
659 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
660 sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
663 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
664 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
665 int *clk_div, int *clk_double,
666 bool use_portd_hvsync,
667 enum sunxi_monitor monitor)
669 struct sunxi_lcdc_reg * const lcdc =
670 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
671 struct sunxi_ccm_reg * const ccm =
672 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
673 struct display_timing timing;
675 video_ctfb_mode_to_display_timing(mode, &timing);
676 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
677 sunxi_is_composite(monitor));
679 if (use_portd_hvsync) {
680 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
681 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
684 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
685 sunxi_is_composite(monitor));
687 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
689 #ifdef CONFIG_VIDEO_HDMI
691 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
693 struct sunxi_hdmi_reg * const hdmi =
694 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
696 u8 avi_info_frame[17] = {
697 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701 u8 vendor_info_frame[19] = {
702 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
703 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708 if (mode->pixclock_khz <= 27000)
709 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
711 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
713 if (mode->xres * 100 / mode->yres < 156)
714 avi_info_frame[5] |= 0x18; /* 4 : 3 */
716 avi_info_frame[5] |= 0x28; /* 16 : 9 */
718 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
719 checksum += avi_info_frame[i];
721 avi_info_frame[3] = 0x100 - checksum;
723 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
724 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
726 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
727 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
729 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
730 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
732 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
733 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
735 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
738 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
739 int clk_div, int clk_double,
740 enum sunxi_monitor monitor)
742 struct sunxi_hdmi_reg * const hdmi =
743 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
746 /* Write clear interrupt status bits */
747 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
749 if (monitor == sunxi_monitor_hdmi)
750 sunxi_hdmi_setup_info_frames(mode);
752 /* Set input sync enable */
753 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
755 /* Init various registers, select pll3 as clock source */
756 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
757 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
758 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
759 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
760 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
762 /* Setup clk div and doubler */
763 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
764 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
766 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
768 /* Setup timing registers */
769 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
772 x = mode->hsync_len + mode->left_margin;
773 y = mode->vsync_len + mode->upper_margin;
774 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
776 x = mode->right_margin;
777 y = mode->lower_margin;
778 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
782 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
784 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
785 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
787 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
788 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
791 static void sunxi_hdmi_enable(void)
793 struct sunxi_hdmi_reg * const hdmi =
794 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
797 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
800 #endif /* CONFIG_VIDEO_HDMI */
802 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
804 static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
806 struct sunxi_ccm_reg * const ccm =
807 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
808 struct sunxi_tve_reg * const tve =
809 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
812 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
814 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
817 case sunxi_monitor_vga:
818 tvencoder_mode_set(tve, tve_mode_vga);
820 case sunxi_monitor_composite_pal_nc:
821 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
823 case sunxi_monitor_composite_pal:
824 tvencoder_mode_set(tve, tve_mode_composite_pal);
826 case sunxi_monitor_composite_pal_m:
827 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
829 case sunxi_monitor_composite_ntsc:
830 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
832 case sunxi_monitor_none:
833 case sunxi_monitor_dvi:
834 case sunxi_monitor_hdmi:
835 case sunxi_monitor_lcd:
840 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
842 static void sunxi_drc_init(void)
844 #ifdef CONFIG_SUNXI_GEN_SUN6I
845 struct sunxi_ccm_reg * const ccm =
846 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
848 /* On sun6i the drc must be clocked even when in pass-through mode */
849 #ifdef CONFIG_MACH_SUN8I_A33
850 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
852 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
853 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
857 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
858 static void sunxi_vga_external_dac_enable(void)
862 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
864 gpio_request(pin, "vga_enable");
865 gpio_direction_output(pin, 1);
868 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
870 #ifdef CONFIG_VIDEO_LCD_SSD2828
871 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
873 struct ssd2828_config cfg = {
874 .csx_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
875 .sck_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
876 .sdi_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
877 .sdo_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
878 .reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
879 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
880 .ssd2828_color_depth = 24,
881 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
882 .mipi_dsi_number_of_data_lanes = 4,
883 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
884 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
885 .mipi_dsi_delay_after_set_display_on_ms = 200
887 #error MIPI LCD panel needs configuration parameters
891 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
892 printf("SSD2828: SPI pins are not properly configured\n");
895 if (cfg.reset_pin == -1) {
896 printf("SSD2828: Reset pin is not properly configured\n");
900 return ssd2828_init(&cfg, mode);
902 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
904 #ifdef CONFIG_VIDEO_LCD_PANEL_I2C
905 static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display)
907 const char *name = CONFIG_VIDEO_LCD_PANEL_I2C_NAME;
908 struct udevice *i2c_bus;
911 ret = uclass_get_device_by_name(UCLASS_I2C, name, &i2c_bus);
915 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
917 * The anx9804 needs 1.8V from eldo3, we do this here
918 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
919 * to avoid turning this on when using hdmi output.
921 axp_set_eldo(3, 1800);
922 anx9804_init(i2c_bus, 4,
923 ANX9804_DATA_RATE_1620M,
924 sunxi_display->depth);
926 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
927 struct udevice *chip;
929 ret = i2c_get_chip(i2c_bus, 0x5c, 1, &chip);
933 dm_i2c_reg_write(chip, 0x04, 0x42); /* Turn on the LCD */
937 static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display) {}
940 static void sunxi_engines_init(void)
942 sunxi_composer_init();
947 static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
948 const struct ctfb_res_modes *mode,
949 unsigned int address)
951 enum sunxi_monitor monitor = sunxi_display->monitor;
952 int __maybe_unused clk_div, clk_double;
953 struct sunxi_lcdc_reg * const lcdc =
954 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
955 struct sunxi_tve_reg * __maybe_unused const tve =
956 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
958 switch (sunxi_display->monitor) {
959 case sunxi_monitor_none:
961 case sunxi_monitor_dvi:
962 case sunxi_monitor_hdmi:
963 #ifdef CONFIG_VIDEO_HDMI
964 sunxi_composer_mode_set(mode, address, monitor);
965 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
966 sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
967 sunxi_composer_enable();
968 lcdc_enable(lcdc, sunxi_display->depth);
972 case sunxi_monitor_lcd:
973 sunxi_lcdc_panel_enable();
974 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
975 mdelay(50); /* Wait for lcd controller power on */
976 hitachi_tx18d42vm_init();
978 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_I2C))
979 sunxi_panel_i2c_init(sunxi_display);
980 sunxi_composer_mode_set(mode, address, monitor);
981 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
982 sunxi_composer_enable();
983 lcdc_enable(lcdc, sunxi_display->depth);
984 #ifdef CONFIG_VIDEO_LCD_SSD2828
985 sunxi_ssd2828_init(mode);
987 sunxi_lcdc_backlight_enable();
989 case sunxi_monitor_vga:
990 #ifdef CONFIG_VIDEO_VGA
991 sunxi_composer_mode_set(mode, address, monitor);
992 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
993 sunxi_tvencoder_mode_set(monitor);
994 sunxi_composer_enable();
995 lcdc_enable(lcdc, sunxi_display->depth);
996 tvencoder_enable(tve);
997 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
998 sunxi_composer_mode_set(mode, address, monitor);
999 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
1000 sunxi_composer_enable();
1001 lcdc_enable(lcdc, sunxi_display->depth);
1002 sunxi_vga_external_dac_enable();
1005 case sunxi_monitor_composite_pal:
1006 case sunxi_monitor_composite_ntsc:
1007 case sunxi_monitor_composite_pal_m:
1008 case sunxi_monitor_composite_pal_nc:
1009 #ifdef CONFIG_VIDEO_COMPOSITE
1010 sunxi_composer_mode_set(mode, address, monitor);
1011 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
1012 sunxi_tvencoder_mode_set(monitor);
1013 sunxi_composer_enable();
1014 lcdc_enable(lcdc, sunxi_display->depth);
1015 tvencoder_enable(tve);
1021 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1024 case sunxi_monitor_dvi: return "dvi";
1025 case sunxi_monitor_hdmi: return "hdmi";
1026 case sunxi_monitor_lcd: return "lcd";
1027 case sunxi_monitor_vga: return "vga";
1028 case sunxi_monitor_composite_pal: return "composite-pal";
1029 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1030 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1031 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
1032 case sunxi_monitor_none: /* fall through */
1033 default: return "none";
1037 static bool sunxi_has_hdmi(void)
1039 #ifdef CONFIG_VIDEO_HDMI
1046 static bool sunxi_has_lcd(void)
1048 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1050 return lcd_mode[0] != 0;
1053 static bool sunxi_has_vga(void)
1055 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1062 static bool sunxi_has_composite(void)
1064 #ifdef CONFIG_VIDEO_COMPOSITE
1071 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1073 if (allow_hdmi && sunxi_has_hdmi())
1074 return sunxi_monitor_dvi;
1075 else if (sunxi_has_lcd())
1076 return sunxi_monitor_lcd;
1077 else if (sunxi_has_vga())
1078 return sunxi_monitor_vga;
1079 else if (sunxi_has_composite())
1080 return sunxi_monitor_composite_pal;
1082 return sunxi_monitor_none;
1085 static int sunxi_de_probe(struct udevice *dev)
1087 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
1088 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1089 struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
1090 const struct ctfb_res_modes *mode;
1091 struct ctfb_res_modes custom;
1092 const char *options;
1093 #ifdef CONFIG_VIDEO_HDMI
1094 int hpd, hpd_delay, edid;
1097 int i, overscan_offset, overscan_x, overscan_y;
1098 unsigned int fb_dma_addr;
1100 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1102 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1103 &sunxi_display->depth, &options);
1104 #ifdef CONFIG_VIDEO_HDMI
1105 hpd = video_get_option_int(options, "hpd", 1);
1106 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1107 edid = video_get_option_int(options, "edid", 1);
1109 overscan_x = video_get_option_int(options, "overscan_x", -1);
1110 overscan_y = video_get_option_int(options, "overscan_y", -1);
1111 sunxi_display->monitor = sunxi_get_default_mon(true);
1112 video_get_option_string(options, "monitor", mon, sizeof(mon),
1113 sunxi_get_mon_desc(sunxi_display->monitor));
1114 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1115 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1116 sunxi_display->monitor = i;
1120 if (i > SUNXI_MONITOR_LAST)
1121 printf("Unknown monitor: '%s', falling back to '%s'\n",
1122 mon, sunxi_get_mon_desc(sunxi_display->monitor));
1124 #ifdef CONFIG_VIDEO_HDMI
1125 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1126 if (sunxi_display->monitor == sunxi_monitor_dvi ||
1127 sunxi_display->monitor == sunxi_monitor_hdmi) {
1128 /* Always call hdp_detect, as it also enables clocks, etc. */
1129 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1130 if (hdmi_present && edid) {
1131 printf("HDMI connected: ");
1132 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
1135 hdmi_present = false;
1137 /* Fall back to EDID in case HPD failed */
1138 if (edid && !hdmi_present) {
1139 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
1141 hdmi_present = true;
1144 /* Shut down when display was not found */
1145 if ((hpd || edid) && !hdmi_present) {
1146 sunxi_hdmi_shutdown();
1147 sunxi_display->monitor = sunxi_get_default_mon(false);
1148 } /* else continue with hdmi/dvi without a cable connected */
1152 switch (sunxi_display->monitor) {
1153 case sunxi_monitor_none:
1154 printf("Unknown monitor\n");
1156 case sunxi_monitor_dvi:
1157 case sunxi_monitor_hdmi:
1158 if (!sunxi_has_hdmi()) {
1159 printf("HDMI/DVI not supported on this board\n");
1160 sunxi_display->monitor = sunxi_monitor_none;
1164 case sunxi_monitor_lcd:
1165 if (!sunxi_has_lcd()) {
1166 printf("LCD not supported on this board\n");
1167 sunxi_display->monitor = sunxi_monitor_none;
1170 sunxi_display->depth = video_get_params(&custom, lcd_mode);
1173 case sunxi_monitor_vga:
1174 if (!sunxi_has_vga()) {
1175 printf("VGA not supported on this board\n");
1176 sunxi_display->monitor = sunxi_monitor_none;
1179 sunxi_display->depth = 18;
1181 case sunxi_monitor_composite_pal:
1182 case sunxi_monitor_composite_ntsc:
1183 case sunxi_monitor_composite_pal_m:
1184 case sunxi_monitor_composite_pal_nc:
1185 if (!sunxi_has_composite()) {
1186 printf("Composite video not supported on this board\n");
1187 sunxi_display->monitor = sunxi_monitor_none;
1190 if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
1191 sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
1192 mode = &composite_video_modes[0];
1194 mode = &composite_video_modes[1];
1195 sunxi_display->depth = 24;
1199 /* Yes these defaults are quite high, overscan on composite sucks... */
1200 if (overscan_x == -1)
1201 overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
1202 if (overscan_y == -1)
1203 overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
1205 sunxi_display->fb_size = plat->size;
1206 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1207 /* We want to keep the fb_base for simplefb page aligned, where as
1208 * the sunxi dma engines will happily accept an unaligned address. */
1209 if (overscan_offset)
1210 sunxi_display->fb_size += 0x1000;
1212 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1213 mode->xres, mode->yres,
1214 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1215 sunxi_get_mon_desc(sunxi_display->monitor),
1216 overscan_x, overscan_y);
1218 sunxi_display->fb_addr = plat->base;
1219 sunxi_engines_init();
1221 #ifdef CONFIG_EFI_LOADER
1222 efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
1223 EFI_RESERVED_MEMORY_TYPE);
1226 fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
1227 if (overscan_offset) {
1228 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1229 sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
1230 memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
1231 flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
1233 sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
1235 /* The members of struct video_priv to be set by the driver. */
1236 uc_priv->bpix = VIDEO_BPP32;
1237 uc_priv->xsize = mode->xres;
1238 uc_priv->ysize = mode->yres;
1240 video_set_flush_dcache(dev, true);
1245 static int sunxi_de_bind(struct udevice *dev)
1247 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1249 plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
1254 static const struct video_ops sunxi_de_ops = {
1257 U_BOOT_DRIVER(sunxi_de) = {
1260 .ops = &sunxi_de_ops,
1261 .bind = sunxi_de_bind,
1262 .probe = sunxi_de_probe,
1263 .priv_auto = sizeof(struct sunxi_display_priv),
1264 .flags = DM_FLAG_PRE_RELOC,
1267 U_BOOT_DRVINFO(sunxi_de) = {
1274 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1275 int sunxi_simplefb_setup(void *blob)
1277 struct sunxi_display_priv *sunxi_display;
1278 struct video_priv *uc_priv;
1282 const char *pipeline = NULL;
1284 #ifdef CONFIG_MACH_SUN4I
1285 #define PIPELINE_PREFIX "de_fe0-"
1287 #define PIPELINE_PREFIX
1290 ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
1292 printf("DE not present\n");
1294 } else if (!device_active(de)) {
1295 printf("DE is present but not probed\n");
1299 uc_priv = dev_get_uclass_priv(de);
1300 sunxi_display = dev_get_priv(de);
1302 switch (sunxi_display->monitor) {
1303 case sunxi_monitor_none:
1305 case sunxi_monitor_dvi:
1306 case sunxi_monitor_hdmi:
1307 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1309 case sunxi_monitor_lcd:
1310 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1312 case sunxi_monitor_vga:
1313 #ifdef CONFIG_VIDEO_VGA
1314 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1315 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1316 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1319 case sunxi_monitor_composite_pal:
1320 case sunxi_monitor_composite_ntsc:
1321 case sunxi_monitor_composite_pal_m:
1322 case sunxi_monitor_composite_pal_nc:
1323 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1327 offset = sunxi_simplefb_fdt_match(blob, pipeline);
1329 eprintf("Cannot setup simplefb: node not found\n");
1330 return 0; /* Keep older kernels working */
1334 * Do not report the framebuffer as free RAM to the OS, note we cannot
1335 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1336 * and e.g. Linux refuses to iomap RAM on ARM, see:
1337 * linux/arch/arm/mm/ioremap.c around line 301.
1339 start = gd->bd->bi_dram[0].start;
1340 size = sunxi_display->fb_addr - start;
1341 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1343 eprintf("Cannot setup simplefb: Error reserving memory\n");
1347 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
1348 uc_priv->xsize, uc_priv->ysize,
1349 VNBYTES(uc_priv->bpix) * uc_priv->xsize,
1352 eprintf("Cannot setup simplefb: Error setting properties\n");
1356 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */