[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