diff mbox

[U-Boot,3/4] Armada100: SD/MMC support for Marvell gplugD

Message ID 1310106168-17166-3-git-send-email-ajay.bhargav@einfochips.com
State Changes Requested
Headers show

Commit Message

Ajay Bhargav July 8, 2011, 6:22 a.m. UTC
This patch provide support for MMC on GuruPlug-Display in uboot.

Signed-off-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
---
 arch/arm/include/asm/arch-armada100/cpu.h |    4 +
 arch/arm/include/asm/arch-armada100/mfp.h |   17 +
 board/Marvell/gplugd/gplugd.c             |   26 ++
 drivers/mmc/Makefile                      |    1 +
 drivers/mmc/pxa_sdh.c                     |  677 +++++++++++++++++++++++++++++
 drivers/mmc/pxa_sdh.h                     |  241 ++++++++++
 include/configs/gplugd.h                  |   15 +
 7 files changed, 981 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/pxa_sdh.c
 create mode 100644 drivers/mmc/pxa_sdh.h

Comments

Wolfgang Denk July 8, 2011, 8:03 a.m. UTC | #1
Dear Ajay Bhargav,

In message <1310106168-17166-3-git-send-email-ajay.bhargav@einfochips.com> you wrote:
> This patch provide support for MMC on GuruPlug-Display in uboot.

> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index a8fe17a..7f88031 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
>  COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
>  COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
>  COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o
> +COBJS-$(CONFIG_PXASDH) += pxa_sdh.o

Please keep list sorted.

> --- /dev/null
> +++ b/drivers/mmc/pxa_sdh.c
> @@ -0,0 +1,677 @@
> +/**************************************************************************
> + *
> + * Copyright (c) 2009, 2010 Marvell International Ltd.

Incorrect multi-line comment style. etc. etc.

...
> +#define CLKRT_OFF			(~0)
> +#define GET_REG(host, reg)		readw(host->regbase + reg)
> +#define SET_REG(host, val, reg)		writew(val, host->regbase + reg)
> +#define DATA_DIRECTION_READ(data)	(data->flags & MMC_DATA_READ)
> +#define SET_REG_BIT(host, bit_mask, reg) \
> +		SET_REG(host, \
> +			GET_REG(host, reg) | (bit_mask), reg)
> +#define CLEAR_REG_BIT(host, bit_mask, reg) \
> +		SET_REG(host, \
> +			GET_REG(host, reg) & ~(bit_mask), reg)
> +#define SET_REG_BITS(host, bits_pos, bits_mask, val, reg) \
> +		{SET_REG(host, \
> +			GET_REG(host, reg) & ~(bits_mask << bits_pos), reg); \
> +		SET_REG(host, \
> +			GET_REG(host, reg) | (val << bits_pos), reg); }
> +#define GET_REG_BITS(host, bit_pos, bits_mask, reg) \
> +		((GET_REG(host, reg) >> bit_pos) & bits_mask)

NAK.  Please don't invent your own accessors, instead use the existing
ones.  Also, make sure to use proper C structs instead of base address
+ offset notation.


> +static void pxa_sdh_finish_request(struct pxa_sdh_host *host)
> +{
> +
> +#ifdef CONFIG_MMC_DEBUG

Drop that blank line above (and all similar ones).

...
> +		do {
> +			ret = pxa_sdh_process_irq(host, (DMA_INT | XFER_COMP));
> +			/* If error or xfer completed (in which case
> +			 * bytes_xfered is reset to 0) break */

Incorrect multiline-comment ...

