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, ÷r))
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, ÷r);
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