Signed-off-by: Reinhard Meyer <u-b...@emk-elektronik.de>
---
 arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c |   20 +++
 arch/arm/include/asm/arch-at91/at91_common.h      |    1 +
 arch/arm/include/asm/arch-at91/clk.h              |    5 +
 arch/arm/include/asm/arch-at91/hardware.h         |    1 +
 doc/README.atmel_mci                              |   68 +++++++++++
 drivers/mmc/atmel_mci.c                           |  134 ++++++++++-----------
 drivers/mmc/atmel_mci.h                           |    6 +-
 include/mmc.h                                     |   93 +++++++++------
 8 files changed, 217 insertions(+), 111 deletions(-)
 create mode 100644 doc/README.atmel_mci

diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c 
b/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c
index 77d49ab..9cef832 100644
--- a/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c
+++ b/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c
@@ -194,3 +194,23 @@ void at91_macb_hw_init(void)
 #endif
 }
 #endif
+
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci_hw_init(void)
+{
+       at91_set_a_periph(AT91_PIO_PORTA, 8, 0);        /* MCCK */
+#if defined(CONFIG_ATMEL_MCI_PORTB)
+       at91_set_b_periph(AT91_PIO_PORTA, 1, 0);        /* MCCDB */
+       at91_set_b_periph(AT91_PIO_PORTA, 0, 0);        /* MCDB0 */
+       at91_set_b_periph(AT91_PIO_PORTA, 5, 0);        /* MCDB1 */
+       at91_set_b_periph(AT91_PIO_PORTA, 4, 0);        /* MCDB2 */
+       at91_set_b_periph(AT91_PIO_PORTA, 3, 0);        /* MCDB3 */
+#else
+       at91_set_a_periph(AT91_PIO_PORTA, 7, 0);        /* MCCDA */
+       at91_set_a_periph(AT91_PIO_PORTA, 6, 0);        /* MCDA0 */
+       at91_set_a_periph(AT91_PIO_PORTA, 9, 0);        /* MCDA1 */
+       at91_set_a_periph(AT91_PIO_PORTA, 10, 0);       /* MCDA2 */
+       at91_set_a_periph(AT91_PIO_PORTA, 11, 0);       /* MCDA3 */
+#endif
+}
+#endif
diff --git a/arch/arm/include/asm/arch-at91/at91_common.h 
b/arch/arm/include/asm/arch-at91/at91_common.h
index 01840ee..90337eb 100644
--- a/arch/arm/include/asm/arch-at91/at91_common.h
+++ b/arch/arm/include/asm/arch-at91/at91_common.h
@@ -35,5 +35,6 @@ void at91_serial3_hw_init(void);
 void at91_spi0_hw_init(unsigned long cs_mask);
 void at91_spi1_hw_init(unsigned long cs_mask);
 void at91_uhp_hw_init(void);
+void at91_mci_hw_init(void);
 
 #endif /* AT91_COMMON_H */
diff --git a/arch/arm/include/asm/arch-at91/clk.h 
b/arch/arm/include/asm/arch-at91/clk.h
index f642dd9..457e6c9 100644
--- a/arch/arm/include/asm/arch-at91/clk.h
+++ b/arch/arm/include/asm/arch-at91/clk.h
@@ -59,5 +59,10 @@ static inline unsigned long get_twi_clk_rate(unsigned int 
dev_id)
        return get_mck_clk_rate();
 }
 
+static inline unsigned long get_mci_clk_rate(void)
+{
+       return get_mck_clk_rate();
+}
+
 int at91_clock_init(unsigned long main_clock);
 #endif /* __ASM_ARM_ARCH_CLK_H__ */
diff --git a/arch/arm/include/asm/arch-at91/hardware.h 
b/arch/arm/include/asm/arch-at91/hardware.h
index 4ddb315..224b285 100644
--- a/arch/arm/include/asm/arch-at91/hardware.h
+++ b/arch/arm/include/asm/arch-at91/hardware.h
@@ -23,6 +23,7 @@
 #define AT91_BASE_SPI  AT91SAM9260_BASE_SPI0
 #define AT91_ID_UHP    AT91SAM9260_ID_UHP
 #define AT91_PMC_UHP   AT91SAM926x_PMC_UHP
