diff options
Diffstat (limited to 'drivers/mailbox/imx-mailbox.c')
-rw-r--r-- | drivers/mailbox/imx-mailbox.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index dced4614065f..306af1880415 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -4,6 +4,7 @@ * Copyright 2022 NXP, Peng Fan <peng.fan@nxp.com> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/firmware/imx/ipc.h> #include <linux/firmware/imx/s4.h> @@ -29,7 +30,9 @@ #define IMX_MU_S4_CHANS 2 #define IMX_MU_CHAN_NAME_SIZE 20 -#define IMX_MU_NUM_RR 4 +#define IMX_MU_V2_PAR_OFF 0x4 +#define IMX_MU_V2_TR_MASK GENMASK(7, 0) +#define IMX_MU_V2_RR_MASK GENMASK(15, 8) #define IMX_MU_SECO_TX_TOUT (msecs_to_jiffies(3000)) #define IMX_MU_SECO_RX_TOUT (msecs_to_jiffies(3000)) @@ -93,10 +96,11 @@ struct imx_mu_priv { struct clk *clk; int irq[IMX_MU_CHANS]; bool suspend; - - u32 xcr[IMX_MU_xCR_MAX]; - bool side_b; + + u32 xcr[IMX_MU_xCR_MAX]; + u32 num_tr; + u32 num_rr; }; enum imx_mu_type { @@ -264,18 +268,17 @@ static int imx_mu_generic_rxdb(struct imx_mu_priv *priv, static int imx_mu_specific_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data) { u32 *arg = data; + u32 num_tr = priv->num_tr; int i, ret; u32 xsr; - u32 size, max_size, num_tr; + u32 size, max_size; if (priv->dcfg->type & IMX_MU_V2_S4) { size = ((struct imx_s4_rpc_msg_max *)data)->hdr.size; max_size = sizeof(struct imx_s4_rpc_msg_max); - num_tr = 8; } else { size = ((struct imx_sc_rpc_msg_max *)data)->hdr.size; max_size = sizeof(struct imx_sc_rpc_msg_max); - num_tr = 4; } switch (cp->type) { @@ -324,6 +327,7 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv * int i, ret; u32 xsr; u32 size, max_size; + u32 num_rr = priv->num_rr; data = (u32 *)priv->msg; @@ -345,13 +349,13 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv * for (i = 1; i < size; i++) { ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_RSR], xsr, - xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % 4), 0, + xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % num_rr), 0, 5 * USEC_PER_SEC); if (ret) { dev_err(priv->dev, "timeout read idx %d\n", i); return ret; } - *data++ = imx_mu_read(priv, priv->dcfg->xRR + (i % 4) * 4); + *data++ = imx_mu_read(priv, priv->dcfg->xRR + (i % num_rr) * 4); } imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, 0), 0); @@ -737,11 +741,30 @@ static struct mbox_chan *imx_mu_seco_xlate(struct mbox_controller *mbox, return imx_mu_xlate(mbox, sp); } +static void imx_mu_get_tr_rr(struct imx_mu_priv *priv) +{ + u32 val; + + if (priv->dcfg->type & IMX_MU_V2) { + val = imx_mu_read(priv, IMX_MU_V2_PAR_OFF); + priv->num_tr = FIELD_GET(IMX_MU_V2_TR_MASK, val); + priv->num_rr = FIELD_GET(IMX_MU_V2_RR_MASK, val); + } else { + priv->num_tr = 4; + priv->num_rr = 4; + } +} + static int imx_mu_init_generic(struct imx_mu_priv *priv) { unsigned int i; unsigned int val; + if (priv->num_rr > 4 || priv->num_tr > 4) { + WARN_ONCE(true, "%s not support TR/RR larger than 4\n", __func__); + return -EOPNOTSUPP; + } + for (i = 0; i < IMX_MU_CHANS; i++) { struct imx_mu_con_priv *cp = &priv->con_priv[i]; @@ -768,8 +791,8 @@ static int imx_mu_init_generic(struct imx_mu_priv *priv) imx_mu_write(priv, val, priv->dcfg->xSR[IMX_MU_GSR]); /* Clear any pending RSR */ - for (i = 0; i < IMX_MU_NUM_RR; i++) - imx_mu_read(priv, priv->dcfg->xRR + (i % 4) * 4); + for (i = 0; i < priv->num_rr; i++) + imx_mu_read(priv, priv->dcfg->xRR + i * 4); return 0; } @@ -874,6 +897,8 @@ static int imx_mu_probe(struct platform_device *pdev) return ret; } + imx_mu_get_tr_rr(priv); + priv->side_b = of_property_read_bool(np, "fsl,mu-side-b"); ret = priv->dcfg->init(priv); |