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>
10 #include <efi_loader.h>
12 #include <asm/arch/clock.h>
13 #include <asm/arch/display.h>
14 #include <asm/arch/gpio.h>
15 #include <asm/arch/lcdc.h>
16 #include <asm/arch/pwm.h>
17 #include <asm/arch/tve.h>
18 #include <asm/global_data.h>
24 #include <fdt_support.h>
28 #include "../videomodes.h"
29 #include "../anx9804.h"
30 #include "../hitachi_tx18d42vm_lcd.h"
31 #include "../ssd2828.h"
32 #include "simplefb_common.h"
34 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
42 DECLARE_GLOBAL_DATA_PTR;
50 sunxi_monitor_composite_pal,
51 sunxi_monitor_composite_ntsc,
52 sunxi_monitor_composite_pal_m,
53 sunxi_monitor_composite_pal_nc,
55 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
57 struct sunxi_display {
58 GraphicDevice graphic_device;
59 enum sunxi_monitor monitor;
65 const struct ctfb_res_modes composite_video_modes[2] = {
66 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
67 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
68 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
71 #ifdef CONFIG_VIDEO_HDMI
74 * Wait up to 200ms for value to be set in given part of reg.
76 static int await_completion(u32 *reg, u32 mask, u32 val)
78 unsigned long tmo = timer_get_us() + 200000;
80 while ((readl(reg) & mask) != val) {
81 if (timer_get_us() > tmo) {
82 printf("DDC: timeout reading EDID\n");
89 static int sunxi_hdmi_hpd_detect(int hpd_delay)
91 struct sunxi_ccm_reg * const ccm =
92 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
93 struct sunxi_hdmi_reg * const hdmi =
94 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
95 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
97 /* Set pll3 to 300MHz */
98 clock_set_pll3(300000000);
100 /* Set hdmi parent to pll3 */
101 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
104 /* Set ahb gating to pass */
105 #ifdef CONFIG_SUNXI_GEN_SUN6I
106 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
108 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
111 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
113 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
114 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
116 /* Enable PLLs for eventual DDC */
117 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
119 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
121 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
123 while (timer_get_us() < tmo) {
124 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
131 static void sunxi_hdmi_shutdown(void)
133 struct sunxi_ccm_reg * const ccm =
134 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
135 struct sunxi_hdmi_reg * const hdmi =
136 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
138 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
139 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
140 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
141 #ifdef CONFIG_SUNXI_GEN_SUN6I
142 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
147 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
149 struct sunxi_hdmi_reg * const hdmi =
150 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
152 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
153 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
154 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
155 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
156 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
157 #ifndef CONFIG_MACH_SUN6I
158 writel(n, &hdmi->ddc_byte_count);
159 writel(cmnd, &hdmi->ddc_cmnd);
161 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
163 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
165 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
168 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
170 struct sunxi_hdmi_reg * const hdmi =
171 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
180 if (sunxi_hdmi_ddc_do_command(
181 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
185 for (i = 0; i < n; i++)
186 *buf++ = readb(&hdmi->ddc_fifo_data);
195 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
200 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
203 r = edid_check_checksum(buf);
205 printf("EDID block %d: checksum error%s\n",
206 block, retries ? ", retrying" : "");
208 } while (r && retries--);
213 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
216 struct edid1_info edid1;
217 struct edid_cea861_info cea681[4];
218 struct edid_detailed_timing *t =
219 (struct edid_detailed_timing *)edid1.monitor_details.timing;
220 struct sunxi_hdmi_reg * const hdmi =
221 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
222 struct sunxi_ccm_reg * const ccm =
223 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
224 int i, r, ext_blocks = 0;
226 /* Reset i2c controller */
227 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
228 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
229 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
230 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
231 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
232 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
235 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
236 #ifndef CONFIG_MACH_SUN6I
237 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
238 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
241 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
243 r = edid_check_info(&edid1);
246 printf("EDID: invalid EDID data\n");
251 ext_blocks = edid1.extension_flag;
254 for (i = 0; i < ext_blocks; i++) {
255 if (sunxi_hdmi_edid_get_block(1 + i,
256 (u8 *)&cea681[i]) != 0) {
263 /* Disable DDC engine, no longer needed */
264 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
265 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
270 /* We want version 1.3 or 1.2 with detailed timing info */
271 if (edid1.version != 1 || (edid1.revision < 3 &&
272 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
273 printf("EDID: unsupported version %d.%d\n",
274 edid1.version, edid1.revision);
278 /* Take the first usable detailed timing */
279 for (i = 0; i < 4; i++, t++) {
280 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
285 printf("EDID: no usable detailed timing found\n");
289 /* Check for basic audio support, if found enable hdmi output */
290 sunxi_display.monitor = sunxi_monitor_dvi;
291 for (i = 0; i < ext_blocks; i++) {
292 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
293 cea681[i].revision < 2)
296 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
297 sunxi_display.monitor = sunxi_monitor_hdmi;
303 #endif /* CONFIG_VIDEO_HDMI */
305 #ifdef CONFIG_MACH_SUN4I
307 * Testing has shown that on sun4i the display backend engine does not have
308 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
309 * fifo underruns. So on sun4i we use the display frontend engine to do the
310 * dma from memory, as the frontend does have deep enough fifo-s.
313 static const u32 sun4i_vert_coef[32] = {
314 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
315 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
316 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
317 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
318 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
319 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
320 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
321 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
324 static const u32 sun4i_horz_coef[64] = {
325 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
326 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
327 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
328 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
329 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
330 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
331 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
332 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
333 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
334 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
335 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
336 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
337 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
338 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
339 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
340 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
343 static void sunxi_frontend_init(void)
345 struct sunxi_ccm_reg * const ccm =
346 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
347 struct sunxi_de_fe_reg * const de_fe =
348 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
352 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
353 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
354 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
356 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
358 for (i = 0; i < 32; i++) {
359 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
360 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
361 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
362 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
363 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
364 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
367 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
370 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
371 unsigned int address)
373 struct sunxi_de_fe_reg * const de_fe =
374 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
376 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
377 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
378 writel(mode->xres * 4, &de_fe->ch0_stride);
379 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
380 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
382 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
384 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
385 &de_fe->ch0_outsize);
386 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
387 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
389 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
391 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
392 &de_fe->ch1_outsize);
393 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
394 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
396 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
399 static void sunxi_frontend_enable(void)
401 struct sunxi_de_fe_reg * const de_fe =
402 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
404 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
407 static void sunxi_frontend_init(void) {}
408 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
409 unsigned int address) {}
410 static void sunxi_frontend_enable(void) {}
413 static bool sunxi_is_composite(void)
415 switch (sunxi_display.monitor) {
416 case sunxi_monitor_none:
417 case sunxi_monitor_dvi:
418 case sunxi_monitor_hdmi:
419 case sunxi_monitor_lcd:
420 case sunxi_monitor_vga:
422 case sunxi_monitor_composite_pal:
423 case sunxi_monitor_composite_ntsc:
424 case sunxi_monitor_composite_pal_m:
425 case sunxi_monitor_composite_pal_nc:
429 return false; /* Never reached */
433 * This is the entity that mixes and matches the different layers and inputs.
434 * Allwinner calls it the back-end, but i like composer better.
436 static void sunxi_composer_init(void)
438 struct sunxi_ccm_reg * const ccm =
439 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
440 struct sunxi_de_be_reg * const de_be =
441 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
444 sunxi_frontend_init();
446 #ifdef CONFIG_SUNXI_GEN_SUN6I
448 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
452 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
453 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
454 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
456 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
458 /* Engine bug, clear registers after reset */
459 for (i = 0x0800; i < 0x1000; i += 4)
460 writel(0, SUNXI_DE_BE0_BASE + i);
462 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
465 static const u32 sunxi_rgb2yuv_coef[12] = {
466 0x00000107, 0x00000204, 0x00000064, 0x00000108,
467 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
468 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
471 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
472 unsigned int address)
474 struct sunxi_de_be_reg * const de_be =
475 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
478 sunxi_frontend_mode_set(mode, address);
480 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
482 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
483 &de_be->layer0_size);
484 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
485 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
486 writel(address << 3, &de_be->layer0_addr_low32b);
487 writel(address >> 29, &de_be->layer0_addr_high4b);
489 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
491 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
493 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
494 if (mode->vmode == FB_VMODE_INTERLACED)
495 setbits_le32(&de_be->mode,
496 #ifndef CONFIG_MACH_SUN5I
497 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
499 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
501 if (sunxi_is_composite()) {
502 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
503 &de_be->output_color_ctrl);
504 for (i = 0; i < 12; i++)
505 writel(sunxi_rgb2yuv_coef[i],
506 &de_be->output_color_coef[i]);
510 static void sunxi_composer_enable(void)
512 struct sunxi_de_be_reg * const de_be =
513 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
515 sunxi_frontend_enable();
517 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
518 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
521 static void sunxi_lcdc_init(void)
523 struct sunxi_ccm_reg * const ccm =
524 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
525 struct sunxi_lcdc_reg * const lcdc =
526 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
529 #ifdef CONFIG_SUNXI_GEN_SUN6I
530 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
532 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
536 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
537 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
538 #ifdef CONFIG_SUNXI_GEN_SUN6I
539 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
541 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
548 static void sunxi_lcdc_panel_enable(void)
553 * Start with backlight disabled to avoid the screen flashing to
554 * white while the lcd inits.
556 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
558 gpio_request(pin, "lcd_backlight_enable");
559 gpio_direction_output(pin, 0);
562 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
564 gpio_request(pin, "lcd_backlight_pwm");
565 gpio_direction_output(pin, PWM_OFF);
568 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
569 if (reset_pin >= 0) {
570 gpio_request(reset_pin, "lcd_reset");
571 gpio_direction_output(reset_pin, 0); /* Assert reset */
574 /* Give the backlight some time to turn off and power up the panel. */
576 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
578 gpio_request(pin, "lcd_power");
579 gpio_direction_output(pin, 1);
583 gpio_direction_output(reset_pin, 1); /* De-assert reset */
586 static void sunxi_lcdc_backlight_enable(void)
591 * We want to have scanned out at least one frame before enabling the
592 * backlight to avoid the screen flashing to white when we enable it.
596 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
598 gpio_direction_output(pin, 1);
600 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
601 #ifdef SUNXI_PWM_PIN0
602 if (pin == SUNXI_PWM_PIN0) {
603 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
604 SUNXI_PWM_CTRL_ENABLE0 |
605 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
606 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
607 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
612 gpio_direction_output(pin, PWM_ON);
615 static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
616 struct display_timing *timing)
618 timing->pixelclock.typ = mode->pixclock_khz * 1000;
620 timing->hactive.typ = mode->xres;
621 timing->hfront_porch.typ = mode->right_margin;
622 timing->hback_porch.typ = mode->left_margin;
623 timing->hsync_len.typ = mode->hsync_len;
625 timing->vactive.typ = mode->yres;
626 timing->vfront_porch.typ = mode->lower_margin;
627 timing->vback_porch.typ = mode->upper_margin;
628 timing->vsync_len.typ = mode->vsync_len;
632 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
633 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
635 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
636 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
637 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
639 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
640 if (mode->vmode == FB_VMODE_INTERLACED)
641 timing->flags |= DISPLAY_FLAGS_INTERLACED;
644 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
645 bool for_ext_vga_dac)
647 struct sunxi_lcdc_reg * const lcdc =
648 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
649 struct sunxi_ccm_reg * const ccm =
650 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
651 int clk_div, clk_double, pin;
652 struct display_timing timing;
654 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
655 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
657 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
659 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
660 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
662 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
663 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
665 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
666 sunxi_gpio_set_drv(pin, 3);
670 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
671 sunxi_is_composite());
673 sunxi_ctfb_mode_to_display_timing(mode, &timing);
674 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
675 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
678 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
679 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
680 int *clk_div, int *clk_double,
681 bool use_portd_hvsync)
683 struct sunxi_lcdc_reg * const lcdc =
684 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
685 struct sunxi_ccm_reg * const ccm =
686 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
687 struct display_timing timing;
689 sunxi_ctfb_mode_to_display_timing(mode, &timing);
690 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
691 sunxi_is_composite());
693 if (use_portd_hvsync) {
694 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
695 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
698 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
699 sunxi_is_composite());
701 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
703 #ifdef CONFIG_VIDEO_HDMI
705 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
707 struct sunxi_hdmi_reg * const hdmi =
708 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
710 u8 avi_info_frame[17] = {
711 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
712 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715 u8 vendor_info_frame[19] = {
716 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
717 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722 if (mode->pixclock_khz <= 27000)
723 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
725 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
727 if (mode->xres * 100 / mode->yres < 156)
728 avi_info_frame[5] |= 0x18; /* 4 : 3 */
730 avi_info_frame[5] |= 0x28; /* 16 : 9 */
732 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
733 checksum += avi_info_frame[i];
735 avi_info_frame[3] = 0x100 - checksum;
737 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
738 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
740 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
741 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
743 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
744 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
746 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
747 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
749 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
752 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
753 int clk_div, int clk_double)
755 struct sunxi_hdmi_reg * const hdmi =
756 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
759 /* Write clear interrupt status bits */
760 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
762 if (sunxi_display.monitor == sunxi_monitor_hdmi)
763 sunxi_hdmi_setup_info_frames(mode);
765 /* Set input sync enable */
766 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
768 /* Init various registers, select pll3 as clock source */
769 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
770 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
771 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
772 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
773 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
775 /* Setup clk div and doubler */
776 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
777 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
779 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
781 /* Setup timing registers */
782 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
785 x = mode->hsync_len + mode->left_margin;
786 y = mode->vsync_len + mode->upper_margin;
787 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
789 x = mode->right_margin;
790 y = mode->lower_margin;
791 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
795 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
797 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
798 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
800 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
801 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
804 static void sunxi_hdmi_enable(void)
806 struct sunxi_hdmi_reg * const hdmi =
807 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
810 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
813 #endif /* CONFIG_VIDEO_HDMI */
815 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
817 static void sunxi_tvencoder_mode_set(void)
819 struct sunxi_ccm_reg * const ccm =
820 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
821 struct sunxi_tve_reg * const tve =
822 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
825 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
827 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
829 switch (sunxi_display.monitor) {
830 case sunxi_monitor_vga:
831 tvencoder_mode_set(tve, tve_mode_vga);
833 case sunxi_monitor_composite_pal_nc:
834 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
836 case sunxi_monitor_composite_pal:
837 tvencoder_mode_set(tve, tve_mode_composite_pal);
839 case sunxi_monitor_composite_pal_m:
840 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
842 case sunxi_monitor_composite_ntsc:
843 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
845 case sunxi_monitor_none:
846 case sunxi_monitor_dvi:
847 case sunxi_monitor_hdmi:
848 case sunxi_monitor_lcd:
853 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
855 static void sunxi_drc_init(void)
857 #ifdef CONFIG_SUNXI_GEN_SUN6I
858 struct sunxi_ccm_reg * const ccm =
859 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
861 /* On sun6i the drc must be clocked even when in pass-through mode */
862 #ifdef CONFIG_MACH_SUN8I_A33
863 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
865 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
866 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
870 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
871 static void sunxi_vga_external_dac_enable(void)
875 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
877 gpio_request(pin, "vga_enable");
878 gpio_direction_output(pin, 1);
881 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
883 #ifdef CONFIG_VIDEO_LCD_SSD2828
884 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
886 struct ssd2828_config cfg = {
887 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
888 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
889 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
890 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
891 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
892 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
893 .ssd2828_color_depth = 24,
894 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
895 .mipi_dsi_number_of_data_lanes = 4,
896 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
897 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
898 .mipi_dsi_delay_after_set_display_on_ms = 200
900 #error MIPI LCD panel needs configuration parameters
904 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
905 printf("SSD2828: SPI pins are not properly configured\n");
908 if (cfg.reset_pin == -1) {
909 printf("SSD2828: Reset pin is not properly configured\n");
913 return ssd2828_init(&cfg, mode);
915 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
917 static void sunxi_engines_init(void)
919 sunxi_composer_init();
924 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
925 unsigned int address)
927 int __maybe_unused clk_div, clk_double;
928 struct sunxi_lcdc_reg * const lcdc =
929 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
930 struct sunxi_tve_reg * __maybe_unused const tve =
931 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
933 switch (sunxi_display.monitor) {
934 case sunxi_monitor_none:
936 case sunxi_monitor_dvi:
937 case sunxi_monitor_hdmi:
938 #ifdef CONFIG_VIDEO_HDMI
939 sunxi_composer_mode_set(mode, address);
940 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
941 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
942 sunxi_composer_enable();
943 lcdc_enable(lcdc, sunxi_display.depth);
947 case sunxi_monitor_lcd:
948 sunxi_lcdc_panel_enable();
949 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
951 * The anx9804 needs 1.8V from eldo3, we do this here
952 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
953 * to avoid turning this on when using hdmi output.
955 axp_set_eldo(3, 1800);
956 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
957 ANX9804_DATA_RATE_1620M,
958 sunxi_display.depth);
960 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
961 mdelay(50); /* Wait for lcd controller power on */
962 hitachi_tx18d42vm_init();
964 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
965 unsigned int orig_i2c_bus = i2c_get_bus_num();
966 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
967 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
968 i2c_set_bus_num(orig_i2c_bus);
970 sunxi_composer_mode_set(mode, address);
971 sunxi_lcdc_tcon0_mode_set(mode, false);
972 sunxi_composer_enable();
973 lcdc_enable(lcdc, sunxi_display.depth);
974 #ifdef CONFIG_VIDEO_LCD_SSD2828
975 sunxi_ssd2828_init(mode);
977 sunxi_lcdc_backlight_enable();
979 case sunxi_monitor_vga:
980 #ifdef CONFIG_VIDEO_VGA
981 sunxi_composer_mode_set(mode, address);
982 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
983 sunxi_tvencoder_mode_set();
984 sunxi_composer_enable();
985 lcdc_enable(lcdc, sunxi_display.depth);
986 tvencoder_enable(tve);
987 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
988 sunxi_composer_mode_set(mode, address);
989 sunxi_lcdc_tcon0_mode_set(mode, true);
990 sunxi_composer_enable();
991 lcdc_enable(lcdc, sunxi_display.depth);
992 sunxi_vga_external_dac_enable();
995 case sunxi_monitor_composite_pal:
996 case sunxi_monitor_composite_ntsc:
997 case sunxi_monitor_composite_pal_m:
998 case sunxi_monitor_composite_pal_nc:
999 #ifdef CONFIG_VIDEO_COMPOSITE
1000 sunxi_composer_mode_set(mode, address);
1001 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1002 sunxi_tvencoder_mode_set();
1003 sunxi_composer_enable();
1004 lcdc_enable(lcdc, sunxi_display.depth);
1005 tvencoder_enable(tve);
1011 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1014 case sunxi_monitor_none: return "none";
1015 case sunxi_monitor_dvi: return "dvi";
1016 case sunxi_monitor_hdmi: return "hdmi";
1017 case sunxi_monitor_lcd: return "lcd";
1018 case sunxi_monitor_vga: return "vga";
1019 case sunxi_monitor_composite_pal: return "composite-pal";
1020 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1021 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1022 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
1024 return NULL; /* never reached */
1027 ulong board_get_usable_ram_top(ulong total_size)
1029 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1032 static bool sunxi_has_hdmi(void)
1034 #ifdef CONFIG_VIDEO_HDMI
1041 static bool sunxi_has_lcd(void)
1043 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1045 return lcd_mode[0] != 0;
1048 static bool sunxi_has_vga(void)
1050 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1057 static bool sunxi_has_composite(void)
1059 #ifdef CONFIG_VIDEO_COMPOSITE
1066 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1068 if (allow_hdmi && sunxi_has_hdmi())
1069 return sunxi_monitor_dvi;
1070 else if (sunxi_has_lcd())
1071 return sunxi_monitor_lcd;
1072 else if (sunxi_has_vga())
1073 return sunxi_monitor_vga;
1074 else if (sunxi_has_composite())
1075 return sunxi_monitor_composite_pal;
1077 return sunxi_monitor_none;
1080 void *video_hw_init(void)
1082 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1083 const struct ctfb_res_modes *mode;
1084 struct ctfb_res_modes custom;
1085 const char *options;
1086 #ifdef CONFIG_VIDEO_HDMI
1087 int hpd, hpd_delay, edid;
1090 int i, overscan_offset, overscan_x, overscan_y;
1091 unsigned int fb_dma_addr;
1093 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1095 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1097 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1098 &sunxi_display.depth, &options);
1099 #ifdef CONFIG_VIDEO_HDMI
1100 hpd = video_get_option_int(options, "hpd", 1);
1101 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1102 edid = video_get_option_int(options, "edid", 1);
1104 overscan_x = video_get_option_int(options, "overscan_x", -1);
1105 overscan_y = video_get_option_int(options, "overscan_y", -1);
1106 sunxi_display.monitor = sunxi_get_default_mon(true);
1107 video_get_option_string(options, "monitor", mon, sizeof(mon),
1108 sunxi_get_mon_desc(sunxi_display.monitor));
1109 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1110 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1111 sunxi_display.monitor = i;
1115 if (i > SUNXI_MONITOR_LAST)
1116 printf("Unknown monitor: '%s', falling back to '%s'\n",
1117 mon, sunxi_get_mon_desc(sunxi_display.monitor));
1119 #ifdef CONFIG_VIDEO_HDMI
1120 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1121 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1122 sunxi_display.monitor == sunxi_monitor_hdmi) {
1123 /* Always call hdp_detect, as it also enables clocks, etc. */
1124 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1125 if (hdmi_present && edid) {
1126 printf("HDMI connected: ");
1127 if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
1130 hdmi_present = false;
1132 /* Fall back to EDID in case HPD failed */
1133 if (edid && !hdmi_present) {
1134 if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1136 hdmi_present = true;
1139 /* Shut down when display was not found */
1140 if ((hpd || edid) && !hdmi_present) {
1141 sunxi_hdmi_shutdown();
1142 sunxi_display.monitor = sunxi_get_default_mon(false);
1143 } /* else continue with hdmi/dvi without a cable connected */
1147 switch (sunxi_display.monitor) {
1148 case sunxi_monitor_none:
1150 case sunxi_monitor_dvi:
1151 case sunxi_monitor_hdmi:
1152 if (!sunxi_has_hdmi()) {
1153 printf("HDMI/DVI not supported on this board\n");
1154 sunxi_display.monitor = sunxi_monitor_none;
1158 case sunxi_monitor_lcd:
1159 if (!sunxi_has_lcd()) {
1160 printf("LCD not supported on this board\n");
1161 sunxi_display.monitor = sunxi_monitor_none;
1164 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1167 case sunxi_monitor_vga:
1168 if (!sunxi_has_vga()) {
1169 printf("VGA not supported on this board\n");
1170 sunxi_display.monitor = sunxi_monitor_none;
1173 sunxi_display.depth = 18;
1175 case sunxi_monitor_composite_pal:
1176 case sunxi_monitor_composite_ntsc:
1177 case sunxi_monitor_composite_pal_m:
1178 case sunxi_monitor_composite_pal_nc:
1179 if (!sunxi_has_composite()) {
1180 printf("Composite video not supported on this board\n");
1181 sunxi_display.monitor = sunxi_monitor_none;
1184 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1185 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1186 mode = &composite_video_modes[0];
1188 mode = &composite_video_modes[1];
1189 sunxi_display.depth = 24;
1193 /* Yes these defaults are quite high, overscan on composite sucks... */
1194 if (overscan_x == -1)
1195 overscan_x = sunxi_is_composite() ? 32 : 0;
1196 if (overscan_y == -1)
1197 overscan_y = sunxi_is_composite() ? 20 : 0;
1199 sunxi_display.fb_size =
1200 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1201 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1202 /* We want to keep the fb_base for simplefb page aligned, where as
1203 * the sunxi dma engines will happily accept an unaligned address. */
1204 if (overscan_offset)
1205 sunxi_display.fb_size += 0x1000;
1207 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1208 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1209 sunxi_display.fb_size >> 10,
1210 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1214 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1215 mode->xres, mode->yres,
1216 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1217 sunxi_get_mon_desc(sunxi_display.monitor),
1218 overscan_x, overscan_y);
1220 gd->fb_base = gd->bd->bi_dram[0].start +
1221 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1222 sunxi_engines_init();
1224 #ifdef CONFIG_EFI_LOADER
1225 efi_add_memory_map(gd->fb_base,
1226 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1228 EFI_RESERVED_MEMORY_TYPE, false);
1231 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1232 sunxi_display.fb_addr = gd->fb_base;
1233 if (overscan_offset) {
1234 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1235 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1236 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1237 flush_cache(gd->fb_base, sunxi_display.fb_size);
1239 sunxi_mode_set(mode, fb_dma_addr);
1242 * These are the only members of this structure that are used. All the
1243 * others are driver specific. The pitch is stored in plnSizeX.
1245 graphic_device->frameAdrs = sunxi_display.fb_addr;
1246 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1247 graphic_device->gdfBytesPP = 4;
1248 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1249 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1250 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1252 return graphic_device;
1258 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1259 int sunxi_simplefb_setup(void *blob)
1261 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1264 const char *pipeline = NULL;
1266 #ifdef CONFIG_MACH_SUN4I
1267 #define PIPELINE_PREFIX "de_fe0-"
1269 #define PIPELINE_PREFIX
1272 switch (sunxi_display.monitor) {
1273 case sunxi_monitor_none:
1275 case sunxi_monitor_dvi:
1276 case sunxi_monitor_hdmi:
1277 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1279 case sunxi_monitor_lcd:
1280 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1282 case sunxi_monitor_vga:
1283 #ifdef CONFIG_VIDEO_VGA
1284 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1285 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1286 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1289 case sunxi_monitor_composite_pal:
1290 case sunxi_monitor_composite_ntsc:
1291 case sunxi_monitor_composite_pal_m:
1292 case sunxi_monitor_composite_pal_nc:
1293 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1297 offset = sunxi_simplefb_fdt_match(blob, pipeline);
1299 eprintf("Cannot setup simplefb: node not found\n");
1300 return 0; /* Keep older kernels working */
1304 * Do not report the framebuffer as free RAM to the OS, note we cannot
1305 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1306 * and e.g. Linux refuses to iomap RAM on ARM, see:
1307 * linux/arch/arm/mm/ioremap.c around line 301.
1309 start = gd->bd->bi_dram[0].start;
1310 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1311 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1313 eprintf("Cannot setup simplefb: Error reserving memory\n");
1317 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1318 graphic_device->winSizeX, graphic_device->winSizeY,
1319 graphic_device->plnSizeX, "x8r8g8b8");
1321 eprintf("Cannot setup simplefb: Error setting properties\n");
1325 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */