]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
AT91: MCI: add SD/MMC driver using mmc framework
authorReinhard Meyer <u-boot@emk-elektronik.de>
Fri, 13 Aug 2010 08:31:06 +0000 (10:31 +0200)
committerReinhard Meyer <u-boot@emk-elektronik.de>
Fri, 3 Sep 2010 09:19:01 +0000 (11:19 +0200)
Signed-off-by: Reinhard Meyer <u-boot@emk-elektronik.de>
arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c
arch/arm/include/asm/arch-at91/at91_common.h
arch/arm/include/asm/arch-at91/clk.h
arch/arm/include/asm/arch-at91/hardware.h
doc/README.atmel_mci [new file with mode: 0644]
drivers/mmc/Makefile
drivers/mmc/atmel_mci.h
drivers/mmc/gen_atmel_mci.c [new file with mode: 0644]
include/mmc.h

index 77d49ab1c762fb20ea0550e73801952d2ea8cc6a..2d8848152a49a8b9d6a589f99e943cd8a3d1238d 100644 (file)
@@ -194,3 +194,24 @@ void at91_macb_hw_init(void)
 #endif
 }
 #endif
 #endif
 }
 #endif
+
+#if defined(CONFIG_ATMEL_MCI) || defined(CONFIG_GENERIC_ATMEL_MCI)
+void at91_mci_hw_init(void)
+{
+       at91_set_a_periph(AT91_PIO_PORTA, 8, 1);        /* MCCK */
+#if defined(CONFIG_ATMEL_MCI_PORTB)
+       at91_set_b_periph(AT91_PIO_PORTA, 1, 1);        /* MCCDB */
+       at91_set_b_periph(AT91_PIO_PORTA, 0, 1);        /* MCDB0 */
+       at91_set_b_periph(AT91_PIO_PORTA, 5, 1);        /* MCDB1 */
+       at91_set_b_periph(AT91_PIO_PORTA, 4, 1);        /* MCDB2 */
+       at91_set_b_periph(AT91_PIO_PORTA, 3, 1);        /* MCDB3 */
+#else
+       at91_set_a_periph(AT91_PIO_PORTA, 7, 1);        /* MCCDA */
+       at91_set_a_periph(AT91_PIO_PORTA, 6, 1);        /* MCDA0 */
+       at91_set_a_periph(AT91_PIO_PORTA, 9, 1);        /* MCDA1 */
+       at91_set_a_periph(AT91_PIO_PORTA, 10, 1);       /* MCDA2 */
+       at91_set_a_periph(AT91_PIO_PORTA, 11, 1);       /* MCDA3 */
+#endif
+}
+#endif
+
index 01840eede41f94ed58d104301249a7b2a6ce02e1..0067190a20e9ca027ad3a82f2a70ecc166a5311b 100644 (file)
@@ -27,6 +27,7 @@
 
 void at91_can_hw_init(void);
 void at91_macb_hw_init(void);
 
 void at91_can_hw_init(void);
 void at91_macb_hw_init(void);
+void at91_mci_hw_init(void);
 void at91_serial_hw_init(void);
 void at91_serial0_hw_init(void);
 void at91_serial1_hw_init(void);
 void at91_serial_hw_init(void);
 void at91_serial0_hw_init(void);
 void at91_serial1_hw_init(void);
index f642dd99585f4248299c3d3ebfbbe41727d2a34f..457e6c9b2b57ed202a4b9634092d30c1f704f3ae 100644 (file)
@@ -59,5 +59,10 @@ static inline unsigned long get_twi_clk_rate(unsigned int dev_id)
        return get_mck_clk_rate();
 }
 
        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__ */
 int at91_clock_init(unsigned long main_clock);
 #endif /* __ASM_ARM_ARCH_CLK_H__ */
