/* * 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 . */ #include #include //#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; }