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