GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / firmware / arm_scmi / smc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * System Control and Management Interface (SCMI) Message SMC/HVC
4  * Transport driver
5  *
6  * Copyright 2020 NXP
7  */
8
9 #include <linux/arm-smccc.h>
10 #include <linux/atomic.h>
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/interrupt.h>
14 #include <linux/mutex.h>
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/of_irq.h>
18 #include <linux/processor.h>
19 #include <linux/slab.h>
20
21 #include "common.h"
22
23 /**
24  * struct scmi_smc - Structure representing a SCMI smc transport
25  *
26  * @cinfo: SCMI channel info
27  * @shmem: Transmit/Receive shared memory area
28  * @shmem_lock: Lock to protect access to Tx/Rx shared memory area.
29  *              Used when NOT operating in atomic mode.
30  * @inflight: Atomic flag to protect access to Tx/Rx shared memory area.
31  *            Used when operating in atomic mode.
32  * @func_id: smc/hvc call function id
33  */
34
35 struct scmi_smc {
36         struct scmi_chan_info *cinfo;
37         struct scmi_shared_mem __iomem *shmem;
38         /* Protect access to shmem area */
39         struct mutex shmem_lock;
40 #define INFLIGHT_NONE   MSG_TOKEN_MAX
41         atomic_t inflight;
42         u32 func_id;
43 };
44
45 static irqreturn_t smc_msg_done_isr(int irq, void *data)
46 {
47         struct scmi_smc *scmi_info = data;
48
49         scmi_rx_callback(scmi_info->cinfo,
50                          shmem_read_header(scmi_info->shmem), NULL);
51
52         return IRQ_HANDLED;
53 }
54
55 static bool smc_chan_available(struct device *dev, int idx)
56 {
57         struct device_node *np = of_parse_phandle(dev->of_node, "shmem", 0);
58         if (!np)
59                 return false;
60
61         of_node_put(np);
62         return true;
63 }
64
65 static inline void smc_channel_lock_init(struct scmi_smc *scmi_info)
66 {
67         if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
68                 atomic_set(&scmi_info->inflight, INFLIGHT_NONE);
69         else
70                 mutex_init(&scmi_info->shmem_lock);
71 }
72
73 static bool smc_xfer_inflight(struct scmi_xfer *xfer, atomic_t *inflight)
74 {
75         int ret;
76
77         ret = atomic_cmpxchg(inflight, INFLIGHT_NONE, xfer->hdr.seq);
78
79         return ret == INFLIGHT_NONE;
80 }
81
82 static inline void
83 smc_channel_lock_acquire(struct scmi_smc *scmi_info,
84                          struct scmi_xfer *xfer __maybe_unused)
85 {
86         if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
87                 spin_until_cond(smc_xfer_inflight(xfer, &scmi_info->inflight));
88         else
89                 mutex_lock(&scmi_info->shmem_lock);
90 }
91
92 static inline void smc_channel_lock_release(struct scmi_smc *scmi_info)
93 {
94         if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
95                 atomic_set(&scmi_info->inflight, INFLIGHT_NONE);
96         else
97                 mutex_unlock(&scmi_info->shmem_lock);
98 }
99
100 static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
101                           bool tx)
102 {
103         struct device *cdev = cinfo->dev;
104         struct scmi_smc *scmi_info;
105         resource_size_t size;
106         struct resource res;
107         struct device_node *np;
108         u32 func_id;
109         int ret, irq;
110
111         if (!tx)
112                 return -ENODEV;
113
114         scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL);
115         if (!scmi_info)
116                 return -ENOMEM;
117
118         np = of_parse_phandle(cdev->of_node, "shmem", 0);
119         if (!of_device_is_compatible(np, "arm,scmi-shmem"))
120                 return -ENXIO;
121
122         ret = of_address_to_resource(np, 0, &res);
123         of_node_put(np);
124         if (ret) {
125                 dev_err(cdev, "failed to get SCMI Tx shared memory\n");
126                 return ret;
127         }
128
129         size = resource_size(&res);
130         scmi_info->shmem = devm_ioremap(dev, res.start, size);
131         if (!scmi_info->shmem) {
132                 dev_err(dev, "failed to ioremap SCMI Tx shared memory\n");
133                 return -EADDRNOTAVAIL;
134         }
135
136         ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
137         if (ret < 0)
138                 return ret;
139
140         /*
141          * If there is an interrupt named "a2p", then the service and
142          * completion of a message is signaled by an interrupt rather than by
143          * the return of the SMC call.
144          */
145         irq = of_irq_get_byname(cdev->of_node, "a2p");
146         if (irq > 0) {
147                 ret = devm_request_irq(dev, irq, smc_msg_done_isr,
148                                        IRQF_NO_SUSPEND,
149                                        dev_name(dev), scmi_info);
150                 if (ret) {
151                         dev_err(dev, "failed to setup SCMI smc irq\n");
152                         return ret;
153                 }
154         } else {
155                 cinfo->no_completion_irq = true;
156         }
157
158         scmi_info->func_id = func_id;
159         scmi_info->cinfo = cinfo;
160         smc_channel_lock_init(scmi_info);
161         cinfo->transport_info = scmi_info;
162
163         return 0;
164 }
165
166 static int smc_chan_free(int id, void *p, void *data)
167 {
168         struct scmi_chan_info *cinfo = p;
169         struct scmi_smc *scmi_info = cinfo->transport_info;
170
171         cinfo->transport_info = NULL;
172         scmi_info->cinfo = NULL;
173
174         scmi_free_channel(cinfo, data, id);
175
176         return 0;
177 }
178
179 static int smc_send_message(struct scmi_chan_info *cinfo,
180                             struct scmi_xfer *xfer)
181 {
182         struct scmi_smc *scmi_info = cinfo->transport_info;
183         struct arm_smccc_res res;
184
185         /*
186          * Channel will be released only once response has been
187          * surely fully retrieved, so after .mark_txdone()
188          */
189         smc_channel_lock_acquire(scmi_info, xfer);
190
191         shmem_tx_prepare(scmi_info->shmem, xfer);
192
193         arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
194
195         /* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
196         if (res.a0) {
197                 smc_channel_lock_release(scmi_info);
198                 return -EOPNOTSUPP;
199         }
200
201         return 0;
202 }
203
204 static void smc_fetch_response(struct scmi_chan_info *cinfo,
205                                struct scmi_xfer *xfer)
206 {
207         struct scmi_smc *scmi_info = cinfo->transport_info;
208
209         shmem_fetch_response(scmi_info->shmem, xfer);
210 }
211
212 static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret,
213                             struct scmi_xfer *__unused)
214 {
215         struct scmi_smc *scmi_info = cinfo->transport_info;
216
217         smc_channel_lock_release(scmi_info);
218 }
219
220 static const struct scmi_transport_ops scmi_smc_ops = {
221         .chan_available = smc_chan_available,
222         .chan_setup = smc_chan_setup,
223         .chan_free = smc_chan_free,
224         .send_message = smc_send_message,
225         .mark_txdone = smc_mark_txdone,
226         .fetch_response = smc_fetch_response,
227 };
228
229 const struct scmi_desc scmi_smc_desc = {
230         .ops = &scmi_smc_ops,
231         .max_rx_timeout_ms = 30,
232         .max_msg = 20,
233         .max_msg_size = 128,
234         /*
235          * Setting .sync_cmds_atomic_replies to true for SMC assumes that,
236          * once the SMC instruction has completed successfully, the issued
237          * SCMI command would have been already fully processed by the SCMI
238          * platform firmware and so any possible response value expected
239          * for the issued command will be immmediately ready to be fetched
240          * from the shared memory area.
241          */
242         .sync_cmds_completed_on_ret = true,
243         .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE),
244 };