@@ -4,6 +4,7 @@
*/
#include <linux/clk.h>
+#include <linux/firmware/imx/ipc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -65,8 +66,14 @@ struct imx_mu_priv {
int irq;
bool side_b;
+ bool scu;
};
+struct imx_sc_rpc_msg_max {
+ struct imx_sc_rpc_msg hdr;
+ u32 data[7];
+} __packed __aligned(4);;
+
static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = {
.xTR = {0x0, 0x4, 0x8, 0xc},
.xRR = {0x10, 0x14, 0x18, 0x1c},
@@ -123,7 +130,10 @@ static irqreturn_t imx_mu_isr(int irq, void *p)
struct mbox_chan *chan = p;
struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
struct imx_mu_con_priv *cp = chan->con_priv;
+ struct imx_sc_rpc_msg_max msg;
+ u32 *p_msg = (u32 *)&msg;
u32 val, ctrl, dat;
+ int i;
ctrl = imx_mu_read(priv, priv->dcfg->xCR);
val = imx_mu_read(priv, priv->dcfg->xSR);
@@ -152,8 +162,19 @@ static irqreturn_t imx_mu_isr(int irq, void *p)
imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx));
mbox_chan_txdone(chan, 0);
} else if (val == IMX_MU_xSR_RFn(cp->idx)) {
- dat = imx_mu_read(priv, priv->dcfg->xRR[cp->idx]);
- mbox_chan_received_data(chan, (void *)&dat);
+ if (!priv->scu) {
+ dat = imx_mu_read(priv, priv->dcfg->xRR[cp->idx]);
+ mbox_chan_received_data(chan, (void *)&dat);
+ } else {
+ imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_RIEn(0));
+ *p_msg++ = imx_mu_read(priv, priv->dcfg->xRR[0]);
+ for (i = 1; i < msg.hdr.size; i++) {
+ *p_msg++ = imx_mu_read(priv,
+ priv->dcfg->xRR[i % 4]);
+ }
+ imx_mu_xcr_rmw(priv, IMX_MU_xCR_RIEn(0), 0);
+ mbox_chan_received_data(chan, (void *)&msg);
+ }
} else if (val == IMX_MU_xSR_GIPn(cp->idx)) {
imx_mu_write(priv, IMX_MU_xSR_GIPn(cp->idx), priv->dcfg->xSR);
mbox_chan_received_data(chan, NULL);
@@ -169,11 +190,20 @@ static int imx_mu_send_data(struct mbox_chan *chan, void *data)
{
struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
struct imx_mu_con_priv *cp = chan->con_priv;
+ struct imx_sc_rpc_msg_max *msg = data;
u32 *arg = data;
+ int i;
switch (cp->type) {
case IMX_MU_TYPE_TX:
- imx_mu_write(priv, *arg, priv->dcfg->xTR[cp->idx]);
+ if (priv->scu) {
+ for (i = 0; i < msg->hdr.size; i++) {
+ imx_mu_write(priv, *arg++,
+ priv->dcfg->xTR[i % 4]);
+ }
+ } else {
+ imx_mu_write(priv, *arg, priv->dcfg->xTR[cp->idx]);
+ }
imx_mu_xcr_rmw(priv, IMX_MU_xCR_TIEn(cp->idx), 0);
break;
case IMX_MU_TYPE_TXDB:
@@ -259,6 +289,7 @@ static const struct mbox_chan_ops imx_mu_ops = {
static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
const struct of_phandle_args *sp)
{
+ struct imx_mu_priv *priv = to_imx_mu_priv(mbox);
u32 type, idx, chan;
if (sp->args_count != 2) {
@@ -270,7 +301,9 @@ static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
idx = sp->args[1]; /* index */
chan = type * 4 + idx;
- if (chan >= mbox->num_chans) {
+ /* For TX/RX SCU, only one channel supported */
+ if ((chan >= mbox->num_chans) ||
+ (priv->scu && type < 1 && idx >= 1)) {
dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", chan, type, idx);
return ERR_PTR(-EINVAL);
}
@@ -341,6 +374,7 @@ static int imx_mu_probe(struct platform_device *pdev)
}
priv->side_b = of_property_read_bool(np, "fsl,mu-side-b");
+ priv->scu = of_property_read_bool(np, "fsl,scu");
spin_lock_init(&priv->xcr_lock);