[U-Boot] [PATCH v2 0/8] basic rockchip rk3188 support

Second version. Simon already applied the cleanup patches from my first version. I've tried to address Simons comments and hopefully haven't overlooked any.
SPL is still missing, so following Simons comment from earlier it cannot go in yet, but maybe the first two cleanups can.
changes in v2: - move clock drivers to subdirectory - use already available log2 function in clock drivers - SPDX header in clock bindings - showcase rk3188 arch code and rock board
Heiko Stuebner (10): rockchip: move clock drivers into a subdirectory rockchip: remove log2 reimplementation from clock drivers rockchip: rk3188: Add header files for PMU and GRF rockchip: rk3188: Add pinctrl driver rockchip: rk3188: Bring in rk3066/rk3188 clock bindings rockchip: rk3188: Add clock driver rockchip: rk3188: add core support rockchip: rk3188: Radxa Rock board add unfinished SPL support hacks to make my rock netboot a fit image
arch/arm/dts/Makefile | 1 + arch/arm/dts/rk3188-radxarock.dts | 406 +++++++++++ arch/arm/dts/rk3188.dtsi | 631 ++++++++++++++++++ arch/arm/dts/rk3xxx.dtsi | 431 ++++++++++++ arch/arm/include/asm/arch-rockchip/cru_rk3188.h | 183 +++++ arch/arm/include/asm/arch-rockchip/grf_rk3188.h | 589 ++++++++++++++++ arch/arm/include/asm/arch-rockchip/pmu_rk3188.h | 36 + arch/arm/mach-rockchip/Kconfig | 11 + arch/arm/mach-rockchip/Makefile | 2 + arch/arm/mach-rockchip/rk3188-board-spl.c | 190 ++++++ arch/arm/mach-rockchip/rk3188/Kconfig | 20 + arch/arm/mach-rockchip/rk3188/Makefile | 10 + arch/arm/mach-rockchip/rk3188/clk_rk3188.c | 17 + arch/arm/mach-rockchip/rk3188/reset_rk3188.c | 47 ++ arch/arm/mach-rockchip/rk3188/sdram_rk3188.c | 839 +++++++++++++++++++++++ arch/arm/mach-rockchip/rk3188/syscon_rk3188.c | 24 + board/radxa/rock/Kconfig | 15 + board/radxa/rock/MAINTAINERS | 6 + board/radxa/rock/Makefile | 7 + board/radxa/rock/rock.c | 32 + configs/rock_defconfig | 80 +++ drivers/clk/Makefile | 3 +- drivers/clk/clk_rk3036.c | 386 ----------- drivers/clk/clk_rk3288.c | 851 ------------------------ drivers/clk/rockchip/Makefile | 9 + drivers/clk/rockchip/clk_rk3036.c | 382 +++++++++++ drivers/clk/rockchip/clk_rk3188.c | 493 ++++++++++++++ drivers/clk/rockchip/clk_rk3288.c | 847 +++++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/rockchip/Makefile | 1 + drivers/pinctrl/rockchip/pinctrl_rk3188.c | 613 +++++++++++++++++ drivers/usb/host/dwc2.c | 4 +- include/configs/rk3188_common.h | 109 +++ include/configs/rock.h | 66 ++ include/dt-bindings/clock/rk3066a-cru.h | 32 + include/dt-bindings/clock/rk3188-cru-common.h | 248 +++++++ include/dt-bindings/clock/rk3188-cru.h | 48 ++ tools/rkcommon.c | 1 + 38 files changed, 6438 insertions(+), 1241 deletions(-) create mode 100644 arch/arm/dts/rk3188-radxarock.dts create mode 100644 arch/arm/dts/rk3188.dtsi create mode 100644 arch/arm/dts/rk3xxx.dtsi create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3188.h create mode 100644 arch/arm/include/asm/arch-rockchip/grf_rk3188.h create mode 100644 arch/arm/include/asm/arch-rockchip/pmu_rk3188.h create mode 100644 arch/arm/mach-rockchip/rk3188-board-spl.c create mode 100644 arch/arm/mach-rockchip/rk3188/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3188/Makefile create mode 100644 arch/arm/mach-rockchip/rk3188/clk_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/reset_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/sdram_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/syscon_rk3188.c create mode 100644 board/radxa/rock/Kconfig create mode 100644 board/radxa/rock/MAINTAINERS create mode 100644 board/radxa/rock/Makefile create mode 100644 board/radxa/rock/rock.c create mode 100644 configs/rock_defconfig delete mode 100644 drivers/clk/clk_rk3036.c delete mode 100644 drivers/clk/clk_rk3288.c create mode 100644 drivers/clk/rockchip/Makefile create mode 100644 drivers/clk/rockchip/clk_rk3036.c create mode 100644 drivers/clk/rockchip/clk_rk3188.c create mode 100644 drivers/clk/rockchip/clk_rk3288.c create mode 100644 drivers/pinctrl/rockchip/pinctrl_rk3188.c create mode 100644 include/configs/rk3188_common.h create mode 100644 include/configs/rock.h create mode 100644 include/dt-bindings/clock/rk3066a-cru.h create mode 100644 include/dt-bindings/clock/rk3188-cru-common.h create mode 100644 include/dt-bindings/clock/rk3188-cru.h

With the number of Rockchip clock drivers increasing, don't clutter up the core drivers/clk directory with them and instead move them out of the way into a separate subdirectory.
Suggested-by: Simon Glass sjg@chromium.org Signed-off-by: Heiko Stuebner heiko@sntech.de --- drivers/clk/Makefile | 3 +- drivers/clk/clk_rk3036.c | 386 ----------------- drivers/clk/clk_rk3288.c | 851 -------------------------------------- drivers/clk/rockchip/Makefile | 8 + drivers/clk/rockchip/clk_rk3036.c | 386 +++++++++++++++++ drivers/clk/rockchip/clk_rk3288.c | 851 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1246 insertions(+), 1239 deletions(-) delete mode 100644 drivers/clk/clk_rk3036.c delete mode 100644 drivers/clk/clk_rk3288.c create mode 100644 drivers/clk/rockchip/Makefile create mode 100644 drivers/clk/rockchip/clk_rk3036.c create mode 100644 drivers/clk/rockchip/clk_rk3288.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f7a8891..3cbdd54 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -6,8 +6,7 @@ #
obj-$(CONFIG_CLK) += clk-uclass.o clk_fixed_rate.o -obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o -obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o +obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_SANDBOX) += clk_sandbox.o obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o obj-$(CONFIG_MACH_PIC32) += clk_pic32.o diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c deleted file mode 100644 index 6202c9d..0000000 --- a/drivers/clk/clk_rk3036.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * (C) Copyright 2015 Google, Inc - * - * 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_rk3036.h> -#include <asm/arch/hardware.h> -#include <dm/lists.h> -#include <dt-bindings/clock/rk3036-cru.h> - -DECLARE_GLOBAL_DATA_PTR; - -struct rk3036_clk_priv { - struct rk3036_cru *cru; - ulong rate; -}; - -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 unsigned int log2(unsigned int value) -{ - return fls(value) - 1; -} - -void *rockchip_get_cru(void) -{ - struct udevice *dev; - fdt_addr_t addr; - int ret; - - ret = uclass_get_device(UCLASS_CLK, 0, &dev); - if (ret) - return ERR_PTR(ret); - - addr = dev_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) - return ERR_PTR(-EINVAL); - - return (void *)addr; -} - -static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id, - const struct pll_div *div) -{ - int pll_id = rk_pll_id(clk_id); - struct rk3036_pll *pll = &cru->pll[pll_id]; - - /* All PLLs have same VCO and output frequency range restrictions. */ - uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000; - uint output_hz = vco_hz / div->postdiv1 / div->postdiv2; - - debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, postdiv2=%d,\ - vco=%u Hz, output=%u Hz\n", - pll, div->fbdiv, div->refdiv, div->postdiv1, - div->postdiv2, vco_hz, output_hz); - assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && - output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); - - /* use interger mode */ - rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); - - rk_clrsetreg(&pll->con0, - PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | 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)); - - /* waiting for pll lock */ - while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) - udelay(1); - - return 0; -} - -static void rkclk_init(struct rk3036_cru *cru) -{ - u32 aclk_div; - u32 hclk_div; - u32 pclk_div; - - /* pll enter slow-mode */ - rk_clrsetreg(&cru->cru_mode_con, - GPLL_MODE_MASK << GPLL_MODE_SHIFT | - APLL_MODE_MASK << APLL_MODE_SHIFT, - GPLL_MODE_SLOW << GPLL_MODE_SHIFT | - APLL_MODE_SLOW << APLL_MODE_SHIFT); - - /* init pll */ - rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg); - 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. - * core hz : apll = 1:1 - */ - aclk_div = APLL_HZ / CORE_ACLK_HZ - 1; - assert((aclk_div + 1) * CORE_ACLK_HZ == APLL_HZ && aclk_div < 0x7); - - pclk_div = APLL_HZ / CORE_PERI_HZ - 1; - 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_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, - aclk_div << CORE_ACLK_DIV_SHIFT | - pclk_div << CORE_PERI_DIV_SHIFT); - - /* - * select apll as cpu clock pll 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); - - pclk_div = APLL_HZ / CPU_PCLK_HZ - 1; - assert((pclk_div + 1) * CPU_PCLK_HZ == APLL_HZ && pclk_div < 0x7); - - hclk_div = APLL_HZ / CPU_HCLK_HZ - 1; - assert((hclk_div + 1) * CPU_HCLK_HZ == APLL_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); - - 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); - - /* - * select gpll as peri clock pll source and - * set up dependent divisors for PCLK/HCLK and ACLK clocks. - */ - aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; - assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); - - hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ); - assert((1 << hclk_div) * PERI_HCLK_HZ == - PERI_ACLK_HZ && (pclk_div < 0x4)); - - pclk_div = log2(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_GPLL << PERI_PLL_SEL_SHIFT | - pclk_div << PERI_PCLK_DIV_SHIFT | - hclk_div << PERI_HCLK_DIV_SHIFT | - aclk_div << PERI_ACLK_DIV_SHIFT); - - /* PLL enter normal-mode */ - rk_clrsetreg(&cru->cru_mode_con, - GPLL_MODE_MASK << GPLL_MODE_SHIFT | - APLL_MODE_MASK << APLL_MODE_SHIFT, - GPLL_MODE_NORM << GPLL_MODE_SHIFT | - APLL_MODE_NORM << APLL_MODE_SHIFT); -} - -/* Get pll rate by id */ -static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru, - enum rk_clk_id clk_id) -{ - uint32_t refdiv, fbdiv, postdiv1, postdiv2; - uint32_t con; - int pll_id = rk_pll_id(clk_id); - struct rk3036_pll *pll = &cru->pll[pll_id]; - static u8 clk_shift[CLK_COUNT] = { - 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 - }; - uint shift; - uint mask; - - con = readl(&cru->cru_mode_con); - shift = clk_shift[clk_id]; - mask = clk_mask[clk_id]; - - switch ((con >> shift) & mask) { - 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; - con = readl(&pll->con1); - postdiv2 = (con >> PLL_POSTDIV2_SHIFT) & PLL_POSTDIV2_MASK; - refdiv = (con >> PLL_REFDIV_SHIFT) & PLL_REFDIV_MASK; - return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; - case GPLL_MODE_DEEP: - default: - return 32768; - } -} - -static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate, - int periph) -{ - uint src_rate; - uint div, mux; - u32 con; - - switch (periph) { - case HCLK_EMMC: - con = readl(&cru->cru_clksel_con[12]); - mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK; - div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; - break; - case HCLK_SDIO: - con = readl(&cru->cru_clksel_con[12]); - mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK; - div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; - break; - default: - return -EINVAL; - } - - src_rate = mux == EMMC_SEL_24M ? OSC_HZ : clk_general_rate; - return DIV_TO_RATE(src_rate, div); -} - -static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate, - int periph, uint freq) -{ - int src_clk_div; - int mux; - - debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate); - - /* mmc clock auto divide 2 in internal */ - src_clk_div = (clk_general_rate / 2 + freq - 1) / freq; - - if (src_clk_div > 0x7f) { - src_clk_div = (OSC_HZ / 2 + freq - 1) / freq; - mux = EMMC_SEL_24M; - } else { - mux = EMMC_SEL_GPLL; - } - - switch (periph) { - case HCLK_EMMC: - rk_clrsetreg(&cru->cru_clksel_con[12], - EMMC_PLL_MASK << EMMC_PLL_SHIFT | - EMMC_DIV_MASK << EMMC_DIV_SHIFT, - mux << EMMC_PLL_SHIFT | - (src_clk_div - 1) << EMMC_DIV_SHIFT); - break; - case HCLK_SDIO: - rk_clrsetreg(&cru->cru_clksel_con[11], - MMC0_PLL_MASK << MMC0_PLL_SHIFT | - MMC0_DIV_MASK << MMC0_DIV_SHIFT, - mux << MMC0_PLL_SHIFT | - (src_clk_div - 1) << MMC0_DIV_SHIFT); - break; - default: - return -EINVAL; - } - - return rockchip_mmc_get_clk(cru, clk_general_rate, periph); -} - -static ulong rk3036_clk_get_rate(struct clk *clk) -{ - struct rk3036_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 rk3036_clk_set_rate(struct clk *clk, ulong rate) -{ - struct rk3036_clk_priv *priv = dev_get_priv(clk->dev); - ulong new_rate, gclk_rate; - - gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); - switch (clk->id) { - case 0 ... 63: - return 0; - case HCLK_EMMC: - new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, - clk->id, rate); - break; - default: - return -ENOENT; - } - - return new_rate; -} - -static struct clk_ops rk3036_clk_ops = { - .get_rate = rk3036_clk_get_rate, - .set_rate = rk3036_clk_set_rate, -}; - -static int rk3036_clk_probe(struct udevice *dev) -{ - struct rk3036_clk_priv *priv = dev_get_priv(dev); - - priv->cru = (struct rk3036_cru *)dev_get_addr(dev); - rkclk_init(priv->cru); - - return 0; -} - -static int rk3036_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, "rk3036_sysreset", "reset", &dev); - if (ret) - debug("Warning: No RK3036 reset driver: ret=%d\n", ret); - - return 0; -} - -static const struct udevice_id rk3036_clk_ids[] = { - { .compatible = "rockchip,rk3036-cru" }, - { } -}; - -U_BOOT_DRIVER(clk_rk3036) = { - .name = "clk_rk3036", - .id = UCLASS_CLK, - .of_match = rk3036_clk_ids, - .priv_auto_alloc_size = sizeof(struct rk3036_clk_priv), - .ops = &rk3036_clk_ops, - .bind = rk3036_clk_bind, - .probe = rk3036_clk_probe, -}; diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c deleted file mode 100644 index e00feb0..0000000 --- a/drivers/clk/clk_rk3288.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * (C) Copyright 2015 Google, Inc - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include <common.h> -#include <clk-uclass.h> -#include <dm.h> -#include <dt-structs.h> -#include <errno.h> -#include <mapmem.h> -#include <syscon.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/hardware.h> -#include <dt-bindings/clock/rk3288-cru.h> -#include <dm/device-internal.h> -#include <dm/lists.h> -#include <dm/uclass-internal.h> - -DECLARE_GLOBAL_DATA_PTR; - -struct rk3288_clk_plat { -#if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_rockchip_rk3288_cru dtd; -#endif -}; - -struct rk3288_clk_priv { - struct rk3288_grf *grf; - struct rk3288_cru *cru; - ulong rate; -}; - -struct pll_div { - u32 nr; - u32 nf; - u32 no; -}; - -enum { - VCO_MAX_HZ = 2200U * 1000000, - VCO_MIN_HZ = 440 * 1000000, - OUTPUT_MAX_HZ = 2200U * 1000000, - OUTPUT_MIN_HZ = 27500000, - FREF_MAX_HZ = 2200U * 1000000, - FREF_MIN_HZ = 269 * 1000, -}; - -enum { - /* PLL CON0 */ - PLL_OD_MASK = 0x0f, - - /* PLL CON1 */ - PLL_NF_MASK = 0x1fff, - - /* PLL CON2 */ - PLL_BWADJ_MASK = 0x0fff, - - /* PLL CON3 */ - PLL_RESET_SHIFT = 5, - - /* CLKSEL0 */ - CORE_SEL_PLL_MASK = 1, - CORE_SEL_PLL_SHIFT = 15, - A17_DIV_MASK = 0x1f, - A17_DIV_SHIFT = 8, - MP_DIV_MASK = 0xf, - MP_DIV_SHIFT = 4, - M0_DIV_MASK = 0xf, - M0_DIV_SHIFT = 0, - - /* CLKSEL1: pd bus clk pll sel: codec or general */ - PD_BUS_SEL_PLL_MASK = 15, - PD_BUS_SEL_CPLL = 0, - PD_BUS_SEL_GPLL, - - /* pd bus pclk div: pclk = pd_bus_aclk /(div + 1) */ - PD_BUS_PCLK_DIV_SHIFT = 12, - PD_BUS_PCLK_DIV_MASK = 7, - - /* pd bus hclk div: aclk_bus: hclk_bus = 1:1 or 2:1 or 4:1 */ - PD_BUS_HCLK_DIV_SHIFT = 8, - PD_BUS_HCLK_DIV_MASK = 3, - - /* pd bus aclk div: pd_bus_aclk = pd_bus_src_clk /(div0 * div1) */ - PD_BUS_ACLK_DIV0_SHIFT = 3, - PD_BUS_ACLK_DIV0_MASK = 0x1f, - PD_BUS_ACLK_DIV1_SHIFT = 0, - PD_BUS_ACLK_DIV1_MASK = 0x7, - - /* - * CLKSEL10 - * peripheral bus pclk div: - * aclk_bus: pclk_bus = 1:1 or 2:1 or 4:1 or 8:1 - */ - PERI_SEL_PLL_MASK = 1, - PERI_SEL_PLL_SHIFT = 15, - PERI_SEL_CPLL = 0, - PERI_SEL_GPLL, - - PERI_PCLK_DIV_SHIFT = 12, - PERI_PCLK_DIV_MASK = 3, - - /* peripheral bus hclk div: aclk_bus: hclk_bus = 1:1 or 2:1 or 4:1 */ - PERI_HCLK_DIV_SHIFT = 8, - PERI_HCLK_DIV_MASK = 3, - - /* - * peripheral bus aclk div: - * aclk_periph = periph_clk_src / (peri_aclk_div_con + 1) - */ - PERI_ACLK_DIV_SHIFT = 0, - PERI_ACLK_DIV_MASK = 0x1f, - - SOCSTS_DPLL_LOCK = 1 << 5, - SOCSTS_APLL_LOCK = 1 << 6, - SOCSTS_CPLL_LOCK = 1 << 7, - SOCSTS_GPLL_LOCK = 1 << 8, - SOCSTS_NPLL_LOCK = 1 << 9, -}; - -#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__)); - -/* Keep divisors as low as possible to reduce jitter and power usage */ -static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1); -static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); -static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); - -void *rockchip_get_cru(void) -{ - struct rk3288_clk_priv *priv; - struct udevice *dev; - int ret; - - ret = rockchip_get_clk(&dev); - if (ret) - return ERR_PTR(ret); - - priv = dev_get_priv(dev); - - return priv->cru; -} - -static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id, - const struct pll_div *div) -{ - int pll_id = rk_pll_id(clk_id); - struct rk3288_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 %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", - (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz); - assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && - output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ && - (div->no == 1 || !(div->no % 2))); - - /* enter reset */ - rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT); - - rk_clrsetreg(&pll->con0, - CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK, - ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1)); - rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1); - rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1); - - udelay(10); - - /* return from reset */ - rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT); - - return 0; -} - -static inline unsigned int log2(unsigned int value) -{ - return fls(value) - 1; -} - -static int rkclk_configure_ddr(struct rk3288_cru *cru, struct rk3288_grf *grf, - unsigned int hz) -{ - static const struct pll_div dpll_cfg[] = { - {.nf = 25, .nr = 2, .no = 1}, - {.nf = 400, .nr = 9, .no = 2}, - {.nf = 500, .nr = 9, .no = 2}, - {.nf = 100, .nr = 3, .no = 1}, - }; - int cfg; - - switch (hz) { - case 300000000: - cfg = 0; - break; - case 533000000: /* actually 533.3P MHz */ - cfg = 1; - break; - case 666000000: /* actually 666.6P MHz */ - cfg = 2; - break; - case 800000000: - cfg = 3; - break; - default: - debug("Unsupported SDRAM frequency"); - return -EINVAL; - } - - /* pll enter slow-mode */ - rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT, - DPLL_MODE_SLOW << DPLL_MODE_SHIFT); - - rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]); - - /* wait for pll lock */ - while (!(readl(&grf->soc_status[1]) & SOCSTS_DPLL_LOCK)) - udelay(1); - - /* PLL enter normal-mode */ - rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT, - DPLL_MODE_NORMAL << DPLL_MODE_SHIFT); - - return 0; -} - -#ifndef CONFIG_SPL_BUILD -#define VCO_MAX_KHZ 2200000 -#define VCO_MIN_KHZ 440000 -#define FREF_MAX_KHZ 2200000 -#define FREF_MIN_KHZ 269 - -static int pll_para_config(ulong freq_hz, struct pll_div *div, uint *ext_div) -{ - uint ref_khz = OSC_HZ / 1000, nr, nf = 0; - uint fref_khz; - uint diff_khz, best_diff_khz; - const uint max_nr = 1 << 6, max_nf = 1 << 12, max_no = 1 << 4; - uint vco_khz; - uint no = 1; - uint freq_khz = freq_hz / 1000; - - if (!freq_hz) { - printf("%s: the frequency can not be 0 Hz\n", __func__); - return -EINVAL; - } - - no = DIV_ROUND_UP(VCO_MIN_KHZ, freq_khz); - if (ext_div) { - *ext_div = DIV_ROUND_UP(no, max_no); - no = DIV_ROUND_UP(no, *ext_div); - } - - /* only even divisors (and 1) are supported */ - if (no > 1) - no = DIV_ROUND_UP(no, 2) * 2; - - vco_khz = freq_khz * no; - if (ext_div) - vco_khz *= *ext_div; - - if (vco_khz < VCO_MIN_KHZ || vco_khz > VCO_MAX_KHZ || no > max_no) { - printf("%s: Cannot find out a supported VCO for Frequency (%luHz).\n", - __func__, freq_hz); - return -1; - } - - div->no = no; - - best_diff_khz = vco_khz; - for (nr = 1; nr < max_nr && best_diff_khz; nr++) { - fref_khz = ref_khz / nr; - if (fref_khz < FREF_MIN_KHZ) - break; - if (fref_khz > FREF_MAX_KHZ) - continue; - - nf = vco_khz / fref_khz; - if (nf >= max_nf) - continue; - diff_khz = vco_khz - nf * fref_khz; - if (nf + 1 < max_nf && diff_khz > fref_khz / 2) { - nf++; - diff_khz = fref_khz - diff_khz; - } - - if (diff_khz >= best_diff_khz) - continue; - - best_diff_khz = diff_khz; - div->nr = nr; - div->nf = nf; - } - - if (best_diff_khz > 4 * 1000) { - printf("%s: Failed to match output frequency %lu, difference is %u Hz, exceed 4MHZ\n", - __func__, freq_hz, best_diff_khz * 1000); - return -EINVAL; - } - - return 0; -} - -static int rockchip_mac_set_clk(struct rk3288_cru *cru, - int periph, uint freq) -{ - /* Assuming mac_clk is fed by an external clock */ - rk_clrsetreg(&cru->cru_clksel_con[21], - RMII_EXTCLK_MASK << RMII_EXTCLK_SHIFT, - RMII_EXTCLK_SELECT_EXT_CLK << RMII_EXTCLK_SHIFT); - - return 0; -} - -static int rockchip_vop_set_clk(struct rk3288_cru *cru, struct rk3288_grf *grf, - int periph, unsigned int rate_hz) -{ - struct pll_div npll_config = {0}; - u32 lcdc_div; - int ret; - - ret = pll_para_config(rate_hz, &npll_config, &lcdc_div); - if (ret) - return ret; - - rk_clrsetreg(&cru->cru_mode_con, NPLL_MODE_MASK << NPLL_MODE_SHIFT, - NPLL_MODE_SLOW << NPLL_MODE_SHIFT); - rkclk_set_pll(cru, CLK_NEW, &npll_config); - - /* waiting for pll lock */ - while (1) { - if (readl(&grf->soc_status[1]) & SOCSTS_NPLL_LOCK) - break; - udelay(1); - } - - rk_clrsetreg(&cru->cru_mode_con, NPLL_MODE_MASK << NPLL_MODE_SHIFT, - NPLL_MODE_NORMAL << NPLL_MODE_SHIFT); - - /* vop dclk source clk: npll,dclk_div: 1 */ - switch (periph) { - case DCLK_VOP0: - rk_clrsetreg(&cru->cru_clksel_con[27], 0xff << 8 | 3 << 0, - (lcdc_div - 1) << 8 | 2 << 0); - break; - case DCLK_VOP1: - rk_clrsetreg(&cru->cru_clksel_con[29], 0xff << 8 | 3 << 6, - (lcdc_div - 1) << 8 | 2 << 6); - break; - } - - return 0; -} -#endif - -#ifdef CONFIG_SPL_BUILD -static void rkclk_init(struct rk3288_cru *cru, struct rk3288_grf *grf) -{ - u32 aclk_div; - u32 hclk_div; - u32 pclk_div; - - /* pll enter slow-mode */ - rk_clrsetreg(&cru->cru_mode_con, - GPLL_MODE_MASK << GPLL_MODE_SHIFT | - CPLL_MODE_MASK << CPLL_MODE_SHIFT, - GPLL_MODE_SLOW << GPLL_MODE_SHIFT | - CPLL_MODE_SLOW << CPLL_MODE_SHIFT); - - /* init pll */ - rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); - rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg); - - /* waiting for pll lock */ - while ((readl(&grf->soc_status[1]) & - (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) != - (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) - udelay(1); - - /* - * pd_bus clock pll source selection and - * set up dependent divisors for PCLK/HCLK and ACLK clocks. - */ - aclk_div = GPLL_HZ / PD_BUS_ACLK_HZ - 1; - assert((aclk_div + 1) * PD_BUS_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); - hclk_div = PD_BUS_ACLK_HZ / PD_BUS_HCLK_HZ - 1; - assert((hclk_div + 1) * PD_BUS_HCLK_HZ == - PD_BUS_ACLK_HZ && (hclk_div < 0x4) && (hclk_div != 0x2)); - - pclk_div = PD_BUS_ACLK_HZ / PD_BUS_PCLK_HZ - 1; - assert((pclk_div + 1) * PD_BUS_PCLK_HZ == - PD_BUS_ACLK_HZ && pclk_div < 0x7); - - rk_clrsetreg(&cru->cru_clksel_con[1], - PD_BUS_PCLK_DIV_MASK << PD_BUS_PCLK_DIV_SHIFT | - PD_BUS_HCLK_DIV_MASK << PD_BUS_HCLK_DIV_SHIFT | - PD_BUS_ACLK_DIV0_MASK << PD_BUS_ACLK_DIV0_SHIFT | - PD_BUS_ACLK_DIV1_MASK << PD_BUS_ACLK_DIV1_SHIFT, - pclk_div << PD_BUS_PCLK_DIV_SHIFT | - hclk_div << PD_BUS_HCLK_DIV_SHIFT | - aclk_div << PD_BUS_ACLK_DIV0_SHIFT | - 0 << 0); - - /* - * peri clock pll source selection and - * set up dependent divisors for PCLK/HCLK and ACLK clocks. - */ - aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; - assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); - - hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ); - assert((1 << hclk_div) * PERI_HCLK_HZ == - PERI_ACLK_HZ && (hclk_div < 0x4)); - - pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ); - assert((1 << pclk_div) * PERI_PCLK_HZ == - PERI_ACLK_HZ && (pclk_div < 0x4)); - - rk_clrsetreg(&cru->cru_clksel_con[10], - 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_SEL_GPLL << PERI_SEL_PLL_SHIFT | - pclk_div << PERI_PCLK_DIV_SHIFT | - hclk_div << PERI_HCLK_DIV_SHIFT | - aclk_div << PERI_ACLK_DIV_SHIFT); - - /* PLL enter normal-mode */ - rk_clrsetreg(&cru->cru_mode_con, - GPLL_MODE_MASK << GPLL_MODE_SHIFT | - CPLL_MODE_MASK << CPLL_MODE_SHIFT, - GPLL_MODE_NORMAL << GPLL_MODE_SHIFT | - CPLL_MODE_NORMAL << CPLL_MODE_SHIFT); -} -#endif - -void rk3288_clk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf) -{ - /* pll enter slow-mode */ - rk_clrsetreg(&cru->cru_mode_con, - APLL_MODE_MASK << APLL_MODE_SHIFT, - APLL_MODE_SLOW << APLL_MODE_SHIFT); - - rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg); - - /* waiting for pll lock */ - while (!(readl(&grf->soc_status[1]) & SOCSTS_APLL_LOCK)) - udelay(1); - - /* - * core clock pll source selection and - * set up dependent divisors for MPAXI/M0AXI and ARM clocks. - * core clock select apll, apll clk = 1800MHz - * arm clk = 1800MHz, mpclk = 450MHz, m0clk = 900MHz - */ - rk_clrsetreg(&cru->cru_clksel_con[0], - CORE_SEL_PLL_MASK << CORE_SEL_PLL_SHIFT | - A17_DIV_MASK << A17_DIV_SHIFT | - MP_DIV_MASK << MP_DIV_SHIFT | - M0_DIV_MASK << M0_DIV_SHIFT, - 0 << A17_DIV_SHIFT | - 3 << MP_DIV_SHIFT | - 1 << M0_DIV_SHIFT); - - /* - * set up dependent divisors for L2RAM/ATCLK and PCLK clocks. - * l2ramclk = 900MHz, atclk = 450MHz, pclk_dbg = 450MHz - */ - rk_clrsetreg(&cru->cru_clksel_con[37], - CLK_L2RAM_DIV_MASK << CLK_L2RAM_DIV_SHIFT | - ATCLK_CORE_DIV_CON_MASK << ATCLK_CORE_DIV_CON_SHIFT | - PCLK_CORE_DBG_DIV_MASK >> PCLK_CORE_DBG_DIV_SHIFT, - 1 << CLK_L2RAM_DIV_SHIFT | - 3 << ATCLK_CORE_DIV_CON_SHIFT | - 3 << PCLK_CORE_DBG_DIV_SHIFT); - - /* PLL enter normal-mode */ - rk_clrsetreg(&cru->cru_mode_con, - APLL_MODE_MASK << APLL_MODE_SHIFT, - APLL_MODE_NORMAL << APLL_MODE_SHIFT); -} - -/* Get pll rate by id */ -static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru, - enum rk_clk_id clk_id) -{ - uint32_t nr, no, nf; - uint32_t con; - int pll_id = rk_pll_id(clk_id); - struct rk3288_pll *pll = &cru->pll[pll_id]; - static u8 clk_shift[CLK_COUNT] = { - 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, - GPLL_MODE_SHIFT, NPLL_MODE_SHIFT - }; - uint shift; - - con = readl(&cru->cru_mode_con); - shift = clk_shift[clk_id]; - switch ((con >> shift) & APLL_MODE_MASK) { - case APLL_MODE_SLOW: - return OSC_HZ; - case APLL_MODE_NORMAL: - /* normal mode */ - con = readl(&pll->con0); - no = ((con >> CLKOD_SHIFT) & CLKOD_MASK) + 1; - nr = ((con >> CLKR_SHIFT) & CLKR_MASK) + 1; - con = readl(&pll->con1); - nf = ((con >> CLKF_SHIFT) & CLKF_MASK) + 1; - - return (24 * nf / (nr * no)) * 1000000; - case APLL_MODE_DEEP: - default: - return 32768; - } -} - -static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate, - int periph) -{ - uint src_rate; - uint div, mux; - u32 con; - - switch (periph) { - case HCLK_EMMC: - con = readl(&cru->cru_clksel_con[12]); - mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK; - div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; - break; - case HCLK_SDMMC: - con = readl(&cru->cru_clksel_con[11]); - mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK; - div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; - break; - case HCLK_SDIO0: - con = readl(&cru->cru_clksel_con[12]); - mux = (con >> SDIO0_PLL_SHIFT) & SDIO0_PLL_MASK; - div = (con >> SDIO0_DIV_SHIFT) & SDIO0_DIV_MASK; - break; - default: - return -EINVAL; - } - - src_rate = mux == EMMC_PLL_SELECT_24MHZ ? OSC_HZ : gclk_rate; - return DIV_TO_RATE(src_rate, div); -} - -static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate, - int periph, uint freq) -{ - int src_clk_div; - int mux; - - debug("%s: gclk_rate=%u\n", __func__, gclk_rate); - src_clk_div = RATE_TO_DIV(gclk_rate, freq); - - if (src_clk_div > 0x3f) { - src_clk_div = RATE_TO_DIV(OSC_HZ, freq); - mux = EMMC_PLL_SELECT_24MHZ; - assert((int)EMMC_PLL_SELECT_24MHZ == - (int)MMC0_PLL_SELECT_24MHZ); - } else { - mux = EMMC_PLL_SELECT_GENERAL; - assert((int)EMMC_PLL_SELECT_GENERAL == - (int)MMC0_PLL_SELECT_GENERAL); - } - switch (periph) { - case HCLK_EMMC: - rk_clrsetreg(&cru->cru_clksel_con[12], - EMMC_PLL_MASK << EMMC_PLL_SHIFT | - EMMC_DIV_MASK << EMMC_DIV_SHIFT, - mux << EMMC_PLL_SHIFT | - (src_clk_div - 1) << EMMC_DIV_SHIFT); - break; - case HCLK_SDMMC: - rk_clrsetreg(&cru->cru_clksel_con[11], - MMC0_PLL_MASK << MMC0_PLL_SHIFT | - MMC0_DIV_MASK << MMC0_DIV_SHIFT, - mux << MMC0_PLL_SHIFT | - (src_clk_div - 1) << MMC0_DIV_SHIFT); - break; - case HCLK_SDIO0: - rk_clrsetreg(&cru->cru_clksel_con[12], - SDIO0_PLL_MASK << SDIO0_PLL_SHIFT | - SDIO0_DIV_MASK << SDIO0_DIV_SHIFT, - mux << SDIO0_PLL_SHIFT | - (src_clk_div - 1) << SDIO0_DIV_SHIFT); - break; - default: - return -EINVAL; - } - - return rockchip_mmc_get_clk(cru, gclk_rate, periph); -} - -static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint gclk_rate, - int periph) -{ - uint div, mux; - u32 con; - - switch (periph) { - case SCLK_SPI0: - con = readl(&cru->cru_clksel_con[25]); - mux = (con >> SPI0_PLL_SHIFT) & SPI0_PLL_MASK; - div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK; - break; - case SCLK_SPI1: - con = readl(&cru->cru_clksel_con[25]); - mux = (con >> SPI1_PLL_SHIFT) & SPI1_PLL_MASK; - div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK; - break; - case SCLK_SPI2: - con = readl(&cru->cru_clksel_con[39]); - mux = (con >> SPI2_PLL_SHIFT) & SPI2_PLL_MASK; - div = (con >> SPI2_DIV_SHIFT) & SPI2_DIV_MASK; - break; - default: - return -EINVAL; - } - assert(mux == SPI0_PLL_SELECT_GENERAL); - - return DIV_TO_RATE(gclk_rate, div); -} - -static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate, - int periph, uint freq) -{ - int src_clk_div; - - debug("%s: clk_general_rate=%u\n", __func__, gclk_rate); - src_clk_div = RATE_TO_DIV(gclk_rate, freq); - switch (periph) { - case SCLK_SPI0: - rk_clrsetreg(&cru->cru_clksel_con[25], - SPI0_PLL_MASK << SPI0_PLL_SHIFT | - SPI0_DIV_MASK << SPI0_DIV_SHIFT, - SPI0_PLL_SELECT_GENERAL << SPI0_PLL_SHIFT | - src_clk_div << SPI0_DIV_SHIFT); - break; - case SCLK_SPI1: - rk_clrsetreg(&cru->cru_clksel_con[25], - SPI1_PLL_MASK << SPI1_PLL_SHIFT | - SPI1_DIV_MASK << SPI1_DIV_SHIFT, - SPI1_PLL_SELECT_GENERAL << SPI1_PLL_SHIFT | - src_clk_div << SPI1_DIV_SHIFT); - break; - case SCLK_SPI2: - rk_clrsetreg(&cru->cru_clksel_con[39], - SPI2_PLL_MASK << SPI2_PLL_SHIFT | - SPI2_DIV_MASK << SPI2_DIV_SHIFT, - SPI2_PLL_SELECT_GENERAL << SPI2_PLL_SHIFT | - src_clk_div << SPI2_DIV_SHIFT); - break; - default: - return -EINVAL; - } - - return rockchip_spi_get_clk(cru, gclk_rate, periph); -} - -static ulong rk3288_clk_get_rate(struct clk *clk) -{ - struct rk3288_clk_priv *priv = dev_get_priv(clk->dev); - ulong new_rate, gclk_rate; - - gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); - switch (clk->id) { - case 0 ... 63: - new_rate = rkclk_pll_get_rate(priv->cru, clk->id); - break; - case HCLK_EMMC: - case HCLK_SDMMC: - case HCLK_SDIO0: - new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id); - break; - case SCLK_SPI0: - case SCLK_SPI1: - case SCLK_SPI2: - new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, clk->id); - break; - case PCLK_I2C0: - case PCLK_I2C1: - case PCLK_I2C2: - case PCLK_I2C3: - case PCLK_I2C4: - case PCLK_I2C5: - return gclk_rate; - default: - return -ENOENT; - } - - return new_rate; -} - -static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate) -{ - struct rk3288_clk_priv *priv = dev_get_priv(clk->dev); - struct rk3288_cru *cru = priv->cru; - ulong new_rate, gclk_rate; - - gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); - switch (clk->id) { - case CLK_DDR: - new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate); - break; - case HCLK_EMMC: - case HCLK_SDMMC: - case HCLK_SDIO0: - new_rate = rockchip_mmc_set_clk(cru, gclk_rate, clk->id, rate); - break; - case SCLK_SPI0: - case SCLK_SPI1: - case SCLK_SPI2: - new_rate = rockchip_spi_set_clk(cru, gclk_rate, clk->id, rate); - break; -#ifndef CONFIG_SPL_BUILD - case SCLK_MAC: - new_rate = rockchip_mac_set_clk(priv->cru, clk->id, rate); - break; - case DCLK_VOP0: - case DCLK_VOP1: - new_rate = rockchip_vop_set_clk(cru, priv->grf, clk->id, rate); - break; - case SCLK_EDP_24M: - /* clk_edp_24M source: 24M */ - rk_setreg(&cru->cru_clksel_con[28], 1 << 15); - - /* rst edp */ - rk_setreg(&cru->cru_clksel_con[6], 1 << 15); - udelay(1); - rk_clrreg(&cru->cru_clksel_con[6], 1 << 15); - new_rate = rate; - break; - case ACLK_VOP0: - case ACLK_VOP1: { - u32 div; - - /* vop aclk source clk: cpll */ - div = CPLL_HZ / rate; - assert((div - 1 < 64) && (div * rate == CPLL_HZ)); - - switch (clk->id) { - case ACLK_VOP0: - rk_clrsetreg(&cru->cru_clksel_con[31], - 3 << 6 | 0x1f << 0, - 0 << 6 | (div - 1) << 0); - break; - case ACLK_VOP1: - rk_clrsetreg(&cru->cru_clksel_con[31], - 3 << 14 | 0x1f << 8, - 0 << 14 | (div - 1) << 8); - break; - } - new_rate = rate; - break; - } - case PCLK_HDMI_CTRL: - /* enable pclk hdmi ctrl */ - rk_clrreg(&cru->cru_clkgate_con[16], 1 << 9); - - /* software reset hdmi */ - rk_setreg(&cru->cru_clkgate_con[7], 1 << 9); - udelay(1); - rk_clrreg(&cru->cru_clkgate_con[7], 1 << 9); - new_rate = rate; - break; -#endif - default: - return -ENOENT; - } - - return new_rate; -} - -static struct clk_ops rk3288_clk_ops = { - .get_rate = rk3288_clk_get_rate, - .set_rate = rk3288_clk_set_rate, -}; - -static int rk3288_clk_ofdata_to_platdata(struct udevice *dev) -{ -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - struct rk3288_clk_priv *priv = dev_get_priv(dev); - - priv->cru = (struct rk3288_cru *)dev_get_addr(dev); -#endif - - return 0; -} - -static int rk3288_clk_probe(struct udevice *dev) -{ - struct rk3288_clk_priv *priv = dev_get_priv(dev); - - priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); - if (IS_ERR(priv->grf)) - return PTR_ERR(priv->grf); -#ifdef CONFIG_SPL_BUILD -#if CONFIG_IS_ENABLED(OF_PLATDATA) - struct rk3288_clk_plat *plat = dev_get_platdata(dev); - - priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); -#endif - rkclk_init(priv->cru, priv->grf); -#endif - - return 0; -} - -static int rk3288_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, "rk3288_sysreset", "reset", &dev); - if (ret) - debug("Warning: No RK3288 reset driver: ret=%d\n", ret); - - return 0; -} - -static const struct udevice_id rk3288_clk_ids[] = { - { .compatible = "rockchip,rk3288-cru" }, - { } -}; - -U_BOOT_DRIVER(rockchip_rk3288_cru) = { - .name = "rockchip_rk3288_cru", - .id = UCLASS_CLK, - .of_match = rk3288_clk_ids, - .priv_auto_alloc_size = sizeof(struct rk3288_clk_priv), - .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat), - .ops = &rk3288_clk_ops, - .bind = rk3288_clk_bind, - .ofdata_to_platdata = rk3288_clk_ofdata_to_platdata, - .probe = rk3288_clk_probe, -}; diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile new file mode 100644 index 0000000..acfd858 --- /dev/null +++ b/drivers/clk/rockchip/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o +obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c new file mode 100644 index 0000000..6202c9d --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3036.c @@ -0,0 +1,386 @@ +/* + * (C) Copyright 2015 Google, Inc + * + * 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_rk3036.h> +#include <asm/arch/hardware.h> +#include <dm/lists.h> +#include <dt-bindings/clock/rk3036-cru.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct rk3036_clk_priv { + struct rk3036_cru *cru; + ulong rate; +}; + +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 unsigned int log2(unsigned int value) +{ + return fls(value) - 1; +} + +void *rockchip_get_cru(void) +{ + struct udevice *dev; + fdt_addr_t addr; + int ret; + + ret = uclass_get_device(UCLASS_CLK, 0, &dev); + if (ret) + return ERR_PTR(ret); + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return ERR_PTR(-EINVAL); + + return (void *)addr; +} + +static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id, + const struct pll_div *div) +{ + int pll_id = rk_pll_id(clk_id); + struct rk3036_pll *pll = &cru->pll[pll_id]; + + /* All PLLs have same VCO and output frequency range restrictions. */ + uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000; + uint output_hz = vco_hz / div->postdiv1 / div->postdiv2; + + debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, postdiv2=%d,\ + vco=%u Hz, output=%u Hz\n", + pll, div->fbdiv, div->refdiv, div->postdiv1, + div->postdiv2, vco_hz, output_hz); + assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && + output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); + + /* use interger mode */ + rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); + + rk_clrsetreg(&pll->con0, + PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | 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)); + + /* waiting for pll lock */ + while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) + udelay(1); + + return 0; +} + +static void rkclk_init(struct rk3036_cru *cru) +{ + u32 aclk_div; + u32 hclk_div; + u32 pclk_div; + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK << GPLL_MODE_SHIFT | + APLL_MODE_MASK << APLL_MODE_SHIFT, + GPLL_MODE_SLOW << GPLL_MODE_SHIFT | + APLL_MODE_SLOW << APLL_MODE_SHIFT); + + /* init pll */ + rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg); + 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. + * core hz : apll = 1:1 + */ + aclk_div = APLL_HZ / CORE_ACLK_HZ - 1; + assert((aclk_div + 1) * CORE_ACLK_HZ == APLL_HZ && aclk_div < 0x7); + + pclk_div = APLL_HZ / CORE_PERI_HZ - 1; + 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_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, + aclk_div << CORE_ACLK_DIV_SHIFT | + pclk_div << CORE_PERI_DIV_SHIFT); + + /* + * select apll as cpu clock pll 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); + + pclk_div = APLL_HZ / CPU_PCLK_HZ - 1; + assert((pclk_div + 1) * CPU_PCLK_HZ == APLL_HZ && pclk_div < 0x7); + + hclk_div = APLL_HZ / CPU_HCLK_HZ - 1; + assert((hclk_div + 1) * CPU_HCLK_HZ == APLL_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); + + 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); + + /* + * select gpll as peri clock pll source and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; + assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); + + hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ); + assert((1 << hclk_div) * PERI_HCLK_HZ == + PERI_ACLK_HZ && (pclk_div < 0x4)); + + pclk_div = log2(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_GPLL << PERI_PLL_SEL_SHIFT | + pclk_div << PERI_PCLK_DIV_SHIFT | + hclk_div << PERI_HCLK_DIV_SHIFT | + aclk_div << PERI_ACLK_DIV_SHIFT); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK << GPLL_MODE_SHIFT | + APLL_MODE_MASK << APLL_MODE_SHIFT, + GPLL_MODE_NORM << GPLL_MODE_SHIFT | + APLL_MODE_NORM << APLL_MODE_SHIFT); +} + +/* Get pll rate by id */ +static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru, + enum rk_clk_id clk_id) +{ + uint32_t refdiv, fbdiv, postdiv1, postdiv2; + uint32_t con; + int pll_id = rk_pll_id(clk_id); + struct rk3036_pll *pll = &cru->pll[pll_id]; + static u8 clk_shift[CLK_COUNT] = { + 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 + }; + uint shift; + uint mask; + + con = readl(&cru->cru_mode_con); + shift = clk_shift[clk_id]; + mask = clk_mask[clk_id]; + + switch ((con >> shift) & mask) { + 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; + con = readl(&pll->con1); + postdiv2 = (con >> PLL_POSTDIV2_SHIFT) & PLL_POSTDIV2_MASK; + refdiv = (con >> PLL_REFDIV_SHIFT) & PLL_REFDIV_MASK; + return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; + case GPLL_MODE_DEEP: + default: + return 32768; + } +} + +static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate, + int periph) +{ + uint src_rate; + uint div, mux; + u32 con; + + switch (periph) { + case HCLK_EMMC: + con = readl(&cru->cru_clksel_con[12]); + mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK; + div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; + break; + case HCLK_SDIO: + con = readl(&cru->cru_clksel_con[12]); + mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK; + div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; + break; + default: + return -EINVAL; + } + + src_rate = mux == EMMC_SEL_24M ? OSC_HZ : clk_general_rate; + return DIV_TO_RATE(src_rate, div); +} + +static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate, + int periph, uint freq) +{ + int src_clk_div; + int mux; + + debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate); + + /* mmc clock auto divide 2 in internal */ + src_clk_div = (clk_general_rate / 2 + freq - 1) / freq; + + if (src_clk_div > 0x7f) { + src_clk_div = (OSC_HZ / 2 + freq - 1) / freq; + mux = EMMC_SEL_24M; + } else { + mux = EMMC_SEL_GPLL; + } + + switch (periph) { + case HCLK_EMMC: + rk_clrsetreg(&cru->cru_clksel_con[12], + EMMC_PLL_MASK << EMMC_PLL_SHIFT | + EMMC_DIV_MASK << EMMC_DIV_SHIFT, + mux << EMMC_PLL_SHIFT | + (src_clk_div - 1) << EMMC_DIV_SHIFT); + break; + case HCLK_SDIO: + rk_clrsetreg(&cru->cru_clksel_con[11], + MMC0_PLL_MASK << MMC0_PLL_SHIFT | + MMC0_DIV_MASK << MMC0_DIV_SHIFT, + mux << MMC0_PLL_SHIFT | + (src_clk_div - 1) << MMC0_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_mmc_get_clk(cru, clk_general_rate, periph); +} + +static ulong rk3036_clk_get_rate(struct clk *clk) +{ + struct rk3036_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 rk3036_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3036_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate, gclk_rate; + + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 0 ... 63: + return 0; + case HCLK_EMMC: + new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, + clk->id, rate); + break; + default: + return -ENOENT; + } + + return new_rate; +} + +static struct clk_ops rk3036_clk_ops = { + .get_rate = rk3036_clk_get_rate, + .set_rate = rk3036_clk_set_rate, +}; + +static int rk3036_clk_probe(struct udevice *dev) +{ + struct rk3036_clk_priv *priv = dev_get_priv(dev); + + priv->cru = (struct rk3036_cru *)dev_get_addr(dev); + rkclk_init(priv->cru); + + return 0; +} + +static int rk3036_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, "rk3036_sysreset", "reset", &dev); + if (ret) + debug("Warning: No RK3036 reset driver: ret=%d\n", ret); + + return 0; +} + +static const struct udevice_id rk3036_clk_ids[] = { + { .compatible = "rockchip,rk3036-cru" }, + { } +}; + +U_BOOT_DRIVER(clk_rk3036) = { + .name = "clk_rk3036", + .id = UCLASS_CLK, + .of_match = rk3036_clk_ids, + .priv_auto_alloc_size = sizeof(struct rk3036_clk_priv), + .ops = &rk3036_clk_ops, + .bind = rk3036_clk_bind, + .probe = rk3036_clk_probe, +}; diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c new file mode 100644 index 0000000..e00feb0 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3288.c @@ -0,0 +1,851 @@ +/* + * (C) Copyright 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dt-structs.h> +#include <errno.h> +#include <mapmem.h> +#include <syscon.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/hardware.h> +#include <dt-bindings/clock/rk3288-cru.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct rk3288_clk_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_cru dtd; +#endif +}; + +struct rk3288_clk_priv { + struct rk3288_grf *grf; + struct rk3288_cru *cru; + ulong rate; +}; + +struct pll_div { + u32 nr; + u32 nf; + u32 no; +}; + +enum { + VCO_MAX_HZ = 2200U * 1000000, + VCO_MIN_HZ = 440 * 1000000, + OUTPUT_MAX_HZ = 2200U * 1000000, + OUTPUT_MIN_HZ = 27500000, + FREF_MAX_HZ = 2200U * 1000000, + FREF_MIN_HZ = 269 * 1000, +}; + +enum { + /* PLL CON0 */ + PLL_OD_MASK = 0x0f, + + /* PLL CON1 */ + PLL_NF_MASK = 0x1fff, + + /* PLL CON2 */ + PLL_BWADJ_MASK = 0x0fff, + + /* PLL CON3 */ + PLL_RESET_SHIFT = 5, + + /* CLKSEL0 */ + CORE_SEL_PLL_MASK = 1, + CORE_SEL_PLL_SHIFT = 15, + A17_DIV_MASK = 0x1f, + A17_DIV_SHIFT = 8, + MP_DIV_MASK = 0xf, + MP_DIV_SHIFT = 4, + M0_DIV_MASK = 0xf, + M0_DIV_SHIFT = 0, + + /* CLKSEL1: pd bus clk pll sel: codec or general */ + PD_BUS_SEL_PLL_MASK = 15, + PD_BUS_SEL_CPLL = 0, + PD_BUS_SEL_GPLL, + + /* pd bus pclk div: pclk = pd_bus_aclk /(div + 1) */ + PD_BUS_PCLK_DIV_SHIFT = 12, + PD_BUS_PCLK_DIV_MASK = 7, + + /* pd bus hclk div: aclk_bus: hclk_bus = 1:1 or 2:1 or 4:1 */ + PD_BUS_HCLK_DIV_SHIFT = 8, + PD_BUS_HCLK_DIV_MASK = 3, + + /* pd bus aclk div: pd_bus_aclk = pd_bus_src_clk /(div0 * div1) */ + PD_BUS_ACLK_DIV0_SHIFT = 3, + PD_BUS_ACLK_DIV0_MASK = 0x1f, + PD_BUS_ACLK_DIV1_SHIFT = 0, + PD_BUS_ACLK_DIV1_MASK = 0x7, + + /* + * CLKSEL10 + * peripheral bus pclk div: + * aclk_bus: pclk_bus = 1:1 or 2:1 or 4:1 or 8:1 + */ + PERI_SEL_PLL_MASK = 1, + PERI_SEL_PLL_SHIFT = 15, + PERI_SEL_CPLL = 0, + PERI_SEL_GPLL, + + PERI_PCLK_DIV_SHIFT = 12, + PERI_PCLK_DIV_MASK = 3, + + /* peripheral bus hclk div: aclk_bus: hclk_bus = 1:1 or 2:1 or 4:1 */ + PERI_HCLK_DIV_SHIFT = 8, + PERI_HCLK_DIV_MASK = 3, + + /* + * peripheral bus aclk div: + * aclk_periph = periph_clk_src / (peri_aclk_div_con + 1) + */ + PERI_ACLK_DIV_SHIFT = 0, + PERI_ACLK_DIV_MASK = 0x1f, + + SOCSTS_DPLL_LOCK = 1 << 5, + SOCSTS_APLL_LOCK = 1 << 6, + SOCSTS_CPLL_LOCK = 1 << 7, + SOCSTS_GPLL_LOCK = 1 << 8, + SOCSTS_NPLL_LOCK = 1 << 9, +}; + +#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__)); + +/* Keep divisors as low as possible to reduce jitter and power usage */ +static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1); +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); +static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); + +void *rockchip_get_cru(void) +{ + struct rk3288_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rockchip_get_clk(&dev); + if (ret) + return ERR_PTR(ret); + + priv = dev_get_priv(dev); + + return priv->cru; +} + +static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id, + const struct pll_div *div) +{ + int pll_id = rk_pll_id(clk_id); + struct rk3288_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 %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", + (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz); + assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && + output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ && + (div->no == 1 || !(div->no % 2))); + + /* enter reset */ + rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT); + + rk_clrsetreg(&pll->con0, + CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK, + ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1)); + rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1); + rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1); + + udelay(10); + + /* return from reset */ + rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT); + + return 0; +} + +static inline unsigned int log2(unsigned int value) +{ + return fls(value) - 1; +} + +static int rkclk_configure_ddr(struct rk3288_cru *cru, struct rk3288_grf *grf, + unsigned int hz) +{ + static const struct pll_div dpll_cfg[] = { + {.nf = 25, .nr = 2, .no = 1}, + {.nf = 400, .nr = 9, .no = 2}, + {.nf = 500, .nr = 9, .no = 2}, + {.nf = 100, .nr = 3, .no = 1}, + }; + int cfg; + + switch (hz) { + case 300000000: + cfg = 0; + break; + case 533000000: /* actually 533.3P MHz */ + cfg = 1; + break; + case 666000000: /* actually 666.6P MHz */ + cfg = 2; + break; + case 800000000: + cfg = 3; + break; + default: + debug("Unsupported SDRAM frequency"); + return -EINVAL; + } + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT, + DPLL_MODE_SLOW << DPLL_MODE_SHIFT); + + rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]); + + /* wait for pll lock */ + while (!(readl(&grf->soc_status[1]) & SOCSTS_DPLL_LOCK)) + udelay(1); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT, + DPLL_MODE_NORMAL << DPLL_MODE_SHIFT); + + return 0; +} + +#ifndef CONFIG_SPL_BUILD +#define VCO_MAX_KHZ 2200000 +#define VCO_MIN_KHZ 440000 +#define FREF_MAX_KHZ 2200000 +#define FREF_MIN_KHZ 269 + +static int pll_para_config(ulong freq_hz, struct pll_div *div, uint *ext_div) +{ + uint ref_khz = OSC_HZ / 1000, nr, nf = 0; + uint fref_khz; + uint diff_khz, best_diff_khz; + const uint max_nr = 1 << 6, max_nf = 1 << 12, max_no = 1 << 4; + uint vco_khz; + uint no = 1; + uint freq_khz = freq_hz / 1000; + + if (!freq_hz) { + printf("%s: the frequency can not be 0 Hz\n", __func__); + return -EINVAL; + } + + no = DIV_ROUND_UP(VCO_MIN_KHZ, freq_khz); + if (ext_div) { + *ext_div = DIV_ROUND_UP(no, max_no); + no = DIV_ROUND_UP(no, *ext_div); + } + + /* only even divisors (and 1) are supported */ + if (no > 1) + no = DIV_ROUND_UP(no, 2) * 2; + + vco_khz = freq_khz * no; + if (ext_div) + vco_khz *= *ext_div; + + if (vco_khz < VCO_MIN_KHZ || vco_khz > VCO_MAX_KHZ || no > max_no) { + printf("%s: Cannot find out a supported VCO for Frequency (%luHz).\n", + __func__, freq_hz); + return -1; + } + + div->no = no; + + best_diff_khz = vco_khz; + for (nr = 1; nr < max_nr && best_diff_khz; nr++) { + fref_khz = ref_khz / nr; + if (fref_khz < FREF_MIN_KHZ) + break; + if (fref_khz > FREF_MAX_KHZ) + continue; + + nf = vco_khz / fref_khz; + if (nf >= max_nf) + continue; + diff_khz = vco_khz - nf * fref_khz; + if (nf + 1 < max_nf && diff_khz > fref_khz / 2) { + nf++; + diff_khz = fref_khz - diff_khz; + } + + if (diff_khz >= best_diff_khz) + continue; + + best_diff_khz = diff_khz; + div->nr = nr; + div->nf = nf; + } + + if (best_diff_khz > 4 * 1000) { + printf("%s: Failed to match output frequency %lu, difference is %u Hz, exceed 4MHZ\n", + __func__, freq_hz, best_diff_khz * 1000); + return -EINVAL; + } + + return 0; +} + +static int rockchip_mac_set_clk(struct rk3288_cru *cru, + int periph, uint freq) +{ + /* Assuming mac_clk is fed by an external clock */ + rk_clrsetreg(&cru->cru_clksel_con[21], + RMII_EXTCLK_MASK << RMII_EXTCLK_SHIFT, + RMII_EXTCLK_SELECT_EXT_CLK << RMII_EXTCLK_SHIFT); + + return 0; +} + +static int rockchip_vop_set_clk(struct rk3288_cru *cru, struct rk3288_grf *grf, + int periph, unsigned int rate_hz) +{ + struct pll_div npll_config = {0}; + u32 lcdc_div; + int ret; + + ret = pll_para_config(rate_hz, &npll_config, &lcdc_div); + if (ret) + return ret; + + rk_clrsetreg(&cru->cru_mode_con, NPLL_MODE_MASK << NPLL_MODE_SHIFT, + NPLL_MODE_SLOW << NPLL_MODE_SHIFT); + rkclk_set_pll(cru, CLK_NEW, &npll_config); + + /* waiting for pll lock */ + while (1) { + if (readl(&grf->soc_status[1]) & SOCSTS_NPLL_LOCK) + break; + udelay(1); + } + + rk_clrsetreg(&cru->cru_mode_con, NPLL_MODE_MASK << NPLL_MODE_SHIFT, + NPLL_MODE_NORMAL << NPLL_MODE_SHIFT); + + /* vop dclk source clk: npll,dclk_div: 1 */ + switch (periph) { + case DCLK_VOP0: + rk_clrsetreg(&cru->cru_clksel_con[27], 0xff << 8 | 3 << 0, + (lcdc_div - 1) << 8 | 2 << 0); + break; + case DCLK_VOP1: + rk_clrsetreg(&cru->cru_clksel_con[29], 0xff << 8 | 3 << 6, + (lcdc_div - 1) << 8 | 2 << 6); + break; + } + + return 0; +} +#endif + +#ifdef CONFIG_SPL_BUILD +static void rkclk_init(struct rk3288_cru *cru, struct rk3288_grf *grf) +{ + u32 aclk_div; + u32 hclk_div; + u32 pclk_div; + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK << GPLL_MODE_SHIFT | + CPLL_MODE_MASK << CPLL_MODE_SHIFT, + GPLL_MODE_SLOW << GPLL_MODE_SHIFT | + CPLL_MODE_SLOW << CPLL_MODE_SHIFT); + + /* init pll */ + rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); + rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg); + + /* waiting for pll lock */ + while ((readl(&grf->soc_status[1]) & + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) != + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) + udelay(1); + + /* + * pd_bus clock pll source selection and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = GPLL_HZ / PD_BUS_ACLK_HZ - 1; + assert((aclk_div + 1) * PD_BUS_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); + hclk_div = PD_BUS_ACLK_HZ / PD_BUS_HCLK_HZ - 1; + assert((hclk_div + 1) * PD_BUS_HCLK_HZ == + PD_BUS_ACLK_HZ && (hclk_div < 0x4) && (hclk_div != 0x2)); + + pclk_div = PD_BUS_ACLK_HZ / PD_BUS_PCLK_HZ - 1; + assert((pclk_div + 1) * PD_BUS_PCLK_HZ == + PD_BUS_ACLK_HZ && pclk_div < 0x7); + + rk_clrsetreg(&cru->cru_clksel_con[1], + PD_BUS_PCLK_DIV_MASK << PD_BUS_PCLK_DIV_SHIFT | + PD_BUS_HCLK_DIV_MASK << PD_BUS_HCLK_DIV_SHIFT | + PD_BUS_ACLK_DIV0_MASK << PD_BUS_ACLK_DIV0_SHIFT | + PD_BUS_ACLK_DIV1_MASK << PD_BUS_ACLK_DIV1_SHIFT, + pclk_div << PD_BUS_PCLK_DIV_SHIFT | + hclk_div << PD_BUS_HCLK_DIV_SHIFT | + aclk_div << PD_BUS_ACLK_DIV0_SHIFT | + 0 << 0); + + /* + * peri clock pll source selection and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; + assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); + + hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ); + assert((1 << hclk_div) * PERI_HCLK_HZ == + PERI_ACLK_HZ && (hclk_div < 0x4)); + + pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ); + assert((1 << pclk_div) * PERI_PCLK_HZ == + PERI_ACLK_HZ && (pclk_div < 0x4)); + + rk_clrsetreg(&cru->cru_clksel_con[10], + 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_SEL_GPLL << PERI_SEL_PLL_SHIFT | + pclk_div << PERI_PCLK_DIV_SHIFT | + hclk_div << PERI_HCLK_DIV_SHIFT | + aclk_div << PERI_ACLK_DIV_SHIFT); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK << GPLL_MODE_SHIFT | + CPLL_MODE_MASK << CPLL_MODE_SHIFT, + GPLL_MODE_NORMAL << GPLL_MODE_SHIFT | + CPLL_MODE_NORMAL << CPLL_MODE_SHIFT); +} +#endif + +void rk3288_clk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf) +{ + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, + APLL_MODE_MASK << APLL_MODE_SHIFT, + APLL_MODE_SLOW << APLL_MODE_SHIFT); + + rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg); + + /* waiting for pll lock */ + while (!(readl(&grf->soc_status[1]) & SOCSTS_APLL_LOCK)) + udelay(1); + + /* + * core clock pll source selection and + * set up dependent divisors for MPAXI/M0AXI and ARM clocks. + * core clock select apll, apll clk = 1800MHz + * arm clk = 1800MHz, mpclk = 450MHz, m0clk = 900MHz + */ + rk_clrsetreg(&cru->cru_clksel_con[0], + CORE_SEL_PLL_MASK << CORE_SEL_PLL_SHIFT | + A17_DIV_MASK << A17_DIV_SHIFT | + MP_DIV_MASK << MP_DIV_SHIFT | + M0_DIV_MASK << M0_DIV_SHIFT, + 0 << A17_DIV_SHIFT | + 3 << MP_DIV_SHIFT | + 1 << M0_DIV_SHIFT); + + /* + * set up dependent divisors for L2RAM/ATCLK and PCLK clocks. + * l2ramclk = 900MHz, atclk = 450MHz, pclk_dbg = 450MHz + */ + rk_clrsetreg(&cru->cru_clksel_con[37], + CLK_L2RAM_DIV_MASK << CLK_L2RAM_DIV_SHIFT | + ATCLK_CORE_DIV_CON_MASK << ATCLK_CORE_DIV_CON_SHIFT | + PCLK_CORE_DBG_DIV_MASK >> PCLK_CORE_DBG_DIV_SHIFT, + 1 << CLK_L2RAM_DIV_SHIFT | + 3 << ATCLK_CORE_DIV_CON_SHIFT | + 3 << PCLK_CORE_DBG_DIV_SHIFT); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, + APLL_MODE_MASK << APLL_MODE_SHIFT, + APLL_MODE_NORMAL << APLL_MODE_SHIFT); +} + +/* Get pll rate by id */ +static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru, + enum rk_clk_id clk_id) +{ + uint32_t nr, no, nf; + uint32_t con; + int pll_id = rk_pll_id(clk_id); + struct rk3288_pll *pll = &cru->pll[pll_id]; + static u8 clk_shift[CLK_COUNT] = { + 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, + GPLL_MODE_SHIFT, NPLL_MODE_SHIFT + }; + uint shift; + + con = readl(&cru->cru_mode_con); + shift = clk_shift[clk_id]; + switch ((con >> shift) & APLL_MODE_MASK) { + case APLL_MODE_SLOW: + return OSC_HZ; + case APLL_MODE_NORMAL: + /* normal mode */ + con = readl(&pll->con0); + no = ((con >> CLKOD_SHIFT) & CLKOD_MASK) + 1; + nr = ((con >> CLKR_SHIFT) & CLKR_MASK) + 1; + con = readl(&pll->con1); + nf = ((con >> CLKF_SHIFT) & CLKF_MASK) + 1; + + return (24 * nf / (nr * no)) * 1000000; + case APLL_MODE_DEEP: + default: + return 32768; + } +} + +static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate, + int periph) +{ + uint src_rate; + uint div, mux; + u32 con; + + switch (periph) { + case HCLK_EMMC: + con = readl(&cru->cru_clksel_con[12]); + mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK; + div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; + break; + case HCLK_SDMMC: + con = readl(&cru->cru_clksel_con[11]); + mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK; + div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; + break; + case HCLK_SDIO0: + con = readl(&cru->cru_clksel_con[12]); + mux = (con >> SDIO0_PLL_SHIFT) & SDIO0_PLL_MASK; + div = (con >> SDIO0_DIV_SHIFT) & SDIO0_DIV_MASK; + break; + default: + return -EINVAL; + } + + src_rate = mux == EMMC_PLL_SELECT_24MHZ ? OSC_HZ : gclk_rate; + return DIV_TO_RATE(src_rate, div); +} + +static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate, + int periph, uint freq) +{ + int src_clk_div; + int mux; + + debug("%s: gclk_rate=%u\n", __func__, gclk_rate); + src_clk_div = RATE_TO_DIV(gclk_rate, freq); + + if (src_clk_div > 0x3f) { + src_clk_div = RATE_TO_DIV(OSC_HZ, freq); + mux = EMMC_PLL_SELECT_24MHZ; + assert((int)EMMC_PLL_SELECT_24MHZ == + (int)MMC0_PLL_SELECT_24MHZ); + } else { + mux = EMMC_PLL_SELECT_GENERAL; + assert((int)EMMC_PLL_SELECT_GENERAL == + (int)MMC0_PLL_SELECT_GENERAL); + } + switch (periph) { + case HCLK_EMMC: + rk_clrsetreg(&cru->cru_clksel_con[12], + EMMC_PLL_MASK << EMMC_PLL_SHIFT | + EMMC_DIV_MASK << EMMC_DIV_SHIFT, + mux << EMMC_PLL_SHIFT | + (src_clk_div - 1) << EMMC_DIV_SHIFT); + break; + case HCLK_SDMMC: + rk_clrsetreg(&cru->cru_clksel_con[11], + MMC0_PLL_MASK << MMC0_PLL_SHIFT | + MMC0_DIV_MASK << MMC0_DIV_SHIFT, + mux << MMC0_PLL_SHIFT | + (src_clk_div - 1) << MMC0_DIV_SHIFT); + break; + case HCLK_SDIO0: + rk_clrsetreg(&cru->cru_clksel_con[12], + SDIO0_PLL_MASK << SDIO0_PLL_SHIFT | + SDIO0_DIV_MASK << SDIO0_DIV_SHIFT, + mux << SDIO0_PLL_SHIFT | + (src_clk_div - 1) << SDIO0_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_mmc_get_clk(cru, gclk_rate, periph); +} + +static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint gclk_rate, + int periph) +{ + uint div, mux; + u32 con; + + switch (periph) { + case SCLK_SPI0: + con = readl(&cru->cru_clksel_con[25]); + mux = (con >> SPI0_PLL_SHIFT) & SPI0_PLL_MASK; + div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK; + break; + case SCLK_SPI1: + con = readl(&cru->cru_clksel_con[25]); + mux = (con >> SPI1_PLL_SHIFT) & SPI1_PLL_MASK; + div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK; + break; + case SCLK_SPI2: + con = readl(&cru->cru_clksel_con[39]); + mux = (con >> SPI2_PLL_SHIFT) & SPI2_PLL_MASK; + div = (con >> SPI2_DIV_SHIFT) & SPI2_DIV_MASK; + break; + default: + return -EINVAL; + } + assert(mux == SPI0_PLL_SELECT_GENERAL); + + return DIV_TO_RATE(gclk_rate, div); +} + +static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate, + int periph, uint freq) +{ + int src_clk_div; + + debug("%s: clk_general_rate=%u\n", __func__, gclk_rate); + src_clk_div = RATE_TO_DIV(gclk_rate, freq); + switch (periph) { + case SCLK_SPI0: + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI0_PLL_MASK << SPI0_PLL_SHIFT | + SPI0_DIV_MASK << SPI0_DIV_SHIFT, + SPI0_PLL_SELECT_GENERAL << SPI0_PLL_SHIFT | + src_clk_div << SPI0_DIV_SHIFT); + break; + case SCLK_SPI1: + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI1_PLL_MASK << SPI1_PLL_SHIFT | + SPI1_DIV_MASK << SPI1_DIV_SHIFT, + SPI1_PLL_SELECT_GENERAL << SPI1_PLL_SHIFT | + src_clk_div << SPI1_DIV_SHIFT); + break; + case SCLK_SPI2: + rk_clrsetreg(&cru->cru_clksel_con[39], + SPI2_PLL_MASK << SPI2_PLL_SHIFT | + SPI2_DIV_MASK << SPI2_DIV_SHIFT, + SPI2_PLL_SELECT_GENERAL << SPI2_PLL_SHIFT | + src_clk_div << SPI2_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_spi_get_clk(cru, gclk_rate, periph); +} + +static ulong rk3288_clk_get_rate(struct clk *clk) +{ + struct rk3288_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate, gclk_rate; + + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 0 ... 63: + new_rate = rkclk_pll_get_rate(priv->cru, clk->id); + break; + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO0: + new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id); + break; + case SCLK_SPI0: + case SCLK_SPI1: + case SCLK_SPI2: + new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, clk->id); + break; + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_I2C4: + case PCLK_I2C5: + return gclk_rate; + default: + return -ENOENT; + } + + return new_rate; +} + +static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3288_clk_priv *priv = dev_get_priv(clk->dev); + struct rk3288_cru *cru = priv->cru; + ulong new_rate, gclk_rate; + + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case CLK_DDR: + new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate); + break; + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO0: + new_rate = rockchip_mmc_set_clk(cru, gclk_rate, clk->id, rate); + break; + case SCLK_SPI0: + case SCLK_SPI1: + case SCLK_SPI2: + new_rate = rockchip_spi_set_clk(cru, gclk_rate, clk->id, rate); + break; +#ifndef CONFIG_SPL_BUILD + case SCLK_MAC: + new_rate = rockchip_mac_set_clk(priv->cru, clk->id, rate); + break; + case DCLK_VOP0: + case DCLK_VOP1: + new_rate = rockchip_vop_set_clk(cru, priv->grf, clk->id, rate); + break; + case SCLK_EDP_24M: + /* clk_edp_24M source: 24M */ + rk_setreg(&cru->cru_clksel_con[28], 1 << 15); + + /* rst edp */ + rk_setreg(&cru->cru_clksel_con[6], 1 << 15); + udelay(1); + rk_clrreg(&cru->cru_clksel_con[6], 1 << 15); + new_rate = rate; + break; + case ACLK_VOP0: + case ACLK_VOP1: { + u32 div; + + /* vop aclk source clk: cpll */ + div = CPLL_HZ / rate; + assert((div - 1 < 64) && (div * rate == CPLL_HZ)); + + switch (clk->id) { + case ACLK_VOP0: + rk_clrsetreg(&cru->cru_clksel_con[31], + 3 << 6 | 0x1f << 0, + 0 << 6 | (div - 1) << 0); + break; + case ACLK_VOP1: + rk_clrsetreg(&cru->cru_clksel_con[31], + 3 << 14 | 0x1f << 8, + 0 << 14 | (div - 1) << 8); + break; + } + new_rate = rate; + break; + } + case PCLK_HDMI_CTRL: + /* enable pclk hdmi ctrl */ + rk_clrreg(&cru->cru_clkgate_con[16], 1 << 9); + + /* software reset hdmi */ + rk_setreg(&cru->cru_clkgate_con[7], 1 << 9); + udelay(1); + rk_clrreg(&cru->cru_clkgate_con[7], 1 << 9); + new_rate = rate; + break; +#endif + default: + return -ENOENT; + } + + return new_rate; +} + +static struct clk_ops rk3288_clk_ops = { + .get_rate = rk3288_clk_get_rate, + .set_rate = rk3288_clk_set_rate, +}; + +static int rk3288_clk_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3288_clk_priv *priv = dev_get_priv(dev); + + priv->cru = (struct rk3288_cru *)dev_get_addr(dev); +#endif + + return 0; +} + +static int rk3288_clk_probe(struct udevice *dev) +{ + struct rk3288_clk_priv *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + if (IS_ERR(priv->grf)) + return PTR_ERR(priv->grf); +#ifdef CONFIG_SPL_BUILD +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3288_clk_plat *plat = dev_get_platdata(dev); + + priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); +#endif + rkclk_init(priv->cru, priv->grf); +#endif + + return 0; +} + +static int rk3288_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, "rk3288_sysreset", "reset", &dev); + if (ret) + debug("Warning: No RK3288 reset driver: ret=%d\n", ret); + + return 0; +} + +static const struct udevice_id rk3288_clk_ids[] = { + { .compatible = "rockchip,rk3288-cru" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3288_cru) = { + .name = "rockchip_rk3288_cru", + .id = UCLASS_CLK, + .of_match = rk3288_clk_ids, + .priv_auto_alloc_size = sizeof(struct rk3288_clk_priv), + .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat), + .ops = &rk3288_clk_ops, + .bind = rk3288_clk_bind, + .ofdata_to_platdata = rk3288_clk_ofdata_to_platdata, + .probe = rk3288_clk_probe, +};

