Commit d2692ed4 authored by Claudiu Beznea's avatar Claudiu Beznea Committed by Geert Uytterhoeven
Browse files

clk: renesas: rzg2l: Lock around writes to mux register



The SD MUX output (SD0) is further divided by 4 in G2{L,UL}.  The
divided clock is SD0_DIV4. SD0_DIV4 is registered with
CLK_SET_RATE_PARENT which means a rate request for it is propagated to
the MUX and could reach rzg2l_cpg_sd_clk_mux_set_parent() concurrently
with the users of SD0.
Add proper locking to avoid concurrent accesses on SD MUX set rate
registers.

Fixes: eaff3364 ("clk: renesas: rzg2l: Add SDHI clk mux support")
Signed-off-by: default avatarClaudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/20230929053915.1530607-4-claudiu.beznea@bp.renesas.com


Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
parent 549f4ae2
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -189,6 +189,7 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index)
	u32 shift = GET_SHIFT(hwdata->conf);
	const u32 clk_src_266 = 2;
	u32 msk, val, bitmask;
	unsigned long flags;
	int ret;

	/*
@@ -204,23 +205,25 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index)
	 */
	bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16;
	msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS;
	spin_lock_irqsave(&priv->rmw_lock, flags);
	if (index != clk_src_266) {
		writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off);

		ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val,
					 !(val & msk), 100,
		ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val,
						!(val & msk), 10,
						CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US);
		if (ret) {
			dev_err(priv->dev, "failed to switch clk source\n");
			return ret;
		}
		if (ret)
			goto unlock;
	}

	writel(bitmask | ((index + 1) << shift), priv->base + off);

	ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val,
				 !(val & msk), 100,
	ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val,
					!(val & msk), 10,
					CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US);
unlock:
	spin_unlock_irqrestore(&priv->rmw_lock, flags);

	if (ret)
		dev_err(priv->dev, "failed to switch clk source\n");

+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@
#define CPG_CLKSTATUS_SELSDHI0_STS	BIT(28)
#define CPG_CLKSTATUS_SELSDHI1_STS	BIT(29)

#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US	20000
#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US	200

/* n = 0/1/2 for PLL1/4/6 */
#define CPG_SAMPLL_CLK1(n)	(0x04 + (16 * n))