[U-Boot] [PATCH V3 10/11] fsl_esdhc: add support for mx51 processor

The esdhc controller in the mx51 processor is quite the same as the one in some powerpc processors (MPC83xx, MPC85xx). This patches adapts the driver to support the arm mx51.
Signed-off-by: Stefano Babic sbabic@denx.de --- cpu/arm_cortexa8/mx51/Makefile | 2 +- cpu/arm_cortexa8/mx51/speed.c | 38 ++++++++++ drivers/mmc/fsl_esdhc.c | 147 ++++++++++++++++++++++++++------------- include/asm-arm/global_data.h | 3 + include/fsl_esdhc.h | 11 +++- lib_arm/board.c | 3 + 6 files changed, 153 insertions(+), 51 deletions(-) create mode 100644 cpu/arm_cortexa8/mx51/speed.c
diff --git a/cpu/arm_cortexa8/mx51/Makefile b/cpu/arm_cortexa8/mx51/Makefile index 4d82293..7cfaa2c 100644 --- a/cpu/arm_cortexa8/mx51/Makefile +++ b/cpu/arm_cortexa8/mx51/Makefile @@ -27,7 +27,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).a
-COBJS = soc.o clock.o iomux.o timer.o +COBJS = soc.o clock.o iomux.o timer.o speed.o SOBJS = lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/arm_cortexa8/mx51/speed.c b/cpu/arm_cortexa8/mx51/speed.c new file mode 100644 index 0000000..10acbbf --- /dev/null +++ b/cpu/arm_cortexa8/mx51/speed.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/arch/imx-regs.h> + +int get_clocks(void) +{ + DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_FSL_ESDHC + gd->sdhc_clk = mxc_get_clock(MXC_IPG_PERCLK); +#endif + return 0; +} diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index c6e9e6e..112beb6 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -37,7 +37,6 @@ #include <fdt_support.h> #include <asm/io.h>
- DECLARE_GLOBAL_DATA_PTR;
struct fsl_esdhc { @@ -102,7 +101,8 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { uint wml_value; int timeout; - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
wml_value = data->blocksize/4;
@@ -112,24 +112,24 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
wml_value = 0x100000 | wml_value;
- out_be32(®s->dsaddr, (u32)data->dest); + write_reg32(®s->dsaddr, (u32)data->dest); } else { if (wml_value > 0x80) wml_value = 0x80; - if ((in_be32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + if ((read_reg32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); return TIMEOUT; } wml_value = wml_value << 16 | 0x10; - out_be32(®s->dsaddr, (u32)data->src); + write_reg32(®s->dsaddr, (u32)data->src); }
- out_be32(®s->wml, wml_value); + write_reg32(®s->wml, wml_value);
- out_be32(®s->blkattr, data->blocks << 16 | data->blocksize); + write_reg32(®s->blkattr, data->blocks << 16 | data->blocksize);
/* Calculate the timeout period for data transactions */ - timeout = __ilog2(mmc->tran_speed/10); + timeout = fls(mmc->tran_speed/10) - 1; timeout -= 13;
if (timeout > 14) @@ -138,7 +138,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) if (timeout < 0) timeout = 0;
- clrsetbits_be32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); + clrsetbits_reg32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
return 0; } @@ -153,17 +153,20 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp; uint irqstat; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
- out_be32(®s->irqstat, -1); + write_reg32(®s->irqstat, -1);
sync();
/* Wait for the bus to be idle */ - while ((in_be32(®s->prsstat) & PRSSTAT_CICHB) || - (in_be32(®s->prsstat) & PRSSTAT_CIDHB)); + while ((read_reg32(®s->prsstat) & PRSSTAT_CICHB) || + (read_reg32(®s->prsstat) & PRSSTAT_CIDHB)) + ;
- while (in_be32(®s->prsstat) & PRSSTAT_DLA); + while (read_reg32(®s->prsstat) & PRSSTAT_DLA) + ;
/* Wait at least 8 SD clock cycles before the next command */ /* @@ -185,14 +188,15 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) xfertyp = esdhc_xfertyp(cmd, data);
/* Send the command */ - out_be32(®s->cmdarg, cmd->cmdarg); - out_be32(®s->xfertyp, xfertyp); + write_reg32(®s->cmdarg, cmd->cmdarg); + write_reg32(®s->xfertyp, xfertyp);
/* Wait for the command to complete */ - while (!(in_be32(®s->irqstat) & IRQSTAT_CC)); + while (!(read_reg32(®s->irqstat) & IRQSTAT_CC)) + ;
- irqstat = in_be32(®s->irqstat); - out_be32(®s->irqstat, irqstat); + irqstat = read_reg32(®s->irqstat); + write_reg32(®s->irqstat, irqstat);
if (irqstat & CMD_ERR) return COMM_ERR; @@ -204,21 +208,21 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (cmd->resp_type & MMC_RSP_136) { u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
- cmdrsp3 = in_be32(®s->cmdrsp3); - cmdrsp2 = in_be32(®s->cmdrsp2); - cmdrsp1 = in_be32(®s->cmdrsp1); - cmdrsp0 = in_be32(®s->cmdrsp0); + cmdrsp3 = read_reg32(®s->cmdrsp3); + cmdrsp2 = read_reg32(®s->cmdrsp2); + cmdrsp1 = read_reg32(®s->cmdrsp1); + cmdrsp0 = read_reg32(®s->cmdrsp0); cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); cmd->response[3] = (cmdrsp0 << 8); } else - cmd->response[0] = in_be32(®s->cmdrsp0); + cmd->response[0] = read_reg32(®s->cmdrsp0);
/* Wait until all of the blocks are transferred */ if (data) { do { - irqstat = in_be32(®s->irqstat); + irqstat = read_reg32(®s->irqstat);
if (irqstat & DATA_ERR) return COMM_ERR; @@ -226,10 +230,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (irqstat & IRQSTAT_DTOE) return TIMEOUT; } while (!(irqstat & IRQSTAT_TC) && - (in_be32(®s->prsstat) & PRSSTAT_DLA)); + (read_reg32(®s->prsstat) & PRSSTAT_DLA)); }
- out_be32(®s->irqstat, -1); + write_reg32(®s->irqstat, -1);
return 0; } @@ -238,9 +242,13 @@ void set_sysctl(struct mmc *mmc, uint clock) { int sdhc_clk = gd->sdhc_clk; int div, pre_div; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; uint clk;
+ if (clock < mmc->f_min) + clock = mmc->f_min; + if (sdhc_clk / 16 > clock) { for (pre_div = 2; pre_div < 256; pre_div *= 2) if ((sdhc_clk / pre_div) <= (clock * 16)) @@ -257,67 +265,100 @@ void set_sysctl(struct mmc *mmc, uint clock)
clk = (pre_div << 8) | (div << 4);
- clrsetbits_be32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); + /* On imx the clock must be stopped before changing frequency */ + clrbits_reg32(®s->sysctl, SYSCTL_CKEN); + + clrsetbits_reg32(®s->sysctl, SYSCTL_CLOCK_MASK, clk);
udelay(10000);
- setbits_be32(®s->sysctl, SYSCTL_PEREN); + setbits_reg32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); }
static void esdhc_set_ios(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
/* Set the clock speed */ set_sysctl(mmc, mmc->clock);
/* Set the bus width */ - clrbits_be32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); + clrbits_reg32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
if (mmc->bus_width == 4) - setbits_be32(®s->proctl, PROCTL_DTW_4); + setbits_reg32(®s->proctl, PROCTL_DTW_4); else if (mmc->bus_width == 8) - setbits_be32(®s->proctl, PROCTL_DTW_8); + setbits_reg32(®s->proctl, PROCTL_DTW_8); + }
static int esdhc_init(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; + int ret = 0; + u8 card_absent;
/* Enable cache snooping */ - out_be32(®s->scr, 0x00000040); + if (cfg && !cfg->no_snoop) + write_reg32(®s->scr, 0x00000040);
- out_be32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); + /* Reset the entire host controller */ + write_reg32(®s->sysctl, SYSCTL_RSTA); + + /* Wait until the controller is available */ + while ((read_reg32(®s->sysctl) & SYSCTL_RSTA) && --timeout) + udelay(1000); + + write_reg32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
/* Set the initial clock speed */ set_sysctl(mmc, 400000);
/* Disable the BRR and BWR bits in IRQSTAT */ - clrbits_be32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); + clrbits_reg32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
/* Put the PROCTL reg back to the default */ - out_be32(®s->proctl, PROCTL_INIT); + write_reg32(®s->proctl, PROCTL_INIT);
- while (!(in_be32(®s->prsstat) & PRSSTAT_CINS) && --timeout) - udelay(1000); + /* Set timout to the maximum value */ + clrsetbits_reg32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
- if (timeout <= 0) - return NO_CARD_ERR; + /* Check if there is a callback for detecting the card */ + if (board_mmc_getcd(&card_absent, mmc)) { + timeout = 1000; + while (!(read_reg32(®s->prsstat) & PRSSTAT_CINS) && + --timeout) + udelay(1000);
- return 0; + if (timeout <= 0) + ret = NO_CARD_ERR; + } else { + if (card_absent) + ret = NO_CARD_ERR; + } + + return ret; }
-static int esdhc_initialize(bd_t *bis) +int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { - struct fsl_esdhc *regs = (struct fsl_esdhc *)CONFIG_SYS_FSL_ESDHC_ADDR; + int sdhc_clk = gd->sdhc_clk; + struct fsl_esdhc *regs; struct mmc *mmc; u32 caps;
+ if (!cfg) + return -1; + mmc = malloc(sizeof(struct mmc));
sprintf(mmc->name, "FSL_ESDHC"); - mmc->priv = regs; + regs = (struct fsl_esdhc *)cfg->esdhc_base; + + mmc->priv = cfg; mmc->send_cmd = esdhc_send_cmd; mmc->set_ios = esdhc_set_ios; mmc->init = esdhc_init; @@ -337,7 +378,7 @@ static int esdhc_initialize(bd_t *bis) mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
mmc->f_min = 400000; - mmc->f_max = MIN(gd->sdhc_clk, 50000000); + mmc->f_max = MIN(sdhc_clk, 50000000);
mmc_register(mmc);
@@ -346,9 +387,16 @@ static int esdhc_initialize(bd_t *bis)
int fsl_esdhc_mmc_init(bd_t *bis) { - return esdhc_initialize(bis); + struct fsl_esdhc_cfg *cfg; + + cfg = malloc(sizeof(struct fsl_esdhc_cfg)); + memset(cfg, 0, sizeof(struct fsl_esdhc_cfg)); + cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; + printf("HERE NOT!!!\n"); + return fsl_esdhc_initialize(bis, cfg); }
+#ifdef CONFIG_OF_LIBFDT void fdt_fixup_esdhc(void *blob, bd_t *bd) { const char *compat = "fsl,esdhc"; @@ -365,3 +413,4 @@ out: do_fixup_by_compat(blob, compat, "status", status, strlen(status) + 1, 1); } +#endif diff --git a/include/asm-arm/global_data.h b/include/asm-arm/global_data.h index 8115a24..02cfe45 100644 --- a/include/asm-arm/global_data.h +++ b/include/asm-arm/global_data.h @@ -44,6 +44,9 @@ typedef struct global_data { #ifdef CONFIG_VFD unsigned char vfd_type; /* display type */ #endif +#ifdef CONFIG_FSL_ESDHC + unsigned long sdhc_clk; +#endif #if 0 unsigned long cpu_clk; /* CPU clock in Hz! */ unsigned long bus_clk; diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index 89b8304..dc177de 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -32,7 +32,9 @@ #define SYSCTL 0x0002e02c #define SYSCTL_INITA 0x08000000 #define SYSCTL_TIMEOUT_MASK 0x000f0000 -#define SYSCTL_CLOCK_MASK 0x00000fff +#define SYSCTL_CLOCK_MASK 0x0000ffff +#define SYSCTL_RSTA 0x01000000 +#define SYSCTL_CKEN 0x00000008 #define SYSCTL_PEREN 0x00000004 #define SYSCTL_HCKEN 0x00000002 #define SYSCTL_IPGEN 0x00000001 @@ -142,8 +144,15 @@ #define ESDHC_HOSTCAPBLT_DMAS 0x00400000 #define ESDHC_HOSTCAPBLT_HSS 0x00200000
+struct fsl_esdhc_cfg { + u32 esdhc_base; + u32 no_snoop; + u32 clk_enable; +}; + #ifdef CONFIG_FSL_ESDHC int fsl_esdhc_mmc_init(bd_t *bis); +int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg); void fdt_fixup_esdhc(void *blob, bd_t *bd); #else static inline int fsl_esdhc_mmc_init(bd_t *bis) { return -ENOSYS; } diff --git a/lib_arm/board.c b/lib_arm/board.c index e148739..f5660a9 100644 --- a/lib_arm/board.c +++ b/lib_arm/board.c @@ -243,6 +243,9 @@ init_fnc_t *init_sequence[] = { interrupt_init, /* set up exceptions */ #endif timer_init, /* initialize timer */ +#ifdef CONFIG_FSL_ESDHC + get_clocks, +#endif env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */

The esdhc controller in the mx51 processor is quite the same as the one in some powerpc processors (MPC83xx, MPC85xx). This patches adapts the driver to support the arm mx51.
Signed-off-by: Stefano Babic sbabic@denx.de --- cpu/arm_cortexa8/mx51/Makefile | 2 +- cpu/arm_cortexa8/mx51/speed.c | 38 ++++++++++ drivers/mmc/fsl_esdhc.c | 149 +++++++++++++++++++++++++++------------- include/asm-arm/global_data.h | 3 + include/fsl_esdhc.h | 27 +++++++ lib_arm/board.c | 3 + 6 files changed, 173 insertions(+), 49 deletions(-) create mode 100644 cpu/arm_cortexa8/mx51/speed.c
diff --git a/cpu/arm_cortexa8/mx51/Makefile b/cpu/arm_cortexa8/mx51/Makefile index 4d82293..7cfaa2c 100644 --- a/cpu/arm_cortexa8/mx51/Makefile +++ b/cpu/arm_cortexa8/mx51/Makefile @@ -27,7 +27,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).a
-COBJS = soc.o clock.o iomux.o timer.o +COBJS = soc.o clock.o iomux.o timer.o speed.o SOBJS = lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/arm_cortexa8/mx51/speed.c b/cpu/arm_cortexa8/mx51/speed.c new file mode 100644 index 0000000..10acbbf --- /dev/null +++ b/cpu/arm_cortexa8/mx51/speed.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/arch/imx-regs.h> + +int get_clocks(void) +{ + DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_FSL_ESDHC + gd->sdhc_clk = mxc_get_clock(MXC_IPG_PERCLK); +#endif + return 0; +} diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index c6e9e6e..e665b5e 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -37,7 +37,6 @@ #include <fdt_support.h> #include <asm/io.h>
- DECLARE_GLOBAL_DATA_PTR;
struct fsl_esdhc { @@ -102,7 +101,8 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { uint wml_value; int timeout; - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
wml_value = data->blocksize/4;
@@ -112,24 +112,24 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
wml_value = 0x100000 | wml_value;
- out_be32(®s->dsaddr, (u32)data->dest); + esdhc_write32(®s->dsaddr, (u32)data->dest); } else { if (wml_value > 0x80) wml_value = 0x80; - if ((in_be32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); return TIMEOUT; } wml_value = wml_value << 16 | 0x10; - out_be32(®s->dsaddr, (u32)data->src); + esdhc_write32(®s->dsaddr, (u32)data->src); }
- out_be32(®s->wml, wml_value); + esdhc_write32(®s->wml, wml_value);
- out_be32(®s->blkattr, data->blocks << 16 | data->blocksize); + esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize);
/* Calculate the timeout period for data transactions */ - timeout = __ilog2(mmc->tran_speed/10); + timeout = fls(mmc->tran_speed/10) - 1; timeout -= 13;
if (timeout > 14) @@ -138,7 +138,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) if (timeout < 0) timeout = 0;
- clrsetbits_be32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
return 0; } @@ -153,17 +153,20 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp; uint irqstat; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
- out_be32(®s->irqstat, -1); + esdhc_write32(®s->irqstat, -1);
sync();
/* Wait for the bus to be idle */ - while ((in_be32(®s->prsstat) & PRSSTAT_CICHB) || - (in_be32(®s->prsstat) & PRSSTAT_CIDHB)); + while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || + (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) + ;
- while (in_be32(®s->prsstat) & PRSSTAT_DLA); + while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) + ;
/* Wait at least 8 SD clock cycles before the next command */ /* @@ -185,14 +188,15 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) xfertyp = esdhc_xfertyp(cmd, data);
/* Send the command */ - out_be32(®s->cmdarg, cmd->cmdarg); - out_be32(®s->xfertyp, xfertyp); + esdhc_write32(®s->cmdarg, cmd->cmdarg); + esdhc_write32(®s->xfertyp, xfertyp);
/* Wait for the command to complete */ - while (!(in_be32(®s->irqstat) & IRQSTAT_CC)); + while (!(esdhc_read32(®s->irqstat) & IRQSTAT_CC)) + ;
- irqstat = in_be32(®s->irqstat); - out_be32(®s->irqstat, irqstat); + irqstat = esdhc_read32(®s->irqstat); + esdhc_write32(®s->irqstat, irqstat);
if (irqstat & CMD_ERR) return COMM_ERR; @@ -204,21 +208,21 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (cmd->resp_type & MMC_RSP_136) { u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
- cmdrsp3 = in_be32(®s->cmdrsp3); - cmdrsp2 = in_be32(®s->cmdrsp2); - cmdrsp1 = in_be32(®s->cmdrsp1); - cmdrsp0 = in_be32(®s->cmdrsp0); + cmdrsp3 = esdhc_read32(®s->cmdrsp3); + cmdrsp2 = esdhc_read32(®s->cmdrsp2); + cmdrsp1 = esdhc_read32(®s->cmdrsp1); + cmdrsp0 = esdhc_read32(®s->cmdrsp0); cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); cmd->response[3] = (cmdrsp0 << 8); } else - cmd->response[0] = in_be32(®s->cmdrsp0); + cmd->response[0] = esdhc_read32(®s->cmdrsp0);
/* Wait until all of the blocks are transferred */ if (data) { do { - irqstat = in_be32(®s->irqstat); + irqstat = esdhc_read32(®s->irqstat);
if (irqstat & DATA_ERR) return COMM_ERR; @@ -226,10 +230,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (irqstat & IRQSTAT_DTOE) return TIMEOUT; } while (!(irqstat & IRQSTAT_TC) && - (in_be32(®s->prsstat) & PRSSTAT_DLA)); + (esdhc_read32(®s->prsstat) & PRSSTAT_DLA)); }
- out_be32(®s->irqstat, -1); + esdhc_write32(®s->irqstat, -1);
return 0; } @@ -238,9 +242,13 @@ void set_sysctl(struct mmc *mmc, uint clock) { int sdhc_clk = gd->sdhc_clk; int div, pre_div; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; uint clk;
+ if (clock < mmc->f_min) + clock = mmc->f_min; + if (sdhc_clk / 16 > clock) { for (pre_div = 2; pre_div < 256; pre_div *= 2) if ((sdhc_clk / pre_div) <= (clock * 16)) @@ -257,67 +265,105 @@ void set_sysctl(struct mmc *mmc, uint clock)
clk = (pre_div << 8) | (div << 4);
- clrsetbits_be32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); + /* On imx the clock must be stopped before changing frequency */ + if (cfg->clk_enable) + esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); + + esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk);
udelay(10000);
- setbits_be32(®s->sysctl, SYSCTL_PEREN); + clk = SYSCTL_PEREN; + /* On imx systems the clock must be explicitely enabled */ + if (cfg->clk_enable) + clk |= SYSCTL_CKEN; + + esdhc_setbits32(®s->sysctl, clk); }
static void esdhc_set_ios(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
/* Set the clock speed */ set_sysctl(mmc, mmc->clock);
/* Set the bus width */ - clrbits_be32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); + esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
if (mmc->bus_width == 4) - setbits_be32(®s->proctl, PROCTL_DTW_4); + esdhc_setbits32(®s->proctl, PROCTL_DTW_4); else if (mmc->bus_width == 8) - setbits_be32(®s->proctl, PROCTL_DTW_8); + esdhc_setbits32(®s->proctl, PROCTL_DTW_8); + }
static int esdhc_init(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; + int ret = 0; + u8 card_absent;
/* Enable cache snooping */ - out_be32(®s->scr, 0x00000040); + if (cfg && !cfg->no_snoop) + esdhc_write32(®s->scr, 0x00000040); + + /* Reset the entire host controller */ + esdhc_write32(®s->sysctl, SYSCTL_RSTA); + + /* Wait until the controller is available */ + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) + udelay(1000);
- out_be32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); + esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
/* Set the initial clock speed */ set_sysctl(mmc, 400000);
/* Disable the BRR and BWR bits in IRQSTAT */ - clrbits_be32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); + esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
/* Put the PROCTL reg back to the default */ - out_be32(®s->proctl, PROCTL_INIT); + esdhc_write32(®s->proctl, PROCTL_INIT);
- while (!(in_be32(®s->prsstat) & PRSSTAT_CINS) && --timeout) - udelay(1000); + /* Set timout to the maximum value */ + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
- if (timeout <= 0) - return NO_CARD_ERR; + /* Check if there is a callback for detecting the card */ + if (board_mmc_getcd(&card_absent, mmc)) { + timeout = 1000; + while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && + --timeout) + udelay(1000);
- return 0; + if (timeout <= 0) + ret = NO_CARD_ERR; + } else { + if (card_absent) + ret = NO_CARD_ERR; + } + + return ret; }
-static int esdhc_initialize(bd_t *bis) +int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { - struct fsl_esdhc *regs = (struct fsl_esdhc *)CONFIG_SYS_FSL_ESDHC_ADDR; + struct fsl_esdhc *regs; struct mmc *mmc; u32 caps;
+ if (!cfg) + return -1; + mmc = malloc(sizeof(struct mmc));
sprintf(mmc->name, "FSL_ESDHC"); - mmc->priv = regs; + regs = (struct fsl_esdhc *)cfg->esdhc_base; + + mmc->priv = cfg; mmc->send_cmd = esdhc_send_cmd; mmc->set_ios = esdhc_set_ios; mmc->init = esdhc_init; @@ -346,9 +392,15 @@ static int esdhc_initialize(bd_t *bis)
int fsl_esdhc_mmc_init(bd_t *bis) { - return esdhc_initialize(bis); + struct fsl_esdhc_cfg *cfg; + + cfg = malloc(sizeof(struct fsl_esdhc_cfg)); + memset(cfg, 0, sizeof(struct fsl_esdhc_cfg)); + cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; + return fsl_esdhc_initialize(bis, cfg); }
+#ifdef CONFIG_OF_LIBFDT void fdt_fixup_esdhc(void *blob, bd_t *bd) { const char *compat = "fsl,esdhc"; @@ -365,3 +417,4 @@ out: do_fixup_by_compat(blob, compat, "status", status, strlen(status) + 1, 1); } +#endif diff --git a/include/asm-arm/global_data.h b/include/asm-arm/global_data.h index 8115a24..02cfe45 100644 --- a/include/asm-arm/global_data.h +++ b/include/asm-arm/global_data.h @@ -44,6 +44,9 @@ typedef struct global_data { #ifdef CONFIG_VFD unsigned char vfd_type; /* display type */ #endif +#ifdef CONFIG_FSL_ESDHC + unsigned long sdhc_clk; +#endif #if 0 unsigned long cpu_clk; /* CPU clock in Hz! */ unsigned long bus_clk; diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index eac6a2b..01b7dec 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -27,12 +27,15 @@ #define __FSL_ESDHC_H__
#include <asm/errno.h> +#include <asm/byteorder.h>
/* FSL eSDHC-specific constants */ #define SYSCTL 0x0002e02c #define SYSCTL_INITA 0x08000000 #define SYSCTL_TIMEOUT_MASK 0x000f0000 #define SYSCTL_CLOCK_MASK 0x0000fff0 +#define SYSCTL_RSTA 0x01000000 +#define SYSCTL_CKEN 0x00000008 #define SYSCTL_PEREN 0x00000004 #define SYSCTL_HCKEN 0x00000002 #define SYSCTL_IPGEN 0x00000001 @@ -142,8 +145,32 @@ #define ESDHC_HOSTCAPBLT_DMAS 0x00400000 #define ESDHC_HOSTCAPBLT_HSS 0x00200000
+struct fsl_esdhc_cfg { + u32 esdhc_base; + u32 no_snoop; + u32 clk_enable; +}; + +/* Select the correct accessors depending on endianess */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define esdhc_read32 in_le32 +#define esdhc_write32 out_le32 +#define esdhc_clrsetbits32 clrsetbits_le32 +#define esdhc_clrbits32 clrbits_le32 +#define esdhc_setbits32 setbits_le32 +#elif __BYTE_ORDER == __BIG_ENDIAN +#define esdhc_read32 in_be32 +#define esdhc_write32 out_be32 +#define esdhc_clrsetbits32 clrsetbits_be32 +#define esdhc_clrbits32 clrbits_be32 +#define esdhc_setbits32 setbits_be32 +#else +#error "Endianess is not defined: please fix to continue" +#endif + #ifdef CONFIG_FSL_ESDHC int fsl_esdhc_mmc_init(bd_t *bis); +int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg); void fdt_fixup_esdhc(void *blob, bd_t *bd); #else static inline int fsl_esdhc_mmc_init(bd_t *bis) { return -ENOSYS; } diff --git a/lib_arm/board.c b/lib_arm/board.c index e148739..f5660a9 100644 --- a/lib_arm/board.c +++ b/lib_arm/board.c @@ -243,6 +243,9 @@ init_fnc_t *init_sequence[] = { interrupt_init, /* set up exceptions */ #endif timer_init, /* initialize timer */ +#ifdef CONFIG_FSL_ESDHC + get_clocks, +#endif env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */

Hi Stefano,
Have you tested mmc on mx51 board?
The original esdhc uses PIO mode in function esdhc_send_cmd(), while fsl_esdhc uses DMA mode.
I hasn't tested DMA mode before.
BTW: have you considered add the feature to save environment data to mmc?
Thanks~~
Yours Terry
-----Original Message----- From: u-boot-bounces@lists.denx.de [mailto:u-boot-bounces@lists.denx.de] On Behalf Of Stefano Babic Sent: 2010年2月5日 22:11 To: u-boot@lists.denx.de Cc: afleming@gmail.com; Phillips Kim-R1AAHA Subject: [U-Boot] [PATCH V4 10/11] fsl_esdhc: add support for mx51 processor
The esdhc controller in the mx51 processor is quite the same as the one in some powerpc processors (MPC83xx, MPC85xx). This patches adapts the driver to support the arm mx51.
Signed-off-by: Stefano Babic sbabic@denx.de --- cpu/arm_cortexa8/mx51/Makefile | 2 +- cpu/arm_cortexa8/mx51/speed.c | 38 ++++++++++ drivers/mmc/fsl_esdhc.c | 149 +++++++++++++++++++++++++++------------- include/asm-arm/global_data.h | 3 + include/fsl_esdhc.h | 27 +++++++ lib_arm/board.c | 3 + 6 files changed, 173 insertions(+), 49 deletions(-) create mode 100644 cpu/arm_cortexa8/mx51/speed.c
diff --git a/cpu/arm_cortexa8/mx51/Makefile b/cpu/arm_cortexa8/mx51/Makefile index 4d82293..7cfaa2c 100644 --- a/cpu/arm_cortexa8/mx51/Makefile +++ b/cpu/arm_cortexa8/mx51/Makefile @@ -27,7 +27,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).a
-COBJS = soc.o clock.o iomux.o timer.o +COBJS = soc.o clock.o iomux.o timer.o speed.o SOBJS = lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/arm_cortexa8/mx51/speed.c b/cpu/arm_cortexa8/mx51/speed.c new file mode 100644 index 0000000..10acbbf --- /dev/null +++ b/cpu/arm_cortexa8/mx51/speed.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/arch/imx-regs.h> + +int get_clocks(void) +{ + DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_FSL_ESDHC + gd->sdhc_clk = mxc_get_clock(MXC_IPG_PERCLK); #endif + return 0; +} diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index c6e9e6e..e665b5e 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -37,7 +37,6 @@ #include <fdt_support.h> #include <asm/io.h>
- DECLARE_GLOBAL_DATA_PTR;
struct fsl_esdhc { @@ -102,7 +101,8 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { uint wml_value; int timeout; - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
wml_value = data->blocksize/4;
@@ -112,24 +112,24 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
wml_value = 0x100000 | wml_value;
- out_be32(®s->dsaddr, (u32)data->dest); + esdhc_write32(®s->dsaddr, (u32)data->dest); } else { if (wml_value > 0x80) wml_value = 0x80; - if ((in_be32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); return TIMEOUT; } wml_value = wml_value << 16 | 0x10; - out_be32(®s->dsaddr, (u32)data->src); + esdhc_write32(®s->dsaddr, (u32)data->src); }
- out_be32(®s->wml, wml_value); + esdhc_write32(®s->wml, wml_value);
- out_be32(®s->blkattr, data->blocks << 16 | data->blocksize); + esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize);
/* Calculate the timeout period for data transactions */ - timeout = __ilog2(mmc->tran_speed/10); + timeout = fls(mmc->tran_speed/10) - 1; timeout -= 13;
if (timeout > 14) @@ -138,7 +138,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) if (timeout < 0) timeout = 0;
- clrsetbits_be32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
return 0; } @@ -153,17 +153,20 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp; uint irqstat; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
- out_be32(®s->irqstat, -1); + esdhc_write32(®s->irqstat, -1);
sync();
/* Wait for the bus to be idle */ - while ((in_be32(®s->prsstat) & PRSSTAT_CICHB) || - (in_be32(®s->prsstat) & PRSSTAT_CIDHB)); + while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || + (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) + ;
- while (in_be32(®s->prsstat) & PRSSTAT_DLA); + while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) + ;
/* Wait at least 8 SD clock cycles before the next command */ /* @@ -185,14 +188,15 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) xfertyp = esdhc_xfertyp(cmd, data);
/* Send the command */ - out_be32(®s->cmdarg, cmd->cmdarg); - out_be32(®s->xfertyp, xfertyp); + esdhc_write32(®s->cmdarg, cmd->cmdarg); + esdhc_write32(®s->xfertyp, xfertyp);
/* Wait for the command to complete */ - while (!(in_be32(®s->irqstat) & IRQSTAT_CC)); + while (!(esdhc_read32(®s->irqstat) & IRQSTAT_CC)) + ;
- irqstat = in_be32(®s->irqstat); - out_be32(®s->irqstat, irqstat); + irqstat = esdhc_read32(®s->irqstat); + esdhc_write32(®s->irqstat, irqstat);
if (irqstat & CMD_ERR) return COMM_ERR; @@ -204,21 +208,21 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (cmd->resp_type & MMC_RSP_136) { u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
- cmdrsp3 = in_be32(®s->cmdrsp3); - cmdrsp2 = in_be32(®s->cmdrsp2); - cmdrsp1 = in_be32(®s->cmdrsp1); - cmdrsp0 = in_be32(®s->cmdrsp0); + cmdrsp3 = esdhc_read32(®s->cmdrsp3); + cmdrsp2 = esdhc_read32(®s->cmdrsp2); + cmdrsp1 = esdhc_read32(®s->cmdrsp1); + cmdrsp0 = esdhc_read32(®s->cmdrsp0); cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); cmd->response[3] = (cmdrsp0 << 8); } else - cmd->response[0] = in_be32(®s->cmdrsp0); + cmd->response[0] = esdhc_read32(®s->cmdrsp0);
/* Wait until all of the blocks are transferred */ if (data) { do { - irqstat = in_be32(®s->irqstat); + irqstat = esdhc_read32(®s->irqstat);
if (irqstat & DATA_ERR) return COMM_ERR; @@ -226,10 +230,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (irqstat & IRQSTAT_DTOE) return TIMEOUT; } while (!(irqstat & IRQSTAT_TC) && - (in_be32(®s->prsstat) & PRSSTAT_DLA)); + (esdhc_read32(®s->prsstat) & PRSSTAT_DLA)); }
- out_be32(®s->irqstat, -1); + esdhc_write32(®s->irqstat, -1);
return 0; } @@ -238,9 +242,13 @@ void set_sysctl(struct mmc *mmc, uint clock) { int sdhc_clk = gd->sdhc_clk; int div, pre_div; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; uint clk;
+ if (clock < mmc->f_min) + clock = mmc->f_min; + if (sdhc_clk / 16 > clock) { for (pre_div = 2; pre_div < 256; pre_div *= 2) if ((sdhc_clk / pre_div) <= (clock * 16)) @@ -257,67 +265,105 @@ void set_sysctl(struct mmc *mmc, uint clock)
clk = (pre_div << 8) | (div << 4);
- clrsetbits_be32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); + /* On imx the clock must be stopped before changing frequency */ + if (cfg->clk_enable) + esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); + + esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk);
udelay(10000);
- setbits_be32(®s->sysctl, SYSCTL_PEREN); + clk = SYSCTL_PEREN; + /* On imx systems the clock must be explicitely enabled */ + if (cfg->clk_enable) + clk |= SYSCTL_CKEN; + + esdhc_setbits32(®s->sysctl, clk); }
static void esdhc_set_ios(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
/* Set the clock speed */ set_sysctl(mmc, mmc->clock);
/* Set the bus width */ - clrbits_be32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); + esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
if (mmc->bus_width == 4) - setbits_be32(®s->proctl, PROCTL_DTW_4); + esdhc_setbits32(®s->proctl, PROCTL_DTW_4); else if (mmc->bus_width == 8) - setbits_be32(®s->proctl, PROCTL_DTW_8); + esdhc_setbits32(®s->proctl, PROCTL_DTW_8); + }
static int esdhc_init(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; + int ret = 0; + u8 card_absent;
/* Enable cache snooping */ - out_be32(®s->scr, 0x00000040); + if (cfg && !cfg->no_snoop) + esdhc_write32(®s->scr, 0x00000040); + + /* Reset the entire host controller */ + esdhc_write32(®s->sysctl, SYSCTL_RSTA); + + /* Wait until the controller is available */ + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) + udelay(1000);
- out_be32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); + esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
/* Set the initial clock speed */ set_sysctl(mmc, 400000);
/* Disable the BRR and BWR bits in IRQSTAT */ - clrbits_be32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); + esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
/* Put the PROCTL reg back to the default */ - out_be32(®s->proctl, PROCTL_INIT); + esdhc_write32(®s->proctl, PROCTL_INIT);
- while (!(in_be32(®s->prsstat) & PRSSTAT_CINS) && --timeout) - udelay(1000); + /* Set timout to the maximum value */ + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
- if (timeout <= 0) - return NO_CARD_ERR; + /* Check if there is a callback for detecting the card */ + if (board_mmc_getcd(&card_absent, mmc)) { + timeout = 1000; + while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && + --timeout) + udelay(1000);
- return 0; + if (timeout <= 0) + ret = NO_CARD_ERR; + } else { + if (card_absent) + ret = NO_CARD_ERR; + } + + return ret; }
-static int esdhc_initialize(bd_t *bis) +int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { - struct fsl_esdhc *regs = (struct fsl_esdhc *)CONFIG_SYS_FSL_ESDHC_ADDR; + struct fsl_esdhc *regs; struct mmc *mmc; u32 caps;
+ if (!cfg) + return -1; + mmc = malloc(sizeof(struct mmc));
sprintf(mmc->name, "FSL_ESDHC"); - mmc->priv = regs; + regs = (struct fsl_esdhc *)cfg->esdhc_base; + + mmc->priv = cfg; mmc->send_cmd = esdhc_send_cmd; mmc->set_ios = esdhc_set_ios; mmc->init = esdhc_init; @@ -346,9 +392,15 @@ static int esdhc_initialize(bd_t *bis)
int fsl_esdhc_mmc_init(bd_t *bis) { - return esdhc_initialize(bis); + struct fsl_esdhc_cfg *cfg; + + cfg = malloc(sizeof(struct fsl_esdhc_cfg)); + memset(cfg, 0, sizeof(struct fsl_esdhc_cfg)); + cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; + return fsl_esdhc_initialize(bis, cfg); }
+#ifdef CONFIG_OF_LIBFDT void fdt_fixup_esdhc(void *blob, bd_t *bd) { const char *compat = "fsl,esdhc"; @@ -365,3 +417,4 @@ out: do_fixup_by_compat(blob, compat, "status", status, strlen(status) + 1, 1); } +#endif diff --git a/include/asm-arm/global_data.h b/include/asm-arm/global_data.h index 8115a24..02cfe45 100644 --- a/include/asm-arm/global_data.h +++ b/include/asm-arm/global_data.h @@ -44,6 +44,9 @@ typedef struct global_data { #ifdef CONFIG_VFD unsigned char vfd_type; /* display type */ #endif +#ifdef CONFIG_FSL_ESDHC + unsigned long sdhc_clk; +#endif #if 0 unsigned long cpu_clk; /* CPU clock in Hz! */ unsigned long bus_clk; diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index eac6a2b..01b7dec 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -27,12 +27,15 @@ #define __FSL_ESDHC_H__
#include <asm/errno.h> +#include <asm/byteorder.h>
/* FSL eSDHC-specific constants */ #define SYSCTL 0x0002e02c #define SYSCTL_INITA 0x08000000 #define SYSCTL_TIMEOUT_MASK 0x000f0000 #define SYSCTL_CLOCK_MASK 0x0000fff0 +#define SYSCTL_RSTA 0x01000000 +#define SYSCTL_CKEN 0x00000008 #define SYSCTL_PEREN 0x00000004 #define SYSCTL_HCKEN 0x00000002 #define SYSCTL_IPGEN 0x00000001 @@ -142,8 +145,32 @@ #define ESDHC_HOSTCAPBLT_DMAS 0x00400000 #define ESDHC_HOSTCAPBLT_HSS 0x00200000
+struct fsl_esdhc_cfg { + u32 esdhc_base; + u32 no_snoop; + u32 clk_enable; +}; + +/* Select the correct accessors depending on endianess */ #if +__BYTE_ORDER == __LITTLE_ENDIAN +#define esdhc_read32 in_le32 +#define esdhc_write32 out_le32 +#define esdhc_clrsetbits32 clrsetbits_le32 +#define esdhc_clrbits32 clrbits_le32 +#define esdhc_setbits32 setbits_le32 +#elif __BYTE_ORDER == __BIG_ENDIAN +#define esdhc_read32 in_be32 +#define esdhc_write32 out_be32 +#define esdhc_clrsetbits32 clrsetbits_be32 +#define esdhc_clrbits32 clrbits_be32 +#define esdhc_setbits32 setbits_be32 +#else +#error "Endianess is not defined: please fix to continue" +#endif + #ifdef CONFIG_FSL_ESDHC int fsl_esdhc_mmc_init(bd_t *bis); +int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg); void fdt_fixup_esdhc(void *blob, bd_t *bd); #else static inline int fsl_esdhc_mmc_init(bd_t *bis) { return -ENOSYS; } diff --git a/lib_arm/board.c b/lib_arm/board.c index e148739..f5660a9 100644 --- a/lib_arm/board.c +++ b/lib_arm/board.c @@ -243,6 +243,9 @@ init_fnc_t *init_sequence[] = { interrupt_init, /* set up exceptions */ #endif timer_init, /* initialize timer */ +#ifdef CONFIG_FSL_ESDHC + get_clocks, +#endif env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */ -- 1.6.3.3
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Lv Terry-R65388 wrote:
Hi Stefano,
Hi Terry,
Have you tested mmc on mx51 board?
Yes, of course. The whole patchset for mx51evk was tested on two different releases of the board, with respectively a TO2 and a TO3 processor.
And the driver was tested with both MMC slots on the mx51evk (both are supported):
For example, on a release 3.0 board: U-Boot 2009.11-00347-g0b1898d (Feb 24 2010 - 11:30:10)
CPU: Freescale i.MX51 family 3.0V at 800 MHz Board: MX51EVK 3.0 [POR]
I get: MMC: FSL_ESDHC: 0, FSL_ESDHC: 1
MX51EVK U-Boot > mmcinfo Device: FSL_ESDHC Manufacturer ID: 1 OEM: 5041 Name: SP02G Tran Speed: 25000000 Rd Block Len: 512 SD version 1.10 High Capacity: No Capacity: 2014838784 Bus Width: 4-bit
MX51EVK U-Boot > fatls mmc 0 14154 6091733.pdf
Of course, I have tested booting Linux that is stored on MMC, too.
The original esdhc uses PIO mode in function esdhc_send_cmd(), while fsl_esdhc uses DMA mode.
I do not understand what you mean. I have not changed the type in esdhc_xfertyp in my patch, it was already set to XFERTYP_DMAEN. The main changes are related to set the correct accessors functions and these are the only changes in esdhc_send_cmd().
I hasn't tested DMA mode before.
Have you tested this patch and have you found some issues ?
BTW: have you considered add the feature to save environment data to mmc?
Adding the environment to the MMC is a feature that should be implemented in a separate patch, because it is not strictly related to the mx51evk. If it works, it must be possible to use it with all targets having a MMC on board.
And I didn't want to add so much features before the patchset goes to the mainline. I prefer that at least the basic support for a MX51 processor is in the mainline, allowing for others to add easier custom boards with this SOC.
I think that such feature should be previously discussed on the ML. On one side, it looks strange that the environment resides on a removable media. On the other side, I understand that for test purposes or for boards without other storage media this is a way to store it.
Regards, Stefano
participants (2)
-
Lv Terry-R65388
-
Stefano Babic