1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2018 NXP 4 * Author: Dong Aisheng <aisheng.dong@nxp.com> 5 * 6 * Implementation of the SCU IPC functions using MUs (client side). 7 * 8 */ 9 10 #include <linux/err.h> 11 #include <linux/firmware/imx/types.h> 12 #include <linux/firmware/imx/ipc.h> 13 #include <linux/firmware/imx/sci.h> 14 #include <linux/interrupt.h> 15 #include <linux/irq.h> 16 #include <linux/kernel.h> 17 #include <linux/mailbox_client.h> 18 #include <linux/module.h> 19 #include <linux/mutex.h> 20 #include <linux/of_platform.h> 21 #include <linux/platform_device.h> 22 23 #define SCU_MU_CHAN_NUM 8 24 #define MAX_RX_TIMEOUT (msecs_to_jiffies(30)) 25 26 struct imx_sc_chan { 27 struct imx_sc_ipc *sc_ipc; 28 29 struct mbox_client cl; 30 struct mbox_chan *ch; 31 int idx; 32 }; 33 34 struct imx_sc_ipc { 35 /* SCU uses 4 Tx and 4 Rx channels */ 36 struct imx_sc_chan chans[SCU_MU_CHAN_NUM]; 37 struct device *dev; 38 struct mutex lock; 39 struct completion done; 40 41 /* temporarily store the SCU msg */ 42 u32 *msg; 43 u8 rx_size; 44 u8 count; 45 }; 46 47 /* 48 * This type is used to indicate error response for most functions. 49 */ 50 enum imx_sc_error_codes { 51 IMX_SC_ERR_NONE = 0, /* Success */ 52 IMX_SC_ERR_VERSION = 1, /* Incompatible API version */ 53 IMX_SC_ERR_CONFIG = 2, /* Configuration error */ 54 IMX_SC_ERR_PARM = 3, /* Bad parameter */ 55 IMX_SC_ERR_NOACCESS = 4, /* Permission error (no access) */ 56 IMX_SC_ERR_LOCKED = 5, /* Permission error (locked) */ 57 IMX_SC_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ 58 IMX_SC_ERR_NOTFOUND = 7, /* Not found */ 59 IMX_SC_ERR_NOPOWER = 8, /* No power */ 60 IMX_SC_ERR_IPC = 9, /* Generic IPC error */ 61 IMX_SC_ERR_BUSY = 10, /* Resource is currently busy/active */ 62 IMX_SC_ERR_FAIL = 11, /* General I/O failure */ 63 IMX_SC_ERR_LAST 64 }; 65 66 static int imx_sc_linux_errmap[IMX_SC_ERR_LAST] = { 67 0, /* IMX_SC_ERR_NONE */ 68 -EINVAL, /* IMX_SC_ERR_VERSION */ 69 -EINVAL, /* IMX_SC_ERR_CONFIG */ 70 -EINVAL, /* IMX_SC_ERR_PARM */ 71 -EACCES, /* IMX_SC_ERR_NOACCESS */ 72 -EACCES, /* IMX_SC_ERR_LOCKED */ 73 -ERANGE, /* IMX_SC_ERR_UNAVAILABLE */ 74 -EEXIST, /* IMX_SC_ERR_NOTFOUND */ 75 -EPERM, /* IMX_SC_ERR_NOPOWER */ 76 -EPIPE, /* IMX_SC_ERR_IPC */ 77 -EBUSY, /* IMX_SC_ERR_BUSY */ 78 -EIO, /* IMX_SC_ERR_FAIL */ 79 }; 80 81 static struct imx_sc_ipc *imx_sc_ipc_handle; 82 83 static inline int imx_sc_to_linux_errno(int errno) 84 { 85 if (errno >= IMX_SC_ERR_NONE && errno < IMX_SC_ERR_LAST) 86 return imx_sc_linux_errmap[errno]; 87 return -EIO; 88 } 89 90 /* 91 * Get the default handle used by SCU 92 */ 93 int imx_scu_get_handle(struct imx_sc_ipc **ipc) 94 { 95 if (!imx_sc_ipc_handle) 96 return -EPROBE_DEFER; 97 98 *ipc = imx_sc_ipc_handle; 99 return 0; 100 } 101 EXPORT_SYMBOL(imx_scu_get_handle); 102 103 static void imx_scu_rx_callback(struct mbox_client *c, void *msg) 104 { 105 struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl); 106 struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc; 107 struct imx_sc_rpc_msg *hdr; 108 u32 *data = msg; 109 110 if (sc_chan->idx == 0) { 111 hdr = msg; 112 sc_ipc->rx_size = hdr->size; 113 dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size); 114 if (sc_ipc->rx_size > 4) 115 dev_warn(sc_ipc->dev, "RPC does not support receiving over 4 words: %u\n", 116 sc_ipc->rx_size); 117 } 118 119 sc_ipc->msg[sc_chan->idx] = *data; 120 sc_ipc->count++; 121 122 dev_dbg(sc_ipc->dev, "mu %u msg %u 0x%x\n", sc_chan->idx, 123 sc_ipc->count, *data); 124 125 if ((sc_ipc->rx_size != 0) && (sc_ipc->count == sc_ipc->rx_size)) 126 complete(&sc_ipc->done); 127 } 128 129 static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg) 130 { 131 struct imx_sc_rpc_msg *hdr = msg; 132 struct imx_sc_chan *sc_chan; 133 u32 *data = msg; 134 int ret; 135 int i; 136 137 /* Check size */ 138 if (hdr->size > IMX_SC_RPC_MAX_MSG) 139 return -EINVAL; 140 141 dev_dbg(sc_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc, 142 hdr->func, hdr->size); 143 144 for (i = 0; i < hdr->size; i++) { 145 sc_chan = &sc_ipc->chans[i % 4]; 146 ret = mbox_send_message(sc_chan->ch, &data[i]); 147 if (ret < 0) 148 return ret; 149 } 150 151 return 0; 152 } 153 154 /* 155 * RPC command/response 156 */ 157 int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) 158 { 159 struct imx_sc_rpc_msg *hdr; 160 int ret; 161 162 if (WARN_ON(!sc_ipc || !msg)) 163 return -EINVAL; 164 165 mutex_lock(&sc_ipc->lock); 166 reinit_completion(&sc_ipc->done); 167 168 sc_ipc->msg = msg; 169 sc_ipc->count = 0; 170 ret = imx_scu_ipc_write(sc_ipc, msg); 171 if (ret < 0) { 172 dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret); 173 goto out; 174 } 175 176 if (have_resp) { 177 if (!wait_for_completion_timeout(&sc_ipc->done, 178 MAX_RX_TIMEOUT)) { 179 dev_err(sc_ipc->dev, "RPC send msg timeout\n"); 180 mutex_unlock(&sc_ipc->lock); 181 return -ETIMEDOUT; 182 } 183 184 /* response status is stored in hdr->func field */ 185 hdr = msg; 186 ret = hdr->func; 187 } 188 189 out: 190 mutex_unlock(&sc_ipc->lock); 191 192 dev_dbg(sc_ipc->dev, "RPC SVC done\n"); 193 194 return imx_sc_to_linux_errno(ret); 195 } 196 EXPORT_SYMBOL(imx_scu_call_rpc); 197 198 static int imx_scu_probe(struct platform_device *pdev) 199 { 200 struct device *dev = &pdev->dev; 201 struct imx_sc_ipc *sc_ipc; 202 struct imx_sc_chan *sc_chan; 203 struct mbox_client *cl; 204 char *chan_name; 205 int ret; 206 int i; 207 208 sc_ipc = devm_kzalloc(dev, sizeof(*sc_ipc), GFP_KERNEL); 209 if (!sc_ipc) 210 return -ENOMEM; 211 212 for (i = 0; i < SCU_MU_CHAN_NUM; i++) { 213 if (i < 4) 214 chan_name = kasprintf(GFP_KERNEL, "tx%d", i); 215 else 216 chan_name = kasprintf(GFP_KERNEL, "rx%d", i - 4); 217 218 if (!chan_name) 219 return -ENOMEM; 220 221 sc_chan = &sc_ipc->chans[i]; 222 cl = &sc_chan->cl; 223 cl->dev = dev; 224 cl->tx_block = false; 225 cl->knows_txdone = true; 226 cl->rx_callback = imx_scu_rx_callback; 227 228 sc_chan->sc_ipc = sc_ipc; 229 sc_chan->idx = i % 4; 230 sc_chan->ch = mbox_request_channel_byname(cl, chan_name); 231 if (IS_ERR(sc_chan->ch)) { 232 ret = PTR_ERR(sc_chan->ch); 233 if (ret != -EPROBE_DEFER) 234 dev_err(dev, "Failed to request mbox chan %s ret %d\n", 235 chan_name, ret); 236 return ret; 237 } 238 239 dev_dbg(dev, "request mbox chan %s\n", chan_name); 240 /* chan_name is not used anymore by framework */ 241 kfree(chan_name); 242 } 243 244 sc_ipc->dev = dev; 245 mutex_init(&sc_ipc->lock); 246 init_completion(&sc_ipc->done); 247 248 imx_sc_ipc_handle = sc_ipc; 249 250 ret = imx_scu_enable_general_irq_channel(dev); 251 if (ret) 252 dev_warn(dev, 253 "failed to enable general irq channel: %d\n", ret); 254 255 dev_info(dev, "NXP i.MX SCU Initialized\n"); 256 257 return devm_of_platform_populate(dev); 258 } 259 260 static const struct of_device_id imx_scu_match[] = { 261 { .compatible = "fsl,imx-scu", }, 262 { /* Sentinel */ } 263 }; 264 265 static struct platform_driver imx_scu_driver = { 266 .driver = { 267 .name = "imx-scu", 268 .of_match_table = imx_scu_match, 269 }, 270 .probe = imx_scu_probe, 271 }; 272 builtin_platform_driver(imx_scu_driver); 273 274 MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>"); 275 MODULE_DESCRIPTION("IMX SCU firmware protocol driver"); 276 MODULE_LICENSE("GPL v2"); 277