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 <linux/delay.h>
16 #include <asm/arch/clock.h>
17 #include <asm/arch/display.h>
18 #include <asm/arch/gpio.h>
19 #include <asm/arch/lcdc.h>
20 #include <asm/arch/pwm.h>
21 #include <asm/arch/tve.h>
22 #include <asm/global_data.h>
28 #include <fdt_support.h>
32 #include "../videomodes.h"
33 #include "../anx9804.h"
34 #include "../hitachi_tx18d42vm_lcd.h"
35 #include "../ssd2828.h"
36 #include "simplefb_common.h"
38 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
46 DECLARE_GLOBAL_DATA_PTR;
54 sunxi_monitor_composite_pal,
55 sunxi_monitor_composite_ntsc,
56 sunxi_monitor_composite_pal_m,
57 sunxi_monitor_composite_pal_nc,
59 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
61 struct sunxi_display {
62 GraphicDevice graphic_device;
63 enum sunxi_monitor monitor;
69 const struct ctfb_res_modes composite_video_modes[2] = {
70 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
71 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
72 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
75 #ifdef CONFIG_VIDEO_HDMI
78 * Wait up to 200ms for value to be set in given part of reg.
80 static int await_completion(u32 *reg, u32 mask, u32 val)
82 unsigned long tmo = timer_get_us() + 200000;
84 while ((readl(reg) & mask) != val) {
85 if (timer_get_us() > tmo) {
86 printf("DDC: timeout reading EDID\n");
93 static int sunxi_hdmi_hpd_detect(int hpd_delay)
95 struct sunxi_ccm_reg * const ccm =
96 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
97 struct sunxi_hdmi_reg * const hdmi =
98 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
99 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
101 /* Set pll3 to 300MHz */
102 clock_set_pll3(300000000);
104 /* Set hdmi parent to pll3 */
105 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
108 /* Set ahb gating to pass */
109 #ifdef CONFIG_SUNXI_GEN_SUN6I
110 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
112 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
115 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
117 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
118 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
120 /* Enable PLLs for eventual DDC */
121 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
123 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
125 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
127 while (timer_get_us() < tmo) {
128 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
135 static void sunxi_hdmi_shutdown(void)
137 struct sunxi_ccm_reg * const ccm =
138 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
139 struct sunxi_hdmi_reg * const hdmi =
140 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
142 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
143 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
144 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
145 #ifdef CONFIG_SUNXI_GEN_SUN6I
146 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
151 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
153 struct sunxi_hdmi_reg * const hdmi =
154 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
156 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
157 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
158 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
159 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
160 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
161 #ifndef CONFIG_MACH_SUN6I
162 writel(n, &hdmi->ddc_byte_count);
163 writel(cmnd, &hdmi->ddc_cmnd);
165 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
167 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
169 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
172 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
174 struct sunxi_hdmi_reg * const hdmi =
175 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
184 if (sunxi_hdmi_ddc_do_command(
185 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
189 for (i = 0; i < n; i++)
190 *buf++ = readb(&hdmi->ddc_fifo_data);
199 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
204 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
207 r = edid_check_checksum(buf);
209 printf("EDID block %d: checksum error%s\n",
210 block, retries ? ", retrying" : "");
212 } while (r && retries--);
217 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
220 struct edid1_info edid1;
221 struct edid_cea861_info cea681[4];
222 struct edid_detailed_timing *t =
223 (struct edid_detailed_timing *)edid1.monitor_details.timing;
224 struct sunxi_hdmi_reg * const hdmi =
225 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
226 struct sunxi_ccm_reg * const ccm =
227 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
228 int i, r, ext_blocks = 0;
230 /* Reset i2c controller */
231 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
232 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
233 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
234 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
235 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
236 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
239 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
240 #ifndef CONFIG_MACH_SUN6I
241 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
242 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
245 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
247 r = edid_check_info(&edid1);
250 printf("EDID: invalid EDID data\n");
255 ext_blocks = edid1.extension_flag;
258 for (i = 0; i < ext_blocks; i++) {
259 if (sunxi_hdmi_edid_get_block(1 + i,
260 (u8 *)&cea681[i]) != 0) {
267 /* Disable DDC engine, no longer needed */
268 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
269 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
274 /* We want version 1.3 or 1.2 with detailed timing info */
275 if (edid1.version != 1 || (edid1.revision < 3 &&
276 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
277 printf("EDID: unsupported version %d.%d\n",
278 edid1.version, edid1.revision);
282 /* Take the first usable detailed timing */
283 for (i = 0; i < 4; i++, t++) {
284 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
289 printf("EDID: no usable detailed timing found\n");
293 /* Check for basic audio support, if found enable hdmi output */
294 sunxi_display.monitor = sunxi_monitor_dvi;
295 for (i = 0; i < ext_blocks; i++) {
296 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
297 cea681[i].revision < 2)
300 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
301 sunxi_display.monitor = sunxi_monitor_hdmi;
307 #endif /* CONFIG_VIDEO_HDMI */
309 #ifdef CONFIG_MACH_SUN4I
311 * Testing has shown that on sun4i the display backend engine does not have
312 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
313 * fifo underruns. So on sun4i we use the display frontend engine to do the
314 * dma from memory, as the frontend does have deep enough fifo-s.
317 static const u32 sun4i_vert_coef[32] = {
318 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
319 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
320 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
321 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
322 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
323 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
324 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
325 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
328 static const u32 sun4i_horz_coef[64] = {
329 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
330 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
331 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
332 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
333 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
334 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
335 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
336 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
337 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
338 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
339 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
340 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
341 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
342 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
343 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
344 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
347 static void sunxi_frontend_init(void)
349 struct sunxi_ccm_reg * const ccm =
350 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
351 struct sunxi_de_fe_reg * const de_fe =
352 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
356 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
357 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
358 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
360 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
362 for (i = 0; i < 32; i++) {
363 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
364 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
365 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
366 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
367 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
368 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
371 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
374 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
375 unsigned int address)
377 struct sunxi_de_fe_reg * const de_fe =
378 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
380 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
381 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
382 writel(mode->xres * 4, &de_fe->ch0_stride);
383 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
384 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
386 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
388 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
389 &de_fe->ch0_outsize);
390 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
391 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
393 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
395 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
396 &de_fe->ch1_outsize);
397 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
398 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
400 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
403 static void sunxi_frontend_enable(void)
405 struct sunxi_de_fe_reg * const de_fe =
406 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
408 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
411 static void sunxi_frontend_init(void) {}
412 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
413 unsigned int address) {}
414 static void sunxi_frontend_enable(void) {}
417 static bool sunxi_is_composite(void)
419 switch (sunxi_display.monitor) {
420 case sunxi_monitor_none:
421 case sunxi_monitor_dvi:
422 case sunxi_monitor_hdmi:
423 case sunxi_monitor_lcd:
424 case sunxi_monitor_vga:
426 case sunxi_monitor_composite_pal:
427 case sunxi_monitor_composite_ntsc:
428 case sunxi_monitor_composite_pal_m:
429 case sunxi_monitor_composite_pal_nc:
433 return false; /* Never reached */
437 * This is the entity that mixes and matches the different layers and inputs.
438 * Allwinner calls it the back-end, but i like composer better.
440 static void sunxi_composer_init(void)
442 struct sunxi_ccm_reg * const ccm =
443 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
444 struct sunxi_de_be_reg * const de_be =
445 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
448 sunxi_frontend_init();
450 #ifdef CONFIG_SUNXI_GEN_SUN6I
452 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
456 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
457 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
458 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
460 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
462 /* Engine bug, clear registers after reset */
463 for (i = 0x0800; i < 0x1000; i += 4)
464 writel(0, SUNXI_DE_BE0_BASE + i);
466 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
469 static const u32 sunxi_rgb2yuv_coef[12] = {
470 0x00000107, 0x00000204, 0x00000064, 0x00000108,
471 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
472 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
475 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
476 unsigned int address)
478 struct sunxi_de_be_reg * const de_be =
479 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
482 sunxi_frontend_mode_set(mode, address);
484 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
486 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
487 &de_be->layer0_size);
488 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
489 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
490 writel(address << 3, &de_be->layer0_addr_low32b);
491 writel(address >> 29, &de_be->layer0_addr_high4b);
493 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
495 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
497 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
498 if (mode->vmode == FB_VMODE_INTERLACED)
499 setbits_le32(&de_be->mode,
500 #ifndef CONFIG_MACH_SUN5I
501 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
503 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
505 if (sunxi_is_composite()) {
506 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
507 &de_be->output_color_ctrl);
508 for (i = 0; i < 12; i++)
509 writel(sunxi_rgb2yuv_coef[i],
510 &de_be->output_color_coef[i]);
514 static void sunxi_composer_enable(void)
516 struct sunxi_de_be_reg * const de_be =
517 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
519 sunxi_frontend_enable();
521 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
522 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
525 static void sunxi_lcdc_init(void)
527 struct sunxi_ccm_reg * const ccm =
528 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
529 struct sunxi_lcdc_reg * const lcdc =
530 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
533 #ifdef CONFIG_SUNXI_GEN_SUN6I
534 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
536 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
540 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
541 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
542 #ifdef CONFIG_SUNXI_GEN_SUN6I
543 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
545 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
552 static void sunxi_lcdc_panel_enable(void)
557 * Start with backlight disabled to avoid the screen flashing to
558 * white while the lcd inits.
560 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
562 gpio_request(pin, "lcd_backlight_enable");
563 gpio_direction_output(pin, 0);
566 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
568 gpio_request(pin, "lcd_backlight_pwm");
569 gpio_direction_output(pin, PWM_OFF);
572 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
573 if (reset_pin >= 0) {
574 gpio_request(reset_pin, "lcd_reset");
575 gpio_direction_output(reset_pin, 0); /* Assert reset */
578 /* Give the backlight some time to turn off and power up the panel. */
580 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
582 gpio_request(pin, "lcd_power");
583 gpio_direction_output(pin, 1);
587 gpio_direction_output(reset_pin, 1); /* De-assert reset */
590 static void sunxi_lcdc_backlight_enable(void)
595 * We want to have scanned out at least one frame before enabling the
596 * backlight to avoid the screen flashing to white when we enable it.
600 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
602 gpio_direction_output(pin, 1);
604 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
605 #ifdef SUNXI_PWM_PIN0
606 if (pin == SUNXI_PWM_PIN0) {
607 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
608 SUNXI_PWM_CTRL_ENABLE0 |
609 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
610 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
611 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
616 gpio_direction_output(pin, PWM_ON);
619 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
620 bool for_ext_vga_dac)
622 struct sunxi_lcdc_reg * const lcdc =
623 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
624 struct sunxi_ccm_reg * const ccm =
625 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
626 int clk_div, clk_double, pin;
627 struct display_timing timing;
629 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
630 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
632 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
634 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
635 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
637 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
638 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
640 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
641 sunxi_gpio_set_drv(pin, 3);
645 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
646 sunxi_is_composite());
648 video_ctfb_mode_to_display_timing(mode, &timing);
649 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
650 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
653 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
654 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
655 int *clk_div, int *clk_double,
656 bool use_portd_hvsync)
658 struct sunxi_lcdc_reg * const lcdc =
659 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
660 struct sunxi_ccm_reg * const ccm =
661 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
662 struct display_timing timing;
664 video_ctfb_mode_to_display_timing(mode, &timing);
665 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
666 sunxi_is_composite());
668 if (use_portd_hvsync) {
669 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
670 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
673 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
674 sunxi_is_composite());
676 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
678 #ifdef CONFIG_VIDEO_HDMI
680 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
682 struct sunxi_hdmi_reg * const hdmi =
683 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
685 u8 avi_info_frame[17] = {
686 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 u8 vendor_info_frame[19] = {
691 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
697 if (mode->pixclock_khz <= 27000)
698 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
700 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
702 if (mode->xres * 100 / mode->yres < 156)
703 avi_info_frame[5] |= 0x18; /* 4 : 3 */
705 avi_info_frame[5] |= 0x28; /* 16 : 9 */
707 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
708 checksum += avi_info_frame[i];
710 avi_info_frame[3] = 0x100 - checksum;
712 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
713 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
715 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
716 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
718 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
719 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
721 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
722 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
724 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
727 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
728 int clk_div, int clk_double)
730 struct sunxi_hdmi_reg * const hdmi =
731 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
734 /* Write clear interrupt status bits */
735 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
737 if (sunxi_display.monitor == sunxi_monitor_hdmi)
738 sunxi_hdmi_setup_info_frames(mode);
740 /* Set input sync enable */
741 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
743 /* Init various registers, select pll3 as clock source */
744 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
745 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
746 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
747 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
748 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
750 /* Setup clk div and doubler */
751 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
752 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
754 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
756 /* Setup timing registers */
757 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
760 x = mode->hsync_len + mode->left_margin;
761 y = mode->vsync_len + mode->upper_margin;
762 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
764 x = mode->right_margin;
765 y = mode->lower_margin;
766 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
770 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
772 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
773 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
775 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
776 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
779 static void sunxi_hdmi_enable(void)
781 struct sunxi_hdmi_reg * const hdmi =
782 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
785 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
788 #endif /* CONFIG_VIDEO_HDMI */
790 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
792 static void sunxi_tvencoder_mode_set(void)
794 struct sunxi_ccm_reg * const ccm =
795 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
796 struct sunxi_tve_reg * const tve =
797 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
800 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
802 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
804 switch (sunxi_display.monitor) {
805 case sunxi_monitor_vga:
806 tvencoder_mode_set(tve, tve_mode_vga);
808 case sunxi_monitor_composite_pal_nc:
809 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
811 case sunxi_monitor_composite_pal:
812 tvencoder_mode_set(tve, tve_mode_composite_pal);
814 case sunxi_monitor_composite_pal_m:
815 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
817 case sunxi_monitor_composite_ntsc:
818 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
820 case sunxi_monitor_none:
821 case sunxi_monitor_dvi:
822 case sunxi_monitor_hdmi:
823 case sunxi_monitor_lcd:
828 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
830 static void sunxi_drc_init(void)
832 #ifdef CONFIG_SUNXI_GEN_SUN6I
833 struct sunxi_ccm_reg * const ccm =
834 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
836 /* On sun6i the drc must be clocked even when in pass-through mode */
837 #ifdef CONFIG_MACH_SUN8I_A33
838 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
840 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
841 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
845 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
846 static void sunxi_vga_external_dac_enable(void)
850 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
852 gpio_request(pin, "vga_enable");
853 gpio_direction_output(pin, 1);
856 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
858 #ifdef CONFIG_VIDEO_LCD_SSD2828
859 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
861 struct ssd2828_config cfg = {
862 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
863 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
864 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
865 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
866 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
867 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
868 .ssd2828_color_depth = 24,
869 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
870 .mipi_dsi_number_of_data_lanes = 4,
871 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
872 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
873 .mipi_dsi_delay_after_set_display_on_ms = 200
875 #error MIPI LCD panel needs configuration parameters
879 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
880 printf("SSD2828: SPI pins are not properly configured\n");
883 if (cfg.reset_pin == -1) {
884 printf("SSD2828: Reset pin is not properly configured\n");
888 return ssd2828_init(&cfg, mode);
890 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
892 static void sunxi_engines_init(void)
894 sunxi_composer_init();
899 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
900 unsigned int address)
902 int __maybe_unused clk_div, clk_double;
903 struct sunxi_lcdc_reg * const lcdc =
904 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
905 struct sunxi_tve_reg * __maybe_unused const tve =
906 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
908 switch (sunxi_display.monitor) {
909 case sunxi_monitor_none:
911 case sunxi_monitor_dvi:
912 case sunxi_monitor_hdmi:
913 #ifdef CONFIG_VIDEO_HDMI
914 sunxi_composer_mode_set(mode, address);
915 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
916 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
917 sunxi_composer_enable();
918 lcdc_enable(lcdc, sunxi_display.depth);
922 case sunxi_monitor_lcd:
923 sunxi_lcdc_panel_enable();
924 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
926 * The anx9804 needs 1.8V from eldo3, we do this here
927 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
928 * to avoid turning this on when using hdmi output.
930 axp_set_eldo(3, 1800);
931 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
932 ANX9804_DATA_RATE_1620M,
933 sunxi_display.depth);
935 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
936 mdelay(50); /* Wait for lcd controller power on */
937 hitachi_tx18d42vm_init();
939 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
940 unsigned int orig_i2c_bus = i2c_get_bus_num();
941 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
942 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
943 i2c_set_bus_num(orig_i2c_bus);
945 sunxi_composer_mode_set(mode, address);
946 sunxi_lcdc_tcon0_mode_set(mode, false);
947 sunxi_composer_enable();
948 lcdc_enable(lcdc, sunxi_display.depth);
949 #ifdef CONFIG_VIDEO_LCD_SSD2828
950 sunxi_ssd2828_init(mode);
952 sunxi_lcdc_backlight_enable();
954 case sunxi_monitor_vga:
955 #ifdef CONFIG_VIDEO_VGA
956 sunxi_composer_mode_set(mode, address);
957 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
958 sunxi_tvencoder_mode_set();
959 sunxi_composer_enable();
960 lcdc_enable(lcdc, sunxi_display.depth);
961 tvencoder_enable(tve);
962 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
963 sunxi_composer_mode_set(mode, address);
964 sunxi_lcdc_tcon0_mode_set(mode, true);
965 sunxi_composer_enable();
966 lcdc_enable(lcdc, sunxi_display.depth);
967 sunxi_vga_external_dac_enable();
970 case sunxi_monitor_composite_pal:
971 case sunxi_monitor_composite_ntsc:
972 case sunxi_monitor_composite_pal_m:
973 case sunxi_monitor_composite_pal_nc:
974 #ifdef CONFIG_VIDEO_COMPOSITE
975 sunxi_composer_mode_set(mode, address);
976 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
977 sunxi_tvencoder_mode_set();
978 sunxi_composer_enable();
979 lcdc_enable(lcdc, sunxi_display.depth);
980 tvencoder_enable(tve);
986 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
989 case sunxi_monitor_dvi: return "dvi";
990 case sunxi_monitor_hdmi: return "hdmi";
991 case sunxi_monitor_lcd: return "lcd";
992 case sunxi_monitor_vga: return "vga";
993 case sunxi_monitor_composite_pal: return "composite-pal";
994 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
995 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
996 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
997 case sunxi_monitor_none: /* fall through */
998 default: return "none";
1002 ulong board_get_usable_ram_top(ulong total_size)
1004 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1007 static bool sunxi_has_hdmi(void)
1009 #ifdef CONFIG_VIDEO_HDMI
1016 static bool sunxi_has_lcd(void)
1018 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1020 return lcd_mode[0] != 0;
1023 static bool sunxi_has_vga(void)
1025 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1032 static bool sunxi_has_composite(void)
1034 #ifdef CONFIG_VIDEO_COMPOSITE
1041 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1043 if (allow_hdmi && sunxi_has_hdmi())
1044 return sunxi_monitor_dvi;
1045 else if (sunxi_has_lcd())
1046 return sunxi_monitor_lcd;
1047 else if (sunxi_has_vga())
1048 return sunxi_monitor_vga;
1049 else if (sunxi_has_composite())
1050 return sunxi_monitor_composite_pal;
1052 return sunxi_monitor_none;
1055 void *video_hw_init(void)
1057 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1058 const struct ctfb_res_modes *mode;
1059 struct ctfb_res_modes custom;
1060 const char *options;
1061 #ifdef CONFIG_VIDEO_HDMI
1062 int hpd, hpd_delay, edid;
1065 int i, overscan_offset, overscan_x, overscan_y;
1066 unsigned int fb_dma_addr;
1068 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1070 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1072 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1073 &sunxi_display.depth, &options);
1074 #ifdef CONFIG_VIDEO_HDMI
1075 hpd = video_get_option_int(options, "hpd", 1);
1076 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1077 edid = video_get_option_int(options, "edid", 1);
1079 overscan_x = video_get_option_int(options, "overscan_x", -1);
1080 overscan_y = video_get_option_int(options, "overscan_y", -1);
1081 sunxi_display.monitor = sunxi_get_default_mon(true);
1082 video_get_option_string(options, "monitor", mon, sizeof(mon),
1083 sunxi_get_mon_desc(sunxi_display.monitor));
1084 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1085 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1086 sunxi_display.monitor = i;
1090 if (i > SUNXI_MONITOR_LAST)
1091 printf("Unknown monitor: '%s', falling back to '%s'\n",
1092 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1094 #ifdef CONFIG_VIDEO_HDMI
1095 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1096 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1097 sunxi_display.monitor == sunxi_monitor_hdmi) {
1098 /* Always call hdp_detect, as it also enables clocks, etc. */
1099 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1100 if (hdmi_present && edid) {
1101 printf("HDMI connected: ");
1102 if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
1105 hdmi_present = false;
1107 /* Fall back to EDID in case HPD failed */
1108 if (edid && !hdmi_present) {
1109 if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1111 hdmi_present = true;
1114 /* Shut down when display was not found */
1115 if ((hpd || edid) && !hdmi_present) {
1116 sunxi_hdmi_shutdown();
1117 sunxi_display.monitor = sunxi_get_default_mon(false);
1118 } /* else continue with hdmi/dvi without a cable connected */
1122 switch (sunxi_display.monitor) {
1123 case sunxi_monitor_none:
1125 case sunxi_monitor_dvi:
1126 case sunxi_monitor_hdmi:
1127 if (!sunxi_has_hdmi()) {
1128 printf("HDMI/DVI not supported on this board\n");
1129 sunxi_display.monitor = sunxi_monitor_none;
1133 case sunxi_monitor_lcd:
1134 if (!sunxi_has_lcd()) {
1135 printf("LCD not supported on this board\n");
1136 sunxi_display.monitor = sunxi_monitor_none;
1139 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1142 case sunxi_monitor_vga:
1143 if (!sunxi_has_vga()) {
1144 printf("VGA not supported on this board\n");
1145 sunxi_display.monitor = sunxi_monitor_none;
1148 sunxi_display.depth = 18;
1150 case sunxi_monitor_composite_pal:
1151 case sunxi_monitor_composite_ntsc:
1152 case sunxi_monitor_composite_pal_m:
1153 case sunxi_monitor_composite_pal_nc:
1154 if (!sunxi_has_composite()) {
1155 printf("Composite video not supported on this board\n");
1156 sunxi_display.monitor = sunxi_monitor_none;
1159 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1160 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1161 mode = &composite_video_modes[0];
1163 mode = &composite_video_modes[1];
1164 sunxi_display.depth = 24;
1168 /* Yes these defaults are quite high, overscan on composite sucks... */
1169 if (overscan_x == -1)
1170 overscan_x = sunxi_is_composite() ? 32 : 0;
1171 if (overscan_y == -1)
1172 overscan_y = sunxi_is_composite() ? 20 : 0;
1174 sunxi_display.fb_size =
1175 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1176 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1177 /* We want to keep the fb_base for simplefb page aligned, where as
1178 * the sunxi dma engines will happily accept an unaligned address. */
1179 if (overscan_offset)
1180 sunxi_display.fb_size += 0x1000;
1182 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1183 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1184 sunxi_display.fb_size >> 10,
1185 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1189 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1190 mode->xres, mode->yres,
1191 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1192 sunxi_get_mon_desc(sunxi_display.monitor),
1193 overscan_x, overscan_y);
1195 gd->fb_base = gd->bd->bi_dram[0].start +
1196 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1197 sunxi_engines_init();
1199 #ifdef CONFIG_EFI_LOADER
1200 efi_add_memory_map(gd->fb_base, sunxi_display.fb_size,
1201 EFI_RESERVED_MEMORY_TYPE);
1204 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1205 sunxi_display.fb_addr = gd->fb_base;
1206 if (overscan_offset) {
1207 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1208 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1209 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1210 flush_cache(gd->fb_base, sunxi_display.fb_size);
1212 sunxi_mode_set(mode, fb_dma_addr);
1215 * These are the only members of this structure that are used. All the
1216 * others are driver specific. The pitch is stored in plnSizeX.
1218 graphic_device->frameAdrs = sunxi_display.fb_addr;
1219 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1220 graphic_device->gdfBytesPP = 4;
1221 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1222 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1223 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1225 return graphic_device;
1231 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1232 int sunxi_simplefb_setup(void *blob)
1234 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1237 const char *pipeline = NULL;
1239 #ifdef CONFIG_MACH_SUN4I
1240 #define PIPELINE_PREFIX "de_fe0-"
1242 #define PIPELINE_PREFIX
1245 switch (sunxi_display.monitor) {
1246 case sunxi_monitor_none:
1248 case sunxi_monitor_dvi:
1249 case sunxi_monitor_hdmi:
1250 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1252 case sunxi_monitor_lcd:
1253 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1255 case sunxi_monitor_vga:
1256 #ifdef CONFIG_VIDEO_VGA
1257 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1258 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1259 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1262 case sunxi_monitor_composite_pal:
1263 case sunxi_monitor_composite_ntsc:
1264 case sunxi_monitor_composite_pal_m:
1265 case sunxi_monitor_composite_pal_nc:
1266 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1270 offset = sunxi_simplefb_fdt_match(blob, pipeline);
1272 eprintf("Cannot setup simplefb: node not found\n");
1273 return 0; /* Keep older kernels working */
1277 * Do not report the framebuffer as free RAM to the OS, note we cannot
1278 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1279 * and e.g. Linux refuses to iomap RAM on ARM, see:
1280 * linux/arch/arm/mm/ioremap.c around line 301.
1282 start = gd->bd->bi_dram[0].start;
1283 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1284 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1286 eprintf("Cannot setup simplefb: Error reserving memory\n");
1290 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1291 graphic_device->winSizeX, graphic_device->winSizeY,
1292 graphic_device->plnSizeX, "x8r8g8b8");
1294 eprintf("Cannot setup simplefb: Error setting properties\n");
1298 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */