1 /*
2 * Copyright (c) 2018, NXP
3 * Copyright (c) 2018, Nordic Semiconductor ASA
4 * Copyright (c) 2018-2019, Linaro Limited
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/ipm.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/device.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include <openamp/open_amp.h>
18
19 #include "common.h"
20
21 #define APP_TASK_STACK_SIZE (1024)
22 K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE);
23 static struct k_thread thread_data;
24
25 static const struct device *const ipm_handle =
26 DEVICE_DT_GET(DT_CHOSEN(zephyr_ipc));
27
28 static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR };
29
30 static volatile unsigned int received_data;
31
32 static struct virtio_vring_info rvrings[2] = {
33 [0] = {
34 .info.align = VRING_ALIGNMENT,
35 },
36 [1] = {
37 .info.align = VRING_ALIGNMENT,
38 },
39 };
40 static struct virtio_device vdev;
41 static struct rpmsg_virtio_device rvdev;
42 static struct metal_io_region shm_io_data;
43 static struct metal_io_region *io = &shm_io_data;
44 static struct virtqueue *vqueue[2];
45
ipc_virtio_get_status(struct virtio_device * dev)46 static unsigned char ipc_virtio_get_status(struct virtio_device *dev)
47 {
48 return sys_read8(VDEV_STATUS_ADDR);
49 }
50
ipc_virtio_get_features(struct virtio_device * dev)51 static uint32_t ipc_virtio_get_features(struct virtio_device *dev)
52 {
53 return 1 << VIRTIO_RPMSG_F_NS;
54 }
55
ipc_virtio_notify(struct virtqueue * vq)56 static void ipc_virtio_notify(struct virtqueue *vq)
57 {
58 #if defined(CONFIG_SOC_MPS2_AN521) || \
59 defined(CONFIG_SOC_V2M_MUSCA_B1)
60 uint32_t current_core = sse_200_platform_get_cpu_id();
61
62 ipm_send(ipm_handle, 0, current_core ? 0 : 1, 0, 1);
63 #else
64 uint32_t dummy_data = 0x00110011; /* Some data must be provided */
65
66 ipm_send(ipm_handle, 0, 0, &dummy_data, sizeof(dummy_data));
67 #endif /* #if defined(CONFIG_SOC_MPS2_AN521) */
68 }
69
70 struct virtio_dispatch dispatch = {
71 .get_status = ipc_virtio_get_status,
72 .get_features = ipc_virtio_get_features,
73 .notify = ipc_virtio_notify,
74 };
75
76 static K_SEM_DEFINE(data_sem, 0, 1);
77 static K_SEM_DEFINE(data_rx_sem, 0, 1);
78
platform_ipm_callback(const struct device * dev,void * context,uint32_t id,volatile void * data)79 static void platform_ipm_callback(const struct device *dev, void *context,
80 uint32_t id, volatile void *data)
81 {
82 k_sem_give(&data_sem);
83 }
84
endpoint_cb(struct rpmsg_endpoint * ept,void * data,size_t len,uint32_t src,void * priv)85 int endpoint_cb(struct rpmsg_endpoint *ept, void *data,
86 size_t len, uint32_t src, void *priv)
87 {
88 received_data = *((unsigned int *) data);
89
90 k_sem_give(&data_rx_sem);
91
92 return RPMSG_SUCCESS;
93 }
94
95 static K_SEM_DEFINE(ept_sem, 0, 1);
96
97 struct rpmsg_endpoint my_ept;
98 struct rpmsg_endpoint *ep = &my_ept;
99
rpmsg_service_unbind(struct rpmsg_endpoint * ept)100 static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
101 {
102 (void)ept;
103 rpmsg_destroy_ept(ep);
104 }
105
receive_message(void)106 static unsigned int receive_message(void)
107 {
108 while (k_sem_take(&data_rx_sem, K_NO_WAIT) != 0) {
109 int status = k_sem_take(&data_sem, K_FOREVER);
110
111 if (status == 0) {
112 virtqueue_notification(vqueue[1]);
113 }
114 }
115 return received_data;
116 }
117
send_message(unsigned int message)118 static int send_message(unsigned int message)
119 {
120 return rpmsg_send(ep, &message, sizeof(message));
121 }
122
app_task(void * arg1,void * arg2,void * arg3)123 void app_task(void *arg1, void *arg2, void *arg3)
124 {
125 ARG_UNUSED(arg1);
126 ARG_UNUSED(arg2);
127 ARG_UNUSED(arg3);
128
129 int status = 0;
130 unsigned int message = 0U;
131 struct rpmsg_device *rdev;
132 struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
133
134 printk("\r\nOpenAMP[remote] demo started\r\n");
135
136 status = metal_init(&metal_params);
137 if (status != 0) {
138 printk("metal_init: failed - error code %d\n", status);
139 return;
140 }
141
142 /* declare shared memory region */
143 metal_io_init(io, (void *)SHM_START_ADDR, shm_physmap, SHM_SIZE, -1, 0, NULL);
144
145 /* setup IPM */
146 if (!device_is_ready(ipm_handle)) {
147 printk("IPM device is not ready\n");
148 return;
149 }
150
151 ipm_register_callback(ipm_handle, platform_ipm_callback, NULL);
152
153 status = ipm_set_enabled(ipm_handle, 1);
154 if (status != 0) {
155 printk("ipm_set_enabled failed\n");
156 return;
157 }
158
159 /* setup vdev */
160 vqueue[0] = virtqueue_allocate(VRING_SIZE);
161 if (vqueue[0] == NULL) {
162 printk("virtqueue_allocate failed to alloc vqueue[0]\n");
163 return;
164 }
165 vqueue[1] = virtqueue_allocate(VRING_SIZE);
166 if (vqueue[1] == NULL) {
167 printk("virtqueue_allocate failed to alloc vqueue[1]\n");
168 return;
169 }
170
171 vdev.role = RPMSG_REMOTE;
172 vdev.vrings_num = VRING_COUNT;
173 vdev.func = &dispatch;
174 rvrings[0].io = io;
175 rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS;
176 rvrings[0].info.num_descs = VRING_SIZE;
177 rvrings[0].info.align = VRING_ALIGNMENT;
178 rvrings[0].vq = vqueue[0];
179
180 rvrings[1].io = io;
181 rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS;
182 rvrings[1].info.num_descs = VRING_SIZE;
183 rvrings[1].info.align = VRING_ALIGNMENT;
184 rvrings[1].vq = vqueue[1];
185
186 vdev.vrings_info = &rvrings[0];
187
188 /* setup rvdev */
189 status = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL);
190 if (status != 0) {
191 printk("rpmsg_init_vdev failed %d\n", status);
192 return;
193 }
194
195 rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
196
197 status = rpmsg_create_ept(ep, rdev, "k", RPMSG_ADDR_ANY,
198 RPMSG_ADDR_ANY, endpoint_cb, rpmsg_service_unbind);
199 if (status != 0) {
200 printk("rpmsg_create_ept failed %d\n", status);
201 return;
202 }
203
204 while (message < 99) {
205 message = receive_message();
206 printk("Remote core received a message: %d\n", message);
207
208 message++;
209 status = send_message(message);
210 if (status < 0) {
211 printk("send_message(%d) failed with status %d\n",
212 message, status);
213 goto _cleanup;
214 }
215 }
216
217 _cleanup:
218 rpmsg_deinit_vdev(&rvdev);
219 metal_finish();
220
221 printk("OpenAMP demo ended.\n");
222 }
223
main(void)224 int main(void)
225 {
226 printk("Starting application thread!\n");
227 k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE,
228 app_task,
229 NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
230 return 0;
231 }
232