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>
15 #include <asm/arch/clock.h>
16 #include <asm/arch/display.h>
17 #include <asm/arch/gpio.h>
18 #include <asm/arch/lcdc.h>
19 #include <asm/arch/pwm.h>
20 #include <asm/arch/tve.h>
21 #include <asm/global_data.h>
27 #include <fdt_support.h>
31 #include "../videomodes.h"
32 #include "../anx9804.h"
33 #include "../hitachi_tx18d42vm_lcd.h"
34 #include "../ssd2828.h"
35 #include "simplefb_common.h"
37 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
45 DECLARE_GLOBAL_DATA_PTR;
53 sunxi_monitor_composite_pal,
54 sunxi_monitor_composite_ntsc,
55 sunxi_monitor_composite_pal_m,
56 sunxi_monitor_composite_pal_nc,
58 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
60 struct sunxi_display {
61 GraphicDevice graphic_device;
62 enum sunxi_monitor monitor;
68 const struct ctfb_res_modes composite_video_modes[2] = {
69 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
70 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
71 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
74 #ifdef CONFIG_VIDEO_HDMI
77 * Wait up to 200ms for value to be set in given part of reg.
79 static int await_completion(u32 *reg, u32 mask, u32 val)
81 unsigned long tmo = timer_get_us() + 200000;
83 while ((readl(reg) & mask) != val) {
84 if (timer_get_us() > tmo) {
85 printf("DDC: timeout reading EDID\n");
92 static int sunxi_hdmi_hpd_detect(int hpd_delay)
94 struct sunxi_ccm_reg * const ccm =
95 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
96 struct sunxi_hdmi_reg * const hdmi =
97 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
98 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
100 /* Set pll3 to 300MHz */
101 clock_set_pll3(300000000);
103 /* Set hdmi parent to pll3 */
104 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
107 /* Set ahb gating to pass */
108 #ifdef CONFIG_SUNXI_GEN_SUN6I
109 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
111 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
114 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
116 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
117 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
119 /* Enable PLLs for eventual DDC */
120 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
122 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
124 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
126 while (timer_get_us() < tmo) {
127 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
134 static void sunxi_hdmi_shutdown(void)
136 struct sunxi_ccm_reg * const ccm =
137 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
138 struct sunxi_hdmi_reg * const hdmi =
139 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
141 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
142 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
143 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
144 #ifdef CONFIG_SUNXI_GEN_SUN6I
145 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
150 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
152 struct sunxi_hdmi_reg * const hdmi =
153 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
155 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
156 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
157 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
158 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
159 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
160 #ifndef CONFIG_MACH_SUN6I
161 writel(n, &hdmi->ddc_byte_count);
162 writel(cmnd, &hdmi->ddc_cmnd);
164 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
166 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
168 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
171 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
173 struct sunxi_hdmi_reg * const hdmi =
174 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
183 if (sunxi_hdmi_ddc_do_command(
184 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
188 for (i = 0; i < n; i++)
189 *buf++ = readb(&hdmi->ddc_fifo_data);
198 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
203 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
206 r = edid_check_checksum(buf);
208 printf("EDID block %d: checksum error%s\n",
209 block, retries ? ", retrying" : "");
211 } while (r && retries--);
216 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
219 struct edid1_info edid1;
220 struct edid_cea861_info cea681[4];
221 struct edid_detailed_timing *t =
222 (struct edid_detailed_timing *)edid1.monitor_details.timing;
223 struct sunxi_hdmi_reg * const hdmi =
224 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
225 struct sunxi_ccm_reg * const ccm =
226 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
227 int i, r, ext_blocks = 0;
229 /* Reset i2c controller */
230 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
231 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
232 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
233 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
234 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
235 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
238 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
239 #ifndef CONFIG_MACH_SUN6I
240 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
241 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
244 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
246 r = edid_check_info(&edid1);
249 printf("EDID: invalid EDID data\n");
254 ext_blocks = edid1.extension_flag;
257 for (i = 0; i < ext_blocks; i++) {
258 if (sunxi_hdmi_edid_get_block(1 + i,
259 (u8 *)&cea681[i]) != 0) {
266 /* Disable DDC engine, no longer needed */
267 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
268 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
273 /* We want version 1.3 or 1.2 with detailed timing info */
274 if (edid1.version != 1 || (edid1.revision < 3 &&
275 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
276 printf("EDID: unsupported version %d.%d\n",
277 edid1.version, edid1.revision);
281 /* Take the first usable detailed timing */
282 for (i = 0; i < 4; i++, t++) {
283 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
288 printf("EDID: no usable detailed timing found\n");
292 /* Check for basic audio support, if found enable hdmi output */
293 sunxi_display.monitor = sunxi_monitor_dvi;
294 for (i = 0; i < ext_blocks; i++) {
295 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
296 cea681[i].revision < 2)
299 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
300 sunxi_display.monitor = sunxi_monitor_hdmi;
306 #endif /* CONFIG_VIDEO_HDMI */
308 #ifdef CONFIG_MACH_SUN4I
310 * Testing has shown that on sun4i the display backend engine does not have
311 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
312 * fifo underruns. So on sun4i we use the display frontend engine to do the
313 * dma from memory, as the frontend does have deep enough fifo-s.
316 static const u32 sun4i_vert_coef[32] = {
317 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
318 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
319 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
320 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
321 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
322 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
323 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
324 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
327 static const u32 sun4i_horz_coef[64] = {
328 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
329 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
330 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
331 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
332 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
333 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
334 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
335 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
336 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
337 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
338 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
339 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
340 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
341 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
342 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
343 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
346 static void sunxi_frontend_init(void)
348 struct sunxi_ccm_reg * const ccm =
349 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
350 struct sunxi_de_fe_reg * const de_fe =
351 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
355 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
356 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
357 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
359 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
361 for (i = 0; i < 32; i++) {
362 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
363 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
364 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
365 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
366 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
367 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
370 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
373 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
374 unsigned int address)
376 struct sunxi_de_fe_reg * const de_fe =
377 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
379 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
380 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
381 writel(mode->xres * 4, &de_fe->ch0_stride);
382 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
383 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
385 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
387 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
388 &de_fe->ch0_outsize);
389 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
390 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
392 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
394 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
395 &de_fe->ch1_outsize);
396 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
397 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
399 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
402 static void sunxi_frontend_enable(void)
404 struct sunxi_de_fe_reg * const de_fe =
405 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
407 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
410 static void sunxi_frontend_init(void) {}
411 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
412 unsigned int address) {}
413 static void sunxi_frontend_enable(void) {}
416 static bool sunxi_is_composite(void)
418 switch (sunxi_display.monitor) {
419 case sunxi_monitor_none:
420 case sunxi_monitor_dvi:
421 case sunxi_monitor_hdmi:
422 case sunxi_monitor_lcd:
423 case sunxi_monitor_vga:
425 case sunxi_monitor_composite_pal:
426 case sunxi_monitor_composite_ntsc:
427 case sunxi_monitor_composite_pal_m:
428 case sunxi_monitor_composite_pal_nc:
432 return false; /* Never reached */
436 * This is the entity that mixes and matches the different layers and inputs.
437 * Allwinner calls it the back-end, but i like composer better.
439 static void sunxi_composer_init(void)
441 struct sunxi_ccm_reg * const ccm =
442 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
443 struct sunxi_de_be_reg * const de_be =
444 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
447 sunxi_frontend_init();
449 #ifdef CONFIG_SUNXI_GEN_SUN6I
451 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
455 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
456 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
457 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
459 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
461 /* Engine bug, clear registers after reset */
462 for (i = 0x0800; i < 0x1000; i += 4)
463 writel(0, SUNXI_DE_BE0_BASE + i);
465 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
468 static const u32 sunxi_rgb2yuv_coef[12] = {
469 0x00000107, 0x00000204, 0x00000064, 0x00000108,
470 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
471 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
474 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
475 unsigned int address)
477 struct sunxi_de_be_reg * const de_be =
478 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
481 sunxi_frontend_mode_set(mode, address);
483 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
485 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
486 &de_be->layer0_size);
487 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
488 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
489 writel(address << 3, &de_be->layer0_addr_low32b);
490 writel(address >> 29, &de_be->layer0_addr_high4b);
492 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
494 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
496 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
497 if (mode->vmode == FB_VMODE_INTERLACED)
498 setbits_le32(&de_be->mode,
499 #ifndef CONFIG_MACH_SUN5I
500 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
502 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
504 if (sunxi_is_composite()) {
505 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
506 &de_be->output_color_ctrl);
507 for (i = 0; i < 12; i++)
508 writel(sunxi_rgb2yuv_coef[i],
509 &de_be->output_color_coef[i]);
513 static void sunxi_composer_enable(void)
515 struct sunxi_de_be_reg * const de_be =
516 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
518 sunxi_frontend_enable();
520 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
521 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
524 static void sunxi_lcdc_init(void)
526 struct sunxi_ccm_reg * const ccm =
527 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
528 struct sunxi_lcdc_reg * const lcdc =
529 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
532 #ifdef CONFIG_SUNXI_GEN_SUN6I
533 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
535 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
539 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
540 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
541 #ifdef CONFIG_SUNXI_GEN_SUN6I
542 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
544 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
551 static void sunxi_lcdc_panel_enable(void)
556 * Start with backlight disabled to avoid the screen flashing to
557 * white while the lcd inits.
559 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
561 gpio_request(pin, "lcd_backlight_enable");
562 gpio_direction_output(pin, 0);
565 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
567 gpio_request(pin, "lcd_backlight_pwm");
568 gpio_direction_output(pin, PWM_OFF);
571 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
572 if (reset_pin >= 0) {
573 gpio_request(reset_pin, "lcd_reset");
574 gpio_direction_output(reset_pin, 0); /* Assert reset */
577 /* Give the backlight some time to turn off and power up the panel. */
579 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
581 gpio_request(pin, "lcd_power");
582 gpio_direction_output(pin, 1);
586 gpio_direction_output(reset_pin, 1); /* De-assert reset */
589 static void sunxi_lcdc_backlight_enable(void)
594 * We want to have scanned out at least one frame before enabling the
595 * backlight to avoid the screen flashing to white when we enable it.
599 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
601 gpio_direction_output(pin, 1);
603 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
604 #ifdef SUNXI_PWM_PIN0
605 if (pin == SUNXI_PWM_PIN0) {
606 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
607 SUNXI_PWM_CTRL_ENABLE0 |
608 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
609 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
610 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
615 gpio_direction_output(pin, PWM_ON);
618 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
619 bool for_ext_vga_dac)
621 struct sunxi_lcdc_reg * const lcdc =
622 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
623 struct sunxi_ccm_reg * const ccm =
624 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
625 int clk_div, clk_double, pin;
626 struct display_timing timing;
628 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
629 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
631 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
633 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
634 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
636 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
637 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
639 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
640 sunxi_gpio_set_drv(pin, 3);
644 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
645 sunxi_is_composite());
647 video_ctfb_mode_to_display_timing(mode, &timing);
648 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
649 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
652 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
653 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
654 int *clk_div, int *clk_double,
655 bool use_portd_hvsync)
657 struct sunxi_lcdc_reg * const lcdc =
658 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
659 struct sunxi_ccm_reg * const ccm =
660 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
661 struct display_timing timing;
663 video_ctfb_mode_to_display_timing(mode, &timing);
664 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
665 sunxi_is_composite());
667 if (use_portd_hvsync) {
668 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
669 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
672 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
673 sunxi_is_composite());
675 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
677 #ifdef CONFIG_VIDEO_HDMI
679 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
681 struct sunxi_hdmi_reg * const hdmi =
682 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
684 u8 avi_info_frame[17] = {
685 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689 u8 vendor_info_frame[19] = {
690 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696 if (mode->pixclock_khz <= 27000)
697 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
699 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
701 if (mode->xres * 100 / mode->yres < 156)
702 avi_info_frame[5] |= 0x18; /* 4 : 3 */
704 avi_info_frame[5] |= 0x28; /* 16 : 9 */
706 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
707 checksum += avi_info_frame[i];
709 avi_info_frame[3] = 0x100 - checksum;
711 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
712 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
714 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
715 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
717 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
718 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
720 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
721 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
723 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
726 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
727 int clk_div, int clk_double)
729 struct sunxi_hdmi_reg * const hdmi =
730 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
733 /* Write clear interrupt status bits */
734 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
736 if (sunxi_display.monitor == sunxi_monitor_hdmi)
737 sunxi_hdmi_setup_info_frames(mode);
739 /* Set input sync enable */
740 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
742 /* Init various registers, select pll3 as clock source */
743 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
744 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
745 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
746 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
747 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
749 /* Setup clk div and doubler */
750 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
751 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
753 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
755 /* Setup timing registers */
756 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
759 x = mode->hsync_len + mode->left_margin;
760 y = mode->vsync_len + mode->upper_margin;
761 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
763 x = mode->right_margin;
764 y = mode->lower_margin;
765 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
769 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
771 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
772 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
774 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
775 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
778 static void sunxi_hdmi_enable(void)
780 struct sunxi_hdmi_reg * const hdmi =
781 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
784 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
787 #endif /* CONFIG_VIDEO_HDMI */
789 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
791 static void sunxi_tvencoder_mode_set(void)
793 struct sunxi_ccm_reg * const ccm =
794 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
795 struct sunxi_tve_reg * const tve =
796 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
799 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
801 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
803 switch (sunxi_display.monitor) {
804 case sunxi_monitor_vga:
805 tvencoder_mode_set(tve, tve_mode_vga);
807 case sunxi_monitor_composite_pal_nc:
808 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
810 case sunxi_monitor_composite_pal:
811 tvencoder_mode_set(tve, tve_mode_composite_pal);
813 case sunxi_monitor_composite_pal_m:
814 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
816 case sunxi_monitor_composite_ntsc:
817 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
819 case sunxi_monitor_none:
820 case sunxi_monitor_dvi:
821 case sunxi_monitor_hdmi:
822 case sunxi_monitor_lcd:
827 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
829 static void sunxi_drc_init(void)
831 #ifdef CONFIG_SUNXI_GEN_SUN6I
832 struct sunxi_ccm_reg * const ccm =
833 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
835 /* On sun6i the drc must be clocked even when in pass-through mode */
836 #ifdef CONFIG_MACH_SUN8I_A33
837 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
839 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
840 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
844 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
845 static void sunxi_vga_external_dac_enable(void)
849 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
851 gpio_request(pin, "vga_enable");
852 gpio_direction_output(pin, 1);
855 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
857 #ifdef CONFIG_VIDEO_LCD_SSD2828
858 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
860 struct ssd2828_config cfg = {
861 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
862 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
863 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
864 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
865 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
866 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
867 .ssd2828_color_depth = 24,
868 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
869 .mipi_dsi_number_of_data_lanes = 4,
870 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
871 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
872 .mipi_dsi_delay_after_set_display_on_ms = 200
874 #error MIPI LCD panel needs configuration parameters
878 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
879 printf("SSD2828: SPI pins are not properly configured\n");
882 if (cfg.reset_pin == -1) {
883 printf("SSD2828: Reset pin is not properly configured\n");
887 return ssd2828_init(&cfg, mode);
889 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
891 static void sunxi_engines_init(void)
893 sunxi_composer_init();
898 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
899 unsigned int address)
901 int __maybe_unused clk_div, clk_double;
902 struct sunxi_lcdc_reg * const lcdc =
903 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
904 struct sunxi_tve_reg * __maybe_unused const tve =
905 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
907 switch (sunxi_display.monitor) {
908 case sunxi_monitor_none:
910 case sunxi_monitor_dvi:
911 case sunxi_monitor_hdmi:
912 #ifdef CONFIG_VIDEO_HDMI
913 sunxi_composer_mode_set(mode, address);
914 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
915 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
916 sunxi_composer_enable();
917 lcdc_enable(lcdc, sunxi_display.depth);
921 case sunxi_monitor_lcd:
922 sunxi_lcdc_panel_enable();
923 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
925 * The anx9804 needs 1.8V from eldo3, we do this here
926 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
927 * to avoid turning this on when using hdmi output.
929 axp_set_eldo(3, 1800);
930 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
931 ANX9804_DATA_RATE_1620M,
932 sunxi_display.depth);
934 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
935 mdelay(50); /* Wait for lcd controller power on */
936 hitachi_tx18d42vm_init();
938 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
939 unsigned int orig_i2c_bus = i2c_get_bus_num();
940 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
941 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
942 i2c_set_bus_num(orig_i2c_bus);
944 sunxi_composer_mode_set(mode, address);
945 sunxi_lcdc_tcon0_mode_set(mode, false);
946 sunxi_composer_enable();
947 lcdc_enable(lcdc, sunxi_display.depth);
948 #ifdef CONFIG_VIDEO_LCD_SSD2828
949 sunxi_ssd2828_init(mode);
951 sunxi_lcdc_backlight_enable();
953 case sunxi_monitor_vga:
954 #ifdef CONFIG_VIDEO_VGA
955 sunxi_composer_mode_set(mode, address);
956 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
957 sunxi_tvencoder_mode_set();
958 sunxi_composer_enable();
959 lcdc_enable(lcdc, sunxi_display.depth);
960 tvencoder_enable(tve);
961 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
962 sunxi_composer_mode_set(mode, address);
963 sunxi_lcdc_tcon0_mode_set(mode, true);
964 sunxi_composer_enable();
965 lcdc_enable(lcdc, sunxi_display.depth);
966 sunxi_vga_external_dac_enable();
969 case sunxi_monitor_composite_pal:
970 case sunxi_monitor_composite_ntsc:
971 case sunxi_monitor_composite_pal_m:
972 case sunxi_monitor_composite_pal_nc:
973 #ifdef CONFIG_VIDEO_COMPOSITE
974 sunxi_composer_mode_set(mode, address);
975 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
976 sunxi_tvencoder_mode_set();
977 sunxi_composer_enable();
978 lcdc_enable(lcdc, sunxi_display.depth);
979 tvencoder_enable(tve);
985 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
988 case sunxi_monitor_dvi: return "dvi";
989 case sunxi_monitor_hdmi: return "hdmi";
990 case sunxi_monitor_lcd: return "lcd";
991 case sunxi_monitor_vga: return "vga";
992 case sunxi_monitor_composite_pal: return "composite-pal";
993 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
994 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
995 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
996 case sunxi_monitor_none: /* fall through */
997 default: return "none";
1001 ulong board_get_usable_ram_top(ulong total_size)
1003 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1006 static bool sunxi_has_hdmi(void)
1008 #ifdef CONFIG_VIDEO_HDMI
1015 static bool sunxi_has_lcd(void)
1017 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1019 return lcd_mode[0] != 0;
1022 static bool sunxi_has_vga(void)
1024 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1031 static bool sunxi_has_composite(void)
1033 #ifdef CONFIG_VIDEO_COMPOSITE
1040 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1042 if (allow_hdmi && sunxi_has_hdmi())
1043 return sunxi_monitor_dvi;
1044 else if (sunxi_has_lcd())
1045 return sunxi_monitor_lcd;
1046 else if (sunxi_has_vga())
1047 return sunxi_monitor_vga;
1048 else if (sunxi_has_composite())
1049 return sunxi_monitor_composite_pal;
1051 return sunxi_monitor_none;
1054 void *video_hw_init(void)
1056 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1057 const struct ctfb_res_modes *mode;
1058 struct ctfb_res_modes custom;
1059 const char *options;
1060 #ifdef CONFIG_VIDEO_HDMI
1061 int hpd, hpd_delay, edid;
1064 int i, overscan_offset, overscan_x, overscan_y;
1065 unsigned int fb_dma_addr;
1067 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1069 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1071 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1072 &sunxi_display.depth, &options);
1073 #ifdef CONFIG_VIDEO_HDMI
1074 hpd = video_get_option_int(options, "hpd", 1);
1075 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1076 edid = video_get_option_int(options, "edid", 1);
1078 overscan_x = video_get_option_int(options, "overscan_x", -1);
1079 overscan_y = video_get_option_int(options, "overscan_y", -1);
1080 sunxi_display.monitor = sunxi_get_default_mon(true);
1081 video_get_option_string(options, "monitor", mon, sizeof(mon),
1082 sunxi_get_mon_desc(sunxi_display.monitor));
1083 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1084 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1085 sunxi_display.monitor = i;
1089 if (i > SUNXI_MONITOR_LAST)
1090 printf("Unknown monitor: '%s', falling back to '%s'\n",
1091 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1093 #ifdef CONFIG_VIDEO_HDMI
1094 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1095 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1096 sunxi_display.monitor == sunxi_monitor_hdmi) {
1097 /* Always call hdp_detect, as it also enables clocks, etc. */
1098 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1099 if (hdmi_present && edid) {
1100 printf("HDMI connected: ");
1101 if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
1104 hdmi_present = false;
1106 /* Fall back to EDID in case HPD failed */
1107 if (edid && !hdmi_present) {
1108 if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1110 hdmi_present = true;
1113 /* Shut down when display was not found */
1114 if ((hpd || edid) && !hdmi_present) {
1115 sunxi_hdmi_shutdown();
1116 sunxi_display.monitor = sunxi_get_default_mon(false);
1117 } /* else continue with hdmi/dvi without a cable connected */
1121 switch (sunxi_display.monitor) {
1122 case sunxi_monitor_none:
1124 case sunxi_monitor_dvi:
1125 case sunxi_monitor_hdmi:
1126 if (!sunxi_has_hdmi()) {
1127 printf("HDMI/DVI not supported on this board\n");
1128 sunxi_display.monitor = sunxi_monitor_none;
1132 case sunxi_monitor_lcd:
1133 if (!sunxi_has_lcd()) {
1134 printf("LCD not supported on this board\n");
1135 sunxi_display.monitor = sunxi_monitor_none;
1138 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1141 case sunxi_monitor_vga:
1142 if (!sunxi_has_vga()) {
1143 printf("VGA not supported on this board\n");
1144 sunxi_display.monitor = sunxi_monitor_none;
1147 sunxi_display.depth = 18;
1149 case sunxi_monitor_composite_pal:
1150 case sunxi_monitor_composite_ntsc:
1151 case sunxi_monitor_composite_pal_m:
1152 case sunxi_monitor_composite_pal_nc:
1153 if (!sunxi_has_composite()) {
1154 printf("Composite video not supported on this board\n");
1155 sunxi_display.monitor = sunxi_monitor_none;
1158 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1159 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1160 mode = &composite_video_modes[0];
1162 mode = &composite_video_modes[1];
1163 sunxi_display.depth = 24;
1167 /* Yes these defaults are quite high, overscan on composite sucks... */
1168 if (overscan_x == -1)
1169 overscan_x = sunxi_is_composite() ? 32 : 0;
1170 if (overscan_y == -1)
1171 overscan_y = sunxi_is_composite() ? 20 : 0;
1173 sunxi_display.fb_size =
1174 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1175 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1176 /* We want to keep the fb_base for simplefb page aligned, where as
1177 * the sunxi dma engines will happily accept an unaligned address. */
1178 if (overscan_offset)
1179 sunxi_display.fb_size += 0x1000;
1181 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1182 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1183 sunxi_display.fb_size >> 10,
1184 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1188 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1189 mode->xres, mode->yres,
1190 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1191 sunxi_get_mon_desc(sunxi_display.monitor),
1192 overscan_x, overscan_y);
1194 gd->fb_base = gd->bd->bi_dram[0].start +
1195 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1196 sunxi_engines_init();
1198 #ifdef CONFIG_EFI_LOADER
1199 efi_add_memory_map(gd->fb_base,
1200 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1202 EFI_RESERVED_MEMORY_TYPE, false);
1205 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1206 sunxi_display.fb_addr = gd->fb_base;
1207 if (overscan_offset) {
1208 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1209 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1210 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1211 flush_cache(gd->fb_base, sunxi_display.fb_size);
1213 sunxi_mode_set(mode, fb_dma_addr);
1216 * These are the only members of this structure that are used. All the
1217 * others are driver specific. The pitch is stored in plnSizeX.
1219 graphic_device->frameAdrs = sunxi_display.fb_addr;
1220 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1221 graphic_device->gdfBytesPP = 4;
1222 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1223 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1224 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1226 return graphic_device;
1232 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1233 int sunxi_simplefb_setup(void *blob)
1235 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1238 const char *pipeline = NULL;
1240 #ifdef CONFIG_MACH_SUN4I
1241 #define PIPELINE_PREFIX "de_fe0-"
1243 #define PIPELINE_PREFIX
1246 switch (sunxi_display.monitor) {
1247 case sunxi_monitor_none:
1249 case sunxi_monitor_dvi:
1250 case sunxi_monitor_hdmi:
1251 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1253 case sunxi_monitor_lcd:
1254 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1256 case sunxi_monitor_vga:
1257 #ifdef CONFIG_VIDEO_VGA
1258 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1259 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1260 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1263 case sunxi_monitor_composite_pal:
1264 case sunxi_monitor_composite_ntsc:
1265 case sunxi_monitor_composite_pal_m:
1266 case sunxi_monitor_composite_pal_nc:
1267 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1271 offset = sunxi_simplefb_fdt_match(blob, pipeline);
1273 eprintf("Cannot setup simplefb: node not found\n");
1274 return 0; /* Keep older kernels working */
1278 * Do not report the framebuffer as free RAM to the OS, note we cannot
1279 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1280 * and e.g. Linux refuses to iomap RAM on ARM, see:
1281 * linux/arch/arm/mm/ioremap.c around line 301.
1283 start = gd->bd->bi_dram[0].start;
1284 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1285 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1287 eprintf("Cannot setup simplefb: Error reserving memory\n");
1291 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1292 graphic_device->winSizeX, graphic_device->winSizeY,
1293 graphic_device->plnSizeX, "x8r8g8b8");
1295 eprintf("Cannot setup simplefb: Error setting properties\n");
1299 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */