1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "ipc_icmsg.h"
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/ipc/icmsg.h>
12 
13 #include <zephyr/ipc/ipc_service_backend.h>
14 
15 #define DT_DRV_COMPAT	zephyr_ipc_icmsg
16 
register_ept(const struct device * instance,void ** token,const struct ipc_ept_cfg * cfg)17 static int register_ept(const struct device *instance, void **token,
18 			const struct ipc_ept_cfg *cfg)
19 {
20 	const struct icmsg_config_t *conf = instance->config;
21 	struct icmsg_data_t *dev_data = instance->data;
22 
23 	/* Only one endpoint is supported. No need for a token. */
24 	*token = NULL;
25 
26 	return icmsg_open(conf, dev_data, &cfg->cb, cfg->priv);
27 }
28 
deregister_ept(const struct device * instance,void * token)29 static int deregister_ept(const struct device *instance, void *token)
30 {
31 	const struct icmsg_config_t *conf = instance->config;
32 	struct icmsg_data_t *dev_data = instance->data;
33 
34 	return icmsg_close(conf, dev_data);
35 }
36 
send(const struct device * instance,void * token,const void * msg,size_t len)37 static int send(const struct device *instance, void *token,
38 		const void *msg, size_t len)
39 {
40 	const struct icmsg_config_t *conf = instance->config;
41 	struct icmsg_data_t *dev_data = instance->data;
42 
43 	return icmsg_send(conf, dev_data, msg, len);
44 }
45 
46 const static struct ipc_service_backend backend_ops = {
47 	.register_endpoint = register_ept,
48 	.deregister_endpoint = deregister_ept,
49 	.send = send,
50 };
51 
backend_init(const struct device * instance)52 static int backend_init(const struct device *instance)
53 {
54 	return 0;
55 }
56 
57 #define UNBOUND_MODE(i) CONCAT(ICMSG_UNBOUND_MODE_, DT_INST_STRING_UPPER_TOKEN(i, unbound))
58 
59 #define DEFINE_BACKEND_DEVICE(i)						\
60 	static const struct icmsg_config_t backend_config_##i = {		\
61 		.mbox_tx = MBOX_DT_SPEC_INST_GET(i, tx),			\
62 		.mbox_rx = MBOX_DT_SPEC_INST_GET(i, rx),			\
63 		.unbound_mode = UNBOUND_MODE(i),				\
64 	};									\
65 										\
66 	PBUF_DEFINE(tx_pb_##i,							\
67 			DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)),		\
68 			DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)),		\
69 			DT_INST_PROP_OR(i, dcache_alignment, 0),		\
70 			UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DISABLE,		\
71 			UNBOUND_MODE(i) == ICMSG_UNBOUND_MODE_DETECT);		\
72 	PBUF_DEFINE(rx_pb_##i,							\
73 			DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)),		\
74 			DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)),		\
75 			DT_INST_PROP_OR(i, dcache_alignment, 0),		\
76 			UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DISABLE,		\
77 			UNBOUND_MODE(i) == ICMSG_UNBOUND_MODE_DETECT);		\
78 										\
79 	BUILD_ASSERT(UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DISABLE ||		\
80 		IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_DISABLED_ALLOWED),	\
81 		"Unbound mode \"disabled\" is was forbidden in Kconfig.");	\
82 										\
83 	BUILD_ASSERT(UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_ENABLE ||		\
84 		IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_ENABLED_ALLOWED),	\
85 		"Unbound mode \"enabled\" is was forbidden in Kconfig.");	\
86 										\
87 	BUILD_ASSERT(UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DETECT ||		\
88 		IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_DETECT_ALLOWED),	\
89 		"Unbound mode \"detect\" is was forbidden in Kconfig.");	\
90 										\
91 	static struct icmsg_data_t backend_data_##i = {				\
92 		.tx_pb = &tx_pb_##i,						\
93 		.rx_pb = &rx_pb_##i,						\
94 	};									\
95 										\
96 	DEVICE_DT_INST_DEFINE(i,						\
97 			 &backend_init,						\
98 			 NULL,							\
99 			 &backend_data_##i,					\
100 			 &backend_config_##i,					\
101 			 POST_KERNEL,						\
102 			 CONFIG_IPC_SERVICE_REG_BACKEND_PRIORITY,		\
103 			 &backend_ops);
104 
105 DT_INST_FOREACH_STATUS_OKAY(DEFINE_BACKEND_DEVICE)
106