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/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>
23 #define SCU_MU_CHAN_NUM 8
24 #define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
27 struct imx_sc_ipc
*sc_ipc
;
29 struct mbox_client cl
;
32 struct completion tx_done
;
36 /* SCU uses 4 Tx and 4 Rx channels */
37 struct imx_sc_chan chans
[SCU_MU_CHAN_NUM
];
40 struct completion done
;
42 /* temporarily store the SCU msg */
49 * This type is used to indicate error response for most functions.
51 enum imx_sc_error_codes
{
52 IMX_SC_ERR_NONE
= 0, /* Success */
53 IMX_SC_ERR_VERSION
= 1, /* Incompatible API version */
54 IMX_SC_ERR_CONFIG
= 2, /* Configuration error */
55 IMX_SC_ERR_PARM
= 3, /* Bad parameter */
56 IMX_SC_ERR_NOACCESS
= 4, /* Permission error (no access) */
57 IMX_SC_ERR_LOCKED
= 5, /* Permission error (locked) */
58 IMX_SC_ERR_UNAVAILABLE
= 6, /* Unavailable (out of resources) */
59 IMX_SC_ERR_NOTFOUND
= 7, /* Not found */
60 IMX_SC_ERR_NOPOWER
= 8, /* No power */
61 IMX_SC_ERR_IPC
= 9, /* Generic IPC error */
62 IMX_SC_ERR_BUSY
= 10, /* Resource is currently busy/active */
63 IMX_SC_ERR_FAIL
= 11, /* General I/O failure */
67 static int imx_sc_linux_errmap
[IMX_SC_ERR_LAST
] = {
68 0, /* IMX_SC_ERR_NONE */
69 -EINVAL
, /* IMX_SC_ERR_VERSION */
70 -EINVAL
, /* IMX_SC_ERR_CONFIG */
71 -EINVAL
, /* IMX_SC_ERR_PARM */
72 -EACCES
, /* IMX_SC_ERR_NOACCESS */
73 -EACCES
, /* IMX_SC_ERR_LOCKED */
74 -ERANGE
, /* IMX_SC_ERR_UNAVAILABLE */
75 -EEXIST
, /* IMX_SC_ERR_NOTFOUND */
76 -EPERM
, /* IMX_SC_ERR_NOPOWER */
77 -EPIPE
, /* IMX_SC_ERR_IPC */
78 -EBUSY
, /* IMX_SC_ERR_BUSY */
79 -EIO
, /* IMX_SC_ERR_FAIL */
82 static struct imx_sc_ipc
*imx_sc_ipc_handle
;
84 static inline int imx_sc_to_linux_errno(int errno
)
86 if (errno
>= IMX_SC_ERR_NONE
&& errno
< IMX_SC_ERR_LAST
)
87 return imx_sc_linux_errmap
[errno
];
92 * Get the default handle used by SCU
94 int imx_scu_get_handle(struct imx_sc_ipc
**ipc
)
96 if (!imx_sc_ipc_handle
)
99 *ipc
= imx_sc_ipc_handle
;
102 EXPORT_SYMBOL(imx_scu_get_handle
);
104 /* Callback called when the word of a message is ack-ed, eg read by SCU */
105 static void imx_scu_tx_done(struct mbox_client
*cl
, void *mssg
, int r
)
107 struct imx_sc_chan
*sc_chan
= container_of(cl
, struct imx_sc_chan
, cl
);
109 complete(&sc_chan
->tx_done
);
112 static void imx_scu_rx_callback(struct mbox_client
*c
, void *msg
)
114 struct imx_sc_chan
*sc_chan
= container_of(c
, struct imx_sc_chan
, cl
);
115 struct imx_sc_ipc
*sc_ipc
= sc_chan
->sc_ipc
;
116 struct imx_sc_rpc_msg
*hdr
;
120 dev_warn(sc_ipc
->dev
, "unexpected rx idx %d 0x%08x, ignore!\n",
121 sc_chan
->idx
, *data
);
125 if (sc_chan
->idx
== 0) {
127 sc_ipc
->rx_size
= hdr
->size
;
128 dev_dbg(sc_ipc
->dev
, "msg rx size %u\n", sc_ipc
->rx_size
);
129 if (sc_ipc
->rx_size
> 4)
130 dev_warn(sc_ipc
->dev
, "RPC does not support receiving over 4 words: %u\n",
134 sc_ipc
->msg
[sc_chan
->idx
] = *data
;
137 dev_dbg(sc_ipc
->dev
, "mu %u msg %u 0x%x\n", sc_chan
->idx
,
138 sc_ipc
->count
, *data
);
140 if ((sc_ipc
->rx_size
!= 0) && (sc_ipc
->count
== sc_ipc
->rx_size
))
141 complete(&sc_ipc
->done
);
144 static int imx_scu_ipc_write(struct imx_sc_ipc
*sc_ipc
, void *msg
)
146 struct imx_sc_rpc_msg
*hdr
= msg
;
147 struct imx_sc_chan
*sc_chan
;
153 if (hdr
->size
> IMX_SC_RPC_MAX_MSG
)
156 dev_dbg(sc_ipc
->dev
, "RPC SVC %u FUNC %u SIZE %u\n", hdr
->svc
,
157 hdr
->func
, hdr
->size
);
159 for (i
= 0; i
< hdr
->size
; i
++) {
160 sc_chan
= &sc_ipc
->chans
[i
% 4];
163 * SCU requires that all messages words are written
164 * sequentially but linux MU driver implements multiple
165 * independent channels for each register so ordering between
166 * different channels must be ensured by SCU API interface.
168 * Wait for tx_done before every send to ensure that no
169 * queueing happens at the mailbox channel level.
171 wait_for_completion(&sc_chan
->tx_done
);
172 reinit_completion(&sc_chan
->tx_done
);
174 ret
= mbox_send_message(sc_chan
->ch
, &data
[i
]);
183 * RPC command/response
185 int imx_scu_call_rpc(struct imx_sc_ipc
*sc_ipc
, void *msg
, bool have_resp
)
187 uint8_t saved_svc
, saved_func
;
188 struct imx_sc_rpc_msg
*hdr
;
191 if (WARN_ON(!sc_ipc
|| !msg
))
194 mutex_lock(&sc_ipc
->lock
);
195 reinit_completion(&sc_ipc
->done
);
199 saved_svc
= ((struct imx_sc_rpc_msg
*)msg
)->svc
;
200 saved_func
= ((struct imx_sc_rpc_msg
*)msg
)->func
;
203 ret
= imx_scu_ipc_write(sc_ipc
, msg
);
205 dev_err(sc_ipc
->dev
, "RPC send msg failed: %d\n", ret
);
210 if (!wait_for_completion_timeout(&sc_ipc
->done
,
212 dev_err(sc_ipc
->dev
, "RPC send msg timeout\n");
213 mutex_unlock(&sc_ipc
->lock
);
217 /* response status is stored in hdr->func field */
221 * Some special SCU firmware APIs do NOT have return value
222 * in hdr->func, but they do have response data, those special
223 * APIs are defined as void function in SCU firmware, so they
224 * should be treated as return success always.
226 if ((saved_svc
== IMX_SC_RPC_SVC_MISC
) &&
227 (saved_func
== IMX_SC_MISC_FUNC_UNIQUE_ID
||
228 saved_func
== IMX_SC_MISC_FUNC_GET_BUTTON_STATUS
))
234 mutex_unlock(&sc_ipc
->lock
);
236 dev_dbg(sc_ipc
->dev
, "RPC SVC done\n");
238 return imx_sc_to_linux_errno(ret
);
240 EXPORT_SYMBOL(imx_scu_call_rpc
);
242 static int imx_scu_probe(struct platform_device
*pdev
)
244 struct device
*dev
= &pdev
->dev
;
245 struct imx_sc_ipc
*sc_ipc
;
246 struct imx_sc_chan
*sc_chan
;
247 struct mbox_client
*cl
;
252 sc_ipc
= devm_kzalloc(dev
, sizeof(*sc_ipc
), GFP_KERNEL
);
256 for (i
= 0; i
< SCU_MU_CHAN_NUM
; i
++) {
258 chan_name
= kasprintf(GFP_KERNEL
, "tx%d", i
);
260 chan_name
= kasprintf(GFP_KERNEL
, "rx%d", i
- 4);
265 sc_chan
= &sc_ipc
->chans
[i
];
268 cl
->tx_block
= false;
269 cl
->knows_txdone
= true;
270 cl
->rx_callback
= imx_scu_rx_callback
;
272 /* Initial tx_done completion as "done" */
273 cl
->tx_done
= imx_scu_tx_done
;
274 init_completion(&sc_chan
->tx_done
);
275 complete(&sc_chan
->tx_done
);
277 sc_chan
->sc_ipc
= sc_ipc
;
278 sc_chan
->idx
= i
% 4;
279 sc_chan
->ch
= mbox_request_channel_byname(cl
, chan_name
);
280 if (IS_ERR(sc_chan
->ch
)) {
281 ret
= PTR_ERR(sc_chan
->ch
);
282 if (ret
!= -EPROBE_DEFER
)
283 dev_err(dev
, "Failed to request mbox chan %s ret %d\n",
288 dev_dbg(dev
, "request mbox chan %s\n", chan_name
);
289 /* chan_name is not used anymore by framework */
294 mutex_init(&sc_ipc
->lock
);
295 init_completion(&sc_ipc
->done
);
297 imx_sc_ipc_handle
= sc_ipc
;
299 ret
= imx_scu_enable_general_irq_channel(dev
);
302 "failed to enable general irq channel: %d\n", ret
);
304 dev_info(dev
, "NXP i.MX SCU Initialized\n");
306 return devm_of_platform_populate(dev
);
309 static const struct of_device_id imx_scu_match
[] = {
310 { .compatible
= "fsl,imx-scu", },
314 static struct platform_driver imx_scu_driver
= {
317 .of_match_table
= imx_scu_match
,
319 .probe
= imx_scu_probe
,
321 builtin_platform_driver(imx_scu_driver
);
323 MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
324 MODULE_DESCRIPTION("IMX SCU firmware protocol driver");
325 MODULE_LICENSE("GPL v2");