1 /*
2 * Copyright (c) 2023 AMD-Xilinx Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT xlnx_zynqmp_ipi_mailbox
8
9 #include "ipm_xlnx_ipi.h"
10
11 #include <errno.h>
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/ipm.h>
14 #include <zephyr/irq.h>
15
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(ipm_xlnx_ipi, CONFIG_IPM_LOG_LEVEL);
18
19 #define XLNX_IPI_MAX_BUF_SIZE_BYTES 32
20
21 struct xlnx_ipi_data {
22 size_t len;
23 void *user_data;
24 uint8_t data[];
25 };
26
27 struct xlnx_ipi_reg_info {
28 uint32_t ipi_ch_bit;
29 };
30
31 static const struct xlnx_ipi_reg_info xlnx_ipi_reg_info_zynqmp[] = {
32 {.ipi_ch_bit = IPI_CH0_BIT}, /* IPI CH ID 0 - Default APU */
33 {.ipi_ch_bit = IPI_CH1_BIT}, /* IPI CH ID 1 - Default RPU0 */
34 {.ipi_ch_bit = IPI_CH2_BIT}, /* IPI CH ID 2 - Default RPU1 */
35 {.ipi_ch_bit = IPI_CH3_BIT}, /* IPI CH ID 3 - Default PMU0 */
36 {.ipi_ch_bit = IPI_CH4_BIT}, /* IPI CH ID 4 - Default PMU1 */
37 {.ipi_ch_bit = IPI_CH5_BIT}, /* IPI CH ID 5 - Default PMU2 */
38 {.ipi_ch_bit = IPI_CH6_BIT}, /* IPI CH ID 6 - Default PMU3 */
39 {.ipi_ch_bit = IPI_CH7_BIT}, /* IPI CH ID 7 - Default PL0 */
40 {.ipi_ch_bit = IPI_CH8_BIT}, /* IPI CH ID 8 - Default PL1 */
41 {.ipi_ch_bit = IPI_CH9_BIT}, /* IPI CH ID 9 - Default PL2 */
42 {.ipi_ch_bit = IPI_CH10_BIT}, /* IPI CH ID 10 - Default PL3 */
43 };
44
45 struct xlnx_ipi_config {
46 uint32_t ipi_ch_bit;
47 uint32_t host_ipi_reg;
48 int (*xlnx_ipi_config_func)(const struct device *dev);
49 const struct device **cdev_list;
50 int num_cdev;
51 };
52
53 struct xlnx_ipi_child_data {
54 bool enabled;
55 ipm_callback_t ipm_callback;
56 void *user_data;
57 };
58
59 struct xlnx_ipi_child_config {
60 const char *node_id;
61 uint32_t local_request_region;
62 uint32_t local_response_region;
63 uint32_t remote_request_region;
64 uint32_t remote_response_region;
65 uint32_t host_ipi_reg;
66 uint32_t remote_ipi_id;
67 uint32_t remote_ipi_ch_bit;
68 };
69
xlnx_mailbox_rx_isr(const struct device * dev)70 static void xlnx_mailbox_rx_isr(const struct device *dev)
71 {
72 const struct xlnx_ipi_config *config;
73 const struct device **cdev_list;
74 const struct xlnx_ipi_child_config *cdev_conf;
75 const struct xlnx_ipi_child_data *cdev_data;
76 uint8_t ipi_buf[XLNX_IPI_MAX_BUF_SIZE_BYTES + sizeof(struct xlnx_ipi_data)];
77 int num_cdev;
78 struct xlnx_ipi_data *msg;
79 const struct device *cdev;
80 uint32_t remote_ipi_ch_bit;
81 int i, j;
82
83 config = dev->config;
84 cdev_list = config->cdev_list;
85 num_cdev = config->num_cdev;
86 msg = (struct xlnx_ipi_data *)ipi_buf;
87 for (i = 0; i < num_cdev; i++) {
88 cdev = cdev_list[i];
89 cdev_conf = cdev->config;
90 cdev_data = cdev->data;
91
92 if (!cdev_data->enabled) {
93 continue;
94 }
95
96 remote_ipi_ch_bit = cdev_conf->remote_ipi_ch_bit;
97 if (!sys_test_bit(config->host_ipi_reg + IPI_ISR, remote_ipi_ch_bit)) {
98 continue;
99 }
100
101 msg->len = XLNX_IPI_MAX_BUF_SIZE_BYTES;
102 msg->user_data = cdev_data->user_data;
103 for (j = 0; j < XLNX_IPI_MAX_BUF_SIZE_BYTES; j++) {
104 msg->data[j] = sys_read8(cdev_conf->remote_request_region + j);
105 }
106 if (cdev_data->ipm_callback) {
107 cdev_data->ipm_callback(cdev, cdev_data->user_data,
108 cdev_conf->remote_ipi_id, msg);
109 }
110 sys_set_bit(config->host_ipi_reg + IPI_ISR, remote_ipi_ch_bit);
111 }
112 }
113
xlnx_ipi_send(const struct device * ipmdev,int wait,uint32_t id,const void * data,int size)114 static int xlnx_ipi_send(const struct device *ipmdev, int wait, uint32_t id, const void *data,
115 int size)
116 {
117 const uint8_t *msg = (uint8_t *)data;
118 const struct xlnx_ipi_child_config *config = ipmdev->config;
119 unsigned int key;
120 int i, obs_bit;
121
122 ARG_UNUSED(id);
123
124 if (size > XLNX_IPI_MAX_BUF_SIZE_BYTES) {
125 return -EMSGSIZE;
126 }
127
128 key = irq_lock();
129 if (msg) {
130 /* Write buffer to send data */
131 for (i = 0; i < size; i++) {
132 sys_write8(msg[i], config->local_request_region + i);
133 }
134 }
135 irq_unlock(key);
136
137 sys_set_bit(config->host_ipi_reg + IPI_TRIG, config->remote_ipi_ch_bit);
138
139 obs_bit = 0;
140 do {
141 obs_bit = sys_test_bit(config->host_ipi_reg + IPI_OBS, config->remote_ipi_ch_bit);
142 } while (obs_bit && wait);
143
144 return 0;
145 }
146
xlnx_ipi_register_callback(const struct device * port,ipm_callback_t cb,void * user_data)147 static void xlnx_ipi_register_callback(const struct device *port, ipm_callback_t cb,
148 void *user_data)
149 {
150 struct xlnx_ipi_child_data *data = port->data;
151
152 data->ipm_callback = cb;
153 data->user_data = user_data;
154 }
155
xlnx_ipi_max_data_size_get(const struct device * ipmdev)156 static int xlnx_ipi_max_data_size_get(const struct device *ipmdev)
157 {
158 return XLNX_IPI_MAX_BUF_SIZE_BYTES;
159 }
160
xlnx_ipi_max_id_val_get(const struct device * ipmdev)161 static uint32_t xlnx_ipi_max_id_val_get(const struct device *ipmdev)
162 {
163 return UINT32_MAX;
164 }
165
xlnx_ipi_set_enabled(const struct device * ipmdev,int enable)166 static int xlnx_ipi_set_enabled(const struct device *ipmdev, int enable)
167 {
168 const struct xlnx_ipi_child_config *config = ipmdev->config;
169 struct xlnx_ipi_child_data *data = ipmdev->data;
170
171 if (enable) {
172 sys_set_bit(config->host_ipi_reg + IPI_IER, config->remote_ipi_ch_bit);
173 } else {
174 sys_set_bit(config->host_ipi_reg + IPI_IDR, config->remote_ipi_ch_bit);
175 }
176
177 /* If IPI channel bit in IPI Mask Register is not set, then interrupt is enabled */
178 if (!sys_test_bit(config->host_ipi_reg + IPI_IMR, config->remote_ipi_ch_bit)) {
179 data->enabled = enable;
180 return 0;
181 }
182
183 return -EINVAL;
184 }
185
xlnx_ipi_init(const struct device * dev)186 static int xlnx_ipi_init(const struct device *dev)
187 {
188 const struct xlnx_ipi_config *conf = dev->config;
189
190 /* disable all the interrupts */
191 sys_write32(0xFFFFFFFF, conf->host_ipi_reg + IPI_IDR);
192
193 /* clear status of any previous interrupts */
194 sys_write32(0xFFFFFFFF, conf->host_ipi_reg + IPI_ISR);
195
196 conf->xlnx_ipi_config_func(dev);
197
198 return 0;
199 }
200
201 static struct ipm_driver_api xlnx_ipi_api = {
202 .send = xlnx_ipi_send,
203 .register_callback = xlnx_ipi_register_callback,
204 .max_data_size_get = xlnx_ipi_max_data_size_get,
205 .max_id_val_get = xlnx_ipi_max_id_val_get,
206 .set_enabled = xlnx_ipi_set_enabled,
207 };
208
209 #define GET_CHILD_DEV(node_id) DEVICE_DT_GET(node_id),
210
211 #define XLNX_IPI_CHILD(ch_node) \
212 struct xlnx_ipi_child_data xlnx_ipi_child_data##ch_node = { \
213 .enabled = false, \
214 .ipm_callback = NULL, \
215 }; \
216 struct xlnx_ipi_child_config xlnx_ipi_child_config##ch_node = { \
217 .local_request_region = DT_REG_ADDR_BY_NAME(ch_node, local_request_region), \
218 .local_response_region = DT_REG_ADDR_BY_NAME(ch_node, local_response_region), \
219 .remote_request_region = DT_REG_ADDR_BY_NAME(ch_node, remote_request_region), \
220 .remote_response_region = DT_REG_ADDR_BY_NAME(ch_node, remote_response_region), \
221 .remote_ipi_id = DT_PROP(ch_node, remote_ipi_id), \
222 .remote_ipi_ch_bit = \
223 xlnx_ipi_reg_info_zynqmp[DT_PROP(ch_node, remote_ipi_id)].ipi_ch_bit, \
224 .host_ipi_reg = DT_REG_ADDR_BY_NAME(DT_PARENT(ch_node), host_ipi_reg), \
225 }; \
226 DEVICE_DT_DEFINE(ch_node, NULL, NULL, &xlnx_ipi_child_data##ch_node, \
227 &xlnx_ipi_child_config##ch_node, POST_KERNEL, \
228 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &xlnx_ipi_api);
229
230 #define XLNX_IPI(inst) \
231 DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, XLNX_IPI_CHILD); \
232 static const struct device *cdev##inst[] = { \
233 DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, GET_CHILD_DEV)}; \
234 static int xlnx_ipi_config_func##inst(const struct device *dev); \
235 struct xlnx_ipi_config xlnx_ipi_config##inst = { \
236 .host_ipi_reg = DT_INST_REG_ADDR_BY_NAME(inst, host_ipi_reg), \
237 .xlnx_ipi_config_func = xlnx_ipi_config_func##inst, \
238 .cdev_list = cdev##inst, \
239 .num_cdev = ARRAY_SIZE(cdev##inst), \
240 }; \
241 DEVICE_DT_INST_DEFINE(inst, &xlnx_ipi_init, NULL, NULL, /* data */ \
242 &xlnx_ipi_config##inst, /* conf */ \
243 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); \
244 static int xlnx_ipi_config_func##inst(const struct device *dev) \
245 { \
246 IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), xlnx_mailbox_rx_isr, \
247 DEVICE_DT_INST_GET(inst), 0); \
248 irq_enable(DT_INST_IRQN(inst)); \
249 LOG_DBG("irq %d is enabled: %s\n", DT_INST_IRQN(inst), \
250 irq_is_enabled(DT_INST_IRQN(inst)) ? "true" : "false"); \
251 return 0; \
252 }
253
254 DT_INST_FOREACH_STATUS_OKAY(XLNX_IPI)
255