| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171 |
- /*
- * Copyright (c) 2021-2024 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
- #include "hpm_sdmmc_emmc.h"
- #include "hpm_l1c_drv.h"
- #include "hpm_clock_drv.h"
- #define SPEED_1Kbps (1000U)
- #define SPEED_1Mbps (1000UL * 1000UL)
- #define MAX_BLOCK_COUNT ((1UL << 26) / 512 - 1U)
- #define WRITE_BLOCK_TIMEOUT_IN_MS (1000U)
- #define READ_BLOCK_TIMEOUT_IN_MS (100U)
- #define EMMC_SECTOR_SIZE_DEFAULT (512U)
- #define SIZE_128KB (128UL * SIZE_1KB)
- #define SIZE_512KB (512UL * SIZE_1KB)
- #define EMMC_RCA_DEFAULT (1U)
- #define EMMC_CSD_VERSION_MAX (2U)
- #define EMMC_EXT_CSD_REV_MAX (8U)
- #define EMMC_CMD_SET_REV_MAX (0U)
- #define EXT_CSD_SECURE_WP_INFO_SECURE_WP_SUPPORT_MASK (1U)
- #define EXT_CSD_SECURE_WP_INFO_SECURE_WP_EN_STATUS (2U)
- #define EXT_CSD_BOOT_INFO_ALT_BOOT_MODE_MASK (1U)
- #define EXT_CSD_BOOT_INFO_DDR_BOOT_MODE_MASK (2U)
- #define EXT_CSD_BOOT_INFO_HS_BOOT_MODE_MASK (4U)
- #define EXT_CSD_SEC_FEATURE_SUPPORT_SECURE_ER_EN_MASK (1UL << 0)
- #define EXT_CSD_SEC_FEATURE_SUPPORT_SEC_BD_BLK_EN_MASK (1UL << 2)
- #define EXT_CSD_SEC_FEATURE_SUPPORT_SEC_GB_CL_EN_MASK (1UL << 4)
- #define EXT_CSD_SEC_FEATURE_SUPPORT_SEC_SANITIZE_MASK (1UL << 6)
- #define EXT_CSD_ERASE_GROUP_DEF_ENABLE_MASK (1UL << 0)
- #define EXT_CSD_HS_TIMING_COMPATIBLE (0U)
- #define EXT_CSD_HS_TIMING_HIGH_SPEED (1U)
- #define EXT_CSD_HS_TIMING_HS200 (2U)
- #define EXT_CSD_HS_TIMING_HS400 (3U)
- /**
- * @brief Set Relative Address
- */
- static hpm_stat_t emmc_set_rca(emmc_card_t *card, uint16_t relative_addr);
- /**
- * @brief Send CSD register
- */
- static hpm_stat_t emmc_send_csd(emmc_card_t *card);
- /**
- * @brief Send Extend CSD register
- */
- static hpm_stat_t emmc_send_ext_csd(emmc_card_t *card);
- /* Decode Extend CSD */
- static hpm_stat_t emmc_decode_ext_csd(emmc_card_t *card, const emmc_ext_csd_t *ext_csd);
- /* Polling Card Status register when the card is busy */
- static hpm_stat_t emmc_polling_card_status_busy(emmc_card_t *card, uint32_t timeout_ms);
- /* Send OP Condition command */
- static hpm_stat_t emmc_send_op_cond(const emmc_card_t *card, emmc_ocr_t ocr);
- /* Decode CSD register */
- static void emmc_decode_csd(emmc_card_t *card, const uint32_t *raw_csd);
- /* Set eMMC Bus Width */
- static hpm_stat_t emmc_set_bus_width(const emmc_card_t *card, emmc_bus_mode_t bus_mode);
- /* Set eMMC HS Timing */
- static hpm_stat_t emmc_set_hs_timing(emmc_card_t *card, emmc_hs_timing_t timing);
- /* Check */
- static hpm_stat_t emmc_check_card_parameters(const emmc_card_t *card);
- static hpm_stat_t emmc_error_recovery(const emmc_card_t *card);
- static hpm_stat_t emmc_send_cmd(const emmc_card_t *card, const sdmmchost_cmd_t *cmd);
- static hpm_stat_t emmc_transfer(const emmc_card_t *card, const sdmmchost_xfer_t *content);
- static hpm_stat_t emmc_send_cmd(const emmc_card_t *card, const sdmmchost_cmd_t *cmd)
- {
- hpm_stat_t status = sdmmchost_send_command(card->host, cmd);
- if ((status >= status_sdxc_busy) && (status <= status_sdxc_tuning_failed)) {
- hpm_stat_t error_recovery_status = emmc_error_recovery(card);
- if (error_recovery_status != status_success) {
- status = error_recovery_status;
- }
- }
- return status;
- }
- static hpm_stat_t emmc_transfer(const emmc_card_t *card, const sdmmchost_xfer_t *content)
- {
- hpm_stat_t status = sdmmchost_transfer(card->host, content);
- if ((status >= status_sdxc_busy) && (status <= status_sdxc_tuning_failed)) {
- hpm_stat_t error_recovery_status = emmc_error_recovery(card);
- if (error_recovery_status != status_success) {
- status = error_recovery_status;
- }
- }
- return status;
- }
- static hpm_stat_t emmc_send_card_status(emmc_card_t *card)
- {
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- memset(cmd, 0, sizeof(*cmd));
- cmd->cmd_index = sdmmc_cmd_send_status;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1;
- cmd->cmd_argument = (uint32_t) card->relative_addr << 16;
- hpm_stat_t status = emmc_send_cmd(card, cmd);
- if (status != status_success) {
- return status;
- }
- card->current_r1_status.card_status = cmd->response[0];
- return status;
- }
- static hpm_stat_t emmc_send_op_cond(const emmc_card_t *card, emmc_ocr_t ocr)
- {
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_send_op_cond;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r3;
- cmd->cmd_argument = ocr.ocr_word;
- hpm_stat_t status = emmc_send_cmd(card, cmd);
- if (status != status_success) {
- return status;
- }
- return status_success;
- }
- static void emmc_decode_csd(emmc_card_t *card, const uint32_t *raw_csd)
- {
- emmc_csd_t *csd = &card->csd;
- csd->sector_size = EMMC_SECTOR_SIZE_DEFAULT;
- csd->csd_structure = extract_csd_field(raw_csd, 127, 126);
- csd->spec_version = (uint8_t) extract_csd_field(raw_csd, 125, 122);
- uint8_t taac = (uint8_t) extract_csd_field(raw_csd, 119, 112);
- uint8_t nsac = (uint8_t) extract_csd_field(raw_csd, 111, 104);
- uint32_t taac_time_unit_ns[8] = {1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL};
- uint32_t taac_mult_factor[16] = {0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80};
- uint8_t taac_time_unit = taac & 0x07;
- uint8_t taac_mult_fact = (taac >> 3) & 0xFU;
- csd->taac_ns = taac_time_unit_ns[taac_time_unit] * taac_mult_factor[taac_mult_fact];
- csd->nsac_cycles = 100UL * nsac;
- uint32_t tran_speed = (uint8_t) extract_csd_field(raw_csd, 103, 96);
- uint32_t bitrate_unit = tran_speed & 0x7U;
- uint32_t time_value = (tran_speed >> 3) & 0xFU;
- const uint32_t bitrate_unit_list[8] = {100UL * SPEED_1Kbps, SPEED_1Mbps, 10U * SPEED_1Mbps, 100U * SPEED_1Mbps, 0,
- 0, 0, 0};
- const uint32_t time_value_list[16] = {0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80};
- csd->max_freq = bitrate_unit_list[bitrate_unit] / 10U * time_value_list[time_value];
- csd->card_command_class = (uint16_t) extract_csd_field(raw_csd, 95, 84);
- uint32_t read_bl_len = (uint8_t) extract_csd_field(raw_csd, 83, 80);
- csd->max_read_block_len = 1UL << read_bl_len;
- csd->support_read_block_partial = (extract_csd_field(raw_csd, 79, 79) != 0);
- csd->support_write_block_misalignment = (extract_csd_field(raw_csd, 78, 78) != 0);
- csd->support_read_block_misalignment = (extract_csd_field(raw_csd, 77, 77) != 0);
- csd->is_dsr_implemented = (extract_csd_field(raw_csd, 76, 76) != 0);
- /* TODO */
- uint32_t c_size = (uint32_t) extract_csd_field(raw_csd, 73, 62);
- uint32_t c_size_mult = (uint8_t) extract_csd_field(raw_csd, 49, 47);
- uint32_t num_of_blocks = (c_size + 1U) * (4UL << c_size_mult);
- csd->device_size_in_bytes = (uint64_t) num_of_blocks * csd->max_read_block_len;
- csd->read_current_vdd_min = (emmc_csd_vdd_current_min_t) extract_csd_field(raw_csd, 61, 59);
- csd->read_current_vdd_max = (emmc_csd_vdd_current_max_t) extract_csd_field(raw_csd, 58, 56);
- csd->write_current_vdd_min = (emmc_csd_vdd_current_min_t) extract_csd_field(raw_csd, 55, 53);
- csd->write_current_vdd_max = (emmc_csd_vdd_current_max_t) extract_csd_field(raw_csd, 52, 50);
- uint32_t erase_group_size = extract_csd_field(raw_csd, 46, 42);
- uint32_t erase_group_multiplier = extract_csd_field(raw_csd, 41, 37);
- uint32_t wp_group_size = extract_csd_field(raw_csd, 36, 32);
- /* TODO: check the unit later */
- csd->erase_group_size = (erase_group_size + 1U) * (erase_group_multiplier + 1U);
- csd->write_protect_group_size = (1U + wp_group_size) * csd->erase_group_size;
- csd->is_write_protection_group_enabled = (extract_csd_field(raw_csd, 31, 31) != 0);
- uint32_t r2w_factor = extract_csd_field(raw_csd, 28, 26);
- uint32_t write_bl_len = extract_csd_field(raw_csd, 25, 22);
- csd->max_write_block_len = 1UL << write_bl_len;
- csd->write_speed_factor = (1U << r2w_factor);
- csd->support_write_block_partial = (extract_csd_field(raw_csd, 21, 21) != 0);
- csd->support_content_protect_app = (extract_csd_field(raw_csd, 16, 16) != 0);
- csd->is_predefined_file_format = (extract_csd_field(raw_csd, 15, 15) != 0);
- csd->support_copy = (extract_csd_field(raw_csd, 14, 14) != 0);
- csd->support_permanent_write_protect = (extract_csd_field(raw_csd, 13, 13) != 0);
- csd->support_temporary_write_protect = (extract_csd_field(raw_csd, 12, 12) != 0);
- csd->file_format = (uint8_t) extract_csd_field(raw_csd, 11, 10);
- csd->ecc_type = (uint8_t) extract_csd_field(raw_csd, 9, 8);
- }
- static hpm_stat_t emmc_send_csd(emmc_card_t *card)
- {
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_send_csd;
- cmd->cmd_argument = (uint32_t) card->relative_addr << 16;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r2;
- hpm_stat_t status = emmc_send_cmd(card, cmd);
- if (status != status_success) {
- return status;
- }
- uint32_t temp_buf[4];
- memcpy(temp_buf, cmd->response, sizeof(temp_buf));
- emmc_decode_csd(card, temp_buf);
- return status_success;
- }
- static uint32_t emmc_get_24bit_num_from_ext_csd(const uint8_t *array)
- {
- uint32_t value = array[0] | (((uint32_t) array[1]) << 8) | (((uint32_t) array[2]) << 16);
- return value;
- }
- static hpm_stat_t emmc_decode_ext_csd(emmc_card_t *card, const emmc_ext_csd_t *ext_csd)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(ext_csd->csd_structure > EMMC_CSD_VERSION_MAX);
- HPM_BREAK_IF(ext_csd->ext_csd_rev > EMMC_EXT_CSD_REV_MAX);
- HPM_BREAK_IF(ext_csd->cmd_set_revision > EMMC_CMD_SET_REV_MAX);
- emmc_device_attribute_t *attr = (emmc_device_attribute_t *) &card->device_attribute;
- attr->is_secure_write_protection_supported = (
- (ext_csd->secure_wp_info & EXT_CSD_SECURE_WP_INFO_SECURE_WP_SUPPORT_MASK) != 0);
- attr->write_protection_mode = ((ext_csd->secure_wp_info & EXT_CSD_SECURE_WP_INFO_SECURE_WP_EN_STATUS) != 0)
- ? emmc_write_protection_mode_secure : emmc_write_protection_mode_legacy;
- attr->boot_info.is_alt_boot_mode_supported = IS_HPM_BITMASK_SET(ext_csd->boot_info,
- EXT_CSD_BOOT_INFO_ALT_BOOT_MODE_MASK);
- attr->boot_info.is_ddr_boot_mode_supported = IS_HPM_BITMASK_SET(ext_csd->boot_info,
- EXT_CSD_BOOT_INFO_DDR_BOOT_MODE_MASK);
- attr->boot_info.is_hs_boot_mode_supported = IS_HPM_BITMASK_SET(ext_csd->boot_info,
- EXT_CSD_BOOT_INFO_HS_BOOT_MODE_MASK);
- attr->secure_feature_info.is_secure_erase_supported = IS_HPM_BITMASK_SET(ext_csd->secure_feature_support,
- EXT_CSD_SEC_FEATURE_SUPPORT_SECURE_ER_EN_MASK);
- attr->secure_feature_info.is_secure_bad_block_management_supported = IS_HPM_BITMASK_SET(
- ext_csd->secure_feature_support, EXT_CSD_SEC_FEATURE_SUPPORT_SEC_BD_BLK_EN_MASK);
- attr->secure_feature_info.is_secure_insecure_trim_supported = IS_HPM_BITMASK_SET(
- ext_csd->secure_feature_support, EXT_CSD_SEC_FEATURE_SUPPORT_SEC_GB_CL_EN_MASK);
- attr->secure_feature_info.is_secure_sanitize_supported = IS_HPM_BITMASK_SET(ext_csd->secure_feature_support,
- EXT_CSD_SEC_FEATURE_SUPPORT_SEC_SANITIZE_MASK);
- attr->boot_partition_size = SIZE_128KB * ext_csd->boot_partition_size_mult;
- attr->rpmb_partition_size = SIZE_128KB * ext_csd->rpmb_size;
- attr->max_enhanced_area_size =
- SIZE_512KB * emmc_get_24bit_num_from_ext_csd(ext_csd->enhanced_user_data_area_size);
- for (uint32_t i = 0; i < 4; i++) {
- attr->gp_partition_size[i] =
- ext_csd->high_capacity_write_protect_group_size * ext_csd->high_capacity_erase_unit_size *
- SIZE_512KB * emmc_get_24bit_num_from_ext_csd(ext_csd->general_purpose_partition_size[i]);
- }
- attr->max_enhanced_area_size = SIZE_512KB * emmc_get_24bit_num_from_ext_csd(ext_csd->max_enh_size_mult) *
- ext_csd->high_capacity_write_protect_group_size *
- ext_csd->high_capacity_erase_unit_size;
- attr->super_page_size = 512 * (1UL << (ext_csd->access_size & 0x03));
- attr->write_protect_group_size =
- SIZE_512KB * ext_csd->high_capacity_erase_unit_size * ext_csd->high_capacity_write_protect_group_size;
- attr->erase_group_size = 512UL * ext_csd->high_capacity_erase_unit_size;
- attr->device_size_in_bytes = (uint64_t) 512UL * ext_csd->sector_count;
- attr->sector_count = ext_csd->sector_count;
- attr->sector_size = (ext_csd->data_sector_size == 0) ? 512U : 4U * SIZE_1KB;
- attr->device_type.device_type = ext_csd->device_type;
- attr->large_unit_size = SIZE_1MB * (ext_csd->large_unit_size + 1U);
- attr->optimal_read_size = 4U * SIZE_1KB * ext_csd->optimal_read_size;
- attr->optimal_write_size = 4U * SIZE_1KB * ext_csd->optimal_write_size;
- attr->optimal_trim_unit_size = 4U * SIZE_1KB * (1UL << ext_csd->optimal_trim_unit_size);
- attr->operation_codes_timeout_us = 100UL * (2U << ext_csd->operation_code_timeout);
- attr->switch_cmd_timeout_ms = 10UL * ext_csd->generic_cmd6_timeout;
- attr->power_off_timeout_ms = 10UL * ext_csd->power_off_long_timeout;
- attr->init_timeout_after_partition_ms = 100UL * ext_csd->init_timeout_after_partitioning;
- attr->trim_timeout_ms = 300UL * ext_csd->trim_mult;
- attr->secure_erase_timeout_ms = 300UL * ext_csd->secure_erase_mult;
- attr->secure_trim_timeout_ms = 300UL * ext_csd->secure_trim_mult;
- attr->erase_timeout_ms = 300UL * ext_csd->erase_timeout_mult;
- attr->partition_switch_timeout_ms = 100UL * ext_csd->partition_switch_timing;
- attr->out_of_interrupt_timeout_ms = 100UL * ext_csd->out_of_interrupt_timing;
- attr->sleep_notification_timeout_us = 10UL * (2UL << ext_csd->sleep_notification_timeout);
- attr->sleep_awake_timeout_ns = 100UL * (2UL << ext_csd->sleep_or_awake_timeout);
- attr->production_state_awareness_timeout_us = 100UL * (2UL << ext_csd->production_state_awareness_timeout);
- attr->sleep_current_vcc_ua = 2UL << ext_csd->sleep_current_vcc;
- attr->sleep_current_vccq_ua = 2UL << ext_csd->sleep_current_vccq;
- attr->use_high_capacity_erase_unit_size = IS_HPM_BITMASK_SET(ext_csd->erase_group_def,
- EXT_CSD_ERASE_GROUP_DEF_ENABLE_MASK);
- attr->is_all_0xffs_for_erased_region = IS_HPM_BITMASK_SET(ext_csd->erased_mem_content, 1);
- attr->is_enhanced_strobe_supported = IS_HPM_BITMASK_SET(ext_csd->strobe_support, 1);
- attr->is_cmd_queue_mode_enabled = IS_HPM_BITMASK_SET(ext_csd->cmdq_support, 1);
- status = status_success;
- } while (false);
- return status;
- }
- static hpm_stat_t emmc_send_ext_csd(emmc_card_t *card)
- {
- hpm_stat_t status;
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- sdmmchost_data_t *data = &card->host->data;
- sdmmchost_xfer_t *content = &card->host->xfer;
- memset(cmd, 0, sizeof(*cmd));
- memset(data, 0, sizeof(*data));
- memset(content, 0, sizeof(*content));
- do {
- cmd->cmd_index = emmc_cmd_send_ext_csd;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1;
- cmd->cmd_argument = 0;
- data->block_size = sizeof(emmc_ext_csd_t);
- data->block_cnt = 1;
- data->rx_data = (uint32_t *) sdmmc_get_sys_addr(card->host, (uint32_t) card->host->buffer);
- content->data = data;
- content->command = cmd;
- status = emmc_transfer(card, content);
- if (status != status_success) {
- break;
- }
- (void) memcpy(&card->ext_csd, card->host->buffer, sizeof(emmc_ext_csd_t));
- status = emmc_decode_ext_csd(card, &card->ext_csd);
- } while (false);
- return status;
- }
- static hpm_stat_t emmc_all_send_cid(emmc_card_t *card)
- {
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_all_send_cid;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r2;
- hpm_stat_t status = emmc_send_cmd(card, cmd);
- if (status != status_success) {
- return status;
- }
- for (uint32_t i = 0; i < 3; i++) {
- card->cid.cid_words[i] = cmd->response[i];
- }
- return status;
- }
- hpm_stat_t emmc_send_cid(emmc_card_t *card)
- {
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_send_cid;
- cmd->cmd_argument = card->relative_addr << 16;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r2;
- hpm_stat_t status = emmc_send_cmd(card, cmd);
- if (status != status_success) {
- return status;
- }
- for (uint32_t i = 0; i < 4; i++) {
- card->cid.cid_words[i] = cmd->response[i];
- }
- return status;
- }
- static hpm_stat_t emmc_set_rca(emmc_card_t *card, uint16_t relative_addr)
- {
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_set_relative_addr;
- cmd->cmd_argument = relative_addr << 16;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1;
- hpm_stat_t status = emmc_send_cmd(card, cmd);
- if (status != status_success) {
- return status;
- }
- card->relative_addr = relative_addr;
- return status;
- }
- static hpm_stat_t emmc_error_recovery(const emmc_card_t *card)
- {
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- cmd->cmd_index = sdmmc_cmd_stop_transmission;
- cmd->cmd_type = sdxc_cmd_type_abort_cmd;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1b;
- return sdmmchost_error_recovery(card->host, cmd);
- }
- static hpm_stat_t emmc_check_card_parameters(const emmc_card_t *card)
- {
- hpm_stat_t status;
- if ((card == NULL) || (card->host == NULL) || (card->host->host_param.base == NULL)) {
- status = status_invalid_argument;
- } else {
- status = status_success;
- }
- return status;
- }
- static hpm_stat_t emmc_set_bus_width(const emmc_card_t *card, emmc_bus_mode_t bus_mode)
- {
- emmc_switch_cmd_arg_t switch_arg = {.argument = 0U};
- switch_arg.access = emmc_switch_cmd_access_mode_write_byte;
- switch_arg.cmd_set = 0;
- switch_arg.index = EMMC_EXT_CSD_INDEX_BUS_WDITH;
- switch_arg.value = (uint8_t) bus_mode;
- hpm_stat_t status = emmc_switch_function(card, switch_arg, card->device_attribute.switch_cmd_timeout_ms * 1000U);
- if (status == status_success) {
- sdmmc_buswidth_t bus_width;
- switch (bus_mode) {
- default:
- bus_width = sdmmc_bus_width_1bit;
- break;
- case emmc_bus_mode_x4_sdr:
- case emmc_bus_mode_x4_ddr:
- bus_width = sdmmc_bus_width_4bit;
- break;
- case emmc_bus_mode_x8_sdr:
- case emmc_bus_mode_x8_ddr:
- case emmc_bus_mode_x8_ddr_ds:
- bus_width = sdmmc_bus_width_8bit;
- break;
- }
- sdmmchost_set_card_bus_width(card->host, bus_width);
- }
- return status;
- }
- static hpm_stat_t emmc_set_hs_timing(emmc_card_t *card, emmc_hs_timing_t timing)
- {
- uint32_t clock_option;
- bool clock_inverse = true;
- sdmmc_speed_mode_t speed;
- uint32_t timing_val = 0; /* refer to EXT_CSD[185] for more details */
- switch (timing) {
- default:
- clock_option = MMC_CLOCK_26MHz;
- speed = sdmmc_emmc_speed_legacy;
- timing_val = (uint8_t) emmc_timing_legacy;
- break;
- case emmc_timing_high_speed:
- clock_option = MMC_CLOCK_52MHz;
- speed = sdmmc_emmc_speed_high_speed_sdr;
- timing_val = (uint8_t) emmc_timing_high_speed;
- break;
- case emmc_timing_hs200:
- clock_option = MMC_CLOCK_HS200;
- speed = sdmmc_emmc_speed_hs200;
- timing_val = (uint8_t) emmc_timing_hs200;
- break;
- case emmc_timing_hs400:
- clock_inverse = false;
- clock_option = MMC_CLOCK_HS400;
- speed = sdmmc_emmc_speed_hs400;
- timing_val = (uint8_t) emmc_timing_hs400;
- break;
- case emmc_timing_high_speed_ddr:
- clock_inverse = false;
- clock_option = MMC_CLOCK_DDR52;
- speed = sdmmc_emmc_speed_high_speed_ddr;
- timing_val = (uint8_t) emmc_timing_high_speed;
- break;
- }
- card->current_hs_timing = timing;
- emmc_switch_cmd_arg_t switch_arg = {.argument = 0U};
- switch_arg.access = emmc_switch_cmd_access_mode_write_byte;
- switch_arg.index = EMMC_EXT_CSD_INDEX_HS_TIMING;
- switch_arg.value = (uint8_t) timing_val;
- hpm_stat_t status = emmc_switch_function(card, switch_arg, card->device_attribute.switch_cmd_timeout_ms * 1000U);
- if (status != status_success) {
- return status;
- }
- sdmmchost_set_speed_mode(card->host, speed);
- card->host->clock_freq = sdmmchost_set_card_clock(card->host, clock_option, clock_inverse);
- return status;
- }
- hpm_stat_t emmc_host_init(emmc_card_t *card)
- {
- hpm_stat_t status = status_success;
- assert(card != NULL);
- status = sdmmchost_init(card->host);
- if (status == status_success) {
- card->is_host_ready = true;
- }
- return status_success;
- }
- hpm_stat_t emmc_init(emmc_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(card == NULL);
- status = emmc_host_init(card);
- HPM_BREAK_IF(status != status_success);
- sdmmchost_enable_emmc_support(card->host, true);
- if (card->host->io_voltage == hpm_sdmmc_io_voltage_3v3) {
- card->operation_voltage = sdmmc_operation_voltage_3v3;
- } else {
- card->operation_voltage = sdmmc_operation_voltage_1v8;
- }
- card->host->card_init_done = false;
- card->relative_addr = 0;
- card->current_hs_timing = emmc_timing_legacy;
- sdmmchost_delay_ms(card->host, 1); /* Wait a while in case the card connection is still not stable */
- status = emmc_card_init(card);
- } while (false);
- return status;
- }
- void emmc_deinit(emmc_card_t *card)
- {
- if (card->is_host_ready) {
- card->is_host_ready = false;
- sdmmchost_deinit(card->host);
- }
- }
- hpm_stat_t emmc_probe_device(emmc_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- status = sdmmc_go_idle_state(card->host, (uint32_t) emmc_idle_option_go_idle_state);
- HPM_BREAK_IF(status != status_success);
- emmc_ocr_t ocr = {.ocr_word = 0xc0ff8080};
- /* Query OCR */
- status = emmc_send_op_cond(card, ocr);
- HPM_BREAK_IF(status != status_success);
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- emmc_ocr_t recv_ocr = {.ocr_word = 0};
- do {
- status = emmc_send_op_cond(card, ocr);
- HPM_BREAK_IF(status != status_success);
- recv_ocr.ocr_word = cmd->response[0];
- } while (recv_ocr.powerup_status == 0);
- card->ocr.ocr_word = recv_ocr.ocr_word;
- } while (false);
- return status;
- }
- hpm_stat_t emmc_card_init(emmc_card_t *card)
- {
- hpm_stat_t status = emmc_check_card_parameters(card);
- do {
- HPM_BREAK_IF(status != status_success);
- sdmmchost_set_card_bus_width(card->host, sdmmc_bus_width_1bit);
- sdmmchost_set_card_clock(card->host, SDMMC_CLOCK_400KHZ, true);
- status = emmc_probe_device(card);
- HPM_BREAK_IF(status != status_success);
- card->host->operation_mode = hpm_sdmmc_operation_mode_identification;
- sdmmchost_init_io(card->host, card->host->operation_mode);
- card->host->dev_type = sdmmc_dev_type_emmc;
- sdmmchost_enable_emmc_support(card->host, true);
- /* Send CMD2 */
- status = emmc_all_send_cid(card);
- HPM_BREAK_IF(status != status_success);
- /* Send CMD3 */
- status = emmc_set_rca(card, EMMC_RCA_DEFAULT);
- HPM_BREAK_IF(status != status_success);
- /* Send CMD9 (SEND_CSD) */
- status = emmc_send_csd(card);
- HPM_BREAK_IF(status != status_success);
- /* Send CMD10 (SEND_CID) */
- status = emmc_send_cid(card);
- HPM_BREAK_IF(status != status_success);
- /* Send CMD7 */
- status = emmc_select_card(card, true);
- HPM_BREAK_IF(status != status_success);
- card->host->operation_mode = hpm_sdmmc_operation_mode_transfer;
- sdmmchost_init_io(card->host, card->host->operation_mode);
- sdmmchost_set_card_clock(card->host, SD_CLOCK_25MHZ, true);
- /* Send CMD8 */
- status = emmc_send_ext_csd(card);
- HPM_BREAK_IF(status != status_success);
- /* Send CMD16: Set block size */
- status = sdmmc_set_block_size(card->host, SDMMC_BLOCK_SIZE_DEFAULT);
- if (status != status_success) {
- return status;
- }
- /***************************************************************************************************************
- *
- * Switch to specified highest frequency
- *
- * Steps:
- *
- * 1. Find the allowed maximum speed mode
- * 2. Switch to the maximum speed mode following the eMMC specification
- *
- **************************************************************************************************************/
- emmc_bus_mode_t bus_mode = emmc_bus_mode_x1_sdr;
- sdmmc_speed_mode_t speed_mode = sdmmc_emmc_speed_legacy;
- bool need_switch_to_hs_timing = false;
- bool need_tuning_in_hs200_mode = false;
- bool need_enable_enhanced_ds = false;
- bool support_4bit = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_4BIT);
- bool support_8bit = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_8BIT);
- bool support_ddr = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_DDR);
- bool support_1v8 = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_1V8);
- bool support_hs200 = support_1v8 && (support_4bit || support_8bit) &&
- IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_HS200);
- bool support_hs400 = support_8bit && support_1v8 &&
- IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_HS400);
- bool has_configured = false;
- if (support_4bit) {
- bus_mode = emmc_bus_mode_x4_sdr;
- }
- if (support_8bit) {
- bus_mode = emmc_bus_mode_x8_sdr;
- }
- if (support_hs400 && (card->device_attribute.device_type.support_hs400_at_200mhz_1v8 != 0)) {
- speed_mode = sdmmc_emmc_speed_hs400;
- need_switch_to_hs_timing = true;
- if (card->device_attribute.is_enhanced_strobe_supported != 0U) {
- need_enable_enhanced_ds = true;
- bus_mode = emmc_bus_mode_x8_ddr_ds;
- } else {
- need_tuning_in_hs200_mode = true;
- bus_mode = emmc_bus_mode_x8_ddr;
- }
- } else if (support_hs200 && (card->device_attribute.device_type.support_hs200_at_200mhz_1v8 != 0)) {
- speed_mode = sdmmc_emmc_speed_hs200;
- need_tuning_in_hs200_mode = true;
- } else if (support_ddr && (card->device_attribute.device_type.support_high_speed_ddr_at_52mhz_1v8_or_3v != 0)) {
- speed_mode = sdmmc_emmc_speed_high_speed_ddr;
- bus_mode = support_8bit ? emmc_bus_mode_x8_ddr : emmc_bus_mode_x4_ddr;
- } else if (card->device_attribute.device_type.support_high_speed_sdr_at_52mhz) {
- speed_mode = sdmmc_emmc_speed_high_speed_sdr;
- } else {
- speed_mode = sdmmc_emmc_speed_legacy;
- }
- /* Perform Tuning procedure for HS200/HS400 without enhanced data strobe */
- if (need_tuning_in_hs200_mode) {
- /* Switch to HS200 mode according to eMMC spec */
- emmc_bus_mode_t expected_mode = support_8bit ? emmc_bus_mode_x8_sdr : emmc_bus_mode_x4_sdr;
- status = emmc_set_bus_width(card, expected_mode);
- HPM_BREAK_IF(status != status_success);
- status = emmc_set_hs_timing(card, emmc_timing_hs200);
- HPM_BREAK_IF(status != status_success);
- card->current_hs_timing = emmc_timing_hs200;
- card->current_bus_mode = expected_mode;
- /* Perform Tuning process if necessary */
- status = sdmmc_enable_auto_tuning(card->host);
- HPM_BREAK_IF(status != status_success);
- if (speed_mode == sdmmc_emmc_speed_hs200) {
- has_configured = true;
- }
- }
- /* Switch to HIGH_SPEED mode first for HS400 mode */
- if (need_switch_to_hs_timing) {
- status = emmc_set_hs_timing(card, emmc_timing_high_speed);
- HPM_BREAK_IF(status != status_success);
- sdmmchost_set_card_clock(card->host, MMC_CLOCK_26MHz, true);
- }
- bool need_manual_set_cardclk_delay_chain = false;
- emmc_hs_timing_t timing_mode;
- switch (speed_mode) {
- case sdmmc_emmc_speed_high_speed_sdr:
- timing_mode = emmc_timing_high_speed;
- break;
- case sdmmc_emmc_speed_high_speed_ddr:
- timing_mode = emmc_timing_high_speed_ddr;
- need_manual_set_cardclk_delay_chain = true;
- break;
- case sdmmc_emmc_speed_hs200:
- timing_mode = emmc_timing_hs200;
- break;
- case sdmmc_emmc_speed_hs400:
- timing_mode = emmc_timing_hs400;
- need_manual_set_cardclk_delay_chain = true;
- break;
- default:
- timing_mode = emmc_timing_legacy;
- break;
- }
- if (!has_configured) {
- if (timing_mode == emmc_timing_hs400) {
- /* Switch BUS mode, then HS_TIMING */
- status = emmc_set_bus_width(card, bus_mode);
- HPM_BREAK_IF(status != status_success);
- status = emmc_set_hs_timing(card, timing_mode);
- HPM_BREAK_IF(status != status_success);
- if (need_enable_enhanced_ds) {
- sdmmchost_enable_enhanced_data_strobe(card->host, true);
- }
- sdmmchost_set_data_strobe_delay(card->host);
- } else {
- /* Switch HS_TIMING and BUS_WIDTH according to eMMC spec */
- status = emmc_set_hs_timing(card, timing_mode);
- HPM_BREAK_IF(status != status_success);
- status = emmc_set_bus_width(card, bus_mode);
- HPM_BREAK_IF(status != status_success);
- }
- }
- card->current_hs_timing = timing_mode;
- card->current_bus_mode = bus_mode;
- if (need_manual_set_cardclk_delay_chain) {
- sdmmchost_set_cardclk_delay_chain(card->host);
- }
- /* Delay a while until card switches to the expected timing mode */
- sdmmchost_delay_ms(card->host, 1U);
- status = emmc_polling_card_status_busy(card, 10U);
- card->host->card_init_done = true;
- } while (false);
- return status;
- }
- bool emmc_is_card_present(const emmc_card_t *card)
- {
- return sdmmchost_is_card_detected(card->host);
- }
- hpm_stat_t emmc_select_card(const emmc_card_t *card, bool is_selected)
- {
- uint16_t rca = (is_selected) ? card->relative_addr : 0;
- return sdmmc_select_card(card->host, rca, is_selected);
- }
- hpm_stat_t emmc_read_blocks(emmc_card_t *card, uint8_t *buffer, uint32_t start_block, uint32_t block_count)
- {
- hpm_stat_t status = emmc_check_card_parameters(card);
- do {
- HPM_BREAK_IF(status != status_success);
- if (!card->host->card_init_done) {
- status = status_sdmmc_device_init_required;
- break;
- }
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- sdmmchost_data_t *data = &card->host->data;
- sdmmchost_xfer_t *content = &card->host->xfer;
- memset(cmd, 0, sizeof(*cmd));
- memset(data, 0, sizeof(*data));
- memset(content, 0, sizeof(*content));
- while (block_count > 0) {
- uint32_t read_block_count = (block_count >= MAX_BLOCK_COUNT) ? MAX_BLOCK_COUNT : block_count;
- if (read_block_count > 1) {
- cmd->cmd_index = sdmmc_cmd_read_multiple_block;
- data->enable_auto_cmd23 = true;
- } else {
- cmd->cmd_index = sdmmc_cmd_read_single_block;
- }
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1;
- cmd->cmd_argument = start_block;
- data->block_size = SDMMC_BLOCK_SIZE_DEFAULT;
- data->block_cnt = read_block_count;
- data->rx_data = (uint32_t *) sdmmc_get_sys_addr(card->host, (uint32_t) buffer);
- content->data = data;
- content->command = cmd;
- #if !defined(HPM_SDMMC_ENABLE_CACHE_MAINTENANCE) || (HPM_SDMMC_ENABLE_CACHE_MAINTENANCE == 1)
- uint32_t buf_start = (uint32_t) data->rx_data;
- uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN(buf_start);
- uint32_t end_addr = buf_start + card->device_attribute.sector_size * block_count;
- uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(end_addr);
- uint32_t aligned_size = aligned_end - aligned_start;
- /* FLUSH un-cacheline aligned memory region */
- if ((buf_start % HPM_L1C_CACHELINE_SIZE) != 0) {
- l1c_dc_writeback(aligned_start, HPM_L1C_CACHELINE_SIZE);
- }
- if ((end_addr % HPM_L1C_CACHELINE_SIZE) != 0) {
- uint32_t aligned_tail = HPM_L1C_CACHELINE_ALIGN_DOWN(end_addr);
- l1c_dc_writeback(aligned_tail, HPM_L1C_CACHELINE_SIZE);
- }
- #endif
- status = emmc_transfer(card, content);
- #if !defined(HPM_SDMMC_ENABLE_CACHE_MAINTENANCE) || (HPM_SDMMC_ENABLE_CACHE_MAINTENANCE == 1)
- l1c_dc_invalidate(aligned_start, aligned_size);
- #endif
- if (status != status_success) {
- break;
- }
- block_count -= read_block_count;
- start_block += read_block_count;
- buffer += SDMMC_BLOCK_SIZE_DEFAULT * read_block_count;
- }
- } while (false);
- return status;
- }
- hpm_stat_t emmc_write_blocks(emmc_card_t *card, const uint8_t *buffer, uint32_t start_block, uint32_t block_count)
- {
- hpm_stat_t status = emmc_check_card_parameters(card);
- do {
- HPM_BREAK_IF(status != status_success);
- if (!card->host->card_init_done) {
- status = status_sdmmc_device_init_required;
- break;
- }
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- sdmmchost_data_t *data = &card->host->data;
- sdmmchost_xfer_t *content = &card->host->xfer;
- memset(cmd, 0, sizeof(*cmd));
- memset(data, 0, sizeof(*data));
- memset(content, 0, sizeof(*content));
- status = emmc_polling_card_status_busy(card, WRITE_BLOCK_TIMEOUT_IN_MS);
- HPM_BREAK_IF(status != status_success);
- while (block_count > 0) {
- uint32_t write_block_count = (block_count >= MAX_BLOCK_COUNT) ? MAX_BLOCK_COUNT : block_count;
- if (write_block_count > 1) {
- cmd->cmd_index = sdmmc_cmd_write_multiple_block;
- data->enable_auto_cmd23 = true;
- } else {
- cmd->cmd_index = sdmmc_cmd_write_single_block;
- data->enable_auto_cmd12 = false;
- }
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1;
- cmd->cmd_argument = start_block;
- data->block_size = SDMMC_BLOCK_SIZE_DEFAULT;
- data->block_cnt = write_block_count;
- data->tx_data = (const uint32_t *) sdmmc_get_sys_addr(card->host, (uint32_t) buffer);
- content->data = data;
- content->command = cmd;
- #if !defined(HPM_SDMMC_ENABLE_CACHE_MAINTENANCE) || (HPM_SDMMC_ENABLE_CACHE_MAINTENANCE == 1)
- uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN((uint32_t) data->tx_data);
- uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(
- (uint32_t) data->tx_data + card->device_attribute.sector_size * write_block_count);
- uint32_t aligned_size = aligned_end - aligned_start;
- l1c_dc_flush(aligned_start, aligned_size);
- #endif
- status = emmc_transfer(card, content);
- if (status != status_success) {
- break;
- }
- status = emmc_polling_card_status_busy(card, WRITE_BLOCK_TIMEOUT_IN_MS);
- HPM_BREAK_IF(status != status_success);
- block_count -= write_block_count;
- start_block += write_block_count;
- buffer += SDMMC_BLOCK_SIZE_DEFAULT * write_block_count;
- }
- } while (false);
- return status;
- }
- /**
- * @brief Calculate SD erase timeout value
- * Refer to SD_Specification_Part1_Physical_Layer_Specification_Version4.20.pdf, section 4.14 for more details.
- */
- static uint32_t emmc_calculate_erase_timeout(const emmc_card_t *card, uint32_t start_block, uint32_t block_count)
- {
- (void) start_block;
- uint32_t erase_timeout;
- if (card->device_attribute.erase_timeout_ms == 0) {
- erase_timeout = block_count * 250U;
- } else {
- erase_timeout = card->device_attribute.erase_timeout_ms;
- }
- return erase_timeout;
- }
- hpm_stat_t emmc_erase_blocks(emmc_card_t *card,
- uint32_t start_block,
- uint32_t block_count,
- emmc_erase_option_t erase_option)
- {
- hpm_stat_t status = emmc_check_card_parameters(card);
- do {
- HPM_BREAK_IF(status != status_success);
- if (!card->host->card_init_done) {
- status = status_sdmmc_device_init_required;
- break;
- }
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- memset(cmd, 0, sizeof(*cmd));
- uint32_t erase_timeout = emmc_calculate_erase_timeout(card, start_block, block_count);
- /* Send erase start */
- cmd->cmd_index = emmc_cmd_erase_group_start;
- cmd->cmd_argument = start_block;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1;
- status = emmc_send_cmd(card, cmd);
- HPM_BREAK_IF(status != status_success);
- /* Send Erase end */
- cmd->cmd_index = emmc_cmd_erase_group_end;
- cmd->cmd_argument = start_block + block_count - 1U;
- status = emmc_send_cmd(card, cmd);
- HPM_BREAK_IF(status != status_success);
- /* Send erase command */
- uint32_t argument = 0;
- switch (erase_option) {
- default:
- argument = 0;
- break;
- case emmc_erase_option_discard:
- argument = 3;
- break;
- case emmc_erase_option_trim:
- argument = 1;
- break;
- }
- cmd->cmd_index = sdmmc_cmd_erase;
- cmd->cmd_argument = argument;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1b;
- cmd->cmd_timeout_ms = erase_timeout;
- status = emmc_send_cmd(card, cmd);
- HPM_BREAK_IF(status != status_success);
- /* Wait until erase completed. */
- status = emmc_polling_card_status_busy(card, erase_timeout);
- } while (false);
- return status;
- }
- hpm_stat_t emmc_polling_card_status_busy(emmc_card_t *card, uint32_t timeout_ms)
- {
- hpm_stat_t status = status_invalid_argument;
- bool is_busy = true;
- volatile uint64_t start_tick = hpm_csr_get_core_mcycle();
- uint64_t timeout_ms_in_ticks = (uint64_t) timeout_ms * (clock_get_frequency(clock_cpu0) / 1000UL);
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL));
- status = emmc_send_card_status(card);
- if (status != status_success) {
- break;
- }
- if ((card->current_r1_status.current_state == sdmmc_state_program) ||
- (card->current_r1_status.ready_for_data == 0U)) {
- is_busy = true;
- uint64_t current_tick = hpm_csr_get_core_mcycle();
- if (current_tick - start_tick > timeout_ms_in_ticks) {
- break;
- }
- } else {
- is_busy = false;
- }
- } while (is_busy && (timeout_ms > 0));
- if ((status == status_success) && is_busy) {
- status = status_sdmmc_wait_busy_timeout;
- }
- return status;
- }
- hpm_stat_t emmc_switch_function(const emmc_card_t *card, emmc_switch_cmd_arg_t arg, uint32_t timeout_us)
- {
- hpm_stat_t error = status_invalid_argument;
- do {
- HPM_BREAK_IF(card == NULL);
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_switch;
- cmd->cmd_argument = arg.argument;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1b;
- cmd->cmd_timeout_ms = (timeout_us + 999) / 1000;
- error = emmc_send_cmd(card, cmd);
- } while (false);
- return error;
- }
- hpm_stat_t emmc_configure_partition(const emmc_card_t *card, emmc_config_partition_option_t option)
- {
- uint8_t partition_config = 0U;
- if (option.enable_boot_ack) {
- partition_config |= (1UL << 6);
- }
- switch (option.boot_partition_enable_option) {
- default:
- /* Do nothing */
- break;
- case boot_partition_enable_option_boot_partition1:
- partition_config |= (1UL << 3);
- break;
- case boot_partition_enable_option_boot_partition2:
- partition_config |= (2UL << 3);
- break;
- case boot_partition_enable_option_user_area:
- partition_config |= (7UL << 3);
- break;
- }
- switch (option.partition_access_option) {
- default:
- /* Do nothing */
- break;
- case emmc_partition_access_read_or_write_boot_partition1:
- partition_config |= (1UL << 0);
- break;
- case emmc_partition_access_read_or_write_boot_partition2:
- partition_config |= (2UL << 0);
- break;
- case emmc_partition_access_read_or_write_rpmb:
- partition_config |= (3UL << 0);
- break;
- case emmc_partition_access_access_to_gp_partition1:
- partition_config |= (4UL << 0);
- break;
- case emmc_partition_access_access_to_gp_partition2:
- partition_config |= (5UL << 0);
- break;
- case emmc_partition_access_access_to_gp_partition3:
- partition_config |= (6UL << 0);
- break;
- case emmc_partition_access_access_to_gp_partition4:
- partition_config |= (7UL << 0);
- break;
- }
- emmc_switch_cmd_arg_t switch_arg = { .argument = 0U };
- switch_arg.access = emmc_switch_cmd_access_mode_write_byte;
- switch_arg.index = EMMC_EXT_CSD_INDEX_PARTITION_CONFIG;
- switch_arg.value = partition_config;
- uint32_t timeout_in_us = card->device_attribute.partition_switch_timeout_ms * 1000UL;
- return emmc_switch_function(card, switch_arg, timeout_in_us);
- }
- hpm_stat_t emmc_enter_sleep_mode(const emmc_card_t *card)
- {
- hpm_stat_t error = status_invalid_argument;
- do {
- HPM_BREAK_IF(card == NULL);
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_sleep_awake;
- cmd->cmd_argument = ((uint32_t)card->relative_addr << 16) | (1UL << 15);
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1b;
- /* Calculate the command timeout in ms, see 7.4.50 section in JESD84-B51A for more details */
- uint32_t timeout_in_ns = 100UL * (1UL << card->ext_csd.sleep_or_awake_timeout);
- cmd->cmd_timeout_ms = (timeout_in_ns + 999999UL) / 1000000UL;
- error = emmc_send_cmd(card, cmd);
- } while (false);
- return error;
- }
- hpm_stat_t emmc_exit_sleep_mode(const emmc_card_t *card)
- {
- hpm_stat_t error = status_invalid_argument;
- do {
- HPM_BREAK_IF(card == NULL);
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = emmc_cmd_sleep_awake;
- cmd->cmd_argument = ((uint32_t)card->relative_addr << 16);
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r1b;
- /* Calculate the command timeout in ms, see 7.4.50 section in JESD84-B51A for more details */
- uint32_t timeout_in_ns = 100UL * (1UL << card->ext_csd.sleep_or_awake_timeout);
- cmd->cmd_timeout_ms = (timeout_in_ns + 999999UL) / 1000000UL;
- error = emmc_send_cmd(card, cmd);
- } while (false);
- return error;
- }
|