From fc7c7130fee73c5aad2d7a774d5a7712eb3e8e6a Mon Sep 17 00:00:00 2001 From: Uros Majstorovic Date: Thu, 8 Apr 2021 21:30:12 +0200 Subject: sdcard driver --- fw/fe310/eos/Makefile | 2 +- fw/fe310/eos/board.h | 8 +- fw/fe310/eos/eos.c | 2 + fw/fe310/eos/sdcard.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++ fw/fe310/eos/sdcard.h | 3 + fw/fe310/eos/spi.c | 4 +- fw/fe310/eos/spi.h | 2 +- fw/fe310/eos/timer.c | 4 + fw/fe310/eos/timer.h | 1 + 9 files changed, 332 insertions(+), 8 deletions(-) create mode 100644 fw/fe310/eos/sdcard.c create mode 100644 fw/fe310/eos/sdcard.h (limited to 'fw/fe310/eos') diff --git a/fw/fe310/eos/Makefile b/fw/fe310/eos/Makefile index 0b3d6fe..66ac136 100644 --- a/fw/fe310/eos/Makefile +++ b/fw/fe310/eos/Makefile @@ -2,7 +2,7 @@ include ../common.mk CFLAGS += -I. -I../bsp/include -I../bsp/drivers -obj = trap_entry.o eos.o msgq.o event.o interrupt.o timer.o power.o i2s.o i2c.o uart.o spi.o spi_dev.o net.o wifi.o cell.o sock.o unicode.o +obj = trap_entry.o eos.o msgq.o event.o interrupt.o timer.o power.o i2s.o i2c.o uart.o spi.o spi_dev.o sdcard.o net.o wifi.o cell.o sock.o unicode.o %.o: %.c %.h diff --git a/fw/fe310/eos/board.h b/fw/fe310/eos/board.h index e663f62..1299bb6 100644 --- a/fw/fe310/eos/board.h +++ b/fw/fe310/eos/board.h @@ -1,19 +1,19 @@ #define SPI_DIV_NET 16 #define SPI_DIV_EVE 16 -#define SPI_DIV_SDC 16 +#define SPI_DIV_SDC 1024 #define SPI_DIV_CAM 16 #define SPI_CSID_NET 3 #define SPI_CSID_EVE 2 -#define SPI_CSID_SDC 0 +#define SPI_CSID_SDC SPI_CSID_NONE #define SPI_CSID_CAM SPI_CSID_NONE #define SPI_CSPIN_NET SPI_CSPIN_NONE #define SPI_CSPIN_EVE SPI_CSPIN_NONE -#define SPI_CSPIN_SDC SPI_CSPIN_NONE +#define SPI_CSPIN_SDC 2 #define SPI_CSPIN_CAM 23 -#define SPI_IOF_MASK_CS (((uint32_t)1 << IOF_SPI1_SS0) | ((uint32_t)1 << IOF_SPI1_SS2) | ((uint32_t)1 << IOF_SPI1_SS3)) +#define SPI_IOF_MASK_CS (((uint32_t)1 << IOF_SPI1_SS2) | ((uint32_t)1 << IOF_SPI1_SS3)) #define NET_PIN_RTS 20 #define NET_PIN_CTS 22 diff --git a/fw/fe310/eos/eos.c b/fw/fe310/eos/eos.c index aa374a0..87b414b 100644 --- a/fw/fe310/eos/eos.c +++ b/fw/fe310/eos/eos.c @@ -8,6 +8,7 @@ #include "uart.h" #include "spi.h" #include "spi_dev.h" +#include "sdcard.h" #include "net.h" #include "wifi.h" #include "cell.h" @@ -30,6 +31,7 @@ void eos_init(void) { eos_uart_init(); eos_spi_init(); eos_spi_dev_init(); + eos_sdc_init(); eos_net_init(); eos_power_init(); eos_wifi_init(); diff --git a/fw/fe310/eos/sdcard.c b/fw/fe310/eos/sdcard.c new file mode 100644 index 0000000..8162a3e --- /dev/null +++ b/fw/fe310/eos/sdcard.c @@ -0,0 +1,314 @@ +#include +#include + +#include "eos.h" +#include "timer.h" + +#include "spi.h" +#include "spi_dev.h" + +#include "sdcard.h" + +#define SDC_POLY_CRC7 0x09 +#define SDC_POLY_CRC16 0x1021 + +#define SDC_CMD_FLAG_CRC 0x01 +#define SDC_CMD_FLAG_NOCS 0x02 +#define SDC_CMD_FLAG_SKIP 0x08 + +#define SDC_TOKEN_START_BLK 0xfe +#define SDC_TOKEN_START_BLKM 0xfc +#define SDC_TOKEN_STOP_TRAN 0xfd + +#define SDC_R1_READY 0x00 + +#define SDC_R1_IDLE_STATE 0x01 +#define SDC_R1_ERASE_RESET 0x02 +#define SDC_R1_ILLEGAL_CMD 0x04 +#define SDC_R1_ERR_CMD_CRC 0x08 +#define SDC_R1_ERR_ERASE_SEQ 0x10 +#define SDC_R1_ERR_ADDR 0x20 +#define SDC_R1_ERR_PARAM 0x40 + +#define SDC_NCR 10 + +#define SDC_TYPE_MMC 1 +#define SDC_TYPE_SDC1 2 +#define SDC_TYPE_SDC2 3 + +#define SDC_ERR(rv) ((rv < 0) ? rv : EOS_ERR) + +/* CMD */ +#define GO_IDLE_STATE 0 +#define SEND_OP_COND 1 +#define SEND_IF_COND 8 +#define SET_BLOCKLEN 16 +#define APP_CMD 55 +#define READ_OCR 58 + +/* ACMD */ +#define SD_APP_OP_COND 41 + +static uint8_t sdc_crc7(uint8_t crc, uint8_t b) { + int i; + + for (i=8; i--; b<<=1) { + crc <<= 1; + if ((b ^ crc) & 0x80) crc ^= SDC_POLY_CRC7; + } + return crc & 0x7f; +} + +static uint16_t sdc_crc16(uint16_t crc, uint8_t b) { + int i; + + crc = crc ^ ((uint16_t)b << 8); + for (i=8; i--;) { + if (crc & 0x8000) { + crc = (crc << 1) ^ SDC_POLY_CRC16; + } else { + crc <<= 1; + } + } + return crc; +} + +static uint32_t sdc_nto(uint64_t start, uint32_t timeout) { + uint32_t d = eos_time_since(start); + return (d > timeout) ? 0 : timeout - d; +} + +static void sdc_xchg(unsigned char *buffer, uint16_t len) { +} + +static uint8_t sdc_xchg8(uint8_t data) { + return eos_spi_xchg8(data, 0); +} + +static uint16_t sdc_xchg16(uint16_t data) { + return eos_spi_xchg16(data, 0); +} + +static uint32_t sdc_xchg32(uint32_t data) { + return eos_spi_xchg32(data, 0); +} + +static void sdc_select(void) { + eos_spi_cs_set(); + eos_spi_xchg8(0xff, 0); +} + +static void sdc_deselect(void) { + eos_spi_cs_clear(); + eos_spi_xchg8(0xff, 0); +} + +static int sdc_xchg_cmd(uint8_t cmd, uint32_t arg, uint8_t flags) { + int i; + uint8_t ret; + uint8_t crc = 0x7f; + + cmd |= 0x40; + if (flags & SDC_CMD_FLAG_CRC) { + crc = sdc_crc7(0, cmd); + crc = sdc_crc7(crc, arg >> 24); + crc = sdc_crc7(crc, arg >> 16); + crc = sdc_crc7(crc, arg >> 8); + crc = sdc_crc7(crc, arg); + } + crc = (crc << 1) | 0x01; + sdc_xchg8(cmd); + sdc_xchg32(arg); + sdc_xchg8(crc); + if (flags & SDC_CMD_FLAG_SKIP) sdc_xchg8(0xff); + + i = SDC_NCR; + do { + ret = sdc_xchg8(0xff); + } while ((ret & 0x80) && --i); + if (ret & 0x80) return EOS_ERR_BUSY; + + return ret; +} + +static int sdc_ready(uint32_t timeout) { + uint8_t d = 0; + uint64_t start; + + if (timeout == 0) return EOS_ERR_BUSY; + start = eos_time_get_tick(); + do { + if (eos_time_since(start) > timeout) break; + d = sdc_xchg8(0xff); + } while (d != 0xff); + if (d != 0xff) return EOS_ERR_BUSY; + + return EOS_OK; +} + +static int sdc_block_read(uint8_t *buffer, uint16_t len, uint32_t timeout) { + uint8_t token = 0xff; + uint64_t start; + + if (timeout == 0) return EOS_ERR_BUSY; + start = eos_time_get_tick(); + do { + if (eos_time_since(start) > timeout) break; + token = sdc_xchg8(0xff); + } while (token == 0xff); + if (token == 0xff) return EOS_ERR_BUSY; + if (token != SDC_TOKEN_START_BLK) return EOS_ERR; + + sdc_xchg(buffer, len); + sdc_xchg16(0xff); /* dummy CRC */ + + return EOS_OK; +} + +static int sdc_block_write(uint8_t token, uint8_t *buffer, uint16_t len, uint32_t timeout) { + uint8_t d; + int rv; + + rv = sdc_ready(timeout); + if (rv) return rv; + + sdc_xchg8(token); + if (buffer && len) { + sdc_xchg(buffer, len); + sdc_xchg16(0xff); /* dummy CRC */ + + d = sdc_xchg8(0xff); /* Response */ + if ((d & 0x1f) != 0x05) return EOS_ERR; + } + + return EOS_OK; +} + +static int sdc_cmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) { + int do_cs = !(flags & SDC_CMD_FLAG_NOCS); + int rv; + + if (do_cs) sdc_select(); + rv = sdc_ready(timeout); + if (rv) { + if (do_cs) sdc_deselect(); + return rv; + } + rv = sdc_xchg_cmd(cmd, arg, flags); + if (do_cs) sdc_deselect(); + return rv; +} + +static int sdc_acmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) { + int rv; + uint64_t start; + + if (flags & SDC_CMD_FLAG_NOCS) return EOS_ERR; + + start = eos_time_get_tick(); + rv = sdc_cmd(APP_CMD, 0, flags & SDC_CMD_FLAG_CRC, timeout); + if (rv & ~SDC_R1_IDLE_STATE) return rv; + + return sdc_cmd(cmd, arg, flags, sdc_nto(start, timeout)); +} + +static int sdc_init(uint32_t timeout, uint8_t *type, uint8_t *lba) { + uint8_t _type, _lba; + int rv, i; + uint8_t ocr[4]; + uint64_t start; + + _type = 0; + _lba = 0; + + start = eos_time_get_tick(); + sdc_select(); + for (i=10; i--;) sdc_xchg8(0xff); /* 80 dummy cycles */ + rv = sdc_cmd(GO_IDLE_STATE, 0, SDC_CMD_FLAG_CRC | SDC_CMD_FLAG_NOCS, timeout); + if (rv != SDC_R1_IDLE_STATE) return SDC_ERR(rv); + sdc_deselect(); + + sdc_select(); + rv = sdc_cmd(SEND_IF_COND, 0x1aa, SDC_CMD_FLAG_CRC | SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout)); + switch (rv) { + case SDC_R1_IDLE_STATE: + for (i=0; i<4; i++) { + ocr[i] = sdc_xchg8(0xff); /* get R7 resp */ + } + sdc_deselect(); + if (ocr[2] == 0x01 && ocr[3] == 0xaa) { /* Check voltage range: 2.7-3.6V */ + do { + rv = sdc_acmd(SD_APP_OP_COND, 0x40000000, 0, sdc_nto(start, timeout)); + } while (rv == SDC_R1_IDLE_STATE); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + + sdc_select(); + rv = sdc_cmd(READ_OCR, 0, SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout)); + if (rv == SDC_R1_READY) { + for (i=0; i<4; i++) { + ocr[i] = sdc_xchg8(0xff); + } + sdc_deselect(); + } else { + sdc_deselect(); + return SDC_ERR(rv); + } + + _type = SDC_TYPE_SDC2; + if (ocr[0] & 0xc0) _lba = 1; + } + break; + + case SDC_R1_IDLE_STATE | SDC_R1_ILLEGAL_CMD: + sdc_deselect(); + rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout)); + switch (rv) { + case SDC_R1_IDLE_STATE: + do { + rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout)); + } while (rv == SDC_R1_IDLE_STATE); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + case SDC_R1_READY: + _type = SDC_TYPE_SDC1; + break; + + default: + do { + rv = sdc_cmd(SEND_OP_COND, 0, 0, sdc_nto(start, timeout)); + } while (rv == SDC_R1_IDLE_STATE); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + _type = SDC_TYPE_MMC; + break; + + } + break; + + default: + sdc_deselect(); + return SDC_ERR(rv); + } + + if (_type && !_lba) { + rv = sdc_cmd(SET_BLOCKLEN, 512, 0, sdc_nto(start, timeout)); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + } + *type = _type; + *lba = _lba; + return EOS_OK; +} + +#include + +void eos_sdc_init(void) { + uint8_t type, lba; + int rv; + + eos_spi_select(EOS_SPI_DEV_SDC); + rv = sdc_init(5000, &type, &lba); + if (rv) { + printf("SDC ERROR\n"); + } else { + printf("SDC OK:%d %d\n", type, lba); + } + eos_spi_deselect(); +} diff --git a/fw/fe310/eos/sdcard.h b/fw/fe310/eos/sdcard.h new file mode 100644 index 0000000..a0a1ae3 --- /dev/null +++ b/fw/fe310/eos/sdcard.h @@ -0,0 +1,3 @@ +#include + +void eos_sdc_init(void); diff --git a/fw/fe310/eos/spi.c b/fw/fe310/eos/spi.c index 2966ab9..c5e953e 100644 --- a/fw/fe310/eos/spi.c +++ b/fw/fe310/eos/spi.c @@ -69,7 +69,7 @@ void eos_spi_init(void) { // SPI1_REG(SPI_REG_CSDEF) = 0xFFFF; } -void eos_spi_start(uint8_t div, uint8_t csid, uint8_t cspin, unsigned char evt) { +void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt) { spi_state_flags = 0; spi_evt = evt; SPI1_REG(SPI_REG_SCKDIV) = div; @@ -77,8 +77,8 @@ void eos_spi_start(uint8_t div, uint8_t csid, uint8_t cspin, unsigned char evt) if (csid != SPI_CSID_NONE) { SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; } else { - SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF; spi_cspin = cspin; + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF; } eos_intr_set_handler(INT_SPI1_BASE, eos_spi_handle_xchg); } diff --git a/fw/fe310/eos/spi.h b/fw/fe310/eos/spi.h index 1463c66..06db0d0 100644 --- a/fw/fe310/eos/spi.h +++ b/fw/fe310/eos/spi.h @@ -11,7 +11,7 @@ #define EOS_SPI_MAX_EVT 2 void eos_spi_init(void); -void eos_spi_start(uint8_t div, uint8_t csid, uint8_t cspin, unsigned char evt); +void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt); void eos_spi_stop(void); void eos_spi_set_handler(unsigned char evt, eos_evt_handler_t handler); diff --git a/fw/fe310/eos/timer.c b/fw/fe310/eos/timer.c index e07b9a6..d8cf107 100644 --- a/fw/fe310/eos/timer.c +++ b/fw/fe310/eos/timer.c @@ -129,3 +129,7 @@ uint64_t eos_time_get_tick(void) { volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); return *mtime; } + +uint32_t eos_time_since(uint32_t start) { + return (eos_time_get_tick() - start) * 1000 / EOS_TIMER_RTC_FREQ; + } diff --git a/fw/fe310/eos/timer.h b/fw/fe310/eos/timer.h index 2ac53f7..99ffa7a 100644 --- a/fw/fe310/eos/timer.h +++ b/fw/fe310/eos/timer.h @@ -20,3 +20,4 @@ void eos_timer_clear(unsigned char evt); void eos_time_sleep(uint32_t msec); uint64_t eos_time_get_tick(void); +uint32_t eos_time_since(uint32_t start); -- cgit v1.2.3