Hi Heiiko,
On 22 July 2016 at 15:51, Heiko Stuebner heiko@sntech.de wrote:
With the number of Rockchip clock drivers increasing, don't clutter up the core drivers/clk directory with them and instead move them out of the way into a separate subdirectory.
Suggested-by: Simon Glass sjg@chromium.org Signed-off-by: Heiko Stuebner heiko@sntech.de
drivers/clk/Makefile | 3 +- drivers/clk/clk_rk3036.c | 386 ----------------- drivers/clk/clk_rk3288.c | 851 -------------------------------------- drivers/clk/rockchip/Makefile | 8 + drivers/clk/rockchip/clk_rk3036.c | 386 +++++++++++++++++ drivers/clk/rockchip/clk_rk3288.c | 851 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1246 insertions(+), 1239 deletions(-) delete mode 100644 drivers/clk/clk_rk3036.c delete mode 100644 drivers/clk/clk_rk3288.c create mode 100644 drivers/clk/rockchip/Makefile create mode 100644 drivers/clk/rockchip/clk_rk3036.c create mode 100644 drivers/clk/rockchip/clk_rk3288.c
Can you please cc the other Rockchip people? Also did you use patman? It should show as a rename I think.
Regards, Simon

The already available ilog2 function does exactly the same in the common case than the log2 function the current clock-driver reimplement. So, simply move to that one.
Signed-off-by: Heiko Stuebner heiko@sntech.de --- drivers/clk/rockchip/clk_rk3036.c | 10 +++------- drivers/clk/rockchip/clk_rk3288.c | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-)
diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c index 6202c9d..8899b0c 100644 --- a/drivers/clk/rockchip/clk_rk3036.c +++ b/drivers/clk/rockchip/clk_rk3036.c @@ -15,6 +15,7 @@ #include <asm/arch/hardware.h> #include <dm/lists.h> #include <dt-bindings/clock/rk3036-cru.h> +#include <linux/log2.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -48,11 +49,6 @@ enum { 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 unsigned int log2(unsigned int value) -{ - return fls(value) - 1; -} - void *rockchip_get_cru(void) { struct udevice *dev; @@ -177,11 +173,11 @@ static void rkclk_init(struct rk3036_cru *cru) aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
- hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ); + hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); assert((1 << hclk_div) * PERI_HCLK_HZ == PERI_ACLK_HZ && (pclk_div < 0x4));
- pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ); + pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ); assert((1 << pclk_div) * PERI_PCLK_HZ == PERI_ACLK_HZ && pclk_div < 0x8);
diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c index e00feb0..c07203d 100644 --- a/drivers/clk/rockchip/clk_rk3288.c +++ b/drivers/clk/rockchip/clk_rk3288.c @@ -20,6 +20,7 @@ #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/uclass-internal.h> +#include <linux/log2.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -186,11 +187,6 @@ static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id, return 0; }
-static inline unsigned int log2(unsigned int value) -{ - return fls(value) - 1; -} - static int rkclk_configure_ddr(struct rk3288_cru *cru, struct rk3288_grf *grf, unsigned int hz) { @@ -421,11 +417,11 @@ static void rkclk_init(struct rk3288_cru *cru, struct rk3288_grf *grf) aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
- hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ); + hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); assert((1 << hclk_div) * PERI_HCLK_HZ == PERI_ACLK_HZ && (hclk_div < 0x4));
- pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ); + pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ); assert((1 << pclk_div) * PERI_PCLK_HZ == PERI_ACLK_HZ && (pclk_div < 0x4));

On 22 July 2016 at 15:51, Heiko Stuebner heiko@sntech.de wrote:
The already available ilog2 function does exactly the same in the common case than the log2 function the current clock-driver reimplement. So, simply move to that one.
Signed-off-by: Heiko Stuebner heiko@sntech.de
drivers/clk/rockchip/clk_rk3036.c | 10 +++------- drivers/clk/rockchip/clk_rk3288.c | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-)
Acked-by: Simon Glass sjg@chromium.org

