commit 99d13f86eea7beecd38116632d704b65b5897a88
Author: Marcin Bukat <marcin.bukat@gmail.com>
Date: Tue Jul 16 21:02:52 2013 +0200
sd rework WIP
Change-Id: I9e8db66338d9bd6bebe7abf309ef37f9ba06edc5
diff --git a/firmware/target/arm/rk27xx/sd-rk27xx.c b/firmware/target/arm/rk27xx/sd-rk27xx.c
index cb870c9..29f6f35 100644
--- a/firmware/target/arm/rk27xx/sd-rk27xx.c
+++ b/firmware/target/arm/rk27xx/sd-rk27xx.c
@@ -47,11 +47,6 @@
#include <stdarg.h>
#include "sysfont.h"
-#define RES_NO (-1)
-
-/* debug stuff */
-unsigned long sd_debug_time_rd = 0;
-unsigned long sd_debug_time_wr = 0;
static tCardInfo card_info;
@@ -66,11 +61,79 @@ static struct event_queue sd_queue;
bool sd_enabled = false;
#endif
+struct sdmmc_command {
+ uint32_t opcode; /* sd command opcode */
+ uint32_t arg; /* sd command argument */
+ uint32_t flags; /* flags coding response type */
+ uint32_t rsp[4]; /* command response buffer */
+ uint32_t retries; /* no of retries */
+ bool error; /* command error indicator */
+};
+
+struct sdmmc_data {
+ void *buf; /* data transfer buffer */
+ uint32_t blksz; /* transfer block size */
+ uint32_t blkcnt; /* transfer block count */
+ uint32_t flags; /* flags coding transfer direction */
+ uint32_t error; /* data transfer error indicator */
+};
+
+struct sdmmc_request {
+ struct sdmmc_command *cmd;
+ struct sdmmc_data *data;
+ struct sdmmc_command *stop;
+};
+
+#define SDMMC_CMD_PREPARE(o,a,f) cmd.opcode = (o); \
+ cmd.arg = (a); \
+ cmd.flags = (f)
+
+#define SDMMC_STP_PREPARE(o,a,f) stp.opcode = (o); \
+ stp.arg = (a); \
+ stp.flags = (f)
+
+#define SDMMC_DAT_PREPARE(b,s,c,f) dat.buf = (void *)(b); \
+ dat.blksz = (s); \
+ dat.blkcnt = (c); \
+ dat.flags = (f)
+
+#define SDMMC_REQ_PREPARE(c,d,s) req.cmd = (c); \
+ req.data = (d); \
+ req.stop = (s)
+
+static struct sdmmc_request req;
+static struct sdmmc_command cmd, stp;
+static struct sdmmc_data dat;
+
+#define SDMMC_RSP_NONE (0)
+#define SDMMC_RSP_R1 (1<<0)
+#define SDMMC_RSP_R1B (1<<1)
+#define SDMMC_RSP_R2 (1<<2)
+#define SDMMC_RSP_R3 (1<<3)
+#define SDMMC_RSP_R4 (1<<4)
+#define SDMMC_RSP_R5 (1<<5)
+#define SDMMC_RSP_R6 (1<<6)
+#define SDMMC_RSP_R7 (1<<7)
+
+
+#define SDMMC_DIR_WRITE (0)
+#define SDMMC_DIR_READ (1)
+
+/* in Hz */
+#define SDMMC_FREQ_INIT (400000)
+#define SDMMC_FREQ_NORMAL (25000000)
+
+
+/********** hw specific part ************/
static struct semaphore transfer_completion_signal;
static struct semaphore command_completion_signal;
static volatile bool retry;
static volatile int cmd_error;
+/* debug stuff */
+unsigned long sd_debug_time_rd = 0;
+unsigned long sd_debug_time_wr = 0;
+
/* interrupt handler for SD */
void INT_SD(void)
{
@@ -105,9 +168,9 @@ void INT_SD(void)
*/
static void mmu_switch_buff(void)
{
- static unsigned int i = 0;
+ static unsigned int i = 1;
- if (i++ & 0x01)
+ if (i ^= 1)
{
MMU_CTRL = MMU_MMU0_BUFII | MMU_CPU_BUFI | MMU_BUFII_RESET |
MMU_BUFII_BYTE | MMU_BUFI_RESET | MMU_BUFI_WORD;
@@ -139,125 +202,286 @@ static inline bool card_detect_target(void)
#endif
}
-/* Send command to the SD card. Command finish is signaled in ISR */
-static bool send_cmd(const int cmd, const int arg, const int res,
- unsigned long *response)
+
+static inline void controller_read_data(void *dst, uint32_t blksz)
{
- SD_CMD = arg;
+ commit_discard_dcache_range((const void *)dst, blksz);
- if (res > 0)
- SD_CMDREST = CMD_XFER_START | RES_XFER_START | res | cmd;
- else
- SD_CMDREST = CMD_XFER_START | RES_XFER_END | RES_R1 | cmd;
+ A2A_IDST0 = (unsigned long)dst;
+ A2A_ICNT0 = blksz;
+ A2A_CON0 = (3<<9) | /* burst 16 */
+ (1<<6) | /* fixed src */
+ (1<<3) | /* DMA start */
+ (2<<1) | /* word transfer size */
+ (1<<0); /* software mode */
- semaphore_wait(&command_completion_signal, TIMEOUT_BLOCK);
+ /* wait for DMA engine to finish transfer */
+ while (A2A_DMA_STS & 1);
+}
- /* Handle command responses & errors */
- if(res != RES_NO)
- {
- if(cmd_error & STAT_CMD_RES_ERR)
- return false;
+static inline void controller_write_data(void *src, uint32_t blksz)
+{
+ commit_discard_dcache_range((const void *)src, blksz);
- if(res == RES_R2)
- {
- response[0] = SD_RES3;
- response[1] = SD_RES2;
- response[2] = SD_RES1;
- response[3] = SD_RES0;
- }
- else
- response[0] = SD_RES3;
- }
- return true;
+ A2A_ISRC1 = (unsigned long)src;
+ A2A_ICNT1 = blksz;
+ A2A_CON1 = (3<<9) | /* burst 16 */
+ (1<<5) | /* fixed dst */
+ (1<<3) | /* DMA start */
+ (2<<1) | /* word transfer size */
+ (1<<0); /* software mode */
+
+ /* wait for DMA engine to finish transfer */
+ while (A2A_DMA_STS & 2);
}
-#if 0
-/* for some misterious reason the card does not report itself as being in TRAN
- * but transfers are successful. Rockchip OF does not check the card state
- * after SELECT. I checked two different cards.
- */
-static void print_card_status(void)
+static int sd_wait_card_busy(void)
{
- unsigned long response;
- send_cmd(SD_SEND_STATUS, card_info.rca, RES_R1,
- &response);
+ unsigned int timeout = current_tick + 5*HZ;
+
+ while (!(SD_CARD & SD_CARD_BSY))
+ {
+ if(TIME_AFTER(current_tick, timeout))
+ return -1;
+ }
- printf("card status: 0x%0x, state: 0x%0x", response, (response>>9)&0xf);
+ return 0;
}
-static int sd_wait_for_tran_state(void)
+static void rk27xx_sd_cmd(struct sdmmc_command *cmd)
{
- unsigned long response;
- unsigned int timeout = current_tick + 5*HZ;
- int cmd_retry = 10;
+ SD_CMD = cmd->arg;
- while (1)
+ switch (cmd->flags)
{
- while (!send_cmd(SD_SEND_STATUS, card_info.rca, RES_R1,
- &response) && cmd_retry > 0)
+ case SDMMC_RSP_NONE:
+ case SDMMC_RSP_R4:
+ case SDMMC_RSP_R7:
+ SD_CMDREST = CMD_XFER_START | RES_XFER_END | cmd->opcode;
+ break;
+
+ case SDMMC_RSP_R1:
+ SD_CMDREST = CMD_XFER_START | RES_XFER_START | RES_R1 | cmd->opcode;
+ break;
+
+ case SDMMC_RSP_R1B:
+ SD_CMDREST = CMD_XFER_START | RES_XFER_START | RES_R1b | cmd->opcode;
+ break;
+
+ case SDMMC_RSP_R2:
+ SD_CMDREST = CMD_XFER_START | RES_XFER_START | RES_R2 | cmd->opcode;
+ break;
+
+ case SDMMC_RSP_R3:
+ SD_CMDREST = CMD_XFER_START | RES_XFER_START | RES_R3 | cmd->opcode;
+ break;
+
+ case SDMMC_RSP_R6:
+ SD_CMDREST = CMD_XFER_START | RES_XFER_START | RES_R6 | cmd->opcode;
+ }
+
+ semaphore_wait(&command_completion_signal, HZ);
+
+ if (cmd->flags != SDMMC_RSP_NONE)
+ {
+ cmd->error = (cmd_error & STAT_CMD_RES_ERR) ? true : false;
+
+ cmd->rsp[0] = SD_RES3;
+ if (cmd->flags == SDMMC_RSP_R2)
{
- cmd_retry--;
+ cmd->rsp[1] = SD_RES2;
+ cmd->rsp[2] = SD_RES1;
+ cmd->rsp[3] = SD_RES0;
}
-
- if (cmd_retry <= 0)
+ else if (cmd->flags == SDMMC_RSP_R1B)
{
- return -1;
+ sd_wait_card_busy();
}
+ }
+}
+
+/* considers only reads for now */
+static void rk27xx_sd_data(struct sdmmc_data *data)
+{
+ uint32_t xfercnt = data->blkcnt;
+ void *xferbuf = data->buf;
+
+ mmu_buff_reset();
- if (((response >> 9) & 0xf) == SD_TRAN)
+ if (data->flags & SDMMC_DIR_READ)
+ {
+ /* first block */
+ SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
+ DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
+ ((xfercnt == 1) ? DATA_XFER_SINGLE : DATA_XFER_MULTI);
+
+ semaphore_wait(&transfer_completion_signal, HZ);
+
+ while(--xfercnt)
{
- return 0;
+ mmu_switch_buff();
+
+ SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
+ DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
+ ((xfercnt == 1) ? DATA_XFER_SINGLE : DATA_XFER_MULTI);
+
+ controller_read_data(xferbuf, data->blksz);
+ xferbuf = (void *)((unsigned char *)xferbuf + data->blksz);
+
+ semaphore_wait(&transfer_completion_signal, HZ);
}
-
- if(TIME_AFTER(current_tick, timeout))
+
+ /* last block */
+ mmu_switch_buff();
+ controller_read_data(xferbuf, data->blksz);
+ }
+ else
+ {
+ controller_write_data(xferbuf, data->blksz);
+ mmu_switch_buff();
+
+ /* first block */
+ SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
+ DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
+ ((xfercnt == 1) ? DATA_XFER_SINGLE : DATA_XFER_MULTI);
+
+ while(--xfercnt)
{
- return -10 * ((response >> 9) & 0xf);
+ xferbuf = (void *)((unsigned char *)xferbuf + data->blksz);
+ controller_write_data(xferbuf, data->blksz);
+
+ semaphore_wait(&transfer_completion_signal, HZ);
+
+ mmu_switch_buff();
+
+ SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
+ DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
+ ((xfercnt == 1) ? DATA_XFER_SINGLE : DATA_XFER_MULTI);
}
- last_disk_activity = current_tick;
+ /* wait for last block to finish */
+ semaphore_wait(&transfer_completion_signal, HZ);
}
}
-#endif
-static bool sd_wait_card_busy(void)
+/* all in one prototype */
+static void sdmmc_command(struct sdmmc_request *req)
{
- unsigned int timeout = current_tick + 5*HZ;
+ if (req->cmd != NULL)
+ rk27xx_sd_cmd(req->cmd);
- while (!(SD_CARD & SD_CARD_BSY))
+ if (req->data != NULL)
+ rk27xx_sd_data(req->data);
+
+ if (req->stop != NULL)
+ rk27xx_sd_cmd(req->stop);
+}
+
+static void controller_set_freq(int freq)
+{
+ if (freq == SDMMC_FREQ_INIT)
+ /* assume 50 MHz APB freq / 125 = 400 kHz */
+ SD_CTRL = (SD_CTRL & ~(0x7FF)) | 0x7D;
+ else
+ /* Card back to full speed 25MHz*/
+ SD_CTRL = (SD_CTRL & ~0x7FF);
+}
+
+static void init_controller(void)
+{
+ /* reset SD module */
+ SCU_RSTCFG |= RSTCFG_SD;
+ sleep(1);
+ SCU_RSTCFG &= ~RSTCFG_SD;
+
+ /* set pins functions as SD signals */
+ SCU_IOMUXA_CON |= IOMUX_SD;
+
+ /* enable and unmask SD interrupts in interrupt controller */
+ SCU_CLKCFG &= ~CLKCFG_SD;
+ INTC_IMR |= IRQ_ARM_SD;
+ INTC_IECR |= IRQ_ARM_SD;
+
+ SD_CTRL = SD_PWR_CPU | SD_DETECT_MECH | SD_CLOCK_EN | 0x7D;
+ SD_INT = CMD_RES_INT_EN | DATA_XFER_INT_EN;
+ SD_CARD = SD_CARD_SELECT | SD_CARD_PWR_EN;
+
+ /* setup mmu buffers */
+ MMU_PNRI = 0x1ff;
+ MMU_PNRII = 0x1ff;
+ MMU_CTRL = MMU_MMU0_BUFII | MMU_CPU_BUFI | MMU_BUFII_RESET |
+ MMU_BUFII_BYTE | MMU_BUFI_RESET | MMU_BUFI_WORD;
+
+ /* setup A2A DMA CH0 for SD reads */
+ A2A_ISRC0 = (unsigned long)(&MMU_DATA);
+ A2A_ICNT0 = 512;
+ A2A_LCNT0 = 1;
+
+ /* setup A2A DMA CH1 for SD writes */
+ A2A_IDST1 = (unsigned long)(&MMU_DATA);
+ A2A_ICNT1 = 512;
+ A2A_LCNT1 = 1;
+
+ /* src and dst for CH0 and CH1 is AHB0 */
+ A2A_DOMAIN = 0;
+
+#ifdef RK27XX_SD_DEBUG
+ /* setup Timer1 for profiling purposes */
+ TMR1CON = (1<<8)|(1<<3);
+#endif
+
+ semaphore_init(&transfer_completion_signal, 1, 0);
+ semaphore_init(&command_completion_signal, 1, 0);
+}
+
+void sd_enable(bool on)
+{
+ /* enable or disable clock signal for SD module */
+ if (on)
{
- if(TIME_AFTER(current_tick, timeout))
- return false;
+ SCU_CLKCFG &= ~CLKCFG_SD;
+ led(true);
+ }
+ else
+ {
+ SCU_CLKCFG |= CLKCFG_SD;
+ led(false);
}
-
- return true;
}
+/************ SDMMC core **************/
static int sd_init_card(void)
{
- unsigned long response;
long init_timeout;
bool sd_v2 = false;
+ uint32_t buf[16];
card_info.rca = 0;
- /* assume 50 MHz APB freq / 125 = 400 kHz */
- SD_CTRL = (SD_CTRL & ~(0x7FF)) | 0x7D;
-
/* 100 - 400kHz clock required for Identification Mode */
+ controller_set_freq(SDMMC_FREQ_INIT);
+
/* Start of Card Identification Mode ************************************/
+ SDMMC_CMD_PREPARE(SD_GO_IDLE_STATE, 0, SDMMC_RSP_NONE);
+ SDMMC_REQ_PREPARE(&cmd, NULL, NULL);
/* CMD0 Go Idle */
- if(!send_cmd(SD_GO_IDLE_STATE, 0, RES_NO, NULL))
+ sdmmc_command(&req);
+
+ if (req.cmd->error)
return -1;
sleep(1);
+ SDMMC_CMD_PREPARE(SD_SEND_IF_COND, 0x1aa, SDMMC_RSP_R6);
/* CMD8 Check for v2 sd card. Must be sent before using ACMD41
Non v2 cards will not respond to this command*/
- if(send_cmd(SD_SEND_IF_COND, 0x1AA, RES_R6, &response))
- if((response & 0xFFF) == 0x1AA)
- sd_v2 = true;
+ sdmmc_command(&req);
+ if (!req.cmd->error)
+ if ((req.cmd->rsp[0] & 0xFFF) == 0x1AA)
+ sd_v2 = true;
+
/* Timeout for inintialization is 2 sec.
According to SD Specification 2.00 it should be >= 1,
but it's not enough in some rare cases. */
@@ -268,47 +492,72 @@ static int sd_init_card(void)
if(TIME_AFTER(current_tick, init_timeout))
return -2;
- if(!send_cmd(SD_APP_CMD, card_info.rca, RES_R1, &response))
+ SDMMC_CMD_PREPARE(SD_APP_CMD, card_info.rca, SDMMC_RSP_R1);
+ sdmmc_command(&req);
+
+ if (req.cmd->error)
return -3;
sleep(1); /* bus conflict otherwise */
- /* ACMD41 For v2 cards set HCS bit[30] & send host voltage range to all */
- if(!send_cmd(SD_APP_OP_COND, (0x00FF8000 | (sd_v2 ? 1<<30 : 0)),
- RES_R3, &card_info.ocr))
+ /* ACMD41 For v2 cards set HCS bit[30] & send host voltage range to all */
+ SDMMC_CMD_PREPARE(SD_APP_OP_COND, (0x00FF8000 | (sd_v2 ? 1<<30 : 0)), SDMMC_RSP_R3);
+ sdmmc_command(&req);
+ if (req.cmd->error)
return -4;
+
+ card_info.ocr = req.cmd->rsp[0];
} while(!(card_info.ocr & (1<<31)) );
/* CMD2 send CID */
- if(!send_cmd(SD_ALL_SEND_CID, 0, RES_R2, card_info.cid))
+ SDMMC_CMD_PREPARE(SD_ALL_SEND_CID, 0, SDMMC_RSP_R2);
+ sdmmc_command(&req);
+
+ if (req.cmd->error)
return -5;
+ memcpy(card_info.cid, req.cmd->rsp, sizeof(card_info.cid));
+
/* CMD3 send RCA */
- if(!send_cmd(SD_SEND_RELATIVE_ADDR, 0, RES_R6, &card_info.rca))
+ SDMMC_CMD_PREPARE(SD_SEND_RELATIVE_ADDR, 0, SDMMC_RSP_R6);
+ sdmmc_command(&req);
+
+ if (req.cmd->error)
return -6;
+ card_info.rca = req.cmd->rsp[0];
/* End of Card Identification Mode ************************************/
-
/* CMD9 send CSD */
- if(!send_cmd(SD_SEND_CSD, card_info.rca, RES_R2, card_info.csd))
+ SDMMC_CMD_PREPARE(SD_SEND_CSD, card_info.rca, SDMMC_RSP_R2);
+ sdmmc_command(&req);
+
+ if (req.cmd->error)
return -11;
+ memcpy(card_info.csd, req.cmd->rsp, sizeof(card_info.csd));
+
sd_parse_csd(&card_info);
- if(!send_cmd(SD_SELECT_CARD, card_info.rca, RES_R1b, &response))
- return -20;
+ SDMMC_CMD_PREPARE(SD_SELECT_CARD, card_info.rca, SDMMC_RSP_R1B);
+ sdmmc_command(&req);
- if (!sd_wait_card_busy())
- return -21;
+ if (req.cmd->error)
+ return -20;
/* CMD6 */
- if(!send_cmd(SD_SWITCH_FUNC, 0x80fffff1, RES_R1, &response))
+ SDMMC_CMD_PREPARE(SD_SWITCH_FUNC, 0x80fffff1, SDMMC_RSP_R1);
+ SDMMC_DAT_PREPARE(buf, 64, 1, SDMMC_DIR_READ);
+ SDMMC_REQ_PREPARE(&cmd, &dat, NULL);
+ sdmmc_command(&req);
+
+ if (req.cmd->error)
return -8;
- sleep(HZ/10);
- /* Card back to full speed 25MHz*/
- SD_CTRL = (SD_CTRL & ~0x7FF);
+ //sleep(HZ/10);
+
+ controller_set_freq(SDMMC_FREQ_NORMAL);
+
card_info.initialized = 1;
return 0;
@@ -394,57 +643,10 @@ static void sd_thread(void)
}
}
-static void init_controller(void)
-{
- /* reset SD module */
- SCU_RSTCFG |= RSTCFG_SD;
- sleep(1);
- SCU_RSTCFG &= ~RSTCFG_SD;
-
- /* set pins functions as SD signals */
- SCU_IOMUXA_CON |= IOMUX_SD;
-
- /* enable and unmask SD interrupts in interrupt controller */
- SCU_CLKCFG &= ~CLKCFG_SD;
- INTC_IMR |= IRQ_ARM_SD;
- INTC_IECR |= IRQ_ARM_SD;
-
- SD_CTRL = SD_PWR_CPU | SD_DETECT_MECH | SD_CLOCK_EN | 0x7D;
- SD_INT = CMD_RES_INT_EN | DATA_XFER_INT_EN;
- SD_CARD = SD_CARD_SELECT | SD_CARD_PWR_EN;
-
- /* setup mmu buffers */
- MMU_PNRI = 0x1ff;
- MMU_PNRII = 0x1ff;
- MMU_CTRL = MMU_MMU0_BUFII | MMU_CPU_BUFI | MMU_BUFII_RESET |
- MMU_BUFII_BYTE | MMU_BUFI_RESET | MMU_BUFI_WORD;
-
- /* setup A2A DMA CH0 for SD reads */
- A2A_ISRC0 = (unsigned long)(&MMU_DATA);
- A2A_ICNT0 = 512;
- A2A_LCNT0 = 1;
-
- /* setup A2A DMA CH1 for SD writes */
- A2A_IDST1 = (unsigned long)(&MMU_DATA);
- A2A_ICNT1 = 512;
- A2A_LCNT1 = 1;
-
- /* src and dst for CH0 and CH1 is AHB0 */
- A2A_DOMAIN = 0;
-
-#ifdef RK27XX_SD_DEBUG
- /* setup Timer1 for profiling purposes */
- TMR1CON = (1<<8)|(1<<3);
-#endif
-}
-
int sd_init(void)
{
int ret;
- semaphore_init(&transfer_completion_signal, 1, 0);
- semaphore_init(&command_completion_signal, 1, 0);
-
init_controller();
ret = sd_init_card();
@@ -461,39 +663,7 @@ int sd_init(void)
return 0;
}
-static inline void read_sd_data(unsigned char **dst)
-{
- commit_discard_dcache_range((const void *)*dst, 512);
-
- A2A_IDST0 = (unsigned long)*dst;
- A2A_CON0 = (3<<9) | /* burst 16 */
- (1<<6) | /* fixed src */
- (1<<3) | /* DMA start */
- (2<<1) | /* word transfer size */
- (1<<0); /* software mode */
- /* wait for DMA engine to finish transfer */
- while (A2A_DMA_STS & 1);
-
- *dst += 512;
-}
-
-static inline void write_sd_data(unsigned char **src)
-{
- commit_discard_dcache_range((const void *)*src, 512);
-
- A2A_ISRC1 = (unsigned long)*src;
- A2A_CON1 = (3<<9) | /* burst 16 */
- (1<<5) | /* fixed dst */
- (1<<3) | /* DMA start */
- (2<<1) | /* word transfer size */
- (1<<0); /* software mode */
-
- /* wait for DMA engine to finish transfer */
- while (A2A_DMA_STS & 2);
-
- *src += 512;
-}
int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count,
void* buf)
@@ -501,11 +671,6 @@ int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count,
#ifdef HAVE_MULTIDRIVE
(void)drive;
#endif
- unsigned long response;
- unsigned int retry_cnt = 0;
- int cnt, ret = 0;
- unsigned char *dst;
-
mutex_lock(&sd_mtx);
sd_enable(true);
@@ -515,106 +680,17 @@ int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count,
if(!(card_info.ocr & (1<<30)))
start <<= 9; /* not SDHC */
- while (retry_cnt++ < 20)
- {
- cnt = count;
- dst = (unsigned char *)buf;
+ SDMMC_CMD_PREPARE(SD_READ_MULTIPLE_BLOCK, start, SDMMC_RSP_R1);
+ SDMMC_STP_PREPARE(SD_STOP_TRANSMISSION, 0, SDMMC_RSP_R1B);
+ SDMMC_DAT_PREPARE(buf, 512, (count + 0x1ff) >> 9, SDMMC_DIR_READ);
+ SDMMC_REQ_PREPARE(&cmd, &dat, &stp);
- ret = 0;
- retry = false; /* reset retry flag */
-
- mmu_buff_reset();
-
- if (cnt == 1)
- {
- /* last block to transfer */
- SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
- DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
- DATA_XFER_SINGLE;
- }
- else
- {
- /* more than one block to transfer */
- SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
- DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
- DATA_XFER_MULTI;
- }
-
- /* issue read command to the card */
- if (!send_cmd(SD_READ_MULTIPLE_BLOCK, start, RES_R1, &response))
- {
- ret = -2;
- continue;
- }
-
- while (cnt > 0)
- {
-#ifdef RK27XX_SD_DEBUG
- /* debug stuff */
- TMR1LR = 0xffffffff;
-#endif
- /* wait for transfer completion */
- semaphore_wait(&transfer_completion_signal, TIMEOUT_BLOCK);
-
-#ifdef RK27XX_SD_DEBUG
- /* debug stuff */
- sd_debug_time_rd = 0xffffffff - TMR1CVR;
-#endif
- if (retry)
- {
- /* data transfer error */
- ret = -3;
- break;
- }
-
- /* exchange buffers */
- mmu_switch_buff();
-
- cnt--;
-
- if (cnt == 0)
- {
- if (!send_cmd(SD_STOP_TRANSMISSION, 0, RES_R1b, &response))
- ret = -4;
-
- read_sd_data(&dst);
-
- break;
- }
- else if (cnt == 1)
- {
- /* last block to transfer */
- SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
- DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
- DATA_XFER_SINGLE;
-
- read_sd_data(&dst);
-
- }
- else
- {
- /* more than one block to transfer */
- SD_DATAT = DATA_XFER_START | DATA_XFER_READ |
- DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
- DATA_XFER_MULTI;
-
- read_sd_data(&dst);
- }
-
- last_disk_activity = current_tick;
-
- } /* while (cnt > 0) */
-
- /* transfer successfull - leave retry loop */
- if (ret == 0)
- break;
-
- } /* while (retry_cnt++ < 20) */
+ sdmmc_command(&req);
sd_enable(false);
mutex_unlock(&sd_mtx);
- return ret;
+ return (req.cmd->error || req.stop->error) ? -1 : 0;
}
/* Not tested */
@@ -631,118 +707,30 @@ int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
return -1;
#else
-#ifdef RK27XX_SD_DEBUG
- /* debug stuff */
- TMR1LR = 0xffffffff;
-#endif
-
- unsigned long response;
- unsigned int retry_cnt = 0;
- int cnt, ret = 0;
- unsigned char *src;
- /* bool card_selected = false; */
-
- mutex_lock(&sd_mtx);
- sd_enable(true);
-
if (count <= 0 || start + count > card_info.numblocks)
return -1;
if(!(card_info.ocr & (1<<30)))
start <<= 9; /* not SDHC */
- while (retry_cnt++ < 20)
- {
- cnt = count;
- src = (unsigned char *)buf;
-
- ret = 0;
- retry = false; /* reset retry flag */
- mmu_buff_reset(); /* reset recive buff state */
-
- write_sd_data(&src); /* put data into transfer buffer */
-
- if (!send_cmd(SD_WRITE_MULTIPLE_BLOCK, start, RES_R1, &response))
- {
- ret = -3;
- continue;
- }
-
- while (cnt > 0)
- {
- /* exchange buffers */
- mmu_switch_buff();
-
- if (cnt == 1)
- {
- /* last block to transfer */
- SD_DATAT = DATA_XFER_START | DATA_XFER_WRITE |
- DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
- DATA_XFER_SINGLE;
-
- }
- else
- {
- /* more than one block to transfer */
- SD_DATAT = DATA_XFER_START | DATA_XFER_WRITE |
- DATA_BUS_1LINE | DATA_XFER_DMA_DIS |
- DATA_XFER_MULTI;
-
- /* put more data */
- write_sd_data(&src);
- }
- /* wait for transfer completion */
- semaphore_wait(&transfer_completion_signal, TIMEOUT_BLOCK);
-
- if (retry)
- {
- /* data transfer error */
- ret = -3;
- break;
- }
-
- cnt--;
- } /* while (cnt > 0) */
-
- if (!send_cmd(SD_STOP_TRANSMISSION, 0, RES_R1b, &response))
- ret = -4;
+ mutex_lock(&sd_mtx);
+ sd_enable(true);
- if (!sd_wait_card_busy())
- ret = -5;
+ SDMMC_CMD_PREPARE(SD_WRITE_MULTIPLE_BLOCK, start, SDMMC_RSP_R1);
+ SDMMC_STP_PREPARE(SD_STOP_TRANSMISSION, 0, SDMMC_RSP_R1B);
+ SDMMC_DAT_PREPARE(buf, 512, (count + 0x1ff) >> 9, SDMMC_DIR_READ);
+ SDMMC_REQ_PREPARE(&cmd, &dat, &stp);
- /* transfer successfull - leave retry loop */
- if (ret == 0)
- break;
- }
+ sdmmc_command(&req);
sd_enable(false);
mutex_unlock(&sd_mtx);
-#ifdef RK27XX_SD_DEBUG
- /* debug stuff */
- sd_debug_time_wr = 0xffffffff - TMR1CVR;
-#endif
-
- return ret;
+ return (req.cmd->error || req.stop->error) ? -1 : 0;;
#endif /* defined(BOOTLOADER) */
}
-void sd_enable(bool on)
-{
- /* enable or disable clock signal for SD module */
- if (on)
- {
- SCU_CLKCFG &= ~CLKCFG_SD;
- led(true);
- }
- else
- {
- SCU_CLKCFG |= CLKCFG_SD;
- led(false);
- }
-}
-
#ifndef BOOTLOADER
long sd_last_disk_activity(void)
{