150586ef2SAndy Fleming /* 2d621da00SJerry Huang * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc 350586ef2SAndy Fleming * Andy Fleming 450586ef2SAndy Fleming * 550586ef2SAndy Fleming * Based vaguely on the pxa mmc code: 650586ef2SAndy Fleming * (C) Copyright 2003 750586ef2SAndy Fleming * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net 850586ef2SAndy Fleming * 91a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 1050586ef2SAndy Fleming */ 1150586ef2SAndy Fleming 1250586ef2SAndy Fleming #include <config.h> 1350586ef2SAndy Fleming #include <common.h> 1450586ef2SAndy Fleming #include <command.h> 15915ffa52SJaehoon Chung #include <errno.h> 16b33433a6SAnton Vorontsov #include <hwconfig.h> 1750586ef2SAndy Fleming #include <mmc.h> 1850586ef2SAndy Fleming #include <part.h> 194483b7ebSPeng Fan #include <power/regulator.h> 2050586ef2SAndy Fleming #include <malloc.h> 2150586ef2SAndy Fleming #include <fsl_esdhc.h> 22b33433a6SAnton Vorontsov #include <fdt_support.h> 2350586ef2SAndy Fleming #include <asm/io.h> 2496f0407bSPeng Fan #include <dm.h> 2596f0407bSPeng Fan #include <asm-generic/gpio.h> 2650586ef2SAndy Fleming 2750586ef2SAndy Fleming DECLARE_GLOBAL_DATA_PTR; 2850586ef2SAndy Fleming 29a3d6e386SYe.Li #define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \ 30a3d6e386SYe.Li IRQSTATEN_CINT | \ 31a3d6e386SYe.Li IRQSTATEN_CTOE | IRQSTATEN_CCE | IRQSTATEN_CEBE | \ 32a3d6e386SYe.Li IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \ 33a3d6e386SYe.Li IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \ 34a3d6e386SYe.Li IRQSTATEN_DINT) 35a3d6e386SYe.Li 3650586ef2SAndy Fleming struct fsl_esdhc { 37511948b2SHaijun.Zhang uint dsaddr; /* SDMA system address register */ 38511948b2SHaijun.Zhang uint blkattr; /* Block attributes register */ 39511948b2SHaijun.Zhang uint cmdarg; /* Command argument register */ 40511948b2SHaijun.Zhang uint xfertyp; /* Transfer type register */ 41511948b2SHaijun.Zhang uint cmdrsp0; /* Command response 0 register */ 42511948b2SHaijun.Zhang uint cmdrsp1; /* Command response 1 register */ 43511948b2SHaijun.Zhang uint cmdrsp2; /* Command response 2 register */ 44511948b2SHaijun.Zhang uint cmdrsp3; /* Command response 3 register */ 45511948b2SHaijun.Zhang uint datport; /* Buffer data port register */ 46511948b2SHaijun.Zhang uint prsstat; /* Present state register */ 47511948b2SHaijun.Zhang uint proctl; /* Protocol control register */ 48511948b2SHaijun.Zhang uint sysctl; /* System Control Register */ 49511948b2SHaijun.Zhang uint irqstat; /* Interrupt status register */ 50511948b2SHaijun.Zhang uint irqstaten; /* Interrupt status enable register */ 51511948b2SHaijun.Zhang uint irqsigen; /* Interrupt signal enable register */ 52511948b2SHaijun.Zhang uint autoc12err; /* Auto CMD error status register */ 53511948b2SHaijun.Zhang uint hostcapblt; /* Host controller capabilities register */ 54511948b2SHaijun.Zhang uint wml; /* Watermark level register */ 55511948b2SHaijun.Zhang uint mixctrl; /* For USDHC */ 56511948b2SHaijun.Zhang char reserved1[4]; /* reserved */ 57511948b2SHaijun.Zhang uint fevt; /* Force event register */ 58511948b2SHaijun.Zhang uint admaes; /* ADMA error status register */ 59511948b2SHaijun.Zhang uint adsaddr; /* ADMA system address register */ 60f53225ccSPeng Fan char reserved2[4]; 61f53225ccSPeng Fan uint dllctrl; 62f53225ccSPeng Fan uint dllstat; 63f53225ccSPeng Fan uint clktunectrlstatus; 64f53225ccSPeng Fan char reserved3[84]; 65f53225ccSPeng Fan uint vendorspec; 66f53225ccSPeng Fan uint mmcboot; 67f53225ccSPeng Fan uint vendorspec2; 68f53225ccSPeng Fan char reserved4[48]; 69511948b2SHaijun.Zhang uint hostver; /* Host controller version register */ 70511948b2SHaijun.Zhang char reserved5[4]; /* reserved */ 71f53225ccSPeng Fan uint dmaerraddr; /* DMA error address register */ 72f022d36eSOtavio Salvador char reserved6[4]; /* reserved */ 73f53225ccSPeng Fan uint dmaerrattr; /* DMA error attribute register */ 74f53225ccSPeng Fan char reserved7[4]; /* reserved */ 75511948b2SHaijun.Zhang uint hostcapblt2; /* Host controller capabilities register 2 */ 76f53225ccSPeng Fan char reserved8[8]; /* reserved */ 77511948b2SHaijun.Zhang uint tcr; /* Tuning control register */ 78f53225ccSPeng Fan char reserved9[28]; /* reserved */ 79511948b2SHaijun.Zhang uint sddirctl; /* SD direction control register */ 80f53225ccSPeng Fan char reserved10[712];/* reserved */ 81511948b2SHaijun.Zhang uint scr; /* eSDHC control register */ 8250586ef2SAndy Fleming }; 8350586ef2SAndy Fleming 84e88e1d9cSSimon Glass struct fsl_esdhc_plat { 85e88e1d9cSSimon Glass struct mmc_config cfg; 86e88e1d9cSSimon Glass struct mmc mmc; 87e88e1d9cSSimon Glass }; 88e88e1d9cSSimon Glass 8996f0407bSPeng Fan /** 9096f0407bSPeng Fan * struct fsl_esdhc_priv 9196f0407bSPeng Fan * 9296f0407bSPeng Fan * @esdhc_regs: registers of the sdhc controller 9396f0407bSPeng Fan * @sdhc_clk: Current clk of the sdhc controller 9496f0407bSPeng Fan * @bus_width: bus width, 1bit, 4bit or 8bit 9596f0407bSPeng Fan * @cfg: mmc config 9696f0407bSPeng Fan * @mmc: mmc 9796f0407bSPeng Fan * Following is used when Driver Model is enabled for MMC 9896f0407bSPeng Fan * @dev: pointer for the device 9996f0407bSPeng Fan * @non_removable: 0: removable; 1: non-removable 1001483151eSPeng Fan * @wp_enable: 1: enable checking wp; 0: no check 10132a9179fSPeng Fan * @vs18_enable: 1: use 1.8V voltage; 0: use 3.3V 10296f0407bSPeng Fan * @cd_gpio: gpio for card detection 1031483151eSPeng Fan * @wp_gpio: gpio for write protection 10496f0407bSPeng Fan */ 10596f0407bSPeng Fan struct fsl_esdhc_priv { 10696f0407bSPeng Fan struct fsl_esdhc *esdhc_regs; 10796f0407bSPeng Fan unsigned int sdhc_clk; 10896f0407bSPeng Fan unsigned int bus_width; 10996f0407bSPeng Fan struct mmc *mmc; 11096f0407bSPeng Fan struct udevice *dev; 11196f0407bSPeng Fan int non_removable; 1121483151eSPeng Fan int wp_enable; 11332a9179fSPeng Fan int vs18_enable; 114fc8048a8SYangbo Lu #ifdef CONFIG_DM_GPIO 11596f0407bSPeng Fan struct gpio_desc cd_gpio; 1161483151eSPeng Fan struct gpio_desc wp_gpio; 117fc8048a8SYangbo Lu #endif 11896f0407bSPeng Fan }; 11996f0407bSPeng Fan 12050586ef2SAndy Fleming /* Return the XFERTYP flags for a given command and data packet */ 121eafa90a1SKim Phillips static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) 12250586ef2SAndy Fleming { 12350586ef2SAndy Fleming uint xfertyp = 0; 12450586ef2SAndy Fleming 12550586ef2SAndy Fleming if (data) { 12677c1458dSDipen Dudhat xfertyp |= XFERTYP_DPSEL; 12777c1458dSDipen Dudhat #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO 12877c1458dSDipen Dudhat xfertyp |= XFERTYP_DMAEN; 12977c1458dSDipen Dudhat #endif 13050586ef2SAndy Fleming if (data->blocks > 1) { 13150586ef2SAndy Fleming xfertyp |= XFERTYP_MSBSEL; 13250586ef2SAndy Fleming xfertyp |= XFERTYP_BCEN; 133d621da00SJerry Huang #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 134d621da00SJerry Huang xfertyp |= XFERTYP_AC12EN; 135d621da00SJerry Huang #endif 13650586ef2SAndy Fleming } 13750586ef2SAndy Fleming 13850586ef2SAndy Fleming if (data->flags & MMC_DATA_READ) 13950586ef2SAndy Fleming xfertyp |= XFERTYP_DTDSEL; 14050586ef2SAndy Fleming } 14150586ef2SAndy Fleming 14250586ef2SAndy Fleming if (cmd->resp_type & MMC_RSP_CRC) 14350586ef2SAndy Fleming xfertyp |= XFERTYP_CCCEN; 14450586ef2SAndy Fleming if (cmd->resp_type & MMC_RSP_OPCODE) 14550586ef2SAndy Fleming xfertyp |= XFERTYP_CICEN; 14650586ef2SAndy Fleming if (cmd->resp_type & MMC_RSP_136) 14750586ef2SAndy Fleming xfertyp |= XFERTYP_RSPTYP_136; 14850586ef2SAndy Fleming else if (cmd->resp_type & MMC_RSP_BUSY) 14950586ef2SAndy Fleming xfertyp |= XFERTYP_RSPTYP_48_BUSY; 15050586ef2SAndy Fleming else if (cmd->resp_type & MMC_RSP_PRESENT) 15150586ef2SAndy Fleming xfertyp |= XFERTYP_RSPTYP_48; 15250586ef2SAndy Fleming 1534571de33SJason Liu if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) 1544571de33SJason Liu xfertyp |= XFERTYP_CMDTYP_ABORT; 15525503443SYangbo Lu 15650586ef2SAndy Fleming return XFERTYP_CMD(cmd->cmdidx) | xfertyp; 15750586ef2SAndy Fleming } 15850586ef2SAndy Fleming 15977c1458dSDipen Dudhat #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO 16077c1458dSDipen Dudhat /* 16177c1458dSDipen Dudhat * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. 16277c1458dSDipen Dudhat */ 16309b465fdSSimon Glass static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv, 16409b465fdSSimon Glass struct mmc_data *data) 16577c1458dSDipen Dudhat { 16696f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 16777c1458dSDipen Dudhat uint blocks; 16877c1458dSDipen Dudhat char *buffer; 16977c1458dSDipen Dudhat uint databuf; 17077c1458dSDipen Dudhat uint size; 17177c1458dSDipen Dudhat uint irqstat; 17277c1458dSDipen Dudhat uint timeout; 17377c1458dSDipen Dudhat 17477c1458dSDipen Dudhat if (data->flags & MMC_DATA_READ) { 17577c1458dSDipen Dudhat blocks = data->blocks; 17677c1458dSDipen Dudhat buffer = data->dest; 17777c1458dSDipen Dudhat while (blocks) { 17877c1458dSDipen Dudhat timeout = PIO_TIMEOUT; 17977c1458dSDipen Dudhat size = data->blocksize; 18077c1458dSDipen Dudhat irqstat = esdhc_read32(®s->irqstat); 18177c1458dSDipen Dudhat while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BREN) 18277c1458dSDipen Dudhat && --timeout); 18377c1458dSDipen Dudhat if (timeout <= 0) { 18477c1458dSDipen Dudhat printf("\nData Read Failed in PIO Mode."); 1857b43db92SWolfgang Denk return; 18677c1458dSDipen Dudhat } 18777c1458dSDipen Dudhat while (size && (!(irqstat & IRQSTAT_TC))) { 18877c1458dSDipen Dudhat udelay(100); /* Wait before last byte transfer complete */ 18977c1458dSDipen Dudhat irqstat = esdhc_read32(®s->irqstat); 19077c1458dSDipen Dudhat databuf = in_le32(®s->datport); 19177c1458dSDipen Dudhat *((uint *)buffer) = databuf; 19277c1458dSDipen Dudhat buffer += 4; 19377c1458dSDipen Dudhat size -= 4; 19477c1458dSDipen Dudhat } 19577c1458dSDipen Dudhat blocks--; 19677c1458dSDipen Dudhat } 19777c1458dSDipen Dudhat } else { 19877c1458dSDipen Dudhat blocks = data->blocks; 1997b43db92SWolfgang Denk buffer = (char *)data->src; 20077c1458dSDipen Dudhat while (blocks) { 20177c1458dSDipen Dudhat timeout = PIO_TIMEOUT; 20277c1458dSDipen Dudhat size = data->blocksize; 20377c1458dSDipen Dudhat irqstat = esdhc_read32(®s->irqstat); 20477c1458dSDipen Dudhat while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BWEN) 20577c1458dSDipen Dudhat && --timeout); 20677c1458dSDipen Dudhat if (timeout <= 0) { 20777c1458dSDipen Dudhat printf("\nData Write Failed in PIO Mode."); 2087b43db92SWolfgang Denk return; 20977c1458dSDipen Dudhat } 21077c1458dSDipen Dudhat while (size && (!(irqstat & IRQSTAT_TC))) { 21177c1458dSDipen Dudhat udelay(100); /* Wait before last byte transfer complete */ 21277c1458dSDipen Dudhat databuf = *((uint *)buffer); 21377c1458dSDipen Dudhat buffer += 4; 21477c1458dSDipen Dudhat size -= 4; 21577c1458dSDipen Dudhat irqstat = esdhc_read32(®s->irqstat); 21677c1458dSDipen Dudhat out_le32(®s->datport, databuf); 21777c1458dSDipen Dudhat } 21877c1458dSDipen Dudhat blocks--; 21977c1458dSDipen Dudhat } 22077c1458dSDipen Dudhat } 22177c1458dSDipen Dudhat } 22277c1458dSDipen Dudhat #endif 22377c1458dSDipen Dudhat 22409b465fdSSimon Glass static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, 22509b465fdSSimon Glass struct mmc_data *data) 22650586ef2SAndy Fleming { 22750586ef2SAndy Fleming int timeout; 22896f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 2299702ec00SEddy Petrișor #if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) 2308b06460eSYangbo Lu dma_addr_t addr; 2318b06460eSYangbo Lu #endif 2327b43db92SWolfgang Denk uint wml_value; 23350586ef2SAndy Fleming 23450586ef2SAndy Fleming wml_value = data->blocksize/4; 23550586ef2SAndy Fleming 23650586ef2SAndy Fleming if (data->flags & MMC_DATA_READ) { 23732c8cfb2SPriyanka Jain if (wml_value > WML_RD_WML_MAX) 23832c8cfb2SPriyanka Jain wml_value = WML_RD_WML_MAX_VAL; 23950586ef2SAndy Fleming 240ab467c51SRoy Zang esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); 24171689776SYe.Li #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO 2429702ec00SEddy Petrișor #if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) 2438b06460eSYangbo Lu addr = virt_to_phys((void *)(data->dest)); 2448b06460eSYangbo Lu if (upper_32_bits(addr)) 2458b06460eSYangbo Lu printf("Error found for upper 32 bits\n"); 2468b06460eSYangbo Lu else 2478b06460eSYangbo Lu esdhc_write32(®s->dsaddr, lower_32_bits(addr)); 2488b06460eSYangbo Lu #else 249c67bee14SStefano Babic esdhc_write32(®s->dsaddr, (u32)data->dest); 25071689776SYe.Li #endif 2518b06460eSYangbo Lu #endif 25250586ef2SAndy Fleming } else { 25371689776SYe.Li #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO 254e576bd90SEric Nelson flush_dcache_range((ulong)data->src, 255e576bd90SEric Nelson (ulong)data->src+data->blocks 256e576bd90SEric Nelson *data->blocksize); 25771689776SYe.Li #endif 25832c8cfb2SPriyanka Jain if (wml_value > WML_WR_WML_MAX) 25932c8cfb2SPriyanka Jain wml_value = WML_WR_WML_MAX_VAL; 2601483151eSPeng Fan if (priv->wp_enable) { 2611483151eSPeng Fan if ((esdhc_read32(®s->prsstat) & 2621483151eSPeng Fan PRSSTAT_WPSPL) == 0) { 26350586ef2SAndy Fleming printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); 264915ffa52SJaehoon Chung return -ETIMEDOUT; 26550586ef2SAndy Fleming } 2661483151eSPeng Fan } 267ab467c51SRoy Zang 268ab467c51SRoy Zang esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, 269ab467c51SRoy Zang wml_value << 16); 27071689776SYe.Li #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO 2719702ec00SEddy Petrișor #if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) 2728b06460eSYangbo Lu addr = virt_to_phys((void *)(data->src)); 2738b06460eSYangbo Lu if (upper_32_bits(addr)) 2748b06460eSYangbo Lu printf("Error found for upper 32 bits\n"); 2758b06460eSYangbo Lu else 2768b06460eSYangbo Lu esdhc_write32(®s->dsaddr, lower_32_bits(addr)); 2778b06460eSYangbo Lu #else 278c67bee14SStefano Babic esdhc_write32(®s->dsaddr, (u32)data->src); 27971689776SYe.Li #endif 2808b06460eSYangbo Lu #endif 28150586ef2SAndy Fleming } 28250586ef2SAndy Fleming 283c67bee14SStefano Babic esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); 28450586ef2SAndy Fleming 28550586ef2SAndy Fleming /* Calculate the timeout period for data transactions */ 286b71ea336SPriyanka Jain /* 287b71ea336SPriyanka Jain * 1)Timeout period = (2^(timeout+13)) SD Clock cycles 288b71ea336SPriyanka Jain * 2)Timeout period should be minimum 0.250sec as per SD Card spec 289b71ea336SPriyanka Jain * So, Number of SD Clock cycles for 0.25sec should be minimum 290b71ea336SPriyanka Jain * (SD Clock/sec * 0.25 sec) SD Clock cycles 291fb823981SAndrew Gabbasov * = (mmc->clock * 1/4) SD Clock cycles 292b71ea336SPriyanka Jain * As 1) >= 2) 293fb823981SAndrew Gabbasov * => (2^(timeout+13)) >= mmc->clock * 1/4 294b71ea336SPriyanka Jain * Taking log2 both the sides 295fb823981SAndrew Gabbasov * => timeout + 13 >= log2(mmc->clock/4) 296b71ea336SPriyanka Jain * Rounding up to next power of 2 297fb823981SAndrew Gabbasov * => timeout + 13 = log2(mmc->clock/4) + 1 298fb823981SAndrew Gabbasov * => timeout + 13 = fls(mmc->clock/4) 299e978a31bSYangbo Lu * 300e978a31bSYangbo Lu * However, the MMC spec "It is strongly recommended for hosts to 301e978a31bSYangbo Lu * implement more than 500ms timeout value even if the card 302e978a31bSYangbo Lu * indicates the 250ms maximum busy length." Even the previous 303e978a31bSYangbo Lu * value of 300ms is known to be insufficient for some cards. 304e978a31bSYangbo Lu * So, we use 305e978a31bSYangbo Lu * => timeout + 13 = fls(mmc->clock/2) 306b71ea336SPriyanka Jain */ 307e978a31bSYangbo Lu timeout = fls(mmc->clock/2); 30850586ef2SAndy Fleming timeout -= 13; 30950586ef2SAndy Fleming 31050586ef2SAndy Fleming if (timeout > 14) 31150586ef2SAndy Fleming timeout = 14; 31250586ef2SAndy Fleming 31350586ef2SAndy Fleming if (timeout < 0) 31450586ef2SAndy Fleming timeout = 0; 31550586ef2SAndy Fleming 3165103a03aSKumar Gala #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001 3175103a03aSKumar Gala if ((timeout == 4) || (timeout == 8) || (timeout == 12)) 3185103a03aSKumar Gala timeout++; 3195103a03aSKumar Gala #endif 3205103a03aSKumar Gala 3211336e2d3SHaijun.Zhang #ifdef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE 3221336e2d3SHaijun.Zhang timeout = 0xE; 3231336e2d3SHaijun.Zhang #endif 324c67bee14SStefano Babic esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); 32550586ef2SAndy Fleming 32650586ef2SAndy Fleming return 0; 32750586ef2SAndy Fleming } 32850586ef2SAndy Fleming 329e576bd90SEric Nelson static void check_and_invalidate_dcache_range 330e576bd90SEric Nelson (struct mmc_cmd *cmd, 331e576bd90SEric Nelson struct mmc_data *data) { 3328b06460eSYangbo Lu unsigned start = 0; 333cc634e28SYangbo Lu unsigned end = 0; 334e576bd90SEric Nelson unsigned size = roundup(ARCH_DMA_MINALIGN, 335e576bd90SEric Nelson data->blocks*data->blocksize); 3369702ec00SEddy Petrișor #if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) 3378b06460eSYangbo Lu dma_addr_t addr; 3388b06460eSYangbo Lu 3398b06460eSYangbo Lu addr = virt_to_phys((void *)(data->dest)); 3408b06460eSYangbo Lu if (upper_32_bits(addr)) 3418b06460eSYangbo Lu printf("Error found for upper 32 bits\n"); 3428b06460eSYangbo Lu else 3438b06460eSYangbo Lu start = lower_32_bits(addr); 344cc634e28SYangbo Lu #else 345cc634e28SYangbo Lu start = (unsigned)data->dest; 3468b06460eSYangbo Lu #endif 347cc634e28SYangbo Lu end = start + size; 348e576bd90SEric Nelson invalidate_dcache_range(start, end); 349e576bd90SEric Nelson } 35010dc7771STom Rini 35150586ef2SAndy Fleming /* 35250586ef2SAndy Fleming * Sends a command out on the bus. Takes the mmc pointer, 35350586ef2SAndy Fleming * a command pointer, and an optional data pointer. 35450586ef2SAndy Fleming */ 3559586aa6eSSimon Glass static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, 3569586aa6eSSimon Glass struct mmc_cmd *cmd, struct mmc_data *data) 35750586ef2SAndy Fleming { 3588a573022SAndrew Gabbasov int err = 0; 35950586ef2SAndy Fleming uint xfertyp; 36050586ef2SAndy Fleming uint irqstat; 36196f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 36250586ef2SAndy Fleming 363d621da00SJerry Huang #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 364d621da00SJerry Huang if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) 365d621da00SJerry Huang return 0; 366d621da00SJerry Huang #endif 367d621da00SJerry Huang 368c67bee14SStefano Babic esdhc_write32(®s->irqstat, -1); 36950586ef2SAndy Fleming 37050586ef2SAndy Fleming sync(); 37150586ef2SAndy Fleming 37250586ef2SAndy Fleming /* Wait for the bus to be idle */ 373c67bee14SStefano Babic while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || 374c67bee14SStefano Babic (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) 375c67bee14SStefano Babic ; 37650586ef2SAndy Fleming 377c67bee14SStefano Babic while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) 378c67bee14SStefano Babic ; 37950586ef2SAndy Fleming 38050586ef2SAndy Fleming /* Wait at least 8 SD clock cycles before the next command */ 38150586ef2SAndy Fleming /* 38250586ef2SAndy Fleming * Note: This is way more than 8 cycles, but 1ms seems to 38350586ef2SAndy Fleming * resolve timing issues with some cards 38450586ef2SAndy Fleming */ 38550586ef2SAndy Fleming udelay(1000); 38650586ef2SAndy Fleming 38750586ef2SAndy Fleming /* Set up for a data transfer if we have one */ 38850586ef2SAndy Fleming if (data) { 38909b465fdSSimon Glass err = esdhc_setup_data(priv, mmc, data); 39050586ef2SAndy Fleming if(err) 39150586ef2SAndy Fleming return err; 3924683b220SPeng Fan 3934683b220SPeng Fan if (data->flags & MMC_DATA_READ) 3944683b220SPeng Fan check_and_invalidate_dcache_range(cmd, data); 39550586ef2SAndy Fleming } 39650586ef2SAndy Fleming 39750586ef2SAndy Fleming /* Figure out the transfer arguments */ 39850586ef2SAndy Fleming xfertyp = esdhc_xfertyp(cmd, data); 39950586ef2SAndy Fleming 40001b77353SAndrew Gabbasov /* Mask all irqs */ 40101b77353SAndrew Gabbasov esdhc_write32(®s->irqsigen, 0); 40201b77353SAndrew Gabbasov 40350586ef2SAndy Fleming /* Send the command */ 404c67bee14SStefano Babic esdhc_write32(®s->cmdarg, cmd->cmdarg); 4054692708dSJason Liu #if defined(CONFIG_FSL_USDHC) 4064692708dSJason Liu esdhc_write32(®s->mixctrl, 4070e1bf614SVolodymyr Riazantsev (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F) 4080e1bf614SVolodymyr Riazantsev | (mmc->ddr_mode ? XFERTYP_DDREN : 0)); 4094692708dSJason Liu esdhc_write32(®s->xfertyp, xfertyp & 0xFFFF0000); 4104692708dSJason Liu #else 411c67bee14SStefano Babic esdhc_write32(®s->xfertyp, xfertyp); 4124692708dSJason Liu #endif 4137a5b8029SDirk Behme 41450586ef2SAndy Fleming /* Wait for the command to complete */ 4157a5b8029SDirk Behme while (!(esdhc_read32(®s->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE))) 416c67bee14SStefano Babic ; 41750586ef2SAndy Fleming 418c67bee14SStefano Babic irqstat = esdhc_read32(®s->irqstat); 41950586ef2SAndy Fleming 4208a573022SAndrew Gabbasov if (irqstat & CMD_ERR) { 421915ffa52SJaehoon Chung err = -ECOMM; 4228a573022SAndrew Gabbasov goto out; 4237a5b8029SDirk Behme } 4247a5b8029SDirk Behme 4258a573022SAndrew Gabbasov if (irqstat & IRQSTAT_CTOE) { 426915ffa52SJaehoon Chung err = -ETIMEDOUT; 4278a573022SAndrew Gabbasov goto out; 4288a573022SAndrew Gabbasov } 42950586ef2SAndy Fleming 430f022d36eSOtavio Salvador /* Switch voltage to 1.8V if CMD11 succeeded */ 431f022d36eSOtavio Salvador if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) { 432f022d36eSOtavio Salvador esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); 433f022d36eSOtavio Salvador 434f022d36eSOtavio Salvador printf("Run CMD11 1.8V switch\n"); 435f022d36eSOtavio Salvador /* Sleep for 5 ms - max time for card to switch to 1.8V */ 436f022d36eSOtavio Salvador udelay(5000); 437f022d36eSOtavio Salvador } 438f022d36eSOtavio Salvador 4397a5b8029SDirk Behme /* Workaround for ESDHC errata ENGcm03648 */ 4407a5b8029SDirk Behme if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { 441253d5bddSYangbo Lu int timeout = 6000; 4427a5b8029SDirk Behme 443253d5bddSYangbo Lu /* Poll on DATA0 line for cmd with busy signal for 600 ms */ 4447a5b8029SDirk Behme while (timeout > 0 && !(esdhc_read32(®s->prsstat) & 4457a5b8029SDirk Behme PRSSTAT_DAT0)) { 4467a5b8029SDirk Behme udelay(100); 4477a5b8029SDirk Behme timeout--; 4487a5b8029SDirk Behme } 4497a5b8029SDirk Behme 4507a5b8029SDirk Behme if (timeout <= 0) { 4517a5b8029SDirk Behme printf("Timeout waiting for DAT0 to go high!\n"); 452915ffa52SJaehoon Chung err = -ETIMEDOUT; 4538a573022SAndrew Gabbasov goto out; 4547a5b8029SDirk Behme } 4557a5b8029SDirk Behme } 4567a5b8029SDirk Behme 45750586ef2SAndy Fleming /* Copy the response to the response buffer */ 45850586ef2SAndy Fleming if (cmd->resp_type & MMC_RSP_136) { 45950586ef2SAndy Fleming u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; 46050586ef2SAndy Fleming 461c67bee14SStefano Babic cmdrsp3 = esdhc_read32(®s->cmdrsp3); 462c67bee14SStefano Babic cmdrsp2 = esdhc_read32(®s->cmdrsp2); 463c67bee14SStefano Babic cmdrsp1 = esdhc_read32(®s->cmdrsp1); 464c67bee14SStefano Babic cmdrsp0 = esdhc_read32(®s->cmdrsp0); 465998be3ddSRabin Vincent cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); 466998be3ddSRabin Vincent cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); 467998be3ddSRabin Vincent cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); 468998be3ddSRabin Vincent cmd->response[3] = (cmdrsp0 << 8); 46950586ef2SAndy Fleming } else 470c67bee14SStefano Babic cmd->response[0] = esdhc_read32(®s->cmdrsp0); 47150586ef2SAndy Fleming 47250586ef2SAndy Fleming /* Wait until all of the blocks are transferred */ 47350586ef2SAndy Fleming if (data) { 47477c1458dSDipen Dudhat #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO 47509b465fdSSimon Glass esdhc_pio_read_write(priv, data); 47677c1458dSDipen Dudhat #else 47750586ef2SAndy Fleming do { 478c67bee14SStefano Babic irqstat = esdhc_read32(®s->irqstat); 47950586ef2SAndy Fleming 4808a573022SAndrew Gabbasov if (irqstat & IRQSTAT_DTOE) { 481915ffa52SJaehoon Chung err = -ETIMEDOUT; 4828a573022SAndrew Gabbasov goto out; 4838a573022SAndrew Gabbasov } 48463fb5a7eSFrans Meulenbroeks 4858a573022SAndrew Gabbasov if (irqstat & DATA_ERR) { 486915ffa52SJaehoon Chung err = -ECOMM; 4878a573022SAndrew Gabbasov goto out; 4888a573022SAndrew Gabbasov } 4899b74dc56SAndrew Gabbasov } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); 49071689776SYe.Li 4914683b220SPeng Fan /* 4924683b220SPeng Fan * Need invalidate the dcache here again to avoid any 4934683b220SPeng Fan * cache-fill during the DMA operations such as the 4944683b220SPeng Fan * speculative pre-fetching etc. 4954683b220SPeng Fan */ 49654899fc8SEric Nelson if (data->flags & MMC_DATA_READ) 49754899fc8SEric Nelson check_and_invalidate_dcache_range(cmd, data); 49871689776SYe.Li #endif 49950586ef2SAndy Fleming } 50050586ef2SAndy Fleming 5018a573022SAndrew Gabbasov out: 5028a573022SAndrew Gabbasov /* Reset CMD and DATA portions on error */ 5038a573022SAndrew Gabbasov if (err) { 5048a573022SAndrew Gabbasov esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | 5058a573022SAndrew Gabbasov SYSCTL_RSTC); 5068a573022SAndrew Gabbasov while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) 5078a573022SAndrew Gabbasov ; 5088a573022SAndrew Gabbasov 5098a573022SAndrew Gabbasov if (data) { 5108a573022SAndrew Gabbasov esdhc_write32(®s->sysctl, 5118a573022SAndrew Gabbasov esdhc_read32(®s->sysctl) | 5128a573022SAndrew Gabbasov SYSCTL_RSTD); 5138a573022SAndrew Gabbasov while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) 5148a573022SAndrew Gabbasov ; 5158a573022SAndrew Gabbasov } 516f022d36eSOtavio Salvador 517f022d36eSOtavio Salvador /* If this was CMD11, then notify that power cycle is needed */ 518f022d36eSOtavio Salvador if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) 519f022d36eSOtavio Salvador printf("CMD11 to switch to 1.8V mode failed, card requires power cycle.\n"); 5208a573022SAndrew Gabbasov } 5218a573022SAndrew Gabbasov 522c67bee14SStefano Babic esdhc_write32(®s->irqstat, -1); 52350586ef2SAndy Fleming 5248a573022SAndrew Gabbasov return err; 52550586ef2SAndy Fleming } 52650586ef2SAndy Fleming 52709b465fdSSimon Glass static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) 52850586ef2SAndy Fleming { 5294f425280SBenoît Thébaudeau int div = 1; 5304f425280SBenoît Thébaudeau #ifdef ARCH_MXC 5314f425280SBenoît Thébaudeau int pre_div = 1; 5324f425280SBenoît Thébaudeau #else 5334f425280SBenoît Thébaudeau int pre_div = 2; 5344f425280SBenoît Thébaudeau #endif 5354f425280SBenoît Thébaudeau int ddr_pre_div = mmc->ddr_mode ? 2 : 1; 53696f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 53796f0407bSPeng Fan int sdhc_clk = priv->sdhc_clk; 53850586ef2SAndy Fleming uint clk; 53950586ef2SAndy Fleming 54093bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 54193bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 542c67bee14SStefano Babic 5434f425280SBenoît Thébaudeau while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256) 5444f425280SBenoît Thébaudeau pre_div *= 2; 54550586ef2SAndy Fleming 5464f425280SBenoît Thébaudeau while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16) 5474f425280SBenoît Thébaudeau div++; 54850586ef2SAndy Fleming 5494f425280SBenoît Thébaudeau pre_div >>= 1; 55050586ef2SAndy Fleming div -= 1; 55150586ef2SAndy Fleming 55250586ef2SAndy Fleming clk = (pre_div << 8) | (div << 4); 55350586ef2SAndy Fleming 554f0b5f23fSEric Nelson #ifdef CONFIG_FSL_USDHC 55584ecdf6dSYe Li esdhc_clrbits32(®s->vendorspec, VENDORSPEC_CKEN); 556f0b5f23fSEric Nelson #else 557c67bee14SStefano Babic esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); 558f0b5f23fSEric Nelson #endif 559c67bee14SStefano Babic 560c67bee14SStefano Babic esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); 56150586ef2SAndy Fleming 56250586ef2SAndy Fleming udelay(10000); 56350586ef2SAndy Fleming 564f0b5f23fSEric Nelson #ifdef CONFIG_FSL_USDHC 56584ecdf6dSYe Li esdhc_setbits32(®s->vendorspec, VENDORSPEC_PEREN | VENDORSPEC_CKEN); 566f0b5f23fSEric Nelson #else 567f0b5f23fSEric Nelson esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); 568f0b5f23fSEric Nelson #endif 569c67bee14SStefano Babic 57050586ef2SAndy Fleming } 57150586ef2SAndy Fleming 5722d9ca2c7SYangbo Lu #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK 57309b465fdSSimon Glass static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) 5742d9ca2c7SYangbo Lu { 57596f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 5762d9ca2c7SYangbo Lu u32 value; 5772d9ca2c7SYangbo Lu u32 time_out; 5782d9ca2c7SYangbo Lu 5792d9ca2c7SYangbo Lu value = esdhc_read32(®s->sysctl); 5802d9ca2c7SYangbo Lu 5812d9ca2c7SYangbo Lu if (enable) 5822d9ca2c7SYangbo Lu value |= SYSCTL_CKEN; 5832d9ca2c7SYangbo Lu else 5842d9ca2c7SYangbo Lu value &= ~SYSCTL_CKEN; 5852d9ca2c7SYangbo Lu 5862d9ca2c7SYangbo Lu esdhc_write32(®s->sysctl, value); 5872d9ca2c7SYangbo Lu 5882d9ca2c7SYangbo Lu time_out = 20; 5892d9ca2c7SYangbo Lu value = PRSSTAT_SDSTB; 5902d9ca2c7SYangbo Lu while (!(esdhc_read32(®s->prsstat) & value)) { 5912d9ca2c7SYangbo Lu if (time_out == 0) { 5922d9ca2c7SYangbo Lu printf("fsl_esdhc: Internal clock never stabilised.\n"); 5932d9ca2c7SYangbo Lu break; 5942d9ca2c7SYangbo Lu } 5952d9ca2c7SYangbo Lu time_out--; 5962d9ca2c7SYangbo Lu mdelay(1); 5972d9ca2c7SYangbo Lu } 5982d9ca2c7SYangbo Lu } 5992d9ca2c7SYangbo Lu #endif 6002d9ca2c7SYangbo Lu 6019586aa6eSSimon Glass static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) 60250586ef2SAndy Fleming { 60396f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 60450586ef2SAndy Fleming 6052d9ca2c7SYangbo Lu #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK 6062d9ca2c7SYangbo Lu /* Select to use peripheral clock */ 60709b465fdSSimon Glass esdhc_clock_control(priv, false); 6082d9ca2c7SYangbo Lu esdhc_setbits32(®s->scr, ESDHCCTL_PCS); 60909b465fdSSimon Glass esdhc_clock_control(priv, true); 6102d9ca2c7SYangbo Lu #endif 61150586ef2SAndy Fleming /* Set the clock speed */ 61209b465fdSSimon Glass set_sysctl(priv, mmc, mmc->clock); 61350586ef2SAndy Fleming 61450586ef2SAndy Fleming /* Set the bus width */ 615c67bee14SStefano Babic esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); 61650586ef2SAndy Fleming 61750586ef2SAndy Fleming if (mmc->bus_width == 4) 618c67bee14SStefano Babic esdhc_setbits32(®s->proctl, PROCTL_DTW_4); 61950586ef2SAndy Fleming else if (mmc->bus_width == 8) 620c67bee14SStefano Babic esdhc_setbits32(®s->proctl, PROCTL_DTW_8); 621c67bee14SStefano Babic 62207b0b9c0SJaehoon Chung return 0; 62350586ef2SAndy Fleming } 62450586ef2SAndy Fleming 6259586aa6eSSimon Glass static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) 62650586ef2SAndy Fleming { 62796f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 628201e828bSSimon Glass ulong start; 62950586ef2SAndy Fleming 630c67bee14SStefano Babic /* Reset the entire host controller */ 631a61da72bSDirk Behme esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); 632c67bee14SStefano Babic 633c67bee14SStefano Babic /* Wait until the controller is available */ 634201e828bSSimon Glass start = get_timer(0); 635201e828bSSimon Glass while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { 636201e828bSSimon Glass if (get_timer(start) > 1000) 637201e828bSSimon Glass return -ETIMEDOUT; 638201e828bSSimon Glass } 639c67bee14SStefano Babic 640f53225ccSPeng Fan #if defined(CONFIG_FSL_USDHC) 641f53225ccSPeng Fan /* RSTA doesn't reset MMC_BOOT register, so manually reset it */ 642f53225ccSPeng Fan esdhc_write32(®s->mmcboot, 0x0); 643f53225ccSPeng Fan /* Reset MIX_CTRL and CLK_TUNE_CTRL_STATUS regs to 0 */ 644f53225ccSPeng Fan esdhc_write32(®s->mixctrl, 0x0); 645f53225ccSPeng Fan esdhc_write32(®s->clktunectrlstatus, 0x0); 646f53225ccSPeng Fan 647f53225ccSPeng Fan /* Put VEND_SPEC to default value */ 648f53225ccSPeng Fan esdhc_write32(®s->vendorspec, VENDORSPEC_INIT); 649f53225ccSPeng Fan 650f53225ccSPeng Fan /* Disable DLL_CTRL delay line */ 651f53225ccSPeng Fan esdhc_write32(®s->dllctrl, 0x0); 652f53225ccSPeng Fan #endif 653f53225ccSPeng Fan 65416e43f35SBenoît Thébaudeau #ifndef ARCH_MXC 6552c1764efSP.V.Suresh /* Enable cache snooping */ 6562c1764efSP.V.Suresh esdhc_write32(®s->scr, 0x00000040); 65716e43f35SBenoît Thébaudeau #endif 6582c1764efSP.V.Suresh 659f0b5f23fSEric Nelson #ifndef CONFIG_FSL_USDHC 660a61da72bSDirk Behme esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); 66184ecdf6dSYe Li #else 66284ecdf6dSYe Li esdhc_setbits32(®s->vendorspec, VENDORSPEC_HCKEN | VENDORSPEC_IPGEN); 663f0b5f23fSEric Nelson #endif 66450586ef2SAndy Fleming 66550586ef2SAndy Fleming /* Set the initial clock speed */ 6664a6ee172SJerry Huang mmc_set_clock(mmc, 400000); 66750586ef2SAndy Fleming 66850586ef2SAndy Fleming /* Disable the BRR and BWR bits in IRQSTAT */ 669c67bee14SStefano Babic esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); 67050586ef2SAndy Fleming 67150586ef2SAndy Fleming /* Put the PROCTL reg back to the default */ 672c67bee14SStefano Babic esdhc_write32(®s->proctl, PROCTL_INIT); 67350586ef2SAndy Fleming 674c67bee14SStefano Babic /* Set timout to the maximum value */ 675c67bee14SStefano Babic esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); 676c67bee14SStefano Babic 67732a9179fSPeng Fan if (priv->vs18_enable) 67832a9179fSPeng Fan esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); 67932a9179fSPeng Fan 680d48d2e21SThierry Reding return 0; 68150586ef2SAndy Fleming } 68250586ef2SAndy Fleming 6839586aa6eSSimon Glass static int esdhc_getcd_common(struct fsl_esdhc_priv *priv) 684d48d2e21SThierry Reding { 68596f0407bSPeng Fan struct fsl_esdhc *regs = priv->esdhc_regs; 686d48d2e21SThierry Reding int timeout = 1000; 687d48d2e21SThierry Reding 688f7e27cc5SHaijun.Zhang #ifdef CONFIG_ESDHC_DETECT_QUIRK 689f7e27cc5SHaijun.Zhang if (CONFIG_ESDHC_DETECT_QUIRK) 690f7e27cc5SHaijun.Zhang return 1; 691f7e27cc5SHaijun.Zhang #endif 69296f0407bSPeng Fan 69396f0407bSPeng Fan #ifdef CONFIG_DM_MMC 69496f0407bSPeng Fan if (priv->non_removable) 69596f0407bSPeng Fan return 1; 696fc8048a8SYangbo Lu #ifdef CONFIG_DM_GPIO 69796f0407bSPeng Fan if (dm_gpio_is_valid(&priv->cd_gpio)) 69896f0407bSPeng Fan return dm_gpio_get_value(&priv->cd_gpio); 69996f0407bSPeng Fan #endif 700fc8048a8SYangbo Lu #endif 70196f0407bSPeng Fan 702d48d2e21SThierry Reding while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) 703d48d2e21SThierry Reding udelay(1000); 704d48d2e21SThierry Reding 705d48d2e21SThierry Reding return timeout > 0; 706c67bee14SStefano Babic } 707c67bee14SStefano Babic 708446e077aSSimon Glass static int esdhc_reset(struct fsl_esdhc *regs) 70948bb3bb5SJerry Huang { 710446e077aSSimon Glass ulong start; 71148bb3bb5SJerry Huang 71248bb3bb5SJerry Huang /* reset the controller */ 713a61da72bSDirk Behme esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); 71448bb3bb5SJerry Huang 71548bb3bb5SJerry Huang /* hardware clears the bit when it is done */ 716446e077aSSimon Glass start = get_timer(0); 717446e077aSSimon Glass while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { 718446e077aSSimon Glass if (get_timer(start) > 100) { 71948bb3bb5SJerry Huang printf("MMC/SD: Reset never completed.\n"); 720446e077aSSimon Glass return -ETIMEDOUT; 721446e077aSSimon Glass } 722446e077aSSimon Glass } 723446e077aSSimon Glass 724446e077aSSimon Glass return 0; 72548bb3bb5SJerry Huang } 72648bb3bb5SJerry Huang 7279586aa6eSSimon Glass static int esdhc_getcd(struct mmc *mmc) 7289586aa6eSSimon Glass { 7299586aa6eSSimon Glass struct fsl_esdhc_priv *priv = mmc->priv; 7309586aa6eSSimon Glass 7319586aa6eSSimon Glass return esdhc_getcd_common(priv); 7329586aa6eSSimon Glass } 7339586aa6eSSimon Glass 7349586aa6eSSimon Glass static int esdhc_init(struct mmc *mmc) 7359586aa6eSSimon Glass { 7369586aa6eSSimon Glass struct fsl_esdhc_priv *priv = mmc->priv; 7379586aa6eSSimon Glass 7389586aa6eSSimon Glass return esdhc_init_common(priv, mmc); 7399586aa6eSSimon Glass } 7409586aa6eSSimon Glass 7419586aa6eSSimon Glass static int esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, 7429586aa6eSSimon Glass struct mmc_data *data) 7439586aa6eSSimon Glass { 7449586aa6eSSimon Glass struct fsl_esdhc_priv *priv = mmc->priv; 7459586aa6eSSimon Glass 7469586aa6eSSimon Glass return esdhc_send_cmd_common(priv, mmc, cmd, data); 7479586aa6eSSimon Glass } 7489586aa6eSSimon Glass 7499586aa6eSSimon Glass static int esdhc_set_ios(struct mmc *mmc) 7509586aa6eSSimon Glass { 7519586aa6eSSimon Glass struct fsl_esdhc_priv *priv = mmc->priv; 7529586aa6eSSimon Glass 7539586aa6eSSimon Glass return esdhc_set_ios_common(priv, mmc); 7549586aa6eSSimon Glass } 7559586aa6eSSimon Glass 756ab769f22SPantelis Antoniou static const struct mmc_ops esdhc_ops = { 7579586aa6eSSimon Glass .getcd = esdhc_getcd, 7589586aa6eSSimon Glass .init = esdhc_init, 759ab769f22SPantelis Antoniou .send_cmd = esdhc_send_cmd, 760ab769f22SPantelis Antoniou .set_ios = esdhc_set_ios, 761ab769f22SPantelis Antoniou }; 762ab769f22SPantelis Antoniou 763e88e1d9cSSimon Glass static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, 764e88e1d9cSSimon Glass struct fsl_esdhc_plat *plat) 76550586ef2SAndy Fleming { 766e88e1d9cSSimon Glass struct mmc_config *cfg; 767c67bee14SStefano Babic struct fsl_esdhc *regs; 768030955c2SLi Yang u32 caps, voltage_caps; 769446e077aSSimon Glass int ret; 77050586ef2SAndy Fleming 77196f0407bSPeng Fan if (!priv) 77296f0407bSPeng Fan return -EINVAL; 773c67bee14SStefano Babic 77496f0407bSPeng Fan regs = priv->esdhc_regs; 775c67bee14SStefano Babic 77648bb3bb5SJerry Huang /* First reset the eSDHC controller */ 777446e077aSSimon Glass ret = esdhc_reset(regs); 778446e077aSSimon Glass if (ret) 779446e077aSSimon Glass return ret; 78048bb3bb5SJerry Huang 781f0b5f23fSEric Nelson #ifndef CONFIG_FSL_USDHC 782975324a7SJerry Huang esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN 783975324a7SJerry Huang | SYSCTL_IPGEN | SYSCTL_CKEN); 78484ecdf6dSYe Li #else 78584ecdf6dSYe Li esdhc_setbits32(®s->vendorspec, VENDORSPEC_PEREN | 78684ecdf6dSYe Li VENDORSPEC_HCKEN | VENDORSPEC_IPGEN | VENDORSPEC_CKEN); 787f0b5f23fSEric Nelson #endif 788975324a7SJerry Huang 78932a9179fSPeng Fan if (priv->vs18_enable) 79032a9179fSPeng Fan esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); 79132a9179fSPeng Fan 792a3d6e386SYe.Li writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); 793e88e1d9cSSimon Glass cfg = &plat->cfg; 794e88e1d9cSSimon Glass memset(cfg, '\0', sizeof(*cfg)); 79593bfd616SPantelis Antoniou 796030955c2SLi Yang voltage_caps = 0; 79719060bd8SWang Huan caps = esdhc_read32(®s->hostcapblt); 7983b4456ecSRoy Zang 7993b4456ecSRoy Zang #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 8003b4456ecSRoy Zang caps = caps & ~(ESDHC_HOSTCAPBLT_SRS | 8013b4456ecSRoy Zang ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30); 8023b4456ecSRoy Zang #endif 803ef38f3ffSHaijun.Zhang 804ef38f3ffSHaijun.Zhang /* T4240 host controller capabilities register should have VS33 bit */ 805ef38f3ffSHaijun.Zhang #ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 806ef38f3ffSHaijun.Zhang caps = caps | ESDHC_HOSTCAPBLT_VS33; 807ef38f3ffSHaijun.Zhang #endif 808ef38f3ffSHaijun.Zhang 80950586ef2SAndy Fleming if (caps & ESDHC_HOSTCAPBLT_VS18) 810030955c2SLi Yang voltage_caps |= MMC_VDD_165_195; 81150586ef2SAndy Fleming if (caps & ESDHC_HOSTCAPBLT_VS30) 812030955c2SLi Yang voltage_caps |= MMC_VDD_29_30 | MMC_VDD_30_31; 81350586ef2SAndy Fleming if (caps & ESDHC_HOSTCAPBLT_VS33) 814030955c2SLi Yang voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34; 815030955c2SLi Yang 816e88e1d9cSSimon Glass cfg->name = "FSL_SDHC"; 817e88e1d9cSSimon Glass cfg->ops = &esdhc_ops; 818030955c2SLi Yang #ifdef CONFIG_SYS_SD_VOLTAGE 819e88e1d9cSSimon Glass cfg->voltages = CONFIG_SYS_SD_VOLTAGE; 820030955c2SLi Yang #else 821e88e1d9cSSimon Glass cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 822030955c2SLi Yang #endif 823e88e1d9cSSimon Glass if ((cfg->voltages & voltage_caps) == 0) { 824030955c2SLi Yang printf("voltage not supported by controller\n"); 825030955c2SLi Yang return -1; 826030955c2SLi Yang } 82750586ef2SAndy Fleming 82896f0407bSPeng Fan if (priv->bus_width == 8) 829e88e1d9cSSimon Glass cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT; 83096f0407bSPeng Fan else if (priv->bus_width == 4) 831e88e1d9cSSimon Glass cfg->host_caps = MMC_MODE_4BIT; 83296f0407bSPeng Fan 833e88e1d9cSSimon Glass cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT; 8340e1bf614SVolodymyr Riazantsev #ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE 835e88e1d9cSSimon Glass cfg->host_caps |= MMC_MODE_DDR_52MHz; 8360e1bf614SVolodymyr Riazantsev #endif 83750586ef2SAndy Fleming 83896f0407bSPeng Fan if (priv->bus_width > 0) { 83996f0407bSPeng Fan if (priv->bus_width < 8) 840e88e1d9cSSimon Glass cfg->host_caps &= ~MMC_MODE_8BIT; 84196f0407bSPeng Fan if (priv->bus_width < 4) 842e88e1d9cSSimon Glass cfg->host_caps &= ~MMC_MODE_4BIT; 843aad4659aSAbbas Raza } 844aad4659aSAbbas Raza 84550586ef2SAndy Fleming if (caps & ESDHC_HOSTCAPBLT_HSS) 846e88e1d9cSSimon Glass cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 84750586ef2SAndy Fleming 848d47e3d27SHaijun.Zhang #ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK 849d47e3d27SHaijun.Zhang if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) 850e88e1d9cSSimon Glass cfg->host_caps &= ~MMC_MODE_8BIT; 851d47e3d27SHaijun.Zhang #endif 852d47e3d27SHaijun.Zhang 853e88e1d9cSSimon Glass cfg->f_min = 400000; 854e88e1d9cSSimon Glass cfg->f_max = min(priv->sdhc_clk, (u32)52000000); 85550586ef2SAndy Fleming 856e88e1d9cSSimon Glass cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 85793bfd616SPantelis Antoniou 85896f0407bSPeng Fan return 0; 85996f0407bSPeng Fan } 86096f0407bSPeng Fan 8612e87c440SJagan Teki #ifndef CONFIG_DM_MMC 8622e87c440SJagan Teki static int fsl_esdhc_cfg_to_priv(struct fsl_esdhc_cfg *cfg, 8632e87c440SJagan Teki struct fsl_esdhc_priv *priv) 8642e87c440SJagan Teki { 8652e87c440SJagan Teki if (!cfg || !priv) 8662e87c440SJagan Teki return -EINVAL; 8672e87c440SJagan Teki 8682e87c440SJagan Teki priv->esdhc_regs = (struct fsl_esdhc *)(unsigned long)(cfg->esdhc_base); 8692e87c440SJagan Teki priv->bus_width = cfg->max_bus_width; 8702e87c440SJagan Teki priv->sdhc_clk = cfg->sdhc_clk; 8712e87c440SJagan Teki priv->wp_enable = cfg->wp_enable; 87232a9179fSPeng Fan priv->vs18_enable = cfg->vs18_enable; 8732e87c440SJagan Teki 8742e87c440SJagan Teki return 0; 8752e87c440SJagan Teki }; 8762e87c440SJagan Teki 87796f0407bSPeng Fan int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) 87896f0407bSPeng Fan { 879e88e1d9cSSimon Glass struct fsl_esdhc_plat *plat; 88096f0407bSPeng Fan struct fsl_esdhc_priv *priv; 881*d6eb25e9SSimon Glass struct mmc *mmc; 88296f0407bSPeng Fan int ret; 88396f0407bSPeng Fan 88496f0407bSPeng Fan if (!cfg) 88596f0407bSPeng Fan return -EINVAL; 88696f0407bSPeng Fan 88796f0407bSPeng Fan priv = calloc(sizeof(struct fsl_esdhc_priv), 1); 88896f0407bSPeng Fan if (!priv) 88996f0407bSPeng Fan return -ENOMEM; 890e88e1d9cSSimon Glass plat = calloc(sizeof(struct fsl_esdhc_plat), 1); 891e88e1d9cSSimon Glass if (!plat) { 892e88e1d9cSSimon Glass free(priv); 893e88e1d9cSSimon Glass return -ENOMEM; 894e88e1d9cSSimon Glass } 89596f0407bSPeng Fan 89696f0407bSPeng Fan ret = fsl_esdhc_cfg_to_priv(cfg, priv); 89796f0407bSPeng Fan if (ret) { 89896f0407bSPeng Fan debug("%s xlate failure\n", __func__); 899e88e1d9cSSimon Glass free(plat); 90096f0407bSPeng Fan free(priv); 90196f0407bSPeng Fan return ret; 90296f0407bSPeng Fan } 90396f0407bSPeng Fan 904e88e1d9cSSimon Glass ret = fsl_esdhc_init(priv, plat); 90596f0407bSPeng Fan if (ret) { 90696f0407bSPeng Fan debug("%s init failure\n", __func__); 907e88e1d9cSSimon Glass free(plat); 90896f0407bSPeng Fan free(priv); 90996f0407bSPeng Fan return ret; 91096f0407bSPeng Fan } 91196f0407bSPeng Fan 912*d6eb25e9SSimon Glass mmc = mmc_create(&plat->cfg, priv); 913*d6eb25e9SSimon Glass if (!mmc) 914*d6eb25e9SSimon Glass return -EIO; 915*d6eb25e9SSimon Glass 916*d6eb25e9SSimon Glass priv->mmc = mmc; 917*d6eb25e9SSimon Glass 91850586ef2SAndy Fleming return 0; 91950586ef2SAndy Fleming } 92050586ef2SAndy Fleming 92150586ef2SAndy Fleming int fsl_esdhc_mmc_init(bd_t *bis) 92250586ef2SAndy Fleming { 923c67bee14SStefano Babic struct fsl_esdhc_cfg *cfg; 924c67bee14SStefano Babic 92588227a1dSFabio Estevam cfg = calloc(sizeof(struct fsl_esdhc_cfg), 1); 926c67bee14SStefano Babic cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; 927e9adeca3SSimon Glass cfg->sdhc_clk = gd->arch.sdhc_clk; 928c67bee14SStefano Babic return fsl_esdhc_initialize(bis, cfg); 92950586ef2SAndy Fleming } 9302e87c440SJagan Teki #endif 931b33433a6SAnton Vorontsov 9325a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 9335a8dbdc6SYangbo Lu void mmc_adapter_card_type_ident(void) 9345a8dbdc6SYangbo Lu { 9355a8dbdc6SYangbo Lu u8 card_id; 9365a8dbdc6SYangbo Lu u8 value; 9375a8dbdc6SYangbo Lu 9385a8dbdc6SYangbo Lu card_id = QIXIS_READ(present) & QIXIS_SDID_MASK; 9395a8dbdc6SYangbo Lu gd->arch.sdhc_adapter = card_id; 9405a8dbdc6SYangbo Lu 9415a8dbdc6SYangbo Lu switch (card_id) { 9425a8dbdc6SYangbo Lu case QIXIS_ESDHC_ADAPTER_TYPE_EMMC45: 943cdc69550SYangbo Lu value = QIXIS_READ(brdcfg[5]); 944cdc69550SYangbo Lu value |= (QIXIS_DAT4 | QIXIS_DAT5_6_7); 945cdc69550SYangbo Lu QIXIS_WRITE(brdcfg[5], value); 9465a8dbdc6SYangbo Lu break; 9475a8dbdc6SYangbo Lu case QIXIS_ESDHC_ADAPTER_TYPE_SDMMC_LEGACY: 948bf50be83SYangbo Lu value = QIXIS_READ(pwr_ctl[1]); 949bf50be83SYangbo Lu value |= QIXIS_EVDD_BY_SDHC_VS; 950bf50be83SYangbo Lu QIXIS_WRITE(pwr_ctl[1], value); 9515a8dbdc6SYangbo Lu break; 9525a8dbdc6SYangbo Lu case QIXIS_ESDHC_ADAPTER_TYPE_EMMC44: 9535a8dbdc6SYangbo Lu value = QIXIS_READ(brdcfg[5]); 9545a8dbdc6SYangbo Lu value |= (QIXIS_SDCLKIN | QIXIS_SDCLKOUT); 9555a8dbdc6SYangbo Lu QIXIS_WRITE(brdcfg[5], value); 9565a8dbdc6SYangbo Lu break; 9575a8dbdc6SYangbo Lu case QIXIS_ESDHC_ADAPTER_TYPE_RSV: 9585a8dbdc6SYangbo Lu break; 9595a8dbdc6SYangbo Lu case QIXIS_ESDHC_ADAPTER_TYPE_MMC: 9605a8dbdc6SYangbo Lu break; 9615a8dbdc6SYangbo Lu case QIXIS_ESDHC_ADAPTER_TYPE_SD: 9625a8dbdc6SYangbo Lu break; 9635a8dbdc6SYangbo Lu case QIXIS_ESDHC_NO_ADAPTER: 9645a8dbdc6SYangbo Lu break; 9655a8dbdc6SYangbo Lu default: 9665a8dbdc6SYangbo Lu break; 9675a8dbdc6SYangbo Lu } 9685a8dbdc6SYangbo Lu } 9695a8dbdc6SYangbo Lu #endif 9705a8dbdc6SYangbo Lu 971c67bee14SStefano Babic #ifdef CONFIG_OF_LIBFDT 972fce1e16cSYangbo Lu __weak int esdhc_status_fixup(void *blob, const char *compat) 973fce1e16cSYangbo Lu { 974fce1e16cSYangbo Lu #ifdef CONFIG_FSL_ESDHC_PIN_MUX 975fce1e16cSYangbo Lu if (!hwconfig("esdhc")) { 976fce1e16cSYangbo Lu do_fixup_by_compat(blob, compat, "status", "disabled", 977fce1e16cSYangbo Lu sizeof("disabled"), 1); 978fce1e16cSYangbo Lu return 1; 979fce1e16cSYangbo Lu } 980fce1e16cSYangbo Lu #endif 981fce1e16cSYangbo Lu return 0; 982fce1e16cSYangbo Lu } 983fce1e16cSYangbo Lu 984b33433a6SAnton Vorontsov void fdt_fixup_esdhc(void *blob, bd_t *bd) 985b33433a6SAnton Vorontsov { 986b33433a6SAnton Vorontsov const char *compat = "fsl,esdhc"; 987b33433a6SAnton Vorontsov 988fce1e16cSYangbo Lu if (esdhc_status_fixup(blob, compat)) 989a6da8b81SChenhui Zhao return; 990b33433a6SAnton Vorontsov 9912d9ca2c7SYangbo Lu #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK 9922d9ca2c7SYangbo Lu do_fixup_by_compat_u32(blob, compat, "peripheral-frequency", 9932d9ca2c7SYangbo Lu gd->arch.sdhc_clk, 1); 9942d9ca2c7SYangbo Lu #else 995b33433a6SAnton Vorontsov do_fixup_by_compat_u32(blob, compat, "clock-frequency", 996e9adeca3SSimon Glass gd->arch.sdhc_clk, 1); 9972d9ca2c7SYangbo Lu #endif 9985a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 9995a8dbdc6SYangbo Lu do_fixup_by_compat_u32(blob, compat, "adapter-type", 10005a8dbdc6SYangbo Lu (u32)(gd->arch.sdhc_adapter), 1); 10015a8dbdc6SYangbo Lu #endif 1002b33433a6SAnton Vorontsov } 1003c67bee14SStefano Babic #endif 100496f0407bSPeng Fan 100596f0407bSPeng Fan #ifdef CONFIG_DM_MMC 100696f0407bSPeng Fan #include <asm/arch/clock.h> 1007b60f1457SPeng Fan __weak void init_clk_usdhc(u32 index) 1008b60f1457SPeng Fan { 1009b60f1457SPeng Fan } 1010b60f1457SPeng Fan 101196f0407bSPeng Fan static int fsl_esdhc_probe(struct udevice *dev) 101296f0407bSPeng Fan { 101396f0407bSPeng Fan struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 1014e88e1d9cSSimon Glass struct fsl_esdhc_plat *plat = dev_get_platdata(dev); 101596f0407bSPeng Fan struct fsl_esdhc_priv *priv = dev_get_priv(dev); 101696f0407bSPeng Fan const void *fdt = gd->fdt_blob; 1017e160f7d4SSimon Glass int node = dev_of_offset(dev); 10189bb272e9SYork Sun #ifdef CONFIG_DM_REGULATOR 10194483b7ebSPeng Fan struct udevice *vqmmc_dev; 10209bb272e9SYork Sun #endif 102196f0407bSPeng Fan fdt_addr_t addr; 102296f0407bSPeng Fan unsigned int val; 102396f0407bSPeng Fan int ret; 102496f0407bSPeng Fan 1025a821c4afSSimon Glass addr = devfdt_get_addr(dev); 102696f0407bSPeng Fan if (addr == FDT_ADDR_T_NONE) 102796f0407bSPeng Fan return -EINVAL; 102896f0407bSPeng Fan 102996f0407bSPeng Fan priv->esdhc_regs = (struct fsl_esdhc *)addr; 103096f0407bSPeng Fan priv->dev = dev; 103196f0407bSPeng Fan 103296f0407bSPeng Fan val = fdtdec_get_int(fdt, node, "bus-width", -1); 103396f0407bSPeng Fan if (val == 8) 103496f0407bSPeng Fan priv->bus_width = 8; 103596f0407bSPeng Fan else if (val == 4) 103696f0407bSPeng Fan priv->bus_width = 4; 103796f0407bSPeng Fan else 103896f0407bSPeng Fan priv->bus_width = 1; 103996f0407bSPeng Fan 104096f0407bSPeng Fan if (fdt_get_property(fdt, node, "non-removable", NULL)) { 104196f0407bSPeng Fan priv->non_removable = 1; 104296f0407bSPeng Fan } else { 104396f0407bSPeng Fan priv->non_removable = 0; 1044fc8048a8SYangbo Lu #ifdef CONFIG_DM_GPIO 1045150c5afeSSimon Glass gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios", 1046150c5afeSSimon Glass 0, &priv->cd_gpio, GPIOD_IS_IN); 1047fc8048a8SYangbo Lu #endif 104896f0407bSPeng Fan } 104996f0407bSPeng Fan 10501483151eSPeng Fan priv->wp_enable = 1; 10511483151eSPeng Fan 1052fc8048a8SYangbo Lu #ifdef CONFIG_DM_GPIO 1053150c5afeSSimon Glass ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "wp-gpios", 0, 10541483151eSPeng Fan &priv->wp_gpio, GPIOD_IS_IN); 10551483151eSPeng Fan if (ret) 10561483151eSPeng Fan priv->wp_enable = 0; 1057fc8048a8SYangbo Lu #endif 10584483b7ebSPeng Fan 10594483b7ebSPeng Fan priv->vs18_enable = 0; 10604483b7ebSPeng Fan 10614483b7ebSPeng Fan #ifdef CONFIG_DM_REGULATOR 10624483b7ebSPeng Fan /* 10634483b7ebSPeng Fan * If emmc I/O has a fixed voltage at 1.8V, this must be provided, 10644483b7ebSPeng Fan * otherwise, emmc will work abnormally. 10654483b7ebSPeng Fan */ 10664483b7ebSPeng Fan ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev); 10674483b7ebSPeng Fan if (ret) { 10684483b7ebSPeng Fan dev_dbg(dev, "no vqmmc-supply\n"); 10694483b7ebSPeng Fan } else { 10704483b7ebSPeng Fan ret = regulator_set_enable(vqmmc_dev, true); 10714483b7ebSPeng Fan if (ret) { 10724483b7ebSPeng Fan dev_err(dev, "fail to enable vqmmc-supply\n"); 10734483b7ebSPeng Fan return ret; 10744483b7ebSPeng Fan } 10754483b7ebSPeng Fan 10764483b7ebSPeng Fan if (regulator_get_value(vqmmc_dev) == 1800000) 10774483b7ebSPeng Fan priv->vs18_enable = 1; 10784483b7ebSPeng Fan } 10794483b7ebSPeng Fan #endif 10804483b7ebSPeng Fan 108196f0407bSPeng Fan /* 108296f0407bSPeng Fan * TODO: 108396f0407bSPeng Fan * Because lack of clk driver, if SDHC clk is not enabled, 108496f0407bSPeng Fan * need to enable it first before this driver is invoked. 108596f0407bSPeng Fan * 108696f0407bSPeng Fan * we use MXC_ESDHC_CLK to get clk freq. 108796f0407bSPeng Fan * If one would like to make this function work, 108896f0407bSPeng Fan * the aliases should be provided in dts as this: 108996f0407bSPeng Fan * 109096f0407bSPeng Fan * aliases { 109196f0407bSPeng Fan * mmc0 = &usdhc1; 109296f0407bSPeng Fan * mmc1 = &usdhc2; 109396f0407bSPeng Fan * mmc2 = &usdhc3; 109496f0407bSPeng Fan * mmc3 = &usdhc4; 109596f0407bSPeng Fan * }; 109696f0407bSPeng Fan * Then if your board only supports mmc2 and mmc3, but we can 109796f0407bSPeng Fan * correctly get the seq as 2 and 3, then let mxc_get_clock 109896f0407bSPeng Fan * work as expected. 109996f0407bSPeng Fan */ 1100b60f1457SPeng Fan 1101b60f1457SPeng Fan init_clk_usdhc(dev->seq); 1102b60f1457SPeng Fan 110396f0407bSPeng Fan priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq); 110496f0407bSPeng Fan if (priv->sdhc_clk <= 0) { 110596f0407bSPeng Fan dev_err(dev, "Unable to get clk for %s\n", dev->name); 110696f0407bSPeng Fan return -EINVAL; 110796f0407bSPeng Fan } 110896f0407bSPeng Fan 1109e88e1d9cSSimon Glass ret = fsl_esdhc_init(priv, plat); 111096f0407bSPeng Fan if (ret) { 111196f0407bSPeng Fan dev_err(dev, "fsl_esdhc_init failure\n"); 111296f0407bSPeng Fan return ret; 111396f0407bSPeng Fan } 111496f0407bSPeng Fan 111596f0407bSPeng Fan upriv->mmc = priv->mmc; 111635ae9946SPeng Fan priv->mmc->dev = dev; 111796f0407bSPeng Fan 111896f0407bSPeng Fan return 0; 111996f0407bSPeng Fan } 112096f0407bSPeng Fan 112196f0407bSPeng Fan static const struct udevice_id fsl_esdhc_ids[] = { 112296f0407bSPeng Fan { .compatible = "fsl,imx6ul-usdhc", }, 112396f0407bSPeng Fan { .compatible = "fsl,imx6sx-usdhc", }, 112496f0407bSPeng Fan { .compatible = "fsl,imx6sl-usdhc", }, 112596f0407bSPeng Fan { .compatible = "fsl,imx6q-usdhc", }, 112696f0407bSPeng Fan { .compatible = "fsl,imx7d-usdhc", }, 1127b60f1457SPeng Fan { .compatible = "fsl,imx7ulp-usdhc", }, 1128a6473f8eSYangbo Lu { .compatible = "fsl,esdhc", }, 112996f0407bSPeng Fan { /* sentinel */ } 113096f0407bSPeng Fan }; 113196f0407bSPeng Fan 113296f0407bSPeng Fan U_BOOT_DRIVER(fsl_esdhc) = { 113396f0407bSPeng Fan .name = "fsl-esdhc-mmc", 113496f0407bSPeng Fan .id = UCLASS_MMC, 113596f0407bSPeng Fan .of_match = fsl_esdhc_ids, 113696f0407bSPeng Fan .probe = fsl_esdhc_probe, 1137e88e1d9cSSimon Glass .platdata_auto_alloc_size = sizeof(struct fsl_esdhc_plat), 113896f0407bSPeng Fan .priv_auto_alloc_size = sizeof(struct fsl_esdhc_priv), 113996f0407bSPeng Fan }; 114096f0407bSPeng Fan #endif 1141