linux-mips
[Top] [All Lists]

[PATCH] ALCHEMY: Add SD support to AU1200 MMC/SD driver

To: linux-mips@linux-mips.org
Subject: [PATCH] ALCHEMY: Add SD support to AU1200 MMC/SD driver
From: "Jordan Crouse" <jordan.crouse@amd.com>
Date: Fri, 2 Dec 2005 12:01:08 -0700
Cc: ralf@linux-mips.org, drzeus-wbsd@drzeus.cx
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
User-agent: Mutt/1.5.11
Add SD support to the AU1200 MMC driver.  This can
be added post 2.6.15, I'm just sending them out today so the various
maintainers can get them queued up. 

Signed-off-by: Jordan Crouse <jordan.crouse@amd.com>
---

 drivers/mmc/au1xmmc.c |  124 ++++++++++++++++++++++++++++---------------------
 1 files changed, 71 insertions(+), 53 deletions(-)

diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index cb32a08..c8c8f29 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -99,16 +99,24 @@ static inline void IRQ_ON(struct au1xmmc
        au_sync();
 }
 
-static inline void FLUSH_FIFO(struct au1xmmc_host *host) 
+/* Turn on the FIFO flush - the fifo will be returned to active right
+ * before data transfer
+ */
+
+static inline void FLUSH_FIFO_ON(struct au1xmmc_host *host)
 {
        u32 val = au_readl(HOST_CONFIG2(host));
+       val |= SD_CONFIG2_FF;
+       au_writel(val, HOST_CONFIG2(host));
+       au_sync();
+}
 
-       au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
-       au_sync_delay(1);
-       
-       /* SEND_STOP will turn off clock control - this re-enables it */
-       val &= ~SD_CONFIG2_DF;
+static inline void FIFO_ACTIVE(struct au1xmmc_host *host)
+{
+       u32 val = au_readl(HOST_CONFIG2(host));
 
+       /* SEND_STOP will turn off clock control - this re-enables it */
+       val &= ~(SD_CONFIG2_DF | SD_CONFIG2_FF);
        au_writel(val, HOST_CONFIG2(host));
        au_sync();
 }