index 4ddb3155d7c45e9fc23fa86767d1676906ab7f69..9f732a738e2a4dfcbae3a73cbdadb7954ae8742f 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/arch-at91/at91rm9200.h>
 #elif defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9G20)
 #include <asm/arch/at91sam9260.h>
 #include <asm/arch-at91/at91rm9200.h>
 #elif defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9G20)
 #include <asm/arch/at91sam9260.h>
+#define AT91_BASE_MCI  AT91SAM9260_BASE_MCI
 #define AT91_BASE_SPI  AT91SAM9260_BASE_SPI0
 #define AT91_ID_UHP    AT91SAM9260_ID_UHP
 #define AT91_PMC_UHP   AT91SAM926x_PMC_UHP
 #define AT91_BASE_SPI  AT91SAM9260_BASE_SPI0
 #define AT91_ID_UHP    AT91SAM9260_ID_UHP
 #define AT91_PMC_UHP   AT91SAM926x_PMC_UHP
diff --git a/doc/README.atmel_mci b/doc/README.atmel_mci
new file mode 100644 (file)
index 0000000..18b1bdf
--- /dev/null
@@ -0,0 +1,86 @@
+How to use SD/MMC cards with Atmel SoCs having MCI hardware
+-----------------------------------------------------------
+2010-08-16 Reinhard Meyer <reinhard.meyer@emk-elektronik.de>
+
+This is a new approach to use Atmel MCI hardware with the
+general MMC framework. Therefore it benefits from that
+framework's abilities to handle SDHC Cards and the ability
+to write blocks.
+
+- 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 ATMEL devices that have MCI,
+including AVR32.
+
+The generic driver does NOT assign port pins to the MCI block
+nor does it start the MCI clock. This has to be handled in a
+board/SoC specific manner before the driver is initialized:
+
+example: this is added to at91sam9260_devices.c:
+
+#if defined(CONFIG_ATMEL_MCI) || defined(CONFIG_GENERIC_ATMEL_MCI)
+void at91_mci_hw_init(void)
+{
+       at91_set_a_periph(AT91_PIO_PORTA, 8, PUP);      /* MCCK */
+#if defined(CONFIG_ATMEL_MCI_PORTB)
+       at91_set_b_periph(AT91_PIO_PORTA, 1, PUP);      /* MCCDB */
+       at91_set_b_periph(AT91_PIO_PORTA, 0, PUP);      /* MCDB0 */
+       at91_set_b_periph(AT91_PIO_PORTA, 5, PUP);      /* MCDB1 */
+       at91_set_b_periph(AT91_PIO_PORTA, 4, PUP);      /* MCDB2 */
+       at91_set_b_periph(AT91_PIO_PORTA, 3, PUP);      /* MCDB3 */
+#else
+       at91_set_a_periph(AT91_PIO_PORTA, 7, PUP);      /* MCCDA */
+       at91_set_a_periph(AT91_PIO_PORTA, 6, PUP);      /* MCDA0 */
+       at91_set_a_periph(AT91_PIO_PORTA, 9, PUP);      /* MCDA1 */
+       at91_set_a_periph(AT91_PIO_PORTA, 10, PUP);     /* MCDA2 */
+       at91_set_a_periph(AT91_PIO_PORTA, 11, PUP);     /* MCDA3 */
+#endif
+}
+#endif
+
+the board specific file need added:
+...
+#ifdef CONFIG_GENERIC_ATMEL_MCI
+# include <mmc.h>
+#endif
+...
+#ifdef CONFIG_GENERIC_ATMEL_MCI
+/* this is a weak define that we are overriding */
+int board_mmc_init(bd_t *bd)
+{
+       /* Enable clock */
+       at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_MCI);
+       at91_mci_hw_init();
+
+       /* This calls the atmel_mci_init in gen_atmel_mci.c */
+       return atmel_mci_init((void *)AT91_BASE_MCI);
+}
+
+/* this is a weak define that we are overriding */
+int board_mmc_getcd(u8 *cd, struct mmc *mmc)
+{
+       /*
+        * the only currently existing use of this function
+        * (fsl_esdhc.c) suggests this function must return
+        * *cs = TRUE if a card is NOT detected -> in most
+        * cases the value of the pin when the detect switch
+        * closes to GND
+        */
+       *cd = at91_get_gpio_value (CONFIG_SYS_MMC_CD_PIN) ? 1 : 0;
+       return 0;
+}
+
+#endif
+
+and the board definition files needs:
+
+/* SD/MMC card */
+#define CONFIG_MMC                     1
+#define CONFIG_GENERIC_MMC             1
+#define CONFIG_GENERIC_ATMEL_MCI       1
+#define CONFIG_ATMEL_MCI_PORTB         1       /* Atmel XE-EK uses port B */
+#define CONFIG_SYS_MMC_CD_PIN          AT91_PIN_PC9
+#define CONFIG_CMD_MMC                 1
+
index 8dfd8a32ba63c8da34200de1d9cbb02d2c8bfaa3..6603d74294be073511758ae51249cda143af58c8 100644 (file)
@@ -25,12 +25,13 @@ include $(TOPDIR)/config.mk
 
 LIB    := $(obj)libmmc.a
 
 
 LIB    := $(obj)libmmc.a
 
-COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o
 COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
 COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o
 COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
-COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
+COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
+COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
 COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
 COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
+COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
 COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
 COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o
 
 COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
 COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o
 
index 5b4f5c99b6dea1c31a66419f479a21e2a22a3cab..823a77d91b3bc99ca2a2330483bf394956ab12ba 100644 (file)
 #ifndef __CPU_AT32AP_ATMEL_MCI_H__
 #define __CPU_AT32AP_ATMEL_MCI_H__
 
 #ifndef __CPU_AT32AP_ATMEL_MCI_H__
 #define __CPU_AT32AP_ATMEL_MCI_H__
 
-/* Atmel MultiMedia Card Interface (MCI) registers */
+#ifndef __ASSEMBLY__
+
+/*
+ * Structure for struct SoC access.
+ * Names starting with '_' are fillers.
+ */
+typedef struct atmel_mci {
+       /*      reg     Offset */
+       u32     cr;     /* 0x00 */
+       u32     mr;     /* 0x04 */
+       u32     dtor;   /* 0x08 */
+       u32     sdcr;   /* 0x0c */
+       u32     argr;   /* 0x10 */
+       u32     cmdr;   /* 0x14 */
+       u32     _18;    /* 0x18 */
+       u32     _1c;    /* 0x1c */
+       u32     rspr;   /* 0x20 */
+       u32     rspr1;  /* 0x24 */
+       u32     rspr2;  /* 0x28 */
+       u32     rspr3;  /* 0x2c */
+       u32     rdr;    /* 0x30 */
+       u32     tdr;    /* 0x34 */
+       u32     _38;    /* 0x38 */
+       u32     _3c;    /* 0x3c */
+       u32     sr;     /* 0x40 */
+       u32     ier;    /* 0x44 */
+       u32     idr;    /* 0x48 */
+       u32     imr;    /* 0x4c */
+} atmel_mci_t;
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * NOTICE: Use of registers offsets is depreciated.
+ * These defines will be removed once the old driver
+ * is taken out of commision.
+ *
+ * Atmel MultiMedia Card Interface (MCI) registers
+ */
 #define MMCI_CR                                        0x0000
 #define MMCI_MR                                        0x0004
 #define MMCI_DTOR                              0x0008
 #define MMCI_CR                                        0x0000
 #define MMCI_MR                                        0x0004
 #define MMCI_DTOR                              0x0008
                    << MMCI_##name##_OFFSET))           \
         | MMCI_BF(name,value))
 
                    << MMCI_##name##_OFFSET))           \
         | MMCI_BF(name,value))
 
