jz4760: Enhancements and fixes to SD driver.

* Fully Interrupt-driven, with proper task yielding
 * Much more robust error handling
 * Eliminate duplicate code
 * Pile of bugfixes

 (Much of this adapted from Igor Poretsky's tree)

Change-Id: I46006412323cba2088b70094635d62a241be1d7e
This commit is contained in:
Solomon Peachy 2018-09-05 14:59:32 -04:00
parent 8edf4052c7
commit 640ada0389

View file

@ -30,6 +30,13 @@
#include "storage.h"
#include "string.h"
#define SD_DMA_ENABLE 1
#define SD_DMA_INTERRUPT 1
#if NUM_DRIVES > 2
#error "JZ4760 SD driver supports NUM_DRIVES <= 2 only"
#endif
static long last_disk_activity = -1;
static tCardInfo card[NUM_DRIVES];
@ -40,13 +47,14 @@ static int sd_drive_nr = 0;
#endif
static struct mutex sd_mtx;
//static struct semaphore sd_wakeup;
#if SD_DMA_INTERRUPT
static struct semaphore sd_wakeup;
#endif
static int use_4bit[NUM_DRIVES];
static int num_6[NUM_DRIVES];
static int sd2_0[NUM_DRIVES];
#define SD_DMA_ENABLE 1
//#define DEBUG(x...) logf(x)
#define DEBUG(x, ...)
@ -129,45 +137,6 @@ enum sd_rsp_t
RESPONSE_R7 = 9,
};
/*
MMC status in R1
Type
e : error bit
s : status bit
r : detected and set for the actual command response
x : detected and set during command execution. the host must poll
the card by sending status command in order to read these bits.
Clear condition
a : according to the card state
b : always related to the previous command. Reception of
a valid command will clear it (with a delay of one command)
c : clear by read
*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_APP_CMD (1 << 7) /* sr, c */
/* These are unpacked versions of the actual responses */
struct sd_response_r1
{
@ -176,7 +145,7 @@ struct sd_response_r1
};
struct sd_response_r3
{
{
unsigned int ocr;
};
@ -233,23 +202,23 @@ static int sd_unpack_r1(struct sd_request *request, struct sd_response_r1 *r1)
DEBUG("sd_unpack_r1: cmd=%d status=%08x", r1->cmd, r1->status);
if (R1_STATUS(r1->status)) {
if (r1->status & R1_OUT_OF_RANGE) return SD_ERROR_OUT_OF_RANGE;
if (r1->status & R1_ADDRESS_ERROR) return SD_ERROR_ADDRESS;
if (r1->status & R1_BLOCK_LEN_ERROR) return SD_ERROR_BLOCK_LEN;
if (r1->status & R1_ERASE_SEQ_ERROR) return SD_ERROR_ERASE_SEQ;
if (r1->status & R1_ERASE_PARAM) return SD_ERROR_ERASE_PARAM;
if (r1->status & R1_WP_VIOLATION) return SD_ERROR_WP_VIOLATION;
//if (r1->status & R1_CARD_IS_LOCKED) return SD_ERROR_CARD_IS_LOCKED;
if (r1->status & R1_LOCK_UNLOCK_FAILED) return SD_ERROR_LOCK_UNLOCK_FAILED;
if (r1->status & R1_COM_CRC_ERROR) return SD_ERROR_COM_CRC;
if (r1->status & R1_ILLEGAL_COMMAND) return SD_ERROR_ILLEGAL_COMMAND;
if (r1->status & R1_CARD_ECC_FAILED) return SD_ERROR_CARD_ECC_FAILED;
if (r1->status & R1_CC_ERROR) return SD_ERROR_CC;
if (r1->status & R1_ERROR) return SD_ERROR_GENERAL;
if (r1->status & R1_UNDERRUN) return SD_ERROR_UNDERRUN;
if (r1->status & R1_OVERRUN) return SD_ERROR_OVERRUN;
if (r1->status & R1_CID_CSD_OVERWRITE) return SD_ERROR_CID_CSD_OVERWRITE;
if (SD_R1_STATUS(r1->status)) {
if (r1->status & SD_R1_OUT_OF_RANGE) return SD_ERROR_OUT_OF_RANGE;
if (r1->status & SD_R1_ADDRESS_ERROR) return SD_ERROR_ADDRESS;
if (r1->status & SD_R1_BLOCK_LEN_ERROR) return SD_ERROR_BLOCK_LEN;
if (r1->status & SD_R1_ERASE_SEQ_ERROR) return SD_ERROR_ERASE_SEQ;
if (r1->status & SD_R1_ERASE_PARAM) return SD_ERROR_ERASE_PARAM;
if (r1->status & SD_R1_WP_VIOLATION) return SD_ERROR_WP_VIOLATION;
//if (r1->status & SD_R1_CARD_IS_LOCKED) return SD_ERROR_CARD_IS_LOCKED;
if (r1->status & SD_R1_LOCK_UNLOCK_FAILED) return SD_ERROR_LOCK_UNLOCK_FAILED;
if (r1->status & SD_R1_COM_CRC_ERROR) return SD_ERROR_COM_CRC;
if (r1->status & SD_R1_ILLEGAL_COMMAND) return SD_ERROR_ILLEGAL_COMMAND;
if (r1->status & SD_R1_CARD_ECC_FAILED) return SD_ERROR_CARD_ECC_FAILED;
if (r1->status & SD_R1_CC_ERROR) return SD_ERROR_CC;
if (r1->status & SD_R1_ERROR) return SD_ERROR_GENERAL;
if (r1->status & SD_R1_UNDERRUN) return SD_ERROR_UNDERRUN;
if (r1->status & SD_R1_OVERRUN) return SD_ERROR_OVERRUN;
if (r1->status & SD_R1_CSD_OVERWRITE) return SD_ERROR_CID_CSD_OVERWRITE;
}
if (buf[0] != request->cmd)
@ -257,7 +226,7 @@ static int sd_unpack_r1(struct sd_request *request, struct sd_response_r1 *r1)
/* This should be last - it's the least dangerous error */
return 0;
return SD_NO_ERROR;
}
static int sd_unpack_r6(struct sd_request *request, struct sd_response_r1 *r1, unsigned long *rca)
@ -287,7 +256,7 @@ static int sd_unpack_r3(struct sd_request *request, struct sd_response_r3 *r3)
if (buf[0] != 0x3f)
return SD_ERROR_HEADER_MISMATCH;
return 0;
return SD_NO_ERROR;
}
/* Stop the MMC clock and wait while it happens */
@ -339,10 +308,8 @@ static int jz_sd_check_status(const int drive, struct sd_request *request)
{
DEBUG("SD CRC error, MSC_STAT 0x%x", status);
return SD_ERROR_CRC;
}
/* Checking for FIFO empty */
/*if(status & MSC_STAT_DATA_FIFO_EMPTY && request->rtype != RESPONSE_NONE)
{
@ -358,7 +325,10 @@ static void jz_sd_get_response(const int drive, struct sd_request *request)
{
int i;
unsigned char *buf;
unsigned int data;
unsigned short data;
if (request->result != SD_NO_RESPONSE)
return;
DEBUG("fetch response for request %d, cmd %d", request->rtype,
request->cmd);
@ -419,37 +389,39 @@ static int jz_sd_receive_data(const int drive, struct sd_request *req)
unsigned char *buf = req->buffer;
unsigned int *wbuf = (unsigned int *) buf;
unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */
unsigned int stat, timeout, data, cnt;
unsigned int stat, data, cnt;
for (; nob >= 1; nob--)
{
timeout = 0x3FFFFFF;
long deadline = current_tick + (HZ * 65);
while (timeout)
{
timeout--;
do {
stat = REG_MSC_STAT(MSC_CHN(drive));
if (stat & MSC_STAT_TIME_OUT_READ)
return SD_ERROR_TIMEOUT;
else if (stat & MSC_STAT_CRC_READ_ERROR)
return SD_ERROR_CRC;
else if (!(stat & MSC_STAT_DATA_FIFO_EMPTY)
|| (stat & MSC_STAT_DATA_FIFO_AFULL))
else if ((stat & MSC_STAT_DATA_FIFO_AFULL) ||
!(stat & MSC_STAT_DATA_FIFO_EMPTY))
/* Ready to read data */
break;
udelay(1);
}
if (!timeout)
return SD_ERROR_TIMEOUT;
yield();
} while (TIME_BEFORE(current_tick, deadline));
/* Read data from RXFIFO. It could be FULL or PARTIAL FULL */
DEBUG("Receive Data = %d", wblocklen);
cnt = wblocklen;
while (cnt)
{
if (REG_MSC_STAT(MSC_CHN(drive)) & MSC_STAT_DATA_FIFO_EMPTY)
{
if (TIME_AFTER(current_tick, deadline))
return SD_ERROR_TIMEOUT;
continue;
}
data = REG_MSC_RXFIFO(MSC_CHN(drive));
if (waligned)
*wbuf++ = data;
@ -461,9 +433,6 @@ static int jz_sd_receive_data(const int drive, struct sd_request *req)
*buf++ = (unsigned char) (data >> 24);
}
cnt--;
while (cnt
&& (REG_MSC_STAT(MSC_CHN(drive)) &
MSC_STAT_DATA_FIFO_EMPTY));
}
}
@ -477,15 +446,13 @@ static int jz_sd_transmit_data(const int drive, struct sd_request *req)
unsigned char *buf = req->buffer;
unsigned int *wbuf = (unsigned int *) buf;
unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */
unsigned int stat, timeout, data, cnt;
unsigned int stat, data, cnt;
for (; nob >= 1; nob--)
{
timeout = 0x3FFFFFF;
long deadline = current_tick + (HZ * 65);
while (timeout)
{
timeout--;
do {
stat = REG_MSC_STAT(MSC_CHN(drive));
if (stat &
@ -496,17 +463,19 @@ static int jz_sd_transmit_data(const int drive, struct sd_request *req)
/* Ready to write data */
break;
udelay(1);
}
if (!timeout)
return SD_ERROR_TIMEOUT;
yield();
} while (TIME_BEFORE(current_tick, deadline));
/* Write data to TXFIFO */
cnt = wblocklen;
while (cnt)
{
while (REG_MSC_STAT(MSC_CHN(drive)) & MSC_STAT_DATA_FIFO_FULL);
if (REG_MSC_STAT(MSC_CHN(drive)) & MSC_STAT_DATA_FIFO_FULL)
{
if (TIME_AFTER(current_tick, deadline))
return SD_ERROR_TIMEOUT;
continue;
}
if (waligned)
REG_MSC_TXFIFO(MSC_CHN(drive)) = *wbuf++;
@ -527,72 +496,81 @@ static int jz_sd_transmit_data(const int drive, struct sd_request *req)
}
#if SD_DMA_ENABLE
static void jz_sd_receive_data_dma(const int drive, struct sd_request *req)
static int jz_sd_receive_data_dma(const int drive, struct sd_request *req)
{
unsigned int waligned = (((unsigned int)req->buffer & 0x3) == 0); /* word aligned ? */
unsigned int size = req->block_len * req->nob;
if (!waligned)
{
jz_sd_receive_data(drive, req);
return;
}
if ((unsigned int)req->buffer & 0x3)
return jz_sd_receive_data(drive, req);
/* flush dcache */
dma_cache_wback_inv((unsigned long) req->buffer, size);
dma_cache_wback_inv((unsigned long) req->buffer, req->cnt);
/* setup dma channel */
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = 0;
REG_DMAC_DSAR(DMA_SD_RX_CHANNEL) = PHYSADDR(MSC_RXFIFO(MSC_CHN(drive))); /* DMA source addr */
REG_DMAC_DTAR(DMA_SD_RX_CHANNEL) = PHYSADDR((unsigned long)req->buffer); /* DMA dest addr */
REG_DMAC_DTCR(DMA_SD_RX_CHANNEL) = (size + 3) >> 2; /* DMA transfer count */
REG_DMAC_DTCR(DMA_SD_RX_CHANNEL) = (req->cnt + 3) >> 2; /* DMA transfer count */
REG_DMAC_DRSR(DMA_SD_RX_CHANNEL) = (drive == SD_SLOT_1) ? DMAC_DRSR_RS_MSC2IN : DMAC_DRSR_RS_MSC1IN; /* DMA request type */
REG_DMAC_DCMD(DMA_SD_RX_CHANNEL) =
#if SD_DMA_INTERRUPT
DMAC_DCMD_TIE | /* Enable DMA interrupt */
#endif
DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 |
DMAC_DCMD_DS_32BIT;
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
/* wait for dma completion */
while (REG_DMAC_DTCR(DMA_SD_RX_CHANNEL));
#if SD_DMA_INTERRUPT
semaphore_wait(&sd_wakeup, TIMEOUT_BLOCK);
#else
while (REG_DMAC_DTCR(DMA_SD_RX_CHANNEL))
yield();
#endif
/* clear status and disable channel */
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = 0;
return SD_NO_ERROR;
}
static void jz_sd_transmit_data_dma(const int drive, struct sd_request *req)
static int jz_sd_transmit_data_dma(const int drive, struct sd_request *req)
{
unsigned int waligned = (((unsigned int)req->buffer & 0x3) == 0); /* word aligned ? */
unsigned int size = req->block_len * req->nob;
if (!waligned)
{
jz_sd_transmit_data(drive, req);
return;
}
if ((unsigned int)req->buffer & 0x3)
return jz_sd_transmit_data(drive, req);
/* flush dcache */
dma_cache_wback_inv((unsigned long) req->buffer, size);
dma_cache_wback_inv((unsigned long) req->buffer, req->cnt);
/* setup dma channel */
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = 0;
REG_DMAC_DSAR(DMA_SD_TX_CHANNEL) = PHYSADDR((unsigned long) req->buffer); /* DMA source addr */
REG_DMAC_DTAR(DMA_SD_TX_CHANNEL) = PHYSADDR(MSC_TXFIFO(MSC_CHN(drive))); /* DMA dest addr */
REG_DMAC_DTCR(DMA_SD_TX_CHANNEL) = (size + 3) >> 2; /* DMA transfer count */
REG_DMAC_DTCR(DMA_SD_TX_CHANNEL) = (req->cnt + 3) >> 2; /* DMA transfer count */
REG_DMAC_DRSR(DMA_SD_TX_CHANNEL) = (drive == SD_SLOT_1) ? DMAC_DRSR_RS_MSC2OUT : DMAC_DRSR_RS_MSC1OUT; /* DMA request type */
REG_DMAC_DCMD(DMA_SD_TX_CHANNEL) =
#if SD_DMA_INTERRUPT
DMAC_DCMD_TIE | /* Enable DMA interrupt */
#endif
DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 |
DMAC_DCMD_DS_32BIT;
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
/* wait for dma completion */
while (REG_DMAC_DTCR(DMA_SD_TX_CHANNEL));
#if SD_DMA_INTERRUPT
semaphore_wait(&sd_wakeup, TIMEOUT_BLOCK);
#else
while (REG_DMAC_DTCR(DMA_SD_TX_CHANNEL))
yield();
#endif
/* clear status and disable channel */
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) = 0;
return SD_NO_ERROR;
}
#if SD_DMA_INTERRUPT
void DMA_CALLBACK(DMA_SD_RX_CHANNEL)(void)
{
if (REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) & DMAC_DCCSR_AR)
@ -612,6 +590,8 @@ void DMA_CALLBACK(DMA_SD_RX_CHANNEL)(void)
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) &= ~DMAC_DCCSR_TT;
//sd_rx_dma_callback();
}
semaphore_release(&sd_wakeup);
}
void DMA_CALLBACK(DMA_SD_TX_CHANNEL)(void)
@ -633,7 +613,10 @@ void DMA_CALLBACK(DMA_SD_TX_CHANNEL)(void)
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) &= ~DMAC_DCCSR_TT;
//sd_tx_dma_callback();
}
semaphore_release(&sd_wakeup);
}
#endif /* SD_DMA_INTERRUPT */
#endif /* SD_DMA_ENABLE */
static inline unsigned int jz_sd_calc_clkrt(const int drive, unsigned int rate)
@ -654,7 +637,7 @@ static inline void cpm_select_msc_clk(unsigned int rate)
{
unsigned int div = __cpm_get_pllout2() / rate;
if (div == 0)
div = 1;
div = 1;
REG_CPM_MSCCDR = MSCCDR_MCS | (div - 1);
DEBUG("MSCCLK == %x\n", REG_CPM_MSCCDR);
@ -686,7 +669,8 @@ static void jz_sd_set_clock(const int drive, unsigned int rate)
static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
{
unsigned int cmdat = 0, events = 0;
int retval, timeout = 0x3fffff;
int retval;
long deadline = current_tick + (HZ * 5);
/* Indicate we have no result yet */
request->result = SD_NO_RESPONSE;
@ -704,32 +688,14 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
/* On reset, stop SD clock */
jz_sd_stop_clock(drive);
}
if (request->cmd == SD_SET_BUS_WIDTH)
{
if (request->arg == 0x2)
{
DEBUG("Use 4-bit bus width");
use_4bit[drive] = 1;
}
else
{
DEBUG("Use 1-bit bus width");
use_4bit[drive] = 0;
}
}
/* stop clock */
jz_sd_stop_clock(drive);
/* mask all interrupts */
//REG_MSC_IMASK(MSC_CHN(drive)) = 0xffff;
/* clear status */
REG_MSC_IREG(MSC_CHN(drive)) = 0xffff;
/* mask all interrupts and clear status */
SD_IRQ_MASK(MSC_CHN(drive));
/*open interrupt */
REG_MSC_IMASK(MSC_CHN(drive)) = (~7);
/* use 4-bit bus width when possible */
if (use_4bit[drive])
cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
REG_MSC_IMASK(MSC_CHN(drive)) = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_DATA_TRAN_DONE | MSC_IMASK_PRG_DONE);
/* Set command type and events */
switch (request->cmd)
@ -750,10 +716,18 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
break;
/* adtc - addressed with data transfer */
case SD_SEND_SCR:
/* SD card returns SCR register as data.
SD core expect it in the response buffer,
after normal response. */
request->buffer =
(unsigned char *) ((unsigned int) request->response + 5);
request->block_len = 8;
request->nob = 1;
case SD_READ_DAT_UNTIL_STOP:
case SD_READ_SINGLE_BLOCK:
case SD_READ_MULTIPLE_BLOCK:
case SD_SEND_SCR:
#if SD_DMA_ENABLE
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_READ | MSC_CMDAT_DMA_EN;
@ -763,7 +737,17 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
events = SD_EVENT_RX_DATA_DONE;
break;
case 6:
case SD_SWITCH_FUNC:
if (request->arg == 0x2)
{
DEBUG("Use 4-bit bus width");
use_4bit[drive] = 1;
}
else
{
DEBUG("Use 1-bit bus width");
use_4bit[drive] = 0;
}
if (num_6[drive] < 2)
{
#if SD_DMA_ENABLE
@ -782,7 +766,7 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
case SD_WRITE_MULTIPLE_BLOCK:
case SD_PROGRAM_CID:
case SD_PROGRAM_CSD:
case SD_LOCK_UNLOCK:
// case SD_LOCK_UNLOCK:
#if SD_DMA_ENABLE
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE | MSC_CMDAT_DMA_EN;
@ -833,6 +817,10 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
break;
}
/* use 4-bit bus width when possible */
if (use_4bit[drive])
cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
/* Set command index */
if (request->cmd == SD_CIM_RESET)
REG_MSC_CMD(MSC_CHN(drive)) = SD_GO_IDLE_STATE;
@ -843,16 +831,8 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
REG_MSC_ARG(MSC_CHN(drive)) = request->arg;
/* Set block length and nob */
if (request->cmd == SD_SEND_SCR)
{ /* get SCR from DataFIFO */
REG_MSC_BLKLEN(MSC_CHN(drive)) = 8;
REG_MSC_NOB(MSC_CHN(drive)) = 1;
}
else
{
REG_MSC_BLKLEN(MSC_CHN(drive)) = request->block_len;
REG_MSC_NOB(MSC_CHN(drive)) = request->nob;
}
REG_MSC_BLKLEN(MSC_CHN(drive)) = request->block_len;
REG_MSC_NOB(MSC_CHN(drive)) = request->nob;
/* Set command */
REG_MSC_CMDAT(MSC_CHN(drive)) = cmdat;
@ -866,11 +846,12 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
/* Wait for command completion */
//__intc_unmask_irq(IRQ_MSC);
//semaphore_wait(&sd_wakeup, 100);
while (timeout-- && !(REG_MSC_STAT(MSC_CHN(drive)) & MSC_STAT_END_CMD_RES));
if (timeout == 0)
return SD_ERROR_TIMEOUT;
while (!(REG_MSC_IREG(MSC_CHN(drive)) & MSC_IREG_END_CMD_RES))
{
if (TIME_AFTER(current_tick, deadline))
return SD_ERROR_TIMEOUT;
yield();
}
REG_MSC_IREG(MSC_CHN(drive)) = MSC_IREG_END_CMD_RES; /* clear flag */
@ -891,33 +872,31 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
{
if (events & SD_EVENT_RX_DATA_DONE)
{
if (request->cmd == SD_SEND_SCR)
{
/* SD card returns SCR register as data.
SD core expect it in the response buffer,
after normal response. */
request->buffer =
(unsigned char *) ((unsigned int) request->response + 5);
}
#if SD_DMA_ENABLE
jz_sd_receive_data_dma(drive, request);
retval = jz_sd_receive_data_dma(drive, request);
#else
jz_sd_receive_data(drive, request);
retval = jz_sd_receive_data(drive, request);
#endif
}
if (retval)
return retval;
if (events & SD_EVENT_TX_DATA_DONE)
{
#if SD_DMA_ENABLE
jz_sd_transmit_data_dma(drive, request);
retval = jz_sd_transmit_data_dma(drive, request);
#else
jz_sd_transmit_data(drive, request);
retval = jz_sd_transmit_data(drive, request);
#endif
}
if (retval)
return retval;
//__intc_unmask_irq(IRQ_MSC);
//semaphore_wait(&sd_wakeup, 100);
/* Wait for Data Done */
while (!(REG_MSC_IREG(MSC_CHN(drive)) & MSC_IREG_DATA_TRAN_DONE));
while (!(REG_MSC_IREG(MSC_CHN(drive)) & MSC_IREG_DATA_TRAN_DONE))
yield();
REG_MSC_IREG(MSC_CHN(drive)) = MSC_IREG_DATA_TRAN_DONE; /* clear status */
}
@ -926,7 +905,8 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
{
//__intc_unmask_irq(IRQ_MSC);
//semaphore_wait(&sd_wakeup, 100);
while (!(REG_MSC_IREG(MSC_CHN(drive)) & MSC_IREG_PRG_DONE));
while (!(REG_MSC_IREG(MSC_CHN(drive)) & MSC_IREG_PRG_DONE))
yield();
REG_MSC_IREG(MSC_CHN(drive)) = MSC_IREG_PRG_DONE; /* clear status */
}
@ -986,10 +966,12 @@ static void jz_sd_hardware_init(const int drive)
jz_sd_stop_clock(drive); /* stop SD clock */
}
static int sd_send_cmd(const int drive, struct sd_request *request, int cmd, unsigned int arg,
static void sd_send_cmd(const int drive, struct sd_request *request, int cmd, unsigned int arg,
unsigned short nob, unsigned short block_len,
enum sd_rsp_t rtype, unsigned char* buffer)
{
int retval;
request->cmd = cmd;
request->arg = arg;
request->rtype = rtype;
@ -998,7 +980,9 @@ static int sd_send_cmd(const int drive, struct sd_request *request, int cmd, uns
request->buffer = buffer;
request->cnt = nob * block_len;
return jz_sd_exec_cmd(drive, request);
retval = jz_sd_exec_cmd(drive, request);
if (retval)
request->result = retval;
}
static void sd_simple_cmd(const int drive, struct sd_request *request, int cmd, unsigned int arg,
@ -1007,6 +991,23 @@ static void sd_simple_cmd(const int drive, struct sd_request *request, int cmd,
sd_send_cmd(drive, request, cmd, arg, 0, 0, rtype, NULL);
}
static int sd_exec_acmd(const int drive, struct sd_request *request, int cmd, unsigned int arg)
{
struct sd_response_r1 r1;
int retval;
sd_simple_cmd(drive, request, SD_APP_CMD, card[drive].rca, RESPONSE_R1);
retval = sd_unpack_r1(request, &r1);
if (!retval)
{
sd_simple_cmd(drive, request, cmd, arg, RESPONSE_R1);
retval = sd_unpack_r1(request, &r1);
}
return retval;
}
#define SD_INIT_DOING 0
#define SD_INIT_PASSED 1
#define SD_INIT_FAILED 2
@ -1014,7 +1015,7 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
{
struct sd_response_r1 r1;
struct sd_response_r3 r3;
int retval, i, ocr = 0x40300000, limit_41 = 0;
int retval, i, ocr = 0x40300000;
switch (request->cmd)
{
@ -1028,28 +1029,15 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
break;
case SD_APP_CMD:
retval = sd_unpack_r1(request, &r1);
if (retval & (limit_41 < 100))
{
DEBUG("sd_init_card_state: unable to SD_APP_CMD error=%d",
retval);
limit_41++;
sd_simple_cmd(drive, request, SD_APP_OP_COND, ocr, RESPONSE_R3);
}
else if (limit_41 < 100)
{
limit_41++;
sd_simple_cmd(drive, request, SD_APP_OP_COND, ocr, RESPONSE_R3);
}
else
/* reset the card to idle*/
sd_simple_cmd(drive, request, SD_GO_IDLE_STATE, 0, RESPONSE_NONE);
if (sd_unpack_r1(request, &r1))
return SD_INIT_FAILED;
sd_simple_cmd(drive, request, SD_APP_OP_COND, ocr, RESPONSE_R3);
break;
case SD_APP_OP_COND:
retval = sd_unpack_r3(request, &r3);
if (retval)
break;
return SD_INIT_FAILED;
DEBUG("sd_init_card_state: read ocr value = 0x%08x", r3.ocr);
card[drive].ocr = r3.ocr;
@ -1068,20 +1056,24 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
break;
case SD_ALL_SEND_CID:
if (request->result)
return SD_INIT_FAILED;
for(i=0; i<4; i++)
card[drive].cid[i] = ((request->response[1+i*4]<<24) | (request->response[2+i*4]<<16) |
card[drive].cid[i] = ((request->response[1+i*4]<<24) | (request->response[2+i*4]<<16) |
(request->response[3+i*4]<< 8) | request->response[4+i*4]);
logf("CID: %08lx%08lx%08lx%08lx", card[drive].cid[0], card[drive].cid[1], card[drive].cid[2], card[drive].cid[3]);
sd_simple_cmd(drive, request, SD_SEND_RELATIVE_ADDR, 0, RESPONSE_R6);
break;
case SD_SEND_RELATIVE_ADDR:
retval = sd_unpack_r6(request, &r1, &card[drive].rca);
card[drive].rca = card[drive].rca << 16;
card[drive].rca = card[drive].rca << 16;
DEBUG("sd_init_card_state: Get RCA from SD: 0x%04lx Status: %x", card[drive].rca, r1.status);
if (retval)
{
DEBUG("sd_init_card_state: unable to SET_RELATIVE_ADDR error=%d",
DEBUG("sd_init_card_state: unable to SET_RELATIVE_ADDR error=%d",
retval);
return SD_INIT_FAILED;
}
@ -1090,8 +1082,10 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
break;
case SD_SEND_CSD:
if (request->result)
return SD_INIT_FAILED;
for(i=0; i<4; i++)
card[drive].csd[i] = ((request->response[1+i*4]<<24) | (request->response[2+i*4]<<16) |
card[drive].csd[i] = ((request->response[1+i*4]<<24) | (request->response[2+i*4]<<16) |
(request->response[3+i*4]<< 8) | request->response[4+i*4]);
sd_parse_csd(&card[drive]);
@ -1120,7 +1114,7 @@ static int sd_switch(const int drive, struct sd_request *request, int mode, int
arg = (mode << 31 | 0x00FFFFFF);
arg &= ~(0xF << (group * 4));
arg |= value << (group * 4);
sd_send_cmd(drive, request, 6, arg, 1, 64, RESPONSE_R1, resp);
sd_send_cmd(drive, request, SD_SWITCH_FUNC, arg, 1, 64, RESPONSE_R1, resp);
return 0;
}
@ -1137,7 +1131,7 @@ static int sd_read_switch(const int drive, struct sd_request *request)
if (((unsigned char *)status)[13] & 0x02)
return 0;
else
else
return 1;
}
@ -1174,13 +1168,10 @@ static int sd_select_card(const int drive)
}
}
num_6[drive] = 3;
sd_simple_cmd(drive, &request, SD_APP_CMD, card[drive].rca,
RESPONSE_R1);
retval = sd_unpack_r1(&request, &r1);
retval = sd_exec_acmd(drive, &request, SD_SET_BUS_WIDTH, 2);
if (retval)
return retval;
sd_simple_cmd(drive, &request, SD_SET_BUS_WIDTH, 2, RESPONSE_R1);
retval = sd_unpack_r1(&request, &r1);
retval = sd_exec_acmd(drive, &request, SD_SET_CLR_CARD_DETECT, 0);
if (retval)
return retval;
@ -1192,8 +1183,8 @@ static int sd_select_card(const int drive)
static int sd_init_device(const int drive)
{
int retval = 0;
long deadline;
struct sd_request init_req;
register int timeout = 1000;
mutex_lock(&sd_mtx);
@ -1212,7 +1203,11 @@ static int sd_init_device(const int drive)
sleep(HZ/2); /* Give the card/controller some rest */
while(timeout-- && ((retval = sd_init_card_state(drive, &init_req)) == SD_INIT_DOING));
deadline = current_tick + HZ;
do {
retval = sd_init_card_state(drive, &init_req);
} while (TIME_BEFORE(current_tick, deadline) && (retval == SD_INIT_DOING));
retval = (retval == SD_INIT_PASSED ? sd_select_card(drive) : -1);
if (drive == SD_SLOT_1)
@ -1238,8 +1233,17 @@ int sd_init(void)
if(!inited)
{
// semaphore_init(&sd_wakeup, 1, 0);
#if SD_DMA_INTERRUPT
semaphore_init(&sd_wakeup, 1, 0);
#endif
mutex_init(&sd_mtx);
#if SD_DMA_ENABLE && SD_DMA_INTERRUPT
system_enable_irq(DMA_IRQ(DMA_SD_RX_CHANNEL));
system_enable_irq(DMA_IRQ(DMA_SD_TX_CHANNEL));
#endif
inited = true;
}
@ -1279,107 +1283,63 @@ static inline void sd_stop_transfer(const int drive)
mutex_unlock(&sd_mtx);
}
int sd_read_sectors(const int drive, unsigned long start, int count, void* buf)
int sd_transfer_sectors(IF_MD(const int drive,) unsigned long start, int count, void* buf, bool write)
{
sd_start_transfer(drive);
struct sd_request request;
struct sd_response_r1 r1;
int retval = -1;
#ifndef HAVE_MULTIDRIVE
const int drive = 0;
#endif
if (!card_detect_target(drive) || count == 0 || start > card[drive].numblocks)
sd_start_transfer(drive);
if (!card_detect_target(drive) || count < 1 || (start + count) > card[drive].numblocks)
goto err;
if(card[drive].initialized == 0 && !sd_init_device(drive))
goto err;
sd_simple_cmd(drive, &request, SD_SEND_STATUS, card[drive].rca, RESPONSE_R1);
retval = sd_unpack_r1(&request, &r1);
if (retval && (retval != SD_ERROR_STATE_MISMATCH))
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
sd_simple_cmd(drive, &request, SD_SET_BLOCKLEN, SD_BLOCK_SIZE, RESPONSE_R1);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
if (sd2_0[drive])
{
sd_send_cmd(drive, &request, SD_READ_MULTIPLE_BLOCK, start,
count, SD_BLOCK_SIZE, RESPONSE_R1, buf);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
else
{
sd_send_cmd(drive, &request, SD_READ_MULTIPLE_BLOCK,
start * SD_BLOCK_SIZE, count,
SD_BLOCK_SIZE, RESPONSE_R1, buf);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
last_disk_activity = current_tick;
sd_simple_cmd(drive, &request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B);
sd_send_cmd(drive, &request,
(count > 1) ?
(write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK) :
(write ? SD_WRITE_BLOCK : SD_READ_SINGLE_BLOCK),
sd2_0[drive] ? start : (start * SD_BLOCK_SIZE),
count, SD_BLOCK_SIZE, RESPONSE_R1, buf);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
if (count > 1)
{
sd_simple_cmd(drive, &request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B);
retval = sd_unpack_r1(&request, &r1);
if (!write && retval == SD_ERROR_OUT_OF_RANGE)
retval = 0;
}
err:
last_disk_activity = current_tick;
sd_stop_transfer(drive);
return retval;
}
int sd_write_sectors(const int drive, unsigned long start, int count, const void* buf)
int sd_read_sectors(IF_MD(int drive,) unsigned long start, int count, void* buf)
{
sd_start_transfer(drive);
return sd_transfer_sectors(IF_MD(drive,) start, count, buf, false);
}
struct sd_request request;
struct sd_response_r1 r1;
int retval = -1;
if (!card_detect_target(drive) || count == 0 || start > card[drive].numblocks)
goto err;
if(card[drive].initialized == 0 && !sd_init_device(drive))
goto err;
sd_simple_cmd(drive, &request, SD_SEND_STATUS, card[drive].rca, RESPONSE_R1);
retval = sd_unpack_r1(&request, &r1);
if (retval && (retval != SD_ERROR_STATE_MISMATCH))
goto err;
sd_simple_cmd(drive, &request, SD_SET_BLOCKLEN, SD_BLOCK_SIZE, RESPONSE_R1);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
if (sd2_0[drive])
{
sd_send_cmd(drive, &request, SD_WRITE_MULTIPLE_BLOCK, start,
count, SD_BLOCK_SIZE, RESPONSE_R1,
(void*)buf);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
else
{
sd_send_cmd(drive, &request, SD_WRITE_MULTIPLE_BLOCK,
start * SD_BLOCK_SIZE, count,
SD_BLOCK_SIZE, RESPONSE_R1, (void*)buf);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
last_disk_activity = current_tick;
sd_simple_cmd(drive, &request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
err:
sd_stop_transfer(drive);
return retval;
int sd_write_sectors(IF_MD(int drive,) unsigned long start, int count, const void* buf)
{
return sd_transfer_sectors(IF_MD(drive,) start, count, (void*)buf, true);
}
long sd_last_disk_activity(void)
@ -1474,8 +1434,8 @@ int sd_event(long id, intptr_t data)
* clear if the last attempt to init failed with an error. */
mutex_lock(&sd_mtx); /* lock-out card activity */
card[data].initialized = 0;
if (id == SYS_HOTSWAP_INSERTED)
sd_init_device(data);
// if (id == SYS_HOTSWAP_INSERTED)
// sd_init_device(data);
mutex_unlock(&sd_mtx);
break;
#endif /* HAVE_HOTSWAP */