[PATCH v1 1/2] soc: qcom: rpmh-rsc: Clear TCS state before kernel boot

Simon Glass sjg at chromium.org
Thu Jan 8 18:42:01 CET 2026


Hi Balaji,

On Thu, 8 Jan 2026 at 03:17, Balaji Selvanathan
<balaji.selvanathan at oss.qualcomm.com> wrote:
>
> Add cleanup mechanism to clear RPMH TCS hardware state before
> booting the kernel. Without this cleanup, leftover U-Boot TCS
> configurations cause timeout errors during kernel RPMH driver
> initialization.
>
> The cleanup clears CMD_STATUS, CMD_WAIT_FOR_CMPL, CMD_ENABLE,
> CONTROL, and IRQ_STATUS registers for all TCS.
>
> Signed-off-by: Aswin Murugan <aswin.murugan at oss.qualcomm.com>
> Signed-off-by: Balaji Selvanathan <balaji.selvanathan at oss.qualcomm.com>
> ---
>  drivers/soc/qcom/rpmh-rsc.c | 101 ++++++++++++++++++++++++++++++++++++
>  include/soc/qcom/rpmh.h     |   9 ++++
>  2 files changed, 110 insertions(+)
>
> diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
> index aee9e55194e..772be401f0d 100644
> --- a/drivers/soc/qcom/rpmh-rsc.c
> +++ b/drivers/soc/qcom/rpmh-rsc.c
> @@ -471,6 +471,106 @@ static int rpmh_probe_tcs_config(struct udevice *dev, struct rsc_drv *drv)
>         return 0;
>  }
>
> +/**
> + * rpmh_rsc_clear_tcs() - Clear TCS state before kernel handoff
> + * @drv: The RSC controller
> + *
> + * Clears all TCS hardware state to ensure kernel starts with clean state.
> + * This prevents timeout errors during kernel RPMH initialization by clearing:
> + * - CMD_STATUS: Leftover ISSUED/COMPLETED flags
> + * - CMD_WAIT_FOR_CMPL: Completion wait configuration
> + * - CMD_ENABLE: Command slot enables
> + * - CONTROL: AMC mode bits
> + * - IRQ_STATUS: Pending interrupts
> + */
> +static void rpmh_rsc_clear_tcs(struct rsc_drv *drv)
> +{
> +       int i, j, ncpt, pending_cmds = 0;
> +       u32 status, irq_status;
> +
> +       ncpt = drv->tcs[ACTIVE_TCS].ncpt;
> +
> +       for (i = 0; i < drv->num_tcs; i++) {
> +               for (j = 0; j < ncpt; j++) {
> +                       status = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_STATUS], i, j);
> +                       if (status)
> +                               pending_cmds++;
> +               }
> +
> +               /* Clear completion wait, command enable, and control registers */
> +               write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_WAIT_FOR_CMPL], i, 0);
> +               write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
> +               write_tcs_reg(drv, drv->regs[RSC_DRV_CONTROL], i, 0);
> +       }
> +
> +       /* Clear any pending IRQ status */
> +       irq_status = readl(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);
> +       if (irq_status)
> +               writel(irq_status, drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]);
> +
> +       log_debug("RPMH: Cleared %d TCS for %s (pending: %d cmds, IRQ: 0x%x)\n",
> +                 drv->num_tcs, drv->name, pending_cmds, irq_status);
> +}
> +
> +/**
> + * rpmh_rsc_cleanup_all() - Public function to cleanup all RPMH controllers
> + *
> + * This function should be called before booting the kernel to ensure all
> + * RPMH controllers have clean TCS state. Can be called from board_quiesce_devices()
> + * or directly before kernel boot.
> + */
> +void rpmh_rsc_cleanup_all(void)
> +{
> +       struct udevice *dev;
> +       struct uclass *uc;
> +       int ret, count = 0;
> +
> +       ret = uclass_get(UCLASS_MISC, &uc);
> +       if (ret) {
> +               log_err("RPMH: Failed to get MISC uclass: %d\n", ret);
> +               return;
> +       }
> +
> +       uclass_foreach_dev(dev, uc) {
> +               if (device_is_compatible(dev, "qcom,rpmh-rsc")) {
> +                       struct rsc_drv *drv = dev_get_priv(dev);
> +
> +                       if (drv && drv->num_tcs > 0) {
> +                               rpmh_rsc_clear_tcs(drv);
> +                               count++;
> +                       }
> +               }
> +       }
> +
> +       if (count > 0)
> +               log_debug("RPMH: Cleaned up %d controller(s)\n", count);
> +       else
> +               log_warning("RPMH: No controllers found to clean up\n");
> +}
> +
> +/**
> + * rpmh_rsc_remove() - Cleanup before handing off to kernel
> + * @dev: The device
> + *
> + * Called before booting kernel to ensure clean TCS state. This prevents
> + * kernel RPMH driver from encountering busy/configured TCS that could
> + * cause timeout errors during initialization.
> + *
> + * Return: 0 on success
> + */
> +static int rpmh_rsc_remove(struct udevice *dev)
> +{
> +       struct rsc_drv *drv = dev_get_priv(dev);
> +
> +       if (!drv)
> +               return 0;
> +
> +       /* Clear all TCS configurations to provide clean state for kernel */
> +       rpmh_rsc_clear_tcs(drv);
> +
> +       return 0;
> +}
> +
>  static int rpmh_rsc_probe(struct udevice *dev)
>  {
>         ofnode dn = dev_ofnode(dev);
> @@ -539,6 +639,7 @@ U_BOOT_DRIVER(qcom_rpmh_rsc) = {
>         .id             = UCLASS_MISC,
>         .priv_auto      = sizeof(struct rsc_drv),
>         .probe          = rpmh_rsc_probe,
> +       .remove         = rpmh_rsc_remove,
>         .of_match       = qcom_rpmh_ids,
>         /* rpmh is under CLUSTER_PD which we don't support, so skip trying to enable PDs */
>         .flags          = DM_FLAG_DEFAULT_PD_CTRL_OFF,

add DM_REMOVE_OS_PREPARE in there too so it will cleanup

> diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
> index 3421fbf1ee3..da3b1517392 100644
> --- a/include/soc/qcom/rpmh.h
> +++ b/include/soc/qcom/rpmh.h
> @@ -25,4 +25,13 @@ static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
>  /* u-boot: no multithreading */
>  #define rpmh_write_async(dev, state, cmd, n) rpmh_write(dev, state, cmd, n)
>
> +/**
> + * rpmh_rsc_cleanup_all() - Cleanup all RPMH controllers before kernel boot
> + *
> + * This function clears TCS (Trigger Command Set) hardware state for all
> + * RPMH controllers to ensure the kernel starts with clean state. Should
> + * be called from board_quiesce_devices() before booting the kernel.
> + */
> +void rpmh_rsc_cleanup_all(void);

I'm not sure who calls this, but each device will be removed before
booting if you use the DM_REMOVE_OS_PREPARE flag

> +
>  #endif /* __SOC_QCOM_RPMH_H__ */
> --
> 2.34.1
>

Regards,
Simon


More information about the U-Boot mailing list