jz47xx: Numerous enhancements to the SD driver

* Rework logf/DEBUG distinction
 * Don't try to init a card that isn't detected
 * Inform card that host supports SDUC
 * Implement CMD22 (SET_UPPER_ADDR)
 * Implement CMD23 (SET_BLOCK_COUNT)
 * Disable DMA for transfers under 512 bytes
 * Created ACMD+data xfer command path
 * Incorrect handling of RESPONSE_R7
 * Clean up 4bit stuff, only turn it on after we enable it in the card.
 * Clear END_CMD_RES bit _after_ we check the status

 * Probe SCR  <-- NOT YET WORKING, DISABLED

jz4740 had these additional improvements:

 * Restructuring to bring it closer to 4760 driver
 * Unified read/write setup code
 * IRQ handling and polling improvements

Change-Id: I47379f097af4bf50177499b3d80a6c9c42d48057
This commit is contained in:
Solomon Peachy 2026-02-16 21:53:23 -05:00
parent 478303346c
commit 59f78841fd
2 changed files with 428 additions and 407 deletions

View file

@ -41,7 +41,7 @@ static struct mutex sd_mtx;
//static struct semaphore sd_wakeup;
static int use_4bit;
static int num_6;
static int use_sbc;
//#define SD_DMA_ENABLE
#define SD_DMA_INTERRUPT 0
@ -84,6 +84,7 @@ enum sd_result_t
SD_ERROR_TIMEOUT,
SD_ERROR_CRC,
SD_ERROR_DRIVER_FAILURE,
SD_ERROR_ACMD_REJECT,
};
/* Standard MMC/SD clock speeds */
@ -109,19 +110,17 @@ enum sd_result_t
/* class 9 */
#define SD_GO_IRQ_STATE 40 /* bcr R5 */
/* Don't change the order of these; they are used in dispatch tables */
enum sd_rsp_t
{
RESPONSE_NONE = 0,
RESPONSE_R1 = 1,
RESPONSE_R1B = 2,
RESPONSE_R2_CID = 3,
RESPONSE_R2_CSD = 4,
RESPONSE_R3 = 5,
RESPONSE_R4 = 6,
RESPONSE_R5 = 7,
RESPONSE_R6 = 8,
RESPONSE_R7 = 9,
RESPONSE_R2 = 3,
RESPONSE_R3 = 4,
RESPONSE_R4 = 5,
RESPONSE_R5 = 6,
RESPONSE_R6 = 7,
RESPONSE_R7 = 8,
};
/*
@ -179,10 +178,9 @@ struct sd_response_r3
struct sd_request
{
int index; /* Slot index - used for CS lines */
int cmd; /* Command to send */
unsigned int arg; /* Argument to send */
enum sd_rsp_t rtype; /* Response type expected */
enum sd_rsp_t rtype; /* Response type expected */
/* Data transfer (these may be modified at the low level) */
unsigned short nob; /* Number of blocks to transfer*/
@ -195,16 +193,6 @@ struct sd_request
enum sd_result_t result;
};
#define SD_OCR_ARG 0x00ff8000 /* Argument of OCR */
/***********************************************************************
* SD Events
*/
#define SD_EVENT_NONE 0x00 /* No events */
#define SD_EVENT_RX_DATA_DONE 0x01 /* Rx data done */
#define SD_EVENT_TX_DATA_DONE 0x02 /* Tx data done */
#define SD_EVENT_PROG_DONE 0x04 /* Programming is done */
/**************************************************************************
* Utility functions
**************************************************************************/
@ -262,6 +250,9 @@ static int sd_unpack_r6(struct sd_request *request, struct sd_response_r1 *r1, u
if (request->result)
return request->result;
if (buf[0] != 0x03)
return SD_ERROR_HEADER_MISMATCH;
*rca = PARSE_U16(buf,1); /* Save RCA returned by the SD Card */
*(buf+1) = 0;
@ -298,7 +289,7 @@ static inline int jz_sd_stop_clock(void)
timeout--;
if (timeout == 0)
{
DEBUG("Timeout on stop clock waiting");
logf("Timeout on stop clock waiting");
return SD_ERROR_TIMEOUT;
}
udelay(1);
@ -322,7 +313,7 @@ static int jz_sd_check_status(struct sd_request *request)
/* Checking for response or data timeout */
if (status & (MSC_STAT_TIME_OUT_RES | MSC_STAT_TIME_OUT_READ))
{
DEBUG("SD timeout, MSC_STAT 0x%x CMD %d", status,
logf("SD timeout, MSC_STAT 0x%x CMD %d", status,
request->cmd);
return SD_ERROR_TIMEOUT;
}
@ -332,7 +323,7 @@ static int jz_sd_check_status(struct sd_request *request)
(MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR |
MSC_STAT_CRC_RES_ERR))
{
DEBUG("SD CRC error, MSC_STAT 0x%x", status);
logf("SD CRC error, MSC_STAT 0x%x", status);
return SD_ERROR_CRC;
}
@ -341,7 +332,7 @@ static int jz_sd_check_status(struct sd_request *request)
/* Checking for FIFO empty */
/*if(status & MSC_STAT_DATA_FIFO_EMPTY && request->rtype != RESPONSE_NONE)
{
DEBUG("SD FIFO empty, MSC_STAT 0x%x", status);
logf("SD FIFO empty, MSC_STAT 0x%x", status);
return SD_ERROR_UNDERRUN;
}*/
@ -360,16 +351,14 @@ static void jz_sd_get_response(struct sd_request *request)
buf = request->response;
request->result = SD_NO_ERROR;
switch (request->rtype)
{
switch (request->rtype) {
case RESPONSE_R1:
case RESPONSE_R1B:
case RESPONSE_R7:
case RESPONSE_R6:
case RESPONSE_R3:
case RESPONSE_R4:
case RESPONSE_R5:
{
case RESPONSE_R6:
case RESPONSE_R7:
data = REG_MSC_RES;
buf[0] = (data >> 8) & 0xff;
buf[1] = data & 0xff;
@ -383,10 +372,7 @@ static void jz_sd_get_response(struct sd_request *request)
request->rtype, buf[0], buf[1], buf[2],
buf[3], buf[4]);
break;
}
case RESPONSE_R2_CID:
case RESPONSE_R2_CSD:
{
case RESPONSE_R2:
for (i = 0; i < 16; i += 2)
{
data = REG_MSC_RES;
@ -395,7 +381,6 @@ static void jz_sd_get_response(struct sd_request *request)
}
DEBUG("request %d, response []", request->rtype);
break;
}
case RESPONSE_NONE:
DEBUG("No response");
break;
@ -441,6 +426,9 @@ static void jz_sd_receive_data_dma(struct sd_request *req)
/* clear status and disable channel */
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL) = 0;
/* flush dcache again */
discard_dcache_range(req->buffer, req->cnt);
}
static void jz_mmc_transmit_data_dma(struct mmc_request *req)
@ -488,6 +476,12 @@ static int jz_sd_receive_data(struct sd_request *req)
unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */
unsigned int stat, timeout, data, cnt;
#ifdef SD_DMA_ENABLE
if (waligned)
jz_sd_reveive_data_dma(request);
return SD_NO_ERROR;
#endif
for (; nob >= 1; nob--)
{
timeout = 0x3FFFFFF;
@ -546,6 +540,12 @@ static int jz_sd_transmit_data(struct sd_request *req)
unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */
unsigned int stat, timeout, data, cnt;
#ifdef SD_DMA_ENABLE
if (waligned)
jz_sd_transmit_data_dma(request);
return SD_NO_ERROR;
#endif
for (; nob >= 1; nob--)
{
timeout = 0x3FFFFFF;
@ -640,12 +640,16 @@ static void jz_sd_set_clock(unsigned int rate)
********************************************************************************************************************/
static int jz_sd_exec_cmd(struct sd_request *request)
{
unsigned int cmdat = 0, events = 0;
unsigned int cmdat = 0;
int retval, timeout = 0x3fffff;
bool has_data = (request->buffer != NULL);
/* Indicate we have no result yet */
request->result = SD_NO_RESPONSE;
/* Stop clock when programming things */
jz_sd_stop_clock(); /* stop SD clock */
if (request->cmd == SD_CIM_RESET) {
/* On reset, 1-bit bus width */
use_4bit = 0;
@ -659,31 +663,30 @@ static int jz_sd_exec_cmd(struct sd_request *request)
/* On reset, stop SD clock */
jz_sd_stop_clock();
}
if (request->cmd == SD_SET_BUS_WIDTH)
{
if (request->arg == 0x2)
{
DEBUG("Use 4-bit bus width");
use_4bit = 1;
}
else
{
DEBUG("Use 1-bit bus width");
use_4bit = 0;
}
/* Generic handling for all requests with data rx/tx */
if (has_data) {
cmdat |= MSC_CMDAT_DATA_EN;
// if (request->nob > 1 && use_sbc[drive])
// cmdat |= MSC_CMDAT_SEND_AS_STOP;
#ifdef SD_DMA_ENABLE
if (request->cnt >= 512)
cmdat |= MSC_CMDAT_DMA_EN;
#endif
}
/* mask all interrupts */
//REG_MSC_IMASK = 0xffff;
REG_MSC_IMASK = 0xffff;
/* clear status */
REG_MSC_IREG = 0xffff;
/*open interrupt */
REG_MSC_IMASK = (~7);
/* unmask interrupts we care about */
REG_MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_DATA_TRAN_DONE | MSC_IMASK_PRG_DONE);
/* use 4-bit bus width when possible */
if (use_4bit)
cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
/* Set command type and events */
/* Per-command type handling */
switch (request->cmd)
{
/* SD core extra command */
@ -706,27 +709,8 @@ static int jz_sd_exec_cmd(struct sd_request *request)
case SD_READ_SINGLE_BLOCK:
case SD_READ_MULTIPLE_BLOCK:
case SD_SEND_SCR:
#if defined(SD_DMA_ENABLE)
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_READ | MSC_CMDAT_DMA_EN;
#else
cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ;
#endif
events = SD_EVENT_RX_DATA_DONE;
break;
case SD_SWITCH_FUNC:
if (num_6 < 2)
{
#if defined(SD_DMA_ENABLE)
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_READ |
MSC_CMDAT_DMA_EN;
#else
cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ;
#endif
events = SD_EVENT_RX_DATA_DONE;
}
/* These READ data */
break;
case SD_WRITE_DAT_UNTIL_STOP:
@ -734,18 +718,14 @@ static int jz_sd_exec_cmd(struct sd_request *request)
case SD_WRITE_MULTIPLE_BLOCK:
case SD_PROGRAM_CID:
case SD_PROGRAM_CSD:
case SD_LOCK_UNLOCK:
#if defined(SD_DMA_ENABLE)
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE | MSC_CMDAT_DMA_EN;
#else
cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE;
#endif
events = SD_EVENT_TX_DATA_DONE | SD_EVENT_PROG_DONE;
/* These WRITE data */
cmdat |= MSC_CMDAT_WRITE;
break;
// case SD_LOCK_UNLOCK: // can be a read or write, needs busy too.
case SD_STOP_TRANSMISSION:
events = SD_EVENT_PROG_DONE;
// cmdat |= MSC_CMDAT_STOP_ABORT;
break;
/* ac - no data transfer */
@ -762,11 +742,9 @@ static int jz_sd_exec_cmd(struct sd_request *request)
cmdat |= MSC_CMDAT_BUSY;
/* FALLTHRU */
case RESPONSE_R1:
case RESPONSE_R7:
cmdat |= MSC_CMDAT_RESPONSE_R1;
break;
case RESPONSE_R2_CID:
case RESPONSE_R2_CSD:
case RESPONSE_R2:
cmdat |= MSC_CMDAT_RESPONSE_R2;
break;
case RESPONSE_R3:
@ -781,6 +759,9 @@ static int jz_sd_exec_cmd(struct sd_request *request)
case RESPONSE_R6:
cmdat |= MSC_CMDAT_RESPONSE_R6;
break;
case RESPONSE_R7:
cmdat |= MSC_CMDAT_RESPONSE_R1; /* 4740 lacks R7 */
break;
default:
break;
}
@ -794,14 +775,8 @@ static int jz_sd_exec_cmd(struct sd_request *request)
/* Set argument */
REG_MSC_ARG = request->arg;
/* Set block length and nob */
if (request->cmd == SD_SEND_SCR)
{ /* get SCR from DataFIFO */
REG_MSC_BLKLEN = 8;
REG_MSC_NOB = 1;
}
else
{
/* Set block length and nob if there is data */
if (has_data) {
REG_MSC_BLKLEN = request->block_len;
REG_MSC_NOB = request->nob;
}
@ -816,18 +791,15 @@ static int jz_sd_exec_cmd(struct sd_request *request)
jz_sd_start_clock();
/* Wait for command completion */
//__intc_unmask_irq(IRQ_MSC);
//semaphore_wait(&sd_wakeup, 100);
while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES));
if (timeout == 0)
return SD_ERROR_TIMEOUT;
REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear flag */
/* Check for status */
retval = jz_sd_check_status(request);
REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear flag */
if (retval)
return retval;
@ -839,46 +811,28 @@ static int jz_sd_exec_cmd(struct sd_request *request)
jz_sd_get_response(request);
/* Start data operation */
if (events & (SD_EVENT_RX_DATA_DONE | SD_EVENT_TX_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);
}
#ifdef SD_DMA_ENABLE
jz_sd_receive_data_dma(request);
#else
jz_sd_receive_data(request);
#endif
if (has_data) {
if (cmdat & MSC_CMDAT_WRITE) {
retval = jz_sd_transmit_data(request);
} else {
retval = jz_sd_receive_data(request);
}
if (retval)
return retval;
if (events & SD_EVENT_TX_DATA_DONE)
{
#ifdef SD_DMA_ENABLE
jz_sd_transmit_data_dma(request);
#else
jz_sd_transmit_data(request);
#endif
}
//__intc_unmask_irq(IRQ_MSC);
//semaphore_wait(&sd_wakeup, 100);
/* Wait for Data Done */
while (!(REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE));
while (!(REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE))
yield();
REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */
}
/* Wait for Prog Done event */
if (events & SD_EVENT_PROG_DONE)
/* Wait for Prog Done event if necessary */
if (cmdat & (MSC_CMDAT_BUSY | MSC_CMDAT_WRITE))
{
//__intc_unmask_irq(IRQ_MSC);
//semaphore_wait(&sd_wakeup, 100);
while (!(REG_MSC_IREG & MSC_IREG_PRG_DONE));
while (!(REG_MSC_IREG & MSC_IREG_PRG_DONE))
yield();
REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */
}
@ -904,7 +858,7 @@ static void jz_sd_tx_handler(unsigned int arg)
{
if (__dmac_channel_address_error_detected(arg))
{
DEBUG("%s: DMAC address error.", __FUNCTION__);
logf("%s: DMAC address error.", __FUNCTION__);
__dmac_channel_clear_address_error(arg);
}
if (__dmac_channel_transmit_end_detected(arg))
@ -918,7 +872,7 @@ static void jz_sd_rx_handler(unsigned int arg)
{
if (__dmac_channel_address_error_detected(arg))
{
DEBUG("%s: DMAC address error.", __FUNCTION__);
logf("%s: DMAC address error.", __FUNCTION__);
__dmac_channel_clear_address_error(arg);
}
if (__dmac_channel_transmit_end_detected(arg))
@ -976,10 +930,12 @@ static void jz_sd_hardware_init(void)
#endif
}
static int sd_send_cmd(struct sd_request *request, int cmd, unsigned int arg,
static void sd_send_cmd(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;
@ -987,8 +943,13 @@ static int sd_send_cmd(struct sd_request *request, int cmd, unsigned int arg,
request->block_len = block_len;
request->buffer = buffer;
request->cnt = nob * block_len;
memset(&request->response, 0xa5, sizeof(request->response));
request->result = SD_NO_RESPONSE;
retval = jz_sd_exec_cmd(request);
if (retval)
request->result = retval;
return jz_sd_exec_cmd(request);
}
static void sd_simple_cmd(struct sd_request *request, int cmd, unsigned int arg,
@ -997,6 +958,46 @@ static void sd_simple_cmd(struct sd_request *request, int cmd, unsigned int arg,
sd_send_cmd(request, cmd, arg, 0, 0, rtype, NULL);
}
static int sd_exec_acmd(struct sd_request *request, int cmd, unsigned int arg)
{
struct sd_response_r1 r1;
int retval;
sd_simple_cmd(request, SD_APP_CMD, card.rca, RESPONSE_R1);
retval = sd_unpack_r1(request, &r1);
if (retval)
return retval;
if (!(r1.status & SD_R1_APP_CMD)) {
logf("ACMD not accepted\n");
return SD_ERROR_ACMD_REJECT;
}
sd_simple_cmd(request, cmd, arg, RESPONSE_R1);
return sd_unpack_r1(request, &r1);
}
static int sd_exec_acmd_buf(struct sd_request *request, int cmd, unsigned int arg, enum sd_rsp_t rtype, unsigned short nob, unsigned short block_len, unsigned char *buffer)
{
struct sd_response_r1 r1;
int retval;
sd_simple_cmd(request, SD_APP_CMD, card.rca, RESPONSE_R1);
retval = sd_unpack_r1(request, &r1);
if (retval)
return retval;
if (!(r1.status & SD_R1_APP_CMD)) {
logf("ACMD not accepted\n");
return SD_ERROR_ACMD_REJECT;
}
sd_send_cmd(request, cmd, arg,
nob, block_len, rtype, buffer);
return SD_NO_ERROR;
}
#define SD_INIT_DOING 0
#define SD_INIT_PASSED 1
#define SD_INIT_FAILED 2
@ -1004,59 +1005,50 @@ static int sd_init_card_state(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 /* SDXC, 3.2-3.4v */;
#ifdef HAVE_SDUC
ocr |= 0x08000000; /* Add on SDUC */
#endif
switch (request->cmd)
{
case SD_GO_IDLE_STATE: /* No response to parse */
sd_simple_cmd(request, SD_SEND_IF_COND, 0x1AA, RESPONSE_R1);
break;
case SD_SEND_IF_COND:
retval = sd_unpack_r1(request, &r1);
sd_simple_cmd(request, SD_APP_CMD, 0, RESPONSE_R1);
break;
// if (retval)
// return SD_INIT_FAILED;
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(request, SD_APP_OP_COND, ocr, RESPONSE_R3);
}
else if (limit_41 < 100)
{
limit_41++;
sd_simple_cmd(request, SD_APP_OP_COND, ocr, RESPONSE_R3);
}
else
/* reset the card to idle*/
sd_simple_cmd(request, SD_GO_IDLE_STATE, 0, RESPONSE_NONE);
retval = sd_exec_acmd_buf(request, SD_APP_OP_COND, ocr,
RESPONSE_R3, 0, 0, NULL);
if (retval)
return SD_INIT_FAILED;
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);
DEBUG("read ocr value = 0x%08x", r3.ocr);
card.ocr = r3.ocr;
// XXX for SDUC, check that B27+B30 of OCR are set.
if(!(r3.ocr & SD_CARD_BUSY || ocr == 0))
{
/* Re-issue AP_OP_COND */
sleep(HZ / 100);
sd_simple_cmd(request, SD_APP_CMD, 0, RESPONSE_R1);
retval = sd_exec_acmd_buf(request, SD_APP_OP_COND, ocr,
RESPONSE_R3, 0, 0, NULL);
if (retval)
return SD_INIT_FAILED;
}
else
{
/* Set the data bus width to 4 bits */
use_4bit = 1;
sd_simple_cmd(request, SD_ALL_SEND_CID, 0, RESPONSE_R2_CID);
sd_simple_cmd(request, SD_ALL_SEND_CID, 0, RESPONSE_R2);
}
break;
case SD_ALL_SEND_CID:
for(i=0; i<4; i++)
card.cid[i] = ((request->response[1+i*4]<<24) | (request->response[2+i*4]<<16) |
@ -1067,16 +1059,16 @@ static int sd_init_card_state(struct sd_request *request)
break;
case SD_SEND_RELATIVE_ADDR:
retval = sd_unpack_r6(request, &r1, &card.rca);
card.rca = card.rca << 16;
DEBUG("sd_init_card_state: Get RCA from SD: 0x%04lx Status: %x", card.rca, r1.status);
card.rca = card.rca << 16;
if (retval)
{
DEBUG("sd_init_card_state: unable to SET_RELATIVE_ADDR error=%d",
logf("sd_init_card_state: unable to SET_RELATIVE_ADDR error=%d",
retval);
return SD_INIT_FAILED;
}
sd_simple_cmd(request, SD_SEND_CSD, card.rca, RESPONSE_R2_CSD);
sd_simple_cmd(request, SD_SEND_CSD, card.rca, RESPONSE_R2);
break;
case SD_SEND_CSD:
@ -1087,12 +1079,31 @@ static int sd_init_card_state(struct sd_request *request)
sd_parse_csd(&card);
logf("CSD: %08lx%08lx%08lx%08lx", card.csd[0], card.csd[1], card.csd[2], card.csd[3]);
#if 0 // XXX SCR is not working yet
retval = sd_exec_acmd_buf(request, SD_SEND_SCR, 0, RESPONSE_R1,
1, 8, &request->response[5]);
if (!retval)
retval = sd_unpack_r1(request, &r1);
// XXX check retval?
break;
case SD_SEND_SCR:
// if (request->result)
// return SD_INIT_FAILED;
for(i=0; i<2; i++)
card.scr[i] = ((request->buffer[0+i*4]<<24) | (request->buffer[1+i*4]<<16) |
(request->buffer[2+i*4]<< 8) | request->buffer[3+i*4]);
logf("SCR: %08lx%08lx", card.scr[0], card.scr[1]);
use_sbc = card.scr[0] & 2;
#endif
DEBUG("SD card is ready");
jz_sd_set_clock(SD_CLOCK_FAST);
return SD_INIT_PASSED;
default:
DEBUG("sd_init_card_state: error! Illegal last cmd %d", request->cmd);
logf("sd_init_card_state: error! Illegal last cmd %d", request->cmd);
return SD_INIT_FAILED;
}
@ -1107,8 +1118,11 @@ static int sd_switch(struct sd_request *request, int mode, int group,
mode = !!mode;
value &= 0xF;
arg = (mode << 31 | 0x00FFFFFF);
arg &= ~(0xF << (group * 4));
arg |= value << (group * 4);
if (mode) {
group--;
arg &= ~(0xF << (group * 4));
arg |= value << (group * 4);
}
sd_send_cmd(request, 6, arg, 1, 64, RESPONSE_R1, resp);
return 0;
@ -1137,7 +1151,7 @@ static int sd_switch_hs(struct sd_request *request)
{
unsigned int status[64 / 4];
sd_switch(request, 1, 0, 1, (unsigned char*) status);
sd_switch(request, 1, 1, 1, (unsigned char*) status);
return 0;
}
@ -1162,14 +1176,17 @@ static int sd_select_card(void)
jz_sd_set_clock(SD_CLOCK_HIGH);
}
}
num_6 = 3;
sd_simple_cmd(&request, SD_APP_CMD, card.rca,
RESPONSE_R1);
retval = sd_unpack_r1(&request, &r1);
if (retval)
return retval;
sd_simple_cmd(&request, SD_SET_BUS_WIDTH, 2, RESPONSE_R1);
retval = sd_unpack_r1(&request, &r1);
bool sup_4bit = 1; // XXX check against SCR
if (sup_4bit) {
retval = sd_exec_acmd(&request, SD_SET_BUS_WIDTH, 2);
if (retval)
return retval;
use_4bit = 2;
DEBUG("Use 4-bit bus width");
}
retval = sd_exec_acmd(&request, SD_SET_CLR_CARD_DETECT, 0);
if (retval)
return retval;
@ -1178,6 +1195,11 @@ static int sd_select_card(void)
return 0;
}
static inline bool card_detect_target(void)
{
return (jz_sd_chkcard() == 1);
}
static int __sd_init_device(void)
{
int retval;
@ -1186,12 +1208,14 @@ static int __sd_init_device(void)
/* Initialise card data as blank */
memset(&card, 0, sizeof(tCardInfo));
num_6 = 0;
use_4bit = 0;
/* reset mmc/sd controller */
jz_sd_hardware_init();
if (!card_detect_target())
return 0;
sd_simple_cmd(&init_req, SD_CIM_RESET, 0, RESPONSE_NONE);
sd_simple_cmd(&init_req, SD_GO_IDLE_STATE, 0, RESPONSE_NONE);
@ -1211,6 +1235,7 @@ int sd_init(void)
if(!inited)
{
// semaphore_init(&sd_wakeup, 1, 0);
//__intc_unmask_irq(IRQ_MSC);
mutex_init(&sd_mtx);
inited = true;
}
@ -1222,11 +1247,6 @@ int sd_init(void)
return ret;
}
static inline bool card_detect_target(void)
{
return (jz_sd_chkcard() == 1);
}
tCardInfo* card_get_info_target(int card_no)
{
(void)card_no;
@ -1247,7 +1267,7 @@ static inline void sd_stop_transfer(void)
mutex_unlock(&sd_mtx);
}
int sd_read_sectors(IF_MD(int drive,) sector_t start, int count, void* buf)
int sd_transfer_sectors(IF_MD(int drive,) sector_t start, int count, void* buf, bool write)
{
#ifdef HAVE_MULTIDRIVE
(void)drive;
@ -1273,26 +1293,35 @@ int sd_read_sectors(IF_MD(int drive,) sector_t start, int count, void* buf)
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
// XXX 64-bit
if (card.sd2plus)
{
sd_send_cmd(&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(&request, SD_READ_MULTIPLE_BLOCK,
start * SD_BLOCK_SIZE, count,
SD_BLOCK_SIZE, RESPONSE_R1, buf);
if (use_sbc && count > 1) {
sd_simple_cmd(&request, SD_SET_BLOCK_COUNT, count, RESPONSE_R1);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
sd_simple_cmd(&request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
#ifdef STORAGE_64BIT_SECTOR
// XXX check card[drive].ocr, b27+b30 == 11
if (card.numblocks > 0xffffffffULL) {
uint32_t upper = start >> 32;
sd_simple_cmd(&request, SD_UC_ADDRESS_EXTENSION, upper, RESPONSE_R1);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
#endif
sd_send_cmd(&request,
(count > 1) ?
(write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK) :
(write ? SD_WRITE_BLOCK : SD_READ_SINGLE_BLOCK),
card.sd2plus ? start : (start * SD_BLOCK_SIZE),
count, SD_BLOCK_SIZE, RESPONSE_R1, buf);
retval = sd_unpack_r1(&request, &r1);
if (retval || (!use_sbc && count > 1)) {
sd_simple_cmd(&request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
err:
last_disk_activity = current_tick;
@ -1301,60 +1330,14 @@ err:
return retval;
}
int sd_read_sectors(IF_MD(int drive,) sector_t start, int count, void* buf)
{
return sd_transfer_sectors(IF_MD(drive,) start, count, buf, false);
}
int sd_write_sectors(IF_MD(int drive,) sector_t start, int count, const void* buf)
{
#ifdef HAVE_MULTIDRIVE
(void)drive;
#endif
sd_start_transfer();
struct sd_request request;
struct sd_response_r1 r1;
int retval = -1;
if (!card_detect_target() || count == 0 || start > card.numblocks)
goto err;
if(card.initialized == 0 && !__sd_init_device())
goto err;
sd_simple_cmd(&request, SD_SEND_STATUS, card.rca, RESPONSE_R1);
retval = sd_unpack_r1(&request, &r1);
if (retval && (retval != SD_ERROR_STATE_MISMATCH))
goto err;
sd_simple_cmd(&request, SD_SET_BLOCKLEN, SD_BLOCK_SIZE, RESPONSE_R1);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
// XXX 64-bit
if (card.sd2plus)
{
sd_send_cmd(&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(&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(&request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
err:
sd_stop_transfer();
return retval;
return sd_transfer_sectors(IF_MD(drive,) start, count, (void*)buf, true);
}
long sd_last_disk_activity(void)

View file

@ -56,7 +56,7 @@ static struct semaphore sd_wakeup[NUM_DRIVES];
#endif
static int use_4bit[NUM_DRIVES];
static int num_6[NUM_DRIVES];
static int use_sbc[NUM_DRIVES];
//#define DEBUG(x...) logf(x)
#define DEBUG(x, ...)
@ -99,6 +99,7 @@ enum sd_result_t
SD_ERROR_TIMEOUT,
SD_ERROR_CRC,
SD_ERROR_DRIVER_FAILURE,
SD_ERROR_ACMD_REJECT,
};
/* Standard MMC/SD clock speeds */
@ -124,19 +125,17 @@ enum sd_result_t
/* class 9 */
#define SD_GO_IRQ_STATE 40 /* bcr R5 */
/* Don't change the order of these; they are used in dispatch tables */
enum sd_rsp_t
{
RESPONSE_NONE = 0,
RESPONSE_R1 = 1,
RESPONSE_R1B = 2,
RESPONSE_R2_CID = 3,
RESPONSE_R2_CSD = 4,
RESPONSE_R3 = 5,
RESPONSE_R4 = 6,
RESPONSE_R5 = 7,
RESPONSE_R6 = 8,
RESPONSE_R7 = 9,
RESPONSE_R2 = 3,
RESPONSE_R3 = 4,
RESPONSE_R4 = 5,
RESPONSE_R5 = 6,
RESPONSE_R6 = 7,
RESPONSE_R7 = 8,
};
/* These are unpacked versions of the actual responses */
@ -155,10 +154,9 @@ struct sd_response_r3
struct sd_request
{
int index; /* Slot index - used for CS lines */
int cmd; /* Command to send */
unsigned int arg; /* Argument to send */
enum sd_rsp_t rtype; /* Response type expected */
enum sd_rsp_t rtype; /* Response type expected */
/* Data transfer (these may be modified at the low level) */
unsigned short nob; /* Number of blocks to transfer*/
@ -171,16 +169,6 @@ struct sd_request
enum sd_result_t result;
};
#define SD_OCR_ARG 0x00ff8000 /* Argument of OCR */
/***********************************************************************
* SD Events
*/
#define SD_EVENT_NONE 0x00 /* No events */
#define SD_EVENT_RX_DATA_DONE 0x01 /* Rx data done */
#define SD_EVENT_TX_DATA_DONE 0x02 /* Tx data done */
#define SD_EVENT_PROG_DONE 0x04 /* Programming is done */
/**************************************************************************
* Utility functions
**************************************************************************/
@ -238,6 +226,9 @@ static int sd_unpack_r6(struct sd_request *request, struct sd_response_r1 *r1, u
if (request->result)
return request->result;
if (buf[0] != 0x03)
return SD_ERROR_HEADER_MISMATCH;
*rca = PARSE_U16(buf,1); /* Save RCA returned by the SD Card */
*(buf+1) = 0;
@ -282,7 +273,7 @@ static inline int jz_sd_stop_clock(const int drive)
timeout--;
if (timeout == 0)
{
DEBUG("Timeout on stop clock waiting");
logf("Timeout on stop clock waiting");
return SD_ERROR_TIMEOUT;
}
udelay(1);
@ -311,7 +302,7 @@ static int jz_sd_check_status(const int drive, struct sd_request *request)
/* Checking for response or data timeout */
if (status & (MSC_STAT_TIME_OUT_RES | MSC_STAT_TIME_OUT_READ))
{
DEBUG("SD timeout, MSC_STAT 0x%x CMD %d", status,
logf("%d SD timeout, MSC_STAT 0x%x CMD %d", drive, status,
request->cmd);
return SD_ERROR_TIMEOUT;
}
@ -321,14 +312,14 @@ static int jz_sd_check_status(const int drive, struct sd_request *request)
(MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR |
MSC_STAT_CRC_RES_ERR))
{
DEBUG("SD CRC error, MSC_STAT 0x%x", status);
logf("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)
{
DEBUG("SD FIFO empty, MSC_STAT 0x%x", status);
logf("SD FIFO empty, MSC_STAT 0x%x", status);
return SD_ERROR_UNDERRUN;
}*/
@ -350,16 +341,14 @@ static void jz_sd_get_response(const int drive, struct sd_request *request)
buf = request->response;
request->result = SD_NO_ERROR;
switch (request->rtype)
{
switch (request->rtype) {
case RESPONSE_R1:
case RESPONSE_R1B:
case RESPONSE_R7:
case RESPONSE_R6:
case RESPONSE_R3:
case RESPONSE_R4:
case RESPONSE_R5:
{
case RESPONSE_R6:
case RESPONSE_R7:
data = REG_MSC_RES(MSC_CHN(drive));
buf[0] = (data >> 8) & 0xff;
buf[1] = data & 0xff;
@ -369,14 +358,11 @@ static void jz_sd_get_response(const int drive, struct sd_request *request)
data = REG_MSC_RES(MSC_CHN(drive));
buf[4] = data & 0xff;
DEBUG("request %d, response [%02x %02x %02x %02x %02x]",
DEBUG("%d request %d, response [%02x %02x %02x %02x %02x]", drive,
request->rtype, buf[0], buf[1], buf[2],
buf[3], buf[4]);
break;
}
case RESPONSE_R2_CID:
case RESPONSE_R2_CSD:
{
case RESPONSE_R2:
for (i = 0; i < 16; i += 2)
{
data = REG_MSC_RES(MSC_CHN(drive));
@ -385,7 +371,6 @@ static void jz_sd_get_response(const int drive, struct sd_request *request)
}
DEBUG("request %d, response []", request->rtype);
break;
}
case RESPONSE_NONE:
DEBUG("No response");
break;
@ -413,7 +398,7 @@ static int jz_sd_receive_data(const int drive, struct sd_request *req)
#if SD_DMA_ENABLE
/* Use DMA if we can */
if ((int)req->buffer & 0x3 == 0)
if ((int)req->buffer & 0x3 == 0 && req->cnt >= 512)
return jz_sd_receive_data_dma(drive, req);
#endif
@ -476,7 +461,7 @@ static int jz_sd_transmit_data(const int drive, struct sd_request *req)
#if SD_DMA_ENABLE
/* Use DMA if we can */
if ((int)req->buffer & 0x3 == 0)
if ((int)req->buffer & 0x3 == 0 && req->cnt >= 512)
return jz_sd_transmit_data_dma(drive, req);
#endif
@ -559,6 +544,9 @@ static int jz_sd_receive_data_dma(const int drive, struct sd_request *req)
/* clear status and disable channel */
REG_DMAC_DCCSR(DMA_SD_RX_CHANNEL(drive)) = 0;
/* flush dcache again */
discard_dcache_range(req->buffer, req->cnt);
return SD_NO_ERROR;
}
@ -726,15 +714,21 @@ 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;
unsigned int cmdat = 0;
int retval;
#if !SD_INTERRUPT
long deadline = current_tick + (HZ * 5);
#endif
bool has_data = (request->buffer != NULL);
/* Indicate we have no result yet */
request->result = SD_NO_RESPONSE;
#if !SD_AUTO_CLOCK
/* Stop clock when programming things */
jz_sd_stop_clock(drive); /* stop SD clock */
#endif
if (request->cmd == SD_CIM_RESET) {
/* On reset, 1-bit bus width */
use_4bit[drive] = 0;
@ -755,13 +749,26 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
#endif
}
/* Generic handling for all requests with data rx/tx */
if (has_data) {
cmdat |= MSC_CMDAT_DATA_EN;
// if (request->nob > 1 && use_sbc[drive])
// cmdat |= MSC_CMDAT_SEND_AS_STOP;
#if SD_DMA_ENABLE
if (request->cnt >= 512)
cmdat |= MSC_CMDAT_DMA_EN;
#endif
}
/* mask all interrupts and clear status */
SD_IRQ_MASK(MSC_CHN(drive));
/* open interrupt */
#if SD_INTERRUPT
/* unmask interrupts we care about */
REG_MSC_IMASK(MSC_CHN(drive)) = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_DATA_TRAN_DONE | MSC_IMASK_PRG_DONE);
#endif
/* Set command type and events */
/* Per-command type handling */
switch (request->cmd)
{
/* SD core extra command */
@ -781,48 +788,11 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
/* 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;
/* fallthrough */
case SD_READ_DAT_UNTIL_STOP:
case SD_READ_SINGLE_BLOCK:
case SD_READ_MULTIPLE_BLOCK:
#if SD_DMA_ENABLE
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_READ | MSC_CMDAT_DMA_EN;
#else
cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ;
#endif
events = SD_EVENT_RX_DATA_DONE;
break;
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
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_READ |
MSC_CMDAT_DMA_EN;
#else
cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ;
#endif
events = SD_EVENT_RX_DATA_DONE;
}
/* These READ data */
break;
case SD_WRITE_DAT_UNTIL_STOP:
@ -830,18 +800,14 @@ 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:
#if SD_DMA_ENABLE
cmdat |=
MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE | MSC_CMDAT_DMA_EN;
#else
cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE;
#endif
events = SD_EVENT_TX_DATA_DONE | SD_EVENT_PROG_DONE;
/* These WRITE data */
cmdat |= MSC_CMDAT_WRITE;
break;
// case SD_LOCK_UNLOCK: // can be a read or write, needs busy too.
case SD_STOP_TRANSMISSION:
events = SD_EVENT_PROG_DONE;
// cmdat |= MSC_CMDAT_STOP_ABORT;
break;
/* ac - no data transfer */
@ -858,11 +824,9 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
cmdat |= MSC_CMDAT_BUSY;
/* FALLTHRU */
case RESPONSE_R1:
case RESPONSE_R7:
cmdat |= MSC_CMDAT_RESPONSE_R1;
break;
case RESPONSE_R2_CID:
case RESPONSE_R2_CSD:
case RESPONSE_R2:
cmdat |= MSC_CMDAT_RESPONSE_R2;
break;
case RESPONSE_R3:
@ -877,6 +841,9 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
case RESPONSE_R6:
cmdat |= MSC_CMDAT_RESPONSE_R6;
break;
case RESPONSE_R7:
cmdat |= MSC_CMDAT_RESPONSE_R7;
break;
default:
break;
}
@ -885,6 +852,12 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
if (use_4bit[drive])
cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
/* Set block length and nob if there is data */
if (has_data) {
REG_MSC_BLKLEN(MSC_CHN(drive)) = request->block_len;
REG_MSC_NOB(MSC_CHN(drive)) = request->nob;
}
/* Set command index */
if (request->cmd == SD_CIM_RESET)
REG_MSC_CMD(MSC_CHN(drive)) = SD_GO_IDLE_STATE;
@ -894,14 +867,10 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
/* Set argument */
REG_MSC_ARG(MSC_CHN(drive)) = request->arg;
/* Set block length and 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;
DEBUG("Send cmd %d cmdat: %x arg: %x resp %d", request->cmd,
DEBUG("%d Send cmd %d cmdat: %x arg: %x resp %d", drive, request->cmd,
cmdat, request->arg, request->rtype);
/* Start SD clock and send command to card */
@ -917,11 +886,13 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
return SD_ERROR_TIMEOUT;
yield();
}
REG_MSC_IREG(MSC_CHN(drive)) = MSC_IREG_END_CMD_RES; /* clear flag */
#endif
/* Check for status */
retval = jz_sd_check_status(drive, request);
#if SD_INTERRUPT
REG_MSC_IREG(MSC_CHN(drive)) = MSC_IREG_END_CMD_RES; /* clear flag */
#endif
if (retval)
return retval;
@ -933,18 +904,11 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
jz_sd_get_response(drive, request);
/* Start data operation */
if (events & (SD_EVENT_RX_DATA_DONE | SD_EVENT_TX_DATA_DONE))
{
if (events & SD_EVENT_RX_DATA_DONE)
{
retval = jz_sd_receive_data(drive, request);
}
if (retval)
return retval;
if (events & SD_EVENT_TX_DATA_DONE)
{
if (has_data) {
if (cmdat & MSC_CMDAT_WRITE) {
retval = jz_sd_transmit_data(drive, request);
} else {
retval = jz_sd_receive_data(drive, request);
}
if (retval)
return retval;
@ -959,8 +923,8 @@ static int jz_sd_exec_cmd(const int drive, struct sd_request *request)
#endif
}
/* Wait for Prog Done event */
if (events & SD_EVENT_PROG_DONE)
/* Wait for Prog Done event if necessary */
if (cmdat & (MSC_CMDAT_BUSY | MSC_CMDAT_WRITE))
{
#if SD_INTERRUPT
semaphore_wait(&sd_wakeup[drive], HZ * 5);
@ -994,7 +958,7 @@ static int jz_sd_chkcard(const int drive)
#if SD_INTERRUPT
void MSC2(void) /* SD_SLOT_1 */
{
logf("MSC2 interrupt");
DEBUG("MSC2 interrupt");
if (REG_MSC_IREG(MSC_CHN(SD_SLOT_1)) & MSC_IREG_END_CMD_RES) {
REG_MSC_IREG(MSC_CHN(SD_SLOT_1)) = MSC_IREG_END_CMD_RES; /* clear flag */
@ -1013,7 +977,7 @@ void MSC2(void) /* SD_SLOT_1 */
/* MSC interrupt handlers */
void MSC1(void) /* SD_SLOT_2 */
{
logf("MSC1 interrupt");
DEBUG("MSC1 interrupt");
if (REG_MSC_IREG(MSC_CHN(SD_SLOT_2)) & MSC_IREG_END_CMD_RES) {
REG_MSC_IREG(MSC_CHN(SD_SLOT_2)) = MSC_IREG_END_CMD_RES; /* clear flag */
semaphore_release(&sd_wakeup[SD_SLOT_2]);
@ -1080,10 +1044,12 @@ static void sd_send_cmd(const int drive, struct sd_request *request, int cmd, un
request->block_len = block_len;
request->buffer = buffer;
request->cnt = nob * block_len;
memset(&request->response, 0xa5, sizeof(request->response));
request->result = SD_NO_RESPONSE;
retval = jz_sd_exec_cmd(drive, request);
if (retval)
request->result = retval;
request->result = retval;
}
static void sd_simple_cmd(const int drive, struct sd_request *request, int cmd, unsigned int arg,
@ -1099,14 +1065,36 @@ static int sd_exec_acmd(const int drive, struct sd_request *request, int cmd, un
sd_simple_cmd(drive, request, SD_APP_CMD, card[drive].rca, RESPONSE_R1);
retval = sd_unpack_r1(request, &r1);
if (retval)
return retval;
if (!retval)
{
sd_simple_cmd(drive, request, cmd, arg, RESPONSE_R1);
retval = sd_unpack_r1(request, &r1);
if (!(r1.status & SD_R1_APP_CMD)) {
logf("ACMD not accepted\n");
return SD_ERROR_ACMD_REJECT;
}
return retval;
sd_simple_cmd(drive, request, cmd, arg, RESPONSE_R1);
return sd_unpack_r1(request, &r1);
}
static int sd_exec_acmd_buf(const int drive, struct sd_request *request, int cmd, unsigned int arg, enum sd_rsp_t rtype, unsigned short nob, unsigned short block_len, unsigned char *buffer)
{
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)
return retval;
if (!(r1.status & SD_R1_APP_CMD)) {
logf("ACMD not accepted\n");
return SD_ERROR_ACMD_REJECT;
}
sd_send_cmd(drive, request, cmd, arg,
nob, block_len, rtype, buffer);
return SD_NO_ERROR;
}
#define SD_INIT_DOING 0
@ -1116,7 +1104,11 @@ 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;
int retval, i, ocr = 0x40300000; /* SDXC, 3.2-3.4v */
#ifdef HAVE_SDUC
ocr |= 0x08000000; /* Add on SDUC */
#endif
switch (request->cmd)
{
@ -1126,36 +1118,37 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
case SD_SEND_IF_COND:
retval = sd_unpack_r1(request, &r1);
sd_simple_cmd(drive, request, SD_APP_CMD, 0, RESPONSE_R1);
break;
// if (retval)
// return SD_INIT_FAILED;
case SD_APP_CMD:
if (sd_unpack_r1(request, &r1))
retval = sd_exec_acmd_buf(drive, request, SD_APP_OP_COND, ocr,
RESPONSE_R3, 0, 0, NULL);
if (retval)
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)
return SD_INIT_FAILED;
DEBUG("sd_init_card_state: read ocr value = 0x%08x", r3.ocr);
DEBUG("%d: read ocr value = 0x%08x", drive, r3.ocr);
card[drive].ocr = r3.ocr;
// XXX for SDUC, check that B27+B30 of OCR are set.
if(!(r3.ocr & SD_CARD_BUSY || ocr == 0))
{
/* Re-issue AP_OP_COND */
sleep(HZ / 100);
sd_simple_cmd(drive, request, SD_APP_CMD, 0, RESPONSE_R1);
retval = sd_exec_acmd_buf(drive, request, SD_APP_OP_COND, ocr,
RESPONSE_R3, 0, 0, NULL);
if (retval)
return SD_INIT_FAILED;
}
else
{
/* Set the data bus width to 4 bits */
use_4bit[drive] = 1;
sd_simple_cmd(drive, request, SD_ALL_SEND_CID, 0, RESPONSE_R2_CID);
sd_simple_cmd(drive, request, SD_ALL_SEND_CID, 0, RESPONSE_R2);
}
break;
case SD_ALL_SEND_CID:
if (request->result)
return SD_INIT_FAILED;
@ -1164,22 +1157,22 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
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]);
logf("%d CID: %08lx%08lx%08lx%08lx", drive, 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;
DEBUG("sd_init_card_state: Get RCA from SD: 0x%04lx Status: %x", card[drive].rca, r1.status);
card[drive].rca = card[drive].rca << 16;
if (retval)
{
DEBUG("sd_init_card_state: unable to SET_RELATIVE_ADDR error=%d",
logf("sd_init_card_state: unable to SET_RELATIVE_ADDR error=%d",
retval);
return SD_INIT_FAILED;
}
sd_simple_cmd(drive, request, SD_SEND_CSD, card[drive].rca, RESPONSE_R2_CSD);
sd_simple_cmd(drive, request, SD_SEND_CSD, card[drive].rca, RESPONSE_R2);
break;
case SD_SEND_CSD:
@ -1191,13 +1184,33 @@ static int sd_init_card_state(const int drive, struct sd_request *request)
sd_parse_csd(&card[drive]);
logf("CSD: %08lx%08lx%08lx%08lx", card[drive].csd[0], card[drive].csd[1], card[drive].csd[2], card[drive].csd[3]);
DEBUG("SD card is ready");
logf("%d CSD: %08lx%08lx%08lx%08lx", drive, card[drive].csd[0], card[drive].csd[1], card[drive].csd[2], card[drive].csd[3]);
#if 0 // XXX SCR is not working yet
retval = sd_exec_acmd_buf(drive, request, SD_SEND_SCR, 0,
RESPONSE_R1,
1, 8, &request->response[5]);
if (!retval)
retval = sd_unpack_r1(request, &r1);
// XXX check retval?
break;
case SD_SEND_SCR:
// if (request->result)
// return SD_INIT_FAILED;
for(i=0; i<2; i++)
card[drive].scr[i] = ((request->buffer[0+i*4]<<24) | (request->buffer[1+i*4]<<16) |
(request->buffer[2+i*4]<< 8) | request->buffer[3+i*4]);
DEBUG("%d SCR: %08lx%08lx", drive, card[drive].scr[0], card[drive].scr[1]);
use_sbc[drive] = card[drive].scr[0] & 2;
#endif
logf("SD card %d is ready", drive);
jz_sd_set_clock(drive, SD_CLOCK_FAST);
return SD_INIT_PASSED;
default:
DEBUG("sd_init_card_state: error! Illegal last cmd %d", request->cmd);
logf("sd_init_card_state: error! Illegal last cmd %d", request->cmd);
return SD_INIT_FAILED;
}
@ -1212,8 +1225,11 @@ static int sd_switch(const int drive, struct sd_request *request, int mode, int
mode = !!mode;
value &= 0xF;
arg = (mode << 31 | 0x00FFFFFF);
arg &= ~(0xF << (group * 4));
arg |= value << (group * 4);
if (mode) {
group--;
arg &= ~(0xF << (group * 4));
arg |= value << (group * 4);
}
sd_send_cmd(drive, request, SD_SWITCH_FUNC, arg, 1, 64, RESPONSE_R1, resp);
return 0;
@ -1242,7 +1258,7 @@ static int sd_switch_hs(const int drive, struct sd_request *request)
{
unsigned int status[64 / 4];
sd_switch(drive, request, 1, 0, 1, (unsigned char*) status);
sd_switch(drive, request, 1, 1, 1, (unsigned char*) status);
return 0;
}
@ -1267,10 +1283,16 @@ static int sd_select_card(const int drive)
jz_sd_set_clock(drive, SD_CLOCK_HIGH);
}
}
num_6[drive] = 3;
retval = sd_exec_acmd(drive, &request, SD_SET_BUS_WIDTH, 2);
if (retval)
return retval;
bool sup_4bit = 1; // XXX check against SCR
if (sup_4bit) {
retval = sd_exec_acmd(drive, &request, SD_SET_BUS_WIDTH, 2);
if (retval)
return retval;
use_4bit[drive] = 2;
DEBUG("Use 4-bit bus width");
}
retval = sd_exec_acmd(drive, &request, SD_SET_CLR_CARD_DETECT, 0);
if (retval)
return retval;
@ -1280,6 +1302,11 @@ static int sd_select_card(const int drive)
return 0;
}
static inline bool card_detect_target(const int drive)
{
return (jz_sd_chkcard(drive) == 1);
}
static int __sd_init_device(const int drive)
{
int retval = 0;
@ -1289,13 +1316,16 @@ static int __sd_init_device(const int drive)
/* Initialise card data as blank */
memset(&card[drive], 0, sizeof(tCardInfo));
num_6[drive] = 0;
use_4bit[drive] = 0;
active[drive] = 0;
/* reset mmc/sd controller */
jz_sd_hardware_init(drive);
/* Don't bother if card isn't present */
if (!card_detect_target(drive))
return 0;
sd_simple_cmd(drive, &init_req, SD_CIM_RESET, 0, RESPONSE_NONE);
sd_simple_cmd(drive, &init_req, SD_GO_IDLE_STATE, 0, RESPONSE_NONE);
@ -1364,11 +1394,6 @@ int sd_init(void)
return 0;
}
static inline bool card_detect_target(const int drive)
{
return (jz_sd_chkcard(drive) == 1);
}
tCardInfo* card_get_info_target(const int drive)
{
return &card[drive];
@ -1423,18 +1448,31 @@ int sd_transfer_sectors(IF_MD(const int drive,) sector_t start, int count, void*
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
// XXX 64-bit
if (use_sbc[drive] && count > 1) {
sd_simple_cmd(drive, &request, SD_SET_BLOCK_COUNT, count, RESPONSE_R1);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
#ifdef STORAGE_64BIT_SECTOR
// XXX check card[drive].ocr, b27+b30 == 11
if (card[drive].numblocks > 0xffffffffULL) {
uint32_t upper = start >> 32;
sd_simple_cmd(drive, &request, SD_UC_ADDRESS_EXTENSION, upper, RESPONSE_R1);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
}
#endif
sd_send_cmd(drive, &request,
(count > 1) ?
(write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK) :
(write ? SD_WRITE_BLOCK : SD_READ_SINGLE_BLOCK),
card[drive].sd2plus ? start : (start * SD_BLOCK_SIZE),
count, SD_BLOCK_SIZE, RESPONSE_R1, buf);
if ((retval = sd_unpack_r1(&request, &r1)))
goto err;
retval = sd_unpack_r1(&request, &r1);
if (count > 1)
{
if (retval || (!use_sbc[drive] && 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)