sunxi: display: add simplefb support for V3s SoC

V3s SoC features a DE2 composer.

Add support for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
This commit is contained in:
Icenowy Zheng
2017-01-20 01:21:02 +08:00
parent cd3e906236
commit 88cbcae366
9 changed files with 303 additions and 21 deletions
@@ -449,9 +449,13 @@ struct sunxi_ccm_reg {
/* CCM bits common to all Display Engine 2.0 clock ctrl regs */
#define CCM_DE2_CTRL_M(n) ((((n) - 1) & 0xf) << 0)
#define CCM_DE2_CTRL_PLL_MASK (3 << 24)
#ifndef CONFIG_MACH_SUN8I_V3S
#define CCM_DE2_CTRL_PLL6_2X (0 << 24)
#define CCM_DE2_CTRL_PLL10 (1 << 24)
#define CCM_DE2_CTRL_PLL3 (1 << 24) /* for V3s */
#else
#define CCM_DE2_CTRL_PLL3 (0 << 24) /* for V3s */
#define CCM_DE2_CTRL_PLL6_2X (2 << 24)
#endif
#define CCM_DE2_CTRL_GATE (1 << 31)
/* CCU security switch, H3 only */
@@ -470,6 +474,7 @@ void clock_set_mipi_pll(unsigned int hz);
unsigned int clock_get_pll3(void);
unsigned int clock_get_pll6(void);
unsigned int clock_get_mipi_pll(void);
void clock_set_de2_mod_clock(u32 *clk_cfg, unsigned int hz);
#endif
#endif /* _SUNXI_CLOCK_SUN6I_H */
@@ -18,6 +18,8 @@
#define SUNXI_SRAM_D_BASE 0x00010000 /* 4 kiB */
#define SUNXI_SRAM_B_BASE 0x00020000 /* 64 kiB (secure) */
#define SUNXI_DE2_BASE 0x01000000
#ifdef CONFIG_MACH_SUN8I_A83T
#define SUNXI_CPUCFG_BASE 0x01700000
#endif
+119
View File
@@ -157,6 +157,89 @@ struct sunxi_de_be_reg {
u32 output_color_coef[12]; /* 0x9d0 */
};
/*
* The following structures are for DE2.
* DE2 is a new generation of "composer" in some new Allwinner SoCs, such as
* A83T, H3, V3s, A64.
*/
/* internal clock settings */
struct de_clk {
u32 gate_cfg;
u32 bus_cfg;
u32 rst_cfg;
u32 div_cfg;
u32 sel_cfg;
};
/* global control */
struct de_glb {
u32 ctl;
u32 status;
u32 dbuff;
u32 size;
};
/* alpha blending */
struct de_bld {
u32 fcolor_ctl; /* 00 */
struct {
u32 fcolor;
u32 insize;
u32 offset;
u32 dum;
} attr[4];
u32 dum0[15]; /* (end of clear offset) */
u32 route; /* 80 */
u32 premultiply;
u32 bkcolor;
u32 output_size;
u32 bld_mode[4];
u32 dum1[4];
u32 ck_ctl; /* b0 */
u32 ck_cfg;
u32 dum2[2];
u32 ck_max[4]; /* c0 */
u32 dum3[4];
u32 ck_min[4]; /* e0 */
u32 dum4[3];
u32 out_ctl; /* fc */
};
/* VI channel */
struct de_vi {
struct {
u32 attr;
u32 size;
u32 coord;
u32 pitch[3];
u32 top_laddr[3];
u32 bot_laddr[3];
} cfg[4];
u32 fcolor[4]; /* c0 */
u32 top_haddr[3]; /* d0 */
u32 bot_haddr[3]; /* dc */
u32 ovl_size[2]; /* e8 */
u32 hori[2]; /* f0 */
u32 vert[2]; /* f8 */
};
struct de_ui {
struct {
u32 attr;
u32 size;
u32 coord;
u32 pitch;
u32 top_laddr;
u32 bot_laddr;
u32 fcolor;
u32 dum;
} cfg[4]; /* 00 */
u32 top_haddr; /* 80 */
u32 bot_haddr;
u32 ovl_size; /* 88 */
};
struct sunxi_lcdc_reg {
u32 ctrl; /* 0x00 */
u32 int0; /* 0x04 */
@@ -346,6 +429,42 @@ struct sunxi_tve_reg {
#define SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888 (0x09 << 8)
#define SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE 1
/*
* DE2 register constants.
*/
#define SUNXI_DE2_MUX0_BASE (u8 *)(SUNXI_DE2_BASE + 0x100000)
#define SUNXI_DE2_MUX_GLB_REGS 0x00000
#define SUNXI_DE2_MUX_BLD_REGS 0x01000
#define SUNXI_DE2_MUX_CHAN_REGS 0x02000
#define SUNXI_DE2_MUX_CHAN_SZ 0x1000
#define SUNXI_DE2_MUX_VSU_REGS 0x20000
#define SUNXI_DE2_MUX_GSU1_REGS 0x30000
#define SUNXI_DE2_MUX_GSU2_REGS 0x40000
#define SUNXI_DE2_MUX_GSU3_REGS 0x50000
#define SUNXI_DE2_MUX_FCE_REGS 0xa0000
#define SUNXI_DE2_MUX_BWS_REGS 0xa2000
#define SUNXI_DE2_MUX_LTI_REGS 0xa4000
#define SUNXI_DE2_MUX_PEAK_REGS 0xa6000
#define SUNXI_DE2_MUX_ASE_REGS 0xa8000
#define SUNXI_DE2_MUX_FCC_REGS 0xaa000
#define SUNXI_DE2_MUX_DCSC_REGS 0xb0000
#define SUNXI_DE2_FORMAT_ARGB_8888 0
#define SUNXI_DE2_FORMAT_BGRA_8888 3
#define SUNXI_DE2_FORMAT_XRGB_8888 4
#define SUNXI_DE2_FORMAT_RGB_888 8
#define SUNXI_DE2_FORMAT_BGR_888 9
#define SUNXI_DE2_MUX_GLB_CTL_RT_EN (1 << 0)
#define SUNXI_DE2_UI_CFG_ATTR_EN (1 << 0)
#define SUNXI_DE2_UI_CFG_ATTR_ALPMOD(m) ((m & 3) << 1)
#define SUNXI_DE2_UI_CFG_ATTR_FMT(f) ((f & 0xf) << 8)
#define SUNXI_DE2_UI_CFG_ATTR_ALPHA(a) ((a & 0xff) << 24)
#define SUNXI_DE2_WH(w, h) (((h - 1) << 16) | (w - 1))
/*
* LCDC register constants.
*/
+2
View File
@@ -151,6 +151,7 @@ enum sunxi_gpio_number {
#define SUN8I_H3_GPA_UART0 2
#define SUN4I_GPB_PWM 2
#define SUN8I_V3S_GPB_PWM 2
#define SUN4I_GPB_TWI0 2
#define SUN4I_GPB_TWI1 2
#define SUN5I_GPB_TWI1 2
@@ -176,6 +177,7 @@ enum sunxi_gpio_number {
#define SUN5I_GPE_SDC2 3
#define SUN8I_GPE_TWI2 3
#define SUN8I_V3S_GPE_LCD 3
#define SUNXI_GPF_SDC0 2
#define SUNXI_GPF_UART0 4
+5
View File
@@ -31,4 +31,9 @@
#define SUNXI_PWM_MUX SUN8I_GPH_PWM
#endif
#if defined CONFIG_MACH_SUN8I_V3S
#define SUNXI_PWM_PIN0 SUNXI_GPB(4)
#define SUNXI_PWM_MUX SUN8I_V3S_GPB_PWM
#endif
#endif
+12
View File
@@ -317,3 +317,15 @@ void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz)
writel(CCM_DE_CTRL_GATE | CCM_DE_CTRL_PLL6_2X | CCM_DE_CTRL_M(div),
clk_cfg);
}
void clock_set_de2_mod_clock(u32 *clk_cfg, unsigned int hz)
{
int pll = clock_get_pll6() * 2;
int div = 1;
while ((pll / div) > hz)
div++;
writel(CCM_DE2_CTRL_GATE | CCM_DE2_CTRL_PLL6_2X | CCM_DE2_CTRL_M(div),
clk_cfg);
}
+1
View File
@@ -136,6 +136,7 @@ config MACH_SUN8I_V3S
select SUPPORT_SPL
select SUNXI_H3_DW_DRAM
select SUNXI_H3_DRAM_DDR2
select SUNXI_DE2
select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN9I
+1
View File
@@ -352,6 +352,7 @@ static const struct udevice_id sunxi_gpio_ids[] = {
ID("allwinner,sun8i-a33-pinctrl", a_all),
ID("allwinner,sun8i-a83t-pinctrl", a_all),
ID("allwinner,sun8i-h3-pinctrl", a_all),
ID("allwinner,sun8i-v3s-pinctrl", a_all),
ID("allwinner,sun9i-a80-pinctrl", a_all),
ID("allwinner,sun6i-a31-r-pinctrl", l_2),
ID("allwinner,sun8i-a23-r-pinctrl", l_1),
+155 -20
View File
@@ -1,3 +1,5 @@
#define DEBUG
/*
* Display driver for Allwinner SoCs.
*
@@ -297,6 +299,26 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
#endif /* CONFIG_VIDEO_HDMI */
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 */
}
#ifndef CONFIG_SUNXI_DE2
#ifdef CONFIG_MACH_SUN4I
/*
* Testing has shown that on sun4i the display backend engine does not have
@@ -405,25 +427,6 @@ static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
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 */
}
/*
* This is the entity that mixes and matches the different layers and inputs.
* Allwinner calls it the back-end, but i like composer better.
@@ -512,6 +515,127 @@ static void sunxi_composer_enable(void)
setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
}
#else /* CONFIG_SUNXI_DE2 */
/*
* This is the entity that mixes and matches the different layers and inputs.
* Allwinner calls it display engine (DE 2.0), but here is called composer.
*/
static void sunxi_composer_init(void)
{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
#ifndef CONFIG_MACH_SUN8I_V3S
clock_set_pll10(432000000);
/* Set DE parent to pll10 */
clrsetbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_PLL_MASK,
CCM_DE2_CTRL_PLL10);
#else
clock_set_de2_mod_clock(&ccm->de_clk_cfg, 300000000);
#endif
/* Set ahb gating to pass */
setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE);
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE);
/* Clock on */
setbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_GATE);
}
static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
unsigned int address)
{
struct de_clk * const de_clk_regs =
(struct de_clk *)(SUNXI_DE2_BASE);
struct de_glb * const de_glb_regs =
(struct de_glb *)(SUNXI_DE2_MUX0_BASE +
SUNXI_DE2_MUX_GLB_REGS);
struct de_bld * const de_bld_regs =
(struct de_bld *)(SUNXI_DE2_MUX0_BASE +
SUNXI_DE2_MUX_BLD_REGS);
struct de_ui * const de_ui_regs =
(struct de_ui *)(SUNXI_DE2_MUX0_BASE +
SUNXI_DE2_MUX_CHAN_REGS +
SUNXI_DE2_MUX_CHAN_SZ * 2);
u32 size = SUNXI_DE2_WH(mode->xres, mode->yres);
int channel, i;
u32 data;
/* enable clock */
setbits_le32(&de_clk_regs->rst_cfg, 1);
setbits_le32(&de_clk_regs->gate_cfg, 1);
setbits_le32(&de_clk_regs->bus_cfg, 1);
clrbits_le32(&de_clk_regs->sel_cfg, 1);
writel(SUNXI_DE2_MUX_GLB_CTL_RT_EN, &de_glb_regs->ctl);
writel(0, &de_glb_regs->status);
writel(1, &de_glb_regs->dbuff);
writel(size, &de_glb_regs->size);
for (channel = 0; channel < 4; channel++) {
void *chan = SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_CHAN_REGS +
SUNXI_DE2_MUX_CHAN_SZ * channel;
memset(chan, 0, channel == 0 ?
sizeof(struct de_vi) : sizeof(struct de_ui));
}
memset(de_bld_regs, 0, sizeof(struct de_bld));
writel(0x00000101, &de_bld_regs->fcolor_ctl);
writel(2, &de_bld_regs->route);
writel(0, &de_bld_regs->premultiply);
writel(0xff000000, &de_bld_regs->bkcolor);
writel(0x03010301, &de_bld_regs->bld_mode[0]);
writel(0x03010301, &de_bld_regs->bld_mode[1]);
writel(size, &de_bld_regs->output_size);
writel(mode->vmode & FB_VMODE_INTERLACED ? 2 : 0,
&de_bld_regs->out_ctl);
writel(0, &de_bld_regs->ck_ctl);
for (i = 0; i < 4; i++) {
writel(0xff000000, &de_bld_regs->attr[i].fcolor);
writel(size, &de_bld_regs->attr[i].insize);
}
/* Disable all other units */
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_VSU_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_GSU1_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_GSU2_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_GSU3_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_FCE_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_BWS_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_LTI_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_PEAK_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_ASE_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_FCC_REGS);
writel(0, SUNXI_DE2_MUX0_BASE + SUNXI_DE2_MUX_DCSC_REGS);
data = SUNXI_DE2_UI_CFG_ATTR_EN |
SUNXI_DE2_UI_CFG_ATTR_FMT(SUNXI_DE2_FORMAT_XRGB_8888) |
SUNXI_DE2_UI_CFG_ATTR_ALPMOD(1) |
SUNXI_DE2_UI_CFG_ATTR_ALPHA(0xff);
writel(data, &de_ui_regs->cfg[0].attr);
writel(size, &de_ui_regs->cfg[0].size);
writel(0, &de_ui_regs->cfg[0].coord);
writel(4 * mode->xres, &de_ui_regs->cfg[0].pitch);
writel(address, &de_ui_regs->cfg[0].top_laddr);
writel(size, &de_ui_regs->ovl_size);
}
static void sunxi_composer_enable(void)
{
struct de_glb * const de_glb_regs =
(struct de_glb *)(SUNXI_DE2_MUX0_BASE +
SUNXI_DE2_MUX_GLB_REGS);
writel(1, &de_glb_regs->dbuff);
}
#endif /* CONFIG_SUNXI_DE2 */
/*
* LCDC, what allwinner calls a CRTC, so timing controller and serializer.
@@ -562,6 +686,8 @@ static void sunxi_lcdc_pll_set(int tcon, int dotclock,
if (!(m & 1))
continue;
/* TCONs with DE2 do not support double clock */
#ifndef CONFIG_SUNXI_DE2
n = (m * dotclock) / 6000;
if ((n >= 9) && (n <= 127)) {
value = (6000 * n) / m;
@@ -573,6 +699,7 @@ static void sunxi_lcdc_pll_set(int tcon, int dotclock,
best_double = 1;
}
}
#endif
}
#ifdef CONFIG_MACH_SUN6I
@@ -778,6 +905,7 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
int bp, clk_delay, clk_div, clk_double, pin, total, val;
#ifndef CONFIG_MACH_SUN8I_V3S
#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
#else
@@ -793,6 +921,13 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
sunxi_gpio_set_drv(pin, 3);
#endif
}
#else /* CONFIG_MACH_SUN8I_V3S */
for (pin = SUNXI_GPE(0); pin <= SUNXI_GPE(24); pin++) {
if (pin >= SUNXI_GPE(20) && pin <= SUNXI_GPE(22))
continue; /* These pins are not LCD */
sunxi_gpio_set_cfgpin(pin, SUN8I_V3S_GPE_LCD);
}
#endif /* !CONFIG_MACH_SUN8I_V3S */
sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
@@ -1141,7 +1276,7 @@ static void sunxi_tvencoder_enable(void)
static void sunxi_drc_init(void)
{
#ifdef CONFIG_SUNXI_GEN_SUN6I
#if defined CONFIG_SUNXI_GEN_SUN6I && !defined CONFIG_SUNXI_DE2
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;