X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fmmc%2Ffsl_esdhc.c;h=20a2df1f01efb4dd9023ded72b60fe0315d1a4b7;hb=526c85ce2fd08564dd14ca7bcff4d6e94772c075;hp=973b19f337b59b9646f58cff06454b0182b85ae5;hpb=fbbbc86e8ebac4f42f4ca39ceba80cea27c983bc;p=karo-tx-uboot.git diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 973b19f337..20a2df1f01 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -6,23 +6,7 @@ * (C) Copyright 2003 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net * - * 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 + * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -39,32 +23,53 @@ DECLARE_GLOBAL_DATA_PTR; +#define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \ + IRQSTATEN_CINT | \ + IRQSTATEN_CTOE | IRQSTATEN_CCE | IRQSTATEN_CEBE | \ + IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \ + IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \ + IRQSTATEN_DINT) + struct fsl_esdhc { - uint dsaddr; - uint blkattr; - uint cmdarg; - uint xfertyp; - uint cmdrsp0; - uint cmdrsp1; - uint cmdrsp2; - uint cmdrsp3; - uint datport; - uint prsstat; - uint proctl; - uint sysctl; - uint irqstat; - uint irqstaten; - uint irqsigen; - uint autoc12err; - uint hostcapblt; - uint wml; - uint mixctrl; - char reserved1[4]; - uint fevt; - char reserved2[168]; - uint hostver; - char reserved3[780]; - uint scr; + uint dsaddr; /* SDMA system address register */ + uint blkattr; /* Block attributes register */ + uint cmdarg; /* Command argument register */ + uint xfertyp; /* Transfer type register */ + uint cmdrsp0; /* Command response 0 register */ + uint cmdrsp1; /* Command response 1 register */ + uint cmdrsp2; /* Command response 2 register */ + uint cmdrsp3; /* Command response 3 register */ + uint datport; /* Buffer data port register */ + uint prsstat; /* Present state register */ + uint proctl; /* Protocol control register */ + uint sysctl; /* System Control Register */ + uint irqstat; /* Interrupt status register */ + uint irqstaten; /* Interrupt status enable register */ + uint irqsigen; /* Interrupt signal enable register */ + uint autoc12err; /* Auto CMD error status register */ + uint hostcapblt; /* Host controller capabilities register */ + uint wml; /* Watermark level register */ + uint mixctrl; /* For USDHC */ + char reserved1[4]; /* reserved */ + uint fevt; /* Force event register */ + uint admaes; /* ADMA error status register */ + uint adsaddr; /* ADMA system address register */ + char reserved2[100]; /* reserved */ + uint vendorspec; /* Vendor Specific register */ + char reserved3[56]; /* reserved */ + uint hostver; /* Host controller version register */ + char reserved4[4]; /* reserved */ + uint dmaerraddr; /* DMA error address register */ + char reserved5[4]; /* reserved */ + uint dmaerrattr; /* DMA error attribute register */ + char reserved6[4]; /* reserved */ + uint hostcapblt2; /* Host controller capabilities register 2 */ + char reserved7[8]; /* reserved */ + uint tcr; /* Tuning control register */ + char reserved8[28]; /* reserved */ + uint sddirctl; /* SD direction control register */ + char reserved9[712]; /* reserved */ + uint scr; /* eSDHC control register */ }; /* Return the XFERTYP flags for a given command and data packet */ @@ -100,7 +105,8 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) else if (cmd->resp_type & MMC_RSP_PRESENT) xfertyp |= XFERTYP_RSPTYP_48; -#ifdef CONFIG_MX53 +#if defined(CONFIG_SOC_MX53) || defined(CONFIG_PPC_T4240) || \ + defined(CONFIG_SOC_LS102XA) || defined(CONFIG_LS2085A) if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) xfertyp |= XFERTYP_CMDTYP_ABORT; #endif @@ -115,57 +121,69 @@ static void esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data) { struct fsl_esdhc_cfg *cfg = mmc->priv; - struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + struct fsl_esdhc *regs = cfg->esdhc_base; uint blocks; char *buffer; uint databuf; uint size; - uint irqstat; uint timeout; + int wml = esdhc_read32(®s->wml); if (data->flags & MMC_DATA_READ) { + wml &= WML_RD_WML_MASK; blocks = data->blocks; buffer = data->dest; while (blocks) { timeout = PIO_TIMEOUT; size = data->blocksize; - irqstat = esdhc_read32(®s->irqstat); - while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BREN) - && --timeout); - if (timeout <= 0) { - printf("\nData Read Failed in PIO Mode."); - return; - } - while (size && (!(irqstat & IRQSTAT_TC))) { - udelay(100); /* Wait before last byte transfer complete */ - irqstat = esdhc_read32(®s->irqstat); - databuf = in_le32(®s->datport); - *((uint *)buffer) = databuf; - buffer += 4; - size -= 4; + while (size && + !(esdhc_read32(®s->irqstat) & IRQSTAT_TC)) { + int i; + u32 prsstat; + + while (!((prsstat = esdhc_read32(®s->prsstat)) & + PRSSTAT_BREN) && --timeout) + /* NOP */; + if (!(prsstat & PRSSTAT_BREN)) { + printf("%s: Data Read Failed in PIO Mode\n", + __func__); + return; + } + for (i = 0; i < wml && size; i++) { + databuf = in_le32(®s->datport); + memcpy(buffer, &databuf, sizeof(databuf)); + buffer += 4; + size -= 4; + } } blocks--; } } else { + wml = (wml & WML_WR_WML_MASK) >> 16; blocks = data->blocks; - buffer = (char *)data->src; + buffer = (char *)data->src; /* cast away 'const' */ while (blocks) { timeout = PIO_TIMEOUT; size = data->blocksize; - irqstat = esdhc_read32(®s->irqstat); - while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BWEN) - && --timeout); - if (timeout <= 0) { - printf("\nData Write Failed in PIO Mode."); - return; - } - while (size && (!(irqstat & IRQSTAT_TC))) { - udelay(100); /* Wait before last byte transfer complete */ - databuf = *((uint *)buffer); - buffer += 4; - size -= 4; - irqstat = esdhc_read32(®s->irqstat); - out_le32(®s->datport, databuf); + while (size && + !(esdhc_read32(®s->irqstat) & IRQSTAT_TC)) { + int i; + u32 prsstat; + + while (!((prsstat = esdhc_read32(®s->prsstat)) & + PRSSTAT_BWEN) && --timeout) + /* NOP */; + if (!(prsstat & PRSSTAT_BWEN)) { + printf("%s: Data Write Failed in PIO Mode\n", + __func__); + return; + } + for (i = 0; i < wml && size; i++) { + memcpy(&databuf, buffer, sizeof(databuf)); + out_le32(®s->datport, databuf); + buffer += 4; + size -= 4; + } } blocks--; } @@ -176,48 +194,62 @@ esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data) static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { int timeout; - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; - struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO + struct fsl_esdhc_cfg *cfg = mmc->priv; + struct fsl_esdhc *regs = cfg->esdhc_base; +#ifdef CONFIG_LS2085A + dma_addr_t addr; +#endif uint wml_value; - wml_value = data->blocksize/4; + wml_value = data->blocksize / 4; if (data->flags & MMC_DATA_READ) { if (wml_value > WML_RD_WML_MAX) wml_value = WML_RD_WML_MAX_VAL; esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO +#ifdef CONFIG_LS2085A + addr = virt_to_phys((void *)(data->dest)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); +#else esdhc_write32(®s->dsaddr, (u32)data->dest); +#endif +#endif } else { +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO flush_dcache_range((ulong)data->src, (ulong)data->src+data->blocks *data->blocksize); - +#endif if (wml_value > WML_WR_WML_MAX) wml_value = WML_WR_WML_MAX_VAL; 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; + printf("The SD card is locked. Can not write to a locked card.\n"); + return UNUSABLE_ERR; } + flush_dcache_range((unsigned long)data->src, + (unsigned long)data->src + data->blocks * data->blocksize); esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, wml_value << 16); +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO +#ifdef CONFIG_LS2085A + addr = virt_to_phys((void *)(data->src)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); +#else esdhc_write32(®s->dsaddr, (u32)data->src); +#endif +#endif } -#else /* CONFIG_SYS_FSL_ESDHC_USE_PIO */ - if (!(data->flags & MMC_DATA_READ)) { - 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; - } - esdhc_write32(®s->dsaddr, (u32)data->src); - } else - esdhc_write32(®s->dsaddr, (u32)data->dest); -#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */ - esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); + esdhc_write32(®s->blkattr, (data->blocks << 16) | data->blocksize); /* Calculate the timeout period for data transactions */ /* @@ -225,22 +257,21 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) * 2)Timeout period should be minimum 0.250sec as per SD Card spec * So, Number of SD Clock cycles for 0.25sec should be minimum * (SD Clock/sec * 0.25 sec) SD Clock cycles - * = (mmc->tran_speed * 1/4) SD Clock cycles + * = (mmc->clock * 1/4) SD Clock cycles * As 1) >= 2) - * => (2^(timeout+13)) >= mmc->tran_speed * 1/4 + * => (2^(timeout+13)) >= mmc->clock * 1/4 * Taking log2 both the sides - * => timeout + 13 >= log2(mmc->tran_speed/4) + * => timeout + 13 >= log2(mmc->clock/4) * Rounding up to next power of 2 - * => timeout + 13 = log2(mmc->tran_speed/4) + 1 - * => timeout + 13 = fls(mmc->tran_speed/4) + * => timeout + 13 = log2(mmc->clock/4) + 1 + * => timeout + 13 = fls(mmc->clock/4) */ - timeout = fls(mmc->tran_speed/4); + timeout = fls(mmc->clock/4); timeout -= 13; if (timeout > 14) timeout = 14; - - if (timeout < 0) + else if (timeout < 0) timeout = 0; #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001 @@ -248,6 +279,9 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) timeout++; #endif +#ifdef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE + timeout = 0xE; +#endif esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); return 0; @@ -256,12 +290,26 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) static void check_and_invalidate_dcache_range (struct mmc_cmd *cmd, struct mmc_data *data) { +#ifdef CONFIG_LS2085A + unsigned start = 0; +#else unsigned start = (unsigned)data->dest ; +#endif unsigned size = roundup(ARCH_DMA_MINALIGN, data->blocks*data->blocksize); unsigned end = start+size ; +#ifdef CONFIG_LS2085A + dma_addr_t addr; + + addr = virt_to_phys((void *)(data->dest)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + start = lower_32_bits(addr); +#endif invalidate_dcache_range(start, end); } + /* * Sends a command out on the bus. Takes the mmc pointer, * a command pointer, and an optional data pointer. @@ -269,27 +317,36 @@ static void check_and_invalidate_dcache_range static int esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { + int err = 0; uint xfertyp; uint irqstat; - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; - volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + struct fsl_esdhc_cfg *cfg = mmc->priv; + volatile struct fsl_esdhc *regs = cfg->esdhc_base; + unsigned long start; #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) return 0; #endif - esdhc_write32(®s->irqstat, -1); sync(); + start = get_timer_masked(); /* Wait for the bus to be idle */ while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || - (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) - ; + (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) { + if (get_timer(start) > CONFIG_SYS_HZ) { + printf("%s: Timeout waiting for bus idle\n", __func__); + return TIMEOUT; + } + } - while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) - ; + start = get_timer_masked(); + while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) { + if (get_timer(start) > CONFIG_SYS_HZ) + return TIMEOUT; + } /* Wait at least 8 SD clock cycles before the next command */ /* @@ -300,11 +357,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) /* Set up for a data transfer if we have one */ if (data) { - int err; - err = esdhc_setup_data(mmc, data); - if(err) + if (err) return err; + + if (data->flags & MMC_DATA_READ) + check_and_invalidate_dcache_range(cmd, data); } /* Figure out the transfer arguments */ @@ -317,45 +375,54 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) esdhc_write32(®s->cmdarg, cmd->cmdarg); #if defined(CONFIG_FSL_USDHC) esdhc_write32(®s->mixctrl, - (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F)); + (esdhc_read32(®s->mixctrl) & ~0x7f) | (xfertyp & 0x7F) + | (mmc->ddr_mode ? XFERTYP_DDREN : 0)); esdhc_write32(®s->xfertyp, xfertyp & 0xFFFF0000); #else esdhc_write32(®s->xfertyp, xfertyp); #endif + /* Mask all irqs */ + esdhc_write32(®s->irqsigen, 0); + + start = get_timer_masked(); /* Wait for the command to complete */ - while (!(esdhc_read32(®s->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE))) - ; + while (!(esdhc_read32(®s->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE))) { + if (get_timer(start) > CONFIG_SYS_HZ) { + printf("%s: Timeout waiting for cmd completion\n", __func__); + return TIMEOUT; + } + } + + if (data && (data->flags & MMC_DATA_READ)) + check_and_invalidate_dcache_range(cmd, data); irqstat = esdhc_read32(®s->irqstat); - /* Reset CMD and DATA portions on error */ - if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) { - esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | - SYSCTL_RSTC); - while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) - ; + if (irqstat & CMD_ERR) { + err = COMM_ERR; + goto out; + } - if (data) { - esdhc_write32(®s->sysctl, - esdhc_read32(®s->sysctl) | - SYSCTL_RSTD); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) - ; - } + if (irqstat & IRQSTAT_CTOE) { + err = TIMEOUT; + goto out; } - if (irqstat & CMD_ERR) - return COMM_ERR; + /* Switch voltage to 1.8V if CMD11 succeeded */ + if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) { + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); - if (irqstat & IRQSTAT_CTOE) - return TIMEOUT; + printf("Run CMD11 1.8V switch\n"); + /* Sleep for 5 ms - max time for card to switch to 1.8V */ + udelay(5000); + } /* Workaround for ESDHC errata ENGcm03648 */ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { - int timeout = 2500; + int timeout = 6000; - /* Poll on DATA0 line for cmd with busy signal for 250 ms */ + /* Poll on DATA0 line for cmd with busy signal for 600 ms */ while (timeout > 0 && !(esdhc_read32(®s->prsstat) & PRSSTAT_DAT0)) { udelay(100); @@ -364,7 +431,8 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (timeout <= 0) { printf("Timeout waiting for DAT0 to go high!\n"); - return TIMEOUT; + err = TIMEOUT; + goto out; } } @@ -391,32 +459,63 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) do { irqstat = esdhc_read32(®s->irqstat); - if (irqstat & IRQSTAT_DTOE) - return TIMEOUT; + if (irqstat & IRQSTAT_DTOE) { + err = TIMEOUT; + goto out; + } - if (irqstat & DATA_ERR) - return COMM_ERR; + if (irqstat & DATA_ERR) { + err = COMM_ERR; + goto out; + } } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); -#endif + + /* + * Need invalidate the dcache here again to avoid any + * cache-fill during the DMA operations such as the + * speculative pre-fetching etc. + */ if (data->flags & MMC_DATA_READ) check_and_invalidate_dcache_range(cmd, data); +#endif } - esdhc_write32(®s->irqstat, -1); +out: + /* Reset CMD and DATA portions on error */ + if (err) { + esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | + SYSCTL_RSTC); + while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) + ; - return 0; + if (data) { + esdhc_write32(®s->sysctl, + esdhc_read32(®s->sysctl) | + SYSCTL_RSTD); + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) + ; + } + + /* If this was CMD11, then notify that power cycle is needed */ + if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) + printf("CMD11 to switch to 1.8V mode failed, card requires power cycle.\n"); + } + + esdhc_write32(®s->irqstat, irqstat); + + return err; } static void set_sysctl(struct mmc *mmc, uint clock) { int div, pre_div; - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; - volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + struct fsl_esdhc_cfg *cfg = mmc->priv; + volatile struct fsl_esdhc *regs = cfg->esdhc_base; int sdhc_clk = cfg->sdhc_clk; uint clk; - if (clock < mmc->f_min) - clock = mmc->f_min; + if (clock < mmc->cfg->f_min) + clock = mmc->cfg->f_min; if (sdhc_clk / 16 > clock) { for (pre_div = 2; pre_div < 256; pre_div *= 2) @@ -429,7 +528,7 @@ static void set_sysctl(struct mmc *mmc, uint clock) if ((sdhc_clk / (div * pre_div)) <= clock) break; - pre_div >>= 1; + pre_div >>= mmc->ddr_mode ? 2 : 1; div -= 1; clk = (pre_div << 8) | (div << 4); @@ -445,11 +544,47 @@ static void set_sysctl(struct mmc *mmc, uint clock) esdhc_setbits32(®s->sysctl, clk); } -static void esdhc_set_ios(struct mmc *mmc) +#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK +static void esdhc_clock_control(struct mmc *mmc, bool enable) { - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + u32 value; + u32 time_out; + + value = esdhc_read32(®s->sysctl); + if (enable) + value |= SYSCTL_CKEN; + else + value &= ~SYSCTL_CKEN; + + esdhc_write32(®s->sysctl, value); + + time_out = 20; + value = PRSSTAT_SDSTB; + while (!(esdhc_read32(®s->prsstat) & value)) { + if (time_out == 0) { + printf("fsl_esdhc: Internal clock never stabilised.\n"); + break; + } + time_out--; + mdelay(1); + } +} +#endif + +static void esdhc_set_ios(struct mmc *mmc) +{ + struct fsl_esdhc_cfg *cfg = mmc->priv; + struct fsl_esdhc *regs = cfg->esdhc_base; + +#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK + /* Select to use peripheral clock */ + esdhc_clock_control(mmc, false); + esdhc_setbits32(®s->scr, ESDHCCTL_PCS); + esdhc_clock_control(mmc, true); +#endif /* Set the clock speed */ set_sysctl(mmc, mmc->clock); @@ -465,12 +600,12 @@ static void esdhc_set_ios(struct mmc *mmc) static int esdhc_init(struct mmc *mmc) { - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; - struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + struct fsl_esdhc_cfg *cfg = mmc->priv; + struct fsl_esdhc *regs = cfg->esdhc_base; int timeout = 1000; /* Reset the entire host controller */ - esdhc_write32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); /* Wait until the controller is available */ while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) @@ -481,7 +616,7 @@ static int esdhc_init(struct mmc *mmc) esdhc_write32(®s->scr, 0x00000040); #endif - esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); + esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); /* Set the initial clock speed */ mmc_set_clock(mmc, 400000); @@ -495,15 +630,23 @@ static int esdhc_init(struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); +#ifdef CONFIG_SYS_FSL_ESDHC_FORCE_VSELECT + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); +#endif + return 0; } static int esdhc_getcd(struct mmc *mmc) { - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; - struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + struct fsl_esdhc_cfg *cfg = mmc->priv; + struct fsl_esdhc *regs = cfg->esdhc_base; int timeout = 1000; +#ifdef CONFIG_ESDHC_DETECT_QUIRK + if (CONFIG_ESDHC_DETECT_QUIRK) + return 1; +#endif while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) udelay(1000); @@ -515,7 +658,7 @@ static void esdhc_reset(struct fsl_esdhc *regs) unsigned long timeout = 100; /* wait max 100 ms */ /* reset the controller */ - esdhc_write32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); /* hardware clears the bit when it is done */ while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) @@ -524,6 +667,13 @@ static void esdhc_reset(struct fsl_esdhc *regs) printf("MMC/SD: Reset never completed.\n"); } +static const struct mmc_ops esdhc_ops = { + .send_cmd = esdhc_send_cmd, + .set_ios = esdhc_set_ios, + .init = esdhc_init, + .getcd = esdhc_getcd, +}; + int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { struct fsl_esdhc *regs; @@ -531,11 +681,8 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) u32 caps, voltage_caps; if (!cfg) - return -1; + return -EINVAL; - mmc = malloc(sizeof(struct mmc)); - - sprintf(mmc->name, "FSL_SDHC"); regs = (struct fsl_esdhc *)cfg->esdhc_base; /* First reset the eSDHC controller */ @@ -544,20 +691,22 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN | SYSCTL_CKEN); - mmc->priv = cfg; - mmc->send_cmd = esdhc_send_cmd; - mmc->set_ios = esdhc_set_ios; - mmc->init = esdhc_init; - mmc->getcd = esdhc_getcd; - mmc->getwp = NULL; + writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); + memset(&cfg->cfg, 0, sizeof(cfg->cfg)); voltage_caps = 0; - caps = regs->hostcapblt; + caps = esdhc_read32(®s->hostcapblt); #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 caps = caps & ~(ESDHC_HOSTCAPBLT_SRS | ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30); #endif + +/* T4240 host controller capabilities register should have VS33 bit */ +#ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 + caps = caps | ESDHC_HOSTCAPBLT_VS33; +#endif + if (caps & ESDHC_HOSTCAPBLT_VS18) voltage_caps |= MMC_VDD_165_195; if (caps & ESDHC_HOSTCAPBLT_VS30) @@ -565,33 +714,46 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) if (caps & ESDHC_HOSTCAPBLT_VS33) voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->cfg.name = "FSL_SDHC"; + cfg->cfg.ops = &esdhc_ops; #ifdef CONFIG_SYS_SD_VOLTAGE - mmc->voltages = CONFIG_SYS_SD_VOLTAGE; + cfg->cfg.voltages = CONFIG_SYS_SD_VOLTAGE; #else - mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; #endif - if ((mmc->voltages & voltage_caps) == 0) { + if ((cfg->cfg.voltages & voltage_caps) == 0) { printf("voltage not supported by controller\n"); - return -1; + return -EINVAL; } - mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC; + cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT; +#ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE + cfg->cfg.host_caps |= MMC_MODE_DDR_52MHz; +#endif if (cfg->max_bus_width > 0) { if (cfg->max_bus_width < 8) - mmc->host_caps &= ~MMC_MODE_8BIT; + cfg->cfg.host_caps &= ~MMC_MODE_8BIT; if (cfg->max_bus_width < 4) - mmc->host_caps &= ~MMC_MODE_4BIT; + cfg->cfg.host_caps &= ~MMC_MODE_4BIT; } if (caps & ESDHC_HOSTCAPBLT_HSS) - mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + cfg->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; - mmc->f_min = 400000; - mmc->f_max = MIN(gd->arch.sdhc_clk, 52000000); +#ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK + if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) + cfg->cfg.host_caps &= ~MMC_MODE_8BIT; +#endif - mmc->b_max = 0; - mmc_register(mmc); + cfg->cfg.f_min = 400000; + cfg->cfg.f_max = min(cfg->sdhc_clk, (u32)52000000); + + cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + mmc = mmc_create(&cfg->cfg, cfg); + if (mmc == NULL) + return -1; return 0; } @@ -600,12 +762,47 @@ int fsl_esdhc_mmc_init(bd_t *bis) { struct fsl_esdhc_cfg *cfg; - cfg = calloc(sizeof(struct fsl_esdhc_cfg), 1); - cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; + cfg = kzalloc(sizeof(struct fsl_esdhc_cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + cfg->esdhc_base = (void __iomem *)CONFIG_SYS_FSL_ESDHC_ADDR; cfg->sdhc_clk = gd->arch.sdhc_clk; return fsl_esdhc_initialize(bis, cfg); } +#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT +void mmc_adapter_card_type_ident(void) +{ + u8 card_id; + u8 value; + + card_id = QIXIS_READ(present) & QIXIS_SDID_MASK; + gd->arch.sdhc_adapter = card_id; + + switch (card_id) { + case QIXIS_ESDHC_ADAPTER_TYPE_EMMC45: + break; + case QIXIS_ESDHC_ADAPTER_TYPE_SDMMC_LEGACY: + break; + case QIXIS_ESDHC_ADAPTER_TYPE_EMMC44: + value = QIXIS_READ(brdcfg[5]); + value |= (QIXIS_SDCLKIN | QIXIS_SDCLKOUT); + QIXIS_WRITE(brdcfg[5], value); + break; + case QIXIS_ESDHC_ADAPTER_TYPE_RSV: + break; + case QIXIS_ESDHC_ADAPTER_TYPE_MMC: + break; + case QIXIS_ESDHC_ADAPTER_TYPE_SD: + break; + case QIXIS_ESDHC_NO_ADAPTER: + break; + default: + break; + } +} +#endif + #ifdef CONFIG_OF_LIBFDT void fdt_fixup_esdhc(void *blob, bd_t *bd) { @@ -619,9 +816,17 @@ void fdt_fixup_esdhc(void *blob, bd_t *bd) } #endif +#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK + do_fixup_by_compat_u32(blob, compat, "peripheral-frequency", + gd->arch.sdhc_clk, 1); +#else do_fixup_by_compat_u32(blob, compat, "clock-frequency", gd->arch.sdhc_clk, 1); - +#endif +#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT + do_fixup_by_compat_u32(blob, compat, "adapter-type", + (u32)(gd->arch.sdhc_adapter), 1); +#endif do_fixup_by_compat(blob, compat, "status", "okay", 4 + 1, 1); }