[PATCH 4/6] clk: qcom: Allow polling for clock status in qcom_gate_clk_en()

Casey Connolly casey.connolly at linaro.org
Tue Apr 22 14:46:17 CEST 2025



On 4/22/25 12:54, Stephan Gerhold wrote:
> GATE_CLK() in its current state is unsafe: A simple write to the clock
> enable register does not guarantee that the clock is immediately running.
> Without polling the clock status, we may issue writes to registers before
> the necessary clocks start running. This doesn't seem to cause issues in
> U-Boot at the moment, but for example removing the CLK_OFF polling in TF-A
> for the SMMU clocks on DB410c reliably triggers an exception during boot.
> 
> Make it possible to poll the branch clock status register, by adding a new
> BRANCH_CLK() macro that takes the extra register address. Existing usages
> work just as before, without polling the clock status. Ideally all usages
> should be updated to specify the correct poll address in the future.
> 
> Signed-off-by: Stephan Gerhold <stephan.gerhold at linaro.org>
> ---
>   drivers/clk/qcom/clock-qcom.c | 15 +++++++++++++++
>   drivers/clk/qcom/clock-qcom.h |  7 +++++--
>   2 files changed, 20 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
> index 7a259db79342c31dfe85220c68c82197861ccdf6..6b46d9db744b87538b796bf729d16785bca08545 100644
> --- a/drivers/clk/qcom/clock-qcom.c
> +++ b/drivers/clk/qcom/clock-qcom.c
> @@ -83,6 +83,21 @@ int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id)
>   	}
>   
>   	setbits_le32(priv->base + priv->data->clks[id].reg, priv->data->clks[id].en_val);
> +	if (priv->data->clks[id].cbcr_reg) {
> +		unsigned int count;
> +		u32 val;
> +
> +		for (count = 0; count < 200; count++) {
> +			val = readl(priv->base + priv->data->clks[id].cbcr_reg);
> +			val &= BRANCH_CHECK_MASK;
> +			if (val == BRANCH_ON_VAL || val == BRANCH_NOC_FSM_ON_VAL)
> +				break;
> +			udelay(1);
> +		}
> +		if (WARN(count == 200, "WARNING: Clock @ %#lx [%#010x] stuck at off\n",
> +			 priv->data->clks[id].cbcr_reg, val))
> +			return -EBUSY;
> +	}
>   	return 0;
>   }
>   
> diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
> index ee0347d9d86716c09e7f57b343f12b5908f8cb92..28145061844255460e8a6868b69ffe9a7dd663b0 100644
> --- a/drivers/clk/qcom/clock-qcom.h
> +++ b/drivers/clk/qcom/clock-qcom.h
> @@ -52,13 +52,16 @@ struct freq_tbl {
>   struct gate_clk {
>   	uintptr_t reg;
>   	u32 en_val;
> +	uintptr_t cbcr_reg;
>   	const char *name;
>   };
>   
>   #ifdef DEBUG
> -#define GATE_CLK(clk, reg, val) [clk] = { reg, val, #clk }
> +#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, #clk }
> +#define BRANCH_CLK(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, #clk }

The "gate clock" naming is kinda BS here anyways, I think it's confusing 
to have "gate clock" = "enable and run" and "branch clock" = "wait for 
enable"

We should probably rename gate clock to branch clock, but let's not 
block this series on that. For now would you be fine with renaming the 
"BRANCH_CLK" macro to "GATE_CLK_POLLED"? Maybe add a comment that we 
plan to rename GATE->BRANCH and that using GATE_CLK (non-polled) is 
deprecated and the polled variant will be required for future patches.

Kind regards,>   #else
> -#define GATE_CLK(clk, reg, val) [clk] = { reg, val, NULL }
> +#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, NULL }
> +#define BRANCH_CLK(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, NULL }
>   #endif
>   
>   struct qcom_reset_map {
> 

-- 
Casey (she/they)



More information about the U-Boot mailing list