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>
11 #include <efi_loader.h>
14 #include <asm/arch/clock.h>
15 #include <asm/arch/display.h>
16 #include <asm/arch/gpio.h>
17 #include <asm/arch/lcdc.h>
18 #include <asm/arch/pwm.h>
19 #include <asm/arch/tve.h>
20 #include <asm/global_data.h>
26 #include <fdt_support.h>
30 #include "../videomodes.h"
31 #include "../anx9804.h"
32 #include "../hitachi_tx18d42vm_lcd.h"
33 #include "../ssd2828.h"
34 #include "simplefb_common.h"
36 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
44 DECLARE_GLOBAL_DATA_PTR;
52 sunxi_monitor_composite_pal,
53 sunxi_monitor_composite_ntsc,
54 sunxi_monitor_composite_pal_m,
55 sunxi_monitor_composite_pal_nc,
57 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
59 struct sunxi_display {
60 GraphicDevice graphic_device;
61 enum sunxi_monitor monitor;
67 const struct ctfb_res_modes composite_video_modes[2] = {
68 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
69 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
70 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
73 #ifdef CONFIG_VIDEO_HDMI
76 * Wait up to 200ms for value to be set in given part of reg.
78 static int await_completion(u32 *reg, u32 mask, u32 val)
80 unsigned long tmo = timer_get_us() + 200000;
82 while ((readl(reg) & mask) != val) {
83 if (timer_get_us() > tmo) {
84 printf("DDC: timeout reading EDID\n");
91 static int sunxi_hdmi_hpd_detect(int hpd_delay)
93 struct sunxi_ccm_reg * const ccm =
94 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
95 struct sunxi_hdmi_reg * const hdmi =
96 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
97 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
99 /* Set pll3 to 300MHz */
100 clock_set_pll3(300000000);
102 /* Set hdmi parent to pll3 */
103 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
106 /* Set ahb gating to pass */
107 #ifdef CONFIG_SUNXI_GEN_SUN6I
108 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
110 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
113 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
115 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
116 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
118 /* Enable PLLs for eventual DDC */
119 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
121 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
123 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
125 while (timer_get_us() < tmo) {
126 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
133 static void sunxi_hdmi_shutdown(void)
135 struct sunxi_ccm_reg * const ccm =
136 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
137 struct sunxi_hdmi_reg * const hdmi =
138 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
140 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
141 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
142 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
143 #ifdef CONFIG_SUNXI_GEN_SUN6I
144 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
149 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
151 struct sunxi_hdmi_reg * const hdmi =
152 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
154 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
155 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
156 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
157 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
158 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
159 #ifndef CONFIG_MACH_SUN6I
160 writel(n, &hdmi->ddc_byte_count);
161 writel(cmnd, &hdmi->ddc_cmnd);
163 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
165 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
167 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
170 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
172 struct sunxi_hdmi_reg * const hdmi =
173 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
182 if (sunxi_hdmi_ddc_do_command(
183 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
187 for (i = 0; i < n; i++)
188 *buf++ = readb(&hdmi->ddc_fifo_data);
197 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
202 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
205 r = edid_check_checksum(buf);
207 printf("EDID block %d: checksum error%s\n",
208 block, retries ? ", retrying" : "");
210 } while (r && retries--);
215 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
218 struct edid1_info edid1;
219 struct edid_cea861_info cea681[4];
220 struct edid_detailed_timing *t =
221 (struct edid_detailed_timing *)edid1.monitor_details.timing;
222 struct sunxi_hdmi_reg * const hdmi =
223 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
224 struct sunxi_ccm_reg * const ccm =
225 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
226 int i, r, ext_blocks = 0;
228 /* Reset i2c controller */
229 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
230 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
231 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
232 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
233 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
234 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
237 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
238 #ifndef CONFIG_MACH_SUN6I
239 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
240 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
243 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
245 r = edid_check_info(&edid1);
248 printf("EDID: invalid EDID data\n");
253 ext_blocks = edid1.extension_flag;
256 for (i = 0; i < ext_blocks; i++) {
257 if (sunxi_hdmi_edid_get_block(1 + i,
258 (u8 *)&cea681[i]) != 0) {
265 /* Disable DDC engine, no longer needed */
266 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
267 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
272 /* We want version 1.3 or 1.2 with detailed timing info */
273 if (edid1.version != 1 || (edid1.revision < 3 &&
274 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
275 printf("EDID: unsupported version %d.%d\n",
276 edid1.version, edid1.revision);
280 /* Take the first usable detailed timing */
281 for (i = 0; i < 4; i++, t++) {
282 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
287 printf("EDID: no usable detailed timing found\n");
291 /* Check for basic audio support, if found enable hdmi output */
292 sunxi_display.monitor = sunxi_monitor_dvi;
293 for (i = 0; i < ext_blocks; i++) {
294 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
295 cea681[i].revision < 2)
298 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
299 sunxi_display.monitor = sunxi_monitor_hdmi;
305 #endif /* CONFIG_VIDEO_HDMI */
307 #ifdef CONFIG_MACH_SUN4I
309 * Testing has shown that on sun4i the display backend engine does not have
310 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
311 * fifo underruns. So on sun4i we use the display frontend engine to do the
312 * dma from memory, as the frontend does have deep enough fifo-s.
315 static const u32 sun4i_vert_coef[32] = {
316 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
317 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
318 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
319 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
320 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
321 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
322 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
323 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
326 static const u32 sun4i_horz_coef[64] = {
327 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
328 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
329 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
330 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
331 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
332 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
333 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
334 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
335 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
336 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
337 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
338 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
339 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
340 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
341 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
342 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
345 static void sunxi_frontend_init(void)
347 struct sunxi_ccm_reg * const ccm =
348 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
349 struct sunxi_de_fe_reg * const de_fe =
350 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
354 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
355 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
356 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
358 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
360 for (i = 0; i < 32; i++) {
361 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
362 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
363 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
364 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
365 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
366 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
369 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
372 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
373 unsigned int address)
375 struct sunxi_de_fe_reg * const de_fe =
376 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
378 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
379 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
380 writel(mode->xres * 4, &de_fe->ch0_stride);
381 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
382 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
384 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
386 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
387 &de_fe->ch0_outsize);
388 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
389 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
391 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
393 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
394 &de_fe->ch1_outsize);
395 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
396 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
398 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
401 static void sunxi_frontend_enable(void)
403 struct sunxi_de_fe_reg * const de_fe =
404 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
406 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
409 static void sunxi_frontend_init(void) {}
410 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
411 unsigned int address) {}
412 static void sunxi_frontend_enable(void) {}
415 static bool sunxi_is_composite(void)
417 switch (sunxi_display.monitor) {
418 case sunxi_monitor_none:
419 case sunxi_monitor_dvi:
420 case sunxi_monitor_hdmi:
421 case sunxi_monitor_lcd:
422 case sunxi_monitor_vga:
424 case sunxi_monitor_composite_pal:
425 case sunxi_monitor_composite_ntsc:
426 case sunxi_monitor_composite_pal_m:
427 case sunxi_monitor_composite_pal_nc:
431 return false; /* Never reached */
435 * This is the entity that mixes and matches the different layers and inputs.
436 * Allwinner calls it the back-end, but i like composer better.
438 static void sunxi_composer_init(void)
440 struct sunxi_ccm_reg * const ccm =
441 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
442 struct sunxi_de_be_reg * const de_be =
443 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
446 sunxi_frontend_init();
448 #ifdef CONFIG_SUNXI_GEN_SUN6I
450 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
454 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
455 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
456 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
458 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
460 /* Engine bug, clear registers after reset */
461 for (i = 0x0800; i < 0x1000; i += 4)
462 writel(0, SUNXI_DE_BE0_BASE + i);
464 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
467 static const u32 sunxi_rgb2yuv_coef[12] = {
468 0x00000107, 0x00000204, 0x00000064, 0x00000108,
469 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
470 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
473 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
474 unsigned int address)
476 struct sunxi_de_be_reg * const de_be =
477 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
480 sunxi_frontend_mode_set(mode, address);
482 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
484 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
485 &de_be->layer0_size);
486 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
487 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
488 writel(address << 3, &de_be->layer0_addr_low32b);
489 writel(address >> 29, &de_be->layer0_addr_high4b);
491 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
493 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
495 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
496 if (mode->vmode == FB_VMODE_INTERLACED)
497 setbits_le32(&de_be->mode,
498 #ifndef CONFIG_MACH_SUN5I
499 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
501 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
503 if (sunxi_is_composite()) {
504 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
505 &de_be->output_color_ctrl);
506 for (i = 0; i < 12; i++)
507 writel(sunxi_rgb2yuv_coef[i],
508 &de_be->output_color_coef[i]);
512 static void sunxi_composer_enable(void)
514 struct sunxi_de_be_reg * const de_be =
515 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
517 sunxi_frontend_enable();
519 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
520 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
523 static void sunxi_lcdc_init(void)
525 struct sunxi_ccm_reg * const ccm =
526 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
527 struct sunxi_lcdc_reg * const lcdc =
528 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
531 #ifdef CONFIG_SUNXI_GEN_SUN6I
532 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
534 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
538 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
539 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
540 #ifdef CONFIG_SUNXI_GEN_SUN6I
541 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
543 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
550 static void sunxi_lcdc_panel_enable(void)
555 * Start with backlight disabled to avoid the screen flashing to
556 * white while the lcd inits.
558 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
560 gpio_request(pin, "lcd_backlight_enable");
561 gpio_direction_output(pin, 0);
564 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
566 gpio_request(pin, "lcd_backlight_pwm");
567 gpio_direction_output(pin, PWM_OFF);
570 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
571 if (reset_pin >= 0) {
572 gpio_request(reset_pin, "lcd_reset");
573 gpio_direction_output(reset_pin, 0); /* Assert reset */
576 /* Give the backlight some time to turn off and power up the panel. */
578 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
580 gpio_request(pin, "lcd_power");
581 gpio_direction_output(pin, 1);
585 gpio_direction_output(reset_pin, 1); /* De-assert reset */
588 static void sunxi_lcdc_backlight_enable(void)
593 * We want to have scanned out at least one frame before enabling the
594 * backlight to avoid the screen flashing to white when we enable it.
598 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
600 gpio_direction_output(pin, 1);
602 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
603 #ifdef SUNXI_PWM_PIN0
604 if (pin == SUNXI_PWM_PIN0) {
605 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
606 SUNXI_PWM_CTRL_ENABLE0 |
607 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
608 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
609 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
614 gpio_direction_output(pin, PWM_ON);
617 static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
618 struct display_timing *timing)
620 timing->pixelclock.typ = mode->pixclock_khz * 1000;
622 timing->hactive.typ = mode->xres;
623 timing->hfront_porch.typ = mode->right_margin;
624 timing->hback_porch.typ = mode->left_margin;
625 timing->hsync_len.typ = mode->hsync_len;
627 timing->vactive.typ = mode->yres;
628 timing->vfront_porch.typ = mode->lower_margin;
629 timing->vback_porch.typ = mode->upper_margin;
630 timing->vsync_len.typ = mode->vsync_len;
634 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
635 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
637 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
638 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
639 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
641 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
642 if (mode->vmode == FB_VMODE_INTERLACED)
643 timing->flags |= DISPLAY_FLAGS_INTERLACED;
646 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
647 bool for_ext_vga_dac)
649 struct sunxi_lcdc_reg * const lcdc =
650 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
651 struct sunxi_ccm_reg * const ccm =
652 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
653 int clk_div, clk_double, pin;
654 struct display_timing timing;
656 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
657 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
659 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
661 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
662 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
664 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
665 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
667 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
668 sunxi_gpio_set_drv(pin, 3);
672 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
673 sunxi_is_composite());
675 sunxi_ctfb_mode_to_display_timing(mode, &timing);
676 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
677 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
680 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
681 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
682 int *clk_div, int *clk_double,
683 bool use_portd_hvsync)
685 struct sunxi_lcdc_reg * const lcdc =
686 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
687 struct sunxi_ccm_reg * const ccm =
688 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
689 struct display_timing timing;
691 sunxi_ctfb_mode_to_display_timing(mode, &timing);
692 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
693 sunxi_is_composite());
695 if (use_portd_hvsync) {
696 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
697 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
700 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
701 sunxi_is_composite());
703 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
705 #ifdef CONFIG_VIDEO_HDMI
707 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
709 struct sunxi_hdmi_reg * const hdmi =
710 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
712 u8 avi_info_frame[17] = {
713 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
717 u8 vendor_info_frame[19] = {
718 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 if (mode->pixclock_khz <= 27000)
725 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
727 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
729 if (mode->xres * 100 / mode->yres < 156)
730 avi_info_frame[5] |= 0x18; /* 4 : 3 */
732 avi_info_frame[5] |= 0x28; /* 16 : 9 */
734 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
735 checksum += avi_info_frame[i];
737 avi_info_frame[3] = 0x100 - checksum;
739 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
740 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
742 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
743 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
745 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
746 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
748 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
749 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
751 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
754 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
755 int clk_div, int clk_double)
757 struct sunxi_hdmi_reg * const hdmi =
758 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
761 /* Write clear interrupt status bits */
762 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
764 if (sunxi_display.monitor == sunxi_monitor_hdmi)
765 sunxi_hdmi_setup_info_frames(mode);
767 /* Set input sync enable */
768 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
770 /* Init various registers, select pll3 as clock source */
771 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
772 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
773 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
774 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
775 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
777 /* Setup clk div and doubler */
778 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
779 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
781 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
783 /* Setup timing registers */
784 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
787 x = mode->hsync_len + mode->left_margin;
788 y = mode->vsync_len + mode->upper_margin;
789 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
791 x = mode->right_margin;
792 y = mode->lower_margin;
793 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
797 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
799 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
800 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
802 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
803 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
806 static void sunxi_hdmi_enable(void)
808 struct sunxi_hdmi_reg * const hdmi =
809 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
812 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
815 #endif /* CONFIG_VIDEO_HDMI */
817 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
819 static void sunxi_tvencoder_mode_set(void)
821 struct sunxi_ccm_reg * const ccm =
822 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
823 struct sunxi_tve_reg * const tve =
824 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
827 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
829 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
831 switch (sunxi_display.monitor) {
832 case sunxi_monitor_vga:
833 tvencoder_mode_set(tve, tve_mode_vga);
835 case sunxi_monitor_composite_pal_nc:
836 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
838 case sunxi_monitor_composite_pal:
839 tvencoder_mode_set(tve, tve_mode_composite_pal);
841 case sunxi_monitor_composite_pal_m:
842 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
844 case sunxi_monitor_composite_ntsc:
845 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
847 case sunxi_monitor_none:
848 case sunxi_monitor_dvi:
849 case sunxi_monitor_hdmi:
850 case sunxi_monitor_lcd:
855 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
857 static void sunxi_drc_init(void)
859 #ifdef CONFIG_SUNXI_GEN_SUN6I
860 struct sunxi_ccm_reg * const ccm =
861 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
863 /* On sun6i the drc must be clocked even when in pass-through mode */
864 #ifdef CONFIG_MACH_SUN8I_A33
865 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
867 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
868 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
872 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
873 static void sunxi_vga_external_dac_enable(void)
877 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
879 gpio_request(pin, "vga_enable");
880 gpio_direction_output(pin, 1);
883 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
885 #ifdef CONFIG_VIDEO_LCD_SSD2828
886 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
888 struct ssd2828_config cfg = {
889 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
890 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
891 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
892 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
893 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
894 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
895 .ssd2828_color_depth = 24,
896 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
897 .mipi_dsi_number_of_data_lanes = 4,
898 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
899 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
900 .mipi_dsi_delay_after_set_display_on_ms = 200
902 #error MIPI LCD panel needs configuration parameters
906 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
907 printf("SSD2828: SPI pins are not properly configured\n");
910 if (cfg.reset_pin == -1) {
911 printf("SSD2828: Reset pin is not properly configured\n");
915 return ssd2828_init(&cfg, mode);
917 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
919 static void sunxi_engines_init(void)
921 sunxi_composer_init();
926 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
927 unsigned int address)
929 int __maybe_unused clk_div, clk_double;
930 struct sunxi_lcdc_reg * const lcdc =
931 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
932 struct sunxi_tve_reg * __maybe_unused const tve =
933 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
935 switch (sunxi_display.monitor) {
936 case sunxi_monitor_none:
938 case sunxi_monitor_dvi:
939 case sunxi_monitor_hdmi:
940 #ifdef CONFIG_VIDEO_HDMI
941 sunxi_composer_mode_set(mode, address);
942 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
943 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
944 sunxi_composer_enable();
945 lcdc_enable(lcdc, sunxi_display.depth);
949 case sunxi_monitor_lcd:
950 sunxi_lcdc_panel_enable();
951 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
953 * The anx9804 needs 1.8V from eldo3, we do this here
954 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
955 * to avoid turning this on when using hdmi output.
957 axp_set_eldo(3, 1800);
958 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
959 ANX9804_DATA_RATE_1620M,
960 sunxi_display.depth);
962 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
963 mdelay(50); /* Wait for lcd controller power on */
964 hitachi_tx18d42vm_init();
966 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
967 unsigned int orig_i2c_bus = i2c_get_bus_num();
968 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
969 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
970 i2c_set_bus_num(orig_i2c_bus);
972 sunxi_composer_mode_set(mode, address);
973 sunxi_lcdc_tcon0_mode_set(mode, false);
974 sunxi_composer_enable();
975 lcdc_enable(lcdc, sunxi_display.depth);
976 #ifdef CONFIG_VIDEO_LCD_SSD2828
977 sunxi_ssd2828_init(mode);
979 sunxi_lcdc_backlight_enable();
981 case sunxi_monitor_vga:
982 #ifdef CONFIG_VIDEO_VGA
983 sunxi_composer_mode_set(mode, address);
984 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
985 sunxi_tvencoder_mode_set();
986 sunxi_composer_enable();
987 lcdc_enable(lcdc, sunxi_display.depth);
988 tvencoder_enable(tve);
989 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
990 sunxi_composer_mode_set(mode, address);
991 sunxi_lcdc_tcon0_mode_set(mode, true);
992 sunxi_composer_enable();
993 lcdc_enable(lcdc, sunxi_display.depth);
994 sunxi_vga_external_dac_enable();
997 case sunxi_monitor_composite_pal:
998 case sunxi_monitor_composite_ntsc:
999 case sunxi_monitor_composite_pal_m:
1000 case sunxi_monitor_composite_pal_nc:
1001 #ifdef CONFIG_VIDEO_COMPOSITE
1002 sunxi_composer_mode_set(mode, address);
1003 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1004 sunxi_tvencoder_mode_set();
1005 sunxi_composer_enable();
1006 lcdc_enable(lcdc, sunxi_display.depth);
1007 tvencoder_enable(tve);
1013 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1016 case sunxi_monitor_none: return "none";
1017 case sunxi_monitor_dvi: return "dvi";
1018 case sunxi_monitor_hdmi: return "hdmi";
1019 case sunxi_monitor_lcd: return "lcd";
1020 case sunxi_monitor_vga: return "vga";
1021 case sunxi_monitor_composite_pal: return "composite-pal";
1022 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1023 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1024 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
1026 return NULL; /* never reached */
1029 ulong board_get_usable_ram_top(ulong total_size)
1031 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1034 static bool sunxi_has_hdmi(void)
1036 #ifdef CONFIG_VIDEO_HDMI
1043 static bool sunxi_has_lcd(void)
1045 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1047 return lcd_mode[0] != 0;
1050 static bool sunxi_has_vga(void)
1052 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1059 static bool sunxi_has_composite(void)
1061 #ifdef CONFIG_VIDEO_COMPOSITE
1068 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1070 if (allow_hdmi && sunxi_has_hdmi())
1071 return sunxi_monitor_dvi;
1072 else if (sunxi_has_lcd())
1073 return sunxi_monitor_lcd;
1074 else if (sunxi_has_vga())
1075 return sunxi_monitor_vga;
1076 else if (sunxi_has_composite())
1077 return sunxi_monitor_composite_pal;
1079 return sunxi_monitor_none;
1082 void *video_hw_init(void)
1084 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1085 const struct ctfb_res_modes *mode;
1086 struct ctfb_res_modes custom;
1087 const char *options;
1088 #ifdef CONFIG_VIDEO_HDMI
1089 int hpd, hpd_delay, edid;
1092 int i, overscan_offset, overscan_x, overscan_y;
1093 unsigned int fb_dma_addr;
1095 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1097 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1099 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1100 &sunxi_display.depth, &options);
1101 #ifdef CONFIG_VIDEO_HDMI
1102 hpd = video_get_option_int(options, "hpd", 1);
1103 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1104 edid = video_get_option_int(options, "edid", 1);
1106 overscan_x = video_get_option_int(options, "overscan_x", -1);
1107 overscan_y = video_get_option_int(options, "overscan_y", -1);
1108 sunxi_display.monitor = sunxi_get_default_mon(true);
1109 video_get_option_string(options, "monitor", mon, sizeof(mon),
1110 sunxi_get_mon_desc(sunxi_display.monitor));
1111 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1112 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1113 sunxi_display.monitor = i;
1117 if (i > SUNXI_MONITOR_LAST)
1118 printf("Unknown monitor: '%s', falling back to '%s'\n",
1119 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1121 #ifdef CONFIG_VIDEO_HDMI
1122 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1123 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1124 sunxi_display.monitor == sunxi_monitor_hdmi) {
1125 /* Always call hdp_detect, as it also enables clocks, etc. */
1126 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1127 if (hdmi_present && edid) {
1128 printf("HDMI connected: ");
1129 if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
1132 hdmi_present = false;
1134 /* Fall back to EDID in case HPD failed */
1135 if (edid && !hdmi_present) {
1136 if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1138 hdmi_present = true;
1141 /* Shut down when display was not found */
1142 if ((hpd || edid) && !hdmi_present) {
1143 sunxi_hdmi_shutdown();
1144 sunxi_display.monitor = sunxi_get_default_mon(false);
1145 } /* else continue with hdmi/dvi without a cable connected */
1149 switch (sunxi_display.monitor) {
1150 case sunxi_monitor_none:
1152 case sunxi_monitor_dvi:
1153 case sunxi_monitor_hdmi:
1154 if (!sunxi_has_hdmi()) {
1155 printf("HDMI/DVI not supported on this board\n");
1156 sunxi_display.monitor = sunxi_monitor_none;
1160 case sunxi_monitor_lcd:
1161 if (!sunxi_has_lcd()) {
1162 printf("LCD not supported on this board\n");
1163 sunxi_display.monitor = sunxi_monitor_none;
1166 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1169 case sunxi_monitor_vga:
1170 if (!sunxi_has_vga()) {
1171 printf("VGA not supported on this board\n");
1172 sunxi_display.monitor = sunxi_monitor_none;
1175 sunxi_display.depth = 18;
1177 case sunxi_monitor_composite_pal:
1178 case sunxi_monitor_composite_ntsc:
1179 case sunxi_monitor_composite_pal_m:
1180 case sunxi_monitor_composite_pal_nc:
1181 if (!sunxi_has_composite()) {
1182 printf("Composite video not supported on this board\n");
1183 sunxi_display.monitor = sunxi_monitor_none;
1186 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1187 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1188 mode = &composite_video_modes[0];
1190 mode = &composite_video_modes[1];
1191 sunxi_display.depth = 24;
1195 /* Yes these defaults are quite high, overscan on composite sucks... */
1196 if (overscan_x == -1)
1197 overscan_x = sunxi_is_composite() ? 32 : 0;
1198 if (overscan_y == -1)
1199 overscan_y = sunxi_is_composite() ? 20 : 0;
1201 sunxi_display.fb_size =
1202 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1203 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1204 /* We want to keep the fb_base for simplefb page aligned, where as
1205 * the sunxi dma engines will happily accept an unaligned address. */
1206 if (overscan_offset)
1207 sunxi_display.fb_size += 0x1000;
1209 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1210 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1211 sunxi_display.fb_size >> 10,
1212 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1216 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1217 mode->xres, mode->yres,
1218 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1219 sunxi_get_mon_desc(sunxi_display.monitor),
1220 overscan_x, overscan_y);
1222 gd->fb_base = gd->bd->bi_dram[0].start +
1223 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1224 sunxi_engines_init();
1226 #ifdef CONFIG_EFI_LOADER
1227 efi_add_memory_map(gd->fb_base,
1228 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1230 EFI_RESERVED_MEMORY_TYPE, false);
1233 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1234 sunxi_display.fb_addr = gd->fb_base;
1235 if (overscan_offset) {
1236 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1237 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1238 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1239 flush_cache(gd->fb_base, sunxi_display.fb_size);
1241 sunxi_mode_set(mode, fb_dma_addr);
1244 * These are the only members of this structure that are used. All the
1245 * others are driver specific. The pitch is stored in plnSizeX.
1247 graphic_device->frameAdrs = sunxi_display.fb_addr;
1248 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1249 graphic_device->gdfBytesPP = 4;
1250 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1251 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1252 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1254 return graphic_device;
1260 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1261 int sunxi_simplefb_setup(void *blob)
1263 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1266 const char *pipeline = NULL;
1268 #ifdef CONFIG_MACH_SUN4I
1269 #define PIPELINE_PREFIX "de_fe0-"
1271 #define PIPELINE_PREFIX
1274 switch (sunxi_display.monitor) {
1275 case sunxi_monitor_none:
1277 case sunxi_monitor_dvi:
1278 case sunxi_monitor_hdmi:
1279 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1281 case sunxi_monitor_lcd:
1282 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1284 case sunxi_monitor_vga:
1285 #ifdef CONFIG_VIDEO_VGA
1286 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1287 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1288 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1291 case sunxi_monitor_composite_pal:
1292 case sunxi_monitor_composite_ntsc:
1293 case sunxi_monitor_composite_pal_m:
1294 case sunxi_monitor_composite_pal_nc:
1295 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1299 offset = sunxi_simplefb_fdt_match(blob, pipeline);
1301 eprintf("Cannot setup simplefb: node not found\n");
1302 return 0; /* Keep older kernels working */
1306 * Do not report the framebuffer as free RAM to the OS, note we cannot
1307 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1308 * and e.g. Linux refuses to iomap RAM on ARM, see:
1309 * linux/arch/arm/mm/ioremap.c around line 301.
1311 start = gd->bd->bi_dram[0].start;
1312 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1313 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1315 eprintf("Cannot setup simplefb: Error reserving memory\n");
1319 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1320 graphic_device->winSizeX, graphic_device->winSizeY,
1321 graphic_device->plnSizeX, "x8r8g8b8");
1323 eprintf("Cannot setup simplefb: Error setting properties\n");
1327 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */