/****************************************************************************** | |
* | |
* mmc_decode_cid() and sd_decode_csd() | |
* | |
* analyse the meta data of an SD-card to read its capacity and some other properties. | |
* | |
* CID and CSD Analysis borrowed from the Linux kernel. | |
* | |
******************************************************************************/ | |
#include "xsdps.h" | |
#include "xparameters.h" | |
#include "xil_cache.h" | |
#include "ff_headers.h" | |
#include "xsdps_info.h" | |
struct mmc_cid myCID; | |
struct mmc_csd myCSD; | |
u32 UNSTUFF_BITS( u32 *ulResponse, int iFirst, int iSize ) | |
{ | |
const u32 ulMask = ( iSize < 32 ? ( 1 << iSize ) : 0 ) - 1; | |
const int iOffset = 3 - ( iFirst / 32); | |
const int iShiftCount = iFirst & 31; | |
u32 ulResult; | |
ulResult = ulResponse[ iOffset ] >> iShiftCount; | |
if( iSize + iShiftCount > 32 ) | |
{ | |
ulResult |= ulResponse[ iOffset - 1 ] << ( ( 32 - iShiftCount ) % 32 ); | |
} | |
return ulResult & ulMask; \ | |
} | |
int mmc_decode_cid( const struct mmc_csd *pxCSD, struct mmc_cid *pxCID, u32 *ulResponse ) | |
{ | |
int iResult = 0; | |
/* | |
* The selection of the format here is based upon published | |
* specs from sandisk and from what people have reported. | |
*/ | |
switch( pxCSD->mmca_vsn ) | |
{ | |
case 0: /* MMC v1.0 - v1.2 */ | |
case 1: /* MMC v1.4 */ | |
pxCID->manfid = UNSTUFF_BITS( ulResponse, 104, 24 ); | |
pxCID->prod_name[ 0 ] = UNSTUFF_BITS( ulResponse, 96, 8 ); | |
pxCID->prod_name[ 1 ] = UNSTUFF_BITS( ulResponse, 88, 8 ); | |
pxCID->prod_name[ 2 ] = UNSTUFF_BITS( ulResponse, 80, 8 ); | |
pxCID->prod_name[ 3 ] = UNSTUFF_BITS( ulResponse, 72, 8 ); | |
pxCID->prod_name[ 4 ] = UNSTUFF_BITS( ulResponse, 64, 8 ); | |
pxCID->prod_name[ 5 ] = UNSTUFF_BITS( ulResponse, 56, 8 ); | |
pxCID->prod_name[ 6 ] = UNSTUFF_BITS( ulResponse, 48, 8 ); | |
pxCID->hwrev = UNSTUFF_BITS( ulResponse, 44, 4 ); | |
pxCID->fwrev = UNSTUFF_BITS( ulResponse, 40, 4 ); | |
pxCID->serial = UNSTUFF_BITS( ulResponse, 16, 24 ); | |
pxCID->month = UNSTUFF_BITS( ulResponse, 12, 4 ); | |
pxCID->year = UNSTUFF_BITS( ulResponse, 8, 4 ) + 1997; | |
break; | |
case 2: /* MMC v2.0 - v2.2 */ | |
case 3: /* MMC v3.1 - v3.3 */ | |
case 4: /* MMC v4 */ | |
pxCID->manfid = UNSTUFF_BITS( ulResponse, 120, 8 ); | |
pxCID->oemid = UNSTUFF_BITS( ulResponse, 104, 16 ); | |
pxCID->prod_name[ 0 ] = UNSTUFF_BITS( ulResponse, 96, 8 ); | |
pxCID->prod_name[ 1 ] = UNSTUFF_BITS( ulResponse, 88, 8 ); | |
pxCID->prod_name[ 2 ] = UNSTUFF_BITS( ulResponse, 80, 8 ); | |
pxCID->prod_name[ 3 ] = UNSTUFF_BITS( ulResponse, 72, 8 ); | |
pxCID->prod_name[ 4 ] = UNSTUFF_BITS( ulResponse, 64, 8 ); | |
pxCID->prod_name[ 5 ] = UNSTUFF_BITS( ulResponse, 56, 8 ); | |
pxCID->serial = UNSTUFF_BITS( ulResponse, 16, 32 ); | |
pxCID->month = UNSTUFF_BITS( ulResponse, 12, 4 ); | |
pxCID->year = UNSTUFF_BITS( ulResponse, 8, 4 ) + 1997; | |
break; | |
default: | |
FF_PRINTF ("mmc_decode_cid: card has unknown MMCA version %d\n", | |
pxCSD->mmca_vsn); | |
iResult = -1; | |
break; | |
} | |
if( iResult >= 0 ) | |
{ | |
FF_PRINTF ("CID: Manfid %lu (%-8.8s) serial %lu oem %u mon/year %u/%u rev %u fw %u\n", | |
pxCID->manfid, | |
pxCID->prod_name, | |
pxCID->serial, | |
pxCID->oemid, | |
pxCID->month, | |
pxCID->year, | |
pxCID->hwrev, | |
pxCID->fwrev); | |
} | |
return iResult; | |
} | |
static const unsigned int tran_exp[] = | |
{ | |
10000, 100000, 1000000, 10000000, | |
0, 0, 0, 0 | |
}; | |
static const unsigned char tran_mant[] = | |
{ | |
0, 10, 12, 13, 15, 20, 25, 30, | |
35, 40, 45, 50, 55, 60, 70, 80, | |
}; | |
static const unsigned int tacc_exp[] = | |
{ | |
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, | |
}; | |
static const unsigned int tacc_mant[] = | |
{ | |
0, 10, 12, 13, 15, 20, 25, 30, | |
35, 40, 45, 50, 55, 60, 70, 80, | |
}; | |
char mmc_is_block_addressed; | |
/* Given a 128-bit response, decode to our card CSD structure. */ | |
static __inline unsigned tobe32( unsigned value ) | |
{ | |
return | |
( value >> 24 ) | | |
( ( value >> 8 ) & 0x0000ff00 ) | | |
( ( value << 8 ) & 0x00ff0000 ) | | |
( value << 24 ); | |
} | |
int sd_decode_csd( struct mmc_csd *pxCSD, u32 *ulResponse ) | |
{ | |
unsigned int e, m, csd_struct; | |
int iResult = 0; | |
csd_struct = UNSTUFF_BITS( ulResponse, 126, 2 ); | |
pxCSD->mmca_vsn = UNSTUFF_BITS( ulResponse, 122, 4 ); | |
FF_PRINTF("CSD data: %08x %08x %08x %08x mmca_vsn = %u\n", | |
( unsigned )ulResponse[0], | |
( unsigned )ulResponse[1], | |
( unsigned )ulResponse[2], | |
( unsigned )ulResponse[3], | |
pxCSD->mmca_vsn); | |
// pxCSD->mmca_vsn = 2; | |
// CSD data: 005e0032 5f5a83cb 2db7ffbf 9680000f | |
// sd_decode_csd: capacity 1989120 (byte addressed) | |
switch (csd_struct) { | |
case 0: | |
m = UNSTUFF_BITS( ulResponse, 115, 4 ); | |
e = UNSTUFF_BITS( ulResponse, 112, 3 ); | |
pxCSD->tacc_ns = ( tacc_exp[ e ] * tacc_mant[ m ] + 9 ) / 10; | |
pxCSD->tacc_clks = UNSTUFF_BITS( ulResponse, 104, 8 ) * 100; | |
m = UNSTUFF_BITS( ulResponse, 99, 4 ); | |
e = UNSTUFF_BITS( ulResponse, 96, 3 ); | |
pxCSD->max_dtr = tran_exp[ e ] * tran_mant[ m ]; | |
pxCSD->cmdclass = UNSTUFF_BITS( ulResponse, 84, 12 ); | |
e = UNSTUFF_BITS( ulResponse, 47, 3 ); | |
m = UNSTUFF_BITS( ulResponse, 62, 12 ); | |
pxCSD->capacity = ( 1 + m ) << ( e + 2 ); | |
/* | |
* The CSD capacity field is in units of read_blkbits. | |
* set_capacity takes units of 512 bytes. | |
*/ | |
pxCSD->read_blkbits = UNSTUFF_BITS( ulResponse, 80, 4 ); | |
pxCSD->read_partial = UNSTUFF_BITS( ulResponse, 79, 1 ); | |
pxCSD->write_misalign = UNSTUFF_BITS( ulResponse, 78, 1 ); | |
pxCSD->read_misalign = UNSTUFF_BITS( ulResponse, 77, 1 ); | |
pxCSD->r2w_factor = UNSTUFF_BITS( ulResponse, 26, 3 ); | |
pxCSD->write_blkbits = UNSTUFF_BITS( ulResponse, 22, 4 ); | |
pxCSD->write_partial = UNSTUFF_BITS( ulResponse, 21, 1 ); | |
pxCSD->capacity <<= ( pxCSD->read_blkbits - 9 ); | |
FF_PRINTF ("Capacity: (%u + 1) << (%u + 2) = %u Rd/Wr bits %u/%u\n", | |
m, e, | |
( unsigned )pxCSD->capacity, | |
( unsigned )pxCSD->read_blkbits, | |
( unsigned )pxCSD->write_blkbits); | |
if( UNSTUFF_BITS( ulResponse, 46, 1 ) ) | |
{ | |
pxCSD->erase_size = 1; | |
} | |
else if( pxCSD->write_blkbits >= 9 ) | |
{ | |
pxCSD->erase_size = UNSTUFF_BITS( ulResponse, 39, 7 ) + 1; | |
pxCSD->erase_size <<= pxCSD->write_blkbits - 9; | |
} | |
else | |
{ | |
pxCSD->erase_size = 0; // Card is not eraseble | |
} | |
break; | |
case 1: | |
/* | |
* This is a block-addressed SDHC card. Most | |
* interesting fields are unused and have fixed | |
* values. To avoid getting tripped by buggy cards, | |
* we assume those fixed values ourselves. | |
*/ | |
mmc_is_block_addressed = 1; | |
pxCSD->tacc_ns = 0; /* Unused */ | |
pxCSD->tacc_clks = 0; /* Unused */ | |
m = UNSTUFF_BITS( ulResponse, 99, 4 ); | |
e = UNSTUFF_BITS( ulResponse, 96, 3 ); | |
// max_dtr gives 25,000,000 | |
pxCSD->max_dtr = tran_exp[ e ] * tran_mant[ m ]; | |
// cmdClass gives: 10110110101 (0x5B5) | |
pxCSD->cmdclass = UNSTUFF_BITS( ulResponse, 84, 12 ); | |
m = UNSTUFF_BITS( ulResponse, 48, 22 ); | |
pxCSD->capacity = ( 1 + m ) << 10; | |
FF_PRINTF( "capacity: (1 + %u) << 10 DTR %u Mhz\n", m, pxCSD->max_dtr / 1000000); | |
pxCSD->read_blkbits = 9; | |
pxCSD->read_partial = 0; | |
pxCSD->write_misalign = 0; | |
pxCSD->read_misalign = 0; | |
pxCSD->r2w_factor = 4; /* Unused */ | |
pxCSD->write_blkbits = 9; | |
pxCSD->write_partial = 0; | |
pxCSD->erase_size = 1; | |
break; | |
default: | |
FF_PRINTF ("sd_decode_csd: unrecognised CSD structure version %d\n", csd_struct); | |
iResult = -1; | |
break; | |
} | |
if( iResult >= 0 ) | |
{ | |
unsigned int sz; | |
FF_PRINTF ("sd_decode_csd: capacity %lu (%s addressed)\n", | |
pxCSD->capacity, mmc_is_block_addressed ? "block" : "byte"); | |
sz = (pxCSD->capacity << (pxCSD->read_blkbits - 9)) >> 11; | |
if (sz < 128) | |
{ | |
pxCSD->pref_erase = 512 * 1024 / 512; | |
} | |
else if (sz < 512) | |
{ | |
pxCSD->pref_erase = 1024 * 1024 / 512; | |
} | |
else if (sz < 1024) | |
{ | |
pxCSD->pref_erase = 2 * 1024 * 1024 / 512; | |
} | |
else | |
{ | |
pxCSD->pref_erase = 4 * 1024 * 1024 / 512; | |
} | |
if (pxCSD->pref_erase < pxCSD->erase_size) | |
{ | |
pxCSD->pref_erase = pxCSD->erase_size; | |
} | |
else | |
{ | |
sz = ( pxCSD->pref_erase % pxCSD->erase_size ); | |
if( sz != 0 ) | |
{ | |
pxCSD->pref_erase += ( pxCSD->erase_size - sz ); | |
} | |
} | |
// compute last block addr | |
pxCSD->sd_last_block_address = pxCSD->capacity - 1; | |
// compute card capacity in bytes | |
pxCSD->capacity_bytes = ( ( uint64_t )XSDPS_BLK_SIZE_512_MASK ) * pxCSD->capacity; | |
FF_PRINTF( "sd_mmc_spi_get_capacity: Capacity %lu MB Erase %u Pref %lu\n", | |
( uint32_t ) ( pxCSD->capacity_bytes / ( 1024LLU * 1024LLU ) ), | |
pxCSD->erase_size, | |
pxCSD->pref_erase ); | |
} | |
return iResult; | |
} |