clk: sunxi-ng: Add support for update bit
authorAndre Przywara <andre.przywara@arm.com>
Fri, 7 Mar 2025 00:26:17 +0000 (00:26 +0000)
committerChen-Yu Tsai <wens@csie.org>
Wed, 12 Mar 2025 03:58:09 +0000 (11:58 +0800)
Some clocks in the Allwinner A523 SoC contain an "update bit" (bit 27),
which must be set to apply any register changes, namely the mux
selector, the divider and the gate bit.

Add a new CCU feature bit to mark those clocks, and set bit 27 whenever
we are applying any changes.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Link: https://patch.msgid.link/20250307002628.10684-4-andre.przywara@arm.com
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
drivers/clk/sunxi-ng/ccu_common.h
drivers/clk/sunxi-ng/ccu_div.c
drivers/clk/sunxi-ng/ccu_gate.c
drivers/clk/sunxi-ng/ccu_mux.c

index 50fd268329671c007c583bc22234e38de38521f7..bbec283b9d9939f85b1ab45e0f2dc421ef9a632e 100644 (file)
 #define CCU_FEATURE_KEY_FIELD          BIT(8)
 #define CCU_FEATURE_CLOSEST_RATE       BIT(9)
 #define CCU_FEATURE_DUAL_DIV           BIT(10)
+#define CCU_FEATURE_UPDATE_BIT         BIT(11)
 
 /* MMC timing mode switch bit */
 #define CCU_MMC_NEW_TIMING_MODE                BIT(30)
 
+/* Some clocks need this bit to actually apply register changes */
+#define CCU_SUNXI_UPDATE_BIT           BIT(27)
+
 struct device_node;
 
 struct ccu_common {
index 7f4691f09e01fc36d8908a296182666352305730..916d6da6d8a3b29240e086eaebbbc620346eef91 100644 (file)
@@ -106,6 +106,8 @@ static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
 
        reg = readl(cd->common.base + cd->common.reg);
        reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift);
+       if (cd->common.features & CCU_FEATURE_UPDATE_BIT)
+               reg |= CCU_SUNXI_UPDATE_BIT;
 
        writel(reg | (val << cd->div.shift),
               cd->common.base + cd->common.reg);
index ac52fd6bff677600817748e12274902bc48e2419..474a9e8831f87ffcec7712c14ecb55b8523f05a6 100644 (file)
@@ -20,6 +20,8 @@ void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
        spin_lock_irqsave(common->lock, flags);
 
        reg = readl(common->base + common->reg);
+       if (common->features & CCU_FEATURE_UPDATE_BIT)
+               reg |= CCU_SUNXI_UPDATE_BIT;
        writel(reg & ~gate, common->base + common->reg);
 
        spin_unlock_irqrestore(common->lock, flags);
@@ -44,6 +46,8 @@ int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
        spin_lock_irqsave(common->lock, flags);
 
        reg = readl(common->base + common->reg);
+       if (common->features & CCU_FEATURE_UPDATE_BIT)
+               reg |= CCU_SUNXI_UPDATE_BIT;
        writel(reg | gate, common->base + common->reg);
 
        spin_unlock_irqrestore(common->lock, flags);
index d7ffbdeee9e0475cb9be1c1ba333c23d00efbb2d..74f9e98a5d355d6a26b1655c25e9e48da1f6f10d 100644 (file)
@@ -197,6 +197,8 @@ int ccu_mux_helper_set_parent(struct ccu_common *common,
        /* The key field always reads as zero. */
        if (common->features & CCU_FEATURE_KEY_FIELD)
                reg |= CCU_MUX_KEY_VALUE;
+       if (common->features & CCU_FEATURE_UPDATE_BIT)
+               reg |= CCU_SUNXI_UPDATE_BIT;
 
        reg &= ~GENMASK(cm->width + cm->shift - 1, cm->shift);
        writel(reg | (index << cm->shift), common->base + common->reg);