]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
soc/qcom: rpmh: correctly wait for TCS flush
authorCasey Connolly <casey.connolly@linaro.org>
Thu, 8 Jan 2026 20:28:45 +0000 (21:28 +0100)
committerCasey Connolly <casey.connolly@linaro.org>
Wed, 14 Jan 2026 15:25:09 +0000 (16:25 +0100)
Several bugs were discovered in the rpmh-rsc driver which collectively
meant we were never actually waiting for the TCS to flush, these were
likely missed because U-Boot runs single threaded and the RPMh had
typically processed the single command we sent by the time we went
to send the next one. However a future patch will implement rpmh read
support which requires us to properly wait for the RPMh command response
so we can return the value.

Fix these issues so we correctly ensure the TCS is done before
returning.

Link: https://patch.msgid.link/20260108-rpmh-regulator-fixes-v1-3-d1b5b300b665@linaro.org
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
drivers/soc/qcom/rpmh-rsc.c
drivers/soc/qcom/rpmh.c

index f51ef0b4af9c2efb5bbf21a4a4c5731e86f1007f..05fff174f8329ae0a6513f979f38a1822c65aa17 100644 (file)
@@ -284,29 +284,35 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
        u32 msgid;
        u32 cmd_msgid = CMD_MSGID_LEN | CMD_MSGID_WRITE;
        u32 cmd_enable = 0;
+       u32 cmd_complete = 0;
        struct tcs_cmd *cmd;
        int i, j;
 
+       if (msg->wait_for_compl)
+               cmd_msgid |= CMD_MSGID_RESP_REQ;
+
+       cmd_complete = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_WAIT_FOR_CMPL], tcs_id);
+
        for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) {
                cmd = &msg->cmds[i];
                cmd_enable |= BIT(j);
+               /* U-Boot: always wait for completion */
+               cmd_complete |= (!!msg->wait_for_compl) << j;
                msgid = cmd_msgid;
-               /*
-                * Additionally, if the cmd->wait is set, make the command
-                * response reqd even if the overall request was fire-n-forget.
-                */
-               msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
 
                write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
                write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
                write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
-               debug("tcs(m): %d [%s] cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d\n",
+               debug("tcs(%d): [%s] cmd_id: %d: msgid: %#x addr: %#x data: %#x complete: %#x\n",
                      tcs_id, msg->state == RPMH_ACTIVE_ONLY_STATE ? "active" : "?", j, msgid,
-                     cmd->addr, cmd->data, cmd->wait);
+                     cmd->addr, cmd->data, cmd_complete);
        }
 
        cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
        write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
+       /* U-Boot: Tell the DRV to wait for completion (?) so we can poll on DRV_STATUS */
+       /* This register applies to the entire TCS group not per command */
+       write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_WAIT_FOR_CMPL], tcs_id, cmd_complete);
 }
 
 /**
@@ -376,26 +382,22 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
 int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
 {
        struct tcs_group *tcs;
-       int tcs_id, i;
-       u32 addr;
+       int tcs_id, i = 0;
+       u32 val;
 
        tcs = get_tcs_for_msg(drv, msg);
        if (IS_ERR(tcs))
                return PTR_ERR(tcs);
 
-       /* u-boot is single-threaded, always use the first TCS as we'll never conflict */
+       /* U-Boot is single-threaded, always use the first TCS as we'll never conflict */
        tcs_id = tcs->offset;
+       if (!read_tcs_reg(drv, drv->regs[RSC_DRV_STATUS], tcs_id)) {
+               pr_err("%s: TCS %d is busy!\n", __func__, tcs_id);
+               return -EBUSY;
+       }
 
        tcs->req[tcs_id - tcs->offset] = msg;
        generic_set_bit(tcs_id, drv->tcs_in_use);
-       if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) {
-               /*
-                * Clear previously programmed WAKE commands in selected
-                * repurposed TCS to avoid triggering them. tcs->slots will be
-                * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
-                */
-               write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
-       }
 
        /*
         * These two can be done after the lock is released because:
@@ -408,10 +410,10 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
        __tcs_buffer_write(drv, tcs_id, 0, msg);
        __tcs_set_trigger(drv, tcs_id, true);
 
-       /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done */
+       /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done. */
        for (i = 0; i < USEC_PER_SEC; i++) {
-               addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, 0);
-               if (addr != msg->cmds[0].addr)
+               val = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_STATUS], tcs_id, 0);
+               if (val & CMD_STATUS_COMPL)
                        break;
                udelay(1);
        }
index 96f14a9afdf20e3736d0826a4a23649105c06558..91b90626af36ae2961371b6e2668985374a66dfb 100644 (file)
@@ -22,6 +22,7 @@
                        .state = s,                     \
                        .cmds = name.cmd,               \
                        .num_cmds = 0,                  \
+                       .wait_for_compl = true          \
                },                                      \
                .cmd = { { 0 } },                       \
                .dev = device,                          \