1 /*
2  * Copyright (c) 2023 - 2024, 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 <helpers/nrfx_gppi.h>
35 
36 #if defined(LUMOS_XXAA)
37 
38 #include <helpers/nrfx_flag32_allocator.h>
39 #include <hal/nrf_ppib.h>
40 #include <hal/nrf_dppi.h>
41 
42 #include <soc/interconnect/dppic_ppib/nrfx_interconnect_dppic_ppib.h>
43 
44 #include <soc/interconnect/dppic_ppib/nrfx_interconnect_dppic_ppib_lumos.h>
45 
46 /** @brief Invalid channel number. */
47 #define NRFX_GPPI_CHANNEL_INVALID UINT8_MAX
48 
49 #if defined(NRF54L15_ENGA_XXAA)
50 #define NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG 0
51 #else
52 #define NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG 1
53 #endif
54 
55 static nrfx_atomic_t m_virtual_channels = NRFX_GPPI_PROG_APP_CHANNELS_MASK;
56 
dppic_channel_get(nrfx_interconnect_dppic_t * p_dppic,uint8_t virtual_channel,uint8_t * p_dppic_channel)57 static nrfx_err_t dppic_channel_get(nrfx_interconnect_dppic_t * p_dppic,
58                                     uint8_t                     virtual_channel,
59                                     uint8_t *                   p_dppic_channel)
60 {
61     for (uint8_t i = 0; i < NRF_DPPI_CH_NUM_MAX; i++)
62     {
63         if (p_dppic->allocate_flag[i] == virtual_channel)
64         {
65             *p_dppic_channel = i;
66             return NRFX_SUCCESS;
67         }
68     }
69 
70     return NRFX_ERROR_INVALID_PARAM;
71 }
72 
dppic_virtual_channel_set(nrfx_interconnect_dppic_t * p_dppic,uint32_t dppi_channel,uint8_t virtual_channel)73 static nrfx_err_t dppic_virtual_channel_set(nrfx_interconnect_dppic_t * p_dppic,
74                                             uint32_t                    dppi_channel,
75                                             uint8_t                     virtual_channel)
76 {
77     p_dppic->allocate_flag[dppi_channel] = virtual_channel;
78 
79     return NRFX_SUCCESS;
80 }
81 
dppic_channel_alloc(nrfx_interconnect_dppic_t * p_dppic,uint8_t * p_channel)82 static nrfx_err_t dppic_channel_alloc(nrfx_interconnect_dppic_t * p_dppic, uint8_t * p_channel)
83 {
84     return nrfx_flag32_alloc(&p_dppic->channels_mask, p_channel);
85 }
86 
dppic_channel_free(nrfx_interconnect_dppic_t * p_dppic,uint8_t channel)87 static nrfx_err_t dppic_channel_free(nrfx_interconnect_dppic_t * p_dppic, uint8_t channel)
88 {
89     return nrfx_flag32_free(&p_dppic->channels_mask, channel);
90 }
91 
ppib_channel_get(nrfx_interconnect_ppib_t * p_ppib,uint8_t virtual_channel,uint8_t * p_ppib_channel)92 static nrfx_err_t ppib_channel_get(nrfx_interconnect_ppib_t * p_ppib,
93                                    uint8_t                    virtual_channel,
94                                    uint8_t *                  p_ppib_channel)
95 {
96     for (uint8_t i = 0; i < PPIB_CHANNEL_MAX_COUNT; i++)
97     {
98         if (p_ppib->allocate_flag[i] == virtual_channel)
99         {
100             *p_ppib_channel = i;
101             return NRFX_SUCCESS;
102         }
103     }
104 
105     return NRFX_ERROR_INVALID_PARAM;
106 }
107 
108 #if NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG
ppib_channel_alloc(nrfx_interconnect_ppib_t * p_ppib,uint8_t * p_channel)109 static nrfx_err_t ppib_channel_alloc(nrfx_interconnect_ppib_t * p_ppib, uint8_t * p_channel)
110 {
111     return nrfx_flag32_alloc(&p_ppib->channels_mask, p_channel);
112 }
113 #endif
114 
ppib_channel_free(nrfx_interconnect_ppib_t * p_ppib,uint8_t channel)115 static nrfx_err_t ppib_channel_free(nrfx_interconnect_ppib_t * p_ppib, uint8_t channel)
116 {
117     return nrfx_flag32_free(&p_ppib->channels_mask, channel);
118 }
119 
ppib_virtual_channel_set(nrfx_interconnect_ppib_t * p_ppib,uint32_t ppib_channel,uint8_t virtual_channel)120 static nrfx_err_t ppib_virtual_channel_set(nrfx_interconnect_ppib_t * p_ppib,
121                                            uint32_t                   ppib_channel,
122                                            uint8_t                    virtual_channel)
123 {
124     p_ppib->allocate_flag[ppib_channel] = virtual_channel;
125 
126     return NRFX_SUCCESS;
127 }
128 
129 /* Enable or disable all channels for all involved DPPIC peripherals. */
virtual_channel_enable_set(uint8_t virtual_channel,bool enable)130 static void virtual_channel_enable_set(uint8_t virtual_channel, bool enable)
131 {
132     for (uint8_t i = 0; i < NRFX_INTERCONNECT_DPPIC_COUNT; i++)
133     {
134         nrfx_interconnect_dppic_t * dppic = nrfx_interconnect_dppic_at_index_get(i);
135         uint8_t dppi_channel;
136         nrfx_err_t err = dppic_channel_get(dppic, virtual_channel, &dppi_channel);
137         if (err == NRFX_SUCCESS)
138         {
139             nrfy_dppi_channels_set(dppic->dppic, NRFX_BIT((uint32_t)dppi_channel), enable);
140         }
141     }
142 }
143 
init(void)144 static void init(void)
145 {
146     static bool initialized = false;
147 
148     if (initialized)
149     {
150         return;
151     }
152 
153     for (uint8_t i = 0; i < NRFX_INTERCONNECT_DPPIC_COUNT; i++)
154     {
155         nrfx_interconnect_dppic_t * dppic = nrfx_interconnect_dppic_at_index_get(i);
156         for (uint8_t j = 0; j < NRF_DPPI_CH_NUM_MAX; j++)
157         {
158             dppic_virtual_channel_set(dppic, j, NRFX_GPPI_CHANNEL_INVALID);
159         }
160     }
161 
162     for (uint8_t i = 0; i < NRFX_INTERCONNECT_PPIB_COUNT; i++)
163     {
164         nrfx_interconnect_ppib_t * ppib = nrfx_interconnect_ppib_at_index_get(i);
165         for (uint8_t j = 0; j < PPIB_CHANNEL_MAX_COUNT; j++)
166         {
167             ppib_virtual_channel_set(ppib, j, NRFX_GPPI_CHANNEL_INVALID);
168         }
169     }
170 
171     initialized = true;
172 }
173 
create_ppib_connection(uint8_t virtual_channel,nrfx_interconnect_dppic_to_dppic_path_t * p_path,uint8_t src_dppi_channel,uint8_t dst_dppi_channel)174 static nrfx_err_t create_ppib_connection(uint8_t                                   virtual_channel,
175                                          nrfx_interconnect_dppic_to_dppic_path_t * p_path,
176                                          uint8_t                                   src_dppi_channel,
177                                          uint8_t                                   dst_dppi_channel)
178 {
179     nrfx_interconnect_ppib_t * p_ppib = p_path->ppib;
180     uint8_t    ppib_channel;
181 #if NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG
182     nrfx_err_t err = ppib_channel_alloc(p_ppib, &ppib_channel);
183 
184     if (err != NRFX_SUCCESS)
185     {
186         return err;
187     }
188 #else
189     NRFX_ASSERT(src_dppi_channel == dst_dppi_channel);
190     ppib_channel = src_dppi_channel;
191 #endif
192 
193     ppib_virtual_channel_set(p_ppib, ppib_channel, virtual_channel);
194     nrf_ppib_task_t  task  = nrf_ppib_send_task_get(ppib_channel);
195     nrf_ppib_event_t event = nrf_ppib_receive_event_get(ppib_channel);
196     if (p_path->ppib_inverted == false)
197     {
198         nrf_ppib_subscribe_set(p_ppib->p_ppib1, task, src_dppi_channel);
199         nrf_ppib_publish_set(p_ppib->p_ppib2, event, dst_dppi_channel);
200     }
201     else
202     {
203         nrf_ppib_subscribe_set(p_ppib->p_ppib2, task, src_dppi_channel);
204         nrf_ppib_publish_set(p_ppib->p_ppib1, event, dst_dppi_channel);
205     }
206     return NRFX_SUCCESS;
207 }
208 
clear_virtual_channel_path(uint8_t virtual_channel)209 static nrfx_err_t clear_virtual_channel_path(uint8_t virtual_channel)
210 {
211     // Clear all DPPI channel masks.
212     for (uint8_t i = 0; i < NRFX_INTERCONNECT_DPPIC_COUNT; i++)
213     {
214         nrfx_interconnect_dppic_t * dppic = nrfx_interconnect_dppic_at_index_get(i);
215         uint8_t dppi_channel;
216         nrfx_err_t err = dppic_channel_get(dppic, virtual_channel, &dppi_channel);
217         if (err == NRFX_SUCCESS)
218         {
219             nrfy_dppi_channels_set(dppic->dppic, NRFX_BIT((uint32_t)dppi_channel), false);
220 
221             err = dppic_channel_free(dppic, dppi_channel);
222             if (err != NRFX_SUCCESS)
223             {
224                 return err;
225             }
226 
227             err = dppic_virtual_channel_set(dppic,
228                                             (uint32_t)dppi_channel,
229                                             NRFX_GPPI_CHANNEL_INVALID);
230             if (err != NRFX_SUCCESS)
231             {
232                 return err;
233             }
234         }
235     }
236 
237     // Clear all PPIB channel masks.
238     for (uint8_t i = 0; i < NRFX_INTERCONNECT_PPIB_COUNT; i++)
239     {
240         nrfx_interconnect_ppib_t * p_ppib = nrfx_interconnect_ppib_at_index_get(i);
241         uint8_t ppib_channel;
242         nrfx_err_t err = ppib_channel_get(p_ppib, virtual_channel, &ppib_channel);
243         if (err == NRFX_SUCCESS)
244         {
245             nrf_ppib_task_t task   = nrf_ppib_send_task_get((uint32_t)ppib_channel);
246             nrf_ppib_event_t event = nrf_ppib_receive_event_get((uint32_t)ppib_channel);
247 
248             nrf_ppib_subscribe_clear(p_ppib->p_ppib1, task);
249             nrf_ppib_subscribe_clear(p_ppib->p_ppib2, task);
250 
251             nrf_ppib_publish_clear(p_ppib->p_ppib1, event);
252             nrf_ppib_publish_clear(p_ppib->p_ppib2, event);
253 
254             err = ppib_channel_free(p_ppib, ppib_channel);
255             if (err != NRFX_SUCCESS)
256             {
257                 return err;
258             }
259 
260             err = ppib_virtual_channel_set(p_ppib, (uint32_t)ppib_channel, NRFX_GPPI_CHANNEL_INVALID);
261             if (err != NRFX_SUCCESS)
262             {
263                 return err;
264             }
265         }
266     }
267 
268     return NRFX_SUCCESS;
269 }
270 
nrfx_gppi_channel_alloc(uint8_t * p_channel)271 nrfx_err_t nrfx_gppi_channel_alloc(uint8_t * p_channel)
272 {
273     init();
274     return nrfx_flag32_alloc(&m_virtual_channels, p_channel);
275 }
276 
nrfx_gppi_event_endpoint_setup(uint8_t channel,uint32_t eep)277 void nrfx_gppi_event_endpoint_setup(uint8_t channel, uint32_t eep)
278 {
279     (void)channel;
280     (void)eep;
281     // `tep` is also needed to decide whether `main_apb` is to be used.
282     NRFX_ASSERT(false);
283 }
284 
nrfx_gppi_task_endpoint_setup(uint8_t channel,uint32_t tep)285 void nrfx_gppi_task_endpoint_setup(uint8_t channel, uint32_t tep)
286 {
287     (void)channel;
288     (void)tep;
289     // `eep` is also needed to decide whether `main_apb` is to be used.
290     NRFX_ASSERT(false);
291 }
292 
nrfx_gppi_event_endpoint_clear(uint8_t channel,uint32_t eep)293 void nrfx_gppi_event_endpoint_clear(uint8_t channel, uint32_t eep)
294 {
295     (void)channel;
296     (void)eep;
297     // `tep` is also needed to decide whether `main_apb` is to be used.
298     NRFX_ASSERT(false);
299 }
300 
nrfx_gppi_task_endpoint_clear(uint8_t channel,uint32_t tep)301 void nrfx_gppi_task_endpoint_clear(uint8_t channel, uint32_t tep)
302 {
303     (void)channel;
304     (void)tep;
305     // `eep` is also needed to decide whether `main_apb` is to be used.
306     NRFX_ASSERT(false);
307 }
308 
nrfx_gppi_fork_endpoint_setup(uint8_t channel,uint32_t fork_tep)309 void nrfx_gppi_fork_endpoint_setup(uint8_t channel, uint32_t fork_tep)
310 {
311     for (uint8_t i = 0; i < NRFX_INTERCONNECT_DPPIC_COUNT; i++)
312     {
313         nrfx_interconnect_dppic_t * dppic = nrfx_interconnect_dppic_at_index_get(i);
314         uint8_t dppi_channel;
315         nrfx_err_t err = dppic_channel_get(dppic, channel, &dppi_channel);
316         if (err == NRFX_SUCCESS)
317         {
318             NRF_DPPI_ENDPOINT_SETUP(fork_tep, (uint32_t)dppi_channel);
319             return;
320         }
321     }
322     NRFX_ASSERT(false);
323 }
324 
nrfx_gppi_fork_endpoint_clear(uint8_t channel,uint32_t fork_tep)325 void nrfx_gppi_fork_endpoint_clear(uint8_t channel, uint32_t fork_tep)
326 {
327     for (uint8_t i = 0; i < NRFX_INTERCONNECT_DPPIC_COUNT; i++)
328     {
329         nrfx_interconnect_dppic_t * dppic = nrfx_interconnect_dppic_at_index_get(i);
330         uint8_t dppi_channel;
331         nrfx_err_t err = dppic_channel_get(dppic, channel, &dppi_channel);
332         if (err == NRFX_SUCCESS)
333         {
334             NRF_DPPI_ENDPOINT_CLEAR(fork_tep);
335             return;
336         }
337     }
338     NRFX_ASSERT(false);
339 }
340 
nrfx_gppi_channel_endpoints_setup(uint8_t channel,uint32_t eep,uint32_t tep)341 void nrfx_gppi_channel_endpoints_setup(uint8_t channel, uint32_t eep, uint32_t tep)
342 {
343     nrfx_err_t err = NRFX_SUCCESS;
344     nrf_apb_index_t src_domain = nrfx_interconnect_apb_index_get(eep);
345     nrf_apb_index_t dst_domain = nrfx_interconnect_apb_index_get(tep);
346 
347     NRFX_ASSERT(src_domain);
348     NRFX_ASSERT(dst_domain);
349 
350     uint8_t src_dppi_channel;
351     uint8_t dst_dppi_channel;
352 
353     if (src_domain == dst_domain)
354     {
355         nrfx_interconnect_dppic_t * dppic = nrfx_interconnect_dppic_get(src_domain);
356         if (dppic_channel_alloc(dppic, &src_dppi_channel) == NRFX_SUCCESS)
357         {
358             dst_dppi_channel = src_dppi_channel;
359             dppic_virtual_channel_set(dppic, src_dppi_channel, channel);
360         }
361         else
362         {
363             clear_virtual_channel_path(channel);
364             NRFX_ASSERT(false);
365             return;
366         }
367     }
368     else
369     {
370         nrfx_interconnect_dppic_t * p_src_dppic = nrfx_interconnect_dppic_get(src_domain);
371         nrfx_interconnect_dppic_t * p_dst_dppic = nrfx_interconnect_dppic_get(dst_domain);
372 
373         nrfx_interconnect_dppic_to_dppic_path_t path =
374         {
375             .src_dppic = p_src_dppic,
376             .dst_dppic = p_dst_dppic,
377         };
378 
379         if (nrfx_interconnect_direct_connection_check(&path))
380         {
381 #if !NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG
382             nrfx_atomic_t possible_mask = path.src_dppic->channels_mask;
383             possible_mask &= path.dst_dppic->channels_mask;
384             possible_mask &= path.ppib->channels_mask;
385 
386             uint8_t common_channel;
387             nrfx_flag32_alloc(&possible_mask, &common_channel);
388             if (err != NRFX_SUCCESS)
389             {
390                 clear_virtual_channel_path(channel);
391                 NRFX_ASSERT(false);
392                 return;
393             }
394 
395             path.src_dppic->channels_mask &= ~NRFX_BIT(common_channel);
396             path.dst_dppic->channels_mask &= ~NRFX_BIT(common_channel);
397             path.ppib->channels_mask &= ~NRFX_BIT(common_channel);
398 
399             src_dppi_channel = common_channel;
400             dst_dppi_channel = common_channel;
401 #else
402             err = dppic_channel_alloc(p_src_dppic, &src_dppi_channel);
403             if (err != NRFX_SUCCESS)
404             {
405                 clear_virtual_channel_path(channel);
406                 NRFX_ASSERT(false);
407                 return;
408             }
409 #endif
410             dppic_virtual_channel_set(p_src_dppic, src_dppi_channel, channel);
411 #if NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG
412             err = dppic_channel_alloc(p_dst_dppic, &dst_dppi_channel);
413             if (err != NRFX_SUCCESS)
414             {
415                 clear_virtual_channel_path(channel);
416                 NRFX_ASSERT(false);
417                 return;
418             }
419 #endif
420             dppic_virtual_channel_set(p_dst_dppic, dst_dppi_channel, channel);
421 
422             err = create_ppib_connection(channel,
423                                          &path,
424                                          src_dppi_channel,
425                                          dst_dppi_channel);
426             if (err != NRFX_SUCCESS)
427             {
428                 clear_virtual_channel_path(channel);
429                 NRFX_ASSERT(false);
430                 return;
431             }
432         }
433         else
434         {
435             nrfx_interconnect_dppic_t * p_main_dppic = nrfx_interconnect_dppic_main_get();
436             p_src_dppic = nrfx_interconnect_dppic_get(src_domain);
437             p_dst_dppic = nrfx_interconnect_dppic_get(dst_domain);
438 
439             nrfx_interconnect_dppic_to_dppic_path_t path_src_to_main =
440             {
441                 .src_dppic = p_src_dppic,
442                 .dst_dppic = p_main_dppic,
443             };
444 
445             nrfx_interconnect_dppic_to_dppic_path_t path_main_to_dst =
446             {
447                 .src_dppic = p_main_dppic,
448                 .dst_dppic = p_dst_dppic,
449             };
450 
451             if (nrfx_interconnect_direct_connection_check(&path_src_to_main) &&
452                 nrfx_interconnect_direct_connection_check(&path_main_to_dst))
453             {
454                 uint8_t main_dppi_channel;
455 #if !NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG
456                 nrfx_atomic_t possible_mask = p_src_dppic->channels_mask;
457                 possible_mask &= p_main_dppic->channels_mask;
458                 possible_mask &= p_dst_dppic->channels_mask;
459                 possible_mask &= path_src_to_main.ppib->channels_mask;
460                 possible_mask &= path_main_to_dst.ppib->channels_mask;
461 
462                 uint8_t common_channel;
463                 nrfx_flag32_alloc(&possible_mask, &common_channel);
464                 if (err != NRFX_SUCCESS)
465                 {
466                     clear_virtual_channel_path(channel);
467                     NRFX_ASSERT(false);
468                     return;
469                 }
470 
471                 p_src_dppic->channels_mask &= ~NRFX_BIT(common_channel);
472                 p_main_dppic->channels_mask &= ~NRFX_BIT(common_channel);
473                 p_dst_dppic->channels_mask &= ~NRFX_BIT(common_channel);
474                 path_src_to_main.ppib->channels_mask &= ~NRFX_BIT(common_channel);
475                 path_main_to_dst.ppib->channels_mask &= ~NRFX_BIT(common_channel);
476 
477                 dppic_virtual_channel_set(p_src_dppic, common_channel, channel);
478                 dppic_virtual_channel_set(p_main_dppic, common_channel, channel);
479                 dppic_virtual_channel_set(p_dst_dppic, common_channel, channel);
480 
481                 src_dppi_channel = common_channel;
482                 dst_dppi_channel = common_channel;
483                 main_dppi_channel = common_channel;
484 #else
485                 err = dppic_channel_alloc(p_src_dppic, &src_dppi_channel);
486                 if (err != NRFX_SUCCESS)
487                 {
488                     clear_virtual_channel_path(channel);
489                     NRFX_ASSERT(false);
490                     return;
491                 }
492 #endif
493                 dppic_virtual_channel_set(p_src_dppic, src_dppi_channel, channel);
494 #if NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG
495                 err = dppic_channel_alloc(p_main_dppic, &main_dppi_channel);
496                 if (err != NRFX_SUCCESS)
497                 {
498                     clear_virtual_channel_path(channel);
499                     NRFX_ASSERT(false);
500                     return;
501                 }
502 #endif
503                 dppic_virtual_channel_set(p_main_dppic, main_dppi_channel, channel);
504 #if NRFX_GPPI_PPIB_HAS_DYNAMIC_CONFIG
505                 err = dppic_channel_alloc(p_dst_dppic, &dst_dppi_channel);
506                 if (err != NRFX_SUCCESS)
507                 {
508                     clear_virtual_channel_path(channel);
509                     NRFX_ASSERT(false);
510                     return;
511                 }
512 #endif
513                 dppic_virtual_channel_set(p_dst_dppic, dst_dppi_channel, channel);
514 
515                 err = create_ppib_connection(channel,
516                                              &path_src_to_main ,
517                                              src_dppi_channel,
518                                              main_dppi_channel);
519                 if (err != NRFX_SUCCESS)
520                 {
521                     clear_virtual_channel_path(channel);
522                     NRFX_ASSERT(false);
523                     return;
524                 }
525 
526                 err = create_ppib_connection(channel,
527                                              &path_main_to_dst,
528                                              main_dppi_channel,
529                                              dst_dppi_channel);
530                 if (err != NRFX_SUCCESS)
531                 {
532                     clear_virtual_channel_path(channel);
533                     NRFX_ASSERT(false);
534                     return;
535                 }
536             }
537             else
538             {
539                 clear_virtual_channel_path(channel);
540                 NRFX_ASSERT(false);
541                 return;
542             }
543         }
544     }
545 
546     if (err == NRFX_SUCCESS)
547     {
548         NRF_DPPI_ENDPOINT_SETUP(eep, src_dppi_channel);
549         NRF_DPPI_ENDPOINT_SETUP(tep, dst_dppi_channel);
550     }
551 }
552 
nrfx_gppi_channel_endpoints_clear(uint8_t channel,uint32_t eep,uint32_t tep)553 void nrfx_gppi_channel_endpoints_clear(uint8_t channel, uint32_t eep, uint32_t tep)
554 {
555     clear_virtual_channel_path(channel);
556 
557     NRF_DPPI_ENDPOINT_CLEAR(eep);
558     NRF_DPPI_ENDPOINT_CLEAR(tep);
559 }
560 
nrfx_gppi_channel_free(uint8_t channel)561 nrfx_err_t nrfx_gppi_channel_free(uint8_t channel)
562 {
563     nrfx_err_t err = nrfx_flag32_free(&m_virtual_channels, channel);
564 
565     if(err != NRFX_SUCCESS)
566     {
567         return err;
568     }
569 
570     return clear_virtual_channel_path(channel);
571 }
572 
nrfx_gppi_channel_check(uint8_t channel)573 bool nrfx_gppi_channel_check(uint8_t channel)
574 {
575     NRFX_ASSERT(nrfx_flag32_is_allocated(m_virtual_channels, channel));
576 
577     for (uint8_t i = 0; i < NRFX_INTERCONNECT_DPPIC_COUNT; i++)
578     {
579         nrfx_interconnect_dppic_t * dppic = nrfx_interconnect_dppic_at_index_get(i);
580         uint8_t dppi_channel;
581         nrfx_err_t err = dppic_channel_get(dppic, channel, &dppi_channel);
582         if (err == NRFX_SUCCESS)
583         {
584             if (nrf_dppi_channel_check(dppic->dppic, (uint32_t)dppi_channel) == false)
585             {
586                 return false;
587             }
588             break;
589         }
590     }
591 
592     return true;
593 }
594 
nrfx_gppi_channels_disable_all(void)595 void nrfx_gppi_channels_disable_all(void)
596 {
597     uint32_t mask = ~(uint32_t)m_virtual_channels;
598 
599     while (mask)
600     {
601         uint8_t channel = (uint8_t)NRF_CTZ(mask);
602         virtual_channel_enable_set(channel, false);
603         mask &= ~NRFX_BIT(channel);
604     }
605 }
606 
nrfx_gppi_channels_enable(uint32_t mask)607 void nrfx_gppi_channels_enable(uint32_t mask)
608 {
609     while (mask)
610     {
611         uint8_t channel = (uint8_t)NRF_CTZ(mask);
612         virtual_channel_enable_set(channel, true);
613         mask &= ~NRFX_BIT(channel);
614     }
615 }
616 
nrfx_gppi_channels_disable(uint32_t mask)617 void nrfx_gppi_channels_disable(uint32_t mask)
618 {
619     // Remove all connections for all channels determined by mask.
620     while (mask)
621     {
622         // Remove assigned channels for all involved DPPICn peripherals.
623         uint8_t channel = (uint8_t)NRF_CTZ(mask);
624         virtual_channel_enable_set(channel, false);
625         mask &= ~NRFX_BIT(channel);
626     }
627 }
628 
629 #endif // defined(LUMOS_XXAA)
630