return EOF;
}
-
-#define SD_READ_SINGLEBLOCK 0x51
-
-static size_t sd_readDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t offset, size_t size)
-{
-
- Sd *sd = SD_CAST(b);
- LOG_INFO("reading from block %ld, offset %d, size %d\n", idx, offset, size);
-
- if (sd->tranfer_len != size)
- {
- if ((sd->r1 = sd_setBlockLen(sd, size)))
- {
- LOG_ERR("setBlockLen failed: %04X\n", sd->r1);
- return 0;
- }
- sd->tranfer_len = size;
- }
-
- SD_SELECT(sd);
-
- sd->r1 = sd_sendCommand(sd, SD_READ_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN + offset, 0);
-
- if (sd->r1)
- {
- LOG_ERR("read single block failed: %04X\n", sd->r1);
- sd_select(sd, false);
- return 0;
- }
-
- bool res = sd_getBlock(sd, buf, size);
- sd_select(sd, false);
- if (!res)
- {
- LOG_ERR("read single block failed reading data\n");
- return 0;
- }
- else
- return size;
-}
-
-#define SD_WRITE_SINGLEBLOCK 0x58
-#define SD_DATA_ACCEPTED 0x05
-
-static size_t sd_writeDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size)
-{
- Sd *sd = SD_CAST(b);
- KFile *fd = sd->ch;
- ASSERT(offset == 0);
- ASSERT(size == SD_DEFAULT_BLOCKLEN);
-
- LOG_INFO("writing block %ld\n", idx);
- if (sd->tranfer_len != SD_DEFAULT_BLOCKLEN)
- {
- if ((sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN)))
- {
- LOG_ERR("setBlockLen failed: %04X\n", sd->r1);
- return 0;
- }
- sd->tranfer_len = SD_DEFAULT_BLOCKLEN;
- }
-
- SD_SELECT(sd);
-
- sd->r1 = sd_sendCommand(sd, SD_WRITE_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN, 0);
-
- if (sd->r1)
- {
- LOG_ERR("write single block failed: %04X\n", sd->r1);
- sd_select(sd, false);
- return 0;
- }
-
- kfile_putc(SD_STARTTOKEN, fd);
- kfile_write(fd, buf, SD_DEFAULT_BLOCKLEN);
- /* send fake crc */
- kfile_putc(0, fd);
- kfile_putc(0, fd);
-
- uint8_t dataresp = kfile_getc(fd);
- sd_select(sd, false);
-
- if ((dataresp & 0x1f) != SD_DATA_ACCEPTED)
- {
- LOG_ERR("write block %ld failed: %02X\n", idx, dataresp);
- return EOF;
- }
-
- return SD_DEFAULT_BLOCKLEN;
-}
-
-void sd_writeTest(Sd *sd)
-{
- uint8_t buf[SD_DEFAULT_BLOCKLEN];
- memset(buf, 0, sizeof(buf));
-
- for (block_idx_t i = 0; i < sd->b.blk_cnt; i++)
- {
- LOG_INFO("writing block %ld: %s\n", i, (sd_writeDirect(&sd->b, i, buf, 0, SD_DEFAULT_BLOCKLEN) == SD_DEFAULT_BLOCKLEN) ? "OK" : "FAIL");
- }
-}
-
-
-bool sd_test(Sd *sd)
-{
- uint8_t buf[SD_DEFAULT_BLOCKLEN];
-
- if (sd_readDirect(&sd->b, 0, buf, 0, sd->b.blk_size) != sd->b.blk_size)
- return false;
-
- kputchar('\n');
- for (int i = 0; i < SD_DEFAULT_BLOCKLEN; i++)
- {
- kprintf("%02X ", buf[i]);
- buf[i] = i;
- if (!((i+1) % 16))
- kputchar('\n');
- }
-
- if (sd_writeDirect(&sd->b, 0, buf, 0, SD_DEFAULT_BLOCKLEN) != SD_DEFAULT_BLOCKLEN)
- return false;
-
- memset(buf, 0, sizeof(buf));
- if (sd_readDirect(&sd->b, 0, buf, 0, sd->b.blk_size) != sd->b.blk_size)
- return false;
-
- kputchar('\n');
- for (block_idx_t i = 0; i < sd->b.blk_size; i++)
- {
- kprintf("%02X ", buf[i]);
- buf[i] = i;
- if (!((i+1) % 16))
- kputchar('\n');
- }
-
- return true;
-}
-
-static int sd_error(KBlock *b)
-{
- Sd *sd = SD_CAST(b);
- return sd->r1;
-}
-
-static void sd_clearerr(KBlock *b)
-{
- Sd *sd = SD_CAST(b);
- sd->r1 = 0;
-}
-
-static const KBlockVTable sd_unbuffered_vt =
-{
- .readDirect = sd_readDirect,
- .writeDirect = sd_writeDirect,
-
- .error = sd_error,
- .clearerr = sd_clearerr,
-};
-
-static const KBlockVTable sd_buffered_vt =
-{
- .readDirect = sd_readDirect,
- .writeDirect = sd_writeDirect,
-
- .readBuf = kblock_swReadBuf,
- .writeBuf = kblock_swWriteBuf,
- .load = kblock_swLoad,
- .store = kblock_swStore,
-
- .error = sd_error,
- .clearerr = sd_clearerr,
-};
-
-#define SD_GO_IDLE_STATE 0x40
-#define SD_GO_IDLE_STATE_CRC 0x95
-#define SD_SEND_OP_COND 0x41
-#define SD_SEND_OP_COND_CRC 0xF9
-
-#define SD_START_DELAY 10
-#define SD_INIT_TIMEOUT ms_to_ticks(2000)
-#define SD_IDLE_RETRIES 4
-
-static bool sd_blockInit(Sd *sd, KFile *ch)
-{
- ASSERT(sd);
- ASSERT(ch);
- memset(sd, 0, sizeof(*sd));
- DB(sd->b.priv.type = KBT_SD);
- sd->ch = ch;
-
-
-#if CPU_CM3_SAM3X8
-
- /* Wait a few moments for supply voltage to stabilize */
- timer_delay(SD_START_DELAY);
-
- sd_sendInit();
- sd_goIdle();
-
- sd_sendIfCond(sd);
-
- ticks_t start = timer_clock();
- bool sd_power_on = false;
- do
- {
- if (!sd_sendAppOpCond(sd))
- {
- sd_power_on = true;
- break;
- }
- cpu_relax();
- }
- while (timer_clock() - start < SD_INIT_TIMEOUT);
-
-
- if (sd_power_on)
- {
-
- if(!sd_getCid(sd, 0, SD_SEND_ALL_CID))
- {
- sd_dumpCid(sd);
- }
-
- if (!sd_getRelativeAddr(sd))
- {
- LOG_INFO("RCA: %0lx\n", sd->addr);
- }
-
-
- if (!sd_getCsd(sd))
- {
- sd_dumpCsd(sd);
- }
-
- if (!sd_appStatus(sd))
- {
- LOG_INFO("STATUS: %ld\n", sd->status);
- }
-
- if (sd->status & SD_CARD_IS_LOCKED)
- {
- LOG_INFO("SD is locked!\n");
- }
- else if (sd->status & SD_READY_FOR_DATA)
- {
- sd_selectCard(sd);
- sd_set_BlockLen(sd, SD_DEFAULT_BLOCKLEN);
- sd_setBus4bit(sd);
- sd_setHightSpeed(sd);
- sd_deSelectCard(sd);
- }
-
- }
-#else
- SD_CS_INIT();
- SD_CS_OFF();
-
- /* Wait a few moments for supply voltage to stabilize */
- timer_delay(SD_START_DELAY);
-
- /* Give 80 clk pulses to wake up the card */
- for (int i = 0; i < 10; i++)
- kfile_putc(0xff, ch);
- kfile_flush(ch);
-
- for (int i = 0; i < SD_IDLE_RETRIES; i++)
- {
- SD_SELECT(sd);
- sd->r1 = sd_sendCommand(sd, SD_GO_IDLE_STATE, 0, SD_GO_IDLE_STATE_CRC);
- sd_select(sd, false);
-
- if (sd->r1 == SD_IN_IDLE)
- break;
- }
-
- if (sd->r1 != SD_IN_IDLE)
- {
- LOG_ERR("go_idle_state failed: %04X\n", sd->r1);
- return false;
- }
-
- ticks_t start = timer_clock();
-
- /* Wait for card to start */
- do
- {
- SD_SELECT(sd);
- sd->r1 = sd_sendCommand(sd, SD_SEND_OP_COND, 0, SD_SEND_OP_COND_CRC);
- sd_select(sd, false);
- cpu_relax();
- }
- while (sd->r1 != 0 && timer_clock() - start < SD_INIT_TIMEOUT);
-
- if (sd->r1)
- {
- LOG_ERR("send_op_cond failed: %04X\n", sd->r1);
- return false;
- }
-
- sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN);
- sd->tranfer_len = SD_DEFAULT_BLOCKLEN;
-
- if (sd->r1)
- {
- LOG_ERR("setBlockLen failed: %04X\n", sd->r1);
- return false;
- }
-
- /* Avoid warning for uninitialized csd use (gcc bug?) */
- CardCSD csd = csd;
-
- sd->r1 = sd_getCSD(sd, &csd);
-
- if (sd->r1)
- {
- LOG_ERR("getCSD failed: %04X\n", sd->r1);
- return false;
- }
-
- sd->b.blk_size = SD_DEFAULT_BLOCKLEN;
- sd->b.blk_cnt = csd.block_num * (csd.block_len / SD_DEFAULT_BLOCKLEN);
- LOG_INFO("blk_size %d, blk_cnt %ld\n", sd->b.blk_size, sd->b.blk_cnt);
-#endif
-
-#if CONFIG_SD_AUTOASSIGN_FAT
- disk_assignDrive(&sd->b, 0);
-#endif
-
- return true;
-}
-
#if CPU_CM3_SAM3X8
#include <drv/hsmci_sam3.h>
-/* SD commands type argument response */
- /* class 0 */
-/* This is basically the same command as for MMC with some quirks. */
-#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
-#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
-#define SD_SWITCH_VOLTAGE 11 /* ac R1 */
-
- /* class 10 */
-#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
-
- /* class 5 */
-#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */
-#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */
-
- /* Application commands */
-#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
-#define SD_APP_SD_STATUS 13 /* adtc R1 */
-#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
-#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
-#define SD_APP_SEND_SCR 51 /* adtc R1 */
-
-/* OCR bit definitions */
-#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */
-#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
-#define SD_OCR_XPC (1 << 28) /* SDXC power control */
-
-/*
- * SD_SWITCH argument format:
- *
- * [31] Check (0) or switch (1)
- * [30:24] Reserved (0)
- * [23:20] Function group 6
- * [19:16] Function group 5
- * [15:12] Function group 4
- * [11:8] Function group 3
- * [7:4] Function group 2
- * [3:0] Function group 1
- */
-
-/*
- * SD_SEND_IF_COND argument format:
- *
- * [31:12] Reserved (0)
- * [11:8] Host Voltage Supply Flags
- * [7:0] Check Pattern (0xAA)
- */
-
-/*
- * SCR field definitions
- */
-
-#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
-#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
-#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */
-
-
#define SD_ADDR_TO_RCA(addr) (uint32_t)(((addr) << 16) & 0xFFFF0000)
#define SD_GET_STATE(status) (uint8_t)(((status) & SD_STATUS_CURR_MASK) >> SD_STATUS_CURR_SHIFT)
kputs("\n");
j = 0;
}
- kprintf("%08lx", r[i]);
+ kprintf("%08lx ", r[i]);
j++;
}
kprintf("\n] len=%d\n\n", i);
}
)
-static const uint32_t tran_exp[] = {
+static const uint32_t tran_exp[] =
+{
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
};
-static const uint8_t tran_mant[] = {
+static const uint8_t tran_mant[] =
+{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
hsmci_readResp(&sd->addr, 1);
sd->addr = sd->addr >> 16;
- LOG_INFOB(dump("RCA", &sd->addr, 1););
+ LOG_INFOB(dump("RCA", &sd->addr, 1););
+
+ return 0;
+}
+
+int sd_appStatus(Sd *sd)
+{
+ ASSERT(sd);
+ LOG_INFO("Send to RCA: %lx\n", SD_ADDR_TO_RCA(sd->addr));
+ if (hsmci_sendCmd(13, SD_ADDR_TO_RCA(sd->addr), HSMCI_CMDR_RSPTYP_48_BIT))
+ {
+ LOG_ERR("STATUS: %lx\n", HSMCI_SR);
+ return -1;
+ }
+
+ hsmci_readResp(&(sd->status), 1);
+ LOG_INFOB(dump("STATUS", &(sd->status), 1););
+
+ LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+
+ if (sd->status & SD_STATUS_READY)
+ return 0;
+
+ return -1;
+}
+
+
+INLINE int sd_cardSelection(Sd *sd, uint32_t rca)
+{
+ ASSERT(sd);
+ LOG_INFO("Select RCA: %lx\n", rca);
+ if (hsmci_sendCmd(7, rca, HSMCI_CMDR_RSPTYP_R1B))
+ {
+ LOG_ERR("SELECT_SD: %lx\n", HSMCI_SR);
+ return -1;
+ }
+
+ HSMCI_CHECK_BUSY();
+ hsmci_readResp(&(sd->status), 1);
+ LOG_INFOB(dump("SELECT_SD", &(sd->status), 1););
+
+ LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+
+ if (sd->status & SD_STATUS_READY)
+ return 0;
+
+ return -1;
+}
+
+int sd_selectCard(Sd *sd)
+{
+ ASSERT(sd);
+ uint32_t rca = SD_ADDR_TO_RCA(sd->addr);
+ LOG_INFO("Select RCA: %lx\n", rca);
+ if (hsmci_sendCmd(7, rca, HSMCI_CMDR_RSPTYP_R1B))
+ {
+ LOG_ERR("SELECT_SD: %lx\n", HSMCI_SR);
+ return -1;
+ }
+
+ HSMCI_CHECK_BUSY();
+ hsmci_readResp(&(sd->status), 1);
+
+ LOG_INFOB(dump("SELECT_SD", &(sd->status), 1););
+ LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+
+ if (sd->status & SD_STATUS_READY)
+ return 0;
+
+ return -1;
+}
+
+int sd_deSelectCard(Sd *sd)
+{
+ ASSERT(sd);
+
+ uint32_t rca = 0;
+ if (!sd->addr)
+ rca = SD_ADDR_TO_RCA(sd->addr + 1);
+
+ LOG_INFO("Select RCA: %lx\n", rca);
+
+ if (hsmci_sendCmd(7, rca, HSMCI_CMDR_RSPTYP_NORESP))
+ {
+ LOG_ERR("DESELECT_SD: %lx\n", HSMCI_SR);
+ return -1;
+ }
+
+ return 0;
+
+}
+
+int sd_setBusWidth(Sd *sd, size_t len)
+{
+ ASSERT(sd);
+
+ if (hsmci_sendCmd(55, SD_ADDR_TO_RCA(sd->addr), HSMCI_CMDR_RSPTYP_48_BIT))
+ {
+ LOG_ERR("APP_CMD %lx\n", HSMCI_SR);
+ return -1;
+ }
+
+ hsmci_readResp(&(sd->status), 1);
+ if ((sd->status) & (SD_STATUS_APP_CMD | SD_STATUS_READY))
+ {
+ hsmci_setBusWidth(len);
+
+ uint8_t arg = 0;
+ if (len == 4)
+ arg = 2;
+
+ if (hsmci_sendCmd(6, arg, HSMCI_CMDR_RSPTYP_48_BIT))
+ {
+ LOG_ERR("SET_BUS_WIDTH CMD: %lx\n", HSMCI_SR);
+ return -1;
+ }
+
+ hsmci_readResp(&(sd->status), 1);
+
+ LOG_INFOB(dump("SET_BUS_WIDTH", &(sd->status), 1););
+ LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+
+ if (sd->status & SD_STATUS_READY)
+ return 0;
+ }
+
+ LOG_ERR("SET_BUS_WIDTH REP %lx\n", (sd->status));
+ return -1;
+}
+
+
+int sd_set_BlockLen(Sd *sd, size_t len)
+{
+ ASSERT(sd);
+
+ if (hsmci_sendCmd(16, len, HSMCI_CMDR_RSPTYP_48_BIT))
+ {
+ LOG_ERR("SET_BLK_LEN: %lx\n", HSMCI_SR);
+ return -1;
+ }
+
+ hsmci_readResp(&(sd->status), 1);
+
+ LOG_INFOB(dump("SET_BLK_LEN", &(sd->status), 1););
+ LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+
+ sd->csd.blk_len = len;
+
+ if (sd->status & SD_STATUS_READY)
+ return 0;
- return 0;
+ return -1;
}
-int sd_appStatus(Sd *sd)
+int sd_getStatus(Sd *sd, uint32_t *buf, size_t words)
{
ASSERT(sd);
- LOG_INFO("Send to RCA: %lx\n", SD_ADDR_TO_RCA(sd->addr));
- if (hsmci_sendCmd(13, SD_ADDR_TO_RCA(sd->addr), HSMCI_CMDR_RSPTYP_48_BIT))
+
+ // Status reply with 512bit data, so the block size in byte is 64
+ hsmci_prgRxDMA(buf, words, 64);
+
+ if (hsmci_sendCmd(55, SD_ADDR_TO_RCA(sd->addr), HSMCI_CMDR_RSPTYP_48_BIT))
{
- LOG_ERR("STATUS: %lx\n", HSMCI_SR);
+ LOG_ERR("APP_CMD %lx\n", HSMCI_SR);
return -1;
}
- hsmci_readResp(&(sd->status), 1);
- LOG_INFOB(dump("STATUS", &(sd->status), 1););
+ uint32_t status = HSMCI_RSPR;
+ if (status & (SD_STATUS_APP_CMD | SD_STATUS_READY))
+ {
+ if (hsmci_sendCmd(13, 0, HSMCI_CMDR_RSPTYP_48_BIT |
+ BV(HSMCI_CMDR_TRDIR) | HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE))
+ {
+ LOG_ERR("STATUS CMD: %lx\n", HSMCI_SR);
+ return -1;
+ }
- LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+ hsmci_readResp(&(sd->status), 1);
+ LOG_INFOB(dump("STATUS", &(sd->status), 1););
+ LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
- if (sd->status & SD_STATUS_READY)
- return 0;
+ if (sd->status & SD_STATUS_READY)
+ {
+ hsmci_waitTransfer();
+
+ LOG_INFOB(dump("STATUS", buf, words););
+ memset(&(sd->ssr), 0, sizeof(SDssr));
+
+ sd->ssr.bus_width = UNSTUFF_BITS(buf, 510, 2);
+ sd->ssr.card_type = UNSTUFF_BITS(buf, 480, 16);
+ sd->ssr.au_size = UNSTUFF_BITS(buf, 432, 8);
+ sd->ssr.speed_class = UNSTUFF_BITS(buf, 440, 8);
+ sd->ssr.erase_size = UNSTUFF_BITS(buf, 408, 24);
+
+ return 0;
+ }
+ }
return -1;
}
-INLINE int sd_cardSelection(Sd *sd, uint32_t rca)
+void sd_setHightSpeed(Sd *sd)
{
- ASSERT(sd);
- LOG_INFO("Select RCA: %lx\n", rca);
- if (hsmci_sendCmd(7, rca, HSMCI_CMDR_RSPTYP_R1B))
+ (void)sd;
+ hsmci_setSpeed(2100000, true);
+}
+
+#endif
+
+
+#define SD_START_DELAY 10
+#define SD_INIT_TIMEOUT ms_to_ticks(2000)
+#define SD_IDLE_RETRIES 4
+
+#if CPU_CM3_SAM3X8
+
+static size_t sd_SdReadDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t offset, size_t size)
+{
+ ASSERT(buf);
+ Sd *sd = SD_CAST(b);
+ LOG_INFO("reading from block %ld, offset %d, size %d\n", idx, offset, size);
+
+ if (sd_selectCard(sd) < 0)
+ return -1;
+
+ hsmci_prgRxDMA(buf, size / 4, sd->csd.blk_len);
+
+ if (hsmci_sendCmd(17, idx * sd->csd.blk_len + offset, HSMCI_CMDR_RSPTYP_48_BIT |
+ BV(HSMCI_CMDR_TRDIR) | HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE))
{
- LOG_ERR("SELECT_SD: %lx\n", HSMCI_SR);
+ LOG_ERR("SIGLE_BLK_READ: %lx\n", HSMCI_SR);
+ sd_deSelectCard(sd);
return -1;
}
- HSMCI_CHECK_BUSY();
hsmci_readResp(&(sd->status), 1);
- LOG_INFOB(dump("SELECT_SD", &(sd->status), 1););
+ LOG_INFOB(dump("SIGLE_BLK_READ", &(sd->status), 1););
LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
if (sd->status & SD_STATUS_READY)
- return 0;
+ {
+ hsmci_waitTransfer();
+ sd_deSelectCard(sd);
+ return size;
+ }
+ sd_deSelectCard(sd);
return -1;
}
-int sd_selectCard(Sd *sd)
+static size_t sd_SdWriteDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size)
{
- ASSERT(sd);
- uint32_t rca = SD_ADDR_TO_RCA(sd->addr);
- LOG_INFO("Select RCA: %lx\n", rca);
- if (hsmci_sendCmd(7, rca, HSMCI_CMDR_RSPTYP_R1B))
+ ASSERT(buf);
+ Sd *sd = SD_CAST(b);
+ const uint32_t *_buf = (const uint32_t *)buf;
+ LOG_INFO("reading from block %ld, offset %d, size %d\n", idx, offset, size);
+
+ if (sd_selectCard(sd) < 0)
+ return 0;
+
+ hsmci_prgTxDMA(_buf, size / 4, sd->csd.blk_len);
+
+ if (hsmci_sendCmd(24, idx * sd->csd.blk_len + offset, HSMCI_CMDR_RSPTYP_48_BIT |
+ HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE))
{
- LOG_ERR("SELECT_SD: %lx\n", HSMCI_SR);
+ LOG_ERR("SIGLE_BLK_WRITE: %lx\n", HSMCI_SR);
+ sd_deSelectCard(sd);
return -1;
}
- HSMCI_CHECK_BUSY();
hsmci_readResp(&(sd->status), 1);
- LOG_INFOB(dump("SELECT_SD", &(sd->status), 1););
+ LOG_INFOB(dump("SIGLE_BLK_WR", &(sd->status), 1););
LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
if (sd->status & SD_STATUS_READY)
- return 0;
+ {
+ hsmci_waitTransfer();
+ sd_deSelectCard(sd);
+ return size;
+ }
+ sd_deSelectCard(sd);
return -1;
}
-int sd_deSelectCard(Sd *sd)
+
+static int sd_SdError(KBlock *b)
{
- ASSERT(sd);
+ Sd *sd = SD_CAST(b);
+ return 0;//sd->status;
+}
- uint32_t rca = 0;
- if (!sd->addr)
- rca = SD_ADDR_TO_RCA(sd->addr + 1);
+static void sd_SdClearerr(KBlock *b)
+{
+ Sd *sd = SD_CAST(b);
+ sd->status = 0;
+}
- LOG_INFO("Select RCA: %lx\n", rca);
- if (hsmci_sendCmd(7, rca, HSMCI_CMDR_RSPTYP_NORESP))
+
+static bool sd_SdBlockInit(Sd *sd)
+{
+ /* Wait a few moments for supply voltage to stabilize */
+ timer_delay(SD_START_DELAY);
+
+ sd_sendInit();
+ sd_goIdle();
+
+ sd_sendIfCond(sd);
+
+ ticks_t start = timer_clock();
+ bool sd_power_on = false;
+ do
{
- LOG_ERR("DESELECT_SD: %lx\n", HSMCI_SR);
- return -1;
+ if (!sd_sendAppOpCond(sd))
+ {
+ sd_power_on = true;
+ break;
+ }
+ cpu_relax();
}
+ while (timer_clock() - start < SD_INIT_TIMEOUT);
- return 0;
+ if (sd_power_on)
+ {
+
+ if(sd_getCid(sd, 0, SD_SEND_ALL_CID) < 0)
+ return false;
+ else
+ {
+ sd_dumpCid(sd);
+ }
+
+ if (sd_getRelativeAddr(sd) < 0)
+ return false;
+ else
+ {
+ LOG_INFO("RCA: %0lx\n", sd->addr);
+ }
+
+
+ if (sd_getCsd(sd) < 0)
+ return false;
+ else
+ {
+ sd_dumpCsd(sd);
+ }
+
+ if (sd_appStatus(sd) < 0)
+ {
+ LOG_INFO("STATUS: %ld\n", sd->status);
+ return false;
+ }
+
+ if (sd->status & SD_CARD_IS_LOCKED)
+ {
+ LOG_INFO("SD is locked!\n");
+ return false;
+ }
+
+ if (sd->status & SD_READY_FOR_DATA)
+ {
+ sd_selectCard(sd);
+ sd_set_BlockLen(sd, SD_DEFAULT_BLOCKLEN);
+ sd_setBus4bit(sd);
+ sd_setHightSpeed(sd);
+ sd_deSelectCard(sd);
+
+ sd->b.blk_size = SD_DEFAULT_BLOCKLEN;
+ sd->b.blk_cnt = sd->csd.blk_num * (sd->csd.blk_len / SD_DEFAULT_BLOCKLEN);
+ LOG_INFO("blk_size %d, blk_cnt %ld\n", sd->b.blk_size, sd->b.blk_cnt);
+
+ return true;
+ }
+ }
+
+ return false;
}
+#else
+
+#define SD_READ_SINGLEBLOCK 0x51
-int sd_setBusWidth(Sd *sd, size_t len)
+static size_t sd_SpiReadDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t offset, size_t size)
{
- ASSERT(sd);
- if (hsmci_sendCmd(55, SD_ADDR_TO_RCA(sd->addr), HSMCI_CMDR_RSPTYP_48_BIT))
+ Sd *sd = SD_CAST(b);
+ LOG_INFO("reading from block %ld, offset %d, size %d\n", idx, offset, size);
+
+ if (sd->tranfer_len != size)
{
- LOG_ERR("APP_CMD %lx\n", HSMCI_SR);
- return -1;
+ if ((sd->r1 = sd_setBlockLen(sd, size)))
+ {
+ LOG_ERR("setBlockLen failed: %04X\n", sd->r1);
+ return 0;
+ }
+ sd->tranfer_len = size;
}
- hsmci_readResp(&(sd->status), 1);
- if ((sd->status) & (SD_STATUS_APP_CMD | SD_STATUS_READY))
- {
- hsmci_setBusWidth(len);
+ SD_SELECT(sd);
- uint8_t arg = 0;
- if (len == 4)
- arg = 2;
+ sd->r1 = sd_sendCommand(sd, SD_READ_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN + offset, 0);
- if (hsmci_sendCmd(6, arg, HSMCI_CMDR_RSPTYP_48_BIT))
- {
- LOG_ERR("SET_BUS_WIDTH CMD: %lx\n", HSMCI_SR);
- return -1;
- }
+ if (sd->r1)
+ {
+ LOG_ERR("read single block failed: %04X\n", sd->r1);
+ sd_select(sd, false);
+ return 0;
+ }
- hsmci_readResp(&(sd->status), 1);
+ bool res = sd_getBlock(sd, buf, size);
+ sd_select(sd, false);
+ if (!res)
+ {
+ LOG_ERR("read single block failed reading data\n");
+ return 0;
+ }
+ else
+ return size;
+}
- LOG_INFOB(dump("SET_BUS_WIDTH", &(sd->status), 1););
- LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+#define SD_WRITE_SINGLEBLOCK 0x58
+#define SD_DATA_ACCEPTED 0x05
- if (sd->status & SD_STATUS_READY)
+static size_t sd_SpiWriteDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size)
+{
+ Sd *sd = SD_CAST(b);
+ KFile *fd = sd->ch;
+ ASSERT(offset == 0);
+ ASSERT(size == SD_DEFAULT_BLOCKLEN);
+
+ LOG_INFO("writing block %ld\n", idx);
+ if (sd->tranfer_len != SD_DEFAULT_BLOCKLEN)
+ {
+ if ((sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN)))
+ {
+ LOG_ERR("setBlockLen failed: %04X\n", sd->r1);
return 0;
+ }
+ sd->tranfer_len = SD_DEFAULT_BLOCKLEN;
}
- LOG_ERR("SET_BUS_WIDTH REP %lx\n", (sd->status));
- return -1;
-}
-
+ SD_SELECT(sd);
-int sd_set_BlockLen(Sd *sd, size_t len)
-{
- ASSERT(sd);
+ sd->r1 = sd_sendCommand(sd, SD_WRITE_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN, 0);
- if (hsmci_sendCmd(16, len, HSMCI_CMDR_RSPTYP_48_BIT))
+ if (sd->r1)
{
- LOG_ERR("SET_BLK_LEN: %lx\n", HSMCI_SR);
- return -1;
+ LOG_ERR("write single block failed: %04X\n", sd->r1);
+ sd_select(sd, false);
+ return 0;
}
- hsmci_readResp(&(sd->status), 1);
+ kfile_putc(SD_STARTTOKEN, fd);
+ kfile_write(fd, buf, SD_DEFAULT_BLOCKLEN);
+ /* send fake crc */
+ kfile_putc(0, fd);
+ kfile_putc(0, fd);
- LOG_INFOB(dump("SET_BLK_LEN", &(sd->status), 1););
- LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+ uint8_t dataresp = kfile_getc(fd);
+ sd_select(sd, false);
- sd->csd.blk_len = len;
+ if ((dataresp & 0x1f) != SD_DATA_ACCEPTED)
+ {
+ LOG_ERR("write block %ld failed: %02X\n", idx, dataresp);
+ return EOF;
+ }
- if (sd->status & SD_STATUS_READY)
- return 0;
+ return SD_DEFAULT_BLOCKLEN;
+}
- return -1;
+static int sd_SpiError(KBlock *b)
+{
+ Sd *sd = SD_CAST(b);
+ return sd->r1;
}
-int sd_getStatus(Sd *sd, uint32_t *buf, size_t words)
+static void sd_SpiClearerr(KBlock *b)
{
- ASSERT(sd);
+ Sd *sd = SD_CAST(b);
+ sd->r1 = 0;
+}
- // Status reply with 512bit data, so the block size in byte is 64
- hsmci_prgRxDMA(buf, words, 64);
- if (hsmci_sendCmd(55, SD_ADDR_TO_RCA(sd->addr), HSMCI_CMDR_RSPTYP_48_BIT))
- {
- LOG_ERR("APP_CMD %lx\n", HSMCI_SR);
- return -1;
- }
- uint32_t status = HSMCI_RSPR;
- if (status & (SD_STATUS_APP_CMD | SD_STATUS_READY))
- {
- if (hsmci_sendCmd(13, 0, HSMCI_CMDR_RSPTYP_48_BIT |
- BV(HSMCI_CMDR_TRDIR) | HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE))
- {
- LOG_ERR("STATUS CMD: %lx\n", HSMCI_SR);
- return -1;
- }
+#define SD_GO_IDLE_STATE 0x40
+#define SD_GO_IDLE_STATE_CRC 0x95
+#define SD_SEND_OP_COND 0x41
+#define SD_SEND_OP_COND_CRC 0xF9
- hsmci_readResp(&(sd->status), 1);
- LOG_INFOB(dump("STATUS", &(sd->status), 1););
- LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+static bool sd_SpiBlockInit(Sd *sd, KFile *ch)
+{
+ sd->ch = ch;
- if (sd->status & SD_STATUS_READY)
- {
- hsmci_waitTransfer();
+ SD_CS_INIT();
+ SD_CS_OFF();
- LOG_INFOB(dump("STATUS", buf, words););
- memset(&(sd->ssr), 0, sizeof(SDssr));
+ /* Wait a few moments for supply voltage to stabilize */
+ timer_delay(SD_START_DELAY);
- sd->ssr.bus_width = UNSTUFF_BITS(buf, 510, 2);
- sd->ssr.card_type = UNSTUFF_BITS(buf, 480, 16);
- sd->ssr.au_size = UNSTUFF_BITS(buf, 432, 8);
- sd->ssr.speed_class = UNSTUFF_BITS(buf, 440, 8);
- sd->ssr.erase_size = UNSTUFF_BITS(buf, 408, 24);
+ /* Give 80 clk pulses to wake up the card */
+ for (int i = 0; i < 10; i++)
+ kfile_putc(0xff, ch);
+ kfile_flush(ch);
- return 0;
- }
+ for (int i = 0; i < SD_IDLE_RETRIES; i++)
+ {
+ SD_SELECT(sd);
+ sd->r1 = sd_sendCommand(sd, SD_GO_IDLE_STATE, 0, SD_GO_IDLE_STATE_CRC);
+ sd_select(sd, false);
+
+ if (sd->r1 == SD_IN_IDLE)
+ break;
}
- return -1;
-}
+ if (sd->r1 != SD_IN_IDLE)
+ {
+ LOG_ERR("go_idle_state failed: %04X\n", sd->r1);
+ return false;
+ }
+ ticks_t start = timer_clock();
+ /* Wait for card to start */
+ do
+ {
+ SD_SELECT(sd);
+ sd->r1 = sd_sendCommand(sd, SD_SEND_OP_COND, 0, SD_SEND_OP_COND_CRC);
+ sd_select(sd, false);
+ cpu_relax();
+ }
+ while (sd->r1 != 0 && timer_clock() - start < SD_INIT_TIMEOUT);
-int sd_readSingleBlock(Sd *sd, size_t index, uint32_t *buf, size_t words)
-{
- ASSERT(sd);
- ASSERT(buf);
+ if (sd->r1)
+ {
+ LOG_ERR("send_op_cond failed: %04X\n", sd->r1);
+ return false;
+ }
- hsmci_prgRxDMA(buf, words, sd->csd.blk_len);
+ sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN);
+ sd->tranfer_len = SD_DEFAULT_BLOCKLEN;
- if (hsmci_sendCmd(17, index * sd->csd.blk_len, HSMCI_CMDR_RSPTYP_48_BIT |
- BV(HSMCI_CMDR_TRDIR) | HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE))
+ if (sd->r1)
{
- LOG_ERR("SIGLE_BLK_READ: %lx\n", HSMCI_SR);
- return -1;
+ LOG_ERR("setBlockLen failed: %04X\n", sd->r1);
+ return false;
}
- hsmci_readResp(&(sd->status), 1);
- LOG_INFOB(dump("SIGLE_BLK_READ", &(sd->status), 1););
- LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+ /* Avoid warning for uninitialized csd use (gcc bug?) */
+ CardCSD csd = csd;
- if (sd->status & SD_STATUS_READY)
+ sd->r1 = sd_getCSD(sd, &csd);
+
+ if (sd->r1)
{
- hsmci_waitTransfer();
- return words;
+ LOG_ERR("getCSD failed: %04X\n", sd->r1);
+ return false;
}
- return -1;
+ sd->b.blk_size = SD_DEFAULT_BLOCKLEN;
+ sd->b.blk_cnt = csd.block_num * (csd.block_len / SD_DEFAULT_BLOCKLEN);
+ LOG_INFO("blk_size %d, blk_cnt %ld\n", sd->b.blk_size, sd->b.blk_cnt);
+ return true;
}
+#endif
-int sd_writeSingleBlock(Sd *sd, size_t index, uint32_t *buf, size_t words)
+static bool sd_blockInit(Sd *sd, KFile *ch)
{
ASSERT(sd);
- ASSERT(buf);
-
- hsmci_prgTxDMA(buf, words, sd->csd.blk_len);
-
- if (hsmci_sendCmd(24, index * sd->csd.blk_len, HSMCI_CMDR_RSPTYP_48_BIT |
- HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE))
- {
- LOG_ERR("SIGLE_BLK_WRITE: %lx\n", HSMCI_SR);
- return -1;
- }
- hsmci_readResp(&(sd->status), 1);
+ ASSERT(ch);
+ memset(sd, 0, sizeof(*sd));
+ DB(sd->b.priv.type = KBT_SD);
- LOG_INFOB(dump("SIGLE_BLK_WR", &(sd->status), 1););
- LOG_INFO("State[%d]\n", SD_GET_STATE(sd->status));
+#if CPU_CM3_SAM3X8
+ if (!sd_SdBlockInit(sd))
+ return false;
+#else
+ if (!sd_SpiBlockInit(sd, ch))
+ return false;
+#endif
- if (sd->status & SD_STATUS_READY)
- {
- hsmci_waitTransfer();
- return words;
- }
+#if CONFIG_SD_AUTOASSIGN_FAT
+ disk_assignDrive(&sd->b, 0);
+#endif
- return -1;
+ return true;
}
+#if CPU_CM3_SAM3X8
+#define sd_writeDirect sd_SdWriteDirect
+#define sd_readDirect sd_SdReadDirect
+#define sd_error sd_SdError
+#define sd_clearerr sd_SdClearerr
+#else
+#define sd_writeDirect sd_SpiWriteDirect
+#define sd_readDirect sd_SpiReadDirect
+#define sd_error sd_SpiError
+#define sd_clearerr sd_SpiClearerr
-void sd_setHightSpeed(Sd *sd)
+#endif
+
+static const KBlockVTable sd_unbuffered_vt =
{
- (void)sd;
- hsmci_setSpeed(2100000, true);
-}
+ .readDirect = sd_readDirect,
+ .writeDirect = sd_writeDirect,
+ .error = sd_error,
+ .clearerr = sd_clearerr,
+};
-#endif
+static const KBlockVTable sd_buffered_vt =
+{
+ .readDirect = sd_readDirect,
+ .writeDirect = sd_writeDirect,
+ .readBuf = kblock_swReadBuf,
+ .writeBuf = kblock_swWriteBuf,
+ .load = kblock_swLoad,
+ .store = kblock_swStore,
+
+ .error = sd_error,
+ .clearerr = sd_clearerr,
+};
bool sd_initUnbuf(Sd *sd, KFile *ch)
{
}
+void sd_writeTest(Sd *sd)
+{
+ uint8_t buf[SD_DEFAULT_BLOCKLEN];
+ memset(buf, 0, sizeof(buf));
+
+ for (block_idx_t i = 0; i < sd->b.blk_cnt; i++)
+ {
+ LOG_INFO("writing block %ld: %s\n", i, (sd_writeDirect(&sd->b, i, buf, 0, SD_DEFAULT_BLOCKLEN) == SD_DEFAULT_BLOCKLEN) ? "OK" : "FAIL");
+ }
+}
+
+
+bool sd_test(Sd *sd)
+{
+ uint8_t buf[SD_DEFAULT_BLOCKLEN];
+
+ if (sd_readDirect(&sd->b, 0, buf, 0, sd->b.blk_size) != sd->b.blk_size)
+ return false;
+
+ kputchar('\n');
+ for (int i = 0; i < SD_DEFAULT_BLOCKLEN; i++)
+ {
+ kprintf("%02X ", buf[i]);
+ buf[i] = i;
+ if (!((i+1) % 16))
+ kputchar('\n');
+ }
+
+ if (sd_writeDirect(&sd->b, 0, buf, 0, SD_DEFAULT_BLOCKLEN) != SD_DEFAULT_BLOCKLEN)
+ return false;
+
+ memset(buf, 0, sizeof(buf));
+ if (sd_readDirect(&sd->b, 0, buf, 0, sd->b.blk_size) != sd->b.blk_size)
+ return false;
+
+ kputchar('\n');
+ for (block_idx_t i = 0; i < sd->b.blk_size; i++)
+ {
+ kprintf("%02X ", buf[i]);
+ buf[i] = i;
+ if (!((i+1) % 16))
+ kputchar('\n');
+ }
+
+ return true;
+}
+
+