SD driver: use CMD6 command to switch the card into high-speed mode.
This commit is contained in:
100
sys/pic32/sd.c
100
sys/pic32/sd.c
@@ -59,11 +59,14 @@
|
||||
#define SECTSIZE 512
|
||||
#define SPI_ENHANCED /* use SPI fifo */
|
||||
#ifndef SD_MHZ
|
||||
#define SD_MHZ 13 /* speed 13.33 MHz */
|
||||
#define SD_MHZ 12 /* set 12.5Mhz; really 13.33MHz */
|
||||
#endif
|
||||
#ifndef SD_FAST_MHZ
|
||||
#define SD_FAST_MHZ 25 /* up to 25Mhz is allowed by the spec */
|
||||
#endif
|
||||
|
||||
#define TIMO_WAIT_WDONE 400000
|
||||
#define TIMO_WAIT_WIDLE 200000
|
||||
#define TIMO_WAIT_WIDLE 300000
|
||||
#define TIMO_WAIT_CMD 100000
|
||||
#define TIMO_WAIT_WDATA 30000
|
||||
#define TIMO_READ 90000
|
||||
@@ -101,6 +104,9 @@ struct disk {
|
||||
int label_writable; /* is sector 0 writable? */
|
||||
int dkindex; /* disk index for statistics */
|
||||
u_int openpart; /* all partitions open on this drive */
|
||||
u_char ocr[4]; /* operation condition register */
|
||||
u_char csd[16]; /* card-specific data */
|
||||
int ma; /* power consumption */
|
||||
};
|
||||
|
||||
struct disk sddrives[NSD]; /* Table of units */
|
||||
@@ -120,6 +126,7 @@ int sd_timo_wait_widle;
|
||||
*/
|
||||
#define CMD_GO_IDLE 0 /* CMD0 */
|
||||
#define CMD_SEND_OP_MMC 1 /* CMD1 (MMC) */
|
||||
#define CMD_SWITCH_FUNC 6
|
||||
#define CMD_SEND_IF_COND 8
|
||||
#define CMD_SEND_CSD 9
|
||||
#define CMD_SEND_CID 10
|
||||
@@ -239,7 +246,6 @@ static int card_cmd(unsigned int unit, unsigned int cmd, unsigned int addr)
|
||||
static int card_init(int unit)
|
||||
{
|
||||
int i, reply;
|
||||
unsigned char response[4];
|
||||
int timeout = 4;
|
||||
struct spiio *io = &sddrives[unit].spiio;
|
||||
struct disk *du = &sddrives[unit];
|
||||
@@ -279,6 +285,7 @@ static int card_init(int unit)
|
||||
card_release(io);
|
||||
du->card_type = TYPE_SD_LEGACY;
|
||||
} else {
|
||||
u_char response[4];
|
||||
response[0] = spi_transfer(io, 0xFF);
|
||||
response[1] = spi_transfer(io, 0xFF);
|
||||
response[2] = spi_transfer(io, 0xFF);
|
||||
@@ -324,17 +331,16 @@ static int card_init(int unit)
|
||||
printf("sd%d: READ_OCR failed, reply=%02x\n", unit, reply);
|
||||
return 0;
|
||||
}
|
||||
response[0] = spi_transfer(io, 0xFF);
|
||||
response[1] = spi_transfer(io, 0xFF);
|
||||
response[2] = spi_transfer(io, 0xFF);
|
||||
response[3] = spi_transfer(io, 0xFF);
|
||||
du->ocr[0] = spi_transfer(io, 0xFF);
|
||||
du->ocr[1] = spi_transfer(io, 0xFF);
|
||||
du->ocr[2] = spi_transfer(io, 0xFF);
|
||||
du->ocr[3] = spi_transfer(io, 0xFF);
|
||||
card_release(io);
|
||||
if ((response[0] & 0xC0) == 0xC0)
|
||||
if ((du->ocr[0] & 0xC0) == 0xC0)
|
||||
{
|
||||
du->card_type = TYPE_SDHC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fast speed. */
|
||||
spi_brg(io, SD_MHZ * 1000);
|
||||
return 1;
|
||||
@@ -346,11 +352,11 @@ static int card_init(int unit)
|
||||
*/
|
||||
static int card_size(int unit)
|
||||
{
|
||||
unsigned char csd [16];
|
||||
unsigned csize, n;
|
||||
int reply, i;
|
||||
int nsectors;
|
||||
struct spiio *io = &sddrives[unit].spiio;
|
||||
struct disk *du = &sddrives[unit];
|
||||
|
||||
spi_select(io);
|
||||
reply = card_cmd(unit, CMD_SEND_CSD, 0);
|
||||
@@ -377,8 +383,8 @@ static int card_size(int unit)
|
||||
sd_timo_send_csd = i;
|
||||
|
||||
/* Read data. */
|
||||
for (i=0; i<sizeof(csd); i++) {
|
||||
csd [i] = spi_transfer(io, 0xFF);
|
||||
for (i=0; i<16; i++) {
|
||||
du->csd[i] = spi_transfer(io, 0xFF);
|
||||
}
|
||||
/* Ignore CRC. */
|
||||
spi_transfer(io, 0xFF);
|
||||
@@ -389,14 +395,16 @@ static int card_size(int unit)
|
||||
|
||||
/* CSD register has different structure
|
||||
* depending upon protocol version. */
|
||||
switch (csd[0] >> 6) {
|
||||
switch (du->csd[0] >> 6) {
|
||||
case 1: /* SDC ver 2.00 */
|
||||
csize = csd[9] + (csd[8] << 8) + 1;
|
||||
csize = du->csd[9] + (du->csd[8] << 8) + 1;
|
||||
nsectors = csize << 10;
|
||||
break;
|
||||
case 0: /* SDC ver 1.XX or MMC. */
|
||||
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
||||
csize = (csd[8] >> 6) + (csd[7] << 2) + ((csd[6] & 3) << 10) + 1;
|
||||
n = (du->csd[5] & 15) + ((du->csd[10] & 128) >> 7) +
|
||||
((du->csd[9] & 3) << 1) + 2;
|
||||
csize = (du->csd[8] >> 6) + (du->csd[7] << 2) +
|
||||
((du->csd[6] & 3) << 10) + 1;
|
||||
nsectors = csize << (n - 9);
|
||||
break;
|
||||
default: /* Unknown version. */
|
||||
@@ -405,6 +413,52 @@ static int card_size(int unit)
|
||||
return nsectors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use CMD6 to enable high-speed mode.
|
||||
*/
|
||||
static void card_high_speed(int unit)
|
||||
{
|
||||
int reply, i;
|
||||
struct spiio *io = &sddrives[unit].spiio;
|
||||
struct disk *du = &sddrives[unit];
|
||||
unsigned char status[64];
|
||||
|
||||
/* Here we set HighSpeed 50MHz.
|
||||
* We do not tackle the power and io driver strength yet. */
|
||||
spi_select(io);
|
||||
reply = card_cmd(unit, CMD_SWITCH_FUNC, 0x80000001);
|
||||
if (reply != 0) {
|
||||
/* Command rejected. */
|
||||
card_release(io);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for a response. */
|
||||
for (i=0; ; i++) {
|
||||
reply = spi_transfer(io, 0xFF);
|
||||
if (reply == DATA_START_BLOCK)
|
||||
break;
|
||||
if (i >= 5000) {
|
||||
/* Command timed out. */
|
||||
card_release(io);
|
||||
printf("sd%d: card_size: SWITCH_FUNC timed out, reply = %d\n",
|
||||
unit, reply);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read 64-byte status. */
|
||||
for (i=0; i<64; i++)
|
||||
status[i] = spi_transfer(io, 0xFF);
|
||||
card_release(io);
|
||||
|
||||
if ((status[16] & 0xF) == 1) {
|
||||
/* The card has switched to high-speed mode. */
|
||||
spi_brg(io, SD_FAST_MHZ * 1000);
|
||||
}
|
||||
du->ma = status[0] << 8 | status[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a block of data.
|
||||
* Return nonzero if successful.
|
||||
@@ -605,11 +659,21 @@ static int sd_setup(int unit)
|
||||
printf("sd%d: cannot get card size\n", unit);
|
||||
return 0;
|
||||
}
|
||||
printf("sd%d: type %s, size %u kbytes, speed %u Mbit/sec\n", unit,
|
||||
|
||||
/* Switch to the high speed mode, if possible. */
|
||||
if (du->csd[4] & 0x40) {
|
||||
/* Class 10 card: switch to high-speed mode.
|
||||
* SPI interface of pic32 allows up to 25MHz clock rate. */
|
||||
card_high_speed(unit);
|
||||
}
|
||||
printf("sd%d: type %s, size %u kbytes, speed %u Mbit/sec", unit,
|
||||
(du->card_type == TYPE_SDHC) ? "SDHC" :
|
||||
(du->card_type == TYPE_SD_II) ? "II" : "I",
|
||||
du->part[RAWPART].dp_nsectors / 2,
|
||||
spi_get_brg(io) / 1000);
|
||||
if (du->ma > 0)
|
||||
printf(", current %u mA", du->ma);
|
||||
printf("\n");
|
||||
|
||||
/* Read partition table. */
|
||||
int s = splbio();
|
||||
@@ -885,7 +949,7 @@ sd_probe(config)
|
||||
/* Disable power to the SD card. */
|
||||
sd_release(unit);
|
||||
|
||||
spi_brg(io, SD_MHZ * 1000);
|
||||
spi_brg(io, 250);
|
||||
spi_set(io, PIC32_SPICON_CKE);
|
||||
|
||||
#ifdef UCB_METER
|
||||
|
||||
Reference in New Issue
Block a user