diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index 81185196e5ef..95e641702f4b 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -11,7 +11,7 @@ #include #include -#define TCS_TYPE_NR 4 +#define TCS_TYPE_NR 5 #define MAX_CMDS_PER_TCS 16 #define MAX_TCS_PER_TYPE 3 #define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR) @@ -153,4 +153,9 @@ void rpmh_tx_done(const struct tcs_request *msg, int r); int rpmh_flush(struct rpmh_ctrlr *ctrlr); int _rpmh_flush(struct rpmh_ctrlr *ctrlr); +int rpmh_rsc_init_fast_path(struct rsc_drv *drv, const struct tcs_request *msg); +int rpmh_rsc_update_fast_path(struct rsc_drv *drv, + const struct tcs_request *msg, + u32 update_mask); + #endif /* __RPM_INTERNAL_H__ */ diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 63fc115b3239..bc54853e4b4b 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -876,6 +876,11 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv) max = tcs->offset + tcs->num_tcs; set = find_next_bit(drv->tcs_in_use, max, tcs->offset); + /* Check if there is pending fastpath transaction */ + if (drv->tcs[FAST_PATH_TCS].num_tcs && + !read_tcs_reg(drv, RSC_DRV_STATUS, drv->tcs[FAST_PATH_TCS].offset)) + return true; + return set < max; } @@ -985,6 +990,90 @@ int rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable) return ret; } +/** + * rpmh_rsc_init_fast_path() - Initialize the fast-path TCS contents + * @drv: The controller. + * @msg: The TCS request to populate. + * + * Return: + * * 0 - success + * * -ENODEV - no fast-path TCS available + */ +int rpmh_rsc_init_fast_path(struct rsc_drv *drv, const struct tcs_request *msg) +{ + int tcs_id; + + if (!drv->tcs[FAST_PATH_TCS].num_tcs) + return -ENODEV; + + tcs_id = drv->tcs[FAST_PATH_TCS].offset; + + /* We won't use the AMC IRQ to confirm if the TCS is free */ + enable_tcs_irq(drv, tcs_id, false); + + __tcs_buffer_write(drv, tcs_id, 0, msg); + + return 0; +} + +/** + * rpmh_rsc_update_fast_path() - Update the fast-path TCS data and trigger + * @drv: The controller. + * @msg: The TCS request data to be updated. + * @mask: The update mask for elements in @msg to be sent + * + * NOTE: Caller should ensure serialization before making this call. + * Return: + * * 0 - success + * * -ENODEV - no fast-path TCS available + */ +int rpmh_rsc_update_fast_path(struct rsc_drv *drv, + const struct tcs_request *msg, + u32 mask) +{ + int i; + u32 sts; + int tcs_id; + struct tcs_cmd *cmd; + int retry = 5; + + if (!drv->tcs[FAST_PATH_TCS].num_tcs) + return -ENODEV; + + tcs_id = drv->tcs[FAST_PATH_TCS].offset; + + /* Ensure the TCS is free before writing to the TCS */ + do { + sts = read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id); + if (!sts) { + retry--; + /* Report and bail, if it took too many attempts */ + if (!retry) { + pr_err("Fast-path TCS is too busy\n"); + return -EBUSY; + } + udelay(1); + } + } while (!sts); + + /* + * We only update the data, everything else remains the same. + * The number of commands and the addresses do not change with + * updates. + */ + for (i = 0; i < msg->num_cmds; i++) { + if (!(mask & BIT(i))) + continue; + cmd = &msg->cmds[i]; + write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, i, cmd->data); + } + + /* Trigger the TCS to send the request */ + __tcs_set_trigger(drv, tcs_id, true); + + return 0; +} + static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv, void __iomem *base) {