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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxx>
---

 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
-



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux