@ -163,7 +163,6 @@ struct bcm2835_host {
int clock ; /* Current clock speed */
unsigned int max_clk ; /* Max possible freq */
unsigned int blocks ; /* remaining PIO blocks */
int irq ; /* Device IRQ */
u32 ns_per_fifo_word ;
@ -173,14 +172,7 @@ struct bcm2835_host {
struct mmc_cmd * cmd ; /* Current command */
struct mmc_data * data ; /* Current data request */
bool data_complete : 1 ; /* Data finished before cmd */
bool use_busy : 1 ; /* Wait for busy interrupt */
bool wait_data_complete : 1 ; /* Wait for data */
/* for threaded irq handler */
bool irq_block ;
bool irq_busy ;
bool irq_data ;
struct udevice * dev ;
struct mmc * mmc ;
@ -240,17 +232,9 @@ static void bcm2835_reset_internal(struct bcm2835_host *host)
writel ( host - > cdiv , host - > ioaddr + SDCDIV ) ;
}
static int bcm2835_finish_command ( struct bcm2835_host * host ) ;
static void bcm2835_wait_transfer_complete ( struct bcm2835_host * host )
static int bcm2835_wait_transfer_complete ( struct bcm2835_host * host )
{
int timediff ;
u32 alternate_idle ;
alternate_idle = ( host - > data - > flags & MMC_DATA_READ ) ?
SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1 ;
timediff = 0 ;
int timediff = 0 ;
while ( 1 ) {
u32 edm , fsm ;
@ -261,7 +245,10 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host)
if ( ( fsm = = SDEDM_FSM_IDENTMODE ) | |
( fsm = = SDEDM_FSM_DATAMODE ) )
break ;
if ( fsm = = alternate_idle ) {
if ( ( fsm = = SDEDM_FSM_READWAIT ) | |
( fsm = = SDEDM_FSM_WRITESTART1 ) | |
( fsm = = SDEDM_FSM_READDATA ) ) {
writel ( edm | SDEDM_FORCE_DATA_MODE ,
host - > ioaddr + SDEDM ) ;
break ;
@ -273,9 +260,11 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host)
" wait_transfer_complete - still waiting after %d retries \n " ,
timediff ) ;
bcm2835_dumpregs ( host ) ;
return ;
return - ETIMEDOUT ;
}
}
return 0 ;
}
static int bcm2835_transfer_block_pio ( struct bcm2835_host * host , bool is_read )
@ -322,6 +311,9 @@ static int bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
fsm_state ! = SDEDM_FSM_READCRC ) ) | |
( ! is_read & &
( fsm_state ! = SDEDM_FSM_WRITEDATA & &
fsm_state ! = SDEDM_FSM_WRITEWAIT1 & &
fsm_state ! = SDEDM_FSM_WRITEWAIT2 & &
fsm_state ! = SDEDM_FSM_WRITECRC & &
fsm_state ! = SDEDM_FSM_WRITESTART1 & &
fsm_state ! = SDEDM_FSM_WRITESTART2 ) ) ) {
hsts = readl ( host - > ioaddr + SDHSTS ) ;
@ -358,9 +350,8 @@ static int bcm2835_transfer_pio(struct bcm2835_host *host)
is_read = ( host - > data - > flags & MMC_DATA_READ ) ! = 0 ;
ret = bcm2835_transfer_block_pio ( host , is_read ) ;
if ( host - > wait_data_complete )
bcm2835_wait_transfer_complete ( host ) ;
if ( ret )
return ret ;
sdhsts = readl ( host - > ioaddr + SDHSTS ) ;
if ( sdhsts & ( SDHSTS_CRC16_ERROR |
@ -379,20 +370,7 @@ static int bcm2835_transfer_pio(struct bcm2835_host *host)
return ret ;
}
static void bcm2835_set_transfer_irqs ( struct bcm2835_host * host )
{
u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN |
SDHCFG_BUSY_IRPT_EN ;
host - > hcfg = ( host - > hcfg & ~ all_irqs ) |
SDHCFG_DATA_IRPT_EN |
SDHCFG_BUSY_IRPT_EN ;
writel ( host - > hcfg , host - > ioaddr + SDHCFG ) ;
}
static
void bcm2835_prepare_data ( struct bcm2835_host * host , struct mmc_cmd * cmd ,
static void bcm2835_prepare_data ( struct bcm2835_host * host , struct mmc_cmd * cmd ,
struct mmc_data * data )
{
WARN_ON ( host - > data ) ;
@ -401,14 +379,9 @@ void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd,
if ( ! data )
return ;
host - > wait_data_complete = cmd - > cmdidx ! = MMC_CMD_READ_MULTIPLE_BLOCK ;
host - > data_complete = false ;
/* Use PIO */
host - > blocks = data - > blocks ;
bcm2835_set_transfer_irqs ( host ) ;
writel ( data - > blocksize , host - > ioaddr + SDHBCT ) ;
writel ( data - > blocks , host - > ioaddr + SDHBLC ) ;
}
@ -483,36 +456,6 @@ static int bcm2835_send_command(struct bcm2835_host *host, struct mmc_cmd *cmd,
return 0 ;
}
static int bcm2835_transfer_complete ( struct bcm2835_host * host )
{
int ret = 0 ;
WARN_ON ( ! host - > data_complete ) ;
host - > data = NULL ;
return ret ;
}
static void bcm2835_finish_data ( struct bcm2835_host * host )
{
host - > hcfg & = ~ ( SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN ) ;
writel ( host - > hcfg , host - > ioaddr + SDHCFG ) ;
host - > data_complete = true ;
if ( host - > cmd ) {
/* Data managed to finish before the
* command completed . Make sure we do
* things in the proper order .
*/
dev_dbg ( dev , " Finished early - HSTS %08x \n " ,
readl ( host - > ioaddr + SDHSTS ) ) ;
} else {
bcm2835_transfer_complete ( host ) ;
}
}
static int bcm2835_finish_command ( struct bcm2835_host * host )
{
struct mmc_cmd * cmd = host - > cmd ;
@ -562,8 +505,6 @@ static int bcm2835_finish_command(struct bcm2835_host *host)
/* Processed actual command. */
host - > cmd = NULL ;
if ( host - > data & & host - > data_complete )
ret = bcm2835_transfer_complete ( host ) ;
return ret ;
}
@ -608,159 +549,44 @@ static int bcm2835_check_data_error(struct bcm2835_host *host, u32 intmask)
return ret ;
}
static void bcm2835_busy_irq ( struct bcm2835_host * host )
{
if ( WARN_ON ( ! host - > cmd ) ) {
bcm2835_dumpregs ( host ) ;
return ;
}
if ( WARN_ON ( ! host - > use_busy ) ) {
bcm2835_dumpregs ( host ) ;
return ;
}
host - > use_busy = false ;
bcm2835_finish_command ( host ) ;
}
static void bcm2835_data_irq ( struct bcm2835_host * host , u32 intmask )
static int bcm2835_transmit ( struct bcm2835_host * host )
{
u32 intmask = readl ( host - > ioaddr + SDHSTS ) ;
int ret ;
/*
* There are no dedicated data / space available interrupt
* status bits , so it is necessary to use the single shared
* data / space available FIFO status bits . It is therefore not
* an error to get here when there is no data transfer in
* progress .
*/
if ( ! host - > data )
return ;
/* Check for errors */
ret = bcm2835_check_data_error ( host , intmask ) ;
if ( ret )
goto finished ;
if ( host - > data - > flags & MMC_DATA_WRITE ) {
/* Use the block interrupt for writes after the first block */
host - > hcfg & = ~ ( SDHCFG_DATA_IRPT_EN ) ;
host - > hcfg | = SDHCFG_BLOCK_IRPT_EN ;
writel ( host - > hcfg , host - > ioaddr + SDHCFG ) ;
bcm2835_transfer_pio ( host ) ;
} else {
bcm2835_transfer_pio ( host ) ;
host - > blocks - - ;
if ( ( host - > blocks = = 0 ) )
goto finished ;
}
return ;
finished :
host - > hcfg & = ~ ( SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN ) ;
writel ( host - > hcfg , host - > ioaddr + SDHCFG ) ;
}
static void bcm2835_data_threaded_irq ( struct bcm2835_host * host )
{
if ( ! host - > data )
return ;
if ( ( host - > blocks = = 0 ) )
bcm2835_finish_data ( host ) ;
}
static void bcm2835_block_irq ( struct bcm2835_host * host )
{
if ( WARN_ON ( ! host - > data ) ) {
bcm2835_dumpregs ( host ) ;
return ;
}
WARN_ON ( ! host - > blocks ) ;
if ( ( - - host - > blocks = = 0 ) )
bcm2835_finish_data ( host ) ;
else
bcm2835_transfer_pio ( host ) ;
}
static irqreturn_t bcm2835_irq ( int irq , void * dev_id )
{
irqreturn_t result = IRQ_NONE ;
struct bcm2835_host * host = dev_id ;
u32 intmask ;
intmask = readl ( host - > ioaddr + SDHSTS ) ;
writel ( SDHSTS_BUSY_IRPT |
SDHSTS_BLOCK_IRPT |
SDHSTS_SDIO_IRPT |
SDHSTS_DATA_FLAG ,
host - > ioaddr + SDHSTS ) ;
if ( intmask & SDHSTS_BLOCK_IRPT ) {
bcm2835_check_data_error ( host , intmask ) ;
host - > irq_block = true ;
result = IRQ_WAKE_THREAD ;
}
if ( intmask & SDHSTS_BUSY_IRPT ) {
if ( ! bcm2835_check_cmd_error ( host , intmask ) ) {
host - > irq_busy = true ;
result = IRQ_WAKE_THREAD ;
} else {
result = IRQ_HANDLED ;
}
}
/* There is no true data interrupt status bit, so it is
* necessary to qualify the data flag with the interrupt
* enable bit .
*/
if ( ( intmask & SDHSTS_DATA_FLAG ) & &
( host - > hcfg & SDHCFG_DATA_IRPT_EN ) ) {
bcm2835_data_irq ( host , intmask ) ;
host - > irq_data = true ;
result = IRQ_WAKE_THREAD ;
}
return result ;
}
static irqreturn_t bcm2835_threaded_irq ( int irq , void * dev_id )
{
struct bcm2835_host * host = dev_id ;
return ret ;
if ( host - > irq_block ) {
host - > irq_block = false ;
bcm2835_block_irq ( host ) ;
}
ret = bcm2835_check_cmd_error ( host , intmask ) ;
if ( ret )
return ret ;
if ( host - > irq_busy ) {
host - > irq_busy = false ;
bcm2835_busy_irq ( host ) ;
/* Handle wait for busy end */
if ( host - > use_busy & & ( intmask & SDHSTS_BUSY_IRPT ) ) {
writel ( SDHSTS_BUSY_IRPT , host - > ioaddr + SDHSTS ) ;
host - > use_busy = false ;
bcm2835_finish_command ( host ) ;
}
if ( host - > irq_data ) {
host - > irq_data = false ;
bcm2835_data_threaded_irq ( host ) ;
/* Handle PIO data transfer */
if ( host - > data ) {
ret = bcm2835_transfer_pio ( host ) ;
if ( ret )
return ret ;
host - > blocks - - ;
if ( host - > blocks = = 0 ) {
/* Wait for command to complete for real */
ret = bcm2835_wait_transfer_complete ( host ) ;
if ( ret )
return ret ;
/* Transfer complete */
host - > data = NULL ;
}
return IRQ_HANDLED ;
}
static void bcm2835_irq_poll ( struct bcm2835_host * host )
{
u32 intmask ;
while ( 1 ) {
intmask = readl ( host - > ioaddr + SDHSTS ) ;
if ( intmask & ( SDHSTS_BUSY_IRPT | SDHSTS_BLOCK_IRPT |
SDHSTS_SDIO_IRPT | SDHSTS_DATA_FLAG ) ) {
bcm2835_irq ( 0 , host ) ;
bcm2835_threaded_irq ( 0 , host ) ;
return ;
}
}
return 0 ;
}
static void bcm2835_set_clock ( struct bcm2835_host * host , unsigned int clock )
@ -864,8 +690,11 @@ static int bcm2835_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
}
/* Wait for completion of busy signal or data transfer */
while ( host - > use_busy | | host - > data )
bcm2835_irq_poll ( host ) ;
while ( host - > use_busy | | host - > data ) {
ret = bcm2835_transmit ( host ) ;
if ( ret )
break ;
}
return ret ;
}