1 /*
2  * Copyright (c) 2020, 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 Nordic Semiconductor ASA 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 
35 #define NRF_802154_MODULE_ID NRF_802154_DRV_MODULE_ID_TRX_PPI
36 
37 #include "nrfx.h"
38 
39 #if defined(DPPI_PRESENT)
40 
41 #include "nrf_802154_trx_ppi_api.h"
42 
43 #include "nrf_802154_debug_log.h"
44 #include "nrf_802154_peripherals.h"
45 
46 #include "hal/nrf_dppi.h"
47 #include "hal/nrf_egu.h"
48 #include "hal/nrf_radio.h"
49 #include "hal/nrf_timer.h"
50 
51 #define EGU_EVENT                   NRF_802154_EGU_RAMP_UP_EVENT
52 #define EGU_TASK                    NRF_802154_EGU_RAMP_UP_TASK
53 
54 #define DPPI_CHGRP_RAMP_UP          NRF_DPPI_CHANNEL_GROUP0 ///< PPI group used to disable self-disabling PPIs
55 #define DPPI_CHGRP_RAMP_UP_DIS_TASK NRF_DPPI_TASK_CHG0_DIS  ///< PPI task used to disable self-disabling PPIs
56 
57 #define PPI_DISABLED_EGU            NRF_802154_DPPI_RADIO_DISABLED
58 #define PPI_EGU_RAMP_UP             NRF_802154_DPPI_EGU_TO_RADIO_RAMP_UP
59 #define PPI_TIMER_TX_ACK            NRF_802154_DPPI_TIMER_COMPARE_TO_RADIO_TXEN
60 #define PPI_RADIO_SYNC_EGU_SYNC     NRF_802154_DPPI_RADIO_SYNC_TO_EGU_SYNC
61 
nrf_802154_trx_ppi_for_enable(void)62 void nrf_802154_trx_ppi_for_enable(void)
63 {
64     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_DISABLED, PPI_DISABLED_EGU);
65     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_READY, NRF_802154_DPPI_RADIO_READY);
66     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS, NRF_802154_DPPI_RADIO_ADDRESS);
67     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_END, NRF_802154_DPPI_RADIO_END);
68     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_PHYEND, NRF_802154_DPPI_RADIO_PHYEND);
69     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE, NRF_802154_DPPI_RADIO_CCAIDLE);
70     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY, NRF_802154_DPPI_RADIO_CCABUSY);
71 
72     nrf_dppi_channels_enable(NRF_802154_DPPIC_INSTANCE,
73                              (1UL << NRF_802154_DPPI_RADIO_CCABUSY) |
74                              (1UL << PPI_DISABLED_EGU) |
75                              (1UL << NRF_802154_DPPI_RADIO_READY) |
76                              (1UL << NRF_802154_DPPI_RADIO_ADDRESS) |
77                              (1UL << NRF_802154_DPPI_RADIO_END) |
78                              (1UL << NRF_802154_DPPI_RADIO_PHYEND) |
79                              (1UL << NRF_802154_DPPI_RADIO_CCAIDLE) |
80                              (1UL << NRF_802154_DPPI_RADIO_HW_TRIGGER));
81 }
82 
nrf_802154_trx_ppi_for_disable(void)83 void nrf_802154_trx_ppi_for_disable(void)
84 {
85     nrf_dppi_channels_disable(NRF_802154_DPPIC_INSTANCE,
86                               (1UL << NRF_802154_DPPI_RADIO_CCABUSY) |
87                               (1UL << PPI_DISABLED_EGU) |
88                               (1UL << NRF_802154_DPPI_RADIO_READY) |
89                               (1UL << NRF_802154_DPPI_RADIO_ADDRESS) |
90                               (1UL << NRF_802154_DPPI_RADIO_END) |
91                               (1UL << NRF_802154_DPPI_RADIO_PHYEND) |
92                               (1UL << NRF_802154_DPPI_RADIO_CCAIDLE) |
93                               (1UL << NRF_802154_DPPI_RADIO_HW_TRIGGER));
94 
95 #if NRF_802154_TEST_MODES_ENABLED
96     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY);
97 #endif // NRF_802154_TEST_MODES_ENABLED
98     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE);
99     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_PHYEND);
100     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_END);
101     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS);
102     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_READY);
103     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
104 }
105 
nrf_802154_trx_ppi_for_ramp_up_channel_id_get(void)106 uint8_t nrf_802154_trx_ppi_for_ramp_up_channel_id_get(void)
107 {
108     return NRF_802154_DPPI_RADIO_HW_TRIGGER;
109 }
110 
nrf_802154_trx_ppi_for_ramp_up_set(nrf_radio_task_t ramp_up_task,nrf_802154_trx_ramp_up_trigger_mode_t trigg_mode,bool start_timer)111 void nrf_802154_trx_ppi_for_ramp_up_set(nrf_radio_task_t                      ramp_up_task,
112                                         nrf_802154_trx_ramp_up_trigger_mode_t trigg_mode,
113                                         bool                                  start_timer)
114 {
115     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
116 
117     // Clr event EGU (needed for nrf_802154_trx_ppi_for_ramp_up_was_triggered)
118     nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, EGU_EVENT);
119 
120     nrf_dppi_channels_include_in_group(NRF_802154_DPPIC_INSTANCE,
121                                        1UL << PPI_EGU_RAMP_UP,
122                                        DPPI_CHGRP_RAMP_UP);
123 
124     nrf_radio_subscribe_set(NRF_RADIO, ramp_up_task, PPI_EGU_RAMP_UP);
125     nrf_dppi_subscribe_set(NRF_802154_DPPIC_INSTANCE, DPPI_CHGRP_RAMP_UP_DIS_TASK, PPI_EGU_RAMP_UP);
126 
127     if (start_timer)
128     {
129         nrf_timer_subscribe_set(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_START, PPI_DISABLED_EGU);
130     }
131 
132     nrf_egu_publish_set(NRF_802154_EGU_INSTANCE, EGU_EVENT, PPI_EGU_RAMP_UP);
133 
134     nrf_egu_subscribe_set(NRF_802154_EGU_INSTANCE, EGU_TASK, PPI_DISABLED_EGU);
135 
136     nrf_dppi_channels_enable(NRF_802154_DPPIC_INSTANCE,
137                              (1UL << PPI_EGU_RAMP_UP));
138 
139     if (trigg_mode == TRX_RAMP_UP_HW_TRIGGER)
140     {
141         nrf_radio_subscribe_set(NRF_RADIO,
142                                 NRF_RADIO_TASK_DISABLE,
143                                 NRF_802154_DPPI_RADIO_HW_TRIGGER);
144     }
145 
146     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
147 }
148 
nrf_802154_trx_ppi_for_extra_cca_attempts_set(void)149 void nrf_802154_trx_ppi_for_extra_cca_attempts_set(void)
150 {
151     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
152 
153     // Assume that NRF_802154_DPPI_RADIO_CCABUSY is enabled and NRF_RADIO_EVENT_CCABUSY publishes to it
154     nrf_radio_subscribe_set(NRF_RADIO, NRF_RADIO_TASK_CCASTART, NRF_802154_DPPI_RADIO_CCABUSY);
155 
156     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
157 }
158 
nrf_802154_trx_ppi_for_ramp_up_reconfigure(void)159 void nrf_802154_trx_ppi_for_ramp_up_reconfigure(void)
160 {
161     // Intentionally empty
162 }
163 
nrf_802154_trx_ppi_for_ramp_up_clear(nrf_radio_task_t ramp_up_task,bool start_timer)164 void nrf_802154_trx_ppi_for_ramp_up_clear(nrf_radio_task_t ramp_up_task, bool start_timer)
165 {
166     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
167 
168     nrf_dppi_channels_disable(NRF_802154_DPPIC_INSTANCE,
169                               (1UL << PPI_EGU_RAMP_UP));
170 
171     nrf_egu_publish_clear(NRF_802154_EGU_INSTANCE, EGU_EVENT);
172     nrf_radio_subscribe_clear(NRF_RADIO, ramp_up_task);
173     nrf_radio_subscribe_clear(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
174     nrf_dppi_subscribe_clear(NRF_802154_DPPIC_INSTANCE, DPPI_CHGRP_RAMP_UP_DIS_TASK);
175     nrf_dppi_channels_remove_from_group(NRF_802154_DPPIC_INSTANCE,
176                                         1UL << PPI_EGU_RAMP_UP,
177                                         DPPI_CHGRP_RAMP_UP);
178 
179     if (start_timer)
180     {
181         nrf_timer_subscribe_clear(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_START);
182     }
183 
184     nrf_egu_subscribe_clear(NRF_802154_EGU_INSTANCE, EGU_TASK);
185 
186     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
187 }
188 
nrf_802154_trx_ppi_for_extra_cca_attempts_clear(void)189 void nrf_802154_trx_ppi_for_extra_cca_attempts_clear(void)
190 {
191     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
192 
193     nrf_radio_subscribe_clear(NRF_RADIO, NRF_RADIO_TASK_CCASTART);
194 
195     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
196 }
197 
nrf_802154_trx_ppi_for_ramp_up_propagation_delay_wait(void)198 void nrf_802154_trx_ppi_for_ramp_up_propagation_delay_wait(void)
199 {
200     __ASM("nop");
201     __ASM("nop");
202     __ASM("nop");
203     __ASM("nop");
204     __ASM("nop");
205     __ASM("nop");
206 }
207 
nrf_802154_trx_ppi_for_ramp_up_was_triggered(void)208 bool nrf_802154_trx_ppi_for_ramp_up_was_triggered(void)
209 {
210     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
211 
212     if (nrf_radio_state_get(NRF_RADIO) != NRF_RADIO_STATE_DISABLED)
213     {
214         // If RADIO state is not DISABLED, it means that RADIO is still ramping down or already
215         // started ramping up.
216         nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
217         return true;
218     }
219 
220     // Wait for PPIs
221     nrf_802154_trx_ppi_for_ramp_up_propagation_delay_wait();
222 
223     if (nrf_egu_event_check(NRF_802154_EGU_INSTANCE, EGU_EVENT))
224     {
225         // If EGU event is set, procedure is running.
226         nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
227         return true;
228     }
229 
230     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
231     return false;
232 }
233 
nrf_802154_trx_ppi_for_ack_tx_set(void)234 void nrf_802154_trx_ppi_for_ack_tx_set(void)
235 {
236     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
237 
238     // TIMER_COMPARE1 ----> RADIO_TXEN
239     nrf_radio_subscribe_set(NRF_RADIO, NRF_RADIO_TASK_TXEN, PPI_TIMER_TX_ACK);
240     nrf_timer_publish_set(NRF_802154_TIMER_INSTANCE, NRF_TIMER_EVENT_COMPARE1, PPI_TIMER_TX_ACK);
241 
242     nrf_dppi_channels_enable(NRF_802154_DPPIC_INSTANCE, (1UL << PPI_TIMER_TX_ACK));
243 
244     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
245 }
246 
nrf_802154_trx_ppi_for_ack_tx_clear(void)247 void nrf_802154_trx_ppi_for_ack_tx_clear(void)
248 {
249     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
250 
251     nrf_dppi_channels_disable(NRF_802154_DPPIC_INSTANCE, (1UL << PPI_TIMER_TX_ACK));
252 
253     nrf_radio_subscribe_clear(NRF_RADIO, NRF_RADIO_TASK_TXEN);
254     nrf_timer_publish_clear(NRF_802154_TIMER_INSTANCE, NRF_TIMER_EVENT_COMPARE1);
255 
256     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
257 }
258 
nrf_802154_trx_ppi_for_fem_set(void)259 void nrf_802154_trx_ppi_for_fem_set(void)
260 {
261     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
262 
263     nrf_timer_subscribe_set(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_START, PPI_DISABLED_EGU);
264 
265     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
266 }
267 
nrf_802154_trx_ppi_for_fem_clear(void)268 void nrf_802154_trx_ppi_for_fem_clear(void)
269 {
270     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
271 
272     nrf_timer_subscribe_clear(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_START);
273 
274     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
275 }
276 
nrf_802154_trx_ppi_group_for_abort_get(void)277 uint32_t nrf_802154_trx_ppi_group_for_abort_get(void)
278 {
279     // TODO: Implement it when external event (like coex) can abort radio operation
280     return 0;
281 }
282 
283 #if defined(RADIO_INTENSET_SYNC_Msk)
nrf_802154_trx_ppi_for_radio_sync_set(nrf_egu_task_t task)284 void nrf_802154_trx_ppi_for_radio_sync_set(nrf_egu_task_t task)
285 {
286     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
287 
288     nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_SYNC, PPI_RADIO_SYNC_EGU_SYNC);
289     nrf_egu_subscribe_set(NRF_802154_EGU_INSTANCE, task, PPI_RADIO_SYNC_EGU_SYNC);
290     nrf_dppi_channels_enable(NRF_802154_DPPIC_INSTANCE, (1UL << PPI_RADIO_SYNC_EGU_SYNC));
291 
292     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
293 }
294 
nrf_802154_trx_ppi_for_radio_sync_clear(nrf_egu_task_t task)295 void nrf_802154_trx_ppi_for_radio_sync_clear(nrf_egu_task_t task)
296 {
297     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
298 
299     nrf_dppi_channels_disable(NRF_802154_DPPIC_INSTANCE, (1UL << PPI_RADIO_SYNC_EGU_SYNC));
300     nrf_radio_publish_clear(NRF_RADIO, NRF_RADIO_EVENT_SYNC);
301     nrf_egu_subscribe_clear(NRF_802154_EGU_INSTANCE, task);
302 
303     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
304 }
305 
306 #endif
307 
308 #endif // defined(DPPI_PRESENT)
309