diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index c7d18230c37d..2b165fda9954 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -138,6 +138,29 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg) complete(&sc_ipc->done); } +static void imx_scu_big_rx_callback(struct mbox_client *c, void *msg) +{ + struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl); + struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc; + struct imx_sc_rpc_msg *hdr; + u32 *data = msg; + + if (sc_ipc->count == 0) { + hdr = msg; + sc_ipc->rx_size = hdr->size; + dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size); + } + + sc_ipc->msg[sc_ipc->count] = *data; + sc_ipc->count++; + + dev_dbg(sc_ipc->dev, "mu %u msg %u 0x%x\n", sc_chan->idx, + sc_ipc->count, *data); + + if (sc_ipc->count == sc_ipc->rx_size) + complete(&sc_ipc->done); +} + static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg) { struct imx_sc_rpc_msg hdr = *(struct imx_sc_rpc_msg *)msg; @@ -232,6 +255,71 @@ out: } EXPORT_SYMBOL(imx_scu_call_rpc); +int imx_scu_call_big_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) +{ + struct imx_sc_rpc_msg *hdr; + struct arm_smccc_res res; + int ret; + int i; + + if (WARN_ON(!sc_ipc || !msg)) + return -EINVAL; + + mutex_lock(&sc_ipc->lock); + for (i = 4; i < 8; i++) { + struct mbox_client *cl = &sc_ipc->chans[i].cl; + + cl->rx_callback = imx_scu_big_rx_callback; + } + + reinit_completion(&sc_ipc->done); + + sc_ipc->msg = msg; + sc_ipc->count = 0; + sc_ipc->rx_size = 0; + if (xen_initial_domain()) { + arm_smccc_hvc(FSL_HVC_SC, (uint64_t)msg, !have_resp, 0, 0, 0, + 0, 0, &res); + if (res.a0) + printk("Error FSL_HVC_SC %ld\n", res.a0); + + ret = res.a0; + + } else { + ret = imx_scu_ipc_write(sc_ipc, msg); + if (ret < 0) { + dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret); + goto out; + } + + if (have_resp) { + if (!wait_for_completion_timeout(&sc_ipc->done, + MAX_RX_TIMEOUT)) { + dev_err(sc_ipc->dev, "RPC send msg timeout\n"); + mutex_unlock(&sc_ipc->lock); + return -ETIMEDOUT; + } + + /* response status is stored in hdr->func field */ + hdr = msg; + ret = hdr->func; + } + } + +out: + for (i = 4; i < 8; i++) { + struct mbox_client *cl = &sc_ipc->chans[i].cl; + + cl->rx_callback = imx_scu_rx_callback; + } + mutex_unlock(&sc_ipc->lock); + + dev_dbg(sc_ipc->dev, "RPC SVC done\n"); + + return imx_sc_to_linux_errno(ret); +} +EXPORT_SYMBOL(imx_scu_call_big_rpc); + static int imx_scu_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; diff --git a/include/linux/firmware/imx/ipc.h b/include/linux/firmware/imx/ipc.h index 713400ec3595..a0491a9c0b7a 100644 --- a/include/linux/firmware/imx/ipc.h +++ b/include/linux/firmware/imx/ipc.h @@ -48,6 +48,8 @@ struct imx_sc_rpc_msg { * and returns the result in msg. */ int imx_scu_call_rpc(struct imx_sc_ipc *ipc, void *msg, bool have_resp); +int imx_scu_call_big_rpc(struct imx_sc_ipc *ipc, void *msg, bool have_resp); + /* * This function gets the default ipc handle used by SCU @@ -65,6 +67,13 @@ imx_scu_call_rpc(struct imx_sc_ipc *ipc, void *msg, bool have_resp) } +static inline int +imx_scu_call_big_rpc(struct imx_sc_ipc *ipc, void *msg, bool have_resp) +{ + return -EIO; + +} + static inline int imx_scu_get_handle(struct imx_sc_ipc **ipc) { return -EIO;