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