> +static int pxa_sdh_cmd_done(struct pxa_sdh_host *host)
> +{
> +	struct mmc_cmd *cmd = host->cmd;
> +	u32 resp[8];
> +
> +	BUG_ON(!cmd);
> +
> +	/* get cmd response */
> +	resp[0] = GET_REG(host, SD_RESP_0);
> +	resp[1] = GET_REG(host, SD_RESP_1);
> +	resp[2] = GET_REG(host, SD_RESP_2);
> +	resp[3] = GET_REG(host, SD_RESP_3);
> +	resp[4] = GET_REG(host, SD_RESP_4);
> +	resp[5] = GET_REG(host, SD_RESP_5);
> +	resp[6] = GET_REG(host, SD_RESP_6);
> +	resp[7] = readb(host->regbase + SD_RESP_7);
> +

NAK - see above, please use proper I/O accessors.

...
> +		char *src = (char *) data->src + host->bytes_xfered;
> +		for (i = 0; i < blk_size; i += sizeof(u32))
> +			writel(*(u32 *)(src +  i),
> +				host->regbase + SD_BUF_DPORT_0);

Braces needed for multiline statement.

> +	if (host->bytes_xfered < host->data_len) {
> +		host_dma_bdry_size = 0x1000 << (((u16) GET_REG(host,
> +				SD_BLOCK_SIZE)) >> HOST_DMA_BDRY_OFFSET);
> +		if (host_dma_bdry_size < data->blocksize)
> +			host->bytes_xfered = host->bytes_xfered +
> +							host_dma_bdry_size;

Braces needed for multiline statement.

> +		else
> +			host->bytes_xfered = host->bytes_xfered +
> +							data->blocksize;

Braces needed for multiline statement. Please fix globally.


> +	switch (host->port_num) {
> +	case 0:
> +		/* Setup the MMC/SD(1) Host Controller Clock */
> +		writel(0x19, 0xd4282854);
> +		udelay(10);
> +		writel(0x1B, 0xd4282854);
> +		break;
> +	case 1:
> +		/* Setup the MMC/SD(2) Host Controller Clock */
> +		writel(0x10, 0xd4282858);
> +		udelay(10);
> +		writel(0x12, 0xd4282858);
> +		break;
> +	case 2:
> +		/* Setup the MMC/SD(3) Host Controller Clock */
> +		writel(0x19, 0xd42828e0);
> +		udelay(10);
> +		writel(0x1b, 0xd42828e0);
> +		break;
> +	case 3:
> +		/* Setup the MMC/SD(4) Host Controller Clock */
> +		writel(0x10, 0xd42828e4);
> +		udelay(10);
> +		writel(0x12, 0xd42828e4);
> +		break;

Please provide symbolic constants / definitions for these (and
similar) magic numbers.

...
> --- /dev/null
> +++ b/drivers/mmc/pxa_sdh.h
> @@ -0,0 +1,241 @@
...
> +/* register definitions of PXA SD Host Controller*/
> +#define SD_SYS_ADDR_LOW		0x0000	/* DMA System Address Low */
> +#define SD_SYS_ADDR_HIGH	0x0002	/* DMA System Address High */
> +#define SD_BLOCK_SIZE		0x0004	/* Block Size*/
...

NAK.   Please use a C struct instead.

...
> +#define HOST_DMA_BDRY_MASK	((u16)0x7)
> +#define BLOCK_SIZE_OFFSET	0
> +#define BLOCK_SIZE_MASK		((u16)0x0fff)
> +#define BLOCK_SIZE_MAX		((u16)0x0800)

Please drop all these casts (and get rid of the parens).

Best regards,

Wolfgang Denk
Lei Wen July 8, 2011, 8:45 a.m. UTC | #2
NAK for this patch, the mv_sdhci.c with the generic sdhci.c framework
is intend to support armada100.

Best regards,
Lei

On Fri, Jul 8, 2011 at 2:22 PM, Ajay Bhargav
<ajay.bhargav@einfochips.com> wrote:
> This patch provide support for MMC on GuruPlug-Display in uboot.
>
> Signed-off-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
> ---
>  arch/arm/include/asm/arch-armada100/cpu.h |    4 +
>  arch/arm/include/asm/arch-armada100/mfp.h |   17 +
>  board/Marvell/gplugd/gplugd.c             |   26 ++
>  drivers/mmc/Makefile                      |    1 +
>  drivers/mmc/pxa_sdh.c                     |  677 +++++++++++++++++++++++++++++
>  drivers/mmc/pxa_sdh.h                     |  241 ++++++++++
>  include/configs/gplugd.h                  |   15 +
>  7 files changed, 981 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mmc/pxa_sdh.c
>  create mode 100644 drivers/mmc/pxa_sdh.h
>
> diff --git a/arch/arm/include/asm/arch-armada100/cpu.h b/arch/arm/include/asm/arch-armada100/cpu.h
> index 0518a6a..6ab3bf9 100644
> --- a/arch/arm/include/asm/arch-armada100/cpu.h
> +++ b/arch/arm/include/asm/arch-armada100/cpu.h
> @@ -50,4 +50,8 @@ struct armd1cpu_registers {
>  u32 armd1_sdram_base(int);
>  u32 armd1_sdram_size(int);
>
> +#ifdef CONFIG_PXASDH
> +int pxa_sdh_init(bd_t *);
> +#endif
> +
>  #endif /* _ARMADA100CPU_H */
> diff --git a/arch/arm/include/asm/arch-armada100/mfp.h b/arch/arm/include/asm/arch-armada100/mfp.h
> index e94be3a..1d897ae 100644
> --- a/arch/arm/include/asm/arch-armada100/mfp.h
> +++ b/arch/arm/include/asm/arch-armada100/mfp.h
> @@ -89,6 +89,23 @@
>  #define MFP110_SSP2_CS          (MFP_REG(0x1B8) | MFP_AF0 | MFP_DRIVE_MEDIUM)
>  #define MFP111_SSP2_CLK         (MFP_REG(0x1BC) | MFP_AF4 | MFP_DRIVE_MEDIUM)
>
> +/* MMC1 */
> +#define MFP040_MMC1_D1         (MFP_REG(0x00C) | MFP_AF1 | MFP_DRIVE_MEDIUM)
> +#define MFP041_MMC1_D0         (MFP_REG(0x010) | MFP_AF1 | MFP_DRIVE_MEDIUM)
> +#define MFP043_MMC1_CLK                (MFP_REG(0x018) | MFP_AF1 | MFP_DRIVE_MEDIUM)
> +#define MFP049_MMC1_CMD                (MFP_REG(0x030) | MFP_AF1 | MFP_DRIVE_MEDIUM)
> +#define MFP051_MMC1_D3         (MFP_REG(0x038) | MFP_AF1 | MFP_DRIVE_MEDIUM)
> +#define MFP052_MMC1_D2         (MFP_REG(0x03C) | MFP_AF1 | MFP_DRIVE_MEDIUM)
> +#define MFP053_MMC1_CD         (MFP_REG(0x040) | MFP_AF1 | MFP_DRIVE_MEDIUM)
> +
> +/* MMC2 */
> +#define MFP028_MMC2_CMD                (MFP_REG(0x0BC) | MFP_AF6 | MFP_DRIVE_MEDIUM)
> +#define MFP029_MMC2_CLK                (MFP_REG(0x0C0) | MFP_AF6 | MFP_DRIVE_MEDIUM)
> +#define MFP030_MMC2_D0         (MFP_REG(0x0C4) | MFP_AF6 | MFP_DRIVE_MEDIUM)
> +#define MFP031_MMC2_D1         (MFP_REG(0x0C8) | MFP_AF6 | MFP_DRIVE_MEDIUM)
> +#define MFP032_MMC2_D2         (MFP_REG(0x0CC) | MFP_AF6 | MFP_DRIVE_MEDIUM)
> +#define MFP033_MMC2_D3         (MFP_REG(0x0D0) | MFP_AF6 | MFP_DRIVE_MEDIUM)
> +
>  /* More macros can be defined here... */
>
>  #define MFP_PIN_MAX    117
> diff --git a/board/Marvell/gplugd/gplugd.c b/board/Marvell/gplugd/gplugd.c
> index 0c7a8fd..7eacd63 100644
> --- a/board/Marvell/gplugd/gplugd.c
> +++ b/board/Marvell/gplugd/gplugd.c
> @@ -31,6 +31,7 @@
>  #include <common.h>
>  #include <mvmfp.h>
>  #include <asm/arch/mfp.h>
> +#include <asm/arch/cpu.h>
>  #include <asm/arch/armada100.h>
>  #include <asm/arch/gpio.h>
>  #include <miiphy.h>
> @@ -81,11 +82,29 @@ int board_early_init_f(void)
>                MFP101_ETH_MDIO,
>                MFP103_ETH_RXDV,
>
> +               /* SPI Flash interface */
>                MFP107_SSP2_RXD,
>                MFP108_SSP2_TXD,
>                MFP110_SSP2_CS,
>                MFP111_SSP2_CLK,
>
> +               /* MMC1 */
> +               MFP040_MMC1_D1,
> +               MFP041_MMC1_D0,
> +               MFP043_MMC1_CLK,
> +               MFP049_MMC1_CMD,
> +               MFP051_MMC1_D3,
> +               MFP052_MMC1_D2,
> +               MFP053_MMC1_CD,
> +
> +               /* MMC2 */
> +               MFP028_MMC2_CMD,
> +               MFP029_MMC2_CLK,
> +               MFP030_MMC2_D0,
> +               MFP031_MMC2_D1,
> +               MFP032_MMC2_D2,
> +               MFP033_MMC2_D3,
> +
>                MFP_EOC         /*End of configuration*/
>        };
>        /* configure MFP's */
> @@ -121,6 +140,13 @@ int board_init(void)
>        return 0;
>  }
>
> +#ifdef CONFIG_PXASDH
> +int board_mmc_init(bd_t *bd)
> +{
> +       return pxa_sdh_init(bd);
> +}
> +#endif
> +
>  #ifdef CONFIG_PXA_ETH
>  int board_eth_init(bd_t *bis)
>  {
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index a8fe17a..7f88031 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
>  COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
>  COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
>  COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o
> +COBJS-$(CONFIG_PXASDH) += pxa_sdh.o
>
>  COBJS  := $(COBJS-y)
>  SRCS   := $(COBJS:.o=.c)
> diff --git a/drivers/mmc/pxa_sdh.c b/drivers/mmc/pxa_sdh.c
> new file mode 100644
> index 0000000..0198af3
> --- /dev/null
> +++ b/drivers/mmc/pxa_sdh.c
> @@ -0,0 +1,677 @@
> +/**************************************************************************
> + *
> + * Copyright (c) 2009, 2010 Marvell International Ltd.
> + *
> + * This file is part of GNU program.
> + *
> + * GNU 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.
> + *
> + * GNU 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, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
> + *
> + *************************************************************************/
> +
> +/*
> + * Copyright (C) Marvell International Ltd. (kvedere@marvell.com)
> + * Code heavily based on Linux driver
> + *     /driver/mmc/host/pxa_sdh.c
> + * Copyright (C) 2008-2009 Marvell International Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <common.h>
> +#include <part.h>
> +#include <malloc.h>
> +#include <mmc.h>
> +#include <asm/io.h>
> +#include <asm/errno.h>
> +#include <linux/mtd/compat.h>
> +
> +#include "pxa_sdh.h"
> +
> +#define CLKRT_OFF                      (~0)
> +#define GET_REG(host, reg)             readw(host->regbase + reg)
> +#define SET_REG(host, val, reg)                writew(val, host->regbase + reg)
> +#define DATA_DIRECTION_READ(data)      (data->flags & MMC_DATA_READ)
> +#define SET_REG_BIT(host, bit_mask, reg) \
> +               SET_REG(host, \
> +                       GET_REG(host, reg) | (bit_mask), reg)
> +#define CLEAR_REG_BIT(host, bit_mask, reg) \
> +               SET_REG(host, \
> +                       GET_REG(host, reg) & ~(bit_mask), reg)
> +#define SET_REG_BITS(host, bits_pos, bits_mask, val, reg) \
> +               {SET_REG(host, \
> +                       GET_REG(host, reg) & ~(bits_mask << bits_pos), reg); \
> +               SET_REG(host, \
> +                       GET_REG(host, reg) | (val << bits_pos), reg); }
> +#define GET_REG_BITS(host, bit_pos, bits_mask, reg) \
> +               ((GET_REG(host, reg) >> bit_pos) & bits_mask)
> +#define mmc_resp_type(cmd) ((cmd)->resp_type & (MMC_RSP_PRESENT|MMC_RSP_136| \
> +                               MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
> +
> +#define MMC_BUS_WIDTH_1                1
> +#define MMC_BUS_WIDTH_4                4
> +#define MMC_BUS_WIDTH_8                8
> +#define CONFIG_MMC_SDMA                1
> +
> +/* #define CONFIG_MMC_DEBUG    1 */
> +
> +#ifdef CONFIG_MMC_DEBUG
> +#define mmc_dbg printf
> +#else
> +#define mmc_dbg(arg...)
> +#endif
> +
> +struct pxa_sdh_host {
> +       struct mmc_cmd  *cmd;
> +       struct mmc_data *data;
> +       u32             regbase;
> +       u32             bytes_xfered;
> +       u32             clkrate;
> +       u32             clkrt;
> +       u32             data_len;
> +       int             error;
> +       int             port_num;
> +};
> +
> +static int pxa_sdh_cmd_done(struct pxa_sdh_host *host);
> +static void pxa_sdh_dma_data_done(struct pxa_sdh_host *host);
> +static void pxa_sdh_data_done(struct pxa_sdh_host *host);
> +
> +#ifdef CONFIG_MMC_DEBUG
> +static void dump_registers(struct pxa_sdh_host *host)
> +{
> +       unsigned int val;
> +       int offset;
> +
> +       for (offset = 0; offset < 0x60; offset += 4) {
> +               if (offset == 0x20)
> +                       continue;
> +               val = readl(host->regbase + offset);
> +               printf("%08x: %08x\n",
> +                       (unsigned int)host->regbase + offset, val);
> +       }
> +       for (offset = 0xE0; offset < 0xF0; offset += 4) {
> +               val = readl(host->regbase + offset);
> +               printf("%08x: %08x\n",
> +                       (unsigned int)host->regbase + offset, val);
> +       }
> +       val = readl(host->regbase + 0xFC);
> +       printf("%08x: %08x\n", (unsigned int)host->regbase + 0xFC, val);
> +}
> +#endif
> +
> +/*static inline int fls(int x)
> +{
> +       int ret;
> +
> +       asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
> +       ret = 32 - ret;
> +       return ret;
> +}*/
> +
> +static int pxa_sdh_wait_reset(struct pxa_sdh_host *host)
> +{
> +       u32 timeout = 1000;
> +       u16 val;
> +
> +       do {
> +               val = GET_REG(host, SD_TO_CTRL_SW_RST);
> +               if (!(val & (SW_RST_DAT | SW_RST_CMD | SW_RST_ALL)))
> +                       break;
> +               udelay(1);
> +       } while (timeout--);
> +       if (timeout)
> +               return 0;
> +
> +       printf("%s: Fatal: Wait RESET timeout.\n", __func__);
> +
> +       return 1;
> +}
> +
> +static void pxa_sdh_stop_clock(struct pxa_sdh_host *host)
> +{
> +       CLEAR_REG_BIT(host, EXT_CLK_EN, SD_CLOCK_CNTL);
> +}
> +
> +static void pxa_sdh_start_clock(struct pxa_sdh_host *host)
> +{
> +       u32 timeout = 1000;
> +
> +       SET_REG_BIT(host, INT_CLK_EN, SD_CLOCK_CNTL);
> +       do {
> +               if (GET_REG(host, SD_CLOCK_CNTL) & INT_CLK_STABLE)
> +                       break;
> +               udelay(1);
> +       } while (timeout--);
> +       if (!timeout)
> +               printf("%s: unable to start clock\n", __func__);
> +
> +       SET_REG_BITS(host, SD_FREQ_SEL_OFFSET, SD_FREQ_SEL_MASK,
> +               host->clkrt, SD_CLOCK_CNTL);
> +
> +       /* set as maximum value for data line timeout*/
> +       SET_REG_BITS(host, DAT_TO_VAL_OFFSET, DAT_TO_MASK,
> +               (DAT_TO_MASK - 1), SD_TO_CTRL_SW_RST);
> +
> +       SET_REG_BIT(host, EXT_CLK_EN, SD_CLOCK_CNTL);
> +}
> +
> +static void pxa_sdh_setup_sdma(struct pxa_sdh_host *host)
> +{
> +       struct mmc_data *data = host->data;
> +       if (DATA_DIRECTION_READ(data)) {
> +               char *dest = data->dest + host->bytes_xfered;
> +               SET_REG(host, (u32) dest & 0xffff, SD_SYS_ADDR_LOW);
> +               SET_REG(host, (u32) dest >> 16, SD_SYS_ADDR_HIGH);
> +       } else {
> +               char *src = (char *) data->src + host->bytes_xfered;
> +               SET_REG(host, (u32) src & 0xffff, SD_SYS_ADDR_LOW);
> +               SET_REG(host, (u32) src >> 16, SD_SYS_ADDR_HIGH);
> +       }
> +
> +}
> +
> +static void pxa_sdh_setup_data(struct pxa_sdh_host *host)
> +{
> +#ifdef CONFIG_MMC_SDMA
> +       pxa_sdh_setup_sdma(host);
> +       SET_REG_BITS(host, DMA_SEL_OFFSET, DMA_SEL_MASK,
> +                               DMA_SEL_SDMA, SD_HOST_CTRL);
> +#endif
> +}
> +
> +static void pxa_sdh_finish_request(struct pxa_sdh_host *host)
> +{
> +
> +#ifdef CONFIG_MMC_DEBUG
> +       struct mmc_cmd *cmd = host->cmd;
> +       dump_registers(host);
> +#endif
> +       if (host->data && host->error)
> +               SET_REG_BIT(host, SW_RST_DAT, SD_TO_CTRL_SW_RST);
> +
> +       mmc_dbg("%s: Finishing CMD%d(%s)\n", __func__, cmd->cmdidx,
> +               (host->error ? "failed" : "done"));
> +
> +       host->data = NULL;
> +       host->cmd = NULL;
> +       host->error = 0;
> +       host->data_len = 0;
> +       host->bytes_xfered = 0;
> +}
> +
> +static int pxa_sdh_process_irq(struct pxa_sdh_host *host, u32 intr_type)
> +{
> +       ulong hz = 3250000; /* 3.25 MHz Timer Clock */
> +       ushort done = GET_REG(host, SD_NOR_I_STAT) & intr_type;
> +       ulong start, curr, diff;
> +#ifdef CONFIG_MMC_DEBUG
> +       struct mmc_cmd *cmd = host->cmd;
> +#endif
> +
> +       start = get_timer(0);
> +       while (!done) {
> +               done = GET_REG(host, SD_NOR_I_STAT) & intr_type;
> +               if (GET_REG(host, SD_NOR_I_STAT) & 0x8000) {
> +                       mmc_dbg("Error! cmd : %d, err : %04x\n",
> +                               cmd->cmdidx, GET_REG(host, SD_ERR_I_STAT));
> +                       host->error = 1;
> +                       pxa_sdh_finish_request(host);
> +                       if (GET_REG(host, SD_ERR_I_STAT) & 0x1)
> +                               return TIMEOUT;      /* error happened */
> +                       else
> +                               return COMM_ERR;
> +               }
> +               curr = get_timer(0);
> +               diff = (long) curr - (long) start;
> +               if (diff > (3*hz)) {
> +                       printf("cmd timeout, status : %04x\n",
> +                                       GET_REG(host, SD_NOR_I_STAT));
> +                       printf("xfer mode : %04x\n",
> +                                       GET_REG(host, SD_TRANS_MODE));
> +                       host->error = 1;
> +                       pxa_sdh_finish_request(host);
> +                       return -ETIMEDOUT;
> +               }
> +       }
> +
> +       if (intr_type & CMD_COMP)
> +               pxa_sdh_cmd_done(host);
> +
> +#ifdef CONFIG_MMC_SDMA
> +       if (intr_type & DMA_INT)
> +               pxa_sdh_dma_data_done(host);
> +#else
> +       if ((cmdtype & TX_RDY) || (cmdtype & RX_RDY))
> +               pxa_sdh_pio_data_done(host);
> +#endif
> +
> +       if (intr_type & XFER_COMP)
> +               pxa_sdh_data_done(host);
> +
> +       /* Clear Status Bits */
> +       SET_REG(host, intr_type, SD_NOR_I_STAT);
> +       return 0;
> +}
> +
> +static int pxa_sdh_start_cmd(struct pxa_sdh_host *host)
> +{
> +       u16 resp = 0;
> +       u16 xfrmd_val = 0;
> +       u16 cmd_val = 0;
> +       u16 val, mask;
> +       struct mmc_data *data = host->data;
> +       struct mmc_cmd *cmd = host->cmd;
> +       int ret;
> +
> +       BUG_ON(!cmd);
> +
> +       /*Set Response Type*/
> +       switch (mmc_resp_type(cmd)) {
> +       case MMC_RSP_NONE:
> +               break;
> +
> +       case MMC_RSP_R1: /* r1, r5, r6, r7 */
> +               resp = CMD_RESP_48BIT;
> +               cmd_val |= CMD_CRC_CHK_EN | CMD_IDX_CHK_EN;
> +               break;
> +
> +       case MMC_RSP_R2: /* r2 */
> +               resp = CMD_RESP_136BIT;
> +               cmd_val |= CMD_CRC_CHK_EN;
> +               break;
> +
> +       case MMC_RSP_R3: /* r3, r4*/
> +               resp = CMD_RESP_48BIT;
> +               break;
> +
> +       case MMC_RSP_R1b: /* r1b */
> +               resp = CMD_RESP_48BITB;
> +               cmd_val |= CMD_CRC_CHK_EN | CMD_IDX_CHK_EN;
> +               break;
> +
> +       default:
> +               break;
> +       }
> +
> +       /*Set Transfer mode regarding to data flag*/
> +       if (data) {
> +               cmd_val |= DATA_PRESENT;
> +               xfrmd_val |= BLK_CNT_EN;
> +               if (data->blocks > 1)
> +                       xfrmd_val |= MULTI_BLK_SEL;
> +#ifdef CONFIG_MMC_SDMA
> +               xfrmd_val |= DMA_EN;
> +#else
> +               xfrmd_val &= ~DMA_EN;
> +#endif
> +               if (DATA_DIRECTION_READ(data))
> +                       xfrmd_val |= TO_HOST_DIR;
> +               else
> +                       xfrmd_val &= ~TO_HOST_DIR;
> +       }
> +
> +       /* if (cmd->opcode == 12)
> +       cmd_val |= host, CMD_TYPE_OFFSET,
> +                        CMD_TYPE_MASK, CMD_TYPE_ABORT, SD_COMMAND);*/
> +       SET_REG(host, cmd->cmdarg & 0xffff, SD_ARG_LOW);
> +       SET_REG(host, cmd->cmdarg >> 16, SD_ARG_HIGH);
> +       SET_REG(host, xfrmd_val, SD_TRANS_MODE);
> +       cmd_val |= cmd->cmdidx << CMD_IDX_OFFSET | resp << RESP_TYPE_OFFSET;
> +       mmc_dbg("%s:Starting CMD%d with ARGUMENT 0x%x\n",
> +                       __func__, cmd->cmdidx, cmd->cmdarg);
> +
> +       val = GET_REG(host, SD_PRESENT_STAT_2);
> +       mask = CMD_LINE_LEVEL_MASK | DATA_LINE_LEVEL_MASK;
> +       if ((val & mask) != mask)
> +               mmc_dbg("%s:WARN: CMD/DATA pins are not all high, "
> +                       "PRE_STAT=0x%04x\n", __func__,
> +                       GET_REG(host, SD_PRESENT_STAT_2));
> +
> +       SET_REG(host, cmd_val, SD_COMMAND);
> +
> +       ret = pxa_sdh_process_irq(host, CMD_COMP);
> +       if (!ret && data) {
> +               do {
> +                       ret = pxa_sdh_process_irq(host, (DMA_INT | XFER_COMP));
> +                       /* If error or xfer completed (in which case
> +                        * bytes_xfered is reset to 0) break */
> +               } while (host->bytes_xfered);
> +       }
> +       return ret;
> +}
> +
> +
> +
> +static int pxa_sdh_cmd_done(struct pxa_sdh_host *host)
> +{
> +       struct mmc_cmd *cmd = host->cmd;
> +       u32 resp[8];
> +
> +       BUG_ON(!cmd);
> +
> +       /* get cmd response */
> +       resp[0] = GET_REG(host, SD_RESP_0);
> +       resp[1] = GET_REG(host, SD_RESP_1);
> +       resp[2] = GET_REG(host, SD_RESP_2);
> +       resp[3] = GET_REG(host, SD_RESP_3);
> +       resp[4] = GET_REG(host, SD_RESP_4);
> +       resp[5] = GET_REG(host, SD_RESP_5);
> +       resp[6] = GET_REG(host, SD_RESP_6);
> +       resp[7] = readb(host->regbase + SD_RESP_7);
> +
> +       if (cmd->resp_type & MMC_RSP_136) {
> +               cmd->response[0] = resp[5] >> 8 | resp[6] << 8 | resp[7] << 24;
> +               cmd->response[1] = resp[3] >> 8 | resp[4] << 8 | resp[5] << 24;
> +               cmd->response[2] = resp[1] >> 8 | resp[2] << 8 | resp[3] << 24;
> +               cmd->response[3] = resp[0] << 8 | resp[1] << 24;
> +       } else {
> +               cmd->response[0] = resp[1] << 16 | resp[0];
> +               cmd->response[1] = resp[3] << 16 | resp[2];
> +               cmd->response[2] = resp[5] << 16 | resp[4];
> +               cmd->response[3] = resp[7] << 16 | resp[6];
> +       }
> +
> +
> +       mmc_dbg("%s: resp[0]=0x%x resp[1]=0x%x resp[2]=0x%x resp[3]=0x%x\n",
> +                       __func__, cmd->response[0], cmd->response[1],
> +                               cmd->response[2], cmd->response[3]);
> +       if (host->error || !host->data)
> +               pxa_sdh_finish_request(host);
> +
> +       return 1;
> +}
> +
> +#ifndef CONFIG_MMC_SDMA
> +static void pxa_sdh_pio_data_done(struct pxa_sdh_host *host)
> +{
> +       struct mmc_data *data = host->data;
> +       u16 blk_size = data->blocksize;
> +       u16 i = 0;
> +
> +       if (DATA_DIRECTION_READ(data)) {
> +               char *dest = data->dest + host->bytes_xfered;
> +               for (i = 0; i < blk_size; i += sizeof(u32)) {
> +                       *(u32 *)(dest + i) = readl(host->regbase +
> +                                                       SD_BUF_DPORT_0);
> +               }
> +       } else {
> +               char *src = (char *) data->src + host->bytes_xfered;
> +               for (i = 0; i < blk_size; i += sizeof(u32))
> +                       writel(*(u32 *)(src +  i),
> +                               host->regbase + SD_BUF_DPORT_0);
> +       }
> +
> +       if (host->bytes_xfered < host->data_len) {
> +               host->bytes_xfered = host->bytes_xfered + blk_size;
> +               pxa_sdh_setup_data(host);
> +       }
> +}
> +#endif
> +
> +static void pxa_sdh_dma_data_done(struct pxa_sdh_host *host)
> +{
> +       struct mmc_data *data = host->data;
> +       int host_dma_bdry_size;
> +
> +       if (host->bytes_xfered < host->data_len) {
> +               host_dma_bdry_size = 0x1000 << (((u16) GET_REG(host,
> +                               SD_BLOCK_SIZE)) >> HOST_DMA_BDRY_OFFSET);
> +               if (host_dma_bdry_size < data->blocksize)
> +                       host->bytes_xfered = host->bytes_xfered +
> +                                                       host_dma_bdry_size;
> +               else
> +                       host->bytes_xfered = host->bytes_xfered +
> +                                                       data->blocksize;
> +               pxa_sdh_setup_data(host);
> +       }
> +}
> +
> +static void pxa_sdh_data_done(struct pxa_sdh_host *host)
> +{
> +       pxa_sdh_finish_request(host);
> +}
> +
> +static int pxa_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd,
> +               struct mmc_data *data)
> +{
> +       struct pxa_sdh_host *host = mmc->priv;
> +       u16 val;
> +       u32 timeout = 1000;
> +       int ret = 0;
> +
> +       host->data = data;
> +       host->cmd  = cmd;
> +
> +       if (pxa_sdh_wait_reset(host)) {
> +               host->error = 1;
> +               pxa_sdh_finish_request(host);
> +               return -ETIMEDOUT;
> +       }
> +       do {
> +               val = GET_REG(host, SD_PRESENT_STAT_1);
> +               if (!(val & CMD_INHBT_DAT || val & CMD_INHBT_CMD))
> +                       break;
> +               udelay(1);
> +       } while (timeout--);
> +       if (!timeout) {
> +               printf("%s: In busy, unable to start the request.\n",
> +                               __func__);
> +               host->error = 1;
> +               pxa_sdh_finish_request(host);
> +               return -EBUSY;
> +       }
> +
> +       /* Clear Interrupt/Error status */
> +       SET_REG(host, 0xffff, SD_NOR_I_STAT);
> +       SET_REG(host, 0xffff, SD_ERR_I_STAT);
> +
> +       if (data) {
> +               mmc_dbg("%s: setup data, blk_sz=%d, blk_cnt=0x%x\n", __func__,
> +                       data->blocksize, data->blocks);
> +               /*
> +                * Set the Host DMA Boundary Buffer
> +                * to Maximum allowed (512 KB)
> +                */
> +               SET_REG(host, ((u16)((HOST_DMA_BDRY_MASK & 0x7) <<
> +                       HOST_DMA_BDRY_OFFSET) | data->blocksize),
> +                               SD_BLOCK_SIZE);
> +               SET_REG(host, data->blocks, SD_BLOCK_COUNT);
> +
> +               pxa_sdh_setup_data(host);
> +       }
> +
> +       ret = pxa_sdh_start_cmd(host);
> +       return ret;
> +}
> +
> +static void pxa_sdh_set_ios(struct mmc *mmc)
> +{
> +       struct pxa_sdh_host *host = mmc->priv;
> +
> +       if (pxa_sdh_wait_reset(host))
> +               return;
> +
> +       if (mmc->clock) {
> +               unsigned long rate = host->clkrate;
> +               unsigned int clk = rate / mmc->clock;
> +               unsigned int shift;
> +
> +               BUG_ON((mmc->clock > mmc->f_max) || (mmc->clock < mmc->f_min));
> +               if (mmc->clock >= host->clkrate) {
> +                       host->clkrt = 0x00;
> +               } else {
> +                       shift = generic_fls(clk);
> +                       if (rate / clk > mmc->clock)
> +                               shift++;
> +                       host->clkrt = 1 << (shift - 2);
> +               }
> +
> +               mmc_dbg("%s: set clkrt = %08x\n", __func__, host->clkrt);
> +               pxa_sdh_stop_clock(host);
> +               pxa_sdh_start_clock(host);
> +
> +               if ((host->clkrt == 0 && host->clkrate > 25000000)
> +                       || (host->clkrt && (host->clkrate/(host->clkrt*2))
> +                                > 25000000)) {
> +                       SET_REG_BIT(host, HI_SPEED_EN, SD_HOST_CTRL);
> +                       mmc_dbg("%s: set as HIGH_SPEED.\n", __func__);
> +               } else
> +                       CLEAR_REG_BIT(host, HI_SPEED_EN, SD_HOST_CTRL);
> +
> +       } else {
> +               pxa_sdh_stop_clock(host);
> +               if (host->clkrt != CLKRT_OFF)
> +                       host->clkrt = CLKRT_OFF;
> +       }
> +
> +       SET_REG_BITS(host, SDCLK_SEL_OFFSET, SDCLK_SEL_MASK,
> +                               SDCLK_SEL_INIT_VAL, SD_CLK_BURST_SET);
> +       SET_REG_BITS(host, SD_BUS_VLT_OFFSET, SD_BUS_VLT_MASK,
> +                       SD_BUS_VLT_18V, SD_HOST_CTRL);
> +       SET_REG_BIT(host, SD_BUS_POWER, SD_HOST_CTRL);
> +
> +       if (mmc->bus_width == MMC_BUS_WIDTH_8) {
> +               SET_REG_BIT(host, MMC_CARD, SD_CE_ATA_2);
> +               SET_REG_BIT(host, DATA_WIDTH_8BIT, SD_CE_ATA_2);
> +                       mmc_dbg("%s: set as 8_BIT_MODE.\n", __func__);
> +       } else {
> +               CLEAR_REG_BIT(host, MMC_CARD, SD_CE_ATA_2);
> +               CLEAR_REG_BIT(host, DATA_WIDTH_8BIT, SD_CE_ATA_2);
> +               if (mmc->bus_width == MMC_BUS_WIDTH_4) {
> +                       SET_REG_BIT(host, DATA_WIDTH_4BIT, SD_HOST_CTRL);
> +                       mmc_dbg("%s: set as 4_BIT_MODE.\n", __func__);
> +               } else {
> +                       CLEAR_REG_BIT(host, DATA_WIDTH_4BIT, SD_HOST_CTRL);
> +               }
> +       }
> +}
> +
> +static int sdh_init(struct mmc *mmc)
> +{
> +       struct pxa_sdh_host *host = mmc->priv;
> +
> +       switch (host->port_num) {
> +       case 0:
> +               /* Setup the MMC/SD(1) Host Controller Clock */
> +               writel(0x19, 0xd4282854);
> +               udelay(10);
> +               writel(0x1B, 0xd4282854);
> +               break;
> +       case 1:
> +               /* Setup the MMC/SD(2) Host Controller Clock */
> +               writel(0x10, 0xd4282858);
> +               udelay(10);
> +               writel(0x12, 0xd4282858);
> +               break;
> +       case 2:
> +               /* Setup the MMC/SD(3) Host Controller Clock */
> +               writel(0x19, 0xd42828e0);
> +               udelay(10);
> +               writel(0x1b, 0xd42828e0);
> +               break;
> +       case 3:
> +               /* Setup the MMC/SD(4) Host Controller Clock */
> +               writel(0x10, 0xd42828e4);
> +               udelay(10);
> +               writel(0x12, 0xd42828e4);
> +               break;
> +       }
> +
> +       /* Enable Interrupt status */
> +       SET_REG(host, 0xffff, SD_NOR_I_STAT_EN);
> +       SET_REG(host, 0xffff, SD_ERR_I_STAT_EN);
> +
> +       /* Disable interrupt generation */
> +       SET_REG(host, 0, SD_NOR_INT_EN);
> +       SET_REG(host, 0, SD_ERR_INT_EN);
> +       return 0;
> +}
> +
> +int pxa_sdh_init(bd_t *bis)
> +{
> +       struct mmc *mmc;
> +       struct pxa_sdh_host *host;
> +       unsigned int i;
> +       unsigned int mmc_base[] = {
> +               CONFIG_SYS_MMC_BASE,
> +               CONFIG_SYS_MMC1_BASE,
> +               CONFIG_SYS_MMC2_BASE,
> +               CONFIG_SYS_MMC3_BASE,
> +               0
> +       };
> +
> +       /* Initialize the controllers clock for SD1 and SD2 */
> +       if (mmc_base[0] != 0xFF || mmc_base[1] != 0xFF) {
> +               writel(0xa, 0xd4282854);
> +               udelay(10);
> +               writel(0xb, 0xd4282854);
> +       }
> +
> +       /* Initialize the controllers clock for SD3 and SD4 */
> +       if (mmc_base[2] != 0xFF || mmc_base[3] != 0xFF) {
> +               writel(0xa, 0xd42828e0);
> +               udelay(10);
> +               writel(0xb, 0xd42828e0);
> +       }
> +
> +       for (i = 0; mmc_base[i]; i++) {
> +               if (mmc_base[i] == 0xFF)
> +                       continue;
> +
> +               mmc = malloc(sizeof(struct mmc));
> +               if (!mmc) {
> +                       printf("mmc malloc fail!!\n");
> +                       return -1;
> +               }
> +
> +               host = malloc(sizeof(struct pxa_sdh_host));
> +               if (!host) {
> +                       printf("host malloc fail!!!\n");
> +                       return -1;
> +               }
> +
> +               host->regbase = mmc_base[i];
> +               host->clkrate = 48000000;
> +               host->clkrt = CLKRT_OFF;
> +               host->port_num = i;
> +
> +               strncpy(mmc->name, "pxa-sdh", 7);
> +               mmc->priv = host;
> +               mmc->send_cmd = pxa_sdh_request;
> +               mmc->set_ios = pxa_sdh_set_ios;
> +               mmc->init = sdh_init;
> +
> +               /*
> +                * Calculate minimum clock rate, rounding up.
> +                */
> +               mmc->f_min = (host->clkrate + SD_FREQ_SEL_MASK) /
> +                                (SD_FREQ_SEL_MASK + 1);
> +               mmc->f_max = host->clkrate / 2;
> +               mmc->ocr = 0xffffffff;
> +               mmc->voltages = MMC_VDD_27_28|MMC_VDD_28_29;
> +#ifndef CONFIG_MMC3
> +               mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS;
> +#else
> +               mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HS;
> +#endif
> +
> +               mmc_register(mmc);
> +       }
> +
> +       return 0;
> +}
> diff --git a/drivers/mmc/pxa_sdh.h b/drivers/mmc/pxa_sdh.h
> new file mode 100644
> index 0000000..fc48cd2
> --- /dev/null
> +++ b/drivers/mmc/pxa_sdh.h
> @@ -0,0 +1,241 @@
> +/**************************************************************************
> + *
> + * Copyright (c) 2009, 2010 Marvell International Ltd.
> + *
> + * This file is part of GNU program.
> + *
> + * GNU 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.
> + *
> + * GNU 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, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
> + *
> + *************************************************************************/
> +
> +/* register definitions of PXA SD Host Controller*/
> +#define SD_SYS_ADDR_LOW                0x0000  /* DMA System Address Low */
> +#define SD_SYS_ADDR_HIGH       0x0002  /* DMA System Address High */
> +#define SD_BLOCK_SIZE          0x0004  /* Block Size*/
> +#define SD_BLOCK_COUNT         0x0006  /* Block Count */
> +#define SD_ARG_LOW             0x0008  /* Command Argument Low */
> +#define SD_ARG_HIGH            0x000a  /* Command Argument High */
> +#define SD_TRANS_MODE          0x000c  /* Transfer Mode */
> +#define SD_COMMAND             0x000e  /* Command */
> +#define SD_RESP_0              0x0010  /* Command Response 0 */
> +#define SD_RESP_1              0x0012  /* Command Response 1 */
> +#define SD_RESP_2              0x0014  /* Command Response 2 */
> +#define SD_RESP_3              0x0016  /* Command Response 3 */
> +#define SD_RESP_4              0x0018  /* Command Response 4 */
> +#define SD_RESP_5              0x001a  /* Command Response 5 */
> +#define SD_RESP_6              0x001c  /* Command Response 6 */
> +#define SD_RESP_7              0x001e  /* Command Response 7 */
> +#define SD_BUF_DPORT_0         0x0020  /* Buffer Data Port 0 */
> +#define SD_BUF_DPORT_1         0x0022  /* Buffer Data Port 1 */
> +#define SD_PRESENT_STAT_1      0x0024  /* Present State 1 */
> +#define SD_PRESENT_STAT_2      0x0026  /* Present State 2 */
> +#define SD_HOST_CTRL           0x0028  /* Host Control */
> +#define SD_BLOCK_GAP_CTRL      0x002a  /* Block Gap Control */
> +#define SD_CLOCK_CNTL          0x002c  /* Clock Control */
> +#define SD_TO_CTRL_SW_RST      0x002e  /* Timeout Control/SW Reset */
> +#define SD_NOR_I_STAT          0x0030  /* Normal Interrupt Status */
> +#define SD_ERR_I_STAT          0x0032  /* Error Interrupt Status */
> +#define SD_NOR_I_STAT_EN       0x0034  /* Normal Interrupt Status Enable */
> +#define SD_ERR_I_STAT_EN       0x0036  /* Error Interrupt Status Enable */
> +#define SD_NOR_INT_EN          0x0038  /* Normal Interrupt Generation Enable */
> +#define SD_ERR_INT_EN          0x003a  /* Error Interrupt Generation Enable */
> +#define SD_ACMD12_ERR_STAT     0x003c  /* Auto CMD12 Error Status */
> +#define SD_CAP_1               0x0040  /* Capabilities 1 */
> +#define SD_CAP_3               0x0044  /* Capabilities 3 */
> +#define SD_CAP_4               0x0046  /* Capabilities 4 */
> +#define SD_MAX_CUR_1           0x0048  /* Maximum Current 1 */
> +#define SD_MAX_CUR_2           0x004a  /* Maximum Current 2 */
> +#define SD_MAX_CUR_3           0x004c  /* Maximum Current 3 */
> +#define SD_MAX_CUR_4           0x004e  /* Maximum Current 4 */
> +#define SD_FE_ACMD12_ERR       0x0050  /* Force Event for Auto CMD12 Error */
> +#define SD_FE_ERR_STAT         0x0052  /* Force Event for Error Status */
> +#define SD_ADMA_ERR_STAT       0x0054  /* ADMA Error Status */
> +#define SD_ADMA_SADDR_1                0x0058  /* ADMA System Address[15:0] */
> +#define SD_ADMA_SADDR_2                0x005a  /* ADMA System Address[31:16] */
> +#define SD_ADMA_SADDR_3                0x005c  /* ADMA System Address[47:32] */
> +#define SD_ADMA_SADDR_4                0x005e  /* ADMA System Address[64:48] */
> +#define SD_FIFO_PARAM          0x00e0  /* FIRO Parameters */
> +#define SD_SPI_MODE            0x00e4  /* SPI Mode */
> +#define SD_CLK_BURST_SET       0x00e6  /* Clock and Burst Size Setup */
> +#define SD_CE_ATA_1            0x00e8  /* CE-ATA 1 */
> +#define SD_CE_ATA_2            0x00ea  /* CE-ATA 2 */
> +#define SD_PAD_IO_SETUP                0x00ec  /* Pad I/O Setup */
> +#define SD_SLOT_INT_STAT       0x00fc  /* Slot Interrupt Status*/
> +#define SD_HOST_CTRL_VER       0x00fe  /* Host Controller Version */
> +
> +/* SD_BLOCK_SIZE */
> +#define HOST_DMA_BDRY_OFFSET   12
> +#define HOST_DMA_BDRY_MASK     ((u16)0x7)
> +#define BLOCK_SIZE_OFFSET      0
> +#define BLOCK_SIZE_MASK                ((u16)0x0fff)
> +#define BLOCK_SIZE_MAX         ((u16)0x0800)
> +
> +/* SD_TRANS_MODE */
> +#define MULTI_BLK_SEL          ((u16)1 << 5)
> +#define TO_HOST_DIR            ((u16)1 << 4)
> +#define AUTO_CMD12_EN          ((u16)1 << 2)
> +#define BLK_CNT_EN             ((u16)1 << 1)
> +#define DMA_EN                 ((u16)1 << 0)
> +
> +/* SD_COMMAND */
> +#define CMD_IDX_OFFSET         8
> +#define CMD_IDX_MASK           ((u16)0x3f)
> +#define CMD_TYPE_OFFSET                6
> +#define CMD_TYPE_MASK          ((u16)0x3)
> +#define CMD_TYPE_NORMAL                ((u16)0x0)
> +#define CMD_TYPE_RESUME                ((u16)0x1)
> +#define CMD_TYPE_SUSPEND       ((u16)0x2)
> +#define CMD_TYPE_ABORT         ((u16)0x3)
> +#define DATA_PRESENT           ((u16)1 << 5)
> +#define CMD_IDX_CHK_EN         ((u16)1 << 4)
> +#define CMD_CRC_CHK_EN         ((u16)1 << 3)
> +#define RESP_TYPE_OFFSET       0
> +#define RESP_TYPE_MASK         ((u16)0x3)
> +/* RES_TYPE */
> +#define CMD_RESP_NONE          ((u16)0x0)
> +#define CMD_RESP_136BIT                ((u16)0x1)
> +#define CMD_RESP_48BIT         ((u16)0x2)
> +#define CMD_RESP_48BITB                ((u16)0x3)
> +
> +/* SD_PRESENT_STAT_1 */
> +#define CMD_INHBT_DAT          ((u16)1 << 1)
> +#define CMD_INHBT_CMD          ((u16)1 << 0)
> +
> +/* SD_PRESENT_STAT_2 */
> +#define CARD_STABLE            ((u16)1 << 1)
> +#define CARD_DETECTED          ((u16)1 << 2)
> +#define CARD_PROT              ((u16)1 << 3)
> +#define DATA_LINE_LEVEL_MASK   ((u16)0xf << 4)
> +#define CMD_LINE_LEVEL_MASK    ((u16)1 << 8)
> +
> +/* SD_HOST_CTRL */
> +#define SD_BUS_VLT_OFFSET      9
> +#define SD_BUS_VLT_MASK                ((u16)0x7)
> +#define SD_BUS_VLT_18V         ((u16)0x5)
> +#define SD_BUS_VLT_30V         ((u16)0x6)
> +#define SD_BUS_VLT_33V         ((u16)0x7)
> +#define SD_BUS_POWER           ((u16)1 << 8)
> +#define DMA_SEL_OFFSET         3
> +#define DMA_SEL_MASK           ((u16)0x3)
> +#define DMA_SEL_SDMA           ((u16)0)
> +#define DMA_SEL_ADMA1          ((u16)1)
> +#define DMA_SEL_ADMA2_32       ((u16)2)
> +#define DMA_SEL_ADMA2_64       ((u16)3)
> +#define HI_SPEED_EN            ((u16)1 << 2)
> +#define DATA_WIDTH_4BIT                ((u16)1 << 1)
> +
> +/* SD_BLOCK_GAP_CTRL */
> +#define INT_BLK_GAP            ((u16)1 << 3)
> +#define RD_WT_CNTL             ((u16)1 << 2)
> +#define CONT_REQ               ((u16)1 << 1)
> +#define STOP_AT_BLK_GAP_REQ    ((u16)1 << 0)
> +
> +/* SD_CLOCK_CNTL */
> +#define SD_FREQ_SEL_OFFSET     8
> +#define SD_FREQ_SEL_MASK       ((u16)0xff)
> +#define EXT_CLK_EN             ((u16)1 << 2)
> +#define INT_CLK_STABLE         ((u16)1 << 1)
> +#define INT_CLK_EN             ((u16)1 << 0)
> +
> +/* SD_TO_CTRL_SW_RST */
> +#define SW_RST_DAT             ((u16)1 << 10)
> +#define SW_RST_CMD             ((u16)1 << 9)
> +#define SW_RST_ALL             ((u16)1 << 8)
> +#define DAT_TO_VAL_OFFSET      0
> +#define DAT_TO_MASK            ((u16)0xf)
> +
> +/* SD_NOR_I_STAT,  SD_NOR_I_STAT_EN, SD_NOR_INT_EN */
> +#define ERR_INT                        ((u16)1 << 15) /* Error Interrupt*/
> +#define CARD_INT               ((u16)1 << 8) /* Card Interrupt */
> +#define CARD_REM               ((u16)1 << 7) /* Card Removal Interrupt */
> +#define CARD_INS               ((u16)1 << 6) /* Card Insertion Interrupt */
> +#define RX_RDY                 ((u16)1 << 5) /* Buffer Read Ready */
> +#define TX_RDY                 ((u16)1 << 4) /* Buffer Write Ready */
> +#define DMA_INT                        ((u16)1 << 3) /* DMA Interrupt */
> +#define BLK_GAP_EVNT           ((u16)1 << 2) /* Block Gap Event */
> +#define XFER_COMP              ((u16)1 << 1) /* Transfer Complete */
> +#define CMD_COMP               ((u16)1 << 0) /* Command Complete */
> +#define SD_NOR_I_STAT_RVD_MASK ((u16)0x7e00) /* Mask for SD_NOR_I_STAT
> +                                                Reserved Bits[14 :9] */
> +#define SD_NOR_INT_EN_RVD_MASK ((u16)0xfe00) /* Mask for SD_NOR_INT_EN/
> +                                       SD_NOR_I_STAT_EN Reserved Bits[15 :9] */
> +
> +/* SD_ERR_I_STAT,  SD_ERR_I_STAT_EN, SD_ERR_INT_EN */
> +#define CRC_STATUS_ERR         ((u16)1 << 15) /* CRC Status Error Returned
> +                                       from Card in Write Transaction */
> +#define CPL_TO_ERR             ((u16)1 << 14) /* Command Completion Signal
> +                                       Timeout Error, for CE-ATA mode only*/
> +#define AXI_RESP_ERR           ((u16)1 << 13) /* AXI Bus Response Error */
> +#define SPI_ERR                        ((u16)1 << 12) /* SPI Mode Error*/
> +#define ADMA_ERR               ((u16)1 << 9) /* AMDA Error */
> +#define AUTO_CMD12_ERR         ((u16)1 << 8) /* Auto CMD12 Error*/
> +#define CUR_LIMIT_ERR          ((u16)1 << 7) /* Current Limit Error*/
> +#define RD_DATA_END_ERR                ((u16)1 << 6) /* Read Data End Bit Error*/
> +#define RD_DATA_CRC_ERR                ((u16)1 << 5) /* Read Data CRC Error*/
> +#define DATA_TO_ERR            ((u16)1 << 4) /* Data Timeout Error*/
> +#define CMD_IDX_ERR            ((u16)1 << 3) /* Command Index Error*/
> +#define CMD_END_BIT_ERR                ((u16)1 << 2) /* Command End Bit Error*/
> +#define CMD_CRC_ERR            ((u16)1 << 1) /* Command CRC Error*/
> +#define CMD_TO_ERR             ((u16)1 << 0) /* Command Timeout Error*/
> +
> +#define SD_ERR_INT_EN_RVD_MASK         ((u16)0x0c00)/* Mask for
> +                       SD_ERR_INT_EN/SD_ERR_I_STAT_EN Reserved Bits[11 :10] */
> +
> +#define SD_ERR_INT_DATA_ERR_MASK       (DATA_TO_ERR | RD_DATA_CRC_ERR | \
> +                                       RD_DATA_END_ERR) /*DATA Line Error*/
> +
> +#define SD_ERR_INT_CMD_ERR_MASK                (CMD_TO_ERR | CMD_CRC_ERR | \
> +                                       CMD_END_BIT_ERR | CMD_IDX_ERR)
> +                                       /* CMD Line Error*/
> +
> +/* SD_FIFO_PARAM */
> +#define DIS_PAD_SD_CLK_GATE    ((u16)1 << 10) /* Turn on/off Dynamic
> +                                               SD Clock Gating */
> +
> +/* SD_CLK_BURST_SET */
> +#define SDCLK_DELAY_OFFSET     10
> +#define SDCLK_DELAY_MASK       ((u16)0xf)
> +#define SDCLK_DELAY_MAX        ((u16)0xf)
> +#define SDCLK_SEL_OFFSET       8
> +#define SDCLK_SEL_MASK         ((u16)0x3)
> +#define SDCLK_SEL_INIT_VAL     ((u16)0x3)
> +#define DMA_BURST_SIZE         ((u16)0)
> +
> +/* SD_SLOT_INT_STAT */
> +#define SLOT_INT1              ((u16)1<<1)
> +#define SLOT_INT0              ((u16)1<<0)
> +#define SlOT_INT_MASK          (SLOT_INT0 | SLOT_INT1)
> +
> +/* SD_CE_ATA_2 */
> +#define DATA_WIDTH_8BIT                ((u16)1 << 8)
> +#define MMC_CARD               ((u16)1 << 12)
> +
> +#ifndef CONFIG_SYS_MMC_BASE
> +#define CONFIG_SYS_MMC_BASE 0xFF
> +#endif
> +
> +#ifndef CONFIG_SYS_MMC1_BASE
> +#define CONFIG_SYS_MMC1_BASE 0xFF
> +#endif
> +
> +#ifndef CONFIG_SYS_MMC2_BASE
> +#define CONFIG_SYS_MMC2_BASE 0xFF
> +#endif
> +
> +#ifndef CONFIG_SYS_MMC3_BASE
> +#define CONFIG_SYS_MMC3_BASE 0xFF
> +#endif
> +
> diff --git a/include/configs/gplugd.h b/include/configs/gplugd.h
> index f0fb057..16fd03e 100644
> --- a/include/configs/gplugd.h
> +++ b/include/configs/gplugd.h
> @@ -109,6 +109,21 @@
>  #endif /*CONFIG_PXA3XX_SPI*/
>
>  /*
> + * SD/MMC & FAT support
> + */
> +#define CONFIG_PXASDH
> +
> +#ifdef CONFIG_PXASDH
> +#define CONFIG_CMD_MMC
> +#define CONFIG_MMC
> +#define CONFIG_CMD_FAT
> +#define CONFIG_DOS_PARTITION
> +#define CONFIG_GENERIC_MMC
> +#define CONFIG_SYS_MMC_BASE     0xd4280000
> +#define CONFIG_SYS_MMC1_BASE    0xd4281000
> +#endif /* CONFIG_PXASDH */
> +
> +/*
>  * mv-common.h should be defined after CMD configs since it used them
>  * to enable certain macros
>  */
> --
> 1.7.0.4
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-armada100/cpu.h b/arch/arm/include/asm/arch-armada100/cpu.h
index 0518a6a..6ab3bf9 100644
--- a/arch/arm/include/asm/arch-armada100/cpu.h
+++ b/arch/arm/include/asm/arch-armada100/cpu.h
@@ -50,4 +50,8 @@  struct armd1cpu_registers {
 u32 armd1_sdram_base(int);
 u32 armd1_sdram_size(int);
 
+#ifdef CONFIG_PXASDH
+int pxa_sdh_init(bd_t *);
+#endif
+
 #endif /* _ARMADA100CPU_H */
diff --git a/arch/arm/include/asm/arch-armada100/mfp.h b/arch/arm/include/asm/arch-armada100/mfp.h
index e94be3a..1d897ae 100644
--- a/arch/arm/include/asm/arch-armada100/mfp.h
+++ b/arch/arm/include/asm/arch-armada100/mfp.h
@@ -89,6 +89,23 @@ 
 #define MFP110_SSP2_CS          (MFP_REG(0x1B8) | MFP_AF0 | MFP_DRIVE_MEDIUM)
 #define MFP111_SSP2_CLK         (MFP_REG(0x1BC) | MFP_AF4 | MFP_DRIVE_MEDIUM)
 
+/* MMC1 */
+#define MFP040_MMC1_D1		(MFP_REG(0x00C) | MFP_AF1 | MFP_DRIVE_MEDIUM)
+#define MFP041_MMC1_D0		(MFP_REG(0x010) | MFP_AF1 | MFP_DRIVE_MEDIUM)
+#define MFP043_MMC1_CLK		(MFP_REG(0x018) | MFP_AF1 | MFP_DRIVE_MEDIUM)
+#define MFP049_MMC1_CMD		(MFP_REG(0x030) | MFP_AF1 | MFP_DRIVE_MEDIUM)
+#define MFP051_MMC1_D3		(MFP_REG(0x038) | MFP_AF1 | MFP_DRIVE_MEDIUM)
+#define MFP052_MMC1_D2		(MFP_REG(0x03C) | MFP_AF1 | MFP_DRIVE_MEDIUM)
+#define MFP053_MMC1_CD		(MFP_REG(0x040) | MFP_AF1 | MFP_DRIVE_MEDIUM)
+
+/* MMC2 */
+#define MFP028_MMC2_CMD		(MFP_REG(0x0BC) | MFP_AF6 | MFP_DRIVE_MEDIUM)
+#define MFP029_MMC2_CLK		(MFP_REG(0x0C0) | MFP_AF6 | MFP_DRIVE_MEDIUM)
+#define MFP030_MMC2_D0		(MFP_REG(0x0C4) | MFP_AF6 | MFP_DRIVE_MEDIUM)
+#define MFP031_MMC2_D1		(MFP_REG(0x0C8) | MFP_AF6 | MFP_DRIVE_MEDIUM)
+#define MFP032_MMC2_D2		(MFP_REG(0x0CC) | MFP_AF6 | MFP_DRIVE_MEDIUM)
+#define MFP033_MMC2_D3		(MFP_REG(0x0D0) | MFP_AF6 | MFP_DRIVE_MEDIUM)
+
 /* More macros can be defined here... */
 
 #define MFP_PIN_MAX	117
diff --git a/board/Marvell/gplugd/gplugd.c b/board/Marvell/gplugd/gplugd.c
index 0c7a8fd..7eacd63 100644
--- a/board/Marvell/gplugd/gplugd.c
+++ b/board/Marvell/gplugd/gplugd.c
@@ -31,6 +31,7 @@ 
 #include <common.h>
 #include <mvmfp.h>
 #include <asm/arch/mfp.h>
+#include <asm/arch/cpu.h>
 #include <asm/arch/armada100.h>
 #include <asm/arch/gpio.h>
 #include <miiphy.h>
@@ -81,11 +82,29 @@  int board_early_init_f(void)
 		MFP101_ETH_MDIO,
 		MFP103_ETH_RXDV,
 
+		/* SPI Flash interface */
 		MFP107_SSP2_RXD,
 		MFP108_SSP2_TXD,
 		MFP110_SSP2_CS,
 		MFP111_SSP2_CLK,
 
+		/* MMC1 */
+		MFP040_MMC1_D1,
+		MFP041_MMC1_D0,
+		MFP043_MMC1_CLK,
+		MFP049_MMC1_CMD,
+		MFP051_MMC1_D3,
+		MFP052_MMC1_D2,
+		MFP053_MMC1_CD,
+
+		/* MMC2 */
+		MFP028_MMC2_CMD,
+		MFP029_MMC2_CLK,
+		MFP030_MMC2_D0,
+		MFP031_MMC2_D1,
+		MFP032_MMC2_D2,
+		MFP033_MMC2_D3,
+
 		MFP_EOC		/*End of configuration*/
 	};
 	/* configure MFP's */