PMU is the power management unit and GRF is the general register file. Both are heavily used in U-Boot. Add header files with register definitions.
Signed-off-by: Heiko Stuebner heiko@sntech.de Acked-by: Simon Glass sjg@chromium.org --- arch/arm/include/asm/arch-rockchip/grf_rk3188.h | 589 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/pmu_rk3188.h | 36 ++ 2 files changed, 625 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/grf_rk3188.h create mode 100644 arch/arm/include/asm/arch-rockchip/pmu_rk3188.h
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3188.h b/arch/arm/include/asm/arch-rockchip/grf_rk3188.h new file mode 100644 index 0000000..ce7bac5 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3188.h @@ -0,0 +1,589 @@ +/* + * Copyright (c) 2016 Heiko Stuebner heiko@sntech.de + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _ASM_ARCH_GRF_RK3188_H +#define _ASM_ARCH_GRF_RK3188_H + +struct rk3188_grf_gpio_lh { + u32 l; + u32 h; +}; + +struct rk3188_grf { + struct rk3188_grf_gpio_lh gpio_dir[4]; + struct rk3188_grf_gpio_lh gpio_do[4]; + struct rk3188_grf_gpio_lh gpio_en[4]; + + u32 reserved[2]; + u32 gpio0c_iomux; + u32 gpio0d_iomux; + + u32 gpio1a_iomux; + u32 gpio1b_iomux; + u32 gpio1c_iomux; + u32 gpio1d_iomux; + + u32 gpio2a_iomux; + u32 gpio2b_iomux; + u32 gpio2c_iomux; + u32 gpio2d_iomux; + + u32 gpio3a_iomux; + u32 gpio3b_iomux; + u32 gpio3c_iomux; + u32 gpio3d_iomux; + + u32 soc_con0; + u32 soc_con1; + u32 soc_con2; + u32 soc_status0; + + u32 busdmac_con[3]; + u32 peridmac_con[4]; + + u32 cpu_con[6]; + u32 reserved0[2]; + + u32 ddrc_con0; + u32 ddrc_stat; + + u32 io_con[5]; + u32 soc_status1; + + u32 uoc0_con[4]; + u32 uoc1_con[4]; + u32 uoc2_con[2]; + u32 reserved1; + u32 uoc3_con[2]; + u32 hsic_stat; + u32 os_reg[8]; + + u32 gpio0_p[3]; + u32 gpio1_p[3][4]; + + u32 flash_data_p; + u32 flash_cmd_p; +}; +check_member(rk3188_grf, flash_cmd_p, 0x01a4); + +/* GRF_GPIO0D_IOMUX */ +enum { + GPIO0D7_SHIFT = 14, + GPIO0D7_MASK = 1, + GPIO0D7_GPIO = 0, + GPIO0D7_SPI1_CSN0, + + GPIO0D6_SHIFT = 12, + GPIO0D6_MASK = 1, + GPIO0D6_GPIO = 0, + GPIO0D6_SPI1_CLK, + + GPIO0D5_SHIFT = 10, + GPIO0D5_MASK = 1, + GPIO0D5_GPIO = 0, + GPIO0D5_SPI1_TXD, + + GPIO0D4_SHIFT = 8, + GPIO0D4_MASK = 1, + GPIO0D4_GPIO = 0, + GPIO0D4_SPI0_RXD, + + GPIO0D3_SHIFT = 6, + GPIO0D3_MASK = 3, + GPIO0D3_GPIO = 0, + GPIO0D3_FLASH_CSN3, + GPIO0D3_EMMC_RSTN_OUT, + + GPIO0D2_SHIFT = 4, + GPIO0D2_MASK = 3, + GPIO0D2_GPIO = 0, + GPIO0D2_FLASH_CSN2, + GPIO0D2_EMMC_CMD, + + GPIO0D1_SHIFT = 2, + GPIO0D1_MASK = 1, + GPIO0D1_GPIO = 0, + GPIO0D1_FLASH_CSN1, + + GPIO0D0_SHIFT = 0, + GPIO0D0_MASK = 3, + GPIO0D0_GPIO = 0, + GPIO0D0_FLASH_DQS, + GPIO0D0_EMMC_CLKOUT +}; + +/* GRF_GPIO1A_IOMUX */ +enum { + GPIO1A7_SHIFT = 14, + GPIO1A7_MASK = 3, + GPIO1A7_GPIO = 0, + GPIO1A7_UART1_RTS_N, + GPIO1A7_SPI0_CSN0, + + GPIO1A6_SHIFT = 12, + GPIO1A6_MASK = 3, + GPIO1A6_GPIO = 0, + GPIO1A6_UART1_CTS_N, + GPIO1A6_SPI0_CLK, + + GPIO1A5_SHIFT = 10, + GPIO1A5_MASK = 3, + GPIO1A5_GPIO = 0, + GPIO1A5_UART1_SOUT, + GPIO1A5_SPI0_TXD, + + GPIO1A4_SHIFT = 8, + GPIO1A4_MASK = 3, + GPIO1A4_GPIO = 0, + GPIO1A4_UART1_SIN, + GPIO1A4_SPI0_RXD, + + GPIO1A3_SHIFT = 6, + GPIO1A3_MASK = 1, + GPIO1A3_GPIO = 0, + GPIO1A3_UART0_RTS_N, + + GPIO1A2_SHIFT = 4, + GPIO1A2_MASK = 1, + GPIO1A2_GPIO = 0, + GPIO1A2_UART0_CTS_N, + + GPIO1A1_SHIFT = 2, + GPIO1A1_MASK = 1, + GPIO1A1_GPIO = 0, + GPIO1A1_UART0_SOUT, + + GPIO1A0_SHIFT = 0, + GPIO1A0_MASK = 1, + GPIO1A0_GPIO = 0, + GPIO1A0_UART0_SIN, +}; + +/* GRF_GPIO1B_IOMUX */ +enum { + GPIO1B7_SHIFT = 14, + GPIO1B7_MASK = 1, + GPIO1B7_GPIO = 0, + GPIO1B7_SPI0_CSN1, + + GPIO1B6_SHIFT = 12, + GPIO1B6_MASK = 3, + GPIO1B6_GPIO = 0, + GPIO1B6_SPDIF_TX, + GPIO1B6_SPI1_CSN1, + + GPIO1B5_SHIFT = 10, + GPIO1B5_MASK = 3, + GPIO1B5_GPIO = 0, + GPIO1B5_UART3_RTS_N, + GPIO1B5_RESERVED, + + GPIO1B4_SHIFT = 8, + GPIO1B4_MASK = 3, + GPIO1B4_GPIO = 0, + GPIO1B4_UART3_CTS_N, + GPIO1B4_GPS_RFCLK, + + GPIO1B3_SHIFT = 6, + GPIO1B3_MASK = 3, + GPIO1B3_GPIO = 0, + GPIO1B3_UART3_SOUT, + GPIO1B3_GPS_SIG, + + GPIO1B2_SHIFT = 4, + GPIO1B2_MASK = 3, + GPIO1B2_GPIO = 0, + GPIO1B2_UART3_SIN, + GPIO1B2_GPS_MAG, + + GPIO1B1_SHIFT = 2, + GPIO1B1_MASK = 3, + GPIO1B1_GPIO = 0, + GPIO1B1_UART2_SOUT, + GPIO1B1_JTAG_TDO, + + GPIO1B0_SHIFT = 0, + GPIO1B0_MASK = 3, + GPIO1B0_GPIO = 0, + GPIO1B0_UART2_SIN, + GPIO1B0_JTAG_TDI, +}; + +/* GRF_GPIO1D_IOMUX */ +enum { + GPIO1D7_SHIFT = 14, + GPIO1D7_MASK = 1, + GPIO1D7_GPIO = 0, + GPIO1D7_I2C4_SCL, + + GPIO1D6_SHIFT = 12, + GPIO1D6_MASK = 1, + GPIO1D6_GPIO = 0, + GPIO1D6_I2C4_SDA, + + GPIO1D5_SHIFT = 10, + GPIO1D5_MASK = 1, + GPIO1D5_GPIO = 0, + GPIO1D5_I2C2_SCL, + + GPIO1D4_SHIFT = 8, + GPIO1D4_MASK = 1, + GPIO1D4_GPIO = 0, + GPIO1D4_I2C2_SDA, + + GPIO1D3_SHIFT = 6, + GPIO1D3_MASK = 1, + GPIO1D3_GPIO = 0, + GPIO1D3_I2C1_SCL, + + GPIO1D2_SHIFT = 4, + GPIO1D2_MASK = 1, + GPIO1D2_GPIO = 0, + GPIO1D2_I2C1_SDA, + + GPIO1D1_SHIFT = 2, + GPIO1D1_MASK = 1, + GPIO1D1_GPIO = 0, + GPIO1D1_I2C0_SCL, + + GPIO1D0_SHIFT = 0, + GPIO1D0_MASK = 1, + GPIO1D0_GPIO = 0, + GPIO1D0_I2C0_SDA, +}; + +/* GRF_GPIO3A_IOMUX */ +enum { + GPIO3A7_SHIFT = 14, + GPIO3A7_MASK = 1, + GPIO3A7_GPIO = 0, + GPIO3A7_SDMMC0_DATA3, + + GPIO3A6_SHIFT = 12, + GPIO3A6_MASK = 1, + GPIO3A6_GPIO = 0, + GPIO3A6_SDMMC0_DATA2, + + GPIO3A5_SHIFT = 10, + GPIO3A5_MASK = 1, + GPIO3A5_GPIO = 0, + GPIO3A5_SDMMC0_DATA1, + + GPIO3A4_SHIFT = 8, + GPIO3A4_MASK = 1, + GPIO3A4_GPIO = 0, + GPIO3A4_SDMMC0_DATA0, + + GPIO3A3_SHIFT = 6, + GPIO3A3_MASK = 1, + GPIO3A3_GPIO = 0, + GPIO3A3_SDMMC0_CMD, + + GPIO3A2_SHIFT = 4, + GPIO3A2_MASK = 1, + GPIO3A2_GPIO = 0, + GPIO3A2_SDMMC0_CLKOUT, + + GPIO3A1_SHIFT = 2, + GPIO3A1_MASK = 1, + GPIO3A1_GPIO = 0, + GPIO3A1_SDMMC0_PWREN, + + GPIO3A0_SHIFT = 0, + GPIO3A0_MASK = 1, + GPIO3A0_GPIO = 0, + GPIO3A0_SDMMC0_RSTN, +}; + +/* GRF_GPIO3B_IOMUX */ +enum { + GPIO3B7_SHIFT = 14, + GPIO3B7_MASK = 3, + GPIO3B7_GPIO = 0, + GPIO3B7_CIF_DATA11, + GPIO3B7_I2C3_SCL, + + GPIO3B6_SHIFT = 12, + GPIO3B6_MASK = 3, + GPIO3B6_GPIO = 0, + GPIO3B6_CIF_DATA10, + GPIO3B6_I2C3_SDA, + + GPIO3B5_SHIFT = 10, + GPIO3B5_MASK = 3, + GPIO3B5_GPIO = 0, + GPIO3B5_CIF_DATA1, + GPIO3B5_HSADC_DATA9, + + GPIO3B4_SHIFT = 8, + GPIO3B4_MASK = 3, + GPIO3B4_GPIO = 0, + GPIO3B4_CIF_DATA0, + GPIO3B4_HSADC_DATA8, + + GPIO3B3_SHIFT = 6, + GPIO3B3_MASK = 1, + GPIO3B3_GPIO = 0, + GPIO3B3_CIF_CLKOUT, + + GPIO3B2_SHIFT = 4, + GPIO3B2_MASK = 1, + GPIO3B2_GPIO = 0, + /* no muxes */ + + GPIO3B1_SHIFT = 2, + GPIO3B1_MASK = 1, + GPIO3B1_GPIO = 0, + GPIO3B1_SDMMC0_WRITE_PRT, + + GPIO3B0_SHIFT = 0, + GPIO3B0_MASK = 1, + GPIO3B0_GPIO = 0, + GPIO3B0_SDMMC_DETECT_N, +}; + +/* GRF_GPIO3C_IOMUX */ +enum { + GPIO3C7_SHIFT = 14, + GPIO3C7_MASK = 3, + GPIO3C7_GPIO = 0, + GPIO3C7_SDMMC1_WRITE_PRT, + GPIO3C7_RMII_CRS_DVALID, + GPIO3C7_RESERVED, + + GPIO3C6_SHIFT = 12, + GPIO3C6_MASK = 3, + GPIO3C6_GPIO = 0, + GPIO3C6_SDMMC1_DECTN, + GPIO3C6_RMII_RX_ERR, + GPIO3C6_RESERVED, + + GPIO3C5_SHIFT = 10, + GPIO3C5_MASK = 3, + GPIO3C5_GPIO = 0, + GPIO3C5_SDMMC1_CLKOUT, + GPIO3C5_RMII_CLKOUT, + GPIO3C5_RMII_CLKIN, + + GPIO3C4_SHIFT = 8, + GPIO3C4_MASK = 3, + GPIO3C4_GPIO = 0, + GPIO3C4_SDMMC1_DATA3, + GPIO3C4_RMII_RXD1, + GPIO3C4_RESERVED, + + GPIO3C3_SHIFT = 6, + GPIO3C3_MASK = 3, + GPIO3C3_GPIO = 0, + GPIO3C3_SDMMC1_DATA2, + GPIO3C3_RMII_RXD0, + GPIO3C3_RESERVED, + + GPIO3C2_SHIFT = 4, + GPIO3C2_MASK = 3, + GPIO3C2_GPIO = 0, + GPIO3C2_SDMMC1_DATA1, + GPIO3C2_RMII_TXD0, + GPIO3C2_RESERVED, + + GPIO3C1_SHIFT = 2, + GPIO3C1_MASK = 3, + GPIO3C1_GPIO = 0, + GPIO3C1_SDMMC1_DATA0, + GPIO3C1_RMII_TXD1, + GPIO3C1_RESERVED, + + GPIO3C0_SHIFT = 0, + GPIO3C0_MASK = 3, + GPIO3C0_GPIO = 0, + GPIO3C0_SDMMC1_CMD, + GPIO3C0_RMII_TX_EN, + GPIO3C0_RESERVED, +}; + +/* GRF_GPIO3D_IOMUX */ +enum { + GPIO3D6_SHIFT = 12, + GPIO3D6_MASK = 3, + GPIO3D6_GPIO = 0, + GPIO3D6_PWM_3, + GPIO3D6_JTAG_TMS, + GPIO3D6_HOST_DRV_VBUS, + + GPIO3D5_SHIFT = 10, + GPIO3D5_MASK = 3, + GPIO3D5_GPIO = 0, + GPIO3D5_PWM_2, + GPIO3D5_JTAG_TCK, + GPIO3D5_OTG_DRV_VBUS, + + GPIO3D4_SHIFT = 8, + GPIO3D4_MASK = 3, + GPIO3D4_GPIO = 0, + GPIO3D4_PWM_1, + GPIO3D4_JTAG_TRSTN, + + GPIO3D3_SHIFT = 6, + GPIO3D3_MASK = 3, + GPIO3D3_GPIO = 0, + GPIO3D3_PWM_0, + + GPIO3D2_SHIFT = 4, + GPIO3D2_MASK = 3, + GPIO3D2_GPIO = 0, + GPIO3D2_SDMMC1_INT_N, + + GPIO3D1_SHIFT = 2, + GPIO3D1_MASK = 3, + GPIO3D1_GPIO = 0, + GPIO3D1_SDMMC1_BACKEND_PWR, + GPIO3D1_MII_MDCLK, + + GPIO3D0_SHIFT = 0, + GPIO3D0_MASK = 3, + GPIO3D0_GPIO = 0, + GPIO3D0_SDMMC1_PWR_EN, + GPIO3D0_MII_MD, +}; + +/* GRF_SOC_CON0 */ +enum { + HSADC_CLK_DIR_SHIFT = 15, + HSADC_CLK_DIR_MASK = 1, + + HSADC_SEL_SHIFT = 14, + HSADC_SEL_MASK = 1, + + NOC_REMAP_SHIFT = 12, + NOC_REMAP_MASK = 1, + + EMMC_FLASH_SEL_SHIFT = 11, + EMMC_FLASH_SEL_MASK = 1, + + TZPC_REVISION_SHIFT = 7, + TZPC_REVISION_MASK = 0xf, + + L2CACHE_ACC_SHIFT = 5, + L2CACHE_ACC_MASK = 3, + + L2RD_WAIT_SHIFT = 3, + L2RD_WAIT_MASK = 3, + + IMEMRD_WAIT_SHIFT = 1, + IMEMRD_WAIT_MASK = 3, +}; + +/* GRF_SOC_CON1 */ +enum { + RKI2C4_SEL_SHIFT = 15, + RKI2C4_SEL_MASK = 1, + + RKI2C3_SEL_SHIFT = 14, + RKI2C3_SEL_MASK = 1, + + RKI2C2_SEL_SHIFT = 13, + RKI2C2_SEL_MASK = 1, + + RKI2C1_SEL_SHIFT = 12, + RKI2C1_SEL_MASK = 1, + + RKI2C0_SEL_SHIFT = 11, + RKI2C0_SEL_MASK = 1, + + VCODEC_SEL_SHIFT = 10, + VCODEC_SEL_MASK = 1, + + PERI_EMEM_PAUSE_SHIFT = 9, + PERI_EMEM_PAUSE_MASK = 1, + + PERI_USB_PAUSE_SHIFT = 8, + PERI_USB_PAUSE_MASK = 1, + + SMC_MUX_MODE_0_SHIFT = 6, + SMC_MUX_MODE_0_MASK = 1, + + SMC_SRAM_MW_0_SHIFT = 4, + SMC_SRAM_MW_0_MASK = 3, + + SMC_REMAP_0_SHIFT = 3, + SMC_REMAP_0_MASK = 1, + + SMC_A_GT_M0_SYNC_SHIFT = 2, + SMC_A_GT_M0_SYNC_MASK = 1, + + EMAC_SPEED_SHIFT = 1, + EMAC_SPEEC_MASK = 1, + + EMAC_MODE_SHIFT = 0, + EMAC_MODE_MASK = 1, +}; + +/* GRF_SOC_CON2 */ +enum { + SDIO_CLK_OUT_SR_SHIFT = 15, + SDIO_CLK_OUT_SR_MASK = 1, + + MEM_EMA_L2C_SHIFT = 11, + MEM_EMA_L2C_MASK = 7, + + MEM_EMA_A9_SHIFT = 8, + MEM_EMA_A9_MASK = 7, + + MSCH4_MAINDDR3_SHIFT = 7, + MSCH4_MAINDDR3_MASK = 1, + MSCH4_MAINDDR3_DDR3 = 1, + + EMAC_NEWRCV_EN_SHIFT = 6, + EMAC_NEWRCV_EN_MASK = 1, + + SW_ADDR15_EN_SHIFT = 5, + SW_ADDR15_EN_MASK = 1, + + SW_ADDR16_EN_SHIFT = 4, + SW_ADDR16_EN_MASK = 1, + + SW_ADDR17_EN_SHIFT = 3, + SW_ADDR17_EN_MASK = 1, + + BANK2_TO_RANK_EN_SHIFT = 2, + BANK2_TO_RANK_EN_MASK = 1, + + RANK_TO_ROW15_EN_SHIFT = 1, + RANK_TO_ROW15_EN_MASK = 1, + + UPCTL_C_ACTIVE_IN_SHIFT = 0, + UPCTL_C_ACTIVE_IN_MASK = 1, + UPCTL_C_ACTIVE_IN_MAY = 0, + UPCTL_C_ACTIVE_IN_WILL, +}; + +/* GRF_DDRC_CON0 */ +enum { + DDR_16BIT_EN_SHIFT = 15, + DDR_16BIT_EN_MASK = 1, + + DTO_LB_SHIFT = 11, + DTO_LB_MASK = 3, + + DTO_TE_SHIFT = 9, + DTO_TE_MASK = 3, + + DTO_PDR_SHIFT = 7, + DTO_PDR_MASK = 3, + + DTO_PDD_SHIFT = 5, + DTO_PDD_MASK = 3, + + DTO_IOM_SHIFT = 3, + DTO_IOM_MASK = 3, + + DTO_OE_SHIFT = 1, + DTO_OE_MASK = 3, + + ATO_AE_SHIFT = 0, + ATO_AE_MASK = 1, +}; +#endif diff --git a/arch/arm/include/asm/arch-rockchip/pmu_rk3188.h b/arch/arm/include/asm/arch-rockchip/pmu_rk3188.h new file mode 100644 index 0000000..d3feac3 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/pmu_rk3188.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Heiko Stuebner heiko@sntech.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_ARCH_PMU_RK3188_H +#define _ASM_ARCH_PMU_RK3188_H + +struct rk3188_pmu { + u32 wakeup_cfg[2]; + u32 pwrdn_con; + u32 pwrdn_st; + + u32 int_con; + u32 int_st; + u32 misc_con; + + u32 osc_cnt; + u32 pll_cnt; + u32 pmu_cnt; + u32 ddrio_pwron_cnt; + u32 wakeup_rst_clr_cnt; + u32 scu_pwrdwn_cnt; + u32 scu_pwrup_cnt; + u32 misc_con1; + u32 gpio0_con; + + u32 sys_reg[4]; + u32 reserved0[4]; + u32 stop_int_dly; + u32 gpio0_p[2]; +}; +check_member(rk3188_pmu, gpio0_p[1], 0x0068); + +#endif

