| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- /*
- * Copyright (c) 2021-2024 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
- #include "hpm_sdmmc_common.h"
- #include "hpm_sdmmc_host.h"
- #include "board.h"
- #define HPM_SDMMC_HOST_TIMEOUT_DEFAULT (1000UL)
- static void sdmmchost_power_control(const sdmmc_host_t *host, hpm_sdmmc_power_option_t option);
- static void sdmmchost_switch_to_3v3_as_needed(const sdmmc_host_t *host);
- static hpm_stat_t sdmmchost_check_host_availability(sdmmc_host_t *host);
- static hpm_stat_t sdmmchost_check_host_availability(sdmmc_host_t *host)
- {
- hpm_stat_t status = status_success;
- if (!sdmmchost_is_card_detected(host)) {
- status = status_sdmmc_no_sd_card_inserted;
- host->card_inserted = false;
- host->card_init_done = false;
- }
- return status;
- }
- void sdmmchost_delay_ms(const sdmmc_host_t *host, uint32_t ms)
- {
- hpm_sdmmc_osal_delay((void *)host, ms);
- }
- static void sdmmchost_switch_to_3v3_as_needed(const sdmmc_host_t *host)
- {
- if (IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_3V3)) {
- sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_3v3);
- }
- }
- hpm_stat_t sdmmchost_init(sdmmc_host_t *host)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(host == NULL);
- /* Initialize clock for the identification stage */
- host->clock_freq = host->host_param.clock_init_func(host->host_param.base, SDMMC_CLOCK_400KHZ, true);
- host->operation_mode = hpm_sdmmc_operation_mode_inactive;
- sdmmchost_init_io(host, host->operation_mode);
- sdmmchost_power_control(host, hpm_sdmmc_power_off);
- sdmmchost_delay_ms(host, 36);
- sdmmchost_switch_to_3v3_as_needed(host);
- sdmmchost_delay_ms(host, 36);
- sdmmchost_power_control(host, hpm_sdmmc_power_on);
- sdxc_config_t sdxc_config;
- sdxc_config.data_timeout = 1000; /* Data timeout interval, configure to 1000 milliseconds by default */
- SDXC_Type *base = host->host_param.base;
- sdxc_init(base, &sdxc_config);
- sdmmchost_wait_card_active(host);
- sdmmchost_delay_ms(host, 10);
- #if defined(HPM_SDMMC_HOST_ENABLE_IRQ) && (HPM_SDMMC_HOST_ENABLE_IRQ == 1)
- host->xfer_done_or_error_event = hpm_sdmmc_osal_event_create(host);
- if (host->xfer_done_or_error_event == NULL) {
- break;
- }
- const uint32_t irq_mask =
- SDXC_INT_STAT_CMD_COMPLETE_MASK | SDXC_INT_STAT_XFER_COMPLETE_MASK | SDXC_INT_STAT_ERR_INTERRUPT_MASK;
- sdxc_enable_interrupt_signal(base, irq_mask, true);
- #endif
- status = status_success;
- } while (false);
- return status;
- }
- void sdmmchost_vsel_pin_control(const sdmmc_host_t *host, hpm_sdmmc_io_volt_t io_volt)
- {
- if (sdmmchost_is_voltage_switch_supported(host)) {
- const hpm_sdmmc_pin_info_t *pin_info = &host->host_param.io_data.vsel_pin;
- if (pin_info->use_gpio) {
- bool polarity = pin_info->polarity;
- uint32_t gpio_index = pin_info->gpio_pin / 32;
- uint32_t pin_index = pin_info->gpio_pin % 32;
- volatile uint32_t *gpio_on = (polarity == false)
- ? &HPM_GPIO0->DO[gpio_index].SET
- : &HPM_GPIO0->DO[gpio_index].CLEAR;
- volatile uint32_t *gpio_off = (polarity == false)
- ? &HPM_GPIO0->DO[gpio_index].CLEAR
- : &HPM_GPIO0->DO[gpio_index].SET;
- HPM_GPIO0->OE[gpio_index].SET = (1UL << pin_index);
- if (io_volt == hpm_sdmmc_io_voltage_3v3) {
- *gpio_off = (1UL << pin_index);
- } else {
- *gpio_on = (1UL << pin_index);
- }
- }
- }
- }
- hpm_stat_t sdmmchost_switch_to_1v8(sdmmc_host_t *host)
- {
- if (host == NULL) {
- return status_invalid_argument;
- }
- /* 1. Stop providing clock to the card */
- sdxc_enable_inverse_clock(host->host_param.base, false);
- sdxc_enable_sd_clock(host->host_param.base, false);
- /* 2. Wait until DAT[3:0] are 4'b0000 */
- uint32_t data3_0_level;
- uint32_t delay_cnt = 1000000UL;
- do {
- data3_0_level = sdxc_get_data3_0_level(host->host_param.base);
- --delay_cnt;
- } while ((data3_0_level != 0U) && (delay_cnt > 0U));
- if (delay_cnt < 1) {
- return status_timeout;
- }
- /* 3. Switch signaling to 1.8v */
- sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_1v8);
- sdmmchost_select_voltage(host, hpm_sdmmc_io_voltage_1v8);
- /* 4. delay 5ms */
- sdmmchost_delay_ms(host, 50);
- /* 5. Provide SD clock the card again */
- sdxc_enable_inverse_clock(host->host_param.base, true);
- sdxc_enable_sd_clock(host->host_param.base, true);
- /* 6. wait 1ms */
- sdmmchost_delay_ms(host, 1);
- /* 7. Check DAT[3:0], make sure the value is 4'b0000 */
- delay_cnt = 1000000UL;
- do {
- data3_0_level = sdxc_get_data3_0_level(host->host_param.base);
- --delay_cnt;
- } while ((data3_0_level == 0U) && (delay_cnt > 0U));
- if (delay_cnt < 1) {
- return status_timeout;
- }
- return status_success;
- }
- void sdmmchost_deinit(sdmmc_host_t *host)
- {
- if (host != NULL) {
- sdxc_reset(host->host_param.base, sdxc_reset_cmd_line, 0xffffu);
- sdxc_reset(host->host_param.base, sdxc_reset_data_line, 0xffffu);
- #if defined(HPM_SDMMC_HOST_ENABLE_IRQ) && (HPM_SDMMC_HOST_ENABLE_IRQ == 1)
- if (host->xfer_done_or_error_event != NULL) {
- hpm_sdmmc_osal_event_delete(host, host->xfer_done_or_error_event);
- host->xfer_done_or_error_event = NULL;
- }
- #endif
- }
- }
- void sdmmchost_reset(const sdmmc_host_t *host)
- {
- sdxc_reset(host->host_param.base, sdxc_reset_cmd_line, 0xffffu);
- sdxc_reset(host->host_param.base, sdxc_reset_data_line, 0xffffu);
- }
- void sdmmchost_enable_emmc_support(const sdmmc_host_t *host, bool enable)
- {
- sdxc_enable_emmc_support(host->host_param.base, enable);
- }
- bool sdmmchost_is_card_detected(const sdmmc_host_t *host)
- {
- bool result = true;
- if (IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_CARD_DETECTION)) {
- const hpm_sdmmc_pin_info_t *pin_info = &host->host_param.io_data.cd_pin;
- if (!pin_info->use_gpio) {
- result = sdxc_is_card_inserted(host->host_param.base);
- } else {
- uint32_t gpio_index = pin_info->gpio_pin / 32;
- uint32_t pin_index = pin_info->gpio_pin % 32;
- uint32_t pin_val = HPM_GPIO0->DI[gpio_index].VALUE & (1UL << pin_index);
- result = (pin_info->polarity == 0) ? (pin_val != 0) : (pin_val == 0);
- }
- }
- return result;
- }
- void sdmmchost_set_card_bus_width(sdmmc_host_t *host, sdmmc_buswidth_t bus_width)
- {
- host->bus_width = bus_width;
- sdmmchost_init_io(host, hpm_sdmmc_operation_mode_transfer);
- sdxc_set_data_bus_width(host->host_param.base, (sdxc_bus_width_t) bus_width);
- }
- uint32_t sdmmchost_set_card_clock(sdmmc_host_t *host, uint32_t freq, bool clock_inverse)
- {
- uint32_t clk_freq = host->host_param.clock_init_func(host->host_param.base, freq, clock_inverse);
- host->clock_freq = clk_freq;
- return clk_freq;
- }
- void sdmmchost_wait_card_active(const sdmmc_host_t *host)
- {
- sdxc_wait_card_active(host->host_param.base);
- sdmmchost_delay_ms(host, 10);
- }
- static hpm_stat_t sdmmchost_wait_command_done(const sdmmc_host_t *host, uint32_t timeout_ms)
- {
- hpm_stat_t status = status_success;
- SDMMCHOST_Type *base = host->host_param.base;
- const uint32_t event_to_wait = SDXC_INT_STAT_CMD_COMPLETE_MASK | SDXC_INT_STAT_ERR_INTERRUPT_MASK;
- do {
- #if defined(HPM_SDMMC_HOST_ENABLE_IRQ) && (HPM_SDMMC_HOST_ENABLE_IRQ == 1)
- status = hpm_sdmmc_osal_event_wait((void *) host, host->xfer_done_or_error_event, event_to_wait, timeout_ms);
- if (status != status_success) {
- break;
- }
- #else
- bool has_done_or_error;
- bool timeout_occurred;
- uint64_t start_ticks = hpm_csr_get_core_mcycle();
- uint32_t ticks_per_ms = clock_get_core_clock_ticks_per_ms();
- uint64_t timeout_ticks = start_ticks + (timeout_ms * ticks_per_ms);
- do {
- uint32_t int_stat = sdxc_get_interrupt_status(base);
- has_done_or_error = IS_HPM_BITMASK_SET(int_stat, event_to_wait);
- timeout_occurred = (hpm_csr_get_core_mcycle() > timeout_ticks);
- } while ((!has_done_or_error) && (!timeout_occurred));
- if (timeout_occurred) {
- break;
- }
- #endif
- } while (false);
- status = sdxc_parse_interrupt_status(base);
- sdxc_clear_interrupt_status(base, event_to_wait);
- return status;
- }
- static hpm_stat_t sdmmchost_wait_xfer_done(sdmmc_host_t *host, uint32_t timeout_ms)
- {
- hpm_stat_t status = status_success;
- SDMMCHOST_Type *base = host->host_param.base;
- const uint32_t event_to_wait = SDXC_INT_STAT_XFER_COMPLETE_MASK | SDXC_INT_STAT_ERR_INTERRUPT_MASK;
- do {
- #if defined(HPM_SDMMC_HOST_ENABLE_IRQ) && (HPM_SDMMC_HOST_ENABLE_IRQ == 1)
- status = hpm_sdmmc_osal_event_wait(host, host->xfer_done_or_error_event, event_to_wait, timeout_ms);
- if (status != status_success) {
- break;
- }
- #else
- bool has_done_or_error;
- bool timeout_occurred;
- uint64_t start_ticks = hpm_csr_get_core_mcycle();
- uint32_t ticks_per_ms = clock_get_core_clock_ticks_per_ms();
- uint64_t timeout_ticks = start_ticks + (timeout_ms * ticks_per_ms);
- do {
- uint32_t int_stat = sdxc_get_interrupt_status(base);
- has_done_or_error = IS_HPM_BITMASK_SET(int_stat, event_to_wait);
- timeout_occurred = (hpm_csr_get_core_mcycle() > timeout_ticks);
- } while ((!has_done_or_error) && (!timeout_occurred));
- if (timeout_occurred) {
- break;
- }
- #endif
- } while (false);
- status = sdxc_parse_interrupt_status(base);
- sdxc_clear_interrupt_status(base, event_to_wait);
- return status;
- }
- static hpm_stat_t sdmmchost_wait_idle(const sdmmc_host_t *host)
- {
- /* Wait a while until the BUS is idle after the previous command */
- uint32_t wait_cnt = 1000L;
- while (!sdxc_is_bus_idle(host->host_param.base) && (wait_cnt > 0U)) {
- wait_cnt--;
- sdmmchost_delay_ms(host, 1);
- }
- if (wait_cnt == 0) {
- return status_timeout;
- }
- return status_success;
- }
- hpm_stat_t sdmmchost_send_command(sdmmc_host_t *host, const sdmmchost_cmd_t *cmd)
- {
- hpm_stat_t status;
- SDXC_Type *base = NULL;
- do {
- status = sdmmchost_check_host_availability(host);
- if (status != status_success) {
- break;
- }
- status = sdmmchost_wait_idle(host);
- if (status != status_success) {
- break;
- }
- base = host->host_param.base;
- status = sdxc_send_command(base, cmd);
- if (status != status_success) {
- break;
- }
- uint32_t timeout_ms = (cmd->cmd_timeout_ms == 0) ? HPM_SDMMC_HOST_TIMEOUT_DEFAULT : cmd->cmd_timeout_ms;
- status = sdmmchost_wait_command_done(host, timeout_ms);
- if (status != status_success) {
- break;
- }
- if (cmd->resp_type == (sdxc_dev_resp_type_t) sdmmc_resp_r1b) {
- status = sdmmchost_wait_xfer_done(host, timeout_ms);
- if ((status != status_success) && (status != status_timeout)) {
- break;
- }
- }
- status = sdxc_receive_cmd_response(host->host_param.base, &host->cmd);
- } while (false);
- if (status != status_success) {
- sdmmchost_error_recovery(host, NULL);
- }
- return status;
- }
- hpm_stat_t sdmmchost_transfer(sdmmc_host_t *host, const sdmmchost_xfer_t *content)
- {
- hpm_stat_t status;
- do {
- status = sdmmchost_check_host_availability(host);
- if (status != status_success) {
- break;
- }
- status = sdmmchost_wait_idle(host);
- if (status != status_success) {
- break;
- }
- SDXC_Type *base = host->host_param.base;
- sdxc_adma_config_t dma_config = { 0 };
- uint32_t timeout_ms = HPM_SDMMC_HOST_TIMEOUT_DEFAULT;
- if (content->data != NULL) {
- #if defined(HPM_SDMMC_USE_ADMA2) && (HPM_SDMMC_USE_ADMA2 == 1)
- dma_config.dma_type = sdxc_dmasel_adma2;
- #else
- dma_config.dma_type = sdxc_dmasel_adma3;
- #endif
- /* Ensure the ADMA descriptor starts at 8-byte aligned address */
- dma_config.adma_table = (uint32_t *)HPM_ALIGN_UP(&host->adma_table, HPM_SDMMC_HOST_ADMA3_ALIGN_SIZE);
- dma_config.adma_table_words = HPM_SDMMC_HOST_ADMA_TBL_SIZE;
- /***************************************************************************************************************
- * Calculate the data timeout interval in millisecond =
- * (block_count * block_size) / tx_rx_bytes_per_sec * 1000 + margin time
- * Here set the margin time to 500 milliseconds
- **************************************************************************************************************/
- uint32_t bus_width = sdxc_get_data_bus_width(host->host_param.base);
- uint32_t tx_rx_bytes_per_sec = host->clock_freq * bus_width / 8;
- uint32_t block_cnt = content->data->block_cnt;
- uint32_t block_size = content->data->block_size;
- uint32_t read_write_size = block_cnt * block_size;
- timeout_ms = (uint32_t) (1.0f * read_write_size / tx_rx_bytes_per_sec) * 1000 + 500;
- sdxc_set_data_timeout(base, timeout_ms, NULL);
- }
- if (dma_config.dma_type == sdxc_dmasel_adma3) {
- sdxc_clear_interrupt_status(base, ~0U);
- }
- status = sdxc_transfer_nonblocking(base, &dma_config, content);
- if (status != status_success) {
- break;
- }
- if (dma_config.dma_type != sdxc_dmasel_adma3) {
- status = sdmmchost_wait_command_done(host, HPM_SDMMC_HOST_TIMEOUT_DEFAULT);
- if (status != status_success) {
- break;
- }
- }
- status = sdxc_parse_interrupt_status(base);
- if (status != status_success) {
- break;
- }
- if (content->data != NULL) {
- status = sdmmchost_wait_xfer_done(host, timeout_ms);
- if (status != status_success) {
- break;
- }
- }
- status = sdxc_receive_cmd_response(host->host_param.base, &host->cmd);
- } while (false);
- return status;
- }
- hpm_stat_t sdmmchost_set_speed_mode(const sdmmc_host_t *host, sdmmc_speed_mode_t speed_mode)
- {
- if ((host == NULL) || (host->host_param.base == NULL)) {
- return status_invalid_argument;
- }
- sdxc_set_speed_mode(host->host_param.base, (sdxc_speed_mode_t) speed_mode);
- return status_success;
- }
- hpm_stat_t sdmmchost_error_recovery(sdmmc_host_t *host, sdmmchost_cmd_t *cmd)
- {
- return sdxc_error_recovery(host->host_param.base, cmd);
- }
- void sdmmchost_set_cardclk_delay_chain(const sdmmc_host_t *host)
- {
- SDXC_Type *base = host->host_param.base;
- bool need_inverse = sdxc_is_inverse_clock_enabled(base);
- sdxc_enable_inverse_clock(base, false);
- sdxc_enable_sd_clock(base, false);
- uint32_t num_delaycells = sdxc_get_default_cardclk_delay_chain(base, host->clock_freq);
- sdxc_set_cardclk_delay_chain(host->host_param.base, num_delaycells);
- sdxc_enable_inverse_clock(base, need_inverse);
- sdxc_enable_sd_clock(base, true);
- }
- bool sdmmchost_is_8bit_supported(const sdmmc_host_t *host)
- {
- return IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_8BIT);
- }
- bool sdmmchost_is_voltage_switch_supported(const sdmmc_host_t *host)
- {
- return IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_VOLTAGE_SWITCH);
- }
- void sdmmchost_power_control(const sdmmc_host_t *host, hpm_sdmmc_power_option_t option)
- {
- if (IS_HPM_BITMASK_SET(host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_POWER_SWITCH)) {
- const hpm_sdmmc_pin_info_t *pin_info = &host->host_param.io_data.pwr_pin;
- const sdmmc_io_init_apis_t *init_apis = &host->host_param.io_init_apis;
- bool use_gpio = pin_info->use_gpio;
- SDMMCHOST_Type *base = host->host_param.base;
- init_apis->pwr_io_init(base, use_gpio);
- if (pin_info->use_gpio) {
- uint32_t gpio_index = pin_info->gpio_pin / 32;
- uint32_t pin_index = pin_info->gpio_pin % 32;
- volatile uint32_t *gpio_reg_off = (pin_info->polarity == 0)
- ? &HPM_GPIO0->DO[gpio_index].CLEAR
- : &HPM_GPIO0->DO[gpio_index].SET;
- volatile uint32_t *gpio_reg_on = (pin_info->polarity == 0)
- ? &HPM_GPIO0->DO[gpio_index].SET
- : &HPM_GPIO0->DO[gpio_index].CLEAR;
- HPM_GPIO0->OE[gpio_index].SET = (1UL << pin_index);
- if (option == hpm_sdmmc_power_off) {
- *gpio_reg_off = (1UL << pin_index);
- } else if (option == hpm_sdmmc_power_on) {
- *gpio_reg_on = (1UL << pin_index);
- } else {
- *gpio_reg_off = (1UL << pin_index);
- host->host_param.delay_ms(1);
- *gpio_reg_on = (1UL << pin_index);
- }
- } else {
- if (option == hpm_sdmmc_power_off) {
- sdxc_enable_power(host->host_param.base, false);
- } else if (option == hpm_sdmmc_power_on) {
- sdxc_enable_power(host->host_param.base, true);
- } else {
- sdxc_enable_power(host->host_param.base, false);
- host->host_param.delay_ms(1);
- sdxc_enable_power(host->host_param.base, true);
- }
- }
- host->host_param.delay_ms(1);
- }
- }
- void sdmmchost_init_io(sdmmc_host_t *host, hpm_sdmmc_operation_mode_t operation_mode)
- {
- bool as_gpio;
- const sdmmc_io_init_apis_t *init_apis = &host->host_param.io_init_apis;
- SDMMCHOST_Type *base = host->host_param.base;
- uint32_t host_flags = host->host_param.host_flags;
- if (operation_mode == hpm_sdmmc_operation_mode_inactive) {
- uint32_t bus_width = host->bus_width;
- const hpm_sdmmc_pin_info_t *pin_info;
- bool support_3v3 = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_3V3);
- host->io_voltage = support_3v3 ? hpm_sdmmc_io_voltage_3v3 : hpm_sdmmc_io_voltage_1v8;
- /* Initialize IO */
- bool support_pwr = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_POWER_SWITCH);
- if (support_pwr) {
- pin_info = &host->host_param.io_data.pwr_pin;
- as_gpio = pin_info->use_gpio;
- if (init_apis->pwr_io_init != NULL) {
- init_apis->pwr_io_init(base, as_gpio);
- }
- }
- bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
- init_apis->cmd_io_init(base, true, is_1v8); /* Configure CMD pin to open-drain mode */
- init_apis->clk_data_io_init(base, bus_width, is_1v8);
- bool support_cd = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_CARD_DETECTION);
- if (support_cd) {
- pin_info = &host->host_param.io_data.cd_pin;
- as_gpio = pin_info->use_gpio;
- if (init_apis->cd_io_init != NULL) {
- init_apis->cd_io_init(base, as_gpio);
- }
- }
- bool support_vsel = sdmmchost_is_voltage_switch_supported(host);
- if (support_vsel) {
- pin_info = &host->host_param.io_data.vsel_pin;
- as_gpio = pin_info->use_gpio;
- if (init_apis->vsel_io_init != NULL) {
- init_apis->vsel_io_init(base, as_gpio);
- }
- /* Since eMMC device doesn't support dynamic voltage switch, so set the voltage at initialization phase */
- if (!support_3v3) {
- sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_1v8);
- sdmmchost_select_voltage(host, hpm_sdmmc_io_voltage_1v8);
- }
- }
- } else if (operation_mode == hpm_sdmmc_operation_mode_identification) {
- bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
- bool is_opendrain = true;
- init_apis->cmd_io_init(base, is_opendrain, is_1v8);
- uint32_t bus_width = 1;
- switch (host->bus_width) {
- case sdmmc_bus_width_4bit:
- bus_width = 4;
- break;
- case sdmmc_bus_width_8bit:
- bus_width = 8;
- break;
- default:
- bus_width = 1;
- break;
- }
- init_apis->clk_data_io_init(base, bus_width, is_1v8);
- bool support_ds = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_HS400);
- if (support_ds) {
- init_apis->ds_io_init(base);
- }
- } else if (operation_mode == hpm_sdmmc_operation_mode_transfer) {
- bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
- bool is_opendrain = false;
- init_apis->cmd_io_init(base, is_opendrain, is_1v8);
- uint32_t bus_width = 1;
- switch (host->bus_width) {
- case sdmmc_bus_width_4bit:
- bus_width = 4;
- break;
- case sdmmc_bus_width_8bit:
- bus_width = 8;
- break;
- default:
- bus_width = 1;
- break;
- }
- init_apis->clk_data_io_init(base, bus_width, is_1v8);
- bool support_ds = IS_HPM_BITMASK_SET(host_flags, HPM_SDMMC_HOST_SUPPORT_HS400);
- if (support_ds) {
- init_apis->ds_io_init(base);
- }
- } else if (operation_mode == hpm_sdmmc_operation_mode_interrupt) {
- bool is_1v8 = host->io_voltage == hpm_sdmmc_io_voltage_3v3 ? false : true;
- bool is_opendrain = true;
- init_apis->cmd_io_init(base, is_opendrain, is_1v8);
- } else {
- /* DO nothing */
- }
- /* Wait a while in case the IO initialization requires small delays to get effective */
- for (volatile uint32_t delay_cnt = 100; delay_cnt > 0; delay_cnt--) {
- NOP();
- }
- }
- void sdmmchost_enable_enhanced_data_strobe(const sdmmc_host_t *host, bool enable)
- {
- sdxc_enable_enhanced_strobe(host->host_param.base, enable);
- }
- void sdmmchost_set_data_strobe_delay(const sdmmc_host_t *host)
- {
- uint32_t num_delaycells = sdxc_get_default_strobe_delay(host->host_param.base);
- sdxc_set_data_strobe_delay(host->host_param.base, num_delaycells);
- }
- void sdmmchost_select_voltage(sdmmc_host_t *host, hpm_sdmmc_io_volt_t io_volt)
- {
- sdxc_bus_voltage_option_t vsel = sdxc_bus_voltage_sd_3v3;
- if (io_volt == hpm_sdmmc_io_voltage_1v8) {
- vsel = sdxc_bus_voltage_sd_1v8;
- host->io_voltage = hpm_sdmmc_io_voltage_1v8;
- } else {
- host->io_voltage = hpm_sdmmc_io_voltage_3v3;
- }
- sdxc_select_voltage(host->host_param.base, vsel);
- }
- ATTR_RAMFUNC void sdmmchost_irq_handler(sdmmc_host_t *host)
- {
- SDXC_Type *base = host->host_param.base;
- uint32_t int_stat = sdxc_get_interrupt_status(base);
- uint32_t int_signal_en = sdxc_get_interrupt_signal(base);
- if (((int_stat & SDXC_INT_STAT_CARD_INTERRUPT_MASK) != 0) &&
- ((int_signal_en & SDXC_INT_STAT_CARD_INTERRUPT_MASK) != 0)) {
- if (host->sdio_irq_handler != NULL) {
- host->sdio_irq_handler(host->sdio_irq_param);
- }
- sdmmchost_enable_sdio_interrupt(host, false);
- }
- #if defined(HPM_SDMMC_HOST_ENABLE_IRQ) && (HPM_SDMMC_HOST_ENABLE_IRQ == 1)
- const uint32_t xfer_done_or_err_int_mask = SDXC_INT_STAT_CMD_COMPLETE_MASK | SDXC_INT_STAT_XFER_COMPLETE_MASK | SDXC_INT_STAT_ERR_INTERRUPT_MASK;
- hpm_sdmmc_osal_event_clear(host, host->xfer_done_or_error_event, xfer_done_or_err_int_mask);
- if ((int_signal_en & xfer_done_or_err_int_mask) && (int_stat & xfer_done_or_err_int_mask)) {
- uint32_t event_flags = int_stat & xfer_done_or_err_int_mask;
- hpm_sdmmc_osal_event_set(host, host->xfer_done_or_error_event, event_flags);
- sdxc_clear_interrupt_status(base, event_flags);
- }
- #endif
- }
- void sdmmchost_enable_sdio_interrupt(sdmmc_host_t *host, bool enable)
- {
- if (host != NULL) {
- if (enable) {
- sdxc_enable_interrupt_signal(host->host_param.base, SDXC_INT_STAT_CARD_INTERRUPT_MASK, true);
- sdxc_enable_interrupt_status(host->host_param.base, SDXC_INT_STAT_CARD_INTERRUPT_MASK, true);
- } else {
- sdxc_enable_interrupt_status(host->host_param.base, SDXC_INT_STAT_CARD_INTERRUPT_MASK, false);
- }
- }
- }
- void sdmmchost_register_sdio_callback(sdmmc_host_t *host, void (*sdio_irq_callback)(void *param), void *param)
- {
- if (host != NULL) {
- host->sdio_irq_handler = sdio_irq_callback;
- host->sdio_irq_param = param;
- }
- }
- uint32_t sdmmchost_get_data_pin_level(sdmmc_host_t *host)
- {
- uint32_t data_pin_level = 0;
- if ((host != NULL) && (host->host_param.base != NULL)) {
- SDXC_Type *base = host->host_param.base;
- data_pin_level = sdxc_get_data3_0_level(base);
- if (sdmmchost_is_8bit_supported(host)) {
- data_pin_level |= (sdxc_get_data7_4_level(base) << 4);
- }
- }
- return data_pin_level;
- }
|