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.bhar...@einfochips.com> wrote: > This patch provide support for MMC on GuruPlug-Display in uboot. > > Signed-off-by: Ajay Bhargav <ajay.bhar...@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. (kved...@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 > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot