disk: sdhc: Add support for standard-capacity SD cards

This patch adds support for SDSCv1 and SDSCv2 cards. It has been tested
with 2 GiB SDSC and 4 GiB to 32 GiB SDHC cards from SanDisk.

Signed-off-by: Markus Fuchs <markus.fuchs@de.sauter-bc.com>
This commit is contained in:
Markus Fuchs 2019-08-11 23:47:05 +02:00 committed by Kumar Gala
commit e52cff81a9
2 changed files with 96 additions and 28 deletions

View file

@ -80,10 +80,12 @@ enum sdhc_app_ext_cmd {
/* Fields in various card registers */ /* Fields in various card registers */
#define SDHC_HCS (1 << 30) #define SDHC_HCS (1 << 30)
#define SDHC_CCS (1 << 30) #define SDHC_CCS (1 << 30)
#define SDHC_BUSY (1 << 31)
#define SDHC_VHS_MASK (0x0F << 8) #define SDHC_VHS_MASK (0x0F << 8)
#define SDHC_VHS_3V3 (1 << 8) #define SDHC_VHS_3V3 (1 << 8)
#define SDHC_CHECK 0xAA #define SDHC_CHECK 0xAA
#define SDHC_CSD_SIZE 16 #define SDHC_CSD_SIZE 16
#define SDHC_CSD_V1 0
#define SDHC_CSD_V2 1 #define SDHC_CSD_V2 1
/* Data block tokens */ /* Data block tokens */

View file

@ -29,6 +29,7 @@ struct sdhc_spi_data {
struct device *cs; struct device *cs;
u32_t pin; u32_t pin;
bool high_capacity;
u32_t sector_count; u32_t sector_count;
u8_t status; u8_t status;
#if LOG_LEVEL >= LOG_LEVEL_DBG #if LOG_LEVEL >= LOG_LEVEL_DBG
@ -468,8 +469,8 @@ static int sdhc_spi_go_idle(struct sdhc_spi_data *data)
return sdhc_spi_cmd_r1_idle(data, SDHC_GO_IDLE_STATE, 0); return sdhc_spi_cmd_r1_idle(data, SDHC_GO_IDLE_STATE, 0);
} }
/* Checks the supported host volatage and basic protocol */ /* Checks the supported host voltage and basic protocol of a SDHC card */
static int sdhc_spi_check_card(struct sdhc_spi_data *data) static int sdhc_spi_check_interface(struct sdhc_spi_data *data)
{ {
u32_t cond; u32_t cond;
int err; int err;
@ -501,8 +502,11 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data)
u32_t ocr; u32_t ocr;
struct sdhc_retry retry; struct sdhc_retry retry;
u8_t structure; u8_t structure;
u8_t readbllen;
u32_t csize; u32_t csize;
u8_t csizemult;
u8_t buf[SDHC_CSD_SIZE]; u8_t buf[SDHC_CSD_SIZE];
bool is_v2;
data->cfg.frequency = SDHC_SPI_INITIAL_SPEED; data->cfg.frequency = SDHC_SPI_INITIAL_SPEED;
data->status = DISK_STATUS_UNINIT; data->status = DISK_STATUS_UNINIT;
@ -513,11 +517,10 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data)
do { do {
err = sdhc_spi_go_idle(data); err = sdhc_spi_go_idle(data);
if (err == 0) { if (err == 0) {
err = sdhc_spi_check_card(data); err = sdhc_spi_check_interface(data);
if (err == 0) { is_v2 = (err == 0) ? true : false;
break; break;
} }
}
if (!sdhc_retry_ok(&retry)) { if (!sdhc_retry_ok(&retry)) {
return -ENOENT; return -ENOENT;
@ -534,7 +537,8 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data)
do { do {
sdhc_spi_cmd_r1_raw(data, SDHC_APP_CMD, 0); sdhc_spi_cmd_r1_raw(data, SDHC_APP_CMD, 0);
err = sdhc_spi_cmd_r1(data, SDHC_SEND_OP_COND, SDHC_HCS); /* Set HCS only if card conforms to specification v2.00 (cf. 4.2.3) */
err = sdhc_spi_cmd_r1(data, SDHC_SEND_OP_COND, is_v2 ? SDHC_HCS : 0);
if (err == 0) { if (err == 0) {
break; break;
} }
@ -545,15 +549,36 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
/* Read OCR and confirm this is a SDHC card */ ocr = 0;
if (is_v2) {
do {
/* Read OCR to check if this is a SDSC or SDHC card.
* CCS bit is valid after BUSY bit is set.
*/
err = sdhc_spi_cmd_r3(data, SDHC_READ_OCR, 0, &ocr); err = sdhc_spi_cmd_r3(data, SDHC_READ_OCR, 0, &ocr);
if (err != 0) { if (err != 0) {
return err; return err;
} }
if ((ocr & SDHC_BUSY) != 0U) {
break;
}
} while (sdhc_retry_ok(&retry));
if ((ocr & SDHC_CCS) == 0U) { if (err != 0) {
/* A 'SDSC' card */ /* Card never finished power-up */
return -ENOTSUP; return -ETIMEDOUT;
}
}
if ((ocr & SDHC_CCS) != 0U) {
data->high_capacity = true;
} else {
/* A 'SDSC' card: Set block length to 512 bytes. */
data->high_capacity = false;
err = sdhc_cmd_r1(data, SDHC_SET_BLOCK_SIZE, SDMMC_DEFAULT_BLOCK_SIZE);
if (err != 0) {
return err;
}
} }
/* Read the CSD */ /* Read the CSD */
@ -569,21 +594,42 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data)
/* Bits 126..127 are the structure version */ /* Bits 126..127 are the structure version */
structure = (buf[0] >> 6); structure = (buf[0] >> 6);
if (structure != SDHC_CSD_V2) { switch (structure) {
/* Unsupported CSD format */ case SDHC_CSD_V1:
/* The maximum read data block length is given by bits 80..83 raised
* to the power of 2. Possible values are 9, 10 and 11 for 512, 1024
* and 2048 bytes, respectively. This driver does not make use of block
* lengths greater than 512 bytes, but forces 512 byte block transfers
* instead.
*/
readbllen = buf[5] & ((1 << 4) - 1);
if ((readbllen < 9) || (readbllen > 11)) {
/* Invalid maximum read data block length (cf. section 5.3.2) */
return -ENOTSUP; return -ENOTSUP;
} }
/* The capacity of the card is given by bits 62..73 plus 1 multiplied
* by bits 47..49 plus 2 raised to the power of 2 in maximum read data
* blocks.
*/
csize = (sys_get_be32(&buf[6]) >> 14) & ((1 << 12) - 1);
csizemult = (u8_t) ((sys_get_be16(&buf[9]) >> 7) & ((1 << 3) - 1));
data->sector_count = ((csize + 1) << (csizemult + 2 + readbllen - 9));
break;
case SDHC_CSD_V2:
/* Bits 48..69 are the capacity of the card in 512 KiB units, minus 1. /* Bits 48..69 are the capacity of the card in 512 KiB units, minus 1.
*/ */
csize = sys_get_be32(&buf[6]) & ((1 << 22) - 1); csize = sys_get_be32(&buf[6]) & ((1 << 22) - 1);
if (csize < 4112) { if (csize < 4112) {
/* Invalid capacity according to section 5.3.3 */ /* Invalid capacity (cf. section 5.3.3) */
return -ENOTSUP; return -ENOTSUP;
} }
data->sector_count = (csize + 1) * data->sector_count = (csize + 1) *
(512 * 1024 / SDMMC_DEFAULT_BLOCK_SIZE); (512 * 1024 / SDMMC_DEFAULT_BLOCK_SIZE);
break;
default:
/* Unsupported CSD format */
return -ENOTSUP;
}
LOG_INF("Found a ~%u MiB SDHC card.", LOG_INF("Found a ~%u MiB SDHC card.",
data->sector_count / (1024 * 1024 / SDMMC_DEFAULT_BLOCK_SIZE)); data->sector_count / (1024 * 1024 / SDMMC_DEFAULT_BLOCK_SIZE));
@ -615,16 +661,26 @@ static int sdhc_spi_read(struct sdhc_spi_data *data,
u8_t *buf, u32_t sector, u32_t count) u8_t *buf, u32_t sector, u32_t count)
{ {
int err; int err;
u32_t addr;
err = sdhc_map_disk_status(data->status); err = sdhc_map_disk_status(data->status);
if (err != 0) { if (err != 0) {
return err; return err;
} }
/* Translate sector number to data address.
* SDSC cards use byte addressing, SDHC cards use block addressing.
*/
if (data->high_capacity) {
addr = sector;
} else {
addr = sector * SDMMC_DEFAULT_BLOCK_SIZE;
}
sdhc_spi_set_cs(data, 0); sdhc_spi_set_cs(data, 0);
/* Send the start read command */ /* Send the start read command */
err = sdhc_spi_cmd_r1(data, SDHC_READ_MULTIPLE_BLOCK, sector); err = sdhc_spi_cmd_r1(data, SDHC_READ_MULTIPLE_BLOCK, addr);
if (err != 0) { if (err != 0) {
goto error; goto error;
} }
@ -655,6 +711,7 @@ static int sdhc_spi_write(struct sdhc_spi_data *data,
const u8_t *buf, u32_t sector, u32_t count) const u8_t *buf, u32_t sector, u32_t count)
{ {
int err; int err;
u32_t addr;
err = sdhc_map_disk_status(data->status); err = sdhc_map_disk_status(data->status);
if (err != 0) { if (err != 0) {
@ -665,7 +722,16 @@ static int sdhc_spi_write(struct sdhc_spi_data *data,
/* Write the blocks one-by-one */ /* Write the blocks one-by-one */
for (; count != 0U; count--) { for (; count != 0U; count--) {
err = sdhc_spi_cmd_r1(data, SDHC_WRITE_BLOCK, sector); /* Translate sector number to data address.
* SDSC cards use byte addressing, SDHC cards use block addressing.
*/
if (data->high_capacity) {
addr = sector;
} else {
addr = sector * SDMMC_DEFAULT_BLOCK_SIZE;
}
err = sdhc_spi_cmd_r1(data, SDHC_WRITE_BLOCK, addr);
if (err < 0) { if (err < 0) {
goto error; goto error;
} }