From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- memories/sdmmc/sdmmc_mci.c | 4048 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4048 insertions(+) create mode 100644 memories/sdmmc/sdmmc_mci.c (limited to 'memories/sdmmc/sdmmc_mci.c') diff --git a/memories/sdmmc/sdmmc_mci.c b/memories/sdmmc/sdmmc_mci.c new file mode 100644 index 0000000..3202945 --- /dev/null +++ b/memories/sdmmc/sdmmc_mci.c @@ -0,0 +1,4048 @@ +/* ---------------------------------------------------------------------------- + * 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)); +} -- cgit v1.2.3