Linux MIPS Architecture development
 help / color / mirror / Atom feed
* [PATCH] ALCHEMY:  Add SD support to AU1200 MMC/SD driver
@ 2005-12-02 19:01 Jordan Crouse
  2005-12-02 19:42 ` Pierre Ossman
  2005-12-14 13:41 ` [PATCH] " Rodolfo Giometti
  0 siblings, 2 replies; 9+ messages in thread
From: Jordan Crouse @ 2005-12-02 19:01 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf, drzeus-wbsd

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
-

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-01-09 18:09 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-12-02 19:01 [PATCH] ALCHEMY: Add SD support to AU1200 MMC/SD driver Jordan Crouse
2005-12-02 19:42 ` Pierre Ossman
2005-12-02 19:45   ` Russell King
2005-12-02 21:17   ` Jordan Crouse
2005-12-02 22:05     ` Pierre Ossman
2005-12-14 13:41 ` [PATCH] " Rodolfo Giometti
2005-12-14 15:53   ` Jordan Crouse
2006-01-09 17:45     ` Rodolfo Giometti
2006-01-09 18:19       ` Jordan Crouse

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox