1 /*
2  * Copyright (c) 2024 Texas Instruments Incorporated.
3  *
4  * TI OMAP Mailbox driver for Zephyr's MBOX model.
5  */
6 
7 #include <zephyr/devicetree.h>
8 #include <zephyr/drivers/mbox.h>
9 #include <zephyr/irq.h>
10 #include <zephyr/spinlock.h>
11 #define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(ti_omap_mailbox);
14 
15 #define DT_DRV_COMPAT ti_omap_mailbox
16 
17 #define MAILBOX_IRQ_NEWMSG(m)  (1 << (2 * (m)))
18 #define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
19 #define OMAP_MAILBOX_NUM_MSGS  16
20 #define MAILBOX_MAX_CHANNELS   16
21 #define OMAP_MAILBOX_NUM_USERS 4
22 #define MAILBOX_MBOX_SIZE      sizeof(uint32_t)
23 
24 #define DEV_CFG(_dev)     ((const struct omap_mailbox_config *)(_dev)->config)
25 #define DEV_DATA(_dev)    ((struct omap_mailbox_data *)(_dev)->data)
26 #define DEV_REG_BASE(dev) ((struct omap_mailbox_regs *)DEVICE_MMIO_NAMED_GET(dev, reg_base))
27 
28 struct omap_mailbox_data {
29 	DEVICE_MMIO_NAMED_RAM(reg_base);
30 	mbox_callback_t cb[MAILBOX_MAX_CHANNELS];
31 	void *user_data[MAILBOX_MAX_CHANNELS];
32 	bool channel_enable[MAILBOX_MAX_CHANNELS];
33 	uint32_t received_data;
34 	struct k_spinlock lock;
35 };
36 
37 struct omap_mailbox_config {
38 	DEVICE_MMIO_NAMED_ROM(reg_base);
39 	uint32_t irq;
40 	uint32_t usr_id;
41 };
42 
43 struct omap_mailbox_irq_regs {
44 	uint32_t status_raw;
45 	uint32_t status_clear;
46 	uint32_t enable_set;
47 	uint32_t enable_clear;
48 };
49 
50 struct omap_mailbox_regs {
51 	uint32_t revision;
52 	uint32_t __pad0[3];
53 	uint32_t sysconfig;
54 	uint32_t __pad1[11];
55 	uint32_t message[OMAP_MAILBOX_NUM_MSGS];
56 	uint32_t fifo_status[OMAP_MAILBOX_NUM_MSGS];
57 	uint32_t msg_status[OMAP_MAILBOX_NUM_MSGS];
58 	struct omap_mailbox_irq_regs irq_regs[OMAP_MAILBOX_NUM_USERS];
59 };
60 
omap_mailbox_isr(const struct device * dev)61 static void omap_mailbox_isr(const struct device *dev)
62 {
63 	volatile struct omap_mailbox_regs *regs = DEV_REG_BASE(dev);
64 	const struct omap_mailbox_config *cfg = DEV_CFG(dev);
65 	struct omap_mailbox_data *data = DEV_DATA(dev);
66 
67 	uint32_t irq_enabled = regs->irq_regs[cfg->usr_id].enable_set;
68 	uint32_t flags = regs->irq_regs[cfg->usr_id].status_clear;
69 
70 	regs->irq_regs[cfg->usr_id].enable_set = 0;
71 
72 	for (int i_channel = 0; i_channel < MAILBOX_MAX_CHANNELS; i_channel++) {
73 		if (!data->channel_enable[i_channel]) {
74 			continue;
75 		}
76 
77 		if ((flags & MAILBOX_IRQ_NEWMSG(i_channel))) {
78 			data->received_data = regs->message[i_channel];
79 			struct mbox_msg msg = {
80 				.data = (const void *)&data->received_data,
81 				.size = MAILBOX_MBOX_SIZE,
82 			};
83 
84 			if (data->cb[i_channel]) {
85 				data->cb[i_channel](dev, i_channel, data->user_data[i_channel],
86 						    &msg);
87 			}
88 		}
89 	}
90 
91 	regs->irq_regs[cfg->usr_id].status_clear = flags;
92 	regs->irq_regs[cfg->usr_id].enable_set = irq_enabled;
93 }
94 
omap_mailbox_send(const struct device * dev,uint32_t channel,const struct mbox_msg * msg)95 static int omap_mailbox_send(const struct device *dev, uint32_t channel, const struct mbox_msg *msg)
96 {
97 	uint32_t __aligned(4) data32;
98 
99 	volatile struct omap_mailbox_regs *regs = DEV_REG_BASE(dev);
100 	struct omap_mailbox_data *data = DEV_DATA(dev);
101 	k_spinlock_key_t key;
102 
103 	if (channel >= MAILBOX_MAX_CHANNELS) {
104 		return -EINVAL;
105 	}
106 
107 	if (regs->fifo_status[channel]) {
108 		return -EBUSY;
109 	}
110 
111 	key = k_spin_lock(&data->lock);
112 	if (!msg) {
113 		regs->message[channel] = 0;
114 		k_spin_unlock(&data->lock, key);
115 		return 0;
116 	}
117 
118 	if (msg->size > MAILBOX_MBOX_SIZE) {
119 		k_spin_unlock(&data->lock, key);
120 		return -EMSGSIZE;
121 	}
122 
123 	memcpy(&data32, msg->data, msg->size);
124 	regs->message[channel] = data32;
125 	k_spin_unlock(&data->lock, key);
126 
127 	return 0;
128 }
129 
omap_mailbox_register_callback(const struct device * dev,uint32_t channel,mbox_callback_t cb,void * user_data)130 static int omap_mailbox_register_callback(const struct device *dev, uint32_t channel,
131 					  mbox_callback_t cb, void *user_data)
132 {
133 	struct omap_mailbox_data *data = DEV_DATA(dev);
134 	k_spinlock_key_t key;
135 
136 	if (channel >= MAILBOX_MAX_CHANNELS) {
137 		return -EINVAL;
138 	}
139 
140 	key = k_spin_lock(&data->lock);
141 	data->cb[channel] = cb;
142 	data->user_data[channel] = user_data;
143 	k_spin_unlock(&data->lock, key);
144 
145 	return 0;
146 }
147 
omap_mailbox_mtu_get(const struct device * dev)148 static int omap_mailbox_mtu_get(const struct device *dev)
149 {
150 	ARG_UNUSED(dev);
151 
152 	return MAILBOX_MBOX_SIZE;
153 }
154 
omap_mailbox_max_channels_get(const struct device * dev)155 static uint32_t omap_mailbox_max_channels_get(const struct device *dev)
156 {
157 	ARG_UNUSED(dev);
158 
159 	return MAILBOX_MAX_CHANNELS;
160 }
161 
omap_mailbox_set_enabled(const struct device * dev,uint32_t channel,bool enable)162 static int omap_mailbox_set_enabled(const struct device *dev, uint32_t channel, bool enable)
163 {
164 	const struct omap_mailbox_config *cfg = DEV_CFG(dev);
165 	struct omap_mailbox_data *data = DEV_DATA(dev);
166 	volatile struct omap_mailbox_regs *regs;
167 	k_spinlock_key_t key;
168 	uint32_t irqstatus;
169 
170 	if (channel >= MAILBOX_MAX_CHANNELS) {
171 		return -EINVAL;
172 	}
173 
174 	if (enable && data->channel_enable[channel]) {
175 		return -EALREADY;
176 	}
177 
178 	key = k_spin_lock(&data->lock);
179 	regs = DEV_REG_BASE(dev);
180 	irqstatus = regs->irq_regs[cfg->usr_id].enable_set;
181 
182 	if (enable) {
183 		irqstatus |= MAILBOX_IRQ_NEWMSG(channel);
184 	} else {
185 		irqstatus &= ~MAILBOX_IRQ_NEWMSG(channel);
186 	}
187 
188 	regs->irq_regs[cfg->usr_id].enable_set = irqstatus;
189 	data->channel_enable[channel] = enable;
190 
191 	if (enable) {
192 		irq_enable(cfg->irq);
193 	} else {
194 		irq_disable(cfg->irq);
195 	}
196 
197 	k_spin_unlock(&data->lock, key);
198 
199 	return 0;
200 }
201 
202 static DEVICE_API(mbox, omap_mailbox_driver_api) = {
203 	.send = omap_mailbox_send,
204 	.register_callback = omap_mailbox_register_callback,
205 	.mtu_get = omap_mailbox_mtu_get,
206 	.max_channels_get = omap_mailbox_max_channels_get,
207 	.set_enabled = omap_mailbox_set_enabled,
208 };
209 
210 #define MAILBOX_INSTANCE_DEFINE(idx)								\
211 	static struct omap_mailbox_data omap_mailbox_##idx##_data;				\
212 	const static struct omap_mailbox_config omap_mailbox_##idx##_config = {			\
213 		DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(idx)),				\
214 		.irq = DT_INST_IRQN(idx),							\
215 		.usr_id = DT_INST_PROP(idx, usr_id),						\
216 	};											\
217 	static int omap_mailbox_##idx##_init(const struct device *dev)				\
218 	{											\
219 		DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE);				\
220 		IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), omap_mailbox_isr,	\
221 			    DEVICE_DT_INST_GET(idx),						\
222 			    COND_CODE_1(DT_INST_IRQ_HAS_CELL(idx, flags),			\
223 					(DT_INST_IRQ(idx, flags)), (0)));			\
224 		return 0;									\
225 	}											\
226 	DEVICE_DT_INST_DEFINE(idx, omap_mailbox_##idx##_init, NULL, &omap_mailbox_##idx##_data,	\
227 			      &omap_mailbox_##idx##_config, POST_KERNEL,	\
228 			      CONFIG_MBOX_INIT_PRIORITY, &omap_mailbox_driver_api)
229 
230 DT_INST_FOREACH_STATUS_OKAY(MAILBOX_INSTANCE_DEFINE)
231