47#include "dev/watchdog.h"
57#define SECTOR_SIZE BLOCK_LEN
60#define CLOCK_FREQ_CARD_ID_MODE 400000
65#define CLOCK_FREQ_DATA_XFER_MODE 20000000
71#define CMD8_VHS_2_7_3_6 0x1
72#define CMD8_ARG(vhs, check_pattern) ((vhs) << 8 | (check_pattern))
73#define CMD8_ECHO_MASK 0x00000fff
90#define ACMD13 (ACMD | 13)
91#define ACMD23 (ACMD | 23)
92#define ACMD41 (ACMD | 41)
93#define ACMD41_HCS (1 << 30)
98#define R1_SUCCESS 0x00
99#define R1_IDLE_STATE (1 << 0)
100#define R1_ERASE_RESET (1 << 1)
101#define R1_ILLEGAL_COMMAND (1 << 2)
102#define R1_COM_CRC_ERROR (1 << 3)
103#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
104#define R1_ADDRESS_ERROR (1 << 5)
105#define R1_PARAMETER_ERROR (1 << 6)
107#define TOK_DATA_RESP_MASK 0x1f
108#define TOK_DATA_RESP_ACCEPTED 0x05
109#define TOK_DATA_RESP_CRC_ERROR 0x0b
110#define TOK_DATA_RESP_WR_ERROR 0x0d
111#define TOK_RD_SINGLE_WR_START_BLOCK 0xfe
112#define TOK_MULTI_WR_START_BLOCK 0xfc
113#define TOK_MULTI_WR_STOP_TRAN 0xfd
116#define SD_STATUS_SIZE (512 / 8)
117#define SD_STATUS_AU_SIZE(sd_status) ((sd_status)[10] >> 4)
119#define OCR_CCS (1 << 30)
122#define CSD_STRUCTURE(csd) ((csd)[0] >> 6)
123#define CSD_STRUCTURE_SD_V1_0 0
124#define CSD_STRUCTURE_SD_V2_0 1
125#define CSD_SD_V1_0_READ_BL_LEN(csd) ((csd)[5] & 0x0f)
126#define CSD_SD_V1_0_BLOCK_LEN(csd) (1ull << CSD_SD_V1_0_READ_BL_LEN(csd))
127#define CSD_SD_V1_0_C_SIZE(csd) \
128 (((csd)[6] & 0x03) << 10 | (csd)[7] << 2 | (csd)[8] >> 6)
129#define CSD_SD_V1_0_C_SIZE_MULT(csd) \
130 (((csd)[9] & 0x03) << 1 | (csd)[10] >> 7)
131#define CSD_SD_V1_0_MULT(csd) \
132 (1 << (CSD_SD_V1_0_C_SIZE_MULT(csd) + 2))
133#define CSD_SD_V1_0_BLOCKNR(csd) \
134 (((uint32_t)CSD_SD_V1_0_C_SIZE(csd) + 1) * CSD_SD_V1_0_MULT(csd))
135#define CSD_SD_V1_0_CAPACITY(csd) \
136 (CSD_SD_V1_0_BLOCKNR(csd) * CSD_SD_V1_0_BLOCK_LEN(csd))
137#define CSD_SD_V1_0_SECTOR_SIZE(csd) \
138 (((csd)[10] & 0x3f) << 1 | (csd)[11] >> 7)
139#define CSD_SD_V1_0_WRITE_BL_LEN(csd) \
140 (((csd)[12] & 0x03) << 2 | (csd)[13] >> 6)
141#define CSD_SD_V2_0_C_SIZE(csd) \
142 (((csd)[7] & 0x3f) << 16 | (csd)[8] << 8 | (csd)[9])
143#define CSD_SD_V2_0_CAPACITY(csd) \
144 (((uint64_t)CSD_SD_V2_0_C_SIZE(csd) + 1) << 19)
145#define CSD_MMC_ERASE_GRP_SIZE(csd) (((csd)[10] & 0x7c) >> 2)
146#define CSD_MMC_ERASE_GRP_MULT(csd) \
147 (((csd)[10] & 0x03) << 3 | (csd)[11] >> 5)
148#define CSD_MMC_WRITE_BL_LEN(csd) \
149 (((csd)[12] & 0x03) << 2 | (csd)[13] >> 6)
152 CARD_TYPE_MMC = 0x01,
153 CARD_TYPE_SD1 = 0x02,
154 CARD_TYPE_SD2 = 0x04,
155 CARD_TYPE_SD = CARD_TYPE_SD1 | CARD_TYPE_SD2,
156 CARD_TYPE_BLOCK = 0x08
159static struct mmc_priv {
166mmc_spi_xchg(uint8_t dev, uint8_t tx_byte)
175mmc_spi_tx(uint8_t dev,
const void *buf,
size_t cnt)
181mmc_spi_rx(uint8_t dev,
void *buf,
size_t cnt)
187mmc_wait_ready(uint8_t dev, uint16_t timeout_ms)
189 rtimer_clock_t timeout_end =
194 rx_byte = mmc_spi_xchg(dev, 0xff);
196 }
while(rx_byte != 0xff && RTIMER_CLOCK_LT(
RTIMER_NOW(), timeout_end));
197 return rx_byte == 0xff;
201mmc_select(uint8_t dev,
bool sel)
204 mmc_spi_xchg(dev, 0xff);
205 if(sel && !mmc_wait_ready(dev, 500)) {
206 mmc_select(dev,
false);
213mmc_send_cmd(uint8_t dev, uint8_t cmd, uint32_t arg)
220 resp = mmc_send_cmd(dev, CMD55, 0);
221 if(resp != R1_SUCCESS && resp != R1_IDLE_STATE) {
230 mmc_select(dev,
false);
231 if(!mmc_select(dev,
true)) {
237 mmc_spi_xchg(dev, CMD_TX | cmd);
238 mmc_spi_xchg(dev, arg >> 24);
239 mmc_spi_xchg(dev, arg >> 16);
240 mmc_spi_xchg(dev, arg >> 8);
241 mmc_spi_xchg(dev, arg);
253 mmc_spi_xchg(dev, n);
257 mmc_spi_xchg(dev, 0xff);
262 resp = mmc_spi_xchg(dev, 0xff);
263 }
while((resp & 0x80) != R1_MSB && --n);
268mmc_tx_block(uint8_t dev,
const void *buf, uint8_t token)
272 if(!mmc_wait_ready(dev, 500)) {
276 mmc_spi_xchg(dev, token);
277 if(token != TOK_MULTI_WR_STOP_TRAN) {
278 mmc_spi_tx(dev, buf, BLOCK_LEN);
279 mmc_spi_xchg(dev, 0xff);
280 mmc_spi_xchg(dev, 0xff);
282 resp = mmc_spi_xchg(dev, 0xff);
283 if((resp & TOK_DATA_RESP_MASK) != TOK_DATA_RESP_ACCEPTED) {
291mmc_rx(uint8_t dev,
void *buf,
size_t cnt)
293 rtimer_clock_t timeout_end =
298 token = mmc_spi_xchg(dev, 0xff);
300 }
while(token == 0xff && RTIMER_CLOCK_LT(
RTIMER_NOW(), timeout_end));
301 if(token != TOK_RD_SINGLE_WR_START_BLOCK) {
305 mmc_spi_rx(dev, buf, cnt);
306 mmc_spi_xchg(dev, 0xff);
307 mmc_spi_xchg(dev, 0xff);
328 mmc_priv[dev].status = status;
332mmc_status(uint8_t dev)
335 struct mmc_priv *priv;
342 priv = &mmc_priv[dev];
350mmc_initialize(uint8_t dev)
354 card_type_t card_type;
355 rtimer_clock_t timeout_end;
356 uint32_t arg, resp, ocr;
357 struct mmc_priv *priv;
362 status = mmc_status(dev);
371 for(n = 10; n; n--) {
372 mmc_spi_xchg(dev, 0xff);
376 if(mmc_send_cmd(dev, CMD0, 0) == R1_IDLE_STATE) {
378 arg = CMD8_ARG(CMD8_VHS_2_7_3_6, 0xaa);
379 if(mmc_send_cmd(dev, CMD8, arg) == R1_IDLE_STATE) {
382 resp = resp << 8 | mmc_spi_xchg(dev, 0xff);
385 if((arg & CMD8_ECHO_MASK) == (resp & CMD8_ECHO_MASK)) {
387 while(RTIMER_CLOCK_LT(
RTIMER_NOW(), timeout_end) &&
388 mmc_send_cmd(dev, ACMD41, ACMD41_HCS) != R1_SUCCESS) {
391 if(RTIMER_CLOCK_LT(
RTIMER_NOW(), timeout_end) &&
392 mmc_send_cmd(dev, CMD58, 0) == R1_SUCCESS) {
395 ocr = ocr << 8 | mmc_spi_xchg(dev, 0xff);
397 card_type = CARD_TYPE_SD2;
399 card_type |= CARD_TYPE_BLOCK;
404 resp = mmc_send_cmd(dev, ACMD41, 0);
405 if(resp == R1_SUCCESS || resp == R1_IDLE_STATE) {
406 card_type = CARD_TYPE_SD1;
409 card_type = CARD_TYPE_MMC;
413 while(RTIMER_CLOCK_LT(
RTIMER_NOW(), timeout_end) &&
414 mmc_send_cmd(dev, cmd, 0) != R1_SUCCESS) {
418 if(!RTIMER_CLOCK_LT(
RTIMER_NOW(), timeout_end) ||
419 mmc_send_cmd(dev, CMD16, BLOCK_LEN) != R1_SUCCESS) {
424 priv = &mmc_priv[dev];
425 priv->card_type = card_type;
426 mmc_select(dev,
false);
428 status = priv->status;
433 status &= ~DISK_STATUS_INIT;
435 priv->status = status;
440mmc_read(uint8_t dev,
void *buff, uint32_t sector, uint32_t
count)
449 if(!(mmc_priv[dev].card_type & CARD_TYPE_BLOCK)) {
450 sector *= SECTOR_SIZE;
454 if(mmc_send_cmd(dev, CMD17, sector) == R1_SUCCESS &&
455 mmc_rx(dev, buff, SECTOR_SIZE)) {
458 }
else if(mmc_send_cmd(dev, CMD18, sector) == R1_SUCCESS) {
460 if(!mmc_rx(dev, buff, SECTOR_SIZE)) {
463 buff = (uint8_t *)buff + SECTOR_SIZE;
466 mmc_send_cmd(dev, CMD12, 0);
468 mmc_select(dev,
false);
473mmc_write(uint8_t dev,
const void *buff, uint32_t sector, uint32_t
count)
476 card_type_t card_type;
481 status = mmc_status(dev);
489 card_type = mmc_priv[dev].card_type;
490 if(!(card_type & CARD_TYPE_BLOCK)) {
491 sector *= SECTOR_SIZE;
495 if(mmc_send_cmd(dev, CMD24, sector) == R1_SUCCESS &&
496 mmc_tx_block(dev, buff, TOK_RD_SINGLE_WR_START_BLOCK)) {
500 if(card_type & CARD_TYPE_SD) {
501 mmc_send_cmd(dev, ACMD23,
count);
503 if(mmc_send_cmd(dev, CMD25, sector) == R1_SUCCESS) {
505 if(!mmc_tx_block(dev, buff, TOK_MULTI_WR_START_BLOCK)) {
508 buff = (uint8_t *)buff + BLOCK_LEN;
511 if(!mmc_tx_block(dev, NULL, TOK_MULTI_WR_STOP_TRAN)) {
516 mmc_select(dev,
false);
521mmc_ioctl(uint8_t dev, uint8_t cmd,
void *buff)
523 card_type_t card_type;
525 uint8_t csd[CSD_SIZE], sd_status[SD_STATUS_SIZE], au_size;
529 static const uint8_t AU_TO_BLOCK_SIZE[] = {12, 16, 24, 32, 64};
538 card_type = mmc_priv[dev].card_type;
543 if(mmc_select(dev,
true)) {
549 if(mmc_send_cmd(dev, CMD9, 0) == R1_SUCCESS && mmc_rx(dev, csd, CSD_SIZE)) {
550 capacity = CSD_STRUCTURE(csd) == CSD_STRUCTURE_SD_V2_0 ?
551 CSD_SD_V2_0_CAPACITY(csd) : CSD_SD_V1_0_CAPACITY(csd);
552 *(uint32_t *)buff = capacity / SECTOR_SIZE;
558 *(uint16_t *)buff = SECTOR_SIZE;
563 if(card_type & CARD_TYPE_SD2) {
564 if(mmc_send_cmd(dev, ACMD13, 0) == R1_SUCCESS) {
565 mmc_spi_xchg(dev, 0xff);
566 if(mmc_rx(dev, sd_status, SD_STATUS_SIZE)) {
567 au_size = SD_STATUS_AU_SIZE(sd_status);
569 block_size = au_size <= 0xa ? 8192ull << au_size :
570 (uint32_t)AU_TO_BLOCK_SIZE[au_size - 0xb] << 20;
571 *(uint32_t *)buff = block_size / SECTOR_SIZE;
576 }
else if(mmc_send_cmd(dev, CMD9, 0) == R1_SUCCESS &&
577 mmc_rx(dev, csd, CSD_SIZE)) {
578 if(card_type & CARD_TYPE_SD1) {
579 block_size = (uint32_t)(CSD_SD_V1_0_SECTOR_SIZE(csd) + 1) <<
580 CSD_SD_V1_0_WRITE_BL_LEN(csd);
582 block_size = (uint32_t)(CSD_MMC_ERASE_GRP_SIZE(csd) + 1) *
583 (CSD_MMC_ERASE_GRP_MULT(csd) + 1) <<
584 CSD_MMC_WRITE_BL_LEN(csd);
586 *(uint32_t *)buff = block_size / SECTOR_SIZE;
595 mmc_select(dev,
false);
601 .initialize = mmc_initialize,
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
void watchdog_periodic(void)
Writes the WDT clear sequence.
static volatile uint64_t count
Num.
disk_result_t
Disk access result codes.
disk_status_t
Disk status flags.
@ DISK_RESULT_IO_ERROR
Unrecoverable I/O error.
@ DISK_RESULT_INVALID_ARG
Invalid argument.
@ DISK_RESULT_WR_PROTECTED
Write-protected medium.
@ DISK_RESULT_NO_INIT
Device not initialized.
@ DISK_IOCTL_GET_SECTOR_SIZE
Get the sector size through the uint16_t pointed to by buff.
@ DISK_IOCTL_GET_BLOCK_SIZE
Get the erase block size (in sectors) through the uint32_t pointed to by buff.
@ DISK_IOCTL_GET_SECTOR_COUNT
Get the sector count through the uint32_t pointed to by buff.
@ DISK_IOCTL_CTRL_SYNC
Synchronize the cached writes to persistent storage.
@ DISK_STATUS_WRITABLE
Writable medium.
@ DISK_STATUS_INIT
Device initialized and ready to work.
@ DISK_STATUS_DISK
Medium present in the drive.
@ DISK_STATUS_ERROR
Device error.
void mmc_arch_spi_set_clock_freq(uint8_t dev, uint32_t freq)
Sets the SPI clock frequency.
bool mmc_arch_get_cd(uint8_t dev)
Gets the state of the card-detection signal.
bool mmc_arch_get_wp(uint8_t dev)
Gets the state of the write-protection signal.
void mmc_arch_spi_xfer(uint8_t dev, const void *tx_buf, size_t tx_cnt, void *rx_buf, size_t rx_cnt)
Performs an SPI transfer.
void mmc_arch_spi_select(uint8_t dev, bool sel)
Sets the SPI /CS signal as indicated.
void mmc_arch_cd_changed_callback(uint8_t dev, bool cd)
Callback of the SD/MMC driver to call when the card-detection signal changes.
#define MMC_CONF_DEV_COUNT
Number of SD/MMC devices.
#define RTIMER_SECOND
Number of rtimer ticks for 1 second.
#define RTIMER_NOW()
Get the current clock time.
Header file for the SD/MMC device driver architecture-specific definitions.
Header file for the SD/MMC device driver.
Header file for the real-time timer module.
Disk driver API structure.
disk_status_t(* status)(uint8_t dev)
Get device status.