1 // SPDX-License-Identifier: GPL-2.0+
4 * Author: Dong Aisheng <aisheng.dong@nxp.com>
6 * Implementation of the SCU IPC functions using MUs (client side).
10 #include <linux/err.h>
11 #include <linux/firmware/imx/types.h>
12 #include <linux/firmware/imx/ipc.h>
13 #include <linux/interrupt.h>
14 #include <linux/irq.h>
15 #include <linux/kernel.h>
16 #include <linux/mailbox_client.h>
17 #include <linux/module.h>
18 #include <linux/mutex.h>
19 #include <linux/of_platform.h>
20 #include <linux/platform_device.h>
22 #define SCU_MU_CHAN_NUM 8
23 #define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
26 struct imx_sc_ipc
*sc_ipc
;
28 struct mbox_client cl
;
34 /* SCU uses 4 Tx and 4 Rx channels */
35 struct imx_sc_chan chans
[SCU_MU_CHAN_NUM
];
38 struct completion done
;
40 /* temporarily store the SCU msg */
47 * This type is used to indicate error response for most functions.
49 enum imx_sc_error_codes
{
50 IMX_SC_ERR_NONE
= 0, /* Success */
51 IMX_SC_ERR_VERSION
= 1, /* Incompatible API version */
52 IMX_SC_ERR_CONFIG
= 2, /* Configuration error */
53 IMX_SC_ERR_PARM
= 3, /* Bad parameter */
54 IMX_SC_ERR_NOACCESS
= 4, /* Permission error (no access) */
55 IMX_SC_ERR_LOCKED
= 5, /* Permission error (locked) */
56 IMX_SC_ERR_UNAVAILABLE
= 6, /* Unavailable (out of resources) */
57 IMX_SC_ERR_NOTFOUND
= 7, /* Not found */
58 IMX_SC_ERR_NOPOWER
= 8, /* No power */
59 IMX_SC_ERR_IPC
= 9, /* Generic IPC error */
60 IMX_SC_ERR_BUSY
= 10, /* Resource is currently busy/active */
61 IMX_SC_ERR_FAIL
= 11, /* General I/O failure */
65 static int imx_sc_linux_errmap
[IMX_SC_ERR_LAST
] = {
66 0, /* IMX_SC_ERR_NONE */
67 -EINVAL
, /* IMX_SC_ERR_VERSION */
68 -EINVAL
, /* IMX_SC_ERR_CONFIG */
69 -EINVAL
, /* IMX_SC_ERR_PARM */
70 -EACCES
, /* IMX_SC_ERR_NOACCESS */
71 -EACCES
, /* IMX_SC_ERR_LOCKED */
72 -ERANGE
, /* IMX_SC_ERR_UNAVAILABLE */
73 -EEXIST
, /* IMX_SC_ERR_NOTFOUND */
74 -EPERM
, /* IMX_SC_ERR_NOPOWER */
75 -EPIPE
, /* IMX_SC_ERR_IPC */
76 -EBUSY
, /* IMX_SC_ERR_BUSY */
77 -EIO
, /* IMX_SC_ERR_FAIL */
80 static struct imx_sc_ipc
*imx_sc_ipc_handle
;
82 static inline int imx_sc_to_linux_errno(int errno
)
84 if (errno
>= IMX_SC_ERR_NONE
&& errno
< IMX_SC_ERR_LAST
)
85 return imx_sc_linux_errmap
[errno
];
90 * Get the default handle used by SCU
92 int imx_scu_get_handle(struct imx_sc_ipc
**ipc
)
94 if (!imx_sc_ipc_handle
)
97 *ipc
= imx_sc_ipc_handle
;
100 EXPORT_SYMBOL(imx_scu_get_handle
);
102 static void imx_scu_rx_callback(struct mbox_client
*c
, void *msg
)
104 struct imx_sc_chan
*sc_chan
= container_of(c
, struct imx_sc_chan
, cl
);
105 struct imx_sc_ipc
*sc_ipc
= sc_chan
->sc_ipc
;
106 struct imx_sc_rpc_msg
*hdr
;
109 if (sc_chan
->idx
== 0) {
111 sc_ipc
->rx_size
= hdr
->size
;
112 dev_dbg(sc_ipc
->dev
, "msg rx size %u\n", sc_ipc
->rx_size
);
113 if (sc_ipc
->rx_size
> 4)
114 dev_warn(sc_ipc
->dev
, "RPC does not support receiving over 4 words: %u\n",
118 sc_ipc
->msg
[sc_chan
->idx
] = *data
;
121 dev_dbg(sc_ipc
->dev
, "mu %u msg %u 0x%x\n", sc_chan
->idx
,
122 sc_ipc
->count
, *data
);
124 if ((sc_ipc
->rx_size
!= 0) && (sc_ipc
->count
== sc_ipc
->rx_size
))
125 complete(&sc_ipc
->done
);
128 static int imx_scu_ipc_write(struct imx_sc_ipc
*sc_ipc
, void *msg
)
130 struct imx_sc_rpc_msg
*hdr
= msg
;
131 struct imx_sc_chan
*sc_chan
;
137 if (hdr
->size
> IMX_SC_RPC_MAX_MSG
)
140 dev_dbg(sc_ipc
->dev
, "RPC SVC %u FUNC %u SIZE %u\n", hdr
->svc
,
141 hdr
->func
, hdr
->size
);
143 for (i
= 0; i
< hdr
->size
; i
++) {
144 sc_chan
= &sc_ipc
->chans
[i
% 4];
145 ret
= mbox_send_message(sc_chan
->ch
, &data
[i
]);
154 * RPC command/response
156 int imx_scu_call_rpc(struct imx_sc_ipc
*sc_ipc
, void *msg
, bool have_resp
)
158 struct imx_sc_rpc_msg
*hdr
;
161 if (WARN_ON(!sc_ipc
|| !msg
))
164 mutex_lock(&sc_ipc
->lock
);
165 reinit_completion(&sc_ipc
->done
);
169 ret
= imx_scu_ipc_write(sc_ipc
, msg
);
171 dev_err(sc_ipc
->dev
, "RPC send msg failed: %d\n", ret
);
176 if (!wait_for_completion_timeout(&sc_ipc
->done
,
178 dev_err(sc_ipc
->dev
, "RPC send msg timeout\n");
179 mutex_unlock(&sc_ipc
->lock
);
183 /* response status is stored in hdr->func field */
189 mutex_unlock(&sc_ipc
->lock
);
191 dev_dbg(sc_ipc
->dev
, "RPC SVC done\n");
193 return imx_sc_to_linux_errno(ret
);
195 EXPORT_SYMBOL(imx_scu_call_rpc
);
197 static int imx_scu_probe(struct platform_device
*pdev
)
199 struct device
*dev
= &pdev
->dev
;
200 struct imx_sc_ipc
*sc_ipc
;
201 struct imx_sc_chan
*sc_chan
;
202 struct mbox_client
*cl
;
207 sc_ipc
= devm_kzalloc(dev
, sizeof(*sc_ipc
), GFP_KERNEL
);
211 for (i
= 0; i
< SCU_MU_CHAN_NUM
; i
++) {
213 chan_name
= kasprintf(GFP_KERNEL
, "tx%d", i
);
215 chan_name
= kasprintf(GFP_KERNEL
, "rx%d", i
- 4);
220 sc_chan
= &sc_ipc
->chans
[i
];
223 cl
->tx_block
= false;
224 cl
->knows_txdone
= true;
225 cl
->rx_callback
= imx_scu_rx_callback
;
227 sc_chan
->sc_ipc
= sc_ipc
;
228 sc_chan
->idx
= i
% 4;
229 sc_chan
->ch
= mbox_request_channel_byname(cl
, chan_name
);
230 if (IS_ERR(sc_chan
->ch
)) {
231 ret
= PTR_ERR(sc_chan
->ch
);
232 if (ret
!= -EPROBE_DEFER
)
233 dev_err(dev
, "Failed to request mbox chan %s ret %d\n",
238 dev_dbg(dev
, "request mbox chan %s\n", chan_name
);
239 /* chan_name is not used anymore by framework */
244 mutex_init(&sc_ipc
->lock
);
245 init_completion(&sc_ipc
->done
);
247 imx_sc_ipc_handle
= sc_ipc
;
249 dev_info(dev
, "NXP i.MX SCU Initialized\n");
251 return devm_of_platform_populate(dev
);
254 static const struct of_device_id imx_scu_match
[] = {
255 { .compatible
= "fsl,imx-scu", },
259 static struct platform_driver imx_scu_driver
= {
262 .of_match_table
= imx_scu_match
,
264 .probe
= imx_scu_probe
,
266 builtin_platform_driver(imx_scu_driver
);
268 MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
269 MODULE_DESCRIPTION("IMX SCU firmware protocol driver");
270 MODULE_LICENSE("GPL v2");