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

Balaji Selvanathan balaji.selvanathan at oss.qualcomm.com
Fri Jan 9 06:48:41 CET 2026


Hi Simon,

Thank you for your feedback. The following patch series addresses the 
same issue that we had reported:

https://lore.kernel.org/u-boot/20260108-rpmh-regulator-fixes-v1-0-d1b5b300b665@linaro.org

We can proceed with this series going forward.

Regards,
Balaji

On 1/8/2026 11:12 PM, Simon Glass wrote:
> 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