1 /***************************************************************************//**
2 * \file cyhal_utils_impl.c
3 *
4 * \brief
5 * Provides utility functions for working with the CAT1/CAT2 HAL implementation.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
10 * an affiliate of Cypress Semiconductor Corporation
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 *     http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 *******************************************************************************/
26 
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include "cyhal_utils.h"
30 #include "cyhal_utils_impl.h"
31 #include "cyhal_hwmgr.h"
32 #include "cyhal_interconnect.h"
33 #include "cyhal_clock.h"
34 
35 #if defined(__cplusplus)
36 extern "C"
37 {
38 #endif
39 
40 #if defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C)
41 #define _CYHAL_MXSPERI_PCLK_DIV_CNT(gr) \
42     case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_8BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_8_VECT; \
43     case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_16BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_16_VECT; \
44     case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_16_5BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_16_5_VECT; \
45     case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_24_5BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_24_5_VECT;
46 #elif defined(COMPONENT_CAT1D)
47 #define _CYHAL_MXSPERI_PCLK_DIV_CNT(instance, gr) \
48     case CYHAL_CLOCK_BLOCK##instance##_PERIPHERAL##gr##_8BIT: return PERI##instance##_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_8_VECT; \
49     case CYHAL_CLOCK_BLOCK##instance##_PERIPHERAL##gr##_16BIT: return PERI##instance##_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_16_VECT; \
50     case CYHAL_CLOCK_BLOCK##instance##_PERIPHERAL##gr##_16_5BIT: return PERI##instance##_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_16_5_VECT; \
51     case CYHAL_CLOCK_BLOCK##instance##_PERIPHERAL##gr##_24_5BIT: return PERI##instance##_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_24_5_VECT;
52 #endif
53 
_cyhal_utils_reserve_and_connect(const cyhal_resource_pin_mapping_t * mapping,uint8_t drive_mode)54 cy_rslt_t _cyhal_utils_reserve_and_connect(const cyhal_resource_pin_mapping_t *mapping, uint8_t drive_mode)
55 {
56     cyhal_resource_inst_t pinRsc = _cyhal_utils_get_gpio_resource(mapping->pin);
57     cy_rslt_t status = cyhal_hwmgr_reserve(&pinRsc);
58     if (CY_RSLT_SUCCESS == status)
59     {
60         status = cyhal_connect_pin(mapping, drive_mode);
61         if (CY_RSLT_SUCCESS != status)
62         {
63             cyhal_hwmgr_free(&pinRsc);
64         }
65     }
66     return status;
67 }
68 
_cyhal_utils_disconnect_and_free(cyhal_gpio_t pin)69 void _cyhal_utils_disconnect_and_free(cyhal_gpio_t pin)
70 {
71     cy_rslt_t rslt = cyhal_disconnect_pin(pin);
72     CY_UNUSED_PARAMETER(rslt); /* CY_ASSERT only processes in DEBUG, ignores for others */
73     CY_ASSERT(CY_RSLT_SUCCESS == rslt);
74     cyhal_resource_inst_t rsc = _cyhal_utils_get_gpio_resource(pin);
75     cyhal_hwmgr_free(&rsc);
76 }
77 
_cyhal_utils_convert_haltopdl_pm_mode(cyhal_syspm_callback_mode_t mode)78 cy_en_syspm_callback_mode_t _cyhal_utils_convert_haltopdl_pm_mode(cyhal_syspm_callback_mode_t mode)
79 {
80     switch (mode)
81     {
82         case CYHAL_SYSPM_CHECK_READY:
83             return CY_SYSPM_CHECK_READY;
84         case CYHAL_SYSPM_CHECK_FAIL:
85             return CY_SYSPM_CHECK_FAIL;
86         case CYHAL_SYSPM_BEFORE_TRANSITION:
87             return CY_SYSPM_BEFORE_TRANSITION;
88         case CYHAL_SYSPM_AFTER_TRANSITION:
89             return CY_SYSPM_AFTER_TRANSITION;
90 #if defined(COMPONENT_CAT1B)
91         case CYHAL_SYSPM_AFTER_DS_WFI_TRANSITION:
92             return CY_SYSPM_AFTER_DS_WFI_TRANSITION;
93 #endif
94         default:
95             /* Should not get here */
96             CY_ASSERT(false);
97             return CY_SYSPM_CHECK_READY;
98     }
99 }
100 
_cyhal_utils_convert_pdltohal_pm_mode(cy_en_syspm_callback_mode_t mode)101 cyhal_syspm_callback_mode_t _cyhal_utils_convert_pdltohal_pm_mode(cy_en_syspm_callback_mode_t mode)
102 {
103     switch (mode)
104     {
105         case CY_SYSPM_CHECK_READY:
106             return CYHAL_SYSPM_CHECK_READY;
107         case CY_SYSPM_CHECK_FAIL:
108             return CYHAL_SYSPM_CHECK_FAIL;
109         case CY_SYSPM_BEFORE_TRANSITION:
110             return CYHAL_SYSPM_BEFORE_TRANSITION;
111         case CY_SYSPM_AFTER_TRANSITION:
112             return CYHAL_SYSPM_AFTER_TRANSITION;
113 #if defined(COMPONENT_CAT1B)
114         case CY_SYSPM_AFTER_DS_WFI_TRANSITION:
115             return CYHAL_SYSPM_AFTER_DS_WFI_TRANSITION;
116 #endif
117         default:
118             /* Should not get here */
119             CY_ASSERT(false);
120             return CYHAL_SYSPM_CHECK_READY;
121     }
122 }
123 
_cyhal_utils_calculate_tolerance(cyhal_clock_tolerance_unit_t type,uint32_t desired_hz,uint32_t actual_hz)124 int32_t _cyhal_utils_calculate_tolerance(cyhal_clock_tolerance_unit_t type, uint32_t desired_hz, uint32_t actual_hz)
125 {
126     switch (type)
127     {
128         case CYHAL_TOLERANCE_HZ:
129             return (int32_t)(desired_hz - actual_hz);
130         case CYHAL_TOLERANCE_PPM:
131             return (int32_t)(((int64_t)(desired_hz - actual_hz)) * 1000000) / ((int32_t)desired_hz);
132         case CYHAL_TOLERANCE_PERCENT:
133             return (int32_t)((((int64_t)desired_hz - actual_hz) * 100) / desired_hz);
134         default:
135             CY_ASSERT(false);
136             return 0;
137     }
138 }
139 
_cyhal_utils_allocate_peri(cyhal_clock_t * clock,uint8_t peri_group,cyhal_clock_block_t div,bool accept_larger)140 static inline cy_rslt_t _cyhal_utils_allocate_peri(cyhal_clock_t *clock, uint8_t peri_group, cyhal_clock_block_t div, bool accept_larger)
141 {
142     static const cyhal_clock_block_t PERI_DIVIDERS[] =
143     {
144         CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT,
145         CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT,
146         CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT,
147         CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT
148     };
149 
150     cy_rslt_t result = CYHAL_HWMGR_RSLT_ERR_NONE_FREE;
151     bool found_minimum = false;
152 
153 #if defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
154     bool dividers_exist = false;
155 #endif
156     for(size_t i = 0; i < sizeof(PERI_DIVIDERS) / sizeof(PERI_DIVIDERS[0]); ++i)
157     {
158         if(PERI_DIVIDERS[i] == div)
159         {
160             found_minimum = true;
161         }
162 
163         if(found_minimum)
164         {
165 #if defined(COMPONENT_CAT1A)
166             CY_UNUSED_PARAMETER(peri_group);
167             result = _cyhal_clock_allocate_peri(clock, PERI_DIVIDERS[i]);
168 #elif defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
169 #if !defined(COMPONENT_CAT1D)
170             cyhal_clock_block_t adjusted_div = (cyhal_clock_block_t)_CYHAL_PERIPHERAL_GROUP_ADJUST(peri_group, PERI_DIVIDERS[i]);
171 #else /* !defined(COMPONENT_CAT1D) */
172             uint8_t instance = _CYHAL_UTILS_UNPACK_INSTANCE(peri_group);
173             uint8_t group = _CYHAL_UTILS_UNPACK_GROUP(peri_group);
174             cyhal_clock_block_t adjusted_div = (cyhal_clock_block_t)_CYHAL_PERIPHERAL_GROUP_ADJUST(instance, group, PERI_DIVIDERS[i]);
175 #endif /* !defined(COMPONENT_CAT1D) or other */
176             dividers_exist |= (_cyhal_utils_get_clock_count(adjusted_div) > 0);
177             result = _cyhal_clock_allocate_peri(clock, adjusted_div);
178 #elif defined(COMPONENT_CAT2)
179             CY_UNUSED_PARAMETER(peri_group);
180             result = cyhal_clock_allocate(clock, PERI_DIVIDERS[i]);
181 #endif
182 
183             if(CY_RSLT_SUCCESS == result || !accept_larger)
184             {
185                 break;
186             }
187         }
188     }
189 
190 #if defined(COMPONENT_CAT1B)
191     // If no dividers exist, try to reserve the hfclk that drives the peri group
192     if(CY_RSLT_SUCCESS != result && false == dividers_exist)
193     {
194         uint8_t hfclk_idx = _cyhal_utils_get_hfclk_for_peri_group(peri_group);
195         result = cyhal_clock_reserve(clock, &CYHAL_CLOCK_HF[hfclk_idx]);
196     }
197 #endif
198     return result;
199 }
200 
201 #if defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
_cyhal_utils_get_hfclk_for_peri_group(uint8_t peri_group)202 uint8_t _cyhal_utils_get_hfclk_for_peri_group(uint8_t peri_group)
203 {
204 #if defined(COMPONENT_CAT1D)
205     switch (peri_group)
206     {
207         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 0):
208         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(1, 4):
209             return 0;
210         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 7):
211         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(1, 0):
212             return 1;
213         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 3):
214         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(1, 2):
215             return 5;
216         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 4):
217         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(1, 3):
218             return 6;
219         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(1, 1):
220             return 7;
221         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 2):
222             return 9;
223         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 1):
224         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 5):
225             return 10;
226         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 8):
227             return 11;
228         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 6):
229         case _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 9):
230             return 13;
231         default:
232             /* Unhandled peri clock */
233             CY_ASSERT(false);
234             break;
235     }
236 #else
237     switch (peri_group)
238     {
239         /* Peripheral groups are device specific. */
240 #if defined(CY_DEVICE_CYW20829)
241         case 0:
242         case 2:
243             return 0;
244         case 1:
245         case 3:
246         case 6:
247             return 1;
248         case 4:
249             return 2;
250         case 5:
251             return 3;
252 #elif defined(CY_DEVICE_TVIIBH8M) || defined(CY_DEVICE_TVIIBH4M)
253         case 0:
254             return 0;
255         case 1:
256             return 2;
257 #else
258 #warning "Unsupported device"
259 #endif /* defined(CY_DEVICE_CYW20829) */
260         default:
261             CY_ASSERT(false); /* Use APIs provided by the clock driver */
262             break;
263     }
264 #endif /* defined(COMPONENT_CAT1D) or other */
265     return 0;
266 }
267 #endif /* defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) */
268 
269 #if defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
_cyhal_utils_get_peri_group(const cyhal_resource_inst_t * clocked_item)270 uint8_t _cyhal_utils_get_peri_group(const cyhal_resource_inst_t *clocked_item)
271 {
272     switch (clocked_item->type)
273     {
274         /* Peripheral groups are device specific. */
275 #if defined(COMPONENT_CAT1D)
276         case CYHAL_RSC_CAN:
277         case CYHAL_RSC_SCB:
278             // SCB1 is clocked from group 8
279             if (clocked_item->block_num == 1)
280             {
281                 /* Peri instance num + Peri group num */
282                 return _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 8);
283             }
284             else
285             {
286                 /* Peri instance num + Peri group num */
287                 return _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 1);
288             }
289 
290         case CYHAL_RSC_TCPWM:
291         case CYHAL_RSC_I3C:
292             /* Peri instance num + Peri group num */
293             return _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 1);
294         case CYHAL_RSC_TDM:
295         case CYHAL_RSC_PDM:
296             /* Peri instance num + Peri group num */
297             return _CYHAL_UTILS_PACK_INSTANCE_GROUP(1, 1);
298         case CYHAL_RSC_ADC:
299             /* Peri instance num + Peri group num */
300             return _CYHAL_UTILS_PACK_INSTANCE_GROUP(0, 2);
301 #elif defined(CY_DEVICE_CYW20829)
302         case CYHAL_RSC_CAN:
303         case CYHAL_RSC_LIN:
304         case CYHAL_RSC_SCB:
305         case CYHAL_RSC_TCPWM:
306             return 1;
307         case CYHAL_RSC_CRYPTO:
308             return 2;
309         case CYHAL_RSC_I2S:
310         case CYHAL_RSC_TDM:
311         case CYHAL_RSC_PDM:
312             return 3;
313         case CYHAL_RSC_BLESS:
314             return 4;
315         case CYHAL_RSC_ADCMIC:
316             return 5;
317         case CYHAL_RSC_SMIF:
318             return 6;
319 #elif defined(CY_DEVICE_TVIIBH8M) || defined(CY_DEVICE_TVIIBH4M)
320         #if defined(CY_DEVICE_TVIIBH8M)
321         case CYHAL_RSC_TCPWM:
322             // 4 is the same as _CYHAL_TCPWM_MAX_GRPS_PER_IP_BLOCK
323             if (clocked_item->block_num < 4)
324             {
325                 return 0;
326             }
327             return 1;
328         #else
329         case CYHAL_RSC_TCPWM:
330         #endif
331         case CYHAL_RSC_ADC:
332         case CYHAL_RSC_SCB:
333         case CYHAL_RSC_CAN:
334         case CYHAL_RSC_LIN:
335             return 1;
336 #else
337 #warning "Unsupported device"
338 #endif
339         default:
340             CY_ASSERT(false); /* Use APIs provided by the clock driver */
341             break;
342     }
343     return 0;
344 }
345 #endif
346 
_cyhal_utils_get_clock_count(cyhal_clock_block_t block)347 uint32_t _cyhal_utils_get_clock_count(cyhal_clock_block_t block)
348 {
349     //NOTE: This could potentially reuse the cyhal_hwmgr.c cyhal_block_offsets_clock array
350     switch (block)
351     {
352         #if defined(COMPONENT_CAT1)
353         #if defined(COMPONENT_CAT1A)
354         case CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT:
355             return PERI_DIV_8_NR;
356         case CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT:
357             return PERI_DIV_16_NR;
358         case CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT:
359             return PERI_DIV_16_5_NR;
360         case CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT:
361             return PERI_DIV_24_5_NR;
362         case CYHAL_CLOCK_BLOCK_PLL:
363             return SRSS_NUM_PLL;
364         #elif defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C)
365         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 0)
366         _CYHAL_MXSPERI_PCLK_DIV_CNT(0);
367         #endif
368         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 1)
369         _CYHAL_MXSPERI_PCLK_DIV_CNT(1);
370         #endif
371         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 2)
372         _CYHAL_MXSPERI_PCLK_DIV_CNT(2);
373         #endif
374         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 3)
375         _CYHAL_MXSPERI_PCLK_DIV_CNT(3);
376         #endif
377         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 4)
378         _CYHAL_MXSPERI_PCLK_DIV_CNT(4);
379         #endif
380         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 5)
381         _CYHAL_MXSPERI_PCLK_DIV_CNT(5);
382         #endif
383         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 6)
384         _CYHAL_MXSPERI_PCLK_DIV_CNT(6);
385         #endif
386         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 7)
387         _CYHAL_MXSPERI_PCLK_DIV_CNT(7);
388         #endif
389         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 8)
390         _CYHAL_MXSPERI_PCLK_DIV_CNT(8);
391         #endif
392         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 9)
393         _CYHAL_MXSPERI_PCLK_DIV_CNT(9);
394         #endif
395         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 10)
396         _CYHAL_MXSPERI_PCLK_DIV_CNT(10);
397         #endif
398         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 11)
399         _CYHAL_MXSPERI_PCLK_DIV_CNT(11);
400         #endif
401         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 12)
402         _CYHAL_MXSPERI_PCLK_DIV_CNT(12);
403         #endif
404         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 13)
405         _CYHAL_MXSPERI_PCLK_DIV_CNT(13);
406         #endif
407         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 14)
408         _CYHAL_MXSPERI_PCLK_DIV_CNT(14);
409         #endif
410         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 15)
411         _CYHAL_MXSPERI_PCLK_DIV_CNT(15);
412         #endif
413         case CYHAL_CLOCK_BLOCK_PERI:
414             return PERI_PCLK_GROUP_NR;
415         case CYHAL_CLOCK_BLOCK_PLL200:
416             return SRSS_NUM_PLL200M;
417         case CYHAL_CLOCK_BLOCK_PLL400:
418             return SRSS_NUM_PLL400M;
419         #elif defined (COMPONENT_CAT1D)
420         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 0)
421         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 0);
422         #endif
423         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 1)
424         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 1);
425         #endif
426         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 2)
427         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 2);
428         #endif
429         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 3)
430         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 3);
431         #endif
432         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 4)
433         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 4);
434         #endif
435         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 5)
436         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 5);
437         #endif
438         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 6)
439         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 6);
440         #endif
441         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 7)
442         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 7);
443         #endif
444         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 8)
445         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 8);
446         #endif
447         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 9)
448         _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 9);
449         #endif
450         #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 10)
451         #warning "Unhandled number of PCLK for PERI0"
452         #endif
453         #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 0)
454         _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 0);
455         #endif
456         #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 1)
457         _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 1);
458         #endif
459         #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 2)
460         _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 2);
461         #endif
462         #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 3)
463         _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 3);
464         #endif
465         #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 4)
466         _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 4);
467         #endif
468         #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 5)
469         _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 5);
470         #endif
471         #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 6)
472         #warning "Unhandled number of PCLK for PERI1"
473         #endif
474         case CYHAL_CLOCK_BLOCK_PERI:
475             return (PERI0_PCLK_GROUP_NR + PERI1_PCLK_GROUP_NR);
476         case CYHAL_CLOCK_BLOCK_DPLL250:
477             return SRSS_NUM_DPLL_LP;
478         case CYHAL_CLOCK_BLOCK_DPLL500:
479             return SRSS_NUM_DPLL_HP;
480         #endif /* defined(COMPONENT_CAT1A) */
481 
482         case CYHAL_CLOCK_BLOCK_PATHMUX:
483             return SRSS_NUM_CLKPATH;
484         case CYHAL_CLOCK_BLOCK_HF:
485             return SRSS_NUM_HFROOT;
486         #elif defined(COMPONENT_CAT2) /* defined(COMPONENT_CAT1) */
487         case CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT:
488             return PERI_PCLK_DIV_8_NR;
489         case CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT:
490             return PERI_PCLK_DIV_16_NR;
491         case CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT:
492             return PERI_PCLK_DIV_16_5_NR;
493         case CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT:
494             return PERI_PCLK_DIV_24_5_NR;
495         #endif /* defined(COMPONENT_CAT2) */
496         default:
497             return 1;
498     }
499 }
500 
501 #if defined(COMPONENT_CAT1A)
_cyhal_utils_allocate_clock(cyhal_clock_t * clock,const cyhal_resource_inst_t * clocked_item,cyhal_clock_block_t div,bool accept_larger)502 cy_rslt_t _cyhal_utils_allocate_clock(cyhal_clock_t *clock, const cyhal_resource_inst_t *clocked_item, cyhal_clock_block_t div, bool accept_larger)
503 {
504     CY_ASSERT(NULL != clocked_item);
505 
506     cyhal_clock_t clock_rsc;
507     switch (clocked_item->type)
508     {
509         /* High frequency clock assignments are device specific. */
510 #if defined(CY_DEVICE_PSOC6ABLE2) || defined(CY_DEVICE_PSOC6A2M)
511         case CYHAL_RSC_I2S:
512         case CYHAL_RSC_PDM:
513             clock_rsc = CYHAL_CLOCK_HF[1];
514             break;
515 #endif
516 #if defined(CY_DEVICE_PSOC6ABLE2) || defined(CY_DEVICE_PSOC6A2M) || defined(CY_DEVICE_PSOC6A512K) || defined(CY_DEVICE_PSOC6A256K)
517         case CYHAL_RSC_SMIF:
518             clock_rsc = CYHAL_CLOCK_HF[2];
519             break;
520         case CYHAL_RSC_USB:
521             clock_rsc = CYHAL_CLOCK_HF[3];
522             break;
523 #endif
524 #if defined(CY_DEVICE_PSOC6A2M)
525         case CYHAL_RSC_SDHC:
526             clock_rsc = (clocked_item->block_num == 0)
527                 ? CYHAL_CLOCK_HF[4]
528                 : CYHAL_CLOCK_HF[2];
529             break;
530 #elif defined(CY_DEVICE_PSOC6A512K)
531         case CYHAL_RSC_SDHC:
532             clock_rsc = CYHAL_CLOCK_HF[4];
533             break;
534 #endif
535         case CYHAL_RSC_CLOCK:
536             CY_ASSERT(false); /* Use APIs provided by the clock driver */
537             return CYHAL_CLOCK_RSLT_ERR_NOT_SUPPORTED;
538         default:
539             return _cyhal_utils_allocate_peri(clock, 0, div, accept_larger);
540     }
541     return cyhal_clock_reserve(clock, &clock_rsc);
542 }
543 #elif defined(COMPONENT_CAT1C)
_cyhal_utils_allocate_clock(cyhal_clock_t * clock,const cyhal_resource_inst_t * clocked_item,cyhal_clock_block_t div,bool accept_larger)544 cy_rslt_t _cyhal_utils_allocate_clock(cyhal_clock_t *clock, const cyhal_resource_inst_t *clocked_item, cyhal_clock_block_t div, bool accept_larger)
545 {
546     CY_ASSERT(NULL != clocked_item);
547 
548     cyhal_clock_t clock_rsc;
549     uint8_t peri_group;
550     switch (clocked_item->type)
551     {
552         /* High frequency clock assignments are device specific. */
553 #if defined(CY_DEVICE_TVIIBH8M) || defined(CY_DEVICE_TVIIBH4M)
554         case CYHAL_RSC_I2S:
555             clock_rsc = CYHAL_CLOCK_HF[5];
556             break;
557         case CYHAL_RSC_SMIF:
558         case CYHAL_RSC_SDHC:
559             clock_rsc = CYHAL_CLOCK_HF[6];
560             break;
561 #endif
562         case CYHAL_RSC_CLOCK:
563             CY_ASSERT(false); /* Use APIs provided by the clock driver */
564             return CYHAL_CLOCK_RSLT_ERR_NOT_SUPPORTED;
565         default:
566             peri_group = _cyhal_utils_get_peri_group(clocked_item);
567             return _cyhal_utils_allocate_peri(clock, peri_group, div, accept_larger);
568     }
569     return cyhal_clock_reserve(clock, &clock_rsc);
570 }
571 
572 #elif defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1D)
_cyhal_utils_allocate_clock(cyhal_clock_t * clock,const cyhal_resource_inst_t * clocked_item,cyhal_clock_block_t div,bool accept_larger)573 cy_rslt_t _cyhal_utils_allocate_clock(cyhal_clock_t *clock, const cyhal_resource_inst_t *clocked_item, cyhal_clock_block_t div, bool accept_larger)
574 {
575     CY_ASSERT(NULL != clocked_item);
576     uint8_t peri_group = _cyhal_utils_get_peri_group(clocked_item);
577     return _cyhal_utils_allocate_peri(clock, peri_group, div, accept_larger);
578 }
579 #elif defined(COMPONENT_CAT2)
_cyhal_utils_allocate_clock(cyhal_clock_t * clock,const cyhal_resource_inst_t * clocked_item,cyhal_clock_block_t div,bool accept_larger)580 cy_rslt_t _cyhal_utils_allocate_clock(cyhal_clock_t *clock, const cyhal_resource_inst_t *clocked_item, cyhal_clock_block_t div, bool accept_larger)
581 {
582     CY_ASSERT(NULL != clocked_item);
583     CY_UNUSED_PARAMETER(clocked_item);
584     return _cyhal_utils_allocate_peri(clock, 0, div, accept_larger);
585 }
586 #endif
587 
_cyhal_utils_set_clock_frequency(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance)588 cy_rslt_t _cyhal_utils_set_clock_frequency(cyhal_clock_t* clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance)
589 {
590 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
591     if(clock->block == CYHAL_CLOCK_BLOCK_HF)
592     {
593         uint32_t divider;
594         cy_en_clkhf_in_sources_t source = Cy_SysClk_ClkHfGetSource(clock->channel);
595         uint32_t source_hz = Cy_SysClk_ClkPathGetFrequency((uint32_t)source);
596         if (CY_RSLT_SUCCESS == _cyhal_utils_find_hf_clk_div(source_hz, hz, tolerance, false, &divider))
597         {
598             return cyhal_clock_set_divider(clock, divider);
599         }
600         return CYHAL_CLOCK_RSLT_ERR_FREQ;
601     }
602     else
603     {
604 #endif
605         // Defer to the clock driver
606         return cyhal_clock_set_frequency(clock, hz, tolerance);
607 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
608     }
609 #endif
610 }
611 
612 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
_cyhal_utils_find_hf_clk_div(uint32_t hz_src,uint32_t desired_hz,const cyhal_clock_tolerance_t * tolerance,bool only_below_desired,uint32_t * div)613 cy_rslt_t _cyhal_utils_find_hf_clk_div(uint32_t hz_src, uint32_t desired_hz, const cyhal_clock_tolerance_t *tolerance,
614                         bool only_below_desired, uint32_t *div)
615 {
616     #if defined (CY_IP_MXS22SRSS)
617     const uint8_t HFCLK_DIVIDERS[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
618     #else
619     const uint8_t HFCLK_DIVIDERS[] = { 1, 2, 4, 8};
620     #endif
621     cy_rslt_t retval = CYHAL_CLOCK_RSLT_ERR_FREQ;
622     uint32_t tolerance_check_value = (NULL != tolerance) ? tolerance->value : 0xFFFFFFFFU;
623     cyhal_clock_tolerance_unit_t tolerance_type = (NULL != tolerance) ? tolerance->type : CYHAL_TOLERANCE_HZ;
624 
625     for(uint8_t i = 0; i < sizeof(HFCLK_DIVIDERS) / sizeof(HFCLK_DIVIDERS[0]); ++i)
626     {
627         const uint32_t divider = HFCLK_DIVIDERS[i];
628         uint32_t actual_freq = hz_src / divider;
629         if ((actual_freq > desired_hz) && only_below_desired)
630             continue;
631         uint32_t achieved_tolerance = abs(_cyhal_utils_calculate_tolerance(tolerance_type, desired_hz, actual_freq));
632         if (achieved_tolerance < tolerance_check_value)
633         {
634             *div = divider;
635             retval = CY_RSLT_SUCCESS;
636             if ((NULL != tolerance) || (achieved_tolerance == 0))
637                 break;
638             tolerance_check_value = achieved_tolerance;
639         }
640         else if (only_below_desired)
641         {
642             /* We are going from smallest divider, to highest. If we've not achieved better tolerance in
643             *   this iteration, we will no achieve it in futher for sure. */
644             break;
645         }
646     }
647     return retval;
648 }
649 
_cyhal_utils_find_hf_source_n_divider(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance,_cyhal_utils_clk_div_func_t div_find_func,cyhal_clock_t * hf_source,uint32_t * div)650 cy_rslt_t _cyhal_utils_find_hf_source_n_divider(cyhal_clock_t *clock, uint32_t hz,
651         const cyhal_clock_tolerance_t *tolerance, _cyhal_utils_clk_div_func_t div_find_func, cyhal_clock_t *hf_source,
652         uint32_t *div)
653 {
654     CY_ASSERT(NULL != clock);
655     CY_ASSERT(hz != 0);
656 
657     uint32_t count;
658     const cyhal_resource_inst_t ** sources;
659     cy_rslt_t retval = cyhal_clock_get_sources(clock, &sources, &count);
660     if (CY_RSLT_SUCCESS != retval)
661         return retval;
662 
663     uint32_t best_tolerance_hz = 0xFFFFFFFFU;
664     cyhal_clock_t best_clock;
665     uint32_t best_clock_freq = 0;
666     uint32_t best_divider = 1;
667     /* Go through all possible HFCLK clock sources and check what source fits best */
668     for (uint32_t i = 0; i < count; ++i)
669     {
670         cyhal_clock_t temp_clock;
671         if (CY_RSLT_SUCCESS == cyhal_clock_get(&temp_clock, sources[i]))
672         {
673             uint32_t cur_hf_source_freq = cyhal_clock_get_frequency(&temp_clock);
674             /* source frequency is much lower than desired, no reason to continue */
675             if ((0 == cur_hf_source_freq) ||
676                 ((NULL != tolerance) && (_cyhal_utils_calculate_tolerance(tolerance->type, hz, cur_hf_source_freq) > (int32_t)tolerance->value)))
677             {
678                 continue;
679             }
680             /* Covering situation when PATHMUX has enabled FLL / PLL on its way. In that case FLL / PLL frequency
681                 is observed on PATHMUX which is covered in other iterations of the sources loop */
682             if (CYHAL_CLOCK_BLOCK_PATHMUX == temp_clock.block)
683             {
684                 if (false
685                 #if !defined(COMPONENT_CAT1D)
686                     /* CAT1D devices does not have FLL */
687                     || ((sources[i]->channel_num == 0) && Cy_SysClk_FllIsEnabled())
688                 #endif /* !defined(COMPONENT_CAT1D) */
689                 #if (SRSS_NUM_PLL > 0)
690                     || ((sources[i]->channel_num > 0) && (sources[i]->channel_num <= SRSS_NUM_PLL) &&
691                         Cy_SysClk_PllIsEnabled(sources[i]->channel_num))
692                 #endif /* SRSS_NUM_PLL > 0 */
693                 #if !defined(COMPONENT_CAT1D)
694                 #if (SRSS_NUM_PLL400M > 0)
695                     || ((sources[i]->channel_num > SRSS_NUM_PLL) && (sources[i]->channel_num <= SRSS_NUM_PLL + SRSS_NUM_PLL400M) &&
696                         Cy_SysClk_PllIsEnabled(sources[i]->channel_num))
697                 #endif /* SRSS_NUM_PLL400M > 0 */
698                 #else /* !defined(COMPONENT_CAT1D) */
699                 #if (SRSS_NUM_DPLL500M > 0)
700                     || ((sources[i]->channel_num > SRSS_NUM_PLL) && (sources[i]->channel_num <= SRSS_NUM_PLL + SRSS_NUM_DPLL500M) &&
701                         Cy_SysClk_PllIsEnabled(sources[i]->channel_num))
702                 #endif /* SRSS_NUM_DPLL500M > 0 */
703                 #endif /* !defined(COMPONENT_CAT1D) or other */
704                 )
705                 {
706                     continue;
707                 }
708             }
709 
710             uint32_t cur_clock_divider;
711             if (CY_RSLT_SUCCESS == div_find_func(cur_hf_source_freq, hz, NULL, true, &cur_clock_divider))
712             {
713                 uint32_t cur_divided_freq = cur_hf_source_freq / cur_clock_divider;
714                 uint32_t cur_clock_tolerance = abs(_cyhal_utils_calculate_tolerance(CYHAL_TOLERANCE_HZ, hz, cur_divided_freq));
715                 if (cur_clock_tolerance < best_tolerance_hz)
716                 {
717                     best_clock = temp_clock;
718                     best_tolerance_hz = cur_clock_tolerance;
719                     best_clock_freq = cur_divided_freq;
720                     best_divider = cur_clock_divider;
721                     if (cur_divided_freq == hz)
722                         break;
723                 }
724             }
725         }
726     }
727 
728     if (0 == best_clock_freq)
729     {
730         retval = CYHAL_CLOCK_RSLT_ERR_SOURCE;
731     }
732     else if (NULL != tolerance) /* Verify within tolerance if one was provided. */
733     {
734         uint32_t achieved_tolerance = abs(_cyhal_utils_calculate_tolerance(tolerance->type, hz, best_clock_freq));
735         if (achieved_tolerance > tolerance->value)
736             retval = CYHAL_CLOCK_RSLT_ERR_FREQ;
737     }
738 
739     if (CY_RSLT_SUCCESS == retval)
740     {
741         *hf_source = best_clock;
742         *div = best_divider;
743     }
744 
745     return retval;
746 }
747 
_cyhal_utils_set_clock_frequency2(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance)748 cy_rslt_t _cyhal_utils_set_clock_frequency2(cyhal_clock_t *clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance)
749 {
750     CY_ASSERT(NULL != clock);
751     CY_ASSERT(hz != 0);
752 
753     cyhal_clock_t hf_source;
754     uint32_t divider = 0;
755     cy_rslt_t retval = _cyhal_utils_find_hf_source_n_divider(clock, hz, tolerance, _cyhal_utils_find_hf_clk_div,
756                             &hf_source, &divider);
757     if (CY_RSLT_SUCCESS == retval)
758     {
759         retval = cyhal_clock_set_source(clock, &hf_source);
760     }
761     if (CY_RSLT_SUCCESS == retval)
762     {
763         retval = cyhal_clock_set_divider(clock, divider);
764     }
765 
766     return retval;
767 }
768 #endif
769 
770 #if defined(__cplusplus)
771 }
772 #endif
773