[U-Boot-Users] drivers MMCplus for at91sam9x

Ken.Fuchs at bench.com Ken.Fuchs at bench.com
Tue Apr 29 21:45:34 CEST 2008


I posted the following patch under a different subject line:
Re: [U-Boot-Users] [PATCH] Add eSDHC driver

> > --- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) ---

Pierre Savary wrote:

> Thanks for that... but it's my own patch ;)
> 
> Pierre

===========================================================

Pierre, I hope you like this patch better. :)

The following MMC v4 patch is for u-boot-1.1.5_atmel_1.2.
To the AT91SAM9261 MCI device driver it adds support for
MMC v4.x chips (MoviNAND in particular).
  
The u-boot_at91sam9260_mmc.patch, previously send to this
thread 23 April 2008 must be applied to
u-boot-1.1.5_atmel_1.2, prior to applying the patch below.

The patch includes lines "/* Ignore */".  These are
simply place holders for code that was not relevant
to the MCI driver or MMC code. 

The patch is actually of four individual source files.
Please let me know of any serious problems applying the
patch.  It should apply cleanly, but I didn't verify this.

The MCI MMC v4 features contained in this patch work perfectly
on our AT91SAM9261 board, except that I never got MMC 4 bit
bus working (that code is omitted from this patch).  Anyone
know why the AT91SAM9261-EK doesn't appear to support 4 bit MMC?

This patch may not work on AT91SAM9261-EK, since we modified
the AT91SAM9261-EK board definitions rather than creating a
new configuration and files for our board.

Sincerely,

Ken Fuchs

u-boot-at91sam9261-mmc-v4.patch
===============================

svn diff -r21 cpu/arm926ejs/at91sam926x/atmel_mci.c
Index: cpu/arm926ejs/at91sam926x/atmel_mci.c
===================================================================
--- cpu/arm926ejs/at91sam926x/atmel_mci.c	(revision 21)
+++ cpu/arm926ejs/at91sam926x/atmel_mci.c	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
  * Copyright (C) 2004-2006 Atmel Corporation
  *
  * See file CREDITS for list of people who contributed to this
@@ -34,21 +38,43 @@
 #include <asm/arch/hardware.h>	//klk
 
 #include "atmel_mci.h"
-#undef DEBUG
+
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
 #ifdef DEBUG
 #define pr_debug(fmt, args...) printf(fmt, ##args)
 #else
 #define pr_debug(...) do { } while(0)
 #endif
 
+#undef  CFG_MMC_CLK_OD
+#define CFG_MMC_CLK_OD		375000
+
 #ifndef CFG_MMC_CLK_OD
 #define CFG_MMC_CLK_OD		375000
 #endif
 
+#undef  CFG_MMC_CLK_PP
+#define CFG_MMC_CLK_PP		20000000
+
 #ifndef CFG_MMC_CLK_PP
 #define CFG_MMC_CLK_PP		20000000
 #endif
 
+#undef  CFG_MMC_OP_COND
+#define CFG_MMC_OP_COND		0x80ff8000
+/*                              0x80ff8080 works with 30+ sec. power
off req */
+/*                              0x00800000 works better, but write
forever?  */
+/*                              0x00100000 works with 30+ sec. power
off req */
+
 #ifndef CFG_MMC_OP_COND
 #define CFG_MMC_OP_COND		0x00100000
 #endif
@@ -74,8 +100,13 @@
 	bus_hz = AT91C_MASTER_CLOCK;
 	clkdiv = (bus_hz / hz) / 2 - 1;
 
+#if     1
+	printf("mmc: setting clock %lu Hz, block size %lu\n",
+		 hz, blklen);
+#else   /* 1 */
 	pr_debug("mmc: setting clock %lu Hz, block size %lu\n",
 		 hz, blklen);
+#endif  /* 1 */
 
 	if (clkdiv & ~255UL) {
 		clkdiv = 255;
@@ -84,10 +115,17 @@
 	}
 
 	blklen &= 0xfffc;
+
+#if     1   /* AT91SAM9261 does not have RDPROOF and WRPROOF fields. */
 	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
+			 | MMCI_BF(BLKLEN, blklen)));
+#else   /* 1 */
+	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
 			 | MMCI_BF(BLKLEN, blklen)
 			 | MMCI_BIT(RDPROOF)
 			 | MMCI_BIT(WRPROOF)));
+#endif  /* 1 */
+
 }
 
 #define RESP_NO_CRC	1
@@ -99,6 +137,7 @@
 #define NCR		MMCI_BF(MAXLAT, 1)
 #define TRCMD_START	MMCI_BF(TRCMD, 1)
 #define TRDIR_READ	MMCI_BF(TRDIR, 1)
+#define TRDIR_WRITE	MMCI_BF(TRDIR, 0)
 #define TRTYP_BLOCK	MMCI_BF(TRTYP, 0)
 #define INIT_CMD	MMCI_BF(SPCMD, 1)
 #define OPEN_DRAIN	MMCI_BF(OPDCMD, 1)
@@ -109,6 +148,20 @@
 			 | MMCI_BIT(RINDE)		\
 			 | MMCI_BIT(RTOE))
 
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
+#undef pr_debug
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
 static int
 mmc_cmd(unsigned long cmd, unsigned long arg,
 	void *resp, unsigned long flags)
@@ -117,7 +170,9 @@
 	int i, response_words = 0;
 	unsigned long error_flags;
 	u32 status;
-
+#if     1
+	pr_debug("mmc_cmd: entry\n");
+#endif  /* 1 */
 	AT91F_MMC_Hardware_Init();
 	
 	pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
@@ -161,12 +216,28 @@
 	return 0;
 }
 
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
+#undef pr_debug
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
 static int mmc_acmd(unsigned long cmd, unsigned long arg,
 		    void *resp, unsigned long flags)
 {
 	unsigned long aresp[4];
 	int ret;
 
+	pr_debug("mmc_acmd: entry\n");
+
 	/*
 	 * Seems like the APP_CMD part of an ACMD has 64 cycles max
 	 * latency even though the ACMD part doesn't. This isn't
@@ -184,7 +255,16 @@
 	return ret;
 }
 
-static unsigned long
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
+unsigned long
 mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
 	  unsigned long *buffer)
 {
@@ -193,7 +273,14 @@
 	unsigned long card_status, data;
 	unsigned long wordcount;
 	u32 status;
+	unsigned long *bufaddr;
 
+	pr_debug("mmc_bread: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n", ret,
card_status);
+
+	bufaddr = buffer;
+
 	if (blkcnt == 0)
 		return 0;
 
@@ -202,10 +289,16 @@
 
 	/* Put the device into Transfer state */
 	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n",
+		 ret, card_status);
 	if (ret) goto fail;
 
 	/* Set block length */
 	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n",
+		 ret, card_status);
 	if (ret) goto fail;
 
 	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
@@ -228,7 +321,6 @@
 
 			if (status & MMCI_BIT(RXRDY)) {
 				data = mmci_readl(RDR);
-				/* pr_debug("%x\n", data); */
 				*buffer++ = data;
 				wordcount++;
 			}
@@ -240,12 +332,68 @@
 			status = mmci_readl(SR);
 		} while (!(status & MMCI_BIT(BLKE)));
 
-		putc('.');
+		mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+			&card_status, R1 | NCR);
+		pr_debug("mmc: bread ret = %d, card status = %08x\n",
+			ret, card_status);
+
+		if (i % 0x800 == 0x7ff) {
+		        putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+               }
+
+#if     0
+		buffer = bufaddr;
+		wordcount = 0;
+		do {
+		        if (wordcount % 8 == 0) {
+			        pr_debug("\n%06lx:", 4 * wordcount);
+			}
+			pr_debug(" %08lx", *buffer++);
+			wordcount++;
+		} while (4 * wordcount < mmc_blkdev.blksz);
+		pr_debug("\n");
+#endif  /* 0 */
+
 	}
 
 out:
 	/* Put the device back into Standby state */
 	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n", ret,
