Skip to content

Commit 11dac1d

Browse files
lenormandfranckJassiBrar
authored andcommitted
mailbox: imx: add i.MX8 SECO MU support
i.MX8/8X SECO firmware IPC is an implementation of passing messages. But current imx-mailbox driver only support one word message, i.MX8/8X linux side firmware has to request four TX, four RX and a TXDB to support IPC to SECO firmware. This is low efficent and more interrupts triggered compared with one TX and one RX. To make SECO MU work, - parse the size of msg. - Only enable TR0/RR0 interrupt for transmit/receive message. - For TX/RX, only support one TX channel and one RX channel - For RX, support receive msg of any size, limited by hardcoded value of 30. Signed-off-by: Franck LENORMAND <[email protected]> Signed-off-by: Peng Fan <[email protected]> Signed-off-by: Jassi Brar <[email protected]>
1 parent 315d2e5 commit 11dac1d

File tree

1 file changed

+212
-1
lines changed

1 file changed

+212
-1
lines changed

drivers/mailbox/imx-mailbox.c

Lines changed: 212 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/interrupt.h>
1010
#include <linux/io.h>
1111
#include <linux/iopoll.h>
12+
#include <linux/jiffies.h>
1213
#include <linux/kernel.h>
1314
#include <linux/mailbox_controller.h>
1415
#include <linux/module.h>
@@ -24,6 +25,9 @@
2425
#define IMX_MU_S4_CHANS 2
2526
#define IMX_MU_CHAN_NAME_SIZE 20
2627

28+
#define IMX_MU_SECO_TX_TOUT (msecs_to_jiffies(3000))
29+
#define IMX_MU_SECO_RX_TOUT (msecs_to_jiffies(3000))
30+
2731
enum imx_mu_chan_type {
2832
IMX_MU_TYPE_TX, /* Tx */
2933
IMX_MU_TYPE_RX, /* Rx */
@@ -48,7 +52,7 @@ enum imx_mu_xsr {
4852

4953
struct imx_sc_rpc_msg_max {
5054
struct imx_sc_rpc_msg hdr;
51-
u32 data[7];
55+
u32 data[30];
5256
};
5357

5458
struct imx_s4_rpc_msg_max {
@@ -131,6 +135,55 @@ static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs)
131135
return ioread32(priv->base + offs);
132136
}
133137

138+
static int imx_mu_tx_waiting_write(struct imx_mu_priv *priv, u32 val, u32 idx)
139+
{
140+
u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_TX_TOUT;
141+
u32 status;
142+
u32 can_write;
143+
144+
dev_dbg(priv->dev, "Trying to write %.8x to idx %d\n", val, idx);
145+
146+
do {
147+
status = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_TSR]);
148+
can_write = status & IMX_MU_xSR_TEn(priv->dcfg->type, idx % 4);
149+
} while (!can_write && time_is_after_jiffies64(timeout_time));
150+
151+
if (!can_write) {
152+
dev_err(priv->dev, "timeout trying to write %.8x at %d(%.8x)\n",
153+
val, idx, status);
154+
return -ETIME;
155+
}
156+
157+
imx_mu_write(priv, val, priv->dcfg->xTR + (idx % 4) * 4);
158+
159+
return 0;
160+
}
161+
162+
static int imx_mu_rx_waiting_read(struct imx_mu_priv *priv, u32 *val, u32 idx)
163+
{
164+
u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_RX_TOUT;
165+
u32 status;
166+
u32 can_read;
167+
168+
dev_dbg(priv->dev, "Trying to read from idx %d\n", idx);
169+
170+
do {
171+
status = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_RSR]);
172+
can_read = status & IMX_MU_xSR_RFn(priv->dcfg->type, idx % 4);
173+
} while (!can_read && time_is_after_jiffies64(timeout_time));
174+
175+
if (!can_read) {
176+
dev_err(priv->dev, "timeout trying to read idx %d (%.8x)\n",
177+
idx, status);
178+
return -ETIME;
179+
}
180+
181+
*val = imx_mu_read(priv, priv->dcfg->xRR + (idx % 4) * 4);
182+
dev_dbg(priv->dev, "Read %.8x\n", *val);
183+
184+
return 0;
185+
}
186+
134187
static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, enum imx_mu_xcr type, u32 set, u32 clr)
135188
{
136189
unsigned long flags;
@@ -289,6 +342,125 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv *
289342
return 0;
290343
}
291344

