1 /***************************************************************************//**
2 * \file cyhal_hwmgr.c
3 *
4 * \brief
5 * Provides a high level interface for managing hardware resources. This is
6 * used to track what hardware blocks are already being used so they are not over
7 * allocated.
8 *
9 ********************************************************************************
10 * \copyright
11 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
12 * an affiliate of Cypress Semiconductor Corporation
13 *
14 * SPDX-License-Identifier: Apache-2.0
15 *
16 * Licensed under the Apache License, Version 2.0 (the "License");
17 * you may not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 *******************************************************************************/
28
29 #include "cy_utils.h"
30 #include "cyhal_hwmgr.h"
31 #include "cyhal_system.h"
32
33 #if defined(__cplusplus)
34 extern "C"
35 {
36 #endif
37
38 #define CY_BYTE_NUM_SHIFT (3)
39 #define CY_BIT_NUM_MASK (0x07)
40
41 // Get device specific resources and offsets
42 // This must declare:
43 // _CYHAL_RESOURCES
44 // typedef _cyhal_hwmgr_offset_t
45 // static uint8_t cyhal_used[<appropriate size>] = {0};
46 // static inline uint16_t _cyhal_uses_channels(cyhal_resource_t type);
47 // static inline uint16_t _cyhal_get_resource_offset(cyhal_resource_t type);
48 // static inline const _cyhal_hwmgr_offset_t* _cyhal_get_block_offsets(cyhal_resource_t type);
49 // static inline uint8_t _cyhal_get_block_offset_length(cyhal_resource_t type);
50 #include "cyhal_hwmgr_impl_part.h"
51
52 /*
53 * This function is designed to verify that the number of valid resources in the cyhal_resource_t
54 * enum and the number entries in the _CYHAL_RESOURCES array are identical. Any mismatch
55 * between the two will lead to runtime failures. This will produce a divide by 0 error if they
56 * get of of sync.
57 * NOTE: This function should never be called, it is only for a compile time error check
58 * NOTE: The suppress is to temporarily disable the IAR warning about an uncalled function
59 */
60 static inline void _check_array_size(void) __attribute__ ((deprecated));
61 #if __ICCARM__
62 #pragma diag_suppress=Pe177
63 #elif __clang__
64 #pragma clang diagnostic push
65 #pragma clang diagnostic ignored "-Wunused-function"
66 #endif
_check_array_size(void)67 static inline void _check_array_size(void)
68 {
69 uint32_t dummy = 1 / (_CYHAL_RESOURCES == CYHAL_RSC_INVALID);
70 (void)dummy;
71 }
72 #if __ICCARM__
73 #pragma diag_default=Pe177
74 #elif __clang__
75 #pragma clang diagnostic pop
76 #endif
77
78 /*******************************************************************************
79 * Utility helper functions
80 *******************************************************************************/
81
_cyhal_get_bit_position(cyhal_resource_t type,uint8_t block,uint8_t channel,uint16_t * bitPosition)82 static cy_rslt_t _cyhal_get_bit_position(cyhal_resource_t type, uint8_t block, uint8_t channel, uint16_t* bitPosition)
83 {
84 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
85 /* For backwards compatability. */
86 if (type == CYHAL_RSC_CLKPATH)
87 {
88 channel = block;
89 block = CYHAL_CLOCK_BLOCK_PATHMUX;
90 type = CYHAL_RSC_CLOCK;
91 }
92 #endif
93 uint16_t offsetRsc = _cyhal_get_resource_offset(type);
94 // Offset that is one past the beginning of the next resource (or one past the end of the array).
95 // Our offset must be strictly less than that
96 uint16_t offsetEndOfRsc = ((1u + type) < _CYHAL_RESOURCES)
97 ? _cyhal_get_resource_offset((cyhal_resource_t)(type + 1))
98 : CY_TOTAL_ALLOCATABLE_ITEMS;
99
100 if (_cyhal_uses_channels(type))
101 {
102 const _cyhal_hwmgr_offset_t* blockOffsets = _cyhal_get_block_offsets(type);
103 *bitPosition = offsetEndOfRsc;
104 if (blockOffsets != NULL)
105 {
106 // Offset (from the beginning of the section for this block type) that is one past the end of
107 // the requested block index. The channel number must be strictly less than that.
108 uint16_t blocks = _cyhal_get_block_offset_length(type);
109 if (block < blocks)
110 {
111 *bitPosition = offsetRsc + blockOffsets[block] + channel;
112 if ((block + 1) < blocks)
113 {
114 offsetEndOfRsc = offsetRsc + blockOffsets[block + 1];
115 }
116 }
117 }
118 }
119 else
120 {
121 *bitPosition = offsetRsc + block;
122 }
123
124 return (*bitPosition < offsetEndOfRsc)
125 ? CY_RSLT_SUCCESS
126 : CYHAL_HWMGR_RSLT_ERR_INVALID;
127 }
128
_cyhal_is_set(const uint8_t * used,cyhal_resource_t type,uint8_t block,uint8_t channel,bool * isSet)129 static inline cy_rslt_t _cyhal_is_set(const uint8_t* used, cyhal_resource_t type, uint8_t block, uint8_t channel, bool* isSet)
130 {
131 uint16_t bitPosition;
132 cy_rslt_t status = _cyhal_get_bit_position(type, block, channel, &bitPosition);
133 if (status == CY_RSLT_SUCCESS)
134 {
135 uint8_t byte = (uint8_t)(bitPosition >> CY_BYTE_NUM_SHIFT);
136 uint8_t bit = bitPosition & CY_BIT_NUM_MASK;
137 *isSet = (used[byte] & (1 << bit));
138 }
139 return status;
140 }
141
_cyhal_set_bit(uint8_t * used,cyhal_resource_t type,uint8_t block,uint8_t channel)142 static inline cy_rslt_t _cyhal_set_bit(uint8_t* used, cyhal_resource_t type, uint8_t block, uint8_t channel)
143 {
144 uint16_t bitPosition;
145 cy_rslt_t status = _cyhal_get_bit_position(type, block, channel, &bitPosition);
146 if (status == CY_RSLT_SUCCESS)
147 {
148 uint8_t byte = (uint8_t)(bitPosition >> CY_BYTE_NUM_SHIFT);
149 uint8_t bit = bitPosition & CY_BIT_NUM_MASK;
150 used[byte] |= (1 << bit);
151 }
152 return status;
153 }
154
_cyhal_clear_bit(uint8_t * used,cyhal_resource_t type,uint8_t block,uint8_t channel)155 static inline cy_rslt_t _cyhal_clear_bit(uint8_t* used, cyhal_resource_t type, uint8_t block, uint8_t channel)
156 {
157 uint16_t bitPosition;
158 cy_rslt_t status = _cyhal_get_bit_position(type, block, channel, &bitPosition);
159 if (status == CY_RSLT_SUCCESS)
160 {
161 uint8_t byte = (uint8_t)(bitPosition >> CY_BYTE_NUM_SHIFT);
162 uint8_t bit = bitPosition & CY_BIT_NUM_MASK;
163 used[byte] &= ~(1 << bit);
164 }
165 return status;
166 }
167
168 /*******************************************************************************
169 * Hardware Manager API
170 *******************************************************************************/
171
cyhal_hwmgr_init(void)172 cy_rslt_t cyhal_hwmgr_init(void)
173 {
174 return CY_RSLT_SUCCESS;
175 }
176
cyhal_hwmgr_reserve(const cyhal_resource_inst_t * obj)177 cy_rslt_t cyhal_hwmgr_reserve(const cyhal_resource_inst_t* obj)
178 {
179 bool isSet;
180 uint32_t state = cyhal_system_critical_section_enter();
181 cy_rslt_t rslt = _cyhal_is_set(cyhal_used, obj->type, obj->block_num, obj->channel_num, &isSet);
182 if (rslt == CY_RSLT_SUCCESS && isSet)
183 {
184 rslt = CYHAL_HWMGR_RSLT_ERR_INUSE;
185 }
186
187 if (rslt == CY_RSLT_SUCCESS)
188 {
189 rslt = _cyhal_set_bit(cyhal_used, obj->type, obj->block_num, obj->channel_num);
190 }
191 cyhal_system_critical_section_exit(state);
192
193 return rslt;
194 }
195
cyhal_hwmgr_free(const cyhal_resource_inst_t * obj)196 void cyhal_hwmgr_free(const cyhal_resource_inst_t* obj)
197 {
198 uint32_t state = cyhal_system_critical_section_enter();
199 cy_rslt_t rslt = _cyhal_clear_bit(cyhal_used, obj->type, obj->block_num, obj->channel_num);
200 CY_UNUSED_PARAMETER(rslt); /* CY_ASSERT only processes in DEBUG, ignores for others */
201 CY_ASSERT(CY_RSLT_SUCCESS == rslt);
202 cyhal_system_critical_section_exit(state);
203 }
204
205 #if (CYHAL_DRIVER_AVAILABLE_INTERCONNECT)
cyhal_hwmgr_allocate(cyhal_resource_t type,cyhal_resource_inst_t * obj)206 cy_rslt_t cyhal_hwmgr_allocate(cyhal_resource_t type, cyhal_resource_inst_t* obj)
207 {
208 return _cyhal_hwmgr_allocate_with_connection(type, NULL, NULL, NULL, NULL, obj);
209 }
210
_cyhal_hwmgr_allocate_with_connection(cyhal_resource_t type,const cyhal_source_t * src,const cyhal_dest_t * dest,_cyhal_hwmgr_get_output_source_t get_src,_cyhal_hwmgr_get_input_dest_t get_dest,cyhal_resource_inst_t * obj)211 cy_rslt_t _cyhal_hwmgr_allocate_with_connection(cyhal_resource_t type, const cyhal_source_t *src, const cyhal_dest_t *dest,
212 _cyhal_hwmgr_get_output_source_t get_src, _cyhal_hwmgr_get_input_dest_t get_dest, cyhal_resource_inst_t *obj)
213 #else
214 cy_rslt_t cyhal_hwmgr_allocate(cyhal_resource_t type, cyhal_resource_inst_t* obj)
215 #endif
216 {
217 uint16_t offsetStartOfRsc = _cyhal_get_resource_offset(type);
218 uint16_t offsetEndOfRsc = ((1u + type) < _CYHAL_RESOURCES)
219 ? _cyhal_get_resource_offset((cyhal_resource_t)(type + 1))
220 : CY_TOTAL_ALLOCATABLE_ITEMS;
221 bool usesChannels = _cyhal_uses_channels(type);
222
223 uint16_t count = offsetEndOfRsc - offsetStartOfRsc;
224 uint8_t block = 0;
225 uint8_t channel = 0;
226 for (uint16_t i = 0; i < count; i++)
227 {
228 #if (CYHAL_DRIVER_AVAILABLE_INTERCONNECT)
229 bool valid = true;
230 if (NULL != src)
231 {
232 cyhal_dest_t destination = get_dest(block, channel);
233 valid = _cyhal_can_connect_signal(*src, destination);
234 }
235 if (valid && NULL != dest)
236 {
237 cyhal_source_t source = get_src(block, channel);
238 valid = _cyhal_can_connect_signal(source, *dest);
239 }
240 if (valid)
241 #endif
242 {
243 cyhal_resource_inst_t rsc = { type, block, channel };
244 if (CY_RSLT_SUCCESS == cyhal_hwmgr_reserve(&rsc))
245 {
246 obj->type = type;
247 obj->block_num = block;
248 obj->channel_num = channel;
249 return CY_RSLT_SUCCESS;
250 }
251 }
252
253 if (usesChannels)
254 {
255 const _cyhal_hwmgr_offset_t* blockOffsets = _cyhal_get_block_offsets(type);
256 uint16_t blocks = _cyhal_get_block_offset_length(type);
257 if ((block + 1) < blocks && blockOffsets[block + 1] <= (i + 1))
258 {
259 channel = 0;
260 do
261 {
262 block++;
263 }
264 while (((block + 1) < blocks) && (blockOffsets[block + 1] == blockOffsets[block])); /* Skip empty blocks */
265 }
266 else
267 {
268 channel++;
269 }
270 }
271 else
272 {
273 block++;
274 }
275 }
276
277 return CYHAL_HWMGR_RSLT_ERR_NONE_FREE;
278 }
279
280 #if defined(__cplusplus)
281 }
282 #endif
283