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_ipc->msg) { 111 dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n", 112 sc_chan->idx, *data); 113 return; 114 } 115 116 if (sc_chan->idx == 0) { 117 hdr = msg; 118 sc_ipc->rx_size = hdr->size; 119 dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size); 120 if (sc_ipc->rx_size > 4) 121 dev_warn(sc_ipc->dev, "RPC does not support receiving over 4 words: %u\n", 122 sc_ipc->rx_size); 123 } 124 125 sc_ipc->msg[sc_chan->idx] = *data; 126 sc_ipc->count++; 127 128 dev_dbg(sc_ipc->dev, "mu %u msg %u 0x%x\n", sc_chan->idx, 129 sc_ipc->count, *data); 130 131 if ((sc_ipc->rx_size != 0) && (sc_ipc->count == sc_ipc->rx_size)) 132 complete(&sc_ipc->done); 133 } 134 135 static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg) 136 { 137 struct imx_sc_rpc_msg *hdr = msg; 138 struct imx_sc_chan *sc_chan; 139 u32 *data = msg; 140 int ret; 141 int i; 142 143 /* Check size */ 144 if (hdr->size > IMX_SC_RPC_MAX_MSG) 145 return -EINVAL; 146 147 dev_dbg(sc_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc, 148 hdr->func, hdr->size); 149 150 for (i = 0; i < hdr->size; i++) { 151 sc_chan = &sc_ipc->chans[i % 4]; 152 ret = mbox_send_message(sc_chan->ch, &data[i]); 153 if (ret < 0) 154 return ret; 155 } 156 157 return 0; 158 } 159 160 /* 161 * RPC command/response 162 */ 163 int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) 164 { 165 uint8_t saved_svc, saved_func; 166 struct imx_sc_rpc_msg *hdr; 167 int ret; 168 169 if (WARN_ON(!sc_ipc || !msg)) 170 return -EINVAL; 171 172 mutex_lock(&sc_ipc->lock); 173 reinit_completion(&sc_ipc->done); 174 175 if (have_resp) { 176 sc_ipc->msg = msg; 177 saved_svc = ((struct imx_sc_rpc_msg *)msg)->svc; 178 saved_func = ((struct imx_sc_rpc_msg *)msg)->func; 179 } 180 sc_ipc->count = 0; 181 ret = imx_scu_ipc_write(sc_ipc, msg); 182 if (ret < 0) { 183 dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret); 184 goto out; 185 } 186 187 if (have_resp) { 188 if (!wait_for_completion_timeout(&sc_ipc->done, 189 MAX_RX_TIMEOUT)) { 190 dev_err(sc_ipc->dev, "RPC send msg timeout\n"); 191 mutex_unlock(&sc_ipc->lock); 192 return -ETIMEDOUT; 193 } 194 195 /* response status is stored in hdr->func field */ 196 hdr = msg; 197 ret = hdr->func; 198 /* 199 * Some special SCU firmware APIs do NOT have return value 200 * in hdr->func, but they do have response data, those special 201 * APIs are defined as void function in SCU firmware, so they 202 * should be treated as return success always. 203 */ 204 if ((saved_svc == IMX_SC_RPC_SVC_MISC) && 205 (saved_func == IMX_SC_MISC_FUNC_UNIQUE_ID || 206 saved_func == IMX_SC_MISC_FUNC_GET_BUTTON_STATUS)) 207 ret = 0; 208 } 209 210 out: 211 sc_ipc->msg = NULL; 212 mutex_unlock(&sc_ipc->lock); 213 214 dev_dbg(sc_ipc->dev, "RPC SVC done\n"); 215 216 return imx_sc_to_linux_errno(ret); 217 } 218 EXPORT_SYMBOL(imx_scu_call_rpc); 219 220 static int imx_scu_probe(struct platform_device *pdev) 221 { 222 struct device *dev = &pdev->dev; 223 struct imx_sc_ipc *sc_ipc; 224 struct imx_sc_chan *sc_chan; 225 struct mbox_client *cl; 226 char *chan_name; 227 int ret; 228 int i; 229 230 sc_ipc = devm_kzalloc(dev, sizeof(*sc_ipc), GFP_KERNEL); 231 if (!sc_ipc) 232 return -ENOMEM; 233 234 for (i = 0; i < SCU_MU_CHAN_NUM; i++) { 235 if (i < 4) 236 chan_name = kasprintf(GFP_KERNEL, "tx%d", i); 237 else 238 chan_name = kasprintf(GFP_KERNEL, "rx%d", i - 4); 239 240 if (!chan_name) 241 return -ENOMEM; 242 243 sc_chan = &sc_ipc->chans[i]; 244 cl = &sc_chan->cl; 245 cl->dev = dev; 246 cl->tx_block = false; 247 cl->knows_txdone = true; 248 cl->rx_callback = imx_scu_rx_callback; 249 250 sc_chan->sc_ipc = sc_ipc; 251 sc_chan->idx = i % 4; 252 sc_chan->ch = mbox_request_channel_byname(cl, chan_name); 253 if (IS_ERR(sc_chan->ch)) { 254 ret = PTR_ERR(sc_chan->ch); 255 if (ret != -EPROBE_DEFER) 256 dev_err(dev, "Failed to request mbox chan %s ret %d\n", 257 chan_name, ret); 258 return ret; 259 } 260 261 dev_dbg(dev, "request mbox chan %s\n", chan_name); 262 /* chan_name is not used anymore by framework */ 263 kfree(chan_name); 264 } 265 266 sc_ipc->dev = dev; 267 mutex_init(&sc_ipc->lock); 268 init_completion(&sc_ipc->done); 269 270 imx_sc_ipc_handle = sc_ipc; 271 272 ret = imx_scu_enable_general_irq_channel(dev); 273 if (ret) 274 dev_warn(dev, 275 "failed to enable general irq channel: %d\n", ret); 276 277 dev_info(dev, "NXP i.MX SCU Initialized\n"); 278 279 return devm_of_platform_populate(dev); 280 } 281 282 static const struct of_device_id imx_scu_match[] = { 283 { .compatible = "fsl,imx-scu", }, 284 { /* Sentinel */ } 285 }; 286 287 static struct platform_driver imx_scu_driver = { 288 .driver = { 289 .name = "imx-scu", 290 .of_match_table = imx_scu_match, 291 }, 292 .probe = imx_scu_probe, 293 }; 294 builtin_platform_driver(imx_scu_driver); 295 296 MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>"); 297 MODULE_DESCRIPTION("IMX SCU firmware protocol driver"); 298 MODULE_LICENSE("GPL v2"); 299