Skip to content

Commit 97961f7

Browse files
MrVanJassiBrar
authored andcommitted
mailbox: imx: support i.MX8ULP S4 MU
Like i.MX8 SCU, i.MX8ULP S4 also has vendor specific protocol. - bind SCU/S4 MU part to share one tx/rx/init API to make code simple. - S4 msg max size is very large, so alloc the space at driver probe, not use local on stack variable. - S4 MU has 8 TR and 4 RR which is different with i.MX8 MU, so adapt code to reflect this. Tested on i.MX8MP, i.MX8ULP Signed-off-by: Peng Fan <[email protected]> Signed-off-by: Jassi Brar <[email protected]>
1 parent a6daa22 commit 97961f7

File tree

2 files changed

+107
-37
lines changed

2 files changed

+107
-37
lines changed

drivers/mailbox/imx-mailbox.c

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <linux/clk.h>
77
#include <linux/firmware/imx/ipc.h>
8+
#include <linux/firmware/imx/s4.h>
89
#include <linux/interrupt.h>
910
#include <linux/io.h>
1011
#include <linux/iopoll.h>
@@ -18,6 +19,8 @@
1819
#define IMX_MU_CHANS 16
1920
/* TX0/RX0/RXDB[0-3] */
2021
#define IMX_MU_SCU_CHANS 6
22+
/* TX0/RX0 */
23+
#define IMX_MU_S4_CHANS 2
2124
#define IMX_MU_CHAN_NAME_SIZE 20
2225

2326
enum imx_mu_chan_type {
@@ -47,6 +50,11 @@ struct imx_sc_rpc_msg_max {
4750
u32 data[7];
4851
};
4952

53+
struct imx_s4_rpc_msg_max {
54+
struct imx_s4_rpc_msg hdr;
55+
u32 data[254];
56+
};
57+
5058
struct imx_mu_con_priv {
5159
unsigned int idx;
5260
char irq_desc[IMX_MU_CHAN_NAME_SIZE];
@@ -58,6 +66,7 @@ struct imx_mu_con_priv {
5866
struct imx_mu_priv {
5967
struct device *dev;
6068
void __iomem *base;
69+
void *msg;
6170
spinlock_t xcr_lock; /* control register lock */
6271

6372
struct mbox_controller mbox;
@@ -75,7 +84,8 @@ struct imx_mu_priv {
7584

7685
enum imx_mu_type {
7786
IMX_MU_V1,
78-
IMX_MU_V2,
87+
IMX_MU_V2 = BIT(1),
88+
IMX_MU_V2_S4 = BIT(15),
7989
};
8090

8191
struct imx_mu_dcfg {
@@ -89,18 +99,18 @@ struct imx_mu_dcfg {
8999
u32 xCR[4]; /* Control Registers */
90100
};
91101

92-
#define IMX_MU_xSR_GIPn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
93-
#define IMX_MU_xSR_RFn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
94-
#define IMX_MU_xSR_TEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
102+
#define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
103+
#define IMX_MU_xSR_RFn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
104+
#define IMX_MU_xSR_TEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
95105

96106
/* General Purpose Interrupt Enable */
97-
#define IMX_MU_xCR_GIEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
107+
#define IMX_MU_xCR_GIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
98108
/* Receive Interrupt Enable */
99-
#define IMX_MU_xCR_RIEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
109+
#define IMX_MU_xCR_RIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
100110
/* Transmit Interrupt Enable */
101-
#define IMX_MU_xCR_TIEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
111+
#define IMX_MU_xCR_TIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
102112
/* General Purpose Interrupt Request */
103-
#define IMX_MU_xCR_GIRn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(16 + (3 - (x))))
113+
#define IMX_MU_xCR_GIRn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(16 + (3 - (x))))
104114

105115

106116
static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
@@ -167,14 +177,22 @@ static int imx_mu_generic_rx(struct imx_mu_priv *priv,
167177
return 0;
168178
}
169179

170-
static int imx_mu_scu_tx(struct imx_mu_priv *priv,
171-
struct imx_mu_con_priv *cp,
172-
void *data)
180+
static int imx_mu_specific_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data)
173181
{
174-
struct imx_sc_rpc_msg_max *msg = data;
175182
u32 *arg = data;
176183
int i, ret;
177184
u32 xsr;
185+
u32 size, max_size, num_tr;
186+
187+
if (priv->dcfg->type & IMX_MU_V2_S4) {
188+
size = ((struct imx_s4_rpc_msg_max *)data)->hdr.size;
189+
max_size = sizeof(struct imx_s4_rpc_msg_max);
190+
num_tr = 8;
191+
} else {
192+
size = ((struct imx_sc_rpc_msg_max *)data)->hdr.size;
193+
max_size = sizeof(struct imx_sc_rpc_msg_max);
194+
num_tr = 4;
195+
}
178196

179197
switch (cp->type) {
180198
case IMX_MU_TYPE_TX:
@@ -183,27 +201,27 @@ static int imx_mu_scu_tx(struct imx_mu_priv *priv,
183201
* sizeof yields bytes.
184202
*/
185203

186-
if (msg->hdr.size > sizeof(*msg) / 4) {
204+
if (size > max_size / 4) {
187205
/*
188206
* The real message size can be different to
189-
* struct imx_sc_rpc_msg_max size
207+
* struct imx_sc_rpc_msg_max/imx_s4_rpc_msg_max size
190208
*/
191-
dev_err(priv->dev, "Maximal message size (%zu bytes) exceeded on TX; got: %i bytes\n", sizeof(*msg), msg->hdr.size << 2);
209+
dev_err(priv->dev, "Maximal message size (%u bytes) exceeded on TX; got: %i bytes\n", max_size, size << 2);
192210
return -EINVAL;
193211
}
194212

195-
for (i = 0; i < 4 && i < msg->hdr.size; i++)
196-
imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % 4) * 4);
197-
for (; i < msg->hdr.size; i++) {
213+
for (i = 0; i < num_tr && i < size; i++)
214+
imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % num_tr) * 4);
215+
for (; i < size; i++) {
198216
ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_TSR],
199217
xsr,
200-
xsr & IMX_MU_xSR_TEn(priv->dcfg->type, i % 4),
218+
xsr & IMX_MU_xSR_TEn(priv->dcfg->type, i % num_tr),
201219
0, 100);
202220
if (ret) {
203221
dev_err(priv->dev, "Send data index: %d timeout\n", i);
204222
return ret;
205223
}
206-
imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % 4) * 4);
224+
imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % num_tr) * 4);
207225
}
208226

