Hi Balaji, On Thu, 8 Jan 2026 at 03:17, Balaji Selvanathan <[email protected]> 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 <[email protected]> > Signed-off-by: Balaji Selvanathan <[email protected]> > --- > 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

