diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index 3b650e30eefb..c186e8966fc1 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -69,12 +69,14 @@ struct rpmh_request { * @cache_lock: synchronize access to the cache data * @dirty: was the cache updated since flush * @batch_cache: Cache sleep and wake requests sent as batch + * @in_solver_mode: Controller is busy in solver mode */ struct rpmh_ctrlr { struct list_head cache; spinlock_t cache_lock; bool dirty; struct list_head batch_cache; + bool in_solver_mode; }; /** @@ -84,6 +86,7 @@ struct rpmh_ctrlr { * @name: controller identifier * @tcs_base: start address of the TCS registers in this controller * @id: instance id in the controller (Direct Resource Voter) + * @in_solver_mode: Controller is in solver mode * @num_tcs: number of TCSes in this DRV * @tcs: TCS groups * @tcs_in_use: s/w state of the TCS @@ -94,6 +97,7 @@ struct rsc_drv { const char *name; void __iomem *tcs_base; int id; + bool in_solver_mode; int num_tcs; struct tcs_group tcs[TCS_TYPE_NR]; DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR); @@ -105,6 +109,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg); int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg); int rpmh_rsc_invalidate(struct rsc_drv *drv); +void rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable); void rpmh_tx_done(const struct tcs_request *msg, int r); diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index a5c527935df7..24df5c3ec4ac 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -386,6 +386,11 @@ static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg) spin_lock_irqsave(&tcs->lock, flags); spin_lock(&drv->lock); + if (msg->state == RPMH_ACTIVE_ONLY_STATE && drv->in_solver_mode) { + ret = -EINVAL; + spin_unlock(&drv->lock); + goto done_write; + } /* * The h/w does not like if we send a request to the same address, * when one is already in-flight or being processed. @@ -552,6 +557,30 @@ int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg) return tcs_ctrl_write(drv, msg); } +/** + * rpmh_rsc_mode_solver_set: Enable/disable solver mode + * + * @drv: The controller + * + * enable: boolean state to be set - true/false + */ +void rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable) +{ + int m; + struct tcs_group *tcs = get_tcs_of_type(drv, ACTIVE_TCS); + +again: + spin_lock(&drv->lock); + for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) { + if (!tcs_is_free(drv, m)) { + spin_unlock(&drv->lock); + goto again; + } + } + drv->in_solver_mode = enable; + spin_unlock(&drv->lock); +} + static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv) { @@ -682,6 +711,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev) return ret; spin_lock_init(&drv->lock); + drv->in_solver_mode = false; bitmap_zero(drv->tcs_in_use, MAX_TCS_NR); irq = platform_get_irq(pdev, drv->id); diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index 6f78d6f0d627..4cace8c642d8 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -73,6 +73,44 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev) return &drv->client; } +static int check_ctrlr_state(struct rpmh_ctrlr *ctrlr, enum rpmh_state state) +{ + int ret = 0; + unsigned long flags; + + /* Do not allow setting active votes when in solver mode */ + spin_lock_irqsave(&ctrlr->cache_lock, flags); + if (ctrlr->in_solver_mode && state == RPMH_ACTIVE_ONLY_STATE) + ret = -EBUSY; + spin_unlock_irqrestore(&ctrlr->cache_lock, flags); + + return ret; +} + +/** + * rpmh_mode_solver_set: Indicate that the RSC controller hardware has + * been configured to be in solver mode + * + * @dev: the device making the request + * @enable: Boolean value indicating if the controller is in solver mode. + * + * When solver mode is enabled, passthru API will not be able to send wake + * votes, just awake and active votes. + */ +int rpmh_mode_solver_set(const struct device *dev, bool enable) +{ + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); + unsigned long flags; + + spin_lock_irqsave(&ctrlr->cache_lock, flags); + rpmh_rsc_mode_solver_set(ctrlr_to_drv(ctrlr), enable); + ctrlr->in_solver_mode = enable; + spin_unlock_irqrestore(&ctrlr->cache_lock, flags); + + return 0; +} +EXPORT_SYMBOL(rpmh_mode_solver_set); + void rpmh_tx_done(const struct tcs_request *msg, int r) { struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request, @@ -229,8 +267,13 @@ int rpmh_write_async(const struct device *dev, enum rpmh_state state, const struct tcs_cmd *cmd, u32 n) { struct rpmh_request *rpm_msg; + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); int ret; + ret = check_ctrlr_state(ctrlr, state); + if (ret) + return ret; + rpm_msg = kzalloc(sizeof(*rpm_msg), GFP_ATOMIC); if (!rpm_msg) return -ENOMEM; @@ -261,11 +304,16 @@ int rpmh_write(const struct device *dev, enum rpmh_state state, { DECLARE_COMPLETION_ONSTACK(compl); DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg); + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); int ret; if (!cmd || !n || n > MAX_RPMH_PAYLOAD) return -EINVAL; + ret = check_ctrlr_state(ctrlr, state); + if (ret) + return ret; + memcpy(rpm_msg.cmd, cmd, n * sizeof(*cmd)); rpm_msg.msg.num_cmds = n; @@ -356,6 +404,10 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, if (!cmd || !n) return -EINVAL; + ret = check_ctrlr_state(ctrlr, state); + if (ret) + return ret; + while (n[count] > 0) count++; if (!count) diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h index ec448b745904..35233b95095d 100644 --- a/include/soc/qcom/rpmh.h +++ b/include/soc/qcom/rpmh.h @@ -22,6 +22,8 @@ int rpmh_flush(const struct device *dev); int rpmh_invalidate(const struct device *dev); +int rpmh_mode_solver_set(const struct device *dev, bool enable); + #else static inline int rpmh_write(const struct device *dev, enum rpmh_state state, @@ -44,6 +46,9 @@ static inline int rpmh_flush(const struct device *dev) static inline int rpmh_invalidate(const struct device *dev) { return -ENODEV; } +static inline int rpmh_mode_solver_set(const struct device *dev, bool enable) +{ return -ENODEV; } + #endif /* CONFIG_QCOM_RPMH */ #endif /* __SOC_QCOM_RPMH_H__ */