+#define MMCI_BASE      AT91SAM9260_BASE_MCI
 #elif defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10)
 #include <asm/arch/at91sam9261.h>
 #define AT91_BASE_SPI  AT91SAM9261_BASE_SPI0
diff --git a/doc/README.atmel_mci b/doc/README.atmel_mci
new file mode 100644
index 0000000..15b3cc0
--- /dev/null
+++ b/doc/README.atmel_mci
@@ -0,0 +1,68 @@
+How to use SD/MMC cards with Atmel SoCs having MCI hardware
+-----------------------------------------------------------
+2010-07-04 Reinhard Meyer <reinhard.me...@emk-elektronik.de>
+
+The drivers/mmc/atmel_mci.c file which originally worked only
+with the AVR32 architecture SoCs like AVR32AP700x has been
+updated to also work with the AT91SAM9260 compatible architectures:
+
+- AT91SAM9XE512 (tested, will definitely work with XE128 and XE256)
+- AT91SAM9260 (not tested, but MCI is to AT91SAM9XE)
+- AT91SAM9G20 (not tested, should work)
+
+It should work with all other AT91SAM9<xxx> devices that have MCI
+provided that a correct version of the following function is added
+to their specific XXX_devices file:
+
+(this example is from at91sam9260_devices.c)
+
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci_hw_init(void)
+{
+       at91_set_a_periph(AT91_PIO_PORTA, 8, 0);        /* MCCK */
+#if defined(CONFIG_ATMEL_MCI_PORTB)
+       at91_set_b_periph(AT91_PIO_PORTA, 1, 0);        /* MCCDB */
+       at91_set_b_periph(AT91_PIO_PORTA, 0, 0);        /* MCDB0 */
+       at91_set_b_periph(AT91_PIO_PORTA, 5, 0);        /* MCDB1 */
+       at91_set_b_periph(AT91_PIO_PORTA, 4, 0);        /* MCDB2 */
+       at91_set_b_periph(AT91_PIO_PORTA, 3, 0);        /* MCDB3 */
+#else
+       at91_set_a_periph(AT91_PIO_PORTA, 7, 0);        /* MCCDA */
+       at91_set_a_periph(AT91_PIO_PORTA, 6, 0);        /* MCDA0 */
+       at91_set_a_periph(AT91_PIO_PORTA, 9, 0);        /* MCDA1 */
+       at91_set_a_periph(AT91_PIO_PORTA, 10, 0);       /* MCDA2 */
+       at91_set_a_periph(AT91_PIO_PORTA, 11, 0);       /* MCDA3 */
+#endif
+
+the board specific files need added:
+
+#ifdef CONFIG_ATMEL_MCI
+static void mci_hw_init(void)
+{
+       /* Enable clock */
+       at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_MCI);
+
+       at91_mci_hw_init();
+}
+#endif
+
+int board_init(void)
+{
+       ...
+#ifdef CONFIG_ATMEL_MCI
+       mci_hw_init();
+#endif
+       ...
+       return 0;
+}
+
+and the board definition files needs:
+/* for the driver itself */
+#define CONFIG_MMC             1
+#define CONFIG_ATMEL_MCI       1
+#define CONFIG_ATMEL_MCI_PORTB 1       /* to use port B, undefine for port A */
+/* to use the cards */
+#define CONFIG_CMD_EXT2                1
+#define CONFIG_CMD_FAT         1
+#define CONFIG_CMD_MMC         1
+
diff --git a/drivers/mmc/atmel_mci.c b/drivers/mmc/atmel_mci.c
index 3946ffe..2d9e3c7 100644
--- a/drivers/mmc/atmel_mci.c
+++ b/drivers/mmc/atmel_mci.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004-2006 Atmel Corporation
- *
+ * Copyright (C) 2010 EMK Elektronik <reinhard.me...@emk-elektronik.de>
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -19,6 +19,12 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  */
+/*
+ * Notes:
+ * - modified to work with AVR32 and AT91
+ * - this driver handles cards in 1 bit bus width only,
+ * which is enough to load a kernel or similiar file
+ */
 #include <common.h>
 
 #include <part.h>
