Patrik Axelsson d56fbaaaf4 Discard undefined byte at end of write multiple block
This byte needs to be read before the card goes busy, but more importantly,
it would otherwise be read out by sd_wait_ready():

For cards where this byte is 0xff, sd_wait_ready() would think the card is
immediately ready and let the code send it the next command, while the read
actually made the card go busy.

This makes the card end up in a state the code cannot recover it from - even
if you reboot the machine so spisd.device is restarted, it still requires
the card to be power cycled by ejecting and re-inserting it.

How to reproduce for affected cards:
1. Use spisd.device v2.2
2. Mount SD0:
3. Write a file larger than 512Bytes to trigger a write multiple block
4. Write or read another file, this will trigger the next command and show
   the issue as a read or write error
2023-08-30 16:56:48 +02:00

556 lines
14 KiB
C

/*
* SPI SD device driver for K1208/Amiga 1200
*
* Copyright (C) 2018 Mike Stirling
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
//#include "common.h"
#include "spi.h"
#include "sd.h"
#include "timer.h"
#define FUNCTION_TRACE
#define INFO(...)
#define ERROR(...)
#define TRACE(...)
#define SLOW_CLOCK 400000
#define FAST_CLOCK 3000000
#define READY_TIMEOUT_MS 500
#define INIT_TIMEOUT_MS 1000
#define MAX_RESPONSE_POLLS 10
/* MMC/SD command */
#define CMD0 (0) /* GO_IDLE_STATE */
#define CMD1 (1) /* SEND_OP_COND (MMC) */
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
#define CMD8 (8) /* SEND_IF_COND */
#define CMD9 (9) /* SEND_CSD */
#define CMD10 (10) /* SEND_CID */
#define CMD12 (12) /* STOP_TRANSMISSION */
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
#define CMD16 (16) /* SET_BLOCKLEN */
#define CMD17 (17) /* READ_SINGLE_BLOCK */
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (24) /* WRITE_BLOCK */
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
#define CMD32 (32) /* ERASE_ER_BLK_START */
#define CMD33 (33) /* ERASE_ER_BLK_END */
#define CMD38 (38) /* ERASE */
#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
static sd_card_info_t sd_card_info;
/*! Utility function for parsing CSD fields */
static int sd_parse_csd(sd_card_info_t *ci, const uint32_t *bits)
{
sd_card_csd_t *csd = &ci->csd;
memset(csd, 0, sizeof(sd_card_csd_t));
TRACE("CSD: %08X %08X %08X %08X\n",
(unsigned int)bits[0],
(unsigned int)bits[1],
(unsigned int)bits[2],
(unsigned int)bits[3]);
csd->csd_structure = (bits[0] >> 30) & 0x2;
csd->taac = (bits[0] >> 16) & 0xff;
csd->nsac = (bits[0] >> 8) & 0xff;
csd->max_transfer_rate = (bits[0] >> 0) & 0xff;
csd->card_command_classes = (bits[1] >> 20) & 0xfff;
csd->read_block_len = (bits[1] >> 16) & 0xf;
csd->read_partial_blocks = (bits[1] >> 15) & 0x1;
csd->write_block_misalign = (bits[1] >> 14) & 0x1;
csd->read_block_misalign = (bits[1] >> 13) & 0x1;
csd->dsr_implemented = (bits[1] >> 12) & 0x1;
if (ci->type == sdCardType_SD1_x || ci->type == sdCardType_SD2_0) {
csd->device_size = ((bits[1] & 0x3ff) << 2) | (bits[2] >> 30);
csd->max_read_current_vdd_min = (bits[2] >> 27) & 0x7;
csd->max_read_current_vdd_max = (bits[2] >> 24) & 0x7;
csd->max_write_current_vdd_min = (bits[2] >> 21) & 0x7;
csd->max_write_current_vdd_max = (bits[2] >> 18) & 0x7;
csd->device_size_mult = (bits[2] >> 15) & 0x7;
//ci->capacity = (uint64_t)(csd->device_size + 1) << (csd->device_size_mult + csd->read_block_len + 2);
ci->total_sectors = (uint32_t)(csd->device_size + 1) << (csd->device_size_mult + 2);
} else if (ci->type == sdCardType_SDHC) {
csd->device_size = ((bits[1] & 0x3f) << 16) | (bits[2] >> 16);
//ci->capacity = (uint64_t)(csd->device_size + 1) << 19;
ci->total_sectors = (uint32_t)(csd->device_size + 1) << (19 - csd->read_block_len);
} else {
ERROR("Card type not supported for CSD decode\n");
return sdError_Unsupported;
}
csd->erase_single_block = (bits[2] >> 14) & 0x1;
csd->erase_sector_size = (bits[2] >> 7) & 0x7f;
csd->write_protect_group_size = (bits[2] >> 0) & 0x7f;
csd->write_protect_group = (bits[3] >> 31) & 0x1;
csd->write_speed_factor = (bits[3] >> 26) & 0x7;
csd->write_block_len = (bits[3] >> 22) & 0xf;
csd->write_partial_blocks = (bits[3] >> 21) & 0x1;
csd->file_format_group = (bits[3] >> 15) & 0x1;
csd->copy_flag = (bits[3] >> 14) & 0x1;
csd->perm_write_prot = (bits[3] >> 13) & 0x1;
csd->temp_write_prot = (bits[3] >> 12) & 0x1;
csd->file_format = (bits[3] >> 10) & 0x3;
csd->crc = (bits[3] >> 1) & 0x7f;
if (csd->read_block_len != csd->write_block_len) {
ERROR("Different read/write block sizes not supported\n");
return sdError_Unsupported;
}
ci->block_size = csd->read_block_len;
INFO("capacity %u MiB block size = %u bytes\n",
(unsigned int)(ci->capacity / 1024 / 1024),
1 << ci->block_size);
/* FIXME: Check CRC */
return 0;
}
/*! Utility function for parsing CID fields */
static int sd_parse_cid(sd_card_info_t *ci, const uint32_t *bits)
{
sd_card_cid_t *cid = &ci->cid;
memset(cid, 0, sizeof(sd_card_cid_t));
TRACE("CID: %08X %08X %08X %08X\n",
(unsigned int)bits[0],
(unsigned int)bits[1],
(unsigned int)bits[2],
(unsigned int)bits[3]);
cid->manufacturer_id = (bits[0] >> 24) & 0xff;
cid->app_id[0] = (bits[0] >> 16) & 0xff;
cid->app_id[1] = (bits[0] >> 8) & 0xff;
cid->product_name[0] = (bits[0] >> 0) & 0xff;
cid->product_name[1] = (bits[1] >> 24) & 0xff;
cid->product_name[2] = (bits[1] >> 16) & 0xff;
cid->product_name[3] = (bits[1] >> 8) & 0xff;
cid->product_name[4] = (bits[1] >> 0) & 0xff;
cid->product_rev = (bits[2] >> 24) & 0xff;
cid->product_sn = (bits[2] << 8) & 0xffffff00;
cid->product_sn |= (bits[3] >> 24) & 0xff;
cid->mfg_date = (bits[3] >> 8) & 0xfff;
cid->crc = (bits[3] >> 1) & 0x7f;
INFO("SD mfg %02X app '%c%c' product '%.5s' rev %02X sn %08X mfg %02u/%04u\n",
cid->manufacturer_id,
cid->app_id[0], cid->app_id[1],
cid->product_name,
cid->product_rev,
(unsigned int)cid->product_sn,
(unsigned int)(cid->mfg_date & 0xf),
(unsigned int)((cid->mfg_date >> 8) + 2000));
/* FIXME: Check CRC */
return 0;
}
static int sd_wait_ready(void)
{
uint32_t timeout;
uint8_t in;
timeout = timer_get_tick_count() + TIMER_MILLIS(READY_TIMEOUT_MS);
do {
spi_read(&in, 1);
} while (in != 0xff && (int32_t)(timer_get_tick_count() - timeout) < 0);
return (in == 0xff) ? 0 : sdError_Timeout;
}
static void sd_deselect(void)
{
spi_deselect();
}
static int sd_select(void)
{
spi_select();
if (sd_wait_ready() == 0) {
return 0;
}
spi_deselect();
ERROR("Timeout waiting for card ready\n");
return sdError_Timeout;
}
static int sd_read_block(uint8_t *buf, unsigned int size)
{
uint32_t timeout;
uint8_t token, crc[2];
/* Wait for data start token */
timeout = timer_get_tick_count() + TIMER_MILLIS(READY_TIMEOUT_MS);
do {
spi_read(&token, 1);
} while (token == 0xff && (int32_t)(timer_get_tick_count() - timeout) < 0);
if (token != 0xfe) {
ERROR("No data token received\n");
return sdError_Timeout;
}
/* Read data */
spi_read(buf, size);
spi_read(crc, 2);
return 0;
}
static int sd_write_block(const uint8_t *buf, uint8_t token)
{
uint8_t crc[2] = {0xff, 0xff};
uint8_t resp;
if (sd_wait_ready() < 0) {
ERROR("Card not ready\n");
return sdError_Timeout;
}
/* Send token */
spi_write(&token, 1);
if (token == 0xfd) {
/* After sending STOP_TRAN, a byte needs to be read before the card
* goes busy. This byte is undefined, so unless we read it now, the
* next sd_wait_ready() will read it and could erronously decide
* that the card is immediately ready.
*/
spi_read(&resp, 1);
}
else {
/* Send data */
spi_write(buf, SD_SECTOR_SIZE);
spi_write(crc, 2); /* dummy */
/* Receive data response */
spi_read(&resp, 1);
if ((resp & 0x1f) != 0x05) {
ERROR("Bad response\n");
return sdError_BadResponse;
}
}
return 0;
}
static uint8_t sd_send_cmd(uint8_t cmd, uint32_t arg)
{
uint8_t res;
uint8_t buf[6];
int n;
if (cmd & 0x80) {
/* Send CMD55 prior to ACMD */
cmd &= 0x7f;
res = sd_send_cmd(CMD55, 0);
if (res > 1) {
return res;
}
}
/* Select the card and wait for ready except for abort */
if (cmd != CMD12) {
sd_deselect();
if (sd_select() < 0) {
return 0xff;
}
}
/* Build command */
buf[0] = 0x40 | cmd;
buf[1] = (uint8_t)(arg >> 24);
buf[2] = (uint8_t)(arg >> 16);
buf[3] = (uint8_t)(arg >> 8);
buf[4] = (uint8_t)(arg >> 0);
if (cmd == CMD0) {
buf[5] = 0x95; /* CRC for CMD0 */
} else if (cmd == CMD8) {
buf[5] = 0x87; /* CRC for CMD8 */
} else {
buf[5] = 0x01; /* Dummy CRC and stop */
}
spi_write(buf, sizeof(buf));
/* Receive command response */
if (cmd == CMD12) {
/* Skip first byte */
spi_read(&res, 1);
}
for (n = 0; n < MAX_RESPONSE_POLLS; n++) {
spi_read(&res, 1);
if (!(res & 0x80)) {
break;
}
}
return res;
}
static uint32_t sd_get_r7_resp(void)
{
uint8_t buf[4];
spi_read(buf, 4);
return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3] << 0);
}
int sd_open(void)
{
sd_card_info_t *ci = &sd_card_info;
uint32_t timeout;
uint8_t cmd;
uint32_t resp[4];
int err;
FUNCTION_TRACE;
spi_set_speed(SPI_SPEED_SLOW);
ci->type = sdCardType_None;
//ci->capacity = 0;
ci->total_sectors = 0;
ci->block_size = sdBlockSize_512;
/* Send dummy clocks with CS high (doing this sends 96 clocks) */
sd_deselect();
sd_get_r7_resp();
sd_get_r7_resp();
sd_get_r7_resp();
if (sd_send_cmd(CMD0,0) == 1) {
if (sd_send_cmd(CMD8, 0x1aa) == 1) {
uint32_t ocr = sd_get_r7_resp();
if (ocr == 0x000001aa) {
TRACE("SDv2 - R7 resp = 0x%08X\n", (unsigned int) ocr);
ci->type = sdCardType_SD2_0;
/* Wait for card ready */
timeout = timer_get_tick_count() + TIMER_MILLIS(INIT_TIMEOUT_MS);
while (sd_send_cmd(ACMD41, (1ul << 30)) > 0) {
if ((int32_t)(timer_get_tick_count() - timeout) >= 0) {
/* Init timed out - invalidate card */
ERROR("Init timed out\n");
ci->type = sdCardType_None;
}
}
if (ci->type) {
/* Read OCR */
if (sd_send_cmd(CMD58, 0) == 0) {
ocr = sd_get_r7_resp();
if (ocr & (1ul << 30)) {
/* Card is high capacity */
TRACE("SDHC\n");
ci->type = sdCardType_SDHC;
}
} else {
ERROR("Failed to read OCR\n");
ci->type = sdCardType_None;
}
}
}
} else {
/* Not SDv2 */
if (sd_send_cmd(ACMD41, 0) <= 1) {
TRACE("SDv1\n");
ci->type = sdCardType_SD1_x;
cmd = ACMD41;
} else {
TRACE("MMCv3\n");
ci->type = sdCardType_MMC;
cmd = CMD1;
}
/* Wait for card ready */
timeout = timer_get_tick_count() + TIMER_MILLIS(INIT_TIMEOUT_MS);
while (sd_send_cmd(cmd, 0) > 0) {
if ((int32_t)(timer_get_tick_count() - timeout) >= 0) {
/* Init timed out - invalidate card */
ERROR("Init timed out\n");
ci->type = sdCardType_None;
}
}
if (ci->type) {
/* Set block length */
if (sd_send_cmd(CMD16, SD_SECTOR_SIZE) > 0) {
ERROR("Failed to set block length\n");
ci->type = sdCardType_None;
}
}
}
}
if (ci->type) {
INFO("SD card ready (type %u)\n", ci->type);
/* Read and decode card info */
if (sd_send_cmd(CMD10, 0) == 0) {
err = sd_read_block((uint8_t*)&resp, sizeof(resp));
if (err < 0) {
ERROR("Read CID failed\n");
}
} else {
err = sdError_BadResponse;
}
if (err == 0) {
err = sd_parse_cid(ci, resp);
}
if (err == 0) {
if (sd_send_cmd(CMD9, 0) == 0) {
err = sd_read_block((uint8_t*)&resp, sizeof(resp));
if (err < 0) {
ERROR("Read CSD failed\n");
}
} else {
err = sdError_BadResponse;
}
}
if (err == 0) {
err = sd_parse_csd(ci, resp);
}
/* Switch to fast clock */
spi_set_speed(SPI_SPEED_FAST);
} else {
/* Card not present */
err = sdError_NoCard;
}
sd_deselect();
return err;
}
int sd_read(uint8_t *buf, uint32_t sector, uint32_t count)
{
sd_card_info_t *ci = &sd_card_info;
int err = 0;
if (ci->type == sdCardType_None) {
ERROR("No card\n");
return sdError_NoCard;
}
if (ci->type != sdCardType_SDHC) {
/* Convert sector to byte addressing (x512) */
sector <<= 9;
}
if (count == 1) {
/* Read single sector */
if (sd_send_cmd(CMD17, sector) == 0) {
err = sd_read_block(buf, SD_SECTOR_SIZE);
} else {
err = sdError_BadResponse;
}
} else if (count > 1) {
/* Read multiple sectors */
if (sd_send_cmd(CMD18, sector) == 0) {
do {
err = sd_read_block(buf, SD_SECTOR_SIZE);
if (err < 0) {
break;
}
buf += SD_SECTOR_SIZE;
} while (--count);
/* Send CMD12 stop transmission */
if (err == 0) {
err = sd_send_cmd(CMD12, 0);
}
} else {
err = sdError_BadResponse;
}
}
sd_deselect();
return err;
}
int sd_write(const uint8_t *buf, uint32_t sector, uint32_t count)
{
sd_card_info_t *ci = &sd_card_info;
int err = 0;
if (ci->type == sdCardType_None) {
ERROR("No card\n");
return sdError_NoCard;
}
if (ci->type != sdCardType_SDHC) {
/* Convert sector to byte addressing (x512) */
sector <<= 9;
}
if (count == 1) {
/* Write single sector */
if (sd_send_cmd(CMD24, sector) == 0) {
err = sd_write_block(buf, 0xfe);
} else {
err = sdError_BadResponse;
}
} else if (count > 1) {
if (ci->type == sdCardType_SD1_x || ci->type == sdCardType_SD2_0 || ci->type == sdCardType_SDHC) {
/* Pre-defined sector count */
sd_send_cmd(ACMD23, count);
}
/* Write multiple sectors */
if (sd_send_cmd(CMD25, sector) == 0) {
do {
err = sd_write_block(buf, 0xfc);
if (err < 0) {
break;
}
buf += SD_SECTOR_SIZE;
} while (--count);
/* Send STOP_TRAN */
if (err == 0) {
err = sd_write_block(0, 0xfd);
}
} else {
err = sdError_BadResponse;
}
}
sd_deselect();
return err;
}
const sd_card_info_t* sd_get_card_info(void)
{
return &sd_card_info;
}