History

Merge tag 'scmi-updates-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/drivers

ARM SCMI/SCPI updates for v5.8 1. Addition of ARM SMC/HVC as SCMI transport type with required abstraction already in place 2. Initial infrastructure support to add SCMI notifications from platform to agents 3. Miscellaneous fix adding header include guards * tag 'scmi-updates-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_scmi: fix psci dependency firmware: arm_scmi: Fix return error code in smc_send_message firmware: arm_scmi: Fix handling of unexpected delayed responses firmware: arm_scmi: Clear channel for delayed responses firmware: arm_scmi: Clear channel on reception of unexpected responses firmware: arm_scmi: Rename .clear_notification() transport_ops firmware: arm_scmi: Add support for notifications message processing firmware: arm_scmi: Add notifications support in transport layer firmware: arm_scmi: Update protocol commands and notification list firmware: arm_scmi: Add receive buffer support for notifications firmware: arm_scpi: Add include guard to linux/scpi_protocol.h firmware: arm_scmi: Add include guard to linux/scmi_protocol.h firmware: arm_scmi: Drop checking for shmem property in parent node firmware: arm_scmi: Check shmem property for channel availablity firmware: arm_scmi: Drop empty stub for smc_mark_txdone firmware: arm_scmi: Make mutex channel specific firmware: arm_scmi: Add smc/hvc transport dt-bindings: arm: Add smc/hvc transport for SCMI

Arnd Bergmann committed 6 years ago

Commit a7afae52 parents 0e698df 5a897e313 files · +340 −30Browse files

Unified · Split

13 files
  1. Documentation/devicetree/bindings/arm/arm,scmi.txt +2 −1
  2. drivers/firmware/arm_scmi/Makefile +3 −1
  3. drivers/firmware/arm_scmi/base.c +7 −0
  4. drivers/firmware/arm_scmi/common.h +11 −0
  5. drivers/firmware/arm_scmi/driver.c +105 −28
  6. drivers/firmware/arm_scmi/mailbox.c +17 −0
  7. drivers/firmware/arm_scmi/perf.c +5 −0
  8. drivers/firmware/arm_scmi/power.c +6 −0
  9. drivers/firmware/arm_scmi/sensors.c +4 −0
  10. drivers/firmware/arm_scmi/shmem.c +15 −0
  11. drivers/firmware/arm_scmi/smc.c +153 −0
  12. include/linux/scmi_protocol.h +6 −0
  13. include/linux/scpi_protocol.h +6 −0
