• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_sdmmc_common.h"
9 #include "hpm_sdmmc_host.h"
10 #include "board.h"
11 
12 
13 static void sdmmchost_vsel_pin_control(sdmmc_host_t *host, hpm_sdmmc_io_volt_t io_volt);
14 
15 static void sdmmchost_power_control(sdmmc_host_t *host, hpm_sdmmc_power_option_t option);
16 
17 
18 static void sdmmchost_switch_to_3v3_as_needed(sdmmc_host_t *host);
19 
20 static hpm_stat_t sdmmchost_check_host_availablity(sdmmc_host_t *host);
21 
sdmmchost_check_host_availablity(sdmmc_host_t * host)22 static hpm_stat_t sdmmchost_check_host_availablity(sdmmc_host_t *host)
23 {
24     hpm_stat_t status = status_success;
25 
26     if (!sdmmchost_is_card_detected(host)) {
27         status = status_sdmmc_no_sd_card_inserted;
28         host->card_inserted = false;
29         host->card_init_done = false;
30     }
31 
32     return status;
33 }
34 
sdmmchost_delay_ms(sdmmc_host_t * host,uint32_t ms)35 void sdmmchost_delay_ms(sdmmc_host_t *host, uint32_t ms)
36 {
37     if (host->host_param.delay_ms != NULL) {
38         host->host_param.delay_ms(ms);
39     }
40 }
41 
42 
sdmmchost_switch_to_3v3_as_needed(sdmmc_host_t * host)43 static void sdmmchost_switch_to_3v3_as_needed(sdmmc_host_t *host)
44 {
45     if (IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_3V3)) {
46         sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_3v3);
47     }
48 }
49 
sdmmchost_init(sdmmc_host_t * host)50 hpm_stat_t sdmmchost_init(sdmmc_host_t *host)
51 {
52     hpm_stat_t status = status_invalid_argument;
53 
54     do {
55         HPM_BREAK_IF(host == NULL);
56 
57         /* Initialize clock for the identification stage */
58         host->clock_freq = host->host_param.clock_init_func(host->host_param.base, SDMMC_CLOCK_400KHZ, true);
59         host->operation_mode = hpm_sdmmc_operation_mode_inactive;
60         sdmmchost_init_io(host, host->operation_mode);
61 
62         sdmmchost_power_control(host, hpm_sdmmc_power_off);
63         sdmmchost_delay_ms(host, 36);
64         sdmmchost_switch_to_3v3_as_needed(host);
65         sdmmchost_delay_ms(host, 36);
66         sdmmchost_power_control(host, hpm_sdmmc_power_on);
67 
68         sdxc_config_t sdxc_config;
69         sdxc_config.data_timeout = 1000; /* Data timeout interval, configure to 1000 milliseconds by default */
70 
71         sdxc_init(host->host_param.base, &sdxc_config);
72 
73         sdmmchost_wait_card_active(host);
74         sdmmchost_delay_ms(host, 10);
75 
76         status = status_success;
77 
78     } while (false);
79 
80     return status;
81 }
82 
sdmmchost_vsel_pin_control(sdmmc_host_t * host,hpm_sdmmc_io_volt_t io_volt)83 static void sdmmchost_vsel_pin_control(sdmmc_host_t *host, hpm_sdmmc_io_volt_t io_volt)
84 {
85     const hpm_sdmmc_pin_info_t *pin_info;
86     if (sdmmchost_is_voltage_switch_supported(host)) {
87         pin_info = &host->host_param.io_data.vsel_pin;
88         if (pin_info->use_gpio) {
89             bool polarity = pin_info->polarity;
90             uint32_t gpio_index = pin_info->gpio_pin / 32;
91             uint32_t pin_index = pin_info->gpio_pin % 32;
92             volatile uint32_t *gpio_on = (polarity == false) ? &HPM_GPIO0->DO[gpio_index].SET
93                                                              : &HPM_GPIO0->DO[gpio_index].CLEAR;
94             volatile uint32_t *gpio_off = (polarity == false) ? &HPM_GPIO0->DO[gpio_index].CLEAR
95                                                               : &HPM_GPIO0->DO[gpio_index].SET;
96 
97             HPM_GPIO0->OE[gpio_index].SET = (1UL << pin_index);
98             if (io_volt == hpm_sdmmc_io_voltage_3v3) {
99                 *gpio_off = (1UL << pin_index);
100             } else {
101                 *gpio_on = (1UL << pin_index);
102             }
103         }
104     }
105 }
106 
sdmmchost_switch_to_1v8(sdmmc_host_t * host)107 hpm_stat_t sdmmchost_switch_to_1v8(sdmmc_host_t *host)
108 {
109     if (host == NULL) {
110         return status_invalid_argument;
111     }
112 
113     /* 1. Stop providing clock to the card */
114     sdxc_enable_inverse_clock(host->host_param.base, false);
115     sdxc_enable_sd_clock(host->host_param.base, false);
116 
117     /* 2. Wait until DAT[3:0] are 4'b0000 */
118     uint32_t data3_0_level;
119     uint32_t delay_cnt = 1000000UL;
120     do {
121         data3_0_level = sdxc_get_data3_0_level(host->host_param.base);
122         --delay_cnt;
123     } while ((data3_0_level != 0U) && (delay_cnt > 0U));
124     if (delay_cnt < 1) {
125         return status_timeout;
126     }
127 
128     /* 3. Switch signaling to 1.8v */
129     sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_1v8);
130     sdmmchost_select_voltage(host, hpm_sdmmc_io_voltage_1v8);
131 
132     /* 4. delay 5ms */
133     host->host_param.delay_ms(50);
134 
135     /* 5. Provide SD clock the card again */
136     sdxc_enable_inverse_clock(host->host_param.base, true);
137     sdxc_enable_sd_clock(host->host_param.base, true);
138 
139     /* 6. wait 1ms */
140     host->host_param.delay_ms(1);
141 
142     /* 7. Check DAT[3:0], make sure the value is 4'b0000 */
143     delay_cnt = 1000000UL;
144     do {
145         data3_0_level = sdxc_get_data3_0_level(host->host_param.base);
146         --delay_cnt;
147     } while ((data3_0_level == 0U) && (delay_cnt > 0U));
148     if (delay_cnt < 1) {
149         return status_timeout;
150     }
151 
152     return status_success;
153 }
154 
sdmmchost_deinit(sdmmc_host_t * host)155 void sdmmchost_deinit(sdmmc_host_t *host)
156 {
157     sdxc_reset(host->host_param.base, sdxc_reset_cmd_line, 0xffffu);
158     sdxc_reset(host->host_param.base, sdxc_reset_data_line, 0xffffu);
159 }
160 
sdmmchost_reset(sdmmc_host_t * host)161 void sdmmchost_reset(sdmmc_host_t *host)
162 {
163     sdxc_reset(host->host_param.base, sdxc_reset_cmd_line, 0xffffu);
164 
165     sdxc_reset(host->host_param.base, sdxc_reset_data_line, 0xffffu);
166 }
167 
sdmmchost_enable_emmc_support(sdmmc_host_t * host,bool enable)168 void sdmmchost_enable_emmc_support(sdmmc_host_t *host, bool enable)
169 {
170     sdxc_enable_emmc_support(host->host_param.base, enable);
171 }
172 
sdmmchost_is_card_detected(sdmmc_host_t * host)173 bool sdmmchost_is_card_detected(sdmmc_host_t *host)
174 {
175     bool result = true;
176     if (IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_CARD_DETECTION)) {
177         const hpm_sdmmc_pin_info_t *pin_info = &host->host_param.io_data.cd_pin;
178         if (!pin_info->use_gpio) {
179             result = sdxc_is_card_inserted(host->host_param.base);
180         } else {
181             uint32_t gpio_index = pin_info->gpio_pin / 32;
182             uint32_t pin_index = pin_info->gpio_pin % 32;
183             uint32_t pin_val = HPM_GPIO0->DI[gpio_index].VALUE & (1UL << pin_index);
184 
185             result = (pin_info->polarity == 0) ? (pin_val != 0) : (pin_val == 0);
186         }
187     }
188     return result;
189 }
190 
sdmmchost_set_card_bus_width(sdmmc_host_t * host,sdmmc_buswidth_t bus_width)191 void sdmmchost_set_card_bus_width(sdmmc_host_t *host, sdmmc_buswidth_t bus_width)
192 {
193     host->bus_width = bus_width;
194     sdmmchost_init_io(host, hpm_sdmmc_operation_mode_transfer);
195     sdxc_set_data_bus_width(host->host_param.base, (sdxc_bus_width_t) bus_width);
196 }
197 
sdmmchost_set_card_clock(sdmmc_host_t * host,uint32_t freq,bool clock_inverse)198 uint32_t sdmmchost_set_card_clock(sdmmc_host_t *host, uint32_t freq, bool clock_inverse)
199 {
200     uint32_t clk_freq = host->host_param.clock_init_func(host->host_param.base, freq, clock_inverse);
201     host->clock_freq = clk_freq;
202     return clk_freq;
203 }
204 
sdmmchost_wait_card_active(sdmmc_host_t * host)205 void sdmmchost_wait_card_active(sdmmc_host_t *host)
206 {
207     sdxc_wait_card_active(host->host_param.base);
208     host->host_param.delay_ms(10);
209 }
210 
sdmmchost_send_command(sdmmc_host_t * host,sdmmchost_cmd_t * cmd)211 hpm_stat_t sdmmchost_send_command(sdmmc_host_t *host, sdmmchost_cmd_t *cmd)
212 {
213     hpm_stat_t status;
214 
215     status = sdmmchost_check_host_availablity(host);
216     if (status != status_success) {
217         return status;
218     }
219 
220     status = sdxc_send_command(host->host_param.base, cmd);
221     if (status != status_success) {
222         return status;
223     }
224 
225     int64_t delay_cnt = 1000000;
226     uint32_t int_stat;
227     bool has_done_or_error = false;
228     do {
229         int_stat = sdxc_get_interrupt_status(host->host_param.base);
230         if (!IS_HPM_BITMASK_SET(int_stat, SDXC_INT_STAT_CMD_COMPLETE_MASK)) {
231             delay_cnt--;
232 
233         } else {
234             has_done_or_error = true;
235         }
236 
237         status = sdxc_parse_interrupt_status(host->host_param.base);
238         if (status != status_success) {
239             has_done_or_error = true;
240         }
241 
242     } while ((!has_done_or_error) && (delay_cnt > 0));
243 
244     if ((delay_cnt <= 0) && (!has_done_or_error)) {
245         status = status_timeout;
246         return status;
247     }
248     if (status != status_success) {
249         return status;
250     }
251     status = sdxc_receive_cmd_response(host->host_param.base, &host->cmd);
252     sdxc_clear_interrupt_status(host->host_param.base, SDXC_INT_STAT_CMD_COMPLETE_MASK);
253 
254     if (cmd->resp_type == (sdxc_dev_resp_type_t) sdmmc_resp_r1b) {
255         uint32_t delay_ms = (cmd->cmd_timeout_ms == 0) ? 100 : cmd->cmd_timeout_ms;
256         delay_cnt = 10 * 1000 * delay_ms;
257         has_done_or_error = false;
258         do {
259             int_stat = sdxc_get_interrupt_status(host->host_param.base);
260             if (!IS_HPM_BITMASK_SET(int_stat, SDXC_INT_STAT_XFER_COMPLETE_MASK)) {
261                 delay_cnt--;
262             } else {
263                 has_done_or_error = true;
264             }
265             status = sdxc_parse_interrupt_status(host->host_param.base);
266             if (status != status_success) {
267                 has_done_or_error = true;
268             }
269         } while ((!has_done_or_error) && (delay_cnt > 0));
270 
271         if ((delay_cnt <= 0) && (!has_done_or_error)) {
272             status = status_timeout;
273         }
274 
275         sdxc_clear_interrupt_status(host->host_param.base, SDXC_INT_STAT_XFER_COMPLETE_MASK);
276     }
277 
278     return status;
279 }
280 
sdmmchost_transfer(sdmmc_host_t * host,sdmmchost_xfer_t * content)281 hpm_stat_t sdmmchost_transfer(sdmmc_host_t *host, sdmmchost_xfer_t *content)
282 {
283     hpm_stat_t status;
284 
285     status = sdmmchost_check_host_availablity(host);
286     if (status != status_success) {
287         return status;
288     }
289 
290     sdxc_adma_config_t *config_ptr = NULL;
291     sdxc_adma_config_t dma_config;
292 
293     if (content->data != NULL) {
294         dma_config.dma_type = sdxc_dmasel_adma2;
295         dma_config.adma_table_words = sizeof(host->adma2_desc) / sizeof(uint32_t);
296         dma_config.adma_table = (uint32_t *) &host->adma2_desc;
297         config_ptr = &dma_config;
298 
299         /***************************************************************************************************************
300          *  Calculate the data timeout interval in millisecond =
301          *  (block_count * block_size) / tx_rx_bytes_per_sec * 1000 + margin time
302          *  Here set the margin time to 100 milliseconds
303          **************************************************************************************************************/
304         uint32_t bus_width = sdxc_get_data_bus_width(host->host_param.base);
305         uint32_t tx_rx_bytes_per_sec = host->clock_freq * bus_width / 8;
306         uint32_t block_cnt = content->data->block_cnt;
307         uint32_t block_size = content->data->block_size;
308         uint32_t read_write_size = block_cnt * block_size;
309         uint32_t timeout_ms = (uint32_t) (1.0f * read_write_size / tx_rx_bytes_per_sec) * 1000 + 100;
310         sdxc_set_data_timeout(host->host_param.base, timeout_ms, NULL);
311     }
312     status = sdxc_transfer_nonblocking(host->host_param.base, config_ptr, content);
313 
314     int32_t delay_cnt = 1000000U;
315     uint32_t int_stat;
316     bool has_done_or_error = false;
317     do {
318         int_stat = sdxc_get_interrupt_status(host->host_param.base);
319         if (!IS_HPM_BITMASK_SET(int_stat, SDXC_INT_STAT_CMD_COMPLETE_MASK)) {
320             delay_cnt--;
321         } else {
322             has_done_or_error = true;
323         }
324 
325         status = sdxc_parse_interrupt_status(host->host_param.base);
326         if (status != status_success) {
327             has_done_or_error = true;
328         }
329     } while ((!has_done_or_error) && (delay_cnt > 0));
330 
331     if ((delay_cnt <= 0) && (!has_done_or_error)) {
332         status = status_timeout;
333         return status;
334     }
335     if (status != status_success) {
336         return status;
337     }
338     status = sdxc_receive_cmd_response(host->host_param.base, &host->cmd);
339 
340     sdxc_clear_interrupt_status(host->host_param.base, SDXC_INT_STAT_CMD_COMPLETE_MASK);
341 
342     if ((content->data != NULL) || (content->command->resp_type == (sdxc_dev_resp_type_t) sdmmc_resp_r1b)) {
343         delay_cnt = 10000000UL; /* Delay more than 1 second based on the Bus Frequency */
344         uint32_t xfer_done_or_error_mask = SDXC_INT_STAT_XFER_COMPLETE_MASK | SDXC_STS_ERROR;
345         bool has_done_or_error = false;
346         do {
347             int_stat = sdxc_get_interrupt_status(host->host_param.base);
348             if (!IS_HPM_BITMASK_SET(int_stat, xfer_done_or_error_mask)) {
349                 delay_cnt--;
350             } else {
351                 has_done_or_error = true;
352             }
353             status = sdxc_parse_interrupt_status(host->host_param.base);
354             if (status != status_success) {
355                 has_done_or_error = true;
356             }
357         } while ((delay_cnt > 0) && (!has_done_or_error));
358 
359         if (delay_cnt <= 0) {
360             status = status_sdxc_data_timeout_error;
361         }
362 
363         sdxc_clear_interrupt_status(host->host_param.base, SDXC_INT_STAT_XFER_COMPLETE_MASK);
364     }
365 
366     return status;
367 }
368 
sdmmchost_set_speed_mode(sdmmc_host_t * host,sdmmc_speed_mode_t speed_mode)369 hpm_stat_t sdmmchost_set_speed_mode(sdmmc_host_t *host, sdmmc_speed_mode_t speed_mode)
370 {
371     if ((host == NULL) || (host->host_param.base == NULL)) {
372         return status_invalid_argument;
373     }
374 
375     sdxc_set_speed_mode(host->host_param.base, (sdxc_speed_mode_t) speed_mode);
376     return status_success;
377 }
378 
sdmmchost_error_recovery(sdmmc_host_t * host,sdmmchost_cmd_t * abort_cmd)379 hpm_stat_t sdmmchost_error_recovery(sdmmc_host_t *host, sdmmchost_cmd_t *abort_cmd)
380 {
381     sdxc_error_recovery(host->host_param.base);
382     return sdmmchost_send_command(host, abort_cmd);
383 }
384 
sdmmchost_set_cardclk_delay_chain(sdmmc_host_t * host)385 void sdmmchost_set_cardclk_delay_chain(sdmmc_host_t *host)
386 {
387     SDXC_Type *base = host->host_param.base;
388     bool need_inverse = sdxc_is_inverse_clock_enabled(base);
389     sdxc_enable_inverse_clock(base, false);
390     sdxc_enable_sd_clock(base, false);
391     uint32_t num_delaycells = sdxc_get_default_cardclk_delay_chain(base, host->clock_freq);
392     sdxc_set_cardclk_delay_chain(host->host_param.base, num_delaycells);
393     sdxc_enable_inverse_clock(base, need_inverse);
394     sdxc_enable_sd_clock(base, true);
395 }
396 
sdmmchost_is_8bit_supported(sdmmc_host_t * host)397 bool sdmmchost_is_8bit_supported(sdmmc_host_t *host)
398 {
399     return IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_8BIT);
400 }
401 
sdmmchost_is_voltage_switch_supported(sdmmc_host_t * host)402 bool sdmmchost_is_voltage_switch_supported(sdmmc_host_t *host)
403 {
404     return IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_VOLTAGE_SWITCH);
405 }
406 
sdmmchost_power_control(sdmmc_host_t * host,hpm_sdmmc_power_option_t option)407 void sdmmchost_power_control(sdmmc_host_t *host, hpm_sdmmc_power_option_t option)
408 {
409     if (IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_POWER_SWITCH)) {
410         const hpm_sdmmc_pin_info_t *pin_info = &host->host_param.io_data.pwr_pin;
411         const sdmmc_io_init_apis_t *init_apis = &host->host_param.io_init_apis;
412         bool use_gpio = pin_info->use_gpio;
413         SDMMCHOST_Type *base = host->host_param.base;
414         init_apis->pwr_io_init(base, use_gpio);
415         if (pin_info->use_gpio) {
416             uint32_t gpio_index = pin_info->gpio_pin / 32;
417             uint32_t pin_index = pin_info->gpio_pin % 32;
418             volatile uint32_t *gpio_reg_off = (pin_info->polarity == 0) ? &HPM_GPIO0->DO[gpio_index].CLEAR
419                                                                         : &HPM_GPIO0->DO[gpio_index].SET;
420             volatile uint32_t *gpio_reg_on = (pin_info->polarity == 0) ? &HPM_GPIO0->DO[gpio_index].SET
421                                                                        : &HPM_GPIO0->DO[gpio_index].CLEAR;
422             HPM_GPIO0->OE[gpio_index].SET = (1UL << pin_index);
423             if (option == hpm_sdmmc_power_off) {
424                 *gpio_reg_off = (1UL << pin_index);
425             } else if (option == hpm_sdmmc_power_on) {
426                 *gpio_reg_on = (1UL << pin_index);
427             } else {
428                 *gpio_reg_off = (1UL << pin_index);
429                 host->host_param.delay_ms(1);
430                 *gpio_reg_on = (1UL << pin_index);
431             }
432         } else {
433             if (option == hpm_sdmmc_power_off) {
434                 sdxc_enable_power(host->host_param.base, false);
435             } else if (option == hpm_sdmmc_power_on) {
436                 sdxc_enable_power(host->host_param.base, true);
437             } else {
438                 sdxc_enable_power(host->host_param.base, false);
439                 host->host_param.delay_ms(1);
440                 sdxc_enable_power(host->host_param.base, true);
441             }
442         }
443         host->host_param.delay_ms(1);
444     }
445 }
446 
sdmmchost_init_io(sdmmc_host_t * host,hpm_sdmmc_operation_mode_t operation_mode)447 void sdmmchost_init_io(sdmmc_host_t *host, hpm_sdmmc_operation_mode_t operation_mode)
448 {
449     const hpm_sdmmc_pin_info_t *pin_info;
450     bool as_gpio;
451     const sdmmc_io_init_apis_t *init_apis = &host->host_param.io_init_apis;
452     SDMMCHOST_Type *base = host->host_param.base;
453     uint32_t host_flags = host->host_param.host_flags;
454 
455     if (operation_mode == hpm_sdmmc_operation_mode_inactive) {
456         uint32_t bus_width = host->bus_width;
457         bool support_3v3 = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_3V3);
458         host->io_voltage = support_3v3 ? hpm_sdmmc_io_voltage_3v3 : hpm_sdmmc_io_voltage_1v8;
459         /* Initialize IO */
460 
461         bool support_pwr = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_POWER_SWITCH);
462         if (support_pwr) {
463             pin_info = &host->host_param.io_data.pwr_pin;
464             as_gpio = pin_info->use_gpio;
465             if (init_apis->pwr_io_init != NULL) {
466                 init_apis->pwr_io_init(base, as_gpio);
467             }
468         }
469 
470         bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
471         init_apis->cmd_io_init(base, true, is_1v8); /* Configure CMD pin to open-drain mode */
472         init_apis->clk_data_io_init(base, bus_width, is_1v8);
473 
474         bool support_cd = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_CARD_DETECTION);
475         if (support_cd) {
476             pin_info = &host->host_param.io_data.cd_pin;
477             as_gpio = pin_info->use_gpio;
478             if (init_apis->cd_io_init != NULL) {
479                 init_apis->cd_io_init(base, as_gpio);
480             }
481         }
482         bool support_vsel = sdmmchost_is_voltage_switch_supported(host);
483         if (support_vsel) {
484             pin_info = &host->host_param.io_data.vsel_pin;
485             as_gpio = pin_info->use_gpio;
486             if (init_apis->vsel_io_init != NULL) {
487                 init_apis->vsel_io_init(base, as_gpio);
488             }
489             /* Since eMMC device doesn't support dynamic voltage switch, so set the voltage at initialization phase */
490             if (!support_3v3) {
491                 sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_1v8);
492                 sdmmchost_select_voltage(host, hpm_sdmmc_io_voltage_1v8);
493             }
494         }
495     } else if (operation_mode == hpm_sdmmc_operation_mode_identification) {
496         bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
497         bool is_opendrain = true;
498         init_apis->cmd_io_init(base, is_opendrain, is_1v8);
499         uint32_t bus_width = 1;
500         switch (host->bus_width) {
501         case sdmmc_bus_width_4bit:
502             bus_width = 4;
503             break;
504         case sdmmc_bus_width_8bit:
505             bus_width = 8;
506             break;
507         default:
508             bus_width = 1;
509             break;
510         }
511         init_apis->clk_data_io_init(base, bus_width, is_1v8);
512         bool support_ds = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_HS400);
513         if (support_ds) {
514             init_apis->ds_io_init(base);
515         }
516     } else if (operation_mode == hpm_sdmmc_operation_mode_transfer) {
517         bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
518         bool is_opendrain = false;
519         init_apis->cmd_io_init(base, is_opendrain, is_1v8);
520         uint32_t bus_width = 1;
521         switch (host->bus_width) {
522         case sdmmc_bus_width_4bit:
523             bus_width = 4;
524             break;
525         case sdmmc_bus_width_8bit:
526             bus_width = 8;
527             break;
528         default:
529             bus_width = 1;
530             break;
531         }
532         init_apis->clk_data_io_init(base, bus_width, is_1v8);
533         bool support_ds = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_HS400);
534         if (support_ds) {
535             init_apis->ds_io_init(base);
536         }
537     } else if (operation_mode == hpm_sdmmc_operation_mode_interrupt) {
538         bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
539         bool is_opendrain = true;
540         init_apis->cmd_io_init(base, is_opendrain, is_1v8);
541     } else {
542         /* DO nothing */
543     }
544     /* Wait a while in case the IO initialization requires small delays to get effective */
545     for (volatile uint32_t delay_cnt = 100; delay_cnt > 0; delay_cnt--) {
546         NOP();
547     }
548 }
549 
sdmmchost_enable_enhanced_data_strobe(sdmmc_host_t * host,bool enable)550 void sdmmchost_enable_enhanced_data_strobe(sdmmc_host_t *host, bool enable)
551 {
552     sdxc_enable_enhanced_strobe(host->host_param.base, enable);
553 }
554 
555 
sdmmchost_set_data_strobe_delay(sdmmc_host_t * host)556 void sdmmchost_set_data_strobe_delay(sdmmc_host_t *host)
557 {
558     uint32_t num_delaycells = sdxc_get_default_strobe_delay(host->host_param.base);
559     sdxc_set_data_strobe_delay(host->host_param.base, num_delaycells);
560 }
561 
sdmmchost_select_voltage(sdmmc_host_t * host,hpm_sdmmc_io_volt_t io_volt)562 void sdmmchost_select_voltage(sdmmc_host_t *host, hpm_sdmmc_io_volt_t io_volt)
563 {
564     sdxc_bus_voltage_option_t vsel = sdxc_bus_voltage_sd_3v3;
565     if (io_volt == hpm_sdmmc_io_voltage_1v8) {
566         vsel = sdxc_bus_voltage_sd_1v8;
567         host->io_voltage = hpm_sdmmc_io_voltage_1v8;
568     } else {
569         host->io_voltage = hpm_sdmmc_io_voltage_3v3;
570     }
571     sdxc_select_voltage(host->host_param.base, vsel);
572 
573 }
574