+#ifdef CONFIG_MACH_SUN4I
+/*
+ * Testing has shown that on sun4i the display backend engine does not have
+ * deep enough fifo-s causing flickering / tearing in full-hd mode due to
+ * fifo underruns. So on sun4i we use the display frontend engine to do the
+ * dma from memory, as the frontend does have deep enough fifo-s.
+ */
+
+static const u32 sun4i_vert_coef[32] = {
+ 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+ 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+ 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+ 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+ 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+ 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+ 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+ 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+};
+
+static const u32 sun4i_horz_coef[64] = {
+ 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
+ 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
+ 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
+ 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
+ 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
+ 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
+ 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
+ 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
+ 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
+ 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
+ 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
+ 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
+ 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
+ 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
+ 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
+ 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
+};
+
+static void sunxi_frontend_init(void)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_de_fe_reg * const de_fe =
+ (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
+ int i;
+
+ /* Clocks on */
+ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
+ setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
+ clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
+
+ setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
+
+ for (i = 0; i < 32; i++) {
+ writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
+ writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
+ writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
+ writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
+ writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
+ writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
+ }
+
+ setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
+}
+
+static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
+ unsigned int address)
+{
+ struct sunxi_de_fe_reg * const de_fe =
+ (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
+
+ setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
+ writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
+ writel(mode->xres * 4, &de_fe->ch0_stride);
+ writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
+ writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
+
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch0_insize);
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch0_outsize);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
+
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch1_insize);
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch1_outsize);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
+
+ setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
+}
+
+static void sunxi_frontend_enable(void)
+{
+ struct sunxi_de_fe_reg * const de_fe =
+ (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
+
+ setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
+}
+#else
+static void sunxi_frontend_init(void) {}
+static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
+ unsigned int address) {}
+static void sunxi_frontend_enable(void) {}
+#endif
+
+static bool sunxi_is_composite(void)
+{
+ switch (sunxi_display.monitor) {
+ case sunxi_monitor_none:
+ case sunxi_monitor_dvi:
+ case sunxi_monitor_hdmi:
+ case sunxi_monitor_lcd:
+ case sunxi_monitor_vga:
+ return false;
+ case sunxi_monitor_composite_pal:
+ case sunxi_monitor_composite_ntsc:
+ case sunxi_monitor_composite_pal_m:
+ case sunxi_monitor_composite_pal_nc:
+ return true;
+ }
+
+ return false; /* Never reached */
+}
+