rk3399: add soc basic driver support
Subsystems (5)
cover rk3399: add soc basic driver support
This patchset add basic driver like clock, grf, sysreset for rk3399, and enable clock init in emmc driver.
This patchset has tested on rk3399 evb.
Kever Yang (2):
rk3399: add basic soc driver
mmc: rockchip: add clock init
arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 93 +++ arch/arm/mach-rockchip/rk3399/Makefile | 2 + arch/arm/mach-rockchip/rk3399/reset_rk3399.c | 45 ++ arch/arm/mach-rockchip/rk3399/syscon_rk3399.c | 20 + drivers/clk/Makefile | 1 + drivers/clk/clk_rk3399.c | 825 ++++++++++++++++++++++++ drivers/mmc/rockchip_sdhci.c | 10 +- include/configs/rk3399_common.h | 2 +- 8 files changed, 996 insertions(+), 2 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3399.h create mode 100644 arch/arm/mach-rockchip/rk3399/reset_rk3399.c create mode 100644 arch/arm/mach-rockchip/rk3399/syscon_rk3399.c create mode 100644 drivers/clk/clk_rk3399.c
Signature · 1 line
1.9.1
PATCH 1/2 rk3399: add basic soc driver
This patch add driver for:
- clock driver including set_rate for cpu, mmc, vop, I2C.
- sysreset driver
- grf syscon driver
---
arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 93 +++ arch/arm/mach-rockchip/rk3399/Makefile | 2 + arch/arm/mach-rockchip/rk3399/reset_rk3399.c | 45 ++ arch/arm/mach-rockchip/rk3399/syscon_rk3399.c | 20 + drivers/clk/Makefile | 1 + drivers/clk/clk_rk3399.c | 825 ++++++++++++++++++++++++ 6 files changed, 986 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3399.h create mode 100644 arch/arm/mach-rockchip/rk3399/reset_rk3399.c create mode 100644 arch/arm/mach-rockchip/rk3399/syscon_rk3399.c create mode 100644 drivers/clk/clk_rk3399.c
arch/arm/include/asm/arch-rockchip/cru_rk3399.h new file +93 -0
@@ -0,0 +1,93 @@ +/* +* (C) Copyright 2016 Rockchip Electronics Co., Ltd +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __ASM_ARCH_CRU_RK3399_H_ +#define __ASM_ARCH_CRU_RK3399_H_ + +#include <common.h> + +struct rk3399_pmucru { +u32 ppll_con[6 ]; +u32 reserved[0x1a ]; +u32 pmucru_clksel[6 ]; +u32 pmucru_clkfrac_con[2 ]; +u32 reserved2[0x18 ]; +u32 pmucru_clkgate_con[3 ]; +u32 reserved3; +u32 pmucru_softrst_con[2 ]; +u32 reserved4[2 ]; +u32 pmucru_rstnhold_con[2 ]; +u32 reserved5[2 ]; +u32 pmucru_gatedis_con[2 ]; +}; +check_member (rk3399_pmucru, pmucru_gatedis_con[1 ],0x134 ); + +struct rk3399_cru { +u32 apll_l_con[6 ]; +u32 reserved[2 ]; +u32 apll_b_con[6 ]; +u32 reserved1[2 ]; +u32 dpll_con[6 ]; +u32 reserved2[2 ]; +u32 cpll_con[6 ]; +u32 reserved3[2 ]; +u32 gpll_con[6 ]; +u32 reserved4[2 ]; +u32 npll_con[6 ]; +u32 reserved5[2 ]; +u32 vpll_con[6 ]; +u32 reserved6[0x0a ]; +u32 clksel_con[108 ]; +u32 reserved7[0x14 ]; +u32 clkgate_con[35 ]; +u32 reserved8[0x1d ]; +u32 softrst_con[21 ]; +u32 reserved9[0x2b ]; +u32 glb_srst_fst_value; +u32 glb_srst_snd_value; +u32 glb_cnt_th; +u32 misc_con; +u32 glb_rst_con; +u32 glb_rst_st; +u32 reserved10[0x1a ]; +u32 sdmmc_con[2 ]; +u32 sdio0_con[2 ]; +u32 sdio1_con[2 ]; +}; +check_member (rk3399_cru, sdio1_con[1 ],0x594 ); +#define MHz 1000000 +#define KHz 1000 +#define OSC_HZ (24*MHz) +#define APLL_HZ (600*MHz) +#define GPLL_HZ (594*MHz) +#define CPLL_HZ (384*MHz) +#define PPLL_HZ (594*MHz) + +#define PMU_PCLK_HZ (99*MHz) + +#define ACLKM_CORE_HZ (300*MHz) +#define ATCLK_CORE_HZ (300*MHz) +#define PCLK_DBG_HZ (100*MHz) + +#define PERIHP_ACLK_HZ (148500*KHz) +#define PERIHP_HCLK_HZ (148500*KHz) +#define PERIHP_PCLK_HZ (37125*KHz) + +#define PERILP0_ACLK_HZ (99000*KHz) +#define PERILP0_HCLK_HZ (99000*KHz) +#define PERILP0_PCLK_HZ (49500*KHz) + +#define PERILP1_HCLK_HZ (99000*KHz) +#define PERILP1_PCLK_HZ (49500*KHz) + +#define PWM_CLOCK_HZ PMU_PCLK_HZ + +enum apll_l_frequencies { +APLL_L_1600_MHZ , +APLL_L_600_MHZ , +}; + +#endif /* __ASM_ARCH_CRU_RK3399_H_ */
arch/arm/mach-rockchip/rk3399/Makefile +2 -0
@@ -5,3 +5,5 @@ # obj-y += rk3399.o +obj-y += reset_rk3399.o +obj-y += syscon_rk3399.o
arch/arm/mach-rockchip/rk3399/reset_rk3399.c new file +45 -0
45 lines not on this page · raw message
arch/arm/mach-rockchip/rk3399/syscon_rk3399.c new file +20 -0
@@ -0,0 +1,20 @@ +/* +* (C) Copyright 2016 Rockchip Electronics Co., Ltd +* +* 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 rk3399_syscon_ids[] = { + { .compatible ="rockchip,rk3399-grf" , .data =ROCKCHIP_SYSCON_GRF }, +}; + +U_BOOT_DRIVER (syscon_rk3399) = { + .name ="rk3399_syscon" , + .id =UCLASS_SYSCON , + .of_match = rk3399_syscon_ids, +};
drivers/clk/Makefile +1 -0
@@ -8,6 +8,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_ROCKCHIP_RK3399) += clk_rk3399.o obj-$(CONFIG_SANDBOX) += clk_sandbox.o obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
drivers/clk/clk_rk3399.c new file +825 -0
825 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 1/2 rk3399: add basic soc driver
Quoted 1 line · Kever Yang
This patch add driver for:
[snip]
...
Quoted 19 lines
drivers/clk/clk_rk3399.c new file +19
-0+ +static ulong rk3399_clk_set_rate (struct clk *clk,ulong rate) +{ +struct rk3399_clk_priv *priv =dev_get_priv (clk->dev); + +switch (clk->id) { + case 0 ... 63: +return 0 ; +case SCLK_SDMMC : +case SCLK_EMMC : +rk3399_mmc_set_clk (priv->cru, clk->id, rate); +break ; +case SCLK_I2C1 : +case SCLK_I2C2 : +case SCLK_I2C3 : +case SCLK_I2C5 : +case SCLK_I2C6 : +case SCLK_I2C7 : +rk3399_i2c_set_clk (priv->cru, clk->id, rate);
drivers/clk/clk_rk3399.c line 763
Quoted 10 lines
drivers/clk/clk_rk3399.c new file +10
-0+break ; +case DCLK_VOP0 : +case DCLK_VOP1 : +rk3399_vop_set_clk (priv->cru, clk->id, rate); +break ; +default : +return -ENOENT ; + } + +return 0 ;
It suppose to return a real clock rate instead a '0' here, will update with other
potential comments later.
Thanks,
- Kever
Quoted 62 lines
drivers/clk/clk_rk3399.c new file +62
-0+} + +static struct clk_ops rk3399_clk_ops = { + .get_rate = rk3399_clk_get_rate, + .set_rate = rk3399_clk_set_rate, +}; + +void *rockchip_get_cru (void ) +{ +struct udevice *dev; +fdt_addr_t addr; +int ret; + + ret =uclass_get_device_by_name (UCLASS_CLK , +"clock-controller at ff760000" , + &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 rk3399_clk_probe (struct udevice *dev) +{ +struct rk3399_clk_priv *priv =dev_get_priv (dev); + + priv->cru = (struct rk3399_cru *)dev_get_addr (dev); +rkclk_init (priv->cru); + +return 0 ; +} + +static int rk3399_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,"rk3399_sysreset" ,"reset" , &dev); +if (ret) +printf ("Warning: No RK3399 reset driver: ret=%d\n" , ret); + +return 0 ; +} + +static const struct udevice_id rk3399_clk_ids[] = { + { .compatible ="rockchip,rk3399-cru" }, + { } +}; + +U_BOOT_DRIVER (clk_rk3399) = { + .name ="clk_rk3399" , + .id =UCLASS_CLK , + .of_match = rk3399_clk_ids, + .priv_auto_alloc_size =sizeof (struct rk3399_clk_priv ), + .ops = &rk3399_clk_ops, + .bind = rk3399_clk_bind, + .probe = rk3399_clk_probe, +};
PATCH 1/2 rk3399: add basic soc driver
In reply to Kever YangHi Kever,
Quoted 276 lines · Kever Yang
This patch add driver for:
- clock driver includingset_ratefor cpu, mmc, vop, I2C.
- sysreset driver
- grf syscon driverSigned-off-by Kever Yang <[email protected]>---
arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 93 +++ arch/arm/mach-rockchip/rk3399/Makefile | 2 + arch/arm/mach-rockchip/rk3399/reset_rk3399.c | 45 ++ arch/arm/mach-rockchip/rk3399/syscon_rk3399.c | 20 + drivers/clk/Makefile | 1 + drivers/clk/clk_rk3399.c | 825 ++++++++++++++++++++++++ 6 files changed, 986 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3399.h create mode 100644 arch/arm/mach-rockchip/rk3399/reset_rk3399.c create mode 100644 arch/arm/mach-rockchip/rk3399/syscon_rk3399.c create mode 100644 drivers/clk/clk_rk3399.carch/arm/include/asm/arch-rockchip/cru_rk3399.h new file +93
-0@@ -0,0 +1,93 @@ +/* +* (C) Copyright 2016 Rockchip Electronics Co., Ltd +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __ASM_ARCH_CRU_RK3399_H_ +#define __ASM_ARCH_CRU_RK3399_H_ + +#include <common.h> + +struct rk3399_pmucru { +u32 ppll_con[6 ]; +u32 reserved[0x1a ]; +u32 pmucru_clksel[6 ]; +u32 pmucru_clkfrac_con[2 ]; +u32 reserved2[0x18 ]; +u32 pmucru_clkgate_con[3 ]; +u32 reserved3; +u32 pmucru_softrst_con[2 ]; +u32 reserved4[2 ]; +u32 pmucru_rstnhold_con[2 ]; +u32 reserved5[2 ]; +u32 pmucru_gatedis_con[2 ]; +}; +check_member (rk3399_pmucru, pmucru_gatedis_con[1 ],0x134 ); + +struct rk3399_cru { +u32 apll_l_con[6 ]; +u32 reserved[2 ]; +u32 apll_b_con[6 ]; +u32 reserved1[2 ]; +u32 dpll_con[6 ]; +u32 reserved2[2 ]; +u32 cpll_con[6 ]; +u32 reserved3[2 ]; +u32 gpll_con[6 ]; +u32 reserved4[2 ]; +u32 npll_con[6 ]; +u32 reserved5[2 ]; +u32 vpll_con[6 ]; +u32 reserved6[0x0a ]; +u32 clksel_con[108 ]; +u32 reserved7[0x14 ]; +u32 clkgate_con[35 ]; +u32 reserved8[0x1d ]; +u32 softrst_con[21 ]; +u32 reserved9[0x2b ]; +u32 glb_srst_fst_value; +u32 glb_srst_snd_value; +u32 glb_cnt_th; +u32 misc_con; +u32 glb_rst_con; +u32 glb_rst_st; +u32 reserved10[0x1a ]; +u32 sdmmc_con[2 ]; +u32 sdio0_con[2 ]; +u32 sdio1_con[2 ]; +}; +check_member (rk3399_cru, sdio1_con[1 ],0x594 ); +#define MHz 1000000 +#define KHz 1000 +#define OSC_HZ (24*MHz) +#define APLL_HZ (600*MHz) +#define GPLL_HZ (594*MHz) +#define CPLL_HZ (384*MHz) +#define PPLL_HZ (594*MHz) + +#define PMU_PCLK_HZ (99*MHz) + +#define ACLKM_CORE_HZ (300*MHz) +#define ATCLK_CORE_HZ (300*MHz) +#define PCLK_DBG_HZ (100*MHz) + +#define PERIHP_ACLK_HZ (148500*KHz) +#define PERIHP_HCLK_HZ (148500*KHz) +#define PERIHP_PCLK_HZ (37125*KHz) + +#define PERILP0_ACLK_HZ (99000*KHz) +#define PERILP0_HCLK_HZ (99000*KHz) +#define PERILP0_PCLK_HZ (49500*KHz) + +#define PERILP1_HCLK_HZ (99000*KHz) +#define PERILP1_PCLK_HZ (49500*KHz) + +#define PWM_CLOCK_HZ PMU_PCLK_HZ + +enum apll_l_frequencies { +APLL_L_1600_MHZ , +APLL_L_600_MHZ , +}; + +#endif /* __ASM_ARCH_CRU_RK3399_H_ */ arch/arm/mach-rockchip/rk3399/Makefile +2
-0@@ -5,3 +5,5 @@ # obj-y += rk3399.o +obj-y += reset_rk3399.o +obj-y += syscon_rk3399.oarch/arm/mach-rockchip/rk3399/reset_rk3399.c new file +45
-0@@ -0,0 +1,45 @@ +/* +* (C) Copyright 2016 Rockchip Electronics Co., Ltd +* +* SPDX-License-Identifier: GPL-2.0 +*/ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <sysreset.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3399.h> +#include <asm/arch/hardware.h> +#include <linux/err.h> + +int rk3399_sysreset_request (struct udevice *dev,enum sysreset_t type) +{ +struct rk3399_cru *cru =rockchip_get_cru (); + +if (IS_ERR (cru)) +return PTR_ERR (cru); +switch (type) { +case SYSRESET_WARM : +writel (0xeca8 , &cru->glb_srst_snd_value); +break ; +case SYSRESET_COLD : +writel (0xfdb9 , &cru->glb_srst_fst_value); +break ; +default : +return -EPROTONOSUPPORT ; + } + +return -EINPROGRESS ; +} + +static struct sysreset_ops rk3399_sysreset = { + .request = rk3399_sysreset_request, +}; + +U_BOOT_DRIVER (sysreset_rk3399) = { + .name ="rk3399_sysreset" , + .id =UCLASS_SYSRESET , + .ops = &rk3399_sysreset, +};arch/arm/mach-rockchip/rk3399/syscon_rk3399.c new file +20
-0@@ -0,0 +1,20 @@ +/* +* (C) Copyright 2016 Rockchip Electronics Co., Ltd +* +* 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 rk3399_syscon_ids[] = { + { .compatible ="rockchip,rk3399-grf" , .data =ROCKCHIP_SYSCON_GRF }, +}; + +U_BOOT_DRIVER (syscon_rk3399) = { + .name ="rk3399_syscon" , + .id =UCLASS_SYSCON , + .of_match = rk3399_syscon_ids, +};drivers/clk/Makefile +1
-0@@ -8,6 +8,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_ROCKCHIP_RK3399) += clk_rk3399.o obj-$(CONFIG_SANDBOX) += clk_sandbox.o obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o obj-$(CONFIG_MACH_PIC32) += clk_pic32.odrivers/clk/clk_rk3399.c new file +52
-0@@ -0,0 +1,825 @@ +/* +* (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_rk3399.h> +#include <asm/arch/hardware.h> +#include <dm/lists.h> +#include <dt-bindings/clock/rk3399-cru.h> + +DECLARE_GLOBAL_DATA_PTR ; + +struct rk3399_clk_priv { +struct rk3399_cru *cru; +ulong rate; +}; + +struct pll_div { +u32 refdiv; +u32 fbdiv; +u32 postdiv1; +u32 postdiv2; +u32 frac; +}; + +#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 const struct pll_div gpll_init_cfg =PLL_DIVISORS (GPLL_HZ ,2 ,2 ,1 ); +static const struct pll_div cpll_init_cfg =PLL_DIVISORS (CPLL_HZ ,1 ,2 ,2 ); +static const struct pll_div ppll_init_cfg =PLL_DIVISORS (PPLL_HZ ,2 ,2 ,1 ); + +static const struct pll_div apll_l_1600_cfg =PLL_DIVISORS (1600 *MHz,3 ,1 ,1 ); +static const struct pll_div apll_l_600_cfg =PLL_DIVISORS (600 *MHz,1 ,2 ,1 ); + +static const struct pll_div *apll_l_cfgs[] = { + [APLL_L_1600_MHZ ] = &apll_l_1600_cfg, + [APLL_L_600_MHZ ] = &apll_l_600_cfg,
drivers/clk/clk_rk3399.c line 62
Quoted 10 lines
drivers/clk/clk_rk3399.c new file +10
-0+}; + +enum { +/* PLL_CON0 */ +PLL_FBDIV_MASK =0xfff , +PLL_FBDIV_SHIFT =0 , + +/* PLL_CON1 */ +PLL_POSTDIV2_MASK =0x7 , +PLL_POSTDIV2_SHIFT =12 ,
I messed this up in my initial patches. Really it should be like this:
PLL_POSTDIV2_SHIFT = 12,
PLL_POSTDIV2_MASK = 0x7 << PLL_POSTDIV2_SHIFT,
and then in the C code you don't need to have PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT. You can just use PLL_POSTDIV2_MASK.
Can you fix this? It would be good to fix it for other SoCs too.
Quoted 183 lines
drivers/clk/clk_rk3399.c new file +183
-0+PLL_POSTDIV1_MASK =0x7 , +PLL_POSTDIV1_SHIFT =8 , +PLL_REFDIV_MASK =0x3f , +PLL_REFDIV_SHIFT =0 , + +/* PLL_CON2 */ +PLL_LOCK_STATUS_MASK =1 , +PLL_LOCK_STATUS_SHIFT =31 , +PLL_FRACDIV_MASK =0xffffff , +PLL_FRACDIV_SHIFT =0 , + +/* PLL_CON3 */ +PLL_MODE_MASK =3 , +PLL_MODE_SHIFT =8 , +PLL_MODE_SLOW =0 , +PLL_MODE_NORM , +PLL_MODE_DEEP , +PLL_DSMPD_MASK =1 , +PLL_DSMPD_SHIFT =3 , +PLL_INTEGER_MODE =1 , + +/* PMUCRU_CLKSEL_CON0 */ +PMU_PCLK_DIV_CON_MASK =0x1f , +PMU_PCLK_DIV_CON_SHIFT =0 , + +/* PMUCRU_CLKSEL_CON1 */ +SPI3_PLL_SEL_MASK =1 , +SPI3_PLL_SEL_SHIFT =7 , +SPI3_PLL_SEL_24M =0 , +SPI3_PLL_SEL_PPLL =1 , +SPI3_DIV_CON_MASK =0x7f , +SPI3_DIV_CON_SHIFT =0x0 , + +/* PMUCRU_CLKSEL_CON2 */ +I2C_DIV_CON_MASK =0x7f , +I2C8_DIV_CON_SHIFT =8 , +I2C0_DIV_CON_SHIFT =0 , + +/* PMUCRU_CLKSEL_CON3 */ +I2C4_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON0 */ +ACLKM_CORE_L_DIV_CON_MASK =0x1f , +ACLKM_CORE_L_DIV_CON_SHIFT =8 , +CLK_CORE_L_PLL_SEL_MASK =3 , +CLK_CORE_L_PLL_SEL_SHIFT =6 , +CLK_CORE_L_PLL_SEL_ALPLL =0x0 , +CLK_CORE_L_PLL_SEL_ABPLL =0x1 , +CLK_CORE_L_PLL_SEL_DPLL =0x10 , +CLK_CORE_L_PLL_SEL_GPLL =0x11 , +CLK_CORE_L_DIV_MASK =0x1f , +CLK_CORE_L_DIV_SHIFT =0 , + +/* CLKSEL_CON1 */ +PCLK_DBG_L_DIV_MASK =0x1f , +PCLK_DBG_L_DIV_SHIFT =0x8 , +ATCLK_CORE_L_DIV_MASK =0x1f , +ATCLK_CORE_L_DIV_SHIFT =0 , + +/* CLKSEL_CON14 */ +PCLK_PERIHP_DIV_CON_MASK =0x7 , +PCLK_PERIHP_DIV_CON_SHIFT =12 , +HCLK_PERIHP_DIV_CON_MASK =3 , +HCLK_PERIHP_DIV_CON_SHIFT =8 , +ACLK_PERIHP_PLL_SEL_MASK =1 , +ACLK_PERIHP_PLL_SEL_SHIFT =7 , +ACLK_PERIHP_PLL_SEL_CPLL =0 , +ACLK_PERIHP_PLL_SEL_GPLL =1 , +ACLK_PERIHP_DIV_CON_MASK =0x1f , +ACLK_PERIHP_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON21 */ +ACLK_EMMC_PLL_SEL_MASK =0x1 , +ACLK_EMMC_PLL_SEL_SHIFT =7 , +ACLK_EMMC_PLL_SEL_GPLL =0x1 , +ACLK_EMMC_DIV_CON_MASK =0x1f , +ACLK_EMMC_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON22 */ +CLK_EMMC_PLL_MASK =0x7 , +CLK_EMMC_PLL_SHIFT =8 , +CLK_EMMC_PLL_SEL_GPLL =0x1 , +CLK_EMMC_DIV_CON_MASK =0x7f , +CLK_EMMC_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON23 */ +PCLK_PERILP0_DIV_CON_MASK =0x7 , +PCLK_PERILP0_DIV_CON_SHIFT =12 , +HCLK_PERILP0_DIV_CON_MASK =3 , +HCLK_PERILP0_DIV_CON_SHIFT =8 , +ACLK_PERILP0_PLL_SEL_MASK =1 , +ACLK_PERILP0_PLL_SEL_SHIFT =7 , +ACLK_PERILP0_PLL_SEL_CPLL =0 , +ACLK_PERILP0_PLL_SEL_GPLL =1 , +ACLK_PERILP0_DIV_CON_MASK =0x1f , +ACLK_PERILP0_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON25 */ +PCLK_PERILP1_DIV_CON_MASK =0x7 , +PCLK_PERILP1_DIV_CON_SHIFT =8 , +HCLK_PERILP1_PLL_SEL_MASK =1 , +HCLK_PERILP1_PLL_SEL_SHIFT =7 , +HCLK_PERILP1_PLL_SEL_CPLL =0 , +HCLK_PERILP1_PLL_SEL_GPLL =1 , +HCLK_PERILP1_DIV_CON_MASK =0x1f , +HCLK_PERILP1_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON26 */ +CLK_SARADC_DIV_CON_MASK =0xff , +CLK_SARADC_DIV_CON_SHIFT =8 , + +/* CLKSEL_CON27 */ +CLK_TSADC_SEL_X24M =0x0 , +CLK_TSADC_SEL_MASK =1 , +CLK_TSADC_SEL_SHIFT =15 , +CLK_TSADC_DIV_CON_MASK =0x3ff , +CLK_TSADC_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON47 & CLKSEL_CON48 */ +ACLK_VOP_PLL_SEL_MASK =0x3 , +ACLK_VOP_PLL_SEL_SHIFT =6 , +ACLK_VOP_PLL_SEL_CPLL =0x1 , +ACLK_VOP_DIV_CON_MASK =0x1f , +ACLK_VOP_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON49 & CLKSEL_CON50 */ +DCLK_VOP_DCLK_SEL_MASK =1 , +DCLK_VOP_DCLK_SEL_SHIFT =11 , +DCLK_VOP_DCLK_SEL_DIVOUT =0 , +DCLK_VOP_PLL_SEL_MASK =3 , +DCLK_VOP_PLL_SEL_SHIFT =8 , +DCLK_VOP_PLL_SEL_VPLL =0 , +DCLK_VOP_DIV_CON_MASK =0xff , +DCLK_VOP_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON58 */ +CLK_SPI_PLL_SEL_MASK =1 , +CLK_SPI_PLL_SEL_CPLL =0 , +CLK_SPI_PLL_SEL_GPLL =1 , +CLK_SPI_PLL_DIV_CON_MASK =0x7f , +CLK_SPI5_PLL_DIV_CON_SHIFT =8 , +CLK_SPI5_PLL_SEL_SHIFT =15 , + +/* CLKSEL_CON59 */ +CLK_SPI1_PLL_SEL_SHIFT =15 , +CLK_SPI1_PLL_DIV_CON_SHIFT =8 , +CLK_SPI0_PLL_SEL_SHIFT =7 , +CLK_SPI0_PLL_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON60 */ +CLK_SPI4_PLL_SEL_SHIFT =15 , +CLK_SPI4_PLL_DIV_CON_SHIFT =8 , +CLK_SPI2_PLL_SEL_SHIFT =7 , +CLK_SPI2_PLL_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON61 */ +CLK_I2C_PLL_SEL_MASK =1 , +CLK_I2C_PLL_SEL_CPLL =0 , +CLK_I2C_PLL_SEL_GPLL =1 , +CLK_I2C5_PLL_SEL_SHIFT =15 , +CLK_I2C5_DIV_CON_SHIFT =8 , +CLK_I2C1_PLL_SEL_SHIFT =7 , +CLK_I2C1_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON62 */ +CLK_I2C6_PLL_SEL_SHIFT =15 , +CLK_I2C6_DIV_CON_SHIFT =8 , +CLK_I2C2_PLL_SEL_SHIFT =7 , +CLK_I2C2_DIV_CON_SHIFT =0 , + +/* CLKSEL_CON63 */ +CLK_I2C7_PLL_SEL_SHIFT =15 , +CLK_I2C7_DIV_CON_SHIFT =8 , +CLK_I2C3_PLL_SEL_SHIFT =7 , +CLK_I2C3_DIV_CON_SHIFT =0 , + +/* CRU_SOFTRST_CON4 */ +RESETN_DDR0_REQ_MASK =1 , +RESETN_DDR0_REQ_SHIFT =8 , +RESETN_DDRPHY0_REQ_MASK =1 , +RESETN_DDRPHY0_REQ_SHIFT =9 , +RESETN_DDR1_REQ_MASK =1 , + RESETN_DDR1_REQ_SHIFT = 12,
drivers/clk/clk_rk3399.c line 255
Quoted 10 lines
drivers/clk/clk_rk3399.c new file +10
-0+RESETN_DDRPHY1_REQ_MASK =1 , + RESETN_DDRPHY1_REQ_SHIFT = 13, +}; + +#define VCO_MAX_KHZ (3200 * (MHz / KHz)) +#define VCO_MIN_KHZ (800 * (MHz / KHz)) +#define OUTPUT_MAX_KHZ (3200 * (MHz / KHz)) +#define OUTPUT_MIN_KHZ (16 * (MHz / KHz)) + +/* the div restrictions of pll in integer mode,
comment style need fixing throughout
/*
* The div restructions
Also please try to wrap comments to around 75 columns.
Quoted 14 lines
drivers/clk/clk_rk3399.c new file +14
-0+* these are defined in * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0 +*/ +#define PLL_DIV_MIN 16 +#define PLL_DIV_MAX 3200 + +/* How to calculate the PLL(from TRM V0.3 Part 1 Page 63): +* Formulas also embedded within the Fractional PLL Verilog model: +* If DSMPD = 1 (DSM is disabled, "integer mode") +* FOUTVCO = FREF / REFDIV * FBDIV +* FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 +* Where: +* FOUTVCO = Fractional PLL non-divided output frequency +* FOUTPOSTDIV = Fractional PLL divided output frequency +* (output of second post divider)
drivers/clk/clk_rk3399.c line 279
Quoted 10 lines
drivers/clk/clk_rk3399.c new file +10
-0+* FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input) +* REFDIV = Fractional PLL input reference clock divider +* FBDIV = Integer value programmed into feedback divide +* +*/ +static void rkclk_set_pll (u32 *pll_con,const struct pll_div *div) +{ +/* All 8 PLLs have same VCO and output frequency range restrictions. */ +u32 vco_khz =OSC_HZ /1000 * div->fbdiv / div->refdiv; +u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2;
Why do you use u32 for all these types? Is uint not what you want?
Quoted 31 lines
drivers/clk/clk_rk3399.c new file +31
-0+ +debug ("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, " +"postdiv2=%d, vco=%u khz, output=%u khz\n" , + pll_con, div->fbdiv, div->refdiv, div->postdiv1, + div->postdiv2, vco_khz, output_khz); +assert (vco_khz >=VCO_MIN_KHZ && vco_khz <=VCO_MAX_KHZ && + output_khz >=OUTPUT_MIN_KHZ && output_khz <=OUTPUT_MAX_KHZ && + div->fbdiv >=PLL_DIV_MIN && div->fbdiv <=PLL_DIV_MAX ); + +/* When power on or changing PLL setting, +* we must force PLL into slow mode to ensure output stable clock. +*/ +rk_clrsetreg (&pll_con[3 ],PLL_MODE_MASK <<PLL_MODE_SHIFT , +PLL_MODE_SLOW <<PLL_MODE_SHIFT ); + +/* use integer mode */ +rk_clrsetreg (&pll_con[3 ],PLL_DSMPD_MASK <<PLL_DSMPD_SHIFT , +PLL_INTEGER_MODE <<PLL_DSMPD_SHIFT ); + +rk_clrsetreg (&pll_con[0 ],PLL_FBDIV_MASK <<PLL_FBDIV_SHIFT , + div->fbdiv <<PLL_FBDIV_SHIFT ); +rk_clrsetreg (&pll_con[1 ], +PLL_POSTDIV2_MASK <<PLL_POSTDIV2_SHIFT | +PLL_POSTDIV1_MASK <<PLL_POSTDIV1_SHIFT | +PLL_REFDIV_MASK |PLL_REFDIV_SHIFT , + (div->postdiv2 <<PLL_POSTDIV2_SHIFT ) | + (div->postdiv1 <<PLL_POSTDIV1_SHIFT ) | + (div->refdiv <<PLL_REFDIV_SHIFT )); + +/* waiting for pll lock */ +while (!(readl (&pll_con[2 ]) & (1 <<PLL_LOCK_STATUS_SHIFT )))
drivers/clk/clk_rk3399.c line 320
Quoted 10 lines
drivers/clk/clk_rk3399.c new file +10
-0+udelay (1 ); + +/* pll enter normal mode */ +rk_clrsetreg (&pll_con[3 ],PLL_MODE_MASK <<PLL_MODE_SHIFT , +PLL_MODE_NORM <<PLL_MODE_SHIFT ); +} + +static inline unsigned long div_round_up (unsigned int n,unsigned int d) +{ +return (n + d -1 ) / d;
Can you use DIV_ROUND_UP()?
Quoted 65 lines
drivers/clk/clk_rk3399.c new file +65
-0+} + +static int pll_para_config (u32 freq_hz,struct pll_div *div) +{ +u32 ref_khz =OSC_HZ / KHz, refdiv, fbdiv =0 ; +u32 postdiv1, postdiv2 =1 ; +u32 fref_khz; +u32 diff_khz, best_diff_khz; +const u32 max_refdiv =63 , max_fbdiv =3200 , min_fbdiv =16 ; +const u32 max_postdiv1 =7 , max_postdiv2 =7 ; +u32 vco_khz; +u32 freq_khz = freq_hz / KHz; + +if (!freq_hz) { +printf ("%s: the frequency can't be 0 Hz\n" , __func__); +return -1 ; + } + + postdiv1 =div_round_up (VCO_MIN_KHZ , freq_khz); +if (postdiv1 > max_postdiv1) { + postdiv2 =div_round_up (postdiv1, max_postdiv1); + postdiv1 =div_round_up (postdiv1, postdiv2); + } + + vco_khz = freq_khz * postdiv1 * postdiv2; + +if (vco_khz <VCO_MIN_KHZ || vco_khz >VCO_MAX_KHZ || + postdiv2 > max_postdiv2) { +printf ("%s: Cannot find out a supported VCO" +" for Frequency (%uHz).\n" , __func__, freq_hz); +return -1 ; + } + + div->postdiv1 = postdiv1; + div->postdiv2 = postdiv2; + + best_diff_khz = vco_khz; +for (refdiv =1 ; refdiv < max_refdiv && best_diff_khz; refdiv++) { + fref_khz = ref_khz / refdiv; + + fbdiv = vco_khz / fref_khz; +if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv)) +continue ; + diff_khz = vco_khz - fbdiv * fref_khz; +if (fbdiv +1 < max_fbdiv && diff_khz > fref_khz /2 ) { + fbdiv++; + diff_khz = fref_khz - diff_khz; + } + +if (diff_khz >= best_diff_khz) +continue ; + + best_diff_khz = diff_khz; + div->refdiv = refdiv; + div->fbdiv = fbdiv; + } + +if (best_diff_khz >4 * (MHz/KHz)) { +printf ("%s: Failed to match output frequency %u, " +"difference is %u Hz,exceed 4MHZ\n" , __func__, freq_hz, + best_diff_khz * KHz); +return -1 ; + } +return 0 ; +}
drivers/clk/clk_rk3399.c line 395
Quoted 10 lines
drivers/clk/clk_rk3399.c new file +10
-0+ +static void rkclk_init (struct rk3399_cru *cru) +{ +u32 aclk_div; +u32 hclk_div; +u32 pclk_div; + +/* some cru registers changed by bootrom, we'd better reset them to +* reset/default values described in TRM to avoid confusion in kernel. +* Please consider these threee lines as a fix of bootrom bug.
three
Quoted 374 lines
drivers/clk/clk_rk3399.c new file +374
-0+*/ +rk_clrsetreg (&cru->clksel_con[12 ],0xffff ,0x4101 ); +rk_clrsetreg (&cru->clksel_con[19 ],0xffff ,0x033f ); +rk_clrsetreg (&cru->clksel_con[56 ],0x0003 ,0x0003 ); + +/* configure gpll cpll */ +rkclk_set_pll (&cru->gpll_con[0 ], &gpll_init_cfg); +rkclk_set_pll (&cru->cpll_con[0 ], &cpll_init_cfg); + +/* configure perihp aclk, hclk, pclk */ + aclk_div =GPLL_HZ /PERIHP_ACLK_HZ -1 ; +assert ((aclk_div +1 ) *PERIHP_ACLK_HZ ==GPLL_HZ && aclk_div <0x1f ); + + hclk_div =PERIHP_ACLK_HZ /PERIHP_HCLK_HZ -1 ; +assert ((hclk_div +1 ) *PERIHP_HCLK_HZ == +PERIHP_ACLK_HZ && (hclk_div <0x4 )); + + pclk_div =PERIHP_ACLK_HZ /PERIHP_PCLK_HZ -1 ; +assert ((pclk_div +1 ) *PERIHP_PCLK_HZ == +PERIHP_ACLK_HZ && (pclk_div <0x7 )); + +rk_clrsetreg (&cru->clksel_con[14 ], +PCLK_PERIHP_DIV_CON_MASK <<PCLK_PERIHP_DIV_CON_SHIFT | +HCLK_PERIHP_DIV_CON_MASK <<HCLK_PERIHP_DIV_CON_SHIFT | +ACLK_PERIHP_PLL_SEL_MASK <<ACLK_PERIHP_PLL_SEL_SHIFT | +ACLK_PERIHP_DIV_CON_MASK <<ACLK_PERIHP_DIV_CON_SHIFT , + pclk_div <<PCLK_PERIHP_DIV_CON_SHIFT | + hclk_div <<HCLK_PERIHP_DIV_CON_SHIFT | +ACLK_PERIHP_PLL_SEL_GPLL <<ACLK_PERIHP_PLL_SEL_SHIFT | + aclk_div <<ACLK_PERIHP_DIV_CON_SHIFT ); + +/* configure perilp0 aclk, hclk, pclk */ + aclk_div =GPLL_HZ /PERILP0_ACLK_HZ -1 ; +assert ((aclk_div +1 ) *PERILP0_ACLK_HZ ==GPLL_HZ && aclk_div <0x1f ); + + hclk_div =PERILP0_ACLK_HZ /PERILP0_HCLK_HZ -1 ; +assert ((hclk_div +1 ) *PERILP0_HCLK_HZ == +PERILP0_ACLK_HZ && (hclk_div <0x4 )); + + pclk_div =PERILP0_ACLK_HZ /PERILP0_PCLK_HZ -1 ; +assert ((pclk_div +1 ) *PERILP0_PCLK_HZ == +PERILP0_ACLK_HZ && (pclk_div <0x7 )); + +rk_clrsetreg (&cru->clksel_con[23 ], +PCLK_PERILP0_DIV_CON_MASK <<PCLK_PERILP0_DIV_CON_SHIFT | +HCLK_PERILP0_DIV_CON_MASK <<HCLK_PERILP0_DIV_CON_SHIFT | +ACLK_PERILP0_PLL_SEL_MASK <<ACLK_PERILP0_PLL_SEL_SHIFT | +ACLK_PERILP0_DIV_CON_MASK <<ACLK_PERILP0_DIV_CON_SHIFT , + pclk_div <<PCLK_PERILP0_DIV_CON_SHIFT | + hclk_div <<HCLK_PERILP0_DIV_CON_SHIFT | +ACLK_PERILP0_PLL_SEL_GPLL <<ACLK_PERILP0_PLL_SEL_SHIFT | + aclk_div <<ACLK_PERILP0_DIV_CON_SHIFT ); + +/* perilp1 hclk select gpll as source */ + hclk_div =GPLL_HZ /PERILP1_HCLK_HZ -1 ; +assert ((hclk_div +1 ) *PERILP1_HCLK_HZ == +GPLL_HZ && (hclk_div <0x1f )); + + pclk_div =PERILP1_HCLK_HZ /PERILP1_HCLK_HZ -1 ; +assert ((pclk_div +1 ) *PERILP1_HCLK_HZ == +PERILP1_HCLK_HZ && (hclk_div <0x7 )); + +rk_clrsetreg (&cru->clksel_con[25 ], +PCLK_PERILP1_DIV_CON_MASK <<PCLK_PERILP1_DIV_CON_SHIFT | +HCLK_PERILP1_DIV_CON_MASK <<HCLK_PERILP1_DIV_CON_SHIFT | +HCLK_PERILP1_PLL_SEL_MASK <<HCLK_PERILP1_PLL_SEL_SHIFT , + pclk_div <<PCLK_PERILP1_DIV_CON_SHIFT | + hclk_div <<HCLK_PERILP1_DIV_CON_SHIFT | +HCLK_PERILP1_PLL_SEL_GPLL <<HCLK_PERILP1_PLL_SEL_SHIFT ); +} + +void rk3399_configure_cpu (struct rk3399_cru *cru, +enum apll_l_frequencies apll_l_freq) +{ +u32 aclkm_div; +u32 pclk_dbg_div; +u32 atclk_div; + +rkclk_set_pll (&cru->apll_l_con[0 ], apll_l_cfgs[apll_l_freq]); + + aclkm_div =APLL_HZ /ACLKM_CORE_HZ -1 ; +assert ((aclkm_div +1 ) *ACLKM_CORE_HZ ==APLL_HZ && + aclkm_div <0x1f ); + + pclk_dbg_div =APLL_HZ /PCLK_DBG_HZ -1 ; +assert ((pclk_dbg_div +1 ) *PCLK_DBG_HZ ==APLL_HZ && + pclk_dbg_div <0x1f ); + + atclk_div =APLL_HZ /ATCLK_CORE_HZ -1 ; +assert ((atclk_div +1 ) *ATCLK_CORE_HZ ==APLL_HZ && + atclk_div <0x1f ); + +rk_clrsetreg (&cru->clksel_con[0 ], +ACLKM_CORE_L_DIV_CON_MASK <<ACLKM_CORE_L_DIV_CON_SHIFT | +CLK_CORE_L_PLL_SEL_MASK <<CLK_CORE_L_PLL_SEL_SHIFT | +CLK_CORE_L_DIV_MASK <<CLK_CORE_L_DIV_SHIFT , + aclkm_div <<ACLKM_CORE_L_DIV_CON_SHIFT | +CLK_CORE_L_PLL_SEL_ALPLL <<CLK_CORE_L_PLL_SEL_SHIFT | +0 <<CLK_CORE_L_DIV_SHIFT ); + +rk_clrsetreg (&cru->clksel_con[1 ], +PCLK_DBG_L_DIV_MASK <<PCLK_DBG_L_DIV_SHIFT | +ATCLK_CORE_L_DIV_MASK <<ATCLK_CORE_L_DIV_SHIFT , + pclk_dbg_div <<PCLK_DBG_L_DIV_SHIFT | + atclk_div <<ATCLK_CORE_L_DIV_SHIFT ); +} +#define I2C_CLK_REG_MASK (bus) \ + (I2C_DIV_CON_MASK << \ + CLK_I2C ##bus## _DIV_CON_SHIFT | \ + CLK_I2C_PLL_SEL_MASK << \ + CLK_I2C ##bus## _PLL_SEL_SHIFT) + +#define I2C_CLK_REG_VALUE (bus, clk_div) \ + ((clk_div - 1) << \ + CLK_I2C ##bus## _DIV_CON_SHIFT | \ + CLK_I2C_PLL_SEL_GPLL << \ + CLK_I2C ##bus## _PLL_SEL_SHIFT) + +#define I2C_CLK_DIV_VALUE (con, bus) \ + (con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & \ + I2C_DIV_CON_MASK; + +static ulong rk3399_i2c_get_clk (struct rk3399_cru *cru,ulong clk_id) +{ +u32 div, con; + +switch (clk_id) { +case SCLK_I2C1 : + con =readl (&cru->clksel_con[61 ]); + div =I2C_CLK_DIV_VALUE (con,1 ); +break ; +case SCLK_I2C2 : + con =readl (&cru->clksel_con[62 ]); + div =I2C_CLK_DIV_VALUE (con,2 ); +break ; +case SCLK_I2C3 : + con =readl (&cru->clksel_con[63 ]); + div =I2C_CLK_DIV_VALUE (con,3 ); +break ; +case SCLK_I2C5 : + con =readl (&cru->clksel_con[61 ]); + div =I2C_CLK_DIV_VALUE (con,5 ); +break ; +case SCLK_I2C6 : + con =readl (&cru->clksel_con[62 ]); + div =I2C_CLK_DIV_VALUE (con,6 ); +break ; +case SCLK_I2C7 : + con =readl (&cru->clksel_con[63 ]); + div =I2C_CLK_DIV_VALUE (con,7 ); +break ; +default : +printf ("do not support this i2c bus\n" ); +return -EINVAL ; + } + +return DIV_TO_RATE (GPLL_HZ , div); +} + +static ulong rk3399_i2c_set_clk (struct rk3399_cru *cru,ulong clk_id,uint hz) +{ +int src_clk_div; + +/* i2c0,4,8 src clock from ppll, i2c1,2,3,5,6,7 src clock from gpll*/ + src_clk_div =GPLL_HZ / hz; +assert (src_clk_div -1 <127 ); + +switch (clk_id) { +case SCLK_I2C1 : +rk_clrsetreg (&cru->clksel_con[61 ],I2C_CLK_REG_MASK (1 ), +I2C_CLK_REG_VALUE (1 , src_clk_div)); +break ; +case SCLK_I2C2 : +rk_clrsetreg (&cru->clksel_con[62 ],I2C_CLK_REG_MASK (2 ), +I2C_CLK_REG_VALUE (2 , src_clk_div)); +break ; +case SCLK_I2C3 : +rk_clrsetreg (&cru->clksel_con[63 ],I2C_CLK_REG_MASK (3 ), +I2C_CLK_REG_VALUE (3 , src_clk_div)); +break ; +case SCLK_I2C5 : +rk_clrsetreg (&cru->clksel_con[61 ],I2C_CLK_REG_MASK (5 ), +I2C_CLK_REG_VALUE (5 , src_clk_div)); +break ; +case SCLK_I2C6 : +rk_clrsetreg (&cru->clksel_con[62 ],I2C_CLK_REG_MASK (6 ), +I2C_CLK_REG_VALUE (6 , src_clk_div)); +break ; +case SCLK_I2C7 : +rk_clrsetreg (&cru->clksel_con[63 ],I2C_CLK_REG_MASK (7 ), +I2C_CLK_REG_VALUE (7 , src_clk_div)); +break ; +default : +printf ("do not support this i2c bus\n" ); +return -EINVAL ; + } + +return DIV_TO_RATE (GPLL_HZ , src_clk_div); +} + +static ulong rk3399_vop_set_clk (struct rk3399_cru *cru,ulong clk_id,u32 hz) +{ +struct pll_div vpll_config = {0 }; +int aclk_vop =198 *MHz; +void *aclkreg_addr, *dclkreg_addr; +u32 div; + +switch (clk_id) { +case DCLK_VOP0 : + aclkreg_addr = &cru->clksel_con[47 ]; + dclkreg_addr = &cru->clksel_con[49 ]; +break ; +case DCLK_VOP1 : + aclkreg_addr = &cru->clksel_con[48 ]; + dclkreg_addr = &cru->clksel_con[50 ]; +break ; +default : +return -EINVAL ; + } +/* vop aclk source clk: cpll */ + div =CPLL_HZ / aclk_vop; +assert (div -1 <32 ); + +rk_clrsetreg (aclkreg_addr, +ACLK_VOP_PLL_SEL_MASK <<ACLK_VOP_PLL_SEL_SHIFT | +ACLK_VOP_DIV_CON_MASK <<ACLK_VOP_DIV_CON_SHIFT , +ACLK_VOP_PLL_SEL_CPLL <<ACLK_VOP_PLL_SEL_SHIFT | + (div -1 ) <<ACLK_VOP_DIV_CON_SHIFT ); + +/* vop dclk source from vpll, and equals to vpll(means div == 1) */ +if (pll_para_config (hz, &vpll_config)) +return -1 ; + +rkclk_set_pll (&cru->vpll_con[0 ], &vpll_config); + +rk_clrsetreg (dclkreg_addr, +DCLK_VOP_DCLK_SEL_MASK <<DCLK_VOP_DCLK_SEL_SHIFT | +DCLK_VOP_PLL_SEL_MASK <<DCLK_VOP_PLL_SEL_SHIFT | +DCLK_VOP_DIV_CON_MASK <<DCLK_VOP_DIV_CON_SHIFT , +DCLK_VOP_DCLK_SEL_DIVOUT <<DCLK_VOP_DCLK_SEL_SHIFT | +DCLK_VOP_PLL_SEL_VPLL <<DCLK_VOP_PLL_SEL_SHIFT | + (1 -1 ) <<DCLK_VOP_DIV_CON_SHIFT ); + +return hz; +} + +static ulong rk3399_mmc_get_clk (struct rk3399_cru *cru,uint clk_id) +{ +u32 div, con; + +switch (clk_id) { +case SCLK_SDMMC : + con =readl (&cru->clksel_con[16 ]); +break ; +case SCLK_EMMC : + con =readl (&cru->clksel_con[21 ]); +break ; +default : +return -EINVAL ; + } + div = (con>>CLK_EMMC_DIV_CON_SHIFT ) &CLK_EMMC_DIV_CON_MASK ; + +return DIV_TO_RATE (GPLL_HZ , div); +} + +static ulong rk3399_mmc_set_clk (struct rk3399_cru *cru, +ulong clk_id,ulong set_rate) +{ +int src_clk_div; +int aclk_emmc =198 *MHz; + +switch (clk_id) { +case SCLK_SDMMC : +/* Select clk_sdmmc source from GPLL too */ + src_clk_div =GPLL_HZ / set_rate; +assert (src_clk_div -1 <127 ); + +rk_clrsetreg (&cru->clksel_con[16 ], +CLK_EMMC_PLL_MASK <<CLK_EMMC_PLL_SHIFT | +CLK_EMMC_DIV_CON_MASK <<CLK_EMMC_DIV_CON_SHIFT , +CLK_EMMC_PLL_SEL_GPLL <<CLK_EMMC_PLL_SHIFT | + (src_clk_div -1 ) <<CLK_EMMC_DIV_CON_SHIFT ); +break ; +case SCLK_EMMC : +/* Select aclk_emmc source from GPLL */ + src_clk_div =GPLL_HZ / aclk_emmc; +assert (src_clk_div -1 <31 ); + +rk_clrsetreg (&cru->clksel_con[21 ], +ACLK_EMMC_PLL_SEL_MASK <<ACLK_EMMC_PLL_SEL_SHIFT | +ACLK_EMMC_DIV_CON_MASK <<ACLK_EMMC_DIV_CON_SHIFT , +ACLK_EMMC_PLL_SEL_GPLL <<ACLK_EMMC_PLL_SEL_SHIFT | + (src_clk_div -1 ) <<ACLK_EMMC_DIV_CON_SHIFT ); + +/* Select clk_emmc source from GPLL too */ + src_clk_div =GPLL_HZ / set_rate; +assert (src_clk_div -1 <127 ); + +rk_clrsetreg (&cru->clksel_con[22 ], +CLK_EMMC_PLL_MASK <<CLK_EMMC_PLL_SHIFT | +CLK_EMMC_DIV_CON_MASK <<CLK_EMMC_DIV_CON_SHIFT , +CLK_EMMC_PLL_SEL_GPLL <<CLK_EMMC_PLL_SHIFT | + (src_clk_div -1 ) <<CLK_EMMC_DIV_CON_SHIFT ); +break ; +default : +return -EINVAL ; + } +return rk3399_mmc_get_clk (cru, clk_id); +} + +static ulong rk3399_clk_get_rate (struct clk *clk) +{ +struct rk3399_clk_priv *priv =dev_get_priv (clk->dev); +ulong rate =0 ; + +switch (clk->id) { + case 0 ... 63: +return 0 ; +case SCLK_SDMMC : +case SCLK_EMMC : + rate =rk3399_mmc_get_clk (priv->cru, clk->id); +break ; +case SCLK_I2C1 : +case SCLK_I2C2 : +case SCLK_I2C3 : +case SCLK_I2C5 : +case SCLK_I2C6 : +case SCLK_I2C7 : + rate =rk3399_i2c_get_clk (priv->cru, clk->id); +break ; +case DCLK_VOP0 : +case DCLK_VOP1 : +break ; +default : +return -ENOENT ; + } + +return rate; +} + +static ulong rk3399_clk_set_rate (struct clk *clk,ulong rate) +{ +struct rk3399_clk_priv *priv =dev_get_priv (clk->dev); + +switch (clk->id) { + case 0 ... 63: +return 0 ; +case SCLK_SDMMC : +case SCLK_EMMC : +rk3399_mmc_set_clk (priv->cru, clk->id, rate); +break ; +case SCLK_I2C1 : +case SCLK_I2C2 : +case SCLK_I2C3 : +case SCLK_I2C5 : +case SCLK_I2C6 : +case SCLK_I2C7 : +rk3399_i2c_set_clk (priv->cru, clk->id, rate); +break ; +case DCLK_VOP0 : +case DCLK_VOP1 : +rk3399_vop_set_clk (priv->cru, clk->id, rate); +break ; +default : +return -ENOENT ; + } + +return 0 ; +} + +static struct clk_ops rk3399_clk_ops = { + .get_rate = rk3399_clk_get_rate, + .set_rate = rk3399_clk_set_rate, +};
drivers/clk/clk_rk3399.c line 779
Quoted 10 lines
drivers/clk/clk_rk3399.c new file +10
-0+ +void *rockchip_get_cru (void ) +{ +struct udevice *dev; +fdt_addr_t addr; +int ret; + + ret =uclass_get_device_by_name (UCLASS_CLK , +"clock-controller at ff760000" , + &dev);
Can you use uclass_get_device_by_driver()?
drivers/clk/clk_rk3399.c line 783
Quoted 4 lines
drivers/clk/clk_rk3399.c new file +4
-0+if (ret) +return ERR_PTR (ret); + + addr =dev_get_addr (dev);
dev_get_addr_ptr()
drivers/clk/clk_rk3399.c line 794
Quoted 11 lines
drivers/clk/clk_rk3399.c new file +11
-0+if (addr ==FDT_ADDR_T_NONE ) +return ERR_PTR (-EINVAL ); + +return (void *)addr; +} + +static int rk3399_clk_probe (struct udevice *dev) +{ +struct rk3399_clk_priv *priv =dev_get_priv (dev); + + priv->cru = (struct rk3399_cru *)dev_get_addr (dev);
That should really go in and ofdata_to_platdata() method.
Quoted 32 lines
drivers/clk/clk_rk3399.c new file +31
-1+rkclk_init (priv->cru); + +return 0 ; +} + +static int rk3399_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,"rk3399_sysreset" ,"reset" , &dev); +if (ret) +printf ("Warning: No RK3399 reset driver: ret=%d\n" , ret); + +return 0 ; +} + +static const struct udevice_id rk3399_clk_ids[] = { + { .compatible ="rockchip,rk3399-cru" }, + { } +}; + +U_BOOT_DRIVER (clk_rk3399) = { + .name ="clk_rk3399" , + .id =UCLASS_CLK , + .of_match = rk3399_clk_ids, + .priv_auto_alloc_size =sizeof (struct rk3399_clk_priv ), + .ops = &rk3399_clk_ops, + .bind = rk3399_clk_bind, + .probe = rk3399_clk_probe, +}; --
Quoted 3 lines
1.9.1
Regards,
Simon
PATCH 2/2 mmc: rockchip: add clock init
In reply to Kever Yang---
drivers/mmc/rockchip_sdhci.c | 10 +++++++++- include/configs/rk3399_common.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-)
drivers/mmc/rockchip_sdhci.c +9 -1
@@ -7,6 +7,7 @@*/ #include <common.h> +#include <clk.h> #include <dm.h> #include <fdtdec.h> #include <libfdt.h>
@@ -32,15 +33,22 @@ static int arasan_sdhci_probe(struct udevice *dev)struct rockchip_sdhc_plat *plat =dev_get_platdata (dev);struct rockchip_sdhc *prv =dev_get_priv (dev);struct sdhci_host *host = &prv->host; +struct clk clk;int ret;u32 caps; host->version =sdhci_readw (host,SDHCI_HOST_VERSION ); host->quirks =SDHCI_QUIRK_WAIT_SEND_CMD ; + ret =clk_get_by_index (dev,0 , &clk); +if (ret <0 ) +debug ("%s get clock fail\n" , __func__); + + ret =clk_set_rate (&clk,CONFIG_ROCKCHIP_SDHCI_MAX_FREQ ); + caps =sdhci_readl (host,SDHCI_CAPABILITIES ); ret =sdhci_setup_cfg (&plat->cfg, dev->name, host->bus_width, - caps,CONFIG_ROCKCHIP_SDHCI_MAX_FREQ ,EMMC_MIN_FREQ , + caps, ret,EMMC_MIN_FREQ , host->version, host->quirks,0 ); host->mmc = &plat->mmc;
include/configs/rk3399_common.h +1 -1
@@ -32,7 +32,7 @@#define CONFIG_GENERIC_MMC #define CONFIG_SDHCI #define CONFIG_BOUNCE_BUFFER -#define CONFIG_ROCKCHIP_SDHCI_MAX_FREQ 200000000 +#define CONFIG_ROCKCHIP_SDHCI_MAX_FREQ (198*1000000)#define CONFIG_FAT_WRITE
Signature · 1 line
1.9.1
PATCH 2/2 mmc: rockchip: add clock init
Hi Kever,
Quoted 25 lines · Kever Yang
Signed-off-by Kever Yang <[email protected]>---
drivers/mmc/rockchip_sdhci.c | 10 +++++++++- include/configs/rk3399_common.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-)drivers/mmc/rockchip_sdhci.c +2
-0@@ -7,6 +7,7 @@*/ #include <common.h> +#include <clk.h> #include <dm.h> #include <fdtdec.h> #include <libfdt.h> @@ -32,15 +33,22 @@ static int arasan_sdhci_probe(struct udevice *dev)struct rockchip_sdhc_plat *plat =dev_get_platdata (dev);struct rockchip_sdhc *prv =dev_get_priv (dev);struct sdhci_host *host = &prv->host; +struct clk clk;int ret;
drivers/mmc/rockchip_sdhci.c static int arasan_sdhci_probe(struct udevice *dev) · line 47
Quoted 10 lines
drivers/mmc/rockchip_sdhci.c +5
-0u32 caps; host->version =sdhci_readw (host,SDHCI_HOST_VERSION ); host->quirks =SDHCI_QUIRK_WAIT_SEND_CMD ; + ret =clk_get_by_index (dev,0 , &clk); +if (ret <0 ) +debug ("%s get clock fail\n" , __func__); + + ret =clk_set_rate (&clk,CONFIG_ROCKCHIP_SDHCI_MAX_FREQ );
Even if failed to get the clk, clk_set_rate() is called...right?
drivers/mmc/rockchip_sdhci.c static int arasan_sdhci_probe(struct udevice *dev) · line 51
Quoted 5 lines
drivers/mmc/rockchip_sdhci.c +2
-1+ caps =sdhci_readl (host,SDHCI_CAPABILITIES ); ret = sdhci_setup_cfg(&plat->cfg, dev->name, host->bus_width, - caps, CONFIG_ROCKCHIP_SDHCI_MAX_FREQ, EMMC_MIN_FREQ, + caps, ret, EMMC_MIN_FREQ,
Don't use "ret"..use the meaningful variable for maximum clock.
include/configs/rk3399_common.h line 35
Quoted 13 lines
drivers/mmc/rockchip_sdhci.c +0
-0host->version, host->quirks, 0); host->mmc = &plat->mmc;include/configs/rk3399_common.h +1
-1@@ -32,7 +32,7 @@#define CONFIG_GENERIC_MMC #define CONFIG_SDHCI #define CONFIG_BOUNCE_BUFFER -#define CONFIG_ROCKCHIP_SDHCI_MAX_FREQ 200000000 +#define CONFIG_ROCKCHIP_SDHCI_MAX_FREQ (198*1000000)
Why change from 200MHz to 198MHz?
Best Regards,
Jaehoon Chung
Quoted 4 lines
include/configs/rk3399_common.h +0
-0#define CONFIG_FAT_WRITE
PATCH 2/2 mmc: rockchip: add clock init
Hi Jaehoon Chung,
Thanks for your review comment.
Quoted 33 lines · Jaehoon Chung
Hi Kever,
Quoted 30 lines · Kever Yang
Signed-off-by Kever Yang <[email protected]>---
drivers/mmc/rockchip_sdhci.c | 10 +++++++++- include/configs/rk3399_common.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-)drivers/mmc/rockchip_sdhci.c +2
-0@@ -7,6 +7,7 @@*/ #include <common.h> +#include <clk.h> #include <dm.h> #include <fdtdec.h> #include <libfdt.h> @@ -32,15 +33,22 @@ static int arasan_sdhci_probe(struct udevice *dev)struct rockchip_sdhc_plat *plat =dev_get_platdata (dev);struct rockchip_sdhc *prv =dev_get_priv (dev);struct sdhci_host *host = &prv->host; +struct clk clk;int ret;u32 caps; host->version =sdhci_readw (host,SDHCI_HOST_VERSION ); host->quirks =SDHCI_QUIRK_WAIT_SEND_CMD ;
Quoted 7 lines
drivers/mmc/rockchip_sdhci.c static int arasan_sdhci_probe(struct udevice *dev) · line 47
Quoted 5 lines
drivers/mmc/rockchip_sdhci.c +5
-0+ ret =clk_get_by_index (dev,0 , &clk); +if (ret <0 ) +debug ("%s get clock fail\n" , __func__); + + ret =clk_set_rate (&clk,CONFIG_ROCKCHIP_SDHCI_MAX_FREQ );Even if failed to get the clk,
clk_set_rate()is called...right?
How about using a else branch for get clock return value?
Quoted 6 lines
drivers/mmc/rockchip_sdhci.c static int arasan_sdhci_probe(struct udevice *dev) · line 51
Quoted 5 lines
drivers/mmc/rockchip_sdhci.c +2
-1+ caps =sdhci_readl (host,SDHCI_CAPABILITIES ); ret = sdhci_setup_cfg(&plat->cfg, dev->name, host->bus_width, - caps, CONFIG_ROCKCHIP_SDHCI_MAX_FREQ, EMMC_MIN_FREQ, + caps, ret, EMMC_MIN_FREQ,Don't use "ret"..use the meaningful variable for maximum clock.
OK, will use another variate like max_freq.
Quoted 15 lines
Quoted 9 lines
drivers/mmc/rockchip_sdhci.c +0
-0host->version, host->quirks, 0); host->mmc = &plat->mmc;include/configs/rk3399_common.h +0
-0include/configs/rk3399_common.h line 35
Quoted 5 lines
include/configs/rk3399_common.h +1
-1@@ -32,7 +32,7 @@#define CONFIG_GENERIC_MMC #define CONFIG_SDHCI #define CONFIG_BOUNCE_BUFFER -#define CONFIG_ROCKCHIP_SDHCI_MAX_FREQ 200000000 +#define CONFIG_ROCKCHIP_SDHCI_MAX_FREQ (198*1000000)Why change from 200MHz to 198MHz?
We are using a source for sdhci which clock rate is 594MHz, so we actually get 198MHz in this sdhci driver clk_set_rate().
This change is not a must, but it may help people know the real frequency?
Thanks,
- Kever
Quoted 11 lines
Best Regards,
Jaehoon ChungQuoted 4 lines
include/configs/rk3399_common.h +0
-0#define CONFIG_FAT_WRITE
PATCH 2/2 mmc: rockchip: add clock init
In reply to Kever YangQuoted 6 lines · Kever Yang
Signed-off-by Kever Yang <[email protected]>---
drivers/mmc/rockchip_sdhci.c | 10 +++++++++- include/configs/rk3399_common.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-)