718 lines
12 KiB
C

#include <includes.h>
#include "sdcard.h"
#include "spi1.h"
#ifdef CONFIG_SDCARD_ENABLE
#define CAP_VER2_00 (1<<0)
#define CAP_SDHC (1<<1)
#define SD_CS_SET() {spi1_unselectChip(SPI1_CS_SD_CARD);}
#define SD_CS_CLR() {spi1_selectChip(SPI1_CS_SD_CARD);}
#define SD_SPI_PEND() {spi1_getSem();}
#define SD_SPI_POST() {spi1_freeSem();}
#define spi_txrx spi1_exchange
///
typedef struct
{
int initialized;
int sectors;
int erase_sectors;
int capabilities;
} HwInfo;
static HwInfo hw_info;
typedef enum
{
SD_SPEED_INVALID,
SD_SPEED_400KHZ,
SD_SPEED_10MHZ
} SdSpeed;
static void spi_set_speed(SdSpeed speed)
{
if (speed == SD_SPEED_400KHZ)
{
spi1_setSpeed(400000);
}
else if (speed == SD_SPEED_10MHZ)
{
spi1_setSpeed(10000000);
}
}
///
static uint8_t crc7_one(uint8_t t, uint8_t data)
{
int i;
const uint8_t g = 0x89;
t ^= data;
for (i=0; i<8; i++) {
if (t & 0x80)
t ^= g;
t <<= 1;
}
return t;
}
///
uint8_t crc7(const uint8_t *p, int len)
{
int j;
uint8_t crc = 0;
for (j=0; j<len; j++)
crc = crc7_one(crc, p[j]);
return crc>>1;
}
///
static uint16_t crc16_ccitt(uint16_t crc, uint8_t ser_data)
{
crc = (uint8_t)(crc >> 8) | (crc << 8);
crc ^= ser_data;
crc ^= (uint8_t)(crc & 0xff) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xff) << 4) << 1;
return crc;
}
///
static uint16_t crc16(const uint8_t *p, int len)
{
int i;
uint16_t crc = 0;
for (i=0; i<len; i++)
crc = crc16_ccitt(crc, p[i]);
return crc;
}
///
static void sd_cmd(uint8_t cmd, uint32_t arg)
{
uint8_t crc = 0;
spi_txrx(0x40 | cmd);
crc = crc7_one(crc, 0x40 | cmd);
spi_txrx(arg >> 24);
crc = crc7_one(crc, arg >> 24);
spi_txrx(arg >> 16);
crc = crc7_one(crc, arg >> 16);
spi_txrx(arg >> 8);
crc = crc7_one(crc, arg >> 8);
spi_txrx(arg);
crc = crc7_one(crc, arg);
spi_txrx(crc | 0x1); /* crc7, for cmd0 */
}
static uint8_t sd_get_r1()
{
int tries = 1000;
uint8_t r;
while (tries--) {
r = spi_txrx(0xff);
if ((r & 0x80) == 0)
return r;
}
return 0xff;
}
static uint16_t sd_get_r2()
{
int tries = 1000;
uint16_t r;
while (tries--) {
r = spi_txrx(0xff);
if ((r & 0x80) == 0)
break;
}
if (tries < 0)
return 0xff;
r = r<<8 | spi_txrx(0xff);
return r;
}
/// r1, then 32-bit reply... same format as r3
static uint8_t sd_get_r7(uint32_t *r7)
{
uint32_t r;
r = sd_get_r1();
if (r != 0x01)
return r;
r = spi_txrx(0xff) << 24;
r |= spi_txrx(0xff) << 16;
r |= spi_txrx(0xff) << 8;
r |= spi_txrx(0xff);
*r7 = r;
return 0x01;
}
#define sd_get_r3 sd_get_r7
/// Nec (=Ncr? which is limited to [0,8]) dummy bytes before lowering CS, as described in sandisk doc, 5.4.
static void sd_nec()
{
int i;
for (i=0; i<8; i++)
spi_txrx(0xff);
}
/// SD card initialization
/// returns 0 if OK
static int sd_guts_init(void)
{
int i;
int r;
uint32_t r7;
uint32_t r3;
int tries;
uint32_t hcs;
// start with 100-400 kHz clock
spi_set_speed(SD_SPEED_400KHZ);
hw_info.capabilities = 0;
// cmd0 - reset..
SD_CS_SET();
// 74+ clocks with CS high
for (i=0; i<10; i++) spi_txrx(0xff);
// reset
SD_CS_CLR();
sd_cmd(0, 0);
r = sd_get_r1();
sd_nec();
SD_CS_SET();
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
if (r != 0x01)
{
// fail
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
// cmd8 - voltage..
// ask about voltage supply
SD_CS_CLR();
sd_cmd(8, 0x1aa); // VHS = 1
r = sd_get_r7(&r7);
sd_nec();
SD_CS_SET();
hw_info.capabilities |= CAP_VER2_00;
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
if (r == 0x01)
{
// success, SD v2.x
}
else if (r & 0x4)
{
// not implemented, SD v1.x
hw_info.capabilities &= ~CAP_VER2_00;
}
else
{
// fail
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
// cmd58 - ocr..
// ask about voltage supply
SD_CS_CLR();
sd_cmd(58, 0);
r = sd_get_r3(&r3);
sd_nec();
SD_CS_SET();
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
if (r != 0x01 && !(r & 0x4))
{
// allow it to not be implemented - old cards
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
// cmd41 - hcs..
tries = 1000;
hcs = 0;
// say we support SDHC
if (hw_info.capabilities & CAP_VER2_00)
hcs = 1<<30;
// needs to be polled until in_idle_state becomes 0
do
{
// send we don't support SDHC
SD_CS_CLR();
// next cmd is ACMD
sd_cmd(55, 0);
r = sd_get_r1();
sd_nec();
SD_CS_SET();
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
// well... it's probably not idle here, but specs aren't clear
if (r & 0xfe)
{
// fail
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
SD_CS_CLR();
sd_cmd(41, hcs);
r = sd_get_r1();
sd_nec();
SD_CS_SET();
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
if (r & 0xfe)
{
// fail
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
} while (r != 0 && tries--);
if (tries == -1)
{
// timeouted
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
// Seems after this card is initialized which means bit 0 of R1 will be cleared. Not too sure.
if (hw_info.capabilities & CAP_VER2_00)
{
// cmd58 - ocr, 2nd time...
// ask about voltage supply
SD_CS_CLR();
sd_cmd(58, 0);
r = sd_get_r3(&r3);
sd_nec();
SD_CS_SET();
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
if (r & 0xfe)
{
// fail
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
else
{
if (r3>>30 & 1)
{
hw_info.capabilities |= CAP_SDHC;
}
}
}
// with SDHC block length is fixed to 1024
if ((hw_info.capabilities & CAP_SDHC) == 0)
{
// cmd16 - block length...
SD_CS_CLR();
sd_cmd(16, 512);
r = sd_get_r1();
sd_nec();
SD_CS_SET();
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
if (r & 0xfe)
{
// fail
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
}
// cmd59 - enable crc...
// crc on
SD_CS_CLR();
sd_cmd(59, 0);
r = sd_get_r1();
sd_nec();
SD_CS_SET();
if (r == 0xff)
{
spi_set_speed(SD_SPEED_10MHZ);
return -1;
}
if (r & 0xfe)
{
// fail
spi_set_speed(SD_SPEED_10MHZ);
return -2;
}
// now we can up the clock to <= 25 MHz
spi_set_speed(SD_SPEED_10MHZ);
return 0;
}
///
static int sd_read_status(void)
{
uint16_t r2;
SD_CS_CLR();
sd_cmd(13, 0);
r2 = sd_get_r2();
sd_nec();
SD_CS_SET();
if (r2 & 0x8000)
return -1;
return 0;
}
// 0xfe marks data start, then len bytes of data and crc16
static int sd_get_data(uint8_t *buf, int len)
{
int tries = 20000;
uint8_t r;
uint16_t _crc16;
uint16_t calc_crc;
int i;
while (tries--) {
r = spi_txrx(0xff);
if (r == 0xfe)
break;
}
if (tries < 0)
return -1;
for (i=0; i<len; i++)
buf[i] = spi_txrx(0xff);
_crc16 = spi_txrx(0xff) << 8;
_crc16 |= spi_txrx(0xff);
calc_crc = crc16(buf, len);
if (_crc16 != calc_crc)
{
return -1;
}
return 0;
}
static int sd_put_data(const uint8_t *buf, int len)
{
uint8_t r;
int tries = 10;
volatile uint8_t b[16];
int bi = 0;
uint16_t crc;
// data start
spi_txrx(0xfe);
while (len--)
spi_txrx(*buf++);
crc = crc16(buf, len);
// crc16
spi_txrx(crc>>8);
spi_txrx(crc);
// normally just one dummy read in between... specs don't say how many
while (tries--)
{
b[bi++] = r = spi_txrx(0xff);
if (r != 0xff)
break;
}
if (tries < 0)
return -1;
// poll busy, about 300 reads for 256 MB card
tries = 100000;
while (tries--)
{
if (spi_txrx(0xff) == 0xff)
break;
}
if (tries < 0)
return -2;
// data accepted, WIN
if ((r & 0x1f) == 0x05)
return 0;
return r;
}
static int sd_read_csd(void)
{
uint8_t buf[16];
int r;
int capacity;
SD_CS_CLR();
sd_cmd(9, 0);
r = sd_get_r1();
if (r == 0xff)
{
SD_CS_SET();
return -1;
}
if (r & 0xfe)
{
SD_CS_SET();
return -2;
}
r = sd_get_data(buf, 16);
sd_nec();
SD_CS_SET();
if (r < 0)
{
// failed to get csd
return -3;
}
if ((buf[0] >> 6) + 1 == 1)
{
// CSD v1
capacity = (((buf[6]&0x3)<<10 | buf[7]<<2 | buf[8]>>6)+1) << (2+(((buf[9]&3) << 1) | buf[10]>>7)) << ((buf[5] & 0xf) - 9);
}
else
{
// CSD v2
// this means the card is HC
hw_info.capabilities |= CAP_SDHC;
capacity = buf[7]<<16 | buf[8]<<8 | buf[9]; // in 512 kB
capacity *= 1024; // in 512 B sectors
}
hw_info.sectors = capacity;
// if erase_blk_en = 0, then only this many sectors can be erased at once this is NOT yet tested
hw_info.erase_sectors = 1;
if (((buf[10]>>6)&1) == 0)
hw_info.erase_sectors = ((buf[10]&0x3f)<<1 | buf[11]>>7) + 1;
return 0;
}
static int sd_read_cid(void)
{
uint8_t buf[16];
int r;
SD_CS_CLR();
sd_cmd(10, 0);
r = sd_get_r1();
if (r == 0xff)
{
SD_CS_SET();
return -1;
}
if (r & 0xfe)
{
SD_CS_SET();
return -2;
}
r = sd_get_data(buf, 16);
sd_nec();
SD_CS_SET();
if (r < 0)
{
// failed to get cid
return -3;
}
return 0;
}
/// Read 1 sector (512 bytes)
/// address - sector number
int sd_readsector(uint32_t address, uint8_t *buf)
{
int r;
SD_SPI_PEND();
SD_CS_CLR();
if (hw_info.capabilities & CAP_SDHC)
sd_cmd(17, address); // read single block
else
sd_cmd(17, address*512); // read single block
r = sd_get_r1();
if (r == 0xff)
{
SD_CS_SET();
r = -1;
SD_SPI_POST();
return -1;
}
if (r & 0xfe)
{
SD_CS_SET();
SD_SPI_POST();
return -2;
}
r = sd_get_data(buf, 512);
sd_nec();
SD_CS_SET();
if (r < 0)
{
SD_SPI_POST();
return -3;
}
SD_SPI_POST();
return 0;
}
/// Write 1 sector (512 bytes)
/// address - sector number
int sd_writesector(uint32_t address, const uint8_t *buf)
{
int r;
SD_SPI_PEND();
SD_CS_CLR();
if (hw_info.capabilities & CAP_SDHC)
sd_cmd(24, address); // write block
else
sd_cmd(24, address*512); // write block
r = sd_get_r1();
if (r == 0xff)
{
SD_CS_SET();
SD_SPI_POST();
return -1;
}
if (r & 0xfe)
{
SD_CS_SET();
SD_SPI_POST();
return -2;
}
spi_txrx(0xff); // Nwr (>= 1) high bytes
r = sd_put_data(buf, 512);
sd_nec();
SD_CS_SET();
if (r != 0)
{
SD_SPI_POST();
return r;
}
SD_SPI_POST();
return 0;
}
/// SD card full initialization
int sd_init(void)
{
int tries = 10;
SD_SPI_PEND();
hw_info.initialized = 0;
while (tries--)
{
if (sd_guts_init() == 0)
break;
}
if (tries == -1)
{
SD_SPI_POST();
return -1;
}
// read status register
sd_read_status();
sd_read_cid();
if (sd_read_csd() != 0)
{
SD_SPI_POST();
return -1;
}
hw_info.initialized = 1;
SD_SPI_POST();
return 0;
}
/// get sector count
int sd_get_sector_count(void)
{
if (hw_info.initialized) return hw_info.sectors;
return 0;
}
#endif