Add a driver which supports pin multiplexing setup for the most commonly used peripherals.
Signed-off-by: Heiko Stuebner heiko@sntech.de Acked-by: Simon Glass sjg@chromium.org --- drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/rockchip/Makefile | 1 + drivers/pinctrl/rockchip/pinctrl_rk3188.c | 613 ++++++++++++++++++++++++++++++ 3 files changed, 623 insertions(+) create mode 100644 drivers/pinctrl/rockchip/pinctrl_rk3188.c
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 2972dba..0d8ee19 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -141,6 +141,15 @@ config ROCKCHIP_RK3288_PINCTRL definitions and pin control functions for each available multiplex function.
+config ROCKCHIP_RK3188_PINCTRL + bool "Rockchip pin control driver" + depends on DM + help + Support pin multiplexing control on Rockchip rk3188 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_SANDBOX bool "Sandbox pinctrl driver" depends on SANDBOX diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile index 64e9587..7768628 100644 --- a/drivers/pinctrl/rockchip/Makefile +++ b/drivers/pinctrl/rockchip/Makefile @@ -6,4 +6,5 @@ #
obj-$(CONFIG_ROCKCHIP_RK3036_PINCTRL) += pinctrl_rk3036.o +obj-$(CONFIG_ROCKCHIP_RK3188_PINCTRL) += pinctrl_rk3188.o obj-$(CONFIG_ROCKCHIP_RK3288_PINCTRL) += pinctrl_rk3288.o diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3188.c b/drivers/pinctrl/rockchip/pinctrl_rk3188.c new file mode 100644 index 0000000..f98356d --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl_rk3188.c @@ -0,0 +1,613 @@ +/* + * Pinctrl driver for Rockchip RK3188 SoCs + * Copyright (c) 2016 Heiko Stuebner heiko@sntech.de + * + * 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_rk3188.h> +#include <asm/arch/hardware.h> +#include <asm/arch/periph.h> +#include <asm/arch/pmu_rk3188.h> +#include <dm/pinctrl.h> +#include <dm/root.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct rk3188_pinctrl_priv { + struct rk3188_grf *grf; + struct rk3188_pmu *pmu; + int num_banks; +}; + +/** + * Encode variants of iomux registers into a type variable + */ +#define IOMUX_GPIO_ONLY BIT(0) + +/** + * @type: iomux variant using IOMUX_* constants + * @offset: if initialized to -1 it will be autocalculated, by specifying + * an initial offset value the relevant source offset can be reset + * to a new value for autocalculating the following iomux registers. + */ +struct rockchip_iomux { + u8 type; + s16 offset; +}; + +/** + * @reg: register offset of the gpio bank + * @nr_pins: number of pins in this bank + * @bank_num: number of the bank, to account for holes + * @name: name of the bank + * @iomux: array describing the 4 iomux sources of the bank + */ +struct rockchip_pin_bank { + u16 reg; + u8 nr_pins; + u8 bank_num; + char *name; + struct rockchip_iomux iomux[4]; +}; + +#define PIN_BANK(id, pins, label) \ + { \ + .bank_num = id, \ + .nr_pins = pins, \ + .name = label, \ + .iomux = { \ + { .offset = -1 }, \ + { .offset = -1 }, \ + { .offset = -1 }, \ + { .offset = -1 }, \ + }, \ + } + +#define PIN_BANK_IOMUX_FLAGS(id, pins, label, iom0, iom1, iom2, iom3) \ + { \ + .bank_num = id, \ + .nr_pins = pins, \ + .name = label, \ + .iomux = { \ + { .type = iom0, .offset = -1 }, \ + { .type = iom1, .offset = -1 }, \ + { .type = iom2, .offset = -1 }, \ + { .type = iom3, .offset = -1 }, \ + }, \ + } + +#ifndef CONFIG_SPL_BUILD +static struct rockchip_pin_bank rk3188_pin_banks[] = { + PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_GPIO_ONLY, 0, 0, 0), + PIN_BANK(1, 32, "gpio1"), + PIN_BANK(2, 32, "gpio2"), + PIN_BANK(3, 32, "gpio3"), +}; +#endif + +static void pinctrl_rk3188_pwm_config(struct rk3188_grf *grf, int pwm_id) +{ + switch (pwm_id) { + case PERIPH_ID_PWM0: + rk_clrsetreg(&grf->gpio3d_iomux, GPIO3D3_MASK << GPIO3D3_SHIFT, + GPIO3D3_PWM_0 << GPIO3D3_SHIFT); + break; + case PERIPH_ID_PWM1: + rk_clrsetreg(&grf->gpio3d_iomux, GPIO3D4_MASK << GPIO3D4_SHIFT, + GPIO3D4_PWM_1 << GPIO3D4_SHIFT); + break; + case PERIPH_ID_PWM2: + rk_clrsetreg(&grf->gpio3d_iomux, GPIO3D5_MASK << GPIO3D5_SHIFT, + GPIO3D5_PWM_2 << GPIO3D5_SHIFT); + break; + case PERIPH_ID_PWM3: + rk_clrsetreg(&grf->gpio3d_iomux, GPIO3D6_MASK << GPIO3D6_SHIFT, + GPIO3D6_PWM_3 << GPIO3D6_SHIFT); + break; + default: + debug("pwm id = %d iomux error!\n", pwm_id); + break; + } +} + +static void pinctrl_rk3188_i2c_config(struct rk3188_grf *grf, + struct rk3188_pmu *pmu, int i2c_id) +{ + switch (i2c_id) { + case PERIPH_ID_I2C0: + rk_clrsetreg(&grf->gpio1d_iomux, + GPIO1D1_MASK << GPIO1D1_SHIFT | + GPIO1D0_MASK << GPIO1D0_SHIFT, + GPIO1D1_I2C0_SCL << GPIO1D1_SHIFT | + GPIO1D0_I2C0_SDA << GPIO1D0_SHIFT); + /* enable new i2c controller */ + rk_clrsetreg(&grf->soc_con1, 1 << RKI2C0_SEL_SHIFT, + 1 << RKI2C0_SEL_SHIFT); + break; + case PERIPH_ID_I2C1: + rk_clrsetreg(&grf->gpio1d_iomux, + GPIO1D3_MASK << GPIO1D3_SHIFT | + GPIO1D2_MASK << GPIO1D2_SHIFT, + GPIO1D3_I2C1_SCL << GPIO1D2_SHIFT | + GPIO1D2_I2C1_SDA << GPIO1D2_SHIFT); + rk_clrsetreg(&grf->soc_con1, 1 << RKI2C1_SEL_SHIFT, + 1 << RKI2C1_SEL_SHIFT); + break; + case PERIPH_ID_I2C2: + rk_clrsetreg(&grf->gpio1d_iomux, + GPIO1D5_MASK << GPIO1D5_SHIFT | + GPIO1D4_MASK << GPIO1D4_SHIFT, + GPIO1D5_I2C2_SCL << GPIO1D5_SHIFT | + GPIO1D4_I2C2_SDA << GPIO1D4_SHIFT); + rk_clrsetreg(&grf->soc_con1, 1 << RKI2C2_SEL_SHIFT, + 1 << RKI2C2_SEL_SHIFT); + break; + case PERIPH_ID_I2C3: + rk_clrsetreg(&grf->gpio3b_iomux, + GPIO3B7_MASK << GPIO3B7_SHIFT | + GPIO3B6_MASK << GPIO3B6_SHIFT, + GPIO3B7_I2C3_SCL << GPIO3B7_SHIFT | + GPIO3B6_I2C3_SDA << GPIO3B6_SHIFT); + rk_clrsetreg(&grf->soc_con1, 1 << RKI2C3_SEL_SHIFT, + 1 << RKI2C3_SEL_SHIFT); + break; + case PERIPH_ID_I2C4: + rk_clrsetreg(&grf->gpio1d_iomux, + GPIO1D7_MASK << GPIO1D7_SHIFT | + GPIO1D6_MASK << GPIO1D6_SHIFT, + GPIO1D7_I2C4_SCL << GPIO1D7_SHIFT | + GPIO1D6_I2C4_SDA << GPIO1D6_SHIFT); + rk_clrsetreg(&grf->soc_con1, 1 << RKI2C4_SEL_SHIFT, + 1 << RKI2C4_SEL_SHIFT); + break; + default: + debug("i2c id = %d iomux error!\n", i2c_id); + break; + } +} + +static int pinctrl_rk3188_spi_config(struct rk3188_grf *grf, + enum periph_id spi_id, int cs) +{ + switch (spi_id) { + case PERIPH_ID_SPI0: + switch (cs) { + case 0: + rk_clrsetreg(&grf->gpio1a_iomux, + GPIO1A7_MASK << GPIO1A7_SHIFT, + GPIO1A7_SPI0_CSN0 << GPIO1A7_SHIFT); + break; + case 1: + rk_clrsetreg(&grf->gpio1b_iomux, + GPIO1B7_MASK << GPIO1B7_SHIFT, + GPIO1B7_SPI0_CSN1 << GPIO1B7_SHIFT); + break; + default: + goto err; + } + rk_clrsetreg(&grf->gpio1a_iomux, + GPIO1A4_MASK << GPIO1A4_SHIFT | + GPIO1A5_MASK << GPIO1A5_SHIFT | + GPIO1A6_MASK << GPIO1A6_SHIFT, + GPIO1A4_SPI0_RXD << GPIO1A4_SHIFT | + GPIO1A5_SPI0_TXD << GPIO1A5_SHIFT | + GPIO1A6_SPI0_CLK << GPIO1A6_SHIFT); + break; + case PERIPH_ID_SPI1: + switch (cs) { + case 0: + rk_clrsetreg(&grf->gpio0d_iomux, + GPIO0D7_MASK << GPIO0D7_SHIFT, + GPIO0D7_SPI1_CSN0 << GPIO0D7_SHIFT); + break; + case 1: + rk_clrsetreg(&grf->gpio1b_iomux, + GPIO1B6_MASK << GPIO1B6_SHIFT, + GPIO1B6_SPI1_CSN1 << GPIO1B6_SHIFT); + break; + default: + goto err; + } + rk_clrsetreg(&grf->gpio0d_iomux, + GPIO0D4_MASK << GPIO0D4_SHIFT | + GPIO0D5_MASK << GPIO0D5_SHIFT | + GPIO0D6_MASK << GPIO0D6_SHIFT, + GPIO0D4_SPI0_RXD << GPIO0D4_SHIFT | + GPIO0D5_SPI1_TXD << GPIO0D5_SHIFT | + GPIO0D6_SPI1_CLK << GPIO0D6_SHIFT); + break; + default: + goto err; + } + + return 0; +err: + debug("rkspi: periph%d cs=%d not supported", spi_id, cs); + return -ENOENT; +} + +static void pinctrl_rk3188_uart_config(struct rk3188_grf *grf, int uart_id) +{ + switch (uart_id) { + case PERIPH_ID_UART0: + rk_clrsetreg(&grf->gpio1a_iomux, + GPIO1A3_MASK << GPIO1A3_SHIFT | + GPIO1A2_MASK << GPIO1A2_SHIFT | + GPIO1A1_MASK << GPIO1A1_SHIFT | + GPIO1A0_MASK << GPIO1A0_SHIFT, + GPIO1A3_UART0_RTS_N << GPIO1A3_SHIFT | + GPIO1A2_UART0_CTS_N << GPIO1A2_SHIFT | + GPIO1A1_UART0_SOUT << GPIO1A1_SHIFT | + GPIO1A0_UART0_SIN << GPIO1A0_SHIFT); + break; + case PERIPH_ID_UART1: + rk_clrsetreg(&grf->gpio1a_iomux, + GPIO1A7_MASK << GPIO1A7_SHIFT | + GPIO1A6_MASK << GPIO1A6_SHIFT | + GPIO1A5_MASK << GPIO1A5_SHIFT | + GPIO1A4_MASK << GPIO1A4_SHIFT, + GPIO1A7_UART1_RTS_N << GPIO1A7_SHIFT | + GPIO1A6_UART1_CTS_N << GPIO1A6_SHIFT | + GPIO1A5_UART1_SOUT << GPIO1A5_SHIFT | + GPIO1A4_UART1_SIN << GPIO1A4_SHIFT); + break; + case PERIPH_ID_UART2: + rk_clrsetreg(&grf->gpio1b_iomux, + GPIO1B1_MASK << GPIO1B1_SHIFT | + GPIO1B0_MASK << GPIO1B0_SHIFT, + GPIO1B1_UART2_SOUT << GPIO1B1_SHIFT | + GPIO1B0_UART2_SIN << GPIO1B0_SHIFT); + break; + case PERIPH_ID_UART3: + rk_clrsetreg(&grf->gpio1b_iomux, + GPIO1B5_MASK << GPIO1B5_SHIFT | + GPIO1B4_MASK << GPIO1B4_SHIFT | + GPIO1B3_MASK << GPIO1B3_SHIFT | + GPIO1B2_MASK << GPIO1B2_SHIFT, + GPIO1B5_UART3_RTS_N << GPIO1B5_SHIFT | + GPIO1B4_UART3_CTS_N << GPIO1B4_SHIFT | + GPIO1B3_UART3_SOUT << GPIO1B3_SHIFT | + GPIO1B2_UART3_SIN << GPIO1B2_SHIFT); + break; + default: + debug("uart id = %d iomux error!\n", uart_id); + break; + } +} + +static void pinctrl_rk3188_sdmmc_config(struct rk3188_grf *grf, int mmc_id) +{ + switch (mmc_id) { + case PERIPH_ID_EMMC: + rk_clrsetreg(&grf->soc_con0, 1 << EMMC_FLASH_SEL_SHIFT, + 1 << EMMC_FLASH_SEL_SHIFT); + rk_clrsetreg(&grf->gpio0d_iomux, + GPIO0D2_MASK << GPIO0D2_SHIFT | + GPIO0D0_MASK << GPIO0D0_SHIFT, + GPIO0D2_EMMC_CMD << GPIO0D2_SHIFT | + GPIO0D0_EMMC_CLKOUT << GPIO0D0_SHIFT); + break; + case PERIPH_ID_SDCARD: + rk_clrsetreg(&grf->gpio3b_iomux, + GPIO3B0_MASK << GPIO3B0_SHIFT, + GPIO3B0_SDMMC_DETECT_N << GPIO3B0_SHIFT); + rk_clrsetreg(&grf->gpio3a_iomux, + GPIO3A7_MASK << GPIO3A7_SHIFT | + GPIO3A6_MASK << GPIO3A6_SHIFT | + GPIO3A5_MASK << GPIO3A5_SHIFT | + GPIO3A4_MASK << GPIO3A4_SHIFT | + GPIO3A3_MASK << GPIO3A3_SHIFT | + GPIO3A3_MASK << GPIO3A2_SHIFT, + GPIO3A7_SDMMC0_DATA3 << GPIO3A7_SHIFT | + GPIO3A6_SDMMC0_DATA2 << GPIO3A6_SHIFT | + GPIO3A5_SDMMC0_DATA1 << GPIO3A5_SHIFT | + GPIO3A4_SDMMC0_DATA0 << GPIO3A4_SHIFT | + GPIO3A3_SDMMC0_CMD << GPIO3A3_SHIFT | + GPIO3A2_SDMMC0_CLKOUT << GPIO3A2_SHIFT); + break; + default: + debug("mmc id = %d iomux error!\n", mmc_id); + break; + } +} + +static int rk3188_pinctrl_request(struct udevice *dev, int func, int flags) +{ + struct rk3188_pinctrl_priv *priv = dev_get_priv(dev); + + debug("%s: func=%x, flags=%x\n", __func__, func, flags); + switch (func) { + case PERIPH_ID_PWM0: + case PERIPH_ID_PWM1: + case PERIPH_ID_PWM2: + case PERIPH_ID_PWM3: + case PERIPH_ID_PWM4: + pinctrl_rk3188_pwm_config(priv->grf, func); + break; + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + pinctrl_rk3188_i2c_config(priv->grf, priv->pmu, func); + break; + case PERIPH_ID_SPI0: + case PERIPH_ID_SPI1: + case PERIPH_ID_SPI2: + pinctrl_rk3188_spi_config(priv->grf, func, flags); + break; + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART2: + case PERIPH_ID_UART3: + case PERIPH_ID_UART4: + pinctrl_rk3188_uart_config(priv->grf, func); + break; + break; + case PERIPH_ID_SDMMC0: + case PERIPH_ID_SDMMC1: + pinctrl_rk3188_sdmmc_config(priv->grf, func); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rk3188_pinctrl_get_periph_id(struct udevice *dev, + struct udevice *periph) +{ + u32 cell[3]; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset, + "interrupts", cell, ARRAY_SIZE(cell)); + if (ret < 0) + return -EINVAL; + + switch (cell[1]) { + case 44: + return PERIPH_ID_SPI0; + case 45: + return PERIPH_ID_SPI1; + case 46: + return PERIPH_ID_SPI2; + case 60: + return PERIPH_ID_I2C0; + case 62: /* Note strange order */ + return PERIPH_ID_I2C1; + case 61: + return PERIPH_ID_I2C2; + case 63: + return PERIPH_ID_I2C3; + case 64: + return PERIPH_ID_I2C4; + case 65: + return PERIPH_ID_I2C5; + } + + return -ENOENT; +} + +static int rk3188_pinctrl_set_state_simple(struct udevice *dev, + struct udevice *periph) +{ + int func; + + func = rk3188_pinctrl_get_periph_id(dev, periph); + if (func < 0) + return func; + return rk3188_pinctrl_request(dev, func, 0); +} + +#ifndef CONFIG_SPL_BUILD +int rk3188_pinctrl_get_pin_info(struct rk3188_pinctrl_priv *priv, + int banknum, int ind, u32 **addrp, uint *shiftp, + uint *maskp) +{ + struct rockchip_pin_bank *bank = &rk3188_pin_banks[banknum]; + uint muxnum; + u32 *addr; + + for (muxnum = 0; muxnum < 4; muxnum++) { + struct rockchip_iomux *mux = &bank->iomux[muxnum]; + + if (ind >= 8) { + ind -= 8; + continue; + } + + addr = &priv->grf->gpio0c_iomux - 2; + addr += mux->offset; + *shiftp = ind & 7; + *maskp = 3; + *shiftp *= 2; + + debug("%s: addr=%p, mask=%x, shift=%x\n", __func__, addr, + *maskp, *shiftp); + *addrp = addr; + return 0; + } + + return -EINVAL; +} + +static int rk3188_pinctrl_get_gpio_mux(struct udevice *dev, int banknum, + int index) +{ + struct rk3188_pinctrl_priv *priv = dev_get_priv(dev); + uint shift; + uint mask; + u32 *addr; + int ret; + + ret = rk3188_pinctrl_get_pin_info(priv, banknum, index, &addr, &shift, + &mask); + if (ret) + return ret; + return (readl(addr) & mask) >> shift; +} + +static int rk3188_pinctrl_set_pins(struct udevice *dev, int banknum, int index, + int muxval, int flags) +{ + struct rk3188_pinctrl_priv *priv = dev_get_priv(dev); + uint shift, ind = index; + uint mask; + u32 *addr; + int ret; + + debug("%s: %x %x %x %x\n", __func__, banknum, index, muxval, flags); + ret = rk3188_pinctrl_get_pin_info(priv, banknum, index, &addr, &shift, + &mask); + if (ret) + return ret; + rk_clrsetreg(addr, mask << shift, muxval << shift); + + /* Handle pullup/pulldown */ + if (flags) { + uint val = 0; + + if (flags & (1 << PIN_CONFIG_BIAS_PULL_UP)) + val = 1; + else if (flags & (1 << PIN_CONFIG_BIAS_PULL_DOWN)) + val = 2; + + ind = index >> 3; + + if (banknum == 0 && index < 12) { + addr = &priv->pmu->gpio0_p[ind]; + shift = (index & 7) * 2; + } else if (banknum == 0 && index >= 12) { + addr = &priv->grf->gpio0_p[ind - 1]; + /* + * The bits in the grf-registers have an inverse + * ordering with the lowest pin being in bits 15:14 + * and the highest pin in bits 1:0 . + */ + shift = (7 - (index & 7)) * 2; + } else { + addr = &priv->grf->gpio1_p[banknum - 1][ind]; + shift = (7 - (index & 7)) * 2; + } + debug("%s: addr=%p, val=%x, shift=%x\n", __func__, addr, val, + shift); + rk_clrsetreg(addr, 3 << shift, val << shift); + } + + return 0; +} + +static int rk3188_pinctrl_set_state(struct udevice *dev, struct udevice *config) +{ + const void *blob = gd->fdt_blob; + int pcfg_node, ret, flags, count, i; + u32 cell[60], *ptr; + + debug("%s: %s %s\n", __func__, dev->name, config->name); + ret = fdtdec_get_int_array_count(blob, config->of_offset, + "rockchip,pins", cell, + ARRAY_SIZE(cell)); + if (ret < 0) { + debug("%s: bad array %d\n", __func__, ret); + return -EINVAL; + } + count = ret; + for (i = 0, ptr = cell; i < count; i += 4, ptr += 4) { + pcfg_node = fdt_node_offset_by_phandle(blob, ptr[3]); + if (pcfg_node < 0) + return -EINVAL; + flags = pinctrl_decode_pin_config(blob, pcfg_node); + if (flags < 0) + return flags; + + ret = rk3188_pinctrl_set_pins(dev, ptr[0], ptr[1], ptr[2], + flags); + if (ret) + return ret; + } + + return 0; +} +#endif + +static struct pinctrl_ops rk3188_pinctrl_ops = { +#ifndef CONFIG_SPL_BUILD + .set_state = rk3188_pinctrl_set_state, + .get_gpio_mux = rk3188_pinctrl_get_gpio_mux, +#endif + .set_state_simple = rk3188_pinctrl_set_state_simple, + .request = rk3188_pinctrl_request, + .get_periph_id = rk3188_pinctrl_get_periph_id, +}; + +static int rk3188_pinctrl_bind(struct udevice *dev) +{ + /* scan child GPIO banks */ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + +#ifndef CONFIG_SPL_BUILD +static int rk3188_pinctrl_parse_tables(struct rk3188_pinctrl_priv *priv, + struct rockchip_pin_bank *banks, + int count) +{ + struct rockchip_pin_bank *bank; + uint reg, muxnum, banknum; + + reg = 0; + for (banknum = 0; banknum < count; banknum++) { + bank = &banks[banknum]; + bank->reg = reg; + debug("%s: bank %d, reg %x\n", __func__, banknum, reg * 4); + for (muxnum = 0; muxnum < 4; muxnum++) { + struct rockchip_iomux *mux = &bank->iomux[muxnum]; + + mux->offset = reg; + reg += 1; + } + } + + return 0; +} +#endif + +static int rk3188_pinctrl_probe(struct udevice *dev) +{ + struct rk3188_pinctrl_priv *priv = dev_get_priv(dev); + int ret = 0; + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); + debug("%s: grf=%p, pmu=%p\n", __func__, priv->grf, priv->pmu); +#ifndef CONFIG_SPL_BUILD + ret = rk3188_pinctrl_parse_tables(priv, rk3188_pin_banks, + ARRAY_SIZE(rk3188_pin_banks)); +#endif + + return ret; +} + +static const struct udevice_id rk3188_pinctrl_ids[] = { + { .compatible = "rockchip,rk3188-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_rk3188) = { + .name = "pinctrl_rk3188", + .id = UCLASS_PINCTRL, + .of_match = rk3188_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct rk3188_pinctrl_priv), + .ops = &rk3188_pinctrl_ops, + .bind = rk3188_pinctrl_bind, + .probe = rk3188_pinctrl_probe, +};

Bring in required device clock binding files from Linux. The clock trees for rk3066 and rk3188 are largely similar, which makes them share the common parts in a shared header. While we focus on rk3188 for now, bring in both headers already for completeness sake.
Signed-off-by: Heiko Stuebner heiko@sntech.de --- include/dt-bindings/clock/rk3066a-cru.h | 32 ++++ include/dt-bindings/clock/rk3188-cru-common.h | 248 ++++++++++++++++++++++++++ include/dt-bindings/clock/rk3188-cru.h | 48 +++++ 3 files changed, 328 insertions(+) create mode 100644 include/dt-bindings/clock/rk3066a-cru.h create mode 100644 include/dt-bindings/clock/rk3188-cru-common.h create mode 100644 include/dt-bindings/clock/rk3188-cru.h
diff --git a/include/dt-bindings/clock/rk3066a-cru.h b/include/dt-bindings/clock/rk3066a-cru.h new file mode 100644 index 0000000..549ae6a --- /dev/null +++ b/include/dt-bindings/clock/rk3066a-cru.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner heiko@sntech.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3066A_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3066A_H + +#include <dt-bindings/clock/rk3188-cru-common.h> + +/* soft-reset indices */ +#define SRST_SRST1 0 +#define SRST_SRST2 1 + +#define SRST_L2MEM 18 +#define SRST_I2S0 23 +#define SRST_I2S1 24 +#define SRST_I2S2 25 +#define SRST_TIMER2 29 + +#define SRST_GPIO4 36 +#define SRST_GPIO6 38 + +#define SRST_TSADC 92 + +#define SRST_HDMI 96 +#define SRST_HDMI_APB 97 +#define SRST_CIF1 111 + +#endif diff --git a/include/dt-bindings/clock/rk3188-cru-common.h b/include/dt-bindings/clock/rk3188-cru-common.h new file mode 100644 index 0000000..f07c4a4 --- /dev/null +++ b/include/dt-bindings/clock/rk3188-cru-common.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner heiko@sntech.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3188_COMMON_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3188_COMMON_H + +/* core clocks from */ +#define PLL_APLL 1 +#define PLL_DPLL 2 +#define PLL_CPLL 3 +#define PLL_GPLL 4 +#define CORE_PERI 5 +#define CORE_L2C 6 +#define ARMCLK 7 + +/* sclk gates (special clocks) */ +#define SCLK_UART0 64 +#define SCLK_UART1 65 +#define SCLK_UART2 66 +#define SCLK_UART3 67 +#define SCLK_MAC 68 +#define SCLK_SPI0 69 +#define SCLK_SPI1 70 +#define SCLK_SARADC 71 +#define SCLK_SDMMC 72 +#define SCLK_SDIO 73 +#define SCLK_EMMC 74 +#define SCLK_I2S0 75 +#define SCLK_I2S1 76 +#define SCLK_I2S2 77 +#define SCLK_SPDIF 78 +#define SCLK_CIF0 79 +#define SCLK_CIF1 80 +#define SCLK_OTGPHY0 81 +#define SCLK_OTGPHY1 82 +#define SCLK_HSADC 83 +#define SCLK_TIMER0 84 +#define SCLK_TIMER1 85 +#define SCLK_TIMER2 86 +#define SCLK_TIMER3 87 +#define SCLK_TIMER4 88 +#define SCLK_TIMER5 89 +#define SCLK_TIMER6 90 +#define SCLK_JTAG 91 +#define SCLK_SMC 92 +#define SCLK_TSADC 93 + +#define DCLK_LCDC0 190 +#define DCLK_LCDC1 191 + +/* aclk gates */ +#define ACLK_DMA1 192 +#define ACLK_DMA2 193 +#define ACLK_GPS 194 +#define ACLK_LCDC0 195 +#define ACLK_LCDC1 196 +#define ACLK_GPU 197 +#define ACLK_SMC 198 +#define ACLK_CIF 199 +#define ACLK_IPP 200 +#define ACLK_RGA 201 +#define ACLK_CIF0 202 + +/* pclk gates */ +#define PCLK_GRF 320 +#define PCLK_PMU 321 +#define PCLK_TIMER0 322 +#define PCLK_TIMER1 323 +#define PCLK_TIMER2 324 +#define PCLK_TIMER3 325 +#define PCLK_PWM01 326 +#define PCLK_PWM23 327 +#define PCLK_SPI0 328 +#define PCLK_SPI1 329 +#define PCLK_SARADC 330 +#define PCLK_WDT 331 +#define PCLK_UART0 332 +#define PCLK_UART1 333 +#define PCLK_UART2 334 +#define PCLK_UART3 335 +#define PCLK_I2C0 336 +#define PCLK_I2C1 337 +#define PCLK_I2C2 338 +#define PCLK_I2C3 339 +#define PCLK_I2C4 340 +#define PCLK_GPIO0 341 +#define PCLK_GPIO1 342 +#define PCLK_GPIO2 343 +#define PCLK_GPIO3 344 +#define PCLK_GPIO4 345 +#define PCLK_GPIO6 346 +#define PCLK_EFUSE 347 +#define PCLK_TZPC 348 +#define PCLK_TSADC 349 + +/* hclk gates */ +#define HCLK_SDMMC 448 +#define HCLK_SDIO 449 +#define HCLK_EMMC 450 +#define HCLK_OTG0 451 +#define HCLK_EMAC 452 +#define HCLK_SPDIF 453 +#define HCLK_I2S0 454 +#define HCLK_I2S1 455 +#define HCLK_I2S2 456 +#define HCLK_OTG1 457 +#define HCLK_HSIC 458 +#define HCLK_HSADC 459 +#define HCLK_PIDF 460 +#define HCLK_LCDC0 461 +#define HCLK_LCDC1 462 +#define HCLK_ROM 463 +#define HCLK_CIF0 464 +#define HCLK_IPP 465 +#define HCLK_RGA 466 +#define HCLK_NANDC0 467 + +#define CLK_NR_CLKS (HCLK_NANDC0 + 1) + +/* soft-reset indices */ +#define SRST_MCORE 2 +#define SRST_CORE0 3 +#define SRST_CORE1 4 +#define SRST_MCORE_DBG 7 +#define SRST_CORE0_DBG 8 +#define SRST_CORE1_DBG 9 +#define SRST_CORE0_WDT 12 +#define SRST_CORE1_WDT 13 +#define SRST_STRC_SYS 14 +#define SRST_L2C 15 + +#define SRST_CPU_AHB 17 +#define SRST_AHB2APB 19 +#define SRST_DMA1 20 +#define SRST_INTMEM 21 +#define SRST_ROM 22 +#define SRST_SPDIF 26 +#define SRST_TIMER0 27 +#define SRST_TIMER1 28 +#define SRST_EFUSE 30 + +#define SRST_GPIO0 32 +#define SRST_GPIO1 33 +#define SRST_GPIO2 34 +#define SRST_GPIO3 35 + +#define SRST_UART0 39 +#define SRST_UART1 40 +#define SRST_UART2 41 +#define SRST_UART3 42 +#define SRST_I2C0 43 +#define SRST_I2C1 44 +#define SRST_I2C2 45 +#define SRST_I2C3 46 +#define SRST_I2C4 47 + +#define SRST_PWM0 48 +#define SRST_PWM1 49 +#define SRST_DAP_PO 50 +#define SRST_DAP 51 +#define SRST_DAP_SYS 52 +#define SRST_TPIU_ATB 53 +#define SRST_PMU_APB 54 +#define SRST_GRF 55 +#define SRST_PMU 56 +#define SRST_PERI_AXI 57 +#define SRST_PERI_AHB 58 +#define SRST_PERI_APB 59 +#define SRST_PERI_NIU 60 +#define SRST_CPU_PERI 61 +#define SRST_EMEM_PERI 62 +#define SRST_USB_PERI 63 + +#define SRST_DMA2 64 +#define SRST_SMC 65 +#define SRST_MAC 66 +#define SRST_NANC0 68 +#define SRST_USBOTG0 69 +#define SRST_USBPHY0 70 +#define SRST_OTGC0 71 +#define SRST_USBOTG1 72 +#define SRST_USBPHY1 73 +#define SRST_OTGC1 74 +#define SRST_HSADC 76 +#define SRST_PIDFILTER 77 +#define SRST_DDR_MSCH 79 + +#define SRST_TZPC 80 +#define SRST_SDMMC 81 +#define SRST_SDIO 82 +#define SRST_EMMC 83 +#define SRST_SPI0 84 +#define SRST_SPI1 85 +#define SRST_WDT 86 +#define SRST_SARADC 87 +#define SRST_DDRPHY 88 +#define SRST_DDRPHY_APB 89 +#define SRST_DDRCTL 90 +#define SRST_DDRCTL_APB 91 +#define SRST_DDRPUB 93 + +#define SRST_VIO0_AXI 98 +#define SRST_VIO0_AHB 99 +#define SRST_LCDC0_AXI 100 +#define SRST_LCDC0_AHB 101 +#define SRST_LCDC0_DCLK 102 +#define SRST_LCDC1_AXI 103 +#define SRST_LCDC1_AHB 104 +#define SRST_LCDC1_DCLK 105 +#define SRST_IPP_AXI 106 +#define SRST_IPP_AHB 107 +#define SRST_RGA_AXI 108 +#define SRST_RGA_AHB 109 +#define SRST_CIF0 110 + +#define SRST_VCODEC_AXI 112 +#define SRST_VCODEC_AHB 113 +#define SRST_VIO1_AXI 114 +#define SRST_VCODEC_CPU 115 +#define SRST_VCODEC_NIU 116 +#define SRST_GPU 120 +#define SRST_GPU_NIU 122 +#define SRST_TFUN_ATB 125 +#define SRST_TFUN_APB 126 +#define SRST_CTI4_APB 127 + +#define SRST_TPIU_APB 128 +#define SRST_TRACE 129 +#define SRST_CORE_DBG 130 +#define SRST_DBG_APB 131 +#define SRST_CTI0 132 +#define SRST_CTI0_APB 133 +#define SRST_CTI1 134 +#define SRST_CTI1_APB 135 +#define SRST_PTM_CORE0 136 +#define SRST_PTM_CORE1 137 +#define SRST_PTM0 138 +#define SRST_PTM0_ATB 139 +#define SRST_PTM1 140 +#define SRST_PTM1_ATB 141 +#define SRST_CTM 142 +#define SRST_TS 143 + +#endif diff --git a/include/dt-bindings/clock/rk3188-cru.h b/include/dt-bindings/clock/rk3188-cru.h new file mode 100644 index 0000000..b6960b0 --- /dev/null +++ b/include/dt-bindings/clock/rk3188-cru.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner heiko@sntech.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3188_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3188_H + +#include <dt-bindings/clock/rk3188-cru-common.h> + +/* soft-reset indices */ +#define SRST_PTM_CORE2 0 +#define SRST_PTM_CORE3 1 +#define SRST_CORE2 5 +#define SRST_CORE3 6 +#define SRST_CORE2_DBG 10 +#define SRST_CORE3_DBG 11 + +#define SRST_TIMER2 16 +#define SRST_TIMER4 23 +#define SRST_I2S0 24 +#define SRST_TIMER5 25 +#define SRST_TIMER3 29 +#define SRST_TIMER6 31 + +#define SRST_PTM3 36 +#define SRST_PTM3_ATB 37 + +#define SRST_GPS 67 +#define SRST_HSICPHY 75 +#define SRST_TIMER 78 + +#define SRST_PTM2 92 +#define SRST_CORE2_WDT 94 +#define SRST_CORE3_WDT 95 + +#define SRST_PTM2_ATB 111 + +#define SRST_HSIC 117 +#define SRST_CTI2 118 +#define SRST_CTI2_APB 119 +#define SRST_GPU_BRIDGE 121 +#define SRST_CTI3 123 +#define SRST_CTI3_APB 124 + +#endif