@@ -121,6 +140,13 @@  int board_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_PXASDH
+int board_mmc_init(bd_t *bd)
+{
+	return pxa_sdh_init(bd);
+}
+#endif
+
 #ifdef CONFIG_PXA_ETH
 int board_eth_init(bd_t *bis)
 {
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index a8fe17a..7f88031 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -38,6 +38,7 @@  COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
 COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
 COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
 COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o
+COBJS-$(CONFIG_PXASDH) += pxa_sdh.o
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/mmc/pxa_sdh.c b/drivers/mmc/pxa_sdh.c
new file mode 100644
index 0000000..0198af3
--- /dev/null
+++ b/drivers/mmc/pxa_sdh.c
@@ -0,0 +1,677 @@ 
+/**************************************************************************
+ *
+ * Copyright (c) 2009, 2010 Marvell International Ltd.
+ *
+ * This file is part of GNU program.
+ *
+ * GNU 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.
+ *
+ * GNU 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, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ *
+ *************************************************************************/
+
+/*
+ * Copyright (C) Marvell International Ltd. (kvedere@marvell.com)
+ * Code heavily based on Linux driver
+ *	/driver/mmc/host/pxa_sdh.c
+ * Copyright (C) 2008-2009 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <part.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/mtd/compat.h>
+
+#include "pxa_sdh.h"
+
+#define CLKRT_OFF			(~0)
+#define GET_REG(host, reg)		readw(host->regbase + reg)
+#define SET_REG(host, val, reg)		writew(val, host->regbase + reg)
+#define DATA_DIRECTION_READ(data)	(data->flags & MMC_DATA_READ)
+#define SET_REG_BIT(host, bit_mask, reg) \
+		SET_REG(host, \
+			GET_REG(host, reg) | (bit_mask), reg)
+#define CLEAR_REG_BIT(host, bit_mask, reg) \
+		SET_REG(host, \
+			GET_REG(host, reg) & ~(bit_mask), reg)
+#define SET_REG_BITS(host, bits_pos, bits_mask, val, reg) \
+		{SET_REG(host, \
+			GET_REG(host, reg) & ~(bits_mask << bits_pos), reg); \
+		SET_REG(host, \
+			GET_REG(host, reg) | (val << bits_pos), reg); }
+#define GET_REG_BITS(host, bit_pos, bits_mask, reg) \
+		((GET_REG(host, reg) >> bit_pos) & bits_mask)
+#define mmc_resp_type(cmd) ((cmd)->resp_type & (MMC_RSP_PRESENT|MMC_RSP_136| \
+				MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
+
+#define MMC_BUS_WIDTH_1		1
+#define MMC_BUS_WIDTH_4		4
+#define MMC_BUS_WIDTH_8		8
+#define CONFIG_MMC_SDMA		1
+
+/* #define CONFIG_MMC_DEBUG	1 */
+
+#ifdef CONFIG_MMC_DEBUG
+#define mmc_dbg printf
+#else
+#define mmc_dbg(arg...)
+#endif
+
+struct pxa_sdh_host {
+	struct mmc_cmd	*cmd;
+	struct mmc_data *data;
+	u32		regbase;
+	u32		bytes_xfered;
+	u32		clkrate;
+	u32		clkrt;
+	u32		data_len;
+	int		error;
+	int		port_num;
+};
+
+static int pxa_sdh_cmd_done(struct pxa_sdh_host *host);
+static void pxa_sdh_dma_data_done(struct pxa_sdh_host *host);
+static void pxa_sdh_data_done(struct pxa_sdh_host *host);
+
+#ifdef CONFIG_MMC_DEBUG
+static void dump_registers(struct pxa_sdh_host *host)
+{
+	unsigned int val;
+	int offset;
+
+	for (offset = 0; offset < 0x60; offset += 4) {
+		if (offset == 0x20)
+			continue;
+		val = readl(host->regbase + offset);
+		printf("%08x: %08x\n",
+			(unsigned int)host->regbase + offset, val);
+	}
+	for (offset = 0xE0; offset < 0xF0; offset += 4) {
+		val = readl(host->regbase + offset);
+		printf("%08x: %08x\n",
+			(unsigned int)host->regbase + offset, val);
+	}
+	val = readl(host->regbase + 0xFC);
+	printf("%08x: %08x\n", (unsigned int)host->regbase + 0xFC, val);
+}
+#endif
+
+/*static inline int fls(int x)
+{
+	int ret;
+
+	asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
+	ret = 32 - ret;
+	return ret;
+}*/
+
+static int pxa_sdh_wait_reset(struct pxa_sdh_host *host)
+{
+	u32 timeout = 1000;
+	u16 val;
+
+	do {
+		val = GET_REG(host, SD_TO_CTRL_SW_RST);
+		if (!(val & (SW_RST_DAT | SW_RST_CMD | SW_RST_ALL)))
+			break;
+		udelay(1);
+	} while (timeout--);
+	if (timeout)
+		return 0;
+
+	printf("%s: Fatal: Wait RESET timeout.\n", __func__);
+
+	return 1;
+}
+
+static void pxa_sdh_stop_clock(struct pxa_sdh_host *host)
+{
+	CLEAR_REG_BIT(host, EXT_CLK_EN, SD_CLOCK_CNTL);
+}
+
+static void pxa_sdh_start_clock(struct pxa_sdh_host *host)
+{
+	u32 timeout = 1000;
+
+	SET_REG_BIT(host, INT_CLK_EN, SD_CLOCK_CNTL);
+	do {
+		if (GET_REG(host, SD_CLOCK_CNTL) & INT_CLK_STABLE)
+			break;
+		udelay(1);
+	} while (timeout--);
+	if (!timeout)
+		printf("%s: unable to start clock\n", __func__);
+
+	SET_REG_BITS(host, SD_FREQ_SEL_OFFSET, SD_FREQ_SEL_MASK,
+		host->clkrt, SD_CLOCK_CNTL);
+
+	/* set as maximum value for data line timeout*/
+	SET_REG_BITS(host, DAT_TO_VAL_OFFSET, DAT_TO_MASK,
+		(DAT_TO_MASK - 1), SD_TO_CTRL_SW_RST);
+
+	SET_REG_BIT(host, EXT_CLK_EN, SD_CLOCK_CNTL);
+}
+
+static void pxa_sdh_setup_sdma(struct pxa_sdh_host *host)
+{
+	struct mmc_data *data = host->data;
+	if (DATA_DIRECTION_READ(data)) {
+		char *dest = data->dest + host->bytes_xfered;
+		SET_REG(host, (u32) dest & 0xffff, SD_SYS_ADDR_LOW);
+		SET_REG(host, (u32) dest >> 16, SD_SYS_ADDR_HIGH);
+	} else {
+		char *src = (char *) data->src + host->bytes_xfered;
+		SET_REG(host, (u32) src & 0xffff, SD_SYS_ADDR_LOW);
+		SET_REG(host, (u32) src >> 16, SD_SYS_ADDR_HIGH);
+	}
+
+}
+
+static void pxa_sdh_setup_data(struct pxa_sdh_host *host)
+{
+#ifdef CONFIG_MMC_SDMA
+	pxa_sdh_setup_sdma(host);
+	SET_REG_BITS(host, DMA_SEL_OFFSET, DMA_SEL_MASK,
+				DMA_SEL_SDMA, SD_HOST_CTRL);
+#endif
+}
+
+static void pxa_sdh_finish_request(struct pxa_sdh_host *host)
+{
+
+#ifdef CONFIG_MMC_DEBUG
+	struct mmc_cmd *cmd = host->cmd;
+	dump_registers(host);
+#endif
+	if (host->data && host->error)
+		SET_REG_BIT(host, SW_RST_DAT, SD_TO_CTRL_SW_RST);
+
+	mmc_dbg("%s: Finishing CMD%d(%s)\n", __func__, cmd->cmdidx,
+		(host->error ? "failed" : "done"));
+
+	host->data = NULL;
+	host->cmd = NULL;
+	host->error = 0;
+	host->data_len = 0;
+	host->bytes_xfered = 0;
+}
+
+static int pxa_sdh_process_irq(struct pxa_sdh_host *host, u32 intr_type)
+{
+	ulong hz = 3250000; /* 3.25 MHz Timer Clock */
+	ushort done = GET_REG(host, SD_NOR_I_STAT) & intr_type;
+	ulong start, curr, diff;
+#ifdef CONFIG_MMC_DEBUG
+	struct mmc_cmd *cmd = host->cmd;
+#endif
+
+	start = get_timer(0);
+	while (!done) {
+		done = GET_REG(host, SD_NOR_I_STAT) & intr_type;
+		if (GET_REG(host, SD_NOR_I_STAT) & 0x8000) {
+			mmc_dbg("Error! cmd : %d, err : %04x\n",
+				cmd->cmdidx, GET_REG(host, SD_ERR_I_STAT));
+			host->error = 1;
+			pxa_sdh_finish_request(host);
+			if (GET_REG(host, SD_ERR_I_STAT) & 0x1)
+				return TIMEOUT;      /* error happened */
+			else
+				return COMM_ERR;
+		}
+		curr = get_timer(0);
+		diff = (long) curr - (long) start;
+		if (diff > (3*hz)) {
+			printf("cmd timeout, status : %04x\n",
+					GET_REG(host, SD_NOR_I_STAT));
+			printf("xfer mode : %04x\n",
+					GET_REG(host, SD_TRANS_MODE));
+			host->error = 1;
+			pxa_sdh_finish_request(host);
+			return -ETIMEDOUT;
+		}
+	}
+
+	if (intr_type & CMD_COMP)
+		pxa_sdh_cmd_done(host);
+
+#ifdef CONFIG_MMC_SDMA
+	if (intr_type & DMA_INT)
+		pxa_sdh_dma_data_done(host);
+#else
+	if ((cmdtype & TX_RDY) || (cmdtype & RX_RDY))
+		pxa_sdh_pio_data_done(host);
+#endif
+
+	if (intr_type & XFER_COMP)
+		pxa_sdh_data_done(host);
+
+	/* Clear Status Bits */
+	SET_REG(host, intr_type, SD_NOR_I_STAT);
+	return 0;
+}
+
+static int pxa_sdh_start_cmd(struct pxa_sdh_host *host)
+{
+	u16 resp = 0;
+	u16 xfrmd_val = 0;
+	u16 cmd_val = 0;
+	u16 val, mask;
+	struct mmc_data *data = host->data;
+	struct mmc_cmd *cmd = host->cmd;
+	int ret;
+
+	BUG_ON(!cmd);
+
+	/*Set Response Type*/
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_NONE:
+		break;
+
+	case MMC_RSP_R1: /* r1, r5, r6, r7 */
+		resp = CMD_RESP_48BIT;
+		cmd_val |= CMD_CRC_CHK_EN | CMD_IDX_CHK_EN;
+		break;
+
+	case MMC_RSP_R2: /* r2 */
+		resp = CMD_RESP_136BIT;
+		cmd_val |= CMD_CRC_CHK_EN;
+		break;
+
+	case MMC_RSP_R3: /* r3, r4*/
+		resp = CMD_RESP_48BIT;
+		break;
+
+	case MMC_RSP_R1b: /* r1b */
+		resp = CMD_RESP_48BITB;
+		cmd_val |= CMD_CRC_CHK_EN | CMD_IDX_CHK_EN;
+		break;
+
+	default:
+		break;
+	}
+
+	/*Set Transfer mode regarding to data flag*/
+	if (data) {
+		cmd_val |= DATA_PRESENT;
+		xfrmd_val |= BLK_CNT_EN;
+		if (data->blocks > 1)
+			xfrmd_val |= MULTI_BLK_SEL;
+#ifdef CONFIG_MMC_SDMA
+		xfrmd_val |= DMA_EN;
+#else
+		xfrmd_val &= ~DMA_EN;
+#endif
+		if (DATA_DIRECTION_READ(data))
+			xfrmd_val |= TO_HOST_DIR;
+		else
+			xfrmd_val &= ~TO_HOST_DIR;
+	}
+
+	/* if (cmd->opcode == 12)
+	cmd_val |= host, CMD_TYPE_OFFSET,
+			 CMD_TYPE_MASK, CMD_TYPE_ABORT, SD_COMMAND);*/
+	SET_REG(host, cmd->cmdarg & 0xffff, SD_ARG_LOW);
+	SET_REG(host, cmd->cmdarg >> 16, SD_ARG_HIGH);
+	SET_REG(host, xfrmd_val, SD_TRANS_MODE);
+	cmd_val |= cmd->cmdidx << CMD_IDX_OFFSET | resp << RESP_TYPE_OFFSET;
+	mmc_dbg("%s:Starting CMD%d with ARGUMENT 0x%x\n",
+			__func__, cmd->cmdidx, cmd->cmdarg);
+
+	val = GET_REG(host, SD_PRESENT_STAT_2);
+	mask = CMD_LINE_LEVEL_MASK | DATA_LINE_LEVEL_MASK;
+	if ((val & mask) != mask)
+		mmc_dbg("%s:WARN: CMD/DATA pins are not all high, "
+			"PRE_STAT=0x%04x\n", __func__,
+			GET_REG(host, SD_PRESENT_STAT_2));
+
+	SET_REG(host, cmd_val, SD_COMMAND);
+
+	ret = pxa_sdh_process_irq(host, CMD_COMP);
+	if (!ret && data) {
+		do {
+			ret = pxa_sdh_process_irq(host, (DMA_INT | XFER_COMP));
+			/* If error or xfer completed (in which case
+			 * bytes_xfered is reset to 0) break */
+		} while (host->bytes_xfered);
+	}
+	return ret;
+}
+
+
+
+static int pxa_sdh_cmd_done(struct pxa_sdh_host *host)
+{
+	struct mmc_cmd *cmd = host->cmd;
+	u32 resp[8];
+
+	BUG_ON(!cmd);
+
+	/* get cmd response */
+	resp[0] = GET_REG(host, SD_RESP_0);
+	resp[1] = GET_REG(host, SD_RESP_1);
+	resp[2] = GET_REG(host, SD_RESP_2);
+	resp[3] = GET_REG(host, SD_RESP_3);
+	resp[4] = GET_REG(host, SD_RESP_4);
+	resp[5] = GET_REG(host, SD_RESP_5);
+	resp[6] = GET_REG(host, SD_RESP_6);
+	resp[7] = readb(host->regbase + SD_RESP_7);
+
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[0] = resp[5] >> 8 | resp[6] << 8 | resp[7] << 24;
+		cmd->response[1] = resp[3] >> 8 | resp[4] << 8 | resp[5] << 24;
+		cmd->response[2] = resp[1] >> 8 | resp[2] << 8 | resp[3] << 24;
+		cmd->response[3] = resp[0] << 8 | resp[1] << 24;
+	} else {
+		cmd->response[0] = resp[1] << 16 | resp[0];
+		cmd->response[1] = resp[3] << 16 | resp[2];
+		cmd->response[2] = resp[5] << 16 | resp[4];
+		cmd->response[3] = resp[7] << 16 | resp[6];
+	}
+
+
+	mmc_dbg("%s: resp[0]=0x%x resp[1]=0x%x resp[2]=0x%x resp[3]=0x%x\n",
+			__func__, cmd->response[0], cmd->response[1],
+				cmd->response[2], cmd->response[3]);
+	if (host->error || !host->data)
+		pxa_sdh_finish_request(host);
+
+	return 1;
+}
+
+#ifndef CONFIG_MMC_SDMA
+static void pxa_sdh_pio_data_done(struct pxa_sdh_host *host)
+{
+	struct mmc_data *data = host->data;
+	u16 blk_size = data->blocksize;
+	u16 i = 0;
+
+	if (DATA_DIRECTION_READ(data)) {
+		char *dest = data->dest + host->bytes_xfered;
+		for (i = 0; i < blk_size; i += sizeof(u32)) {
+			*(u32 *)(dest + i) = readl(host->regbase +
+							SD_BUF_DPORT_0);
+		}
+	} else {
+		char *src = (char *) data->src + host->bytes_xfered;
+		for (i = 0; i < blk_size; i += sizeof(u32))
+			writel(*(u32 *)(src +  i),
+				host->regbase + SD_BUF_DPORT_0);
+	}
+
+	if (host->bytes_xfered < host->data_len) {
+		host->bytes_xfered = host->bytes_xfered + blk_size;
+		pxa_sdh_setup_data(host);
+	}
+}
+#endif
+
+static void pxa_sdh_dma_data_done(struct pxa_sdh_host *host)
+{
+	struct mmc_data *data = host->data;
+	int host_dma_bdry_size;
+
+	if (host->bytes_xfered < host->data_len) {
+		host_dma_bdry_size = 0x1000 << (((u16) GET_REG(host,
+				SD_BLOCK_SIZE)) >> HOST_DMA_BDRY_OFFSET);
+		if (host_dma_bdry_size < data->blocksize)
+			host->bytes_xfered = host->bytes_xfered +
+							host_dma_bdry_size;
+		else
+			host->bytes_xfered = host->bytes_xfered +
+							data->blocksize;
+		pxa_sdh_setup_data(host);
+	}
+}
+
+static void pxa_sdh_data_done(struct pxa_sdh_host *host)
+{
+	pxa_sdh_finish_request(host);
+}
+
+static int pxa_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd,
+		struct mmc_data *data)
+{
+	struct pxa_sdh_host *host = mmc->priv;
+	u16 val;
+	u32 timeout = 1000;
+	int ret = 0;
+
+	host->data = data;
+	host->cmd  = cmd;
+
+	if (pxa_sdh_wait_reset(host)) {
+		host->error = 1;
+		pxa_sdh_finish_request(host);
+		return -ETIMEDOUT;
+	}
+	do {
+		val = GET_REG(host, SD_PRESENT_STAT_1);
+		if (!(val & CMD_INHBT_DAT || val & CMD_INHBT_CMD))
+			break;
+		udelay(1);
+	} while (timeout--);
+	if (!timeout) {
+		printf("%s: In busy, unable to start the request.\n",
+				__func__);
+		host->error = 1;
+		pxa_sdh_finish_request(host);
+		return -EBUSY;
+	}
+
+	/* Clear Interrupt/Error status */
+	SET_REG(host, 0xffff, SD_NOR_I_STAT);
+	SET_REG(host, 0xffff, SD_ERR_I_STAT);
+
+	if (data) {
+		mmc_dbg("%s: setup data, blk_sz=%d, blk_cnt=0x%x\n", __func__,
+			data->blocksize, data->blocks);
+		/*
+		 * Set the Host DMA Boundary Buffer
+		 * to Maximum allowed (512 KB)
+		 */
+		SET_REG(host, ((u16)((HOST_DMA_BDRY_MASK & 0x7) <<
+			HOST_DMA_BDRY_OFFSET) | data->blocksize),
+				SD_BLOCK_SIZE);
+		SET_REG(host, data->blocks, SD_BLOCK_COUNT);
+
+		pxa_sdh_setup_data(host);
+	}
+
+	ret = pxa_sdh_start_cmd(host);
+	return ret;
+}
+
+static void pxa_sdh_set_ios(struct mmc *mmc)
+{
+	struct pxa_sdh_host *host = mmc->priv;
+
+	if (pxa_sdh_wait_reset(host))
+		return;
+
+	if (mmc->clock) {
+		unsigned long rate = host->clkrate;
+		unsigned int clk = rate / mmc->clock;
+		unsigned int shift;
+
+		BUG_ON((mmc->clock > mmc->f_max) || (mmc->clock < mmc->f_min));
+		if (mmc->clock >= host->clkrate) {
+			host->clkrt = 0x00;
+		} else {
+			shift = generic_fls(clk);
+			if (rate / clk > mmc->clock)
+				shift++;
+			host->clkrt = 1 << (shift - 2);
+		}
+
+		mmc_dbg("%s: set clkrt = %08x\n", __func__, host->clkrt);
+		pxa_sdh_stop_clock(host);
+		pxa_sdh_start_clock(host);
+
+		if ((host->clkrt == 0 && host->clkrate > 25000000)
+			|| (host->clkrt && (host->clkrate/(host->clkrt*2))
+				 > 25000000)) {
+			SET_REG_BIT(host, HI_SPEED_EN, SD_HOST_CTRL);
+			mmc_dbg("%s: set as HIGH_SPEED.\n", __func__);
+		} else
+			CLEAR_REG_BIT(host, HI_SPEED_EN, SD_HOST_CTRL);
+
+	} else {
+		pxa_sdh_stop_clock(host);
+		if (host->clkrt != CLKRT_OFF)
+			host->clkrt = CLKRT_OFF;
+	}
+
+	SET_REG_BITS(host, SDCLK_SEL_OFFSET, SDCLK_SEL_MASK,
+				SDCLK_SEL_INIT_VAL, SD_CLK_BURST_SET);
+	SET_REG_BITS(host, SD_BUS_VLT_OFFSET, SD_BUS_VLT_MASK,
+			SD_BUS_VLT_18V, SD_HOST_CTRL);
+	SET_REG_BIT(host, SD_BUS_POWER, SD_HOST_CTRL);
+
+	if (mmc->bus_width == MMC_BUS_WIDTH_8) {
+		SET_REG_BIT(host, MMC_CARD, SD_CE_ATA_2);
+		SET_REG_BIT(host, DATA_WIDTH_8BIT, SD_CE_ATA_2);
+			mmc_dbg("%s: set as 8_BIT_MODE.\n", __func__);
+	} else {
+		CLEAR_REG_BIT(host, MMC_CARD, SD_CE_ATA_2);
+		CLEAR_REG_BIT(host, DATA_WIDTH_8BIT, SD_CE_ATA_2);
+		if (mmc->bus_width == MMC_BUS_WIDTH_4) {
+			SET_REG_BIT(host, DATA_WIDTH_4BIT, SD_HOST_CTRL);
+			mmc_dbg("%s: set as 4_BIT_MODE.\n", __func__);
+		} else {
+			CLEAR_REG_BIT(host, DATA_WIDTH_4BIT, SD_HOST_CTRL);
+		}
+	}
+}
+
+static int sdh_init(struct mmc *mmc)
+{
+	struct pxa_sdh_host *host = mmc->priv;
+
+	switch (host->port_num) {
+	case 0:
+		/* Setup the MMC/SD(1) Host Controller Clock */
+		writel(0x19, 0xd4282854);
+		udelay(10);
+		writel(0x1B, 0xd4282854);
+		break;
+	case 1:
+		/* Setup the MMC/SD(2) Host Controller Clock */
+		writel(0x10, 0xd4282858);
+		udelay(10);
+		writel(0x12, 0xd4282858);
+		break;
+	case 2:
+		/* Setup the MMC/SD(3) Host Controller Clock */
+		writel(0x19, 0xd42828e0);
+		udelay(10);
+		writel(0x1b, 0xd42828e0);
+		break;
+	case 3:
+		/* Setup the MMC/SD(4) Host Controller Clock */
+		writel(0x10, 0xd42828e4);
+		udelay(10);
+		writel(0x12, 0xd42828e4);
+		break;
+	}
+
+	/* Enable Interrupt status */
+	SET_REG(host, 0xffff, SD_NOR_I_STAT_EN);
+	SET_REG(host, 0xffff, SD_ERR_I_STAT_EN);
+
+	/* Disable interrupt generation */
+	SET_REG(host, 0, SD_NOR_INT_EN);
+	SET_REG(host, 0, SD_ERR_INT_EN);
+	return 0;
+}
+
+int pxa_sdh_init(bd_t *bis)
+{
+	struct mmc *mmc;
+	struct pxa_sdh_host *host;
+	unsigned int i;
+	unsigned int mmc_base[] = {
+		CONFIG_SYS_MMC_BASE,
+		CONFIG_SYS_MMC1_BASE,
+		CONFIG_SYS_MMC2_BASE,
+		CONFIG_SYS_MMC3_BASE,
+		0
+	};
+
+	/* Initialize the controllers clock for SD1 and SD2 */
+	if (mmc_base[0] != 0xFF || mmc_base[1] != 0xFF) {
+		writel(0xa, 0xd4282854);
+		udelay(10);
+		writel(0xb, 0xd4282854);
+	}
+
+	/* Initialize the controllers clock for SD3 and SD4 */
+	if (mmc_base[2] != 0xFF || mmc_base[3] != 0xFF) {
+		writel(0xa, 0xd42828e0);
+		udelay(10);
+		writel(0xb, 0xd42828e0);
+	}
+
+	for (i = 0; mmc_base[i]; i++) {
+		if (mmc_base[i] == 0xFF)
+			continue;
+
+		mmc = malloc(sizeof(struct mmc));
+		if (!mmc) {
+			printf("mmc malloc fail!!\n");
+			return -1;
+		}
+
+		host = malloc(sizeof(struct pxa_sdh_host));
+		if (!host) {
+			printf("host malloc fail!!!\n");
+			return -1;
+		}
+
+		host->regbase = mmc_base[i];
+		host->clkrate = 48000000;
+		host->clkrt = CLKRT_OFF;
+		host->port_num = i;
+
+		strncpy(mmc->name, "pxa-sdh", 7);
+		mmc->priv = host;
+		mmc->send_cmd = pxa_sdh_request;
+		mmc->set_ios = pxa_sdh_set_ios;
+		mmc->init = sdh_init;
+
+		/*
+		 * Calculate minimum clock rate, rounding up.
+		 */
+		mmc->f_min = (host->clkrate + SD_FREQ_SEL_MASK) /
+				 (SD_FREQ_SEL_MASK + 1);
+		mmc->f_max = host->clkrate / 2;
+		mmc->ocr = 0xffffffff;
+		mmc->voltages = MMC_VDD_27_28|MMC_VDD_28_29;
+#ifndef CONFIG_MMC3
+		mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS;
+#else
+		mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HS;
+#endif
+
+		mmc_register(mmc);
+	}
+
+	return 0;
+}
diff --git a/drivers/mmc/pxa_sdh.h b/drivers/mmc/pxa_sdh.h
new file mode 100644
index 0000000..fc48cd2
--- /dev/null
+++ b/drivers/mmc/pxa_sdh.h
@@ -0,0 +1,241 @@ 
+/**************************************************************************
+ *
+ * Copyright (c) 2009, 2010 Marvell International Ltd.
+ *
+ * This file is part of GNU program.
+ *
+ * GNU 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.
+ *
+ * GNU 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, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ *
+ *************************************************************************/
+
+/* register definitions of PXA SD Host Controller*/
+#define SD_SYS_ADDR_LOW		0x0000	/* DMA System Address Low */
+#define SD_SYS_ADDR_HIGH	0x0002	/* DMA System Address High */
+#define SD_BLOCK_SIZE		0x0004	/* Block Size*/
+#define SD_BLOCK_COUNT		0x0006	/* Block Count */
+#define SD_ARG_LOW		0x0008	/* Command Argument Low */
+#define SD_ARG_HIGH		0x000a	/* Command Argument High */
+#define SD_TRANS_MODE		0x000c	/* Transfer Mode */
+#define SD_COMMAND		0x000e	/* Command */
+#define SD_RESP_0		0x0010	/* Command Response 0 */
+#define SD_RESP_1		0x0012	/* Command Response 1 */
+#define SD_RESP_2		0x0014	/* Command Response 2 */
+#define SD_RESP_3		0x0016	/* Command Response 3 */
+#define SD_RESP_4		0x0018	/* Command Response 4 */
+#define SD_RESP_5		0x001a	/* Command Response 5 */
+#define SD_RESP_6		0x001c	/* Command Response 6 */
+#define SD_RESP_7		0x001e	/* Command Response 7 */
+#define SD_BUF_DPORT_0		0x0020	/* Buffer Data Port 0 */
+#define SD_BUF_DPORT_1		0x0022	/* Buffer Data Port 1 */
+#define SD_PRESENT_STAT_1	0x0024	/* Present State 1 */
+#define SD_PRESENT_STAT_2	0x0026	/* Present State 2 */
+#define SD_HOST_CTRL		0x0028	/* Host Control */
+#define SD_BLOCK_GAP_CTRL	0x002a	/* Block Gap Control */
+#define SD_CLOCK_CNTL		0x002c	/* Clock Control */
+#define SD_TO_CTRL_SW_RST	0x002e	/* Timeout Control/SW Reset */
+#define SD_NOR_I_STAT		0x0030	/* Normal Interrupt Status */
+#define SD_ERR_I_STAT		0x0032	/* Error Interrupt Status */
+#define SD_NOR_I_STAT_EN	0x0034	/* Normal Interrupt Status Enable */
+#define SD_ERR_I_STAT_EN	0x0036	/* Error Interrupt Status Enable */
+#define SD_NOR_INT_EN		0x0038	/* Normal Interrupt Generation Enable */
+#define SD_ERR_INT_EN		0x003a	/* Error Interrupt Generation Enable */
+#define SD_ACMD12_ERR_STAT	0x003c	/* Auto CMD12 Error Status */
+#define SD_CAP_1		0x0040	/* Capabilities 1 */
+#define SD_CAP_3		0x0044	/* Capabilities 3 */
+#define SD_CAP_4		0x0046	/* Capabilities 4 */
+#define SD_MAX_CUR_1		0x0048	/* Maximum Current 1 */
+#define SD_MAX_CUR_2		0x004a	/* Maximum Current 2 */
+#define SD_MAX_CUR_3		0x004c	/* Maximum Current 3 */
+#define SD_MAX_CUR_4		0x004e	/* Maximum Current 4 */
+#define SD_FE_ACMD12_ERR	0x0050	/* Force Event for Auto CMD12 Error */
+#define SD_FE_ERR_STAT		0x0052	/* Force Event for Error Status */
+#define SD_ADMA_ERR_STAT	0x0054	/* ADMA Error Status */
+#define SD_ADMA_SADDR_1		0x0058	/* ADMA System Address[15:0] */
+#define SD_ADMA_SADDR_2		0x005a	/* ADMA System Address[31:16] */
+#define SD_ADMA_SADDR_3		0x005c	/* ADMA System Address[47:32] */
+#define SD_ADMA_SADDR_4		0x005e	/* ADMA System Address[64:48] */
+#define SD_FIFO_PARAM		0x00e0	/* FIRO Parameters */
+#define SD_SPI_MODE		0x00e4	/* SPI Mode */
+#define SD_CLK_BURST_SET	0x00e6	/* Clock and Burst Size Setup */
+#define SD_CE_ATA_1		0x00e8	/* CE-ATA 1 */
+#define SD_CE_ATA_2		0x00ea	/* CE-ATA 2 */
+#define SD_PAD_IO_SETUP		0x00ec	/* Pad I/O Setup */
+#define SD_SLOT_INT_STAT	0x00fc	/* Slot Interrupt Status*/
+#define SD_HOST_CTRL_VER	0x00fe	/* Host Controller Version */
+
+/* SD_BLOCK_SIZE */
+#define HOST_DMA_BDRY_OFFSET	12
+#define HOST_DMA_BDRY_MASK	((u16)0x7)
+#define BLOCK_SIZE_OFFSET	0
+#define BLOCK_SIZE_MASK		((u16)0x0fff)
+#define BLOCK_SIZE_MAX		((u16)0x0800)
+
+/* SD_TRANS_MODE */
+#define MULTI_BLK_SEL		((u16)1 << 5)
+#define TO_HOST_DIR		((u16)1 << 4)
+#define AUTO_CMD12_EN		((u16)1 << 2)
+#define BLK_CNT_EN		((u16)1 << 1)
+#define DMA_EN			((u16)1 << 0)
+
+/* SD_COMMAND */
+#define CMD_IDX_OFFSET		8
+#define CMD_IDX_MASK		((u16)0x3f)
+#define CMD_TYPE_OFFSET		6
+#define CMD_TYPE_MASK		((u16)0x3)
+#define CMD_TYPE_NORMAL		((u16)0x0)
+#define CMD_TYPE_RESUME		((u16)0x1)
+#define CMD_TYPE_SUSPEND	((u16)0x2)
+#define CMD_TYPE_ABORT		((u16)0x3)
+#define DATA_PRESENT		((u16)1 << 5)
+#define CMD_IDX_CHK_EN		((u16)1 << 4)
+#define CMD_CRC_CHK_EN		((u16)1 << 3)
+#define RESP_TYPE_OFFSET	0
+#define RESP_TYPE_MASK		((u16)0x3)
+/* RES_TYPE */
+#define CMD_RESP_NONE		((u16)0x0)
+#define CMD_RESP_136BIT		((u16)0x1)
+#define CMD_RESP_48BIT		((u16)0x2)
+#define CMD_RESP_48BITB		((u16)0x3)
+
+/* SD_PRESENT_STAT_1 */
+#define CMD_INHBT_DAT		((u16)1 << 1)
+#define CMD_INHBT_CMD		((u16)1 << 0)
+
+/* SD_PRESENT_STAT_2 */
+#define CARD_STABLE		((u16)1 << 1)
+#define CARD_DETECTED		((u16)1 << 2)
+#define CARD_PROT		((u16)1 << 3)
+#define DATA_LINE_LEVEL_MASK	((u16)0xf << 4)
+#define CMD_LINE_LEVEL_MASK	((u16)1 << 8)
+
+/* SD_HOST_CTRL */
+#define SD_BUS_VLT_OFFSET	9
+#define SD_BUS_VLT_MASK		((u16)0x7)
+#define SD_BUS_VLT_18V		((u16)0x5)
+#define SD_BUS_VLT_30V		((u16)0x6)
+#define SD_BUS_VLT_33V		((u16)0x7)
+#define SD_BUS_POWER		((u16)1 << 8)
+#define DMA_SEL_OFFSET		3
+#define DMA_SEL_MASK		((u16)0x3)
+#define DMA_SEL_SDMA		((u16)0)
+#define DMA_SEL_ADMA1		((u16)1)
+#define DMA_SEL_ADMA2_32	((u16)2)
+#define DMA_SEL_ADMA2_64	((u16)3)
+#define HI_SPEED_EN		((u16)1 << 2)
+#define DATA_WIDTH_4BIT		((u16)1 << 1)
+
+/* SD_BLOCK_GAP_CTRL */
+#define INT_BLK_GAP		((u16)1 << 3)
+#define RD_WT_CNTL		((u16)1 << 2)
+#define CONT_REQ		((u16)1 << 1)
+#define STOP_AT_BLK_GAP_REQ	((u16)1 << 0)
+
+/* SD_CLOCK_CNTL */
+#define SD_FREQ_SEL_OFFSET	8
+#define SD_FREQ_SEL_MASK	((u16)0xff)
+#define EXT_CLK_EN		((u16)1 << 2)
+#define INT_CLK_STABLE		((u16)1 << 1)
+#define INT_CLK_EN		((u16)1 << 0)
+
+/* SD_TO_CTRL_SW_RST */
+#define SW_RST_DAT		((u16)1 << 10)
+#define SW_RST_CMD		((u16)1 << 9)
+#define SW_RST_ALL		((u16)1 << 8)
+#define DAT_TO_VAL_OFFSET	0
+#define DAT_TO_MASK		((u16)0xf)
+
+/* SD_NOR_I_STAT,  SD_NOR_I_STAT_EN, SD_NOR_INT_EN */
+#define ERR_INT			((u16)1 << 15) /* Error Interrupt*/
+#define CARD_INT		((u16)1 << 8) /* Card Interrupt */
+#define CARD_REM		((u16)1 << 7) /* Card Removal Interrupt */
+#define CARD_INS		((u16)1 << 6) /* Card Insertion Interrupt */
+#define RX_RDY			((u16)1 << 5) /* Buffer Read Ready */
+#define TX_RDY			((u16)1 << 4) /* Buffer Write Ready */
+#define DMA_INT			((u16)1 << 3) /* DMA Interrupt */
+#define BLK_GAP_EVNT		((u16)1 << 2) /* Block Gap Event */
+#define XFER_COMP		((u16)1 << 1) /* Transfer Complete */
+#define CMD_COMP		((u16)1 << 0) /* Command Complete */
+#define SD_NOR_I_STAT_RVD_MASK	((u16)0x7e00) /* Mask for SD_NOR_I_STAT
+						 Reserved Bits[14 :9] */
+#define SD_NOR_INT_EN_RVD_MASK	((u16)0xfe00) /* Mask for SD_NOR_INT_EN/
+					SD_NOR_I_STAT_EN Reserved Bits[15 :9] */
+
+/* SD_ERR_I_STAT,  SD_ERR_I_STAT_EN, SD_ERR_INT_EN */
+#define CRC_STATUS_ERR		((u16)1 << 15) /* CRC Status Error Returned
+					from Card in Write Transaction */
+#define CPL_TO_ERR		((u16)1 << 14) /* Command Completion Signal
+					Timeout Error, for CE-ATA mode only*/
+#define AXI_RESP_ERR		((u16)1 << 13) /* AXI Bus Response Error */
+#define SPI_ERR			((u16)1 << 12) /* SPI Mode Error*/
+#define ADMA_ERR		((u16)1 << 9) /* AMDA Error */
+#define AUTO_CMD12_ERR		((u16)1 << 8) /* Auto CMD12 Error*/
+#define CUR_LIMIT_ERR		((u16)1 << 7) /* Current Limit Error*/
+#define RD_DATA_END_ERR		((u16)1 << 6) /* Read Data End Bit Error*/
+#define RD_DATA_CRC_ERR		((u16)1 << 5) /* Read Data CRC Error*/
+#define DATA_TO_ERR		((u16)1 << 4) /* Data Timeout Error*/
+#define CMD_IDX_ERR		((u16)1 << 3) /* Command Index Error*/
+#define CMD_END_BIT_ERR		((u16)1 << 2) /* Command End Bit Error*/
+#define CMD_CRC_ERR		((u16)1 << 1) /* Command CRC Error*/
+#define CMD_TO_ERR		((u16)1 << 0) /* Command Timeout Error*/
+
+#define SD_ERR_INT_EN_RVD_MASK		((u16)0x0c00)/* Mask for
+			SD_ERR_INT_EN/SD_ERR_I_STAT_EN Reserved Bits[11 :10] */
+
+#define SD_ERR_INT_DATA_ERR_MASK	(DATA_TO_ERR | RD_DATA_CRC_ERR | \
+					RD_DATA_END_ERR) /*DATA Line Error*/
+
+#define SD_ERR_INT_CMD_ERR_MASK		(CMD_TO_ERR | CMD_CRC_ERR | \
+					CMD_END_BIT_ERR | CMD_IDX_ERR)
+					/* CMD Line Error*/
+
+/* SD_FIFO_PARAM */
+#define DIS_PAD_SD_CLK_GATE	((u16)1 << 10) /* Turn on/off Dynamic
+						SD Clock Gating */
+
+/* SD_CLK_BURST_SET */
+#define SDCLK_DELAY_OFFSET	10
+#define SDCLK_DELAY_MASK	((u16)0xf)
+#define SDCLK_DELAY_MAX	((u16)0xf)
+#define SDCLK_SEL_OFFSET	8
+#define SDCLK_SEL_MASK		((u16)0x3)
+#define SDCLK_SEL_INIT_VAL	((u16)0x3)
+#define DMA_BURST_SIZE		((u16)0)
+
+/* SD_SLOT_INT_STAT */
+#define SLOT_INT1		((u16)1<<1)
+#define SLOT_INT0		((u16)1<<0)
+#define SlOT_INT_MASK		(SLOT_INT0 | SLOT_INT1)
+
+/* SD_CE_ATA_2 */
+#define DATA_WIDTH_8BIT		((u16)1 << 8)
+#define MMC_CARD		((u16)1 << 12)
+
+#ifndef CONFIG_SYS_MMC_BASE
+#define CONFIG_SYS_MMC_BASE 0xFF
+#endif
+
+#ifndef CONFIG_SYS_MMC1_BASE
+#define CONFIG_SYS_MMC1_BASE 0xFF
+#endif
+
+#ifndef CONFIG_SYS_MMC2_BASE
+#define CONFIG_SYS_MMC2_BASE 0xFF
+#endif
+
+#ifndef CONFIG_SYS_MMC3_BASE
+#define CONFIG_SYS_MMC3_BASE 0xFF
+#endif
+
diff --git a/include/configs/gplugd.h b/include/configs/gplugd.h
index f0fb057..16fd03e 100644
--- a/include/configs/gplugd.h
+++ b/include/configs/gplugd.h
@@ -109,6 +109,21 @@ 
 #endif /*CONFIG_PXA3XX_SPI*/
 
 /*
+ * SD/MMC & FAT support
+ */
+#define CONFIG_PXASDH
+
+#ifdef CONFIG_PXASDH
+#define CONFIG_CMD_MMC
+#define CONFIG_MMC
+#define CONFIG_CMD_FAT
+#define CONFIG_DOS_PARTITION
+#define CONFIG_GENERIC_MMC
+#define CONFIG_SYS_MMC_BASE     0xd4280000
+#define CONFIG_SYS_MMC1_BASE    0xd4281000
+#endif /* CONFIG_PXASDH */
+
+/*
  * mv-common.h should be defined after CMD configs since it used them
  * to enable certain macros
  */