Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/mtk-adsp-ipc.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (c) 2022 MediaTek Corporation. All rights reserved.
4
* Author: Allen-KH Cheng <[email protected]>
5
*/
6
7
#include <linux/firmware/mediatek/mtk-adsp-ipc.h>
8
#include <linux/kernel.h>
9
#include <linux/mailbox_client.h>
10
#include <linux/module.h>
11
#include <linux/platform_device.h>
12
#include <linux/slab.h>
13
14
static const char * const adsp_mbox_ch_names[MTK_ADSP_MBOX_NUM] = { "rx", "tx" };
15
16
/*
17
* mtk_adsp_ipc_send - send ipc cmd to MTK ADSP
18
*
19
* @ipc: ADSP IPC handle
20
* @idx: index of the mailbox channel
21
* @msg: IPC cmd (reply or request)
22
*
23
* Returns zero for success from mbox_send_message
24
* negative value for error
25
*/
26
int mtk_adsp_ipc_send(struct mtk_adsp_ipc *ipc, unsigned int idx, uint32_t msg)
27
{
28
struct mtk_adsp_chan *adsp_chan;
29
int ret;
30
31
if (idx >= MTK_ADSP_MBOX_NUM)
32
return -EINVAL;
33
34
adsp_chan = &ipc->chans[idx];
35
ret = mbox_send_message(adsp_chan->ch, &msg);
36
if (ret < 0)
37
return ret;
38
39
return 0;
40
}
41
EXPORT_SYMBOL_GPL(mtk_adsp_ipc_send);
42
43
/*
44
* mtk_adsp_ipc_recv - recv callback used by MTK ADSP mailbox
45
*
46
* @c: mbox client
47
* @msg: message received
48
*
49
* Users of ADSP IPC will need to privde handle_reply and handle_request
50
* callbacks.
51
*/
52
static void mtk_adsp_ipc_recv(struct mbox_client *c, void *msg)
53
{
54
struct mtk_adsp_chan *chan = container_of(c, struct mtk_adsp_chan, cl);
55
struct device *dev = c->dev;
56
57
switch (chan->idx) {
58
case MTK_ADSP_MBOX_REPLY:
59
chan->ipc->ops->handle_reply(chan->ipc);
60
break;
61
case MTK_ADSP_MBOX_REQUEST:
62
chan->ipc->ops->handle_request(chan->ipc);
63
break;
64
default:
65
dev_err(dev, "wrong mbox chan %d\n", chan->idx);
66
break;
67
}
68
}
69
70
static int mtk_adsp_ipc_probe(struct platform_device *pdev)
71
{
72
struct device *dev = &pdev->dev;
73
struct mtk_adsp_ipc *adsp_ipc;
74
struct mtk_adsp_chan *adsp_chan;
75
struct mbox_client *cl;
76
int ret;
77
int i, j;
78
79
device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
80
81
adsp_ipc = devm_kzalloc(dev, sizeof(*adsp_ipc), GFP_KERNEL);
82
if (!adsp_ipc)
83
return -ENOMEM;
84
85
for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) {
86
adsp_chan = &adsp_ipc->chans[i];
87
cl = &adsp_chan->cl;
88
cl->dev = dev->parent;
89
cl->tx_block = false;
90
cl->knows_txdone = false;
91
cl->tx_prepare = NULL;
92
cl->rx_callback = mtk_adsp_ipc_recv;
93
94
adsp_chan->ipc = adsp_ipc;
95
adsp_chan->idx = i;
96
adsp_chan->ch = mbox_request_channel_byname(cl, adsp_mbox_ch_names[i]);
97
if (IS_ERR(adsp_chan->ch)) {
98
ret = dev_err_probe(dev, PTR_ERR(adsp_chan->ch),
99
"Failed to request mbox channel %s\n",
100
adsp_mbox_ch_names[i]);
101
102
for (j = 0; j < i; j++) {
103
adsp_chan = &adsp_ipc->chans[j];
104
mbox_free_channel(adsp_chan->ch);
105
}
106
107
return ret;
108
}
109
}
110
111
adsp_ipc->dev = dev;
112
dev_set_drvdata(dev, adsp_ipc);
113
dev_dbg(dev, "MTK ADSP IPC initialized\n");
114
115
return 0;
116
}
117
118
static void mtk_adsp_ipc_remove(struct platform_device *pdev)
119
{
120
struct mtk_adsp_ipc *adsp_ipc = dev_get_drvdata(&pdev->dev);
121
struct mtk_adsp_chan *adsp_chan;
122
int i;
123
124
for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) {
125
adsp_chan = &adsp_ipc->chans[i];
126
mbox_free_channel(adsp_chan->ch);
127
}
128
}
129
130
static struct platform_driver mtk_adsp_ipc_driver = {
131
.driver = {
132
.name = "mtk-adsp-ipc",
133
},
134
.probe = mtk_adsp_ipc_probe,
135
.remove = mtk_adsp_ipc_remove,
136
};
137
builtin_platform_driver(mtk_adsp_ipc_driver);
138
139
MODULE_AUTHOR("Allen-KH Cheng <[email protected]>");
140
MODULE_DESCRIPTION("MTK ADSP IPC Driver");
141
MODULE_LICENSE("GPL");
142
143