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 * @shmem_lock: Lock to protect access to Tx/Rx shared memory area 25 * @func_id: smc/hvc call function id 26 */ 27 28 struct scmi_smc { 29 struct scmi_chan_info *cinfo; 30 struct scmi_shared_mem __iomem *shmem; 31 struct mutex shmem_lock; 32 u32 func_id; 33 }; 34 35 static bool smc_chan_available(struct device *dev, int idx) 36 { 37 struct device_node *np = of_parse_phandle(dev->of_node, "shmem", 0); 38 if (!np) 39 return false; 40 41 of_node_put(np); 42 return true; 43 } 44 45 static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, 46 bool tx) 47 { 48 struct device *cdev = cinfo->dev; 49 struct scmi_smc *scmi_info; 50 resource_size_t size; 51 struct resource res; 52 struct device_node *np; 53 u32 func_id; 54 int ret; 55 56 if (!tx) 57 return -ENODEV; 58 59 scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL); 60 if (!scmi_info) 61 return -ENOMEM; 62 63 np = of_parse_phandle(cdev->of_node, "shmem", 0); 64 ret = of_address_to_resource(np, 0, &res); 65 of_node_put(np); 66 if (ret) { 67 dev_err(cdev, "failed to get SCMI Tx shared memory\n"); 68 return ret; 69 } 70 71 size = resource_size(&res); 72 scmi_info->shmem = devm_ioremap(dev, res.start, size); 73 if (!scmi_info->shmem) { 74 dev_err(dev, "failed to ioremap SCMI Tx shared memory\n"); 75 return -EADDRNOTAVAIL; 76 } 77 78 ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id); 79 if (ret < 0) 80 return ret; 81 82 scmi_info->func_id = func_id; 83 scmi_info->cinfo = cinfo; 84 mutex_init(&scmi_info->shmem_lock); 85 cinfo->transport_info = scmi_info; 86 87 return 0; 88 } 89 90 static int smc_chan_free(int id, void *p, void *data) 91 { 92 struct scmi_chan_info *cinfo = p; 93 struct scmi_smc *scmi_info = cinfo->transport_info; 94 95 cinfo->transport_info = NULL; 96 scmi_info->cinfo = NULL; 97 98 scmi_free_channel(cinfo, data, id); 99 100 return 0; 101 } 102 103 static int smc_send_message(struct scmi_chan_info *cinfo, 104 struct scmi_xfer *xfer) 105 { 106 struct scmi_smc *scmi_info = cinfo->transport_info; 107 struct arm_smccc_res res; 108 109 mutex_lock(&scmi_info->shmem_lock); 110 111 shmem_tx_prepare(scmi_info->shmem, xfer); 112 113 arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res); 114 scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem)); 115 116 mutex_unlock(&scmi_info->shmem_lock); 117 118 /* Only SMCCC_RET_NOT_SUPPORTED is valid error code */ 119 if (res.a0) 120 return -EOPNOTSUPP; 121 return 0; 122 } 123 124 static void smc_fetch_response(struct scmi_chan_info *cinfo, 125 struct scmi_xfer *xfer) 126 { 127 struct scmi_smc *scmi_info = cinfo->transport_info; 128 129 shmem_fetch_response(scmi_info->shmem, xfer); 130 } 131 132 static bool 133 smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) 134 { 135 struct scmi_smc *scmi_info = cinfo->transport_info; 136 137 return shmem_poll_done(scmi_info->shmem, xfer); 138 } 139 140 static struct scmi_transport_ops scmi_smc_ops = { 141 .chan_available = smc_chan_available, 142 .chan_setup = smc_chan_setup, 143 .chan_free = smc_chan_free, 144 .send_message = smc_send_message, 145 .fetch_response = smc_fetch_response, 146 .poll_done = smc_poll_done, 147 }; 148 149 const struct scmi_desc scmi_smc_desc = { 150 .ops = &scmi_smc_ops, 151 .max_rx_timeout_ms = 30, 152 .max_msg = 1, 153 .max_msg_size = 128, 154 }; 155