card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
 	return i;
 
 fail:
@@ -254,8 +402,329 @@
 	goto out;
 }
 
+unsigned long
+mmc_bwrite(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+	unsigned long *bufaddr;
+
+	pr_debug("mmc_bwrite: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("en mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+
+	bufaddr = buffer;
+
+	if (blkcnt == 0)
+		return 0;
+
+	pr_debug("mmc_bwrite: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("sc mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bl mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	for (i = 0; i < blkcnt; i++, start++) {
+		ret = mmc_cmd(MMC_CMD_WRITE_BLOCK,
+			      start * mmc_blkdev.blksz, resp,
+			      (R1 | NCR | TRCMD_START | TRDIR_WRITE
+			       | TRTYP_BLOCK));
+		if (ret) goto fail;
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(UNRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(TXRDY)));
+
+			if (status & MMCI_BIT(TXRDY)) {
+			        data = *buffer++;
+				mmci_writel(TDR, data);
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+		pr_debug("mmc: write %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+
+		do {
+		        mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+				&card_status, R1 | NCR);
+			if ((card_status & 0x00000100) != 0x00000100) {
+#if     0
+			        printf("lp mmc: bwrite ret = %d, ",
ret);
+				printf("card status = %08x\n",
card_status);
+#endif  /* 0 */
+			} else {
+			        pr_debug("lp mmc: bwrite ret = %d, ",
ret);
+				pr_debug("card status = %08x\n",
card_status);
+			}
+		} while ((card_status & 0x00000100) != 0x00000100);
+
+		if (i % 0x800 == 0x7ff) {
+		         putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+		}
+
+#if     0
+		ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+			      0, resp,
+			      R1 | NCR);
+		mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+			&card_status, R1 | NCR);
+		pr_debug("st mmc: bwrite ret = %d, card status =
%08x\n",
+			 ret, card_status);
+		if (ret) goto fail;
+#endif  /* 0 */
+
+	}
+
+out:
+#if     0
+	ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+		      0, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("st mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+#endif  /* 0 */
+
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("dc mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("fa mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	goto out;
+}
+
+   /* Hangs - did not attempt to debug */
+/* MMC Multiple Block Write - mmc_mbwrite() */
+unsigned long
+mmc_mbwrite(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+	unsigned long *bufaddr;
+
+	pr_debug("mmc_bwrite: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("en mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+
+	bufaddr = buffer;
+
+	if (blkcnt == 0)
+		return 0;
+
+	if (blkcnt > 0xffff) {  /* Exceeds length supported by MoviNAND.
*/
+	        return -1;
+	}
+
+	pr_debug("mmc_mbwrite: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("sc mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bl mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	ret = mmc_cmd(MMC_CMD_SET_BLOCK_COUNT,
+		      blkcnt, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bc mmc: mbwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	ret = mmc_cmd(MMC_CMD_WRITE_MULTIPLE_BLOCK,
+		      start * mmc_blkdev.blksz, resp,
+		      (R1 | NCR | TRCMD_START | TRDIR_WRITE |
TRTYP_BLOCK));
+	if (ret) goto fail;
+
+	for (i = 0; i < blkcnt; i++, start++) {
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(UNRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(TXRDY)));
+
+			if (status & MMCI_BIT(TXRDY)) {
+			        data = *buffer++;
+				mmci_writel(TDR, data);
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+#if     1
+		pr_debug("mmc: write %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+#endif  /* 0 */
+
+		do {
+		        mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+				&card_status, R1 | NCR);
+			if ((card_status & 0x00000100) != 0x00000100) {
+#if     0
+			        printf("lp mmc: mbwrite ret = %d, ",
ret);
+				printf("card status = %08x\n",
card_status);
+#endif  /* 0 */
+			} else {
+			        pr_debug("lp mmc: mbwrite ret = %d, ",
ret);
+				pr_debug("card status = %08x\n",
card_status);
+			}
+		} while ((card_status & 0x00000100) != 0x00000100);
+
+		if (i % 0x800 == 0x7ff) {
+		         putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+		}
+	}
+
+out:
+#if     0
+	ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+		      0, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("st mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+#endif  /* 0 */
+
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("dc mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("fa mmc: mbwrite failed, card status = %08x\n",
card_status);
+	goto out;
+}
+
 static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp)
 {
+	pr_debug("mmc_parse_cid: entry\n");
+
 	cid->mid = resp[0] >> 24;
 	cid->oid = (resp[0] >> 8) & 0xffff;
 	cid->pnm[0] = resp[0];
@@ -272,6 +741,8 @@
 
 static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp)
 {
+	pr_debug("sd_parse_cid: entry\n");
+
 	cid->mid = resp[0] >> 24;
 	cid->oid = (resp[0] >> 8) & 0xffff;
 	cid->pnm[0] = resp[0];
@@ -288,6 +759,8 @@
 
 static void mmc_dump_cid(const struct mmc_cid *cid)
 {
+	pr_debug("mmc_dump_cid: entry\n");
+
 	printf("Manufacturer ID:       %02lX\n", cid->mid);
 	printf("OEM/Application ID:    %04lX\n", cid->oid);
 	printf("Product name:          %s\n", cid->pnm);
@@ -301,6 +774,9 @@
 static void mmc_dump_csd(const struct mmc_csd *csd)
 {
 	unsigned long *csd_raw = (unsigned long *)csd;
+
+	pr_debug("mmc_dump_csd: entry\n");
+
 	pr_debug("CSD data: %08lx %08lx %08lx %08lx\n",
 	       csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
 	pr_debug("CSD structure version:   1.%u\n", csd->csd_structure);
@@ -337,6 +813,8 @@
 {
 	int ret;
 
+	pr_debug("mmc_idle_cards: entry\n");
+
 	/* Reset and initialize all cards */
 	ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0);
 	
@@ -352,6 +830,8 @@
 	unsigned long resp[4];
 	int i, ret = 0;
 
+	pr_debug("sd_init_card: entry\n");
+
 	mmc_idle_cards();
 	for (i = 0; i < 1000; i++) {
 		ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND,
CFG_MMC_OP_COND,
@@ -387,10 +867,40 @@
 {
 	unsigned long resp[4];
 	int i, ret = 0;
+	u32 status;
 
+	pr_debug("mmc_init_card: entry\n");
+
 	mmc_idle_cards();
 
+	/* MoviNAND initialization */
 	for (i = 0; i < 1000; i++) {
+	        mmci_writel(ARGR, 0xFFFFFFFF);
+		mmci_writel(CMDR, 0x0018113F);
+		do {
+		        status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(CMDRDY)));
+	}
+        /* Getting the OCR value seems to prevent marginal chips from
*/
+        /* working at all, whereas they would work fine after waiting
*/
+        /* a full minute or more with the power off prior to booting.
*/
+        /* Our marginal chips have date codes 0716 and 0728.
*/
+#if     0   
+	for (i = 0; i < 1000; i++) {
+	  /* Request OCR value to determine chip's supported volt. */
+		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, 0, resp,
+			      R3 | NID | OPEN_DRAIN);
+		if (ret || (resp[0] & 0x80000000))
+		{
+			break;
+		}
+		ret = -ETIMEDOUT;
+	}
+	if (ret) {
+		return ret;
+	}
+#endif  /* 0 */
+	for (i = 0; i < 1000; i++) {
 		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND,
resp,
 			      R3 | NID | OPEN_DRAIN);
 		if (ret || (resp[0] & 0x80000000))
@@ -399,13 +909,35 @@
 		}
 		ret = -ETIMEDOUT;
 	}
+        pr_debug("Step 4: ret = 0x%lx\n", ret);
+	pr_debug("MMC_CMD_SEND_OP_COND = 0x%lx\n",
MMC_CMD_SEND_OP_COND);
+        pr_debug("CFG_MMC_OP_COND = 0x%lx\n", CFG_MMC_OP_COND);
+        pr_debug("resp[0] = 0x%lx\n", resp[0]);
+        pr_debug("resp[1] = 0x%lx\n", resp[1]);
+        pr_debug("resp[2] = 0x%lx\n", resp[2]);
+        pr_debug("resp[3] = 0x%lx\n", resp[3]);
+        pr_debug("R3 = 0x%lx\n", R3);
+        pr_debug("NID = 0x%lx\n", NID);
+        pr_debug("OPEN_DRAIN = 0x%lx\n", OPEN_DRAIN);
+
 	pr_debug("4\n");
 	pr_debug("ret : %i\n",ret);
+
+	pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR));
+	pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR));
+	pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR));
+	pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR));
+	/* RSPR */
+	/* RDR */
+	pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR));
+	pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR));
+
 	if (ret)
 		return ret;
 	pr_debug("5\n");
 	/* Get CID of all cards. FIXME: Support more than one card */
 	ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID |
OPEN_DRAIN);
+	pr_debug("ALL_SEND_CID ret: 0x%08lx\n", ret);
 	if (ret)
 		return ret;
 	mmc_parse_cid(cid, resp);
@@ -415,6 +947,7 @@
 	/* Set Relative Address of the card that responded */
 	ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp,
 		      R1 | NCR | OPEN_DRAIN);
+	pr_debug("SET_RELATIVE_ADDR ret: 0x%08lx\n", ret);
 	return ret;
 }
 
@@ -471,23 +1004,42 @@
 	       dtocyc << shift, dtor);
 }
 
+#define DEFAULT_SECTOR_SIZE 512
+
 int mmc_init(int verbose)
 {
 	struct mmc_cid cid;
 	struct mmc_csd csd;
 	unsigned int max_blksz;
 	int ret,aux;
+	unsigned char buffer[DEFAULT_SECTOR_SIZE];
 	
+	pr_debug("mmc_init: entry\n");
+	pr_debug("mmc_init: verbose = 0x%08lx\n", verbose);
+
 	AT91F_MMC_Hardware_Init();
 	
 	pr_debug("0\n");
 	/* Initialize controller */
 	mmci_writel(CR, MMCI_BIT(SWRST));
 	mmci_writel(CR, MMCI_BIT(MCIEN));
+
+	pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR));
+	pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR));
+	pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR));
+	pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR));
+	/* RSPR */
+	/* RDR */
+	pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR));
+	pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR));
+
 	mmci_writel(DTOR, 0x5f);
 	mmci_writel(IDR, ~0UL);
 	mmci_writel(SDCR, 0x1);
 	mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+#if     0