345+
static int imx_mu_seco_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp,
346+
void *data)
347+
{
348+
struct imx_sc_rpc_msg_max *msg = data;
349+
u32 *arg = data;
350+
u32 byte_size;
351+
int err;
352+
int i;
353+
354+
dev_dbg(priv->dev, "Sending message\n");
355+
356+
switch (cp->type) {
357+
case IMX_MU_TYPE_TXDB:
358+
byte_size = msg->hdr.size * sizeof(u32);
359+
if (byte_size > sizeof(*msg)) {
360+
/*
361+
* The real message size can be different to
362+
* struct imx_sc_rpc_msg_max size
363+
*/
364+
dev_err(priv->dev,
365+
"Exceed max msg size (%zu) on TX, got: %i\n",
366+
sizeof(*msg), byte_size);
367+
return -EINVAL;
368+
}
369+
370+
print_hex_dump_debug("from client ", DUMP_PREFIX_OFFSET, 4, 4,
371+
data, byte_size, false);
372+
373+
/* Send first word */
374+
dev_dbg(priv->dev, "Sending header\n");
375+
imx_mu_write(priv, *arg++, priv->dcfg->xTR);
376+
377+
/* Send signaling */
378+
dev_dbg(priv->dev, "Sending signaling\n");
379+
imx_mu_xcr_rmw(priv, IMX_MU_GCR,
380+
IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 0);
381+
382+
/* Send words to fill the mailbox */
383+
for (i = 1; i < 4 && i < msg->hdr.size; i++) {
384+
dev_dbg(priv->dev, "Sending word %d\n", i);
385+
imx_mu_write(priv, *arg++,
386+
priv->dcfg->xTR + (i % 4) * 4);
387+
}
388+
389+
/* Send rest of message waiting for remote read */
390+
for (; i < msg->hdr.size; i++) {
391+
dev_dbg(priv->dev, "Sending word %d\n", i);
392+
err = imx_mu_tx_waiting_write(priv, *arg++, i);
393+
if (err) {
394+
dev_err(priv->dev, "Timeout tx %d\n", i);
395+
return err;
396+
}
397+
}
398+
399+
/* Simulate hack for mbox framework */
400+
tasklet_schedule(&cp->txdb_tasklet);
401+
402+
break;
403+
default:
404+
dev_warn_ratelimited(priv->dev,
405+
"Send data on wrong channel type: %d\n",
406+
cp->type);
407+
return -EINVAL;
408+
}
409+
410+
return 0;
411+
}
412+
413+
static int imx_mu_seco_rxdb(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp)
414+
{
415+
struct imx_sc_rpc_msg_max msg;
416+
u32 *data = (u32 *)&msg;
417+
u32 byte_size;
418+
int err = 0;
419+
int i;
420+
421+
dev_dbg(priv->dev, "Receiving message\n");
422+
423+
/* Read header */
424+
dev_dbg(priv->dev, "Receiving header\n");
425+
*data++ = imx_mu_read(priv, priv->dcfg->xRR);
426+
byte_size = msg.hdr.size * sizeof(u32);
427+
if (byte_size > sizeof(msg)) {
428+
dev_err(priv->dev, "Exceed max msg size (%zu) on RX, got: %i\n",
429+
sizeof(msg), byte_size);
430+
err = -EINVAL;
431+
goto error;
432+
}
433+
434+
/* Read message waiting they are written */
435+
for (i = 1; i < msg.hdr.size; i++) {
436+
dev_dbg(priv->dev, "Receiving word %d\n", i);
437+
err = imx_mu_rx_waiting_read(priv, data++, i);
438+
if (err) {
439+
dev_err(priv->dev, "Timeout rx %d\n", i);
440+
goto error;
441+
}
442+
}
443+
444+
/* Clear GIP */
445+
imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx),
446+
priv->dcfg->xSR[IMX_MU_GSR]);
447+
448+
print_hex_dump_debug("to client ", DUMP_PREFIX_OFFSET, 4, 4,
449+
&msg, byte_size, false);
450+
451+
/* send data to client */
452+
dev_dbg(priv->dev, "Sending message to client\n");
453+
mbox_chan_received_data(cp->chan, (void *)&msg);
454+
455+
goto exit;
456+
457+
error:
458+
mbox_chan_received_data(cp->chan, ERR_PTR(err));
459+
460+
exit:
461+
return err;
462+
}
463+
292464
static void imx_mu_txdb_tasklet(unsigned long data)
293465
{
294466
struct imx_mu_con_priv *cp = (struct imx_mu_con_priv *)data;
@@ -494,6 +666,27 @@ static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
494666
return &mbox->chans[chan];
495667
}
496668

