1 /* Copyright 2023 The ChromiumOS Authors
2 * SPDX-License-Identifier: Apache-2.0
3 */
4
5 #include <zephyr/device.h>
6 #include <zephyr/irq.h>
7 #include <zephyr/devicetree.h>
8 #include <soc.h>
9
10 #define DT_DRV_COMPAT mediatek_mbox
11
12 /* Mailbox: a simple interrupt source. Each direction has a 5-bit
13 * command register and will latch an interrupt if any of the bits are
14 * non-zero. The interrupt bits get cleared/acknowledged by writing
15 * ones to the corresponding bits of "cmd_clear". There are five
16 * scratch registers for use as message data in each direction.
17 *
18 * The same device is mapped at the same address by the host and DSP,
19 * and the naming is from the perspective of the DSP: the "in"
20 * registers control interrupts on the DSP, the "out" registers are
21 * for transmitting data to the host.
22 *
23 * There is an array of the devices. Linux's device-tree defines two.
24 * SOF uses those for IPC, but also implements platform_trace_point()
25 * using the third (no linux driver though?). The upstream headers
26 * list interrupts for FIVE, and indeed those all seem to be present
27 * and working.
28 *
29 * In practice: The first device (mbox0) is for IPC commands in both
30 * directions. The cmd register is written with a 1 ("IPI_OP_REQ")
31 * and the command is placed in shared DRAM.
32 *
33 * Note that the 8195 has ten "msg" registers. These only exist on
34 * this version of the hardware, and act as uninspected r/w scratch
35 * registers to both the host and DSP, with no other behavior. They
36 * aren't used by the Linux kernel at all (which has a single driver
37 * for all these DSPs), so are described here for completeness but
38 * otherwise ignored. In practice they don't do anything that simple
39 * shared memory can't.
40 */
41
42 struct mtk_mbox {
43 #ifdef SOC_SERIES_MT8195
44 uint32_t in_cmd;
45 uint32_t in_cmd_clr;
46 uint32_t in_msg[5];
47 uint32_t out_cmd;
48 uint32_t out_cmd_clr;
49 uint32_t out_msg[5];
50 #else
51 uint32_t in_cmd;
52 uint32_t out_cmd;
53 uint32_t in_cmd_clr;
54 uint32_t out_cmd_clr;
55 #endif
56 };
57
58 struct mbox_cfg {
59 volatile struct mtk_mbox *mbox;
60 uint32_t irq;
61 };
62
63 struct mbox_data {
64 mtk_adsp_mbox_handler_t handlers[MTK_ADSP_MBOX_CHANNELS];
65 void *handler_arg[MTK_ADSP_MBOX_CHANNELS];
66 };
67
mtk_adsp_mbox_set_handler(const struct device * mbox,uint32_t chan,mtk_adsp_mbox_handler_t handler,void * arg)68 void mtk_adsp_mbox_set_handler(const struct device *mbox, uint32_t chan,
69 mtk_adsp_mbox_handler_t handler, void *arg)
70 {
71 struct mbox_data *data = ((struct device *)mbox)->data;
72
73 if (chan < MTK_ADSP_MBOX_CHANNELS) {
74 data->handlers[chan] = handler;
75 data->handler_arg[chan] = arg;
76 }
77 }
78
mtk_adsp_mbox_signal(const struct device * mbox,uint32_t chan)79 void mtk_adsp_mbox_signal(const struct device *mbox, uint32_t chan)
80 {
81 const struct mbox_cfg *cfg = ((struct device *)mbox)->config;
82
83 if (chan < MTK_ADSP_MBOX_CHANNELS) {
84 cfg->mbox->out_cmd |= BIT(chan);
85 }
86 }
87
mbox_isr(const void * arg)88 static void mbox_isr(const void *arg)
89 {
90 const struct mbox_cfg *cfg = ((struct device *)arg)->config;
91 struct mbox_data *data = ((struct device *)arg)->data;
92
93 for (int i = 0; i < MTK_ADSP_MBOX_CHANNELS; i++) {
94 if (cfg->mbox->in_cmd & BIT(i)) {
95 if (data->handlers[i] != NULL) {
96 data->handlers[i](arg, data->handler_arg[i]);
97 }
98 }
99 }
100
101 cfg->mbox->in_cmd_clr = cfg->mbox->in_cmd; /* ACK */
102 }
103
104 #define DEF_IRQ(N) \
105 { IRQ_CONNECT(DT_INST_IRQN(N), 0, mbox_isr, DEVICE_DT_INST_GET(N), 0); \
106 irq_enable(DT_INST_IRQN(N)); }
107
108
mbox_init(void)109 static int mbox_init(void)
110 {
111 DT_INST_FOREACH_STATUS_OKAY(DEF_IRQ);
112 return 0;
113 }
114
115 SYS_INIT(mbox_init, POST_KERNEL, 0);
116
117 #define DEF_DEV(N) \
118 static struct mbox_data dev_data##N; \
119 static const struct mbox_cfg dev_cfg##N = \
120 { .irq = DT_INST_IRQN(N), .mbox = (void *)DT_INST_REG_ADDR(N), }; \
121 DEVICE_DT_INST_DEFINE(N, NULL, NULL, &dev_data##N, &dev_cfg##N, \
122 POST_KERNEL, 0, NULL);
123
124 DT_INST_FOREACH_STATUS_OKAY(DEF_DEV)
125