diff options
Diffstat (limited to 'drivers')
30 files changed, 1915 insertions, 447 deletions
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 1091a76f05..e404c0cdb9 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,4 +8,6 @@ obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o obj-$(CONFIG_ROCKCHIP_RK3188) += clk_rk3188.o obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o +obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o +obj-$(CONFIG_ROCKCHIP_RV1108) += clk_rv1108.o diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c index 0bee5db69b..28652df72d 100644 --- a/drivers/clk/rockchip/clk_rk3036.c +++ b/drivers/clk/rockchip/clk_rk3036.c @@ -65,12 +65,11 @@ static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id, rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); rk_clrsetreg(&pll->con0, - PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | PLL_FBDIV_MASK, + PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv); - rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT | - PLL_REFDIV_MASK << PLL_REFDIV_SHIFT, - (div->postdiv2 << PLL_POSTDIV2_SHIFT | - div->refdiv << PLL_REFDIV_SHIFT)); + rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, + (div->postdiv2 << PLL_POSTDIV2_SHIFT | + div->refdiv << PLL_REFDIV_SHIFT)); /* waiting for pll lock */ while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) @@ -87,8 +86,7 @@ static void rkclk_init(struct rk3036_cru *cru) /* pll enter slow-mode */ rk_clrsetreg(&cru->cru_mode_con, - GPLL_MODE_MASK << GPLL_MODE_SHIFT | - APLL_MODE_MASK << APLL_MODE_SHIFT, + GPLL_MODE_MASK | APLL_MODE_MASK, GPLL_MODE_SLOW << GPLL_MODE_SHIFT | APLL_MODE_SLOW << APLL_MODE_SHIFT); @@ -97,8 +95,8 @@ static void rkclk_init(struct rk3036_cru *cru) rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); /* - * select apll as core clock pll source and - * set up dependent divisors for PCLK/HCLK and ACLK clocks. + * select apll as cpu/core clock pll source and + * set up dependent divisors for PERI and ACLK clocks. * core hz : apll = 1:1 */ aclk_div = APLL_HZ / CORE_ACLK_HZ - 1; @@ -108,44 +106,40 @@ static void rkclk_init(struct rk3036_cru *cru) assert((pclk_div + 1) * CORE_PERI_HZ == APLL_HZ && pclk_div < 0xf); rk_clrsetreg(&cru->cru_clksel_con[0], - CORE_CLK_PLL_SEL_MASK << CORE_CLK_PLL_SEL_SHIFT | - CORE_DIV_CON_MASK << CORE_DIV_CON_SHIFT, + CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK, CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 0 << CORE_DIV_CON_SHIFT); rk_clrsetreg(&cru->cru_clksel_con[1], - CORE_ACLK_DIV_MASK << CORE_ACLK_DIV_SHIFT | - CORE_PERI_DIV_MASK << CORE_PERI_DIV_SHIFT, + CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK, aclk_div << CORE_ACLK_DIV_SHIFT | pclk_div << CORE_PERI_DIV_SHIFT); /* - * select apll as cpu clock pll source and + * select apll as pd_bus bus clock source and * set up dependent divisors for PCLK/HCLK and ACLK clocks. */ - aclk_div = APLL_HZ / CPU_ACLK_HZ - 1; - assert((aclk_div + 1) * CPU_ACLK_HZ == APLL_HZ && aclk_div < 0x1f); + aclk_div = GPLL_HZ / BUS_ACLK_HZ - 1; + assert((aclk_div + 1) * BUS_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f); - pclk_div = APLL_HZ / CPU_PCLK_HZ - 1; - assert((pclk_div + 1) * CPU_PCLK_HZ == APLL_HZ && pclk_div < 0x7); + pclk_div = GPLL_HZ / BUS_PCLK_HZ - 1; + assert((pclk_div + 1) * BUS_PCLK_HZ == GPLL_HZ && pclk_div <= 0x7); - hclk_div = APLL_HZ / CPU_HCLK_HZ - 1; - assert((hclk_div + 1) * CPU_HCLK_HZ == APLL_HZ && hclk_div < 0x3); + hclk_div = GPLL_HZ / BUS_HCLK_HZ - 1; + assert((hclk_div + 1) * BUS_HCLK_HZ == GPLL_HZ && hclk_div <= 0x3); rk_clrsetreg(&cru->cru_clksel_con[0], - CPU_CLK_PLL_SEL_MASK << CPU_CLK_PLL_SEL_SHIFT | - ACLK_CPU_DIV_MASK << ACLK_CPU_DIV_SHIFT, - CPU_CLK_PLL_SEL_APLL << CPU_CLK_PLL_SEL_SHIFT | - aclk_div << ACLK_CPU_DIV_SHIFT); + BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, + BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT | + aclk_div << BUS_ACLK_DIV_SHIFT); rk_clrsetreg(&cru->cru_clksel_con[1], - CPU_PCLK_DIV_MASK << CPU_PCLK_DIV_SHIFT | - CPU_HCLK_DIV_MASK << CPU_HCLK_DIV_SHIFT, - pclk_div << CPU_PCLK_DIV_SHIFT | - hclk_div << CPU_HCLK_DIV_SHIFT); + BUS_PCLK_DIV_MASK | BUS_HCLK_DIV_MASK, + pclk_div << BUS_PCLK_DIV_SHIFT | + hclk_div << BUS_HCLK_DIV_SHIFT); /* - * select gpll as peri clock pll source and + * select gpll as pd_peri bus clock source and * set up dependent divisors for PCLK/HCLK and ACLK clocks. */ aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; @@ -153,17 +147,15 @@ static void rkclk_init(struct rk3036_cru *cru) hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); assert((1 << hclk_div) * PERI_HCLK_HZ == - PERI_ACLK_HZ && (pclk_div < 0x4)); + PERI_ACLK_HZ && (hclk_div < 0x4)); pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ); assert((1 << pclk_div) * PERI_PCLK_HZ == PERI_ACLK_HZ && pclk_div < 0x8); rk_clrsetreg(&cru->cru_clksel_con[10], - PERI_PLL_SEL_MASK << PERI_PLL_SEL_SHIFT | - PERI_PCLK_DIV_MASK << PERI_PCLK_DIV_SHIFT | - PERI_HCLK_DIV_MASK << PERI_HCLK_DIV_SHIFT | - PERI_ACLK_DIV_MASK << PERI_ACLK_DIV_SHIFT, + PERI_PLL_SEL_MASK | PERI_PCLK_DIV_MASK | + PERI_HCLK_DIV_MASK | PERI_ACLK_DIV_MASK, PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | pclk_div << PERI_PCLK_DIV_SHIFT | hclk_div << PERI_HCLK_DIV_SHIFT | @@ -171,8 +163,7 @@ static void rkclk_init(struct rk3036_cru *cru) /* PLL enter normal-mode */ rk_clrsetreg(&cru->cru_mode_con, - GPLL_MODE_MASK << GPLL_MODE_SHIFT | - APLL_MODE_MASK << APLL_MODE_SHIFT, + GPLL_MODE_MASK | APLL_MODE_MASK, GPLL_MODE_NORM << GPLL_MODE_SHIFT | APLL_MODE_NORM << APLL_MODE_SHIFT); } @@ -189,9 +180,9 @@ static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru, 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, 0xff, GPLL_MODE_SHIFT, 0xff }; - static u8 clk_mask[CLK_COUNT] = { - 0xff, APLL_MODE_MASK, DPLL_MODE_MASK, 0xff, - GPLL_MODE_MASK, 0xff + static u32 clk_mask[CLK_COUNT] = { + 0xffffffff, APLL_MODE_MASK, DPLL_MODE_MASK, 0xffffffff, + GPLL_MODE_MASK, 0xffffffff }; uint shift; uint mask; @@ -200,18 +191,18 @@ static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru, shift = clk_shift[clk_id]; mask = clk_mask[clk_id]; - switch ((con >> shift) & mask) { + switch ((con & mask) >> shift) { case GPLL_MODE_SLOW: return OSC_HZ; case GPLL_MODE_NORM: /* normal mode */ con = readl(&pll->con0); - postdiv1 = (con >> PLL_POSTDIV1_SHIFT) & PLL_POSTDIV1_MASK; - fbdiv = (con >> PLL_FBDIV_SHIFT) & PLL_FBDIV_MASK; + postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT; + fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT; con = readl(&pll->con1); - postdiv2 = (con >> PLL_POSTDIV2_SHIFT) & PLL_POSTDIV2_MASK; - refdiv = (con >> PLL_REFDIV_SHIFT) & PLL_REFDIV_MASK; + postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT; + refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT; return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; case GPLL_MODE_DEEP: default: @@ -230,14 +221,14 @@ static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate, case HCLK_EMMC: case SCLK_EMMC: con = readl(&cru->cru_clksel_con[12]); - mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK; - div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; + mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT; + div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; break; case HCLK_SDIO: case SCLK_SDIO: con = readl(&cru->cru_clksel_con[12]); - mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK; - div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; + mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT; + div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT; break; default: return -EINVAL; @@ -269,16 +260,14 @@ static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate, case HCLK_EMMC: case SCLK_EMMC: rk_clrsetreg(&cru->cru_clksel_con[12], - EMMC_PLL_MASK << EMMC_PLL_SHIFT | - EMMC_DIV_MASK << EMMC_DIV_SHIFT, + EMMC_PLL_MASK | EMMC_DIV_MASK, mux << EMMC_PLL_SHIFT | (src_clk_div - 1) << EMMC_DIV_SHIFT); break; case HCLK_SDIO: case SCLK_SDIO: rk_clrsetreg(&cru->cru_clksel_con[11], - MMC0_PLL_MASK << MMC0_PLL_SHIFT | - MMC0_DIV_MASK << MMC0_DIV_SHIFT, + MMC0_PLL_MASK | MMC0_DIV_MASK, mux << MMC0_PLL_SHIFT | (src_clk_div - 1) << MMC0_DIV_SHIFT); break; diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c new file mode 100644 index 0000000000..52cad38446 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3368.c @@ -0,0 +1,291 @@ +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd + * Author: Andy Yan <andy.yan@rock-chips.com> + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3368.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> +#include <dm/lists.h> +#include <dt-bindings/clock/rk3368-cru.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct pll_div { + u32 nr; + u32 nf; + u32 no; +}; + +#define OSC_HZ (24 * 1000 * 1000) +#define APLL_L_HZ (800 * 1000 * 1000) +#define APLL_B_HZ (816 * 1000 * 1000) +#define GPLL_HZ (576 * 1000 * 1000) +#define CPLL_HZ (400 * 1000 * 1000) + +#define RATE_TO_DIV(input_rate, output_rate) \ + ((input_rate) / (output_rate) - 1); + +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) + +#define PLL_DIVISORS(hz, _nr, _no) { \ + .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no}; \ + _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\ + (_nr * _no) == hz, #hz "Hz cannot be hit with PLL " \ + "divisors on line " __stringify(__LINE__)); + +static const struct pll_div apll_l_init_cfg = PLL_DIVISORS(APLL_L_HZ, 12, 2); +static const struct pll_div apll_b_init_cfg = PLL_DIVISORS(APLL_B_HZ, 1, 2); +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 2); +static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 6); + +/* Get pll rate by id */ +static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru, + enum rk3368_pll_id pll_id) +{ + uint32_t nr, no, nf; + uint32_t con; + struct rk3368_pll *pll = &cru->pll[pll_id]; + + con = readl(&pll->con3); + + switch ((con & PLL_MODE_MASK) >> PLL_MODE_SHIFT) { + case PLL_MODE_SLOW: + return OSC_HZ; + case PLL_MODE_NORMAL: + con = readl(&pll->con0); + no = ((con & PLL_OD_MASK) >> PLL_OD_SHIFT) + 1; + nr = ((con & PLL_NR_MASK) >> PLL_NR_SHIFT) + 1; + con = readl(&pll->con1); + nf = ((con & PLL_NF_MASK) >> PLL_NF_SHIFT) + 1; + + return (24 * nf / (nr * no)) * 1000000; + case PLL_MODE_DEEP_SLOW: + default: + return 32768; + } +} + +static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id, + const struct pll_div *div, bool has_bwadj) +{ + struct rk3368_pll *pll = &cru->pll[pll_id]; + /* All PLLs have same VCO and output frequency range restrictions*/ + uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000; + uint output_hz = vco_hz / div->no; + + debug("PLL at %p: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", + pll, div->nf, div->nr, div->no, vco_hz, output_hz); + + /* enter slow mode and reset pll */ + rk_clrsetreg(&pll->con3, PLL_MODE_MASK | PLL_RESET_MASK, + PLL_RESET << PLL_RESET_SHIFT); + + rk_clrsetreg(&pll->con0, PLL_NR_MASK | PLL_OD_MASK, + ((div->nr - 1) << PLL_NR_SHIFT) | + ((div->no - 1) << PLL_OD_SHIFT)); + writel((div->nf - 1) << PLL_NF_SHIFT, &pll->con1); + udelay(10); + + /* return from reset */ + rk_clrreg(&pll->con3, PLL_RESET_MASK); + + /* waiting for pll lock */ + while (!(readl(&pll->con1) & PLL_LOCK_STA)) + udelay(1); + + rk_clrsetreg(&pll->con3, PLL_MODE_MASK, + PLL_MODE_NORMAL << PLL_MODE_SHIFT); + + return 0; +} + +static void rkclk_init(struct rk3368_cru *cru) +{ + u32 apllb, aplll, dpll, cpll, gpll; + + rkclk_set_pll(cru, APLLB, &apll_b_init_cfg, false); + rkclk_set_pll(cru, APLLL, &apll_l_init_cfg, false); + rkclk_set_pll(cru, GPLL, &gpll_init_cfg, false); + rkclk_set_pll(cru, CPLL, &cpll_init_cfg, false); + + apllb = rkclk_pll_get_rate(cru, APLLB); + aplll = rkclk_pll_get_rate(cru, APLLL); + dpll = rkclk_pll_get_rate(cru, DPLL); + cpll = rkclk_pll_get_rate(cru, CPLL); + gpll = rkclk_pll_get_rate(cru, GPLL); + + debug("%s apllb(%d) apll(%d) dpll(%d) cpll(%d) gpll(%d)\n", + __func__, apllb, aplll, dpll, cpll, gpll); +} + +static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id) +{ + u32 div, con, con_id, rate; + u32 pll_rate; + + switch (clk_id) { + case SCLK_SDMMC: + con_id = 50; + break; + case SCLK_EMMC: + con_id = 51; + break; + case SCLK_SDIO0: + con_id = 48; + break; + default: + return -EINVAL; + } + + con = readl(&cru->clksel_con[con_id]); + switch ((con & MMC_PLL_SEL_MASK) >> MMC_PLL_SEL_SHIFT) { + case MMC_PLL_SEL_GPLL: + pll_rate = rkclk_pll_get_rate(cru, GPLL); + break; + case MMC_PLL_SEL_24M: + pll_rate = OSC_HZ; + break; + case MMC_PLL_SEL_CPLL: + case MMC_PLL_SEL_USBPHY_480M: + default: + return -EINVAL; + } + div = (con & MMC_CLK_DIV_MASK) >> MMC_CLK_DIV_SHIFT; + rate = DIV_TO_RATE(pll_rate, div); + + return rate >> 1; +} + +static ulong rk3368_mmc_set_clk(struct rk3368_cru *cru, + ulong clk_id, ulong rate) +{ + u32 div; + u32 con_id; + u32 gpll_rate = rkclk_pll_get_rate(cru, GPLL); + + div = RATE_TO_DIV(gpll_rate, rate << 1); + + switch (clk_id) { + case SCLK_SDMMC: + con_id = 50; + break; + case SCLK_EMMC: + con_id = 51; + break; + case SCLK_SDIO0: + con_id = 48; + break; + default: + return -EINVAL; + } + + if (div > 0x3f) { + div = RATE_TO_DIV(OSC_HZ, rate); + rk_clrsetreg(&cru->clksel_con[con_id], + MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK, + (MMC_PLL_SEL_24M << MMC_PLL_SEL_SHIFT) | + (div << MMC_CLK_DIV_SHIFT)); + } else { + rk_clrsetreg(&cru->clksel_con[con_id], + MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK, + (MMC_PLL_SEL_GPLL << MMC_PLL_SEL_SHIFT) | + div << MMC_CLK_DIV_SHIFT); + } + + return rk3368_mmc_get_clk(cru, clk_id); +} + +static ulong rk3368_clk_get_rate(struct clk *clk) +{ + struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); + ulong rate = 0; + + debug("%s id:%ld\n", __func__, clk->id); + switch (clk->id) { + case HCLK_SDMMC: + case HCLK_EMMC: + rate = rk3368_mmc_get_clk(priv->cru, clk->id); + break; + default: + return -ENOENT; + } + + return rate; +} + +static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); + ulong ret = 0; + + debug("%s id:%ld rate:%ld\n", __func__, clk->id, rate); + switch (clk->id) { + case SCLK_SDMMC: + case SCLK_EMMC: + ret = rk3368_mmc_set_clk(priv->cru, clk->id, rate); + break; + default: + return -ENOENT; + } + + return ret; +} + +static struct clk_ops rk3368_clk_ops = { + .get_rate = rk3368_clk_get_rate, + .set_rate = rk3368_clk_set_rate, +}; + +static int rk3368_clk_probe(struct udevice *dev) +{ + struct rk3368_clk_priv *priv = dev_get_priv(dev); + + rkclk_init(priv->cru); + + return 0; +} + +static int rk3368_clk_ofdata_to_platdata(struct udevice *dev) +{ + struct rk3368_clk_priv *priv = dev_get_priv(dev); + + priv->cru = (struct rk3368_cru *)devfdt_get_addr(dev); + + return 0; +} + +static int rk3368_clk_bind(struct udevice *dev) +{ + int ret; + + /* The reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(gd->dm_root, "rk3368_sysreset", "reset", &dev); + if (ret) + error("bind RK3368 reset driver failed: ret=%d\n", ret); + + return ret; +} + +static const struct udevice_id rk3368_clk_ids[] = { + { .compatible = "rockchip,rk3368-cru" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3368_cru) = { + .name = "rockchip_rk3368_cru", + .id = UCLASS_CLK, + .of_match = rk3368_clk_ids, + .priv_auto_alloc_size = sizeof(struct rk3368_cru), + .ofdata_to_platdata = rk3368_clk_ofdata_to_platdata, + .ops = &rk3368_clk_ops, + .bind = rk3368_clk_bind, + .probe = rk3368_clk_probe, +}; diff --git a/drivers/clk/rockchip/clk_rv1108.c b/drivers/clk/rockchip/clk_rv1108.c new file mode 100644 index 0000000000..0a3ba3bff9 --- /dev/null +++ b/drivers/clk/rockchip/clk_rv1108.c @@ -0,0 +1,223 @@ +/* + * (C) Copyright 2016 Rockchip Electronics Co., Ltd + * Author: Andy Yan <andy.yan@rock-chips.com> + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rv1108.h> +#include <asm/arch/hardware.h> +#include <dm/lists.h> +#include <dt-bindings/clock/rv1108-cru.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { + VCO_MAX_HZ = 2400U * 1000000, + VCO_MIN_HZ = 600 * 1000000, + OUTPUT_MAX_HZ = 2400U * 1000000, + OUTPUT_MIN_HZ = 24 * 1000000, +}; + +#define RATE_TO_DIV(input_rate, output_rate) \ + ((input_rate) / (output_rate) - 1); + +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) + +#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\ + .refdiv = _refdiv,\ + .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\ + .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\ + _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\ + OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\ + #hz "Hz cannot be hit with PLL "\ + "divisors on line " __stringify(__LINE__)); + +/* use interge mode*/ +static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1); +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1); + +static inline int rv1108_pll_id(enum rk_clk_id clk_id) +{ + int id = 0; + + switch (clk_id) { + case CLK_ARM: + case CLK_DDR: + id = clk_id - 1; + break; + case CLK_GENERAL: + id = 2; + break; + default: + printf("invalid pll id:%d\n", clk_id); + id = -1; + break; + } + + return id; +} + +static uint32_t rkclk_pll_get_rate(struct rv1108_cru *cru, + enum rk_clk_id clk_id) +{ + uint32_t refdiv, fbdiv, postdiv1, postdiv2; + uint32_t con0, con1, con3; + int pll_id = rv1108_pll_id(clk_id); + struct rv1108_pll *pll = &cru->pll[pll_id]; + uint32_t freq; + + con3 = readl(&pll->con3); + + if (con3 & WORK_MODE_MASK) { + con0 = readl(&pll->con0); + con1 = readl(&pll->con1); + fbdiv = (con0 >> FBDIV_SHIFT) & FBDIV_MASK; + postdiv1 = (con1 & POSTDIV1_MASK) >> POSTDIV1_SHIFT; + postdiv2 = (con1 & POSTDIV2_MASK) >> POSTDIV2_SHIFT; + refdiv = (con1 & REFDIV_MASK) >> REFDIV_SHIFT; + freq = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; + } else { + freq = OSC_HZ; + } + + return freq; +} + +static int rv1108_mac_set_clk(struct rv1108_cru *cru, ulong rate) +{ + uint32_t con = readl(&cru->clksel_con[24]); + ulong pll_rate; + uint8_t div; + + if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_GPLL) + pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + else + pll_rate = rkclk_pll_get_rate(cru, CLK_ARM); + + /*default set 50MHZ for gmac*/ + if (!rate) + rate = 50000000; + + div = DIV_ROUND_UP(pll_rate, rate) - 1; + if (div <= 0x1f) + rk_clrsetreg(&cru->clksel_con[24], MAC_CLK_DIV_MASK, + div << MAC_CLK_DIV_SHIFT); + else + debug("Unsupported div for gmac:%d\n", div); + + return DIV_TO_RATE(pll_rate, div); +} + +static int rv1108_sfc_set_clk(struct rv1108_cru *cru, uint rate) +{ + u32 con = readl(&cru->clksel_con[27]); + u32 pll_rate; + u32 div; + + if ((con >> SFC_PLL_SEL_SHIFT) && SFC_PLL_SEL_GPLL) + pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + else + pll_rate = rkclk_pll_get_rate(cru, CLK_DDR); + + div = DIV_ROUND_UP(pll_rate, rate) - 1; + if (div <= 0x3f) + rk_clrsetreg(&cru->clksel_con[27], SFC_CLK_DIV_MASK, + div << SFC_CLK_DIV_SHIFT); + else + debug("Unsupported sfc clk rate:%d\n", rate); + + return DIV_TO_RATE(pll_rate, div); +} + +static ulong rv1108_clk_get_rate(struct clk *clk) +{ + struct rv1108_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case 0 ... 63: + return rkclk_pll_get_rate(priv->cru, clk->id); + default: + return -ENOENT; + } +} + +static ulong rv1108_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rv1108_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate; + + switch (clk->id) { + case SCLK_MAC: + new_rate = rv1108_mac_set_clk(priv->cru, rate); + break; + case SCLK_SFC: + new_rate = rv1108_sfc_set_clk(priv->cru, rate); + break; + default: + return -ENOENT; + } + + return new_rate; +} + +static const struct clk_ops rv1108_clk_ops = { + .get_rate = rv1108_clk_get_rate, + .set_rate = rv1108_clk_set_rate, +}; + +static void rkclk_init(struct rv1108_cru *cru) +{ + unsigned int apll = rkclk_pll_get_rate(cru, CLK_ARM); + unsigned int dpll = rkclk_pll_get_rate(cru, CLK_DDR); + unsigned int gpll = rkclk_pll_get_rate(cru, CLK_GENERAL); + + rk_clrsetreg(&cru->clksel_con[0], CORE_CLK_DIV_MASK, + 0 << MAC_CLK_DIV_SHIFT); + + printf("APLL: %d DPLL:%d GPLL:%d\n", apll, dpll, gpll); +} + +static int rv1108_clk_probe(struct udevice *dev) +{ + struct rv1108_clk_priv *priv = dev_get_priv(dev); + + priv->cru = (struct rv1108_cru *)devfdt_get_addr(dev); + + rkclk_init(priv->cru); + + return 0; +} + +static int rv1108_clk_bind(struct udevice *dev) +{ + int ret; + + /* The reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(gd->dm_root, "rv1108_sysreset", "reset", &dev); + if (ret) + error("No Rv1108 reset driver: ret=%d\n", ret); + + return 0; +} + +static const struct udevice_id rv1108_clk_ids[] = { + { .compatible = "rockchip,rv1108-cru" }, + { } +}; + +U_BOOT_DRIVER(clk_rv1108) = { + .name = "clk_rv1108", + .id = UCLASS_CLK, + .of_match = rv1108_clk_ids, + .priv_auto_alloc_size = sizeof(struct rv1108_clk_priv), + .ops = &rv1108_clk_ops, + .bind = rv1108_clk_bind, + .probe = rv1108_clk_probe, +}; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ecca159d14..92f348f409 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -20,6 +20,19 @@ config ALTERA_SYSID Select this to enable a sysid for Altera devices. Please find details on the "Embedded Peripherals IP User Guide" of Altera. +config ROCKCHIP_EFUSE + bool "Rockchip e-fuse support" + depends on MISC + help + Enable (read-only) access for the e-fuse block found in Rockchip + SoCs: accesses can either be made using byte addressing and a length + or through child-nodes that are generated based on the e-fuse map + retrieved from the DTS. + + This driver currently supports the RK3399 only, but can easily be + extended (by porting the read function from the Linux kernel sources) + to support other recent Rockchip devices. + config CMD_CROS_EC bool "Enable crosec command" depends on CROS_EC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 4543cd647e..ea64677c33 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -50,3 +50,4 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o obj-$(CONFIG_QFW) += qfw.o +obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c new file mode 100644 index 0000000000..423d24c26e --- /dev/null +++ b/drivers/misc/rockchip-efuse.c @@ -0,0 +1,161 @@ +/* + * eFuse driver for Rockchip devices + * + * Copyright 2017, Theobroma Systems Design und Consulting GmbH + * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <command.h> +#include <display_options.h> +#include <dm.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <misc.h> + +#define RK3399_A_SHIFT 16 +#define RK3399_A_MASK 0x3ff +#define RK3399_NFUSES 32 +#define RK3399_BYTES_PER_FUSE 4 +#define RK3399_STROBSFTSEL BIT(9) +#define RK3399_RSB BIT(7) +#define RK3399_PD BIT(5) +#define RK3399_PGENB BIT(3) +#define RK3399_LOAD BIT(2) +#define RK3399_STROBE BIT(1) +#define RK3399_CSB BIT(0) + +struct rockchip_efuse_regs { + u32 ctrl; /* 0x00 efuse control register */ + u32 dout; /* 0x04 efuse data out register */ + u32 rf; /* 0x08 efuse redundancy bit used register */ + u32 _rsvd0; + u32 jtag_pass; /* 0x10 JTAG password */ + u32 strobe_finish_ctrl; + /* 0x14 efuse strobe finish control register */ +}; + +struct rockchip_efuse_platdata { + void __iomem *base; + struct clk *clk; +}; + +#if defined(DEBUG) +static int dump_efuses(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + /* + * N.B.: This function is tailored towards the RK3399 and assumes that + * there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to + * be read. + */ + + struct udevice *dev; + u8 fuses[128]; + int ret; + + /* retrieve the device */ + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(rockchip_efuse), &dev); + if (ret) { + printf("%s: no misc-device found\n", __func__); + return 0; + } + + ret = misc_read(dev, 0, &fuses, sizeof(fuses)); + if (ret) { + printf("%s: misc_read failed\n", __func__); + return 0; + } + + printf("efuse-contents:\n"); + print_buffer(0, fuses, 1, 128, 16); + + return 0; +} + +U_BOOT_CMD( + rk3399_dump_efuses, 1, 1, dump_efuses, + "Dump the content of the efuses", + "" +); +#endif + +static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, + void *buf, int size) +{ + struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); + struct rockchip_efuse_regs *efuse = + (struct rockchip_efuse_regs *)plat->base; + + unsigned int addr_start, addr_end, addr_offset; + u32 out_value; + u8 bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE]; + int i = 0; + u32 addr; + + addr_start = offset / RK3399_BYTES_PER_FUSE; + addr_offset = offset % RK3399_BYTES_PER_FUSE; + addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE); + + /* cap to the size of the efuse block */ + if (addr_end > RK3399_NFUSES) + addr_end = RK3399_NFUSES; + + writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, + &efuse->ctrl); + udelay(1); + for (addr = addr_start; addr < addr_end; addr++) { + setbits_le32(&efuse->ctrl, + RK3399_STROBE | (addr << RK3399_A_SHIFT)); + udelay(1); + out_value = readl(&efuse->dout); + clrbits_le32(&efuse->ctrl, RK3399_STROBE); + udelay(1); + + memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE); + i += RK3399_BYTES_PER_FUSE; + } + + /* Switch to standby mode */ + writel(RK3399_PD | RK3399_CSB, &efuse->ctrl); + + memcpy(buf, bytes + addr_offset, size); + + return 0; +} + +static int rockchip_efuse_read(struct udevice *dev, int offset, + void *buf, int size) +{ + return rockchip_rk3399_efuse_read(dev, offset, buf, size); +} + +static const struct misc_ops rockchip_efuse_ops = { + .read = rockchip_efuse_read, +}; + +static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev) +{ + struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); + + plat->base = (void *)devfdt_get_addr(dev); + return 0; +} + +static const struct udevice_id rockchip_efuse_ids[] = { + { .compatible = "rockchip,rk3399-efuse" }, + {} +}; + +U_BOOT_DRIVER(rockchip_efuse) = { + .name = "rockchip_efuse", + .id = UCLASS_MISC, + .of_match = rockchip_efuse_ids, + .ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata), + .ops = &rockchip_efuse_ops, +}; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index f6616c5329..150c68d794 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -197,6 +197,16 @@ config PINCTRL_ROCKCHIP_RK3328 the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_ROCKCHIP_RK3368 + bool "Rockchip RK3368 pin control driver" + depends on DM + help + Support pin multiplexing control on Rockchip rk3368 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. + config PINCTRL_ROCKCHIP_RK3399 bool "Rockchip rk3399 pin control driver" depends on DM @@ -207,6 +217,16 @@ config PINCTRL_ROCKCHIP_RK3399 the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_ROCKCHIP_RV1108 + bool "Rockchip rv1108 pin control driver" + depends on DM + help + Support pin multiplexing control on Rockchip rv1108 SoC. + + The driver is controlled by a device tree node which contains + both the GPIO definitions and pin control functions for each + available multiplex function. + config PINCTRL_SANDBOX bool "Sandbox pinctrl driver" depends on SANDBOX diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile index 69eef4c024..a1c655d537 100644 --- a/drivers/pinctrl/rockchip/Makefile +++ b/drivers/pinctrl/rockchip/Makefile @@ -9,4 +9,6 @@ obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3036) += pinctrl_rk3036.o obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3188) += pinctrl_rk3188.o obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3288) += pinctrl_rk3288.o obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3328) += pinctrl_rk3328.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3368) += pinctrl_rk3368.o obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3399) += pinctrl_rk3399.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RV1108) += pinctrl_rv1108.o diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3036.c b/drivers/pinctrl/rockchip/pinctrl_rk3036.c index 8d42584b31..9215d6c96e 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3036.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3036.c @@ -26,19 +26,19 @@ static void pinctrl_rk3036_pwm_config(struct rk3036_grf *grf, int pwm_id) { switch (pwm_id) { case PERIPH_ID_PWM0: - rk_clrsetreg(&grf->gpio0d_iomux, GPIO0D2_MASK << GPIO0D2_SHIFT, + rk_clrsetreg(&grf->gpio0d_iomux, GPIO0D2_MASK, GPIO0D2_PWM0 << GPIO0D2_SHIFT); break; case PERIPH_ID_PWM1: - rk_clrsetreg(&grf->gpio0a_iomux, GPIO0A0_MASK << GPIO0A0_SHIFT, + rk_clrsetreg(&grf->gpio0a_iomux, GPIO0A0_MASK, GPIO0A0_PWM1 << GPIO0A0_SHIFT); break; case PERIPH_ID_PWM2: - rk_clrsetreg(&grf->gpio0a_iomux, GPIO0A1_MASK << GPIO0A1_SHIFT, + rk_clrsetreg(&grf->gpio0a_iomux, GPIO0A1_MASK, GPIO0A1_PWM2 << GPIO0A1_SHIFT); break; case PERIPH_ID_PWM3: - rk_clrsetreg(&grf->gpio0a_iomux, GPIO0D3_MASK << GPIO0D3_SHIFT, + rk_clrsetreg(&grf->gpio0a_iomux, GPIO0D3_MASK, GPIO0D3_PWM3 << GPIO0D3_SHIFT); break; default: @@ -52,23 +52,20 @@ static void pinctrl_rk3036_i2c_config(struct rk3036_grf *grf, int i2c_id) switch (i2c_id) { case PERIPH_ID_I2C0: rk_clrsetreg(&grf->gpio0a_iomux, - GPIO0A1_MASK << GPIO0A1_SHIFT | - GPIO0A0_MASK << GPIO0A0_SHIFT, + GPIO0A1_MASK | GPIO0A0_MASK, GPIO0A1_I2C0_SDA << GPIO0A1_SHIFT | GPIO0A0_I2C0_SCL << GPIO0A0_SHIFT); break; case PERIPH_ID_I2C1: rk_clrsetreg(&grf->gpio0a_iomux, - GPIO0A3_MASK << GPIO0A3_SHIFT | - GPIO0A2_MASK << GPIO0A2_SHIFT, + GPIO0A3_MASK | GPIO0A2_MASK, GPIO0A3_I2C1_SDA << GPIO0A3_SHIFT | GPIO0A2_I2C1_SCL << GPIO0A2_SHIFT); break; case PERIPH_ID_I2C2: rk_clrsetreg(&grf->gpio2c_iomux, - GPIO2C5_MASK << GPIO2C5_SHIFT | - GPIO2C4_MASK << GPIO2C4_SHIFT, + GPIO2C5_MASK | GPIO2C4_MASK, GPIO2C5_I2C2_SCL << GPIO2C5_SHIFT | GPIO2C4_I2C2_SDA << GPIO2C4_SHIFT); @@ -80,24 +77,20 @@ static void pinctrl_rk3036_spi_config(struct rk3036_grf *grf, int cs) { switch (cs) { case 0: - rk_clrsetreg(&grf->gpio1d_iomux, - GPIO1D6_MASK << GPIO1D6_SHIFT, + rk_clrsetreg(&grf->gpio1d_iomux, GPIO1D6_MASK, GPIO1D6_SPI_CSN0 << GPIO1D6_SHIFT); break; case 1: - rk_clrsetreg(&grf->gpio1d_iomux, - GPIO1D7_MASK << GPIO1D7_SHIFT, + rk_clrsetreg(&grf->gpio1d_iomux, GPIO1D7_MASK, GPIO1D7_SPI_CSN1 << GPIO1D7_SHIFT); break; } rk_clrsetreg(&grf->gpio1d_iomux, - GPIO1D5_MASK << GPIO1D5_SHIFT | - GPIO1D4_MASK << GPIO1D4_SHIFT, + GPIO1D5_MASK | GPIO1D4_MASK, GPIO1D5_SPI_TXD << GPIO1D5_SHIFT | GPIO1D4_SPI_RXD << GPIO1D4_SHIFT); - rk_clrsetreg(&grf->gpio2a_iomux, - GPIO2A0_MASK << GPIO2A0_SHIFT, + rk_clrsetreg(&grf->gpio2a_iomux, GPIO2A0_MASK, GPIO2A0_SPI_CLK << GPIO2A0_SHIFT); } @@ -106,10 +99,8 @@ static void pinctrl_rk3036_uart_config(struct rk3036_grf *grf, int uart_id) switch (uart_id) { case PERIPH_ID_UART0: rk_clrsetreg(&grf->gpio0c_iomux, - GPIO0C3_MASK << GPIO0C3_SHIFT | - GPIO0C2_MASK << GPIO0C2_SHIFT | - GPIO0C1_MASK << GPIO0C1_SHIFT | - GPIO0C0_MASK << GPIO0C0_SHIFT, + GPIO0C3_MASK | GPIO0C2_MASK | + GPIO0C1_MASK | GPIO0C0_MASK, GPIO0C3_UART0_CTSN << GPIO0C3_SHIFT | GPIO0C2_UART0_RTSN << GPIO0C2_SHIFT | GPIO0C1_UART0_SIN << GPIO0C1_SHIFT | @@ -117,15 +108,13 @@ static void pinctrl_rk3036_uart_config(struct rk3036_grf *grf, int uart_id) break; case PERIPH_ID_UART1: rk_clrsetreg(&grf->gpio2c_iomux, - GPIO2C7_MASK << GPIO2C7_SHIFT | - GPIO2C6_MASK << GPIO2C6_SHIFT, + GPIO2C7_MASK | GPIO2C6_MASK, GPIO2C7_UART1_SOUT << GPIO2C7_SHIFT | GPIO2C6_UART1_SIN << GPIO2C6_SHIFT); break; case PERIPH_ID_UART2: rk_clrsetreg(&grf->gpio1c_iomux, - GPIO1C3_MASK << GPIO1C3_SHIFT | - GPIO1C2_MASK << GPIO1C2_SHIFT, + GPIO1C3_MASK | GPIO1C2_MASK, GPIO1C3_UART2_SOUT << GPIO1C3_SHIFT | GPIO1C2_UART2_SIN << GPIO1C2_SHIFT); break; @@ -146,8 +135,7 @@ static void pinctrl_rk3036_sdmmc_config(struct rk3036_grf *grf, int mmc_id) GPIO1D1_EMMC_D1 << GPIO1D1_SHIFT | GPIO1D0_EMMC_D0 << GPIO1D0_SHIFT); rk_clrsetreg(&grf->gpio2a_iomux, - GPIO2A4_MASK << GPIO2A4_SHIFT | - GPIO2A1_MASK << GPIO2A1_SHIFT, + GPIO2A4_MASK | GPIO2A1_MASK, GPIO2A4_EMMC_CMD << GPIO2A4_SHIFT | GPIO2A1_EMMC_CLKOUT << GPIO2A1_SHIFT); break; diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3328.c b/drivers/pinctrl/rockchip/pinctrl_rk3328.c index b6beec5ed0..d0ffeb1f04 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3328.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3328.c @@ -21,135 +21,28 @@ struct rk3328_pinctrl_priv { struct rk3328_grf_regs *grf; }; -enum { - /* GRF_GPIO0A_IOMUX */ - GRF_GPIO0A5_SEL_SHIFT = 10, - GRF_GPIO0A5_SEL_MASK = 3 << GRF_GPIO0A5_SEL_SHIFT, - GRF_I2C3_SCL = 2, - - GRF_GPIO0A6_SEL_SHIFT = 12, - GRF_GPIO0A6_SEL_MASK = 3 << GRF_GPIO0A6_SEL_SHIFT, - GRF_I2C3_SDA = 2, - - GRF_GPIO0A7_SEL_SHIFT = 14, - GRF_GPIO0A7_SEL_MASK = 3 << GRF_GPIO0A7_SEL_SHIFT, - GRF_EMMC_DATA0 = 2, - - /* GRF_GPIO1A_IOMUX */ - GRF_GPIO1A0_SEL_SHIFT = 0, - GRF_GPIO1A0_SEL_MASK = 0x3fff << GRF_GPIO1A0_SEL_SHIFT, - GRF_CARD_DATA_CLK_CMD_DETN = 0x1555, - - /* GRF_GPIO2A_IOMUX */ - GRF_GPIO2A0_SEL_SHIFT = 0, - GRF_GPIO2A0_SEL_MASK = 3 << GRF_GPIO2A0_SEL_SHIFT, - GRF_UART2_TX_M1 = 1, - - GRF_GPIO2A1_SEL_SHIFT = 2, - GRF_GPIO2A1_SEL_MASK = 3 << GRF_GPIO2A1_SEL_SHIFT, - GRF_UART2_RX_M1 = 1, - - GRF_GPIO2A2_SEL_SHIFT = 4, - GRF_GPIO2A2_SEL_MASK = 3 << GRF_GPIO2A2_SEL_SHIFT, - GRF_PWM_IR = 1, - - GRF_GPIO2A4_SEL_SHIFT = 8, - GRF_GPIO2A4_SEL_MASK = 3 << GRF_GPIO2A4_SEL_SHIFT, - GRF_PWM_0 = 1, - GRF_I2C1_SDA, - - GRF_GPIO2A5_SEL_SHIFT = 10, - GRF_GPIO2A5_SEL_MASK = 3 << GRF_GPIO2A5_SEL_SHIFT, - GRF_PWM_1 = 1, - GRF_I2C1_SCL, - - GRF_GPIO2A6_SEL_SHIFT = 12, - GRF_GPIO2A6_SEL_MASK = 3 << GRF_GPIO2A6_SEL_SHIFT, - GRF_PWM_2 = 1, - - GRF_GPIO2A7_SEL_SHIFT = 14, - GRF_GPIO2A7_SEL_MASK = 3 << GRF_GPIO2A7_SEL_SHIFT, - GRF_CARD_PWR_EN_M0 = 1, - - /* GRF_GPIO2BL_IOMUX */ - GRF_GPIO2BL0_SEL_SHIFT = 0, - GRF_GPIO2BL0_SEL_MASK = 0x3f << GRF_GPIO2BL0_SEL_SHIFT, - GRF_SPI_CLK_TX_RX_M0 = 0x15, - - GRF_GPIO2BL3_SEL_SHIFT = 6, - GRF_GPIO2BL3_SEL_MASK = 3 << GRF_GPIO2BL3_SEL_SHIFT, - GRF_SPI_CSN0_M0 = 1, - - GRF_GPIO2BL4_SEL_SHIFT = 8, - GRF_GPIO2BL4_SEL_MASK = 3 << GRF_GPIO2BL4_SEL_SHIFT, - GRF_SPI_CSN1_M0 = 1, - - GRF_GPIO2BL5_SEL_SHIFT = 10, - GRF_GPIO2BL5_SEL_MASK = 3 << GRF_GPIO2BL5_SEL_SHIFT, - GRF_I2C2_SDA = 1, - - GRF_GPIO2BL6_SEL_SHIFT = 12, - GRF_GPIO2BL6_SEL_MASK = 3 << GRF_GPIO2BL6_SEL_SHIFT, - GRF_I2C2_SCL = 1, - - /* GRF_GPIO2D_IOMUX */ - GRF_GPIO2D0_SEL_SHIFT = 0, - GRF_GPIO2D0_SEL_MASK = 3 << GRF_GPIO2D0_SEL_SHIFT, - GRF_I2C0_SCL = 1, - - GRF_GPIO2D1_SEL_SHIFT = 2, - GRF_GPIO2D1_SEL_MASK = 3 << GRF_GPIO2D1_SEL_SHIFT, - GRF_I2C0_SDA = 1, - - GRF_GPIO2D4_SEL_SHIFT = 8, - GRF_GPIO2D4_SEL_MASK = 0xff << GRF_GPIO2D4_SEL_SHIFT, - GRF_EMMC_DATA123 = 0xaa, - - /* GRF_GPIO3C_IOMUX */ - GRF_GPIO3C0_SEL_SHIFT = 0, - GRF_GPIO3C0_SEL_MASK = 0x3fff << GRF_GPIO3C0_SEL_SHIFT, - GRF_EMMC_DATA567_PWR_CLK_RSTN_CMD = 0x2aaa, - - /* GRF_COM_IOMUX */ - GRF_UART2_IOMUX_SEL_SHIFT = 0, - GRF_UART2_IOMUX_SEL_MASK = 3 << GRF_UART2_IOMUX_SEL_SHIFT, - GRF_UART2_IOMUX_SEL_M0 = 0, - GRF_UART2_IOMUX_SEL_M1, - - GRF_SPI_IOMUX_SEL_SHIFT = 4, - GRF_SPI_IOMUX_SEL_MASK = 3 << GRF_SPI_IOMUX_SEL_SHIFT, - GRF_SPI_IOMUX_SEL_M0 = 0, - GRF_SPI_IOMUX_SEL_M1, - GRF_SPI_IOMUX_SEL_M2, - - GRF_CARD_IOMUX_SEL_SHIFT = 7, - GRF_CARD_IOMUX_SEL_MASK = 1 << GRF_CARD_IOMUX_SEL_SHIFT, - GRF_CARD_IOMUX_SEL_M0 = 0, - GRF_CARD_IOMUX_SEL_M1, -}; - static void pinctrl_rk3328_pwm_config(struct rk3328_grf_regs *grf, int pwm_id) { switch (pwm_id) { case PERIPH_ID_PWM0: rk_clrsetreg(&grf->gpio2a_iomux, - GRF_GPIO2A4_SEL_MASK, - GRF_PWM_0 << GRF_GPIO2A4_SEL_SHIFT); + GPIO2A4_SEL_MASK, + GPIO2A4_PWM_0 << GPIO2A4_SEL_SHIFT); break; case PERIPH_ID_PWM1: rk_clrsetreg(&grf->gpio2a_iomux, - GRF_GPIO2A5_SEL_MASK, - GRF_PWM_1 << GRF_GPIO2A5_SEL_SHIFT); + GPIO2A5_SEL_MASK, + GPIO2A5_PWM_1 << GPIO2A5_SEL_SHIFT); break; case PERIPH_ID_PWM2: rk_clrsetreg(&grf->gpio2a_iomux, - GRF_GPIO2A6_SEL_MASK, - GRF_PWM_2 << GRF_GPIO2A6_SEL_SHIFT); + GPIO2A6_SEL_MASK, + GPIO2A6_PWM_2 << GPIO2A6_SEL_SHIFT); break; case PERIPH_ID_PWM3: rk_clrsetreg(&grf->gpio2a_iomux, - GRF_GPIO2A2_SEL_MASK, - GRF_PWM_IR << GRF_GPIO2A2_SEL_SHIFT); + GPIO2A2_SEL_MASK, + GPIO2A2_PWM_IR << GPIO2A2_SEL_SHIFT); break; default: debug("pwm id = %d iomux error!\n", pwm_id); @@ -162,27 +55,27 @@ static void pinctrl_rk3328_i2c_config(struct rk3328_grf_regs *grf, int i2c_id) switch (i2c_id) { case PERIPH_ID_I2C0: rk_clrsetreg(&grf->gpio2d_iomux, - GRF_GPIO2D0_SEL_MASK | GRF_GPIO2D1_SEL_MASK, - GRF_I2C0_SCL << GRF_GPIO2D0_SEL_SHIFT - | GRF_I2C0_SDA << GRF_GPIO2D1_SEL_SHIFT); + GPIO2D0_SEL_MASK | GPIO2D1_SEL_MASK, + GPIO2D0_I2C0_SCL << GPIO2D0_SEL_SHIFT | + GPIO2D1_I2C0_SDA << GPIO2D1_SEL_SHIFT); break; case PERIPH_ID_I2C1: rk_clrsetreg(&grf->gpio2a_iomux, - GRF_GPIO2A4_SEL_MASK | GRF_GPIO2A5_SEL_MASK, - GRF_I2C1_SCL << GRF_GPIO2A5_SEL_SHIFT - | GRF_I2C1_SDA << GRF_GPIO2A4_SEL_SHIFT); + GPIO2A4_SEL_MASK | GPIO2A5_SEL_MASK, + GPIO2A5_I2C1_SCL << GPIO2A5_SEL_SHIFT | + GPIO2A4_I2C1_SDA << GPIO2A4_SEL_SHIFT); break; case PERIPH_ID_I2C2: rk_clrsetreg(&grf->gpio2bl_iomux, - GRF_GPIO2BL5_SEL_MASK | GRF_GPIO2BL6_SEL_MASK, - GRF_I2C2_SCL << GRF_GPIO2BL6_SEL_SHIFT - | GRF_I2C2_SDA << GRF_GPIO2BL6_SEL_SHIFT); + GPIO2BL5_SEL_MASK | GPIO2BL6_SEL_MASK, + GPIO2BL6_I2C2_SCL << GPIO2BL6_SEL_SHIFT | + GPIO2BL5_I2C2_SDA << GPIO2BL5_SEL_SHIFT); break; case PERIPH_ID_I2C3: rk_clrsetreg(&grf->gpio0a_iomux, - GRF_GPIO0A5_SEL_MASK | GRF_GPIO0A6_SEL_MASK, - GRF_I2C3_SCL << GRF_GPIO0A5_SEL_SHIFT - | GRF_I2C3_SDA << GRF_GPIO0A6_SEL_SHIFT); + GPIO0A5_SEL_MASK | GPIO0A6_SEL_MASK, + GPIO0A5_I2C3_SCL << GPIO0A5_SEL_SHIFT | + GPIO0A6_I2C3_SDA << GPIO0A6_SEL_SHIFT); break; default: debug("i2c id = %d iomux error!\n", i2c_id); @@ -204,29 +97,35 @@ static void pinctrl_rk3328_lcdc_config(struct rk3328_grf_regs *grf, int lcd_id) static int pinctrl_rk3328_spi_config(struct rk3328_grf_regs *grf, enum periph_id spi_id, int cs) { - rk_clrsetreg(&grf->com_iomux, - GRF_SPI_IOMUX_SEL_MASK, - GRF_SPI_IOMUX_SEL_M0 << GRF_SPI_IOMUX_SEL_SHIFT); + u32 com_iomux = readl(&grf->com_iomux); + + if ((com_iomux & IOMUX_SEL_SPI_MASK) != + IOMUX_SEL_SPI_M0 << IOMUX_SEL_SPI_SHIFT) { + debug("driver do not support iomux other than m0\n"); + goto err; + } switch (spi_id) { case PERIPH_ID_SPI0: switch (cs) { case 0: rk_clrsetreg(&grf->gpio2bl_iomux, - GRF_GPIO2BL3_SEL_MASK, - GRF_SPI_CSN0_M0 << GRF_GPIO2BL3_SEL_SHIFT); + GPIO2BL3_SEL_MASK, + GPIO2BL3_SPI_CSN0_M0 + << GPIO2BL3_SEL_SHIFT); break; case 1: rk_clrsetreg(&grf->gpio2bl_iomux, - GRF_GPIO2BL4_SEL_MASK, - GRF_SPI_CSN1_M0 << GRF_GPIO2BL4_SEL_SHIFT); + GPIO2BL4_SEL_MASK, + GPIO2BL4_SPI_CSN1_M0 + << GPIO2BL4_SEL_SHIFT); break; default: goto err; } rk_clrsetreg(&grf->gpio2bl_iomux, - GRF_GPIO2BL0_SEL_MASK, - GRF_SPI_CLK_TX_RX_M0 << GRF_GPIO2BL0_SEL_SHIFT); + GPIO2BL0_SEL_MASK, + GPIO2BL0_SPI_CLK_TX_RX_M0 << GPIO2BL0_SEL_SHIFT); break; default: goto err; @@ -240,18 +139,17 @@ err: static void pinctrl_rk3328_uart_config(struct rk3328_grf_regs *grf, int uart_id) { + u32 com_iomux = readl(&grf->com_iomux); + switch (uart_id) { case PERIPH_ID_UART2: break; - /* uart2 iomux select m1 */ - rk_clrsetreg(&grf->com_iomux, - GRF_UART2_IOMUX_SEL_MASK, - GRF_UART2_IOMUX_SEL_M1 - << GRF_UART2_IOMUX_SEL_SHIFT); - rk_clrsetreg(&grf->gpio2a_iomux, - GRF_GPIO2A0_SEL_MASK | GRF_GPIO2A1_SEL_MASK, - GRF_UART2_TX_M1 << GRF_GPIO2A0_SEL_SHIFT | - GRF_UART2_RX_M1 << GRF_GPIO2A1_SEL_SHIFT); + if (com_iomux & IOMUX_SEL_UART2_MASK) + rk_clrsetreg(&grf->gpio2a_iomux, + GPIO2A0_SEL_MASK | GPIO2A1_SEL_MASK, + GPIO2A0_UART2_TX_M1 << GPIO2A0_SEL_SHIFT | + GPIO2A1_UART2_RX_M1 << GPIO2A1_SEL_SHIFT); + break; case PERIPH_ID_UART0: case PERIPH_ID_UART1: @@ -266,31 +164,37 @@ static void pinctrl_rk3328_uart_config(struct rk3328_grf_regs *grf, int uart_id) static void pinctrl_rk3328_sdmmc_config(struct rk3328_grf_regs *grf, int mmc_id) { + u32 com_iomux = readl(&grf->com_iomux); + switch (mmc_id) { case PERIPH_ID_EMMC: rk_clrsetreg(&grf->gpio0a_iomux, - GRF_GPIO0A7_SEL_MASK, - GRF_EMMC_DATA0 << GRF_GPIO0A7_SEL_SHIFT); + GPIO0A7_SEL_MASK, + GPIO0A7_EMMC_DATA0 << GPIO0A7_SEL_SHIFT); rk_clrsetreg(&grf->gpio2d_iomux, - GRF_GPIO2D4_SEL_MASK, - GRF_EMMC_DATA123 << GRF_GPIO2D4_SEL_SHIFT); + GPIO2D4_SEL_MASK, + GPIO2D4_EMMC_DATA1234 << GPIO2D4_SEL_SHIFT); rk_clrsetreg(&grf->gpio3c_iomux, - GRF_GPIO3C0_SEL_MASK, - GRF_EMMC_DATA567_PWR_CLK_RSTN_CMD - << GRF_GPIO3C0_SEL_SHIFT); + GPIO3C0_SEL_MASK, + GPIO3C0_EMMC_DATA567_PWR_CLK_RSTN_CMD + << GPIO3C0_SEL_SHIFT); break; case PERIPH_ID_SDCARD: - /* sdcard iomux select m0 */ - rk_clrsetreg(&grf->com_iomux, - GRF_CARD_IOMUX_SEL_MASK, - GRF_CARD_IOMUX_SEL_M0 << GRF_CARD_IOMUX_SEL_SHIFT); - rk_clrsetreg(&grf->gpio2a_iomux, - GRF_GPIO2A7_SEL_MASK, - GRF_CARD_PWR_EN_M0 << GRF_GPIO2A7_SEL_SHIFT); + /* SDMMC_PWREN use GPIO and init as regulator-fiexed */ + if (com_iomux & IOMUX_SEL_SDMMC_MASK) + rk_clrsetreg(&grf->gpio0d_iomux, + GPIO0D6_SEL_MASK, + GPIO0D6_SDMMC0_PWRENM1 + << GPIO0D6_SEL_SHIFT); + else + rk_clrsetreg(&grf->gpio2a_iomux, + GPIO2A7_SEL_MASK, + GPIO2A7_SDMMC0_PWRENM0 + << GPIO2A7_SEL_SHIFT); rk_clrsetreg(&grf->gpio1a_iomux, - GRF_GPIO1A0_SEL_MASK, - GRF_CARD_DATA_CLK_CMD_DETN - << GRF_GPIO1A0_SEL_SHIFT); + GPIO1A0_SEL_MASK, + GPIO1A0_CARD_DATA_CLK_CMD_DETN + << GPIO1A0_SEL_SHIFT); break; default: debug("mmc id = %d iomux error!\n", mmc_id); diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3368.c b/drivers/pinctrl/rockchip/pinctrl_rk3368.c new file mode 100644 index 0000000000..bdf0758c0c --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl_rk3368.c @@ -0,0 +1,149 @@ +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd + * Author: Andy Yan <andy.yan@rock-chips.com> + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/arch/grf_rk3368.h> +#include <asm/arch/periph.h> +#include <dm/pinctrl.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct rk3368_pinctrl_priv { + struct rk3368_grf *grf; + struct rk3368_pmu_grf *pmugrf; +}; + +static void pinctrl_rk3368_uart_config(struct rk3368_pinctrl_priv *priv, + int uart_id) +{ + struct rk3368_grf *grf = priv->grf; + struct rk3368_pmu_grf *pmugrf = priv->pmugrf; + + switch (uart_id) { + case PERIPH_ID_UART2: + rk_clrsetreg(&grf->gpio2a_iomux, + GPIO2A6_MASK | GPIO2A5_MASK, + GPIO2A6_UART2_SIN << GPIO2A6_SHIFT | + GPIO2A5_UART2_SOUT << GPIO2A5_SHIFT); + break; + case PERIPH_ID_UART0: + break; + case PERIPH_ID_UART1: + break; + case PERIPH_ID_UART3: + break; + case PERIPH_ID_UART4: + rk_clrsetreg(&pmugrf->gpio0d_iomux, + GPIO0D0_MASK | GPIO0D1_MASK | + GPIO0D2_MASK | GPIO0D3_MASK, + GPIO0D0_GPIO << GPIO0D0_SHIFT | + GPIO0D1_GPIO << GPIO0D1_SHIFT | + GPIO0D2_UART4_SOUT << GPIO0D2_SHIFT | + GPIO0D3_UART4_SIN << GPIO0D3_SHIFT); + break; + default: + debug("uart id = %d iomux error!\n", uart_id); + break; + } +} + +static int rk3368_pinctrl_request(struct udevice *dev, int func, int flags) +{ + struct rk3368_pinctrl_priv *priv = dev_get_priv(dev); + + debug("%s: func=%d, flags=%x\n", __func__, func, flags); + switch (func) { + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART2: + case PERIPH_ID_UART3: + case PERIPH_ID_UART4: + pinctrl_rk3368_uart_config(priv, func); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rk3368_pinctrl_get_periph_id(struct udevice *dev, + struct udevice *periph) +{ + u32 cell[3]; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(periph), + "interrupts", cell, ARRAY_SIZE(cell)); + if (ret < 0) + return -EINVAL; + + switch (cell[1]) { + case 59: + return PERIPH_ID_UART4; + case 58: + return PERIPH_ID_UART3; + case 57: + return PERIPH_ID_UART2; + case 56: + return PERIPH_ID_UART1; + case 55: + return PERIPH_ID_UART0; + } + + return -ENOENT; +} + +static int rk3368_pinctrl_set_state_simple(struct udevice *dev, + struct udevice *periph) +{ + int func; + + func = rk3368_pinctrl_get_periph_id(dev, periph); + if (func < 0) + return func; + + return rk3368_pinctrl_request(dev, func, 0); +} + +static struct pinctrl_ops rk3368_pinctrl_ops = { + .set_state_simple = rk3368_pinctrl_set_state_simple, + .request = rk3368_pinctrl_request, + .get_periph_id = rk3368_pinctrl_get_periph_id, +}; + +static int rk3368_pinctrl_probe(struct udevice *dev) +{ + struct rk3368_pinctrl_priv *priv = dev_get_priv(dev); + int ret = 0; + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); + + debug("%s: grf=%p pmugrf:%p\n", __func__, priv->grf, priv->pmugrf); + + return ret; +} + +static const struct udevice_id rk3368_pinctrl_ids[] = { + { .compatible = "rockchip,rk3368-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_rk3368) = { + .name = "rockchip_rk3368_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = rk3368_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct rk3368_pinctrl_priv), + .ops = &rk3368_pinctrl_ops, + .bind = dm_scan_fdt_dev, + .probe = rk3368_pinctrl_probe, +}; diff --git a/drivers/pinctrl/rockchip/pinctrl_rv1108.c b/drivers/pinctrl/rockchip/pinctrl_rv1108.c new file mode 100644 index 0000000000..bdf3910a88 --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl_rv1108.c @@ -0,0 +1,184 @@ +/* + * (C) Copyright 2016 Rockchip Electronics Co., Ltd + * Author: Andy Yan <andy.yan@rock-chips.com> + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rv1108.h> +#include <asm/arch/hardware.h> +#include <asm/arch/periph.h> +#include <dm/pinctrl.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct rv1108_pinctrl_priv { + struct rv1108_grf *grf; +}; + +static void pinctrl_rv1108_uart_config(struct rv1108_grf *grf, int uart_id) +{ + switch (uart_id) { + case PERIPH_ID_UART0: + rk_clrsetreg(&grf->gpio3a_iomux, + GPIO3A6_MASK | GPIO3A5_MASK, + GPIO3A6_UART1_SOUT << GPIO3A6_SHIFT | + GPIO3A5_UART1_SIN << GPIO3A5_SHIFT); + break; + case PERIPH_ID_UART1: + rk_clrsetreg(&grf->gpio1d_iomux, + GPIO1D3_MASK | GPIO1D2_MASK | GPIO1D1_MASK | + GPIO1D0_MASK, + GPIO1D3_UART0_SOUT << GPIO1D3_SHIFT | + GPIO1D2_UART0_SIN << GPIO1D2_SHIFT | + GPIO1D1_UART0_RTSN << GPIO1D1_SHIFT | + GPIO1D0_UART0_CTSN << GPIO1D0_SHIFT); + break; + case PERIPH_ID_UART2: + rk_clrsetreg(&grf->gpio2d_iomux, + GPIO2D2_MASK | GPIO2D1_MASK, + GPIO2D2_UART2_SOUT_M0 << GPIO2D2_SHIFT | + GPIO2D1_UART2_SIN_M0 << GPIO2D1_SHIFT); + break; + } +} + +static void pinctrl_rv1108_gmac_config(struct rv1108_grf *grf, int func) +{ + rk_clrsetreg(&grf->gpio1b_iomux, + GPIO1B7_MASK | GPIO1B6_MASK | GPIO1B5_MASK | + GPIO1B4_MASK | GPIO1B3_MASK | GPIO1B2_MASK, + GPIO1B7_GMAC_RXDV << GPIO1B7_SHIFT | + GPIO1B6_GMAC_RXD1 << GPIO1B6_SHIFT | + GPIO1B5_GMAC_RXD0 << GPIO1B5_SHIFT | + GPIO1B4_GMAC_TXEN << GPIO1B4_SHIFT | + GPIO1B3_GMAC_TXD1 << GPIO1B3_SHIFT | + GPIO1B2_GMAC_TXD0 << GPIO1B2_SHIFT); + rk_clrsetreg(&grf->gpio1c_iomux, + GPIO1C5_MASK | GPIO1C4_MASK | + GPIO1C3_MASK | GPIO1C2_MASK, + GPIO1C5_GMAC_CLK << GPIO1C5_SHIFT | + GPIO1C4_GMAC_MDC << GPIO1C4_SHIFT | + GPIO1C3_GMAC_MDIO << GPIO1C3_SHIFT | + GPIO1C2_GMAC_RXER << GPIO1C2_SHIFT); + writel(0xffff57f5, &grf->gpio1b_drv); +} + +static void pinctrl_rv1108_sfc_config(struct rv1108_grf *grf) +{ + rk_clrsetreg(&grf->gpio2a_iomux, GPIO2A3_MASK | GPIO2A2_MASK | + GPIO2A1_MASK | GPIO2A0_MASK, + GPIO2A3_SFC_HOLD_IO3 << GPIO2A3_SHIFT | + GPIO2A2_SFC_WP_IO2 << GPIO2A2_SHIFT | + GPIO2A1_SFC_SO_IO1 << GPIO2A1_SHIFT | + GPIO2A0_SFC_SI_IO0 << GPIO2A0_SHIFT); + rk_clrsetreg(&grf->gpio2b_iomux, GPIO2B7_MASK | GPIO2B4_MASK, + GPIO2B7_SFC_CLK << GPIO2B7_SHIFT | + GPIO2B4_SFC_CSN0 << GPIO2B4_SHIFT); +} + +static int rv1108_pinctrl_request(struct udevice *dev, int func, int flags) +{ + struct rv1108_pinctrl_priv *priv = dev_get_priv(dev); + + switch (func) { + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART2: + pinctrl_rv1108_uart_config(priv->grf, func); + break; + case PERIPH_ID_GMAC: + pinctrl_rv1108_gmac_config(priv->grf, func); + case PERIPH_ID_SFC: + pinctrl_rv1108_sfc_config(priv->grf); + default: + return -EINVAL; + } + + return 0; +} + +static int rv1108_pinctrl_get_periph_id(struct udevice *dev, + struct udevice *periph) +{ + u32 cell[3]; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(periph), + "interrupts", cell, ARRAY_SIZE(cell)); + if (ret < 0) + return -EINVAL; + + switch (cell[1]) { + case 11: + return PERIPH_ID_SDCARD; + case 13: + return PERIPH_ID_EMMC; + case 19: + return PERIPH_ID_GMAC; + case 30: + return PERIPH_ID_I2C0; + case 31: + return PERIPH_ID_I2C1; + case 32: + return PERIPH_ID_I2C2; + case 39: + return PERIPH_ID_PWM0; + case 44: + return PERIPH_ID_UART0; + case 45: + return PERIPH_ID_UART1; + case 46: + return PERIPH_ID_UART2; + case 56: + return PERIPH_ID_SFC; + } + + return -ENOENT; +} + +static int rv1108_pinctrl_set_state_simple(struct udevice *dev, + struct udevice *periph) +{ + int func; + + func = rv1108_pinctrl_get_periph_id(dev, periph); + if (func < 0) + return func; + + return rv1108_pinctrl_request(dev, func, 0); +} + +static struct pinctrl_ops rv1108_pinctrl_ops = { + .set_state_simple = rv1108_pinctrl_set_state_simple, + .request = rv1108_pinctrl_request, + .get_periph_id = rv1108_pinctrl_get_periph_id, +}; + +static int rv1108_pinctrl_probe(struct udevice *dev) +{ + struct rv1108_pinctrl_priv *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + return 0; +} + +static const struct udevice_id rv1108_pinctrl_ids[] = { + {.compatible = "rockchip,rv1108-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_rv1108) = { + .name = "pinctrl_rv1108", + .id = UCLASS_PINCTRL, + .of_match = rv1108_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct rv1108_pinctrl_priv), + .ops = &rv1108_pinctrl_ops, + .bind = dm_scan_fdt_dev, + .probe = rv1108_pinctrl_probe, +}; diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index 09b9b54c62..eb3ec0f601 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -111,6 +111,7 @@ U_BOOT_DRIVER(pmic_rk8xx) = { #if CONFIG_IS_ENABLED(PMIC_CHILDREN) .bind = rk8xx_bind, #endif + .priv_auto_alloc_size = sizeof(struct rk8xx_priv), .probe = rk8xx_probe, .ops = &rk8xx_ops, }; diff --git a/drivers/power/regulator/pwm_regulator.c b/drivers/power/regulator/pwm_regulator.c index a6c9fccd68..00a7cca7f7 100644 --- a/drivers/power/regulator/pwm_regulator.c +++ b/drivers/power/regulator/pwm_regulator.c @@ -32,13 +32,13 @@ struct pwm_regulator_info { bool polarity; struct udevice *pwm; /* initialize voltage of regulator */ - unsigned int init_voltage; + int init_voltage; /* the maximum voltage of regulator */ - unsigned int max_voltage; + int max_voltage; /* the minimum voltage of regulator */ - unsigned int min_voltage; + int min_voltage; /* the current voltage of regulator */ - unsigned int volt_uV; + int volt_uV; }; static int pwm_regulator_enable(struct udevice *dev, bool enable) diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c index e655c2d91f..c1ece96b66 100644 --- a/drivers/power/regulator/rk8xx.c +++ b/drivers/power/regulator/rk8xx.c @@ -92,9 +92,9 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic, struct rk8xx_priv *priv = dev_get_priv(pmic); switch (priv->variant) { case RK818_ID: - return &rk818_ldo[num - 1]; + return &rk818_ldo[num]; default: - return &rk808_ldo[num - 1]; + return &rk808_ldo[num]; } } diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index b68381148c..a5200d377d 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -15,7 +15,9 @@ endif obj-$(CONFIG_ROCKCHIP_RK3188) += sysreset_rk3188.o obj-$(CONFIG_ROCKCHIP_RK3288) += sysreset_rk3288.o obj-$(CONFIG_ROCKCHIP_RK3328) += sysreset_rk3328.o +obj-$(CONFIG_ROCKCHIP_RK3368) += sysreset_rk3368.o obj-$(CONFIG_ROCKCHIP_RK3399) += sysreset_rk3399.o +obj-$(CONFIG_ROCKCHIP_RV1108) += sysreset_rv1108.o obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o obj-$(CONFIG_ARCH_SNAPDRAGON) += sysreset_snapdragon.o obj-$(CONFIG_ARCH_STI) += sysreset_sti.o diff --git a/drivers/sysreset/sysreset_rk3368.c b/drivers/sysreset/sysreset_rk3368.c new file mode 100644 index 0000000000..de62921b78 --- /dev/null +++ b/drivers/sysreset/sysreset_rk3368.c @@ -0,0 +1,62 @@ +/* + * (C) Copyright Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <sysreset.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3368.h> +#include <asm/arch/hardware.h> +#include <linux/err.h> + +static void rk3368_pll_enter_slow_mode(struct rk3368_cru *cru) +{ + struct rk3368_pll *pll; + int i; + + for (i = 0; i < 6; i++) { + pll = &cru->pll[i]; + rk_clrreg(&pll->con3, PLL_MODE_MASK); + } +} + +static int rk3368_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct rk3368_cru *cru = rockchip_get_cru(); + + if (IS_ERR(cru)) + return PTR_ERR(cru); + switch (type) { + case SYSRESET_WARM: + rk3368_pll_enter_slow_mode(cru); + rk_clrsetreg(&cru->glb_rst_con, PMU_GLB_SRST_CTRL_MASK, + PMU_RST_BY_SND_GLB_SRST << PMU_GLB_SRST_CTRL_SHIFT); + writel(0xeca8, &cru->glb_srst_snd_val); + break; + case SYSRESET_COLD: + rk3368_pll_enter_slow_mode(cru); + rk_clrsetreg(&cru->glb_rst_con, PMU_GLB_SRST_CTRL_MASK, + PMU_RST_BY_FST_GLB_SRST << PMU_GLB_SRST_CTRL_SHIFT); + writel(0xfdb9, &cru->glb_srst_fst_val); + break; + default: + return -EPROTONOSUPPORT; + } + + return -EINPROGRESS; +} + +static struct sysreset_ops rk3368_sysreset = { + .request = rk3368_sysreset_request, +}; + +U_BOOT_DRIVER(sysreset_rk3368) = { + .name = "rk3368_sysreset", + .id = UCLASS_SYSRESET, + .ops = &rk3368_sysreset, +}; diff --git a/drivers/sysreset/sysreset_rv1108.c b/drivers/sysreset/sysreset_rv1108.c new file mode 100644 index 0000000000..9d8e9f7ade --- /dev/null +++ b/drivers/sysreset/sysreset_rv1108.c @@ -0,0 +1,46 @@ +/* + * (C) Copyright 2015 Rockchip Electronics Co., Ltd + * Author: Andy Yan <andy.yan@rock-chips.com> + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <sysreset.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rv1108.h> +#include <asm/arch/hardware.h> +#include <linux/err.h> + +int rv1108_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct rv1108_cru *cru = rockchip_get_cru(); + + if (IS_ERR(cru)) + return PTR_ERR(cru); + + switch (type) { + case SYSRESET_WARM: + writel(0xeca8, &cru->glb_srst_snd_val); + break; + case SYSRESET_COLD: + writel(0xfdb9, &cru->glb_srst_fst_val); + break; + default: + return -EPROTONOSUPPORT; + } + + return -EINPROGRESS; +} + +static struct sysreset_ops rv1108_sysreset = { + .request = rv1108_sysreset_request, +}; + +U_BOOT_DRIVER(sysreset_rv1108) = { + .name = "rv1108_sysreset", + .id = UCLASS_SYSRESET, + .ops = &rv1108_sysreset, +}; diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c index 38e1c68db7..c4ae55fc39 100644 --- a/drivers/usb/host/xhci-rockchip.c +++ b/drivers/usb/host/xhci-rockchip.c @@ -11,10 +11,10 @@ #include <malloc.h> #include <usb.h> #include <watchdog.h> -#include <asm/gpio.h> #include <linux/errno.h> #include <linux/compat.h> #include <linux/usb/dwc3.h> +#include <power/regulator.h> #include "xhci.h" @@ -23,7 +23,7 @@ DECLARE_GLOBAL_DATA_PTR; struct rockchip_xhci_platdata { fdt_addr_t hcd_base; fdt_addr_t phy_base; - struct gpio_desc vbus_gpio; + struct udevice *vbus_supply; }; /* @@ -66,11 +66,13 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) return -ENXIO; } - /* Vbus gpio */ - ret = gpio_request_by_name(dev, "rockchip,vbus-gpio", 0, - &plat->vbus_gpio, GPIOD_IS_OUT); +#if defined(CONFIG_DM_USB) && defined(CONFIG_DM_REGULATOR) + /* Vbus regulator */ + ret = device_get_supply_regulator(dev, "vbus-supply", + &plat->vbus_supply); if (ret) - debug("rockchip,vbus-gpio node missing!"); + debug("Can't get vbus supply\n"); +#endif return 0; } @@ -153,9 +155,11 @@ static int xhci_usb_probe(struct udevice *dev) hcor = (struct xhci_hcor *)((uint64_t)ctx->hcd + HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase))); - /* setup the Vbus gpio here */ - if (dm_gpio_is_valid(&plat->vbus_gpio)) - dm_gpio_set_value(&plat->vbus_gpio, 1); +#if defined(CONFIG_DM_USB) && defined(CONFIG_DM_REGULATOR) + ret = regulator_set_enable(plat->vbus_supply, true); + if (ret) + debug("XHCI: Failed to enable vbus supply\n"); +#endif ret = rockchip_xhci_core_init(ctx, dev); if (ret) { @@ -168,6 +172,7 @@ static int xhci_usb_probe(struct udevice *dev) static int xhci_usb_remove(struct udevice *dev) { + struct rockchip_xhci_platdata *plat = dev_get_platdata(dev); struct rockchip_xhci *ctx = dev_get_priv(dev); int ret; @@ -178,11 +183,18 @@ static int xhci_usb_remove(struct udevice *dev) if (ret) return ret; +#if defined(CONFIG_DM_USB) && defined(CONFIG_DM_REGULATOR) + ret = regulator_set_enable(plat->vbus_supply, false); + if (ret) + debug("XHCI: Failed to disable vbus supply\n"); +#endif + return 0; } static const struct udevice_id xhci_usb_ids[] = { { .compatible = "rockchip,rk3399-xhci" }, + { .compatible = "rockchip,rk3328-xhci" }, { } }; @@ -202,6 +214,7 @@ U_BOOT_DRIVER(usb_xhci) = { static const struct udevice_id usb_phy_ids[] = { { .compatible = "rockchip,rk3399-usb3-phy" }, + { .compatible = "rockchip,rk3328-usb3-phy" }, { } }; diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 80e399f7d7..b1d7c62fca 100644 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -12,11 +12,30 @@ menuconfig VIDEO_ROCKCHIP bool "Enable Rockchip Video Support" depends on DM_VIDEO help - Rockchip SoCs provide video output capabilities for High-Definition - Multimedia Interface (HDMI), Low-voltage Differential Signalling - (LVDS), embedded DisplayPort (eDP) and Display Serial Interface - (DSI). This driver supports the on-chip video output device, and - targets the Rockchip RK3288 and RK3399. + Rockchip SoCs provide video output capabilities for High-Definition + Multimedia Interface (HDMI), Low-voltage Differential Signalling + (LVDS), embedded DisplayPort (eDP) and Display Serial Interface (DSI). + + This driver supports the on-chip video output device, and targets the + Rockchip RK3288 and RK3399. + +config VIDEO_ROCKCHIP_MAX_XRES + int "Maximum horizontal resolution (for memory allocation purposes)" + depends on VIDEO_ROCKCHIP + default 1920 + help + The maximum horizontal resolution to support for the framebuffer. + This configuration is used for reserving/allocating memory for the + framebuffer during device-model binding/probing. + +config VIDEO_ROCKCHIP_MAX_YRES + int "Maximum vertical resolution (for memory allocation purposes)" + depends on VIDEO_ROCKCHIP + default 1080 + help + The maximum vertical resolution to support for the framebuffer. + This configuration is used for reserving/allocating memory for the + framebuffer during device-model binding/probing. if VIDEO_ROCKCHIP diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index cd54b12a4e..872dc0f653 100644 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -7,8 +7,12 @@ ifdef CONFIG_VIDEO_ROCKCHIP obj-y += rk_vop.o +obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288_vop.o +obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399_vop.o obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o -obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o +obj-hdmi-$(CONFIG_ROCKCHIP_RK3288) += rk3288_hdmi.o +obj-hdmi-$(CONFIG_ROCKCHIP_RK3399) += rk3399_hdmi.o +obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o $(obj-hdmi-y) obj-$(CONFIG_DISPLAY_ROCKCHIP_MIPI) += rk_mipi.o endif diff --git a/drivers/video/rockchip/rk3288_hdmi.c b/drivers/video/rockchip/rk3288_hdmi.c new file mode 100644 index 0000000000..eae0dd2abf --- /dev/null +++ b/drivers/video/rockchip/rk3288_hdmi.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <dw_hdmi.h> +#include <edid.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/arch/grf_rk3288.h> +#include <power/regulator.h> +#include "rk_hdmi.h" + +static int rk3288_hdmi_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *edid) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + int vop_id = uc_plat->source_id; + struct rk3288_grf *grf = priv->grf; + + /* hdmi source select hdmi controller */ + rk_setreg(&grf->soc_con6, 1 << 15); + + /* hdmi data from vop id */ + rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0); + + return 0; +} + +static int rk3288_hdmi_ofdata_to_platdata(struct udevice *dev) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct dw_hdmi *hdmi = &priv->hdmi; + + hdmi->i2c_clk_high = 0x7a; + hdmi->i2c_clk_low = 0x8d; + + /* + * TODO(sjg@chromium.org): The above values don't work - these + * ones work better, but generate lots of errors in the data. + */ + hdmi->i2c_clk_high = 0x0d; + hdmi->i2c_clk_low = 0x0d; + + return rk_hdmi_ofdata_to_platdata(dev); +} + +static int rk3288_clk_config(struct udevice *dev) +{ + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + struct clk clk; + int ret; + + /* + * Configure the maximum clock to permit whatever resolution the + * monitor wants + */ + ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); + if (ret >= 0) { + ret = clk_set_rate(&clk, 384000000); + clk_free(&clk); + } + if (ret < 0) { + debug("%s: Failed to set clock in source device '%s': ret=%d\n", + __func__, uc_plat->src_dev->name, ret); + return ret; + } + + return 0; +} + +static const char * const rk3288_regulator_names[] = { + "vcc50_hdmi" +}; + +static int rk3288_hdmi_probe(struct udevice *dev) +{ + /* Enable VOP clock for RK3288 */ + rk3288_clk_config(dev); + + /* Enable regulators required for HDMI */ + rk_hdmi_probe_regulators(dev, rk3288_regulator_names, + ARRAY_SIZE(rk3288_regulator_names)); + + return rk_hdmi_probe(dev); +} + +static const struct dm_display_ops rk3288_hdmi_ops = { + .read_edid = rk_hdmi_read_edid, + .enable = rk3288_hdmi_enable, +}; + +static const struct udevice_id rk3288_hdmi_ids[] = { + { .compatible = "rockchip,rk3288-dw-hdmi" }, + { } +}; + +U_BOOT_DRIVER(rk3288_hdmi_rockchip) = { + .name = "rk3288_hdmi_rockchip", + .id = UCLASS_DISPLAY, + .of_match = rk3288_hdmi_ids, + .ops = &rk3288_hdmi_ops, + .ofdata_to_platdata = rk3288_hdmi_ofdata_to_platdata, + .probe = rk3288_hdmi_probe, + .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), +}; diff --git a/drivers/video/rockchip/rk3288_vop.c b/drivers/video/rockchip/rk3288_vop.c new file mode 100644 index 0000000000..e3e1ec728c --- /dev/null +++ b/drivers/video/rockchip/rk3288_vop.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * Copyright (c) 2015 Google, Inc + * Copyright 2014 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <display.h> +#include <dm.h> +#include <regmap.h> +#include <syscon.h> +#include <video.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3288.h> +#include "rk_vop.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void rk3288_set_pin_polarity(struct udevice *dev, + enum vop_modes mode, u32 polarity) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs; + + /* The RK3328 VOP (v3.1) has its polarity configuration in ctrl0 */ + clrsetbits_le32(®s->dsp_ctrl0, + M_DSP_DCLK_POL | M_DSP_DEN_POL | + M_DSP_VSYNC_POL | M_DSP_HSYNC_POL, + V_DSP_PIN_POL(polarity)); +} + +static void rk3288_set_io_vsel(struct udevice *dev) +{ + struct rk3288_grf *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + /* lcdc(vop) iodomain select 1.8V */ + rk_setreg(&grf->io_vsel, 1 << 0); +} + +/* + * Try some common regulators. We should really get these from the + * device tree somehow. + */ +static const char * const rk3288_regulator_names[] = { + "vcc18_lcd", + "VCC18_LCD", + "vdd10_lcd_pwren_h", + "vdd10_lcd", + "VDD10_LCD", + "vcc33_lcd" +}; + +static int rk3288_vop_probe(struct udevice *dev) +{ + /* Before relocation we don't need to do anything */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + /* Set the LCDC(vop) iodomain to 1.8V */ + rk3288_set_io_vsel(dev); + + /* Probe regulators required for the RK3288 VOP */ + rk_vop_probe_regulators(dev, rk3288_regulator_names, + ARRAY_SIZE(rk3288_regulator_names)); + + return rk_vop_probe(dev); +} + +struct rkvop_driverdata rk3288_driverdata = { + .features = VOP_FEATURE_OUTPUT_10BIT, + .set_pin_polarity = rk3288_set_pin_polarity, +}; + +static const struct udevice_id rk3288_vop_ids[] = { + { .compatible = "rockchip,rk3288-vop", + .data = (ulong)&rk3288_driverdata }, + { } +}; + +static const struct video_ops rk3288_vop_ops = { +}; + +U_BOOT_DRIVER(rk_vop) = { + .name = "rk3288_vop", + .id = UCLASS_VIDEO, + .of_match = rk3288_vop_ids, + .ops = &rk3288_vop_ops, + .bind = rk_vop_bind, + .probe = rk3288_vop_probe, + .priv_auto_alloc_size = sizeof(struct rk_vop_priv), +}; diff --git a/drivers/video/rockchip/rk3399_hdmi.c b/drivers/video/rockchip/rk3399_hdmi.c new file mode 100644 index 0000000000..b1e50974f6 --- /dev/null +++ b/drivers/video/rockchip/rk3399_hdmi.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <display.h> +#include <dm.h> +#include <dw_hdmi.h> +#include <edid.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/arch/grf_rk3399.h> +#include <power/regulator.h> +#include "rk_hdmi.h" + +static int rk3399_hdmi_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *edid) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + int vop_id = uc_plat->source_id; + struct rk3399_grf_regs *grf = priv->grf; + + /* select the hdmi encoder input data from our source_id */ + rk_clrsetreg(&grf->soc_con20, GRF_RK3399_HDMI_VOP_SEL_MASK, + (vop_id == 1) ? GRF_RK3399_HDMI_VOP_SEL_L : 0); + + return dw_hdmi_enable(&priv->hdmi, edid); +} + +static int rk3399_hdmi_ofdata_to_platdata(struct udevice *dev) +{ + struct rk_hdmi_priv *priv = dev_get_priv(dev); + struct dw_hdmi *hdmi = &priv->hdmi; + + hdmi->i2c_clk_high = 0x7a; + hdmi->i2c_clk_low = 0x8d; + + return rk_hdmi_ofdata_to_platdata(dev); +} + +static const char * const rk3399_regulator_names[] = { + "vcc1v8_hdmi", + "vcc0v9_hdmi" +}; + +static int rk3399_hdmi_probe(struct udevice *dev) +{ + /* Enable regulators required for HDMI */ + rk_hdmi_probe_regulators(dev, rk3399_regulator_names, + ARRAY_SIZE(rk3399_regulator_names)); + + return rk_hdmi_probe(dev); +} + +static const struct dm_display_ops rk3399_hdmi_ops = { + .read_edid = rk_hdmi_read_edid, + .enable = rk3399_hdmi_enable, +}; + +static const struct udevice_id rk3399_hdmi_ids[] = { + { .compatible = "rockchip,rk3399-dw-hdmi" }, + { } +}; + +U_BOOT_DRIVER(rk3399_hdmi_rockchip) = { + .name = "rk3399_hdmi_rockchip", + .id = UCLASS_DISPLAY, + .of_match = rk3399_hdmi_ids, + .ops = &rk3399_hdmi_ops, + .ofdata_to_platdata = rk3399_hdmi_ofdata_to_platdata, + .probe = rk3399_hdmi_probe, + .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), +}; diff --git a/drivers/video/rockchip/rk3399_vop.c b/drivers/video/rockchip/rk3399_vop.c new file mode 100644 index 0000000000..91a40ab9fe --- /dev/null +++ b/drivers/video/rockchip/rk3399_vop.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * Copyright (c) 2015 Google, Inc + * Copyright 2014 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <display.h> +#include <dm.h> +#include <regmap.h> +#include <video.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include "rk_vop.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void rk3399_set_pin_polarity(struct udevice *dev, + enum vop_modes mode, u32 polarity) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs; + + /* + * The RK3399 VOPs (v3.5 and v3.6) require a per-mode setting of + * the polarity configuration (in ctrl1). + */ + switch (mode) { + case VOP_MODE_HDMI: + clrsetbits_le32(®s->dsp_ctrl1, + M_RK3399_DSP_HDMI_POL, + V_RK3399_DSP_HDMI_POL(polarity)); + break; + + case VOP_MODE_EDP: + clrsetbits_le32(®s->dsp_ctrl1, + M_RK3399_DSP_EDP_POL, + V_RK3399_DSP_EDP_POL(polarity)); + break; + + case VOP_MODE_MIPI: + clrsetbits_le32(®s->dsp_ctrl1, + M_RK3399_DSP_MIPI_POL, + V_RK3399_DSP_MIPI_POL(polarity)); + break; + + case VOP_MODE_LVDS: + /* The RK3399 has neither parallel RGB nor LVDS output. */ + default: + debug("%s: unsupported output mode %x\n", __func__, mode); + } +} + +/* + * Try some common regulators. We should really get these from the + * device tree somehow. + */ +static const char * const rk3399_regulator_names[] = { + "vcc33_lcd" +}; + +static int rk3399_vop_probe(struct udevice *dev) +{ + /* Before relocation we don't need to do anything */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + /* Probe regulators required for the RK3399 VOP */ + rk_vop_probe_regulators(dev, rk3399_regulator_names, + ARRAY_SIZE(rk3399_regulator_names)); + + return rk_vop_probe(dev); +} + +struct rkvop_driverdata rk3399_lit_driverdata = { + .set_pin_polarity = rk3399_set_pin_polarity, +}; + +struct rkvop_driverdata rk3399_big_driverdata = { + .features = VOP_FEATURE_OUTPUT_10BIT, + .set_pin_polarity = rk3399_set_pin_polarity, +}; + +static const struct udevice_id rk3399_vop_ids[] = { + { .compatible = "rockchip,rk3399-vop-big", + .data = (ulong)&rk3399_big_driverdata }, + { .compatible = "rockchip,rk3399-vop-lit", + .data = (ulong)&rk3399_lit_driverdata }, + { } +}; + +static const struct video_ops rk3399_vop_ops = { +}; + +U_BOOT_DRIVER(rk3399_vop) = { + .name = "rk3399_vop", + .id = UCLASS_VIDEO, + .of_match = rk3399_vop_ids, + .ops = &rk3399_vop_ops, + .bind = rk_vop_bind, + .probe = rk3399_vop_probe, + .priv_auto_alloc_size = sizeof(struct rk_vop_priv), +}; diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c index cd695ca508..a9c8fba7e4 100644 --- a/drivers/video/rockchip/rk_hdmi.c +++ b/drivers/video/rockchip/rk_hdmi.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH * Copyright (c) 2015 Google, Inc * Copyright 2014 Rockchip Inc. * @@ -14,15 +15,12 @@ #include <regmap.h> #include <syscon.h> #include <asm/gpio.h> +#include <asm/hardware.h> #include <asm/io.h> #include <asm/arch/clock.h> -#include <asm/arch/grf_rk3288.h> -#include <power/regulator.h> - -struct rk_hdmi_priv { - struct dw_hdmi hdmi; - struct rk3288_grf *grf; -}; +#include <asm/arch/hardware.h> +#include "rk_hdmi.h" +#include "rk_vop.h" /* for rk_vop_probe_regulators */ static const struct hdmi_phy_config rockchip_phy_config[] = { { @@ -35,6 +33,9 @@ static const struct hdmi_phy_config rockchip_phy_config[] = { .mpixelclock = 297000000, .sym_ctr = 0x8039, .term = 0x0005, .vlev_ctr = 0x028d, }, { + .mpixelclock = 584000000, + .sym_ctr = 0x8039, .term = 0x0000, .vlev_ctr = 0x019d, + }, { .mpixelclock = ~0ul, .sym_ctr = 0x0000, .term = 0x0000, .vlev_ctr = 0x0000, } @@ -60,27 +61,25 @@ static const struct hdmi_mpll_config rockchip_mpll_cfg[] = { .mpixelclock = 148500000, .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, }, { + .mpixelclock = 272000000, + .cpce = 0x0040, .gmp = 0x0003, .curr = 0x0000, + }, { + .mpixelclock = 340000000, + .cpce = 0x0040, .gmp = 0x0003, .curr = 0x0000, + }, { .mpixelclock = ~0ul, .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, } }; -static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) +int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) { struct rk_hdmi_priv *priv = dev_get_priv(dev); return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size); } -static int rk_hdmi_enable(struct udevice *dev, int panel_bpp, - const struct display_timing *edid) -{ - struct rk_hdmi_priv *priv = dev_get_priv(dev); - - return dw_hdmi_enable(&priv->hdmi, edid); -} - -static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) +int rk_hdmi_ofdata_to_platdata(struct udevice *dev) { struct rk_hdmi_priv *priv = dev_get_priv(dev); struct dw_hdmi *hdmi = &priv->hdmi; @@ -88,15 +87,9 @@ static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) hdmi->ioaddr = (ulong)devfdt_get_addr(dev); hdmi->mpll_cfg = rockchip_mpll_cfg; hdmi->phy_cfg = rockchip_phy_config; - hdmi->i2c_clk_high = 0x7a; - hdmi->i2c_clk_low = 0x8d; - - /* - * TODO(sjg@chromium.org): The above values don't work - these ones - * work better, but generate lots of errors in the data. - */ - hdmi->i2c_clk_high = 0x0d; - hdmi->i2c_clk_low = 0x0d; + + /* hdmi->i2c_clk_{high,low} are set up by the SoC driver */ + hdmi->reg_io_width = 4; hdmi->phy_set = dw_hdmi_phy_cfg; @@ -105,53 +98,17 @@ static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) return 0; } -static int rk_hdmi_probe(struct udevice *dev) +void rk_hdmi_probe_regulators(struct udevice *dev, + const char * const *names, int cnt) +{ + rk_vop_probe_regulators(dev, names, cnt); +} + +int rk_hdmi_probe(struct udevice *dev) { - struct display_plat *uc_plat = dev_get_uclass_platdata(dev); struct rk_hdmi_priv *priv = dev_get_priv(dev); struct dw_hdmi *hdmi = &priv->hdmi; - struct udevice *reg; - struct clk clk; int ret; - int vop_id = uc_plat->source_id; - - ret = clk_get_by_index(dev, 0, &clk); - if (ret >= 0) { - ret = clk_set_rate(&clk, 0); - clk_free(&clk); - } - if (ret) { - debug("%s: Failed to set hdmi clock: ret=%d\n", __func__, ret); - return ret; - } - - /* - * Configure the maximum clock to permit whatever resolution the - * monitor wants - */ - ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); - if (ret >= 0) { - ret = clk_set_rate(&clk, 384000000); - clk_free(&clk); - } - if (ret < 0) { - debug("%s: Failed to set clock in source device '%s': ret=%d\n", - __func__, uc_plat->src_dev->name, ret); - return ret; - } - - ret = regulator_get_by_platname("vcc50_hdmi", ®); - if (!ret) - ret = regulator_set_enable(reg, true); - if (ret) - debug("%s: Cannot set regulator vcc50_hdmi\n", __func__); - - /* hdmi source select hdmi controller */ - rk_setreg(&priv->grf->soc_con6, 1 << 15); - - /* hdmi data from vop id */ - rk_clrsetreg(&priv->grf->soc_con6, 1 << 4, - (vop_id == 1) ? (1 << 4) : 0); ret = dw_hdmi_phy_wait_for_hpd(hdmi); if (ret < 0) { @@ -164,23 +121,3 @@ static int rk_hdmi_probe(struct udevice *dev) return 0; } - -static const struct dm_display_ops rk_hdmi_ops = { - .read_edid = rk_hdmi_read_edid, - .enable = rk_hdmi_enable, -}; - -static const struct udevice_id rk_hdmi_ids[] = { - { .compatible = "rockchip,rk3288-dw-hdmi" }, - { } -}; - -U_BOOT_DRIVER(hdmi_rockchip) = { - .name = "hdmi_rockchip", - .id = UCLASS_DISPLAY, - .of_match = rk_hdmi_ids, - .ops = &rk_hdmi_ops, - .ofdata_to_platdata = rk_hdmi_ofdata_to_platdata, - .probe = rk_hdmi_probe, - .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), -}; diff --git a/drivers/video/rockchip/rk_hdmi.h b/drivers/video/rockchip/rk_hdmi.h new file mode 100644 index 0000000000..501ed3ada8 --- /dev/null +++ b/drivers/video/rockchip/rk_hdmi.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RK_HDMI_H__ +#define __RK_HDMI_H__ + +struct rkhdmi_driverdata { + /* configuration */ + u8 i2c_clk_high; + u8 i2c_clk_low; + const char * const *regulator_names; + u32 regulator_names_cnt; + /* setters/getters */ + int (*set_input_vop)(struct udevice *dev); + int (*clk_config)(struct udevice *dev); +}; + +struct rk_hdmi_priv { + struct dw_hdmi hdmi; + void *grf; +}; + +int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size); +void rk_hdmi_probe_regulators(struct udevice *dev, + const char * const *names, int cnt); +int rk_hdmi_ofdata_to_platdata(struct udevice *dev); +int rk_hdmi_probe(struct udevice *dev); + +#endif diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index 48bfcd4f34..93437964b2 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -17,24 +17,25 @@ #include <asm/hardware.h> #include <asm/io.h> #include <asm/arch/clock.h> -#include <asm/arch/cru_rk3288.h> -#include <asm/arch/grf_rk3288.h> #include <asm/arch/edp_rk3288.h> #include <asm/arch/vop_rk3288.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> -#include <dt-bindings/clock/rk3288-cru.h> #include <power/regulator.h> +#include "rk_vop.h" DECLARE_GLOBAL_DATA_PTR; -struct rk_vop_priv { - struct rk3288_vop *regs; - struct rk3288_grf *grf; +enum vop_pol { + HSYNC_POSITIVE = 0, + VSYNC_POSITIVE = 1, + DEN_NEGATIVE = 2, + DCLK_INVERT = 3 }; -void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, - int fb_bits_per_pixel, const struct display_timing *edid) +static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, + int fb_bits_per_pixel, + const struct display_timing *edid) { u32 lb_mode; u32 rgb_mode; @@ -89,54 +90,83 @@ void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, writel(0x01, ®s->reg_cfg_done); /* enable reg config */ } -void rkvop_mode_set(struct rk3288_vop *regs, - const struct display_timing *edid, enum vop_modes mode) +static void rkvop_set_pin_polarity(struct udevice *dev, + enum vop_modes mode, u32 polarity) { - u32 hactive = edid->hactive.typ; - u32 vactive = edid->vactive.typ; - u32 hsync_len = edid->hsync_len.typ; - u32 hback_porch = edid->hback_porch.typ; - u32 vsync_len = edid->vsync_len.typ; - u32 vback_porch = edid->vback_porch.typ; - u32 hfront_porch = edid->hfront_porch.typ; - u32 vfront_porch = edid->vfront_porch.typ; - uint flags; - int mode_flags; + struct rkvop_driverdata *ops = + (struct rkvop_driverdata *)dev_get_driver_data(dev); + + if (ops->set_pin_polarity) + ops->set_pin_polarity(dev, mode, polarity); +} + +static void rkvop_enable_output(struct udevice *dev, enum vop_modes mode) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs; switch (mode) { case VOP_MODE_HDMI: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_HDMI_OUT_EN(1)); break; + case VOP_MODE_EDP: - default: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_EDP_OUT_EN(1)); break; + case VOP_MODE_LVDS: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_RGB_OUT_EN(1)); break; + case VOP_MODE_MIPI: clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN, V_MIPI_OUT_EN(1)); - break; + break; + + default: + debug("%s: unsupported output mode %x\n", __func__, mode); } +} - if (mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP) - /* RGBaaa */ - mode_flags = 15; - else - /* RGB888 */ - mode_flags = 0; +static void rkvop_mode_set(struct udevice *dev, + const struct display_timing *edid, + enum vop_modes mode) +{ + struct rk_vop_priv *priv = dev_get_priv(dev); + struct rk3288_vop *regs = priv->regs; + struct rkvop_driverdata *data = + (struct rkvop_driverdata *)dev_get_driver_data(dev); - flags = V_DSP_OUT_MODE(mode_flags) | - V_DSP_HSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_HSYNC_HIGH)) | - V_DSP_VSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_VSYNC_HIGH)); + u32 hactive = edid->hactive.typ; + u32 vactive = edid->vactive.typ; + u32 hsync_len = edid->hsync_len.typ; + u32 hback_porch = edid->hback_porch.typ; + u32 vsync_len = edid->vsync_len.typ; + u32 vback_porch = edid->vback_porch.typ; + u32 hfront_porch = edid->hfront_porch.typ; + u32 vfront_porch = edid->vfront_porch.typ; + int mode_flags; + u32 pin_polarity; + + pin_polarity = BIT(DCLK_INVERT); + if (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH) + pin_polarity |= BIT(HSYNC_POSITIVE); + if (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH) + pin_polarity |= BIT(VSYNC_POSITIVE); + + rkvop_set_pin_polarity(dev, mode, pin_polarity); + rkvop_enable_output(dev, mode); - clrsetbits_le32(®s->dsp_ctrl0, - M_DSP_OUT_MODE | M_DSP_VSYNC_POL | M_DSP_HSYNC_POL, - flags); + mode_flags = 0; /* RGB888 */ + if ((data->features & VOP_FEATURE_OUTPUT_10BIT) && + (mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP)) + mode_flags = 15; /* RGBaaa */ + + clrsetbits_le32(®s->dsp_ctrl0, M_DSP_OUT_MODE, + V_DSP_OUT_MODE(mode_flags)); writel(V_HSYNC(hsync_len) | V_HORPRD(hsync_len + hback_porch + hactive + hfront_porch), @@ -185,7 +215,7 @@ void rkvop_mode_set(struct rk3288_vop *regs, * node within the VOP's 'port' list. * @return 0 if OK, -ve if something went wrong */ -int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) +static int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) { struct video_priv *uc_priv = dev_get_uclass_priv(dev); const void *blob = gd->fdt_blob; @@ -255,18 +285,18 @@ int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) /* Set bitwidth for vop display according to vop mode */ switch (vop_id) { case VOP_MODE_EDP: - case VOP_MODE_HDMI: case VOP_MODE_LVDS: l2bpp = VIDEO_BPP16; break; + case VOP_MODE_HDMI: case VOP_MODE_MIPI: l2bpp = VIDEO_BPP32; break; default: l2bpp = VIDEO_BPP16; } - rkvop_mode_set(regs, &timing, vop_id); + rkvop_mode_set(dev, &timing, vop_id); rkvop_enable(regs, fbbase, 1 << l2bpp, &timing); ret = display_enable(disp, 1 << l2bpp, &timing); @@ -281,53 +311,37 @@ int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node) return 0; } -static int rk_vop_probe(struct udevice *dev) +void rk_vop_probe_regulators(struct udevice *dev, + const char * const *names, int cnt) +{ + int i, ret; + const char *name; + struct udevice *reg; + + for (i = 0; i < cnt; ++i) { + name = names[i]; + debug("%s: probing regulator '%s'\n", dev->name, name); + + ret = regulator_autoset_by_name(name, ®); + if (!ret) + ret = regulator_set_enable(reg, true); + } +} + +int rk_vop_probe(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); const void *blob = gd->fdt_blob; struct rk_vop_priv *priv = dev_get_priv(dev); - struct udevice *reg; - int ret, port, node; + int ret = 0; + int port, node; /* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC)) return 0; - priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); priv->regs = (struct rk3288_vop *)devfdt_get_addr(dev); - /* lcdc(vop) iodomain select 1.8V */ - rk_setreg(&priv->grf->io_vsel, 1 << 0); - - /* - * Try some common regulators. We should really get these from the - * device tree somehow. - */ - ret = regulator_autoset_by_name("vcc18_lcd", ®); - if (ret) - debug("%s: Cannot autoset regulator vcc18_lcd\n", __func__); - ret = regulator_autoset_by_name("VCC18_LCD", ®); - if (ret) - debug("%s: Cannot autoset regulator VCC18_LCD\n", __func__); - ret = regulator_autoset_by_name("vdd10_lcd_pwren_h", ®); - if (ret) { - debug("%s: Cannot autoset regulator vdd10_lcd_pwren_h\n", - __func__); - } - ret = regulator_autoset_by_name("vdd10_lcd", ®); - if (ret) { - debug("%s: Cannot autoset regulator vdd10_lcd\n", - __func__); - } - ret = regulator_autoset_by_name("VDD10_LCD", ®); - if (ret) { - debug("%s: Cannot autoset regulator VDD10_LCD\n", - __func__); - } - ret = regulator_autoset_by_name("vcc33_lcd", ®); - if (ret) - debug("%s: Cannot autoset regulator vcc33_lcd\n", __func__); - /* * Try all the ports until we find one that works. In practice this * tries EDP first if available, then HDMI. @@ -353,31 +367,12 @@ static int rk_vop_probe(struct udevice *dev) return ret; } -static int rk_vop_bind(struct udevice *dev) +int rk_vop_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); - plat->size = 1920 * 1200 * 4; + plat->size = 4 * (CONFIG_VIDEO_ROCKCHIP_MAX_XRES * + CONFIG_VIDEO_ROCKCHIP_MAX_YRES); return 0; } - -static const struct video_ops rk_vop_ops = { -}; - -static const struct udevice_id rk_vop_ids[] = { - { .compatible = "rockchip,rk3399-vop-big" }, - { .compatible = "rockchip,rk3399-vop-lit" }, - { .compatible = "rockchip,rk3288-vop" }, - { } -}; - -U_BOOT_DRIVER(rk_vop) = { - .name = "rk_vop", - .id = UCLASS_VIDEO, - .of_match = rk_vop_ids, - .ops = &rk_vop_ops, - .bind = rk_vop_bind, - .probe = rk_vop_probe, - .priv_auto_alloc_size = sizeof(struct rk_vop_priv), -}; diff --git a/drivers/video/rockchip/rk_vop.h b/drivers/video/rockchip/rk_vop.h new file mode 100644 index 0000000000..9bda51410d --- /dev/null +++ b/drivers/video/rockchip/rk_vop.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RK_VOP_H__ +#define __RK_VOP_H__ + +#include <asm/arch/vop_rk3288.h> + +struct rk_vop_priv { + void *grf; + void *regs; +}; + +enum vop_features { + VOP_FEATURE_OUTPUT_10BIT = (1 << 0), +}; + +struct rkvop_driverdata { + /* configuration */ + u32 features; + /* block-specific setters/getters */ + void (*set_pin_polarity)(struct udevice *, enum vop_modes, u32); +}; + +int rk_vop_probe(struct udevice *dev); +int rk_vop_bind(struct udevice *dev); +void rk_vop_probe_regulators(struct udevice *dev, + const char * const *names, int cnt); + +#endif |