as3525v2: Use CD Interrupt vs. CD polling in send_cmd()
Also enable write support, test_disk passes on all targets Flyspray: FS#11140 Authors: Jack Halpin and myself git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25799 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1bc59454d5
commit
7480afb3c5
1 changed files with 34 additions and 29 deletions
|
@ -338,7 +338,9 @@ bool sd_enabled = false;
|
|||
#endif
|
||||
|
||||
static struct wakeup transfer_completion_signal;
|
||||
static struct wakeup command_completion_signal;
|
||||
static volatile bool retry;
|
||||
static volatile int cmd_error;
|
||||
|
||||
#if defined(HAVE_MULTIDRIVE)
|
||||
int active_card = 0;
|
||||
|
@ -350,7 +352,8 @@ static inline void mci_delay(void) { udelay(1000); }
|
|||
void INT_NAND(void)
|
||||
{
|
||||
MCI_CTRL &= ~INT_ENABLE;
|
||||
const int status = MCI_MASK_STATUS;
|
||||
/* use raw status here as we need to check some Ints that are masked */
|
||||
const int status = MCI_RAW_STATUS;
|
||||
|
||||
MCI_RAW_STATUS = status; /* clear status */
|
||||
|
||||
|
@ -360,6 +363,11 @@ void INT_NAND(void)
|
|||
if( status & (MCI_INT_DTO|MCI_DATA_ERROR))
|
||||
wakeup_signal(&transfer_completion_signal);
|
||||
|
||||
cmd_error = status & MCI_CMD_ERROR;
|
||||
|
||||
if(status & MCI_INT_CD)
|
||||
wakeup_signal(&command_completion_signal);
|
||||
|
||||
MCI_CTRL |= INT_ENABLE;
|
||||
}
|
||||
|
||||
|
@ -394,6 +402,12 @@ static bool send_cmd(const int drive, const int cmd, const int arg, const int fl
|
|||
#define TRANSFER_CMD (cmd == SD_READ_MULTIPLE_BLOCK || \
|
||||
cmd == SD_WRITE_MULTIPLE_BLOCK)
|
||||
|
||||
/* RCRC & RTO interrupts should be set together with the CD interrupt but
|
||||
* in practice sometimes incorrectly precede the CD interrupt. If we leave
|
||||
* them masked for now we can check them in the isr by reading raw status when
|
||||
* the CD int is triggered.
|
||||
*/
|
||||
MCI_MASK |= MCI_INT_CD;
|
||||
MCI_ARGUMENT = arg;
|
||||
|
||||
/* Construct MCI_COMMAND */
|
||||
|
@ -415,19 +429,17 @@ static bool send_cmd(const int drive, const int cmd, const int arg, const int fl
|
|||
/*b23 | CMD_CCS_EXPECTED unused */
|
||||
/*b31 */ | CMD_DONE_BIT;
|
||||
|
||||
int max = 0x40000;
|
||||
while(MCI_COMMAND & CMD_DONE_BIT)
|
||||
{
|
||||
if(--max == 0) /* timeout */
|
||||
return false;
|
||||
}
|
||||
wakeup_wait(&command_completion_signal, TIMEOUT_BLOCK);
|
||||
|
||||
MCI_MASK &= ~MCI_INT_CD;
|
||||
|
||||
/* Handle command responses */
|
||||
|
||||
/* TODO Check crc values to determine if the response was valid */
|
||||
if(flags & MCI_RESP)
|
||||
{
|
||||
int i = 0xff; while(i--) ;
|
||||
/* if we read the response too fast we might read the response
|
||||
* of the previous command instead */
|
||||
if(cmd_error & MCI_INT_RCRC) /* skipping timeout for now */
|
||||
return false;
|
||||
|
||||
if(flags & MCI_LONG_RESP)
|
||||
{
|
||||
|
@ -498,6 +510,9 @@ static int sd_init_card(const int drive)
|
|||
#endif
|
||||
/* End of Card Identification Mode ************************************/
|
||||
|
||||
/* Card back to full speed */
|
||||
MCI_CLKDIV &= ~(0xFF); /* CLK_DIV_0 : bits 7:0 = 0x00 */
|
||||
|
||||
/* Attempt to switch cards to HS timings, non HS cards just ignore this */
|
||||
/* CMD7 w/rca: Select card to put it in TRAN state */
|
||||
if(!send_cmd(drive, SD_SELECT_CARD, card_info[drive].rca, MCI_RESP, &response))
|
||||
|
@ -509,7 +524,6 @@ static int sd_init_card(const int drive)
|
|||
/* CMD6 */
|
||||
if(!send_cmd(drive, SD_SWITCH_FUNC, 0x80fffff1, MCI_NO_RESP, NULL))
|
||||
return -9;
|
||||
mci_delay();
|
||||
|
||||
/* We need to go back to STBY state now so we can read csd */
|
||||
/* CMD7 w/rca=0: Deselect card to put it in STBY state */
|
||||
|
@ -523,8 +537,6 @@ static int sd_init_card(const int drive)
|
|||
|
||||
sd_parse_csd(&card_info[drive]);
|
||||
|
||||
/* Card back to full speed */
|
||||
MCI_CLKDIV &= ~(0xFF); /* CLK_DIV_0 : bits 7:0 = 0x00 */
|
||||
|
||||
#ifndef HAVE_MULTIDRIVE
|
||||
/* CMD7 w/rca: Select card to put it in TRAN state */
|
||||
|
@ -686,7 +698,7 @@ int sd_init(void)
|
|||
| 1; /* clock source = PLLA */
|
||||
|
||||
wakeup_init(&transfer_completion_signal);
|
||||
|
||||
wakeup_init(&command_completion_signal);
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
/* clear previous irq */
|
||||
GPIOA_IC = EXT_SD_BITS;
|
||||
|
@ -729,9 +741,7 @@ static int sd_wait_for_state(const int drive, unsigned int state)
|
|||
{
|
||||
long tick;
|
||||
|
||||
if(!send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca,
|
||||
MCI_RESP, &response))
|
||||
return -1;
|
||||
while(!(send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca, MCI_RESP, &response)));
|
||||
|
||||
if (((response >> 9) & 0xf) == state)
|
||||
return 0;
|
||||
|
@ -818,15 +828,11 @@ static int sd_transfer_sectors(IF_MD2(int drive,) unsigned long start,
|
|||
}
|
||||
|
||||
MCI_MASK |= (MCI_DATA_ERROR | MCI_INT_DTO);
|
||||
MCI_CTRL |= DMA_ENABLE;
|
||||
|
||||
int arg = start;
|
||||
if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */
|
||||
arg *= SD_BLOCK_SIZE;
|
||||
|
||||
if(!send_cmd(drive, cmd, arg, MCI_NO_RESP, NULL))
|
||||
panicf("%s multiple blocks failed", write ? "write" : "read");
|
||||
|
||||
if(write)
|
||||
dma_enable_channel(0, dma_buf, MCI_FIFO, DMA_PERI_SD,
|
||||
DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL);
|
||||
|
@ -834,6 +840,12 @@ static int sd_transfer_sectors(IF_MD2(int drive,) unsigned long start,
|
|||
dma_enable_channel(0, MCI_FIFO, dma_buf, DMA_PERI_SD,
|
||||
DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL);
|
||||
|
||||
MCI_CTRL |= DMA_ENABLE;
|
||||
|
||||
unsigned long dummy; /* if we don't ask for a response, writing fails */
|
||||
if(!send_cmd(drive, cmd, arg, MCI_RESP, &dummy))
|
||||
panicf("%s multiple blocks failed", write ? "write" : "read");
|
||||
|
||||
wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK);
|
||||
|
||||
MCI_MASK &= ~(MCI_DATA_ERROR | MCI_INT_DTO);
|
||||
|
@ -904,14 +916,7 @@ int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
|
|||
(void) buf;
|
||||
return -1;
|
||||
#else
|
||||
//return sd_transfer_sectors(IF_MD2(drive,) start, count, (void*)buf, true);
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
(void)drive;
|
||||
#endif
|
||||
(void)start;
|
||||
(void)count;
|
||||
(void)buf;
|
||||
return -1; /* not working, seems to cause FIFO overruns */
|
||||
return sd_transfer_sectors(IF_MD2(drive,) start, count, (void*)buf, true);
|
||||
#endif /* defined(BOOTLOADER) */
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue