Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: qcom: rpmh: add RPMH helper functions

Sending RPMH requests and waiting for response from the controller
through a callback is common functionality across all platform drivers.
To simplify drivers, add a library functions to create RPMH client and
send resource state requests.

rpmh_write() is a synchronous blocking call that can be used to send
active state requests.

Signed-off-by: Lina Iyer <ilina@codeaurora.org>
Signed-off-by: Raju P.L.S.S.S.N <rplsssn@codeaurora.org>
Signed-off-by: Andy Gross <andy.gross@linaro.org>

authored by

Lina Iyer and committed by
Andy Gross
c1038456 fc087fe5

+179 -3
+3 -1
drivers/soc/qcom/Makefile
··· 9 9 obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o 10 10 qmi_helpers-y += qmi_encdec.o qmi_interface.o 11 11 obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o 12 - obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o 12 + obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o 13 + qcom_rpmh-y += rpmh-rsc.o 14 + qcom_rpmh-y += rpmh.o 13 15 obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o 14 16 obj-$(CONFIG_QCOM_SMEM) += smem.o 15 17 obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
+30 -1
drivers/soc/qcom/rpmh-internal.h
··· 42 42 }; 43 43 44 44 /** 45 + * struct rpmh_request: the message to be sent to rpmh-rsc 46 + * 47 + * @msg: the request 48 + * @cmd: the payload that will be part of the @msg 49 + * @completion: triggered when request is done 50 + * @dev: the device making the request 51 + * @err: err return from the controller 52 + */ 53 + struct rpmh_request { 54 + struct tcs_request msg; 55 + struct tcs_cmd cmd[MAX_RPMH_PAYLOAD]; 56 + struct completion *completion; 57 + const struct device *dev; 58 + int err; 59 + }; 60 + 61 + /** 62 + * struct rpmh_ctrlr: our representation of the controller 63 + * 64 + * @drv: the controller instance 65 + */ 66 + struct rpmh_ctrlr { 67 + struct rsc_drv *drv; 68 + }; 69 + 70 + /** 45 71 * struct rsc_drv: the Direct Resource Voter (DRV) of the 46 72 * Resource State Coordinator controller (RSC) 47 73 * ··· 78 52 * @tcs: TCS groups 79 53 * @tcs_in_use: s/w state of the TCS 80 54 * @lock: synchronize state of the controller 55 + * @client: handle to the DRV's client. 81 56 */ 82 57 struct rsc_drv { 83 58 const char *name; ··· 88 61 struct tcs_group tcs[TCS_TYPE_NR]; 89 62 DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR); 90 63 spinlock_t lock; 64 + struct rpmh_ctrlr client; 91 65 }; 92 66 93 - 94 67 int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg); 68 + 69 + void rpmh_tx_done(const struct tcs_request *msg, int r); 95 70 96 71 #endif /* __RPM_INTERNAL_H__ */
+5 -1
drivers/soc/qcom/rpmh-rsc.c
··· 138 138 static irqreturn_t tcs_tx_done(int irq, void *p) 139 139 { 140 140 struct rsc_drv *drv = p; 141 - int i, j, err; 141 + int i, j, err = 0; 142 142 unsigned long irq_status; 143 143 const struct tcs_request *req; 144 144 struct tcs_cmd *cmd; ··· 175 175 spin_lock(&drv->lock); 176 176 clear_bit(i, drv->tcs_in_use); 177 177 spin_unlock(&drv->lock); 178 + if (req) 179 + rpmh_tx_done(req, err); 178 180 } 179 181 180 182 return IRQ_HANDLED; ··· 468 466 469 467 /* Enable the active TCS to send requests immediately */ 470 468 write_tcs_reg(drv, RSC_DRV_IRQ_ENABLE, 0, drv->tcs[ACTIVE_TCS].mask); 469 + 470 + dev_set_drvdata(&pdev->dev, drv); 471 471 472 472 return devm_of_platform_populate(&pdev->dev); 473 473 }
+116
drivers/soc/qcom/rpmh.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #include <linux/atomic.h> 7 + #include <linux/bug.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/jiffies.h> 10 + #include <linux/kernel.h> 11 + #include <linux/module.h> 12 + #include <linux/of.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/slab.h> 15 + #include <linux/types.h> 16 + #include <linux/wait.h> 17 + 18 + #include <soc/qcom/rpmh.h> 19 + 20 + #include "rpmh-internal.h" 21 + 22 + #define RPMH_TIMEOUT_MS msecs_to_jiffies(10000) 23 + 24 + #define DEFINE_RPMH_MSG_ONSTACK(dev, s, q, name) \ 25 + struct rpmh_request name = { \ 26 + .msg = { \ 27 + .state = s, \ 28 + .cmds = name.cmd, \ 29 + .num_cmds = 0, \ 30 + .wait_for_compl = true, \ 31 + }, \ 32 + .cmd = { { 0 } }, \ 33 + .completion = q, \ 34 + .dev = dev, \ 35 + } 36 + 37 + #define ctrlr_to_drv(ctrlr) container_of(ctrlr, struct rsc_drv, client) 38 + 39 + static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev) 40 + { 41 + struct rsc_drv *drv = dev_get_drvdata(dev->parent); 42 + 43 + return &drv->client; 44 + } 45 + 46 + void rpmh_tx_done(const struct tcs_request *msg, int r) 47 + { 48 + struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request, 49 + msg); 50 + struct completion *compl = rpm_msg->completion; 51 + 52 + rpm_msg->err = r; 53 + 54 + if (r) 55 + dev_err(rpm_msg->dev, "RPMH TX fail in msg addr=%#x, err=%d\n", 56 + rpm_msg->msg.cmds[0].addr, r); 57 + 58 + /* Signal the blocking thread we are done */ 59 + if (compl) 60 + complete(compl); 61 + } 62 + 63 + /** 64 + * __rpmh_write: send the RPMH request 65 + * 66 + * @dev: The device making the request 67 + * @state: Active/Sleep request type 68 + * @rpm_msg: The data that needs to be sent (cmds). 69 + */ 70 + static int __rpmh_write(const struct device *dev, enum rpmh_state state, 71 + struct rpmh_request *rpm_msg) 72 + { 73 + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); 74 + 75 + rpm_msg->msg.state = state; 76 + 77 + if (state != RPMH_ACTIVE_ONLY_STATE) 78 + return -EINVAL; 79 + 80 + WARN_ON(irqs_disabled()); 81 + 82 + return rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg); 83 + } 84 + 85 + /** 86 + * rpmh_write: Write a set of RPMH commands and block until response 87 + * 88 + * @rc: The RPMH handle got from rpmh_get_client 89 + * @state: Active/sleep set 90 + * @cmd: The payload data 91 + * @n: The number of elements in @cmd 92 + * 93 + * May sleep. Do not call from atomic contexts. 94 + */ 95 + int rpmh_write(const struct device *dev, enum rpmh_state state, 96 + const struct tcs_cmd *cmd, u32 n) 97 + { 98 + DECLARE_COMPLETION_ONSTACK(compl); 99 + DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg); 100 + int ret; 101 + 102 + if (!cmd || !n || n > MAX_RPMH_PAYLOAD) 103 + return -EINVAL; 104 + 105 + memcpy(rpm_msg.cmd, cmd, n * sizeof(*cmd)); 106 + rpm_msg.msg.num_cmds = n; 107 + 108 + ret = __rpmh_write(dev, state, &rpm_msg); 109 + if (ret) 110 + return ret; 111 + 112 + ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS); 113 + WARN_ON(!ret); 114 + return (ret > 0) ? 0 : -ETIMEDOUT; 115 + } 116 + EXPORT_SYMBOL(rpmh_write);
+25
include/soc/qcom/rpmh.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #ifndef __SOC_QCOM_RPMH_H__ 7 + #define __SOC_QCOM_RPMH_H__ 8 + 9 + #include <soc/qcom/tcs.h> 10 + #include <linux/platform_device.h> 11 + 12 + 13 + #if IS_ENABLED(CONFIG_QCOM_RPMH) 14 + int rpmh_write(const struct device *dev, enum rpmh_state state, 15 + const struct tcs_cmd *cmd, u32 n); 16 + 17 + #else 18 + 19 + static inline int rpmh_write(const struct device *dev, enum rpmh_state state, 20 + const struct tcs_cmd *cmd, u32 n) 21 + { return -ENODEV; } 22 + 23 + #endif /* CONFIG_QCOM_RPMH */ 24 + 25 + #endif /* __SOC_QCOM_RPMH_H__ */