@@ -32,12 +38,6 @@
 
 #include "atmel_mci.h"
 
-#ifdef DEBUG
-#define pr_debug(fmt, args...) printf(fmt, ##args)
-#else
-#define pr_debug(...) do { } while(0)
-#endif
-
 #ifndef CONFIG_SYS_MMC_CLK_OD
 #define CONFIG_SYS_MMC_CLK_OD          150000
 #endif
@@ -70,13 +70,13 @@ static void mci_set_mode(unsigned long hz, unsigned long 
blklen)
        bus_hz = get_mci_clk_rate();
        clkdiv = (bus_hz / hz) / 2 - 1;
 
-       pr_debug("mmc: setting clock %lu Hz, block size %lu\n",
-                hz, blklen);
+       debug("mmc: bus_hz is %lu, setting clock %lu Hz, block size %lu\n",
+                bus_hz, hz, blklen);
 
        if (clkdiv & ~255UL) {
                clkdiv = 255;
-               printf("mmc: clock %lu too low; setting CLKDIV to 255\n",
-                       hz);
+               printf("mmc: requested clock %lu is too low; changed to %lu\n",
+                       hz, (bus_hz / (clkdiv+1)) / 2);
        }
 
        blklen &= 0xfffc;
@@ -84,6 +84,10 @@ static void mci_set_mode(unsigned long hz, unsigned long 
blklen)
                         | MMCI_BF(BLKLEN, blklen)
                         | MMCI_BIT(RDPROOF)
                         | MMCI_BIT(WRPROOF)));
+#if defined(CONFIG_ATMEL_MCI_PORTB)
+       mmci_writel(SDCR, (MMCI_BF(SCDSEL, 1)
+                        | MMCI_BF(SCDBUS, 0)));
+#endif
 }
 
 #define RESP_NO_CRC    1
@@ -114,7 +118,7 @@ mmc_cmd(unsigned long cmd, unsigned long arg,
        unsigned long error_flags;
        u32 status;
 
-       pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
+       debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
                 cmd, arg, flags);
 
        error_flags = ERROR_FLAGS;
@@ -135,7 +139,7 @@ mmc_cmd(unsigned long cmd, unsigned long arg,
                status = mmci_readl(SR);
        } while (!(status & MMCI_BIT(CMDRDY)));
 
-       pr_debug("mmc: status 0x%08x\n", status);
+       debug("mmc: status 0x%08x\n", status);
 
        if (status & error_flags) {
                printf("mmc: command %lu failed (status: 0x%08x)\n",
@@ -144,13 +148,13 @@ mmc_cmd(unsigned long cmd, unsigned long arg,
        }
 
        if (response_words)
-               pr_debug("mmc: response:");
+               debug("mmc: response:");
 
        for (i = 0; i < response_words; i++) {
                response[i] = mmci_readl(RSPR);
-               pr_debug(" %08lx", response[i]);
+               debug(" %08lx", response[i]);
        }
-       pr_debug("\n");
+       debug("\n");
 
        return 0;
 }
@@ -192,7 +196,7 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
        if (blkcnt == 0)
                return 0;
 
-       pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n",
+       debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n",
                 dev, start, blkcnt);
 
        /* Put the device into Transfer state */
@@ -203,7 +207,7 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
        ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR);
        if (ret) goto out;
 
-       pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+       debug("MCI_DTOR = %08x\n", mmci_readl(DTOR));
 
        for (i = 0; i < blkcnt; i++, start++) {
                ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK,
@@ -229,13 +233,16 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
                        }
                } while(wordcount < (mmc_blkdev.blksz / 4));
 
-               pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount);
+               debug("mmc: read %lu words, waiting for BLKE\n", wordcount);
 
                do {
                        status = mmci_readl(SR);
                } while (!(status & MMCI_BIT(BLKE)));
-
-               putc('.');
+#if DEBUG
+               /* print the first block only */
+               if (i==0)
+                       print_buffer(0, buffer, 1, mmc_blkdev.blksz, 0);
+#endif
        }
 
 out:
@@ -294,39 +301,26 @@ static void mmc_dump_cid(const struct mmc_cid *cid)
               cid->mdt >> 4, cid->mdt & 0x0f);
 }
 
