From b782921ddd7f84f524723090377903f399fdbbcb Mon Sep 17 00:00:00 2001 From: Jay Buddhabhatti Date: Wed, 29 Nov 2023 03:29:15 -0800 Subject: drivers: clk: zynqmp: calculate closest mux rate Currently zynqmp clock driver is not calculating closest mux rate and because of that Linux is not setting proper frequency for CPU and not able to set given frequency for dynamic frequency scaling. E.g., In current logic initial acpu clock parent and frequency as below apll1 0 0 0 2199999978 0 0 50000 Y acpu0_mux 0 0 0 2199999978 0 0 50000 Y acpu0_idiv1 0 0 0 2199999978 0 0 50000 Y acpu0 0 0 0 2199999978 0 0 50000 Y After changing acpu frequency to 549999994 Hz using CPU freq scaling its selecting incorrect parent which is not closest frequency. rpll_to_xpd 0 0 0 1599999984 0 0 50000 Y acpu0_mux 0 0 0 1599999984 0 0 50000 Y acpu0_div1 0 0 0 533333328 0 0 50000 Y acpu0 0 0 0 533333328 0 0 50000 Y Parent should remain same since 549999994 = 2199999978 / 4. So use __clk_mux_determine_rate_closest() generic function to calculate closest rate for mux clock. After this change its selecting correct parent and correct clock rate. apll1 0 0 0 2199999978 0 0 50000 Y acpu0_mux 0 0 0 2199999978 0 0 50000 Y acpu0_div1 0 0 0 549999995 0 0 50000 Y acpu0 0 0 0 549999995 0 0 50000 Y Fixes: 3fde0e16d016 ("drivers: clk: Add ZynqMP clock driver") Signed-off-by: Jay Buddhabhatti Link: https://lore.kernel.org/r/20231129112916.23125-2-jay.buddhabhatti@amd.com Signed-off-by: Stephen Boyd --- drivers/clk/zynqmp/clk-mux-zynqmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c index 60359333f26d..9b5d3050b742 100644 --- a/drivers/clk/zynqmp/clk-mux-zynqmp.c +++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c @@ -89,7 +89,7 @@ static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index) static const struct clk_ops zynqmp_clk_mux_ops = { .get_parent = zynqmp_clk_mux_get_parent, .set_parent = zynqmp_clk_mux_set_parent, - .determine_rate = __clk_mux_determine_rate, + .determine_rate = __clk_mux_determine_rate_closest, }; static const struct clk_ops zynqmp_clk_mux_ro_ops = { -- cgit v1.2.3 From 1fe15be1fb613534ecbac5f8c3f8744f757d237d Mon Sep 17 00:00:00 2001 From: Jay Buddhabhatti Date: Wed, 29 Nov 2023 03:29:16 -0800 Subject: drivers: clk: zynqmp: update divider round rate logic Currently zynqmp divider round rate is considering single parent and calculating rate and parent rate accordingly. But if divider clock flag is set to SET_RATE_PARENT then its not trying to traverse through all parent rate and not selecting best parent rate from that. So use common divider_round_rate() which is traversing through all clock parents and its rate and calculating proper parent rate. Fixes: 3fde0e16d016 ("drivers: clk: Add ZynqMP clock driver") Signed-off-by: Jay Buddhabhatti Link: https://lore.kernel.org/r/20231129112916.23125-3-jay.buddhabhatti@amd.com Signed-off-by: Stephen Boyd --- drivers/clk/zynqmp/divider.c | 66 ++++---------------------------------------- 1 file changed, 5 insertions(+), 61 deletions(-) diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c index 33a3b2a22659..5a00487ae408 100644 --- a/drivers/clk/zynqmp/divider.c +++ b/drivers/clk/zynqmp/divider.c @@ -110,52 +110,6 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, return DIV_ROUND_UP_ULL(parent_rate, value); } -static void zynqmp_get_divider2_val(struct clk_hw *hw, - unsigned long rate, - struct zynqmp_clk_divider *divider, - u32 *bestdiv) -{ - int div1; - int div2; - long error = LONG_MAX; - unsigned long div1_prate; - struct clk_hw *div1_parent_hw; - struct zynqmp_clk_divider *pdivider; - struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw); - - if (!div2_parent_hw) - return; - - pdivider = to_zynqmp_clk_divider(div2_parent_hw); - if (!pdivider) - return; - - div1_parent_hw = clk_hw_get_parent(div2_parent_hw); - if (!div1_parent_hw) - return; - - div1_prate = clk_hw_get_rate(div1_parent_hw); - *bestdiv = 1; - for (div1 = 1; div1 <= pdivider->max_div;) { - for (div2 = 1; div2 <= divider->max_div;) { - long new_error = ((div1_prate / div1) / div2) - rate; - - if (abs(new_error) < abs(error)) { - *bestdiv = div2; - error = new_error; - } - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) - div2 = div2 << 1; - else - div2++; - } - if (pdivider->flags & CLK_DIVIDER_POWER_OF_TWO) - div1 = div1 << 1; - else - div1++; - } -} - /** * zynqmp_clk_divider_round_rate() - Round rate of divider clock * @hw: handle between common and hardware-specific interfaces @@ -174,6 +128,7 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, u32 div_type = divider->div_type; u32 bestdiv; int ret; + u8 width; /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { @@ -193,23 +148,12 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); } - bestdiv = zynqmp_divider_get_val(*prate, rate, divider->flags); - - /* - * In case of two divisors, compute best divider values and return - * divider2 value based on compute value. div1 will be automatically - * set to optimum based on required total divider value. - */ - if (div_type == TYPE_DIV2 && - (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { - zynqmp_get_divider2_val(hw, rate, divider, &bestdiv); - } + width = fls(divider->max_div); - if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac) - bestdiv = rate % *prate ? 1 : bestdiv; + rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags); - bestdiv = min_t(u32, bestdiv, divider->max_div); - *prate = rate * bestdiv; + if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate)) + *prate = rate; return rate; } -- cgit v1.2.3 From 86b1ec23bb8132aee1ab33c98ca1849f2d1ab044 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Thu, 14 Dec 2023 16:21:24 +0530 Subject: dt-bindings: clock: xilinx: add versal compatible Add the devicetree compatible for Versal clocking wizard. Acked-by: Krzysztof Kozlowski Signed-off-by: Shubhrajyoti Datta Link: https://lore.kernel.org/r/20231214105125.26919-2-shubhrajyoti.datta@amd.com Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml index 02bd556bd91a..9d5324dc1027 100644 --- a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml +++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml @@ -20,6 +20,7 @@ properties: - xlnx,clocking-wizard - xlnx,clocking-wizard-v5.2 - xlnx,clocking-wizard-v6.0 + - xlnx,versal-clk-wizard reg: -- cgit v1.2.3 From 3a96393a46e780d14a8592d7265b5a639fa7e5c9 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Thu, 14 Dec 2023 16:21:25 +0530 Subject: clocking-wizard: Add support for versal clocking wizard Add support for Clocking Wizard for Versal adaptive compute acceleration platforms. The Versal clocking wizard differs in the programming model and the register layout. The CLKFBOUT_1 registers are at offset of 0x200 instead of the 0x330 in Versal. In Versal clocking wizard the low and high time is programmed instead of the divisor. Signed-off-by: Shubhrajyoti Datta Link: https://lore.kernel.org/r/20231214105125.26919-3-shubhrajyoti.datta@amd.com [sboyd@kernel.org: Stop initializing spinlock flags] Signed-off-by: Stephen Boyd --- drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 628 ++++++++++++++++++++++++----- 1 file changed, 536 insertions(+), 92 deletions(-) diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index d56822ce6126..6a6e5d9292e8 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -23,15 +23,41 @@ #define WZRD_NUM_OUTPUTS 7 #define WZRD_ACLK_MAX_FREQ 250000000UL -#define WZRD_CLK_CFG_REG(n) (0x200 + 4 * (n)) +#define WZRD_CLK_CFG_REG(v, n) (0x200 + 0x130 * (v) + 4 * (n)) #define WZRD_CLKOUT0_FRAC_EN BIT(18) -#define WZRD_CLKFBOUT_FRAC_EN BIT(26) +#define WZRD_CLKFBOUT_1 0 +#define WZRD_CLKFBOUT_2 1 +#define WZRD_CLKOUT0_1 2 +#define WZRD_CLKOUT0_2 3 +#define WZRD_DESKEW_2 20 +#define WZRD_DIVCLK 21 +#define WZRD_CLKFBOUT_4 51 +#define WZRD_CLKFBOUT_3 48 +#define WZRD_DUTY_CYCLE 2 +#define WZRD_O_DIV 4 + +#define WZRD_CLKFBOUT_FRAC_EN BIT(1) +#define WZRD_CLKFBOUT_PREDIV2 (BIT(11) | BIT(12) | BIT(9)) +#define WZRD_MULT_PREDIV2 (BIT(10) | BIT(9) | BIT(12)) +#define WZRD_CLKFBOUT_EDGE BIT(8) +#define WZRD_P5EN BIT(13) +#define WZRD_P5EN_SHIFT 13 +#define WZRD_P5FEDGE BIT(15) +#define WZRD_DIVCLK_EDGE BIT(10) +#define WZRD_P5FEDGE_SHIFT 15 +#define WZRD_CLKOUT0_PREDIV2 BIT(11) +#define WZRD_EDGE_SHIFT 8 #define WZRD_CLKFBOUT_MULT_SHIFT 8 #define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT) +#define WZRD_CLKFBOUT_L_SHIFT 0 +#define WZRD_CLKFBOUT_H_SHIFT 8 +#define WZRD_CLKFBOUT_L_MASK GENMASK(7, 0) +#define WZRD_CLKFBOUT_H_MASK GENMASK(15, 8) #define WZRD_CLKFBOUT_FRAC_SHIFT 16 #define WZRD_CLKFBOUT_FRAC_MASK (0x3ff << WZRD_CLKFBOUT_FRAC_SHIFT) +#define WZRD_VERSAL_FRAC_MASK GENMASK(5, 0) #define WZRD_DIVCLK_DIVIDE_SHIFT 0 #define WZRD_DIVCLK_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) #define WZRD_CLKOUT_DIVIDE_SHIFT 0 @@ -45,6 +71,7 @@ #define WZRD_DR_STATUS_REG_OFFSET 0x04 #define WZRD_DR_LOCK_BIT_MASK 0x00000001 #define WZRD_DR_INIT_REG_OFFSET 0x25C +#define WZRD_DR_INIT_VERSAL_OFFSET 0x14 #define WZRD_DR_DIV_TO_PHASE_OFFSET 4 #define WZRD_DR_BEGIN_DYNA_RECONF 0x03 #define WZRD_DR_BEGIN_DYNA_RECONF_5_2 0x07 @@ -52,6 +79,8 @@ #define WZRD_USEC_POLL 10 #define WZRD_TIMEOUT_POLL 1000 +#define WZRD_FRAC_GRADIENT 64 +#define PREDIV2_MULT 2 /* Divider limits, from UG572 Table 3-4 for Ultrascale+ */ #define DIV_O 0x01 @@ -65,6 +94,14 @@ #define WZRD_VCO_MAX 1600000000 #define WZRD_O_MIN 1 #define WZRD_O_MAX 128 +#define VER_WZRD_M_MIN 4 +#define VER_WZRD_M_MAX 432 +#define VER_WZRD_D_MIN 1 +#define VER_WZRD_D_MAX 123 +#define VER_WZRD_VCO_MIN 2160000000ULL +#define VER_WZRD_VCO_MAX 4320000000ULL +#define VER_WZRD_O_MIN 2 +#define VER_WZRD_O_MAX 511 #define WZRD_MIN_ERR 20000 #define WZRD_FRAC_POINTS 1000 @@ -135,6 +172,10 @@ struct clk_wzrd_divider { spinlock_t *lock; /* divider lock */ }; +struct versal_clk_data { + bool is_versal; +}; + #define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb) /* maximum frequencies for input/output clocks per speed grade */ @@ -147,6 +188,31 @@ static const unsigned long clk_wzrd_max_freq[] = { /* spin lock variable for clk_wzrd */ static DEFINE_SPINLOCK(clkwzrd_lock); +static unsigned long clk_wzrd_recalc_rate_ver(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + u32 div, p5en, edge, prediv2, all; + unsigned int vall, valh; + + edge = !!(readl(div_addr) & WZRD_CLKFBOUT_EDGE); + p5en = !!(readl(div_addr) & WZRD_P5EN); + prediv2 = !!(readl(div_addr) & WZRD_CLKOUT0_PREDIV2); + vall = readl(div_addr + 4) & WZRD_CLKFBOUT_L_MASK; + valh = readl(div_addr + 4) >> WZRD_CLKFBOUT_H_SHIFT; + all = valh + vall + edge; + if (!all) + all = 1; + + if (prediv2) + div = 2 * all + prediv2 * p5en; + else + div = all; + + return DIV_ROUND_UP_ULL((u64)parent_rate, div); +} + static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -161,19 +227,64 @@ static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } +static int clk_wzrd_ver_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + u32 value, regh, edged, p5en, p5fedge, regval, regval1; + unsigned long flags; + int err; + + spin_lock_irqsave(divider->lock, flags); + + value = DIV_ROUND_CLOSEST(parent_rate, rate); + + regh = (value / 4); + regval1 = readl(div_addr); + regval1 |= WZRD_CLKFBOUT_PREDIV2; + regval1 = regval1 & ~(WZRD_CLKFBOUT_EDGE | WZRD_P5EN | WZRD_P5FEDGE); + if (value % 4 > 1) { + edged = 1; + regval1 |= (edged << WZRD_EDGE_SHIFT); + } + p5fedge = value % 2; + p5en = value % 2; + regval1 = regval1 | p5en << WZRD_P5EN_SHIFT | p5fedge << WZRD_P5FEDGE_SHIFT; + writel(regval1, div_addr); + + regval = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval, div_addr + 4); + /* Check status register */ + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + goto err_reconfig; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, + divider->base + WZRD_DR_INIT_VERSAL_OFFSET); + + /* Check status register */ + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +err_reconfig: + spin_unlock_irqrestore(divider->lock, flags); + return err; +} + static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - int err; - u32 value; - unsigned long flags = 0; struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); void __iomem *div_addr = divider->base + divider->offset; + unsigned long flags; + u32 value; + int err; - if (divider->lock) - spin_lock_irqsave(divider->lock, flags); - else - __acquire(divider->lock); + spin_lock_irqsave(divider->lock, flags); value = DIV_ROUND_CLOSEST(parent_rate, rate); @@ -185,9 +296,9 @@ static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, writel(0x00, div_addr + WZRD_DR_DIV_TO_PHASE_OFFSET); /* Check status register */ - err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, - value, value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); if (err) goto err_reconfig; @@ -198,14 +309,11 @@ static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, divider->base + WZRD_DR_INIT_REG_OFFSET); /* Check status register */ - err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, - value, value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); err_reconfig: - if (divider->lock) - spin_unlock_irqrestore(divider->lock, flags); - else - __release(divider->lock); + spin_unlock_irqrestore(divider->lock, flags); return err; } @@ -223,18 +331,66 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, return *prate / div; } +static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + u64 vco_freq, freq, diff, vcomin, vcomax; + u32 m, d, o; + u32 mmin, mmax, dmin, dmax, omin, omax; + + mmin = VER_WZRD_M_MIN; + mmax = VER_WZRD_M_MAX; + dmin = VER_WZRD_D_MIN; + dmax = VER_WZRD_D_MAX; + omin = VER_WZRD_O_MIN; + omax = VER_WZRD_O_MAX; + vcomin = VER_WZRD_VCO_MIN; + vcomax = VER_WZRD_VCO_MAX; + + for (m = mmin; m <= mmax; m++) { + for (d = dmin; d <= dmax; d++) { + vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d); + if (vco_freq >= vcomin && vco_freq <= vcomax) { + for (o = omin; o <= omax; o++) { + freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o); + diff = abs(freq - rate); + + if (diff < WZRD_MIN_ERR) { + divider->m = m; + divider->d = d; + divider->o = o; + return 0; + } + } + } + } + } + return -EBUSY; +} + static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); - unsigned long vco_freq, freq, diff; + u64 vco_freq, freq, diff, vcomin, vcomax; u32 m, d, o; - - for (m = WZRD_M_MIN; m <= WZRD_M_MAX; m++) { - for (d = WZRD_D_MIN; d <= WZRD_D_MAX; d++) { + u32 mmin, mmax, dmin, dmax, omin, omax; + + mmin = WZRD_M_MIN; + mmax = WZRD_M_MAX; + dmin = WZRD_D_MIN; + dmax = WZRD_D_MAX; + omin = WZRD_O_MIN; + omax = WZRD_O_MAX; + vcomin = WZRD_VCO_MIN; + vcomax = WZRD_VCO_MAX; + + for (m = mmin; m <= mmax; m++) { + for (d = dmin; d <= dmax; d++) { vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d); - if (vco_freq >= WZRD_VCO_MIN && vco_freq <= WZRD_VCO_MAX) { - for (o = WZRD_O_MIN; o <= WZRD_O_MAX; o++) { + if (vco_freq >= vcomin && vco_freq <= vcomax) { + for (o = omin; o <= omax; o++) { freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o); diff = abs(freq - rate); @@ -251,12 +407,99 @@ static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, return -EBUSY; } +static int clk_wzrd_reconfig(struct clk_wzrd_divider *divider, void __iomem *div_addr) +{ + u32 value; + int err; + + /* Check status register */ + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + return -ETIMEDOUT; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, div_addr); + /* Check status register */ + return readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +} + +static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u32 regh, edged, p5en, p5fedge, value2, m, regval, regval1, value; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr; + int err; + + err = clk_wzrd_get_divisors_ver(hw, rate, parent_rate); + if (err) + return err; + + writel(0, divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_4)); + + m = divider->m; + edged = m % WZRD_DUTY_CYCLE; + regh = m / WZRD_DUTY_CYCLE; + regval1 = readl(divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKFBOUT_1)); + regval1 |= WZRD_MULT_PREDIV2; + if (edged) + regval1 = regval1 | WZRD_CLKFBOUT_EDGE; + else + regval1 = regval1 & ~WZRD_CLKFBOUT_EDGE; + + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKFBOUT_1)); + regval1 = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKFBOUT_2)); + + value2 = divider->d; + edged = value2 % WZRD_DUTY_CYCLE; + regh = (value2 / WZRD_DUTY_CYCLE); + regval1 = FIELD_PREP(WZRD_DIVCLK_EDGE, edged); + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_DESKEW_2)); + regval1 = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, WZRD_DIVCLK)); + + value = divider->o; + regh = value / WZRD_O_DIV; + regval1 = readl(divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKOUT0_1)); + regval1 |= WZRD_CLKFBOUT_PREDIV2; + regval1 = regval1 & ~(WZRD_CLKFBOUT_EDGE | WZRD_P5EN | WZRD_P5FEDGE); + + if (value % WZRD_O_DIV > 1) { + edged = 1; + regval1 |= edged << WZRD_CLKFBOUT_H_SHIFT; + } + + p5fedge = value % WZRD_DUTY_CYCLE; + p5en = value % WZRD_DUTY_CYCLE; + + regval1 = regval1 | FIELD_PREP(WZRD_P5EN, p5en) | FIELD_PREP(WZRD_P5FEDGE, p5fedge); + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKOUT0_1)); + regval = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKOUT0_2)); + div_addr = divider->base + WZRD_DR_INIT_VERSAL_OFFSET; + + return clk_wzrd_reconfig(divider, div_addr); +} + static int clk_wzrd_dynamic_all_nolock(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); unsigned long vco_freq, rate_div, clockout0_div; - u32 reg, pre, value, f; + void __iomem *div_addr = divider->base; + u32 reg, pre, f; int err; err = clk_wzrd_get_divisors(hw, rate, parent_rate); @@ -275,35 +518,22 @@ static int clk_wzrd_dynamic_all_nolock(struct clk_hw *hw, unsigned long rate, reg = FIELD_PREP(WZRD_CLKOUT_DIVIDE_MASK, clockout0_div) | FIELD_PREP(WZRD_CLKOUT0_FRAC_MASK, f); - writel(reg, divider->base + WZRD_CLK_CFG_REG(2)); + writel(reg, divider->base + WZRD_CLK_CFG_REG(0, 2)); /* Set divisor and clear phase offset */ reg = FIELD_PREP(WZRD_CLKFBOUT_MULT_MASK, divider->m) | FIELD_PREP(WZRD_DIVCLK_DIVIDE_MASK, divider->d); - writel(reg, divider->base + WZRD_CLK_CFG_REG(0)); - writel(divider->o, divider->base + WZRD_CLK_CFG_REG(2)); - writel(0, divider->base + WZRD_CLK_CFG_REG(3)); - /* Check status register */ - err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, - value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); - if (err) - return -ETIMEDOUT; - - /* Initiate reconfiguration */ - writel(WZRD_DR_BEGIN_DYNA_RECONF, - divider->base + WZRD_DR_INIT_REG_OFFSET); - - /* Check status register */ - return readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, - value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + writel(reg, divider->base + WZRD_CLK_CFG_REG(0, 0)); + writel(divider->o, divider->base + WZRD_CLK_CFG_REG(0, 2)); + writel(0, divider->base + WZRD_CLK_CFG_REG(0, 3)); + div_addr = divider->base + WZRD_DR_INIT_REG_OFFSET; + return clk_wzrd_reconfig(divider, div_addr); } static int clk_wzrd_dynamic_all(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); - unsigned long flags = 0; + unsigned long flags; int ret; spin_lock_irqsave(divider->lock, flags); @@ -315,21 +545,103 @@ static int clk_wzrd_dynamic_all(struct clk_hw *hw, unsigned long rate, return ret; } +static int clk_wzrd_dynamic_all_ver(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + unsigned long flags; + int ret; + + spin_lock_irqsave(divider->lock, flags); + + ret = clk_wzrd_dynamic_ver_all_nolock(hw, rate, parent_rate); + + spin_unlock_irqrestore(divider->lock, flags); + + return ret; +} + static unsigned long clk_wzrd_recalc_rate_all(struct clk_hw *hw, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); u32 m, d, o, div, reg, f; - reg = readl(divider->base + WZRD_CLK_CFG_REG(0)); + reg = readl(divider->base + WZRD_CLK_CFG_REG(0, 0)); d = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg); m = FIELD_GET(WZRD_CLKFBOUT_MULT_MASK, reg); - reg = readl(divider->base + WZRD_CLK_CFG_REG(2)); + reg = readl(divider->base + WZRD_CLK_CFG_REG(0, 2)); o = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg); f = FIELD_GET(WZRD_CLKOUT0_FRAC_MASK, reg); div = DIV_ROUND_CLOSEST(d * (WZRD_FRAC_POINTS * o + f), WZRD_FRAC_POINTS); return divider_recalc_rate(hw, parent_rate * m, div, divider->table, + divider->flags, divider->width); +} + +static unsigned long clk_wzrd_recalc_rate_all_ver(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + u32 edged, div2, p5en, edge, prediv2, all, regl, regh, mult; + u32 div, reg; + + edge = !!(readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_1)) & + WZRD_CLKFBOUT_EDGE); + + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_2)); + regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg); + regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg); + + mult = regl + regh + edge; + if (!mult) + mult = 1; + + regl = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_4)) & + WZRD_CLKFBOUT_FRAC_EN; + if (regl) { + regl = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_3)) + & WZRD_VERSAL_FRAC_MASK; + mult = mult * WZRD_FRAC_GRADIENT + regl; + parent_rate = DIV_ROUND_CLOSEST((parent_rate * mult), WZRD_FRAC_GRADIENT); + } else { + parent_rate = parent_rate * mult; + } + + /* O Calculation */ + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKOUT0_1)); + edged = FIELD_GET(WZRD_CLKFBOUT_EDGE, reg); + p5en = FIELD_GET(WZRD_P5EN, reg); + prediv2 = FIELD_GET(WZRD_CLKOUT0_PREDIV2, reg); + + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKOUT0_2)); + /* Low time */ + regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg); + /* High time */ + regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg); + all = regh + regl + edged; + if (!all) + all = 1; + + if (prediv2) + div2 = PREDIV2_MULT * all + p5en; + else + div2 = all; + + /* D calculation */ + edged = !!(readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_DESKEW_2)) & + WZRD_DIVCLK_EDGE); + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_DIVCLK)); + /* Low time */ + regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg); + /* High time */ + regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg); + div = regl + regh + edged; + if (!div) + div = 1; + + div = div * div2; + return divider_recalc_rate(hw, parent_rate, div, divider->table, divider->flags, divider->width); } @@ -360,6 +672,18 @@ static long clk_wzrd_round_rate_all(struct clk_hw *hw, unsigned long rate, return rate; } +static const struct clk_ops clk_wzrd_ver_divider_ops = { + .round_rate = clk_wzrd_round_rate, + .set_rate = clk_wzrd_ver_dynamic_reconfig, + .recalc_rate = clk_wzrd_recalc_rate_ver, +}; + +static const struct clk_ops clk_wzrd_ver_div_all_ops = { + .round_rate = clk_wzrd_round_rate_all, + .set_rate = clk_wzrd_dynamic_all_ver, + .recalc_rate = clk_wzrd_recalc_rate_all_ver, +}; + static const struct clk_ops clk_wzrd_clk_divider_ops = { .round_rate = clk_wzrd_round_rate, .set_rate = clk_wzrd_dynamic_reconfig, @@ -484,6 +808,53 @@ static struct clk *clk_wzrd_register_divf(struct device *dev, return hw->clk; } +static struct clk *clk_wzrd_ver_register_divider(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, + u16 offset, + u8 shift, u8 width, + u8 clk_divider_flags, + u32 div_type, + spinlock_t *lock) +{ + struct clk_wzrd_divider *div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) + init.ops = &clk_divider_ro_ops; + else if (div_type == DIV_O) + init.ops = &clk_wzrd_ver_divider_ops; + else + init.ops = &clk_wzrd_ver_div_all_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + div->base = base; + div->offset = offset; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + + hw = &div->hw; + ret = devm_clk_hw_register(dev, hw); + if (ret) + return ERR_PTR(ret); + + return hw->clk; +} + static struct clk *clk_wzrd_register_divider(struct device *dev, const char *name, const char *parent_name, @@ -588,18 +959,24 @@ static int __maybe_unused clk_wzrd_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend, clk_wzrd_resume); +static const struct versal_clk_data versal_data = { + .is_versal = true, +}; + static int clk_wzrd_probe(struct platform_device *pdev) { - int i, ret; + const char *clkout_name, *clk_name, *clk_mul_name; + u32 regl, regh, edge, regld, reghd, edged, div; + struct device_node *np = pdev->dev.of_node; + const struct versal_clk_data *data; + struct clk_wzrd *clk_wzrd; + unsigned long flags = 0; + void __iomem *ctrl_reg; u32 reg, reg_f, mult; + bool is_versal = false; unsigned long rate; - const char *clk_name; - void __iomem *ctrl_reg; - struct clk_wzrd *clk_wzrd; - const char *clkout_name; - struct device_node *np = pdev->dev.of_node; int nr_outputs; - unsigned long flags = 0; + int i, ret; clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); if (!clk_wzrd) @@ -641,6 +1018,10 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } + data = device_get_match_data(&pdev->dev); + if (data) + is_versal = data->is_versal; + ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs); if (ret || nr_outputs > WZRD_NUM_OUTPUTS) { ret = -EINVAL; @@ -653,26 +1034,61 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } - if (nr_outputs == 1) { - clk_wzrd->clkout[0] = clk_wzrd_register_divider + if (is_versal) { + if (nr_outputs == 1) { + clk_wzrd->clkout[0] = clk_wzrd_ver_register_divider (&pdev->dev, clkout_name, __clk_get_name(clk_wzrd->clk_in1), 0, - clk_wzrd->base, WZRD_CLK_CFG_REG(3), + clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3), WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, DIV_ALL, &clkwzrd_lock); - goto out; - } - - reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)); - reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; - reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT; + goto out; + } + /* register multiplier */ + edge = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0)) & + BIT(8)); + regl = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 1)) & + WZRD_CLKFBOUT_L_MASK) >> WZRD_CLKFBOUT_L_SHIFT; + regh = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 1)) & + WZRD_CLKFBOUT_H_MASK) >> WZRD_CLKFBOUT_H_SHIFT; + mult = regl + regh + edge; + if (!mult) + mult = 1; + mult = mult * WZRD_FRAC_GRADIENT; + + regl = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 51)) & + WZRD_CLKFBOUT_FRAC_EN; + if (regl) { + regl = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 48)) & + WZRD_VERSAL_FRAC_MASK; + mult = mult + regl; + } + div = 64; + } else { + if (nr_outputs == 1) { + clk_wzrd->clkout[0] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, + __clk_get_name(clk_wzrd->clk_in1), 0, + clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + DIV_ALL, &clkwzrd_lock); - reg = reg & WZRD_CLKFBOUT_MULT_MASK; - reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT; - mult = (reg * 1000) + reg_f; + goto out; + } + reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0)); + reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; + reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT; + + reg = reg & WZRD_CLKFBOUT_MULT_MASK; + reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT; + mult = (reg * 1000) + reg_f; + div = 1000; + } clk_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; @@ -681,7 +1097,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clk_in1), - 0, mult, 1000); + 0, mult, div); if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) { dev_err(&pdev->dev, "unable to register fixed-factor clock\n"); ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]); @@ -694,13 +1110,29 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_rm_int_clk; } - ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(0); - /* register div */ - clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider + if (is_versal) { + edged = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 20)) & + BIT(10)); + regld = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 21)) & + WZRD_CLKFBOUT_L_MASK) >> WZRD_CLKFBOUT_L_SHIFT; + reghd = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 21)) & + WZRD_CLKFBOUT_H_MASK) >> WZRD_CLKFBOUT_H_SHIFT; + div = (regld + reghd + edged); + if (!div) + div = 1; + + clk_mul_name = __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]); + clk_wzrd->clks_internal[wzrd_clk_mul_div] = + clk_register_fixed_factor(&pdev->dev, clk_name, + clk_mul_name, 0, 1, div); + } else { + ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0); + clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]), flags, ctrl_reg, 0, 8, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, &clkwzrd_lock); + } if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) { dev_err(&pdev->dev, "unable to register divider clock\n"); ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]); @@ -716,24 +1148,35 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_rm_int_clk; } - if (!i) - clk_wzrd->clkout[i] = clk_wzrd_register_divf - (&pdev->dev, clkout_name, - clk_name, flags, - clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), - WZRD_CLKOUT_DIVIDE_SHIFT, - WZRD_CLKOUT_DIVIDE_WIDTH, - CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - DIV_O, &clkwzrd_lock); - else - clk_wzrd->clkout[i] = clk_wzrd_register_divider - (&pdev->dev, clkout_name, - clk_name, 0, - clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), - WZRD_CLKOUT_DIVIDE_SHIFT, - WZRD_CLKOUT_DIVIDE_WIDTH, - CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - DIV_O, &clkwzrd_lock); + if (is_versal) { + clk_wzrd->clkout[i] = clk_wzrd_ver_register_divider + (&pdev->dev, + clkout_name, clk_name, 0, + clk_wzrd->base, + (WZRD_CLK_CFG_REG(is_versal, 3) + i * 8), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO, + DIV_O, &clkwzrd_lock); + } else { + if (!i) + clk_wzrd->clkout[i] = clk_wzrd_register_divf + (&pdev->dev, clkout_name, clk_name, flags, clk_wzrd->base, + (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + DIV_O, &clkwzrd_lock); + else + clk_wzrd->clkout[i] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, clk_name, 0, clk_wzrd->base, + (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + DIV_O, &clkwzrd_lock); + } if (IS_ERR(clk_wzrd->clkout[i])) { int j; @@ -799,9 +1242,10 @@ static void clk_wzrd_remove(struct platform_device *pdev) } static const struct of_device_id clk_wzrd_ids[] = { - { .compatible = "xlnx,clocking-wizard" }, - { .compatible = "xlnx,clocking-wizard-v5.2" }, - { .compatible = "xlnx,clocking-wizard-v6.0" }, + { .compatible = "xlnx,versal-clk-wizard", .data = &versal_data }, + { .compatible = "xlnx,clocking-wizard" }, + { .compatible = "xlnx,clocking-wizard-v5.2" }, + { .compatible = "xlnx,clocking-wizard-v6.0" }, { }, }; MODULE_DEVICE_TABLE(of, clk_wzrd_ids); -- cgit v1.2.3 From 3ac7ca599515d335a55009c9c1016f244ef82a79 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Fri, 8 Dec 2023 15:36:56 +0100 Subject: clk: stm32mp1: move stm32mp1 clock driver into stm32 directory Move all STM32MP clock drivers into same directory (stm32). Signed-off-by: Gabriel Fernandez Link: https://lore.kernel.org/r/20231208143700.354785-2-gabriel.fernandez@foss.st.com Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 11 +- drivers/clk/Makefile | 1 - drivers/clk/clk-stm32mp1.c | 2459 -------------------------------------- drivers/clk/stm32/Kconfig | 29 + drivers/clk/stm32/Makefile | 1 + drivers/clk/stm32/clk-stm32mp1.c | 2459 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 2490 insertions(+), 2470 deletions(-) delete mode 100644 drivers/clk/clk-stm32mp1.c create mode 100644 drivers/clk/stm32/Kconfig create mode 100644 drivers/clk/stm32/clk-stm32mp1.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c30d0d396f7a..50af5fc7f570 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -414,16 +414,6 @@ config COMMON_CLK_VC7 Renesas Versaclock7 is a family of configurable clock generator and jitter attenuator ICs with fractional and integer dividers. -config COMMON_CLK_STM32MP135 - def_bool COMMON_CLK && MACH_STM32MP13 - help - Support for stm32mp135 SoC family clocks - -config COMMON_CLK_STM32MP157 - def_bool COMMON_CLK && MACH_STM32MP157 - help - Support for stm32mp157 SoC family clocks - config COMMON_CLK_STM32F def_bool COMMON_CLK && (MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746) help @@ -504,6 +494,7 @@ source "drivers/clk/starfive/Kconfig" source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" +source "drivers/clk/stm32/Kconfig" source "drivers/clk/ti/Kconfig" source "drivers/clk/uniphier/Kconfig" source "drivers/clk/visconti/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ed71f2e0ee36..14fa8d4ecc1f 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_COMMON_CLK_SP7021) += clk-sp7021.o obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o -obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_CLK_TWL) += clk-twl.o diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c deleted file mode 100644 index 939779f66867..000000000000 --- a/drivers/clk/clk-stm32mp1.c +++ /dev/null @@ -1,2459 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) STMicroelectronics 2018 - All Rights Reserved - * Author: Olivier Bideau for STMicroelectronics. - * Author: Gabriel Fernandez for STMicroelectronics. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static DEFINE_SPINLOCK(rlock); - -#define RCC_OCENSETR 0x0C -#define RCC_HSICFGR 0x18 -#define RCC_RDLSICR 0x144 -#define RCC_PLL1CR 0x80 -#define RCC_PLL1CFGR1 0x84 -#define RCC_PLL1CFGR2 0x88 -#define RCC_PLL2CR 0x94 -#define RCC_PLL2CFGR1 0x98 -#define RCC_PLL2CFGR2 0x9C -#define RCC_PLL3CR 0x880 -#define RCC_PLL3CFGR1 0x884 -#define RCC_PLL3CFGR2 0x888 -#define RCC_PLL4CR 0x894 -#define RCC_PLL4CFGR1 0x898 -#define RCC_PLL4CFGR2 0x89C -#define RCC_APB1ENSETR 0xA00 -#define RCC_APB2ENSETR 0xA08 -#define RCC_APB3ENSETR 0xA10 -#define RCC_APB4ENSETR 0x200 -#define RCC_APB5ENSETR 0x208 -#define RCC_AHB2ENSETR 0xA18 -#define RCC_AHB3ENSETR 0xA20 -#define RCC_AHB4ENSETR 0xA28 -#define RCC_AHB5ENSETR 0x210 -#define RCC_AHB6ENSETR 0x218 -#define RCC_AHB6LPENSETR 0x318 -#define RCC_RCK12SELR 0x28 -#define RCC_RCK3SELR 0x820 -#define RCC_RCK4SELR 0x824 -#define RCC_MPCKSELR 0x20 -#define RCC_ASSCKSELR 0x24 -#define RCC_MSSCKSELR 0x48 -#define RCC_SPI6CKSELR 0xC4 -#define RCC_SDMMC12CKSELR 0x8F4 -#define RCC_SDMMC3CKSELR 0x8F8 -#define RCC_FMCCKSELR 0x904 -#define RCC_I2C46CKSELR 0xC0 -#define RCC_I2C12CKSELR 0x8C0 -#define RCC_I2C35CKSELR 0x8C4 -#define RCC_UART1CKSELR 0xC8 -#define RCC_QSPICKSELR 0x900 -#define RCC_ETHCKSELR 0x8FC -#define RCC_RNG1CKSELR 0xCC -#define RCC_RNG2CKSELR 0x920 -#define RCC_GPUCKSELR 0x938 -#define RCC_USBCKSELR 0x91C -#define RCC_STGENCKSELR 0xD4 -#define RCC_SPDIFCKSELR 0x914 -#define RCC_SPI2S1CKSELR 0x8D8 -#define RCC_SPI2S23CKSELR 0x8DC -#define RCC_SPI2S45CKSELR 0x8E0 -#define RCC_CECCKSELR 0x918 -#define RCC_LPTIM1CKSELR 0x934 -#define RCC_LPTIM23CKSELR 0x930 -#define RCC_LPTIM45CKSELR 0x92C -#define RCC_UART24CKSELR 0x8E8 -#define RCC_UART35CKSELR 0x8EC -#define RCC_UART6CKSELR 0x8E4 -#define RCC_UART78CKSELR 0x8F0 -#define RCC_FDCANCKSELR 0x90C -#define RCC_SAI1CKSELR 0x8C8 -#define RCC_SAI2CKSELR 0x8CC -#define RCC_SAI3CKSELR 0x8D0 -#define RCC_SAI4CKSELR 0x8D4 -#define RCC_ADCCKSELR 0x928 -#define RCC_MPCKDIVR 0x2C -#define RCC_DSICKSELR 0x924 -#define RCC_CPERCKSELR 0xD0 -#define RCC_MCO1CFGR 0x800 -#define RCC_MCO2CFGR 0x804 -#define RCC_BDCR 0x140 -#define RCC_AXIDIVR 0x30 -#define RCC_MCUDIVR 0x830 -#define RCC_APB1DIVR 0x834 -#define RCC_APB2DIVR 0x838 -#define RCC_APB3DIVR 0x83C -#define RCC_APB4DIVR 0x3C -#define RCC_APB5DIVR 0x40 -#define RCC_TIMG1PRER 0x828 -#define RCC_TIMG2PRER 0x82C -#define RCC_RTCDIVR 0x44 -#define RCC_DBGCFGR 0x80C - -#define RCC_CLR 0x4 - -static const char * const ref12_parents[] = { - "ck_hsi", "ck_hse" -}; - -static const char * const ref3_parents[] = { - "ck_hsi", "ck_hse", "ck_csi" -}; - -static const char * const ref4_parents[] = { - "ck_hsi", "ck_hse", "ck_csi" -}; - -static const char * const cpu_src[] = { - "ck_hsi", "ck_hse", "pll1_p" -}; - -static const char * const axi_src[] = { - "ck_hsi", "ck_hse", "pll2_p" -}; - -static const char * const per_src[] = { - "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const mcu_src[] = { - "ck_hsi", "ck_hse", "ck_csi", "pll3_p" -}; - -static const char * const sdmmc12_src[] = { - "ck_axi", "pll3_r", "pll4_p", "ck_hsi" -}; - -static const char * const sdmmc3_src[] = { - "ck_mcu", "pll3_r", "pll4_p", "ck_hsi" -}; - -static const char * const fmc_src[] = { - "ck_axi", "pll3_r", "pll4_p", "ck_per" -}; - -static const char * const qspi_src[] = { - "ck_axi", "pll3_r", "pll4_p", "ck_per" -}; - -static const char * const eth_src[] = { - "pll4_p", "pll3_q" -}; - -static const struct clk_parent_data ethrx_src[] = { - { .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" }, -}; - -static const char * const rng_src[] = { - "ck_csi", "pll4_r", "ck_lse", "ck_lsi" -}; - -static const char * const usbphy_src[] = { - "ck_hse", "pll4_r", "clk-hse-div2" -}; - -static const char * const usbo_src[] = { - "pll4_r", "ck_usbo_48m" -}; - -static const char * const stgen_src[] = { - "ck_hsi", "ck_hse" -}; - -static const char * const spdif_src[] = { - "pll4_p", "pll3_q", "ck_hsi" -}; - -static const char * const spi123_src[] = { - "pll4_p", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" -}; - -static const char * const spi45_src[] = { - "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const spi6_src[] = { - "pclk5", "pll4_q", "ck_hsi", "ck_csi", "ck_hse", "pll3_q" -}; - -static const char * const cec_src[] = { - "ck_lse", "ck_lsi", "ck_csi" -}; - -static const char * const i2c12_src[] = { - "pclk1", "pll4_r", "ck_hsi", "ck_csi" -}; - -static const char * const i2c35_src[] = { - "pclk1", "pll4_r", "ck_hsi", "ck_csi" -}; - -static const char * const i2c46_src[] = { - "pclk5", "pll3_q", "ck_hsi", "ck_csi" -}; - -static const char * const lptim1_src[] = { - "pclk1", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" -}; - -static const char * const lptim23_src[] = { - "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi" -}; - -static const char * const lptim45_src[] = { - "pclk3", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" -}; - -static const char * const usart1_src[] = { - "pclk5", "pll3_q", "ck_hsi", "ck_csi", "pll4_q", "ck_hse" -}; - -static const char * const usart234578_src[] = { - "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const usart6_src[] = { - "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const fdcan_src[] = { - "ck_hse", "pll3_q", "pll4_q", "pll4_r" -}; - -static const char * const sai_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" -}; - -static const char * const sai2_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r" -}; - -static const char * const adc12_src[] = { - "pll4_r", "ck_per", "pll3_q" -}; - -static const char * const dsi_src[] = { - "ck_dsi_phy", "pll4_p" -}; - -static const char * const rtc_src[] = { - "off", "ck_lse", "ck_lsi", "ck_hse" -}; - -static const char * const mco1_src[] = { - "ck_hsi", "ck_hse", "ck_csi", "ck_lsi", "ck_lse" -}; - -static const char * const mco2_src[] = { - "ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi" -}; - -static const char * const ck_trace_src[] = { - "ck_axi" -}; - -static const struct clk_div_table axi_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, - { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, - { 0 }, -}; - -static const struct clk_div_table mcu_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, - { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, - { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 }, - { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, - { 0 }, -}; - -static const struct clk_div_table apb_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, - { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, - { 0 }, -}; - -static const struct clk_div_table ck_trace_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, - { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, - { 0 }, -}; - -#define MAX_MUX_CLK 2 - -struct stm32_mmux { - u8 nbr_clk; - struct clk_hw *hws[MAX_MUX_CLK]; -}; - -struct stm32_clk_mmux { - struct clk_mux mux; - struct stm32_mmux *mmux; -}; - -struct stm32_mgate { - u8 nbr_clk; - u32 flag; -}; - -struct stm32_clk_mgate { - struct clk_gate gate; - struct stm32_mgate *mgate; - u32 mask; -}; - -struct clock_config { - u32 id; - const char *name; - const char *parent_name; - const char * const *parent_names; - const struct clk_parent_data *parent_data; - int num_parents; - unsigned long flags; - void *cfg; - struct clk_hw * (*func)(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg); -}; - -#define NO_ID ~0 - -struct gate_cfg { - u32 reg_off; - u8 bit_idx; - u8 gate_flags; -}; - -struct fixed_factor_cfg { - unsigned int mult; - unsigned int div; -}; - -struct div_cfg { - u32 reg_off; - u8 shift; - u8 width; - u8 div_flags; - const struct clk_div_table *table; -}; - -struct mux_cfg { - u32 reg_off; - u8 shift; - u8 width; - u8 mux_flags; - u32 *table; -}; - -struct stm32_gate_cfg { - struct gate_cfg *gate; - struct stm32_mgate *mgate; - const struct clk_ops *ops; -}; - -struct stm32_div_cfg { - struct div_cfg *div; - const struct clk_ops *ops; -}; - -struct stm32_mux_cfg { - struct mux_cfg *mux; - struct stm32_mmux *mmux; - const struct clk_ops *ops; -}; - -/* STM32 Composite clock */ -struct stm32_composite_cfg { - const struct stm32_gate_cfg *gate; - const struct stm32_div_cfg *div; - const struct stm32_mux_cfg *mux; -}; - -static struct clk_hw * -_clk_hw_register_gate(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct gate_cfg *gate_cfg = cfg->cfg; - - return clk_hw_register_gate(dev, - cfg->name, - cfg->parent_name, - cfg->flags, - gate_cfg->reg_off + base, - gate_cfg->bit_idx, - gate_cfg->gate_flags, - lock); -} - -static struct clk_hw * -_clk_hw_register_fixed_factor(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct fixed_factor_cfg *ff_cfg = cfg->cfg; - - return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name, - cfg->flags, ff_cfg->mult, - ff_cfg->div); -} - -static struct clk_hw * -_clk_hw_register_divider_table(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct div_cfg *div_cfg = cfg->cfg; - - return clk_hw_register_divider_table(dev, - cfg->name, - cfg->parent_name, - cfg->flags, - div_cfg->reg_off + base, - div_cfg->shift, - div_cfg->width, - div_cfg->div_flags, - div_cfg->table, - lock); -} - -static struct clk_hw * -_clk_hw_register_mux(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct mux_cfg *mux_cfg = cfg->cfg; - - return clk_hw_register_mux(dev, cfg->name, cfg->parent_names, - cfg->num_parents, cfg->flags, - mux_cfg->reg_off + base, mux_cfg->shift, - mux_cfg->width, mux_cfg->mux_flags, lock); -} - -/* MP1 Gate clock with set & clear registers */ - -static int mp1_gate_clk_enable(struct clk_hw *hw) -{ - if (!clk_gate_ops.is_enabled(hw)) - clk_gate_ops.enable(hw); - - return 0; -} - -static void mp1_gate_clk_disable(struct clk_hw *hw) -{ - struct clk_gate *gate = to_clk_gate(hw); - unsigned long flags = 0; - - if (clk_gate_ops.is_enabled(hw)) { - spin_lock_irqsave(gate->lock, flags); - writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR); - spin_unlock_irqrestore(gate->lock, flags); - } -} - -static const struct clk_ops mp1_gate_clk_ops = { - .enable = mp1_gate_clk_enable, - .disable = mp1_gate_clk_disable, - .is_enabled = clk_gate_is_enabled, -}; - -static struct clk_hw *_get_stm32_mux(struct device *dev, void __iomem *base, - const struct stm32_mux_cfg *cfg, - spinlock_t *lock) -{ - struct stm32_clk_mmux *mmux; - struct clk_mux *mux; - struct clk_hw *mux_hw; - - if (cfg->mmux) { - mmux = devm_kzalloc(dev, sizeof(*mmux), GFP_KERNEL); - if (!mmux) - return ERR_PTR(-ENOMEM); - - mmux->mux.reg = cfg->mux->reg_off + base; - mmux->mux.shift = cfg->mux->shift; - mmux->mux.mask = (1 << cfg->mux->width) - 1; - mmux->mux.flags = cfg->mux->mux_flags; - mmux->mux.table = cfg->mux->table; - mmux->mux.lock = lock; - mmux->mmux = cfg->mmux; - mux_hw = &mmux->mux.hw; - cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; - - } else { - mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); - if (!mux) - return ERR_PTR(-ENOMEM); - - mux->reg = cfg->mux->reg_off + base; - mux->shift = cfg->mux->shift; - mux->mask = (1 << cfg->mux->width) - 1; - mux->flags = cfg->mux->mux_flags; - mux->table = cfg->mux->table; - mux->lock = lock; - mux_hw = &mux->hw; - } - - return mux_hw; -} - -static struct clk_hw *_get_stm32_div(struct device *dev, void __iomem *base, - const struct stm32_div_cfg *cfg, - spinlock_t *lock) -{ - struct clk_divider *div; - - div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); - - if (!div) - return ERR_PTR(-ENOMEM); - - div->reg = cfg->div->reg_off + base; - div->shift = cfg->div->shift; - div->width = cfg->div->width; - div->flags = cfg->div->div_flags; - div->table = cfg->div->table; - div->lock = lock; - - return &div->hw; -} - -static struct clk_hw *_get_stm32_gate(struct device *dev, void __iomem *base, - const struct stm32_gate_cfg *cfg, - spinlock_t *lock) -{ - struct stm32_clk_mgate *mgate; - struct clk_gate *gate; - struct clk_hw *gate_hw; - - if (cfg->mgate) { - mgate = devm_kzalloc(dev, sizeof(*mgate), GFP_KERNEL); - if (!mgate) - return ERR_PTR(-ENOMEM); - - mgate->gate.reg = cfg->gate->reg_off + base; - mgate->gate.bit_idx = cfg->gate->bit_idx; - mgate->gate.flags = cfg->gate->gate_flags; - mgate->gate.lock = lock; - mgate->mask = BIT(cfg->mgate->nbr_clk++); - - mgate->mgate = cfg->mgate; - - gate_hw = &mgate->gate.hw; - - } else { - gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); - if (!gate) - return ERR_PTR(-ENOMEM); - - gate->reg = cfg->gate->reg_off + base; - gate->bit_idx = cfg->gate->bit_idx; - gate->flags = cfg->gate->gate_flags; - gate->lock = lock; - - gate_hw = &gate->hw; - } - - return gate_hw; -} - -static struct clk_hw * -clk_stm32_register_gate_ops(struct device *dev, - const char *name, - const char *parent_name, - const struct clk_parent_data *parent_data, - unsigned long flags, - void __iomem *base, - const struct stm32_gate_cfg *cfg, - spinlock_t *lock) -{ - struct clk_init_data init = { NULL }; - struct clk_hw *hw; - int ret; - - init.name = name; - if (parent_name) - init.parent_names = &parent_name; - if (parent_data) - init.parent_data = parent_data; - init.num_parents = 1; - init.flags = flags; - - init.ops = &clk_gate_ops; - - if (cfg->ops) - init.ops = cfg->ops; - - hw = _get_stm32_gate(dev, base, cfg, lock); - if (IS_ERR(hw)) - return ERR_PTR(-ENOMEM); - - hw->init = &init; - - ret = clk_hw_register(dev, hw); - if (ret) - hw = ERR_PTR(ret); - - return hw; -} - -static struct clk_hw * -clk_stm32_register_composite(struct device *dev, - const char *name, const char * const *parent_names, - const struct clk_parent_data *parent_data, - int num_parents, void __iomem *base, - const struct stm32_composite_cfg *cfg, - unsigned long flags, spinlock_t *lock) -{ - const struct clk_ops *mux_ops, *div_ops, *gate_ops; - struct clk_hw *mux_hw, *div_hw, *gate_hw; - - mux_hw = NULL; - div_hw = NULL; - gate_hw = NULL; - mux_ops = NULL; - div_ops = NULL; - gate_ops = NULL; - - if (cfg->mux) { - mux_hw = _get_stm32_mux(dev, base, cfg->mux, lock); - - if (!IS_ERR(mux_hw)) { - mux_ops = &clk_mux_ops; - - if (cfg->mux->ops) - mux_ops = cfg->mux->ops; - } - } - - if (cfg->div) { - div_hw = _get_stm32_div(dev, base, cfg->div, lock); - - if (!IS_ERR(div_hw)) { - div_ops = &clk_divider_ops; - - if (cfg->div->ops) - div_ops = cfg->div->ops; - } - } - - if (cfg->gate) { - gate_hw = _get_stm32_gate(dev, base, cfg->gate, lock); - - if (!IS_ERR(gate_hw)) { - gate_ops = &clk_gate_ops; - - if (cfg->gate->ops) - gate_ops = cfg->gate->ops; - } - } - - return clk_hw_register_composite(dev, name, parent_names, num_parents, - mux_hw, mux_ops, div_hw, div_ops, - gate_hw, gate_ops, flags); -} - -#define to_clk_mgate(_gate) container_of(_gate, struct stm32_clk_mgate, gate) - -static int mp1_mgate_clk_enable(struct clk_hw *hw) -{ - struct clk_gate *gate = to_clk_gate(hw); - struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); - - clk_mgate->mgate->flag |= clk_mgate->mask; - - mp1_gate_clk_enable(hw); - - return 0; -} - -static void mp1_mgate_clk_disable(struct clk_hw *hw) -{ - struct clk_gate *gate = to_clk_gate(hw); - struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); - - clk_mgate->mgate->flag &= ~clk_mgate->mask; - - if (clk_mgate->mgate->flag == 0) - mp1_gate_clk_disable(hw); -} - -static const struct clk_ops mp1_mgate_clk_ops = { - .enable = mp1_mgate_clk_enable, - .disable = mp1_mgate_clk_disable, - .is_enabled = clk_gate_is_enabled, - -}; - -#define to_clk_mmux(_mux) container_of(_mux, struct stm32_clk_mmux, mux) - -static u8 clk_mmux_get_parent(struct clk_hw *hw) -{ - return clk_mux_ops.get_parent(hw); -} - -static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_mux *mux = to_clk_mux(hw); - struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - struct clk_hw *hwp; - int ret, n; - - ret = clk_mux_ops.set_parent(hw, index); - if (ret) - return ret; - - hwp = clk_hw_get_parent(hw); - - for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) - if (clk_mmux->mmux->hws[n] != hw) - clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); - - return 0; -} - -static const struct clk_ops clk_mmux_ops = { - .get_parent = clk_mmux_get_parent, - .set_parent = clk_mmux_set_parent, - .determine_rate = __clk_mux_determine_rate, -}; - -/* STM32 PLL */ -struct stm32_pll_obj { - /* lock pll enable/disable registers */ - spinlock_t *lock; - void __iomem *reg; - struct clk_hw hw; - struct clk_mux mux; -}; - -#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) - -#define PLL_ON BIT(0) -#define PLL_RDY BIT(1) -#define DIVN_MASK 0x1FF -#define DIVM_MASK 0x3F -#define DIVM_SHIFT 16 -#define DIVN_SHIFT 0 -#define FRAC_OFFSET 0xC -#define FRAC_MASK 0x1FFF -#define FRAC_SHIFT 3 -#define FRACLE BIT(16) -#define PLL_MUX_SHIFT 0 -#define PLL_MUX_MASK 3 - -static int __pll_is_enabled(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - - return readl_relaxed(clk_elem->reg) & PLL_ON; -} - -#define TIMEOUT 5 - -static int pll_enable(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - unsigned long flags = 0; - unsigned int timeout = TIMEOUT; - int bit_status = 0; - - spin_lock_irqsave(clk_elem->lock, flags); - - if (__pll_is_enabled(hw)) - goto unlock; - - reg = readl_relaxed(clk_elem->reg); - reg |= PLL_ON; - writel_relaxed(reg, clk_elem->reg); - - /* We can't use readl_poll_timeout() because we can be blocked if - * someone enables this clock before clocksource changes. - * Only jiffies counter is available. Jiffies are incremented by - * interruptions and enable op does not allow to be interrupted. - */ - do { - bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); - - if (bit_status) - udelay(120); - - } while (bit_status && --timeout); - -unlock: - spin_unlock_irqrestore(clk_elem->lock, flags); - - return bit_status; -} - -static void pll_disable(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - unsigned long flags = 0; - - spin_lock_irqsave(clk_elem->lock, flags); - - reg = readl_relaxed(clk_elem->reg); - reg &= ~PLL_ON; - writel_relaxed(reg, clk_elem->reg); - - spin_unlock_irqrestore(clk_elem->lock, flags); -} - -static u32 pll_frac_val(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg, frac = 0; - - reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); - if (reg & FRACLE) - frac = (reg >> FRAC_SHIFT) & FRAC_MASK; - - return frac; -} - -static unsigned long pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - u32 frac, divm, divn; - u64 rate, rate_frac = 0; - - reg = readl_relaxed(clk_elem->reg + 4); - - divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; - divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; - rate = (u64)parent_rate * divn; - - do_div(rate, divm); - - frac = pll_frac_val(hw); - if (frac) { - rate_frac = (u64)parent_rate * (u64)frac; - do_div(rate_frac, (divm * 8192)); - } - - return rate + rate_frac; -} - -static int pll_is_enabled(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - unsigned long flags = 0; - int ret; - - spin_lock_irqsave(clk_elem->lock, flags); - ret = __pll_is_enabled(hw); - spin_unlock_irqrestore(clk_elem->lock, flags); - - return ret; -} - -static u8 pll_get_parent(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - struct clk_hw *mux_hw = &clk_elem->mux.hw; - - __clk_hw_set_clk(mux_hw, hw); - - return clk_mux_ops.get_parent(mux_hw); -} - -static const struct clk_ops pll_ops = { - .enable = pll_enable, - .disable = pll_disable, - .recalc_rate = pll_recalc_rate, - .is_enabled = pll_is_enabled, - .get_parent = pll_get_parent, -}; - -static struct clk_hw *clk_register_pll(struct device *dev, const char *name, - const char * const *parent_names, - int num_parents, - void __iomem *reg, - void __iomem *mux_reg, - unsigned long flags, - spinlock_t *lock) -{ - struct stm32_pll_obj *element; - struct clk_init_data init; - struct clk_hw *hw; - int err; - - element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL); - if (!element) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &pll_ops; - init.flags = flags; - init.parent_names = parent_names; - init.num_parents = num_parents; - - element->mux.lock = lock; - element->mux.reg = mux_reg; - element->mux.shift = PLL_MUX_SHIFT; - element->mux.mask = PLL_MUX_MASK; - element->mux.flags = CLK_MUX_READ_ONLY; - element->mux.reg = mux_reg; - - element->hw.init = &init; - element->reg = reg; - element->lock = lock; - - hw = &element->hw; - err = clk_hw_register(dev, hw); - - if (err) - return ERR_PTR(err); - - return hw; -} - -/* Kernel Timer */ -struct timer_cker { - /* lock the kernel output divider register */ - spinlock_t *lock; - void __iomem *apbdiv; - void __iomem *timpre; - struct clk_hw hw; -}; - -#define to_timer_cker(_hw) container_of(_hw, struct timer_cker, hw) - -#define APB_DIV_MASK 0x07 -#define TIM_PRE_MASK 0x01 - -static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct timer_cker *tim_ker = to_timer_cker(hw); - u32 prescaler; - unsigned int mult = 0; - - prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; - if (prescaler < 2) - return 1; - - mult = 2; - - if (rate / parent_rate >= 4) - mult = 4; - - return mult; -} - -static long timer_ker_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - unsigned long factor = __bestmult(hw, rate, *parent_rate); - - return *parent_rate * factor; -} - -static int timer_ker_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct timer_cker *tim_ker = to_timer_cker(hw); - unsigned long flags = 0; - unsigned long factor = __bestmult(hw, rate, parent_rate); - int ret = 0; - - spin_lock_irqsave(tim_ker->lock, flags); - - switch (factor) { - case 1: - break; - case 2: - writel_relaxed(0, tim_ker->timpre); - break; - case 4: - writel_relaxed(1, tim_ker->timpre); - break; - default: - ret = -EINVAL; - } - spin_unlock_irqrestore(tim_ker->lock, flags); - - return ret; -} - -static unsigned long timer_ker_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct timer_cker *tim_ker = to_timer_cker(hw); - u32 prescaler, timpre; - u32 mul; - - prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; - - timpre = readl_relaxed(tim_ker->timpre) & TIM_PRE_MASK; - - if (!prescaler) - return parent_rate; - - mul = (timpre + 1) * 2; - - return parent_rate * mul; -} - -static const struct clk_ops timer_ker_ops = { - .recalc_rate = timer_ker_recalc_rate, - .round_rate = timer_ker_round_rate, - .set_rate = timer_ker_set_rate, - -}; - -static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, - const char *parent_name, - unsigned long flags, - void __iomem *apbdiv, - void __iomem *timpre, - spinlock_t *lock) -{ - struct timer_cker *tim_ker; - struct clk_init_data init; - struct clk_hw *hw; - int err; - - tim_ker = devm_kzalloc(dev, sizeof(*tim_ker), GFP_KERNEL); - if (!tim_ker) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &timer_ker_ops; - init.flags = flags; - init.parent_names = &parent_name; - init.num_parents = 1; - - tim_ker->hw.init = &init; - tim_ker->lock = lock; - tim_ker->apbdiv = apbdiv; - tim_ker->timpre = timpre; - - hw = &tim_ker->hw; - err = clk_hw_register(dev, hw); - - if (err) - return ERR_PTR(err); - - return hw; -} - -/* The divider of RTC clock concerns only ck_hse clock */ -#define HSE_RTC 3 - -static unsigned long clk_divider_rtc_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) - return clk_divider_ops.recalc_rate(hw, parent_rate); - - return parent_rate; -} - -static int clk_divider_rtc_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) - return clk_divider_ops.set_rate(hw, rate, parent_rate); - - return parent_rate; -} - -static int clk_divider_rtc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) -{ - if (req->best_parent_hw == clk_hw_get_parent_by_index(hw, HSE_RTC)) - return clk_divider_ops.determine_rate(hw, req); - - req->rate = req->best_parent_rate; - - return 0; -} - -static const struct clk_ops rtc_div_clk_ops = { - .recalc_rate = clk_divider_rtc_recalc_rate, - .set_rate = clk_divider_rtc_set_rate, - .determine_rate = clk_divider_rtc_determine_rate -}; - -struct stm32_pll_cfg { - u32 offset; - u32 muxoff; -}; - -static struct clk_hw *_clk_register_pll(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; - - return clk_register_pll(dev, cfg->name, cfg->parent_names, - cfg->num_parents, - base + stm_pll_cfg->offset, - base + stm_pll_cfg->muxoff, - cfg->flags, lock); -} - -struct stm32_cktim_cfg { - u32 offset_apbdiv; - u32 offset_timpre; -}; - -static struct clk_hw *_clk_register_cktim(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct stm32_cktim_cfg *cktim_cfg = cfg->cfg; - - return clk_register_cktim(dev, cfg->name, cfg->parent_name, cfg->flags, - cktim_cfg->offset_apbdiv + base, - cktim_cfg->offset_timpre + base, lock); -} - -static struct clk_hw * -_clk_stm32_register_gate(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - return clk_stm32_register_gate_ops(dev, - cfg->name, - cfg->parent_name, - cfg->parent_data, - cfg->flags, - base, - cfg->cfg, - lock); -} - -static struct clk_hw * -_clk_stm32_register_composite(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names, - cfg->parent_data, cfg->num_parents, - base, cfg->cfg, cfg->flags, lock); -} - -#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct gate_cfg) {\ - .reg_off = _offset,\ - .bit_idx = _bit_idx,\ - .gate_flags = _gate_flags,\ - },\ - .func = _clk_hw_register_gate,\ -} - -#define FIXED_FACTOR(_id, _name, _parent, _flags, _mult, _div)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct fixed_factor_cfg) {\ - .mult = _mult,\ - .div = _div,\ - },\ - .func = _clk_hw_register_fixed_factor,\ -} - -#define DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ - _div_flags, _div_table)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct div_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .div_flags = _div_flags,\ - .table = _div_table,\ - },\ - .func = _clk_hw_register_divider_table,\ -} - -#define DIV(_id, _name, _parent, _flags, _offset, _shift, _width, _div_flags)\ - DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ - _div_flags, NULL) - -#define MUX(_id, _name, _parents, _flags, _offset, _shift, _width, _mux_flags)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_names = _parents,\ - .num_parents = ARRAY_SIZE(_parents),\ - .flags = _flags,\ - .cfg = &(struct mux_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .mux_flags = _mux_flags,\ - },\ - .func = _clk_hw_register_mux,\ -} - -#define PLL(_id, _name, _parents, _flags, _offset_p, _offset_mux)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_names = _parents,\ - .num_parents = ARRAY_SIZE(_parents),\ - .flags = CLK_IGNORE_UNUSED | (_flags),\ - .cfg = &(struct stm32_pll_cfg) {\ - .offset = _offset_p,\ - .muxoff = _offset_mux,\ - },\ - .func = _clk_register_pll,\ -} - -#define STM32_CKTIM(_name, _parent, _flags, _offset_apbdiv, _offset_timpre)\ -{\ - .id = NO_ID,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct stm32_cktim_cfg) {\ - .offset_apbdiv = _offset_apbdiv,\ - .offset_timpre = _offset_timpre,\ - },\ - .func = _clk_register_cktim,\ -} - -#define STM32_TIM(_id, _name, _parent, _offset_set, _bit_idx)\ - GATE_MP1(_id, _name, _parent, CLK_SET_RATE_PARENT,\ - _offset_set, _bit_idx, 0) - -/* STM32 GATE */ -#define STM32_GATE(_id, _name, _parent, _flags, _gate)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = (struct stm32_gate_cfg *) {_gate},\ - .func = _clk_stm32_register_gate,\ -} - -#define STM32_GATE_PDATA(_id, _name, _parent, _flags, _gate)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_data = _parent,\ - .flags = _flags,\ - .cfg = (struct stm32_gate_cfg *) {_gate},\ - .func = _clk_stm32_register_gate,\ -} - -#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ - (&(struct stm32_gate_cfg) {\ - &(struct gate_cfg) {\ - .reg_off = _gate_offset,\ - .bit_idx = _gate_bit_idx,\ - .gate_flags = _gate_flags,\ - },\ - .mgate = _mgate,\ - .ops = _ops,\ - }) - -#define _STM32_MGATE(_mgate)\ - (&per_gate_cfg[_mgate]) - -#define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ - _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ - NULL, NULL)\ - -#define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ - _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ - NULL, &mp1_gate_clk_ops)\ - -#define _MGATE_MP1(_mgate)\ - .gate = &per_gate_cfg[_mgate] - -#define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ - STM32_GATE(_id, _name, _parent, _flags,\ - _GATE_MP1(_offset, _bit_idx, _gate_flags)) - -#define MGATE_MP1(_id, _name, _parent, _flags, _mgate)\ - STM32_GATE(_id, _name, _parent, _flags,\ - _STM32_MGATE(_mgate)) - -#define MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)\ - STM32_GATE_PDATA(_id, _name, _parent, _flags,\ - _STM32_MGATE(_mgate)) - -#define _STM32_DIV(_div_offset, _div_shift, _div_width,\ - _div_flags, _div_table, _ops)\ - .div = &(struct stm32_div_cfg) {\ - &(struct div_cfg) {\ - .reg_off = _div_offset,\ - .shift = _div_shift,\ - .width = _div_width,\ - .div_flags = _div_flags,\ - .table = _div_table,\ - },\ - .ops = _ops,\ - } - -#define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ - _STM32_DIV(_div_offset, _div_shift, _div_width,\ - _div_flags, _div_table, NULL)\ - -#define _DIV_RTC(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ - _STM32_DIV(_div_offset, _div_shift, _div_width,\ - _div_flags, _div_table, &rtc_div_clk_ops) - -#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ - .mux = &(struct stm32_mux_cfg) {\ - &(struct mux_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .mux_flags = _mux_flags,\ - .table = NULL,\ - },\ - .mmux = _mmux,\ - .ops = _ops,\ - } - -#define _MUX(_offset, _shift, _width, _mux_flags)\ - _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ - -#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] - -#define PARENT(_parent) ((const char *[]) { _parent}) - -#define _NO_MUX .mux = NULL -#define _NO_DIV .div = NULL -#define _NO_GATE .gate = NULL - -#define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_names = _parents,\ - .num_parents = ARRAY_SIZE(_parents),\ - .flags = _flags,\ - .cfg = &(struct stm32_composite_cfg) {\ - _gate,\ - _mux,\ - _div,\ - },\ - .func = _clk_stm32_register_composite,\ -} - -#define PCLK(_id, _name, _parent, _flags, _mgate)\ - MGATE_MP1(_id, _name, _parent, _flags, _mgate) - -#define PCLK_PDATA(_id, _name, _parent, _flags, _mgate)\ - MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate) - -#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ - COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\ - CLK_SET_RATE_NO_REPARENT | _flags,\ - _MGATE_MP1(_mgate),\ - _MMUX(_mmux),\ - _NO_DIV) - -enum { - G_SAI1, - G_SAI2, - G_SAI3, - G_SAI4, - G_SPI1, - G_SPI2, - G_SPI3, - G_SPI4, - G_SPI5, - G_SPI6, - G_SPDIF, - G_I2C1, - G_I2C2, - G_I2C3, - G_I2C4, - G_I2C5, - G_I2C6, - G_USART2, - G_UART4, - G_USART3, - G_UART5, - G_USART1, - G_USART6, - G_UART7, - G_UART8, - G_LPTIM1, - G_LPTIM2, - G_LPTIM3, - G_LPTIM4, - G_LPTIM5, - G_LTDC, - G_DSI, - G_QSPI, - G_FMC, - G_SDMMC1, - G_SDMMC2, - G_SDMMC3, - G_USBO, - G_USBPHY, - G_RNG1, - G_RNG2, - G_FDCAN, - G_DAC12, - G_CEC, - G_ADC12, - G_GPU, - G_STGEN, - G_DFSDM, - G_ADFSDM, - G_TIM2, - G_TIM3, - G_TIM4, - G_TIM5, - G_TIM6, - G_TIM7, - G_TIM12, - G_TIM13, - G_TIM14, - G_MDIO, - G_TIM1, - G_TIM8, - G_TIM15, - G_TIM16, - G_TIM17, - G_SYSCFG, - G_VREF, - G_TMPSENS, - G_PMBCTRL, - G_HDP, - G_IWDG2, - G_STGENRO, - G_DMA1, - G_DMA2, - G_DMAMUX, - G_DCMI, - G_CRYP2, - G_HASH2, - G_CRC2, - G_HSEM, - G_IPCC, - G_GPIOA, - G_GPIOB, - G_GPIOC, - G_GPIOD, - G_GPIOE, - G_GPIOF, - G_GPIOG, - G_GPIOH, - G_GPIOI, - G_GPIOJ, - G_GPIOK, - G_MDMA, - G_ETHCK, - G_ETHTX, - G_ETHRX, - G_ETHMAC, - G_CRC1, - G_USBH, - G_ETHSTP, - G_RTCAPB, - G_TZC1, - G_TZC2, - G_TZPC, - G_IWDG1, - G_BSEC, - G_GPIOZ, - G_CRYP1, - G_HASH1, - G_BKPSRAM, - G_DDRPERFM, - - G_LAST -}; - -static struct stm32_mgate mp1_mgate[G_LAST]; - -#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ - _mgate, _ops)\ - [_id] = {\ - &(struct gate_cfg) {\ - .reg_off = _gate_offset,\ - .bit_idx = _gate_bit_idx,\ - .gate_flags = _gate_flags,\ - },\ - .mgate = _mgate,\ - .ops = _ops,\ - } - -#define K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ - _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ - NULL, &mp1_gate_clk_ops) - -#define K_MGATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ - _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ - &mp1_mgate[_id], &mp1_mgate_clk_ops) - -/* Peripheral gates */ -static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { - /* Multi gates */ - K_GATE(G_MDIO, RCC_APB1ENSETR, 31, 0), - K_MGATE(G_DAC12, RCC_APB1ENSETR, 29, 0), - K_MGATE(G_CEC, RCC_APB1ENSETR, 27, 0), - K_MGATE(G_SPDIF, RCC_APB1ENSETR, 26, 0), - K_MGATE(G_I2C5, RCC_APB1ENSETR, 24, 0), - K_MGATE(G_I2C3, RCC_APB1ENSETR, 23, 0), - K_MGATE(G_I2C2, RCC_APB1ENSETR, 22, 0), - K_MGATE(G_I2C1, RCC_APB1ENSETR, 21, 0), - K_MGATE(G_UART8, RCC_APB1ENSETR, 19, 0), - K_MGATE(G_UART7, RCC_APB1ENSETR, 18, 0), - K_MGATE(G_UART5, RCC_APB1ENSETR, 17, 0), - K_MGATE(G_UART4, RCC_APB1ENSETR, 16, 0), - K_MGATE(G_USART3, RCC_APB1ENSETR, 15, 0), - K_MGATE(G_USART2, RCC_APB1ENSETR, 14, 0), - K_MGATE(G_SPI3, RCC_APB1ENSETR, 12, 0), - K_MGATE(G_SPI2, RCC_APB1ENSETR, 11, 0), - K_MGATE(G_LPTIM1, RCC_APB1ENSETR, 9, 0), - K_GATE(G_TIM14, RCC_APB1ENSETR, 8, 0), - K_GATE(G_TIM13, RCC_APB1ENSETR, 7, 0), - K_GATE(G_TIM12, RCC_APB1ENSETR, 6, 0), - K_GATE(G_TIM7, RCC_APB1ENSETR, 5, 0), - K_GATE(G_TIM6, RCC_APB1ENSETR, 4, 0), - K_GATE(G_TIM5, RCC_APB1ENSETR, 3, 0), - K_GATE(G_TIM4, RCC_APB1ENSETR, 2, 0), - K_GATE(G_TIM3, RCC_APB1ENSETR, 1, 0), - K_GATE(G_TIM2, RCC_APB1ENSETR, 0, 0), - - K_MGATE(G_FDCAN, RCC_APB2ENSETR, 24, 0), - K_GATE(G_ADFSDM, RCC_APB2ENSETR, 21, 0), - K_GATE(G_DFSDM, RCC_APB2ENSETR, 20, 0), - K_MGATE(G_SAI3, RCC_APB2ENSETR, 18, 0), - K_MGATE(G_SAI2, RCC_APB2ENSETR, 17, 0), - K_MGATE(G_SAI1, RCC_APB2ENSETR, 16, 0), - K_MGATE(G_USART6, RCC_APB2ENSETR, 13, 0), - K_MGATE(G_SPI5, RCC_APB2ENSETR, 10, 0), - K_MGATE(G_SPI4, RCC_APB2ENSETR, 9, 0), - K_MGATE(G_SPI1, RCC_APB2ENSETR, 8, 0), - K_GATE(G_TIM17, RCC_APB2ENSETR, 4, 0), - K_GATE(G_TIM16, RCC_APB2ENSETR, 3, 0), - K_GATE(G_TIM15, RCC_APB2ENSETR, 2, 0), - K_GATE(G_TIM8, RCC_APB2ENSETR, 1, 0), - K_GATE(G_TIM1, RCC_APB2ENSETR, 0, 0), - - K_GATE(G_HDP, RCC_APB3ENSETR, 20, 0), - K_GATE(G_PMBCTRL, RCC_APB3ENSETR, 17, 0), - K_GATE(G_TMPSENS, RCC_APB3ENSETR, 16, 0), - K_GATE(G_VREF, RCC_APB3ENSETR, 13, 0), - K_GATE(G_SYSCFG, RCC_APB3ENSETR, 11, 0), - K_MGATE(G_SAI4, RCC_APB3ENSETR, 8, 0), - K_MGATE(G_LPTIM5, RCC_APB3ENSETR, 3, 0), - K_MGATE(G_LPTIM4, RCC_APB3ENSETR, 2, 0), - K_MGATE(G_LPTIM3, RCC_APB3ENSETR, 1, 0), - K_MGATE(G_LPTIM2, RCC_APB3ENSETR, 0, 0), - - K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), - K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), - K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), - K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0), - K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), - K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), - - K_GATE(G_STGEN, RCC_APB5ENSETR, 20, 0), - K_GATE(G_BSEC, RCC_APB5ENSETR, 16, 0), - K_GATE(G_IWDG1, RCC_APB5ENSETR, 15, 0), - K_GATE(G_TZPC, RCC_APB5ENSETR, 13, 0), - K_GATE(G_TZC2, RCC_APB5ENSETR, 12, 0), - K_GATE(G_TZC1, RCC_APB5ENSETR, 11, 0), - K_GATE(G_RTCAPB, RCC_APB5ENSETR, 8, 0), - K_MGATE(G_USART1, RCC_APB5ENSETR, 4, 0), - K_MGATE(G_I2C6, RCC_APB5ENSETR, 3, 0), - K_MGATE(G_I2C4, RCC_APB5ENSETR, 2, 0), - K_MGATE(G_SPI6, RCC_APB5ENSETR, 0, 0), - - K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), - K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), - K_MGATE(G_ADC12, RCC_AHB2ENSETR, 5, 0), - K_GATE(G_DMAMUX, RCC_AHB2ENSETR, 2, 0), - K_GATE(G_DMA2, RCC_AHB2ENSETR, 1, 0), - K_GATE(G_DMA1, RCC_AHB2ENSETR, 0, 0), - - K_GATE(G_IPCC, RCC_AHB3ENSETR, 12, 0), - K_GATE(G_HSEM, RCC_AHB3ENSETR, 11, 0), - K_GATE(G_CRC2, RCC_AHB3ENSETR, 7, 0), - K_MGATE(G_RNG2, RCC_AHB3ENSETR, 6, 0), - K_GATE(G_HASH2, RCC_AHB3ENSETR, 5, 0), - K_GATE(G_CRYP2, RCC_AHB3ENSETR, 4, 0), - K_GATE(G_DCMI, RCC_AHB3ENSETR, 0, 0), - - K_GATE(G_GPIOK, RCC_AHB4ENSETR, 10, 0), - K_GATE(G_GPIOJ, RCC_AHB4ENSETR, 9, 0), - K_GATE(G_GPIOI, RCC_AHB4ENSETR, 8, 0), - K_GATE(G_GPIOH, RCC_AHB4ENSETR, 7, 0), - K_GATE(G_GPIOG, RCC_AHB4ENSETR, 6, 0), - K_GATE(G_GPIOF, RCC_AHB4ENSETR, 5, 0), - K_GATE(G_GPIOE, RCC_AHB4ENSETR, 4, 0), - K_GATE(G_GPIOD, RCC_AHB4ENSETR, 3, 0), - K_GATE(G_GPIOC, RCC_AHB4ENSETR, 2, 0), - K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), - K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), - - K_GATE(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), - K_MGATE(G_RNG1, RCC_AHB5ENSETR, 6, 0), - K_GATE(G_HASH1, RCC_AHB5ENSETR, 5, 0), - K_GATE(G_CRYP1, RCC_AHB5ENSETR, 4, 0), - K_GATE(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), - - K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), - K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), - K_MGATE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), - K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), - K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), - K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), - K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), - K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), - K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), - K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), - K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), - K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), - K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), -}; - -enum { - M_SDMMC12, - M_SDMMC3, - M_FMC, - M_QSPI, - M_RNG1, - M_RNG2, - M_USBPHY, - M_USBO, - M_STGEN, - M_SPDIF, - M_SPI1, - M_SPI23, - M_SPI45, - M_SPI6, - M_CEC, - M_I2C12, - M_I2C35, - M_I2C46, - M_LPTIM1, - M_LPTIM23, - M_LPTIM45, - M_USART1, - M_UART24, - M_UART35, - M_USART6, - M_UART78, - M_SAI1, - M_SAI2, - M_SAI3, - M_SAI4, - M_DSI, - M_FDCAN, - M_ADC12, - M_ETHCK, - M_CKPER, - M_LAST -}; - -static struct stm32_mmux ker_mux[M_LAST]; - -#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops)\ - [_id] = {\ - &(struct mux_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .mux_flags = _mux_flags,\ - .table = NULL,\ - },\ - .mmux = _mmux,\ - .ops = _ops,\ - } - -#define K_MUX(_id, _offset, _shift, _width, _mux_flags)\ - _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ - NULL, NULL) - -#define K_MMUX(_id, _offset, _shift, _width, _mux_flags)\ - _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ - &ker_mux[_id], &clk_mmux_ops) - -static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - /* Kernel multi mux */ - K_MMUX(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), - K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), - K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), - K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), - K_MMUX(M_I2C35, RCC_I2C35CKSELR, 0, 3, 0), - K_MMUX(M_LPTIM23, RCC_LPTIM23CKSELR, 0, 3, 0), - K_MMUX(M_LPTIM45, RCC_LPTIM45CKSELR, 0, 3, 0), - K_MMUX(M_UART24, RCC_UART24CKSELR, 0, 3, 0), - K_MMUX(M_UART35, RCC_UART35CKSELR, 0, 3, 0), - K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), - K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), - K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), - K_MMUX(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), - - /* Kernel simple mux */ - K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), - K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), - K_MUX(M_FMC, RCC_FMCCKSELR, 0, 2, 0), - K_MUX(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), - K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), - K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), - K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), - K_MUX(M_SPI1, RCC_SPI2S1CKSELR, 0, 3, 0), - K_MUX(M_CEC, RCC_CECCKSELR, 0, 2, 0), - K_MUX(M_LPTIM1, RCC_LPTIM1CKSELR, 0, 3, 0), - K_MUX(M_USART6, RCC_UART6CKSELR, 0, 3, 0), - K_MUX(M_FDCAN, RCC_FDCANCKSELR, 0, 2, 0), - K_MUX(M_SAI2, RCC_SAI2CKSELR, 0, 3, 0), - K_MUX(M_SAI3, RCC_SAI3CKSELR, 0, 3, 0), - K_MUX(M_SAI4, RCC_SAI4CKSELR, 0, 3, 0), - K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), - K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), - K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), - K_MUX(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), - K_MUX(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), - K_MUX(M_USART1, RCC_UART1CKSELR, 0, 3, 0), - K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), -}; - -static const struct clock_config stm32mp1_clock_cfg[] = { - /* External / Internal Oscillators */ - GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), - /* ck_csi is used by IO compensation and should be critical */ - GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, - RCC_OCENSETR, 4, 0), - COMPOSITE(CK_HSI, "ck_hsi", PARENT("clk-hsi"), 0, - _GATE_MP1(RCC_OCENSETR, 0, 0), - _NO_MUX, - _DIV(RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO | - CLK_DIVIDER_READ_ONLY, NULL)), - GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), - GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), - - FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), - - /* PLLs */ - PLL(PLL1, "pll1", ref12_parents, 0, RCC_PLL1CR, RCC_RCK12SELR), - PLL(PLL2, "pll2", ref12_parents, 0, RCC_PLL2CR, RCC_RCK12SELR), - PLL(PLL3, "pll3", ref3_parents, 0, RCC_PLL3CR, RCC_RCK3SELR), - PLL(PLL4, "pll4", ref4_parents, 0, RCC_PLL4CR, RCC_RCK4SELR), - - /* ODF */ - COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, - _GATE(RCC_PLL1CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, - _GATE(RCC_PLL2CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, - _GATE(RCC_PLL2CR, 5, 0), - _NO_MUX, - _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, - _GATE(RCC_PLL2CR, 6, 0), - _NO_MUX, - _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), - - COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL3CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 5, 0), - _NO_MUX, - _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 6, 0), - _NO_MUX, - _DIV(RCC_PLL3CFGR2, 16, 7, 0, NULL)), - - COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0, - _GATE(RCC_PLL4CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL4CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0, - _GATE(RCC_PLL4CR, 5, 0), - _NO_MUX, - _DIV(RCC_PLL4CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, - _GATE(RCC_PLL4CR, 6, 0), - _NO_MUX, - _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), - - /* MUX system clocks */ - MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, - RCC_CPERCKSELR, 0, 2, 0), - - MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | - CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), - - COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | - CLK_OPS_PARENT_ENABLE, - _NO_GATE, - _MUX(RCC_ASSCKSELR, 0, 2, 0), - _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), - - COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | - CLK_OPS_PARENT_ENABLE, - _NO_GATE, - _MUX(RCC_MSSCKSELR, 0, 2, 0), - _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), - - DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - /* Kernel Timers */ - STM32_CKTIM("ck1_tim", "pclk1", 0, RCC_APB1DIVR, RCC_TIMG1PRER), - STM32_CKTIM("ck2_tim", "pclk2", 0, RCC_APB2DIVR, RCC_TIMG2PRER), - - STM32_TIM(TIM2_K, "tim2_k", "ck1_tim", RCC_APB1ENSETR, 0), - STM32_TIM(TIM3_K, "tim3_k", "ck1_tim", RCC_APB1ENSETR, 1), - STM32_TIM(TIM4_K, "tim4_k", "ck1_tim", RCC_APB1ENSETR, 2), - STM32_TIM(TIM5_K, "tim5_k", "ck1_tim", RCC_APB1ENSETR, 3), - STM32_TIM(TIM6_K, "tim6_k", "ck1_tim", RCC_APB1ENSETR, 4), - STM32_TIM(TIM7_K, "tim7_k", "ck1_tim", RCC_APB1ENSETR, 5), - STM32_TIM(TIM12_K, "tim12_k", "ck1_tim", RCC_APB1ENSETR, 6), - STM32_TIM(TIM13_K, "tim13_k", "ck1_tim", RCC_APB1ENSETR, 7), - STM32_TIM(TIM14_K, "tim14_k", "ck1_tim", RCC_APB1ENSETR, 8), - STM32_TIM(TIM1_K, "tim1_k", "ck2_tim", RCC_APB2ENSETR, 0), - STM32_TIM(TIM8_K, "tim8_k", "ck2_tim", RCC_APB2ENSETR, 1), - STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2), - STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3), - STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4), - - /* Peripheral clocks */ - PCLK(TIM2, "tim2", "pclk1", CLK_IGNORE_UNUSED, G_TIM2), - PCLK(TIM3, "tim3", "pclk1", CLK_IGNORE_UNUSED, G_TIM3), - PCLK(TIM4, "tim4", "pclk1", CLK_IGNORE_UNUSED, G_TIM4), - PCLK(TIM5, "tim5", "pclk1", CLK_IGNORE_UNUSED, G_TIM5), - PCLK(TIM6, "tim6", "pclk1", CLK_IGNORE_UNUSED, G_TIM6), - PCLK(TIM7, "tim7", "pclk1", CLK_IGNORE_UNUSED, G_TIM7), - PCLK(TIM12, "tim12", "pclk1", CLK_IGNORE_UNUSED, G_TIM12), - PCLK(TIM13, "tim13", "pclk1", CLK_IGNORE_UNUSED, G_TIM13), - PCLK(TIM14, "tim14", "pclk1", CLK_IGNORE_UNUSED, G_TIM14), - PCLK(LPTIM1, "lptim1", "pclk1", 0, G_LPTIM1), - PCLK(SPI2, "spi2", "pclk1", 0, G_SPI2), - PCLK(SPI3, "spi3", "pclk1", 0, G_SPI3), - PCLK(USART2, "usart2", "pclk1", 0, G_USART2), - PCLK(USART3, "usart3", "pclk1", 0, G_USART3), - PCLK(UART4, "uart4", "pclk1", 0, G_UART4), - PCLK(UART5, "uart5", "pclk1", 0, G_UART5), - PCLK(UART7, "uart7", "pclk1", 0, G_UART7), - PCLK(UART8, "uart8", "pclk1", 0, G_UART8), - PCLK(I2C1, "i2c1", "pclk1", 0, G_I2C1), - PCLK(I2C2, "i2c2", "pclk1", 0, G_I2C2), - PCLK(I2C3, "i2c3", "pclk1", 0, G_I2C3), - PCLK(I2C5, "i2c5", "pclk1", 0, G_I2C5), - PCLK(SPDIF, "spdif", "pclk1", 0, G_SPDIF), - PCLK(CEC, "cec", "pclk1", 0, G_CEC), - PCLK(DAC12, "dac12", "pclk1", 0, G_DAC12), - PCLK(MDIO, "mdio", "pclk1", 0, G_MDIO), - PCLK(TIM1, "tim1", "pclk2", CLK_IGNORE_UNUSED, G_TIM1), - PCLK(TIM8, "tim8", "pclk2", CLK_IGNORE_UNUSED, G_TIM8), - PCLK(TIM15, "tim15", "pclk2", CLK_IGNORE_UNUSED, G_TIM15), - PCLK(TIM16, "tim16", "pclk2", CLK_IGNORE_UNUSED, G_TIM16), - PCLK(TIM17, "tim17", "pclk2", CLK_IGNORE_UNUSED, G_TIM17), - PCLK(SPI1, "spi1", "pclk2", 0, G_SPI1), - PCLK(SPI4, "spi4", "pclk2", 0, G_SPI4), - PCLK(SPI5, "spi5", "pclk2", 0, G_SPI5), - PCLK(USART6, "usart6", "pclk2", 0, G_USART6), - PCLK(SAI1, "sai1", "pclk2", 0, G_SAI1), - PCLK(SAI2, "sai2", "pclk2", 0, G_SAI2), - PCLK(SAI3, "sai3", "pclk2", 0, G_SAI3), - PCLK(DFSDM, "dfsdm", "pclk2", 0, G_DFSDM), - PCLK(FDCAN, "fdcan", "pclk2", 0, G_FDCAN), - PCLK(LPTIM2, "lptim2", "pclk3", 0, G_LPTIM2), - PCLK(LPTIM3, "lptim3", "pclk3", 0, G_LPTIM3), - PCLK(LPTIM4, "lptim4", "pclk3", 0, G_LPTIM4), - PCLK(LPTIM5, "lptim5", "pclk3", 0, G_LPTIM5), - PCLK(SAI4, "sai4", "pclk3", 0, G_SAI4), - PCLK(SYSCFG, "syscfg", "pclk3", 0, G_SYSCFG), - PCLK(VREF, "vref", "pclk3", 13, G_VREF), - PCLK(TMPSENS, "tmpsens", "pclk3", 0, G_TMPSENS), - PCLK(PMBCTRL, "pmbctrl", "pclk3", 0, G_PMBCTRL), - PCLK(HDP, "hdp", "pclk3", 0, G_HDP), - PCLK(LTDC, "ltdc", "pclk4", 0, G_LTDC), - PCLK(DSI, "dsi", "pclk4", 0, G_DSI), - PCLK(IWDG2, "iwdg2", "pclk4", 0, G_IWDG2), - PCLK(USBPHY, "usbphy", "pclk4", 0, G_USBPHY), - PCLK(STGENRO, "stgenro", "pclk4", 0, G_STGENRO), - PCLK(SPI6, "spi6", "pclk5", 0, G_SPI6), - PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), - PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), - PCLK(USART1, "usart1", "pclk5", 0, G_USART1), - PCLK(RTCAPB, "rtcapb", "pclk5", CLK_IGNORE_UNUSED | - CLK_IS_CRITICAL, G_RTCAPB), - PCLK(TZC1, "tzc1", "ck_axi", CLK_IGNORE_UNUSED, G_TZC1), - PCLK(TZC2, "tzc2", "ck_axi", CLK_IGNORE_UNUSED, G_TZC2), - PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), - PCLK(IWDG1, "iwdg1", "pclk5", 0, G_IWDG1), - PCLK(BSEC, "bsec", "pclk5", CLK_IGNORE_UNUSED, G_BSEC), - PCLK(STGEN, "stgen", "pclk5", CLK_IGNORE_UNUSED, G_STGEN), - PCLK(DMA1, "dma1", "ck_mcu", 0, G_DMA1), - PCLK(DMA2, "dma2", "ck_mcu", 0, G_DMA2), - PCLK(DMAMUX, "dmamux", "ck_mcu", 0, G_DMAMUX), - PCLK(ADC12, "adc12", "ck_mcu", 0, G_ADC12), - PCLK(USBO, "usbo", "ck_mcu", 0, G_USBO), - PCLK(SDMMC3, "sdmmc3", "ck_mcu", 0, G_SDMMC3), - PCLK(DCMI, "dcmi", "ck_mcu", 0, G_DCMI), - PCLK(CRYP2, "cryp2", "ck_mcu", 0, G_CRYP2), - PCLK(HASH2, "hash2", "ck_mcu", 0, G_HASH2), - PCLK(RNG2, "rng2", "ck_mcu", 0, G_RNG2), - PCLK(CRC2, "crc2", "ck_mcu", 0, G_CRC2), - PCLK(HSEM, "hsem", "ck_mcu", 0, G_HSEM), - PCLK(IPCC, "ipcc", "ck_mcu", 0, G_IPCC), - PCLK(GPIOA, "gpioa", "ck_mcu", 0, G_GPIOA), - PCLK(GPIOB, "gpiob", "ck_mcu", 0, G_GPIOB), - PCLK(GPIOC, "gpioc", "ck_mcu", 0, G_GPIOC), - PCLK(GPIOD, "gpiod", "ck_mcu", 0, G_GPIOD), - PCLK(GPIOE, "gpioe", "ck_mcu", 0, G_GPIOE), - PCLK(GPIOF, "gpiof", "ck_mcu", 0, G_GPIOF), - PCLK(GPIOG, "gpiog", "ck_mcu", 0, G_GPIOG), - PCLK(GPIOH, "gpioh", "ck_mcu", 0, G_GPIOH), - PCLK(GPIOI, "gpioi", "ck_mcu", 0, G_GPIOI), - PCLK(GPIOJ, "gpioj", "ck_mcu", 0, G_GPIOJ), - PCLK(GPIOK, "gpiok", "ck_mcu", 0, G_GPIOK), - PCLK(GPIOZ, "gpioz", "ck_axi", CLK_IGNORE_UNUSED, G_GPIOZ), - PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), - PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), - PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), - PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, G_BKPSRAM), - PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), - PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), - PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), - PCLK_PDATA(ETHRX, "ethrx", ethrx_src, 0, G_ETHRX), - PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC), - PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC), - PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI), - PCLK(SDMMC1, "sdmmc1", "ck_axi", 0, G_SDMMC1), - PCLK(SDMMC2, "sdmmc2", "ck_axi", 0, G_SDMMC2), - PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), - PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), - PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), - PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM), - - /* Kernel clocks */ - KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), - KCLK(SDMMC2_K, "sdmmc2_k", sdmmc12_src, 0, G_SDMMC2, M_SDMMC12), - KCLK(SDMMC3_K, "sdmmc3_k", sdmmc3_src, 0, G_SDMMC3, M_SDMMC3), - KCLK(FMC_K, "fmc_k", fmc_src, 0, G_FMC, M_FMC), - KCLK(QSPI_K, "qspi_k", qspi_src, 0, G_QSPI, M_QSPI), - KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), - KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), - KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), - KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, G_STGEN, M_STGEN), - KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), - KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), - KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), - KCLK(SPI3_K, "spi3_k", spi123_src, 0, G_SPI3, M_SPI23), - KCLK(SPI4_K, "spi4_k", spi45_src, 0, G_SPI4, M_SPI45), - KCLK(SPI5_K, "spi5_k", spi45_src, 0, G_SPI5, M_SPI45), - KCLK(SPI6_K, "spi6_k", spi6_src, 0, G_SPI6, M_SPI6), - KCLK(CEC_K, "cec_k", cec_src, 0, G_CEC, M_CEC), - KCLK(I2C1_K, "i2c1_k", i2c12_src, 0, G_I2C1, M_I2C12), - KCLK(I2C2_K, "i2c2_k", i2c12_src, 0, G_I2C2, M_I2C12), - KCLK(I2C3_K, "i2c3_k", i2c35_src, 0, G_I2C3, M_I2C35), - KCLK(I2C5_K, "i2c5_k", i2c35_src, 0, G_I2C5, M_I2C35), - KCLK(I2C4_K, "i2c4_k", i2c46_src, 0, G_I2C4, M_I2C46), - KCLK(I2C6_K, "i2c6_k", i2c46_src, 0, G_I2C6, M_I2C46), - KCLK(LPTIM1_K, "lptim1_k", lptim1_src, 0, G_LPTIM1, M_LPTIM1), - KCLK(LPTIM2_K, "lptim2_k", lptim23_src, 0, G_LPTIM2, M_LPTIM23), - KCLK(LPTIM3_K, "lptim3_k", lptim23_src, 0, G_LPTIM3, M_LPTIM23), - KCLK(LPTIM4_K, "lptim4_k", lptim45_src, 0, G_LPTIM4, M_LPTIM45), - KCLK(LPTIM5_K, "lptim5_k", lptim45_src, 0, G_LPTIM5, M_LPTIM45), - KCLK(USART1_K, "usart1_k", usart1_src, 0, G_USART1, M_USART1), - KCLK(USART2_K, "usart2_k", usart234578_src, 0, G_USART2, M_UART24), - KCLK(USART3_K, "usart3_k", usart234578_src, 0, G_USART3, M_UART35), - KCLK(UART4_K, "uart4_k", usart234578_src, 0, G_UART4, M_UART24), - KCLK(UART5_K, "uart5_k", usart234578_src, 0, G_UART5, M_UART35), - KCLK(USART6_K, "uart6_k", usart6_src, 0, G_USART6, M_USART6), - KCLK(UART7_K, "uart7_k", usart234578_src, 0, G_UART7, M_UART78), - KCLK(UART8_K, "uart8_k", usart234578_src, 0, G_UART8, M_UART78), - KCLK(FDCAN_K, "fdcan_k", fdcan_src, 0, G_FDCAN, M_FDCAN), - KCLK(SAI1_K, "sai1_k", sai_src, 0, G_SAI1, M_SAI1), - KCLK(SAI2_K, "sai2_k", sai2_src, 0, G_SAI2, M_SAI2), - KCLK(SAI3_K, "sai3_k", sai_src, 0, G_SAI3, M_SAI3), - KCLK(SAI4_K, "sai4_k", sai_src, 0, G_SAI4, M_SAI4), - KCLK(ADC12_K, "adc12_k", adc12_src, 0, G_ADC12, M_ADC12), - KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI), - KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1), - KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO), - - /* Particulary Kernel Clocks (no mux or no gate) */ - MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM), - MGATE_MP1(DSI_PX, "dsi_px", "pll4_q", CLK_SET_RATE_PARENT, G_DSI), - MGATE_MP1(LTDC_PX, "ltdc_px", "pll4_q", CLK_SET_RATE_PARENT, G_LTDC), - MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), - MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), - - COMPOSITE(NO_ID, "ck_ker_eth", eth_src, CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, - _NO_GATE, - _MMUX(M_ETHCK), - _NO_DIV), - - MGATE_MP1(ETHCK_K, "ethck_k", "ck_ker_eth", 0, G_ETHCK), - - DIV(ETHPTP_K, "ethptp_k", "ck_ker_eth", CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, RCC_ETHCKSELR, 4, 4, 0), - - /* RTC clock */ - COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE, - _GATE(RCC_BDCR, 20, 0), - _MUX(RCC_BDCR, 16, 2, 0), - _DIV_RTC(RCC_RTCDIVR, 0, 6, 0, NULL)), - - /* MCO clocks */ - COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, - _GATE(RCC_MCO1CFGR, 12, 0), - _MUX(RCC_MCO1CFGR, 0, 3, 0), - _DIV(RCC_MCO1CFGR, 4, 4, 0, NULL)), - - COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, - _GATE(RCC_MCO2CFGR, 12, 0), - _MUX(RCC_MCO2CFGR, 0, 3, 0), - _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), - - /* Debug clocks */ - GATE(CK_DBG, "ck_sys_dbg", "ck_axi", CLK_IGNORE_UNUSED, - RCC_DBGCFGR, 8, 0), - - COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE, - _GATE(RCC_DBGCFGR, 9, 0), - _NO_MUX, - _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), -}; - -static const u32 stm32mp1_clock_secured[] = { - CK_HSE, - CK_HSI, - CK_CSI, - CK_LSI, - CK_LSE, - PLL1, - PLL2, - PLL1_P, - PLL2_P, - PLL2_Q, - PLL2_R, - CK_MPU, - CK_AXI, - SPI6, - I2C4, - I2C6, - USART1, - RTCAPB, - TZC1, - TZC2, - TZPC, - IWDG1, - BSEC, - STGEN, - GPIOZ, - CRYP1, - HASH1, - RNG1, - BKPSRAM, - RNG1_K, - STGEN_K, - SPI6_K, - I2C4_K, - I2C6_K, - USART1_K, - RTC, -}; - -static bool stm32_check_security(const struct clock_config *cfg) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(stm32mp1_clock_secured); i++) - if (cfg->id == stm32mp1_clock_secured[i]) - return true; - return false; -} - -struct stm32_rcc_match_data { - const struct clock_config *cfg; - unsigned int num; - unsigned int maxbinding; - u32 clear_offset; - bool (*check_security)(const struct clock_config *cfg); -}; - -static struct stm32_rcc_match_data stm32mp1_data = { - .cfg = stm32mp1_clock_cfg, - .num = ARRAY_SIZE(stm32mp1_clock_cfg), - .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR, -}; - -static struct stm32_rcc_match_data stm32mp1_data_secure = { - .cfg = stm32mp1_clock_cfg, - .num = ARRAY_SIZE(stm32mp1_clock_cfg), - .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR, - .check_security = &stm32_check_security -}; - -static const struct of_device_id stm32mp1_match_data[] = { - { - .compatible = "st,stm32mp1-rcc", - .data = &stm32mp1_data, - }, - { - .compatible = "st,stm32mp1-rcc-secure", - .data = &stm32mp1_data_secure, - }, - { } -}; -MODULE_DEVICE_TABLE(of, stm32mp1_match_data); - -static int stm32_register_hw_clk(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct clk_hw **hws; - struct clk_hw *hw = ERR_PTR(-ENOENT); - - hws = clk_data->hws; - - if (cfg->func) - hw = (*cfg->func)(dev, clk_data, base, lock, cfg); - - if (IS_ERR(hw)) { - pr_err("Unable to register %s\n", cfg->name); - return PTR_ERR(hw); - } - - if (cfg->id != NO_ID) - hws[cfg->id] = hw; - - return 0; -} - -#define STM32_RESET_ID_MASK GENMASK(15, 0) - -struct stm32_reset_data { - /* reset lock */ - spinlock_t lock; - struct reset_controller_dev rcdev; - void __iomem *membase; - u32 clear_offset; -}; - -static inline struct stm32_reset_data * -to_stm32_reset_data(struct reset_controller_dev *rcdev) -{ - return container_of(rcdev, struct stm32_reset_data, rcdev); -} - -static int stm32_reset_update(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - struct stm32_reset_data *data = to_stm32_reset_data(rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - - if (data->clear_offset) { - void __iomem *addr; - - addr = data->membase + (bank * reg_width); - if (!assert) - addr += data->clear_offset; - - writel(BIT(offset), addr); - - } else { - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * reg_width)); - - if (assert) - reg |= BIT(offset); - else - reg &= ~BIT(offset); - - writel(reg, data->membase + (bank * reg_width)); - - spin_unlock_irqrestore(&data->lock, flags); - } - - return 0; -} - -static int stm32_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return stm32_reset_update(rcdev, id, true); -} - -static int stm32_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return stm32_reset_update(rcdev, id, false); -} - -static int stm32_reset_status(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct stm32_reset_data *data = to_stm32_reset_data(rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - u32 reg; - - reg = readl(data->membase + (bank * reg_width)); - - return !!(reg & BIT(offset)); -} - -static const struct reset_control_ops stm32_reset_ops = { - .assert = stm32_reset_assert, - .deassert = stm32_reset_deassert, - .status = stm32_reset_status, -}; - -static int stm32_rcc_reset_init(struct device *dev, void __iomem *base, - const struct of_device_id *match) -{ - const struct stm32_rcc_match_data *data = match->data; - struct stm32_reset_data *reset_data = NULL; - - reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); - if (!reset_data) - return -ENOMEM; - - spin_lock_init(&reset_data->lock); - reset_data->membase = base; - reset_data->rcdev.owner = THIS_MODULE; - reset_data->rcdev.ops = &stm32_reset_ops; - reset_data->rcdev.of_node = dev_of_node(dev); - reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK; - reset_data->clear_offset = data->clear_offset; - - return reset_controller_register(&reset_data->rcdev); -} - -static int stm32_rcc_clock_init(struct device *dev, void __iomem *base, - const struct of_device_id *match) -{ - const struct stm32_rcc_match_data *data = match->data; - struct clk_hw_onecell_data *clk_data; - struct clk_hw **hws; - int err, n, max_binding; - - max_binding = data->maxbinding; - - clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding), - GFP_KERNEL); - if (!clk_data) - return -ENOMEM; - - clk_data->num = max_binding; - - hws = clk_data->hws; - - for (n = 0; n < max_binding; n++) - hws[n] = ERR_PTR(-ENOENT); - - for (n = 0; n < data->num; n++) { - if (data->check_security && data->check_security(&data->cfg[n])) - continue; - - err = stm32_register_hw_clk(dev, clk_data, base, &rlock, - &data->cfg[n]); - if (err) { - dev_err(dev, "Can't register clk %s: %d\n", - data->cfg[n].name, err); - - return err; - } - } - - return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, clk_data); -} - -static int stm32_rcc_init(struct device *dev, void __iomem *base, - const struct of_device_id *match_data) -{ - const struct of_device_id *match; - int err; - - match = of_match_node(match_data, dev_of_node(dev)); - if (!match) { - dev_err(dev, "match data not found\n"); - return -ENODEV; - } - - /* RCC Reset Configuration */ - err = stm32_rcc_reset_init(dev, base, match); - if (err) { - pr_err("stm32mp1 reset failed to initialize\n"); - return err; - } - - /* RCC Clock Configuration */ - err = stm32_rcc_clock_init(dev, base, match); - if (err) { - pr_err("stm32mp1 clock failed to initialize\n"); - return err; - } - - return 0; -} - -static int stm32mp1_rcc_init(struct device *dev) -{ - void __iomem *base; - int ret; - - base = of_iomap(dev_of_node(dev), 0); - if (!base) { - pr_err("%pOFn: unable to map resource", dev_of_node(dev)); - ret = -ENOMEM; - goto out; - } - - ret = stm32_rcc_init(dev, base, stm32mp1_match_data); - -out: - if (ret) { - if (base) - iounmap(base); - - of_node_put(dev_of_node(dev)); - } - - return ret; -} - -static int get_clock_deps(struct device *dev) -{ - static const char * const clock_deps_name[] = { - "hsi", "hse", "csi", "lsi", "lse", - }; - size_t deps_size = sizeof(struct clk *) * ARRAY_SIZE(clock_deps_name); - struct clk **clk_deps; - int i; - - clk_deps = devm_kzalloc(dev, deps_size, GFP_KERNEL); - if (!clk_deps) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(clock_deps_name); i++) { - struct clk *clk = of_clk_get_by_name(dev_of_node(dev), - clock_deps_name[i]); - - if (IS_ERR(clk)) { - if (PTR_ERR(clk) != -EINVAL && PTR_ERR(clk) != -ENOENT) - return PTR_ERR(clk); - } else { - /* Device gets a reference count on the clock */ - clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk)); - clk_put(clk); - } - } - - return 0; -} - -static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int ret = get_clock_deps(dev); - - if (!ret) - ret = stm32mp1_rcc_init(dev); - - return ret; -} - -static void stm32mp1_rcc_clocks_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *child, *np = dev_of_node(dev); - - for_each_available_child_of_node(np, child) - of_clk_del_provider(child); -} - -static struct platform_driver stm32mp1_rcc_clocks_driver = { - .driver = { - .name = "stm32mp1_rcc", - .of_match_table = stm32mp1_match_data, - }, - .probe = stm32mp1_rcc_clocks_probe, - .remove_new = stm32mp1_rcc_clocks_remove, -}; - -static int __init stm32mp1_clocks_init(void) -{ - return platform_driver_register(&stm32mp1_rcc_clocks_driver); -} -core_initcall(stm32mp1_clocks_init); diff --git a/drivers/clk/stm32/Kconfig b/drivers/clk/stm32/Kconfig new file mode 100644 index 000000000000..3c8493a94a11 --- /dev/null +++ b/drivers/clk/stm32/Kconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-only +# common clock support for STMicroelectronics SoC family. + +menuconfig COMMON_CLK_STM32MP + bool "Clock support for common STM32MP clocks" + depends on ARCH_STM32 || COMPILE_TEST + default y + select RESET_CONTROLLER + help + Support for STM32MP SoC family clocks. + +if COMMON_CLK_STM32MP + +config COMMON_CLK_STM32MP135 + bool "Clock driver for stm32mp13x clocks" + depends on ARM || COMPILE_TEST + default y + help + Support for stm32mp13x SoC family clocks. + +config COMMON_CLK_STM32MP157 + bool "Clock driver for stm32mp15x clocks" + depends on ARM || COMPILE_TEST + default y + help + Support for stm32mp15x SoC family clocks. + +endif + diff --git a/drivers/clk/stm32/Makefile b/drivers/clk/stm32/Makefile index 95bd2230bba0..c154ef3e88f9 100644 --- a/drivers/clk/stm32/Makefile +++ b/drivers/clk/stm32/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_COMMON_CLK_STM32MP135) += clk-stm32mp13.o clk-stm32-core.o reset-stm32.o +obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c new file mode 100644 index 000000000000..939779f66867 --- /dev/null +++ b/drivers/clk/stm32/clk-stm32mp1.c @@ -0,0 +1,2459 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Olivier Bideau for STMicroelectronics. + * Author: Gabriel Fernandez for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static DEFINE_SPINLOCK(rlock); + +#define RCC_OCENSETR 0x0C +#define RCC_HSICFGR 0x18 +#define RCC_RDLSICR 0x144 +#define RCC_PLL1CR 0x80 +#define RCC_PLL1CFGR1 0x84 +#define RCC_PLL1CFGR2 0x88 +#define RCC_PLL2CR 0x94 +#define RCC_PLL2CFGR1 0x98 +#define RCC_PLL2CFGR2 0x9C +#define RCC_PLL3CR 0x880 +#define RCC_PLL3CFGR1 0x884 +#define RCC_PLL3CFGR2 0x888 +#define RCC_PLL4CR 0x894 +#define RCC_PLL4CFGR1 0x898 +#define RCC_PLL4CFGR2 0x89C +#define RCC_APB1ENSETR 0xA00 +#define RCC_APB2ENSETR 0xA08 +#define RCC_APB3ENSETR 0xA10 +#define RCC_APB4ENSETR 0x200 +#define RCC_APB5ENSETR 0x208 +#define RCC_AHB2ENSETR 0xA18 +#define RCC_AHB3ENSETR 0xA20 +#define RCC_AHB4ENSETR 0xA28 +#define RCC_AHB5ENSETR 0x210 +#define RCC_AHB6ENSETR 0x218 +#define RCC_AHB6LPENSETR 0x318 +#define RCC_RCK12SELR 0x28 +#define RCC_RCK3SELR 0x820 +#define RCC_RCK4SELR 0x824 +#define RCC_MPCKSELR 0x20 +#define RCC_ASSCKSELR 0x24 +#define RCC_MSSCKSELR 0x48 +#define RCC_SPI6CKSELR 0xC4 +#define RCC_SDMMC12CKSELR 0x8F4 +#define RCC_SDMMC3CKSELR 0x8F8 +#define RCC_FMCCKSELR 0x904 +#define RCC_I2C46CKSELR 0xC0 +#define RCC_I2C12CKSELR 0x8C0 +#define RCC_I2C35CKSELR 0x8C4 +#define RCC_UART1CKSELR 0xC8 +#define RCC_QSPICKSELR 0x900 +#define RCC_ETHCKSELR 0x8FC +#define RCC_RNG1CKSELR 0xCC +#define RCC_RNG2CKSELR 0x920 +#define RCC_GPUCKSELR 0x938 +#define RCC_USBCKSELR 0x91C +#define RCC_STGENCKSELR 0xD4 +#define RCC_SPDIFCKSELR 0x914 +#define RCC_SPI2S1CKSELR 0x8D8 +#define RCC_SPI2S23CKSELR 0x8DC +#define RCC_SPI2S45CKSELR 0x8E0 +#define RCC_CECCKSELR 0x918 +#define RCC_LPTIM1CKSELR 0x934 +#define RCC_LPTIM23CKSELR 0x930 +#define RCC_LPTIM45CKSELR 0x92C +#define RCC_UART24CKSELR 0x8E8 +#define RCC_UART35CKSELR 0x8EC +#define RCC_UART6CKSELR 0x8E4 +#define RCC_UART78CKSELR 0x8F0 +#define RCC_FDCANCKSELR 0x90C +#define RCC_SAI1CKSELR 0x8C8 +#define RCC_SAI2CKSELR 0x8CC +#define RCC_SAI3CKSELR 0x8D0 +#define RCC_SAI4CKSELR 0x8D4 +#define RCC_ADCCKSELR 0x928 +#define RCC_MPCKDIVR 0x2C +#define RCC_DSICKSELR 0x924 +#define RCC_CPERCKSELR 0xD0 +#define RCC_MCO1CFGR 0x800 +#define RCC_MCO2CFGR 0x804 +#define RCC_BDCR 0x140 +#define RCC_AXIDIVR 0x30 +#define RCC_MCUDIVR 0x830 +#define RCC_APB1DIVR 0x834 +#define RCC_APB2DIVR 0x838 +#define RCC_APB3DIVR 0x83C +#define RCC_APB4DIVR 0x3C +#define RCC_APB5DIVR 0x40 +#define RCC_TIMG1PRER 0x828 +#define RCC_TIMG2PRER 0x82C +#define RCC_RTCDIVR 0x44 +#define RCC_DBGCFGR 0x80C + +#define RCC_CLR 0x4 + +static const char * const ref12_parents[] = { + "ck_hsi", "ck_hse" +}; + +static const char * const ref3_parents[] = { + "ck_hsi", "ck_hse", "ck_csi" +}; + +static const char * const ref4_parents[] = { + "ck_hsi", "ck_hse", "ck_csi" +}; + +static const char * const cpu_src[] = { + "ck_hsi", "ck_hse", "pll1_p" +}; + +static const char * const axi_src[] = { + "ck_hsi", "ck_hse", "pll2_p" +}; + +static const char * const per_src[] = { + "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const mcu_src[] = { + "ck_hsi", "ck_hse", "ck_csi", "pll3_p" +}; + +static const char * const sdmmc12_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_hsi" +}; + +static const char * const sdmmc3_src[] = { + "ck_mcu", "pll3_r", "pll4_p", "ck_hsi" +}; + +static const char * const fmc_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_per" +}; + +static const char * const qspi_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_per" +}; + +static const char * const eth_src[] = { + "pll4_p", "pll3_q" +}; + +static const struct clk_parent_data ethrx_src[] = { + { .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" }, +}; + +static const char * const rng_src[] = { + "ck_csi", "pll4_r", "ck_lse", "ck_lsi" +}; + +static const char * const usbphy_src[] = { + "ck_hse", "pll4_r", "clk-hse-div2" +}; + +static const char * const usbo_src[] = { + "pll4_r", "ck_usbo_48m" +}; + +static const char * const stgen_src[] = { + "ck_hsi", "ck_hse" +}; + +static const char * const spdif_src[] = { + "pll4_p", "pll3_q", "ck_hsi" +}; + +static const char * const spi123_src[] = { + "pll4_p", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" +}; + +static const char * const spi45_src[] = { + "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const spi6_src[] = { + "pclk5", "pll4_q", "ck_hsi", "ck_csi", "ck_hse", "pll3_q" +}; + +static const char * const cec_src[] = { + "ck_lse", "ck_lsi", "ck_csi" +}; + +static const char * const i2c12_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c35_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c46_src[] = { + "pclk5", "pll3_q", "ck_hsi", "ck_csi" +}; + +static const char * const lptim1_src[] = { + "pclk1", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" +}; + +static const char * const lptim23_src[] = { + "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi" +}; + +static const char * const lptim45_src[] = { + "pclk3", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" +}; + +static const char * const usart1_src[] = { + "pclk5", "pll3_q", "ck_hsi", "ck_csi", "pll4_q", "ck_hse" +}; + +static const char * const usart234578_src[] = { + "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const usart6_src[] = { + "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const fdcan_src[] = { + "ck_hse", "pll3_q", "pll4_q", "pll4_r" +}; + +static const char * const sai_src[] = { + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" +}; + +static const char * const sai2_src[] = { + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r" +}; + +static const char * const adc12_src[] = { + "pll4_r", "ck_per", "pll3_q" +}; + +static const char * const dsi_src[] = { + "ck_dsi_phy", "pll4_p" +}; + +static const char * const rtc_src[] = { + "off", "ck_lse", "ck_lsi", "ck_hse" +}; + +static const char * const mco1_src[] = { + "ck_hsi", "ck_hse", "ck_csi", "ck_lsi", "ck_lse" +}; + +static const char * const mco2_src[] = { + "ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi" +}; + +static const char * const ck_trace_src[] = { + "ck_axi" +}; + +static const struct clk_div_table axi_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, + { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, + { 0 }, +}; + +static const struct clk_div_table mcu_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, + { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 }, + { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, + { 0 }, +}; + +static const struct clk_div_table apb_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, + { 0 }, +}; + +static const struct clk_div_table ck_trace_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, + { 0 }, +}; + +#define MAX_MUX_CLK 2 + +struct stm32_mmux { + u8 nbr_clk; + struct clk_hw *hws[MAX_MUX_CLK]; +}; + +struct stm32_clk_mmux { + struct clk_mux mux; + struct stm32_mmux *mmux; +}; + +struct stm32_mgate { + u8 nbr_clk; + u32 flag; +}; + +struct stm32_clk_mgate { + struct clk_gate gate; + struct stm32_mgate *mgate; + u32 mask; +}; + +struct clock_config { + u32 id; + const char *name; + const char *parent_name; + const char * const *parent_names; + const struct clk_parent_data *parent_data; + int num_parents; + unsigned long flags; + void *cfg; + struct clk_hw * (*func)(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg); +}; + +#define NO_ID ~0 + +struct gate_cfg { + u32 reg_off; + u8 bit_idx; + u8 gate_flags; +}; + +struct fixed_factor_cfg { + unsigned int mult; + unsigned int div; +}; + +struct div_cfg { + u32 reg_off; + u8 shift; + u8 width; + u8 div_flags; + const struct clk_div_table *table; +}; + +struct mux_cfg { + u32 reg_off; + u8 shift; + u8 width; + u8 mux_flags; + u32 *table; +}; + +struct stm32_gate_cfg { + struct gate_cfg *gate; + struct stm32_mgate *mgate; + const struct clk_ops *ops; +}; + +struct stm32_div_cfg { + struct div_cfg *div; + const struct clk_ops *ops; +}; + +struct stm32_mux_cfg { + struct mux_cfg *mux; + struct stm32_mmux *mmux; + const struct clk_ops *ops; +}; + +/* STM32 Composite clock */ +struct stm32_composite_cfg { + const struct stm32_gate_cfg *gate; + const struct stm32_div_cfg *div; + const struct stm32_mux_cfg *mux; +}; + +static struct clk_hw * +_clk_hw_register_gate(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct gate_cfg *gate_cfg = cfg->cfg; + + return clk_hw_register_gate(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + gate_cfg->reg_off + base, + gate_cfg->bit_idx, + gate_cfg->gate_flags, + lock); +} + +static struct clk_hw * +_clk_hw_register_fixed_factor(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct fixed_factor_cfg *ff_cfg = cfg->cfg; + + return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name, + cfg->flags, ff_cfg->mult, + ff_cfg->div); +} + +static struct clk_hw * +_clk_hw_register_divider_table(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct div_cfg *div_cfg = cfg->cfg; + + return clk_hw_register_divider_table(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + div_cfg->reg_off + base, + div_cfg->shift, + div_cfg->width, + div_cfg->div_flags, + div_cfg->table, + lock); +} + +static struct clk_hw * +_clk_hw_register_mux(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct mux_cfg *mux_cfg = cfg->cfg; + + return clk_hw_register_mux(dev, cfg->name, cfg->parent_names, + cfg->num_parents, cfg->flags, + mux_cfg->reg_off + base, mux_cfg->shift, + mux_cfg->width, mux_cfg->mux_flags, lock); +} + +/* MP1 Gate clock with set & clear registers */ + +static int mp1_gate_clk_enable(struct clk_hw *hw) +{ + if (!clk_gate_ops.is_enabled(hw)) + clk_gate_ops.enable(hw); + + return 0; +} + +static void mp1_gate_clk_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + unsigned long flags = 0; + + if (clk_gate_ops.is_enabled(hw)) { + spin_lock_irqsave(gate->lock, flags); + writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR); + spin_unlock_irqrestore(gate->lock, flags); + } +} + +static const struct clk_ops mp1_gate_clk_ops = { + .enable = mp1_gate_clk_enable, + .disable = mp1_gate_clk_disable, + .is_enabled = clk_gate_is_enabled, +}; + +static struct clk_hw *_get_stm32_mux(struct device *dev, void __iomem *base, + const struct stm32_mux_cfg *cfg, + spinlock_t *lock) +{ + struct stm32_clk_mmux *mmux; + struct clk_mux *mux; + struct clk_hw *mux_hw; + + if (cfg->mmux) { + mmux = devm_kzalloc(dev, sizeof(*mmux), GFP_KERNEL); + if (!mmux) + return ERR_PTR(-ENOMEM); + + mmux->mux.reg = cfg->mux->reg_off + base; + mmux->mux.shift = cfg->mux->shift; + mmux->mux.mask = (1 << cfg->mux->width) - 1; + mmux->mux.flags = cfg->mux->mux_flags; + mmux->mux.table = cfg->mux->table; + mmux->mux.lock = lock; + mmux->mmux = cfg->mmux; + mux_hw = &mmux->mux.hw; + cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; + + } else { + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = cfg->mux->reg_off + base; + mux->shift = cfg->mux->shift; + mux->mask = (1 << cfg->mux->width) - 1; + mux->flags = cfg->mux->mux_flags; + mux->table = cfg->mux->table; + mux->lock = lock; + mux_hw = &mux->hw; + } + + return mux_hw; +} + +static struct clk_hw *_get_stm32_div(struct device *dev, void __iomem *base, + const struct stm32_div_cfg *cfg, + spinlock_t *lock) +{ + struct clk_divider *div; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + + if (!div) + return ERR_PTR(-ENOMEM); + + div->reg = cfg->div->reg_off + base; + div->shift = cfg->div->shift; + div->width = cfg->div->width; + div->flags = cfg->div->div_flags; + div->table = cfg->div->table; + div->lock = lock; + + return &div->hw; +} + +static struct clk_hw *_get_stm32_gate(struct device *dev, void __iomem *base, + const struct stm32_gate_cfg *cfg, + spinlock_t *lock) +{ + struct stm32_clk_mgate *mgate; + struct clk_gate *gate; + struct clk_hw *gate_hw; + + if (cfg->mgate) { + mgate = devm_kzalloc(dev, sizeof(*mgate), GFP_KERNEL); + if (!mgate) + return ERR_PTR(-ENOMEM); + + mgate->gate.reg = cfg->gate->reg_off + base; + mgate->gate.bit_idx = cfg->gate->bit_idx; + mgate->gate.flags = cfg->gate->gate_flags; + mgate->gate.lock = lock; + mgate->mask = BIT(cfg->mgate->nbr_clk++); + + mgate->mgate = cfg->mgate; + + gate_hw = &mgate->gate.hw; + + } else { + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->reg = cfg->gate->reg_off + base; + gate->bit_idx = cfg->gate->bit_idx; + gate->flags = cfg->gate->gate_flags; + gate->lock = lock; + + gate_hw = &gate->hw; + } + + return gate_hw; +} + +static struct clk_hw * +clk_stm32_register_gate_ops(struct device *dev, + const char *name, + const char *parent_name, + const struct clk_parent_data *parent_data, + unsigned long flags, + void __iomem *base, + const struct stm32_gate_cfg *cfg, + spinlock_t *lock) +{ + struct clk_init_data init = { NULL }; + struct clk_hw *hw; + int ret; + + init.name = name; + if (parent_name) + init.parent_names = &parent_name; + if (parent_data) + init.parent_data = parent_data; + init.num_parents = 1; + init.flags = flags; + + init.ops = &clk_gate_ops; + + if (cfg->ops) + init.ops = cfg->ops; + + hw = _get_stm32_gate(dev, base, cfg, lock); + if (IS_ERR(hw)) + return ERR_PTR(-ENOMEM); + + hw->init = &init; + + ret = clk_hw_register(dev, hw); + if (ret) + hw = ERR_PTR(ret); + + return hw; +} + +static struct clk_hw * +clk_stm32_register_composite(struct device *dev, + const char *name, const char * const *parent_names, + const struct clk_parent_data *parent_data, + int num_parents, void __iomem *base, + const struct stm32_composite_cfg *cfg, + unsigned long flags, spinlock_t *lock) +{ + const struct clk_ops *mux_ops, *div_ops, *gate_ops; + struct clk_hw *mux_hw, *div_hw, *gate_hw; + + mux_hw = NULL; + div_hw = NULL; + gate_hw = NULL; + mux_ops = NULL; + div_ops = NULL; + gate_ops = NULL; + + if (cfg->mux) { + mux_hw = _get_stm32_mux(dev, base, cfg->mux, lock); + + if (!IS_ERR(mux_hw)) { + mux_ops = &clk_mux_ops; + + if (cfg->mux->ops) + mux_ops = cfg->mux->ops; + } + } + + if (cfg->div) { + div_hw = _get_stm32_div(dev, base, cfg->div, lock); + + if (!IS_ERR(div_hw)) { + div_ops = &clk_divider_ops; + + if (cfg->div->ops) + div_ops = cfg->div->ops; + } + } + + if (cfg->gate) { + gate_hw = _get_stm32_gate(dev, base, cfg->gate, lock); + + if (!IS_ERR(gate_hw)) { + gate_ops = &clk_gate_ops; + + if (cfg->gate->ops) + gate_ops = cfg->gate->ops; + } + } + + return clk_hw_register_composite(dev, name, parent_names, num_parents, + mux_hw, mux_ops, div_hw, div_ops, + gate_hw, gate_ops, flags); +} + +#define to_clk_mgate(_gate) container_of(_gate, struct stm32_clk_mgate, gate) + +static int mp1_mgate_clk_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag |= clk_mgate->mask; + + mp1_gate_clk_enable(hw); + + return 0; +} + +static void mp1_mgate_clk_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag &= ~clk_mgate->mask; + + if (clk_mgate->mgate->flag == 0) + mp1_gate_clk_disable(hw); +} + +static const struct clk_ops mp1_mgate_clk_ops = { + .enable = mp1_mgate_clk_enable, + .disable = mp1_mgate_clk_disable, + .is_enabled = clk_gate_is_enabled, + +}; + +#define to_clk_mmux(_mux) container_of(_mux, struct stm32_clk_mmux, mux) + +static u8 clk_mmux_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + struct clk_hw *hwp; + int ret, n; + + ret = clk_mux_ops.set_parent(hw, index); + if (ret) + return ret; + + hwp = clk_hw_get_parent(hw); + + for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) + if (clk_mmux->mmux->hws[n] != hw) + clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); + + return 0; +} + +static const struct clk_ops clk_mmux_ops = { + .get_parent = clk_mmux_get_parent, + .set_parent = clk_mmux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +/* STM32 PLL */ +struct stm32_pll_obj { + /* lock pll enable/disable registers */ + spinlock_t *lock; + void __iomem *reg; + struct clk_hw hw; + struct clk_mux mux; +}; + +#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) + +#define PLL_ON BIT(0) +#define PLL_RDY BIT(1) +#define DIVN_MASK 0x1FF +#define DIVM_MASK 0x3F +#define DIVM_SHIFT 16 +#define DIVN_SHIFT 0 +#define FRAC_OFFSET 0xC +#define FRAC_MASK 0x1FFF +#define FRAC_SHIFT 3 +#define FRACLE BIT(16) +#define PLL_MUX_SHIFT 0 +#define PLL_MUX_MASK 3 + +static int __pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + + return readl_relaxed(clk_elem->reg) & PLL_ON; +} + +#define TIMEOUT 5 + +static int pll_enable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + unsigned int timeout = TIMEOUT; + int bit_status = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + if (__pll_is_enabled(hw)) + goto unlock; + + reg = readl_relaxed(clk_elem->reg); + reg |= PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + /* We can't use readl_poll_timeout() because we can be blocked if + * someone enables this clock before clocksource changes. + * Only jiffies counter is available. Jiffies are incremented by + * interruptions and enable op does not allow to be interrupted. + */ + do { + bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); + + if (bit_status) + udelay(120); + + } while (bit_status && --timeout); + +unlock: + spin_unlock_irqrestore(clk_elem->lock, flags); + + return bit_status; +} + +static void pll_disable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + reg = readl_relaxed(clk_elem->reg); + reg &= ~PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + spin_unlock_irqrestore(clk_elem->lock, flags); +} + +static u32 pll_frac_val(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg, frac = 0; + + reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); + if (reg & FRACLE) + frac = (reg >> FRAC_SHIFT) & FRAC_MASK; + + return frac; +} + +static unsigned long pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + u32 frac, divm, divn; + u64 rate, rate_frac = 0; + + reg = readl_relaxed(clk_elem->reg + 4); + + divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; + divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; + rate = (u64)parent_rate * divn; + + do_div(rate, divm); + + frac = pll_frac_val(hw); + if (frac) { + rate_frac = (u64)parent_rate * (u64)frac; + do_div(rate_frac, (divm * 8192)); + } + + return rate + rate_frac; +} + +static int pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + unsigned long flags = 0; + int ret; + + spin_lock_irqsave(clk_elem->lock, flags); + ret = __pll_is_enabled(hw); + spin_unlock_irqrestore(clk_elem->lock, flags); + + return ret; +} + +static u8 pll_get_parent(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + struct clk_hw *mux_hw = &clk_elem->mux.hw; + + __clk_hw_set_clk(mux_hw, hw); + + return clk_mux_ops.get_parent(mux_hw); +} + +static const struct clk_ops pll_ops = { + .enable = pll_enable, + .disable = pll_disable, + .recalc_rate = pll_recalc_rate, + .is_enabled = pll_is_enabled, + .get_parent = pll_get_parent, +}; + +static struct clk_hw *clk_register_pll(struct device *dev, const char *name, + const char * const *parent_names, + int num_parents, + void __iomem *reg, + void __iomem *mux_reg, + unsigned long flags, + spinlock_t *lock) +{ + struct stm32_pll_obj *element; + struct clk_init_data init; + struct clk_hw *hw; + int err; + + element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL); + if (!element) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; + + element->mux.lock = lock; + element->mux.reg = mux_reg; + element->mux.shift = PLL_MUX_SHIFT; + element->mux.mask = PLL_MUX_MASK; + element->mux.flags = CLK_MUX_READ_ONLY; + element->mux.reg = mux_reg; + + element->hw.init = &init; + element->reg = reg; + element->lock = lock; + + hw = &element->hw; + err = clk_hw_register(dev, hw); + + if (err) + return ERR_PTR(err); + + return hw; +} + +/* Kernel Timer */ +struct timer_cker { + /* lock the kernel output divider register */ + spinlock_t *lock; + void __iomem *apbdiv; + void __iomem *timpre; + struct clk_hw hw; +}; + +#define to_timer_cker(_hw) container_of(_hw, struct timer_cker, hw) + +#define APB_DIV_MASK 0x07 +#define TIM_PRE_MASK 0x01 + +static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + u32 prescaler; + unsigned int mult = 0; + + prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; + if (prescaler < 2) + return 1; + + mult = 2; + + if (rate / parent_rate >= 4) + mult = 4; + + return mult; +} + +static long timer_ker_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long factor = __bestmult(hw, rate, *parent_rate); + + return *parent_rate * factor; +} + +static int timer_ker_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + unsigned long flags = 0; + unsigned long factor = __bestmult(hw, rate, parent_rate); + int ret = 0; + + spin_lock_irqsave(tim_ker->lock, flags); + + switch (factor) { + case 1: + break; + case 2: + writel_relaxed(0, tim_ker->timpre); + break; + case 4: + writel_relaxed(1, tim_ker->timpre); + break; + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(tim_ker->lock, flags); + + return ret; +} + +static unsigned long timer_ker_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + u32 prescaler, timpre; + u32 mul; + + prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; + + timpre = readl_relaxed(tim_ker->timpre) & TIM_PRE_MASK; + + if (!prescaler) + return parent_rate; + + mul = (timpre + 1) * 2; + + return parent_rate * mul; +} + +static const struct clk_ops timer_ker_ops = { + .recalc_rate = timer_ker_recalc_rate, + .round_rate = timer_ker_round_rate, + .set_rate = timer_ker_set_rate, + +}; + +static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *apbdiv, + void __iomem *timpre, + spinlock_t *lock) +{ + struct timer_cker *tim_ker; + struct clk_init_data init; + struct clk_hw *hw; + int err; + + tim_ker = devm_kzalloc(dev, sizeof(*tim_ker), GFP_KERNEL); + if (!tim_ker) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &timer_ker_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + tim_ker->hw.init = &init; + tim_ker->lock = lock; + tim_ker->apbdiv = apbdiv; + tim_ker->timpre = timpre; + + hw = &tim_ker->hw; + err = clk_hw_register(dev, hw); + + if (err) + return ERR_PTR(err); + + return hw; +} + +/* The divider of RTC clock concerns only ck_hse clock */ +#define HSE_RTC 3 + +static unsigned long clk_divider_rtc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) + return clk_divider_ops.recalc_rate(hw, parent_rate); + + return parent_rate; +} + +static int clk_divider_rtc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) + return clk_divider_ops.set_rate(hw, rate, parent_rate); + + return parent_rate; +} + +static int clk_divider_rtc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + if (req->best_parent_hw == clk_hw_get_parent_by_index(hw, HSE_RTC)) + return clk_divider_ops.determine_rate(hw, req); + + req->rate = req->best_parent_rate; + + return 0; +} + +static const struct clk_ops rtc_div_clk_ops = { + .recalc_rate = clk_divider_rtc_recalc_rate, + .set_rate = clk_divider_rtc_set_rate, + .determine_rate = clk_divider_rtc_determine_rate +}; + +struct stm32_pll_cfg { + u32 offset; + u32 muxoff; +}; + +static struct clk_hw *_clk_register_pll(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; + + return clk_register_pll(dev, cfg->name, cfg->parent_names, + cfg->num_parents, + base + stm_pll_cfg->offset, + base + stm_pll_cfg->muxoff, + cfg->flags, lock); +} + +struct stm32_cktim_cfg { + u32 offset_apbdiv; + u32 offset_timpre; +}; + +static struct clk_hw *_clk_register_cktim(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct stm32_cktim_cfg *cktim_cfg = cfg->cfg; + + return clk_register_cktim(dev, cfg->name, cfg->parent_name, cfg->flags, + cktim_cfg->offset_apbdiv + base, + cktim_cfg->offset_timpre + base, lock); +} + +static struct clk_hw * +_clk_stm32_register_gate(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + return clk_stm32_register_gate_ops(dev, + cfg->name, + cfg->parent_name, + cfg->parent_data, + cfg->flags, + base, + cfg->cfg, + lock); +} + +static struct clk_hw * +_clk_stm32_register_composite(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names, + cfg->parent_data, cfg->num_parents, + base, cfg->cfg, cfg->flags, lock); +} + +#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct gate_cfg) {\ + .reg_off = _offset,\ + .bit_idx = _bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .func = _clk_hw_register_gate,\ +} + +#define FIXED_FACTOR(_id, _name, _parent, _flags, _mult, _div)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct fixed_factor_cfg) {\ + .mult = _mult,\ + .div = _div,\ + },\ + .func = _clk_hw_register_fixed_factor,\ +} + +#define DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ + _div_flags, _div_table)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct div_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .div_flags = _div_flags,\ + .table = _div_table,\ + },\ + .func = _clk_hw_register_divider_table,\ +} + +#define DIV(_id, _name, _parent, _flags, _offset, _shift, _width, _div_flags)\ + DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ + _div_flags, NULL) + +#define MUX(_id, _name, _parents, _flags, _offset, _shift, _width, _mux_flags)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + },\ + .func = _clk_hw_register_mux,\ +} + +#define PLL(_id, _name, _parents, _flags, _offset_p, _offset_mux)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = CLK_IGNORE_UNUSED | (_flags),\ + .cfg = &(struct stm32_pll_cfg) {\ + .offset = _offset_p,\ + .muxoff = _offset_mux,\ + },\ + .func = _clk_register_pll,\ +} + +#define STM32_CKTIM(_name, _parent, _flags, _offset_apbdiv, _offset_timpre)\ +{\ + .id = NO_ID,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct stm32_cktim_cfg) {\ + .offset_apbdiv = _offset_apbdiv,\ + .offset_timpre = _offset_timpre,\ + },\ + .func = _clk_register_cktim,\ +} + +#define STM32_TIM(_id, _name, _parent, _offset_set, _bit_idx)\ + GATE_MP1(_id, _name, _parent, CLK_SET_RATE_PARENT,\ + _offset_set, _bit_idx, 0) + +/* STM32 GATE */ +#define STM32_GATE(_id, _name, _parent, _flags, _gate)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = (struct stm32_gate_cfg *) {_gate},\ + .func = _clk_stm32_register_gate,\ +} + +#define STM32_GATE_PDATA(_id, _name, _parent, _flags, _gate)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_data = _parent,\ + .flags = _flags,\ + .cfg = (struct stm32_gate_cfg *) {_gate},\ + .func = _clk_stm32_register_gate,\ +} + +#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ + (&(struct stm32_gate_cfg) {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .mgate = _mgate,\ + .ops = _ops,\ + }) + +#define _STM32_MGATE(_mgate)\ + (&per_gate_cfg[_mgate]) + +#define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, NULL)\ + +#define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, &mp1_gate_clk_ops)\ + +#define _MGATE_MP1(_mgate)\ + .gate = &per_gate_cfg[_mgate] + +#define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _GATE_MP1(_offset, _bit_idx, _gate_flags)) + +#define MGATE_MP1(_id, _name, _parent, _flags, _mgate)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _STM32_MGATE(_mgate)) + +#define MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)\ + STM32_GATE_PDATA(_id, _name, _parent, _flags,\ + _STM32_MGATE(_mgate)) + +#define _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, _ops)\ + .div = &(struct stm32_div_cfg) {\ + &(struct div_cfg) {\ + .reg_off = _div_offset,\ + .shift = _div_shift,\ + .width = _div_width,\ + .div_flags = _div_flags,\ + .table = _div_table,\ + },\ + .ops = _ops,\ + } + +#define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, NULL)\ + +#define _DIV_RTC(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, &rtc_div_clk_ops) + +#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ + .mux = &(struct stm32_mux_cfg) {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .mmux = _mmux,\ + .ops = _ops,\ + } + +#define _MUX(_offset, _shift, _width, _mux_flags)\ + _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ + +#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] + +#define PARENT(_parent) ((const char *[]) { _parent}) + +#define _NO_MUX .mux = NULL +#define _NO_DIV .div = NULL +#define _NO_GATE .gate = NULL + +#define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct stm32_composite_cfg) {\ + _gate,\ + _mux,\ + _div,\ + },\ + .func = _clk_stm32_register_composite,\ +} + +#define PCLK(_id, _name, _parent, _flags, _mgate)\ + MGATE_MP1(_id, _name, _parent, _flags, _mgate) + +#define PCLK_PDATA(_id, _name, _parent, _flags, _mgate)\ + MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate) + +#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ + COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\ + CLK_SET_RATE_NO_REPARENT | _flags,\ + _MGATE_MP1(_mgate),\ + _MMUX(_mmux),\ + _NO_DIV) + +enum { + G_SAI1, + G_SAI2, + G_SAI3, + G_SAI4, + G_SPI1, + G_SPI2, + G_SPI3, + G_SPI4, + G_SPI5, + G_SPI6, + G_SPDIF, + G_I2C1, + G_I2C2, + G_I2C3, + G_I2C4, + G_I2C5, + G_I2C6, + G_USART2, + G_UART4, + G_USART3, + G_UART5, + G_USART1, + G_USART6, + G_UART7, + G_UART8, + G_LPTIM1, + G_LPTIM2, + G_LPTIM3, + G_LPTIM4, + G_LPTIM5, + G_LTDC, + G_DSI, + G_QSPI, + G_FMC, + G_SDMMC1, + G_SDMMC2, + G_SDMMC3, + G_USBO, + G_USBPHY, + G_RNG1, + G_RNG2, + G_FDCAN, + G_DAC12, + G_CEC, + G_ADC12, + G_GPU, + G_STGEN, + G_DFSDM, + G_ADFSDM, + G_TIM2, + G_TIM3, + G_TIM4, + G_TIM5, + G_TIM6, + G_TIM7, + G_TIM12, + G_TIM13, + G_TIM14, + G_MDIO, + G_TIM1, + G_TIM8, + G_TIM15, + G_TIM16, + G_TIM17, + G_SYSCFG, + G_VREF, + G_TMPSENS, + G_PMBCTRL, + G_HDP, + G_IWDG2, + G_STGENRO, + G_DMA1, + G_DMA2, + G_DMAMUX, + G_DCMI, + G_CRYP2, + G_HASH2, + G_CRC2, + G_HSEM, + G_IPCC, + G_GPIOA, + G_GPIOB, + G_GPIOC, + G_GPIOD, + G_GPIOE, + G_GPIOF, + G_GPIOG, + G_GPIOH, + G_GPIOI, + G_GPIOJ, + G_GPIOK, + G_MDMA, + G_ETHCK, + G_ETHTX, + G_ETHRX, + G_ETHMAC, + G_CRC1, + G_USBH, + G_ETHSTP, + G_RTCAPB, + G_TZC1, + G_TZC2, + G_TZPC, + G_IWDG1, + G_BSEC, + G_GPIOZ, + G_CRYP1, + G_HASH1, + G_BKPSRAM, + G_DDRPERFM, + + G_LAST +}; + +static struct stm32_mgate mp1_mgate[G_LAST]; + +#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + _mgate, _ops)\ + [_id] = {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .mgate = _mgate,\ + .ops = _ops,\ + } + +#define K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, &mp1_gate_clk_ops) + +#define K_MGATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + &mp1_mgate[_id], &mp1_mgate_clk_ops) + +/* Peripheral gates */ +static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + /* Multi gates */ + K_GATE(G_MDIO, RCC_APB1ENSETR, 31, 0), + K_MGATE(G_DAC12, RCC_APB1ENSETR, 29, 0), + K_MGATE(G_CEC, RCC_APB1ENSETR, 27, 0), + K_MGATE(G_SPDIF, RCC_APB1ENSETR, 26, 0), + K_MGATE(G_I2C5, RCC_APB1ENSETR, 24, 0), + K_MGATE(G_I2C3, RCC_APB1ENSETR, 23, 0), + K_MGATE(G_I2C2, RCC_APB1ENSETR, 22, 0), + K_MGATE(G_I2C1, RCC_APB1ENSETR, 21, 0), + K_MGATE(G_UART8, RCC_APB1ENSETR, 19, 0), + K_MGATE(G_UART7, RCC_APB1ENSETR, 18, 0), + K_MGATE(G_UART5, RCC_APB1ENSETR, 17, 0), + K_MGATE(G_UART4, RCC_APB1ENSETR, 16, 0), + K_MGATE(G_USART3, RCC_APB1ENSETR, 15, 0), + K_MGATE(G_USART2, RCC_APB1ENSETR, 14, 0), + K_MGATE(G_SPI3, RCC_APB1ENSETR, 12, 0), + K_MGATE(G_SPI2, RCC_APB1ENSETR, 11, 0), + K_MGATE(G_LPTIM1, RCC_APB1ENSETR, 9, 0), + K_GATE(G_TIM14, RCC_APB1ENSETR, 8, 0), + K_GATE(G_TIM13, RCC_APB1ENSETR, 7, 0), + K_GATE(G_TIM12, RCC_APB1ENSETR, 6, 0), + K_GATE(G_TIM7, RCC_APB1ENSETR, 5, 0), + K_GATE(G_TIM6, RCC_APB1ENSETR, 4, 0), + K_GATE(G_TIM5, RCC_APB1ENSETR, 3, 0), + K_GATE(G_TIM4, RCC_APB1ENSETR, 2, 0), + K_GATE(G_TIM3, RCC_APB1ENSETR, 1, 0), + K_GATE(G_TIM2, RCC_APB1ENSETR, 0, 0), + + K_MGATE(G_FDCAN, RCC_APB2ENSETR, 24, 0), + K_GATE(G_ADFSDM, RCC_APB2ENSETR, 21, 0), + K_GATE(G_DFSDM, RCC_APB2ENSETR, 20, 0), + K_MGATE(G_SAI3, RCC_APB2ENSETR, 18, 0), + K_MGATE(G_SAI2, RCC_APB2ENSETR, 17, 0), + K_MGATE(G_SAI1, RCC_APB2ENSETR, 16, 0), + K_MGATE(G_USART6, RCC_APB2ENSETR, 13, 0), + K_MGATE(G_SPI5, RCC_APB2ENSETR, 10, 0), + K_MGATE(G_SPI4, RCC_APB2ENSETR, 9, 0), + K_MGATE(G_SPI1, RCC_APB2ENSETR, 8, 0), + K_GATE(G_TIM17, RCC_APB2ENSETR, 4, 0), + K_GATE(G_TIM16, RCC_APB2ENSETR, 3, 0), + K_GATE(G_TIM15, RCC_APB2ENSETR, 2, 0), + K_GATE(G_TIM8, RCC_APB2ENSETR, 1, 0), + K_GATE(G_TIM1, RCC_APB2ENSETR, 0, 0), + + K_GATE(G_HDP, RCC_APB3ENSETR, 20, 0), + K_GATE(G_PMBCTRL, RCC_APB3ENSETR, 17, 0), + K_GATE(G_TMPSENS, RCC_APB3ENSETR, 16, 0), + K_GATE(G_VREF, RCC_APB3ENSETR, 13, 0), + K_GATE(G_SYSCFG, RCC_APB3ENSETR, 11, 0), + K_MGATE(G_SAI4, RCC_APB3ENSETR, 8, 0), + K_MGATE(G_LPTIM5, RCC_APB3ENSETR, 3, 0), + K_MGATE(G_LPTIM4, RCC_APB3ENSETR, 2, 0), + K_MGATE(G_LPTIM3, RCC_APB3ENSETR, 1, 0), + K_MGATE(G_LPTIM2, RCC_APB3ENSETR, 0, 0), + + K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), + K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), + K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), + K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0), + K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), + K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), + + K_GATE(G_STGEN, RCC_APB5ENSETR, 20, 0), + K_GATE(G_BSEC, RCC_APB5ENSETR, 16, 0), + K_GATE(G_IWDG1, RCC_APB5ENSETR, 15, 0), + K_GATE(G_TZPC, RCC_APB5ENSETR, 13, 0), + K_GATE(G_TZC2, RCC_APB5ENSETR, 12, 0), + K_GATE(G_TZC1, RCC_APB5ENSETR, 11, 0), + K_GATE(G_RTCAPB, RCC_APB5ENSETR, 8, 0), + K_MGATE(G_USART1, RCC_APB5ENSETR, 4, 0), + K_MGATE(G_I2C6, RCC_APB5ENSETR, 3, 0), + K_MGATE(G_I2C4, RCC_APB5ENSETR, 2, 0), + K_MGATE(G_SPI6, RCC_APB5ENSETR, 0, 0), + + K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), + K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), + K_MGATE(G_ADC12, RCC_AHB2ENSETR, 5, 0), + K_GATE(G_DMAMUX, RCC_AHB2ENSETR, 2, 0), + K_GATE(G_DMA2, RCC_AHB2ENSETR, 1, 0), + K_GATE(G_DMA1, RCC_AHB2ENSETR, 0, 0), + + K_GATE(G_IPCC, RCC_AHB3ENSETR, 12, 0), + K_GATE(G_HSEM, RCC_AHB3ENSETR, 11, 0), + K_GATE(G_CRC2, RCC_AHB3ENSETR, 7, 0), + K_MGATE(G_RNG2, RCC_AHB3ENSETR, 6, 0), + K_GATE(G_HASH2, RCC_AHB3ENSETR, 5, 0), + K_GATE(G_CRYP2, RCC_AHB3ENSETR, 4, 0), + K_GATE(G_DCMI, RCC_AHB3ENSETR, 0, 0), + + K_GATE(G_GPIOK, RCC_AHB4ENSETR, 10, 0), + K_GATE(G_GPIOJ, RCC_AHB4ENSETR, 9, 0), + K_GATE(G_GPIOI, RCC_AHB4ENSETR, 8, 0), + K_GATE(G_GPIOH, RCC_AHB4ENSETR, 7, 0), + K_GATE(G_GPIOG, RCC_AHB4ENSETR, 6, 0), + K_GATE(G_GPIOF, RCC_AHB4ENSETR, 5, 0), + K_GATE(G_GPIOE, RCC_AHB4ENSETR, 4, 0), + K_GATE(G_GPIOD, RCC_AHB4ENSETR, 3, 0), + K_GATE(G_GPIOC, RCC_AHB4ENSETR, 2, 0), + K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), + K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), + + K_GATE(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), + K_MGATE(G_RNG1, RCC_AHB5ENSETR, 6, 0), + K_GATE(G_HASH1, RCC_AHB5ENSETR, 5, 0), + K_GATE(G_CRYP1, RCC_AHB5ENSETR, 4, 0), + K_GATE(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), + + K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), + K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), + K_MGATE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), + K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), + K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), + K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), + K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), + K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), + K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), + K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), + K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), + K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), + K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), +}; + +enum { + M_SDMMC12, + M_SDMMC3, + M_FMC, + M_QSPI, + M_RNG1, + M_RNG2, + M_USBPHY, + M_USBO, + M_STGEN, + M_SPDIF, + M_SPI1, + M_SPI23, + M_SPI45, + M_SPI6, + M_CEC, + M_I2C12, + M_I2C35, + M_I2C46, + M_LPTIM1, + M_LPTIM23, + M_LPTIM45, + M_USART1, + M_UART24, + M_UART35, + M_USART6, + M_UART78, + M_SAI1, + M_SAI2, + M_SAI3, + M_SAI4, + M_DSI, + M_FDCAN, + M_ADC12, + M_ETHCK, + M_CKPER, + M_LAST +}; + +static struct stm32_mmux ker_mux[M_LAST]; + +#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops)\ + [_id] = {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .mmux = _mmux,\ + .ops = _ops,\ + } + +#define K_MUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + NULL, NULL) + +#define K_MMUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + &ker_mux[_id], &clk_mmux_ops) + +static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + /* Kernel multi mux */ + K_MMUX(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), + K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), + K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), + K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), + K_MMUX(M_I2C35, RCC_I2C35CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM23, RCC_LPTIM23CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM45, RCC_LPTIM45CKSELR, 0, 3, 0), + K_MMUX(M_UART24, RCC_UART24CKSELR, 0, 3, 0), + K_MMUX(M_UART35, RCC_UART35CKSELR, 0, 3, 0), + K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), + K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), + K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), + K_MMUX(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), + + /* Kernel simple mux */ + K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), + K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), + K_MUX(M_FMC, RCC_FMCCKSELR, 0, 2, 0), + K_MUX(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), + K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), + K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), + K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), + K_MUX(M_SPI1, RCC_SPI2S1CKSELR, 0, 3, 0), + K_MUX(M_CEC, RCC_CECCKSELR, 0, 2, 0), + K_MUX(M_LPTIM1, RCC_LPTIM1CKSELR, 0, 3, 0), + K_MUX(M_USART6, RCC_UART6CKSELR, 0, 3, 0), + K_MUX(M_FDCAN, RCC_FDCANCKSELR, 0, 2, 0), + K_MUX(M_SAI2, RCC_SAI2CKSELR, 0, 3, 0), + K_MUX(M_SAI3, RCC_SAI3CKSELR, 0, 3, 0), + K_MUX(M_SAI4, RCC_SAI4CKSELR, 0, 3, 0), + K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), + K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), + K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), + K_MUX(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), + K_MUX(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), + K_MUX(M_USART1, RCC_UART1CKSELR, 0, 3, 0), + K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), +}; + +static const struct clock_config stm32mp1_clock_cfg[] = { + /* External / Internal Oscillators */ + GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), + /* ck_csi is used by IO compensation and should be critical */ + GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, + RCC_OCENSETR, 4, 0), + COMPOSITE(CK_HSI, "ck_hsi", PARENT("clk-hsi"), 0, + _GATE_MP1(RCC_OCENSETR, 0, 0), + _NO_MUX, + _DIV(RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_READ_ONLY, NULL)), + GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), + GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), + + FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), + + /* PLLs */ + PLL(PLL1, "pll1", ref12_parents, 0, RCC_PLL1CR, RCC_RCK12SELR), + PLL(PLL2, "pll2", ref12_parents, 0, RCC_PLL2CR, RCC_RCK12SELR), + PLL(PLL3, "pll3", ref3_parents, 0, RCC_PLL3CR, RCC_RCK3SELR), + PLL(PLL4, "pll4", ref4_parents, 0, RCC_PLL4CR, RCC_RCK4SELR), + + /* ODF */ + COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, + _GATE(RCC_PLL1CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, + _GATE(RCC_PLL2CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), + + /* MUX system clocks */ + MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, + RCC_CPERCKSELR, 0, 2, 0), + + MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | + CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), + + COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | + CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MUX(RCC_ASSCKSELR, 0, 2, 0), + _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), + + COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | + CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MUX(RCC_MSSCKSELR, 0, 2, 0), + _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), + + DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + /* Kernel Timers */ + STM32_CKTIM("ck1_tim", "pclk1", 0, RCC_APB1DIVR, RCC_TIMG1PRER), + STM32_CKTIM("ck2_tim", "pclk2", 0, RCC_APB2DIVR, RCC_TIMG2PRER), + + STM32_TIM(TIM2_K, "tim2_k", "ck1_tim", RCC_APB1ENSETR, 0), + STM32_TIM(TIM3_K, "tim3_k", "ck1_tim", RCC_APB1ENSETR, 1), + STM32_TIM(TIM4_K, "tim4_k", "ck1_tim", RCC_APB1ENSETR, 2), + STM32_TIM(TIM5_K, "tim5_k", "ck1_tim", RCC_APB1ENSETR, 3), + STM32_TIM(TIM6_K, "tim6_k", "ck1_tim", RCC_APB1ENSETR, 4), + STM32_TIM(TIM7_K, "tim7_k", "ck1_tim", RCC_APB1ENSETR, 5), + STM32_TIM(TIM12_K, "tim12_k", "ck1_tim", RCC_APB1ENSETR, 6), + STM32_TIM(TIM13_K, "tim13_k", "ck1_tim", RCC_APB1ENSETR, 7), + STM32_TIM(TIM14_K, "tim14_k", "ck1_tim", RCC_APB1ENSETR, 8), + STM32_TIM(TIM1_K, "tim1_k", "ck2_tim", RCC_APB2ENSETR, 0), + STM32_TIM(TIM8_K, "tim8_k", "ck2_tim", RCC_APB2ENSETR, 1), + STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2), + STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3), + STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4), + + /* Peripheral clocks */ + PCLK(TIM2, "tim2", "pclk1", CLK_IGNORE_UNUSED, G_TIM2), + PCLK(TIM3, "tim3", "pclk1", CLK_IGNORE_UNUSED, G_TIM3), + PCLK(TIM4, "tim4", "pclk1", CLK_IGNORE_UNUSED, G_TIM4), + PCLK(TIM5, "tim5", "pclk1", CLK_IGNORE_UNUSED, G_TIM5), + PCLK(TIM6, "tim6", "pclk1", CLK_IGNORE_UNUSED, G_TIM6), + PCLK(TIM7, "tim7", "pclk1", CLK_IGNORE_UNUSED, G_TIM7), + PCLK(TIM12, "tim12", "pclk1", CLK_IGNORE_UNUSED, G_TIM12), + PCLK(TIM13, "tim13", "pclk1", CLK_IGNORE_UNUSED, G_TIM13), + PCLK(TIM14, "tim14", "pclk1", CLK_IGNORE_UNUSED, G_TIM14), + PCLK(LPTIM1, "lptim1", "pclk1", 0, G_LPTIM1), + PCLK(SPI2, "spi2", "pclk1", 0, G_SPI2), + PCLK(SPI3, "spi3", "pclk1", 0, G_SPI3), + PCLK(USART2, "usart2", "pclk1", 0, G_USART2), + PCLK(USART3, "usart3", "pclk1", 0, G_USART3), + PCLK(UART4, "uart4", "pclk1", 0, G_UART4), + PCLK(UART5, "uart5", "pclk1", 0, G_UART5), + PCLK(UART7, "uart7", "pclk1", 0, G_UART7), + PCLK(UART8, "uart8", "pclk1", 0, G_UART8), + PCLK(I2C1, "i2c1", "pclk1", 0, G_I2C1), + PCLK(I2C2, "i2c2", "pclk1", 0, G_I2C2), + PCLK(I2C3, "i2c3", "pclk1", 0, G_I2C3), + PCLK(I2C5, "i2c5", "pclk1", 0, G_I2C5), + PCLK(SPDIF, "spdif", "pclk1", 0, G_SPDIF), + PCLK(CEC, "cec", "pclk1", 0, G_CEC), + PCLK(DAC12, "dac12", "pclk1", 0, G_DAC12), + PCLK(MDIO, "mdio", "pclk1", 0, G_MDIO), + PCLK(TIM1, "tim1", "pclk2", CLK_IGNORE_UNUSED, G_TIM1), + PCLK(TIM8, "tim8", "pclk2", CLK_IGNORE_UNUSED, G_TIM8), + PCLK(TIM15, "tim15", "pclk2", CLK_IGNORE_UNUSED, G_TIM15), + PCLK(TIM16, "tim16", "pclk2", CLK_IGNORE_UNUSED, G_TIM16), + PCLK(TIM17, "tim17", "pclk2", CLK_IGNORE_UNUSED, G_TIM17), + PCLK(SPI1, "spi1", "pclk2", 0, G_SPI1), + PCLK(SPI4, "spi4", "pclk2", 0, G_SPI4), + PCLK(SPI5, "spi5", "pclk2", 0, G_SPI5), + PCLK(USART6, "usart6", "pclk2", 0, G_USART6), + PCLK(SAI1, "sai1", "pclk2", 0, G_SAI1), + PCLK(SAI2, "sai2", "pclk2", 0, G_SAI2), + PCLK(SAI3, "sai3", "pclk2", 0, G_SAI3), + PCLK(DFSDM, "dfsdm", "pclk2", 0, G_DFSDM), + PCLK(FDCAN, "fdcan", "pclk2", 0, G_FDCAN), + PCLK(LPTIM2, "lptim2", "pclk3", 0, G_LPTIM2), + PCLK(LPTIM3, "lptim3", "pclk3", 0, G_LPTIM3), + PCLK(LPTIM4, "lptim4", "pclk3", 0, G_LPTIM4), + PCLK(LPTIM5, "lptim5", "pclk3", 0, G_LPTIM5), + PCLK(SAI4, "sai4", "pclk3", 0, G_SAI4), + PCLK(SYSCFG, "syscfg", "pclk3", 0, G_SYSCFG), + PCLK(VREF, "vref", "pclk3", 13, G_VREF), + PCLK(TMPSENS, "tmpsens", "pclk3", 0, G_TMPSENS), + PCLK(PMBCTRL, "pmbctrl", "pclk3", 0, G_PMBCTRL), + PCLK(HDP, "hdp", "pclk3", 0, G_HDP), + PCLK(LTDC, "ltdc", "pclk4", 0, G_LTDC), + PCLK(DSI, "dsi", "pclk4", 0, G_DSI), + PCLK(IWDG2, "iwdg2", "pclk4", 0, G_IWDG2), + PCLK(USBPHY, "usbphy", "pclk4", 0, G_USBPHY), + PCLK(STGENRO, "stgenro", "pclk4", 0, G_STGENRO), + PCLK(SPI6, "spi6", "pclk5", 0, G_SPI6), + PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), + PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), + PCLK(USART1, "usart1", "pclk5", 0, G_USART1), + PCLK(RTCAPB, "rtcapb", "pclk5", CLK_IGNORE_UNUSED | + CLK_IS_CRITICAL, G_RTCAPB), + PCLK(TZC1, "tzc1", "ck_axi", CLK_IGNORE_UNUSED, G_TZC1), + PCLK(TZC2, "tzc2", "ck_axi", CLK_IGNORE_UNUSED, G_TZC2), + PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), + PCLK(IWDG1, "iwdg1", "pclk5", 0, G_IWDG1), + PCLK(BSEC, "bsec", "pclk5", CLK_IGNORE_UNUSED, G_BSEC), + PCLK(STGEN, "stgen", "pclk5", CLK_IGNORE_UNUSED, G_STGEN), + PCLK(DMA1, "dma1", "ck_mcu", 0, G_DMA1), + PCLK(DMA2, "dma2", "ck_mcu", 0, G_DMA2), + PCLK(DMAMUX, "dmamux", "ck_mcu", 0, G_DMAMUX), + PCLK(ADC12, "adc12", "ck_mcu", 0, G_ADC12), + PCLK(USBO, "usbo", "ck_mcu", 0, G_USBO), + PCLK(SDMMC3, "sdmmc3", "ck_mcu", 0, G_SDMMC3), + PCLK(DCMI, "dcmi", "ck_mcu", 0, G_DCMI), + PCLK(CRYP2, "cryp2", "ck_mcu", 0, G_CRYP2), + PCLK(HASH2, "hash2", "ck_mcu", 0, G_HASH2), + PCLK(RNG2, "rng2", "ck_mcu", 0, G_RNG2), + PCLK(CRC2, "crc2", "ck_mcu", 0, G_CRC2), + PCLK(HSEM, "hsem", "ck_mcu", 0, G_HSEM), + PCLK(IPCC, "ipcc", "ck_mcu", 0, G_IPCC), + PCLK(GPIOA, "gpioa", "ck_mcu", 0, G_GPIOA), + PCLK(GPIOB, "gpiob", "ck_mcu", 0, G_GPIOB), + PCLK(GPIOC, "gpioc", "ck_mcu", 0, G_GPIOC), + PCLK(GPIOD, "gpiod", "ck_mcu", 0, G_GPIOD), + PCLK(GPIOE, "gpioe", "ck_mcu", 0, G_GPIOE), + PCLK(GPIOF, "gpiof", "ck_mcu", 0, G_GPIOF), + PCLK(GPIOG, "gpiog", "ck_mcu", 0, G_GPIOG), + PCLK(GPIOH, "gpioh", "ck_mcu", 0, G_GPIOH), + PCLK(GPIOI, "gpioi", "ck_mcu", 0, G_GPIOI), + PCLK(GPIOJ, "gpioj", "ck_mcu", 0, G_GPIOJ), + PCLK(GPIOK, "gpiok", "ck_mcu", 0, G_GPIOK), + PCLK(GPIOZ, "gpioz", "ck_axi", CLK_IGNORE_UNUSED, G_GPIOZ), + PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), + PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), + PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), + PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, G_BKPSRAM), + PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), + PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), + PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), + PCLK_PDATA(ETHRX, "ethrx", ethrx_src, 0, G_ETHRX), + PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC), + PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC), + PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI), + PCLK(SDMMC1, "sdmmc1", "ck_axi", 0, G_SDMMC1), + PCLK(SDMMC2, "sdmmc2", "ck_axi", 0, G_SDMMC2), + PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), + PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), + PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), + PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM), + + /* Kernel clocks */ + KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), + KCLK(SDMMC2_K, "sdmmc2_k", sdmmc12_src, 0, G_SDMMC2, M_SDMMC12), + KCLK(SDMMC3_K, "sdmmc3_k", sdmmc3_src, 0, G_SDMMC3, M_SDMMC3), + KCLK(FMC_K, "fmc_k", fmc_src, 0, G_FMC, M_FMC), + KCLK(QSPI_K, "qspi_k", qspi_src, 0, G_QSPI, M_QSPI), + KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), + KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), + KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), + KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, G_STGEN, M_STGEN), + KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), + KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), + KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), + KCLK(SPI3_K, "spi3_k", spi123_src, 0, G_SPI3, M_SPI23), + KCLK(SPI4_K, "spi4_k", spi45_src, 0, G_SPI4, M_SPI45), + KCLK(SPI5_K, "spi5_k", spi45_src, 0, G_SPI5, M_SPI45), + KCLK(SPI6_K, "spi6_k", spi6_src, 0, G_SPI6, M_SPI6), + KCLK(CEC_K, "cec_k", cec_src, 0, G_CEC, M_CEC), + KCLK(I2C1_K, "i2c1_k", i2c12_src, 0, G_I2C1, M_I2C12), + KCLK(I2C2_K, "i2c2_k", i2c12_src, 0, G_I2C2, M_I2C12), + KCLK(I2C3_K, "i2c3_k", i2c35_src, 0, G_I2C3, M_I2C35), + KCLK(I2C5_K, "i2c5_k", i2c35_src, 0, G_I2C5, M_I2C35), + KCLK(I2C4_K, "i2c4_k", i2c46_src, 0, G_I2C4, M_I2C46), + KCLK(I2C6_K, "i2c6_k", i2c46_src, 0, G_I2C6, M_I2C46), + KCLK(LPTIM1_K, "lptim1_k", lptim1_src, 0, G_LPTIM1, M_LPTIM1), + KCLK(LPTIM2_K, "lptim2_k", lptim23_src, 0, G_LPTIM2, M_LPTIM23), + KCLK(LPTIM3_K, "lptim3_k", lptim23_src, 0, G_LPTIM3, M_LPTIM23), + KCLK(LPTIM4_K, "lptim4_k", lptim45_src, 0, G_LPTIM4, M_LPTIM45), + KCLK(LPTIM5_K, "lptim5_k", lptim45_src, 0, G_LPTIM5, M_LPTIM45), + KCLK(USART1_K, "usart1_k", usart1_src, 0, G_USART1, M_USART1), + KCLK(USART2_K, "usart2_k", usart234578_src, 0, G_USART2, M_UART24), + KCLK(USART3_K, "usart3_k", usart234578_src, 0, G_USART3, M_UART35), + KCLK(UART4_K, "uart4_k", usart234578_src, 0, G_UART4, M_UART24), + KCLK(UART5_K, "uart5_k", usart234578_src, 0, G_UART5, M_UART35), + KCLK(USART6_K, "uart6_k", usart6_src, 0, G_USART6, M_USART6), + KCLK(UART7_K, "uart7_k", usart234578_src, 0, G_UART7, M_UART78), + KCLK(UART8_K, "uart8_k", usart234578_src, 0, G_UART8, M_UART78), + KCLK(FDCAN_K, "fdcan_k", fdcan_src, 0, G_FDCAN, M_FDCAN), + KCLK(SAI1_K, "sai1_k", sai_src, 0, G_SAI1, M_SAI1), + KCLK(SAI2_K, "sai2_k", sai2_src, 0, G_SAI2, M_SAI2), + KCLK(SAI3_K, "sai3_k", sai_src, 0, G_SAI3, M_SAI3), + KCLK(SAI4_K, "sai4_k", sai_src, 0, G_SAI4, M_SAI4), + KCLK(ADC12_K, "adc12_k", adc12_src, 0, G_ADC12, M_ADC12), + KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI), + KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1), + KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO), + + /* Particulary Kernel Clocks (no mux or no gate) */ + MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM), + MGATE_MP1(DSI_PX, "dsi_px", "pll4_q", CLK_SET_RATE_PARENT, G_DSI), + MGATE_MP1(LTDC_PX, "ltdc_px", "pll4_q", CLK_SET_RATE_PARENT, G_LTDC), + MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), + MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), + + COMPOSITE(NO_ID, "ck_ker_eth", eth_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _NO_GATE, + _MMUX(M_ETHCK), + _NO_DIV), + + MGATE_MP1(ETHCK_K, "ethck_k", "ck_ker_eth", 0, G_ETHCK), + + DIV(ETHPTP_K, "ethptp_k", "ck_ker_eth", CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, RCC_ETHCKSELR, 4, 4, 0), + + /* RTC clock */ + COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE, + _GATE(RCC_BDCR, 20, 0), + _MUX(RCC_BDCR, 16, 2, 0), + _DIV_RTC(RCC_RTCDIVR, 0, 6, 0, NULL)), + + /* MCO clocks */ + COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO1CFGR, 12, 0), + _MUX(RCC_MCO1CFGR, 0, 3, 0), + _DIV(RCC_MCO1CFGR, 4, 4, 0, NULL)), + + COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO2CFGR, 12, 0), + _MUX(RCC_MCO2CFGR, 0, 3, 0), + _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), + + /* Debug clocks */ + GATE(CK_DBG, "ck_sys_dbg", "ck_axi", CLK_IGNORE_UNUSED, + RCC_DBGCFGR, 8, 0), + + COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE, + _GATE(RCC_DBGCFGR, 9, 0), + _NO_MUX, + _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), +}; + +static const u32 stm32mp1_clock_secured[] = { + CK_HSE, + CK_HSI, + CK_CSI, + CK_LSI, + CK_LSE, + PLL1, + PLL2, + PLL1_P, + PLL2_P, + PLL2_Q, + PLL2_R, + CK_MPU, + CK_AXI, + SPI6, + I2C4, + I2C6, + USART1, + RTCAPB, + TZC1, + TZC2, + TZPC, + IWDG1, + BSEC, + STGEN, + GPIOZ, + CRYP1, + HASH1, + RNG1, + BKPSRAM, + RNG1_K, + STGEN_K, + SPI6_K, + I2C4_K, + I2C6_K, + USART1_K, + RTC, +}; + +static bool stm32_check_security(const struct clock_config *cfg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(stm32mp1_clock_secured); i++) + if (cfg->id == stm32mp1_clock_secured[i]) + return true; + return false; +} + +struct stm32_rcc_match_data { + const struct clock_config *cfg; + unsigned int num; + unsigned int maxbinding; + u32 clear_offset; + bool (*check_security)(const struct clock_config *cfg); +}; + +static struct stm32_rcc_match_data stm32mp1_data = { + .cfg = stm32mp1_clock_cfg, + .num = ARRAY_SIZE(stm32mp1_clock_cfg), + .maxbinding = STM32MP1_LAST_CLK, + .clear_offset = RCC_CLR, +}; + +static struct stm32_rcc_match_data stm32mp1_data_secure = { + .cfg = stm32mp1_clock_cfg, + .num = ARRAY_SIZE(stm32mp1_clock_cfg), + .maxbinding = STM32MP1_LAST_CLK, + .clear_offset = RCC_CLR, + .check_security = &stm32_check_security +}; + +static const struct of_device_id stm32mp1_match_data[] = { + { + .compatible = "st,stm32mp1-rcc", + .data = &stm32mp1_data, + }, + { + .compatible = "st,stm32mp1-rcc-secure", + .data = &stm32mp1_data_secure, + }, + { } +}; +MODULE_DEVICE_TABLE(of, stm32mp1_match_data); + +static int stm32_register_hw_clk(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct clk_hw **hws; + struct clk_hw *hw = ERR_PTR(-ENOENT); + + hws = clk_data->hws; + + if (cfg->func) + hw = (*cfg->func)(dev, clk_data, base, lock, cfg); + + if (IS_ERR(hw)) { + pr_err("Unable to register %s\n", cfg->name); + return PTR_ERR(hw); + } + + if (cfg->id != NO_ID) + hws[cfg->id] = hw; + + return 0; +} + +#define STM32_RESET_ID_MASK GENMASK(15, 0) + +struct stm32_reset_data { + /* reset lock */ + spinlock_t lock; + struct reset_controller_dev rcdev; + void __iomem *membase; + u32 clear_offset; +}; + +static inline struct stm32_reset_data * +to_stm32_reset_data(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct stm32_reset_data, rcdev); +} + +static int stm32_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct stm32_reset_data *data = to_stm32_reset_data(rcdev); + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); + + if (data->clear_offset) { + void __iomem *addr; + + addr = data->membase + (bank * reg_width); + if (!assert) + addr += data->clear_offset; + + writel(BIT(offset), addr); + + } else { + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&data->lock, flags); + + reg = readl(data->membase + (bank * reg_width)); + + if (assert) + reg |= BIT(offset); + else + reg &= ~BIT(offset); + + writel(reg, data->membase + (bank * reg_width)); + + spin_unlock_irqrestore(&data->lock, flags); + } + + return 0; +} + +static int stm32_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return stm32_reset_update(rcdev, id, true); +} + +static int stm32_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return stm32_reset_update(rcdev, id, false); +} + +static int stm32_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct stm32_reset_data *data = to_stm32_reset_data(rcdev); + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); + u32 reg; + + reg = readl(data->membase + (bank * reg_width)); + + return !!(reg & BIT(offset)); +} + +static const struct reset_control_ops stm32_reset_ops = { + .assert = stm32_reset_assert, + .deassert = stm32_reset_deassert, + .status = stm32_reset_status, +}; + +static int stm32_rcc_reset_init(struct device *dev, void __iomem *base, + const struct of_device_id *match) +{ + const struct stm32_rcc_match_data *data = match->data; + struct stm32_reset_data *reset_data = NULL; + + reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); + if (!reset_data) + return -ENOMEM; + + spin_lock_init(&reset_data->lock); + reset_data->membase = base; + reset_data->rcdev.owner = THIS_MODULE; + reset_data->rcdev.ops = &stm32_reset_ops; + reset_data->rcdev.of_node = dev_of_node(dev); + reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK; + reset_data->clear_offset = data->clear_offset; + + return reset_controller_register(&reset_data->rcdev); +} + +static int stm32_rcc_clock_init(struct device *dev, void __iomem *base, + const struct of_device_id *match) +{ + const struct stm32_rcc_match_data *data = match->data; + struct clk_hw_onecell_data *clk_data; + struct clk_hw **hws; + int err, n, max_binding; + + max_binding = data->maxbinding; + + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = max_binding; + + hws = clk_data->hws; + + for (n = 0; n < max_binding; n++) + hws[n] = ERR_PTR(-ENOENT); + + for (n = 0; n < data->num; n++) { + if (data->check_security && data->check_security(&data->cfg[n])) + continue; + + err = stm32_register_hw_clk(dev, clk_data, base, &rlock, + &data->cfg[n]); + if (err) { + dev_err(dev, "Can't register clk %s: %d\n", + data->cfg[n].name, err); + + return err; + } + } + + return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, clk_data); +} + +static int stm32_rcc_init(struct device *dev, void __iomem *base, + const struct of_device_id *match_data) +{ + const struct of_device_id *match; + int err; + + match = of_match_node(match_data, dev_of_node(dev)); + if (!match) { + dev_err(dev, "match data not found\n"); + return -ENODEV; + } + + /* RCC Reset Configuration */ + err = stm32_rcc_reset_init(dev, base, match); + if (err) { + pr_err("stm32mp1 reset failed to initialize\n"); + return err; + } + + /* RCC Clock Configuration */ + err = stm32_rcc_clock_init(dev, base, match); + if (err) { + pr_err("stm32mp1 clock failed to initialize\n"); + return err; + } + + return 0; +} + +static int stm32mp1_rcc_init(struct device *dev) +{ + void __iomem *base; + int ret; + + base = of_iomap(dev_of_node(dev), 0); + if (!base) { + pr_err("%pOFn: unable to map resource", dev_of_node(dev)); + ret = -ENOMEM; + goto out; + } + + ret = stm32_rcc_init(dev, base, stm32mp1_match_data); + +out: + if (ret) { + if (base) + iounmap(base); + + of_node_put(dev_of_node(dev)); + } + + return ret; +} + +static int get_clock_deps(struct device *dev) +{ + static const char * const clock_deps_name[] = { + "hsi", "hse", "csi", "lsi", "lse", + }; + size_t deps_size = sizeof(struct clk *) * ARRAY_SIZE(clock_deps_name); + struct clk **clk_deps; + int i; + + clk_deps = devm_kzalloc(dev, deps_size, GFP_KERNEL); + if (!clk_deps) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(clock_deps_name); i++) { + struct clk *clk = of_clk_get_by_name(dev_of_node(dev), + clock_deps_name[i]); + + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EINVAL && PTR_ERR(clk) != -ENOENT) + return PTR_ERR(clk); + } else { + /* Device gets a reference count on the clock */ + clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk)); + clk_put(clk); + } + } + + return 0; +} + +static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int ret = get_clock_deps(dev); + + if (!ret) + ret = stm32mp1_rcc_init(dev); + + return ret; +} + +static void stm32mp1_rcc_clocks_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *child, *np = dev_of_node(dev); + + for_each_available_child_of_node(np, child) + of_clk_del_provider(child); +} + +static struct platform_driver stm32mp1_rcc_clocks_driver = { + .driver = { + .name = "stm32mp1_rcc", + .of_match_table = stm32mp1_match_data, + }, + .probe = stm32mp1_rcc_clocks_probe, + .remove_new = stm32mp1_rcc_clocks_remove, +}; + +static int __init stm32mp1_clocks_init(void) +{ + return platform_driver_register(&stm32mp1_rcc_clocks_driver); +} +core_initcall(stm32mp1_clocks_init); -- cgit v1.2.3 From 30500c2ad9c440d1a81e7a5dac3bcef62e21d910 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Fri, 8 Dec 2023 15:36:57 +0100 Subject: clk: stm32mp1: use stm32mp13 reset driver STM32MP15 is now using the same reset driver as STM32MP13 as they have the same binding requirement. Signed-off-by: Gabriel Fernandez Link: https://lore.kernel.org/r/20231208143700.354785-3-gabriel.fernandez@foss.st.com Signed-off-by: Stephen Boyd --- drivers/clk/stm32/Makefile | 2 +- drivers/clk/stm32/clk-stm32-core.c | 5 +- drivers/clk/stm32/clk-stm32-core.h | 5 +- drivers/clk/stm32/clk-stm32mp1.c | 127 +++++-------------------------------- drivers/clk/stm32/clk-stm32mp13.c | 9 ++- drivers/clk/stm32/reset-stm32.c | 14 ++-- drivers/clk/stm32/reset-stm32.h | 8 ++- 7 files changed, 42 insertions(+), 128 deletions(-) diff --git a/drivers/clk/stm32/Makefile b/drivers/clk/stm32/Makefile index c154ef3e88f9..5ced7fe3ddec 100644 --- a/drivers/clk/stm32/Makefile +++ b/drivers/clk/stm32/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_COMMON_CLK_STM32MP135) += clk-stm32mp13.o clk-stm32-core.o reset-stm32.o -obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o +obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o reset-stm32.o diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c index 067b918a8894..58705fcad334 100644 --- a/drivers/clk/stm32/clk-stm32-core.c +++ b/drivers/clk/stm32/clk-stm32-core.c @@ -70,6 +70,7 @@ static int stm32_rcc_clock_init(struct device *dev, int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data, void __iomem *base) { + const struct stm32_rcc_match_data *rcc_match_data; const struct of_device_id *match; int err; @@ -79,8 +80,10 @@ int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data, return -ENODEV; } + rcc_match_data = match->data; + /* RCC Reset Configuration */ - err = stm32_rcc_reset_init(dev, match, base); + err = stm32_rcc_reset_init(dev, rcc_match_data->reset_data, base); if (err) { pr_err("stm32 reset failed to initialize\n"); return err; diff --git a/drivers/clk/stm32/clk-stm32-core.h b/drivers/clk/stm32/clk-stm32-core.h index 76cffda02308..bb5aa19a792d 100644 --- a/drivers/clk/stm32/clk-stm32-core.h +++ b/drivers/clk/stm32/clk-stm32-core.h @@ -70,15 +70,12 @@ struct stm32_rcc_match_data { const struct clock_config *tab_clocks; unsigned int maxbinding; struct clk_stm32_clock_data *clock_data; - u32 clear_offset; + struct clk_stm32_reset_data *reset_data; int (*check_security)(void __iomem *base, const struct clock_config *cfg); int (*multi_mux)(void __iomem *base, const struct clock_config *cfg); }; -int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, - void __iomem *base); - int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data, void __iomem *base); diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c index 939779f66867..7e2337297402 100644 --- a/drivers/clk/stm32/clk-stm32mp1.c +++ b/drivers/clk/stm32/clk-stm32mp1.c @@ -20,6 +20,10 @@ #include +#include "reset-stm32.h" + +#define STM32MP1_RESET_ID_MASK GENMASK(15, 0) + static DEFINE_SPINLOCK(rlock); #define RCC_OCENSETR 0x0C @@ -2137,22 +2141,27 @@ struct stm32_rcc_match_data { const struct clock_config *cfg; unsigned int num; unsigned int maxbinding; - u32 clear_offset; + struct clk_stm32_reset_data *reset_data; bool (*check_security)(const struct clock_config *cfg); }; +static struct clk_stm32_reset_data stm32mp1_reset_data = { + .nr_lines = STM32MP1_RESET_ID_MASK, + .clear_offset = RCC_CLR, +}; + static struct stm32_rcc_match_data stm32mp1_data = { .cfg = stm32mp1_clock_cfg, .num = ARRAY_SIZE(stm32mp1_clock_cfg), .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR, + .reset_data = &stm32mp1_reset_data, }; static struct stm32_rcc_match_data stm32mp1_data_secure = { .cfg = stm32mp1_clock_cfg, .num = ARRAY_SIZE(stm32mp1_clock_cfg), .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR, + .reset_data = &stm32mp1_reset_data, .check_security = &stm32_check_security }; @@ -2193,113 +2202,6 @@ static int stm32_register_hw_clk(struct device *dev, return 0; } -#define STM32_RESET_ID_MASK GENMASK(15, 0) - -struct stm32_reset_data { - /* reset lock */ - spinlock_t lock; - struct reset_controller_dev rcdev; - void __iomem *membase; - u32 clear_offset; -}; - -static inline struct stm32_reset_data * -to_stm32_reset_data(struct reset_controller_dev *rcdev) -{ - return container_of(rcdev, struct stm32_reset_data, rcdev); -} - -static int stm32_reset_update(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - struct stm32_reset_data *data = to_stm32_reset_data(rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - - if (data->clear_offset) { - void __iomem *addr; - - addr = data->membase + (bank * reg_width); - if (!assert) - addr += data->clear_offset; - - writel(BIT(offset), addr); - - } else { - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * reg_width)); - - if (assert) - reg |= BIT(offset); - else - reg &= ~BIT(offset); - - writel(reg, data->membase + (bank * reg_width)); - - spin_unlock_irqrestore(&data->lock, flags); - } - - return 0; -} - -static int stm32_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return stm32_reset_update(rcdev, id, true); -} - -static int stm32_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return stm32_reset_update(rcdev, id, false); -} - -static int stm32_reset_status(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct stm32_reset_data *data = to_stm32_reset_data(rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - u32 reg; - - reg = readl(data->membase + (bank * reg_width)); - - return !!(reg & BIT(offset)); -} - -static const struct reset_control_ops stm32_reset_ops = { - .assert = stm32_reset_assert, - .deassert = stm32_reset_deassert, - .status = stm32_reset_status, -}; - -static int stm32_rcc_reset_init(struct device *dev, void __iomem *base, - const struct of_device_id *match) -{ - const struct stm32_rcc_match_data *data = match->data; - struct stm32_reset_data *reset_data = NULL; - - reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); - if (!reset_data) - return -ENOMEM; - - spin_lock_init(&reset_data->lock); - reset_data->membase = base; - reset_data->rcdev.owner = THIS_MODULE; - reset_data->rcdev.ops = &stm32_reset_ops; - reset_data->rcdev.of_node = dev_of_node(dev); - reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK; - reset_data->clear_offset = data->clear_offset; - - return reset_controller_register(&reset_data->rcdev); -} - static int stm32_rcc_clock_init(struct device *dev, void __iomem *base, const struct of_device_id *match) { @@ -2342,6 +2244,7 @@ static int stm32_rcc_clock_init(struct device *dev, void __iomem *base, static int stm32_rcc_init(struct device *dev, void __iomem *base, const struct of_device_id *match_data) { + const struct stm32_rcc_match_data *rcc_match_data; const struct of_device_id *match; int err; @@ -2351,8 +2254,10 @@ static int stm32_rcc_init(struct device *dev, void __iomem *base, return -ENODEV; } + rcc_match_data = match->data; + /* RCC Reset Configuration */ - err = stm32_rcc_reset_init(dev, base, match); + err = stm32_rcc_reset_init(dev, rcc_match_data->reset_data, base); if (err) { pr_err("stm32mp1 reset failed to initialize\n"); return err; diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c index c4a737482fe5..d4ecb3c34a1b 100644 --- a/drivers/clk/stm32/clk-stm32mp13.c +++ b/drivers/clk/stm32/clk-stm32mp13.c @@ -10,8 +10,10 @@ #include #include #include "clk-stm32-core.h" +#include "reset-stm32.h" #include "stm32mp13_rcc.h" +#define STM32MP1_RESET_ID_MASK GENMASK(15, 0) #define RCC_CLR_OFFSET 0x4 /* STM32 Gates definition */ @@ -1511,13 +1513,18 @@ static struct clk_stm32_clock_data stm32mp13_clock_data = { .is_multi_mux = stm32mp13_is_multi_mux, }; +static struct clk_stm32_reset_data stm32mp13_reset_data = { + .nr_lines = STM32MP1_RESET_ID_MASK, + .clear_offset = RCC_CLR_OFFSET, +}; + static const struct stm32_rcc_match_data stm32mp13_data = { .tab_clocks = stm32mp13_clock_cfg, .num_clocks = ARRAY_SIZE(stm32mp13_clock_cfg), .clock_data = &stm32mp13_clock_data, .check_security = &stm32mp13_clock_is_provided_by_secure, .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR_OFFSET, + .reset_data = &stm32mp13_reset_data, }; static const struct of_device_id stm32mp13_match_data[] = { diff --git a/drivers/clk/stm32/reset-stm32.c b/drivers/clk/stm32/reset-stm32.c index e89381528af9..14c2ee1eebee 100644 --- a/drivers/clk/stm32/reset-stm32.c +++ b/drivers/clk/stm32/reset-stm32.c @@ -11,9 +11,7 @@ #include #include -#include "clk-stm32-core.h" - -#define STM32_RESET_ID_MASK GENMASK(15, 0) +#include "reset-stm32.h" struct stm32_reset_data { /* reset lock */ @@ -99,24 +97,22 @@ static const struct reset_control_ops stm32_reset_ops = { .status = stm32_reset_status, }; -int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, +int stm32_rcc_reset_init(struct device *dev, struct clk_stm32_reset_data *data, void __iomem *base) { - const struct stm32_rcc_match_data *data = match->data; - struct stm32_reset_data *reset_data = NULL; - - data = match->data; + struct stm32_reset_data *reset_data; reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); if (!reset_data) return -ENOMEM; spin_lock_init(&reset_data->lock); + reset_data->membase = base; reset_data->rcdev.owner = THIS_MODULE; reset_data->rcdev.ops = &stm32_reset_ops; reset_data->rcdev.of_node = dev_of_node(dev); - reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK; + reset_data->rcdev.nr_resets = data->nr_lines; reset_data->clear_offset = data->clear_offset; return reset_controller_register(&reset_data->rcdev); diff --git a/drivers/clk/stm32/reset-stm32.h b/drivers/clk/stm32/reset-stm32.h index 6eb6ea4b55ab..8cf1cc9be480 100644 --- a/drivers/clk/stm32/reset-stm32.h +++ b/drivers/clk/stm32/reset-stm32.h @@ -4,5 +4,11 @@ * Author: Gabriel Fernandez for STMicroelectronics. */ -int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, +struct clk_stm32_reset_data { + const struct reset_control_ops *ops; + unsigned int nr_lines; + u32 clear_offset; +}; + +int stm32_rcc_reset_init(struct device *dev, struct clk_stm32_reset_data *data, void __iomem *base); -- cgit v1.2.3 From b5be49db3d47eae30998174410a0eaac9816c0cf Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Fri, 8 Dec 2023 15:36:58 +0100 Subject: dt-bindings: stm32: add clocks and reset binding for stm32mp25 platform Adds clock and reset binding entries for STM32MP25 SoC family Signed-off-by: Gabriel Fernandez Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231208143700.354785-4-gabriel.fernandez@foss.st.com Signed-off-by: Stephen Boyd --- .../bindings/clock/st,stm32mp25-rcc.yaml | 76 ++++ include/dt-bindings/clock/st,stm32mp25-rcc.h | 492 +++++++++++++++++++++ include/dt-bindings/reset/st,stm32mp25-rcc.h | 167 +++++++ 3 files changed, 735 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml create mode 100644 include/dt-bindings/clock/st,stm32mp25-rcc.h create mode 100644 include/dt-bindings/reset/st,stm32mp25-rcc.h diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml new file mode 100644 index 000000000000..7732e79a42b9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/st,stm32mp25-rcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STM32MP25 Reset Clock Controller + +maintainers: + - Gabriel Fernandez + +description: | + The RCC hardware block is both a reset and a clock controller. + RCC makes also power management (resume/supend). + + See also:: + include/dt-bindings/clock/st,stm32mp25-rcc.h + include/dt-bindings/reset/st,stm32mp25-rcc.h + +properties: + compatible: + enum: + - st,stm32mp25-rcc + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + clocks: + items: + - description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz) + - description: CK_SCMI_HSI High Speed Internal oscillator (~ 64 MHz) + - description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz) + - description: CK_SCMI_LSE Low Speed External oscillator (32 KHz) + - description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz) + + clock-names: + items: + - const: hse + - const: hsi + - const: msi + - const: lse + - const: lsi + +required: + - compatible + - reg + - '#clock-cells' + - '#reset-cells' + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + + rcc: clock-controller@44200000 { + compatible = "st,stm32mp25-rcc"; + reg = <0x44200000 0x10000>; + #clock-cells = <1>; + #reset-cells = <1>; + clock-names = "hse", "hsi", "msi", "lse", "lsi"; + clocks = <&scmi_clk CK_SCMI_HSE>, + <&scmi_clk CK_SCMI_HSI>, + <&scmi_clk CK_SCMI_MSI>, + <&scmi_clk CK_SCMI_LSE>, + <&scmi_clk CK_SCMI_LSI>; + }; +... diff --git a/include/dt-bindings/clock/st,stm32mp25-rcc.h b/include/dt-bindings/clock/st,stm32mp25-rcc.h new file mode 100644 index 000000000000..b6cf05ad4be6 --- /dev/null +++ b/include/dt-bindings/clock/st,stm32mp25-rcc.h @@ -0,0 +1,492 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (C) STMicroelectronics 2023 - All Rights Reserved + * Author: Gabriel Fernandez + */ + +#ifndef _DT_BINDINGS_STM32MP25_CLKS_H_ +#define _DT_BINDINGS_STM32MP25_CLKS_H_ + +/* INTERNAL/EXTERNAL OSCILLATORS */ +#define HSI_CK 0 +#define HSE_CK 1 +#define MSI_CK 2 +#define LSI_CK 3 +#define LSE_CK 4 +#define I2S_CK 5 +#define RTC_CK 6 +#define SPDIF_CK_SYMB 7 + +/* PLL CLOCKS */ +#define PLL1_CK 8 +#define PLL2_CK 9 +#define PLL3_CK 10 +#define PLL4_CK 11 +#define PLL5_CK 12 +#define PLL6_CK 13 +#define PLL7_CK 14 +#define PLL8_CK 15 + +#define CK_CPU1 16 + +/* APB DIV CLOCKS */ +#define CK_ICN_APB1 17 +#define CK_ICN_APB2 18 +#define CK_ICN_APB3 19 +#define CK_ICN_APB4 20 +#define CK_ICN_APBDBG 21 + +/* GLOBAL TIMER */ +#define TIMG1_CK 22 +#define TIMG2_CK 23 + +/* FLEXGEN CLOCKS */ +#define CK_ICN_HS_MCU 24 +#define CK_ICN_SDMMC 25 +#define CK_ICN_DDR 26 +#define CK_ICN_DISPLAY 27 +#define CK_ICN_HSL 28 +#define CK_ICN_NIC 29 +#define CK_ICN_VID 30 +#define CK_FLEXGEN_07 31 +#define CK_FLEXGEN_08 32 +#define CK_FLEXGEN_09 33 +#define CK_FLEXGEN_10 34 +#define CK_FLEXGEN_11 35 +#define CK_FLEXGEN_12 36 +#define CK_FLEXGEN_13 37 +#define CK_FLEXGEN_14 38 +#define CK_FLEXGEN_15 39 +#define CK_FLEXGEN_16 40 +#define CK_FLEXGEN_17 41 +#define CK_FLEXGEN_18 42 +#define CK_FLEXGEN_19 43 +#define CK_FLEXGEN_20 44 +#define CK_FLEXGEN_21 45 +#define CK_FLEXGEN_22 46 +#define CK_FLEXGEN_23 47 +#define CK_FLEXGEN_24 48 +#define CK_FLEXGEN_25 49 +#define CK_FLEXGEN_26 50 +#define CK_FLEXGEN_27 51 +#define CK_FLEXGEN_28 52 +#define CK_FLEXGEN_29 53 +#define CK_FLEXGEN_30 54 +#define CK_FLEXGEN_31 55 +#define CK_FLEXGEN_32 56 +#define CK_FLEXGEN_33 57 +#define CK_FLEXGEN_34 58 +#define CK_FLEXGEN_35 59 +#define CK_FLEXGEN_36 60 +#define CK_FLEXGEN_37 61 +#define CK_FLEXGEN_38 62 +#define CK_FLEXGEN_39 63 +#define CK_FLEXGEN_40 64 +#define CK_FLEXGEN_41 65 +#define CK_FLEXGEN_42 66 +#define CK_FLEXGEN_43 67 +#define CK_FLEXGEN_44 68 +#define CK_FLEXGEN_45 69 +#define CK_FLEXGEN_46 70 +#define CK_FLEXGEN_47 71 +#define CK_FLEXGEN_48 72 +#define CK_FLEXGEN_49 73 +#define CK_FLEXGEN_50 74 +#define CK_FLEXGEN_51 75 +#define CK_FLEXGEN_52 76 +#define CK_FLEXGEN_53 77 +#define CK_FLEXGEN_54 78 +#define CK_FLEXGEN_55 79 +#define CK_FLEXGEN_56 80 +#define CK_FLEXGEN_57 81 +#define CK_FLEXGEN_58 82 +#define CK_FLEXGEN_59 83 +#define CK_FLEXGEN_60 84 +#define CK_FLEXGEN_61 85 +#define CK_FLEXGEN_62 86 +#define CK_FLEXGEN_63 87 + +/* LOW SPEED MCU CLOCK */ +#define CK_ICN_LS_MCU 88 + +#define CK_BUS_STM500 89 +#define CK_BUS_FMC 90 +#define CK_BUS_GPU 91 +#define CK_BUS_ETH1 92 +#define CK_BUS_ETH2 93 +#define CK_BUS_PCIE 94 +#define CK_BUS_DDRPHYC 95 +#define CK_BUS_SYSCPU1 96 +#define CK_BUS_ETHSW 97 +#define CK_BUS_HPDMA1 98 +#define CK_BUS_HPDMA2 99 +#define CK_BUS_HPDMA3 100 +#define CK_BUS_ADC12 101 +#define CK_BUS_ADC3 102 +#define CK_BUS_IPCC1 103 +#define CK_BUS_CCI 104 +#define CK_BUS_CRC 105 +#define CK_BUS_MDF1 106 +#define CK_BUS_OSPIIOM 107 +#define CK_BUS_BKPSRAM 108 +#define CK_BUS_HASH 109 +#define CK_BUS_RNG 110 +#define CK_BUS_CRYP1 111 +#define CK_BUS_CRYP2 112 +#define CK_BUS_SAES 113 +#define CK_BUS_PKA 114 +#define CK_BUS_GPIOA 115 +#define CK_BUS_GPIOB 116 +#define CK_BUS_GPIOC 117 +#define CK_BUS_GPIOD 118 +#define CK_BUS_GPIOE 119 +#define CK_BUS_GPIOF 120 +#define CK_BUS_GPIOG 121 +#define CK_BUS_GPIOH 122 +#define CK_BUS_GPIOI 123 +#define CK_BUS_GPIOJ 124 +#define CK_BUS_GPIOK 125 +#define CK_BUS_LPSRAM1 126 +#define CK_BUS_LPSRAM2 127 +#define CK_BUS_LPSRAM3 128 +#define CK_BUS_GPIOZ 129 +#define CK_BUS_LPDMA 130 +#define CK_BUS_HSEM 131 +#define CK_BUS_IPCC2 132 +#define CK_BUS_RTC 133 +#define CK_BUS_SPI8 134 +#define CK_BUS_LPUART1 135 +#define CK_BUS_I2C8 136 +#define CK_BUS_LPTIM3 137 +#define CK_BUS_LPTIM4 138 +#define CK_BUS_LPTIM5 139 +#define CK_BUS_IWDG5 140 +#define CK_BUS_WWDG2 141 +#define CK_BUS_I3C4 142 +#define CK_BUS_TIM2 143 +#define CK_BUS_TIM3 144 +#define CK_BUS_TIM4 145 +#define CK_BUS_TIM5 146 +#define CK_BUS_TIM6 147 +#define CK_BUS_TIM7 148 +#define CK_BUS_TIM10 149 +#define CK_BUS_TIM11 150 +#define CK_BUS_TIM12 151 +#define CK_BUS_TIM13 152 +#define CK_BUS_TIM14 153 +#define CK_BUS_LPTIM1 154 +#define CK_BUS_LPTIM2 155 +#define CK_BUS_SPI2 156 +#define CK_BUS_SPI3 157 +#define CK_BUS_SPDIFRX 158 +#define CK_BUS_USART2 159 +#define CK_BUS_USART3 160 +#define CK_BUS_UART4 161 +#define CK_BUS_UART5 162 +#define CK_BUS_I2C1 163 +#define CK_BUS_I2C2 164 +#define CK_BUS_I2C3 165 +#define CK_BUS_I2C4 166 +#define CK_BUS_I2C5 167 +#define CK_BUS_I2C6 168 +#define CK_BUS_I2C7 169 +#define CK_BUS_I3C1 170 +#define CK_BUS_I3C2 171 +#define CK_BUS_I3C3 172 +#define CK_BUS_TIM1 173 +#define CK_BUS_TIM8 174 +#define CK_BUS_TIM15 175 +#define CK_BUS_TIM16 176 +#define CK_BUS_TIM17 177 +#define CK_BUS_TIM20 178 +#define CK_BUS_SAI1 179 +#define CK_BUS_SAI2 180 +#define CK_BUS_SAI3 181 +#define CK_BUS_SAI4 182 +#define CK_BUS_USART1 183 +#define CK_BUS_USART6 184 +#define CK_BUS_UART7 185 +#define CK_BUS_UART8 186 +#define CK_BUS_UART9 187 +#define CK_BUS_FDCAN 188 +#define CK_BUS_SPI1 189 +#define CK_BUS_SPI4 190 +#define CK_BUS_SPI5 191 +#define CK_BUS_SPI6 192 +#define CK_BUS_SPI7 193 +#define CK_BUS_BSEC 194 +#define CK_BUS_IWDG1 195 +#define CK_BUS_IWDG2 196 +#define CK_BUS_IWDG3 197 +#define CK_BUS_IWDG4 198 +#define CK_BUS_WWDG1 199 +#define CK_BUS_VREF 200 +#define CK_BUS_DTS 201 +#define CK_BUS_SERC 202 +#define CK_BUS_HDP 203 +#define CK_BUS_IS2M 204 +#define CK_BUS_DSI 205 +#define CK_BUS_LTDC 206 +#define CK_BUS_CSI 207 +#define CK_BUS_DCMIPP 208 +#define CK_BUS_DDRC 209 +#define CK_BUS_DDRCFG 210 +#define CK_BUS_GICV2M 211 +#define CK_BUS_USBTC 212 +#define CK_BUS_USB3PCIEPHY 214 +#define CK_BUS_STGEN 215 +#define CK_BUS_VDEC 216 +#define CK_BUS_VENC 217 +#define CK_SYSDBG 218 +#define CK_KER_TIM2 219 +#define CK_KER_TIM3 220 +#define CK_KER_TIM4 221 +#define CK_KER_TIM5 222 +#define CK_KER_TIM6 223 +#define CK_KER_TIM7 224 +#define CK_KER_TIM10 225 +#define CK_KER_TIM11 226 +#define CK_KER_TIM12 227 +#define CK_KER_TIM13 228 +#define CK_KER_TIM14 229 +#define CK_KER_TIM1 230 +#define CK_KER_TIM8 231 +#define CK_KER_TIM15 232 +#define CK_KER_TIM16 233 +#define CK_KER_TIM17 234 +#define CK_KER_TIM20 235 +#define CK_BUS_SYSRAM 236 +#define CK_BUS_VDERAM 237 +#define CK_BUS_RETRAM 238 +#define CK_BUS_OSPI1 239 +#define CK_BUS_OSPI2 240 +#define CK_BUS_OTFD1 241 +#define CK_BUS_OTFD2 242 +#define CK_BUS_SRAM1 243 +#define CK_BUS_SRAM2 244 +#define CK_BUS_SDMMC1 245 +#define CK_BUS_SDMMC2 246 +#define CK_BUS_SDMMC3 247 +#define CK_BUS_DDR 248 +#define CK_BUS_RISAF4 249 +#define CK_BUS_USB2OHCI 250 +#define CK_BUS_USB2EHCI 251 +#define CK_BUS_USB3DR 252 +#define CK_KER_LPTIM1 253 +#define CK_KER_LPTIM2 254 +#define CK_KER_USART2 255 +#define CK_KER_UART4 256 +#define CK_KER_USART3 257 +#define CK_KER_UART5 258 +#define CK_KER_SPI2 259 +#define CK_KER_SPI3 260 +#define CK_KER_SPDIFRX 261 +#define CK_KER_I2C1 262 +#define CK_KER_I2C2 263 +#define CK_KER_I3C1 264 +#define CK_KER_I3C2 265 +#define CK_KER_I2C3 266 +#define CK_KER_I2C5 267 +#define CK_KER_I3C3 268 +#define CK_KER_I2C4 269 +#define CK_KER_I2C6 270 +#define CK_KER_I2C7 271 +#define CK_KER_SPI1 272 +#define CK_KER_SPI4 273 +#define CK_KER_SPI5 274 +#define CK_KER_SPI6 275 +#define CK_KER_SPI7 276 +#define CK_KER_USART1 277 +#define CK_KER_USART6 278 +#define CK_KER_UART7 279 +#define CK_KER_UART8 280 +#define CK_KER_UART9 281 +#define CK_KER_MDF1 282 +#define CK_KER_SAI1 283 +#define CK_KER_SAI2 284 +#define CK_KER_SAI3 285 +#define CK_KER_SAI4 286 +#define CK_KER_FDCAN 287 +#define CK_KER_DSIBLANE 288 +#define CK_KER_DSIPHY 289 +#define CK_KER_CSI 290 +#define CK_KER_CSITXESC 291 +#define CK_KER_CSIPHY 292 +#define CK_KER_LVDSPHY 293 +#define CK_KER_STGEN 294 +#define CK_KER_USB3PCIEPHY 295 +#define CK_KER_USB2PHY2EN 296 +#define CK_KER_I3C4 297 +#define CK_KER_SPI8 298 +#define CK_KER_I2C8 299 +#define CK_KER_LPUART1 300 +#define CK_KER_LPTIM3 301 +#define CK_KER_LPTIM4 302 +#define CK_KER_LPTIM5 303 +#define CK_KER_TSDBG 304 +#define CK_KER_TPIU 305 +#define CK_BUS_ETR 306 +#define CK_BUS_SYSATB 307 +#define CK_KER_ADC12 308 +#define CK_KER_ADC3 309 +#define CK_KER_OSPI1 310 +#define CK_KER_OSPI2 311 +#define CK_KER_FMC 312 +#define CK_KER_SDMMC1 313 +#define CK_KER_SDMMC2 314 +#define CK_KER_SDMMC3 315 +#define CK_KER_ETH1 316 +#define CK_KER_ETH2 317 +#define CK_KER_ETH1PTP 318 +#define CK_KER_ETH2PTP 319 +#define CK_KER_USB2PHY1 320 +#define CK_KER_USB2PHY2 321 +#define CK_KER_ETHSW 322 +#define CK_KER_ETHSWREF 323 +#define CK_MCO1 324 +#define CK_MCO2 325 +#define CK_KER_DTS 326 +#define CK_ETH1_RX 327 +#define CK_ETH1_TX 328 +#define CK_ETH1_MAC 329 +#define CK_ETH2_RX 330 +#define CK_ETH2_TX 331 +#define CK_ETH2_MAC 332 +#define CK_ETH1_STP 333 +#define CK_ETH2_STP 334 +#define CK_KER_USBTC 335 +#define CK_BUS_ADF1 336 +#define CK_KER_ADF1 337 +#define CK_BUS_LVDS 338 +#define CK_KER_LTDC 339 +#define CK_KER_GPU 340 +#define CK_BUS_ETHSWACMCFG 341 +#define CK_BUS_ETHSWACMMSG 342 +#define HSE_DIV2_CK 343 + +#define STM32MP25_LAST_CLK 344 + +#define CK_SCMI_ICN_HS_MCU 0 +#define CK_SCMI_ICN_SDMMC 1 +#define CK_SCMI_ICN_DDR 2 +#define CK_SCMI_ICN_DISPLAY 3 +#define CK_SCMI_ICN_HSL 4 +#define CK_SCMI_ICN_NIC 5 +#define CK_SCMI_ICN_VID 6 +#define CK_SCMI_FLEXGEN_07 7 +#define CK_SCMI_FLEXGEN_08 8 +#define CK_SCMI_FLEXGEN_09 9 +#define CK_SCMI_FLEXGEN_10 10 +#define CK_SCMI_FLEXGEN_11 11 +#define CK_SCMI_FLEXGEN_12 12 +#define CK_SCMI_FLEXGEN_13 13 +#define CK_SCMI_FLEXGEN_14 14 +#define CK_SCMI_FLEXGEN_15 15 +#define CK_SCMI_FLEXGEN_16 16 +#define CK_SCMI_FLEXGEN_17 17 +#define CK_SCMI_FLEXGEN_18 18 +#define CK_SCMI_FLEXGEN_19 19 +#define CK_SCMI_FLEXGEN_20 20 +#define CK_SCMI_FLEXGEN_21 21 +#define CK_SCMI_FLEXGEN_22 22 +#define CK_SCMI_FLEXGEN_23 23 +#define CK_SCMI_FLEXGEN_24 24 +#define CK_SCMI_FLEXGEN_25 25 +#define CK_SCMI_FLEXGEN_26 26 +#define CK_SCMI_FLEXGEN_27 27 +#define CK_SCMI_FLEXGEN_28 28 +#define CK_SCMI_FLEXGEN_29 29 +#define CK_SCMI_FLEXGEN_30 30 +#define CK_SCMI_FLEXGEN_31 31 +#define CK_SCMI_FLEXGEN_32 32 +#define CK_SCMI_FLEXGEN_33 33 +#define CK_SCMI_FLEXGEN_34 34 +#define CK_SCMI_FLEXGEN_35 35 +#define CK_SCMI_FLEXGEN_36 36 +#define CK_SCMI_FLEXGEN_37 37 +#define CK_SCMI_FLEXGEN_38 38 +#define CK_SCMI_FLEXGEN_39 39 +#define CK_SCMI_FLEXGEN_40 40 +#define CK_SCMI_FLEXGEN_41 41 +#define CK_SCMI_FLEXGEN_42 42 +#define CK_SCMI_FLEXGEN_43 43 +#define CK_SCMI_FLEXGEN_44 44 +#define CK_SCMI_FLEXGEN_45 45 +#define CK_SCMI_FLEXGEN_46 46 +#define CK_SCMI_FLEXGEN_47 47 +#define CK_SCMI_FLEXGEN_48 48 +#define CK_SCMI_FLEXGEN_49 49 +#define CK_SCMI_FLEXGEN_50 50 +#define CK_SCMI_FLEXGEN_51 51 +#define CK_SCMI_FLEXGEN_52 52 +#define CK_SCMI_FLEXGEN_53 53 +#define CK_SCMI_FLEXGEN_54 54 +#define CK_SCMI_FLEXGEN_55 55 +#define CK_SCMI_FLEXGEN_56 56 +#define CK_SCMI_FLEXGEN_57 57 +#define CK_SCMI_FLEXGEN_58 58 +#define CK_SCMI_FLEXGEN_59 59 +#define CK_SCMI_FLEXGEN_60 60 +#define CK_SCMI_FLEXGEN_61 61 +#define CK_SCMI_FLEXGEN_62 62 +#define CK_SCMI_FLEXGEN_63 63 +#define CK_SCMI_ICN_LS_MCU 64 +#define CK_SCMI_HSE 65 +#define CK_SCMI_LSE 66 +#define CK_SCMI_HSI 67 +#define CK_SCMI_LSI 68 +#define CK_SCMI_MSI 69 +#define CK_SCMI_HSE_DIV2 70 +#define CK_SCMI_CPU1 71 +#define CK_SCMI_SYSCPU1 72 +#define CK_SCMI_PLL2 73 +#define CK_SCMI_PLL3 74 +#define CK_SCMI_RTC 75 +#define CK_SCMI_RTCCK 76 +#define CK_SCMI_ICN_APB1 77 +#define CK_SCMI_ICN_APB2 78 +#define CK_SCMI_ICN_APB3 79 +#define CK_SCMI_ICN_APB4 80 +#define CK_SCMI_ICN_APBDBG 81 +#define CK_SCMI_TIMG1 82 +#define CK_SCMI_TIMG2 83 +#define CK_SCMI_BKPSRAM 84 +#define CK_SCMI_BSEC 85 +#define CK_SCMI_ETR 87 +#define CK_SCMI_FMC 88 +#define CK_SCMI_GPIOA 89 +#define CK_SCMI_GPIOB 90 +#define CK_SCMI_GPIOC 91 +#define CK_SCMI_GPIOD 92 +#define CK_SCMI_GPIOE 93 +#define CK_SCMI_GPIOF 94 +#define CK_SCMI_GPIOG 95 +#define CK_SCMI_GPIOH 96 +#define CK_SCMI_GPIOI 97 +#define CK_SCMI_GPIOJ 98 +#define CK_SCMI_GPIOK 99 +#define CK_SCMI_GPIOZ 100 +#define CK_SCMI_HPDMA1 101 +#define CK_SCMI_HPDMA2 102 +#define CK_SCMI_HPDMA3 103 +#define CK_SCMI_HSEM 104 +#define CK_SCMI_IPCC1 105 +#define CK_SCMI_IPCC2 106 +#define CK_SCMI_LPDMA 107 +#define CK_SCMI_RETRAM 108 +#define CK_SCMI_SRAM1 109 +#define CK_SCMI_SRAM2 110 +#define CK_SCMI_LPSRAM1 111 +#define CK_SCMI_LPSRAM2 112 +#define CK_SCMI_LPSRAM3 113 +#define CK_SCMI_VDERAM 114 +#define CK_SCMI_SYSRAM 115 +#define CK_SCMI_OSPI1 116 +#define CK_SCMI_OSPI2 117 +#define CK_SCMI_TPIU 118 +#define CK_SCMI_SYSDBG 119 +#define CK_SCMI_SYSATB 120 +#define CK_SCMI_TSDBG 121 +#define CK_SCMI_STM500 122 + +#endif /* _DT_BINDINGS_STM32MP25_CLKS_H_ */ diff --git a/include/dt-bindings/reset/st,stm32mp25-rcc.h b/include/dt-bindings/reset/st,stm32mp25-rcc.h new file mode 100644 index 000000000000..d5615930bcc8 --- /dev/null +++ b/include/dt-bindings/reset/st,stm32mp25-rcc.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (C) STMicroelectronics 2023 - All Rights Reserved + * Author(s): Gabriel Fernandez + */ + +#ifndef _DT_BINDINGS_STM32MP25_RESET_H_ +#define _DT_BINDINGS_STM32MP25_RESET_H_ + +#define TIM1_R 0 +#define TIM2_R 1 +#define TIM3_R 2 +#define TIM4_R 3 +#define TIM5_R 4 +#define TIM6_R 5 +#define TIM7_R 6 +#define TIM8_R 7 +#define TIM10_R 8 +#define TIM11_R 9 +#define TIM12_R 10 +#define TIM13_R 11 +#define TIM14_R 12 +#define TIM15_R 13 +#define TIM16_R 14 +#define TIM17_R 15 +#define TIM20_R 16 +#define LPTIM1_R 17 +#define LPTIM2_R 18 +#define LPTIM3_R 19 +#define LPTIM4_R 20 +#define LPTIM5_R 21 +#define SPI1_R 22 +#define SPI2_R 23 +#define SPI3_R 24 +#define SPI4_R 25 +#define SPI5_R 26 +#define SPI6_R 27 +#define SPI7_R 28 +#define SPI8_R 29 +#define SPDIFRX_R 30 +#define USART1_R 31 +#define USART2_R 32 +#define USART3_R 33 +#define UART4_R 34 +#define UART5_R 35 +#define USART6_R 36 +#define UART7_R 37 +#define UART8_R 38 +#define UART9_R 39 +#define LPUART1_R 40 +#define IS2M_R 41 +#define I2C1_R 42 +#define I2C2_R 43 +#define I2C3_R 44 +#define I2C4_R 45 +#define I2C5_R 46 +#define I2C6_R 47 +#define I2C7_R 48 +#define I2C8_R 49 +#define SAI1_R 50 +#define SAI2_R 51 +#define SAI3_R 52 +#define SAI4_R 53 +#define MDF1_R 54 +#define MDF2_R 55 +#define FDCAN_R 56 +#define HDP_R 57 +#define ADC12_R 58 +#define ADC3_R 59 +#define ETH1_R 60 +#define ETH2_R 61 +#define USB2_R 62 +#define USB2PHY1_R 63 +#define USB2PHY2_R 64 +#define USB3DR_R 65 +#define USB3PCIEPHY_R 66 +#define USBTC_R 67 +#define ETHSW_R 68 +#define SDMMC1_R 69 +#define SDMMC1DLL_R 70 +#define SDMMC2_R 71 +#define SDMMC2DLL_R 72 +#define SDMMC3_R 73 +#define SDMMC3DLL_R 74 +#define GPU_R 75 +#define LTDC_R 76 +#define DSI_R 77 +#define LVDS_R 78 +#define CSI_R 79 +#define DCMIPP_R 80 +#define CCI_R 81 +#define VDEC_R 82 +#define VENC_R 83 +#define WWDG1_R 84 +#define WWDG2_R 85 +#define VREF_R 86 +#define DTS_R 87 +#define CRC_R 88 +#define SERC_R 89 +#define OSPIIOM_R 90 +#define I3C1_R 91 +#define I3C2_R 92 +#define I3C3_R 93 +#define I3C4_R 94 +#define IWDG2_KER_R 95 +#define IWDG4_KER_R 96 +#define RNG_R 97 +#define PKA_R 98 +#define SAES_R 99 +#define HASH_R 100 +#define CRYP1_R 101 +#define CRYP2_R 102 +#define PCIE_R 103 +#define OSPI1_R 104 +#define OSPI1DLL_R 105 +#define OSPI2_R 106 +#define OSPI2DLL_R 107 +#define FMC_R 108 +#define DBG_R 109 +#define GPIOA_R 110 +#define GPIOB_R 111 +#define GPIOC_R 112 +#define GPIOD_R 113 +#define GPIOE_R 114 +#define GPIOF_R 115 +#define GPIOG_R 116 +#define GPIOH_R 117 +#define GPIOI_R 118 +#define GPIOJ_R 119 +#define GPIOK_R 120 +#define GPIOZ_R 121 +#define HPDMA1_R 122 +#define HPDMA2_R 123 +#define HPDMA3_R 124 +#define LPDMA_R 125 +#define HSEM_R 126 +#define IPCC1_R 127 +#define IPCC2_R 128 +#define C2_HOLDBOOT_R 129 +#define C1_HOLDBOOT_R 130 +#define C1_R 131 +#define C1P1POR_R 132 +#define C1P1_R 133 +#define C2_R 134 +#define C3_R 135 +#define SYS_R 136 +#define VSW_R 137 +#define C1MS_R 138 +#define DDRCP_R 139 +#define DDRCAPB_R 140 +#define DDRPHYCAPB_R 141 +#define DDRCFG_R 142 +#define DDR_R 143 + +#define STM32MP25_LAST_RESET 144 + +#define RST_SCMI_C1_R 0 +#define RST_SCMI_C2_R 1 +#define RST_SCMI_C1_HOLDBOOT_R 2 +#define RST_SCMI_C2_HOLDBOOT_R 3 +#define RST_SCMI_FMC 4 +#define RST_SCMI_OSPI1 5 +#define RST_SCMI_OSPI1DLL 6 +#define RST_SCMI_OSPI2 7 +#define RST_SCMI_OSPI2DLL 8 + +#endif /* _DT_BINDINGS_STM32MP25_RESET_H_ */ -- cgit v1.2.3