diff options
| author | Tom Rini <[email protected]> | 2026-07-06 18:26:12 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-07-06 18:26:12 -0600 |
| commit | ee5d46b45ec0c63f8f9dd1e816e0dac3452ccc3d (patch) | |
| tree | 800cd9e204ca027144070101884c0d5d3c00130f /drivers/clk | |
| parent | ece349ade2973e220f524ce59e59711cc919263f (diff) | |
| parent | a18265f1ccb7a272721ed4286ed3b5a6182ff424 (diff) | |
Merge branch 'next'
Diffstat (limited to 'drivers/clk')
29 files changed, 1737 insertions, 77 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c2da7b3938b..addcece4da3 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -134,8 +134,8 @@ config CLK_CDCE9XX bool "Enable CDCD9XX clock driver" depends on CLK && ARCH_OMAP2PLUS help - Enable the clock synthesizer driver for CDCE913/925/937/949 - series of chips. + Enable the clock synthesizer driver for CDCE913/925/937/949 + series of chips. config CLK_ICS8N3QV01 bool "Enable ICS8N3QV01 VCXO driver" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5f0c0d8a5c2..c37ef75d420 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_$(PHASE_)CLK_STUB) += clk-stub.o obj-y += adi/ obj-y += airoha/ obj-y += analogbits/ -obj-y += imx/ +obj-$(CONFIG_MACH_IMX) += imx/ obj-$(CONFIG_CLK_JH7110) += starfive/ obj-y += tegra/ obj-y += ti/ diff --git a/drivers/clk/altera/clk-mem-n5x.c b/drivers/clk/altera/clk-mem-n5x.c index ac59571a853..149e3016dd3 100644 --- a/drivers/clk/altera/clk-mem-n5x.c +++ b/drivers/clk/altera/clk-mem-n5x.c @@ -103,12 +103,13 @@ static int socfpga_mem_clk_enable(struct clk *clk) static int socfpga_mem_clk_of_to_plat(struct udevice *dev) { struct socfpga_mem_clk_plat *plat = dev_get_plat(dev); - fdt_addr_t addr; + void __iomem *addr; - addr = devfdt_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) + addr = dev_read_addr_ptr(dev); + if (!addr) return -EINVAL; - plat->regs = (void __iomem *)addr; + + plat->regs = addr; return 0; } diff --git a/drivers/clk/altera/clk-n5x.c b/drivers/clk/altera/clk-n5x.c index 185c9028a78..0a3bae38589 100644 --- a/drivers/clk/altera/clk-n5x.c +++ b/drivers/clk/altera/clk-n5x.c @@ -454,12 +454,12 @@ static int socfpga_clk_probe(struct udevice *dev) static int socfpga_clk_of_to_plat(struct udevice *dev) { struct socfpga_clk_plat *plat = dev_get_plat(dev); - fdt_addr_t addr; + void __iomem *addr; - addr = devfdt_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) + addr = dev_read_addr_ptr(dev); + if (!addr) return -EINVAL; - plat->regs = (void __iomem *)addr; + plat->regs = addr; return 0; } diff --git a/drivers/clk/aspeed/Makefile b/drivers/clk/aspeed/Makefile index 84776e5265e..285180b67cf 100644 --- a/drivers/clk/aspeed/Makefile +++ b/drivers/clk/aspeed/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_ASPEED_AST2500) += clk_ast2500.o obj-$(CONFIG_ASPEED_AST2600) += clk_ast2600.o +obj-$(CONFIG_ASPEED_AST2700) += clk_ast2700.o diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index a330dcda4dc..94c7f662319 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -534,7 +534,7 @@ static int ast2500_clk_enable(struct clk *clk) return 0; } -struct clk_ops ast2500_clk_ops = { +static const struct clk_ops ast2500_clk_ops = { .get_rate = ast2500_clk_get_rate, .set_rate = ast2500_clk_set_rate, .enable = ast2500_clk_enable, @@ -544,9 +544,9 @@ static int ast2500_clk_of_to_plat(struct udevice *dev) { struct ast2500_clk_priv *priv = dev_get_priv(dev); - priv->scu = devfdt_get_addr_ptr(dev); - if (IS_ERR(priv->scu)) - return PTR_ERR(priv->scu); + priv->scu = dev_read_addr_ptr(dev); + if (!priv->scu) + return -EINVAL; return 0; } diff --git a/drivers/clk/aspeed/clk_ast2600.c b/drivers/clk/aspeed/clk_ast2600.c index 535010b7941..74209e947ed 100644 --- a/drivers/clk/aspeed/clk_ast2600.c +++ b/drivers/clk/aspeed/clk_ast2600.c @@ -1161,7 +1161,7 @@ static void ast2600_clk_dump(struct udevice *dev) } #endif -struct clk_ops ast2600_clk_ops = { +static const struct clk_ops ast2600_clk_ops = { .get_rate = ast2600_clk_get_rate, .set_rate = ast2600_clk_set_rate, .enable = ast2600_clk_enable, @@ -1174,9 +1174,9 @@ static int ast2600_clk_probe(struct udevice *dev) { struct ast2600_clk_priv *priv = dev_get_priv(dev); - priv->scu = devfdt_get_addr_ptr(dev); - if (IS_ERR(priv->scu)) - return PTR_ERR(priv->scu); + priv->scu = dev_read_addr_ptr(dev); + if (!priv->scu) + return -EINVAL; ast2600_init_rgmii_clk(priv->scu, &rgmii_clk_defconfig); ast2600_init_rmii_clk(priv->scu, &rmii_clk_defconfig); diff --git a/drivers/clk/aspeed/clk_ast2700.c b/drivers/clk/aspeed/clk_ast2700.c new file mode 100644 index 00000000000..ca76abef48f --- /dev/null +++ b/drivers/clk/aspeed/clk_ast2700.c @@ -0,0 +1,952 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. + */ + +#include <asm/io.h> +#include <asm/arch/scu_ast2700.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <syscon.h> +#include <linux/bitfield.h> + +#include <dt-bindings/clock/aspeed,ast2700-scu.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * RGMII clock source tree + * HPLL -->|\ + * | |---->| divider |---->RGMII 125M for MAC#0 & MAC#1 + * APLL -->|/ + */ +#define RGMII_DEFAULT_CLK_SRC SCU1_CLK_HPLL + +struct mac_delay_config { + u32 tx_delay_1000; + u32 rx_delay_1000; + u32 tx_delay_100; + u32 rx_delay_100; + u32 tx_delay_10; + u32 rx_delay_10; +}; + +typedef int (*ast2700_clk_init_fn)(struct udevice *dev); + +struct ast2700_clk_priv { + void __iomem *reg; + ast2700_clk_init_fn init; +}; + +static u32 ast2700_soc1_get_pll_rate(struct ast2700_scu1 *scu, int pll_idx) +{ + union ast2700_pll_reg pll_reg; + u32 mul = 1, div = 1; + + switch (pll_idx) { + case SCU1_CLK_HPLL: + pll_reg.w = readl(&scu->hpll); + break; + case SCU1_CLK_APLL: + pll_reg.w = readl(&scu->apll); + break; + case SCU1_CLK_DPLL: + pll_reg.w = readl(&scu->dpll); + break; + } + + if (!pll_reg.b.bypass) { + mul = (pll_reg.b.m + 1) / (pll_reg.b.n + 1); + div = (pll_reg.b.p + 1); + } + + return ((CLKIN_25M * mul) / div); +} + +#define SCU_CLKSEL2_HCLK_DIV_MASK GENMASK(22, 20) +#define SCU_CLKSEL2_HCLK_DIV_SHIFT 20 + +static u32 ast2700_soc1_get_hclk_rate(struct ast2700_scu1 *scu) +{ + u32 rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 clk_sel2 = readl(&scu->clk_sel2); + u32 hclk_div = (clk_sel2 & SCU_CLKSEL2_HCLK_DIV_MASK) >> + SCU_CLKSEL2_HCLK_DIV_SHIFT; + + if (!hclk_div) + hclk_div = 2; + else + hclk_div++; + + return (rate / hclk_div); +} + +#define SCU1_CLKSEL1_PCLK_DIV_MASK GENMASK(20, 18) +#define SCU1_CLKSEL1_PCLK_DIV_SHIFT 18 + +static u32 ast2700_soc1_get_pclk_rate(struct ast2700_scu1 *scu) +{ + u32 rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + + u32 clk_sel1 = readl(&scu->clk_sel1); + u32 pclk_div = (clk_sel1 & SCU1_CLKSEL1_PCLK_DIV_MASK) >> + SCU1_CLKSEL1_PCLK_DIV_SHIFT; + + return (rate / ((pclk_div + 1) * 2)); +} + +#define SCU_UART_CLKGEN_N_MASK GENMASK(17, 8) +#define SCU_UART_CLKGEN_N_SHIFT 8 +#define SCU_UART_CLKGEN_R_MASK GENMASK(7, 0) +#define SCU_UART_CLKGEN_R_SHIFT 0 + +static u32 ast2700_soc1_get_uart_uxclk_rate(struct ast2700_scu1 *scu) +{ + u32 uxclk_sel = readl(&scu->clk_sel2) & GENMASK(1, 0); + u32 uxclk_ctrl = readl(&scu->uxclk_ctrl); + u32 rate; + + switch (uxclk_sel) { + case 0: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 4; + break; + case 1: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 2; + break; + case 2: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL); + break; + case 3: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + break; + } + + u32 n = (uxclk_ctrl & SCU_UART_CLKGEN_N_MASK) >> + SCU_UART_CLKGEN_N_SHIFT; + u32 r = (uxclk_ctrl & SCU_UART_CLKGEN_R_MASK) >> + SCU_UART_CLKGEN_R_SHIFT; + + return ((rate * r) / (n * 2)); +} + +#define SCU_HUART_CLKGEN_N_MASK GENMASK(17, 8) +#define SCU_HUART_CLKGEN_N_SHIFT 8 +#define SCU_HUART_CLKGEN_R_MASK GENMASK(7, 0) +#define SCU_HUART_CLKGEN_R_SHIFT 0 + +static u32 ast2700_soc1_get_uart_huxclk_rate(struct ast2700_scu1 *scu) +{ + u32 huxclk_sel = (readl(&scu->clk_sel2) & GENMASK(4, 3)) >> 3; + u32 huxclk_ctrl = readl(&scu->huxclk_ctrl); + u32 n = (huxclk_ctrl & SCU_HUART_CLKGEN_N_MASK) >> + SCU_HUART_CLKGEN_N_SHIFT; + u32 r = (huxclk_ctrl & SCU_HUART_CLKGEN_R_MASK) >> + SCU_HUART_CLKGEN_R_SHIFT; + u32 rate; + + switch (huxclk_sel) { + case 0: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 4; + break; + case 1: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 2; + break; + case 2: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL); + break; + case 3: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + break; + } + + return ((rate * r) / (n * 2)); +} + +#define SCU_CLKSRC1_SDIO_DIV_MASK GENMASK(16, 14) +#define SCU_CLKSRC1_SDIO_DIV_SHIFT 14 +#define SCU_CLKSRC1_SDIO_SEL BIT(13) +const int ast2700_sd_div_tbl[] = { + 2, 2, 3, 4, 5, 6, 7, 8 +}; + +static u32 ast2700_soc1_get_sdio_clk_rate(struct ast2700_scu1 *scu) +{ + u32 rate = 0; + u32 clk_sel1 = readl(&scu->clk_sel1); + u32 div = (clk_sel1 & SCU_CLKSRC1_SDIO_DIV_MASK) >> + SCU_CLKSRC1_SDIO_DIV_SHIFT; + + if (clk_sel1 & SCU_CLKSRC1_SDIO_SEL) + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL); + else + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + + if (!div) + div = 1; + + div++; + + return (rate / div); +} + +static void ast2700_init_sdclk(struct ast2700_scu1 *scu) +{ + u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 reg_280; + int i; + + for (i = 0; i < 8; i++) { + if (src_clk / ast2700_sd_div_tbl[i] <= 125000000) + break; + } + + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~(SCU_CLKSRC1_SDIO_DIV_MASK | SCU_CLKSRC1_SDIO_SEL); + reg_280 |= i << SCU_CLKSRC1_SDIO_DIV_SHIFT; + writel(reg_280, &scu->clk_sel1); +} + +static u32 +ast2700_soc1_get_uart_clk_rate(struct ast2700_scu1 *scu, int uart_idx) +{ + u32 rate = 0; + + if (readl(&scu->clk_sel1) & BIT(uart_idx)) + rate = ast2700_soc1_get_uart_huxclk_rate(scu); + else + rate = ast2700_soc1_get_uart_uxclk_rate(scu); + + return rate; +} + +static ulong ast2700_soc1_clk_get_rate(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg; + ulong rate = 0; + + switch (clk->id) { + case SCU1_CLK_HPLL: + case SCU1_CLK_APLL: + case SCU1_CLK_DPLL: + rate = ast2700_soc1_get_pll_rate(scu, clk->id); + break; + case SCU1_CLK_AHB: + rate = ast2700_soc1_get_hclk_rate(scu); + break; + case SCU1_CLK_APB: + rate = ast2700_soc1_get_pclk_rate(scu); + break; + case SCU1_CLK_GATE_UART0CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 0); + break; + case SCU1_CLK_GATE_UART1CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 1); + break; + case SCU1_CLK_GATE_UART2CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 2); + break; + case SCU1_CLK_GATE_UART3CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 3); + break; + case SCU1_CLK_GATE_UART5CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 5); + break; + case SCU1_CLK_GATE_UART6CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 6); + break; + case SCU1_CLK_GATE_UART7CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 7); + break; + case SCU1_CLK_GATE_UART8CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 8); + break; + case SCU1_CLK_GATE_UART9CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 9); + break; + case SCU1_CLK_GATE_UART10CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 10); + break; + case SCU1_CLK_GATE_UART11CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 11); + break; + case SCU1_CLK_GATE_UART12CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 12); + break; + case SCU1_CLK_GATE_SDCLK: + rate = ast2700_soc1_get_sdio_clk_rate(scu); + break; + case SCU1_CLK_UXCLK: + rate = ast2700_soc1_get_uart_uxclk_rate(scu); + break; + case SCU1_CLK_HUXCLK: + rate = ast2700_soc1_get_uart_huxclk_rate(scu); + break; + default: + debug("%s: unknown clk %ld\n", __func__, clk->id); + return -ENOENT; + } + + return rate; +} + +static int ast2700_soc1_clk_enable(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg; + u32 clkgate_bit; + + if (clk->id >= 32) + clkgate_bit = BIT(clk->id - 32); + else + clkgate_bit = BIT(clk->id); + + writel(clkgate_bit, &scu->clkgate_clr1); + + return 0; +} + +static const struct clk_ops ast2700_soc1_clk_ops = { + .get_rate = ast2700_soc1_clk_get_rate, + .enable = ast2700_soc1_clk_enable, +}; + +#define SCU_HW_REVISION_ID GENMASK(23, 16) +#define SCU_CPUCLK_MASK GENMASK(4, 2) +#define SCU_CPUCLK_SHIFT 2 +static u32 ast2700_soc0_get_hpll_rate(struct ast2700_scu0 *scu) +{ + u32 chip_id1 = readl(&scu->chip_id1); + u32 hwstrap1 = readl(&scu->hwstrap1); + union ast2700_pll_reg pll_reg; + u32 mul = 1, div = 1; + u32 rate; + + pll_reg.w = readl(&scu->hpll); + + if ((chip_id1 & SCU_HW_REVISION_ID) && (hwstrap1 & BIT(3))) { + switch ((hwstrap1 & GENMASK(4, 2)) >> 2) { + case 2: + rate = 1800000000; + break; + case 3: + rate = 1700000000; + break; + case 6: + rate = 1200000000; + break; + case 7: + rate = 800000000; + break; + default: + rate = 1600000000; + } + } else if (hwstrap1 & GENMASK(3, 2)) { + switch ((hwstrap1 & GENMASK(3, 2)) >> 2) { + case 1U: + rate = 1900000000; + break; + case 2U: + rate = 1800000000; + break; + case 3U: + rate = 1700000000; + break; + default: + rate = 1600000000; + break; + } + } else { + if (pll_reg.b.bypass == 0U) { + /* F = 25Mhz * [(M + 2) / 2 * (n + 1)] / (p + 1) */ + mul = (pll_reg.b.m + 1) / ((pll_reg.b.n + 1) * 2); + div = (pll_reg.b.p + 1); + } + rate = ((CLKIN_25M * mul) / div); + } + + return rate; +} + +static u32 ast2700_soc0_get_pll_rate(struct ast2700_scu0 *scu, int pll_idx) +{ + union ast2700_pll_reg pll_reg; + u32 mul = 1, div = 1; + u32 rate; + + switch (pll_idx) { + case SCU0_CLK_DPLL: + pll_reg.w = readl(&scu->dpll); + break; + case SCU0_CLK_MPLL: + pll_reg.w = readl(&scu->mpll); + break; + default: + pr_err("%s: invalid PSP clock source (%d)\n", __func__, pll_idx); + return 0; + } + + if (pll_reg.b.bypass == 0U) { + if (pll_idx == SCU0_CLK_MPLL) { + /* F = 25Mhz * [M / (n + 1)] / (p + 1) */ + mul = (pll_reg.b.m) / ((pll_reg.b.n + 1)); + div = (pll_reg.b.p + 1); + } else { + /* F = 25Mhz * [(M + 2) / 2 * (n + 1)] / (p + 1) */ + mul = (pll_reg.b.m + 1) / ((pll_reg.b.n + 1) * 2); + div = (pll_reg.b.p + 1); + } + } + + rate = ((CLKIN_25M * mul) / div); + + return rate; +} + +/* + * AST2700A1 + * SCU010[4:2]: + * 000: CPUCLK=MPLL=1.6GHz (MPLL default setting with SCU310, SCU314) + * 001: CPUCLK=HPLL=2.0GHz (HPLL default setting with SCU300, SCU304) + * 010: CPUCLK=HPLL=1.8GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + * 011: CPUCLK=HPLL=1.7GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + * 100: CPUCLK=MPLL/2=800MHz (MPLL default setting with SCU310, SCU314) + * 101: CPUCLK=HPLL/2=1.0GHz (HPLL default setting with SCU300, SCU304) + * 110: CPUCLK=HPLL=1.2GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + * 111: CPUCLK=HPLL=800MHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + */ + +static u32 ast2700_soc0_get_pspclk_rate(struct ast2700_scu0 *scu) +{ + u32 chip_id1 = readl(&scu->chip_id1); + u32 hwstrap1 = readl(&scu->hwstrap1); + u32 rate; + int cpuclk_set; + + if (chip_id1 & SCU_HW_REVISION_ID) { + cpuclk_set = (hwstrap1 & SCU_CPUCLK_MASK) >> SCU_CPUCLK_SHIFT; + switch (cpuclk_set) { + case 0: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + break; + case 1: + case 2: + case 3: + case 6: + case 7: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + case 4: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 2; + break; + case 5: + rate = ast2700_soc0_get_hpll_rate(scu) / 2; + break; + default: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + } + } else { + if (hwstrap1 & BIT(4)) + rate = ast2700_soc0_get_hpll_rate(scu); + else + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + } + return rate; +} + +static u32 ast2700_soc0_get_axi0clk_rate(struct ast2700_scu0 *scu) +{ + return ast2700_soc0_get_pspclk_rate(scu) / 2; +} + +#define SCU_AHB_DIV_MASK GENMASK(6, 5) +#define SCU_AHB_DIV_SHIFT 5 +static u32 hclk_ast2700a1_div_table[] = { + 6, 5, 4, 7, +}; + +static u32 ast2700_soc0_get_hclk_rate(struct ast2700_scu0 *scu) +{ + u32 hwstrap1 = readl(&scu->hwstrap1); + u32 chip_id1 = readl(&scu->chip_id1); + u32 src_clk; + int div; + + if (chip_id1 & SCU_HW_REVISION_ID) { + if (hwstrap1 & BIT(7)) + src_clk = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + else + src_clk = ast2700_soc0_get_hpll_rate(scu); + + div = (hwstrap1 & SCU_AHB_DIV_MASK) >> SCU_AHB_DIV_SHIFT; + div = hclk_ast2700a1_div_table[div]; + } else { + if (hwstrap1 & BIT(7)) + src_clk = ast2700_soc0_get_hpll_rate(scu); + else + src_clk = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + + div = (hwstrap1 & SCU_AHB_DIV_MASK) >> SCU_AHB_DIV_SHIFT; + + if (!div) + div = 4; + else + div = (div + 1) * 2; + } + return (src_clk / div); +} + +static u32 ast2700_soc0_get_axi1clk_rate(struct ast2700_scu0 *scu) +{ + if (readl(&scu->chip_id1) & SCU_HW_REVISION_ID) + return ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4; + else + return ast2700_soc0_get_hclk_rate(scu); +} + +#define SCU0_CLKSEL1_PCLK_DIV_MASK GENMASK(25, 23) +#define SCU0_CLKSEL1_PCLK_DIV_SHIFT 23 + +static u32 ast2700_soc0_get_pclk_rate(struct ast2700_scu0 *scu) +{ + u32 rate = ast2700_soc0_get_axi0clk_rate(scu); + u32 clksel1 = readl(&scu->clk_sel1); + int div; + + div = (clksel1 & SCU0_CLKSEL1_PCLK_DIV_MASK) >> + SCU0_CLKSEL1_PCLK_DIV_SHIFT; + + return (rate / ((div + 1) * 2)); +} + +#define SCU_CLKSEL1_MPHYCLK_SEL_MASK GENMASK(19, 18) +#define SCU_CLKSEL1_MPHYCLK_SEL_SHIFT 18 +#define SCU_CLKSEL1_MPHYCLK_DIV_MASK GENMASK(7, 0) +static u32 ast2700_soc0_get_mphyclk_rate(struct ast2700_scu0 *scu) +{ + int div = readl(&scu->mphyclk_para) & SCU_CLKSEL1_MPHYCLK_DIV_MASK; + u32 chip_id1 = readl(&scu->chip_id1); + u32 clk_sel2; + int clk_sel; + u32 rate = 0; + + if (chip_id1 & SCU_HW_REVISION_ID) { + clk_sel2 = readl(&scu->clk_sel2); + clk_sel = (clk_sel2 & SCU_CLKSEL1_MPHYCLK_SEL_MASK) + >> SCU_CLKSEL1_MPHYCLK_SEL_SHIFT; + switch (clk_sel) { + case 0: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + break; + case 1: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + case 2: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_DPLL); + break; + case 3: + rate = 26000000; + break; + } + } else { + rate = ast2700_soc0_get_hpll_rate(scu); + } + + return (rate / (div + 1)); +} + +static void ast2700_mphy_clk_init(struct ast2700_scu0 *scu) +{ + u32 clksrc1, rate = 0; + int i; + + /* set mphy clk */ + if (readl(&scu->chip_id1) & SCU_HW_REVISION_ID) { + clksrc1 = (readl(&scu->clk_sel2) & SCU_CLKSEL1_MPHYCLK_SEL_MASK) + >> SCU_CLKSEL1_MPHYCLK_SEL_SHIFT; + switch (clksrc1) { + case 0: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + break; + case 1: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + case 2: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_DPLL); + break; + case 3: + rate = 26000000; + break; + } + } else { + rate = ast2700_soc0_get_hpll_rate(scu); + } + + for (i = 1; i < 256; i++) { + if ((rate / i) <= 26000000) + break; + } + + /* register defined the value plus 1 is divider*/ + i--; + writel(i, &scu->mphyclk_para); +} + +#define SCU_CLKSRC1_EMMC_DIV_MASK GENMASK(14, 12) +#define SCU_CLKSRC1_EMMC_DIV_SHIFT 12 +#define SCU_CLKSRC1_EMMC_SEL BIT(11) +static u32 ast2700_soc0_get_emmcclk_rate(struct ast2700_scu0 *scu) +{ + u32 clksel1 = readl(&scu->clk_sel1); + u32 rate; + int div; + + div = (clksel1 & SCU_CLKSRC1_EMMC_DIV_MASK) >> SCU_CLKSRC1_EMMC_DIV_SHIFT; + + if (clksel1 & SCU_CLKSRC1_EMMC_SEL) + rate = ast2700_soc0_get_hpll_rate(scu) / 4; + else + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4; + + return (rate / ((div + 1) * 2)); +} + +static void ast2700_emmc_init(struct ast2700_scu0 *scu) +{ + u32 clksrc1, rate, div; + int i; + + /* set clk/cmd driving */ + writel(2, &scu->gpio18d0_ioctrl); /* clk driving */ + writel(1, &scu->gpio18d1_ioctrl); /* cmd driving */ + writel(1, &scu->gpio18d2_ioctrl); /* data0 driving */ + writel(1, &scu->gpio18d3_ioctrl); /* data1 driving */ + writel(1, &scu->gpio18d4_ioctrl); /* data2 driving */ + writel(1, &scu->gpio18d5_ioctrl); /* data2 driving */ + + /* emmc clk: set clk src mpll/4:400Mhz */ + clksrc1 = readl(&scu->clk_sel1); + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4; + for (i = 0; i < 8; i++) { + div = (i + 1) * 2; + if ((rate / div) <= 200000000) + break; + } + + clksrc1 &= ~(SCU_CLKSRC1_EMMC_DIV_MASK | SCU_CLKSRC1_EMMC_SEL); + clksrc1 |= (i << SCU_CLKSRC1_EMMC_DIV_SHIFT); + writel(clksrc1, &scu->clk_sel1); +} + +static void ast2700_vga_clk_init(struct ast2700_scu0 *scu) +{ + if ((readl(&scu->chip_id1) & SCU_HW_REVISION_ID) == 0) + return; + + // Use d0clk/d1clk which generated from hpll for vga0/1 after A0 + // Use CRT1clk as soc display source + setbits_le32(&scu->clk_sel3, BIT(14) | BIT(13) | BIT(12)); +} + +static u32 ast2700_soc0_get_uartclk_rate(struct ast2700_scu0 *scu) +{ + u32 clksel2 = readl(&scu->clk_sel2); + u32 div = 1; + u32 rate; + + if (clksel2 & BIT(15)) + rate = 192000000; + else + rate = 24000000; + + if (clksel2 & BIT(30)) + div = 13; + return (rate / div); +} + +static ulong ast2700_soc0_clk_get_rate(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + ulong rate = 0; + + switch (clk->id) { + case SCU0_CLK_PSP: + rate = ast2700_soc0_get_pspclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_HPLL: + rate = ast2700_soc0_get_hpll_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_DPLL: + case SCU0_CLK_MPLL: + rate = ast2700_soc0_get_pll_rate((struct ast2700_scu0 *)priv->reg, clk->id); + break; + case SCU0_CLK_AXI0: + rate = ast2700_soc0_get_axi0clk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_AXI1: + rate = ast2700_soc0_get_axi1clk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_AHB: + rate = ast2700_soc0_get_hclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_APB: + rate = ast2700_soc0_get_pclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_GATE_EMMCCLK: + rate = ast2700_soc0_get_emmcclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_GATE_UART4CLK: + rate = ast2700_soc0_get_uartclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_MPHY: + rate = ast2700_soc0_get_mphyclk_rate((struct ast2700_scu0 *)priv->reg); + break; + default: + debug("%s: unknown clk %ld\n", __func__, clk->id); + return -ENOENT; + } + + return rate; +} + +static int ast2700_soc0_clk_enable(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + struct ast2700_scu0 *scu = (struct ast2700_scu0 *)priv->reg; + u32 clkgate_bit = BIT(clk->id); + + writel(clkgate_bit, &scu->clkgate_clr); + + return 0; +} + +static const struct clk_ops ast2700_soc0_clk_ops = { + .get_rate = ast2700_soc0_clk_get_rate, + .enable = ast2700_soc0_clk_enable, +}; + +static void ast2700_init_mac_clk(struct ast2700_scu1 *scu) +{ + u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 reg_280; + u8 div_idx; + + /* The MAC source clock selects HPLL only, and the default clock + * setting is 200 Mhz. + * Calculate the corresponding divider: + * 1: div 2 + * 2: div 3 + * ... + * 7: div 8 + */ + for (div_idx = 1; div_idx <= 7; div_idx++) + if (DIV_ROUND_UP(src_clk, div_idx + 1) == 200000000) + break; + + if (div_idx == 8) { + pr_err("MAC clock cannot divide to 200 MHz\n"); + return; + } + + /* set HPLL clock divider */ + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~GENMASK(31, 29); + reg_280 |= div_idx << 29; + writel(reg_280, &scu->clk_sel1); +} + +static void ast2700_init_rgmii_clk(struct ast2700_scu1 *scu) +{ + u32 reg_284 = readl(&scu->clk_sel2); + u32 src_clk = ast2700_soc1_get_pll_rate(scu, RGMII_DEFAULT_CLK_SRC); + + if (RGMII_DEFAULT_CLK_SRC == SCU1_CLK_HPLL) { + u32 reg_280; + u8 div_idx; + + /* Calculate the corresponding divider: + * 1: div 4 + * 2: div 6 + * ... + * 7: div 16 + */ + for (div_idx = 1; div_idx <= 7; div_idx++) { + u8 div = 4 + 2 * (div_idx - 1); + + if (DIV_ROUND_UP(src_clk, div) == 125000000) + break; + } + if (div_idx == 8) { + pr_err("RGMII using HPLL cannot divide to 125 MHz\n"); + return; + } + + /* set HPLL clock divider */ + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~GENMASK(27, 25); + reg_280 |= div_idx << 25; + writel(reg_280, &scu->clk_sel1); + + /* select HPLL clock source */ + reg_284 &= ~BIT(18); + } else { + /* APLL clock divider is fixed to 8 */ + if (DIV_ROUND_UP(src_clk, 8) != 125000000) { + pr_err("RGMII using APLL cannot divide to 125 MHz\n"); + return; + } + + /* select APLL clock source */ + reg_284 |= BIT(18); + } + + writel(reg_284, &scu->clk_sel2); +} + +static void ast2700_init_rmii_clk(struct ast2700_scu1 *scu) +{ + u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 reg_280; + u8 div_idx; + + /* The RMII source clock selects HPLL only. + * Calculate the corresponding divider: + * 1: div 8 + * 2: div 12 + * ... + * 7: div 32 + */ + for (div_idx = 1; div_idx <= 7; div_idx++) { + u8 div = 8 + 4 * (div_idx - 1); + + if (DIV_ROUND_UP(src_clk, div) == 50000000) + break; + } + if (div_idx == 8) { + pr_err("RMII using HPLL cannot divide to 50 MHz\n"); + return; + } + + /* set RMII clock divider */ + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~GENMASK(23, 21); + reg_280 |= div_idx << 21; + writel(reg_280, &scu->clk_sel1); +} + +static void ast2700_init_spi(struct ast2700_scu1 *scu) +{ + writel(readl(&scu->io_driving8) | 0x0000aaaa, &scu->io_driving8); /* fwspi driving */ + writel(readl(&scu->io_driving3) | 0x00000aaa, &scu->io_driving3); /* spi0 driving */ + writel(readl(&scu->io_driving3) | 0x0aaa0000, &scu->io_driving3); /* spi1 driving */ + writel(readl(&scu->io_driving4) | 0x00002aaa, &scu->io_driving4); /* spi2 driving */ +} + +#define SCU1_CLK_I3C_DIV_MASK GENMASK(25, 23) +#define SCU1_CLK_I3C_DIV(n) ((n) - 1) +static void ast2700_init_i3c_clk(struct ast2700_scu1 *scu) +{ + u32 reg_284; + + /* I3C 250MHz = HPLL/4 */ + reg_284 = readl(&scu->clk_sel2); + reg_284 &= ~SCU1_CLK_I3C_DIV_MASK; + reg_284 |= FIELD_PREP(SCU1_CLK_I3C_DIV_MASK, SCU1_CLK_I3C_DIV(4)); + writel(reg_284, &scu->clk_sel2); +} + +static int ast2700_clk1_init(struct udevice *dev) +{ + struct ast2700_clk_priv *priv = dev_get_priv(dev); + struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg; + + ast2700_init_spi(scu); + ast2700_init_mac_clk(scu); + ast2700_init_rgmii_clk(scu); + ast2700_init_rmii_clk(scu); + ast2700_init_sdclk(scu); + ast2700_init_i3c_clk(scu); + + return 0; +} + +static int ast2700_clk0_init(struct udevice *dev) +{ + struct ast2700_clk_priv *priv = dev_get_priv(dev); + struct ast2700_scu0 *scu = (struct ast2700_scu0 *)priv->reg; + + ast2700_emmc_init(scu); + ast2700_mphy_clk_init(scu); + ast2700_vga_clk_init(scu); + + return 0; +} + +static int ast2700_clk_probe(struct udevice *dev) +{ + struct ast2700_clk_priv *priv = dev_get_priv(dev); + + priv->init = (ast2700_clk_init_fn)dev_get_driver_data(dev); + priv->reg = (void __iomem *)dev_read_addr_ptr(dev); + + if (priv->init) + return priv->init(dev); + + return 0; +} + +static int ast2700_clk_bind(struct udevice *dev) +{ + struct udevice *sysreset_dev, *rst_dev; + int ret; + + /* The system reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &sysreset_dev); + if (ret) + debug("Warning: No sysreset driver: ret = %d\n", ret); + + /* Bind the per-SCU reset controller to the same ofnode so that + * <&syscon0/1 RESET_X> phandle references resolve to a UCLASS_RESET + * device. This pairs with the airoha-style binding pattern. + */ + if (CONFIG_IS_ENABLED(RESET_AST2700)) { + ret = device_bind_driver_to_node(dev, "ast2700_reset", "reset", + dev_ofnode(dev), &rst_dev); + if (ret) + debug("Warning: failed to bind reset controller: ret = %d\n", ret); + } + + return 0; +} + +static const struct udevice_id ast2700_soc1_clk_ids[] = { + { .compatible = "aspeed,ast2700-scu1", .data = (ulong)&ast2700_clk1_init }, + { }, +}; + +U_BOOT_DRIVER(aspeed_ast2700_soc1_clk) = { + .name = "aspeed_ast2700_scu1", + .id = UCLASS_CLK, + .of_match = ast2700_soc1_clk_ids, + .priv_auto = sizeof(struct ast2700_clk_priv), + .ops = &ast2700_soc1_clk_ops, + .probe = ast2700_clk_probe, + .bind = ast2700_clk_bind, +}; + +static const struct udevice_id ast2700_soc0_clk_ids[] = { + { .compatible = "aspeed,ast2700-scu0", .data = (ulong)&ast2700_clk0_init }, + { }, +}; + +U_BOOT_DRIVER(aspeed_ast2700_soc0_clk) = { + .name = "aspeed_ast2700_scu0", + .id = UCLASS_CLK, + .of_match = ast2700_soc0_clk_ids, + .priv_auto = sizeof(struct ast2700_clk_priv), + .ops = &ast2700_soc0_clk_ops, + .probe = ast2700_clk_probe, + .bind = ast2700_clk_bind, +}; diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 2251e2846fa..0d0e39db57e 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -426,7 +426,7 @@ static const struct pmc_clk_setup sam9x60_clk_setup[] = { static int sam9x60_clk_probe(struct udevice *dev) { - void __iomem *base = (void *)devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[64], *muxallocs[64]; const char *p[10]; unsigned int cm[10], m[10], *tmpclkmux, *tmpmux; diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c index 9ea253e6ff8..93f899b6617 100644 --- a/drivers/clk/at91/sam9x7.c +++ b/drivers/clk/at91/sam9x7.c @@ -817,7 +817,7 @@ static const struct { static int sam9x7_clk_probe(struct udevice *dev) { - void __iomem *base = (void *)devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[64], *muxallocs[64]; const char *p[10]; unsigned int cm[10], m[10], *tmpclkmux, *tmpmux; diff --git a/drivers/clk/at91/sama7d65.c b/drivers/clk/at91/sama7d65.c index 9f0b394543b..0c17a8cf67b 100644 --- a/drivers/clk/at91/sama7d65.c +++ b/drivers/clk/at91/sama7d65.c @@ -1176,7 +1176,7 @@ static const struct pmc_clk_setup sama7d65_clk_setup[] = { static int sama7d65_clk_probe(struct udevice *dev) { - void __iomem *base = (void *)devfdt_get_addr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[SAMA7D65_MAX_MUX_ALLOCS]; unsigned int *muxallocs[SAMA7D65_MAX_MUX_ALLOCS]; const char *p[12]; @@ -1185,8 +1185,8 @@ static int sama7d65_clk_probe(struct udevice *dev) bool main_osc_bypass; int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j; - if (IS_ERR(base)) - return PTR_ERR(base); + if (!base) + return -EINVAL; memset(muxallocs, 0, ARRAY_SIZE(muxallocs)); memset(clkmuxallocs, 0, ARRAY_SIZE(clkmuxallocs)); diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index f24d251857f..c436038aed2 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -1109,7 +1109,7 @@ static const struct pmc_clk_setup sama7g5_clk_setup[] = { static int sama7g5_clk_probe(struct udevice *dev) { - void __iomem *base = devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[SAMA7G5_MAX_MUX_ALLOCS]; unsigned int *muxallocs[SAMA7G5_MAX_MUX_ALLOCS]; const char *p[10]; @@ -1118,8 +1118,8 @@ static int sama7g5_clk_probe(struct udevice *dev) bool main_osc_bypass; int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j; - if (IS_ERR(base)) - return PTR_ERR(base); + if (!base) + return -EINVAL; memset(muxallocs, 0, sizeof(muxallocs)); memset(clkmuxallocs, 0, sizeof(clkmuxallocs)); diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index dcaffd360fd..410bc088248 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -124,12 +124,15 @@ U_BOOT_DRIVER(at91_sam9x60_td_slck) = { static int at91_sam9x60_sckc_probe(struct udevice *dev) { struct sam9x60_sckc *sckc = dev_get_priv(dev); - void __iomem *base = devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); const char *slow_rc_osc, *slow_osc; const char *parents[2]; struct clk *clk, c; int ret; + if (!base) + return -EINVAL; + ret = clk_get_by_index(dev, 0, &c); if (ret) return ret; diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index e692b9c2167..d30786a9e6c 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -228,20 +228,30 @@ static struct clk *_register_divider(struct udevice *dev, const char *name, return clk; } -struct clk *clk_register_divider(struct udevice *dev, const char *name, +struct clk *clk_register_divider_table(struct udevice *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags) + u8 clk_divider_flags, const struct clk_div_table *table) { struct clk *clk; clk = _register_divider(dev, name, parent_name, flags, reg, shift, - width, clk_divider_flags, NULL); + width, clk_divider_flags, table); if (IS_ERR(clk)) return ERR_CAST(clk); return clk; } +struct clk *clk_register_divider(struct udevice *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags) +{ + return clk_register_divider_table(dev, name, parent_name, flags, reg, + shift, width, clk_divider_flags, + NULL); +} + U_BOOT_DRIVER(ccf_clk_divider) = { .name = UBOOT_DM_CLK_CCF_DIVIDER, .id = UCLASS_CLK, diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c index 53655059279..dbc926a4391 100644 --- a/drivers/clk/clk-hsdk-cgu.c +++ b/drivers/clk/clk-hsdk-cgu.c @@ -753,11 +753,11 @@ static int hsdk_cgu_clk_probe(struct udevice *dev) else hsdk_clk->map = hsdk_4xd_clk_map; - hsdk_clk->cgu_regs = devfdt_get_addr_index_ptr(dev, 0); + hsdk_clk->cgu_regs = dev_read_addr_index_ptr(dev, 0); if (!hsdk_clk->cgu_regs) return -EINVAL; - hsdk_clk->creg_regs = devfdt_get_addr_index_ptr(dev, 1); + hsdk_clk->creg_regs = dev_read_addr_index_ptr(dev, 1); if (!hsdk_clk->creg_regs) return -EINVAL; diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c index 117266ac778..4a6c71016da 100644 --- a/drivers/clk/clk-stub.c +++ b/drivers/clk/clk-stub.c @@ -49,11 +49,13 @@ static struct clk_ops stub_clk_ops = { }; static const struct udevice_id stub_clk_ids[] = { + { .compatible = "qcom,qcs615-rpmh-clk" }, { .compatible = "qcom,rpmcc" }, - { .compatible = "qcom,sdm670-rpmh-clk" }, - { .compatible = "qcom,sdm845-rpmh-clk" }, + { .compatible = "qcom,sa8775p-rpmh-clk" }, { .compatible = "qcom,sc7180-rpmh-clk" }, { .compatible = "qcom,sc7280-rpmh-clk" }, + { .compatible = "qcom,sdm670-rpmh-clk" }, + { .compatible = "qcom,sdm845-rpmh-clk" }, { .compatible = "qcom,sm6350-rpmh-clk" }, { .compatible = "qcom,sm8150-rpmh-clk" }, { .compatible = "qcom,sm8250-rpmh-clk" }, diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index f57ac79f8ca..846b8011f5c 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -9,6 +9,7 @@ #include <log.h> #include <asm/arch/clock.h> #include <asm/arch/imx-regs.h> +#include <dm/of_access.h> #include <dt-bindings/clock/imx6qdl-clock.h> #include "clk.h" @@ -46,6 +47,33 @@ static struct clk_ops imx6q_clk_ops = { .disable = ccf_clk_disable, }; +static const char *const pll_bypass_src_sels[] = { + "osc", + "lvds1_in", + "lvds2_in", + "dummy", +}; + +static const char *const pll2_bypass_sels[] = { + "pll2", + "pll2_bypass_src", +}; + +static const char *const pll3_bypass_sels[] = { + "pll3", + "pll3_bypass_src", +}; + +static const char *const pll5_bypass_sels[] = { + "pll5", + "pll5_bypass_src", +}; + +static const char *const pll6_bypass_sels[] = { + "pll6", + "pll6_bypass_src", +}; + static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", @@ -72,6 +100,23 @@ static const char *const ecspi_sels[] = { "pll3_60m", "osc", }; + +static const struct clk_div_table post_div_table[] = { + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { /* sentinel */ } +}; + +static const struct clk_div_table video_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { /* sentinel */ } +}; + +#if CONFIG_IS_ENABLED(VIDEO) static const char *const ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", @@ -113,6 +158,122 @@ static const char *ipu2_di1_sels_2[] = { static unsigned int share_count_mipi_core_cfg; +static void of_assigned_ldb_sels(struct udevice *dev, int *ldb_di0_sel, + int *ldb_di1_sel) +{ + struct ofnode_phandle_args clk_args, parent_args; + ofnode node = dev_ofnode(dev); + int count, err; + + count = dev_count_phandle_with_args(dev, "assigned-clocks", + "#clock-cells", 0); + if (count <= 0) { + if (count == 0) + debug("%s: no assigned_clocks found\n", dev->name); + else + pr_err("%s: failed to get phandle count (%d)\n", + dev->name, count); + return; + } + + for (int i = 0; i < count; i++) { + err = dev_read_phandle_with_args(dev, "assigned-clocks", + "#clock-cells", 0, i, + &clk_args); + if (err == -ENOENT) + /* Skip empty handles */ + continue; + else if (err < 0) + return; + + if (!ofnode_equal(clk_args.node, node) || + clk_args.args[0] >= IMX6QDL_CLK_END) { + pr_err("%s: clock %d not in ccm\n", dev->name, i); + return; + } + + err = dev_read_phandle_with_args(dev, "assigned-clock-parents", + "#clock-cells", 0, i, + &parent_args); + if (err < 0) + return; + + if (!ofnode_equal(parent_args.node, node) || + parent_args.args[0] >= IMX6QDL_CLK_END) { + pr_err("%s: parent clock %d not in ccm\n", dev->name, + i); + return; + } + + if (clk_args.args[0] == IMX6QDL_CLK_LDB_DI0_SEL) + *ldb_di0_sel = parent_args.args[0]; + else if (clk_args.args[0] == IMX6QDL_CLK_LDB_DI1_SEL) + *ldb_di1_sel = parent_args.args[0]; + } +} + +static void imx6q_init_ldb_clks(struct udevice *dev) +{ + int ldb_di_sel[] = { IMX6QDL_CLK_END, IMX6QDL_CLK_END }; + enum ldb_di_clock ldb_di_clk[] = { MXC_MMDC_CH1_CLK, MXC_MMDC_CH1_CLK }; + + of_assigned_ldb_sels(dev, &ldb_di_sel[0], &ldb_di_sel[1]); + for (int i = 0; i < 2; i++) { + switch (ldb_di_sel[i]) { + case IMX6QDL_CLK_PLL5_VIDEO_DIV: + ldb_di_clk[i] = MXC_PLL5_CLK; + break; + case IMX6QDL_CLK_PLL2_PFD0_352M: + ldb_di_clk[i] = MXC_PLL2_PFD0_CLK; + break; + case IMX6QDL_CLK_PLL2_PFD2_396M: { + struct clk *clk, *parent; + + int err = clk_get_by_id(IMX6QDL_CLK_PERIPH_PRE, &clk); + + if (err) { + pr_err("%s: failed to get periph_pre clock " + "(%d)\n", + dev->name, err); + return; + } + + err = clk_get_by_id(IMX6QDL_CLK_PLL2_PFD2_396M, + &parent); + if (err) { + pr_err("%s: failed to get pll2_pfd2_396m clock" + " (%d)\n", + dev->name, err); + return; + } + + if (parent == clk) { + pr_err("%s: ldb_di%d_sel: couldn't disable " + "pll2_pfd2_396m clock\n", + dev->name, i); + return; + } + + ldb_di_clk[i] = MXC_PLL2_PFD2_CLK; + break; + } + case IMX6QDL_CLK_MMDC_CH1_AXI: + case IMX6QDL_CLK_END: + /* use the default clock */ + break; + case IMX6QDL_CLK_PLL3_USB_OTG: + ldb_di_clk[i] = MXC_PLL3_SW_CLK; + break; + default: + pr_err("%s: invalid LDB clock parent\n", dev->name); + return; + } + } + + select_ldb_di_clock_source(ldb_di_clk[0], ldb_di_clk[1]); +} +#endif /* CONFIG_IS_ENABLED(VIDEO) */ + static int imx6q_clk_probe(struct udevice *dev) { void *base; @@ -120,26 +281,70 @@ static int imx6q_clk_probe(struct udevice *dev) /* Anatop clocks */ base = (void *)ANATOP_BASE_ADDR; - clk_dm(IMX6QDL_CLK_PLL2, - imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_bus", "osc", - base + 0x30, 0x1)); + clk_dm(IMX6QDL_PLL2_BYPASS_SRC, + imx_clk_mux(dev, "pll2_bypass_src", base + 0x30, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL3_BYPASS_SRC, + imx_clk_mux(dev, "pll3_bypass_src", base + 0x10, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL5_BYPASS_SRC, + imx_clk_mux(dev, "pll5_bypass_src", base + 0xa0, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL6_BYPASS_SRC, + imx_clk_mux(dev, "pll6_bypass_src", base + 0xe0, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + + clk_dm(IMX6QDL_CLK_PLL2, imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2", + "osc", base + 0x30, 0x1)); + clk_dm(IMX6QDL_CLK_PLL3, imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3", + "osc", base + 0x10, 0x3)); + clk_dm(IMX6QDL_CLK_PLL5, imx_clk_pllv3(dev, IMX_PLLV3_AV, "pll5", "osc", + base + 0xa0, 0x7f)); + clk_dm(IMX6QDL_CLK_PLL6, imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", + "osc", base + 0xe0, 0x3)); + + clk_dm(IMX6QDL_PLL2_BYPASS, + imx_clk_mux_flags(dev, "pll2_bypass", base + 0x30, 16, 1, + pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL3_BYPASS, + imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1, + pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL5_BYPASS, + imx_clk_mux_flags(dev, "pll5_bypass", base + 0xa0, 16, 1, + pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL6_BYPASS, + imx_clk_mux_flags(dev, "pll6_bypass", base + 0xe0, 16, 1, + pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), + CLK_SET_RATE_PARENT)); + + SET_CLK_PARENT(IMX6QDL_PLL2_BYPASS, IMX6QDL_CLK_PLL2); + SET_CLK_PARENT(IMX6QDL_PLL3_BYPASS, IMX6QDL_CLK_PLL3); + SET_CLK_PARENT(IMX6QDL_PLL5_BYPASS, IMX6QDL_CLK_PLL5); + SET_CLK_PARENT(IMX6QDL_PLL6_BYPASS, IMX6QDL_CLK_PLL6); + + clk_dm(IMX6QDL_CLK_PLL2_BUS, + imx_clk_gate(dev, "pll2_bus", "pll2_bypass", base + 0x30, 13)); clk_dm(IMX6QDL_CLK_PLL3_USB_OTG, - imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3_usb_otg", "osc", - base + 0x10, 0x3)); + imx_clk_gate(dev, "pll3_usb_otg", "pll3_bypass", base + 0x10, + 13)); + clk_dm(IMX6QDL_CLK_PLL5_VIDEO, + imx_clk_gate(dev, "pll5_video", "pll5_bypass", base + 0xa0, 13)); + clk_dm(IMX6QDL_CLK_PLL6_ENET, + imx_clk_gate(dev, "pll6_enet", "pll6_bypass", base + 0xe0, 13)); + clk_dm(IMX6QDL_CLK_PLL3_60M, imx_clk_fixed_factor(dev, "pll3_60m", "pll3_usb_otg", 1, 8)); clk_dm(IMX6QDL_CLK_PLL3_80M, imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6)); clk_dm(IMX6QDL_CLK_PLL3_120M, imx_clk_fixed_factor(dev, "pll3_120m", "pll3_usb_otg", 1, 4)); - clk_dm(IMX6QDL_CLK_PLL5, imx_clk_pllv3(dev, IMX_PLLV3_AV, "pll5", "osc", - base + 0xa0, 0x7f)); - clk_dm(IMX6QDL_CLK_PLL5_VIDEO, - imx_clk_gate(dev, "pll5_video", "pll5", base + 0xa0, 13)); - clk_dm(IMX6QDL_CLK_PLL6, imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", - "osc", base + 0xe0, 0x3)); - clk_dm(IMX6QDL_CLK_PLL6_ENET, - imx_clk_gate(dev, "pll6_enet", "pll6", base + 0xe0, 13)); clk_dm(IMX6QDL_CLK_PLL2_PFD0_352M, imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0)); @@ -151,10 +356,14 @@ static int imx6q_clk_probe(struct udevice *dev) clk_dm(IMX6QDL_CLK_PLL2_198M, imx_clk_fixed_factor(dev, "pll2_198m", "pll2_pfd2_396m", 1, 2)); clk_dm(IMX6QDL_CLK_PLL5_POST_DIV, - imx_clk_fixed_factor(dev, "pll5_post_div", "pll5_video", 1, 1)); + clk_register_divider_table(dev, "pll5_post_div", "pll5_video", + CLK_SET_RATE_PARENT, base + 0xa0, 19, + 2, 0, post_div_table)); clk_dm(IMX6QDL_CLK_PLL5_VIDEO_DIV, - imx_clk_fixed_factor(dev, "pll5_video_div", "pll5_post_div", 1, - 1)); + clk_register_divider_table(dev, "pll5_video_div", + "pll5_post_div", CLK_SET_RATE_PARENT, + base + 0x170, 30, 2, 0, + video_div_table)); clk_dm(IMX6QDL_CLK_VIDEO_27M, imx_clk_fixed_factor(dev, "video_27m", "pll3_pfd1_540m", 1, 20)); @@ -263,6 +472,7 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_gate2(dev, "mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22)); +#if CONFIG_IS_ENABLED(VIDEO) clk_dm(IMX6QDL_CLK_IPU1_SEL, imx_clk_mux(dev, "ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels))); @@ -279,9 +489,12 @@ static int imx6q_clk_probe(struct udevice *dev) ldb_di_sels, ARRAY_SIZE(ldb_di_sels))); } else { /* - * Need to set these as read-only due to a hardware bug. - * Keeping default mux values. Fixed on the i.MX6 QuadPlus - */ + * Need to set these as read-only due to a hardware bug. + * Keeping default mux values. Fixed on the i.MX6 QuadPlus + * Need to set the clocks now and make them read-only due to a + * hardware bug. Fixed on the i.MX6 QuadPlus + */ + imx6q_init_ldb_clks(dev); clk_dm(IMX6QDL_CLK_LDB_DI0_SEL, imx_clk_mux_flags(dev, "ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), @@ -413,6 +626,7 @@ static int imx6q_clk_probe(struct udevice *dev) ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT)); } +#endif /* CONFIG_IS_ENABLED(VIDEO) */ clk_dm(IMX6QDL_CLK_ECSPI1, imx_clk_gate2(dev, "ecspi1", "ecspi_root", base + 0x6c, 0)); @@ -453,6 +667,8 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10)); clk_dm(IMX6QDL_CLK_ENET_REF, imx_clk_fixed_factor(dev, "enet_ref", "pll6_enet", 1, 1)); + +#if CONFIG_IS_ENABLED(VIDEO) clk_dm(IMX6QDL_CLK_MIPI_CORE_CFG, imx_clk_gate2_shared(dev, "mipi_core_cfg", "video_27m", base + 0x74, 16, @@ -480,6 +696,7 @@ static int imx6q_clk_probe(struct udevice *dev) SET_CLK_PARENT(IMX6QDL_CLK_IPU1_SEL, IMX6QDL_CLK_PLL3_PFD1_540M); } +#endif /* CONFIG_IS_ENABLED(VIDEO) */ return 0; } diff --git a/drivers/clk/owl/Kconfig b/drivers/clk/owl/Kconfig index c6afef90034..5f3b8fe8ab4 100644 --- a/drivers/clk/owl/Kconfig +++ b/drivers/clk/owl/Kconfig @@ -1,8 +1,8 @@ config CLK_OWL - bool "Actions Semi OWL clock drivers" - depends on CLK && ARCH_OWL - help - Enable support for clock managemet unit present in Actions Semi + bool "Actions Semi OWL clock drivers" + depends on CLK && ARCH_OWL + help + Enable support for clock managemet unit present in Actions Semi Owl series S900/S700 SoCs. diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 0a2ce55aaa2..9ad233c83ac 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -111,6 +111,14 @@ config CLK_QCOM_SM6115 on the Snapdragon SM6115 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_SM6125 + bool "Qualcomm SM6125 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon SM6125 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_SM6350 bool "Qualcomm SM6350 GCC" select CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index b96d61b603e..c0d95a6300e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CLK_QCOM_QCS615) += clock-qcs615.o obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o +obj-$(CONFIG_CLK_QCOM_SM6125) += clock-sm6125.o obj-$(CONFIG_CLK_QCOM_SM6350) += clock-sm6350.o obj-$(CONFIG_CLK_QCOM_SM7150) += clock-sm7150.o obj-$(CONFIG_CLK_QCOM_SM8150) += clock-sm8150.o diff --git a/drivers/clk/qcom/clock-qcm2290.c b/drivers/clk/qcom/clock-qcm2290.c index 5a599085b50..c38ff1a1e4a 100644 --- a/drivers/clk/qcom/clock-qcm2290.c +++ b/drivers/clk/qcom/clock-qcm2290.c @@ -73,7 +73,7 @@ static const struct pll_vote_clk gpll6_clk = { .status = 0x6000, .status_bit = BIT(31), .ena_vote = 0x79000, - .vote_bit = BIT(7), + .vote_bit = BIT(6), }; static const struct gate_clk qcm2290_clks[] = { diff --git a/drivers/clk/qcom/clock-qcs615.c b/drivers/clk/qcom/clock-qcs615.c index 2087fc38f63..7b3fe49de9c 100644 --- a/drivers/clk/qcom/clock-qcs615.c +++ b/drivers/clk/qcom/clock-qcs615.c @@ -19,6 +19,11 @@ #define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c #define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf060 +#define UFS_PHY_AXI_CLK_CMD_RCGR 0x77020 +#define UFS_PHY_ICE_CORE_CLK_CMD_RCGR 0x77048 +#define UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR 0x77060 +#define UFS_PHY_PHY_AUX_CLK_CMD_RCGR 0x7707c + #define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) #define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) #define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12) @@ -33,9 +38,37 @@ #define GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT BIT(26) #define GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT BIT(27) +/* UFS PHY AXI clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0), + F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0), + { } +}; + +/* UFS PHY ICE CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(37500000, CFG_CLK_SRC_GPLL0_EVEN, 8, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + +/* UFS PHY UNIPRO CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(37500000, CFG_CLK_SRC_GPLL0_EVEN, 8, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0, 8, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + { } +}; + static ulong qcs615_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; if (clk->id < priv->data->num_clks) debug("%s: %s, requested rate=%ld\n", __func__, @@ -52,6 +85,24 @@ static ulong qcs615_set_rate(struct clk *clk, ulong rate) 5, 0, 0, CFG_CLK_SRC_GPLL0, 8); clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0); return rate; + case GCC_UFS_PHY_AXI_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_axi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_AXI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_UNIPRO_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_unipro_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_ICE_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_ice_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_ICE_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_PHY_AUX_CLK: + clk_rcg_set_rate(priv->base, UFS_PHY_PHY_AUX_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return 19200000; default: return 0; } @@ -81,7 +132,17 @@ static const struct gate_clk qcs615_clks[] = { GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT), GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT), GATE_CLK(GCC_DISP_HF_AXI_CLK, 0xb038, BIT(0)), - GATE_CLK(GCC_DISP_AHB_CLK, 0xb032, BIT(0)) + GATE_CLK(GCC_DISP_AHB_CLK, 0xb032, BIT(0)), + /* UFS clocks */ + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770c0, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77014, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x77040, BIT(0)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77044, BIT(0)), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77018, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x7701c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x77078, BIT(0)), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, BIT(0)), }; static int qcs615_enable(struct clk *clk) diff --git a/drivers/clk/qcom/clock-sa8775p.c b/drivers/clk/qcom/clock-sa8775p.c index 4957abf6f58..7eec4aeae48 100644 --- a/drivers/clk/qcom/clock-sa8775p.c +++ b/drivers/clk/qcom/clock-sa8775p.c @@ -19,6 +19,11 @@ #define USB30_PRIM_MASTER_CLK_CMD_RCGR 0x1b028 #define USB3_PRIM_PHY_AUX_CMD_RCGR 0x1b06c +#define UFS_PHY_AXI_CLK_CMD_RCGR 0x8302c +#define UFS_PHY_ICE_CORE_CLK_CMD_RCGR 0x83074 +#define UFS_PHY_PHY_AUX_CLK_CMD_RCGR 0x830a8 +#define UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR 0x8308c + #define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) #define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) #define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12) @@ -44,9 +49,35 @@ #define GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT BIT(25) +/* UFS AXI clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + +/* UFS ICE CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + +/* UFS UNIPRO CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + static ulong sa8775p_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; if (clk->id < priv->data->num_clks) debug("%s: %s, requested rate=%ld\n", __func__, @@ -63,6 +94,24 @@ static ulong sa8775p_set_rate(struct clk *clk, ulong rate) 5, 0, 0, CFG_CLK_SRC_GPLL0, 8); clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0); return rate; + case GCC_UFS_PHY_AXI_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_axi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_AXI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_UNIPRO_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_unipro_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_ICE_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_ice_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_ICE_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_PHY_AUX_CLK: + clk_rcg_set_rate(priv->base, UFS_PHY_PHY_AUX_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return 19200000; default: return 0; } @@ -106,6 +155,20 @@ static const struct gate_clk sa8775p_clks[] = { /* QUP Wrapper 3 clocks */ GATE_CLK(GCC_QUPV3_WRAP3_S0_CLK, 0x4b000, GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT), + + /* UFS PHY clocks */ + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x83018, 1), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x830d4, 1), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x83020, 1), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x83064, 1), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x83024, 1), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x83028, 1), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x830c0, 1), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x830a4, 1), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x8306c, 1), + + /* EDP reference clock (used by UFS PHY) */ + GATE_CLK(GCC_EDP_REF_CLKREF_EN, 0x97448, 1), }; static int sa8775p_enable(struct clk *clk) diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c index 01c8587ac39..91e3fcc27cb 100644 --- a/drivers/clk/qcom/clock-sc7280.c +++ b/drivers/clk/qcom/clock-sc7280.c @@ -23,6 +23,10 @@ #define PCIE_1_AUX_CLK_CMD_RCGR 0x8d058 #define PCIE1_PHY_RCHNG_CMD_RCGR 0x8d03c #define PCIE_1_PIPE_CLK_PHY_MUX 0x8d054 +#define UFS_PHY_AXI_CLK_CMD_RCGR 0x77024 +#define UFS_PHY_ICE_CORE_CLK_CMD_RCGR 0x7706c +#define UFS_PHY_PHY_AUX_CLK_CMD_RCGR 0x770a0 +#define UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR 0x77084 static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { F(66666667, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0), @@ -54,6 +58,33 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0_EVEN, 2, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0_EVEN, 2, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = { + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0_EVEN, 2, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 0, 0), + { } +}; + static ulong sc7280_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -103,6 +134,26 @@ static ulong sc7280_set_rate(struct clk *clk, ulong rate) case GCC_PCIE1_PHY_RCHNG_CLK: clk_rcg_set_rate(priv->base, PCIE1_PHY_RCHNG_CMD_RCGR, 5, CFG_CLK_SRC_GPLL0_EVEN); return 100000000; + case GCC_UFS_PHY_AXI_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_axi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_AXI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_ICE_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_ice_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_ICE_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_PHY_AUX_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_phy_aux_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_PHY_AUX_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_UNIPRO_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_unipro_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; default: return rate; } @@ -148,6 +199,7 @@ static const struct gate_clk sc7280_clks[] = { GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)), GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770cc, BIT(0)), GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77018, BIT(0)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77064, BIT(0)), GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7705c, BIT(0)), GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x7709c, BIT(0)), GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x7701c, BIT(0)), diff --git a/drivers/clk/qcom/clock-sm6125.c b/drivers/clk/qcom/clock-sm6125.c new file mode 100644 index 00000000000..1fd72d55e88 --- /dev/null +++ b/drivers/clk/qcom/clock-sm6125.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm sm6125 + * + * (C) Copyright 2026 Biswapriyo Nath <[email protected]> + * + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/bug.h> +#include <dt-bindings/clock/qcom,gcc-sm6125.h> + +#include "clock-qcom.h" + +#define GCC_BASE 0x01400000 + +#define QUPV3_WRAP0_S4_CMD_RCGR 0x1f608 +#define SDCC1_APPS_CLK_CMD_RCGR 0x38028 +#define SDCC2_APPS_CLK_CMD_RCGR 0x1e00c + +#define GCC_GPLL0_MODE 0x0 +#define GCC_GPLL3_MODE 0x3000 +#define GCC_GPLL4_MODE 0x4000 +#define GCC_GPLL5_MODE 0x5000 +#define GCC_GPLL6_MODE 0x6000 +#define GCC_GPLL7_MODE 0x7000 +#define GCC_GPLL8_MODE 0x8000 +#define GCC_GPLL9_MODE 0x9000 + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_AUX2, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_AUX2, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_AUX2, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 16, 75), + F(75000000, CFG_CLK_SRC_GPLL0_AUX2, 4, 0, 0), + F(80000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_AUX2, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_AUX2, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_AUX2, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL6, 3, 0, 0), + {} +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0_AUX2, 12, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_AUX2, 3, 0, 0), + {} +}; + +static const struct pll_vote_clk gpll0_clk = { + .status = 0, + .status_bit = BIT(31), + .ena_vote = 0x79000, + .vote_bit = BIT(0), +}; + +static const struct gate_clk sm6125_clks[] = { + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1a084, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP0_CORE_2X_CLK, 0x7900c, BIT(9)), + GATE_CLK(GCC_QUPV3_WRAP0_CORE_CLK, 0x7900c, BIT(8)), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x7900c, BIT(10)), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x7900c, BIT(11)), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x7900c, BIT(12)), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x7900c, BIT(13)), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x7900c, BIT(14)), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x7900c, BIT(15)), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x7900c, BIT(6)), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x7900c, BIT(7)), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x38008, BIT(0)), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x38004, BIT(0)), + GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x3800c, BIT(0)), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x1e008, BIT(0)), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x1e004, BIT(0)), + GATE_CLK(GCC_SYS_NOC_CPUSS_AHB_CLK, 0x79004, BIT(0)), + GATE_CLK(GCC_SYS_NOC_UFS_PHY_AXI_CLK, 0x45098, BIT(0)), + GATE_CLK(GCC_SYS_NOC_USB3_PRIM_AXI_CLK, 0x1a080, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x45014, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x45010, BIT(0)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x45044, BIT(0)), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x45078, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x4501c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x45018, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x45040, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1a010, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1a018, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1a014, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x80278, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1a054, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x1a058, BIT(0)), + GATE_CLK(GCC_AHB2PHY_USB_CLK, 0x1d008, BIT(0)), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, BIT(0)), +}; + +static ulong sm6125_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + debug("%s: clk %s rate %lu\n", __func__, sm6125_clks[clk->id].name, + rate); + + switch (clk->id) { + case GCC_QUPV3_WRAP0_S4_CLK: + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, QUPV3_WRAP0_S4_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, + 16); + return 0; + case GCC_SDCC2_APPS_CLK: + clk_enable_gpll0(priv->base, &gpll0_clk); + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + WARN(freq->src != CFG_CLK_SRC_GPLL0, + "SDCC2_APPS_CLK_SRC not set to GPLL0, requested rate %lu\n", + rate); + clk_rcg_set_rate_mnd(priv->base, SDCC2_APPS_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, + 8); + return freq->freq; + case GCC_SDCC1_APPS_CLK: + /* The firmware turns this on for us and always sets it to this rate */ + return 384000000; + default: + return rate; + } +} + +static int sm6125_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %s\n", __func__, sm6125_clks[clk->id].name); + + switch (clk->id) { + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_CLKREF_CLK); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map sm6125_gcc_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = { 0x1c000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x1c004 }, + [GCC_UFS_PHY_BCR] = { 0x45000 }, + [GCC_USB30_PRIM_BCR] = { 0x1a000 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x1d000 }, + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x1b008 }, + [GCC_USB3_PHY_PRIM_SP0_BCR] = { 0x1b000 }, + [GCC_CAMSS_MICRO_BCR] = { 0x560ac }, +}; + +static const struct qcom_power_map sm6125_gdscs[] = { + [USB30_PRIM_GDSC] = { 0x1a004 }, + [UFS_PHY_GDSC] = { 0x45004 }, + [CAMSS_VFE0_GDSC] = { 0x54004 }, + [CAMSS_VFE1_GDSC] = { 0x5403c }, + [CAMSS_TOP_GDSC] = { 0x5607c }, + [CAM_CPP_GDSC] = { 0x560bc }, + [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = { 0x7d060 }, + [HLOS1_VOTE_MM_SNOC_MMU_TBU_RT_GDSC] = { 0x80074 }, + [HLOS1_VOTE_MM_SNOC_MMU_TBU_NRT_GDSC] = { 0x80084 }, + [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = { 0x80094 }, +}; + +static const phys_addr_t sm6125_gpll_addrs[] = { + GCC_BASE + GCC_GPLL0_MODE, GCC_BASE + GCC_GPLL3_MODE, + GCC_BASE + GCC_GPLL4_MODE, GCC_BASE + GCC_GPLL5_MODE, + GCC_BASE + GCC_GPLL6_MODE, GCC_BASE + GCC_GPLL7_MODE, + GCC_BASE + GCC_GPLL8_MODE, GCC_BASE + GCC_GPLL9_MODE, +}; + +static const phys_addr_t sm6125_rcg_addrs[] = { + 0x0141a01c, // GCC_USB30_PRIM_MASTER_CMD_RCGR + 0x0141a034, // GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR + 0x0141a060, // GCC_USB3_PRIM_PHY_AUX_CMD_RCGR + 0x01438028, // GCC_SDCC1_APPS_CMD_RCGR + 0x0141e00c, // GCC_SDCC2_APPS_CMD_RCGR + 0x0141f148, // GCC_QUPV3_WRAP0_S0_CMD_RCGR + 0x0141f278, // GCC_QUPV3_WRAP0_S1_CMD_RCGR + 0x0141f3a8, // GCC_QUPV3_WRAP0_S2_CMD_RCGR + 0x0141f4d8, // GCC_QUPV3_WRAP0_S3_CMD_RCGR + 0x0141f608, // GCC_QUPV3_WRAP0_S4_CMD_RCGR + 0x0141f738, // GCC_QUPV3_WRAP0_S5_CMD_RCGR + 0x01445020, // GCC_UFS_PHY_AXI_CMD_RCGR + 0x01445048, // GCC_UFS_PHY_ICE_CORE_CMD_RCGR + 0x01445060, // GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR + 0x0144507c, // GCC_UFS_PHY_PHY_AUX_CMD_RCGR +}; + +static const char *const sm6125_rcg_names[] = { + "GCC_USB30_PRIM_MASTER_CMD_RCGR", + "GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR", + "GCC_USB3_PRIM_PHY_AUX_CMD_RCGR", + "GCC_SDCC1_APPS_CMD_RCGR", + "GCC_SDCC2_APPS_CMD_RCGR", + "GCC_QUPV3_WRAP0_S0_CMD_RCGR", + "GCC_QUPV3_WRAP0_S1_CMD_RCGR", + "GCC_QUPV3_WRAP0_S2_CMD_RCGR", + "GCC_QUPV3_WRAP0_S3_CMD_RCGR", + "GCC_QUPV3_WRAP0_S4_CMD_RCGR", + "GCC_QUPV3_WRAP0_S5_CMD_RCGR", + "GCC_UFS_PHY_AXI_CMD_RCGR", + "GCC_UFS_PHY_ICE_CORE_CMD_RCGR", + "GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR", + "GCC_UFS_PHY_PHY_AUX_CMD_RCGR", +}; + +static struct msm_clk_data sm6125_gcc_data = { + .resets = sm6125_gcc_resets, + .num_resets = ARRAY_SIZE(sm6125_gcc_resets), + .clks = sm6125_clks, + .num_clks = ARRAY_SIZE(sm6125_clks), + .power_domains = sm6125_gdscs, + .num_power_domains = ARRAY_SIZE(sm6125_gdscs), + + .enable = sm6125_enable, + .set_rate = sm6125_set_rate, + + .dbg_pll_addrs = sm6125_gpll_addrs, + .num_plls = ARRAY_SIZE(sm6125_gpll_addrs), + .dbg_rcg_addrs = sm6125_rcg_addrs, + .num_rcgs = ARRAY_SIZE(sm6125_rcg_addrs), + .dbg_rcg_names = sm6125_rcg_names, +}; + +static const struct udevice_id gcc_sm6125_of_match[] = { + { + .compatible = "qcom,gcc-sm6125", + .data = (ulong)&sm6125_gcc_data, + }, + {} +}; + +U_BOOT_DRIVER(gcc_sm6125) = { + .name = "gcc_sm6125", + .id = UCLASS_NOP, + .of_match = gcc_sm6125_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 72f99e9fa1b..1893b6c4181 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -61,11 +61,11 @@ config CLK_RCAR_GEN3 Enable this to support the clocks on Renesas R-Car Gen3 and Gen4 SoCs. config CLK_R8A774A1 - bool "Renesas R8A774A1 clock driver" + bool "Renesas R8A774A1 clock driver" def_bool y if R8A774A1 - depends on CLK_RCAR_GEN3 - help - Enable this to support the clocks on Renesas R8A774A1 SoC. + depends on CLK_RCAR_GEN3 + help + Enable this to support the clocks on Renesas R8A774A1 SoC. config CLK_R8A774B1 bool "Renesas R8A774B1 clock driver" diff --git a/drivers/clk/sophgo/clk-cv1800b.c b/drivers/clk/sophgo/clk-cv1800b.c index d946ea57a46..248a69321fc 100644 --- a/drivers/clk/sophgo/clk-cv1800b.c +++ b/drivers/clk/sophgo/clk-cv1800b.c @@ -500,9 +500,12 @@ static int cv1800b_register_clk(struct udevice *dev) { struct clk osc; ulong osc_rate; - void *base = devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); int i, ret; + if (!base) + return -EINVAL; + ret = clk_get_by_index(dev, 0, &osc); if (ret) { pr_err("Failed to get clock\n"); diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c index 842a0541bd6..046d5d1605a 100644 --- a/drivers/clk/sunxi/clk_sunxi.c +++ b/drivers/clk/sunxi/clk_sunxi.c @@ -64,7 +64,7 @@ static int sunxi_clk_disable(struct clk *clk) return sunxi_set_gate(clk, false); } -struct clk_ops sunxi_clk_ops = { +static const struct clk_ops sunxi_clk_ops = { .enable = sunxi_clk_enable, .disable = sunxi_clk_disable, }; diff --git a/drivers/clk/ti/clk-ctrl.c b/drivers/clk/ti/clk-ctrl.c index c5c97dc35c4..08f7410edce 100644 --- a/drivers/clk/ti/clk-ctrl.c +++ b/drivers/clk/ti/clk-ctrl.c @@ -8,7 +8,11 @@ #include <dm.h> #include <dm/device_compat.h> #include <clk-uclass.h> -#include <asm/arch-am33xx/clock.h> +#include <asm/ti-common/omap_clock.h> +#include <asm/io.h> +#include <linux/iopoll.h> + +#define TRANSITION_TIMEOUT_US 10000 struct clk_ti_ctrl_offs { fdt_addr_t start; @@ -33,10 +37,37 @@ static int clk_ti_ctrl_check_offs(struct clk *clk, fdt_addr_t offs) return -EFAULT; } +#define IDLEST_DISABLED (MODULE_CLKCTRL_IDLEST_DISABLED << MODULE_CLKCTRL_IDLEST_SHIFT) +#define IDLEST_TRANSITION (MODULE_CLKCTRL_IDLEST_TRANSITIONING << MODULE_CLKCTRL_IDLEST_SHIFT) +static int clk_ti_ctrl_disable_clock_module(u32 addr) +{ + int val; + + clrsetbits_le32(addr, MODULE_CLKCTRL_MODULEMODE_MASK, + MODULE_CLKCTRL_MODULEMODE_SW_DISABLE << + MODULE_CLKCTRL_MODULEMODE_SHIFT); + + return readl_relaxed_poll_timeout(addr, val, + (val & MODULE_CLKCTRL_IDLEST_MASK) == IDLEST_DISABLED, + TRANSITION_TIMEOUT_US); +} + +static int clk_ti_ctrl_enable_clock_module(u32 addr) +{ + int val; + + clrsetbits_le32(addr, MODULE_CLKCTRL_MODULEMODE_MASK, + MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << + MODULE_CLKCTRL_MODULEMODE_SHIFT); + return readl_relaxed_poll_timeout(addr, val, + ((val & MODULE_CLKCTRL_IDLEST_MASK) != IDLEST_DISABLED) && + ((val & MODULE_CLKCTRL_IDLEST_MASK) != IDLEST_TRANSITION), + TRANSITION_TIMEOUT_US); +} + static int clk_ti_ctrl_disable(struct clk *clk) { struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); - u32 *clk_modules[2] = { }; fdt_addr_t offs; int err; @@ -47,16 +78,13 @@ static int clk_ti_ctrl_disable(struct clk *clk) return err; } - clk_modules[0] = (u32 *)(offs); - dev_dbg(clk->dev, "disable module @ %p\n", clk_modules[0]); - do_disable_clocks(NULL, clk_modules, 1); - return 0; + dev_dbg(clk->dev, "disable module @ %x\n", offs); + return clk_ti_ctrl_disable_clock_module(offs); } static int clk_ti_ctrl_enable(struct clk *clk) { struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); - u32 *clk_modules[2] = { }; fdt_addr_t offs; int err; @@ -67,10 +95,8 @@ static int clk_ti_ctrl_enable(struct clk *clk) return err; } - clk_modules[0] = (u32 *)(offs); - dev_dbg(clk->dev, "enable module @ %p\n", clk_modules[0]); - do_enable_clocks(NULL, clk_modules, 1); - return 0; + dev_dbg(clk->dev, "enable module @ %x\n", offs); + return clk_ti_ctrl_enable_clock_module(offs); } static ulong clk_ti_ctrl_get_rate(struct clk *clk) |
