1 /*******************************************************************************
2 * File Name: cyhal_sdhc.c
3 *
4 * Description:
5 * Provides a high level interface for interacting with the Infineon SDHC. This
6 * is a wrapper around the lower level PDL API.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
11 * an affiliate of Cypress Semiconductor Corporation
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *******************************************************************************/
27
28 #include <string.h> /* For memcpy */
29 #include <stdlib.h>
30 #include <time.h>
31 #include "cy_pdl.h"
32 #include "cy_utils.h"
33 #include "cy_result.h"
34 #include "cyhal_sdhc.h"
35 #include "cyhal_sdio.h"
36 #include "cyhal_gpio.h"
37 #include "cyhal_clock.h"
38 #include "cyhal_hwmgr.h"
39 #include "cyhal_utils.h"
40 #include "cyhal_irq_impl.h"
41 #include "cyhal_system.h"
42 #if CYHAL_DRIVER_AVAILABLE_SYSPM
43 #include "cyhal_syspm.h"
44 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
45
46 /**
47 * \addtogroup group_hal_impl_sdhc SDHC (SD Host Controller)
48 * \ingroup group_hal_impl
49 * \{
50 *
51 * The SHDC HAL implemenation for CAT1 provides implementations for the following weak functions
52 * specified by the PDL to make their usage in SDHC HAL driver more flexible by providing user ability
53 * to use card detect, write protect, pwr en, and io select signals on custom pins instead of dedicated
54 * SDHC block pins
55 * - Cy_SD_Host_IsCardConnected
56 * - Cy_SD_Host_IsWpSet
57 * - Cy_SD_Host_EnableCardVoltage
58 * - Cy_SD_Host_DisableCardVoltage
59 * - Cy_SD_Host_ChangeIoVoltage
60 * In order to disable these implementations, the define CYHAL_DISABLE_WEAK_FUNC_IMPL
61 * (DEFINES+=CYHAL_DISABLE_WEAK_FUNC_IMPL) must be set when building the application.
62 *
63 * By default, if the timeout_ms parameter given to \ref cyhal_sdhc_erase function is 0. The SDHC HAL driver
64 * will check to see if the connected card is emmc. If so, the timeout_ms parameter will be set to 100 milliseconds,
65 * otherwise it will be set to 1000 milliseconds.
66 * \} group_hal_impl_sdhc
67 */
68
69
70 #if (CYHAL_DRIVER_AVAILABLE_SDHC)
71
72 #if defined(__cplusplus)
73 extern "C"
74 {
75 #endif
76
77 #define _CYHAL_SDXX_MHZ(x) (((uint32_t)(x)) * 1000UL * 1000UL)
78
79 #define _CYHAL_SDHC_IRQ_PRIORITY (3UL)
80 #define _CYHAL_SDHC_RW_RETRY_CYCLES (1000u) /* Number of cycles for read/write operation complete */
81 #define _CYHAL_SDHC_RETRY_TIMES (1000UL) /* The number loops to make the timeout in msec */
82 #define _CYHAL_SDHC_FUJE_TIMEOUT_MS (1000U) /* The Fuje timeout for one block */
83 #define _CYHAL_SDHC_RW_TIMEOUT_US (500U) /* The SDHC Read/Write timeout for one block */
84 #define _CYHAL_SDHC_TRANSFER_TIMEOUT (0xCUL) /* The transfer timeout */
85 #define _CYHAL_SDHC_EMMC_TRIM_DELAY_MS (100U) /* The EMMC TRIM timeout */
86 #define _CYHAL_SDIO_ENUMERATION_TIMEOUT_MS (500U)
87 #define _CYHAL_SDHC_READ_TIMEOUT_MS (100U) /* The Read timeout for one block. */
88 #define _CYHAL_SDHC_ALL_ERR_INTERRUPTS (CYHAL_SDHC_CMD_TOUT_ERR | CYHAL_SDHC_CMD_CRC_ERR |\
89 CYHAL_SDHC_CMD_END_BIT_ERR | CYHAL_SDHC_CMD_IDX_ERR |\
90 CYHAL_SDHC_DATA_TOUT_ERR | CYHAL_SDHC_DATA_CRC_ERR |\
91 CYHAL_SDHC_DATA_END_BIT_ERR | CYHAL_SDHC_CUR_LMT_ERR |\
92 CYHAL_SDHC_AUTO_CMD_ERR | CYHAL_SDHC_ADMA_ERR |\
93 CYHAL_SDHC_TUNNING_ERR | CYHAL_SDHC_RESP_ERR |\
94 CYHAL_SDHC_BOOT_ACK_ERR)
95 #define _CYHAL_SDHC_RCA_SHIFT (16U)
96 #define _CYHAL_SDHC_1_8_REG_STABLE_TIME_MS (30U) /* The 1.8 voltage regulator stable time. */
97 #define _CYHAL_SDHC_PWR_RAMP_UP_TIME_MS (36U) /* Time needed for card VDD to achieve operating
98 * supply range level after power on (power on time,
99 * 1 ms + pwr ramp up, max 35 ms) */
100 #define _CYHAL_SDHC_TOUT_TMCLK_POW_MIN (13U) /* Minimal power of 2 for data timeout counter value */
101 #define _CYHAL_SDHC_TOUT_TMCLK_POW_MAX (27U) /* Maximal power of 2 for data timeout counter value */
102 #define _CYHAL_SDHC_EXPECTED_BASE_CLK_FREQ_HZ (_CYHAL_SDXX_MHZ(100))
103 /* By default SDHC block is expected to be clocked by 100 MHz */
104
105 #define _CYHAL_SDHC_EXTCSD_SIZE (512U) /* EMMC EXT_CSD register size in bytes */
106 #define _CYHAL_SDHC_EMMC_CMD6_TIMEOUT_MULT (10U) /* The 10x multiplier of GENERIC_CMD6_TIME[248]. */
107 #define _CYHAL_SDHC_EXTCSD_GENERIC_CMD6_TIME (248U) /* Idx of GENERIC_CMD6_TIME byte in EXT_CSD register */
108 #define _CYHAL_SDHC_EMMC_MAX_SUP_FREQ_HZ (_CYHAL_SDXX_MHZ(52))
109 /* Maximal supported frequency for eMMC for current
110 * implementation */
111
112 #define _CYHAL_SDIO_RW_TIMEOUT_US (5U) /* The SDIO Read/Write timeout for one block */
113 #define _CYHAL_SDIO_CMD_CMPLT_DELAY_US (5U) /* The Command complete delay */
114 #define _CYHAL_SDIO_HOST_CLK_400K (400UL * 1000UL) /* 400 kHz clock frequency */
115 #define _CYHAL_SDIO_64B_BLOCK (64U)
116
117
118 #define _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK (0x61FFUL)
119 #define _CYHAL_SDIO_ALL_INTERRUPTS_ENABLE_MASK (0x61FFUL)
120 #define _CYHAL_SDIO_CLEAR_ALL_INTERRUPTS_MASK (0x0UL)
121 #define _CYHAL_SDIO_CLEAR_ALL_INTERRUPTS_ENABLE_MASK (0x0UL)
122 #define _CYHAL_SDIO_TRANSFER_TRIES (50U)
123
124 /* Clock frequency which is connected to SDHC divider */
125 #define _CYHAL_SDIO_CLK_HF_HZ (_CYHAL_SDXX_MHZ(100))
126
127 /* Macro-function to calculate pin mapping number */
128 #define _CYHAL_SDHC_ELEM_COUNT(pin_mapping) (sizeof(pin_mapping)/sizeof(cyhal_resource_pin_mapping_t))
129
130 #if (defined(SDHC_CHIP_TOP_DATA8_PRESENT) && (SDHC_CHIP_TOP_DATA8_PRESENT)) || \
131 (defined(SDHC0_CHIP_TOP_DATA8_PRESENT) && (SDHC0_CHIP_TOP_DATA8_PRESENT)) || \
132 (defined(SDHC1_CHIP_TOP_DATA8_PRESENT) && (SDHC1_CHIP_TOP_DATA8_PRESENT))
133 #define _CYHAL_SDHC_DATA8_PRESENT 1
134 #else
135 #define _CYHAL_SDHC_DATA8_PRESENT 0
136 #endif
137 #if (defined(SDHC_CHIP_TOP_CARD_DETECT_PRESENT) && (SDHC_CHIP_TOP_CARD_DETECT_PRESENT)) || \
138 (defined(SDHC0_CHIP_TOP_CARD_DETECT_PRESENT) && (SDHC0_CHIP_TOP_CARD_DETECT_PRESENT)) || \
139 (defined(SDHC1_CHIP_TOP_CARD_DETECT_PRESENT) && (SDHC1_CHIP_TOP_CARD_DETECT_PRESENT))
140 #define _CYHAL_SDHC_CARD_DETECT_PRESENT 1
141 #else
142 #define _CYHAL_SDHC_CARD_DETECT_PRESENT 0
143 #endif
144 #if (defined(SDHC_CHIP_TOP_CARD_WRITE_PROT_PRESENT) && (SDHC_CHIP_TOP_CARD_WRITE_PROT_PRESENT)) || \
145 (defined(SDHC0_CHIP_TOP_CARD_WRITE_PROT_PRESENT) && (SDHC0_CHIP_TOP_CARD_WRITE_PROT_PRESENT)) || \
146 (defined(SDHC1_CHIP_TOP_CARD_WRITE_PROT_PRESENT) && (SDHC1_CHIP_TOP_CARD_WRITE_PROT_PRESENT))
147 #define _CYHAL_SDHC_CARD_WRITE_PROT_PRESENT 1
148 #else
149 #define _CYHAL_SDHC_CARD_WRITE_PROT_PRESENT 0
150 #endif
151 #if (defined(SDHC_CHIP_TOP_LED_CTRL_PRESENT) && (SDHC_CHIP_TOP_LED_CTRL_PRESENT)) || \
152 (defined(SDHC0_CHIP_TOP_LED_CTRL_PRESENT) && (SDHC0_CHIP_TOP_LED_CTRL_PRESENT)) || \
153 (defined(SDHC1_CHIP_TOP_LED_CTRL_PRESENT) && (SDHC1_CHIP_TOP_LED_CTRL_PRESENT))
154 #define _CYHAL_SDHC_LED_CTRL_PRESENT 1
155 #else
156 #define _CYHAL_SDHC_LED_CTRL_PRESENT 0
157 #endif
158 #if (defined(SDHC_CHIP_TOP_IO_VOLT_SEL_PRESENT) && (SDHC_CHIP_TOP_IO_VOLT_SEL_PRESENT)) || \
159 (defined(SDHC0_CHIP_TOP_IO_VOLT_SEL_PRESENT) && (SDHC0_CHIP_TOP_IO_VOLT_SEL_PRESENT)) || \
160 (defined(SDHC1_CHIP_TOP_IO_VOLT_SEL_PRESENT) && (SDHC1_CHIP_TOP_IO_VOLT_SEL_PRESENT))
161 #define _CYHAL_SDHC_IO_VOLT_SEL_PRESENT 1
162 #else
163 #define _CYHAL_SDHC_IO_VOLT_SEL_PRESENT 0
164 #endif
165 #if (defined(SDHC_CHIP_TOP_CARD_IF_PWR_EN_PRESENT) && (SDHC_CHIP_TOP_CARD_IF_PWR_EN_PRESENT)) || \
166 (defined(SDHC0_CHIP_TOP_CARD_IF_PWR_EN_PRESENT) && (SDHC0_CHIP_TOP_CARD_IF_PWR_EN_PRESENT)) || \
167 (defined(SDHC1_CHIP_TOP_CARD_IF_PWR_EN_PRESENT) && (SDHC1_CHIP_TOP_CARD_IF_PWR_EN_PRESENT))
168 #define _CYHAL_SDHC_CARD_IF_PWR_EN_PRESENT 1
169 #else
170 #define _CYHAL_SDHC_CARD_IF_PWR_EN_PRESENT 0
171 #endif
172 #if (defined(SDHC_CHIP_TOP_CARD_EMMC_RESET_PRESENT) && (SDHC_CHIP_TOP_CARD_EMMC_RESET_PRESENT)) || \
173 (defined(SDHC0_CHIP_TOP_CARD_EMMC_RESET_PRESENT) && (SDHC0_CHIP_TOP_CARD_EMMC_RESET_PRESENT)) || \
174 (defined(SDHC1_CHIP_TOP_CARD_EMMC_RESET_PRESENT) && (SDHC1_CHIP_TOP_CARD_EMMC_RESET_PRESENT))
175 #define _CYHAL_SDHC_CARD_EMMC_RESET_PRESENT 1
176 #else
177 #define _CYHAL_SDHC_CARD_EMMC_RESET_PRESENT 0
178 #endif
179
180 /* Mask which indicates interface change */
181 #define _CYHAL_SDIO_INTERFACE_CHANGE_MASK ((uint32_t) ((uint32_t) CYHAL_SDIO_GOING_DOWN) | ((uint32_t) CYHAL_SDIO_COMING_UP))
182 const uint32_t MAX_FREQUENCY = 50000000;
183
184 /* List of available SDHC instances */
185 static SDHC_Type * const _CYHAL_SDHC_BASE_ADDRESSES[CY_IP_MXSDHC_INSTANCES] =
186 {
187 #ifdef SDHC0
188 SDHC0,
189 #endif /* ifdef SDHC0 */
190
191 #ifdef SDHC1
192 SDHC1,
193 #endif /* ifdef SDHC1 */
194 };
195
196 /* List of available SDHC interrupt sources */
197 static const _cyhal_system_irq_t _CYHAL_SDHC_IRQ_N[CY_IP_MXSDHC_INSTANCES] =
198 {
199 #ifdef SDHC0
200 sdhc_0_interrupt_general_IRQn,
201 #endif /* ifdef SDHC0 */
202
203 #ifdef SDHC1
204 sdhc_1_interrupt_general_IRQn,
205 #endif /* ifdef SDHC1 */
206 };
207
208 /* SDHC/SDIO I/O voltage select principle.
209 * Internal version of cyhal_sdhc_io_volt_action_type_t and cyhal_sdio_io_volt_action_type_t */
210 typedef enum
211 {
212 _CYHAL_SDXX_IO_VOLT_ACTION_NEGOTIATE = 0U,
213 _CYHAL_SDXX_IO_VOLT_ACTION_SWITCH_SEQ_ONLY = 1U,
214 _CYHAL_SDXX_IO_VOLT_ACTION_NONE = 2U,
215 } _cyhal_sdxx_io_switch_action_t;
216
217 /** I/O voltage levels.
218 * Internal version of cyhal_sdhc_io_voltage_t and cyhal_sdio_io_voltage_t */
219 typedef enum
220 {
221 _CYHAL_SDXX_IO_VOLTAGE_3_3V = 0U, //!< I/O voltage is 3.3V.
222 _CYHAL_SDXX_IO_VOLTAGE_1_8V = 1U //!< I/O voltage is 1.8V.
223 } cyhal_sdxx_io_voltage_t;
224
225 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
226 #include "cyabs_rtos.h"
227
228 typedef enum
229 {
230 /* Semaphore is not initialized */
231 _CYHAL_SDXX_SEMA_NOT_INITED,
232 /* Semaphore is initialized, but will not be used */
233 _CYHAL_SDXX_SEMA_NOT_USED,
234 /* Semaphore is initialized and used (expected to be set in IRQ handler) */
235 _CYHAL_SDXX_SEMA_USED,
236 /* Set in irq handler */
237 _CYHAL_SDXX_SEMA_SET
238 } _cyhal_sdxx_semaphore_status_t;
239
240 /* _cyhal_sdxx_t would be the better place for keeping these items, but since
241 * cy_semaphore_t depends on cyabs_rtos.h that results in circular includes/
242 * messy forward declarations. */
243 static cy_semaphore_t _cyhal_sdxx_semaphore_xfer_done[CY_IP_MXSDHC_INSTANCES];
244 static _cyhal_sdxx_semaphore_status_t _cyhal_sdxx_semaphore_status[CY_IP_MXSDHC_INSTANCES];
245
_cyhal_sdxx_is_smfr_ready_for_set(_cyhal_sdxx_t * sdxx)246 static inline bool _cyhal_sdxx_is_smfr_ready_for_set(_cyhal_sdxx_t *sdxx)
247 {
248 CY_ASSERT(sdxx != NULL);
249 return (_CYHAL_SDXX_SEMA_USED == _cyhal_sdxx_semaphore_status[sdxx->resource.block_num]);
250 }
251
_cyhal_sdxx_is_smfr_ready_for_get(_cyhal_sdxx_t * sdxx)252 static inline bool _cyhal_sdxx_is_smfr_ready_for_get(_cyhal_sdxx_t *sdxx)
253 {
254 CY_ASSERT(sdxx != NULL);
255 return (_CYHAL_SDXX_SEMA_USED == _cyhal_sdxx_semaphore_status[sdxx->resource.block_num]) ||
256 (_CYHAL_SDXX_SEMA_SET == _cyhal_sdxx_semaphore_status[sdxx->resource.block_num]);
257 }
258
259 #endif /* CY_RTOS_AWARE or COMPONENT_RTOS_AWARE defined */
260
_cyhal_sdxx_prepare_for_transfer(_cyhal_sdxx_t * sdxx)261 static cy_rslt_t _cyhal_sdxx_prepare_for_transfer(_cyhal_sdxx_t *sdxx)
262 {
263 CY_ASSERT(sdxx != NULL);
264
265 uint32_t activated_cmd_complete = 0;
266 if (sdxx->irq_cause & (sdxx->is_sdio ? CYHAL_SDIO_CMD_COMPLETE : CYHAL_SDHC_CMD_COMPLETE))
267 {
268 /* Activate CY_SD_HOST_CMD_COMPLETE interrupt mask only if user enabled callback for that event */
269 activated_cmd_complete = CY_SD_HOST_CMD_COMPLETE;
270 }
271
272 /* Enabling transfer complete interrupt as it takes part in in write / read processes */
273 Cy_SD_Host_SetNormalInterruptMask(sdxx->base, Cy_SD_Host_GetNormalInterruptMask(sdxx->base) | activated_cmd_complete | CY_SD_HOST_XFER_COMPLETE);
274
275 return CY_RSLT_SUCCESS;
276 }
277
278 typedef enum
279 {
280 _CYHAL_SDHC_CARD_VDD = 0,
281 _CYHAL_SDHC_CARD_IO_VOLTAGE = 1,
282 _CYHAL_SDHC_CARD_DETECT = 2,
283 _CYHAL_SDHC_CARD_MECH_WRITE_PROTECT = 3,
284 _CYHAL_SDHC_NOT_WEAK_FUNC = 4
285 } _cyhal_sdhc_weak_func_type;
286
287 static _cyhal_sdxx_t *_cyhal_sdxx_config_structs[CY_IP_MXSDHC_INSTANCES];
288
289 /* Structure to map SDHC events on SDHC interrupts */
290 static const uint32_t _cyhal_sdhc_event_map[] =
291 {
292 (uint32_t)CYHAL_SDHC_ERR_INTERRUPT, // Default error if nothing is recognized
293 (uint32_t)CYHAL_SDHC_CMD_COMPLETE, // CY_SD_HOST_CMD_COMPLETE
294 (uint32_t)CYHAL_SDHC_XFER_COMPLETE, // CY_SD_HOST_XFER_COMPLETE
295 (uint32_t)CYHAL_SDHC_BGAP_EVENT, // CY_SD_HOST_BGAP
296 (uint32_t)CYHAL_SDHC_DMA_INTERRUPT, // CY_SD_HOST_DMA_INTERRUPT
297 (uint32_t)CYHAL_SDHC_BUF_WR_READY, // CY_SD_HOST_BUF_WR_READY
298 (uint32_t)CYHAL_SDHC_BUF_RD_READY, // CY_SD_HOST_BUF_RD_READY
299 (uint32_t)CYHAL_SDHC_CARD_INSERTION, // CY_SD_HOST_CARD_INSERTION
300 (uint32_t)CYHAL_SDHC_CARD_REMOVAL, // CY_SD_HOST_CARD_REMOVAL
301 /* Placeholder of removed CYHAL_SDHC_CARD_INTERRUPT.
302 * It is needed for cyhal_sdhc_enable_event and _cyhal_utils_convert_flags
303 * functions correct work. */
304 0,
305 (uint32_t)CYHAL_SDHC_FX_EVENT, // CY_SD_HOST_FX_EVENT
306 (uint32_t)CYHAL_SDHC_CQE_EVENT, // CY_SD_HOST_CQE_EVENT
307 (uint32_t)CYHAL_SDHC_ERR_INTERRUPT, // CY_SD_HOST_ERR_INTERRUPT
308 };
309
310
311 /* This callback is used when card detect pin is GPIO (not dedicated SDHC block signal) */
_cyhal_sdhc_gpio_card_detect_callback(void * callback_arg,cyhal_gpio_event_t event)312 static void _cyhal_sdhc_gpio_card_detect_callback(void *callback_arg, cyhal_gpio_event_t event)
313 {
314 CY_ASSERT(NULL != callback_arg);
315 _cyhal_sdxx_t *sdxx = (_cyhal_sdxx_t *)callback_arg;
316
317 if (sdxx->callback_data.callback != NULL)
318 {
319 cyhal_sdhc_event_callback_t callback = (cyhal_sdhc_event_callback_t) sdxx->callback_data.callback;
320
321 /* Card is considered as inserted if card_detect pin in low state. */
322
323 /* Card removal event */
324 if ((event & CYHAL_GPIO_IRQ_RISE) && (sdxx->irq_cause & CYHAL_SDHC_CARD_REMOVAL))
325 {
326 /* Call registered callbacks here */
327 (callback) (sdxx->callback_data.callback_arg, CYHAL_SDHC_CARD_REMOVAL);
328 }
329 /* Card insertion event */
330 if ((event & CYHAL_GPIO_IRQ_FALL) && (sdxx->irq_cause & CYHAL_SDHC_CARD_INSERTION))
331 {
332 /* Call registered callbacks here */
333 (callback) (sdxx->callback_data.callback_arg, CYHAL_SDHC_CARD_INSERTION);
334 }
335 }
336 }
337
338 #if !defined(CYHAL_DISABLE_WEAK_FUNC_IMPL)
339
340 /* Function, that handles pins that stands behind SD Host PDL driver pin-related WEAK functions, such as:
341 * - Cy_SD_Host_IsCardConnected
342 * - Cy_SD_Host_IsWpSet
343 * - Cy_SD_Host_EnableCardVoltage
344 * - Cy_SD_Host_DisableCardVoltage
345 * - Cy_SD_Host_ChangeIoVoltage
346 * To make their usage in SDHC HAL driver more flexible by providing user ability to use card detect,
347 * write protect, pwr en, and io select signals on pins they like instead of dedicated SDHC block pins */
_cyhal_sdxx_handle_weak_func(const SDHC_Type * base,_cyhal_sdhc_weak_func_type weak_function,bool enable)348 static bool _cyhal_sdxx_handle_weak_func(const SDHC_Type *base, _cyhal_sdhc_weak_func_type weak_function, bool enable)
349 {
350 uint8_t block_idx = (SDHC0 == base) ? 0 : 1;
351 _cyhal_sdxx_t *sdxx = _cyhal_sdxx_config_structs[block_idx];
352 CY_ASSERT(NULL != sdxx);
353
354 cyhal_gpio_t pin_pwr_en;
355 cyhal_gpio_t pin_io_volt_sel;
356 cyhal_gpio_t pin_card_detect;
357 cyhal_gpio_t pin_write_prot;
358
359 CY_ASSERT((weak_function == _CYHAL_SDHC_CARD_VDD) || (weak_function == _CYHAL_SDHC_CARD_IO_VOLTAGE) ||
360 (weak_function == _CYHAL_SDHC_CARD_DETECT) || (weak_function == _CYHAL_SDHC_CARD_MECH_WRITE_PROTECT));
361
362 pin_io_volt_sel = sdxx->pin_io_vol_sel;
363
364 if (sdxx->is_sdio)
365 {
366 pin_pwr_en = NC;
367 pin_card_detect = NC;
368 pin_write_prot = NC;
369 }
370 else
371 {
372 cyhal_sdhc_t *sdhc = (cyhal_sdhc_t *) sdxx->obj;
373 pin_pwr_en = sdhc->pin_card_pwr_en;
374 pin_card_detect = sdhc->pin_card_detect;
375 pin_write_prot = sdhc->pin_card_mech_write_prot;
376 }
377
378 /* function index */
379 uint8_t f_idx = (uint8_t)weak_function;
380
381 /* Indexes according to _cyhal_sdhc_weak_func_type */
382 #if _CYHAL_SDHC_IO_VOLT_SEL_PRESENT
383 static const cyhal_resource_pin_mapping_t* pin_mappings[] = {
384 cyhal_pin_map_sdhc_card_if_pwr_en, cyhal_pin_map_sdhc_io_volt_sel, cyhal_pin_map_sdhc_card_detect_n,
385 cyhal_pin_map_sdhc_card_mech_write_prot
386 };
387 static const size_t pin_mapping_sizes[] = {
388 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_if_pwr_en), _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_io_volt_sel),
389 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_detect_n), _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_mech_write_prot)
390 };
391 #else // _CYHAL_SDHC_IO_VOLT_SEL_PRESENT
392 static const cyhal_resource_pin_mapping_t* pin_mappings[] = {
393 cyhal_pin_map_sdhc_card_if_pwr_en, NULL, cyhal_pin_map_sdhc_card_detect_n,
394 cyhal_pin_map_sdhc_card_mech_write_prot
395 };
396 static const size_t pin_mapping_sizes[] = {
397 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_if_pwr_en), 0,
398 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_detect_n), _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_mech_write_prot)
399 };
400 #endif // _CYHAL_SDHC_IO_VOLT_SEL_PRESENT
401 cyhal_gpio_t pins[] = { pin_pwr_en, pin_io_volt_sel, pin_card_detect, pin_write_prot };
402
403 /* Per sd_host PDL documentation (documentation for Cy_SD_Host_ChangeIoVoltage),
404 * SIGNALING_EN bit of the SDHC_CORE_HOST_CTRL2_R register must be set even if
405 * GPIO used for io voltage switching. */
406 if (_CYHAL_SDHC_CARD_IO_VOLTAGE == weak_function)
407 {
408 SDHC_CORE_HOST_CTRL2_R(base) = _CLR_SET_FLD16U(SDHC_CORE_HOST_CTRL2_R(base),
409 SDHC_CORE_HOST_CTRL2_R_SIGNALING_EN, enable);
410
411 /* enable (true) stands for 1.8V while false for 3.3V */
412 sdxx->low_voltage_io_set = enable;
413 }
414
415 /* BSP-3317. Need to enable PWR_CTRL_R for all pin types */
416 if(weak_function == _CYHAL_SDHC_CARD_VDD)
417 {
418 SDHC_CORE_PWR_CTRL_R(base) =
419 _CLR_SET_FLD8U(SDHC_CORE_PWR_CTRL_R(base), SDHC_CORE_PWR_CTRL_R_SD_BUS_PWR_VDD1, enable);
420 /* If GPIO pin */
421 if (NULL == _cyhal_utils_get_resource(pins[f_idx], pin_mappings[f_idx], pin_mapping_sizes[f_idx], NULL, false))
422 {
423 cyhal_gpio_write(pins[f_idx], enable);
424 }
425 return true;
426 }
427 /* Pin is not provided by user */
428 else if (NC == pins[f_idx])
429 {
430 /* Return true for card detect, false for write protect and false for other (dont care) */
431 return (weak_function == _CYHAL_SDHC_CARD_DETECT) ? true : false;
432 }
433 /* Pin is GPIO */
434 else if (NULL == _cyhal_utils_get_resource(pins[f_idx], pin_mappings[f_idx], pin_mapping_sizes[f_idx], NULL, false))
435 {
436 if (weak_function == _CYHAL_SDHC_CARD_DETECT)
437 {
438 /* Card is inserted if signal is low */
439 return !cyhal_gpio_read(pins[f_idx]);
440 }
441 else if (weak_function == _CYHAL_SDHC_CARD_MECH_WRITE_PROTECT)
442 {
443 /* Card is mech. write protected if signal is high */
444 return cyhal_gpio_read(pins[f_idx]);
445 }
446 /* _CYHAL_SDHC_CARD_IO_VOLTAGE */
447 else
448 {
449 cyhal_gpio_write(pins[f_idx], enable);
450 /* Don't care */
451 return true;
452 }
453 }
454 /* Pin is dedicated SDHC block signal */
455 else
456 {
457 /* Actually copies of corresponding functions from cy_sd_host.c */
458 /* _CYHAL_SDHC_CARD_VDD handled above */
459 switch(weak_function)
460 {
461 case _CYHAL_SDHC_CARD_DETECT:
462 while(true != _FLD2BOOL(SDHC_CORE_PSTATE_REG_CARD_STABLE, SDHC_CORE_PSTATE_REG(base)))
463 {
464 /* Wait until the card is stable. */
465 }
466 return _FLD2BOOL(SDHC_CORE_PSTATE_REG_CARD_INSERTED, SDHC_CORE_PSTATE_REG(base));
467 case _CYHAL_SDHC_CARD_MECH_WRITE_PROTECT:
468 return _FLD2BOOL(SDHC_CORE_PSTATE_REG_WR_PROTECT_SW_LVL, SDHC_CORE_PSTATE_REG(base));
469 case _CYHAL_SDHC_CARD_IO_VOLTAGE:
470 /* io voltage already handled above */
471 (void)0;
472 break;
473 default:
474 CY_ASSERT(false);
475 break;
476 }
477 /* dont care */
478 return true;
479 }
480 }
481
482 /* Overriden Cy_SD_Host_IsCardConnected (originally part of cy_sd_host.c)
483 * This version can handle both - dedicated IP block sdhc_card_detect_n pin and
484 * user-provided GPIO */
Cy_SD_Host_IsCardConnected(SDHC_Type const * base)485 bool Cy_SD_Host_IsCardConnected(SDHC_Type const *base)
486 {
487 return _cyhal_sdxx_handle_weak_func(base, _CYHAL_SDHC_CARD_DETECT, false);
488 }
489
490 /* Overriden Cy_SD_Host_IsWpSet function (originally part of cy_sd_host.c).
491 * This version can handle both - dedicated IP block sdhc_card_mech_write_prot pin
492 * and user-provided GPIO */
Cy_SD_Host_IsWpSet(SDHC_Type const * base)493 bool Cy_SD_Host_IsWpSet(SDHC_Type const *base)
494 {
495 return _cyhal_sdxx_handle_weak_func(base, _CYHAL_SDHC_CARD_MECH_WRITE_PROTECT, false);
496 }
497
498 /* Overriden Cy_SD_Host_EnableCardVoltage and Cy_SD_Host_DisableCardVoltage
499 * functions (originally part of in cy_sd_host.c).
500 * This version can handle both - dedicated IP block sdhc_card_if_pwr_en pin and
501 * user-provided GPIO */
Cy_SD_Host_EnableCardVoltage(SDHC_Type * base)502 void Cy_SD_Host_EnableCardVoltage(SDHC_Type *base)
503 {
504 (void)_cyhal_sdxx_handle_weak_func(base, _CYHAL_SDHC_CARD_VDD, true);
505 }
Cy_SD_Host_DisableCardVoltage(SDHC_Type * base)506 void Cy_SD_Host_DisableCardVoltage(SDHC_Type *base)
507 {
508 (void)_cyhal_sdxx_handle_weak_func(base, _CYHAL_SDHC_CARD_VDD, false);
509 }
510
511 /* Overriden Cy_SD_Host_ChangeIoVoltage function (originally part of cy_sd_host.c).
512 * This version can handle both - dedicated IP block sdhc_io_volt_sel pin
513 * and user-provided GPIO */
Cy_SD_Host_ChangeIoVoltage(SDHC_Type * base,cy_en_sd_host_io_voltage_t ioVoltage)514 void Cy_SD_Host_ChangeIoVoltage(SDHC_Type *base, cy_en_sd_host_io_voltage_t ioVoltage)
515 {
516 (void)_cyhal_sdxx_handle_weak_func(base, _CYHAL_SDHC_CARD_IO_VOLTAGE, (CY_SD_HOST_IO_VOLT_1_8V == ioVoltage));
517 }
518
519 #endif /* CYHAL_DISABLE_WEAK_FUNC_IMPL */
520
_cyhal_sdhc_get_block_from_irqn(_cyhal_system_irq_t irqn)521 static uint8_t _cyhal_sdhc_get_block_from_irqn(_cyhal_system_irq_t irqn)
522 {
523 switch (irqn)
524 {
525 #if (CY_IP_MXSDHC_INSTANCES > 0)
526 case sdhc_0_interrupt_general_IRQn: return 0;
527 #endif
528
529 #if (CY_IP_MXSDHC_INSTANCES > 1)
530 case sdhc_1_interrupt_general_IRQn: return 1;
531 #endif
532
533 #if (CY_IP_MXSDHC_INSTANCES > 2)
534 #error "Unhandled SDHC count"
535 #endif
536 default:
537 CY_ASSERT(false); /* Should never be called with a non-SDHC IRQn */
538 return 0;
539 }
540 }
541
_cyhal_sdxx_setup_pin(_cyhal_sdxx_t * sdxx,cyhal_gpio_t pin,const cyhal_resource_pin_mapping_t * pinmap,uint8_t drive_mode,size_t count,cyhal_gpio_t * objRef,_cyhal_sdhc_weak_func_type weak_func_pin_type,bool reserve_pin)542 static cy_rslt_t _cyhal_sdxx_setup_pin(_cyhal_sdxx_t *sdxx, cyhal_gpio_t pin, const cyhal_resource_pin_mapping_t *pinmap, uint8_t drive_mode,
543 size_t count, cyhal_gpio_t *objRef, _cyhal_sdhc_weak_func_type weak_func_pin_type, bool reserve_pin)
544 {
545 cy_rslt_t result;
546 const cyhal_resource_pin_mapping_t *map = _cyhal_utils_get_resource(pin, pinmap, count, NULL, false);
547
548 if (map == NULL)
549 {
550 result = CYHAL_SDHC_RSLT_ERR_PIN;
551 if (_CYHAL_SDHC_NOT_WEAK_FUNC != weak_func_pin_type)
552 {
553 /* pin, provided by user is probably not dedicated SDHC signal, but GPIO */
554 switch(weak_func_pin_type)
555 {
556 case _CYHAL_SDHC_CARD_DETECT:
557 case _CYHAL_SDHC_CARD_MECH_WRITE_PROTECT:
558 result = reserve_pin
559 ? cyhal_gpio_init(pin, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_NONE, true)
560 : CY_RSLT_SUCCESS;
561 break;
562 case _CYHAL_SDHC_CARD_VDD:
563 case _CYHAL_SDHC_CARD_IO_VOLTAGE:
564 result = reserve_pin
565 ? cyhal_gpio_init(pin, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false)
566 : CY_RSLT_SUCCESS;
567 break;
568 default:
569 CY_ASSERT(false); /* Should never get here. */
570 }
571 }
572 if ((_CYHAL_SDHC_CARD_DETECT == weak_func_pin_type) && (CY_RSLT_SUCCESS == result))
573 {
574 // Ensure the two structures are the same. Divide by 0 build error if they differ.
575 CY_ASSERT(1 / (sizeof(struct cyhal_sdhc_t_gpio_cb) == sizeof(cyhal_gpio_callback_data_t)));
576
577 cyhal_sdhc_t* sdhc = ((cyhal_sdhc_t*) sdxx->obj);
578 cyhal_gpio_callback_data_t* cb_data = (cyhal_gpio_callback_data_t*)&(sdhc->card_detect_cb);
579 cb_data->callback = _cyhal_sdhc_gpio_card_detect_callback;
580 cb_data->callback_arg = sdxx;
581 cyhal_gpio_register_callback(pin, cb_data);
582 cyhal_gpio_enable_event(pin, CYHAL_GPIO_IRQ_BOTH, CYHAL_ISR_PRIORITY_DEFAULT, true);
583 sdhc->cd_gpio_cb_enabled = true;
584 }
585 }
586 else
587 {
588 result = reserve_pin
589 ? _cyhal_utils_reserve_and_connect(map, drive_mode)
590 : CY_RSLT_SUCCESS;
591 }
592
593 if (result == CY_RSLT_SUCCESS)
594 {
595 *objRef = pin;
596 }
597
598 return result;
599 }
600
_cyhal_sdhc_is_busy(const _cyhal_sdxx_t * sdxx)601 bool _cyhal_sdhc_is_busy(const _cyhal_sdxx_t *sdxx) {
602 bool busy_status = true;
603 /* Check DAT Line Active */
604 uint32_t pState = Cy_SD_Host_GetPresentState(sdxx->base);
605 if ((CY_SD_HOST_DAT_LINE_ACTIVE != (pState & CY_SD_HOST_DAT_LINE_ACTIVE)) &&
606 (CY_SD_HOST_CMD_CMD_INHIBIT_DAT != (pState & CY_SD_HOST_CMD_CMD_INHIBIT_DAT)))
607 {
608 busy_status = false;
609 }
610 return busy_status || (_CYHAL_SDXX_NOT_RUNNING != sdxx->data_transfer_status);
611 }
612
613
_cyhal_sdio_is_busy(const _cyhal_sdxx_t * sdxx)614 bool _cyhal_sdio_is_busy(const _cyhal_sdxx_t *sdxx) {
615 return (_CYHAL_SDXX_NOT_RUNNING != sdxx->data_transfer_status);
616 }
617
618 /*******************************************************************************
619 * Deep Sleep Callback Service Routine
620 *******************************************************************************/
621 #if CYHAL_DRIVER_AVAILABLE_SYSPM
_cyhal_sdio_syspm_callback(cyhal_syspm_callback_state_t state,cyhal_syspm_callback_mode_t mode,void * callback_arg)622 static bool _cyhal_sdio_syspm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void *callback_arg)
623 {
624 bool allow = true;
625 _cyhal_sdxx_t *sdxx = (_cyhal_sdxx_t *)callback_arg;
626 CY_ASSERT(sdxx != NULL);
627
628 cyhal_sdio_t *sdio = (cyhal_sdio_t *) sdxx->obj;
629
630 cy_stc_syspm_callback_params_t pdl_params =
631 {
632 .base = sdxx->base,
633 .context = &(sdxx->context)
634 };
635
636 /* Check if hardware is ready to go sleep using lower level callback. */
637 if (state == CYHAL_SYSPM_CB_CPU_DEEPSLEEP)
638 {
639 allow = (Cy_SD_Host_DeepSleepCallback(&pdl_params, _cyhal_utils_convert_haltopdl_pm_mode(mode)) == CY_SYSPM_SUCCESS);
640 }
641
642 if (allow)
643 {
644 switch (mode)
645 {
646 case CYHAL_SYSPM_CHECK_READY:
647 {
648 allow = !_cyhal_sdio_is_busy(sdxx);
649 if (allow)
650 {
651 /* Call the event only if we are ready to go to sleep */
652 cyhal_sdio_event_callback_t callback = (cyhal_sdio_event_callback_t) sdxx->callback_data.callback;
653 if ((callback != NULL) && (0U != (sdio->events & (uint32_t) CYHAL_SDIO_GOING_DOWN)))
654 {
655 (callback)(sdxx->callback_data.callback_arg, CYHAL_SDIO_GOING_DOWN);
656 }
657 /* Set transition flag to prevent any further transaction */
658 sdxx->pm_transition_pending = true;
659 }
660 break;
661 }
662
663 case CYHAL_SYSPM_BEFORE_TRANSITION:
664 case CYHAL_SYSPM_AFTER_DS_WFI_TRANSITION:
665 {
666 /* Nothing to do */
667 break;
668 }
669
670 case CYHAL_SYSPM_AFTER_TRANSITION:
671 case CYHAL_SYSPM_CHECK_FAIL:
672 {
673 /* Execute this only if check ready case was executed */
674 if (sdxx->pm_transition_pending)
675 {
676 /* Execute callback to indicate that interface is coming up */
677 cyhal_sdio_event_callback_t callback = (cyhal_sdio_event_callback_t) sdxx->callback_data.callback;
678 if ((callback != NULL) && (0U != (sdio->events & (uint32_t) CYHAL_SDIO_COMING_UP)))
679 {
680 (callback)(sdxx->callback_data.callback_arg, CYHAL_SDIO_COMING_UP);
681 }
682
683 sdxx->pm_transition_pending = false;
684 }
685 break;
686 }
687
688 default:
689 CY_ASSERT(false);
690 break;
691 }
692 }
693 return allow;
694 }
695
_cyhal_sdhc_syspm_callback(cyhal_syspm_callback_state_t state,cyhal_syspm_callback_mode_t mode,void * callback_arg)696 static bool _cyhal_sdhc_syspm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void *callback_arg)
697 {
698 bool allow = true;
699 _cyhal_sdxx_t *sdxx = (_cyhal_sdxx_t *)callback_arg;
700 CY_ASSERT(sdxx != NULL);
701
702 cy_stc_syspm_callback_params_t pdl_params =
703 {
704 .base = sdxx->base,
705 .context = &(sdxx->context)
706 };
707
708 /* Check if hardware is ready to go sleep using lower level callback. */
709 if ((state == CYHAL_SYSPM_CB_CPU_DEEPSLEEP) || (state == CYHAL_SYSPM_CB_CPU_DEEPSLEEP_RAM))
710 {
711 allow = (Cy_SD_Host_DeepSleepCallback(&pdl_params, _cyhal_utils_convert_haltopdl_pm_mode(mode)) == CY_SYSPM_SUCCESS);
712 }
713
714 if (allow)
715 {
716 switch (mode)
717 {
718 case CYHAL_SYSPM_CHECK_READY:
719 {
720 allow = !_cyhal_sdhc_is_busy(sdxx);
721 if (allow)
722 {
723 /* Set transition flag to prevent any further transaction */
724 sdxx->pm_transition_pending = true;
725 }
726 break;
727 }
728
729 case CYHAL_SYSPM_BEFORE_TRANSITION:
730 {
731 /* Nothing to do */
732 break;
733 }
734
735 case CYHAL_SYSPM_AFTER_TRANSITION:
736 case CYHAL_SYSPM_CHECK_FAIL:
737 {
738 /* Execute this only if check ready case was executed */
739 sdxx->pm_transition_pending = false;
740 break;
741 }
742
743 default:
744 CY_ASSERT(false);
745 break;
746 }
747 }
748 return allow;
749 }
750 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
751
_cyhal_sdhc_buswidth_hal_to_pdl(uint8_t sd_data_bits)752 static cy_en_sd_host_bus_width_t _cyhal_sdhc_buswidth_hal_to_pdl(uint8_t sd_data_bits)
753 {
754 switch (sd_data_bits)
755 {
756 case 1:
757 return CY_SD_HOST_BUS_WIDTH_1_BIT;
758 case 4:
759 return CY_SD_HOST_BUS_WIDTH_4_BIT;
760 case 8:
761 return CY_SD_HOST_BUS_WIDTH_8_BIT;
762 default:
763 CY_ASSERT(false);
764 return CY_SD_HOST_BUS_WIDTH_1_BIT;
765 }
766 }
767
_cyhal_sdhc_buswidth_pdl_to_hal(cy_en_sd_host_bus_width_t sd_data_bits)768 static uint8_t _cyhal_sdhc_buswidth_pdl_to_hal(cy_en_sd_host_bus_width_t sd_data_bits)
769 {
770 switch (sd_data_bits)
771 {
772 case CY_SD_HOST_BUS_WIDTH_1_BIT:
773 return 1;
774 case CY_SD_HOST_BUS_WIDTH_4_BIT:
775 return 4;
776 case CY_SD_HOST_BUS_WIDTH_8_BIT:
777 return 8;
778 default:
779 CY_ASSERT(false);
780 return 1;
781 }
782 }
783
784 /***********************************************************************************************************************
785 *
786 * Finds SDHC internal divider value according to source clock frequency and desired frequency.
787 *
788 * hz_src - Source clock frequency, that needs to be divided
789 * desired_hz - Desired clock frequency
790 * tolerance - (Not used)
791 * only_below_desired - (Not used)
792 * div - Calculated divider value will be placed by this pointer
793 *
794 ***********************************************************************************************************************/
_cyhal_sdxx_find_best_div(uint32_t hz_src,uint32_t desired_hz,const cyhal_clock_tolerance_t * tolerance,bool only_below_desired,uint32_t * div)795 static cy_rslt_t _cyhal_sdxx_find_best_div(uint32_t hz_src, uint32_t desired_hz,
796 const cyhal_clock_tolerance_t *tolerance, bool only_below_desired, uint32_t *div)
797 {
798 CY_UNUSED_PARAMETER(tolerance);
799 CY_UNUSED_PARAMETER(only_below_desired);
800
801 /* Rounding up for correcting the error in integer division
802 * to ensure the actual frequency is less than or equal to
803 * the requested frequency.
804 * Ensure computed divider is no more than 10-bit.
805 */
806
807 if (hz_src > desired_hz)
808 {
809 uint32_t freq = (desired_hz << 1);
810 uint32_t calculated_divider = ((hz_src + freq - 1) / freq) & 0x3FF;
811 /* Real divider is 2 x calculated_divider */
812 *div = calculated_divider << 1;
813 }
814 else
815 {
816 *div = 1;
817 }
818
819 return CY_RSLT_SUCCESS;
820 }
821
822 /***********************************************************************************************************************
823 *
824 * Determines SD bus speed mode according to provided clock frequency and updates SDHC HW registers with corresponding
825 * speed mode setting and, optionally, negotiates new speed mode with the card
826 *
827 * sdxx - Pointer to SDHC/SDIO common structure
828 * freq - Clock frequency, according to which speed mode will be determined
829 * lv_signaling - Support 1.8V
830 * negotiate - Whether new frequency value needs to be negotiated with the card
831 *
832 ***********************************************************************************************************************/
_cyhal_sdxx_update_hw_clock_config(_cyhal_sdxx_t * sdxx,uint32_t freq,bool lv_signaling,bool negotiate)833 static cy_rslt_t _cyhal_sdxx_update_hw_clock_config(_cyhal_sdxx_t *sdxx, uint32_t freq, bool lv_signaling, bool negotiate)
834 {
835 cy_en_sd_host_bus_speed_mode_t busSpeed;
836 cy_rslt_t result;
837
838 if (!sdxx->is_sdio && sdxx->emmc)
839 {
840 /* legacy MMC speed is 0-26 MHz */
841 if (freq <= _CYHAL_SDXX_MHZ(26))
842 {
843 busSpeed = CY_SD_HOST_BUS_SPEED_EMMC_LEGACY;
844 }
845 /* High Speed SDR is 0-52 MHz */
846 else
847 {
848 busSpeed = CY_SD_HOST_BUS_SPEED_EMMC_HIGHSPEED_SDR;
849 }
850 }
851 else
852 {
853 if (freq <= _CYHAL_SDXX_MHZ(25))
854 {
855 busSpeed = (lv_signaling)
856 ? CY_SD_HOST_BUS_SPEED_SDR12_5
857 : CY_SD_HOST_BUS_SPEED_DEFAULT;
858 }
859 else if (freq <= _CYHAL_SDXX_MHZ(50))
860 {
861 busSpeed = (lv_signaling)
862 ? CY_SD_HOST_BUS_SPEED_SDR25
863 : CY_SD_HOST_BUS_SPEED_HIGHSPEED;
864 }
865 else
866 {
867 busSpeed = (lv_signaling)
868 ? CY_SD_HOST_BUS_SPEED_SDR50
869 : CY_SD_HOST_BUS_SPEED_HIGHSPEED;
870 }
871 }
872
873 /* Currently can only negotiate with SD Card. SDIO negotiation proccess is tracked in BSP-2643. */
874 if (negotiate && !sdxx->is_sdio)
875 {
876 result = (cy_rslt_t)Cy_SD_Host_SetBusSpeedMode(sdxx->base, busSpeed, &(sdxx->context));
877 }
878 else
879 {
880 result = (cy_rslt_t)Cy_SD_Host_SetHostSpeedMode(sdxx->base, busSpeed);
881 }
882 return result;
883 }
884
885 /***********************************************************************************************************************
886 *
887 * Changes the Host controller SD clock.
888 *
889 * sdxx - Pointer to SHDC/SDIO common structure
890 * frequency - The frequency in Hz (pointer). This variable will be updated with actual frequency achieved
891 * upon function return.
892 * lv_signaling - Support 1.8V
893 * negotiate - Whether new frequency value needs to be negotiated with the card
894 *
895 ***********************************************************************************************************************/
_cyhal_sdxx_sdcardchangeclock(_cyhal_sdxx_t * sdxx,uint32_t * frequency,bool lv_signaling,bool negotiate)896 static cy_rslt_t _cyhal_sdxx_sdcardchangeclock(_cyhal_sdxx_t *sdxx, uint32_t *frequency, bool lv_signaling, bool negotiate)
897 {
898 CY_ASSERT(NULL != sdxx);
899 CY_ASSERT(NULL != frequency);
900 CY_ASSERT(NULL != sdxx->base);
901
902 cyhal_clock_t most_suitable_hf_source;
903 uint32_t most_suitable_div = 0;
904 uint32_t actual_freq = 0;
905 uint32_t hf_freq = 0;
906 cy_rslt_t ret = CY_RSLT_SUCCESS;
907
908 if (sdxx->clock_owned)
909 {
910 /* Find most suitable HF clock source and divider for it to achieve closest frequency to desired.
911 * No clock settings are being changed here. */
912 ret = _cyhal_utils_find_hf_source_n_divider(&(sdxx->clock), *frequency, NULL, _cyhal_sdxx_find_best_div,
913 &most_suitable_hf_source, &most_suitable_div);
914 }
915 else
916 {
917 ret = _cyhal_sdxx_find_best_div(cyhal_clock_get_frequency(&(sdxx->clock)), *frequency, NULL, false, &most_suitable_div);
918 }
919
920 if (CY_RSLT_SUCCESS == ret)
921 {
922 /* If clock is owned, we just found most suitable hf source for it. if not - we need to work with the one provided */
923 hf_freq = cyhal_clock_get_frequency(sdxx->clock_owned ? &most_suitable_hf_source : &(sdxx->clock));
924 actual_freq = hf_freq / most_suitable_div;
925
926 ret = _cyhal_sdxx_update_hw_clock_config(sdxx, actual_freq, lv_signaling, negotiate);
927 }
928
929 if (sdxx->clock_owned)
930 {
931 if (CY_RSLT_SUCCESS == ret)
932 {
933 /* Switch to most suitable HF clock source */
934 ret = cyhal_clock_set_source(&(sdxx->clock), &most_suitable_hf_source);
935 }
936
937 if (CY_RSLT_SUCCESS == ret)
938 {
939 /* SDHC internal divider will be configured instead. */
940 ret = cyhal_clock_set_divider(&(sdxx->clock), 1);
941 }
942 }
943
944 if (!sdxx->is_sdio)
945 {
946 ((cyhal_sdhc_t *) sdxx->obj)->block_source_freq_hz = hf_freq;
947 }
948
949 if (CY_RSLT_SUCCESS == ret)
950 {
951 Cy_SD_Host_DisableSdClk(sdxx->base);
952 ret = (cy_rslt_t)Cy_SD_Host_SetSdClkDiv(sdxx->base, most_suitable_div >> 1);
953 Cy_SD_Host_EnableSdClk(sdxx->base);
954 }
955
956 if (CY_RSLT_SUCCESS == ret)
957 {
958 *frequency = actual_freq;
959 }
960
961 return ret;
962 }
963
964 /*******************************************************************************
965 *
966 * Waits for the command complete event.
967 *
968 * sdxx - Pointer to SHDC/SDIO common structure
969 * time_used_ms - Pointer to uint32_t value for the total time taken for the function.
970 *
971 *******************************************************************************/
_cyhal_sdxx_pollcmdcomplete(_cyhal_sdxx_t * sdxx,uint32_t * time_used_ms)972 static cy_en_sd_host_status_t _cyhal_sdxx_pollcmdcomplete(_cyhal_sdxx_t *sdxx, uint32_t *time_used_ms)
973 {
974 cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_TIMEOUT;
975 uint32_t retry = _CYHAL_SDHC_RETRY_TIMES * _CYHAL_SDIO_CMD_CMPLT_DELAY_US;
976
977 while (retry > 0UL)
978 {
979 /* Command complete */
980 if (CY_SD_HOST_CMD_COMPLETE == (CY_SD_HOST_CMD_COMPLETE & Cy_SD_Host_GetNormalInterruptStatus(sdxx->base)))
981 {
982 sdxx->data_transfer_status &= ~_CYHAL_SDXX_WAIT_CMD_COMPLETE;
983
984 /* Clear interrupt flag */
985 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, CY_SD_HOST_CMD_COMPLETE);
986
987 ret = CY_SD_HOST_SUCCESS;
988 break;
989 }
990
991 cyhal_system_delay_us(1);
992 retry--;
993 }
994 if (time_used_ms != NULL)
995 {
996 *time_used_ms = (((_CYHAL_SDHC_RETRY_TIMES * _CYHAL_SDIO_CMD_CMPLT_DELAY_US) - retry) / 1000);
997 }
998
999 return ret;
1000 }
1001
1002
1003 /*******************************************************************************
1004 *
1005 * Waits for the transfer complete event.
1006 *
1007 * sdxx - Pointer to SHDC/SDIO common structure
1008 * delay - The delay timeout for one block transfer.
1009 *
1010 * return If the sdxx pointer is NULL, returns error.
1011 *
1012 *******************************************************************************/
_cyhal_sdxx_polltransfercomplete(_cyhal_sdxx_t * sdxx,const uint16_t delay)1013 static cy_en_sd_host_status_t _cyhal_sdxx_polltransfercomplete(_cyhal_sdxx_t *sdxx, const uint16_t delay)
1014 {
1015 cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_TIMEOUT;
1016 uint32_t retry = _CYHAL_SDHC_RW_RETRY_CYCLES;
1017 uint32_t status = 0UL;
1018
1019 while ((CY_SD_HOST_ERROR_TIMEOUT == ret) && (retry-- > 0U))
1020 {
1021 /* We check for either the interrupt register or the byte set in the _cyhal_sdxx_irq_handler
1022 * to avoid a deadlock in the case where if an API that is polling is called from an ISR
1023 * and its priority is higher than the priority of the _cyhal_sdxx_irq_handler thus not allowing
1024 * the signalling byte to be set.
1025 */
1026 status = Cy_SD_Host_GetNormalInterruptStatus(sdxx->base);
1027 if (CY_SD_HOST_XFER_COMPLETE == (CY_SD_HOST_XFER_COMPLETE & status) ||
1028 (sdxx->is_sdio ? !_cyhal_sdio_is_busy(sdxx) : !_cyhal_sdhc_is_busy(sdxx)))
1029 {
1030 /* Transfer complete */
1031 ret = CY_SD_HOST_SUCCESS;
1032 break;
1033 }
1034 cyhal_system_delay_us(delay);
1035 }
1036
1037 return ret;
1038 }
1039
1040 // Indicates that a sync transfer is in process
_cyhal_sdxx_setup_smphr(_cyhal_sdxx_t * sdxx)1041 static void _cyhal_sdxx_setup_smphr(_cyhal_sdxx_t *sdxx)
1042 {
1043 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
1044 uint8_t block_num = sdxx->resource.block_num;
1045 bool in_isr = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
1046 if (!in_isr)
1047 {
1048 cy_rslt_t ret = CY_RSLT_SUCCESS;
1049 if (_CYHAL_SDXX_SEMA_NOT_INITED == _cyhal_sdxx_semaphore_status[block_num])
1050 {
1051 /* Semaphore is used to make transfer complete event wait process be more RTOS-friendly.
1052 * It cannot be initialized in ISR context (some of mbed layers are initializing sdio in ISR conext),
1053 * so we have to do it in scope of transfer functions. */
1054 /* Assert that we are not in an ISR */
1055 CY_ASSERT((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) == 0);
1056 ret = cy_rtos_init_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[block_num]), 1, 0);
1057 }
1058 else if (_CYHAL_SDXX_SEMA_SET == _cyhal_sdxx_semaphore_status[block_num])
1059 {
1060 /* Situation, when semaphore was set, but _cyhal_sdxx_waitfor_transfer_complete function was not
1061 * used for the transfer to get the semaphore (async transfer). Clearing the semaphore in order
1062 * to prepare it for another transfer. */
1063 ret = cy_rtos_get_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[block_num]), 500, in_isr);
1064 }
1065 if (CY_RSLT_SUCCESS == ret)
1066 {
1067 _cyhal_sdxx_semaphore_status[block_num] = _CYHAL_SDXX_SEMA_USED;
1068 }
1069 }
1070 else if (_CYHAL_SDXX_SEMA_NOT_INITED != _cyhal_sdxx_semaphore_status[block_num])
1071 {
1072 _cyhal_sdxx_semaphore_status[block_num] = _CYHAL_SDXX_SEMA_NOT_USED;
1073 }
1074 #else
1075 // We don't need to do anything special if we're not in an RTOS context
1076 CY_UNUSED_PARAMETER(sdxx);
1077 #endif
1078 }
1079
_cyhal_sdxx_waitfor_transfer_complete(_cyhal_sdxx_t * sdxx)1080 static cy_rslt_t _cyhal_sdxx_waitfor_transfer_complete(_cyhal_sdxx_t *sdxx)
1081 {
1082 /* When using an RTOS if a sdxx api (read or write) is called from and ISR in
1083 * in certain RTOSes cy_rtos_get_semaphore returns immediately without blocking. So we can
1084 * either busy wait around the semaphore being set in the ISR or use the normal polling method
1085 * we use in the non-RTOS case. For simplicity and to avoid the calling ISR from depending on
1086 * the SDXX ISR priority we use the normal polling method.
1087 */
1088 cy_rslt_t ret = CY_RSLT_SUCCESS;
1089 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
1090 bool in_isr = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
1091 if ((!in_isr) && _cyhal_sdxx_is_smfr_ready_for_get(sdxx))
1092 {
1093 ret = cy_rtos_get_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[sdxx->resource.block_num]), 500, in_isr);
1094 if (CY_RSLT_SUCCESS == ret)
1095 {
1096 _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_NOT_USED;
1097 }
1098 }
1099 else
1100 {
1101 #endif
1102 ret = (cy_rslt_t)_cyhal_sdxx_polltransfercomplete(sdxx, _CYHAL_SDHC_RW_TIMEOUT_US);
1103 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
1104 }
1105 #endif
1106
1107 return ret;
1108 }
1109
_cyhal_sdhc_irq_handler(void)1110 static void _cyhal_sdhc_irq_handler(void)
1111 {
1112 _cyhal_system_irq_t irqn = _cyhal_irq_get_active();
1113 uint8_t block = _cyhal_sdhc_get_block_from_irqn(irqn);
1114 SDHC_Type *blockAddr = _CYHAL_SDHC_BASE_ADDRESSES[block];
1115 _cyhal_sdxx_t *sdxx = (_cyhal_sdxx_t*) _cyhal_sdxx_config_structs[block];
1116
1117 uint32_t interruptStatus = Cy_SD_Host_GetNormalInterruptStatus(blockAddr);
1118 uint32_t userInterruptStatus = interruptStatus & sdxx->irq_cause;
1119 cyhal_sdhc_event_t user_events = (0 != userInterruptStatus) ? (cyhal_sdhc_event_t)_cyhal_utils_convert_flags(
1120 _cyhal_sdhc_event_map, sizeof(_cyhal_sdhc_event_map) / sizeof(uint32_t), userInterruptStatus) :
1121 (cyhal_sdhc_event_t)0;
1122
1123 /* Some parts of SDHost PDL and SDHC HAL drivers are sending SD commands and polling interrupt status
1124 * until CY_SD_HOST_CMD_COMPLETE occurs. Thats why we can't clear CY_SD_HOST_CMD_COMPLETE interrupt status
1125 * and code below prevents _cyhal_sdhc_irq_handler from being continuosly called because of uncleared
1126 * CY_SD_HOST_CMD_COMPLETE event. */
1127
1128 if (interruptStatus & Cy_SD_Host_GetNormalInterruptMask(blockAddr) & CY_SD_HOST_CMD_COMPLETE)
1129 {
1130 /* Disabling command complete interrupt mask */
1131 Cy_SD_Host_SetNormalInterruptMask(sdxx->base,
1132 Cy_SD_Host_GetNormalInterruptMask(sdxx->base) & (uint32_t) ~CY_SD_HOST_CMD_COMPLETE);
1133 sdxx->data_transfer_status &= ~_CYHAL_SDXX_WAIT_CMD_COMPLETE;
1134 }
1135
1136 /* During SDHost PDL driver operation, CY_SD_HOST_XFER_COMPLETE status can occur and driver
1137 * is polling Cy_SD_Host_GetNormalInterruptStatus while waiting for it. Because of this
1138 * it is critical to have CY_SD_HOST_XFER_COMPLETE event mask disabled and only enabled during
1139 * transfers. Write / Read SDHC/SDIO HAL functions are taking care of enabling CY_SD_HOST_XFER_COMPLETE
1140 * mask before transfer while code below disables it. */
1141
1142 /* CY_SD_HOST_XFER_COMPLETE occured and appropriate bit in interrupt mask is enabled */
1143 if (interruptStatus & Cy_SD_Host_GetNormalInterruptMask(blockAddr) & CY_SD_HOST_XFER_COMPLETE)
1144 {
1145 /* Clearing transfer complete status */
1146 Cy_SD_Host_ClearNormalInterruptStatus(blockAddr, CY_SD_HOST_XFER_COMPLETE);
1147
1148 sdxx->data_transfer_status &= ~_CYHAL_SDXX_WAIT_XFER_COMPLETE;
1149
1150 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
1151 if (_cyhal_sdxx_is_smfr_ready_for_set(sdxx))
1152 {
1153 cy_rtos_set_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[sdxx->resource.block_num]), true);
1154 _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_SET;
1155 }
1156 #endif /* CY_RTOS_AWARE or COMPONENT_RTOS_AWARE defined */
1157
1158 /* Disabling transfer complete interrupt mask */
1159 Cy_SD_Host_SetNormalInterruptMask(sdxx->base,
1160 Cy_SD_Host_GetNormalInterruptMask(sdxx->base) & (uint32_t) ~CY_SD_HOST_XFER_COMPLETE);
1161 }
1162
1163 if ((sdxx->callback_data.callback != NULL) && (0 != user_events))
1164 {
1165 cyhal_sdhc_event_callback_t callback = (cyhal_sdhc_event_callback_t) sdxx->callback_data.callback;
1166
1167 /* Call registered callbacks here */
1168 (callback) (sdxx->callback_data.callback_arg, user_events);
1169 }
1170
1171 /* Cannot clear cmd complete interrupt, as it is being polling-waited by many SD Host functions.
1172 * It is expected to be cleared by mentioned polling functions. */
1173 userInterruptStatus &= (uint32_t) ~CY_SD_HOST_CMD_COMPLETE;
1174
1175 /* Clear only handled events */
1176 Cy_SD_Host_ClearNormalInterruptStatus(blockAddr, userInterruptStatus);
1177 }
1178
_cyhal_sdio_irq_handler(void)1179 static void _cyhal_sdio_irq_handler(void)
1180 {
1181 _cyhal_system_irq_t irqn = _cyhal_irq_get_active();
1182 uint8_t block = _cyhal_sdhc_get_block_from_irqn(irqn);
1183 SDHC_Type *blockAddr = _CYHAL_SDHC_BASE_ADDRESSES[block];
1184 _cyhal_sdxx_t *sdxx = (_cyhal_sdxx_t*) _cyhal_sdxx_config_structs[block];
1185
1186 uint32_t interruptStatus = Cy_SD_Host_GetNormalInterruptStatus(blockAddr);
1187 uint32_t userInterruptStatus = interruptStatus & sdxx->irq_cause;
1188 uint32_t normalInterruptMask = Cy_SD_Host_GetNormalInterruptMask(blockAddr);
1189
1190 /* Some parts of SDHost PDL and SDIO HAL drivers are sending SD commands and polling interrupt status
1191 * until CY_SD_HOST_CMD_COMPLETE occurs. Thats why we can't clear CY_SD_HOST_CMD_COMPLETE interrupt status
1192 * and code below prevents _cyhal_sdhc_irq_handler from being continuosly called because of uncleared
1193 * CY_SD_HOST_CMD_COMPLETE event. */
1194
1195 if (interruptStatus & normalInterruptMask & CY_SD_HOST_CMD_COMPLETE)
1196 {
1197 /* Disabling command complete interrupt mask */
1198 Cy_SD_Host_SetNormalInterruptMask(sdxx->base,
1199 Cy_SD_Host_GetNormalInterruptMask(sdxx->base) & (uint32_t) ~CY_SD_HOST_CMD_COMPLETE);
1200 sdxx->data_transfer_status &= ~_CYHAL_SDXX_WAIT_CMD_COMPLETE;
1201 }
1202
1203 /* During SDHost PDL driver operation, CY_SD_HOST_XFER_COMPLETE status can occur and driver
1204 * is polling Cy_SD_Host_GetNormalInterruptStatus while waiting for it. Because of this
1205 * it is critical to have CY_SD_HOST_XFER_COMPLETE event mask disabled and only enabled during
1206 * transfers. Write / Read SDHC/SDIO HAL functions are taking care of enabling CY_SD_HOST_XFER_COMPLETE
1207 * mask before transfer while code below disables it. */
1208
1209 /* CY_SD_HOST_XFER_COMPLETE occured and appropriate bit in interrupt mask is enabled */
1210 if (interruptStatus & normalInterruptMask & CY_SD_HOST_XFER_COMPLETE)
1211 {
1212 sdxx->data_transfer_status &= ~_CYHAL_SDXX_WAIT_XFER_COMPLETE ;
1213 Cy_SD_Host_ClearNormalInterruptStatus(blockAddr, CY_SD_HOST_XFER_COMPLETE);
1214 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
1215 if (_cyhal_sdxx_is_smfr_ready_for_set(sdxx))
1216 {
1217 cy_rtos_set_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[block]), true);
1218 _cyhal_sdxx_semaphore_status[block] = _CYHAL_SDXX_SEMA_SET;
1219 }
1220 #endif /* CY_RTOS_AWARE or COMPONENT_RTOS_AWARE defined */
1221
1222 /* Disabling transfer complete interrupt mask */
1223 Cy_SD_Host_SetNormalInterruptMask(sdxx->base,
1224 Cy_SD_Host_GetNormalInterruptMask(sdxx->base) & (uint32_t) ~CY_SD_HOST_XFER_COMPLETE);
1225
1226 /* Transfer is no more active. If card interrupt was not yet enabled after it was disabled in
1227 * interrupt handler, enable it.
1228 */
1229 uint32_t interrupt_enable_status = Cy_SD_Host_GetNormalInterruptEnable(sdxx->base);
1230 if ((interrupt_enable_status & CY_SD_HOST_CARD_INTERRUPT) == 0)
1231 {
1232 Cy_SD_Host_SetNormalInterruptEnable(sdxx->base, (interrupt_enable_status | CY_SD_HOST_CARD_INTERRUPT));
1233 }
1234 }
1235
1236 if (sdxx->callback_data.callback != NULL && (userInterruptStatus & normalInterruptMask) > 0)
1237 {
1238 cyhal_sdio_event_callback_t callback = (cyhal_sdio_event_callback_t) sdxx->callback_data.callback;
1239 /* Call registered callbacks here */
1240 /* We may have masked off CMD_COMPLETE above on a previous interrupt, mask here with normalInterruptMask to echo this */
1241 (callback)(sdxx->callback_data.callback_arg, (cyhal_sdio_event_t) (userInterruptStatus & normalInterruptMask));
1242 }
1243
1244 /* Cannot clear cmd complete interrupt, as it is being polling-waited by many SD Host functions.
1245 * It is expected to be cleared by mentioned polling functions. */
1246 userInterruptStatus &= (uint32_t) ~CY_SD_HOST_CMD_COMPLETE;
1247
1248 /* Clear only handled events */
1249 Cy_SD_Host_ClearNormalInterruptStatus(blockAddr, userInterruptStatus);
1250
1251 /* To clear Card Interrupt need to disable Card Interrupt Enable bit.
1252 * The Card Interrupt is enabled after the current transfer is complete
1253 */
1254 if (0U != (interruptStatus & CY_SD_HOST_CARD_INTERRUPT))
1255 {
1256 uint32_t interruptMask = Cy_SD_Host_GetNormalInterruptEnable(blockAddr);
1257 interruptMask &= (uint32_t) ~CY_SD_HOST_CARD_INTERRUPT;
1258 /* Disable Card Interrupt */
1259 Cy_SD_Host_SetNormalInterruptEnable(blockAddr, interruptMask);
1260 }
1261 }
1262
1263 /* Software reset of SDHC block data and command circuits */
_cyhal_sdxx_reset(_cyhal_sdxx_t * sdxx)1264 static void _cyhal_sdxx_reset(_cyhal_sdxx_t *sdxx)
1265 {
1266 CY_ASSERT(NULL != sdxx);
1267 CY_ASSERT(NULL != sdxx->base);
1268
1269 /* Usually it is enough ~ 15 us for reset to complete on 100 MHz HF clock for any supported compiler / optimization.
1270 * Making max time much greater to cover different frequencies and unusual cases. Timeout and SW_RST_R check
1271 * will be removed after DRIVERS-5769 is resolved. */
1272 uint32_t timeout_us = 1000;
1273
1274 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
1275 Cy_SD_Host_SoftwareReset(sdxx->base, CY_SD_HOST_RESET_DATALINE);
1276 Cy_SD_Host_SoftwareReset(sdxx->base, CY_SD_HOST_RESET_CMD_LINE);
1277
1278 /* This wait loop will be removed after DRIVERS-5769 resolved. */
1279 while ((sdxx->base->CORE.SW_RST_R != 0) && (timeout_us-- != 0))
1280 {
1281 cyhal_system_delay_us(1);
1282 }
1283
1284 /* Reset was not cleared by SDHC IP Block. Something wrong. Are clocks enabled? */
1285 CY_ASSERT(timeout_us != 0);
1286 }
1287
_cyhal_sdhc_init_common_hw(cyhal_sdhc_t * obj,const cyhal_sdhc_configurator_t * cfg)1288 static cy_rslt_t _cyhal_sdhc_init_common_hw(cyhal_sdhc_t *obj, const cyhal_sdhc_configurator_t *cfg)
1289 {
1290 CY_ASSERT(NULL != obj);
1291 CY_ASSERT(NULL != cfg);
1292
1293 cy_rslt_t result = CY_RSLT_SUCCESS;
1294
1295 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1296 sdxx->obj = obj;
1297 sdxx->is_sdio = false;
1298
1299 /* Configuration is provided by device configurator */
1300 sdxx->dc_configured = (cfg->resource != NULL);
1301 sdxx->dma_type = cfg->host_config->dmaType;
1302
1303 if (sdxx->dc_configured && (cfg->host_config->dmaType != CY_SD_HOST_DMA_ADMA2))
1304 {
1305 /* SDHC HAL does not support non-CY_SD_HOST_DMA_ADMA2 DMA configurations */
1306 return CYHAL_SDHC_RSLT_ERR_UNSUPPORTED;
1307 }
1308
1309 sdxx->base = NULL;
1310 sdxx->resource.type = CYHAL_RSC_INVALID;
1311
1312 sdxx->pin_clk = CYHAL_NC_PIN_VALUE;
1313 sdxx->pin_cmd = CYHAL_NC_PIN_VALUE;
1314 obj->pin_data[0] = CYHAL_NC_PIN_VALUE;
1315 obj->pin_data[1] = CYHAL_NC_PIN_VALUE;
1316 obj->pin_data[2] = CYHAL_NC_PIN_VALUE;
1317 obj->pin_data[3] = CYHAL_NC_PIN_VALUE;
1318 obj->pin_data[4] = CYHAL_NC_PIN_VALUE;
1319 obj->pin_data[5] = CYHAL_NC_PIN_VALUE;
1320 obj->pin_data[6] = CYHAL_NC_PIN_VALUE;
1321 obj->pin_data[7] = CYHAL_NC_PIN_VALUE;
1322 obj->pin_card_detect = CYHAL_NC_PIN_VALUE;
1323 sdxx->pin_io_vol_sel = CYHAL_NC_PIN_VALUE;
1324 obj->pin_card_pwr_en = CYHAL_NC_PIN_VALUE;
1325 obj->pin_card_mech_write_prot = CYHAL_NC_PIN_VALUE;
1326 obj->pin_led_ctrl = CYHAL_NC_PIN_VALUE;
1327 obj->pin_emmc_reset = CYHAL_NC_PIN_VALUE;
1328
1329 obj->cd_gpio_cb_enabled = false;
1330 sdxx->clock_owned = false;
1331 sdxx->low_voltage_io_set = false;
1332
1333 cyhal_gpio_t data[8];
1334 memcpy(data, cfg->gpios.data, sizeof(data));
1335
1336 cyhal_gpio_t cmd = cfg->gpios.cmd;
1337 cyhal_gpio_t clk = cfg->gpios.clk;
1338 cyhal_gpio_t card_detect = cfg->gpios.card_detect;
1339 cyhal_gpio_t io_volt_sel = cfg->gpios.io_volt_sel;
1340 cyhal_gpio_t card_pwr_en = cfg->gpios.card_pwr_en;
1341 cyhal_gpio_t card_mech_write_prot = cfg->gpios.card_mech_write_prot;
1342 cyhal_gpio_t led_ctrl = cfg->gpios.led_ctrl;
1343 cyhal_gpio_t emmc_reset = cfg->gpios.emmc_reset;
1344
1345 obj->data_timeout_tout = _CYHAL_SDHC_TRANSFER_TIMEOUT;
1346 obj->data_timeout_card_clocks_user = 0;
1347 obj->data_timeout_auto_reconfig = false;
1348
1349 /* Reserve SDHC */
1350 const cyhal_resource_pin_mapping_t *map = _CYHAL_UTILS_GET_RESOURCE(cmd, cyhal_pin_map_sdhc_card_cmd);
1351
1352 if (NULL == map || NC == data[0])
1353 {
1354 // return now, nothing has been allocated so no need to proceed on
1355 return CYHAL_SDHC_RSLT_ERR_PIN;
1356 }
1357
1358 cyhal_resource_inst_t rsc = { CYHAL_RSC_SDHC, map->block_num, map->channel_num };
1359
1360 /* Reserve and configure GPIO pins */
1361 if (result == CY_RSLT_SUCCESS)
1362 {
1363 result = _cyhal_sdxx_setup_pin(
1364 sdxx, cmd, cyhal_pin_map_sdhc_card_cmd, CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_CMD,
1365 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_cmd),
1366 &(sdxx->pin_cmd), _CYHAL_SDHC_NOT_WEAK_FUNC, !sdxx->dc_configured);
1367 }
1368
1369 if (result == CY_RSLT_SUCCESS)
1370 {
1371 result = _cyhal_sdxx_setup_pin(
1372 sdxx, clk, cyhal_pin_map_sdhc_clk_card, CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CLK_CARD,
1373 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_clk_card),
1374 &(sdxx->pin_clk), _CYHAL_SDHC_NOT_WEAK_FUNC, !sdxx->dc_configured);
1375 }
1376
1377 for (uint8_t i = 0; (i < 4) && (CY_RSLT_SUCCESS == result); i++)
1378 {
1379 if (NC != data[i])
1380 {
1381 result = _cyhal_sdxx_setup_pin(sdxx, data[i], cyhal_pin_map_sdhc_card_dat_3to0,
1382 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
1383 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data[i]),
1384 _CYHAL_SDHC_NOT_WEAK_FUNC, !sdxx->dc_configured);
1385 }
1386 }
1387
1388 #if _CYHAL_SDHC_DATA8_PRESENT
1389 for (uint8_t i = 4; (i < 8) && (CY_RSLT_SUCCESS == result); i++)
1390 {
1391 if (NC != data[i])
1392 {
1393 result = _cyhal_sdxx_setup_pin(sdxx, data[i], cyhal_pin_map_sdhc_card_dat_7to4,
1394 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_7TO4,
1395 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_7to4), &(obj->pin_data[i]),
1396 _CYHAL_SDHC_NOT_WEAK_FUNC, !sdxx->dc_configured);
1397 }
1398 }
1399 #else
1400 if ((NC != data[4] || NC != data[5] || NC != data[6] || NC != data[7]) && (CY_RSLT_SUCCESS == result))
1401 {
1402 result = CYHAL_SDHC_RSLT_ERR_PIN;
1403 }
1404 #endif
1405
1406 if ((NC != card_detect) && (CY_RSLT_SUCCESS == result))
1407 {
1408 #if _CYHAL_SDHC_CARD_DETECT_PRESENT
1409 result = _cyhal_sdxx_setup_pin(sdxx, card_detect, cyhal_pin_map_sdhc_card_detect_n,
1410 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DETECT_N,
1411 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_detect_n), &(obj->pin_card_detect),
1412 _CYHAL_SDHC_CARD_DETECT, !sdxx->dc_configured);
1413 #else
1414 result = CYHAL_SDHC_RSLT_ERR_PIN;
1415 #endif
1416 }
1417
1418 if ((NC != io_volt_sel) && (CY_RSLT_SUCCESS == result))
1419 {
1420 #if _CYHAL_SDHC_IO_VOLT_SEL_PRESENT
1421 result = _cyhal_sdxx_setup_pin(sdxx, io_volt_sel, cyhal_pin_map_sdhc_io_volt_sel,
1422 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_IO_VOLT_SEL,
1423 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_io_volt_sel), &(sdxx->pin_io_vol_sel),
1424 _CYHAL_SDHC_CARD_IO_VOLTAGE, !sdxx->dc_configured);
1425 #else
1426 result = _cyhal_sdxx_setup_pin(sdxx, io_volt_sel, NULL,
1427 CY_GPIO_DM_STRONG_IN_OFF,
1428 0, &(sdxx->pin_io_vol_sel),
1429 _CYHAL_SDHC_CARD_IO_VOLTAGE, !sdxx->dc_configured);
1430 #endif
1431 }
1432
1433 if ((NC != card_pwr_en) && (CY_RSLT_SUCCESS == result))
1434 {
1435 #if _CYHAL_SDHC_CARD_IF_PWR_EN_PRESENT
1436 result = _cyhal_sdxx_setup_pin(sdxx, card_pwr_en, cyhal_pin_map_sdhc_card_if_pwr_en,
1437 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_IF_PWR_EN,
1438 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_if_pwr_en), &(obj->pin_card_pwr_en), _CYHAL_SDHC_CARD_VDD,
1439 !sdxx->dc_configured);
1440 #else
1441 result = CYHAL_SDHC_RSLT_ERR_PIN;
1442 #endif
1443 }
1444
1445 if ((NC != card_mech_write_prot) && (CY_RSLT_SUCCESS == result))
1446 {
1447 #if _CYHAL_SDHC_CARD_WRITE_PROT_PRESENT
1448 result = _cyhal_sdxx_setup_pin(sdxx, card_mech_write_prot, cyhal_pin_map_sdhc_card_mech_write_prot,
1449 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_MECH_WRITE_PROT,
1450 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_mech_write_prot), &(obj->pin_card_mech_write_prot),
1451 _CYHAL_SDHC_CARD_MECH_WRITE_PROTECT, !sdxx->dc_configured);
1452 #else
1453 result = CYHAL_SDHC_RSLT_ERR_PIN;
1454 #endif
1455 }
1456
1457 if ((NC != led_ctrl) && (CY_RSLT_SUCCESS == result))
1458 {
1459 #if _CYHAL_SDHC_LED_CTRL_PRESENT
1460 result = _cyhal_sdxx_setup_pin(sdxx, led_ctrl, cyhal_pin_map_sdhc_led_ctrl,
1461 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_LED_CTRL,
1462 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_led_ctrl), &(obj->pin_led_ctrl), _CYHAL_SDHC_NOT_WEAK_FUNC, !sdxx->dc_configured);
1463 #else
1464 result = CYHAL_SDHC_RSLT_ERR_PIN;
1465 #endif
1466 }
1467
1468 if ((NC != emmc_reset) && (CY_RSLT_SUCCESS == result))
1469 {
1470 #if _CYHAL_SDHC_CARD_EMMC_RESET_PRESENT
1471 result = _cyhal_sdxx_setup_pin(sdxx, emmc_reset, cyhal_pin_map_sdhc_card_emmc_reset_n,
1472 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_EMMC_RESET_N,
1473 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_emmc_reset_n), &(obj->pin_emmc_reset),
1474 _CYHAL_SDHC_NOT_WEAK_FUNC, !sdxx->dc_configured);
1475 #else
1476 result = CYHAL_SDHC_RSLT_ERR_PIN;
1477 #endif
1478 }
1479
1480 if (CY_RSLT_SUCCESS == result)
1481 {
1482 /* Clock was not provided, so allocate one */
1483 if (cfg->clock == NULL)
1484 {
1485 result = _cyhal_utils_allocate_clock(&(sdxx->clock), &rsc, CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT, true);
1486
1487 if (CY_RSLT_SUCCESS == result)
1488 {
1489 sdxx->clock_owned = true;
1490 result = _cyhal_utils_set_clock_frequency2(&(sdxx->clock), MAX_FREQUENCY, &CYHAL_CLOCK_TOLERANCE_5_P);
1491 }
1492
1493 if (CY_RSLT_SUCCESS == result && !cyhal_clock_is_enabled(&(sdxx->clock)))
1494 {
1495 result = cyhal_clock_set_enabled(&(sdxx->clock), true, true);
1496 }
1497 }
1498 else
1499 {
1500 if (cfg->clock->block == CYHAL_CLOCK_BLOCK_HF)
1501 {
1502 sdxx->clock = *cfg->clock;
1503 obj->bus_frequency_hz = cyhal_clock_get_frequency(&(sdxx->clock));
1504 }
1505 if ((cfg->clock->block != CYHAL_CLOCK_BLOCK_HF) || (obj->bus_frequency_hz == 0))
1506 {
1507 result = CYHAL_SDHC_RSLT_ERR_CLOCK;
1508 }
1509 }
1510 }
1511
1512 if (CY_RSLT_SUCCESS == result)
1513 {
1514 if (sdxx->dc_configured)
1515 {
1516 sdxx->resource = *(cfg->resource);
1517 }
1518 else
1519 {
1520 result = cyhal_hwmgr_reserve(&rsc);
1521 }
1522 }
1523
1524 if (CY_RSLT_SUCCESS == result)
1525 {
1526 sdxx->resource = rsc;
1527 sdxx->base = _CYHAL_SDHC_BASE_ADDRESSES[sdxx->resource.block_num];
1528 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
1529 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
1530 _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_NOT_INITED;
1531 #endif /* defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE) */
1532
1533 /* Enable the SDHC block */
1534 Cy_SD_Host_Enable(sdxx->base);
1535
1536 sdxx->emmc = cfg->host_config->emmc;
1537 sdxx->context.cardType = CY_SD_HOST_NOT_EMMC;
1538
1539 sdxx->irq_cause = 0UL;
1540 sdxx->callback_data.callback = NULL;
1541 sdxx->callback_data.callback_arg = NULL;
1542 _cyhal_sdxx_config_structs[sdxx->resource.block_num] = sdxx;
1543
1544 _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
1545 _cyhal_irq_register(irqn, CYHAL_ISR_PRIORITY_DEFAULT, _cyhal_sdhc_irq_handler);
1546 _cyhal_irq_enable(irqn);
1547
1548 result = (cy_rslt_t)Cy_SD_Host_Init(sdxx->base, cfg->host_config, &(sdxx->context));
1549 }
1550
1551 #if CYHAL_DRIVER_AVAILABLE_SYSPM
1552 if(result == CY_RSLT_SUCCESS)
1553 {
1554 sdxx->pm_transition_pending = false;
1555 sdxx->pm_callback_data.callback = &_cyhal_sdhc_syspm_callback;
1556 sdxx->pm_callback_data.states =
1557 (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE);
1558 sdxx->pm_callback_data.next = NULL;
1559 sdxx->pm_callback_data.args = sdxx;
1560 /* The CYHAL_SYSPM_BEFORE_TRANSITION mode cannot be ignored because the PM handler
1561 * calls the PDL deep-sleep callback that disables the block in this mode before transitioning.
1562 */
1563 sdxx->pm_callback_data.ignore_modes = (cyhal_syspm_callback_mode_t)0;
1564
1565 _cyhal_syspm_register_peripheral_callback(&(sdxx->pm_callback_data));
1566 }
1567 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1568
1569 if (result != CY_RSLT_SUCCESS)
1570 {
1571 cyhal_sdhc_free(obj);
1572 }
1573
1574 return result;
1575 }
1576
cyhal_sdhc_init_hw(cyhal_sdhc_t * obj,const cyhal_sdhc_config_t * config,cyhal_gpio_t cmd,cyhal_gpio_t clk,cyhal_gpio_t data0,cyhal_gpio_t data1,cyhal_gpio_t data2,cyhal_gpio_t data3,cyhal_gpio_t data4,cyhal_gpio_t data5,cyhal_gpio_t data6,cyhal_gpio_t data7,cyhal_gpio_t card_detect,cyhal_gpio_t io_volt_sel,cyhal_gpio_t card_pwr_en,cyhal_gpio_t card_mech_write_prot,cyhal_gpio_t led_ctrl,cyhal_gpio_t emmc_reset,cyhal_clock_t * block_clk)1577 cy_rslt_t cyhal_sdhc_init_hw(cyhal_sdhc_t *obj,
1578 const cyhal_sdhc_config_t *config,
1579 cyhal_gpio_t cmd,
1580 cyhal_gpio_t clk,
1581 cyhal_gpio_t data0,
1582 cyhal_gpio_t data1,
1583 cyhal_gpio_t data2,
1584 cyhal_gpio_t data3,
1585 cyhal_gpio_t data4,
1586 cyhal_gpio_t data5,
1587 cyhal_gpio_t data6,
1588 cyhal_gpio_t data7,
1589 cyhal_gpio_t card_detect,
1590 cyhal_gpio_t io_volt_sel,
1591 cyhal_gpio_t card_pwr_en,
1592 cyhal_gpio_t card_mech_write_prot,
1593 cyhal_gpio_t led_ctrl,
1594 cyhal_gpio_t emmc_reset,
1595 cyhal_clock_t *block_clk)
1596 {
1597 CY_ASSERT(NULL != obj);
1598
1599 cy_stc_sd_host_init_config_t sd_host_config = {
1600 .emmc = config->isEmmc,
1601 .dmaType = CY_SD_HOST_DMA_ADMA2,
1602 .enableLedControl = config->enableLedControl
1603 };
1604
1605 const cyhal_sdhc_configurator_t cfg = {
1606 /* Resource will be reserved and assigned in HAL flow */
1607 .resource = NULL,
1608 .host_config = &sd_host_config,
1609 .card_config = NULL,
1610 .clock = block_clk,
1611 .gpios = {
1612 .cmd = cmd, .clk = clk, .data[0] = data0, .data[1] = data1, .data[2] = data2, .data[3] = data3,
1613 .data[4] = data4, .data[5] = data5, .data[6] = data6, .data[7] = data7, .card_detect = card_detect,
1614 .io_volt_sel = io_volt_sel, .card_pwr_en = card_pwr_en, .card_mech_write_prot = card_mech_write_prot,
1615 .led_ctrl = led_ctrl, .emmc_reset = emmc_reset
1616 }
1617 };
1618
1619 obj->low_voltage_io_desired = config->lowVoltageSignaling;
1620 obj->bus_width = config->busWidth;
1621
1622 return _cyhal_sdhc_init_common_hw(obj, &cfg);
1623 }
1624
_cyhal_sdhc_init_card_common(cyhal_sdhc_t * obj,cy_stc_sd_host_sd_card_config_t * cfg)1625 static cy_rslt_t _cyhal_sdhc_init_card_common(cyhal_sdhc_t *obj, cy_stc_sd_host_sd_card_config_t *cfg)
1626 {
1627 CY_ASSERT(NULL != obj);
1628 CY_ASSERT(NULL != obj->sdxx.base);
1629
1630 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1631
1632 /* Initialize the card */
1633 cy_rslt_t result = (cy_rslt_t)Cy_SD_Host_InitCard(sdxx->base, cfg, &(sdxx->context));
1634
1635 if (CY_RSLT_SUCCESS == result)
1636 {
1637 /* If clock is owned by driver, update SD Card frequency to be 25 Mhz. Otherwise, configure interface clock
1638 * for passthrough (to be same as SDHC block source clock) */
1639 result = cyhal_sdhc_set_frequency(obj,
1640 sdxx->clock_owned ? _CYHAL_SDXX_MHZ(25) : cyhal_clock_get_frequency(&(sdxx->clock)), true);
1641 }
1642
1643 if ((CY_RSLT_SUCCESS == result) && (sdxx->emmc))
1644 {
1645 uint8_t ext_csd[_CYHAL_SDHC_EXTCSD_SIZE] = { 0UL };
1646 if (CY_RSLT_SUCCESS == (cy_rslt_t)Cy_SD_Host_GetExtCsd(sdxx->base, (uint32_t *)ext_csd, &(sdxx->context)))
1647 {
1648 /* Get GENERIC_CMD6_TIME [248] of the EXTCSD register */
1649 obj->emmc_generic_cmd6_time_ms =
1650 (uint16_t) (_CYHAL_SDHC_EMMC_CMD6_TIMEOUT_MULT * ext_csd[_CYHAL_SDHC_EXTCSD_GENERIC_CMD6_TIME]);
1651 }
1652 }
1653 return result;
1654 }
1655
cyhal_sdhc_init_card(cyhal_sdhc_t * obj)1656 cy_rslt_t cyhal_sdhc_init_card(cyhal_sdhc_t *obj)
1657 {
1658 cy_en_sd_host_card_type_t card_type;
1659 cy_en_sd_host_card_capacity_t card_capacity;
1660 uint32_t rca = 0;
1661
1662 cy_stc_sd_host_sd_card_config_t sd_card_config = {
1663 .lowVoltageSignaling = obj->low_voltage_io_desired,
1664 .busWidth = _cyhal_sdhc_buswidth_hal_to_pdl(obj->bus_width),
1665 .cardType = &card_type,
1666 .rca = &rca,
1667 .cardCapacity = &card_capacity
1668 };
1669
1670 return _cyhal_sdhc_init_card_common(obj, &sd_card_config);
1671 }
1672
cyhal_sdhc_init(cyhal_sdhc_t * obj,const cyhal_sdhc_config_t * config,cyhal_gpio_t cmd,cyhal_gpio_t clk,cyhal_gpio_t data0,cyhal_gpio_t data1,cyhal_gpio_t data2,cyhal_gpio_t data3,cyhal_gpio_t data4,cyhal_gpio_t data5,cyhal_gpio_t data6,cyhal_gpio_t data7,cyhal_gpio_t card_detect,cyhal_gpio_t io_volt_sel,cyhal_gpio_t card_pwr_en,cyhal_gpio_t card_mech_write_prot,cyhal_gpio_t led_ctrl,cyhal_gpio_t emmc_reset,cyhal_clock_t * block_clk)1673 cy_rslt_t cyhal_sdhc_init(cyhal_sdhc_t *obj,
1674 const cyhal_sdhc_config_t *config,
1675 cyhal_gpio_t cmd,
1676 cyhal_gpio_t clk,
1677 cyhal_gpio_t data0,
1678 cyhal_gpio_t data1,
1679 cyhal_gpio_t data2,
1680 cyhal_gpio_t data3,
1681 cyhal_gpio_t data4,
1682 cyhal_gpio_t data5,
1683 cyhal_gpio_t data6,
1684 cyhal_gpio_t data7,
1685 cyhal_gpio_t card_detect,
1686 cyhal_gpio_t io_volt_sel,
1687 cyhal_gpio_t card_pwr_en,
1688 cyhal_gpio_t card_mech_write_prot,
1689 cyhal_gpio_t led_ctrl,
1690 cyhal_gpio_t emmc_reset,
1691 cyhal_clock_t *block_clk)
1692 {
1693 cy_rslt_t result = cyhal_sdhc_init_hw(obj, config, cmd, clk, data0, data1, data2, data3, data4, data5, data6,
1694 data7, card_detect, io_volt_sel, card_pwr_en, card_mech_write_prot, led_ctrl, emmc_reset, block_clk);
1695
1696 /* Initialize card */
1697 if (result == CY_RSLT_SUCCESS)
1698 {
1699 result = cyhal_sdhc_init_card(obj);
1700 }
1701
1702 return result;
1703 }
1704
cyhal_sdhc_init_cfg(cyhal_sdhc_t * obj,const cyhal_sdhc_configurator_t * cfg)1705 cy_rslt_t cyhal_sdhc_init_cfg(cyhal_sdhc_t *obj, const cyhal_sdhc_configurator_t *cfg)
1706 {
1707 obj->low_voltage_io_desired = cfg->card_config->lowVoltageSignaling;
1708 obj->bus_width = _cyhal_sdhc_buswidth_pdl_to_hal(cfg->card_config->busWidth);
1709
1710 return _cyhal_sdhc_init_common_hw(obj, cfg);
1711 }
1712
cyhal_sdhc_free(cyhal_sdhc_t * obj)1713 void cyhal_sdhc_free(cyhal_sdhc_t *obj)
1714 {
1715 CY_ASSERT(NULL != obj);
1716
1717 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1718
1719 if (NULL != sdxx->base)
1720 {
1721 _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
1722 _cyhal_irq_free(irqn);
1723 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
1724 if (_CYHAL_SDXX_SEMA_NOT_INITED != _cyhal_sdxx_semaphore_status[sdxx->resource.block_num])
1725 {
1726 cy_rtos_deinit_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[sdxx->resource.block_num]));
1727 _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_NOT_INITED;
1728 }
1729 #endif /* CY_RTOS_AWARE or COMPONENT_RTOS_AWARE defined */
1730
1731 Cy_SD_Host_DeInit(sdxx->base);
1732 _cyhal_sdxx_config_structs[sdxx->resource.block_num] = NULL;
1733 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
1734
1735 if (!sdxx->dc_configured)
1736 {
1737 cyhal_hwmgr_free(&(sdxx->resource));
1738 }
1739 sdxx->base = NULL;
1740
1741 #if CYHAL_DRIVER_AVAILABLE_SYSPM
1742 _cyhal_syspm_unregister_peripheral_callback(&(sdxx->pm_callback_data));
1743 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1744 }
1745
1746 if (sdxx->resource.type != CYHAL_RSC_INVALID)
1747 {
1748 sdxx->resource.type = CYHAL_RSC_INVALID;
1749 }
1750
1751 if (sdxx->clock_owned)
1752 {
1753 cyhal_clock_free(&(sdxx->clock));
1754 sdxx->clock_owned = false;
1755 }
1756
1757 if (!sdxx->dc_configured)
1758 {
1759 /* Free pins */
1760 _cyhal_utils_release_if_used(&(sdxx->pin_cmd));
1761 _cyhal_utils_release_if_used(&(sdxx->pin_clk));
1762 #if _CYHAL_SDHC_DATA8_PRESENT
1763 const uint8_t max_idx = 8;
1764 #else
1765 const uint8_t max_idx = 4;
1766 #endif
1767 for (uint8_t i = 0; i < max_idx; i++)
1768 {
1769 _cyhal_utils_release_if_used(&(obj->pin_data[i]));
1770 }
1771 }
1772
1773 #if _CYHAL_SDHC_CARD_DETECT_PRESENT
1774 if ((obj->cd_gpio_cb_enabled) && (CYHAL_NC_PIN_VALUE != obj->pin_card_detect))
1775 {
1776 cyhal_gpio_enable_event(obj->pin_card_detect, CYHAL_GPIO_IRQ_BOTH, CYHAL_ISR_PRIORITY_DEFAULT, false);
1777 cyhal_gpio_register_callback(obj->pin_card_detect, NULL);
1778 obj->cd_gpio_cb_enabled = false;
1779 }
1780 if (!sdxx->dc_configured)
1781 {
1782 _cyhal_utils_release_if_used(&(obj->pin_card_detect));
1783 }
1784 #endif
1785
1786 if (!sdxx->dc_configured)
1787 {
1788 /* io_vol_sel may have been used with GPIO pin */
1789 _cyhal_utils_release_if_used(&(sdxx->pin_io_vol_sel));
1790
1791 #if _CYHAL_SDHC_CARD_IF_PWR_EN_PRESENT
1792 _cyhal_utils_release_if_used(&(obj->pin_card_pwr_en));
1793 #endif
1794
1795 #if _CYHAL_SDHC_CARD_WRITE_PROT_PRESENT
1796 _cyhal_utils_release_if_used(&(obj->pin_card_mech_write_prot));
1797 #endif
1798
1799 #if _CYHAL_SDHC_LED_CTRL_PRESENT
1800 _cyhal_utils_release_if_used(&(obj->pin_led_ctrl));
1801 #endif
1802
1803 #if _CYHAL_SDHC_CARD_EMMC_RESET_PRESENT
1804 _cyhal_utils_release_if_used(&(obj->pin_emmc_reset));
1805 #endif
1806 }
1807 }
1808
cyhal_sdhc_read(cyhal_sdhc_t * obj,uint32_t address,uint8_t * data,size_t * length)1809 cy_rslt_t cyhal_sdhc_read(cyhal_sdhc_t *obj, uint32_t address, uint8_t *data, size_t *length)
1810 {
1811 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1812 CY_ASSERT(_CYHAL_SDXX_NOT_RUNNING == sdxx->data_transfer_status);
1813 _cyhal_sdxx_setup_smphr(sdxx);
1814 cy_rslt_t ret = cyhal_sdhc_read_async(obj, address, data, length);
1815 /* Waiting for async operation to end */
1816 if (CY_RSLT_SUCCESS == ret)
1817 {
1818 ret = _cyhal_sdxx_waitfor_transfer_complete(sdxx);
1819 }
1820 if(CY_RSLT_SUCCESS != ret)
1821 {
1822 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
1823 }
1824 return ret;
1825 }
1826
cyhal_sdhc_write(cyhal_sdhc_t * obj,uint32_t address,const uint8_t * data,size_t * length)1827 cy_rslt_t cyhal_sdhc_write(cyhal_sdhc_t *obj, uint32_t address, const uint8_t *data, size_t *length)
1828 {
1829 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1830 CY_ASSERT(_CYHAL_SDXX_NOT_RUNNING == sdxx->data_transfer_status);
1831 _cyhal_sdxx_setup_smphr(sdxx);
1832 cy_rslt_t ret = cyhal_sdhc_write_async(obj, address, data, length);
1833 /* Waiting for async operation to end */
1834 if (CY_RSLT_SUCCESS == ret)
1835 {
1836 ret = _cyhal_sdxx_waitfor_transfer_complete(sdxx);
1837 }
1838 if(CY_RSLT_SUCCESS != ret)
1839 {
1840 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
1841 }
1842 return ret;
1843 }
1844
cyhal_sdhc_erase(cyhal_sdhc_t * obj,uint32_t start_addr,size_t length,uint32_t timeout_ms)1845 cy_rslt_t cyhal_sdhc_erase(cyhal_sdhc_t *obj, uint32_t start_addr, size_t length, uint32_t timeout_ms)
1846 {
1847 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1848
1849 if (timeout_ms == 0)
1850 {
1851 timeout_ms = sdxx->emmc ? _CYHAL_SDHC_EMMC_TRIM_DELAY_MS : _CYHAL_SDHC_RETRY_TIMES;
1852 }
1853 #if CYHAL_DRIVER_AVAILABLE_SYSPM
1854 if (sdxx->pm_transition_pending)
1855 {
1856 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1857 }
1858 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1859 if (0 == length)
1860 {
1861 return CYHAL_SDHC_RSLT_ERR_WRONG_PARAM;
1862 }
1863
1864 cy_rslt_t ret = CY_RSLT_SUCCESS;
1865 cy_en_sd_host_erase_type_t eraseType = CY_SD_HOST_ERASE_ERASE;
1866 uint32_t cardStatus;
1867
1868 if (sdxx->emmc)
1869 {
1870 eraseType = CY_SD_HOST_ERASE_TRIM;
1871 }
1872
1873 /* First clear out the transfer and command complete statuses */
1874 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, (CY_SD_HOST_XFER_COMPLETE | CY_SD_HOST_CMD_COMPLETE));
1875
1876 if (sdxx->irq_cause & CYHAL_SDHC_CMD_COMPLETE)
1877 {
1878 /* Enabling command complete interrupt mask if corresponding event was enabled by user
1879 * _cyhal_sdhc_irq_handler will disable CY_SD_HOST_CMD_COMPLETE mask once interrupt
1880 * is generated. */
1881 Cy_SD_Host_SetNormalInterruptMask(sdxx->base, Cy_SD_Host_GetNormalInterruptMask(sdxx->base) |
1882 CY_SD_HOST_CMD_COMPLETE);
1883 }
1884
1885 ret = (cy_rslt_t)Cy_SD_Host_Erase(sdxx->base, start_addr, (start_addr + length - 1), eraseType, &(sdxx->context));
1886
1887 if (CY_RSLT_SUCCESS == ret)
1888 {
1889 uint32_t time_used_ms;
1890 ret = (cy_rslt_t)_cyhal_sdxx_pollcmdcomplete(sdxx, &time_used_ms);
1891 timeout_ms = timeout_ms - time_used_ms;
1892 }
1893 if (CY_RSLT_SUCCESS == ret)
1894 {
1895 if (false == sdxx->emmc)
1896 {
1897 /* polling result */
1898 ret = CYHAL_SDHC_RSLT_ERR_ERASE_CMPLT_TIMEOUT;
1899 while(timeout_ms > 0)
1900 {
1901 cardStatus = Cy_SD_Host_GetCardStatus(sdxx->base, &(sdxx->context));
1902 if (((CY_SD_HOST_CARD_TRAN << CY_SD_HOST_CMD13_CURRENT_STATE) |
1903 (1UL << CY_SD_HOST_CMD13_READY_FOR_DATA)) == cardStatus)
1904 {
1905 ret = CY_RSLT_SUCCESS;
1906 break;
1907 }
1908 cyhal_system_delay_us(_CYHAL_SDHC_FUJE_TIMEOUT_MS); /* The Fuje timeout for one block. */
1909 timeout_ms--;
1910 }
1911 }
1912 else
1913 {
1914 cyhal_system_delay_ms(timeout_ms);
1915 }
1916 }
1917
1918 return ret;
1919 }
1920
cyhal_sdhc_read_async(cyhal_sdhc_t * obj,uint32_t address,uint8_t * data,size_t * length)1921 cy_rslt_t cyhal_sdhc_read_async(cyhal_sdhc_t *obj, uint32_t address, uint8_t *data, size_t *length)
1922 {
1923 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1924
1925 #if CYHAL_DRIVER_AVAILABLE_SYSPM
1926 if (sdxx->pm_transition_pending)
1927 {
1928 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1929 }
1930 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1931
1932 cy_rslt_t ret;
1933 cy_stc_sd_host_write_read_config_t dataConfig;
1934
1935 /* The pointer to data. */
1936 dataConfig.data = (uint32_t*)data;
1937 /* The address to write/read data on the card or eMMC. */
1938 dataConfig.address = address;
1939 /* The number of blocks to write/read. */
1940 dataConfig.numberOfBlocks = (uint32_t)*length;
1941 dataConfig.autoCommand = (1UL == (uint32_t)*length)
1942 ? CY_SD_HOST_AUTO_CMD_NONE
1943 : CY_SD_HOST_AUTO_CMD_AUTO;
1944 /* The timeout value for the transfer. */
1945 dataConfig.dataTimeout = obj->data_timeout_tout;
1946 /* For EMMC cards enable reliable write. */
1947 dataConfig.enReliableWrite = false;
1948 dataConfig.enableDma = true;
1949
1950 /* First clear out the transfer and command complete statuses */
1951 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, (CY_SD_HOST_XFER_COMPLETE | CY_SD_HOST_CMD_COMPLETE));
1952
1953 ret = _cyhal_sdxx_prepare_for_transfer(sdxx);
1954
1955 if (CY_RSLT_SUCCESS == ret)
1956 {
1957 // The PDL takes care of the cmd complete stage in sdhc mode so we can jump straight
1958 // to waiting for the xfer complete
1959 sdxx->data_transfer_status = _CYHAL_SDXX_WAIT_XFER_COMPLETE;
1960 ret = (cy_rslt_t)Cy_SD_Host_Read(sdxx->base, &dataConfig, &(sdxx->context));
1961 /* Read operation failed */
1962 if (CY_RSLT_SUCCESS != ret)
1963 {
1964 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
1965 }
1966 }
1967
1968 return ret;
1969 }
1970
cyhal_sdhc_write_async(cyhal_sdhc_t * obj,uint32_t address,const uint8_t * data,size_t * length)1971 cy_rslt_t cyhal_sdhc_write_async(cyhal_sdhc_t *obj, uint32_t address, const uint8_t *data, size_t *length)
1972 {
1973 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
1974
1975 #if CYHAL_DRIVER_AVAILABLE_SYSPM
1976 if (sdxx->pm_transition_pending)
1977 {
1978 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1979 }
1980 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1981
1982 cy_rslt_t ret;
1983 cy_stc_sd_host_write_read_config_t dataConfig;
1984
1985 /* The pointer to data. */
1986 dataConfig.data = (uint32_t*)data;
1987 /* The address to write/read data on the card or eMMC. */
1988 dataConfig.address = address;
1989 /* The number of blocks to write/read. */
1990 dataConfig.numberOfBlocks = (uint32_t)*length;
1991 dataConfig.autoCommand = (1UL == (uint32_t)*length)
1992 ? CY_SD_HOST_AUTO_CMD_NONE
1993 : CY_SD_HOST_AUTO_CMD_AUTO;
1994 /* The timeout value for the transfer. */
1995 dataConfig.dataTimeout = obj->data_timeout_tout;
1996 /* For EMMC cards enable reliable write. */
1997 dataConfig.enReliableWrite = false;
1998 dataConfig.enableDma = true;
1999
2000 /* First clear out the transfer and command complete statuses */
2001 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, (CY_SD_HOST_XFER_COMPLETE | CY_SD_HOST_CMD_COMPLETE));
2002
2003 ret = _cyhal_sdxx_prepare_for_transfer(sdxx);
2004
2005 if (CY_RSLT_SUCCESS == ret)
2006 {
2007 // The PDL takes care of the cmd complete stage in sdhc mode so we can jump straight
2008 // to waiting for the xfer complete
2009 sdxx->data_transfer_status = _CYHAL_SDXX_WAIT_XFER_COMPLETE;
2010 ret = (cy_rslt_t)Cy_SD_Host_Write(sdxx->base, &dataConfig, &(sdxx->context));
2011 /* Write operation failed */
2012 if (CY_RSLT_SUCCESS != ret)
2013 {
2014 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
2015 }
2016 }
2017
2018 return ret;
2019 }
2020
cyhal_sdhc_is_busy(const cyhal_sdhc_t * obj)2021 bool cyhal_sdhc_is_busy(const cyhal_sdhc_t *obj)
2022 {
2023 CY_ASSERT(NULL != obj);
2024 return _cyhal_sdhc_is_busy(&(obj->sdxx));
2025 }
2026
cyhal_sdhc_abort_async(cyhal_sdhc_t * obj)2027 cy_rslt_t cyhal_sdhc_abort_async(cyhal_sdhc_t *obj)
2028 {
2029 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2030 cy_rslt_t ret = (cy_rslt_t)Cy_SD_Host_AbortTransfer(sdxx->base, &(sdxx->context));
2031 if (CY_RSLT_SUCCESS == ret)
2032 {
2033 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
2034 }
2035 return ret;
2036 }
2037
cyhal_sdhc_register_callback(cyhal_sdhc_t * obj,cyhal_sdhc_event_callback_t callback,void * callback_arg)2038 void cyhal_sdhc_register_callback(cyhal_sdhc_t *obj, cyhal_sdhc_event_callback_t callback, void *callback_arg)
2039 {
2040 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2041 uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
2042 sdxx->callback_data.callback = (cy_israddress) callback;
2043 sdxx->callback_data.callback_arg = callback_arg;
2044 cyhal_system_critical_section_exit(savedIntrStatus);
2045 }
2046
cyhal_sdhc_enable_event(cyhal_sdhc_t * obj,cyhal_sdhc_event_t event,uint8_t intr_priority,bool enable)2047 void cyhal_sdhc_enable_event(cyhal_sdhc_t *obj, cyhal_sdhc_event_t event, uint8_t intr_priority, bool enable)
2048 {
2049 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2050
2051 uint32_t interruptMask = Cy_SD_Host_GetNormalInterruptMask(sdxx->base);
2052
2053 _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
2054 _cyhal_irq_set_priority(irqn, intr_priority);
2055 uint32_t map_count = sizeof(_cyhal_sdhc_event_map) / sizeof(uint32_t);
2056
2057 /* Specific interrupt */
2058 if ((uint32_t) event < (uint32_t) CYHAL_SDHC_ALL_INTERRUPTS)
2059 {
2060 for (uint8_t i = 1; i < map_count; i++)
2061 {
2062 if ((_cyhal_sdhc_event_map[i] & (uint32_t) event) != 0)
2063 {
2064 if (enable)
2065 interruptMask |= ((uint32_t)1 << (i - 1));
2066 else
2067 interruptMask &= ~((uint32_t)1 << (i - 1));
2068 }
2069 }
2070 }
2071 /* All interrupts */
2072 else
2073 {
2074 interruptMask = (enable) ? CYHAL_SDHC_ALL_INTERRUPTS : 0;
2075 }
2076
2077 sdxx->irq_cause = interruptMask;
2078 /* CY_SD_HOST_CMD_COMPLETE and CY_SD_HOST_XFER_COMPLETE cannot be always enabled because of SD Host driver limitations.
2079 * SDHC HAL transfer APIs are taking care of enabling these statuses. CY_SD_HOST_CMD_COMPLETE is only
2080 * enabled if user callback is enabled while CY_SD_HOST_XFER_COMPLETE is enabled by transfer API regardless it was enabled
2081 * by user or not. */
2082 interruptMask &= ((uint32_t) ~CY_SD_HOST_CMD_COMPLETE) & ((uint32_t) ~CY_SD_HOST_XFER_COMPLETE);
2083 Cy_SD_Host_SetNormalInterruptMask(sdxx->base, interruptMask);
2084 }
2085
cyhal_sdhc_is_card_inserted(const cyhal_sdhc_t * obj)2086 bool cyhal_sdhc_is_card_inserted(const cyhal_sdhc_t *obj)
2087 {
2088 CY_ASSERT(NULL != obj);
2089 CY_ASSERT(NULL != obj->sdxx.base);
2090 return Cy_SD_Host_IsCardConnected(obj->sdxx.base);
2091 }
2092
cyhal_sdhc_is_card_mech_write_protected(const cyhal_sdhc_t * obj)2093 bool cyhal_sdhc_is_card_mech_write_protected(const cyhal_sdhc_t *obj)
2094 {
2095 CY_ASSERT(NULL != obj);
2096 CY_ASSERT(NULL != obj->sdxx.base);
2097 return Cy_SD_Host_IsWpSet(obj->sdxx.base);
2098 }
2099
cyhal_sdhc_get_block_count(cyhal_sdhc_t * obj,uint32_t * block_count)2100 cy_rslt_t cyhal_sdhc_get_block_count(cyhal_sdhc_t *obj, uint32_t * block_count)
2101 {
2102 CY_ASSERT(NULL != obj);
2103
2104 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2105 cy_rslt_t result = CYHAL_SDHC_RSLT_ERR_BLOCK_COUNT_GET_FAILURE;
2106
2107 if (CY_SD_HOST_SUCCESS == Cy_SD_Host_GetBlockCount(sdxx->base, block_count, &(sdxx->context)))
2108 {
2109 result = CY_RSLT_SUCCESS;
2110 }
2111
2112 return result;
2113 }
2114
cyhal_sdhc_set_frequency(cyhal_sdhc_t * obj,uint32_t hz,bool negotiate)2115 cy_rslt_t cyhal_sdhc_set_frequency(cyhal_sdhc_t *obj, uint32_t hz, bool negotiate)
2116 {
2117 CY_ASSERT(NULL != obj);
2118 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2119
2120 cy_rslt_t result = CYHAL_SDHC_RSLT_ERR_SET_FREQ;
2121 if (NULL != sdxx->base)
2122 {
2123 if ((sdxx->emmc) && (_CYHAL_SDHC_EMMC_MAX_SUP_FREQ_HZ < hz))
2124 {
2125 /* Maximal supported frequency for eMMC for current implementation is exceeded */
2126 return CYHAL_SDHC_RSLT_ERR_UNSUPPORTED;
2127 }
2128
2129 /* Assigning for desired freq as for now and this variable
2130 * will be updated with achieved freq. */
2131 uint32_t actual_freq = hz;
2132 result = _cyhal_sdxx_sdcardchangeclock(sdxx, &actual_freq, sdxx->low_voltage_io_set, negotiate);
2133 if (CY_RSLT_SUCCESS == result)
2134 {
2135 obj->bus_frequency_hz = actual_freq;
2136 if (obj->data_timeout_auto_reconfig && (0 != obj->data_timeout_card_clocks_user))
2137 {
2138 /* User have data timeout configured, we need to reconfigure it according to new card clock */
2139 result = cyhal_sdhc_set_data_read_timeout(obj, obj->data_timeout_card_clocks_user, true);
2140 }
2141 }
2142 }
2143 return result;
2144 }
2145
cyhal_sdhc_get_frequency(cyhal_sdhc_t * obj)2146 uint32_t cyhal_sdhc_get_frequency(cyhal_sdhc_t *obj)
2147 {
2148 CY_ASSERT(NULL != obj);
2149 return obj->bus_frequency_hz;
2150 }
2151
cyhal_sdhc_set_data_read_timeout(cyhal_sdhc_t * obj,uint32_t timeout,bool auto_reconfigure)2152 cy_rslt_t cyhal_sdhc_set_data_read_timeout(cyhal_sdhc_t *obj, uint32_t timeout, bool auto_reconfigure)
2153 {
2154 CY_ASSERT(NULL != obj);
2155
2156 uint32_t current_card_clock = cyhal_sdhc_get_frequency(obj);
2157
2158 /* TMCLK works on 1 MHz in current block implementation if corresponding HF clock is 100 MHz.
2159 * This is defined in registers (TOUT_CLK_FREQ[5:0] = 1 and TOUT_CLK_UNIT[7] = 1). */
2160 float tout_clk_period_us = _CYHAL_SDHC_EXPECTED_BASE_CLK_FREQ_HZ / (float)obj->block_source_freq_hz;
2161
2162 uint32_t user_needs_us = (((uint64_t)timeout * 1000000) + current_card_clock - 1) / current_card_clock;
2163
2164 /* Timeout range from 0x0 to 0xE is valid for CAT1 which corresponds to
2165 * TMCLK x 2^13 for 0, TMCLK x 2^14 for 1, ..., TMCLK x 2^27 for 0xE. 0xF is reserved. */
2166 const uint8_t tout_clk_power_base = _CYHAL_SDHC_TOUT_TMCLK_POW_MIN;
2167 for (uint8_t tmclk_power = tout_clk_power_base; tmclk_power <= _CYHAL_SDHC_TOUT_TMCLK_POW_MAX; tmclk_power++)
2168 {
2169 if (tout_clk_period_us * ((uint32_t)1 << tmclk_power) >= user_needs_us)
2170 {
2171 obj->data_timeout_tout = tmclk_power - tout_clk_power_base;
2172 obj->data_timeout_card_clocks_user = timeout;
2173 obj->data_timeout_auto_reconfig = auto_reconfigure;
2174 return CY_RSLT_SUCCESS;
2175 }
2176 }
2177 return CYHAL_SDHC_RSLT_ERR_TOUT_CFG;
2178 }
2179
cyhal_sdhc_config_data_transfer(cyhal_sdhc_t * obj,cyhal_sdhc_data_config_t * data_config)2180 cy_rslt_t cyhal_sdhc_config_data_transfer(cyhal_sdhc_t *obj, cyhal_sdhc_data_config_t *data_config)
2181 {
2182 CY_ASSERT(NULL != obj);
2183 CY_ASSERT(NULL != data_config);
2184
2185 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2186 CY_ASSERT(NULL != sdxx->base);
2187
2188 if (NULL == data_config->data_ptr)
2189 {
2190 return CYHAL_SDHC_RSLT_ERR_WRONG_PARAM;
2191 }
2192
2193 cy_stc_sd_host_data_config_t dataConfig = {
2194 .blockSize = data_config->block_size,
2195 .numberOfBlock = data_config->number_of_blocks,
2196 .enableDma = true,
2197 .autoCommand = (cy_en_sd_host_auto_cmd_t)data_config->auto_command,
2198 .read = data_config->is_read,
2199 /* .data is skipped to configure adma2 descriptor for it later */
2200 .dataTimeout = obj->data_timeout_tout,
2201 .enableIntAtBlockGap = false,
2202 .enReliableWrite = false
2203 };
2204
2205 uint32_t length = data_config->block_size * data_config->number_of_blocks;
2206
2207 sdxx->adma_descriptor_tbl[0] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | /* Attr Valid */
2208 (1UL << CY_SD_HOST_ADMA_ATTR_END_POS) | /* Attr End */
2209 (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) | /* Attr Int */
2210 (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |
2211 (length << CY_SD_HOST_ADMA_LEN_POS); /* Len */
2212
2213 sdxx->adma_descriptor_tbl[1] = (uint32_t)data_config->data_ptr;
2214
2215 /* The address of the ADMA descriptor table. */
2216 dataConfig.data = (uint32_t*)&sdxx->adma_descriptor_tbl[0];
2217
2218 return (cy_rslt_t) Cy_SD_Host_InitDataTransfer(sdxx->base, &dataConfig);
2219 }
2220
cyhal_sdhc_send_cmd(cyhal_sdhc_t * obj,cyhal_sdhc_cmd_config_t * cmd_config)2221 cy_rslt_t cyhal_sdhc_send_cmd(cyhal_sdhc_t *obj, cyhal_sdhc_cmd_config_t *cmd_config)
2222 {
2223 CY_ASSERT(NULL != obj);
2224 CY_ASSERT(NULL != cmd_config);
2225
2226 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2227 CY_ASSERT(NULL != sdxx->base);
2228
2229 cy_rslt_t result = CY_RSLT_SUCCESS;
2230 bool cmd_data_present = (NULL != cmd_config->data_config);
2231
2232 cy_stc_sd_host_cmd_config_t cmd = {
2233 .commandIndex = cmd_config->command_index,
2234 .commandArgument = cmd_config->command_argument,
2235 .enableCrcCheck = cmd_config->enable_crc_check,
2236 .enableAutoResponseErrorCheck = false,
2237 .respType = (cy_en_sd_host_response_type_t)cmd_config->response_type,
2238 .enableIdxCheck = cmd_config->enable_idx_check,
2239 .dataPresent = cmd_data_present,
2240 .cmdType = (cy_en_sd_host_cmd_type_t)cmd_config->command_type
2241 };
2242
2243 /* First clear out the transfer and command complete statuses */
2244 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, (CY_SD_HOST_XFER_COMPLETE | CY_SD_HOST_CMD_COMPLETE));
2245
2246 if (cmd_data_present)
2247 {
2248 result = _cyhal_sdxx_prepare_for_transfer(sdxx);
2249 }
2250
2251 if (CY_RSLT_SUCCESS == result)
2252 {
2253 if (cmd_data_present)
2254 {
2255 /* Data will be transfered in scope of this command, so setting _CYHAL_SDXX_WAIT_BOTH (cmd and data)
2256 * and setting up xfer complete semaphore */
2257 sdxx->data_transfer_status = _CYHAL_SDXX_WAIT_BOTH;
2258 _cyhal_sdxx_setup_smphr(sdxx);
2259 }
2260 else
2261 {
2262 /* No data is transfered in this command, just waiting for cmd to complete */
2263 sdxx->data_transfer_status = _CYHAL_SDXX_WAIT_CMD_COMPLETE;
2264 }
2265 result = (cy_rslt_t)Cy_SD_Host_SendCommand(sdxx->base, &cmd);
2266 }
2267
2268 if (CY_RSLT_SUCCESS == result)
2269 {
2270 result = (cy_rslt_t)_cyhal_sdxx_pollcmdcomplete(sdxx, NULL);
2271 }
2272
2273 if (CY_RSLT_SUCCESS != result)
2274 {
2275 /* Transfer failed */
2276 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
2277 }
2278
2279 return result;
2280 }
2281
cyhal_sdhc_get_response(cyhal_sdhc_t * obj,uint32_t * response,bool large_response)2282 cy_rslt_t cyhal_sdhc_get_response(cyhal_sdhc_t *obj, uint32_t *response, bool large_response)
2283 {
2284 CY_ASSERT(NULL != obj);
2285 CY_ASSERT(NULL != obj->sdxx.base);
2286 CY_ASSERT(NULL != response);
2287 return (cy_rslt_t)Cy_SD_Host_GetResponse(obj->sdxx.base, response, large_response);
2288 }
2289
cyhal_sdhc_wait_transfer_complete(cyhal_sdhc_t * obj)2290 cy_rslt_t cyhal_sdhc_wait_transfer_complete(cyhal_sdhc_t *obj)
2291 {
2292 CY_ASSERT(NULL != obj);
2293 CY_ASSERT(NULL != obj->sdxx.base);
2294 return _cyhal_sdxx_waitfor_transfer_complete(&(obj->sdxx));
2295 }
2296
_cyhal_sdxx_io_volt_switch_seq(SDHC_Type * base)2297 static cy_rslt_t _cyhal_sdxx_io_volt_switch_seq(SDHC_Type *base)
2298 {
2299 CY_ASSERT(NULL != base);
2300
2301 uint32_t p_state;
2302 cy_rslt_t result = CY_RSLT_SUCCESS;
2303
2304 /* Disable providing the SD Clock. */
2305 Cy_SD_Host_DisableSdClk(base);
2306
2307 p_state = Cy_SD_Host_GetPresentState(base) & SDHC_CORE_PSTATE_REG_DAT_3_0_Msk;
2308
2309 /* Check DAT[3:0]. */
2310 if (0UL == p_state)
2311 {
2312 /* Switch the bus to 1.8 V (Set the IO_VOLT_SEL pin to low)*/
2313 Cy_SD_Host_ChangeIoVoltage(base, CY_SD_HOST_IO_VOLT_1_8V);
2314
2315 /* Wait 10 ms to 1.8 voltage regulator to be stable. */
2316 cyhal_system_delay_ms(_CYHAL_SDHC_1_8_REG_STABLE_TIME_MS);
2317
2318 /* Check the 1.8V signaling enable. */
2319 if (true == _FLD2BOOL(SDHC_CORE_HOST_CTRL2_R_SIGNALING_EN,
2320 SDHC_CORE_HOST_CTRL2_R(base)))
2321 {
2322 /* Enable providing the SD Clock. */
2323 Cy_SD_Host_EnableSdClk(base);
2324
2325 /* Wait for the stable CLK */
2326 cyhal_system_delay_ms(CY_SD_HOST_CLK_RAMP_UP_TIME_MS);
2327
2328 p_state = Cy_SD_Host_GetPresentState(base) & SDHC_CORE_PSTATE_REG_DAT_3_0_Msk;
2329
2330 /* Check DAT[3:0]. */
2331 if (SDHC_CORE_PSTATE_REG_DAT_3_0_Msk != p_state)
2332 {
2333 result = (cy_rslt_t)CY_SD_HOST_ERROR;
2334 }
2335 }
2336 else
2337 {
2338 result = (cy_rslt_t)CY_SD_HOST_ERROR;
2339 }
2340 }
2341 else
2342 {
2343 result = (cy_rslt_t)CY_SD_HOST_ERROR;
2344 }
2345
2346 return result;
2347 }
2348
2349 /* Ncc - is time, needed to wait after certain commands before issuing next cmd.
2350 * Ncc is 8 clock cycles which for 400 kHz is 20 us */
_cyhal_sdhc_wait_ncc_time_at_400khz(void)2351 static inline void _cyhal_sdhc_wait_ncc_time_at_400khz(void)
2352 {
2353 cyhal_system_delay_us(20);
2354 }
2355
_cyhal_sdhc_io_volt_negotiate(cyhal_sdhc_t * obj,cyhal_sdhc_io_voltage_t io_voltage)2356 static cy_rslt_t _cyhal_sdhc_io_volt_negotiate(cyhal_sdhc_t *obj, cyhal_sdhc_io_voltage_t io_voltage)
2357 {
2358 /* GO_IDLE (CMD0) command is issued in scope of Cy_SD_Host_SelBusVoltage, which resets
2359 * SD bus to 1 bit bus width and 400 khz on the SD card side. Preparing host side for that. */
2360
2361 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2362
2363 /* 1 bit data bus width */
2364 cy_rslt_t result = cyhal_sdhc_set_bus_width(obj, 1, true);
2365
2366 if (CY_RSLT_SUCCESS == result)
2367 {
2368 /* 400 khz sd bus clock */
2369 result = cyhal_sdhc_set_frequency(obj, 400000, false);
2370 }
2371
2372 if (CY_RSLT_SUCCESS == result)
2373 {
2374 bool voltage_1v8 = (io_voltage == CYHAL_SDHC_IO_VOLTAGE_1_8V);
2375 result = (cy_rslt_t)Cy_SD_Host_SelBusVoltage(sdxx->base, voltage_1v8, &(sdxx->context));
2376 /* Card is expected to be in "ready" state now */
2377 }
2378
2379 if (CY_RSLT_SUCCESS == result)
2380 {
2381 /* GetCid (CMD2) will switch card from "ready" state to "ident" */
2382 uint32_t cid_reg[4]; /* The Device Identification register. */
2383 result = (cy_rslt_t)Cy_SD_Host_GetCid(sdxx->base, cid_reg);
2384 _cyhal_sdhc_wait_ncc_time_at_400khz();
2385 }
2386
2387 if (CY_RSLT_SUCCESS == result)
2388 {
2389 /* Cy_SD_Host_GetRca (CMD3) will switch card from "ident" state to "stand-by" state */
2390 sdxx->context.RCA = Cy_SD_Host_GetRca(sdxx->base);
2391 _cyhal_sdhc_wait_ncc_time_at_400khz();
2392
2393 /* CMD7 will switch card from "stand-by" state to "transfer" state */
2394 cyhal_sdhc_cmd_config_t cmd = {
2395 .command_index = 7,
2396 .command_argument = sdxx->context.RCA << _CYHAL_SDHC_RCA_SHIFT,
2397 .enable_crc_check = false,
2398 .response_type = CYHAL_SDHC_RESPONSE_LEN_48B,
2399 .enable_idx_check = false,
2400 .command_type = CYHAL_SDHC_CMD_NORMAL,
2401 .data_config = NULL
2402 };
2403
2404 result = cyhal_sdhc_send_cmd(obj, &cmd);
2405 }
2406
2407 if (CY_RSLT_SUCCESS == result)
2408 {
2409 _cyhal_sdhc_wait_ncc_time_at_400khz();
2410 result = _cyhal_sdxx_waitfor_transfer_complete(sdxx);
2411 }
2412
2413 return result;
2414 }
2415
2416 typedef struct
2417 {
2418 en_hsiom_sel_t clk;
2419 en_hsiom_sel_t cmd;
2420 #if _CYHAL_SDHC_DATA8_PRESENT
2421 en_hsiom_sel_t data[8];
2422 #else
2423 en_hsiom_sel_t data[4];
2424 #endif
2425 } _cyhal_sdhc_saved_lines_hsiom_t;
2426
2427 /* power cycle config single pin */
_cyhal_sdhc_pc_config_single_pin(cyhal_gpio_t * gpio_ptr,en_hsiom_sel_t * hsiom_ptr,bool set_line_low)2428 static void _cyhal_sdhc_pc_config_single_pin(cyhal_gpio_t *gpio_ptr, en_hsiom_sel_t *hsiom_ptr, bool set_line_low)
2429 {
2430 GPIO_PRT_Type* port;
2431 uint8_t pin;
2432
2433 cyhal_gpio_t gpio = *gpio_ptr;
2434 if (NC != gpio)
2435 {
2436 port = CYHAL_GET_PORTADDR(gpio);
2437 pin = (uint8_t)CYHAL_GET_PIN(gpio);
2438 if(set_line_low)
2439 {
2440 /* Switching HSIOM to GPIO and set pin to low state */
2441 *hsiom_ptr = Cy_GPIO_GetHSIOM(port, pin);
2442 Cy_GPIO_Clr(port, pin);
2443 Cy_GPIO_SetHSIOM(port, pin, HSIOM_SEL_GPIO);
2444 }
2445 else
2446 {
2447 /* Restore pin's HSIOM configuration for SDHC block signals */
2448 Cy_GPIO_SetHSIOM(port, pin, *hsiom_ptr);
2449 }
2450 }
2451 }
2452
2453 /* Per SD Spec, during card power down, DAT, CMD and CLK lines should be disconnected or driven to logical 0
2454 * by the host to avoid operating current being drawn through the signal lines.
2455 * Lines are set low if set_lines_low true, pins configuration resored if set_lines_low false */
_cyhal_sdhc_power_cycle_config_lines(cyhal_sdhc_t * obj,_cyhal_sdhc_saved_lines_hsiom_t * pins_cfg,bool set_lines_low)2456 static void _cyhal_sdhc_power_cycle_config_lines(cyhal_sdhc_t *obj, _cyhal_sdhc_saved_lines_hsiom_t *pins_cfg,
2457 bool set_lines_low)
2458 {
2459 _cyhal_sdhc_pc_config_single_pin(&(obj->sdxx.pin_clk), &pins_cfg->clk, set_lines_low);
2460 _cyhal_sdhc_pc_config_single_pin(&(obj->sdxx.pin_cmd), &pins_cfg->cmd, set_lines_low);
2461 for(size_t i = 0; i < sizeof(pins_cfg->data)/sizeof(pins_cfg->data[0]); ++i)
2462 {
2463 _cyhal_sdhc_pc_config_single_pin(&(obj->pin_data[i]), &(pins_cfg->data[i]), set_lines_low);
2464 }
2465 }
2466
_cyhal_sdhc_card_power_cycle(cyhal_sdhc_t * obj)2467 static cy_rslt_t _cyhal_sdhc_card_power_cycle(cyhal_sdhc_t *obj)
2468 {
2469 /* To perform reliable SD card hard reset, Card VDD should drop to below 0.5V for at least 1 ms */
2470 if (NC == obj->pin_card_pwr_en)
2471 {
2472 /* card_pwr_en needs to be provided in order to control card VDD */
2473 return CYHAL_SDHC_RSLT_ERR_PIN;
2474 }
2475
2476 _cyhal_sdhc_saved_lines_hsiom_t pins_cfg;
2477
2478 /* Drive signal lines logic 0 to avoid card being powered through signal lines */
2479 _cyhal_sdhc_power_cycle_config_lines(obj, &pins_cfg, true);
2480 /* Power down the card */
2481 cyhal_sdhc_enable_card_power(obj, false);
2482 /* Waiting for 1 ms per spec */
2483 cyhal_system_delay_us(1000);
2484 /* Restore signals configuration */
2485 _cyhal_sdhc_power_cycle_config_lines(obj, &pins_cfg, false);
2486 /* Power up the card */
2487 cyhal_sdhc_enable_card_power(obj, true);
2488 cyhal_system_delay_ms(_CYHAL_SDHC_PWR_RAMP_UP_TIME_MS);
2489
2490 return CY_RSLT_SUCCESS;
2491 }
2492
_cyhal_sdxx_set_io_voltage(_cyhal_sdxx_t * sdxx,cyhal_sdxx_io_voltage_t io_voltage,_cyhal_sdxx_io_switch_action_t io_switch_type)2493 static cy_rslt_t _cyhal_sdxx_set_io_voltage(_cyhal_sdxx_t *sdxx, cyhal_sdxx_io_voltage_t io_voltage,
2494 _cyhal_sdxx_io_switch_action_t io_switch_type)
2495 {
2496 CY_ASSERT(NULL != sdxx);
2497 CY_ASSERT(NULL != sdxx->base);
2498
2499 if ((!sdxx->is_sdio && CY_SD_HOST_SD != sdxx->context.cardType) &&
2500 (_CYHAL_SDXX_IO_VOLT_ACTION_NONE != io_switch_type))
2501 {
2502 /* For SDHC, Negotiation or Voltage switch is not supported when eMMC used */
2503 return CYHAL_SDHC_RSLT_ERR_UNSUPPORTED;
2504 }
2505 if (sdxx->is_sdio && (_CYHAL_SDXX_IO_VOLT_ACTION_NEGOTIATE == io_switch_type))
2506 {
2507 /* For SDIO, Negotiation is not supported */
2508 return CYHAL_SDIO_RSLT_ERR_UNSUPPORTED;
2509 }
2510
2511 cy_rslt_t result = CY_RSLT_SUCCESS;
2512
2513 switch (io_switch_type)
2514 {
2515 /* Not supported by current SDIO HAL implementation */
2516 case _CYHAL_SDXX_IO_VOLT_ACTION_NEGOTIATE:
2517 {
2518 cyhal_sdhc_t *sdhc_obj = (cyhal_sdhc_t *) sdxx->obj;
2519
2520 /* Bus width and card frequency settings are initialized to default during negotiation.
2521 * Saving the parameters to restore them after I/O switch is done. */
2522 uint8_t sd_bus_width_before_switch = cyhal_sdhc_get_bus_width(sdhc_obj);
2523 uint32_t sd_freq_before_switch = cyhal_sdhc_get_frequency(sdhc_obj);
2524
2525 /* Once the card enters 1.8V signaling mode, it cannot be switched back to 3.3V signaling without power cycle. */
2526 if ((sdxx->low_voltage_io_set) && (_CYHAL_SDXX_IO_VOLTAGE_3_3V == io_voltage))
2527 {
2528 result = _cyhal_sdhc_card_power_cycle(sdhc_obj);
2529 if (CY_RSLT_SUCCESS == result)
2530 {
2531 sdhc_obj->low_voltage_io_desired = false;
2532 result = cyhal_sdhc_init_card(sdhc_obj);
2533 }
2534 }
2535 else
2536 {
2537 result = _cyhal_sdhc_io_volt_negotiate(sdhc_obj, (cyhal_sdhc_io_voltage_t)io_voltage);
2538 }
2539
2540 /* Return back bus width and frequency regardless of volt select change status */
2541 (void)cyhal_sdhc_set_bus_width(sdhc_obj, sd_bus_width_before_switch, true);
2542 (void)cyhal_sdhc_set_frequency(sdhc_obj, sd_freq_before_switch, true);
2543 break;
2544 }
2545
2546 case _CYHAL_SDXX_IO_VOLT_ACTION_SWITCH_SEQ_ONLY:
2547 if (_CYHAL_SDXX_IO_VOLTAGE_1_8V == io_voltage)
2548 {
2549 result = _cyhal_sdxx_io_volt_switch_seq(sdxx->base);
2550 if (CY_RSLT_SUCCESS != result)
2551 {
2552 result = sdxx->is_sdio ? CYHAL_SDHC_RSLT_ERR_IO_VOLT_SWITCH_SEQ : CYHAL_SDIO_RSLT_ERR_IO_VOLT_SWITCH_SEQ;
2553 }
2554 break;
2555 }
2556 Cy_SD_Host_ChangeIoVoltage(sdxx->base, (cy_en_sd_host_io_voltage_t)io_voltage);
2557 break;
2558
2559 case _CYHAL_SDXX_IO_VOLT_ACTION_NONE:
2560 Cy_SD_Host_ChangeIoVoltage(sdxx->base, (cy_en_sd_host_io_voltage_t)io_voltage);
2561 break;
2562
2563 default:
2564 /* Illegal io_switch_type value provided */
2565 CY_ASSERT(false);
2566 }
2567
2568 return result;
2569 }
2570
cyhal_sdhc_set_io_voltage(cyhal_sdhc_t * obj,cyhal_sdhc_io_voltage_t io_voltage,cyhal_sdhc_io_volt_action_type_t io_switch_type)2571 cy_rslt_t cyhal_sdhc_set_io_voltage(cyhal_sdhc_t *obj, cyhal_sdhc_io_voltage_t io_voltage, cyhal_sdhc_io_volt_action_type_t io_switch_type)
2572 {
2573 CY_ASSERT(NULL != obj);
2574
2575 if (NC == obj->sdxx.pin_io_vol_sel)
2576 {
2577 /* Need to have io_volt_sel pin configured in order to switch io voltage */
2578 return CYHAL_SDHC_RSLT_ERR_PIN;
2579 }
2580
2581 return _cyhal_sdxx_set_io_voltage(&(obj->sdxx), (cyhal_sdxx_io_voltage_t)io_voltage,
2582 (_cyhal_sdxx_io_switch_action_t)io_switch_type);
2583 }
2584
cyhal_sdhc_get_io_voltage(cyhal_sdhc_t * obj)2585 cyhal_sdhc_io_voltage_t cyhal_sdhc_get_io_voltage(cyhal_sdhc_t *obj)
2586 {
2587 CY_ASSERT(NULL != obj);
2588 return obj->sdxx.low_voltage_io_set ? CYHAL_SDHC_IO_VOLTAGE_1_8V : CYHAL_SDHC_IO_VOLTAGE_3_3V;
2589 }
2590
_cyhal_sdhc_is_buswidth_correct(uint8_t sd_data_bits)2591 static inline bool _cyhal_sdhc_is_buswidth_correct(uint8_t sd_data_bits)
2592 {
2593 return ((1 == sd_data_bits) || (4 == sd_data_bits) || (8 == sd_data_bits));
2594 }
2595
cyhal_sdhc_set_bus_width(cyhal_sdhc_t * obj,uint8_t bus_width,bool configure_card)2596 cy_rslt_t cyhal_sdhc_set_bus_width(cyhal_sdhc_t *obj, uint8_t bus_width, bool configure_card)
2597 {
2598 CY_ASSERT(NULL != obj);
2599
2600 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2601 CY_ASSERT(NULL != sdxx->base);
2602
2603 if (!_cyhal_sdhc_is_buswidth_correct(bus_width))
2604 {
2605 return CYHAL_SDHC_RSLT_ERR_WRONG_PARAM;
2606 }
2607
2608 cy_rslt_t result;
2609
2610 if (configure_card)
2611 {
2612 result = (cy_rslt_t)Cy_SD_Host_SetBusWidth(sdxx->base, _cyhal_sdhc_buswidth_hal_to_pdl(bus_width), &(sdxx->context));
2613 if ((CY_RSLT_SUCCESS == result) && (sdxx->emmc))
2614 {
2615 /* GENERIC_CMD6_TIME is maximum timeout for a SWITCH command (CMD6), that is called for eMMC in scope of
2616 * Cy_SD_Host_SetBusWidth */
2617 cyhal_system_delay_ms(obj->emmc_generic_cmd6_time_ms);
2618 }
2619 }
2620 else
2621 {
2622 result = (cy_rslt_t)Cy_SD_Host_SetHostBusWidth(sdxx->base, _cyhal_sdhc_buswidth_hal_to_pdl(bus_width));
2623 }
2624
2625 if (CY_RSLT_SUCCESS == result)
2626 {
2627 obj->bus_width = bus_width;
2628 }
2629
2630 return result;
2631 }
2632
cyhal_sdhc_get_bus_width(cyhal_sdhc_t * obj)2633 uint8_t cyhal_sdhc_get_bus_width(cyhal_sdhc_t *obj)
2634 {
2635 CY_ASSERT(NULL != obj);
2636 return obj->bus_width;
2637 }
2638
cyhal_sdhc_clear_errors(cyhal_sdhc_t * obj)2639 void cyhal_sdhc_clear_errors(cyhal_sdhc_t *obj)
2640 {
2641 CY_ASSERT(NULL != obj);
2642 CY_ASSERT(NULL != obj->sdxx.base);
2643 Cy_SD_Host_ClearErrorInterruptStatus(obj->sdxx.base, _CYHAL_SDHC_ALL_ERR_INTERRUPTS);
2644 }
2645
cyhal_sdhc_get_last_command_errors(cyhal_sdhc_t * obj)2646 cyhal_sdhc_error_type_t cyhal_sdhc_get_last_command_errors(cyhal_sdhc_t *obj)
2647 {
2648 CY_ASSERT(NULL != obj);
2649 CY_ASSERT(NULL != obj->sdxx.base);
2650 return (cyhal_sdhc_error_type_t)Cy_SD_Host_GetErrorInterruptStatus(obj->sdxx.base);
2651 }
2652
cyhal_sdhc_software_reset(cyhal_sdhc_t * obj)2653 void cyhal_sdhc_software_reset(cyhal_sdhc_t *obj)
2654 {
2655 CY_ASSERT(NULL != obj);
2656 _cyhal_sdxx_reset(&(obj->sdxx));
2657 }
2658
cyhal_sdhc_enable_card_power(cyhal_sdhc_t * obj,bool enable)2659 cy_rslt_t cyhal_sdhc_enable_card_power(cyhal_sdhc_t *obj, bool enable)
2660 {
2661 CY_ASSERT(NULL != obj);
2662
2663 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2664 CY_ASSERT(NULL != sdxx->base);
2665
2666 if (NC == obj->pin_card_pwr_en)
2667 {
2668 /* Need to have card_pwr_en pin configured in order to switch card power state */
2669 return CYHAL_SDHC_RSLT_ERR_PIN;
2670 }
2671
2672 if (enable)
2673 {
2674 Cy_SD_Host_EnableCardVoltage(sdxx->base);
2675 }
2676 else
2677 {
2678 Cy_SD_Host_DisableCardVoltage(sdxx->base);
2679 }
2680 return CY_RSLT_SUCCESS;
2681 }
2682
_cyhal_sdio_init_common(cyhal_sdio_t * obj,const cyhal_sdio_configurator_t * cfg)2683 static cy_rslt_t _cyhal_sdio_init_common(cyhal_sdio_t *obj, const cyhal_sdio_configurator_t *cfg)
2684 {
2685 CY_ASSERT(NULL != obj);
2686 CY_ASSERT(NULL != cfg);
2687 CY_ASSERT(NULL != cfg->host_config);
2688 CY_ASSERT(NULL != cfg->card_config);
2689
2690 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2691 sdxx->obj = obj;
2692 sdxx->is_sdio = true;
2693
2694 /* Configuration is provided by device configurator */
2695 sdxx->dc_configured = (cfg->resource != NULL);
2696
2697 if ((sdxx->dc_configured) &&
2698 (cfg->host_config->emmc || cfg->host_config->dmaType != CY_SD_HOST_DMA_ADMA2 ||
2699 cfg->card_config->busWidth != CY_SD_HOST_BUS_WIDTH_4_BIT))
2700 {
2701 /* emmc setting should be false for SDIO.
2702 Next settings are only supported by SDIO HAL:
2703 - DMA type : ADMA2
2704 - Data bus width : 4 bit
2705 */
2706 return CYHAL_SDIO_RSLT_ERR_UNSUPPORTED;
2707 }
2708
2709 sdxx->resource.type = CYHAL_RSC_INVALID;
2710 sdxx->base = NULL;
2711 sdxx->pin_cmd = CYHAL_NC_PIN_VALUE;
2712 sdxx->pin_clk = CYHAL_NC_PIN_VALUE;
2713 obj->pin_data0 = CYHAL_NC_PIN_VALUE;
2714 obj->pin_data1 = CYHAL_NC_PIN_VALUE;
2715 obj->pin_data2 = CYHAL_NC_PIN_VALUE;
2716 obj->pin_data3 = CYHAL_NC_PIN_VALUE;
2717 sdxx->pin_io_vol_sel = CYHAL_NC_PIN_VALUE;
2718
2719 sdxx->low_voltage_io_set = false;
2720 sdxx->clock_owned = false;
2721
2722 cyhal_gpio_t cmd = cfg->gpios.cmd;
2723 cyhal_gpio_t clk = cfg->gpios.clk;
2724 cyhal_gpio_t data[4];
2725 memcpy(data, cfg->gpios.data, sizeof(cfg->gpios.data));
2726
2727 cy_rslt_t result = _cyhal_sdxx_setup_pin(sdxx, cmd, cyhal_pin_map_sdhc_card_cmd,
2728 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_CMD,
2729 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_cmd), &(sdxx->pin_cmd), _CYHAL_SDHC_NOT_WEAK_FUNC,
2730 !sdxx->dc_configured);
2731
2732 if (CY_RSLT_SUCCESS == result)
2733 {
2734 result = _cyhal_sdxx_setup_pin(sdxx, clk, cyhal_pin_map_sdhc_clk_card,
2735 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CLK_CARD,
2736 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_clk_card), &(sdxx->pin_clk), _CYHAL_SDHC_NOT_WEAK_FUNC,
2737 !sdxx->dc_configured);
2738 }
2739
2740 if (CY_RSLT_SUCCESS == result)
2741 {
2742 result = _cyhal_sdxx_setup_pin(sdxx, data[0], cyhal_pin_map_sdhc_card_dat_3to0,
2743 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2744 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data0), _CYHAL_SDHC_NOT_WEAK_FUNC,
2745 !sdxx->dc_configured);
2746 }
2747
2748 if (CY_RSLT_SUCCESS == result)
2749 {
2750 result = _cyhal_sdxx_setup_pin(sdxx, data[1], cyhal_pin_map_sdhc_card_dat_3to0,
2751 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2752 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data1), _CYHAL_SDHC_NOT_WEAK_FUNC,
2753 !sdxx->dc_configured);
2754 }
2755
2756 if (CY_RSLT_SUCCESS == result)
2757 {
2758 result = _cyhal_sdxx_setup_pin(sdxx, data[2], cyhal_pin_map_sdhc_card_dat_3to0,
2759 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2760 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data2), _CYHAL_SDHC_NOT_WEAK_FUNC,
2761 !sdxx->dc_configured);
2762 }
2763
2764 if (CY_RSLT_SUCCESS == result)
2765 {
2766 result = _cyhal_sdxx_setup_pin(sdxx, data[3], cyhal_pin_map_sdhc_card_dat_3to0,
2767 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2768 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data3), _CYHAL_SDHC_NOT_WEAK_FUNC,
2769 !sdxx->dc_configured);
2770 }
2771
2772 if (result == CY_RSLT_SUCCESS)
2773 {
2774 const cyhal_resource_pin_mapping_t *cmd_map = _CYHAL_UTILS_GET_RESOURCE(cmd, cyhal_pin_map_sdhc_card_cmd);
2775 cyhal_resource_inst_t sdhc = { CYHAL_RSC_SDHC, cmd_map->block_num, cmd_map->channel_num };
2776
2777 if (cfg->clock == NULL)
2778 {
2779 result = _cyhal_utils_allocate_clock(&(sdxx->clock), &sdhc, CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
2780 if (CY_RSLT_SUCCESS == result)
2781 {
2782 sdxx->clock_owned = true;
2783 result = _cyhal_utils_set_clock_frequency2(&(sdxx->clock), MAX_FREQUENCY, &CYHAL_CLOCK_TOLERANCE_5_P);
2784 }
2785 if (CY_RSLT_SUCCESS == result && !cyhal_clock_is_enabled(&(sdxx->clock)))
2786 {
2787 result = cyhal_clock_set_enabled(&(sdxx->clock), true, true);
2788 }
2789 }
2790 else
2791 {
2792 if (cfg->clock->block == CYHAL_CLOCK_BLOCK_HF)
2793 {
2794 sdxx->clock = *cfg->clock;
2795 obj->frequencyhal_hz = cyhal_clock_get_frequency(&(sdxx->clock));
2796 }
2797
2798 if ((cfg->clock->block != CYHAL_CLOCK_BLOCK_HF) || (obj->frequencyhal_hz == 0))
2799 {
2800 result = CYHAL_SDIO_RSLT_ERR_CLOCK;
2801 }
2802 }
2803
2804 if (CY_RSLT_SUCCESS == result)
2805 {
2806 if (sdxx->dc_configured)
2807 {
2808 sdxx->resource = *(cfg->resource);
2809 }
2810 else
2811 {
2812 sdxx->resource = sdhc;
2813 result = cyhal_hwmgr_reserve(&sdhc);
2814 }
2815 }
2816 }
2817
2818 if (result == CY_RSLT_SUCCESS)
2819 {
2820 sdxx->base = _CYHAL_SDHC_BASE_ADDRESSES[sdxx->resource.block_num];
2821 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
2822
2823 /* Enable the SDHC block */
2824 Cy_SD_Host_Enable(sdxx->base);
2825
2826 /* Configure SD Host to operate */
2827 result = (cy_rslt_t)Cy_SD_Host_Init(sdxx->base, cfg->host_config, &sdxx->context);
2828
2829 /* Register SDIO Deep Sleep Callback */
2830 if (CY_RSLT_SUCCESS == result)
2831 {
2832 sdxx->context.cardType = CY_SD_HOST_SDIO;
2833 #if CYHAL_DRIVER_AVAILABLE_SYSPM
2834 sdxx->pm_transition_pending = false;
2835 sdxx->pm_callback_data.callback = &_cyhal_sdio_syspm_callback;
2836 sdxx->pm_callback_data.states = (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE);
2837 sdxx->pm_callback_data.next = NULL;
2838 sdxx->pm_callback_data.args = sdxx;
2839 /* The CYHAL_SYSPM_BEFORE_TRANSITION mode cannot be ignored because the PM handler
2840 * calls the PDL deep-sleep callback that disables the block in this mode before transitioning.
2841 */
2842 sdxx->pm_callback_data.ignore_modes = (cyhal_syspm_callback_mode_t)0;
2843
2844 _cyhal_syspm_register_peripheral_callback(&(sdxx->pm_callback_data));
2845 #endif // #if CYHAL_DRIVER_AVAILABLE_SYSPM
2846 }
2847
2848 if (result == CY_RSLT_SUCCESS)
2849 {
2850 /* Don't enable any error interrupts for now */
2851 Cy_SD_Host_SetErrorInterruptMask(sdxx->base, 0UL);
2852
2853 /* Clear all interrupts */
2854 Cy_SD_Host_ClearErrorInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
2855 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
2856
2857 sdxx->irq_cause = 0UL;
2858 obj->events = 0UL;
2859
2860 sdxx->callback_data.callback = NULL;
2861 sdxx->callback_data.callback_arg = NULL;
2862 _cyhal_sdxx_config_structs[sdxx->resource.block_num] = sdxx;
2863
2864 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
2865 _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_NOT_INITED;
2866 #endif /* defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE) */
2867
2868 _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
2869 _cyhal_irq_register(irqn, CYHAL_ISR_PRIORITY_DEFAULT, _cyhal_sdio_irq_handler);
2870 _cyhal_irq_enable(irqn);
2871
2872 result = (cy_rslt_t)Cy_SD_Host_SetHostBusWidth(sdxx->base, CY_SD_HOST_BUS_WIDTH_4_BIT);
2873 }
2874
2875 /* Change the host SD clock to 400 kHz */
2876 if (result == CY_RSLT_SUCCESS)
2877 {
2878 uint32_t freq = _CYHAL_SDIO_HOST_CLK_400K;
2879 result = _cyhal_sdxx_sdcardchangeclock(sdxx, &freq, sdxx->low_voltage_io_set, false);
2880 if (result == CY_RSLT_SUCCESS)
2881 {
2882 obj->frequencyhal_hz = freq;
2883 obj->block_size = _CYHAL_SDIO_64B_BLOCK;
2884 }
2885 }
2886 }
2887
2888 if (result != CY_RSLT_SUCCESS)
2889 {
2890 cyhal_sdio_free(obj);
2891 }
2892
2893 return result;
2894 }
2895
cyhal_sdio_init(cyhal_sdio_t * obj,cyhal_gpio_t cmd,cyhal_gpio_t clk,cyhal_gpio_t data0,cyhal_gpio_t data1,cyhal_gpio_t data2,cyhal_gpio_t data3)2896 cy_rslt_t cyhal_sdio_init(cyhal_sdio_t *obj, cyhal_gpio_t cmd, cyhal_gpio_t clk, cyhal_gpio_t data0, cyhal_gpio_t data1,
2897 cyhal_gpio_t data2, cyhal_gpio_t data3)
2898 {
2899 cy_en_sd_host_card_capacity_t card_capacity = CY_SD_HOST_SDSC;
2900 cy_en_sd_host_card_type_t card_type = CY_SD_HOST_NOT_EMMC;
2901 uint32_t rca = 0u;
2902 const cy_stc_sd_host_init_config_t host_config =
2903 {
2904 .emmc = false,
2905 .dmaType = CY_SD_HOST_DMA_ADMA2,
2906 .enableLedControl = false,
2907 };
2908 cy_stc_sd_host_sd_card_config_t card_config =
2909 {
2910 .lowVoltageSignaling = false,
2911 .busWidth = CY_SD_HOST_BUS_WIDTH_4_BIT,
2912 .cardType = &card_type,
2913 .rca = &rca,
2914 .cardCapacity = &card_capacity,
2915 };
2916 const cyhal_sdio_configurator_t cfg = {
2917 .resource = NULL,
2918 .host_config = &host_config,
2919 .card_config = &card_config,
2920 .clock = NULL,
2921 .gpios = {clk, cmd, { data0, data1, data2, data3 } }
2922 };
2923 return _cyhal_sdio_init_common(obj, &cfg);
2924 }
2925
cyhal_sdio_free(cyhal_sdio_t * obj)2926 void cyhal_sdio_free(cyhal_sdio_t *obj)
2927 {
2928 CY_ASSERT(NULL != obj);
2929
2930 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2931
2932 if (NULL != sdxx->base)
2933 {
2934 _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
2935 _cyhal_irq_free(irqn);
2936
2937 #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
2938 if (_CYHAL_SDXX_SEMA_NOT_INITED != _cyhal_sdxx_semaphore_status[sdxx->resource.block_num])
2939 {
2940 cy_rtos_deinit_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[sdxx->resource.block_num]));
2941 _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_NOT_INITED;
2942 }
2943 #endif /* CY_RTOS_AWARE or COMPONENT_RTOS_AWARE defined */
2944
2945 Cy_SD_Host_DeInit(sdxx->base);
2946 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
2947
2948 if (!sdxx->dc_configured)
2949 {
2950 cyhal_hwmgr_free(&(sdxx->resource));
2951 }
2952 sdxx->base = NULL;
2953
2954 _cyhal_sdxx_config_structs[sdxx->resource.block_num] = NULL;
2955 #if CYHAL_DRIVER_AVAILABLE_SYSPM
2956 _cyhal_syspm_unregister_peripheral_callback(&(sdxx->pm_callback_data));
2957 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
2958 }
2959
2960 if (sdxx->resource.type != CYHAL_RSC_INVALID)
2961 {
2962 sdxx->resource.type = CYHAL_RSC_INVALID;
2963 }
2964
2965 if (sdxx->clock_owned)
2966 {
2967 cyhal_clock_free(&(sdxx->clock));
2968 sdxx->clock_owned = false;
2969 }
2970
2971 if (!sdxx->dc_configured)
2972 {
2973 /* Free pins */
2974 _cyhal_utils_release_if_used(&(sdxx->pin_clk));
2975 _cyhal_utils_release_if_used(&(sdxx->pin_cmd));
2976 _cyhal_utils_release_if_used(&obj->pin_data0);
2977 _cyhal_utils_release_if_used(&obj->pin_data1);
2978 _cyhal_utils_release_if_used(&obj->pin_data2);
2979 _cyhal_utils_release_if_used(&obj->pin_data3);
2980 }
2981 }
2982
cyhal_sdio_configure(cyhal_sdio_t * obj,const cyhal_sdio_cfg_t * config)2983 cy_rslt_t cyhal_sdio_configure(cyhal_sdio_t *obj, const cyhal_sdio_cfg_t *config)
2984 {
2985 cy_rslt_t result = CYHAL_SDIO_RSLT_ERR_CONFIG;
2986
2987 if ((NULL == obj) || (config == NULL))
2988 {
2989 return CYHAL_SDIO_RSLT_ERR_BAD_PARAM;
2990 }
2991
2992 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2993
2994 if (config->frequencyhal_hz != 0U)
2995 {
2996 uint32_t freq = config->frequencyhal_hz;
2997 result = _cyhal_sdxx_sdcardchangeclock(sdxx, &freq, sdxx->low_voltage_io_set, false);
2998 if (CY_RSLT_SUCCESS == result)
2999 {
3000 obj->frequencyhal_hz = freq;
3001 }
3002 }
3003
3004 if (config->block_size != 0U)
3005 {
3006 /* No need to change anything in HW, because it will be overwritten
3007 * in cyhal_sdio_bulk_transfer()/cyhal_sdio_transfer_async() functions.
3008 * The HW block size will taken based on obj->block_size, which is
3009 * updated here.
3010 */
3011 obj->block_size = config->block_size;
3012 }
3013
3014 return result;
3015 }
3016
cyhal_sdio_host_send_cmd(cyhal_sdio_t * obj,cyhal_sdio_host_transfer_type_t direction,cyhal_sdio_host_command_t command,uint32_t argument,uint32_t * response)3017 cy_rslt_t cyhal_sdio_host_send_cmd(cyhal_sdio_t *obj, cyhal_sdio_host_transfer_type_t direction, \
3018 cyhal_sdio_host_command_t command, uint32_t argument, uint32_t* response)
3019 {
3020 CY_UNUSED_PARAMETER(direction);
3021 if (NULL == obj)
3022 {
3023 return CYHAL_SDIO_RSLT_ERR_BAD_PARAM;
3024 }
3025
3026 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3027
3028 #if CYHAL_DRIVER_AVAILABLE_SYSPM
3029 if (sdxx->pm_transition_pending)
3030 {
3031 return CYHAL_SDIO_RSLT_ERR_PM_PENDING;
3032 }
3033 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
3034
3035 cy_rslt_t ret;
3036 cy_stc_sd_host_cmd_config_t cmd;
3037 uint32_t retry = _CYHAL_SDIO_TRANSFER_TRIES;
3038
3039 /* Clear out the response */
3040 if ( response != NULL )
3041 {
3042 *response = 0UL;
3043 }
3044
3045 do
3046 {
3047 /* First clear out the command complete and transfer complete statuses */
3048 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, CY_SD_HOST_CMD_COMPLETE);
3049
3050 /* Check if an error occurred on any previous transactions */
3051 if ( Cy_SD_Host_GetNormalInterruptStatus(sdxx->base) & CY_SD_HOST_ERR_INTERRUPT )
3052 {
3053 /* Reset the block if there was an error. Note a full reset usually
3054 * requires more time, but this short version is working quite well and
3055 * successfully clears out the error state.
3056 */
3057 Cy_SD_Host_ClearErrorInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
3058 _cyhal_sdxx_reset(sdxx);
3059 }
3060
3061 cmd.commandIndex = (uint32_t)command;
3062 cmd.commandArgument = argument;
3063 cmd.enableCrcCheck = true;
3064 cmd.enableAutoResponseErrorCheck = false;
3065 cmd.respType = CY_SD_HOST_RESPONSE_LEN_48;
3066 cmd.enableIdxCheck = true;
3067 cmd.dataPresent = false;
3068 cmd.cmdType = CY_SD_HOST_CMD_NORMAL;
3069
3070 if (sdxx->irq_cause & CYHAL_SDIO_CMD_COMPLETE)
3071 {
3072 /* Enabling command complete interrupt mask if corresponding event was enabled by user
3073 * _cyhal_sdio_irq_handler will disable CY_SD_HOST_CMD_COMPLETE mask once interrupt
3074 * is generated. */
3075 Cy_SD_Host_SetNormalInterruptMask(sdxx->base, Cy_SD_Host_GetNormalInterruptMask(sdxx->base) |
3076 CY_SD_HOST_CMD_COMPLETE);
3077 }
3078
3079 ret = (cy_rslt_t)Cy_SD_Host_SendCommand(sdxx->base, &cmd);
3080
3081 if (CY_RSLT_SUCCESS == ret)
3082 {
3083 ret = (cy_rslt_t)_cyhal_sdxx_pollcmdcomplete(sdxx, NULL);
3084 }
3085 } while ((CY_RSLT_SUCCESS != ret) && (retry-- > 0UL));
3086
3087 if (CY_RSLT_SUCCESS == ret)
3088 {
3089 ret = (cy_rslt_t)Cy_SD_Host_GetResponse(sdxx->base, response, false);
3090 }
3091
3092 return ret;
3093 }
3094
cyhal_sdio_host_bulk_transfer(cyhal_sdio_t * obj,cyhal_sdio_host_transfer_type_t direction,uint32_t argument,const uint32_t * data,uint16_t length,uint32_t * response)3095 cy_rslt_t cyhal_sdio_host_bulk_transfer(cyhal_sdio_t *obj, cyhal_sdio_host_transfer_type_t direction,
3096 uint32_t argument, const uint32_t* data,
3097 uint16_t length, uint32_t* response)
3098 {
3099 cy_rslt_t ret = CY_RSLT_SUCCESS;
3100 uint32_t retry = _CYHAL_SDIO_TRANSFER_TRIES;
3101
3102 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3103
3104 _cyhal_sdxx_setup_smphr(sdxx);
3105
3106 do
3107 {
3108 ret = cyhal_sdio_transfer_async(obj, direction, argument, data, length);
3109
3110 if (CY_RSLT_SUCCESS == ret)
3111 {
3112 ret = _cyhal_sdxx_waitfor_transfer_complete(sdxx);
3113 }
3114
3115 if (CY_RSLT_SUCCESS != ret)
3116 {
3117 /* SDIO Error Handling
3118 * SDIO write timeout is expected when doing first write to register
3119 * after KSO bit disable (as it goes to AOS core).
3120 * This is the only time known that a write timeout occurs.
3121 * Issue the reset to recover from error. */
3122 _cyhal_sdxx_reset(sdxx);
3123 }
3124
3125 } while ((CY_RSLT_SUCCESS != ret) && (--retry > 0UL));
3126
3127 if(CY_RSLT_SUCCESS != ret)
3128 {
3129 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
3130 }
3131
3132 if ((response != NULL) && (CY_RSLT_SUCCESS == ret))
3133 {
3134 *response = 0UL;
3135 ret = (cy_rslt_t)Cy_SD_Host_GetResponse(sdxx->base, response, false);
3136 }
3137
3138 return ret;
3139 }
3140
3141 /*******************************************************************************
3142 *
3143 * The asynchronous transfer is implemented on the CY_SD_HOST_XFER_COMPLETE
3144 * interrupt. The function sets up data and enables the CY_SD_HOST_XFER_COMPLETE
3145 * interrupt mask, which causes interrupt to occur and handled by _cyhal_sdio_irq_handler
3146 * which take care of disabling CY_SD_HOST_XFER_COMPLETE mask. This function
3147 * can also activate CY_SD_HOST_CMD_COMPLETE interrupt mask if it was enabled
3148 * by user via cyhal_sdio_enable_event function.
3149 *
3150 *******************************************************************************/
cyhal_sdio_host_transfer_async(cyhal_sdio_t * obj,cyhal_sdio_host_transfer_type_t direction,uint32_t argument,const uint32_t * data,uint16_t length)3151 cy_rslt_t cyhal_sdio_host_transfer_async(cyhal_sdio_t *obj, cyhal_sdio_host_transfer_type_t direction,
3152 uint32_t argument, const uint32_t* data, uint16_t length)
3153 {
3154 if (NULL == obj)
3155 {
3156 return CYHAL_SDIO_RSLT_ERR_BAD_PARAM;
3157 }
3158
3159 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3160
3161 #if CYHAL_DRIVER_AVAILABLE_SYSPM
3162 if (sdxx->pm_transition_pending)
3163 {
3164 return CYHAL_SDIO_RSLT_ERR_PM_PENDING;
3165 }
3166 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
3167
3168 cy_rslt_t ret;
3169 uint32_t retry = _CYHAL_SDIO_TRANSFER_TRIES;
3170 cy_stc_sd_host_cmd_config_t cmd;
3171 cy_stc_sd_host_data_config_t dat;
3172
3173 /* Initialize data constants*/
3174 dat.autoCommand = CY_SD_HOST_AUTO_CMD_NONE;
3175 dat.dataTimeout = 0x0dUL;
3176 dat.enableIntAtBlockGap = false;
3177 dat.enReliableWrite = false;
3178 dat.enableDma = true;
3179
3180 do
3181 {
3182 /* Add SDIO Error Handling
3183 * SDIO write timeout is expected when doing first write to register
3184 * after KSO bit disable (as it goes to AOS core).
3185 * This timeout, however, triggers an error state in the hardware.
3186 * So, check for the error and then recover from it
3187 * as needed via reset issuance. This is the only time known that
3188 * a write timeout occurs.
3189 */
3190
3191 /* First clear out the command complete and transfer complete statuses */
3192 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, (CY_SD_HOST_XFER_COMPLETE | CY_SD_HOST_CMD_COMPLETE));
3193
3194 /* Check if an error occurred on any previous transactions or reset after the first unsuccessful transfer try */
3195 if ((Cy_SD_Host_GetNormalInterruptStatus(sdxx->base) & CY_SD_HOST_ERR_INTERRUPT) ||
3196 (retry < _CYHAL_SDIO_TRANSFER_TRIES))
3197 {
3198 /* Reset the block if there was an error. Note a full reset usually
3199 * requires more time, but this short version is working quite well and
3200 * successfully clears out the error state.
3201 */
3202 Cy_SD_Host_ClearErrorInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
3203 _cyhal_sdxx_reset(sdxx);
3204 }
3205
3206 /* Prepare the data transfer register */
3207 cmd.commandIndex = (uint32_t) CYHAL_SDIO_CMD_IO_RW_EXTENDED;
3208 cmd.commandArgument = argument;
3209 cmd.enableCrcCheck = true;
3210 cmd.enableAutoResponseErrorCheck = false;
3211 cmd.respType = CY_SD_HOST_RESPONSE_LEN_48;
3212 cmd.enableIdxCheck = true;
3213 cmd.dataPresent = true;
3214 cmd.cmdType = CY_SD_HOST_CMD_NORMAL;
3215
3216 dat.read = ( direction == CYHAL_SDIO_XFER_TYPE_WRITE ) ? false : true;
3217
3218 /* Block mode */
3219 if (length >= obj->block_size)
3220 {
3221 dat.blockSize = obj->block_size;
3222 dat.numberOfBlock = ( length + obj->block_size - 1 ) / obj->block_size;
3223 }
3224 /* Byte mode */
3225 else
3226 {
3227 dat.blockSize = length;
3228 dat.numberOfBlock = 1UL;
3229 }
3230
3231 length = dat.blockSize * dat.numberOfBlock;
3232
3233 sdxx->adma_descriptor_tbl[0] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | /* Attr Valid */
3234 (1UL << CY_SD_HOST_ADMA_ATTR_END_POS) | /* Attr End */
3235 (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) | /* Attr Int */
3236 (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |
3237 ((uint32_t)length << CY_SD_HOST_ADMA_LEN_POS); /* Len */
3238
3239 sdxx->adma_descriptor_tbl[1] = (uint32_t)data;
3240
3241 /* The address of the ADMA descriptor table. */
3242 dat.data = (uint32_t*)&(sdxx->adma_descriptor_tbl[0]);
3243
3244 ret = _cyhal_sdxx_prepare_for_transfer(sdxx);
3245
3246 if (CY_RSLT_SUCCESS == ret)
3247 {
3248 ret = (cy_rslt_t)Cy_SD_Host_InitDataTransfer(sdxx->base, &dat);
3249 }
3250
3251 if (CY_RSLT_SUCCESS == ret)
3252 {
3253 /* Indicate that async transfer in progress */
3254 sdxx->data_transfer_status = _CYHAL_SDXX_WAIT_BOTH;
3255 ret = (cy_rslt_t)Cy_SD_Host_SendCommand(sdxx->base, &cmd);
3256 }
3257
3258 if (CY_RSLT_SUCCESS == ret)
3259 {
3260 ret = (cy_rslt_t)_cyhal_sdxx_pollcmdcomplete(sdxx, NULL);
3261 }
3262
3263 } while ((CY_RSLT_SUCCESS != ret) && (--retry > 0UL));
3264
3265 if (CY_RSLT_SUCCESS != ret)
3266 {
3267 /* Transfer failed */
3268 sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
3269 }
3270
3271 return ret;
3272 }
3273
cyhal_sdio_is_busy(const cyhal_sdio_t * obj)3274 bool cyhal_sdio_is_busy(const cyhal_sdio_t *obj)
3275 {
3276 CY_ASSERT(NULL != obj);
3277 return _cyhal_sdio_is_busy(&(obj->sdxx));
3278 }
3279
cyhal_sdio_abort_async(cyhal_sdio_t * obj)3280 cy_rslt_t cyhal_sdio_abort_async(cyhal_sdio_t *obj)
3281 {
3282 cy_rslt_t ret = CY_RSLT_SUCCESS;
3283
3284 /* To abort transition reset dat and cmd lines (software reset) */
3285 _cyhal_sdxx_reset(&(obj->sdxx));
3286 obj->sdxx.data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
3287 return ret;
3288 }
3289
cyhal_sdio_register_callback(cyhal_sdio_t * obj,cyhal_sdio_event_callback_t callback,void * callback_arg)3290 void cyhal_sdio_register_callback(cyhal_sdio_t *obj, cyhal_sdio_event_callback_t callback, void *callback_arg)
3291 {
3292 uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
3293 obj->sdxx.callback_data.callback = (cy_israddress) callback;
3294 obj->sdxx.callback_data.callback_arg = callback_arg;
3295 cyhal_system_critical_section_exit(savedIntrStatus);
3296 }
3297
cyhal_sdio_enable_event(cyhal_sdio_t * obj,cyhal_sdio_event_t event,uint8_t intr_priority,bool enable)3298 void cyhal_sdio_enable_event(cyhal_sdio_t *obj, cyhal_sdio_event_t event, uint8_t intr_priority, bool enable)
3299 {
3300 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3301
3302 /* Configure interrupt-based event(s) */
3303 if (0U != ((uint32_t) event & (uint32_t) CYHAL_SDIO_ALL_INTERRUPTS))
3304 {
3305 uint32_t cur_interrupt_mask = Cy_SD_Host_GetNormalInterruptMask(sdxx->base);
3306 uint32_t new_interrupt_mask = cur_interrupt_mask;
3307
3308 _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
3309 _cyhal_irq_set_priority(irqn, intr_priority);
3310
3311 if (enable)
3312 {
3313 sdxx->irq_cause |= event;
3314
3315 /* CY_SD_HOST_CMD_COMPLETE and CY_SD_HOST_XFER_COMPLETE cannot be always enabled because of SD Host driver limitations.
3316 * SDHC HAL transfer APIs are taking care of enabling these statuses. CY_SD_HOST_CMD_COMPLETE is only
3317 * enabled if corresponding user callback is enabled while CY_SD_HOST_XFER_COMPLETE is enabled by transfer API
3318 * regardless it was enabled by user or not. */
3319 event &= ((uint32_t) ~CY_SD_HOST_CMD_COMPLETE) & ((uint32_t) ~CY_SD_HOST_XFER_COMPLETE);
3320
3321 new_interrupt_mask |= event;
3322 Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, new_interrupt_mask & ~cur_interrupt_mask);
3323 }
3324 else
3325 {
3326 new_interrupt_mask &= ~(event);
3327 sdxx->irq_cause &= ~event;
3328 }
3329
3330 Cy_SD_Host_SetNormalInterruptMask(sdxx->base, new_interrupt_mask);
3331 }
3332
3333 /* Configure non-interrupt based event(s) */
3334 if (0U != ((uint32_t) event & _CYHAL_SDIO_INTERFACE_CHANGE_MASK))
3335 {
3336 if (enable)
3337 {
3338 obj->events |= (uint32_t) event;
3339 }
3340 else
3341 {
3342 obj->events &= (uint32_t) ~((uint32_t) event);
3343 }
3344 }
3345 }
3346
cyhal_sdio_host_set_io_voltage(cyhal_sdio_t * obj,cyhal_gpio_t io_volt_sel,cyhal_sdio_host_io_voltage_t io_voltage,cyhal_sdio_host_io_volt_action_type_t io_switch_type)3347 cy_rslt_t cyhal_sdio_host_set_io_voltage(cyhal_sdio_t *obj, cyhal_gpio_t io_volt_sel, cyhal_sdio_host_io_voltage_t io_voltage,
3348 cyhal_sdio_host_io_volt_action_type_t io_switch_type)
3349 {
3350 CY_ASSERT(NULL != obj);
3351 cy_rslt_t result = CY_RSLT_SUCCESS;
3352
3353 _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3354
3355 if (NC != io_volt_sel)
3356 {
3357 /* Configure provided pin it was not yet configured */
3358 if (NC == sdxx->pin_io_vol_sel)
3359 {
3360 #if _CYHAL_SDHC_IO_VOLT_SEL_PRESENT
3361 result = _cyhal_sdxx_setup_pin(sdxx, io_volt_sel, cyhal_pin_map_sdhc_io_volt_sel,
3362 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_IO_VOLT_SEL,
3363 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_io_volt_sel), &(sdxx->pin_io_vol_sel),
3364 _CYHAL_SDHC_CARD_IO_VOLTAGE, true);
3365 #else
3366 result = _cyhal_sdxx_setup_pin(sdxx, io_volt_sel, NULL,
3367 CY_GPIO_DM_STRONG_IN_OFF,
3368 0, &(sdxx->pin_io_vol_sel),
3369 _CYHAL_SDHC_CARD_IO_VOLTAGE, true);
3370 #endif //_CYHAL_SDHC_IO_VOLT_SEL_PRESENT
3371 }
3372 /* io volt sel pin is already configured and user provided other pin */
3373 else if (io_volt_sel != sdxx->pin_io_vol_sel)
3374 {
3375 result = CYHAL_SDIO_RSLT_ERR_IO_VOLT_SEL_PIN_CONFIGURED;
3376 }
3377 }
3378
3379 if (CY_RSLT_SUCCESS == result)
3380 {
3381 result = _cyhal_sdxx_set_io_voltage(sdxx, (cyhal_sdxx_io_voltage_t)io_voltage,
3382 (_cyhal_sdxx_io_switch_action_t)io_switch_type);
3383 }
3384
3385 return result;
3386 }
3387
cyhal_sdio_init_cfg(cyhal_sdio_t * obj,const cyhal_sdio_configurator_t * cfg)3388 cy_rslt_t cyhal_sdio_init_cfg(cyhal_sdio_t *obj, const cyhal_sdio_configurator_t *cfg)
3389 {
3390 CY_ASSERT(NULL != obj);
3391 CY_ASSERT(NULL != cfg);
3392 return _cyhal_sdio_init_common(obj, cfg);
3393 }
3394
3395 #if defined(__cplusplus)
3396 }
3397 #endif
3398
3399 #endif /* CYHAL_DRIVER_AVAILABLE_SDHC */
3400