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