@@ -124,8 +132,8 @@ static inline void IRQ_OFF(struct au1xmm
 static inline void SEND_STOP(struct au1xmmc_host *host) 
 {
 
-       /* We know the value of CONFIG2, so avoid a read we don't need */
-       u32 mask = SD_CONFIG2_EN;
+       /* Penalty box for Jordan - NEVER ASSUME! */
+       u32 mask = au_readl(HOST_CONFIG2(host));
 
        WARN_ON(host->status != HOST_S_DATA);
        host->status = HOST_S_STOP;
@@ -169,7 +177,7 @@ static void au1xmmc_finish_request(struc
        host->flags &= HOST_F_ACTIVE; 
 
        host->dma.len = 0;
-       host->dma.dir = 0;
+       host->dma.dir = DMA_BIDIRECTIONAL;
 
        host->pio.index  = 0;
        host->pio.offset = 0;
@@ -179,6 +187,9 @@ static void au1xmmc_finish_request(struc
 
        bcsr->disk_leds |= (1 << 8);
 
+       /* Flush the FIFO until our next request */
+       FLUSH_FIFO_ON(host);
+
        mmc_request_done(host->mmc, mrq);
 }
 
@@ -196,7 +207,11 @@ static int au1xmmc_send_command(struct a
 
        switch(cmd->flags) {
        case MMC_RSP_R1:
-               mmccmd |= SD_CMD_RT_1;
+               if (cmd->opcode == 0x03 && host->mmc->mode == MMC_MODE_SD)
+                       mmccmd |= SD_CMD_RT_6;
+               else
+                       mmccmd |= SD_CMD_RT_1;
+
                break;
        case MMC_RSP_R1B:
                mmccmd |= SD_CMD_RT_1B;
@@ -504,8 +519,8 @@ static void au1xmmc_cmd_complete(struct 
                r[3] = au_readl(host->iobase + SD_RESP0);
                
                /* The CRC is omitted from the response, so really we only got
-                * 120 bytes, but the engine expects 128 bits, so we have to 
shift
-                * things up 
+                * 120 bytes, but the engine expects 128 bits, so we have to 
+                * shift things up 
                 */
                
                for(i = 0; i < 4; i++) {
@@ -576,9 +591,8 @@ au1xmmc_prepare_data(struct au1xmmc_host
 {
 
        int datalen = data->blocks * (1 << data->blksz_bits);
-
-       if (dma != 0) 
-               host->flags |= HOST_F_DMA;
+       int i = 0;
+       u32 channel;
 
        if (data->flags & MMC_DATA_READ)
                host->flags |= HOST_F_RECV;
@@ -588,8 +602,6 @@ au1xmmc_prepare_data(struct au1xmmc_host
        if (host->mrq->stop) 
                host->flags |= HOST_F_STOP;
                
-       host->dma.dir = DMA_BIDIRECTIONAL;
-
        host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
                                   data->sg_len, host->dma.dir);
 
@@ -598,9 +610,21 @@ au1xmmc_prepare_data(struct au1xmmc_host
 
        au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host));     
 
-       if (host->flags & HOST_F_DMA) {
-               int i;
-               u32 channel = DMA_CHANNEL(host);
+       if (dma == 0) {
+               host->pio.index = 0;
+               host->pio.offset = 0;
+               host->pio.len = datalen;
+               
+               if (host->flags & HOST_F_XMIT)
+                       IRQ_ON(host, SD_CONFIG_TH);
+               else 
+                       IRQ_ON(host, SD_CONFIG_NE);
+
+               return MMC_ERR_NONE;
+       }
+
+       host->flags |= HOST_F_DMA;
+       channel = DMA_CHANNEL(host);
 
                au1xxx_dbdma_stop(channel);
 
@@ -611,7 +635,7 @@ au1xmmc_prepare_data(struct au1xmmc_host
                        
                        int len = (datalen > sg_len) ? sg_len : datalen;
 
-                       if (i == host->dma.len - 1)
+               if (i == (host->dma.len - 1))
                                flags = DDMA_FLAGS_IE;
 
                        if (host->flags & HOST_F_XMIT){
@@ -627,23 +651,11 @@ au1xmmc_prepare_data(struct au1xmmc_host
                                        len, flags);
                        }
 
-                       if (!ret) 
+               if (ret == 0) 
                                goto dataerr;
 
                        datalen -= len;
                }
-       }
-       else {
-               host->pio.index = 0;
-               host->pio.offset = 0;
-               host->pio.len = datalen;
-               
-               if (host->flags & HOST_F_XMIT)
-                       IRQ_ON(host, SD_CONFIG_TH);
-               else 
-                       IRQ_ON(host, SD_CONFIG_NE);
-                       //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
-       }
 
        return MMC_ERR_NONE;
 
@@ -671,7 +683,7 @@ static void au1xmmc_request(struct mmc_h
        bcsr->disk_leds &= ~(1 << 8);
 
        if (mrq->data) {
-               FLUSH_FIFO(host);
+               FIFO_ACTIVE(host);
                ret = au1xmmc_prepare_data(host, mrq->data);
        }
 
@@ -734,6 +746,20 @@ static void au1xmmc_set_ios(struct mmc_h
                au1xmmc_set_clock(host, ios->clock);
                host->clock = ios->clock;
        }
+
+       /* Set the bus width for SD */
+
+       if (ios->bus_width != host->bus_width) {
+               u32 val;
+               val = au_readl(HOST_CONFIG2(host));
+               val &= ~(SD_CONFIG2_WB);
+               val |= (ios->bus_width == MMC_BUS_WIDTH_4) ? SD_CONFIG2_WB : 0;
+
+               au_writel(val, HOST_CONFIG2(host));
+               au_sync();
+
+               host->bus_width = ios->bus_width;
+       }
 }
 
 static void au1xmmc_dma_callback(int irq, void *dev_id, struct pt_regs *regs) 
@@ -778,24 +804,8 @@ static irqreturn_t au1xmmc_irq(int irq, 
                
                        /* In PIO mode, interrupts might still be enabled */
                        IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
-
-                       //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
                        tasklet_schedule(&host->finish_task);
                }
-#if 0
-               else if (status & SD_STATUS_DD) {
-
-                       /* Sometimes we get a DD before a NE in PIO mode */
-
-                       if (!(host->flags & HOST_F_DMA) && 
-                                       (status & SD_STATUS_NE))
-                               au1xmmc_receive_pio(host);
-                       else {
-                               au1xmmc_data_complete(host, status);
-                               //tasklet_schedule(&host->data_task);
-                       }
-               }
-#endif
                else if (status & (SD_STATUS_CR)) {
                        if (host->status == HOST_S_CMD)
                                au1xmmc_cmd_complete(host,status);
@@ -875,9 +885,15 @@ static void au1xmmc_init_dma(struct au1x
        host->rx_chan = rxchan;
 }
 
+static int au1xmmc_get_ro(struct mmc_host *mmc) {
+       struct au1xmmc_host *host = mmc_priv(mmc);
+       return au1xmmc_card_readonly(host);
+}
+
 struct mmc_host_ops au1xmmc_ops = {
        .request        = au1xmmc_request,
        .set_ios        = au1xmmc_set_ios,
+       .get_ro         = au1xmmc_get_ro, 
 };
 
 static int au1xmmc_probe(struct device *dev) 
@@ -914,6 +930,7 @@ static int au1xmmc_probe(struct device *
                mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
                mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; 
 
+               mmc->caps = MMC_CAP_4_BIT_DATA;
                mmc->ocr_avail = AU1XMMC_OCR;
 
                host = mmc_priv(mmc);
@@ -923,7 +940,9 @@ static int au1xmmc_probe(struct device *
                host->iobase = au1xmmc_card_table[host->id].iobase;
                host->clock = 0;
                host->power_mode = MMC_POWER_OFF;
-               
+
+               host->bus_width = MMC_BUS_WIDTH_1;
+
                host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
                host->status = HOST_S_IDLE;
 
@@ -1017,4 +1036,3 @@ MODULE_AUTHOR("Advanced Micro Devices, I
 MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
 MODULE_LICENSE("GPL");
 #endif
-


<Prev in Thread] Current Thread [Next in Thread>