| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- /*
- * Copyright (c) 2021-2024 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
- #include "hpm_sdmmc_common.h"
- #include "hpm_sdmmc_card.h"
- #include <string.h>
- hpm_stat_t sdmmc_go_idle_state(sdmmc_host_t *host, uint32_t argument)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(host == NULL);
- sdmmchost_cmd_t *host_cmd = &host->cmd;
- (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
- host_cmd->cmd_index = sdmmc_cmd_go_idle_state;
- host_cmd->cmd_argument = argument;
- host_cmd->resp_type = sdxc_dev_resp_none;
- status = sdmmchost_send_command(host, host_cmd);
- } while (false);
- return status;
- }
- hpm_stat_t sdmmc_go_inactive_state(sdmmc_host_t *host, uint16_t relative_addr)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(host == NULL);
- sdmmchost_cmd_t *host_cmd = &host->cmd;
- (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
- host_cmd->cmd_index = sdmmc_cmd_go_inactive_state;
- host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
- host_cmd->resp_type = sdxc_dev_resp_none;
- status = sdmmchost_send_command(host, host_cmd);
- } while (false);
- return status;
- }
- hpm_stat_t sdmmc_select_card(sdmmc_host_t *host, uint16_t relative_addr, bool is_selected)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(host == NULL);
- sdmmchost_cmd_t *host_cmd = &host->cmd;
- (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
- host_cmd->cmd_index = sdmmc_cmd_select_card;
- host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
- if (is_selected) {
- host_cmd->resp_type = sdxc_dev_resp_r1b;
- } else {
- host_cmd->resp_type = sdxc_dev_resp_none;
- }
- status = sdmmchost_send_command(host, host_cmd);
- } while (false);
- return status;
- }
- hpm_stat_t sdmmc_send_application_command(sdmmc_host_t *host, uint16_t relative_addr)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(host == NULL);
- sdmmchost_cmd_t *host_cmd = &host->cmd;
- (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
- host_cmd->cmd_index = sdmmc_cmd_app_cmd;
- host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
- host_cmd->resp_type = sdxc_dev_resp_r1;
- status = sdmmchost_send_command(host, host_cmd);
- } while (false);
- return status;
- }
- hpm_stat_t sdmmc_set_block_count(sdmmc_host_t *host, uint32_t block_count)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(host == NULL);
- sdmmchost_cmd_t *host_cmd = &host->cmd;
- (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
- host_cmd->cmd_index = sdmmc_cmd_set_block_count;
- host_cmd->cmd_argument = block_count;
- host_cmd->resp_type = sdxc_dev_resp_r1;
- status = sdmmchost_send_command(host, host_cmd);
- } while (false);
- return status;
- }
- hpm_stat_t sdmmc_set_block_size(sdmmc_host_t *host, uint32_t block_size)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(host == NULL);
- sdmmchost_cmd_t *host_cmd = &host->cmd;
- (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
- host_cmd->cmd_index = sdmmc_cmd_set_block_length;
- host_cmd->cmd_argument = block_size;
- host_cmd->resp_type = sdxc_dev_resp_r1;
- status = sdmmchost_send_command(host, host_cmd);
- } while (false);
- return status;
- }
- hpm_stat_t sdmmc_enable_auto_tuning(const sdmmc_host_t *host)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((host == NULL) || (host->host_param.base == NULL));
- SDXC_Type *base = host->host_param.base;
- /* Prepare the Auto tuning environment */
- sdxc_stop_clock_during_phase_code_change(base, true);
- sdxc_set_post_change_delay(base, 3U);
- sdxc_select_cardclk_delay_source(base, false);
- sdxc_enable_power(base, true);
- /* Start Auto tuning */
- uint8_t tuning_cmd = (host->dev_type == sdmmc_dev_type_sd) ? 19U : 21U;
- status = sdxc_perform_auto_tuning(host->host_param.base, tuning_cmd);
- HPM_BREAK_IF(status != status_success);
- } while (false);
- return status;
- }
- uint32_t extract_csd_field(const uint32_t *raw_csd, uint8_t end_offset, uint8_t start_offset)
- {
- uint32_t result = 0;
- uint32_t start_word_index = start_offset / 32;
- uint32_t end_word_index = end_offset / 32;
- uint32_t end_offset_in_word = end_offset % 32;
- uint32_t start_offset_in_word = start_offset % 32;
- /* If all bits of the field are in the same raw_csd word */
- if (start_word_index == end_word_index) {
- uint32_t field_width = end_offset - start_offset + 1U;
- uint32_t field_mask = ((1UL << field_width) - 1U) << start_offset;
- result = (raw_csd[start_word_index] & field_mask) >> start_offset_in_word;
- } else {
- /* If the bits of the field crosses two raw_csd words */
- uint32_t lsb_width = 32U - start_offset_in_word;
- uint32_t result_lsb = raw_csd[start_word_index] >> start_offset_in_word;
- uint32_t msb_width = end_offset_in_word + 1UL;
- uint32_t result_msb = raw_csd[end_word_index] & ((1UL << msb_width) - 1U);
- result = (result_msb << lsb_width) | result_lsb;
- }
- return result;
- }
|