123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876 |
- #include <stdbool.h>
- #include <stddef.h>
- #include <string.h>
- #include "fw.h"
- #include "io.h"
- #include "sdcard.h"
- #include "systime.h"
- #include "console.h"
- #include "ff.h"
- #include "diskio.h"
- #ifndef DEBUG
- # define DEBUG 0
- #endif
- #if DEBUG
- # define dbg_printf con_printf
- # define dbg_puts con_puts
- # define dbg_putc con_putc
- #else
- # define dbg_printf(f,...) ((void)0)
- # define dbg_puts(x) ((void)0)
- # define dbg_putc(x) ((void)0)
- #endif
- #define SECTOR_SHIFT 9
- #define SECTOR_SIZE (1UL << SECTOR_SHIFT)
- enum sdcard_cmd {
- CMD_GO_IDLE_STATE = 0x40,
- CMD_SEND_OP_COND = 0x41,
- CMD_SWITCH_FUNC = 0x46,
- CMD_SEND_IF_COND = 0x48,
- CMD_SEND_CSD = 0x49,
- CMD_SEND_CID = 0x4a,
- CMD_STOP_TRANSMISSION = 0x4c,
- CMD_SEND_STATUS = 0x4d,
- CMD_SET_BLOCKLEN = 0x50,
- CMD_READ_SINGLE_BLOCK = 0x51,
- CMD_READ_MULTIPLE_BLOCK = 0x52,
- CMD_WRITE_BLOCK = 0x58,
- CMD_WRITE_MULTIPLE_BLOCK = 0x59,
- CMD_PROGRAM_CSD = 0x5b,
- CMD_SET_WRITE_PROT = 0x5c,
- CMD_CLR_WRITE_PROT = 0x5d,
- CMD_SEND_WRITE_PROT = 0x5e,
- CMD_ERASE_WR_BLK_START_ADDR = 0x60,
- CMD_ERASE_WR_BLK_END_ADDR = 0x61,
- CMD_ERASE = 0x66,
- CMD_LOCK_UNLOCK = 0x6a,
- CMD_APP_CMD = 0x77,
- CMD_GEN_CMD = 0x78,
- CMD_READ_OCR = 0x7a,
- CMD_CRC_ON_OFF = 0x7b
- };
- enum sdcard_acmd {
- ACMD_SD_STATUS = 0x4d,
- ACMD_SEND_NUM_WR_BLOCKS = 0x56,
- ACMD_SET_WR_BLK_ERASE_COUNT = 0x57,
- ACMD_SD_SEND_OP_COND = 0x69,
- ACMD_SET_CLR_CARD_DETECT = 0x6a,
- ACMD_SEND_SCR = 0x73
- };
- struct sdcard_csd {
- uint32_t raw[4];
- };
- struct sdcard_cid {
- uint32_t raw[4];
- };
- struct sdcard_info {
- DSTATUS status;
- int8_t card_type;
- unsigned long lbasize;
- uint32_t if_cond;
- uint32_t ocr;
- struct sdcard_csd csd;
- struct sdcard_cid cid;
- };
- struct sdcard_info sdc = {
- .status = STA_NOINIT
- };
- static volatile int8_t sdcard_led;
- void sdcard_timer_tick(void)
- {
- #if 0
- if (sdcard_led > 0) {
- if (--sdcard_led == 0)
- *IO_SYS_LED &= ~0x01;
- }
- #endif
- }
- static void sdcard_led_on(void)
- {
- #if 0
- sdcard_led = -1;
- *IO_SYS_LED |= 0x01;
- #endif
- }
- static void sdcard_led_off(void)
- {
- sdcard_led = 4;
- }
- static int sdcard_send_cmd(uint8_t opcode, uint32_t argument)
- {
- int status = -1;
- int i;
- if (!opcode)
- return 0;
- dbg_printf("sdcard: CMD%02u arg %08x:", opcode ^ 0x40, argument);
- sd_writeb(opcode, SD_GO8|SD_CLEARCRC);
- sd_writel(argument, SD_BE|SD_GO32);
-
- sd_writeb(sd_crc7_wr(), SD_GO16);
-
- for (i = 16; i; i--) {
- status = sd_readb(SD_GO8);
- dbg_printf(" %02x", status);
- if ((int8_t)status >= 0)
- break;
- }
- dbg_putc('\n');
- return status;
- }
- static int sdcard_send_acmd(uint8_t opcode, uint32_t argument)
- {
- int rv;
-
- rv = sdcard_send_cmd(CMD_APP_CMD, 0);
- if (rv & 0x04)
- return rv;
- return sdcard_send_cmd(opcode, argument);
- }
- static int sdcard_read_block(void *buf, int len, int timeout,
- uint8_t xcmd, uint32_t xarg)
- {
- uint8_t tok;
- uint16_t zcrc;
- xptr_t p;
- int i;
- int badtimeout = 8;
- p.b = buf;
-
- if (xcmd)
- len -= 6;
-
- dbg_puts("sdcard: read token:");
- for (;;) {
- tok = sd_readb(SD_GO8|SD_CLEARCRC);
- dbg_printf(" %02x", tok);
- if (tok == 0xfe)
- break;
- if (tok < 0xfe && !--badtimeout) {
- dbg_printf("\nsdcard: read_block: bad token: %02x\n", tok);
- return -1;
- }
- if (!--timeout) {
- dbg_printf("\nsdcard: read_block: reply timeout\n");
- return -1;
- }
- }
- dbg_putc('\n');
-
-
- if (p.a & 1) {
- *p.b++ = sd_readb(SD_GO8);
- len--;
- }
- sd_readb(SD_GO8);
- if (p.a & 2) {
- *p.w++ = sd_readh(SD_GO16);
- len -= 2;
- }
- if (len >= 6) {
- sd_readh(SD_GO16);
- while (len >= 6) {
- *p.l++ = sd_readl(SD_GO32);
- len -= 4;
- }
- *p.w++ = sd_readh(2);
- len -= 2;
- }
-
- while (len--)
- *p.b++ = sd_readb(SD_GO8 | 1);
-
- if (xcmd) {
- sd_writeb(xcmd, SD_CLEARCRC);
- *p.b++ = sd_readb(SD_GO8 | 1);
- sd_writel(xarg, SD_BE);
- *p.b++ = sd_readb(SD_GO8 | 1);
- *p.b++ = sd_readb(SD_GO8 | 1);
- *p.b++ = sd_readb(SD_GO8 | 1);
- *p.b++ = sd_readb(SD_GO8 | 1);
- sd_writeb(sd_crc7_wr(), 0);
- *p.b++ = sd_readb(SD_GO8 | 1);
- }
-
- zcrc = sd_crc16_rd();
- if (zcrc != 0x0000) {
- con_printf("sdcard_read_block: CRC error (zcrc = %04x)\n", zcrc);
- return -1;
- }
-
- sd_readb(SD_GO8);
- return 0;
- }
- int sdcard_read_sectors(void *buf, uint32_t lba, int count)
- {
- int rv;
- int okcount = 0;
- static const uint16_t stop_transmission[3] =
- { (0x40|CMD_STOP_TRANSMISSION) << 8, 0x0000, 0x0061 };
- uint8_t resp;
- uint8_t *p = buf;
- if (!count)
- return 0;
- sdcard_led_on();
- con_printf("sdcard: reading %d sector%s at %u to %p\n",
- count, (count != 1) ? "s" : "", lba, buf);
- if (sdc.card_type == 1)
- lba <<= SECTOR_SHIFT;
- rv = sdcard_send_cmd(CMD_READ_MULTIPLE_BLOCK, lba);
- if (rv & ~1) {
- con_printf("sdcard: read_multiple error %02x\n", rv);
- goto out;
- }
- while (count--) {
- rv = sdcard_read_block(p, SECTOR_SIZE, 200000,
- count ? 0 : CMD_STOP_TRANSMISSION, 0);
- if (rv)
- goto out;
- okcount++;
- p += SECTOR_SIZE;
- }
-
- sd_readb(SD_GO8);
-
- do {
- resp = sd_readb(SD_GO8);
- } while ((int8_t)resp < 0);
- if (resp) {
- con_printf("sdcard: read_sectors: terminate command error %02x\n",
- resp);
- }
- out:
- sdcard_led_off();
- return okcount;
- }
- DRESULT disk_read(BYTE drive, BYTE *buffer,
- LBA_t sectornumber, UINT sectorcount)
- {
- int rv;
- (void)drive;
- rv = sdcard_read_sectors(buffer, sectornumber, sectorcount);
- return (rv == (int)sectorcount) ? RES_OK : RES_ERROR;
- }
- static int sdcard_read_reg(uint8_t opcode, void *buf, const char *name)
- {
- int rv;
- uint32_t *bp = buf;
- unsigned int i;
- memset(buf, 0, 16);
- con_printf("sdcard: %s:", name);
- rv = sdcard_send_cmd(opcode, 0);
- if (rv & ~1)
- goto err;
- rv = sdcard_read_block(buf, 16, 2000, 0, 0);
- if (rv)
- goto err;
- for (i = 0; i < 4; i++) {
- bp[i] = __builtin_bswap32(bp[i]);
- con_printf(" %08x", bp[i]);
- }
- con_putc('\n');
- return 0;
- err:
- con_printf(" failed, err %02x\n", rv);
- return rv;
- }
- static int sdcard_read_csd(void)
- {
- return sdcard_read_reg(CMD_SEND_CSD, &sdc.csd, "CSD");
- }
- static int sdcard_read_cid(void)
- {
- return sdcard_read_reg(CMD_SEND_CID, &sdc.cid, "CID");
- }
- int sdcard_write_sectors(const void *buf, uint32_t lba, int count)
- {
- int rv;
- int okcount = 0;
- uint16_t crc;
- uint8_t resp;
- xcptr_t p;
- if (!count)
- return 0;
- p.b = buf;
- sdcard_led_on();
- con_printf("sdcard: writing %d sectors at %u from %p\n", count, lba, buf);
- if (sdc.card_type == 1)
- lba <<= SECTOR_SHIFT;
- rv = sdcard_send_cmd(CMD_WRITE_MULTIPLE_BLOCK, lba);
- if (rv) {
- con_printf("sdcard: write_multiple error %02x\n", rv);
- goto out;
- }
- while (count--) {
- unsigned int podd = p.a & 3;
- size_t endloop = (p.a + SECTOR_SIZE) & ~3;
-
- sd_writeb(0xfc, SD_GO8);
-
- sd_writeb(~0, SD_CLEARCRC);
- if (podd & 1)
- sd_writeb(*p.b++, SD_GO8);
- if (podd & 2)
- sd_writeh(*p.w++, SD_GO16);
- while (p.a < endloop)
- sd_writel(*p.l++, SD_GO32);
- podd = -podd;
- if (podd & 2)
- sd_writeh(*p.w++, SD_GO16);
- if (podd & 1)
- sd_writeb(*p.b++, SD_GO8);
- sd_writeh(sd_crc16_wr(), SD_GO16);
-
- do {
- resp = sd_readb(SD_GO8);
- } while ((resp & 0x11) != 0x01);
- resp &= ~0xe0;
- if (resp != 0x05) {
-
- break;
- }
-
- do {
- resp = sd_readb(SD_GO8);
- } while (resp == 0x00);
- okcount++;
- }
-
- sd_writeb(0xfd, SD_GO8);
-
- do {
- resp = sd_readb(SD_GO8);
- } while (resp != 0x00);
- do {
- resp = sd_readb(SD_GO8);
- } while (resp == 0x00);
- out:
- sdcard_led_off();
- return okcount;
- }
- DRESULT disk_write(BYTE drive, const BYTE *buffer, LBA_t sectornumber,
- UINT sectorcount)
- {
- int rv;
- if (drive != 0)
- return STA_NOINIT;
- rv = sdcard_write_sectors(buffer, sectornumber, sectorcount);
- return (rv == (int)sectorcount) ? RES_OK : RES_ERROR;
- }
- DRESULT disk_ioctl(BYTE drive, BYTE command, void *buffer)
- {
- if (drive != 0)
- return STA_NOINIT;
- switch (command) {
- case CTRL_SYNC:
- return RES_OK;
- case GET_SECTOR_SIZE:
- *(WORD *)buffer = 512;
- return RES_OK;
- case GET_SECTOR_COUNT:
- *(DWORD *)buffer = sdc.lbasize;
- return RES_OK;
- case GET_BLOCK_SIZE:
- *(DWORD *)buffer = 1;
- return RES_OK;
- default:
- return RES_PARERR;
- }
- }
- DWORD get_fattime(void)
- {
- return SYSCLOCK_DATETIME;
- }
- static unsigned long sdcard_compute_size(struct sdcard_info *sdi)
- {
- unsigned int c_size;
- unsigned int c_size_mult;
- unsigned int read_bl_len;
- unsigned long lbasize;
- sdi->card_type = (sdi->csd.raw[0] >> 30)+1;
- switch (sdi->card_type) {
- case 1:
- c_size = ((sdi->csd.raw[2] & 0x3ff) << 2) +
- (sdi->csd.raw[3] >> 30);
- c_size_mult = (sdi->csd.raw[2] >> 15) & 7;
- read_bl_len = (sdi->csd.raw[1] >> 16) & 0xf;
- lbasize = (c_size + 1) << (c_size_mult + read_bl_len + 2 - 9);
- break;
- case 2:
- c_size = ((sdi->csd.raw[1] & 0x3f) << 16) +
- (sdi->csd.raw[2] >> 16);
- lbasize = c_size << 10;
- break;
- default:
- sdi->card_type = 0;
- return 0;
- }
- return sdi->lbasize = lbasize;
- }
- static const char *sdcard_type_name(uint8_t type)
- {
- static const char * const names[] = {
- "unknown",
- "SD/MMC",
- "SDHC/SDXC/eMMC"
- };
- if (type >= sizeof names/sizeof names[0])
- type = 0;
- return names[type];
- }
- static void sdcard_try_high_speed(void)
- {
- int rv;
- uint8_t tran_speed;
- return;
- if (!(sdc.csd.raw[1] & (1 << 30)))
- return;
-
- rv = sdcard_send_cmd(CMD_SWITCH_FUNC, 0x80fffff1);
- if (rv & ~1) {
- dbg_printf("sdcard: CMD6 returned %02x\n", rv);
- return;
- }
- if (1) {
-
- uint8_t swdata[64];
- int i;
- for (i = 0; i < 64; i++)
- swdata[i] = sd_readb(SD_GO8);
- if ((swdata[47] & 0x0f) != 1) {
- dbg_printf("sdcard: CMD6 reported %X for high speed request\n",
- swdata[47] & 0x0f);
- return;
- }
- }
-
- sd_readl(SD_GO32);
-
- sdcard_read_csd();
-
- tran_speed = (uint8_t)sdc.csd.raw[0];
- if ((tran_speed & 7) < 2 ||
- ((tran_speed & 7) == 2 && (tran_speed >> 3) < 0xb)) {
- dbg_printf("sdcard: speed switch failed, tran_speed %02x\n",
- tran_speed);
- return;
- }
- sd_set_mode(SD_50MHZ, true);
- con_printf("sdcard: switched to high speed\n");
- }
- DSTATUS disk_initialize(BYTE drive)
- {
- uint16_t status;
- uint32_t try_sdhc;
- bool is_sd;
- int i, j, rv;
- if (drive != 0)
- return STA_NOINIT;
-
- SDCARD_CTL_IRQEN = SDCARD_IRQ_READY;
- memset(&sdc, 0, sizeof sdc);
- #if 0
- status =
- if (!(status & 0x04)) {
- con_printf("No memory card installed\n");
- return sdc.status = STA_NOINIT|STA_NODISK;
- }
- #endif
- sdcard_led_on();
-
- i = 4;
- while (1) {
-
- sd_set_mode(SD_SLOW, false);
- for (j = 0; j < 8; j++)
- sd_writel(~0, SD_GO32);
-
- sd_set_mode(SD_SLOW, true);
- sd_writeb(~0, SD_GO8);
- rv = sdcard_send_cmd(CMD_GO_IDLE_STATE, 0);
- if (rv == 0x01)
- break;
- if (!--i) {
- con_printf("sdcard: reset failed, assuming no card present\n", rv);
- sdcard_led_off();
- return sdc.status = STA_NOINIT | STA_NODISK;
- }
- }
-
- sd_set_mode(SD_20MHZ, true);
-
- sdcard_send_cmd(CMD_CRC_ON_OFF, 0x0001);
-
-
- rv = sdcard_send_cmd(CMD_SEND_IF_COND, 0x01aa);
- if ((rv & 0x04) == 0) {
-
- if (rv & ~0x03) {
- dbg_printf("sdcard; CMD8 error %02x\n", rv);
- sdcard_led_off();
- return sdc.status = STA_NOINIT;
- }
-
- sd_readb(SD_GO8);
- sd_readh(SD_GO16);
- sdc.if_cond = sd_readl(SD_GO16|SD_BE);
- dbg_printf("sdcard: CMD8 returned 0x%08x\n", sdc.if_cond);
- if ((sdc.if_cond & 0x1ff) != 0x1aa) {
- con_printf("sdcard: CMD8 reports unusable card (0x%x)\n",
- sdc.if_cond);
- sdcard_led_off();
- return sdc.status = STA_NOINIT;
- }
- try_sdhc = 1 << 30;
- } else {
- try_sdhc = 0;
- }
-
- do {
- rv = sdcard_send_acmd(ACMD_SD_SEND_OP_COND, try_sdhc);
- if (rv & 0x04)
- break;
- if (rv & ~0x01) {
- con_printf("sdcard: ACMD41 error %02x\n", rv);
- sdcard_led_off();
- return sdc.status = STA_NOINIT;
- }
- } while (rv);
- if (!rv) {
-
- is_sd = true;
- sd_set_mode(SD_25MHZ, true);
- rv = sdcard_send_cmd(CMD_READ_OCR, try_sdhc);
- if (rv) {
- con_printf("sdcard: CMD58 error %02x\n", rv);
- sdcard_led_off();
- return sdc.status = STA_NOINIT;
- }
-
- sd_readb(SD_GO8);
- sd_readh(SD_GO16);
- sdc.ocr = sd_readl(SD_GO16|SD_BE);
- } else {
-
- is_sd = false;
- do {
- rv = sdcard_send_cmd(CMD_SEND_OP_COND, 0);
- if (rv & ~0x01) {
- con_printf("sdcard: CMD1 error %02x\n", rv);
- sdcard_led_off();
- return sdc.status = STA_NOINIT;
- }
- } while (rv);
- }
-
- rv = sdcard_send_cmd(CMD_SET_BLOCKLEN, 512);
- if (rv) {
- con_printf("sdcard: CMD16 error %02x\n", rv);
- sdcard_led_off();
- return sdc.status = STA_NOINIT;
- }
-
- sdcard_read_csd();
-
- if (is_sd)
- sdcard_try_high_speed();
-
- sdcard_read_cid();
- sdcard_compute_size(&sdc);
- con_printf("sdcard: %s card found, capacity %u sectors\n",
- sdcard_type_name(sdc.card_type), sdc.lbasize);
- sdc.status = 0;
- sdcard_led_off();
- return sdc.status;
- }
- DSTATUS disk_status(BYTE drive)
- {
- if (drive != 0)
- return STA_NOINIT;
- return sdc.status;
- }
- static FATFS sd_fs;
- int disk_init(void)
- {
- FRESULT rv;
- char label[128];
- uint32_t volid, freeclust;
- FATFS *fs;
- rv = f_mount(&sd_fs, "", 1);
- if (rv != FR_OK) {
- con_printf("sdcard: no volume found\n");
- return -1;
- }
- label[0] = '\0';
- volid = 0;
- f_getlabel("", label, &volid);
- con_printf("sdcard: volume found, label \"%s\", volid %08x\n", label, volid);
- freeclust = 0;
- f_getfree("", &freeclust, &fs);
- con_printf("sdcard: %u/%u clusters free, clusters = %u bytes\n",
- freeclust, fs->n_fatent - 2, fs->csize << 9);
- return 0;
- }
|