+	mmci_writel(MR, 0x02009B4A);
+#endif  /* 0 */
 /* 	//mmci_writel(CR, MMCI_BIT(SWRST));
 	mmci_writel(CR, 0x00000001);
 	mmci_writel(DTOR, 0x0000007F);
@@ -502,6 +1054,7 @@
 
 	ret = sd_init_card(&cid, verbose);
 	if (ret) {
+	  	pr_debug("Not SDCard, try MMC\n");
 		mmc_rca = MMC_DEFAULT_RCA;
 		ret = mmc_init_card(&cid, verbose);
 	}
@@ -545,6 +1098,20 @@
 	mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz);
 
 #if 0
+	mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer);
+        buffer[0] = 0x00; buffer[1] = 0x11;
+        buffer[2] = 0x22; buffer[3] = 0x33;
+        buffer[4] = 0x44; buffer[5] = 0x55;
+        buffer[6] = 0x66; buffer[7] = 0x77;
+        buffer[504] = 0x88; buffer[505] = 0x99;
+        buffer[506] = 0xaa; buffer[507] = 0xbb;
+        buffer[508] = 0xcc; buffer[509] = 0xdd;
+        buffer[510] = 0xee; buffer[511] = 0xff;
+	mmc_bwrite(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); 
+	mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer);
+#endif  /* 0 */
+
+#if 0
 	if (fat_register_device(&mmc_blkdev, 1))
 		pr_debug("Could not register MMC fat device\n");
 #else