-static void mmc_dump_csd(const struct mmc_csd *csd)
+static void mmc_parse_csd(struct mmc_csd *csd, int verbose)
 {
-       unsigned long *csd_raw = (unsigned long *)csd;
-       printf("CSD data: %08lx %08lx %08lx %08lx\n",
-              csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
-       printf("CSD structure version:   1.%u\n", csd->csd_structure);
-       printf("MMC System Spec version: %u\n", csd->spec_vers);
-       printf("Card command classes:    %03x\n", csd->ccc);
-       printf("Read block length:       %u\n", 1 << csd->read_bl_len);
-       if (csd->read_bl_partial)
-               puts("Supports partial reads\n");
-       else
-               puts("Does not support partial reads\n");
-       printf("Write block length:      %u\n", 1 << csd->write_bl_len);
-       if (csd->write_bl_partial)
-               puts("Supports partial writes\n");
-       else
-               puts("Does not support partial writes\n");
-       if (csd->wp_grp_enable)
-               printf("Supports group WP:      %u\n", csd->wp_grp_size + 1);
-       else
-               puts("Does not support group WP\n");
-       printf("Card capacity:          %u bytes\n",
-              (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) *
-              (1 << csd->read_bl_len));
-       printf("File format:            %u/%u\n",
-              csd->file_format_grp, csd->file_format);
-       puts("Write protection:        ");
-       if (csd->perm_write_protect)
-               puts(" permanent");
-       if (csd->tmp_write_protect)
-               puts(" temporary");
-       putc('\n');
+       csd->taac = (csd->raw[0] >> 16) & 0xff;
+       csd->nsac = (csd->raw[0] >> 8) & 0xff;
+       csd->read_bl_len = (csd->raw[1] >> 16) & 0x0f;
+       csd->read_bl_partial = (csd->raw[1] >> 15) & 0x01;
+       csd->c_size = ((csd->raw[1] << 2) & 0x0ffc) | ((csd->raw[2] >> 30) & 
0x03);
+       csd->c_size_mult = (csd->raw[2] >> 15) & 0x07;
+       csd->blocks = (csd->c_size+1) * (1 << (csd->c_size_mult+2));
+       csd->blocksize = 1 << csd->read_bl_len;
+
+       if (verbose) {
+               printf("raw CSD data: %08x %08x %08x %08x\n",
+                      csd->raw[0], csd->raw[1], csd->raw[2], csd->raw[3]);
+               printf("Read block length: %u\n", 1 << csd->read_bl_len);
+               if (csd->read_bl_partial)
+                       puts("  (Supports partial reads)\n");
+               printf("Card capacity: %u Mbytes\n",
+                      (csd->blocks>>12) * (csd->blocksize>>8));
+       }
 }
 
 static int mmc_idle_cards(void)
@@ -409,7 +403,7 @@ static int mmc_init_card(struct mmc_cid *cid, int verbose)
        return ret;
 }
 
-static void mci_set_data_timeout(struct mmc_csd *csd)
+static void mci_set_data_timeout(const struct mmc_csd *csd)
 {
        static const unsigned int dtomul_to_shift[] = {
                0, 4, 7, 8, 10, 12, 16, 20,
@@ -467,7 +461,6 @@ int mmc_legacy_init(int verbose)
 {
        struct mmc_cid cid;
        struct mmc_csd csd;
-       unsigned int max_blksz;
        int ret;
 
        /* Initialize controller */
@@ -491,8 +484,7 @@ int mmc_legacy_init(int verbose)
        ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR);
        if (ret)
                return ret;
-       if (verbose)
-               mmc_dump_csd(&csd);
+       mmc_parse_csd(&csd, verbose);
 
        mci_set_data_timeout(&csd);
 
@@ -508,26 +500,28 @@ int mmc_legacy_init(int verbose)
        sprintf((char *)mmc_blkdev.revision, "%x %x",
                cid.prv >> 4, cid.prv & 0x0f);
 
-       /*
-        * If we can't use 512 byte blocks, refuse to deal with the
-        * card. Tons of code elsewhere seems to depend on this.
-        */
-       max_blksz = 1 << csd.read_bl_len;
-       if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) {
+       mmc_blkdev.blksz = csd.blocksize;
+       mmc_blkdev.lba = csd.blocks;
+
+       /* if the card supports partial reads, decrease the block size to 512 */
+       while (mmc_blkdev.blksz > 512 && csd.read_bl_partial) {
+               mmc_blkdev.blksz >>= 1;
+               mmc_blkdev.lba <<= 1;
+       }
+       if (mmc_blkdev.blksz != csd.blocksize) {
+               printf ("mmc: blocksize reduced to %lu, number of blocks: 
%lu\n",
+                       mmc_blkdev.blksz, mmc_blkdev.lba);
+       }
+
+       /* fail if blocksize != 512 */
+       if (mmc_blkdev.blksz != 512) {
                printf("Card does not support 512 byte reads, aborting.\n");
                return -ENODEV;
        }
-       mmc_blkdev.blksz = 512;
-       mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2));
 
        mci_set_mode(CONFIG_SYS_MMC_CLK_PP, mmc_blkdev.blksz);
 