-/* Register access macros */
+/*
+ * NOTICE: Use of registers offsets is depreciated.
+ * These defines will be removed once the old driver
+ * is taken out of commision.
+ *
+ * Register access macros
+ */
 #define mmci_readl(reg)                                        \
        readl((void *)MMCI_BASE + MMCI_##reg)
 #define mmci_writel(reg,value)                         \
 #define mmci_readl(reg)                                        \
        readl((void *)MMCI_BASE + MMCI_##reg)
 #define mmci_writel(reg,value)                         \
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
new file mode 100644 (file)
index 0000000..fa4df99
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2010
+ * Rob Emanuele <rob@emanuele.us>
+ * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
+ *
+ * Original Driver:
+ * 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
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/memory-map.h>
+#include "atmel_mci.h"
+
+#ifndef CONFIG_SYS_MMC_CLK_OD
+# define CONFIG_SYS_MMC_CLK_OD 150000
+#endif
+
+#define MMC_DEFAULT_BLKLEN     512
+
+#if defined(CONFIG_ATMEL_MCI_PORTB)
+# define MCI_BUS 1
+#else
+# define MCI_BUS 0
+#endif
+
+static int initialized = 0;
+
+/*
+ * Print command and status:
+ *
+ * - always when DEBUG is defined
+ * - on command errors
+ */
+static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
+{
+       printf("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
+               cmdr, cmdr&0x3F, arg, status, msg);
+}
+
+/* Setup for MCI Clock and Block Size */
+static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
+{
+       atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+       u32 bus_hz = get_mci_clk_rate();
+       u32 clkdiv = 255;
+
+       debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
+               bus_hz, hz, blklen);
+       if (hz > 0) {
+               /* find lowest clkdiv yielding a rate <= than requested */
+               for (clkdiv=0; clkdiv<255; clkdiv++) {
+                       if ((bus_hz / (clkdiv+1) / 2) <= hz)
+                               break;
+               }
+       }
+       printf("mci: setting clock %u Hz, block size %u\n",
+               (bus_hz / (clkdiv+1)) / 2, blklen);
+
+       blklen &= 0xfffc;
+       /* On some platforms RDPROOF and WRPROOF are ignored */
+       writel((MMCI_BF(CLKDIV, clkdiv)
+                | MMCI_BF(BLKLEN, blklen)
+                | MMCI_BIT(RDPROOF)
+                | MMCI_BIT(WRPROOF)), &mci->mr);
+       initialized = 1;
+}
+
+/* Return the CMDR with flags for a given command and data packet */
+static u32 mci_encode_cmd(
+       struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
+{
+       u32 cmdr = 0;
+
+       /* Default Flags for Errors */
+       *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
+               MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
+
+       /* Default Flags for the Command */
+       cmdr |= MMCI_BIT(MAXLAT);
+
+       if (data) {
+               cmdr |= MMCI_BF(TRCMD, 1);
+               if (data->blocks > 1)
+                       cmdr |= MMCI_BF(TRTYP, 1);
+               if (data->flags & MMC_DATA_READ)
+                       cmdr |= MMCI_BIT(TRDIR);
+       }
+
+       if (cmd->resp_type & MMC_RSP_CRC)
+               *error_flags |= MMCI_BIT(RCRCE);
+       if (cmd->resp_type & MMC_RSP_136)
+               cmdr |= MMCI_BF(RSPTYP, 2);
+       else if (cmd->resp_type & MMC_RSP_BUSY)
+               cmdr |= MMCI_BF(RSPTYP, 3);
+       else if (cmd->resp_type & MMC_RSP_PRESENT)
+               cmdr |= MMCI_BF(RSPTYP, 1);
+
+       return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
+}
+
+/* Entered into function pointer in mci_send_cmd */
+static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
+{
+       u32 status;
+
+       do {
+               status = readl(&mci->sr);
+               if (status & (error_flags | MMCI_BIT(OVRE)))
+                       goto io_fail;
+       } while (!(status & MMCI_BIT(RXRDY)));
+
+       if (status & MMCI_BIT(RXRDY)) {
+               *data = readl(&mci->rdr);
+               status = 0;
+       }
+io_fail:
+       return status;
+}
+
+/* Entered into function pointer in mci_send_cmd */
+static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
+{
+       u32 status;
+
+       do {
+               status = readl(&mci->sr);
+               if (status & (error_flags | MMCI_BIT(UNRE)))
+                       goto io_fail;
+       } while (!(status & MMCI_BIT(TXRDY)));
+
+       if (status & MMCI_BIT(TXRDY)) {
+               writel(*data, &mci->tdr);
+               status = 0;
+       }
+io_fail:
+       return status;
+}
+
+/*
+ * Entered into mmc structure during driver init
+ *
+ * Sends a command out on the bus and deals with the block data.
+ * Takes the mmc pointer, a command pointer, and an optional data pointer.
+ */
+static int
+mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+       atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+       u32 cmdr;
+       u32 error_flags = 0;
+       u32 status;
+
+       if (!initialized) {
+               puts ("MCI not initialized!\n");
+               return COMM_ERR;
+       }
+
+       /* Figure out the transfer arguments */
+       cmdr = mci_encode_cmd(cmd, data, &error_flags);
+
+       /* Send the command */
+       writel(cmd->cmdarg, &mci->argr);
+       writel(cmdr, &mci->cmdr);
+
+#ifdef DEBUG
+       dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
+#endif
+
+       /* Wait for the command to complete */
+       while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
+
+       if (status & error_flags) {
+               dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
+               return COMM_ERR;
+       }
+
+       /* Copy the response to the response buffer */
+       if (cmd->resp_type & MMC_RSP_136) {
+               cmd->response[0] = readl(&mci->rspr);
+               cmd->response[1] = readl(&mci->rspr1);
+               cmd->response[2] = readl(&mci->rspr2);
+               cmd->response[3] = readl(&mci->rspr3);
+       } else
+               cmd->response[0] = readl(&mci->rspr);
+
+       /* transfer all of the blocks */
+       if (data) {
+               u32 word_count, block_count;
+               u32* ioptr;
+               u32 sys_blocksize, dummy, i;
+               u32 (*mci_data_op)
+                       (atmel_mci_t *mci, u32* data, u32 error_flags);
+
+               if (data->flags & MMC_DATA_READ) {
+                       mci_data_op = mci_data_read;
+                       sys_blocksize = mmc->read_bl_len;
+                       ioptr = (u32*)data->dest;
+               } else {
+                       mci_data_op = mci_data_write;
+                       sys_blocksize = mmc->write_bl_len;
+                       ioptr = (u32*)data->src;
+               }
+
+               status = 0;
+               for (block_count = 0;
+                               block_count < data->blocks && !status;
+                               block_count++) {
+                       word_count = 0;
+                       do {
+                               status = mci_data_op(mci, ioptr, error_flags);
+                               word_count++;
+                               ioptr++;
+                       } while (!status && word_count < (data->blocksize/4));
+#ifdef DEBUG
+                       if (data->flags & MMC_DATA_READ)
+                       {
+                               printf("Read Data:\n");
+                               print_buffer(0, data->dest, 1,
+                                       word_count*4, 0);
+                       }
+#endif
+#ifdef DEBUG
+                       if (!status && word_count < (sys_blocksize / 4))
+                               printf("filling rest of block...\n");
+#endif
+                       /* fill the rest of a full block */
+                       while (!status && word_count < (sys_blocksize / 4)) {
+                               status = mci_data_op(mci, &dummy,
+                                       error_flags);
+                               word_count++;
+                       }
+                       if (status) {
+                               dump_cmd(cmdr, cmd->cmdarg, status,
+                                       "Data Transfer Failed");
+                               return COMM_ERR;
+                       }
+               }
+
+               /* Wait for Transfer End */
+               i = 0;
+               do {
+                       status = readl(&mci->sr);
+
+                       if (status & error_flags) {
+                               dump_cmd(cmdr, cmd->cmdarg, status,
+                                       "DTIP Wait Failed");
+                               return COMM_ERR;
+                       }
+                       i++;
+               } while ((status & MMCI_BIT(DTIP)) && i < 10000);
+               if (status & MMCI_BIT(DTIP)) {
+                       dump_cmd(cmdr, cmd->cmdarg, status,
+                               "XFER DTIP never unset, ignoring");
+               }
+       }
+
+       return 0;
+}
+
+/* Entered into mmc structure during driver init */
+static void mci_set_ios(struct mmc *mmc)
+{
+       atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+       int busw = (mmc->bus_width == 4) ? 1 : 0;
+
+       /* Set the clock speed */
+       mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
+
+       /*
+        * set the bus width and select slot for this interface
+        * there is no capability for multiple slots on the same interface yet
+        * Bitfield SCDBUS needs to be expanded to 2 bits for 8-bit buses
+        */
+       writel(MMCI_BF(SCDBUS, busw) | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
+}
+
+/* Entered into mmc structure during driver init */
+static int mci_init(struct mmc *mmc)
+{
+       atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+
+       /* Initialize controller */
+       writel(MMCI_BIT(SWRST), &mci->cr);      /* soft reset */
+       writel(MMCI_BIT(PWSDIS), &mci->cr);     /* disable power save */
+       writel(MMCI_BIT(MCIEN), &mci->cr);      /* enable mci */
+
+       /* Initial Time-outs */
+       writel(0x5f, &mci->dtor);
+       /* Disable Interrupts */
+       writel(~0UL, &mci->idr);
+
+       /* Set default clocks and blocklen */
+       mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+
+       return 0;
+}
+
+/*
+ * This is the only exported function
+ *
+ * Call it with the MCI register base address
+ */
+int atmel_mci_init(void *regs)
+{
+       struct mmc *mmc = malloc(sizeof(struct mmc));
+
+       if (!mmc)
+               return -1;
+       strcpy(mmc->name, "mci");
+       mmc->priv = regs;
+       mmc->send_cmd = mci_send_cmd;
+       mmc->set_ios = mci_set_ios;
+       mmc->init = mci_init;
+
+       /* need to be able to pass these in on a board by board basis */
+       mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+       mmc->host_caps = MMC_MODE_4BIT;
+       /*
+        * min and max frequencies determined by
+        * max and min of clock divider
+        */
+       mmc->f_min = get_mci_clk_rate() / (2*256);
+       mmc->f_max = get_mci_clk_rate() / (2*1);
+
+       mmc_register(mmc);
+
+       return 0;
+}
index fcb237e81e4788c03408ceeb7d1fc94fcfc9b006..9f94f423fbf55a4536c0e736409e43ecc38cbd68 100644 (file)
@@ -179,6 +179,16 @@ struct mmc_cid {
        char pnm[7];
 };
 
        char pnm[7];
 };
 
+/*
+ * WARNING!
+ *
+ * This structure is used by atmel_mci.c only.
+ * It works for the AVR32 architecture but NOT
+ * for ARM/AT91 architectures.
+ * Its use is highly depreciated.
+ * After the atmel_mci.c driver for AVR32 has
+ * been replaced this structure will be removed.
+ */
 struct mmc_csd
 {
        u8      csd_structure:2,
 struct mmc_csd
 {
        u8      csd_structure:2,
@@ -275,7 +285,10 @@ int mmc_set_dev(int dev_num);
 void print_mmc_devices(char separator);
 int board_mmc_getcd(u8 *cd, struct mmc *mmc);
 
 void print_mmc_devices(char separator);
 int board_mmc_getcd(u8 *cd, struct mmc *mmc);
 
-#ifndef CONFIG_GENERIC_MMC
+#ifdef CONFIG_GENERIC_MMC
+int atmel_mci_init(void *regs);
+#else
 int mmc_legacy_init(int verbose);
 #endif
 int mmc_legacy_init(int verbose);
 #endif
+
 #endif /* _MMC_H_ */
 #endif /* _MMC_H_ */