Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2022 MediaTek Corporation. All rights reserved.
0004  * Author: Allen-KH Cheng <allen-kh.cheng@mediatek.com>
0005  */
0006 
0007 #include <linux/firmware/mediatek/mtk-adsp-ipc.h>
0008 #include <linux/kernel.h>
0009 #include <linux/mailbox_client.h>
0010 #include <linux/module.h>
0011 #include <linux/of_platform.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/slab.h>
0014 
0015 static const char * const adsp_mbox_ch_names[MTK_ADSP_MBOX_NUM] = { "rx", "tx" };
0016 
0017 /*
0018  * mtk_adsp_ipc_send - send ipc cmd to MTK ADSP
0019  *
0020  * @ipc: ADSP IPC handle
0021  * @idx: index of the mailbox channel
0022  * @msg: IPC cmd (reply or request)
0023  *
0024  * Returns zero for success from mbox_send_message
0025  * negative value for error
0026  */
0027 int mtk_adsp_ipc_send(struct mtk_adsp_ipc *ipc, unsigned int idx, uint32_t msg)
0028 {
0029     struct mtk_adsp_chan *adsp_chan;
0030     int ret;
0031 
0032     if (idx >= MTK_ADSP_MBOX_NUM)
0033         return -EINVAL;
0034 
0035     adsp_chan = &ipc->chans[idx];
0036     ret = mbox_send_message(adsp_chan->ch, &msg);
0037     if (ret < 0)
0038         return ret;
0039 
0040     return 0;
0041 }
0042 EXPORT_SYMBOL_GPL(mtk_adsp_ipc_send);
0043 
0044 /*
0045  * mtk_adsp_ipc_recv - recv callback used by MTK ADSP mailbox
0046  *
0047  * @c: mbox client
0048  * @msg: message received
0049  *
0050  * Users of ADSP IPC will need to privde handle_reply and handle_request
0051  * callbacks.
0052  */
0053 static void mtk_adsp_ipc_recv(struct mbox_client *c, void *msg)
0054 {
0055     struct mtk_adsp_chan *chan = container_of(c, struct mtk_adsp_chan, cl);
0056     struct device *dev = c->dev;
0057 
0058     switch (chan->idx) {
0059     case MTK_ADSP_MBOX_REPLY:
0060         chan->ipc->ops->handle_reply(chan->ipc);
0061         break;
0062     case MTK_ADSP_MBOX_REQUEST:
0063         chan->ipc->ops->handle_request(chan->ipc);
0064         break;
0065     default:
0066         dev_err(dev, "wrong mbox chan %d\n", chan->idx);
0067         break;
0068     }
0069 }
0070 
0071 static int mtk_adsp_ipc_probe(struct platform_device *pdev)
0072 {
0073     struct device *dev = &pdev->dev;
0074     struct mtk_adsp_ipc *adsp_ipc;
0075     struct mtk_adsp_chan *adsp_chan;
0076     struct mbox_client *cl;
0077     int ret;
0078     int i, j;
0079 
0080     device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
0081 
0082     adsp_ipc = devm_kzalloc(dev, sizeof(*adsp_ipc), GFP_KERNEL);
0083     if (!adsp_ipc)
0084         return -ENOMEM;
0085 
0086     for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) {
0087         adsp_chan = &adsp_ipc->chans[i];
0088         cl = &adsp_chan->cl;
0089         cl->dev = dev->parent;
0090         cl->tx_block = false;
0091         cl->knows_txdone = false;
0092         cl->tx_prepare = NULL;
0093         cl->rx_callback = mtk_adsp_ipc_recv;
0094 
0095         adsp_chan->ipc = adsp_ipc;
0096         adsp_chan->idx = i;
0097         adsp_chan->ch = mbox_request_channel_byname(cl, adsp_mbox_ch_names[i]);
0098         if (IS_ERR(adsp_chan->ch)) {
0099             ret = PTR_ERR(adsp_chan->ch);
0100             if (ret != -EPROBE_DEFER)
0101                 dev_err(dev, "Failed to request mbox chan %s ret %d\n",
0102                     adsp_mbox_ch_names[i], ret);
0103 
0104             for (j = 0; j < i; j++) {
0105                 adsp_chan = &adsp_ipc->chans[j];
0106                 mbox_free_channel(adsp_chan->ch);
0107             }
0108 
0109             return ret;
0110         }
0111     }
0112 
0113     adsp_ipc->dev = dev;
0114     dev_set_drvdata(dev, adsp_ipc);
0115     dev_dbg(dev, "MTK ADSP IPC initialized\n");
0116 
0117     return 0;
0118 }
0119 
0120 static int mtk_adsp_ipc_remove(struct platform_device *pdev)
0121 {
0122     struct mtk_adsp_ipc *adsp_ipc = dev_get_drvdata(&pdev->dev);
0123     struct mtk_adsp_chan *adsp_chan;
0124     int i;
0125 
0126     for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) {
0127         adsp_chan = &adsp_ipc->chans[i];
0128         mbox_free_channel(adsp_chan->ch);
0129     }
0130 
0131     return 0;
0132 }
0133 
0134 static struct platform_driver mtk_adsp_ipc_driver = {
0135     .driver = {
0136         .name = "mtk-adsp-ipc",
0137     },
0138     .probe = mtk_adsp_ipc_probe,
0139     .remove = mtk_adsp_ipc_remove,
0140 };
0141 builtin_platform_driver(mtk_adsp_ipc_driver);
0142 
0143 MODULE_AUTHOR("Allen-KH Cheng <allen-kh.cheng@mediatek.com>");
0144 MODULE_DESCRIPTION("MTK ADSP IPC Driver");
0145 MODULE_LICENSE("GPL");