1 /*
2  * Copyright (c) 2019 - 2025, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <nrfx.h>
35 
36 #if NRFX_CHECK(NRFX_IPC_ENABLED)
37 
38 #include <nrfx_ipc.h>
39 
40 #define NRFX_LOG_MODULE IPC
41 #include <nrfx_log.h>
42 
43 // Control block - driver instance local data.
44 typedef struct
45 {
46     nrfx_ipc_handler_t handler;
47     nrfx_drv_state_t   state;
48     void *             p_context;
49 } ipc_control_block_t;
50 
51 static ipc_control_block_t m_cb;
52 
nrfx_ipc_init(uint8_t irq_priority,nrfx_ipc_handler_t handler,void * p_context)53 nrfx_err_t nrfx_ipc_init(uint8_t irq_priority, nrfx_ipc_handler_t handler, void * p_context)
54 {
55     NRFX_ASSERT(handler);
56     if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
57     {
58         return NRFX_ERROR_ALREADY;
59     }
60 
61     NRFX_IRQ_PRIORITY_SET(IPC_IRQn, irq_priority);
62     NRFX_IRQ_ENABLE(IPC_IRQn);
63 
64     m_cb.state = NRFX_DRV_STATE_INITIALIZED;
65     m_cb.handler = handler;
66     m_cb.p_context = p_context;
67 
68     NRFX_LOG_INFO("Initialized.");
69     return NRFX_SUCCESS;
70 }
71 
nrfx_ipc_config_load(const nrfx_ipc_config_t * p_config)72 void nrfx_ipc_config_load(const nrfx_ipc_config_t * p_config)
73 {
74     NRFX_ASSERT(p_config);
75     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
76 
77     uint8_t i;
78     for (i = 0; i < IPC_CONF_NUM; ++i)
79     {
80         nrf_ipc_send_config_set(NRF_IPC, i, p_config->send_task_config[i]);
81     }
82 
83     for (i = 0; i < IPC_CONF_NUM; ++i)
84     {
85         nrf_ipc_receive_config_set(NRF_IPC, i, p_config->receive_event_config[i]);
86     }
87 
88     nrf_ipc_int_enable(NRF_IPC, p_config->receive_events_enabled);
89 
90     NRFX_LOG_INFO("Configuartion loaded.");
91 }
92 
nrfx_ipc_uninit(void)93 void nrfx_ipc_uninit(void)
94 {
95     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
96 
97     uint8_t i;
98     for (i = 0; i < IPC_CONF_NUM; ++i)
99     {
100         nrf_ipc_send_config_set(NRF_IPC, i, 0);
101     }
102 
103     for (i = 0; i < IPC_CONF_NUM; ++i)
104     {
105         nrf_ipc_receive_config_set(NRF_IPC, i, 0);
106     }
107 
108     NRFX_IRQ_DISABLE(IPC_IRQn);
109     nrf_ipc_int_disable(NRF_IPC, 0xFFFFFFFF);
110 
111     m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
112     NRFX_LOG_INFO("Uninitialized.");
113 }
114 
nrfx_ipc_init_check(void)115 bool nrfx_ipc_init_check(void)
116 {
117     return (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
118 }
119 
nrfx_ipc_receive_event_enable(uint8_t event_index)120 void nrfx_ipc_receive_event_enable(uint8_t event_index)
121 {
122     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
123     nrf_ipc_int_enable(NRF_IPC, (1UL << event_index));
124 
125     NRFX_LOG_INFO("Event %u enabled.", event_index);
126 }
127 
nrfx_ipc_receive_event_disable(uint8_t event_index)128 void nrfx_ipc_receive_event_disable(uint8_t event_index)
129 {
130     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
131     nrf_ipc_int_disable(NRF_IPC, (1UL << event_index));
132 
133     NRFX_LOG_INFO("Event %u disabled.", event_index);
134 }
135 
nrfx_ipc_receive_event_group_enable(uint32_t event_bitmask)136 void nrfx_ipc_receive_event_group_enable(uint32_t event_bitmask)
137 {
138     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
139     nrf_ipc_int_enable(NRF_IPC, event_bitmask);
140 
141     NRFX_LOG_INFO("Events masked with %x enabled.", event_bitmask);
142 }
143 
nrfx_ipc_receive_event_group_disable(uint32_t event_bitmask)144 void nrfx_ipc_receive_event_group_disable(uint32_t event_bitmask)
145 {
146     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
147     nrf_ipc_int_disable(NRF_IPC, event_bitmask);
148 
149     NRFX_LOG_INFO("Events masked with %x disabled.", event_bitmask);
150 }
151 
nrfx_ipc_receive_event_channel_assign(uint8_t event_index,uint8_t channel_index)152 void nrfx_ipc_receive_event_channel_assign(uint8_t event_index, uint8_t channel_index)
153 {
154     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
155     NRFX_ASSERT(channel_index < IPC_CH_NUM);
156 
157     uint32_t channel_bitmask = (1UL << channel_index);
158     channel_bitmask |= nrf_ipc_receive_config_get(NRF_IPC, event_index);
159     nrf_ipc_receive_config_set(NRF_IPC, event_index, channel_bitmask);
160 
161     NRFX_LOG_INFO("Event %u assigned to IPC channel %u.", event_index, channel_index);
162 }
163 
nrfx_ipc_send_task_channel_assign(uint8_t send_index,uint8_t channel_index)164 void nrfx_ipc_send_task_channel_assign(uint8_t send_index, uint8_t channel_index)
165 {
166     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
167     NRFX_ASSERT(channel_index < IPC_CH_NUM);
168 
169     uint32_t channel_bitmask = (1UL << channel_index);
170     channel_bitmask |= nrf_ipc_send_config_get(NRF_IPC, send_index);
171     nrf_ipc_send_config_set(NRF_IPC, send_index, channel_bitmask);
172 
173     NRFX_LOG_INFO("Signal %u assigned to IPC channel %u.", send_index, channel_index);
174 }
175 
nrfx_ipc_irq_handler(void)176 void nrfx_ipc_irq_handler(void)
177 {
178     // Get the information about events that fire this interrupt
179     uint32_t events_map = nrf_ipc_int_pending_get(NRF_IPC);
180     // Clear these events
181     uint32_t bitmask = events_map;
182 
183     while (bitmask)
184     {
185         uint8_t event_idx = (uint8_t)NRF_CTZ(bitmask);
186         bitmask &= ~(1UL << event_idx);
187         nrf_ipc_event_clear(NRF_IPC, nrf_ipc_receive_event_get(event_idx));
188         if (m_cb.handler)
189         {
190             m_cb.handler(event_idx, m_cb.p_context);
191         }
192     }
193 }
194 
195 #endif // NRFX_CHECK(NRFX_IPC_ENABLED)
196