mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-10 13:45:10 -05:00
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:
parent
8edf4052c7
commit
640ada0389
1 changed files with 239 additions and 279 deletions
|
|
@ -30,6 +30,13 @@
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "string.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 long last_disk_activity = -1;
|
||||||
static tCardInfo card[NUM_DRIVES];
|
static tCardInfo card[NUM_DRIVES];
|
||||||
|
|
||||||
|
|
@ -40,13 +47,14 @@ static int sd_drive_nr = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct mutex sd_mtx;
|
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 use_4bit[NUM_DRIVES];
|
||||||
static int num_6[NUM_DRIVES];
|
static int num_6[NUM_DRIVES];
|
||||||
static int sd2_0[NUM_DRIVES];
|
static int sd2_0[NUM_DRIVES];
|
||||||
|
|
||||||
#define SD_DMA_ENABLE 1
|
|
||||||
|
|
||||||
//#define DEBUG(x...) logf(x)
|
//#define DEBUG(x...) logf(x)
|
||||||
#define DEBUG(x, ...)
|
#define DEBUG(x, ...)
|
||||||
|
|
@ -129,45 +137,6 @@ enum sd_rsp_t
|
||||||
RESPONSE_R7 = 9,
|
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 */
|
/* These are unpacked versions of the actual responses */
|
||||||
struct sd_response_r1
|
struct sd_response_r1
|
||||||
{
|
{
|
||||||
|
|
@ -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);
|
DEBUG("sd_unpack_r1: cmd=%d status=%08x", r1->cmd, r1->status);
|
||||||
|
|
||||||
if (R1_STATUS(r1->status)) {
|
if (SD_R1_STATUS(r1->status)) {
|
||||||
if (r1->status & R1_OUT_OF_RANGE) return SD_ERROR_OUT_OF_RANGE;
|
if (r1->status & SD_R1_OUT_OF_RANGE) return SD_ERROR_OUT_OF_RANGE;
|
||||||
if (r1->status & R1_ADDRESS_ERROR) return SD_ERROR_ADDRESS;
|
if (r1->status & SD_R1_ADDRESS_ERROR) return SD_ERROR_ADDRESS;
|
||||||
if (r1->status & R1_BLOCK_LEN_ERROR) return SD_ERROR_BLOCK_LEN;
|
if (r1->status & SD_R1_BLOCK_LEN_ERROR) return SD_ERROR_BLOCK_LEN;
|
||||||
if (r1->status & R1_ERASE_SEQ_ERROR) return SD_ERROR_ERASE_SEQ;
|
if (r1->status & SD_R1_ERASE_SEQ_ERROR) return SD_ERROR_ERASE_SEQ;
|
||||||
if (r1->status & R1_ERASE_PARAM) return SD_ERROR_ERASE_PARAM;
|
if (r1->status & SD_R1_ERASE_PARAM) return SD_ERROR_ERASE_PARAM;
|
||||||
if (r1->status & R1_WP_VIOLATION) return SD_ERROR_WP_VIOLATION;
|
if (r1->status & SD_R1_WP_VIOLATION) return SD_ERROR_WP_VIOLATION;
|
||||||
//if (r1->status & R1_CARD_IS_LOCKED) return SD_ERROR_CARD_IS_LOCKED;
|
//if (r1->status & SD_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 & SD_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 & SD_R1_COM_CRC_ERROR) return SD_ERROR_COM_CRC;
|
||||||
if (r1->status & R1_ILLEGAL_COMMAND) return SD_ERROR_ILLEGAL_COMMAND;
|
if (r1->status & SD_R1_ILLEGAL_COMMAND) return SD_ERROR_ILLEGAL_COMMAND;
|
||||||
if (r1->status & R1_CARD_ECC_FAILED) return SD_ERROR_CARD_ECC_FAILED;
|
if (r1->status & SD_R1_CARD_ECC_FAILED) return SD_ERROR_CARD_ECC_FAILED;
|
||||||
if (r1->status & R1_CC_ERROR) return SD_ERROR_CC;
|
if (r1->status & SD_R1_CC_ERROR) return SD_ERROR_CC;
|
||||||
if (r1->status & R1_ERROR) return SD_ERROR_GENERAL;
|
if (r1->status & SD_R1_ERROR) return SD_ERROR_GENERAL;
|
||||||
if (r1->status & R1_UNDERRUN) return SD_ERROR_UNDERRUN;
|
if (r1->status & SD_R1_UNDERRUN) return SD_ERROR_UNDERRUN;
|
||||||
if (r1->status & R1_OVERRUN) return SD_ERROR_OVERRUN;
|
if (r1->status & SD_R1_OVERRUN) return SD_ERROR_OVERRUN;
|
||||||
if (r1->status & R1_CID_CSD_OVERWRITE) return SD_ERROR_CID_CSD_OVERWRITE;
|
if (r1->status & SD_R1_CSD_OVERWRITE) return SD_ERROR_CID_CSD_OVERWRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[0] != request->cmd)
|
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 */
|
/* 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)
|
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)
|
if (buf[0] != 0x3f)
|
||||||
return SD_ERROR_HEADER_MISMATCH;
|
return SD_ERROR_HEADER_MISMATCH;
|
||||||
|
|
||||||
return 0;
|
return SD_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop the MMC clock and wait while it happens */
|
/* 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);
|
DEBUG("SD CRC error, MSC_STAT 0x%x", status);
|
||||||
return SD_ERROR_CRC;
|
return SD_ERROR_CRC;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Checking for FIFO empty */
|
/* Checking for FIFO empty */
|
||||||
/*if(status & MSC_STAT_DATA_FIFO_EMPTY && request->rtype != RESPONSE_NONE)
|
/*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;
|
int i;
|
||||||
unsigned char *buf;
|
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,
|
DEBUG("fetch response for request %d, cmd %d", request->rtype,
|
||||||
request->cmd);
|
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 char *buf = req->buffer;
|
||||||
unsigned int *wbuf = (unsigned int *) buf;
|
unsigned int *wbuf = (unsigned int *) buf;
|
||||||
unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */
|
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--)
|
for (; nob >= 1; nob--)
|
||||||
{
|
{
|
||||||
timeout = 0x3FFFFFF;
|
long deadline = current_tick + (HZ * 65);
|
||||||
|
|
||||||
while (timeout)
|
do {
|
||||||
{
|
|
||||||
timeout--;
|
|
||||||
stat = REG_MSC_STAT(MSC_CHN(drive));
|
stat = REG_MSC_STAT(MSC_CHN(drive));
|
||||||
|
|
||||||
if (stat & MSC_STAT_TIME_OUT_READ)
|
if (stat & MSC_STAT_TIME_OUT_READ)
|
||||||
return SD_ERROR_TIMEOUT;
|
return SD_ERROR_TIMEOUT;
|
||||||
else if (stat & MSC_STAT_CRC_READ_ERROR)
|
else if (stat & MSC_STAT_CRC_READ_ERROR)
|
||||||
return SD_ERROR_CRC;
|
return SD_ERROR_CRC;
|
||||||
else if (!(stat & MSC_STAT_DATA_FIFO_EMPTY)
|
else if ((stat & MSC_STAT_DATA_FIFO_AFULL) ||
|
||||||
|| (stat & MSC_STAT_DATA_FIFO_AFULL))
|
!(stat & MSC_STAT_DATA_FIFO_EMPTY))
|
||||||
/* Ready to read data */
|
/* Ready to read data */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
udelay(1);
|
yield();
|
||||||
}
|
} while (TIME_BEFORE(current_tick, deadline));
|
||||||
|
|
||||||
if (!timeout)
|
|
||||||
return SD_ERROR_TIMEOUT;
|
|
||||||
|
|
||||||
/* Read data from RXFIFO. It could be FULL or PARTIAL FULL */
|
/* Read data from RXFIFO. It could be FULL or PARTIAL FULL */
|
||||||
DEBUG("Receive Data = %d", wblocklen);
|
DEBUG("Receive Data = %d", wblocklen);
|
||||||
cnt = wblocklen;
|
cnt = wblocklen;
|
||||||
while (cnt)
|
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));
|
data = REG_MSC_RXFIFO(MSC_CHN(drive));
|
||||||
if (waligned)
|
if (waligned)
|
||||||
*wbuf++ = data;
|
*wbuf++ = data;
|
||||||
|
|
@ -461,9 +433,6 @@ static int jz_sd_receive_data(const int drive, struct sd_request *req)
|
||||||
*buf++ = (unsigned char) (data >> 24);
|
*buf++ = (unsigned char) (data >> 24);
|
||||||
}
|
}
|
||||||
cnt--;
|
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 char *buf = req->buffer;
|
||||||
unsigned int *wbuf = (unsigned int *) buf;
|
unsigned int *wbuf = (unsigned int *) buf;
|
||||||
unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */
|
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--)
|
for (; nob >= 1; nob--)
|
||||||
{
|
{
|
||||||
timeout = 0x3FFFFFF;
|
long deadline = current_tick + (HZ * 65);
|
||||||
|
|
||||||
while (timeout)
|
do {
|
||||||
{
|
|
||||||
timeout--;
|
|
||||||
stat = REG_MSC_STAT(MSC_CHN(drive));
|
stat = REG_MSC_STAT(MSC_CHN(drive));
|
||||||
|
|
||||||
if (stat &
|
if (stat &
|
||||||
|
|
@ -496,17 +463,19 @@ static int jz_sd_transmit_data(const int drive, struct sd_request *req)
|
||||||
/* Ready to write data */
|
/* Ready to write data */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
udelay(1);
|
yield();
|
||||||
}
|
} while (TIME_BEFORE(current_tick, deadline));
|
||||||
|
|
||||||
if (!timeout)
|
|
||||||
return SD_ERROR_TIMEOUT;
|
|
||||||
|
|
||||||
/* Write data to TXFIFO */
|
/* Write data to TXFIFO */
|
||||||
cnt = wblocklen;
|
cnt = wblocklen;
|
||||||
while (cnt)
|
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)
|
if (waligned)
|
||||||
REG_MSC_TXFIFO(MSC_CHN(drive)) = *wbuf++;
|
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
|
#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 ? */
|
if ((unsigned int)req->buffer & 0x3)
|
||||||
unsigned int size = req->block_len * req->nob;
|
return jz_sd_receive_data(drive, req);
|
||||||
|
|
||||||
if (!waligned)
|
|
||||||
{
|
|
||||||
jz_sd_receive_data(drive, req);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush dcache */
|
/* flush dcache */
|
||||||
dma_cache_wback_inv((unsigned long) req->buffer, size);
|
dma_cache_wback_inv((unsigned long) req->buffer, req->cnt);
|
||||||
|
|
||||||
/* setup dma channel */
|
/* setup dma channel */
|
||||||
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = 0;
|
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_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_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_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) =
|
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_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 |
|
||||||
DMAC_DCMD_DS_32BIT;
|
DMAC_DCMD_DS_32BIT;
|
||||||
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
|
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
|
||||||
|
|
||||||
/* wait for dma completion */
|
/* 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 */
|
/* clear status and disable channel */
|
||||||
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = 0;
|
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 ? */
|
if ((unsigned int)req->buffer & 0x3)
|
||||||
unsigned int size = req->block_len * req->nob;
|
return jz_sd_transmit_data(drive, req);
|
||||||
|
|
||||||
if (!waligned)
|
|
||||||
{
|
|
||||||
jz_sd_transmit_data(drive, req);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush dcache */
|
/* flush dcache */
|
||||||
dma_cache_wback_inv((unsigned long) req->buffer, size);
|
dma_cache_wback_inv((unsigned long) req->buffer, req->cnt);
|
||||||
|
|
||||||
/* setup dma channel */
|
/* setup dma channel */
|
||||||
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = 0;
|
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_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_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_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) =
|
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_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 |
|
||||||
DMAC_DCMD_DS_32BIT;
|
DMAC_DCMD_DS_32BIT;
|
||||||
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
|
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
|
||||||
|
|
||||||
/* wait for dma completion */
|
/* 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 */
|
/* clear status and disable channel */
|
||||||
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) = 0;
|
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) = 0;
|
||||||
|
|
||||||
|
return SD_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SD_DMA_INTERRUPT
|
||||||
void DMA_CALLBACK(DMA_SD_RX_CHANNEL)(void)
|
void DMA_CALLBACK(DMA_SD_RX_CHANNEL)(void)
|
||||||
{
|
{
|
||||||
if (REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) & DMAC_DCCSR_AR)
|
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;
|
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) &= ~DMAC_DCCSR_TT;
|
||||||
//sd_rx_dma_callback();
|
//sd_rx_dma_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
semaphore_release(&sd_wakeup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA_CALLBACK(DMA_SD_TX_CHANNEL)(void)
|
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;
|
REG_DMAC_DCCSR(DMA_SD_TX_CHANNEL) &= ~DMAC_DCCSR_TT;
|
||||||
//sd_tx_dma_callback();
|
//sd_tx_dma_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
semaphore_release(&sd_wakeup);
|
||||||
}
|
}
|
||||||
|
#endif /* SD_DMA_INTERRUPT */
|
||||||
#endif /* SD_DMA_ENABLE */
|
#endif /* SD_DMA_ENABLE */
|
||||||
|
|
||||||
static inline unsigned int jz_sd_calc_clkrt(const int drive, unsigned int rate)
|
static inline unsigned int jz_sd_calc_clkrt(const int drive, unsigned int rate)
|
||||||
|
|
@ -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)
|
static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
|
||||||
{
|
{
|
||||||
unsigned int cmdat = 0, events = 0;
|
unsigned int cmdat = 0, events = 0;
|
||||||
int retval, timeout = 0x3fffff;
|
int retval;
|
||||||
|
long deadline = current_tick + (HZ * 5);
|
||||||
|
|
||||||
/* Indicate we have no result yet */
|
/* Indicate we have no result yet */
|
||||||
request->result = SD_NO_RESPONSE;
|
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 */
|
/* On reset, stop SD clock */
|
||||||
jz_sd_stop_clock(drive);
|
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 */
|
/* stop clock */
|
||||||
jz_sd_stop_clock(drive);
|
jz_sd_stop_clock(drive);
|
||||||
|
|
||||||
/* mask all interrupts */
|
/* mask all interrupts and clear status */
|
||||||
//REG_MSC_IMASK(MSC_CHN(drive)) = 0xffff;
|
SD_IRQ_MASK(MSC_CHN(drive));
|
||||||
/* clear status */
|
|
||||||
REG_MSC_IREG(MSC_CHN(drive)) = 0xffff;
|
|
||||||
/*open interrupt */
|
/*open interrupt */
|
||||||
REG_MSC_IMASK(MSC_CHN(drive)) = (~7);
|
REG_MSC_IMASK(MSC_CHN(drive)) = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_DATA_TRAN_DONE | MSC_IMASK_PRG_DONE);
|
||||||
/* use 4-bit bus width when possible */
|
|
||||||
if (use_4bit[drive])
|
|
||||||
cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
|
|
||||||
|
|
||||||
/* Set command type and events */
|
/* Set command type and events */
|
||||||
switch (request->cmd)
|
switch (request->cmd)
|
||||||
|
|
@ -750,10 +716,18 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* adtc - addressed with data transfer */
|
/* 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_DAT_UNTIL_STOP:
|
||||||
case SD_READ_SINGLE_BLOCK:
|
case SD_READ_SINGLE_BLOCK:
|
||||||
case SD_READ_MULTIPLE_BLOCK:
|
case SD_READ_MULTIPLE_BLOCK:
|
||||||
case SD_SEND_SCR:
|
|
||||||
#if SD_DMA_ENABLE
|
#if SD_DMA_ENABLE
|
||||||
cmdat |=
|
cmdat |=
|
||||||
MSC_CMDAT_DATA_EN | MSC_CMDAT_READ | MSC_CMDAT_DMA_EN;
|
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;
|
events = SD_EVENT_RX_DATA_DONE;
|
||||||
break;
|
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 (num_6[drive] < 2)
|
||||||
{
|
{
|
||||||
#if SD_DMA_ENABLE
|
#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_WRITE_MULTIPLE_BLOCK:
|
||||||
case SD_PROGRAM_CID:
|
case SD_PROGRAM_CID:
|
||||||
case SD_PROGRAM_CSD:
|
case SD_PROGRAM_CSD:
|
||||||
case SD_LOCK_UNLOCK:
|
// case SD_LOCK_UNLOCK:
|
||||||
#if SD_DMA_ENABLE
|
#if SD_DMA_ENABLE
|
||||||
cmdat |=
|
cmdat |=
|
||||||
MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE | MSC_CMDAT_DMA_EN;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* use 4-bit bus width when possible */
|
||||||
|
if (use_4bit[drive])
|
||||||
|
cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
|
||||||
|
|
||||||
/* Set command index */
|
/* Set command index */
|
||||||
if (request->cmd == SD_CIM_RESET)
|
if (request->cmd == SD_CIM_RESET)
|
||||||
REG_MSC_CMD(MSC_CHN(drive)) = SD_GO_IDLE_STATE;
|
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;
|
REG_MSC_ARG(MSC_CHN(drive)) = request->arg;
|
||||||
|
|
||||||
/* Set block length and nob */
|
/* 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_BLKLEN(MSC_CHN(drive)) = request->block_len;
|
||||||
REG_MSC_NOB(MSC_CHN(drive)) = request->nob;
|
REG_MSC_NOB(MSC_CHN(drive)) = request->nob;
|
||||||
}
|
|
||||||
|
|
||||||
/* Set command */
|
/* Set command */
|
||||||
REG_MSC_CMDAT(MSC_CHN(drive)) = cmdat;
|
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 */
|
/* Wait for command completion */
|
||||||
//__intc_unmask_irq(IRQ_MSC);
|
//__intc_unmask_irq(IRQ_MSC);
|
||||||
//semaphore_wait(&sd_wakeup, 100);
|
//semaphore_wait(&sd_wakeup, 100);
|
||||||
while (timeout-- && !(REG_MSC_STAT(MSC_CHN(drive)) & MSC_STAT_END_CMD_RES));
|
while (!(REG_MSC_IREG(MSC_CHN(drive)) & MSC_IREG_END_CMD_RES))
|
||||||
|
{
|
||||||
|
if (TIME_AFTER(current_tick, deadline))
|
||||||
if (timeout == 0)
|
|
||||||
return SD_ERROR_TIMEOUT;
|
return SD_ERROR_TIMEOUT;
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
REG_MSC_IREG(MSC_CHN(drive)) = MSC_IREG_END_CMD_RES; /* clear flag */
|
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 (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
|
#if SD_DMA_ENABLE
|
||||||
jz_sd_receive_data_dma(drive, request);
|
retval = jz_sd_receive_data_dma(drive, request);
|
||||||
#else
|
#else
|
||||||
jz_sd_receive_data(drive, request);
|
retval = jz_sd_receive_data(drive, request);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
if (events & SD_EVENT_TX_DATA_DONE)
|
if (events & SD_EVENT_TX_DATA_DONE)
|
||||||
{
|
{
|
||||||
#if SD_DMA_ENABLE
|
#if SD_DMA_ENABLE
|
||||||
jz_sd_transmit_data_dma(drive, request);
|
retval = jz_sd_transmit_data_dma(drive, request);
|
||||||
#else
|
#else
|
||||||
jz_sd_transmit_data(drive, request);
|
retval = jz_sd_transmit_data(drive, request);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
//__intc_unmask_irq(IRQ_MSC);
|
//__intc_unmask_irq(IRQ_MSC);
|
||||||
//semaphore_wait(&sd_wakeup, 100);
|
//semaphore_wait(&sd_wakeup, 100);
|
||||||
/* Wait for Data Done */
|
/* 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 */
|
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);
|
//__intc_unmask_irq(IRQ_MSC);
|
||||||
//semaphore_wait(&sd_wakeup, 100);
|
//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 */
|
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 */
|
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,
|
unsigned short nob, unsigned short block_len,
|
||||||
enum sd_rsp_t rtype, unsigned char* buffer)
|
enum sd_rsp_t rtype, unsigned char* buffer)
|
||||||
{
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
request->cmd = cmd;
|
request->cmd = cmd;
|
||||||
request->arg = arg;
|
request->arg = arg;
|
||||||
request->rtype = rtype;
|
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->buffer = buffer;
|
||||||
request->cnt = nob * block_len;
|
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,
|
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);
|
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_DOING 0
|
||||||
#define SD_INIT_PASSED 1
|
#define SD_INIT_PASSED 1
|
||||||
#define SD_INIT_FAILED 2
|
#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_r1 r1;
|
||||||
struct sd_response_r3 r3;
|
struct sd_response_r3 r3;
|
||||||
int retval, i, ocr = 0x40300000, limit_41 = 0;
|
int retval, i, ocr = 0x40300000;
|
||||||
|
|
||||||
switch (request->cmd)
|
switch (request->cmd)
|
||||||
{
|
{
|
||||||
|
|
@ -1028,28 +1029,15 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_APP_CMD:
|
case SD_APP_CMD:
|
||||||
retval = sd_unpack_r1(request, &r1);
|
if (sd_unpack_r1(request, &r1))
|
||||||
if (retval & (limit_41 < 100))
|
return SD_INIT_FAILED;
|
||||||
{
|
|
||||||
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);
|
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);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_APP_OP_COND:
|
case SD_APP_OP_COND:
|
||||||
retval = sd_unpack_r3(request, &r3);
|
retval = sd_unpack_r3(request, &r3);
|
||||||
if (retval)
|
if (retval)
|
||||||
break;
|
return SD_INIT_FAILED;
|
||||||
|
|
||||||
DEBUG("sd_init_card_state: read ocr value = 0x%08x", r3.ocr);
|
DEBUG("sd_init_card_state: read ocr value = 0x%08x", r3.ocr);
|
||||||
card[drive].ocr = r3.ocr;
|
card[drive].ocr = r3.ocr;
|
||||||
|
|
@ -1068,6 +1056,9 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_ALL_SEND_CID:
|
case SD_ALL_SEND_CID:
|
||||||
|
if (request->result)
|
||||||
|
return SD_INIT_FAILED;
|
||||||
|
|
||||||
for(i=0; i<4; i++)
|
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]);
|
(request->response[3+i*4]<< 8) | request->response[4+i*4]);
|
||||||
|
|
@ -1075,6 +1066,7 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
|
||||||
logf("CID: %08lx%08lx%08lx%08lx", card[drive].cid[0], card[drive].cid[1], card[drive].cid[2], card[drive].cid[3]);
|
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);
|
sd_simple_cmd(drive, request, SD_SEND_RELATIVE_ADDR, 0, RESPONSE_R6);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_SEND_RELATIVE_ADDR:
|
case SD_SEND_RELATIVE_ADDR:
|
||||||
retval = sd_unpack_r6(request, &r1, &card[drive].rca);
|
retval = sd_unpack_r6(request, &r1, &card[drive].rca);
|
||||||
card[drive].rca = card[drive].rca << 16;
|
card[drive].rca = card[drive].rca << 16;
|
||||||
|
|
@ -1090,6 +1082,8 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_SEND_CSD:
|
case SD_SEND_CSD:
|
||||||
|
if (request->result)
|
||||||
|
return SD_INIT_FAILED;
|
||||||
for(i=0; i<4; i++)
|
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]);
|
(request->response[3+i*4]<< 8) | request->response[4+i*4]);
|
||||||
|
|
@ -1120,7 +1114,7 @@ static int sd_switch(const int drive, struct sd_request *request, int mode, int
|
||||||
arg = (mode << 31 | 0x00FFFFFF);
|
arg = (mode << 31 | 0x00FFFFFF);
|
||||||
arg &= ~(0xF << (group * 4));
|
arg &= ~(0xF << (group * 4));
|
||||||
arg |= value << (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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1174,13 +1168,10 @@ static int sd_select_card(const int drive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
num_6[drive] = 3;
|
num_6[drive] = 3;
|
||||||
sd_simple_cmd(drive, &request, SD_APP_CMD, card[drive].rca,
|
retval = sd_exec_acmd(drive, &request, SD_SET_BUS_WIDTH, 2);
|
||||||
RESPONSE_R1);
|
|
||||||
retval = sd_unpack_r1(&request, &r1);
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
sd_simple_cmd(drive, &request, SD_SET_BUS_WIDTH, 2, RESPONSE_R1);
|
retval = sd_exec_acmd(drive, &request, SD_SET_CLR_CARD_DETECT, 0);
|
||||||
retval = sd_unpack_r1(&request, &r1);
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
|
@ -1192,8 +1183,8 @@ static int sd_select_card(const int drive)
|
||||||
static int sd_init_device(const int drive)
|
static int sd_init_device(const int drive)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
long deadline;
|
||||||
struct sd_request init_req;
|
struct sd_request init_req;
|
||||||
register int timeout = 1000;
|
|
||||||
|
|
||||||
mutex_lock(&sd_mtx);
|
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 */
|
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);
|
retval = (retval == SD_INIT_PASSED ? sd_select_card(drive) : -1);
|
||||||
|
|
||||||
if (drive == SD_SLOT_1)
|
if (drive == SD_SLOT_1)
|
||||||
|
|
@ -1238,8 +1233,17 @@ int sd_init(void)
|
||||||
|
|
||||||
if(!inited)
|
if(!inited)
|
||||||
{
|
{
|
||||||
// semaphore_init(&sd_wakeup, 1, 0);
|
|
||||||
|
#if SD_DMA_INTERRUPT
|
||||||
|
semaphore_init(&sd_wakeup, 1, 0);
|
||||||
|
#endif
|
||||||
mutex_init(&sd_mtx);
|
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;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1279,107 +1283,63 @@ static inline void sd_stop_transfer(const int drive)
|
||||||
mutex_unlock(&sd_mtx);
|
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_request request;
|
||||||
struct sd_response_r1 r1;
|
struct sd_response_r1 r1;
|
||||||
int retval = -1;
|
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;
|
goto err;
|
||||||
|
|
||||||
if(card[drive].initialized == 0 && !sd_init_device(drive))
|
if(card[drive].initialized == 0 && !sd_init_device(drive))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
sd_simple_cmd(drive, &request, SD_SEND_STATUS, card[drive].rca, RESPONSE_R1);
|
sd_simple_cmd(drive, &request, SD_SEND_STATUS, card[drive].rca, RESPONSE_R1);
|
||||||
retval = sd_unpack_r1(&request, &r1);
|
if ((retval = sd_unpack_r1(&request, &r1)))
|
||||||
if (retval && (retval != SD_ERROR_STATE_MISMATCH))
|
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
sd_simple_cmd(drive, &request, SD_SET_BLOCKLEN, SD_BLOCK_SIZE, RESPONSE_R1);
|
sd_simple_cmd(drive, &request, SD_SET_BLOCKLEN, SD_BLOCK_SIZE, RESPONSE_R1);
|
||||||
if ((retval = sd_unpack_r1(&request, &r1)))
|
if ((retval = sd_unpack_r1(&request, &r1)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (sd2_0[drive])
|
sd_send_cmd(drive, &request,
|
||||||
{
|
(count > 1) ?
|
||||||
sd_send_cmd(drive, &request, SD_READ_MULTIPLE_BLOCK, start,
|
(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);
|
count, SD_BLOCK_SIZE, RESPONSE_R1, buf);
|
||||||
if ((retval = sd_unpack_r1(&request, &r1)))
|
if ((retval = sd_unpack_r1(&request, &r1)))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
else
|
if (count > 1)
|
||||||
{
|
{
|
||||||
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_simple_cmd(drive, &request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B);
|
||||||
if ((retval = sd_unpack_r1(&request, &r1)))
|
retval = sd_unpack_r1(&request, &r1);
|
||||||
goto err;
|
if (!write && retval == SD_ERROR_OUT_OF_RANGE)
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
last_disk_activity = current_tick;
|
||||||
sd_stop_transfer(drive);
|
sd_stop_transfer(drive);
|
||||||
|
|
||||||
return retval;
|
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;
|
int sd_write_sectors(IF_MD(int drive,) unsigned long start, int count, const void* buf)
|
||||||
struct sd_response_r1 r1;
|
{
|
||||||
int retval = -1;
|
return sd_transfer_sectors(IF_MD(drive,) start, count, (void*)buf, true);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long sd_last_disk_activity(void)
|
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. */
|
* clear if the last attempt to init failed with an error. */
|
||||||
mutex_lock(&sd_mtx); /* lock-out card activity */
|
mutex_lock(&sd_mtx); /* lock-out card activity */
|
||||||
card[data].initialized = 0;
|
card[data].initialized = 0;
|
||||||
if (id == SYS_HOTSWAP_INSERTED)
|
// if (id == SYS_HOTSWAP_INSERTED)
|
||||||
sd_init_device(data);
|
// sd_init_device(data);
|
||||||
mutex_unlock(&sd_mtx);
|
mutex_unlock(&sd_mtx);
|
||||||
break;
|
break;
|
||||||
#endif /* HAVE_HOTSWAP */
|
#endif /* HAVE_HOTSWAP */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue