diff options
Diffstat (limited to 'drivers/clk')
| -rw-r--r-- | drivers/clk/Makefile | 20 | ||||
| -rw-r--r-- | drivers/clk/clk-hsdk-cgu.c | 177 | ||||
| -rw-r--r-- | drivers/clk/clk-uclass.c | 22 | ||||
| -rw-r--r-- | drivers/clk/clk_fixed_rate.c | 6 | ||||
| -rw-r--r-- | drivers/clk/clk_stm32f.c | 7 |
5 files changed, 195 insertions, 37 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 876c2b816f1..dab106ab7fc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -6,21 +6,21 @@ # obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o clk_fixed_rate.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 -obj-$(CONFIG_CLK_RENESAS) += renesas/ -obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o -obj-$(CONFIG_CLK_ZYNQMP) += clk_zynqmp.o obj-y += tegra/ -obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ -obj-$(CONFIG_CLK_EXYNOS) += exynos/ +obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o obj-$(CONFIG_CLK_BOSTON) += clk_boston.o +obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o -obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_CLK_RENESAS) += renesas/ obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o +obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ +obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o +obj-$(CONFIG_CLK_ZYNQMP) += clk_zynqmp.o +obj-$(CONFIG_MACH_PIC32) += clk_pic32.o +obj-$(CONFIG_SANDBOX) += clk_sandbox.o +obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o obj-$(CONFIG_STM32H7) += clk_stm32h7.o diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c index c80f90ec2f0..4362d583cb4 100644 --- a/drivers/clk/clk-hsdk-cgu.c +++ b/drivers/clk/clk-hsdk-cgu.c @@ -42,7 +42,9 @@ * |-->| TUNNEL PLL | * | -------------- * | | - * | |-->|CGU_TUN_IDIV|-----------> + * | |-->|CGU_TUN_IDIV_TUN|-----------> + * | |-->|CGU_TUN_IDIV_ROM|-----------> + * | |-->|CGU_TUN_IDIV_PWM|-----------> * | * | ------------ * |-->| HDMI PLL | @@ -60,7 +62,9 @@ DECLARE_GLOBAL_DATA_PTR; #define CGU_ARC_IDIV 0x080 -#define CGU_TUN_IDIV 0x380 +#define CGU_TUN_IDIV_TUN 0x380 +#define CGU_TUN_IDIV_ROM 0x390 +#define CGU_TUN_IDIV_PWM 0x3A0 #define CGU_HDMI_IDIV_APB 0x480 #define CGU_SYS_IDIV_APB 0x180 #define CGU_SYS_IDIV_AXI 0x190 @@ -114,8 +118,68 @@ DECLARE_GLOBAL_DATA_PTR; #define CREG_CORE_IF_CLK_DIV_1 0x0 #define CREG_CORE_IF_CLK_DIV_2 0x1 +#define MIN_PLL_RATE 100000000 /* 100 MHz */ #define PARENT_RATE 33333333 /* fixed clock - xtal */ -#define CGU_MAX_CLOCKS 24 +#define CGU_MAX_CLOCKS 26 + +#define CGU_SYS_CLOCKS 16 +#define MAX_AXI_CLOCKS 4 + +#define CGU_TUN_CLOCKS 3 +#define MAX_TUN_CLOCKS 6 + +struct hsdk_tun_idiv_cfg { + u32 oft; + u8 val[MAX_TUN_CLOCKS]; +}; + +struct hsdk_tun_clk_cfg { + const u32 clk_rate[MAX_TUN_CLOCKS]; + const u32 pll_rate[MAX_TUN_CLOCKS]; + const struct hsdk_tun_idiv_cfg idiv[CGU_TUN_CLOCKS]; +}; + +static const struct hsdk_tun_clk_cfg tun_clk_cfg = { + { 25000000, 50000000, 75000000, 100000000, 125000000, 150000000 }, + { 600000000, 600000000, 600000000, 600000000, 700000000, 600000000 }, { + { CGU_TUN_IDIV_TUN, { 24, 12, 8, 6, 6, 4 } }, + { CGU_TUN_IDIV_ROM, { 4, 4, 4, 4, 5, 4 } }, + { CGU_TUN_IDIV_PWM, { 8, 8, 8, 8, 10, 8 } } + } +}; + +struct hsdk_sys_idiv_cfg { + u32 oft; + u8 val[MAX_AXI_CLOCKS]; +}; + +struct hsdk_axi_clk_cfg { + const u32 clk_rate[MAX_AXI_CLOCKS]; + const u32 pll_rate[MAX_AXI_CLOCKS]; + const struct hsdk_sys_idiv_cfg idiv[CGU_SYS_CLOCKS]; +}; + +static const struct hsdk_axi_clk_cfg axi_clk_cfg = { + { 200000000, 400000000, 600000000, 800000000 }, + { 800000000, 800000000, 600000000, 800000000 }, { + { CGU_SYS_IDIV_APB, { 4, 4, 3, 4 } }, /* APB */ + { CGU_SYS_IDIV_AXI, { 4, 2, 1, 1 } }, /* AXI */ + { CGU_SYS_IDIV_ETH, { 2, 2, 2, 2 } }, /* ETH */ + { CGU_SYS_IDIV_USB, { 2, 2, 2, 2 } }, /* USB */ + { CGU_SYS_IDIV_SDIO, { 2, 2, 2, 2 } }, /* SDIO */ + { CGU_SYS_IDIV_HDMI, { 2, 2, 2, 2 } }, /* HDMI */ + { CGU_SYS_IDIV_GFX_CORE, { 1, 1, 1, 1 } }, /* GPU-CORE */ + { CGU_SYS_IDIV_GFX_DMA, { 2, 2, 2, 2 } }, /* GPU-DMA */ + { CGU_SYS_IDIV_GFX_CFG, { 4, 4, 3, 4 } }, /* GPU-CFG */ + { CGU_SYS_IDIV_DMAC_CORE,{ 2, 2, 2, 2 } }, /* DMAC-CORE */ + { CGU_SYS_IDIV_DMAC_CFG, { 4, 4, 3, 4 } }, /* DMAC-CFG */ + { CGU_SYS_IDIV_SDIO_REF, { 8, 8, 6, 8 } }, /* SDIO-REF */ + { CGU_SYS_IDIV_SPI_REF, { 24, 24, 18, 24 } }, /* SPI-REF */ + { CGU_SYS_IDIV_I2C_REF, { 4, 4, 3, 4 } }, /* I2C-REF */ + { CGU_SYS_IDIV_UART_REF, { 24, 24, 18, 24 } }, /* UART-REF */ + { CGU_SYS_IDIV_EBI_REF, { 16, 16, 12, 16 } } /* EBI-REF */ + } +}; struct hsdk_pll_cfg { u32 rate; @@ -201,6 +265,9 @@ static const struct hsdk_pll_devdata hdmi_pll_dat = { }; static ulong idiv_set(struct clk *, ulong); +static ulong cpu_clk_set(struct clk *, ulong); +static ulong axi_clk_set(struct clk *, ulong); +static ulong tun_clk_set(struct clk *, ulong); static ulong idiv_get(struct clk *); static int idiv_off(struct clk *); static ulong pll_set(struct clk *, ulong); @@ -218,11 +285,11 @@ struct hsdk_cgu_clock_map { static const struct hsdk_cgu_clock_map clock_map[] = { { CGU_ARC_PLL, 0, 0, &core_pll_dat, pll_get, pll_set, NULL }, - { CGU_ARC_PLL, 0, CGU_ARC_IDIV, &core_pll_dat, idiv_get, idiv_set, idiv_off }, + { CGU_ARC_PLL, 0, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off }, { CGU_DDR_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL }, { CGU_SYS_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL }, { CGU_SYS_PLL, 0, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, - { CGU_SYS_PLL, 0, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, + { CGU_SYS_PLL, 0, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off }, { CGU_SYS_PLL, 0, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, { CGU_SYS_PLL, 0, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, @@ -238,7 +305,9 @@ static const struct hsdk_cgu_clock_map clock_map[] = { { CGU_SYS_PLL, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, { CGU_SYS_PLL, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, { CGU_TUN_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL }, - { CGU_TUN_PLL, 0, CGU_TUN_IDIV, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, + { CGU_TUN_PLL, 0, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off }, + { CGU_TUN_PLL, 0, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, + { CGU_TUN_PLL, 0, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, { CGU_HDMI_PLL, 0, 0, &hdmi_pll_dat, pll_get, pll_set, NULL }, { CGU_HDMI_PLL, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off } }; @@ -423,7 +492,7 @@ static ulong pll_set(struct clk *sclk, ulong rate) } } - pr_err("invalid rate=%ld, parent_rate=%d\n", best_rate, PARENT_RATE); + pr_err("invalid rate=%ld Hz, parent_rate=%d Hz\n", best_rate, PARENT_RATE); return -EINVAL; } @@ -453,6 +522,94 @@ static ulong idiv_get(struct clk *sclk) return parent_rate / div_factor; } +/* Special behavior: wen we set this clock we set both idiv and pll */ +static ulong cpu_clk_set(struct clk *sclk, ulong rate) +{ + ulong ret; + + ret = pll_set(sclk, rate); + idiv_set(sclk, rate); + + return ret; +} + +/* Special behavior: wen we set this clock we set both idiv and pll and all pll dividers */ +static ulong axi_clk_set(struct clk *sclk, ulong rate) +{ + struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); + ulong pll_rate; + int i, freq_idx = -1; + ulong ret = 0; + + pll_rate = pll_get(sclk); + + for (i = 0; i < MAX_AXI_CLOCKS; i++) { + if (axi_clk_cfg.clk_rate[i] == rate) { + freq_idx = i; + break; + } + } + + if (freq_idx < 0) { + pr_err("axi clk: invalid rate=%ld Hz\n", rate); + return -EINVAL; + } + + /* configure PLL before dividers */ + if (axi_clk_cfg.pll_rate[freq_idx] < pll_rate) + ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]); + + /* configure SYS dividers */ + for (i = 0; i < CGU_SYS_CLOCKS; i++) { + clk->idiv_regs = clk->cgu_regs + axi_clk_cfg.idiv[i].oft; + hsdk_idiv_write(clk, axi_clk_cfg.idiv[i].val[freq_idx]); + } + + /* configure PLL after dividers */ + if (axi_clk_cfg.pll_rate[freq_idx] >= pll_rate) + ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]); + + return ret; +} + +static ulong tun_clk_set(struct clk *sclk, ulong rate) +{ + struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); + ulong pll_rate; + int i, freq_idx = -1; + ulong ret = 0; + + pll_rate = pll_get(sclk); + + for (i = 0; i < MAX_TUN_CLOCKS; i++) { + if (tun_clk_cfg.clk_rate[i] == rate) { + freq_idx = i; + break; + } + } + + if (freq_idx < 0) { + pr_err("tun clk: invalid rate=%ld Hz\n", rate); + return -EINVAL; + } + + /* configure PLL before dividers */ + if (tun_clk_cfg.pll_rate[freq_idx] < pll_rate) + ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]); + + /* configure SYS dividers */ + for (i = 0; i < CGU_TUN_CLOCKS; i++) { + clk->idiv_regs = clk->cgu_regs + tun_clk_cfg.idiv[i].oft; + hsdk_idiv_write(clk, tun_clk_cfg.idiv[i].val[freq_idx]); + } + + /* configure PLL after dividers */ + if (tun_clk_cfg.pll_rate[freq_idx] >= pll_rate) + ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]); + + return ret; +} + static ulong idiv_set(struct clk *sclk, ulong rate) { struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); @@ -466,14 +623,14 @@ static ulong idiv_set(struct clk *sclk, ulong rate) } if (div_factor & ~CGU_IDIV_MASK) { - pr_err("invalid rate=%ld, parent_rate=%ld, div=%d: max divider valie is%d\n", + pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: max divider valie is%d\n", rate, parent_rate, div_factor, CGU_IDIV_MASK); div_factor = CGU_IDIV_MASK; } if (div_factor == 0) { - pr_err("invalid rate=%ld, parent_rate=%ld, div=%d: min divider valie is 1\n", + pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: min divider valie is 1\n", rate, parent_rate, div_factor); div_factor = 1; @@ -559,6 +716,6 @@ U_BOOT_DRIVER(hsdk_cgu_clk) = { .id = UCLASS_CLK, .of_match = hsdk_cgu_clk_id, .probe = hsdk_cgu_clk_probe, - .platdata_auto_alloc_size = sizeof(struct hsdk_cgu_clk), + .priv_auto_alloc_size = sizeof(struct hsdk_cgu_clk), .ops = &hsdk_cgu_ops, }; diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 83ba13374c7..fbea72091b1 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -13,11 +13,9 @@ #include <dt-structs.h> #include <errno.h> -DECLARE_GLOBAL_DATA_PTR; - -static inline struct clk_ops *clk_dev_ops(struct udevice *dev) +static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) { - return (struct clk_ops *)dev->driver->ops; + return (const struct clk_ops *)dev->driver->ops; } #if CONFIG_IS_ENABLED(OF_CONTROL) @@ -60,7 +58,7 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) int ret; struct ofnode_phandle_args args; struct udevice *dev_clk; - struct clk_ops *ops; + const struct clk_ops *ops; debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk); @@ -68,7 +66,7 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) clk->dev = NULL; ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0, - index, &args); + index, &args); if (ret) { debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", __func__, ret); @@ -142,7 +140,7 @@ int clk_release_all(struct clk *clk, int count) int clk_request(struct udevice *dev, struct clk *clk) { - struct clk_ops *ops = clk_dev_ops(dev); + const struct clk_ops *ops = clk_dev_ops(dev); debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk); @@ -156,7 +154,7 @@ int clk_request(struct udevice *dev, struct clk *clk) int clk_free(struct clk *clk) { - struct clk_ops *ops = clk_dev_ops(clk->dev); + const struct clk_ops *ops = clk_dev_ops(clk->dev); debug("%s(clk=%p)\n", __func__, clk); @@ -168,7 +166,7 @@ int clk_free(struct clk *clk) ulong clk_get_rate(struct clk *clk) { - struct clk_ops *ops = clk_dev_ops(clk->dev); + const struct clk_ops *ops = clk_dev_ops(clk->dev); debug("%s(clk=%p)\n", __func__, clk); @@ -180,7 +178,7 @@ ulong clk_get_rate(struct clk *clk) ulong clk_set_rate(struct clk *clk, ulong rate) { - struct clk_ops *ops = clk_dev_ops(clk->dev); + const struct clk_ops *ops = clk_dev_ops(clk->dev); debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate); @@ -192,7 +190,7 @@ ulong clk_set_rate(struct clk *clk, ulong rate) int clk_enable(struct clk *clk) { - struct clk_ops *ops = clk_dev_ops(clk->dev); + const struct clk_ops *ops = clk_dev_ops(clk->dev); debug("%s(clk=%p)\n", __func__, clk); @@ -204,7 +202,7 @@ int clk_enable(struct clk *clk) int clk_disable(struct clk *clk) { - struct clk_ops *ops = clk_dev_ops(clk->dev); + const struct clk_ops *ops = clk_dev_ops(clk->dev); debug("%s(clk=%p)\n", __func__, clk); diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 63565b6ed8d..c9a9f0a20b6 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -8,8 +8,6 @@ #include <clk-uclass.h> #include <dm.h> -DECLARE_GLOBAL_DATA_PTR; - struct clk_fixed_rate { unsigned long fixed_rate; }; @@ -31,8 +29,8 @@ const struct clk_ops clk_fixed_rate_ops = { static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev) { #if !CONFIG_IS_ENABLED(OF_PLATDATA) - to_clk_fixed_rate(dev)->fixed_rate = dev_read_u32_default(dev, - "clock-frequency", 0); + to_clk_fixed_rate(dev)->fixed_rate = + dev_read_u32_default(dev, "clock-frequency", 0); #endif return 0; diff --git a/drivers/clk/clk_stm32f.c b/drivers/clk/clk_stm32f.c index 634f0717c68..63116e0bac3 100644 --- a/drivers/clk/clk_stm32f.c +++ b/drivers/clk/clk_stm32f.c @@ -12,7 +12,6 @@ #include <asm/io.h> #include <asm/arch/stm32.h> -#include <asm/arch/stm32_periph.h> #include <asm/arch/stm32_pwr.h> #include <dt-bindings/mfd/stm32f7-rcc.h> @@ -88,6 +87,12 @@ */ #define RCC_APB2ENR_SYSCFGEN BIT(14) +enum periph_clock { + SYSCFG_CLOCK_CFG, + TIMER2_CLOCK_CFG, + STMMAC_CLOCK_CFG, +}; + struct stm32_clk_info stm32f4_clk_info = { /* 180 MHz */ .sys_pll_psc = { |