Documentation/devicetree/bindings/arm/arm,scmi.txt+2−1
@@ -14,7 +14,7 @@ Required properties: · 13 unmodified lines
14 14
15The scmi node with the following properties shall be under the /firmware/ node.15The scmi node with the following properties shall be under the /firmware/ node.
16 16
17- compatible : shall be "arm,scmi"17- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports
18- mboxes: List of phandle and mailbox channel specifiers. It should contain18- mboxes: List of phandle and mailbox channel specifiers. It should contain
19 exactly one or two mailboxes, one for transmitting messages("tx")19 exactly one or two mailboxes, one for transmitting messages("tx")
20 and another optional for receiving the notifications("rx") if20 and another optional for receiving the notifications("rx") if
@@ -25,6 +25,7 @@ The scmi node with the following properties shall be under the /firmware/ node. · 4 unmodified lines
25 protocol identifier for a given sub-node.25 protocol identifier for a given sub-node.
26- #size-cells : should be '0' as 'reg' property doesn't have any size26- #size-cells : should be '0' as 'reg' property doesn't have any size
27 associated with it.27 associated with it.
28- arm,smc-id : SMC id required when using smc or hvc transports
28 29
29Optional properties:30Optional properties:
30 31
drivers/firmware/arm_scmi/Makefile+3−1
@@ -2,6 +2,8 @@ · 1 unmodified line
2obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o2obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
3scmi-bus-y = bus.o3scmi-bus-y = bus.o
4scmi-driver-y = driver.o4scmi-driver-y = driver.o
5scmi-transport-y = mailbox.o shmem.o5scmi-transport-y = shmem.o
6scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
7scmi-transport-$(CONFIG_ARM_PSCI_FW) += smc.o
6scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o8scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
7obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o9obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
drivers/firmware/arm_scmi/base.c+7−0
@@ -14,6 +14,13 @@ enum scmi_base_protocol_cmd { · 13 unmodified lines
14 BASE_DISCOVER_LIST_PROTOCOLS = 0x6,14 BASE_DISCOVER_LIST_PROTOCOLS = 0x6,
15 BASE_DISCOVER_AGENT = 0x7,15 BASE_DISCOVER_AGENT = 0x7,
16 BASE_NOTIFY_ERRORS = 0x8,16 BASE_NOTIFY_ERRORS = 0x8,
17 BASE_SET_DEVICE_PERMISSIONS = 0x9,
18 BASE_SET_PROTOCOL_PERMISSIONS = 0xa,
19 BASE_RESET_AGENT_CONFIGURATION = 0xb,
20};
21
22enum scmi_base_protocol_notify {
23 BASE_ERROR_EVENT = 0x0,
17};24};
18 25
19struct scmi_msg_resp_base_attributes {26struct scmi_msg_resp_base_attributes {
drivers/firmware/arm_scmi/common.h+11−0
@@ -178,6 +178,8 @@ struct scmi_chan_info { · 177 unmodified lines
178 * @send_message: Callback to send a message178 * @send_message: Callback to send a message
179 * @mark_txdone: Callback to mark tx as done179 * @mark_txdone: Callback to mark tx as done
180 * @fetch_response: Callback to fetch response180 * @fetch_response: Callback to fetch response
181 * @fetch_notification: Callback to fetch notification
182 * @clear_channel: Callback to clear a channel
181 * @poll_done: Callback to poll transfer status183 * @poll_done: Callback to poll transfer status
182 */184 */
183struct scmi_transport_ops {185struct scmi_transport_ops {
@@ -190,6 +192,9 @@ struct scmi_transport_ops { · 6 unmodified lines
190 void (*mark_txdone)(struct scmi_chan_info *cinfo, int ret);192 void (*mark_txdone)(struct scmi_chan_info *cinfo, int ret);
191 void (*fetch_response)(struct scmi_chan_info *cinfo,193 void (*fetch_response)(struct scmi_chan_info *cinfo,
192 struct scmi_xfer *xfer);194 struct scmi_xfer *xfer);
195 void (*fetch_notification)(struct scmi_chan_info *cinfo,
196 size_t max_len, struct scmi_xfer *xfer);
197 void (*clear_channel)(struct scmi_chan_info *cinfo);
193 bool (*poll_done)(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer);198 bool (*poll_done)(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer);
194};199};
195 200
@@ -210,6 +215,9 @@ struct scmi_desc { · 14 unmodified lines
210};215};
211 216
212extern const struct scmi_desc scmi_mailbox_desc;217extern const struct scmi_desc scmi_mailbox_desc;
218#ifdef CONFIG_HAVE_ARM_SMCCC
219extern const struct scmi_desc scmi_smc_desc;
220#endif
213 221
214void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr);222void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr);
215void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);223void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);
@@ -222,5 +230,8 @@ void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, · 6 unmodified lines
222u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem);230u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem);
223void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,231void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
224 struct scmi_xfer *xfer);232 struct scmi_xfer *xfer);
233void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
234 size_t max_len, struct scmi_xfer *xfer);
235void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
225bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,236bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
226 struct scmi_xfer *xfer);237 struct scmi_xfer *xfer);
drivers/firmware/arm_scmi/driver.c+105−28
@@ -76,6 +76,7 @@ struct scmi_xfers_info { · 75 unmodified lines
76 * implementation version and (sub-)vendor identification.76 * implementation version and (sub-)vendor identification.
77 * @handle: Instance of SCMI handle to send to clients77 * @handle: Instance of SCMI handle to send to clients
78 * @tx_minfo: Universal Transmit Message management info78 * @tx_minfo: Universal Transmit Message management info
79 * @rx_minfo: Universal Receive Message management info
79 * @tx_idr: IDR object to map protocol id to Tx channel info pointer80 * @tx_idr: IDR object to map protocol id to Tx channel info pointer
80 * @rx_idr: IDR object to map protocol id to Rx channel info pointer81 * @rx_idr: IDR object to map protocol id to Rx channel info pointer
81 * @protocols_imp: List of protocols implemented, currently maximum of82 * @protocols_imp: List of protocols implemented, currently maximum of
@@ -89,6 +90,7 @@ struct scmi_info { · 7 unmodified lines
89 struct scmi_revision_info version;90 struct scmi_revision_info version;
90 struct scmi_handle handle;91 struct scmi_handle handle;
91 struct scmi_xfers_info tx_minfo;92 struct scmi_xfers_info tx_minfo;
93 struct scmi_xfers_info rx_minfo;
92 struct idr tx_idr;94 struct idr tx_idr;
93 struct idr rx_idr;95 struct idr rx_idr;
94 u8 *protocols_imp;96 u8 *protocols_imp;
@@ -200,37 +202,66 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer) · 105 unmodified lines
200 spin_unlock_irqrestore(&minfo->xfer_lock, flags);202 spin_unlock_irqrestore(&minfo->xfer_lock, flags);
201}203}
202 204
203/**205static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr)
204 * scmi_rx_callback() - callback for receiving messages
205 *
206 * @cinfo: SCMI channel info
207 * @msg_hdr: Message header
208 *
209 * Processes one received message to appropriate transfer information and
210 * signals completion of the transfer.
211 *
212 * NOTE: This function will be invoked in IRQ context, hence should be
213 * as optimal as possible.
214 */
215void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr)
216{206{
217 struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
218 struct scmi_xfers_info *minfo = &info->tx_minfo;
219 u16 xfer_id = MSG_XTRACT_TOKEN(msg_hdr);
220 u8 msg_type = MSG_XTRACT_TYPE(msg_hdr);
221 struct device *dev = cinfo->dev;
222 struct scmi_xfer *xfer;207 struct scmi_xfer *xfer;
208 struct device *dev = cinfo->dev;
209 struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
210 struct scmi_xfers_info *minfo = &info->rx_minfo;
223 211
224 if (msg_type == MSG_TYPE_NOTIFICATION)212 xfer = scmi_xfer_get(cinfo->handle, minfo);
225 return; /* Notifications not yet supported */213 if (IS_ERR(xfer)) {
214 dev_err(dev, "failed to get free message slot (%ld)\n",
215 PTR_ERR(xfer));
216 info->desc->ops->clear_channel(cinfo);
217 return;
218 }
219
220 unpack_scmi_header(msg_hdr, &xfer->hdr);
221 scmi_dump_header_dbg(dev, &xfer->hdr);
222 info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
223 xfer);
224
225 trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
226 xfer->hdr.protocol_id, xfer->hdr.seq,
227 MSG_TYPE_NOTIFICATION);
228
229 __scmi_xfer_put(minfo, xfer);
230
231 info->desc->ops->clear_channel(cinfo);
232}
233
234static void scmi_handle_response(struct scmi_chan_info *cinfo,
235 u16 xfer_id, u8 msg_type)
236{
237 struct scmi_xfer *xfer;
238 struct device *dev = cinfo->dev;
239 struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
240 struct scmi_xfers_info *minfo = &info->tx_minfo;
226 241
227 /* Are we even expecting this? */242 /* Are we even expecting this? */
228 if (!test_bit(xfer_id, minfo->xfer_alloc_table)) {243 if (!test_bit(xfer_id, minfo->xfer_alloc_table)) {
229 dev_err(dev, "message for %d is not expected!\n", xfer_id);244 dev_err(dev, "message for %d is not expected!\n", xfer_id);
245 info->desc->ops->clear_channel(cinfo);
230 return;246 return;
231 }247 }
232 248
233 xfer = &minfo->xfer_block[xfer_id];249 xfer = &minfo->xfer_block[xfer_id];
250 /*
251 * Even if a response was indeed expected on this slot at this point,
252 * a buggy platform could wrongly reply feeding us an unexpected
253 * delayed response we're not prepared to handle: bail-out safely
254 * blaming firmware.
255 */
256 if (unlikely(msg_type == MSG_TYPE_DELAYED_RESP && !xfer->async_done)) {
257 dev_err(dev,
258 "Delayed Response for %d not expected! Buggy F/W ?\n",
259 xfer_id);
260 info->desc->ops->clear_channel(cinfo);
261 /* It was unexpected, so nobody will clear the xfer if not us */
262 __scmi_xfer_put(minfo, xfer);
263 return;
264 }
234 265
235 scmi_dump_header_dbg(dev, &xfer->hdr);266 scmi_dump_header_dbg(dev, &xfer->hdr);
236 267
@@ -240,10 +271,43 @@ void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr) · 3 unmodified lines
240 xfer->hdr.protocol_id, xfer->hdr.seq,271 xfer->hdr.protocol_id, xfer->hdr.seq,
241 msg_type);272 msg_type);
242 273
243 if (msg_type == MSG_TYPE_DELAYED_RESP)274 if (msg_type == MSG_TYPE_DELAYED_RESP) {
275 info->desc->ops->clear_channel(cinfo);
244 complete(xfer->async_done);276 complete(xfer->async_done);
245 else277 } else {
246 complete(&xfer->done);278 complete(&xfer->done);
279 }
280}
281
282/**
283 * scmi_rx_callback() - callback for receiving messages
284 *
285 * @cinfo: SCMI channel info
286 * @msg_hdr: Message header
287 *
288 * Processes one received message to appropriate transfer information and
289 * signals completion of the transfer.
290 *
291 * NOTE: This function will be invoked in IRQ context, hence should be
292 * as optimal as possible.
293 */
294void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr)
295{
296 u16 xfer_id = MSG_XTRACT_TOKEN(msg_hdr);
297 u8 msg_type = MSG_XTRACT_TYPE(msg_hdr);
298
299 switch (msg_type) {
300 case MSG_TYPE_NOTIFICATION:
301 scmi_handle_notification(cinfo, msg_hdr);
302 break;
303 case MSG_TYPE_COMMAND:
304 case MSG_TYPE_DELAYED_RESP:
305 scmi_handle_response(cinfo, xfer_id, msg_type);
306 break;
307 default:
308 WARN_ONCE(1, "received unknown msg_type:%d\n", msg_type);
309 break;
310 }
247}311}
248 312
249/**313/**
@@ -525,13 +589,13 @@ int scmi_handle_put(const struct scmi_handle *handle) · 275 unmodified lines
525 return 0;589 return 0;
526}590}
527 591
528static int scmi_xfer_info_init(struct scmi_info *sinfo)592static int __scmi_xfer_info_init(struct scmi_info *sinfo,
593 struct scmi_xfers_info *info)
529{594{
530 int i;595 int i;
531 struct scmi_xfer *xfer;596 struct scmi_xfer *xfer;
532 struct device *dev = sinfo->dev;597 struct device *dev = sinfo->dev;
533 const struct scmi_desc *desc = sinfo->desc;598 const struct scmi_desc *desc = sinfo->desc;
534 struct scmi_xfers_info *info = &sinfo->tx_minfo;
535 599
536 /* Pre-allocated messages, no more than what hdr.seq can support */600 /* Pre-allocated messages, no more than what hdr.seq can support */
537 if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) {601 if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) {
@@ -566,6 +630,16 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) · 28 unmodified lines
566 return 0;630 return 0;
567}631}
568 632
633static int scmi_xfer_info_init(struct scmi_info *sinfo)
634{
635 int ret = __scmi_xfer_info_init(sinfo, &sinfo->tx_minfo);
636
637 if (!ret && idr_find(&sinfo->rx_idr, SCMI_PROTOCOL_BASE))
638 ret = __scmi_xfer_info_init(sinfo, &sinfo->rx_minfo);
639
640 return ret;
641}
642
569static int scmi_chan_setup(struct scmi_info *info, struct device *dev,643static int scmi_chan_setup(struct scmi_info *info, struct device *dev,
570 int prot_id, bool tx)644 int prot_id, bool tx)
571{645{
@@ -699,10 +773,6 @@ static int scmi_probe(struct platform_device *pdev) · 127 unmodified lines
699 info->desc = desc;773 info->desc = desc;
700 INIT_LIST_HEAD(&info->node);774 INIT_LIST_HEAD(&info->node);
701 775
702 ret = scmi_xfer_info_init(info);
703 if (ret)
704 return ret;
705
706 platform_set_drvdata(pdev, info);776 platform_set_drvdata(pdev, info);
707 idr_init(&info->tx_idr);777 idr_init(&info->tx_idr);
708 idr_init(&info->rx_idr);778 idr_init(&info->rx_idr);
@@ -715,6 +785,10 @@ static int scmi_probe(struct platform_device *pdev) · 6 unmodified lines
715 if (ret)785 if (ret)
716 return ret;786 return ret;
717 787
788 ret = scmi_xfer_info_init(info);
789 if (ret)
790 return ret;
791
718 ret = scmi_base_protocol_init(handle);792 ret = scmi_base_protocol_init(handle);
719 if (ret) {793 if (ret) {
720 dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);794 dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
@@ -827,6 +901,9 @@ ATTRIBUTE_GROUPS(versions); · 106 unmodified lines
827/* Each compatible listed below must have descriptor associated with it */901/* Each compatible listed below must have descriptor associated with it */
828static const struct of_device_id scmi_of_match[] = {902static const struct of_device_id scmi_of_match[] = {
829 { .compatible = "arm,scmi", .data = &scmi_mailbox_desc },903 { .compatible = "arm,scmi", .data = &scmi_mailbox_desc },
904#ifdef CONFIG_ARM_PSCI_FW
905 { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
906#endif
830 { /* Sentinel */ },907 { /* Sentinel */ },
831};908};
832 909
drivers/firmware/arm_scmi/mailbox.c+17−0
@@ -158,6 +158,21 @@ static void mailbox_fetch_response(struct scmi_chan_info *cinfo, · 157 unmodified lines
158 shmem_fetch_response(smbox->shmem, xfer);158 shmem_fetch_response(smbox->shmem, xfer);
159}159}
160 160
161static void mailbox_fetch_notification(struct scmi_chan_info *cinfo,
162 size_t max_len, struct scmi_xfer *xfer)
163{
164 struct scmi_mailbox *smbox = cinfo->transport_info;
165
166 shmem_fetch_notification(smbox->shmem, max_len, xfer);
167}
168
169static void mailbox_clear_channel(struct scmi_chan_info *cinfo)
170{
171 struct scmi_mailbox *smbox = cinfo->transport_info;
172
173 shmem_clear_channel(smbox->shmem);
174}
175
161static bool176static bool
162mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)177mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
163{178{
@@ -173,6 +188,8 @@ static struct scmi_transport_ops scmi_mailbox_ops = { · 9 unmodified lines
173 .send_message = mailbox_send_message,188 .send_message = mailbox_send_message,
174 .mark_txdone = mailbox_mark_txdone,189 .mark_txdone = mailbox_mark_txdone,
175 .fetch_response = mailbox_fetch_response,190 .fetch_response = mailbox_fetch_response,
191 .fetch_notification = mailbox_fetch_notification,
192 .clear_channel = mailbox_clear_channel,
176 .poll_done = mailbox_poll_done,193 .poll_done = mailbox_poll_done,
177};194};
178 195
drivers/firmware/arm_scmi/perf.c+5−0
@@ -27,6 +27,11 @@ enum scmi_performance_protocol_cmd { · 26 unmodified lines
27 PERF_DESCRIBE_FASTCHANNEL = 0xb,27 PERF_DESCRIBE_FASTCHANNEL = 0xb,
28};28};
29 29
30enum scmi_performance_protocol_notify {
31 PERFORMANCE_LIMITS_CHANGED = 0x0,
32 PERFORMANCE_LEVEL_CHANGED = 0x1,
33};
34
30struct scmi_opp {35struct scmi_opp {
31 u32 perf;36 u32 perf;
32 u32 power;37 u32 power;
drivers/firmware/arm_scmi/power.c+6−0
@@ -12,6 +12,12 @@ enum scmi_power_protocol_cmd { · 11 unmodified lines
12 POWER_STATE_SET = 0x4,12 POWER_STATE_SET = 0x4,
13 POWER_STATE_GET = 0x5,13 POWER_STATE_GET = 0x5,
14 POWER_STATE_NOTIFY = 0x6,14 POWER_STATE_NOTIFY = 0x6,
15 POWER_STATE_CHANGE_REQUESTED_NOTIFY = 0x7,
16};
17
18enum scmi_power_protocol_notify {
19 POWER_STATE_CHANGED = 0x0,
20 POWER_STATE_CHANGE_REQUESTED = 0x1,
15};21};
16 22
17struct scmi_msg_resp_power_attributes {23struct scmi_msg_resp_power_attributes {
drivers/firmware/arm_scmi/sensors.c+4−0
@@ -14,6 +14,10 @@ enum scmi_sensor_protocol_cmd { · 13 unmodified lines
14 SENSOR_READING_GET = 0x6,14 SENSOR_READING_GET = 0x6,
15};15};
16 16
17enum scmi_sensor_protocol_notify {
18 SENSOR_TRIP_POINT_EVENT = 0x0,
19};
20
17struct scmi_msg_resp_sensor_attributes {21struct scmi_msg_resp_sensor_attributes {
18 __le16 num_sensors;22 __le16 num_sensors;
19 u8 max_requests;23 u8 max_requests;
drivers/firmware/arm_scmi/shmem.c+15−0
@@ -67,6 +67,21 @@ void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, · 66 unmodified lines
67 memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);67 memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
68}68}
69 69
70void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
71 size_t max_len, struct scmi_xfer *xfer)
72{
73 /* Skip only the length of header in shmem area i.e 4 bytes */
74 xfer->rx.len = min_t(size_t, max_len, ioread32(&shmem->length) - 4);
75
76 /* Take a copy to the rx buffer.. */
77 memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len);
78}
79
80void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem)
81{
82 iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status);
83}
84
70bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,85bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
71 struct scmi_xfer *xfer)86 struct scmi_xfer *xfer)
72{87{
drivers/firmware/arm_scmi/smc.c+153−0
@@ -0,0 +1,153 @@
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/device.h>
11#include <linux/err.h>
12#include <linux/mutex.h>
13#include <linux/of.h>
14#include <linux/of_address.h>
15#include <linux/slab.h>
16
17#include "common.h"
18
19/**
20 * struct scmi_smc - Structure representing a SCMI smc transport
21 *
22 * @cinfo: SCMI channel info
23 * @shmem: Transmit/Receive shared memory area
24 * @func_id: smc/hvc call function id
25 */
26
27struct scmi_smc {
28 struct scmi_chan_info *cinfo;
29 struct scmi_shared_mem __iomem *shmem;
30 struct mutex shmem_lock;
31 u32 func_id;
32};
33
34static bool smc_chan_available(struct device *dev, int idx)
35{
36 struct device_node *np = of_parse_phandle(dev->of_node, "shmem", 0);
37 if (!np)
38 return false;
39
40 of_node_put(np);
41 return true;
42}
43
44static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
45 bool tx)
46{
47 struct device *cdev = cinfo->dev;
48 struct scmi_smc *scmi_info;
49 resource_size_t size;
50 struct resource res;
51 struct device_node *np;
52 u32 func_id;
53 int ret;
54
55 if (!tx)
56 return -ENODEV;
57
58 scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL);
59 if (!scmi_info)
60 return -ENOMEM;
61
62 np = of_parse_phandle(cdev->of_node, "shmem", 0);
63 ret = of_address_to_resource(np, 0, &res);
64 of_node_put(np);
65 if (ret) {
66 dev_err(cdev, "failed to get SCMI Tx shared memory\n");
67 return ret;
68 }
69
70 size = resource_size(&res);
71 scmi_info->shmem = devm_ioremap(dev, res.start, size);
72 if (!scmi_info->shmem) {
73 dev_err(dev, "failed to ioremap SCMI Tx shared memory\n");
74 return -EADDRNOTAVAIL;
75 }
76
77 ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
78 if (ret < 0)
79 return ret;
80
81 scmi_info->func_id = func_id;
82 scmi_info->cinfo = cinfo;
83 mutex_init(&scmi_info->shmem_lock);
84 cinfo->transport_info = scmi_info;
85
86 return 0;
87}
88
89static int smc_chan_free(int id, void *p, void *data)
90{
91 struct scmi_chan_info *cinfo = p;
92 struct scmi_smc *scmi_info = cinfo->transport_info;
93
94 cinfo->transport_info = NULL;
95 scmi_info->cinfo = NULL;
96
97 scmi_free_channel(cinfo, data, id);
98
99 return 0;
100}
101
102static int smc_send_message(struct scmi_chan_info *cinfo,
103 struct scmi_xfer *xfer)
104{
105 struct scmi_smc *scmi_info = cinfo->transport_info;
106 struct arm_smccc_res res;
107
108 mutex_lock(&scmi_info->shmem_lock);
109
110 shmem_tx_prepare(scmi_info->shmem, xfer);
111
112 arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
113 scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem));
114
115 mutex_unlock(&scmi_info->shmem_lock);
116
117 /* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
118 if (res.a0)
119 return -EOPNOTSUPP;
120 return 0;
121}
122
123static void smc_fetch_response(struct scmi_chan_info *cinfo,
124 struct scmi_xfer *xfer)
125{
126 struct scmi_smc *scmi_info = cinfo->transport_info;
127
128 shmem_fetch_response(scmi_info->shmem, xfer);
129}
130
131static bool
132smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
133{
134 struct scmi_smc *scmi_info = cinfo->transport_info;
135
136 return shmem_poll_done(scmi_info->shmem, xfer);
137}
138
139static struct scmi_transport_ops scmi_smc_ops = {
140 .chan_available = smc_chan_available,
141 .chan_setup = smc_chan_setup,
142 .chan_free = smc_chan_free,
143 .send_message = smc_send_message,
144 .fetch_response = smc_fetch_response,
145 .poll_done = smc_poll_done,
146};
147
148const struct scmi_desc scmi_smc_desc = {
149 .ops = &scmi_smc_ops,
150 .max_rx_timeout_ms = 30,
151 .max_msg = 1,
152 .max_msg_size = 128,
153};
include/linux/scmi_protocol.h+6−0
@@ -4,6 +4,10 @@ · 3 unmodified lines
4 *4 *
5 * Copyright (C) 2018 ARM Ltd.5 * Copyright (C) 2018 ARM Ltd.
6 */6 */
7
8#ifndef _LINUX_SCMI_PROTOCOL_H
9#define _LINUX_SCMI_PROTOCOL_H
10
7#include <linux/device.h>11#include <linux/device.h>
8#include <linux/types.h>12#include <linux/types.h>
9 13
@@ -319,3 +323,5 @@ static inline void scmi_driver_unregister(struct scmi_driver *driver) {} · 309 unmodified lines
319typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);323typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);
320int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn);324int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn);
321void scmi_protocol_unregister(int protocol_id);325void scmi_protocol_unregister(int protocol_id);
326
327#endif /* _LINUX_SCMI_PROTOCOL_H */
include/linux/scpi_protocol.h+6−0
@@ -4,6 +4,10 @@ · 3 unmodified lines
4 *4 *
5 * Copyright (C) 2014 ARM Ltd.5 * Copyright (C) 2014 ARM Ltd.
6 */6 */
7
8#ifndef _LINUX_SCPI_PROTOCOL_H
9#define _LINUX_SCPI_PROTOCOL_H
10
7#include <linux/types.h>11#include <linux/types.h>
8 12
9struct scpi_opp {13struct scpi_opp {
@@ -71,3 +75,5 @@ struct scpi_ops *get_scpi_ops(void); · 61 unmodified lines
71#else75#else
72static inline struct scpi_ops *get_scpi_ops(void) { return NULL; }76static inline struct scpi_ops *get_scpi_ops(void) { return NULL; }
73#endif77#endif
78
79#endif /* _LINUX_SCPI_PROTOCOL_H */