1 /*
2 * Copyright (c) 2019 Linaro Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT arm_mhu
8
9 #include <errno.h>
10 #include <zephyr/device.h>
11 #include <soc.h>
12 #include <zephyr/irq.h>
13 #include "ipm_mhu.h"
14
15 #define IPM_MHU_REGS(dev) \
16 ((volatile struct ipm_mhu_reg_map_t *) \
17 (((const struct ipm_mhu_device_config * const)(dev)->config)->base))
18
ipm_mhu_get_cpu_id(const struct device * d)19 static enum ipm_mhu_cpu_id_t ipm_mhu_get_cpu_id(const struct device *d)
20 {
21 volatile uint32_t *p_mhu_dev_base;
22 volatile uint32_t *p_cpu_id;
23
24 p_mhu_dev_base = (volatile uint32_t *)IPM_MHU_REGS(d);
25
26 p_cpu_id = (volatile uint32_t *)(((uint32_t)p_mhu_dev_base &
27 SSE_200_DEVICE_BASE_REG_MSK) +
28 SSE_200_CPU_ID_UNIT_OFFSET);
29
30 return (enum ipm_mhu_cpu_id_t)*p_cpu_id;
31 }
32
ipm_mhu_get_status(const struct device * d,enum ipm_mhu_cpu_id_t cpu_id,uint32_t * status)33 static uint32_t ipm_mhu_get_status(const struct device *d,
34 enum ipm_mhu_cpu_id_t cpu_id,
35 uint32_t *status)
36 {
37 struct ipm_mhu_reg_map_t *p_mhu_dev;
38
39 if (status == NULL) {
40 return IPM_MHU_ERR_INVALID_ARG;
41 }
42
43 p_mhu_dev = (struct ipm_mhu_reg_map_t *)IPM_MHU_REGS(d);
44
45 switch (cpu_id) {
46 case IPM_MHU_CPU1:
47 *status = p_mhu_dev->cpu1intr_stat;
48 break;
49 case IPM_MHU_CPU0:
50 default:
51 *status = p_mhu_dev->cpu0intr_stat;
52 break;
53 }
54
55 return IPM_MHU_ERR_NONE;
56 }
57
ipm_mhu_send(const struct device * d,int wait,uint32_t cpu_id,const void * data,int size)58 static int ipm_mhu_send(const struct device *d, int wait, uint32_t cpu_id,
59 const void *data, int size)
60 {
61 ARG_UNUSED(wait);
62 ARG_UNUSED(data);
63 const uint32_t set_val = 0x01;
64
65 struct ipm_mhu_reg_map_t *p_mhu_dev;
66
67 if (cpu_id >= IPM_MHU_CPU_MAX) {
68 return -EINVAL;
69 }
70
71 if (size > IPM_MHU_MAX_DATA_SIZE) {
72 return -EMSGSIZE;
73 }
74
75 p_mhu_dev = (struct ipm_mhu_reg_map_t *)IPM_MHU_REGS(d);
76
77 switch (cpu_id) {
78 case IPM_MHU_CPU1:
79 p_mhu_dev->cpu1intr_set = set_val;
80 break;
81 case IPM_MHU_CPU0:
82 default:
83 p_mhu_dev->cpu0intr_set = set_val;
84 break;
85 }
86
87 return 0;
88 }
89
ipm_mhu_clear_val(const struct device * d,enum ipm_mhu_cpu_id_t cpu_id,uint32_t clear_val)90 static void ipm_mhu_clear_val(const struct device *d,
91 enum ipm_mhu_cpu_id_t cpu_id,
92 uint32_t clear_val)
93 {
94 struct ipm_mhu_reg_map_t *p_mhu_dev;
95
96 p_mhu_dev = (struct ipm_mhu_reg_map_t *)IPM_MHU_REGS(d);
97
98 switch (cpu_id) {
99 case IPM_MHU_CPU1:
100 p_mhu_dev->cpu1intr_clr = clear_val;
101 break;
102 case IPM_MHU_CPU0:
103 default:
104 p_mhu_dev->cpu0intr_clr = clear_val;
105 break;
106 }
107 }
108
ipm_mhu_max_id_val_get(const struct device * d)109 static uint32_t ipm_mhu_max_id_val_get(const struct device *d)
110 {
111 ARG_UNUSED(d);
112
113 return IPM_MHU_MAX_ID_VAL;
114 }
115
ipm_mhu_init(const struct device * d)116 static int ipm_mhu_init(const struct device *d)
117 {
118 const struct ipm_mhu_device_config *config = d->config;
119
120 config->irq_config_func(d);
121
122 return 0;
123 }
124
ipm_mhu_isr(const struct device * d)125 static void ipm_mhu_isr(const struct device *d)
126 {
127 struct ipm_mhu_data *driver_data = d->data;
128 enum ipm_mhu_cpu_id_t cpu_id;
129 uint32_t ipm_mhu_status;
130
131 cpu_id = ipm_mhu_get_cpu_id(d);
132
133 ipm_mhu_get_status(d, cpu_id, &ipm_mhu_status);
134 ipm_mhu_clear_val(d, cpu_id, ipm_mhu_status);
135
136 if (driver_data->callback) {
137 driver_data->callback(d, driver_data->user_data, cpu_id,
138 &ipm_mhu_status);
139 }
140 }
141
ipm_mhu_set_enabled(const struct device * d,int enable)142 static int ipm_mhu_set_enabled(const struct device *d, int enable)
143 {
144 ARG_UNUSED(d);
145 ARG_UNUSED(enable);
146 return 0;
147 }
148
ipm_mhu_max_data_size_get(const struct device * d)149 static int ipm_mhu_max_data_size_get(const struct device *d)
150 {
151 ARG_UNUSED(d);
152
153 return IPM_MHU_MAX_DATA_SIZE;
154 }
155
ipm_mhu_register_cb(const struct device * d,ipm_callback_t cb,void * user_data)156 static void ipm_mhu_register_cb(const struct device *d,
157 ipm_callback_t cb,
158 void *user_data)
159 {
160 struct ipm_mhu_data *driver_data = d->data;
161
162 driver_data->callback = cb;
163 driver_data->user_data = user_data;
164 }
165
166 static const struct ipm_driver_api ipm_mhu_driver_api = {
167 .send = ipm_mhu_send,
168 .register_callback = ipm_mhu_register_cb,
169 .max_data_size_get = ipm_mhu_max_data_size_get,
170 .max_id_val_get = ipm_mhu_max_id_val_get,
171 .set_enabled = ipm_mhu_set_enabled,
172 };
173
174 static void ipm_mhu_irq_config_func_0(const struct device *d);
175
176 static const struct ipm_mhu_device_config ipm_mhu_cfg_0 = {
177 .base = (uint8_t *)DT_INST_REG_ADDR(0),
178 .irq_config_func = ipm_mhu_irq_config_func_0,
179 };
180
181 static struct ipm_mhu_data ipm_mhu_data_0 = {
182 .callback = NULL,
183 .user_data = NULL,
184 };
185
186 DEVICE_DT_INST_DEFINE(0,
187 &ipm_mhu_init,
188 NULL,
189 &ipm_mhu_data_0,
190 &ipm_mhu_cfg_0, PRE_KERNEL_1,
191 CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
192 &ipm_mhu_driver_api);
193
ipm_mhu_irq_config_func_0(const struct device * d)194 static void ipm_mhu_irq_config_func_0(const struct device *d)
195 {
196 ARG_UNUSED(d);
197 IRQ_CONNECT(DT_INST_IRQN(0),
198 DT_INST_IRQ(0, priority),
199 ipm_mhu_isr,
200 DEVICE_DT_INST_GET(0),
201 0);
202 irq_enable(DT_INST_IRQN(0));
203 }
204
205 static void ipm_mhu_irq_config_func_1(const struct device *d);
206
207 static const struct ipm_mhu_device_config ipm_mhu_cfg_1 = {
208 .base = (uint8_t *)DT_INST_REG_ADDR(1),
209 .irq_config_func = ipm_mhu_irq_config_func_1,
210 };
211
212 static struct ipm_mhu_data ipm_mhu_data_1 = {
213 .callback = NULL,
214 .user_data = NULL,
215 };
216
217 DEVICE_DT_INST_DEFINE(1,
218 &ipm_mhu_init,
219 NULL,
220 &ipm_mhu_data_1,
221 &ipm_mhu_cfg_1, PRE_KERNEL_1,
222 CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
223 &ipm_mhu_driver_api);
224
ipm_mhu_irq_config_func_1(const struct device * d)225 static void ipm_mhu_irq_config_func_1(const struct device *d)
226 {
227 ARG_UNUSED(d);
228 IRQ_CONNECT(DT_INST_IRQN(1),
229 DT_INST_IRQ(1, priority),
230 ipm_mhu_isr,
231 DEVICE_DT_INST_GET(1),
232 0);
233 irq_enable(DT_INST_IRQN(1));
234 }
235