-#if 0
-       if (fat_register_device(&mmc_blkdev, 1))
-               printf("Could not register MMC fat device\n");
-#else
        init_part(&mmc_blkdev);
-#endif
 
        return 0;
 }
diff --git a/drivers/mmc/atmel_mci.h b/drivers/mmc/atmel_mci.h
index 5b4f5c9..8632cb4 100644
--- a/drivers/mmc/atmel_mci.h
+++ b/drivers/mmc/atmel_mci.h
@@ -19,8 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  */
-#ifndef __CPU_AT32AP_ATMEL_MCI_H__
-#define __CPU_AT32AP_ATMEL_MCI_H__
+#ifndef __ATMEL_MCI_H__
+#define __ATMEL_MCI_H__
 
 /* Atmel MultiMedia Card Interface (MCI) registers */
 #define MMCI_CR                                        0x0000
@@ -198,4 +198,4 @@
 #define mmci_writel(reg,value)                         \
        writel((value), (void *)MMCI_BASE + MMCI_##reg)
 
-#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */
+#endif /* __ATMEL_MCI_H__ */
diff --git a/include/mmc.h b/include/mmc.h
index fcb237e..c739986 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -179,44 +179,61 @@ struct mmc_cid {
        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;
+/*
+ * CSD structure forSD/MMC  cards upto 4GB
+ *
+ * Bitfields in the 128 Bit answer from the card
+ * (bit 127 is bit 31 of first u32
+ * bit 0 is bit 0 of last u32)
+ * csd_structure:127..126
+ * spec_vers:125..122
+ * rsvd1:121..120
+ * taac:119..112
+ * nsac:111..104
+ * tran_speed:103..96
+ * ccc:95..84
+ * read_bl_len:83..80
+ * read_bl_partial:79
+ * write_blk_misalign:78
+ * read_blk_misalign:77
+ * dsr_imp:76
+ * rsvd2:75..74
+ * c_size:73..62 - crosses u32 boundary!
+ * vdd_r_curr_min:61..59
+ * vdd_r_curr_max:58..56
+ * vdd_w_curr_min:55..53
+ * vdd_w_curr_max:52..50
+ * c_size_mult:49..47
+ * sector_size:46..42
+ * erase_grp_size:41..37
+ * wp_grp_size:36..32
+ * wp_grp_enable:31
+ * default_ecc:30..29
+ * r2w_factor:28..26
+ * write_bl_len:25..22
+ * write_bl_partial:21
+ * rsvd3:20..16
+ * file_format_grp:15
+ * copy:14
+ * perm_write_protect:13
+ * tmp_write_protect:12
+ * file_format:11..10
+ * ecc:9..8
+ * crc:7..1
+ * one:0
+ */
+struct mmc_csd {
+       /* raw data */
+       u32 raw[4];
+       /* parsed values we need to read a card */
+       u8 taac;
+       u8 nsac;
+       u8 read_bl_len;
+       u8 read_bl_partial;
+       u32 c_size;
+       u8 c_size_mult;
+       u32 blocks;
+       u32 blocksize;
 };
 
 struct mmc_cmd {

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to