+
+ setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
+#ifdef CONFIG_SUNXI_GEN_SUN6I
+ udelay(2); /* delay at least 1200 ns */
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
+ udelay(2); /* delay at least 1200 ns */
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
+ if (sunxi_display.depth == 18)
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
+ else
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
+#else
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
+ udelay(2); /* delay at least 1200 ns */
+ setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
+ udelay(1); /* delay at least 120 ns */
+ setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
+#endif
+#endif
+}
+
+static void sunxi_lcdc_panel_enable(void)
+{
+ int pin, reset_pin;
+
+ /*
+ * Start with backlight disabled to avoid the screen flashing to
+ * white while the lcd inits.
+ */
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
+ if (pin >= 0) {
+ gpio_request(pin, "lcd_backlight_enable");
+ gpio_direction_output(pin, 0);
+ }
+
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
+ if (pin >= 0) {
+ gpio_request(pin, "lcd_backlight_pwm");
+ gpio_direction_output(pin, PWM_OFF);
+ }
+
+ reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
+ if (reset_pin >= 0) {
+ gpio_request(reset_pin, "lcd_reset");
+ gpio_direction_output(reset_pin, 0); /* Assert reset */
+ }
+
+ /* Give the backlight some time to turn off and power up the panel. */
+ mdelay(40);
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
+ if (pin >= 0) {
+ gpio_request(pin, "lcd_power");
+ gpio_direction_output(pin, 1);
+ }
+
+ if (reset_pin >= 0)
+ gpio_direction_output(reset_pin, 1); /* De-assert reset */
+}
+
+static void sunxi_lcdc_backlight_enable(void)
+{
+ int pin;
+
+ /*
+ * We want to have scanned out at least one frame before enabling the
+ * backlight to avoid the screen flashing to white when we enable it.
+ */
+ mdelay(40);
+
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
+ if (pin >= 0)
+ gpio_direction_output(pin, 1);
+
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
+ if (pin >= 0)
+ gpio_direction_output(pin, PWM_ON);
+}
+
+static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
+{
+ int delay;
+
+ delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
+ return (delay > 30) ? 30 : delay;
+}
+
+static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
+ bool for_ext_vga_dac)
+{
+ struct sunxi_lcdc_reg * const lcdc =
+ (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+ int bp, clk_delay, clk_div, clk_double, pin, total, val;
+
+ for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
+#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
+ sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
+#endif
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
+#endif
+
+ sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
+
+ /* Use tcon0 */
+ clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
+ SUNXI_LCDC_CTRL_IO_MAP_TCON0);
+
+ clk_delay = sunxi_lcdc_get_clk_delay(mode);
+ writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
+ SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
+
+ writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
+ SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
+
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ &lcdc->tcon0_timing_active);
+
+ bp = mode->hsync_len + mode->left_margin;
+ total = mode->xres + mode->right_margin + bp;
+ writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
+ SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
+
+ bp = mode->vsync_len + mode->upper_margin;
+ total = mode->yres + mode->lower_margin + bp;
+ writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
+ SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
+
+#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
+ writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
+ &lcdc->tcon0_timing_sync);
+
+ writel(0, &lcdc->tcon0_hv_intf);
+ writel(0, &lcdc->tcon0_cpu_intf);
+#endif
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ val = (sunxi_display.depth == 18) ? 1 : 0;
+ writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
+ SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
+#endif
+
+ if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
+ writel(((sunxi_display.depth == 18) ?
+ SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
+ SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
+ &lcdc->tcon0_frm_ctrl);
+ }
+
+ val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
+ if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
+ val |= SUNXI_LCDC_TCON_HSYNC_MASK;
+ if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
+ val |= SUNXI_LCDC_TCON_VSYNC_MASK;
+
+#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
+ if (for_ext_vga_dac)
+ val = 0;
+#endif
+ writel(val, &lcdc->tcon0_io_polarity);
+
+ writel(0, &lcdc->tcon0_io_tristate);
+}
+
+#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
+static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
+ int *clk_div, int *clk_double,
+ bool use_portd_hvsync)
+{
+ struct sunxi_lcdc_reg * const lcdc =
+ (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+ int bp, clk_delay, total, val;