mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-27 17:35:18 -04:00
soc: qcom: rpmh: Add support to read back resource settings
All rpmh_*() APIs so far have supported placing votes for various resource settings but the H/W also have option to read resource settings. Add new rpmh_read() API to allow clients to read back resource setting from H/W. This will be useful for clients like regulators, which currently don't have a way to know the settings applied during bootloader stage. Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Maulik Shah <maulik.shah@oss.qualcomm.com> Signed-off-by: Kamal Wadhwa <kamal.wadhwa@oss.qualcomm.com> Link: https://patch.msgid.link/20260801-b4-read-rpmh-v5-v6-1-9fcb54928523@oss.qualcomm.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
@@ -443,6 +443,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
|
||||
int i;
|
||||
unsigned long irq_status;
|
||||
const struct tcs_request *req;
|
||||
u32 reg;
|
||||
|
||||
irq_status = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);
|
||||
|
||||
@@ -453,6 +454,11 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
|
||||
|
||||
trace_rpmh_tx_done(drv, i, req);
|
||||
|
||||
if (req->is_read) {
|
||||
reg = drv->regs[RSC_DRV_CMD_RESP_DATA];
|
||||
req->cmds[0].data = read_tcs_reg(drv, reg, i);
|
||||
}
|
||||
|
||||
/* Clear AMC trigger & enable modes and
|
||||
* disable interrupt for this TCS
|
||||
*/
|
||||
@@ -493,13 +499,15 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
|
||||
const struct tcs_request *msg)
|
||||
{
|
||||
u32 msgid;
|
||||
u32 cmd_msgid = CMD_MSGID_LEN | CMD_MSGID_WRITE;
|
||||
u32 cmd_msgid = CMD_MSGID_LEN;
|
||||
u32 cmd_enable = 0;
|
||||
struct tcs_cmd *cmd;
|
||||
int i, j;
|
||||
|
||||
/* Convert all commands to RR when the request has wait_for_compl set */
|
||||
cmd_msgid |= msg->wait_for_compl ? CMD_MSGID_RESP_REQ : 0;
|
||||
if (!msg->is_read)
|
||||
cmd_msgid |= CMD_MSGID_WRITE;
|
||||
|
||||
for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) {
|
||||
cmd = &msg->cmds[i];
|
||||
@@ -513,7 +521,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
|
||||
|
||||
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);
|
||||
if (!msg->is_read)
|
||||
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
|
||||
trace_rpmh_send_msg(drv, tcs_id, msg->state, j, msgid, cmd);
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,9 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
|
||||
struct cache_req *req;
|
||||
int i;
|
||||
|
||||
if (rpm_msg->msg.is_read)
|
||||
goto send_data;
|
||||
|
||||
/* Cache the request in our store and link the payload */
|
||||
for (i = 0; i < rpm_msg->msg.num_cmds; i++) {
|
||||
req = cache_rpm_request(ctrlr, state, &rpm_msg->msg.cmds[i]);
|
||||
@@ -182,6 +185,7 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
|
||||
return PTR_ERR(req);
|
||||
}
|
||||
|
||||
send_data:
|
||||
if (state == RPMH_ACTIVE_ONLY_STATE) {
|
||||
ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
|
||||
} else {
|
||||
@@ -194,7 +198,7 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
|
||||
}
|
||||
|
||||
static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
|
||||
const struct tcs_cmd *cmd, u32 n)
|
||||
const struct tcs_cmd *cmd, u32 n, bool is_read)
|
||||
{
|
||||
if (!cmd || !n || n > MAX_RPMH_PAYLOAD)
|
||||
return -EINVAL;
|
||||
@@ -204,10 +208,45 @@ static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
|
||||
req->msg.state = state;
|
||||
req->msg.cmds = req->cmd;
|
||||
req->msg.num_cmds = n;
|
||||
req->msg.is_read = is_read;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmh_read: Read a resource value
|
||||
*
|
||||
* @dev: The device making the request
|
||||
* @cmd: The payload having address of resource to read
|
||||
*
|
||||
* Reads the value for the resource address given in tcs_cmd->addr
|
||||
* and returns the tcs_cmd->data filled with same.
|
||||
*
|
||||
* Context: May sleep. Do not call from atomic contexts.
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure
|
||||
*/
|
||||
int rpmh_read(const struct device *dev, struct tcs_cmd *cmd)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(compl);
|
||||
DEFINE_RPMH_MSG_ONSTACK(dev, RPMH_ACTIVE_ONLY_STATE, &compl, rpm_msg);
|
||||
int ret;
|
||||
|
||||
ret = __fill_rpmh_msg(&rpm_msg, RPMH_ACTIVE_ONLY_STATE, cmd, 1, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __rpmh_write(dev, RPMH_ACTIVE_ONLY_STATE, &rpm_msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS);
|
||||
cmd[0].data = rpm_msg.cmd[0].data;
|
||||
|
||||
return (ret > 0) ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpmh_read);
|
||||
|
||||
/**
|
||||
* rpmh_write_async: Write a set of RPMH commands
|
||||
*
|
||||
@@ -230,7 +269,7 @@ int rpmh_write_async(const struct device *dev, enum rpmh_state state,
|
||||
return -ENOMEM;
|
||||
rpm_msg->needs_free = true;
|
||||
|
||||
ret = __fill_rpmh_msg(rpm_msg, state, cmd, n);
|
||||
ret = __fill_rpmh_msg(rpm_msg, state, cmd, n, false);
|
||||
if (ret) {
|
||||
kfree(rpm_msg);
|
||||
return ret;
|
||||
@@ -257,7 +296,7 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
|
||||
DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg);
|
||||
int ret;
|
||||
|
||||
ret = __fill_rpmh_msg(&rpm_msg, state, cmd, n);
|
||||
ret = __fill_rpmh_msg(&rpm_msg, state, cmd, n, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -352,7 +391,7 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
|
||||
rpm_msgs = req->rpm_msgs;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
__fill_rpmh_msg(rpm_msgs + i, state, cmd, n[i]);
|
||||
__fill_rpmh_msg(rpm_msgs + i, state, cmd, n[i], false);
|
||||
cmd += n[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_RPMH)
|
||||
int rpmh_read(const struct device *dev, struct tcs_cmd *cmd);
|
||||
|
||||
int rpmh_write(const struct device *dev, enum rpmh_state state,
|
||||
const struct tcs_cmd *cmd, u32 n);
|
||||
|
||||
@@ -24,6 +26,9 @@ void rpmh_invalidate(const struct device *dev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int rpmh_read(const struct device *dev, struct tcs_cmd *cmd)
|
||||
{ return -ENODEV; }
|
||||
|
||||
static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
|
||||
const struct tcs_cmd *cmd, u32 n)
|
||||
{ return -ENODEV; }
|
||||
|
||||
@@ -51,6 +51,7 @@ struct tcs_cmd {
|
||||
* struct tcs_request: A set of tcs_cmds sent together in a TCS
|
||||
*
|
||||
* @state: state for the request.
|
||||
* @is_read: set for read only requests
|
||||
* @wait_for_compl: wait until we get a response from the h/w accelerator
|
||||
* (same as setting cmd->wait for all commands in the request)
|
||||
* @num_cmds: the number of @cmds in this request
|
||||
@@ -58,6 +59,7 @@ struct tcs_cmd {
|
||||
*/
|
||||
struct tcs_request {
|
||||
enum rpmh_state state;
|
||||
bool is_read;
|
||||
u32 wait_for_compl;
|
||||
u32 num_cmds;
|
||||
struct tcs_cmd *cmds;
|
||||
|
||||
Reference in New Issue
Block a user