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     cy_rslt_t result = CY_RSLT_SUCCESS;
2691 
2692     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2693     sdxx->obj = obj;
2694     sdxx->is_sdio = true;
2695 
2696     /* Configuration is provided by device configurator */
2697     sdxx->dc_configured = (cfg->resource != NULL);
2698 
2699     if ((sdxx->dc_configured) &&
2700             (cfg->host_config->emmc || cfg->host_config->dmaType != CY_SD_HOST_DMA_ADMA2 ||
2701              cfg->card_config->busWidth != CY_SD_HOST_BUS_WIDTH_4_BIT))
2702     {
2703         /*  emmc setting should be false for SDIO.
2704             Next settings are only supported by SDIO HAL:
2705                 - DMA type : ADMA2
2706                 - Data bus width : 4 bit
2707         */
2708         return CYHAL_SDIO_RSLT_ERR_UNSUPPORTED;
2709     }
2710 
2711     sdxx->resource.type = CYHAL_RSC_INVALID;
2712     sdxx->base = NULL;
2713     sdxx->pin_cmd = CYHAL_NC_PIN_VALUE;
2714     sdxx->pin_clk = CYHAL_NC_PIN_VALUE;
2715     obj->pin_data0 = CYHAL_NC_PIN_VALUE;
2716     obj->pin_data1 = CYHAL_NC_PIN_VALUE;
2717     obj->pin_data2 = CYHAL_NC_PIN_VALUE;
2718     obj->pin_data3 = CYHAL_NC_PIN_VALUE;
2719     sdxx->pin_io_vol_sel = CYHAL_NC_PIN_VALUE;
2720 
2721     sdxx->low_voltage_io_set = false;
2722     sdxx->clock_owned = false;
2723 
2724     cyhal_gpio_t cmd = cfg->gpios.cmd;
2725     cyhal_gpio_t clk = cfg->gpios.clk;
2726     cyhal_gpio_t data[4];
2727     memcpy(data, cfg->gpios.data, sizeof(cfg->gpios.data));
2728 
2729     if (NC != sdxx->pin_cmd)
2730     {
2731     		result = _cyhal_sdxx_setup_pin(sdxx, cmd, cyhal_pin_map_sdhc_card_cmd,
2732 			CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_CMD,
2733 			_CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_cmd), &(sdxx->pin_cmd), _CYHAL_SDHC_NOT_WEAK_FUNC,
2734 			!sdxx->dc_configured);
2735     }
2736 
2737     if ((NC != sdxx->pin_clk) && (result == CY_RSLT_SUCCESS))
2738     {
2739         result = _cyhal_sdxx_setup_pin(sdxx, clk, cyhal_pin_map_sdhc_clk_card,
2740             CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CLK_CARD,
2741             _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_clk_card), &(sdxx->pin_clk), _CYHAL_SDHC_NOT_WEAK_FUNC,
2742             !sdxx->dc_configured);
2743     }
2744 
2745     if ((NC != obj->pin_data0) && (result == CY_RSLT_SUCCESS))
2746     {
2747         result = _cyhal_sdxx_setup_pin(sdxx, data[0], cyhal_pin_map_sdhc_card_dat_3to0,
2748             CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2749             _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data0), _CYHAL_SDHC_NOT_WEAK_FUNC,
2750             !sdxx->dc_configured);
2751     }
2752 
2753     if ((NC != obj->pin_data1) && (result == CY_RSLT_SUCCESS))
2754     {
2755         result = _cyhal_sdxx_setup_pin(sdxx, data[1], cyhal_pin_map_sdhc_card_dat_3to0,
2756             CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2757             _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data1), _CYHAL_SDHC_NOT_WEAK_FUNC,
2758             !sdxx->dc_configured);
2759     }
2760 
2761     if ((NC != obj->pin_data2) && (result == CY_RSLT_SUCCESS))
2762     {
2763         result = _cyhal_sdxx_setup_pin(sdxx, data[2], cyhal_pin_map_sdhc_card_dat_3to0,
2764             CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2765             _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data2), _CYHAL_SDHC_NOT_WEAK_FUNC,
2766             !sdxx->dc_configured);
2767     }
2768 
2769     if ((NC != obj->pin_data3) && (result == CY_RSLT_SUCCESS))
2770     {
2771         result = _cyhal_sdxx_setup_pin(sdxx, data[3], cyhal_pin_map_sdhc_card_dat_3to0,
2772             CYHAL_PIN_MAP_DRIVE_MODE_SDHC_CARD_DAT_3TO0,
2773             _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_card_dat_3to0), &(obj->pin_data3), _CYHAL_SDHC_NOT_WEAK_FUNC,
2774             !sdxx->dc_configured);
2775     }
2776 
2777     if (result == CY_RSLT_SUCCESS)
2778     {
2779         const cyhal_resource_pin_mapping_t *cmd_map = _CYHAL_UTILS_GET_RESOURCE(cmd, cyhal_pin_map_sdhc_card_cmd);
2780         cyhal_resource_inst_t sdhc = { CYHAL_RSC_SDHC, cmd_map->block_num, cmd_map->channel_num };
2781 
2782         if (cfg->clock == NULL)
2783         {
2784             result = _cyhal_utils_allocate_clock(&(sdxx->clock), &sdhc, CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
2785             if (CY_RSLT_SUCCESS == result)
2786             {
2787                 sdxx->clock_owned = true;
2788                 result = _cyhal_utils_set_clock_frequency2(&(sdxx->clock), MAX_FREQUENCY, &CYHAL_CLOCK_TOLERANCE_5_P);
2789             }
2790             if (CY_RSLT_SUCCESS == result && !cyhal_clock_is_enabled(&(sdxx->clock)))
2791             {
2792                 result = cyhal_clock_set_enabled(&(sdxx->clock), true, true);
2793             }
2794         }
2795         else
2796         {
2797             if (cfg->clock->block == CYHAL_CLOCK_BLOCK_HF)
2798             {
2799                 sdxx->clock = *cfg->clock;
2800                 obj->frequencyhal_hz = cyhal_clock_get_frequency(&(sdxx->clock));
2801             }
2802 
2803             if ((cfg->clock->block != CYHAL_CLOCK_BLOCK_HF) || (obj->frequencyhal_hz == 0))
2804             {
2805                 result = CYHAL_SDIO_RSLT_ERR_CLOCK;
2806             }
2807         }
2808 
2809         if (CY_RSLT_SUCCESS == result)
2810         {
2811             if (sdxx->dc_configured)
2812             {
2813                 sdxx->resource = *(cfg->resource);
2814             }
2815             else
2816             {
2817                 sdxx->resource = sdhc;
2818                 result = cyhal_hwmgr_reserve(&sdhc);
2819             }
2820         }
2821     }
2822 
2823         if (result == CY_RSLT_SUCCESS)
2824         {
2825             sdxx->base = _CYHAL_SDHC_BASE_ADDRESSES[sdxx->resource.block_num];
2826             sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
2827 
2828             /* Enable the SDHC block */
2829             Cy_SD_Host_Enable(sdxx->base);
2830 
2831         /* Configure SD Host to operate */
2832         result = (cy_rslt_t)Cy_SD_Host_Init(sdxx->base, cfg->host_config, &sdxx->context);
2833 
2834         /* Register SDIO Deep Sleep Callback */
2835         if (CY_RSLT_SUCCESS == result)
2836         {
2837             sdxx->context.cardType = CY_SD_HOST_SDIO;
2838             #if CYHAL_DRIVER_AVAILABLE_SYSPM
2839             sdxx->pm_transition_pending = false;
2840             sdxx->pm_callback_data.callback = &_cyhal_sdio_syspm_callback;
2841             sdxx->pm_callback_data.states = (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE);
2842             sdxx->pm_callback_data.next = NULL;
2843             sdxx->pm_callback_data.args = sdxx;
2844             /* The CYHAL_SYSPM_BEFORE_TRANSITION mode cannot be ignored because the PM handler
2845                 * calls the PDL deep-sleep callback that disables the block in this mode before transitioning.
2846                 */
2847             sdxx->pm_callback_data.ignore_modes = (cyhal_syspm_callback_mode_t)0;
2848 
2849             _cyhal_syspm_register_peripheral_callback(&(sdxx->pm_callback_data));
2850             #endif // #if CYHAL_DRIVER_AVAILABLE_SYSPM
2851         }
2852 
2853         if (result == CY_RSLT_SUCCESS)
2854         {
2855             /* Don't enable any error interrupts for now */
2856             Cy_SD_Host_SetErrorInterruptMask(sdxx->base, 0UL);
2857 
2858             /* Clear all interrupts */
2859             Cy_SD_Host_ClearErrorInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
2860             Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
2861 
2862             sdxx->irq_cause = 0UL;
2863             obj->events    = 0UL;
2864 
2865             sdxx->callback_data.callback = NULL;
2866             sdxx->callback_data.callback_arg = NULL;
2867             _cyhal_sdxx_config_structs[sdxx->resource.block_num] = sdxx;
2868 
2869             #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
2870             _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_NOT_INITED;
2871             #endif /* defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE) */
2872 
2873             _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
2874             _cyhal_irq_register(irqn, CYHAL_ISR_PRIORITY_DEFAULT, _cyhal_sdio_irq_handler);
2875             _cyhal_irq_enable(irqn);
2876 
2877             result = (cy_rslt_t)Cy_SD_Host_SetHostBusWidth(sdxx->base, CY_SD_HOST_BUS_WIDTH_4_BIT);
2878         }
2879 
2880         /* Change the host SD clock to 400 kHz */
2881         if (result == CY_RSLT_SUCCESS)
2882         {
2883             uint32_t freq = _CYHAL_SDIO_HOST_CLK_400K;
2884             result = _cyhal_sdxx_sdcardchangeclock(sdxx, &freq, sdxx->low_voltage_io_set, false);
2885             if (result == CY_RSLT_SUCCESS)
2886             {
2887                 obj->frequencyhal_hz = freq;
2888                 obj->block_size = _CYHAL_SDIO_64B_BLOCK;
2889             }
2890         }
2891     }
2892 
2893     if (result != CY_RSLT_SUCCESS)
2894     {
2895         cyhal_sdio_free(obj);
2896     }
2897 
2898     return result;
2899 }
2900 
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)2901 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,
2902         cyhal_gpio_t data2, cyhal_gpio_t data3)
2903 {
2904     cy_en_sd_host_card_capacity_t card_capacity = CY_SD_HOST_SDSC;
2905     cy_en_sd_host_card_type_t card_type = CY_SD_HOST_NOT_EMMC;
2906     uint32_t rca = 0u;
2907     const cy_stc_sd_host_init_config_t host_config =
2908     {
2909         .emmc = false,
2910         .dmaType = CY_SD_HOST_DMA_ADMA2,
2911         .enableLedControl = false,
2912     };
2913     cy_stc_sd_host_sd_card_config_t card_config =
2914     {
2915         .lowVoltageSignaling = false,
2916         .busWidth = CY_SD_HOST_BUS_WIDTH_4_BIT,
2917         .cardType = &card_type,
2918         .rca = &rca,
2919         .cardCapacity = &card_capacity,
2920     };
2921     const cyhal_sdio_configurator_t cfg = {
2922         .resource = NULL,
2923         .host_config = &host_config,
2924 		.card_config = &card_config,
2925         .clock = NULL,
2926         .gpios = {clk, cmd, { data0, data1, data2, data3 } }
2927     };
2928     return _cyhal_sdio_init_common(obj, &cfg);
2929 }
2930 
cyhal_sdio_free(cyhal_sdio_t * obj)2931 void cyhal_sdio_free(cyhal_sdio_t *obj)
2932 {
2933     CY_ASSERT(NULL != obj);
2934 
2935     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2936 
2937     if (NULL != sdxx->base)
2938     {
2939         _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
2940         _cyhal_irq_free(irqn);
2941 
2942         #if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
2943         if (_CYHAL_SDXX_SEMA_NOT_INITED != _cyhal_sdxx_semaphore_status[sdxx->resource.block_num])
2944         {
2945             cy_rtos_deinit_semaphore(&(_cyhal_sdxx_semaphore_xfer_done[sdxx->resource.block_num]));
2946             _cyhal_sdxx_semaphore_status[sdxx->resource.block_num] = _CYHAL_SDXX_SEMA_NOT_INITED;
2947         }
2948         #endif /* CY_RTOS_AWARE or COMPONENT_RTOS_AWARE defined */
2949 
2950         Cy_SD_Host_DeInit(sdxx->base);
2951         sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
2952 
2953         if (!sdxx->dc_configured)
2954         {
2955             cyhal_hwmgr_free(&(sdxx->resource));
2956         }
2957         sdxx->base = NULL;
2958 
2959         _cyhal_sdxx_config_structs[sdxx->resource.block_num] = NULL;
2960         #if CYHAL_DRIVER_AVAILABLE_SYSPM
2961         _cyhal_syspm_unregister_peripheral_callback(&(sdxx->pm_callback_data));
2962         #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
2963     }
2964 
2965     if (sdxx->resource.type != CYHAL_RSC_INVALID)
2966     {
2967         sdxx->resource.type = CYHAL_RSC_INVALID;
2968     }
2969 
2970     if (sdxx->clock_owned)
2971     {
2972         cyhal_clock_free(&(sdxx->clock));
2973         sdxx->clock_owned = false;
2974     }
2975 
2976     if (!sdxx->dc_configured)
2977     {
2978         /* Free pins */
2979         _cyhal_utils_release_if_used(&(sdxx->pin_clk));
2980         _cyhal_utils_release_if_used(&(sdxx->pin_cmd));
2981         _cyhal_utils_release_if_used(&obj->pin_data0);
2982         _cyhal_utils_release_if_used(&obj->pin_data1);
2983         _cyhal_utils_release_if_used(&obj->pin_data2);
2984         _cyhal_utils_release_if_used(&obj->pin_data3);
2985     }
2986 }
2987 
cyhal_sdio_configure(cyhal_sdio_t * obj,const cyhal_sdio_cfg_t * config)2988 cy_rslt_t cyhal_sdio_configure(cyhal_sdio_t *obj, const cyhal_sdio_cfg_t *config)
2989 {
2990     cy_rslt_t result = CYHAL_SDIO_RSLT_ERR_CONFIG;
2991 
2992     if ((NULL == obj) || (config == NULL))
2993     {
2994         return CYHAL_SDIO_RSLT_ERR_BAD_PARAM;
2995     }
2996 
2997     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
2998 
2999     if (config->frequencyhal_hz != 0U)
3000     {
3001         uint32_t freq = config->frequencyhal_hz;
3002         result = _cyhal_sdxx_sdcardchangeclock(sdxx, &freq, sdxx->low_voltage_io_set, false);
3003         if (CY_RSLT_SUCCESS == result)
3004         {
3005             obj->frequencyhal_hz = freq;
3006         }
3007     }
3008 
3009     if (config->block_size != 0U)
3010     {
3011         /* No need to change anything in HW, because it will be overwritten
3012         *  in cyhal_sdio_bulk_transfer()/cyhal_sdio_transfer_async() functions.
3013         *  The HW block size will taken based on obj->block_size, which is
3014         *  updated here.
3015         */
3016         obj->block_size = config->block_size;
3017     }
3018 
3019     return result;
3020 }
3021 
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)3022 cy_rslt_t cyhal_sdio_host_send_cmd(cyhal_sdio_t *obj, cyhal_sdio_host_transfer_type_t direction, \
3023                               cyhal_sdio_host_command_t command, uint32_t argument, uint32_t* response)
3024 {
3025     CY_UNUSED_PARAMETER(direction);
3026     if (NULL == obj)
3027     {
3028         return CYHAL_SDIO_RSLT_ERR_BAD_PARAM;
3029     }
3030 
3031     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3032 
3033     #if CYHAL_DRIVER_AVAILABLE_SYSPM
3034     if (sdxx->pm_transition_pending)
3035     {
3036         return CYHAL_SDIO_RSLT_ERR_PM_PENDING;
3037     }
3038     #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
3039 
3040     cy_rslt_t                   ret;
3041     cy_stc_sd_host_cmd_config_t cmd;
3042     uint32_t                    retry = _CYHAL_SDIO_TRANSFER_TRIES;
3043 
3044     /* Clear out the response */
3045     if ( response != NULL )
3046     {
3047         *response = 0UL;
3048     }
3049 
3050     do
3051     {
3052         /* First clear out the command complete and transfer complete statuses */
3053         Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, CY_SD_HOST_CMD_COMPLETE);
3054 
3055         /* Check if an error occurred on any previous transactions */
3056         if ( Cy_SD_Host_GetNormalInterruptStatus(sdxx->base) & CY_SD_HOST_ERR_INTERRUPT )
3057         {
3058             /* Reset the block if there was an error. Note a full reset usually
3059              * requires more time, but this short version is working quite well and
3060              * successfully clears out the error state.
3061              */
3062             Cy_SD_Host_ClearErrorInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
3063             _cyhal_sdxx_reset(sdxx);
3064         }
3065 
3066         cmd.commandIndex                 = (uint32_t)command;
3067         cmd.commandArgument              = argument;
3068         cmd.enableCrcCheck               = true;
3069         cmd.enableAutoResponseErrorCheck = false;
3070         cmd.respType                     = CY_SD_HOST_RESPONSE_LEN_48;
3071         cmd.enableIdxCheck               = true;
3072         cmd.dataPresent                  = false;
3073         cmd.cmdType                      = CY_SD_HOST_CMD_NORMAL;
3074 
3075         if (sdxx->irq_cause & CYHAL_SDIO_CMD_COMPLETE)
3076         {
3077             /*  Enabling command complete interrupt mask if corresponding event was enabled by user
3078             *   _cyhal_sdio_irq_handler will disable CY_SD_HOST_CMD_COMPLETE mask once interrupt
3079             *   is generated. */
3080             Cy_SD_Host_SetNormalInterruptMask(sdxx->base, Cy_SD_Host_GetNormalInterruptMask(sdxx->base) |
3081                     CY_SD_HOST_CMD_COMPLETE);
3082         }
3083 
3084         ret = (cy_rslt_t)Cy_SD_Host_SendCommand(sdxx->base, &cmd);
3085 
3086         if (CY_RSLT_SUCCESS == ret)
3087         {
3088             ret = (cy_rslt_t)_cyhal_sdxx_pollcmdcomplete(sdxx, NULL);
3089         }
3090     } while ((CY_RSLT_SUCCESS != ret) && (retry-- > 0UL));
3091 
3092     if (CY_RSLT_SUCCESS == ret)
3093     {
3094         ret = (cy_rslt_t)Cy_SD_Host_GetResponse(sdxx->base, response, false);
3095     }
3096 
3097     return ret;
3098 }
3099 
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)3100 cy_rslt_t cyhal_sdio_host_bulk_transfer(cyhal_sdio_t *obj, cyhal_sdio_host_transfer_type_t direction,
3101                                    uint32_t argument, const uint32_t* data,
3102                                    uint16_t length, uint32_t* response)
3103 {
3104     cy_rslt_t ret = CY_RSLT_SUCCESS;
3105     uint32_t retry = _CYHAL_SDIO_TRANSFER_TRIES;
3106 
3107     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3108 
3109     _cyhal_sdxx_setup_smphr(sdxx);
3110 
3111     do
3112     {
3113         ret = cyhal_sdio_transfer_async(obj, direction, argument, data, length);
3114 
3115         if (CY_RSLT_SUCCESS == ret)
3116         {
3117             ret = _cyhal_sdxx_waitfor_transfer_complete(sdxx);
3118         }
3119 
3120         if (CY_RSLT_SUCCESS != ret)
3121         {
3122             /*  SDIO Error Handling
3123             *   SDIO write timeout is expected when doing first write to register
3124             *   after KSO bit disable (as it goes to AOS core).
3125             *   This is the only time known that a write timeout occurs.
3126             *   Issue the reset to recover from error. */
3127             _cyhal_sdxx_reset(sdxx);
3128         }
3129 
3130     } while ((CY_RSLT_SUCCESS != ret) && (--retry > 0UL));
3131 
3132     if(CY_RSLT_SUCCESS != ret)
3133     {
3134         sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
3135     }
3136 
3137     if ((response != NULL) && (CY_RSLT_SUCCESS == ret))
3138     {
3139         *response = 0UL;
3140         ret = (cy_rslt_t)Cy_SD_Host_GetResponse(sdxx->base, response, false);
3141     }
3142 
3143     return ret;
3144 }
3145 
3146 /*******************************************************************************
3147 *
3148 *   The asynchronous transfer is implemented on the CY_SD_HOST_XFER_COMPLETE
3149 *   interrupt. The function sets up data and enables the CY_SD_HOST_XFER_COMPLETE
3150 *   interrupt mask, which causes interrupt to occur and handled by _cyhal_sdio_irq_handler
3151 *   which take care of disabling CY_SD_HOST_XFER_COMPLETE mask. This function
3152 *   can also activate CY_SD_HOST_CMD_COMPLETE interrupt mask if it was enabled
3153 *   by user via cyhal_sdio_enable_event function.
3154 *
3155 *******************************************************************************/
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)3156 cy_rslt_t cyhal_sdio_host_transfer_async(cyhal_sdio_t *obj, cyhal_sdio_host_transfer_type_t direction,
3157                                     uint32_t argument, const uint32_t* data, uint16_t length)
3158 {
3159     if (NULL == obj)
3160     {
3161         return CYHAL_SDIO_RSLT_ERR_BAD_PARAM;
3162     }
3163 
3164     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3165 
3166     #if CYHAL_DRIVER_AVAILABLE_SYSPM
3167     if (sdxx->pm_transition_pending)
3168     {
3169         return CYHAL_SDIO_RSLT_ERR_PM_PENDING;
3170     }
3171     #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
3172 
3173     cy_rslt_t                    ret;
3174     uint32_t                     retry = _CYHAL_SDIO_TRANSFER_TRIES;
3175     cy_stc_sd_host_cmd_config_t  cmd;
3176     cy_stc_sd_host_data_config_t dat;
3177 
3178     /* Initialize data constants*/
3179     dat.autoCommand         = CY_SD_HOST_AUTO_CMD_NONE;
3180     dat.dataTimeout         = 0x0dUL;
3181     dat.enableIntAtBlockGap = false;
3182     dat.enReliableWrite     = false;
3183     dat.enableDma           = true;
3184 
3185     do
3186     {
3187         /* Add SDIO Error Handling
3188         * SDIO write timeout is expected when doing first write to register
3189         * after KSO bit disable (as it goes to AOS core).
3190         * This timeout, however, triggers an error state in the hardware.
3191         * So, check for the error and then recover from it
3192         * as needed via reset issuance. This is the only time known that
3193         * a write timeout occurs.
3194         */
3195 
3196         /* First clear out the command complete and transfer complete statuses */
3197         Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, (CY_SD_HOST_XFER_COMPLETE | CY_SD_HOST_CMD_COMPLETE));
3198 
3199         /* Check if an error occurred on any previous transactions or reset after the first unsuccessful transfer try */
3200         if ((Cy_SD_Host_GetNormalInterruptStatus(sdxx->base) & CY_SD_HOST_ERR_INTERRUPT) ||
3201             (retry < _CYHAL_SDIO_TRANSFER_TRIES))
3202         {
3203             /* Reset the block if there was an error. Note a full reset usually
3204              * requires more time, but this short version is working quite well and
3205              * successfully clears out the error state.
3206              */
3207             Cy_SD_Host_ClearErrorInterruptStatus(sdxx->base, _CYHAL_SDIO_SET_ALL_INTERRUPTS_MASK);
3208             _cyhal_sdxx_reset(sdxx);
3209         }
3210 
3211         /* Prepare the data transfer register */
3212         cmd.commandIndex                 = (uint32_t) CYHAL_SDIO_CMD_IO_RW_EXTENDED;
3213         cmd.commandArgument              = argument;
3214         cmd.enableCrcCheck               = true;
3215         cmd.enableAutoResponseErrorCheck = false;
3216         cmd.respType                     = CY_SD_HOST_RESPONSE_LEN_48;
3217         cmd.enableIdxCheck               = true;
3218         cmd.dataPresent                  = true;
3219         cmd.cmdType                      = CY_SD_HOST_CMD_NORMAL;
3220 
3221         dat.read = ( direction == CYHAL_SDIO_XFER_TYPE_WRITE ) ? false : true;
3222 
3223         /* Block mode */
3224         if (length >= obj->block_size)
3225         {
3226             dat.blockSize     = obj->block_size;
3227             dat.numberOfBlock = ( length + obj->block_size - 1 ) / obj->block_size;
3228         }
3229         /* Byte mode */
3230         else
3231         {
3232             dat.blockSize     = length;
3233             dat.numberOfBlock = 1UL;
3234         }
3235 
3236         length = dat.blockSize * dat.numberOfBlock;
3237 
3238         sdxx->adma_descriptor_tbl[0] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | /* Attr Valid */
3239                                        (1UL << CY_SD_HOST_ADMA_ATTR_END_POS) |   /* Attr End */
3240                                        (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) |   /* Attr Int */
3241                                        (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |
3242                                        ((uint32_t)length << CY_SD_HOST_ADMA_LEN_POS);     /* Len */
3243 
3244         sdxx->adma_descriptor_tbl[1] = (uint32_t)data;
3245 
3246         /* The address of the ADMA descriptor table. */
3247         dat.data = (uint32_t*)&(sdxx->adma_descriptor_tbl[0]);
3248 
3249         ret = _cyhal_sdxx_prepare_for_transfer(sdxx);
3250 
3251         if (CY_RSLT_SUCCESS == ret)
3252         {
3253             ret = (cy_rslt_t)Cy_SD_Host_InitDataTransfer(sdxx->base, &dat);
3254         }
3255 
3256         if (CY_RSLT_SUCCESS == ret)
3257         {
3258             /* Indicate that async transfer in progress */
3259             sdxx->data_transfer_status = _CYHAL_SDXX_WAIT_BOTH;
3260             ret = (cy_rslt_t)Cy_SD_Host_SendCommand(sdxx->base, &cmd);
3261         }
3262 
3263         if (CY_RSLT_SUCCESS == ret)
3264         {
3265             ret = (cy_rslt_t)_cyhal_sdxx_pollcmdcomplete(sdxx, NULL);
3266         }
3267 
3268     } while ((CY_RSLT_SUCCESS != ret) && (--retry > 0UL));
3269 
3270     if (CY_RSLT_SUCCESS != ret)
3271     {
3272         /* Transfer failed */
3273         sdxx->data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
3274     }
3275 
3276     return ret;
3277 }
3278 
cyhal_sdio_is_busy(const cyhal_sdio_t * obj)3279 bool cyhal_sdio_is_busy(const cyhal_sdio_t *obj)
3280 {
3281     CY_ASSERT(NULL != obj);
3282     return _cyhal_sdio_is_busy(&(obj->sdxx));
3283 }
3284 
cyhal_sdio_abort_async(cyhal_sdio_t * obj)3285 cy_rslt_t cyhal_sdio_abort_async(cyhal_sdio_t *obj)
3286 {
3287     cy_rslt_t ret = CY_RSLT_SUCCESS;
3288 
3289     /* To abort transition reset dat and cmd lines (software reset) */
3290     _cyhal_sdxx_reset(&(obj->sdxx));
3291     obj->sdxx.data_transfer_status = _CYHAL_SDXX_NOT_RUNNING;
3292     return ret;
3293 }
3294 
cyhal_sdio_register_callback(cyhal_sdio_t * obj,cyhal_sdio_event_callback_t callback,void * callback_arg)3295 void cyhal_sdio_register_callback(cyhal_sdio_t *obj, cyhal_sdio_event_callback_t callback, void *callback_arg)
3296 {
3297     uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
3298     obj->sdxx.callback_data.callback = (cy_israddress) callback;
3299     obj->sdxx.callback_data.callback_arg = callback_arg;
3300     cyhal_system_critical_section_exit(savedIntrStatus);
3301 }
3302 
cyhal_sdio_enable_event(cyhal_sdio_t * obj,cyhal_sdio_event_t event,uint8_t intr_priority,bool enable)3303 void cyhal_sdio_enable_event(cyhal_sdio_t *obj, cyhal_sdio_event_t event, uint8_t intr_priority, bool enable)
3304 {
3305     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3306 
3307     /* Configure interrupt-based event(s) */
3308     if (0U != ((uint32_t) event & (uint32_t) CYHAL_SDIO_ALL_INTERRUPTS))
3309     {
3310         uint32_t cur_interrupt_mask = Cy_SD_Host_GetNormalInterruptMask(sdxx->base);
3311         uint32_t new_interrupt_mask = cur_interrupt_mask;
3312 
3313         _cyhal_system_irq_t irqn = _CYHAL_SDHC_IRQ_N[sdxx->resource.block_num];
3314         _cyhal_irq_set_priority(irqn, intr_priority);
3315 
3316         if (enable)
3317         {
3318             sdxx->irq_cause |= event;
3319 
3320             /*  CY_SD_HOST_CMD_COMPLETE and CY_SD_HOST_XFER_COMPLETE cannot be always enabled because of SD Host driver limitations.
3321             *   SDHC HAL transfer APIs are taking care of enabling these statuses. CY_SD_HOST_CMD_COMPLETE is only
3322             *   enabled if corresponding user callback is enabled while CY_SD_HOST_XFER_COMPLETE is enabled by transfer API
3323             *   regardless it was enabled by user or not. */
3324             event &= ((uint32_t) ~CY_SD_HOST_CMD_COMPLETE) & ((uint32_t) ~CY_SD_HOST_XFER_COMPLETE);
3325 
3326             new_interrupt_mask |= event;
3327             Cy_SD_Host_ClearNormalInterruptStatus(sdxx->base, new_interrupt_mask & ~cur_interrupt_mask);
3328         }
3329         else
3330         {
3331             new_interrupt_mask &= ~(event);
3332             sdxx->irq_cause &= ~event;
3333         }
3334 
3335         Cy_SD_Host_SetNormalInterruptMask(sdxx->base, new_interrupt_mask);
3336     }
3337 
3338     /* Configure non-interrupt based event(s) */
3339     if (0U != ((uint32_t) event & _CYHAL_SDIO_INTERFACE_CHANGE_MASK))
3340     {
3341         if (enable)
3342         {
3343             obj->events |= (uint32_t) event;
3344         }
3345         else
3346         {
3347             obj->events &= (uint32_t) ~((uint32_t) event);
3348         }
3349     }
3350 }
3351 
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)3352 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,
3353                                     cyhal_sdio_host_io_volt_action_type_t io_switch_type)
3354 {
3355     CY_ASSERT(NULL != obj);
3356     cy_rslt_t result = CY_RSLT_SUCCESS;
3357 
3358     _cyhal_sdxx_t *sdxx = &(obj->sdxx);
3359 
3360     if (NC != io_volt_sel)
3361     {
3362         /* Configure provided pin it was not yet configured */
3363         if (NC == sdxx->pin_io_vol_sel)
3364         {
3365             #if _CYHAL_SDHC_IO_VOLT_SEL_PRESENT
3366             result = _cyhal_sdxx_setup_pin(sdxx, io_volt_sel, cyhal_pin_map_sdhc_io_volt_sel,
3367                 CYHAL_PIN_MAP_DRIVE_MODE_SDHC_IO_VOLT_SEL,
3368                 _CYHAL_SDHC_ELEM_COUNT(cyhal_pin_map_sdhc_io_volt_sel), &(sdxx->pin_io_vol_sel),
3369                 _CYHAL_SDHC_CARD_IO_VOLTAGE, true);
3370             #else
3371             result = _cyhal_sdxx_setup_pin(sdxx, io_volt_sel, NULL,
3372                 CY_GPIO_DM_STRONG_IN_OFF,
3373                 0, &(sdxx->pin_io_vol_sel),
3374                 _CYHAL_SDHC_CARD_IO_VOLTAGE, true);
3375             #endif //_CYHAL_SDHC_IO_VOLT_SEL_PRESENT
3376         }
3377         /* io volt sel pin is already configured and user provided other pin */
3378         else if (io_volt_sel != sdxx->pin_io_vol_sel)
3379         {
3380             result = CYHAL_SDIO_RSLT_ERR_IO_VOLT_SEL_PIN_CONFIGURED;
3381         }
3382     }
3383 
3384     if (CY_RSLT_SUCCESS == result)
3385     {
3386         result = _cyhal_sdxx_set_io_voltage(sdxx, (cyhal_sdxx_io_voltage_t)io_voltage,
3387             (_cyhal_sdxx_io_switch_action_t)io_switch_type);
3388     }
3389 
3390     return result;
3391 }
3392 
cyhal_sdio_init_cfg(cyhal_sdio_t * obj,const cyhal_sdio_configurator_t * cfg)3393 cy_rslt_t cyhal_sdio_init_cfg(cyhal_sdio_t *obj, const cyhal_sdio_configurator_t *cfg)
3394 {
3395     CY_ASSERT(NULL != obj);
3396     CY_ASSERT(NULL != cfg);
3397     return _cyhal_sdio_init_common(obj, cfg);
3398 }
3399 
3400 #if defined(__cplusplus)
3401 }
3402 #endif
3403 
3404 #endif /* CYHAL_DRIVER_AVAILABLE_SDHC */
3405