On 22 July 2016 at 15:51, Heiko Stuebner heiko@sntech.de wrote:
Bring in required device clock binding files from Linux. The clock trees for rk3066 and rk3188 are largely similar, which makes them share the common parts in a shared header. While we focus on rk3188 for now, bring in both headers already for completeness sake.
Signed-off-by: Heiko Stuebner heiko@sntech.de
include/dt-bindings/clock/rk3066a-cru.h | 32 ++++ include/dt-bindings/clock/rk3188-cru-common.h | 248 ++++++++++++++++++++++++++ include/dt-bindings/clock/rk3188-cru.h | 48 +++++ 3 files changed, 328 insertions(+) create mode 100644 include/dt-bindings/clock/rk3066a-cru.h create mode 100644 include/dt-bindings/clock/rk3188-cru-common.h create mode 100644 include/dt-bindings/clock/rk3188-cru.h
Acked-by: Simon Glass sjg@chromium.org

Add a driver for setting up and modifying the various PLLs and peripheral clocks on the RK3188.
Signed-off-by: Heiko Stuebner heiko@sntech.de --- arch/arm/include/asm/arch-rockchip/cru_rk3188.h | 183 +++++++++ drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk_rk3188.c | 493 ++++++++++++++++++++++++ 3 files changed, 677 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3188.h create mode 100644 drivers/clk/rockchip/clk_rk3188.c
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3188.h b/arch/arm/include/asm/arch-rockchip/cru_rk3188.h new file mode 100644 index 0000000..8d1daec --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3188.h @@ -0,0 +1,183 @@ +/* + * (C) Copyright 2016 Heiko Stuebner heiko@sntech.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _ASM_ARCH_CRU_RK3188_H +#define _ASM_ARCH_CRU_RK3188_H + +#define OSC_HZ (24 * 1000 * 1000) + +#define APLL_HZ (1608 * 1000000) +#define GPLL_HZ (594 * 1000000) +#define CPLL_HZ (384 * 1000000) + +/* The SRAM is clocked off aclk_cpu, so we want to max it out for boot speed */ +#define CPU_ACLK_HZ 297000000 +#define CPU_HCLK_HZ 148500000 +#define CPU_PCLK_HZ 74250000 +#define CPU_H2P_HZ 74250000 + +#define PERI_ACLK_HZ 148500000 +#define PERI_HCLK_HZ 148500000 +#define PERI_PCLK_HZ 74250000 + +struct rk3188_cru { + struct rk3188_pll { + u32 con0; + u32 con1; + u32 con2; + u32 con3; + } pll[4]; + u32 cru_mode_con; + u32 cru_clksel_con[35]; + u32 cru_clkgate_con[10]; + u32 reserved1[2]; + u32 cru_glb_srst_fst_value; + u32 cru_glb_srst_snd_value; + u32 reserved2[2]; + u32 cru_softrst_con[9]; + u32 cru_misc_con; + u32 reserved3[2]; + u32 cru_glb_cnt_th; +}; +check_member(rk3188_cru, cru_glb_cnt_th, 0x0140); + +/* CRU_CLKSEL0_CON */ +enum { + /* a9_core_div: core = core_src / (a9_core_div + 1) */ + A9_CORE_DIV_SHIFT = 9, + A9_CORE_DIV_MASK = 0x1f, + CORE_PLL_SHIFT = 8, + CORE_PLL_MASK = 1, + CORE_PLL_SELECT_APLL = 0, + CORE_PLL_SELECT_GPLL, + + /* core peri div: core:core_peri = 2:1, 4:1, 8:1 or 16:1 */ + CORE_PERI_DIV_SHIFT = 6, + CORE_PERI_DIV_MASK = 3, + + /* aclk_cpu pll selection */ + CPU_ACLK_PLL_SHIFT = 5, + CPU_ACLK_PLL_MASK = 1, + CPU_ACLK_PLL_SELECT_APLL = 0, + CPU_ACLK_PLL_SELECT_GPLL, + + /* a9_cpu_div: aclk_cpu = cpu_src / (a9_cpu_div + 1) */ + A9_CPU_DIV_SHIFT = 0, + A9_CPU_DIV_MASK = 0x1f, +}; + +/* CRU_CLKSEL1_CON */ +enum { + /* ahb2apb_pclk_div: hclk_cpu:pclk_cpu = 1:1, 2:1 or 4:1 */ + AHB2APB_DIV_SHIFT = 14, + AHB2APB_DIV_MASK = 3, + + /* cpu_pclk_div: aclk_cpu:pclk_cpu = 1:1, 2:1, 4:1 or 8:1 */ + CPU_PCLK_DIV_SHIFT = 12, + CPU_PCLK_DIV_MASK = 3, + + /* cpu_hclk_div: aclk_cpu:hclk_cpu = 1:1, 2:1 or 4:1 */ + CPU_HCLK_DIV_SHIFT = 8, + CPU_HCLK_DIV_MASK = 3, + + /* core_aclk_div: cire:aclk_core = 1:1, 2:1, 3:1, 4:1 or 8:1 */ + CORE_ACLK_DIV_SHIFT = 3, + CORE_ACLK_DIV_MASK = 7, +}; + +/* CRU_CLKSEL10_CON */ +enum { + PERI_SEL_PLL_MASK = 1, + PERI_SEL_PLL_SHIFT = 15, + PERI_SEL_CPLL = 0, + PERI_SEL_GPLL, + + /* peri pclk div: aclk_bus:pclk_bus = 1:1, 2:1, 4:1 or 8:1 */ + PERI_PCLK_DIV_SHIFT = 12, + PERI_PCLK_DIV_MASK = 3, + + /* peripheral bus hclk div:aclk_bus: hclk_bus = 1:1, 2:1 or 4:1 */ + PERI_HCLK_DIV_SHIFT = 8, + PERI_HCLK_DIV_MASK = 3, + + /* peri aclk div: aclk_peri = periph_src / (peri_aclk_div + 1) */ + PERI_ACLK_DIV_SHIFT = 0, + PERI_ACLK_DIV_MASK = 0x1f, +}; +/* CRU_CLKSEL11_CON */ +enum { + HSICPHY_DIV_SHIFT = 8, + HSICPHY_DIV_MASK = 0x3f, + + MMC0_DIV_SHIFT = 0, + MMC0_DIV_MASK = 0x3f, +}; + +/* CRU_CLKSEL12_CON */ +enum { + UART_PLL_SHIFT = 15, + UART_PLL_MASK = 1, + UART_PLL_SELECT_GENERAL = 0, + UART_PLL_SELECT_CODEC, + + EMMC_DIV_SHIFT = 8, + EMMC_DIV_MASK = 0x3f, + + SDIO_DIV_SHIFT = 0, + SDIO_DIV_MASK = 0x3f, +}; + +/* CRU_CLKSEL25_CON */ +enum { + SPI1_DIV_SHIFT = 8, + SPI1_DIV_MASK = 0x7f, + + SPI0_DIV_SHIFT = 0, + SPI0_DIV_MASK = 0x7f, +}; + +/* CRU_MODE_CON */ +enum { + GPLL_MODE_SHIFT = 12, + GPLL_MODE_MASK = 3, + GPLL_MODE_SLOW = 0, + GPLL_MODE_NORMAL, + GPLL_MODE_DEEP, + + CPLL_MODE_SHIFT = 8, + CPLL_MODE_MASK = 3, + CPLL_MODE_SLOW = 0, + CPLL_MODE_NORMAL, + CPLL_MODE_DEEP, + + DPLL_MODE_SHIFT = 4, + DPLL_MODE_MASK = 3, + DPLL_MODE_SLOW = 0, + DPLL_MODE_NORMAL, + DPLL_MODE_DEEP, + + APLL_MODE_SHIFT = 0, + APLL_MODE_MASK = 3, + APLL_MODE_SLOW = 0, + APLL_MODE_NORMAL, + APLL_MODE_DEEP, +}; + +/* CRU_APLL_CON0 */ +enum { + CLKR_SHIFT = 8, + CLKR_MASK = 0x3f, + + CLKOD_SHIFT = 0, + CLKOD_MASK = 0x3f, +}; + +/* CRU_APLL_CON1 */ +enum { + CLKF_SHIFT = 0, + CLKF_MASK = 0x1fff, +}; + +#endif diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index acfd858..cf922b4 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -5,4 +5,5 @@ #
obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o +obj-$(CONFIG_ROCKCHIP_RK3188) += clk_rk3188.o obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c new file mode 100644 index 0000000..6a6f4c2 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3188.c @@ -0,0 +1,493 @@ +/* + * (C) Copyright 2015 Google, Inc + * (C) Copyright 2016 Heiko Stuebner heiko@sntech.de + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dt-structs.h> +#include <errno.h> +#include <mapmem.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3188.h> +#include <asm/arch/grf_rk3188.h> +#include <asm/arch/hardware.h> +#include <dt-bindings/clock/rk3188-cru.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/uclass-internal.h> +#include <linux/log2.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum rk3188_clk_type { + RK3188_CRU, + RK3188A_CRU, +}; + +struct rk3188_clk_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3188_cru dtd; +#endif +}; + +struct rk3188_clk_priv { + struct rk3188_grf *grf; + struct rk3188_cru *cru; + ulong rate; + bool has_bwadj; +}; + +struct pll_div { + u32 nr; + u32 nf; + u32 no; +}; + +enum { + VCO_MAX_HZ = 2200U * 1000000, + VCO_MIN_HZ = 440 * 1000000, + OUTPUT_MAX_HZ = 2200U * 1000000, + OUTPUT_MIN_HZ = 30 * 1000000, + FREF_MAX_HZ = 2200U * 1000000, + FREF_MIN_HZ = 30 * 1000, +}; + +enum { + /* PLL CON0 */ + PLL_OD_MASK = 0x0f, + + /* PLL CON1 */ + PLL_NF_MASK = 0x1fff, + + /* PLL CON2 */ + PLL_BWADJ_MASK = 0x0fff, + + /* PLL CON3 */ + PLL_RESET_SHIFT = 5, + + /* GRF_SOC_STATUS0 */ + SOCSTS_DPLL_LOCK = 1 << 5, + SOCSTS_APLL_LOCK = 1 << 6, + SOCSTS_CPLL_LOCK = 1 << 7, + SOCSTS_GPLL_LOCK = 1 << 8, +}; + +#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__)); + +/* Keep divisors as low as possible to reduce jitter and power usage */ +static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1); +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); +static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); + +void *rockchip_get_cru(void) +{ + struct rk3188_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rockchip_get_clk(&dev); + if (ret) + return ERR_PTR(ret); + + priv = dev_get_priv(dev); + + return priv->cru; +} + +static int rkclk_set_pll(struct rk3188_cru *cru, enum rk_clk_id clk_id, + const struct pll_div *div, bool has_bwadj) +{ + int pll_id = rk_pll_id(clk_id); + struct rk3188_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 %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", + (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz); + assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && + output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ && + (div->no == 1 || !(div->no % 2))); + + /* enter reset */ + rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT); + + rk_clrsetreg(&pll->con0, + CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK, + ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1)); + rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1); + + if (has_bwadj) + rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1); + + udelay(10); + + /* return from reset */ + rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT); + + return 0; +} + +static void rkclk_init(struct rk3188_cru *cru, struct rk3188_grf *grf, + bool has_bwadj) +{ + u32 aclk_div, hclk_div, pclk_div, h2p_div; + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK << GPLL_MODE_SHIFT | + CPLL_MODE_MASK << CPLL_MODE_SHIFT, + GPLL_MODE_SLOW << GPLL_MODE_SHIFT | + CPLL_MODE_SLOW << CPLL_MODE_SHIFT); + + /* init pll */ + rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg, has_bwadj); + rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg, has_bwadj); + + /* waiting for pll lock */ + while ((readl(&grf->soc_status0) & + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) != + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) + udelay(1); + + /* + * cpu clock pll source selection and + * reparent aclk_cpu_pre from apll to gpll + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = RATE_TO_DIV(GPLL_HZ, CPU_ACLK_HZ); + assert((aclk_div + 1) * CPU_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); + + rk_clrsetreg(&cru->cru_clksel_con[0], + CPU_ACLK_PLL_MASK << CPU_ACLK_PLL_SHIFT | + A9_CPU_DIV_MASK << A9_CPU_DIV_SHIFT, + CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT | + aclk_div << A9_CPU_DIV_SHIFT); + + hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ); + assert((1 << hclk_div) * CPU_HCLK_HZ == CPU_ACLK_HZ && hclk_div < 0x3); + pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ); + assert((1 << pclk_div) * CPU_PCLK_HZ == CPU_ACLK_HZ && pclk_div < 0x4); + h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ); + assert((1 << h2p_div) * CPU_H2P_HZ == CPU_HCLK_HZ && pclk_div < 0x3); + + rk_clrsetreg(&cru->cru_clksel_con[1], + AHB2APB_DIV_MASK << AHB2APB_DIV_SHIFT | + CPU_PCLK_DIV_MASK << CPU_PCLK_DIV_SHIFT | + CPU_HCLK_DIV_MASK << CPU_HCLK_DIV_SHIFT, + h2p_div << AHB2APB_DIV_SHIFT | + pclk_div << CPU_PCLK_DIV_SHIFT | + hclk_div << CPU_HCLK_DIV_SHIFT); + + /* + * peri clock pll source selection and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; + assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); + + hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); + assert((1 << hclk_div) * PERI_HCLK_HZ == + 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 < 0x4)); + + rk_clrsetreg(&cru->cru_clksel_con[10], + 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_SEL_GPLL << PERI_SEL_PLL_SHIFT | + pclk_div << PERI_PCLK_DIV_SHIFT | + hclk_div << PERI_HCLK_DIV_SHIFT | + aclk_div << PERI_ACLK_DIV_SHIFT); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK << GPLL_MODE_SHIFT | + CPLL_MODE_MASK << CPLL_MODE_SHIFT, + GPLL_MODE_NORMAL << GPLL_MODE_SHIFT | + CPLL_MODE_NORMAL << CPLL_MODE_SHIFT); +} + +/* Get pll rate by id */ +static uint32_t rkclk_pll_get_rate(struct rk3188_cru *cru, + enum rk_clk_id clk_id) +{ + uint32_t nr, no, nf; + uint32_t con; + int pll_id = rk_pll_id(clk_id); + struct rk3188_pll *pll = &cru->pll[pll_id]; + static u8 clk_shift[CLK_COUNT] = { + 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, + GPLL_MODE_SHIFT + }; + uint shift; + + con = readl(&cru->cru_mode_con); + shift = clk_shift[clk_id]; + switch ((con >> shift) & APLL_MODE_MASK) { + case APLL_MODE_SLOW: + return OSC_HZ; + case APLL_MODE_NORMAL: + /* normal mode */ + con = readl(&pll->con0); + no = ((con >> CLKOD_SHIFT) & CLKOD_MASK) + 1; + nr = ((con >> CLKR_SHIFT) & CLKR_MASK) + 1; + con = readl(&pll->con1); + nf = ((con >> CLKF_SHIFT) & CLKF_MASK) + 1; + + return (24 * nf / (nr * no)) * 1000000; + case APLL_MODE_DEEP: + default: + return 32768; + } +} + +static ulong rockchip_mmc_get_clk(struct rk3188_cru *cru, uint gclk_rate, + int periph) +{ + uint div; + u32 con; + + switch (periph) { + case HCLK_EMMC: + con = readl(&cru->cru_clksel_con[12]); + div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; + break; + case HCLK_SDMMC: + con = readl(&cru->cru_clksel_con[11]); + div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; + break; + case HCLK_SDIO: + con = readl(&cru->cru_clksel_con[12]); + div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK; + break; + default: + return -EINVAL; + } + + return DIV_TO_RATE(gclk_rate, div); +} + +static ulong rockchip_mmc_set_clk(struct rk3188_cru *cru, uint gclk_rate, + int periph, uint freq) +{ + int src_clk_div; + + debug("%s: gclk_rate=%u\n", __func__, gclk_rate); + src_clk_div = RATE_TO_DIV(gclk_rate, freq); + assert(src_clk_div <= 0x3f); + + switch (periph) { + case HCLK_EMMC: + rk_clrsetreg(&cru->cru_clksel_con[12], + EMMC_DIV_MASK << EMMC_DIV_SHIFT, + src_clk_div << EMMC_DIV_SHIFT); + break; + case HCLK_SDMMC: + rk_clrsetreg(&cru->cru_clksel_con[11], + MMC0_DIV_MASK << MMC0_DIV_SHIFT, + src_clk_div << MMC0_DIV_SHIFT); + break; + case HCLK_SDIO: + rk_clrsetreg(&cru->cru_clksel_con[12], + SDIO_DIV_MASK << SDIO_DIV_SHIFT, + src_clk_div << SDIO_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_mmc_get_clk(cru, gclk_rate, periph); +} + +static ulong rockchip_spi_get_clk(struct rk3188_cru *cru, uint gclk_rate, + int periph) +{ + uint div; + u32 con; + + switch (periph) { + case SCLK_SPI0: + con = readl(&cru->cru_clksel_con[25]); + div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK; + break; + case SCLK_SPI1: + con = readl(&cru->cru_clksel_con[25]); + div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK; + break; + default: + return -EINVAL; + } + + return DIV_TO_RATE(gclk_rate, div); +} + +static ulong rockchip_spi_set_clk(struct rk3188_cru *cru, uint gclk_rate, + int periph, uint freq) +{ + int src_clk_div = RATE_TO_DIV(gclk_rate, freq); + + switch (periph) { + case SCLK_SPI0: + assert(src_clk_div <= SPI0_DIV_MASK); + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI0_DIV_MASK << SPI0_DIV_SHIFT, + src_clk_div << SPI0_DIV_SHIFT); + break; + case SCLK_SPI1: + assert(src_clk_div <= SPI1_DIV_MASK); + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI1_DIV_MASK << SPI1_DIV_SHIFT, + src_clk_div << SPI1_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_spi_get_clk(cru, gclk_rate, periph); +} + +static ulong rk3188_clk_get_rate(struct clk *clk) +{ + struct rk3188_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate, gclk_rate; + + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 1 ... 4: + new_rate = rkclk_pll_get_rate(priv->cru, clk->id); + break; + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO: + new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ, + clk->id); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ, + clk->id); + break; + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_I2C4: + return gclk_rate; + default: + return -ENOENT; + } + + return new_rate; +} + +static ulong rk3188_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3188_clk_priv *priv = dev_get_priv(clk->dev); + struct rk3188_cru *cru = priv->cru; + ulong new_rate; + + switch (clk->id) { + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO: + new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, + clk->id, rate); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ, + clk->id, rate); + break; + default: + return -ENOENT; + } + + return new_rate; +} + +static struct clk_ops rk3188_clk_ops = { + .get_rate = rk3188_clk_get_rate, + .set_rate = rk3188_clk_set_rate, +}; + +static int rk3188_clk_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3188_clk_priv *priv = dev_get_priv(dev); + + priv->cru = (struct rk3188_cru *)dev_get_addr(dev); +#endif + + return 0; +} + +static int rk3188_clk_probe(struct udevice *dev) +{ + struct rk3188_clk_priv *priv = dev_get_priv(dev); + enum rk3188_clk_type type = dev_get_driver_data(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + if (IS_ERR(priv->grf)) + return PTR_ERR(priv->grf); + priv->has_bwadj = (type == RK3188A_CRU) ? 1 : 0; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3188_clk_plat *plat = dev_get_platdata(dev); + + priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); +#endif + + /* we don't have a spl yet, so call rkclk_init at the regular time */ + rkclk_init(priv->cru, priv->grf, priv->has_bwadj); + + return 0; +} + +static int rk3188_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, "rk3188_sysreset", "reset", &dev); + if (ret) + debug("Warning: No rk3188 reset driver: ret=%d\n", ret); + + return 0; +} + +static const struct udevice_id rk3188_clk_ids[] = { + { .compatible = "rockchip,rk3188-cru", .data = RK3188_CRU }, + { .compatible = "rockchip,rk3188a-cru", .data = RK3188A_CRU }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3188_cru) = { + .name = "rockchip_rk3188_cru", + .id = UCLASS_CLK, + .of_match = rk3188_clk_ids, + .priv_auto_alloc_size = sizeof(struct rk3188_clk_priv), + .platdata_auto_alloc_size = sizeof(struct rk3188_clk_plat), + .ops = &rk3188_clk_ops, + .bind = rk3188_clk_bind, + .ofdata_to_platdata = rk3188_clk_ofdata_to_platdata, + .probe = rk3188_clk_probe, +};

On 22 July 2016 at 15:51, Heiko Stuebner heiko@sntech.de wrote:
Add a driver for setting up and modifying the various PLLs and peripheral clocks on the RK3188.
Signed-off-by: Heiko Stuebner heiko@sntech.de
arch/arm/include/asm/arch-rockchip/cru_rk3188.h | 183 +++++++++ drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk_rk3188.c | 493 ++++++++++++++++++++++++ 3 files changed, 677 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3188.h create mode 100644 drivers/clk/rockchip/clk_rk3188.c
Acked-by: Simon Glass sjg@chromium.org
Do you actually using CONFIG_OF_PLATDATA?

