From e52cff81a9aee98ff1033c6205182ef5a80feab9 Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Sun, 11 Aug 2019 23:47:05 +0200 Subject: [PATCH] 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 --- subsys/disk/disk_access_sdhc.h | 2 + subsys/disk/disk_access_spi_sdhc.c | 122 ++++++++++++++++++++++------- 2 files changed, 96 insertions(+), 28 deletions(-) diff --git a/subsys/disk/disk_access_sdhc.h b/subsys/disk/disk_access_sdhc.h index 9ec5e2d7c82f7d..3ce7d7a767d3fa 100644 --- a/subsys/disk/disk_access_sdhc.h +++ b/subsys/disk/disk_access_sdhc.h @@ -80,10 +80,12 @@ enum sdhc_app_ext_cmd { /* Fields in various card registers */ #define SDHC_HCS (1 << 30) #define SDHC_CCS (1 << 30) +#define SDHC_BUSY (1 << 31) #define SDHC_VHS_MASK (0x0F << 8) #define SDHC_VHS_3V3 (1 << 8) #define SDHC_CHECK 0xAA #define SDHC_CSD_SIZE 16 +#define SDHC_CSD_V1 0 #define SDHC_CSD_V2 1 /* Data block tokens */ diff --git a/subsys/disk/disk_access_spi_sdhc.c b/subsys/disk/disk_access_spi_sdhc.c index d8d13b8650190d..83afb329d6f8dd 100644 --- a/subsys/disk/disk_access_spi_sdhc.c +++ b/subsys/disk/disk_access_spi_sdhc.c @@ -29,6 +29,7 @@ struct sdhc_spi_data { struct device *cs; u32_t pin; + bool high_capacity; u32_t sector_count; u8_t status; #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); } -/* Checks the supported host volatage and basic protocol */ -static int sdhc_spi_check_card(struct sdhc_spi_data *data) +/* Checks the supported host voltage and basic protocol of a SDHC card */ +static int sdhc_spi_check_interface(struct sdhc_spi_data *data) { u32_t cond; int err; @@ -501,8 +502,11 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data) u32_t ocr; struct sdhc_retry retry; u8_t structure; + u8_t readbllen; u32_t csize; + u8_t csizemult; u8_t buf[SDHC_CSD_SIZE]; + bool is_v2; data->cfg.frequency = SDHC_SPI_INITIAL_SPEED; data->status = DISK_STATUS_UNINIT; @@ -513,10 +517,9 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data) do { err = sdhc_spi_go_idle(data); if (err == 0) { - err = sdhc_spi_check_card(data); - if (err == 0) { - break; - } + err = sdhc_spi_check_interface(data); + is_v2 = (err == 0) ? true : false; + break; } if (!sdhc_retry_ok(&retry)) { @@ -534,7 +537,8 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data) do { 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) { break; } @@ -545,15 +549,36 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data) return -ETIMEDOUT; } - /* Read OCR and confirm this is a SDHC card */ - err = sdhc_spi_cmd_r3(data, SDHC_READ_OCR, 0, &ocr); - if (err != 0) { - return err; + 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); + if (err != 0) { + return err; + } + if ((ocr & SDHC_BUSY) != 0U) { + break; + } + } while (sdhc_retry_ok(&retry)); + + if (err != 0) { + /* Card never finished power-up */ + return -ETIMEDOUT; + } } - if ((ocr & SDHC_CCS) == 0U) { - /* A 'SDSC' card */ - return -ENOTSUP; + 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 */ @@ -569,22 +594,43 @@ static int sdhc_spi_detect(struct sdhc_spi_data *data) /* Bits 126..127 are the structure version */ structure = (buf[0] >> 6); - if (structure != SDHC_CSD_V2) { + switch (structure) { + 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; + } + /* 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. + */ + csize = sys_get_be32(&buf[6]) & ((1 << 22) - 1); + if (csize < 4112) { + /* Invalid capacity (cf. section 5.3.3) */ + return -ENOTSUP; + } + data->sector_count = (csize + 1) * + (512 * 1024 / SDMMC_DEFAULT_BLOCK_SIZE); + break; + default: /* Unsupported CSD format */ return -ENOTSUP; } - /* Bits 48..69 are the capacity of the card in 512 KiB units, minus 1. - */ - csize = sys_get_be32(&buf[6]) & ((1 << 22) - 1); - if (csize < 4112) { - /* Invalid capacity according to section 5.3.3 */ - return -ENOTSUP; - } - - data->sector_count = (csize + 1) * - (512 * 1024 / SDMMC_DEFAULT_BLOCK_SIZE); - LOG_INF("Found a ~%u MiB SDHC card.", 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) { int err; + u32_t addr; err = sdhc_map_disk_status(data->status); if (err != 0) { 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); /* 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) { 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) { int err; + u32_t addr; err = sdhc_map_disk_status(data->status); if (err != 0) { @@ -665,7 +722,16 @@ static int sdhc_spi_write(struct sdhc_spi_data *data, /* Write the blocks one-by-one */ 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) { goto error; }