1 /*
2  * Copyright (c) 2017-2018, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_lpc_mailbox
8 
9 #include <errno.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/ipm.h>
12 #include <fsl_mailbox.h>
13 #include <fsl_clock.h>
14 #include <soc.h>
15 #include <zephyr/irq.h>
16 #include <zephyr/sys/barrier.h>
17 #include <zephyr/drivers/reset.h>
18 #include <zephyr/sys/util_macro.h>
19 
20 #define MCUX_IPM_DATA_REGS 1
21 #define MCUX_IPM_MAX_ID_VAL 0
22 
23 #if (defined(LPC55S69_cm33_core0_SERIES) || defined(LPC55S69_cm33_core1_SERIES))
24 #ifdef LPC55S69_cm33_core0_SERIES
25 #define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core0
26 #define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core1
27 #else
28 #define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core1
29 #define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core0
30 #endif
31 #else
32 #if defined(__CM4_CMSIS_VERSION)
33 #define MAILBOX_ID_THIS_CPU kMAILBOX_CM4
34 #define MAILBOX_ID_OTHER_CPU kMAILBOX_CM0Plus
35 #else
36 #define MAILBOX_ID_THIS_CPU kMAILBOX_CM0Plus
37 #define MAILBOX_ID_OTHER_CPU kMAILBOX_CM4
38 #endif
39 #endif
40 
41 #define MAILBOX_USES_RESET COND_CODE_1(DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets), (true), (false))
42 
43 struct mcux_mailbox_config {
44 	MAILBOX_Type *base;
45 	void (*irq_config_func)(const struct device *dev);
46 	const struct reset_dt_spec reset;
47 };
48 
49 struct mcux_mailbox_data {
50 	ipm_callback_t callback;
51 	void *callback_ctx;
52 };
53 
mcux_mailbox_isr(const struct device * dev)54 static void mcux_mailbox_isr(const struct device *dev)
55 {
56 	struct mcux_mailbox_data *data = dev->data;
57 	const struct mcux_mailbox_config *config = dev->config;
58 	mailbox_cpu_id_t cpu_id;
59 
60 	cpu_id = MAILBOX_ID_THIS_CPU;
61 
62 	volatile uint32_t value = MAILBOX_GetValue(config->base, cpu_id);
63 
64 	__ASSERT(value, "spurious MAILBOX interrupt");
65 
66 	/* Clear or the interrupt gets called intermittently */
67 	MAILBOX_ClearValueBits(config->base, cpu_id, value);
68 
69 	if (data->callback) {
70 		/* Only one MAILBOX, id is unused and set to 0 */
71 		data->callback(dev, data->callback_ctx, 0, &value);
72 	}
73 	/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F
74 	 * Store immediate overlapping exception return operation
75 	 * might vector to incorrect interrupt
76 	 */
77 #if defined __CORTEX_M && (__CORTEX_M == 4U)
78 	barrier_dsync_fence_full();
79 #endif
80 }
81 
82 
mcux_mailbox_ipm_send(const struct device * d,int wait,uint32_t id,const void * data,int size)83 static int mcux_mailbox_ipm_send(const struct device *d, int wait,
84 				 uint32_t id,
85 				 const void *data, int size)
86 {
87 	const struct mcux_mailbox_config *config = d->config;
88 	MAILBOX_Type *base = config->base;
89 	/* Until we change API to uint32_t array */
90 	uint32_t data32[MCUX_IPM_DATA_REGS] = {0};
91 	unsigned int flags;
92 	int i;
93 
94 	ARG_UNUSED(wait);
95 
96 	if (id > MCUX_IPM_MAX_ID_VAL) {
97 		return -EINVAL;
98 	}
99 
100 	if ((size < 0) || (size > MCUX_IPM_DATA_REGS * sizeof(uint32_t))) {
101 		return -EMSGSIZE;
102 	}
103 
104 	flags = irq_lock();
105 
106 	/* Actual message is passing using 32 bits registers */
107 	memcpy(data32, data, size);
108 
109 	for (i = 0; i < ARRAY_SIZE(data32); ++i) {
110 		MAILBOX_SetValueBits(base, MAILBOX_ID_OTHER_CPU, data32[i]);
111 	}
112 
113 	irq_unlock(flags);
114 
115 	return 0;
116 }
117 
118 
mcux_mailbox_ipm_max_data_size_get(const struct device * d)119 static int mcux_mailbox_ipm_max_data_size_get(const struct device *d)
120 {
121 	ARG_UNUSED(d);
122 	/* Only a single 32-bit register available */
123 	return MCUX_IPM_DATA_REGS*sizeof(uint32_t);
124 }
125 
126 
mcux_mailbox_ipm_max_id_val_get(const struct device * d)127 static uint32_t mcux_mailbox_ipm_max_id_val_get(const struct device *d)
128 {
129 	ARG_UNUSED(d);
130 	/* Only a single instance of MAILBOX available for this platform */
131 	return MCUX_IPM_MAX_ID_VAL;
132 }
133 
mcux_mailbox_ipm_register_callback(const struct device * d,ipm_callback_t cb,void * context)134 static void mcux_mailbox_ipm_register_callback(const struct device *d,
135 					       ipm_callback_t cb,
136 					       void *context)
137 {
138 	struct mcux_mailbox_data *driver_data = d->data;
139 
140 	driver_data->callback = cb;
141 	driver_data->callback_ctx = context;
142 }
143 
144 
mcux_mailbox_ipm_set_enabled(const struct device * d,int enable)145 static int mcux_mailbox_ipm_set_enabled(const struct device *d, int enable)
146 {
147 	/* For now: nothing to be done */
148 	return 0;
149 }
150 
mcux_mailbox_reset(const struct device * dev)151 static inline int mcux_mailbox_reset(const struct device *dev)
152 {
153 	const struct mcux_mailbox_config *config = dev->config;
154 	int ret = 0;
155 
156 	/* on some platforms, explicit reset is not needed or possible for the mailbox */
157 	if (!MAILBOX_USES_RESET) {
158 		return 0;
159 	}
160 
161 	if (!device_is_ready(config->reset.dev)) {
162 		ret = -ENODEV;
163 	} else {
164 		ret = reset_line_toggle(config->reset.dev, config->reset.id);
165 	}
166 
167 	return ret;
168 }
169 
mcux_mailbox_init(const struct device * dev)170 static int mcux_mailbox_init(const struct device *dev)
171 {
172 	const struct mcux_mailbox_config *config = dev->config;
173 	int ret = 0;
174 
175 	ret = mcux_mailbox_reset(dev);
176 	if (ret) {
177 		return ret;
178 	}
179 
180 	MAILBOX_Init(config->base);
181 	config->irq_config_func(dev);
182 	return 0;
183 }
184 
185 static DEVICE_API(ipm, mcux_mailbox_driver_api) = {
186 	.send = mcux_mailbox_ipm_send,
187 	.register_callback = mcux_mailbox_ipm_register_callback,
188 	.max_data_size_get = mcux_mailbox_ipm_max_data_size_get,
189 	.max_id_val_get = mcux_mailbox_ipm_max_id_val_get,
190 	.set_enabled = mcux_mailbox_ipm_set_enabled
191 };
192 
193 
194 /* Config MAILBOX 0 */
195 
196 static void mcux_mailbox_config_func_0(const struct device *dev);
197 
198 static const struct mcux_mailbox_config mcux_mailbox_0_config = {
199 	.base = (MAILBOX_Type *)DT_INST_REG_ADDR(0),
200 	.irq_config_func = mcux_mailbox_config_func_0,
201 	.reset = RESET_DT_SPEC_INST_GET_OR(0, {0}),
202 };
203 
204 static struct mcux_mailbox_data mcux_mailbox_0_data;
205 
206 DEVICE_DT_INST_DEFINE(0,
207 		    &mcux_mailbox_init,
208 		    NULL,
209 		    &mcux_mailbox_0_data, &mcux_mailbox_0_config,
210 		    PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
211 		    &mcux_mailbox_driver_api);
212 
213 
mcux_mailbox_config_func_0(const struct device * dev)214 static void mcux_mailbox_config_func_0(const struct device *dev)
215 {
216 	IRQ_CONNECT(DT_INST_IRQN(0),
217 		    DT_INST_IRQ(0, priority),
218 		    mcux_mailbox_isr, DEVICE_DT_INST_GET(0), 0);
219 
220 	irq_enable(DT_INST_IRQN(0));
221 }
222