669+
static struct mbox_chan *imx_mu_seco_xlate(struct mbox_controller *mbox,
670+
const struct of_phandle_args *sp)
671+
{
672+
u32 type;
673+
674+
if (sp->args_count < 1) {
675+
dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count);
676+
return ERR_PTR(-EINVAL);
677+
}
678+
679+
type = sp->args[0]; /* channel type */
680+
681+
/* Only supports TXDB and RXDB */
682+
if (type == IMX_MU_TYPE_TX || type == IMX_MU_TYPE_RX) {
683+
dev_err(mbox->dev, "Invalid type: %d\n", type);
684+
return ERR_PTR(-EINVAL);
685+
}
686+
687+
return imx_mu_xlate(mbox, sp);
688+
}
689+
497690
static void imx_mu_init_generic(struct imx_mu_priv *priv)
498691
{
499692
unsigned int i;
@@ -544,6 +737,12 @@ static void imx_mu_init_specific(struct imx_mu_priv *priv)
544737
imx_mu_write(priv, 0, priv->dcfg->xCR[i]);
545738
}
546739

740+
static void imx_mu_init_seco(struct imx_mu_priv *priv)
741+
{
742+
imx_mu_init_generic(priv);
743+
priv->mbox.of_xlate = imx_mu_seco_xlate;
744+
}
745+
547746
static int imx_mu_probe(struct platform_device *pdev)
548747
{
549748
struct device *dev = &pdev->dev;
@@ -702,12 +901,24 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = {
702901
.xCR = {0x24, 0x24, 0x24, 0x24},
703902
};
704903

904+
static const struct imx_mu_dcfg imx_mu_cfg_imx8_seco = {
905+
.tx = imx_mu_seco_tx,
906+
.rx = imx_mu_generic_rx,
907+
.rxdb = imx_mu_seco_rxdb,
908+
.init = imx_mu_init_seco,
909+
.xTR = 0x0,
910+
.xRR = 0x10,
911+
.xSR = {0x20, 0x20, 0x20, 0x20},
912+
.xCR = {0x24, 0x24, 0x24, 0x24},
913+
};
914+
705915
static const struct of_device_id imx_mu_dt_ids[] = {
706916
{ .compatible = "fsl,imx7ulp-mu", .data = &imx_mu_cfg_imx7ulp },
707917
{ .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx },
708918
{ .compatible = "fsl,imx8ulp-mu", .data = &imx_mu_cfg_imx8ulp },
709919
{ .compatible = "fsl,imx8ulp-mu-s4", .data = &imx_mu_cfg_imx8ulp_s4 },
710920
{ .compatible = "fsl,imx8-mu-scu", .data = &imx_mu_cfg_imx8_scu },
921+
{ .compatible = "fsl,imx8-mu-seco", .data = &imx_mu_cfg_imx8_seco },
711922
{ },
712923
};
713924
MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);

0 commit comments

Comments
 (0)