diff --git a/recipes-kernel/linux/linux-stm32mp.inc b/recipes-kernel/linux/linux-stm32mp.inc index 9ef82ad..3e7bc08 100644 --- a/recipes-kernel/linux/linux-stm32mp.inc +++ b/recipes-kernel/linux/linux-stm32mp.inc @@ -1,7 +1,6 @@ COMPATIBLE_MACHINE = "(stm32mpcommon)" inherit kernel -inherit kernel-fitimage DEPENDS += "openssl-native util-linux-native libyaml-native" @@ -114,6 +113,18 @@ do_deploy:append() { fi } do_deploy[depends] += " virtual/kernel:do_package " + +python() { + fitimage_signed = d.getVar('UBOOT_SIGN_ENABLE') + devicetree = d.getVar('KERNEL_DEVICETREE').split() + machine_features = d.getVar('MACHINE_FEATURES') + if 'fit' in machine_features: + if fitimage_signed is not None and fitimage_signed == "1": + if len(devicetree) > 1: + bb.fatal("The signature of FIT image work only when there is only " + "one DEVICE-TREE specified") +} + # --------------------------------------------------------------------- # Support checking the kernel load address parameter: expecting proper value for ST kernel. # diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0001-ARM-5.10.61-stm32mp1-r2-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0001-ARM-5.10.61-stm32mp1-r2-MACHINE.patch deleted file mode 100644 index 0da8c6c..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0001-ARM-5.10.61-stm32mp1-r2-MACHINE.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 291e33f627836085d320628794cbc836a3241965 Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:41 +0200 -Subject: [PATCH 01/23] ARM 5.10.61-stm32mp1-r2 MACHINE - ---- - arch/arm/mach-stm32/Kconfig | 2 ++ - arch/arm/mach-stm32/board-dt.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig -index 57699bd8f..d1f79bc2c 100644 ---- a/arch/arm/mach-stm32/Kconfig -+++ b/arch/arm/mach-stm32/Kconfig -@@ -46,6 +46,8 @@ if ARCH_MULTI_V7 - config MACH_STM32MP157 - bool "STMicroelectronics STM32MP157" - select ARM_ERRATA_814220 -+ select REGULATOR -+ select ARCH_SUPPORTS_RT - default y - - endif # ARMv7-A -diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c -index 011d57b48..8e06a9442 100644 ---- a/arch/arm/mach-stm32/board-dt.c -+++ b/arch/arm/mach-stm32/board-dt.c -@@ -17,6 +17,8 @@ static const char *const stm32_compat[] __initconst = { - "st,stm32f746", - "st,stm32f769", - "st,stm32h743", -+ "st,stm32mp151", -+ "st,stm32mp153", - "st,stm32mp157", - NULL - }; --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0002-ARM-5.10.61-stm32mp1-r2-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0002-ARM-5.10.61-stm32mp1-r2-CLOCK.patch deleted file mode 100644 index 4d723fb..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0002-ARM-5.10.61-stm32mp1-r2-CLOCK.patch +++ /dev/null @@ -1,1799 +0,0 @@ -From 449ee632a4a7c7e93107d3c1ea502974d4c206f5 Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:41 +0200 -Subject: [PATCH 02/23] ARM 5.10.61-stm32mp1-r2 CLOCK - ---- - drivers/clk/clk-composite.c | 15 + - drivers/clk/clk-stm32mp1.c | 1153 ++++++++++++++++----- - drivers/clk/clk.c | 7 +- - drivers/clocksource/timer-stm32-lp.c | 4 +- - include/dt-bindings/clock/stm32mp1-clks.h | 33 + - 5 files changed, 945 insertions(+), 267 deletions(-) - -diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c -index 2ddb54f7d..b49ecd1b9 100644 ---- a/drivers/clk/clk-composite.c -+++ b/drivers/clk/clk-composite.c -@@ -41,6 +41,18 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, - return rate_ops->recalc_rate(rate_hw, parent_rate); - } - -+static int clk_composite_get_duty_cycle(struct clk_hw *hw, -+ struct clk_duty *duty) -+{ -+ struct clk_composite *composite = to_clk_composite(hw); -+ const struct clk_ops *rate_ops = composite->rate_ops; -+ struct clk_hw *rate_hw = composite->rate_hw; -+ -+ __clk_hw_set_clk(rate_hw, hw); -+ -+ return rate_ops->get_duty_cycle(rate_hw, duty); -+} -+ - static int clk_composite_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) - { -@@ -250,6 +262,9 @@ static struct clk_hw *__clk_hw_register_composite(struct device *dev, - } - clk_composite_ops->recalc_rate = clk_composite_recalc_rate; - -+ if (rate_ops->get_duty_cycle) -+ clk_composite_ops->get_duty_cycle = clk_composite_get_duty_cycle; -+ - if (rate_ops->determine_rate) - clk_composite_ops->determine_rate = - clk_composite_determine_rate; -diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index a875649df..ddaf7dc9b 100644 ---- a/drivers/clk/clk-stm32mp1.c -+++ b/drivers/clk/clk-stm32mp1.c -@@ -5,15 +5,28 @@ - * Author: Gabriel Fernandez for STMicroelectronics. - */ - -+#include -+#include - #include - #include - #include -+#include - #include -+#include - #include -+#include -+#include -+#include -+#include - #include - #include -+#include -+#include -+#include -+#include - #include - #include -+#include - - #include - -@@ -45,6 +58,7 @@ static DEFINE_SPINLOCK(rlock); - #define RCC_AHB5ENSETR 0x210 - #define RCC_AHB6ENSETR 0x218 - #define RCC_AHB6LPENSETR 0x318 -+#define RCC_MLAHBENSETR 0xA38 - #define RCC_RCK12SELR 0x28 - #define RCC_RCK3SELR 0x820 - #define RCC_RCK4SELR 0x824 -@@ -101,8 +115,12 @@ static DEFINE_SPINLOCK(rlock); - #define RCC_TIMG2PRER 0x82C - #define RCC_RTCDIVR 0x44 - #define RCC_DBGCFGR 0x80C -+#define RCC_SREQSETR 0x104 -+#define RCC_SREQCLRR 0x108 -+#define RCC_CIER 0x414 -+#define RCC_CIFR 0x418 - --#define RCC_CLR 0x4 -+#define RCC_CLR 0x4 - - static const char * const ref12_parents[] = { - "ck_hsi", "ck_hse" -@@ -113,7 +131,7 @@ static const char * const ref3_parents[] = { - }; - - static const char * const ref4_parents[] = { -- "ck_hsi", "ck_hse", "ck_csi" -+ "ck_hsi", "ck_hse", "ck_csi", "i2s_ckin" - }; - - static const char * const cpu_src[] = { -@@ -245,7 +263,7 @@ static const char * const dsi_src[] = { - }; - - static const char * const rtc_src[] = { -- "off", "ck_lse", "ck_lsi", "ck_hse_rtc" -+ "off", "ck_lse", "ck_lsi", "ck_hse" - }; - - static const char * const mco1_src[] = { -@@ -291,6 +309,7 @@ static const struct clk_div_table ck_trace_div_table[] = { - struct stm32_mmux { - u8 nbr_clk; - struct clk_hw *hws[MAX_MUX_CLK]; -+ u8 saved_parent; - }; - - struct stm32_clk_mmux { -@@ -323,7 +342,7 @@ struct clock_config { - const struct clock_config *cfg); - }; - --#define NO_ID ~0 -+#define NO_ID GENMASK(31, 0) - - struct gate_cfg { - u32 reg_off; -@@ -469,7 +488,7 @@ static const struct clk_ops mp1_gate_clk_ops = { - .is_enabled = clk_gate_is_enabled, - }; - --static struct clk_hw *_get_stm32_mux(void __iomem *base, -+static struct clk_hw *_get_stm32_mux(struct device *dev, void __iomem *base, - const struct stm32_mux_cfg *cfg, - spinlock_t *lock) - { -@@ -478,7 +497,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, - struct clk_hw *mux_hw; - - if (cfg->mmux) { -- mmux = kzalloc(sizeof(*mmux), GFP_KERNEL); -+ mmux = devm_kzalloc(dev, sizeof(*mmux), GFP_KERNEL); - if (!mmux) - return ERR_PTR(-ENOMEM); - -@@ -493,7 +512,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, - cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; - - } else { -- mux = kzalloc(sizeof(*mux), GFP_KERNEL); -+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); - if (!mux) - return ERR_PTR(-ENOMEM); - -@@ -509,13 +528,13 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, - return mux_hw; - } - --static struct clk_hw *_get_stm32_div(void __iomem *base, -+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 = kzalloc(sizeof(*div), GFP_KERNEL); -+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); - - if (!div) - return ERR_PTR(-ENOMEM); -@@ -530,16 +549,16 @@ static struct clk_hw *_get_stm32_div(void __iomem *base, - return &div->hw; - } - --static struct clk_hw * --_get_stm32_gate(void __iomem *base, -- const struct stm32_gate_cfg *cfg, spinlock_t *lock) -+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 = kzalloc(sizeof(*mgate), GFP_KERNEL); -+ mgate = devm_kzalloc(dev, sizeof(*mgate), GFP_KERNEL); - if (!mgate) - return ERR_PTR(-ENOMEM); - -@@ -554,7 +573,7 @@ _get_stm32_gate(void __iomem *base, - gate_hw = &mgate->gate.hw; - - } else { -- gate = kzalloc(sizeof(*gate), GFP_KERNEL); -+ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); - if (!gate) - return ERR_PTR(-ENOMEM); - -@@ -592,7 +611,7 @@ clk_stm32_register_gate_ops(struct device *dev, - if (cfg->ops) - init.ops = cfg->ops; - -- hw = _get_stm32_gate(base, cfg, lock); -+ hw = _get_stm32_gate(dev, base, cfg, lock); - if (IS_ERR(hw)) - return ERR_PTR(-ENOMEM); - -@@ -623,7 +642,7 @@ clk_stm32_register_composite(struct device *dev, - gate_ops = NULL; - - if (cfg->mux) { -- mux_hw = _get_stm32_mux(base, cfg->mux, lock); -+ mux_hw = _get_stm32_mux(dev, base, cfg->mux, lock); - - if (!IS_ERR(mux_hw)) { - mux_ops = &clk_mux_ops; -@@ -634,7 +653,7 @@ clk_stm32_register_composite(struct device *dev, - } - - if (cfg->div) { -- div_hw = _get_stm32_div(base, cfg->div, lock); -+ div_hw = _get_stm32_div(dev, base, cfg->div, lock); - - if (!IS_ERR(div_hw)) { - div_ops = &clk_divider_ops; -@@ -645,7 +664,7 @@ clk_stm32_register_composite(struct device *dev, - } - - if (cfg->gate) { -- gate_hw = _get_stm32_gate(base, cfg->gate, lock); -+ gate_hw = _get_stm32_gate(dev, base, cfg->gate, lock); - - if (!IS_ERR(gate_hw)) { - gate_ops = &clk_gate_ops; -@@ -714,7 +733,7 @@ static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) - - 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); -+ clk_hw_set_parent(clk_mmux->mmux->hws[n], hwp); - - return 0; - } -@@ -725,178 +744,266 @@ static const struct clk_ops clk_mmux_ops = { - .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; --}; -+static bool is_all_clk_on_switch_are_off(struct clk_hw *hw) -+{ -+ struct clk_composite *composite = to_clk_composite(hw); -+ struct clk_hw *mux_hw = composite->mux_hw; -+ struct clk_mux *mux = to_clk_mux(mux_hw); -+ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); -+ int i = 0; - --#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) -+ for (i = 0; i < clk_mmux->mmux->nbr_clk; i++) -+ if (__clk_is_enabled(clk_mmux->mmux->hws[i]->clk)) -+ return false; -+ -+ return true; -+} - --#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 MMUX_SAFE_POSITION 0 - --static int __pll_is_enabled(struct clk_hw *hw) -+static int clk_mmux_set_safe_position(struct clk_hw *hw) - { -- struct stm32_pll_obj *clk_elem = to_pll(hw); -+ struct clk_composite *composite = to_clk_composite(hw); -+ struct clk_hw *mux_hw = composite->mux_hw; -+ struct clk_mux *mux = to_clk_mux(mux_hw); -+ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - -- return readl_relaxed(clk_elem->reg) & PLL_ON; --} -+ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(mux_hw); -+ clk_mux_ops.set_parent(mux_hw, MMUX_SAFE_POSITION); - --#define TIMEOUT 5 -+ return 0; -+} - --static int pll_enable(struct clk_hw *hw) -+static int clk_mmux_restore_parent(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; -+ struct clk_composite *composite = to_clk_composite(hw); -+ struct clk_hw *mux_hw = composite->mux_hw; -+ struct clk_mux *mux = to_clk_mux(mux_hw); -+ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - -- spin_lock_irqsave(clk_elem->lock, flags); -+ clk_mux_ops.set_parent(mux_hw, clk_mmux->mmux->saved_parent); - -- if (__pll_is_enabled(hw)) -- goto unlock; -+ return 0; -+} - -- reg = readl_relaxed(clk_elem->reg); -- reg |= PLL_ON; -- writel_relaxed(reg, clk_elem->reg); -+static u8 clk_mmux_get_parent_safe(struct clk_hw *hw) -+{ -+ struct clk_mux *mux = to_clk_mux(hw); -+ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - -- /* 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); -+ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(hw); - -- if (bit_status) -- udelay(120); -+ return clk_mmux->mmux->saved_parent; -+} - -- } while (bit_status && --timeout); -+static int clk_mmux_set_parent_safe(struct clk_hw *hw, u8 index) -+{ -+ struct clk_mux *mux = to_clk_mux(hw); -+ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - --unlock: -- spin_unlock_irqrestore(clk_elem->lock, flags); -+ clk_mmux_set_parent(hw, index); -+ clk_mmux->mmux->saved_parent = index; - -- return bit_status; -+ return 0; - } - --static void pll_disable(struct clk_hw *hw) -+static const struct clk_ops clk_mmux_safe_ops = { -+ .get_parent = clk_mmux_get_parent_safe, -+ .set_parent = clk_mmux_set_parent_safe, -+ .determine_rate = __clk_mux_determine_rate, -+}; -+ -+static int mp1_mgate_clk_enable_safe(struct clk_hw *hw) - { -- struct stm32_pll_obj *clk_elem = to_pll(hw); -- u32 reg; -- unsigned long flags = 0; -+ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); - -- spin_lock_irqsave(clk_elem->lock, flags); -+ clk_mmux_restore_parent(composite_hw); -+ mp1_mgate_clk_enable(hw); - -- reg = readl_relaxed(clk_elem->reg); -- reg &= ~PLL_ON; -- writel_relaxed(reg, clk_elem->reg); -+ return 0; -+} -+ -+static void mp1_mgate_clk_disable_safe(struct clk_hw *hw) -+{ -+ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); - -- spin_unlock_irqrestore(clk_elem->lock, flags); -+ mp1_mgate_clk_disable(hw); -+ -+ if (is_all_clk_on_switch_are_off(composite_hw)) -+ clk_mmux_set_safe_position(composite_hw); - } - --static u32 pll_frac_val(struct clk_hw *hw) -+static const struct clk_ops mp1_mgate_clk_safe_ops = { -+ .enable = mp1_mgate_clk_enable_safe, -+ .disable = mp1_mgate_clk_disable_safe, -+ .is_enabled = clk_gate_is_enabled, -+}; -+ -+/* STM32 PLL */ -+struct clk_pll_fractional_divider { -+ struct clk_hw hw; -+ void __iomem *mreg; -+ u8 mshift; -+ u8 mwidth; -+ u8 mflags; -+ void __iomem *nreg; -+ u8 nshift; -+ u8 nwidth; -+ u8 nflags; -+ void __iomem *freg; -+ u8 fshift; -+ u8 fwidth; -+ -+ /* lock pll enable/disable registers */ -+ spinlock_t *lock; -+}; -+ -+#define to_pll_fractional_divider(_hw)\ -+ container_of(_hw, struct clk_pll_fractional_divider, hw) -+ -+static unsigned long clk_pll_frac_div_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) - { -- struct stm32_pll_obj *clk_elem = to_pll(hw); -- u32 reg, frac = 0; -+ struct clk_pll_fractional_divider *fd = to_pll_fractional_divider(hw); -+ u32 mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift; -+ u32 nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift; -+ u32 fmask = GENMASK(fd->fwidth - 1, 0) << fd->fshift; -+ unsigned long m, n, f; -+ u64 rate, frate = 0; -+ u32 val; -+ -+ val = readl(fd->mreg); -+ m = (val & mmask) >> fd->mshift; -+ if (fd->mflags & CLK_FRAC_DIVIDER_ZERO_BASED) -+ m++; -+ -+ val = readl(fd->nreg); -+ n = (val & nmask) >> fd->nshift; -+ if (fd->nflags & CLK_FRAC_DIVIDER_ZERO_BASED) -+ n++; -+ -+ if (!n || !m) -+ return parent_rate; - -- reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); -- if (reg & FRACLE) -- frac = (reg >> FRAC_SHIFT) & FRAC_MASK; -+ rate = (u64)parent_rate * n; -+ do_div(rate, m); - -- return frac; -+ val = readl(fd->freg); -+ f = (val & fmask) >> fd->fshift; -+ if (f) { -+ frate = (u64)parent_rate * (u64)f; -+ do_div(frate, (m * (1 << fd->fwidth))); -+ } -+ return rate + frate; - } - --static unsigned long pll_recalc_rate(struct clk_hw *hw, -- unsigned long parent_rate) -+static const struct clk_ops clk_pll_frac_div_ops = { -+ .recalc_rate = clk_pll_frac_div_recalc_rate, -+}; -+ -+#define PLL_BIT_ON 0 -+#define PLL_BIT_RDY 1 -+#define PLL_MUX_SHIFT 0 -+#define PLL_MUX_MASK 3 -+#define PLL_DIVMN_OFFSET 4 -+#define PLL_DIVM_SHIFT 16 -+#define PLL_DIVM_WIDTH 6 -+#define PLL_DIVN_SHIFT 0 -+#define PLL_DIVN_WIDTH 9 -+#define PLL_FRAC_OFFSET 0xC -+#define PLL_FRAC_SHIFT 3 -+#define PLL_FRAC_WIDTH 13 -+ -+#define TIMEOUT 5 -+ -+static int pll_enable(struct clk_hw *hw) - { -- struct stm32_pll_obj *clk_elem = to_pll(hw); -- u32 reg; -- u32 frac, divm, divn; -- u64 rate, rate_frac = 0; -+ struct clk_gate *gate = to_clk_gate(hw); -+ u32 timeout = TIMEOUT; -+ int bit_status = 0; - -- reg = readl_relaxed(clk_elem->reg + 4); -+ if (clk_gate_ops.is_enabled(hw)) -+ return 0; - -- divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; -- divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; -- rate = (u64)parent_rate * divn; -+ clk_gate_ops.enable(hw); - -- do_div(rate, divm); -+ do { -+ bit_status = !(readl_relaxed(gate->reg) & BIT(PLL_BIT_RDY)); - -- frac = pll_frac_val(hw); -- if (frac) { -- rate_frac = (u64)parent_rate * (u64)frac; -- do_div(rate_frac, (divm * 8192)); -- } -+ if (bit_status) -+ udelay(120); -+ -+ } while (bit_status && --timeout); - -- return rate + rate_frac; -+ return bit_status; - } - --static int pll_is_enabled(struct clk_hw *hw) -+static void pll_disable(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); -+ if (!clk_gate_ops.is_enabled(hw)) -+ return; - -- return ret; -+ clk_gate_ops.disable(hw); - } - --static const struct clk_ops pll_ops = { -+const struct clk_ops pll_gate_ops = { - .enable = pll_enable, - .disable = pll_disable, -- .recalc_rate = pll_recalc_rate, -- .is_enabled = pll_is_enabled, -+ .is_enabled = clk_gate_is_enabled, - }; - - static struct clk_hw *clk_register_pll(struct device *dev, const char *name, -- const char *parent_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; -+ struct clk_pll_fractional_divider *frac_div; -+ struct clk_gate *gate; -+ struct clk_mux *mux; - -- element = kzalloc(sizeof(*element), GFP_KERNEL); -- if (!element) -+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); -+ if (!mux) - return ERR_PTR(-ENOMEM); - -- init.name = name; -- init.ops = &pll_ops; -- init.flags = flags; -- init.parent_names = &parent_name; -- init.num_parents = 1; -+ mux->reg = mux_reg; -+ mux->shift = PLL_MUX_SHIFT; -+ mux->mask = PLL_MUX_MASK; -+ mux->flags = CLK_MUX_READ_ONLY; -+ mux->table = NULL; -+ mux->lock = lock; - -- element->hw.init = &init; -- element->reg = reg; -- element->lock = lock; -+ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); -+ if (!gate) -+ return ERR_PTR(-ENOMEM); - -- hw = &element->hw; -- err = clk_hw_register(dev, hw); -+ gate->reg = reg; -+ gate->bit_idx = PLL_BIT_ON; -+ gate->flags = 0; -+ gate->lock = lock; - -- if (err) { -- kfree(element); -- return ERR_PTR(err); -- } -+ frac_div = devm_kzalloc(dev, sizeof(*frac_div), GFP_KERNEL); -+ if (!frac_div) -+ return ERR_PTR(-ENOMEM); - -- return hw; -+ frac_div->mreg = reg + PLL_DIVMN_OFFSET; -+ frac_div->mshift = PLL_DIVM_SHIFT; -+ frac_div->mwidth = PLL_DIVM_WIDTH; -+ frac_div->mflags = CLK_FRAC_DIVIDER_ZERO_BASED; -+ frac_div->nreg = reg + PLL_DIVMN_OFFSET; -+ frac_div->nshift = PLL_DIVN_SHIFT; -+ frac_div->nwidth = PLL_DIVN_WIDTH; -+ frac_div->nflags = CLK_FRAC_DIVIDER_ZERO_BASED; -+ frac_div->freg = reg + PLL_FRAC_OFFSET; -+ frac_div->fshift = PLL_FRAC_SHIFT; -+ frac_div->fwidth = PLL_FRAC_WIDTH; -+ -+ return clk_hw_register_composite(dev, name, parent_names, num_parents, -+ &mux->hw, &clk_mux_ops, -+ &frac_div->hw, &clk_pll_frac_div_ops, -+ &gate->hw, &pll_gate_ops, flags); - } - - /* Kernel Timer */ -@@ -1005,7 +1112,7 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, - struct clk_hw *hw; - int err; - -- tim_ker = kzalloc(sizeof(*tim_ker), GFP_KERNEL); -+ tim_ker = devm_kzalloc(dev, sizeof(*tim_ker), GFP_KERNEL); - if (!tim_ker) - return ERR_PTR(-ENOMEM); - -@@ -1023,16 +1130,90 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, - hw = &tim_ker->hw; - err = clk_hw_register(dev, hw); - -- if (err) { -- kfree(tim_ker); -+ if (err) - return ERR_PTR(err); -- } - - return hw; - } - -+#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 long clk_divider_rtc_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) -+ return clk_divider_ops.round_rate(hw, rate, prate); -+ -+ return *prate; -+} -+ -+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_div_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) -+{ -+ struct clk_divider *divider = to_clk_divider(hw); -+ unsigned int val; -+ -+ val = readl(divider->reg) >> divider->shift; -+ val &= clk_div_mask(divider->width); -+ -+ duty->num = (val + 1) / 2; -+ duty->den = (val + 1); -+ -+ return 0; -+} -+ -+static const struct clk_ops rtc_div_clk_ops = { -+ .recalc_rate = clk_divider_rtc_recalc_rate, -+ .round_rate = clk_divider_rtc_round_rate, -+ .set_rate = clk_divider_rtc_set_rate, -+}; -+ -+static unsigned long clk_div_duty_cycle_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ return clk_divider_ops.recalc_rate(hw, parent_rate); -+} -+ -+static long clk_div_duty_cycle_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ return clk_divider_ops.round_rate(hw, rate, prate); -+} -+ -+static int clk_div_duty_cycle_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ return clk_divider_ops.set_rate(hw, rate, parent_rate); -+} -+ -+static const struct clk_ops div_dc_clk_ops = { -+ .recalc_rate = clk_div_duty_cycle_recalc_rate, -+ .round_rate = clk_div_duty_cycle_round_rate, -+ .set_rate = clk_div_duty_cycle_set_rate, -+ .get_duty_cycle = clk_div_get_duty_cycle, -+}; -+ - struct stm32_pll_cfg { - u32 offset; -+ u32 muxoff; -+ const struct clk_ops *ops; - }; - - static struct clk_hw *_clk_register_pll(struct device *dev, -@@ -1042,8 +1223,11 @@ static struct clk_hw *_clk_register_pll(struct device *dev, - { - struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; - -- return clk_register_pll(dev, cfg->name, cfg->parent_name, -- base + stm_pll_cfg->offset, cfg->flags, lock); -+ 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 { -@@ -1153,14 +1337,16 @@ _clk_stm32_register_composite(struct device *dev, - .func = _clk_hw_register_mux,\ - } - --#define PLL(_id, _name, _parent, _flags, _offset)\ -+#define PLL(_id, _name, _parents, _flags, _offset_p, _offset_mux)\ - {\ - .id = _id,\ - .name = _name,\ -- .parent_name = _parent,\ -- .flags = _flags,\ -+ .parent_names = _parents,\ -+ .num_parents = ARRAY_SIZE(_parents),\ -+ .flags = CLK_IGNORE_UNUSED | (_flags),\ - .cfg = &(struct stm32_pll_cfg) {\ -- .offset = _offset,\ -+ .offset = _offset_p,\ -+ .muxoff = _offset_mux,\ - },\ - .func = _clk_register_pll,\ - } -@@ -1216,7 +1402,7 @@ _clk_stm32_register_composite(struct device *dev, - NULL, &mp1_gate_clk_ops)\ - - #define _MGATE_MP1(_mgate)\ -- .gate = &per_gate_cfg[_mgate] -+ &per_gate_cfg[_mgate] - - #define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ - STM32_GATE(_id, _name, _parent, _flags,\ -@@ -1228,7 +1414,7 @@ _clk_stm32_register_composite(struct device *dev, - - #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ - _div_flags, _div_table, _ops)\ -- .div = &(struct stm32_div_cfg) {\ -+ (&(struct stm32_div_cfg) {\ - &(struct div_cfg) {\ - .reg_off = _div_offset,\ - .shift = _div_shift,\ -@@ -1237,14 +1423,23 @@ _clk_stm32_register_composite(struct device *dev, - .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)\ -+ _div_flags, _div_table, NULL) -+ -+#define _DIV_DUTY_CYCLE(_div_offset, _div_shift, _div_width, _div_flags,\ -+ _div_table)\ -+ _STM32_DIV(_div_offset, _div_shift, _div_width,\ -+ _div_flags, _div_table, &div_dc_clk_ops) -+ -+#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 stm32_mux_cfg) {\ - &(struct mux_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ -@@ -1254,18 +1449,18 @@ _clk_stm32_register_composite(struct device *dev, - },\ - .mmux = _mmux,\ - .ops = _ops,\ -- } -+ }) - - #define _MUX(_offset, _shift, _width, _mux_flags)\ -- _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ -+ _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL) - --#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] -+#define _MMUX(_mmux) &ker_mux_cfg[_mmux] - --#define PARENT(_parent) ((const char *[]) { _parent}) -+#define PARENT(_parent) ((const char *[]) { _parent}) - --#define _NO_MUX .mux = NULL --#define _NO_DIV .div = NULL --#define _NO_GATE .gate = NULL -+#define _NO_MUX NULL -+#define _NO_DIV NULL -+#define _NO_GATE NULL - - #define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ - {\ -@@ -1275,9 +1470,9 @@ _clk_stm32_register_composite(struct device *dev, - .num_parents = ARRAY_SIZE(_parents),\ - .flags = _flags,\ - .cfg = &(struct stm32_composite_cfg) {\ -- _gate,\ -- _mux,\ -- _div,\ -+ .gate = (_gate),\ -+ .mux = (_mux),\ -+ .div = (_div),\ - },\ - .func = _clk_stm32_register_composite,\ - } -@@ -1292,6 +1487,11 @@ _clk_stm32_register_composite(struct device *dev, - _MMUX(_mmux),\ - _NO_DIV) - -+/* -+ * -+ * Security management -+ */ -+ - enum { - G_SAI1, - G_SAI2, -@@ -1409,8 +1609,7 @@ enum { - - static struct stm32_mgate mp1_mgate[G_LAST]; - --#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ -- _mgate, _ops)\ -+#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ - [_id] = {\ - &(struct gate_cfg) {\ - .reg_off = _gate_offset,\ -@@ -1429,6 +1628,10 @@ static struct stm32_mgate mp1_mgate[G_LAST]; - _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ - &mp1_mgate[_id], &mp1_mgate_clk_ops) - -+#define K_MGATE_SAFE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ -+ _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ -+ &mp1_mgate[_id], &mp1_mgate_clk_safe_ops) -+ - /* Peripheral gates */ - static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { - /* Multi gates */ -@@ -1540,16 +1743,19 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { - - 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_MGATE_SAFE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), -+ K_MGATE_SAFE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), -+ K_MGATE_SAFE(G_QSPI, RCC_AHB6ENSETR, 14, 0), -+ K_MGATE_SAFE(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), - }; - -@@ -1615,9 +1821,13 @@ static struct stm32_mmux ker_mux[M_LAST]; - _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ - &ker_mux[_id], &clk_mmux_ops) - -+#define K_MMUX_SAFE(_id, _offset, _shift, _width, _mux_flags)\ -+ _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ -+ &ker_mux[_id], &clk_mmux_safe_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_SAFE(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), -@@ -1634,8 +1844,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - /* 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_MMUX_SAFE(M_FMC, RCC_FMCCKSELR, 0, 2, 0), -+ K_MMUX_SAFE(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), -@@ -1656,40 +1866,43 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), - }; - -+/* -+ * On stm32mp15x, when TZEN is enabled, secure firmware provides -+ * the secure clocks RCC clock driver relies on. Firmware registers -+ * the following clocks in the Linux clock tree: -+ * "ck_hse", "ck_hsi", "ck_csi", "ck_lse", "ck_lsi", -+ * "pll2_q", "pll2_r", "ck_mpu", "ck_axi", -+ * "bsec", "cryp1", "gpioz", "hash1", "i2c4_k", "i2c6_k", "iwdg1", "rng1_k", -+ * "ck_rtc", "rtcapb", "spi6_k" and "usart1_k". -+ * For these clocks and there dependencies, SECURE bit is set in clock -+ * identifier field id to state which clocks RCC clock driver does not register -+ * because it has limited or no access to. -+ */ - static const struct clock_config stm32mp1_clock_cfg[] = { -- /* Oscillator divider */ -- DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO, -- RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), -- -- /* External / Internal Oscillators */ -+ /* 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), -- GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 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)), -+ /* ck_csi is used by IO compensation and shall be critical */ -+ GATE_MP1(CK_CSI, "ck_csi", "clk-csi", -+ CLK_IS_CRITICAL, RCC_OCENSETR, 4, 0), - 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), - -- /* ref clock pll */ -- MUX(NO_ID, "ref1", ref12_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK12SELR, -- 0, 2, CLK_MUX_READ_ONLY), -- -- MUX(NO_ID, "ref3", ref3_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK3SELR, -- 0, 2, CLK_MUX_READ_ONLY), -- -- MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR, -- 0, 2, CLK_MUX_READ_ONLY), -- - /* PLLs */ -- PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), -- PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), -- PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), -- PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), -+ 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, -+ COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), -+ CLK_SET_RATE_PARENT, - _GATE(RCC_PLL1CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), -@@ -1717,7 +1930,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 5, 0), - _NO_MUX, -- _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), -+ _DIV_DUTY_CYCLE(RCC_PLL3CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 6, 0), -@@ -1737,40 +1950,42 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, - _GATE(RCC_PLL4CR, 6, 0), - _NO_MUX, -- _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), -+ _DIV_DUTY_CYCLE(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), -+ MUX(CK_MPU, "ck_mpu", cpu_src, -+ CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT | -+ 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_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)), -+ 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, -+ DIV_TABLE(PCLK1, "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, -+ DIV_TABLE(PCLK2, "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, -+ DIV_TABLE(PCLK3, "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, -+ DIV_TABLE(PCLK4, "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, -+ DIV_TABLE(PCLK5, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - /* Kernel Timers */ -@@ -1852,8 +2067,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - 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(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), -@@ -1888,16 +2103,13 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - 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(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(ETHRX, "ethrx", "ck_axi", 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), -@@ -1912,7 +2124,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - 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(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), -@@ -1965,23 +2178,21 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), - - /* RTC clock */ -- DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0), -- -- COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | -- CLK_SET_RATE_PARENT, -+ COMPOSITE(RTC, "ck_rtc", rtc_src, -+ CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT, - _GATE(RCC_BDCR, 20, 0), - _MUX(RCC_BDCR, 16, 2, 0), -- _NO_DIV), -+ _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, -+ 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, -+ 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)), -@@ -1990,22 +2201,83 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - 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, -+ COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, -+ CLK_OPS_PARENT_ENABLE | CLK_IGNORE_UNUSED, - _GATE(RCC_DBGCFGR, 9, 0), - _NO_MUX, - _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), - }; - --struct stm32_clock_match_data { -+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; -+ bool (*check_security)(const struct clock_config *cfg); -+ u32 clear_offset; -+}; -+ -+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_clock_match_data stm32mp1_data = { -+static struct stm32_rcc_match_data stm32mp1_data_secure = { - .cfg = stm32mp1_clock_cfg, - .num = ARRAY_SIZE(stm32mp1_clock_cfg), - .maxbinding = STM32MP1_LAST_CLK, -+ .check_security = &stm32_check_security, -+ .clear_offset = RCC_CLR, - }; - - static const struct of_device_id stm32mp1_match_data[] = { -@@ -2013,8 +2285,13 @@ 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, -@@ -2040,28 +2317,195 @@ static int stm32_register_hw_clk(struct device *dev, - return 0; - } - --static int stm32_rcc_init(struct device_node *np, -- void __iomem *base, -- const struct of_device_id *match_data) -+#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) - { -- struct clk_hw_onecell_data *clk_data; -- struct clk_hw **hws; -- const struct of_device_id *match; -- const struct stm32_clock_match_data *data; -- int err, n, max_binding; -+ return container_of(rcdev, struct stm32_reset_data, rcdev); -+} - -- match = of_match_node(match_data, np); -- if (!match) { -- pr_err("%s: match data not found\n", __func__); -- return -ENODEV; -+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; -+ - data = match->data; - -+ reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); -+ if (!reset_data) -+ return -ENOMEM; -+ -+ 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 struct stm32_clk_boot_on { -+ struct clk **clks; -+ int nb; -+} *clk_boot_on; -+ -+static struct stm32_clk_boot_on *clk_boot_on; -+ -+static int stm32_clk_boot_on_enable(struct device_node *np, -+ struct clk_hw_onecell_data *clk_data) -+{ -+ struct of_phandle_args clkspec; -+ struct property *prop; -+ const __be32 *cur; -+ struct clk **clks; -+ int nb, count = 0; -+ -+ nb = of_property_count_u32_elems(np, "clocks-boot-on"); -+ if (!nb) -+ return 0; -+ -+ clks = kcalloc(nb, sizeof(struct clk_bulk_data *), GFP_KERNEL); -+ if (!clks) -+ return -ENOMEM; -+ -+ clk_boot_on = kzalloc(sizeof(*clk_boot_on), GFP_KERNEL); -+ if (!clk_boot_on) { -+ kfree(clks); -+ return -ENOMEM; -+ } -+ -+ of_property_for_each_u32(np, "clocks-boot-on", prop, cur, -+ clkspec.args[0]) { -+ struct clk_hw *hw; -+ -+ hw = of_clk_hw_onecell_get(&clkspec, clk_data); -+ if (IS_ERR(hw)) -+ continue; -+ -+ if (clk_prepare_enable(hw->clk)) { -+ pr_warn("can't enable clock %s !\n", -+ clk_hw_get_name(hw)); -+ continue; -+ } -+ -+ clks[count++] = hw->clk; -+ } -+ -+ clk_boot_on->clks = clks; -+ clk_boot_on->nb = count; -+ -+ return 0; -+} -+ -+static int stm32_clk_boot_on_disable(void) -+{ -+ int i; -+ -+ if (clk_boot_on) { -+ for (i = 0; i < clk_boot_on->nb; i++) -+ clk_disable_unprepare(clk_boot_on->clks[i]); -+ -+ kfree(clk_boot_on->clks); -+ kfree(clk_boot_on); -+ } -+ -+ return 0; -+} -+late_initcall_sync(stm32_clk_boot_on_disable); -+ -+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 = kzalloc(struct_size(clk_data, hws, max_binding), -- GFP_KERNEL); -+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding), -+ GFP_KERNEL); - if (!clk_data) - return -ENOMEM; - -@@ -2073,36 +2517,221 @@ static int stm32_rcc_init(struct device_node *np, - hws[n] = ERR_PTR(-ENOENT); - - for (n = 0; n < data->num; n++) { -- err = stm32_register_hw_clk(NULL, clk_data, base, &rlock, -+ 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) { -- pr_err("%s: can't register %s\n", __func__, -- data->cfg[n].name); -- -- kfree(clk_data); -+ dev_err(dev, "Can't register clk %s: %d\n", -+ data->cfg[n].name, err); - - return err; - } - } - -- return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); -+ err = of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, clk_data); -+ if (!err) -+ stm32_clk_boot_on_enable(dev_of_node(dev), clk_data); -+ -+ return err; - } - --static void stm32mp1_rcc_init(struct device_node *np) -+static int stm32_rcc_init(struct device *dev, void __iomem *base, -+ const struct of_device_id *match_data) - { -- void __iomem *base; -+ const struct of_device_id *match; -+ int err; - -- base = of_iomap(np, 0); -- if (!base) { -- pr_err("%pOFn: unable to map resource", np); -- of_node_put(np); -- return; -+ 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 stm32_rcc_init_pwr(struct device *dev, void __iomem *rcc_base); -+ -+static int stm32mp1_rcc_init(struct device *dev) -+{ -+ void __iomem *rcc_base; -+ int ret = -ENOMEM; -+ -+ rcc_base = of_iomap(dev_of_node(dev), 0); -+ if (!rcc_base) { -+ dev_err(dev, "%pOFn: unable to map resource", dev_of_node(dev)); -+ goto out; -+ } -+ -+ ret = stm32_rcc_init(dev, rcc_base, stm32mp1_match_data); -+ if (ret) -+ goto out; -+ -+ ret = stm32_rcc_init_pwr(dev, rcc_base); -+ -+out: -+ if (ret) { -+ if (rcc_base) -+ iounmap(rcc_base); -+ rcc_base = NULL; -+ -+ of_node_put(dev_of_node(dev)); -+ } -+ -+ return ret; -+} -+ -+/* -+ * RCC POWER -+ * -+ */ -+ -+struct reg { -+ u32 address; -+ u32 val; -+}; -+ -+/* This table lists the IPs for which CSLEEP is enabled */ -+static const struct reg lp_table[] = { -+ { 0xB04, 0x00000000 }, /* APB1 */ -+ { 0xB0C, 0x00000000 }, /* APB2 */ -+ { 0xB14, 0x00000800 }, /* APB3 */ -+ { 0x304, 0x00000000 }, /* APB4 */ -+ { 0xB1C, 0x00000000 }, /* AHB2 */ -+ { 0xB24, 0x00000000 }, /* AHB3 */ -+ { 0xB2C, 0x00000000 }, /* AHB4 */ -+ { 0x31C, 0x00000000 }, /* AHB6 */ -+ { 0xB34, 0x00000000 }, /* AXIM */ -+ { 0xB3C, 0x00000000 }, /* MLAHB */ -+}; -+ -+#define SMC(class, op, address, val)\ -+ ({\ -+ struct arm_smccc_res res;\ -+ arm_smccc_smc(class, op, address, val,\ -+ 0, 0, 0, 0, &res);\ -+ }) -+ -+#define STM32_SVC_RCC 0x82001000 -+#define STM32_WRITE 0x1 -+#define RCC_IRQ_FLAGS_MASK 0x110F1F -+ -+static irqreturn_t stm32mp1_rcc_irq_handler(int irq, void *sdata) -+{ -+ pr_info("RCC generic interrupt received\n"); -+ -+ /* clear interrupt flag */ -+ SMC(STM32_SVC_RCC, STM32_WRITE, RCC_CIFR, RCC_IRQ_FLAGS_MASK); -+ -+ return IRQ_HANDLED; -+} -+ -+static int stm32_rcc_init_pwr(struct device *dev, void __iomem *rcc_base) -+{ -+ int irq; -+ int ret; -+ int i; -+ -+ /* register generic irq */ -+ irq = of_irq_get(dev_of_node(dev), 0); -+ if (irq <= 0) { -+ pr_err("%s: failed to get RCC generic IRQ\n", __func__); -+ return irq ? irq : -ENXIO; - } - -- if (stm32_rcc_init(np, base, stm32mp1_match_data)) { -- iounmap(base); -- of_node_put(np); -+ ret = devm_request_irq(dev, irq, stm32mp1_rcc_irq_handler, IRQF_ONESHOT, -+ "rcc irq", NULL); -+ if (ret) { -+ pr_err("%s: failed to register generic IRQ\n", __func__); -+ return ret; -+ } -+ -+ /* Configure LPEN static table */ -+ for (i = 0; i < ARRAY_SIZE(lp_table); i++) -+ writel_relaxed(lp_table[i].val, rcc_base + lp_table[i].address); -+ -+ return 0; -+} -+ -+static int get_clock_deps(struct device *dev) -+{ -+ const char *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; - } - --CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); -+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 int 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); -+ -+ return 0; -+} -+ -+static struct platform_driver stm32mp1_rcc_clocks_driver = { -+ .driver = { -+ .name = "stm32mp1_rcc", -+ .of_match_table = stm32mp1_match_data, -+ }, -+ .probe = stm32mp1_rcc_clocks_probe, -+ .remove = 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/clk.c b/drivers/clk/clk.c -index 61c78714c..9b9a17695 100644 ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -1743,6 +1743,7 @@ static void clk_reparent(struct clk_core *core, struct clk_core *new_parent) - core->parent = new_parent; - } - -+static const struct clk_ops clk_nodrv_ops; - static struct clk_core *__clk_set_parent_before(struct clk_core *core, - struct clk_core *parent) - { -@@ -1771,7 +1772,8 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core, - - /* enable old_parent & parent if CLK_OPS_PARENT_ENABLE is set */ - if (core->flags & CLK_OPS_PARENT_ENABLE) { -- clk_core_prepare_enable(old_parent); -+ if (old_parent && old_parent->ops != &clk_nodrv_ops) -+ clk_core_prepare_enable(old_parent); - clk_core_prepare_enable(parent); - } - -@@ -1805,7 +1807,8 @@ static void __clk_set_parent_after(struct clk_core *core, - /* re-balance ref counting if CLK_OPS_PARENT_ENABLE is set */ - if (core->flags & CLK_OPS_PARENT_ENABLE) { - clk_core_disable_unprepare(parent); -- clk_core_disable_unprepare(old_parent); -+ if (old_parent && old_parent->ops != &clk_nodrv_ops) -+ clk_core_disable_unprepare(old_parent); - } - } - -diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c -index db2841d0b..90c10f378 100644 ---- a/drivers/clocksource/timer-stm32-lp.c -+++ b/drivers/clocksource/timer-stm32-lp.c -@@ -168,9 +168,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) - } - - if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { -- ret = device_init_wakeup(&pdev->dev, true); -- if (ret) -- goto out_clk_disable; -+ device_set_wakeup_capable(&pdev->dev, true); - - ret = dev_pm_set_wake_irq(&pdev->dev, irq); - if (ret) -diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h -index 4cdaf1358..ec7b1a932 100644 ---- a/include/dt-bindings/clock/stm32mp1-clks.h -+++ b/include/dt-bindings/clock/stm32mp1-clks.h -@@ -179,6 +179,12 @@ - #define DAC12_K 168 - #define ETHPTP_K 169 - -+#define PCLK1 170 -+#define PCLK2 171 -+#define PCLK3 172 -+#define PCLK4 173 -+#define PCLK5 174 -+ - /* PLL */ - #define PLL1 176 - #define PLL2 177 -@@ -248,4 +254,31 @@ - - #define STM32MP1_LAST_CLK 232 - -+/* SCMI clock identifiers */ -+#define CK_SCMI0_HSE 0 -+#define CK_SCMI0_HSI 1 -+#define CK_SCMI0_CSI 2 -+#define CK_SCMI0_LSE 3 -+#define CK_SCMI0_LSI 4 -+#define CK_SCMI0_PLL2_Q 5 -+#define CK_SCMI0_PLL2_R 6 -+#define CK_SCMI0_MPU 7 -+#define CK_SCMI0_AXI 8 -+#define CK_SCMI0_BSEC 9 -+#define CK_SCMI0_CRYP1 10 -+#define CK_SCMI0_GPIOZ 11 -+#define CK_SCMI0_HASH1 12 -+#define CK_SCMI0_I2C4 13 -+#define CK_SCMI0_I2C6 14 -+#define CK_SCMI0_IWDG1 15 -+#define CK_SCMI0_RNG1 16 -+#define CK_SCMI0_RTC 17 -+#define CK_SCMI0_RTCAPB 18 -+#define CK_SCMI0_SPI6 19 -+#define CK_SCMI0_USART1 20 -+ -+#define CK_SCMI1_PLL3_Q 0 -+#define CK_SCMI1_PLL3_R 1 -+#define CK_SCMI1_MCU 2 -+ - #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0004-ARM-5.10.61-stm32mp1-r2-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0004-ARM-5.10.61-stm32mp1-r2-CRYPTO.patch deleted file mode 100644 index 6fcd755..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0004-ARM-5.10.61-stm32mp1-r2-CRYPTO.patch +++ /dev/null @@ -1,1596 +0,0 @@ -From 06c6f8f73cdc2be580cb20926507696234053bfc Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:42 +0200 -Subject: [PATCH 04/23] ARM 5.10.61-stm32mp1-r2 CRYPTO - ---- - drivers/crypto/stm32/stm32-cryp.c | 993 +++++++++++++----------------- - drivers/crypto/stm32/stm32-hash.c | 19 +- - 2 files changed, 429 insertions(+), 583 deletions(-) - -diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c -index 7999b26a1..361b99e9c 100644 ---- a/drivers/crypto/stm32/stm32-cryp.c -+++ b/drivers/crypto/stm32/stm32-cryp.c -@@ -37,7 +37,6 @@ - /* Mode mask = bits [15..0] */ - #define FLG_MODE_MASK GENMASK(15, 0) - /* Bit [31..16] status */ --#define FLG_CCM_PADDED_WA BIT(16) - - /* Registers */ - #define CRYP_CR 0x00000000 -@@ -105,8 +104,6 @@ - /* Misc */ - #define AES_BLOCK_32 (AES_BLOCK_SIZE / sizeof(u32)) - #define GCM_CTR_INIT 2 --#define _walked_in (cryp->in_walk.offset - cryp->in_sg->offset) --#define _walked_out (cryp->out_walk.offset - cryp->out_sg->offset) - #define CRYP_AUTOSUSPEND_DELAY 50 - - struct stm32_cryp_caps { -@@ -144,26 +141,16 @@ struct stm32_cryp { - size_t authsize; - size_t hw_blocksize; - -- size_t total_in; -- size_t total_in_save; -- size_t total_out; -- size_t total_out_save; -+ size_t payload_in; -+ size_t header_in; -+ size_t payload_out; - -- struct scatterlist *in_sg; - struct scatterlist *out_sg; -- struct scatterlist *out_sg_save; -- -- struct scatterlist in_sgl; -- struct scatterlist out_sgl; -- bool sgs_copied; -- -- int in_sg_len; -- int out_sg_len; - - struct scatter_walk in_walk; - struct scatter_walk out_walk; - -- u32 last_ctr[4]; -+ __be32 last_ctr[4]; - u32 gcm_ctr; - }; - -@@ -245,6 +232,11 @@ static inline int stm32_cryp_wait_busy(struct stm32_cryp *cryp) - !(status & SR_BUSY), 10, 100000); - } - -+static inline void stm32_cryp_enable(struct stm32_cryp *cryp) -+{ -+ writel_relaxed(readl_relaxed(cryp->regs + CRYP_CR) | CR_CRYPEN, cryp->regs + CRYP_CR); -+} -+ - static inline int stm32_cryp_wait_enable(struct stm32_cryp *cryp) - { - u32 status; -@@ -262,6 +254,7 @@ static inline int stm32_cryp_wait_output(struct stm32_cryp *cryp) - } - - static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp); -+static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err); - - static struct stm32_cryp *stm32_cryp_find_dev(struct stm32_cryp_ctx *ctx) - { -@@ -283,103 +276,6 @@ static struct stm32_cryp *stm32_cryp_find_dev(struct stm32_cryp_ctx *ctx) - return cryp; - } - --static int stm32_cryp_check_aligned(struct scatterlist *sg, size_t total, -- size_t align) --{ -- int len = 0; -- -- if (!total) -- return 0; -- -- if (!IS_ALIGNED(total, align)) -- return -EINVAL; -- -- while (sg) { -- if (!IS_ALIGNED(sg->offset, sizeof(u32))) -- return -EINVAL; -- -- if (!IS_ALIGNED(sg->length, align)) -- return -EINVAL; -- -- len += sg->length; -- sg = sg_next(sg); -- } -- -- if (len != total) -- return -EINVAL; -- -- return 0; --} -- --static int stm32_cryp_check_io_aligned(struct stm32_cryp *cryp) --{ -- int ret; -- -- ret = stm32_cryp_check_aligned(cryp->in_sg, cryp->total_in, -- cryp->hw_blocksize); -- if (ret) -- return ret; -- -- ret = stm32_cryp_check_aligned(cryp->out_sg, cryp->total_out, -- cryp->hw_blocksize); -- -- return ret; --} -- --static void sg_copy_buf(void *buf, struct scatterlist *sg, -- unsigned int start, unsigned int nbytes, int out) --{ -- struct scatter_walk walk; -- -- if (!nbytes) -- return; -- -- scatterwalk_start(&walk, sg); -- scatterwalk_advance(&walk, start); -- scatterwalk_copychunks(buf, &walk, nbytes, out); -- scatterwalk_done(&walk, out, 0); --} -- --static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp) --{ -- void *buf_in, *buf_out; -- int pages, total_in, total_out; -- -- if (!stm32_cryp_check_io_aligned(cryp)) { -- cryp->sgs_copied = 0; -- return 0; -- } -- -- total_in = ALIGN(cryp->total_in, cryp->hw_blocksize); -- pages = total_in ? get_order(total_in) : 1; -- buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages); -- -- total_out = ALIGN(cryp->total_out, cryp->hw_blocksize); -- pages = total_out ? get_order(total_out) : 1; -- buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages); -- -- if (!buf_in || !buf_out) { -- dev_err(cryp->dev, "Can't allocate pages when unaligned\n"); -- cryp->sgs_copied = 0; -- return -EFAULT; -- } -- -- sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->total_in, 0); -- -- sg_init_one(&cryp->in_sgl, buf_in, total_in); -- cryp->in_sg = &cryp->in_sgl; -- cryp->in_sg_len = 1; -- -- sg_init_one(&cryp->out_sgl, buf_out, total_out); -- cryp->out_sg_save = cryp->out_sg; -- cryp->out_sg = &cryp->out_sgl; -- cryp->out_sg_len = 1; -- -- cryp->sgs_copied = 1; -- -- return 0; --} -- - static void stm32_cryp_hw_write_iv(struct stm32_cryp *cryp, __be32 *iv) - { - if (!iv) -@@ -481,16 +377,100 @@ static int stm32_cryp_gcm_init(struct stm32_cryp *cryp, u32 cfg) - - /* Wait for end of processing */ - ret = stm32_cryp_wait_enable(cryp); -- if (ret) -+ if (ret) { - dev_err(cryp->dev, "Timeout (gcm init)\n"); -+ return ret; -+ } - -- return ret; -+ /* Prepare next phase */ -+ if (cryp->areq->assoclen) { -+ cfg |= CR_PH_HEADER; -+ stm32_cryp_write(cryp, CRYP_CR, cfg); -+ } else if (stm32_cryp_get_input_text_len(cryp)) { -+ cfg |= CR_PH_PAYLOAD; -+ stm32_cryp_write(cryp, CRYP_CR, cfg); -+ } -+ -+ return 0; -+} -+ -+static void stm32_crypt_gcmccm_end_header(struct stm32_cryp *cryp) -+{ -+ u32 cfg; -+ int err; -+ -+ /* Check if whole header written */ -+ if (!cryp->header_in) { -+ /* Wait for completion */ -+ err = stm32_cryp_wait_busy(cryp); -+ if (err) { -+ dev_err(cryp->dev, "Timeout (gcm/ccm header)\n"); -+ stm32_cryp_write(cryp, CRYP_IMSCR, 0); -+ stm32_cryp_finish_req(cryp, err); -+ return; -+ } -+ -+ if (stm32_cryp_get_input_text_len(cryp)) { -+ /* Phase 3 : payload */ -+ cfg = stm32_cryp_read(cryp, CRYP_CR); -+ cfg &= ~CR_CRYPEN; -+ stm32_cryp_write(cryp, CRYP_CR, cfg); -+ -+ cfg &= ~CR_PH_MASK; -+ cfg |= CR_PH_PAYLOAD | CR_CRYPEN; -+ stm32_cryp_write(cryp, CRYP_CR, cfg); -+ } else { -+ /* -+ * Phase 4 : tag. -+ * Nothing to read, nothing to write, caller have to -+ * end request -+ */ -+ } -+ } - } - -+static void stm32_cryp_write_ccm_first_header(struct stm32_cryp *cryp) -+{ -+ unsigned int i; -+ size_t written; -+ size_t len; -+ u32 alen = cryp->areq->assoclen; -+ u32 block[AES_BLOCK_32] = {0}; -+ u8 *b8 = (u8 *)block; -+ -+ if (alen <= 65280) { -+ /* Write first u32 of B1 */ -+ b8[0] = (alen >> 8) & 0xFF; -+ b8[1] = alen & 0xFF; -+ len = 2; -+ } else { -+ /* Build the two first u32 of B1 */ -+ b8[0] = 0xFF; -+ b8[1] = 0xFE; -+ b8[2] = alen & 0xFF000000; -+ b8[3] = alen & 0x00FF0000; -+ b8[4] = alen & 0x0000FF00; -+ b8[5] = alen & 0x000000FF; -+ len = 6; -+ } -+ -+ written = min_t(size_t, AES_BLOCK_SIZE - len, alen); -+ -+ scatterwalk_copychunks((char *)block + len, &cryp->in_walk, written, 0); -+ for (i = 0; i < AES_BLOCK_32; i++) -+ stm32_cryp_write(cryp, CRYP_DIN, block[i]); -+ -+ cryp->header_in -= written; -+ -+ stm32_crypt_gcmccm_end_header(cryp); -+} -+ -+ - static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg) - { - int ret; -- u8 iv[AES_BLOCK_SIZE], b0[AES_BLOCK_SIZE]; -+ u32 iv_32[AES_BLOCK_32], b0_32[AES_BLOCK_32]; -+ u8 *iv = (u8 *)iv_32, *b0 = (u8 *)b0_32; - __be32 *bd; - u32 *d; - unsigned int i, textlen; -@@ -531,25 +511,35 @@ static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg) - - /* Wait for end of processing */ - ret = stm32_cryp_wait_enable(cryp); -- if (ret) -+ if (ret) { - dev_err(cryp->dev, "Timeout (ccm init)\n"); -+ return ret; -+ } - -- return ret; -+ /* Prepare next phase */ -+ if (cryp->areq->assoclen) { -+ cfg |= CR_PH_HEADER | CR_CRYPEN; -+ stm32_cryp_write(cryp, CRYP_CR, cfg); -+ -+ /* Write first (special) block (may move to next phase [payload]) */ -+ stm32_cryp_write_ccm_first_header(cryp); -+ } else if (stm32_cryp_get_input_text_len(cryp)) { -+ cfg |= CR_PH_PAYLOAD; -+ stm32_cryp_write(cryp, CRYP_CR, cfg); -+ } -+ -+ return 0; - } - - static int stm32_cryp_hw_init(struct stm32_cryp *cryp) - { - int ret; - u32 cfg, hw_mode; -- - pm_runtime_resume_and_get(cryp->dev); - - /* Disable interrupt */ - stm32_cryp_write(cryp, CRYP_IMSCR, 0); - -- /* Set key */ -- stm32_cryp_hw_write_key(cryp); -- - /* Set configuration */ - cfg = CR_DATA8 | CR_FFLUSH; - -@@ -575,23 +565,36 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) - /* AES ECB/CBC decrypt: run key preparation first */ - if (is_decrypt(cryp) && - ((hw_mode == CR_AES_ECB) || (hw_mode == CR_AES_CBC))) { -- stm32_cryp_write(cryp, CRYP_CR, cfg | CR_AES_KP | CR_CRYPEN); -+ /* Configure in key preparation mode */ -+ stm32_cryp_write(cryp, CRYP_CR, cfg | CR_AES_KP); -+ -+ /* Set key only after full configuration done */ -+ stm32_cryp_hw_write_key(cryp); - -+ /* Start prepare key */ -+ stm32_cryp_enable(cryp); - /* Wait for end of processing */ - ret = stm32_cryp_wait_busy(cryp); - if (ret) { - dev_err(cryp->dev, "Timeout (key preparation)\n"); - return ret; - } -- } - -- cfg |= hw_mode; -+ cfg |= hw_mode | CR_DEC_NOT_ENC; -+ -+ /* Apply updated config (Decrypt + algo) and flush */ -+ stm32_cryp_write(cryp, CRYP_CR, cfg); -+ } else { -+ cfg |= hw_mode; -+ if (is_decrypt(cryp)) -+ cfg |= CR_DEC_NOT_ENC; - -- if (is_decrypt(cryp)) -- cfg |= CR_DEC_NOT_ENC; -+ /* Apply config and flush */ -+ stm32_cryp_write(cryp, CRYP_CR, cfg); - -- /* Apply config and flush (valid when CRYPEN = 0) */ -- stm32_cryp_write(cryp, CRYP_CR, cfg); -+ /* Set key only after configuration done */ -+ stm32_cryp_hw_write_key(cryp); -+ } - - switch (hw_mode) { - case CR_AES_GCM: -@@ -605,16 +608,6 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) - if (ret) - return ret; - -- /* Phase 2 : header (authenticated data) */ -- if (cryp->areq->assoclen) { -- cfg |= CR_PH_HEADER; -- } else if (stm32_cryp_get_input_text_len(cryp)) { -- cfg |= CR_PH_PAYLOAD; -- stm32_cryp_write(cryp, CRYP_CR, cfg); -- } else { -- cfg |= CR_PH_INIT; -- } -- - break; - - case CR_DES_CBC: -@@ -629,11 +622,7 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) - } - - /* Enable now */ -- cfg |= CR_CRYPEN; -- -- stm32_cryp_write(cryp, CRYP_CR, cfg); -- -- cryp->flags &= ~FLG_CCM_PADDED_WA; -+ stm32_cryp_enable(cryp); - - return 0; - } -@@ -647,24 +636,7 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) - if (!err && (!(is_gcm(cryp) || is_ccm(cryp)))) - stm32_cryp_get_iv(cryp); - -- if (cryp->sgs_copied) { -- void *buf_in, *buf_out; -- int pages, len; -- -- buf_in = sg_virt(&cryp->in_sgl); -- buf_out = sg_virt(&cryp->out_sgl); -- -- sg_copy_buf(buf_out, cryp->out_sg_save, 0, -- cryp->total_out_save, 1); -- -- len = ALIGN(cryp->total_in_save, cryp->hw_blocksize); -- pages = len ? get_order(len) : 1; -- free_pages((unsigned long)buf_in, pages); -- -- len = ALIGN(cryp->total_out_save, cryp->hw_blocksize); -- pages = len ? get_order(len) : 1; -- free_pages((unsigned long)buf_out, pages); -- } -+ memset(cryp->ctx->key, 0, sizeof(cryp->ctx->key)); - - pm_runtime_mark_last_busy(cryp->dev); - pm_runtime_put_autosuspend(cryp->dev); -@@ -674,8 +646,6 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) - else - crypto_finalize_skcipher_request(cryp->engine, cryp->req, - err); -- -- memset(cryp->ctx->key, 0, cryp->ctx->keylen); - } - - static int stm32_cryp_cpu_start(struct stm32_cryp *cryp) -@@ -801,7 +771,20 @@ static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key, - static int stm32_cryp_aes_gcm_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) - { -- return authsize == AES_BLOCK_SIZE ? 0 : -EINVAL; -+ switch (authsize) { -+ case 4: -+ case 8: -+ case 12: -+ case 13: -+ case 14: -+ case 15: -+ case 16: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; - } - - static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, -@@ -825,31 +808,61 @@ static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, - - static int stm32_cryp_aes_ecb_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_ECB | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_ecb_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_ECB); - } - - static int stm32_cryp_aes_cbc_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CBC | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_cbc_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CBC); - } - - static int stm32_cryp_aes_ctr_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CTR | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_ctr_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CTR); - } - -@@ -863,53 +876,122 @@ static int stm32_cryp_aes_gcm_decrypt(struct aead_request *req) - return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM); - } - -+static inline int crypto_ccm_check_iv(const u8 *iv) -+{ -+ /* 2 <= L <= 8, so 1 <= L' <= 7. */ -+ if (iv[0] < 1 || iv[0] > 7) -+ return -EINVAL; -+ -+ return 0; -+} -+ - static int stm32_cryp_aes_ccm_encrypt(struct aead_request *req) - { -+ int err; -+ -+ err = crypto_ccm_check_iv(req->iv); -+ if (err) -+ return err; -+ - return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_ccm_decrypt(struct aead_request *req) - { -+ int err; -+ -+ err = crypto_ccm_check_iv(req->iv); -+ if (err) -+ return err; -+ - return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM); - } - - static int stm32_cryp_des_ecb_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_ECB | FLG_ENCRYPT); - } - - static int stm32_cryp_des_ecb_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_ECB); - } - - static int stm32_cryp_des_cbc_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_CBC | FLG_ENCRYPT); - } - - static int stm32_cryp_des_cbc_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_CBC); - } - - static int stm32_cryp_tdes_ecb_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB | FLG_ENCRYPT); - } - - static int stm32_cryp_tdes_ecb_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB); - } - - static int stm32_cryp_tdes_cbc_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC | FLG_ENCRYPT); - } - - static int stm32_cryp_tdes_cbc_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC); - } - -@@ -919,6 +1001,7 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req, - struct stm32_cryp_ctx *ctx; - struct stm32_cryp *cryp; - struct stm32_cryp_reqctx *rctx; -+ struct scatterlist *in_sg; - int ret; - - if (!req && !areq) -@@ -944,76 +1027,57 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req, - if (req) { - cryp->req = req; - cryp->areq = NULL; -- cryp->total_in = req->cryptlen; -- cryp->total_out = cryp->total_in; -+ cryp->header_in = 0; -+ cryp->payload_in = req->cryptlen; -+ cryp->payload_out = req->cryptlen; -+ cryp->authsize = 0; - } else { - /* - * Length of input and output data: - * Encryption case: -- * INPUT = AssocData || PlainText -+ * INPUT = AssocData || PlainText - * <- assoclen -> <- cryptlen -> -- * <------- total_in -----------> - * -- * OUTPUT = AssocData || CipherText || AuthTag -- * <- assoclen -> <- cryptlen -> <- authsize -> -- * <---------------- total_out -----------------> -+ * OUTPUT = AssocData || CipherText || AuthTag -+ * <- assoclen -> <-- cryptlen --> <- authsize -> - * - * Decryption case: -- * INPUT = AssocData || CipherText || AuthTag -- * <- assoclen -> <--------- cryptlen ---------> -- * <- authsize -> -- * <---------------- total_in ------------------> -+ * INPUT = AssocData || CipherTex || AuthTag -+ * <- assoclen ---> <---------- cryptlen ----------> - * -- * OUTPUT = AssocData || PlainText -- * <- assoclen -> <- crypten - authsize -> -- * <---------- total_out -----------------> -+ * OUTPUT = AssocData || PlainText -+ * <- assoclen -> <- cryptlen - authsize -> - */ - cryp->areq = areq; - cryp->req = NULL; - cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq)); -- cryp->total_in = areq->assoclen + areq->cryptlen; -- if (is_encrypt(cryp)) -- /* Append auth tag to output */ -- cryp->total_out = cryp->total_in + cryp->authsize; -- else -- /* No auth tag in output */ -- cryp->total_out = cryp->total_in - cryp->authsize; -- } -- -- cryp->total_in_save = cryp->total_in; -- cryp->total_out_save = cryp->total_out; -- -- cryp->in_sg = req ? req->src : areq->src; -- cryp->out_sg = req ? req->dst : areq->dst; -- cryp->out_sg_save = cryp->out_sg; -- -- cryp->in_sg_len = sg_nents_for_len(cryp->in_sg, cryp->total_in); -- if (cryp->in_sg_len < 0) { -- dev_err(cryp->dev, "Cannot get in_sg_len\n"); -- ret = cryp->in_sg_len; -- return ret; -+ if (is_encrypt(cryp)) { -+ cryp->payload_in = areq->cryptlen; -+ cryp->header_in = areq->assoclen; -+ cryp->payload_out = areq->cryptlen; -+ } else { -+ cryp->payload_in = areq->cryptlen - cryp->authsize; -+ cryp->header_in = areq->assoclen; -+ cryp->payload_out = cryp->payload_in; -+ } - } - -- cryp->out_sg_len = sg_nents_for_len(cryp->out_sg, cryp->total_out); -- if (cryp->out_sg_len < 0) { -- dev_err(cryp->dev, "Cannot get out_sg_len\n"); -- ret = cryp->out_sg_len; -- return ret; -- } - -- ret = stm32_cryp_copy_sgs(cryp); -- if (ret) -- return ret; -+ in_sg = req ? req->src : areq->src; -+ scatterwalk_start(&cryp->in_walk, in_sg); - -- scatterwalk_start(&cryp->in_walk, cryp->in_sg); -+ cryp->out_sg = req ? req->dst : areq->dst; - scatterwalk_start(&cryp->out_walk, cryp->out_sg); - - if (is_gcm(cryp) || is_ccm(cryp)) { - /* In output, jump after assoc data */ -- scatterwalk_advance(&cryp->out_walk, cryp->areq->assoclen); -- cryp->total_out -= cryp->areq->assoclen; -+ scatterwalk_copychunks(NULL, &cryp->out_walk, -+ cryp->areq->assoclen, 2); - } - -+ if (is_ctr(cryp)) -+ memset(cryp->last_ctr, 0, sizeof(cryp->last_ctr)); -+ - ret = stm32_cryp_hw_init(cryp); - return ret; - } -@@ -1061,8 +1125,7 @@ static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq) - if (!cryp) - return -ENODEV; - -- if (unlikely(!cryp->areq->assoclen && -- !stm32_cryp_get_input_text_len(cryp))) { -+ if (unlikely(!cryp->payload_in && !cryp->header_in)) { - /* No input data to process: get tag and finish */ - stm32_cryp_finish_req(cryp, 0); - return 0; -@@ -1071,43 +1134,10 @@ static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq) - return stm32_cryp_cpu_start(cryp); - } - --static u32 *stm32_cryp_next_out(struct stm32_cryp *cryp, u32 *dst, -- unsigned int n) --{ -- scatterwalk_advance(&cryp->out_walk, n); -- -- if (unlikely(cryp->out_sg->length == _walked_out)) { -- cryp->out_sg = sg_next(cryp->out_sg); -- if (cryp->out_sg) { -- scatterwalk_start(&cryp->out_walk, cryp->out_sg); -- return (sg_virt(cryp->out_sg) + _walked_out); -- } -- } -- -- return (u32 *)((u8 *)dst + n); --} -- --static u32 *stm32_cryp_next_in(struct stm32_cryp *cryp, u32 *src, -- unsigned int n) --{ -- scatterwalk_advance(&cryp->in_walk, n); -- -- if (unlikely(cryp->in_sg->length == _walked_in)) { -- cryp->in_sg = sg_next(cryp->in_sg); -- if (cryp->in_sg) { -- scatterwalk_start(&cryp->in_walk, cryp->in_sg); -- return (sg_virt(cryp->in_sg) + _walked_in); -- } -- } -- -- return (u32 *)((u8 *)src + n); --} -- - static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - { -- u32 cfg, size_bit, *dst, d32; -- u8 *d8; -- unsigned int i, j; -+ u32 cfg, size_bit; -+ unsigned int i; - int ret = 0; - - /* Update Config */ -@@ -1130,7 +1160,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_DIN, size_bit); - - size_bit = is_encrypt(cryp) ? cryp->areq->cryptlen : -- cryp->areq->cryptlen - AES_BLOCK_SIZE; -+ cryp->areq->cryptlen - cryp->authsize; - size_bit *= 8; - if (cryp->caps->swap_final) - size_bit = (__force u32)cpu_to_be32(size_bit); -@@ -1139,11 +1169,9 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_DIN, size_bit); - } else { - /* CCM: write CTR0 */ -- u8 iv[AES_BLOCK_SIZE]; -- u32 *iv32 = (u32 *)iv; -- __be32 *biv; -- -- biv = (void *)iv; -+ u32 iv32[AES_BLOCK_32]; -+ u8 *iv = (u8 *)iv32; -+ __be32 *biv = (__be32 *)iv32; - - memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE); - memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1); -@@ -1165,39 +1193,18 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - } - - if (is_encrypt(cryp)) { -+ u32 out_tag[AES_BLOCK_32]; -+ - /* Get and write tag */ -- dst = sg_virt(cryp->out_sg) + _walked_out; -+ for (i = 0; i < AES_BLOCK_32; i++) -+ out_tag[i] = stm32_cryp_read(cryp, CRYP_DOUT); - -- for (i = 0; i < AES_BLOCK_32; i++) { -- if (cryp->total_out >= sizeof(u32)) { -- /* Read a full u32 */ -- *dst = stm32_cryp_read(cryp, CRYP_DOUT); -- -- dst = stm32_cryp_next_out(cryp, dst, -- sizeof(u32)); -- cryp->total_out -= sizeof(u32); -- } else if (!cryp->total_out) { -- /* Empty fifo out (data from input padding) */ -- stm32_cryp_read(cryp, CRYP_DOUT); -- } else { -- /* Read less than an u32 */ -- d32 = stm32_cryp_read(cryp, CRYP_DOUT); -- d8 = (u8 *)&d32; -- -- for (j = 0; j < cryp->total_out; j++) { -- *((u8 *)dst) = *(d8++); -- dst = stm32_cryp_next_out(cryp, dst, 1); -- } -- cryp->total_out = 0; -- } -- } -+ scatterwalk_copychunks(out_tag, &cryp->out_walk, cryp->authsize, 1); - } else { - /* Get and check tag */ - u32 in_tag[AES_BLOCK_32], out_tag[AES_BLOCK_32]; - -- scatterwalk_map_and_copy(in_tag, cryp->in_sg, -- cryp->total_in_save - cryp->authsize, -- cryp->authsize, 0); -+ scatterwalk_copychunks(in_tag, &cryp->in_walk, cryp->authsize, 0); - - for (i = 0; i < AES_BLOCK_32; i++) - out_tag[i] = stm32_cryp_read(cryp, CRYP_DOUT); -@@ -1219,113 +1226,63 @@ static void stm32_cryp_check_ctr_counter(struct stm32_cryp *cryp) - - if (unlikely(cryp->last_ctr[3] == 0xFFFFFFFF)) { - cryp->last_ctr[3] = 0; -- cryp->last_ctr[2]++; -+ cryp->last_ctr[2] = cpu_to_be32(be32_to_cpu(cryp->last_ctr[2]) + 1); - if (!cryp->last_ctr[2]) { -- cryp->last_ctr[1]++; -+ cryp->last_ctr[1] = cpu_to_be32(be32_to_cpu(cryp->last_ctr[1]) + 1); - if (!cryp->last_ctr[1]) -- cryp->last_ctr[0]++; -+ cryp->last_ctr[0] = cpu_to_be32(be32_to_cpu(cryp->last_ctr[0]) + 1); - } - - cr = stm32_cryp_read(cryp, CRYP_CR); - stm32_cryp_write(cryp, CRYP_CR, cr & ~CR_CRYPEN); - -- stm32_cryp_hw_write_iv(cryp, (u32 *)cryp->last_ctr); -+ stm32_cryp_hw_write_iv(cryp, cryp->last_ctr); - - stm32_cryp_write(cryp, CRYP_CR, cr); - } - -- cryp->last_ctr[0] = stm32_cryp_read(cryp, CRYP_IV0LR); -- cryp->last_ctr[1] = stm32_cryp_read(cryp, CRYP_IV0RR); -- cryp->last_ctr[2] = stm32_cryp_read(cryp, CRYP_IV1LR); -- cryp->last_ctr[3] = stm32_cryp_read(cryp, CRYP_IV1RR); -+ /* The IV registers are BE */ -+ cryp->last_ctr[0] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV0LR)); -+ cryp->last_ctr[1] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV0RR)); -+ cryp->last_ctr[2] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV1LR)); -+ cryp->last_ctr[3] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV1RR)); - } - --static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp) -+static void stm32_cryp_irq_read_data(struct stm32_cryp *cryp) - { -- unsigned int i, j; -- u32 d32, *dst; -- u8 *d8; -- size_t tag_size; -- -- /* Do no read tag now (if any) */ -- if (is_encrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp))) -- tag_size = cryp->authsize; -- else -- tag_size = 0; -- -- dst = sg_virt(cryp->out_sg) + _walked_out; -- -- for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { -- if (likely(cryp->total_out - tag_size >= sizeof(u32))) { -- /* Read a full u32 */ -- *dst = stm32_cryp_read(cryp, CRYP_DOUT); -+ unsigned int i; -+ u32 block[AES_BLOCK_32]; - -- dst = stm32_cryp_next_out(cryp, dst, sizeof(u32)); -- cryp->total_out -= sizeof(u32); -- } else if (cryp->total_out == tag_size) { -- /* Empty fifo out (data from input padding) */ -- d32 = stm32_cryp_read(cryp, CRYP_DOUT); -- } else { -- /* Read less than an u32 */ -- d32 = stm32_cryp_read(cryp, CRYP_DOUT); -- d8 = (u8 *)&d32; -- -- for (j = 0; j < cryp->total_out - tag_size; j++) { -- *((u8 *)dst) = *(d8++); -- dst = stm32_cryp_next_out(cryp, dst, 1); -- } -- cryp->total_out = tag_size; -- } -- } -+ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) -+ block[i] = stm32_cryp_read(cryp, CRYP_DOUT); - -- return !(cryp->total_out - tag_size) || !cryp->total_in; -+ scatterwalk_copychunks(block, &cryp->out_walk, min_t(size_t, -+ cryp->hw_blocksize, -+ cryp->payload_out), -+ 1); -+ cryp->payload_out -= min_t(size_t, cryp->hw_blocksize, -+ cryp->payload_out); - } - - static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp) - { -- unsigned int i, j; -- u32 *src; -- u8 d8[4]; -- size_t tag_size; -- -- /* Do no write tag (if any) */ -- if (is_decrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp))) -- tag_size = cryp->authsize; -- else -- tag_size = 0; -- -- src = sg_virt(cryp->in_sg) + _walked_in; -+ unsigned int i; -+ u32 block[AES_BLOCK_32] = {0}; - -- for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { -- if (likely(cryp->total_in - tag_size >= sizeof(u32))) { -- /* Write a full u32 */ -- stm32_cryp_write(cryp, CRYP_DIN, *src); -+ scatterwalk_copychunks(block, &cryp->in_walk, min_t(size_t, -+ cryp->hw_blocksize, -+ cryp->payload_in), -+ 0); -+ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) -+ stm32_cryp_write(cryp, CRYP_DIN, block[i]); - -- src = stm32_cryp_next_in(cryp, src, sizeof(u32)); -- cryp->total_in -= sizeof(u32); -- } else if (cryp->total_in == tag_size) { -- /* Write padding data */ -- stm32_cryp_write(cryp, CRYP_DIN, 0); -- } else { -- /* Write less than an u32 */ -- memset(d8, 0, sizeof(u32)); -- for (j = 0; j < cryp->total_in - tag_size; j++) { -- d8[j] = *((u8 *)src); -- src = stm32_cryp_next_in(cryp, src, 1); -- } -- -- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); -- cryp->total_in = tag_size; -- } -- } -+ cryp->payload_in -= min_t(size_t, cryp->hw_blocksize, cryp->payload_in); - } - - static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - { - int err; -- u32 cfg, tmp[AES_BLOCK_32]; -- size_t total_in_ori = cryp->total_in; -- struct scatterlist *out_sg_ori = cryp->out_sg; -+ u32 cfg, block[AES_BLOCK_32] = {0}; - unsigned int i; - - /* 'Special workaround' procedure described in the datasheet */ -@@ -1350,18 +1307,27 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - - /* b) pad and write the last block */ - stm32_cryp_irq_write_block(cryp); -- cryp->total_in = total_in_ori; -+ /* wait end of process */ - err = stm32_cryp_wait_output(cryp); - if (err) { -- dev_err(cryp->dev, "Timeout (write gcm header)\n"); -+ dev_err(cryp->dev, "Timeout (write gcm last data)\n"); - return stm32_cryp_finish_req(cryp, err); - } - - /* c) get and store encrypted data */ -- stm32_cryp_irq_read_data(cryp); -- scatterwalk_map_and_copy(tmp, out_sg_ori, -- cryp->total_in_save - total_in_ori, -- total_in_ori, 0); -+ /* -+ * Same code as stm32_cryp_irq_read_data(), but we want to store -+ * block value -+ */ -+ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) -+ block[i] = stm32_cryp_read(cryp, CRYP_DOUT); -+ -+ scatterwalk_copychunks(block, &cryp->out_walk, min_t(size_t, -+ cryp->hw_blocksize, -+ cryp->payload_out), -+ 1); -+ cryp->payload_out -= min_t(size_t, cryp->hw_blocksize, -+ cryp->payload_out); - - /* d) change mode back to AES GCM */ - cfg &= ~CR_ALGO_MASK; -@@ -1374,19 +1340,13 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_CR, cfg); - - /* f) write padded data */ -- for (i = 0; i < AES_BLOCK_32; i++) { -- if (cryp->total_in) -- stm32_cryp_write(cryp, CRYP_DIN, tmp[i]); -- else -- stm32_cryp_write(cryp, CRYP_DIN, 0); -- -- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); -- } -+ for (i = 0; i < AES_BLOCK_32; i++) -+ stm32_cryp_write(cryp, CRYP_DIN, block[i]); - - /* g) Empty fifo out */ - err = stm32_cryp_wait_output(cryp); - if (err) { -- dev_err(cryp->dev, "Timeout (write gcm header)\n"); -+ dev_err(cryp->dev, "Timeout (write gcm padded data)\n"); - return stm32_cryp_finish_req(cryp, err); - } - -@@ -1399,16 +1359,14 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - - static void stm32_cryp_irq_set_npblb(struct stm32_cryp *cryp) - { -- u32 cfg, payload_bytes; -+ u32 cfg; - - /* disable ip, set NPBLB and reneable ip */ - cfg = stm32_cryp_read(cryp, CRYP_CR); - cfg &= ~CR_CRYPEN; - stm32_cryp_write(cryp, CRYP_CR, cfg); - -- payload_bytes = is_decrypt(cryp) ? cryp->total_in - cryp->authsize : -- cryp->total_in; -- cfg |= (cryp->hw_blocksize - payload_bytes) << CR_NBPBL_SHIFT; -+ cfg |= (cryp->hw_blocksize - cryp->payload_in) << CR_NBPBL_SHIFT; - cfg |= CR_CRYPEN; - stm32_cryp_write(cryp, CRYP_CR, cfg); - } -@@ -1417,13 +1375,11 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - { - int err = 0; - u32 cfg, iv1tmp; -- u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32], tmp[AES_BLOCK_32]; -- size_t last_total_out, total_in_ori = cryp->total_in; -- struct scatterlist *out_sg_ori = cryp->out_sg; -+ u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32]; -+ u32 block[AES_BLOCK_32] = {0}; - unsigned int i; - - /* 'Special workaround' procedure described in the datasheet */ -- cryp->flags |= FLG_CCM_PADDED_WA; - - /* a) disable ip */ - stm32_cryp_write(cryp, CRYP_IMSCR, 0); -@@ -1453,7 +1409,7 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - - /* b) pad and write the last block */ - stm32_cryp_irq_write_block(cryp); -- cryp->total_in = total_in_ori; -+ /* wait end of process */ - err = stm32_cryp_wait_output(cryp); - if (err) { - dev_err(cryp->dev, "Timeout (wite ccm padded data)\n"); -@@ -1461,13 +1417,19 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - } - - /* c) get and store decrypted data */ -- last_total_out = cryp->total_out; -- stm32_cryp_irq_read_data(cryp); -- -- memset(tmp, 0, sizeof(tmp)); -- scatterwalk_map_and_copy(tmp, out_sg_ori, -- cryp->total_out_save - last_total_out, -- last_total_out, 0); -+ /* -+ * Same code as stm32_cryp_irq_read_data(), but we want to store -+ * block value -+ */ -+ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) -+ block[i] = stm32_cryp_read(cryp, CRYP_DOUT); -+ -+ scatterwalk_copychunks(block, &cryp->out_walk, min_t(size_t, -+ cryp->hw_blocksize, -+ cryp->payload_out), -+ 1); -+ cryp->payload_out -= min_t(size_t, cryp->hw_blocksize, -+ cryp->payload_out); - - /* d) Load again CRYP_CSGCMCCMxR */ - for (i = 0; i < ARRAY_SIZE(cstmp2); i++) -@@ -1484,10 +1446,10 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_CR, cfg); - - /* g) XOR and write padded data */ -- for (i = 0; i < ARRAY_SIZE(tmp); i++) { -- tmp[i] ^= cstmp1[i]; -- tmp[i] ^= cstmp2[i]; -- stm32_cryp_write(cryp, CRYP_DIN, tmp[i]); -+ for (i = 0; i < ARRAY_SIZE(block); i++) { -+ block[i] ^= cstmp1[i]; -+ block[i] ^= cstmp2[i]; -+ stm32_cryp_write(cryp, CRYP_DIN, block[i]); - } - - /* h) wait for completion */ -@@ -1501,30 +1463,34 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - - static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) - { -- if (unlikely(!cryp->total_in)) { -+ if (unlikely(!cryp->payload_in)) { - dev_warn(cryp->dev, "No more data to process\n"); - return; - } - -- if (unlikely(cryp->total_in < AES_BLOCK_SIZE && -+ if (unlikely(cryp->payload_in < AES_BLOCK_SIZE && - (stm32_cryp_get_hw_mode(cryp) == CR_AES_GCM) && - is_encrypt(cryp))) { - /* Padding for AES GCM encryption */ -- if (cryp->caps->padding_wa) -+ if (cryp->caps->padding_wa) { - /* Special case 1 */ -- return stm32_cryp_irq_write_gcm_padded_data(cryp); -+ stm32_cryp_irq_write_gcm_padded_data(cryp); -+ return; -+ } - - /* Setting padding bytes (NBBLB) */ - stm32_cryp_irq_set_npblb(cryp); - } - -- if (unlikely((cryp->total_in - cryp->authsize < AES_BLOCK_SIZE) && -+ if (unlikely((cryp->payload_in < AES_BLOCK_SIZE) && - (stm32_cryp_get_hw_mode(cryp) == CR_AES_CCM) && - is_decrypt(cryp))) { - /* Padding for AES CCM decryption */ -- if (cryp->caps->padding_wa) -+ if (cryp->caps->padding_wa) { - /* Special case 2 */ -- return stm32_cryp_irq_write_ccm_padded_data(cryp); -+ stm32_cryp_irq_write_ccm_padded_data(cryp); -+ return; -+ } - - /* Setting padding bytes (NBBLB) */ - stm32_cryp_irq_set_npblb(cryp); -@@ -1536,192 +1502,61 @@ static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) - stm32_cryp_irq_write_block(cryp); - } - --static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp) -+static void stm32_cryp_irq_write_gcmccm_header(struct stm32_cryp *cryp) - { -- int err; -- unsigned int i, j; -- u32 cfg, *src; -- -- src = sg_virt(cryp->in_sg) + _walked_in; -- -- for (i = 0; i < AES_BLOCK_32; i++) { -- stm32_cryp_write(cryp, CRYP_DIN, *src); -- -- src = stm32_cryp_next_in(cryp, src, sizeof(u32)); -- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); -- -- /* Check if whole header written */ -- if ((cryp->total_in_save - cryp->total_in) == -- cryp->areq->assoclen) { -- /* Write padding if needed */ -- for (j = i + 1; j < AES_BLOCK_32; j++) -- stm32_cryp_write(cryp, CRYP_DIN, 0); -- -- /* Wait for completion */ -- err = stm32_cryp_wait_busy(cryp); -- if (err) { -- dev_err(cryp->dev, "Timeout (gcm header)\n"); -- return stm32_cryp_finish_req(cryp, err); -- } -- -- if (stm32_cryp_get_input_text_len(cryp)) { -- /* Phase 3 : payload */ -- cfg = stm32_cryp_read(cryp, CRYP_CR); -- cfg &= ~CR_CRYPEN; -- stm32_cryp_write(cryp, CRYP_CR, cfg); -- -- cfg &= ~CR_PH_MASK; -- cfg |= CR_PH_PAYLOAD; -- cfg |= CR_CRYPEN; -- stm32_cryp_write(cryp, CRYP_CR, cfg); -- } else { -- /* Phase 4 : tag */ -- stm32_cryp_write(cryp, CRYP_IMSCR, 0); -- stm32_cryp_finish_req(cryp, 0); -- } -- -- break; -- } -- -- if (!cryp->total_in) -- break; -- } --} -+ unsigned int i; -+ u32 block[AES_BLOCK_32] = {0}; -+ size_t written; - --static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) --{ -- int err; -- unsigned int i = 0, j, k; -- u32 alen, cfg, *src; -- u8 d8[4]; -- -- src = sg_virt(cryp->in_sg) + _walked_in; -- alen = cryp->areq->assoclen; -- -- if (!_walked_in) { -- if (cryp->areq->assoclen <= 65280) { -- /* Write first u32 of B1 */ -- d8[0] = (alen >> 8) & 0xFF; -- d8[1] = alen & 0xFF; -- d8[2] = *((u8 *)src); -- src = stm32_cryp_next_in(cryp, src, 1); -- d8[3] = *((u8 *)src); -- src = stm32_cryp_next_in(cryp, src, 1); -- -- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); -- i++; -- -- cryp->total_in -= min_t(size_t, 2, cryp->total_in); -- } else { -- /* Build the two first u32 of B1 */ -- d8[0] = 0xFF; -- d8[1] = 0xFE; -- d8[2] = alen & 0xFF000000; -- d8[3] = alen & 0x00FF0000; -- -- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); -- i++; -- -- d8[0] = alen & 0x0000FF00; -- d8[1] = alen & 0x000000FF; -- d8[2] = *((u8 *)src); -- src = stm32_cryp_next_in(cryp, src, 1); -- d8[3] = *((u8 *)src); -- src = stm32_cryp_next_in(cryp, src, 1); -- -- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); -- i++; -- -- cryp->total_in -= min_t(size_t, 2, cryp->total_in); -- } -- } -+ written = min_t(size_t, AES_BLOCK_SIZE, cryp->header_in); - -- /* Write next u32 */ -- for (; i < AES_BLOCK_32; i++) { -- /* Build an u32 */ -- memset(d8, 0, sizeof(u32)); -- for (k = 0; k < sizeof(u32); k++) { -- d8[k] = *((u8 *)src); -- src = stm32_cryp_next_in(cryp, src, 1); -- -- cryp->total_in -= min_t(size_t, 1, cryp->total_in); -- if ((cryp->total_in_save - cryp->total_in) == alen) -- break; -- } -+ scatterwalk_copychunks(block, &cryp->in_walk, written, 0); -+ for (i = 0; i < AES_BLOCK_32; i++) -+ stm32_cryp_write(cryp, CRYP_DIN, block[i]); - -- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); -- -- if ((cryp->total_in_save - cryp->total_in) == alen) { -- /* Write padding if needed */ -- for (j = i + 1; j < AES_BLOCK_32; j++) -- stm32_cryp_write(cryp, CRYP_DIN, 0); -- -- /* Wait for completion */ -- err = stm32_cryp_wait_busy(cryp); -- if (err) { -- dev_err(cryp->dev, "Timeout (ccm header)\n"); -- return stm32_cryp_finish_req(cryp, err); -- } -- -- if (stm32_cryp_get_input_text_len(cryp)) { -- /* Phase 3 : payload */ -- cfg = stm32_cryp_read(cryp, CRYP_CR); -- cfg &= ~CR_CRYPEN; -- stm32_cryp_write(cryp, CRYP_CR, cfg); -- -- cfg &= ~CR_PH_MASK; -- cfg |= CR_PH_PAYLOAD; -- cfg |= CR_CRYPEN; -- stm32_cryp_write(cryp, CRYP_CR, cfg); -- } else { -- /* Phase 4 : tag */ -- stm32_cryp_write(cryp, CRYP_IMSCR, 0); -- stm32_cryp_finish_req(cryp, 0); -- } -+ cryp->header_in -= written; - -- break; -- } -- } -+ stm32_crypt_gcmccm_end_header(cryp); - } - - static irqreturn_t stm32_cryp_irq_thread(int irq, void *arg) - { - struct stm32_cryp *cryp = arg; - u32 ph; -+ u32 it_mask = stm32_cryp_read(cryp, CRYP_IMSCR); -+ - - if (cryp->irq_status & MISR_OUT) - /* Output FIFO IRQ: read data */ -- if (unlikely(stm32_cryp_irq_read_data(cryp))) { -- /* All bytes processed, finish */ -- stm32_cryp_write(cryp, CRYP_IMSCR, 0); -- stm32_cryp_finish_req(cryp, 0); -- return IRQ_HANDLED; -- } -+ stm32_cryp_irq_read_data(cryp); - - if (cryp->irq_status & MISR_IN) { -- if (is_gcm(cryp)) { -- ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK; -- if (unlikely(ph == CR_PH_HEADER)) -- /* Write Header */ -- stm32_cryp_irq_write_gcm_header(cryp); -- else -- /* Input FIFO IRQ: write data */ -- stm32_cryp_irq_write_data(cryp); -- cryp->gcm_ctr++; -- } else if (is_ccm(cryp)) { -+ if (is_gcm(cryp) || is_ccm(cryp)) { - ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK; - if (unlikely(ph == CR_PH_HEADER)) - /* Write Header */ -- stm32_cryp_irq_write_ccm_header(cryp); -+ stm32_cryp_irq_write_gcmccm_header(cryp); - else - /* Input FIFO IRQ: write data */ - stm32_cryp_irq_write_data(cryp); -+ if (is_gcm(cryp)) -+ cryp->gcm_ctr++; - } else { - /* Input FIFO IRQ: write data */ - stm32_cryp_irq_write_data(cryp); - } - } - -+ /* Mask useless interrupts */ -+ if (!cryp->payload_in && !cryp->header_in) -+ it_mask &= ~IMSCR_IN; -+ if (!cryp->payload_out) -+ it_mask &= ~IMSCR_OUT; -+ stm32_cryp_write(cryp, CRYP_IMSCR, it_mask); -+ -+ if (!cryp->payload_in && !cryp->header_in && !cryp->payload_out) -+ stm32_cryp_finish_req(cryp, 0); -+ - return IRQ_HANDLED; - } - -@@ -1742,7 +1577,7 @@ static struct skcipher_alg crypto_algs[] = { - .base.cra_flags = CRYPTO_ALG_ASYNC, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .base.cra_alignmask = 0xf, -+ .base.cra_alignmask = 0, - .base.cra_module = THIS_MODULE, - - .init = stm32_cryp_init_tfm, -@@ -1759,7 +1594,7 @@ static struct skcipher_alg crypto_algs[] = { - .base.cra_flags = CRYPTO_ALG_ASYNC, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .base.cra_alignmask = 0xf, -+ .base.cra_alignmask = 0, - .base.cra_module = THIS_MODULE, - - .init = stm32_cryp_init_tfm, -@@ -1777,7 +1612,7 @@ static struct skcipher_alg crypto_algs[] = { - .base.cra_flags = CRYPTO_ALG_ASYNC, - .base.cra_blocksize = 1, - .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .base.cra_alignmask = 0xf, -+ .base.cra_alignmask = 0, - .base.cra_module = THIS_MODULE, - - .init = stm32_cryp_init_tfm, -@@ -1795,7 +1630,7 @@ static struct skcipher_alg crypto_algs[] = { - .base.cra_flags = CRYPTO_ALG_ASYNC, - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .base.cra_alignmask = 0xf, -+ .base.cra_alignmask = 0, - .base.cra_module = THIS_MODULE, - - .init = stm32_cryp_init_tfm, -@@ -1812,7 +1647,7 @@ static struct skcipher_alg crypto_algs[] = { - .base.cra_flags = CRYPTO_ALG_ASYNC, - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .base.cra_alignmask = 0xf, -+ .base.cra_alignmask = 0, - .base.cra_module = THIS_MODULE, - - .init = stm32_cryp_init_tfm, -@@ -1830,7 +1665,7 @@ static struct skcipher_alg crypto_algs[] = { - .base.cra_flags = CRYPTO_ALG_ASYNC, - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .base.cra_alignmask = 0xf, -+ .base.cra_alignmask = 0, - .base.cra_module = THIS_MODULE, - - .init = stm32_cryp_init_tfm, -@@ -1847,7 +1682,7 @@ static struct skcipher_alg crypto_algs[] = { - .base.cra_flags = CRYPTO_ALG_ASYNC, - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .base.cra_alignmask = 0xf, -+ .base.cra_alignmask = 0, - .base.cra_module = THIS_MODULE, - - .init = stm32_cryp_init_tfm, -@@ -1877,7 +1712,7 @@ static struct aead_alg aead_algs[] = { - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .cra_alignmask = 0xf, -+ .cra_alignmask = 0, - .cra_module = THIS_MODULE, - }, - }, -@@ -1897,7 +1732,7 @@ static struct aead_alg aead_algs[] = { - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct stm32_cryp_ctx), -- .cra_alignmask = 0xf, -+ .cra_alignmask = 0, - .cra_module = THIS_MODULE, - }, - }, -@@ -1955,7 +1790,9 @@ static int stm32_cryp_probe(struct platform_device *pdev) - - cryp->clk = devm_clk_get(dev, NULL); - if (IS_ERR(cryp->clk)) { -- dev_err(dev, "Could not get clock\n"); -+ if (PTR_ERR(cryp->clk) != -EPROBE_DEFER) -+ dev_err(dev, "Could not get clock\n"); -+ - return PTR_ERR(cryp->clk); - } - -@@ -1973,7 +1810,11 @@ static int stm32_cryp_probe(struct platform_device *pdev) - pm_runtime_enable(dev); - - rst = devm_reset_control_get(dev, NULL); -- if (!IS_ERR(rst)) { -+ if (IS_ERR(rst)) { -+ ret = PTR_ERR(rst); -+ if (ret == -EPROBE_DEFER) -+ goto err_rst; -+ } else { - reset_control_assert(rst); - udelay(2); - reset_control_deassert(rst); -@@ -2024,9 +1865,7 @@ static int stm32_cryp_probe(struct platform_device *pdev) - spin_lock(&cryp_list.lock); - list_del(&cryp->list); - spin_unlock(&cryp_list.lock); -- -- pm_runtime_disable(dev); -- pm_runtime_put_noidle(dev); -+err_rst: - pm_runtime_disable(dev); - pm_runtime_put_noidle(dev); - -diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c -index ff5362da1..19b3d8518 100644 ---- a/drivers/crypto/stm32/stm32-hash.c -+++ b/drivers/crypto/stm32/stm32-hash.c -@@ -925,15 +925,10 @@ static int stm32_hash_final(struct ahash_request *req) - static int stm32_hash_finup(struct ahash_request *req) - { - struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); -- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); -- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); - int err1, err2; - - rctx->flags |= HASH_FLAGS_FINUP; - -- if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) -- rctx->flags &= ~HASH_FLAGS_CPU; -- - err1 = stm32_hash_update(req); - - if (err1 == -EINPROGRESS || err1 == -EBUSY) -@@ -950,7 +945,19 @@ static int stm32_hash_finup(struct ahash_request *req) - - static int stm32_hash_digest(struct ahash_request *req) - { -- return stm32_hash_init(req) ?: stm32_hash_finup(req); -+ int ret; -+ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); -+ struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); -+ struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); -+ -+ ret = stm32_hash_init(req); -+ if (ret) -+ return ret; -+ -+ if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) -+ rctx->flags &= ~HASH_FLAGS_CPU; -+ -+ return stm32_hash_finup(req); - } - - static int stm32_hash_export(struct ahash_request *req, void *out) --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0006-ARM-5.10.61-stm32mp1-r2-DRM.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0006-ARM-5.10.61-stm32mp1-r2-DRM.patch deleted file mode 100644 index ca683bc..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0006-ARM-5.10.61-stm32mp1-r2-DRM.patch +++ /dev/null @@ -1,1468 +0,0 @@ -From 6d9c0eb22dc7c3fbe05bbb000a5d35d0fd1168ab Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:43 +0200 -Subject: [PATCH 06/23] ARM 5.10.61-stm32mp1-r2 DRM - ---- - drivers/gpu/drm/bridge/sii902x.c | 100 +++++++++- - drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 172 ++++++++++++++---- - drivers/gpu/drm/drm_atomic_state_helper.c | 1 + - drivers/gpu/drm/drm_atomic_uapi.c | 4 + - drivers/gpu/drm/drm_blend.c | 34 +++- - drivers/gpu/drm/drm_mode_config.c | 6 + - drivers/gpu/drm/drm_modes.c | 19 +- - .../gpu/drm/panel/panel-orisetech-otm8009a.c | 119 +++++++----- - drivers/gpu/drm/panel/panel-raydium-rm68200.c | 21 ++- - drivers/gpu/drm/stm/drv.c | 5 + - drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 20 +- - drivers/gpu/drm/stm/ltdc.c | 169 +++++++++++------ - drivers/input/touchscreen/edt-ft5x06.c | 18 +- - drivers/input/touchscreen/goodix.c | 15 ++ - include/drm/drm_blend.h | 1 + - include/drm/drm_crtc.h | 12 ++ - include/drm/drm_mode_config.h | 5 + - include/uapi/drm/drm_mode.h | 34 ++++ - 18 files changed, 591 insertions(+), 164 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c -index 89558e581..69208ead5 100644 ---- a/drivers/gpu/drm/bridge/sii902x.c -+++ b/drivers/gpu/drm/bridge/sii902x.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -162,6 +163,11 @@ - - #define SII902X_AUDIO_PORT_INDEX 3 - -+/* CEC device */ -+#define SII902X_CEC_I2C_ADDR 0x30 -+ -+#define SII902X_CEC_SETUP 0x8e -+ - struct sii902x { - struct i2c_client *i2c; - struct regmap *regmap; -@@ -170,6 +176,7 @@ struct sii902x { - struct gpio_desc *reset_gpio; - struct i2c_mux_core *i2cmux; - struct regulator_bulk_data supplies[2]; -+ struct edid *edid; - /* - * Mutex protects audio and video functions from interfering - * each other, by keeping their i2c command sequences atomic. -@@ -280,6 +287,8 @@ static int sii902x_get_modes(struct drm_connector *connector) - - mutex_lock(&sii902x->mutex); - -+ kfree(sii902x->edid); -+ sii902x->edid = NULL; - edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); - drm_connector_update_edid_property(connector, edid); - if (edid) { -@@ -287,7 +296,7 @@ static int sii902x_get_modes(struct drm_connector *connector) - output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; - - num = drm_add_edid_modes(connector, edid); -- kfree(edid); -+ sii902x->edid = edid; - } - - ret = drm_display_info_set_bus_formats(&connector->display_info, -@@ -337,6 +346,7 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) - static void sii902x_bridge_enable(struct drm_bridge *bridge) - { - struct sii902x *sii902x = bridge_to_sii902x(bridge); -+ u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; - - mutex_lock(&sii902x->mutex); - -@@ -346,6 +356,14 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge) - regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, - SII902X_SYS_CTRL_PWR_DWN, 0); - -+ if (sii902x->edid) { -+ if (drm_detect_hdmi_monitor(sii902x->edid)) -+ output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; -+ } -+ -+ regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, -+ SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); -+ - mutex_unlock(&sii902x->mutex); - } - -@@ -960,6 +978,13 @@ static int sii902x_init(struct sii902x *sii902x) - { - struct device *dev = &sii902x->i2c->dev; - unsigned int status = 0; -+ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; -+ struct i2c_msg msg = { -+ .addr = SII902X_CEC_I2C_ADDR << 1, -+ .flags = 0, -+ .len = 2, -+ .buf = data, -+ }; - u8 chipid[4]; - int ret; - -@@ -982,13 +1007,22 @@ static int sii902x_init(struct sii902x *sii902x) - return -EINVAL; - } - -+ /* -+ * By default, CEC must be disabled to allow other CEC devives -+ * to bypass the bridge. -+ */ -+ ret = i2c_transfer(sii902x->i2c->adapter, &msg, 1); -+ if (ret < 0) -+ dev_warn(&sii902x->i2c->dev, "Failed to disable CEC device!\n"); -+ - /* Clear all pending interrupts */ - regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); - regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); - - if (sii902x->i2c->irq > 0) { -- regmap_write(sii902x->regmap, SII902X_INT_ENABLE, -- SII902X_HOTPLUG_EVENT); -+ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, -+ SII902X_HOTPLUG_EVENT, -+ SII902X_HOTPLUG_EVENT); - - ret = devm_request_threaded_irq(dev, sii902x->i2c->irq, NULL, - sii902x_interrupt, -@@ -1087,6 +1121,65 @@ static int sii902x_remove(struct i2c_client *client) - return 0; - } - -+static int sii902x_pm_suspend(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sii902x *sii902x = i2c_get_clientdata(client); -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ if (sii902x->reset_gpio) -+ gpiod_set_value(sii902x->reset_gpio, 1); -+ -+ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ -+ return 0; -+} -+ -+static int sii902x_pm_resume(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sii902x *sii902x = i2c_get_clientdata(client); -+ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; -+ struct i2c_msg msg = { -+ .addr = SII902X_CEC_I2C_ADDR << 1, -+ .flags = 0, -+ .len = 2, -+ .buf = data, -+ }; -+ int ret; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ if (ret) { -+ DRM_ERROR("regulator_bulk_enable failed\n"); -+ return ret; -+ } -+ -+ if (sii902x->reset_gpio) -+ gpiod_set_value(sii902x->reset_gpio, 0); -+ -+ regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x00); -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ if (ret < 0) -+ DRM_ERROR("Failed to disable CEC device!\n"); -+ -+ if (client->irq > 0) -+ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, -+ SII902X_HOTPLUG_EVENT, -+ SII902X_HOTPLUG_EVENT); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops sii902x_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(sii902x_pm_suspend, sii902x_pm_resume) -+}; -+ - static const struct of_device_id sii902x_dt_ids[] = { - { .compatible = "sil,sii9022", }, - { } -@@ -1105,6 +1198,7 @@ static struct i2c_driver sii902x_driver = { - .driver = { - .name = "sii902x", - .of_match_table = sii902x_dt_ids, -+ .pm = &sii902x_pm_ops, - }, - .id_table = sii902x_i2c_ids, - }; -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -index 6b268f944..25b634911 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -@@ -213,6 +213,20 @@ - - #define DSI_INT_ST0 0xbc - #define DSI_INT_ST1 0xc0 -+#define GPRXE BIT(12) -+#define GPRDE BIT(11) -+#define GPTXE BIT(10) -+#define GPWRE BIT(9) -+#define GCWRE BIT(8) -+#define DPIPLDWE BIT(7) -+#define EOTPE BIT(6) -+#define PSE BIT(5) -+#define CRCE BIT(4) -+#define ECCME BIT(3) -+#define ECCSE BIT(2) -+#define TOLPRX BIT(1) -+#define TOHSTX BIT(0) -+ - #define DSI_INT_MSK0 0xc4 - #define DSI_INT_MSK1 0xc8 - -@@ -314,9 +328,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, - { - struct dw_mipi_dsi *dsi = host_to_dsi(host); - const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; -- struct drm_bridge *bridge; -- struct drm_panel *panel; -- int ret; -+ int ret = -ENODEV; - - if (device->lanes > dsi->plat_data->max_data_lanes) { - dev_err(dsi->dev, "the number of data lanes(%u) is too many\n", -@@ -329,22 +341,6 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, - dsi->format = device->format; - dsi->mode_flags = device->mode_flags; - -- ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, -- &panel, &bridge); -- if (ret) -- return ret; -- -- if (panel) { -- bridge = drm_panel_bridge_add_typed(panel, -- DRM_MODE_CONNECTOR_DSI); -- if (IS_ERR(bridge)) -- return PTR_ERR(bridge); -- } -- -- dsi->panel_bridge = bridge; -- -- drm_bridge_add(&dsi->bridge); -- - if (pdata->host_ops && pdata->host_ops->attach) { - ret = pdata->host_ops->attach(pdata->priv_data, device); - if (ret < 0) -@@ -367,10 +363,6 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, - return ret; - } - -- drm_of_panel_bridge_remove(host->dev->of_node, 1, 0); -- -- drm_bridge_remove(&dsi->bridge); -- - return 0; - } - -@@ -431,6 +423,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) - return 0; - } - -+static int dw_mipi_dsi_read_status(struct dw_mipi_dsi *dsi) -+{ -+ u32 val; -+ -+ val = dsi_read(dsi, DSI_INT_ST1); -+ -+ if (val & GPRXE) -+ DRM_DEBUG_DRIVER("DSI Generic payload receive error\n"); -+ if (val & GPRDE) -+ DRM_DEBUG_DRIVER("DSI Generic payload read error\n"); -+ if (val & GPTXE) -+ DRM_DEBUG_DRIVER("DSI Generic payload transmit error\n"); -+ if (val & GPWRE) -+ DRM_DEBUG_DRIVER("DSI Generic payload write error\n"); -+ if (val & GCWRE) -+ DRM_DEBUG_DRIVER("DSI Generic command write error\n"); -+ if (val & DPIPLDWE) -+ DRM_DEBUG_DRIVER("DSI DPI payload write error\n"); -+ if (val & EOTPE) -+ DRM_DEBUG_DRIVER("DSI EoTp error\n"); -+ if (val & PSE) -+ DRM_DEBUG_DRIVER("DSI Packet size error\n"); -+ if (val & CRCE) -+ DRM_DEBUG_DRIVER("DSI CRC error\n"); -+ if (val & ECCME) -+ DRM_DEBUG_DRIVER("DSI ECC multi-bit error\n"); -+ if (val & ECCSE) -+ DRM_DEBUG_DRIVER("DSI ECC single-bit error\n"); -+ if (val & TOLPRX) -+ DRM_DEBUG_DRIVER("DSI Timeout low-power reception\n"); -+ if (val & TOHSTX) -+ DRM_DEBUG_DRIVER("DSI Timeout high-speed transmission\n"); -+ -+ return val; -+} -+ - static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, - const struct mipi_dsi_packet *packet) - { -@@ -460,6 +488,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, - "failed to get available write payload FIFO\n"); - return ret; - } -+ -+ val = dw_mipi_dsi_read_status(dsi); -+ if (val) { -+ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); -+ return -EINVAL; -+ } - } - - word = 0; -@@ -493,6 +527,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, - return ret; - } - -+ val = dw_mipi_dsi_read_status(dsi); -+ if (val) { -+ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); -+ return -EINVAL; -+ } -+ - val = dsi_read(dsi, DSI_GEN_PLD_DATA); - for (j = 0; j < 4 && j + i < len; j++) - buf[i + j] = val >> (8 * j); -@@ -507,6 +547,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, - struct dw_mipi_dsi *dsi = host_to_dsi(host); - struct mipi_dsi_packet packet; - int ret, nb_bytes; -+ int retry = 3; - - ret = mipi_dsi_create_packet(&packet, msg); - if (ret) { -@@ -518,24 +559,32 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, - if (dsi->slave) - dw_mipi_message_config(dsi->slave, msg); - -- ret = dw_mipi_dsi_write(dsi, &packet); -- if (ret) -- return ret; -- if (dsi->slave) { -- ret = dw_mipi_dsi_write(dsi->slave, &packet); -+ while (retry--) { -+ ret = dw_mipi_dsi_write(dsi, &packet); - if (ret) -- return ret; -- } -+ continue; - -- if (msg->rx_buf && msg->rx_len) { -- ret = dw_mipi_dsi_read(dsi, msg); -- if (ret) -- return ret; -- nb_bytes = msg->rx_len; -- } else { -- nb_bytes = packet.size; -+ if (dsi->slave) { -+ ret = dw_mipi_dsi_write(dsi->slave, &packet); -+ if (ret) -+ continue; -+ } -+ -+ if (msg->rx_buf && msg->rx_len) { -+ ret = dw_mipi_dsi_read(dsi, msg); -+ if (ret) -+ continue; -+ nb_bytes = msg->rx_len; -+ break; -+ } else { -+ nb_bytes = packet.size; -+ break; -+ } - } - -+ if (ret) -+ return ret; -+ - return nb_bytes; - } - -@@ -1105,6 +1154,9 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, - struct device *dev = &pdev->dev; - struct reset_control *apb_rst; - struct dw_mipi_dsi *dsi; -+ struct drm_bridge *bridge; -+ struct drm_panel *panel; -+ int i, nb_endpoints; - int ret; - - dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); -@@ -1172,8 +1224,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, - ret = mipi_dsi_host_register(&dsi->dsi_host); - if (ret) { - dev_err(dev, "Failed to register MIPI host: %d\n", ret); -- dw_mipi_dsi_debugfs_remove(dsi); -- return ERR_PTR(ret); -+ goto err_pmr_enable; - } - - dsi->bridge.driver_private = dsi; -@@ -1182,11 +1233,54 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, - dsi->bridge.of_node = pdev->dev.of_node; - #endif - -+ /* Get number of endpoints */ -+ nb_endpoints = of_graph_get_endpoint_count(pdev->dev.of_node); -+ if (!nb_endpoints) { -+ ret = -ENODEV; -+ goto err_host_reg; -+ } -+ -+ for (i = 1; i < nb_endpoints; i++) { -+ ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, i, 0, -+ &panel, &bridge); -+ if (!ret) -+ break; -+ else if (ret == -EPROBE_DEFER) -+ goto err_host_reg; -+ } -+ -+ /* check if an error is returned >> no panel or bridge detected */ -+ if (ret) -+ goto err_host_reg; -+ -+ if (panel) { -+ bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI); -+ if (IS_ERR(bridge)) { -+ ret = PTR_ERR(bridge); -+ goto err_host_reg; -+ } -+ } -+ -+ dsi->panel_bridge = bridge; -+ -+ drm_bridge_add(&dsi->bridge); -+ - return dsi; -+ -+err_host_reg: -+ mipi_dsi_host_unregister(&dsi->dsi_host); -+ -+err_pmr_enable: -+ pm_runtime_disable(dev); -+ dw_mipi_dsi_debugfs_remove(dsi); -+ -+ return ERR_PTR(ret); - } - - static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) - { -+ drm_bridge_remove(&dsi->bridge); -+ drm_panel_bridge_remove(dsi->panel_bridge); - mipi_dsi_host_unregister(&dsi->dsi_host); - - pm_runtime_disable(dsi->dev); -diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c -index 9ad740451..ae89e8134 100644 ---- a/drivers/gpu/drm/drm_atomic_state_helper.c -+++ b/drivers/gpu/drm/drm_atomic_state_helper.c -@@ -72,6 +72,7 @@ __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *crtc_state, - struct drm_crtc *crtc) - { - crtc_state->crtc = crtc; -+ crtc_state->bgcolor = drm_argb(16, 0xffff, 0, 0, 0); - } - EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset); - -diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c -index 25c269bc4..569f5d364 100644 ---- a/drivers/gpu/drm/drm_atomic_uapi.c -+++ b/drivers/gpu/drm/drm_atomic_uapi.c -@@ -469,6 +469,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, - return -EFAULT; - - set_out_fence_for_crtc(state->state, crtc, fence_ptr); -+ } else if (property == config->bgcolor_property) { -+ state->bgcolor = val; - } else if (crtc->funcs->atomic_set_property) { - return crtc->funcs->atomic_set_property(crtc, state, property, val); - } else { -@@ -503,6 +505,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, - *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; - else if (property == config->prop_out_fence_ptr) - *val = 0; -+ else if (property == config->bgcolor_property) -+ *val = state->bgcolor; - else if (crtc->funcs->atomic_get_property) - return crtc->funcs->atomic_get_property(crtc, state, property, val); - else -diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c -index f1dcad96f..1e786abc6 100644 ---- a/drivers/gpu/drm/drm_blend.c -+++ b/drivers/gpu/drm/drm_blend.c -@@ -185,6 +185,21 @@ - * plane does not expose the "alpha" property, then this is - * assumed to be 1.0 - * -+ * BACKGROUND_COLOR: -+ * Defines the ARGB color of a full-screen layer that exists below all -+ * planes. This color will be used for pixels not covered by any plane -+ * and may also be blended with plane contents as allowed by a plane's -+ * alpha values. The background color defaults to black, and is assumed -+ * to be black for drivers that do not expose this property. Although -+ * background color isn't a plane, it is assumed that the color provided -+ * here undergoes the same pipe-level degamma/CSC/gamma transformations -+ * that planes undergo. Note that the color value provided here includes -+ * an alpha channel...non-opaque background color values are allowed, -+ * but are generally only honored in special cases (e.g., when a memory -+ * writeback connector is in use). -+ * -+ * This property is setup with drm_crtc_add_bgcolor_property(). -+ * - * IN_FORMATS: - * Blob property which contains the set of buffer format and modifier - * pairs supported by this plane. The blob is a drm_format_modifier_blob -@@ -192,8 +207,7 @@ - * modifiers. Userspace cannot change this property. - * - * Note that all the property extensions described here apply either to the -- * plane or the CRTC (e.g. for the background color, which currently is not -- * exposed and assumed to be black). -+ * plane or the CRTC. - */ - - /** -@@ -609,3 +623,19 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, - return 0; - } - EXPORT_SYMBOL(drm_plane_create_blend_mode_property); -+ -+/** -+ * drm_crtc_add_bgcolor_property - add background color property -+ * @crtc: drm crtc -+ * -+ * Adds the background color property to @crtc. The property defaults to -+ * solid black and will accept 64-bit ARGB values in the format generated by -+ * drm_argb(). -+ */ -+void drm_crtc_add_bgcolor_property(struct drm_crtc *crtc) -+{ -+ drm_object_attach_property(&crtc->base, -+ crtc->dev->mode_config.bgcolor_property, -+ drm_argb(16, 0xffff, 0, 0, 0)); -+} -+EXPORT_SYMBOL(drm_crtc_add_bgcolor_property); -diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c -index f1affc1bb..845091106 100644 ---- a/drivers/gpu/drm/drm_mode_config.c -+++ b/drivers/gpu/drm/drm_mode_config.c -@@ -371,6 +371,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) - return -ENOMEM; - dev->mode_config.modifiers_property = prop; - -+ prop = drm_property_create_range(dev, 0, "BACKGROUND_COLOR", -+ 0, GENMASK_ULL(63, 0)); -+ if (!prop) -+ return -ENOMEM; -+ dev->mode_config.bgcolor_property = prop; -+ - return 0; - } - -diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c -index 511cde5c7..58ab4a543 100644 ---- a/drivers/gpu/drm/drm_modes.c -+++ b/drivers/gpu/drm/drm_modes.c -@@ -127,7 +127,7 @@ EXPORT_SYMBOL(drm_mode_probed_add); - * according to the hdisplay, vdisplay, vrefresh. - * It is based from the VESA(TM) Coordinated Video Timing Generator by - * Graham Loveridge April 9, 2003 available at -- * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls -+ * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls - * - * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c. - * What I have done is to translate it by using integer calculation. -@@ -615,6 +615,15 @@ void drm_display_mode_from_videomode(const struct videomode *vm, - dmode->flags |= DRM_MODE_FLAG_DBLSCAN; - if (vm->flags & DISPLAY_FLAGS_DOUBLECLK) - dmode->flags |= DRM_MODE_FLAG_DBLCLK; -+ if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) -+ dmode->flags |= DRM_MODE_FLAG_PPIXDATA; -+ else if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) -+ dmode->flags |= DRM_MODE_FLAG_NPIXDATA; -+ if (vm->flags & DISPLAY_FLAGS_DE_HIGH) -+ dmode->flags |= DRM_MODE_FLAG_PDE; -+ else if (vm->flags & DISPLAY_FLAGS_DE_LOW) -+ dmode->flags |= DRM_MODE_FLAG_NDE; -+ - drm_mode_set_name(dmode); - } - EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); -@@ -656,6 +665,14 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode, - vm->flags |= DISPLAY_FLAGS_DOUBLESCAN; - if (dmode->flags & DRM_MODE_FLAG_DBLCLK) - vm->flags |= DISPLAY_FLAGS_DOUBLECLK; -+ if (dmode->flags & DRM_MODE_FLAG_PPIXDATA) -+ vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; -+ else if (dmode->flags & DRM_MODE_FLAG_NPIXDATA) -+ vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; -+ if (dmode->flags & DRM_MODE_FLAG_PDE) -+ vm->flags |= DISPLAY_FLAGS_DE_HIGH; -+ else if (dmode->flags & DRM_MODE_FLAG_NDE) -+ vm->flags |= DISPLAY_FLAGS_DE_LOW; - } - EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); - -diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -index 6ac1accad..70b2bb72d 100644 ---- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -@@ -60,6 +60,9 @@ - #define MCS_CMD2_ENA1 0xFF00 /* Enable Access Command2 "CMD2" */ - #define MCS_CMD2_ENA2 0xFF80 /* Enable Access Orise Command2 */ - -+#define OTM8009A_HDISPLAY 480 -+#define OTM8009A_VDISPLAY 800 -+ - struct otm8009a { - struct device *dev; - struct drm_panel panel; -@@ -70,19 +73,35 @@ struct otm8009a { - bool enabled; - }; - --static const struct drm_display_mode default_mode = { -- .clock = 29700, -- .hdisplay = 480, -- .hsync_start = 480 + 98, -- .hsync_end = 480 + 98 + 32, -- .htotal = 480 + 98 + 32 + 98, -- .vdisplay = 800, -- .vsync_start = 800 + 15, -- .vsync_end = 800 + 15 + 10, -- .vtotal = 800 + 15 + 10 + 14, -- .flags = 0, -- .width_mm = 52, -- .height_mm = 86, -+static const struct drm_display_mode modes[] = { -+ { /* 50 Hz, preferred */ -+ .clock = 29700, -+ .hdisplay = 480, -+ .hsync_start = 480 + 98, -+ .hsync_end = 480 + 98 + 32, -+ .htotal = 480 + 98 + 32 + 98, -+ .vdisplay = 800, -+ .vsync_start = 800 + 15, -+ .vsync_end = 800 + 15 + 10, -+ .vtotal = 800 + 15 + 10 + 14, -+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, -+ .width_mm = 52, -+ .height_mm = 86, -+ }, -+ { /* 60 Hz */ -+ .clock = 33000, -+ .hdisplay = 480, -+ .hsync_start = 480 + 70, -+ .hsync_end = 480 + 70 + 32, -+ .htotal = 480 + 70 + 32 + 72, -+ .vdisplay = 800, -+ .vsync_start = 800 + 15, -+ .vsync_end = 800 + 15 + 10, -+ .vtotal = 800 + 15 + 10 + 16, -+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, -+ .width_mm = 52, -+ .height_mm = 86, -+ }, - }; - - static inline struct otm8009a *panel_to_otm8009a(struct drm_panel *panel) -@@ -99,20 +118,6 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, - dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n"); - } - --static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data, -- size_t len) --{ -- struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); -- -- /* data will be sent in dsi hs mode (ie. no lpm) */ -- dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; -- -- otm8009a_dcs_write_buf(ctx, data, len); -- -- /* restore back the dsi lpm mode */ -- dsi->mode_flags |= MIPI_DSI_MODE_LPM; --} -- - #define dcs_write_seq(ctx, seq...) \ - ({ \ - static const u8 d[] = { seq }; \ -@@ -222,12 +227,11 @@ static int otm8009a_init_sequence(struct otm8009a *ctx) - /* Default portrait 480x800 rgb24 */ - dcs_write_seq(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); - -- ret = mipi_dsi_dcs_set_column_address(dsi, 0, -- default_mode.hdisplay - 1); -+ ret = mipi_dsi_dcs_set_column_address(dsi, 0, OTM8009A_HDISPLAY - 1); - if (ret) - return ret; - -- ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1); -+ ret = mipi_dsi_dcs_set_page_address(dsi, 0, OTM8009A_VDISPLAY - 1); - if (ret) - return ret; - -@@ -351,24 +355,35 @@ static int otm8009a_get_modes(struct drm_panel *panel, - struct drm_connector *connector) - { - struct drm_display_mode *mode; -- -- mode = drm_mode_duplicate(connector->dev, &default_mode); -- if (!mode) { -- dev_err(panel->dev, "failed to add mode %ux%u@%u\n", -- default_mode.hdisplay, default_mode.vdisplay, -- drm_mode_vrefresh(&default_mode)); -- return -ENOMEM; -+ unsigned int num_modes = ARRAY_SIZE(modes); -+ unsigned int i; -+ -+ for (i = 0; i < num_modes; i++) { -+ mode = drm_mode_duplicate(connector->dev, &modes[i]); -+ if (!mode) { -+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n", -+ modes[i].hdisplay, -+ modes[i].vdisplay, -+ drm_mode_vrefresh(&modes[i])); -+ return -ENOMEM; -+ } -+ -+ mode->type = DRM_MODE_TYPE_DRIVER; -+ -+ /* Setting first mode as preferred */ -+ if (!i) -+ mode->type |= DRM_MODE_TYPE_PREFERRED; -+ -+ drm_mode_set_name(mode); -+ drm_mode_probed_add(connector, mode); - } - -- drm_mode_set_name(mode); -- -- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -- drm_mode_probed_add(connector, mode); -- - connector->display_info.width_mm = mode->width_mm; - connector->display_info.height_mm = mode->height_mm; -+ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | -+ DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - -- return 1; -+ return num_modes; - } - - static const struct drm_panel_funcs otm8009a_drm_funcs = { -@@ -400,7 +415,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) - */ - data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS; - data[1] = bd->props.brightness; -- otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); -+ otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); - - /* set Brightness Control & Backlight on */ - data[1] = 0x24; -@@ -412,7 +427,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) - - /* Update Brightness Control & Backlight */ - data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY; -- otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); -+ otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); - - return 0; - } -@@ -433,8 +448,18 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) - - ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { -- dev_err(dev, "cannot get reset-gpio\n"); -- return PTR_ERR(ctx->reset_gpio); -+ ret = PTR_ERR(ctx->reset_gpio); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "cannot get reset GPIO: %d\n", ret); -+ return ret; -+ } -+ -+ /* Reset the panel to avoid visual artifacts */ -+ if (ctx->reset_gpio) { -+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); -+ gpiod_set_value_cansleep(ctx->reset_gpio, 1); -+ msleep(20); -+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); - } - - ctx->supply = devm_regulator_get(dev, "power"); -diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c -index f908eeafb..d5542266e 100644 ---- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c -+++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c -@@ -82,16 +82,16 @@ struct rm68200 { - }; - - static const struct drm_display_mode default_mode = { -- .clock = 52582, -+ .clock = 54000, - .hdisplay = 720, -- .hsync_start = 720 + 38, -- .hsync_end = 720 + 38 + 8, -- .htotal = 720 + 38 + 8 + 38, -+ .hsync_start = 720 + 48, -+ .hsync_end = 720 + 48 + 9, -+ .htotal = 720 + 48 + 9 + 48, - .vdisplay = 1280, - .vsync_start = 1280 + 12, -- .vsync_end = 1280 + 12 + 4, -- .vtotal = 1280 + 12 + 4 + 12, -- .flags = 0, -+ .vsync_end = 1280 + 12 + 5, -+ .vtotal = 1280 + 12 + 5 + 12, -+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, - .width_mm = 68, - .height_mm = 122, - }; -@@ -347,6 +347,8 @@ static int rm68200_get_modes(struct drm_panel *panel, - - connector->display_info.width_mm = mode->width_mm; - connector->display_info.height_mm = mode->height_mm; -+ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | -+ DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - - return 1; - } -@@ -372,7 +374,8 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) - ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { - ret = PTR_ERR(ctx->reset_gpio); -- dev_err(dev, "cannot get reset GPIO: %d\n", ret); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "cannot get reset GPIO: %d\n", ret); - return ret; - } - -@@ -391,7 +394,7 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) - dsi->lanes = 2; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | -- MIPI_DSI_MODE_LPM; -+ MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; - - drm_panel_init(&ctx->panel, dev, &rm68200_drm_funcs, - DRM_MODE_CONNECTOR_DSI); -diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c -index 411103f01..0f2383026 100644 ---- a/drivers/gpu/drm/stm/drv.c -+++ b/drivers/gpu/drm/stm/drv.c -@@ -193,6 +193,11 @@ static int stm_drm_platform_probe(struct platform_device *pdev) - if (ret) - goto err_put; - -+ ret = drm_fb_helper_remove_conflicting_framebuffers(NULL, "stmdrmfb", -+ false); -+ if (ret) -+ goto err_put; -+ - ret = drm_dev_register(ddev, 0); - if (ret) - goto err_put; -diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -index 2e1f26644..87f894ea3 100644 ---- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -@@ -309,14 +309,23 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, - return 0; - } - -+#define DSI_PHY_DELAY(fp, vp, mbps) DIV_ROUND_UP((fp) * (mbps) + 1000 * (vp), 8000) -+ - static int - dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, - struct dw_mipi_dsi_dphy_timing *timing) - { -- timing->clk_hs2lp = 0x40; -- timing->clk_lp2hs = 0x40; -- timing->data_hs2lp = 0x40; -- timing->data_lp2hs = 0x40; -+ /* -+ * From STM32MP157 datasheet, valid for STM32F469, STM32F7x9, STM32H747 -+ * phy_clkhs2lp_time = (272+136*UI)/(8*UI) -+ * phy_clklp2hs_time = (512+40*UI)/(8*UI) -+ * phy_hs2lp_time = (192+64*UI)/(8*UI) -+ * phy_lp2hs_time = (256+32*UI)/(8*UI) -+ */ -+ timing->clk_hs2lp = DSI_PHY_DELAY(272, 136, lane_mbps); -+ timing->clk_lp2hs = DSI_PHY_DELAY(512, 40, lane_mbps); -+ timing->data_hs2lp = DSI_PHY_DELAY(192, 64, lane_mbps); -+ timing->data_lp2hs = DSI_PHY_DELAY(256, 32, lane_mbps); - - return 0; - } -@@ -419,7 +428,8 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) - dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); - if (IS_ERR(dsi->dsi)) { - ret = PTR_ERR(dsi->dsi); -- DRM_ERROR("Failed to initialize mipi dsi host: %d\n", ret); -+ if (ret != -EPROBE_DEFER) -+ DRM_ERROR("Failed to initialize mipi dsi host: %d\n", ret); - goto err_dsi_probe; - } - -diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c -index 62488ac14..a7c85a922 100644 ---- a/drivers/gpu/drm/stm/ltdc.c -+++ b/drivers/gpu/drm/stm/ltdc.c -@@ -195,6 +195,11 @@ - - #define NB_PF 8 /* Max nb of HW pixel format */ - -+#define DRM_ARGB_TO_LTDC_RGB24(bgcolor) \ -+ ((u32)(DRM_ARGB_RED(bgcolor, 8) << 16 \ -+ | DRM_ARGB_GREEN(bgcolor, 8) << 8 \ -+ | DRM_ARGB_BLUE(bgcolor, 8))) -+ - enum ltdc_pix_fmt { - PF_NONE, - /* RGB formats */ -@@ -363,6 +368,15 @@ static inline u32 get_pixelformat_without_alpha(u32 drm) - } - } - -+/* -+ * All non-alpha color formats derived from native alpha color formats are -+ * either characterized by a FourCC format code -+ */ -+static inline u32 is_xrgb(u32 drm) -+{ -+ return ((drm & 'X') == 'X' || (drm & ('X' << 8)) == ('X' << 8)); -+} -+ - static irqreturn_t ltdc_irq_thread(int irq, void *arg) - { - struct drm_device *ddev = arg; -@@ -430,7 +444,8 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, - pm_runtime_get_sync(ddev->dev); - - /* Sets the background color value */ -- reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); -+ reg_write(ldev->regs, LTDC_BCCR, -+ DRM_ARGB_TO_LTDC_RGB24(crtc->state->bgcolor)); - - /* Enable IRQ */ - reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); -@@ -451,6 +466,9 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, - - drm_crtc_vblank_off(crtc); - -+ /* Reset background color */ -+ reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); -+ - /* disable IRQ */ - reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); - -@@ -530,7 +548,6 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) - struct drm_encoder *encoder = NULL; - struct drm_bridge *bridge = NULL; - struct drm_display_mode *mode = &crtc->state->adjusted_mode; -- struct videomode vm; - u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; - u32 total_width, total_height; - u32 bus_flags = 0; -@@ -539,20 +556,17 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) - - /* get encoder from crtc */ - drm_for_each_encoder(encoder, ddev) -- if (encoder->crtc == crtc) -- break; -+ if (encoder->crtc == crtc) break; - - if (encoder) { - /* get bridge from encoder */ - list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) -- if (bridge->encoder == encoder) -- break; -+ if (bridge->encoder == encoder) break; - - /* Get the connector from encoder */ - drm_connector_list_iter_begin(ddev, &iter); - drm_for_each_connector_iter(connector, &iter) -- if (connector->encoder == encoder) -- break; -+ if (connector->encoder == encoder) break; - drm_connector_list_iter_end(&iter); - } - -@@ -569,31 +583,33 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - } - -- drm_display_mode_to_videomode(mode, &vm); -- - DRM_DEBUG_DRIVER("CRTC:%d mode:%s\n", crtc->base.id, mode->name); -- DRM_DEBUG_DRIVER("Video mode: %dx%d", vm.hactive, vm.vactive); -+ DRM_DEBUG_DRIVER("Video mode: %dx%d", mode->hdisplay, mode->vdisplay); - DRM_DEBUG_DRIVER(" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n", -- vm.hfront_porch, vm.hback_porch, vm.hsync_len, -- vm.vfront_porch, vm.vback_porch, vm.vsync_len); -+ mode->hsync_start - mode->hdisplay, -+ mode->htotal - mode->hsync_end, -+ mode->hsync_end - mode->hsync_start, -+ mode->vsync_start - mode->vdisplay, -+ mode->vtotal - mode->vsync_end, -+ mode->vsync_end - mode->vsync_start); - - /* Convert video timings to ltdc timings */ -- hsync = vm.hsync_len - 1; -- vsync = vm.vsync_len - 1; -- accum_hbp = hsync + vm.hback_porch; -- accum_vbp = vsync + vm.vback_porch; -- accum_act_w = accum_hbp + vm.hactive; -- accum_act_h = accum_vbp + vm.vactive; -- total_width = accum_act_w + vm.hfront_porch; -- total_height = accum_act_h + vm.vfront_porch; -+ hsync = mode->hsync_end - mode->hsync_start - 1; -+ vsync = mode->vsync_end - mode->vsync_start - 1; -+ accum_hbp = mode->htotal - mode->hsync_start - 1; -+ accum_vbp = mode->vtotal - mode->vsync_start - 1; -+ accum_act_w = accum_hbp + mode->hdisplay; -+ accum_act_h = accum_vbp + mode->vdisplay; -+ total_width = mode->htotal - 1; -+ total_height = mode->vtotal - 1; - - /* Configures the HS, VS, DE and PC polarities. Default Active Low */ - val = 0; - -- if (vm.flags & DISPLAY_FLAGS_HSYNC_HIGH) -+ if (mode->flags & DRM_MODE_FLAG_PHSYNC) - val |= GCR_HSPOL; - -- if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) -+ if (mode->flags & DRM_MODE_FLAG_PVSYNC) - val |= GCR_VSPOL; - - if (bus_flags & DRM_BUS_FLAG_DE_LOW) -@@ -753,22 +769,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state) - { - struct drm_framebuffer *fb = state->fb; -- u32 src_w, src_h; -+ struct drm_crtc_state *crtc_state; -+ struct drm_rect *src = &state->src; -+ struct drm_rect *dst = &state->dst; - - DRM_DEBUG_DRIVER("\n"); - - if (!fb) - return 0; - -- /* convert src_ from 16:16 format */ -- src_w = state->src_w >> 16; -- src_h = state->src_h >> 16; -+ /* convert src from 16:16 format */ -+ src->x1 = state->src_x >> 16; -+ src->y1 = state->src_y >> 16; -+ src->x2 = (state->src_w >> 16) + src->x1 - 1; -+ src->y2 = (state->src_h >> 16) + src->y1 - 1; -+ -+ dst->x1 = state->crtc_x; -+ dst->y1 = state->crtc_y; -+ dst->x2 = state->crtc_w + dst->x1 - 1; -+ dst->y2 = state->crtc_h + dst->y1 - 1; -+ -+ DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", -+ plane->base.id, fb->base.id, -+ src->x2 - src->x1 + 1, src->y2 - src->y1 + 1, -+ src->x1, src->y1, -+ dst->x2 - dst->x1 + 1, dst->y2 - dst->y1 + 1, -+ dst->x1, dst->y1); -+ -+ crtc_state = drm_atomic_get_existing_crtc_state(state->state, -+ state->crtc); -+ /* destination coordinates do not have to exceed display sizes */ -+ if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 || -+ crtc_state->mode.vdisplay <= dst->y2)) -+ return -EINVAL; - -- /* Reject scaling */ -- if (src_w != state->crtc_w || src_h != state->crtc_h) { -- DRM_ERROR("Scaling is not supported"); -+ /* source sizes do not have to exceed destination sizes */ -+ if (dst->x2 - dst->x1 < src->x2 - src->x1 || -+ dst->y2 - dst->y1 < src->y2 - src->y1) - return -EINVAL; -- } - - return 0; - } -@@ -778,44 +816,37 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, - { - struct ltdc_device *ldev = plane_to_ltdc(plane); - struct drm_plane_state *state = plane->state; -+ struct drm_rect *src = &state->src; -+ struct drm_rect *dst = &state->dst; - struct drm_framebuffer *fb = state->fb; - u32 lofs = plane->index * LAY_OFS; -- u32 x0 = state->crtc_x; -- u32 x1 = state->crtc_x + state->crtc_w - 1; -- u32 y0 = state->crtc_y; -- u32 y1 = state->crtc_y + state->crtc_h - 1; -- u32 src_x, src_y, src_w, src_h; - u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; -+ u32 bgcolor = DRM_ARGB_TO_LTDC_RGB24(state->crtc->state->bgcolor); - enum ltdc_pix_fmt pf; -+ struct drm_rect dr; - - if (!state->crtc || !fb) { - DRM_DEBUG_DRIVER("fb or crtc NULL"); - return; - } - -- /* convert src_ from 16:16 format */ -- src_x = state->src_x >> 16; -- src_y = state->src_y >> 16; -- src_w = state->src_w >> 16; -- src_h = state->src_h >> 16; -- -- DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", -- plane->base.id, fb->base.id, -- src_w, src_h, src_x, src_y, -- state->crtc_w, state->crtc_h, -- state->crtc_x, state->crtc_y); -+ /* compute final coordinates of frame buffer */ -+ dr.x1 = src->x1 + dst->x1; -+ dr.y1 = src->y1 + dst->y1; -+ dr.x2 = src->x2 + dst->x1; -+ dr.y2 = src->y2 + dst->y1; - - bpcr = reg_read(ldev->regs, LTDC_BPCR); - ahbp = (bpcr & BPCR_AHBP) >> 16; - avbp = bpcr & BPCR_AVBP; - - /* Configures the horizontal start and stop position */ -- val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); -+ val = ((dr.x2 + 1 + ahbp) << 16) + (dr.x1 + 1 + ahbp); - reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, - LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); - - /* Configures the vertical start and stop position */ -- val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); -+ val = ((dr.y2 + 1 + avbp) << 16) + (dr.y1 + 1 + avbp); - reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, - LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); - -@@ -834,14 +865,14 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, - - /* Configures the color frame buffer pitch in bytes & line length */ - pitch_in_bytes = fb->pitches[0]; -- line_length = fb->format->cpp[0] * -- (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; -+ line_length = fb->format->cpp[0] * (dr.x2 - dr.x1 + 1) + -+ (ldev->caps.bus_width >> 3) - 1; - val = ((pitch_in_bytes << 16) | line_length); - reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, - LXCFBLR_CFBLL | LXCFBLR_CFBP, val); - - /* Specifies the constant alpha value */ -- val = CONSTA_MAX; -+ val = state->alpha >> 8; - reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); - - /* Specifies the blending factors */ -@@ -849,16 +880,34 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, - if (!fb->format->has_alpha) - val = BF1_CA | BF2_1CA; - -- /* Manage hw-specific capabilities */ -- if (ldev->caps.non_alpha_only_l1 && -- plane->type != DRM_PLANE_TYPE_PRIMARY) -- val = BF1_PAXCA | BF2_1PAXCA; -+ /* -+ * Manage hw-specific capabilities -+ * -+ * Depending on the hardware version, the background color can not be -+ * properly displayed with non-alpha color formats derived from native -+ * alpha color formats (such as XR24 or XR15) since the use of this -+ * pixel format generates a non transparent layer. As a workaround, -+ * the stage background color of the layer and the general background -+ * color need to be synced. -+ * -+ * This is done by activating for all XRGB color format the default -+ * color as the background color and then setting blending factor -+ * accordingly. -+ */ -+ if (ldev->caps.non_alpha_only_l1) { -+ if (is_xrgb(fb->format->format)) { -+ val = BF1_CA | BF2_1CA; -+ reg_write(ldev->regs, LTDC_L1DCCR + lofs, bgcolor); -+ } else { -+ val = BF1_PAXCA | BF2_1PAXCA; -+ } -+ } - - reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, - LXBFCR_BF2 | LXBFCR_BF1, val); - - /* Configures the frame buffer line number */ -- val = y1 - y0 + 1; -+ val = dr.y2 - dr.y1 + 1; - reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); - - /* Sets the FB address */ -@@ -992,6 +1041,8 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, - - drm_plane_helper_add(plane, <dc_plane_helper_funcs); - -+ drm_plane_create_alpha_property(plane); -+ - DRM_DEBUG_DRIVER("plane:%d created\n", plane->base.id); - - return plane; -@@ -1019,6 +1070,8 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) - return -EINVAL; - } - -+ drm_plane_create_zpos_immutable_property(primary, 0); -+ - ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, - <dc_crtc_funcs, NULL); - if (ret) { -@@ -1028,6 +1081,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) - - drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs); - -+ drm_crtc_add_bgcolor_property(crtc); - drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE); - drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE); - -@@ -1041,6 +1095,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) - DRM_ERROR("Can not create overlay plane %d\n", i); - goto cleanup; - } -+ drm_plane_create_zpos_immutable_property(overlay, i); - } - - return 0; -diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c -index 6ff81d48d..1643ddf5f 100644 ---- a/drivers/input/touchscreen/edt-ft5x06.c -+++ b/drivers/input/touchscreen/edt-ft5x06.c -@@ -30,6 +30,8 @@ - #include - - #include -+#include -+#include - - #define WORK_REGISTER_THRESHOLD 0x00 - #define WORK_REGISTER_REPORT_RATE 0x08 -@@ -1074,6 +1076,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, - const struct edt_i2c_chip_data *chip_data; - struct edt_ft5x06_ts_data *tsdata; - u8 buf[2] = { 0xfc, 0x00 }; -+ struct mipi_dsi_device *panel; -+ struct device_node *np; - struct input_dev *input; - unsigned long irq_flags; - int error; -@@ -1173,7 +1177,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, - - error = edt_ft5x06_ts_identify(client, tsdata, fw_version); - if (error) { -- dev_err(&client->dev, "touchscreen probe failed\n"); -+ dev_dbg(&client->dev, "touchscreen probe failed\n"); - return error; - } - -@@ -1242,6 +1246,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, - if (error) - return error; - -+ np = of_parse_phandle(client->dev.of_node, "panel", 0); -+ if (np) { -+ panel = of_find_mipi_dsi_device_by_node(np); -+ of_node_put(np); -+ if (!panel) -+ return -EPROBE_DEFER; -+ -+ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | -+ DL_FLAG_AUTOREMOVE_SUPPLIER); -+ put_device(&panel->dev); -+ } -+ - edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); - - dev_dbg(&client->dev, -diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c -index a06385c55..388544f2d 100644 ---- a/drivers/input/touchscreen/goodix.c -+++ b/drivers/input/touchscreen/goodix.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1153,6 +1154,8 @@ static int goodix_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) - { - struct goodix_ts_data *ts; -+ struct mipi_dsi_device *panel; -+ struct device_node *np; - int error; - - dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); -@@ -1252,6 +1255,17 @@ static int goodix_ts_probe(struct i2c_client *client, - return error; - } - -+ np = of_parse_phandle(client->dev.of_node, "panel", 0); -+ if (np) { -+ panel = of_find_mipi_dsi_device_by_node(np); -+ of_node_put(np); -+ if (!panel) -+ return -EPROBE_DEFER; -+ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | -+ DL_FLAG_AUTOREMOVE_SUPPLIER); -+ put_device(&panel->dev); -+ } -+ - return 0; - } - -@@ -1307,6 +1321,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) - * sooner, delay 58ms here. - */ - msleep(58); -+ - return 0; - } - -diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h -index 88bdfec3b..9e2538dd7 100644 ---- a/include/drm/drm_blend.h -+++ b/include/drm/drm_blend.h -@@ -58,4 +58,5 @@ int drm_atomic_normalize_zpos(struct drm_device *dev, - struct drm_atomic_state *state); - int drm_plane_create_blend_mode_property(struct drm_plane *plane, - unsigned int supported_modes); -+void drm_crtc_add_bgcolor_property(struct drm_crtc *crtc); - #endif -diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h -index 59b51a09c..d6808aca9 100644 ---- a/include/drm/drm_crtc.h -+++ b/include/drm/drm_crtc.h -@@ -288,6 +288,18 @@ struct drm_crtc_state { - */ - struct drm_property_blob *gamma_lut; - -+ /** -+ * @bgcolor: -+ * -+ * RGB value representing the pipe's background color. The background -+ * color (aka "canvas color") of a pipe is the color that will be used -+ * for pixels not covered by a plane, or covered by transparent pixels -+ * of a plane. The value here should be built via drm_argb(); -+ * individual color components can be extracted with desired precision -+ * via the DRM_ARGB_*() macros. -+ */ -+ u64 bgcolor; -+ - /** - * @target_vblank: - * -diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h -index a18f73eb3..3e37a3a19 100644 ---- a/include/drm/drm_mode_config.h -+++ b/include/drm/drm_mode_config.h -@@ -861,6 +861,11 @@ struct drm_mode_config { - */ - struct drm_property *hdcp_content_type_property; - -+ /** -+ * @bgcolor_property: RGB background color for CRTC. -+ */ -+ struct drm_property *bgcolor_property; -+ - /* dumb ioctl parameters */ - uint32_t preferred_depth, prefer_shadow; - -diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h -index 863eda048..5042afb3d 100644 ---- a/include/uapi/drm/drm_mode.h -+++ b/include/uapi/drm/drm_mode.h -@@ -97,6 +97,12 @@ extern "C" { - #define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14) - #define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14) - -+/* flags for polarity clock & data enable polarities */ -+#define DRM_MODE_FLAG_PPIXDATA (1 << 19) -+#define DRM_MODE_FLAG_NPIXDATA (1 << 20) -+#define DRM_MODE_FLAG_PDE (1 << 21) -+#define DRM_MODE_FLAG_NDE (1 << 22) -+ - /* Picture aspect ratio options */ - #define DRM_MODE_PICTURE_ASPECT_NONE 0 - #define DRM_MODE_PICTURE_ASPECT_4_3 1 -@@ -1030,6 +1036,34 @@ struct drm_mode_rect { - __s32 y2; - }; - -+/* -+ * Put ARGB values into a standard 64-bit representation that can be used -+ * for ioctl parameters, inter-driver commmunication, etc. If the component -+ * values being provided contain less than 16 bits of precision, they'll -+ * be shifted into the most significant bits. -+ */ -+static inline __u64 -+drm_argb(__u8 bpc, __u16 alpha, __u16 red, __u16 green, __u16 blue) -+{ -+ int msb_shift = 16 - bpc; -+ -+ return (__u64)alpha << msb_shift << 48 | -+ (__u64)red << msb_shift << 32 | -+ (__u64)green << msb_shift << 16 | -+ (__u64)blue << msb_shift; -+} -+ -+/* -+ * Extract the specified number of bits of a specific color component from a -+ * standard 64-bit ARGB value. -+ */ -+#define DRM_ARGB_COMP(c, shift, numbits) \ -+ (__u16)(((c) & 0xFFFFull << (shift)) >> ((shift) + 16 - (numbits))) -+#define DRM_ARGB_BLUE(c, numbits) DRM_ARGB_COMP(c, 0, numbits) -+#define DRM_ARGB_GREEN(c, numbits) DRM_ARGB_COMP(c, 16, numbits) -+#define DRM_ARGB_RED(c, numbits) DRM_ARGB_COMP(c, 32, numbits) -+#define DRM_ARGB_ALPHA(c, numbits) DRM_ARGB_COMP(c, 48, numbits) -+ - #if defined(__cplusplus) - } - #endif --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0008-ARM-5.10.61-stm32mp1-r2-I2C-IIO-IRQCHIP.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0008-ARM-5.10.61-stm32mp1-r2-I2C-IIO-IRQCHIP.patch deleted file mode 100644 index 0c30d3d..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0008-ARM-5.10.61-stm32mp1-r2-I2C-IIO-IRQCHIP.patch +++ /dev/null @@ -1,2145 +0,0 @@ -From fc843f64f154b843cd7834d6748b409ef1e1487f Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:44 +0200 -Subject: [PATCH 08/23] ARM 5.10.61-stm32mp1-r2 I2C-IIO-IRQCHIP - ---- - drivers/i2c/busses/i2c-stm32f7.c | 285 +++++++++++------- - drivers/iio/adc/sd_adc_modulator.c | 89 +++++- - drivers/iio/adc/stm32-adc-core.c | 21 +- - drivers/iio/adc/stm32-adc-core.h | 8 + - drivers/iio/adc/stm32-adc.c | 445 ++++++++++++++++++++++++----- - drivers/iio/adc/stm32-dfsdm-adc.c | 108 ++++++- - drivers/iio/adc/stm32-dfsdm-core.c | 91 ++++-- - drivers/iio/adc/stm32-dfsdm.h | 69 +++-- - drivers/irqchip/irq-stm32-exti.c | 89 +++++- - 9 files changed, 973 insertions(+), 232 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index 1e800b65e..0bc9acef2 100644 ---- a/drivers/i2c/busses/i2c-stm32f7.c -+++ b/drivers/i2c/busses/i2c-stm32f7.c -@@ -51,6 +51,7 @@ - - /* STM32F7 I2C control 1 */ - #define STM32F7_I2C_CR1_PECEN BIT(23) -+#define STM32F7_I2C_CR1_ALERTEN BIT(22) - #define STM32F7_I2C_CR1_SMBHEN BIT(20) - #define STM32F7_I2C_CR1_WUPEN BIT(18) - #define STM32F7_I2C_CR1_SBC BIT(16) -@@ -125,6 +126,7 @@ - (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) - #define STM32F7_I2C_ISR_DIR BIT(16) - #define STM32F7_I2C_ISR_BUSY BIT(15) -+#define STM32F7_I2C_ISR_ALERT BIT(13) - #define STM32F7_I2C_ISR_PECERR BIT(11) - #define STM32F7_I2C_ISR_ARLO BIT(9) - #define STM32F7_I2C_ISR_BERR BIT(8) -@@ -138,6 +140,7 @@ - #define STM32F7_I2C_ISR_TXE BIT(0) - - /* STM32F7 I2C Interrupt Clear */ -+#define STM32F7_I2C_ICR_ALERTCF BIT(13) - #define STM32F7_I2C_ICR_PECCF BIT(11) - #define STM32F7_I2C_ICR_ARLOCF BIT(9) - #define STM32F7_I2C_ICR_BERRCF BIT(8) -@@ -161,10 +164,8 @@ enum { - STM32F7_I2C_MAX_SLAVE - }; - --#define STM32F7_I2C_DNF_DEFAULT 0 - #define STM32F7_I2C_DNF_MAX 15 - --#define STM32F7_I2C_ANALOG_FILTER_ENABLE 1 - #define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */ - #define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ - -@@ -223,8 +224,6 @@ struct stm32f7_i2c_spec { - * @clock_src: I2C clock source frequency (Hz) - * @rise_time: Rise time (ns) - * @fall_time: Fall time (ns) -- * @dnf: Digital filter coefficient (0-16) -- * @analog_filter: Analog filter delay (On/Off) - * @fmp_clr_offset: Fast Mode Plus clear register offset from set register - */ - struct stm32f7_i2c_setup { -@@ -232,8 +231,6 @@ struct stm32f7_i2c_setup { - u32 clock_src; - u32 rise_time; - u32 fall_time; -- u8 dnf; -- bool analog_filter; - u32 fmp_clr_offset; - }; - -@@ -283,6 +280,17 @@ struct stm32f7_i2c_msg { - u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4); - }; - -+/** -+ * struct stm32f7_i2c_alert - SMBus alert specific data -+ * @setup: platform data for the smbus_alert i2c client -+ * @ara: I2C slave device used to respond to the SMBus Alert with Alert -+ * Response Address -+ */ -+struct stm32f7_i2c_alert { -+ struct i2c_smbus_alert_setup setup; -+ struct i2c_client *ara; -+}; -+ - /** - * struct stm32f7_i2c_dev - private data of the controller - * @adap: I2C adapter for this controller -@@ -312,6 +320,10 @@ struct stm32f7_i2c_msg { - * @wakeup_src: boolean to know if the device is a wakeup source - * @smbus_mode: states that the controller is configured in SMBus mode - * @host_notify_client: SMBus host-notify client -+ * @alert: SMBus alert specific data -+ * @analog_filter: boolean to indicate enabling of the analog filter -+ * @dnf_dt: value of digital filter requested via dt -+ * @dnf: value of digital filter to apply - */ - struct stm32f7_i2c_dev { - struct i2c_adapter adap; -@@ -340,6 +352,10 @@ struct stm32f7_i2c_dev { - bool wakeup_src; - bool smbus_mode; - struct i2c_client *host_notify_client; -+ struct stm32f7_i2c_alert *alert; -+ bool analog_filter; -+ u32 dnf_dt; -+ u32 dnf; - }; - - /* -@@ -385,15 +401,11 @@ static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = { - static const struct stm32f7_i2c_setup stm32f7_setup = { - .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, - .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, -- .dnf = STM32F7_I2C_DNF_DEFAULT, -- .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, - }; - - static const struct stm32f7_i2c_setup stm32mp15_setup = { - .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, - .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, -- .dnf = STM32F7_I2C_DNF_DEFAULT, -- .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, - .fmp_clr_offset = 0x40, - }; - -@@ -462,27 +474,28 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - return -EINVAL; - } - -- if (setup->dnf > STM32F7_I2C_DNF_MAX) { -+ i2c_dev->dnf = DIV_ROUND_CLOSEST(i2c_dev->dnf_dt, i2cclk); -+ if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX) { - dev_err(i2c_dev->dev, - "DNF out of bound %d/%d\n", -- setup->dnf, STM32F7_I2C_DNF_MAX); -+ i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk); - return -EINVAL; - } - - /* Analog and Digital Filters */ - af_delay_min = -- (setup->analog_filter ? -+ (i2c_dev->analog_filter ? - STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0); - af_delay_max = -- (setup->analog_filter ? -+ (i2c_dev->analog_filter ? - STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); -- dnf_delay = setup->dnf * i2cclk; -+ dnf_delay = i2c_dev->dnf * i2cclk; - - sdadel_min = specs->hddat_min + setup->fall_time - -- af_delay_min - (setup->dnf + 3) * i2cclk; -+ af_delay_min - (i2c_dev->dnf + 3) * i2cclk; - - sdadel_max = specs->vddat_max - setup->rise_time - -- af_delay_max - (setup->dnf + 4) * i2cclk; -+ af_delay_max - (i2c_dev->dnf + 4) * i2cclk; - - scldel_min = setup->rise_time + specs->sudat_min; - -@@ -648,6 +661,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, - setup->speed_freq = t->bus_freq_hz; - i2c_dev->setup.rise_time = t->scl_rise_ns; - i2c_dev->setup.fall_time = t->scl_fall_ns; -+ i2c_dev->dnf_dt = t->digital_filter_width_ns; - setup->clock_src = clk_get_rate(i2c_dev->clk); - - if (!setup->clock_src) { -@@ -655,6 +669,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, - return -EINVAL; - } - -+ if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter")) -+ i2c_dev->dnf_dt = 0; -+ - do { - ret = stm32f7_i2c_compute_timing(i2c_dev, setup, - &i2c_dev->timing); -@@ -676,12 +693,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, - return ret; - } - -+ i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node, -+ "i2c-analog-filter"); -+ - dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n", - setup->speed_freq, setup->clock_src); - dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n", - setup->rise_time, setup->fall_time); - dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n", -- (setup->analog_filter ? "On" : "Off"), setup->dnf); -+ (i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf); - - i2c_dev->bus_rate = setup->speed_freq; - -@@ -720,8 +740,8 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) - timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll); - writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR); - -- /* Enable I2C */ -- if (i2c_dev->setup.analog_filter) -+ /* Configure the Analog Filter */ -+ if (i2c_dev->analog_filter) - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, - STM32F7_I2C_CR1_ANFOFF); - else -@@ -732,7 +752,7 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, - STM32F7_I2C_CR1_DNF_MASK); - stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, -- STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf)); -+ STM32F7_I2C_CR1_DNF(i2c_dev->dnf)); - - stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, - STM32F7_I2C_CR1_PE); -@@ -1403,7 +1423,7 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) - status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); - - /* Slave transmitter mode */ -- if (status & STM32F7_I2C_ISR_TXIS) { -+ if (i2c_dev->slave_running && (status & STM32F7_I2C_ISR_TXIS)) { - i2c_slave_event(i2c_dev->slave_running, - I2C_SLAVE_READ_PROCESSED, - &val); -@@ -1413,7 +1433,8 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) - } - - /* Transfer Complete Reload for Slave receiver mode */ -- if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) { -+ if (i2c_dev->slave_running && -+ (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE)) { - /* - * Read data byte then set NBYTES to receive next byte or NACK - * the current received byte -@@ -1439,7 +1460,7 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) - } - - /* STOP received */ -- if (status & STM32F7_I2C_ISR_STOPF) { -+ if (i2c_dev->slave_running && (status & STM32F7_I2C_ISR_STOPF)) { - /* Disable interrupts */ - stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK); - -@@ -1472,6 +1493,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) - { - struct stm32f7_i2c_dev *i2c_dev = data; - struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; -+ struct stm32_i2c_dma *dma = i2c_dev->dma; - void __iomem *base = i2c_dev->base; - u32 status, mask; - int ret = IRQ_HANDLED; -@@ -1497,6 +1519,10 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) - dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", - __func__, f7_msg->addr); - writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); -+ if (i2c_dev->use_dma) { -+ stm32f7_i2c_disable_dma_req(i2c_dev); -+ dmaengine_terminate_async(dma->chan_using); -+ } - f7_msg->result = -ENXIO; - } - -@@ -1512,7 +1538,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) - /* Clear STOP flag */ - writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - -- if (i2c_dev->use_dma) { -+ if (i2c_dev->use_dma && !f7_msg->result) { - ret = IRQ_WAKE_THREAD; - } else { - i2c_dev->master_mode = false; -@@ -1525,7 +1551,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) - if (f7_msg->stop) { - mask = STM32F7_I2C_CR2_STOP; - stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); -- } else if (i2c_dev->use_dma) { -+ } else if (i2c_dev->use_dma && !f7_msg->result) { - ret = IRQ_WAKE_THREAD; - } else if (f7_msg->smbus) { - stm32f7_i2c_smbus_rep_start(i2c_dev); -@@ -1562,7 +1588,7 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) - if (!ret) { - dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); - stm32f7_i2c_disable_dma_req(i2c_dev); -- dmaengine_terminate_all(dma->chan_using); -+ dmaengine_terminate_async(dma->chan_using); - f7_msg->result = -ETIMEDOUT; - } - -@@ -1597,7 +1623,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) - - /* Bus error */ - if (status & STM32F7_I2C_ISR_BERR) { -- dev_err(dev, "<%s>: Bus error\n", __func__); -+ dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n", -+ __func__, f7_msg->addr); - writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); - stm32f7_i2c_release_bus(&i2c_dev->adap); - f7_msg->result = -EIO; -@@ -1605,17 +1632,26 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) - - /* Arbitration loss */ - if (status & STM32F7_I2C_ISR_ARLO) { -- dev_dbg(dev, "<%s>: Arbitration loss\n", __func__); -+ dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n", -+ __func__, f7_msg->addr); - writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); - f7_msg->result = -EAGAIN; - } - - if (status & STM32F7_I2C_ISR_PECERR) { -- dev_err(dev, "<%s>: PEC error in reception\n", __func__); -+ dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n", -+ __func__, f7_msg->addr); - writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); - f7_msg->result = -EINVAL; - } - -+ if (status & STM32F7_I2C_ISR_ALERT) { -+ dev_dbg(dev, "<%s>: SMBus alert received\n", __func__); -+ writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); -+ i2c_handle_smbus_alert(i2c_dev->alert->ara); -+ return IRQ_HANDLED; -+ } -+ - if (!i2c_dev->slave_running) { - u32 mask; - /* Disable interrupts */ -@@ -1629,7 +1665,7 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) - /* Disable dma */ - if (i2c_dev->use_dma) { - stm32f7_i2c_disable_dma_req(i2c_dev); -- dmaengine_terminate_all(dma->chan_using); -+ dmaengine_terminate_async(dma->chan_using); - } - - i2c_dev->master_mode = false; -@@ -1665,12 +1701,26 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, - time_left = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); - ret = f7_msg->result; -+ if (ret) { -+ if (i2c_dev->use_dma) -+ dmaengine_synchronize(dma->chan_using); -+ -+ /* -+ * It is possible that some unsent data have already been -+ * written into TXDR. To avoid sending old data in a -+ * further transfer, flush TXDR in case of any error -+ */ -+ writel_relaxed(STM32F7_I2C_ISR_TXE, -+ i2c_dev->base + STM32F7_I2C_ISR); -+ goto pm_free; -+ } - - if (!time_left) { - dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n", - i2c_dev->msg->addr); - if (i2c_dev->use_dma) -- dmaengine_terminate_all(dma->chan_using); -+ dmaengine_terminate_sync(dma->chan_using); -+ stm32f7_i2c_wait_free_bus(i2c_dev); - ret = -ETIMEDOUT; - } - -@@ -1713,13 +1763,25 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); - ret = f7_msg->result; -- if (ret) -+ if (ret) { -+ if (i2c_dev->use_dma) -+ dmaengine_synchronize(dma->chan_using); -+ -+ /* -+ * It is possible that some unsent data have already been -+ * written into TXDR. To avoid sending old data in a -+ * further transfer, flush TXDR in case of any error -+ */ -+ writel_relaxed(STM32F7_I2C_ISR_TXE, -+ i2c_dev->base + STM32F7_I2C_ISR); - goto pm_free; -+ } - - if (!timeout) { - dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); - if (i2c_dev->use_dma) -- dmaengine_terminate_all(dma->chan_using); -+ dmaengine_terminate_sync(dma->chan_using); -+ stm32f7_i2c_wait_free_bus(i2c_dev); - ret = -ETIMEDOUT; - goto pm_free; - } -@@ -1982,6 +2044,42 @@ static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) - } - } - -+static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ struct stm32f7_i2c_alert *alert; -+ struct i2c_adapter *adap = &i2c_dev->adap; -+ struct device *dev = i2c_dev->dev; -+ void __iomem *base = i2c_dev->base; -+ -+ alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL); -+ if (!alert) -+ return -ENOMEM; -+ -+ alert->ara = i2c_new_smbus_alert_device(adap, &alert->setup); -+ if (IS_ERR(alert->ara)) -+ return PTR_ERR(alert->ara); -+ -+ i2c_dev->alert = alert; -+ -+ /* Enable SMBus Alert */ -+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN); -+ -+ return 0; -+} -+ -+static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ struct stm32f7_i2c_alert *alert = i2c_dev->alert; -+ void __iomem *base = i2c_dev->base; -+ -+ if (alert) { -+ /* Disable SMBus Alert */ -+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, -+ STM32F7_I2C_CR1_ALERTEN); -+ i2c_unregister_device(alert->ara); -+ } -+} -+ - static u32 stm32f7_i2c_func(struct i2c_adapter *adap) - { - struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap); -@@ -2173,6 +2271,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - } - } - -+ if (of_property_read_bool(pdev->dev.of_node, "st,smbus-alert")) { -+ ret = stm32f7_i2c_enable_smbus_alert(i2c_dev); -+ if (ret) { -+ dev_err(i2c_dev->dev, -+ "failed to enable SMBus alert protocol (%d)\n", -+ ret); -+ goto i2c_disable_smbus_host; -+ } -+ } -+ - dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr); - - pm_runtime_mark_last_busy(i2c_dev->dev); -@@ -2180,6 +2288,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - - return 0; - -+i2c_disable_smbus_host: -+ stm32f7_i2c_disable_smbus_host(i2c_dev); -+ - i2c_adapter_remove: - i2c_del_adapter(adap); - -@@ -2214,6 +2325,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) - { - struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - -+ stm32f7_i2c_disable_smbus_alert(i2c_dev); - stm32f7_i2c_disable_smbus_host(i2c_dev); - - i2c_del_adapter(&i2c_dev->adap); -@@ -2245,64 +2357,25 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) - return 0; - } - --static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) -+static void __maybe_unused -+stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) - { -- struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -- -- if (!stm32f7_i2c_is_slave_registered(i2c_dev)) -- clk_disable_unprepare(i2c_dev->clk); -- -- return 0; --} -- --static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) --{ -- struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -- int ret; -- -- if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { -- ret = clk_prepare_enable(i2c_dev->clk); -- if (ret) { -- dev_err(dev, "failed to prepare_enable clock\n"); -- return ret; -- } -- } -- -- return 0; --} -- --#ifdef CONFIG_PM_SLEEP --static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) --{ -- int ret; - struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; - -- ret = pm_runtime_resume_and_get(i2c_dev->dev); -- if (ret < 0) -- return ret; -- - backup_regs->cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); - backup_regs->cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); - backup_regs->oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); - backup_regs->oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); - backup_regs->tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR); - stm32f7_i2c_write_fm_plus_bits(i2c_dev, false); -- -- pm_runtime_put_sync(i2c_dev->dev); -- -- return ret; - } - --static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) -+static void __maybe_unused -+stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) - { - u32 cr1; -- int ret; - struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; - -- ret = pm_runtime_resume_and_get(i2c_dev->dev); -- if (ret < 0) -- return ret; -- - cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); - if (cr1 & STM32F7_I2C_CR1_PE) - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, -@@ -2318,54 +2391,68 @@ static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) - writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1); - writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2); - stm32f7_i2c_write_fm_plus_bits(i2c_dev, true); -+} - -- pm_runtime_put_sync(i2c_dev->dev); -+static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) -+{ -+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); - -- return ret; -+ stm32f7_i2c_regs_backup(i2c_dev); -+ -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) -+ clk_disable_unprepare(i2c_dev->clk); -+ -+ return 0; - } - --static int stm32f7_i2c_suspend(struct device *dev) -+static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) - { - struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); - int ret; - -- i2c_mark_adapter_suspended(&i2c_dev->adap); -- -- if (!device_may_wakeup(dev) && !dev->power.wakeup_path) { -- ret = stm32f7_i2c_regs_backup(i2c_dev); -- if (ret < 0) { -- i2c_mark_adapter_resumed(&i2c_dev->adap); -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { -+ ret = clk_prepare_enable(i2c_dev->clk); -+ if (ret) { -+ dev_err(dev, "failed to prepare_enable clock\n"); - return ret; - } -+ } - -+ stm32f7_i2c_regs_restore(i2c_dev); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32f7_i2c_suspend(struct device *dev) -+{ -+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -+ -+ i2c_mark_adapter_suspended(&i2c_dev->adap); -+ -+ if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) - pinctrl_pm_select_sleep_state(dev); -- pm_runtime_force_suspend(dev); -- } -+ -+ pm_runtime_force_suspend(dev); - - return 0; - } - --static int stm32f7_i2c_resume(struct device *dev) -+static int __maybe_unused stm32f7_i2c_resume(struct device *dev) - { - struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); - int ret; - -- if (!device_may_wakeup(dev) && !dev->power.wakeup_path) { -- ret = pm_runtime_force_resume(dev); -- if (ret < 0) -- return ret; -- pinctrl_pm_select_default_state(dev); -+ ret = pm_runtime_force_resume(dev); -+ if (ret < 0) -+ return ret; - -- ret = stm32f7_i2c_regs_restore(i2c_dev); -- if (ret < 0) -- return ret; -- } -+ if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) -+ pinctrl_pm_select_default_state(dev); - - i2c_mark_adapter_resumed(&i2c_dev->adap); - - return 0; - } --#endif - - static const struct dev_pm_ops stm32f7_i2c_pm_ops = { - SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend, -diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c -index 327cc2097..ceb150296 100644 ---- a/drivers/iio/adc/sd_adc_modulator.c -+++ b/drivers/iio/adc/sd_adc_modulator.c -@@ -9,10 +9,8 @@ - #include - #include - #include --#include --#include -- --static const struct iio_info iio_sd_mod_iio_info; -+#include -+#include - - static const struct iio_chan_spec iio_sd_mod_ch = { - .type = IIO_VOLTAGE, -@@ -22,34 +20,99 @@ static const struct iio_chan_spec iio_sd_mod_ch = { - .realbits = 1, - .shift = 0, - }, -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), -+}; -+ -+static const struct iio_chan_spec iio_sd_mod_ch_ads = { -+ .type = IIO_VOLTAGE, -+ .indexed = 1, -+ .scan_type = { -+ .sign = 'u', -+ .realbits = 1, -+ .shift = 0, -+ }, -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), -+ .differential = 1, -+}; -+ -+struct iio_sd_mod_priv { -+ int vref_mv; -+}; -+ -+static const struct of_device_id sd_adc_of_match[] = { -+ { .compatible = "sd-modulator", .data = &iio_sd_mod_ch }, -+ { .compatible = "ads1201", .data = &iio_sd_mod_ch_ads }, -+ { } -+}; -+ -+static int iio_sd_mod_read_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, int *val, -+ int *val2, long mask) -+{ -+ struct iio_sd_mod_priv *priv = iio_priv(indio_dev); -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_SCALE: -+ *val = priv->vref_mv; -+ *val2 = chan->scan_type.realbits; -+ return IIO_VAL_INT; -+ } -+ -+ return -EINVAL; -+} -+ -+static const struct iio_info iio_sd_mod_iio_info = { -+ .read_raw = iio_sd_mod_read_raw, - }; - - static int iio_sd_mod_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -+ struct iio_sd_mod_priv *priv; -+ struct regulator *vref; - struct iio_dev *iio; -+ int ret; - -- iio = devm_iio_device_alloc(dev, 0); -+ iio = devm_iio_device_alloc(dev, sizeof(*priv)); - if (!iio) - return -ENOMEM; - -+ iio->channels = (const struct iio_chan_spec *) -+ of_match_device(sd_adc_of_match, &pdev->dev)->data; -+ -+ priv = iio_priv(iio); -+ -+ iio->dev.parent = dev; -+ iio->dev.of_node = dev->of_node; - iio->name = dev_name(dev); - iio->info = &iio_sd_mod_iio_info; - iio->modes = INDIO_BUFFER_HARDWARE; -- - iio->num_channels = 1; -- iio->channels = &iio_sd_mod_ch; - -- platform_set_drvdata(pdev, iio); -+ vref = devm_regulator_get_optional(dev, "vref"); -+ if (IS_ERR(vref)) { -+ ret = PTR_ERR(vref); -+ if (ret != -ENODEV) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "vref get failed, %d\n", ret); -+ return ret; -+ } -+ } -+ -+ if (!IS_ERR(vref)) { -+ ret = regulator_get_voltage(vref); -+ if (ret < 0) { -+ dev_err(dev, "vref get failed, %d\n", ret); -+ return ret; -+ } -+ -+ priv->vref_mv = ret / 1000; -+ dev_dbg(dev, "vref+=%dmV\n", priv->vref_mv); -+ } - - return devm_iio_device_register(&pdev->dev, iio); - } - --static const struct of_device_id sd_adc_of_match[] = { -- { .compatible = "sd-modulator" }, -- { .compatible = "ads1201" }, -- { } --}; - MODULE_DEVICE_TABLE(of, sd_adc_of_match); - - static struct platform_driver iio_sd_mod_adc = { -diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index a83199b21..9d1ad6e38 100644 ---- a/drivers/iio/adc/stm32-adc-core.c -+++ b/drivers/iio/adc/stm32-adc-core.c -@@ -200,7 +200,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - { - u32 ckmode, presc, val; - unsigned long rate; -- int i, div; -+ int i, div, duty; - - /* stm32h7 bus clock is common for all ADC instances (mandatory) */ - if (!priv->bclk) { -@@ -224,6 +224,11 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - return -EINVAL; - } - -+ /* If duty is an error, kindly use at least /2 divider */ -+ duty = clk_get_scaled_duty_cycle(priv->aclk, 100); -+ if (duty < 0) -+ dev_warn(&pdev->dev, "adc clock duty: %d\n", duty); -+ - for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { - ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; - presc = stm32h7_adc_ckmodes_spec[i].presc; -@@ -232,6 +237,13 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - if (ckmode) - continue; - -+ /* -+ * For proper operation, clock duty cycle range is 49% -+ * to 51%. Apply at least /2 prescaler otherwise. -+ */ -+ if (div == 1 && (duty < 49 || duty > 51)) -+ continue; -+ - if ((rate / div) <= priv->max_clk_rate) - goto out; - } -@@ -244,6 +256,10 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - return -EINVAL; - } - -+ duty = clk_get_scaled_duty_cycle(priv->bclk, 100); -+ if (duty < 0) -+ dev_warn(&pdev->dev, "bus clock duty: %d\n", duty); -+ - for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { - ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; - presc = stm32h7_adc_ckmodes_spec[i].presc; -@@ -252,6 +268,9 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - if (!ckmode) - continue; - -+ if (div == 1 && (duty < 49 || duty > 51)) -+ continue; -+ - if ((rate / div) <= priv->max_clk_rate) - goto out; - } -diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h -index 2322809bf..7c924f463 100644 ---- a/drivers/iio/adc/stm32-adc-core.h -+++ b/drivers/iio/adc/stm32-adc-core.h -@@ -102,6 +102,9 @@ - #define STM32H7_ADC_CALFACT 0xC4 - #define STM32H7_ADC_CALFACT2 0xC8 - -+/* STM32MP1 - ADC2 instance option register */ -+#define STM32MP1_ADC2_OR 0xD0 -+ - /* STM32H7 - common registers for all ADC instances */ - #define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) - #define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) -@@ -168,11 +171,16 @@ enum stm32h7_adc_dmngt { - #define STM32H7_EOC_MST BIT(2) - - /* STM32H7_ADC_CCR - bit fields */ -+#define STM32H7_VBATEN BIT(24) -+#define STM32H7_VREFEN BIT(22) - #define STM32H7_PRESC_SHIFT 18 - #define STM32H7_PRESC_MASK GENMASK(21, 18) - #define STM32H7_CKMODE_SHIFT 16 - #define STM32H7_CKMODE_MASK GENMASK(17, 16) - -+/* STM32MP1_ADC2_OR - bit fields */ -+#define STM32MP1_VDDCOREEN BIT(0) -+ - /** - * struct stm32_adc_common - stm32 ADC driver common data (for all instances) - * @base: control registers base cpu addr -diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c -index 16c02c30d..6e9744944 100644 ---- a/drivers/iio/adc/stm32-adc.c -+++ b/drivers/iio/adc/stm32-adc.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -35,12 +36,14 @@ - #define STM32H7_BOOST_CLKRATE 20000000UL - - #define STM32_ADC_CH_MAX 20 /* max number of channels */ --#define STM32_ADC_CH_SZ 10 /* max channel name size */ -+#define STM32_ADC_CH_SZ 16 /* max channel name size */ - #define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */ - #define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ - #define STM32_ADC_TIMEOUT_US 100000 - #define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) - #define STM32_ADC_HW_STOP_DELAY_MS 100 -+#define STM32_ADC_CHAN_NONE -1 -+#define STM32_ADC_VREFINT_VOLTAGE 3300 - - #define STM32_DMA_BUFFER_SIZE PAGE_SIZE - -@@ -77,6 +80,30 @@ enum stm32_adc_extsel { - STM32_EXT20, - }; - -+enum stm32_adc_int_ch { -+ STM32_ADC_INT_CH_NONE = -1, -+ STM32_ADC_INT_CH_VDDCORE, -+ STM32_ADC_INT_CH_VREFINT, -+ STM32_ADC_INT_CH_VBAT, -+ STM32_ADC_INT_CH_NB, -+}; -+ -+/** -+ * struct stm32_adc_ic - ADC internal channels -+ * @name: name of the internal channel -+ * @idx: internal channel enum index -+ */ -+struct stm32_adc_ic { -+ const char *name; -+ u32 idx; -+}; -+ -+static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = { -+ { "vddcore", STM32_ADC_INT_CH_VDDCORE }, -+ { "vrefint", STM32_ADC_INT_CH_VREFINT }, -+ { "vbat", STM32_ADC_INT_CH_VBAT }, -+}; -+ - /** - * struct stm32_adc_trig_info - ADC trigger info - * @name: name of the trigger, corresponding to its source -@@ -113,6 +140,16 @@ struct stm32_adc_regs { - int shift; - }; - -+/** -+ * struct stm32_adc_vrefint - stm32 ADC internal reference voltage data -+ * @vrefint_cal: vrefint calibration value from nvmem -+ * @vrefint_data: vrefint actual value -+ */ -+struct stm32_adc_vrefint { -+ u32 vrefint_cal; -+ u32 vrefint_data; -+}; -+ - /** - * struct stm32_adc_regspec - stm32 registers definition - * @dr: data register offset -@@ -126,6 +163,9 @@ struct stm32_adc_regs { - * @res: resolution selection register & bitfield - * @smpr: smpr1 & smpr2 registers offset array - * @smp_bits: smpr1 & smpr2 index and bitfields -+ * @or_vdd: option register & vddcore bitfield -+ * @ccr_vbat: common register & vbat bitfield -+ * @ccr_vref: common register & vrefint bitfield - */ - struct stm32_adc_regspec { - const u32 dr; -@@ -139,6 +179,9 @@ struct stm32_adc_regspec { - const struct stm32_adc_regs res; - const u32 smpr[2]; - const struct stm32_adc_regs *smp_bits; -+ const struct stm32_adc_regs or_vdd; -+ const struct stm32_adc_regs ccr_vbat; -+ const struct stm32_adc_regs ccr_vref; - }; - - struct stm32_adc; -@@ -156,6 +199,7 @@ struct stm32_adc; - * @unprepare: optional unprepare routine (disable, power-down) - * @irq_clear: routine to clear irqs - * @smp_cycles: programmable sampling time (ADC clock cycles) -+ * @ts_vrefint_ns: vrefint minimum sampling time in ns - */ - struct stm32_adc_cfg { - const struct stm32_adc_regspec *regs; -@@ -169,6 +213,7 @@ struct stm32_adc_cfg { - void (*unprepare)(struct iio_dev *); - void (*irq_clear)(struct iio_dev *indio_dev, u32 msk); - const unsigned int *smp_cycles; -+ const unsigned int ts_vrefint_ns; - }; - - /** -@@ -193,7 +238,10 @@ struct stm32_adc_cfg { - * @pcsel: bitmask to preselect channels on some devices - * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) - * @cal: optional calibration data on some devices -+ * @vrefint: internal reference voltage data - * @chan_name: channel name array -+ * @num_diff: number of differential channels -+ * @int_ch: internal channel indexes array - */ - struct stm32_adc { - struct stm32_adc_common *common; -@@ -216,7 +264,10 @@ struct stm32_adc { - u32 pcsel; - u32 smpr_val[2]; - struct stm32_adc_calib cal; -+ struct stm32_adc_vrefint vrefint; - char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ]; -+ u32 num_diff; -+ int int_ch[STM32_ADC_INT_CH_NB]; - }; - - struct stm32_adc_diff_channel { -@@ -449,6 +500,24 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = { - .smp_bits = stm32h7_smp_bits, - }; - -+static const struct stm32_adc_regspec stm32mp1_adc_regspec = { -+ .dr = STM32H7_ADC_DR, -+ .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE }, -+ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE }, -+ .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC }, -+ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR }, -+ .sqr = stm32h7_sq, -+ .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT }, -+ .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK, -+ STM32H7_EXTSEL_SHIFT }, -+ .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, -+ .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, -+ .smp_bits = stm32h7_smp_bits, -+ .or_vdd = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN }, -+ .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN }, -+ .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN }, -+}; -+ - /** - * STM32 ADC registers access routines - * @adc: stm32 adc instance -@@ -581,6 +650,61 @@ static int stm32_adc_hw_start(struct device *dev) - return ret; - } - -+static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev) -+{ -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ u32 i, val, bits = 0, offset = 0; -+ -+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { -+ if (adc->int_ch[i] == STM32_ADC_CHAN_NONE) -+ continue; -+ -+ switch (i) { -+ case STM32_ADC_INT_CH_VDDCORE: -+ dev_dbg(&indio_dev->dev, "Enable VDDCore\n"); -+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vdd.reg, -+ adc->cfg->regs->or_vdd.mask); -+ break; -+ case STM32_ADC_INT_CH_VREFINT: -+ dev_dbg(&indio_dev->dev, "Enable VREFInt\n"); -+ offset = adc->cfg->regs->ccr_vref.reg; -+ bits |= adc->cfg->regs->ccr_vref.mask; -+ break; -+ case STM32_ADC_INT_CH_VBAT: -+ dev_dbg(&indio_dev->dev, "Enable VBAT\n"); -+ offset = adc->cfg->regs->ccr_vbat.reg; -+ bits |= adc->cfg->regs->ccr_vbat.mask; -+ break; -+ } -+ } -+ -+ if (bits) { -+ val = readl_relaxed(adc->common->base + offset); -+ val |= bits; -+ writel_relaxed(val, adc->common->base + offset); -+ } -+} -+ -+static void stm32_adc_int_ch_disable(struct stm32_adc *adc) -+{ -+ u32 val, bits, offset, i; -+ -+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vdd.reg, -+ adc->cfg->regs->or_vdd.mask); -+ -+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { -+ if (adc->int_ch[i] != STM32_ADC_CHAN_NONE) { -+ offset = adc->cfg->regs->ccr_vref.reg; -+ bits = adc->cfg->regs->ccr_vref.mask | -+ adc->cfg->regs->ccr_vbat.mask; -+ val = readl_relaxed(adc->common->base + offset); -+ val &= ~bits; -+ writel_relaxed(bits, adc->common->base + offset); -+ break; -+ } -+ } -+} -+ - /** - * stm32f4_adc_start_conv() - Start conversions for regular channels. - * @indio_dev: IIO device instance -@@ -949,11 +1073,13 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev) - goto pwr_dwn; - calib = ret; - -+ stm32_adc_int_ch_enable(indio_dev); -+ - stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); - - ret = stm32h7_adc_enable(indio_dev); - if (ret) -- goto pwr_dwn; -+ goto ch_disable; - - /* Either restore or read calibration result for future reference */ - if (calib) -@@ -969,6 +1095,8 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev) - - disable: - stm32h7_adc_disable(indio_dev); -+ch_disable: -+ stm32_adc_int_ch_disable(adc); - pwr_dwn: - stm32h7_adc_enter_pwr_down(adc); - -@@ -979,7 +1107,9 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev) - { - struct stm32_adc *adc = iio_priv(indio_dev); - -+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0); - stm32h7_adc_disable(indio_dev); -+ stm32_adc_int_ch_disable(adc); - stm32h7_adc_enter_pwr_down(adc); - } - -@@ -1225,15 +1355,35 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, - ret = stm32_adc_single_conv(indio_dev, chan, val); - else - ret = -EINVAL; -+ -+ /* If channel mask corresponds to vrefint, store data */ -+ if (adc->int_ch[STM32_ADC_INT_CH_VREFINT] == chan->channel) -+ adc->vrefint.vrefint_data = *val; -+ - iio_device_release_direct_mode(indio_dev); - return ret; - - case IIO_CHAN_INFO_SCALE: - if (chan->differential) { -- *val = adc->common->vref_mv * 2; -+ if (adc->vrefint.vrefint_data && -+ adc->vrefint.vrefint_cal) { -+ *val = STM32_ADC_VREFINT_VOLTAGE * 2 * -+ adc->vrefint.vrefint_cal / -+ adc->vrefint.vrefint_data; -+ } else { -+ *val = adc->common->vref_mv * 2; -+ } - *val2 = chan->scan_type.realbits; - } else { -- *val = adc->common->vref_mv; -+ /* Use vrefint data if available */ -+ if (adc->vrefint.vrefint_data && -+ adc->vrefint.vrefint_cal) { -+ *val = STM32_ADC_VREFINT_VOLTAGE * -+ adc->vrefint.vrefint_cal / -+ adc->vrefint.vrefint_data; -+ } else { -+ *val = adc->common->vref_mv; -+ } - *val2 = chan->scan_type.realbits; - } - return IIO_VAL_FRACTIONAL_LOG2; -@@ -1353,7 +1503,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) - * dma cyclic transfers are used, buffer is split into two periods. - * There should be : - * - always one buffer (period) dma is working on -- * - one buffer (period) driver can push with iio_trigger_poll(). -+ * - one buffer (period) driver can push data. - */ - watermark = min(watermark, val * (unsigned)(sizeof(u16))); - adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv); -@@ -1616,31 +1766,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p) - - dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); - -- if (!adc->dma_chan) { -- /* reset buffer index */ -- adc->bufi = 0; -- iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, -- pf->timestamp); -- } else { -- int residue = stm32_adc_dma_residue(adc); -- -- while (residue >= indio_dev->scan_bytes) { -- u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi]; -- -- iio_push_to_buffers_with_timestamp(indio_dev, buffer, -- pf->timestamp); -- residue -= indio_dev->scan_bytes; -- adc->bufi += indio_dev->scan_bytes; -- if (adc->bufi >= adc->rx_buf_sz) -- adc->bufi = 0; -- } -- } -- -+ /* reset buffer index */ -+ adc->bufi = 0; -+ iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, -+ pf->timestamp); - iio_trigger_notify_done(indio_dev->trig); - - /* re-enable eoc irq */ -- if (!adc->dma_chan) -- stm32_adc_conv_irq_enable(adc); -+ stm32_adc_conv_irq_enable(adc); - - return IRQ_HANDLED; - } -@@ -1686,6 +1819,14 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) - u32 period_ns, shift = smpr->shift, mask = smpr->mask; - unsigned int smp, r = smpr->reg; - -+ /* -+ * For vrefint channel, ensure that the sampling time cannot -+ * be lower than the one specified in the datasheet -+ */ -+ if (channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT] && -+ smp_ns < adc->cfg->ts_vrefint_ns) -+ smp_ns = adc->cfg->ts_vrefint_ns; -+ - /* Determine sampling time (ADC clock cycles) */ - period_ns = NSEC_PER_SEC / adc->common->rate; - for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++) -@@ -1735,17 +1876,11 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, - } - } - --static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) -+static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm32_adc *adc) - { - struct device_node *node = indio_dev->dev.of_node; -- struct stm32_adc *adc = iio_priv(indio_dev); - const struct stm32_adc_info *adc_info = adc->cfg->adc_info; -- struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; -- struct property *prop; -- const __be32 *cur; -- struct iio_chan_spec *channels; -- int scan_index = 0, num_channels = 0, num_diff = 0, ret, i; -- u32 val, smp = 0; -+ int num_channels = 0, ret; - - ret = of_property_count_u32_elems(node, "st,adc-channels"); - if (ret > adc_info->max_channels) { -@@ -1756,23 +1891,17 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) - } - - ret = of_property_count_elems_of_size(node, "st,adc-diff-channels", -- sizeof(*diff)); -+ sizeof(struct stm32_adc_diff_channel)); - if (ret > adc_info->max_channels) { - dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n"); - return -EINVAL; - } else if (ret > 0) { -- int size = ret * sizeof(*diff) / sizeof(u32); -- -- num_diff = ret; -+ adc->num_diff = ret; - num_channels += ret; -- ret = of_property_read_u32_array(node, "st,adc-diff-channels", -- (u32 *)diff, size); -- if (ret) -- return ret; - } - - if (!num_channels) { -- dev_err(&indio_dev->dev, "No channels configured\n"); -+ dev_err(indio_dev->dev.parent, "No channel found\n"); - return -ENODATA; - } - -@@ -1783,10 +1912,45 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) - return -EINVAL; - } - -- channels = devm_kcalloc(&indio_dev->dev, num_channels, -- sizeof(struct iio_chan_spec), GFP_KERNEL); -- if (!channels) -- return -ENOMEM; -+ return num_channels; -+} -+ -+static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev, -+ struct stm32_adc *adc, -+ struct iio_chan_spec *channels) -+{ -+ struct device_node *node = indio_dev->dev.of_node; -+ const struct stm32_adc_info *adc_info = adc->cfg->adc_info; -+ struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; -+ u32 num_diff = adc->num_diff; -+ int size = num_diff * sizeof(*diff) / sizeof(u32); -+ int scan_index = 0, val, ret, i; -+ struct property *prop; -+ const __be32 *cur; -+ u32 smp = 0; -+ -+ if (num_diff) { -+ ret = of_property_read_u32_array(node, "st,adc-diff-channels", -+ (u32 *)diff, size); -+ if (ret) { -+ dev_err(&indio_dev->dev, "Failed to get diff channels %d\n", ret); -+ return ret; -+ } -+ -+ for (i = 0; i < num_diff; i++) { -+ if (diff[i].vinp >= adc_info->max_channels || -+ diff[i].vinn >= adc_info->max_channels) { -+ dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", -+ diff[i].vinp, diff[i].vinn); -+ return -EINVAL; -+ } -+ -+ stm32_adc_chan_init_one(indio_dev, &channels[scan_index], -+ diff[i].vinp, diff[i].vinn, -+ scan_index, true); -+ scan_index++; -+ } -+ } - - of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) { - if (val >= adc_info->max_channels) { -@@ -1797,8 +1961,7 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) - /* Channel can't be configured both as single-ended & diff */ - for (i = 0; i < num_diff; i++) { - if (val == diff[i].vinp) { -- dev_err(&indio_dev->dev, -- "channel %d miss-configured\n", val); -+ dev_err(&indio_dev->dev, "channel %d misconfigured\n", val); - return -EINVAL; - } - } -@@ -1807,19 +1970,6 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) - scan_index++; - } - -- for (i = 0; i < num_diff; i++) { -- if (diff[i].vinp >= adc_info->max_channels || -- diff[i].vinn >= adc_info->max_channels) { -- dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", -- diff[i].vinp, diff[i].vinn); -- return -EINVAL; -- } -- stm32_adc_chan_init_one(indio_dev, &channels[scan_index], -- diff[i].vinp, diff[i].vinn, scan_index, -- true); -- scan_index++; -- } -- - for (i = 0; i < scan_index; i++) { - /* - * Using of_property_read_u32_index(), smp value will only be -@@ -1827,13 +1977,173 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) - * get either no value, 1 shared value for all indexes, or one - * value per channel. - */ -- of_property_read_u32_index(node, "st,min-sample-time-nsecs", -- i, &smp); -+ of_property_read_u32_index(node, "st,min-sample-time-nsecs", i, &smp); -+ - /* Prepare sampling time settings */ - stm32_adc_smpr_init(adc, channels[i].channel, smp); - } - -- indio_dev->num_channels = scan_index; -+ return scan_index; -+} -+ -+static int stm32_adc_get_int_ch(struct iio_dev *indio_dev, const char *ch_name, -+ int chan) -+{ -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ u16 vrefint; -+ int i, ret; -+ -+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { -+ if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) { -+ adc->int_ch[i] = chan; -+ /* If channel is vrefint get calibration data. */ -+ if (stm32_adc_ic[i].idx == STM32_ADC_INT_CH_VREFINT) { -+ ret = nvmem_cell_read_u16(&indio_dev->dev, "vrefint", &vrefint); -+ if (ret && ret != -ENOENT && ret != -EOPNOTSUPP) { -+ dev_err(&indio_dev->dev, "nvmem access error %d\n", ret); -+ return ret; -+ } -+ if (ret == -ENOENT) -+ dev_dbg(&indio_dev->dev, -+ "vrefint calibration not found\n"); -+ else -+ adc->vrefint.vrefint_cal = vrefint; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, -+ struct stm32_adc *adc, -+ struct iio_chan_spec *channels) -+{ -+ struct device_node *node = indio_dev->dev.of_node; -+ const struct stm32_adc_info *adc_info = adc->cfg->adc_info; -+ struct device_node *child; -+ const char *name; -+ int val, scan_index = 0, ret, i; -+ bool differential; -+ u32 vin[2]; -+ -+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) -+ adc->int_ch[i] = STM32_ADC_CHAN_NONE; -+ -+ for_each_available_child_of_node(node, child) { -+ ret = of_property_read_u32(child, "reg", &val); -+ if (ret) { -+ dev_err(&indio_dev->dev, "Missing channel index %d\n", ret); -+ goto err; -+ } -+ -+ ret = of_property_read_string(child, "label", &name); -+ /* label is optional */ -+ if (!ret) { -+ if (strlen(name) >= STM32_ADC_CH_SZ) { -+ dev_err(&indio_dev->dev, "Label %s exceeds %d characters\n", -+ name, STM32_ADC_CH_SZ); -+ return -EINVAL; -+ } -+ strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); -+ ret = stm32_adc_get_int_ch(indio_dev, name, val); -+ if (ret) -+ goto err; -+ } else if (ret != -EINVAL) { -+ dev_err(&indio_dev->dev, "Invalid label %d\n", ret); -+ goto err; -+ } -+ -+ if (val >= adc_info->max_channels) { -+ dev_err(&indio_dev->dev, "Invalid channel %d\n", val); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ differential = false; -+ ret = of_property_read_u32_array(child, "diff-channels", vin, 2); -+ /* diff-channels is optional */ -+ if (!ret) { -+ differential = true; -+ if (vin[0] != val || vin[1] >= adc_info->max_channels) { -+ dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", -+ vin[0], vin[1]); -+ goto err; -+ } -+ } else if (ret != -EINVAL) { -+ dev_err(&indio_dev->dev, "Invalid diff-channels property %d\n", ret); -+ goto err; -+ } -+ -+ stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val, -+ vin[1], scan_index, differential); -+ -+ ret = of_property_read_u32(child, "st,min-sample-time-nsecs", &val); -+ /* st,min-sample-time-nsecs is optional */ -+ if (!ret) { -+ stm32_adc_smpr_init(adc, channels[scan_index].channel, val); -+ if (differential) -+ stm32_adc_smpr_init(adc, vin[1], val); -+ } else if (ret != -EINVAL) { -+ dev_err(&indio_dev->dev, "Invalid st,min-sample-time-nsecs property %d\n", -+ ret); -+ goto err; -+ } -+ -+ scan_index++; -+ } -+ -+ return scan_index; -+ -+err: -+ of_node_put(child); -+ -+ return ret; -+} -+ -+static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) -+{ -+ struct device_node *node = indio_dev->dev.of_node; -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ const struct stm32_adc_info *adc_info = adc->cfg->adc_info; -+ struct iio_chan_spec *channels; -+ int num_channels = 0, ret; -+ bool legacy = false; -+ -+ num_channels = of_get_available_child_count(node); -+ /* -+ * If no channels have been found, fallback to channels legacy properties. -+ * Legacy channel properties will be ignored, if some channels are -+ * already defined using the standard binding. -+ */ -+ if (!num_channels) { -+ ret = stm32_adc_get_legacy_chan_count(indio_dev, adc); -+ if (ret < 0) -+ return ret; -+ -+ legacy = true; -+ num_channels = ret; -+ } -+ -+ if (num_channels > adc_info->max_channels) { -+ dev_err(&indio_dev->dev, "Channel number [%d] exceeds %d\n", -+ num_channels, adc_info->max_channels); -+ return -EINVAL; -+ } -+ -+ channels = devm_kcalloc(&indio_dev->dev, num_channels, -+ sizeof(struct iio_chan_spec), GFP_KERNEL); -+ if (!channels) -+ return -ENOMEM; -+ -+ if (legacy) -+ ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels); -+ else -+ ret = stm32_adc_generic_chan_init(indio_dev, adc, channels); -+ if (ret < 0) -+ return ret; -+ -+ indio_dev->num_channels = ret; - indio_dev->channels = channels; - - return 0; -@@ -2105,7 +2415,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { - }; - - static const struct stm32_adc_cfg stm32mp1_adc_cfg = { -- .regs = &stm32h7_adc_regspec, -+ .regs = &stm32mp1_adc_regspec, - .adc_info = &stm32h7_adc_info, - .trigs = stm32h7_adc_trigs, - .has_vregready = true, -@@ -2115,6 +2425,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { - .unprepare = stm32h7_adc_unprepare, - .smp_cycles = stm32h7_adc_smp_cycles, - .irq_clear = stm32h7_adc_irq_clear, -+ .ts_vrefint_ns = 4300, - }; - - static const struct of_device_id stm32_adc_of_match[] = { -diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c -index 9234f1416..10e5a48cd 100644 ---- a/drivers/iio/adc/stm32-dfsdm-adc.c -+++ b/drivers/iio/adc/stm32-dfsdm-adc.c -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -67,6 +68,13 @@ struct stm32_dfsdm_dev_data { - const struct regmap_config *regmap_cfg; - }; - -+struct stm32_dfsdm_sd_chan_info { -+ int scale_val; -+ int scale_val2; -+ int offset; -+ unsigned int differential; -+}; -+ - struct stm32_dfsdm_adc { - struct stm32_dfsdm *dfsdm; - const struct stm32_dfsdm_dev_data *dev_data; -@@ -79,6 +87,7 @@ struct stm32_dfsdm_adc { - struct iio_hw_consumer *hwc; - struct completion completion; - u32 *buffer; -+ struct stm32_dfsdm_sd_chan_info *sd_chan; - - /* Audio specific */ - unsigned int spi_freq; /* SPI bus clock frequency */ -@@ -1224,7 +1233,13 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, - int *val2, long mask) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -- int ret; -+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; -+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; -+ u32 max = flo->max << (flo->lshift - chan->scan_type.shift); -+ int ret, idx = chan->scan_index; -+ -+ if (flo->lshift < chan->scan_type.shift) -+ max = flo->max >> (chan->scan_type.shift - flo->lshift); - - switch (mask) { - case IIO_CHAN_INFO_RAW: -@@ -1260,6 +1275,39 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, - *val = adc->sample_freq; - - return IIO_VAL_INT; -+ -+ case IIO_CHAN_INFO_SCALE: -+ /* -+ * Scale is expressed in mV. -+ * When fast mode is disabled, actual resolution may be lower -+ * than 2^n, where n=realbits-1. -+ * This leads to underestimating input voltage. To -+ * compensate this deviation, the voltage reference can be -+ * corrected with a factor = realbits resolution / actual max -+ */ -+ *val = div_u64((u64)adc->sd_chan[idx].scale_val * -+ (u64)BIT(DFSDM_DATA_RES - 1), max); -+ *val2 = chan->scan_type.realbits; -+ if (adc->sd_chan[idx].differential) -+ *val *= 2; -+ return IIO_VAL_FRACTIONAL_LOG2; -+ -+ case IIO_CHAN_INFO_OFFSET: -+ /* -+ * DFSDM output data are in the range [-2^n,2^n-1], -+ * with n=realbits-1. -+ * - Differential modulator: -+ * Offset correspond to SD modulator offset. -+ * - Single ended modulator: -+ * Input is in [0V,Vref] range, where 0V corresponds to -2^n. -+ * Add 2^n to offset. (i.e. middle of input range) -+ * offset = offset(sd) * vref / res(sd) * max / vref. -+ */ -+ *val = div_u64((u64)max * adc->sd_chan[idx].offset, -+ BIT(adc->sd_chan[idx].scale_val2 - 1)); -+ if (!adc->sd_chan[idx].differential) -+ *val += max; -+ return IIO_VAL_INT; - } - - return -EINVAL; -@@ -1384,7 +1432,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, - * IIO_CHAN_INFO_RAW: used to compute regular conversion - * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling - */ -- ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); -+ ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | -+ BIT(IIO_CHAN_INFO_SCALE) | -+ BIT(IIO_CHAN_INFO_OFFSET); - ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | - BIT(IIO_CHAN_INFO_SAMP_FREQ); - -@@ -1394,7 +1444,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, - ch->scan_type.shift = 8; - } - ch->scan_type.sign = 's'; -- ch->scan_type.realbits = 24; -+ ch->scan_type.realbits = DFSDM_DATA_RES; - ch->scan_type.storagebits = 32; - - return stm32_dfsdm_chan_configure(adc->dfsdm, -@@ -1435,8 +1485,10 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) - { - struct iio_chan_spec *ch; - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ struct iio_channel *channels, *chan; -+ struct stm32_dfsdm_sd_chan_info *sd_chan; - int num_ch; -- int ret, chan_idx; -+ int ret, chan_idx, val2; - - adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; - ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp); -@@ -1460,6 +1512,21 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) - if (!ch) - return -ENOMEM; - -+ /* Get SD modulator channels */ -+ channels = iio_channel_get_all(&indio_dev->dev); -+ if (IS_ERR(channels)) { -+ dev_err(&indio_dev->dev, "Failed to get channel %ld\n", -+ PTR_ERR(channels)); -+ return PTR_ERR(channels); -+ } -+ chan = &channels[0]; -+ -+ adc->sd_chan = devm_kzalloc(&indio_dev->dev, -+ sizeof(*adc->sd_chan) * num_ch, GFP_KERNEL); -+ if (!adc->sd_chan) -+ return -ENOMEM; -+ sd_chan = adc->sd_chan; -+ - for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { - ch[chan_idx].scan_index = chan_idx; - ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]); -@@ -1467,6 +1534,38 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) - dev_err(&indio_dev->dev, "Channels init failed\n"); - return ret; - } -+ -+ if (!chan->indio_dev) -+ return -EINVAL; -+ -+ ret = iio_read_channel_scale(chan, &sd_chan->scale_val, -+ &sd_chan->scale_val2); -+ if (ret < 0) { -+ dev_err(&indio_dev->dev, -+ "Failed to get channel %d scale\n", chan_idx); -+ return ret; -+ } -+ -+ if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_OFFSET)) { -+ ret = iio_read_channel_offset(chan, &sd_chan->offset, -+ &val2); -+ if (ret < 0) { -+ dev_err(&indio_dev->dev, -+ "Failed to get channel %d offset\n", -+ chan_idx); -+ return ret; -+ } -+ } -+ -+ sd_chan->differential = chan->channel->differential; -+ -+ dev_dbg(&indio_dev->dev, "Channel %d %s scale ref=%d offset=%d", -+ chan_idx, chan->channel->differential ? -+ "differential" : "single-ended", -+ sd_chan->scale_val, sd_chan->offset); -+ -+ chan++; -+ sd_chan++; - } - - indio_dev->num_channels = num_ch; -@@ -1521,6 +1620,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = { - }, - {} - }; -+MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match); - - static int stm32_dfsdm_adc_probe(struct platform_device *pdev) - { -diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c -index 42a737770..627557d8e 100644 ---- a/drivers/iio/adc/stm32-dfsdm-core.c -+++ b/drivers/iio/adc/stm32-dfsdm-core.c -@@ -6,6 +6,7 @@ - * Author(s): Arnaud Pouliquen for STMicroelectronics. - */ - -+#include - #include - #include - #include -@@ -20,6 +21,7 @@ - #include "stm32-dfsdm.h" - - struct stm32_dfsdm_dev_data { -+ u32 ipid; - unsigned int num_filters; - unsigned int num_channels; - const struct regmap_config *regmap_cfg; -@@ -27,8 +29,6 @@ struct stm32_dfsdm_dev_data { - - #define STM32H7_DFSDM_NUM_FILTERS 4 - #define STM32H7_DFSDM_NUM_CHANNELS 8 --#define STM32MP1_DFSDM_NUM_FILTERS 6 --#define STM32MP1_DFSDM_NUM_CHANNELS 8 - - static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) - { -@@ -75,8 +75,7 @@ static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = { - }; - - static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = { -- .num_filters = STM32MP1_DFSDM_NUM_FILTERS, -- .num_channels = STM32MP1_DFSDM_NUM_CHANNELS, -+ .ipid = STM32MP15_IPIDR_NUMBER, - .regmap_cfg = &stm32mp1_dfsdm_regmap_cfg, - }; - -@@ -298,6 +297,64 @@ static const struct of_device_id stm32_dfsdm_of_match[] = { - }; - MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); - -+static int stm32_dfsdm_config_check(struct platform_device *pdev, -+ struct dfsdm_priv *priv, -+ const struct stm32_dfsdm_dev_data *dev_data) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct device_node *child; -+ struct stm32_dfsdm *dfsdm = &priv->dfsdm; -+ const char *compat; -+ int ret, count = 0; -+ u32 id, val; -+ -+ if (!dev_data->ipid) { -+ dfsdm->num_fls = dev_data->num_filters; -+ dfsdm->num_chs = dev_data->num_channels; -+ return 0; -+ } -+ -+ ret = regmap_read(dfsdm->regmap, DFSDM_IPIDR, &val); -+ if (ret) -+ return ret; -+ -+ id = FIELD_GET(DFSDM_IPIDR_MASK, val); -+ if (id != dev_data->ipid) { -+ dev_err(&pdev->dev, "Unexpected IP version: 0x%x", id); -+ return -EINVAL; -+ } -+ -+ for_each_child_of_node(np, child) { -+ ret = of_property_read_string(child, "compatible", &compat); -+ if (ret) -+ continue; -+ count++; -+ } -+ -+ ret = regmap_read(dfsdm->regmap, DFSDM_HWCFGR, &val); -+ if (ret) -+ return ret; -+ -+ dfsdm->num_fls = FIELD_GET(DFSDM_HWCFGR_NBF_MASK, val); -+ dfsdm->num_chs = FIELD_GET(DFSDM_HWCFGR_NBT_MASK, val); -+ -+ if (count > dfsdm->num_fls) { -+ dev_err(&pdev->dev, "Unexpected child number: %d", count); -+ return -EINVAL; -+ } -+ -+ ret = regmap_read(dfsdm->regmap, DFSDM_VERR, &val); -+ if (ret) -+ return ret; -+ -+ dev_dbg(&pdev->dev, "DFSDM version: %lu.%lu. %d channels/%d filters\n", -+ FIELD_GET(DFSDM_VERR_MAJREV_MASK, val), -+ FIELD_GET(DFSDM_VERR_MINREV_MASK, val), -+ dfsdm->num_chs, dfsdm->num_fls); -+ -+ return 0; -+} -+ - static int stm32_dfsdm_probe(struct platform_device *pdev) - { - struct dfsdm_priv *priv; -@@ -314,18 +371,6 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) - dev_data = of_device_get_match_data(&pdev->dev); - - dfsdm = &priv->dfsdm; -- dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters, -- sizeof(*dfsdm->fl_list), GFP_KERNEL); -- if (!dfsdm->fl_list) -- return -ENOMEM; -- -- dfsdm->num_fls = dev_data->num_filters; -- dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels, -- sizeof(*dfsdm->ch_list), -- GFP_KERNEL); -- if (!dfsdm->ch_list) -- return -ENOMEM; -- dfsdm->num_chs = dev_data->num_channels; - - ret = stm32_dfsdm_parse_of(pdev, priv); - if (ret < 0) -@@ -341,6 +386,20 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) - return ret; - } - -+ ret = stm32_dfsdm_config_check(pdev, priv, dev_data); -+ if (ret < 0) -+ return ret; -+ -+ dfsdm->fl_list = devm_kcalloc(&pdev->dev, dfsdm->num_fls, -+ sizeof(*dfsdm->fl_list), GFP_KERNEL); -+ if (!dfsdm->fl_list) -+ return -ENOMEM; -+ -+ dfsdm->ch_list = devm_kcalloc(&pdev->dev, dfsdm->num_chs, -+ sizeof(*dfsdm->ch_list), GFP_KERNEL); -+ if (!dfsdm->ch_list) -+ return -ENOMEM; -+ - platform_set_drvdata(pdev, dfsdm); - - ret = stm32_dfsdm_clk_prepare_enable(dfsdm); -diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h -index 4afc1f528..4f230e2a7 100644 ---- a/drivers/iio/adc/stm32-dfsdm.h -+++ b/drivers/iio/adc/stm32-dfsdm.h -@@ -13,25 +13,28 @@ - - /* - * STM32 DFSDM - global register map -- * ________________________________________________________ -- * | Offset | Registers block | -- * -------------------------------------------------------- -- * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS | -- * -------------------------------------------------------- -- * | 0x020 | CHANNEL 1 | -- * -------------------------------------------------------- -- * | ... | ..... | -- * -------------------------------------------------------- -- * | 0x0E0 | CHANNEL 7 | -- * -------------------------------------------------------- -- * | 0x100 | FILTER 0 + COMMON FILTER FIELDs | -- * -------------------------------------------------------- -- * | 0x200 | FILTER 1 | -- * -------------------------------------------------------- -- * | 0x300 | FILTER 2 | -- * -------------------------------------------------------- -- * | 0x400 | FILTER 3 | -- * -------------------------------------------------------- -+ * __________________________________________________________ -+ * | Offset | Registers block | -+ * ---------------------------------------------------------- -+ * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS | -+ * ---------------------------------------------------------- -+ * | 0x020 | CHANNEL 1 | -+ * ---------------------------------------------------------- -+ * | ... | ..... | -+ * ---------------------------------------------------------- -+ * | 0x20 x n | CHANNEL n | -+ * ---------------------------------------------------------- -+ * | 0x100 | FILTER 0 + COMMON FILTER FIELDs | -+ * ---------------------------------------------------------- -+ * | 0x200 | FILTER 1 | -+ * ---------------------------------------------------------- -+ * | | ..... | -+ * ---------------------------------------------------------- -+ * | 0x100 x m| FILTER m | -+ * ---------------------------------------------------------- -+ * ---------------------------------------------------------- -+ * | 0x7F0-7FC| Identification registers | -+ * ---------------------------------------------------------- - */ - - /* -@@ -231,6 +234,34 @@ - #define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8) - #define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v) - -+/* -+ * Identification register definitions -+ */ -+#define DFSDM_HWCFGR 0x7F0 -+#define DFSDM_VERR 0x7F4 -+#define DFSDM_IPIDR 0x7F8 -+#define DFSDM_SIDR 0x7FC -+ -+/* HWCFGR: Hardware configuration register */ -+#define DFSDM_HWCFGR_NBT_SHIFT 0 -+#define DFSDM_HWCFGR_NBT_MASK GENMASK(7, 0) -+#define DFSDM_HWCFGR_NBF_SHIFT 8 -+#define DFSDM_HWCFGR_NBF_MASK GENMASK(15, 8) -+ -+/* VERR: Version register */ -+#define DFSDM_VERR_MINREV_SHIFT 0 -+#define DFSDM_VERR_MINREV_MASK GENMASK(3, 0) -+#define DFSDM_VERR_MAJREV_SHIFT 4 -+#define DFSDM_VERR_MAJREV_MASK GENMASK(7, 4) -+ -+/* IPDR: Identification register */ -+#define DFSDM_IPIDR_MASK GENMASK(31, 0) -+ -+/* SIDR: Size identification register */ -+#define DFSDM_SIDR_MASK GENMASK(31, 0) -+ -+#define STM32MP15_IPIDR_NUMBER 0x00110031 -+ - /* DFSDM filter order */ - enum stm32_dfsdm_sinc_order { - DFSDM_FASTSINC_ORDER, /* FastSinc filter type */ -diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index 8662d7b7b..d38896125 100644 ---- a/drivers/irqchip/irq-stm32-exti.c -+++ b/drivers/irqchip/irq-stm32-exti.c -@@ -132,7 +132,6 @@ static const struct stm32_exti_drv_data stm32h7xx_drv_data = { - - static const struct stm32_exti_bank stm32mp1_exti_b1 = { - .imr_ofst = 0x80, -- .emr_ofst = 0x84, - .rtsr_ofst = 0x00, - .ftsr_ofst = 0x04, - .swier_ofst = 0x08, -@@ -142,7 +141,6 @@ static const struct stm32_exti_bank stm32mp1_exti_b1 = { - - static const struct stm32_exti_bank stm32mp1_exti_b2 = { - .imr_ofst = 0x90, -- .emr_ofst = 0x94, - .rtsr_ofst = 0x20, - .ftsr_ofst = 0x24, - .swier_ofst = 0x28, -@@ -152,7 +150,6 @@ static const struct stm32_exti_bank stm32mp1_exti_b2 = { - - static const struct stm32_exti_bank stm32mp1_exti_b3 = { - .imr_ofst = 0xA0, -- .emr_ofst = 0xA4, - .rtsr_ofst = 0x40, - .ftsr_ofst = 0x44, - .swier_ofst = 0x48, -@@ -193,7 +190,16 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = { - { .exti = 23, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct }, - { .exti = 24, .irq_parent = 95, .chip = &stm32_exti_h_chip_direct }, - { .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 26, .irq_parent = 37, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 27, .irq_parent = 38, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 28, .irq_parent = 39, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 29, .irq_parent = 71, .chip = &stm32_exti_h_chip_direct }, - { .exti = 30, .irq_parent = 52, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 31, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 32, .irq_parent = 82, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 43, .irq_parent = 75, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 44, .irq_parent = 98, .chip = &stm32_exti_h_chip_direct }, - { .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct }, - { .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct }, - { .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct }, -@@ -534,6 +540,9 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) - unlock: - raw_spin_unlock(&chip_data->rlock); - -+ if (d->parent_data->chip) -+ irq_chip_set_type_parent(d, type); -+ - return err; - } - -@@ -551,6 +560,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) - - raw_spin_unlock(&chip_data->rlock); - -+ if (d->parent_data->chip) -+ irq_chip_set_wake_parent(d, on); -+ - return 0; - } - -@@ -560,7 +572,13 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, - if (d->parent_data->chip) - return irq_chip_set_affinity_parent(d, dest, force); - -- return -EINVAL; -+ return IRQ_SET_MASK_OK_DONE; -+} -+ -+static void stm32_exti_h_ack(struct irq_data *d) -+{ -+ if (d->parent_data->chip) -+ irq_chip_ack_parent(d); - } - - static int __maybe_unused stm32_exti_h_suspend(void) -@@ -624,6 +642,7 @@ static int stm32_exti_h_retrigger(struct irq_data *d) - static struct irq_chip stm32_exti_h_chip = { - .name = "stm32-exti-h", - .irq_eoi = stm32_exti_h_eoi, -+ .irq_ack = stm32_exti_h_ack, - .irq_mask = stm32_exti_h_mask, - .irq_unmask = stm32_exti_h_unmask, - .irq_retrigger = stm32_exti_h_retrigger, -@@ -637,8 +656,8 @@ static struct irq_chip stm32_exti_h_chip_direct = { - .name = "stm32-exti-h-direct", - .irq_eoi = irq_chip_eoi_parent, - .irq_ack = irq_chip_ack_parent, -- .irq_mask = irq_chip_mask_parent, -- .irq_unmask = irq_chip_unmask_parent, -+ .irq_mask = stm32_exti_h_mask, -+ .irq_unmask = stm32_exti_h_unmask, - .irq_retrigger = irq_chip_retrigger_hierarchy, - .irq_set_type = irq_chip_set_type_parent, - .irq_set_wake = stm32_exti_h_set_wake, -@@ -669,14 +688,28 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm, - - irq_domain_set_hwirq_and_chip(dm, virq, hwirq, desc->chip, - chip_data); -- if (desc->irq_parent) { -+ /* -+ * EXTI 55 to 60 are mapped to PWR interrupt controller. -+ * The hwirq translation is done diferently than for GIC. -+ */ -+ if (hwirq >= 55 && hwirq <= 60) { - p_fwspec.fwnode = dm->parent->fwnode; -- p_fwspec.param_count = 3; -- p_fwspec.param[0] = GIC_SPI; -- p_fwspec.param[1] = desc->irq_parent; -- p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; -+ p_fwspec.param_count = 2; -+ p_fwspec.param[0] = hwirq - 55; -+ p_fwspec.param[1] = fwspec->param[1]; - - return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); -+ } else { -+ if (desc->irq_parent) { -+ p_fwspec.fwnode = dm->parent->fwnode; -+ p_fwspec.param_count = 3; -+ p_fwspec.param[0] = GIC_SPI; -+ p_fwspec.param[1] = desc->irq_parent; -+ p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; -+ -+ return irq_domain_alloc_irqs_parent(dm, virq, 1, -+ &p_fwspec); -+ } - } - - return 0; -@@ -738,7 +771,8 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, - * clear registers to avoid residue - */ - writel_relaxed(0, base + stm32_bank->imr_ofst); -- writel_relaxed(0, base + stm32_bank->emr_ofst); -+ if (stm32_bank->emr_ofst) -+ writel_relaxed(0, base + stm32_bank->emr_ofst); - - pr_info("%pOF: bank%d\n", node, bank_idx); - -@@ -841,11 +875,12 @@ static int stm32_exti_probe(struct platform_device *pdev) - { - int ret, i; - struct device *dev = &pdev->dev; -- struct device_node *np = dev->of_node; -+ struct device_node *child, *np = dev->of_node; - struct irq_domain *parent_domain, *domain; - struct stm32_exti_host_data *host_data; - const struct stm32_exti_drv_data *drv_data; - struct resource *res; -+ u32 nirqs; - - host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); - if (!host_data) -@@ -913,6 +948,34 @@ static int stm32_exti_probe(struct platform_device *pdev) - if (ret) - return ret; - -+ for_each_child_of_node(np, child) { -+ parent_domain = irq_find_host(of_irq_find_parent(child)); -+ if (!parent_domain) { -+ dev_err(dev, "child interrupt-parent not found\n"); -+ return -EINVAL; -+ } -+ -+ ret = of_property_read_u32(child, "st,irq-number", &nirqs); -+ if (ret || !nirqs) { -+ dev_err(dev, "Missing or bad irq-number property\n"); -+ return -EINVAL; -+ } -+ -+ domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs, -+ child, -+ &stm32_exti_h_domain_ops, -+ host_data); -+ if (!domain) { -+ dev_err(dev, "Could not register exti domain\n"); -+ return -ENOMEM; -+ } -+ -+ ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, -+ domain); -+ if (ret) -+ return ret; -+ } -+ - stm32_exti_h_syscore_init(host_data); - - return 0; --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0009-ARM-5.10.61-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0009-ARM-5.10.61-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch deleted file mode 100644 index e352b06..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0009-ARM-5.10.61-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch +++ /dev/null @@ -1,3099 +0,0 @@ -From 471f33cca896724288eed3ab00e022aab3302b08 Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:45 +0200 -Subject: [PATCH 09/23] ARM 5.10.61-stm32mp1-r2 MAILBOX-REMOTEPROC-RPMSG - ---- - Documentation/staging/remoteproc.rst | 22 + - drivers/mailbox/Kconfig | 7 + - drivers/mailbox/Makefile | 2 + - drivers/mailbox/arm-smc-mailbox.c | 166 ++++++ - drivers/remoteproc/Kconfig | 29 + - drivers/remoteproc/Makefile | 3 + - drivers/remoteproc/remoteproc_core.c | 19 +- - drivers/remoteproc/rproc_srm_core.c | 303 ++++++++++ - drivers/remoteproc/rproc_srm_core.h | 98 ++++ - drivers/remoteproc/rproc_srm_dev.c | 744 +++++++++++++++++++++++++ - drivers/remoteproc/stm32_rproc.c | 346 ++++++++---- - drivers/remoteproc/tee_remoteproc.c | 378 +++++++++++++ - drivers/rpmsg/Kconfig | 9 + - drivers/rpmsg/Makefile | 1 + - drivers/rpmsg/rpmsg_core.c | 19 + - drivers/rpmsg/rpmsg_internal.h | 2 + - drivers/rpmsg/rpmsg_tty.c | 342 ++++++++++++ - drivers/rpmsg/virtio_rpmsg_bus.c | 11 + - include/linux/mailbox/arm-smccc-mbox.h | 20 + - include/linux/rpmsg.h | 9 + - include/linux/tee_remoteproc.h | 101 ++++ - 21 files changed, 2516 insertions(+), 115 deletions(-) - create mode 100644 drivers/mailbox/arm-smc-mailbox.c - create mode 100644 drivers/remoteproc/rproc_srm_core.c - create mode 100644 drivers/remoteproc/rproc_srm_core.h - create mode 100644 drivers/remoteproc/rproc_srm_dev.c - create mode 100644 drivers/remoteproc/tee_remoteproc.c - create mode 100644 drivers/rpmsg/rpmsg_tty.c - create mode 100644 include/linux/mailbox/arm-smccc-mbox.h - create mode 100644 include/linux/tee_remoteproc.h - -diff --git a/Documentation/staging/remoteproc.rst b/Documentation/staging/remoteproc.rst -index 9cccd3dd6..c2367e3c0 100644 ---- a/Documentation/staging/remoteproc.rst -+++ b/Documentation/staging/remoteproc.rst -@@ -357,3 +357,25 @@ Of course, RSC_VDEV resource entries are only good enough for static - allocation of virtio devices. Dynamic allocations will also be made possible - using the rpmsg bus (similar to how we already do dynamic allocations of - rpmsg channels; read more about it in rpmsg.txt). -+ -+8. System Resource Manager (SRM) -+ -+Since some resources are shared (directly or not) between the processors, a -+processor cannot manage such resources without potentially impacting the other -+processors : as an example, if a processor changes the frequency of a clock, the -+frequency of another clock managed by another processor may be updated too. -+ -+The System Resource Manager prevents such resource conflicts between the -+processors : it reserves and initializes the system resources of the peripherals -+assigned to a remote processor. -+ -+As of today the following resources are controlled by the SRM: -+- clocks -+- regulators (power supplies) -+ -+The SRM is implemented as an 'rproc_subdev' and registered to remoteproc_core. -+Unlike the virtio device (vdev), the SRM subdev is probed *before* the rproc -+boots, ensuring the availability of the resources before the remoteproc starts. -+ -+The resources handled by the SRM are defined in the DeviceTree: please read -+Documentation/devicetree/bindings/remoteproc/rproc-srm.txt for details. -diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig -index 05b1009e2..3d388bf2d 100644 ---- a/drivers/mailbox/Kconfig -+++ b/drivers/mailbox/Kconfig -@@ -16,6 +16,13 @@ config ARM_MHU - The controller has 3 mailbox channels, the last of which can be - used in Secure mode only. - -+config ARM_SMC_MBOX -+ tristate "Generic ARM smc mailbox" -+ depends on OF && HAVE_ARM_SMCCC -+ help -+ Generic mailbox driver which uses ARM smc calls to call into -+ firmware for triggering mailboxes. -+ - config IMX_MBOX - tristate "i.MX Mailbox" - depends on ARCH_MXC || COMPILE_TEST -diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile -index 2e06e02b2..24841a298 100644 ---- a/drivers/mailbox/Makefile -+++ b/drivers/mailbox/Makefile -@@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o - - obj-$(CONFIG_ARM_MHU) += arm_mhu.o arm_mhu_db.o - -+obj-$(CONFIG_ARM_SMC_MBOX) += arm-smc-mailbox.o -+ - obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o - - obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o -diff --git a/drivers/mailbox/arm-smc-mailbox.c b/drivers/mailbox/arm-smc-mailbox.c -new file mode 100644 -index 000000000..a6ec56f41 ---- /dev/null -+++ b/drivers/mailbox/arm-smc-mailbox.c -@@ -0,0 +1,166 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2016,2017 ARM Ltd. -+ * Copyright 2019 NXP -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+typedef unsigned long (smc_mbox_fn)(unsigned int, unsigned long, -+ unsigned long, unsigned long, -+ unsigned long, unsigned long, -+ unsigned long); -+ -+struct arm_smc_chan_data { -+ unsigned int function_id; -+ smc_mbox_fn *invoke_smc_mbox_fn; -+}; -+ -+static int arm_smc_send_data(struct mbox_chan *link, void *data) -+{ -+ struct arm_smc_chan_data *chan_data = link->con_priv; -+ struct arm_smccc_mbox_cmd *cmd = data; -+ unsigned long ret; -+ -+ if (ARM_SMCCC_IS_64(chan_data->function_id)) { -+ ret = chan_data->invoke_smc_mbox_fn(chan_data->function_id, -+ cmd->args_smccc64[0], -+ cmd->args_smccc64[1], -+ cmd->args_smccc64[2], -+ cmd->args_smccc64[3], -+ cmd->args_smccc64[4], -+ cmd->args_smccc64[5]); -+ } else { -+ ret = chan_data->invoke_smc_mbox_fn(chan_data->function_id, -+ cmd->args_smccc32[0], -+ cmd->args_smccc32[1], -+ cmd->args_smccc32[2], -+ cmd->args_smccc32[3], -+ cmd->args_smccc32[4], -+ cmd->args_smccc32[5]); -+ } -+ -+ mbox_chan_received_data(link, (void *)ret); -+ -+ return 0; -+} -+ -+static unsigned long __invoke_fn_hvc(unsigned int function_id, -+ unsigned long arg0, unsigned long arg1, -+ unsigned long arg2, unsigned long arg3, -+ unsigned long arg4, unsigned long arg5) -+{ -+ struct arm_smccc_res res; -+ -+ arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, -+ arg5, 0, &res); -+ return res.a0; -+} -+ -+static unsigned long __invoke_fn_smc(unsigned int function_id, -+ unsigned long arg0, unsigned long arg1, -+ unsigned long arg2, unsigned long arg3, -+ unsigned long arg4, unsigned long arg5) -+{ -+ struct arm_smccc_res res; -+ -+ arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, -+ arg5, 0, &res); -+ return res.a0; -+} -+ -+static const struct mbox_chan_ops arm_smc_mbox_chan_ops = { -+ .send_data = arm_smc_send_data, -+}; -+ -+static struct mbox_chan * -+arm_smc_mbox_of_xlate(struct mbox_controller *mbox, -+ const struct of_phandle_args *sp) -+{ -+ return mbox->chans; -+} -+ -+static int arm_smc_mbox_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct mbox_controller *mbox; -+ struct arm_smc_chan_data *chan_data; -+ int ret; -+ -+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); -+ if (!mbox) -+ return -ENOMEM; -+ -+ mbox->of_xlate = arm_smc_mbox_of_xlate; -+ mbox->num_chans = 1; -+ mbox->chans = devm_kzalloc(dev, sizeof(*mbox->chans), GFP_KERNEL); -+ if (!mbox->chans) -+ return -ENOMEM; -+ -+ chan_data = devm_kzalloc(dev, sizeof(*chan_data), GFP_KERNEL); -+ if (!chan_data) -+ return -ENOMEM; -+ -+ ret = of_property_read_u32(dev->of_node, "arm,func-id", -+ &chan_data->function_id); -+ if (ret) -+ return ret; -+ -+ if (of_device_is_compatible(dev->of_node, "arm,smc-mbox")) -+ chan_data->invoke_smc_mbox_fn = __invoke_fn_smc; -+ else -+ chan_data->invoke_smc_mbox_fn = __invoke_fn_hvc; -+ -+ -+ mbox->chans->con_priv = chan_data; -+ -+ mbox->txdone_poll = false; -+ mbox->txdone_irq = false; -+ mbox->ops = &arm_smc_mbox_chan_ops; -+ mbox->dev = dev; -+ -+ platform_set_drvdata(pdev, mbox); -+ -+ ret = devm_mbox_controller_register(dev, mbox); -+ if (ret) -+ return ret; -+ -+ dev_info(dev, "ARM SMC mailbox enabled.\n"); -+ -+ return ret; -+} -+ -+static int arm_smc_mbox_remove(struct platform_device *pdev) -+{ -+ struct mbox_controller *mbox = platform_get_drvdata(pdev); -+ -+ mbox_controller_unregister(mbox); -+ return 0; -+} -+ -+static const struct of_device_id arm_smc_mbox_of_match[] = { -+ { .compatible = "arm,smc-mbox", }, -+ { .compatible = "arm,hvc-mbox", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, arm_smc_mbox_of_match); -+ -+static struct platform_driver arm_smc_mbox_driver = { -+ .driver = { -+ .name = "arm-smc-mbox", -+ .of_match_table = arm_smc_mbox_of_match, -+ }, -+ .probe = arm_smc_mbox_probe, -+ .remove = arm_smc_mbox_remove, -+}; -+module_platform_driver(arm_smc_mbox_driver); -+ -+MODULE_AUTHOR("Peng Fan "); -+MODULE_DESCRIPTION("Generic ARM smc mailbox driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig -index d99548fb5..d3253dc6f 100644 ---- a/drivers/remoteproc/Kconfig -+++ b/drivers/remoteproc/Kconfig -@@ -23,6 +23,25 @@ config REMOTEPROC_CDEV - - It's safe to say N if you don't want to use this interface. - -+config REMOTEPROC_SRM_CORE -+ tristate "Remoteproc System Resource Manager core" -+ depends on RPMSG -+ help -+ Say y here to enable the core driver of the remoteproc System Resource -+ Manager (SRM). -+ The SRM handles resources allocated to remote processors. -+ The core part is in charge of controlling the device children. -+ -+config REMOTEPROC_SRM_DEV -+ tristate "Remoteproc System Resource Manager device" -+ depends on REMOTEPROC_SRM_CORE -+ help -+ Say y here to enable the device driver of the remoteproc System -+ Resource Manager (SRM). -+ The SRM handles resources allocated to remote processors. -+ The device part is in charge of reserving and initializing resources -+ for a peripheral assigned to a coprocessor. -+ - config IMX_REMOTEPROC - tristate "IMX6/7 remoteproc support" - depends on ARCH_MXC -@@ -252,6 +271,7 @@ config STM32_RPROC - depends on ARCH_STM32 - depends on REMOTEPROC - select MAILBOX -+ select TEE_REMOTEPROC - help - Say y here to support STM32 MCU processors via the - remote processor framework. -@@ -288,6 +308,15 @@ config TI_K3_R5_REMOTEPROC - It's safe to say N here if you're not interested in utilizing - a slave processor. - -+ -+config TEE_REMOTEPROC -+ tristate "trusted firmware support by a trusted application" -+ depends on OPTEE -+ help -+ Support for trusted remote processors firmware. The firmware -+ authentication and/or decryption are managed by a trusted application. -+ This can be either built-in or a loadable module. -+ - endif # REMOTEPROC - - endmenu -diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile -index da2ace4ec..9f2eb094c 100644 ---- a/drivers/remoteproc/Makefile -+++ b/drivers/remoteproc/Makefile -@@ -11,6 +11,9 @@ remoteproc-y += remoteproc_sysfs.o - remoteproc-y += remoteproc_virtio.o - remoteproc-y += remoteproc_elf_loader.o - obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o -+obj-$(CONFIG_REMOTEPROC_SRM_CORE) += rproc_srm_core.o -+obj-$(CONFIG_REMOTEPROC_SRM_DEV) += rproc_srm_dev.o -+obj-$(CONFIG_TEE_REMOTEPROC) += tee_remoteproc.o - obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o - obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o - obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o -diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c -index 47924d5ed..99bdc6eb4 100644 ---- a/drivers/remoteproc/remoteproc_core.c -+++ b/drivers/remoteproc/remoteproc_core.c -@@ -37,6 +37,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -1687,20 +1688,29 @@ int rproc_trigger_recovery(struct rproc *rproc) - { - const struct firmware *firmware_p; - struct device *dev = &rproc->dev; -+ bool detached; - int ret; - - ret = mutex_lock_interruptible(&rproc->lock); - if (ret) - return ret; - -+ detached = rproc->autonomous && !atomic_read(&rproc->power); -+ - /* State could have changed before we got the mutex */ - if (rproc->state != RPROC_CRASHED) - goto unlock_mutex; - - dev_err(dev, "recovering %s\n", rproc->name); - -+ if (rproc->autonomous && !detached) { -+ mutex_unlock(&rproc->lock); -+ rproc_shutdown(rproc); -+ return 0; -+ } -+ - ret = rproc_stop(rproc, true); -- if (ret) -+ if (ret || detached) - goto unlock_mutex; - - /* generate coredump */ -@@ -2014,6 +2024,11 @@ int rproc_add(struct rproc *rproc) - if (ret < 0) - return ret; - -+ /* add resource manager device */ -+ ret = devm_of_platform_populate(dev->parent); -+ if (ret < 0) -+ return ret; -+ - /* - * Remind ourselves the remote processor has been attached to rather - * than booted by the remoteproc core. This is important because the -@@ -2296,6 +2311,8 @@ int rproc_del(struct rproc *rproc) - list_del_rcu(&rproc->node); - mutex_unlock(&rproc_list_mutex); - -+ of_platform_depopulate(rproc->dev.parent); -+ - /* Ensure that no readers of rproc_list are still active */ - synchronize_rcu(); - -diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c -new file mode 100644 -index 000000000..fc61e8b35 ---- /dev/null -+++ b/drivers/remoteproc/rproc_srm_core.c -@@ -0,0 +1,303 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Fabien Dessenne for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "rproc_srm_core.h" -+ -+#define BIND_TIMEOUT 10000 -+ -+struct rproc_srm_core { -+ struct device *dev; -+ struct completion all_bound; -+ int bind_status; -+ atomic_t prepared; -+ struct rproc_subdev subdev; -+ struct rpmsg_driver rpdrv; -+ struct blocking_notifier_head notifier; -+}; -+ -+#define to_rproc_srm_core(s) container_of(s, struct rproc_srm_core, subdev) -+ -+static struct rproc_srm_core *rpmsg_srm_to_core(struct rpmsg_device *rpdev) -+{ -+ struct rpmsg_driver *rpdrv; -+ struct rproc_srm_core *core; -+ -+ rpdrv = container_of(rpdev->dev.driver, struct rpmsg_driver, drv); -+ core = container_of(rpdrv, struct rproc_srm_core, rpdrv); -+ -+ return core; -+} -+ -+int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg) -+{ -+ int ret; -+ -+ ret = rpmsg_send(ept, (void *)msg, sizeof(*msg)); -+ if (ret) -+ dev_err(&ept->rpdev->dev, "rpmsg_send failed: %d\n", ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(rpmsg_srm_send); -+ -+static int rpmsg_srm_cb(struct rpmsg_device *rpdev, void *data, int len, -+ void *priv, u32 src) -+{ -+ struct rproc_srm_core *core = rpmsg_srm_to_core(rpdev); -+ struct rpmsg_srm_msg_desc desc; -+ int ret; -+ -+ desc.ept = rpdev->ept; -+ desc.msg = data; -+ -+ ret = blocking_notifier_call_chain(&core->notifier, 0, &desc); -+ -+ if (!(ret & NOTIFY_STOP_MASK)) { -+ dev_warn(&rpdev->dev, "unknown device\n"); -+ desc.msg->message_type = RPROC_SRM_MSG_ERROR; -+ rpmsg_srm_send(desc.ept, desc.msg); -+ } -+ -+ return 0; -+} -+ -+static int rpmsg_srm_probe(struct rpmsg_device *rpdev) -+{ -+ int ret; -+ -+ dev_dbg(&rpdev->dev, "%s\n", __func__); -+ -+ /* Send an empty message to complete the initialization */ -+ ret = rpmsg_send(rpdev->ept, NULL, 0); -+ if (ret) -+ dev_err(&rpdev->dev, "failed to send init message\n"); -+ -+ return ret; -+} -+ -+static void rpmsg_srm_remove(struct rpmsg_device *rpdev) -+{ -+ /* Note : the remove ops is mandatory */ -+ dev_dbg(&rpdev->dev, "%s\n", __func__); -+} -+ -+static struct rpmsg_device_id rpmsg_srm_id_table[] = { -+ { .name = "rproc-srm" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(rpmsg, rpmsg_srm_id_table); -+ -+static struct rpmsg_driver rpmsg_srm_drv = { -+ .drv.name = "rpmsg_srm", -+ .id_table = rpmsg_srm_id_table, -+ .probe = rpmsg_srm_probe, -+ .callback = rpmsg_srm_cb, -+ .remove = rpmsg_srm_remove, -+}; -+ -+int rproc_srm_core_register_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_register(&core->notifier, nb); -+} -+EXPORT_SYMBOL(rproc_srm_core_register_notifier); -+ -+int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_unregister(&core->notifier, nb); -+} -+EXPORT_SYMBOL(rproc_srm_core_unregister_notifier); -+ -+static int compare_of(struct device *dev, void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static void release_of(struct device *dev, void *data) -+{ -+ of_node_put(data); -+} -+ -+static void rproc_srm_core_unbind(struct device *dev) -+{ -+ component_unbind_all(dev, NULL); -+} -+ -+static int rproc_srm_core_bind(struct device *dev) -+{ -+ struct rproc_srm_core *rproc_srm_core = dev_get_drvdata(dev); -+ -+ rproc_srm_core->bind_status = component_bind_all(dev, NULL); -+ complete(&rproc_srm_core->all_bound); -+ -+ return rproc_srm_core->bind_status; -+} -+ -+static const struct component_master_ops srm_comp_ops = { -+ .bind = rproc_srm_core_bind, -+ .unbind = rproc_srm_core_unbind, -+}; -+ -+static int rproc_srm_core_prepare(struct rproc_subdev *subdev) -+{ -+ struct rproc_srm_core *rproc_srm_core = to_rproc_srm_core(subdev); -+ struct device *dev = rproc_srm_core->dev; -+ struct device_node *node = dev->of_node; -+ struct device_node *child_np; -+ struct component_match *match = NULL; -+ int ret; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ init_completion(&rproc_srm_core->all_bound); -+ -+ ret = devm_of_platform_populate(dev); -+ if (ret) { -+ dev_err(dev, "cannot populate node (%d)\n", ret); -+ return ret; -+ } -+ -+ child_np = of_get_next_available_child(node, NULL); -+ -+ while (child_np) { -+ of_node_get(child_np); -+ component_match_add_release(dev, &match, release_of, compare_of, -+ child_np); -+ child_np = of_get_next_available_child(node, child_np); -+ } -+ -+ if (!match) { -+ dev_dbg(dev, "No available child\n"); -+ goto done; -+ } -+ -+ ret = component_master_add_with_match(dev, &srm_comp_ops, match); -+ if (ret) -+ goto depopulate; -+ -+ /* Wait for every child to be bound */ -+ if (!wait_for_completion_timeout(&rproc_srm_core->all_bound, -+ msecs_to_jiffies(BIND_TIMEOUT))) { -+ dev_err(dev, "failed to bind one or more system resource device(s)\n"); -+ ret = -ETIMEDOUT; -+ goto master; -+ } -+ -+ ret = rproc_srm_core->bind_status; -+ if (ret) { -+ dev_err(dev, "failed to bind\n"); -+ goto master; -+ } -+ -+ /* Register rpmsg driver for dynamic management */ -+ rproc_srm_core->rpdrv = rpmsg_srm_drv; -+ ret = register_rpmsg_driver(&rproc_srm_core->rpdrv); -+ if (ret) { -+ dev_err(dev, "failed to register rpmsg drv\n"); -+ goto master; -+ } -+ -+done: -+ atomic_inc(&rproc_srm_core->prepared); -+ -+ return 0; -+ -+master: -+ component_master_del(dev, &srm_comp_ops); -+depopulate: -+ devm_of_platform_depopulate(dev); -+ return ret; -+} -+ -+static void rproc_srm_core_unprepare(struct rproc_subdev *subdev) -+{ -+ struct rproc_srm_core *rproc_srm_core = to_rproc_srm_core(subdev); -+ struct device *dev = rproc_srm_core->dev; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ if (!atomic_read(&rproc_srm_core->prepared)) -+ return; -+ -+ atomic_dec(&rproc_srm_core->prepared); -+ -+ unregister_rpmsg_driver(&rproc_srm_core->rpdrv); -+ -+ component_master_del(dev, &srm_comp_ops); -+ devm_of_platform_depopulate(dev); -+} -+ -+static int rproc_srm_core_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc *rproc = dev_get_drvdata(dev->parent); -+ struct rproc_srm_core *rproc_srm_core; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ rproc_srm_core = devm_kzalloc(dev, sizeof(struct rproc_srm_core), -+ GFP_KERNEL); -+ if (!rproc_srm_core) -+ return -ENOMEM; -+ -+ rproc_srm_core->dev = dev; -+ BLOCKING_INIT_NOTIFIER_HEAD(&rproc_srm_core->notifier); -+ -+ /* Register rproc subdevice with (un)prepare ops */ -+ rproc_srm_core->subdev.prepare = rproc_srm_core_prepare; -+ rproc_srm_core->subdev.unprepare = rproc_srm_core_unprepare; -+ rproc_add_subdev(rproc, &rproc_srm_core->subdev); -+ -+ dev_set_drvdata(dev, rproc_srm_core); -+ -+ return 0; -+} -+ -+static int rproc_srm_core_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc_srm_core *rproc_srm_core = dev_get_drvdata(dev); -+ struct rproc *rproc = dev_get_drvdata(dev->parent); -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ if (atomic_read(&rproc->power) > 0) -+ dev_warn(dev, "Releasing resources while firmware running!\n"); -+ -+ rproc_srm_core_unprepare(&rproc_srm_core->subdev); -+ -+ return 0; -+} -+ -+static const struct of_device_id rproc_srm_core_match[] = { -+ { .compatible = "rproc-srm-core", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, rproc_srm_core_match); -+ -+static struct platform_driver rproc_srm_core_driver = { -+ .probe = rproc_srm_core_probe, -+ .remove = rproc_srm_core_remove, -+ .driver = { -+ .name = "rproc-srm-core", -+ .of_match_table = of_match_ptr(rproc_srm_core_match), -+ }, -+}; -+ -+module_platform_driver(rproc_srm_core_driver); -+ -+MODULE_AUTHOR("Fabien Dessenne "); -+MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - core"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h -new file mode 100644 -index 000000000..7dffdb38f ---- /dev/null -+++ b/drivers/remoteproc/rproc_srm_core.h -@@ -0,0 +1,98 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Fabien Dessenne for STMicroelectronics. -+ */ -+ -+#ifndef _RPROC_SRM_CORE_H_ -+#define _RPROC_SRM_CORE_H_ -+ -+/** -+ * Message type used in resource manager rpmsg: -+ * RPROC_SRM_MSG_GETCONFIG: Request to get the configuration of a resource -+ * RPROC_SRM_MSG_SETCONFIG: Request to set the configuration of a resource -+ * RPROC_SRM_MSG_ERROR: Error when processing a request -+ */ -+#define RPROC_SRM_MSG_GETCONFIG 0x00 -+#define RPROC_SRM_MSG_SETCONFIG 0x01 -+#define RPROC_SRM_MSG_ERROR 0xFF -+ -+/** -+ * Resource type used in resource manager rpmsg: -+ * RPROC_SRM_RSC_CLOCK: clock resource -+ * RPROC_SRM_RSC_REGU: regulator resource -+ */ -+#define RPROC_SRM_RSC_CLOCK 0x00 -+#define RPROC_SRM_RSC_REGU 0x01 -+ -+/** -+ * struct clock_cfg - clock configuration used in resource manager rpmsg -+ * @index: clock index -+ * @name: clock name -+ * @rate: clock rate request (in SetConfig message) or current status (in -+ * GetConfig message) -+ */ -+struct clock_cfg { -+ u32 index; -+ u8 name[16]; -+ u32 rate; -+}; -+ -+/** -+ * struct regu_cfg - regu configuration used in resource manager rpmsg -+ * @index: regulator index -+ * @name: regulator name -+ * @enable: regulator enable/disable request (in SetConfig message) or -+ * current status (in GetConfig message) -+ * @curr_voltage_mv: current regulator voltage in mV (meaningful in -+ * SetConfig message) -+ * @min_voltage_mv: regulator min voltage request in mV (meaningful in -+ * SetConfig message) -+ * @max_voltage_mv: regulator max voltage request in mV (meaningful in -+ * SetConfig message) -+ */ -+struct regu_cfg { -+ u32 index; -+ u8 name[16]; -+ u32 enable; -+ u32 curr_voltage_mv; -+ u32 min_voltage_mv; -+ u32 max_voltage_mv; -+}; -+ -+/** -+ * struct rpmsg_srm_msg - message structure used between processors to -+ * dynamically update resources configuration -+ * @message_type: type of the message: see RPROC_SRM_MSG* -+ * @device_id: an identifier specifying the device owning the resources. -+ * This is implementation dependent. As example it may be the -+ * device name or the device address. -+ * @rsc_type: the type of the resource for which the configuration applies: -+ * see RPROC_SRM_RSC* -+ * @clock_cfg: clock config - relevant if &rsc_type is RPROC_SRM_RSC_CLOCK -+ * @regu_cfg: regulator config - relevant if &rsc_type is RPROC_SRM_RSC_REGU -+ */ -+struct rpmsg_srm_msg { -+ u32 message_type; -+ u8 device_id[32]; -+ u32 rsc_type; -+ union { -+ struct clock_cfg clock_cfg; -+ struct regu_cfg regu_cfg; -+ }; -+}; -+ -+struct rpmsg_srm_msg_desc { -+ struct rpmsg_endpoint *ept; -+ struct rpmsg_srm_msg *msg; -+}; -+ -+struct rproc_srm_core; -+ -+int rproc_srm_core_register_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb); -+int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb); -+int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg); -+ -+#endif -diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c -new file mode 100644 -index 000000000..9dad0820f ---- /dev/null -+++ b/drivers/remoteproc/rproc_srm_dev.c -@@ -0,0 +1,744 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Fabien Dessenne for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "rproc_srm_core.h" -+ -+struct rproc_srm_clk_info { -+ struct list_head list; -+ unsigned int index; -+ struct clk *clk; -+ const char *name; -+ bool parent_enabled; -+}; -+ -+struct rproc_srm_regu_info { -+ struct list_head list; -+ unsigned int index; -+ struct regulator *regu; -+ const char *name; -+ bool enabled; -+}; -+ -+struct rproc_srm_irq_info { -+ struct list_head list; -+ unsigned int index; -+ char *name; -+ int irq; -+ bool enabled; -+}; -+ -+struct rproc_srm_dev { -+ struct device *dev; -+ struct rproc_srm_core *core; -+ struct notifier_block nb; -+ bool early_boot; -+ -+ struct list_head clk_list_head; -+ struct list_head regu_list_head; -+ struct list_head irq_list_head; -+}; -+ -+/* Irqs */ -+static void rproc_srm_dev_irqs_put(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct rproc_srm_irq_info *i, *tmp; -+ -+ list_for_each_entry_safe(i, tmp, &rproc_srm_dev->irq_list_head, list) { -+ devm_free_irq(dev, i->irq, NULL); -+ dev_dbg(dev, "Put irq %d (%s)\n", i->irq, i->name); -+ list_del(&i->list); -+ } -+} -+ -+static irqreturn_t rproc_srm_dev_irq_handler(int irq, void *dev) -+{ -+ dev_warn(dev, "Spurious interrupt\n"); -+ return IRQ_HANDLED; -+} -+ -+static int rproc_srm_dev_irqs_get(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct platform_device *pdev = to_platform_device(dev); -+ struct device_node *np = dev->of_node; -+ struct rproc_srm_irq_info *info; -+ const char *name; -+ int nr, ret, irq; -+ unsigned int i; -+ -+ if (!np) -+ return 0; -+ -+ nr = platform_irq_count(pdev); -+ if (!nr) -+ return 0; -+ -+ if (rproc_srm_dev->early_boot) -+ /* -+ * Do not overwrite the irq configuration. -+ * No need to parse irq from DT since the resource manager does -+ * not offer any service to update the irq config. -+ */ -+ return 0; -+ -+ for (i = 0; i < nr; i++) { -+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); -+ if (!info) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ irq = platform_get_irq(pdev, i); -+ if (irq <= 0) { -+ ret = irq; -+ dev_err(dev, "Failed to get irq (%d)\n", ret); -+ goto err; -+ } -+ -+ info->irq = irq; -+ -+ /* Register a dummy irq handleras not used by Linux */ -+ ret = devm_request_irq(dev, info->irq, -+ rproc_srm_dev_irq_handler, 0, -+ dev_name(dev), NULL); -+ if (ret) { -+ dev_err(dev, "Failed to request irq (%d)\n", ret); -+ goto err; -+ } -+ -+ /* -+ * Disable IRQ. Since it is used by the remote processor we -+ * must not use the 'irq lazy disable' optimization -+ */ -+ irq_set_status_flags(info->irq, IRQ_DISABLE_UNLAZY); -+ disable_irq(info->irq); -+ -+ /* Note: "interrupt-names" is optional */ -+ if (!of_property_read_string_index(np, "interrupt-names", i, -+ &name)) -+ info->name = devm_kstrdup(dev, name, GFP_KERNEL); -+ else -+ info->name = devm_kstrdup(dev, "", GFP_KERNEL); -+ -+ info->index = i; -+ -+ list_add_tail(&info->list, &rproc_srm_dev->irq_list_head); -+ dev_dbg(dev, "Got irq %d (%s)\n", info->irq, info->name); -+ } -+ -+ return 0; -+ -+err: -+ rproc_srm_dev_irqs_put(rproc_srm_dev); -+ -+ return ret; -+} -+ -+/* Clocks */ -+static void rproc_srm_dev_clocks_unsetup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_clk_info *c; -+ -+ list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) { -+ if (!c->parent_enabled) -+ continue; -+ -+ clk_disable_unprepare(clk_get_parent(c->clk)); -+ c->parent_enabled = false; -+ dev_dbg(rproc_srm_dev->dev, "clk %d (%s) unsetup\n", -+ c->index, c->name); -+ } -+} -+ -+static int rproc_srm_dev_clocks_setup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_clk_info *c; -+ int ret; -+ -+ /* -+ * Prepare and enable the parent clocks. -+ * Since the clock tree is under the exclusive control of the master -+ * processor, we need to configure the clock tree of the targeted clock. -+ * We do not want to enable the clock itself, which is under the -+ * responsibility of the remote processor. -+ * Hence we prepare and enable the parent clock. -+ */ -+ -+ list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) { -+ if (c->parent_enabled) -+ continue; -+ -+ ret = clk_prepare_enable(clk_get_parent(c->clk)); -+ if (ret) { -+ dev_err(rproc_srm_dev->dev, -+ "clk %d (%s) parent enable failed\n", -+ c->index, c->name); -+ rproc_srm_dev_clocks_unsetup(rproc_srm_dev); -+ return ret; -+ } -+ c->parent_enabled = true; -+ dev_dbg(rproc_srm_dev->dev, "clk %d (%s) parent enabled\n", -+ c->index, c->name); -+ } -+ -+ return 0; -+} -+ -+static struct rproc_srm_clk_info -+ *rproc_srm_dev_clock_find(struct rproc_srm_dev *rproc_srm_dev, -+ struct clock_cfg *cfg) -+{ -+ struct rproc_srm_clk_info *ci; -+ -+ /* Search by index (if valid value) otherwise search by name */ -+ list_for_each_entry(ci, &rproc_srm_dev->clk_list_head, list) { -+ if (cfg->index != U32_MAX) { -+ if (ci->index == cfg->index) -+ return ci; -+ } else { -+ if (!strcmp(ci->name, cfg->name)) -+ return ci; -+ } -+ } -+ -+ return NULL; -+} -+ -+static int rproc_srm_dev_clock_set_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct clock_cfg *cfg) -+{ -+ struct rproc_srm_clk_info *c; -+ struct device *dev = rproc_srm_dev->dev; -+ int ret; -+ -+ c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg); -+ -+ if (!c) { -+ dev_err(dev, "unknown clock (id %d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ if (cfg->rate && clk_get_rate(c->clk) != cfg->rate) { -+ ret = clk_set_rate(c->clk, cfg->rate); -+ if (ret) { -+ dev_err(dev, "clk set rate failed\n"); -+ return ret; -+ } -+ -+ dev_dbg(dev, "clk %d (%s) rate = %d\n", c->index, c->name, -+ cfg->rate); -+ } -+ -+ return 0; -+} -+ -+static int rproc_srm_dev_clock_get_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct clock_cfg *cfg) -+{ -+ struct rproc_srm_clk_info *c; -+ -+ c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg); -+ if (!c) { -+ dev_err(rproc_srm_dev->dev, "unknown clock (%d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ strlcpy(cfg->name, c->name, sizeof(cfg->name)); -+ cfg->index = c->index; -+ cfg->rate = (u32)clk_get_rate(c->clk); -+ -+ return 0; -+} -+ -+static void rproc_srm_dev_clocks_put(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct rproc_srm_clk_info *c, *tmp; -+ -+ list_for_each_entry_safe(c, tmp, &rproc_srm_dev->clk_list_head, list) { -+ clk_put(c->clk); -+ dev_dbg(dev, "put clock %d (%s)\n", c->index, c->name); -+ list_del(&c->list); -+ } -+} -+ -+static int rproc_srm_dev_clocks_get(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct device_node *np = dev->of_node; -+ struct rproc_srm_clk_info *c; -+ const char *name; -+ int nb_c, ret; -+ unsigned int i; -+ -+ if (!np) -+ return 0; -+ -+ nb_c = of_clk_get_parent_count(np); -+ if (!nb_c) -+ return 0; -+ -+ for (i = 0; i < nb_c; i++) { -+ c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); -+ if (!c) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ c->clk = of_clk_get(np, i); -+ if (IS_ERR(c->clk)) { -+ dev_err(dev, "clock %d KO (%ld)\n", i, -+ PTR_ERR(c->clk)); -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ /* Note: "clock-names" is optional */ -+ if (!of_property_read_string_index(np, "clock-names", i, -+ &name)) -+ c->name = devm_kstrdup(dev, name, GFP_KERNEL); -+ else -+ c->name = devm_kstrdup(dev, "", GFP_KERNEL); -+ -+ c->index = i; -+ -+ list_add_tail(&c->list, &rproc_srm_dev->clk_list_head); -+ dev_dbg(dev, "got clock %d (%s)\n", c->index, c->name); -+ } -+ -+ return 0; -+ -+err: -+ rproc_srm_dev_clocks_put(rproc_srm_dev); -+ return ret; -+} -+ -+/* Regulators */ -+static void rproc_srm_dev_regus_unsetup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_regu_info *r; -+ struct device *dev = rproc_srm_dev->dev; -+ -+ list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) { -+ if (!r->enabled) -+ continue; -+ -+ if (regulator_disable(r->regu)) { -+ dev_warn(dev, "regu %d disabled failed\n", r->index); -+ continue; -+ } -+ -+ r->enabled = false; -+ dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name); -+ } -+} -+ -+static int rproc_srm_dev_regus_setup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_regu_info *r; -+ int ret; -+ -+ /* Enable all the regulators */ -+ list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) { -+ if (r->enabled) -+ continue; -+ -+ /* in early_boot mode sync on hw */ -+ if (rproc_srm_dev->early_boot && !regulator_is_enabled(r->regu)) -+ continue; -+ -+ ret = regulator_enable(r->regu); -+ if (ret) { -+ dev_err(rproc_srm_dev->dev, "regu %d (%s) failed\n", -+ r->index, r->name); -+ rproc_srm_dev_regus_unsetup(rproc_srm_dev); -+ return ret; -+ } -+ r->enabled = true; -+ dev_dbg(rproc_srm_dev->dev, "regu %d (%s) enabled\n", -+ r->index, r->name); -+ } -+ -+ return 0; -+} -+ -+static struct rproc_srm_regu_info -+ *rproc_srm_dev_regu_find(struct rproc_srm_dev *rproc_srm_dev, -+ struct regu_cfg *cfg) -+{ -+ struct rproc_srm_regu_info *ri; -+ -+ list_for_each_entry(ri, &rproc_srm_dev->regu_list_head, list) { -+ if (cfg->index != U32_MAX) { -+ if (ri->index == cfg->index) -+ return ri; -+ } else { -+ if (!strcmp(ri->name, cfg->name)) -+ return ri; -+ } -+ } -+ -+ return NULL; -+} -+ -+static int rproc_srm_dev_regu_set_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct regu_cfg *cfg) -+{ -+ struct rproc_srm_regu_info *r; -+ struct device *dev = rproc_srm_dev->dev; -+ int ret; -+ -+ r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg); -+ if (!r) { -+ dev_err(dev, "unknown regu (%d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ if (!r->enabled && cfg->enable) { -+ ret = regulator_enable(r->regu); -+ if (ret) { -+ dev_err(dev, "regu %d enable failed\n", r->index); -+ return ret; -+ } -+ r->enabled = true; -+ dev_dbg(dev, "regu %d (%s) enabled\n", r->index, r->name); -+ } else if (r->enabled && !cfg->enable) { -+ ret = regulator_disable(r->regu); -+ if (ret) { -+ dev_err(dev, "regu %d disable failed\n", r->index); -+ return ret; -+ } -+ r->enabled = false; -+ dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name); -+ } -+ -+ if (cfg->min_voltage_mv || cfg->max_voltage_mv) { -+ ret = regulator_set_voltage(r->regu, cfg->min_voltage_mv * 1000, -+ cfg->max_voltage_mv * 1000); -+ if (ret) { -+ dev_err(dev, "regu %d set voltage failed\n", r->index); -+ return ret; -+ } -+ -+ dev_dbg(dev, "regu %d (%s) voltage = [%d - %d] mv\n", r->index, -+ r->name, cfg->min_voltage_mv, cfg->max_voltage_mv); -+ } -+ -+ return 0; -+} -+ -+static int rproc_srm_dev_regu_get_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct regu_cfg *cfg) -+{ -+ struct rproc_srm_regu_info *r; -+ struct device *dev = rproc_srm_dev->dev; -+ int v; -+ -+ r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg); -+ if (!r) { -+ dev_err(dev, "unknown regu (%d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ strlcpy(cfg->name, r->name, sizeof(cfg->name)); -+ cfg->index = r->index; -+ cfg->enable = r->enabled; -+ cfg->min_voltage_mv = 0; -+ cfg->max_voltage_mv = 0; -+ -+ v = regulator_get_voltage(r->regu); -+ if (v < 0) { -+ dev_warn(dev, "cannot get %s voltage\n", r->name); -+ cfg->curr_voltage_mv = 0; -+ } else { -+ cfg->curr_voltage_mv = v / 1000; -+ } -+ -+ return 0; -+} -+ -+static void rproc_srm_dev_regus_put(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct rproc_srm_regu_info *r, *tmp; -+ -+ list_for_each_entry_safe(r, tmp, &rproc_srm_dev->regu_list_head, list) { -+ devm_regulator_put(r->regu); -+ dev_dbg(dev, "put regu %d (%s)\n", r->index, r->name); -+ list_del(&r->list); -+ } -+} -+ -+static int rproc_srm_dev_regus_get(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct device_node *np = dev->of_node; -+ struct property *p; -+ const char *n; -+ char *name; -+ struct rproc_srm_regu_info *r; -+ int ret, nb_s = 0; -+ -+ if (!np) -+ return 0; -+ -+ for_each_property_of_node(np, p) { -+ n = strstr(p->name, "-supply"); -+ if (!n || n == p->name) -+ continue; -+ -+ r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); -+ if (!r) { -+ ret = -ENOMEM; -+ goto err_list; -+ } -+ -+ name = devm_kstrdup(dev, p->name, GFP_KERNEL); -+ name[strlen(p->name) - strlen("-supply")] = '\0'; -+ r->name = name; -+ -+ r->regu = devm_regulator_get(dev, r->name); -+ if (IS_ERR(r->regu)) { -+ dev_err(dev, "cannot get regu %s\n", r->name); -+ ret = -EINVAL; -+ goto err_list; -+ } -+ -+ r->index = nb_s++; -+ -+ list_add_tail(&r->list, &rproc_srm_dev->regu_list_head); -+ dev_dbg(dev, "got regu %d (%s)\n", r->index, r->name); -+ } -+ -+ return 0; -+ -+err_list: -+ rproc_srm_dev_regus_put(rproc_srm_dev); -+ return ret; -+} -+ -+/* Core */ -+static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt, -+ void *data) -+{ -+ struct rproc_srm_dev *rproc_srm_dev = -+ container_of(nb, struct rproc_srm_dev, nb); -+ struct device *dev = rproc_srm_dev->dev; -+ struct rpmsg_srm_msg_desc *desc; -+ struct rpmsg_srm_msg *i, o; -+ int ret = 0; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ desc = (struct rpmsg_srm_msg_desc *)data; -+ i = desc->msg; -+ o = *i; -+ -+ /* Check if 'device_id' (name / addr ) matches this device */ -+ if (!strstr(dev_name(dev), i->device_id)) -+ return NOTIFY_DONE; -+ -+ switch (i->message_type) { -+ case RPROC_SRM_MSG_SETCONFIG: -+ switch (i->rsc_type) { -+ case RPROC_SRM_RSC_CLOCK: -+ ret = rproc_srm_dev_clock_set_cfg(rproc_srm_dev, -+ &i->clock_cfg); -+ if (!ret) -+ ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, -+ &o.clock_cfg); -+ break; -+ case RPROC_SRM_RSC_REGU: -+ ret = rproc_srm_dev_regu_set_cfg(rproc_srm_dev, -+ &i->regu_cfg); -+ if (!ret) -+ ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, -+ &o.regu_cfg); -+ break; -+ default: -+ dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type); -+ ret = -EINVAL; -+ break; -+ } -+ break; -+ case RPROC_SRM_MSG_GETCONFIG: -+ switch (i->rsc_type) { -+ case RPROC_SRM_RSC_CLOCK: -+ ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, -+ &o.clock_cfg); -+ break; -+ case RPROC_SRM_RSC_REGU: -+ ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, -+ &o.regu_cfg); -+ break; -+ default: -+ dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type); -+ ret = -EINVAL; -+ break; -+ } -+ break; -+ default: -+ dev_warn(dev, "bad msg type (%d)\n", i->message_type); -+ ret = -EINVAL; -+ break; -+ } -+ -+ /* Send return msg */ -+ if (ret) -+ o.message_type = RPROC_SRM_MSG_ERROR; -+ -+ ret = rpmsg_srm_send(desc->ept, &o); -+ -+ return ret ? NOTIFY_BAD : NOTIFY_STOP; -+} -+ -+static void -+rproc_srm_dev_unbind(struct device *dev, struct device *master, void *data) -+{ -+ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ rproc_srm_dev_regus_unsetup(rproc_srm_dev); -+ rproc_srm_dev_clocks_unsetup(rproc_srm_dev); -+ -+ /* For IRQs: nothing to unsetup */ -+} -+ -+static int -+rproc_srm_dev_bind(struct device *dev, struct device *master, void *data) -+{ -+ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); -+ int ret; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ ret = rproc_srm_dev_clocks_setup(rproc_srm_dev); -+ if (ret) -+ return ret; -+ -+ ret = rproc_srm_dev_regus_setup(rproc_srm_dev); -+ if (ret) -+ return ret; -+ -+ /* For IRQs: nothing to setup */ -+ return 0; -+} -+ -+static const struct component_ops rproc_srm_dev_ops = { -+ .bind = rproc_srm_dev_bind, -+ .unbind = rproc_srm_dev_unbind, -+}; -+ -+static int rproc_srm_dev_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc_srm_dev *rproc_srm_dev; -+ struct rproc *rproc; -+ int ret; -+ -+ dev_dbg(dev, "%s for node %s\n", __func__, dev->of_node->name); -+ -+ rproc_srm_dev = devm_kzalloc(dev, sizeof(struct rproc_srm_dev), -+ GFP_KERNEL); -+ if (!rproc_srm_dev) -+ return -ENOMEM; -+ -+ rproc_srm_dev->dev = dev; -+ rproc = (struct rproc *)dev_get_drvdata(dev->parent->parent); -+ rproc_srm_dev->early_boot = (rproc->state == RPROC_DETACHED); -+ rproc_srm_dev->core = dev_get_drvdata(dev->parent); -+ -+ INIT_LIST_HEAD(&rproc_srm_dev->clk_list_head); -+ INIT_LIST_HEAD(&rproc_srm_dev->regu_list_head); -+ INIT_LIST_HEAD(&rproc_srm_dev->irq_list_head); -+ -+ /* Get clocks, regu and irqs */ -+ ret = rproc_srm_dev_clocks_get(rproc_srm_dev); -+ if (ret) -+ return ret; -+ -+ ret = rproc_srm_dev_regus_get(rproc_srm_dev); -+ if (ret) -+ goto err_get; -+ -+ ret = rproc_srm_dev_irqs_get(rproc_srm_dev); -+ if (ret) -+ goto err_get; -+ -+ rproc_srm_dev->nb.notifier_call = rproc_srm_dev_notify_cb; -+ ret = rproc_srm_core_register_notifier(rproc_srm_dev->core, -+ &rproc_srm_dev->nb); -+ if (ret) -+ goto err_register; -+ -+ dev_set_drvdata(dev, rproc_srm_dev); -+ -+ return component_add(dev, &rproc_srm_dev_ops); -+ -+err_register: -+ rproc_srm_core_unregister_notifier(rproc_srm_dev->core, -+ &rproc_srm_dev->nb); -+err_get: -+ rproc_srm_dev_irqs_put(rproc_srm_dev); -+ rproc_srm_dev_regus_put(rproc_srm_dev); -+ rproc_srm_dev_clocks_put(rproc_srm_dev); -+ return ret; -+} -+ -+static int rproc_srm_dev_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ component_del(dev, &rproc_srm_dev_ops); -+ -+ rproc_srm_core_unregister_notifier(rproc_srm_dev->core, -+ &rproc_srm_dev->nb); -+ -+ rproc_srm_dev_irqs_put(rproc_srm_dev); -+ rproc_srm_dev_regus_put(rproc_srm_dev); -+ rproc_srm_dev_clocks_put(rproc_srm_dev); -+ -+ return 0; -+} -+ -+static const struct of_device_id rproc_srm_dev_match[] = { -+ { .compatible = "rproc-srm-dev", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, rproc_srm_dev_match); -+ -+static struct platform_driver rproc_srm_dev_driver = { -+ .probe = rproc_srm_dev_probe, -+ .remove = rproc_srm_dev_remove, -+ .driver = { -+ .name = "rproc-srm-dev", -+ .of_match_table = of_match_ptr(rproc_srm_dev_match), -+ }, -+}; -+ -+module_platform_driver(rproc_srm_dev_driver); -+ -+MODULE_AUTHOR("Fabien Dessenne "); -+MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - dev"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index d2414cc1d..9e9f89895 100644 ---- a/drivers/remoteproc/stm32_rproc.c -+++ b/drivers/remoteproc/stm32_rproc.c -@@ -20,13 +20,11 @@ - #include - #include - #include -+#include - #include - - #include "remoteproc_internal.h" - --#define HOLD_BOOT 0 --#define RELEASE_BOOT 1 -- - #define MBOX_NB_VQ 2 - #define MBOX_NB_MBX 3 - -@@ -48,6 +46,13 @@ - #define M4_STATE_STANDBY 4 - #define M4_STATE_CRASH 5 - -+/* -+ * Define a default index in future may come a global list of -+ * firmwares which list platforms and associated firmware(s) -+ */ -+ -+#define STM32_MP1_FW_ID 0 -+ - struct stm32_syscon { - struct regmap *map; - u32 reg; -@@ -78,7 +83,7 @@ struct stm32_mbox { - - struct stm32_rproc { - struct reset_control *rst; -- struct stm32_syscon hold_boot; -+ struct reset_control *hold_boot; - struct stm32_syscon pdds; - struct stm32_syscon m4_state; - struct stm32_syscon rsctbl; -@@ -87,7 +92,8 @@ struct stm32_rproc { - struct stm32_rproc_mem *rmems; - struct stm32_mbox mb[MBOX_NB_MBX]; - struct workqueue_struct *workqueue; -- bool secured_soc; -+ bool fw_loaded; -+ struct tee_rproc *trproc; - void __iomem *rsc_va; - }; - -@@ -207,15 +213,139 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) - return -EINVAL; - } - --static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, -+static void stm32_rproc_request_shutdown(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ int err, dummy_data, idx; -+ -+ /* Request shutdown of the remote processor */ -+ if (rproc->state != RPROC_OFFLINE) { -+ idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); -+ if (idx >= 0 && ddata->mb[idx].chan) { -+ /* A dummy data is sent to allow to block on transmit. */ -+ err = mbox_send_message(ddata->mb[idx].chan, -+ &dummy_data); -+ if (err < 0) -+ dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n"); -+ } -+ } -+} -+ -+static int stm32_rproc_release(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ unsigned int err = 0; -+ -+ /* To allow platform Standby power mode, set remote proc Deep Sleep. */ -+ if (ddata->pdds.map) { -+ err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg, -+ ddata->pdds.mask, 1); -+ if (err) { -+ dev_err(&rproc->dev, "failed to set pdds\n"); -+ return err; -+ } -+ } -+ -+ /* Update coprocessor state to OFF if available. */ -+ if (ddata->m4_state.map) { -+ err = regmap_update_bits(ddata->m4_state.map, -+ ddata->m4_state.reg, -+ ddata->m4_state.mask, -+ M4_STATE_OFF); -+ if (err) { -+ dev_err(&rproc->dev, "failed to set copro state\n"); -+ return err; -+ } -+ } -+ -+ return err; -+} -+ -+static int stm32_rproc_tee_elf_sanity_check(struct rproc *rproc, -+ const struct firmware *fw) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ unsigned int ret = 0; -+ -+ if (rproc->state == RPROC_DETACHED) -+ return 0; -+ -+ ret = tee_rproc_load_fw(ddata->trproc, fw); -+ if (!ret) -+ ddata->fw_loaded = true; -+ -+ return ret; -+} -+ -+static int stm32_rproc_tee_elf_load(struct rproc *rproc, -+ const struct firmware *fw) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ unsigned int ret; -+ -+ /* -+ * This function can be called by remote proc for recovery -+ * without the sanity check. In this case we need to load the firmware -+ * else nothing done here as the firmware has been preloaded for the -+ * sanity check to be able to parse it for the resource table -+ */ -+ if (ddata->fw_loaded) -+ return 0; -+ -+ ret = tee_rproc_load_fw(ddata->trproc, fw); -+ if (ret) -+ return ret; -+ ddata->fw_loaded = true; -+ -+ /* update the resource table parameters */ -+ if (rproc_tee_get_rsc_table(ddata->trproc)) { -+ /* no resource table: reset the related fields */ -+ rproc->cached_table = NULL; -+ rproc->table_ptr = NULL; -+ rproc->table_sz = 0; -+ } -+ -+ return 0; -+} -+ -+static struct resource_table * -+stm32_rproc_tee_elf_find_loaded_rsc_table(struct rproc *rproc, - const struct firmware *fw) - { -- if (rproc_elf_load_rsc_table(rproc, fw)) -- dev_warn(&rproc->dev, "no resource table found for this firmware\n"); -+ struct stm32_rproc *ddata = rproc->priv; -+ -+ return tee_rproc_get_loaded_rsc_table(ddata->trproc); -+} - -+static int stm32_rproc_tee_start(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ -+ return tee_rproc_start(ddata->trproc); -+} -+ -+static int stm32_rproc_tee_attach(struct rproc *rproc) -+{ -+ /* Nothing to do, remote proc already started by the secured context */ - return 0; - } - -+static int stm32_rproc_tee_stop(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ int err; -+ -+ stm32_rproc_request_shutdown(rproc); -+ -+ err = tee_rproc_stop(ddata->trproc); -+ if (err) -+ return err; -+ -+ ddata->fw_loaded = false; -+ -+ return stm32_rproc_release(rproc); -+} -+ - static int stm32_rproc_parse_memory_regions(struct rproc *rproc) - { - struct device *dev = rproc->dev.parent; -@@ -274,12 +404,21 @@ static int stm32_rproc_parse_memory_regions(struct rproc *rproc) - - static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) - { -- int ret = stm32_rproc_parse_memory_regions(rproc); -+ struct stm32_rproc *ddata = rproc->priv; -+ int ret; - -+ ret = stm32_rproc_parse_memory_regions(rproc); - if (ret) - return ret; - -- return stm32_rproc_elf_load_rsc_table(rproc, fw); -+ if (ddata->trproc) -+ ret = rproc_tee_get_rsc_table(ddata->trproc); -+ else -+ ret = rproc_elf_load_rsc_table(rproc, fw); -+ if (ret) -+ dev_warn(&rproc->dev, "no resource table found for this firmware\n"); -+ -+ return 0; - } - - static irqreturn_t stm32_rproc_wdg(int irq, void *data) -@@ -370,8 +509,13 @@ static int stm32_rproc_request_mbox(struct rproc *rproc) - - ddata->mb[i].chan = mbox_request_channel_byname(cl, name); - if (IS_ERR(ddata->mb[i].chan)) { -- if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) -+ if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) { -+ dev_err_probe(dev->parent, -+ PTR_ERR(ddata->mb[i].chan), -+ "failed to request mailbox %s\n", -+ name); - goto err_probe; -+ } - dev_warn(dev, "cannot get %s mbox\n", name); - ddata->mb[i].chan = NULL; - } -@@ -390,30 +534,6 @@ static int stm32_rproc_request_mbox(struct rproc *rproc) - return -EPROBE_DEFER; - } - --static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) --{ -- struct stm32_rproc *ddata = rproc->priv; -- struct stm32_syscon hold_boot = ddata->hold_boot; -- struct arm_smccc_res smc_res; -- int val, err; -- -- val = hold ? HOLD_BOOT : RELEASE_BOOT; -- -- if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) && ddata->secured_soc) { -- arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE, -- hold_boot.reg, val, 0, 0, 0, 0, &smc_res); -- err = smc_res.a0; -- } else { -- err = regmap_update_bits(hold_boot.map, hold_boot.reg, -- hold_boot.mask, val); -- } -- -- if (err) -- dev_err(&rproc->dev, "failed to set hold boot\n"); -- -- return err; --} -- - static void stm32_rproc_add_coredump_trace(struct rproc *rproc) - { - struct rproc_debug_trace *trace; -@@ -453,40 +573,34 @@ static int stm32_rproc_start(struct rproc *rproc) - } - } - -- err = stm32_rproc_set_hold_boot(rproc, false); -+ err = reset_control_deassert(ddata->hold_boot); - if (err) - return err; - -- return stm32_rproc_set_hold_boot(rproc, true); -+ return reset_control_assert(ddata->hold_boot); - } - - static int stm32_rproc_attach(struct rproc *rproc) - { -+ struct stm32_rproc *ddata = rproc->priv; -+ - stm32_rproc_add_coredump_trace(rproc); - -- return stm32_rproc_set_hold_boot(rproc, true); -+ return reset_control_assert(ddata->hold_boot); - } - - static int stm32_rproc_stop(struct rproc *rproc) - { - struct stm32_rproc *ddata = rproc->priv; -- int err, dummy_data, idx; -+ int err; - -- /* request shutdown of the remote processor */ -- if (rproc->state != RPROC_OFFLINE) { -- idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); -- if (idx >= 0 && ddata->mb[idx].chan) { -- /* a dummy data is sent to allow to block on transmit */ -- err = mbox_send_message(ddata->mb[idx].chan, -- &dummy_data); -- if (err < 0) -- dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n"); -- } -- } -+ stm32_rproc_request_shutdown(rproc); - -- err = stm32_rproc_set_hold_boot(rproc, true); -- if (err) -+ err = reset_control_assert(ddata->hold_boot); -+ if (err) { -+ dev_err(&rproc->dev, "failed to assert the hold boot\n"); - return err; -+ } - - err = reset_control_assert(ddata->rst); - if (err) { -@@ -494,29 +608,8 @@ static int stm32_rproc_stop(struct rproc *rproc) - return err; - } - -- /* to allow platform Standby power mode, set remote proc Deep Sleep */ -- if (ddata->pdds.map) { -- err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg, -- ddata->pdds.mask, 1); -- if (err) { -- dev_err(&rproc->dev, "failed to set pdds\n"); -- return err; -- } -- } - -- /* update coprocessor state to OFF if available */ -- if (ddata->m4_state.map) { -- err = regmap_update_bits(ddata->m4_state.map, -- ddata->m4_state.reg, -- ddata->m4_state.mask, -- M4_STATE_OFF); -- if (err) { -- dev_err(&rproc->dev, "failed to set copro state\n"); -- return err; -- } -- } -- -- return 0; -+ return stm32_rproc_release(rproc); - } - - static void stm32_rproc_kick(struct rproc *rproc, int vqid) -@@ -553,8 +646,19 @@ static struct rproc_ops st_rproc_ops = { - .get_boot_addr = rproc_elf_get_boot_addr, - }; - -+static struct rproc_ops st_rproc_tee_ops = { -+ .start = stm32_rproc_tee_start, -+ .stop = stm32_rproc_tee_stop, -+ .attach = stm32_rproc_tee_attach, -+ .kick = stm32_rproc_kick, -+ .parse_fw = stm32_rproc_parse_fw, -+ .find_loaded_rsc_table = stm32_rproc_tee_elf_find_loaded_rsc_table, -+ .sanity_check = stm32_rproc_tee_elf_sanity_check, -+ .load = stm32_rproc_tee_elf_load, -+}; -+ - static const struct of_device_id stm32_rproc_match[] = { -- { .compatible = "st,stm32mp1-m4" }, -+ {.compatible = "st,stm32mp1-m4",}, - {}, - }; - MODULE_DEVICE_TABLE(of, stm32_rproc_match); -@@ -586,21 +690,18 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev, - { - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; -- struct stm32_syscon tz; -- unsigned int tzen; - int err, irq; - - irq = platform_get_irq(pdev, 0); - if (irq == -EPROBE_DEFER) -- return -EPROBE_DEFER; -+ return dev_err_probe(dev, irq, "failed to get interrupt\n"); - - if (irq > 0) { - err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0, - dev_name(dev), pdev); -- if (err) { -- dev_err(dev, "failed to request wdg irq\n"); -- return err; -- } -+ if (err) -+ return dev_err_probe(dev, err, -+ "failed to request wdg irq\n"); - - ddata->wdg_irq = irq; - -@@ -612,36 +713,15 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev, - dev_info(dev, "wdg irq registered\n"); - } - -- ddata->rst = devm_reset_control_get_by_index(dev, 0); -- if (IS_ERR(ddata->rst)) { -- dev_err(dev, "failed to get mcu reset\n"); -- return PTR_ERR(ddata->rst); -- } -+ ddata->rst = devm_reset_control_get(dev, "mcu_rst"); -+ if (IS_ERR(ddata->rst)) -+ return dev_err_probe(dev, PTR_ERR(ddata->rst), -+ "failed to get mcu_reset\n"); - -- /* -- * if platform is secured the hold boot bit must be written by -- * smc call and read normally. -- * if not secure the hold boot bit could be read/write normally -- */ -- err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz); -- if (err) { -- dev_err(dev, "failed to get tz syscfg\n"); -- return err; -- } -- -- err = regmap_read(tz.map, tz.reg, &tzen); -- if (err) { -- dev_err(dev, "failed to read tzen\n"); -- return err; -- } -- ddata->secured_soc = tzen & tz.mask; -- -- err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot", -- &ddata->hold_boot); -- if (err) { -- dev_err(dev, "failed to get hold boot\n"); -- return err; -- } -+ ddata->hold_boot = devm_reset_control_get(dev, "hold_boot"); -+ if (IS_ERR(ddata->hold_boot)) -+ return dev_err_probe(dev, PTR_ERR(ddata->hold_boot), -+ "failed to get mcu reset\n"); - - err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); - if (err) -@@ -766,6 +846,7 @@ static int stm32_rproc_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct stm32_rproc *ddata; - struct device_node *np = dev->of_node; -+ struct tee_rproc *trproc; - struct rproc *rproc; - unsigned int state; - int ret; -@@ -774,11 +855,32 @@ static int stm32_rproc_probe(struct platform_device *pdev) - if (ret) - return ret; - -- rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); -- if (!rproc) -- return -ENOMEM; -+ trproc = tee_rproc_register(dev, STM32_MP1_FW_ID); -+ if (!IS_ERR_OR_NULL(trproc)) { -+ /* -+ * Delagate the firmware management to the secure context. The -+ * firmware loaded has to be signed. -+ */ -+ dev_info(dev, "Support of signed firmware only\n"); -+ -+ } else { -+ if (PTR_ERR(trproc) == -EPROBE_DEFER) -+ return PTR_ERR(trproc); -+ trproc = NULL; -+ } -+ -+ rproc = rproc_alloc(dev, np->name, -+ trproc ? &st_rproc_tee_ops : &st_rproc_ops, -+ NULL, sizeof(*ddata)); -+ if (!rproc) { -+ ret = -ENOMEM; -+ goto free_tee; -+ } - - ddata = rproc->priv; -+ ddata->trproc = trproc; -+ if (trproc) -+ ddata->trproc->rproc = rproc; - - rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); - -@@ -838,6 +940,10 @@ static int stm32_rproc_probe(struct platform_device *pdev) - device_init_wakeup(dev, false); - } - rproc_free(rproc); -+free_tee: -+ if (trproc) -+ tee_rproc_unregister(trproc); -+ - return ret; - } - -@@ -859,10 +965,21 @@ static int stm32_rproc_remove(struct platform_device *pdev) - device_init_wakeup(dev, false); - } - rproc_free(rproc); -+ if (ddata->trproc) -+ tee_rproc_unregister(ddata->trproc); - - return 0; - } - -+static void stm32_rproc_shutdown(struct platform_device *pdev) -+{ -+ struct rproc *rproc = platform_get_drvdata(pdev); -+ -+ if (atomic_read(&rproc->power) > 0) -+ dev_warn(&pdev->dev, -+ "Warning: remote fw is still running with possible side effect!!!\n"); -+} -+ - static int __maybe_unused stm32_rproc_suspend(struct device *dev) - { - struct rproc *rproc = dev_get_drvdata(dev); -@@ -891,6 +1008,7 @@ static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, - static struct platform_driver stm32_rproc_driver = { - .probe = stm32_rproc_probe, - .remove = stm32_rproc_remove, -+ .shutdown = stm32_rproc_shutdown, - .driver = { - .name = "stm32-rproc", - .pm = &stm32_rproc_pm_ops, -diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c -new file mode 100644 -index 000000000..690cb86f6 ---- /dev/null -+++ b/drivers/remoteproc/tee_remoteproc.c -@@ -0,0 +1,378 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) STMicroelectronics 2020 - All Rights Reserved -+ * Authors: Arnaud Pouliquen -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "remoteproc_internal.h" -+ -+#define MAX_TEE_PARAM_ARRY_MEMBER 4 -+ -+/* -+ * Authentication of the firmware and load in the remote processor memory -+ * -+ * [in] params[0].value.a: unique 32bit identifier of the firmware -+ * [in] params[1].memref: buffer containing the image of the buffer -+ */ -+#define TA_RPROC_FW_CMD_LOAD_FW 1 -+ -+/* -+ * start the remote processor -+ * -+ * [in] params[0].value.a: unique 32bit identifier of the firmware -+ */ -+#define TA_RPROC_FW_CMD_START_FW 2 -+ -+/* -+ * stop the remote processor -+ * -+ * [in] params[0].value.a: unique 32bit identifier of the firmware -+ */ -+#define TA_RPROC_FW_CMD_STOP_FW 3 -+ -+/* -+ * return the address of the resource table, or 0 if not found -+ * No chech is done to verify that the address returned is accessible by -+ * the non secure context. If the resource table is loaded in a protected -+ * memory the acces by the non secure context will lead to a data abort. -+ * -+ * [in] params[0].value.a: unique 32bit identifier of the firmware -+ * [out] params[1].value.a: 32bit LSB resource table memory address -+ * [out] params[1].value.b: 32bit MSB resource table memory address -+ * [out] params[2].value.a: 32bit LSB resource table memory size -+ * [out] params[2].value.b: 32bit MSB resource table memory size -+ */ -+#define TA_RPROC_FW_CMD_GET_RSC_TABLE 4 -+ -+/* -+ * return the address of the core dump -+ * -+ * [in] params[0].value.a: unique 32bit identifier of the firmware -+ * [out] params[1].memref: address of the core dump image if exist, -+ * else return Null -+ */ -+#define TA_RPROC_FW_CMD_GET_COREDUMP 5 -+ -+struct tee_rproc_mem { -+ char name[20]; -+ void __iomem *cpu_addr; -+ phys_addr_t bus_addr; -+ u32 dev_addr; -+ size_t size; -+}; -+ -+struct tee_rproc_context { -+ struct list_head sessions; -+ struct tee_context *ctx; -+ struct device *dev; -+}; -+ -+struct tee_rproc_context pvt_data; -+ -+static void prepare_args(struct tee_rproc *trproc, int cmd, -+ struct tee_ioctl_invoke_arg *arg, -+ struct tee_param *param, unsigned int num_params) -+{ -+ memset(arg, 0, sizeof(*arg)); -+ memset(param, 0, MAX_TEE_PARAM_ARRY_MEMBER * sizeof(*param)); -+ -+ arg->func = cmd; -+ arg->session = trproc->session_id; -+ arg->num_params = num_params + 1; -+ -+ param[0] = (struct tee_param) { -+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, -+ .u.value.a = trproc->fw_id, -+ }; -+} -+ -+int tee_rproc_load_fw(struct tee_rproc *trproc, const struct firmware *fw) -+{ -+ struct tee_ioctl_invoke_arg arg; -+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; -+ struct tee_shm *fw_shm; -+ int ret; -+ -+ /* -+ * useless copy waiting that tee_shm_register and tee well support -+ * kernel buffers registration -+ */ -+ -+ fw_shm = tee_shm_alloc(pvt_data.ctx, fw->size, -+ TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); -+ if (IS_ERR(fw_shm)) -+ return PTR_ERR(fw_shm); -+ -+ memcpy(tee_shm_get_va(fw_shm, 0), fw->data, fw->size); -+ -+ prepare_args(trproc, TA_RPROC_FW_CMD_LOAD_FW, &arg, param, 1); -+ -+ /* provide the address of the firmware image */ -+ param[1] = (struct tee_param) { -+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, -+ .u.memref = { -+ .shm = fw_shm, -+ .size = fw->size, -+ .shm_offs = 0, -+ }, -+ }; -+ -+ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); -+ if (ret < 0 || arg.ret != 0) { -+ dev_err(pvt_data.dev, -+ "TA_RPROC_FW_CMD_LOAD_FW invoke failed TEE err: %x, ret:%x\n", -+ arg.ret, ret); -+ if (!ret) -+ ret = -EIO; -+ } -+ -+ tee_shm_free(fw_shm); -+ -+ return ret; -+} -+EXPORT_SYMBOL(tee_rproc_load_fw); -+ -+int rproc_tee_get_rsc_table(struct tee_rproc *trproc) -+{ -+ struct tee_ioctl_invoke_arg arg; -+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; -+ struct rproc *rproc = trproc->rproc; -+ size_t rsc_size; -+ int ret; -+ -+ prepare_args(trproc, TA_RPROC_FW_CMD_GET_RSC_TABLE, &arg, param, 2); -+ -+ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; -+ param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; -+ -+ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); -+ if (ret < 0 || arg.ret != 0) { -+ dev_err(pvt_data.dev, -+ "TA_RPROC_FW_CMD_GET_RSC_TABLE invoke failed TEE err: %x, ret:%x\n", -+ arg.ret, ret); -+ return -EIO; -+ } -+ -+ rsc_size = param[2].u.value.a; -+ -+ /* -+ * Store the resource table address that would be updated by the remote -+ * core and the virtio. -+ */ -+ trproc->rsc_va = ioremap_wc(param[1].u.value.a, rsc_size); -+ if (IS_ERR_OR_NULL(trproc->rsc_va)) { -+ dev_err(pvt_data.dev, "Unable to map memory region: %lld+%zx\n", -+ param[1].u.value.a, rsc_size); -+ trproc->rsc_va = NULL; -+ return -ENOMEM; -+ } -+ -+ /* -+ * A cached table is requested as the physical address is not mapped yet -+ * but remoteproc need to parse the table for resources. -+ */ -+ rproc->cached_table = kmemdup(trproc->rsc_va, rsc_size, GFP_KERNEL); -+ if (!rproc->cached_table) -+ return -ENOMEM; -+ -+ rproc->table_ptr = rproc->cached_table; -+ rproc->table_sz = rsc_size; -+ -+ return 0; -+} -+EXPORT_SYMBOL(rproc_tee_get_rsc_table); -+ -+struct resource_table *tee_rproc_get_loaded_rsc_table(struct tee_rproc *trproc) -+{ -+ return (struct resource_table *)trproc->rsc_va; -+} -+EXPORT_SYMBOL(tee_rproc_get_loaded_rsc_table); -+ -+int tee_rproc_start(struct tee_rproc *trproc) -+{ -+ struct tee_ioctl_invoke_arg arg; -+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; -+ int ret; -+ -+ prepare_args(trproc, TA_RPROC_FW_CMD_START_FW, &arg, param, 0); -+ -+ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); -+ if (ret < 0 || arg.ret != 0) { -+ dev_err(pvt_data.dev, -+ "TA_RPROC_FW_CMD_START_FW invoke failed TEE err: %x, ret:%x\n", -+ arg.ret, ret); -+ if (!ret) -+ ret = -EIO; -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL(tee_rproc_start); -+ -+int tee_rproc_stop(struct tee_rproc *trproc) -+{ -+ struct tee_ioctl_invoke_arg arg; -+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; -+ int ret; -+ -+ prepare_args(trproc, TA_RPROC_FW_CMD_STOP_FW, &arg, param, 0); -+ -+ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); -+ if (ret < 0 || arg.ret != 0) { -+ dev_err(pvt_data.dev, -+ "TA_RPROC_FW_CMD_STOP_FW invoke failed TEE err: %x, ret:%x\n", -+ arg.ret, ret); -+ if (!ret) -+ ret = -EIO; -+ } -+ if (trproc->rsc_va) -+ iounmap(trproc->rsc_va); -+ trproc->rsc_va = NULL; -+ -+ return ret; -+} -+EXPORT_SYMBOL(tee_rproc_stop); -+ -+static const struct tee_client_device_id stm32_tee_fw_id_table[] = { -+ {UUID_INIT(0x80a4c275, 0x0a47, 0x4905, -+ 0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)}, -+ {} -+}; -+ -+struct tee_rproc *tee_rproc_register(struct device *dev, unsigned int fw_id) -+{ -+ struct tee_client_device *rproc_tee_device; -+ struct tee_ioctl_open_session_arg sess_arg; -+ struct tee_rproc *trproc; -+ int ret; -+ -+ if (!pvt_data.ctx) -+ return ERR_PTR(-ENODEV); -+ -+ trproc = devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL); -+ if (!trproc) -+ return ERR_PTR(-ENOMEM); -+ -+ rproc_tee_device = to_tee_client_device(pvt_data.dev); -+ memset(&sess_arg, 0, sizeof(sess_arg)); -+ -+ /* Open session with rproc_tee load Trusted App */ -+ memcpy(sess_arg.uuid, rproc_tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN); -+ -+ /* -+ * TODO: should we replace TEE_IOCTL_LOGIN_PUBLIC by -+ * TEE_IOCTL_LOGIN_REE_KERNEL? -+ */ -+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; -+ sess_arg.num_params = 0; -+ -+ ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL); -+ if (ret < 0 || sess_arg.ret != 0) { -+ dev_err(dev, "tee_client_open_session failed, err: %x\n", -+ sess_arg.ret); -+ return ERR_PTR(ret); -+ } -+ -+ trproc->parent = dev; -+ trproc->fw_id = fw_id; -+ trproc->session_id = sess_arg.session; -+ -+ list_add_tail(&trproc->node, &pvt_data.sessions); -+ -+ return trproc; -+} -+EXPORT_SYMBOL(tee_rproc_register); -+ -+int tee_rproc_unregister(struct tee_rproc *trproc) -+{ -+ int ret; -+ -+ if (!pvt_data.ctx) -+ return -ENODEV; -+ -+ ret = tee_client_close_session(pvt_data.ctx, trproc->session_id); -+ if (ret < 0) { -+ dev_err(trproc->parent, -+ "tee_client_close_session failed, err: %x\n", ret); -+ } -+ -+ list_del(&trproc->node); -+ -+ return ret; -+} -+EXPORT_SYMBOL(tee_rproc_unregister); -+ -+static int tee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) -+{ -+ /* Today we support only the OP-TEE, could be extend to other tees */ -+ return (ver->impl_id == TEE_IMPL_ID_OPTEE); -+} -+ -+static int tee_rproc_probe(struct device *dev) -+{ -+ /* Open context with TEE driver */ -+ pvt_data.ctx = tee_client_open_context(NULL, tee_ctx_match, NULL, -+ NULL); -+ if (IS_ERR(pvt_data.ctx)) -+ return PTR_ERR(pvt_data.ctx); -+ -+ pvt_data.dev = dev; -+ INIT_LIST_HEAD(&pvt_data.sessions); -+ -+ return 0; -+} -+ -+static int tee_rproc_remove(struct device *dev) -+{ -+ struct tee_rproc *entry, *tmp; -+ -+ list_for_each_entry_safe(entry, tmp, &pvt_data.sessions, node) { -+ tee_client_close_session(pvt_data.ctx, entry->session_id); -+ list_del(&entry->node); -+ kfree(entry); -+ } -+ -+ tee_client_close_context(pvt_data.ctx); -+ return 0; -+} -+ -+MODULE_DEVICE_TABLE(tee, stm32_tee_fw_id_table); -+ -+static struct tee_client_driver tee_rproc_fw_driver = { -+ .id_table = stm32_tee_fw_id_table, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .bus = &tee_bus_type, -+ .probe = tee_rproc_probe, -+ .remove = tee_rproc_remove, -+ }, -+}; -+ -+static int __init tee_rproc_fw_mod_init(void) -+{ -+ return driver_register(&tee_rproc_fw_driver.driver); -+} -+ -+static void __exit tee_rproc_fw_mod_exit(void) -+{ -+ driver_unregister(&tee_rproc_fw_driver.driver); -+} -+ -+module_init(tee_rproc_fw_mod_init); -+module_exit(tee_rproc_fw_mod_exit); -+ -+MODULE_DESCRIPTION("secure remote processor control driver"); -+MODULE_AUTHOR("Arnaud Pouliquen "); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig -index f96716893..7c8053aa9 100644 ---- a/drivers/rpmsg/Kconfig -+++ b/drivers/rpmsg/Kconfig -@@ -64,4 +64,13 @@ config RPMSG_VIRTIO - select RPMSG - select VIRTIO - -+config RPMSG_TTY -+ tristate "RPMSG tty driver" -+ depends on RPMSG -+ help -+ Say y here to export rpmsg endpoints as tty console, usually found -+ in /dev/ttyRPMSG. -+ This makes it possible for user-space programs to send and receive -+ rpmsg messages as a standard tty protocol. -+ - endmenu -diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile -index ffe932ef6..26a197365 100644 ---- a/drivers/rpmsg/Makefile -+++ b/drivers/rpmsg/Makefile -@@ -7,4 +7,5 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o - obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o - obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o - obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o -+obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o - obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o -diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c -index 91de94089..380500872 100644 ---- a/drivers/rpmsg/rpmsg_core.c -+++ b/drivers/rpmsg/rpmsg_core.c -@@ -283,6 +283,25 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, - } - EXPORT_SYMBOL(rpmsg_trysend_offchannel); - -+/** -+ * rpmsg_get_buffer_size() -+ * This function returns buffer size available for sending messages. -+ * -+ * @ept: the rpmsg endpoint -+ * -+ * Returns buffer size on success and an appropriate error value on failure. -+ */ -+int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept) -+{ -+ if (WARN_ON(!ept)) -+ return -EINVAL; -+ if (!ept->ops->get_buffer_size) -+ return -ENXIO; -+ -+ return ept->ops->get_buffer_size(ept); -+} -+EXPORT_SYMBOL(rpmsg_get_buffer_size); -+ - /* - * match a rpmsg channel with a channel info struct. - * this is used to make sure we're not creating rpmsg devices for channels -diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h -index 3fc83cd50..244292540 100644 ---- a/drivers/rpmsg/rpmsg_internal.h -+++ b/drivers/rpmsg/rpmsg_internal.h -@@ -47,6 +47,7 @@ struct rpmsg_device_ops { - * @trysendto: see @rpmsg_trysendto(), optional - * @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional - * @poll: see @rpmsg_poll(), optional -+ * @get_buffer_size: see @rpmsg_get_buffer_size(), optional - * - * Indirection table for the operations that a rpmsg backend should implement. - * In addition to @destroy_ept, the backend must at least implement @send and -@@ -66,6 +67,7 @@ struct rpmsg_endpoint_ops { - void *data, int len); - __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, - poll_table *wait); -+ int (*get_buffer_size)(struct rpmsg_endpoint *ept); - }; - - int rpmsg_register_device(struct rpmsg_device *rpdev); -diff --git a/drivers/rpmsg/rpmsg_tty.c b/drivers/rpmsg/rpmsg_tty.c -new file mode 100644 -index 000000000..b7bd11966 ---- /dev/null -+++ b/drivers/rpmsg/rpmsg_tty.c -@@ -0,0 +1,342 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Arnaud Pouliquen for STMicroelectronics. -+ * Derived from the imx-rmpsg and omap-rpmsg implementations. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MAX_TTY_RPMSG_INDEX 32 /* Should be enough for a while */ -+ -+static LIST_HEAD(rpmsg_tty_list); /* tty instances list */ -+static DEFINE_MUTEX(rpmsg_tty_lock); /* protect tty list */ -+ -+static struct tty_driver *rpmsg_tty_driver; -+static struct tty_port_operations rpmsg_tty_port_ops = { }; -+ -+struct rpmsg_tty_port { -+ struct tty_port *port; /* TTY port data */ -+ struct list_head list; /* TTY device list */ -+ u32 id; /* tty rpmsg index */ -+ spinlock_t rx_lock; /* message reception lock */ -+ struct rpmsg_device *rpdev; /* handle rpmsg device */ -+}; -+ -+static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, -+ void *priv, u32 src) -+{ -+ int space; -+ unsigned char *cbuf; -+ struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); -+ -+ /* Flush the recv-ed none-zero data to tty node */ -+ if (len == 0) -+ return -EINVAL; -+ -+ dev_dbg(&rpdev->dev, "msg(<- src 0x%x) len %d\n", src, len); -+ -+ print_hex_dump_debug(__func__, DUMP_PREFIX_NONE, 16, 1, data, len, -+ true); -+ -+ spin_lock(&cport->rx_lock); -+ space = tty_prepare_flip_string(cport->port, &cbuf, len); -+ if (space <= 0) { -+ dev_err(&rpdev->dev, "No memory for tty_prepare_flip_string\n"); -+ spin_unlock(&cport->rx_lock); -+ return -ENOMEM; -+ } -+ -+ if (space != len) -+ dev_warn(&rpdev->dev, "Trunc buffer from %d to %d\n", -+ len, space); -+ -+ memcpy(cbuf, data, space); -+ tty_flip_buffer_push(cport->port); -+ spin_unlock(&cport->rx_lock); -+ -+ return 0; -+} -+ -+static struct rpmsg_tty_port *rpmsg_tty_get(unsigned int index) -+{ -+ struct rpmsg_tty_port *cport; -+ -+ mutex_lock(&rpmsg_tty_lock); -+ list_for_each_entry(cport, &rpmsg_tty_list, list) { -+ if (index == cport->id) { -+ mutex_unlock(&rpmsg_tty_lock); -+ return cport; -+ } -+ } -+ mutex_unlock(&rpmsg_tty_lock); -+ -+ return NULL; -+} -+ -+static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty) -+{ -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ -+ if (!cport) -+ return -ENODEV; -+ -+ return tty_port_install(cport->port, driver, tty); -+} -+ -+static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp) -+{ -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ -+ if (!cport) -+ return -ENODEV; -+ -+ return tty_port_open(tty->port, tty, filp); -+} -+ -+static void rpmsg_tty_close(struct tty_struct *tty, struct file *filp) -+{ -+ tty_port_close(tty->port, tty, filp); -+} -+ -+static int rpmsg_tty_write(struct tty_struct *tty, const unsigned char *buf, -+ int total) -+{ -+ int count, ret = 0; -+ const unsigned char *tbuf; -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ -+ struct rpmsg_device *rpdev = cport->rpdev; -+ int msg_size; -+ -+ dev_dbg(&rpdev->dev, "%s: send message from tty->index = %d\n", -+ __func__, tty->index); -+ -+ if (!buf) { -+ dev_err(&rpdev->dev, "buf shouldn't be null.\n"); -+ return -ENOMEM; -+ } -+ -+ msg_size = rpmsg_get_buffer_size(rpdev->ept); -+ if (msg_size < 0) -+ return msg_size; -+ -+ count = total; -+ tbuf = buf; -+ do { -+ /* send a message to our remote processor */ -+ ret = rpmsg_trysend(rpdev->ept, (void *)tbuf, -+ count > msg_size ? msg_size : count); -+ if (ret) { -+ dev_dbg(&rpdev->dev, "rpmsg_send failed: %d\n", ret); -+ return 0; -+ } -+ -+ if (count > msg_size) { -+ count -= msg_size; -+ tbuf += msg_size; -+ } else { -+ count = 0; -+ } -+ } while (count > 0); -+ -+ tty_port_tty_wakeup(cport->port); -+ -+ return total; -+} -+ -+static int rpmsg_tty_write_room(struct tty_struct *tty) -+{ -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ struct rpmsg_device *rpdev = cport->rpdev; -+ -+ /* report the space in the rpmsg buffer */ -+ return rpmsg_get_buffer_size(rpdev->ept); -+} -+ -+static const struct tty_operations rpmsg_tty_ops = { -+ .install = rpmsg_tty_install, -+ .open = rpmsg_tty_open, -+ .close = rpmsg_tty_close, -+ .write = rpmsg_tty_write, -+ .write_room = rpmsg_tty_write_room, -+}; -+ -+static int rpmsg_tty_probe(struct rpmsg_device *rpdev) -+{ -+ struct rpmsg_tty_port *cport, *tmp; -+ unsigned int index; -+ struct device *tty_dev; -+ int ret = 0; -+ -+ cport = devm_kzalloc(&rpdev->dev, sizeof(*cport), GFP_KERNEL); -+ if (!cport) -+ return -ENOMEM; -+ -+ mutex_lock(&rpmsg_tty_lock); -+ -+ /* Get free index */ -+ for (index = 0; index < MAX_TTY_RPMSG_INDEX; index++) { -+ bool id_found = false; -+ -+ list_for_each_entry(tmp, &rpmsg_tty_list, list) { -+ if (index == tmp->id) { -+ id_found = true; -+ break; -+ } -+ } -+ if (!id_found) -+ break; -+ } -+ -+ if (index >= MAX_TTY_RPMSG_INDEX) { -+ ret = -ENOSPC; -+ goto end_probe; -+ } -+ -+ /* -+ * the tty port allocation has to be independent from the tty device -+ * The reason is that it can be use after device removing, for instance -+ * if a user has opened it. -+ * So it is not possible to release the port on device remove. -+ * A solution is to store the port in the driver structure. The port -+ * structure is reused on next probe to save memory. -+ */ -+ if (!rpmsg_tty_driver->ports[index]) { -+ /* first allocation of the port associated to the index */ -+ rpmsg_tty_driver->ports[index] = kzalloc(sizeof(*cport->port), -+ GFP_KERNEL); -+ if (!rpmsg_tty_driver->ports[index]) { -+ ret = -ENOMEM; -+ goto end_probe; -+ } -+ } -+ -+ cport->port = rpmsg_tty_driver->ports[index]; -+ tty_port_init(cport->port); -+ cport->port->ops = &rpmsg_tty_port_ops; -+ -+ spin_lock_init(&cport->rx_lock); -+ cport->port->low_latency = cport->port->flags | ASYNC_LOW_LATENCY; -+ cport->rpdev = rpdev; -+ -+ tty_dev = tty_port_register_device(cport->port, rpmsg_tty_driver, -+ index, &rpdev->dev); -+ if (IS_ERR(tty_dev)) { -+ dev_err(&rpdev->dev, "failed to register tty port\n"); -+ tty_port_destroy(cport->port); -+ ret = PTR_ERR(tty_dev); -+ goto end_probe; -+ } -+ -+ cport->id = index; -+ list_add_tail(&cport->list, &rpmsg_tty_list); -+ dev_set_drvdata(&rpdev->dev, cport); -+ -+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x : ttyRPMSG%d\n", -+ rpdev->src, rpdev->dst, index); -+end_probe: -+ mutex_unlock(&rpmsg_tty_lock); -+ -+ return ret; -+} -+ -+static void rpmsg_tty_remove(struct rpmsg_device *rpdev) -+{ -+ struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); -+ struct tty_struct *tty; -+ -+ tty_unregister_device(rpmsg_tty_driver, cport->id); -+ tty = tty_port_tty_get(cport->port); -+ if (tty) { -+ tty_vhangup(cport->port->tty); -+ tty_kref_put(tty); -+ } -+ list_del(&cport->list); -+ -+ dev_info(&rpdev->dev, "rpmsg tty device %d is removed\n", cport->id); -+} -+ -+static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = { -+ { .name = "rpmsg-tty-channel" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table); -+ -+static struct rpmsg_driver rpmsg_tty_rmpsg_drv = { -+ .drv.name = KBUILD_MODNAME, -+ .drv.owner = THIS_MODULE, -+ .id_table = rpmsg_driver_tty_id_table, -+ .probe = rpmsg_tty_probe, -+ .callback = rpmsg_tty_cb, -+ .remove = rpmsg_tty_remove, -+}; -+ -+static int __init rpmsg_tty_init(void) -+{ -+ int err; -+ -+ rpmsg_tty_driver = tty_alloc_driver(MAX_TTY_RPMSG_INDEX, 0); -+ if (IS_ERR(rpmsg_tty_driver)) -+ return PTR_ERR(rpmsg_tty_driver); -+ -+ rpmsg_tty_driver->driver_name = "rpmsg_tty"; -+ rpmsg_tty_driver->name = "ttyRPMSG"; -+ rpmsg_tty_driver->major = TTYAUX_MAJOR; -+ rpmsg_tty_driver->minor_start = 3; -+ rpmsg_tty_driver->type = TTY_DRIVER_TYPE_CONSOLE; -+ rpmsg_tty_driver->init_termios = tty_std_termios; -+ rpmsg_tty_driver->flags = TTY_DRIVER_REAL_RAW | -+ TTY_DRIVER_DYNAMIC_DEV; -+ -+ tty_set_operations(rpmsg_tty_driver, &rpmsg_tty_ops); -+ -+ /* Disable unused mode by default */ -+ rpmsg_tty_driver->init_termios = tty_std_termios; -+ rpmsg_tty_driver->init_termios.c_lflag &= ~(ECHO | ICANON); -+ rpmsg_tty_driver->init_termios.c_oflag &= ~(OPOST | ONLCR); -+ -+ err = tty_register_driver(rpmsg_tty_driver); -+ if (err < 0) { -+ pr_err("Couldn't install rpmsg tty driver: err %d\n", err); -+ goto tty_error; -+ } -+ err = register_rpmsg_driver(&rpmsg_tty_rmpsg_drv); -+ -+ if (!err) -+ return 0; -+ -+ tty_unregister_driver(rpmsg_tty_driver); -+ -+tty_error: -+ put_tty_driver(rpmsg_tty_driver); -+ -+ return err; -+} -+ -+static void __exit rpmsg_tty_exit(void) -+{ -+ unsigned int index; -+ -+ unregister_rpmsg_driver(&rpmsg_tty_rmpsg_drv); -+ tty_unregister_driver(rpmsg_tty_driver); -+ -+ /* release port allocations */ -+ for (index = 0; index < MAX_TTY_RPMSG_INDEX; index++) -+ kfree(rpmsg_tty_driver->ports[index]); -+ put_tty_driver(rpmsg_tty_driver); -+} -+ -+module_init(rpmsg_tty_init); -+module_exit(rpmsg_tty_exit); -+ -+MODULE_AUTHOR("Arnaud Pouliquen "); -+MODULE_DESCRIPTION("virtio remote processor messaging tty driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c -index 7d7ed4e5c..b8e60b34c 100644 ---- a/drivers/rpmsg/virtio_rpmsg_bus.c -+++ b/drivers/rpmsg/virtio_rpmsg_bus.c -@@ -181,6 +181,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, - int len, u32 dst); - static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, - u32 dst, void *data, int len); -+static int virtio_get_buffer_size(struct rpmsg_endpoint *ept); - - static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { - .destroy_ept = virtio_rpmsg_destroy_ept, -@@ -190,6 +191,7 @@ static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { - .trysend = virtio_rpmsg_trysend, - .trysendto = virtio_rpmsg_trysendto, - .trysend_offchannel = virtio_rpmsg_trysend_offchannel, -+ .get_buffer_size = virtio_get_buffer_size, - }; - - /** -@@ -705,6 +707,15 @@ static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, - return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); - } - -+static int virtio_get_buffer_size(struct rpmsg_endpoint *ept) -+{ -+ struct rpmsg_device *rpdev = ept->rpdev; -+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); -+ struct virtproc_info *vrp = vch->vrp; -+ -+ return vrp->buf_size - sizeof(struct rpmsg_hdr); -+} -+ - static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, - struct rpmsg_hdr *msg, unsigned int len) - { -diff --git a/include/linux/mailbox/arm-smccc-mbox.h b/include/linux/mailbox/arm-smccc-mbox.h -new file mode 100644 -index 000000000..d35fb89a7 ---- /dev/null -+++ b/include/linux/mailbox/arm-smccc-mbox.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+#ifndef _LINUX_ARM_SMCCC_MBOX_H_ -+#define _LINUX_ARM_SMCCC_MBOX_H_ -+ -+#include -+ -+/** -+ * struct arm_smccc_mbox_cmd - ARM SMCCC message structure -+ * @args_smccc32/64: actual usage of registers is up to the protocol -+ * (within the SMCCC limits) -+ */ -+struct arm_smccc_mbox_cmd { -+ union { -+ u32 args_smccc32[6]; -+ u64 args_smccc64[6]; -+ }; -+}; -+ -+#endif /* _LINUX_ARM_SMCCC_MBOX_H_ */ -diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h -index 9fe156d1c..2af767403 100644 ---- a/include/linux/rpmsg.h -+++ b/include/linux/rpmsg.h -@@ -135,6 +135,7 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, - __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, - poll_table *wait); - -+int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept); - #else - - static inline int register_rpmsg_device(struct rpmsg_device *dev) -@@ -242,6 +243,14 @@ static inline __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, - return 0; - } - -+static int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return -ENXIO; -+} -+ - #endif /* IS_ENABLED(CONFIG_RPMSG) */ - - /* use a macro to avoid include chaining to get THIS_MODULE */ -diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h -new file mode 100644 -index 000000000..5ba0b6116 ---- /dev/null -+++ b/include/linux/tee_remoteproc.h -@@ -0,0 +1,101 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright(c) 2020 STMicroelectronics 2020 -+ */ -+ -+#ifndef TEE_REMOTEPROC_H -+#define TEE_REMOTEPROC_H -+ -+#include -+#include -+ -+/** -+ * struct tee_rproc - TEE remoteproc structure -+ * @node: Reference in list -+ * @rproc: Remoteproc reference -+ * @parent: Parent device -+ * @fw_id: Identifier of the target firmware -+ * @session_id: TEE session identifier -+ * @rsc_va: Resource table virtual address. -+ */ -+struct tee_rproc { -+ struct list_head node; -+ -+ struct rproc *rproc; -+ struct device *parent; -+ u32 fw_id; -+ u32 session_id; -+ void *rsc_va; -+}; -+ -+#if IS_ENABLED(CONFIG_TEE_REMOTEPROC) -+ -+struct tee_rproc *tee_rproc_register(struct device *dev, unsigned int fw_id); -+int tee_rproc_unregister(struct tee_rproc *trproc); -+ -+int tee_rproc_load_fw(struct tee_rproc *trproc, const struct firmware *fw); -+int rproc_tee_get_rsc_table(struct tee_rproc *trproc); -+struct resource_table *tee_rproc_get_loaded_rsc_table(struct tee_rproc *trproc); -+int tee_rproc_start(struct tee_rproc *trproc); -+int tee_rproc_stop(struct tee_rproc *trproc); -+ -+#else -+ -+static inline struct tee_rproc *tee_rproc_register(struct device *dev, -+ unsigned int fw_id) -+{ -+ return ERR_PTR(-ENODEV); -+} -+ -+static inline int tee_rproc_unregister(struct tee_rproc *trproc) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return 0; -+} -+ -+static inline int tee_rproc_load_fw(struct tee_rproc *trproc, -+ const struct firmware *fw) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return 0; -+} -+ -+static inline int tee_rproc_start(struct tee_rproc *trproc) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return 0; -+} -+ -+static inline int tee_rproc_stop(struct tee_rproc *trproc) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return 0; -+} -+ -+static inline int rproc_tee_get_rsc_table(struct tee_rproc *trproc) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return 0; -+} -+ -+static inline struct resource_table * -+ tee_rproc_get_loaded_rsc_table(struct tee_rproc *trproc) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return NULL; -+} -+ -+#endif /* CONFIG_TEE_REMOTEPROC */ -+#endif /* TEE_REMOTEPROC_H */ --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0010-ARM-5.10.61-stm32mp1-r2-MEDIA-SOC-THERMAL.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0010-ARM-5.10.61-stm32mp1-r2-MEDIA-SOC-THERMAL.patch deleted file mode 100644 index 879c66a..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0010-ARM-5.10.61-stm32mp1-r2-MEDIA-SOC-THERMAL.patch +++ /dev/null @@ -1,1441 +0,0 @@ -From 75eede33771d5a5da7fcccae80f2b2682b4897b3 Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:46 +0200 -Subject: [PATCH 10/23] ARM 5.10.61-stm32mp1-r2 MEDIA-SOC-THERMAL - ---- - drivers/media/i2c/ov5640.c | 111 +++++++--- - drivers/media/platform/stm32/stm32-dcmi.c | 173 +++++++++++++--- - drivers/media/v4l2-core/v4l2-fwnode.c | 3 + - drivers/soc/Kconfig | 1 + - drivers/soc/Makefile | 1 + - drivers/soc/st/Kconfig | 17 ++ - drivers/soc/st/Makefile | 2 + - drivers/soc/st/stm32_hdp.c | 242 ++++++++++++++++++++++ - drivers/soc/st/stm32_pm_domain.c | 212 +++++++++++++++++++ - drivers/thermal/st/stm_thermal.c | 30 +-- - include/dt-bindings/soc/stm32-hdp.h | 108 ++++++++++ - include/media/v4l2-fwnode.h | 2 + - 12 files changed, 824 insertions(+), 78 deletions(-) - create mode 100644 drivers/soc/st/Kconfig - create mode 100644 drivers/soc/st/Makefile - create mode 100644 drivers/soc/st/stm32_hdp.c - create mode 100644 drivers/soc/st/stm32_pm_domain.c - create mode 100644 include/dt-bindings/soc/stm32-hdp.h - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 8f0812e85..d7d36ad86 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -65,6 +65,7 @@ - #define OV5640_REG_TIMING_VTS 0x380e - #define OV5640_REG_TIMING_TC_REG20 0x3820 - #define OV5640_REG_TIMING_TC_REG21 0x3821 -+#define OV5640_REG_DVP_PCLK_DIVIDER 0x3824 - #define OV5640_REG_AEC_CTRL00 0x3a00 - #define OV5640_REG_AEC_B50_STEP 0x3a08 - #define OV5640_REG_AEC_B60_STEP 0x3a0a -@@ -98,7 +99,8 @@ - #define OV5640_REG_AVG_READOUT 0x56a1 - - enum ov5640_mode_id { -- OV5640_MODE_QCIF_176_144 = 0, -+ OV5640_MODE_QQVGA_160_120 = 0, -+ OV5640_MODE_QCIF_176_144, - OV5640_MODE_QVGA_320_240, - OV5640_MODE_VGA_640_480, - OV5640_MODE_NTSC_720_480, -@@ -113,7 +115,6 @@ enum ov5640_mode_id { - enum ov5640_frame_rate { - OV5640_15_FPS = 0, - OV5640_30_FPS, -- OV5640_60_FPS, - OV5640_NUM_FRAMERATES, - }; - -@@ -155,7 +156,6 @@ MODULE_PARM_DESC(virtual_channel, - static const int ov5640_framerates[] = { - [OV5640_15_FPS] = 15, - [OV5640_30_FPS] = 30, -- [OV5640_60_FPS] = 60, - }; - - /* regulator supplies */ -@@ -219,6 +219,7 @@ struct ov5640_ctrls { - struct v4l2_ctrl *test_pattern; - struct v4l2_ctrl *hflip; - struct v4l2_ctrl *vflip; -+ struct v4l2_ctrl *link_freq; - }; - - struct ov5640_dev { -@@ -374,8 +375,8 @@ static const struct reg_value ov5640_setting_VGA_640_480[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4407, 0x04, 0, 0}, -+ {0x5001, 0xa3, 0, 0}, - }; - - static const struct reg_value ov5640_setting_XGA_1024_768[] = { -@@ -393,8 +394,7 @@ static const struct reg_value ov5640_setting_XGA_1024_768[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - - static const struct reg_value ov5640_setting_QVGA_320_240[] = { -@@ -412,8 +412,25 @@ static const struct reg_value ov5640_setting_QVGA_320_240[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, -+}; -+ -+static const struct reg_value ov5640_setting_QQVGA_160_120[] = { -+ {0x3c07, 0x08, 0, 0}, -+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -+ {0x3814, 0x31, 0, 0}, -+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, -+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, -+ {0x3810, 0x00, 0, 0}, -+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, -+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, -+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, -+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - - static const struct reg_value ov5640_setting_QCIF_176_144[] = { -@@ -431,8 +448,7 @@ static const struct reg_value ov5640_setting_QCIF_176_144[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - - static const struct reg_value ov5640_setting_NTSC_720_480[] = { -@@ -450,8 +466,7 @@ static const struct reg_value ov5640_setting_NTSC_720_480[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - - static const struct reg_value ov5640_setting_PAL_720_576[] = { -@@ -469,8 +484,7 @@ static const struct reg_value ov5640_setting_PAL_720_576[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - - static const struct reg_value ov5640_setting_720P_1280_720[] = { -@@ -488,8 +502,7 @@ static const struct reg_value ov5640_setting_720P_1280_720[] = { - {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, - {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, -- {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - - static const struct reg_value ov5640_setting_1080P_1920_1080[] = { -@@ -507,8 +520,8 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, -+ {0x4407, 0x04, 0, 0}, -+ {0x5001, 0x83, 0, 0}, - {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, -@@ -519,7 +532,6 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { - {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, - {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, - {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, -- {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, - {0x4005, 0x1a, 0, 0}, - }; - -@@ -538,8 +550,8 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, -+ {0x4407, 0x04, 0, 0}, -+ {0x5001, 0x83, 0, 70}, - }; - - /* power-on sensor init reg table */ -@@ -552,6 +564,11 @@ static const struct ov5640_mode_info ov5640_mode_init_data = { - - static const struct ov5640_mode_info - ov5640_mode_data[OV5640_NUM_MODES] = { -+ {OV5640_MODE_QQVGA_160_120, SUBSAMPLING, -+ 160, 1896, 120, 984, -+ ov5640_setting_QQVGA_160_120, -+ ARRAY_SIZE(ov5640_setting_QQVGA_160_120), -+ OV5640_30_FPS}, - {OV5640_MODE_QCIF_176_144, SUBSAMPLING, - 176, 1896, 144, 984, - ov5640_setting_QCIF_176_144, -@@ -566,7 +583,7 @@ ov5640_mode_data[OV5640_NUM_MODES] = { - 640, 1896, 480, 1080, - ov5640_setting_VGA_640_480, - ARRAY_SIZE(ov5640_setting_VGA_640_480), -- OV5640_60_FPS}, -+ OV5640_30_FPS}, - {OV5640_MODE_NTSC_720_480, SUBSAMPLING, - 720, 1896, 480, 984, - ov5640_setting_NTSC_720_480, -@@ -1018,9 +1035,38 @@ static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, - - static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) - { -+ const struct ov5640_mode_info *mode = sensor->current_mode; - u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; -+ struct i2c_client *client = sensor->i2c_client; -+ unsigned int pclk_freq, max_pclk_freq; -+ u8 dvp_pclk_divider; - int ret; - -+ /* -+ * 1280x720 and 1024x768 are reported to use 'SUBSAMPLING' only, -+ * but they seems to go through the scaler before subsampling. -+ */ -+ if (mode->dn_mode == SCALING || -+ (mode->id == OV5640_MODE_720P_1280_720) || -+ (mode->id == OV5640_MODE_XGA_1024_768)) -+ dvp_pclk_divider = 1; -+ else -+ dvp_pclk_divider = 2; -+ -+ ret = ov5640_write_reg(sensor, OV5640_REG_DVP_PCLK_DIVIDER, -+ dvp_pclk_divider); -+ if (ret) -+ return ret; -+ pclk_freq = rate / dvp_pclk_divider; -+ max_pclk_freq = sensor->ep.bus.parallel.pclk_max_frequency; -+ -+ /* clip rate according to optional maximum pixel clock limit */ -+ if (max_pclk_freq && (pclk_freq > max_pclk_freq)) { -+ rate = max_pclk_freq * dvp_pclk_divider; -+ dev_dbg(&client->dev, "DVP pixel clock too high (%d > %d Hz), reducing rate...\n", -+ pclk_freq, max_pclk_freq); -+ } -+ - ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, - &bit_div, &pclk_div); - -@@ -1055,6 +1101,7 @@ static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) - (ilog2(pclk_div) << 4)); - } - -+#if 0 - /* set JPEG framing sizes */ - static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode) -@@ -1078,19 +1125,20 @@ static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, - - return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); - } -+#endif - - /* download ov5640 settings to sensor through i2c */ - static int ov5640_set_timings(struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode) - { - int ret; -- -+#if 0 - if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { - ret = ov5640_set_jpeg_timings(sensor, mode); - if (ret < 0) - return ret; - } -- -+#endif - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); - if (ret < 0) - return ret; -@@ -2172,12 +2220,12 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, - int i; - - minfps = ov5640_framerates[OV5640_15_FPS]; -- maxfps = ov5640_framerates[OV5640_60_FPS]; -+ maxfps = ov5640_framerates[OV5640_30_FPS]; - - if (fi->numerator == 0) { - fi->denominator = maxfps; - fi->numerator = 1; -- rate = OV5640_60_FPS; -+ rate = OV5640_30_FPS; - goto find_mode; - } - -@@ -2260,6 +2308,10 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, - return 0; - } - -+static const s64 link_freq_menu_items[] = { -+ 384000000, -+}; -+ - static int ov5640_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -@@ -2700,6 +2752,8 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) - case V4L2_CID_VFLIP: - ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); - break; -+ case V4L2_CID_LINK_FREQ: -+ return 0; - default: - ret = -EINVAL; - break; -@@ -2772,6 +2826,9 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) - V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, - V4L2_CID_POWER_LINE_FREQUENCY_50HZ); - -+ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, -+ 0, 0, link_freq_menu_items); -+ - if (hdl->error) { - ret = hdl->error; - goto free_ctrls; -diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c -index fd1c41cba..af7fe3e37 100644 ---- a/drivers/media/platform/stm32/stm32-dcmi.c -+++ b/drivers/media/platform/stm32/stm32-dcmi.c -@@ -95,6 +95,9 @@ enum state { - #define MIN_HEIGHT 16U - #define MAX_HEIGHT 2592U - -+/* DMA can sustain YUV 720p@15fps max */ -+#define MAX_DMA_BANDWIDTH (1280 * 720 * 2 * 15) -+ - #define TIMEOUT_MS 1000 - - #define OVERRUN_ERROR_THRESHOLD 3 -@@ -120,7 +123,7 @@ struct dcmi_framesize { - struct dcmi_buf { - struct vb2_v4l2_buffer vb; - bool prepared; -- dma_addr_t paddr; -+ struct sg_table sgt; - size_t size; - struct list_head list; - }; -@@ -157,11 +160,13 @@ struct stm32_dcmi { - struct vb2_queue queue; - - struct v4l2_fwnode_bus_parallel bus; -+ enum v4l2_mbus_type bus_type; - struct completion complete; - struct clk *mclk; - enum state state; - struct dma_chan *dma_chan; - dma_cookie_t dma_cookie; -+ u32 dma_max_burst; - u32 misr; - int errors_count; - int overrun_count; -@@ -324,20 +329,19 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, - } - - /* -- * Avoid call of dmaengine_terminate_all() between -+ * Avoid call of dmaengine_terminate_sync() between - * dmaengine_prep_slave_single() and dmaengine_submit() - * by locking the whole DMA submission sequence - */ - mutex_lock(&dcmi->dma_lock); - - /* Prepare a DMA transaction */ -- desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr, -- buf->size, -+ desc = dmaengine_prep_slave_sg(dcmi->dma_chan, buf->sgt.sgl, -+ buf->sgt.nents, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { -- dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n", -- __func__, &buf->paddr, buf->size); -+ dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__); - mutex_unlock(&dcmi->dma_lock); - return -EINVAL; - } -@@ -438,7 +442,7 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi) - } - - /* Abort DMA operation */ -- dmaengine_terminate_all(dcmi->dma_chan); -+ dmaengine_terminate_sync(dcmi->dma_chan); - - /* Restart capture */ - if (dcmi_restart_capture(dcmi)) -@@ -529,6 +533,10 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb); - unsigned long size; -+ unsigned int num_sgs; -+ dma_addr_t dma_buf; -+ struct scatterlist *sg; -+ int i, ret; - - size = dcmi->fmt.fmt.pix.sizeimage; - -@@ -542,15 +550,35 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) - - if (!buf->prepared) { - /* Get memory addresses */ -- buf->paddr = -- vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); - buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0); -- buf->prepared = true; -+ if (buf->size <= dcmi->dma_max_burst) -+ num_sgs = 1; -+ else -+ num_sgs = DIV_ROUND_UP(buf->size, dcmi->dma_max_burst); -+ -+ ret = sg_alloc_table(&buf->sgt, num_sgs, GFP_ATOMIC); -+ if (ret) { -+ dev_err(dcmi->dev, "sg table alloc failed\n"); -+ return ret; -+ } - -- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); -+ dma_buf = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); - - dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n", -- vb->index, &buf->paddr, buf->size); -+ vb->index, &dma_buf, buf->size); -+ -+ for_each_sg(buf->sgt.sgl, sg, num_sgs, i) { -+ size_t bytes = min_t(size_t, size, dcmi->dma_max_burst); -+ -+ sg_dma_address(sg) = dma_buf; -+ sg_dma_len(sg) = bytes; -+ dma_buf += bytes; -+ size -= bytes; -+ } -+ -+ buf->prepared = true; -+ -+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); - } - - return 0; -@@ -777,6 +805,23 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - if (dcmi->bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - val |= CR_PCKPOL; - -+ /* -+ * BT656 embedded synchronisation bus mode. -+ * -+ * Default SAV/EAV mode is supported here with default codes -+ * SAV=0xff000080 & EAV=0xff00009d. -+ * With DCMI this means LSC=SAV=0x80 & LEC=EAV=0x9d. -+ */ -+ if (dcmi->bus_type == V4L2_MBUS_BT656) { -+ val |= CR_ESS; -+ -+ /* Unmask all codes */ -+ reg_write(dcmi->regs, DCMI_ESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */ -+ -+ /* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */ -+ reg_write(dcmi->regs, DCMI_ESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */ -+ } -+ - reg_write(dcmi->regs, DCMI_CR, val); - - /* Set crop */ -@@ -784,8 +829,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - dcmi_set_crop(dcmi); - - /* Enable jpeg capture */ -- if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) -- reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ -+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) { -+ unsigned int rate; -+ struct v4l2_streamparm p = { -+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE -+ }; -+ struct v4l2_fract frame_interval = {1, 30}; -+ -+ ret = v4l2_g_parm_cap(dcmi->vdev, dcmi->entity.source, &p); -+ if (!ret) -+ frame_interval = p.parm.capture.timeperframe; -+ -+ rate = dcmi->fmt.fmt.pix.sizeimage * -+ frame_interval.denominator / frame_interval.numerator; -+ -+ /* -+ * If rate exceed DMA capabilities, switch to snapshot mode -+ * to ensure that current DMA transfer is elapsed before -+ * capturing a new JPEG. -+ */ -+ if (rate > MAX_DMA_BANDWIDTH) { -+ reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ -+ dev_dbg(dcmi->dev, "Capture rate is too high for continuous mode (%d > %d bytes/s), switch to snapshot mode\n", -+ rate, MAX_DMA_BANDWIDTH); -+ } -+ } - - /* Enable dcmi */ - reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); -@@ -882,7 +950,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) - - /* Stop all pending DMA operations */ - mutex_lock(&dcmi->dma_lock); -- dmaengine_terminate_all(dcmi->dma_chan); -+ dmaengine_terminate_sync(dcmi->dma_chan); - mutex_unlock(&dcmi->dma_lock); - - pm_runtime_put(dcmi->dev); -@@ -1067,8 +1135,9 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) - if (ret) - return ret; - -- /* Disable crop if JPEG is requested */ -- if (pix->pixelformat == V4L2_PIX_FMT_JPEG) -+ /* Disable crop if JPEG is requested or BT656 bus is selected */ -+ if (pix->pixelformat == V4L2_PIX_FMT_JPEG && -+ dcmi->bus_type != V4L2_MBUS_BT656) - dcmi->do_crop = false; - - /* pix to mbus format */ -@@ -1574,6 +1643,22 @@ static const struct dcmi_format dcmi_formats[] = { - .fourcc = V4L2_PIX_FMT_JPEG, - .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, - .bpp = 1, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SBGGR8, -+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, -+ .bpp = 1, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGBRG8, -+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, -+ .bpp = 1, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGRBG8, -+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, -+ .bpp = 1, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SRGGB8, -+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, -+ .bpp = 1, - }, - }; - -@@ -1592,6 +1677,11 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) - if (dcmi_formats[i].mbus_code != mbus_code.code) - continue; - -+ /* Exclude JPEG if BT656 bus is selected */ -+ if (dcmi_formats[i].fourcc == V4L2_PIX_FMT_JPEG && -+ dcmi->bus_type == V4L2_MBUS_BT656) -+ continue; -+ - /* Code supported, have we got this fourcc yet? */ - for (j = 0; j < num_fmts; j++) - if (sd_fmts[j]->fourcc == -@@ -1745,6 +1835,15 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, - - dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); - -+ ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1); -+ if (ret) { -+ dev_err(dcmi->dev, "Failed to register video device\n"); -+ return ret; -+ } -+ -+ dev_dbg(dcmi->dev, "Device registered as %s\n", -+ video_device_node_name(dcmi->vdev)); -+ - /* - * Link this sub-device to DCMI, it could be - * a parallel camera sensor or a bridge -@@ -1757,10 +1856,11 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, - &dcmi->vdev->entity, 0, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); -- if (ret) -+ if (ret) { - dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n", - subdev->name); -- else -+ video_unregister_device(dcmi->vdev); -+ } else - dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", - subdev->name); - -@@ -1835,6 +1935,7 @@ static int dcmi_probe(struct platform_device *pdev) - struct stm32_dcmi *dcmi; - struct vb2_queue *q; - struct dma_chan *chan; -+ struct dma_slave_caps caps; - struct clk *mclk; - int irq; - int ret = 0; -@@ -1851,7 +1952,9 @@ static int dcmi_probe(struct platform_device *pdev) - - dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(dcmi->rstc)) { -- dev_err(&pdev->dev, "Could not get reset control\n"); -+ if (PTR_ERR(dcmi->rstc) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "Could not get reset control\n"); -+ - return PTR_ERR(dcmi->rstc); - } - -@@ -1873,9 +1976,18 @@ static int dcmi_probe(struct platform_device *pdev) - dev_err(&pdev->dev, "CSI bus not supported\n"); - return -ENODEV; - } -+ -+ if (ep.bus_type == V4L2_MBUS_BT656 && -+ ep.bus.parallel.bus_width != 8) { -+ dev_err(&pdev->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n", -+ ep.bus.parallel.bus_width); -+ return -ENODEV; -+ } -+ - dcmi->bus.flags = ep.bus.parallel.flags; - dcmi->bus.bus_width = ep.bus.parallel.bus_width; - dcmi->bus.data_shift = ep.bus.parallel.data_shift; -+ dcmi->bus_type = ep.bus_type; - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) -@@ -1917,6 +2029,12 @@ static int dcmi_probe(struct platform_device *pdev) - return ret; - } - -+ dcmi->dma_max_burst = UINT_MAX; -+ ret = dma_get_slave_caps(chan, &caps); -+ if (!ret && caps.max_sg_burst) -+ dcmi->dma_max_burst = caps.max_sg_burst * -+ DMA_SLAVE_BUSWIDTH_4_BYTES; -+ - spin_lock_init(&dcmi->irqlock); - mutex_init(&dcmi->lock); - mutex_init(&dcmi->dma_lock); -@@ -1972,15 +2090,6 @@ static int dcmi_probe(struct platform_device *pdev) - } - dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; - -- ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1); -- if (ret) { -- dev_err(dcmi->dev, "Failed to register video device\n"); -- goto err_media_entity_cleanup; -- } -- -- dev_dbg(dcmi->dev, "Device registered as %s\n", -- video_device_node_name(dcmi->vdev)); -- - /* Buffer queue */ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; -@@ -2001,7 +2110,7 @@ static int dcmi_probe(struct platform_device *pdev) - - ret = dcmi_graph_init(dcmi); - if (ret < 0) -- goto err_media_entity_cleanup; -+ goto err_vb2_queue_release; - - /* Reset device */ - ret = reset_control_assert(dcmi->rstc); -@@ -2027,7 +2136,10 @@ static int dcmi_probe(struct platform_device *pdev) - return 0; - - err_cleanup: -+ v4l2_async_notifier_unregister(&dcmi->notifier); - v4l2_async_notifier_cleanup(&dcmi->notifier); -+err_vb2_queue_release: -+ vb2_queue_release(q); - err_media_entity_cleanup: - media_entity_cleanup(&dcmi->vdev->entity); - err_device_release: -@@ -2049,6 +2161,7 @@ static int dcmi_remove(struct platform_device *pdev) - - v4l2_async_notifier_unregister(&dcmi->notifier); - v4l2_async_notifier_cleanup(&dcmi->notifier); -+ vb2_queue_release(&dcmi->queue); - media_entity_cleanup(&dcmi->vdev->entity); - v4l2_device_unregister(&dcmi->v4l2_dev); - media_device_cleanup(&dcmi->mdev); -diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index dfc53d110..7d0e2f5d1 100644 ---- a/drivers/media/v4l2-core/v4l2-fwnode.c -+++ b/drivers/media/v4l2-core/v4l2-fwnode.c -@@ -356,6 +356,9 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode, - pr_debug("data-enable-active %s\n", v ? "high" : "low"); - } - -+ if (!fwnode_property_read_u32(fwnode, "pclk-max-frequency", &v)) -+ bus->pclk_max_frequency = v; -+ - switch (bus_type) { - default: - bus->flags = flags; -diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig -index 425ab6f7e..30afdfbfd 100644 ---- a/drivers/soc/Kconfig -+++ b/drivers/soc/Kconfig -@@ -15,6 +15,7 @@ source "drivers/soc/renesas/Kconfig" - source "drivers/soc/rockchip/Kconfig" - source "drivers/soc/samsung/Kconfig" - source "drivers/soc/sifive/Kconfig" -+source "drivers/soc/st/Kconfig" - source "drivers/soc/sunxi/Kconfig" - source "drivers/soc/tegra/Kconfig" - source "drivers/soc/ti/Kconfig" -diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile -index 36452bed8..6b957db9a 100644 ---- a/drivers/soc/Makefile -+++ b/drivers/soc/Makefile -@@ -21,6 +21,7 @@ obj-y += renesas/ - obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ - obj-$(CONFIG_SOC_SAMSUNG) += samsung/ - obj-$(CONFIG_SOC_SIFIVE) += sifive/ -+obj-$(CONFIG_ARCH_STM32) += st/ - obj-y += sunxi/ - obj-$(CONFIG_ARCH_TEGRA) += tegra/ - obj-y += ti/ -diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig -new file mode 100644 -index 000000000..8ab604999 ---- /dev/null -+++ b/drivers/soc/st/Kconfig -@@ -0,0 +1,17 @@ -+if ARCH_STM32 -+ -+config STM32_PM_DOMAINS -+ bool "STM32 PM domains" -+ depends on MACH_STM32MP157 -+ select PM_GENERIC_DOMAINS -+ default y if MACH_STM32MP157 -+ -+config STM32_HDP -+ bool "STMicroelectronics STM32MP157 Hardware Debug Port (HDP) pin control" -+ depends on MACH_STM32MP157 -+ default n if MACH_STM32MP157 -+ help -+ The Hardware Debug Port allows the observation of internal signals. By using multiplexers, -+ up to 16 signals for each of 8-bit output can be observed. -+ -+endif # ARCH_STM32 -diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile -new file mode 100644 -index 000000000..85905b768 ---- /dev/null -+++ b/drivers/soc/st/Makefile -@@ -0,0 +1,2 @@ -+obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o -+obj-$(CONFIG_STM32_HDP) += stm32_hdp.o -diff --git a/drivers/soc/st/stm32_hdp.c b/drivers/soc/st/stm32_hdp.c -new file mode 100644 -index 000000000..47687ebd1 ---- /dev/null -+++ b/drivers/soc/st/stm32_hdp.c -@@ -0,0 +1,242 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Christophe Roullier -+ * for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define HDP_CTRL_ENABLE 1 -+#define HDP_CTRL_DISABLE 0 -+ -+enum { -+ HDP_CTRL = 0, -+ HDP_MUX = 0x4, -+ HDP_VAL = 0x10, -+ HDP_GPOSET = 0x14, -+ HDP_GPOCLR = 0x18, -+ HDP_GPOVAL = 0x1c, -+ HDP_VERR = 0x3f4, -+ HDP_IPIDR = 0x3f8, -+ HDP_SIDR = 0x3fc -+} HDP_register_offsets; -+ -+struct data_priv { -+ struct clk *clk; -+ int clk_is_enabled; -+ struct dentry *pwr_dentry; -+ unsigned char __iomem *hdp_membase; -+ unsigned int hdp_ctrl; -+ unsigned int hdp_mux; -+}; -+ -+/* enable/disable */ -+static int stm32_hdp_enable_set(void *data, int val) -+{ -+ struct data_priv *e = (struct data_priv *)data; -+ -+ if (!e->clk) -+ return -EPERM; -+ -+ if (val == 1) { -+ if (clk_prepare_enable(e->clk) < 0) { -+ pr_err("Failed to enable HDP clock\n"); -+ return -EPERM; -+ } -+ e->clk_is_enabled = 1; -+ } else { -+ clk_disable_unprepare(e->clk); -+ e->clk_is_enabled = 0; -+ } -+ return 0; -+} -+ -+static int stm32_hdp_fops_set(void *data, u64 val) -+{ -+ unsigned char __iomem *addr = (unsigned char __iomem *)data; -+ -+ writel_relaxed(val, addr); -+ -+ return 0; -+} -+ -+static int stm32_hdp_fops_get(void *data, u64 *val) -+{ -+ unsigned char __iomem *addr = (unsigned char __iomem *)data; -+ -+ *val = readl_relaxed(addr); -+ -+ return 0; -+} -+ -+DEFINE_SIMPLE_ATTRIBUTE(stm32_hdp_fops, stm32_hdp_fops_get, -+ stm32_hdp_fops_set, "0x%llx\n"); -+ -+static int stm32_hdp_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct device *dev = &pdev->dev; -+ struct resource *res; -+ -+ struct data_priv *data; -+ struct dentry *r; -+ -+ int ret; -+ const __be32 *getmuxing; -+ u32 muxing, version; -+ -+ if (!np) -+ return -ENODEV; -+ -+ data = devm_kzalloc(&pdev->dev, sizeof(struct data_priv), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ data->hdp_membase = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(data->hdp_membase)) -+ return PTR_ERR(data->hdp_membase); -+ -+ /* Get HDP clocks */ -+ data->clk = devm_clk_get(dev, "hdp"); -+ if (IS_ERR(data->clk)) { -+ dev_err(dev, "No HDP CK clock provided...\n"); -+ return PTR_ERR(data->clk); -+ } -+ -+ /* Enable clock */ -+ ret = stm32_hdp_enable_set(data, 1); -+ if (ret != 0) -+ return ret; -+ -+ getmuxing = of_get_property(np, "muxing-hdp", NULL); -+ if (!getmuxing) { -+ dev_err(dev, -+ "no muxing-hdp property in node\n"); -+ /* Disable clock */ -+ ret = stm32_hdp_enable_set(data, 0); -+ if (ret != 0) -+ return ret; -+ -+ return -EINVAL; -+ } -+ -+ /* add hdp directory */ -+ r = debugfs_create_dir("hdp", NULL); -+ if (!r) { -+ dev_err(dev, "Unable to create HDP debugFS\n"); -+ /* Disable clock */ -+ ret = stm32_hdp_enable_set(data, 0); -+ if (ret != 0) -+ return ret; -+ -+ return -ENODEV; -+ } -+ -+ debugfs_create_file("ctrl", 0644, r, -+ data->hdp_membase + HDP_CTRL, &stm32_hdp_fops); -+ debugfs_create_file("mux", 0644, r, -+ data->hdp_membase + HDP_MUX, &stm32_hdp_fops); -+ debugfs_create_file("val", 0644, r, -+ data->hdp_membase + HDP_VAL, &stm32_hdp_fops); -+ debugfs_create_file("gposet", 0644, r, -+ data->hdp_membase + HDP_GPOSET, &stm32_hdp_fops); -+ debugfs_create_file("gpoclr", 0644, r, -+ data->hdp_membase + HDP_GPOCLR, &stm32_hdp_fops); -+ debugfs_create_file("gpoval", 0644, r, -+ data->hdp_membase + HDP_GPOVAL, &stm32_hdp_fops); -+ -+ /* Enable HDP */ -+ writel(HDP_CTRL_ENABLE, data->hdp_membase + HDP_CTRL); -+ -+ /* HDP Multiplexing */ -+ muxing = of_read_number(getmuxing, -+ of_n_addr_cells(np)); -+ -+ writel(muxing, data->hdp_membase + HDP_MUX); -+ -+ platform_set_drvdata(pdev, data); -+ -+ /* Get Majeur, Minor version */ -+ version = readl(data->hdp_membase + HDP_VERR); -+ -+ dev_info(dev, "STM32 HDP version %d.%d initialized\n", -+ version >> 4, version & 0x0F); -+ -+ return 0; -+} -+ -+static int stm32_hdp_remove(struct platform_device *pdev) -+{ -+ struct data_priv *data = platform_get_drvdata(pdev); -+ -+ /* Disable HDP */ -+ writel(HDP_CTRL_DISABLE, data->hdp_membase + HDP_CTRL); -+ -+ if (data->clk) { -+ if (data->clk_is_enabled) -+ clk_disable_unprepare(data->clk); -+ } -+ -+ pr_info("driver STM32 HDP removed\n"); -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm32_hdp_suspend(struct device *dev) -+{ -+ struct data_priv *data = dev_get_drvdata(dev); -+ -+ data->hdp_ctrl = readl_relaxed(data->hdp_membase + HDP_CTRL); -+ data->hdp_mux = readl_relaxed(data->hdp_membase + HDP_MUX); -+ -+ pinctrl_pm_select_sleep_state(dev); -+ -+ return 0; -+} -+ -+static int stm32_hdp_resume(struct device *dev) -+{ -+ struct data_priv *data = dev_get_drvdata(dev); -+ -+ writel_relaxed(data->hdp_ctrl, data->hdp_membase + HDP_CTRL); -+ writel_relaxed(data->hdp_mux, data->hdp_membase + HDP_MUX); -+ -+ pinctrl_pm_select_default_state(dev); -+ -+ return 0; -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static SIMPLE_DEV_PM_OPS(stm32_hdp_pm_ops, -+ stm32_hdp_suspend, -+ stm32_hdp_resume); -+ -+static const struct of_device_id hdp_match[] = { -+ { .compatible = "st,stm32mp1-hdp",}, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, hdp_match); -+ -+static struct platform_driver hdp_driver = { -+ .probe = stm32_hdp_probe, -+ .remove = stm32_hdp_remove, -+ .driver = { -+ .name = "hdp", -+ .of_match_table = hdp_match, -+ .pm = &stm32_hdp_pm_ops, -+ }, -+}; -+ -+module_platform_driver(hdp_driver); -diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c -new file mode 100644 -index 000000000..0386624c2 ---- /dev/null -+++ b/drivers/soc/st/stm32_pm_domain.c -@@ -0,0 +1,212 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Alexandre Torgue for STMicroelectronics. -+ * Author: Olivier Bideau for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SMC(domain, state) \ -+{ \ -+ struct arm_smccc_res res; \ -+ arm_smccc_smc(0x82001008, domain, state, 0, \ -+ 0, 0, 0, 0, &res); \ -+} -+ -+#define STM32_SMC_PD_DOMAIN_ON 0 -+#define STM32_SMC_PD_DOMAIN_OFF 1 -+ -+struct stm32_pm_domain { -+ struct device *dev; -+ struct generic_pm_domain genpd; -+ int id; -+}; -+ -+static int stm32_pd_power_off(struct generic_pm_domain *domain) -+{ -+ struct stm32_pm_domain *priv = container_of(domain, -+ struct stm32_pm_domain, -+ genpd); -+ -+ SMC(priv->id, STM32_SMC_PD_DOMAIN_OFF); -+ -+ dev_dbg(priv->dev, "%s OFF\n", domain->name); -+ -+ return 0; -+} -+ -+static int stm32_pd_power_on(struct generic_pm_domain *domain) -+{ -+ struct stm32_pm_domain *priv = container_of(domain, -+ struct stm32_pm_domain, -+ genpd); -+ -+ SMC(priv->id, STM32_SMC_PD_DOMAIN_ON); -+ -+ dev_dbg(priv->dev, "%s ON\n", domain->name); -+ -+ return 0; -+} -+ -+static void stm32_pm_domain_remove(struct stm32_pm_domain *domain) -+{ -+ int ret; -+ -+ ret = pm_genpd_remove(&domain->genpd); -+ if (ret) -+ dev_err(domain->dev, "failed to remove PM domain %s: %d\n", -+ domain->genpd.name, ret); -+} -+ -+static int stm32_pm_domain_add(struct stm32_pm_domain *domain, -+ struct device *dev, -+ struct device_node *np) -+{ -+ int ret; -+ -+ domain->dev = dev; -+ domain->genpd.name = np->name; -+ domain->genpd.power_off = stm32_pd_power_off; -+ domain->genpd.power_on = stm32_pd_power_on; -+ domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; -+ -+ ret = of_property_read_u32(np, "reg", &domain->id); -+ if (ret) { -+ dev_err(domain->dev, "no domain ID\n"); -+ return ret; -+ } -+ -+ ret = pm_genpd_init(&domain->genpd, NULL, 0); -+ if (ret < 0) { -+ dev_err(domain->dev, "failed to initialise PM domain %s: %d\n", -+ np->name, ret); -+ return ret; -+ } -+ -+ ret = of_genpd_add_provider_simple(np, &domain->genpd); -+ if (ret < 0) { -+ dev_err(domain->dev, "failed to register PM domain %s: %d\n", -+ np->name, ret); -+ stm32_pm_domain_remove(domain); -+ return ret; -+ } -+ -+ dev_info(domain->dev, "domain %s registered\n", np->name); -+ -+ return 0; -+} -+ -+static void stm32_pm_subdomain_add(struct stm32_pm_domain *domain, -+ struct device *dev, -+ struct device_node *np) -+{ -+ struct device_node *np_child; -+ int ret; -+ -+ for_each_child_of_node(np, np_child) { -+ struct stm32_pm_domain *sub_domain; -+ -+ sub_domain = devm_kzalloc(dev, sizeof(*sub_domain), GFP_KERNEL); -+ if (!sub_domain) -+ continue; -+ -+ sub_domain->dev = dev; -+ sub_domain->genpd.name = np_child->name; -+ sub_domain->genpd.power_off = stm32_pd_power_off; -+ sub_domain->genpd.power_on = stm32_pd_power_on; -+ sub_domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; -+ -+ ret = of_property_read_u32(np_child, "reg", &sub_domain->id); -+ if (ret) { -+ dev_err(sub_domain->dev, "no domain ID\n"); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ ret = pm_genpd_init(&sub_domain->genpd, NULL, 0); -+ if (ret < 0) { -+ dev_err(sub_domain->dev, "failed to initialise PM domain %s: %d\n" -+ , np_child->name, ret); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ ret = of_genpd_add_provider_simple(np_child, -+ &sub_domain->genpd); -+ if (ret < 0) { -+ dev_err(sub_domain->dev, "failed to register PM domain %s: %d\n" -+ , np_child->name, ret); -+ stm32_pm_domain_remove(sub_domain); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ ret = pm_genpd_add_subdomain(&domain->genpd, -+ &sub_domain->genpd); -+ -+ if (ret < 0) { -+ dev_err(sub_domain->dev, "failed to add Sub PM domain %s: %d\n" -+ , np_child->name, ret); -+ stm32_pm_domain_remove(sub_domain); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ dev_info(sub_domain->dev, "subdomain %s registered\n", -+ np_child->name); -+ } -+} -+ -+static int stm32_pm_domain_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node, *child_np; -+ int ret; -+ -+ for_each_child_of_node(np, child_np) { -+ struct stm32_pm_domain *domain; -+ -+ domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); -+ if (!domain) -+ continue; -+ -+ ret = stm32_pm_domain_add(domain, dev, child_np); -+ if (ret) { -+ devm_kfree(dev, domain); -+ continue; -+ } -+ -+ stm32_pm_subdomain_add(domain, dev, child_np); -+ } -+ -+ dev_info(dev, "domains probed\n"); -+ -+ return 0; -+} -+ -+static const struct of_device_id stm32_pm_domain_matches[] = { -+ { .compatible = "st,stm32mp157c-pd", }, -+ { }, -+}; -+ -+static struct platform_driver stm32_pm_domains_driver = { -+ .probe = stm32_pm_domain_probe, -+ .driver = { -+ .name = "stm32-pm-domain", -+ .of_match_table = stm32_pm_domain_matches, -+ }, -+}; -+ -+static int __init stm32_pm_domains_init(void) -+{ -+ return platform_driver_register(&stm32_pm_domains_driver); -+} -+core_initcall(stm32_pm_domains_init); -diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c -index 5fd3fb891..1e065a332 100644 ---- a/drivers/thermal/st/stm_thermal.c -+++ b/drivers/thermal/st/stm_thermal.c -@@ -82,8 +82,7 @@ - #define ONE_MHZ 1000000 - #define POLL_TIMEOUT 5000 - #define STARTUP_TIME 40 --#define TS1_T0_VAL0 30000 /* 30 celsius */ --#define TS1_T0_VAL1 130000 /* 130 celsius */ -+#define T0 30000 /* 30 celsius */ - #define NO_HW_TRIG 0 - #define SAMPLING_TIME 15 - -@@ -96,7 +95,7 @@ struct stm_thermal_sensor { - unsigned int high_temp_enabled; - int irq; - void __iomem *base; -- int t0, fmt0, ramp_coeff; -+ int fmt0, ramp_coeff; - }; - - static int stm_enable_irq(struct stm_thermal_sensor *sensor) -@@ -243,14 +242,6 @@ static int stm_thermal_calibration(struct stm_thermal_sensor *sensor) - /* Fill in DTS structure with factory sensor values */ - static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor) - { -- /* Retrieve engineering calibration temperature */ -- sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) & -- TS1_T0_MASK; -- if (!sensor->t0) -- sensor->t0 = TS1_T0_VAL0; -- else -- sensor->t0 = TS1_T0_VAL1; -- - /* Retrieve fmt0 and put it on Hz */ - sensor->fmt0 = ADJUST * (readl_relaxed(sensor->base + - DTS_T0VALR1_OFFSET) & TS1_FMT0_MASK); -@@ -264,8 +255,8 @@ static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor) - return -EINVAL; - } - -- dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC", -- __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff); -+ dev_dbg(sensor->dev, "%s: FMT0 = %dHz, RAMP_COEFF = %dHz/oC", -+ __func__, sensor->fmt0, sensor->ramp_coeff); - - return 0; - } -@@ -276,8 +267,7 @@ static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor, - int freqM; - - /* Figure out the CLK_PTAT frequency for a given temperature */ -- freqM = ((temp - sensor->t0) * sensor->ramp_coeff) / 1000 + -- sensor->fmt0; -+ freqM = ((temp - T0) * sensor->ramp_coeff) / 1000 + sensor->fmt0; - - /* Figure out the threshold sample number */ - *th = clk_get_rate(sensor->clk) * SAMPLING_TIME / freqM; -@@ -372,7 +362,7 @@ static int stm_thermal_get_temp(void *data, int *temp) - return -EINVAL; - - /* Figure out the temperature in mili celsius */ -- *temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + sensor->t0; -+ *temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + T0; - - return 0; - } -@@ -515,11 +505,9 @@ static int stm_thermal_probe(struct platform_device *pdev) - sensor->base = base; - - sensor->clk = devm_clk_get(&pdev->dev, "pclk"); -- if (IS_ERR(sensor->clk)) { -- dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n", -- __func__); -- return PTR_ERR(sensor->clk); -- } -+ if (IS_ERR(sensor->clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(sensor->clk), -+ "Failed to get PCLK clock\n"); - - stm_disable_irq(sensor); - -diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h -new file mode 100644 -index 000000000..d98665327 ---- /dev/null -+++ b/include/dt-bindings/soc/stm32-hdp.h -@@ -0,0 +1,108 @@ -+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Roullier Christophe -+ * for STMicroelectronics. -+ */ -+ -+#ifndef _DT_BINDINGS_STM32_HDP_H -+#define _DT_BINDINGS_STM32_HDP_H -+ -+#define STM32_HDP(port, value) ((value) << ((port) * 4)) -+ -+/* define HDP Pins number*/ -+#define HDP0_PWR_PWRWAKE_SYS 0 -+#define HDP0_CM4_SLEEPDEEP 1 -+#define HDP0_PWR_STDBY_WKUP 2 -+#define HDP0_PWR_ENCOMP_VDDCORE 3 -+#define HDP0_BSEC_OUT_SEC_NIDEN 4 -+#define HDP0_RCC_CM4_SLEEPDEEP 6 -+#define HDP0_GPU_DBG7 7 -+#define HDP0_DDRCTRL_LP_REQ 8 -+#define HDP0_PWR_DDR_RET_ENABLE_N 9 -+#define HDP0_GPOVAL_0 15 -+ -+#define HDP1_PWR_PWRWAKE_MCU 0 -+#define HDP1_CM4_HALTED 1 -+#define HDP1_CA7_NAXIERRIRQ 2 -+#define HDP1_PWR_OKIN_MR 3 -+#define HDP1_BSEC_OUT_SEC_DBGEN 4 -+#define HDP1_EXTI_SYS_WAKEUP 5 -+#define HDP1_RCC_PWRDS_MPU 6 -+#define HDP1_GPU_DBG6 7 -+#define HDP1_DDRCTRL_DFI_CTRLUPD_REQ 8 -+#define HDP1_DDRCTRL_CACTIVE_DDRC_ASR 9 -+#define HDP1_GPOVAL_1 15 -+ -+#define HDP2_PWR_PWRWAKE_MPU 0 -+#define HDP2_CM4_RXEV 1 -+#define HDP2_CA7_NPMUIRQ1 2 -+#define HDP2_CA7_NFIQOUT1 3 -+#define HDP2_BSEC_IN_RSTCORE_N 4 -+#define HDP2_EXTI_C2_WAKEUP 5 -+#define HDP2_RCC_PWRDS_MCU 6 -+#define HDP2_GPU_DBG5 7 -+#define HDP2_DDRCTRL_DFI_INIT_COMPLETE 8 -+#define HDP2_DDRCTRL_PERF_OP_IS_REFRESH 9 -+#define HDP2_DDRCTRL_GSKP_DFI_LP_REQ 10 -+#define HDP2_GPOVAL_2 15 -+ -+#define HDP3_PWR_SEL_VTH_VDD_CORE 0 -+#define HDP3_CM4_TXEV 1 -+#define HDP3_CA7_NPMUIRQ0 2 -+#define HDP3_CA7_NFIQOUT0 3 -+#define HDP3_BSEC_OUT_SEC_DFTLOCK 4 -+#define HDP3_EXTI_C1_WAKEUP 5 -+#define HDP3_RCC_PWRDS_SYS 6 -+#define HDP3_GPU_DBG4 7 -+#define HDP3_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE0 8 -+#define HDP3_DDRCTRL_CACTIVE_1 9 -+#define HDP3_GPOVAL_3 15 -+ -+#define HDP4_PWR_PDDS 0 -+#define HDP4_CM4_SLEEPING 1 -+#define HDP4_CA7_NRESET1 2 -+#define HDP4_CA7_NIRQOUT1 3 -+#define HDP4_BSEC_OUT_SEC_DFTEN 4 -+#define HDP4_BSEC_OUT_SEC_DBGSWENABLE 5 -+#define HDP4_ETH_OUT_PMT_INTR_O 6 -+#define HDP4_GPU_DBG3 7 -+#define HDP4_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE1 8 -+#define HDP4_DDRCTRL_CACTIVE_0 9 -+#define HDP4_GPOVAL_4 15 -+ -+#define HDP5_CA7_STANDBYWFIL2 0 -+#define HDP5_PWR_VTH_VDDCORE_ACK 1 -+#define HDP5_CA7_NRESET0 2 -+#define HDP5_CA7_NIRQOUT0 3 -+#define HDP5_BSEC_IN_PWROK 4 -+#define HDP5_BSEC_OUT_SEC_DEVICEEN 5 -+#define HDP5_ETH_OUT_LPI_INTR_O 6 -+#define HDP5_GPU_DBG2 7 -+#define HDP5_DDRCTRL_CACTIVE_DDRC 8 -+#define HDP5_DDRCTRL_WR_CREDIT_CNT 9 -+#define HDP5_GPOVAL_5 15 -+ -+#define HDP6_CA7_STANDBYWFI1 0 -+#define HDP6_CA7_STANDBYWFE1 1 -+#define HDP6_CA7_EVENT0 2 -+#define HDP6_CA7_DBGACK1 3 -+#define HDP6_BSEC_OUT_SEC_SPNIDEN 5 -+#define HDP6_ETH_OUT_MAC_SPEED_O1 6 -+#define HDP6_GPU_DBG1 7 -+#define HDP6_DDRCTRL_CSYSACK_DDRC 8 -+#define HDP6_DDRCTRL_LPR_CREDIT_CNT 9 -+#define HDP6_GPOVAL_6 15 -+ -+#define HDP7_CA7_STANDBYWFI0 0 -+#define HDP7_CA7_STANDBYWFE0 1 -+#define HDP7_CA7_DBGACK0 3 -+#define HDP7_BSEC_OUT_FUSE_OK 4 -+#define HDP7_BSEC_OUT_SEC_SPIDEN 5 -+#define HDP7_ETH_OUT_MAC_SPEED_O0 6 -+#define HDP7_GPU_DBG0 7 -+#define HDP7_DDRCTRL_CSYSREQ_DDRC 8 -+#define HDP7_DDRCTRL_HPR_CREDIT_CNT 9 -+#define HDP7_GPOVAL_7 15 -+ -+#endif /* _DT_BINDINGS_STM32_HDP_H */ -diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h -index ed0840f3d..598822e23 100644 ---- a/include/media/v4l2-fwnode.h -+++ b/include/media/v4l2-fwnode.h -@@ -49,11 +49,13 @@ struct v4l2_fwnode_bus_mipi_csi2 { - * @flags: media bus (V4L2_MBUS_*) flags - * @bus_width: bus width in bits - * @data_shift: data shift in bits -+ * @max_pclk_frequency: maximum pixel clock in hertz - */ - struct v4l2_fwnode_bus_parallel { - unsigned int flags; - unsigned char bus_width; - unsigned char data_shift; -+ unsigned int pclk_max_frequency; - }; - - /** --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0012-ARM-5.10.61-stm32mp1-r2-MMC.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0012-ARM-5.10.61-stm32mp1-r2-MMC.patch deleted file mode 100644 index acd1f3e..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0012-ARM-5.10.61-stm32mp1-r2-MMC.patch +++ /dev/null @@ -1,40 +0,0 @@ -From b1ce5fb5a80db8945c9496f8ad9a74280d31ecf8 Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:47 +0200 -Subject: [PATCH 12/23] ARM 5.10.61-stm32mp1-r2 MMC - ---- - drivers/mmc/core/mmc_test.c | 2 +- - drivers/mmc/host/mmci.c | 3 --- - 2 files changed, 1 insertion(+), 4 deletions(-) - -diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c -index 152e7525e..b1f0d04f9 100644 ---- a/drivers/mmc/core/mmc_test.c -+++ b/drivers/mmc/core/mmc_test.c -@@ -2124,7 +2124,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test, - if (mmc_can_erase(test->card) && - tdata->prepare & MMC_TEST_PREP_ERASE) { - ret = mmc_erase(test->card, dev_addr, -- size / 512, MMC_SECURE_ERASE_ARG); -+ size / 512, test->card->erase_arg); - if (ret) - ret = mmc_erase(test->card, dev_addr, - size / 512, MMC_ERASE_ARG); -diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index 9bde0def1..fa6d85190 100644 ---- a/drivers/mmc/host/mmci.c -+++ b/drivers/mmc/host/mmci.c -@@ -2104,9 +2104,6 @@ static int mmci_probe(struct amba_device *dev, - host->stop_abort.arg = 0; - host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; - -- /* We support these PM capabilities. */ -- mmc->pm_caps |= MMC_PM_KEEP_POWER; -- - /* - * We can do SGIO - */ --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0015-ARM-5.10.61-stm32mp1-r2-PHY-USB.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0015-ARM-5.10.61-stm32mp1-r2-PHY-USB.patch deleted file mode 100644 index b34153e..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0015-ARM-5.10.61-stm32mp1-r2-PHY-USB.patch +++ /dev/null @@ -1,1527 +0,0 @@ -From a936dc53617e4f56a85fc96fb7dd4567261a160d Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:49 +0200 -Subject: [PATCH 15/23] ARM 5.10.61-stm32mp1-r2 PHY-USB - ---- - drivers/phy/st/phy-stm32-usbphyc.c | 509 +++++++++++++++++++++++++---- - drivers/usb/core/hcd.c | 9 +- - drivers/usb/core/phy.c | 22 +- - drivers/usb/core/phy.h | 6 +- - drivers/usb/dwc2/core.c | 123 ++++--- - drivers/usb/dwc2/core.h | 14 + - drivers/usb/dwc2/drd.c | 37 ++- - drivers/usb/dwc2/gadget.c | 6 +- - drivers/usb/dwc2/hcd.c | 7 +- - drivers/usb/dwc2/params.c | 24 ++ - drivers/usb/dwc2/platform.c | 47 ++- - drivers/usb/host/ehci-platform.c | 16 +- - 12 files changed, 662 insertions(+), 158 deletions(-) - -diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c -index 2b3639cba..f21160659 100644 ---- a/drivers/phy/st/phy-stm32-usbphyc.c -+++ b/drivers/phy/st/phy-stm32-usbphyc.c -@@ -7,8 +7,9 @@ - */ - #include - #include -+#include - #include --#include -+#include - #include - #include - #include -@@ -17,6 +18,8 @@ - - #define STM32_USBPHYC_PLL 0x0 - #define STM32_USBPHYC_MISC 0x8 -+#define STM32_USBPHYC_MONITOR(X) (0x108 + ((X) * 0x100)) -+#define STM32_USBPHYC_TUNE(X) (0x10C + ((X) * 0x100)) - #define STM32_USBPHYC_VERSION 0x3F4 - - /* STM32_USBPHYC_PLL bit fields */ -@@ -32,19 +35,93 @@ - /* STM32_USBPHYC_MISC bit fields */ - #define SWITHOST BIT(0) - --/* STM32_USBPHYC_VERSION bit fields */ --#define MINREV GENMASK(3, 0) --#define MAJREV GENMASK(7, 4) -+/* STM32_USBPHYC_MONITOR bit fields */ -+#define STM32_USBPHYC_MON_OUT GENMASK(3, 0) -+#define STM32_USBPHYC_MON_SEL GENMASK(8, 4) -+#define STM32_USBPHYC_MON_SEL_LOCKP 0x1F -+#define STM32_USBPHYC_MON_OUT_LOCKP BIT(3) -+ -+/* STM32_USBPHYC_TUNE bit fields */ -+#define INCURREN BIT(0) -+#define INCURRINT BIT(1) -+#define LFSCAPEN BIT(2) -+#define HSDRVSLEW BIT(3) -+#define HSDRVDCCUR BIT(4) -+#define HSDRVDCLEV BIT(5) -+#define HSDRVCURINCR BIT(6) -+#define FSDRVRFADJ BIT(7) -+#define HSDRVRFRED BIT(8) -+#define HSDRVCHKITRM GENMASK(12, 9) -+#define HSDRVCHKZTRM GENMASK(14, 13) -+#define OTPCOMP GENMASK(19, 15) -+#define SQLCHCTL GENMASK(21, 20) -+#define HDRXGNEQEN BIT(22) -+#define HSRXOFF GENMASK(24, 23) -+#define HSFALLPREEM BIT(25) -+#define SHTCCTCTLPROT BIT(26) -+#define STAGSEL BIT(27) -+ -+enum boosting_vals { -+ BOOST_1_MA = 1, -+ BOOST_2_MA, -+ BOOST_MAX, -+}; -+ -+enum dc_level_vals { -+ DC_MINUS_5_TO_7_MV, -+ DC_PLUS_5_TO_7_MV, -+ DC_PLUS_10_TO_14_MV, -+ DC_MAX, -+}; -+ -+enum current_trim { -+ CUR_NOMINAL, -+ CUR_PLUS_1_56_PCT, -+ CUR_PLUS_3_12_PCT, -+ CUR_PLUS_4_68_PCT, -+ CUR_PLUS_6_24_PCT, -+ CUR_PLUS_7_8_PCT, -+ CUR_PLUS_9_36_PCT, -+ CUR_PLUS_10_92_PCT, -+ CUR_PLUS_12_48_PCT, -+ CUR_PLUS_14_04_PCT, -+ CUR_PLUS_15_6_PCT, -+ CUR_PLUS_17_16_PCT, -+ CUR_PLUS_19_01_PCT, -+ CUR_PLUS_20_58_PCT, -+ CUR_PLUS_22_16_PCT, -+ CUR_PLUS_23_73_PCT, -+ CUR_MAX, -+}; -+ -+enum impedance_trim { -+ IMP_NOMINAL, -+ IMP_MINUS_2_OHMS, -+ IMP_MINUS_4_OMHS, -+ IMP_MINUS_6_OHMS, -+ IMP_MAX, -+}; -+ -+enum squelch_level { -+ SQLCH_NOMINAL, -+ SQLCH_PLUS_7_MV, -+ SQLCH_MINUS_5_MV, -+ SQLCH_PLUS_14_MV, -+ SQLCH_MAX, -+}; - --static const char * const supplies_names[] = { -- "vdda1v1", /* 1V1 */ -- "vdda1v8", /* 1V8 */ -+enum rx_offset { -+ NO_RX_OFFSET, -+ RX_OFFSET_PLUS_5_MV, -+ RX_OFFSET_PLUS_10_MV, -+ RX_OFFSET_MINUS_5_MV, -+ RX_OFFSET_MAX, - }; - --#define NUM_SUPPLIES ARRAY_SIZE(supplies_names) -+/* STM32_USBPHYC_VERSION bit fields */ -+#define MINREV GENMASK(3, 0) -+#define MAJREV GENMASK(7, 4) - --#define PLL_LOCK_TIME_US 100 --#define PLL_PWR_DOWN_TIME_US 5 - #define PLL_FVCO_MHZ 2880 - #define PLL_INFF_MIN_RATE_HZ 19200000 - #define PLL_INFF_MAX_RATE_HZ 38400000 -@@ -58,9 +135,10 @@ struct pll_params { - struct stm32_usbphyc_phy { - struct phy *phy; - struct stm32_usbphyc *usbphyc; -- struct regulator_bulk_data supplies[NUM_SUPPLIES]; -+ struct regulator *vbus; - u32 index; - bool active; -+ u32 tune; - }; - - struct stm32_usbphyc { -@@ -70,6 +148,10 @@ struct stm32_usbphyc { - struct reset_control *rst; - struct stm32_usbphyc_phy **phys; - int nphys; -+ struct regulator *vdda1v1; -+ struct regulator *vdda1v8; -+ atomic_t n_pll_cons; -+ struct clk_hw clk48_hw; - int switch_setup; - }; - -@@ -83,6 +165,41 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) - writel_relaxed(readl_relaxed(reg) & ~bits, reg); - } - -+static int stm32_usbphyc_regulators_enable(struct stm32_usbphyc *usbphyc) -+{ -+ int ret; -+ -+ ret = regulator_enable(usbphyc->vdda1v1); -+ if (ret) -+ return ret; -+ -+ ret = regulator_enable(usbphyc->vdda1v8); -+ if (ret) -+ goto vdda1v1_disable; -+ -+ return 0; -+ -+vdda1v1_disable: -+ regulator_disable(usbphyc->vdda1v1); -+ -+ return ret; -+} -+ -+static int stm32_usbphyc_regulators_disable(struct stm32_usbphyc *usbphyc) -+{ -+ int ret; -+ -+ ret = regulator_disable(usbphyc->vdda1v8); -+ if (ret) -+ return ret; -+ -+ ret = regulator_disable(usbphyc->vdda1v1); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ - static void stm32_usbphyc_get_pll_params(u32 clk_rate, - struct pll_params *pll_params) - { -@@ -142,83 +259,106 @@ static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) - return 0; - } - --static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc) -+static int __stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) - { -- int i; -+ void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -+ u32 pllen; -+ -+ stm32_usbphyc_clr_bits(pll_reg, PLLEN); - -- for (i = 0; i < usbphyc->nphys; i++) -- if (usbphyc->phys[i]->active) -- return true; -+ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ -+ if (readl_relaxed_poll_timeout(pll_reg, pllen, !(pllen & PLLEN), 5, 50)) -+ dev_err(usbphyc->dev, "PLL not reset\n"); - -- return false; -+ return stm32_usbphyc_regulators_disable(usbphyc); -+} -+ -+static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) -+{ -+ /* Check if a phy port is still active or clk48 in use */ -+ if (atomic_dec_return(&usbphyc->n_pll_cons) > 0) -+ return 0; -+ -+ return __stm32_usbphyc_pll_disable(usbphyc); - } - - static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) - { - void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -- bool pllen = (readl_relaxed(pll_reg) & PLLEN); -+ bool pllen = readl_relaxed(pll_reg) & PLLEN; - int ret; - -- /* Check if one phy port has already configured the pll */ -- if (pllen && stm32_usbphyc_has_one_phy_active(usbphyc)) -+ /* -+ * Check if a phy port or clk48 prepare has configured the pll -+ * and ensure the PLL is enabled -+ */ -+ if (atomic_inc_return(&usbphyc->n_pll_cons) > 1 && pllen) - return 0; - - if (pllen) { -- stm32_usbphyc_clr_bits(pll_reg, PLLEN); -- /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ -- udelay(PLL_PWR_DOWN_TIME_US); -+ /* -+ * PLL shouldn't be enabled without known consumer, -+ * disable it and reinit n_pll_cons -+ */ -+ dev_warn(usbphyc->dev, "PLL enabled without known consumers\n"); -+ -+ ret = __stm32_usbphyc_pll_disable(usbphyc); -+ if (ret) -+ return ret; - } - -+ ret = stm32_usbphyc_regulators_enable(usbphyc); -+ if (ret) -+ goto dec_n_pll_cons; -+ - ret = stm32_usbphyc_pll_init(usbphyc); - if (ret) -- return ret; -+ goto reg_disable; - - stm32_usbphyc_set_bits(pll_reg, PLLEN); - -- /* Wait for maximum lock time */ -- udelay(PLL_LOCK_TIME_US); -- -- if (!(readl_relaxed(pll_reg) & PLLEN)) { -- dev_err(usbphyc->dev, "PLLEN not set\n"); -- return -EIO; -- } -- - return 0; --} -- --static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) --{ -- void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -- -- /* Check if other phy port active */ -- if (stm32_usbphyc_has_one_phy_active(usbphyc)) -- return 0; - -- stm32_usbphyc_clr_bits(pll_reg, PLLEN); -- /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ -- udelay(PLL_PWR_DOWN_TIME_US); -+reg_disable: -+ stm32_usbphyc_regulators_disable(usbphyc); - -- if (readl_relaxed(pll_reg) & PLLEN) { -- dev_err(usbphyc->dev, "PLL not reset\n"); -- return -EIO; -- } -+dec_n_pll_cons: -+ atomic_dec(&usbphyc->n_pll_cons); - -- return 0; -+ return ret; - } - - static int stm32_usbphyc_phy_init(struct phy *phy) - { - struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); - struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc; -+ u32 reg_mon = STM32_USBPHYC_MONITOR(usbphyc_phy->index); -+ u32 monsel = FIELD_PREP(STM32_USBPHYC_MON_SEL, -+ STM32_USBPHYC_MON_SEL_LOCKP); -+ u32 monout; - int ret; - - ret = stm32_usbphyc_pll_enable(usbphyc); - if (ret) - return ret; - -+ /* Check that PLL Lock input to PHY is High */ -+ writel_relaxed(monsel, usbphyc->base + reg_mon); -+ ret = readl_relaxed_poll_timeout(usbphyc->base + reg_mon, monout, -+ (monout & STM32_USBPHYC_MON_OUT_LOCKP), -+ 100, 1000); -+ if (ret) { -+ dev_err(usbphyc->dev, "PLL Lock input to PHY is Low (val=%x)\n", -+ (u32)(monout & STM32_USBPHYC_MON_OUT)); -+ goto pll_disable; -+ } -+ - usbphyc_phy->active = true; - - return 0; -+ -+pll_disable: -+ return stm32_usbphyc_pll_disable(usbphyc); - } - - static int stm32_usbphyc_phy_exit(struct phy *phy) -@@ -235,14 +375,20 @@ static int stm32_usbphyc_phy_power_on(struct phy *phy) - { - struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); - -- return regulator_bulk_enable(NUM_SUPPLIES, usbphyc_phy->supplies); -+ if (usbphyc_phy->vbus) -+ return regulator_enable(usbphyc_phy->vbus); -+ -+ return 0; - } - - static int stm32_usbphyc_phy_power_off(struct phy *phy) - { - struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); - -- return regulator_bulk_disable(NUM_SUPPLIES, usbphyc_phy->supplies); -+ if (usbphyc_phy->vbus) -+ return regulator_disable(usbphyc_phy->vbus); -+ -+ return 0; - } - - static const struct phy_ops stm32_usbphyc_phy_ops = { -@@ -253,6 +399,163 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { - .owner = THIS_MODULE, - }; - -+static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) -+{ -+ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, -+ clk48_hw); -+ -+ return stm32_usbphyc_pll_enable(usbphyc); -+} -+ -+static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) -+{ -+ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, -+ clk48_hw); -+ -+ stm32_usbphyc_pll_disable(usbphyc); -+} -+ -+static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ return 48000000; -+} -+ -+static const struct clk_ops usbphyc_clk48_ops = { -+ .prepare = stm32_usbphyc_clk48_prepare, -+ .unprepare = stm32_usbphyc_clk48_unprepare, -+ .recalc_rate = stm32_usbphyc_clk48_recalc_rate, -+}; -+ -+static void stm32_usbphyc_clk48_unregister(void *data) -+{ -+ struct stm32_usbphyc *usbphyc = data; -+ -+ of_clk_del_provider(usbphyc->dev->of_node); -+ clk_hw_unregister(&usbphyc->clk48_hw); -+} -+ -+static int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc) -+{ -+ struct device_node *node = usbphyc->dev->of_node; -+ struct clk_init_data init = { }; -+ int ret = 0; -+ -+ init.name = "ck_usbo_48m"; -+ init.ops = &usbphyc_clk48_ops; -+ -+ usbphyc->clk48_hw.init = &init; -+ -+ ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw); -+ if (ret) -+ return ret; -+ -+ ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, -+ &usbphyc->clk48_hw); -+ if (ret) -+ clk_hw_unregister(&usbphyc->clk48_hw); -+ -+ return ret; -+} -+ -+static void stm32_usbphyc_phy_tuning(struct stm32_usbphyc *usbphyc, -+ struct device_node *np, u32 index) -+{ -+ struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys[index]; -+ struct device_node *tune_np; -+ u32 reg = STM32_USBPHYC_TUNE(index); -+ u32 otpcomp, val; -+ int ret; -+ -+ tune_np = of_parse_phandle(np, "st,phy-tuning", 0); -+ if (!tune_np) -+ return; -+ -+ /* Backup OTP compensation code */ -+ otpcomp = FIELD_GET(OTPCOMP, readl_relaxed(usbphyc->base + reg)); -+ -+ ret = of_property_read_u32(tune_np, "st,current-boost", &val); -+ if (!ret && val < BOOST_MAX) { -+ val = (val == BOOST_2_MA) ? 1 : 0; -+ usbphyc_phy->tune |= INCURREN | FIELD_PREP(INCURRINT, val); -+ } else if (ret != -EINVAL) { -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,current-boost value\n", index); -+ } -+ -+ if (!of_property_read_bool(tune_np, "st,no-lsfs-fb-cap")) -+ usbphyc_phy->tune |= LFSCAPEN; -+ -+ if (of_property_read_bool(tune_np, "st,hs-slew-ctrl")) -+ usbphyc_phy->tune |= HSDRVSLEW; -+ -+ ret = of_property_read_u32(tune_np, "st,hs-dc-level", &val); -+ if (!ret && val < DC_MAX) { -+ if (val == DC_MINUS_5_TO_7_MV) { -+ usbphyc_phy->tune |= HSDRVDCCUR; -+ } else { -+ val = (val == DC_PLUS_10_TO_14_MV) ? 1 : 0; -+ usbphyc_phy->tune |= HSDRVCURINCR | FIELD_PREP(HSDRVDCLEV, val); -+ } -+ } else if (ret != -EINVAL) { -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,hs-dc-level value\n", index); -+ } -+ -+ if (of_property_read_bool(tune_np, "st,fs-rftime-tuning")) -+ usbphyc_phy->tune |= FSDRVRFADJ; -+ -+ if (of_property_read_bool(tune_np, "st,hs-rftime-reduction")) -+ usbphyc_phy->tune |= HSDRVRFRED; -+ -+ ret = of_property_read_u32(tune_np, "st,hs-current-trim", &val); -+ if (!ret && val < CUR_MAX) -+ usbphyc_phy->tune |= FIELD_PREP(HSDRVCHKITRM, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,hs-current-trim value\n", index); -+ -+ ret = of_property_read_u32(tune_np, "st,hs-impedance-trim", &val); -+ if (!ret && val < IMP_MAX) -+ usbphyc_phy->tune |= FIELD_PREP(HSDRVCHKZTRM, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid hs-impedance-trim value\n", index); -+ -+ ret = of_property_read_u32(tune_np, "st,squelch-level", &val); -+ if (!ret && val < SQLCH_MAX) -+ usbphyc_phy->tune |= FIELD_PREP(SQLCHCTL, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,squelch-level value\n", index); -+ -+ if (of_property_read_bool(tune_np, "st,hs-rx-gain-eq")) -+ usbphyc_phy->tune |= HDRXGNEQEN; -+ -+ ret = of_property_read_u32(tune_np, "st,hs-rx-offset", &val); -+ if (!ret && val < RX_OFFSET_MAX) -+ usbphyc_phy->tune |= FIELD_PREP(HSRXOFF, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,hs-rx-offset value\n", index); -+ -+ if (of_property_read_bool(tune_np, "st,no-hs-ftime-ctrl")) -+ usbphyc_phy->tune |= HSFALLPREEM; -+ -+ if (!of_property_read_bool(tune_np, "st,no-lsfs-sc")) -+ usbphyc_phy->tune |= SHTCCTCTLPROT; -+ -+ if (of_property_read_bool(tune_np, "st,hs-tx-staggering")) -+ usbphyc_phy->tune |= STAGSEL; -+ -+ of_node_put(tune_np); -+ -+ /* Restore OTP compensation code */ -+ usbphyc_phy->tune |= FIELD_PREP(OTPCOMP, otpcomp); -+ -+ writel_relaxed(usbphyc_phy->tune, usbphyc->base + reg); -+} -+ - static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, - u32 utmi_switch) - { -@@ -313,7 +616,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - struct device_node *child, *np = dev->of_node; - struct resource *res; - struct phy_provider *phy_provider; -- u32 version; -+ u32 pllen, version; - int ret, port = 0; - - usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL); -@@ -328,11 +631,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - return PTR_ERR(usbphyc->base); - - usbphyc->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(usbphyc->clk)) { -- ret = PTR_ERR(usbphyc->clk); -- dev_err(dev, "clk get failed: %d\n", ret); -- return ret; -- } -+ if (IS_ERR(usbphyc->clk)) -+ return dev_err_probe(dev, PTR_ERR(usbphyc->clk), "clk get failed\n"); - - ret = clk_prepare_enable(usbphyc->clk); - if (ret) { -@@ -345,6 +645,23 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - reset_control_assert(usbphyc->rst); - udelay(2); - reset_control_deassert(usbphyc->rst); -+ } else { -+ ret = PTR_ERR(usbphyc->rst); -+ if (ret == -EPROBE_DEFER) -+ goto clk_disable; -+ -+ stm32_usbphyc_clr_bits(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); -+ } -+ -+ /* -+ * Wait for minimum width of powerdown pulse (ENABLE = Low): -+ * we have to ensure the PLL is disabled before phys initialization. -+ */ -+ if (readl_relaxed_poll_timeout(usbphyc->base + STM32_USBPHYC_PLL, -+ pllen, !(pllen & PLLEN), 5, 50)) { -+ dev_warn(usbphyc->dev, "PLL not reset\n"); -+ ret = -EPROBE_DEFER; -+ goto clk_disable; - } - - usbphyc->switch_setup = -EINVAL; -@@ -356,11 +673,26 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - goto clk_disable; - } - -+ usbphyc->vdda1v1 = devm_regulator_get(dev, "vdda1v1"); -+ if (IS_ERR(usbphyc->vdda1v1)) { -+ ret = PTR_ERR(usbphyc->vdda1v1); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to get vdda1v1 supply: %d\n", ret); -+ goto clk_disable; -+ } -+ -+ usbphyc->vdda1v8 = devm_regulator_get(dev, "vdda1v8"); -+ if (IS_ERR(usbphyc->vdda1v8)) { -+ ret = PTR_ERR(usbphyc->vdda1v8); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to get vdda1v8 supply: %d\n", ret); -+ goto clk_disable; -+ } -+ - for_each_child_of_node(np, child) { - struct stm32_usbphyc_phy *usbphyc_phy; - struct phy *phy; - u32 index; -- int i; - - phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops); - if (IS_ERR(phy)) { -@@ -378,18 +710,6 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - goto put_child; - } - -- for (i = 0; i < NUM_SUPPLIES; i++) -- usbphyc_phy->supplies[i].supply = supplies_names[i]; -- -- ret = devm_regulator_bulk_get(&phy->dev, NUM_SUPPLIES, -- usbphyc_phy->supplies); -- if (ret) { -- if (ret != -EPROBE_DEFER) -- dev_err(&phy->dev, -- "failed to get regulators: %d\n", ret); -- goto put_child; -- } -- - ret = of_property_read_u32(child, "reg", &index); - if (ret || index > usbphyc->nphys) { - dev_err(&phy->dev, "invalid reg property: %d\n", ret); -@@ -405,6 +725,17 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - usbphyc->phys[port]->index = index; - usbphyc->phys[port]->active = false; - -+ usbphyc->phys[port]->vbus = devm_regulator_get_optional(&phy->dev, "vbus"); -+ if (IS_ERR(usbphyc->phys[port]->vbus)) { -+ ret = PTR_ERR(usbphyc->phys[port]->vbus); -+ if (ret == -EPROBE_DEFER) -+ goto put_child; -+ usbphyc->phys[port]->vbus = NULL; -+ } -+ -+ /* Configure phy tuning */ -+ stm32_usbphyc_phy_tuning(usbphyc, child, index); -+ - port++; - } - -@@ -416,6 +747,13 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - goto clk_disable; - } - -+ ret = stm32_usbphyc_clk48_register(usbphyc); -+ if (ret) { -+ dev_err(dev, -+ "failed to register ck_usbo_48m clock: %d\n", ret); -+ goto clk_disable; -+ } -+ - version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); - dev_info(dev, "registered rev:%lu.%lu\n", - FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); -@@ -433,12 +771,42 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - static int stm32_usbphyc_remove(struct platform_device *pdev) - { - struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev); -+ int port; -+ -+ /* Ensure PHYs are not active, to allow PLL disabling */ -+ for (port = 0; port < usbphyc->nphys; port++) -+ if (usbphyc->phys[port]->active) -+ stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy); -+ -+ stm32_usbphyc_clk48_unregister(usbphyc); - - clk_disable_unprepare(usbphyc->clk); - - return 0; - } - -+#ifdef CONFIG_PM_SLEEP -+static int stm32_usbphyc_resume(struct device *dev) -+{ -+ struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); -+ struct stm32_usbphyc_phy *usbphyc_phy; -+ int port; -+ -+ if (usbphyc->switch_setup >= 0) -+ stm32_usbphyc_switch_setup(usbphyc, usbphyc->switch_setup); -+ -+ for (port = 0; port < usbphyc->nphys; port++) { -+ usbphyc_phy = usbphyc->phys[port]; -+ if (usbphyc_phy->tune) -+ writel_relaxed(usbphyc_phy->tune, usbphyc->base + STM32_USBPHYC_TUNE(port)); -+ } -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stm32_usbphyc_pm_ops, NULL, stm32_usbphyc_resume); -+ - static const struct of_device_id stm32_usbphyc_of_match[] = { - { .compatible = "st,stm32mp1-usbphyc", }, - { }, -@@ -451,6 +819,7 @@ static struct platform_driver stm32_usbphyc_driver = { - .driver = { - .of_match_table = stm32_usbphyc_of_match, - .name = "stm32-usbphyc", -+ .pm = &stm32_usbphyc_pm_ops, - } - }; - module_platform_driver(stm32_usbphyc_driver); -diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c -index 99908d8d2..5290a47b4 100644 ---- a/drivers/usb/core/hcd.c -+++ b/drivers/usb/core/hcd.c -@@ -2138,7 +2138,8 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) - - if (!PMSG_IS_AUTO(msg)) - usb_phy_roothub_suspend(hcd->self.sysdev, -- hcd->phy_roothub); -+ hcd->phy_roothub, -+ usb_wakeup_enabled_descendants(rhdev)); - - /* Did we race with a root-hub wakeup event? */ - if (rhdev->do_remote_wakeup) { -@@ -2179,7 +2180,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) - - if (!PMSG_IS_AUTO(msg)) { - status = usb_phy_roothub_resume(hcd->self.sysdev, -- hcd->phy_roothub); -+ hcd->phy_roothub, -+ usb_wakeup_enabled_descendants(rhdev)); - if (status) - return status; - } -@@ -2224,7 +2226,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) - } - } else { - hcd->state = old_state; -- usb_phy_roothub_suspend(hcd->self.sysdev, hcd->phy_roothub); -+ usb_phy_roothub_suspend(hcd->self.sysdev, hcd->phy_roothub, -+ usb_wakeup_enabled_descendants(rhdev)); - dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", - "resume", status); - if (status != -ESHUTDOWN) -diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c -index fb1588e7c..746615aa1 100644 ---- a/drivers/usb/core/phy.c -+++ b/drivers/usb/core/phy.c -@@ -212,34 +212,36 @@ void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) - EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); - - int usb_phy_roothub_suspend(struct device *controller_dev, -- struct usb_phy_roothub *phy_roothub) -+ struct usb_phy_roothub *phy_roothub, -+ unsigned wakeup_enabled_descendants) - { -- usb_phy_roothub_power_off(phy_roothub); -- - /* keep the PHYs initialized so the device can wake up the system */ -- if (device_may_wakeup(controller_dev)) -+ if (device_may_wakeup(controller_dev) || wakeup_enabled_descendants) - return 0; - -+ usb_phy_roothub_power_off(phy_roothub); -+ - return usb_phy_roothub_exit(phy_roothub); - } - EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend); - - int usb_phy_roothub_resume(struct device *controller_dev, -- struct usb_phy_roothub *phy_roothub) -+ struct usb_phy_roothub *phy_roothub, -+ unsigned wakeup_enabled_descendants) - { -- int err; -+ int err = 0; - - /* if the device can't wake up the system _exit was called */ -- if (!device_may_wakeup(controller_dev)) { -+ if (!device_may_wakeup(controller_dev) && !wakeup_enabled_descendants) { - err = usb_phy_roothub_init(phy_roothub); - if (err) - return err; -- } - -- err = usb_phy_roothub_power_on(phy_roothub); -+ err = usb_phy_roothub_power_on(phy_roothub); -+ } - - /* undo _init if _power_on failed */ -- if (err && !device_may_wakeup(controller_dev)) -+ if (err && !device_may_wakeup(controller_dev) && !wakeup_enabled_descendants) - usb_phy_roothub_exit(phy_roothub); - - return err; -diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h -index 20a267cd9..3df4ddbb6 100644 ---- a/drivers/usb/core/phy.h -+++ b/drivers/usb/core/phy.h -@@ -23,8 +23,10 @@ int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); - void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); - - int usb_phy_roothub_suspend(struct device *controller_dev, -- struct usb_phy_roothub *phy_roothub); -+ struct usb_phy_roothub *phy_roothub, -+ unsigned wakeup_enabled_descendants); - int usb_phy_roothub_resume(struct device *controller_dev, -- struct usb_phy_roothub *phy_roothub); -+ struct usb_phy_roothub *phy_roothub, -+ unsigned wakeup_enabled_descendants); - - #endif /* __USB_CORE_PHY_H_ */ -diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c -index 15911ac75..997b14c05 100644 ---- a/drivers/usb/dwc2/core.c -+++ b/drivers/usb/dwc2/core.c -@@ -83,6 +83,7 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) - gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); - gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG); - gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL); -+ gr->ggpio = dwc2_readl(hsotg, GGPIO); - gr->pcgcctl = dwc2_readl(hsotg, PCGCTL); - - gr->valid = true; -@@ -112,21 +113,82 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) - gr->valid = false; - - dwc2_writel(hsotg, 0xffffffff, GINTSTS); -+ dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); -+ dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); - dwc2_writel(hsotg, gr->gotgctl, GOTGCTL); - dwc2_writel(hsotg, gr->gintmsk, GINTMSK); -- dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); -- dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); - dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ); - dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ); - dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG); - dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1); - dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG); - dwc2_writel(hsotg, gr->pcgcctl, PCGCTL); -+ dwc2_writel(hsotg, gr->ggpio, GGPIO); - dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL); - - return 0; - } - -+int dwc2_backup_registers(struct dwc2_hsotg *hsotg) -+{ -+ int ret; -+ -+ /* Backup all registers */ -+ ret = dwc2_backup_global_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to backup global registers\n", -+ __func__); -+ return ret; -+ } -+ -+ if (dwc2_is_host_mode(hsotg)) { -+ ret = dwc2_backup_host_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to backup host registers\n", -+ __func__); -+ return ret; -+ } -+ } else { -+ ret = dwc2_backup_device_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to backup device registers\n", -+ __func__); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+int dwc2_restore_registers(struct dwc2_hsotg *hsotg) -+{ -+ int ret; -+ -+ ret = dwc2_restore_global_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to restore registers\n", -+ __func__); -+ return ret; -+ } -+ if (dwc2_is_host_mode(hsotg)) { -+ ret = dwc2_restore_host_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to restore host registers\n", -+ __func__); -+ return ret; -+ } -+ } else { -+ ret = dwc2_restore_device_registers(hsotg, 0); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to restore device registers\n", -+ __func__); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ - /** - * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. - * -@@ -136,7 +198,6 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) - int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) - { - u32 pcgcctl; -- int ret = 0; - - if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) - return -ENOTSUPP; -@@ -154,31 +215,11 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) - dwc2_writel(hsotg, pcgcctl, PCGCTL); - - udelay(100); -- if (restore) { -- ret = dwc2_restore_global_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to restore registers\n", -- __func__); -- return ret; -- } -- if (dwc2_is_host_mode(hsotg)) { -- ret = dwc2_restore_host_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to restore host registers\n", -- __func__); -- return ret; -- } -- } else { -- ret = dwc2_restore_device_registers(hsotg, 0); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to restore device registers\n", -- __func__); -- return ret; -- } -- } -- } - -- return ret; -+ if (restore) -+ return dwc2_restore_registers(hsotg); -+ -+ return 0; - } - - /** -@@ -189,34 +230,14 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) - int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) - { - u32 pcgcctl; -- int ret = 0; -+ int ret; - - if (!hsotg->params.power_down) - return -ENOTSUPP; - -- /* Backup all registers */ -- ret = dwc2_backup_global_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to backup global registers\n", -- __func__); -+ ret = dwc2_backup_registers(hsotg); -+ if (ret) - return ret; -- } -- -- if (dwc2_is_host_mode(hsotg)) { -- ret = dwc2_backup_host_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to backup host registers\n", -- __func__); -- return ret; -- } -- } else { -- ret = dwc2_backup_device_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to backup device registers\n", -- __func__); -- return ret; -- } -- } - - /* - * Clear any pending interrupts since dwc2 will not be able to -@@ -238,7 +259,7 @@ int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) - pcgcctl |= PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgcctl, PCGCTL); - -- return ret; -+ return 0; - } - - /** -diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index 641e4251c..21d1fc490 100644 ---- a/drivers/usb/dwc2/core.h -+++ b/drivers/usb/dwc2/core.h -@@ -240,6 +240,9 @@ enum dwc2_ep0_state { - * 1 - SRP Only capable - * 2 - No HNP/SRP capable (always available) - * Defaults to best available option (0, 1, then 2) -+ * @otg_rev: The OTG revision number the device is compliant with, -+ * in binary-coded decimal (i.e. 2.0 is 0200H). -+ * (see struct usb_otg_caps) - * @host_dma: Specifies whether to use slave or DMA mode for accessing - * the data FIFOs. The driver will automatically detect the - * value for this parameter if none is specified. -@@ -452,6 +455,7 @@ struct dwc2_core_params { - #define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1 - #define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 - -+ u16 otg_rev; - u8 phy_type; - #define DWC2_PHY_TYPE_PARAM_FS 0 - #define DWC2_PHY_TYPE_PARAM_UTMI 1 -@@ -687,6 +691,7 @@ struct dwc2_hw_params { - * @grxfsiz: Backup of GRXFSIZ register - * @gnptxfsiz: Backup of GNPTXFSIZ register - * @gi2cctl: Backup of GI2CCTL register -+ * @ggpio: Backup of GGPIO register - * @glpmcfg: Backup of GLPMCFG register - * @gdfifocfg: Backup of GDFIFOCFG register - * @pcgcctl: Backup of PCGCCTL register -@@ -703,6 +708,7 @@ struct dwc2_gregs_backup { - u32 grxfsiz; - u32 gnptxfsiz; - u32 gi2cctl; -+ u32 ggpio; - u32 glpmcfg; - u32 pcgcctl; - u32 pcgcctl1; -@@ -863,6 +869,8 @@ struct dwc2_hregs_backup { - * - USB_DR_MODE_HOST - * - USB_DR_MODE_OTG - * @role_sw: usb_role_switch handle -+ * @role_sw_default_mode: default operation mode of controller while usb role -+ * is USB_ROLE_NONE - * @hcd_enabled: Host mode sub-driver initialization indicator. - * @gadget_enabled: Peripheral mode sub-driver initialization indicator. - * @ll_hw_enabled: Status of low-level hardware resources. -@@ -1046,6 +1054,8 @@ struct dwc2_hregs_backup { - * @new_connection: Used in host mode. True if there are new connected - * device - * @enabled: Indicates the enabling state of controller -+ * @dw_otg_caps: OTG caps from the platform parameters, used to setup the -+ * gadget structure. - * - */ - struct dwc2_hsotg { -@@ -1058,6 +1068,7 @@ struct dwc2_hsotg { - enum usb_otg_state op_state; - enum usb_dr_mode dr_mode; - struct usb_role_switch *role_sw; -+ enum usb_dr_mode role_sw_default_mode; - unsigned int hcd_enabled:1; - unsigned int gadget_enabled:1; - unsigned int ll_hw_enabled:1; -@@ -1211,6 +1222,7 @@ struct dwc2_hsotg { - unsigned int remote_wakeup_allowed:1; - struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS]; - struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS]; -+ struct usb_otg_caps dw_otg_caps; - #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ - }; - -@@ -1331,6 +1343,8 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); - - void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, - int is_host); -+int dwc2_backup_registers(struct dwc2_hsotg *hsotg); -+int dwc2_restore_registers(struct dwc2_hsotg *hsotg); - int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg); - int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg); - -diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c -index 2d4176f57..9e78d98da 100644 ---- a/drivers/usb/dwc2/drd.c -+++ b/drivers/usb/dwc2/drd.c -@@ -7,6 +7,7 @@ - * Author(s): Amelie Delaunay - */ - -+#include - #include - #include - #include -@@ -23,11 +24,15 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) - gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN; - gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; - gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); -+ if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) -+ gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; -+ else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) -+ gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; - dwc2_writel(hsotg, gotgctl, GOTGCTL); - -- dwc2_force_mode(hsotg, false); -- - spin_unlock_irqrestore(&hsotg->lock, flags); -+ -+ dwc2_force_mode(hsotg, (hsotg->dr_mode == USB_DR_MODE_HOST)); - } - - static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) -@@ -39,6 +44,7 @@ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) - (!valid && !(gotgctl & GOTGCTL_ASESVLD))) - return -EALREADY; - -+ gotgctl &= ~GOTGCTL_BVALOVAL; - if (valid) - gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; - else -@@ -57,6 +63,7 @@ static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid) - (!valid && !(gotgctl & GOTGCTL_BSESVLD))) - return -EALREADY; - -+ gotgctl &= ~GOTGCTL_AVALOVAL; - if (valid) - gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; - else -@@ -86,6 +93,19 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) - } - #endif - -+ /* -+ * In case of USB_DR_MODE_PERIPHERAL, clock is disabled at the end of -+ * the probe and enabled on udc_start. -+ * If role-switch set is called before the udc_start, we need to enable -+ * the clock to read/write GOTGCTL and GUSBCFG registers to override -+ * mode and sessions. It is the case if cable is plugged at boot. -+ */ -+ if (!hsotg->ll_hw_enabled && hsotg->clk) { -+ int ret = clk_prepare_enable(hsotg->clk); -+ if (ret) -+ return ret; -+ } -+ - spin_lock_irqsave(&hsotg->lock, flags); - - if (role == USB_ROLE_HOST) { -@@ -110,6 +130,9 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) - /* This will raise a Connector ID Status Change Interrupt */ - dwc2_force_mode(hsotg, role == USB_ROLE_HOST); - -+ if (!hsotg->ll_hw_enabled && hsotg->clk) -+ clk_disable_unprepare(hsotg->clk); -+ - dev_dbg(hsotg->dev, "%s-session valid\n", - role == USB_ROLE_NONE ? "No" : - role == USB_ROLE_HOST ? "A" : "B"); -@@ -121,11 +144,21 @@ int dwc2_drd_init(struct dwc2_hsotg *hsotg) - { - struct usb_role_switch_desc role_sw_desc = {0}; - struct usb_role_switch *role_sw; -+ const char *str; - int ret; - - if (!device_property_read_bool(hsotg->dev, "usb-role-switch")) - return 0; - -+ hsotg->role_sw_default_mode = USB_DR_MODE_UNKNOWN; -+ ret = device_property_read_string(hsotg->dev, "role-switch-default-mode", &str); -+ if (!ret) { -+ if (!strncmp(str, "host", strlen("host"))) -+ hsotg->role_sw_default_mode = USB_DR_MODE_HOST; -+ else if (!strncmp(str, "peripheral", strlen("peripheral"))) -+ hsotg->role_sw_default_mode = USB_DR_MODE_PERIPHERAL; -+ } -+ - role_sw_desc.driver_data = hsotg; - role_sw_desc.fwnode = dev_fwnode(hsotg->dev); - role_sw_desc.set = dwc2_drd_role_sw_set; -diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c -index b06286f13..9f6baef56 100644 ---- a/drivers/usb/dwc2/gadget.c -+++ b/drivers/usb/dwc2/gadget.c -@@ -3562,7 +3562,8 @@ void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) - void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) - { - /* remove the soft-disconnect and let's go */ -- dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); -+ if (!hsotg->role_sw || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD)) -+ dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); - } - - /** -@@ -4892,6 +4893,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) - hsotg->gadget.max_speed = USB_SPEED_HIGH; - hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; - hsotg->gadget.name = dev_name(dev); -+ hsotg->gadget.otg_caps = &hsotg->dw_otg_caps; - hsotg->remote_wakeup_allowed = 0; - - if (hsotg->params.lpm) -@@ -5000,7 +5002,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) - hsotg->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock_irqrestore(&hsotg->lock, flags); - -- for (ep = 0; ep < hsotg->num_of_eps; ep++) { -+ for (ep = 1; ep < hsotg->num_of_eps; ep++) { - if (hsotg->eps_in[ep]) - dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); - if (hsotg->eps_out[ep]) -diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c -index 6af1dcbc3..71d5ca1a7 100644 ---- a/drivers/usb/dwc2/hcd.c -+++ b/drivers/usb/dwc2/hcd.c -@@ -1736,7 +1736,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) - * release_channel_ddma(), which is called from ep_disable when - * device disconnects - */ -- channel->qh = NULL; -+ if (hsotg->params.host_dma && hsotg->params.dma_desc_enable) -+ channel->qh = NULL; - } - /* All channels have been freed, mark them available */ - if (hsotg->params.uframe_sched) { -@@ -3612,7 +3613,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) - goto error; - -- if (!hsotg->flags.b.port_connect_status) { -+ if (!hsotg->flags.b.port_connect_status && -+ !dwc2_is_host_mode(hsotg)) { - /* - * The port is disconnected, which means the core is - * either in device mode or it soon will be. Just -@@ -3698,6 +3700,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - hprt0 &= ~HPRT0_TSTCTL_MASK; - hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT; - dwc2_writel(hsotg, hprt0, HPRT0); -+ hsotg->test_mode = windex >> 8; - break; - - default: -diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c -index 267543c3d..49a677ba6 100644 ---- a/drivers/usb/dwc2/params.c -+++ b/drivers/usb/dwc2/params.c -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - - #include "core.h" - -@@ -168,6 +169,7 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) - struct dwc2_core_params *p = &hsotg->params; - - p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; -+ p->otg_rev = 0x200; - p->speed = DWC2_SPEED_PARAM_FULL; - p->host_rx_fifo_size = 128; - p->host_nperio_tx_fifo_size = 96; -@@ -177,7 +179,10 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) - p->i2c_enable = false; - p->activate_stm_fs_transceiver = true; - p->activate_stm_id_vb_detection = true; -+ p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; - p->power_down = DWC2_POWER_DOWN_PARAM_NONE; -+ p->host_support_fs_ls_low_power = true; -+ p->host_ls_low_power_phy_clk = true; - } - - static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) -@@ -185,11 +190,17 @@ static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) - struct dwc2_core_params *p = &hsotg->params; - - p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; -+ p->otg_rev = 0x200; - p->activate_stm_id_vb_detection = !device_property_read_bool(hsotg->dev, "usb-role-switch"); - p->host_rx_fifo_size = 440; - p->host_nperio_tx_fifo_size = 256; - p->host_perio_tx_fifo_size = 256; -+ p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; - p->power_down = DWC2_POWER_DOWN_PARAM_NONE; -+ p->lpm = false; -+ p->lpm_clock_gating = false; -+ p->besl = false; -+ p->hird_threshold_en = false; - } - - const struct of_device_id dwc2_of_match_table[] = { -@@ -231,18 +242,25 @@ static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg) - switch (hsotg->hw_params.op_mode) { - case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: - val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; -+ hsotg->dw_otg_caps.hnp_support = true; -+ hsotg->dw_otg_caps.srp_support = true; - break; - case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: - val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; -+ hsotg->dw_otg_caps.hnp_support = false; -+ hsotg->dw_otg_caps.srp_support = true; - break; - default: - val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; -+ hsotg->dw_otg_caps.hnp_support = false; -+ hsotg->dw_otg_caps.srp_support = false; - break; - } - - hsotg->params.otg_cap = val; -+ hsotg->dw_otg_caps.otg_rev = hsotg->params.otg_rev; - } - - static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg) -@@ -450,6 +468,9 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) - } - } - -+ if (hsotg->dr_mode == USB_DR_MODE_OTG) -+ of_usb_update_otg_caps(hsotg->dev->of_node, &hsotg->dw_otg_caps); -+ - if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL)) - p->oc_disable = true; - } -@@ -469,6 +490,7 @@ static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) - case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: -+ hsotg->dw_otg_caps.hnp_support = false; - break; - default: - valid = 0; -@@ -477,6 +499,8 @@ static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) - break; - case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: - /* always valid */ -+ hsotg->dw_otg_caps.hnp_support = false; -+ hsotg->dw_otg_caps.srp_support = false; - break; - default: - valid = 0; -diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index 5f18acac7..f0964babf 100644 ---- a/drivers/usb/dwc2/platform.c -+++ b/drivers/usb/dwc2/platform.c -@@ -224,8 +224,7 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) - hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2"); - if (IS_ERR(hsotg->reset)) { - ret = PTR_ERR(hsotg->reset); -- dev_err(hsotg->dev, "error getting reset control %d\n", ret); -- return ret; -+ return dev_err_probe(hsotg->dev, ret, "error getting reset control\n"); - } - - reset_control_deassert(hsotg->reset); -@@ -233,8 +232,7 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) - hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc"); - if (IS_ERR(hsotg->reset_ecc)) { - ret = PTR_ERR(hsotg->reset_ecc); -- dev_err(hsotg->dev, "error getting reset control for ecc %d\n", ret); -- return ret; -+ return dev_err_probe(hsotg->dev, ret, "error getting reset control for ecc\n"); - } - - reset_control_deassert(hsotg->reset_ecc); -@@ -283,8 +281,8 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) - /* Clock */ - hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg"); - if (IS_ERR(hsotg->clk)) { -- dev_err(hsotg->dev, "cannot get otg clock\n"); -- return PTR_ERR(hsotg->clk); -+ ret = PTR_ERR(hsotg->clk); -+ return dev_err_probe(hsotg->dev, ret, "cannot get otg clock\n"); - } - - /* Regulators */ -@@ -293,12 +291,9 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) - - ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), - hsotg->supplies); -- if (ret) { -- if (ret != -EPROBE_DEFER) -- dev_err(hsotg->dev, "failed to request supplies: %d\n", -- ret); -- return ret; -- } -+ if (ret) -+ return dev_err_probe(hsotg->dev, ret, "failed to request supplies\n"); -+ - return 0; - } - -@@ -638,6 +633,19 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - - dwc2_drd_suspend(dwc2); - -+ if (dwc2->params.power_down == DWC2_POWER_DOWN_PARAM_NONE) { -+ /* -+ * Backup host registers when power_down param is 'none', if -+ * controller power is disabled. -+ * This shouldn't be needed, when using other power_down modes. -+ */ -+ ret = dwc2_backup_registers(dwc2); -+ if (ret) { -+ dev_err(dwc2->dev, "backup regs failed %d\n", ret); -+ return ret; -+ } -+ } -+ - if (dwc2->params.activate_stm_id_vb_detection) { - unsigned long flags; - u32 ggpio, gotgctl; -@@ -675,6 +683,9 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - dwc2->phy_off_for_suspend = true; - } - -+ if (device_may_wakeup(dev) || device_wakeup_path(dev)) -+ enable_irq_wake(dwc2->irq); -+ - return ret; - } - -@@ -683,6 +694,9 @@ static int __maybe_unused dwc2_resume(struct device *dev) - struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); - int ret = 0; - -+ if (device_may_wakeup(dev) || device_wakeup_path(dev)) -+ disable_irq_wake(dwc2->irq); -+ - if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { - ret = __dwc2_lowlevel_hw_enable(dwc2); - if (ret) -@@ -715,8 +729,13 @@ static int __maybe_unused dwc2_resume(struct device *dev) - spin_unlock_irqrestore(&dwc2->lock, flags); - } - -- /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ -- dwc2_force_dr_mode(dwc2); -+ if (dwc2->params.power_down == DWC2_POWER_DOWN_PARAM_NONE) { -+ ret = dwc2_restore_registers(dwc2); -+ if (ret) { -+ dev_err(dwc2->dev, "restore regs failed %d\n", ret); -+ return ret; -+ } -+ } - - dwc2_drd_resume(dwc2); - -diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c -index a48dd3fac..5017913ce 100644 ---- a/drivers/usb/host/ehci-platform.c -+++ b/drivers/usb/host/ehci-platform.c -@@ -35,6 +35,7 @@ - #include - #include - #include -+#include - - #include "ehci.h" - -@@ -364,7 +365,9 @@ static int ehci_platform_probe(struct platform_device *dev) - if (err) - goto err_power; - -- device_wakeup_enable(hcd->self.controller); -+ if (of_property_read_bool(dev->dev.of_node, "wakeup-source")) -+ device_set_wakeup_capable(hcd->self.controller, true); -+ - device_enable_async_suspend(hcd->self.controller); - platform_set_drvdata(dev, hcd); - -@@ -400,6 +403,9 @@ static int ehci_platform_remove(struct platform_device *dev) - if (priv->quirk_poll) - quirk_poll_end(priv); - -+ if (of_property_read_bool(dev->dev.of_node, "wakeup-source")) -+ device_set_wakeup_capable(hcd->self.controller, false); -+ - usb_remove_hcd(hcd); - - if (pdata->power_off) -@@ -424,7 +430,7 @@ static int __maybe_unused ehci_platform_suspend(struct device *dev) - struct usb_ehci_pdata *pdata = dev_get_platdata(dev); - struct platform_device *pdev = to_platform_device(dev); - struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); -- bool do_wakeup = device_may_wakeup(dev); -+ bool do_wakeup = device_may_wakeup(dev) || device_wakeup_path(dev); - int ret; - - if (priv->quirk_poll) -@@ -437,6 +443,9 @@ static int __maybe_unused ehci_platform_suspend(struct device *dev) - if (pdata->power_suspend) - pdata->power_suspend(pdev); - -+ if (do_wakeup) -+ enable_irq_wake(hcd->irq); -+ - return ret; - } - -@@ -448,6 +457,9 @@ static int __maybe_unused ehci_platform_resume(struct device *dev) - struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - struct device *companion_dev; - -+ if (device_may_wakeup(dev) || device_wakeup_path(dev)) -+ disable_irq_wake(hcd->irq); -+ - if (pdata->power_on) { - int err = pdata->power_on(pdev); - if (err < 0) --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0016-ARM-5.10.61-stm32mp1-r2-PINCTRL-REGULATOR-SPI.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0016-ARM-5.10.61-stm32mp1-r2-PINCTRL-REGULATOR-SPI.patch deleted file mode 100644 index 834ca94..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0016-ARM-5.10.61-stm32mp1-r2-PINCTRL-REGULATOR-SPI.patch +++ /dev/null @@ -1,2218 +0,0 @@ -From b38c029ee9690c49ab2b225e9f83221f4c17254f Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:50 +0200 -Subject: [PATCH 16/23] ARM 5.10.61-stm32mp1-r2 PINCTRL-REGULATOR-SPI - ---- - drivers/mtd/nand/spi/core.c | 157 ++++++++---- - drivers/pinctrl/stm32/pinctrl-stm32.c | 121 +++++---- - drivers/pinctrl/stm32/pinctrl-stm32.h | 17 +- - drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1 + - drivers/pwm/pwm-stm32-lp.c | 4 +- - drivers/pwm/pwm-stm32.c | 4 + - drivers/regulator/stm32-pwr.c | 85 ++++++- - drivers/regulator/stpmic1_regulator.c | 182 ++++++++++++- - drivers/spi/Kconfig | 1 + - drivers/spi/spi-mem.c | 86 +++++++ - drivers/spi/spi-stm32-qspi.c | 176 +++++++++++-- - drivers/spi/spi-stm32.c | 267 +++++++++----------- - include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + - include/linux/mtd/spinand.h | 22 ++ - include/linux/spi/spi-mem.h | 16 ++ - 15 files changed, 840 insertions(+), 300 deletions(-) - -diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c -index 558d8a148..89ebb42a2 100644 ---- a/drivers/mtd/nand/spi/core.c -+++ b/drivers/mtd/nand/spi/core.c -@@ -138,20 +138,12 @@ int spinand_select_target(struct spinand_device *spinand, unsigned int target) - return 0; - } - --static int spinand_init_cfg_cache(struct spinand_device *spinand) -+static int spinand_read_cfg(struct spinand_device *spinand) - { - struct nand_device *nand = spinand_to_nand(spinand); -- struct device *dev = &spinand->spimem->spi->dev; - unsigned int target; - int ret; - -- spinand->cfg_cache = devm_kcalloc(dev, -- nand->memorg.ntargets, -- sizeof(*spinand->cfg_cache), -- GFP_KERNEL); -- if (!spinand->cfg_cache) -- return -ENOMEM; -- - for (target = 0; target < nand->memorg.ntargets; target++) { - ret = spinand_select_target(spinand, target); - if (ret) -@@ -170,6 +162,21 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand) - return 0; - } - -+static int spinand_init_cfg_cache(struct spinand_device *spinand) -+{ -+ struct nand_device *nand = spinand_to_nand(spinand); -+ struct device *dev = &spinand->spimem->spi->dev; -+ -+ spinand->cfg_cache = devm_kcalloc(dev, -+ nand->memorg.ntargets, -+ sizeof(*spinand->cfg_cache), -+ GFP_KERNEL); -+ if (!spinand->cfg_cache) -+ return -ENOMEM; -+ -+ return 0; -+} -+ - static int spinand_init_quad_enable(struct spinand_device *spinand) - { - bool enable = false; -@@ -341,20 +348,26 @@ static int spinand_erase_op(struct spinand_device *spinand, - return spi_mem_exec_op(spinand->spimem, &op); - } - --static int spinand_wait(struct spinand_device *spinand, u8 *s) -+static int spinand_wait(struct spinand_device *spinand, -+ unsigned long initial_delay_us, -+ unsigned long poll_delay_us, -+ u8 *s) - { -- unsigned long timeo = jiffies + msecs_to_jiffies(400); -+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS, -+ spinand->scratchbuf); - u8 status; - int ret; - -- do { -- ret = spinand_read_status(spinand, &status); -- if (ret) -- return ret; -+ ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0, -+ initial_delay_us, -+ poll_delay_us, -+ SPINAND_WAITRDY_TIMEOUT_MS); -+ if (ret) -+ return ret; - -- if (!(status & STATUS_BUSY)) -- goto out; -- } while (time_before(jiffies, timeo)); -+ status = *spinand->scratchbuf; -+ if (!(status & STATUS_BUSY)) -+ goto out; - - /* - * Extra read, just in case the STATUS_READY bit has changed -@@ -394,7 +407,10 @@ static int spinand_reset_op(struct spinand_device *spinand) - if (ret) - return ret; - -- return spinand_wait(spinand, NULL); -+ return spinand_wait(spinand, -+ SPINAND_RESET_INITIAL_DELAY_US, -+ SPINAND_RESET_POLL_DELAY_US, -+ NULL); - } - - static int spinand_lock_block(struct spinand_device *spinand, u8 lock) -@@ -442,7 +458,10 @@ static int spinand_read_page(struct spinand_device *spinand, - if (ret) - return ret; - -- ret = spinand_wait(spinand, &status); -+ ret = spinand_wait(spinand, -+ SPINAND_READ_INITIAL_DELAY_US, -+ SPINAND_READ_POLL_DELAY_US, -+ &status); - if (ret < 0) - return ret; - -@@ -474,7 +493,10 @@ static int spinand_write_page(struct spinand_device *spinand, - if (ret) - return ret; - -- ret = spinand_wait(spinand, &status); -+ ret = spinand_wait(spinand, -+ SPINAND_WRITE_INITIAL_DELAY_US, -+ SPINAND_WRITE_POLL_DELAY_US, -+ &status); - if (!ret && (status & STATUS_PROG_FAILED)) - ret = -EIO; - -@@ -659,7 +681,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos) - if (ret) - return ret; - -- ret = spinand_wait(spinand, &status); -+ ret = spinand_wait(spinand, -+ SPINAND_ERASE_INITIAL_DELAY_US, -+ SPINAND_ERASE_POLL_DELAY_US, -+ &status); -+ - if (!ret && (status & STATUS_ERASE_FAILED)) - ret = -EIO; - -@@ -989,12 +1015,71 @@ static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = { - .free = spinand_noecc_ooblayout_free, - }; - -+static int spinand_init_flash(struct spinand_device *spinand) -+{ -+ struct device *dev = &spinand->spimem->spi->dev; -+ struct nand_device *nand = spinand_to_nand(spinand); -+ int ret, i; -+ -+ ret = spinand_read_cfg(spinand); -+ if (ret) -+ return ret; -+ -+ ret = spinand_init_quad_enable(spinand); -+ if (ret) -+ return ret; -+ -+ ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0); -+ if (ret) -+ return ret; -+ -+ ret = spinand_manufacturer_init(spinand); -+ if (ret) { -+ dev_err(dev, -+ "Failed to initialize the SPI NAND chip (err = %d)\n", -+ ret); -+ return ret; -+ } -+ -+ /* After power up, all blocks are locked, so unlock them here. */ -+ for (i = 0; i < nand->memorg.ntargets; i++) { -+ ret = spinand_select_target(spinand, i); -+ if (ret) -+ break; -+ -+ ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED); -+ if (ret) -+ break; -+ } -+ -+ if (ret) -+ spinand_manufacturer_cleanup(spinand); -+ -+ return ret; -+} -+ -+static void spinand_mtd_resume(struct mtd_info *mtd) -+{ -+ struct spinand_device *spinand = mtd_to_spinand(mtd); -+ int ret; -+ -+ ret = spinand_reset_op(spinand); -+ if (ret) -+ return; -+ -+ ret = spinand_init_flash(spinand); -+ if (ret) -+ return; -+ -+ spinand_ecc_enable(spinand, false); -+} -+ - static int spinand_init(struct spinand_device *spinand) - { - struct device *dev = &spinand->spimem->spi->dev; - struct mtd_info *mtd = spinand_to_mtd(spinand); - struct nand_device *nand = mtd_to_nanddev(mtd); -- int ret, i; -+ int ret; - - /* - * We need a scratch buffer because the spi_mem interface requires that -@@ -1027,22 +1112,10 @@ static int spinand_init(struct spinand_device *spinand) - if (ret) - goto err_free_bufs; - -- ret = spinand_init_quad_enable(spinand); -+ ret = spinand_init_flash(spinand); - if (ret) - goto err_free_bufs; - -- ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0); -- if (ret) -- goto err_free_bufs; -- -- ret = spinand_manufacturer_init(spinand); -- if (ret) { -- dev_err(dev, -- "Failed to initialize the SPI NAND chip (err = %d)\n", -- ret); -- goto err_free_bufs; -- } -- - ret = spinand_create_dirmaps(spinand); - if (ret) { - dev_err(dev, -@@ -1051,17 +1124,6 @@ static int spinand_init(struct spinand_device *spinand) - goto err_manuf_cleanup; - } - -- /* After power up, all blocks are locked, so unlock them here. */ -- for (i = 0; i < nand->memorg.ntargets; i++) { -- ret = spinand_select_target(spinand, i); -- if (ret) -- goto err_manuf_cleanup; -- -- ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED); -- if (ret) -- goto err_manuf_cleanup; -- } -- - ret = nanddev_init(nand, &spinand_ops, THIS_MODULE); - if (ret) - goto err_manuf_cleanup; -@@ -1077,6 +1139,7 @@ static int spinand_init(struct spinand_device *spinand) - mtd->_block_isreserved = spinand_mtd_block_isreserved; - mtd->_erase = spinand_mtd_erase; - mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks; -+ mtd->_resume = spinand_mtd_resume; - - if (spinand->eccinfo.ooblayout) - mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout); -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c -index 3af443054..474b9debc 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c -@@ -73,6 +73,7 @@ static const char * const stm32_gpio_functions[] = { - "af8", "af9", "af10", - "af11", "af12", "af13", - "af14", "af15", "analog", -+ "reserved", - }; - - struct stm32_pinctrl_group { -@@ -115,6 +116,7 @@ struct stm32_pinctrl { - u32 pkg; - u16 irqmux_map; - spinlock_t irqmux_lock; -+ u32 pin_base_shift; - }; - - static inline int stm32_gpio_pin(int gpio) -@@ -414,57 +416,25 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, - { - struct stm32_gpio_bank *bank = d->host_data; - struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); -- unsigned long flags; - int ret = 0; - -- /* -- * gpio irq mux is shared between several banks, a lock has to be done -- * to avoid overriding. -- */ -- spin_lock_irqsave(&pctl->irqmux_lock, flags); -- - if (pctl->hwlock) { - ret = hwspin_lock_timeout_in_atomic(pctl->hwlock, - HWSPNLCK_TIMEOUT); - if (ret) { - dev_err(pctl->dev, "Can't get hwspinlock\n"); -- goto unlock; -+ return ret; - } - } - -- if (pctl->irqmux_map & BIT(irq_data->hwirq)) { -- dev_err(pctl->dev, "irq line %ld already requested.\n", -- irq_data->hwirq); -- ret = -EBUSY; -- if (pctl->hwlock) -- hwspin_unlock_in_atomic(pctl->hwlock); -- goto unlock; -- } else { -- pctl->irqmux_map |= BIT(irq_data->hwirq); -- } -- - regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr); - - if (pctl->hwlock) - hwspin_unlock_in_atomic(pctl->hwlock); - --unlock: -- spin_unlock_irqrestore(&pctl->irqmux_lock, flags); - return ret; - } - --static void stm32_gpio_domain_deactivate(struct irq_domain *d, -- struct irq_data *irq_data) --{ -- struct stm32_gpio_bank *bank = d->host_data; -- struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); -- unsigned long flags; -- -- spin_lock_irqsave(&pctl->irqmux_lock, flags); -- pctl->irqmux_map &= ~BIT(irq_data->hwirq); -- spin_unlock_irqrestore(&pctl->irqmux_lock, flags); --} -- - static int stm32_gpio_domain_alloc(struct irq_domain *d, - unsigned int virq, - unsigned int nr_irqs, void *data) -@@ -472,9 +442,28 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d, - struct stm32_gpio_bank *bank = d->host_data; - struct irq_fwspec *fwspec = data; - struct irq_fwspec parent_fwspec; -- irq_hw_number_t hwirq; -+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); -+ irq_hw_number_t hwirq = fwspec->param[0]; -+ unsigned long flags; -+ int ret = 0; -+ -+ /* -+ * Check first that the IRQ MUX of that line is free. -+ * gpio irq mux is shared between several banks, protect with a lock -+ */ -+ spin_lock_irqsave(&pctl->irqmux_lock, flags); -+ -+ if (pctl->irqmux_map & BIT(hwirq)) { -+ dev_err(pctl->dev, "irq line %ld already requested.\n", hwirq); -+ ret = -EBUSY; -+ } else { -+ pctl->irqmux_map |= BIT(hwirq); -+ } -+ -+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags); -+ if (ret) -+ return ret; - -- hwirq = fwspec->param[0]; - parent_fwspec.fwnode = d->parent->fwnode; - parent_fwspec.param_count = 2; - parent_fwspec.param[0] = fwspec->param[0]; -@@ -486,12 +475,26 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d, - return irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &parent_fwspec); - } - -+static void stm32_gpio_domain_free(struct irq_domain *d, unsigned int virq, -+ unsigned int nr_irqs) -+{ -+ struct stm32_gpio_bank *bank = d->host_data; -+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); -+ struct irq_data *irq_data = irq_domain_get_irq_data(d, virq); -+ unsigned long flags, hwirq = irq_data->hwirq; -+ -+ irq_domain_free_irqs_common(d, virq, nr_irqs); -+ -+ spin_lock_irqsave(&pctl->irqmux_lock, flags); -+ pctl->irqmux_map &= ~BIT(hwirq); -+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags); -+} -+ - static const struct irq_domain_ops stm32_gpio_domain_ops = { -- .translate = stm32_gpio_domain_translate, -- .alloc = stm32_gpio_domain_alloc, -- .free = irq_domain_free_irqs_common, -+ .translate = stm32_gpio_domain_translate, -+ .alloc = stm32_gpio_domain_alloc, -+ .free = stm32_gpio_domain_free, - .activate = stm32_gpio_domain_activate, -- .deactivate = stm32_gpio_domain_deactivate, - }; - - /* Pinctrl functions */ -@@ -513,7 +516,7 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) - static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, - u32 pin_num, u32 fnum) - { -- int i; -+ int i, k; - - for (i = 0; i < pctl->npins; i++) { - const struct stm32_desc_pin *pin = pctl->pins + i; -@@ -522,7 +525,10 @@ static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, - if (pin->pin.number != pin_num) - continue; - -- while (func && func->name) { -+ if (fnum == STM32_PIN_RSVD) -+ return true; -+ -+ for (k = 0; k < STM32_CONFIG_NUM; k++) { - if (func->num == fnum) - return true; - func++; -@@ -833,6 +839,11 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, - return -EINVAL; - } - -+ if (function == STM32_PIN_RSVD) { -+ dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n"); -+ return 0; -+ } -+ - bank = gpiochip_get_data(range->gc); - pin = stm32_gpio_pin(g->pin); - -@@ -1147,10 +1158,27 @@ static int stm32_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - return 0; - } - -+static struct stm32_desc_pin * -+stm32_pconf_get_pin_desc_by_pin_number(struct stm32_pinctrl *pctl, -+ unsigned int pin_number) -+{ -+ struct stm32_desc_pin *pins = pctl->pins; -+ int i; -+ -+ for (i = 0; i < pctl->npins; i++) { -+ if (pins->pin.number == pin_number) -+ return pins; -+ pins++; -+ } -+ return NULL; -+} -+ - static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, - struct seq_file *s, - unsigned int pin) - { -+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); -+ const struct stm32_desc_pin *pin_desc; - struct pinctrl_gpio_range *range; - struct stm32_gpio_bank *bank; - int offset; -@@ -1200,7 +1228,12 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, - case 2: - drive = stm32_pconf_get_driving(bank, offset); - speed = stm32_pconf_get_speed(bank, offset); -- seq_printf(s, "%d - %s - %s - %s %s", alt, -+ pin_desc = stm32_pconf_get_pin_desc_by_pin_number(pctl, pin); -+ if (!pin_desc) -+ return; -+ -+ seq_printf(s, "%d (%s) - %s - %s - %s %s", alt, -+ pin_desc->functions[alt + 1].name, - drive ? "open drain" : "push pull", - biasing[bias], - speeds[speed], "speed"); -@@ -1409,7 +1442,8 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, - if (pctl->pkg && !(pctl->pkg & p->pkg)) - continue; - pins->pin = p->pin; -- pins->functions = p->functions; -+ memcpy((struct stm32_desc_pin *)pins->functions, p->functions, -+ STM32_CONFIG_NUM * sizeof(struct stm32_desc_function)); - pins++; - nb_pins_available++; - } -@@ -1518,6 +1552,7 @@ int stm32_pctl_probe(struct platform_device *pdev) - pctl->pctl_desc.pctlops = &stm32_pctrl_ops; - pctl->pctl_desc.pmxops = &stm32_pmx_ops; - pctl->dev = &pdev->dev; -+ pctl->pin_base_shift = pctl->match_data->pin_base_shift; - - pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, - pctl); -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h -index b0882d120..a7137fbff 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.h -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.h -@@ -17,6 +17,8 @@ - #define STM32_PIN_GPIO 0 - #define STM32_PIN_AF(x) ((x) + 1) - #define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1) -+#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1) -+#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1) - - /* package information */ - #define STM32MP_PKG_AA BIT(0) -@@ -24,6 +26,8 @@ - #define STM32MP_PKG_AC BIT(2) - #define STM32MP_PKG_AD BIT(3) - -+#define STM32MP157_Z_BASE_SHIFT 400 -+ - struct stm32_desc_function { - const char *name; - const unsigned char num; -@@ -31,26 +35,26 @@ struct stm32_desc_function { - - struct stm32_desc_pin { - struct pinctrl_pin_desc pin; -- const struct stm32_desc_function *functions; -+ const struct stm32_desc_function functions[STM32_CONFIG_NUM]; - const unsigned int pkg; - }; - - #define STM32_PIN(_pin, ...) \ - { \ - .pin = _pin, \ -- .functions = (struct stm32_desc_function[]){ \ -- __VA_ARGS__, { } }, \ -+ .functions = { \ -+ __VA_ARGS__}, \ - } - - #define STM32_PIN_PKG(_pin, _pkg, ...) \ - { \ - .pin = _pin, \ - .pkg = _pkg, \ -- .functions = (struct stm32_desc_function[]){ \ -- __VA_ARGS__, { } }, \ -+ .functions = { \ -+ __VA_ARGS__}, \ - } - #define STM32_FUNCTION(_num, _name) \ -- { \ -+ [_num] = { \ - .num = _num, \ - .name = _name, \ - } -@@ -58,6 +62,7 @@ struct stm32_desc_pin { - struct stm32_pinctrl_match_data { - const struct stm32_desc_pin *pins; - const unsigned int npins; -+ const unsigned int pin_base_shift; - }; - - struct stm32_gpio_bank; -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -index 2ccb99d64..86fe6d5ac 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -@@ -2328,6 +2328,7 @@ static struct stm32_pinctrl_match_data stm32mp157_match_data = { - static struct stm32_pinctrl_match_data stm32mp157_z_match_data = { - .pins = stm32mp157_z_pins, - .npins = ARRAY_SIZE(stm32mp157_z_pins), -+ .pin_base_shift = STM32MP157_Z_BASE_SHIFT, - }; - - static const struct of_device_id stm32mp157_pctrl_match[] = { -diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c -index 134c14621..5967025e9 100644 ---- a/drivers/pwm/pwm-stm32-lp.c -+++ b/drivers/pwm/pwm-stm32-lp.c -@@ -58,7 +58,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, - - /* Calculate the period and prescaler value */ - div = (unsigned long long)clk_get_rate(priv->clk) * state->period; -- do_div(div, NSEC_PER_SEC); -+ div = DIV_ROUND_CLOSEST_ULL(div, NSEC_PER_SEC); - if (!div) { - /* Clock is too slow to achieve requested period. */ - dev_dbg(priv->chip.dev, "Can't reach %llu ns\n", state->period); -@@ -78,7 +78,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, - - /* Calculate the duty cycle */ - dty = prd * state->duty_cycle; -- do_div(dty, state->period); -+ dty = DIV_ROUND_CLOSEST_ULL(dty, state->period); - - if (!cstate.enabled) { - /* enable clock to drive PWM counter */ -diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c -index d3be944f2..13f47e255 100644 ---- a/drivers/pwm/pwm-stm32.c -+++ b/drivers/pwm/pwm-stm32.c -@@ -207,6 +207,10 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, - regmap_write(priv->regmap, TIM_ARR, priv->max_arr); - regmap_write(priv->regmap, TIM_PSC, psc); - -+ /* Reset input selector to its default input and disable slave mode */ -+ regmap_write(priv->regmap, TIM_TISEL, 0x0); -+ regmap_write(priv->regmap, TIM_SMCR, 0x0); -+ - /* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */ - regmap_update_bits(priv->regmap, - pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, -diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c -index 2a42acb7c..2b328b970 100644 ---- a/drivers/regulator/stm32-pwr.c -+++ b/drivers/regulator/stm32-pwr.c -@@ -3,12 +3,15 @@ - // Authors: Gabriel Fernandez - // Pascal Paillet . - -+#include - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - #include - -@@ -24,6 +27,11 @@ - #define REG_1_1_EN BIT(30) - #define REG_1_1_RDY BIT(31) - -+#define STM32_SMC_PWR 0x82001001 -+#define STM32_WRITE 0x1 -+#define STM32_SMC_REG_SET 0x2 -+#define STM32_SMC_REG_CLEAR 0x3 -+ - /* list of supported regulators */ - enum { - PWR_REG11, -@@ -39,10 +47,18 @@ static u32 ready_mask_table[STM32PWR_REG_NUM_REGS] = { - }; - - struct stm32_pwr_reg { -+ int tzen; - void __iomem *base; - u32 ready_mask; - }; - -+#define SMC(class, op, address, val)\ -+ ({\ -+ struct arm_smccc_res res;\ -+ arm_smccc_smc(class, op, address, val,\ -+ 0, 0, 0, 0, &res);\ -+ }) -+ - static int stm32_pwr_reg_is_ready(struct regulator_dev *rdev) - { - struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); -@@ -69,9 +85,15 @@ static int stm32_pwr_reg_enable(struct regulator_dev *rdev) - int ret; - u32 val; - -- val = readl_relaxed(priv->base + REG_PWR_CR3); -- val |= rdev->desc->enable_mask; -- writel_relaxed(val, priv->base + REG_PWR_CR3); -+ if (priv->tzen) { -+ SMC(STM32_SMC_PWR, STM32_SMC_REG_SET, REG_PWR_CR3, -+ rdev->desc->enable_mask); -+ } else { -+ val = readl_relaxed(priv->base + REG_PWR_CR3); -+ val |= rdev->desc->enable_mask; -+ writel_relaxed(val, priv->base + REG_PWR_CR3); -+ } -+ - - /* use an arbitrary timeout of 20ms */ - ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, val, -@@ -88,9 +110,14 @@ static int stm32_pwr_reg_disable(struct regulator_dev *rdev) - int ret; - u32 val; - -- val = readl_relaxed(priv->base + REG_PWR_CR3); -- val &= ~rdev->desc->enable_mask; -- writel_relaxed(val, priv->base + REG_PWR_CR3); -+ if (priv->tzen) { -+ SMC(STM32_SMC_PWR, STM32_SMC_REG_CLEAR, REG_PWR_CR3, -+ rdev->desc->enable_mask); -+ } else { -+ val = readl_relaxed(priv->base + REG_PWR_CR3); -+ val &= ~rdev->desc->enable_mask; -+ writel_relaxed(val, priv->base + REG_PWR_CR3); -+ } - - /* use an arbitrary timeout of 20ms */ - ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, !val, -@@ -121,12 +148,50 @@ static const struct regulator_ops stm32_pwr_reg_ops = { - .supply_name = _supply, \ - } \ - --static const struct regulator_desc stm32_pwr_desc[] = { -+static struct regulator_desc stm32_pwr_desc[] = { - PWR_REG(PWR_REG11, "reg11", 1100000, REG_1_1_EN, "vdd"), - PWR_REG(PWR_REG18, "reg18", 1800000, REG_1_8_EN, "vdd"), - PWR_REG(PWR_USB33, "usb33", 3300000, USB_3_3_EN, "vdd_3v3_usbfs"), - }; - -+static int is_stm32_soc_secured(struct platform_device *pdev, int *val) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct regmap *syscon; -+ u32 reg, mask; -+ int tzc_val = 0; -+ int err; -+ -+ syscon = syscon_regmap_lookup_by_phandle(np, "st,tzcr"); -+ if (IS_ERR(syscon)) { -+ if (PTR_ERR(syscon) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "tzcr syscon required\n"); -+ return PTR_ERR(syscon); -+ } -+ -+ err = of_property_read_u32_index(np, "st,tzcr", 1, ®); -+ if (err) { -+ dev_err(&pdev->dev, "tzcr offset required !\n"); -+ return err; -+ } -+ -+ err = of_property_read_u32_index(np, "st,tzcr", 2, &mask); -+ if (err) { -+ dev_err(&pdev->dev, "tzcr mask required !\n"); -+ return err; -+ } -+ -+ err = regmap_read(syscon, reg, &tzc_val); -+ if (err) { -+ dev_err(&pdev->dev, "failed to read tzcr status !\n"); -+ return err; -+ } -+ -+ *val = tzc_val & mask; -+ -+ return 0; -+} -+ - static int stm32_pwr_regulator_probe(struct platform_device *pdev) - { - struct device_node *np = pdev->dev.of_node; -@@ -135,6 +200,11 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) - struct regulator_dev *rdev; - struct regulator_config config = { }; - int i, ret = 0; -+ int tzen = 0; -+ -+ ret = is_stm32_soc_secured(pdev, &tzen); -+ if (ret) -+ return ret; - - base = of_iomap(np, 0); - if (!base) { -@@ -149,6 +219,7 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) - GFP_KERNEL); - if (!priv) - return -ENOMEM; -+ priv->tzen = tzen; - priv->base = base; - priv->ready_mask = ready_mask_table[i]; - config.driver_data = priv; -diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c -index cf10fdb72..c5337a12a 100644 ---- a/drivers/regulator/stpmic1_regulator.c -+++ b/drivers/regulator/stpmic1_regulator.c -@@ -2,7 +2,9 @@ - // Copyright (C) STMicroelectronics 2018 - // Author: Pascal Paillet for STMicroelectronics. - -+#include - #include -+#include - #include - #include - #include -@@ -30,10 +32,26 @@ struct stpmic1_regulator_cfg { - u8 icc_mask; - }; - -+/** -+ * struct boost_data - this structure is used as driver data for the usb boost -+ * @boost_rdev: device for boost regulator -+ * @vbus_otg_rdev: device for vbus_otg regulator -+ * @sw_out_rdev: device for sw_out regulator -+ * @occ_timeout: overcurrent detection timeout -+ */ -+struct boost_data { -+ struct regulator_dev *boost_rdev; -+ struct regulator_dev *vbus_otg_rdev; -+ struct regulator_dev *sw_out_rdev; -+ ktime_t occ_timeout; -+}; -+ - static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); - static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); - static int stpmic1_set_icc(struct regulator_dev *rdev); - static unsigned int stpmic1_map_mode(unsigned int mode); -+static int regulator_enable_boost(struct regulator_dev *rdev); -+static int regulator_disable_boost(struct regulator_dev *rdev); - - enum { - STPMIC1_BUCK1 = 0, -@@ -181,8 +199,8 @@ static const struct regulator_ops stpmic1_vref_ddr_ops = { - - static const struct regulator_ops stpmic1_boost_regul_ops = { - .is_enabled = regulator_is_enabled_regmap, -- .enable = regulator_enable_regmap, -- .disable = regulator_disable_regmap, -+ .enable = regulator_enable_boost, -+ .disable = regulator_disable_boost, - .set_over_current_protection = stpmic1_set_icc, - }; - -@@ -513,6 +531,79 @@ static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) - return IRQ_HANDLED; - } - -+static int regulator_enable_boost(struct regulator_dev *rdev) -+{ -+ struct boost_data *usb_data = rdev_get_drvdata(rdev); -+ -+ usb_data->occ_timeout = ktime_add_us(ktime_get(), 100000); -+ -+ return regulator_enable_regmap(rdev); -+} -+ -+static int regulator_disable_boost(struct regulator_dev *rdev) -+{ -+ struct boost_data *usb_data = rdev_get_drvdata(rdev); -+ -+ usb_data->occ_timeout = 0; -+ -+ return regulator_disable_regmap(rdev); -+} -+ -+static void stpmic1_reset_boost(struct boost_data *usb_data) -+{ -+ int otg_on = 0; -+ int sw_out_on = 0; -+ -+ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "reset usb boost\n"); -+ -+ /* the boost was actually disabled by the over-current protection */ -+ regulator_disable_regmap(usb_data->boost_rdev); -+ -+ if (usb_data->vbus_otg_rdev) -+ otg_on = regulator_is_enabled_regmap(usb_data->vbus_otg_rdev); -+ if (otg_on) -+ regulator_disable_regmap(usb_data->vbus_otg_rdev); -+ -+ if (usb_data->sw_out_rdev) -+ sw_out_on = regulator_is_enabled_regmap(usb_data->sw_out_rdev); -+ if (sw_out_on) -+ regulator_disable_regmap(usb_data->sw_out_rdev); -+ -+ regulator_enable_regmap(usb_data->boost_rdev); -+ -+ /* sleep at least 5ms */ -+ usleep_range(5000, 10000); -+ -+ if (otg_on) -+ regulator_enable_regmap(usb_data->vbus_otg_rdev); -+ -+ if (sw_out_on) -+ regulator_enable_regmap(usb_data->sw_out_rdev); -+ -+} -+ -+static irqreturn_t stpmic1_boost_irq_handler(int irq, void *data) -+{ -+ struct boost_data *usb_data = (struct boost_data *)data; -+ -+ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "usb boost irq handler\n"); -+ -+ /* overcurrent detected on boost after timeout */ -+ if (usb_data->occ_timeout != 0 && -+ ktime_compare(ktime_get(), usb_data->occ_timeout) > 0) { -+ /* reset usb boost and usb power switches */ -+ stpmic1_reset_boost(usb_data); -+ return IRQ_HANDLED; -+ } -+ -+ /* Send an overcurrent notification */ -+ regulator_notifier_call_chain(usb_data->boost_rdev, -+ REGULATOR_EVENT_OVER_CURRENT, -+ NULL); -+ -+ return IRQ_HANDLED; -+} -+ - #define MATCH(_name, _id) \ - [STPMIC1_##_id] = { \ - .name = #_name, \ -@@ -536,9 +627,10 @@ static struct of_regulator_match stpmic1_matches[] = { - MATCH(pwr_sw2, SW_OUT), - }; - --static int stpmic1_regulator_register(struct platform_device *pdev, int id, -- struct of_regulator_match *match, -- const struct stpmic1_regulator_cfg *cfg) -+static struct regulator_dev * -+stpmic1_regulator_register(struct platform_device *pdev, int id, -+ struct of_regulator_match *match, -+ const struct stpmic1_regulator_cfg *cfg) - { - struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); - struct regulator_dev *rdev; -@@ -556,7 +648,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register %s regulator\n", - cfg->desc.name); -- return PTR_ERR(rdev); -+ return rdev; - } - - /* set mask reset */ -@@ -568,7 +660,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, - cfg->mask_reset_mask); - if (ret) { - dev_err(&pdev->dev, "set mask reset failed\n"); -- return ret; -+ return ERR_PTR(ret); - } - } - -@@ -582,15 +674,60 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, - pdev->name, rdev); - if (ret) { - dev_err(&pdev->dev, "Request IRQ failed\n"); -- return ret; -+ return ERR_PTR(ret); - } - } -- return 0; -+ -+ return rdev; -+} -+ -+static struct regulator_dev * -+stpmic1_boost_register(struct platform_device *pdev, int id, -+ struct of_regulator_match *match, -+ const struct stpmic1_regulator_cfg *cfg, -+ struct boost_data *usb_data) -+{ -+ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); -+ struct regulator_dev *rdev; -+ struct regulator_config config = {}; -+ int ret = 0; -+ int irq; -+ -+ config.dev = &pdev->dev; -+ config.init_data = match->init_data; -+ config.of_node = match->of_node; -+ config.regmap = pmic_dev->regmap; -+ config.driver_data = (void *)usb_data; -+ -+ rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); -+ if (IS_ERR(rdev)) { -+ dev_err(&pdev->dev, "failed to register %s regulator\n", -+ cfg->desc.name); -+ return rdev; -+ } -+ -+ /* setup an irq handler for over-current detection */ -+ irq = of_irq_get(config.of_node, 0); -+ if (irq > 0) { -+ ret = devm_request_threaded_irq(&pdev->dev, -+ irq, NULL, -+ stpmic1_boost_irq_handler, -+ IRQF_ONESHOT, pdev->name, -+ usb_data); -+ if (ret) { -+ dev_err(&pdev->dev, "Request IRQ failed\n"); -+ return ERR_PTR(ret); -+ } -+ } -+ -+ return rdev; - } - - static int stpmic1_regulator_probe(struct platform_device *pdev) - { - int i, ret; -+ struct boost_data *usb_data; -+ struct regulator_dev *rdev; - - ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, - ARRAY_SIZE(stpmic1_matches)); -@@ -600,11 +737,30 @@ static int stpmic1_regulator_probe(struct platform_device *pdev) - return ret; - } - -+ usb_data = devm_kzalloc(&pdev->dev, sizeof(*usb_data), GFP_KERNEL); -+ if (!usb_data) -+ return -ENOMEM; -+ - for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { -- ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], -- &stpmic1_regulator_cfgs[i]); -- if (ret < 0) -- return ret; -+ if (i == STPMIC1_BOOST) { -+ rdev = -+ stpmic1_boost_register(pdev, i, &stpmic1_matches[i], -+ &stpmic1_regulator_cfgs[i], -+ usb_data); -+ -+ usb_data->boost_rdev = rdev; -+ } else { -+ rdev = -+ stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], -+ &stpmic1_regulator_cfgs[i]); -+ -+ if (i == STPMIC1_VBUS_OTG) -+ usb_data->vbus_otg_rdev = rdev; -+ else if (i == STPMIC1_SW_OUT) -+ usb_data->sw_out_rdev = rdev; -+ } -+ if (IS_ERR(rdev)) -+ return PTR_ERR(rdev); - } - - dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); -diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -index aadaea052..6bdeeea0d 100644 ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -795,6 +795,7 @@ config SPI_STM32_QSPI - tristate "STMicroelectronics STM32 QUAD SPI controller" - depends on ARCH_STM32 || COMPILE_TEST - depends on OF -+ depends on SPI_MEM - help - This enables support for the Quad SPI controller in master mode. - This driver does not support generic SPI. The implementation only -diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c -index 4682f49dc..1325db7f5 100644 ---- a/drivers/spi/spi-mem.c -+++ b/drivers/spi/spi-mem.c -@@ -6,6 +6,7 @@ - * Author: Boris Brezillon - */ - #include -+#include - #include - #include - #include -@@ -726,6 +727,91 @@ static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv) - return container_of(drv, struct spi_mem_driver, spidrv.driver); - } - -+static int spi_mem_read_status(struct spi_mem *mem, -+ const struct spi_mem_op *op, -+ u16 *status) -+{ -+ const u8 *bytes = (u8 *)op->data.buf.in; -+ int ret; -+ -+ ret = spi_mem_exec_op(mem, op); -+ if (ret) -+ return ret; -+ -+ if (op->data.nbytes > 1) -+ *status = ((u16)bytes[0] << 8) | bytes[1]; -+ else -+ *status = bytes[0]; -+ -+ return 0; -+} -+ -+/** -+ * spi_mem_poll_status() - Poll memory device status -+ * @mem: SPI memory device -+ * @op: the memory operation to execute -+ * @mask: status bitmask to ckeck -+ * @match: (status & mask) expected value -+ * @initial_delay_us: delay in us before starting to poll -+ * @polling_delay_us: time to sleep between reads in us -+ * @timeout_ms: timeout in milliseconds -+ * -+ * This function polls a status register and returns when -+ * (status & mask) == match or when the timeout has expired. -+ * -+ * Return: 0 in case of success, -ETIMEDOUT in case of error, -+ * -EOPNOTSUPP if not supported. -+ */ -+int spi_mem_poll_status(struct spi_mem *mem, -+ const struct spi_mem_op *op, -+ u16 mask, u16 match, -+ unsigned long initial_delay_us, -+ unsigned long polling_delay_us, -+ u16 timeout_ms) -+{ -+ struct spi_controller *ctlr = mem->spi->controller; -+ int ret = -EOPNOTSUPP; -+ int read_status_ret; -+ u16 status; -+ -+ if (op->data.nbytes < 1 || op->data.nbytes > 2 || -+ op->data.dir != SPI_MEM_DATA_IN) -+ return -EINVAL; -+ -+ if (ctlr->mem_ops && ctlr->mem_ops->poll_status) { -+ ret = spi_mem_access_start(mem); -+ if (ret) -+ return ret; -+ -+ ret = ctlr->mem_ops->poll_status(mem, op, mask, match, -+ initial_delay_us, polling_delay_us, -+ timeout_ms); -+ -+ spi_mem_access_end(mem); -+ } -+ -+ if (ret == -EOPNOTSUPP) { -+ if (!spi_mem_supports_op(mem, op)) -+ return ret; -+ -+ if (initial_delay_us < 10) -+ udelay(initial_delay_us); -+ else -+ usleep_range((initial_delay_us >> 2) + 1, -+ initial_delay_us); -+ -+ ret = read_poll_timeout(spi_mem_read_status, read_status_ret, -+ (read_status_ret || ((status) & mask) == match), -+ polling_delay_us, timeout_ms * 1000, false, mem, -+ op, &status); -+ if (read_status_ret) -+ return read_status_ret; -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(spi_mem_poll_status); -+ - static int spi_mem_probe(struct spi_device *spi) - { - struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); -diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c -index 4f24f6392..39003e1f6 100644 ---- a/drivers/spi/spi-stm32-qspi.c -+++ b/drivers/spi/spi-stm32-qspi.c -@@ -36,6 +36,7 @@ - #define CR_FTIE BIT(18) - #define CR_SMIE BIT(19) - #define CR_TOIE BIT(20) -+#define CR_APMS BIT(22) - #define CR_PRESC_MASK GENMASK(31, 24) - - #define QSPI_DCR 0x04 -@@ -53,6 +54,7 @@ - #define QSPI_FCR 0x0c - #define FCR_CTEF BIT(0) - #define FCR_CTCF BIT(1) -+#define FCR_CSMF BIT(3) - - #define QSPI_DLR 0x10 - -@@ -91,7 +93,6 @@ - #define STM32_AUTOSUSPEND_DELAY -1 - - struct stm32_qspi_flash { -- struct stm32_qspi *qspi; - u32 cs; - u32 presc; - }; -@@ -107,6 +108,7 @@ struct stm32_qspi { - u32 clk_rate; - struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP]; - struct completion data_completion; -+ struct completion match_completion; - u32 fmode; - - struct dma_chan *dma_chtx; -@@ -115,6 +117,7 @@ struct stm32_qspi { - - u32 cr_reg; - u32 dcr_reg; -+ unsigned long status_timeout; - - /* - * to protect device configuration, could be different between -@@ -128,11 +131,20 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) - struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; - u32 cr, sr; - -+ cr = readl_relaxed(qspi->io_base + QSPI_CR); - sr = readl_relaxed(qspi->io_base + QSPI_SR); - -+ if (cr & CR_SMIE && sr & SR_SMF) { -+ /* disable irq */ -+ cr &= ~CR_SMIE; -+ writel_relaxed(cr, qspi->io_base + QSPI_CR); -+ complete(&qspi->match_completion); -+ -+ return IRQ_HANDLED; -+ } -+ - if (sr & (SR_TEF | SR_TCF)) { - /* disable irq */ -- cr = readl_relaxed(qspi->io_base + QSPI_CR); - cr &= ~CR_TCIE & ~CR_TEIE; - writel_relaxed(cr, qspi->io_base + QSPI_CR); - complete(&qspi->data_completion); -@@ -269,8 +281,9 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) - - if (qspi->fmode == CCR_FMODE_MM) - return stm32_qspi_tx_mm(qspi, op); -- else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || -- (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) -+ else if (((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || -+ (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) && -+ op->data.nbytes > 4) - if (!stm32_qspi_tx_dma(qspi, op)) - return 0; - -@@ -321,6 +334,24 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, - return err; - } - -+static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi, -+ const struct spi_mem_op *op) -+{ -+ u32 cr; -+ -+ reinit_completion(&qspi->match_completion); -+ cr = readl_relaxed(qspi->io_base + QSPI_CR); -+ writel_relaxed(cr | CR_SMIE, qspi->io_base + QSPI_CR); -+ -+ if (!wait_for_completion_timeout(&qspi->match_completion, -+ msecs_to_jiffies(qspi->status_timeout))) -+ return -ETIMEDOUT; -+ -+ writel_relaxed(FCR_CSMF, qspi->io_base + QSPI_FCR); -+ -+ return 0; -+} -+ - static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth) - { - if (buswidth == 4) -@@ -333,8 +364,8 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) - { - struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); - struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; -- u32 ccr, cr, addr_max; -- int timeout, err = 0; -+ u32 ccr, cr; -+ int timeout, err = 0, err_poll_status = 0; - - dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", - op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, -@@ -345,18 +376,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) - if (err) - goto abort; - -- addr_max = op->addr.val + op->data.nbytes + 1; -- -- if (op->data.dir == SPI_MEM_DATA_IN) { -- if (addr_max < qspi->mm_size && -- op->addr.buswidth) -- qspi->fmode = CCR_FMODE_MM; -- else -- qspi->fmode = CCR_FMODE_INDR; -- } else { -- qspi->fmode = CCR_FMODE_INDW; -- } -- - cr = readl_relaxed(qspi->io_base + QSPI_CR); - cr &= ~CR_PRESC_MASK & ~CR_FSEL; - cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); -@@ -366,8 +385,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) - if (op->data.nbytes) - writel_relaxed(op->data.nbytes - 1, - qspi->io_base + QSPI_DLR); -- else -- qspi->fmode = CCR_FMODE_INDW; - - ccr = qspi->fmode; - ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); -@@ -394,6 +411,9 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) - if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM) - writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); - -+ if (qspi->fmode == CCR_FMODE_APM) -+ err_poll_status = stm32_qspi_wait_poll_status(qspi, op); -+ - err = stm32_qspi_tx(qspi, op); - - /* -@@ -403,7 +423,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) - * byte of device (device size - fifo size). like device size is not - * knows, the prefetching is always stop. - */ -- if (err || qspi->fmode == CCR_FMODE_MM) -+ if (err || err_poll_status || qspi->fmode == CCR_FMODE_MM) - goto abort; - - /* wait end of tx in indirect mode */ -@@ -422,15 +442,49 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) - cr, !(cr & CR_ABORT), 1, - STM32_ABT_TIMEOUT_US); - -- writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR); -+ writel_relaxed(FCR_CTCF | FCR_CSMF, qspi->io_base + QSPI_FCR); - -- if (err || timeout) -- dev_err(qspi->dev, "%s err:%d abort timeout:%d\n", -- __func__, err, timeout); -+ if (err || err_poll_status || timeout) -+ dev_err(qspi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n", -+ __func__, err, err_poll_status, timeout); - - return err; - } - -+static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *op, -+ u16 mask, u16 match, -+ unsigned long initial_delay_us, -+ unsigned long polling_rate_us, -+ unsigned long timeout_ms) -+{ -+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); -+ int ret; -+ -+ if (!spi_mem_supports_op(mem, op)) -+ return -EOPNOTSUPP; -+ -+ ret = pm_runtime_get_sync(qspi->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(qspi->dev); -+ return ret; -+ } -+ -+ mutex_lock(&qspi->lock); -+ -+ writel_relaxed(mask, qspi->io_base + QSPI_PSMKR); -+ writel_relaxed(match, qspi->io_base + QSPI_PSMAR); -+ qspi->fmode = CCR_FMODE_APM; -+ qspi->status_timeout = timeout_ms; -+ -+ ret = stm32_qspi_send(mem, op); -+ mutex_unlock(&qspi->lock); -+ -+ pm_runtime_mark_last_busy(qspi->dev); -+ pm_runtime_put_autosuspend(qspi->dev); -+ -+ return ret; -+} -+ - static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) - { - struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); -@@ -443,6 +497,11 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) - } - - mutex_lock(&qspi->lock); -+ if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) -+ qspi->fmode = CCR_FMODE_INDR; -+ else -+ qspi->fmode = CCR_FMODE_INDW; -+ - ret = stm32_qspi_send(mem, op); - mutex_unlock(&qspi->lock); - -@@ -452,6 +511,64 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) - return ret; - } - -+static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) -+{ -+ struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); -+ -+ if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) -+ return -EOPNOTSUPP; -+ -+ /* should never happen, as mm_base == null is an error probe exit condition */ -+ if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) -+ return -EOPNOTSUPP; -+ -+ if (!qspi->mm_size) -+ return -EOPNOTSUPP; -+ -+ return 0; -+} -+ -+static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, -+ u64 offs, size_t len, void *buf) -+{ -+ struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); -+ struct spi_mem_op op; -+ u32 addr_max; -+ int ret; -+ -+ ret = pm_runtime_get_sync(qspi->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(qspi->dev); -+ return ret; -+ } -+ -+ mutex_lock(&qspi->lock); -+ /* make a local copy of desc op_tmpl and complete dirmap rdesc -+ * spi_mem_op template with offs, len and *buf in order to get -+ * all needed transfer information into struct spi_mem_op -+ */ -+ memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); -+ dev_dbg(qspi->dev, "%s len = 0x%x offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); -+ -+ op.data.nbytes = len; -+ op.addr.val = desc->info.offset + offs; -+ op.data.buf.in = buf; -+ -+ addr_max = op.addr.val + op.data.nbytes + 1; -+ if (addr_max < qspi->mm_size && op.addr.buswidth) -+ qspi->fmode = CCR_FMODE_MM; -+ else -+ qspi->fmode = CCR_FMODE_INDR; -+ -+ ret = stm32_qspi_send(desc->mem, &op); -+ mutex_unlock(&qspi->lock); -+ -+ pm_runtime_mark_last_busy(qspi->dev); -+ pm_runtime_put_autosuspend(qspi->dev); -+ -+ return ret ?: len; -+} -+ - static int stm32_qspi_setup(struct spi_device *spi) - { - struct spi_controller *ctrl = spi->master; -@@ -475,12 +592,11 @@ static int stm32_qspi_setup(struct spi_device *spi) - presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; - - flash = &qspi->flash[spi->chip_select]; -- flash->qspi = qspi; - flash->cs = spi->chip_select; - flash->presc = presc; - - mutex_lock(&qspi->lock); -- qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; -+ qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; - writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); - - /* set dcr fsize to max address */ -@@ -557,7 +673,10 @@ static void stm32_qspi_dma_free(struct stm32_qspi *qspi) - * to check supported mode. - */ - static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { -- .exec_op = stm32_qspi_exec_op, -+ .exec_op = stm32_qspi_exec_op, -+ .dirmap_create = stm32_qspi_dirmap_create, -+ .dirmap_read = stm32_qspi_dirmap_read, -+ .poll_status = stm32_qspi_poll_status, - }; - - static int stm32_qspi_probe(struct platform_device *pdev) -@@ -612,6 +731,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) - } - - init_completion(&qspi->data_completion); -+ init_completion(&qspi->match_completion); - - qspi->clk = devm_clk_get(dev, NULL); - if (IS_ERR(qspi->clk)) { -diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c -index a6dfc8fef..c42c0ae92 100644 ---- a/drivers/spi/spi-stm32.c -+++ b/drivers/spi/spi-stm32.c -@@ -5,6 +5,7 @@ - // Copyright (C) 2017, STMicroelectronics - All Rights Reserved - // Author(s): Amelie Delaunay for STMicroelectronics. - -+#include - #include - #include - #include -@@ -31,8 +32,8 @@ - #define STM32F4_SPI_CR1_CPHA BIT(0) - #define STM32F4_SPI_CR1_CPOL BIT(1) - #define STM32F4_SPI_CR1_MSTR BIT(2) --#define STM32F4_SPI_CR1_BR_SHIFT 3 - #define STM32F4_SPI_CR1_BR GENMASK(5, 3) -+#define STM32F4_SPI_CR1_BR_SHIFT 3 - #define STM32F4_SPI_CR1_SPE BIT(6) - #define STM32F4_SPI_CR1_LSBFRST BIT(7) - #define STM32F4_SPI_CR1_SSI BIT(8) -@@ -94,27 +95,22 @@ - #define STM32H7_SPI_CR1_SSI BIT(12) - - /* STM32H7_SPI_CR2 bit fields */ --#define STM32H7_SPI_CR2_TSIZE_SHIFT 0 - #define STM32H7_SPI_CR2_TSIZE GENMASK(15, 0) -+#define STM32H7_SPI_TSIZE_MAX GENMASK(15, 0) - - /* STM32H7_SPI_CFG1 bit fields */ --#define STM32H7_SPI_CFG1_DSIZE_SHIFT 0 - #define STM32H7_SPI_CFG1_DSIZE GENMASK(4, 0) --#define STM32H7_SPI_CFG1_FTHLV_SHIFT 5 - #define STM32H7_SPI_CFG1_FTHLV GENMASK(8, 5) - #define STM32H7_SPI_CFG1_RXDMAEN BIT(14) - #define STM32H7_SPI_CFG1_TXDMAEN BIT(15) --#define STM32H7_SPI_CFG1_MBR_SHIFT 28 - #define STM32H7_SPI_CFG1_MBR GENMASK(30, 28) -+#define STM32H7_SPI_CFG1_MBR_SHIFT 28 - #define STM32H7_SPI_CFG1_MBR_MIN 0 - #define STM32H7_SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28) - - /* STM32H7_SPI_CFG2 bit fields */ --#define STM32H7_SPI_CFG2_MIDI_SHIFT 4 - #define STM32H7_SPI_CFG2_MIDI GENMASK(7, 4) --#define STM32H7_SPI_CFG2_COMM_SHIFT 17 - #define STM32H7_SPI_CFG2_COMM GENMASK(18, 17) --#define STM32H7_SPI_CFG2_SP_SHIFT 19 - #define STM32H7_SPI_CFG2_SP GENMASK(21, 19) - #define STM32H7_SPI_CFG2_MASTER BIT(22) - #define STM32H7_SPI_CFG2_LSBFRST BIT(23) -@@ -130,17 +126,15 @@ - #define STM32H7_SPI_IER_EOTIE BIT(3) - #define STM32H7_SPI_IER_TXTFIE BIT(4) - #define STM32H7_SPI_IER_OVRIE BIT(6) --#define STM32H7_SPI_IER_MODFIE BIT(9) - #define STM32H7_SPI_IER_ALL GENMASK(10, 0) - - /* STM32H7_SPI_SR bit fields */ - #define STM32H7_SPI_SR_RXP BIT(0) - #define STM32H7_SPI_SR_TXP BIT(1) - #define STM32H7_SPI_SR_EOT BIT(3) -+#define STM32H7_SPI_SR_TXTF BIT(4) - #define STM32H7_SPI_SR_OVR BIT(6) --#define STM32H7_SPI_SR_MODF BIT(9) - #define STM32H7_SPI_SR_SUSP BIT(11) --#define STM32H7_SPI_SR_RXPLVL_SHIFT 13 - #define STM32H7_SPI_SR_RXPLVL GENMASK(14, 13) - #define STM32H7_SPI_SR_RXWNE BIT(15) - -@@ -167,7 +161,7 @@ - #define SPI_3WIRE_TX 3 - #define SPI_3WIRE_RX 4 - --#define SPI_1HZ_NS 1000000000 -+#define STM32_SPI_AUTOSUSPEND_DELAY 1 /* 1 ms */ - - /* - * use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers -@@ -268,7 +262,6 @@ struct stm32_spi_cfg { - * @base: virtual memory area - * @clk: hw kernel clock feeding the SPI clock generator - * @clk_rate: rate of the hw kernel clock feeding the SPI clock generator -- * @rst: SPI controller reset line - * @lock: prevent I/O concurrent access - * @irq: SPI controller interrupt line - * @fifo_size: size of the embedded fifo in bytes -@@ -294,7 +287,6 @@ struct stm32_spi { - void __iomem *base; - struct clk *clk; - u32 clk_rate; -- struct reset_control *rst; - spinlock_t lock; /* prevent I/O concurrent access */ - int irq; - unsigned int fifo_size; -@@ -417,9 +409,7 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi) - stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_DSIZE); - - cfg1 = readl_relaxed(spi->base + STM32H7_SPI_CFG1); -- max_bpw = (cfg1 & STM32H7_SPI_CFG1_DSIZE) >> -- STM32H7_SPI_CFG1_DSIZE_SHIFT; -- max_bpw += 1; -+ max_bpw = FIELD_GET(STM32H7_SPI_CFG1_DSIZE, cfg1) + 1; - - spin_unlock_irqrestore(&spi->lock, flags); - -@@ -599,30 +589,30 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) - /** - * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register - * @spi: pointer to the spi controller data structure -- * @flush: boolean indicating that FIFO should be flushed - * - * Write in rx_buf depends on remaining bytes to avoid to write beyond - * rx_buf end. - */ --static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) -+static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi) - { - u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR); -- u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> -- STM32H7_SPI_SR_RXPLVL_SHIFT; -+ u32 rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); - - while ((spi->rx_len > 0) && - ((sr & STM32H7_SPI_SR_RXP) || -- (flush && ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { -+ ((sr & STM32H7_SPI_SR_EOT) && -+ ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { - u32 offs = spi->cur_xferlen - spi->rx_len; - - if ((spi->rx_len >= sizeof(u32)) || -- (flush && (sr & STM32H7_SPI_SR_RXWNE))) { -+ (sr & STM32H7_SPI_SR_RXWNE)) { - u32 *rx_buf32 = (u32 *)(spi->rx_buf + offs); - - *rx_buf32 = readl_relaxed(spi->base + STM32H7_SPI_RXDR); - spi->rx_len -= sizeof(u32); - } else if ((spi->rx_len >= sizeof(u16)) || -- (flush && (rxplvl >= 2 || spi->cur_bpw > 8))) { -+ (!(sr & STM32H7_SPI_SR_RXWNE) && -+ (rxplvl >= 2 || spi->cur_bpw > 8))) { - u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); - - *rx_buf16 = readw_relaxed(spi->base + STM32H7_SPI_RXDR); -@@ -635,12 +625,11 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) - } - - sr = readl_relaxed(spi->base + STM32H7_SPI_SR); -- rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> -- STM32H7_SPI_SR_RXPLVL_SHIFT; -+ rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); - } - -- dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__, -- flush ? "(flush)" : "", spi->rx_len); -+ dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n", -+ __func__, spi->rx_len, sr); - } - - /** -@@ -707,18 +696,12 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) - * stm32h7_spi_disable - Disable SPI controller - * @spi: pointer to the spi controller data structure - * -- * RX-Fifo is flushed when SPI controller is disabled. To prevent any data -- * loss, use stm32h7_spi_read_rxfifo(flush) to read the remaining bytes in -- * RX-Fifo. -- * Normally, if TSIZE has been configured, we should relax the hardware at the -- * reception of the EOT interrupt. But in case of error, EOT will not be -- * raised. So the subsystem unprepare_message call allows us to properly -- * complete the transfer from an hardware point of view. -+ * RX-Fifo is flushed when SPI controller is disabled. - */ - static void stm32h7_spi_disable(struct stm32_spi *spi) - { - unsigned long flags; -- u32 cr1, sr; -+ u32 cr1; - - dev_dbg(spi->dev, "disable controller\n"); - -@@ -731,25 +714,6 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) - return; - } - -- /* Wait on EOT or suspend the flow */ -- if (readl_relaxed_poll_timeout_atomic(spi->base + STM32H7_SPI_SR, -- sr, !(sr & STM32H7_SPI_SR_EOT), -- 10, 100000) < 0) { -- if (cr1 & STM32H7_SPI_CR1_CSTART) { -- writel_relaxed(cr1 | STM32H7_SPI_CR1_CSUSP, -- spi->base + STM32H7_SPI_CR1); -- if (readl_relaxed_poll_timeout_atomic( -- spi->base + STM32H7_SPI_SR, -- sr, !(sr & STM32H7_SPI_SR_SUSP), -- 10, 100000) < 0) -- dev_warn(spi->dev, -- "Suspend request timeout\n"); -- } -- } -- -- if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) -- stm32h7_spi_read_rxfifo(spi, true); -- - if (spi->cur_usedma && spi->dma_tx) - dmaengine_terminate_all(spi->dma_tx); - if (spi->cur_usedma && spi->dma_rx) -@@ -907,7 +871,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) - { - struct spi_master *master = dev_id; - struct stm32_spi *spi = spi_master_get_devdata(master); -- u32 sr, ier, mask; -+ u32 sr, ier, mask, ifcr; - unsigned long flags; - bool end = false; - -@@ -915,6 +879,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) - - sr = readl_relaxed(spi->base + STM32H7_SPI_SR); - ier = readl_relaxed(spi->base + STM32H7_SPI_IER); -+ ifcr = 0; - - mask = ier; - /* -@@ -927,57 +892,63 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) - * DXPIE is set in Full-Duplex, one IT will be raised if TXP and RXP - * are set. So in case of Full-Duplex, need to poll TXP and RXP event. - */ -- if ((spi->cur_comm == SPI_FULL_DUPLEX) && !spi->cur_usedma) -+ if ((spi->cur_comm == SPI_FULL_DUPLEX) && (!spi->cur_usedma)) - mask |= STM32H7_SPI_SR_TXP | STM32H7_SPI_SR_RXP; - -- if (!(sr & mask)) { -+ mask &= sr; -+ -+ if (!mask) { - dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", - sr, ier); - spin_unlock_irqrestore(&spi->lock, flags); - return IRQ_NONE; - } - -- if (sr & STM32H7_SPI_SR_SUSP) { -+ if (mask & STM32H7_SPI_SR_SUSP) { - static DEFINE_RATELIMIT_STATE(rs, - DEFAULT_RATELIMIT_INTERVAL * 10, - 1); - if (__ratelimit(&rs)) - dev_dbg_ratelimited(spi->dev, "Communication suspended\n"); - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32h7_spi_read_rxfifo(spi, false); -+ stm32h7_spi_read_rxfifo(spi); - /* - * If communication is suspended while using DMA, it means - * that something went wrong, so stop the current transfer - */ - if (spi->cur_usedma) - end = true; -+ ifcr |= STM32H7_SPI_SR_SUSP; - } - -- if (sr & STM32H7_SPI_SR_MODF) { -- dev_warn(spi->dev, "Mode fault: transfer aborted\n"); -- end = true; -- } -- -- if (sr & STM32H7_SPI_SR_OVR) { -+ if (mask & STM32H7_SPI_SR_OVR) { - dev_err(spi->dev, "Overrun: RX data lost\n"); - end = true; -+ ifcr |= STM32H7_SPI_SR_OVR; - } - -- if (sr & STM32H7_SPI_SR_EOT) { -+ if (mask & STM32H7_SPI_SR_TXTF) -+ ifcr |= STM32H7_SPI_SR_TXTF; -+ -+ if (mask & STM32H7_SPI_SR_EOT) { - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32h7_spi_read_rxfifo(spi, true); -- end = true; -+ stm32h7_spi_read_rxfifo(spi); -+ ifcr |= STM32H7_SPI_SR_EOT; -+ if (!spi->cur_usedma || -+ (spi->cur_usedma && (spi->cur_comm == SPI_SIMPLEX_TX || -+ spi->cur_comm == SPI_3WIRE_TX))) -+ end = true; - } - -- if (sr & STM32H7_SPI_SR_TXP) -+ if (mask & STM32H7_SPI_SR_TXP) - if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0))) - stm32h7_spi_write_txfifo(spi); - -- if (sr & STM32H7_SPI_SR_RXP) -+ if (mask & STM32H7_SPI_SR_RXP) - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32h7_spi_read_rxfifo(spi, false); -+ stm32h7_spi_read_rxfifo(spi); - -- writel_relaxed(sr & mask, spi->base + STM32H7_SPI_IFCR); -+ writel_relaxed(ifcr, spi->base + STM32H7_SPI_IFCR); - - spin_unlock_irqrestore(&spi->lock, flags); - -@@ -1029,6 +1000,20 @@ static int stm32_spi_prepare_msg(struct spi_master *master, - spi_dev->mode & SPI_LSB_FIRST, - spi_dev->mode & SPI_CS_HIGH); - -+ /* On STM32H7, messages should not exceed a maximum size setted -+ * afterward via the set_number_of_data function. In order to -+ * ensure that, split large messages into several messages -+ */ -+ if (spi->cfg->set_number_of_data) { -+ int ret; -+ -+ ret = spi_split_transfers_maxsize(master, msg, -+ STM32H7_SPI_TSIZE_MAX, -+ GFP_KERNEL | GFP_DMA); -+ if (ret) -+ return ret; -+ } -+ - spin_lock_irqsave(&spi->lock, flags); - - /* CPOL, CPHA and LSB FIRST bits have common register */ -@@ -1060,42 +1045,17 @@ static void stm32f4_spi_dma_tx_cb(void *data) - } - - /** -- * stm32f4_spi_dma_rx_cb - dma callback -+ * stm32_spi_dma_rx_cb - dma callback - * @data: pointer to the spi controller data structure - * - * DMA callback is called when the transfer is complete for DMA RX channel. - */ --static void stm32f4_spi_dma_rx_cb(void *data) -+static void stm32_spi_dma_rx_cb(void *data) - { - struct stm32_spi *spi = data; - - spi_finalize_current_transfer(spi->master); -- stm32f4_spi_disable(spi); --} -- --/** -- * stm32h7_spi_dma_cb - dma callback -- * @data: pointer to the spi controller data structure -- * -- * DMA callback is called when the transfer is complete or when an error -- * occurs. If the transfer is complete, EOT flag is raised. -- */ --static void stm32h7_spi_dma_cb(void *data) --{ -- struct stm32_spi *spi = data; -- unsigned long flags; -- u32 sr; -- -- spin_lock_irqsave(&spi->lock, flags); -- -- sr = readl_relaxed(spi->base + STM32H7_SPI_SR); -- -- spin_unlock_irqrestore(&spi->lock, flags); -- -- if (!(sr & STM32H7_SPI_SR_EOT)) -- dev_warn(spi->dev, "DMA error (sr=0x%08x)\n", sr); -- -- /* Now wait for EOT, or SUSP or OVR in case of error */ -+ spi->cfg->disable(spi); - } - - /** -@@ -1214,7 +1174,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) - - /* Enable the interrupts relative to the end of transfer */ - ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | -- STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; -+ STM32H7_SPI_IER_OVRIE; - - spin_lock_irqsave(&spi->lock, flags); - -@@ -1261,11 +1221,13 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) - */ - static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) - { -- /* Enable the interrupts relative to the end of transfer */ -- stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | -- STM32H7_SPI_IER_TXTFIE | -- STM32H7_SPI_IER_OVRIE | -- STM32H7_SPI_IER_MODFIE); -+ uint32_t ier = STM32H7_SPI_IER_OVRIE; -+ -+ /* Enable the interrupts */ -+ if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) -+ ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE; -+ -+ stm32_spi_set_bits(spi, STM32H7_SPI_IER, ier); - - stm32_spi_enable(spi); - -@@ -1401,15 +1363,13 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi) - bpw = spi->cur_bpw - 1; - - cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; -- cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & -- STM32H7_SPI_CFG1_DSIZE; -+ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_DSIZE, bpw); - - spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen); - fthlv = spi->cur_fthlv - 1; - - cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; -- cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) & -- STM32H7_SPI_CFG1_FTHLV; -+ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_FTHLV, fthlv); - - writel_relaxed( - (readl_relaxed(spi->base + STM32H7_SPI_CFG1) & -@@ -1427,8 +1387,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) - u32 clrb = 0, setb = 0; - - clrb |= spi->cfg->regs->br.mask; -- setb |= ((u32)mbrdiv << spi->cfg->regs->br.shift) & -- spi->cfg->regs->br.mask; -+ setb |= (mbrdiv << spi->cfg->regs->br.shift) & spi->cfg->regs->br.mask; - - writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) & - ~clrb) | setb, -@@ -1519,8 +1478,7 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) - } - - cfg2_clrb |= STM32H7_SPI_CFG2_COMM; -- cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) & -- STM32H7_SPI_CFG2_COMM; -+ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_COMM, mode); - - writel_relaxed( - (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & -@@ -1542,15 +1500,16 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) - - cfg2_clrb |= STM32H7_SPI_CFG2_MIDI; - if ((len > 1) && (spi->cur_midi > 0)) { -- u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed); -- u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns), -- (u32)STM32H7_SPI_CFG2_MIDI >> -- STM32H7_SPI_CFG2_MIDI_SHIFT); -+ u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed); -+ u32 midi = min_t(u32, -+ DIV_ROUND_UP(spi->cur_midi, sck_period_ns), -+ FIELD_GET(STM32H7_SPI_CFG2_MIDI, -+ STM32H7_SPI_CFG2_MIDI)); -+ - - dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n", - sck_period_ns, midi, midi * sck_period_ns); -- cfg2_setb |= (midi << STM32H7_SPI_CFG2_MIDI_SHIFT) & -- STM32H7_SPI_CFG2_MIDI; -+ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_MIDI, midi); - } - - writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & -@@ -1565,14 +1524,8 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) - */ - static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) - { -- u32 cr2_clrb = 0, cr2_setb = 0; -- -- if (nb_words <= (STM32H7_SPI_CR2_TSIZE >> -- STM32H7_SPI_CR2_TSIZE_SHIFT)) { -- cr2_clrb |= STM32H7_SPI_CR2_TSIZE; -- cr2_setb = nb_words << STM32H7_SPI_CR2_TSIZE_SHIFT; -- writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CR2) & -- ~cr2_clrb) | cr2_setb, -+ if (nb_words <= STM32H7_SPI_TSIZE_MAX) { -+ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, nb_words), - spi->base + STM32H7_SPI_CR2); - } else { - return -EMSGSIZE; -@@ -1673,10 +1626,6 @@ static int stm32_spi_transfer_one(struct spi_master *master, - struct stm32_spi *spi = spi_master_get_devdata(master); - int ret; - -- /* Don't do anything on 0 bytes transfers */ -- if (transfer->len == 0) -- return 0; -- - spi->tx_buf = transfer->tx_buf; - spi->rx_buf = transfer->rx_buf; - spi->tx_len = spi->tx_buf ? transfer->len : 0; -@@ -1790,7 +1739,7 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = { - .set_mode = stm32f4_spi_set_mode, - .transfer_one_dma_start = stm32f4_spi_transfer_one_dma_start, - .dma_tx_cb = stm32f4_spi_dma_tx_cb, -- .dma_rx_cb = stm32f4_spi_dma_rx_cb, -+ .dma_rx_cb = stm32_spi_dma_rx_cb, - .transfer_one_irq = stm32f4_spi_transfer_one_irq, - .irq_handler_event = stm32f4_spi_irq_event, - .irq_handler_thread = stm32f4_spi_irq_thread, -@@ -1810,8 +1759,11 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = { - .set_data_idleness = stm32h7_spi_data_idleness, - .set_number_of_data = stm32h7_spi_number_of_data, - .transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start, -- .dma_rx_cb = stm32h7_spi_dma_cb, -- .dma_tx_cb = stm32h7_spi_dma_cb, -+ .dma_rx_cb = stm32_spi_dma_rx_cb, -+ /* -+ * dma_tx_cb is not necessary since in case of TX, dma is followed by -+ * SPI access hence handling is performed within the SPI interrupt -+ */ - .transfer_one_irq = stm32h7_spi_transfer_one_irq, - .irq_handler_thread = stm32h7_spi_irq_thread, - .baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN, -@@ -1831,6 +1783,7 @@ static int stm32_spi_probe(struct platform_device *pdev) - struct spi_master *master; - struct stm32_spi *spi; - struct resource *res; -+ struct reset_control *rst; - int ret; - - master = devm_spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); -@@ -1890,11 +1843,19 @@ static int stm32_spi_probe(struct platform_device *pdev) - goto err_clk_disable; - } - -- spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); -- if (!IS_ERR(spi->rst)) { -- reset_control_assert(spi->rst); -+ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); -+ if (rst) { -+ if (IS_ERR(rst)) { -+ ret = PTR_ERR(rst); -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "reset get failed: %d\n", -+ ret); -+ goto err_clk_disable; -+ } -+ -+ reset_control_assert(rst); - udelay(2); -- reset_control_deassert(spi->rst); -+ reset_control_deassert(rst); - } - - if (spi->cfg->has_fifo) -@@ -1948,6 +1909,9 @@ static int stm32_spi_probe(struct platform_device *pdev) - if (spi->dma_tx || spi->dma_rx) - master->can_dma = stm32_spi_can_dma; - -+ pm_runtime_set_autosuspend_delay(&pdev->dev, -+ STM32_SPI_AUTOSUSPEND_DELAY); -+ pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_enable(&pdev->dev); -@@ -1959,11 +1923,8 @@ static int stm32_spi_probe(struct platform_device *pdev) - goto err_pm_disable; - } - -- if (!master->cs_gpiods) { -- dev_err(&pdev->dev, "no CS gpios available\n"); -- ret = -EINVAL; -- goto err_pm_disable; -- } -+ pm_runtime_mark_last_busy(&pdev->dev); -+ pm_runtime_put_autosuspend(&pdev->dev); - - dev_info(&pdev->dev, "driver initialized\n"); - -@@ -1973,6 +1934,7 @@ static int stm32_spi_probe(struct platform_device *pdev) - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_dont_use_autosuspend(&pdev->dev); - err_dma_release: - if (spi->dma_tx) - dma_release_channel(spi->dma_tx); -@@ -1997,6 +1959,8 @@ static int stm32_spi_remove(struct platform_device *pdev) - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_dont_use_autosuspend(&pdev->dev); -+ - if (master->dma_tx) - dma_release_channel(master->dma_tx); - if (master->dma_rx) -@@ -2004,14 +1968,12 @@ static int stm32_spi_remove(struct platform_device *pdev) - - clk_disable_unprepare(spi->clk); - -- - pinctrl_pm_select_sleep_state(&pdev->dev); - - return 0; - } - --#ifdef CONFIG_PM --static int stm32_spi_runtime_suspend(struct device *dev) -+static int __maybe_unused stm32_spi_runtime_suspend(struct device *dev) - { - struct spi_master *master = dev_get_drvdata(dev); - struct stm32_spi *spi = spi_master_get_devdata(master); -@@ -2021,7 +1983,7 @@ static int stm32_spi_runtime_suspend(struct device *dev) - return pinctrl_pm_select_sleep_state(dev); - } - --static int stm32_spi_runtime_resume(struct device *dev) -+static int __maybe_unused stm32_spi_runtime_resume(struct device *dev) - { - struct spi_master *master = dev_get_drvdata(dev); - struct stm32_spi *spi = spi_master_get_devdata(master); -@@ -2033,10 +1995,8 @@ static int stm32_spi_runtime_resume(struct device *dev) - - return clk_prepare_enable(spi->clk); - } --#endif - --#ifdef CONFIG_PM_SLEEP --static int stm32_spi_suspend(struct device *dev) -+static int __maybe_unused stm32_spi_suspend(struct device *dev) - { - struct spi_master *master = dev_get_drvdata(dev); - int ret; -@@ -2048,7 +2008,7 @@ static int stm32_spi_suspend(struct device *dev) - return pm_runtime_force_suspend(dev); - } - --static int stm32_spi_resume(struct device *dev) -+static int __maybe_unused stm32_spi_resume(struct device *dev) - { - struct spi_master *master = dev_get_drvdata(dev); - struct stm32_spi *spi = spi_master_get_devdata(master); -@@ -2078,7 +2038,6 @@ static int stm32_spi_resume(struct device *dev) - - return 0; - } --#endif - - static const struct dev_pm_ops stm32_spi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_spi_suspend, stm32_spi_resume) -diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h -index e6fb8ada3..370a25a93 100644 ---- a/include/dt-bindings/pinctrl/stm32-pinfunc.h -+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h -@@ -26,6 +26,7 @@ - #define AF14 0xf - #define AF15 0x10 - #define ANALOG 0x11 -+#define RSVD 0x12 - - /* define Pins number*/ - #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) -diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h -index 7b78c4ba9..74b5db35c 100644 ---- a/include/linux/mtd/spinand.h -+++ b/include/linux/mtd/spinand.h -@@ -170,6 +170,28 @@ struct spinand_op; - struct spinand_device; - - #define SPINAND_MAX_ID_LEN 4 -+/* -+ * For erase, write and read operation, we got the following timings : -+ * tBERS (erase) 1ms to 4ms -+ * tPROG 300us to 400us -+ * tREAD 25us to 100us -+ * In order to minimize latency, the min value is divided by 4 for the -+ * initial delay, and dividing by 20 for the poll delay. -+ * For reset, 5us/10us/500us if the device is respectively -+ * reading/programming/erasing when the RESET occurs. Since we always -+ * issue a RESET when the device is IDLE, 5us is selected for both initial -+ * and poll delay. -+ */ -+#define SPINAND_READ_INITIAL_DELAY_US 6 -+#define SPINAND_READ_POLL_DELAY_US 5 -+#define SPINAND_RESET_INITIAL_DELAY_US 5 -+#define SPINAND_RESET_POLL_DELAY_US 5 -+#define SPINAND_WRITE_INITIAL_DELAY_US 75 -+#define SPINAND_WRITE_POLL_DELAY_US 15 -+#define SPINAND_ERASE_INITIAL_DELAY_US 250 -+#define SPINAND_ERASE_POLL_DELAY_US 50 -+ -+#define SPINAND_WAITRDY_TIMEOUT_MS 400 - - /** - * struct spinand_id - SPI NAND id structure -diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h -index 159463cc6..c24fa5c11 100644 ---- a/include/linux/spi/spi-mem.h -+++ b/include/linux/spi/spi-mem.h -@@ -250,6 +250,9 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem) - * the currently mapped area), and the caller of - * spi_mem_dirmap_write() is responsible for calling it again in - * this case. -+ * @poll_status: poll memory device status until (status & mask) == match or -+ * when the timeout has expired. It fills the data buffer with -+ * the last status value. - * - * This interface should be implemented by SPI controllers providing an - * high-level interface to execute SPI memory operation, which is usually the -@@ -274,6 +277,12 @@ struct spi_controller_mem_ops { - u64 offs, size_t len, void *buf); - ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc, - u64 offs, size_t len, const void *buf); -+ int (*poll_status)(struct spi_mem *mem, -+ const struct spi_mem_op *op, -+ u16 mask, u16 match, -+ unsigned long initial_delay_us, -+ unsigned long polling_rate_us, -+ unsigned long timeout_ms); - }; - - /** -@@ -360,6 +369,13 @@ devm_spi_mem_dirmap_create(struct device *dev, struct spi_mem *mem, - void devm_spi_mem_dirmap_destroy(struct device *dev, - struct spi_mem_dirmap_desc *desc); - -+int spi_mem_poll_status(struct spi_mem *mem, -+ const struct spi_mem_op *op, -+ u16 mask, u16 match, -+ unsigned long initial_delay_us, -+ unsigned long polling_delay_us, -+ u16 timeout_ms); -+ - int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv, - struct module *owner); - --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0017-ARM-5.10.61-stm32mp1-r2-RESET-RTC-WATCHDOG.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0017-ARM-5.10.61-stm32mp1-r2-RESET-RTC-WATCHDOG.patch deleted file mode 100644 index 5ed70b8..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0017-ARM-5.10.61-stm32mp1-r2-RESET-RTC-WATCHDOG.patch +++ /dev/null @@ -1,652 +0,0 @@ -From 32651dddd362b90d443aa3e6f15b699d0e1ad26c Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:50 +0200 -Subject: [PATCH 17/23] ARM 5.10.61-stm32mp1-r2 RESET-RTC-WATCHDOG - ---- - drivers/reset/Kconfig | 6 - - drivers/reset/Makefile | 1 - - drivers/reset/reset-stm32mp1.c | 115 ----------- - drivers/rtc/Kconfig | 1 + - drivers/rtc/rtc-stm32.c | 214 +++++++++++++++----- - drivers/watchdog/stm32_iwdg.c | 13 +- - include/dt-bindings/reset/stm32mp1-resets.h | 15 ++ - include/dt-bindings/rtc/rtc-stm32.h | 13 ++ - 8 files changed, 202 insertions(+), 176 deletions(-) - delete mode 100644 drivers/reset/reset-stm32mp1.c - create mode 100644 include/dt-bindings/rtc/rtc-stm32.h - -diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig -index 147543ad3..6c1409b38 100644 ---- a/drivers/reset/Kconfig -+++ b/drivers/reset/Kconfig -@@ -182,12 +182,6 @@ config RESET_SIMPLE - - Allwinner SoCs - - ZTE's zx2967 family - --config RESET_STM32MP157 -- bool "STM32MP157 Reset Driver" if COMPILE_TEST -- default MACH_STM32MP157 -- help -- This enables the RCC reset controller driver for STM32 MPUs. -- - config RESET_SOCFPGA - bool "SoCFPGA Reset Driver" if COMPILE_TEST && !ARCH_SOCFPGA - default ARCH_SOCFPGA -diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile -index 16947610c..b2c9eff41 100644 ---- a/drivers/reset/Makefile -+++ b/drivers/reset/Makefile -@@ -24,7 +24,6 @@ obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o - obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o - obj-$(CONFIG_RESET_SCMI) += reset-scmi.o - obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o --obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o - obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o - obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o - obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o -diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c -deleted file mode 100644 -index b221a2804..000000000 ---- a/drivers/reset/reset-stm32mp1.c -+++ /dev/null -@@ -1,115 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -- * Author: Gabriel Fernandez for STMicroelectronics. -- */ -- --#include --#include --#include --#include --#include --#include -- --#define CLR_OFFSET 0x4 -- --struct stm32_reset_data { -- struct reset_controller_dev rcdev; -- void __iomem *membase; --}; -- --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); -- void __iomem *addr; -- -- addr = data->membase + (bank * reg_width); -- if (!assert) -- addr += CLR_OFFSET; -- -- writel(BIT(offset), addr); -- -- 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 const struct of_device_id stm32_reset_dt_ids[] = { -- { .compatible = "st,stm32mp1-rcc"}, -- { /* sentinel */ }, --}; -- --static int stm32_reset_probe(struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- struct stm32_reset_data *data; -- void __iomem *membase; -- struct resource *res; -- -- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -- if (!data) -- return -ENOMEM; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- membase = devm_ioremap_resource(dev, res); -- if (IS_ERR(membase)) -- return PTR_ERR(membase); -- -- data->membase = membase; -- data->rcdev.owner = THIS_MODULE; -- data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; -- data->rcdev.ops = &stm32_reset_ops; -- data->rcdev.of_node = dev->of_node; -- -- return devm_reset_controller_register(dev, &data->rcdev); --} -- --static struct platform_driver stm32_reset_driver = { -- .probe = stm32_reset_probe, -- .driver = { -- .name = "stm32mp1-reset", -- .of_match_table = stm32_reset_dt_ids, -- }, --}; -- --builtin_platform_driver(stm32_reset_driver); -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 33e4ecd6c..65619e077 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -1885,6 +1885,7 @@ config RTC_DRV_R7301 - config RTC_DRV_STM32 - tristate "STM32 RTC" - select REGMAP_MMIO -+ depends on COMMON_CLK - depends on ARCH_STM32 || COMPILE_TEST - help - If you say yes here you get support for the STM32 On-Chip -diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c -index d096b58cd..ffab177ed 100644 ---- a/drivers/rtc/rtc-stm32.c -+++ b/drivers/rtc/rtc-stm32.c -@@ -6,6 +6,8 @@ - - #include - #include -+#include -+#include - #include - #include - #include -@@ -15,6 +17,8 @@ - #include - #include - -+#include -+ - #define DRIVER_NAME "stm32_rtc" - - /* STM32_RTC_TR bit fields */ -@@ -39,6 +43,12 @@ - #define STM32_RTC_CR_FMT BIT(6) - #define STM32_RTC_CR_ALRAE BIT(8) - #define STM32_RTC_CR_ALRAIE BIT(12) -+#define STM32_RTC_CR_COSEL BIT(19) -+#define STM32_RTC_CR_OSEL_SHIFT 21 -+#define STM32_RTC_CR_OSEL GENMASK(22, 21) -+#define STM32_RTC_CR_COE BIT(23) -+#define STM32_RTC_CR_TAMPOE BIT(26) -+#define STM32_RTC_CR_OUT2EN BIT(31) - - /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */ - #define STM32_RTC_ISR_ALRAWF BIT(0) -@@ -75,6 +85,11 @@ - /* STM32_RTC_SR/_SCR bit fields */ - #define STM32_RTC_SR_ALRA BIT(0) - -+/* STM32_RTC_CFGR bit fields */ -+#define STM32_RTC_CFGR_OUT2_RMP BIT(0) -+#define STM32_RTC_CFGR_LSCOEN_OUT1 1 -+#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2 -+ - /* STM32_RTC_VERR bit fields */ - #define STM32_RTC_VERR_MINREV_SHIFT 0 - #define STM32_RTC_VERR_MINREV GENMASK(3, 0) -@@ -101,6 +116,7 @@ struct stm32_rtc_registers { - u16 wpr; - u16 sr; - u16 scr; -+ u16 cfgr; - u16 verr; - }; - -@@ -114,7 +130,8 @@ struct stm32_rtc_data { - void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); - bool has_pclk; - bool need_dbp; -- bool has_wakeirq; -+ bool has_lsco; -+ bool need_accuracy; - }; - - struct stm32_rtc { -@@ -127,9 +144,87 @@ struct stm32_rtc { - struct clk *rtc_ck; - const struct stm32_rtc_data *data; - int irq_alarm; -- int wakeirq_alarm; -+ int lsco; -+ struct clk *clk_lsco; - }; - -+/* -+ * ------------------------------------------------------------------------- -+ * | TAMPOE | OSEL[1:0] | COE | OUT2EN | RTC_OUT1 | RTC_OUT2 | -+ * | | | | | | or RTC_OUT2_RMP | -+ * |-------------------------------------------------------------------------| -+ * | 0 | 00 | 0 | 0 or 1 | - | - | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 | 00 | 1 | 0 | CALIB | - | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 or 1 | !=00 | 0 | 0 | TAMPALRM | - | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 | 00 | 1 | 1 | - | CALIB | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 or 1 | !=00 | 0 | 1 | - | TAMPALRM | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 or 1 | !=00 | 1 | 1 | TAMPALRM | CALIB | -+ * ------------------------------------------------------------------------- -+ */ -+static int stm32_rtc_clk_lsco_check_availability(struct stm32_rtc *rtc) -+{ -+ struct stm32_rtc_registers regs = rtc->data->regs; -+ unsigned int cr = readl_relaxed(rtc->base + regs.cr); -+ unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr); -+ unsigned int calib = STM32_RTC_CR_COE; -+ unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL; -+ -+ switch (rtc->lsco) { -+ case RTC_OUT1: -+ if ((!(cr & STM32_RTC_CR_OUT2EN) && -+ ((cr & calib) || cr & tampalrm)) || -+ ((cr & calib) && (cr & tampalrm))) -+ return -EBUSY; -+ break; -+ case RTC_OUT2_RMP: -+ if ((cr & STM32_RTC_CR_OUT2EN) && -+ (cfgr & STM32_RTC_CFGR_OUT2_RMP) && -+ ((cr & calib) || (cr & tampalrm))) -+ return -EBUSY; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (clk_get_rate(rtc->rtc_ck) != 32768) -+ return -ERANGE; -+ -+ return 0; -+} -+ -+static int stm32_rtc_clk_lsco_register(struct platform_device *pdev) -+{ -+ struct stm32_rtc *rtc = platform_get_drvdata(pdev); -+ struct stm32_rtc_registers regs = rtc->data->regs; -+ u8 lscoen; -+ int ret; -+ -+ ret = stm32_rtc_clk_lsco_check_availability(rtc); -+ if (ret) -+ return ret; -+ -+ lscoen = (rtc->lsco == RTC_OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : -+ STM32_RTC_CFGR_LSCOEN_OUT2_RMP; -+ -+ rtc->clk_lsco = clk_register_gate(&pdev->dev, "rtc_lsco", -+ __clk_get_name(rtc->rtc_ck), -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, -+ rtc->base + regs.cfgr, lscoen, -+ 0, NULL); -+ if (IS_ERR(rtc->clk_lsco)) -+ return PTR_ERR(rtc->clk_lsco); -+ -+ of_clk_add_provider(pdev->dev.of_node, -+ of_clk_src_simple_get, rtc->clk_lsco); -+ -+ return 0; -+} -+ - static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) - { - const struct stm32_rtc_registers *regs = &rtc->data->regs; -@@ -160,10 +255,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) - * slowest rtc_ck frequency may be 32kHz and highest should be - * 1MHz, we poll every 10 us with a timeout of 100ms. - */ -- return readl_relaxed_poll_timeout_atomic( -- rtc->base + regs->isr, -- isr, (isr & STM32_RTC_ISR_INITF), -- 10, 100000); -+ return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr, -+ (isr & STM32_RTC_ISR_INITF), -+ 10, 100000); - } - - return 0; -@@ -448,16 +542,16 @@ static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) - * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S - * with a specific case for December... - */ -- if ((((tm->tm_year > cur_year) && -- (tm->tm_mon == 0x1) && (cur_mon == 0x12)) || -- ((tm->tm_year == cur_year) && -- (tm->tm_mon <= cur_mon + 1))) && -- ((tm->tm_mday > cur_day) || -- ((tm->tm_mday == cur_day) && -- ((tm->tm_hour > cur_hour) || -- ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || -- ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && -- (tm->tm_sec >= cur_sec)))))) -+ if (((tm->tm_year > cur_year && -+ tm->tm_mon == 0x1 && cur_mon == 0x12) || -+ (tm->tm_year == cur_year && -+ tm->tm_mon <= cur_mon + 1)) && -+ (tm->tm_mday > cur_day || -+ (tm->tm_mday == cur_day && -+ (tm->tm_hour > cur_hour || -+ (tm->tm_hour == cur_hour && tm->tm_min > cur_min) || -+ (tm->tm_hour == cur_hour && tm->tm_min == cur_min && -+ tm->tm_sec >= cur_sec))))) - return 0; - - return -EINVAL; -@@ -547,7 +641,8 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, - static const struct stm32_rtc_data stm32_rtc_data = { - .has_pclk = false, - .need_dbp = true, -- .has_wakeirq = false, -+ .has_lsco = false, -+ .need_accuracy = false, - .regs = { - .tr = 0x00, - .dr = 0x04, -@@ -558,6 +653,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { - .wpr = 0x24, - .sr = 0x0C, /* set to ISR offset to ease alarm management */ - .scr = UNDEF_REG, -+ .cfgr = UNDEF_REG, - .verr = UNDEF_REG, - }, - .events = { -@@ -569,7 +665,8 @@ static const struct stm32_rtc_data stm32_rtc_data = { - static const struct stm32_rtc_data stm32h7_rtc_data = { - .has_pclk = true, - .need_dbp = true, -- .has_wakeirq = false, -+ .has_lsco = false, -+ .need_accuracy = false, - .regs = { - .tr = 0x00, - .dr = 0x04, -@@ -580,6 +677,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { - .wpr = 0x24, - .sr = 0x0C, /* set to ISR offset to ease alarm management */ - .scr = UNDEF_REG, -+ .cfgr = UNDEF_REG, - .verr = UNDEF_REG, - }, - .events = { -@@ -600,7 +698,8 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, - static const struct stm32_rtc_data stm32mp1_data = { - .has_pclk = true, - .need_dbp = false, -- .has_wakeirq = true, -+ .has_lsco = true, -+ .need_accuracy = true, - .regs = { - .tr = 0x00, - .dr = 0x04, -@@ -611,6 +710,7 @@ static const struct stm32_rtc_data stm32mp1_data = { - .wpr = 0x24, - .sr = 0x50, - .scr = 0x5C, -+ .cfgr = 0x60, - .verr = 0x3F4, - }, - .events = { -@@ -641,18 +741,32 @@ static int stm32_rtc_init(struct platform_device *pdev, - pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; - pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; - -- for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { -- pred_s = (rate / (pred_a + 1)) - 1; -+ if (rate > (pred_a_max + 1) * (pred_s_max + 1)) { -+ dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate); -+ return -EINVAL; -+ } -+ -+ if (rtc->data->need_accuracy) { -+ for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { -+ pred_s = (rate / (pred_a + 1)) - 1; - -- if (((pred_s + 1) * (pred_a + 1)) == rate) -- break; -+ if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate) -+ break; -+ } -+ } else { -+ for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { -+ pred_s = (rate / (pred_a + 1)) - 1; -+ -+ if (((pred_s + 1) * (pred_a + 1)) == rate) -+ break; -+ } - } - - /* - * Can't find a 1Hz, so give priority to RTC power consumption - * by choosing the higher possible value for prediv_a - */ -- if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) { -+ if (pred_s > pred_s_max || pred_a > pred_a_max) { - pred_a = pred_a_max; - pred_s = (rate / (pred_a + 1)) - 1; - -@@ -736,13 +850,15 @@ static int stm32_rtc_probe(struct platform_device *pdev) - } else { - rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(rtc->pclk)) { -- dev_err(&pdev->dev, "no pclk clock"); -+ if (PTR_ERR(rtc->pclk) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "no pclk clock"); - return PTR_ERR(rtc->pclk); - } - rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); - } - if (IS_ERR(rtc->rtc_ck)) { -- dev_err(&pdev->dev, "no rtc_ck clock"); -+ if (PTR_ERR(rtc->rtc_ck) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "no rtc_ck clock"); - return PTR_ERR(rtc->rtc_ck); - } - -@@ -779,19 +895,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) - } - - ret = device_init_wakeup(&pdev->dev, true); -- if (rtc->data->has_wakeirq) { -- rtc->wakeirq_alarm = platform_get_irq(pdev, 1); -- if (rtc->wakeirq_alarm > 0) { -- ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, -- rtc->wakeirq_alarm); -- } else { -- ret = rtc->wakeirq_alarm; -- if (rtc->wakeirq_alarm == -EPROBE_DEFER) -- goto err; -- } -- } - if (ret) -- dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret); -+ goto err; -+ -+ ret = dev_pm_set_wake_irq(&pdev->dev, rtc->irq_alarm); -+ if (ret) -+ goto err; - - platform_set_drvdata(pdev, rtc); - -@@ -814,6 +923,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) - goto err; - } - -+ if (rtc->data->has_lsco) { -+ ret = of_property_read_s32(pdev->dev.of_node, -+ "st,lsco", &rtc->lsco); -+ if (!ret) { -+ ret = stm32_rtc_clk_lsco_register(pdev); -+ if (ret) -+ dev_warn(&pdev->dev, -+ "LSCO clock registration failed: %d\n", -+ ret); -+ } else { -+ rtc->lsco = ret; -+ dev_dbg(&pdev->dev, "No LSCO clock: %d\n", ret); -+ } -+ } -+ - /* - * If INITS flag is reset (calendar year field set to 0x00), calendar - * must be initialized -@@ -852,6 +976,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) - const struct stm32_rtc_registers *regs = &rtc->data->regs; - unsigned int cr; - -+ if (!IS_ERR_OR_NULL(rtc->clk_lsco)) -+ clk_unregister_gate(rtc->clk_lsco); -+ - /* Disable interrupts */ - stm32_rtc_wpr_unlock(rtc); - cr = readl_relaxed(rtc->base + regs->cr); -@@ -881,9 +1008,6 @@ static int stm32_rtc_suspend(struct device *dev) - if (rtc->data->has_pclk) - clk_disable_unprepare(rtc->pclk); - -- if (device_may_wakeup(dev)) -- return enable_irq_wake(rtc->irq_alarm); -- - return 0; - } - -@@ -905,15 +1029,13 @@ static int stm32_rtc_resume(struct device *dev) - return ret; - } - -- if (device_may_wakeup(dev)) -- return disable_irq_wake(rtc->irq_alarm); -- - return ret; - } - #endif - --static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, -- stm32_rtc_suspend, stm32_rtc_resume); -+static const struct dev_pm_ops stm32_rtc_pm_ops = { -+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) -+}; - - static struct platform_driver stm32_rtc_driver = { - .probe = stm32_rtc_probe, -diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c -index 25188d6bb..a3436c296 100644 ---- a/drivers/watchdog/stm32_iwdg.c -+++ b/drivers/watchdog/stm32_iwdg.c -@@ -162,18 +162,15 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, - u32 ret; - - wdt->clk_lsi = devm_clk_get(dev, "lsi"); -- if (IS_ERR(wdt->clk_lsi)) { -- dev_err(dev, "Unable to get lsi clock\n"); -- return PTR_ERR(wdt->clk_lsi); -- } -+ if (IS_ERR(wdt->clk_lsi)) -+ return dev_err_probe(dev, PTR_ERR(wdt->clk_lsi), "Unable to get lsi clock\n"); - - /* optional peripheral clock */ - if (wdt->data->has_pclk) { - wdt->clk_pclk = devm_clk_get(dev, "pclk"); -- if (IS_ERR(wdt->clk_pclk)) { -- dev_err(dev, "Unable to get pclk clock\n"); -- return PTR_ERR(wdt->clk_pclk); -- } -+ if (IS_ERR(wdt->clk_pclk)) -+ return dev_err_probe(dev, PTR_ERR(wdt->clk_pclk), -+ "Unable to get pclk clock\n"); - - ret = clk_prepare_enable(wdt->clk_pclk); - if (ret) { -diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h -index f0c3aaef6..f3a0ed317 100644 ---- a/include/dt-bindings/reset/stm32mp1-resets.h -+++ b/include/dt-bindings/reset/stm32mp1-resets.h -@@ -7,6 +7,7 @@ - #ifndef _DT_BINDINGS_STM32MP1_RESET_H_ - #define _DT_BINDINGS_STM32MP1_RESET_H_ - -+#define MCU_HOLD_BOOT_R 2144 - #define LTDC_R 3072 - #define DSI_R 3076 - #define DDRPERFM_R 3080 -@@ -105,4 +106,18 @@ - #define GPIOJ_R 19785 - #define GPIOK_R 19786 - -+/* SCMI reset domain identifiers */ -+#define RST_SCMI0_SPI6 0 -+#define RST_SCMI0_I2C4 1 -+#define RST_SCMI0_I2C6 2 -+#define RST_SCMI0_USART1 3 -+#define RST_SCMI0_STGEN 4 -+#define RST_SCMI0_GPIOZ 5 -+#define RST_SCMI0_CRYP1 6 -+#define RST_SCMI0_HASH1 7 -+#define RST_SCMI0_RNG1 8 -+#define RST_SCMI0_MDMA 9 -+#define RST_SCMI0_MCU 10 -+#define RST_SCMI0_MCU_HOLD_BOOT 11 -+ - #endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ -diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h -new file mode 100644 -index 000000000..4373c4dea ---- /dev/null -+++ b/include/dt-bindings/rtc/rtc-stm32.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This header provides constants for STM32_RTC bindings. -+ */ -+ -+#ifndef _DT_BINDINGS_RTC_RTC_STM32_H -+#define _DT_BINDINGS_RTC_RTC_STM32_H -+ -+#define RTC_OUT1 0 -+#define RTC_OUT2 1 -+#define RTC_OUT2_RMP 2 -+ -+#endif --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0018-ARM-5.10.61-stm32mp1-r2-SCMI.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0018-ARM-5.10.61-stm32mp1-r2-SCMI.patch deleted file mode 100644 index 2b2aab3..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0018-ARM-5.10.61-stm32mp1-r2-SCMI.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 03fe6061e18768eee7b247999cecaad2280098cf Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:51 +0200 -Subject: [PATCH 18/23] ARM 5.10.61-stm32mp1-r2 SCMI - ---- - drivers/firmware/arm_scmi/base.c | 2 +- - drivers/firmware/arm_scmi/bus.c | 9 --------- - drivers/firmware/arm_scmi/clock.c | 2 +- - drivers/firmware/arm_scmi/common.h | 2 ++ - drivers/firmware/arm_scmi/driver.c | 10 ++++++++++ - drivers/firmware/arm_scmi/perf.c | 2 +- - drivers/firmware/arm_scmi/sensors.c | 2 +- - 7 files changed, 16 insertions(+), 13 deletions(-) - -diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c -index 017e5d8bd..a70b10eba 100644 ---- a/drivers/firmware/arm_scmi/base.c -+++ b/drivers/firmware/arm_scmi/base.c -@@ -183,7 +183,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, - /* Set the number of protocols to be skipped/already read */ - *num_skip = cpu_to_le32(tot_num_ret); - -- ret = scmi_do_xfer(handle, t); -+ ret = scmi_do_xfer_again(handle, t); - if (ret) - break; - -diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c -index def8a84d1..33d1a6c79 100644 ---- a/drivers/firmware/arm_scmi/bus.c -+++ b/drivers/firmware/arm_scmi/bus.c -@@ -60,11 +60,6 @@ static int scmi_protocol_init(int protocol_id, struct scmi_handle *handle) - return fn(handle); - } - --static int scmi_protocol_dummy_init(struct scmi_handle *handle) --{ -- return 0; --} -- - static int scmi_dev_probe(struct device *dev) - { - struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver); -@@ -83,10 +78,6 @@ static int scmi_dev_probe(struct device *dev) - if (ret) - return ret; - -- /* Skip protocol initialisation for additional devices */ -- idr_replace(&scmi_protocols, &scmi_protocol_dummy_init, -- scmi_dev->protocol_id); -- - return scmi_drv->probe(scmi_dev); - } - -diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c -index 4645677d8..c348a6f2e 100644 ---- a/drivers/firmware/arm_scmi/clock.c -+++ b/drivers/firmware/arm_scmi/clock.c -@@ -161,7 +161,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, - /* Set the number of rates to be skipped/already read */ - clk_desc->rate_index = cpu_to_le32(tot_rate_cnt); - -- ret = scmi_do_xfer(handle, t); -+ ret = scmi_do_xfer_again(handle, t); - if (ret) - goto err; - -diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h -index 34b7ae798..9fa5c0022 100644 ---- a/drivers/firmware/arm_scmi/common.h -+++ b/drivers/firmware/arm_scmi/common.h -@@ -143,6 +143,8 @@ struct scmi_xfer { - - void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer); - int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer); -+int scmi_do_xfer_again(const struct scmi_handle *handle, -+ struct scmi_xfer *xfer); - int scmi_do_xfer_with_response(const struct scmi_handle *h, - struct scmi_xfer *xfer); - int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id, -diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c -index 763223248..2b3ce604f 100644 ---- a/drivers/firmware/arm_scmi/driver.c -+++ b/drivers/firmware/arm_scmi/driver.c -@@ -415,6 +415,16 @@ void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle, - xfer->rx.len = info->desc->max_msg_size; - } - -+int scmi_do_xfer_again(const struct scmi_handle *handle, struct scmi_xfer *xfer) -+{ -+ struct scmi_info *info = handle_to_scmi_info(handle); -+ -+ xfer->rx.len = info->desc->max_msg_size; -+ xfer->hdr.poll_completion = false; -+ -+ return scmi_do_xfer(handle, xfer); -+} -+ - #define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) - - /** -diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c -index 82fb3babf..7bea0f646 100644 ---- a/drivers/firmware/arm_scmi/perf.c -+++ b/drivers/firmware/arm_scmi/perf.c -@@ -281,7 +281,7 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, - /* Set the number of OPPs to be skipped/already read */ - dom_info->level_index = cpu_to_le32(tot_opp_cnt); - -- ret = scmi_do_xfer(handle, t); -+ ret = scmi_do_xfer_again(handle, t); - if (ret) - break; - -diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c -index b4232d611..6dae881be 100644 ---- a/drivers/firmware/arm_scmi/sensors.c -+++ b/drivers/firmware/arm_scmi/sensors.c -@@ -134,7 +134,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, - /* Set the number of sensors to be skipped/already read */ - put_unaligned_le32(desc_index, t->tx.buf); - -- ret = scmi_do_xfer(handle, t); -+ ret = scmi_do_xfer_again(handle, t); - if (ret) - break; - --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0019-ARM-5.10.61-stm32mp1-r2-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0019-ARM-5.10.61-stm32mp1-r2-SOUND.patch deleted file mode 100644 index a5b6517..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0019-ARM-5.10.61-stm32mp1-r2-SOUND.patch +++ /dev/null @@ -1,717 +0,0 @@ -From e8a701ceba6fdf12989b38212c510bfdfea5c830 Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:51 +0200 -Subject: [PATCH 19/23] ARM 5.10.61-stm32mp1-r2 SOUND - ---- - sound/soc/codecs/Kconfig | 2 +- - sound/soc/codecs/wm8994.c | 81 ++++++++- - sound/soc/stm/stm32_adfsdm.c | 11 +- - sound/soc/stm/stm32_i2s.c | 316 +++++++++++++++++++++++++++++----- - sound/soc/stm/stm32_sai_sub.c | 4 +- - sound/soc/stm/stm32_spdifrx.c | 4 + - 6 files changed, 361 insertions(+), 57 deletions(-) - -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 34c6dd04b..3afc5d1f0 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -1642,7 +1642,7 @@ config SND_SOC_WM8993 - depends on I2C - - config SND_SOC_WM8994 -- tristate -+ tristate "Wolfson Microelectronics WM8994 codec" - - config SND_SOC_WM8995 - tristate -diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c -index f57884113..6d30b438b 100644 ---- a/sound/soc/codecs/wm8994.c -+++ b/sound/soc/codecs/wm8994.c -@@ -7,6 +7,7 @@ - * Author: Mark Brown - */ - -+#include - #include - #include - #include -@@ -838,6 +839,37 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, - return 0; - } - -+static int mclk_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); -+ struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(comp); -+ int ret, mclk_id = 0; -+ -+ if (!strncmp(w->name, "MCLK2", 5)) -+ mclk_id = 1; -+ -+ switch (event) { -+ case SND_SOC_DAPM_PRE_PMU: -+ dev_dbg(comp->dev, "Enable master clock %s\n", -+ mclk_id ? "MCLK2" : "MCLK1"); -+ -+ ret = clk_prepare_enable(wm8994->mclk[mclk_id].clk); -+ if (ret < 0) { -+ dev_err(comp->dev, "Failed to enable clock: %d\n", ret); -+ return ret; -+ } -+ break; -+ case SND_SOC_DAPM_POST_PMD: -+ dev_dbg(comp->dev, "Disable master clock %s\n", -+ mclk_id ? "MCLK2" : "MCLK1"); -+ clk_disable_unprepare(wm8994->mclk[mclk_id].clk); -+ break; -+ } -+ -+ return 0; -+} -+ - static void vmid_reference(struct snd_soc_component *component) - { - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); -@@ -1225,7 +1257,6 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, - else - adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA; - -- - val = snd_soc_component_read(component, WM8994_AIF2_CONTROL_2); - if ((val & WM8994_AIF2DACL_SRC) && - (val & WM8994_AIF2DACR_SRC)) -@@ -1847,6 +1878,16 @@ static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = { - SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux), - }; - -+static const struct snd_soc_dapm_widget wm8994_mclk1_dapm_widgets[] = { -+SND_SOC_DAPM_SUPPLY("MCLK1", SND_SOC_NOPM, 0, 0, mclk_event, -+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -+}; -+ -+static const struct snd_soc_dapm_widget wm8994_mclk2_dapm_widgets[] = { -+SND_SOC_DAPM_SUPPLY("MCLK2", SND_SOC_NOPM, 0, 0, mclk_event, -+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -+}; -+ - static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0), - SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux), -@@ -2071,10 +2112,10 @@ static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { - }; - - static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { -- { "AIF1DACDAT", NULL, "AIF2DACDAT" }, -- { "AIF2DACDAT", NULL, "AIF1DACDAT" }, -- { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, -- { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, -+// { "AIF1DACDAT", NULL, "AIF2DACDAT" }, -+// { "AIF2DACDAT", NULL, "AIF1DACDAT" }, -+// { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, -+// { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, - { "MICBIAS1", NULL, "CLK_SYS" }, - { "MICBIAS1", NULL, "MICBIAS Supply" }, - { "MICBIAS2", NULL, "CLK_SYS" }, -@@ -2506,11 +2547,24 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, - { - struct snd_soc_component *component = dai->component; - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); -- int ret, i; -+ int i, ret; - -+ /* -+ * Simple card provides unconditionnaly clock_id = 0. -+ * Workaround to select master clock for aif1/2 -+ */ - switch (dai->id) { - case 1: -+ if (wm8994->mclk[0].clk) -+ clk_id = WM8994_SYSCLK_MCLK1; -+ else if (wm8994->mclk[1].clk) -+ clk_id = WM8994_SYSCLK_MCLK2; -+ break; - case 2: -+ if (wm8994->mclk[1].clk) -+ clk_id = WM8994_SYSCLK_MCLK2; -+ else if (wm8994->mclk[0].clk) -+ clk_id = WM8994_SYSCLK_MCLK1; - break; - - default: -@@ -2522,6 +2576,10 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, - case WM8994_SYSCLK_MCLK1: - wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1; - -+ /* Avoid busy error on exclusive rate change request */ -+ if (!freq) -+ break; -+ - ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq); - if (ret < 0) - return ret; -@@ -2535,6 +2593,9 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, - /* TODO: Set GPIO AF */ - wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2; - -+ if (!freq) -+ break; -+ - ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq); - if (ret < 0) - return ret; -@@ -4438,6 +4499,14 @@ static int wm8994_component_probe(struct snd_soc_component *component) - ARRAY_SIZE(wm8994_snd_controls)); - snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, - ARRAY_SIZE(wm8994_specific_dapm_widgets)); -+ if (wm8994->mclk[0].clk) -+ snd_soc_dapm_new_controls(dapm, wm8994_mclk1_dapm_widgets, -+ ARRAY_SIZE(wm8994_mclk1_dapm_widgets)); -+ -+ if (wm8994->mclk[1].clk) -+ snd_soc_dapm_new_controls(dapm, wm8994_mclk2_dapm_widgets, -+ ARRAY_SIZE(wm8994_mclk2_dapm_widgets)); -+ - if (control->revision < 4) { - snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, - ARRAY_SIZE(wm8994_lateclk_revd_widgets)); -diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c -index c4031988f..a67cadc03 100644 ---- a/sound/soc/stm/stm32_adfsdm.c -+++ b/sound/soc/stm/stm32_adfsdm.c -@@ -12,7 +12,7 @@ - #include - #include - #include -- -+#include - #include - #include - #include -@@ -353,15 +353,20 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) - #endif - - ret = snd_soc_add_component(component, NULL, 0); -- if (ret < 0) -+ if (ret < 0) { - dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", - __func__); -+ return ret; -+ } - -- return ret; -+ pm_runtime_enable(&pdev->dev); -+ -+ return 0; - } - - static int stm32_adfsdm_remove(struct platform_device *pdev) - { -+ pm_runtime_disable(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - - return 0; -diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c -index 7c4d63c33..f324ce974 100644 ---- a/sound/soc/stm/stm32_i2s.c -+++ b/sound/soc/stm/stm32_i2s.c -@@ -8,10 +8,12 @@ - - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -196,6 +198,9 @@ enum i2s_datlen { - #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER) - #define STM32_I2S_IS_SLAVE(x) ((x)->ms_flg == I2S_MS_SLAVE) - -+#define STM32_I2S_NAME_LEN 32 -+#define STM32_I2S_RATE_11K 11025 -+ - /** - * struct stm32_i2s_data - private data of I2S - * @regmap_conf: I2S register map configuration pointer -@@ -206,6 +211,7 @@ enum i2s_datlen { - * @dma_data_rx: dma configuration data for tx channel - * @substream: PCM substream data pointer - * @i2sclk: kernel clock feeding the I2S clock generator -+ * @i2smclk: master clock from I2S mclk provider - * @pclk: peripheral clock driving bus interface - * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz - * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz -@@ -215,6 +221,9 @@ enum i2s_datlen { - * @irq_lock: prevent race condition with IRQ - * @mclk_rate: master clock frequency (Hz) - * @fmt: DAI protocol -+ * @divider: prescaler division ratio -+ * @div: prescaler div field -+ * @odd: prescaler odd field - * @refcount: keep count of opened streams on I2S - * @ms_flg: master mode flag. - */ -@@ -227,6 +236,7 @@ struct stm32_i2s_data { - struct snd_dmaengine_dai_dma_data dma_data_rx; - struct snd_pcm_substream *substream; - struct clk *i2sclk; -+ struct clk *i2smclk; - struct clk *pclk; - struct clk *x8kclk; - struct clk *x11kclk; -@@ -236,10 +246,210 @@ struct stm32_i2s_data { - spinlock_t irq_lock; /* used to prevent race condition with IRQ */ - unsigned int mclk_rate; - unsigned int fmt; -+ unsigned int divider; -+ unsigned int div; -+ bool odd; - int refcount; - int ms_flg; - }; - -+struct stm32_i2smclk_data { -+ struct clk_hw hw; -+ unsigned long freq; -+ struct stm32_i2s_data *i2s_data; -+}; -+ -+#define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw) -+ -+static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s, -+ unsigned long input_rate, -+ unsigned long output_rate) -+{ -+ unsigned int ratio, div, divider = 1; -+ bool odd; -+ -+ ratio = DIV_ROUND_CLOSEST(input_rate, output_rate); -+ -+ /* Check the parity of the divider */ -+ odd = ratio & 0x1; -+ -+ /* Compute the div prescaler */ -+ div = ratio >> 1; -+ -+ /* If div is 0 actual divider is 1 */ -+ if (div) { -+ divider = ((2 * div) + odd); -+ dev_dbg(&i2s->pdev->dev, "Divider: 2*%d(div)+%d(odd) = %d\n", -+ div, odd, divider); -+ } -+ -+ /* Division by three is not allowed by I2S prescaler */ -+ if ((div == 1 && odd) || div > I2S_CGFR_I2SDIV_MAX) { -+ dev_err(&i2s->pdev->dev, "Wrong divider setting\n"); -+ return -EINVAL; -+ } -+ -+ if (input_rate % divider) -+ dev_dbg(&i2s->pdev->dev, -+ "Rate not accurate. requested (%ld), actual (%ld)\n", -+ output_rate, input_rate / divider); -+ -+ i2s->div = div; -+ i2s->odd = odd; -+ i2s->divider = divider; -+ -+ return 0; -+} -+ -+static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s) -+{ -+ u32 cgfr, cgfr_mask; -+ -+ cgfr = I2S_CGFR_I2SDIV_SET(i2s->div) | (i2s->odd << I2S_CGFR_ODD_SHIFT); -+ cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD; -+ -+ return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, -+ cgfr_mask, cgfr); -+} -+ -+static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s, -+ unsigned int rate) -+{ -+ struct platform_device *pdev = i2s->pdev; -+ struct clk *parent_clk; -+ int ret; -+ -+ if (!(rate % STM32_I2S_RATE_11K)) -+ parent_clk = i2s->x11kclk; -+ else -+ parent_clk = i2s->x8kclk; -+ -+ ret = clk_set_parent(i2s->i2sclk, parent_clk); -+ if (ret) -+ dev_err(&pdev->dev, -+ "Error %d setting i2sclk parent clock\n", ret); -+ -+ return ret; -+} -+ -+static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); -+ struct stm32_i2s_data *i2s = mclk->i2s_data; -+ int ret; -+ -+ ret = stm32_i2s_calc_clk_div(i2s, *prate, rate); -+ if (ret) -+ return ret; -+ -+ mclk->freq = *prate / i2s->divider; -+ -+ return mclk->freq; -+} -+ -+static unsigned long stm32_i2smclk_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); -+ -+ return mclk->freq; -+} -+ -+static int stm32_i2smclk_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); -+ struct stm32_i2s_data *i2s = mclk->i2s_data; -+ int ret; -+ -+ ret = stm32_i2s_calc_clk_div(i2s, parent_rate, rate); -+ if (ret) -+ return ret; -+ -+ ret = stm32_i2s_set_clk_div(i2s); -+ if (ret) -+ return ret; -+ -+ mclk->freq = rate; -+ -+ return 0; -+} -+ -+static int stm32_i2smclk_enable(struct clk_hw *hw) -+{ -+ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); -+ struct stm32_i2s_data *i2s = mclk->i2s_data; -+ -+ dev_dbg(&i2s->pdev->dev, "Enable master clock\n"); -+ -+ return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, -+ I2S_CGFR_MCKOE, I2S_CGFR_MCKOE); -+} -+ -+static void stm32_i2smclk_disable(struct clk_hw *hw) -+{ -+ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); -+ struct stm32_i2s_data *i2s = mclk->i2s_data; -+ -+ dev_dbg(&i2s->pdev->dev, "Disable master clock\n"); -+ -+ regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, 0); -+} -+ -+static const struct clk_ops mclk_ops = { -+ .enable = stm32_i2smclk_enable, -+ .disable = stm32_i2smclk_disable, -+ .recalc_rate = stm32_i2smclk_recalc_rate, -+ .round_rate = stm32_i2smclk_round_rate, -+ .set_rate = stm32_i2smclk_set_rate, -+}; -+ -+static int stm32_i2s_add_mclk_provider(struct stm32_i2s_data *i2s) -+{ -+ struct clk_hw *hw; -+ struct stm32_i2smclk_data *mclk; -+ struct device *dev = &i2s->pdev->dev; -+ const char *pname = __clk_get_name(i2s->i2sclk); -+ char *mclk_name, *p, *s = (char *)pname; -+ int ret, i = 0; -+ -+ mclk = devm_kzalloc(dev, sizeof(*mclk), GFP_KERNEL); -+ if (!mclk) -+ return -ENOMEM; -+ -+ mclk_name = devm_kcalloc(dev, sizeof(char), -+ STM32_I2S_NAME_LEN, GFP_KERNEL); -+ if (!mclk_name) -+ return -ENOMEM; -+ -+ /* -+ * Forge mclk clock name from parent clock name and suffix. -+ * String after "_" char is stripped in parent name. -+ */ -+ p = mclk_name; -+ while (*s && *s != '_' && (i < (STM32_I2S_NAME_LEN - 7))) { -+ *p++ = *s++; -+ i++; -+ } -+ strcat(p, "_mclk"); -+ -+ mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0); -+ mclk->i2s_data = i2s; -+ hw = &mclk->hw; -+ -+ dev_dbg(dev, "Register master clock %s\n", mclk_name); -+ ret = devm_clk_hw_register(&i2s->pdev->dev, hw); -+ if (ret) { -+ dev_err(dev, "mclk register fails with error %d\n", ret); -+ return ret; -+ } -+ i2s->i2smclk = hw->clk; -+ -+ /* register mclk provider */ -+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); -+} -+ - static irqreturn_t stm32_i2s_isr(int irq, void *devid) - { - struct stm32_i2s_data *i2s = (struct stm32_i2s_data *)devid; -@@ -405,18 +615,46 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) - { - struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); -+ int ret = 0; - -- dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz\n", freq); -+ dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz. mode: %s, dir: %s\n", -+ freq, STM32_I2S_IS_MASTER(i2s) ? "master" : "slave", -+ dir ? "output" : "input"); - -- if ((dir == SND_SOC_CLOCK_OUT) && STM32_I2S_IS_MASTER(i2s)) { -- i2s->mclk_rate = freq; -+ /* MCLK generation is available only in master mode */ -+ if (dir == SND_SOC_CLOCK_OUT && STM32_I2S_IS_MASTER(i2s)) { -+ if (!i2s->i2smclk) { -+ dev_dbg(cpu_dai->dev, "No MCLK registered\n"); -+ return 0; -+ } - -- /* Enable master clock if master mode and mclk-fs are set */ -- return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, -- I2S_CGFR_MCKOE, I2S_CGFR_MCKOE); -+ /* Assume shutdown if requested frequency is 0Hz */ -+ if (!freq) { -+ /* Release mclk rate only if rate was actually set */ -+ if (i2s->mclk_rate) { -+ clk_rate_exclusive_put(i2s->i2smclk); -+ i2s->mclk_rate = 0; -+ } -+ return regmap_update_bits(i2s->regmap, -+ STM32_I2S_CGFR_REG, -+ I2S_CGFR_MCKOE, 0); -+ } -+ /* If master clock is used, set parent clock now */ -+ ret = stm32_i2s_set_parent_clock(i2s, freq); -+ if (ret) -+ return ret; -+ ret = clk_set_rate_exclusive(i2s->i2smclk, freq); -+ if (ret) { -+ dev_err(cpu_dai->dev, "Could not set mclk rate\n"); -+ return ret; -+ } -+ ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, -+ I2S_CGFR_MCKOE, I2S_CGFR_MCKOE); -+ if (!ret) -+ i2s->mclk_rate = freq; - } - -- return 0; -+ return ret; - } - - static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, -@@ -424,11 +662,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, - { - struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); - unsigned long i2s_clock_rate; -- unsigned int tmp, div, real_div, nb_bits, frame_len; -+ unsigned int nb_bits, frame_len; - unsigned int rate = params_rate(params); -+ u32 cgfr; - int ret; -- u32 cgfr, cgfr_mask; -- bool odd; - - if (!(rate % 11025)) - clk_set_parent(i2s->i2sclk, i2s->x11kclk); -@@ -449,7 +686,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, - * dsp mode : div = i2s_clk / (nb_bits x ws) - */ - if (i2s->mclk_rate) { -- tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, i2s->mclk_rate); -+ ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate, -+ i2s->mclk_rate); -+ if (ret) -+ return ret; - } else { - frame_len = 32; - if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == -@@ -461,35 +701,14 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, - if (ret < 0) - return ret; - -- nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1); -- tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, (nb_bits * rate)); -- } -- -- /* Check the parity of the divider */ -- odd = tmp & 0x1; -- -- /* Compute the div prescaler */ -- div = tmp >> 1; -- -- cgfr = I2S_CGFR_I2SDIV_SET(div) | (odd << I2S_CGFR_ODD_SHIFT); -- cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD; -- -- real_div = ((2 * div) + odd); -- dev_dbg(cpu_dai->dev, "I2S clk: %ld, SCLK: %d\n", -- i2s_clock_rate, rate); -- dev_dbg(cpu_dai->dev, "Divider: 2*%d(div)+%d(odd) = %d\n", -- div, odd, real_div); -- -- if (((div == 1) && odd) || (div > I2S_CGFR_I2SDIV_MAX)) { -- dev_err(cpu_dai->dev, "Wrong divider setting\n"); -- return -EINVAL; -+ nb_bits = frame_len * (FIELD_GET(I2S_CGFR_CHLEN, cgfr) + 1); -+ ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate, -+ (nb_bits * rate)); -+ if (ret) -+ return ret; - } - -- if (!div && !odd) -- dev_warn(cpu_dai->dev, "real divider forced to 1\n"); -- -- ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, -- cgfr_mask, cgfr); -+ ret = stm32_i2s_set_clk_div(i2s); - if (ret < 0) - return ret; - -@@ -694,9 +913,6 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, - struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); - unsigned long flags; - -- regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, -- I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE); -- - clk_disable_unprepare(i2s->i2sclk); - - spin_lock_irqsave(&i2s->irq_lock, flags); -@@ -861,6 +1077,13 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, - return PTR_ERR(i2s->x11kclk); - } - -+ /* Register mclk provider if requested */ -+ if (of_find_property(np, "#clock-cells", NULL)) { -+ ret = stm32_i2s_add_mclk_provider(i2s); -+ if (ret < 0) -+ return ret; -+ } -+ - /* Get irqs */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) -@@ -892,6 +1115,7 @@ static int stm32_i2s_remove(struct platform_device *pdev) - { - snd_dmaengine_pcm_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); - - return 0; - } -@@ -906,16 +1130,16 @@ static int stm32_i2s_probe(struct platform_device *pdev) - if (!i2s) - return -ENOMEM; - -- ret = stm32_i2s_parse_dt(pdev, i2s); -- if (ret) -- return ret; -- - i2s->pdev = pdev; - i2s->ms_flg = I2S_MS_NOT_SET; - spin_lock_init(&i2s->lock_fd); - spin_lock_init(&i2s->irq_lock); - platform_set_drvdata(pdev, i2s); - -+ ret = stm32_i2s_parse_dt(pdev, i2s); -+ if (ret) -+ return ret; -+ - ret = stm32_i2s_dais_init(pdev, i2s); - if (ret) - return ret; -@@ -974,6 +1198,8 @@ static int stm32_i2s_probe(struct platform_device *pdev) - FIELD_GET(I2S_VERR_MIN_MASK, val)); - } - -+ pm_runtime_enable(&pdev->dev); -+ - return ret; - - error: -diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c -index 3aa1cf262..780f48138 100644 ---- a/sound/soc/stm/stm32_sai_sub.c -+++ b/sound/soc/stm/stm32_sai_sub.c -@@ -1294,7 +1294,7 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = { - .id = 1, /* avoid call to fmt_single_name() */ - .playback = { - .channels_min = 1, -- .channels_max = 2, -+ .channels_max = 16, - .rate_min = 8000, - .rate_max = 192000, - .rates = SNDRV_PCM_RATE_CONTINUOUS, -@@ -1312,7 +1312,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = { - .id = 1, /* avoid call to fmt_single_name() */ - .capture = { - .channels_min = 1, -- .channels_max = 2, -+ .channels_max = 16, - .rate_min = 8000, - .rate_max = 192000, - .rates = SNDRV_PCM_RATE_CONTINUOUS, -diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c -index 1bfa3b2ba..aa38f9df9 100644 ---- a/sound/soc/stm/stm32_spdifrx.c -+++ b/sound/soc/stm/stm32_spdifrx.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -956,6 +957,7 @@ static int stm32_spdifrx_remove(struct platform_device *pdev) - - snd_dmaengine_pcm_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); - - return 0; - } -@@ -1046,6 +1048,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) - FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver)); - } - -+ pm_runtime_enable(&pdev->dev); -+ - return ret; - - error: --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0020-ARM-5.10.61-stm32mp1-r2-MISC.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0020-ARM-5.10.61-stm32mp1-r2-MISC.patch deleted file mode 100644 index 41b91ce..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0020-ARM-5.10.61-stm32mp1-r2-MISC.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 49a7d9003e2c89aa252d3ccccb16d4ab22a90ef6 Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:52 +0200 -Subject: [PATCH 20/23] ARM 5.10.61-stm32mp1-r2 MISC - ---- - drivers/opp/core.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/drivers/opp/core.c b/drivers/opp/core.c -index 903b465c8..dbcce5de9 100644 ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -1608,9 +1608,13 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, - struct opp_table *opp_table; - - opp_table = dev_pm_opp_get_opp_table(dev); -- if (IS_ERR(opp_table)) -+ -+ if (PTR_ERR(opp_table) == -EPROBE_DEFER) - return opp_table; - -+ if (!opp_table) -+ return ERR_PTR(-ENOMEM); -+ - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); - --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0021-ARM-5.10.61-stm32mp1-r2-CPUIDLE-POWER.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0021-ARM-5.10.61-stm32mp1-r2-CPUIDLE-POWER.patch deleted file mode 100644 index a4fd750..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0021-ARM-5.10.61-stm32mp1-r2-CPUIDLE-POWER.patch +++ /dev/null @@ -1,701 +0,0 @@ -From 5707d44444b4bd31e2690d5d7e72f83c6e28b48b Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Fri, 15 Oct 2021 08:44:32 +0200 -Subject: [PATCH 21/23] ARM 5.10.61-stm32mp1-r2 CPUIDLE-POWER - ---- - drivers/base/power/domain.c | 4 +- - drivers/base/power/main.c | 4 +- - drivers/cpuidle/Kconfig.arm | 8 + - drivers/cpuidle/Makefile | 1 + - drivers/cpuidle/cpuidle-stm32.c | 276 ++++++++++++++++++++++++++++++++ - drivers/nvmem/stm32-romem.c | 165 +++++++++++++++++-- - include/linux/pm_wakeup.h | 10 ++ - kernel/power/suspend.c | 1 - - 8 files changed, 453 insertions(+), 16 deletions(-) - create mode 100644 drivers/cpuidle/cpuidle-stm32.c - -diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c -index 743268996..e0894ef84 100644 ---- a/drivers/base/power/domain.c -+++ b/drivers/base/power/domain.c -@@ -1142,7 +1142,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff) - if (ret) - return ret; - -- if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) -+ if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd)) - return 0; - - if (genpd->dev_ops.stop && genpd->dev_ops.start && -@@ -1196,7 +1196,7 @@ static int genpd_resume_noirq(struct device *dev) - if (IS_ERR(genpd)) - return -EINVAL; - -- if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) -+ if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd)) - return pm_generic_resume_noirq(dev); - - genpd_lock(genpd); -diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c -index c7ac49042..921c5b2ec 100644 ---- a/drivers/base/power/main.c -+++ b/drivers/base/power/main.c -@@ -1359,7 +1359,7 @@ static void dpm_propagate_wakeup_to_parent(struct device *dev) - - spin_lock_irq(&parent->power.lock); - -- if (dev->power.wakeup_path && !parent->power.ignore_children) -+ if (device_wakeup_path(dev) && !parent->power.ignore_children) - parent->power.wakeup_path = true; - - spin_unlock_irq(&parent->power.lock); -@@ -1627,7 +1627,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) - goto Complete; - - /* Avoid direct_complete to let wakeup_path propagate. */ -- if (device_may_wakeup(dev) || dev->power.wakeup_path) -+ if (device_may_wakeup(dev) || device_wakeup_path(dev)) - dev->power.direct_complete = false; - - if (dev->power.direct_complete) { -diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm -index 334f83e56..4de5db493 100644 ---- a/drivers/cpuidle/Kconfig.arm -+++ b/drivers/cpuidle/Kconfig.arm -@@ -91,6 +91,14 @@ config ARM_EXYNOS_CPUIDLE - help - Select this to enable cpuidle for Exynos processors. - -+config ARM_STM32_CPUIDLE -+ bool "Cpu Idle Driver for the STM32 processors" -+ depends on MACH_STM32MP157 -+ select DT_IDLE_STATES -+ select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP -+ help -+ Select this to enable cpuidle for STM32 processors. -+ - config ARM_MVEBU_V7_CPUIDLE - bool "CPU Idle Driver for mvebu v7 family processors" - depends on (ARCH_MVEBU || COMPILE_TEST) && !ARM64 -diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile -index 26bbc5e74..cc1eccc73 100644 ---- a/drivers/cpuidle/Makefile -+++ b/drivers/cpuidle/Makefile -@@ -25,6 +25,7 @@ obj-$(CONFIG_ARM_PSCI_CPUIDLE) += cpuidle-psci.o - obj-$(CONFIG_ARM_PSCI_CPUIDLE_DOMAIN) += cpuidle-psci-domain.o - obj-$(CONFIG_ARM_TEGRA_CPUIDLE) += cpuidle-tegra.o - obj-$(CONFIG_ARM_QCOM_SPM_CPUIDLE) += cpuidle-qcom-spm.o -+obj-$(CONFIG_ARM_STM32_CPUIDLE) += cpuidle-stm32.o - - ############################################################################### - # MIPS drivers -diff --git a/drivers/cpuidle/cpuidle-stm32.c b/drivers/cpuidle/cpuidle-stm32.c -new file mode 100644 -index 000000000..d3413386c ---- /dev/null -+++ b/drivers/cpuidle/cpuidle-stm32.c -@@ -0,0 +1,276 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) STMicroelectronics 2019 -+// Author: -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "dt_idle_states.h" -+ -+#define SMC_AUTOSTOP() \ -+{ \ -+ struct arm_smccc_res res; \ -+ arm_smccc_smc(0x8200100a, 0, 0, 0, \ -+ 0, 0, 0, 0, &res); \ -+} -+ -+struct stm32_pm_domain { -+ struct device *dev; -+ struct generic_pm_domain genpd; -+ int id; -+}; -+ -+static atomic_t stm_idle_barrier; -+ -+static int stm32_enter_idle(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int index) -+{ -+ /* -+ * Call idle CPU PM enter notifier chain so that -+ * VFP and per CPU interrupt context is saved. -+ */ -+ cpu_pm_enter(); -+ -+ /* -+ * be sure that both cpu enter at the same time -+ * normally not needed is the state is declared as coupled -+ */ -+ cpuidle_coupled_parallel_barrier(dev, &stm_idle_barrier); -+ -+ /* Enter broadcast mode for periodic timers */ -+ tick_broadcast_enable(); -+ -+ /* Enter broadcast mode for one-shot timers */ -+ tick_broadcast_enter(); -+ -+ if (dev->cpu == 0) -+ cpu_cluster_pm_enter(); -+ -+ SMC_AUTOSTOP(); -+ -+ if (dev->cpu == 0) -+ cpu_cluster_pm_exit(); -+ -+ tick_broadcast_exit(); -+ -+ cpuidle_coupled_parallel_barrier(dev, &stm_idle_barrier); -+ -+ /* -+ * Call idle CPU PM exit notifier chain to restore -+ * VFP and per CPU IRQ context. -+ */ -+ cpu_pm_exit(); -+ -+ return index; -+} -+ -+static const struct of_device_id stm32_idle_state_match[] __initconst = { -+ { .compatible = "arm,idle-state", -+ .data = stm32_enter_idle }, -+ { }, -+}; -+ -+static struct cpuidle_driver stm32_idle_driver = { -+ .name = "stm32_idle", -+ .states = { -+ ARM_CPUIDLE_WFI_STATE, -+ { -+ .enter = stm32_enter_idle, -+ .exit_latency = 620, -+ .target_residency = 700, -+ .flags = /*CPUIDLE_FLAG_TIMER_STOP | */ -+ CPUIDLE_FLAG_COUPLED, -+ .name = "CStop", -+ .desc = "Clocks off", -+ }, -+ }, -+ .safe_state_index = 0, -+ .state_count = 2, -+}; -+ -+static int stm32_pd_cpuidle_off(struct generic_pm_domain *domain) -+{ -+ struct stm32_pm_domain *priv = container_of(domain, -+ struct stm32_pm_domain, -+ genpd); -+ int cpu; -+ -+ for_each_possible_cpu(cpu) { -+ struct cpuidle_device *cpuidle_dev = per_cpu(cpuidle_devices, -+ cpu); -+ -+ cpuidle_dev->states_usage[1].disable = false; -+ } -+ -+ dev_dbg(priv->dev, "%s OFF\n", domain->name); -+ -+ return 0; -+} -+ -+static int stm32_pd_cpuidle_on(struct generic_pm_domain *domain) -+{ -+ struct stm32_pm_domain *priv = container_of(domain, -+ struct stm32_pm_domain, -+ genpd); -+ int cpu; -+ -+ for_each_possible_cpu(cpu) { -+ struct cpuidle_device *cpuidle_dev = per_cpu(cpuidle_devices, -+ cpu); -+ -+ cpuidle_dev->states_usage[1].disable = true; -+ } -+ -+ dev_dbg(priv->dev, "%s ON\n", domain->name); -+ -+ return 0; -+} -+ -+static void stm32_cpuidle_domain_remove(struct stm32_pm_domain *domain) -+{ -+ int ret; -+ -+ ret = pm_genpd_remove(&domain->genpd); -+ if (ret) -+ dev_err(domain->dev, "failed to remove PM domain %s: %d\n", -+ domain->genpd.name, ret); -+} -+ -+static int stm32_cpuidle_domain_add(struct stm32_pm_domain *domain, -+ struct device *dev, -+ struct device_node *np) -+{ -+ int ret; -+ -+ domain->dev = dev; -+ domain->genpd.name = np->name; -+ domain->genpd.power_off = stm32_pd_cpuidle_off; -+ domain->genpd.power_on = stm32_pd_cpuidle_on; -+ -+ ret = pm_genpd_init(&domain->genpd, NULL, 0); -+ if (ret < 0) { -+ dev_err(domain->dev, "failed to initialise PM domain %s: %d\n", -+ np->name, ret); -+ return ret; -+ } -+ -+ ret = of_genpd_add_provider_simple(np, &domain->genpd); -+ if (ret < 0) { -+ dev_err(domain->dev, "failed to register PM domain %s: %d\n", -+ np->name, ret); -+ stm32_cpuidle_domain_remove(domain); -+ return ret; -+ } -+ -+ dev_info(domain->dev, "domain %s registered\n", np->name); -+ -+ return 0; -+} -+ -+static int stm32_cpuidle_probe(struct platform_device *pdev) -+{ -+ struct cpuidle_driver *drv; -+ struct stm32_pm_domain *domain; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct of_phandle_args child, parent; -+ struct device_node *np_child; -+ int cpu, ret; -+ -+ drv = devm_kmemdup(dev, &stm32_idle_driver, sizeof(*drv), GFP_KERNEL); -+ if (!drv) -+ return -ENOMEM; -+ -+ /* Start at index 1, index 0 standard WFI */ -+ ret = dt_init_idle_driver(drv, stm32_idle_state_match, 1); -+ if (ret < 0) -+ return ret; -+ -+ /* all the cpus of the system are coupled */ -+ ret = cpuidle_register(drv, cpu_possible_mask); -+ if (ret) -+ return ret; -+ -+ /* Declare cpuidle domain */ -+ domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); -+ if (!domain) -+ return -ENOMEM; -+ -+ ret = stm32_cpuidle_domain_add(domain, dev, np); -+ if (ret) { -+ devm_kfree(dev, domain); -+ return ret; -+ } -+ -+ /* disable cpu idle */ -+ for_each_possible_cpu(cpu) { -+ struct cpuidle_device *cpuidle_dev = per_cpu(cpuidle_devices, -+ cpu); -+ -+ cpuidle_dev->states_usage[1].disable = true; -+ } -+ -+ /* link main cpuidle domain to consumer domain */ -+ for_each_child_of_node(np, np_child) { -+ if (!of_parse_phandle_with_args(np_child, "power-domains", -+ "#power-domain-cells", -+ 0, &child)) { -+ struct device_node *np_test = child.np; -+ -+ parent.np = np; -+ parent.args_count = 0; -+ -+ ret = of_genpd_add_subdomain(&parent, &child); -+ if (ret < 0) -+ dev_err(dev, "failed to add Sub PM domain %d\n", -+ ret); -+ -+ dev_dbg(dev, "%s, add sub cpuidle of %s, with child %s\n", -+ __func__, np->name, np_test->name); -+ -+ pm_runtime_put(dev); -+ } -+ } -+ -+ dev_info(dev, "cpuidle domain probed\n"); -+ -+ return 0; -+} -+ -+int stm32_cpuidle_remove(struct platform_device *pdev) -+{ -+ cpuidle_unregister(&stm32_idle_driver); -+ return 0; -+} -+ -+static const struct of_device_id stm32_cpuidle_of_match[] = { -+ { -+ .compatible = "stm32,cpuidle", -+ }, -+}; -+ -+static struct platform_driver stm32_cpuidle_driver = { -+ .probe = stm32_cpuidle_probe, -+ .remove = stm32_cpuidle_remove, -+ .driver = { -+ .name = "stm32_cpuidle", -+ .owner = THIS_MODULE, -+ .of_match_table = stm32_cpuidle_of_match, -+ }, -+}; -+ -+module_platform_driver(stm32_cpuidle_driver); -+ -+MODULE_AUTHOR("<>"); -+MODULE_DESCRIPTION("STM32 cpu idle driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c -index 354be5268..14013fa66 100644 ---- a/drivers/nvmem/stm32-romem.c -+++ b/drivers/nvmem/stm32-romem.c -@@ -2,15 +2,17 @@ - /* - * STM32 Factory-programmed memory read access driver - * -- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved -+ * Copyright (C) 2017-2021, STMicroelectronics - All Rights Reserved - * Author: Fabrice Gasnier for STMicroelectronics. - */ - - #include -+#include - #include - #include - #include - #include -+#include - - /* BSEC secure service access from non-secure */ - #define STM32_SMC_BSEC 0x82001003 -@@ -25,6 +27,8 @@ - /* 32 (x 32-bits) lower shadow registers */ - #define STM32MP15_BSEC_NUM_LOWER 32 - -+#define STM32_ROMEM_AUTOSUSPEND_DELAY_MS 50 -+ - struct stm32_romem_cfg { - int size; - }; -@@ -32,6 +36,7 @@ struct stm32_romem_cfg { - struct stm32_romem_priv { - void __iomem *base; - struct nvmem_config cfg; -+ struct clk *clk; - }; - - static int stm32_romem_read(void *context, unsigned int offset, void *buf, -@@ -39,11 +44,18 @@ static int stm32_romem_read(void *context, unsigned int offset, void *buf, - { - struct stm32_romem_priv *priv = context; - u8 *buf8 = buf; -- int i; -+ int i, ret; -+ -+ ret = pm_runtime_resume_and_get(priv->cfg.dev); -+ if (ret < 0) -+ return ret; - - for (i = offset; i < offset + bytes; i++) - *buf8++ = readb_relaxed(priv->base + i); - -+ pm_runtime_mark_last_busy(priv->cfg.dev); -+ pm_runtime_put_autosuspend(priv->cfg.dev); -+ - return 0; - } - -@@ -74,13 +86,19 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf, - u8 *buf8 = buf, *val8 = (u8 *)&val; - int i, j = 0, ret, skip_bytes, size; - -+ ret = pm_runtime_resume_and_get(priv->cfg.dev); -+ if (ret < 0) -+ return ret; -+ - /* Round unaligned access to 32-bits */ - roffset = rounddown(offset, 4); - skip_bytes = offset & 0x3; - rbytes = roundup(bytes + skip_bytes, 4); - -- if (roffset + rbytes > priv->cfg.size) -- return -EINVAL; -+ if (roffset + rbytes > priv->cfg.size) { -+ ret = -EINVAL; -+ goto end_read; -+ } - - for (i = roffset; (i < roffset + rbytes); i += 4) { - u32 otp = i >> 2; -@@ -95,7 +113,7 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf, - if (ret) { - dev_err(dev, "Can't read data%d (%d)\n", otp, - ret); -- return ret; -+ goto end_read; - } - } - /* skip first bytes in case of unaligned read */ -@@ -109,7 +127,11 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf, - skip_bytes = 0; - } - -- return 0; -+end_read: -+ pm_runtime_mark_last_busy(priv->cfg.dev); -+ pm_runtime_put_autosuspend(priv->cfg.dev); -+ -+ return ret; - } - - static int stm32_bsec_write(void *context, unsigned int offset, void *buf, -@@ -120,20 +142,30 @@ static int stm32_bsec_write(void *context, unsigned int offset, void *buf, - u32 *buf32 = buf; - int ret, i; - -+ ret = pm_runtime_resume_and_get(priv->cfg.dev); -+ if (ret < 0) -+ return ret; -+ - /* Allow only writing complete 32-bits aligned words */ -- if ((bytes % 4) || (offset % 4)) -- return -EINVAL; -+ if ((bytes % 4) || (offset % 4)) { -+ ret = -EINVAL; -+ goto end_write; -+ } - - for (i = offset; i < offset + bytes; i += 4) { - ret = stm32_bsec_smc(STM32_SMC_PROG_OTP, i >> 2, *buf32++, - NULL); - if (ret) { - dev_err(dev, "Can't write data%d (%d)\n", i >> 2, ret); -- return ret; -+ goto end_write; - } - } - -- return 0; -+end_write: -+ pm_runtime_mark_last_busy(priv->cfg.dev); -+ pm_runtime_put_autosuspend(priv->cfg.dev); -+ -+ return ret; - } - - static int stm32_romem_probe(struct platform_device *pdev) -@@ -142,6 +174,8 @@ static int stm32_romem_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct stm32_romem_priv *priv; - struct resource *res; -+ struct nvmem_device *nvmem; -+ int ret; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) -@@ -159,6 +193,27 @@ static int stm32_romem_probe(struct platform_device *pdev) - priv->cfg.priv = priv; - priv->cfg.owner = THIS_MODULE; - -+ priv->clk = devm_clk_get_optional(&pdev->dev, NULL); -+ if (IS_ERR(priv->clk)) -+ return dev_err_probe(dev, PTR_ERR(priv->clk), -+ "failed to get clock\n"); -+ -+ if (priv->clk) { -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(dev, "failed to enable clock (%d)\n", ret); -+ return ret; -+ } -+ } -+ -+ pm_runtime_set_autosuspend_delay(dev, -+ STM32_ROMEM_AUTOSUSPEND_DELAY_MS); -+ pm_runtime_use_autosuspend(dev); -+ -+ pm_runtime_get_noresume(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ - cfg = (const struct stm32_romem_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; - if (!cfg) { -@@ -171,9 +226,95 @@ static int stm32_romem_probe(struct platform_device *pdev) - priv->cfg.reg_write = stm32_bsec_write; - } - -- return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); -+ platform_set_drvdata(pdev, priv); -+ -+ nvmem = nvmem_register(&priv->cfg); -+ if (IS_ERR(nvmem)) -+ goto err_pm_stop; -+ -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ -+ return 0; -+ -+err_pm_stop: -+ pm_runtime_disable(dev); -+ pm_runtime_set_suspended(dev); -+ pm_runtime_put_noidle(dev); -+ -+ if (priv->clk) -+ clk_disable_unprepare(priv->clk); -+ -+ return PTR_ERR(nvmem); - } - -+static int stm32_romem_remove(struct platform_device *pdev) -+{ -+ struct stm32_romem_priv *priv; -+ int ret; -+ -+ priv = dev_get_drvdata(&pdev->dev); -+ if (!priv) -+ return -ENODEV; -+ -+ ret = pm_runtime_get_sync(&pdev->dev); -+ if (ret < 0) -+ return ret; -+ -+ nvmem_unregister((struct nvmem_device *)&priv->cfg); -+ -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ if (priv->clk) -+ clk_disable_unprepare(priv->clk); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32_romem_runtime_suspend(struct device *dev) -+{ -+ struct stm32_romem_priv *priv; -+ -+ priv = dev_get_drvdata(dev); -+ if (!priv) -+ return -ENODEV; -+ -+ if (priv->clk) -+ clk_disable_unprepare(priv->clk); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32_romem_runtime_resume(struct device *dev) -+{ -+ struct stm32_romem_priv *priv; -+ int ret; -+ -+ priv = dev_get_drvdata(dev); -+ if (!priv) -+ return -ENODEV; -+ -+ if (priv->clk) { -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(priv->cfg.dev, -+ "Failed to prepare_enable clock (%d)\n", ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops stm32_romem_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(stm32_romem_runtime_suspend, -+ stm32_romem_runtime_resume, NULL) -+}; -+ - static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { - .size = 384, /* 96 x 32-bits data words */ - }; -@@ -189,8 +330,10 @@ MODULE_DEVICE_TABLE(of, stm32_romem_of_match); - - static struct platform_driver stm32_romem_driver = { - .probe = stm32_romem_probe, -+ .remove = stm32_romem_remove, - .driver = { - .name = "stm32-romem", -+ .pm = &stm32_romem_pm_ops, - .of_match_table = of_match_ptr(stm32_romem_of_match), - }, - }; -diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h -index aa3da6611..196a15745 100644 ---- a/include/linux/pm_wakeup.h -+++ b/include/linux/pm_wakeup.h -@@ -84,6 +84,11 @@ static inline bool device_may_wakeup(struct device *dev) - return dev->power.can_wakeup && !!dev->power.wakeup; - } - -+static inline bool device_wakeup_path(struct device *dev) -+{ -+ return dev->power.wakeup_path; -+} -+ - static inline void device_set_wakeup_path(struct device *dev) - { - dev->power.wakeup_path = true; -@@ -174,6 +179,11 @@ static inline bool device_may_wakeup(struct device *dev) - return dev->power.can_wakeup && dev->power.should_wakeup; - } - -+static inline bool device_wakeup_path(struct device *dev) -+{ -+ return false; -+} -+ - static inline void device_set_wakeup_path(struct device *dev) {} - - static inline void __pm_stay_awake(struct wakeup_source *ws) {} -diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c -index 32391acc8..dc800d4f5 100644 ---- a/kernel/power/suspend.c -+++ b/kernel/power/suspend.c -@@ -34,7 +34,6 @@ - #include "power.h" - - const char * const pm_labels[] = { -- [PM_SUSPEND_TO_IDLE] = "freeze", - [PM_SUSPEND_STANDBY] = "standby", - [PM_SUSPEND_MEM] = "mem", - }; --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0001-ARM-5.15.24-stm32mp1-r1-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0001-ARM-5.15.24-stm32mp1-r1-MACHINE.patch new file mode 100644 index 0000000..a933e42 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0001-ARM-5.15.24-stm32mp1-r1-MACHINE.patch @@ -0,0 +1,124 @@ +From 4868d40c41f2fb7dea18d7b5fe14da02fc82e2f1 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 31 May 2022 11:50:09 +0200 +Subject: [PATCH 01/22] ARM-5.15.24-stm32mp1-r1-MACHINE + +Signed-off-by: Christophe Priouzeau +--- + Documentation/arm/index.rst | 1 + + .../arm/stm32/stm32mp13-overview.rst | 37 +++++++++++++++++++ + arch/arm/Kconfig.debug | 2 +- + arch/arm/mach-stm32/Kconfig | 9 +++++ + arch/arm/mach-stm32/board-dt.c | 5 +++ + 5 files changed, 53 insertions(+), 1 deletion(-) + create mode 100644 Documentation/arm/stm32/stm32mp13-overview.rst + +diff --git a/Documentation/arm/index.rst b/Documentation/arm/index.rst +index d4f34ae9e..2bda5461a 100644 +--- a/Documentation/arm/index.rst ++++ b/Documentation/arm/index.rst +@@ -55,6 +55,7 @@ SoC-specific documents + stm32/stm32h750-overview + stm32/stm32f769-overview + stm32/stm32f429-overview ++ stm32/stm32mp13-overview + stm32/stm32mp157-overview + + sunxi +diff --git a/Documentation/arm/stm32/stm32mp13-overview.rst b/Documentation/arm/stm32/stm32mp13-overview.rst +new file mode 100644 +index 000000000..3bb9492da +--- /dev/null ++++ b/Documentation/arm/stm32/stm32mp13-overview.rst +@@ -0,0 +1,37 @@ ++=================== ++STM32MP13 Overview ++=================== ++ ++Introduction ++------------ ++ ++The STM32MP131/STM32MP133/STM32MP135 are Cortex-A MPU aimed at various applications. ++They feature: ++ ++- One Cortex-A7 application core ++- Standard memories interface support ++- Standard connectivity, widely inherited from the STM32 MCU family ++- Comprehensive security support ++ ++More details: ++ ++- Cortex-A7 core running up to @900MHz ++- FMC controller to connect SDRAM, NOR and NAND memories ++- QSPI ++- SD/MMC/SDIO support ++- 2*Ethernet controller ++- CAN ++- ADC/DAC ++- USB EHCI/OHCI controllers ++- USB OTG ++- I2C, SPI, CAN busses support ++- Several general purpose timers ++- Serial Audio interface ++- LCD controller ++- DCMIPP ++- SPDIFRX ++- DFSDM ++ ++:Authors: ++ ++- Alexandre Torgue +diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug +index 644875d73..37b833761 100644 +--- a/arch/arm/Kconfig.debug ++++ b/arch/arm/Kconfig.debug +@@ -1244,7 +1244,7 @@ choice + + config STM32MP1_DEBUG_UART + bool "Use STM32MP1 UART for low-level debug" +- depends on MACH_STM32MP157 ++ depends on MACH_STM32MP157 || MACH_STM32MP13 + select DEBUG_STM32_UART + help + Say Y here if you want kernel low-level debugging support +diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig +index 57699bd8f..ab6978451 100644 +--- a/arch/arm/mach-stm32/Kconfig ++++ b/arch/arm/mach-stm32/Kconfig +@@ -46,8 +46,17 @@ if ARCH_MULTI_V7 + config MACH_STM32MP157 + bool "STMicroelectronics STM32MP157" + select ARM_ERRATA_814220 ++ select REGULATOR + default y + ++config MACH_STM32MP13 ++ bool "STMicroelectronics STM32MP13x" ++ select ARM_ERRATA_814220 ++ default y ++ help ++ Support for STM32MP13 SoCs: ++ STM32MP131, STM32MP133, STM32MP135 ++ + endif # ARMv7-A + + endif +diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c +index a766310d8..9ff06f2fc 100644 +--- a/arch/arm/mach-stm32/board-dt.c ++++ b/arch/arm/mach-stm32/board-dt.c +@@ -18,6 +18,11 @@ static const char *const stm32_compat[] __initconst = { + "st,stm32f769", + "st,stm32h743", + "st,stm32h750", ++ "st,stm32mp131", ++ "st,stm32mp133", ++ "st,stm32mp135", ++ "st,stm32mp151", ++ "st,stm32mp153", + "st,stm32mp157", + NULL + }; +-- +2.25.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0002-ARM-5.15.24-stm32mp1-r1-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0002-ARM-5.15.24-stm32mp1-r1-CLOCK.patch new file mode 100644 index 0000000..594488e --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0002-ARM-5.15.24-stm32mp1-r1-CLOCK.patch @@ -0,0 +1,5180 @@ +From 696e5d9592c88d2e0137dafa02cd293eb2776d15 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 31 May 2022 11:50:45 +0200 +Subject: [PATCH 02/22] ARM-5.15.24-stm32mp1-r1-CLOCK + +Signed-off-by: Christophe Priouzeau +--- + drivers/clk/Kconfig | 5 + + drivers/clk/Makefile | 1 + + drivers/clk/clk-composite.c | 15 + + drivers/clk/clk-scmi.c | 36 + + drivers/clk/clk-stm32mp1.c | 471 ++++-- + drivers/clk/clk.c | 7 +- + drivers/clk/stm32/Makefile | 1 + + drivers/clk/stm32/clk-stm32-core.c | 722 ++++++++ + drivers/clk/stm32/clk-stm32-core.h | 243 +++ + drivers/clk/stm32/clk-stm32mp13.c | 1062 ++++++++++++ + drivers/clk/stm32/reset-stm32.c | 122 ++ + drivers/clk/stm32/reset-stm32.h | 7 + + drivers/clk/stm32/stm32mp13_rcc.h | 1751 ++++++++++++++++++++ + drivers/clocksource/timer-stm32-lp.c | 4 +- + include/dt-bindings/clock/stm32mp1-clks.h | 52 +- + include/dt-bindings/clock/stm32mp13-clks.h | 229 +++ + 16 files changed, 4521 insertions(+), 207 deletions(-) + create mode 100644 drivers/clk/stm32/Makefile + create mode 100644 drivers/clk/stm32/clk-stm32-core.c + create mode 100644 drivers/clk/stm32/clk-stm32-core.h + create mode 100644 drivers/clk/stm32/clk-stm32mp13.c + create mode 100644 drivers/clk/stm32/reset-stm32.c + create mode 100644 drivers/clk/stm32/reset-stm32.h + create mode 100644 drivers/clk/stm32/stm32mp13_rcc.h + create mode 100644 include/dt-bindings/clock/stm32mp13-clks.h + +diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig +index c5b3dc973..c23287f7d 100644 +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -334,6 +334,11 @@ config COMMON_CLK_VC5 + This driver supports the IDT VersaClock 5 and VersaClock 6 + programmable clock generators. + ++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 +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index e42312121..6172bc25b 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -109,6 +109,7 @@ obj-y += socfpga/ + obj-$(CONFIG_PLAT_SPEAR) += spear/ + obj-y += sprd/ + obj-$(CONFIG_ARCH_STI) += st/ ++obj-$(CONFIG_ARCH_STM32) += stm32/ + obj-$(CONFIG_ARCH_SUNXI) += sunxi/ + obj-$(CONFIG_SUNXI_CCU) += sunxi-ng/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ +diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c +index 510a99656..8fcbb34de 100644 +--- a/drivers/clk/clk-composite.c ++++ b/drivers/clk/clk-composite.c +@@ -42,6 +42,18 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, + return rate_ops->recalc_rate(rate_hw, parent_rate); + } + ++static int clk_composite_get_duty_cycle(struct clk_hw *hw, ++ struct clk_duty *duty) ++{ ++ struct clk_composite *composite = to_clk_composite(hw); ++ const struct clk_ops *rate_ops = composite->rate_ops; ++ struct clk_hw *rate_hw = composite->rate_hw; ++ ++ __clk_hw_set_clk(rate_hw, hw); ++ ++ return rate_ops->get_duty_cycle(rate_hw, duty); ++} ++ + static int clk_composite_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { +@@ -251,6 +263,9 @@ static struct clk_hw *__clk_hw_register_composite(struct device *dev, + } + clk_composite_ops->recalc_rate = clk_composite_recalc_rate; + ++ if (rate_ops->get_duty_cycle) ++ clk_composite_ops->get_duty_cycle = clk_composite_get_duty_cycle; ++ + if (rate_ops->determine_rate) + clk_composite_ops->determine_rate = + clk_composite_determine_rate; +diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c +index 1e357d364..3e87eefa8 100644 +--- a/drivers/clk/clk-scmi.c ++++ b/drivers/clk/clk-scmi.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -37,6 +38,37 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw, + return rate; + } + ++static unsigned long scmi_clk_round_rate_get(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ int ret; ++ u64 round_rate = rate; ++ struct scmi_clk *clk = to_scmi_clk(hw); ++ ++ ret = scmi_proto_clk_ops->round_rate_get(clk->ph, clk->id, &round_rate); ++ if (ret) ++ return 0; ++ ++ return round_rate; ++} ++ ++static int scmi_clk_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) ++{ ++ struct scmi_clk *clk = to_scmi_clk(hw); ++ int ret; ++ ++ ret = scmi_proto_clk_ops->get_duty_cycle(clk->ph, clk->id, ++ &duty->num, &duty->den); ++ if (ret) { ++ /* Assume a default value of 50% */ ++ duty->num = 1; ++ duty->den = 2; ++ } ++ ++ return 0; ++} ++ + static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) + { +@@ -59,6 +91,9 @@ static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate, + else if (rate >= fmax) + return fmax; + ++ if (clk->info->range.step_size == 0) ++ return scmi_clk_round_rate_get(hw, rate, parent_rate); ++ + ftmp = rate - fmin; + ftmp += clk->info->range.step_size - 1; /* to round up */ + do_div(ftmp, clk->info->range.step_size); +@@ -100,6 +135,7 @@ static const struct clk_ops scmi_clk_ops = { + */ + .prepare = scmi_clk_enable, + .unprepare = scmi_clk_disable, ++ .get_duty_cycle = scmi_clk_get_duty_cycle, + }; + + static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk) +diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c +index 4bd1fe7d8..c0b3dc0e8 100644 +--- a/drivers/clk/clk-stm32mp1.c ++++ b/drivers/clk/clk-stm32mp1.c +@@ -116,7 +116,7 @@ static const char * const ref3_parents[] = { + }; + + static const char * const ref4_parents[] = { +- "ck_hsi", "ck_hse", "ck_csi" ++ "ck_hsi", "ck_hse", "ck_csi", "i2s_ckin" + }; + + static const char * const cpu_src[] = { +@@ -294,6 +294,7 @@ static const struct clk_div_table ck_trace_div_table[] = { + struct stm32_mmux { + u8 nbr_clk; + struct clk_hw *hws[MAX_MUX_CLK]; ++ u8 saved_parent; + }; + + struct stm32_clk_mmux { +@@ -717,7 +718,7 @@ static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) + + 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); ++ clk_hw_set_parent(clk_mmux->mmux->hws[n], hwp); + + return 0; + } +@@ -728,156 +729,212 @@ static const struct clk_ops clk_mmux_ops = { + .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; +-}; ++static bool is_all_clk_on_switch_are_off(struct clk_hw *hw) ++{ ++ struct clk_composite *composite = to_clk_composite(hw); ++ struct clk_hw *mux_hw = composite->mux_hw; ++ struct clk_mux *mux = to_clk_mux(mux_hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); ++ int i = 0; ++ ++ for (i = 0; i < clk_mmux->mmux->nbr_clk; i++) ++ if (__clk_is_enabled(clk_mmux->mmux->hws[i]->clk)) ++ return false; + +-#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) ++ return true; ++} + +-#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 ++#define MMUX_SAFE_POSITION 0 + +-static int __pll_is_enabled(struct clk_hw *hw) ++static int clk_mmux_set_safe_position(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); ++ struct clk_composite *composite = to_clk_composite(hw); ++ struct clk_hw *mux_hw = composite->mux_hw; ++ struct clk_mux *mux = to_clk_mux(mux_hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +- return readl_relaxed(clk_elem->reg) & PLL_ON; +-} ++ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(mux_hw); ++ clk_mux_ops.set_parent(mux_hw, MMUX_SAFE_POSITION); + +-#define TIMEOUT 5 ++ return 0; ++} + +-static int pll_enable(struct clk_hw *hw) ++static int clk_mmux_restore_parent(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; ++ struct clk_composite *composite = to_clk_composite(hw); ++ struct clk_hw *mux_hw = composite->mux_hw; ++ struct clk_mux *mux = to_clk_mux(mux_hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +- spin_lock_irqsave(clk_elem->lock, flags); ++ clk_mux_ops.set_parent(mux_hw, clk_mmux->mmux->saved_parent); + +- if (__pll_is_enabled(hw)) +- goto unlock; ++ return 0; ++} + +- reg = readl_relaxed(clk_elem->reg); +- reg |= PLL_ON; +- writel_relaxed(reg, clk_elem->reg); ++static u8 clk_mmux_get_parent_safe(struct clk_hw *hw) ++{ ++ struct clk_mux *mux = to_clk_mux(hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +- /* 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); ++ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(hw); + +- if (bit_status) +- udelay(120); ++ return clk_mmux->mmux->saved_parent; ++} + +- } while (bit_status && --timeout); ++static int clk_mmux_set_parent_safe(struct clk_hw *hw, u8 index) ++{ ++ struct clk_mux *mux = to_clk_mux(hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +-unlock: +- spin_unlock_irqrestore(clk_elem->lock, flags); ++ clk_mmux_set_parent(hw, index); ++ clk_mmux->mmux->saved_parent = index; + +- return bit_status; ++ return 0; + } + +-static void pll_disable(struct clk_hw *hw) +-{ +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- u32 reg; +- unsigned long flags = 0; ++static const struct clk_ops clk_mmux_safe_ops = { ++ .get_parent = clk_mmux_get_parent_safe, ++ .set_parent = clk_mmux_set_parent_safe, ++ .determine_rate = __clk_mux_determine_rate, ++}; + +- spin_lock_irqsave(clk_elem->lock, flags); ++static int mp1_mgate_clk_enable_safe(struct clk_hw *hw) ++{ ++ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); + +- reg = readl_relaxed(clk_elem->reg); +- reg &= ~PLL_ON; +- writel_relaxed(reg, clk_elem->reg); ++ clk_mmux_restore_parent(composite_hw); ++ mp1_mgate_clk_enable(hw); + +- spin_unlock_irqrestore(clk_elem->lock, flags); ++ return 0; + } + +-static u32 pll_frac_val(struct clk_hw *hw) ++static void mp1_mgate_clk_disable_safe(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- u32 reg, frac = 0; ++ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); + +- reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); +- if (reg & FRACLE) +- frac = (reg >> FRAC_SHIFT) & FRAC_MASK; ++ mp1_mgate_clk_disable(hw); + +- return frac; ++ if (is_all_clk_on_switch_are_off(composite_hw)) ++ clk_mmux_set_safe_position(composite_hw); + } + +-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; ++static const struct clk_ops mp1_mgate_clk_safe_ops = { ++ .enable = mp1_mgate_clk_enable_safe, ++ .disable = mp1_mgate_clk_disable_safe, ++ .is_enabled = clk_gate_is_enabled, ++}; + +- reg = readl_relaxed(clk_elem->reg + 4); ++/* STM32 PLL */ ++struct clk_pll_fractional_divider { ++ struct clk_hw hw; ++ void __iomem *mreg; ++ u8 mshift; ++ u8 mwidth; ++ u8 mflags; ++ void __iomem *nreg; ++ u8 nshift; ++ u8 nwidth; ++ u8 nflags; ++ void __iomem *freg; ++ u8 fshift; ++ u8 fwidth; + +- divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; +- divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; +- rate = (u64)parent_rate * divn; ++ /* lock pll enable/disable registers */ ++ spinlock_t *lock; ++}; + +- do_div(rate, divm); ++#define to_pll_fractional_divider(_hw)\ ++ container_of(_hw, struct clk_pll_fractional_divider, hw) + +- frac = pll_frac_val(hw); +- if (frac) { +- rate_frac = (u64)parent_rate * (u64)frac; +- do_div(rate_frac, (divm * 8192)); +- } ++static unsigned long clk_pll_frac_div_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_pll_fractional_divider *fd = to_pll_fractional_divider(hw); ++ u32 mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift; ++ u32 nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift; ++ u32 fmask = GENMASK(fd->fwidth - 1, 0) << fd->fshift; ++ unsigned long m, n, f; ++ u64 rate, frate = 0; ++ u32 val; ++ ++ val = readl(fd->mreg); ++ m = (val & mmask) >> fd->mshift; ++ if (fd->mflags & CLK_FRAC_DIVIDER_ZERO_BASED) ++ m++; ++ ++ val = readl(fd->nreg); ++ n = (val & nmask) >> fd->nshift; ++ if (fd->nflags & CLK_FRAC_DIVIDER_ZERO_BASED) ++ n++; ++ ++ if (!n || !m) ++ return parent_rate; + +- return rate + rate_frac; ++ rate = (u64)parent_rate * n; ++ do_div(rate, m); ++ ++ val = readl(fd->freg); ++ f = (val & fmask) >> fd->fshift; ++ if (f) { ++ frate = (u64)parent_rate * (u64)f; ++ do_div(frate, (m * (1 << fd->fwidth))); ++ } ++ return rate + frate; + } + +-static int pll_is_enabled(struct clk_hw *hw) ++static const struct clk_ops clk_pll_frac_div_ops = { ++ .recalc_rate = clk_pll_frac_div_recalc_rate, ++}; ++ ++#define PLL_BIT_ON 0 ++#define PLL_BIT_RDY 1 ++#define PLL_MUX_SHIFT 0 ++#define PLL_MUX_MASK 3 ++#define PLL_DIVMN_OFFSET 4 ++#define PLL_DIVM_SHIFT 16 ++#define PLL_DIVM_WIDTH 6 ++#define PLL_DIVN_SHIFT 0 ++#define PLL_DIVN_WIDTH 9 ++#define PLL_FRAC_OFFSET 0xC ++#define PLL_FRAC_SHIFT 3 ++#define PLL_FRAC_WIDTH 13 ++ ++#define TIMEOUT 5 ++ ++static int pll_enable(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- unsigned long flags = 0; +- int ret; ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 timeout = TIMEOUT; ++ int bit_status = 0; + +- spin_lock_irqsave(clk_elem->lock, flags); +- ret = __pll_is_enabled(hw); +- spin_unlock_irqrestore(clk_elem->lock, flags); ++ if (clk_gate_ops.is_enabled(hw)) ++ return 0; + +- return ret; ++ clk_gate_ops.enable(hw); ++ ++ do { ++ bit_status = !(readl_relaxed(gate->reg) & BIT(PLL_BIT_RDY)); ++ ++ if (bit_status) ++ udelay(120); ++ ++ } while (bit_status && --timeout); ++ ++ return bit_status; + } + +-static u8 pll_get_parent(struct clk_hw *hw) ++static void pll_disable(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); ++ if (!clk_gate_ops.is_enabled(hw)) ++ return; + +- return clk_mux_ops.get_parent(mux_hw); ++ clk_gate_ops.disable(hw); + } + +-static const struct clk_ops pll_ops = { ++const struct clk_ops pll_gate_ops = { + .enable = pll_enable, + .disable = pll_disable, +- .recalc_rate = pll_recalc_rate, +- .is_enabled = pll_is_enabled, +- .get_parent = pll_get_parent, ++ .is_enabled = clk_gate_is_enabled, + }; + + static struct clk_hw *clk_register_pll(struct device *dev, const char *name, +@@ -888,39 +945,50 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name, + unsigned long flags, + spinlock_t *lock) + { +- struct stm32_pll_obj *element; +- struct clk_init_data init; +- struct clk_hw *hw; +- int err; ++ struct clk_pll_fractional_divider *frac_div; ++ struct clk_gate *gate; ++ struct clk_mux *mux; + +- element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL); +- if (!element) ++ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); ++ if (!mux) + return ERR_PTR(-ENOMEM); + +- init.name = name; +- init.ops = &pll_ops; +- init.flags = flags; +- init.parent_names = parent_names; +- init.num_parents = num_parents; ++ mux->reg = mux_reg; ++ mux->shift = PLL_MUX_SHIFT; ++ mux->mask = PLL_MUX_MASK; ++ mux->flags = CLK_MUX_READ_ONLY; ++ mux->table = NULL; ++ mux->lock = lock; + +- 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; ++ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ return ERR_PTR(-ENOMEM); + +- element->hw.init = &init; +- element->reg = reg; +- element->lock = lock; ++ gate->reg = reg; ++ gate->bit_idx = PLL_BIT_ON; ++ gate->flags = 0; ++ gate->lock = lock; + +- hw = &element->hw; +- err = clk_hw_register(dev, hw); ++ frac_div = devm_kzalloc(dev, sizeof(*frac_div), GFP_KERNEL); ++ if (!frac_div) ++ return ERR_PTR(-ENOMEM); + +- if (err) +- return ERR_PTR(err); ++ frac_div->mreg = reg + PLL_DIVMN_OFFSET; ++ frac_div->mshift = PLL_DIVM_SHIFT; ++ frac_div->mwidth = PLL_DIVM_WIDTH; ++ frac_div->mflags = CLK_FRAC_DIVIDER_ZERO_BASED; ++ frac_div->nreg = reg + PLL_DIVMN_OFFSET; ++ frac_div->nshift = PLL_DIVN_SHIFT; ++ frac_div->nwidth = PLL_DIVN_WIDTH; ++ frac_div->nflags = CLK_FRAC_DIVIDER_ZERO_BASED; ++ frac_div->freg = reg + PLL_FRAC_OFFSET; ++ frac_div->fshift = PLL_FRAC_SHIFT; ++ frac_div->fwidth = PLL_FRAC_WIDTH; + +- return hw; ++ return clk_hw_register_composite(dev, name, parent_names, num_parents, ++ &mux->hw, &clk_mux_ops, ++ &frac_div->hw, &clk_pll_frac_div_ops, ++ &gate->hw, &pll_gate_ops, flags); + } + + /* Kernel Timer */ +@@ -1090,9 +1158,49 @@ static const struct clk_ops rtc_div_clk_ops = { + .determine_rate = clk_divider_rtc_determine_rate + }; + ++static int clk_div_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) ++{ ++ struct clk_divider *divider = to_clk_divider(hw); ++ unsigned int val; ++ ++ val = readl(divider->reg) >> divider->shift; ++ val &= clk_div_mask(divider->width); ++ ++ duty->num = (val + 1) / 2; ++ duty->den = (val + 1); ++ ++ return 0; ++} ++ ++static unsigned long clk_div_duty_cycle_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return clk_divider_ops.recalc_rate(hw, parent_rate); ++} ++ ++static long clk_div_duty_cycle_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ return clk_divider_ops.round_rate(hw, rate, prate); ++} ++ ++static int clk_div_duty_cycle_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ return clk_divider_ops.set_rate(hw, rate, parent_rate); ++} ++ ++static const struct clk_ops div_dc_clk_ops = { ++ .recalc_rate = clk_div_duty_cycle_recalc_rate, ++ .round_rate = clk_div_duty_cycle_round_rate, ++ .set_rate = clk_div_duty_cycle_set_rate, ++ .get_duty_cycle = clk_div_get_duty_cycle, ++}; ++ + struct stm32_pll_cfg { + u32 offset; + u32 muxoff; ++ const struct clk_ops *ops; + }; + + static struct clk_hw *_clk_register_pll(struct device *dev, +@@ -1281,7 +1389,7 @@ _clk_stm32_register_composite(struct device *dev, + NULL, &mp1_gate_clk_ops)\ + + #define _MGATE_MP1(_mgate)\ +- .gate = &per_gate_cfg[_mgate] ++ &per_gate_cfg[_mgate] + + #define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ + STM32_GATE(_id, _name, _parent, _flags,\ +@@ -1293,7 +1401,7 @@ _clk_stm32_register_composite(struct device *dev, + + #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, _ops)\ +- .div = &(struct stm32_div_cfg) {\ ++ (&(struct stm32_div_cfg) {\ + &(struct div_cfg) {\ + .reg_off = _div_offset,\ + .shift = _div_shift,\ +@@ -1302,18 +1410,23 @@ _clk_stm32_register_composite(struct device *dev, + .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)\ ++ _div_flags, _div_table, NULL) ++ ++#define _DIV_DUTY_CYCLE(_div_offset, _div_shift, _div_width, _div_flags,\ ++ _div_table)\ ++ _STM32_DIV(_div_offset, _div_shift, _div_width,\ ++ _div_flags, _div_table, &div_dc_clk_ops) + + #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 stm32_mux_cfg) {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ +@@ -1323,18 +1436,18 @@ _clk_stm32_register_composite(struct device *dev, + },\ + .mmux = _mmux,\ + .ops = _ops,\ +- } ++ }) + + #define _MUX(_offset, _shift, _width, _mux_flags)\ +- _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ ++ _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL) + +-#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] ++#define _MMUX(_mmux) &ker_mux_cfg[_mmux] + +-#define PARENT(_parent) ((const char *[]) { _parent}) ++#define PARENT(_parent) ((const char *[]) { _parent}) + +-#define _NO_MUX .mux = NULL +-#define _NO_DIV .div = NULL +-#define _NO_GATE .gate = NULL ++#define _NO_MUX NULL ++#define _NO_DIV NULL ++#define _NO_GATE NULL + + #define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ + {\ +@@ -1344,9 +1457,9 @@ _clk_stm32_register_composite(struct device *dev, + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct stm32_composite_cfg) {\ +- _gate,\ +- _mux,\ +- _div,\ ++ .gate = (_gate),\ ++ .mux = (_mux),\ ++ .div = (_div),\ + },\ + .func = _clk_stm32_register_composite,\ + } +@@ -1498,6 +1611,10 @@ static struct stm32_mgate mp1_mgate[G_LAST]; + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + &mp1_mgate[_id], &mp1_mgate_clk_ops) + ++#define K_MGATE_SAFE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ ++ _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ ++ &mp1_mgate[_id], &mp1_mgate_clk_safe_ops) ++ + /* Peripheral gates */ + static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + /* Multi gates */ +@@ -1609,10 +1726,10 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + + 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_MGATE_SAFE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), ++ K_MGATE_SAFE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), ++ K_MGATE_SAFE(G_QSPI, RCC_AHB6ENSETR, 14, 0), ++ K_MGATE_SAFE(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), +@@ -1684,9 +1801,13 @@ static struct stm32_mmux ker_mux[M_LAST]; + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + &ker_mux[_id], &clk_mmux_ops) + ++#define K_MMUX_SAFE(_id, _offset, _shift, _width, _mux_flags)\ ++ _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ ++ &ker_mux[_id], &clk_mmux_safe_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_SAFE(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), +@@ -1703,8 +1824,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + /* 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_MMUX_SAFE(M_FMC, RCC_FMCCKSELR, 0, 2, 0), ++ K_MMUX_SAFE(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), +@@ -1748,7 +1869,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + PLL(PLL4, "pll4", ref4_parents, 0, RCC_PLL4CR, RCC_RCK4SELR), + + /* ODF */ +- COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, ++ COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), CLK_SET_RATE_PARENT, + _GATE(RCC_PLL1CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), +@@ -1776,7 +1897,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 5, 0), + _NO_MUX, +- _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), ++ _DIV_DUTY_CYCLE(RCC_PLL3CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 6, 0), +@@ -1796,40 +1917,40 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 6, 0), + _NO_MUX, +- _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), ++ _DIV_DUTY_CYCLE(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), ++ CLK_SET_RATE_PARENT | 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)), ++ 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)), ++ 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, ++ DIV_TABLE(PCLK1, "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, ++ DIV_TABLE(PCLK2, "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, ++ DIV_TABLE(PCLK3, "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, ++ DIV_TABLE(PCLK4, "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, ++ DIV_TABLE(PCLK5, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + /* Kernel Timers */ +@@ -1911,8 +2032,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + 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(RTCAPB, "rtcapb", "pclk5", 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), +@@ -1953,10 +2073,6 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), + PCLK(ETHRX, "ethrx", "ck_axi", 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), +@@ -2046,7 +2162,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + 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, ++ COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, ++ CLK_OPS_PARENT_ENABLE | CLK_IGNORE_UNUSED, + _GATE(RCC_DBGCFGR, 9, 0), + _NO_MUX, + _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index ac11cefc3..a66dba8be 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -1764,6 +1764,7 @@ static void clk_reparent(struct clk_core *core, struct clk_core *new_parent) + core->parent = new_parent; + } + ++static const struct clk_ops clk_nodrv_ops; + static struct clk_core *__clk_set_parent_before(struct clk_core *core, + struct clk_core *parent) + { +@@ -1792,7 +1793,8 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core, + + /* enable old_parent & parent if CLK_OPS_PARENT_ENABLE is set */ + if (core->flags & CLK_OPS_PARENT_ENABLE) { +- clk_core_prepare_enable(old_parent); ++ if (old_parent && old_parent->ops != &clk_nodrv_ops) ++ clk_core_prepare_enable(old_parent); + clk_core_prepare_enable(parent); + } + +@@ -1826,7 +1828,8 @@ static void __clk_set_parent_after(struct clk_core *core, + /* re-balance ref counting if CLK_OPS_PARENT_ENABLE is set */ + if (core->flags & CLK_OPS_PARENT_ENABLE) { + clk_core_disable_unprepare(parent); +- clk_core_disable_unprepare(old_parent); ++ if (old_parent && old_parent->ops != &clk_nodrv_ops) ++ clk_core_disable_unprepare(old_parent); + } + } + +diff --git a/drivers/clk/stm32/Makefile b/drivers/clk/stm32/Makefile +new file mode 100644 +index 000000000..95bd2230b +--- /dev/null ++++ b/drivers/clk/stm32/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_COMMON_CLK_STM32MP135) += clk-stm32mp13.o clk-stm32-core.o reset-stm32.o +diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c +new file mode 100644 +index 000000000..b977bfb1e +--- /dev/null ++++ b/drivers/clk/stm32/clk-stm32-core.c +@@ -0,0 +1,722 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk-stm32-core.h" ++#include "reset-stm32.h" ++ ++static DEFINE_SPINLOCK(rlock); ++ ++static int stm32_rcc_clock_init(struct device *dev, ++ const struct of_device_id *match, ++ void __iomem *base) ++{ ++ const struct stm32_rcc_match_data *data = match->data; ++ struct clk_hw_onecell_data *clk_data = data->hw_clks; ++ struct clk_hw **hws; ++ int 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_clocks; n++) { ++ const struct clock_config *cfg_clock = &data->tab_clocks[n]; ++ struct clk_hw *hw = ERR_PTR(-ENOENT); ++ ++ if (data->check_security && ++ data->check_security(base, cfg_clock)) ++ continue; ++ ++ if (cfg_clock->func) ++ hw = (*cfg_clock->func)(dev, data, base, &rlock, ++ cfg_clock); ++ ++ if (IS_ERR(hw)) { ++ dev_err(dev, "Can't register clk %d: %ld\n", n, ++ PTR_ERR(hw)); ++ return PTR_ERR(hw); ++ } ++ ++ if (cfg_clock->id < NO_ID) ++ hws[cfg_clock->id] = hw; ++ } ++ ++ return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, ++ clk_data); ++} ++ ++int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data, ++ void __iomem *base) ++{ ++ 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, match, base); ++ if (err) { ++ pr_err("stm32mp1 reset failed to initialize\n"); ++ return err; ++ } ++ ++ /* RCC Clock Configuration */ ++ err = stm32_rcc_clock_init(dev, match, base); ++ if (err) { ++ pr_err("stm32mp1 clock failed to initialize\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++void clk_stm32_endisable_gate(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 gate_id, int enable) ++{ ++ const struct stm32_gate_cfg *gate = &data->gates[gate_id]; ++ void __iomem *addr = base + gate->offset; ++ ++ if (enable) { ++ if (data->gate_cpt[gate_id]++ > 0) ++ return; ++ ++ if (gate->set_clr != 0) ++ writel(BIT(gate->bit_idx), addr); ++ else ++ writel(readl(addr) | BIT(gate->bit_idx), addr); ++ } else { ++ if (--data->gate_cpt[gate_id] > 0) ++ return; ++ ++ if (gate->set_clr != 0) ++ writel(BIT(gate->bit_idx), addr + gate->set_clr); ++ else ++ writel(readl(addr) & ~BIT(gate->bit_idx), addr); ++ } ++} ++ ++static void clk_stm32_disable_unused_gate(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 gate_id) ++{ ++ const struct stm32_gate_cfg *gate = &data->gates[gate_id]; ++ void __iomem *addr = base + gate->offset; ++ ++ if (data->gate_cpt[gate_id] > 0) ++ return; ++ ++ if (gate->set_clr != 0) ++ writel(BIT(gate->bit_idx), addr + gate->set_clr); ++ else ++ writel(readl(addr) & ~BIT(gate->bit_idx), addr); ++} ++ ++int clk_stm32_is_enabled_gate(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 gate_id) ++{ ++ const struct stm32_gate_cfg *gate = &data->gates[gate_id]; ++ ++ return (readl(base + gate->offset) & BIT(gate->bit_idx)) != 0; ++} ++ ++void clk_stm32_gate_endisable(struct clk_hw *hw, int enable) ++{ ++ struct clk_stm32_gate *gate = to_clk_stm32_gate(hw); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(gate->lock, flags); ++ ++ clk_stm32_endisable_gate(gate->base, gate->clock_data, ++ gate->gate_id, enable); ++ ++ spin_unlock_irqrestore(gate->lock, flags); ++} ++ ++int clk_stm32_gate_enable(struct clk_hw *hw) ++{ ++ clk_stm32_gate_endisable(hw, 1); ++ ++ return 0; ++} ++ ++void clk_stm32_gate_disable(struct clk_hw *hw) ++{ ++ clk_stm32_gate_endisable(hw, 0); ++} ++ ++int clk_stm32_gate_is_enabled(struct clk_hw *hw) ++{ ++ struct clk_stm32_gate *gate = to_clk_stm32_gate(hw); ++ ++ return clk_stm32_is_enabled_gate(gate->base, gate->clock_data, ++ gate->gate_id); ++} ++ ++static void clk_stm32_gate_disable_unused(struct clk_hw *hw) ++{ ++ struct clk_stm32_gate *gate = to_clk_stm32_gate(hw); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(gate->lock, flags); ++ ++ clk_stm32_disable_unused_gate(gate->base, gate->clock_data, gate->gate_id); ++ ++ spin_unlock_irqrestore(gate->lock, flags); ++} ++ ++const struct clk_ops clk_stm32_gate_ops = { ++ .enable = clk_stm32_gate_enable, ++ .disable = clk_stm32_gate_disable, ++ .is_enabled = clk_stm32_gate_is_enabled, ++ .disable_unused = clk_stm32_gate_disable_unused, ++}; ++ ++#define MUX_SAFE_POSITION 0 ++ ++static int clk_stm32_has_safe_mux(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ const struct stm32_mux_cfg *mux = &composite->clock_data->muxes[composite->mux_id]; ++ ++ return !!(mux->flags & MUX_SAFE); ++} ++ ++static void clk_stm32_set_safe_position_mux(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ ++ if (!clk_stm32_composite_is_enabled(hw)) { ++ unsigned long flags = 0; ++ ++ if (composite->clock_data->is_multi_mux) { ++ struct clk_hw *other_mux_hw = NULL; ++ ++ other_mux_hw = composite->clock_data->is_multi_mux(hw); ++ ++ if (!other_mux_hw || clk_stm32_composite_is_enabled(other_mux_hw)) ++ return; ++ } ++ ++ spin_lock_irqsave(composite->lock, flags); ++ ++ clk_stm32_set_parent_mux(composite->base, composite->clock_data, ++ composite->mux_id, MUX_SAFE_POSITION); ++ ++ spin_unlock_irqrestore(composite->lock, flags); ++ } ++} ++ ++static void clk_stm32_safe_restore_position_mux(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ int sel = clk_hw_get_parent_index(hw); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(composite->lock, flags); ++ ++ clk_stm32_set_parent_mux(composite->base, composite->clock_data, ++ composite->mux_id, sel); ++ ++ spin_unlock_irqrestore(composite->lock, flags); ++} ++ ++void clk_stm32_composite_gate_endisable(struct clk_hw *hw, int enable) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(composite->lock, flags); ++ ++ clk_stm32_endisable_gate(composite->base, composite->clock_data, ++ composite->gate_id, enable); ++ ++ spin_unlock_irqrestore(composite->lock, flags); ++} ++ ++int clk_stm32_composite_gate_enable(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ ++ if (composite->gate_id == NO_STM32_GATE) ++ return 0; ++ ++ clk_stm32_composite_gate_endisable(hw, 1); ++ ++ if (composite->mux_id != NO_STM32_MUX && clk_stm32_has_safe_mux(hw)) ++ clk_stm32_safe_restore_position_mux(hw); ++ ++ return 0; ++} ++ ++void clk_stm32_composite_gate_disable(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ ++ if (composite->gate_id == NO_STM32_GATE) ++ return; ++ ++ clk_stm32_composite_gate_endisable(hw, 0); ++ ++ if (composite->mux_id != NO_STM32_MUX && clk_stm32_has_safe_mux(hw)) ++ clk_stm32_set_safe_position_mux(hw); ++} ++ ++int clk_stm32_composite_is_enabled(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ ++ if (composite->gate_id == NO_STM32_GATE) ++ return (__clk_get_enable_count(hw->clk) > 0); ++ ++ return clk_stm32_is_enabled_gate(composite->base, composite->clock_data, ++ composite->gate_id); ++} ++ ++static void clk_stm32_composite_disable_unused(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ unsigned long flags = 0; ++ ++ if (composite->gate_id == NO_STM32_GATE) ++ return; ++ ++ spin_lock_irqsave(composite->lock, flags); ++ ++ clk_stm32_disable_unused_gate(composite->base, composite->clock_data, ++ composite->gate_id); ++ ++ spin_unlock_irqrestore(composite->lock, flags); ++} ++ ++u8 clk_stm32_get_parent_mux(void __iomem *base, ++ struct clk_stm32_clock_data *data, u16 mux_id) ++{ ++ const struct stm32_mux_cfg *mux = &data->muxes[mux_id]; ++ u32 mask = BIT(mux->width) - 1; ++ u32 val; ++ ++ val = readl(base + mux->offset) >> mux->shift; ++ val &= mask; ++ ++ return val; ++} ++ ++int clk_stm32_set_parent_mux(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 mux_id, u8 index) ++{ ++ const struct stm32_mux_cfg *mux = &data->muxes[mux_id]; ++ ++ u32 mask = BIT(mux->width) - 1; ++ u32 reg = readl(base + mux->offset); ++ u32 val = index << mux->shift; ++ ++ reg &= ~(mask << mux->shift); ++ reg |= val; ++ ++ writel(reg, base + mux->offset); ++ ++ return 0; ++} ++ ++u8 clk_stm32_composite_get_parent(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ ++ return clk_stm32_get_parent_mux(composite->base, composite->clock_data, ++ composite->mux_id); ++} ++ ++int clk_stm32_composite_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(composite->lock, flags); ++ ++ clk_stm32_set_parent_mux(composite->base, composite->clock_data, ++ composite->mux_id, index); ++ ++ spin_unlock_irqrestore(composite->lock, flags); ++ ++ if (composite->clock_data->is_multi_mux) { ++ struct clk_hw *other_mux_hw = composite->clock_data->is_multi_mux(hw); ++ ++ if (other_mux_hw) { ++ struct clk_hw *hwp = clk_hw_get_parent_by_index(hw, index); ++ ++ clk_hw_reparent(other_mux_hw, hwp); ++ } ++ } ++ return 0; ++} ++ ++static unsigned int _get_table_div(const struct clk_div_table *table, ++ unsigned int val) ++{ ++ const struct clk_div_table *clkt; ++ ++ for (clkt = table; clkt->div; clkt++) ++ if (clkt->val == val) ++ return clkt->div; ++ return 0; ++} ++ ++static unsigned int _get_div(const struct clk_div_table *table, ++ unsigned int val, unsigned long flags, u8 width) ++{ ++ if (flags & CLK_DIVIDER_ONE_BASED) ++ return val; ++ if (flags & CLK_DIVIDER_POWER_OF_TWO) ++ return 1 << val; ++ if (table) ++ return _get_table_div(table, val); ++ return val + 1; ++} ++ ++unsigned long clk_stm32_get_rate_divider(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 div_id, unsigned long parent_rate) ++{ ++ const struct stm32_div_cfg *divider = &data->dividers[div_id]; ++ unsigned int val; ++ unsigned int div; ++ ++ val = readl(base + divider->offset) >> divider->shift; ++ val &= clk_div_mask(divider->width); ++ div = _get_div(divider->table, val, divider->flags, divider->width); ++ ++ if (!div) { ++ WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), ++ "%d: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", ++ div_id); ++ return parent_rate; ++ } ++ ++ return DIV_ROUND_UP_ULL((u64)parent_rate, div); ++} ++ ++unsigned long clk_stm32_composite_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ ++ if (composite->div_id == NO_STM32_DIV) ++ return parent_rate; ++ ++ return clk_stm32_get_rate_divider(composite->base, ++ composite->clock_data, ++ composite->div_id, ++ parent_rate); ++} ++ ++int clk_stm32_set_rate_divider(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 div_id, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ const struct stm32_div_cfg *divider = &data->dividers[div_id]; ++ int value; ++ u32 val; ++ ++ value = divider_get_val(rate, parent_rate, divider->table, ++ divider->width, divider->flags); ++ if (value < 0) ++ return value; ++ ++ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { ++ val = clk_div_mask(divider->width) << (divider->shift + 16); ++ } else { ++ val = readl(base + divider->offset); ++ val &= ~(clk_div_mask(divider->width) << divider->shift); ++ } ++ ++ val |= (u32)value << divider->shift; ++ ++ writel(val, base + divider->offset); ++ ++ return 0; ++} ++ ++int clk_stm32_composite_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ unsigned long flags = 0; ++ int ret; ++ ++ if (composite->div_id == NO_STM32_DIV) ++ return rate; ++ ++ spin_lock_irqsave(composite->lock, flags); ++ ++ ret = clk_stm32_set_rate_divider(composite->base, composite->clock_data, ++ composite->div_id, rate, parent_rate); ++ ++ spin_unlock_irqrestore(composite->lock, flags); ++ ++ return ret; ++} ++ ++long clk_stm32_composite_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ ++ const struct stm32_div_cfg *divider; ++ ++ if (composite->div_id == NO_STM32_DIV) ++ return rate; ++ ++ divider = &composite->clock_data->dividers[composite->div_id]; ++ ++ /* if read only, just return current value */ ++ if (divider->flags & CLK_DIVIDER_READ_ONLY) { ++ u32 val; ++ ++ val = readl(composite->base + divider->offset) >> divider->shift; ++ val &= clk_div_mask(divider->width); ++ ++ return divider_ro_round_rate(hw, rate, prate, divider->table, ++ divider->width, divider->flags, ++ val); ++ } ++ ++ return divider_round_rate_parent(hw, clk_hw_get_parent(hw), ++ rate, prate, divider->table, ++ divider->width, divider->flags); ++} ++ ++const struct clk_ops clk_stm32_composite_ops = { ++ .set_rate = clk_stm32_composite_set_rate, ++ .recalc_rate = clk_stm32_composite_recalc_rate, ++ .round_rate = clk_stm32_composite_round_rate, ++ .get_parent = clk_stm32_composite_get_parent, ++ .set_parent = clk_stm32_composite_set_parent, ++ .enable = clk_stm32_composite_gate_enable, ++ .disable = clk_stm32_composite_gate_disable, ++ .is_enabled = clk_stm32_composite_is_enabled, ++ .disable_unused = clk_stm32_composite_disable_unused, ++}; ++ ++u8 clk_stm32_mux_get_parent(struct clk_hw *hw) ++{ ++ struct clk_stm32_mux *mux = to_clk_stm32_mux(hw); ++ ++ return clk_stm32_get_parent_mux(mux->base, mux->clock_data, ++ mux->mux_id); ++} ++ ++int clk_stm32_mux_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct clk_stm32_mux *mux = to_clk_stm32_mux(hw); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(mux->lock, flags); ++ ++ clk_stm32_set_parent_mux(mux->base, mux->clock_data, ++ mux->mux_id, index); ++ ++ spin_unlock_irqrestore(mux->lock, flags); ++ ++ return 0; ++} ++ ++const struct clk_ops clk_stm32_mux_ops = { ++ .get_parent = clk_stm32_mux_get_parent, ++ .set_parent = clk_stm32_mux_set_parent, ++}; ++ ++static int clk_stm32_divider_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_stm32_div *div = to_clk_stm32_divider(hw); ++ unsigned long flags = 0; ++ int ret; ++ ++ if (div->div_id == NO_STM32_DIV) ++ return rate; ++ ++ spin_lock_irqsave(div->lock, flags); ++ ++ ret = clk_stm32_set_rate_divider(div->base, div->clock_data, div->div_id, ++ rate, parent_rate); ++ ++ spin_unlock_irqrestore(div->lock, flags); ++ ++ return ret; ++ ++} ++ ++static long clk_stm32_divider_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_stm32_div *div = to_clk_stm32_divider(hw); ++ const struct stm32_div_cfg *divider; ++ ++ if (div->div_id == NO_STM32_DIV) ++ return rate; ++ ++ divider = &div->clock_data->dividers[div->div_id]; ++ ++ /* if read only, just return current value */ ++ if (divider->flags & CLK_DIVIDER_READ_ONLY) { ++ u32 val; ++ ++ val = readl(div->base + divider->offset) >> divider->shift; ++ val &= clk_div_mask(divider->width); ++ ++ return divider_ro_round_rate(hw, rate, prate, divider->table, ++ divider->width, divider->flags, ++ val); ++ } ++ ++ return divider_round_rate_parent(hw, clk_hw_get_parent(hw), ++ rate, prate, divider->table, ++ divider->width, divider->flags); ++} ++ ++static unsigned long clk_stm32_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_stm32_div *div = to_clk_stm32_divider(hw); ++ ++ if (div->div_id == NO_STM32_DIV) ++ return parent_rate; ++ ++ return clk_stm32_get_rate_divider(div->base, div->clock_data, ++ div->div_id, parent_rate); ++} ++ ++const struct clk_ops clk_stm32_divider_ops = { ++ .recalc_rate = clk_stm32_divider_recalc_rate, ++ .round_rate = clk_stm32_divider_round_rate, ++ .set_rate = clk_stm32_divider_set_rate, ++}; ++ ++/* Clock register function */ ++struct clk_hw *clk_stm32_gate_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg) ++{ ++ struct clk_stm32_gate *gate = cfg->clock_cfg; ++ struct clk_hw *hw = &gate->hw; ++ const struct clk_init_data *init_data = hw->init; ++ int err; ++ ++ gate->base = base; ++ gate->lock = lock; ++ gate->clock_data = data->clock_data; ++ ++ err = clk_hw_register(dev, hw); ++ if (err) { ++ dev_err(dev, "Can't register clk %s: %ld\n", init_data->name, PTR_ERR(hw)); ++ return ERR_PTR(err); ++ } ++ ++ return hw; ++} ++ ++struct clk_hw *clk_stm32_div_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg) ++{ ++ struct clk_stm32_div *div = cfg->clock_cfg; ++ struct clk_hw *hw = &div->hw; ++ const struct clk_init_data *init_data = hw->init; ++ int err; ++ ++ div->base = base; ++ div->lock = lock; ++ div->clock_data = data->clock_data; ++ ++ err = clk_hw_register(dev, hw); ++ if (err) { ++ dev_err(dev, "Can't register clk %s: %ld\n", init_data->name, PTR_ERR(hw)); ++ return ERR_PTR(err); ++ } ++ ++ return hw; ++} ++ ++struct clk_hw *clk_stm32_mux_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg) ++{ ++ struct clk_stm32_mux *mux = cfg->clock_cfg; ++ struct clk_hw *hw = &mux->hw; ++ const struct clk_init_data *init_data = hw->init; ++ int err; ++ ++ mux->base = base; ++ mux->lock = lock; ++ mux->clock_data = data->clock_data; ++ ++ err = clk_hw_register(dev, hw); ++ if (err) { ++ dev_err(dev, "Can't register clk %s: %ld\n", init_data->name, PTR_ERR(hw)); ++ return ERR_PTR(err); ++ } ++ ++ return hw; ++} ++ ++struct clk_hw *clk_stm32_composite_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg) ++{ ++ struct clk_stm32_composite *composite = cfg->clock_cfg; ++ struct clk_hw *hw = &composite->hw; ++ const struct clk_init_data *init_data = hw->init; ++ int err; ++ ++ composite->base = base; ++ composite->lock = lock; ++ composite->clock_data = data->clock_data; ++ ++ err = clk_hw_register(dev, hw); ++ if (err) { ++ dev_err(dev, "Can't register clk %s: %ld\n", init_data->name, PTR_ERR(hw)); ++ return ERR_PTR(err); ++ } ++ ++ return hw; ++} +diff --git a/drivers/clk/stm32/clk-stm32-core.h b/drivers/clk/stm32/clk-stm32-core.h +new file mode 100644 +index 000000000..63e62878b +--- /dev/null ++++ b/drivers/clk/stm32/clk-stm32-core.h +@@ -0,0 +1,243 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++#include ++ ++struct stm32_rcc_match_data; ++ ++struct stm32_mux_cfg { ++ u16 offset; ++ u8 shift; ++ u8 width; ++ u8 flags; ++ u32 *table; ++ u8 ready; ++}; ++ ++struct stm32_gate_cfg { ++ u16 offset; ++ u8 bit_idx; ++ u8 set_clr; ++}; ++ ++struct stm32_div_cfg { ++ u16 offset; ++ u8 shift; ++ u8 width; ++ u8 flags; ++ u8 ready; ++ const struct clk_div_table *table; ++}; ++ ++struct stm32_composite_cfg { ++ int mux; ++ int gate; ++ int div; ++}; ++ ++#define NO_ID 0xFFFF0000 ++ ++#define NO_STM32_MUX 0xFFFF ++#define NO_STM32_DIV 0xFFFF ++#define NO_STM32_GATE 0xFFFF ++ ++struct clock_config { ++ unsigned long id; ++ int sec_id; ++ void *clock_cfg; ++ ++ struct clk_hw *(*func)(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg); ++}; ++ ++struct clk_stm32_clock_data { ++ u16 *gate_cpt; ++ const struct stm32_gate_cfg *gates; ++ const struct stm32_mux_cfg *muxes; ++ const struct stm32_div_cfg *dividers; ++ struct clk_hw *(*is_multi_mux)(struct clk_hw *hw); ++}; ++ ++struct stm32_rcc_match_data { ++ struct clk_hw_onecell_data *hw_clks; ++ unsigned int num_clocks; ++ const struct clock_config *tab_clocks; ++ unsigned int maxbinding; ++ struct clk_stm32_clock_data *clock_data; ++ int (*multi_mux)(void __iomem *base, const struct clock_config *cfg); ++ int (*check_security)(void __iomem *base, const struct clock_config *cfg); ++ u32 clear_offset; ++}; ++ ++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); ++ ++/* MUX define */ ++#define MUX_NO_RDY 0xFF ++#define MUX_SAFE BIT(7) ++ ++/* DIV define */ ++#define DIV_NO_RDY 0xFF ++ ++struct clk_stm32_gate { ++ u16 gate_id; ++ struct clk_hw hw; ++ void __iomem *base; ++ struct clk_stm32_clock_data *clock_data; ++ spinlock_t *lock; /* spin lock */ ++}; ++ ++#define to_clk_stm32_gate(_hw) container_of(_hw, struct clk_stm32_gate, hw) ++ ++struct clk_stm32_mux { ++ u16 mux_id; ++ struct clk_hw hw; ++ void __iomem *base; ++ struct clk_stm32_clock_data *clock_data; ++ spinlock_t *lock; /* spin lock */ ++}; ++ ++#define to_clk_stm32_mux(_hw) container_of(_hw, struct clk_stm32_mux, hw) ++ ++struct clk_stm32_div { ++ u16 div_id; ++ struct clk_hw hw; ++ void __iomem *base; ++ struct clk_stm32_clock_data *clock_data; ++ spinlock_t *lock; /* spin lock */ ++}; ++ ++#define to_clk_stm32_divider(_hw) container_of(_hw, struct clk_stm32_div, hw) ++ ++struct clk_stm32_composite { ++ u16 gate_id; ++ u16 mux_id; ++ u16 div_id; ++ struct clk_hw hw; ++ void __iomem *base; ++ struct clk_stm32_clock_data *clock_data; ++ spinlock_t *lock; /* spin lock */ ++}; ++ ++#define to_clk_stm32_composite(_hw) container_of(_hw, struct clk_stm32_composite, hw) ++ ++void clk_stm32_endisable_gate(void __iomem *base, ++ struct clk_stm32_clock_data *data, u16 gate_id, ++ int enable); ++int clk_stm32_is_enabled_gate(void __iomem *base, ++ struct clk_stm32_clock_data *data, u16 gate_id); ++u8 clk_stm32_get_parent_mux(void __iomem *base, ++ struct clk_stm32_clock_data *data, u16 mux_id); ++int clk_stm32_set_parent_mux(void __iomem *base, ++ struct clk_stm32_clock_data *data, u16 mux_id, ++ u8 index); ++int clk_stm32_set_rate_divider(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 div_id, unsigned long rate, ++ unsigned long parent_rate); ++unsigned long clk_stm32_get_rate_divider(void __iomem *base, ++ struct clk_stm32_clock_data *data, ++ u16 div_id, unsigned long parent_rate); ++ ++void clk_stm32_gate_endisable(struct clk_hw *hw, int enable); ++int clk_stm32_gate_enable(struct clk_hw *hw); ++void clk_stm32_gate_disable(struct clk_hw *hw); ++int clk_stm32_gate_is_enabled(struct clk_hw *hw); ++ ++u8 clk_stm32_mux_get_parent(struct clk_hw *hw); ++int clk_stm32_mux_set_parent(struct clk_hw *hw, u8 index); ++ ++void clk_stm32_composite_gate_endisable(struct clk_hw *hw, int enable); ++int clk_stm32_composite_gate_enable(struct clk_hw *hw); ++void clk_stm32_composite_gate_disable(struct clk_hw *hw); ++int clk_stm32_composite_is_enabled(struct clk_hw *hw); ++u8 clk_stm32_composite_get_parent(struct clk_hw *hw); ++int clk_stm32_composite_set_parent(struct clk_hw *hw, u8 index); ++unsigned long clk_stm32_composite_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate); ++long clk_stm32_composite_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate); ++int clk_stm32_composite_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate); ++ ++struct clk_hw *clk_stm32_gate_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg); ++ ++struct clk_hw *clk_stm32_div_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg); ++ ++struct clk_hw *clk_stm32_mux_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg); ++ ++struct clk_hw *clk_stm32_composite_register(struct device *dev, ++ const struct stm32_rcc_match_data *data, ++ void __iomem *base, ++ spinlock_t *lock, ++ const struct clock_config *cfg); ++ ++extern const struct clk_ops clk_stm32_gate_ops; ++extern const struct clk_ops clk_stm32_divider_ops; ++extern const struct clk_ops clk_stm32_mux_ops; ++extern const struct clk_ops clk_stm32_composite_ops; ++ ++#define PARENT(_parent) ((const char *[]) { _parent}) ++ ++#define CLK_STM32_GATE(_name, _parent, _flags, _gate_id)\ ++struct clk_stm32_gate _name = {\ ++ .gate_id = _gate_id,\ ++ .hw.init = CLK_HW_INIT(#_name, _parent, &clk_stm32_gate_ops, _flags),\ ++} ++ ++#define CLK_STM32_MUX(_name, _parents, _flags, _mux_id)\ ++struct clk_stm32_mux _name = {\ ++ .mux_id = _mux_id,\ ++ .hw.init = CLK_HW_INIT_PARENTS(#_name, _parents, &clk_stm32_mux_ops, _flags),\ ++} ++ ++#define CLK_STM32_DIV(_name, _parent, _flags, _div_id)\ ++struct clk_stm32_div _name = {\ ++ .div_id = _div_id,\ ++ .hw.init = CLK_HW_INIT(#_name, _parent, &clk_stm32_divider_ops, _flags),\ ++} ++ ++#define CLK_STM32_COMPOSITE(_name, _parents, _flags, _gate_id, _mux_id, _div_id)\ ++struct clk_stm32_composite _name = {\ ++ .gate_id = _gate_id,\ ++ .mux_id = _mux_id,\ ++ .div_id = _div_id,\ ++ .hw.init = CLK_HW_INIT_PARENTS(#_name, _parents, &clk_stm32_composite_ops, _flags),\ ++} ++ ++#define STM32_CLOCK_CFG(_binding, _clk, _sec_id, _struct, _register)\ ++{\ ++ .id = (_binding),\ ++ .sec_id = (_sec_id),\ ++ .clock_cfg = (_struct) {_clk},\ ++ .func = (_register),\ ++} ++ ++#define STM32_GATE_CFG(_binding, _clk, _sec_id)\ ++ STM32_CLOCK_CFG(_binding, &(_clk), _sec_id, struct clk_stm32_gate *,\ ++ &clk_stm32_gate_register) ++ ++#define STM32_COMPOSITE_CFG(_binding, _clk, _sec_id)\ ++ STM32_CLOCK_CFG(_binding, &(_clk), _sec_id, struct clk_stm32_composite *,\ ++ &clk_stm32_composite_register) +diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c +new file mode 100644 +index 000000000..9c60a1c7f +--- /dev/null ++++ b/drivers/clk/stm32/clk-stm32mp13.c +@@ -0,0 +1,1062 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk-stm32-core.h" ++#include "stm32mp13_rcc.h" ++ ++#define RCC_CLR 0x4 ++ ++static const char * const adc12_src[] = { ++ "pll4_r", "ck_per", "pll3_q" ++}; ++ ++static const char * const dcmipp_src[] = { ++ "ck_axi", "pll2_q", "pll4_p", "ck_per", ++}; ++ ++static const char * const eth12_src[] = { ++ "pll4_p", "pll3_q" ++}; ++ ++static const char * const fdcan_src[] = { ++ "ck_hse", "pll3_q", "pll4_q", "pll4_r" ++}; ++ ++static const char * const fmc_src[] = { ++ "ck_axi", "pll3_r", "pll4_p", "ck_per" ++}; ++ ++static const char * const i2c12_src[] = { ++ "pclk1", "pll4_r", "ck_hsi", "ck_csi" ++}; ++ ++static const char * const i2c345_src[] = { ++ "pclk6", "pll4_r", "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 mco1_src[] = { ++ "ck_hsi", "ck_hse", "ck_csi", "ck_lsi", "ck_lse" ++}; ++ ++static const char * const mco2_src[] = { ++ "ck_mpu", "ck_axi", "ck_mlahb", "pll4_p", "ck_hse", "ck_hsi" ++}; ++ ++static const char * const qspi_src[] = { ++ "ck_axi", "pll3_r", "pll4_p", "ck_per" ++}; ++ ++static const char * const rng1_src[] = { ++ "ck_csi", "pll4_r", "reserved", "ck_lsi" ++}; ++ ++static const char * const saes_src[] = { ++ "ck_axi", "ck_per", "pll4_r", "ck_lsi" ++}; ++ ++static const char * const sai1_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 sdmmc12_src[] = { ++ "ck_axi", "pll3_r", "pll4_p", "ck_hsi" ++}; ++ ++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 spi4_src[] = { ++ "pclk6", "pll4_q", "ck_hsi", "ck_csi", "ck_hse", "i2s_ckin" ++}; ++ ++static const char * const spi5_src[] = { ++ "pclk6", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" ++}; ++ ++static const char * const stgen_src[] = { ++ "ck_hsi", "ck_hse" ++}; ++ ++static const char * const usart12_src[] = { ++ "pclk6", "pll3_q", "ck_hsi", "ck_csi", "pll4_q", "ck_hse" ++}; ++ ++static const char * const usart34578_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 usbo_src[] = { ++ "pll4_r", "ck_usbo_48m" ++}; ++ ++static const char * const usbphy_src[] = { ++ "ck_hse", "pll4_r", "clk-hse-div2" ++}; ++ ++enum enum_gate_cfg { ++ GATE_MCO1, ++ GATE_MCO2, ++ GATE_DBGCK, ++ GATE_TRACECK, ++ GATE_DDRC1, ++ GATE_DDRC1LP, ++ GATE_DDRPHYC, ++ GATE_DDRPHYCLP, ++ GATE_DDRCAPB, ++ GATE_DDRCAPBLP, ++ GATE_AXIDCG, ++ GATE_DDRPHYCAPB, ++ GATE_DDRPHYCAPBLP, ++ GATE_TIM2, ++ GATE_TIM3, ++ GATE_TIM4, ++ GATE_TIM5, ++ GATE_TIM6, ++ GATE_TIM7, ++ GATE_LPTIM1, ++ GATE_SPI2, ++ GATE_SPI3, ++ GATE_USART3, ++ GATE_UART4, ++ GATE_UART5, ++ GATE_UART7, ++ GATE_UART8, ++ GATE_I2C1, ++ GATE_I2C2, ++ GATE_SPDIF, ++ GATE_TIM1, ++ GATE_TIM8, ++ GATE_SPI1, ++ GATE_USART6, ++ GATE_SAI1, ++ GATE_SAI2, ++ GATE_DFSDM, ++ GATE_ADFSDM, ++ GATE_FDCAN, ++ GATE_LPTIM2, ++ GATE_LPTIM3, ++ GATE_LPTIM4, ++ GATE_LPTIM5, ++ GATE_VREF, ++ GATE_DTS, ++ GATE_PMBCTRL, ++ GATE_HDP, ++ GATE_SYSCFG, ++ GATE_DCMIPP, ++ GATE_DDRPERFM, ++ GATE_IWDG2APB, ++ GATE_USBPHY, ++ GATE_STGENRO, ++ GATE_LTDC, ++ GATE_TZC, ++ GATE_ETZPC, ++ GATE_IWDG1APB, ++ GATE_BSEC, ++ GATE_STGENC, ++ GATE_USART1, ++ GATE_USART2, ++ GATE_SPI4, ++ GATE_SPI5, ++ GATE_I2C3, ++ GATE_I2C4, ++ GATE_I2C5, ++ GATE_TIM12, ++ GATE_TIM13, ++ GATE_TIM14, ++ GATE_TIM15, ++ GATE_TIM16, ++ GATE_TIM17, ++ GATE_DMA1, ++ GATE_DMA2, ++ GATE_DMAMUX1, ++ GATE_DMA3, ++ GATE_DMAMUX2, ++ GATE_ADC1, ++ GATE_ADC2, ++ GATE_USBO, ++ GATE_TSC, ++ GATE_GPIOA, ++ GATE_GPIOB, ++ GATE_GPIOC, ++ GATE_GPIOD, ++ GATE_GPIOE, ++ GATE_GPIOF, ++ GATE_GPIOG, ++ GATE_GPIOH, ++ GATE_GPIOI, ++ GATE_PKA, ++ GATE_SAES, ++ GATE_CRYP1, ++ GATE_HASH1, ++ GATE_RNG1, ++ GATE_BKPSRAM, ++ GATE_AXIMC, ++ GATE_MCE, ++ GATE_ETH1CK, ++ GATE_ETH1TX, ++ GATE_ETH1RX, ++ GATE_ETH1MAC, ++ GATE_FMC, ++ GATE_QSPI, ++ GATE_SDMMC1, ++ GATE_SDMMC2, ++ GATE_CRC1, ++ GATE_USBH, ++ GATE_ETH2CK, ++ GATE_ETH2TX, ++ GATE_ETH2RX, ++ GATE_ETH2MAC, ++ GATE_ETH1STP, ++ GATE_ETH2STP, ++ GATE_MDMA, ++ GATE_NB ++}; ++ ++#define _CFG_GATE(_id, _offset, _bit_idx, _offset_clr)\ ++ [(_id)] = {\ ++ .offset = (_offset),\ ++ .bit_idx = (_bit_idx),\ ++ .set_clr = (_offset_clr),\ ++ } ++ ++#define CFG_GATE(_id, _offset, _bit_idx)\ ++ _CFG_GATE(_id, _offset, _bit_idx, 0) ++ ++#define CFG_GATE_SETCLR(_id, _offset, _bit_idx)\ ++ _CFG_GATE(_id, _offset, _bit_idx, RCC_CLR) ++ ++static struct stm32_gate_cfg stm32mp13_gates[] = { ++ CFG_GATE(GATE_MCO1, RCC_MCO1CFGR, 12), ++ CFG_GATE(GATE_MCO2, RCC_MCO2CFGR, 12), ++ CFG_GATE(GATE_DBGCK, RCC_DBGCFGR, 8), ++ CFG_GATE(GATE_TRACECK, RCC_DBGCFGR, 9), ++ CFG_GATE(GATE_DDRC1, RCC_DDRITFCR, 0), ++ CFG_GATE(GATE_DDRC1LP, RCC_DDRITFCR, 1), ++ CFG_GATE(GATE_DDRPHYC, RCC_DDRITFCR, 4), ++ CFG_GATE(GATE_DDRPHYCLP, RCC_DDRITFCR, 5), ++ CFG_GATE(GATE_DDRCAPB, RCC_DDRITFCR, 6), ++ CFG_GATE(GATE_DDRCAPBLP, RCC_DDRITFCR, 7), ++ CFG_GATE(GATE_AXIDCG, RCC_DDRITFCR, 8), ++ CFG_GATE(GATE_DDRPHYCAPB, RCC_DDRITFCR, 9), ++ CFG_GATE(GATE_DDRPHYCAPBLP, RCC_DDRITFCR, 10), ++ CFG_GATE_SETCLR(GATE_TIM2, RCC_MP_APB1ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_TIM3, RCC_MP_APB1ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_TIM4, RCC_MP_APB1ENSETR, 2), ++ CFG_GATE_SETCLR(GATE_TIM5, RCC_MP_APB1ENSETR, 3), ++ CFG_GATE_SETCLR(GATE_TIM6, RCC_MP_APB1ENSETR, 4), ++ CFG_GATE_SETCLR(GATE_TIM7, RCC_MP_APB1ENSETR, 5), ++ CFG_GATE_SETCLR(GATE_LPTIM1, RCC_MP_APB1ENSETR, 9), ++ CFG_GATE_SETCLR(GATE_SPI2, RCC_MP_APB1ENSETR, 11), ++ CFG_GATE_SETCLR(GATE_SPI3, RCC_MP_APB1ENSETR, 12), ++ CFG_GATE_SETCLR(GATE_USART3, RCC_MP_APB1ENSETR, 15), ++ CFG_GATE_SETCLR(GATE_UART4, RCC_MP_APB1ENSETR, 16), ++ CFG_GATE_SETCLR(GATE_UART5, RCC_MP_APB1ENSETR, 17), ++ CFG_GATE_SETCLR(GATE_UART7, RCC_MP_APB1ENSETR, 18), ++ CFG_GATE_SETCLR(GATE_UART8, RCC_MP_APB1ENSETR, 19), ++ CFG_GATE_SETCLR(GATE_I2C1, RCC_MP_APB1ENSETR, 21), ++ CFG_GATE_SETCLR(GATE_I2C2, RCC_MP_APB1ENSETR, 22), ++ CFG_GATE_SETCLR(GATE_SPDIF, RCC_MP_APB1ENSETR, 26), ++ CFG_GATE_SETCLR(GATE_TIM1, RCC_MP_APB2ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_TIM8, RCC_MP_APB2ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_SPI1, RCC_MP_APB2ENSETR, 8), ++ CFG_GATE_SETCLR(GATE_USART6, RCC_MP_APB2ENSETR, 13), ++ CFG_GATE_SETCLR(GATE_SAI1, RCC_MP_APB2ENSETR, 16), ++ CFG_GATE_SETCLR(GATE_SAI2, RCC_MP_APB2ENSETR, 17), ++ CFG_GATE_SETCLR(GATE_DFSDM, RCC_MP_APB2ENSETR, 20), ++ CFG_GATE_SETCLR(GATE_ADFSDM, RCC_MP_APB2ENSETR, 21), ++ CFG_GATE_SETCLR(GATE_FDCAN, RCC_MP_APB2ENSETR, 24), ++ CFG_GATE_SETCLR(GATE_LPTIM2, RCC_MP_APB3ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_LPTIM3, RCC_MP_APB3ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_LPTIM4, RCC_MP_APB3ENSETR, 2), ++ CFG_GATE_SETCLR(GATE_LPTIM5, RCC_MP_APB3ENSETR, 3), ++ CFG_GATE_SETCLR(GATE_VREF, RCC_MP_APB3ENSETR, 13), ++ CFG_GATE_SETCLR(GATE_DTS, RCC_MP_APB3ENSETR, 16), ++ CFG_GATE_SETCLR(GATE_PMBCTRL, RCC_MP_APB3ENSETR, 17), ++ CFG_GATE_SETCLR(GATE_HDP, RCC_MP_APB3ENSETR, 20), ++ CFG_GATE_SETCLR(GATE_SYSCFG, RCC_MP_NS_APB3ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_DCMIPP, RCC_MP_APB4ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_DDRPERFM, RCC_MP_APB4ENSETR, 8), ++ CFG_GATE_SETCLR(GATE_IWDG2APB, RCC_MP_APB4ENSETR, 15), ++ CFG_GATE_SETCLR(GATE_USBPHY, RCC_MP_APB4ENSETR, 16), ++ CFG_GATE_SETCLR(GATE_STGENRO, RCC_MP_APB4ENSETR, 20), ++ CFG_GATE_SETCLR(GATE_LTDC, RCC_MP_NS_APB4ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_TZC, RCC_MP_APB5ENSETR, 11), ++ CFG_GATE_SETCLR(GATE_ETZPC, RCC_MP_APB5ENSETR, 13), ++ CFG_GATE_SETCLR(GATE_IWDG1APB, RCC_MP_APB5ENSETR, 15), ++ CFG_GATE_SETCLR(GATE_BSEC, RCC_MP_APB5ENSETR, 16), ++ CFG_GATE_SETCLR(GATE_STGENC, RCC_MP_APB5ENSETR, 20), ++ CFG_GATE_SETCLR(GATE_USART1, RCC_MP_APB6ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_USART2, RCC_MP_APB6ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_SPI4, RCC_MP_APB6ENSETR, 2), ++ CFG_GATE_SETCLR(GATE_SPI5, RCC_MP_APB6ENSETR, 3), ++ CFG_GATE_SETCLR(GATE_I2C3, RCC_MP_APB6ENSETR, 4), ++ CFG_GATE_SETCLR(GATE_I2C4, RCC_MP_APB6ENSETR, 5), ++ CFG_GATE_SETCLR(GATE_I2C5, RCC_MP_APB6ENSETR, 6), ++ CFG_GATE_SETCLR(GATE_TIM12, RCC_MP_APB6ENSETR, 7), ++ CFG_GATE_SETCLR(GATE_TIM13, RCC_MP_APB6ENSETR, 8), ++ CFG_GATE_SETCLR(GATE_TIM14, RCC_MP_APB6ENSETR, 9), ++ CFG_GATE_SETCLR(GATE_TIM15, RCC_MP_APB6ENSETR, 10), ++ CFG_GATE_SETCLR(GATE_TIM16, RCC_MP_APB6ENSETR, 11), ++ CFG_GATE_SETCLR(GATE_TIM17, RCC_MP_APB6ENSETR, 12), ++ CFG_GATE_SETCLR(GATE_DMA1, RCC_MP_AHB2ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_DMA2, RCC_MP_AHB2ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_DMAMUX1, RCC_MP_AHB2ENSETR, 2), ++ CFG_GATE_SETCLR(GATE_DMA3, RCC_MP_AHB2ENSETR, 3), ++ CFG_GATE_SETCLR(GATE_DMAMUX2, RCC_MP_AHB2ENSETR, 4), ++ CFG_GATE_SETCLR(GATE_ADC1, RCC_MP_AHB2ENSETR, 5), ++ CFG_GATE_SETCLR(GATE_ADC2, RCC_MP_AHB2ENSETR, 6), ++ CFG_GATE_SETCLR(GATE_USBO, RCC_MP_AHB2ENSETR, 8), ++ CFG_GATE_SETCLR(GATE_TSC, RCC_MP_AHB4ENSETR, 15), ++ CFG_GATE_SETCLR(GATE_GPIOA, RCC_MP_NS_AHB4ENSETR, 0), ++ CFG_GATE_SETCLR(GATE_GPIOB, RCC_MP_NS_AHB4ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_GPIOC, RCC_MP_NS_AHB4ENSETR, 2), ++ CFG_GATE_SETCLR(GATE_GPIOD, RCC_MP_NS_AHB4ENSETR, 3), ++ CFG_GATE_SETCLR(GATE_GPIOE, RCC_MP_NS_AHB4ENSETR, 4), ++ CFG_GATE_SETCLR(GATE_GPIOF, RCC_MP_NS_AHB4ENSETR, 5), ++ CFG_GATE_SETCLR(GATE_GPIOG, RCC_MP_NS_AHB4ENSETR, 6), ++ CFG_GATE_SETCLR(GATE_GPIOH, RCC_MP_NS_AHB4ENSETR, 7), ++ CFG_GATE_SETCLR(GATE_GPIOI, RCC_MP_NS_AHB4ENSETR, 8), ++ CFG_GATE_SETCLR(GATE_PKA, RCC_MP_AHB5ENSETR, 2), ++ CFG_GATE_SETCLR(GATE_SAES, RCC_MP_AHB5ENSETR, 3), ++ CFG_GATE_SETCLR(GATE_CRYP1, RCC_MP_AHB5ENSETR, 4), ++ CFG_GATE_SETCLR(GATE_HASH1, RCC_MP_AHB5ENSETR, 5), ++ CFG_GATE_SETCLR(GATE_RNG1, RCC_MP_AHB5ENSETR, 6), ++ CFG_GATE_SETCLR(GATE_BKPSRAM, RCC_MP_AHB5ENSETR, 8), ++ CFG_GATE_SETCLR(GATE_AXIMC, RCC_MP_AHB5ENSETR, 16), ++ CFG_GATE_SETCLR(GATE_MCE, RCC_MP_AHB6ENSETR, 1), ++ CFG_GATE_SETCLR(GATE_ETH1CK, RCC_MP_AHB6ENSETR, 7), ++ CFG_GATE_SETCLR(GATE_ETH1TX, RCC_MP_AHB6ENSETR, 8), ++ CFG_GATE_SETCLR(GATE_ETH1RX, RCC_MP_AHB6ENSETR, 9), ++ CFG_GATE_SETCLR(GATE_ETH1MAC, RCC_MP_AHB6ENSETR, 10), ++ CFG_GATE_SETCLR(GATE_FMC, RCC_MP_AHB6ENSETR, 12), ++ CFG_GATE_SETCLR(GATE_QSPI, RCC_MP_AHB6ENSETR, 14), ++ CFG_GATE_SETCLR(GATE_SDMMC1, RCC_MP_AHB6ENSETR, 16), ++ CFG_GATE_SETCLR(GATE_SDMMC2, RCC_MP_AHB6ENSETR, 17), ++ CFG_GATE_SETCLR(GATE_CRC1, RCC_MP_AHB6ENSETR, 20), ++ CFG_GATE_SETCLR(GATE_USBH, RCC_MP_AHB6ENSETR, 24), ++ CFG_GATE_SETCLR(GATE_ETH2CK, RCC_MP_AHB6ENSETR, 27), ++ CFG_GATE_SETCLR(GATE_ETH2TX, RCC_MP_AHB6ENSETR, 28), ++ CFG_GATE_SETCLR(GATE_ETH2RX, RCC_MP_AHB6ENSETR, 29), ++ CFG_GATE_SETCLR(GATE_ETH2MAC, RCC_MP_AHB6ENSETR, 30), ++ CFG_GATE_SETCLR(GATE_ETH1STP, RCC_MP_AHB6LPENSETR, 11), ++ CFG_GATE_SETCLR(GATE_ETH2STP, RCC_MP_AHB6LPENSETR, 31), ++ CFG_GATE_SETCLR(GATE_MDMA, RCC_MP_NS_AHB6ENSETR, 0), ++}; ++ ++enum enum_mux_cfg { ++ MUX_I2C12, ++ MUX_LPTIM45, ++ MUX_SPI23, ++ MUX_UART35, ++ MUX_UART78, ++ MUX_ADC1, ++ MUX_ADC2, ++ MUX_DCMIPP, ++ MUX_ETH1, ++ MUX_ETH2, ++ MUX_FDCAN, ++ MUX_FMC, ++ MUX_I2C3, ++ MUX_I2C4, ++ MUX_I2C5, ++ MUX_LPTIM1, ++ MUX_LPTIM2, ++ MUX_LPTIM3, ++ MUX_QSPI, ++ MUX_RNG1, ++ MUX_SAES, ++ MUX_SAI1, ++ MUX_SAI2, ++ MUX_SDMMC1, ++ MUX_SDMMC2, ++ MUX_SPDIF, ++ MUX_SPI1, ++ MUX_SPI4, ++ MUX_SPI5, ++ MUX_STGEN, ++ MUX_UART1, ++ MUX_UART2, ++ MUX_UART4, ++ MUX_UART6, ++ MUX_USBO, ++ MUX_USBPHY, ++ MUX_MCO1, ++ MUX_MCO2, ++ MUX_NB ++}; ++ ++#define _CFG_MUX(_id, _offset, _shift, _witdh, _ready, _flags)\ ++ [_id] = {\ ++ .offset = (_offset),\ ++ .shift = (_shift),\ ++ .width = (_witdh),\ ++ .ready = (_ready),\ ++ .flags = (_flags),\ ++ } ++ ++#define CFG_MUX(_id, _offset, _shift, _witdh)\ ++ _CFG_MUX(_id, _offset, _shift, _witdh, MUX_NO_RDY, 0) ++ ++#define CFG_MUX_RDY(_id, _offset, _shift, _witdh, _ready)\ ++ _CFG_MUX(_id, _offset, _shift, _witdh, _ready, 0) ++ ++#define CFG_MUX_SAFE(_id, _offset, _shift, _witdh)\ ++ _CFG_MUX(_id, _offset, _shift, _witdh, MUX_NO_RDY, MUX_SAFE) ++ ++static const struct stm32_mux_cfg stm32mp13_muxes[] = { ++ CFG_MUX(MUX_I2C12, RCC_I2C12CKSELR, 0, 3), ++ CFG_MUX(MUX_LPTIM45, RCC_LPTIM45CKSELR, 0, 3), ++ CFG_MUX(MUX_SPI23, RCC_SPI2S23CKSELR, 0, 3), ++ CFG_MUX(MUX_UART35, RCC_UART35CKSELR, 0, 3), ++ CFG_MUX(MUX_UART78, RCC_UART78CKSELR, 0, 3), ++ CFG_MUX(MUX_ADC1, RCC_ADC12CKSELR, 0, 2), ++ CFG_MUX(MUX_ADC2, RCC_ADC12CKSELR, 2, 2), ++ CFG_MUX(MUX_DCMIPP, RCC_DCMIPPCKSELR, 0, 2), ++ CFG_MUX(MUX_ETH1, RCC_ETH12CKSELR, 0, 2), ++ CFG_MUX(MUX_ETH2, RCC_ETH12CKSELR, 8, 2), ++ CFG_MUX(MUX_FDCAN, RCC_FDCANCKSELR, 0, 2), ++ CFG_MUX(MUX_I2C3, RCC_I2C345CKSELR, 0, 3), ++ CFG_MUX(MUX_I2C4, RCC_I2C345CKSELR, 3, 3), ++ CFG_MUX(MUX_I2C5, RCC_I2C345CKSELR, 6, 3), ++ CFG_MUX(MUX_LPTIM1, RCC_LPTIM1CKSELR, 0, 3), ++ CFG_MUX(MUX_LPTIM2, RCC_LPTIM23CKSELR, 0, 3), ++ CFG_MUX(MUX_LPTIM3, RCC_LPTIM23CKSELR, 3, 3), ++ CFG_MUX(MUX_MCO1, RCC_MCO1CFGR, 0, 3), ++ CFG_MUX(MUX_MCO2, RCC_MCO2CFGR, 0, 3), ++ CFG_MUX(MUX_RNG1, RCC_RNG1CKSELR, 0, 2), ++ CFG_MUX(MUX_SAES, RCC_SAESCKSELR, 0, 2), ++ CFG_MUX(MUX_SAI1, RCC_SAI1CKSELR, 0, 3), ++ CFG_MUX(MUX_SAI2, RCC_SAI2CKSELR, 0, 3), ++ CFG_MUX(MUX_SPDIF, RCC_SPDIFCKSELR, 0, 2), ++ CFG_MUX(MUX_SPI1, RCC_SPI2S1CKSELR, 0, 3), ++ CFG_MUX(MUX_SPI4, RCC_SPI45CKSELR, 0, 3), ++ CFG_MUX(MUX_SPI5, RCC_SPI45CKSELR, 3, 3), ++ CFG_MUX(MUX_STGEN, RCC_STGENCKSELR, 0, 2), ++ CFG_MUX(MUX_UART1, RCC_UART12CKSELR, 0, 3), ++ CFG_MUX(MUX_UART2, RCC_UART12CKSELR, 3, 3), ++ CFG_MUX(MUX_UART4, RCC_UART4CKSELR, 0, 3), ++ CFG_MUX(MUX_UART6, RCC_UART6CKSELR, 0, 3), ++ CFG_MUX(MUX_USBO, RCC_USBCKSELR, 4, 1), ++ CFG_MUX(MUX_USBPHY, RCC_USBCKSELR, 0, 2), ++ ++ CFG_MUX_SAFE(MUX_FMC, RCC_FMCCKSELR, 0, 2), ++ CFG_MUX_SAFE(MUX_QSPI, RCC_QSPICKSELR, 0, 2), ++ CFG_MUX_SAFE(MUX_SDMMC1, RCC_SDMMC12CKSELR, 0, 3), ++ CFG_MUX_SAFE(MUX_SDMMC2, RCC_SDMMC12CKSELR, 3, 3), ++}; ++ ++enum enum_div_cfg { ++ DIV_MCO1, ++ DIV_MCO2, ++ DIV_TRACE, ++ DIV_ETH1PTP, ++ DIV_ETH2PTP, ++ DIV_NB ++}; ++ ++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 CFG_DIV(_id, _offset, _shift, _width, _flags, _table, _ready)\ ++ [(_id)] = {\ ++ .offset = (_offset),\ ++ .shift = (_shift),\ ++ .width = (_width),\ ++ .flags = (_flags),\ ++ .table = (_table),\ ++ .ready = (_ready),\ ++ } ++ ++static const struct stm32_div_cfg stm32mp13_dividers[DIV_NB] = { ++ CFG_DIV(DIV_MCO1, RCC_MCO1CFGR, 4, 4, 0, NULL, DIV_NO_RDY), ++ CFG_DIV(DIV_MCO2, RCC_MCO2CFGR, 4, 4, 0, NULL, DIV_NO_RDY), ++ CFG_DIV(DIV_TRACE, RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table, DIV_NO_RDY), ++ CFG_DIV(DIV_ETH1PTP, RCC_ETH12CKSELR, 4, 4, 0, NULL, DIV_NO_RDY), ++ CFG_DIV(DIV_ETH2PTP, RCC_ETH12CKSELR, 12, 4, 0, NULL, DIV_NO_RDY), ++}; ++ ++struct clk_stm32_securiy { ++ u16 offset; ++ u8 bit_idx; ++}; ++ ++enum securit_clk { ++ SECF_NONE, ++ SECF_LPTIM2, ++ SECF_LPTIM3, ++ SECF_VREF, ++ SECF_DCMIPP, ++ SECF_USBPHY, ++ SECF_RTC, ++ SECF_TZC, ++ SECF_ETZPC, ++ SECF_IWDG1, ++ SECF_BSEC, ++ SECF_STGENC, ++ SECF_STGENRO, ++ SECF_USART1, ++ SECF_USART2, ++ SECF_SPI4, ++ SECF_SPI5, ++ SECF_I2C3, ++ SECF_I2C4, ++ SECF_I2C5, ++ SECF_TIM12, ++ SECF_TIM13, ++ SECF_TIM14, ++ SECF_TIM15, ++ SECF_TIM16, ++ SECF_TIM17, ++ SECF_DMA3, ++ SECF_DMAMUX2, ++ SECF_ADC1, ++ SECF_ADC2, ++ SECF_USBO, ++ SECF_TSC, ++ SECF_PKA, ++ SECF_SAES, ++ SECF_CRYP1, ++ SECF_HASH1, ++ SECF_RNG1, ++ SECF_BKPSRAM, ++ SECF_MCE, ++ SECF_FMC, ++ SECF_QSPI, ++ SECF_SDMMC1, ++ SECF_SDMMC2, ++ SECF_ETH1CK, ++ SECF_ETH1TX, ++ SECF_ETH1RX, ++ SECF_ETH1MAC, ++ SECF_ETH1STP, ++ SECF_ETH2CK, ++ SECF_ETH2TX, ++ SECF_ETH2RX, ++ SECF_ETH2MAC, ++ SECF_ETH2STP, ++ SECF_MCO1, ++ SECF_MCO2 ++}; ++ ++#define SECF(_sec_id, _offset, _bit_idx)[_sec_id] = {\ ++ .offset = _offset,\ ++ .bit_idx = _bit_idx,\ ++} ++ ++static const struct clk_stm32_securiy stm32mp13_security[] = { ++ SECF(SECF_LPTIM2, RCC_APB3SECSR, RCC_APB3SECSR_LPTIM2SECF), ++ SECF(SECF_LPTIM3, RCC_APB3SECSR, RCC_APB3SECSR_LPTIM3SECF), ++ SECF(SECF_VREF, RCC_APB3SECSR, RCC_APB3SECSR_VREFSECF), ++ SECF(SECF_DCMIPP, RCC_APB4SECSR, RCC_APB4SECSR_DCMIPPSECF), ++ SECF(SECF_USBPHY, RCC_APB4SECSR, RCC_APB4SECSR_USBPHYSECF), ++ SECF(SECF_RTC, RCC_APB5SECSR, RCC_APB5SECSR_RTCSECF), ++ SECF(SECF_TZC, RCC_APB5SECSR, RCC_APB5SECSR_TZCSECF), ++ SECF(SECF_ETZPC, RCC_APB5SECSR, RCC_APB5SECSR_ETZPCSECF), ++ SECF(SECF_IWDG1, RCC_APB5SECSR, RCC_APB5SECSR_IWDG1SECF), ++ SECF(SECF_BSEC, RCC_APB5SECSR, RCC_APB5SECSR_BSECSECF), ++ SECF(SECF_STGENC, RCC_APB5SECSR, RCC_APB5SECSR_STGENCSECF), ++ SECF(SECF_STGENRO, RCC_APB5SECSR, RCC_APB5SECSR_STGENROSECF), ++ SECF(SECF_USART1, RCC_APB6SECSR, RCC_APB6SECSR_USART1SECF), ++ SECF(SECF_USART2, RCC_APB6SECSR, RCC_APB6SECSR_USART2SECF), ++ SECF(SECF_SPI4, RCC_APB6SECSR, RCC_APB6SECSR_SPI4SECF), ++ SECF(SECF_SPI5, RCC_APB6SECSR, RCC_APB6SECSR_SPI5SECF), ++ SECF(SECF_I2C3, RCC_APB6SECSR, RCC_APB6SECSR_I2C3SECF), ++ SECF(SECF_I2C4, RCC_APB6SECSR, RCC_APB6SECSR_I2C4SECF), ++ SECF(SECF_I2C5, RCC_APB6SECSR, RCC_APB6SECSR_I2C5SECF), ++ SECF(SECF_TIM12, RCC_APB6SECSR, RCC_APB6SECSR_TIM12SECF), ++ SECF(SECF_TIM13, RCC_APB6SECSR, RCC_APB6SECSR_TIM13SECF), ++ SECF(SECF_TIM14, RCC_APB6SECSR, RCC_APB6SECSR_TIM14SECF), ++ SECF(SECF_TIM15, RCC_APB6SECSR, RCC_APB6SECSR_TIM15SECF), ++ SECF(SECF_TIM16, RCC_APB6SECSR, RCC_APB6SECSR_TIM16SECF), ++ SECF(SECF_TIM17, RCC_APB6SECSR, RCC_APB6SECSR_TIM17SECF), ++ SECF(SECF_DMA3, RCC_AHB2SECSR, RCC_AHB2SECSR_DMA3SECF), ++ SECF(SECF_DMAMUX2, RCC_AHB2SECSR, RCC_AHB2SECSR_DMAMUX2SECF), ++ SECF(SECF_ADC1, RCC_AHB2SECSR, RCC_AHB2SECSR_ADC1SECF), ++ SECF(SECF_ADC2, RCC_AHB2SECSR, RCC_AHB2SECSR_ADC2SECF), ++ SECF(SECF_USBO, RCC_AHB2SECSR, RCC_AHB2SECSR_USBOSECF), ++ SECF(SECF_TSC, RCC_AHB4SECSR, RCC_AHB4SECSR_TSCSECF), ++ SECF(SECF_PKA, RCC_AHB5SECSR, RCC_AHB5SECSR_PKASECF), ++ SECF(SECF_SAES, RCC_AHB5SECSR, RCC_AHB5SECSR_SAESSECF), ++ SECF(SECF_CRYP1, RCC_AHB5SECSR, RCC_AHB5SECSR_CRYP1SECF), ++ SECF(SECF_HASH1, RCC_AHB5SECSR, RCC_AHB5SECSR_HASH1SECF), ++ SECF(SECF_RNG1, RCC_AHB5SECSR, RCC_AHB5SECSR_RNG1SECF), ++ SECF(SECF_BKPSRAM, RCC_AHB5SECSR, RCC_AHB5SECSR_BKPSRAMSECF), ++ SECF(SECF_MCE, RCC_AHB6SECSR, RCC_AHB6SECSR_MCESECF), ++ SECF(SECF_FMC, RCC_AHB6SECSR, RCC_AHB6SECSR_FMCSECF), ++ SECF(SECF_QSPI, RCC_AHB6SECSR, RCC_AHB6SECSR_QSPISECF), ++ SECF(SECF_SDMMC1, RCC_AHB6SECSR, RCC_AHB6SECSR_SDMMC1SECF), ++ SECF(SECF_SDMMC2, RCC_AHB6SECSR, RCC_AHB6SECSR_SDMMC2SECF), ++ SECF(SECF_ETH1CK, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH1CKSECF), ++ SECF(SECF_ETH1TX, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH1TXSECF), ++ SECF(SECF_ETH1RX, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH1RXSECF), ++ SECF(SECF_ETH1MAC, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH1MACSECF), ++ SECF(SECF_ETH1STP, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH1STPSECF), ++ SECF(SECF_ETH2CK, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH2CKSECF), ++ SECF(SECF_ETH2TX, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH2TXSECF), ++ SECF(SECF_ETH2RX, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH2RXSECF), ++ SECF(SECF_ETH2MAC, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH2MACSECF), ++ SECF(SECF_ETH2STP, RCC_AHB6SECSR, RCC_AHB6SECSR_ETH2STPSECF), ++ SECF(SECF_MCO1, RCC_SECCFGR, RCC_SECCFGR_MCO1SECF), ++ SECF(SECF_MCO2, RCC_SECCFGR, RCC_SECCFGR_MCO2SECF), ++}; ++ ++#define CLK_KER(_name, _parents, _flags, _gate_id, _mux_id)\ ++ CLK_STM32_COMPOSITE(_name, _parents, ((_flags) | CLK_OPS_PARENT_ENABLE |\ ++ CLK_SET_RATE_NO_REPARENT), _gate_id, _mux_id, NO_STM32_DIV) ++ ++static CLK_STM32_GATE(tim2_k, "timg1_ck", CLK_SET_RATE_PARENT, GATE_TIM2); ++static CLK_STM32_GATE(tim3_k, "timg1_ck", CLK_SET_RATE_PARENT, GATE_TIM3); ++static CLK_STM32_GATE(tim4_k, "timg1_ck", CLK_SET_RATE_PARENT, GATE_TIM4); ++static CLK_STM32_GATE(tim5_k, "timg1_ck", CLK_SET_RATE_PARENT, GATE_TIM5); ++static CLK_STM32_GATE(tim6_k, "timg1_ck", CLK_SET_RATE_PARENT, GATE_TIM6); ++static CLK_STM32_GATE(tim7_k, "timg1_ck", CLK_SET_RATE_PARENT, GATE_TIM7); ++static CLK_STM32_GATE(tim1_k, "timg2_ck", CLK_SET_RATE_PARENT, GATE_TIM1); ++static CLK_STM32_GATE(tim8_k, "timg2_ck", CLK_SET_RATE_PARENT, GATE_TIM8); ++static CLK_STM32_GATE(tim12_k, "timg3_ck", CLK_SET_RATE_PARENT, GATE_TIM12); ++static CLK_STM32_GATE(tim13_k, "timg3_ck", CLK_SET_RATE_PARENT, GATE_TIM13); ++static CLK_STM32_GATE(tim14_k, "timg3_ck", CLK_SET_RATE_PARENT, GATE_TIM14); ++static CLK_STM32_GATE(tim15_k, "timg3_ck", CLK_SET_RATE_PARENT, GATE_TIM15); ++static CLK_STM32_GATE(tim16_k, "timg3_ck", CLK_SET_RATE_PARENT, GATE_TIM16); ++static CLK_STM32_GATE(tim17_k, "timg3_ck", CLK_SET_RATE_PARENT, GATE_TIM17); ++ ++static CLK_STM32_GATE(sai1, "pclk2", 0, GATE_SAI1); ++static CLK_STM32_GATE(sai2, "pclk2", 0, GATE_SAI2); ++ ++static CLK_STM32_GATE(syscfg, "pclk3", 0, GATE_SYSCFG); ++static CLK_STM32_GATE(vref, "pclk3", 0, GATE_VREF); ++static CLK_STM32_GATE(dts, "pclk3", 0, GATE_DTS); ++static CLK_STM32_GATE(pmbctrl, "pclk3", 0, GATE_PMBCTRL); ++static CLK_STM32_GATE(hdp, "pclk3", 0, GATE_HDP); ++ ++static CLK_STM32_GATE(iwdg2, "pclk4", 0, GATE_IWDG2APB); ++static CLK_STM32_GATE(stgenro, "pclk4", 0, GATE_STGENRO); ++static CLK_STM32_GATE(gpioa, "pclk4", 0, GATE_GPIOA); ++static CLK_STM32_GATE(gpiob, "pclk4", 0, GATE_GPIOB); ++static CLK_STM32_GATE(gpioc, "pclk4", 0, GATE_GPIOC); ++static CLK_STM32_GATE(gpiod, "pclk4", 0, GATE_GPIOD); ++static CLK_STM32_GATE(gpioe, "pclk4", 0, GATE_GPIOE); ++static CLK_STM32_GATE(gpiof, "pclk4", 0, GATE_GPIOF); ++static CLK_STM32_GATE(gpiog, "pclk4", 0, GATE_GPIOG); ++static CLK_STM32_GATE(gpioh, "pclk4", 0, GATE_GPIOH); ++static CLK_STM32_GATE(gpioi, "pclk4", 0, GATE_GPIOI); ++static CLK_STM32_GATE(tsc, "pclk4", 0, GATE_TSC); ++static CLK_STM32_GATE(ddrperfm, "pclk4", 0, GATE_DDRPERFM); ++ ++static CLK_STM32_GATE(tzpc, "pclk5", 0, GATE_TZC); ++static CLK_STM32_GATE(iwdg1, "pclk5", 0, GATE_IWDG1APB); ++static CLK_STM32_GATE(bsec, "pclk5", 0, GATE_BSEC); ++ ++static CLK_STM32_GATE(dma1, "ck_mlahb", 0, GATE_DMA1); ++static CLK_STM32_GATE(dma2, "ck_mlahb", 0, GATE_DMA2); ++static CLK_STM32_GATE(dmamux1, "ck_mlahb", 0, GATE_DMAMUX1); ++static CLK_STM32_GATE(dma3, "ck_mlahb", 0, GATE_DMA3); ++static CLK_STM32_GATE(dmamux2, "ck_mlahb", 0, GATE_DMAMUX2); ++static CLK_STM32_GATE(adc1, "ck_mlahb", 0, GATE_ADC1); ++static CLK_STM32_GATE(adc2, "ck_mlahb", 0, GATE_ADC2); ++ ++static CLK_STM32_GATE(pka, "ck_axi", 0, GATE_PKA); ++static CLK_STM32_GATE(cryp1, "ck_axi", 0, GATE_CRYP1); ++static CLK_STM32_GATE(hash1, "ck_axi", 0, GATE_HASH1); ++static CLK_STM32_GATE(bkpsram, "ck_axi", 0, GATE_BKPSRAM); ++static CLK_STM32_GATE(mdma, "ck_axi", 0, GATE_MDMA); ++static CLK_STM32_GATE(eth1tx, "ck_axi", 0, GATE_ETH1TX); ++static CLK_STM32_GATE(eth1rx, "ck_axi", 0, GATE_ETH1RX); ++static CLK_STM32_GATE(eth1mac, "ck_axi", 0, GATE_ETH1MAC); ++static CLK_STM32_GATE(eth2tx, "ck_axi", 0, GATE_ETH2TX); ++static CLK_STM32_GATE(eth2rx, "ck_axi", 0, GATE_ETH2RX); ++static CLK_STM32_GATE(eth2mac, "ck_axi", 0, GATE_ETH2MAC); ++static CLK_STM32_GATE(crc1, "ck_axi", 0, GATE_CRC1); ++static CLK_STM32_GATE(usbh, "ck_axi", 0, GATE_USBH); ++static CLK_STM32_GATE(eth1stp, "ck_axi", 0, GATE_ETH1STP); ++static CLK_STM32_GATE(eth2stp, "ck_axi", 0, GATE_ETH2STP); ++ ++static CLK_KER(sdmmc1_k, sdmmc12_src, 0, GATE_SDMMC1, MUX_SDMMC1); ++static CLK_KER(sdmmc2_k, sdmmc12_src, 0, GATE_SDMMC2, MUX_SDMMC2); ++static CLK_KER(fmc_k, fmc_src, 0, GATE_FMC, MUX_FMC); ++static CLK_KER(qspi_k, qspi_src, 0, GATE_QSPI, MUX_QSPI); ++static CLK_KER(spi2_k, spi123_src, 0, GATE_SPI2, MUX_SPI23); ++static CLK_KER(spi3_k, spi123_src, 0, GATE_SPI3, MUX_SPI23); ++static CLK_KER(i2c1_k, i2c12_src, 0, GATE_I2C1, MUX_I2C12); ++static CLK_KER(i2c2_k, i2c12_src, 0, GATE_I2C2, MUX_I2C12); ++static CLK_KER(lptim4_k, lptim45_src, 0, GATE_LPTIM4, MUX_LPTIM45); ++static CLK_KER(lptim5_k, lptim45_src, 0, GATE_LPTIM5, MUX_LPTIM45); ++static CLK_KER(usart3_k, usart34578_src, 0, GATE_USART3, MUX_UART35); ++static CLK_KER(uart5_k, usart34578_src, 0, GATE_UART5, MUX_UART35); ++static CLK_KER(uart7_k, usart34578_src, 0, GATE_UART7, MUX_UART78); ++static CLK_KER(uart8_k, usart34578_src, 0, GATE_UART8, MUX_UART78); ++static CLK_KER(sai1_k, sai1_src, 0, GATE_SAI1, MUX_SAI1); ++static CLK_KER(adfsdm_k, sai1_src, 0, GATE_ADFSDM, MUX_SAI1); ++static CLK_KER(sai2_k, sai2_src, 0, GATE_SAI2, MUX_SAI2); ++static CLK_KER(adc1_k, adc12_src, 0, GATE_ADC1, MUX_ADC1); ++static CLK_KER(adc2_k, adc12_src, 0, GATE_ADC2, MUX_ADC2); ++static CLK_KER(rng1_k, rng1_src, 0, GATE_RNG1, MUX_RNG1); ++static CLK_KER(usbphy_k, usbphy_src, 0, GATE_USBPHY, MUX_USBPHY); ++static CLK_KER(stgen_k, stgen_src, 0, GATE_STGENC, MUX_STGEN); ++static CLK_KER(spdif_k, spdif_src, 0, GATE_SPDIF, MUX_SPDIF); ++static CLK_KER(spi1_k, spi123_src, 0, GATE_SPI1, MUX_SPI1); ++static CLK_KER(spi4_k, spi4_src, 0, GATE_SPI4, MUX_SPI4); ++static CLK_KER(spi5_k, spi5_src, 0, GATE_SPI5, MUX_SPI5); ++static CLK_KER(i2c3_k, i2c345_src, 0, GATE_I2C3, MUX_I2C3); ++static CLK_KER(i2c4_k, i2c345_src, 0, GATE_I2C4, MUX_I2C4); ++static CLK_KER(i2c5_k, i2c345_src, 0, GATE_I2C5, MUX_I2C5); ++static CLK_KER(lptim1_k, lptim1_src, 0, GATE_LPTIM1, MUX_LPTIM1); ++static CLK_KER(lptim2_k, lptim23_src, 0, GATE_LPTIM2, MUX_LPTIM2); ++static CLK_KER(lptim3_k, lptim23_src, 0, GATE_LPTIM3, MUX_LPTIM3); ++static CLK_KER(usart1_k, usart12_src, 0, GATE_USART1, MUX_UART1); ++static CLK_KER(usart2_k, usart12_src, 0, GATE_USART2, MUX_UART2); ++static CLK_KER(uart4_k, usart34578_src, 0, GATE_UART4, MUX_UART4); ++static CLK_KER(uart6_k, usart6_src, 0, GATE_USART6, MUX_UART6); ++static CLK_KER(fdcan_k, fdcan_src, 0, GATE_FDCAN, MUX_FDCAN); ++static CLK_KER(dcmipp_k, dcmipp_src, 0, GATE_DCMIPP, MUX_DCMIPP); ++static CLK_KER(usbo_k, usbo_src, 0, GATE_USBO, MUX_USBO); ++static CLK_KER(eth1ck_k, eth12_src, 0, GATE_ETH1CK, MUX_ETH1); ++static CLK_KER(eth2ck_k, eth12_src, 0, GATE_ETH2CK, MUX_ETH2); ++static CLK_KER(saes_k, saes_src, 0, GATE_SAES, MUX_SAES); ++ ++static CLK_STM32_GATE(dfsdm_k, "ck_mlahb", 0, GATE_DFSDM); ++static CLK_STM32_GATE(ltdc_px, "pll4_q", CLK_SET_RATE_PARENT, GATE_LTDC); ++ ++static CLK_STM32_COMPOSITE(eth1ptp_k, eth12_src, CLK_OPS_PARENT_ENABLE | ++ CLK_SET_RATE_NO_REPARENT, ++ NO_STM32_GATE, MUX_ETH1, DIV_ETH1PTP); ++ ++static CLK_STM32_COMPOSITE(eth2ptp_k, eth12_src, CLK_OPS_PARENT_ENABLE | ++ CLK_SET_RATE_NO_REPARENT, ++ NO_STM32_GATE, MUX_ETH2, DIV_ETH2PTP); ++ ++/* MCO clocks */ ++static CLK_STM32_COMPOSITE(ck_mco1, mco1_src, CLK_OPS_PARENT_ENABLE | ++ CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED, ++ GATE_MCO1, MUX_MCO1, DIV_MCO1); ++ ++static CLK_STM32_COMPOSITE(ck_mco2, mco2_src, CLK_OPS_PARENT_ENABLE | ++ CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED, ++ GATE_MCO2, MUX_MCO2, DIV_MCO2); ++ ++/* Debug clocks */ ++static CLK_STM32_GATE(ck_sys_dbg, "ck_axi", CLK_IS_CRITICAL, GATE_DBGCK); ++ ++static CLK_STM32_COMPOSITE(ck_trace, PARENT("ck_axi"), CLK_IGNORE_UNUSED, ++ GATE_TRACECK, NO_STM32_MUX, DIV_TRACE); ++ ++static const struct clock_config stm32mp13_clock_cfg[] = { ++ /* Timer clocks */ ++ STM32_GATE_CFG(TIM2_K, tim2_k, SECF_NONE), ++ STM32_GATE_CFG(TIM3_K, tim3_k, SECF_NONE), ++ STM32_GATE_CFG(TIM4_K, tim4_k, SECF_NONE), ++ STM32_GATE_CFG(TIM5_K, tim5_k, SECF_NONE), ++ STM32_GATE_CFG(TIM6_K, tim6_k, SECF_NONE), ++ STM32_GATE_CFG(TIM7_K, tim7_k, SECF_NONE), ++ STM32_GATE_CFG(TIM1_K, tim1_k, SECF_NONE), ++ STM32_GATE_CFG(TIM8_K, tim8_k, SECF_NONE), ++ STM32_GATE_CFG(TIM12_K, tim12_k, SECF_TIM12), ++ STM32_GATE_CFG(TIM13_K, tim13_k, SECF_TIM13), ++ STM32_GATE_CFG(TIM14_K, tim14_k, SECF_TIM14), ++ STM32_GATE_CFG(TIM15_K, tim15_k, SECF_TIM15), ++ STM32_GATE_CFG(TIM16_K, tim16_k, SECF_TIM16), ++ STM32_GATE_CFG(TIM17_K, tim17_k, SECF_TIM17), ++ ++ /* Peripheral clocks */ ++ STM32_GATE_CFG(SAI1, sai1, SECF_NONE), ++ STM32_GATE_CFG(SAI2, sai2, SECF_NONE), ++ STM32_GATE_CFG(SYSCFG, syscfg, SECF_NONE), ++ STM32_GATE_CFG(VREF, vref, SECF_VREF), ++ STM32_GATE_CFG(DTS, dts, SECF_NONE), ++ STM32_GATE_CFG(PMBCTRL, pmbctrl, SECF_NONE), ++ STM32_GATE_CFG(HDP, hdp, SECF_NONE), ++ STM32_GATE_CFG(IWDG2, iwdg2, SECF_NONE), ++ STM32_GATE_CFG(STGENRO, stgenro, SECF_STGENRO), ++ STM32_GATE_CFG(TZPC, tzpc, SECF_TZC), ++ STM32_GATE_CFG(IWDG1, iwdg1, SECF_IWDG1), ++ STM32_GATE_CFG(BSEC, bsec, SECF_BSEC), ++ STM32_GATE_CFG(DMA1, dma1, SECF_NONE), ++ STM32_GATE_CFG(DMA2, dma2, SECF_NONE), ++ STM32_GATE_CFG(DMAMUX1, dmamux1, SECF_NONE), ++ STM32_GATE_CFG(DMA3, dma3, SECF_DMA3), ++ STM32_GATE_CFG(DMAMUX2, dmamux2, SECF_DMAMUX2), ++ STM32_GATE_CFG(ADC1, adc1, SECF_ADC1), ++ STM32_GATE_CFG(ADC2, adc2, SECF_ADC2), ++ STM32_GATE_CFG(GPIOA, gpioa, SECF_NONE), ++ STM32_GATE_CFG(GPIOB, gpiob, SECF_NONE), ++ STM32_GATE_CFG(GPIOC, gpioc, SECF_NONE), ++ STM32_GATE_CFG(GPIOD, gpiod, SECF_NONE), ++ STM32_GATE_CFG(GPIOE, gpioe, SECF_NONE), ++ STM32_GATE_CFG(GPIOF, gpiof, SECF_NONE), ++ STM32_GATE_CFG(GPIOG, gpiog, SECF_NONE), ++ STM32_GATE_CFG(GPIOH, gpioh, SECF_NONE), ++ STM32_GATE_CFG(GPIOI, gpioi, SECF_NONE), ++ STM32_GATE_CFG(TSC, tsc, SECF_TZC), ++ STM32_GATE_CFG(PKA, pka, SECF_PKA), ++ STM32_GATE_CFG(CRYP1, cryp1, SECF_CRYP1), ++ STM32_GATE_CFG(HASH1, hash1, SECF_HASH1), ++ STM32_GATE_CFG(BKPSRAM, bkpsram, SECF_BKPSRAM), ++ STM32_GATE_CFG(MDMA, mdma, SECF_NONE), ++ STM32_GATE_CFG(ETH1TX, eth1tx, SECF_ETH1TX), ++ STM32_GATE_CFG(ETH1RX, eth1rx, SECF_ETH1RX), ++ STM32_GATE_CFG(ETH1MAC, eth1mac, SECF_ETH1MAC), ++ STM32_GATE_CFG(ETH2TX, eth2tx, SECF_ETH2TX), ++ STM32_GATE_CFG(ETH2RX, eth2rx, SECF_ETH2RX), ++ STM32_GATE_CFG(ETH2MAC, eth2mac, SECF_ETH2MAC), ++ STM32_GATE_CFG(CRC1, crc1, SECF_NONE), ++ STM32_GATE_CFG(USBH, usbh, SECF_NONE), ++ STM32_GATE_CFG(DDRPERFM, ddrperfm, SECF_NONE), ++ STM32_GATE_CFG(ETH1STP, eth1stp, SECF_ETH1STP), ++ STM32_GATE_CFG(ETH2STP, eth2stp, SECF_ETH2STP), ++ ++ /* Kernel clocks */ ++ STM32_COMPOSITE_CFG(SDMMC1_K, sdmmc1_k, SECF_SDMMC1), ++ STM32_COMPOSITE_CFG(SDMMC2_K, sdmmc2_k, SECF_SDMMC2), ++ STM32_COMPOSITE_CFG(FMC_K, fmc_k, SECF_FMC), ++ STM32_COMPOSITE_CFG(QSPI_K, qspi_k, SECF_QSPI), ++ STM32_COMPOSITE_CFG(SPI2_K, spi2_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(SPI3_K, spi3_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(I2C1_K, i2c1_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(I2C2_K, i2c2_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(LPTIM4_K, lptim4_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(LPTIM5_K, lptim5_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(USART3_K, usart3_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(UART5_K, uart5_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(UART7_K, uart7_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(UART8_K, uart8_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(SAI1_K, sai1_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(SAI2_K, sai2_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(ADFSDM_K, adfsdm_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(ADC1_K, adc1_k, SECF_ADC1), ++ STM32_COMPOSITE_CFG(ADC2_K, adc2_k, SECF_ADC2), ++ STM32_COMPOSITE_CFG(RNG1_K, rng1_k, SECF_RNG1), ++ STM32_COMPOSITE_CFG(USBPHY_K, usbphy_k, SECF_USBPHY), ++ STM32_COMPOSITE_CFG(STGEN_K, stgen_k, SECF_STGENC), ++ STM32_COMPOSITE_CFG(SPDIF_K, spdif_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(SPI1_K, spi1_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(SPI4_K, spi4_k, SECF_SPI4), ++ STM32_COMPOSITE_CFG(SPI5_K, spi5_k, SECF_SPI5), ++ STM32_COMPOSITE_CFG(I2C3_K, i2c3_k, SECF_I2C3), ++ STM32_COMPOSITE_CFG(I2C4_K, i2c4_k, SECF_I2C4), ++ STM32_COMPOSITE_CFG(I2C5_K, i2c5_k, SECF_I2C5), ++ STM32_COMPOSITE_CFG(LPTIM1_K, lptim1_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(LPTIM2_K, lptim2_k, SECF_LPTIM2), ++ STM32_COMPOSITE_CFG(LPTIM3_K, lptim3_k, SECF_LPTIM3), ++ STM32_COMPOSITE_CFG(USART1_K, usart1_k, SECF_USART1), ++ STM32_COMPOSITE_CFG(USART2_K, usart2_k, SECF_USART2), ++ STM32_COMPOSITE_CFG(UART4_K, uart4_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(USART6_K, uart6_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(FDCAN_K, fdcan_k, SECF_NONE), ++ STM32_COMPOSITE_CFG(DCMIPP_K, dcmipp_k, SECF_DCMIPP), ++ STM32_COMPOSITE_CFG(USBO_K, usbo_k, SECF_USBO), ++ STM32_COMPOSITE_CFG(ETH1CK_K, eth1ck_k, SECF_ETH1CK), ++ STM32_COMPOSITE_CFG(ETH2CK_K, eth2ck_k, SECF_ETH2CK), ++ STM32_COMPOSITE_CFG(SAES_K, saes_k, SECF_SAES), ++ ++ STM32_GATE_CFG(DFSDM_K, dfsdm_k, SECF_NONE), ++ STM32_GATE_CFG(LTDC_PX, ltdc_px, SECF_NONE), ++ ++ STM32_COMPOSITE_CFG(ETH1PTP_K, eth1ptp_k, SECF_ETH1CK), ++ STM32_COMPOSITE_CFG(ETH2PTP_K, eth2ptp_k, SECF_ETH2CK), ++ STM32_COMPOSITE_CFG(CK_MCO1, ck_mco1, SECF_MCO1), ++ STM32_COMPOSITE_CFG(CK_MCO2, ck_mco2, SECF_MCO2), ++ ++ STM32_GATE_CFG(CK_DBG, ck_sys_dbg, SECF_NONE), ++ ++ STM32_COMPOSITE_CFG(CK_TRACE, ck_trace, SECF_NONE), ++}; ++ ++static int stm32mp13_check_security(void __iomem *base, ++ const struct clock_config *cfg) ++{ ++ int sec_id = cfg->sec_id; ++ int secured = 0; ++ ++ if (sec_id != SECF_NONE) { ++ const struct clk_stm32_securiy *secf; ++ ++ secf = &stm32mp13_security[sec_id]; ++ secured = !!(readl(base + secf->offset) & BIT(secf->bit_idx)); ++ } ++ ++ return secured; ++} ++ ++struct multi_mux { ++ struct clk_hw *hw1; ++ struct clk_hw *hw2; ++}; ++ ++static struct multi_mux *stm32_mp13_multi_mux[MUX_NB] = { ++ [MUX_SPI23] = &(struct multi_mux){ &spi2_k.hw, &spi3_k.hw }, ++ [MUX_I2C12] = &(struct multi_mux){ &i2c1_k.hw, &i2c2_k.hw }, ++ [MUX_LPTIM45] = &(struct multi_mux){ &lptim4_k.hw, &lptim5_k.hw }, ++ [MUX_UART35] = &(struct multi_mux){ &usart3_k.hw, &uart5_k.hw }, ++ [MUX_UART78] = &(struct multi_mux){ &uart7_k.hw, &uart8_k.hw }, ++ [MUX_SAI1] = &(struct multi_mux){ &sai1_k.hw, &adfsdm_k.hw }, ++}; ++ ++static struct clk_hw *clk_stm32_is_multi_mux(struct clk_hw *hw) ++{ ++ struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); ++ struct multi_mux *mmux = stm32_mp13_multi_mux[composite->mux_id]; ++ ++ if (mmux) { ++ if (!(mmux->hw1 == hw)) ++ return mmux->hw1; ++ else ++ return mmux->hw2; ++ } ++ ++ return NULL; ++} ++ ++u16 stm32mp13_cpt_gate[GATE_NB]; ++ ++struct clk_stm32_clock_data stm32mp13_clock_data = { ++ .gate_cpt = stm32mp13_cpt_gate, ++ .gates = stm32mp13_gates, ++ .muxes = stm32mp13_muxes, ++ .dividers = stm32mp13_dividers, ++ .is_multi_mux = clk_stm32_is_multi_mux, ++}; ++ ++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_check_security, ++ .maxbinding = STM32MP1_LAST_CLK, ++ .clear_offset = RCC_CLR, ++}; ++ ++static const struct of_device_id stm32mp13_match_data[] = { ++ { ++ .compatible = "st,stm32mp13-rcc", ++ .data = &stm32mp13_data, ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, stm32mp13_match_data); ++ ++static int stm32mp1_rcc_init(struct device *dev) ++{ ++ void __iomem *rcc_base; ++ int ret = -ENOMEM; ++ ++ rcc_base = of_iomap(dev_of_node(dev), 0); ++ if (!rcc_base) { ++ dev_err(dev, "%pOFn: unable to map resource", dev_of_node(dev)); ++ goto out; ++ } ++ ++ ret = stm32_rcc_init(dev, stm32mp13_match_data, rcc_base); ++out: ++ if (ret) { ++ if (rcc_base) ++ iounmap(rcc_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 int 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); ++ ++ return 0; ++} ++ ++static struct platform_driver stm32mp13_rcc_clocks_driver = { ++ .driver = { ++ .name = "stm32mp13_rcc", ++ .of_match_table = stm32mp13_match_data, ++ }, ++ .probe = stm32mp1_rcc_clocks_probe, ++ .remove = stm32mp1_rcc_clocks_remove, ++}; ++ ++static int __init stm32mp13_clocks_init(void) ++{ ++ return platform_driver_register(&stm32mp13_rcc_clocks_driver); ++} ++core_initcall(stm32mp13_clocks_init); +diff --git a/drivers/clk/stm32/reset-stm32.c b/drivers/clk/stm32/reset-stm32.c +new file mode 100644 +index 000000000..eb7ed08f9 +--- /dev/null ++++ b/drivers/clk/stm32/reset-stm32.c +@@ -0,0 +1,122 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2021 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk-stm32-core.h" ++ ++#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, ++}; ++ ++int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, ++ void __iomem *base) ++{ ++ const struct stm32_rcc_match_data *data = match->data; ++ struct stm32_reset_data *reset_data = NULL; ++ ++ data = match->data; ++ ++ reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); ++ if (!reset_data) ++ return -ENOMEM; ++ ++ 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); ++} +diff --git a/drivers/clk/stm32/reset-stm32.h b/drivers/clk/stm32/reset-stm32.h +new file mode 100644 +index 000000000..63a4a35b5 +--- /dev/null ++++ b/drivers/clk/stm32/reset-stm32.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) STMicroelectronics 2021 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, void __iomem *base); +diff --git a/drivers/clk/stm32/stm32mp13_rcc.h b/drivers/clk/stm32/stm32mp13_rcc.h +new file mode 100644 +index 000000000..f01a98c85 +--- /dev/null ++++ b/drivers/clk/stm32/stm32mp13_rcc.h +@@ -0,0 +1,1751 @@ ++/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ ++/* ++ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved ++ * ++ * Configuration settings for the STM32MP13x CPU ++ */ ++ ++#ifndef STM32MP13_RCC_H ++#define STM32MP13_RCC_H ++/* RCC registers */ ++#define RCC_SECCFGR 0x0 ++#define RCC_MP_SREQSETR 0x100 ++#define RCC_MP_SREQCLRR 0x104 ++#define RCC_MP_APRSTCR 0x108 ++#define RCC_MP_APRSTSR 0x10c ++#define RCC_PWRLPDLYCR 0x110 ++#define RCC_MP_GRSTCSETR 0x114 ++#define RCC_BR_RSTSCLRR 0x118 ++#define RCC_MP_RSTSSETR 0x11c ++#define RCC_MP_RSTSCLRR 0x120 ++#define RCC_MP_IWDGFZSETR 0x124 ++#define RCC_MP_IWDGFZCLRR 0x128 ++#define RCC_MP_CIER 0x200 ++#define RCC_MP_CIFR 0x204 ++#define RCC_BDCR 0x400 ++#define RCC_RDLSICR 0x404 ++#define RCC_OCENSETR 0x420 ++#define RCC_OCENCLRR 0x424 ++#define RCC_OCRDYR 0x428 ++#define RCC_HSICFGR 0x440 ++#define RCC_CSICFGR 0x444 ++#define RCC_MCO1CFGR 0x460 ++#define RCC_MCO2CFGR 0x464 ++#define RCC_DBGCFGR 0x468 ++#define RCC_RCK12SELR 0x480 ++#define RCC_RCK3SELR 0x484 ++#define RCC_RCK4SELR 0x488 ++#define RCC_PLL1CR 0x4a0 ++#define RCC_PLL1CFGR1 0x4a4 ++#define RCC_PLL1CFGR2 0x4a8 ++#define RCC_PLL1FRACR 0x4ac ++#define RCC_PLL1CSGR 0x4b0 ++#define RCC_PLL2CR 0x4d0 ++#define RCC_PLL2CFGR1 0x4d4 ++#define RCC_PLL2CFGR2 0x4d8 ++#define RCC_PLL2FRACR 0x4dc ++#define RCC_PLL2CSGR 0x4e0 ++#define RCC_PLL3CR 0x500 ++#define RCC_PLL3CFGR1 0x504 ++#define RCC_PLL3CFGR2 0x508 ++#define RCC_PLL3FRACR 0x50c ++#define RCC_PLL3CSGR 0x510 ++#define RCC_PLL4CR 0x520 ++#define RCC_PLL4CFGR1 0x524 ++#define RCC_PLL4CFGR2 0x528 ++#define RCC_PLL4FRACR 0x52c ++#define RCC_PLL4CSGR 0x530 ++#define RCC_MPCKSELR 0x540 ++#define RCC_ASSCKSELR 0x544 ++#define RCC_MSSCKSELR 0x548 ++#define RCC_CPERCKSELR 0x54c ++#define RCC_RTCDIVR 0x560 ++#define RCC_MPCKDIVR 0x564 ++#define RCC_AXIDIVR 0x568 ++#define RCC_MLAHBDIVR 0x56c ++#define RCC_APB1DIVR 0x570 ++#define RCC_APB2DIVR 0x574 ++#define RCC_APB3DIVR 0x578 ++#define RCC_APB4DIVR 0x57c ++#define RCC_APB5DIVR 0x580 ++#define RCC_APB6DIVR 0x584 ++#define RCC_TIMG1PRER 0x5a0 ++#define RCC_TIMG2PRER 0x5a4 ++#define RCC_TIMG3PRER 0x5a8 ++#define RCC_DDRITFCR 0x5c0 ++#define RCC_I2C12CKSELR 0x600 ++#define RCC_I2C345CKSELR 0x604 ++#define RCC_SPI2S1CKSELR 0x608 ++#define RCC_SPI2S23CKSELR 0x60c ++#define RCC_SPI45CKSELR 0x610 ++#define RCC_UART12CKSELR 0x614 ++#define RCC_UART35CKSELR 0x618 ++#define RCC_UART4CKSELR 0x61c ++#define RCC_UART6CKSELR 0x620 ++#define RCC_UART78CKSELR 0x624 ++#define RCC_LPTIM1CKSELR 0x628 ++#define RCC_LPTIM23CKSELR 0x62c ++#define RCC_LPTIM45CKSELR 0x630 ++#define RCC_SAI1CKSELR 0x634 ++#define RCC_SAI2CKSELR 0x638 ++#define RCC_FDCANCKSELR 0x63c ++#define RCC_SPDIFCKSELR 0x640 ++#define RCC_ADC12CKSELR 0x644 ++#define RCC_SDMMC12CKSELR 0x648 ++#define RCC_ETH12CKSELR 0x64c ++#define RCC_USBCKSELR 0x650 ++#define RCC_QSPICKSELR 0x654 ++#define RCC_FMCCKSELR 0x658 ++#define RCC_RNG1CKSELR 0x65c ++#define RCC_STGENCKSELR 0x660 ++#define RCC_DCMIPPCKSELR 0x664 ++#define RCC_SAESCKSELR 0x668 ++#define RCC_APB1RSTSETR 0x6a0 ++#define RCC_APB1RSTCLRR 0x6a4 ++#define RCC_APB2RSTSETR 0x6a8 ++#define RCC_APB2RSTCLRR 0x6ac ++#define RCC_APB3RSTSETR 0x6b0 ++#define RCC_APB3RSTCLRR 0x6b4 ++#define RCC_APB4RSTSETR 0x6b8 ++#define RCC_APB4RSTCLRR 0x6bc ++#define RCC_APB5RSTSETR 0x6c0 ++#define RCC_APB5RSTCLRR 0x6c4 ++#define RCC_APB6RSTSETR 0x6c8 ++#define RCC_APB6RSTCLRR 0x6cc ++#define RCC_AHB2RSTSETR 0x6d0 ++#define RCC_AHB2RSTCLRR 0x6d4 ++#define RCC_AHB4RSTSETR 0x6e0 ++#define RCC_AHB4RSTCLRR 0x6e4 ++#define RCC_AHB5RSTSETR 0x6e8 ++#define RCC_AHB5RSTCLRR 0x6ec ++#define RCC_AHB6RSTSETR 0x6f0 ++#define RCC_AHB6RSTCLRR 0x6f4 ++#define RCC_MP_APB1ENSETR 0x700 ++#define RCC_MP_APB1ENCLRR 0x704 ++#define RCC_MP_APB2ENSETR 0x708 ++#define RCC_MP_APB2ENCLRR 0x70c ++#define RCC_MP_APB3ENSETR 0x710 ++#define RCC_MP_APB3ENCLRR 0x714 ++#define RCC_MP_S_APB3ENSETR 0x718 ++#define RCC_MP_S_APB3ENCLRR 0x71c ++#define RCC_MP_NS_APB3ENSETR 0x720 ++#define RCC_MP_NS_APB3ENCLRR 0x724 ++#define RCC_MP_APB4ENSETR 0x728 ++#define RCC_MP_APB4ENCLRR 0x72c ++#define RCC_MP_S_APB4ENSETR 0x730 ++#define RCC_MP_S_APB4ENCLRR 0x734 ++#define RCC_MP_NS_APB4ENSETR 0x738 ++#define RCC_MP_NS_APB4ENCLRR 0x73c ++#define RCC_MP_APB5ENSETR 0x740 ++#define RCC_MP_APB5ENCLRR 0x744 ++#define RCC_MP_APB6ENSETR 0x748 ++#define RCC_MP_APB6ENCLRR 0x74c ++#define RCC_MP_AHB2ENSETR 0x750 ++#define RCC_MP_AHB2ENCLRR 0x754 ++#define RCC_MP_AHB4ENSETR 0x760 ++#define RCC_MP_AHB4ENCLRR 0x764 ++#define RCC_MP_S_AHB4ENSETR 0x768 ++#define RCC_MP_S_AHB4ENCLRR 0x76c ++#define RCC_MP_NS_AHB4ENSETR 0x770 ++#define RCC_MP_NS_AHB4ENCLRR 0x774 ++#define RCC_MP_AHB5ENSETR 0x778 ++#define RCC_MP_AHB5ENCLRR 0x77c ++#define RCC_MP_AHB6ENSETR 0x780 ++#define RCC_MP_AHB6ENCLRR 0x784 ++#define RCC_MP_S_AHB6ENSETR 0x788 ++#define RCC_MP_S_AHB6ENCLRR 0x78c ++#define RCC_MP_NS_AHB6ENSETR 0x790 ++#define RCC_MP_NS_AHB6ENCLRR 0x794 ++#define RCC_MP_APB1LPENSETR 0x800 ++#define RCC_MP_APB1LPENCLRR 0x804 ++#define RCC_MP_APB2LPENSETR 0x808 ++#define RCC_MP_APB2LPENCLRR 0x80c ++#define RCC_MP_APB3LPENSETR 0x810 ++#define RCC_MP_APB3LPENCLRR 0x814 ++#define RCC_MP_S_APB3LPENSETR 0x818 ++#define RCC_MP_S_APB3LPENCLRR 0x81c ++#define RCC_MP_NS_APB3LPENSETR 0x820 ++#define RCC_MP_NS_APB3LPENCLRR 0x824 ++#define RCC_MP_APB4LPENSETR 0x828 ++#define RCC_MP_APB4LPENCLRR 0x82c ++#define RCC_MP_S_APB4LPENSETR 0x830 ++#define RCC_MP_S_APB4LPENCLRR 0x834 ++#define RCC_MP_NS_APB4LPENSETR 0x838 ++#define RCC_MP_NS_APB4LPENCLRR 0x83c ++#define RCC_MP_APB5LPENSETR 0x840 ++#define RCC_MP_APB5LPENCLRR 0x844 ++#define RCC_MP_APB6LPENSETR 0x848 ++#define RCC_MP_APB6LPENCLRR 0x84c ++#define RCC_MP_AHB2LPENSETR 0x850 ++#define RCC_MP_AHB2LPENCLRR 0x854 ++#define RCC_MP_AHB4LPENSETR 0x858 ++#define RCC_MP_AHB4LPENCLRR 0x85c ++#define RCC_MP_S_AHB4LPENSETR 0x868 ++#define RCC_MP_S_AHB4LPENCLRR 0x86c ++#define RCC_MP_NS_AHB4LPENSETR 0x870 ++#define RCC_MP_NS_AHB4LPENCLRR 0x874 ++#define RCC_MP_AHB5LPENSETR 0x878 ++#define RCC_MP_AHB5LPENCLRR 0x87c ++#define RCC_MP_AHB6LPENSETR 0x880 ++#define RCC_MP_AHB6LPENCLRR 0x884 ++#define RCC_MP_S_AHB6LPENSETR 0x888 ++#define RCC_MP_S_AHB6LPENCLRR 0x88c ++#define RCC_MP_NS_AHB6LPENSETR 0x890 ++#define RCC_MP_NS_AHB6LPENCLRR 0x894 ++#define RCC_MP_S_AXIMLPENSETR 0x898 ++#define RCC_MP_S_AXIMLPENCLRR 0x89c ++#define RCC_MP_NS_AXIMLPENSETR 0x8a0 ++#define RCC_MP_NS_AXIMLPENCLRR 0x8a4 ++#define RCC_MP_MLAHBLPENSETR 0x8a8 ++#define RCC_MP_MLAHBLPENCLRR 0x8ac ++#define RCC_APB3SECSR 0x8c0 ++#define RCC_APB4SECSR 0x8c4 ++#define RCC_APB5SECSR 0x8c8 ++#define RCC_APB6SECSR 0x8cc ++#define RCC_AHB2SECSR 0x8d0 ++#define RCC_AHB4SECSR 0x8d4 ++#define RCC_AHB5SECSR 0x8d8 ++#define RCC_AHB6SECSR 0x8dc ++#define RCC_VERR 0xff4 ++#define RCC_IDR 0xff8 ++#define RCC_SIDR 0xffc ++ ++/* RCC_SECCFGR register fields */ ++#define RCC_SECCFGR_HSISEC BIT(0) ++#define RCC_SECCFGR_CSISEC BIT(1) ++#define RCC_SECCFGR_HSESEC BIT(2) ++#define RCC_SECCFGR_LSISEC BIT(3) ++#define RCC_SECCFGR_LSESEC BIT(4) ++#define RCC_SECCFGR_PLL12SEC BIT(8) ++#define RCC_SECCFGR_PLL3SEC BIT(9) ++#define RCC_SECCFGR_PLL4SEC BIT(10) ++#define RCC_SECCFGR_MPUSEC BIT(11) ++#define RCC_SECCFGR_AXISEC BIT(12) ++#define RCC_SECCFGR_MLAHBSEC BIT(13) ++#define RCC_SECCFGR_APB3DIVSEC BIT(16) ++#define RCC_SECCFGR_APB4DIVSEC BIT(17) ++#define RCC_SECCFGR_APB5DIVSEC BIT(18) ++#define RCC_SECCFGR_APB6DIVSEC BIT(19) ++#define RCC_SECCFGR_TIMG3SEC BIT(20) ++#define RCC_SECCFGR_CPERSEC BIT(21) ++#define RCC_SECCFGR_MCO1SEC BIT(22) ++#define RCC_SECCFGR_MCO2SEC BIT(23) ++#define RCC_SECCFGR_STPSEC BIT(24) ++#define RCC_SECCFGR_RSTSEC BIT(25) ++#define RCC_SECCFGR_PWRSEC BIT(31) ++ ++#define RCC_SECCFGR_MCO1SECF 22 ++#define RCC_SECCFGR_MCO2SECF 23 ++ ++/* RCC_MP_SREQSETR register fields */ ++#define RCC_MP_SREQSETR_STPREQ_P0 BIT(0) ++ ++/* RCC_MP_SREQCLRR register fields */ ++#define RCC_MP_SREQCLRR_STPREQ_P0 BIT(0) ++ ++/* RCC_MP_APRSTCR register fields */ ++#define RCC_MP_APRSTCR_RDCTLEN BIT(0) ++#define RCC_MP_APRSTCR_RSTTO_MASK GENMASK(14, 8) ++#define RCC_MP_APRSTCR_RSTTO_SHIFT 8 ++ ++/* RCC_MP_APRSTSR register fields */ ++#define RCC_MP_APRSTSR_RSTTOV_MASK GENMASK(14, 8) ++#define RCC_MP_APRSTSR_RSTTOV_SHIFT 8 ++ ++/* RCC_PWRLPDLYCR register fields */ ++#define RCC_PWRLPDLYCR_PWRLP_DLY_MASK GENMASK(21, 0) ++#define RCC_PWRLPDLYCR_PWRLP_DLY_SHIFT 0 ++ ++/* RCC_MP_GRSTCSETR register fields */ ++#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0) ++#define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) ++ ++/* RCC_BR_RSTSCLRR register fields */ ++#define RCC_BR_RSTSCLRR_PORRSTF BIT(0) ++#define RCC_BR_RSTSCLRR_BORRSTF BIT(1) ++#define RCC_BR_RSTSCLRR_PADRSTF BIT(2) ++#define RCC_BR_RSTSCLRR_HCSSRSTF BIT(3) ++#define RCC_BR_RSTSCLRR_VCORERSTF BIT(4) ++#define RCC_BR_RSTSCLRR_VCPURSTF BIT(5) ++#define RCC_BR_RSTSCLRR_MPSYSRSTF BIT(6) ++#define RCC_BR_RSTSCLRR_IWDG1RSTF BIT(8) ++#define RCC_BR_RSTSCLRR_IWDG2RSTF BIT(9) ++#define RCC_BR_RSTSCLRR_MPUP0RSTF BIT(13) ++ ++/* RCC_MP_RSTSSETR register fields */ ++#define RCC_MP_RSTSSETR_PORRSTF BIT(0) ++#define RCC_MP_RSTSSETR_BORRSTF BIT(1) ++#define RCC_MP_RSTSSETR_PADRSTF BIT(2) ++#define RCC_MP_RSTSSETR_HCSSRSTF BIT(3) ++#define RCC_MP_RSTSSETR_VCORERSTF BIT(4) ++#define RCC_MP_RSTSSETR_VCPURSTF BIT(5) ++#define RCC_MP_RSTSSETR_MPSYSRSTF BIT(6) ++#define RCC_MP_RSTSSETR_IWDG1RSTF BIT(8) ++#define RCC_MP_RSTSSETR_IWDG2RSTF BIT(9) ++#define RCC_MP_RSTSSETR_STP2RSTF BIT(10) ++#define RCC_MP_RSTSSETR_STDBYRSTF BIT(11) ++#define RCC_MP_RSTSSETR_CSTDBYRSTF BIT(12) ++#define RCC_MP_RSTSSETR_MPUP0RSTF BIT(13) ++#define RCC_MP_RSTSSETR_SPARE BIT(15) ++ ++/* RCC_MP_RSTSCLRR register fields */ ++#define RCC_MP_RSTSCLRR_PORRSTF BIT(0) ++#define RCC_MP_RSTSCLRR_BORRSTF BIT(1) ++#define RCC_MP_RSTSCLRR_PADRSTF BIT(2) ++#define RCC_MP_RSTSCLRR_HCSSRSTF BIT(3) ++#define RCC_MP_RSTSCLRR_VCORERSTF BIT(4) ++#define RCC_MP_RSTSCLRR_VCPURSTF BIT(5) ++#define RCC_MP_RSTSCLRR_MPSYSRSTF BIT(6) ++#define RCC_MP_RSTSCLRR_IWDG1RSTF BIT(8) ++#define RCC_MP_RSTSCLRR_IWDG2RSTF BIT(9) ++#define RCC_MP_RSTSCLRR_STP2RSTF BIT(10) ++#define RCC_MP_RSTSCLRR_STDBYRSTF BIT(11) ++#define RCC_MP_RSTSCLRR_CSTDBYRSTF BIT(12) ++#define RCC_MP_RSTSCLRR_MPUP0RSTF BIT(13) ++#define RCC_MP_RSTSCLRR_SPARE BIT(15) ++ ++/* RCC_MP_IWDGFZSETR register fields */ ++#define RCC_MP_IWDGFZSETR_FZ_IWDG1 BIT(0) ++#define RCC_MP_IWDGFZSETR_FZ_IWDG2 BIT(1) ++ ++/* RCC_MP_IWDGFZCLRR register fields */ ++#define RCC_MP_IWDGFZCLRR_FZ_IWDG1 BIT(0) ++#define RCC_MP_IWDGFZCLRR_FZ_IWDG2 BIT(1) ++ ++/* RCC_MP_CIER register fields */ ++#define RCC_MP_CIER_LSIRDYIE BIT(0) ++#define RCC_MP_CIER_LSERDYIE BIT(1) ++#define RCC_MP_CIER_HSIRDYIE BIT(2) ++#define RCC_MP_CIER_HSERDYIE BIT(3) ++#define RCC_MP_CIER_CSIRDYIE BIT(4) ++#define RCC_MP_CIER_PLL1DYIE BIT(8) ++#define RCC_MP_CIER_PLL2DYIE BIT(9) ++#define RCC_MP_CIER_PLL3DYIE BIT(10) ++#define RCC_MP_CIER_PLL4DYIE BIT(11) ++#define RCC_MP_CIER_LSECSSIE BIT(16) ++#define RCC_MP_CIER_WKUPIE BIT(20) ++ ++/* RCC_MP_CIFR register fields */ ++#define RCC_MP_CIFR_LSIRDYF BIT(0) ++#define RCC_MP_CIFR_LSERDYF BIT(1) ++#define RCC_MP_CIFR_HSIRDYF BIT(2) ++#define RCC_MP_CIFR_HSERDYF BIT(3) ++#define RCC_MP_CIFR_CSIRDYF BIT(4) ++#define RCC_MP_CIFR_PLL1DYF BIT(8) ++#define RCC_MP_CIFR_PLL2DYF BIT(9) ++#define RCC_MP_CIFR_PLL3DYF BIT(10) ++#define RCC_MP_CIFR_PLL4DYF BIT(11) ++#define RCC_MP_CIFR_LSECSSF BIT(16) ++#define RCC_MP_CIFR_WKUPF BIT(20) ++ ++/* RCC_BDCR register fields */ ++#define RCC_BDCR_LSEON BIT(0) ++#define RCC_BDCR_LSEBYP BIT(1) ++#define RCC_BDCR_LSERDY BIT(2) ++#define RCC_BDCR_DIGBYP BIT(3) ++#define RCC_BDCR_LSEDRV_MASK GENMASK(5, 4) ++#define RCC_BDCR_LSECSSON BIT(8) ++#define RCC_BDCR_LSECSSD BIT(9) ++#define RCC_BDCR_RTCSRC_MASK GENMASK(17, 16) ++#define RCC_BDCR_RTCCKEN BIT(20) ++#define RCC_BDCR_VSWRST BIT(31) ++#define RCC_BDCR_LSEDRV_SHIFT 4 ++#define RCC_BDCR_RTCSRC_SHIFT 16 ++ ++/* RCC_RDLSICR register fields */ ++#define RCC_RDLSICR_LSION BIT(0) ++#define RCC_RDLSICR_LSIRDY BIT(1) ++#define RCC_RDLSICR_MRD_MASK GENMASK(20, 16) ++#define RCC_RDLSICR_EADLY_MASK GENMASK(26, 24) ++#define RCC_RDLSICR_SPARE_MASK GENMASK(31, 27) ++#define RCC_RDLSICR_MRD_SHIFT 16 ++#define RCC_RDLSICR_EADLY_SHIFT 24 ++#define RCC_RDLSICR_SPARE_SHIFT 27 ++ ++/* RCC_OCENSETR register fields */ ++#define RCC_OCENSETR_HSION BIT(0) ++#define RCC_OCENSETR_HSIKERON BIT(1) ++#define RCC_OCENSETR_CSION BIT(4) ++#define RCC_OCENSETR_CSIKERON BIT(5) ++#define RCC_OCENSETR_DIGBYP BIT(7) ++#define RCC_OCENSETR_HSEON BIT(8) ++#define RCC_OCENSETR_HSEKERON BIT(9) ++#define RCC_OCENSETR_HSEBYP BIT(10) ++#define RCC_OCENSETR_HSECSSON BIT(11) ++ ++/* RCC_OCENCLRR register fields */ ++#define RCC_OCENCLRR_HSION BIT(0) ++#define RCC_OCENCLRR_HSIKERON BIT(1) ++#define RCC_OCENCLRR_CSION BIT(4) ++#define RCC_OCENCLRR_CSIKERON BIT(5) ++#define RCC_OCENCLRR_DIGBYP BIT(7) ++#define RCC_OCENCLRR_HSEON BIT(8) ++#define RCC_OCENCLRR_HSEKERON BIT(9) ++#define RCC_OCENCLRR_HSEBYP BIT(10) ++ ++/* RCC_OCRDYR register fields */ ++#define RCC_OCRDYR_HSIRDY BIT(0) ++#define RCC_OCRDYR_HSIDIVRDY BIT(2) ++#define RCC_OCRDYR_CSIRDY BIT(4) ++#define RCC_OCRDYR_HSERDY BIT(8) ++#define RCC_OCRDYR_MPUCKRDY BIT(23) ++#define RCC_OCRDYR_AXICKRDY BIT(24) ++ ++/* RCC_HSICFGR register fields */ ++#define RCC_HSICFGR_HSIDIV_MASK GENMASK(1, 0) ++#define RCC_HSICFGR_HSITRIM_MASK GENMASK(14, 8) ++#define RCC_HSICFGR_HSICAL_MASK GENMASK(27, 16) ++#define RCC_HSICFGR_HSIDIV_SHIFT 0 ++#define RCC_HSICFGR_HSITRIM_SHIFT 8 ++#define RCC_HSICFGR_HSICAL_SHIFT 16 ++ ++/* RCC_CSICFGR register fields */ ++#define RCC_CSICFGR_CSITRIM_MASK GENMASK(12, 8) ++#define RCC_CSICFGR_CSICAL_MASK GENMASK(23, 16) ++#define RCC_CSICFGR_CSITRIM_SHIFT 8 ++#define RCC_CSICFGR_CSICAL_SHIFT 16 ++ ++/* RCC_MCO1CFGR register fields */ ++#define RCC_MCO1CFGR_MCO1SEL_MASK GENMASK(2, 0) ++#define RCC_MCO1CFGR_MCO1DIV_MASK GENMASK(7, 4) ++#define RCC_MCO1CFGR_MCO1ON BIT(12) ++#define RCC_MCO1CFGR_MCO1SEL_SHIFT 0 ++#define RCC_MCO1CFGR_MCO1DIV_SHIFT 4 ++ ++/* RCC_MCO2CFGR register fields */ ++#define RCC_MCO2CFGR_MCO2SEL_MASK GENMASK(2, 0) ++#define RCC_MCO2CFGR_MCO2DIV_MASK GENMASK(7, 4) ++#define RCC_MCO2CFGR_MCO2ON BIT(12) ++#define RCC_MCO2CFGR_MCO2SEL_SHIFT 0 ++#define RCC_MCO2CFGR_MCO2DIV_SHIFT 4 ++ ++/* RCC_DBGCFGR register fields */ ++#define RCC_DBGCFGR_TRACEDIV_MASK GENMASK(2, 0) ++#define RCC_DBGCFGR_DBGCKEN BIT(8) ++#define RCC_DBGCFGR_TRACECKEN BIT(9) ++#define RCC_DBGCFGR_DBGRST BIT(12) ++#define RCC_DBGCFGR_TRACEDIV_SHIFT 0 ++ ++/* RCC_RCK12SELR register fields */ ++#define RCC_RCK12SELR_PLL12SRC_MASK GENMASK(1, 0) ++#define RCC_RCK12SELR_PLL12SRCRDY BIT(31) ++#define RCC_RCK12SELR_PLL12SRC_SHIFT 0 ++ ++/* RCC_RCK3SELR register fields */ ++#define RCC_RCK3SELR_PLL3SRC_MASK GENMASK(1, 0) ++#define RCC_RCK3SELR_PLL3SRCRDY BIT(31) ++#define RCC_RCK3SELR_PLL3SRC_SHIFT 0 ++ ++/* RCC_RCK4SELR register fields */ ++#define RCC_RCK4SELR_PLL4SRC_MASK GENMASK(1, 0) ++#define RCC_RCK4SELR_PLL4SRCRDY BIT(31) ++#define RCC_RCK4SELR_PLL4SRC_SHIFT 0 ++ ++/* RCC_PLL1CR register fields */ ++#define RCC_PLL1CR_PLLON BIT(0) ++#define RCC_PLL1CR_PLL1RDY BIT(1) ++#define RCC_PLL1CR_SSCG_CTRL BIT(2) ++#define RCC_PLL1CR_DIVPEN BIT(4) ++#define RCC_PLL1CR_DIVQEN BIT(5) ++#define RCC_PLL1CR_DIVREN BIT(6) ++ ++/* RCC_PLL1CFGR1 register fields */ ++#define RCC_PLL1CFGR1_DIVN_MASK GENMASK(8, 0) ++#define RCC_PLL1CFGR1_DIVM1_MASK GENMASK(21, 16) ++#define RCC_PLL1CFGR1_DIVN_SHIFT 0 ++#define RCC_PLL1CFGR1_DIVM1_SHIFT 16 ++ ++/* RCC_PLL1CFGR2 register fields */ ++#define RCC_PLL1CFGR2_DIVP_MASK GENMASK(6, 0) ++#define RCC_PLL1CFGR2_DIVQ_MASK GENMASK(14, 8) ++#define RCC_PLL1CFGR2_DIVR_MASK GENMASK(22, 16) ++#define RCC_PLL1CFGR2_DIVP_SHIFT 0 ++#define RCC_PLL1CFGR2_DIVQ_SHIFT 8 ++#define RCC_PLL1CFGR2_DIVR_SHIFT 16 ++ ++/* RCC_PLL1FRACR register fields */ ++#define RCC_PLL1FRACR_FRACV_MASK GENMASK(15, 3) ++#define RCC_PLL1FRACR_FRACLE BIT(16) ++#define RCC_PLL1FRACR_FRACV_SHIFT 3 ++ ++/* RCC_PLL1CSGR register fields */ ++#define RCC_PLL1CSGR_MOD_PER_MASK GENMASK(12, 0) ++#define RCC_PLL1CSGR_TPDFN_DIS BIT(13) ++#define RCC_PLL1CSGR_RPDFN_DIS BIT(14) ++#define RCC_PLL1CSGR_SSCG_MODE BIT(15) ++#define RCC_PLL1CSGR_INC_STEP_MASK GENMASK(30, 16) ++#define RCC_PLL1CSGR_MOD_PER_SHIFT 0 ++#define RCC_PLL1CSGR_INC_STEP_SHIFT 16 ++ ++/* RCC_PLL2CR register fields */ ++#define RCC_PLL2CR_PLLON BIT(0) ++#define RCC_PLL2CR_PLL2RDY BIT(1) ++#define RCC_PLL2CR_SSCG_CTRL BIT(2) ++#define RCC_PLL2CR_DIVPEN BIT(4) ++#define RCC_PLL2CR_DIVQEN BIT(5) ++#define RCC_PLL2CR_DIVREN BIT(6) ++ ++/* RCC_PLL2CFGR1 register fields */ ++#define RCC_PLL2CFGR1_DIVN_MASK GENMASK(8, 0) ++#define RCC_PLL2CFGR1_DIVM2_MASK GENMASK(21, 16) ++#define RCC_PLL2CFGR1_DIVN_SHIFT 0 ++#define RCC_PLL2CFGR1_DIVM2_SHIFT 16 ++ ++/* RCC_PLL2CFGR2 register fields */ ++#define RCC_PLL2CFGR2_DIVP_MASK GENMASK(6, 0) ++#define RCC_PLL2CFGR2_DIVQ_MASK GENMASK(14, 8) ++#define RCC_PLL2CFGR2_DIVR_MASK GENMASK(22, 16) ++#define RCC_PLL2CFGR2_DIVP_SHIFT 0 ++#define RCC_PLL2CFGR2_DIVQ_SHIFT 8 ++#define RCC_PLL2CFGR2_DIVR_SHIFT 16 ++ ++/* RCC_PLL2FRACR register fields */ ++#define RCC_PLL2FRACR_FRACV_MASK GENMASK(15, 3) ++#define RCC_PLL2FRACR_FRACLE BIT(16) ++#define RCC_PLL2FRACR_FRACV_SHIFT 3 ++ ++/* RCC_PLL2CSGR register fields */ ++#define RCC_PLL2CSGR_MOD_PER_MASK GENMASK(12, 0) ++#define RCC_PLL2CSGR_TPDFN_DIS BIT(13) ++#define RCC_PLL2CSGR_RPDFN_DIS BIT(14) ++#define RCC_PLL2CSGR_SSCG_MODE BIT(15) ++#define RCC_PLL2CSGR_INC_STEP_MASK GENMASK(30, 16) ++#define RCC_PLL2CSGR_MOD_PER_SHIFT 0 ++#define RCC_PLL2CSGR_INC_STEP_SHIFT 16 ++ ++/* RCC_PLL3CR register fields */ ++#define RCC_PLL3CR_PLLON BIT(0) ++#define RCC_PLL3CR_PLL3RDY BIT(1) ++#define RCC_PLL3CR_SSCG_CTRL BIT(2) ++#define RCC_PLL3CR_DIVPEN BIT(4) ++#define RCC_PLL3CR_DIVQEN BIT(5) ++#define RCC_PLL3CR_DIVREN BIT(6) ++ ++/* RCC_PLL3CFGR1 register fields */ ++#define RCC_PLL3CFGR1_DIVN_MASK GENMASK(8, 0) ++#define RCC_PLL3CFGR1_DIVM3_MASK GENMASK(21, 16) ++#define RCC_PLL3CFGR1_IFRGE_MASK GENMASK(25, 24) ++#define RCC_PLL3CFGR1_DIVN_SHIFT 0 ++#define RCC_PLL3CFGR1_DIVM3_SHIFT 16 ++#define RCC_PLL3CFGR1_IFRGE_SHIFT 24 ++ ++/* RCC_PLL3CFGR2 register fields */ ++#define RCC_PLL3CFGR2_DIVP_MASK GENMASK(6, 0) ++#define RCC_PLL3CFGR2_DIVQ_MASK GENMASK(14, 8) ++#define RCC_PLL3CFGR2_DIVR_MASK GENMASK(22, 16) ++#define RCC_PLL3CFGR2_DIVP_SHIFT 0 ++#define RCC_PLL3CFGR2_DIVQ_SHIFT 8 ++#define RCC_PLL3CFGR2_DIVR_SHIFT 16 ++ ++/* RCC_PLL3FRACR register fields */ ++#define RCC_PLL3FRACR_FRACV_MASK GENMASK(15, 3) ++#define RCC_PLL3FRACR_FRACLE BIT(16) ++#define RCC_PLL3FRACR_FRACV_SHIFT 3 ++ ++/* RCC_PLL3CSGR register fields */ ++#define RCC_PLL3CSGR_MOD_PER_MASK GENMASK(12, 0) ++#define RCC_PLL3CSGR_TPDFN_DIS BIT(13) ++#define RCC_PLL3CSGR_RPDFN_DIS BIT(14) ++#define RCC_PLL3CSGR_SSCG_MODE BIT(15) ++#define RCC_PLL3CSGR_INC_STEP_MASK GENMASK(30, 16) ++#define RCC_PLL3CSGR_MOD_PER_SHIFT 0 ++#define RCC_PLL3CSGR_INC_STEP_SHIFT 16 ++ ++/* RCC_PLL4CR register fields */ ++#define RCC_PLL4CR_PLLON BIT(0) ++#define RCC_PLL4CR_PLL4RDY BIT(1) ++#define RCC_PLL4CR_SSCG_CTRL BIT(2) ++#define RCC_PLL4CR_DIVPEN BIT(4) ++#define RCC_PLL4CR_DIVQEN BIT(5) ++#define RCC_PLL4CR_DIVREN BIT(6) ++ ++/* RCC_PLL4CFGR1 register fields */ ++#define RCC_PLL4CFGR1_DIVN_MASK GENMASK(8, 0) ++#define RCC_PLL4CFGR1_DIVM4_MASK GENMASK(21, 16) ++#define RCC_PLL4CFGR1_IFRGE_MASK GENMASK(25, 24) ++#define RCC_PLL4CFGR1_DIVN_SHIFT 0 ++#define RCC_PLL4CFGR1_DIVM4_SHIFT 16 ++#define RCC_PLL4CFGR1_IFRGE_SHIFT 24 ++ ++/* RCC_PLL4CFGR2 register fields */ ++#define RCC_PLL4CFGR2_DIVP_MASK GENMASK(6, 0) ++#define RCC_PLL4CFGR2_DIVQ_MASK GENMASK(14, 8) ++#define RCC_PLL4CFGR2_DIVR_MASK GENMASK(22, 16) ++#define RCC_PLL4CFGR2_DIVP_SHIFT 0 ++#define RCC_PLL4CFGR2_DIVQ_SHIFT 8 ++#define RCC_PLL4CFGR2_DIVR_SHIFT 16 ++ ++/* RCC_PLL4FRACR register fields */ ++#define RCC_PLL4FRACR_FRACV_MASK GENMASK(15, 3) ++#define RCC_PLL4FRACR_FRACLE BIT(16) ++#define RCC_PLL4FRACR_FRACV_SHIFT 3 ++ ++/* RCC_PLL4CSGR register fields */ ++#define RCC_PLL4CSGR_MOD_PER_MASK GENMASK(12, 0) ++#define RCC_PLL4CSGR_TPDFN_DIS BIT(13) ++#define RCC_PLL4CSGR_RPDFN_DIS BIT(14) ++#define RCC_PLL4CSGR_SSCG_MODE BIT(15) ++#define RCC_PLL4CSGR_INC_STEP_MASK GENMASK(30, 16) ++#define RCC_PLL4CSGR_MOD_PER_SHIFT 0 ++#define RCC_PLL4CSGR_INC_STEP_SHIFT 16 ++ ++/* RCC_MPCKSELR register fields */ ++#define RCC_MPCKSELR_MPUSRC_MASK GENMASK(1, 0) ++#define RCC_MPCKSELR_MPUSRCRDY BIT(31) ++#define RCC_MPCKSELR_MPUSRC_SHIFT 0 ++ ++/* RCC_ASSCKSELR register fields */ ++#define RCC_ASSCKSELR_AXISSRC_MASK GENMASK(2, 0) ++#define RCC_ASSCKSELR_AXISSRCRDY BIT(31) ++#define RCC_ASSCKSELR_AXISSRC_SHIFT 0 ++ ++/* RCC_MSSCKSELR register fields */ ++#define RCC_MSSCKSELR_MLAHBSSRC_MASK GENMASK(1, 0) ++#define RCC_MSSCKSELR_MLAHBSSRCRDY BIT(31) ++#define RCC_MSSCKSELR_MLAHBSSRC_SHIFT 0 ++ ++/* RCC_CPERCKSELR register fields */ ++#define RCC_CPERCKSELR_CKPERSRC_MASK GENMASK(1, 0) ++#define RCC_CPERCKSELR_CKPERSRC_SHIFT 0 ++ ++/* RCC_RTCDIVR register fields */ ++#define RCC_RTCDIVR_RTCDIV_MASK GENMASK(5, 0) ++#define RCC_RTCDIVR_RTCDIV_SHIFT 0 ++ ++/* RCC_MPCKDIVR register fields */ ++#define RCC_MPCKDIVR_MPUDIV_MASK GENMASK(3, 0) ++#define RCC_MPCKDIVR_MPUDIVRDY BIT(31) ++#define RCC_MPCKDIVR_MPUDIV_SHIFT 0 ++ ++/* RCC_AXIDIVR register fields */ ++#define RCC_AXIDIVR_AXIDIV_MASK GENMASK(2, 0) ++#define RCC_AXIDIVR_AXIDIVRDY BIT(31) ++#define RCC_AXIDIVR_AXIDIV_SHIFT 0 ++ ++/* RCC_MLAHBDIVR register fields */ ++#define RCC_MLAHBDIVR_MLAHBDIV_MASK GENMASK(3, 0) ++#define RCC_MLAHBDIVR_MLAHBDIVRDY BIT(31) ++#define RCC_MLAHBDIVR_MLAHBDIV_SHIFT 0 ++ ++/* RCC_APB1DIVR register fields */ ++#define RCC_APB1DIVR_APB1DIV_MASK GENMASK(2, 0) ++#define RCC_APB1DIVR_APB1DIVRDY BIT(31) ++#define RCC_APB1DIVR_APB1DIV_SHIFT 0 ++ ++/* RCC_APB2DIVR register fields */ ++#define RCC_APB2DIVR_APB2DIV_MASK GENMASK(2, 0) ++#define RCC_APB2DIVR_APB2DIVRDY BIT(31) ++#define RCC_APB2DIVR_APB2DIV_SHIFT 0 ++ ++/* RCC_APB3DIVR register fields */ ++#define RCC_APB3DIVR_APB3DIV_MASK GENMASK(2, 0) ++#define RCC_APB3DIVR_APB3DIVRDY BIT(31) ++#define RCC_APB3DIVR_APB3DIV_SHIFT 0 ++ ++/* RCC_APB4DIVR register fields */ ++#define RCC_APB4DIVR_APB4DIV_MASK GENMASK(2, 0) ++#define RCC_APB4DIVR_APB4DIVRDY BIT(31) ++#define RCC_APB4DIVR_APB4DIV_SHIFT 0 ++ ++/* RCC_APB5DIVR register fields */ ++#define RCC_APB5DIVR_APB5DIV_MASK GENMASK(2, 0) ++#define RCC_APB5DIVR_APB5DIVRDY BIT(31) ++#define RCC_APB5DIVR_APB5DIV_SHIFT 0 ++ ++/* RCC_APB6DIVR register fields */ ++#define RCC_APB6DIVR_APB6DIV_MASK GENMASK(2, 0) ++#define RCC_APB6DIVR_APB6DIVRDY BIT(31) ++#define RCC_APB6DIVR_APB6DIV_SHIFT 0 ++ ++/* RCC_TIMG1PRER register fields */ ++#define RCC_TIMG1PRER_TIMG1PRE BIT(0) ++#define RCC_TIMG1PRER_TIMG1PRERDY BIT(31) ++ ++/* RCC_TIMG2PRER register fields */ ++#define RCC_TIMG2PRER_TIMG2PRE BIT(0) ++#define RCC_TIMG2PRER_TIMG2PRERDY BIT(31) ++ ++/* RCC_TIMG3PRER register fields */ ++#define RCC_TIMG3PRER_TIMG3PRE BIT(0) ++#define RCC_TIMG3PRER_TIMG3PRERDY BIT(31) ++ ++/* RCC_DDRITFCR register fields */ ++#define RCC_DDRITFCR_DDRC1EN BIT(0) ++#define RCC_DDRITFCR_DDRC1LPEN BIT(1) ++#define RCC_DDRITFCR_DDRPHYCEN BIT(4) ++#define RCC_DDRITFCR_DDRPHYCLPEN BIT(5) ++#define RCC_DDRITFCR_DDRCAPBEN BIT(6) ++#define RCC_DDRITFCR_DDRCAPBLPEN BIT(7) ++#define RCC_DDRITFCR_AXIDCGEN BIT(8) ++#define RCC_DDRITFCR_DDRPHYCAPBEN BIT(9) ++#define RCC_DDRITFCR_DDRPHYCAPBLPEN BIT(10) ++#define RCC_DDRITFCR_KERDCG_DLY_MASK GENMASK(13, 11) ++#define RCC_DDRITFCR_DDRCAPBRST BIT(14) ++#define RCC_DDRITFCR_DDRCAXIRST BIT(15) ++#define RCC_DDRITFCR_DDRCORERST BIT(16) ++#define RCC_DDRITFCR_DPHYAPBRST BIT(17) ++#define RCC_DDRITFCR_DPHYRST BIT(18) ++#define RCC_DDRITFCR_DPHYCTLRST BIT(19) ++#define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20) ++#define RCC_DDRITFCR_GSKPMOD BIT(23) ++#define RCC_DDRITFCR_GSKPCTRL BIT(24) ++#define RCC_DDRITFCR_DFILP_WIDTH_MASK GENMASK(27, 25) ++#define RCC_DDRITFCR_GSKP_DUR_MASK GENMASK(31, 28) ++#define RCC_DDRITFCR_KERDCG_DLY_SHIFT 11 ++#define RCC_DDRITFCR_DDRCKMOD_SHIFT 20 ++#define RCC_DDRITFCR_DFILP_WIDTH_SHIFT 25 ++#define RCC_DDRITFCR_GSKP_DUR_SHIFT 28 ++ ++/* RCC_I2C12CKSELR register fields */ ++#define RCC_I2C12CKSELR_I2C12SRC_MASK GENMASK(2, 0) ++#define RCC_I2C12CKSELR_I2C12SRC_SHIFT 0 ++ ++/* RCC_I2C345CKSELR register fields */ ++#define RCC_I2C345CKSELR_I2C3SRC_MASK GENMASK(2, 0) ++#define RCC_I2C345CKSELR_I2C4SRC_MASK GENMASK(5, 3) ++#define RCC_I2C345CKSELR_I2C5SRC_MASK GENMASK(8, 6) ++#define RCC_I2C345CKSELR_I2C3SRC_SHIFT 0 ++#define RCC_I2C345CKSELR_I2C4SRC_SHIFT 3 ++#define RCC_I2C345CKSELR_I2C5SRC_SHIFT 6 ++ ++/* RCC_SPI2S1CKSELR register fields */ ++#define RCC_SPI2S1CKSELR_SPI1SRC_MASK GENMASK(2, 0) ++#define RCC_SPI2S1CKSELR_SPI1SRC_SHIFT 0 ++ ++/* RCC_SPI2S23CKSELR register fields */ ++#define RCC_SPI2S23CKSELR_SPI23SRC_MASK GENMASK(2, 0) ++#define RCC_SPI2S23CKSELR_SPI23SRC_SHIFT 0 ++ ++/* RCC_SPI45CKSELR register fields */ ++#define RCC_SPI45CKSELR_SPI4SRC_MASK GENMASK(2, 0) ++#define RCC_SPI45CKSELR_SPI5SRC_MASK GENMASK(5, 3) ++#define RCC_SPI45CKSELR_SPI4SRC_SHIFT 0 ++#define RCC_SPI45CKSELR_SPI5SRC_SHIFT 3 ++ ++/* RCC_UART12CKSELR register fields */ ++#define RCC_UART12CKSELR_UART1SRC_MASK GENMASK(2, 0) ++#define RCC_UART12CKSELR_UART2SRC_MASK GENMASK(5, 3) ++#define RCC_UART12CKSELR_UART1SRC_SHIFT 0 ++#define RCC_UART12CKSELR_UART2SRC_SHIFT 3 ++ ++/* RCC_UART35CKSELR register fields */ ++#define RCC_UART35CKSELR_UART35SRC_MASK GENMASK(2, 0) ++#define RCC_UART35CKSELR_UART35SRC_SHIFT 0 ++ ++/* RCC_UART4CKSELR register fields */ ++#define RCC_UART4CKSELR_UART4SRC_MASK GENMASK(2, 0) ++#define RCC_UART4CKSELR_UART4SRC_SHIFT 0 ++ ++/* RCC_UART6CKSELR register fields */ ++#define RCC_UART6CKSELR_UART6SRC_MASK GENMASK(2, 0) ++#define RCC_UART6CKSELR_UART6SRC_SHIFT 0 ++ ++/* RCC_UART78CKSELR register fields */ ++#define RCC_UART78CKSELR_UART78SRC_MASK GENMASK(2, 0) ++#define RCC_UART78CKSELR_UART78SRC_SHIFT 0 ++ ++/* RCC_LPTIM1CKSELR register fields */ ++#define RCC_LPTIM1CKSELR_LPTIM1SRC_MASK GENMASK(2, 0) ++#define RCC_LPTIM1CKSELR_LPTIM1SRC_SHIFT 0 ++ ++/* RCC_LPTIM23CKSELR register fields */ ++#define RCC_LPTIM23CKSELR_LPTIM2SRC_MASK GENMASK(2, 0) ++#define RCC_LPTIM23CKSELR_LPTIM3SRC_MASK GENMASK(5, 3) ++#define RCC_LPTIM23CKSELR_LPTIM2SRC_SHIFT 0 ++#define RCC_LPTIM23CKSELR_LPTIM3SRC_SHIFT 3 ++ ++/* RCC_LPTIM45CKSELR register fields */ ++#define RCC_LPTIM45CKSELR_LPTIM45SRC_MASK GENMASK(2, 0) ++#define RCC_LPTIM45CKSELR_LPTIM45SRC_SHIFT 0 ++ ++/* RCC_SAI1CKSELR register fields */ ++#define RCC_SAI1CKSELR_SAI1SRC_MASK GENMASK(2, 0) ++#define RCC_SAI1CKSELR_SAI1SRC_SHIFT 0 ++ ++/* RCC_SAI2CKSELR register fields */ ++#define RCC_SAI2CKSELR_SAI2SRC_MASK GENMASK(2, 0) ++#define RCC_SAI2CKSELR_SAI2SRC_SHIFT 0 ++ ++/* RCC_FDCANCKSELR register fields */ ++#define RCC_FDCANCKSELR_FDCANSRC_MASK GENMASK(1, 0) ++#define RCC_FDCANCKSELR_FDCANSRC_SHIFT 0 ++ ++/* RCC_SPDIFCKSELR register fields */ ++#define RCC_SPDIFCKSELR_SPDIFSRC_MASK GENMASK(1, 0) ++#define RCC_SPDIFCKSELR_SPDIFSRC_SHIFT 0 ++ ++/* RCC_ADC12CKSELR register fields */ ++#define RCC_ADC12CKSELR_ADC1SRC_MASK GENMASK(1, 0) ++#define RCC_ADC12CKSELR_ADC2SRC_MASK GENMASK(3, 2) ++#define RCC_ADC12CKSELR_ADC1SRC_SHIFT 0 ++#define RCC_ADC12CKSELR_ADC2SRC_SHIFT 2 ++ ++/* RCC_SDMMC12CKSELR register fields */ ++#define RCC_SDMMC12CKSELR_SDMMC1SRC_MASK GENMASK(2, 0) ++#define RCC_SDMMC12CKSELR_SDMMC2SRC_MASK GENMASK(5, 3) ++#define RCC_SDMMC12CKSELR_SDMMC1SRC_SHIFT 0 ++#define RCC_SDMMC12CKSELR_SDMMC2SRC_SHIFT 3 ++ ++/* RCC_ETH12CKSELR register fields */ ++#define RCC_ETH12CKSELR_ETH1SRC_MASK GENMASK(1, 0) ++#define RCC_ETH12CKSELR_ETH1PTPDIV_MASK GENMASK(7, 4) ++#define RCC_ETH12CKSELR_ETH2SRC_MASK GENMASK(9, 8) ++#define RCC_ETH12CKSELR_ETH2PTPDIV_MASK GENMASK(15, 12) ++#define RCC_ETH12CKSELR_ETH1SRC_SHIFT 0 ++#define RCC_ETH12CKSELR_ETH1PTPDIV_SHIFT 4 ++#define RCC_ETH12CKSELR_ETH2SRC_SHIFT 8 ++#define RCC_ETH12CKSELR_ETH2PTPDIV_SHIFT 12 ++ ++/* RCC_USBCKSELR register fields */ ++#define RCC_USBCKSELR_USBPHYSRC_MASK GENMASK(1, 0) ++#define RCC_USBCKSELR_USBOSRC BIT(4) ++#define RCC_USBCKSELR_USBPHYSRC_SHIFT 0 ++ ++/* RCC_QSPICKSELR register fields */ ++#define RCC_QSPICKSELR_QSPISRC_MASK GENMASK(1, 0) ++#define RCC_QSPICKSELR_QSPISRC_SHIFT 0 ++ ++/* RCC_FMCCKSELR register fields */ ++#define RCC_FMCCKSELR_FMCSRC_MASK GENMASK(1, 0) ++#define RCC_FMCCKSELR_FMCSRC_SHIFT 0 ++ ++/* RCC_RNG1CKSELR register fields */ ++#define RCC_RNG1CKSELR_RNG1SRC_MASK GENMASK(1, 0) ++#define RCC_RNG1CKSELR_RNG1SRC_SHIFT 0 ++ ++/* RCC_STGENCKSELR register fields */ ++#define RCC_STGENCKSELR_STGENSRC_MASK GENMASK(1, 0) ++#define RCC_STGENCKSELR_STGENSRC_SHIFT 0 ++ ++/* RCC_DCMIPPCKSELR register fields */ ++#define RCC_DCMIPPCKSELR_DCMIPPSRC_MASK GENMASK(1, 0) ++#define RCC_DCMIPPCKSELR_DCMIPPSRC_SHIFT 0 ++ ++/* RCC_SAESCKSELR register fields */ ++#define RCC_SAESCKSELR_SAESSRC_MASK GENMASK(1, 0) ++#define RCC_SAESCKSELR_SAESSRC_SHIFT 0 ++ ++/* RCC_APB1RSTSETR register fields */ ++#define RCC_APB1RSTSETR_TIM2RST BIT(0) ++#define RCC_APB1RSTSETR_TIM3RST BIT(1) ++#define RCC_APB1RSTSETR_TIM4RST BIT(2) ++#define RCC_APB1RSTSETR_TIM5RST BIT(3) ++#define RCC_APB1RSTSETR_TIM6RST BIT(4) ++#define RCC_APB1RSTSETR_TIM7RST BIT(5) ++#define RCC_APB1RSTSETR_LPTIM1RST BIT(9) ++#define RCC_APB1RSTSETR_SPI2RST BIT(11) ++#define RCC_APB1RSTSETR_SPI3RST BIT(12) ++#define RCC_APB1RSTSETR_USART3RST BIT(15) ++#define RCC_APB1RSTSETR_UART4RST BIT(16) ++#define RCC_APB1RSTSETR_UART5RST BIT(17) ++#define RCC_APB1RSTSETR_UART7RST BIT(18) ++#define RCC_APB1RSTSETR_UART8RST BIT(19) ++#define RCC_APB1RSTSETR_I2C1RST BIT(21) ++#define RCC_APB1RSTSETR_I2C2RST BIT(22) ++#define RCC_APB1RSTSETR_SPDIFRST BIT(26) ++ ++/* RCC_APB1RSTCLRR register fields */ ++#define RCC_APB1RSTCLRR_TIM2RST BIT(0) ++#define RCC_APB1RSTCLRR_TIM3RST BIT(1) ++#define RCC_APB1RSTCLRR_TIM4RST BIT(2) ++#define RCC_APB1RSTCLRR_TIM5RST BIT(3) ++#define RCC_APB1RSTCLRR_TIM6RST BIT(4) ++#define RCC_APB1RSTCLRR_TIM7RST BIT(5) ++#define RCC_APB1RSTCLRR_LPTIM1RST BIT(9) ++#define RCC_APB1RSTCLRR_SPI2RST BIT(11) ++#define RCC_APB1RSTCLRR_SPI3RST BIT(12) ++#define RCC_APB1RSTCLRR_USART3RST BIT(15) ++#define RCC_APB1RSTCLRR_UART4RST BIT(16) ++#define RCC_APB1RSTCLRR_UART5RST BIT(17) ++#define RCC_APB1RSTCLRR_UART7RST BIT(18) ++#define RCC_APB1RSTCLRR_UART8RST BIT(19) ++#define RCC_APB1RSTCLRR_I2C1RST BIT(21) ++#define RCC_APB1RSTCLRR_I2C2RST BIT(22) ++#define RCC_APB1RSTCLRR_SPDIFRST BIT(26) ++ ++/* RCC_APB2RSTSETR register fields */ ++#define RCC_APB2RSTSETR_TIM1RST BIT(0) ++#define RCC_APB2RSTSETR_TIM8RST BIT(1) ++#define RCC_APB2RSTSETR_SPI1RST BIT(8) ++#define RCC_APB2RSTSETR_USART6RST BIT(13) ++#define RCC_APB2RSTSETR_SAI1RST BIT(16) ++#define RCC_APB2RSTSETR_SAI2RST BIT(17) ++#define RCC_APB2RSTSETR_DFSDMRST BIT(20) ++#define RCC_APB2RSTSETR_FDCANRST BIT(24) ++ ++/* RCC_APB2RSTCLRR register fields */ ++#define RCC_APB2RSTCLRR_TIM1RST BIT(0) ++#define RCC_APB2RSTCLRR_TIM8RST BIT(1) ++#define RCC_APB2RSTCLRR_SPI1RST BIT(8) ++#define RCC_APB2RSTCLRR_USART6RST BIT(13) ++#define RCC_APB2RSTCLRR_SAI1RST BIT(16) ++#define RCC_APB2RSTCLRR_SAI2RST BIT(17) ++#define RCC_APB2RSTCLRR_DFSDMRST BIT(20) ++#define RCC_APB2RSTCLRR_FDCANRST BIT(24) ++ ++/* RCC_APB3RSTSETR register fields */ ++#define RCC_APB3RSTSETR_LPTIM2RST BIT(0) ++#define RCC_APB3RSTSETR_LPTIM3RST BIT(1) ++#define RCC_APB3RSTSETR_LPTIM4RST BIT(2) ++#define RCC_APB3RSTSETR_LPTIM5RST BIT(3) ++#define RCC_APB3RSTSETR_SYSCFGRST BIT(11) ++#define RCC_APB3RSTSETR_VREFRST BIT(13) ++#define RCC_APB3RSTSETR_DTSRST BIT(16) ++#define RCC_APB3RSTSETR_PMBCTRLRST BIT(17) ++ ++/* RCC_APB3RSTCLRR register fields */ ++#define RCC_APB3RSTCLRR_LPTIM2RST BIT(0) ++#define RCC_APB3RSTCLRR_LPTIM3RST BIT(1) ++#define RCC_APB3RSTCLRR_LPTIM4RST BIT(2) ++#define RCC_APB3RSTCLRR_LPTIM5RST BIT(3) ++#define RCC_APB3RSTCLRR_SYSCFGRST BIT(11) ++#define RCC_APB3RSTCLRR_VREFRST BIT(13) ++#define RCC_APB3RSTCLRR_DTSRST BIT(16) ++#define RCC_APB3RSTCLRR_PMBCTRLRST BIT(17) ++ ++/* RCC_APB4RSTSETR register fields */ ++#define RCC_APB4RSTSETR_LTDCRST BIT(0) ++#define RCC_APB4RSTSETR_DCMIPPRST BIT(1) ++#define RCC_APB4RSTSETR_DDRPERFMRST BIT(8) ++#define RCC_APB4RSTSETR_USBPHYRST BIT(16) ++ ++/* RCC_APB4RSTCLRR register fields */ ++#define RCC_APB4RSTCLRR_LTDCRST BIT(0) ++#define RCC_APB4RSTCLRR_DCMIPPRST BIT(1) ++#define RCC_APB4RSTCLRR_DDRPERFMRST BIT(8) ++#define RCC_APB4RSTCLRR_USBPHYRST BIT(16) ++ ++/* RCC_APB5RSTSETR register fields */ ++#define RCC_APB5RSTSETR_STGENRST BIT(20) ++ ++/* RCC_APB5RSTCLRR register fields */ ++#define RCC_APB5RSTCLRR_STGENRST BIT(20) ++ ++/* RCC_APB6RSTSETR register fields */ ++#define RCC_APB6RSTSETR_USART1RST BIT(0) ++#define RCC_APB6RSTSETR_USART2RST BIT(1) ++#define RCC_APB6RSTSETR_SPI4RST BIT(2) ++#define RCC_APB6RSTSETR_SPI5RST BIT(3) ++#define RCC_APB6RSTSETR_I2C3RST BIT(4) ++#define RCC_APB6RSTSETR_I2C4RST BIT(5) ++#define RCC_APB6RSTSETR_I2C5RST BIT(6) ++#define RCC_APB6RSTSETR_TIM12RST BIT(7) ++#define RCC_APB6RSTSETR_TIM13RST BIT(8) ++#define RCC_APB6RSTSETR_TIM14RST BIT(9) ++#define RCC_APB6RSTSETR_TIM15RST BIT(10) ++#define RCC_APB6RSTSETR_TIM16RST BIT(11) ++#define RCC_APB6RSTSETR_TIM17RST BIT(12) ++ ++/* RCC_APB6RSTCLRR register fields */ ++#define RCC_APB6RSTCLRR_USART1RST BIT(0) ++#define RCC_APB6RSTCLRR_USART2RST BIT(1) ++#define RCC_APB6RSTCLRR_SPI4RST BIT(2) ++#define RCC_APB6RSTCLRR_SPI5RST BIT(3) ++#define RCC_APB6RSTCLRR_I2C3RST BIT(4) ++#define RCC_APB6RSTCLRR_I2C4RST BIT(5) ++#define RCC_APB6RSTCLRR_I2C5RST BIT(6) ++#define RCC_APB6RSTCLRR_TIM12RST BIT(7) ++#define RCC_APB6RSTCLRR_TIM13RST BIT(8) ++#define RCC_APB6RSTCLRR_TIM14RST BIT(9) ++#define RCC_APB6RSTCLRR_TIM15RST BIT(10) ++#define RCC_APB6RSTCLRR_TIM16RST BIT(11) ++#define RCC_APB6RSTCLRR_TIM17RST BIT(12) ++ ++/* RCC_AHB2RSTSETR register fields */ ++#define RCC_AHB2RSTSETR_DMA1RST BIT(0) ++#define RCC_AHB2RSTSETR_DMA2RST BIT(1) ++#define RCC_AHB2RSTSETR_DMAMUX1RST BIT(2) ++#define RCC_AHB2RSTSETR_DMA3RST BIT(3) ++#define RCC_AHB2RSTSETR_DMAMUX2RST BIT(4) ++#define RCC_AHB2RSTSETR_ADC1RST BIT(5) ++#define RCC_AHB2RSTSETR_ADC2RST BIT(6) ++#define RCC_AHB2RSTSETR_USBORST BIT(8) ++ ++/* RCC_AHB2RSTCLRR register fields */ ++#define RCC_AHB2RSTCLRR_DMA1RST BIT(0) ++#define RCC_AHB2RSTCLRR_DMA2RST BIT(1) ++#define RCC_AHB2RSTCLRR_DMAMUX1RST BIT(2) ++#define RCC_AHB2RSTCLRR_DMA3RST BIT(3) ++#define RCC_AHB2RSTCLRR_DMAMUX2RST BIT(4) ++#define RCC_AHB2RSTCLRR_ADC1RST BIT(5) ++#define RCC_AHB2RSTCLRR_ADC2RST BIT(6) ++#define RCC_AHB2RSTCLRR_USBORST BIT(8) ++ ++/* RCC_AHB4RSTSETR register fields */ ++#define RCC_AHB4RSTSETR_GPIOARST BIT(0) ++#define RCC_AHB4RSTSETR_GPIOBRST BIT(1) ++#define RCC_AHB4RSTSETR_GPIOCRST BIT(2) ++#define RCC_AHB4RSTSETR_GPIODRST BIT(3) ++#define RCC_AHB4RSTSETR_GPIOERST BIT(4) ++#define RCC_AHB4RSTSETR_GPIOFRST BIT(5) ++#define RCC_AHB4RSTSETR_GPIOGRST BIT(6) ++#define RCC_AHB4RSTSETR_GPIOHRST BIT(7) ++#define RCC_AHB4RSTSETR_GPIOIRST BIT(8) ++#define RCC_AHB4RSTSETR_TSCRST BIT(15) ++ ++/* RCC_AHB4RSTCLRR register fields */ ++#define RCC_AHB4RSTCLRR_GPIOARST BIT(0) ++#define RCC_AHB4RSTCLRR_GPIOBRST BIT(1) ++#define RCC_AHB4RSTCLRR_GPIOCRST BIT(2) ++#define RCC_AHB4RSTCLRR_GPIODRST BIT(3) ++#define RCC_AHB4RSTCLRR_GPIOERST BIT(4) ++#define RCC_AHB4RSTCLRR_GPIOFRST BIT(5) ++#define RCC_AHB4RSTCLRR_GPIOGRST BIT(6) ++#define RCC_AHB4RSTCLRR_GPIOHRST BIT(7) ++#define RCC_AHB4RSTCLRR_GPIOIRST BIT(8) ++#define RCC_AHB4RSTCLRR_TSCRST BIT(15) ++ ++/* RCC_AHB5RSTSETR register fields */ ++#define RCC_AHB5RSTSETR_PKARST BIT(2) ++#define RCC_AHB5RSTSETR_SAESRST BIT(3) ++#define RCC_AHB5RSTSETR_CRYP1RST BIT(4) ++#define RCC_AHB5RSTSETR_HASH1RST BIT(5) ++#define RCC_AHB5RSTSETR_RNG1RST BIT(6) ++#define RCC_AHB5RSTSETR_AXIMCRST BIT(16) ++ ++/* RCC_AHB5RSTCLRR register fields */ ++#define RCC_AHB5RSTCLRR_PKARST BIT(2) ++#define RCC_AHB5RSTCLRR_SAESRST BIT(3) ++#define RCC_AHB5RSTCLRR_CRYP1RST BIT(4) ++#define RCC_AHB5RSTCLRR_HASH1RST BIT(5) ++#define RCC_AHB5RSTCLRR_RNG1RST BIT(6) ++#define RCC_AHB5RSTCLRR_AXIMCRST BIT(16) ++ ++/* RCC_AHB6RSTSETR register fields */ ++#define RCC_AHB6RSTSETR_MDMARST BIT(0) ++#define RCC_AHB6RSTSETR_MCERST BIT(1) ++#define RCC_AHB6RSTSETR_ETH1MACRST BIT(10) ++#define RCC_AHB6RSTSETR_FMCRST BIT(12) ++#define RCC_AHB6RSTSETR_QSPIRST BIT(14) ++#define RCC_AHB6RSTSETR_SDMMC1RST BIT(16) ++#define RCC_AHB6RSTSETR_SDMMC2RST BIT(17) ++#define RCC_AHB6RSTSETR_CRC1RST BIT(20) ++#define RCC_AHB6RSTSETR_USBHRST BIT(24) ++#define RCC_AHB6RSTSETR_ETH2MACRST BIT(30) ++ ++/* RCC_AHB6RSTCLRR register fields */ ++#define RCC_AHB6RSTCLRR_MDMARST BIT(0) ++#define RCC_AHB6RSTCLRR_MCERST BIT(1) ++#define RCC_AHB6RSTCLRR_ETH1MACRST BIT(10) ++#define RCC_AHB6RSTCLRR_FMCRST BIT(12) ++#define RCC_AHB6RSTCLRR_QSPIRST BIT(14) ++#define RCC_AHB6RSTCLRR_SDMMC1RST BIT(16) ++#define RCC_AHB6RSTCLRR_SDMMC2RST BIT(17) ++#define RCC_AHB6RSTCLRR_CRC1RST BIT(20) ++#define RCC_AHB6RSTCLRR_USBHRST BIT(24) ++#define RCC_AHB6RSTCLRR_ETH2MACRST BIT(30) ++ ++/* RCC_MP_APB1ENSETR register fields */ ++#define RCC_MP_APB1ENSETR_TIM2EN BIT(0) ++#define RCC_MP_APB1ENSETR_TIM3EN BIT(1) ++#define RCC_MP_APB1ENSETR_TIM4EN BIT(2) ++#define RCC_MP_APB1ENSETR_TIM5EN BIT(3) ++#define RCC_MP_APB1ENSETR_TIM6EN BIT(4) ++#define RCC_MP_APB1ENSETR_TIM7EN BIT(5) ++#define RCC_MP_APB1ENSETR_LPTIM1EN BIT(9) ++#define RCC_MP_APB1ENSETR_SPI2EN BIT(11) ++#define RCC_MP_APB1ENSETR_SPI3EN BIT(12) ++#define RCC_MP_APB1ENSETR_USART3EN BIT(15) ++#define RCC_MP_APB1ENSETR_UART4EN BIT(16) ++#define RCC_MP_APB1ENSETR_UART5EN BIT(17) ++#define RCC_MP_APB1ENSETR_UART7EN BIT(18) ++#define RCC_MP_APB1ENSETR_UART8EN BIT(19) ++#define RCC_MP_APB1ENSETR_I2C1EN BIT(21) ++#define RCC_MP_APB1ENSETR_I2C2EN BIT(22) ++#define RCC_MP_APB1ENSETR_SPDIFEN BIT(26) ++ ++/* RCC_MP_APB1ENCLRR register fields */ ++#define RCC_MP_APB1ENCLRR_TIM2EN BIT(0) ++#define RCC_MP_APB1ENCLRR_TIM3EN BIT(1) ++#define RCC_MP_APB1ENCLRR_TIM4EN BIT(2) ++#define RCC_MP_APB1ENCLRR_TIM5EN BIT(3) ++#define RCC_MP_APB1ENCLRR_TIM6EN BIT(4) ++#define RCC_MP_APB1ENCLRR_TIM7EN BIT(5) ++#define RCC_MP_APB1ENCLRR_LPTIM1EN BIT(9) ++#define RCC_MP_APB1ENCLRR_SPI2EN BIT(11) ++#define RCC_MP_APB1ENCLRR_SPI3EN BIT(12) ++#define RCC_MP_APB1ENCLRR_USART3EN BIT(15) ++#define RCC_MP_APB1ENCLRR_UART4EN BIT(16) ++#define RCC_MP_APB1ENCLRR_UART5EN BIT(17) ++#define RCC_MP_APB1ENCLRR_UART7EN BIT(18) ++#define RCC_MP_APB1ENCLRR_UART8EN BIT(19) ++#define RCC_MP_APB1ENCLRR_I2C1EN BIT(21) ++#define RCC_MP_APB1ENCLRR_I2C2EN BIT(22) ++#define RCC_MP_APB1ENCLRR_SPDIFEN BIT(26) ++ ++/* RCC_MP_APB2ENSETR register fields */ ++#define RCC_MP_APB2ENSETR_TIM1EN BIT(0) ++#define RCC_MP_APB2ENSETR_TIM8EN BIT(1) ++#define RCC_MP_APB2ENSETR_SPI1EN BIT(8) ++#define RCC_MP_APB2ENSETR_USART6EN BIT(13) ++#define RCC_MP_APB2ENSETR_SAI1EN BIT(16) ++#define RCC_MP_APB2ENSETR_SAI2EN BIT(17) ++#define RCC_MP_APB2ENSETR_DFSDMEN BIT(20) ++#define RCC_MP_APB2ENSETR_ADFSDMEN BIT(21) ++#define RCC_MP_APB2ENSETR_FDCANEN BIT(24) ++ ++/* RCC_MP_APB2ENCLRR register fields */ ++#define RCC_MP_APB2ENCLRR_TIM1EN BIT(0) ++#define RCC_MP_APB2ENCLRR_TIM8EN BIT(1) ++#define RCC_MP_APB2ENCLRR_SPI1EN BIT(8) ++#define RCC_MP_APB2ENCLRR_USART6EN BIT(13) ++#define RCC_MP_APB2ENCLRR_SAI1EN BIT(16) ++#define RCC_MP_APB2ENCLRR_SAI2EN BIT(17) ++#define RCC_MP_APB2ENCLRR_DFSDMEN BIT(20) ++#define RCC_MP_APB2ENCLRR_ADFSDMEN BIT(21) ++#define RCC_MP_APB2ENCLRR_FDCANEN BIT(24) ++ ++/* RCC_MP_APB3ENSETR register fields */ ++#define RCC_MP_APB3ENSETR_LPTIM2EN BIT(0) ++#define RCC_MP_APB3ENSETR_LPTIM3EN BIT(1) ++#define RCC_MP_APB3ENSETR_LPTIM4EN BIT(2) ++#define RCC_MP_APB3ENSETR_LPTIM5EN BIT(3) ++#define RCC_MP_APB3ENSETR_VREFEN BIT(13) ++#define RCC_MP_APB3ENSETR_DTSEN BIT(16) ++#define RCC_MP_APB3ENSETR_PMBCTRLEN BIT(17) ++#define RCC_MP_APB3ENSETR_HDPEN BIT(20) ++ ++/* RCC_MP_APB3ENCLRR register fields */ ++#define RCC_MP_APB3ENCLRR_LPTIM2EN BIT(0) ++#define RCC_MP_APB3ENCLRR_LPTIM3EN BIT(1) ++#define RCC_MP_APB3ENCLRR_LPTIM4EN BIT(2) ++#define RCC_MP_APB3ENCLRR_LPTIM5EN BIT(3) ++#define RCC_MP_APB3ENCLRR_VREFEN BIT(13) ++#define RCC_MP_APB3ENCLRR_DTSEN BIT(16) ++#define RCC_MP_APB3ENCLRR_PMBCTRLEN BIT(17) ++#define RCC_MP_APB3ENCLRR_HDPEN BIT(20) ++ ++/* RCC_MP_S_APB3ENSETR register fields */ ++#define RCC_MP_S_APB3ENSETR_SYSCFGEN BIT(0) ++ ++/* RCC_MP_S_APB3ENCLRR register fields */ ++#define RCC_MP_S_APB3ENCLRR_SYSCFGEN BIT(0) ++ ++/* RCC_MP_NS_APB3ENSETR register fields */ ++#define RCC_MP_NS_APB3ENSETR_SYSCFGEN BIT(0) ++ ++/* RCC_MP_NS_APB3ENCLRR register fields */ ++#define RCC_MP_NS_APB3ENCLRR_SYSCFGEN BIT(0) ++ ++/* RCC_MP_APB4ENSETR register fields */ ++#define RCC_MP_APB4ENSETR_DCMIPPEN BIT(1) ++#define RCC_MP_APB4ENSETR_DDRPERFMEN BIT(8) ++#define RCC_MP_APB4ENSETR_IWDG2APBEN BIT(15) ++#define RCC_MP_APB4ENSETR_USBPHYEN BIT(16) ++#define RCC_MP_APB4ENSETR_STGENROEN BIT(20) ++ ++/* RCC_MP_APB4ENCLRR register fields */ ++#define RCC_MP_APB4ENCLRR_DCMIPPEN BIT(1) ++#define RCC_MP_APB4ENCLRR_DDRPERFMEN BIT(8) ++#define RCC_MP_APB4ENCLRR_IWDG2APBEN BIT(15) ++#define RCC_MP_APB4ENCLRR_USBPHYEN BIT(16) ++#define RCC_MP_APB4ENCLRR_STGENROEN BIT(20) ++ ++/* RCC_MP_S_APB4ENSETR register fields */ ++#define RCC_MP_S_APB4ENSETR_LTDCEN BIT(0) ++ ++/* RCC_MP_S_APB4ENCLRR register fields */ ++#define RCC_MP_S_APB4ENCLRR_LTDCEN BIT(0) ++ ++/* RCC_MP_NS_APB4ENSETR register fields */ ++#define RCC_MP_NS_APB4ENSETR_LTDCEN BIT(0) ++ ++/* RCC_MP_NS_APB4ENCLRR register fields */ ++#define RCC_MP_NS_APB4ENCLRR_LTDCEN BIT(0) ++ ++/* RCC_MP_APB5ENSETR register fields */ ++#define RCC_MP_APB5ENSETR_RTCAPBEN BIT(8) ++#define RCC_MP_APB5ENSETR_TZCEN BIT(11) ++#define RCC_MP_APB5ENSETR_ETZPCEN BIT(13) ++#define RCC_MP_APB5ENSETR_IWDG1APBEN BIT(15) ++#define RCC_MP_APB5ENSETR_BSECEN BIT(16) ++#define RCC_MP_APB5ENSETR_STGENCEN BIT(20) ++ ++/* RCC_MP_APB5ENCLRR register fields */ ++#define RCC_MP_APB5ENCLRR_RTCAPBEN BIT(8) ++#define RCC_MP_APB5ENCLRR_TZCEN BIT(11) ++#define RCC_MP_APB5ENCLRR_ETZPCEN BIT(13) ++#define RCC_MP_APB5ENCLRR_IWDG1APBEN BIT(15) ++#define RCC_MP_APB5ENCLRR_BSECEN BIT(16) ++#define RCC_MP_APB5ENCLRR_STGENCEN BIT(20) ++ ++/* RCC_MP_APB6ENSETR register fields */ ++#define RCC_MP_APB6ENSETR_USART1EN BIT(0) ++#define RCC_MP_APB6ENSETR_USART2EN BIT(1) ++#define RCC_MP_APB6ENSETR_SPI4EN BIT(2) ++#define RCC_MP_APB6ENSETR_SPI5EN BIT(3) ++#define RCC_MP_APB6ENSETR_I2C3EN BIT(4) ++#define RCC_MP_APB6ENSETR_I2C4EN BIT(5) ++#define RCC_MP_APB6ENSETR_I2C5EN BIT(6) ++#define RCC_MP_APB6ENSETR_TIM12EN BIT(7) ++#define RCC_MP_APB6ENSETR_TIM13EN BIT(8) ++#define RCC_MP_APB6ENSETR_TIM14EN BIT(9) ++#define RCC_MP_APB6ENSETR_TIM15EN BIT(10) ++#define RCC_MP_APB6ENSETR_TIM16EN BIT(11) ++#define RCC_MP_APB6ENSETR_TIM17EN BIT(12) ++ ++/* RCC_MP_APB6ENCLRR register fields */ ++#define RCC_MP_APB6ENCLRR_USART1EN BIT(0) ++#define RCC_MP_APB6ENCLRR_USART2EN BIT(1) ++#define RCC_MP_APB6ENCLRR_SPI4EN BIT(2) ++#define RCC_MP_APB6ENCLRR_SPI5EN BIT(3) ++#define RCC_MP_APB6ENCLRR_I2C3EN BIT(4) ++#define RCC_MP_APB6ENCLRR_I2C4EN BIT(5) ++#define RCC_MP_APB6ENCLRR_I2C5EN BIT(6) ++#define RCC_MP_APB6ENCLRR_TIM12EN BIT(7) ++#define RCC_MP_APB6ENCLRR_TIM13EN BIT(8) ++#define RCC_MP_APB6ENCLRR_TIM14EN BIT(9) ++#define RCC_MP_APB6ENCLRR_TIM15EN BIT(10) ++#define RCC_MP_APB6ENCLRR_TIM16EN BIT(11) ++#define RCC_MP_APB6ENCLRR_TIM17EN BIT(12) ++ ++/* RCC_MP_AHB2ENSETR register fields */ ++#define RCC_MP_AHB2ENSETR_DMA1EN BIT(0) ++#define RCC_MP_AHB2ENSETR_DMA2EN BIT(1) ++#define RCC_MP_AHB2ENSETR_DMAMUX1EN BIT(2) ++#define RCC_MP_AHB2ENSETR_DMA3EN BIT(3) ++#define RCC_MP_AHB2ENSETR_DMAMUX2EN BIT(4) ++#define RCC_MP_AHB2ENSETR_ADC1EN BIT(5) ++#define RCC_MP_AHB2ENSETR_ADC2EN BIT(6) ++#define RCC_MP_AHB2ENSETR_USBOEN BIT(8) ++ ++/* RCC_MP_AHB2ENCLRR register fields */ ++#define RCC_MP_AHB2ENCLRR_DMA1EN BIT(0) ++#define RCC_MP_AHB2ENCLRR_DMA2EN BIT(1) ++#define RCC_MP_AHB2ENCLRR_DMAMUX1EN BIT(2) ++#define RCC_MP_AHB2ENCLRR_DMA3EN BIT(3) ++#define RCC_MP_AHB2ENCLRR_DMAMUX2EN BIT(4) ++#define RCC_MP_AHB2ENCLRR_ADC1EN BIT(5) ++#define RCC_MP_AHB2ENCLRR_ADC2EN BIT(6) ++#define RCC_MP_AHB2ENCLRR_USBOEN BIT(8) ++ ++/* RCC_MP_AHB4ENSETR register fields */ ++#define RCC_MP_AHB4ENSETR_TSCEN BIT(15) ++ ++/* RCC_MP_AHB4ENCLRR register fields */ ++#define RCC_MP_AHB4ENCLRR_TSCEN BIT(15) ++ ++/* RCC_MP_S_AHB4ENSETR register fields */ ++#define RCC_MP_S_AHB4ENSETR_GPIOAEN BIT(0) ++#define RCC_MP_S_AHB4ENSETR_GPIOBEN BIT(1) ++#define RCC_MP_S_AHB4ENSETR_GPIOCEN BIT(2) ++#define RCC_MP_S_AHB4ENSETR_GPIODEN BIT(3) ++#define RCC_MP_S_AHB4ENSETR_GPIOEEN BIT(4) ++#define RCC_MP_S_AHB4ENSETR_GPIOFEN BIT(5) ++#define RCC_MP_S_AHB4ENSETR_GPIOGEN BIT(6) ++#define RCC_MP_S_AHB4ENSETR_GPIOHEN BIT(7) ++#define RCC_MP_S_AHB4ENSETR_GPIOIEN BIT(8) ++ ++/* RCC_MP_S_AHB4ENCLRR register fields */ ++#define RCC_MP_S_AHB4ENCLRR_GPIOAEN BIT(0) ++#define RCC_MP_S_AHB4ENCLRR_GPIOBEN BIT(1) ++#define RCC_MP_S_AHB4ENCLRR_GPIOCEN BIT(2) ++#define RCC_MP_S_AHB4ENCLRR_GPIODEN BIT(3) ++#define RCC_MP_S_AHB4ENCLRR_GPIOEEN BIT(4) ++#define RCC_MP_S_AHB4ENCLRR_GPIOFEN BIT(5) ++#define RCC_MP_S_AHB4ENCLRR_GPIOGEN BIT(6) ++#define RCC_MP_S_AHB4ENCLRR_GPIOHEN BIT(7) ++#define RCC_MP_S_AHB4ENCLRR_GPIOIEN BIT(8) ++ ++/* RCC_MP_NS_AHB4ENSETR register fields */ ++#define RCC_MP_NS_AHB4ENSETR_GPIOAEN BIT(0) ++#define RCC_MP_NS_AHB4ENSETR_GPIOBEN BIT(1) ++#define RCC_MP_NS_AHB4ENSETR_GPIOCEN BIT(2) ++#define RCC_MP_NS_AHB4ENSETR_GPIODEN BIT(3) ++#define RCC_MP_NS_AHB4ENSETR_GPIOEEN BIT(4) ++#define RCC_MP_NS_AHB4ENSETR_GPIOFEN BIT(5) ++#define RCC_MP_NS_AHB4ENSETR_GPIOGEN BIT(6) ++#define RCC_MP_NS_AHB4ENSETR_GPIOHEN BIT(7) ++#define RCC_MP_NS_AHB4ENSETR_GPIOIEN BIT(8) ++ ++/* RCC_MP_NS_AHB4ENCLRR register fields */ ++#define RCC_MP_NS_AHB4ENCLRR_GPIOAEN BIT(0) ++#define RCC_MP_NS_AHB4ENCLRR_GPIOBEN BIT(1) ++#define RCC_MP_NS_AHB4ENCLRR_GPIOCEN BIT(2) ++#define RCC_MP_NS_AHB4ENCLRR_GPIODEN BIT(3) ++#define RCC_MP_NS_AHB4ENCLRR_GPIOEEN BIT(4) ++#define RCC_MP_NS_AHB4ENCLRR_GPIOFEN BIT(5) ++#define RCC_MP_NS_AHB4ENCLRR_GPIOGEN BIT(6) ++#define RCC_MP_NS_AHB4ENCLRR_GPIOHEN BIT(7) ++#define RCC_MP_NS_AHB4ENCLRR_GPIOIEN BIT(8) ++ ++/* RCC_MP_AHB5ENSETR register fields */ ++#define RCC_MP_AHB5ENSETR_PKAEN BIT(2) ++#define RCC_MP_AHB5ENSETR_SAESEN BIT(3) ++#define RCC_MP_AHB5ENSETR_CRYP1EN BIT(4) ++#define RCC_MP_AHB5ENSETR_HASH1EN BIT(5) ++#define RCC_MP_AHB5ENSETR_RNG1EN BIT(6) ++#define RCC_MP_AHB5ENSETR_BKPSRAMEN BIT(8) ++#define RCC_MP_AHB5ENSETR_AXIMCEN BIT(16) ++ ++/* RCC_MP_AHB5ENCLRR register fields */ ++#define RCC_MP_AHB5ENCLRR_PKAEN BIT(2) ++#define RCC_MP_AHB5ENCLRR_SAESEN BIT(3) ++#define RCC_MP_AHB5ENCLRR_CRYP1EN BIT(4) ++#define RCC_MP_AHB5ENCLRR_HASH1EN BIT(5) ++#define RCC_MP_AHB5ENCLRR_RNG1EN BIT(6) ++#define RCC_MP_AHB5ENCLRR_BKPSRAMEN BIT(8) ++#define RCC_MP_AHB5ENCLRR_AXIMCEN BIT(16) ++ ++/* RCC_MP_AHB6ENSETR register fields */ ++#define RCC_MP_AHB6ENSETR_MCEEN BIT(1) ++#define RCC_MP_AHB6ENSETR_ETH1CKEN BIT(7) ++#define RCC_MP_AHB6ENSETR_ETH1TXEN BIT(8) ++#define RCC_MP_AHB6ENSETR_ETH1RXEN BIT(9) ++#define RCC_MP_AHB6ENSETR_ETH1MACEN BIT(10) ++#define RCC_MP_AHB6ENSETR_FMCEN BIT(12) ++#define RCC_MP_AHB6ENSETR_QSPIEN BIT(14) ++#define RCC_MP_AHB6ENSETR_SDMMC1EN BIT(16) ++#define RCC_MP_AHB6ENSETR_SDMMC2EN BIT(17) ++#define RCC_MP_AHB6ENSETR_CRC1EN BIT(20) ++#define RCC_MP_AHB6ENSETR_USBHEN BIT(24) ++#define RCC_MP_AHB6ENSETR_ETH2CKEN BIT(27) ++#define RCC_MP_AHB6ENSETR_ETH2TXEN BIT(28) ++#define RCC_MP_AHB6ENSETR_ETH2RXEN BIT(29) ++#define RCC_MP_AHB6ENSETR_ETH2MACEN BIT(30) ++ ++/* RCC_MP_AHB6ENCLRR register fields */ ++#define RCC_MP_AHB6ENCLRR_MCEEN BIT(1) ++#define RCC_MP_AHB6ENCLRR_ETH1CKEN BIT(7) ++#define RCC_MP_AHB6ENCLRR_ETH1TXEN BIT(8) ++#define RCC_MP_AHB6ENCLRR_ETH1RXEN BIT(9) ++#define RCC_MP_AHB6ENCLRR_ETH1MACEN BIT(10) ++#define RCC_MP_AHB6ENCLRR_FMCEN BIT(12) ++#define RCC_MP_AHB6ENCLRR_QSPIEN BIT(14) ++#define RCC_MP_AHB6ENCLRR_SDMMC1EN BIT(16) ++#define RCC_MP_AHB6ENCLRR_SDMMC2EN BIT(17) ++#define RCC_MP_AHB6ENCLRR_CRC1EN BIT(20) ++#define RCC_MP_AHB6ENCLRR_USBHEN BIT(24) ++#define RCC_MP_AHB6ENCLRR_ETH2CKEN BIT(27) ++#define RCC_MP_AHB6ENCLRR_ETH2TXEN BIT(28) ++#define RCC_MP_AHB6ENCLRR_ETH2RXEN BIT(29) ++#define RCC_MP_AHB6ENCLRR_ETH2MACEN BIT(30) ++ ++/* RCC_MP_S_AHB6ENSETR register fields */ ++#define RCC_MP_S_AHB6ENSETR_MDMAEN BIT(0) ++ ++/* RCC_MP_S_AHB6ENCLRR register fields */ ++#define RCC_MP_S_AHB6ENCLRR_MDMAEN BIT(0) ++ ++/* RCC_MP_NS_AHB6ENSETR register fields */ ++#define RCC_MP_NS_AHB6ENSETR_MDMAEN BIT(0) ++ ++/* RCC_MP_NS_AHB6ENCLRR register fields */ ++#define RCC_MP_NS_AHB6ENCLRR_MDMAEN BIT(0) ++ ++/* RCC_MP_APB1LPENSETR register fields */ ++#define RCC_MP_APB1LPENSETR_TIM2LPEN BIT(0) ++#define RCC_MP_APB1LPENSETR_TIM3LPEN BIT(1) ++#define RCC_MP_APB1LPENSETR_TIM4LPEN BIT(2) ++#define RCC_MP_APB1LPENSETR_TIM5LPEN BIT(3) ++#define RCC_MP_APB1LPENSETR_TIM6LPEN BIT(4) ++#define RCC_MP_APB1LPENSETR_TIM7LPEN BIT(5) ++#define RCC_MP_APB1LPENSETR_LPTIM1LPEN BIT(9) ++#define RCC_MP_APB1LPENSETR_SPI2LPEN BIT(11) ++#define RCC_MP_APB1LPENSETR_SPI3LPEN BIT(12) ++#define RCC_MP_APB1LPENSETR_USART3LPEN BIT(15) ++#define RCC_MP_APB1LPENSETR_UART4LPEN BIT(16) ++#define RCC_MP_APB1LPENSETR_UART5LPEN BIT(17) ++#define RCC_MP_APB1LPENSETR_UART7LPEN BIT(18) ++#define RCC_MP_APB1LPENSETR_UART8LPEN BIT(19) ++#define RCC_MP_APB1LPENSETR_I2C1LPEN BIT(21) ++#define RCC_MP_APB1LPENSETR_I2C2LPEN BIT(22) ++#define RCC_MP_APB1LPENSETR_SPDIFLPEN BIT(26) ++ ++/* RCC_MP_APB1LPENCLRR register fields */ ++#define RCC_MP_APB1LPENCLRR_TIM2LPEN BIT(0) ++#define RCC_MP_APB1LPENCLRR_TIM3LPEN BIT(1) ++#define RCC_MP_APB1LPENCLRR_TIM4LPEN BIT(2) ++#define RCC_MP_APB1LPENCLRR_TIM5LPEN BIT(3) ++#define RCC_MP_APB1LPENCLRR_TIM6LPEN BIT(4) ++#define RCC_MP_APB1LPENCLRR_TIM7LPEN BIT(5) ++#define RCC_MP_APB1LPENCLRR_LPTIM1LPEN BIT(9) ++#define RCC_MP_APB1LPENCLRR_SPI2LPEN BIT(11) ++#define RCC_MP_APB1LPENCLRR_SPI3LPEN BIT(12) ++#define RCC_MP_APB1LPENCLRR_USART3LPEN BIT(15) ++#define RCC_MP_APB1LPENCLRR_UART4LPEN BIT(16) ++#define RCC_MP_APB1LPENCLRR_UART5LPEN BIT(17) ++#define RCC_MP_APB1LPENCLRR_UART7LPEN BIT(18) ++#define RCC_MP_APB1LPENCLRR_UART8LPEN BIT(19) ++#define RCC_MP_APB1LPENCLRR_I2C1LPEN BIT(21) ++#define RCC_MP_APB1LPENCLRR_I2C2LPEN BIT(22) ++#define RCC_MP_APB1LPENCLRR_SPDIFLPEN BIT(26) ++ ++/* RCC_MP_APB2LPENSETR register fields */ ++#define RCC_MP_APB2LPENSETR_TIM1LPEN BIT(0) ++#define RCC_MP_APB2LPENSETR_TIM8LPEN BIT(1) ++#define RCC_MP_APB2LPENSETR_SPI1LPEN BIT(8) ++#define RCC_MP_APB2LPENSETR_USART6LPEN BIT(13) ++#define RCC_MP_APB2LPENSETR_SAI1LPEN BIT(16) ++#define RCC_MP_APB2LPENSETR_SAI2LPEN BIT(17) ++#define RCC_MP_APB2LPENSETR_DFSDMLPEN BIT(20) ++#define RCC_MP_APB2LPENSETR_ADFSDMLPEN BIT(21) ++#define RCC_MP_APB2LPENSETR_FDCANLPEN BIT(24) ++ ++/* RCC_MP_APB2LPENCLRR register fields */ ++#define RCC_MP_APB2LPENCLRR_TIM1LPEN BIT(0) ++#define RCC_MP_APB2LPENCLRR_TIM8LPEN BIT(1) ++#define RCC_MP_APB2LPENCLRR_SPI1LPEN BIT(8) ++#define RCC_MP_APB2LPENCLRR_USART6LPEN BIT(13) ++#define RCC_MP_APB2LPENCLRR_SAI1LPEN BIT(16) ++#define RCC_MP_APB2LPENCLRR_SAI2LPEN BIT(17) ++#define RCC_MP_APB2LPENCLRR_DFSDMLPEN BIT(20) ++#define RCC_MP_APB2LPENCLRR_ADFSDMLPEN BIT(21) ++#define RCC_MP_APB2LPENCLRR_FDCANLPEN BIT(24) ++ ++/* RCC_MP_APB3LPENSETR register fields */ ++#define RCC_MP_APB3LPENSETR_LPTIM2LPEN BIT(0) ++#define RCC_MP_APB3LPENSETR_LPTIM3LPEN BIT(1) ++#define RCC_MP_APB3LPENSETR_LPTIM4LPEN BIT(2) ++#define RCC_MP_APB3LPENSETR_LPTIM5LPEN BIT(3) ++#define RCC_MP_APB3LPENSETR_VREFLPEN BIT(13) ++#define RCC_MP_APB3LPENSETR_DTSLPEN BIT(16) ++#define RCC_MP_APB3LPENSETR_PMBCTRLLPEN BIT(17) ++ ++/* RCC_MP_APB3LPENCLRR register fields */ ++#define RCC_MP_APB3LPENCLRR_LPTIM2LPEN BIT(0) ++#define RCC_MP_APB3LPENCLRR_LPTIM3LPEN BIT(1) ++#define RCC_MP_APB3LPENCLRR_LPTIM4LPEN BIT(2) ++#define RCC_MP_APB3LPENCLRR_LPTIM5LPEN BIT(3) ++#define RCC_MP_APB3LPENCLRR_VREFLPEN BIT(13) ++#define RCC_MP_APB3LPENCLRR_DTSLPEN BIT(16) ++#define RCC_MP_APB3LPENCLRR_PMBCTRLLPEN BIT(17) ++ ++/* RCC_MP_S_APB3LPENSETR register fields */ ++#define RCC_MP_S_APB3LPENSETR_SYSCFGLPEN BIT(0) ++ ++/* RCC_MP_S_APB3LPENCLRR register fields */ ++#define RCC_MP_S_APB3LPENCLRR_SYSCFGLPEN BIT(0) ++ ++/* RCC_MP_NS_APB3LPENSETR register fields */ ++#define RCC_MP_NS_APB3LPENSETR_SYSCFGLPEN BIT(0) ++ ++/* RCC_MP_NS_APB3LPENCLRR register fields */ ++#define RCC_MP_NS_APB3LPENCLRR_SYSCFGLPEN BIT(0) ++ ++/* RCC_MP_APB4LPENSETR register fields */ ++#define RCC_MP_APB4LPENSETR_DCMIPPLPEN BIT(1) ++#define RCC_MP_APB4LPENSETR_DDRPERFMLPEN BIT(8) ++#define RCC_MP_APB4LPENSETR_IWDG2APBLPEN BIT(15) ++#define RCC_MP_APB4LPENSETR_USBPHYLPEN BIT(16) ++#define RCC_MP_APB4LPENSETR_STGENROLPEN BIT(20) ++#define RCC_MP_APB4LPENSETR_STGENROSTPEN BIT(21) ++ ++/* RCC_MP_APB4LPENCLRR register fields */ ++#define RCC_MP_APB4LPENCLRR_DCMIPPLPEN BIT(1) ++#define RCC_MP_APB4LPENCLRR_DDRPERFMLPEN BIT(8) ++#define RCC_MP_APB4LPENCLRR_IWDG2APBLPEN BIT(15) ++#define RCC_MP_APB4LPENCLRR_USBPHYLPEN BIT(16) ++#define RCC_MP_APB4LPENCLRR_STGENROLPEN BIT(20) ++#define RCC_MP_APB4LPENCLRR_STGENROSTPEN BIT(21) ++ ++/* RCC_MP_S_APB4LPENSETR register fields */ ++#define RCC_MP_S_APB4LPENSETR_LTDCLPEN BIT(0) ++ ++/* RCC_MP_S_APB4LPENCLRR register fields */ ++#define RCC_MP_S_APB4LPENCLRR_LTDCLPEN BIT(0) ++ ++/* RCC_MP_NS_APB4LPENSETR register fields */ ++#define RCC_MP_NS_APB4LPENSETR_LTDCLPEN BIT(0) ++ ++/* RCC_MP_NS_APB4LPENCLRR register fields */ ++#define RCC_MP_NS_APB4LPENCLRR_LTDCLPEN BIT(0) ++ ++/* RCC_MP_APB5LPENSETR register fields */ ++#define RCC_MP_APB5LPENSETR_RTCAPBLPEN BIT(8) ++#define RCC_MP_APB5LPENSETR_TZCLPEN BIT(11) ++#define RCC_MP_APB5LPENSETR_ETZPCLPEN BIT(13) ++#define RCC_MP_APB5LPENSETR_IWDG1APBLPEN BIT(15) ++#define RCC_MP_APB5LPENSETR_BSECLPEN BIT(16) ++#define RCC_MP_APB5LPENSETR_STGENCLPEN BIT(20) ++#define RCC_MP_APB5LPENSETR_STGENCSTPEN BIT(21) ++ ++/* RCC_MP_APB5LPENCLRR register fields */ ++#define RCC_MP_APB5LPENCLRR_RTCAPBLPEN BIT(8) ++#define RCC_MP_APB5LPENCLRR_TZCLPEN BIT(11) ++#define RCC_MP_APB5LPENCLRR_ETZPCLPEN BIT(13) ++#define RCC_MP_APB5LPENCLRR_IWDG1APBLPEN BIT(15) ++#define RCC_MP_APB5LPENCLRR_BSECLPEN BIT(16) ++#define RCC_MP_APB5LPENCLRR_STGENCLPEN BIT(20) ++#define RCC_MP_APB5LPENCLRR_STGENCSTPEN BIT(21) ++ ++/* RCC_MP_APB6LPENSETR register fields */ ++#define RCC_MP_APB6LPENSETR_USART1LPEN BIT(0) ++#define RCC_MP_APB6LPENSETR_USART2LPEN BIT(1) ++#define RCC_MP_APB6LPENSETR_SPI4LPEN BIT(2) ++#define RCC_MP_APB6LPENSETR_SPI5LPEN BIT(3) ++#define RCC_MP_APB6LPENSETR_I2C3LPEN BIT(4) ++#define RCC_MP_APB6LPENSETR_I2C4LPEN BIT(5) ++#define RCC_MP_APB6LPENSETR_I2C5LPEN BIT(6) ++#define RCC_MP_APB6LPENSETR_TIM12LPEN BIT(7) ++#define RCC_MP_APB6LPENSETR_TIM13LPEN BIT(8) ++#define RCC_MP_APB6LPENSETR_TIM14LPEN BIT(9) ++#define RCC_MP_APB6LPENSETR_TIM15LPEN BIT(10) ++#define RCC_MP_APB6LPENSETR_TIM16LPEN BIT(11) ++#define RCC_MP_APB6LPENSETR_TIM17LPEN BIT(12) ++ ++/* RCC_MP_APB6LPENCLRR register fields */ ++#define RCC_MP_APB6LPENCLRR_USART1LPEN BIT(0) ++#define RCC_MP_APB6LPENCLRR_USART2LPEN BIT(1) ++#define RCC_MP_APB6LPENCLRR_SPI4LPEN BIT(2) ++#define RCC_MP_APB6LPENCLRR_SPI5LPEN BIT(3) ++#define RCC_MP_APB6LPENCLRR_I2C3LPEN BIT(4) ++#define RCC_MP_APB6LPENCLRR_I2C4LPEN BIT(5) ++#define RCC_MP_APB6LPENCLRR_I2C5LPEN BIT(6) ++#define RCC_MP_APB6LPENCLRR_TIM12LPEN BIT(7) ++#define RCC_MP_APB6LPENCLRR_TIM13LPEN BIT(8) ++#define RCC_MP_APB6LPENCLRR_TIM14LPEN BIT(9) ++#define RCC_MP_APB6LPENCLRR_TIM15LPEN BIT(10) ++#define RCC_MP_APB6LPENCLRR_TIM16LPEN BIT(11) ++#define RCC_MP_APB6LPENCLRR_TIM17LPEN BIT(12) ++ ++/* RCC_MP_AHB2LPENSETR register fields */ ++#define RCC_MP_AHB2LPENSETR_DMA1LPEN BIT(0) ++#define RCC_MP_AHB2LPENSETR_DMA2LPEN BIT(1) ++#define RCC_MP_AHB2LPENSETR_DMAMUX1LPEN BIT(2) ++#define RCC_MP_AHB2LPENSETR_DMA3LPEN BIT(3) ++#define RCC_MP_AHB2LPENSETR_DMAMUX2LPEN BIT(4) ++#define RCC_MP_AHB2LPENSETR_ADC1LPEN BIT(5) ++#define RCC_MP_AHB2LPENSETR_ADC2LPEN BIT(6) ++#define RCC_MP_AHB2LPENSETR_USBOLPEN BIT(8) ++ ++/* RCC_MP_AHB2LPENCLRR register fields */ ++#define RCC_MP_AHB2LPENCLRR_DMA1LPEN BIT(0) ++#define RCC_MP_AHB2LPENCLRR_DMA2LPEN BIT(1) ++#define RCC_MP_AHB2LPENCLRR_DMAMUX1LPEN BIT(2) ++#define RCC_MP_AHB2LPENCLRR_DMA3LPEN BIT(3) ++#define RCC_MP_AHB2LPENCLRR_DMAMUX2LPEN BIT(4) ++#define RCC_MP_AHB2LPENCLRR_ADC1LPEN BIT(5) ++#define RCC_MP_AHB2LPENCLRR_ADC2LPEN BIT(6) ++#define RCC_MP_AHB2LPENCLRR_USBOLPEN BIT(8) ++ ++/* RCC_MP_AHB4LPENSETR register fields */ ++#define RCC_MP_AHB4LPENSETR_TSCLPEN BIT(15) ++ ++/* RCC_MP_AHB4LPENCLRR register fields */ ++#define RCC_MP_AHB4LPENCLRR_TSCLPEN BIT(15) ++ ++/* RCC_MP_S_AHB4LPENSETR register fields */ ++#define RCC_MP_S_AHB4LPENSETR_GPIOALPEN BIT(0) ++#define RCC_MP_S_AHB4LPENSETR_GPIOBLPEN BIT(1) ++#define RCC_MP_S_AHB4LPENSETR_GPIOCLPEN BIT(2) ++#define RCC_MP_S_AHB4LPENSETR_GPIODLPEN BIT(3) ++#define RCC_MP_S_AHB4LPENSETR_GPIOELPEN BIT(4) ++#define RCC_MP_S_AHB4LPENSETR_GPIOFLPEN BIT(5) ++#define RCC_MP_S_AHB4LPENSETR_GPIOGLPEN BIT(6) ++#define RCC_MP_S_AHB4LPENSETR_GPIOHLPEN BIT(7) ++#define RCC_MP_S_AHB4LPENSETR_GPIOILPEN BIT(8) ++ ++/* RCC_MP_S_AHB4LPENCLRR register fields */ ++#define RCC_MP_S_AHB4LPENCLRR_GPIOALPEN BIT(0) ++#define RCC_MP_S_AHB4LPENCLRR_GPIOBLPEN BIT(1) ++#define RCC_MP_S_AHB4LPENCLRR_GPIOCLPEN BIT(2) ++#define RCC_MP_S_AHB4LPENCLRR_GPIODLPEN BIT(3) ++#define RCC_MP_S_AHB4LPENCLRR_GPIOELPEN BIT(4) ++#define RCC_MP_S_AHB4LPENCLRR_GPIOFLPEN BIT(5) ++#define RCC_MP_S_AHB4LPENCLRR_GPIOGLPEN BIT(6) ++#define RCC_MP_S_AHB4LPENCLRR_GPIOHLPEN BIT(7) ++#define RCC_MP_S_AHB4LPENCLRR_GPIOILPEN BIT(8) ++ ++/* RCC_MP_NS_AHB4LPENSETR register fields */ ++#define RCC_MP_NS_AHB4LPENSETR_GPIOALPEN BIT(0) ++#define RCC_MP_NS_AHB4LPENSETR_GPIOBLPEN BIT(1) ++#define RCC_MP_NS_AHB4LPENSETR_GPIOCLPEN BIT(2) ++#define RCC_MP_NS_AHB4LPENSETR_GPIODLPEN BIT(3) ++#define RCC_MP_NS_AHB4LPENSETR_GPIOELPEN BIT(4) ++#define RCC_MP_NS_AHB4LPENSETR_GPIOFLPEN BIT(5) ++#define RCC_MP_NS_AHB4LPENSETR_GPIOGLPEN BIT(6) ++#define RCC_MP_NS_AHB4LPENSETR_GPIOHLPEN BIT(7) ++#define RCC_MP_NS_AHB4LPENSETR_GPIOILPEN BIT(8) ++ ++/* RCC_MP_NS_AHB4LPENCLRR register fields */ ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOALPEN BIT(0) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOBLPEN BIT(1) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOCLPEN BIT(2) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIODLPEN BIT(3) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOELPEN BIT(4) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOFLPEN BIT(5) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOGLPEN BIT(6) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOHLPEN BIT(7) ++#define RCC_MP_NS_AHB4LPENCLRR_GPIOILPEN BIT(8) ++ ++/* RCC_MP_AHB5LPENSETR register fields */ ++#define RCC_MP_AHB5LPENSETR_PKALPEN BIT(2) ++#define RCC_MP_AHB5LPENSETR_SAESLPEN BIT(3) ++#define RCC_MP_AHB5LPENSETR_CRYP1LPEN BIT(4) ++#define RCC_MP_AHB5LPENSETR_HASH1LPEN BIT(5) ++#define RCC_MP_AHB5LPENSETR_RNG1LPEN BIT(6) ++#define RCC_MP_AHB5LPENSETR_BKPSRAMLPEN BIT(8) ++ ++/* RCC_MP_AHB5LPENCLRR register fields */ ++#define RCC_MP_AHB5LPENCLRR_PKALPEN BIT(2) ++#define RCC_MP_AHB5LPENCLRR_SAESLPEN BIT(3) ++#define RCC_MP_AHB5LPENCLRR_CRYP1LPEN BIT(4) ++#define RCC_MP_AHB5LPENCLRR_HASH1LPEN BIT(5) ++#define RCC_MP_AHB5LPENCLRR_RNG1LPEN BIT(6) ++#define RCC_MP_AHB5LPENCLRR_BKPSRAMLPEN BIT(8) ++ ++/* RCC_MP_AHB6LPENSETR register fields */ ++#define RCC_MP_AHB6LPENSETR_MCELPEN BIT(1) ++#define RCC_MP_AHB6LPENSETR_ETH1CKLPEN BIT(7) ++#define RCC_MP_AHB6LPENSETR_ETH1TXLPEN BIT(8) ++#define RCC_MP_AHB6LPENSETR_ETH1RXLPEN BIT(9) ++#define RCC_MP_AHB6LPENSETR_ETH1MACLPEN BIT(10) ++#define RCC_MP_AHB6LPENSETR_ETH1STPEN BIT(11) ++#define RCC_MP_AHB6LPENSETR_FMCLPEN BIT(12) ++#define RCC_MP_AHB6LPENSETR_QSPILPEN BIT(14) ++#define RCC_MP_AHB6LPENSETR_SDMMC1LPEN BIT(16) ++#define RCC_MP_AHB6LPENSETR_SDMMC2LPEN BIT(17) ++#define RCC_MP_AHB6LPENSETR_CRC1LPEN BIT(20) ++#define RCC_MP_AHB6LPENSETR_USBHLPEN BIT(24) ++#define RCC_MP_AHB6LPENSETR_ETH2CKLPEN BIT(27) ++#define RCC_MP_AHB6LPENSETR_ETH2TXLPEN BIT(28) ++#define RCC_MP_AHB6LPENSETR_ETH2RXLPEN BIT(29) ++#define RCC_MP_AHB6LPENSETR_ETH2MACLPEN BIT(30) ++#define RCC_MP_AHB6LPENSETR_ETH2STPEN BIT(31) ++ ++/* RCC_MP_AHB6LPENCLRR register fields */ ++#define RCC_MP_AHB6LPENCLRR_MCELPEN BIT(1) ++#define RCC_MP_AHB6LPENCLRR_ETH1CKLPEN BIT(7) ++#define RCC_MP_AHB6LPENCLRR_ETH1TXLPEN BIT(8) ++#define RCC_MP_AHB6LPENCLRR_ETH1RXLPEN BIT(9) ++#define RCC_MP_AHB6LPENCLRR_ETH1MACLPEN BIT(10) ++#define RCC_MP_AHB6LPENCLRR_ETH1STPEN BIT(11) ++#define RCC_MP_AHB6LPENCLRR_FMCLPEN BIT(12) ++#define RCC_MP_AHB6LPENCLRR_QSPILPEN BIT(14) ++#define RCC_MP_AHB6LPENCLRR_SDMMC1LPEN BIT(16) ++#define RCC_MP_AHB6LPENCLRR_SDMMC2LPEN BIT(17) ++#define RCC_MP_AHB6LPENCLRR_CRC1LPEN BIT(20) ++#define RCC_MP_AHB6LPENCLRR_USBHLPEN BIT(24) ++#define RCC_MP_AHB6LPENCLRR_ETH2CKLPEN BIT(27) ++#define RCC_MP_AHB6LPENCLRR_ETH2TXLPEN BIT(28) ++#define RCC_MP_AHB6LPENCLRR_ETH2RXLPEN BIT(29) ++#define RCC_MP_AHB6LPENCLRR_ETH2MACLPEN BIT(30) ++#define RCC_MP_AHB6LPENCLRR_ETH2STPEN BIT(31) ++ ++/* RCC_MP_S_AHB6LPENSETR register fields */ ++#define RCC_MP_S_AHB6LPENSETR_MDMALPEN BIT(0) ++ ++/* RCC_MP_S_AHB6LPENCLRR register fields */ ++#define RCC_MP_S_AHB6LPENCLRR_MDMALPEN BIT(0) ++ ++/* RCC_MP_NS_AHB6LPENSETR register fields */ ++#define RCC_MP_NS_AHB6LPENSETR_MDMALPEN BIT(0) ++ ++/* RCC_MP_NS_AHB6LPENCLRR register fields */ ++#define RCC_MP_NS_AHB6LPENCLRR_MDMALPEN BIT(0) ++ ++/* RCC_MP_S_AXIMLPENSETR register fields */ ++#define RCC_MP_S_AXIMLPENSETR_SYSRAMLPEN BIT(0) ++ ++/* RCC_MP_S_AXIMLPENCLRR register fields */ ++#define RCC_MP_S_AXIMLPENCLRR_SYSRAMLPEN BIT(0) ++ ++/* RCC_MP_NS_AXIMLPENSETR register fields */ ++#define RCC_MP_NS_AXIMLPENSETR_SYSRAMLPEN BIT(0) ++ ++/* RCC_MP_NS_AXIMLPENCLRR register fields */ ++#define RCC_MP_NS_AXIMLPENCLRR_SYSRAMLPEN BIT(0) ++ ++/* RCC_MP_MLAHBLPENSETR register fields */ ++#define RCC_MP_MLAHBLPENSETR_SRAM1LPEN BIT(0) ++#define RCC_MP_MLAHBLPENSETR_SRAM2LPEN BIT(1) ++#define RCC_MP_MLAHBLPENSETR_SRAM3LPEN BIT(2) ++ ++/* RCC_MP_MLAHBLPENCLRR register fields */ ++#define RCC_MP_MLAHBLPENCLRR_SRAM1LPEN BIT(0) ++#define RCC_MP_MLAHBLPENCLRR_SRAM2LPEN BIT(1) ++#define RCC_MP_MLAHBLPENCLRR_SRAM3LPEN BIT(2) ++ ++/* RCC_APB3SECSR register fields */ ++#define RCC_APB3SECSR_LPTIM2SECF 0 ++#define RCC_APB3SECSR_LPTIM3SECF 1 ++#define RCC_APB3SECSR_VREFSECF 13 ++ ++/* RCC_APB4SECSR register fields */ ++#define RCC_APB4SECSR_DCMIPPSECF 1 ++#define RCC_APB4SECSR_USBPHYSECF 16 ++ ++/* RCC_APB5SECSR register fields */ ++#define RCC_APB5SECSR_RTCSECF 8 ++#define RCC_APB5SECSR_TZCSECF 11 ++#define RCC_APB5SECSR_ETZPCSECF 13 ++#define RCC_APB5SECSR_IWDG1SECF 15 ++#define RCC_APB5SECSR_BSECSECF 16 ++#define RCC_APB5SECSR_STGENCSECF_MASK GENMASK(21, 20) ++#define RCC_APB5SECSR_STGENCSECF 20 ++#define RCC_APB5SECSR_STGENROSECF 21 ++ ++/* RCC_APB6SECSR register fields */ ++#define RCC_APB6SECSR_USART1SECF 0 ++#define RCC_APB6SECSR_USART2SECF 1 ++#define RCC_APB6SECSR_SPI4SECF 2 ++#define RCC_APB6SECSR_SPI5SECF 3 ++#define RCC_APB6SECSR_I2C3SECF 4 ++#define RCC_APB6SECSR_I2C4SECF 5 ++#define RCC_APB6SECSR_I2C5SECF 6 ++#define RCC_APB6SECSR_TIM12SECF 7 ++#define RCC_APB6SECSR_TIM13SECF 8 ++#define RCC_APB6SECSR_TIM14SECF 9 ++#define RCC_APB6SECSR_TIM15SECF 10 ++#define RCC_APB6SECSR_TIM16SECF 11 ++#define RCC_APB6SECSR_TIM17SECF 12 ++ ++/* RCC_AHB2SECSR register fields */ ++#define RCC_AHB2SECSR_DMA3SECF 3 ++#define RCC_AHB2SECSR_DMAMUX2SECF 4 ++#define RCC_AHB2SECSR_ADC1SECF 5 ++#define RCC_AHB2SECSR_ADC2SECF 6 ++#define RCC_AHB2SECSR_USBOSECF 8 ++ ++/* RCC_AHB4SECSR register fields */ ++#define RCC_AHB4SECSR_TSCSECF 15 ++ ++/* RCC_AHB5SECSR register fields */ ++#define RCC_AHB5SECSR_PKASECF 2 ++#define RCC_AHB5SECSR_SAESSECF 3 ++#define RCC_AHB5SECSR_CRYP1SECF 4 ++#define RCC_AHB5SECSR_HASH1SECF 5 ++#define RCC_AHB5SECSR_RNG1SECF 6 ++#define RCC_AHB5SECSR_BKPSRAMSECF 8 ++ ++/* RCC_AHB6SECSR register fields */ ++#define RCC_AHB6SECSR_MCESECF 1 ++#define RCC_AHB6SECSR_FMCSECF 12 ++#define RCC_AHB6SECSR_QSPISECF 14 ++#define RCC_AHB6SECSR_SDMMC1SECF 16 ++#define RCC_AHB6SECSR_SDMMC2SECF 17 ++ ++#define RCC_AHB6SECSR_ETH1SECF_MASK GENMASK(11, 7) ++#define RCC_AHB6SECSR_ETH2SECF_MASK GENMASK(31, 27) ++#define RCC_AHB6SECSR_ETH1SECF_SHIFT 7 ++#define RCC_AHB6SECSR_ETH2SECF_SHIFT 27 ++ ++#define RCC_AHB6SECSR_ETH1CKSECF 7 ++#define RCC_AHB6SECSR_ETH1TXSECF 8 ++#define RCC_AHB6SECSR_ETH1RXSECF 9 ++#define RCC_AHB6SECSR_ETH1MACSECF 10 ++#define RCC_AHB6SECSR_ETH1STPSECF 11 ++ ++#define RCC_AHB6SECSR_ETH2CKSECF 27 ++#define RCC_AHB6SECSR_ETH2TXSECF 28 ++#define RCC_AHB6SECSR_ETH2RXSECF 29 ++#define RCC_AHB6SECSR_ETH2MACSECF 30 ++#define RCC_AHB6SECSR_ETH2STPSECF 31 ++ ++/* RCC_VERR register fields */ ++#define RCC_VERR_MINREV_MASK GENMASK(3, 0) ++#define RCC_VERR_MAJREV_MASK GENMASK(7, 4) ++#define RCC_VERR_MINREV_SHIFT 0 ++#define RCC_VERR_MAJREV_SHIFT 4 ++ ++/* RCC_IDR register fields */ ++#define RCC_IDR_ID_MASK GENMASK(31, 0) ++#define RCC_IDR_ID_SHIFT 0 ++ ++/* RCC_SIDR register fields */ ++#define RCC_SIDR_SID_MASK GENMASK(31, 0) ++#define RCC_SIDR_SID_SHIFT 0 ++ ++#endif /* STM32MP13_RCC_H */ ++ +diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c +index db2841d0b..90c10f378 100644 +--- a/drivers/clocksource/timer-stm32-lp.c ++++ b/drivers/clocksource/timer-stm32-lp.c +@@ -168,9 +168,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) + } + + if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { +- ret = device_init_wakeup(&pdev->dev, true); +- if (ret) +- goto out_clk_disable; ++ device_set_wakeup_capable(&pdev->dev, true); + + ret = dev_pm_set_wake_irq(&pdev->dev, irq); + if (ret) +diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h +index e02770b98..2e23e0384 100644 +--- a/include/dt-bindings/clock/stm32mp1-clks.h ++++ b/include/dt-bindings/clock/stm32mp1-clks.h +@@ -179,6 +179,12 @@ + #define DAC12_K 168 + #define ETHPTP_K 169 + ++#define PCLK1 170 ++#define PCLK2 171 ++#define PCLK3 172 ++#define PCLK4 173 ++#define PCLK5 174 ++ + /* PLL */ + #define PLL1 176 + #define PLL2 177 +@@ -249,30 +255,26 @@ + #define STM32MP1_LAST_CLK 232 + + /* SCMI clock identifiers */ +-#define CK_SCMI0_HSE 0 +-#define CK_SCMI0_HSI 1 +-#define CK_SCMI0_CSI 2 +-#define CK_SCMI0_LSE 3 +-#define CK_SCMI0_LSI 4 +-#define CK_SCMI0_PLL2_Q 5 +-#define CK_SCMI0_PLL2_R 6 +-#define CK_SCMI0_MPU 7 +-#define CK_SCMI0_AXI 8 +-#define CK_SCMI0_BSEC 9 +-#define CK_SCMI0_CRYP1 10 +-#define CK_SCMI0_GPIOZ 11 +-#define CK_SCMI0_HASH1 12 +-#define CK_SCMI0_I2C4 13 +-#define CK_SCMI0_I2C6 14 +-#define CK_SCMI0_IWDG1 15 +-#define CK_SCMI0_RNG1 16 +-#define CK_SCMI0_RTC 17 +-#define CK_SCMI0_RTCAPB 18 +-#define CK_SCMI0_SPI6 19 +-#define CK_SCMI0_USART1 20 +- +-#define CK_SCMI1_PLL3_Q 0 +-#define CK_SCMI1_PLL3_R 1 +-#define CK_SCMI1_MCU 2 ++#define CK_SCMI_HSE 0 ++#define CK_SCMI_HSI 1 ++#define CK_SCMI_CSI 2 ++#define CK_SCMI_LSE 3 ++#define CK_SCMI_LSI 4 ++#define CK_SCMI_PLL2_Q 5 ++#define CK_SCMI_PLL2_R 6 ++#define CK_SCMI_MPU 7 ++#define CK_SCMI_AXI 8 ++#define CK_SCMI_BSEC 9 ++#define CK_SCMI_CRYP1 10 ++#define CK_SCMI_GPIOZ 11 ++#define CK_SCMI_HASH1 12 ++#define CK_SCMI_I2C4 13 ++#define CK_SCMI_I2C6 14 ++#define CK_SCMI_IWDG1 15 ++#define CK_SCMI_RNG1 16 ++#define CK_SCMI_RTC 17 ++#define CK_SCMI_RTCAPB 18 ++#define CK_SCMI_SPI6 19 ++#define CK_SCMI_USART1 20 + + #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ +diff --git a/include/dt-bindings/clock/stm32mp13-clks.h b/include/dt-bindings/clock/stm32mp13-clks.h +new file mode 100644 +index 000000000..02befd25e +--- /dev/null ++++ b/include/dt-bindings/clock/stm32mp13-clks.h +@@ -0,0 +1,229 @@ ++/* SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause */ ++/* ++ * Copyright (C) STMicroelectronics 2020 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++#ifndef _DT_BINDINGS_STM32MP13_CLKS_H_ ++#define _DT_BINDINGS_STM32MP13_CLKS_H_ ++ ++/* OSCILLATOR clocks */ ++#define CK_HSE 0 ++#define CK_CSI 1 ++#define CK_LSI 2 ++#define CK_LSE 3 ++#define CK_HSI 4 ++#define CK_HSE_DIV2 5 ++ ++/* PLL */ ++#define PLL1 6 ++#define PLL2 7 ++#define PLL3 8 ++#define PLL4 9 ++ ++/* ODF */ ++#define PLL1_P 10 ++#define PLL1_Q 11 ++#define PLL1_R 12 ++#define PLL2_P 13 ++#define PLL2_Q 14 ++#define PLL2_R 15 ++#define PLL3_P 16 ++#define PLL3_Q 17 ++#define PLL3_R 18 ++#define PLL4_P 19 ++#define PLL4_Q 20 ++#define PLL4_R 21 ++ ++#define PCLK1 22 ++#define PCLK2 23 ++#define PCLK3 24 ++#define PCLK4 25 ++#define PCLK5 26 ++#define PCLK6 27 ++ ++/* SYSTEM CLOCK */ ++#define CK_PER 28 ++#define CK_MPU 29 ++#define CK_AXI 30 ++#define CK_MLAHB 31 ++ ++/* BASE TIMER */ ++#define CK_TIMG1 32 ++#define CK_TIMG2 33 ++#define CK_TIMG3 34 ++ ++/* AUX */ ++#define RTC 35 ++ ++/* TRACE & DEBUG clocks */ ++#define CK_DBG 36 ++#define CK_TRACE 37 ++ ++/* MCO clocks */ ++#define CK_MCO1 38 ++#define CK_MCO2 39 ++ ++/* IP clocks */ ++#define SYSCFG 40 ++#define VREF 41 ++#define DTS 42 ++#define PMBCTRL 43 ++#define HDP 44 ++#define IWDG2 45 ++#define STGENRO 46 ++#define USART1 47 ++#define RTCAPB 48 ++#define TZC 49 ++#define TZPC 50 ++#define IWDG1 51 ++#define BSEC 52 ++#define DMA1 53 ++#define DMA2 54 ++#define DMAMUX1 55 ++#define DMAMUX2 56 ++#define GPIOA 57 ++#define GPIOB 58 ++#define GPIOC 59 ++#define GPIOD 60 ++#define GPIOE 61 ++#define GPIOF 62 ++#define GPIOG 63 ++#define GPIOH 64 ++#define GPIOI 65 ++#define CRYP1 66 ++#define HASH1 67 ++#define BKPSRAM 68 ++#define MDMA 69 ++#define CRC1 70 ++#define USBH 71 ++#define DMA3 72 ++#define TSC 73 ++#define PKA 74 ++#define AXIMC 75 ++#define MCE 76 ++#define ETH1TX 77 ++#define ETH2TX 78 ++#define ETH1RX 79 ++#define ETH2RX 80 ++#define ETH1MAC 81 ++#define ETH2MAC 82 ++#define ETH1STP 83 ++#define ETH2STP 84 ++ ++/* IP clocks with parents */ ++#define SDMMC1_K 85 ++#define SDMMC2_K 86 ++#define ADC1_K 87 ++#define ADC2_K 88 ++#define FMC_K 89 ++#define QSPI_K 90 ++#define RNG1_K 91 ++#define USBPHY_K 92 ++#define STGEN_K 93 ++#define SPDIF_K 94 ++#define SPI1_K 95 ++#define SPI2_K 96 ++#define SPI3_K 97 ++#define SPI4_K 98 ++#define SPI5_K 99 ++#define I2C1_K 100 ++#define I2C2_K 101 ++#define I2C3_K 102 ++#define I2C4_K 103 ++#define I2C5_K 104 ++#define TIM2_K 105 ++#define TIM3_K 106 ++#define TIM4_K 107 ++#define TIM5_K 108 ++#define TIM6_K 109 ++#define TIM7_K 110 ++#define TIM12_K 111 ++#define TIM13_K 112 ++#define TIM14_K 113 ++#define TIM1_K 114 ++#define TIM8_K 115 ++#define TIM15_K 116 ++#define TIM16_K 117 ++#define TIM17_K 118 ++#define LPTIM1_K 119 ++#define LPTIM2_K 120 ++#define LPTIM3_K 121 ++#define LPTIM4_K 122 ++#define LPTIM5_K 123 ++#define USART1_K 124 ++#define USART2_K 125 ++#define USART3_K 126 ++#define UART4_K 127 ++#define UART5_K 128 ++#define USART6_K 129 ++#define UART7_K 130 ++#define UART8_K 131 ++#define DFSDM_K 132 ++#define FDCAN_K 133 ++#define SAI1_K 134 ++#define SAI2_K 135 ++#define ADFSDM_K 136 ++#define USBO_K 137 ++#define LTDC_PX 138 ++#define ETH1CK_K 139 ++#define ETH1PTP_K 140 ++#define ETH2CK_K 141 ++#define ETH2PTP_K 142 ++#define DCMIPP_K 143 ++#define SAES_K 144 ++#define DTS_K 145 ++ ++/* DDR */ ++#define DDRC1 146 ++#define DDRC1LP 147 ++#define DDRC2 148 ++#define DDRC2LP 149 ++#define DDRPHYC 150 ++#define DDRPHYCLP 151 ++#define DDRCAPB 152 ++#define DDRCAPBLP 153 ++#define AXIDCG 154 ++#define DDRPHYCAPB 155 ++#define DDRPHYCAPBLP 156 ++#define DDRPERFM 157 ++ ++#define ADC1 158 ++#define ADC2 159 ++#define SAI1 160 ++#define SAI2 161 ++ ++#define STM32MP1_LAST_CLK 162 ++ ++/* SCMI clock identifiers */ ++#define CK_SCMI_HSE 0 ++#define CK_SCMI_HSI 1 ++#define CK_SCMI_CSI 2 ++#define CK_SCMI_LSE 3 ++#define CK_SCMI_LSI 4 ++#define CK_SCMI_HSE_DIV2 5 ++#define CK_SCMI_PLL2_Q 6 ++#define CK_SCMI_PLL2_R 7 ++#define CK_SCMI_PLL3_P 8 ++#define CK_SCMI_PLL3_Q 9 ++#define CK_SCMI_PLL3_R 10 ++#define CK_SCMI_PLL4_P 11 ++#define CK_SCMI_PLL4_Q 12 ++#define CK_SCMI_PLL4_R 13 ++#define CK_SCMI_MPU 14 ++#define CK_SCMI_AXI 15 ++#define CK_SCMI_MLAHB 16 ++#define CK_SCMI_CKPER 17 ++#define CK_SCMI_PCLK1 18 ++#define CK_SCMI_PCLK2 19 ++#define CK_SCMI_PCLK3 20 ++#define CK_SCMI_PCLK4 21 ++#define CK_SCMI_PCLK5 22 ++#define CK_SCMI_PCLK6 23 ++#define CK_SCMI_CKTIMG1 24 ++#define CK_SCMI_CKTIMG2 25 ++#define CK_SCMI_CKTIMG3 26 ++#define CK_SCMI_RTC 27 ++#define CK_SCMI_RTCAPB 28 ++ ++#endif /* _DT_BINDINGS_STM32MP13_CLKS_H_ */ +-- +2.25.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0003-ARM-5.10.61-stm32mp1-r2-CPUFREQ.patch b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0003-ARM-5.15.24-stm32mp1-r1-CPUFREQ.patch similarity index 80% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0003-ARM-5.10.61-stm32mp1-r2-CPUFREQ.patch rename to recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0003-ARM-5.15.24-stm32mp1-r1-CPUFREQ.patch index ddbe24d..8264d77 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0003-ARM-5.10.61-stm32mp1-r2-CPUFREQ.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0003-ARM-5.15.24-stm32mp1-r1-CPUFREQ.patch @@ -1,21 +1,22 @@ -From f425522a8000b8fe201de2db79367a1a7e7b7fdb Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:41 +0200 -Subject: [PATCH 03/23] ARM 5.10.61-stm32mp1-r2 CPUFREQ +From 1aacc70479e14dd5ca0e60a969478957a390dbda Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 31 May 2022 11:51:10 +0200 +Subject: [PATCH 03/22] ARM-5.15.24-stm32mp1-r1-CPUFREQ +Signed-off-by: Christophe Priouzeau --- drivers/cpufreq/Kconfig.arm | 7 ++ drivers/cpufreq/Makefile | 1 + - drivers/cpufreq/cpufreq-dt-platdev.c | 3 + - drivers/cpufreq/stm32-cpufreq.c | 101 +++++++++++++++++++++++++++ + drivers/cpufreq/cpufreq-dt-platdev.c | 1 + + drivers/cpufreq/stm32-cpufreq.c | 103 +++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 drivers/cpufreq/stm32-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm -index 1f73fa75b..56b210670 100644 +index 954749afb..eac08e907 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm -@@ -289,6 +289,13 @@ config ARM_STI_CPUFREQ +@@ -311,6 +311,13 @@ config ARM_STI_CPUFREQ this config option if you wish to add CPUFreq support for STi based SoCs. @@ -26,11 +27,11 @@ index 1f73fa75b..56b210670 100644 + help + This adds the CPUFreq driver support for STM32 MPU SOCs. + - config ARM_TANGO_CPUFREQ - bool - depends on CPUFREQ_DT && ARCH_TANGO + config ARM_TEGRA20_CPUFREQ + tristate "Tegra20/30 CPUFreq support" + depends on ARCH_TEGRA && CPUFREQ_DT diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index f1b7e3dd6..b373f97f2 100644 +index 48ee58590..d34de1b92 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o @@ -39,28 +40,26 @@ index f1b7e3dd6..b373f97f2 100644 obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o +obj-$(CONFIG_ARM_STM32_CPUFREQ) += stm32-cpufreq.o obj-$(CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM) += sun50i-cpufreq-nvmem.o - obj-$(CONFIG_ARM_TANGO_CPUFREQ) += tango-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o + obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c -index 1c192a42f..4d72dbb3a 100644 +index ca1d103ec..f205e6e97 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c -@@ -140,6 +140,9 @@ static const struct of_device_id blacklist[] __initconst = { +@@ -150,6 +150,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, { .compatible = "st,stih418", }, -+ { .compatible = "st,stm32mp151", }, -+ { .compatible = "st,stm32mp153", }, + { .compatible = "st,stm32mp157", }, - { .compatible = "sigma,tango4", }, - + { .compatible = "ti,am33xx", }, + { .compatible = "ti,am43", }, diff --git a/drivers/cpufreq/stm32-cpufreq.c b/drivers/cpufreq/stm32-cpufreq.c new file mode 100644 -index 000000000..35fb3520d +index 000000000..d7b1b16ea --- /dev/null +++ b/drivers/cpufreq/stm32-cpufreq.c -@@ -0,0 +1,101 @@ +@@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -104,7 +103,9 @@ index 000000000..35fb3520d + /* Get chip info */ + ret = nvmem_cell_read_u8(cpu_dev, "part_number", &part_number); + if (ret) { -+ dev_err(&pdev->dev, "Failed to get chip info: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Failed to get chip info: %d\n", ++ ret); + return ret; + } + @@ -163,5 +164,5 @@ index 000000000..35fb3520d +MODULE_AUTHOR("Alexandre Torgue "); +MODULE_LICENSE("GPL v2"); -- -2.17.1 +2.25.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0004-ARM-5.15.24-stm32mp1-r1-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0004-ARM-5.15.24-stm32mp1-r1-CRYPTO.patch new file mode 100644 index 0000000..257f76e --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0004-ARM-5.15.24-stm32mp1-r1-CRYPTO.patch @@ -0,0 +1,1539 @@ +From a3e88eba0837217682d75a26b81498d6476d0cc2 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 31 May 2022 11:51:37 +0200 +Subject: [PATCH 04/22] ARM-5.15.24-stm32mp1-r1-CRYPTO + +Signed-off-by: Christophe Priouzeau +--- + drivers/crypto/stm32/stm32-cryp.c | 50 +- + drivers/crypto/stm32/stm32-hash.c | 839 ++++++++++++++++++++++-------- + 2 files changed, 662 insertions(+), 227 deletions(-) + +diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c +index 81eb136b6..59ef54112 100644 +--- a/drivers/crypto/stm32/stm32-cryp.c ++++ b/drivers/crypto/stm32/stm32-cryp.c +@@ -232,6 +232,11 @@ static inline int stm32_cryp_wait_busy(struct stm32_cryp *cryp) + !(status & SR_BUSY), 10, 100000); + } + ++static inline void stm32_cryp_enable(struct stm32_cryp *cryp) ++{ ++ writel_relaxed(readl_relaxed(cryp->regs + CRYP_CR) | CR_CRYPEN, cryp->regs + CRYP_CR); ++} ++ + static inline int stm32_cryp_wait_enable(struct stm32_cryp *cryp) + { + u32 status; +@@ -535,9 +540,6 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) + /* Disable interrupt */ + stm32_cryp_write(cryp, CRYP_IMSCR, 0); + +- /* Set key */ +- stm32_cryp_hw_write_key(cryp); +- + /* Set configuration */ + cfg = CR_DATA8 | CR_FFLUSH; + +@@ -563,23 +565,36 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) + /* AES ECB/CBC decrypt: run key preparation first */ + if (is_decrypt(cryp) && + ((hw_mode == CR_AES_ECB) || (hw_mode == CR_AES_CBC))) { +- stm32_cryp_write(cryp, CRYP_CR, cfg | CR_AES_KP | CR_CRYPEN); ++ /* Configure in key preparation mode */ ++ stm32_cryp_write(cryp, CRYP_CR, cfg | CR_AES_KP); ++ ++ /* Set key only after full configuration done */ ++ stm32_cryp_hw_write_key(cryp); + ++ /* Start prepare key */ ++ stm32_cryp_enable(cryp); + /* Wait for end of processing */ + ret = stm32_cryp_wait_busy(cryp); + if (ret) { + dev_err(cryp->dev, "Timeout (key preparation)\n"); + return ret; + } +- } + +- cfg |= hw_mode; ++ cfg |= hw_mode | CR_DEC_NOT_ENC; + +- if (is_decrypt(cryp)) +- cfg |= CR_DEC_NOT_ENC; ++ /* Apply updated config (Decrypt + algo) and flush */ ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ } else { ++ cfg |= hw_mode; ++ if (is_decrypt(cryp)) ++ cfg |= CR_DEC_NOT_ENC; + +- /* Apply config and flush (valid when CRYPEN = 0) */ +- stm32_cryp_write(cryp, CRYP_CR, cfg); ++ /* Apply config and flush */ ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ ++ /* Set key only after configuration done */ ++ stm32_cryp_hw_write_key(cryp); ++ } + + switch (hw_mode) { + case CR_AES_GCM: +@@ -607,9 +622,7 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) + } + + /* Enable now */ +- cfg |= CR_CRYPEN; +- +- stm32_cryp_write(cryp, CRYP_CR, cfg); ++ stm32_cryp_enable(cryp); + + return 0; + } +@@ -1761,7 +1774,8 @@ static int stm32_cryp_probe(struct platform_device *pdev) + + cryp->clk = devm_clk_get(dev, NULL); + if (IS_ERR(cryp->clk)) { +- dev_err(dev, "Could not get clock\n"); ++ dev_err_probe(dev, PTR_ERR(cryp->clk), "Could not get clock\n"); ++ + return PTR_ERR(cryp->clk); + } + +@@ -1779,7 +1793,11 @@ static int stm32_cryp_probe(struct platform_device *pdev) + pm_runtime_enable(dev); + + rst = devm_reset_control_get(dev, NULL); +- if (!IS_ERR(rst)) { ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret == -EPROBE_DEFER) ++ goto err_rst; ++ } else { + reset_control_assert(rst); + udelay(2); + reset_control_deassert(rst); +@@ -1830,7 +1848,7 @@ static int stm32_cryp_probe(struct platform_device *pdev) + spin_lock(&cryp_list.lock); + list_del(&cryp->list); + spin_unlock(&cryp_list.lock); +- ++err_rst: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + +diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c +index d33006d43..383324f5f 100644 +--- a/drivers/crypto/stm32/stm32-hash.c ++++ b/drivers/crypto/stm32/stm32-hash.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + #define HASH_CR 0x00 +@@ -49,11 +50,6 @@ + #define HASH_CR_DMAA BIT(14) + #define HASH_CR_LKEY BIT(16) + +-#define HASH_CR_ALGO_SHA1 0x0 +-#define HASH_CR_ALGO_MD5 0x80 +-#define HASH_CR_ALGO_SHA224 0x40000 +-#define HASH_CR_ALGO_SHA256 0x40080 +- + /* Interrupt */ + #define HASH_DINIE BIT(0) + #define HASH_DCIE BIT(1) +@@ -62,9 +58,6 @@ + #define HASH_MASK_CALC_COMPLETION BIT(0) + #define HASH_MASK_DATA_INPUT BIT(1) + +-/* Context swap register */ +-#define HASH_CSR_REGISTER_NUMBER 53 +- + /* Status Flags */ + #define HASH_SR_DATA_INPUT_READY BIT(0) + #define HASH_SR_OUTPUT_READY BIT(1) +@@ -75,6 +68,17 @@ + #define HASH_STR_NBLW_MASK GENMASK(4, 0) + #define HASH_STR_DCAL BIT(8) + ++/* HWCFGR Register */ ++#define HASH_HWCFG_DMA_MASK GENMASK(3, 0) ++ ++/* CSR register */ ++#define HASH_CSR_NB_SHA256_HMAC 54 ++#define HASH_CSR_NB_SHA256 22 ++#define HASH_CSR_NB_SHA512_HMAC 103 ++#define HASH_CSR_NB_SHA512 91 ++#define HASH_CSR_NB_SHA3_HMAC 88 ++#define HASH_CSR_NB_SHA3 72 ++ + #define HASH_FLAGS_INIT BIT(0) + #define HASH_FLAGS_OUTPUT_READY BIT(1) + #define HASH_FLAGS_CPU BIT(2) +@@ -83,20 +87,19 @@ + #define HASH_FLAGS_HMAC_INIT BIT(5) + #define HASH_FLAGS_HMAC_FINAL BIT(6) + #define HASH_FLAGS_HMAC_KEY BIT(7) +- ++#define HASH_FLAGS_SHA3_MODE BIT(8) + #define HASH_FLAGS_FINAL BIT(15) + #define HASH_FLAGS_FINUP BIT(16) +-#define HASH_FLAGS_ALGO_MASK GENMASK(21, 18) +-#define HASH_FLAGS_MD5 BIT(18) +-#define HASH_FLAGS_SHA1 BIT(19) +-#define HASH_FLAGS_SHA224 BIT(20) +-#define HASH_FLAGS_SHA256 BIT(21) +-#define HASH_FLAGS_ERRORS BIT(22) +-#define HASH_FLAGS_HMAC BIT(23) ++#define HASH_FLAGS_ALGO_MASK GENMASK(20, 17) ++#define HASH_FLAGS_ALGO_SHIFT 17 ++#define HASH_FLAGS_ERRORS BIT(21) ++#define HASH_FLAGS_HMAC BIT(22) + + #define HASH_OP_UPDATE 1 + #define HASH_OP_FINAL 2 + ++#define HASH_BURST_LEVEL 4 ++ + enum stm32_hash_data_format { + HASH_DATA_32_BITS = 0x0, + HASH_DATA_16_BITS = 0x1, +@@ -104,17 +107,26 @@ enum stm32_hash_data_format { + HASH_DATA_1_BIT = 0x3 + }; + +-#define HASH_BUFLEN 256 +-#define HASH_LONG_KEY 64 +-#define HASH_MAX_KEY_SIZE (SHA256_BLOCK_SIZE * 8) +-#define HASH_QUEUE_LENGTH 16 +-#define HASH_DMA_THRESHOLD 50 ++enum stm32_hash_algo { ++ HASH_SHA1 = 0, ++ HASH_MD5 = 1, ++ HASH_SHA224 = 2, ++ HASH_SHA256 = 3, ++ HASH_SHA3_224 = 4, ++ HASH_SHA3_256 = 5, ++ HASH_SHA3_384 = 6, ++ HASH_SHA3_512 = 7, ++ HASH_SHA384 = 12, ++ HASH_SHA512 = 15, ++}; + ++#define HASH_MAX_BUFLEN (SHA3_224_BLOCK_SIZE + 4) ++#define HASH_MAX_KEY_SIZE (SHA512_BLOCK_SIZE * 8) ++#define HASH_QUEUE_LENGTH 60 + #define HASH_AUTOSUSPEND_DELAY 50 + + struct stm32_hash_ctx { + struct crypto_engine_ctx enginectx; +- struct stm32_hash_dev *hdev; + unsigned long flags; + + u8 key[HASH_MAX_KEY_SIZE]; +@@ -126,8 +138,7 @@ struct stm32_hash_request_ctx { + unsigned long flags; + unsigned long op; + +- u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32)); +- size_t digcnt; ++ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32)); + size_t bufcnt; + size_t buflen; + +@@ -143,7 +154,7 @@ struct stm32_hash_request_ctx { + + u8 data_type; + +- u8 buffer[HASH_BUFLEN] __aligned(sizeof(u32)); ++ u8 buffer[HASH_MAX_BUFLEN] __aligned(sizeof(u32)); + + /* Export Context */ + u32 *hw_context; +@@ -155,8 +166,9 @@ struct stm32_hash_algs_info { + }; + + struct stm32_hash_pdata { +- struct stm32_hash_algs_info *algs_info; +- size_t algs_info_size; ++ const int alg_shift; ++ const struct stm32_hash_algs_info *algs_info; ++ size_t algs_info_size; + }; + + struct stm32_hash_dev { +@@ -167,10 +179,10 @@ struct stm32_hash_dev { + void __iomem *io_base; + phys_addr_t phys_base; + u32 dma_mode; +- u32 dma_maxburst; + + struct ahash_request *req; + struct crypto_engine *engine; ++ struct crypto_queue queue; + + int err; + unsigned long flags; +@@ -212,11 +224,18 @@ static inline int stm32_hash_wait_busy(struct stm32_hash_dev *hdev) + !(status & HASH_SR_BUSY), 10, 10000); + } + ++static inline int stm32_hash_wait_dinis(struct stm32_hash_dev *hdev) ++{ ++ u32 status; ++ ++ return readl_relaxed_poll_timeout(hdev->io_base + HASH_SR, status, ++ (status & HASH_SR_DATA_INPUT_READY), 10, 10000); ++} ++ + static void stm32_hash_set_nblw(struct stm32_hash_dev *hdev, int length) + { +- u32 reg; ++ u32 reg = stm32_hash_read(hdev, HASH_STR); + +- reg = stm32_hash_read(hdev, HASH_STR); + reg &= ~(HASH_STR_NBLW_MASK); + reg |= (8U * ((length) % 4U)); + stm32_hash_write(hdev, HASH_STR, reg); +@@ -254,44 +273,32 @@ static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev) + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(hdev->req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(hdev->req); + struct stm32_hash_ctx *ctx = crypto_ahash_ctx(tfm); +- ++ u32 alg = (rctx->flags & HASH_FLAGS_ALGO_MASK) >> HASH_FLAGS_ALGO_SHIFT; + u32 reg = HASH_CR_INIT; + +- if (!(hdev->flags & HASH_FLAGS_INIT)) { +- switch (rctx->flags & HASH_FLAGS_ALGO_MASK) { +- case HASH_FLAGS_MD5: +- reg |= HASH_CR_ALGO_MD5; +- break; +- case HASH_FLAGS_SHA1: +- reg |= HASH_CR_ALGO_SHA1; +- break; +- case HASH_FLAGS_SHA224: +- reg |= HASH_CR_ALGO_SHA224; +- break; +- case HASH_FLAGS_SHA256: +- reg |= HASH_CR_ALGO_SHA256; +- break; +- default: +- reg |= HASH_CR_ALGO_MD5; +- } ++ if (hdev->pdata->alg_shift == 7) ++ reg |= ((alg & BIT(1)) << 17) | ((alg & BIT(0)) << 7); ++ else ++ reg |= alg << hdev->pdata->alg_shift; + +- reg |= (rctx->data_type << HASH_CR_DATATYPE_POS); ++ reg |= (rctx->data_type << HASH_CR_DATATYPE_POS); + +- if (rctx->flags & HASH_FLAGS_HMAC) { +- hdev->flags |= HASH_FLAGS_HMAC; +- reg |= HASH_CR_MODE; +- if (ctx->keylen > HASH_LONG_KEY) +- reg |= HASH_CR_LKEY; +- } ++ if (rctx->flags & HASH_FLAGS_HMAC) { ++ hdev->flags |= HASH_FLAGS_HMAC; ++ reg |= HASH_CR_MODE; ++ if (ctx->keylen > (rctx->buflen - sizeof(uint32_t))) ++ reg |= HASH_CR_LKEY; ++ } + +- stm32_hash_write(hdev, HASH_IMR, HASH_DCIE); ++ stm32_hash_write(hdev, HASH_IMR, HASH_DCIE); ++ stm32_hash_write(hdev, HASH_CR, reg); ++ stm32_hash_read(hdev, HASH_SR); + +- stm32_hash_write(hdev, HASH_CR, reg); ++ hdev->flags |= HASH_FLAGS_INIT; + +- hdev->flags |= HASH_FLAGS_INIT; ++ dev_dbg(hdev->dev, "Write Control %x\n", reg); + +- dev_dbg(hdev->dev, "Write Control %x\n", reg); +- } ++ rctx->buflen = rctx->buflen - sizeof(uint32_t); + } + + static void stm32_hash_append_sg(struct stm32_hash_request_ctx *rctx) +@@ -328,11 +335,12 @@ static void stm32_hash_append_sg(struct stm32_hash_request_ctx *rctx) + } + } + +-static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev, +- const u8 *buf, size_t length, int final) ++static int stm32_hash_xmit_cpu(struct stm32_hash_request_ctx *rctx, ++ size_t length, int final) + { ++ const u32 *buffer = (const u32 *)rctx->buffer; ++ struct stm32_hash_dev *hdev = rctx->hdev; + unsigned int count, len32; +- const u32 *buffer = (const u32 *)buf; + u32 reg; + + if (final) +@@ -345,10 +353,8 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev, + + hdev->flags |= HASH_FLAGS_CPU; + +- stm32_hash_write_ctrl(hdev); +- +- if (stm32_hash_wait_busy(hdev)) +- return -ETIMEDOUT; ++ if (!(hdev->flags & HASH_FLAGS_INIT)) ++ stm32_hash_write_ctrl(hdev); + + if ((hdev->flags & HASH_FLAGS_HMAC) && + (!(hdev->flags & HASH_FLAGS_HMAC_KEY))) { +@@ -371,6 +377,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev, + return -ETIMEDOUT; + stm32_hash_write_key(hdev); + } ++ + return -EINPROGRESS; + } + +@@ -386,12 +393,12 @@ static int stm32_hash_update_cpu(struct stm32_hash_dev *hdev) + + final = (rctx->flags & HASH_FLAGS_FINUP); + +- while ((rctx->total >= rctx->buflen) || +- (rctx->bufcnt + rctx->total >= rctx->buflen)) { ++ while ((rctx->total > rctx->buflen) || ++ (rctx->bufcnt + rctx->total > rctx->buflen)) { + stm32_hash_append_sg(rctx); + bufcnt = rctx->bufcnt; + rctx->bufcnt = 0; +- err = stm32_hash_xmit_cpu(hdev, rctx->buffer, bufcnt, 0); ++ err = stm32_hash_xmit_cpu(rctx, bufcnt, 0); + } + + stm32_hash_append_sg(rctx); +@@ -399,7 +406,7 @@ static int stm32_hash_update_cpu(struct stm32_hash_dev *hdev) + if (final) { + bufcnt = rctx->bufcnt; + rctx->bufcnt = 0; +- err = stm32_hash_xmit_cpu(hdev, rctx->buffer, bufcnt, ++ err = stm32_hash_xmit_cpu(rctx, bufcnt, + (rctx->flags & HASH_FLAGS_FINUP)); + } + +@@ -482,7 +489,7 @@ static int stm32_hash_hmac_dma_send(struct stm32_hash_dev *hdev) + struct stm32_hash_ctx *ctx = crypto_ahash_ctx(tfm); + int err; + +- if (ctx->keylen < HASH_DMA_THRESHOLD || (hdev->dma_mode == 1)) { ++ if (ctx->keylen < rctx->buflen || (hdev->dma_mode == 1)) { + err = stm32_hash_write_key(hdev); + if (stm32_hash_wait_busy(hdev)) + return -ETIMEDOUT; +@@ -517,8 +524,8 @@ static int stm32_hash_dma_init(struct stm32_hash_dev *hdev) + dma_conf.direction = DMA_MEM_TO_DEV; + dma_conf.dst_addr = hdev->phys_base + HASH_DIN; + dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +- dma_conf.src_maxburst = hdev->dma_maxburst; +- dma_conf.dst_maxburst = hdev->dma_maxburst; ++ dma_conf.src_maxburst = HASH_BURST_LEVEL; ++ dma_conf.dst_maxburst = HASH_BURST_LEVEL; + dma_conf.device_fc = false; + + chan = dma_request_chan(hdev->dev, "in"); +@@ -552,11 +559,11 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev) + rctx->total = hdev->req->nbytes; + + rctx->nents = sg_nents(rctx->sg); +- + if (rctx->nents < 0) + return -EINVAL; + +- stm32_hash_write_ctrl(hdev); ++ if (!(hdev->flags & HASH_FLAGS_INIT)) ++ stm32_hash_write_ctrl(hdev); + + if (hdev->flags & HASH_FLAGS_HMAC) { + err = stm32_hash_hmac_dma_send(hdev); +@@ -633,21 +640,17 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev) + return err; + } + +-static struct stm32_hash_dev *stm32_hash_find_dev(struct stm32_hash_ctx *ctx) ++static struct stm32_hash_dev *stm32_hash_find_dev(struct stm32_hash_request_ctx *rctx) + { +- struct stm32_hash_dev *hdev = NULL, *tmp; ++ struct stm32_hash_dev *hdev = NULL; + +- spin_lock_bh(&stm32_hash.lock); +- if (!ctx->hdev) { +- list_for_each_entry(tmp, &stm32_hash.dev_list, list) { +- hdev = tmp; +- break; +- } +- ctx->hdev = hdev; +- } else { +- hdev = ctx->hdev; +- } ++ if (rctx->hdev) ++ return rctx->hdev; + ++ spin_lock_bh(&stm32_hash.lock); ++ hdev = list_first_entry(&stm32_hash.dev_list, struct stm32_hash_dev, list); ++ list_move_tail(&hdev->list, &stm32_hash.dev_list); ++ rctx->hdev = hdev; + spin_unlock_bh(&stm32_hash.lock); + + return hdev; +@@ -656,16 +659,17 @@ static struct stm32_hash_dev *stm32_hash_find_dev(struct stm32_hash_ctx *ctx) + static bool stm32_hash_dma_aligned_data(struct ahash_request *req) + { + struct scatterlist *sg; +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); ++ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ struct stm32_hash_dev *hdev = rctx->hdev; + int i; + +- if (req->nbytes <= HASH_DMA_THRESHOLD) ++ if ((!hdev->dma_lch) || (req->nbytes <= rctx->buflen)) + return false; + + if (sg_nents(req->src) > 1) { + if (hdev->dma_mode == 1) + return false; ++ + for_each_sg(req->src, sg, sg_nents(req->src), i) { + if ((!IS_ALIGNED(sg->length, sizeof(u32))) && + (!sg_is_last(sg))) +@@ -684,37 +688,61 @@ static int stm32_hash_init(struct ahash_request *req) + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct stm32_hash_ctx *ctx = crypto_ahash_ctx(tfm); + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); ++ struct stm32_hash_dev *hdev; ++ bool sha3_mode = ctx->flags & HASH_FLAGS_SHA3_MODE; + +- rctx->hdev = hdev; ++ rctx->hdev = NULL; ++ hdev = stm32_hash_find_dev(rctx); ++ if (!hdev) ++ return -ENODEV; + + rctx->flags = HASH_FLAGS_CPU; + +- rctx->digcnt = crypto_ahash_digestsize(tfm); +- switch (rctx->digcnt) { ++ if (sha3_mode) ++ rctx->flags |= HASH_FLAGS_SHA3_MODE; ++ ++ switch (crypto_ahash_digestsize(tfm)) { + case MD5_DIGEST_SIZE: +- rctx->flags |= HASH_FLAGS_MD5; ++ rctx->flags |= HASH_MD5 << HASH_FLAGS_ALGO_SHIFT; + break; + case SHA1_DIGEST_SIZE: +- rctx->flags |= HASH_FLAGS_SHA1; ++ rctx->flags |= HASH_SHA1 << HASH_FLAGS_ALGO_SHIFT; + break; + case SHA224_DIGEST_SIZE: +- rctx->flags |= HASH_FLAGS_SHA224; ++ if (sha3_mode) ++ rctx->flags |= HASH_SHA3_224 << HASH_FLAGS_ALGO_SHIFT; ++ else ++ rctx->flags |= HASH_SHA224 << HASH_FLAGS_ALGO_SHIFT; + break; + case SHA256_DIGEST_SIZE: +- rctx->flags |= HASH_FLAGS_SHA256; ++ if (sha3_mode) ++ rctx->flags |= HASH_SHA3_256 << HASH_FLAGS_ALGO_SHIFT; ++ else ++ rctx->flags |= HASH_SHA256 << HASH_FLAGS_ALGO_SHIFT; ++ break; ++ case SHA384_DIGEST_SIZE: ++ if (sha3_mode) ++ rctx->flags |= HASH_SHA3_384 << HASH_FLAGS_ALGO_SHIFT; ++ else ++ rctx->flags |= HASH_SHA384 << HASH_FLAGS_ALGO_SHIFT; ++ break; ++ case SHA512_DIGEST_SIZE: ++ if (sha3_mode) ++ rctx->flags |= HASH_SHA3_512 << HASH_FLAGS_ALGO_SHIFT; ++ else ++ rctx->flags |= HASH_SHA512 << HASH_FLAGS_ALGO_SHIFT; + break; + default: + return -EINVAL; + } + ++ rctx->buflen = crypto_ahash_blocksize(tfm) + sizeof(uint32_t); + rctx->bufcnt = 0; +- rctx->buflen = HASH_BUFLEN; + rctx->total = 0; + rctx->offset = 0; + rctx->data_type = HASH_DATA_8_BITS; + +- memset(rctx->buffer, 0, HASH_BUFLEN); ++ memset(rctx->buffer, 0, rctx->buflen); + + if (ctx->flags & HASH_FLAGS_HMAC) + rctx->flags |= HASH_FLAGS_HMAC; +@@ -741,8 +769,7 @@ static int stm32_hash_final_req(struct stm32_hash_dev *hdev) + if (!(rctx->flags & HASH_FLAGS_CPU)) + err = stm32_hash_dma_send(hdev); + else +- err = stm32_hash_xmit_cpu(hdev, rctx->buffer, buflen, 1); +- ++ err = stm32_hash_xmit_cpu(rctx, buflen, 1); + + return err; + } +@@ -750,39 +777,31 @@ static int stm32_hash_final_req(struct stm32_hash_dev *hdev) + static void stm32_hash_copy_hash(struct ahash_request *req) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ unsigned int hashsize = crypto_ahash_digestsize(tfm); + __be32 *hash = (void *)rctx->digest; +- unsigned int i, hashsize; +- +- switch (rctx->flags & HASH_FLAGS_ALGO_MASK) { +- case HASH_FLAGS_MD5: +- hashsize = MD5_DIGEST_SIZE; +- break; +- case HASH_FLAGS_SHA1: +- hashsize = SHA1_DIGEST_SIZE; +- break; +- case HASH_FLAGS_SHA224: +- hashsize = SHA224_DIGEST_SIZE; +- break; +- case HASH_FLAGS_SHA256: +- hashsize = SHA256_DIGEST_SIZE; +- break; +- default: +- return; +- } ++ unsigned int i; ++ u32 reg; + + for (i = 0; i < hashsize / sizeof(u32); i++) + hash[i] = cpu_to_be32(stm32_hash_read(rctx->hdev, + HASH_HREG(i))); ++ ++ reg = stm32_hash_read(rctx->hdev, HASH_SR); ++ reg &= ~HASH_SR_OUTPUT_READY; ++ stm32_hash_write(rctx->hdev, HASH_SR, reg); + } + + static int stm32_hash_finish(struct ahash_request *req) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ unsigned int digsize = crypto_ahash_digestsize(tfm); + + if (!req->result) + return -EINVAL; + +- memcpy(req->result, rctx->digest, rctx->digcnt); ++ memcpy(req->result, rctx->digest, digsize); + + return 0; + } +@@ -799,7 +818,7 @@ static void stm32_hash_finish_req(struct ahash_request *req, int err) + HASH_FLAGS_INIT | HASH_FLAGS_DMA_READY | + HASH_FLAGS_OUTPUT_READY | HASH_FLAGS_HMAC | + HASH_FLAGS_HMAC_INIT | HASH_FLAGS_HMAC_FINAL | +- HASH_FLAGS_HMAC_KEY); ++ HASH_FLAGS_HMAC_KEY | HASH_FLAGS_SHA3_MODE); + } else { + rctx->flags |= HASH_FLAGS_ERRORS; + } +@@ -810,8 +829,7 @@ static void stm32_hash_finish_req(struct ahash_request *req, int err) + crypto_finalize_hash_request(hdev->engine, req, err); + } + +-static int stm32_hash_hw_init(struct stm32_hash_dev *hdev, +- struct stm32_hash_request_ctx *rctx) ++static int stm32_hash_hw_init(struct stm32_hash_dev *hdev) + { + pm_runtime_get_sync(hdev->dev); + +@@ -839,38 +857,30 @@ static int stm32_hash_prepare_req(struct crypto_engine *engine, void *areq) + { + struct ahash_request *req = container_of(areq, struct ahash_request, + base); +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); +- struct stm32_hash_request_ctx *rctx; +- +- if (!hdev) +- return -ENODEV; ++ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ struct stm32_hash_dev *hdev = rctx->hdev; + + hdev->req = req; + +- rctx = ahash_request_ctx(req); +- + dev_dbg(hdev->dev, "processing new req, op: %lu, nbytes %d\n", + rctx->op, req->nbytes); + +- return stm32_hash_hw_init(hdev, rctx); ++ return stm32_hash_hw_init(hdev); + } + + static int stm32_hash_one_request(struct crypto_engine *engine, void *areq) + { + struct ahash_request *req = container_of(areq, struct ahash_request, + base); +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); +- struct stm32_hash_request_ctx *rctx; ++ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ struct stm32_hash_dev *hdev = rctx->hdev; + int err = 0; + +- if (!hdev) +- return -ENODEV; +- + hdev->req = req; + +- rctx = ahash_request_ctx(req); ++ err = stm32_hash_hw_init(hdev); ++ if (err) ++ return err; + + if (rctx->op == HASH_OP_UPDATE) + err = stm32_hash_update_req(hdev); +@@ -887,8 +897,7 @@ static int stm32_hash_one_request(struct crypto_engine *engine, void *areq) + static int stm32_hash_enqueue(struct ahash_request *req, unsigned int op) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); +- struct stm32_hash_ctx *ctx = crypto_tfm_ctx(req->base.tfm); +- struct stm32_hash_dev *hdev = ctx->hdev; ++ struct stm32_hash_dev *hdev = rctx->hdev; + + rctx->op = op; + +@@ -899,14 +908,16 @@ static int stm32_hash_update(struct ahash_request *req) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); + +- if (!req->nbytes || !(rctx->flags & HASH_FLAGS_CPU)) ++ if ((!req->nbytes) || !(rctx->flags & HASH_FLAGS_CPU)) + return 0; + ++ stm32_hash_find_dev(rctx); ++ + rctx->total = req->nbytes; + rctx->sg = req->src; + rctx->offset = 0; + +- if ((rctx->bufcnt + rctx->total < rctx->buflen)) { ++ if (rctx->bufcnt + rctx->total <= rctx->buflen) { + stm32_hash_append_sg(rctx); + return 0; + } +@@ -926,15 +937,10 @@ static int stm32_hash_final(struct ahash_request *req) + static int stm32_hash_finup(struct ahash_request *req) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); + int err1, err2; + + rctx->flags |= HASH_FLAGS_FINUP; + +- if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) +- rctx->flags &= ~HASH_FLAGS_CPU; +- + err1 = stm32_hash_update(req); + + if (err1 == -EINPROGRESS || err1 == -EBUSY) +@@ -951,32 +957,81 @@ static int stm32_hash_finup(struct ahash_request *req) + + static int stm32_hash_digest(struct ahash_request *req) + { +- return stm32_hash_init(req) ?: stm32_hash_finup(req); ++ int ret; ++ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ ++ ret = stm32_hash_init(req); ++ if (ret) ++ return ret; ++ ++ if (stm32_hash_dma_aligned_data(req)) ++ rctx->flags &= ~HASH_FLAGS_CPU; ++ ++ return stm32_hash_finup(req); ++} ++ ++static int hash_swap_reg(struct stm32_hash_request_ctx *rctx) ++{ ++ switch ((rctx->flags & HASH_FLAGS_ALGO_MASK) >> ++ HASH_FLAGS_ALGO_SHIFT) { ++ case HASH_MD5: ++ case HASH_SHA1: ++ case HASH_SHA224: ++ case HASH_SHA256: ++ if (rctx->flags & HASH_FLAGS_HMAC) ++ return HASH_CSR_NB_SHA256_HMAC; ++ else ++ return HASH_CSR_NB_SHA256; ++ break; ++ ++ case HASH_SHA384: ++ case HASH_SHA512: ++ if (rctx->flags & HASH_FLAGS_HMAC) ++ return HASH_CSR_NB_SHA512_HMAC; ++ else ++ return HASH_CSR_NB_SHA512; ++ break; ++ ++ case HASH_SHA3_224: ++ case HASH_SHA3_256: ++ case HASH_SHA3_384: ++ case HASH_SHA3_512: ++ if (rctx->flags & HASH_FLAGS_HMAC) ++ return HASH_CSR_NB_SHA3_HMAC; ++ else ++ return HASH_CSR_NB_SHA3; ++ break; ++ ++ default: ++ return -EINVAL; ++ } + } + + static int stm32_hash_export(struct ahash_request *req, void *out) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); ++ struct stm32_hash_dev *hdev = rctx->hdev; + u32 *preg; + unsigned int i; ++ int swap_reg; + + pm_runtime_get_sync(hdev->dev); + + while ((stm32_hash_read(hdev, HASH_SR) & HASH_SR_BUSY)) + cpu_relax(); + +- rctx->hw_context = kmalloc_array(3 + HASH_CSR_REGISTER_NUMBER, +- sizeof(u32), +- GFP_KERNEL); ++ swap_reg = hash_swap_reg(rctx); ++ if (swap_reg < 0) ++ return swap_reg; ++ ++ rctx->hw_context = kmalloc_array(3 + swap_reg, sizeof(u32), GFP_KERNEL); + + preg = rctx->hw_context; + + *preg++ = stm32_hash_read(hdev, HASH_IMR); + *preg++ = stm32_hash_read(hdev, HASH_STR); + *preg++ = stm32_hash_read(hdev, HASH_CR); +- for (i = 0; i < HASH_CSR_REGISTER_NUMBER; i++) ++ for (i = 0; i < swap_reg; i++) + *preg++ = stm32_hash_read(hdev, HASH_CSR(i)); + + pm_runtime_mark_last_busy(hdev->dev); +@@ -990,14 +1045,14 @@ static int stm32_hash_export(struct ahash_request *req, void *out) + static int stm32_hash_import(struct ahash_request *req, const void *in) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); ++ struct stm32_hash_dev *hdev; + const u32 *preg = in; + u32 reg; + unsigned int i; ++ int swap_reg; + + memcpy(rctx, in, sizeof(*rctx)); +- ++ hdev = rctx->hdev; + preg = rctx->hw_context; + + pm_runtime_get_sync(hdev->dev); +@@ -1008,7 +1063,11 @@ static int stm32_hash_import(struct ahash_request *req, const void *in) + reg = *preg++ | HASH_CR_INIT; + stm32_hash_write(hdev, HASH_CR, reg); + +- for (i = 0; i < HASH_CSR_REGISTER_NUMBER; i++) ++ swap_reg = hash_swap_reg(rctx); ++ if (swap_reg < 0) ++ return swap_reg; ++ ++ for (i = 0; i < swap_reg; i++) + stm32_hash_write(hdev, HASH_CSR(i), *preg++); + + pm_runtime_mark_last_busy(hdev->dev); +@@ -1034,8 +1093,7 @@ static int stm32_hash_setkey(struct crypto_ahash *tfm, + return 0; + } + +-static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm, +- const char *algs_hmac_name) ++static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm, u32 algs_flags) + { + struct stm32_hash_ctx *ctx = crypto_tfm_ctx(tfm); + +@@ -1044,8 +1102,8 @@ static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm, + + ctx->keylen = 0; + +- if (algs_hmac_name) +- ctx->flags |= HASH_FLAGS_HMAC; ++ if (algs_flags) ++ ctx->flags |= algs_flags; + + ctx->enginectx.op.do_one_request = stm32_hash_one_request; + ctx->enginectx.op.prepare_request = stm32_hash_prepare_req; +@@ -1055,27 +1113,23 @@ static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm, + + static int stm32_hash_cra_init(struct crypto_tfm *tfm) + { +- return stm32_hash_cra_init_algs(tfm, NULL); ++ return stm32_hash_cra_init_algs(tfm, 0); + } + +-static int stm32_hash_cra_md5_init(struct crypto_tfm *tfm) ++static int stm32_hash_cra_hmac_init(struct crypto_tfm *tfm) + { +- return stm32_hash_cra_init_algs(tfm, "md5"); ++ return stm32_hash_cra_init_algs(tfm, HASH_FLAGS_HMAC); + } + +-static int stm32_hash_cra_sha1_init(struct crypto_tfm *tfm) ++static int stm32_hash_cra_sha3_init(struct crypto_tfm *tfm) + { +- return stm32_hash_cra_init_algs(tfm, "sha1"); ++ return stm32_hash_cra_init_algs(tfm, HASH_FLAGS_SHA3_MODE); + } + +-static int stm32_hash_cra_sha224_init(struct crypto_tfm *tfm) ++static int stm32_hash_cra_sha3_hmac_init(struct crypto_tfm *tfm) + { +- return stm32_hash_cra_init_algs(tfm, "sha224"); +-} +- +-static int stm32_hash_cra_sha256_init(struct crypto_tfm *tfm) +-{ +- return stm32_hash_cra_init_algs(tfm, "sha256"); ++ return stm32_hash_cra_init_algs(tfm, HASH_FLAGS_SHA3_MODE | ++ HASH_FLAGS_HMAC); + } + + static irqreturn_t stm32_hash_irq_thread(int irq, void *dev_id) +@@ -1110,8 +1164,6 @@ static irqreturn_t stm32_hash_irq_handler(int irq, void *dev_id) + + reg = stm32_hash_read(hdev, HASH_SR); + if (reg & HASH_SR_OUTPUT_READY) { +- reg &= ~HASH_SR_OUTPUT_READY; +- stm32_hash_write(hdev, HASH_SR, reg); + hdev->flags |= HASH_FLAGS_OUTPUT_READY; + /* Disable IT*/ + stm32_hash_write(hdev, HASH_IMR, 0); +@@ -1121,7 +1173,7 @@ static irqreturn_t stm32_hash_irq_handler(int irq, void *dev_id) + return IRQ_NONE; + } + +-static struct ahash_alg algs_md5_sha1[] = { ++static struct ahash_alg algs_md5[] = { + { + .init = stm32_hash_init, + .update = stm32_hash_update, +@@ -1132,7 +1184,8 @@ static struct ahash_alg algs_md5_sha1[] = { + .import = stm32_hash_import, + .halg = { + .digestsize = MD5_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "md5", + .cra_driver_name = "stm32-md5", +@@ -1158,7 +1211,8 @@ static struct ahash_alg algs_md5_sha1[] = { + .setkey = stm32_hash_setkey, + .halg = { + .digestsize = MD5_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "hmac(md5)", + .cra_driver_name = "stm32-hmac-md5", +@@ -1168,11 +1222,14 @@ static struct ahash_alg algs_md5_sha1[] = { + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_hash_ctx), + .cra_alignmask = 3, +- .cra_init = stm32_hash_cra_md5_init, ++ .cra_init = stm32_hash_cra_hmac_init, + .cra_module = THIS_MODULE, + } + } +- }, ++ } ++}; ++ ++static struct ahash_alg algs_sha1[] = { + { + .init = stm32_hash_init, + .update = stm32_hash_update, +@@ -1183,7 +1240,8 @@ static struct ahash_alg algs_md5_sha1[] = { + .import = stm32_hash_import, + .halg = { + .digestsize = SHA1_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "sha1", + .cra_driver_name = "stm32-sha1", +@@ -1209,7 +1267,8 @@ static struct ahash_alg algs_md5_sha1[] = { + .setkey = stm32_hash_setkey, + .halg = { + .digestsize = SHA1_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "hmac(sha1)", + .cra_driver_name = "stm32-hmac-sha1", +@@ -1219,7 +1278,7 @@ static struct ahash_alg algs_md5_sha1[] = { + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_hash_ctx), + .cra_alignmask = 3, +- .cra_init = stm32_hash_cra_sha1_init, ++ .cra_init = stm32_hash_cra_hmac_init, + .cra_module = THIS_MODULE, + } + } +@@ -1237,7 +1296,8 @@ static struct ahash_alg algs_sha224_sha256[] = { + .import = stm32_hash_import, + .halg = { + .digestsize = SHA224_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "sha224", + .cra_driver_name = "stm32-sha224", +@@ -1263,7 +1323,8 @@ static struct ahash_alg algs_sha224_sha256[] = { + .import = stm32_hash_import, + .halg = { + .digestsize = SHA224_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "hmac(sha224)", + .cra_driver_name = "stm32-hmac-sha224", +@@ -1273,7 +1334,7 @@ static struct ahash_alg algs_sha224_sha256[] = { + .cra_blocksize = SHA224_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_hash_ctx), + .cra_alignmask = 3, +- .cra_init = stm32_hash_cra_sha224_init, ++ .cra_init = stm32_hash_cra_hmac_init, + .cra_module = THIS_MODULE, + } + } +@@ -1288,7 +1349,8 @@ static struct ahash_alg algs_sha224_sha256[] = { + .import = stm32_hash_import, + .halg = { + .digestsize = SHA256_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "sha256", + .cra_driver_name = "stm32-sha256", +@@ -1314,7 +1376,8 @@ static struct ahash_alg algs_sha224_sha256[] = { + .setkey = stm32_hash_setkey, + .halg = { + .digestsize = SHA256_DIGEST_SIZE, +- .statesize = sizeof(struct stm32_hash_request_ctx), ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, + .base = { + .cra_name = "hmac(sha256)", + .cra_driver_name = "stm32-hmac-sha256", +@@ -1324,13 +1387,339 @@ static struct ahash_alg algs_sha224_sha256[] = { + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_hash_ctx), + .cra_alignmask = 3, +- .cra_init = stm32_hash_cra_sha256_init, ++ .cra_init = stm32_hash_cra_hmac_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++}; ++ ++ ++static struct ahash_alg algs_sha384_sha512[] = { ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .halg = { ++ .digestsize = SHA384_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "sha384", ++ .cra_driver_name = "stm32-sha384", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA384_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .setkey = stm32_hash_setkey, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .halg = { ++ .digestsize = SHA384_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "hmac(sha384)", ++ .cra_driver_name = "stm32-hmac-sha384", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA384_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_hmac_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .halg = { ++ .digestsize = SHA512_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "sha512", ++ .cra_driver_name = "stm32-sha512", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA512_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .setkey = stm32_hash_setkey, ++ .halg = { ++ .digestsize = SHA512_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "hmac(sha512)", ++ .cra_driver_name = "stm32-hmac-sha512", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA512_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_hmac_init, + .cra_module = THIS_MODULE, + } + } + }, + }; + ++static struct ahash_alg algs_sha3[] = { ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .halg = { ++ .digestsize = SHA3_224_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "sha3-224", ++ .cra_driver_name = "stm32-sha3-224", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_224_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .setkey = stm32_hash_setkey, ++ .halg = { ++ .digestsize = SHA3_224_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "hmac(sha3-224)", ++ .cra_driver_name = "stm32-hmac-sha3-224", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_224_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_hmac_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .halg = { ++ .digestsize = SHA3_256_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "sha3-256", ++ .cra_driver_name = "stm32-sha3-256", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_256_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .setkey = stm32_hash_setkey, ++ .halg = { ++ .digestsize = SHA3_256_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "hmac(sha3-256)", ++ .cra_driver_name = "stm32-hmac-sha3-256", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_256_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_hmac_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .halg = { ++ .digestsize = SHA3_384_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "sha3-384", ++ .cra_driver_name = "stm32-sha3-384", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_384_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .setkey = stm32_hash_setkey, ++ .halg = { ++ .digestsize = SHA3_384_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "hmac(sha3-384)", ++ .cra_driver_name = "stm32-hmac-sha3-384", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_384_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_hmac_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .halg = { ++ .digestsize = SHA3_512_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "sha3-512", ++ .cra_driver_name = "stm32-sha3-512", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_512_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ }, ++ { ++ .init = stm32_hash_init, ++ .update = stm32_hash_update, ++ .final = stm32_hash_final, ++ .finup = stm32_hash_finup, ++ .digest = stm32_hash_digest, ++ .export = stm32_hash_export, ++ .import = stm32_hash_import, ++ .setkey = stm32_hash_setkey, ++ .halg = { ++ .digestsize = SHA3_512_DIGEST_SIZE, ++ .statesize = sizeof(struct stm32_hash_request_ctx) + ++ HASH_MAX_BUFLEN, ++ .base = { ++ .cra_name = "hmac(sha3-512)", ++ .cra_driver_name = "stm32-hmac-sha3-512", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_512_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct stm32_hash_ctx), ++ .cra_alignmask = 3, ++ .cra_init = stm32_hash_cra_sha3_hmac_init, ++ .cra_module = THIS_MODULE, ++ } ++ } ++ } ++}; ++ ++ + static int stm32_hash_register_algs(struct stm32_hash_dev *hdev) + { + unsigned int i, j; +@@ -1372,20 +1761,29 @@ static int stm32_hash_unregister_algs(struct stm32_hash_dev *hdev) + + static struct stm32_hash_algs_info stm32_hash_algs_info_stm32f4[] = { + { +- .algs_list = algs_md5_sha1, +- .size = ARRAY_SIZE(algs_md5_sha1), ++ .algs_list = algs_md5, ++ .size = ARRAY_SIZE(algs_md5), ++ }, ++ { ++ .algs_list = algs_sha1, ++ .size = ARRAY_SIZE(algs_sha1), + }, + }; + + static const struct stm32_hash_pdata stm32_hash_pdata_stm32f4 = { ++ .alg_shift = 7, + .algs_info = stm32_hash_algs_info_stm32f4, + .algs_info_size = ARRAY_SIZE(stm32_hash_algs_info_stm32f4), + }; + + static struct stm32_hash_algs_info stm32_hash_algs_info_stm32f7[] = { + { +- .algs_list = algs_md5_sha1, +- .size = ARRAY_SIZE(algs_md5_sha1), ++ .algs_list = algs_md5, ++ .size = ARRAY_SIZE(algs_md5), ++ }, ++ { ++ .algs_list = algs_sha1, ++ .size = ARRAY_SIZE(algs_sha1), + }, + { + .algs_list = algs_sha224_sha256, +@@ -1394,19 +1792,41 @@ static struct stm32_hash_algs_info stm32_hash_algs_info_stm32f7[] = { + }; + + static const struct stm32_hash_pdata stm32_hash_pdata_stm32f7 = { ++ .alg_shift = 7, + .algs_info = stm32_hash_algs_info_stm32f7, + .algs_info_size = ARRAY_SIZE(stm32_hash_algs_info_stm32f7), + }; + +-static const struct of_device_id stm32_hash_of_match[] = { ++ ++static struct stm32_hash_algs_info stm32_hash_algs_info_stm32mp13[] = { ++ { ++ .algs_list = algs_sha1, ++ .size = ARRAY_SIZE(algs_sha1), ++ }, ++ { ++ .algs_list = algs_sha224_sha256, ++ .size = ARRAY_SIZE(algs_sha224_sha256), ++ }, + { +- .compatible = "st,stm32f456-hash", +- .data = &stm32_hash_pdata_stm32f4, ++ .algs_list = algs_sha384_sha512, ++ .size = ARRAY_SIZE(algs_sha384_sha512), + }, + { +- .compatible = "st,stm32f756-hash", +- .data = &stm32_hash_pdata_stm32f7, ++ .algs_list = algs_sha3, ++ .size = ARRAY_SIZE(algs_sha3), + }, ++}; ++ ++static const struct stm32_hash_pdata stm32_hash_pdata_stm32mp13 = { ++ .alg_shift = 17, ++ .algs_info = stm32_hash_algs_info_stm32mp13, ++ .algs_info_size = ARRAY_SIZE(stm32_hash_algs_info_stm32mp13), ++}; ++ ++static const struct of_device_id stm32_hash_of_match[] = { ++ { .compatible = "st,stm32f456-hash", .data = &stm32_hash_pdata_stm32f4 }, ++ { .compatible = "st,stm32f756-hash", .data = &stm32_hash_pdata_stm32f7 }, ++ { .compatible = "st,stm32mp13-hash", .data = &stm32_hash_pdata_stm32mp13 }, + {}, + }; + +@@ -1421,12 +1841,6 @@ static int stm32_hash_get_of_match(struct stm32_hash_dev *hdev, + return -EINVAL; + } + +- if (of_property_read_u32(dev->of_node, "dma-maxburst", +- &hdev->dma_maxburst)) { +- dev_info(dev, "dma-maxburst not specified, using 0\n"); +- hdev->dma_maxburst = 0; +- } +- + return 0; + } + +@@ -1494,6 +1908,8 @@ static int stm32_hash_probe(struct platform_device *pdev) + reset_control_deassert(hdev->rst); + } + ++ crypto_init_queue(&hdev->queue, HASH_QUEUE_LENGTH); ++ + hdev->dev = dev; + + platform_set_drvdata(pdev, hdev); +@@ -1502,7 +1918,7 @@ static int stm32_hash_probe(struct platform_device *pdev) + switch (ret) { + case 0: + break; +- case -ENOENT: ++ case -ENODEV: + dev_dbg(dev, "DMA mode not available\n"); + break; + default: +@@ -1524,7 +1940,8 @@ static int stm32_hash_probe(struct platform_device *pdev) + if (ret) + goto err_engine_start; + +- hdev->dma_mode = stm32_hash_read(hdev, HASH_HWCFGR); ++ hdev->dma_mode = stm32_hash_read(hdev, HASH_HWCFGR) & ++ HASH_HWCFG_DMA_MASK; + + /* Register algos */ + ret = stm32_hash_register_algs(hdev); +@@ -1633,6 +2050,6 @@ static struct platform_driver stm32_hash_driver = { + + module_platform_driver(stm32_hash_driver); + +-MODULE_DESCRIPTION("STM32 SHA1/224/256 & MD5 (HMAC) hw accelerator driver"); ++MODULE_DESCRIPTION("STM32 SHA1/SHA2/SHA3 & MD5 (HMAC) hw accelerator driver"); + MODULE_AUTHOR("Lionel Debieve "); + MODULE_LICENSE("GPL v2"); +-- +2.25.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0005-ARM-5.10.61-stm32mp1-r2-DMA.patch b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0005-ARM-5.15.24-stm32mp1-r1-DMA.patch similarity index 68% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0005-ARM-5.10.61-stm32mp1-r2-DMA.patch rename to recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0005-ARM-5.15.24-stm32mp1-r1-DMA.patch index df06284..d729d85 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0005-ARM-5.10.61-stm32mp1-r2-DMA.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0005-ARM-5.15.24-stm32mp1-r1-DMA.patch @@ -1,69 +1,135 @@ -From f7324af2c2808c281ecd773cdc1efd68026aa3fd Mon Sep 17 00:00:00 2001 -From: Lionel Vitte -Date: Thu, 14 Oct 2021 16:51:42 +0200 -Subject: [PATCH 05/23] ARM 5.10.61-stm32mp1-r2 DMA +From 20c1092971871e4018f8ca5de96282711289cb6f Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 31 May 2022 11:52:37 +0200 +Subject: [PATCH 05/22] ARM-5.15.24-stm32mp1-r1-DMA +Signed-off-by: Christophe Priouzeau --- - drivers/dma/dmaengine.c | 34 ++ - drivers/dma/stm32-dma.c | 1207 +++++++++++++++++++++++++++++++++---- - drivers/dma/stm32-mdma.c | 188 ++++-- - include/linux/dmaengine.h | 11 + - 4 files changed, 1272 insertions(+), 168 deletions(-) + .../devicetree/bindings/dma/st,stm32-dma.yaml | 47 + + .../bindings/dma/st,stm32-mdma.yaml | 12 +- + drivers/dma/stm32-dma.c | 1169 +++++++++++++++-- + drivers/dma/stm32-dmamux.c | 2 +- + drivers/dma/stm32-mdma.c | 170 ++- + 5 files changed, 1246 insertions(+), 154 deletions(-) -diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c -index af3ee288b..8a0cf0d8a 100644 ---- a/drivers/dma/dmaengine.c -+++ b/drivers/dma/dmaengine.c -@@ -873,6 +873,33 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name) - } - EXPORT_SYMBOL_GPL(dma_request_chan); +diff --git a/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml b/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml +index 4bf676fd2..99351fe0f 100644 +--- a/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml ++++ b/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml +@@ -47,6 +47,14 @@ description: | + not wait for the de-assertion of the REQuest, ACK is only managed + by transfer completion. This must only be used on channels + managing transfers for STM32 USART/UART. ++ -bit 30-29: indicated SRAM Buffer size in (2^order)*PAGE_SIZE. ++ Order is given by those 2 bits starting at 0. ++ Valid only whether Intermediate M2M transfer is set. ++ For cyclic, whether Intermediate M2M transfer is chosen, any value can be set: ++ SRAM buffer size will rely on period size and not on this DT value. ++ -bit 31: Intermediate M2M transfer from/to DDR to/from SRAM throughout MDMA ++ 0: MDMA not used to generate an intermediate M2M transfer ++ 1: MDMA used to generate an intermediate M2M transfer. -+/** -+ * dma_request_chan_linked - try to allocate an exclusive slave channel -+ * @dev: pointer to client device structure -+ * @name: slave channel name -+ * -+ * Returns pointer to appropriate DMA channel on success or an error pointer. -+ * Create device link between DMA channel provider and client device consumer. -+ */ -+struct dma_chan *dma_request_chan_linked(struct device *dev, const char *name) -+{ -+ struct dma_chan *chan = dma_request_chan(dev, name); -+ struct device *provider_dev = chan->device->dev; -+ struct device_link *link; -+ -+ if (!IS_ERR_OR_NULL(chan)) { -+ link = device_link_add(dev, provider_dev, DL_FLAG_STATELESS); -+ if (!link) { -+ dev_err(provider_dev, "failed to add dev link with %s\n", dev_name(dev)); -+ dma_release_channel(chan); -+ return ERR_PTR(-EINVAL); -+ } -+ } -+ -+ return chan; -+} -+EXPORT_SYMBOL_GPL(dma_request_chan_linked); -+ - /** - * dma_request_chan_by_mask - allocate a channel satisfying certain capabilities - * @mask: capabilities that the channel must satisfy -@@ -926,6 +953,13 @@ void dma_release_channel(struct dma_chan *chan) - } - EXPORT_SYMBOL_GPL(dma_release_channel); -+void dma_release_chan_linked(struct device *dev, struct dma_chan *chan) -+{ -+ device_link_remove(dev, chan->device->dev); -+ dma_release_channel(chan); -+} -+EXPORT_SYMBOL_GPL(dma_release_chan_linked); + maintainers: +@@ -82,6 +90,35 @@ properties: + description: if defined, it indicates that the controller + supports memory-to-memory transfer + ++ dmas: ++ description: A list of eight dma specifiers, one for each entry in dma-names. ++ Refer to stm32-mdma.yaml for more details. ++ items: ++ - description: DMA channel 0 connected to the MDMA channel specified ++ - description: DMA channel 1 connected to the MDMA channel specified ++ - description: DMA channel 2 connected to the MDMA channel specified ++ - description: DMA channel 3 connected to the MDMA channel specified ++ - description: DMA channel 4 connected to the MDMA channel specified ++ - description: DMA channel 5 connected to the MDMA channel specified ++ - description: DMA channel 6 connected to the MDMA channel specified ++ - description: DMA channel 7 connected to the MDMA channel specified + - /** - * dmaengine_get - register interest in dma_channels - */ ++ dma-names: ++ description: Represents each STM32 DMA channel connected to a STM32 MDMA one. ++ items: ++ - const: ch0 ++ - const: ch1 ++ - const: ch2 ++ - const: ch3 ++ - const: ch4 ++ - const: ch5 ++ - const: ch6 ++ - const: ch7 ++ ++ memory-region: ++ description: Phandle to a node describing memory to be used for M2M intermediate transfer ++ between DMA and MDMA. ++ + required: + - compatible + - reg +@@ -111,6 +148,16 @@ examples: + st,mem2mem; + resets = <&rcc 150>; + dma-requests = <8>; ++ dmas = <&mdma1 8 0x3 0x1200000a 0x40026408 0x00000020 1>, ++ <&mdma1 9 0x3 0x1200000a 0x40026408 0x00000800 1>, ++ <&mdma1 10 0x3 0x1200000a 0x40026408 0x00200000 1>, ++ <&mdma1 11 0x3 0x1200000a 0x40026408 0x08000000 1>, ++ <&mdma1 12 0x3 0x1200000a 0x4002640C 0x00000020 1>, ++ <&mdma1 13 0x3 0x1200000a 0x4002640C 0x00000800 1>, ++ <&mdma1 14 0x3 0x1200000a 0x4002640C 0x00200000 1>, ++ <&mdma1 15 0x3 0x1200000a 0x4002640C 0x08000000 1>; ++ dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; ++ memory-region = <&sram_dmapool>; + }; + + ... +diff --git a/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml b/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml +index c30be840b..c4bb58014 100644 +--- a/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml ++++ b/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml +@@ -10,8 +10,8 @@ description: | + The STM32 MDMA is a general-purpose direct memory access controller capable of + supporting 64 independent DMA channels with 256 HW requests. + DMA clients connected to the STM32 MDMA controller must use the format +- described in the dma.txt file, using a five-cell specifier for each channel: +- a phandle to the MDMA controller plus the following five integer cells: ++ described in the dma.txt file, using a six-cell specifier for each channel: ++ a phandle to the MDMA controller plus the following six integer cells: + 1. The request line number + 2. The priority level + 0x0: Low +@@ -48,6 +48,10 @@ description: | + if no HW ack signal is used by the MDMA client + 5. A 32bit mask specifying the value to be written to acknowledge the request + if no HW ack signal is used by the MDMA client ++ 6. A bitfield value specifying if the MDMA client wants to generate M2M transfer ++ with HW trigger (1) or not (0). This bitfield should be only enabled for ++ M2M transfer triggered by STM32 DMA client. The memory devices involved in this ++ kind of transfer are SRAM and DDR. + + maintainers: + - Amelie Delaunay +@@ -57,7 +61,7 @@ allOf: + + properties: + "#dma-cells": +- const: 5 ++ const: 6 + + compatible: + const: st,stm32h7-mdma +@@ -97,7 +101,7 @@ examples: + interrupts = <122>; + clocks = <&timer_clk>; + resets = <&rcc 992>; +- #dma-cells = <5>; ++ #dma-cells = <6>; + dma-channels = <16>; + dma-requests = <32>; + st,ahb-addr-masks = <0x20000000>, <0x00000000>; diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 1150aa90e..5dd476365 100644 +index 7dfc743ac..7c6078c6c 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -14,12 +14,14 @@ @@ -81,15 +147,7 @@ index 1150aa90e..5dd476365 100644 #include #include #include -@@ -60,6 +62,7 @@ - #define STM32_DMA_SCR_PSIZE_GET(n) ((n & STM32_DMA_SCR_PSIZE_MASK) >> 11) - #define STM32_DMA_SCR_DIR_MASK GENMASK(7, 6) - #define STM32_DMA_SCR_DIR(n) ((n & 0x3) << 6) -+#define STM32_DMA_SCR_TRBUFF BIT(20) /* Bufferable transfer for USART/UART */ - #define STM32_DMA_SCR_CT BIT(19) /* Target in double buffer */ - #define STM32_DMA_SCR_DBM BIT(18) /* Double Buffer Mode */ - #define STM32_DMA_SCR_PINCOS BIT(15) /* Peripheral inc offset size */ -@@ -120,6 +123,7 @@ +@@ -121,6 +123,7 @@ #define STM32_DMA_FIFO_THRESHOLD_NONE 0x04 #define STM32_DMA_MAX_DATA_ITEMS 0xffff @@ -97,23 +155,18 @@ index 1150aa90e..5dd476365 100644 /* * Valid transfer starts from @0 to @0xFFFE leading to unaligned scatter * gather at boundary. Thus it's safer to round down this value on FIFO -@@ -140,6 +144,15 @@ - #define STM32_DMA_DIRECT_MODE_MASK BIT(2) - #define STM32_DMA_DIRECT_MODE_GET(n) (((n) & STM32_DMA_DIRECT_MODE_MASK) \ - >> 2) -+#define STM32_DMA_ALT_ACK_MODE_MASK BIT(4) -+#define STM32_DMA_ALT_ACK_MODE_GET(n) (((n) & STM32_DMA_ALT_ACK_MODE_MASK) \ -+ >> 4) +@@ -142,6 +145,10 @@ + #define STM32_DMA_DIRECT_MODE_GET(n) (((n) & STM32_DMA_DIRECT_MODE_MASK) >> 2) + #define STM32_DMA_ALT_ACK_MODE_MASK BIT(4) + #define STM32_DMA_ALT_ACK_MODE_GET(n) (((n) & STM32_DMA_ALT_ACK_MODE_MASK) >> 4) +#define STM32_DMA_MDMA_CHAIN_FTR_MASK BIT(31) -+#define STM32_DMA_MDMA_CHAIN_FTR_GET(n) (((n) & STM32_DMA_MDMA_CHAIN_FTR_MASK) \ -+ >> 31) ++#define STM32_DMA_MDMA_CHAIN_FTR_GET(n) (((n) & STM32_DMA_MDMA_CHAIN_FTR_MASK) >> 31) +#define STM32_DMA_MDMA_SRAM_SIZE_MASK GENMASK(30, 29) -+#define STM32_DMA_MDMA_SRAM_SIZE_GET(n) (((n) & STM32_DMA_MDMA_SRAM_SIZE_MASK) \ -+ >> 29) ++#define STM32_DMA_MDMA_SRAM_SIZE_GET(n) (((n) & STM32_DMA_MDMA_SRAM_SIZE_MASK) >> 29) enum stm32_dma_width { STM32_DMA_BYTE, -@@ -181,15 +194,32 @@ struct stm32_dma_chan_reg { +@@ -183,15 +190,31 @@ struct stm32_dma_chan_reg { u32 dma_sfcr; }; @@ -127,7 +180,6 @@ index 1150aa90e..5dd476365 100644 + enum dma_transfer_direction dir; + dma_addr_t sram_buf; + u32 sram_period; -+ u32 num_sgs; +}; + struct stm32_dma_sg_req { @@ -147,7 +199,7 @@ index 1150aa90e..5dd476365 100644 struct stm32_dma_sg_req sg_req[]; }; -@@ -206,6 +236,11 @@ struct stm32_dma_chan { +@@ -208,6 +231,13 @@ struct stm32_dma_chan { u32 threshold; u32 mem_burst; u32 mem_width; @@ -156,10 +208,12 @@ index 1150aa90e..5dd476365 100644 + u32 use_mdma; + u32 sram_size; + u32 residue_after_drain; ++ struct workqueue_struct *mdma_wq; ++ struct work_struct mdma_work; }; struct stm32_dma_device { -@@ -214,6 +249,7 @@ struct stm32_dma_device { +@@ -216,6 +246,7 @@ struct stm32_dma_device { struct clk *clk; bool mem2mem; struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS]; @@ -167,25 +221,16 @@ index 1150aa90e..5dd476365 100644 }; static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) -@@ -264,6 +300,7 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan, +@@ -266,7 +297,7 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan, } static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, +- dma_addr_t buf_addr, + u64 buf_addr, u32 threshold) { enum dma_slave_buswidth max_width; -@@ -277,6 +314,9 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, - max_width > DMA_SLAVE_BUSWIDTH_1_BYTE) - max_width = max_width >> 1; - -+ if (do_div(buf_addr, max_width)) -+ max_width = DMA_SLAVE_BUSWIDTH_1_BYTE; -+ - return max_width; - } - -@@ -374,6 +414,16 @@ static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan, +@@ -380,6 +411,16 @@ static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan, } } @@ -202,7 +247,7 @@ index 1150aa90e..5dd476365 100644 static int stm32_dma_slave_config(struct dma_chan *c, struct dma_slave_config *config) { -@@ -479,17 +529,26 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) +@@ -485,17 +526,25 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) } chan->busy = false; @@ -218,8 +263,7 @@ index 1150aa90e..5dd476365 100644 - spin_lock_irqsave(&chan->vchan.lock, flags); + if (chan->use_mdma) { -+ spin_lock_irqsave_nested(&chan->vchan.lock, flags, -+ SINGLE_DEPTH_NESTING); ++ spin_lock_irqsave_nested(&chan->vchan.lock, flags, SINGLE_DEPTH_NESTING); + dmaengine_terminate_async(mchan->chan); + } else { + spin_lock_irqsave(&chan->vchan.lock, flags); @@ -230,7 +274,7 @@ index 1150aa90e..5dd476365 100644 vchan_terminate_vdesc(&chan->desc->vdesc); if (chan->busy) stm32_dma_stop(chan); -@@ -503,9 +562,103 @@ static int stm32_dma_terminate_all(struct dma_chan *c) +@@ -509,9 +558,102 @@ static int stm32_dma_terminate_all(struct dma_chan *c) return 0; } @@ -259,6 +303,8 @@ index 1150aa90e..5dd476365 100644 + int ret; + unsigned long flags; + ++ flush_workqueue(chan->mdma_wq); ++ + /* DMA/MDMA chain: drain remaining data in SRAM */ + + /* Get the residue on MDMA side */ @@ -279,8 +325,7 @@ index 1150aa90e..5dd476365 100644 + /* Remaining data stuck in SRAM */ + dma_to_write = mchan->sram_period - stm32_dma_get_remaining_bytes(chan); + if (dma_to_write > 0) { -+ spin_lock_irqsave_nested(&chan->vchan.lock, flags, -+ SINGLE_DEPTH_NESTING); ++ spin_lock_irqsave_nested(&chan->vchan.lock, flags, SINGLE_DEPTH_NESTING); + + /* Terminate current MDMA to initiate a new one */ + dmaengine_terminate_async(mchan->chan); @@ -292,13 +337,10 @@ index 1150aa90e..5dd476365 100644 + + /* Double buffer management */ + src_buf = mchan->sram_buf + -+ ((mdma_wrote / mchan->sram_period) & 0x1) * -+ mchan->sram_period; ++ ((mdma_wrote / mchan->sram_period) & 0x1) * mchan->sram_period; + dst_buf = sg_dma_address(&sg_req->stm32_sgl_req) + mdma_wrote; + -+ desc = ddev->device_prep_dma_memcpy(mchan->chan, -+ dst_buf, src_buf, -+ dma_to_write, ++ desc = ddev->device_prep_dma_memcpy(mchan->chan, dst_buf, src_buf, dma_to_write, + DMA_PREP_INTERRUPT); + if (!desc) + return -EINVAL; @@ -309,8 +351,7 @@ index 1150aa90e..5dd476365 100644 + + status = dma_wait_for_async_tx(desc); + if (status != DMA_COMPLETE) { -+ dev_err(chan2dev(chan), -+ "%s dma_wait_for_async_tx error\n", __func__); ++ dev_err(chan2dev(chan), "%s dma_wait_for_async_tx error\n", __func__); + dmaengine_terminate_async(mchan->chan); + return -EBUSY; + } @@ -329,16 +370,17 @@ index 1150aa90e..5dd476365 100644 + + if (chan->desc && chan->use_mdma && mchan->dir == DMA_DEV_TO_MEM) + if (stm32_dma_mdma_drain(chan)) -+ dev_err(chan2dev(chan), "%s: can't drain DMA\n", -+ __func__); ++ dev_err(chan2dev(chan), "%s: can't drain DMA\n", __func__); ++ ++ if (chan->use_mdma) ++ dmaengine_synchronize(mchan->chan); vchan_synchronize(&chan->vchan); } -@@ -528,7 +681,244 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) +@@ -534,6 +676,231 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); } --static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan); +static int stm32_dma_dummy_memcpy_xfer(struct stm32_dma_chan *chan) +{ + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); @@ -371,13 +413,11 @@ index 1150aa90e..5dd476365 100644 + reg.dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_MEM) | + STM32_DMA_SCR_PBURST(STM32_DMA_BURST_SINGLE) | + STM32_DMA_SCR_MBURST(STM32_DMA_BURST_SINGLE) | -+ STM32_DMA_SCR_MINC | -+ STM32_DMA_SCR_PINC | ++ STM32_DMA_SCR_MINC | STM32_DMA_SCR_PINC | + STM32_DMA_SCR_TEIE; + reg.dma_spar = dma_src_buf; + reg.dma_sm0ar = dma_dst_buf; -+ reg.dma_sfcr = STM32_DMA_SFCR_MASK | -+ STM32_DMA_SFCR_FTH(STM32_DMA_FIFO_THRESHOLD_FULL); ++ reg.dma_sfcr = STM32_DMA_SFCR_MASK | STM32_DMA_SFCR_FTH(STM32_DMA_FIFO_THRESHOLD_FULL); + reg.dma_sm1ar = dma_dst_buf; + reg.dma_sndtr = 1; + @@ -401,8 +441,7 @@ index 1150aa90e..5dd476365 100644 + reg.dma_scr |= STM32_DMA_SCR_EN; + stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg.dma_scr); + -+ ret = readl_relaxed_poll_timeout_atomic(dmadev->base + -+ STM32_DMA_SNDTR(chan->id), ++ ret = readl_relaxed_poll_timeout_atomic(dmadev->base + STM32_DMA_SNDTR(chan->id), + ndtr, !ndtr, 10, 1000); + if (ret) { + dev_err(chan2dev(chan), "%s: timeout!\n", __func__); @@ -448,15 +487,12 @@ index 1150aa90e..5dd476365 100644 + remain = len % mchan->sram_period; + + if (len > mchan->sram_period && ((len % mchan->sram_period) != 0)) { -+ unsigned long dma_sync_wait_timeout = -+ jiffies + msecs_to_jiffies(5000); ++ unsigned long dma_sync_wait_timeout = jiffies + msecs_to_jiffies(5000); + -+ while (residue > 0 && -+ residue > (mchan->sram_period - remain)) { ++ while (residue > 0 && residue > (mchan->sram_period - remain)) { + if (time_after_eq(jiffies, dma_sync_wait_timeout)) { + dev_err(chan2dev(chan), -+ "%s timeout pending last %d bytes\n", -+ __func__, residue); ++ "%s timeout pending last %d bytes\n", __func__, residue); + return -EBUSY; + } + cpu_relax(); @@ -464,15 +500,11 @@ index 1150aa90e..5dd476365 100644 + } + stm32_dma_disable_chan(chan); + -+ src_buf = mchan->sram_buf + ((len / mchan->sram_period) & 0x1) -+ * mchan->sram_period; -+ dst_buf = sg_dma_address(&sg_req->stm32_sgl_req) + len - -+ (len % mchan->sram_period); ++ src_buf = mchan->sram_buf + ((len / mchan->sram_period) & 0x1) * mchan->sram_period; ++ dst_buf = sg_dma_address(&sg_req->stm32_sgl_req) + len - (len % mchan->sram_period); + -+ desc = ddev->device_prep_dma_memcpy(mchan->chan, -+ dst_buf, src_buf, -+ len % mchan->sram_period, -+ DMA_PREP_INTERRUPT); ++ desc = ddev->device_prep_dma_memcpy(mchan->chan, dst_buf, src_buf, ++ len % mchan->sram_period, DMA_PREP_INTERRUPT); + + if (!desc) + return -EINVAL; @@ -493,34 +525,50 @@ index 1150aa90e..5dd476365 100644 + +static void stm32_dma_start_transfer(struct stm32_dma_chan *chan); + -+static void stm32_mdma_chan_complete(void *param, -+ const struct dmaengine_result *result) ++static void stm32_mdma_chan_complete_worker(struct work_struct *work) +{ -+ struct stm32_dma_chan *chan = param; ++ struct stm32_dma_chan *chan = container_of(work, struct stm32_dma_chan, mdma_work); ++ unsigned long flags; + int ret; + + chan->busy = false; + chan->status = DMA_COMPLETE; -+ if (result->result == DMA_TRANS_NOERROR) { -+ ret = stm32_dma_mdma_flush_remaining(chan); -+ if (ret) { -+ dev_err(chan2dev(chan), "Can't flush DMA: %d\n", ret); -+ return; -+ } ++ ret = stm32_dma_mdma_flush_remaining(chan); ++ if (ret) { ++ dev_err(chan2dev(chan), "Can't flush DMA: %d\n", ret); ++ return; ++ } + -+ if (chan->next_sg == chan->desc->num_sgs) { -+ vchan_cookie_complete(&chan->desc->vdesc); -+ chan->desc = NULL; ++ spin_lock_irqsave_nested(&chan->vchan.lock, flags, SINGLE_DEPTH_NESTING); ++ ++ if (chan->next_sg == chan->desc->num_sgs) { ++ vchan_cookie_complete(&chan->desc->vdesc); ++ chan->desc = NULL; ++ } ++ ++ stm32_dma_start_transfer(chan); ++ ++ spin_unlock_irqrestore(&chan->vchan.lock, flags); ++} ++ ++static void stm32_mdma_chan_complete(void *param, const struct dmaengine_result *result) ++{ ++ struct stm32_dma_chan *chan = param; ++ ++ if (result->result == DMA_TRANS_NOERROR) { ++ if (!queue_work(chan->mdma_wq, &chan->mdma_work)) { ++ chan->busy = false; ++ chan->status = DMA_COMPLETE; ++ dev_warn(chan2dev(chan), "Work already queued\n"); + } -+ stm32_dma_start_transfer(chan); + } else { -+ dev_err(chan2dev(chan), "MDMA transfer error: %d\n", -+ result->result); ++ chan->busy = false; ++ chan->status = DMA_COMPLETE; ++ dev_err(chan2dev(chan), "MDMA transfer error: %d\n", result->result); + } +} + -+static int stm32_dma_mdma_start(struct stm32_dma_chan *chan, -+ struct stm32_dma_sg_req *sg_req) ++static int stm32_dma_mdma_start(struct stm32_dma_chan *chan, struct stm32_dma_sg_req *sg_req) +{ + struct stm32_dma_mdma *mchan = &chan->mchan; + struct stm32_dma_mdma_desc *m_desc = &sg_req->m_desc; @@ -551,36 +599,17 @@ index 1150aa90e..5dd476365 100644 + return ret; +} + -+static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) ++static void stm32_dma_sg_inc(struct stm32_dma_chan *chan) +{ -+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -+ struct stm32_dma_sg_req *sg_req; -+ u32 dma_scr, dma_sm0ar, dma_sm1ar, id; -+ -+ id = chan->id; -+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); -+ -+ if (chan->next_sg == chan->desc->num_sgs) ++ chan->next_sg++; ++ if (chan->desc->cyclic && (chan->next_sg == chan->desc->num_sgs)) + chan->next_sg = 0; -+ -+ sg_req = &chan->desc->sg_req[chan->next_sg]; -+ -+ if (dma_scr & STM32_DMA_SCR_CT) { -+ dma_sm0ar = sg_req->chan_reg.dma_sm0ar; -+ stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar); -+ dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n", -+ stm32_dma_read(dmadev, STM32_DMA_SM0AR(id))); -+ } else { -+ dma_sm1ar = sg_req->chan_reg.dma_sm1ar; -+ stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar); -+ dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", -+ stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); -+ } +} ++ + static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan); static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) - { -@@ -552,6 +942,8 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) +@@ -558,6 +925,8 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) chan->desc = to_stm32_dma_desc(vdesc); chan->next_sg = 0; @@ -589,7 +618,7 @@ index 1150aa90e..5dd476365 100644 } if (chan->next_sg == chan->desc->num_sgs) -@@ -560,6 +952,59 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) +@@ -566,6 +935,53 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) sg_req = &chan->desc->sg_req[chan->next_sg]; reg = &sg_req->chan_reg; @@ -604,15 +633,10 @@ index 1150aa90e..5dd476365 100644 + + m_desc = &sg_req->m_desc; + if (chan->desc->cyclic) { -+ /* -+ * If one callback is set, it will be called by -+ * MDMA driver. -+ */ ++ /* If one callback is set, it will be called by MDMA driver. */ + if (vdesc->tx.callback) { -+ m_desc->desc->callback = -+ vdesc->tx.callback; -+ m_desc->desc->callback_param = -+ vdesc->tx.callback_param; ++ m_desc->desc->callback = vdesc->tx.callback; ++ m_desc->desc->callback_param = vdesc->tx.callback_param; + vdesc->tx.callback = NULL; + vdesc->tx.callback_param = NULL; + } @@ -633,8 +657,7 @@ index 1150aa90e..5dd476365 100644 + if (!chan->desc->cyclic) { + /* MDMA already started */ + if (chan->mchan.dir != DMA_MEM_TO_DEV && -+ sg_dma_len(&sg_req->stm32_sgl_req) > -+ chan->mchan.sram_period) ++ sg_dma_len(&sg_req->stm32_sgl_req) > chan->mchan.sram_period) + reg->dma_scr |= STM32_DMA_SCR_DBM; + ret = stm32_dma_mdma_start(chan, sg_req); + if (ret < 0) { @@ -644,12 +667,12 @@ index 1150aa90e..5dd476365 100644 + } + } + -+ chan->next_sg++; ++ stm32_dma_sg_inc(chan); + reg->dma_scr &= ~STM32_DMA_SCR_EN; stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar); -@@ -568,71 +1013,123 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) +@@ -574,24 +990,17 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar); stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr); @@ -676,55 +699,28 @@ index 1150aa90e..5dd476365 100644 dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan); } --static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) -+static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan) -+{ -+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -+ -+ /* -+ * Read and store current remaining data items and peripheral/memory addresses to be -+ * updated on resume -+ */ -+ chan->chan_reg.dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); -+ /* -+ * Transfer can be paused while between a previous resume and reconfiguration on transfer -+ * complete. If transfer is cyclic and CIRC and DBM have been deactivated for resume, need -+ * to set it here in SCR backup to ensure a good reconfiguration on transfer complete. -+ */ -+ if (chan->desc && chan->desc->cyclic) { -+ if (chan->desc->num_sgs == 1) -+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_CIRC; -+ else -+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM; -+ } -+ chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); -+ -+ dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan); -+} -+ -+static void stm32_dma_post_resume_reconfigure(struct stm32_dma_chan *chan) - { - struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); - struct stm32_dma_sg_req *sg_req; -- u32 dma_scr, dma_sm0ar, dma_sm1ar, id; -+ u32 dma_scr, status, id; - +@@ -604,41 +1013,137 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) id = chan->id; dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); - if (dma_scr & STM32_DMA_SCR_DBM) { - if (chan->next_sg == chan->desc->num_sgs) - chan->next_sg = 0; -+ /* Clear interrupt status if it is there */ -+ status = stm32_dma_irq_status(chan); -+ if (status) -+ stm32_dma_irq_clear(chan, status); ++ sg_req = &chan->desc->sg_req[chan->next_sg]; - sg_req = &chan->desc->sg_req[chan->next_sg]; -+ if (!chan->next_sg) -+ sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1]; -+ else -+ sg_req = &chan->desc->sg_req[chan->next_sg - 1]; ++ if (dma_scr & STM32_DMA_SCR_CT) { ++ dma_sm0ar = sg_req->chan_reg.dma_sm0ar; ++ stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar); ++ dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n", ++ stm32_dma_read(dmadev, STM32_DMA_SM0AR(id))); ++ } else { ++ dma_sm1ar = sg_req->chan_reg.dma_sm1ar; ++ stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar); ++ dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", ++ stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); ++ } ++} - if (dma_scr & STM32_DMA_SCR_CT) { - dma_sm0ar = sg_req->chan_reg.dma_sm0ar; @@ -737,6 +733,69 @@ index 1150aa90e..5dd476365 100644 - dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", - stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); - } ++static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan) ++{ ++ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); ++ u32 dma_scr; ++ ++ /* ++ * Read and store current remaining data items and peripheral/memory addresses to be ++ * updated on resume ++ */ ++ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); ++ /* ++ * Transfer can be paused while between a previous resume and reconfiguration on transfer ++ * complete. If transfer is cyclic and CIRC and DBM have been deactivated for resume, need ++ * to set it here in SCR backup to ensure a good reconfiguration on transfer complete. ++ */ ++ if (chan->desc && chan->desc->cyclic) { ++ if (chan->desc->num_sgs == 1) ++ dma_scr |= STM32_DMA_SCR_CIRC; ++ else ++ dma_scr |= STM32_DMA_SCR_DBM; ++ } ++ chan->chan_reg.dma_scr = dma_scr; ++ ++ /* ++ * Need to temporarily deactivate CIRC/DBM until next Transfer Complete interrupt, otherwise ++ * on resume NDTR autoreload value will be wrong (lower than the initial period length) ++ */ ++ if (chan->desc && chan->desc->cyclic) { ++ dma_scr &= ~(STM32_DMA_SCR_DBM | STM32_DMA_SCR_CIRC); ++ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); + } ++ ++ chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); ++ ++ chan->status = DMA_PAUSED; ++ ++ dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan); + } + +-static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan) ++static void stm32_dma_post_resume_reconfigure(struct stm32_dma_chan *chan) + { +- if (chan->desc) { +- if (chan->desc->cyclic) { +- vchan_cyclic_callback(&chan->desc->vdesc); +- chan->next_sg++; ++ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); ++ struct stm32_dma_sg_req *sg_req; ++ u32 dma_scr, status, id; ++ ++ id = chan->id; ++ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); ++ ++ /* Clear interrupt status if it is there */ ++ status = stm32_dma_irq_status(chan); ++ if (status) ++ stm32_dma_irq_clear(chan, status); ++ ++ if (!chan->next_sg) ++ sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1]; ++ else ++ sg_req = &chan->desc->sg_req[chan->next_sg - 1]; ++ + /* Reconfigure NDTR with the initial value */ + stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), sg_req->chan_reg.dma_sndtr); + @@ -757,7 +816,7 @@ index 1150aa90e..5dd476365 100644 + dma_scr |= STM32_DMA_SCR_CT; + } else if (chan->chan_reg.dma_scr & STM32_DMA_SCR_CIRC) { + dma_scr |= STM32_DMA_SCR_CIRC; - } ++ } + stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); + + stm32_dma_configure_next_sg(chan); @@ -768,15 +827,10 @@ index 1150aa90e..5dd476365 100644 + stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); + + dev_dbg(chan2dev(chan), "vchan %pK: reconfigured after pause/resume\n", &chan->vchan); - } - --static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan) ++} ++ +static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan, u32 scr) - { -- if (chan->desc) { -- if (chan->desc->cyclic) { -- vchan_cyclic_callback(&chan->desc->vdesc); -- chan->next_sg++; ++{ + if (!chan->desc) + return; + @@ -784,7 +838,7 @@ index 1150aa90e..5dd476365 100644 + vchan_cyclic_callback(&chan->desc->vdesc); + if (chan->use_mdma) + return; -+ chan->next_sg++; ++ stm32_dma_sg_inc(chan); + /* cyclic while CIRC/DBM disable => post resume reconfiguration needed */ + if (!(scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM))) + stm32_dma_post_resume_reconfigure(chan); @@ -798,87 +852,50 @@ index 1150aa90e..5dd476365 100644 - } - stm32_dma_start_transfer(chan); + } else { ++ if (chan->use_mdma && chan->mchan.dir != DMA_MEM_TO_DEV) ++ return; /* wait for callback */ + chan->busy = false; + chan->status = DMA_COMPLETE; -+ if (chan->use_mdma && chan->mchan.dir != DMA_MEM_TO_DEV) -+ return; + if (chan->next_sg == chan->desc->num_sgs) { + vchan_cookie_complete(&chan->desc->vdesc); + chan->desc = NULL; } -+ + stm32_dma_start_transfer(chan); } } -@@ -648,21 +1145,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) - scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); - sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); +@@ -674,8 +1179,10 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) -- if (status & STM32_DMA_TCI) { -- stm32_dma_irq_clear(chan, STM32_DMA_TCI); + if (status & STM32_DMA_TCI) { + stm32_dma_irq_clear(chan, STM32_DMA_TCI); - if (scr & STM32_DMA_SCR_TCIE) - stm32_dma_handle_chan_done(chan); -- status &= ~STM32_DMA_TCI; -- } -- if (status & STM32_DMA_HTI) { -- stm32_dma_irq_clear(chan, STM32_DMA_HTI); -- status &= ~STM32_DMA_HTI; -- } - if (status & STM32_DMA_FEI) { - stm32_dma_irq_clear(chan, STM32_DMA_FEI); - status &= ~STM32_DMA_FEI; - if (sfcr & STM32_DMA_SFCR_FEIE) { -- if (!(scr & STM32_DMA_SCR_EN)) -+ if (!(scr & STM32_DMA_SCR_EN) && -+ !(status & STM32_DMA_TCI)) - dev_err(chan2dev(chan), "FIFO Error\n"); - else - dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); -@@ -674,6 +1162,23 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) - if (sfcr & STM32_DMA_SCR_DMEIE) - dev_dbg(chan2dev(chan), "Direct mode overrun\n"); - } -+ -+ if (status & STM32_DMA_TCI) { -+ stm32_dma_irq_clear(chan, STM32_DMA_TCI); + if (scr & STM32_DMA_SCR_TCIE) { -+ if (chan->status == DMA_PAUSED) -+ stm32_dma_handle_chan_paused(chan); -+ else ++ if (chan->status != DMA_PAUSED) + stm32_dma_handle_chan_done(chan, scr); + } -+ status &= ~STM32_DMA_TCI; -+ } -+ -+ if (status & STM32_DMA_HTI) { -+ stm32_dma_irq_clear(chan, STM32_DMA_HTI); -+ status &= ~STM32_DMA_HTI; -+ } -+ - if (status) { - stm32_dma_irq_clear(chan, status); - dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); -@@ -691,19 +1196,125 @@ static void stm32_dma_issue_pending(struct dma_chan *c) + status &= ~STM32_DMA_TCI; + } + +@@ -701,19 +1208,122 @@ static void stm32_dma_issue_pending(struct dma_chan *c) struct stm32_dma_chan *chan = to_stm32_dma_chan(c); unsigned long flags; - spin_lock_irqsave(&chan->vchan.lock, flags); + if (chan->use_mdma) -+ spin_lock_irqsave_nested(&chan->vchan.lock, flags, -+ SINGLE_DEPTH_NESTING); ++ spin_lock_irqsave_nested(&chan->vchan.lock, flags, SINGLE_DEPTH_NESTING); + else + spin_lock_irqsave(&chan->vchan.lock, flags); + if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) { dev_dbg(chan2dev(chan), "vchan %pK: issued\n", &chan->vchan); stm32_dma_start_transfer(chan); - +- } + -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+} -+ + spin_unlock_irqrestore(&chan->vchan.lock, flags); + } + +static int stm32_dma_pause(struct dma_chan *c) +{ + struct stm32_dma_chan *chan = to_stm32_dma_chan(c); @@ -889,14 +906,12 @@ index 1150aa90e..5dd476365 100644 + return -EPERM; + + spin_lock_irqsave(&chan->vchan.lock, flags); ++ + ret = stm32_dma_disable_chan(chan); -+ /* -+ * A transfer complete flag is set to indicate the end of transfer due to the stream -+ * interruption, so wait for interrupt -+ */ + if (!ret) -+ chan->status = DMA_PAUSED; - spin_unlock_irqrestore(&chan->vchan.lock, flags); ++ stm32_dma_handle_chan_paused(chan); ++ ++ spin_unlock_irqrestore(&chan->vchan.lock, flags); + + return ret; +} @@ -958,12 +973,13 @@ index 1150aa90e..5dd476365 100644 + + /* + * Need to temporarily deactivate CIRC/DBM until next Transfer Complete interrupt, -+ * otherwise NDTR autoreload value will be wrong (lower than the initial period length ++ * otherwise NDTR autoreload value will be wrong (lower than the initial period length) + */ -+ if (chan_reg.dma_scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM)) { ++ if (chan_reg.dma_scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM)) + chan_reg.dma_scr &= ~(STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM); -+ stm32_dma_write(dmadev, STM32_DMA_SCR(id), chan_reg.dma_scr); -+ } ++ ++ if (chan_reg.dma_scr & STM32_DMA_SCR_DBM) ++ stm32_dma_configure_next_sg(chan); + + stm32_dma_dump_reg(chan); + @@ -977,74 +993,23 @@ index 1150aa90e..5dd476365 100644 + dev_dbg(chan2dev(chan), "vchan %pK: resumed\n", &chan->vchan); + + return 0; - } - ++} ++ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, enum dma_transfer_direction direction, enum dma_slave_buswidth *buswidth, -- u32 buf_len) +- u32 buf_len, dma_addr_t buf_addr) + u32 buf_len, u64 buf_addr) { enum dma_slave_buswidth src_addr_width, dst_addr_width; int src_bus_width, dst_bus_width; -@@ -735,14 +1346,21 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, - return dst_burst_size; - - /* Set memory data size */ -- src_addr_width = stm32_dma_get_max_width(buf_len, fifoth); -+ src_addr_width = stm32_dma_get_max_width(buf_len, buf_addr, -+ fifoth); - chan->mem_width = src_addr_width; - src_bus_width = stm32_dma_get_width(chan, src_addr_width); - if (src_bus_width < 0) - return src_bus_width; - -- /* Set memory burst size */ -- src_maxburst = STM32_DMA_MAX_BURST; -+ /* -+ * Set memory burst size - burst not possible if address is not aligned on -+ * the address boundary equal to the size of the transfer -+ */ -+ if (do_div(buf_addr, buf_len)) -+ src_maxburst = 1; -+ else -+ src_maxburst = STM32_DMA_MAX_BURST; - src_best_burst = stm32_dma_get_best_burst(buf_len, - src_maxburst, - fifoth, -@@ -784,14 +1402,21 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, - return src_burst_size; - - /* Set memory data size */ -- dst_addr_width = stm32_dma_get_max_width(buf_len, fifoth); -+ dst_addr_width = stm32_dma_get_max_width(buf_len, buf_addr, -+ fifoth); - chan->mem_width = dst_addr_width; - dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); - if (dst_bus_width < 0) - return dst_bus_width; - -- /* Set memory burst size */ -- dst_maxburst = STM32_DMA_MAX_BURST; -+ /* -+ * Set memory burst size - burst not possible if address is not aligned on -+ * the address boundary equal to the size of the transfer -+ */ -+ if (do_div(buf_addr, buf_len)) -+ dst_maxburst = 1; -+ else -+ dst_maxburst = STM32_DMA_MAX_BURST; - dst_best_burst = stm32_dma_get_best_burst(buf_len, - dst_maxburst, - fifoth, -@@ -838,6 +1463,162 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) +@@ -862,6 +1472,151 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); } +static int stm32_dma_mdma_prep_slave_sg(struct stm32_dma_chan *chan, + struct scatterlist *sgl, u32 sg_len, -+ struct stm32_dma_desc *desc, -+ unsigned long flags) ++ struct stm32_dma_desc *desc, unsigned long flags) +{ + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + struct stm32_dma_mdma *mchan = &chan->mchan; @@ -1053,9 +1018,7 @@ index 1150aa90e..5dd476365 100644 + u32 len, num_sgs, sram_period; + int i, j, ret; + -+ desc->dma_buf_cpu = gen_pool_dma_alloc(dmadev->sram_pool, -+ chan->sram_size, -+ &desc->dma_buf); ++ desc->dma_buf_cpu = gen_pool_dma_alloc(dmadev->sram_pool, chan->sram_size, &desc->dma_buf); + if (!desc->dma_buf_cpu) + return -ENOMEM; + desc->dma_buf_size = chan->sram_size; @@ -1073,8 +1036,7 @@ index 1150aa90e..5dd476365 100644 + if (mchan->dir == DMA_MEM_TO_DEV) { + if (len > chan->sram_size) { + dev_err(chan2dev(chan), -+ "max buf size = %d bytes\n", -+ chan->sram_size); ++ "max buf size = %d bytes\n", chan->sram_size); + ret = -EINVAL; + goto free_alloc; + } @@ -1117,10 +1079,8 @@ index 1150aa90e..5dd476365 100644 + + /* Prepare MDMA descriptor */ + m_desc->desc = dmaengine_prep_slave_sg(mchan->chan, -+ m_desc->sgt.sgl, -+ m_desc->sgt.nents, -+ mchan->dir, -+ DMA_PREP_INTERRUPT); ++ m_desc->sgt.sgl, m_desc->sgt.nents, ++ mchan->dir, DMA_PREP_INTERRUPT); + + if (!m_desc->desc) { + ret = -EINVAL; @@ -1131,15 +1091,14 @@ index 1150aa90e..5dd476365 100644 + dmaengine_desc_set_reuse(m_desc->desc); + + if (mchan->dir != DMA_MEM_TO_DEV) { -+ m_desc->desc->callback_result = -+ stm32_mdma_chan_complete; ++ m_desc->desc->callback_result = stm32_mdma_chan_complete; + m_desc->desc->callback_param = chan; ++ INIT_WORK(&chan->mdma_work, stm32_mdma_chan_complete_worker); + } + } + + chan->mchan.sram_buf = desc->dma_buf; + chan->mchan.sram_period = sram_period; -+ chan->mchan.num_sgs = num_sgs; + + return 0; + @@ -1151,14 +1110,12 @@ index 1150aa90e..5dd476365 100644 + sg_free_table(&desc->sg_req[j].m_desc.sgt); + } +free_alloc: -+ gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu, -+ desc->dma_buf_size); ++ gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu, desc->dma_buf_size); + return ret; +} + +static int stm32_dma_setup_sg_requests(struct stm32_dma_chan *chan, -+ struct scatterlist *sgl, -+ unsigned int sg_len, ++ struct scatterlist *sgl, unsigned int sg_len, + enum dma_transfer_direction direction, + struct stm32_dma_desc *desc) +{ @@ -1168,8 +1125,7 @@ index 1150aa90e..5dd476365 100644 + enum dma_slave_buswidth buswidth; + + for_each_sg(sgl, sg, sg_len, i) { -+ ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, -+ sg_dma_len(sg), ++ ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, sg_dma_len(sg), + (u64)sg_dma_address(sg)); + if (ret < 0) + return ret; @@ -1187,8 +1143,7 @@ index 1150aa90e..5dd476365 100644 + desc->sg_req[i].chan_reg.dma_sm0ar = sg_dma_address(sg); + desc->sg_req[i].chan_reg.dma_sm1ar = sg_dma_address(sg); + if (chan->use_mdma) -+ desc->sg_req[i].chan_reg.dma_sm1ar += -+ chan->mchan.sram_period; ++ desc->sg_req[i].chan_reg.dma_sm1ar += chan->mchan.sram_period; + desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; + } + @@ -1200,7 +1155,7 @@ index 1150aa90e..5dd476365 100644 static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( struct dma_chan *c, struct scatterlist *sgl, u32 sg_len, enum dma_transfer_direction direction, -@@ -845,9 +1626,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -869,9 +1624,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); struct stm32_dma_desc *desc; @@ -1210,39 +1165,36 @@ index 1150aa90e..5dd476365 100644 int i, ret; if (!chan->config_init) { -@@ -870,48 +1648,140 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -894,49 +1646,130 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( else chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; - for_each_sg(sgl, sg, sg_len, i) { - ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, -- sg_dma_len(sg)); -- if (ret < 0) -- goto err; -- -- desc->sg_req[i].len = sg_dma_len(sg); +- sg_dma_len(sg), +- sg_dma_address(sg)); + if (chan->use_mdma) { + struct sg_table new_sgt; + struct scatterlist *s, *_sgl; ++ ++ chan->mchan.dir = direction; ++ ret = stm32_dma_mdma_prep_slave_sg(chan, sgl, sg_len, desc, flags); + if (ret < 0) +- goto err; ++ return NULL; + +- desc->sg_req[i].len = sg_dma_len(sg); ++ ret = sg_alloc_table(&new_sgt, sg_len, GFP_ATOMIC); ++ if (ret) ++ dev_err(chan2dev(chan), "DMA sg table alloc failed\n"); - nb_data_items = desc->sg_req[i].len / buswidth; - if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) { - dev_err(chan2dev(chan), "nb items not supported\n"); - goto err; -+ chan->mchan.dir = direction; -+ ret = stm32_dma_mdma_prep_slave_sg(chan, sgl, sg_len, desc, -+ flags); -+ if (ret < 0) -+ return NULL; -+ -+ ret = sg_alloc_table(&new_sgt, sg_len, GFP_ATOMIC); -+ if (ret) -+ dev_err(chan2dev(chan), "DMA sg table alloc failed\n"); -+ + for_each_sg(new_sgt.sgl, s, sg_len, i) { + _sgl = sgl; -+ sg_dma_len(s) = -+ min(sg_dma_len(_sgl), chan->mchan.sram_period); ++ sg_dma_len(s) = min(sg_dma_len(_sgl), chan->mchan.sram_period); + s->dma_address = chan->mchan.sram_buf; + _sgl = sg_next(_sgl); } @@ -1254,15 +1206,13 @@ index 1150aa90e..5dd476365 100644 - desc->sg_req[i].chan_reg.dma_sm0ar = sg_dma_address(sg); - desc->sg_req[i].chan_reg.dma_sm1ar = sg_dma_address(sg); - desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; -+ ret = stm32_dma_setup_sg_requests(chan, new_sgt.sgl, sg_len, -+ direction, desc); ++ ret = stm32_dma_setup_sg_requests(chan, new_sgt.sgl, sg_len, direction, desc); + sg_free_table(&new_sgt); + if (ret < 0) + goto err; + } else { + /* Prepare a normal DMA transfer */ -+ ret = stm32_dma_setup_sg_requests(chan, sgl, sg_len, direction, -+ desc); ++ ret = stm32_dma_setup_sg_requests(chan, sgl, sg_len, direction, desc); + if (ret < 0) + goto err; } @@ -1279,8 +1229,7 @@ index 1150aa90e..5dd476365 100644 + for (i = 0; i < sg_len; i++) + sg_free_table(&desc->sg_req[i].m_desc.sgt); + -+ gen_pool_free(dmadev->sram_pool, -+ (unsigned long)desc->dma_buf_cpu, ++ gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu, + desc->dma_buf_size); + } kfree(desc); @@ -1289,8 +1238,7 @@ index 1150aa90e..5dd476365 100644 +static int stm32_dma_mdma_prep_dma_cyclic(struct stm32_dma_chan *chan, + dma_addr_t buf_addr, size_t buf_len, -+ size_t period_len, -+ struct stm32_dma_desc *desc) ++ size_t period_len, struct stm32_dma_desc *desc) +{ + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + struct stm32_dma_mdma *mchan = &chan->mchan; @@ -1299,8 +1247,7 @@ index 1150aa90e..5dd476365 100644 + int ret; + + chan->sram_size = ALIGN(period_len, STM32_DMA_SRAM_GRANULARITY); -+ desc->dma_buf_cpu = gen_pool_dma_alloc(dmadev->sram_pool, -+ 2 * chan->sram_size, ++ desc->dma_buf_cpu = gen_pool_dma_alloc(dmadev->sram_pool, 2 * chan->sram_size, + &desc->dma_buf); + if (!desc->dma_buf_cpu) + return -ENOMEM; @@ -1342,8 +1289,7 @@ index 1150aa90e..5dd476365 100644 + if (chan->mchan.dir == DMA_MEM_TO_DEV) { + ret = stm32_dma_dummy_memcpy_xfer(chan); + if (ret < 0) { -+ dev_err(chan2dev(chan), -+ "stm32_dma_dummy_memcpy_xfer failed\n"); ++ dev_err(chan2dev(chan), "stm32_dma_dummy_memcpy_xfer failed\n"); + dmaengine_terminate_async(mchan->chan); + goto err; + } @@ -1351,9 +1297,7 @@ index 1150aa90e..5dd476365 100644 + + return 0; +err: -+ gen_pool_free(dmadev->sram_pool, -+ (unsigned long)desc->dma_buf_cpu, -+ desc->dma_buf_size); ++ gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu, desc->dma_buf_size); + return ret; +} + @@ -1371,16 +1315,29 @@ index 1150aa90e..5dd476365 100644 int i, ret; if (!buf_len || !period_len) { -@@ -940,7 +1810,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -965,8 +1798,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( return NULL; } -- ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len); +- ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len, +- buf_addr); + ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len, (u64)buf_addr); if (ret < 0) return NULL; -@@ -959,28 +1829,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -977,36 +1809,57 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( + } + + /* Enable Circular mode or double buffer mode */ +- if (buf_len == period_len) ++ if (buf_len == period_len) { + chan->chan_reg.dma_scr |= STM32_DMA_SCR_CIRC; +- else ++ } else { + chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM; ++ chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_CT; ++ } + /* Clear periph ctrl if client set it */ chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -1401,16 +1358,15 @@ index 1150aa90e..5dd476365 100644 + + if (chan->use_mdma) { + chan->mchan.dir = direction; -+ -+ ret = stm32_dma_mdma_prep_dma_cyclic(chan, buf_addr, buf_len, -+ period_len, desc); + ++ ret = stm32_dma_mdma_prep_dma_cyclic(chan, buf_addr, buf_len, period_len, desc); + if (ret < 0) + return NULL; + dma_buf = desc->dma_buf; + } else { + dma_buf = buf_addr; + } - ++ + for (i = 0; i < num_periods; i++) { + sg_dma_len(&desc->sg_req[i].stm32_sgl_req) = period_len; + sg_dma_address(&desc->sg_req[i].stm32_sgl_req) = dma_buf; @@ -1425,8 +1381,7 @@ index 1150aa90e..5dd476365 100644 + desc->sg_req[i].chan_reg.dma_spar = chan_reg->dma_spar; + if (chan->use_mdma) { + desc->sg_req[i].chan_reg.dma_sm0ar = desc->dma_buf; -+ desc->sg_req[i].chan_reg.dma_sm1ar = desc->dma_buf + -+ chan->sram_size; ++ desc->sg_req[i].chan_reg.dma_sm1ar = desc->dma_buf + chan->sram_size; + } else { + desc->sg_req[i].chan_reg.dma_sm0ar = dma_buf; + desc->sg_req[i].chan_reg.dma_sm1ar = dma_buf; @@ -1442,7 +1397,7 @@ index 1150aa90e..5dd476365 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -@@ -1021,13 +1912,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1047,13 +1900,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( STM32_DMA_SCR_PINC | STM32_DMA_SCR_TCIE | STM32_DMA_SCR_TEIE; @@ -1458,7 +1413,7 @@ index 1150aa90e..5dd476365 100644 } desc->num_sgs = num_sgs; -@@ -1036,18 +1927,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1062,18 +1915,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } @@ -1477,7 +1432,48 @@ index 1150aa90e..5dd476365 100644 /** * stm32_dma_is_current_sg - check that expected sg_req is currently transferred * @chan: dma channel -@@ -1094,6 +1973,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1090,24 +1931,36 @@ static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan) + { + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + struct stm32_dma_sg_req *sg_req; +- u32 dma_scr, dma_smar, id; ++ u32 dma_scr, dma_smar, id, period_len; + + id = chan->id; + dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); + ++ /* In cyclic CIRC but not DBM, CT is not used */ + if (!(dma_scr & STM32_DMA_SCR_DBM)) + return true; + + sg_req = &chan->desc->sg_req[chan->next_sg]; ++ period_len = sg_dma_len(&sg_req->stm32_sgl_req); + ++ /* DBM - take care of a previous pause/resume not yet post reconfigured */ + if (dma_scr & STM32_DMA_SCR_CT) { + dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)); +- return (dma_smar == sg_req->chan_reg.dma_sm0ar); ++ /* ++ * If transfer has been pause/resumed, ++ * SM0AR is in the range of [SM0AR:SM0AR+period_len] ++ */ ++ return (dma_smar >= sg_req->chan_reg.dma_sm0ar && ++ dma_smar < sg_req->chan_reg.dma_sm0ar + period_len); + } + + dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)); +- +- return (dma_smar == sg_req->chan_reg.dma_sm1ar); ++ /* ++ * If transfer has been pause/resumed, ++ * SM1AR is in the range of [SM1AR:SM1AR+period_len] ++ */ ++ return (dma_smar >= sg_req->chan_reg.dma_sm1ar && ++ dma_smar < sg_req->chan_reg.dma_sm1ar + period_len); + } + + static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1120,6 +1973,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; int i; @@ -1488,7 +1484,12 @@ index 1150aa90e..5dd476365 100644 /* * Calculate the residue means compute the descriptors * information: -@@ -1125,7 +2008,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1147,11 +2004,11 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, + + residue = stm32_dma_get_remaining_bytes(chan); + +- if (!stm32_dma_is_current_sg(chan)) { ++ if (chan->desc->cyclic && !stm32_dma_is_current_sg(chan)) { n_sg++; if (n_sg == chan->desc->num_sgs) n_sg = 0; @@ -1497,7 +1498,7 @@ index 1150aa90e..5dd476365 100644 } /* -@@ -1137,7 +2020,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1163,7 +2020,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, */ if (!chan->desc->cyclic || n_sg != 0) for (i = n_sg; i < desc->num_sgs; i++) @@ -1506,7 +1507,7 @@ index 1150aa90e..5dd476365 100644 if (!chan->mem_burst) return residue; -@@ -1155,13 +2038,30 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, +@@ -1181,13 +2038,29 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, struct dma_tx_state *state) { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); @@ -1524,8 +1525,7 @@ index 1150aa90e..5dd476365 100644 + if (chan->desc && chan->use_mdma && + (mchan->dir != DMA_MEM_TO_DEV || chan->desc->cyclic) && + !chan->residue_after_drain) -+ return dmaengine_tx_status(mchan->chan, mchan->chan->cookie, -+ state); ++ return dmaengine_tx_status(mchan->chan, mchan->chan->cookie, state); + status = dma_cookie_status(c, cookie, state); - if (status == DMA_COMPLETE || !state) @@ -1538,12 +1538,10 @@ index 1150aa90e..5dd476365 100644 return status; spin_lock_irqsave(&chan->vchan.lock, flags); -@@ -1216,27 +2116,53 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) - pm_runtime_put(dmadev->ddev.dev); - +@@ -1244,29 +2117,50 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) vchan_free_chan_resources(to_virt_chan(c)); -+ stm32_dma_clear_reg(&chan->chan_reg); -+ chan->threshold = 0; + stm32_dma_clear_reg(&chan->chan_reg); + chan->threshold = 0; + chan->use_mdma = false; + chan->sram_size = 0; } @@ -1567,8 +1565,7 @@ index 1150aa90e..5dd476365 100644 + sg_free_table(&m_desc->sgt); + } + -+ gen_pool_free(dmadev->sram_pool, -+ (unsigned long)desc->dma_buf_cpu, ++ gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu, + desc->dma_buf_size); + } + @@ -1589,15 +1586,15 @@ index 1150aa90e..5dd476365 100644 chan->threshold = STM32_DMA_THRESHOLD_FTR_GET(cfg->features); if (STM32_DMA_DIRECT_MODE_GET(cfg->features)) chan->threshold = STM32_DMA_FIFO_THRESHOLD_NONE; -+ if (STM32_DMA_ALT_ACK_MODE_GET(cfg->features)) -+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_TRBUFF; + if (STM32_DMA_ALT_ACK_MODE_GET(cfg->features)) + chan->chan_reg.dma_scr |= STM32_DMA_SCR_TRBUFF; + chan->use_mdma = STM32_DMA_MDMA_CHAIN_FTR_GET(cfg->features); + chan->sram_size = (1 << STM32_DMA_MDMA_SRAM_SIZE_GET(cfg->features)) * -+ STM32_DMA_SRAM_GRANULARITY; ++ STM32_DMA_SRAM_GRANULARITY; } static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, -@@ -1274,6 +2200,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1304,6 +2198,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, stm32_dma_set_config(chan, &cfg); @@ -1607,7 +1604,7 @@ index 1150aa90e..5dd476365 100644 return c; } -@@ -1286,11 +2215,13 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); +@@ -1316,11 +2213,13 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); static int stm32_dma_probe(struct platform_device *pdev) { struct stm32_dma_chan *chan; @@ -1621,7 +1618,7 @@ index 1150aa90e..5dd476365 100644 int i, ret; match = of_match_device(stm32_dma_of_match, &pdev->dev); -@@ -1334,6 +2265,13 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1364,6 +2263,13 @@ static int stm32_dma_probe(struct platform_device *pdev) reset_control_deassert(rst); } @@ -1629,13 +1626,13 @@ index 1150aa90e..5dd476365 100644 + if (!dmadev->sram_pool) + dev_info(&pdev->dev, "no dma pool: can't use MDMA: %d\n", ret); + else -+ dev_dbg(&pdev->dev, "SRAM pool: %zu KiB\n", -+ gen_pool_size(dmadev->sram_pool) / 1024); ++ dev_dbg(&pdev->dev, ++ "SRAM pool: %zu KiB\n", gen_pool_size(dmadev->sram_pool) / 1024); + dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); dma_cap_set(DMA_SLAVE, dd->cap_mask); -@@ -1345,7 +2283,10 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1375,7 +2281,10 @@ static int stm32_dma_probe(struct platform_device *pdev) dd->device_issue_pending = stm32_dma_issue_pending; dd->device_prep_slave_sg = stm32_dma_prep_slave_sg; dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic; @@ -1646,7 +1643,7 @@ index 1150aa90e..5dd476365 100644 dd->device_terminate_all = stm32_dma_terminate_all; dd->device_synchronize = stm32_dma_synchronize; dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | -@@ -1373,11 +2314,27 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1403,11 +2312,39 @@ static int stm32_dma_probe(struct platform_device *pdev) chan->id = i; chan->vchan.desc_free = stm32_dma_desc_free; vchan_init(&chan->vchan, dd); @@ -1661,9 +1658,21 @@ index 1150aa90e..5dd476365 100644 + if (ret == -EPROBE_DEFER) + goto err_dma; + -+ dev_info(&pdev->dev, -+ "can't request MDMA chan for %s\n", -+ name); ++ dev_info(&pdev->dev, "can't request MDMA chan for %s\n", name); ++ } else { ++ /* ++ * Allocate workqueue per channel in case of MDMA/DMA chaining, to ++ * avoid deadlock with MDMA callback stm32_mdma_chan_complete() when ++ * MDMA interrupt handler is executed in a thread (which is the ++ * case in Linux-RT kernel or if force_irqthreads is set). ++ */ ++ chan->mdma_wq = alloc_ordered_workqueue("dma_work-%s", 0, name); ++ if (!chan->mdma_wq) { ++ dma_release_channel(mchan->chan); ++ mchan->chan = NULL; ++ dev_warn(&pdev->dev, ++ "can't alloc MDMA workqueue for %s\n", name); ++ } + } + } } @@ -1675,7 +1684,7 @@ index 1150aa90e..5dd476365 100644 for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; -@@ -1418,6 +2375,10 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1448,6 +2385,10 @@ static int stm32_dma_probe(struct platform_device *pdev) err_unregister: dma_async_device_unregister(dd); @@ -1686,7 +1695,7 @@ index 1150aa90e..5dd476365 100644 clk_free: clk_disable_unprepare(dmadev->clk); -@@ -1450,7 +2411,7 @@ static int stm32_dma_runtime_resume(struct device *dev) +@@ -1480,7 +2421,7 @@ static int stm32_dma_runtime_resume(struct device *dev) #endif #ifdef CONFIG_PM_SLEEP @@ -1695,7 +1704,7 @@ index 1150aa90e..5dd476365 100644 { struct stm32_dma_device *dmadev = dev_get_drvdata(dev); int id, ret, scr; -@@ -1474,14 +2435,14 @@ static int stm32_dma_suspend(struct device *dev) +@@ -1504,14 +2445,14 @@ static int stm32_dma_suspend(struct device *dev) return 0; } @@ -1712,27 +1721,60 @@ index 1150aa90e..5dd476365 100644 SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, stm32_dma_runtime_resume, NULL) }; -@@ -1499,4 +2460,4 @@ static int __init stm32_dma_init(void) +@@ -1529,4 +2470,4 @@ static int __init stm32_dma_init(void) { return platform_driver_register(&stm32_dma_driver); } -subsys_initcall(stm32_dma_init); +device_initcall(stm32_dma_init); +diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c +index a42164389..f9f77bb09 100644 +--- a/drivers/dma/stm32-dmamux.c ++++ b/drivers/dma/stm32-dmamux.c +@@ -267,7 +267,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev) + ret = PTR_ERR(rst); + if (ret == -EPROBE_DEFER) + goto err_clk; +- } else { ++ } else if (count > 1) { /* Don't reset if there is only one dma-master */ + reset_control_assert(rst); + udelay(2); + reset_control_deassert(rst); diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c -index 9d4739237..88e521bbd 100644 +index f17a9ffcd..133534663 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c -@@ -199,7 +199,9 @@ - #define STM32_MDMA_MAX_CHANNELS 63 +@@ -40,7 +40,6 @@ + STM32_MDMA_SHIFT(mask)) + + #define STM32_MDMA_GISR0 0x0000 /* MDMA Int Status Reg 1 */ +-#define STM32_MDMA_GISR1 0x0004 /* MDMA Int Status Reg 2 */ + + /* MDMA Channel x interrupt/status register */ + #define STM32_MDMA_CISR(x) (0x40 + 0x40 * (x)) /* x = 0..62 */ +@@ -79,6 +78,7 @@ + #define STM32_MDMA_CCR_WEX BIT(14) + #define STM32_MDMA_CCR_HEX BIT(13) + #define STM32_MDMA_CCR_BEX BIT(12) ++#define STM32_MDMA_CCR_SM BIT(8) + #define STM32_MDMA_CCR_PL_MASK GENMASK(7, 6) + #define STM32_MDMA_CCR_PL(n) STM32_MDMA_SET(n, \ + STM32_MDMA_CCR_PL_MASK) +@@ -196,11 +196,13 @@ + + #define STM32_MDMA_MAX_BUF_LEN 128 + #define STM32_MDMA_MAX_BLOCK_LEN 65536 +-#define STM32_MDMA_MAX_CHANNELS 63 ++#define STM32_MDMA_MAX_CHANNELS 32 #define STM32_MDMA_MAX_REQUESTS 256 #define STM32_MDMA_MAX_BURST 128 --#define STM32_MDMA_VERY_HIGH_PRIORITY 0x11 -+#define STM32_MDMA_VERY_HIGH_PRIORITY 0x3 -+ -+#define STM32_DMA_SRAM_GRANULARITY PAGE_SIZE + #define STM32_MDMA_VERY_HIGH_PRIORITY 0x3 ++#define STM32_DMA_SRAM_GRANULARITY PAGE_SIZE ++ enum stm32_mdma_trigger_mode { STM32_MDMA_BUFFER, + STM32_MDMA_BLOCK, @@ -227,6 +229,7 @@ struct stm32_mdma_chan_config { u32 transfer_config; u32 mask_addr; @@ -1749,14 +1791,21 @@ index 9d4739237..88e521bbd 100644 struct stm32_mdma_desc_node node[]; }; -@@ -566,13 +570,25 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, +@@ -276,6 +280,7 @@ struct stm32_mdma_device { + u32 nr_channels; + u32 nr_requests; + u32 nr_ahb_addr_masks; ++ u32 chan_reserved; + struct stm32_mdma_chan chan[STM32_MDMA_MAX_CHANNELS]; + u32 ahb_addr_masks[]; + }; +@@ -566,13 +571,24 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, dst_addr = chan->dma_config.dst_addr; /* Set device data size */ + if (chan_config->m2m_hw) -+ dst_addr_width = -+ stm32_mdma_get_max_width(dst_addr, buf_len, -+ STM32_MDMA_MAX_BUF_LEN); ++ dst_addr_width = stm32_mdma_get_max_width(dst_addr, buf_len, ++ STM32_MDMA_MAX_BUF_LEN); + dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width); if (dst_bus_width < 0) @@ -1775,14 +1824,13 @@ index 9d4739237..88e521bbd 100644 dst_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, dst_maxburst, dst_addr_width); -@@ -615,13 +631,25 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, +@@ -615,13 +631,24 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, src_addr = chan->dma_config.src_addr; /* Set device data size */ + if (chan_config->m2m_hw) -+ src_addr_width = -+ stm32_mdma_get_max_width(src_addr, buf_len, -+ STM32_MDMA_MAX_BUF_LEN); ++ src_addr_width = stm32_mdma_get_max_width(src_addr, buf_len, ++ STM32_MDMA_MAX_BUF_LEN); + src_bus_width = stm32_mdma_get_width(chan, src_addr_width); if (src_bus_width < 0) @@ -1801,7 +1849,7 @@ index 9d4739237..88e521bbd 100644 src_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, src_maxburst, src_addr_width); -@@ -729,6 +757,7 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, +@@ -729,6 +756,7 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, { struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct dma_slave_config *dma_config = &chan->dma_config; @@ -1809,7 +1857,7 @@ index 9d4739237..88e521bbd 100644 struct scatterlist *sg; dma_addr_t src_addr, dst_addr; u32 ccr, ctcr, ctbr; -@@ -751,6 +780,8 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, +@@ -751,6 +779,8 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, } else { src_addr = dma_config->src_addr; dst_addr = sg_dma_address(sg); @@ -1818,7 +1866,7 @@ index 9d4739237..88e521bbd 100644 ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr, &ctbr, dst_addr, sg_dma_len(sg)); -@@ -769,8 +800,6 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, +@@ -769,8 +799,6 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, /* Enable interrupts */ ccr &= ~STM32_MDMA_CCR_IRQ_MASK; ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE; @@ -1827,7 +1875,7 @@ index 9d4739237..88e521bbd 100644 desc->ccr = ccr; return 0; -@@ -782,7 +811,9 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, +@@ -782,7 +810,9 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, unsigned long flags, void *context) { struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); @@ -1837,7 +1885,7 @@ index 9d4739237..88e521bbd 100644 int i, ret; /* -@@ -804,6 +835,20 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, +@@ -804,6 +834,20 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, if (ret < 0) goto xfer_setup_err; @@ -1858,7 +1906,7 @@ index 9d4739237..88e521bbd 100644 desc->cyclic = false; return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -@@ -825,9 +870,10 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, +@@ -825,9 +869,10 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct dma_slave_config *dma_config = &chan->dma_config; @@ -1870,7 +1918,7 @@ index 9d4739237..88e521bbd 100644 int i, ret; /* -@@ -881,12 +927,29 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, +@@ -881,12 +926,29 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, desc->ccr = ccr; /* Configure hwdesc list */ @@ -1902,7 +1950,7 @@ index 9d4739237..88e521bbd 100644 dst_addr = buf_addr + i * period_len; } -@@ -896,6 +959,7 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, +@@ -896,6 +958,7 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, } desc->cyclic = true; @@ -1910,7 +1958,7 @@ index 9d4739237..88e521bbd 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -@@ -1280,14 +1344,28 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan, +@@ -1280,14 +1343,28 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan, { struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct stm32_mdma_hwdesc *hwdesc = desc->node[0].hwdesc; @@ -1942,7 +1990,7 @@ index 9d4739237..88e521bbd 100644 cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)); residue += cbndtr & STM32_MDMA_CBNDTR_BNDT_MASK; -@@ -1307,24 +1385,39 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, +@@ -1307,24 +1384,36 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, struct dma_tx_state *state) { struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); @@ -1971,14 +2019,11 @@ index 9d4739237..88e521bbd 100644 + * add 1 period of data to return the good residue to the + * client + */ -+ if (chan_config->m2m_hw && chan->desc->dir == DMA_MEM_TO_DEV && -+ chan->curr_hwdesc > 1) -+ residue = -+ stm32_mdma_desc_residue(chan, chan->desc, -+ chan->curr_hwdesc - 1); ++ if (chan_config->m2m_hw && ++ chan->desc->dir == DMA_MEM_TO_DEV && chan->curr_hwdesc > 1) ++ residue = stm32_mdma_desc_residue(chan, chan->desc, chan->curr_hwdesc - 1); + else -+ residue = stm32_mdma_desc_residue(chan, chan->desc, -+ chan->curr_hwdesc); ++ residue = stm32_mdma_desc_residue(chan, chan->desc, chan->curr_hwdesc); + } else if (vdesc) { residue = stm32_mdma_desc_residue(chan, to_stm32_mdma_desc(vdesc), 0); @@ -1987,117 +2032,76 @@ index 9d4739237..88e521bbd 100644 dma_set_residue(state, residue); spin_unlock_irqrestore(&chan->vchan.lock, flags); -@@ -1346,7 +1439,7 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) +@@ -1345,26 +1434,16 @@ static void stm32_mdma_xfer_end(struct stm32_mdma_chan *chan) + static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) { struct stm32_mdma_device *dmadev = devid; - struct stm32_mdma_chan *chan = devid; -- u32 reg, id, ien, status, flag; -+ u32 reg, id, ccr, ien, status; +- struct stm32_mdma_chan *chan = devid; ++ struct stm32_mdma_chan *chan; + u32 reg, id, ccr, ien, status; /* Find out which channel generates the interrupt */ status = readl_relaxed(dmadev->base + STM32_MDMA_GISR0); -@@ -1368,67 +1461,71 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) +- if (status) { +- id = __ffs(status); +- } else { +- status = readl_relaxed(dmadev->base + STM32_MDMA_GISR1); +- if (!status) { +- dev_dbg(mdma2dev(dmadev), "spurious it\n"); +- return IRQ_NONE; +- } +- id = __ffs(status); +- /* +- * As GISR0 provides status for channel id from 0 to 31, +- * so GISR1 provides status for channel id from 32 to 62 +- */ +- id += 32; ++ if (!status) { ++ dev_dbg(mdma2dev(dmadev), "spurious it\n"); ++ return IRQ_NONE; + } ++ id = __ffs(status); chan = &dmadev->chan[id]; if (!chan) { -- dev_dbg(mdma2dev(dmadev), "MDMA channel not initialized\n"); -- goto exit; -+ dev_warn(mdma2dev(dmadev), "MDMA channel not initialized\n"); -+ return IRQ_NONE; - } - - /* Handle interrupt for the channel */ - spin_lock(&chan->vchan.lock); -- status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(chan->id)); -- ien = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)); -- ien &= STM32_MDMA_CCR_IRQ_MASK; -- ien >>= 1; -+ status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(id)); -+ /* Mask Channel ReQuest Active bit which can be set in case of MEM2MEM */ -+ status &= ~STM32_MDMA_CISR_CRQA; -+ ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(id)); -+ ien = (ccr & STM32_MDMA_CCR_IRQ_MASK) >> 1; +@@ -1382,9 +1461,12 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) if (!(status & ien)) { spin_unlock(&chan->vchan.lock); -- dev_dbg(chan2dev(chan), -- "spurious it (status=0x%04x, ien=0x%04x)\n", -- status, ien); -+ dev_warn(chan2dev(chan), -+ "spurious it (status=0x%04x, ien=0x%04x)\n", -+ status, ien); +- dev_warn(chan2dev(chan), +- "spurious it (status=0x%04x, ien=0x%04x)\n", +- status, ien); ++ if (chan->busy) ++ dev_warn(chan2dev(chan), ++ "spurious it (status=0x%04x, ien=0x%04x)\n", status, ien); ++ else ++ dev_dbg(chan2dev(chan), ++ "spurious it (status=0x%04x, ien=0x%04x)\n", status, ien); return IRQ_NONE; } -- flag = __ffs(status & ien); -- reg = STM32_MDMA_CIFCR(chan->id); -+ reg = STM32_MDMA_CIFCR(id); - -- switch (1 << flag) { -- case STM32_MDMA_CISR_TEIF: -- id = chan->id; -- status = readl_relaxed(dmadev->base + STM32_MDMA_CESR(id)); -- dev_err(chan2dev(chan), "Transfer Err: stat=0x%08x\n", status); -+ if (status & STM32_MDMA_CISR_TEIF) { -+ dev_err(chan2dev(chan), "Transfer Err: stat=0x%08x\n", -+ readl_relaxed(dmadev->base + STM32_MDMA_CESR(id))); - stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CTEIF); -- break; -+ status &= ~STM32_MDMA_CISR_TEIF; -+ } - -- case STM32_MDMA_CISR_CTCIF: -+ if (status & STM32_MDMA_CISR_CTCIF) { - stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CCTCIF); -+ status &= ~STM32_MDMA_CISR_CTCIF; - stm32_mdma_xfer_end(chan); -- break; -+ } - -- case STM32_MDMA_CISR_BRTIF: -+ if (status & STM32_MDMA_CISR_BRTIF) { - stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CBRTIF); -- break; -+ status &= ~STM32_MDMA_CISR_BRTIF; -+ } - -- case STM32_MDMA_CISR_BTIF: -+ if (status & STM32_MDMA_CISR_BTIF) { - stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CBTIF); -+ status &= ~STM32_MDMA_CISR_BTIF; - chan->curr_hwdesc++; - if (chan->desc && chan->desc->cyclic) { - if (chan->curr_hwdesc == chan->desc->count) - chan->curr_hwdesc = 0; - vchan_cyclic_callback(&chan->desc->vdesc); - } -- break; -+ } - -- case STM32_MDMA_CISR_TCIF: -+ if (status & STM32_MDMA_CISR_TCIF) { - stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CLTCIF); -- break; -+ status &= ~STM32_MDMA_CISR_TCIF; -+ } - -- default: -- dev_err(chan2dev(chan), "it %d unhandled (status=0x%04x)\n", -- 1 << flag, status); -+ if (status) { -+ stm32_mdma_set_bits(dmadev, reg, status); -+ dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); -+ if (!(ccr & STM32_MDMA_CCR_EN)) -+ dev_err(chan2dev(chan), "chan disabled by HW\n"); - } - - spin_unlock(&chan->vchan.lock); - --exit: - return IRQ_HANDLED; +@@ -1484,15 +1566,28 @@ static void stm32_mdma_free_chan_resources(struct dma_chan *c) + chan->desc_pool = NULL; } -@@ -1488,7 +1585,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, ++static bool stm32_mdma_filter_fn(struct dma_chan *c, void *fn_param) ++{ ++ struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); ++ struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); ++ ++ /* Check if chan is marked Secure */ ++ if (dmadev->chan_reserved & BIT(chan->id)) ++ return false; ++ ++ return true; ++} ++ + static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) + { + struct stm32_mdma_device *dmadev = ofdma->of_dma_data; ++ dma_cap_mask_t mask = dmadev->ddev.cap_mask; + struct stm32_mdma_chan *chan; struct dma_chan *c; struct stm32_mdma_chan_config config; @@ -2106,7 +2110,7 @@ index 9d4739237..88e521bbd 100644 dev_err(mdma2dev(dmadev), "Bad number of args\n"); return NULL; } -@@ -1498,6 +1595,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1502,6 +1597,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, config.transfer_config = dma_spec->args[2]; config.mask_addr = dma_spec->args[3]; config.mask_data = dma_spec->args[4]; @@ -2114,45 +2118,26 @@ index 9d4739237..88e521bbd 100644 if (config.request >= dmadev->nr_requests) { dev_err(mdma2dev(dmadev), "Bad request line\n"); -diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h -index dd357a747..42745f584 100644 ---- a/include/linux/dmaengine.h -+++ b/include/linux/dmaengine.h -@@ -1474,9 +1474,11 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, - struct device_node *np); +@@ -1513,7 +1609,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, + return NULL; + } - struct dma_chan *dma_request_chan(struct device *dev, const char *name); -+struct dma_chan *dma_request_chan_linked(struct device *dev, const char *name); - struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask); - - void dma_release_channel(struct dma_chan *chan); -+void dma_release_chan_linked(struct device *dev, struct dma_chan *chan); - int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps); - #else - static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) -@@ -1506,6 +1508,11 @@ static inline struct dma_chan *dma_request_chan(struct device *dev, - { - return ERR_PTR(-ENODEV); - } -+static inline struct dma_chan *dma_request_chan_linked(struct device *dev, -+ const char *name) -+{ -+ return ERR_PTR(-ENODEV); -+} - static inline struct dma_chan *dma_request_chan_by_mask( - const dma_cap_mask_t *mask) - { -@@ -1514,6 +1521,10 @@ static inline struct dma_chan *dma_request_chan_by_mask( - static inline void dma_release_channel(struct dma_chan *chan) - { - } -+static inline void dma_release_chan_linked(struct device *dev, -+ struct dma_chan *chan) -+{ -+} - static inline int dma_get_slave_caps(struct dma_chan *chan, - struct dma_slave_caps *caps) - { +- c = dma_get_any_slave_channel(&dmadev->ddev); ++ c = __dma_request_channel(&mask, stm32_mdma_filter_fn, &config, ofdma->of_node); + if (!c) { + dev_err(mdma2dev(dmadev), "No more channels available\n"); + return NULL; +@@ -1642,6 +1738,10 @@ static int stm32_mdma_probe(struct platform_device *pdev) + for (i = 0; i < dmadev->nr_channels; i++) { + chan = &dmadev->chan[i]; + chan->id = i; ++ ++ if (stm32_mdma_read(dmadev, STM32_MDMA_CCR(i)) & STM32_MDMA_CCR_SM) ++ dmadev->chan_reserved |= BIT(i); ++ + chan->vchan.desc_free = stm32_mdma_desc_free; + vchan_init(&chan->vchan, dd); + } -- -2.17.1 +2.25.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0006-ARM-5.15.24-stm32mp1-r1-DRM.patch b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0006-ARM-5.15.24-stm32mp1-r1-DRM.patch new file mode 100644 index 0000000..8894369 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.15/5.15.24/0006-ARM-5.15.24-stm32mp1-r1-DRM.patch @@ -0,0 +1,2538 @@ +From f595fb2c09e4d443332aae91899ce97f09200c4d Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 31 May 2022 11:53:18 +0200 +Subject: [PATCH 06/22] ARM-5.15.24-stm32mp1-r1-DRM + +Signed-off-by: Christophe Priouzeau +--- + drivers/gpu/drm/bridge/sii902x.c | 100 +- + drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 5 +- + drivers/gpu/drm/drm_bridge.c | 10 +- + drivers/gpu/drm/panel/Kconfig | 9 + + drivers/gpu/drm/panel/Makefile | 1 + + .../gpu/drm/panel/panel-orisetech-otm8009a.c | 101 +- + drivers/gpu/drm/panel/panel-raydium-rm68200.c | 7 +- + drivers/gpu/drm/panel/panel-rocktech-hx8394.c | 397 ++++++++ + drivers/gpu/drm/panel/panel-simple.c | 16 + + drivers/gpu/drm/stm/drv.c | 5 + + drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 114 ++- + drivers/gpu/drm/stm/ltdc.c | 922 +++++++++++++++--- + drivers/gpu/drm/stm/ltdc.h | 15 +- + drivers/video/backlight/gpio_backlight.c | 7 +- + drivers/video/fbdev/simplefb.c | 21 +- + include/drm/bridge/dw_mipi_dsi.h | 4 +- + 16 files changed, 1502 insertions(+), 232 deletions(-) + create mode 100644 drivers/gpu/drm/panel/panel-rocktech-hx8394.c + +diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c +index 89558e581..69208ead5 100644 +--- a/drivers/gpu/drm/bridge/sii902x.c ++++ b/drivers/gpu/drm/bridge/sii902x.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -162,6 +163,11 @@ + + #define SII902X_AUDIO_PORT_INDEX 3 + ++/* CEC device */ ++#define SII902X_CEC_I2C_ADDR 0x30 ++ ++#define SII902X_CEC_SETUP 0x8e ++ + struct sii902x { + struct i2c_client *i2c; + struct regmap *regmap; +@@ -170,6 +176,7 @@ struct sii902x { + struct gpio_desc *reset_gpio; + struct i2c_mux_core *i2cmux; + struct regulator_bulk_data supplies[2]; ++ struct edid *edid; + /* + * Mutex protects audio and video functions from interfering + * each other, by keeping their i2c command sequences atomic. +@@ -280,6 +287,8 @@ static int sii902x_get_modes(struct drm_connector *connector) + + mutex_lock(&sii902x->mutex); + ++ kfree(sii902x->edid); ++ sii902x->edid = NULL; + edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); + drm_connector_update_edid_property(connector, edid); + if (edid) { +@@ -287,7 +296,7 @@ static int sii902x_get_modes(struct drm_connector *connector) + output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; + + num = drm_add_edid_modes(connector, edid); +- kfree(edid); ++ sii902x->edid = edid; + } + + ret = drm_display_info_set_bus_formats(&connector->display_info, +@@ -337,6 +346,7 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) + static void sii902x_bridge_enable(struct drm_bridge *bridge) + { + struct sii902x *sii902x = bridge_to_sii902x(bridge); ++ u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; + + mutex_lock(&sii902x->mutex); + +@@ -346,6 +356,14 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge) + regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, + SII902X_SYS_CTRL_PWR_DWN, 0); + ++ if (sii902x->edid) { ++ if (drm_detect_hdmi_monitor(sii902x->edid)) ++ output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; ++ } ++ ++ regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, ++ SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); ++ + mutex_unlock(&sii902x->mutex); + } + +@@ -960,6 +978,13 @@ static int sii902x_init(struct sii902x *sii902x) + { + struct device *dev = &sii902x->i2c->dev; + unsigned int status = 0; ++ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; ++ struct i2c_msg msg = { ++ .addr = SII902X_CEC_I2C_ADDR << 1, ++ .flags = 0, ++ .len = 2, ++ .buf = data, ++ }; + u8 chipid[4]; + int ret; + +@@ -982,13 +1007,22 @@ static int sii902x_init(struct sii902x *sii902x) + return -EINVAL; + } + ++ /* ++ * By default, CEC must be disabled to allow other CEC devives ++ * to bypass the bridge. ++ */ ++ ret = i2c_transfer(sii902x->i2c->adapter, &msg, 1); ++ if (ret < 0) ++ dev_warn(&sii902x->i2c->dev, "Failed to disable CEC device!\n"); ++ + /* Clear all pending interrupts */ + regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); + regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); + + if (sii902x->i2c->irq > 0) { +- regmap_write(sii902x->regmap, SII902X_INT_ENABLE, +- SII902X_HOTPLUG_EVENT); ++ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, ++ SII902X_HOTPLUG_EVENT, ++ SII902X_HOTPLUG_EVENT); + + ret = devm_request_threaded_irq(dev, sii902x->i2c->irq, NULL, + sii902x_interrupt, +@@ -1087,6 +1121,65 @@ static int sii902x_remove(struct i2c_client *client) + return 0; + } + ++static int sii902x_pm_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sii902x *sii902x = i2c_get_clientdata(client); ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ if (sii902x->reset_gpio) ++ gpiod_set_value(sii902x->reset_gpio, 1); ++ ++ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ ++ return 0; ++} ++ ++static int sii902x_pm_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sii902x *sii902x = i2c_get_clientdata(client); ++ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; ++ struct i2c_msg msg = { ++ .addr = SII902X_CEC_I2C_ADDR << 1, ++ .flags = 0, ++ .len = 2, ++ .buf = data, ++ }; ++ int ret; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ if (ret) { ++ DRM_ERROR("regulator_bulk_enable failed\n"); ++ return ret; ++ } ++ ++ if (sii902x->reset_gpio) ++ gpiod_set_value(sii902x->reset_gpio, 0); ++ ++ regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x00); ++ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret < 0) ++ DRM_ERROR("Failed to disable CEC device!\n"); ++ ++ if (client->irq > 0) ++ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, ++ SII902X_HOTPLUG_EVENT, ++ SII902X_HOTPLUG_EVENT); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops sii902x_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(sii902x_pm_suspend, sii902x_pm_resume) ++}; ++ + static const struct of_device_id sii902x_dt_ids[] = { + { .compatible = "sil,sii9022", }, + { } +@@ -1105,6 +1198,7 @@ static struct i2c_driver sii902x_driver = { + .driver = { + .name = "sii902x", + .of_match_table = sii902x_dt_ids, ++ .pm = &sii902x_pm_ops, + }, + .id_table = sii902x_i2c_ids, + }; +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +index e44e18a01..3f6564762 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +@@ -998,7 +998,10 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, + enum drm_mode_status mode_status = MODE_OK; + + if (pdata->mode_valid) +- mode_status = pdata->mode_valid(pdata->priv_data, mode); ++ mode_status = pdata->mode_valid(pdata->priv_data, mode, ++ dsi->mode_flags, ++ dw_mipi_dsi_get_lanes(dsi), ++ dsi->format); + + return mode_status; + } +diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c +index a8ed66751..01494544e 100644 +--- a/drivers/gpu/drm/drm_bridge.c ++++ b/drivers/gpu/drm/drm_bridge.c +@@ -228,11 +228,13 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, + list_del(&bridge->chain_node); + + #ifdef CONFIG_OF +- DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n", +- bridge->of_node, encoder->name, ret); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n", ++ bridge->of_node, encoder->name, ret); + #else +- DRM_ERROR("failed to attach bridge to encoder %s: %d\n", +- encoder->name, ret); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("failed to attach bridge to encoder %s: %d\n", ++ encoder->name, ret); + #endif + + return ret; +diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig +index 418638e6e..f1a60de49 100644 +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -357,6 +357,15 @@ config DRM_PANEL_RAYDIUM_RM68200 + Say Y here if you want to enable support for Raydium RM68200 + 720x1280 DSI video mode panel. + ++config DRM_PANEL_ROCKTECH_HX8394 ++ tristate "Rocktech HX8394 720x1280 DSI video mode panel" ++ depends on OF ++ depends on DRM_MIPI_DSI ++ depends on BACKLIGHT_CLASS_DEVICE ++ help ++ Say Y here if you want to enable support for Rocktech HX8394 ++ 720x1280 DSI video mode panel. ++ + config DRM_PANEL_RONBO_RB070D30 + tristate "Ronbo Electronics RB070D30 panel" + depends on OF +diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile +index c8132050b..57d794897 100644 +--- a/drivers/gpu/drm/panel/Makefile ++++ b/drivers/gpu/drm/panel/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o + obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o + obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o + obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o ++obj-$(CONFIG_DRM_PANEL_ROCKTECH_HX8394) += panel-rocktech-hx8394.o + obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o + obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o + obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o +diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +index f80b44a8a..70b2bb72d 100644 +--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c ++++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +@@ -60,6 +60,9 @@ + #define MCS_CMD2_ENA1 0xFF00 /* Enable Access Command2 "CMD2" */ + #define MCS_CMD2_ENA2 0xFF80 /* Enable Access Orise Command2 */ + ++#define OTM8009A_HDISPLAY 480 ++#define OTM8009A_VDISPLAY 800 ++ + struct otm8009a { + struct device *dev; + struct drm_panel panel; +@@ -70,19 +73,35 @@ struct otm8009a { + bool enabled; + }; + +-static const struct drm_display_mode default_mode = { +- .clock = 29700, +- .hdisplay = 480, +- .hsync_start = 480 + 98, +- .hsync_end = 480 + 98 + 32, +- .htotal = 480 + 98 + 32 + 98, +- .vdisplay = 800, +- .vsync_start = 800 + 15, +- .vsync_end = 800 + 15 + 10, +- .vtotal = 800 + 15 + 10 + 14, +- .flags = 0, +- .width_mm = 52, +- .height_mm = 86, ++static const struct drm_display_mode modes[] = { ++ { /* 50 Hz, preferred */ ++ .clock = 29700, ++ .hdisplay = 480, ++ .hsync_start = 480 + 98, ++ .hsync_end = 480 + 98 + 32, ++ .htotal = 480 + 98 + 32 + 98, ++ .vdisplay = 800, ++ .vsync_start = 800 + 15, ++ .vsync_end = 800 + 15 + 10, ++ .vtotal = 800 + 15 + 10 + 14, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, ++ .width_mm = 52, ++ .height_mm = 86, ++ }, ++ { /* 60 Hz */ ++ .clock = 33000, ++ .hdisplay = 480, ++ .hsync_start = 480 + 70, ++ .hsync_end = 480 + 70 + 32, ++ .htotal = 480 + 70 + 32 + 72, ++ .vdisplay = 800, ++ .vsync_start = 800 + 15, ++ .vsync_end = 800 + 15 + 10, ++ .vtotal = 800 + 15 + 10 + 16, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, ++ .width_mm = 52, ++ .height_mm = 86, ++ }, + }; + + static inline struct otm8009a *panel_to_otm8009a(struct drm_panel *panel) +@@ -208,12 +227,11 @@ static int otm8009a_init_sequence(struct otm8009a *ctx) + /* Default portrait 480x800 rgb24 */ + dcs_write_seq(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + +- ret = mipi_dsi_dcs_set_column_address(dsi, 0, +- default_mode.hdisplay - 1); ++ ret = mipi_dsi_dcs_set_column_address(dsi, 0, OTM8009A_HDISPLAY - 1); + if (ret) + return ret; + +- ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1); ++ ret = mipi_dsi_dcs_set_page_address(dsi, 0, OTM8009A_VDISPLAY - 1); + if (ret) + return ret; + +@@ -337,24 +355,35 @@ static int otm8009a_get_modes(struct drm_panel *panel, + struct drm_connector *connector) + { + struct drm_display_mode *mode; +- +- mode = drm_mode_duplicate(connector->dev, &default_mode); +- if (!mode) { +- dev_err(panel->dev, "failed to add mode %ux%u@%u\n", +- default_mode.hdisplay, default_mode.vdisplay, +- drm_mode_vrefresh(&default_mode)); +- return -ENOMEM; ++ unsigned int num_modes = ARRAY_SIZE(modes); ++ unsigned int i; ++ ++ for (i = 0; i < num_modes; i++) { ++ mode = drm_mode_duplicate(connector->dev, &modes[i]); ++ if (!mode) { ++ dev_err(panel->dev, "failed to add mode %ux%u@%u\n", ++ modes[i].hdisplay, ++ modes[i].vdisplay, ++ drm_mode_vrefresh(&modes[i])); ++ return -ENOMEM; ++ } ++ ++ mode->type = DRM_MODE_TYPE_DRIVER; ++ ++ /* Setting first mode as preferred */ ++ if (!i) ++ mode->type |= DRM_MODE_TYPE_PREFERRED; ++ ++ drm_mode_set_name(mode); ++ drm_mode_probed_add(connector, mode); + } + +- drm_mode_set_name(mode); +- +- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; +- drm_mode_probed_add(connector, mode); +- + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; ++ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | ++ DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; + +- return 1; ++ return num_modes; + } + + static const struct drm_panel_funcs otm8009a_drm_funcs = { +@@ -419,8 +448,18 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) + + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) { +- dev_err(dev, "cannot get reset-gpio\n"); +- return PTR_ERR(ctx->reset_gpio); ++ ret = PTR_ERR(ctx->reset_gpio); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "cannot get reset GPIO: %d\n", ret); ++ return ret; ++ } ++ ++ /* Reset the panel to avoid visual artifacts */ ++ if (ctx->reset_gpio) { ++ gpiod_set_value_cansleep(ctx->reset_gpio, 0); ++ gpiod_set_value_cansleep(ctx->reset_gpio, 1); ++ msleep(20); ++ gpiod_set_value_cansleep(ctx->reset_gpio, 0); + } + + ctx->supply = devm_regulator_get(dev, "power"); +diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c +index 412c0dbcb..d5542266e 100644 +--- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c ++++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c +@@ -91,7 +91,7 @@ static const struct drm_display_mode default_mode = { + .vsync_start = 1280 + 12, + .vsync_end = 1280 + 12 + 5, + .vtotal = 1280 + 12 + 5 + 12, +- .flags = 0, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 68, + .height_mm = 122, + }; +@@ -347,6 +347,8 @@ static int rm68200_get_modes(struct drm_panel *panel, + + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; ++ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | ++ DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; + + return 1; + } +@@ -372,7 +374,8 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) { + ret = PTR_ERR(ctx->reset_gpio); +- dev_err(dev, "cannot get reset GPIO: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "cannot get reset GPIO: %d\n", ret); + return ret; + } + +diff --git a/drivers/gpu/drm/panel/panel-rocktech-hx8394.c b/drivers/gpu/drm/panel/panel-rocktech-hx8394.c +new file mode 100644 +index 000000000..6a5926cc7 +--- /dev/null ++++ b/drivers/gpu/drm/panel/panel-rocktech-hx8394.c +@@ -0,0 +1,397 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics SA 2022 ++ * ++ * Author: Yannick Fertre ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include