@@ -556,16 +1123,22 @@
 
 int mmc_read(ulong src, uchar *dst, int size)
 {
+	pr_debug("mmc_read: entry\n");
+
 	return -ENOSYS;
 }
 
 int mmc_write(uchar *src, ulong dst, int size)
 {
+	pr_debug("mmc_write: entry\n");
+
 	return -ENOSYS;
 }
 
 int mmc2info(ulong addr)
 {
+	pr_debug("mmc2info: entry\n");
+
 	return 0;
 }
 
svn diff -r21 include/asm-arm/arch-at91sam926x/mmc.h
Index: include/asm-arm/arch-at91sam926x/mmc.h
===================================================================
--- include/asm-arm/arch-at91sam926x/mmc.h	(revision 0)
+++ include/asm-arm/arch-at91sam926x/mmc.h	(revision 50)
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright 2007
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __ASM_AT91SAM926X_MMC_H
+#define __ASM_AT91SAM926X_MMC_H
+
+struct mmc_cid {
+	unsigned long psn;
+	unsigned short oid;
+	unsigned char mid;
+	unsigned char prv;
+	unsigned char mdt;
+	char pnm[7];
+};
+
+struct mmc_csd
+{
+	u8	csd_structure:2,
+		spec_vers:4,
+		rsvd1:2;
+	u8	taac;
+	u8	nsac;
+	u8	tran_speed;
+	u16	ccc:12,
+		read_bl_len:4;
+	u64	read_bl_partial:1,
+		write_blk_misalign:1,
+		read_blk_misalign:1,
+		dsr_imp:1,
+		rsvd2:2,
+		c_size:12,
+		vdd_r_curr_min:3,
+		vdd_r_curr_max:3,
+		vdd_w_curr_min:3,
+		vdd_w_curr_max:3,
+		c_size_mult:3,
+		sector_size:5,
+		erase_grp_size:5,
+		wp_grp_size:5,
+		wp_grp_enable:1,
+		default_ecc:2,
+		r2w_factor:3,
+		write_bl_len:4,
+		write_bl_partial:1,
+		rsvd3:5;
+	u8	file_format_grp:1,
+		copy:1,
+		perm_write_protect:1,
+		tmp_write_protect:1,
+		file_format:2,
+		ecc:2;
+	u8	crc:7;
+	u8	one:1;
+};
+
+/* MMC Command numbers */
+#define MMC_CMD_GO_IDLE_STATE		0
+#define MMC_CMD_SEND_OP_COND		1
+#define MMC_CMD_ALL_SEND_CID 		2
+#define MMC_CMD_SET_RELATIVE_ADDR	3
+#define MMC_CMD_SD_SEND_RELATIVE_ADDR	3
+#define MMC_CMD_SET_DSR			4
+#define MMC_CMD_SELECT_CARD		7
+#define MMC_CMD_SEND_CSD 		9
+#define MMC_CMD_SEND_CID 		10
+#define MMC_CMD_STOP_TRANSMISSION	12
+#define MMC_CMD_SEND_STATUS		13
+#define MMC_CMD_SET_BLOCKLEN		16
+#define MMC_CMD_READ_SINGLE_BLOCK	17
+#define MMC_CMD_READ_MULTIPLE_BLOCK	18
+#define MMC_CMD_SET_BLOCK_COUNT		23
+#define MMC_CMD_WRITE_BLOCK		24
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK	25
+#define MMC_CMD_APP_CMD			55
+
+#define MMC_ACMD_SD_SEND_OP_COND	41
+
+#define R1_ILLEGAL_COMMAND		(1 << 22)
+#define R1_APP_CMD			(1 << 5)
+
+#endif /* __ASM_AT91SAM926X_MMC_H */

svn diff -r21 include/configs/at91sam9261ek.h
Index: include/configs/at91sam9261ek.h
===================================================================
--- include/configs/at91sam9261ek.h	(revision 21)
+++ include/configs/at91sam9261ek.h	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
  * (C) Copyright 2005
  * M. Amine SAYA ATMEL Rousset, France.
  *
@@ -95,18 +99,24 @@
 /* SPI */
 #define CONFIG_SPI
 
+/* kf - define hush (from busy box) command line interface & options */
+#define CFG_HUSH_PARSER
+#define CFG_PROMPT_HUSH_PS2     "> "
+#define CFG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
 #define CONFIG_COMMANDS		\
 		       ((CONFIG_CMD_DFL	| \
                         CFG_CMD_NET | \
                         CFG_CMD_ENV | \
                         CFG_CMD_USB | \
                         CFG_CMD_FLASH | \
-			CFG_CMD_NAND | \
+                        CFG_CMD_MMC | \
+                        CFG_CMD_EXT2 | \
+                        CFG_CMD_FAT | \
 			CFG_CMD_AUTOSCRIPT | \
-                        CFG_CMD_FAT | \
                         CFG_CMD_NFS | \
                         CFG_CMD_SPI | \
-                        CFG_CMD_U | \
 			CFG_CMD_IMI | \
                         CFG_CMD_PING ) & \
 		      ~(CFG_CMD_BDI | \
@@ -296,8 +306,12 @@
 #define CFG_FLASH_ERASE_TOUT		(2*CFG_HZ) /* Timeout for Flash
Erase */
 #define CFG_FLASH_WRITE_TOUT		(2*CFG_HZ) /* Timeout for Flash
Write */
 
+#undef  CFG_ENV_IS_IN_FLASH
 #define	CFG_ENV_IS_IN_DATAFLASH         1
-#undef  CFG_ENV_IS_IN_FLASH
+#if     0
+#undef  CFG_ENV_IS_IN_NAND
+#endif  /* 0 - kf */
+#undef  CFG_ENV_IS_NOWHERE
 
 #ifdef CFG_ENV_IS_IN_DATAFLASH
 #define CFG_ENV_OFFSET			0x4000
@@ -305,6 +319,10 @@
 #define CFG_ENV_SIZE			0x4000  /* 0x8000 */
 #endif
 
+#ifdef CFG_ENV_IS_NOWHERE
+#define CFG_ENV_SIZE			0x4000
+#endif
+
 #ifdef CFG_ENV_IS_IN_FLASH
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_ENV_ADDR			(PHYS_FLASH_1 + 0x60000)  /*
after u-boot.bin */
@@ -316,6 +334,9 @@
 #endif
 
 /* Add LCD stuff */
+/* Ignore */
+/* Ignore */
+
 #if 0  /* No LCD */
 #define  CONFIG_LCD
 /* #undef  CONFIG_LCD_LOGO */
@@ -333,8 +354,21 @@
 #define CONFIG_DOS_PARTITION	        1
 #define LITTLEENDIAN 			1
 
-#define CFG_LOAD_ADDR		0x23f00000  /* default load address */
+/* Add FAT filesystem configuration, other than CFG_CMD_FAT */
+#define CONFIG_SUPPORT_VFAT
 
+/* MMC */
+#define CONFIG_MMC		1
+#define MMCI_BASE		0xFFFA8000  /* (void *)AT91C_BASE_MCI */
+/* MMC - kf - slow down speed for debug from 20000000 Hz down to ...
*/
+/* However, tweaking this value here causes all code to be compiled,
*/
+/* so we shall change the value only where needed - in atmel_mci.c.
*/
+#define CFG_MMC_CLK_PP          20000000
+
+#define CFG_LOAD_ADDR		0x23f00000  /* default load address   */
+
+#define CFG_BOOTM_LEN           0x02100000  /* 33MB uncompressed max.
*/
+
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_BOOT_SIZE		0x00 /* 0 KBytes */
 #define CFG_U_BOOT_BASE		PHYS_FLASH_1

svn diff -r21 board/at91sam9261ek/at91sam9261ek.c
Index: board/at91sam9261ek/at91sam9261ek.c
===================================================================
--- board/at91sam9261ek/at91sam9261ek.c	(revision 21)
+++ board/at91sam9261ek/at91sam9261ek.c	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added specific AT91SAM9261 board support
+ *
  * (C) Copyright 2005
  * M. Amine SAYA ATMEL Rousset, France.
  * Added AT91SAM9261EK support.
@@ -28,12 +32,19 @@
 
 #include <common.h>
 #include <asm/arch/hardware.h>
+#include <asm/arch-at91sam926x/at91sam9261.h>
 
 #include <net.h>
 
 extern void AT91F_Spi1Init (void);
 extern void gpio_init(void);
 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
 /*
------------------------------------------------------------------------
- */
 /*
  * Miscelaneous platform dependent initialisations
@@ -107,7 +118,8 @@
   *AT91C_PMC_PCER |= 1 << AT91C_ID_US0;	/* enable clock */
 #endif
   
-#ifdef CONFIG_USART1
+#if     1
+  /* #ifdef CONFIG_USART1 */
   *AT91C_PIOB_PDR = AT91C_PC12_TXD1 | AT91C_PC13_RXD1;
   *AT91C_PMC_PCER |= 1 << AT91C_ID_US1;	/* enable clock */
 #endif
@@ -118,6 +130,41 @@
 #endif
 }
 
+#ifdef CONFIG_MMC
+#if (CONFIG_COMMANDS & CFG_CMD_MMC)
+int AT91F_MMC_Hardware_Init(void)
+{
+#if     0
+	printf("AT91F_MMC_Hardware_Init: entry\n");
+#endif  /* 0 */
+
+        AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,
+			    0,                   /*  <- Peripheral A */
+			    (AT91C_PA0_MCDA0 |    /*  MMC NAND MCDA0  */
+			     AT91C_PA1_MCCDA |    /*  MMC NAND MCCDA  */
+			     AT91C_PA2_MCCK  |    /*  MMC NAND MCCK   */
+			     AT91C_PA4_MCDA1 |    /*  MMC NAND MCDA1  */
+			     AT91C_PA5_MCDA2 |    /*  MMC NAND MCDA2  */
+			     AT91C_PA6_MCDA3 |    /*  MMC NAND MCDA3  */
+			     0));                 /*  <- Peripheral B */
+
+#if     1
+	/* Pull up disable register */
+	AT91C_BASE_PIOA->PIO_PPUDR |=
+	        AT91C_PA0_MCDA0 |    /*  MMC NAND MCDA0  */
+	        AT91C_PA1_MCCDA |    /*  MMC NAND MCCDA  */
+	        AT91C_PA2_MCCK  |    /*  MMC NAND MCCK   */
+	        AT91C_PA4_MCDA1 |    /*  MMC NAND MCDA1  */
+	        AT91C_PA5_MCDA2 |    /*  MMC NAND MCDA2  */
+	        AT91C_PA6_MCDA3;     /*  MMC NAND MCDA3  */
+#endif  /* 0 */
+
+	AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_MCI);
+}
+#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */
+#endif /* CONFIG_MMC */
+
+
 int dram_init (void)
 {
   DECLARE_GLOBAL_DATA_PTR;
@@ -148,5 +195,35 @@
 
   gpio_init();
 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
   return 0;
 }




More information about the U-Boot mailing list