209227
imx_mu_xcr_rmw(priv, IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx), 0);
@@ -216,23 +234,32 @@ static int imx_mu_scu_tx(struct imx_mu_priv *priv,
216234
return 0;
217235
}
218236

219-
static int imx_mu_scu_rx(struct imx_mu_priv *priv,
220-
struct imx_mu_con_priv *cp)
237+
static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp)
221238
{
222-
struct imx_sc_rpc_msg_max msg;
223-
u32 *data = (u32 *)&msg;
239+
u32 *data;
224240
int i, ret;
225241
u32 xsr;
242+
u32 size, max_size;
243+
244+
data = (u32 *)priv->msg;
226245

227246
imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, 0));
228247
*data++ = imx_mu_read(priv, priv->dcfg->xRR);
229248

230-
if (msg.hdr.size > sizeof(msg) / 4) {
231-
dev_err(priv->dev, "Maximal message size (%zu bytes) exceeded on RX; got: %i bytes\n", sizeof(msg), msg.hdr.size << 2);
249+
if (priv->dcfg->type & IMX_MU_V2_S4) {
250+
size = ((struct imx_s4_rpc_msg_max *)priv->msg)->hdr.size;
251+
max_size = sizeof(struct imx_s4_rpc_msg_max);
252+
} else {
253+
size = ((struct imx_sc_rpc_msg_max *)priv->msg)->hdr.size;
254+
max_size = sizeof(struct imx_sc_rpc_msg_max);
255+
}
256+
257+
if (size > max_size / 4) {
258+
dev_err(priv->dev, "Maximal message size (%u bytes) exceeded on RX; got: %i bytes\n", max_size, size << 2);
232259
return -EINVAL;
233260
}
234261

235-
for (i = 1; i < msg.hdr.size; i++) {
262+
for (i = 1; i < size; i++) {
236263
ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_RSR], xsr,
237264
xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % 4), 0, 100);
238265
if (ret) {
@@ -243,7 +270,7 @@ static int imx_mu_scu_rx(struct imx_mu_priv *priv,
243270
}
244271

245272
imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, 0), 0);
246-
mbox_chan_received_data(cp->chan, (void *)&msg);
273+
mbox_chan_received_data(cp->chan, (void *)priv->msg);
247274

248275
return 0;
249276
}
@@ -394,8 +421,8 @@ static const struct mbox_chan_ops imx_mu_ops = {
394421
.shutdown = imx_mu_shutdown,
395422
};
396423

397-
static struct mbox_chan *imx_mu_scu_xlate(struct mbox_controller *mbox,
398-
const struct of_phandle_args *sp)
424+
static struct mbox_chan *imx_mu_specific_xlate(struct mbox_controller *mbox,
425+
const struct of_phandle_args *sp)
399426
{
400427
u32 type, idx, chan;
401428

@@ -478,11 +505,12 @@ static void imx_mu_init_generic(struct imx_mu_priv *priv)
478505
imx_mu_write(priv, 0, priv->dcfg->xCR[i]);
479506
}
480507

