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