/* Copyright (C) 2019 RDA Technologies Limited and/or its affiliates("RDA"). * All rights reserved. * * This software is supplied "AS IS" without any warranties. * RDA assumes no responsibility or liability for the use of the software, * conveys no license or title under any patent, copyright, or mask work * right to the product. RDA reserves the right to make changes in the * software without notification. RDA also make no representation or * warranty that such application will be suitable for the specified use * without further testing or modification. */ #ifndef _DRV_SDMMC_IMP_H_ #define _DRV_SDMMC_IMP_H_ #include "osi_compiler.h" #include "drv_names.h" #include "drv_config.h" #include "osi_api.h" #include "osi_clock.h" #include "hwregs.h" #include "drv_ifc.h" #include #include "quec_proj_config.h" OSI_EXTERN_C_BEGIN #ifndef CONFIG_8910_EMMC_SUPPORT #ifdef CONFIG_SOC_8910 #define SDMMC_CLOCK_SOURCE CONFIG_DEFAULT_SYSAXI_FREQ #endif #if defined(CONFIG_SOC_8811) || defined(CONFIG_SOC_8850) #define SDMMC_CLOCK_SOURCE CONFIG_DEFAULT_SYS_CLK_FREQ #endif #define SDMMC_CLK_FREQ_IDENTIFY (400000) #define SDMMC_CLK_FREQ_SD CONFIG_SDMMC_CLK_FREQ_SD #define SDMMC_CLK_FREQ_SDHC CONFIG_SDMMC_CLK_FREQ_SDHC #define SDMMC_CMD8_CHECK_PATTERN 0xaa #define SDMMC_CMD8_VOLTAGE_SEL (0x1 << 8) #define SDMMC_READ_TIMEOUT_MS (5000) #define SDMMC_WRITE_TIMEOUT_MS (5000) #if QUEC_PATCH_SDMMC_WRITE_READ_BIG_FILE #define SDMMC_CMD_TIMEOUT_US (10000) #define SDMMC_RESP_TIMEOUT_US (10000) #define QUEC_SDMMC_CMD_LONG_TIMEOUT_US (2000000) #define QUEC_SDMMC_RESP_LONG_TIMEOUT_US (2000000) #else #define SDMMC_CMD_TIMEOUT_US (30000) #define SDMMC_RESP_TIMEOUT_US (30000) #endif #define SDMMC_TRAN_TIMEOUT_US (2000000) #define SDMMC_SDMMC_OCR_TIMEOUT_US (1000000) // the card is supposed to answer within 1s #define SDMMC_CSD_VERSION_1 0 #define SDMMC_CSD_VERSION_2 1 #define SDMMC_CSD_VERSION_3 2 typedef struct { uint32_t v[4]; } drvSdmmcResp_t; /** * sdmmcCardState_t * * The state of the card when receiving the command. If the command execution * causes a state change, it will be visible to the host in the response to * the next command. The four bits are interpreted as a binary coded number * between 0 and 15. */ typedef enum { SDMMC_CARD_STATE_IDLE = 0, SDMMC_CARD_STATE_READY = 1, SDMMC_CARD_STATE_IDENT = 2, SDMMC_CARD_STATE_STBY = 3, SDMMC_CARD_STATE_TRAN = 4, SDMMC_CARD_STATE_DATA = 5, SDMMC_CARD_STATE_RCV = 6, SDMMC_CARD_STATE_PRG = 7, SDMMC_CARD_STATE_DIS = 8 } sdmmcCardState_t; typedef union { uint32_t v; struct { uint32_t vdd_win : 24; // [23:0] uint32_t s18a : 1; // [24] uint32_t __16_15 : 2; // [26:25] uint32_t co2t : 1; // [27] uint32_t __28_28 : 1; // [28] uint32_t uhs2 : 1; // [29] uint32_t ccs : 1; // [30] uint32_t power_on_finish : 1; // [31] } b; } sdmmcOcr_t; /** * sdmmcCardStatus_t * * Card status as returned by R1 reponses (spec V2 pdf p.) */ #ifdef CONFIG_QUEC_PROJECT_FEATURE_EMMC2 typedef union { uint32_t v; struct { uint32_t __2_0 : 3; // [0:2] uint32_t ake_seq_error : 1; // [3] uint32_t __4_4 : 1; // [4] uint32_t app_cmd : 1; // [5] uint32_t fx_event : 1; // [6] uint32_t __7_7 : 1; // [7] uint32_t ready_for_data : 1; // [8] sdmmcCardState_t current_state : 4; // [9:12] uint32_t erase_reset : 1; // [13] uint32_t card_ecc_disabled : 1; // [14] uint32_t wp_erase_skip : 1; // [15] uint32_t csd_overwrite : 1; // [16] uint32_t __18_17 : 2; // [17:18] uint32_t error : 1; // [19] uint32_t cc_error : 1; // [20] uint32_t card_ecc_failed : 1; // [21] uint32_t illegal_command : 1; // [22] uint32_t com_crc_error : 1; // [23] uint32_t lock_unlock_fail : 1; // [24] uint32_t card_is_locked : 1; // [25] uint32_t wp_violation : 1; // [26] uint32_t erase_param : 1; // [27] uint32_t erase_seq_error : 1; // [28] uint32_t block_len_error : 1; // [29] uint32_t address_error : 1; // [30] uint32_t out_of_range : 1; // [31] } b; } sdmmcCardStatus_SD_t; //重新定义一个符合EMMC 5.1协议的sdmmcCardStatus_t typedef union { uint32_t v; struct { uint32_t __4_0 : 5; // [0:4] uint32_t app_cmd : 1; // [5] uint32_t exception_event : 1; // [6] uint32_t switch_error : 1; // [7] uint32_t ready_for_data : 1; // [8] sdmmcCardState_t current_state : 4; // [9:12] uint32_t erase_reset : 1; // [13] uint32_t __14_14 : 1; // [14] uint32_t wp_erase_skip : 1; // [15] uint32_t csd_overwrite : 1; // [16] uint32_t obsolete : 2; // [17:18] uint32_t error : 1; // [19] uint32_t cc_error : 1; // [20] uint32_t device_ecc_failed : 1; // [21] uint32_t illegal_command : 1; // [22] uint32_t com_crc_error : 1; // [23] uint32_t lock_unlock_failed : 1; // [24] uint32_t device_is_locked : 1; // [25] uint32_t wp_violation : 1; // [26] uint32_t erase_param : 1; // [27] uint32_t erase_seq_error : 1; // [28] uint32_t block_len_error : 1; // [29] uint32_t address_misalign : 1; // [30] uint32_t address_out_of_range : 1; // [31] } b; } sdmmcCardStatus_t; #else typedef union { uint32_t v; struct { uint32_t __2_0 : 3; // [0:2] uint32_t ake_seq_error : 1; // [3] uint32_t __4_4 : 1; // [4] uint32_t app_cmd : 1; // [5] uint32_t fx_event : 1; // [6] uint32_t __7_7 : 1; // [7] uint32_t ready_for_data : 1; // [8] sdmmcCardState_t current_state : 4; // [9:12] uint32_t erase_reset : 1; // [13] uint32_t card_ecc_disabled : 1; // [14] uint32_t wp_erase_skip : 1; // [15] uint32_t csd_overwrite : 1; // [16] uint32_t __18_17 : 2; // [17:18] uint32_t error : 1; // [19] uint32_t cc_error : 1; // [20] uint32_t card_ecc_failed : 1; // [21] uint32_t illegal_command : 1; // [22] uint32_t com_crc_error : 1; // [23] uint32_t lock_unlock_fail : 1; // [24] uint32_t card_is_locked : 1; // [25] uint32_t wp_violation : 1; // [26] uint32_t erase_param : 1; // [27] uint32_t erase_seq_error : 1; // [28] uint32_t block_len_error : 1; // [29] uint32_t address_error : 1; // [30] uint32_t out_of_range : 1; // [31] } b; } sdmmcCardStatus_t; #endif typedef struct __attribute__((packed, aligned(1))) { unsigned __0__0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned mdt : 12; // [19:8] unsigned __23_20 : 4; // [23:20] unsigned psn : 32; // [55:24] unsigned prv : 8; // [63:56] uint64_t pnm : 40; // [103:64] unsigned oid : 16; // [119:104] unsigned mid : 8; // [127:120] } sdmmcCid_t; #ifdef CONFIG_QUEC_PROJECT_FEATURE_EMMC2 typedef struct __attribute__((packed, aligned(1))) { unsigned __0__0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned mdt : 8; // [15:8] unsigned psn : 32; // [47:16] unsigned prv : 8; // [55:48] uint64_t pnm : 48; // [103:56] unsigned oid : 8; // [111:104] unsigned cbx : 2; // [113:112] unsigned _119_114 : 6;// [119:114] unsigned mid : 8; // [127:120] } sdmmcCidEmmc_t; #endif typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned __9_8 : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned __20_16 : 5; // [20:16] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned __30_29 : 2; // [30:29] unsigned wr_grp_enable : 1; // [31:31] unsigned wr_grp_size : 7; // [38:32] unsigned sector_size : 7; // [45:39] unsigned erase_blk_en : 1; // [46:46] unsigned c_size_mult : 3; // [49:47] unsigned vdd_w_curr_max : 3; // [52:50] unsigned vdd_w_curr_min : 3; // [55:53] unsigned vdd_r_curr_max : 3; // [58:56] unsigned vdd_r_curr_min : 3; // [61:59] unsigned c_size : 12; // [73:62] unsigned __75_74 : 2; // [75:74] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __125_120 : 6; // [125:120] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV1_t; typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned __9_8 : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned __20_16 : 5; // [20:16] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned __30_29 : 2; // [30:29] unsigned wr_grp_enable : 1; // [31:31] unsigned wr_grp_size : 7; // [38:32] unsigned sector_size : 7; // [45:39] unsigned erase_blk_en : 1; // [46:46] unsigned __47_47 : 1; // [47:47] unsigned c_size : 22; // [69:48] unsigned __75_70 : 6; // [75:70] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __125_120 : 6; // [125:120] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV2_t; typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned __9_8 : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned __20_16 : 5; // [20:16] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned __30_29 : 2; // [30:29] unsigned wr_grp_enable : 1; // [31:31] unsigned wr_grp_size : 7; // [38:32] unsigned sector_size : 7; // [45:39] unsigned erase_blk_en : 1; // [46:46] unsigned __47_47 : 1; // [47:47] unsigned c_size : 28; // [75:48] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __125_120 : 6; // [125:120] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV3_t; #ifdef CONFIG_QUEC_PROJECT_FEATURE_EMMC2 //符合EMMC 4.4和EMMC 5.1规范的CSD寄存器定义 typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned ecc : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned content_prot_app : 1; // [16:16] unsigned __20_17 : 4; // [20:17] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned default_ecc : 2; // [30:29] unsigned wp_grp_enable : 1; // [31:31] unsigned wp_grp_size : 5; // [36:32] unsigned erase_grp_mult : 5; // [41:37] unsigned erase_grp_size : 5; // [46:42] unsigned c_size_mult : 3; // [49:47] unsigned vdd_w_curr_max : 3; // [52:50] unsigned vdd_w_curr_min : 3; // [55:53] unsigned vdd_r_curr_max : 3; // [58:56] unsigned vdd_r_curr_min : 3; // [61:59] unsigned c_size : 12; // [73:62] unsigned __75_74 : 2; // [75:74] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __121_120 : 2; // [121:120] unsigned spec_vers : 4; // [125:122] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV4_t; #endif typedef union { sdmmcCsdV1_t v1; sdmmcCsdV2_t v2; sdmmcCsdV3_t v3; #ifdef CONFIG_QUEC_PROJECT_FEATURE_EMMC2 sdmmcCsdV4_t v4; #endif } sdmmcCsd_t; #define CSD_FIELD(csd, f) (csd->v1.csd_struct == 0 ? csd->v1.f : csd->v1.csd_struct == 1 ? csd->v2.f : csd->v3.f) static_assert(sizeof(sdmmcCsdV1_t) == 16, "sdmmcCsdV1_t is wrong"); static_assert(sizeof(sdmmcCsdV2_t) == 16, "sdmmcCsdV2_t is wrong"); static_assert(sizeof(sdmmcCsdV3_t) == 16, "sdmmcCsdV3_t is wrong"); static_assert(sizeof(sdmmcCsd_t) == 16, "sdmmcCsd_t is wrong"); static_assert(sizeof(sdmmcCid_t) == 16, "sdmmcCid_t is wrong"); static inline unsigned prvCsdStruct(sdmmcCsd_t *csd) { return csd->v1.csd_struct; } static inline unsigned prvCsdTaac(sdmmcCsd_t *csd) { return CSD_FIELD(csd, taac); } static inline unsigned prvCsdNsac(sdmmcCsd_t *csd) { return CSD_FIELD(csd, nsac); } static inline unsigned prvCsdTransSpeed(sdmmcCsd_t *csd) { return CSD_FIELD(csd, trans_speed); } static inline unsigned prvCsdCcc(sdmmcCsd_t *csd) { return CSD_FIELD(csd, ccc); } static inline unsigned prvCsdReadBlLen(sdmmcCsd_t *csd) { return CSD_FIELD(csd, read_bl_len); } static inline unsigned prvCsdReadBlPartial(sdmmcCsd_t *csd) { return CSD_FIELD(csd, read_bl_partial); } static inline unsigned prvCsdWriteBlkMisalign(sdmmcCsd_t *csd) { return CSD_FIELD(csd, write_blk_misalign); } static inline unsigned prvCsdReadBlkMisalign(sdmmcCsd_t *csd) { return CSD_FIELD(csd, read_blk_misalign); } static inline unsigned prvCsdDsrImp(sdmmcCsd_t *csd) { return CSD_FIELD(csd, dsr_imp); } static inline unsigned prvCsdCSize(sdmmcCsd_t *csd) { return CSD_FIELD(csd, c_size); } static inline unsigned prvCsdVddRCurrMin(sdmmcCsd_t *csd) { return csd->v1.vdd_r_curr_min; } static inline unsigned prvCsdVddRCurrMax(sdmmcCsd_t *csd) { return csd->v1.vdd_r_curr_max; } static inline unsigned prvCsdVddWCurrMin(sdmmcCsd_t *csd) { return csd->v1.vdd_w_curr_min; } static inline unsigned prvCsdVddWCurrMax(sdmmcCsd_t *csd) { return csd->v1.vdd_w_curr_max; } static inline unsigned prvCsdCSizeMult(sdmmcCsd_t *csd) { return csd->v1.c_size_mult; } static inline unsigned prvCsdEraseBlkEn(sdmmcCsd_t *csd) { return CSD_FIELD(csd, erase_blk_en); } static inline unsigned prvCsdSectorSize(sdmmcCsd_t *csd) { return CSD_FIELD(csd, sector_size); } static inline unsigned prvCsdWrGrpSize(sdmmcCsd_t *csd) { return CSD_FIELD(csd, wr_grp_size); } static inline unsigned prvCsdWrGrpEnable(sdmmcCsd_t *csd) { return CSD_FIELD(csd, wr_grp_enable); } static inline unsigned prvCsdR2wFactor(sdmmcCsd_t *csd) { return CSD_FIELD(csd, r2w_factor); } static inline unsigned prvCsdWriteBlLen(sdmmcCsd_t *csd) { return CSD_FIELD(csd, write_bl_len); } static inline unsigned prvCsdWriteBlPartial(sdmmcCsd_t *csd) { return CSD_FIELD(csd, write_bl_partial); } static inline unsigned prvCsdFileFormatGrp(sdmmcCsd_t *csd) { return CSD_FIELD(csd, file_format_grp); } static inline unsigned prvCsdCopy(sdmmcCsd_t *csd) { return CSD_FIELD(csd, copy); } static inline unsigned prvCsdPermWriteProtect(sdmmcCsd_t *csd) { return CSD_FIELD(csd, perm_write_protect); } static inline unsigned prvCsdTmpWriteProtect(sdmmcCsd_t *csd) { return CSD_FIELD(csd, tmp_write_protect); } static inline unsigned prvCsdFileFormat(sdmmcCsd_t *csd) { return CSD_FIELD(csd, file_format_grp); } static inline unsigned prvCsdCrc(sdmmcCsd_t *csd) { return CSD_FIELD(csd, crc); } /** * SDMMC_ACMD_SEL * mark a command as application specific */ #define SDMMC_ACMD_SEL 0x80000000 /** * SDMMC_CMD_MASK * * Mask to get from a sdmmcCmd_t value the corresponding * command index */ #define SDMMC_CMD_MASK 0x3F /** * sdmmcCmd_t * SD commands index */ typedef enum { SDMMC_CMD_GO_IDLE_STATE = 0, SDMMC_CMD_MMC_SEND_OP_COND = 1, SDMMC_CMD_ALL_SEND_CID = 2, SDMMC_CMD_SEND_RELATIVE_ADDR = 3, SDMMC_CMD_SET_DSR = 4, SDMMC_CMD_SWITCH = 6, SDMMC_CMD_SELECT_CARD = 7, SDMMC_CMD_SEND_IF_COND = 8, #ifdef CONFIG_QUEC_PROJECT_FEATURE_EMMC2 SEND_EXT_CSD = SDMMC_CMD_SEND_IF_COND, #endif SDMMC_CMD_SEND_CSD = 9, SDMMC_CMD_STOP_TRANSMISSION = 12, SDMMC_CMD_SEND_STATUS = 13, SDMMC_CMD_SET_BLOCKLEN = 16, SDMMC_CMD_READ_SINGLE_BLOCK = 17, SDMMC_CMD_READ_MULT_BLOCK = 18, SDMMC_CMD_WRITE_SINGLE_BLOCK = 24, SDMMC_CMD_WRITE_MULT_BLOCK = 25, SDMMC_CMD_APP_CMD = 55, SDMMC_CMD_SET_BUS_WIDTH = (6 | SDMMC_ACMD_SEL), SDMMC_CMD_SEND_NUM_WR_BLOCKS = (22 | SDMMC_ACMD_SEL), #ifdef CONFIG_QUEC_PROJECT_FEATURE_EMMC2 SDMMC_CMD_SET_WR_BLK_COUNT_EMMC = 23, #endif SDMMC_CMD_SET_WR_BLK_COUNT = (23 | SDMMC_ACMD_SEL), SDMMC_CMD_SEND_OP_COND = (41 | SDMMC_ACMD_SEL) } sdmmcCmd_t; /** * sdmmcCheckStatus_t * * check register hwp->sdmmc_status different bit */ typedef enum { SDMMC_CHECK_TRANSFER_DONE, SDMMC_CHECK_RESPONSE_OK, SDMMC_CHECK_CRC_OK, SDMMC_CHECK_DATA_OK, } sdmmcCheckStatus_t; /** * sdmmcDataBusWidth_t * * Cf spec v2 pdf p. 76 for ACMD6 argument * That type is used to describe how many data lines are used to transfer data * to and from the SD card. */ typedef enum { SDMMC_DATA_BUS_WIDTH_1 = 0x0, SDMMC_DATA_BUS_WIDTH_4 = 0x2, SDMMC_DATA_BUS_WIDTH_8 = 0x4 } sdmmcDataBusWidth_t; typedef enum { SDMMC_RESP_NONE = 0, SDMMC_RESP_FETCH = 1, SDMMC_RESP_CHECK = 2, } sdmmcRespOption_t; /** * Maximum block count per transfter are affected by 2 registers: * 1. sdmmc_block_cnt_reg: 16bits * 2. ifc.tc: 23bits, 14bits when block size is 512 */ #define SDMMC_MAX_BLOCK_PER_XFER (0x3fff) #if QUEC_PATCH_SDMMC_WRITE_READ_BIG_FILE typedef enum { QUEC_SDMMC_CMD_RESP_SHORT_WAIT = 0, //10ms超时。默认为0。上电时序使用0 QUEC_SDMMC_CMD_RESP_LONG_WAIT, //2S超时,只有在读写的时候使用 }quec_sdmmc_cmd_resp_wait_time_e; #endif struct drvSdmmc { uint32_t name; HWP_SDMMC_T *hwp; drvIfcChannel_t rx_ifc; drvIfcChannel_t tx_ifc; uint32_t irqn; drvSdmmcResp_t resp; sdmmcCsd_t csd; sdmmcCid_t cid; sdmmcOcr_t ocr; uint32_t rca; uint32_t dsr; uint8_t clk_adj; uint8_t clk_inv; bool card_is_sdhc; sdmmcDataBusWidth_t bus_width; uint32_t max_clk; uint32_t master_clk; uint32_t card_type; bool opened; bool rx_enabled; bool tx_enabled; uint32_t block_count; uint32_t block_size; osiClockConstrainRegistry_t clk_constrain; osiPmSource_t *pm_source; osiSemaphore_t *tx_done_sema; osiSemaphore_t *rx_done_sema; osiMutex_t *lock; struct { unsigned sdmmc_trans_speed; } pm_ctx; #if QUEC_PATCH_SDMMC_WRITE_READ_BIG_FILE quec_sdmmc_cmd_resp_wait_time_e quec_cmd_resp_loog_wait; //默认为QUEC_SDMMC_CMD_RESP_SHORT_WAIT #endif }; #else #ifdef CONFIG_SOC_8910 #define SDMMC_CLOCK_SOURCE CONFIG_DEFAULT_SYSAXI_FREQ #endif #ifdef CONFIG_SOC_8811 #define SDMMC_CLOCK_SOURCE CONFIG_DEFAULT_SYS_CLK_FREQ #endif #define SDMMC_CLK_FREQ_IDENTIFY (400000) #define SDMMC_CLK_FREQ_SD CONFIG_SDMMC_CLK_FREQ_SD #define SDMMC_CLK_FREQ_SDHC CONFIG_SDMMC_CLK_FREQ_SDHC #define SDMMC_CMD8_CHECK_PATTERN 0xaa #define SDMMC_CMD8_VOLTAGE_SEL (0x1 << 8) #define SDMMC_READ_TIMEOUT_MS (5000) #define SDMMC_WRITE_TIMEOUT_MS (5000) #define SDMMC_CMD_TIMEOUT_US (10000) #define SDMMC_RESP_TIMEOUT_US (10000) #define SDMMC_TRAN_TIMEOUT_US (2000000) #define SDMMC_SDMMC_OCR_TIMEOUT_US (1000000) // the card is supposed to answer within 1s #define SDMMC_CSD_VERSION_1 0 #define SDMMC_CSD_VERSION_2 1 #define SDMMC_CSD_VERSION_3 2 typedef struct { uint32_t v[4]; } drvSdmmcResp_t; /** * sdmmcCardState_t * * The state of the card when receiving the command. If the command execution * causes a state change, it will be visible to the host in the response to * the next command. The four bits are interpreted as a binary coded number * between 0 and 15. */ typedef enum { SDMMC_CARD_STATE_IDLE = 0, SDMMC_CARD_STATE_READY = 1, SDMMC_CARD_STATE_IDENT = 2, SDMMC_CARD_STATE_STBY = 3, SDMMC_CARD_STATE_TRAN = 4, SDMMC_CARD_STATE_DATA = 5, SDMMC_CARD_STATE_RCV = 6, SDMMC_CARD_STATE_PRG = 7, SDMMC_CARD_STATE_DIS = 8 } sdmmcCardState_t; typedef union { uint32_t v; struct { uint32_t vdd_win : 24; // [23:0] uint32_t s18a : 1; // [24] uint32_t __16_15 : 2; // [26:25] uint32_t co2t : 1; // [27] uint32_t __28_28 : 1; // [28] uint32_t uhs2 : 1; // [29] uint32_t ccs : 1; // [30] uint32_t power_on_finish : 1; // [31] } b; } sdmmcOcr_t; /** * sdmmcCardStatus_t * * Card status as returned by R1 reponses (spec V2 pdf p.) */ /* typedef union { uint32_t v; struct { uint32_t __2_0 : 3; // [0:2] uint32_t ake_seq_error : 1; // [3] uint32_t __4_4 : 1; // [4] uint32_t app_cmd : 1; // [5] uint32_t fx_event : 1; // [6] uint32_t __7_7 : 1; // [7] uint32_t ready_for_data : 1; // [8] sdmmcCardState_t current_state : 4; // [9:12] uint32_t erase_reset : 1; // [13] uint32_t card_ecc_disabled : 1; // [14] uint32_t wp_erase_skip : 1; // [15] uint32_t csd_overwrite : 1; // [16] uint32_t __18_17 : 2; // [17:18] uint32_t error : 1; // [19] uint32_t cc_error : 1; // [20] uint32_t card_ecc_failed : 1; // [21] uint32_t illegal_command : 1; // [22] uint32_t com_crc_error : 1; // [23] uint32_t lock_unlock_fail : 1; // [24] uint32_t card_is_locked : 1; // [25] uint32_t wp_violation : 1; // [26] uint32_t erase_param : 1; // [27] uint32_t erase_seq_error : 1; // [28] uint32_t block_len_error : 1; // [29] uint32_t address_error : 1; // [30] uint32_t out_of_range : 1; // [31] } b; } sdmmcCardStatus_t; */ //重新定义一个符合EMMC 5.1协议的sdmmcCardStatus_t typedef union { uint32_t v; struct { uint32_t __4_0 : 5; // [0:4] uint32_t app_cmd : 1; // [5] uint32_t exception_event : 1; // [6] uint32_t switch_error : 1; // [7] uint32_t ready_for_data : 1; // [8] sdmmcCardState_t current_state : 4; // [9:12] uint32_t erase_reset : 1; // [13] uint32_t __14_14 : 1; // [14] uint32_t wp_erase_skip : 1; // [15] uint32_t csd_overwrite : 1; // [16] uint32_t obsolete : 2; // [17:18] uint32_t error : 1; // [19] uint32_t cc_error : 1; // [20] uint32_t device_ecc_failed : 1; // [21] uint32_t illegal_command : 1; // [22] uint32_t com_crc_error : 1; // [23] uint32_t lock_unlock_failed : 1; // [24] uint32_t device_is_locked : 1; // [25] uint32_t wp_violation : 1; // [26] uint32_t erase_param : 1; // [27] uint32_t erase_seq_error : 1; // [28] uint32_t block_len_error : 1; // [29] uint32_t address_misalign : 1; // [30] uint32_t address_out_of_range : 1; // [31] } b; } sdmmcCardStatus_t; typedef struct __attribute__((packed, aligned(1))) { unsigned __0__0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned mdt : 12; // [19:8] unsigned __23_20 : 4; // [23:20] unsigned psn : 32; // [55:24] unsigned prv : 8; // [63:56] uint64_t pnm : 40; // [103:64] unsigned oid : 16; // [119:104] unsigned mid : 8; // [127:120] } sdmmcCid_t; typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned __9_8 : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned __20_16 : 5; // [20:16] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned __30_29 : 2; // [30:29] unsigned wr_grp_enable : 1; // [31:31] unsigned wr_grp_size : 7; // [38:32] unsigned sector_size : 7; // [45:39] unsigned erase_blk_en : 1; // [46:46] unsigned c_size_mult : 3; // [49:47] unsigned vdd_w_curr_max : 3; // [52:50] unsigned vdd_w_curr_min : 3; // [55:53] unsigned vdd_r_curr_max : 3; // [58:56] unsigned vdd_r_curr_min : 3; // [61:59] unsigned c_size : 12; // [73:62] unsigned __75_74 : 2; // [75:74] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __125_120 : 6; // [125:120] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV1_t; typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned __9_8 : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned __20_16 : 5; // [20:16] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned __30_29 : 2; // [30:29] unsigned wr_grp_enable : 1; // [31:31] unsigned wr_grp_size : 7; // [38:32] unsigned sector_size : 7; // [45:39] unsigned erase_blk_en : 1; // [46:46] unsigned __47_47 : 1; // [47:47] unsigned c_size : 22; // [69:48] unsigned __75_70 : 6; // [75:70] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __125_120 : 6; // [125:120] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV2_t; typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned __9_8 : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned __20_16 : 5; // [20:16] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned __30_29 : 2; // [30:29] unsigned wr_grp_enable : 1; // [31:31] unsigned wr_grp_size : 7; // [38:32] unsigned sector_size : 7; // [45:39] unsigned erase_blk_en : 1; // [46:46] unsigned __47_47 : 1; // [47:47] unsigned c_size : 28; // [75:48] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __125_120 : 6; // [125:120] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV3_t; //符合EMMC 4.4和EMMC 5.1规范的CSD寄存器定义 typedef struct __attribute__((packed, aligned(1))) { unsigned __0_0 : 1; // [0:0] unsigned crc : 7; // [7:1] unsigned ecc : 2; // [9:8] unsigned file_format : 2; // [11:10] unsigned tmp_write_protect : 1; // [12:12] unsigned perm_write_protect : 1; // [13:13] unsigned copy : 1; // [14:14] unsigned file_format_grp : 1; // [15:15] unsigned content_prot_app : 1; // [16:16] unsigned __20_17 : 4; // [20:17] unsigned write_bl_partial : 1; // [21:21] unsigned write_bl_len : 4; // [25:22] unsigned r2w_factor : 3; // [28:26] unsigned default_ecc : 2; // [30:29] unsigned wp_grp_enable : 1; // [31:31] unsigned wp_grp_size : 5; // [36:32] unsigned erase_grp_mult : 5; // [41:37] unsigned erase_grp_size : 5; // [46:42] unsigned c_size_mult : 3; // [49:47] unsigned vdd_w_curr_max : 3; // [52:50] unsigned vdd_w_curr_min : 3; // [55:53] unsigned vdd_r_curr_max : 3; // [58:56] unsigned vdd_r_curr_min : 3; // [61:59] unsigned c_size : 12; // [73:62] unsigned __75_74 : 2; // [75:74] unsigned dsr_imp : 1; // [76:76] unsigned read_blk_misalign : 1; // [77:77] unsigned write_blk_misalign : 1; // [78:78] unsigned read_bl_partial : 1; // [79:79] unsigned read_bl_len : 4; // [83:80] unsigned ccc : 12; // [95:84] unsigned trans_speed : 8; // [103:96] unsigned nsac : 8; // [111:104] unsigned taac : 8; // [119:112] unsigned __121_120 : 2; // [121:120] unsigned spec_vers : 4; // [125:122] unsigned csd_struct : 2; // [127:126] } sdmmcCsdV4_t; typedef union { sdmmcCsdV1_t v1; sdmmcCsdV2_t v2; sdmmcCsdV3_t v3; sdmmcCsdV4_t v4; } sdmmcCsd_t; // #define CSD_FIELD(csd, f) (csd->v1.csd_struct == 0 ? csd->v1.f : csd->v1.csd_struct == 1 ? csd->v2.f : csd->v3.f) #define CSD_FIELD(csd, f) (csd->v4.f) static_assert(sizeof(sdmmcCsdV1_t) == 16, "sdmmcCsdV1_t is wrong"); static_assert(sizeof(sdmmcCsdV2_t) == 16, "sdmmcCsdV2_t is wrong"); static_assert(sizeof(sdmmcCsdV3_t) == 16, "sdmmcCsdV3_t is wrong"); static_assert(sizeof(sdmmcCsdV4_t) == 16, "sdmmcCsdV4_t is wrong"); static_assert(sizeof(sdmmcCsd_t) == 16, "sdmmcCsd_t is wrong"); static_assert(sizeof(sdmmcCid_t) == 16, "sdmmcCid_t is wrong"); static inline unsigned prvCsdStruct(sdmmcCsd_t *csd) { return csd->v4.csd_struct; } static inline unsigned prvCsdSpecVers(sdmmcCsd_t *csd) { return CSD_FIELD(csd, spec_vers); } static inline unsigned prvCsdTaac(sdmmcCsd_t *csd) { return CSD_FIELD(csd, taac); } static inline unsigned prvCsdNsac(sdmmcCsd_t *csd) { return CSD_FIELD(csd, nsac); } static inline unsigned prvCsdTransSpeed(sdmmcCsd_t *csd) { return CSD_FIELD(csd, trans_speed); } static inline unsigned prvCsdCcc(sdmmcCsd_t *csd) { return CSD_FIELD(csd, ccc); } static inline unsigned prvCsdReadBlLen(sdmmcCsd_t *csd) { return CSD_FIELD(csd, read_bl_len); } static inline unsigned prvCsdReadBlPartial(sdmmcCsd_t *csd) { return CSD_FIELD(csd, read_bl_partial); } static inline unsigned prvCsdWriteBlkMisalign(sdmmcCsd_t *csd) { return CSD_FIELD(csd, write_blk_misalign); } static inline unsigned prvCsdReadBlkMisalign(sdmmcCsd_t *csd) { return CSD_FIELD(csd, read_blk_misalign); } static inline unsigned prvCsdDsrImp(sdmmcCsd_t *csd) { return CSD_FIELD(csd, dsr_imp); } static inline unsigned prvCsdCSize(sdmmcCsd_t *csd) { return CSD_FIELD(csd, c_size); } static inline unsigned prvCsdVddRCurrMin(sdmmcCsd_t *csd) { return csd->v4.vdd_r_curr_min; } static inline unsigned prvCsdVddRCurrMax(sdmmcCsd_t *csd) { return csd->v4.vdd_r_curr_max; } static inline unsigned prvCsdVddWCurrMin(sdmmcCsd_t *csd) { return csd->v4.vdd_w_curr_min; } static inline unsigned prvCsdVddWCurrMax(sdmmcCsd_t *csd) { return csd->v4.vdd_w_curr_max; } static inline unsigned prvCsdCSizeMult(sdmmcCsd_t *csd) { return csd->v4.c_size_mult; } static inline unsigned prvCsdEraseGrpSize(sdmmcCsd_t *csd) { return CSD_FIELD(csd, erase_grp_size); } static inline unsigned prvCsdEraseGrpMult(sdmmcCsd_t *csd) { return CSD_FIELD(csd, erase_grp_mult); } static inline unsigned prvCsdWpGrpSize(sdmmcCsd_t *csd) { return CSD_FIELD(csd, wp_grp_size); } static inline unsigned prvCsdWpGrpEnable(sdmmcCsd_t *csd) { return CSD_FIELD(csd, wp_grp_enable); } static inline unsigned prvCsdDefaultEcc(sdmmcCsd_t *csd) { return CSD_FIELD(csd, default_ecc); } static inline unsigned prvCsdR2wFactor(sdmmcCsd_t *csd) { return CSD_FIELD(csd, r2w_factor); } static inline unsigned prvCsdWriteBlLen(sdmmcCsd_t *csd) { return CSD_FIELD(csd, write_bl_len); } static inline unsigned prvCsdWriteBlPartial(sdmmcCsd_t *csd) { return CSD_FIELD(csd, write_bl_partial); } static inline unsigned prvCsdContentProtApp(sdmmcCsd_t *csd) { return CSD_FIELD(csd, content_prot_app); } static inline unsigned prvCsdFileFormatGrp(sdmmcCsd_t *csd) { return CSD_FIELD(csd, file_format_grp); } static inline unsigned prvCsdCopy(sdmmcCsd_t *csd) { return CSD_FIELD(csd, copy); } static inline unsigned prvCsdPermWriteProtect(sdmmcCsd_t *csd) { return CSD_FIELD(csd, perm_write_protect); } static inline unsigned prvCsdTmpWriteProtect(sdmmcCsd_t *csd) { return CSD_FIELD(csd, tmp_write_protect); } static inline unsigned prvCsdFileFormat(sdmmcCsd_t *csd) { return CSD_FIELD(csd, file_format); } static inline unsigned prvCsdEcc(sdmmcCsd_t *csd) { return CSD_FIELD(csd, ecc); } static inline unsigned prvCsdCrc(sdmmcCsd_t *csd) { return CSD_FIELD(csd, crc); } /** * SDMMC_ACMD_SEL * mark a command as application specific */ #define SDMMC_ACMD_SEL 0x80000000 /** * SDMMC_CMD_MASK * * Mask to get from a sdmmcCmd_t value the corresponding * command index */ #define SDMMC_CMD_MASK 0x3F /** * sdmmcCmd_t * SD commands index */ typedef enum { SDMMC_CMD_GO_IDLE_STATE = 0, SDMMC_CMD_MMC_SEND_OP_COND = 1, SDMMC_CMD_ALL_SEND_CID = 2, SDMMC_CMD_SEND_RELATIVE_ADDR = 3, SDMMC_CMD_SET_DSR = 4, SDMMC_CMD_SWITCH = 6, SDMMC_CMD_SELECT_CARD = 7, // SDMMC_CMD_SEND_IF_COND = 8, SEND_EXT_CSD = 8, SDMMC_CMD_SEND_CSD = 9, SDMMC_CMD_STOP_TRANSMISSION = 12, SDMMC_CMD_SEND_STATUS = 13, SDMMC_CMD_SET_BLOCKLEN = 16, SDMMC_CMD_READ_SINGLE_BLOCK = 17, SDMMC_CMD_READ_MULT_BLOCK = 18, SDMMC_CMD_WRITE_SINGLE_BLOCK = 24, SDMMC_CMD_WRITE_MULT_BLOCK = 25, SDMMC_CMD_APP_CMD = 55, SDMMC_CMD_SET_BUS_WIDTH = (6 | SDMMC_ACMD_SEL), SDMMC_CMD_SEND_NUM_WR_BLOCKS = (22 | SDMMC_ACMD_SEL), SDMMC_CMD_SET_WR_BLK_COUNT = 23, //(23 | SDMMC_ACMD_SEL), SDMMC_CMD_SEND_OP_COND = (41 | SDMMC_ACMD_SEL) } sdmmcCmd_t; /** * sdmmcCheckStatus_t * * check register hwp->sdmmc_status different bit */ typedef enum { SDMMC_CHECK_TRANSFER_DONE, SDMMC_CHECK_RESPONSE_OK, SDMMC_CHECK_CRC_OK, SDMMC_CHECK_DATA_OK, } sdmmcCheckStatus_t; /** * sdmmcDataBusWidth_t * * Cf spec v2 pdf p. 76 for ACMD6 argument * That type is used to describe how many data lines are used to transfer data * to and from the SD card. */ typedef enum { SDMMC_DATA_BUS_WIDTH_1 = 0x0, SDMMC_DATA_BUS_WIDTH_4 = 0x2, SDMMC_DATA_BUS_WIDTH_8 = 0x4 } sdmmcDataBusWidth_t; typedef enum { SDMMC_RESP_NONE = 0, SDMMC_RESP_FETCH = 1, SDMMC_RESP_CHECK = 2, } sdmmcRespOption_t; /** * Maximum block count per transfter are affected by 2 registers: * 1. sdmmc_block_cnt_reg: 16bits * 2. ifc.tc: 23bits, 14bits when block size is 512 */ #define SDMMC_MAX_BLOCK_PER_XFER (0x3fff) struct drvSdmmc { uint32_t name; HWP_SDMMC_T *hwp; drvIfcChannel_t rx_ifc; drvIfcChannel_t tx_ifc; uint32_t irqn; drvSdmmcResp_t resp; sdmmcCsd_t csd; sdmmcCid_t cid; sdmmcOcr_t ocr; uint32_t rca; uint32_t dsr; uint8_t clk_adj; uint8_t clk_inv; bool card_is_sdhc; sdmmcDataBusWidth_t bus_width; uint32_t max_clk; uint32_t master_clk; uint32_t card_type; bool opened; bool rx_enabled; bool tx_enabled; uint32_t block_count; uint32_t block_size; osiClockConstrainRegistry_t clk_constrain; osiPmSource_t *pm_source; osiSemaphore_t *tx_done_sema; osiSemaphore_t *rx_done_sema; osiMutex_t *lock; struct { unsigned sdmmc_trans_speed; } pm_ctx; }; #endif OSI_EXTERN_C_END #endif