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 #if defined(SRSS_HT_VARIANT) && (SRSS_HT_VARIANT > 0)
363 case CYHAL_CLOCK_BLOCK_PLL200:
364 return SRSS_NUM_PLL200M;
365 case CYHAL_CLOCK_BLOCK_PLL400:
366 return SRSS_NUM_PLL400M;
367 #else
368 case CYHAL_CLOCK_BLOCK_PLL:
369 return SRSS_NUM_PLL;
370 #endif
371 #elif defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C)
372 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 0)
373 _CYHAL_MXSPERI_PCLK_DIV_CNT(0);
374 #endif
375 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 1)
376 _CYHAL_MXSPERI_PCLK_DIV_CNT(1);
377 #endif
378 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 2)
379 _CYHAL_MXSPERI_PCLK_DIV_CNT(2);
380 #endif
381 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 3)
382 _CYHAL_MXSPERI_PCLK_DIV_CNT(3);
383 #endif
384 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 4)
385 _CYHAL_MXSPERI_PCLK_DIV_CNT(4);
386 #endif
387 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 5)
388 _CYHAL_MXSPERI_PCLK_DIV_CNT(5);
389 #endif
390 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 6)
391 _CYHAL_MXSPERI_PCLK_DIV_CNT(6);
392 #endif
393 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 7)
394 _CYHAL_MXSPERI_PCLK_DIV_CNT(7);
395 #endif
396 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 8)
397 _CYHAL_MXSPERI_PCLK_DIV_CNT(8);
398 #endif
399 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 9)
400 _CYHAL_MXSPERI_PCLK_DIV_CNT(9);
401 #endif
402 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 10)
403 _CYHAL_MXSPERI_PCLK_DIV_CNT(10);
404 #endif
405 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 11)
406 _CYHAL_MXSPERI_PCLK_DIV_CNT(11);
407 #endif
408 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 12)
409 _CYHAL_MXSPERI_PCLK_DIV_CNT(12);
410 #endif
411 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 13)
412 _CYHAL_MXSPERI_PCLK_DIV_CNT(13);
413 #endif
414 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 14)
415 _CYHAL_MXSPERI_PCLK_DIV_CNT(14);
416 #endif
417 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 15)
418 _CYHAL_MXSPERI_PCLK_DIV_CNT(15);
419 #endif
420 case CYHAL_CLOCK_BLOCK_PERI:
421 return PERI_PCLK_GROUP_NR;
422 case CYHAL_CLOCK_BLOCK_PLL200:
423 return SRSS_NUM_PLL200M;
424 case CYHAL_CLOCK_BLOCK_PLL400:
425 return SRSS_NUM_PLL400M;
426 #elif defined (COMPONENT_CAT1D)
427 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 0)
428 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 0);
429 #endif
430 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 1)
431 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 1);
432 #endif
433 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 2)
434 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 2);
435 #endif
436 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 3)
437 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 3);
438 #endif
439 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 4)
440 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 4);
441 #endif
442 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 5)
443 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 5);
444 #endif
445 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 6)
446 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 6);
447 #endif
448 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 7)
449 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 7);
450 #endif
451 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 8)
452 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 8);
453 #endif
454 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 9)
455 _CYHAL_MXSPERI_PCLK_DIV_CNT(0, 9);
456 #endif
457 #if (PERI0_PERI_PCLK_PCLK_GROUP_NR > 10)
458 #warning "Unhandled number of PCLK for PERI0"
459 #endif
460 #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 0)
461 _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 0);
462 #endif
463 #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 1)
464 _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 1);
465 #endif
466 #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 2)
467 _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 2);
468 #endif
469 #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 3)
470 _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 3);
471 #endif
472 #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 4)
473 _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 4);
474 #endif
475 #if (PERI1_PERI_PCLK_PCLK_GROUP_NR > 5)
476 _CYHAL_MXSPERI_PCLK_DIV_CNT(1, 5);
477 #endif
478 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 6)
479 #warning "Unhandled number of PCLK for PERI1"
480 #endif
481 case CYHAL_CLOCK_BLOCK_PERI:
482 return (PERI0_PCLK_GROUP_NR + PERI1_PCLK_GROUP_NR);
483 case CYHAL_CLOCK_BLOCK_DPLL250:
484 return SRSS_NUM_DPLL_LP;
485 case CYHAL_CLOCK_BLOCK_DPLL500:
486 return SRSS_NUM_DPLL_HP;
487 #endif /* defined(COMPONENT_CAT1A) */
488
489 case CYHAL_CLOCK_BLOCK_PATHMUX:
490 return SRSS_NUM_CLKPATH;
491 case CYHAL_CLOCK_BLOCK_HF:
492 return SRSS_NUM_HFROOT;
493 #elif defined(COMPONENT_CAT2) /* defined(COMPONENT_CAT1) */
494 case CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT:
495 return PERI_PCLK_DIV_8_NR;
496 case CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT:
497 return PERI_PCLK_DIV_16_NR;
498 case CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT:
499 return PERI_PCLK_DIV_16_5_NR;
500 case CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT:
501 return PERI_PCLK_DIV_24_5_NR;
502 #endif /* defined(COMPONENT_CAT2) */
503 default:
504 return 1;
505 }
506 }
507
508 #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)509 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)
510 {
511 CY_ASSERT(NULL != clocked_item);
512
513 cyhal_clock_t clock_rsc;
514 switch (clocked_item->type)
515 {
516 /* High frequency clock assignments are device specific. */
517 #if defined(CY_DEVICE_PSOC6ABLE2) || defined(CY_DEVICE_PSOC6A2M)
518 case CYHAL_RSC_I2S:
519 case CYHAL_RSC_PDM:
520 clock_rsc = CYHAL_CLOCK_HF[1];
521 break;
522 #endif
523 #if defined(CY_DEVICE_PSOC6ABLE2) || defined(CY_DEVICE_PSOC6A2M) || defined(CY_DEVICE_PSOC6A512K) || defined(CY_DEVICE_PSOC6A256K)
524 case CYHAL_RSC_SMIF:
525 clock_rsc = CYHAL_CLOCK_HF[2];
526 break;
527 case CYHAL_RSC_USB:
528 clock_rsc = CYHAL_CLOCK_HF[3];
529 break;
530 #endif
531 #if defined(CY_DEVICE_PSOC6A2M)
532 case CYHAL_RSC_SDHC:
533 clock_rsc = (clocked_item->block_num == 0)
534 ? CYHAL_CLOCK_HF[4]
535 : CYHAL_CLOCK_HF[2];
536 break;
537 #elif defined(CY_DEVICE_PSOC6A512K)
538 case CYHAL_RSC_SDHC:
539 clock_rsc = CYHAL_CLOCK_HF[4];
540 break;
541 #endif
542 case CYHAL_RSC_CLOCK:
543 CY_UNUSED_PARAMETER(clock_rsc);
544 CY_ASSERT(false); /* Use APIs provided by the clock driver */
545 return CYHAL_CLOCK_RSLT_ERR_NOT_SUPPORTED;
546 default:
547 CY_UNUSED_PARAMETER(clock_rsc);
548 return _cyhal_utils_allocate_peri(clock, 0, div, accept_larger);
549 }
550 #if defined(CY_DEVICE_PSOC6ABLE2) || defined(CY_DEVICE_PSOC6A2M) || defined(CY_DEVICE_PSOC6A512K) || defined(CY_DEVICE_PSOC6A256K)
551 /* These devices don't return their value in the above switch statement - return the value here. */
552 return cyhal_clock_reserve(clock, &clock_rsc);
553 #endif
554 }
555 #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)556 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)
557 {
558 CY_ASSERT(NULL != clocked_item);
559
560 cyhal_clock_t clock_rsc;
561 uint8_t peri_group;
562 switch (clocked_item->type)
563 {
564 /* High frequency clock assignments are device specific. */
565 #if defined(CY_DEVICE_TVIIBH8M) || defined(CY_DEVICE_TVIIBH4M)
566 case CYHAL_RSC_I2S:
567 clock_rsc = CYHAL_CLOCK_HF[5];
568 break;
569 case CYHAL_RSC_SMIF:
570 case CYHAL_RSC_SDHC:
571 clock_rsc = CYHAL_CLOCK_HF[6];
572 break;
573 #endif
574 case CYHAL_RSC_CLOCK:
575 CY_ASSERT(false); /* Use APIs provided by the clock driver */
576 return CYHAL_CLOCK_RSLT_ERR_NOT_SUPPORTED;
577 default:
578 peri_group = _cyhal_utils_get_peri_group(clocked_item);
579 return _cyhal_utils_allocate_peri(clock, peri_group, div, accept_larger);
580 }
581 return cyhal_clock_reserve(clock, &clock_rsc);
582 }
583
584 #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)585 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)
586 {
587 CY_ASSERT(NULL != clocked_item);
588 uint8_t peri_group = _cyhal_utils_get_peri_group(clocked_item);
589 return _cyhal_utils_allocate_peri(clock, peri_group, div, accept_larger);
590 }
591 #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)592 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)
593 {
594 CY_ASSERT(NULL != clocked_item);
595 CY_UNUSED_PARAMETER(clocked_item);
596 return _cyhal_utils_allocate_peri(clock, 0, div, accept_larger);
597 }
598 #endif
599
_cyhal_utils_set_clock_frequency(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance)600 cy_rslt_t _cyhal_utils_set_clock_frequency(cyhal_clock_t* clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance)
601 {
602 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
603 if(clock->block == CYHAL_CLOCK_BLOCK_HF)
604 {
605 uint32_t divider;
606 cy_en_clkhf_in_sources_t source = Cy_SysClk_ClkHfGetSource(clock->channel);
607 uint32_t source_hz = Cy_SysClk_ClkPathGetFrequency((uint32_t)source);
608 if (CY_RSLT_SUCCESS == _cyhal_utils_find_hf_clk_div(source_hz, hz, tolerance, false, ÷r))
609 {
610 return cyhal_clock_set_divider(clock, divider);
611 }
612 return CYHAL_CLOCK_RSLT_ERR_FREQ;
613 }
614 else
615 {
616 #endif
617 // Defer to the clock driver
618 return cyhal_clock_set_frequency(clock, hz, tolerance);
619 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
620 }
621 #endif
622 }
623
624 #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)625 cy_rslt_t _cyhal_utils_find_hf_clk_div(uint32_t hz_src, uint32_t desired_hz, const cyhal_clock_tolerance_t *tolerance,
626 bool only_below_desired, uint32_t *div)
627 {
628 #if defined (CY_IP_MXS22SRSS)
629 const uint8_t HFCLK_DIVIDERS[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
630 #else
631 const uint8_t HFCLK_DIVIDERS[] = { 1, 2, 4, 8};
632 #endif
633 cy_rslt_t retval = CYHAL_CLOCK_RSLT_ERR_FREQ;
634 uint32_t tolerance_check_value = (NULL != tolerance) ? tolerance->value : 0xFFFFFFFFU;
635 cyhal_clock_tolerance_unit_t tolerance_type = (NULL != tolerance) ? tolerance->type : CYHAL_TOLERANCE_HZ;
636
637 for(uint8_t i = 0; i < sizeof(HFCLK_DIVIDERS) / sizeof(HFCLK_DIVIDERS[0]); ++i)
638 {
639 const uint32_t divider = HFCLK_DIVIDERS[i];
640 uint32_t actual_freq = hz_src / divider;
641 if ((actual_freq > desired_hz) && only_below_desired)
642 continue;
643 uint32_t achieved_tolerance = abs(_cyhal_utils_calculate_tolerance(tolerance_type, desired_hz, actual_freq));
644 if (achieved_tolerance < tolerance_check_value)
645 {
646 *div = divider;
647 retval = CY_RSLT_SUCCESS;
648 if ((NULL != tolerance) || (achieved_tolerance == 0))
649 break;
650 tolerance_check_value = achieved_tolerance;
651 }
652 else if (only_below_desired)
653 {
654 /* We are going from smallest divider, to highest. If we've not achieved better tolerance in
655 * this iteration, we will no achieve it in futher for sure. */
656 break;
657 }
658 }
659 return retval;
660 }
661
_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)662 cy_rslt_t _cyhal_utils_find_hf_source_n_divider(cyhal_clock_t *clock, uint32_t hz,
663 const cyhal_clock_tolerance_t *tolerance, _cyhal_utils_clk_div_func_t div_find_func, cyhal_clock_t *hf_source,
664 uint32_t *div)
665 {
666 CY_ASSERT(NULL != clock);
667 CY_ASSERT(hz != 0);
668
669 uint32_t count;
670 const cyhal_resource_inst_t ** sources;
671 cy_rslt_t retval = cyhal_clock_get_sources(clock, &sources, &count);
672 if (CY_RSLT_SUCCESS != retval)
673 return retval;
674
675 uint32_t best_tolerance_hz = 0xFFFFFFFFU;
676 cyhal_clock_t best_clock;
677 uint32_t best_clock_freq = 0;
678 uint32_t best_divider = 1;
679 /* Go through all possible HFCLK clock sources and check what source fits best */
680 for (uint32_t i = 0; i < count; ++i)
681 {
682 cyhal_clock_t temp_clock;
683 if (CY_RSLT_SUCCESS == cyhal_clock_get(&temp_clock, sources[i]))
684 {
685 uint32_t cur_hf_source_freq = cyhal_clock_get_frequency(&temp_clock);
686 /* source frequency is much lower than desired, no reason to continue */
687 if ((0 == cur_hf_source_freq) ||
688 ((NULL != tolerance) && (_cyhal_utils_calculate_tolerance(tolerance->type, hz, cur_hf_source_freq) > (int32_t)tolerance->value)))
689 {
690 continue;
691 }
692 /* Covering situation when PATHMUX has enabled FLL / PLL on its way. In that case FLL / PLL frequency
693 is observed on PATHMUX which is covered in other iterations of the sources loop */
694 if (CYHAL_CLOCK_BLOCK_PATHMUX == temp_clock.block)
695 {
696 if (false
697 #if !defined(COMPONENT_CAT1D)
698 /* CAT1D devices does not have FLL */
699 || ((sources[i]->channel_num == 0) && Cy_SysClk_FllIsEnabled())
700 #endif /* !defined(COMPONENT_CAT1D) */
701 #if (SRSS_NUM_PLL > 0)
702 || ((sources[i]->channel_num > 0) && (sources[i]->channel_num <= SRSS_NUM_PLL) &&
703 Cy_SysClk_PllIsEnabled(sources[i]->channel_num))
704 #endif /* SRSS_NUM_PLL > 0 */
705 #if !defined(COMPONENT_CAT1D)
706 #if (SRSS_NUM_PLL400M > 0)
707 || ((sources[i]->channel_num > SRSS_NUM_PLL) && (sources[i]->channel_num <= SRSS_NUM_PLL + SRSS_NUM_PLL400M) &&
708 Cy_SysClk_PllIsEnabled(sources[i]->channel_num))
709 #endif /* SRSS_NUM_PLL400M > 0 */
710 #else /* !defined(COMPONENT_CAT1D) */
711 #if (SRSS_NUM_DPLL500M > 0)
712 || ((sources[i]->channel_num > SRSS_NUM_PLL) && (sources[i]->channel_num <= SRSS_NUM_PLL + SRSS_NUM_DPLL500M) &&
713 Cy_SysClk_PllIsEnabled(sources[i]->channel_num))
714 #endif /* SRSS_NUM_DPLL500M > 0 */
715 #endif /* !defined(COMPONENT_CAT1D) or other */
716 )
717 {
718 continue;
719 }
720 }
721
722 uint32_t cur_clock_divider;
723 if (CY_RSLT_SUCCESS == div_find_func(cur_hf_source_freq, hz, NULL, true, &cur_clock_divider))
724 {
725 uint32_t cur_divided_freq = cur_hf_source_freq / cur_clock_divider;
726 uint32_t cur_clock_tolerance = abs(_cyhal_utils_calculate_tolerance(CYHAL_TOLERANCE_HZ, hz, cur_divided_freq));
727 if (cur_clock_tolerance < best_tolerance_hz)
728 {
729 best_clock = temp_clock;
730 best_tolerance_hz = cur_clock_tolerance;
731 best_clock_freq = cur_divided_freq;
732 best_divider = cur_clock_divider;
733 if (cur_divided_freq == hz)
734 break;
735 }
736 }
737 }
738 }
739
740 if (0 == best_clock_freq)
741 {
742 retval = CYHAL_CLOCK_RSLT_ERR_SOURCE;
743 }
744 else if (NULL != tolerance) /* Verify within tolerance if one was provided. */
745 {
746 uint32_t achieved_tolerance = abs(_cyhal_utils_calculate_tolerance(tolerance->type, hz, best_clock_freq));
747 if (achieved_tolerance > tolerance->value)
748 retval = CYHAL_CLOCK_RSLT_ERR_FREQ;
749 }
750
751 if (CY_RSLT_SUCCESS == retval)
752 {
753 *hf_source = best_clock;
754 *div = best_divider;
755 }
756
757 return retval;
758 }
759
_cyhal_utils_set_clock_frequency2(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance)760 cy_rslt_t _cyhal_utils_set_clock_frequency2(cyhal_clock_t *clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance)
761 {
762 CY_ASSERT(NULL != clock);
763 CY_ASSERT(hz != 0);
764
765 cyhal_clock_t hf_source;
766 uint32_t divider = 0;
767 cy_rslt_t retval = _cyhal_utils_find_hf_source_n_divider(clock, hz, tolerance, _cyhal_utils_find_hf_clk_div,
768 &hf_source, ÷r);
769 if (CY_RSLT_SUCCESS == retval)
770 {
771 retval = cyhal_clock_set_source(clock, &hf_source);
772 }
773 if (CY_RSLT_SUCCESS == retval)
774 {
775 retval = cyhal_clock_set_divider(clock, divider);
776 }
777
778 return retval;
779 }
780 #endif
781
782 #if defined(__cplusplus)
783 }
784 #endif
785