481-
static void imx_mu_init_scu(struct imx_mu_priv *priv)
508+
static void imx_mu_init_specific(struct imx_mu_priv *priv)
482509
{
483510
unsigned int i;
511+
int num_chans = priv->dcfg->type & IMX_MU_V2_S4 ? IMX_MU_S4_CHANS : IMX_MU_SCU_CHANS;
484512

485-
for (i = 0; i < IMX_MU_SCU_CHANS; i++) {
513+
for (i = 0; i < num_chans; i++) {
486514
struct imx_mu_con_priv *cp = &priv->con_priv[i];
487515

488516
cp->idx = i < 2 ? 0 : i - 2;
@@ -493,8 +521,8 @@ static void imx_mu_init_scu(struct imx_mu_priv *priv)
493521
"imx_mu_chan[%i-%i]", cp->type, cp->idx);
494522
}
495523

496-
priv->mbox.num_chans = IMX_MU_SCU_CHANS;
497-
priv->mbox.of_xlate = imx_mu_scu_xlate;
524+
priv->mbox.num_chans = num_chans;
525+
priv->mbox.of_xlate = imx_mu_specific_xlate;
498526

499527
/* Set default MU configuration */
500528
for (i = 0; i < IMX_MU_xCR_MAX; i++)
@@ -508,6 +536,7 @@ static int imx_mu_probe(struct platform_device *pdev)
508536
struct imx_mu_priv *priv;
509537
const struct imx_mu_dcfg *dcfg;
510538
int ret;
539+
u32 size;
511540

512541
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
513542
if (!priv)
@@ -528,6 +557,15 @@ static int imx_mu_probe(struct platform_device *pdev)
528557
return -EINVAL;
529558
priv->dcfg = dcfg;
530559

560+
if (priv->dcfg->type & IMX_MU_V2_S4)
561+
size = sizeof(struct imx_s4_rpc_msg_max);
562+
else
563+
size = sizeof(struct imx_sc_rpc_msg_max);
564+
565+
priv->msg = devm_kzalloc(dev, size, GFP_KERNEL);
566+
if (IS_ERR(priv->msg))
567+
return PTR_ERR(priv->msg);
568+
531569
priv->clk = devm_clk_get(dev, NULL);
532570
if (IS_ERR(priv->clk)) {
533571
if (PTR_ERR(priv->clk) != -ENOENT)
@@ -623,10 +661,21 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = {
623661
.xCR = {0x110, 0x114, 0x120, 0x128},
624662
};
625663

664+
static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp_s4 = {
665+
.tx = imx_mu_specific_tx,
666+
.rx = imx_mu_specific_rx,
667+
.init = imx_mu_init_specific,
668+
.type = IMX_MU_V2 | IMX_MU_V2_S4,
669+
.xTR = 0x200,
670+
.xRR = 0x280,
671+
.xSR = {0xC, 0x118, 0x124, 0x12C},
672+
.xCR = {0x110, 0x114, 0x120, 0x128},
673+
};
674+
626675
static const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = {
627-
.tx = imx_mu_scu_tx,
628-
.rx = imx_mu_scu_rx,
629-
.init = imx_mu_init_scu,
676+
.tx = imx_mu_specific_tx,
677+
.rx = imx_mu_specific_rx,
678+
.init = imx_mu_init_specific,
630679
.xTR = 0x0,
631680
.xRR = 0x10,
632681
.xSR = {0x20, 0x20, 0x20, 0x20},
@@ -637,6 +686,7 @@ static const struct of_device_id imx_mu_dt_ids[] = {
637686
{ .compatible = "fsl,imx7ulp-mu", .data = &imx_mu_cfg_imx7ulp },
638687
{ .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx },
639688
{ .compatible = "fsl,imx8ulp-mu", .data = &imx_mu_cfg_imx8ulp },
689+
{ .compatible = "fsl,imx8ulp-mu-s4", .data = &imx_mu_cfg_imx8ulp_s4 },
640690
{ .compatible = "fsl,imx8-mu-scu", .data = &imx_mu_cfg_imx8_scu },
641691
{ },
642692
};

include/linux/firmware/imx/s4.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* SPDX-License-Identifier: GPL-2.0+ */
2+
/*
3+
* Copyright 2021 NXP
4+
*
5+
* Header file for the IPC implementation.
6+
*/
7+
8+
#ifndef _S4_IPC_H
9+
#define _S4_IPC_H
10+
11+
struct imx_s4_ipc;
12+
13+
struct imx_s4_rpc_msg {
14+
uint8_t ver;
15+
uint8_t size;
16+
uint8_t cmd;
17+
uint8_t tag;
18+
} __packed;
19+
20+
#endif /* _S4_IPC_H */

0 commit comments

Comments
 (0)