Add the core architecture code for the rk3188. It doesn't support the SPL yet, as because of some unknown error it doesn't start yet.
Signed-off-by: Heiko Stuebner heiko@sntech.de --- arch/arm/dts/rk3188.dtsi | 631 ++++++++++++++++++++++++++ arch/arm/dts/rk3xxx.dtsi | 431 ++++++++++++++++++ arch/arm/mach-rockchip/Kconfig | 11 + arch/arm/mach-rockchip/Makefile | 1 + arch/arm/mach-rockchip/rk3188/Kconfig | 9 + arch/arm/mach-rockchip/rk3188/Makefile | 9 + arch/arm/mach-rockchip/rk3188/clk_rk3188.c | 17 + arch/arm/mach-rockchip/rk3188/reset_rk3188.c | 47 ++ arch/arm/mach-rockchip/rk3188/syscon_rk3188.c | 24 + include/configs/rk3188_common.h | 95 ++++ tools/rkcommon.c | 1 + 11 files changed, 1276 insertions(+) create mode 100644 arch/arm/dts/rk3188.dtsi create mode 100644 arch/arm/dts/rk3xxx.dtsi create mode 100644 arch/arm/mach-rockchip/rk3188/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3188/Makefile create mode 100644 arch/arm/mach-rockchip/rk3188/clk_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/reset_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/syscon_rk3188.c create mode 100644 include/configs/rk3188_common.h
diff --git a/arch/arm/dts/rk3188.dtsi b/arch/arm/dts/rk3188.dtsi new file mode 100644 index 0000000..ef1b962 --- /dev/null +++ b/arch/arm/dts/rk3188.dtsi @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2013 MundoReader S.L. + * Author: Heiko Stuebner heiko@sntech.de + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/pinctrl/rockchip.h> +#include <dt-bindings/clock/rk3188-cru.h> +#include "rk3xxx.dtsi" + +/ { + compatible = "rockchip,rk3188"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "rockchip,rk3066-smp"; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + reg = <0x0>; + operating-points = < + /* kHz uV */ + 1608000 1350000 + 1416000 1250000 + 1200000 1150000 + 1008000 1075000 + 816000 975000 + 600000 950000 + 504000 925000 + 312000 875000 + >; + clock-latency = <40000>; + clocks = <&cru ARMCLK>; + }; + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + reg = <0x1>; + }; + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + reg = <0x2>; + }; + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + reg = <0x3>; + }; + }; + + sram: sram@10080000 { + compatible = "mmio-sram"; + reg = <0x10080000 0x8000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x10080000 0x8000>; + + smp-sram@0 { + compatible = "rockchip,rk3066-smp-sram"; + reg = <0x0 0x50>; + }; + }; + + i2s0: i2s@1011a000 { + compatible = "rockchip,rk3188-i2s", "rockchip,rk3066-i2s"; + reg = <0x1011a000 0x2000>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_bus>; + dmas = <&dmac1_s 6>, <&dmac1_s 7>; + dma-names = "tx", "rx"; + clock-names = "i2s_hclk", "i2s_clk"; + clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>; + rockchip,playback-channels = <2>; + rockchip,capture-channels = <2>; + status = "disabled"; + }; + + spdif: sound@1011e000 { + compatible = "rockchip,rk3188-spdif", "rockchip,rk3066-spdif"; + reg = <0x1011e000 0x2000>; + #sound-dai-cells = <0>; + clock-names = "hclk", "mclk"; + clocks = <&cru HCLK_SPDIF>, <&cru SCLK_SPDIF>; + dmas = <&dmac1_s 8>; + dma-names = "tx"; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx>; + status = "disabled"; + }; + + cru: clock-controller@20000000 { + compatible = "rockchip,rk3188-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + + efuse: efuse@20010000 { + compatible = "rockchip,rockchip-efuse"; + reg = <0x20010000 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&cru PCLK_EFUSE>; + clock-names = "pclk_efuse"; + + cpu_leakage: cpu_leakage@17 { + reg = <0x17 0x1>; + }; + }; + + usbphy: phy { + compatible = "rockchip,rk3188-usb-phy", "rockchip,rk3288-usb-phy"; + rockchip,grf = <&grf>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + usbphy0: usb-phy@10c { + #phy-cells = <0>; + reg = <0x10c>; + clocks = <&cru SCLK_OTGPHY0>; + clock-names = "phyclk"; + #clock-cells = <0>; + }; + + usbphy1: usb-phy@11c { + #phy-cells = <0>; + reg = <0x11c>; + clocks = <&cru SCLK_OTGPHY1>; + clock-names = "phyclk"; + #clock-cells = <0>; + }; + }; + + pinctrl: pinctrl { + compatible = "rockchip,rk3188-pinctrl"; + rockchip,grf = <&grf>; + rockchip,pmu = <&pmu>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio0: gpio0@2000a000 { + compatible = "rockchip,gpio-bank"; + reg = <0x2000a000 0x100>; + interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO0>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio1@2003c000 { + compatible = "rockchip,gpio-bank"; + reg = <0x2003c000 0x100>; + interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO1>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio2@2003e000 { + compatible = "rockchip,gpio-bank"; + reg = <0x2003e000 0x100>; + interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO2>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio3@20080000 { + compatible = "rockchip,gpio-bank"; + reg = <0x20080000 0x100>; + interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO3>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + pcfg_pull_up: pcfg_pull_up { + bias-pull-up; + }; + + pcfg_pull_down: pcfg_pull_down { + bias-pull-down; + }; + + pcfg_pull_none: pcfg_pull_none { + bias-disable; + }; + + emmc { + emmc_clk: emmc-clk { + rockchip,pins = <RK_GPIO0 24 RK_FUNC_2 &pcfg_pull_none>; + }; + + emmc_cmd: emmc-cmd { + rockchip,pins = <RK_GPIO0 26 RK_FUNC_2 &pcfg_pull_up>; + }; + + emmc_rst: emmc-rst { + rockchip,pins = <RK_GPIO0 27 RK_FUNC_2 &pcfg_pull_none>; + }; + + /* + * The data pins are shared between nandc and emmc and + * not accessible through pinctrl. Also they should've + * been already set correctly by firmware, as + * flash/emmc is the boot-device. + */ + }; + + emac { + emac_xfer: emac-xfer { + rockchip,pins = <RK_GPIO3 16 RK_FUNC_2 &pcfg_pull_none>, /* tx_en */ + <RK_GPIO3 17 RK_FUNC_2 &pcfg_pull_none>, /* txd1 */ + <RK_GPIO3 18 RK_FUNC_2 &pcfg_pull_none>, /* txd0 */ + <RK_GPIO3 19 RK_FUNC_2 &pcfg_pull_none>, /* rxd0 */ + <RK_GPIO3 20 RK_FUNC_2 &pcfg_pull_none>, /* rxd1 */ + <RK_GPIO3 21 RK_FUNC_2 &pcfg_pull_none>, /* mac_clk */ + <RK_GPIO3 22 RK_FUNC_2 &pcfg_pull_none>, /* rx_err */ + <RK_GPIO3 23 RK_FUNC_2 &pcfg_pull_none>; /* crs_dvalid */ + }; + + emac_mdio: emac-mdio { + rockchip,pins = <RK_GPIO3 24 RK_FUNC_2 &pcfg_pull_none>, + <RK_GPIO3 25 RK_FUNC_2 &pcfg_pull_none>; + }; + }; + + i2c0 { + i2c0_xfer: i2c0-xfer { + rockchip,pins = <RK_GPIO1 24 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 25 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + i2c1 { + i2c1_xfer: i2c1-xfer { + rockchip,pins = <RK_GPIO1 26 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 27 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + i2c2 { + i2c2_xfer: i2c2-xfer { + rockchip,pins = <RK_GPIO1 28 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 29 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + i2c3 { + i2c3_xfer: i2c3-xfer { + rockchip,pins = <RK_GPIO3 14 RK_FUNC_2 &pcfg_pull_none>, + <RK_GPIO3 15 RK_FUNC_2 &pcfg_pull_none>; + }; + }; + + i2c4 { + i2c4_xfer: i2c4-xfer { + rockchip,pins = <RK_GPIO1 30 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 31 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + pwm0 { + pwm0_out: pwm0-out { + rockchip,pins = <RK_GPIO3 27 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + pwm1 { + pwm1_out: pwm1-out { + rockchip,pins = <RK_GPIO3 28 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + pwm2 { + pwm2_out: pwm2-out { + rockchip,pins = <RK_GPIO3 29 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + pwm3 { + pwm3_out: pwm3-out { + rockchip,pins = <RK_GPIO3 30 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + spi0 { + spi0_clk: spi0-clk { + rockchip,pins = <RK_GPIO1 6 RK_FUNC_2 &pcfg_pull_up>; + }; + spi0_cs0: spi0-cs0 { + rockchip,pins = <RK_GPIO1 7 RK_FUNC_2 &pcfg_pull_up>; + }; + spi0_tx: spi0-tx { + rockchip,pins = <RK_GPIO1 5 RK_FUNC_2 &pcfg_pull_up>; + }; + spi0_rx: spi0-rx { + rockchip,pins = <RK_GPIO1 4 RK_FUNC_2 &pcfg_pull_up>; + }; + spi0_cs1: spi0-cs1 { + rockchip,pins = <RK_GPIO1 15 RK_FUNC_1 &pcfg_pull_up>; + }; + }; + + spi1 { + spi1_clk: spi1-clk { + rockchip,pins = <RK_GPIO0 30 RK_FUNC_1 &pcfg_pull_up>; + }; + spi1_cs0: spi1-cs0 { + rockchip,pins = <RK_GPIO0 31 RK_FUNC_1 &pcfg_pull_up>; + }; + spi1_rx: spi1-rx { + rockchip,pins = <RK_GPIO0 28 RK_FUNC_1 &pcfg_pull_up>; + }; + spi1_tx: spi1-tx { + rockchip,pins = <RK_GPIO0 29 RK_FUNC_1 &pcfg_pull_up>; + }; + spi1_cs1: spi1-cs1 { + rockchip,pins = <RK_GPIO1 14 RK_FUNC_2 &pcfg_pull_up>; + }; + }; + + uart0 { + uart0_xfer: uart0-xfer { + rockchip,pins = <RK_GPIO1 0 RK_FUNC_1 &pcfg_pull_up>, + <RK_GPIO1 1 RK_FUNC_1 &pcfg_pull_none>; + }; + + uart0_cts: uart0-cts { + rockchip,pins = <RK_GPIO1 2 RK_FUNC_1 &pcfg_pull_none>; + }; + + uart0_rts: uart0-rts { + rockchip,pins = <RK_GPIO1 3 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + uart1 { + uart1_xfer: uart1-xfer { + rockchip,pins = <RK_GPIO1 4 RK_FUNC_1 &pcfg_pull_up>, + <RK_GPIO1 5 RK_FUNC_1 &pcfg_pull_none>; + }; + + uart1_cts: uart1-cts { + rockchip,pins = <RK_GPIO1 6 RK_FUNC_1 &pcfg_pull_none>; + }; + + uart1_rts: uart1-rts { + rockchip,pins = <RK_GPIO1 7 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + uart2 { + uart2_xfer: uart2-xfer { + rockchip,pins = <RK_GPIO1 8 RK_FUNC_1 &pcfg_pull_up>, + <RK_GPIO1 9 RK_FUNC_1 &pcfg_pull_none>; + }; + /* no rts / cts for uart2 */ + }; + + uart3 { + uart3_xfer: uart3-xfer { + rockchip,pins = <RK_GPIO1 10 RK_FUNC_1 &pcfg_pull_up>, + <RK_GPIO1 11 RK_FUNC_1 &pcfg_pull_none>; + }; + + uart3_cts: uart3-cts { + rockchip,pins = <RK_GPIO1 12 RK_FUNC_1 &pcfg_pull_none>; + }; + + uart3_rts: uart3-rts { + rockchip,pins = <RK_GPIO1 13 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + sd0 { + sd0_clk: sd0-clk { + rockchip,pins = <RK_GPIO3 2 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd0_cmd: sd0-cmd { + rockchip,pins = <RK_GPIO3 3 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd0_cd: sd0-cd { + rockchip,pins = <RK_GPIO3 8 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd0_wp: sd0-wp { + rockchip,pins = <RK_GPIO3 9 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd0_pwr: sd0-pwr { + rockchip,pins = <RK_GPIO3 1 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd0_bus1: sd0-bus-width1 { + rockchip,pins = <RK_GPIO3 4 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd0_bus4: sd0-bus-width4 { + rockchip,pins = <RK_GPIO3 4 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO3 5 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO3 6 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO3 7 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + sd1 { + sd1_clk: sd1-clk { + rockchip,pins = <RK_GPIO3 21 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd1_cmd: sd1-cmd { + rockchip,pins = <RK_GPIO3 16 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd1_cd: sd1-cd { + rockchip,pins = <RK_GPIO3 22 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd1_wp: sd1-wp { + rockchip,pins = <RK_GPIO3 23 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd1_bus1: sd1-bus-width1 { + rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_none>; + }; + + sd1_bus4: sd1-bus-width4 { + rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO3 18 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO3 19 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + i2s0 { + i2s0_bus: i2s0-bus { + rockchip,pins = <RK_GPIO1 16 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 17 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 18 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 19 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 20 RK_FUNC_1 &pcfg_pull_none>, + <RK_GPIO1 21 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + + spdif { + spdif_tx: spdif-tx { + rockchip,pins = <RK_GPIO1 14 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + }; +}; + +&emac { + compatible = "rockchip,rk3188-emac"; +}; + +&global_timer { + interrupts = <GIC_PPI 11 0xf04>; +}; + +&grf { + compatible = "rockchip,rk3188-grf", "syscon"; +}; + +&local_timer { + interrupts = <GIC_PPI 13 0xf04>; +}; + +&i2c0 { + compatible = "rockchip,rk3188-i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_xfer>; +}; + +&i2c1 { + compatible = "rockchip,rk3188-i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_xfer>; +}; + +&i2c2 { + compatible = "rockchip,rk3188-i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_xfer>; +}; + +&i2c3 { + compatible = "rockchip,rk3188-i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_xfer>; +}; + +&i2c4 { + compatible = "rockchip,rk3188-i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_xfer>; +}; + +&pmu { + compatible = "rockchip,rk3188-pmu", "syscon"; +}; + +&pwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_out>; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm1_out>; +}; + +&pwm2 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm2_out>; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm3_out>; +}; + +&spi0 { + compatible = "rockchip,rk3188-spi", "rockchip,rk3066-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_clk &spi0_tx &spi0_rx &spi0_cs0>; +}; + +&spi1 { + compatible = "rockchip,rk3188-spi", "rockchip,rk3066-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_clk &spi1_tx &spi1_rx &spi1_cs0>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer>; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_xfer>; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_xfer>; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_xfer>; +}; + +&wdt { + compatible = "rockchip,rk3188-wdt", "snps,dw-wdt"; +}; diff --git a/arch/arm/dts/rk3xxx.dtsi b/arch/arm/dts/rk3xxx.dtsi new file mode 100644 index 0000000..15a62d9 --- /dev/null +++ b/arch/arm/dts/rk3xxx.dtsi @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2013 MundoReader S.L. + * Author: Heiko Stuebner heiko@sntech.de + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include "skeleton.dtsi" + +/ { + interrupt-parent = <&gic>; + + aliases { + ethernet0 = &emac; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + mshc0 = &emmc; + mshc1 = &mmc0; + mshc2 = &mmc1; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + spi0 = &spi0; + spi1 = &spi1; + }; + + amba { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dmac1_s: dma-controller@20018000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x20018000 0x4000>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; + clocks = <&cru ACLK_DMA1>; + clock-names = "apb_pclk"; + }; + + dmac1_ns: dma-controller@2001c000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x2001c000 0x4000>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; + clocks = <&cru ACLK_DMA1>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + dmac2: dma-controller@20078000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x20078000 0x4000>; + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; + clocks = <&cru ACLK_DMA2>; + clock-names = "apb_pclk"; + }; + }; + + xin24m: oscillator { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + #clock-cells = <0>; + clock-output-names = "xin24m"; + }; + + L2: l2-cache-controller@10138000 { + compatible = "arm,pl310-cache"; + reg = <0x10138000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + scu@1013c000 { + compatible = "arm,cortex-a9-scu"; + reg = <0x1013c000 0x100>; + }; + + global_timer: global-timer@1013c200 { + compatible = "arm,cortex-a9-global-timer"; + reg = <0x1013c200 0x20>; + interrupts = <GIC_PPI 11 0x304>; + clocks = <&cru CORE_PERI>; + }; + + local_timer: local-timer@1013c600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0x1013c600 0x20>; + interrupts = <GIC_PPI 13 0x304>; + clocks = <&cru CORE_PERI>; + }; + + gic: interrupt-controller@1013d000 { + compatible = "arm,cortex-a9-gic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x1013d000 0x1000>, + <0x1013c100 0x0100>; + }; + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <1>; + clock-names = "baudclk", "apb_pclk"; + clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; + status = "disabled"; + }; + + uart1: serial@10126000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10126000 0x400>; + interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <1>; + clock-names = "baudclk", "apb_pclk"; + clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; + status = "disabled"; + }; + + usb_otg: usb@10180000 { + compatible = "rockchip,rk3066-usb", "snps,dwc2"; + reg = <0x10180000 0x40000>; + interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru HCLK_OTG0>; + clock-names = "otg"; + dr_mode = "otg"; + g-np-tx-fifo-size = <16>; + g-rx-fifo-size = <275>; + g-tx-fifo-size = <256 128 128 64 64 32>; + g-use-dma; + phys = <&usbphy0>; + phy-names = "usb2-phy"; + status = "disabled"; + }; + + usb_host: usb@101c0000 { + compatible = "snps,dwc2"; + reg = <0x101c0000 0x40000>; + interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru HCLK_OTG1>; + clock-names = "otg"; + dr_mode = "host"; + phys = <&usbphy1>; + phy-names = "usb2-phy"; + status = "disabled"; + }; + + emac: ethernet@10204000 { + compatible = "snps,arc-emac"; + reg = <0x10204000 0x3c>; + interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>; + clock-names = "hclk", "macref"; + max-speed = <100>; + phy-mode = "rmii"; + + status = "disabled"; + }; + + mmc0: dwmmc@10214000 { + compatible = "rockchip,rk2928-dw-mshc"; + reg = <0x10214000 0x1000>; + interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; + clock-names = "biu", "ciu"; + fifo-depth = <256>; + status = "disabled"; + }; + + mmc1: dwmmc@10218000 { + compatible = "rockchip,rk2928-dw-mshc"; + reg = <0x10218000 0x1000>; + interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>; + clock-names = "biu", "ciu"; + fifo-depth = <256>; + status = "disabled"; + }; + + emmc: dwmmc@1021c000 { + compatible = "rockchip,rk2928-dw-mshc"; + reg = <0x1021c000 0x1000>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>; + clock-names = "biu", "ciu"; + fifo-depth = <256>; + status = "disabled"; + }; + + pmu: pmu@20004000 { + compatible = "rockchip,rk3066-pmu", "syscon"; + reg = <0x20004000 0x100>; + }; + + grf: grf@20008000 { + compatible = "syscon"; + reg = <0x20008000 0x200>; + }; + + i2c0: i2c@2002d000 { + compatible = "rockchip,rk3066-i2c"; + reg = <0x2002d000 0x1000>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clock-names = "i2c"; + clocks = <&cru PCLK_I2C0>; + + status = "disabled"; + }; + + i2c1: i2c@2002f000 { + compatible = "rockchip,rk3066-i2c"; + reg = <0x2002f000 0x1000>; + interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clocks = <&cru PCLK_I2C1>; + clock-names = "i2c"; + + status = "disabled"; + }; + + pwm0: pwm@20030000 { + compatible = "rockchip,rk2928-pwm"; + reg = <0x20030000 0x10>; + #pwm-cells = <2>; + clocks = <&cru PCLK_PWM01>; + status = "disabled"; + }; + + pwm1: pwm@20030010 { + compatible = "rockchip,rk2928-pwm"; + reg = <0x20030010 0x10>; + #pwm-cells = <2>; + clocks = <&cru PCLK_PWM01>; + status = "disabled"; + }; + + wdt: watchdog@2004c000 { + compatible = "snps,dw-wdt"; + reg = <0x2004c000 0x100>; + clocks = <&cru PCLK_WDT>; + interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + pwm2: pwm@20050020 { + compatible = "rockchip,rk2928-pwm"; + reg = <0x20050020 0x10>; + #pwm-cells = <2>; + clocks = <&cru PCLK_PWM23>; + status = "disabled"; + }; + + pwm3: pwm@20050030 { + compatible = "rockchip,rk2928-pwm"; + reg = <0x20050030 0x10>; + #pwm-cells = <2>; + clocks = <&cru PCLK_PWM23>; + status = "disabled"; + }; + + i2c2: i2c@20056000 { + compatible = "rockchip,rk3066-i2c"; + reg = <0x20056000 0x1000>; + interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clocks = <&cru PCLK_I2C2>; + clock-names = "i2c"; + + status = "disabled"; + }; + + i2c3: i2c@2005a000 { + compatible = "rockchip,rk3066-i2c"; + reg = <0x2005a000 0x1000>; + interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clocks = <&cru PCLK_I2C3>; + clock-names = "i2c"; + + status = "disabled"; + }; + + i2c4: i2c@2005e000 { + compatible = "rockchip,rk3066-i2c"; + reg = <0x2005e000 0x1000>; + interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clocks = <&cru PCLK_I2C4>; + clock-names = "i2c"; + + status = "disabled"; + }; + + uart2: serial@20064000 { + compatible = "snps,dw-apb-uart"; + reg = <0x20064000 0x400>; + interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <1>; + clock-frequency = <24000000>; + clock-names = "baudclk", "apb_pclk"; + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + status = "disabled"; + }; + + uart3: serial@20068000 { + compatible = "snps,dw-apb-uart"; + reg = <0x20068000 0x400>; + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <1>; + clock-names = "baudclk", "apb_pclk"; + clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>; + status = "disabled"; + }; + + saradc: saradc@2006c000 { + compatible = "rockchip,saradc"; + reg = <0x2006c000 0x100>; + interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; + #io-channel-cells = <1>; + clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>; + clock-names = "saradc", "apb_pclk"; + status = "disabled"; + }; + + spi0: spi@20070000 { + compatible = "rockchip,rk3066-spi"; + clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>; + clock-names = "spiclk", "apb_pclk"; + interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x20070000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + dmas = <&dmac2 10>, <&dmac2 11>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + spi1: spi@20074000 { + compatible = "rockchip,rk3066-spi"; + clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>; + clock-names = "spiclk", "apb_pclk"; + interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x20074000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + dmas = <&dmac2 12>, <&dmac2 13>; + dma-names = "tx", "rx"; + status = "disabled"; + }; +}; diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index 362dc28..c47e16c 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -11,6 +11,16 @@ config ROCKCHIP_RK3036 select SUPPORT_SPL select SPL
+config ROCKCHIP_RK3188 + bool "Support Rockchip RK3188" + select CPU_V7 + help + The Rockchip RK3188 is a ARM-based SoC with a quad-core Cortex-A9 + including NEON and GPU, 512KB L2 cache, Mali-400 graphics, two + video interfaces, several memory options and video codec support. + Peripherals include Fast Ethernet, USB2 host and OTG, SDIO, I2S, + UART, SPI, I2C and PWMs. + config ROCKCHIP_RK3288 bool "Support Rockchip RK3288" select CPU_V7 @@ -43,6 +53,7 @@ config ROCKCHIP_RK3399 select ARM64
source "arch/arm/mach-rockchip/rk3036/Kconfig" +source "arch/arm/mach-rockchip/rk3188/Kconfig" source "arch/arm/mach-rockchip/rk3288/Kconfig" source "arch/arm/mach-rockchip/rk3399/Kconfig" endif diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index 722b582..cabc91b 100644 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -15,4 +15,5 @@ ifndef CONFIG_ARM64 obj-y += rk_timer.o endif obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/ +obj-$(CONFIG_ROCKCHIP_RK3188) += rk3188/ obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288/ diff --git a/arch/arm/mach-rockchip/rk3188/Kconfig b/arch/arm/mach-rockchip/rk3188/Kconfig new file mode 100644 index 0000000..7ec9364 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3188/Kconfig @@ -0,0 +1,9 @@ +if ROCKCHIP_RK3188 + +config SYS_SOC + default "rockchip" + +config SYS_MALLOC_F_LEN + default 0x0800 + +endif diff --git a/arch/arm/mach-rockchip/rk3188/Makefile b/arch/arm/mach-rockchip/rk3188/Makefile new file mode 100644 index 0000000..2ffbd15 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3188/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (c) 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += clk_rk3188.o +obj-y += reset_rk3188.o +obj-y += syscon_rk3188.o diff --git a/arch/arm/mach-rockchip/rk3188/clk_rk3188.c b/arch/arm/mach-rockchip/rk3188/clk_rk3188.c new file mode 100644 index 0000000..902524f --- /dev/null +++ b/arch/arm/mach-rockchip/rk3188/clk_rk3188.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <syscon.h> +#include <asm/arch/clock.h> + +int rockchip_get_clk(struct udevice **devp) +{ + return uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(rockchip_rk3188_cru), devp); +} diff --git a/arch/arm/mach-rockchip/rk3188/reset_rk3188.c b/arch/arm/mach-rockchip/rk3188/reset_rk3188.c new file mode 100644 index 0000000..65a1465 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3188/reset_rk3188.c @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2015 Google, Inc + * + * 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_rk3188.h> +#include <asm/arch/hardware.h> +#include <linux/err.h> + +int rk3188_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct rk3188_cru *cru = rockchip_get_cru(); + + if (IS_ERR(cru)) + return PTR_ERR(cru); + switch (type) { + case SYSRESET_WARM: + writel(RK_CLRBITS(0xffff), &cru->cru_mode_con); + writel(0xeca8, &cru->cru_glb_srst_snd_value); + break; + case SYSRESET_COLD: + writel(RK_CLRBITS(0xffff), &cru->cru_mode_con); + writel(0xfdb9, &cru->cru_glb_srst_fst_value); + break; + default: + return -EPROTONOSUPPORT; + } + + return -EINPROGRESS; +} + +static struct sysreset_ops rk3188_sysreset = { + .request = rk3188_sysreset_request, +}; + +U_BOOT_DRIVER(sysreset_rk3188) = { + .name = "rk3188_sysreset", + .id = UCLASS_SYSRESET, + .ops = &rk3188_sysreset, +}; diff --git a/arch/arm/mach-rockchip/rk3188/syscon_rk3188.c b/arch/arm/mach-rockchip/rk3188/syscon_rk3188.c new file mode 100644 index 0000000..05c36bd --- /dev/null +++ b/arch/arm/mach-rockchip/rk3188/syscon_rk3188.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <syscon.h> +#include <asm/arch/clock.h> + +static const struct udevice_id rk3188_syscon_ids[] = { + { .compatible = "rockchip,rk3188-noc", .data = ROCKCHIP_SYSCON_NOC }, + { .compatible = "rockchip,rk3188-grf", .data = ROCKCHIP_SYSCON_GRF }, + { .compatible = "rockchip,rk3188-pmu", .data = ROCKCHIP_SYSCON_PMU }, + { } +}; + +U_BOOT_DRIVER(syscon_rk3188) = { + .name = "rk3188_syscon", + .id = UCLASS_SYSCON, + .of_match = rk3188_syscon_ids, +}; diff --git a/include/configs/rk3188_common.h b/include/configs/rk3188_common.h new file mode 100644 index 0000000..7bd5b63 --- /dev/null +++ b/include/configs/rk3188_common.h @@ -0,0 +1,95 @@ +/* + * (C) Copyright 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_RK3188_COMMON_H +#define __CONFIG_RK3188_COMMON_H + +#define CONFIG_SYS_CACHELINE_SIZE 32 + +#include <asm/arch/hardware.h> + +#define CONFIG_SYS_NO_FLASH +#define CONFIG_NR_DRAM_BANKS 1 +#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_SIZE 0x2000 +#define CONFIG_SYS_MAXARGS 16 +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_MALLOC_LEN (32 << 20) +#define CONFIG_SYS_CBSIZE 1024 +#define CONFIG_SKIP_LOWLEVEL_INIT +#define CONFIG_SYS_THUMB_BUILD +#define CONFIG_DISPLAY_BOARDINFO + +#define CONFIG_SYS_TIMER_RATE (24 * 1000 * 1000) +#define CONFIG_SYS_TIMER_BASE 0x2000e000 /* TIMER3 */ +#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMER_BASE + 8) +#define CONFIG_SYS_TIMER_COUNTS_DOWN + +#define CONFIG_SYS_NS16550_MEM32 + +#define CONFIG_SYS_TEXT_BASE 0x60000000 +#define CONFIG_SYS_INIT_SP_ADDR 0x60100000 +#define CONFIG_SYS_LOAD_ADDR 0x60800800 + +#define CONFIG_ROCKCHIP_MAX_INIT_SIZE 0x8000 - 0x800 +#define CONFIG_ROCKCHIP_CHIP_TAG "RK31" + +#define CONFIG_ROCKCHIP_COMMON + +/* #define CONFIG_SILENT_CONSOLE +#ifndef CONFIG_SPL_BUILD +# define CONFIG_SYS_CONSOLE_IS_IN_ENV +# define CONFIG_CONSOLE_MUX +#endif */ + +/* MMC/SD IP block */ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_SDHCI +#define CONFIG_DWMMC +#define CONFIG_BOUNCE_BUFFER + +#define CONFIG_DOS_PARTITION +#define CONFIG_FAT_WRITE +#define CONFIG_PARTITION_UUIDS +#define CONFIG_CMD_PART + +#define CONFIG_SYS_SDRAM_BASE 0x60000000 +#define CONFIG_NR_DRAM_BANKS 1 +#define SDRAM_BANK_SIZE (2UL << 30) + +#define CONFIG_SPI_FLASH +#define CONFIG_SPI +#define CONFIG_SF_DEFAULT_SPEED 20000000 + +#ifndef CONFIG_SPL_BUILD +#include <config_distro_defaults.h> + +#define ENV_MEM_LAYOUT_SETTINGS \ + "scriptaddr=0x60000000\0" \ + "pxefile_addr_r=0x60100000\0" \ + "fdt_addr_r=0x61f00000\0" \ + "kernel_addr_r=0x62000000\0" \ + "ramdisk_addr_r=0x64000000\0" + +/* First try to boot from SD (index 0), then eMMC (index 1 */ +#define BOOT_TARGET_DEVICES(func) \ + func(MMC, mmc, 0) \ + func(MMC, mmc, 1) + +#include <config_distro_bootcmd.h> + +/* Linux fails to load the fdt if it's loaded above 512M on rk3188 boards, so + * limit the fdt reallocation to that */ +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdt_high=0x7fffffff\0" \ + "initrd_high=0x7fffffff\0" \ + ENV_MEM_LAYOUT_SETTINGS \ + ROCKCHIP_DEVICE_SETTINGS \ + BOOTENV +#endif + +#endif diff --git a/tools/rkcommon.c b/tools/rkcommon.c index 0a072aa..0f38b15 100644 --- a/tools/rkcommon.c +++ b/tools/rkcommon.c @@ -55,6 +55,7 @@ struct spl_info {
static struct spl_info spl_infos[] = { { "rk3036", "RK30", 0x1000 }, + { "rk3188", "RK31", 0x8000 - 0x800 }, { "rk3288", "RK32", 0x8000 }, { "rk3399", "RK33", 0x20000 }, };

Am Freitag, 22. Juli 2016, 23:51:11 schrieb Heiko Stuebner:
Add the core architecture code for the rk3188. It doesn't support the SPL yet, as because of some unknown error it doesn't start yet.
Signed-off-by: Heiko Stuebner heiko@sntech.de
arch/arm/dts/rk3188.dtsi | 631 ++++++++++++++++++++++++++ arch/arm/dts/rk3xxx.dtsi | 431 ++++++++++++++++++ arch/arm/mach-rockchip/Kconfig | 11
arch/arm/mach-rockchip/Makefile | 1 + arch/arm/mach-rockchip/rk3188/Kconfig | 9 + arch/arm/mach-rockchip/rk3188/Makefile | 9 + arch/arm/mach-rockchip/rk3188/clk_rk3188.c | 17 + arch/arm/mach-rockchip/rk3188/reset_rk3188.c | 47 ++ arch/arm/mach-rockchip/rk3188/syscon_rk3188.c | 24 + include/configs/rk3188_common.h | 95 ++++ tools/rkcommon.c | 1 + 11 files changed, 1276 insertions(+) create mode 100644 arch/arm/dts/rk3188.dtsi create mode 100644 arch/arm/dts/rk3xxx.dtsi create mode 100644 arch/arm/mach-rockchip/rk3188/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3188/Makefile create mode 100644 arch/arm/mach-rockchip/rk3188/clk_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/reset_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/syscon_rk3188.c create mode 100644 include/configs/rk3188_common.h
diff --git a/arch/arm/dts/rk3188.dtsi b/arch/arm/dts/rk3188.dtsi new file mode 100644 index 0000000..ef1b962 --- /dev/null +++ b/arch/arm/dts/rk3188.dtsi @@ -0,0 +1,631 @@ +/*
- Copyright (c) 2013 MundoReader S.L.
- Author: Heiko Stuebner heiko@sntech.de
- This file is dual-licensed: you can use it either under the terms
- of the GPL or the X11 license, at your option. Note that this dual
- licensing only applies to this file, and not this project as a
- whole.
- a) This file is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- Or, alternatively,
- b) Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
- */
it seems I forgot more license-header conversions in these new two patches. Sorry about that.
Heiko

