1451 lines
44 KiB
C++
1451 lines
44 KiB
C++
/*
|
|
* Authors (alphabetical order)
|
|
* - Andre Bernet <bernet.andre@gmail.com>
|
|
* - Bertrand Songis <bsongis@gmail.com>
|
|
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
|
* - Cameron Weeks <th9xer@gmail.com>
|
|
* - Erez Raviv
|
|
* - Jean-Pierre Parisy
|
|
* - Karl Szmutny <shadow@privy.de>
|
|
* - Michael Blandford
|
|
* - Michal Hlavinka
|
|
* - Pat Mackenzie
|
|
* - Philip Moss
|
|
* - Rob Thomson
|
|
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
|
* - Thomas Husterer
|
|
*
|
|
* open9x is based on code named
|
|
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
|
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
|
* and the original (and ongoing) project by
|
|
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2010 */
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Only rcvr_spi(), xmit_spi(), sdPoll10ms() and some macros */
|
|
/* are platform dependent. */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
#include <string.h>
|
|
#include "board.h"
|
|
#include "debug.h"
|
|
#include "../FatFs/diskio.h"
|
|
#include "../FatFs/ff.h"
|
|
#include "../CoOS/kernel/CoOS.h"
|
|
|
|
#define CARD_TYPE_bmHC (1 << 0) /**< Bit for High-Capacity(Density) */
|
|
#define CARD_TYPE_bmSDMMC (0x3 << 1) /**< Bits mask for SD/MMC */
|
|
#define CARD_TYPE_bmUNKNOWN (0x0 << 1) /**< Bits for Unknown card */
|
|
#define CARD_TYPE_bmSD (0x1 << 1) /**< Bits for SD */
|
|
#define CARD_TYPE_bmMMC (0x2 << 1) /**< Bits for MMC */
|
|
#define CARD_TYPE_bmSDIO (1 << 3) /**< Bit for SDIO */
|
|
/** Card can not be identified */
|
|
#define CARD_UNKNOWN (0)
|
|
/** SD Card (0x2) */
|
|
#define CARD_SD (CARD_TYPE_bmSD)
|
|
/** SD High Capacity Card (0x3) */
|
|
#define CARD_SDHC (CARD_TYPE_bmSD|CARD_TYPE_bmHC)
|
|
/** MMC Card (0x4) */
|
|
#define CARD_MMC (CARD_TYPE_bmMMC)
|
|
/** MMC High-Density Card (0x5) */
|
|
#define CARD_MMCHD (CARD_TYPE_bmMMC|CARD_TYPE_bmHC)
|
|
/** SDIO only card (0x8) */
|
|
#define CARD_SDIO (CARD_TYPE_bmSDIO)
|
|
/** SDIO Combo, with SD embedded (0xA) */
|
|
#define CARD_SDCOMBO (CARD_TYPE_bmSDIO|CARD_SD)
|
|
/** SDIO Combo, with SDHC embedded (0xB) */
|
|
#define CARD_SDHCCOMBO (CARD_TYPE_bmSDIO|CARD_SDHC)
|
|
|
|
#define STATUS_READY_FOR_DATA (1UL << 8)
|
|
#define STATUS_TRAN (4UL << 9)
|
|
#define STATUS_STATE (0xFUL << 9)
|
|
|
|
/** Bit mask for data errors */
|
|
#define STATUS_ERRORS_DATA ((uint32_t)(HSMCI_SR_UNRE \
|
|
| HSMCI_SR_OVRE \
|
|
/*| HSMCI_SR_BLKOVRE*/ \
|
|
/*| HSMCI_SR_CSTOE*/ \
|
|
| HSMCI_SR_DTOE \
|
|
| HSMCI_SR_DCRCE))
|
|
|
|
|
|
uint32_t Card_ID[4] ;
|
|
uint32_t Card_SCR[2] ;
|
|
uint32_t Card_CSD[4] ;
|
|
int32_t Card_state = SD_ST_STARTUP ;
|
|
volatile uint32_t Card_initialized = 0;
|
|
uint32_t Sd_rca ;
|
|
uint32_t Cmd_A41_resp ;
|
|
uint8_t cardType;
|
|
uint32_t transSpeed;
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Lock / unlock functions */
|
|
/*-----------------------------------------------------------------------*/
|
|
int ff_cre_syncobj (BYTE vol, _SYNC_t *mutex)
|
|
{
|
|
*mutex = CoCreateMutex();
|
|
return 1;
|
|
}
|
|
|
|
int ff_req_grant (_SYNC_t mutex)
|
|
{
|
|
CoEnterMutexSection(mutex);
|
|
return 1;
|
|
}
|
|
|
|
void ff_rel_grant (_SYNC_t mutex)
|
|
{
|
|
CoLeaveMutexSection(mutex);
|
|
}
|
|
|
|
int ff_del_syncobj (_SYNC_t mutex)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// 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
|
|
//------------------------------------------------------------------------------
|
|
uint32_t GetTransSpeedValue()
|
|
{
|
|
// 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
|
|
transSpeed = MmcGetTranSpeed(SD_CSD_TRAN_SPEED(Card_CSD),
|
|
units, 4,
|
|
values_sdmmc);
|
|
#endif
|
|
/*if (pSd->cardType >= CARD_MMC && SD_EXTCSD_HS_TIMING(pSd)) {
|
|
pSd->transSpeed *= 2;
|
|
}*/
|
|
TRACE_ERROR("-I- SD/MMC TRANS SPEED %d KBit/s\r\n", transSpeed);
|
|
transSpeed *= 1000;
|
|
return transSpeed;
|
|
}
|
|
|
|
/**
|
|
* Configure the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
|
|
* MCK/2 and corresponds to CLKDIV = 0
|
|
* \param mciSpeed MCI clock speed in Hz, 0 will not change current speed.
|
|
* \return The actual speed used, 0 for fail.
|
|
*/
|
|
uint32_t sdSetSpeed(uint32_t mciSpeed )
|
|
{
|
|
uint32_t mciMr;
|
|
uint32_t clkdiv, divLimit;
|
|
|
|
mciMr = HSMCI->HSMCI_MR & (~(uint32_t)HSMCI_MR_CLKDIV_Msk);
|
|
/* Multimedia Card Interface clock (MCCK or MCI_CK) is Master Clock (MCK)
|
|
* divided by (2*(CLKDIV+1))
|
|
* mciSpeed = MCK / (2*(CLKDIV+1)) */
|
|
if (mciSpeed > 0) {
|
|
|
|
#if 1
|
|
divLimit = (Master_frequency / 2 / mciSpeed);
|
|
if ((Master_frequency / 2) % mciSpeed) divLimit ++;
|
|
|
|
clkdiv = (Master_frequency / 2 / mciSpeed);
|
|
if (mciSpeed && clkdiv < divLimit)
|
|
clkdiv = divLimit;
|
|
if (clkdiv > 0)
|
|
clkdiv -= 1;
|
|
#else
|
|
clkdiv = (Master_frequency / 2 / mciSpeed);
|
|
/* Speed should not bigger than expired one */
|
|
if (mciSpeed < Master_frequency / 2 / clkdiv) {
|
|
clkdiv++;
|
|
}
|
|
if (clkdiv > 0) {
|
|
clkdiv -= 1;
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
clkdiv = 0;
|
|
}
|
|
|
|
/* Actual MCI speed */
|
|
mciSpeed = Master_frequency / 2 / (clkdiv + 1);
|
|
/* Modify MR */
|
|
HSMCI->HSMCI_MR = mciMr | clkdiv;
|
|
|
|
return mciSpeed;
|
|
}
|
|
|
|
#if 0
|
|
void SD_SetBlklen( uint32_t blklen )
|
|
{
|
|
uint32_t mciMr;
|
|
uint32_t clkdiv;
|
|
|
|
mciMr = HSMCI->HSMCI_MR & (~(uint32_t)HSMCI_MR_BLKLEN);
|
|
/* Modify MR */
|
|
HSMCI->HSMCI_MR = mciMr | blklen << 16 ;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
/**
|
|
* Reset MCI HW interface and disable it.
|
|
* \param keepSettings Keep old register settings, including
|
|
* _MR, _SDCR, _DTOR, _CSTOR, _DMA and _CFG.
|
|
*/
|
|
void SD_Reset( uint8_t keepSettings)
|
|
{
|
|
Hsmci *pMciHw = HSMCI ;
|
|
|
|
if (keepSettings)
|
|
{
|
|
uint32_t mr, sdcr, dtor, cstor;
|
|
uint32_t cfg;
|
|
mr = pMciHw->HSMCI_MR;
|
|
sdcr = pMciHw->HSMCI_SDCR;
|
|
dtor = pMciHw->HSMCI_DTOR;
|
|
cstor = pMciHw->HSMCI_CSTOR;
|
|
cfg = pMciHw->HSMCI_CFG;
|
|
pMciHw->HSMCI_CR = HSMCI_CR_SWRST ; // Reset
|
|
pMciHw->HSMCI_CR = HSMCI_CR_MCIDIS; // Disable
|
|
pMciHw->HSMCI_MR = mr;
|
|
pMciHw->HSMCI_SDCR = sdcr;
|
|
pMciHw->HSMCI_DTOR = dtor;
|
|
pMciHw->HSMCI_CSTOR = cstor;
|
|
pMciHw->HSMCI_CFG = cfg;
|
|
}
|
|
else
|
|
{
|
|
pMciHw->HSMCI_CR = HSMCI_CR_SWRST ; // Reset
|
|
pMciHw->HSMCI_CR = HSMCI_CR_MCIDIS; // Disable
|
|
}
|
|
}
|
|
#endif
|
|
|
|
const char SD_NORESPONSE[] = "No response";
|
|
|
|
const char * sdCommand(uint32_t cmd, uint32_t arg)
|
|
{
|
|
uint32_t i;
|
|
Hsmci *phsmci = HSMCI;
|
|
|
|
if (CardIsConnected()) {
|
|
phsmci->HSMCI_ARGR = arg;
|
|
phsmci->HSMCI_CMDR = cmd;
|
|
|
|
for (i = 0; i < 50000; i += 1) {
|
|
if (phsmci->HSMCI_SR & HSMCI_SR_CMDRDY) {
|
|
return 0;
|
|
}
|
|
}
|
|
return SD_NORESPONSE;
|
|
}
|
|
else {
|
|
return "No Sdcard";
|
|
}
|
|
}
|
|
|
|
#define SDMMC_POWER_ON_INIT (0 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_INIT \
|
|
| HSMCI_CMDR_OPDCMD )
|
|
|
|
const char * sdPowerOn()
|
|
{
|
|
return sdCommand(SDMMC_POWER_ON_INIT, 0);
|
|
}
|
|
|
|
#define SDMMC_GO_IDLE_STATE (0 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD )
|
|
|
|
const char * sdCmd0()
|
|
{
|
|
return sdCommand(SDMMC_GO_IDLE_STATE, 0);
|
|
}
|
|
|
|
#if 0
|
|
#define SDIO_SEND_OP_COND (5 | HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_OPDCMD )
|
|
|
|
const char * sdCmd5(uint32_t *pIo)
|
|
{
|
|
const char * result = sdCommand(SDIO_SEND_OP_COND, *pIo);
|
|
if (result)
|
|
return result;
|
|
*pIo = HSMCI->HSMCI_RSPR[0];
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#define SD_SEND_IF_COND (8 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_OPDCMD /* BSS difference */ \
|
|
| HSMCI_CMDR_MAXLAT )
|
|
|
|
const char * sdCmd8(uint8_t supplyVoltage)
|
|
{
|
|
return sdCommand(SD_SEND_IF_COND, (supplyVoltage << 8) | (0xAA));
|
|
}
|
|
|
|
#define SDMMC_APP_CMD (55| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_MAXLAT)
|
|
|
|
const char * sdCmd55()
|
|
{
|
|
return sdCommand(SDMMC_APP_CMD, Sd_rca);
|
|
}
|
|
|
|
#define SDMMC_SEND_STATUS_CMD (13 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_MAXLAT )
|
|
|
|
const char * sdCmd13(unsigned int *status)
|
|
{
|
|
const char *result = sdCommand(SDMMC_SEND_STATUS_CMD, Sd_rca);
|
|
if (result)
|
|
return result;
|
|
*status = HSMCI->HSMCI_RSPR[0];
|
|
return 0;
|
|
}
|
|
|
|
#define SDMMC_SET_BLOCKLEN (16 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_MAXLAT_64 )
|
|
|
|
uint32_t sdCmd16()
|
|
{
|
|
Hsmci *phsmci = HSMCI;
|
|
|
|
if (CardIsConnected()) {
|
|
phsmci->HSMCI_BLKR = ( ( 512 ) << 16 ) | 1 ;
|
|
phsmci->HSMCI_ARGR = 512;
|
|
phsmci->HSMCI_CMDR = SDMMC_SET_BLOCKLEN;
|
|
|
|
while(1) {
|
|
if (phsmci->HSMCI_SR & HSMCI_SR_CMDRDY) {
|
|
break;
|
|
}
|
|
}
|
|
return phsmci->HSMCI_RSPR[0];
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#define SD_SD_SEND_OP_COND (41| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_TRCMD_NO_DATA \
|
|
/*| HSMCI_CMDR_OPDCMD_OPENDRAIN */ )
|
|
|
|
const char * sdCmd41(uint32_t arg, uint32_t * status)
|
|
{
|
|
const char * result = sdCommand(SD_SD_SEND_OP_COND, arg);
|
|
if (result)
|
|
return result;
|
|
*status = HSMCI->HSMCI_RSPR[0];
|
|
return 0;
|
|
}
|
|
|
|
#define OCR_VDD_27_28 ((uint32_t)(1 << 15))
|
|
#define OCR_VDD_28_29 ((uint32_t)(1 << 16))
|
|
#define OCR_VDD_29_30 ((uint32_t)(1 << 17))
|
|
#define OCR_VDD_30_31 ((uint32_t)(1 << 18))
|
|
#define OCR_VDD_31_32 ((uint32_t)(1 << 19))
|
|
#define OCR_VDD_32_33 ((uint32_t)(1 << 20))
|
|
#define OCR_VDD_33_34 ((uint32_t)(1 << 21))
|
|
|
|
#define SDMMC_HOST_VOLTAGE_RANGE (OCR_VDD_27_28 +\
|
|
OCR_VDD_28_29 +\
|
|
OCR_VDD_29_30 +\
|
|
OCR_VDD_30_31 +\
|
|
OCR_VDD_31_32 +\
|
|
OCR_VDD_32_33 +\
|
|
OCR_VDD_32_33) /* not in SAM3S reference code */
|
|
|
|
#define OCR_POWER_UP_BUSY (1UL << 31)
|
|
|
|
const char * sdMemInit(uint8_t hcs, uint32_t *pCCS)
|
|
{
|
|
const char * result;
|
|
uint32_t arg;
|
|
uint32_t status;
|
|
do {
|
|
result = sdCmd55();
|
|
if (result)
|
|
return result;
|
|
arg = SDMMC_HOST_VOLTAGE_RANGE;
|
|
if (hcs) arg |= OCR_SD_CCS;
|
|
result = sdCmd41(arg, &status);
|
|
if (result)
|
|
return result;
|
|
*pCCS = (status & OCR_SD_CCS);
|
|
} while ((status & OCR_POWER_UP_BUSY) != OCR_POWER_UP_BUSY);
|
|
return 0;
|
|
}
|
|
|
|
// Get Card ID
|
|
const char * sdCmd2()
|
|
{
|
|
const char * result = sdCommand(0x00001082, 0);
|
|
if (result)
|
|
return result;
|
|
|
|
Hsmci *phsmci = HSMCI ;
|
|
Card_ID[0] = phsmci->HSMCI_RSPR[0] ;
|
|
Card_ID[1] = phsmci->HSMCI_RSPR[1] ;
|
|
Card_ID[2] = phsmci->HSMCI_RSPR[2] ;
|
|
Card_ID[3] = phsmci->HSMCI_RSPR[3] ;
|
|
return 0;
|
|
}
|
|
|
|
// Get new RCA
|
|
const char * sdCmd3()
|
|
{
|
|
const char * result = sdCommand(0x00001043, 0);
|
|
if (result)
|
|
return result;
|
|
Sd_rca = HSMCI->HSMCI_RSPR[0];
|
|
return 0;
|
|
}
|
|
|
|
// Get CSD
|
|
const char * sdCmd9()
|
|
{
|
|
const char * result = sdCommand(0x00001089, Sd_rca);
|
|
if (result)
|
|
return result;
|
|
|
|
Hsmci *phsmci = HSMCI ;
|
|
Card_CSD[0] = phsmci->HSMCI_RSPR[0] ;
|
|
Card_CSD[1] = phsmci->HSMCI_RSPR[1] ;
|
|
Card_CSD[2] = phsmci->HSMCI_RSPR[2] ;
|
|
Card_CSD[3] = phsmci->HSMCI_RSPR[3] ;
|
|
return 0;
|
|
}
|
|
|
|
/** Cmd7 MCI, ac, R1/R1b */
|
|
#define SDMMC_SELECT_CARD (7 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_R1B \
|
|
| HSMCI_CMDR_MAXLAT )
|
|
|
|
const char * sdCmd7()
|
|
{
|
|
return sdCommand(SDMMC_SELECT_CARD, Sd_rca);
|
|
}
|
|
|
|
#define SD_SEND_SCR (51 | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRDIR_READ \
|
|
| HSMCI_CMDR_TRTYP_SINGLE | HSMCI_CMDR_MAXLAT)
|
|
|
|
#define SD_READ_SINGLE_BLOCK (17 | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRDIR_READ \
|
|
| HSMCI_CMDR_TRTYP_SINGLE | HSMCI_CMDR_MAXLAT)
|
|
|
|
#define SD_WRITE_SINGLE_BLOCK (24 | HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_TRCMD_START_DATA \
|
|
| HSMCI_CMDR_TRDIR_WRITE \
|
|
| HSMCI_CMDR_TRTYP_SINGLE \
|
|
| HSMCI_CMDR_MAXLAT)
|
|
|
|
// Get SCR
|
|
const char * sdAcmd51()
|
|
{
|
|
const char * result;
|
|
result = sdCmd55();
|
|
if (result)
|
|
return result;
|
|
|
|
Hsmci *phsmci = HSMCI ;
|
|
// Block size = 64/ 8, nblocks = 1
|
|
phsmci->HSMCI_BLKR = ( ( 64 / 8 ) << 16 ) | 1 ;
|
|
phsmci->HSMCI_ARGR = 0 ;
|
|
phsmci->HSMCI_CMDR = SD_SEND_SCR ;
|
|
|
|
uint8_t scrLen = 0;
|
|
uint32_t i;
|
|
for ( i = 0 ; i < 50000 ; i += 1 ) {
|
|
if ( phsmci->HSMCI_SR & HSMCI_SR_RXRDY )
|
|
Card_SCR[scrLen++] = __REV(phsmci->HSMCI_RDR) ;
|
|
if ( ( phsmci->HSMCI_SR & ( HSMCI_SR_CMDRDY | HSMCI_SR_XFRDONE ) ) == ( HSMCI_SR_CMDRDY | HSMCI_SR_XFRDONE ) )
|
|
return 0;
|
|
}
|
|
return "No response";
|
|
}
|
|
|
|
#define SD_SET_BUS_WIDTH (6 | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_MAXLAT)
|
|
|
|
void sdEnableHsMode(uint8_t enable)
|
|
{
|
|
Hsmci *phsmci = HSMCI;
|
|
if (enable)
|
|
phsmci->HSMCI_CFG |= HSMCI_CFG_HSMODE;
|
|
else
|
|
phsmci->HSMCI_CFG &= ~HSMCI_CFG_HSMODE;
|
|
}
|
|
|
|
void sdSetBusWidth(uint32_t busWidth)
|
|
{
|
|
Hsmci *phsmci = HSMCI;
|
|
phsmci->HSMCI_SDCR = (HSMCI->HSMCI_SDCR & ~HSMCI_SDCR_SDCBUS_Msk) | busWidth;
|
|
}
|
|
|
|
// Set bus width to 4 bits, set speed to 9 MHz
|
|
const char * sdAcmd6()
|
|
{
|
|
const char * result;
|
|
result = sdCmd55() ;
|
|
if (result)
|
|
return result;
|
|
|
|
result = sdCommand(SD_SET_BUS_WIDTH, 2);
|
|
if (result)
|
|
return result;
|
|
|
|
sdSetBusWidth( HSMCI_SDCR_SDCBUS_4 ) ;
|
|
|
|
GetTransSpeedValue();
|
|
sdSetSpeed(transSpeed/*9000000*/);
|
|
|
|
// TODO + Cmd6? sdEnableHsMode(1);
|
|
|
|
if (Cmd_A41_resp & OCR_SD_CCS)
|
|
sdCmd16();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
/** SDIO CMD52, R5 */
|
|
#define SDIO_IO_RW_DIRECT (52| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_MAXLAT)
|
|
|
|
static const char * sdCmd52(uint8_t wrFlag,
|
|
uint8_t funcNb,
|
|
uint8_t rdAfterWr,
|
|
uint32_t addr,
|
|
uint32_t *status)
|
|
{
|
|
typedef struct
|
|
{
|
|
uint32_t data:8, /**< [ 7: 0] data for writing */
|
|
stuff0:1, /**< [ 8] reserved */
|
|
regAddress:17, /**< [25: 9] register address */
|
|
stuff1:1, /**< [ 26] reserved */
|
|
rawFlag:1, /**< [ 27] Read after Write flag */
|
|
functionNum:3, /**< [30:28] Number of the function */
|
|
rwFlag:1; /**< [ 31] Direction, 1:write, 0:read. */
|
|
} SdioCmd52Arg;
|
|
|
|
SdioCmd52Arg pArg52;
|
|
pArg52.rwFlag = wrFlag;
|
|
pArg52.functionNum = funcNb;
|
|
pArg52.rawFlag = rdAfterWr;
|
|
pArg52.regAddress = addr;
|
|
|
|
const char * result = sdCommand(SDIO_IO_RW_DIRECT, *(uint32_t*)&pArg52);
|
|
if (result)
|
|
return result;
|
|
*status = HSMCI->HSMCI_RSPR[0];
|
|
return 0;
|
|
}
|
|
|
|
const char * sdSwReset(uint32_t retry)
|
|
{
|
|
uint32_t i;
|
|
const char * result = 0;
|
|
|
|
for (i = 0; i < retry; i++) {
|
|
result = sdCmd0(0);
|
|
if (result != SD_NORESPONSE)
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* \brief Run the SD/MMC/SDIO Mode initialization sequence.
|
|
* This function runs the initialization procedure and the identification
|
|
* process. Then it leaves the card in ready state. The following procedure 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.
|
|
* \param pSd Pointer to a SD card driver instance.
|
|
* \return 0 if successful; otherwise returns an \ref sdmmc_rc "SD_ERROR code".
|
|
*/
|
|
|
|
#define SDIO_CIA 0 /**< SDIO Function 0 (CIA) */
|
|
#define SDIO_IOA_REG 0x06 /**< I/O Abort */
|
|
|
|
/** SDIO state (in R5) */
|
|
#define SDIO_R5_ERROR (1UL << 11)/**< General error */
|
|
#define SDIO_R5_FUNC_NUM (1UL << 10)/**< Invalid function number */
|
|
#define SDIO_R5_OUT_OF_RANGE (1UL << 9) /**< Argument out of range */
|
|
|
|
/** Status bits mask for SDIO R5 */
|
|
#define STATUS_SDIO_R5 (0/*SDIO_R5_STATE*/ \
|
|
| SDIO_R5_ERROR \
|
|
| SDIO_R5_FUNC_NUM \
|
|
| SDIO_R5_OUT_OF_RANGE)
|
|
|
|
|
|
#define OCR_SDIO_MP (1UL << 27)
|
|
#define OCR_SDIO_NF (7UL << 28)
|
|
|
|
#if 0
|
|
const char * sdIdentify()
|
|
{
|
|
uint8_t mem = 0, io = 0, f8 = 0, mp = 1;
|
|
uint32_t status, ccs=0;
|
|
const char * result;
|
|
|
|
/* Reset HC to default HS and BusMode */
|
|
sdEnableHsMode(0);
|
|
sdSetBusWidth(HSMCI_SDCR_SDCBUS_1);
|
|
|
|
#if 0
|
|
/* Reset SDIO: CMD52, write 1 to RES bit in CCCR (bit 3 of register 6) */
|
|
result = sdCmd52(1, SDIO_CIA, 0, SDIO_IOA_REG, &status);
|
|
if (result)
|
|
return result;
|
|
if (status & STATUS_SDIO_R5)
|
|
return "Identify.52 error";
|
|
#endif
|
|
|
|
/* Reset MEM: CMD0 */
|
|
result = sdSwReset(1);
|
|
if (result)
|
|
return result;
|
|
|
|
/* 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... */
|
|
result = sdCmd8(1);
|
|
if (result == 0) f8 = 1;
|
|
else if (result == SD_NORESPONSE) CoTickDelay(1); /* 2ms delay after "no response" */
|
|
else return "Identify.8 error";
|
|
|
|
#if 0
|
|
/* CMD5 is newly added for SDIO initialize & power on */
|
|
status = 0;
|
|
result = sdCmd5(&status);
|
|
if (!result && (status & OCR_SDIO_NF) > 0) {
|
|
unsigned int cmd5Retries = 10000;
|
|
do {
|
|
status &= SDMMC_HOST_VOLTAGE_RANGE;
|
|
result = sdCmd5(&status);
|
|
if (status & OCR_POWER_UP_BUSY) break;
|
|
} while(!result && cmd5Retries --);
|
|
if (result)
|
|
return "Identify.5 error";
|
|
io = 1;
|
|
/* IO only ?*/
|
|
mp = ((status & OCR_SDIO_MP) > 0);
|
|
}
|
|
#endif
|
|
|
|
/* Has memory: SD/MMC/COMBO */
|
|
/*if (mp) */
|
|
{
|
|
/* Try SD memory initialize */
|
|
result = sdMemInit(f8, &ccs);
|
|
if (result) {
|
|
//unsigned int cmd1Retries = 10000;
|
|
/* Try MMC initialize */
|
|
result = sdSwReset(10);
|
|
if (result)
|
|
return "Reset error";
|
|
/* TODO ccs = 1;
|
|
do { result = sdCmd1(&ccs); } while(result && cmd1Retries -- > 0);
|
|
if (error) {
|
|
TRACE_ERROR("SdMmcIdentify.Cmd1: %u\n\r", error);
|
|
return SDMMC_ERROR;
|
|
}
|
|
else if (ccs) cardType = CARD_MMCHD;
|
|
else cardType = CARD_MMC;
|
|
*/
|
|
return "TODO error";
|
|
/* MMC card identification OK */
|
|
return 0;
|
|
}
|
|
// mem = 1;
|
|
}
|
|
/* SD(IO) + MEM ? */
|
|
/* if (!mem) {
|
|
if (io) cardType = CARD_SDIO;
|
|
else
|
|
return "Unknown SD";
|
|
} */
|
|
/* SD(HC) combo */
|
|
/*else if (io)
|
|
cardType = ccs ? CARD_SDHCCOMBO : CARD_SDCOMBO;*/
|
|
/* SD(HC) */
|
|
//else
|
|
cardType = ccs ? CARD_SDHC : CARD_SD;
|
|
|
|
return 0;
|
|
}
|
|
|
|
const char * sdEnum()
|
|
{
|
|
uint8_t mem , io;
|
|
const char * result;
|
|
uint32_t ioSpeed = 0, memSpeed = 0;
|
|
uint8_t hsExec = 0, bwExec = 0;
|
|
|
|
/* - has Memory/IO/High-Capacity - */
|
|
mem = ((cardType & CARD_TYPE_bmSDMMC) > 0);
|
|
io = ((cardType & CARD_TYPE_bmSDIO) > 0);
|
|
|
|
/* For MEMORY cards:
|
|
* 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) {
|
|
result = sdCmd2();
|
|
if (result)
|
|
return result;
|
|
}
|
|
|
|
/* For MEMORY and SDIO cards:
|
|
* 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. */
|
|
result = sdCmd3();
|
|
if (result)
|
|
return result;
|
|
|
|
/* For MEMORY cards:
|
|
* SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
|
|
* e.g. block length, card storage capacity, etc... */
|
|
if (mem) {
|
|
result = sdCmd9();
|
|
if (result)
|
|
return result;
|
|
}
|
|
|
|
/* Now select the card, to TRAN state */
|
|
error = MmcSelectCard(pSd, pSd->cardAddress, 0);
|
|
if (error) {
|
|
TRACE_ERROR("SdMmcInit.SelCard(%d)\n\r", error);
|
|
return error;
|
|
}
|
|
|
|
/* - Now in TRAN, obtain extended setup information - */
|
|
|
|
/* 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, 1);
|
|
|
|
/* Calculate transfer speed */
|
|
if (io) ioSpeed = SdioGetMaxSpeed(pSd);
|
|
if (mem) memSpeed = SdmmcGetMaxSpeed(pSd);
|
|
/* Combo, min speed */
|
|
if (io && mem) {
|
|
pSd->transSpeed = (ioSpeed > memSpeed) ? memSpeed : ioSpeed;
|
|
}
|
|
/* SDIO only */
|
|
else if (io) {
|
|
pSd->transSpeed = ioSpeed;
|
|
}
|
|
/* Memory card only */
|
|
else if (mem) {
|
|
pSd->transSpeed = memSpeed;
|
|
}
|
|
pSd->transSpeed *= 1000;
|
|
|
|
/* Enable more bus width Mode */
|
|
error = SdMmcDesideBuswidth(pSd);
|
|
if (!error) bwExec = 1;
|
|
else if (error != SDMMC_ERROR_NOT_SUPPORT) {
|
|
TRACE_ERROR("SdmmcEnum.DesideBusWidth: %u\n\r", error);
|
|
return SDMMC_ERROR;
|
|
}
|
|
|
|
/* Enable High-Speed Mode */
|
|
error = SdMmcEnableHighSpeed(pSd);
|
|
if (!error) hsExec = 1;
|
|
else if (error != SDMMC_ERROR_NOT_SUPPORT) {
|
|
TRACE_ERROR("SdmmcEnum.EnableHS: %u\n\r", error);
|
|
return SDMMC_ERROR;
|
|
}
|
|
|
|
/* In HS mode transfer speed *2 */
|
|
if (hsExec) pSd->transSpeed *= 2;
|
|
|
|
/* Update card information since status changed */
|
|
if (bwExec || hsExec) SdMmcUpdateInformation(pSd, hsExec, 1);
|
|
return 0;
|
|
}
|
|
|
|
void sdInit()
|
|
{
|
|
const char * result;
|
|
uint8_t i;
|
|
|
|
/* Clear CID, CSD, EXT_CSD data */
|
|
for (i = 0; i < 4; i++) Card_ID[i] = 0;
|
|
for (i = 0; i < 4; i++) Card_CSD[i] = 0;
|
|
// TODO for (i = 0; i < 512/4; i++) pSd->extData[i] = 0;
|
|
|
|
/* Set low speed for device identification (LS device max speed) */
|
|
sdSetSpeed(400000);
|
|
|
|
/* 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 */
|
|
result = sdPowerOn();
|
|
if (result)
|
|
return;
|
|
|
|
/* 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).
|
|
*/
|
|
result = sdIdentify();
|
|
if (result) {
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
result = sdEnum();
|
|
if (result) {
|
|
return;
|
|
}
|
|
|
|
/* 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, SDMMC_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 MMC Card & get size from EXT_CSD */
|
|
if ((pSd->cardType & CARD_TYPE_bmSDMMC) == CARD_TYPE_bmMMC
|
|
&& 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_TYPE_bmSDMMC) == CARD_TYPE_bmSD
|
|
&& SD_CSD_STRUCTURE(pSd) >= 1) {
|
|
pSd->blockNr = SD_CSD_BLOCKNR_HC(pSd);
|
|
pSd->totalSize = 0xFFFFFFFF;
|
|
}
|
|
/* Normal SD/MMC card */
|
|
else if (pSd->cardType & CARD_TYPE_bmSDMMC) {
|
|
pSd->totalSize = SD_CSD_TOTAL_SIZE(pSd);
|
|
pSd->blockNr = SD_CSD_BLOCKNR(pSd);
|
|
}
|
|
|
|
if (pSd->cardType == CARD_UNKNOWN) {
|
|
return SDMMC_ERROR_NOT_INITIALIZED;
|
|
}
|
|
/* Automatically select the max clock */
|
|
clock = SdmmcSetSpeed(pSd, pSd->transSpeed);
|
|
TRACE_WARNING_WP("-I- Set SD/MMC clock to %dK\n\r", clock/1000);
|
|
pSd->accSpeed = clock;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
uint8_t sdErrorCount = 0;
|
|
FATFS g_FATFS_Obj = { 0 };
|
|
|
|
void sdMountPoll()
|
|
{
|
|
#if 0
|
|
if (!Card_initialized)
|
|
return;
|
|
|
|
if (!CardIsConnected()) {
|
|
Card_state = SD_ST_EMPTY;
|
|
Sd_rca = 0;
|
|
sdErrorCount = 0;
|
|
}
|
|
|
|
switch (Card_state) {
|
|
case SD_ST_EMPTY:
|
|
if (CardIsConnected()) {
|
|
Card_state = SD_ST_INIT1;
|
|
}
|
|
break;
|
|
|
|
case SD_ST_INIT1:
|
|
sdCmd0();
|
|
Card_state = SD_ST_INIT2;
|
|
break;
|
|
|
|
case SD_ST_INIT2:
|
|
sdCmd8(1);
|
|
Card_state = SD_ST_IDLE;
|
|
break;
|
|
|
|
case SD_ST_IDLE:
|
|
sdMemInit(1, &Cmd_A41_resp);
|
|
Card_state = SD_ST_READY;
|
|
break;
|
|
|
|
case SD_ST_READY:
|
|
if (!sdCmd2()) Card_state = SD_ST_IDENT;
|
|
break;
|
|
|
|
case SD_ST_IDENT:
|
|
if (!sdCmd3()) Card_state = SD_ST_STBY;
|
|
break;
|
|
|
|
case SD_ST_STBY:
|
|
sdCmd9();
|
|
sdCmd7(); // Select Card
|
|
Card_state = SD_ST_TRAN;
|
|
break;
|
|
|
|
case SD_ST_TRAN:
|
|
sdAcmd51();
|
|
sdAcmd6(); // Set bus width to 4 bits, and speed to 9 MHz
|
|
// Should check the card can do this ****
|
|
Card_state = SD_ST_DATA;
|
|
break;
|
|
|
|
case SD_ST_DATA:
|
|
if (!usbPlugged() && f_mount(0, &g_FATFS_Obj) == FR_OK) {
|
|
refreshSystemAudioFiles();
|
|
Card_state = SD_ST_MOUNTED;
|
|
}
|
|
break;
|
|
|
|
case SD_ST_ERR:
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void sdInit()
|
|
{
|
|
Sd_rca = 0;
|
|
sdErrorCount = 0;
|
|
|
|
if (!CardIsConnected()) {
|
|
Card_state = SD_ST_EMPTY;
|
|
Card_initialized = 1;
|
|
return;
|
|
}
|
|
|
|
sdCmd0();
|
|
CoTickDelay(5); // 10ms
|
|
sdCmd8(1);
|
|
|
|
#if 0
|
|
uint8_t i;
|
|
uint32_t status;
|
|
for (i=0; i<100; i++)
|
|
sdCmd5(&status);
|
|
#endif
|
|
|
|
sdMemInit(1, &Cmd_A41_resp);
|
|
|
|
uint8_t retry;
|
|
for (retry=0; retry<10; retry++) {
|
|
if (!sdCmd2()) break;
|
|
CoTickDelay(1); // 2ms
|
|
}
|
|
|
|
if (retry == 10) {
|
|
Card_state = SD_ST_READY;
|
|
Card_initialized = 1;
|
|
return;
|
|
}
|
|
|
|
for (retry=0; retry<10; retry++) {
|
|
if (!sdCmd3()) break;
|
|
CoTickDelay(1); // 2ms
|
|
}
|
|
|
|
if (retry == 10) {
|
|
Card_state = SD_ST_IDENT;
|
|
Card_initialized = 1;
|
|
return;
|
|
}
|
|
|
|
sdCmd9();
|
|
sdCmd7(); // Select Card
|
|
|
|
sdAcmd51();
|
|
sdAcmd6(); // Set bus width to 4 bits, and speed to 9 MHz
|
|
|
|
// Should check the card can do this ****
|
|
Card_state = SD_ST_DATA;
|
|
|
|
if (f_mount(0, &g_FATFS_Obj) == FR_OK) {
|
|
refreshSystemAudioFiles();
|
|
Card_state = SD_ST_MOUNTED;
|
|
}
|
|
|
|
Card_initialized = 1;
|
|
}
|
|
|
|
// Checks for card ready for read/write
|
|
// returns 1 for YES, 0 for NO
|
|
uint32_t sd_card_ready( void )
|
|
{
|
|
return CardIsConnected() && Card_state >= SD_ST_DATA;
|
|
}
|
|
|
|
uint32_t sdMounted( void )
|
|
{
|
|
return CardIsConnected() && Card_state == SD_ST_MOUNTED;
|
|
}
|
|
|
|
uint32_t sd_read_block(uint32_t block_no, uint32_t *data)
|
|
{
|
|
unsigned int status = 0;
|
|
|
|
// TRACE_ERROR("read block %d", block_no);
|
|
|
|
if (sd_card_ready()) {
|
|
|
|
// Wait for card to be ready for data transfers
|
|
do {
|
|
sdCmd13(&status);
|
|
}
|
|
while (((status & STATUS_READY_FOR_DATA) == 0)
|
|
|| ((status & STATUS_STATE) != STATUS_TRAN) );
|
|
|
|
// Block size = 512, nblocks = 1
|
|
HSMCI->HSMCI_BLKR = ((512) << 16) | 1;
|
|
HSMCI->HSMCI_MR = (HSMCI->HSMCI_MR & (~(HSMCI_MR_BLKLEN_Msk|HSMCI_MR_FBYTE))) | (HSMCI_MR_PDCMODE|HSMCI_MR_WRPROOF|HSMCI_MR_RDPROOF) | (512 << 16);
|
|
HSMCI->HSMCI_ARGR = (Cmd_A41_resp & OCR_SD_CCS ? block_no : (block_no << 9));
|
|
HSMCI->HSMCI_RPR = (uint32_t)data;
|
|
HSMCI->HSMCI_RCR = 512 / 4;
|
|
HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTEN;
|
|
HSMCI->HSMCI_CMDR = SD_READ_SINGLE_BLOCK;
|
|
|
|
while (!(HSMCI->HSMCI_SR & HSMCI_SR_CMDRDY));
|
|
|
|
(void) HSMCI->HSMCI_RSPR[0];
|
|
|
|
while (1) {
|
|
if ((HSMCI->HSMCI_SR & (HSMCI_SR_ENDRX|HSMCI_SR_XFRDONE)) == (HSMCI_SR_ENDRX|HSMCI_SR_XFRDONE)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Disable PDC */
|
|
HSMCI->HSMCI_MR &= ~(uint32_t)HSMCI_MR_PDCMODE;
|
|
HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTDIS | HSMCI_PTCR_TXTDIS;
|
|
|
|
return 1;
|
|
}
|
|
|
|
// TRACE_ERROR("ok %.2X %.4Xd\n\r", HSMCI->HSMCI_SR, HSMCI->HSMCI_RSPR[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t sd_write_block( uint32_t block_no, uint32_t *data )
|
|
{
|
|
unsigned int status = 0;
|
|
|
|
if (sd_card_ready()) {
|
|
|
|
// TRACE_ERROR("write block %d", block_no);
|
|
|
|
// Wait for card to be ready for data transfers
|
|
do {
|
|
sdCmd13(&status);
|
|
} while ((status & STATUS_READY_FOR_DATA) == 0);
|
|
|
|
// Block size = 512, nblocks = 1
|
|
HSMCI->HSMCI_BLKR = ((512) << 16) | 1;
|
|
HSMCI->HSMCI_MR = (HSMCI->HSMCI_MR & (~(HSMCI_MR_BLKLEN_Msk|HSMCI_MR_FBYTE))) | (HSMCI_MR_PDCMODE|HSMCI_MR_WRPROOF) | (512 << 16);
|
|
HSMCI->HSMCI_ARGR = (Cmd_A41_resp & OCR_SD_CCS ? block_no : (block_no << 9));
|
|
HSMCI->HSMCI_TPR = (uint32_t)data;
|
|
HSMCI->HSMCI_TCR = 512 / 4;
|
|
HSMCI->HSMCI_CMDR = SD_WRITE_SINGLE_BLOCK;
|
|
|
|
while (!(HSMCI->HSMCI_SR & HSMCI_SR_CMDRDY));
|
|
|
|
(void) HSMCI->HSMCI_RSPR[0];
|
|
|
|
HSMCI->HSMCI_PTCR = HSMCI_PTCR_TXTEN;
|
|
|
|
while (1) {
|
|
if ((HSMCI->HSMCI_SR & (HSMCI_SR_NOTBUSY|HSMCI_SR_XFRDONE)) == (HSMCI_SR_NOTBUSY|HSMCI_SR_XFRDONE)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Disable PDC */
|
|
HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTDIS | HSMCI_PTCR_TXTDIS;
|
|
HSMCI->HSMCI_MR &= ~(uint32_t)HSMCI_MR_PDCMODE;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Notes on SD card:
|
|
|
|
1) CMD8 fails and CMD58 fails: must be MMC, thus initialize using CMD1
|
|
2) CMD8 fails and CMD58 passes: must be Ver1.x Standard Capacity SD Memory Card
|
|
3) CMD8 passes and CMD58 passes (CCS = 0): must be Ver2.00 or later Standard Capacity SD Memory Card
|
|
4) CMD8 passes and CMD58 passes (CCS = 1): must be Ver2.00 or later High Capacity SD Memory Card
|
|
5) CMD8 passes and CMD58 passes but indicates non compatible voltage range: unusable card
|
|
|
|
On card present
|
|
1. Send CMD 55 (resp 48bit)
|
|
followed by ACMD41 (resp48bit)
|
|
until bit 31 of response is '1'
|
|
|
|
2. Send CMD 2 (resp 136bit) - card ID
|
|
|
|
3. Send CMD 3 (resp 48 bit) - new RCA returned
|
|
|
|
4. Send CMD 9 (resp 136) - CSD
|
|
|
|
5. Send CMD 7 (resp 48) -
|
|
|
|
6. Send CMD 55 (resp 48bit)
|
|
followed by ACMD51 (resp48bit) - SCR stored as 2 32 bit values
|
|
|
|
Now decide what the card can do!
|
|
|
|
7. Set block length
|
|
|
|
8. Set bus width
|
|
|
|
9. Read block 0
|
|
|
|
*/
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Initialize Disk Drive */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
DSTATUS disk_initialize (
|
|
BYTE drv /* Physical drive nmuber (0) */
|
|
)
|
|
{
|
|
if (drv) return STA_NOINIT; /* Supports only single drive */
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
return RES_OK;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Get Disk Status */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
DSTATUS disk_status (
|
|
BYTE drv /* Physical drive number (0) */
|
|
)
|
|
{
|
|
if (drv) return STA_NOINIT; /* Supports only single drive */
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
return RES_OK;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Read Sector(s) */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
uint32_t dma_sd_buffer[512/4];
|
|
|
|
DRESULT disk_read (
|
|
BYTE drv, /* Physical drive nmuber (0) */
|
|
BYTE *buff, /* Pointer to the data buffer to store read data */
|
|
DWORD sector, /* Start sector number (LBA) */
|
|
BYTE count /* Sector count (1..255) */
|
|
)
|
|
{
|
|
uint32_t result ;
|
|
|
|
if (drv || !count) return RES_PARERR;
|
|
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
|
|
do {
|
|
result = sd_read_block(sector, dma_sd_buffer) ;
|
|
if (result) {
|
|
memcpy(buff, dma_sd_buffer, 512);
|
|
sector += 1 ;
|
|
buff += 512 ;
|
|
count -= 1 ;
|
|
}
|
|
else {
|
|
count = 1 ; // Flag error
|
|
break ;
|
|
}
|
|
} while ( count ) ;
|
|
|
|
if (!count)
|
|
return RES_OK;
|
|
|
|
if (++sdErrorCount > 3)
|
|
Card_state = SD_ST_ERR;
|
|
|
|
return RES_ERROR;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Write Sector(s) */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
extern const char * s_warning;
|
|
|
|
DRESULT disk_write (
|
|
BYTE drv, /* Physical drive nmuber (0) */
|
|
const BYTE *buff, /* Pointer to the data to be written */
|
|
DWORD sector, /* Start sector number (LBA) */
|
|
BYTE count /* Sector count (1..255) */
|
|
)
|
|
{
|
|
uint32_t result ;
|
|
|
|
if (drv || !count) return RES_PARERR;
|
|
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
|
|
do {
|
|
|
|
while (1) {
|
|
|
|
memcpy(dma_sd_buffer, buff, 512);
|
|
|
|
result = sd_write_block(sector, dma_sd_buffer) ;
|
|
|
|
sd_read_block(sector, dma_sd_buffer) ;
|
|
|
|
if (!memcmp(dma_sd_buffer, buff, 512))
|
|
break;
|
|
else {
|
|
TRACE_ERROR("Block %d ko SR=%.2X\r\n", sector, HSMCI->HSMCI_SR);
|
|
// DUMP(buff, 512);
|
|
// DUMP(copy, 512);
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
sector += 1 ;
|
|
buff += 512 ;
|
|
count -= 1 ;
|
|
}
|
|
else {
|
|
count = 1 ; // Flag error
|
|
break ;
|
|
}
|
|
} while ( count ) ;
|
|
|
|
if (!count)
|
|
return RES_OK;
|
|
|
|
if (++sdErrorCount > 3)
|
|
Card_state = SD_ST_ERR;
|
|
|
|
return RES_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Miscellaneous Functions */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
DRESULT disk_ioctl (
|
|
BYTE drv, /* Physical drive nmuber (0) */
|
|
BYTE ctrl, /* Control code */
|
|
void *buff /* Buffer to send/receive control data */
|
|
)
|
|
{
|
|
DRESULT res;
|
|
|
|
if (drv) return RES_PARERR;
|
|
|
|
res = RES_ERROR;
|
|
|
|
if (ctrl == CTRL_POWER) {
|
|
#if 0
|
|
switch (ptr[0]) {
|
|
case 0: /* Sub control code (POWER_OFF) */
|
|
power_off(); /* Power off */
|
|
res = RES_OK;
|
|
break;
|
|
case 1: /* Sub control code (POWER_GET) */
|
|
ptr[1] = (BYTE)power_status();
|
|
res = RES_OK;
|
|
break;
|
|
default :
|
|
res = RES_PARERR;
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
switch (ctrl) {
|
|
case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
|
*(DWORD*)buff = SD_GET_BLOCKNR();
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
|
|
*(WORD*)buff = 512;
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
|
|
*(WORD*)buff = 1;
|
|
res = RES_OK;
|
|
break;
|
|
|
|
#if 0
|
|
case MMC_GET_TYPE : /* Get card type flags (1 byte) */
|
|
*ptr = CardType;
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
|
|
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
|
|
&& rcvr_datablock(ptr, 16))
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
|
|
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
|
|
&& rcvr_datablock(ptr, 16))
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
|
|
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
|
|
for (n = 4; n; n--) *ptr++ = rcvr_spi();
|
|
res = RES_OK;
|
|
}
|
|
break;
|
|
|
|
case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
|
|
if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
|
|
rcvr_spi();
|
|
if (rcvr_datablock(ptr, 64))
|
|
res = RES_OK;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
res = RES_PARERR;
|
|
break;
|
|
}
|
|
|
|
// BSS deselect();
|
|
}
|
|
|
|
return res;
|
|
}
|