/* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2008, Atmel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include "sdmmc_mci.h" #include #include #include #include //------------------------------------------------------------------------------ // Global variables //------------------------------------------------------------------------------ #if defined(MCI2_INTERFACE) unsigned char gSdmmcAutoHsEnable = 1; #else unsigned char gSdmmcAutoHsEnable = 0; #endif //------------------------------------------------------------------------------ // Local constants //------------------------------------------------------------------------------ //#define SINGLE_READ //#define SINGLE_WRITE // Timeout wait loop #define TO_LOOP 0x10000 // SD card operation states #define SD_STATE_IDLE 0 #define SD_STATE_INIT 1 #define SD_STATE_READY 2 #define SD_STATE_READ 0x10 #define SD_STATE_RD_RDY 0x11 #define SD_STATE_RD_BSY 0x12 #define SD_STATE_WRITE 0x20 #define SD_STATE_WR_RDY 0x21 #define SD_STATE_WR_BSY 0x22 #define SD_STATE_BOOT 0x30 // Delay between sending MMC commands #define MMC_DELAY 0x4FF #define SD_ADDRESS(pSd, address) \ ( ((pSd)->totalSize == 0xFFFFFFFF) ? \ (address):((address) << SD_BLOCK_SIZE_BIT) ) //----------------------------------------------------------------------------- /// MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS /// R1 is the low order byte; R2 is the next highest byte, when present. //----------------------------------------------------------------------------- #define R1_SPI_IDLE (1 << 0) #define R1_SPI_ERASE_RESET (1 << 1) #define R1_SPI_ILLEGAL_COMMAND (1 << 2) #define R1_SPI_COM_CRC (1 << 3) #define R1_SPI_ERASE_SEQ (1 << 4) #define R1_SPI_ADDRESS (1 << 5) #define R1_SPI_PARAMETER (1 << 6) // R1 bit 7 is always zero #define R2_SPI_CARD_LOCKED (1 << 0) #define R2_SPI_WP_ERASE_SKIP (1 << 1) #define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP #define R2_SPI_ERROR (1 << 2) #define R2_SPI_CC_ERROR (1 << 3) #define R2_SPI_CARD_ECC_ERROR (1 << 4) #define R2_SPI_WP_VIOLATION (1 << 5) #define R2_SPI_ERASE_PARAM (1 << 6) #define R2_SPI_OUT_OF_RANGE (1 << 7) #define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE // Status register constants #define STATUS_APP_CMD (1UL << 5) #define STATUS_SWITCH_ERROR (1UL << 7) #define STATUS_READY_FOR_DATA (1UL << 8) #define STATUS_IDLE (0UL << 9) #define STATUS_READY (1UL << 9) #define STATUS_IDENT (2UL << 9) #define STATUS_STBY (3UL << 9) #define STATUS_TRAN (4UL << 9) #define STATUS_DATA (5UL << 9) #define STATUS_RCV (6UL << 9) #define STATUS_PRG (7UL << 9) #define STATUS_DIS (8UL << 9) #define STATUS_STATE (0xFUL << 9) #define STATUS_ERASE_RESET (1UL << 13) #define STATUS_WP_ERASE_SKIP (1UL << 15) #define STATUS_CIDCSD_OVERWRITE (1UL << 16) #define STATUS_OVERRUN (1UL << 17) #define STATUS_UNERRUN (1UL << 18) #define STATUS_ERROR (1UL << 19) #define STATUS_CC_ERROR (1UL << 20) #define STATUS_CARD_ECC_FAILED (1UL << 21) #define STATUS_ILLEGAL_COMMAND (1UL << 22) #define STATUS_COM_CRC_ERROR (1UL << 23) #define STATUS_UN_LOCK_FAILED (1UL << 24) #define STATUS_CARD_IS_LOCKED (1UL << 25) #define STATUS_WP_VIOLATION (1UL << 26) #define STATUS_ERASE_PARAM (1UL << 27) #define STATUS_ERASE_SEQ_ERROR (1UL << 28) #define STATUS_BLOCK_LEN_ERROR (1UL << 29) #define STATUS_ADDRESS_MISALIGN (1UL << 30) #define STATUS_ADDR_OUT_OR_RANGE (1UL << 31) #define STATUS_STOP ( STATUS_CARD_IS_LOCKED \ | STATUS_COM_CRC_ERROR \ | STATUS_ILLEGAL_COMMAND \ | STATUS_CC_ERROR \ | STATUS_ERROR \ | STATUS_STATE \ | STATUS_READY_FOR_DATA ) #define STATUS_WRITE ( STATUS_ADDR_OUT_OR_RANGE \ | STATUS_ADDRESS_MISALIGN \ | STATUS_BLOCK_LEN_ERROR \ | STATUS_WP_VIOLATION \ | STATUS_CARD_IS_LOCKED \ | STATUS_COM_CRC_ERROR \ | STATUS_ILLEGAL_COMMAND \ | STATUS_CC_ERROR \ | STATUS_ERROR \ | STATUS_ERASE_RESET \ | STATUS_STATE \ | STATUS_READY_FOR_DATA ) #define STATUS_READ ( STATUS_ADDR_OUT_OR_RANGE \ | STATUS_ADDRESS_MISALIGN \ | STATUS_BLOCK_LEN_ERROR \ | STATUS_CARD_IS_LOCKED \ | STATUS_COM_CRC_ERROR \ | STATUS_ILLEGAL_COMMAND \ | STATUS_CARD_ECC_FAILED \ | STATUS_CC_ERROR \ | STATUS_ERROR \ | STATUS_ERASE_RESET \ | STATUS_STATE \ | STATUS_READY_FOR_DATA ) #define STATUS_SD_SWITCH ( STATUS_ADDR_OUT_OR_RANGE \ | STATUS_CARD_IS_LOCKED \ | STATUS_COM_CRC_ERROR \ | STATUS_ILLEGAL_COMMAND \ | STATUS_CARD_ECC_FAILED \ | STATUS_CC_ERROR \ | STATUS_ERROR \ | STATUS_UNERRUN \ | STATUS_OVERRUN \ | STATUS_STATE) #define STATUS_MMC_SWITCH ( STATUS_CARD_IS_LOCKED \ | STATUS_COM_CRC_ERROR \ | STATUS_ILLEGAL_COMMAND \ | STATUS_CC_ERROR \ | STATUS_ERROR \ | STATUS_ERASE_RESET \ | STATUS_STATE \ | STATUS_READY_FOR_DATA \ | STATUS_SWITCH_ERROR ) // | (0x3UL << 12) /* IO_CURRENT_STATE */ #define STATUS_SDIO_CMD52 ( (1UL << 15) /* COM_CRC_ERROR */ \ | (1UL << 14) /* ILLEGAL_COMMAND */ \ | (1UL << 11) /* ERRIR */ \ | (1UL << 9) /* FUNCTION_NUMBER */ \ | (1UL << 8) /* OUT_OF_RANGE */) //----------------------------------------------------------------------------- /// OCR Register //----------------------------------------------------------------------------- #define AT91C_VDD_16_17 (1UL << 4) #define AT91C_VDD_17_18 (1UL << 5) #define AT91C_VDD_18_19 (1UL << 6) #define AT91C_VDD_19_20 (1UL << 7) #define AT91C_VDD_20_21 (1UL << 8) #define AT91C_VDD_21_22 (1UL << 9) #define AT91C_VDD_22_23 (1UL << 10) #define AT91C_VDD_23_24 (1UL << 11) #define AT91C_VDD_24_25 (1UL << 12) #define AT91C_VDD_25_26 (1UL << 13) #define AT91C_VDD_26_27 (1UL << 14) #define AT91C_VDD_27_28 (1UL << 15) #define AT91C_VDD_28_29 (1UL << 16) #define AT91C_VDD_29_30 (1UL << 17) #define AT91C_VDD_30_31 (1UL << 18) #define AT91C_VDD_31_32 (1UL << 19) #define AT91C_VDD_32_33 (1UL << 20) #define AT91C_VDD_33_34 (1UL << 21) #define AT91C_VDD_34_35 (1UL << 22) #define AT91C_VDD_35_36 (1UL << 23) #define AT91C_SDIO_MP (1UL << 27) #define AT91C_SDIO_NF (7UL << 28) #define AT91C_MMC_OCR_BIT2930 (3UL << 29) #define AT91C_CARD_POWER_UP_BUSY (1UL << 31) #define AT91C_MMC_HOST_VOLTAGE_RANGE (AT91C_VDD_27_28 +\ AT91C_VDD_28_29 +\ AT91C_VDD_29_30 +\ AT91C_VDD_30_31 +\ AT91C_VDD_31_32 +\ AT91C_VDD_32_33) // MMC OCR response for Bit 29, 30 #define AT91C_MMC_NORM_DENSITY (0x0UL << 29) #define AT91C_MMC_HIGH_DENSITY (0x2UL << 29) #define AT91C_CCS (1 << 30) // MCI_CMD Register Value #define AT91C_POWER_ON_INIT (0 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_INIT \ | AT91C_MCI_OPDCMD) //----------------------------------------------------------------------------- /// eMMC CMD6 //----------------------------------------------------------------------------- #define AT91C_EMMC_CMD6ARG_ACCESS_BITS (0x3UL << 24) #define AT91C_EMMC_CMD6ARG_ACCESS_SHIFT (24) // change command sets #define AT91C_EMMC_CMD6ARG_ACCESS_CMDSETS (0x0UL << 24) // set bits in the value field #define AT91C_EMMC_CMD6ARG_ACCESS_SETBITS (0x1UL << 24) // clear bits in the value field #define AT91C_EMMC_CMD6ARG_ACCESS_CLRBITS (0x2UL << 24) // the value field is written into the pointed byte #define AT91C_EMMC_CMD6ARG_ACCESS_WRBYTES (0x3UL << 24) #define AT91C_EMMC_CMD6ARG_INDEX_BITS (0xffUL << 16) #define AT91C_EMMC_CMD6ARG_INDEX_SHIFT (16) #define AT91C_EMMC_CMD6ARG_VALUE_BITS (0xffUL << 8) #define AT91C_EMMC_CMD6ARG_VALUE_SHIFT (8) #define AT91C_EMMC_CMD6ARG_CMDSET_BITS (0x7UL << 0) #define AT91C_EMMC_CMD6ARG_CMDSET_SHIFT (0) //----------------------------------------------------------------------------- // Command Classes //----------------------------------------------------------------------------- // // Class 0, 2, 4, 5, 7 and 8 are mandatory and shall be supported by // all SD Memory Cards. // // Basic Commands (class 0) // // Cmd0 MCI + SPI #define AT91C_GO_IDLE_STATE_CMD (0 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE ) // Cmd1 SPI #define AT91C_MMC_SEND_OP_COND_CMD (1 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_OPDCMD) // Cmd2 MCI #define AT91C_ALL_SEND_CID_CMD (2 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_OPDCMD \ | AT91C_MCI_RSPTYP_136 ) // Cmd3 MCI #define AT91C_SET_RELATIVE_ADDR_CMD (3 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_OPDCMD \ | AT91C_MCI_MAXLAT ) // Cmd4 MCI #define AT91C_SET_DSR_CMD (4 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_NO \ | AT91C_MCI_MAXLAT ) // Cmd5 MCI #define AT91C_IO_SEND_OP_COND_CMD (5 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_OPDCMD ) // Cmd6 SD/MMC #if defined(MCI2_INTERFACE) #define AT91C_MMC_SWITCH_CMD (6 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_R1B \ | AT91C_MCI_MAXLAT ) #else #define AT91C_MMC_SWITCH_CMD (6 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) #endif #define AT91C_SD_SWITCH_CMD (6 | AT91C_MCI_TRCMD_START \ | AT91C_MCI_TRTYP_BLOCK \ | AT91C_MCI_TRDIR_READ \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) // cmd7 MCI #define AT91C_SEL_DESEL_CARD_CMD (7 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) #define AT91C_SEL_CARD_CMD (7 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) #define AT91C_DESEL_CARD_CMD (7 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_NO \ | AT91C_MCI_MAXLAT ) // Cmd8 MCI + SPI #define AT91C_SEND_IF_COND (8 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) // Cmd9 MCI + SPI #define AT91C_SEND_CSD_CMD (9 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_136 \ | AT91C_MCI_MAXLAT ) // Cmd10 MCI + SPI #define AT91C_SEND_CID_CMD (10 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_136 \ | AT91C_MCI_MAXLAT ) // Cmd12 MCI + SPI #if defined(MCI2_INTERFACE) #define AT91C_STOP_TRANSMISSION_CMD (12 | AT91C_MCI_TRCMD_STOP \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_R1B \ | AT91C_MCI_MAXLAT ) #else #define AT91C_STOP_TRANSMISSION_CMD (12 | AT91C_MCI_TRCMD_STOP \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) #endif // Cmd13 MCI + SPI #define AT91C_SEND_STATUS_CMD (13 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) // Cmd15 MCI #define AT91C_GO_INACTIVE_STATE_CMD (15 | AT91C_MCI_RSPTYP_NO ) // Cmd58 SPI #define AT91C_READ_OCR_CMD (58 | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_MAXLAT ) // Cmd59 SPI #define AT91C_CRC_ON_OFF_CMD (59 | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_MAXLAT ) //*------------------------------------------------ //* Class 2 commands: Block oriented Read commands //*------------------------------------------------ // Cmd8 for MMC #define AT91C_SEND_EXT_CSD_CMD (8 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_OPDCMD_PUSHPULL \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | AT91C_MCI_TRTYP_BLOCK \ | AT91C_MCI_TRDIR \ | AT91C_MCI_MAXLAT) // Cmd16 #define AT91C_SET_BLOCKLEN_CMD (16 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) // Cmd17 #define AT91C_READ_SINGLE_BLOCK_CMD (17 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | AT91C_MCI_TRTYP_BLOCK \ | AT91C_MCI_TRDIR \ | AT91C_MCI_MAXLAT) // Cmd18 #define AT91C_READ_MULTIPLE_BLOCK_CMD (18 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | AT91C_MCI_TRTYP_MULTIPLE \ | AT91C_MCI_TRDIR \ | AT91C_MCI_MAXLAT) //*------------------------------------------------ //* Class 4 commands: Block oriented write commands //*------------------------------------------------ // Cmd24 #define AT91C_WRITE_BLOCK_CMD (24 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | (AT91C_MCI_TRTYP_BLOCK \ & ~(AT91C_MCI_TRDIR)) \ | AT91C_MCI_MAXLAT) // Cmd25 #define AT91C_WRITE_MULTIPLE_BLOCK_CMD (25 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | (AT91C_MCI_TRTYP_MULTIPLE \ & ~(AT91C_MCI_TRDIR)) \ | AT91C_MCI_MAXLAT) // Cmd27 #define AT91C_PROGRAM_CSD_CMD (27 | AT91C_MCI_RSPTYP_48 ) //*---------------------------------------- //* Class 5 commands: Erase commands //*---------------------------------------- // Cmd32 //#define AT91C_TAG_SECTOR_START_CMD (32 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // Cmd33 //#define AT91C_TAG_SECTOR_END_CMD (33 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // Cmd38 //#define AT91C_ERASE_CMD (38 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT ) //*---------------------------------------- //* Class 7 commands: Lock commands //*---------------------------------------- // Cmd42 //#define AT91C_LOCK_UNLOCK (42 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // not tested //*----------------------------------------------- // Class 8 commands: Application specific commands //*----------------------------------------------- // Cmd55 #define AT91C_APP_CMD (55 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_MAXLAT) // cmd 56 //#define AT91C_GEN_CMD (56 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // not tested // ACMD6 #define AT91C_SD_SET_BUS_WIDTH_CMD (6 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_MAXLAT) // ACMD13 #define AT91C_SD_STATUS_CMD (13 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | AT91C_MCI_TRTYP_BLOCK \ | AT91C_MCI_TRDIR_READ \ | AT91C_MCI_MAXLAT) // ACMD22 //#define AT91C_SD_SEND_NUM_WR_BLOCKS_CMD (22 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // ACMD23 //#define AT91C_SD_SET_WR_BLK_ERASE_COUNT_CMD (23 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // ACMD41 #define AT91C_SD_APP_OP_COND_CMD (41 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_NO ) // ACMD42 //#define AT91C_SD_SET_CLR_CARD_DETECT_CMD (42 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // ACMD51 #define AT91C_SD_SEND_SCR_CMD (51 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | AT91C_MCI_TRDIR_READ \ | AT91C_MCI_TRTYP_BLOCK \ | AT91C_MCI_MAXLAT) // SDIO commands // CMD5, R4 #define AT91C_SDIO_SEND_OP_COND (5 | AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_OPDCMD) // CMD52, R5 #define AT91C_SDIO_IO_RW_DIRECT (52| AT91C_MCI_TRCMD_NO \ | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_MAXLAT ) // CMD53, R5 #define AT91C_SDIO_IO_RW_EXTENDED (53 | AT91C_MCI_SPCMD_NONE \ | AT91C_MCI_RSPTYP_48 \ | AT91C_MCI_TRCMD_START \ | AT91C_MCI_MAXLAT) #ifdef AT91C_MCI_SPCMD_BOOTREQ // BOOTREQ #define AT91C_BOOTREQ (AT91C_MCI_SPCMD_BOOTREQ \ | AT91C_MCI_TRDIR_READ \ | AT91C_MCI_TRCMD_START \ | AT91C_MCI_MAXLAT) // BOOTEND #define AT91C_BOOTEND (AT91C_MCI_SPCMD_BOOTEND \ | AT91C_MCI_OPDCMD_PUSHPULL) #endif // Optional commands #define SD_ACMD6_SUPPORT (1UL << 0) #define SD_ACMD13_SUPPORT (1UL << 1) #define SD_ACMD41_SUPPORT (1UL << 2) #define SD_ACMD51_SUPPORT (1UL << 3) #define SD_CMD16_SUPPORT (1UL << 8) //------------------------------------------------------------------------------ // Local functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// DecodeR1 /// \param R1 //------------------------------------------------------------------------------ void DecodeR1(unsigned char R1) { if( (R1 & R1_SPI_IDLE)==R1_SPI_IDLE) { TRACE_DEBUG("R1_SPI_IDLE\n\r"); } if( (R1 & R1_SPI_ERASE_RESET)==R1_SPI_ERASE_RESET) { TRACE_DEBUG("R1_SPI_ERASE_RESET\n\r"); } if( (R1 & R1_SPI_ILLEGAL_COMMAND)==R1_SPI_ILLEGAL_COMMAND) { TRACE_DEBUG("R1_SPI_ILLEGAL_COMMAND\n\r"); } if( (R1 & R1_SPI_COM_CRC)==R1_SPI_COM_CRC) { TRACE_DEBUG("R1_SPI_COM_CRC\n\r"); } if( (R1 & R1_SPI_ERASE_SEQ)==R1_SPI_ERASE_SEQ) { TRACE_DEBUG("R1_SPI_ERASE_SEQ\n\r"); } if( (R1 & R1_SPI_ADDRESS)==R1_SPI_ADDRESS) { TRACE_DEBUG("R1_SPI_ADDRESS\n\r"); } if( (R1 & R1_SPI_PARAMETER)==R1_SPI_PARAMETER) { TRACE_DEBUG("R1_SPI_PARAMETER\n\r"); } } //------------------------------------------------------------------------------ /// DecodeR2 /// \param R2 //------------------------------------------------------------------------------ void DecodeR2(unsigned char R2) { if( (R2 & R2_SPI_CARD_LOCKED)==R2_SPI_CARD_LOCKED) { TRACE_DEBUG("R2_SPI_CARD_LOCKED\n\r"); } if( (R2 & R2_SPI_WP_ERASE_SKIP)==R2_SPI_WP_ERASE_SKIP) { TRACE_DEBUG("R2_SPI_WP_ERASE_SKIP/R2_SPI_LOCK_UNLOCK_FAIL\n\r"); } if( (R2 & R2_SPI_ERROR)==R2_SPI_ERROR) { TRACE_DEBUG("R2_SPI_ERROR\n\r"); } if( (R2 & R2_SPI_CC_ERROR)==R2_SPI_CC_ERROR) { TRACE_DEBUG("R2_SPI_CC_ERROR\n\r"); } if( (R2 & R2_SPI_CARD_ECC_ERROR)==R2_SPI_CARD_ECC_ERROR) { TRACE_DEBUG("R2_SPI_CARD_ECC_ERROR\n\r"); } if( (R2 & R2_SPI_WP_VIOLATION)==R2_SPI_WP_VIOLATION) { TRACE_DEBUG("R2_SPI_WP_VIOLATION\n\r"); } if( (R2 & R2_SPI_ERASE_PARAM)==R2_SPI_ERASE_PARAM) { TRACE_DEBUG("R2_SPI_ERASE_PARAM\n\r"); } if( (R2 & R2_SPI_OUT_OF_RANGE)==R2_SPI_OUT_OF_RANGE) { TRACE_DEBUG("R2_SPI_OUT_OF_RANGE/R2_SPI_CSD_OVERWRITE\n\r"); } } //------------------------------------------------------------------------------ /// Get Trans Speed Value (Kbit/s) /// \param tranSpeed The TRAN_SPEED value from SD(IO)/MMC enum information. /// \param unitList Transfer rate units (Kbit/s), 4 units listed. /// \param nbUnits Transfer rate units list size. /// \param codeList Time value codes list, 16 codes listed. //------------------------------------------------------------------------------ static unsigned int MmcGetTranSpeed(unsigned int tranSpeed, const unsigned int* unitList, unsigned int nbUnits, const unsigned int* codeList) { unsigned int unit, value; unit = tranSpeed & 0x7; if (unit < nbUnits) unit = unitList[unit]; else return 0; value = (tranSpeed >> 3) & 0xF; if (value < 16) value = codeList[value]; else return 0; return (unit * value); } //------------------------------------------------------------------------------ /// Get Trans Speed Value /// \param pSd //------------------------------------------------------------------------------ void GetTransSpeedValue(SdCard *pSd) { // CSD register, TRANS_SPEED bit const unsigned int units[4] = {10, 100, 1000, 10000 }; // *Kbit/s const unsigned int values_emmc[16] = {0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80}; const unsigned int values_sdmmc[16] = {0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; #if 0 unsigned int unit, value; unit = (SD_CSD_TRAN_SPEED(pSd) & 0x7); if(unit < 4) unit = units[unit]; else return; value = (SD_CSD_TRAN_SPEED(pSd) >> 3) & 0xF; if (value < 16) { if (pSd->cardType >= CARD_MMC && SD_CID_BGA(pSd) == 1) { value = values_emmc[value]; } else value = values_sdmmc[value]; } else return; pSd->transSpeed = (unit * value); #else pSd->transSpeed = MmcGetTranSpeed(SD_CSD_TRAN_SPEED(pSd), units, 4, (pSd->cardType >= CARD_MMC && SD_CID_BGA(pSd) == 1) ? values_emmc : values_sdmmc); #endif if (pSd->cardType >= CARD_MMC && SD_EXTCSD_HS_TIMING(pSd)) { pSd->transSpeed *= 2; } TRACE_WARNING_WP("-I- SD/MMC TRANS SPEED %d KBit/s\r\n", pSd->transSpeed); pSd->transSpeed *= 1000; } #if 1 //------------------------------------------------------------------------------ /// Reset the SdCmd //------------------------------------------------------------------------------ static void ResetCommand(SdCmd *pCommand) { #if 0 unsigned char* p = (unsigned char*)pCommand; unsigned int l = sizeof(SdCmd); while(l --) *p++ = 0; #else pCommand->cmd = 0; pCommand->arg = 0; pCommand->pData = 0; pCommand->blockSize = 0; pCommand->nbBlock = 0; pCommand->pResp = 0; pCommand->callback = 0; pCommand->pArg = 0; pCommand->resType = 0; pCommand->dataTran = 0; pCommand->tranType = 0; pCommand->isRead = 0; pCommand->status = 0; #endif } #else // GNU halt on memset now # define ResetCommand(pCommand) memset(pCommand, 0, sizeof(SdCmd)) #endif //------------------------------------------------------------------------------ /// Delay some loop //------------------------------------------------------------------------------ static void Delay(volatile unsigned int loop) { for(;loop > 0; loop --); } //------------------------------------------------------------------------------ /// Sends the current SD card driver command to the card. /// Returns 0 if successful; Otherwise, returns the transfer status code or /// SD_ERROR_DRIVER if there was a problem with the SD transfer. /// \param pSd Pointer to a SdCard driver instance. //------------------------------------------------------------------------------ static unsigned char SendCommand(SdCard *pSd) { SdCmd *pCommand = &(pSd->command); SdDriver *pSdDriver = pSd->pSdDriver; unsigned char error; // Send command error = MCI_SendCommand((Mci *)pSdDriver, (MciCmd *)pCommand); if (error) { TRACE_ERROR("MCI SendCommand: Failed to send command (%d)\n\r", error); return SD_ERROR_DRIVER; } // Wait for command to complete (if no callback defined) if (pCommand->callback == 0) { while (!MCI_IsTxComplete((Mci *)pSdDriver)); } // Check for using fifo to transfer data #if !defined(MCI_DMA_ENABLE) && defined(MCI2_INTERFACE) if (pCommand->dataTran && pCommand->nbBlock) { MCI_FifoTransfer((Mci *)pSdDriver, (MciCmd *)pCommand); } #endif return pCommand->status; } //------------------------------------------------------------------------------ /// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp /// up time. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SdCard driver instance. //------------------------------------------------------------------------------ static unsigned char Pon(SdCard *pSd) { SdCmd *pCommand = &(pSd->command); unsigned int response; unsigned char error; ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_POWER_ON_INIT; pCommand->pResp = &response; // Send command error = SendCommand(pSd); return error; } #if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ) //------------------------------------------------------------------------------ /// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp /// up time, CMD keeps low so that the device run in boot mode. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SdCard driver instance. //------------------------------------------------------------------------------ static unsigned char PonBoot(SdCard *pSd) { SdCmd *pCommand = &(pSd->command); unsigned int response; unsigned char error; ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_POWER_ON_INIT; pCommand->pResp = &response; // Send command error = SendCommand(pSd); return error; } #endif //------------------------------------------------------------------------------ /// Resets all cards to idle state /// \param pSd Pointer to a SdCard driver instance. /// \param arg Argument used. /// \return the command transfer result (see SendCommand). //------------------------------------------------------------------------------ static unsigned char Cmd0(SdCard *pSd, unsigned int arg) { SdCmd *pCommand = &(pSd->command); unsigned int response; unsigned char error; TRACE_DEBUG("Cmd0()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_GO_IDLE_STATE_CMD; pCommand->arg = arg; pCommand->pResp = &response; // send command error = SendCommand(pSd); return error; } //------------------------------------------------------------------------------ /// MMC send operation condition command. /// Sends host capacity support information and activates the card's /// initialization process. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SdCard driver instance. /// \param hdSupport Indicate whether the host support high density MMC. /// \param pHdSupport Indicate whether the card is a high density MMC. //------------------------------------------------------------------------------ static unsigned char Cmd1(SdCard *pSd, unsigned char hdSupport, unsigned char *pHdSupport) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd1()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_MMC_SEND_OP_COND_CMD; pCommand->arg = AT91C_MMC_HOST_VOLTAGE_RANGE; if(hdSupport) { pCommand->arg |= AT91C_MMC_HIGH_DENSITY; } else { pCommand->arg |= AT91C_MMC_NORM_DENSITY; } pCommand->resType = 3; pCommand->pResp = &response; // send command *pHdSupport = 0; error = SendCommand(pSd); if (error) { return error; } if ((response & AT91C_CARD_POWER_UP_BUSY) == AT91C_CARD_POWER_UP_BUSY) { if((response & AT91C_MMC_OCR_BIT2930) == AT91C_MMC_HIGH_DENSITY) { *pHdSupport = 1; } return 0; } else { return SD_ERROR_DRIVER; } } //------------------------------------------------------------------------------ /// Asks any card to send the CID numbers /// on the CMD line (any card that is /// connected to the host will respond) /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. /// \param pCid Buffer for storing the CID numbers. //------------------------------------------------------------------------------ static unsigned char Cmd2(SdCard *pSd) { SdCmd *pCommand = &(pSd->command); TRACE_DEBUG("Cmd2()\n\r"); ResetCommand(pCommand); // Fill the command information pCommand->cmd = AT91C_ALL_SEND_CID_CMD; pCommand->resType = 2; pCommand->pResp = pSd->cid; // Send the command return SendCommand(pSd); } //------------------------------------------------------------------------------ /// Ask the card to publish a new relative address (RCA) /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ static unsigned char Cmd3(SdCard *pSd) { SdCmd *pCommand = &(pSd->command); unsigned int cardAddress; unsigned char error; TRACE_DEBUG("Cmd3()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SET_RELATIVE_ADDR_CMD; // Assign relative address to MMC card if ((pSd->cardType == CARD_MMC) || (pSd->cardType == CARD_MMCHD)) { pCommand->arg = (0x1 << 16); } pCommand->resType = 1; pCommand->pResp = &cardAddress; // Send command error = SendCommand(pSd); if (error) { return error; } // Save card address in driver if ( (pSd->cardType == CARD_SD) || (pSd->cardType == CARD_SDHC)) { pSd->cardAddress = (cardAddress >> 16) & 0xFFFF; } else if (pSd->cardType >= CARD_SDIO) { pSd->cardAddress = (cardAddress >> 16) & 0xFFFF; } else { // Default MMC RCA is 0x0001 pSd->cardAddress = 1; } return 0; } #if MCI_SDIO_ENABLE //------------------------------------------------------------------------------ /// SDIO send operation condition command. /// Sends host capacity support information and activates the card's /// initialization process. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SdCard driver instance. /// \param pIo Pointer to data send as well as response buffer. //------------------------------------------------------------------------------ static unsigned char Cmd5(SdCard *pSd, unsigned int *pIo) { SdCmd *pCommand = &(pSd->command); unsigned char error; TRACE_DEBUG("Cmd5()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_IO_SEND_OP_COND_CMD; pCommand->arg = *pIo; pCommand->resType = 4; pCommand->pResp = pIo; // send command error = SendCommand(pSd); return error; } #endif //------------------------------------------------------------------------------ /// Command toggles a card between the /// stand-by and transfer states or between /// the programming and disconnect states. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. /// \param address Relative Card Address (0 deselects all). //------------------------------------------------------------------------------ static unsigned char Cmd7(SdCard *pSd, unsigned int address) { SdCmd *pCommand = &(pSd->command); TRACE_DEBUG("Cmd7()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SEL_DESEL_CARD_CMD; pCommand->arg = address << 16; pCommand->resType = 1; // Send command return SendCommand(pSd); } //------------------------------------------------------------------------------ /// Switches the mode of operation of the selected card (SD/MMC) or /// modifies the EXT_CSD registers (for MMC only). /// CMD6 is valid under the "trans" state. /// \return The command transfer result (see SendCommand). /// \param pSd Pointer to a SD/MMC card driver instance. /// \param pSwitchArg Pointer to a MmcCmd6Arg instance. /// \param pStatus Pointer to where the 512bit status is returned. /// \param pResp Pointer to where the response is returned. //------------------------------------------------------------------------------ static unsigned char Cmd6(SdCard *pSd, const void * pSwitchArg, unsigned int * pStatus, unsigned int * pResp) { SdCmd *pCommand = &(pSd->command); unsigned int response; unsigned char error; SdCmd6Arg * pSdSwitch; MmcCmd6Arg * pMmcSwitch; SANITY_CHECK(pSd); SANITY_CHECK(pSwitchArg); TRACE_DEBUG("CMD6()\n\r"); ResetCommand(pCommand); if (pSd->cardType >= CARD_MMC) { pMmcSwitch = (MmcCmd6Arg*)pSwitchArg; // R1b response pCommand->cmd = AT91C_MMC_SWITCH_CMD; pCommand->resType = 1; pCommand->arg = (pMmcSwitch->access << 24) | (pMmcSwitch->index << 16) | (pMmcSwitch->value << 8) | (pMmcSwitch->cmdSet << 0); } else if (pSd->cardType >= CARD_SD) { pSdSwitch = (SdCmd6Arg*)pSwitchArg; // R1 response & 512 bits of status on DAT pCommand->cmd = AT91C_SD_SWITCH_CMD; pCommand->resType = 1; pCommand->arg = (pSdSwitch->mode << 31) | (pSdSwitch->reserved << 30) | (pSdSwitch->reserveFG6 << 20) | (pSdSwitch->reserveFG5 << 16) | (pSdSwitch->reserveFG4 << 12) | (pSdSwitch->reserveFG3 << 8) | (pSdSwitch->command << 4) | (pSdSwitch->accessMode << 0); if (pStatus) { pCommand->blockSize = 512 / 8; pCommand->nbBlock = 1; pCommand->pData = (unsigned char*)pStatus; pCommand->dataTran = 1; pCommand->isRead = 1; pCommand->tranType = MCI_NEW_TRANSFER; } } pCommand->pResp = &response; TRACE_INFO("CMD6(%d) arg 0x%X\n\r", pSd->cardType, pCommand->arg); error = SendCommand(pSd); if (error) return error; else if (pResp) *pResp = response; return 0; } //------------------------------------------------------------------------------ /// SD: Sends SD Memory Card interface condition, which includes host supply /// voltage information and asks the card whether card supports voltage. /// Should be performed at initialization time to detect the card type. /// MMC: SEND_EXT_CSD, to get EXT_CSD register as a block of data. /// Valid under "trans" state. /// \param pSd Pointer to a SD card driver instance. /// \param sdCmd For SD Memory Card interface condition /// \param arg Expected supply voltage(SD) or 512 byte buffer pointer (MMC). /// \return 0 if successful; /// otherwise returns SD_ERROR_NORESPONSE if the card did not answer /// the command, or SD_ERROR_DRIVER. //------------------------------------------------------------------------------ static unsigned char Cmd8(SdCard *pSd, unsigned char sdCmd, void* arg) { SdCmd *pCommand = &(pSd->command); unsigned int response; unsigned char error; unsigned char supplyVoltage = (unsigned char)((unsigned int)arg); TRACE_DEBUG("Cmd8()\n\r"); ResetCommand(pCommand); if (sdCmd) { // Fill command information pCommand->cmd = AT91C_SEND_IF_COND; pCommand->arg = (supplyVoltage << 8) | (0xAA); pCommand->resType = 7; TRACE_DEBUG("supplyVoltage: 0x%x\n\r", supplyVoltage); } else { pCommand->cmd = AT91C_SEND_EXT_CSD_CMD; pCommand->resType = 1; pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = 512 / SD_BLOCK_SIZE; pCommand->pData = arg; pCommand->dataTran = 1; pCommand->isRead = 1; pCommand->tranType = MCI_NEW_TRANSFER; } pCommand->pResp = &response; // Send command error = SendCommand(pSd); if (sdCmd) { // Check result if (error == MCI_STATUS_NORESPONSE) { return SD_ERROR_NORESPONSE; } // SD_R7 // Bit 0 - 7: check pattern (echo-back) // Bit 8 -11: voltage accepted else if (!error && ((response & 0x00000FFF) == ((supplyVoltage << 8) | 0xAA))) { return 0; } else { return SD_ERROR_DRIVER; } } return error; } //------------------------------------------------------------------------------ /// Addressed card sends its card-specific /// data (CSD) on the CMD line. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ static unsigned char Cmd9(SdCard *pSd) { SdCmd *pCommand = &(pSd->command); unsigned char error; TRACE_DEBUG("Cmd9()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SEND_CSD_CMD; pCommand->arg = pSd->cardAddress << 16; pCommand->resType = 2; pCommand->pResp = pSd->csd; // Send command error = SendCommand(pSd); return error; } //------------------------------------------------------------------------------ /// Forces the card to stop transmission /// \param pSd Pointer to a SD card driver instance. /// \param stopRead Stop reading stream/writing stream. /// \param pStatus Pointer to a status variable. //------------------------------------------------------------------------------ static unsigned char Cmd12(SdCard *pSd, unsigned char stopRead, unsigned int *pStatus) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd12()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_STOP_TRANSMISSION_CMD; pCommand->isRead = stopRead; pCommand->tranType = MCI_STOP_TRANSFER; pCommand->resType = 1; pCommand->pResp = &response; // Send command error = SendCommand(pSd); if (pStatus) *pStatus = response; return error; } //------------------------------------------------------------------------------ /// Addressed card sends its status register. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. /// \param pStatus Pointer to a status variable. //------------------------------------------------------------------------------ static unsigned char Cmd13(SdCard *pSd, unsigned int *pStatus) { SdCmd *pCommand = &(pSd->command); unsigned char error; TRACE_DEBUG("Cmd13()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SEND_STATUS_CMD; pCommand->arg = pSd->cardAddress << 16; pCommand->resType = 1; pCommand->pResp = pStatus; // Send command error = SendCommand(pSd); return error; } //------------------------------------------------------------------------------ /// In the case of a Standard Capacity SD Memory Card, this command sets the /// block length (in bytes) for all following block commands /// (read, write, lock). /// Default block length is fixed to 512 Bytes. /// Set length is valid for memory access commands only if partial block read /// operation are allowed in CSD. /// In the case of a High Capacity SD Memory Card, block length set by CMD16 /// command does not affect the memory read and write commands. Always 512 /// Bytes fixed block length is used. This command is effective for LOCK_UNLOCK /// command. In both cases, if block length is set larger than 512Bytes, the /// card sets the BLOCK_LEN_ERROR bit. /// \param pSd Pointer to a SD card driver instance. /// \param blockLength Block length in bytes. //------------------------------------------------------------------------------ static unsigned char Cmd16(SdCard *pSd, unsigned short blockLength) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd16()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SET_BLOCKLEN_CMD; pCommand->arg = blockLength; pCommand->resType = 1; pCommand->pResp = &response; // Send command error = SendCommand(pSd); return error; } #ifdef SINGLE_READ static unsigned char Cmd17(SdCard *pSd, unsigned char *pData, unsigned int address, unsigned int *pStatus) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd17()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_READ_SINGLE_BLOCK_CMD; pCommand->arg = address; pCommand->resType = 1; pCommand->pResp = &response; pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = 1; pCommand->pData = pData; pCommand->dataTran = 1; pCommand->isRead = 1; pCommand->tranType = MCI_NEW_TRANSFER; // Send command error = SendCommand(pSd); if (pStatus) *pStatus = response; return error; } #endif //------------------------------------------------------------------------------ /// Continously transfers datablocks from card to host until interrupted by a /// STOP_TRANSMISSION command. /// \param pSd Pointer to a SD card driver instance. /// \param blockSize Block size (shall be set to 512 in case of high capacity). /// \param pData Pointer to the DW aligned buffer to be filled. /// \param address SD card address. //------------------------------------------------------------------------------ static unsigned char Cmd18(SdCard *pSd, unsigned short nbBlock, unsigned char *pData, unsigned int address, unsigned int *pStatus) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd18()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_READ_MULTIPLE_BLOCK_CMD; pCommand->arg = address; pCommand->resType = 1; pCommand->pResp = &response; pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = nbBlock; pCommand->pData = pData; pCommand->dataTran = 1; pCommand->isRead = 1; pCommand->tranType = MCI_NEW_TRANSFER; // Send command error = SendCommand(pSd); if (pStatus) *pStatus = response; return error; } #ifdef SINGLE_WRITE static unsigned char Cmd24(SdCard *pSd, unsigned char *pData, unsigned int address, unsigned int *pStatus) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd24()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_WRITE_BLOCK_CMD; pCommand->arg = address; pCommand->resType = 1; pCommand->pResp = &response; pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = 1; pCommand->pData = pData; pCommand->dataTran = 1; pCommand->isRead = 0; pCommand->tranType = MCI_NEW_TRANSFER; // Send command error = SendCommand(pSd); if (pStatus) *pStatus = response; return error; } #endif //------------------------------------------------------------------------------ /// Write block command /// \param pSd Pointer to a SD card driver instance. /// \param blockSize Block size (shall be set to 512 in case of high capacity). /// \param pData Pointer to the DW aligned buffer to be filled. /// \param address SD card address. //------------------------------------------------------------------------------ static unsigned char Cmd25(SdCard *pSd, unsigned short nbBlock, unsigned char *pData, unsigned int address, unsigned int *pStatus) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd25()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_WRITE_MULTIPLE_BLOCK_CMD; pCommand->arg = address; pCommand->resType = 1; pCommand->pResp = &response; pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = nbBlock; pCommand->pData = pData; pCommand->dataTran = 1; pCommand->tranType = MCI_NEW_TRANSFER; // Send command error = SendCommand(pSd); if (pStatus) *pStatus = response; return error; } #if MCI_SDIO_ENABLE //------------------------------------------------------------------------------ /// SDIO R/W Byte Direct, response R5 /// \param pSd Pointer to SdCard instance. /// \param func Number of function. /// \param rw The direction of IO operation, 1 for write. /// \param raw Read after write /// \param addr The register address to access. /// \param pIoData Pointer to fill written data and response. //------------------------------------------------------------------------------ static unsigned char Cmd52(SdCard *pSd, unsigned char func, unsigned char rw, unsigned char raw, unsigned int addr, unsigned int *pIoData) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; unsigned char byte = 0; TRACE_DEBUG("Cmd52()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SDIO_IO_RW_DIRECT; // - argument if (pIoData) byte = *pIoData; pCommand->arg = byte | (addr << 9) // register address 25: 9 | (raw << 27) // ReadAfterWrite 27 | (func << 28) // FunctionNumber 30:28 | (rw << 31); // R/W 31 pCommand->resType = 5; pCommand->pResp = &response; // Send command error = SendCommand(pSd); if (pIoData) *pIoData = response; return error; } //------------------------------------------------------------------------------ /// SDIO R/W Extended, response R5 /// \param pSd Pointer to SdCard instance. /// \param func Number of function. /// \param rw The direction of IO operation, 1 for write. /// \param blockMode R/O on a block basis /// \param incAddress R/W to incrementing address (1) or fixed address (0) /// \param addr The register address to access. /// \param pIoData Pointer to fill written data and response. /// \param size Data size base on bytes or blocks depending on blockMode /// \param pResp Pointer to response buffer //------------------------------------------------------------------------------ static unsigned char Cmd53(SdCard *pSd, unsigned char func, unsigned char rw, unsigned char blockMode, unsigned char incAddress, unsigned int addr, unsigned char *pIoData, unsigned short size, unsigned int *pResp) { SdCmd *pCommand = &(pSd->command); unsigned char error; TRACE_DEBUG("Cmd53()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SDIO_IO_RW_EXTENDED; // - argument pCommand->arg = size | (addr << 9) // register address 25: 9 | (incAddress << 26) // OP Code 26 | (blockMode << 27) // ReadAfterWrite 27 | (func << 28) // FunctionNumber 30:28 | (rw << 31); // R/W 31 pCommand->resType = 5; pCommand->pResp = pResp; // - Write... if (rw) {} else { pCommand->cmd |= AT91C_MCI_TRDIR_READ; pCommand->isRead = 1; } // - Block... if (blockMode) { pCommand->cmd |= AT91C_MCI_TRTYP_SDIO_BLOCK | AT91C_MCI_TRCMD_START; pCommand->blockSize = SD_BLOCK_SIZE; } else { pCommand->cmd |= AT91C_MCI_TRTYP_SDIO_BYTE | AT91C_MCI_TRCMD_START; pCommand->blockSize = 1; } pCommand->nbBlock = size; pCommand->pData = pIoData; pCommand->dataTran = 1; pCommand->tranType = MCI_NEW_TRANSFER; // Send command error = SendCommand(pSd); return error; } #endif //------------------------------------------------------------------------------ /// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply /// ramp up time. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ static unsigned char Cmd55(SdCard *pSd) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd55()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_APP_CMD; pCommand->arg = (pSd->cardAddress << 16); pCommand->resType = 1; pCommand->pResp = &response; // Send command error = SendCommand(pSd); return error; } /* //------------------------------------------------------------------------------ /// SPI Mode, Reads the OCR register of a card /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. /// \param pOcr OCR value of the card //------------------------------------------------------------------------------ static unsigned char Cmd58(SdCard *pSd, unsigned int *pOcr) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response[2]; TRACE_DEBUG("Cmd58()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_READ_OCR_CMD; pCommand->resType = 3; pCommand->pResp = &response[0]; // Send command error = SendCommand(pSd); return error; } //------------------------------------------------------------------------------ /// SPI Mode, Set CRC option of a card /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. /// \param option CRC option, 1 to turn on, 0 to trun off //------------------------------------------------------------------------------ static unsigned char Cmd59(SdCard *pSd, unsigned char option) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Cmd59()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_CRC_ON_OFF_CMD; pCommand->arg = (option & 0x1); pCommand->resType = 1; pCommand->pResp = &response; // Send command error = SendCommand(pSd); return error; } */ //------------------------------------------------------------------------------ /// Defines the data bus width (00=1bit or 10=4 bits bus) to be used for data /// transfer. /// The allowed data bus widths are given in SCR register. /// \param pSd Pointer to a SD card driver instance. /// \param busWidth Bus width in bits. /// \return the command transfer result (see SendCommand). //------------------------------------------------------------------------------ static unsigned char Acmd6(SdCard *pSd, unsigned char busWidth) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; TRACE_DEBUG("Acmd6()\n\r"); error = Cmd55(pSd); if (error) { TRACE_ERROR("Acmd6.Cmd55: %d\n\r", error); return error; } ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SD_SET_BUS_WIDTH_CMD; pCommand->arg = (busWidth == 4) ? SD_STAT_DATA_BUS_WIDTH_4BIT : SD_STAT_DATA_BUS_WIDTH_1BIT; pCommand->resType = 1; pCommand->pResp = &response; // Send command return SendCommand(pSd); } //------------------------------------------------------------------------------ /// The SD Status contains status bits that are related to the SD memory Card /// proprietary features and may be used for future application-specific usage. /// Can be sent to a card only in 'tran_state'. //------------------------------------------------------------------------------ static unsigned char Acmd13(SdCard *pSd, unsigned int * pSdSTAT) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response[1]; TRACE_DEBUG("Acmd13()\n\r"); error = Cmd55(pSd); if (error) { TRACE_ERROR("Acmd13.Cmd55: %d\n\r", error); return error; } ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SD_STATUS_CMD; pCommand->resType = 1; pCommand->pResp = response; pCommand->blockSize = 512 / 8; pCommand->nbBlock = 1; pCommand->pData = (unsigned char*)pSdSTAT; pCommand->dataTran = 1; pCommand->isRead = 1; pCommand->tranType = MCI_NEW_TRANSFER; // Send command error = SendCommand(pSd); return error; } //------------------------------------------------------------------------------ /// Asks to all cards to send their operations conditions. /// Returns the command transfer result (see SendCommand). /// \param pSd Pointer to a SD card driver instance. /// \param hcs Shall be true if Host support High capacity. /// \param pCCS Set the pointed flag to 1 if hcs != 0 and SD OCR CCS flag is set. //------------------------------------------------------------------------------ static unsigned char Acmd41(SdCard *pSd, unsigned char hcs, unsigned char *pCCS) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response; do { error = Cmd55(pSd); if (error) { return error; } ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SD_APP_OP_COND_CMD; pCommand->arg = AT91C_MMC_HOST_VOLTAGE_RANGE; if (hcs) { pCommand->arg |= AT91C_CCS; } pCommand->resType = 3; pCommand->pResp = &response; // Send command TRACE_DEBUG("Acmd41()\n\r"); error = SendCommand(pSd); if (error) { return error; } *pCCS = ((response & AT91C_CCS) != 0); } while ((response & AT91C_CARD_POWER_UP_BUSY) != AT91C_CARD_POWER_UP_BUSY); return 0; } //------------------------------------------------------------------------------ /// SD Card Configuration Register (SCR) provides information on the SD Memory /// Card's special features that were configured into the given card. The size /// of SCR register is 64 bits. //------------------------------------------------------------------------------ static unsigned char Acmd51(SdCard *pSd, unsigned int * pSCR) { SdCmd *pCommand = &(pSd->command); unsigned char error; unsigned int response[1]; TRACE_DEBUG("Acmd51()\n\r"); error = Cmd55(pSd); if (error) { TRACE_ERROR("Acmd51.Cmd55: %d\n\r", error); return error; } ResetCommand(pCommand); // Fill command information pCommand->cmd = AT91C_SD_SEND_SCR_CMD; pCommand->resType = 1; pCommand->pResp = response; pCommand->blockSize = 64 / 8; pCommand->nbBlock = 1; pCommand->pData = (unsigned char*)pSCR; pCommand->dataTran = 1; pCommand->isRead = 1; pCommand->tranType = MCI_NEW_TRANSFER; // Send command error = SendCommand(pSd); //if (!error) Int2MsbFirstStream((unsigned char*)pSCR, 8 / 4); return error; } #if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ) //------------------------------------------------------------------------------ /// Terminate boot stream. /// \param pSd Pointer to SdCard instance. //------------------------------------------------------------------------------ static unsigned char BootEnd(SdCard *pSd) { SdCmd * pCommand = &(pSd->command); TRACE_DEBUG("BootEnd()\n\r"); ResetCommand(pCommand); // Send boot end pCommand->cmd = AT91C_BOOTEND; return SendCommand(pSd); } //------------------------------------------------------------------------------ /// In boot operation mode, the processor can read boot data from the slave, /// by keeping the CMD line low after power-on before issuing CMD1. /// BootEnd() must be invoked after the boot request done. /// \param pSd Pointer to SdCard instance. /// \param pBuffer The buffer holding received data. /// \param length The buffer length. //------------------------------------------------------------------------------ static unsigned char BootREQ(SdCard *pSd, unsigned char* pBuffer, unsigned int nbBlocks, unsigned char ackEnable) { SdCmd * pCommand = &(pSd->command); unsigned char error; TRACE_DEBUG("BootREQ()\n\r"); ResetCommand(pCommand); // Send boot request pCommand->cmd = ackEnable ? (AT91C_BOOTREQ | AT91C_MCI_BOOTACK) : AT91C_BOOTREQ; pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = nbBlocks; pCommand->pData = pBuffer; pCommand->isRead = 1; pCommand->tranType = MCI_NEW_TRANSFER; error = SendCommand(pSd); if (error) { TRACE_ERROR("BootOperation.BootReq: %d\n\r", error); return error; } return error; } #endif //------------------------------------------------------------------------------ /// Continue to transfer datablocks from card to host until interrupted by a /// STOP_TRANSMISSION command. /// \param pSd Pointer to a SD card driver instance. /// \param blockSize Block size (shall be set to 512 in case of high capacity). /// \param pData Pointer to the application buffer to be filled. /// \param address SD card address. //------------------------------------------------------------------------------ static unsigned char ContinuousRead(SdCard *pSd, unsigned short nbBlock, unsigned char *pData, SdCallback pCb, void *pArg) { SdCmd *pCommand = &(pSd->command); TRACE_DEBUG("Read()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = nbBlock; pCommand->pData = pData; pCommand->dataTran = 1; pCommand->tranType = MCI_CONTINUE_TRANSFER; pCommand->isRead = 1; pCommand->callback = pCb; pCommand->pArg = pArg; // Send command return SendCommand(pSd); } //------------------------------------------------------------------------------ /// Continue to transfer datablocks from host to card until interrupted by a /// STOP_TRANSMISSION command. /// \param pSd Pointer to a SD card driver instance. /// \param blockSize Block size (shall be set to 512 in case of high capacity). /// \param pData Pointer to the application buffer to be filled. //------------------------------------------------------------------------------ static unsigned char ContinuousWrite(SdCard *pSd, unsigned short nbBlock, const unsigned char *pData, SdCallback pCb, void *pArg) { SdCmd *pCommand = &(pSd->command); TRACE_DEBUG("Write()\n\r"); ResetCommand(pCommand); // Fill command information pCommand->blockSize = SD_BLOCK_SIZE; pCommand->nbBlock = nbBlock; pCommand->pData = (unsigned char*)pData; pCommand->dataTran = 1; pCommand->tranType = MCI_CONTINUE_TRANSFER; pCommand->callback = pCb; pCommand->pArg = pArg; // Send command return SendCommand(pSd); } //------------------------------------------------------------------------------ /// Try SW Reset several times (CMD0 with ARG 0) /// \param pSd Pointer to a SD card driver instance. /// \param retry Retry times. /// \return 0 or MCI error code. //------------------------------------------------------------------------------ static unsigned char SwReset(SdCard *pSd, unsigned int retry) { unsigned int i; unsigned char error = 0; for (i = 0; i < retry; i ++) { error = Cmd0(pSd, 0); if (error != MCI_STATUS_NORESPONSE) break; } return error; } /* //------------------------------------------------------------------------------ /// Re-init card to trans state. //------------------------------------------------------------------------------ static unsigned char ReInit(SdCard *pSd) { #if 0 unsigned char error; error = SwReset(pSd, 1); if (error) { TRACE_ERROR("ReInit.Cmd0: %d\n\r", error); return error; } error = Cmd1(pSd); if (error) { TRACE_ERROR("ReInit.Cmd1: %d\n\r", error); return error; } error = Cmd2(pSd); if (error) { TRACE_ERROR("ReInit.Cmd2: %d\n\r", error); return error; } error = Cmd3(pSd); if (error) { TRACE_ERROR("ReInit.Cmd3: %d\n\r", error); return error; } error = Cmd7(pSd, pSd->cardAddress); if (error) { TRACE_ERROR("ReInit.Cmd7: %d\n\r", error); return error; } #endif return 0; } */ //------------------------------------------------------------------------------ /// Move SD card to transfer state. //------------------------------------------------------------------------------ static unsigned char MoveToTranState(SdCard * pSd) { unsigned char error; unsigned int status; // Quit transfer state if((pSd->state == SD_STATE_READ) || (pSd->state == SD_STATE_WRITE)) { error = Cmd12(pSd, (pSd->state == SD_STATE_READ), &status); if (error) { TRACE_ERROR("MvToTran.Cmd12: %d\n\r", error); return error; } } // Put device into tran state error = Cmd13(pSd, &status); if (error) { TRACE_ERROR("MvToTran.Cmd13: %d\n\r", error); return error; } if ((status & STATUS_STATE) == STATUS_STBY) { error = Cmd7(pSd, pSd->cardAddress); if (error) { TRACE_ERROR("MvToTran.Cmd7: %d\n\r", error); return error; } } return 0; } #if defined(SINGLE_READ) || defined(SINGLE_WRITE) static unsigned char PerformSingleTransfer(SdCard *pSd, unsigned int address, unsigned char *pData, unsigned char isRead) { unsigned int status; unsigned char error = 0; /* Reset transfer state if previous in multi- mode */ if( (pSd->state == SD_STATE_READ) || (pSd->state == SD_STATE_WRITE)) { /* Stop transfer */ error = Cmd12(pSd, (pSd->state == SD_STATE_READ), &status); if (error) { TRACE_ERROR("SingleTx.Cmd12: st%x, er%d\n\r", pSd->state, error); } pSd->state = SD_STATE_READY; pSd->preBlock = 0xFFFFFFFF; } #ifdef SINGLE_READ if(isRead) { // Wait for card to be ready for data transfers do { error = Cmd13(pSd, &status); if (error) { TRACE_ERROR("SingleTx.RD.Cmd13: %d\n\r", error); return error; } if( ((status & STATUS_STATE) == STATUS_IDLE) ||((status & STATUS_STATE) == STATUS_READY) ||((status & STATUS_STATE) == STATUS_IDENT)) { TRACE_ERROR("SingleTx.mode\n\r"); return SD_ERROR_NOT_INITIALIZED; } // If the card is in sending data state or in receivce data state if ( ((status & STATUS_STATE) == STATUS_RCV) ||((status & STATUS_STATE) == STATUS_DATA) ){ TRACE_DEBUG("SingleTx.state = 0x%X\n\r", (status & STATUS_STATE) >> 9); } } while ( ((status & STATUS_READY_FOR_DATA) == 0) || ((status & STATUS_STATE) != STATUS_TRAN) ); ASSERT((status & STATUS_STATE) == STATUS_TRAN, "SD Card can't be configured in transfer state 0x%X\n\r", (status & STATUS_STATE)>>9); // Read data // Move to Sending data state error = Cmd17(pSd, pData, SD_ADDRESS(pSd,address), &status); if (error) { TRACE_ERROR("SingleTx.Cmd17: %d\n\r", error); return error; } if (status & ~(STATUS_READY_FOR_DATA | STATUS_STATE)) { TRACE_ERROR("CMD17.stat: %x\n\r", status & ~(STATUS_READY_FOR_DATA | STATUS_STATE)); return SD_ERROR_DRIVER; } return error; } #endif #ifdef SINGLE_WRITE // Write { // Wait for card to be ready for data transfers do { error = Cmd13(pSd, &status); if (error) { TRACE_ERROR("SingleTx.WR.Cmd13: %d\n\r", error); return error; } } while ((status & STATUS_READY_FOR_DATA) == 0); // Move to Sending data state error = Cmd24(pSd, pData, SD_ADDRESS(pSd,address), &status); if (error) { TRACE_DEBUG("SingleTx.Cmd25: %d\n\r", error); return error; } if (status & (STATUS_WRITE & ~(STATUS_READY_FOR_DATA | STATUS_STATE))) { TRACE_ERROR("CMD24(0x%x).stat: %x\n\r", SD_ADDRESS(pSd,address), status & (STATUS_WRITE & ~(STATUS_READY_FOR_DATA | STATUS_STATE))); return SD_ERROR_DRIVER; } } return error; #endif } #endif //------------------------------------------------------------------------------ /// Move SD card to transfer state. The buffer size must be at /// least 512 byte long. This function checks the SD card status register and /// address the card if required before sending the transfer command. /// Returns 0 if successful; otherwise returns an code describing the error. /// \param pSd Pointer to a SD card driver instance. /// \param address Address of the block to transfer. /// \param nbBlocks Number of blocks to be transfer, 0 for infinite transfer. /// \param pData Data buffer whose size is at least the block size. /// \param isRead 1 for read data and 0 for write data. //------------------------------------------------------------------------------ static unsigned char MoveToTransferState(SdCard *pSd, unsigned int address, unsigned short nbBlocks, unsigned char *pData, unsigned char isRead) { unsigned int status; unsigned char error; if( (pSd->state == SD_STATE_READ) || (pSd->state == SD_STATE_WRITE)) { #if 1//!defined(MCI2_INTERFACE) if (pSd->state == SD_STATE_WRITE) { DBGU_PutChar(0); DBGU_PutChar(0); DBGU_PutChar(0); DBGU_PutChar(0); } #endif // RW MULTI with length error = Cmd12(pSd, (pSd->state == SD_STATE_READ), &status); if (error) { TRACE_ERROR("MTTranState.Cmd12: st%x, er%d\n\r", pSd->state, error); return error; } #if !defined(MCI2_INTERFACE) // RW MULTI Infinite if (pSd->state == SD_STATE_WRITE) { while(MCI_CheckBusy((Mci *)pSd->pSdDriver) != 0); } #endif } if(isRead) { // Wait for card to be ready for data transfers do { error = Cmd13(pSd, &status); if (error) { TRACE_ERROR("MTTranState.RD.Cmd13: %d\n\r", error); return error; } if( ((status & STATUS_STATE) == STATUS_IDLE) ||((status & STATUS_STATE) == STATUS_READY) ||((status & STATUS_STATE) == STATUS_IDENT)) { TRACE_ERROR("Pb Card Identification mode\n\r"); return SD_ERROR_NOT_INITIALIZED; } // If the card is in sending data state or in receivce data state if ( ((status & STATUS_STATE) == STATUS_RCV) ||((status & STATUS_STATE) == STATUS_DATA) ){ TRACE_DEBUG("state = 0x%X\n\r", (status & STATUS_STATE) >> 9); } } while ( ((status & STATUS_READY_FOR_DATA) == 0) || ((status & STATUS_STATE) != STATUS_TRAN) ); ASSERT((status & STATUS_STATE) == STATUS_TRAN, "SD Card can't be configured in transfer state 0x%X\n\r", (status & STATUS_STATE)>>9); // Read data // Move to Sending data state error = Cmd18(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address), &status); if (error) { TRACE_ERROR("MTTranState.Cmd18: %d\n\r", error); return error; } if (status & ~(STATUS_READY_FOR_DATA | STATUS_STATE)) { TRACE_ERROR("CMD18.stat: %x\n\r", status & ~(STATUS_READY_FOR_DATA | STATUS_STATE)); return SD_ERROR_DRIVER; } } else { // Wait for card to be ready for data transfers do { error = Cmd13(pSd, &status); if (error) { TRACE_ERROR("MoveToTransferState.WR.Cmd13: %d\n\r", error); return error; } } while ((status & STATUS_READY_FOR_DATA) == 0); // Move to Sending data state error = Cmd25(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address), &status); if (error) { TRACE_DEBUG("MoveToTransferState.Cmd25: %d\n\r", error); return error; } if (status & (STATUS_WRITE & ~(STATUS_READY_FOR_DATA | STATUS_STATE))) { TRACE_ERROR("CMD25(0x%x, %d).stat: %x\n\r", SD_ADDRESS(pSd,address), nbBlocks, status & (STATUS_WRITE & ~(STATUS_READY_FOR_DATA | STATUS_STATE))); return SD_ERROR_DRIVER; } } if (!error) pSd->preBlock = address + (nbBlocks-1); return error; } //------------------------------------------------------------------------------ /// Switch the bus width of card //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Switch the HS mode of card /// \param pSd Pointer to SdCard instance. /// \param hsEnable 1 to enable, 0 to disable. //------------------------------------------------------------------------------ static unsigned char SdMmcSwitchHsMode(SdCard *pSd, unsigned char hsEnable) { unsigned int status; unsigned char error = SD_ERROR_DRIVER; if (pSd->mode == hsEnable) return 0; if (pSd->cardType >= CARD_MMC) { MmcCmd6Arg cmd6Arg; cmd6Arg.access = 0x3; cmd6Arg.index = SD_EXTCSD_HS_TIMING_INDEX; cmd6Arg.value = hsEnable ? SD_EXTCSD_HS_TIMING_ENABLE : SD_EXTCSD_HS_TIMING_DISABLE; cmd6Arg.cmdSet = 0; error = Cmd6(pSd, &cmd6Arg, 0, &status); if (error) { TRACE_ERROR("MMC SwitchHs.Cmd6: %d\n\r", error); } else if (status & STATUS_SWITCH_ERROR) { TRACE_WARNING("MMC HS SW Fail\n\r"); error = SD_ERROR_DRIVER; } else { TRACE_WARNING_WP("-I- MMC HS %d\n\r", hsEnable); pSd->mode = hsEnable; } } else if (pSd->cardType >= CARD_SD) { SdCmd6Arg cmd6Arg; unsigned int switchStatus[512/32]; cmd6Arg.mode = 1; cmd6Arg.reserved = 0; cmd6Arg.reserveFG6 = 0xF; cmd6Arg.reserveFG5 = 0xF; cmd6Arg.reserveFG4 = 0xF; cmd6Arg.reserveFG3 = 0xF; cmd6Arg.command = 0; cmd6Arg.accessMode = 1; error = Cmd6(pSd, &cmd6Arg, switchStatus, &status); #if 0 unsigned int i; printf("SD Switch status:"); for(i = 0; i < 512 / 8; i ++) { if ((i % 8) == 0) printf("\n\r[%3d]", i); printf(" %02x", ((char*)switchStatus)[i]); } printf("\n\r"); printf(" _FG1_INFO %x\n\r", SD_SW_STAT_FUN_GRP1_INFO(switchStatus)); printf(" _FG1_RC %x\n\r", SD_SW_STAT_FUN_GRP1_RC(switchStatus)); printf(" _FG1_BUSY %x\n\r", SD_SW_STAT_FUN_GRP1_BUSY(switchStatus)); printf(" _FG1_DS_V %x\n\r", SD_SW_STAT_DATA_STRUCT_VER(switchStatus)); #endif if (error) { TRACE_ERROR("SD SwitchHs.Cmd6: %d\n\r", error); } else if (status & STATUS_SWITCH_ERROR) { TRACE_WARNING("SD HS SW Fail\n\r"); error = SD_ERROR_DRIVER; } else if (SD_SW_STAT_FUN_GRP1_RC(switchStatus) == SD_SW_STAT_FUN_GRP_RC_ERROR) { TRACE_ERROR_WP("-I- SD HS Not Supported\n\r"); error = SD_ERROR_DRIVER; } else if (SD_SW_STAT_FUN_GRP1_BUSY(switchStatus)) { TRACE_WARNING("SD HS Busy\n\r"); error = SD_ERROR_DRIVER; } else { TRACE_WARNING_WP("-I- SD HS %d\n\r", hsEnable); pSd->mode = hsEnable; } } return error; } #if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ) //------------------------------------------------------------------------------ /// Process a list of SWITCH command /// \param pSd Pointer to SdCard instance. /// \param pArgList Argument list. /// \param listSize Number of arguments listed. /// \return 0, or error code and argument index. //------------------------------------------------------------------------------ static unsigned short MmcSwitchSettings(SdCard *pSd, const MmcCmd6Arg * pArgList, unsigned int listSize, unsigned int * pErrSta) { unsigned int i, status; unsigned char error; SANITY_CHECK(pSd); SANITY_CHECK(pArgList); for (i = 0; i < listSize; i ++) { error = Cmd6(pSd, &pArgList[i], 0, &status); if (pErrSta) *pErrSta = status; if (error) { return (error | (i << 8)); } if (status & ~(STATUS_STATE | STATUS_READY_FOR_DATA)) { TRACE_WARNING("Error in SWITCH.%d, 0x%x\n\r", pArgList[i].index, status); } else { TRACE_INFO("SWITCH.%d: 0x%x\n\r", pArgList[i].index, status); } } return 0; } #endif //------------------------------------------------------------------------------ /// Switch card state between STBY and TRAN /// \param pSd Pointer to a SD card driver instance. /// \param address Card address to TRAN, 0 to STBY /// \param check Whether to check the state //------------------------------------------------------------------------------ static unsigned char MmcSelectCard(SdCard *pSd, unsigned short address, unsigned char check) { unsigned char error; unsigned int status; unsigned int targetState = address ? STATUS_TRAN : STATUS_STBY; unsigned int srcState = address ? STATUS_STBY : STATUS_TRAN; if (pSd->cardType == CARD_SDIO) check = 0; // At this stage the Initialization and identification process is achieved // The SD card is supposed to be in Stand-by State while(check) { error = Cmd13(pSd, &status); if (error) { TRACE_ERROR("MmcSelectCard.Cmd13 (%d)\n\r", error); return error; } if ((status & STATUS_READY_FOR_DATA)) { unsigned int currState = status & STATUS_STATE; if (currState == targetState) return 0; if (currState != srcState) { TRACE_ERROR("MmcSelectCard, wrong state %x\n\r", currState); return SD_ERROR_DRIVER; } break; } } // witch to TRAN mode to Select the current SD/MMC // so that SD ACMD6 can process or EXT_CSD can read. error = Cmd7(pSd, address); if (error == SD_ERROR_NOT_INITIALIZED && address == 0) {} else if (error) { TRACE_ERROR("MmcSelectCard.Cmd7 (%d)\n\r", error); } return error; } //------------------------------------------------------------------------------ /// Get EXT_CSD information /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ static unsigned char MmcGetExtInformation(SdCard *pSd) { unsigned char error; unsigned int i; // CSD 1.2 or Higher version if(SD_CSD_STRUCTURE(pSd) >= 2) { /* Clear EXT_CSD data */ for (i = 0;i < 512/4; i ++) pSd->extData[i] = 0; error = Cmd8(pSd, 0, pSd->extData); if (error) { TRACE_ERROR("MmcGetExt.Cmd8: %d\n\r", error); } } return 0; } //------------------------------------------------------------------------------ /// Get SCR and SD Status information /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ static unsigned char SdGetExtInformation(SdCard *pSd) { unsigned char error; // Reset data (64 + 512 bits, 8 + 64 bytes) // memset(pSd->extData, 0x00, 512); // SD Status if (pSd->optCmdBitMap & SD_ACMD13_SUPPORT) { error = Acmd13(pSd, &pSd->extData[SD_EXT_OFFSET_SD_STAT]); if (error) { TRACE_ERROR("SdGetExt.Acmd13: %d\n\r", error); pSd->optCmdBitMap &= ~SD_ACMD13_SUPPORT; } } // SD SCR error = Acmd51(pSd, &pSd->extData[SD_EXT_OFFSET_SD_SCR]); if (error) { TRACE_ERROR("SdGetExt.Acmd51: %d\n\r", error); } return 0; } //------------------------------------------------------------------------------ /// Update SD/MMC information. /// Update CSD for card speed switch. /// Update ExtDATA for any card function switch. /// \param pSd Pointer to a SD card driver instance. /// \return error code when update CSD error. //------------------------------------------------------------------------------ static unsigned char SdMmcUpdateInformation(SdCard *pSd, unsigned char csd, unsigned char extData) { unsigned char error; // Update CSD for new TRAN_SPEED value if (csd) { MmcSelectCard(pSd, 0, 1); Delay(800); error = Cmd9(pSd); if (error ) { TRACE_ERROR("SdMmcUpdateInfo.Cmd9 (%d)\n\r", error); return error; } error = MmcSelectCard(pSd, pSd->cardAddress, 1); } if (pSd->cardType >= CARD_MMC) MmcGetExtInformation(pSd); else if (pSd->cardType >= CARD_SD) SdGetExtInformation(pSd); GetTransSpeedValue(pSd); return 0; } #if MCI_SDIO_ENABLE //------------------------------------------------------------------------------ /// Find ManfID, Func0 tuple. //------------------------------------------------------------------------------ static unsigned char SdioFindTuples(SdCard * pSd, unsigned int address, unsigned int size, unsigned int *pAddrManfID, unsigned int *pAddrFunc0) { unsigned char error, tmp[3]; unsigned int addr = address; unsigned char nbFound = 0; for (;;) { error = SDIO_ReadDirect(pSd, 0, addr, tmp, 3); if (error) return error; // ManfID if (tmp[0] == CISTPL_MANFID) { if (pAddrManfID) *pAddrManfID = addr; nbFound ++; } // Func0 if (tmp[0] == CISTPL_FUNCE && tmp[2] == 0x00) { if (pAddrFunc0) *pAddrFunc0 = addr; nbFound ++; } // END if (tmp[0] == CISTPL_END) break; // All found if (nbFound >= 2) break; // Not tuple? if (tmp[1] == 0) break; // Next address addr += (tmp[1] + 2); if (addr > (address + size)) break; } return 0; } #endif //------------------------------------------------------------------------------ // Global functions //------------------------------------------------------------------------------ #if MCI_SDIO_ENABLE //------------------------------------------------------------------------------ /// Read at least one byte from SDIO card, using RW_DIRECT command. /// \param pSd Pointer to SdCard instance. /// \param funNb Function number. /// \param address First byte address of data in SDIO card. /// \param pBytes Pointer to data buffer. /// \param size Buffer size. //------------------------------------------------------------------------------ unsigned char SDIO_ReadDirect(SdCard *pSd, unsigned char funNb, unsigned int address, unsigned char *pBytes, unsigned int size) { unsigned char error; unsigned int status; if (pSd->cardType < CARD_SDIO) { return SD_ERROR_NOT_SUPPORT; } if (size == 0) return SD_ERROR_DRIVER; while(size --) { status = 0; error = Cmd52(pSd, funNb, 0, 0, address ++, &status); if (pBytes) *pBytes ++ = (unsigned char)status; if (error) { TRACE_ERROR("SDIO_ReadDirect.Cmd52: %d, %x\n\r", error, status); return SD_ERROR_DRIVER; } } return 0; } //------------------------------------------------------------------------------ /// Write one byte to SDIO card, using RW_DIRECT command. /// \param pSd Pointer to SdCard instance. /// \param funNb Function number. /// \param address First byte address of data in SDIO card. /// \param pBytes Pointer to data buffer. /// \param size Buffer size. //------------------------------------------------------------------------------ unsigned char SDIO_WriteDirect(SdCard *pSd, unsigned char funNb, unsigned int address, unsigned char byte) { if (pSd->cardType < CARD_SDIO) { return SD_ERROR_NOT_SUPPORT; } unsigned char error; unsigned int status; status = byte; error = Cmd52(pSd, funNb, 1, 0, address, &status); if (error) { TRACE_ERROR("SDIO_ReadDirect.Cmd52: %d, %x\n\r", error, status); return SD_ERROR_DRIVER; } return 0; } //------------------------------------------------------------------------------ /// Read byte by byte from SDIO card, using RW_EXT command. /// \param pSd Pointer to SdCard instance. /// \param funNb Function number. /// \param address First byte address of data in SDIO card. /// \param isFixedAddr Address not increased. /// \param pBytes Pointer to data buffer. /// \param size Buffer size. //------------------------------------------------------------------------------ unsigned char SDIO_ReadBytes(SdCard *pSd, unsigned char funNb, unsigned int address, unsigned char isFixedAddr, unsigned char *pBytes, unsigned int size) { unsigned char error; unsigned int status; if (pSd->cardType < CARD_SDIO) { return SD_ERROR_NOT_SUPPORT; } if (size == 0) return SD_ERROR_DRIVER; error = Cmd53(pSd, funNb, 0, 0, !isFixedAddr, address, pBytes, size, &status); if (error || (status & STATUS_SDIO_CMD52)) { TRACE_ERROR("SDIO_ReadBytes.Cmd53: %d, %x\n\r", error, status); return SD_ERROR_DRIVER; } return 0; } //------------------------------------------------------------------------------ /// Write byte by byte to SDIO card, using RW_EXT command. /// \param pSd Pointer to SdCard instance. /// \param funNb Function number. /// \param address First byte address of data in SDIO card. /// \param isFixedAddr Address not increased. /// \param pBytes Pointer to data buffer. /// \param size Buffer size. //------------------------------------------------------------------------------ unsigned char SDIO_WriteBytes(SdCard *pSd, unsigned char funNb, unsigned int address, unsigned char isFixedAddr, unsigned char *pBytes, unsigned int size) { unsigned char error; unsigned int status; if (pSd->cardType < CARD_SDIO) { return SD_ERROR_NOT_SUPPORT; } if (size == 0) return SD_ERROR_DRIVER; error = Cmd53(pSd, funNb, 1, 0, !isFixedAddr, address, pBytes, size, &status); if (error || (status & STATUS_SDIO_CMD52)) { TRACE_ERROR("SDIO_ReadBytes.Cmd53: %d, %x\n\r", error, status); return SD_ERROR_DRIVER; } return 0; } #endif //------------------------------------------------------------------------------ /// Read Block of data in a buffer pointed by pData. The buffer size must be at /// least 512 byte long. This function checks the SD card status register and /// address the card if required before sending the read command. /// Returns 0 if successful; otherwise returns an code describing the error. /// \param pSd Pointer to a SD card driver instance. /// \param address Address of the block to read. /// \param pData Data buffer whose size is at least the block size, it can /// be 1,2 or 4-bytes aligned when used with DMA. /// \param length Number of blocks to be read. /// \param pCallback Pointer to callback function that invoked when read done. /// 0 to start a blocked read. /// \param pArgs Pointer to callback function arguments. //------------------------------------------------------------------------------ unsigned char SD_Read(SdCard *pSd, unsigned int address, void *pData, unsigned short length, SdCallback pCallback, void *pArgs) { unsigned char error; // If callback is defined, performe none blocked reading if (pCallback) { if (MCI_IsTxComplete((Mci *)pSd) == 0) { return SD_ERROR_BUSY; } } if ( pSd->state != SD_STATE_READ || pSd->preBlock + 1 != address ) { // Start infinite block reading error = MoveToTransferState(pSd, address, 0, 0, 1); } else error = 0; if (!error) { pSd->state = SD_STATE_READ; pSd->preBlock = address + (length - 1); error = ContinuousRead(pSd, length, pData, pCallback, pArgs); } TRACE_DEBUG("SDrd(%u,%u):%u\n\r", address, length, error); return 0; } //------------------------------------------------------------------------------ /// Write Block of data in a buffer pointed by pData. The buffer size must be at /// least 512 byte long. This function checks the SD card status register and /// address the card if required before sending the read command. /// Returns 0 if successful; otherwise returns an code describing the error. /// \param pSd Pointer to a SD card driver instance. /// \param address Address of the block to read. /// \param pData Data buffer whose size is at least the block size, it can /// be 1,2 or 4-bytes aligned when used with DMA. /// \param length Number of blocks to be read. /// \param pCallback Pointer to callback function that invoked when read done. /// 0 to start a blocked read. /// \param pArgs Pointer to callback function arguments. //------------------------------------------------------------------------------ unsigned char SD_Write(SdCard *pSd, unsigned int address, void *pData, unsigned short length, SdCallback pCallback, void *pArgs) { unsigned char error; // If callback is defined, performe none blocked writing if (pCallback) { if (MCI_IsTxComplete((Mci *)pSd) == 0) { return SD_ERROR_BUSY; } } if ( pSd->state != SD_STATE_WRITE || pSd->preBlock + 1 != address ) { // Start infinite block writing error = MoveToTransferState(pSd, address, 0, 0, 0); } else error = 0; if (!error) { pSd->state = SD_STATE_WRITE; error = ContinuousWrite(pSd, length, pData, pCallback, pArgs); pSd->preBlock = address + (length - 1); } TRACE_DEBUG("SDwr(%u,%u):%u\n\r", address, length, error); return 0; } //------------------------------------------------------------------------------ /// Read Block of data in a buffer pointed by pData. The buffer size must be at /// least 512 byte long. This function checks the SD card status register and /// address the card if required before sending the read command. /// Returns 0 if successful; otherwise returns an code describing the error. /// \param pSd Pointer to a SD card driver instance. /// \param address Address of the block to read. /// \param nbBlocks Number of blocks to be read. /// \param pData Data buffer whose size is at least the block size, it can /// be 1,2 or 4-bytes aligned when used with DMA. //------------------------------------------------------------------------------ unsigned char SD_ReadBlock(SdCard *pSd, unsigned int address, unsigned short nbBlocks, unsigned char *pData) { unsigned char error = 0; SANITY_CHECK(pSd); SANITY_CHECK(pData); SANITY_CHECK(nbBlocks); TRACE_DEBUG("ReadBlk(%d,%d)\n\r", address, nbBlocks); #if defined(SINGLE_READ) while(nbBlocks --) { error = PerformSingleTransfer(pSd, address, pData, 1); if (error) break; // SDHC if (pSd->totalSize == 0xFFFFFFFF) { address += 1; pData = &pData[512]; } else { address += 1; pData = &pData[512]; } } return error; #endif #if !defined(MCI2_INTERFACE) #if !defined(AT91C_MCI_RDPROOF) error = MoveToTransferState(pSd, address, nbBlocks, pData, 1); pSd->state = SD_STATE_READ; #else if((pSd->state == SD_STATE_READ) && ((pSd->preBlock + 1) == address)) { #if defined(at91rm9200) error = Cmd12(pSd, 0); if (error) { return error; } #else TRACE_DEBUG("SD_ReadBlock:ContinuousRead\n\r"); error = ContinuousRead(pSd, nbBlocks, pData, 0, 0); pSd->preBlock = address + (nbBlocks-1); #endif } else { error = MoveToTransferState(pSd, address, nbBlocks, pData, 1); pSd->state = SD_STATE_READ; } #endif #else if ( pSd->state != SD_STATE_READ || pSd->preBlock + 1 != address ) { // Start infinite block reading error = MoveToTransferState(pSd, address, 0, 0, 1); } if (!error) { pSd->state = SD_STATE_READ; error = ContinuousRead(pSd, nbBlocks, pData, 0, 0); if (!error) pSd->preBlock = address + (nbBlocks - 1); } #endif return error; } //------------------------------------------------------------------------------ /// Write Block of data pointed by pData. The buffer size must be at /// least 512 byte long. This function checks the SD card status register and /// address the card if required before sending the read command. /// Returns 0 if successful; otherwise returns an SD_ERROR code. /// \param pSd Pointer to a SD card driver instance. /// \param address Address of block to write. /// \param nbBlocks Number of blocks to be read /// \param pData Data buffer whose size is at least the block size, it can /// be 1,2 or 4-bytes aligned when used with DMA. //------------------------------------------------------------------------------ unsigned char SD_WriteBlock(SdCard *pSd, unsigned int address, unsigned short nbBlocks, const unsigned char *pData) { unsigned char error = 0; SANITY_CHECK(pSd); SANITY_CHECK(pData); SANITY_CHECK(nbBlocks); TRACE_DEBUG("WriteBlk(%d,%d)\n\r", address, nbBlocks); #if defined(SINGLE_WRITE) unsigned char *pB = (unsigned char*)pData; while(nbBlocks --) { error = PerformSingleTransfer(pSd, address, pB, 0); if (error) break; // SDHC if (pSd->totalSize == 0xFFFFFFFF) { address += 1; pB = &pB[512]; } else { address += 1; pB = &pB[512]; } } return error; #endif #if !defined(MCI2_INTERFACE) #if !defined(AT91C_MCI_WRPROOF) error = MoveToTransferState(pSd, address, nbBlocks, (unsigned char *)pData, 0); pSd->state = SD_STATE_WRITE; #else if((pSd->state == SD_STATE_WRITE) && ((pSd->preBlock + 1) == address)) { TRACE_DEBUG("SD_WriteBlock:ContinuousWrite\n\r"); error = ContinuousWrite(pSd, nbBlocks, pData, 0, 0); pSd->preBlock = address + (nbBlocks-1); } else { //TRACE_FATAL("SD_WriteBlock:MoveToTransferState\n\r"); error = MoveToTransferState(pSd, address, nbBlocks, (unsigned char *)pData, 0); pSd->state = SD_STATE_WRITE; } #endif #else if ( pSd->state != SD_STATE_WRITE || pSd->preBlock + 1 != address ) { // Start infinite block writing error = MoveToTransferState(pSd, address, 0, 0, 0); } if (!error) { pSd->state = SD_STATE_WRITE; error = ContinuousWrite(pSd, nbBlocks, pData, 0, 0); if (!error) pSd->preBlock = address + (nbBlocks - 1); } #endif return error; } //------------------------------------------------------------------------------ /// Run the SDcard SD/MMC/SDIO Mode initialization sequence. /// This function resets both IO and memory controller, runs the initialisation /// procedure and the identification process. Then it leaves the card in ready /// state. The following command must check the card type and continue to put /// the card into tran(for memory card) or cmd(for io card) state for data /// exchange. /// Returns 0 if successful; otherwise returns an SD_ERROR code. /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ static unsigned char SdMmcIdentify(SdCard *pSd) { unsigned char mem = 0, io = 0, f8 = 0, mp = 1, ccs = 0; unsigned char error = 0; #if MCI_SDIO_ENABLE unsigned int status; #endif // Reset HC to default HS and BusMode MCI_EnableHsMode(pSd->pSdDriver, 0); MCI_SetBusWidth(pSd->pSdDriver, MCI_SDCBUS_1BIT); #if MCI_SDIO_ENABLE // Reset SDIO // CMD52, write 1 to RES bit in the CCCR (bit 3 of register 6) status = (0x1 << 3); error = Cmd52(pSd, 0, 1, 0, 6, &status); if (!error && ((status & STATUS_SDIO_CMD52) == 0)) {} else if (error == MCI_STATUS_NORESPONSE) {} else { TRACE_DEBUG("SdMmcIdentify.Cmd52 fail: %d, %x\n\r", error, status); } #endif // Reset MEM error = SwReset(pSd, 1); if (error) { TRACE_DEBUG("SdMmcIdentify.SwReset: %d\n\r", error) } // CMD8 is newly added in the Physical Layer Specification Version 2.00 to // support multiple voltage ranges and used to check whether the card // supports supplied voltage. The version 2.00 host shall issue CMD8 and // verify voltage before card initialization. // The host that does not support CMD8 shall supply high voltage range... error = Cmd8(pSd, 1, (void*)1); if (error == 0) { f8 = 1; } else if (error != SD_ERROR_NORESPONSE) { TRACE_ERROR("SdMmcIdentify.Cmd8: %d\n\r", error); return SD_ERROR_DRIVER; } else { // Delay after "no response" Delay(800); } #if MCI_SDIO_ENABLE // CMD5 is added for SDIO OCR check status = 0; error = Cmd5(pSd, &status); if (error) { TRACE_WARNING("SdMmcIdentify.Cmd5: %d\n\r", error); } // SDIO or SD COMBO: FN > 0 else if ((status & AT91C_SDIO_NF) > 0) { // Set New Voltage unsigned int cmd5Retries = 10000; do { status &= AT91C_MMC_HOST_VOLTAGE_RANGE; error = Cmd5(pSd, &status); if (status & AT91C_CARD_POWER_UP_BUSY) break; } while(!error && cmd5Retries --); if (error) { TRACE_ERROR("SdMmcIdentify.Cmd5 V: %d\n\r", error); return SD_ERROR_DRIVER; } TRACE_INFO("SDIO\n\r"); io = 1; // SDIO only? if ((status & AT91C_SDIO_MP) == 0) mp = 0; } #endif // SD or MMC or COMBO: mp is 1 if (mp) { // Try SD memory initialize error = Acmd41(pSd, f8, &ccs); if (error) { unsigned int cmd1Retries = 10000; TRACE_DEBUG("SdMmcIdentify.Acmd41: %d, try MMC\n\r", error); // Try MMC initialize error = SwReset(pSd, 10); if (error) { TRACE_ERROR("SdMmcIdentify.Mmc.SwReset: %d\n\r", error); return SD_ERROR_DRIVER; } // - Set Voltage do { error = Cmd1(pSd, 1, &ccs); } while ((error) && (cmd1Retries-- > 0)); if (error) { TRACE_ERROR("SdMmcIdentify.Cmd1: %d\n\r", error); return SD_ERROR_DRIVER; } else if (ccs) { pSd->cardType = CARD_MMCHD; } else { pSd->cardType = CARD_MMC; } // MMC Identified OK return 0; } else if (ccs) { TRACE_INFO("SDHC MEM\n\r"); } else { TRACE_INFO("SD MEM\n\r"); } mem = 1; } // SD(IO)+MEM ? if (!mem) { // SDIO only if (io) { pSd->cardType = CARD_SDIO; return 0; } } // SD COMBO, continue with memory initialize else if (io) { if (ccs) pSd->cardType = CARD_SDHCCOMBO; else pSd->cardType = CARD_SDCOMBO; } // SD(HC), continue with memory initialize else { if (ccs) pSd->cardType = CARD_SDHC; else pSd->cardType = CARD_SD; } return 0; } //------------------------------------------------------------------------------ /// Run the SDcard SD Mode enumeration sequence. This function runs after the /// initialisation procedure and the identification process. It sets the /// SD card in transfer state to set the block length and the bus width. /// Returns 0 if successful; otherwise returns an SD_ERROR code. /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ static unsigned char SdMmcEnum(SdCard *pSd) { unsigned char mem = 0, io = 0; unsigned int status; unsigned short error; unsigned char isHsSupport = 0; unsigned char updateInformation = 0; if (pSd->cardType & CARD_TYPE_bmSDMMC) mem = 1; if (pSd->cardType & CARD_TYPE_bmSDIO) io = 1; // For MEM // The host then issues the command ALL_SEND_CID (CMD2) to the card to get // its unique card identification (CID) number. // Card that is unidentified (i.e. which is in Ready State) sends its CID // number as the response (on the CMD line). if (mem) { error = Cmd2(pSd); if (error) { TRACE_ERROR("SdMmcEnum.Cmd2: %d\n\r", error); return SD_ERROR_DRIVER; } } // For SDIO & MEM // Thereafter, the host issues CMD3 (SEND_RELATIVE_ADDR) asks the // card to publish a new relative card address (RCA), which is shorter than // CID and which is used to address the card in the future data transfer // mode. Once the RCA is received the card state changes to the Stand-by // State. At this point, if the host wants to assign another RCA number, it // can ask the card to publish a new number by sending another CMD3 command // to the card. The last published RCA is the actual RCA number of the card. error = Cmd3(pSd); if (error) { TRACE_ERROR("SdMmcInit.Cmd3 %d\n\r", error); return SD_ERROR_DRIVER; } // For MEM // SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register), // e.g. block length, card storage capacity, etc... if (mem) { error = Cmd9(pSd); if (error) { TRACE_ERROR("SdMmcInit.Cmd9 %d\n\r", error); return SD_ERROR_DRIVER; } } // For SDIO & MEM // Now select the card, to TRAN state error = MmcSelectCard(pSd, pSd->cardAddress, 0); if (error) { TRACE_ERROR("SdMmcInit.Sel %d\n\r", error); return SD_ERROR_DRIVER; } // SDIO only card, enumeration done if (!mem && io) { // Default tranSpeed: 25MHz pSd->transSpeed = 25000000; return 0; } // For MEM cards or combo // If the card support EXT_CSD, read it! TRACE_INFO("Card Type %d, CSD_STRUCTURE %d\n\r", pSd->cardType, SD_CSD_STRUCTURE(pSd)); // Get extended information of the card SdMmcUpdateInformation(pSd, 0, 0); // Advanced settings for HD & HS card if (pSd->cardType >= CARD_MMC){ MmcCmd6Arg cmd6Arg; // MMC4 or later if (SD_CSD_SPEC_VERS(pSd) >= 4) { unsigned char busWidth, widthMode; // Calculate MMC busWidth (limited by slot information) switch (pSd->pSdDriver->mciMode & AT91C_MCI_SCDBUS) { #if defined(AT91C_MCI_SCDBUS_8BITS) case AT91C_MCI_SCDBUS_8BITS: busWidth = 8; widthMode = MCI_SDCBUS_8BIT; break; #endif #if defined(AT91C_MCI_SCDBUS_4BITS) case AT91C_MCI_SCDBUS_4BITS: busWidth = 4; widthMode = MCI_SDCBUS_4BIT; break; #endif default: busWidth = 1; widthMode = MCI_SDCBUS_1BIT; } // Switch to max bus width (4 now) cmd6Arg.access = 0x1; cmd6Arg.index = SD_EXTCSD_BUS_WIDTH_INDEX; cmd6Arg.value = SD_EXTCSD_BUS_WIDTH_4BIT; cmd6Arg.cmdSet = 0; error = Cmd6(pSd, &cmd6Arg, 0, &status); if (!error) { TRACE_WARNING_WP("-I- MMC %d-BIT BUS\n\r", busWidth); if (status & (STATUS_MMC_SWITCH & ~(STATUS_STATE | STATUS_READY_FOR_DATA))) { printf("-E- Status %x\n\r", status); } else { MCI_SetBusWidth(pSd->pSdDriver, widthMode); updateInformation = 1; } } else { TRACE_WARNING("MMC %d-BIT not supported\n\r", busWidth) } } // CARD_TYPE 3 if (SD_CSD_STRUCTURE(pSd) >= 2 && (SD_EXTCSD_CARD_TYPE(pSd) & 0x2)) { #if !defined(OP_BOOTSTRAP_MCI_on) // Switch to HS mode if (gSdmmcAutoHsEnable) { cmd6Arg.access = 0x3; cmd6Arg.index = SD_EXTCSD_HS_TIMING_INDEX; cmd6Arg.value = SD_EXTCSD_HS_TIMING_ENABLE; cmd6Arg.cmdSet = 0; error = Cmd6(pSd, &cmd6Arg, 0, &status); if (error || (status & (STATUS_MMC_SWITCH & ~(STATUS_STATE | STATUS_READY_FOR_DATA)))) { TRACE_WARNING("MMC HS Fail, st %x\n\r", status); } else { MCI_EnableHsMode(pSd->pSdDriver, 1); TRACE_WARNING_WP("-I- MMC HS Enabled\n\r"); isHsSupport = 1; updateInformation = 1; } } #endif // end of OP_BOOTSTRAP_MCI_on } } else if (pSd->cardType >= CARD_SD) { #if 1 // Switch to 4-bits bus width // (All SD Card shall support 1-bit, 4 bitswidth) error = Acmd6(pSd, 4); TRACE_WARNING_WP("-I- SD 4-BITS BUS\n\r"); if (error) { TRACE_ERROR("SdMmcInit.12 (%d)\n\r", error); return error; } MCI_SetBusWidth(pSd->pSdDriver, MCI_SDCBUS_4BIT); #if !defined(OP_BOOTSTRAP_MCI_on) // SD Spec V1.10 or higher, switch to high-speed mode if (gSdmmcAutoHsEnable) { if (SD_SCR_SD_SPEC(pSd) >= SD_SCR_SD_SPEC_1_10) { SdCmd6Arg cmd6Arg; unsigned int switchStatus[512/32]; cmd6Arg.mode = 1; cmd6Arg.reserved = 0; cmd6Arg.reserveFG6 = 0xF; cmd6Arg.reserveFG5 = 0xF; cmd6Arg.reserveFG4 = 0xF; cmd6Arg.reserveFG3 = 0xF; cmd6Arg.command = 0; cmd6Arg.accessMode = 1; error = Cmd6(pSd, &cmd6Arg, switchStatus, &status); #if 0 unsigned int i; printf("SD Switch status:"); for(i = 0; i < 512 / 8; i ++) { if ((i % 8) == 0) printf("\n\r[%3d]", i); printf(" %02x", ((char*)switchStatus)[i]); } printf("\n\r"); printf(" _FG1_INFO %x\n\r", SD_SW_STAT_FUN_GRP1_INFO(switchStatus)); printf(" _FG1_RC %x\n\r", SD_SW_STAT_FUN_GRP1_RC(switchStatus)); printf(" _FG1_BUSY %x\n\r", SD_SW_STAT_FUN_GRP1_BUSY(switchStatus)); printf(" _FG1_DS_V %x\n\r", SD_SW_STAT_DATA_STRUCT_VER(switchStatus)); #endif if (error || (status & STATUS_SWITCH_ERROR)) { TRACE_WARNING("SD HS Fail\n\r"); } else if (SD_SW_STAT_FUN_GRP1_RC(switchStatus) == SD_SW_STAT_FUN_GRP_RC_ERROR) { TRACE_ERROR_WP("-I- SD HS Not Supported\n\r"); } else if (SD_SW_STAT_FUN_GRP1_BUSY(switchStatus)) { TRACE_WARNING("SD HS Busy\n\r") } else { MCI_EnableHsMode(pSd->pSdDriver, 1); TRACE_WARNING_WP("-I- SD HS Enable\n\r"); isHsSupport = 1; } } } #endif // Update updateInformation = 1; #endif } if (updateInformation) { SdMmcUpdateInformation(pSd, isHsSupport, 1); } return 0; } //------------------------------------------------------------------------------ /// Run the SDcard initialization sequence. This function runs the /// initialisation procedure and the identification process, then it sets the /// SD card in transfer state to set the block length and the bus width. /// Returns 0 if successful; otherwise returns an SD_ERROR code. /// \param pSd Pointer to a SD card driver instance. /// \param pSdDriver Pointer to SD driver already initialized. //------------------------------------------------------------------------------ unsigned char SD_Init(SdCard *pSd, SdDriver *pSdDriver) { unsigned char error; //TRACE_DEBUG("SD_Init()\n\r"); // Initialize SdCard structure pSd->pSdDriver = pSdDriver; pSd->cardAddress = 0; pSd->preBlock = 0xffffffff; pSd->state = SD_STATE_INIT; pSd->cardType = CARD_UNKNOWN; pSd->optCmdBitMap = 0xFFFFFFFF; pSd->mode = 0; ResetCommand(&pSd->command); // Initialization delay: The maximum of 1 msec, 74 clock cycles and supply // ramp up time. Supply ramp up time provides the time that the power is // built up to the operating level (the bus master supply voltage) and the // time to wait until the SD card can accept the first command. // Power On Init Special Command //TRACE_DEBUG("Pon()\n\r"); error = Pon(pSd); if (error) { TRACE_ERROR("SD_Init.1 (%d)\n\r", error); return error; } // After power-on or CMD0, all cards?CMD lines are in input mode, waiting // for start bit of the next command. // The cards are initialized with a default relative card address // (RCA=0x0000) and with a default driver stage register setting // (lowest speed, highest driving current capability). error = SdMmcIdentify(pSd); if (error) { TRACE_ERROR("SD_Init.Identify\n\r"); return error; } error = SdMmcEnum(pSd); if (error) { TRACE_ERROR("SD_Init.Enum\n\r"); return error; } // In the case of a Standard Capacity SD Memory Card, this command sets the // block length (in bytes) for all following block commands // (read, write, lock). // Default block length is fixed to 512 Bytes. // Set length is valid for memory access commands only if partial block read // operation are allowed in CSD. // In the case of a High Capacity SD Memory Card, block length set by CMD16 // command does not affect the memory read and write commands. Always 512 // Bytes fixed block length is used. This command is effective for // LOCK_UNLOCK command. // In both cases, if block length is set larger than 512Bytes, the card sets // the BLOCK_LEN_ERROR bit. if (pSd->cardType == CARD_SD) { error = Cmd16(pSd, SD_BLOCK_SIZE); if (error) { pSd->optCmdBitMap &= ~SD_CMD16_SUPPORT; TRACE_INFO("SD_Init.Cmd16 (%d)\n\r", error); TRACE_INFO("Fail to set BLK_LEN, default is 512\n\r"); } } // Reset status for R/W pSd->state = SD_STATE_READY; // If SDIO Card if (pSd->cardType == CARD_SDIO) { pSd->blockNr = 0; pSd->totalSize = 0; } // If MMC Card & get size from EXT_CSD else if (pSd->cardType >= CARD_MMC && SD_CSD_C_SIZE(pSd) == 0xFFF) { pSd->blockNr = SD_EXTCSD_BLOCKNR(pSd); // Block number less than 0x100000000/512 if (pSd->blockNr > 0x800000) pSd->totalSize = 0xFFFFFFFF; else pSd->totalSize = SD_EXTCSD_TOTAL_SIZE(pSd); } // If SD CSD v2.0 else if(pSd->cardType >= CARD_SD && pSd->cardType < CARD_MMC && SD_CSD_STRUCTURE(pSd) >= 1) { pSd->blockNr = SD_CSD_BLOCKNR_HC(pSd); pSd->totalSize = 0xFFFFFFFF; } // Normal card else { pSd->totalSize = SD_CSD_TOTAL_SIZE(pSd); pSd->blockNr = SD_CSD_BLOCKNR(pSd); } if (pSd->cardType == CARD_UNKNOWN) { return SD_ERROR_NOT_INITIALIZED; } else { return 0; } } //------------------------------------------------------------------------------ /// Stop the SDcard. This function stops all SD operations. /// Returns 0 if successful; otherwise returns an SD_ERROR code. /// \param pSd Pointer to a SD card driver instance. /// \param pSdDriver Pointer to MCI driver already initialized. //------------------------------------------------------------------------------ unsigned char SD_Stop(SdCard *pSd, SdDriver *pSdDriver) { unsigned char error; SdCmd *pCommand = &(pSd->command); if (pSd == 0 || pSdDriver == 0) return 0; if(pCommand->tranType == MCI_CONTINUE_TRANSFER) { TRACE_DEBUG("SD_StopTransmission()\n\r"); error = Cmd12(pSd, (pSd->state != SD_STATE_WRITE), 0); if(error) { return error; } } MCI_Close((Mci *)pSdDriver); return 0; } //------------------------------------------------------------------------------ /// Switch the SD/MMC card to High-Speed mode. /// pSd->transSpeed will change to new speed limit. /// Invoke MCI_SetSpeed() and MCI_EnableHsMode() to change MCI timing after. /// For SD/MMC card, the speed mode will not change back until another init. /// \param pSd Pointer to a SD card driver instance. /// \param hsMode 1 to enable HS mode, 0 to disable /// 0xFF to return current mode. /// \return current mode is hsMode is 0xFF; /// error code if hsMode is 0 or 1. //------------------------------------------------------------------------------ unsigned char SD_HighSpeedMode(SdCard *pSd, unsigned char hsMode) { unsigned char error = 0; if (hsMode == 0xFF) return pSd->mode; if (hsMode == 0) { TRACE_WARNING("Can not switch, do re-init to disable HS mode\n\r"); return SD_ERROR_DRIVER; } // Quit transfer state error = MoveToTranState(pSd); if (error) { TRACE_ERROR("SD_HighSpeedMode.Tran: %d\n\r", error); return error; } if (pSd->mode != hsMode) { error = SdMmcSwitchHsMode(pSd, hsMode); if (error == 0) error = SdMmcUpdateInformation(pSd, 1, 1); } // Reset state for data R/W pSd->state = SD_STATE_READY; return error; } unsigned char SD_BusWidth(SdCard *pSd, unsigned char busWidth) { return 0; } #if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ) //------------------------------------------------------------------------------ /// Read Block of data in a buffer pointed by pData. The buffer size must be at /// least 512 byte long. This function checks the SD card status register and /// address the card if required before sending the read command. /// Returns 0 if successful; otherwise returns an code describing the error. /// \param pSd Pointer to a SD card driver instance. /// \param address Address of the block to read. /// \param nbBlocks Number of blocks to be read. /// \param pData Data buffer whose size is at least the block size. //------------------------------------------------------------------------------ unsigned char MMC_BootRead(SdCard *pSd, unsigned int nbBlocks, unsigned char *pData) { unsigned char error; unsigned char bootAck = 0; unsigned char busWidth = MCI_SDCBUS_4BIT; SANITY_CHECK(pSd); if (pSd->state != SD_STATE_BOOT) return SD_ERROR_DRIVER; #if 0 switch(SD_EXTCSD_BOOT_BUS_WIDTH(pSd)) { case SD_EXTCSD_BOOT_BUS_1BIT: busWidth = MCI_SDCBUS_1BIT; break; case SD_EXTCSD_BOOT_BUS_8BIT: busWidth = MCI_SDCBUS_8BIT; break; } if (SD_EXTCSD_BOOT_CONFIG(pSd) & SD_EXTCSD_BOOT_PARTITION_ACK) bootAck = 1; #endif MCI_SetBusWidth((Mci*)pSd->pSdDriver, busWidth); error = BootREQ(pSd, pData, nbBlocks, bootAck); pSd->state = SD_STATE_BOOT; return error; } //------------------------------------------------------------------------------ /// In boot operation mode, the master can read boot data from the slave. /// By keeping CMD line low after power-on /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ unsigned char MMC_BootInit(SdCard *pSd) { unsigned char error = 0; SANITY_CHECK(pSd); error = PonBoot(pSd); if (!error) { //error = BootREQ(pSd, 0, 0, 0); if (!error) pSd->state = SD_STATE_BOOT; else { TRACE_ERROR("MMC_BootInit.BootREQ: %d\n\r", error); } } else { TRACE_ERROR("MMC_BootInit.PonBoot: %d\n\r", error); } return error; } //------------------------------------------------------------------------------ /// In boot operation mode, the master can read boot data from the slave. /// By sending CMD0 with argument + 0xFFFFFFFA /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ unsigned char MMC_BootStart(SdCard *pSd) { unsigned char error; SANITY_CHECK(pSd); if (pSd->state == SD_STATE_BOOT) return 0; if (pSd->cardType >= CARD_MMC && SD_CSD_STRUCTURE(pSd) >= 2 && SD_CID_BGA(pSd) == 1 && SD_EXTCSD_BOOT_INFO(pSd) == 1) {} else return SD_ERROR_NOT_SUPPORT; error = Cmd0(pSd, 0xFFFFFFFA); pSd->state = SD_STATE_BOOT; return 0; } //------------------------------------------------------------------------------ /// Terminate the boot operation mode /// \param pSd Pointer to a SD card driver instance. //------------------------------------------------------------------------------ unsigned char MMC_BootStop(SdCard *pSd) { unsigned char error; SANITY_CHECK(pSd); if (pSd->state != SD_STATE_BOOT) return 0; error = BootEnd(pSd); if(!error) pSd->state = SD_STATE_IDLE; return error; } //------------------------------------------------------------------------------ /// Setup Boot Settings /// \param resetBus Wether bus width is reset to 1-bit after quit boot mode. /// \param busWidth The bus width in boot operation. /// \param bootPart The partition used for boot operation. /// \param accPart The partition to access with normal read/write. /// \param bootAck Enable boot acknoledge. /// \return 0 or error code. //------------------------------------------------------------------------------ unsigned char MMC_SetupBootMode(SdCard *pSd, unsigned char resetBus, unsigned char busWidth, unsigned char bootPart, unsigned char accPart, unsigned char bootAck) { unsigned int status; unsigned short error; const MmcCmd6Arg bootArgs[] = { // BOOT_CONFIG {3, 179, (bootAck << 6)|(bootPart << 3)|(accPart << 0), 0}, // BOOT_BUS_WIDTH {3, 177, (busWidth << 2)|(resetBus << 0), 0} }; SANITY_CHECK(pSd); if ( pSd->cardType >= CARD_MMC && SD_CSD_STRUCTURE(pSd) >= 2 && SD_CID_CBS(pSd) == 1) {} else return SD_ERROR_NOT_SUPPORT; //if (MMC_GetBootSizeKB(pSd) == 0) return SD_ERROR_NOT_SUPPORT; // Quit transfer state error = MoveToTranState(pSd); if (error) { TRACE_ERROR("MMC_SetupBootMode.Tran: %d\n\r", error); return error; } // Setup all boot informations error = MmcSwitchSettings(pSd, bootArgs, sizeof(bootArgs)/sizeof(MmcCmd6Arg), &status); if (error) { TRACE_ERROR("MMC_SetupBootMode.Cmd6: 0x%x, %x\n\r", error, status); return (unsigned char)error; } // Update the EXT_CSD #if 1 error = Cmd8(pSd, 0, pSd->extData); if (error) { TRACE_ERROR("MMC_SetupBootMode.Cmd8 (%d)\n\r", error); } #if 0 if ( SD_EXTCSD_BOOT_BUS_WIDTH(pSd) != bootArgs[0].value || SD_EXTCSD_BOOT_CONFIG(pSd) != bootArgs[1].value ) { TRACE_ERROR("MMC_SetupBootMode: ExtCSD not changed\n\r"); #if 1 Cmd13(pSd, &status); TRACE_INFO(" CARD status: 0x%x\n\r", status); #endif return SD_ERROR_DRIVER; } #endif #endif // Reset state for data R/W pSd->state = SD_STATE_READY; return 0; } //------------------------------------------------------------------------------ /// \return 0 or error code. //------------------------------------------------------------------------------ unsigned char MMC_StopBootMode() { return 0; } #endif //------------------------------------------------------------------------------ /// \return size of the card in KB //------------------------------------------------------------------------------ unsigned int MMC_GetTotalSizeKB(SdCard *pSd) { SANITY_CHECK(pSd); if (pSd->totalSize == 0xFFFFFFFF) { return pSd->blockNr / 2; } return pSd->totalSize / 1024; } //------------------------------------------------------------------------------ /// \return size of boot area if the card support boot operation. //------------------------------------------------------------------------------ unsigned int MMC_GetBootSizeKB(SdCard *pSd) { SANITY_CHECK(pSd); if ( pSd->cardType >= CARD_MMC && SD_CSD_STRUCTURE(pSd) >= 2) { return SD_EXTCSD_BOOT_SIZE_MULTI(pSd) * 128; } return 0; } #if MCI_SDIO_ENABLE //------------------------------------------------------------------------------ /// Display the content of the CCCR //------------------------------------------------------------------------------ void SDIO_DisplayCardInformation(SdCard *pSd) { unsigned int tmp = 0, addrCIS = 0, addrManfID = 0, addrFunc0 = 0; unsigned char* p = (unsigned char*)&tmp; unsigned char buf[8]; switch(pSd->cardType) { case CARD_SDIO: TRACE_INFO("** SDIO ONLY card\n\r"); break; case CARD_SDCOMBO: case CARD_SDHCCOMBO: TRACE_INFO("** SDIO Combo card\n\r"); break; default: TRACE_INFO("** NO SDIO, CCCR not supported\n\r"); return; } // CCCR TRACE_INFO("====== CCCR ======\n\r"); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_CCCR_REG, p, 1); TRACE_INFO(".SDIO %02X\n\r", (tmp & SDIO_SDIO) >> 4); TRACE_INFO(".CCCR %02X\n\r", (tmp & SDIO_CCCR) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_SD_REV_REG, p, 1); TRACE_INFO(".SD %02X\n\r", (tmp & SDIO_SD) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_IOE_REG, p, 1); TRACE_INFO(".IOE %02X\n\r", (tmp & SDIO_IOE) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_IOR_REG, p, 1); TRACE_INFO(".IOR %02X\n\r", (tmp & SDIO_IOR) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_IEN_REG, p, 1); TRACE_INFO(".IEN %02X\n\r", (tmp & SDIO_IEN) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_INT_REG, p, 1); TRACE_INFO(".INT %02X\n\r", (tmp & SDIO_INT) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_BUS_CTRL_REG, p, 1); TRACE_INFO(".CD %x\n\r", (tmp & SDIO_CD) >> 7); TRACE_INFO(".SCSI %x\n\r", (tmp & SDIO_SCSI) >> 6); TRACE_INFO(".ECSI %x\n\r", (tmp & SDIO_ECSI) >> 5); TRACE_INFO(".BUS_WIDTH %x\n\r", (tmp & SDIO_BUSWIDTH) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_CAP_REG, p, 1); TRACE_INFO(".4BLS %x\n\r", (tmp & SDIO_4BLS) >> 7); TRACE_INFO(".LSC %x\n\r", (tmp & SDIO_LSC) >> 6); TRACE_INFO(".E4MI %x\n\r", (tmp & SDIO_E4MI) >> 5); TRACE_INFO(".S4MI %x\n\r", (tmp & SDIO_S4MI) >> 4); TRACE_INFO(".SBS %x\n\r", (tmp & SDIO_SBS) >> 3); TRACE_INFO(".SRW %x\n\r", (tmp & SDIO_SRW) >> 2); TRACE_INFO(".SMB %x\n\r", (tmp & SDIO_SMB) >> 1); TRACE_INFO(".SDC %x\n\r", (tmp & SDIO_SDC) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_CIS_PTR_REG, p, 3); TRACE_INFO(".CIS_PTR %06X\n\r", tmp); addrCIS = tmp; tmp = 0; SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_BUS_SUSP_REG, p, 1); TRACE_INFO(".BR %x\n\r", (tmp & SDIO_BR) >> 1); TRACE_INFO(".BS %x\n\r", (tmp & SDIO_BS) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_FUN_SEL_REG, p, 1); TRACE_INFO(".DF %x\n\r", (tmp & SDIO_DF) >> 7); TRACE_INFO(".FS %x\n\r", (tmp & SDIO_FS) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_EXEC_REG, p, 1); TRACE_INFO(".EX %x\n\r", (tmp & SDIO_EX)); TRACE_INFO(".EXM %x\n\r", (tmp & SDIO_EXM) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_READY_REG, p, 1); TRACE_INFO(".RF %x\n\r", (tmp & SDIO_RF)); TRACE_INFO(".RFM %x\n\r", (tmp & SDIO_RFM) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_FN0_BLKSIZ_REG, p, 2); TRACE_INFO(".FN0_SIZE %d(%04X)\n\r", tmp, tmp); tmp = 0; SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_POWER_REG, p, 1); TRACE_INFO(".EMPC %x\n\r", (tmp & SDIO_EMPC) >> 1); TRACE_INFO(".SMPC %x\n\r", (tmp & SDIO_SMPC) >> 0); SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_HS_REG, p, 1); TRACE_INFO(".EHS %x\n\r", (tmp & SDIO_EHS) >> 1); TRACE_INFO(".SHS %x\n\r", (tmp & SDIO_SHS) >> 0); // Metaformat SdioFindTuples(pSd, addrCIS, 128, &addrManfID, &addrFunc0); if (addrManfID != 0) { SDIO_ReadDirect(pSd, SDIO_CIA, addrManfID, buf, 6); TRACE_INFO("==== CISTPL_MANFID ====\n\r"); TRACE_INFO("._MANF %04X\n\r", buf[2] + (buf[3] << 8)); TRACE_INFO("._CARD %04X\n\r", buf[4] + (buf[5] << 8)); } if (addrFunc0 != 0) { SDIO_ReadDirect(pSd, SDIO_CIA, addrFunc0, buf, 6); TRACE_INFO("== CISTPL_FUNCE Fun0 ==\n\r"); TRACE_INFO("._FN0_BLK_SIZE %d(0x%04X)\n\r", buf[3] + (buf[4] << 8), buf[3] + (buf[4] << 8)); TRACE_INFO("._MAX_TRAN_SPEED %02X\n\r", buf[5]); } } #endif //------------------------------------------------------------------------------ /// Display the content of the CID register /// \param pCid Pointer to the Cid register value //------------------------------------------------------------------------------ void SD_DisplayRegisterCID(SdCard *pSd) { // CID for memory card only if (pSd->cardType == CARD_UNKNOWN || pSd->cardType >= CARD_SDIO) return; TRACE_INFO("======= CID =======\n\r"); #if 0 TRACE_INFO(" .Card/BGA %X\n\r", SD_CID_BGA(pSd)); #else TRACE_INFO("CID MID Manufacturer ID %02X\n\r", SD_CID_MID(pSd)); TRACE_INFO("CID OID OEM/Application ID %c%c\n\r", (char)SD_CID_OID_BYTE_1(pSd), (char)SD_CID_OID_BYTE_0(pSd)); TRACE_INFO("CID PNM Product revision %c%c%c%c%c\n\r", (char)SD_CID_PNM_BYTE_4(pSd), (char)SD_CID_PNM_BYTE_3(pSd), (char)SD_CID_PNM_BYTE_2(pSd), (char)SD_CID_PNM_BYTE_1(pSd), (char)SD_CID_PNM_BYTE_0(pSd)); TRACE_INFO("CID PRV Product serial number %02X%04X\n\r", SD_CID_PRV_2(pSd), SD_CID_PRV_1(pSd)); TRACE_INFO("CID MDT Manufacturing date %04d/%02d\n\r", (unsigned short)SD_CID_MDT_YEAR(pSd), (unsigned char)SD_CID_MDT_MONTH(pSd)); TRACE_INFO("CID CRC checksum %02X\n\r", SD_CID_CRC(pSd)); #endif } //------------------------------------------------------------------------------ /// Display the content of the CSD register /// \param pSd //------------------------------------------------------------------------------ void SD_DisplayRegisterCSD(SdCard *pSd) { // CID for memory card only if (pSd->cardType == CARD_UNKNOWN || pSd->cardType >= CARD_SDIO) return; TRACE_INFO("======== CSD ========"); #if 0 { unsigned int i; unsigned char *p = (unsigned char *)pSd->csd; for(i = 0; i < 128 / 8; i++) { if ((i % 16) == 0) TRACE_INFO_WP("\n\r [%3d]:", i); TRACE_INFO_WP(" %2x", p[i]); } TRACE_INFO_WP("\n\r"); TRACE_INFO("------------------------\n\r"); } #else TRACE_INFO_WP("\n\r"); #endif TRACE_INFO(" .CSD_STRUCTURE 0x%x\r\n", SD_CSD_STRUCTURE(pSd)); TRACE_INFO(" .SPEC_VERS 0x%x\r\n", SD_CSD_SPEC_VERS(pSd)); TRACE_INFO(" .TAAC 0x%X\r\n", SD_CSD_TAAC(pSd) ); TRACE_INFO(" .NSAC 0x%X\r\n", SD_CSD_NSAC(pSd) ); TRACE_INFO(" .TRAN_SPEED 0x%X\r\n", SD_CSD_TRAN_SPEED(pSd) ); TRACE_INFO(" .CCC 0x%X\r\n", SD_CSD_CCC(pSd) ); TRACE_INFO(" .READ_BL_LEN 0x%X\r\n", SD_CSD_READ_BL_LEN(pSd) ); TRACE_INFO(" .READ_BL_PARTIAL 0x%X\r\n", SD_CSD_READ_BL_PARTIAL(pSd) ); TRACE_INFO(" .WRITE_BLK_MISALIGN 0x%X\r\n", SD_CSD_WRITE_BLK_MISALIGN(pSd)); TRACE_INFO(" .READ_BLK_MISALIGN 0x%X\r\n", SD_CSD_READ_BLK_MISALIGN(pSd) ); TRACE_INFO(" .DSR_IMP 0x%X\r\n", SD_CSD_DSR_IMP(pSd) ); TRACE_INFO(" .C_SIZE 0x%X\r\n", SD_CSD_C_SIZE(pSd) ); TRACE_INFO(" .C_SIZE_HC 0x%X\r\n", SD_CSD_C_SIZE_HC(pSd) ); TRACE_INFO(" .VDD_R_CURR_MIN 0x%X\r\n", SD_CSD_VDD_R_CURR_MIN(pSd) ); TRACE_INFO(" .VDD_R_CURR_MAX 0x%X\r\n", SD_CSD_VDD_R_CURR_MAX(pSd) ); TRACE_INFO(" .VDD_W_CURR_MIN 0x%X\r\n", SD_CSD_VDD_W_CURR_MIN(pSd) ); TRACE_INFO(" .VDD_W_CURR_MAX 0x%X\r\n", SD_CSD_VDD_W_CURR_MAX(pSd) ); TRACE_INFO(" .C_SIZE_MULT 0x%X\r\n", SD_CSD_C_SIZE_MULT(pSd) ); TRACE_INFO(" .ERASE_BLK_EN 0x%X\r\n", SD_CSD_ERASE_BLK_EN(pSd) ); TRACE_INFO(" .SECTOR_SIZE 0x%X\r\n", SD_CSD_SECTOR_SIZE(pSd) ); TRACE_INFO(" .WP_GRP_SIZE 0x%X\r\n", SD_CSD_WP_GRP_SIZE(pSd) ); TRACE_INFO(" .WP_GRP_ENABLE 0x%X\r\n", SD_CSD_WP_GRP_ENABLE(pSd) ); TRACE_INFO(" .R2W_FACTOR 0x%X\r\n", SD_CSD_R2W_FACTOR(pSd) ); TRACE_INFO(" .WRITE_BL_LEN 0x%X\r\n", SD_CSD_WRITE_BL_LEN(pSd) ); TRACE_INFO(" .WRITE_BL_PARTIAL 0x%X\r\n", SD_CSD_WRITE_BL_PARTIAL(pSd) ); TRACE_INFO(" .FILE_FORMAT_GRP 0x%X\r\n", SD_CSD_FILE_FORMAT_GRP(pSd) ); TRACE_INFO(" .COPY 0x%X\r\n", SD_CSD_COPY(pSd) ); TRACE_INFO(" .PERM_WRITE_PROTECT 0x%X\r\n", SD_CSD_PERM_WRITE_PROTECT(pSd)); TRACE_INFO(" .TMP_WRITE_PROTECT 0x%X\r\n", SD_CSD_TMP_WRITE_PROTECT(pSd) ); TRACE_INFO(" .FILE_FORMAT 0x%X\r\n", SD_CSD_FILE_FORMAT(pSd) ); TRACE_INFO(" .ECC 0x%X\r\n", SD_CSD_ECC(pSd) ); TRACE_INFO(" .CRC 0x%X\r\n", SD_CSD_CRC(pSd) ); TRACE_INFO(" .MULT 0x%X\r\n", SD_CSD_MULT(pSd) ); TRACE_INFO(" .BLOCKNR 0x%X\r\n", SD_CSD_BLOCKNR(pSd) ); TRACE_INFO(" .BLOCKNR_HC 0x%X\r\n", SD_CSD_BLOCKNR_HC(pSd) ); TRACE_INFO(" .BLOCK_LEN 0x%X\r\n", SD_CSD_BLOCK_LEN(pSd) ); TRACE_INFO(" .TOTAL_SIZE 0x%X\r\n", SD_CSD_TOTAL_SIZE(pSd) ); TRACE_INFO(" .TOTAL_SIZE_HC 0x%X\r\n", SD_CSD_TOTAL_SIZE_HC(pSd) ); TRACE_INFO(" -SD_TOTAL_SIZE 0x%X\r\n", SD_TOTAL_SIZE(pSd) ); TRACE_INFO(" -SD_TOTAL_BLOCK 0x%X\r\n", SD_TOTAL_BLOCK(pSd) ); } //------------------------------------------------------------------------------ /// Display the content of the EXT_CSD register /// \param pSd //------------------------------------------------------------------------------ void SD_DisplayRegisterECSD(SdCard *pSd) { if (pSd->cardType >= CARD_MMC && pSd->cardType <= CARD_MMCHD && SD_CSD_STRUCTURE(pSd) >= 2) {} else { TRACE_INFO("** EXT_CSD NOT SUPPORTED\n\r"); return; } TRACE_INFO("======= EXT_CSD ======="); #if 0 { unsigned int i; unsigned char *p = (unsigned char *)pSd->extData; for(i = 0; i < 512; i++) { if ((i % 16) == 0) TRACE_INFO_WP("\n\r [%3d]:", i); TRACE_INFO_WP(" %2x", p[i]); } TRACE_INFO_WP("\n\r"); TRACE_INFO("------------------------\n\r"); } #else TRACE_INFO_WP("\n\r"); #endif TRACE_INFO(" .S_CMD_SET : 0x%X\n\r", SD_EXTCSD_S_CMD_SET(pSd)); TRACE_INFO(" .BOOT_INFO : 0x%X\n\r", SD_EXTCSD_BOOT_INFO(pSd)); TRACE_INFO(" .BOOT_SIZE_MULTI : 0x%X\n\r", SD_EXTCSD_BOOT_SIZE_MULTI(pSd)); TRACE_INFO(" .ACC_SIZE : 0x%X\n\r", SD_EXTCSD_ACC_SIZE(pSd)); TRACE_INFO(" .HC_ERASE_GRP_SIZE : 0x%X\n\r", SD_EXTCSD_HC_ERASE_GRP_SIZE(pSd)); TRACE_INFO(" .ERASE_TIMEOUT_MULT : 0x%X\n\r", SD_EXTCSD_ERASE_TIMEOUT_MULT(pSd)); TRACE_INFO(" .REL_WR_SEC_C : 0x%X\n\r", SD_EXTCSD_REL_WR_SEC_C(pSd)); TRACE_INFO(" .HC_WP_GRP_SIZE : 0x%X\n\r", SD_EXTCSD_HC_WP_GRP_SIZE(pSd)); TRACE_INFO(" .S_C_VCC : 0x%X\n\r", SD_EXTCSD_S_C_VCC(pSd)); TRACE_INFO(" .S_C_VCCQ : 0x%X\n\r", SD_EXTCSD_S_C_VCCQ(pSd)); TRACE_INFO(" .S_A_TIMEOUT : 0x%X\n\r", SD_EXTCSD_S_A_TIMEOUT(pSd)); TRACE_INFO(" .SEC_COUNT : 0x%X\n\r", SD_EXTCSD_SEC_COUNT(pSd)); TRACE_INFO(" .MIN_PERF_W_8_52 : 0x%X\n\r", SD_EXTCSD_MIN_PERF_W_8_52(pSd)); TRACE_INFO(" .MIN_PERF_R_8_52 : 0x%X\n\r", SD_EXTCSD_MIN_PERF_R_8_52(pSd)); TRACE_INFO(" .MIN_PERF_W_8_26_4_52 : 0x%X\n\r", SD_EXTCSD_MIN_PERF_W_8_26_4_52(pSd)); TRACE_INFO(" .MIN_PERF_R_8_26_4_52 : 0x%X\n\r", SD_EXTCSD_MIN_PERF_R_8_26_4_52(pSd)); TRACE_INFO(" .MIN_PERF_W_4_26 : 0x%X\n\r", SD_EXTCSD_MIN_PERF_W_4_26(pSd)); TRACE_INFO(" .MIN_PERF_R_4_26 : 0x%X\n\r", SD_EXTCSD_MIN_PERF_R_4_26(pSd)); TRACE_INFO(" .PWR_CL_26_360 : 0x%X\n\r", SD_EXTCSD_PWR_CL_26_360(pSd)); TRACE_INFO(" .PWR_CL_52_360 : 0x%X\n\r", SD_EXTCSD_PWR_CL_52_360(pSd)); TRACE_INFO(" .PWR_CL_26_195 : 0x%X\n\r", SD_EXTCSD_PWR_CL_26_195(pSd)); TRACE_INFO(" .PWR_CL_52_195 : 0x%X\n\r", SD_EXTCSD_PWR_CL_52_195(pSd)); TRACE_INFO(" .CARD_TYPE : 0x%X\n\r", SD_EXTCSD_CARD_TYPE(pSd)); TRACE_INFO(" .CSD_STRUCTURE : 0x%X\n\r", SD_EXTCSD_CSD_STRUCTURE(pSd)); TRACE_INFO(" .EXT_CSD_REV : 0x%X\n\r", SD_EXTCSD_EXT_CSD_REV(pSd)); TRACE_INFO(" .CMD_SET : 0x%X\n\r", SD_EXTCSD_CMD_SET(pSd)); TRACE_INFO(" .CMD_SET_REV : 0x%X\n\r", SD_EXTCSD_CMD_SET_REV(pSd)); TRACE_INFO(" .POWER_CLASS : 0x%X\n\r", SD_EXTCSD_POWER_CLASS(pSd)); TRACE_INFO(" .HS_TIMING : 0x%X\n\r", SD_EXTCSD_HS_TIMING(pSd)); TRACE_INFO(" .BUS_WIDTH : 0x%X\n\r", SD_EXTCSD_BUS_WIDTH(pSd)); TRACE_INFO(" .ERASED_MEM_CONT : 0x%X\n\r", SD_EXTCSD_ERASED_MEM_CONT(pSd)); TRACE_INFO(" .BOOT_CONFIG : 0x%X\n\r", SD_EXTCSD_BOOT_CONFIG(pSd)); TRACE_INFO(" .BOOT_BUS_WIDTH : 0x%X\n\r", SD_EXTCSD_BOOT_BUS_WIDTH(pSd)); TRACE_INFO(" .ERASE_GROUP_DEF : 0x%X\n\r", SD_EXTCSD_ERASE_GROUP_DEF(pSd)); } //------------------------------------------------------------------------------ /// Display the content of the SCR register /// \param pSd Pointer to SdCard instance. //------------------------------------------------------------------------------ void SD_DisplayRegisterSCR(SdCard *pSd) { if (pSd->cardType >= CARD_SD && pSd->cardType <= CARD_SDHC) {} else { TRACE_INFO("** SCR NOT Supported!\n\r"); return; } TRACE_INFO("========== SCR =========="); #if 0 { unsigned int i; unsigned char *p = (unsigned char*)pSd->extData; //TRACE_INFO_WP("\n\r"); //TRACE_INFO("DATA @ 0x%X", (unsigned int)p); for(i = 0; i < 16; i ++) { if ((i % 8) == 0) TRACE_INFO_WP("\n\r [%3d]:", i); TRACE_INFO_WP(" %02x", p[i]); } TRACE_INFO_WP("\n\r"); TRACE_INFO("------------------------\n\r"); } #else TRACE_INFO_WP("\n\r"); #endif TRACE_INFO(" .SCR_STRUCTURE :0x%X\n\r", SD_SCR_SCR_STRUCTURE(pSd)); TRACE_INFO(" .SD_SPEC :0x%X\n\r", SD_SCR_SD_SPEC(pSd)); TRACE_INFO(" .DATA_STAT_AFTER_ERASE :0x%X\n\r", SD_SCR_DATA_STAT_AFTER_ERASE(pSd)); TRACE_INFO(" .SD_SECURITY :0x%X\n\r", SD_SCR_SD_SECURITY(pSd)); TRACE_INFO(" .SD_BUS_WIDTHS :0x%X\n\r", SD_SCR_SD_BUS_WIDTHS(pSd)); } //------------------------------------------------------------------------------ /// Display the content of the SD Status /// \param pSd Pointer to SdCard instance. //------------------------------------------------------------------------------ void SD_DisplaySdStatus(SdCard *pSd) { if ( pSd->cardType >= CARD_SD && pSd->cardType <= CARD_SDHC && (pSd->optCmdBitMap & SD_ACMD13_SUPPORT) ) {} else { TRACE_INFO("** SD Status NOT Supported!\n\r"); return; } TRACE_INFO("=========== STAT ============"); #if 0 { unsigned int i; unsigned char *p = (unsigned char*)pSd->extData; //TRACE_INFO_WP("\n\r"); //TRACE_INFO("DATA @ 0x%X", (unsigned int)p); for(i = 0; i < 72; i ++) { if ((i % 8) == 0) TRACE_INFO_WP("\n\r [%3d]:", i); TRACE_INFO_WP(" %02x", p[i]); } TRACE_INFO_WP("\n\r"); TRACE_INFO("------------------------\n\r"); } #else TRACE_INFO_WP("\n\r"); #endif TRACE_INFO(" .DAT_BUS_WIDTH :0x%X\n\r", SD_STAT_DAT_BUS_WIDTH(pSd)); TRACE_INFO(" .SECURED_MODE :0x%X\n\r", SD_STAT_SECURED_MODE(pSd)); TRACE_INFO(" .SD_CARD_TYPE :0x%X\n\r", SD_STAT_SD_CARD_TYPE(pSd)); TRACE_INFO(" .SIZE_OF_PROTECTED_AREA :0x%X\n\r", SD_STAT_SIZE_OF_PROTECTED_AREA(pSd)); TRACE_INFO(" .SPEED_CLASS :0x%X\n\r", SD_STAT_SPEED_CLASS(pSd)); TRACE_INFO(" .PERFORMANCE_MOVE :0x%X\n\r", SD_STAT_PERFORMANCE_MOVE(pSd)); TRACE_INFO(" .AU_SIZE :0x%X\n\r", SD_STAT_AU_SIZE(pSd)); TRACE_INFO(" .ERASE_SIZE :0x%X\n\r", SD_STAT_ERASE_SIZE(pSd)); TRACE_INFO(" .ERASE_TIMEOUT :0x%X\n\r", SD_STAT_ERASE_TIMEOUT(pSd)); TRACE_INFO(" .ERASE_OFFSET :0x%X\n\r", SD_STAT_ERASE_OFFSET(pSd)); }