On 22 July 2016 at 15:54, Heiko Stübner heiko@sntech.de wrote:
Am Freitag, 22. Juli 2016, 23:51:11 schrieb Heiko Stuebner:
Add the core architecture code for the rk3188. It doesn't support the SPL yet, as because of some unknown error it doesn't start yet.
Signed-off-by: Heiko Stuebner heiko@sntech.de
arch/arm/dts/rk3188.dtsi | 631 ++++++++++++++++++++++++++ arch/arm/dts/rk3xxx.dtsi | 431 ++++++++++++++++++ arch/arm/mach-rockchip/Kconfig | 11
arch/arm/mach-rockchip/Makefile | 1 + arch/arm/mach-rockchip/rk3188/Kconfig | 9 + arch/arm/mach-rockchip/rk3188/Makefile | 9 + arch/arm/mach-rockchip/rk3188/clk_rk3188.c | 17 + arch/arm/mach-rockchip/rk3188/reset_rk3188.c | 47 ++ arch/arm/mach-rockchip/rk3188/syscon_rk3188.c | 24 + include/configs/rk3188_common.h | 95 ++++ tools/rkcommon.c | 1 + 11 files changed, 1276 insertions(+) create mode 100644 arch/arm/dts/rk3188.dtsi create mode 100644 arch/arm/dts/rk3xxx.dtsi create mode 100644 arch/arm/mach-rockchip/rk3188/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3188/Makefile create mode 100644 arch/arm/mach-rockchip/rk3188/clk_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/reset_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/syscon_rk3188.c create mode 100644 include/configs/rk3188_common.h
diff --git a/arch/arm/dts/rk3188.dtsi b/arch/arm/dts/rk3188.dtsi new file mode 100644 index 0000000..ef1b962 --- /dev/null +++ b/arch/arm/dts/rk3188.dtsi @@ -0,0 +1,631 @@ +/*
- Copyright (c) 2013 MundoReader S.L.
- Author: Heiko Stuebner heiko@sntech.de
- This file is dual-licensed: you can use it either under the terms
- of the GPL or the X11 license, at your option. Note that this dual
- licensing only applies to this file, and not this project as a
- whole.
- a) This file is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- Or, alternatively,
- b) Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
- */
it seems I forgot more license-header conversions in these new two patches. Sorry about that.
Acked-by: Simon Glass sjg@chromium.org
Regards, Simon

The Rock is a RK3188 based single board computer by Radxa. Currently it still relies on the proprietary DDR init and cannot use the generic SPL, but at least is able to boot a linux kernel and system up to a regular login prompt.
Signed-off-by: Heiko Stuebner heiko@sntech.de --- arch/arm/dts/Makefile | 1 + arch/arm/dts/rk3188-radxarock.dts | 406 ++++++++++++++++++++++++++++++++++ arch/arm/mach-rockchip/rk3188/Kconfig | 11 + board/radxa/rock/Kconfig | 15 ++ board/radxa/rock/MAINTAINERS | 6 + board/radxa/rock/Makefile | 7 + board/radxa/rock/rock.c | 32 +++ configs/rock_defconfig | 68 ++++++ include/configs/rock.h | 20 ++ 9 files changed, 566 insertions(+) create mode 100644 arch/arm/dts/rk3188-radxarock.dts create mode 100644 board/radxa/rock/Kconfig create mode 100644 board/radxa/rock/MAINTAINERS create mode 100644 board/radxa/rock/Makefile create mode 100644 board/radxa/rock/rock.c create mode 100644 configs/rock_defconfig create mode 100644 include/configs/rock.h
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 3f5b2bf..cf286a7 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -28,6 +28,7 @@ dtb-$(CONFIG_EXYNOS5) += exynos5250-arndale.dtb \ exynos5422-odroidxu3.dtb dtb-$(CONFIG_EXYNOS7420) += exynos7420-espresso7420.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += \ + rk3188-radxarock.dtb \ rk3288-firefly.dtb \ rk3288-jerry.dtb \ rk3288-rock2-square.dtb \ diff --git a/arch/arm/dts/rk3188-radxarock.dts b/arch/arm/dts/rk3188-radxarock.dts new file mode 100644 index 0000000..3de9191 --- /dev/null +++ b/arch/arm/dts/rk3188-radxarock.dts @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2013 Heiko Stuebner heiko@sntech.de + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include <dt-bindings/input/input.h> +#include "rk3188.dtsi" + +/ { + model = "Radxa Rock"; + compatible = "radxa,rock", "rockchip,rk3188"; + + chosen { +/* stdout-path = &uart2; */ + stdout-path = "serial2:115200n8"; + }; + + config { + u-boot,dm-pre-reloc; + u-boot,boot-led = "rock:red:power"; + }; + + memory { + device_type = "memory"; + reg = <0x60000000 0x80000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + + power { + gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; + linux,code = <KEY_POWER>; + label = "GPIO Key Power"; + linux,input-type = <1>; + wakeup-source; + debounce-interval = <100>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + green { + label = "rock:green:user1"; + gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + blue { + label = "rock:blue:user2"; + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + sleep { + label = "rock:red:power"; + gpios = <&gpio0 15 0>; + default-state = "off"; + }; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "SPDIF"; + + simple-audio-card,dai-link@1 { /* S/PDIF - S/PDIF */ + cpu { sound-dai = <&spdif>; }; + codec { sound-dai = <&spdif_out>; }; + }; + }; + + spdif_out: spdif-out { + compatible = "linux,spdif-dit"; + #sound-dai-cells = <0>; + }; + + ir_recv: gpio-ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio0 10 1>; + pinctrl-names = "default"; + pinctrl-0 = <&ir_recv_pin>; + }; + + vcc_otg: usb-otg-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 31 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&otg_vbus_drv>; + regulator-name = "otg-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_sd0: sdmmc-regulator { + compatible = "regulator-fixed"; + regulator-name = "sdmmc-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio3 1 GPIO_ACTIVE_LOW>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; + + vcc_host: usb-host-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&host_vbus_drv>; + regulator-name = "host-pwr"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys: vsys-regulator { + compatible = "regulator-fixed"; + regulator-name = "vsys"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; +}; + +&emac { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>; + + phy = <&phy0>; + phy-supply = <&vcc_rmii>; + + phy0: ethernet-phy@0 { + reg = <0>; + interrupt-parent = <&gpio3>; + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&cpu0 { + cpu0-supply = <&vdd_arm>; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <400000>; + + rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + interrupt-parent = <&gpio0>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_int>; + #clock-cells = <0>; + clock-output-names = "xin32k"; + }; + + act8846: act8846@5a { + compatible = "active-semi,act8846"; + reg = <0x5a>; + status = "okay"; + system-power-controller; + + pinctrl-names = "default"; + pinctrl-0 = <&act8846_dvs0_ctl>; + + vp1-supply = <&vsys>; + vp2-supply = <&vsys>; + vp3-supply = <&vsys>; + vp4-supply = <&vsys>; + inl1-supply = <&vcc_io>; + inl2-supply = <&vsys>; + inl3-supply = <&vsys>; + + regulators { + vcc_ddr: REG1 { + regulator-name = "VCC_DDR"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vdd_log: REG2 { + regulator-name = "VDD_LOG"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + vdd_arm: REG3 { + regulator-name = "VDD_ARM"; + regulator-min-microvolt = <875000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + vcc_io: REG4 { + regulator-name = "VCC_IO"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_10: REG5 { + regulator-name = "VDD_10"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + vdd_hdmi: REG6 { + regulator-name = "VDD_HDMI"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vcc18: REG7 { + regulator-name = "VCC_18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vcca_33: REG8 { + regulator-name = "VCCA_33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vcc_rmii: REG9 { + regulator-name = "VCC_RMII"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vccio_wl: REG10 { + regulator-name = "VCCIO_WL"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vcc_18: REG11 { + regulator-name = "VCC18_IO"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vcc28: REG12 { + regulator-name = "VCC_28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + }; + }; +}; + +&mmc0 { + num-slots = <1>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>; + vmmc-supply = <&vcc_sd0>; + + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; +}; + +&pwm1 { + status = "okay"; +}; + +&pwm2 { + status = "okay"; +}; + +&pwm3 { + status = "okay"; +}; + +&pinctrl { + pcfg_output_low: pcfg-output-low { + output-low; + }; + + act8846 { + act8846_dvs0_ctl: act8846-dvs0-ctl { + rockchip,pins = <RK_GPIO3 27 RK_FUNC_GPIO &pcfg_output_low>; + }; + }; + + hym8563 { + rtc_int: rtc-int { + rockchip,pins = <RK_GPIO0 0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + lan8720a { + phy_int: phy-int { + rockchip,pins = <RK_GPIO3 26 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + ir-receiver { + ir_recv_pin: ir-recv-pin { + rockchip,pins = <RK_GPIO0 10 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + host_vbus_drv: host-vbus-drv { + rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + otg_vbus_drv: otg-vbus-drv { + rockchip,pins = <2 31 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&spdif { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; + +&usb_host { + status = "okay"; +}; + +&usb_otg { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/arm/mach-rockchip/rk3188/Kconfig b/arch/arm/mach-rockchip/rk3188/Kconfig index 7ec9364..ecf0ec6 100644 --- a/arch/arm/mach-rockchip/rk3188/Kconfig +++ b/arch/arm/mach-rockchip/rk3188/Kconfig @@ -1,9 +1,20 @@ if ROCKCHIP_RK3188
+config TARGET_ROCK + bool "Radxa Rock" + help + Rock is a RK3188-based development board with 2 USB and 1 otg + ports, HDMI, TV-out, micro-SD card, audio, WiFi and 100MBit + Ethernet, It also includes on-board nand and 1GB of SDRAM. + Expansion connectors provide access to display pins, I2C, SPI, + UART and GPIOs. + config SYS_SOC default "rockchip"
config SYS_MALLOC_F_LEN default 0x0800
+source "board/radxa/rock/Kconfig" + endif diff --git a/board/radxa/rock/Kconfig b/board/radxa/rock/Kconfig new file mode 100644 index 0000000..855b9b6 --- /dev/null +++ b/board/radxa/rock/Kconfig @@ -0,0 +1,15 @@ +if TARGET_ROCK + +config SYS_BOARD + default "rock" + +config SYS_VENDOR + default "radxa" + +config SYS_CONFIG_NAME + default "rock" + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + +endif diff --git a/board/radxa/rock/MAINTAINERS b/board/radxa/rock/MAINTAINERS new file mode 100644 index 0000000..d44e7b8 --- /dev/null +++ b/board/radxa/rock/MAINTAINERS @@ -0,0 +1,6 @@ +RADXA_ROCK +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/radxa/rock +F: include/configs/rock.h +F: configs/rock_defconfig diff --git a/board/radxa/rock/Makefile b/board/radxa/rock/Makefile new file mode 100644 index 0000000..fe94b60 --- /dev/null +++ b/board/radxa/rock/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2015 Heiko Stuebner +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += rock.o diff --git a/board/radxa/rock/rock.c b/board/radxa/rock/rock.c new file mode 100644 index 0000000..33db137 --- /dev/null +++ b/board/radxa/rock/rock.c @@ -0,0 +1,32 @@ +/* + * (C) Copyright 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <asm/arch/clock.h> +#include <asm/arch/timer.h> + +DECLARE_GLOBAL_DATA_PTR; + +int board_init(void) +{ + struct udevice *dev; + int ret; + + rockchip_timer_init(); + ret = rockchip_get_clk(&dev); + if (ret < 0) + return ret; + + return 0; +} + +int dram_init(void) +{ + gd->ram_size = 0x40000000; + + return 0; +} diff --git a/configs/rock_defconfig b/configs/rock_defconfig new file mode 100644 index 0000000..749d993 --- /dev/null +++ b/configs/rock_defconfig @@ -0,0 +1,68 @@ +CONFIG_ARM=y +CONFIG_ARCH_ROCKCHIP=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_ROCKCHIP_RK3188=y +CONFIG_TARGET_ROCK=y +CONFIG_SPL_STACK_R_ADDR=0x80000 +CONFIG_DEFAULT_DEVICE_TREE="rk3188-radxarock" +CONFIG_SPL_STACK_R=y +CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 +CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +CONFIG_CMD_I2C=y +CONFIG_CMD_GPIO=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents" +CONFIG_REGMAP=y +CONFIG_SPL_REGMAP=y +CONFIG_SYSCON=y +CONFIG_SPL_SYSCON=y +# CONFIG_SPL_SIMPLE_BUS is not set +CONFIG_CLK=y +CONFIG_SPL_CLK=y +CONFIG_ROCKCHIP_GPIO=y +CONFIG_SYS_I2C_ROCKCHIP=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_SYSRESET=y +CONFIG_DM_MMC=y +CONFIG_ROCKCHIP_DWMMC=y +CONFIG_PINCTRL=y +CONFIG_SPL_PINCTRL=y +# CONFIG_SPL_PINCTRL_FULL is not set +CONFIG_ROCKCHIP_RK3188_PINCTRL=y +CONFIG_DM_PMIC=y +# CONFIG_SPL_PMIC_CHILDREN is not set +CONFIG_PMIC_ACT8846=y +CONFIG_DM_REGULATOR=y +CONFIG_REGULATOR_ACT8846=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_PWM=y +CONFIG_PWM_ROCKCHIP=y +CONFIG_RAM=y +CONFIG_SPL_RAM=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_BASE=0x20064000 +CONFIG_DEBUG_UART_CLOCK=24000000 +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_SYS_NS16550=y +CONFIG_USE_PRIVATE_LIBGCC=y +CONFIG_USE_TINY_PRINTF=y +CONFIG_CMD_DHRYSTONE=y +CONFIG_ERRNO_STR=y diff --git a/include/configs/rock.h b/include/configs/rock.h new file mode 100644 index 0000000..1407938 --- /dev/null +++ b/include/configs/rock.h @@ -0,0 +1,20 @@ +/* + * (C) Copyright 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define ROCKCHIP_DEVICE_SETTINGS \ + "stdin=serial\0" \ + "stdout=serial\0" \ + "stderr=serial\0" + +#include <configs/rk3188_common.h> + +#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_SPL_MMC_SUPPORT + +#endif

On 22 July 2016 at 15:51, Heiko Stuebner heiko@sntech.de wrote:
The Rock is a RK3188 based single board computer by Radxa. Currently it still relies on the proprietary DDR init and cannot use the generic SPL, but at least is able to boot a linux kernel and system up to a regular login prompt.
Signed-off-by: Heiko Stuebner heiko@sntech.de
arch/arm/dts/Makefile | 1 + arch/arm/dts/rk3188-radxarock.dts | 406 ++++++++++++++++++++++++++++++++++ arch/arm/mach-rockchip/rk3188/Kconfig | 11 + board/radxa/rock/Kconfig | 15 ++ board/radxa/rock/MAINTAINERS | 6 + board/radxa/rock/Makefile | 7 + board/radxa/rock/rock.c | 32 +++ configs/rock_defconfig | 68 ++++++ include/configs/rock.h | 20 ++ 9 files changed, 566 insertions(+) create mode 100644 arch/arm/dts/rk3188-radxarock.dts create mode 100644 board/radxa/rock/Kconfig create mode 100644 board/radxa/rock/MAINTAINERS create mode 100644 board/radxa/rock/Makefile create mode 100644 board/radxa/rock/rock.c create mode 100644 configs/rock_defconfig create mode 100644 include/configs/rock.h
Acked-by: Simon Glass sjg@chromium.org
When you come back to this can you please add info to the README on how to run on this board?
- SImon

Hi Heiko,
On 22 July 2016 at 15:51, Heiko Stuebner heiko@sntech.de wrote:
Second version. Simon already applied the cleanup patches from my first version. I've tried to address Simons comments and hopefully haven't overlooked any.
SPL is still missing, so following Simons comment from earlier it cannot go in yet, but maybe the first two cleanups can.
Re the first patch, if you can resend it as a 'move' patch then I can apply it. Please base on u-boot-rockchip/master.
For rk3188, yes I would prefer to wait until we have the proper SPL. It sounds like you are close? I don't have an rk3188 board - I could get a TV box with that chip but I'm not sure if it would work for development.
changes in v2:
- move clock drivers to subdirectory
- use already available log2 function in clock drivers
- SPDX header in clock bindings
- showcase rk3188 arch code and rock board
Heiko Stuebner (10): rockchip: move clock drivers into a subdirectory rockchip: remove log2 reimplementation from clock drivers rockchip: rk3188: Add header files for PMU and GRF rockchip: rk3188: Add pinctrl driver rockchip: rk3188: Bring in rk3066/rk3188 clock bindings rockchip: rk3188: Add clock driver rockchip: rk3188: add core support rockchip: rk3188: Radxa Rock board add unfinished SPL support hacks to make my rock netboot a fit image
arch/arm/dts/Makefile | 1 + arch/arm/dts/rk3188-radxarock.dts | 406 +++++++++++ arch/arm/dts/rk3188.dtsi | 631 ++++++++++++++++++ arch/arm/dts/rk3xxx.dtsi | 431 ++++++++++++ arch/arm/include/asm/arch-rockchip/cru_rk3188.h | 183 +++++ arch/arm/include/asm/arch-rockchip/grf_rk3188.h | 589 ++++++++++++++++ arch/arm/include/asm/arch-rockchip/pmu_rk3188.h | 36 + arch/arm/mach-rockchip/Kconfig | 11 + arch/arm/mach-rockchip/Makefile | 2 + arch/arm/mach-rockchip/rk3188-board-spl.c | 190 ++++++ arch/arm/mach-rockchip/rk3188/Kconfig | 20 + arch/arm/mach-rockchip/rk3188/Makefile | 10 + arch/arm/mach-rockchip/rk3188/clk_rk3188.c | 17 + arch/arm/mach-rockchip/rk3188/reset_rk3188.c | 47 ++ arch/arm/mach-rockchip/rk3188/sdram_rk3188.c | 839 +++++++++++++++++++++++ arch/arm/mach-rockchip/rk3188/syscon_rk3188.c | 24 + board/radxa/rock/Kconfig | 15 + board/radxa/rock/MAINTAINERS | 6 + board/radxa/rock/Makefile | 7 + board/radxa/rock/rock.c | 32 + configs/rock_defconfig | 80 +++ drivers/clk/Makefile | 3 +- drivers/clk/clk_rk3036.c | 386 ----------- drivers/clk/clk_rk3288.c | 851 ------------------------ drivers/clk/rockchip/Makefile | 9 + drivers/clk/rockchip/clk_rk3036.c | 382 +++++++++++ drivers/clk/rockchip/clk_rk3188.c | 493 ++++++++++++++ drivers/clk/rockchip/clk_rk3288.c | 847 +++++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/rockchip/Makefile | 1 + drivers/pinctrl/rockchip/pinctrl_rk3188.c | 613 +++++++++++++++++ drivers/usb/host/dwc2.c | 4 +- include/configs/rk3188_common.h | 109 +++ include/configs/rock.h | 66 ++ include/dt-bindings/clock/rk3066a-cru.h | 32 + include/dt-bindings/clock/rk3188-cru-common.h | 248 +++++++ include/dt-bindings/clock/rk3188-cru.h | 48 ++ tools/rkcommon.c | 1 + 38 files changed, 6438 insertions(+), 1241 deletions(-) create mode 100644 arch/arm/dts/rk3188-radxarock.dts create mode 100644 arch/arm/dts/rk3188.dtsi create mode 100644 arch/arm/dts/rk3xxx.dtsi create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3188.h create mode 100644 arch/arm/include/asm/arch-rockchip/grf_rk3188.h create mode 100644 arch/arm/include/asm/arch-rockchip/pmu_rk3188.h create mode 100644 arch/arm/mach-rockchip/rk3188-board-spl.c create mode 100644 arch/arm/mach-rockchip/rk3188/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3188/Makefile create mode 100644 arch/arm/mach-rockchip/rk3188/clk_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/reset_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/sdram_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/syscon_rk3188.c create mode 100644 board/radxa/rock/Kconfig create mode 100644 board/radxa/rock/MAINTAINERS create mode 100644 board/radxa/rock/Makefile create mode 100644 board/radxa/rock/rock.c create mode 100644 configs/rock_defconfig delete mode 100644 drivers/clk/clk_rk3036.c delete mode 100644 drivers/clk/clk_rk3288.c create mode 100644 drivers/clk/rockchip/Makefile create mode 100644 drivers/clk/rockchip/clk_rk3036.c create mode 100644 drivers/clk/rockchip/clk_rk3188.c create mode 100644 drivers/clk/rockchip/clk_rk3288.c create mode 100644 drivers/pinctrl/rockchip/pinctrl_rk3188.c create mode 100644 include/configs/rk3188_common.h create mode 100644 include/configs/rock.h create mode 100644 include/dt-bindings/clock/rk3066a-cru.h create mode 100644 include/dt-bindings/clock/rk3188-cru-common.h create mode 100644 include/dt-bindings/clock/rk3188-cru.h
-- 2.8.1
Regards, Simon

Hi Simon,
Am Mittwoch, 27. Juli 2016, 21:42:47 schrieb Simon Glass:
On 22 July 2016 at 15:51, Heiko Stuebner heiko@sntech.de wrote:
Second version. Simon already applied the cleanup patches from my first version. I've tried to address Simons comments and hopefully haven't overlooked any.
SPL is still missing, so following Simons comment from earlier it cannot go in yet, but maybe the first two cleanups can.
Re the first patch, if you can resend it as a 'move' patch then I can apply it. Please base on u-boot-rockchip/master.
ok, I can do that :-)
For rk3188, yes I would prefer to wait until we have the proper SPL. It sounds like you are close? I don't have an rk3188 board - I could get a TV box with that chip but I'm not sure if it would work for development.
I wouldn't call it close, but it's moving along somewhat and we figure out the special requirements step by step. As for yout getting a box, I guess the worst part is finding serial pin testpoints. For booting the rk3188 seems to be the easiest of them all - if you plug in a suitably prepared card, it will always prefer this one over everything else.
Heiko
changes in v2:
- move clock drivers to subdirectory
- use already available log2 function in clock drivers
- SPDX header in clock bindings
- showcase rk3188 arch code and rock board
Heiko Stuebner (10): rockchip: move clock drivers into a subdirectory rockchip: remove log2 reimplementation from clock drivers rockchip: rk3188: Add header files for PMU and GRF rockchip: rk3188: Add pinctrl driver rockchip: rk3188: Bring in rk3066/rk3188 clock bindings rockchip: rk3188: Add clock driver rockchip: rk3188: add core support rockchip: rk3188: Radxa Rock board add unfinished SPL support hacks to make my rock netboot a fit image
arch/arm/dts/Makefile | 1 + arch/arm/dts/rk3188-radxarock.dts | 406 +++++++++++ arch/arm/dts/rk3188.dtsi | 631 ++++++++++++++++++ arch/arm/dts/rk3xxx.dtsi | 431 ++++++++++++ arch/arm/include/asm/arch-rockchip/cru_rk3188.h | 183 +++++ arch/arm/include/asm/arch-rockchip/grf_rk3188.h | 589 ++++++++++++++++ arch/arm/include/asm/arch-rockchip/pmu_rk3188.h | 36 + arch/arm/mach-rockchip/Kconfig | 11 + arch/arm/mach-rockchip/Makefile | 2 + arch/arm/mach-rockchip/rk3188-board-spl.c | 190 ++++++ arch/arm/mach-rockchip/rk3188/Kconfig | 20 + arch/arm/mach-rockchip/rk3188/Makefile | 10 + arch/arm/mach-rockchip/rk3188/clk_rk3188.c | 17 + arch/arm/mach-rockchip/rk3188/reset_rk3188.c | 47 ++ arch/arm/mach-rockchip/rk3188/sdram_rk3188.c | 839 +++++++++++++++++++++++ arch/arm/mach-rockchip/rk3188/syscon_rk3188.c | 24 + board/radxa/rock/Kconfig | 15 + board/radxa/rock/MAINTAINERS | 6 + board/radxa/rock/Makefile | 7 + board/radxa/rock/rock.c | 32 + configs/rock_defconfig | 80 +++ drivers/clk/Makefile | 3 +- drivers/clk/clk_rk3036.c | 386 ----------- drivers/clk/clk_rk3288.c | 851 ------------------------ drivers/clk/rockchip/Makefile | 9 + drivers/clk/rockchip/clk_rk3036.c | 382 +++++++++++ drivers/clk/rockchip/clk_rk3188.c | 493 ++++++++++++++ drivers/clk/rockchip/clk_rk3288.c | 847 +++++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/rockchip/Makefile | 1 + drivers/pinctrl/rockchip/pinctrl_rk3188.c | 613 +++++++++++++++++ drivers/usb/host/dwc2.c | 4 +- include/configs/rk3188_common.h | 109 +++ include/configs/rock.h | 66 ++ include/dt-bindings/clock/rk3066a-cru.h | 32 + include/dt-bindings/clock/rk3188-cru-common.h | 248 +++++++ include/dt-bindings/clock/rk3188-cru.h | 48 ++ tools/rkcommon.c | 1 + 38 files changed, 6438 insertions(+), 1241 deletions(-) create mode 100644 arch/arm/dts/rk3188-radxarock.dts create mode 100644 arch/arm/dts/rk3188.dtsi create mode 100644 arch/arm/dts/rk3xxx.dtsi create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3188.h create mode 100644 arch/arm/include/asm/arch-rockchip/grf_rk3188.h create mode 100644 arch/arm/include/asm/arch-rockchip/pmu_rk3188.h create mode 100644 arch/arm/mach-rockchip/rk3188-board-spl.c create mode 100644 arch/arm/mach-rockchip/rk3188/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3188/Makefile create mode 100644 arch/arm/mach-rockchip/rk3188/clk_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/reset_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/sdram_rk3188.c create mode 100644 arch/arm/mach-rockchip/rk3188/syscon_rk3188.c create mode 100644 board/radxa/rock/Kconfig create mode 100644 board/radxa/rock/MAINTAINERS create mode 100644 board/radxa/rock/Makefile create mode 100644 board/radxa/rock/rock.c create mode 100644 configs/rock_defconfig delete mode 100644 drivers/clk/clk_rk3036.c delete mode 100644 drivers/clk/clk_rk3288.c create mode 100644 drivers/clk/rockchip/Makefile create mode 100644 drivers/clk/rockchip/clk_rk3036.c create mode 100644 drivers/clk/rockchip/clk_rk3188.c create mode 100644 drivers/clk/rockchip/clk_rk3288.c create mode 100644 drivers/pinctrl/rockchip/pinctrl_rk3188.c create mode 100644 include/configs/rk3188_common.h create mode 100644 include/configs/rock.h create mode 100644 include/dt-bindings/clock/rk3066a-cru.h create mode 100644 include/dt-bindings/clock/rk3188-cru-common.h create mode 100644 include/dt-bindings/clock/rk3188-cru.h
-- 2.8.1
Regards, Simon
participants (3)
-
Heiko Stuebner
-
Heiko Stübner
-
Simon Glass