diff options
Diffstat (limited to 'drivers/mci/imx-esdhc.c')
-rw-r--r-- | drivers/mci/imx-esdhc.c | 613 |
1 files changed, 136 insertions, 477 deletions
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index db3450a26d..fb52c7b893 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -1,25 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2007,2010 Freescale Semiconductor, Inc +// SPDX-FileCopyrightText: 2003 Kyle Harris <kharris@nexus-tech.net>, Nexus Technologies + /* - * Copyright 2007,2010 Freescale Semiconductor, Inc * Andy Fleming - * - * Based vaguely on the pxa mmc code: - * (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. - * */ + #include <config.h> #include <common.h> #include <dma.h> @@ -35,271 +21,18 @@ #include <platform_data/mmc-esdhc-imx.h> #include <gpio.h> #include <of_device.h> +#include <mach/imx/generic.h> +#include <mach/imx/imx53-regs.h> #include "sdhci.h" #include "imx-esdhc.h" -/* - * The CMDTYPE of the CMD register (offset 0xE) should be set to - * "11" when the STOP CMD12 is issued on imx53 to abort one - * open ended multi-blk IO. Otherwise the TC INT wouldn't - * be generated. - * In exact block transfer, the controller doesn't complete the - * operations automatically as required at the end of the - * transfer and remains on hold if the abort command is not sent. - * As a result, the TC flag is not asserted and SW received timeout - * exeception. Bit1 of Vendor Spec registor is used to fix it. - */ -#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) -/* - * The flag enables the workaround for ESDHC errata ENGcm07207 which - * affects i.MX25 and i.MX35. - */ -#define ESDHC_FLAG_ENGCM07207 BIT(2) -/* - * The flag tells that the ESDHC controller is an USDHC block that is - * integrated on the i.MX6 series. - */ -#define ESDHC_FLAG_USDHC BIT(3) -/* The IP supports manual tuning process */ -#define ESDHC_FLAG_MAN_TUNING BIT(4) -/* The IP supports standard tuning process */ -#define ESDHC_FLAG_STD_TUNING BIT(5) -/* The IP has SDHCI_CAPABILITIES_1 register */ -#define ESDHC_FLAG_HAVE_CAP1 BIT(6) -/* - * The IP has errata ERR004536 - * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, - * when reading data from the card - */ -#define ESDHC_FLAG_ERR004536 BIT(7) -/* The IP supports HS200 mode */ -#define ESDHC_FLAG_HS200 BIT(8) -/* The IP supports HS400 mode */ -#define ESDHC_FLAG_HS400 BIT(9) - -/* Need to access registers in bigendian mode */ -#define ESDHC_FLAG_BIGENDIAN BIT(10) -/* Enable cache snooping */ -#define ESDHC_FLAG_CACHE_SNOOPING BIT(11) - -struct esdhc_soc_data { - u32 flags; - const char *clkidx; -}; +#define PRSSTAT_SDSTB 0x00000008 -struct fsl_esdhc_host { - struct mci_host mci; - void __iomem *regs; - struct device_d *dev; - struct clk *clk; - const struct esdhc_soc_data *socdata; -}; #define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci) -#define SDHCI_CMD_ABORTCMD (0xC0 << 16) - -static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data) -{ - return !!(data->socdata->flags & ESDHC_FLAG_USDHC); -} - -static inline u32 esdhc_read32(struct fsl_esdhc_host *host, unsigned int reg) -{ - if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) - return in_be32(host->regs + reg); - else - return readl(host->regs + reg); -} - -static inline void esdhc_write32(struct fsl_esdhc_host *host, unsigned int reg, - u32 val) -{ - if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) - out_be32(host->regs + reg, val); - else - writel(val, host->regs + reg); -} - -static inline void esdhc_clrsetbits32(struct fsl_esdhc_host *host, unsigned int reg, - u32 clear, u32 set) -{ - u32 val; - - val = esdhc_read32(host, reg); - val &= ~clear; - val |= set; - esdhc_write32(host, reg, val); -} - -static inline void esdhc_clrbits32(struct fsl_esdhc_host *host, unsigned int reg, - u32 clear) -{ - esdhc_clrsetbits32(host, reg, clear, 0); -} - -static inline void esdhc_setbits32(struct fsl_esdhc_host *host, unsigned int reg, - u32 set) -{ - esdhc_clrsetbits32(host, reg, 0, set); -} - -/* Return the XFERTYP flags for a given command and data packet */ -static u32 esdhc_xfertyp(struct fsl_esdhc_host *host, - struct mci_cmd *cmd, struct mci_data *data) -{ - u32 xfertyp = 0; - - if (data) { - xfertyp |= COMMAND_DPSEL; - - if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) - xfertyp |= TRANSFER_MODE_DMAEN; - - if (data->blocks > 1) { - xfertyp |= TRANSFER_MODE_MSBSEL; - xfertyp |= TRANSFER_MODE_BCEN; - } - - if (data->flags & MMC_DATA_READ) - xfertyp |= TRANSFER_MODE_DTDSEL; - } - - if (cmd->resp_type & MMC_RSP_CRC) - xfertyp |= COMMAND_CCCEN; - if (cmd->resp_type & MMC_RSP_OPCODE) - xfertyp |= COMMAND_CICEN; - if (cmd->resp_type & MMC_RSP_136) - xfertyp |= COMMAND_RSPTYP_136; - else if (cmd->resp_type & MMC_RSP_BUSY) - xfertyp |= COMMAND_RSPTYP_48_BUSY; - else if (cmd->resp_type & MMC_RSP_PRESENT) - xfertyp |= COMMAND_RSPTYP_48; - if ((host->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) && - (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)) - xfertyp |= SDHCI_CMD_ABORTCMD; - - return COMMAND_CMD(cmd->cmdidx) | xfertyp; -} - -/* - * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. - */ -static int -esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data) -{ - struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - u32 blocks; - char *buffer; - u32 databuf; - u32 size; - u32 irqstat; - u32 timeout; - - if (data->flags & MMC_DATA_READ) { - blocks = data->blocks; - buffer = data->dest; - while (blocks) { - timeout = PIO_TIMEOUT; - size = data->blocksize; - irqstat = esdhc_read32(host, SDHCI_INT_STATUS); - while (!(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_BREN) - && --timeout); - if (timeout <= 0) { - dev_err(host->dev, "Data Read Failed\n"); - return -ETIMEDOUT; - } - while (size && (!(irqstat & IRQSTAT_TC))) { - udelay(100); /* Wait before last byte transfer complete */ - irqstat = esdhc_read32(host, SDHCI_INT_STATUS); - databuf = esdhc_read32(host, SDHCI_BUFFER); - *((u32 *)buffer) = databuf; - buffer += 4; - size -= 4; - } - blocks--; - } - } else { - blocks = data->blocks; - buffer = (char *)data->src; - while (blocks) { - timeout = PIO_TIMEOUT; - size = data->blocksize; - irqstat = esdhc_read32(host, SDHCI_INT_STATUS); - while (!(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_BWEN) - && --timeout); - if (timeout <= 0) { - dev_err(host->dev, "Data Write Failed\n"); - return -ETIMEDOUT; - } - while (size && (!(irqstat & IRQSTAT_TC))) { - udelay(100); /* Wait before last byte transfer complete */ - databuf = *((u32 *)buffer); - buffer += 4; - size -= 4; - irqstat = esdhc_read32(host, SDHCI_INT_STATUS); - esdhc_write32(host, SDHCI_BUFFER, databuf); - } - blocks--; - } - } - - return 0; -} - -static int esdhc_setup_data(struct mci_host *mci, struct mci_data *data, - dma_addr_t dma) -{ - struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - u32 wml_value; - - if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) { - wml_value = data->blocksize/4; - - if (data->flags & MMC_DATA_READ) { - if (wml_value > 0x10) - wml_value = 0x10; - - esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value); - } else { - if (wml_value > 0x80) - wml_value = 0x80; - - esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK, - wml_value << 16); - } - esdhc_write32(host, SDHCI_DMA_ADDRESS, dma); - } - - esdhc_write32(host, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize); - - return 0; -} - -static int esdhc_do_data(struct mci_host *mci, struct mci_data *data) -{ - struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - u32 irqstat; - - if (IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) - return esdhc_pio_read_write(mci, data); - - do { - irqstat = esdhc_read32(host, SDHCI_INT_STATUS); - - if (irqstat & DATA_ERR) - return -EIO; - - if (irqstat & IRQSTAT_DTOE) - return -ETIMEDOUT; - } while (!(irqstat & IRQSTAT_TC) && - (esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); - - return 0; -} - /* * Sends a command out on the bus. Takes the mci pointer, * a command pointer, and an optional data pointer. @@ -307,166 +40,40 @@ static int esdhc_do_data(struct mci_host *mci, struct mci_data *data) static int esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) { - u32 xfertyp, mixctrl; - u32 irqstat; struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - unsigned int num_bytes = 0; - int ret; - void *ptr; - enum dma_data_direction dir = 0; - dma_addr_t dma = 0; - - esdhc_write32(host, SDHCI_INT_STATUS, -1); - - /* Wait at least 8 SD clock cycles before the next command */ - udelay(1); - - /* Set up for a data transfer if we have one */ - if (data) { - int err; - - if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) { - num_bytes = data->blocks * data->blocksize; - - if (data->flags & MMC_DATA_WRITE) { - ptr = (void *)data->src; - dir = DMA_TO_DEVICE; - } else { - ptr = data->dest; - dir = DMA_FROM_DEVICE; - } - - dma = dma_map_single(host->dev, ptr, num_bytes, dir); - if (dma_mapping_error(host->dev, dma)) - return -EFAULT; - } - - err = esdhc_setup_data(mci, data, dma); - if(err) - return err; - } - - /* Figure out the transfer arguments */ - xfertyp = esdhc_xfertyp(host, cmd, data); - - /* Send the command */ - esdhc_write32(host, SDHCI_ARGUMENT, cmd->cmdarg); - - if (esdhc_is_usdhc(host)) { - /* write lower-half of xfertyp to mixctrl */ - mixctrl = xfertyp & 0xFFFF; - /* Keep the bits 22-25 of the register as is */ - mixctrl |= (esdhc_read32(host, IMX_SDHCI_MIXCTRL) & (0xF << 22)); - esdhc_write32(host, IMX_SDHCI_MIXCTRL, mixctrl); - } - - esdhc_write32(host, SDHCI_TRANSFER_MODE__COMMAND, xfertyp); - - /* Wait for the command to complete */ - ret = wait_on_timeout(100 * MSECOND, - esdhc_read32(host, SDHCI_INT_STATUS) & IRQSTAT_CC); - if (ret) { - dev_dbg(host->dev, "timeout 1\n"); - return -ETIMEDOUT; - } - - irqstat = esdhc_read32(host, SDHCI_INT_STATUS); - esdhc_write32(host, SDHCI_INT_STATUS, irqstat); - - if (irqstat & CMD_ERR) - return -EIO; - - if (irqstat & IRQSTAT_CTOE) - return -ETIMEDOUT; - - /* Workaround for ESDHC errata ENGcm03648 / ENGcm12360 */ - if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { - /* - * Poll on DATA0 line for cmd with busy signal for - * timout / 10 usec since DLA polling can be insecure. - */ - ret = wait_on_timeout(2500 * MSECOND, - (esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DAT0)); - - if (ret) { - dev_err(host->dev, "timeout PRSSTAT_DAT0\n"); - return -ETIMEDOUT; - } - } - - /* Copy the response to the response buffer */ - if (cmd->resp_type & MMC_RSP_136) { - u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; - - cmdrsp3 = esdhc_read32(host, SDHCI_RESPONSE_3); - cmdrsp2 = esdhc_read32(host, SDHCI_RESPONSE_2); - cmdrsp1 = esdhc_read32(host, SDHCI_RESPONSE_1); - cmdrsp0 = esdhc_read32(host, SDHCI_RESPONSE_0); - 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] = esdhc_read32(host, SDHCI_RESPONSE_0); - - /* Wait until all of the blocks are transferred */ - if (data) { - ret = esdhc_do_data(mci, data); - if (ret) - return ret; - if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) - dma_unmap_single(host->dev, dma, num_bytes, dir); - } - - esdhc_write32(host, SDHCI_INT_STATUS, -1); - - /* Wait for the bus to be idle */ - ret = wait_on_timeout(SECOND, - !(esdhc_read32(host, SDHCI_PRESENT_STATE) & - (PRSSTAT_CICHB | PRSSTAT_CIDHB))); - if (ret) { - dev_err(host->dev, "timeout 2\n"); - return -ETIMEDOUT; - } - - ret = wait_on_timeout(100 * MSECOND, - !(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); - if (ret) { - dev_err(host->dev, "timeout 3\n"); - return -ETIMEDOUT; - } - - return 0; + return __esdhc_send_cmd(host, cmd, data); } -static void set_sysctl(struct mci_host *mci, u32 clock) +static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr) { - int div, pre_div; + int div, pre_div, ddr_pre_div = 1; struct fsl_esdhc_host *host = to_fsl_esdhc(mci); int sdhc_clk = clk_get_rate(host->clk); u32 clk; unsigned long cur_clock; - /* - * With eMMC and imx53 (sdhc_clk=200MHz) a pre_div of 1 results in - * pre_div=1,div=4 (=50MHz) - * which is valid and should work, but somehow doesn't. - * Starting with pre_div=2 gives - * pre_div=2, div=2 (=50MHz) - * and works fine. - */ - pre_div = 2; + if (esdhc_is_usdhc(host) && ddr) + ddr_pre_div = 2; + + if (esdhc_is_layerscape(host)) + sdhc_clk >>= 1; + + /* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */ + if (cpu_is_mx53() && host->sdhci.base == (void *)MX53_ESDHC3_BASE_ADDR) + pre_div = 2; + else + pre_div = 1; if (sdhc_clk == clock) pre_div = 1; else if (sdhc_clk / 16 > clock) for (; pre_div < 256; pre_div *= 2) - if ((sdhc_clk / pre_div) <= (clock * 16)) + if ((sdhc_clk / (pre_div * ddr_pre_div)) <= (clock * 16)) break; for (div = 1; div <= 16; div++) - if ((sdhc_clk / (div * pre_div)) <= clock) + if ((sdhc_clk / (div * pre_div * ddr_pre_div)) <= clock) break; cur_clock = sdhc_clk / pre_div / div; @@ -486,24 +93,84 @@ static void set_sysctl(struct mci_host *mci, u32 clock) esdhc_clrsetbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, SYSCTL_CLOCK_MASK, clk); - wait_on_timeout(10 * MSECOND, - esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_SDSTB); + esdhc_poll(host, SDHCI_PRESENT_STATE, + PRSSTAT_SDSTB, PRSSTAT_SDSTB, + 10 * MSECOND); clk = SYSCTL_PEREN | SYSCTL_CKEN | SYSCTL_INITA; esdhc_setbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, clk); - wait_on_timeout(1 * MSECOND, - !(esdhc_read32(host, SDHCI_CLOCK_CONTROL) & SYSCTL_INITA)); + esdhc_poll(host, SDHCI_CLOCK_CONTROL, + SYSCTL_INITA, SYSCTL_INITA, + 10 * MSECOND); +} + +static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing) +{ + u32 mixctrl; + + mixctrl = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL); + mixctrl &= ~MIX_CTRL_DDREN; + + switch (timing) { + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + mixctrl |= MIX_CTRL_DDREN; + sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl); + break; + default: + sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl); + } + + host->sdhci.timing = timing; +} + +static void layerscape_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing) +{ + esdhc_clrbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + SYSCTL_CKEN); + + switch (timing) { + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + esdhc_clrsetbits32(host, SDHCI_ACMD12_ERR__HOST_CONTROL2, + SDHCI_ACMD12_ERR__HOST_CONTROL2_UHSM, + FIELD_PREP(SDHCI_ACMD12_ERR__HOST_CONTROL2_UHSM, 4)); + break; + default: + esdhc_clrbits32(host, SDHCI_ACMD12_ERR__HOST_CONTROL2, + SDHCI_ACMD12_ERR__HOST_CONTROL2_UHSM); + break; + } + + esdhc_setbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + SYSCTL_CKEN); + + host->sdhci.timing = timing; } static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + /* + * call esdhc_set_timing() before update the clock rate, + * This is because current we support DDR and SDR timing, + * Once the DDR_EN bit is set, the card clock will be + * divide by 2 automatically. So need to do this before + * setting clock rate. + */ + if (host->sdhci.timing != ios->timing) { + if (esdhc_is_usdhc(host)) + usdhc_set_timing(host, ios->timing); + else if (esdhc_is_layerscape(host)) + layerscape_set_timing(host, ios->timing); + } + /* Set the clock speed */ - set_sysctl(mci, ios->clock); + set_sysctl(mci, ios->clock, mci_timing_is_ddr(ios->timing)); /* Set the bus width */ esdhc_clrbits32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, @@ -540,7 +207,7 @@ static int esdhc_card_present(struct mci_host *mci) case ESDHC_CD_PERMANENT: return 1; case ESDHC_CD_CONTROLLER: - return !(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL); + return !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_WRITE_PROTECT); case ESDHC_CD_GPIO: ret = gpio_direction_input(pdata->cd_gpio); if (ret) @@ -553,40 +220,35 @@ static int esdhc_card_present(struct mci_host *mci) static int esdhc_reset(struct fsl_esdhc_host *host) { - uint64_t start; int val; /* reset the controller */ - esdhc_write32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, SYSCTL_RSTA); /* extra register reset for i.MX6 Solo/DualLite */ if (esdhc_is_usdhc(host)) { /* reset bit FBCLK_SEL */ - val = esdhc_read32(host, IMX_SDHCI_MIXCTRL); + val = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL); val &= ~IMX_SDHCI_MIX_CTRL_FBCLK_SEL; - esdhc_write32(host, IMX_SDHCI_MIXCTRL, val); + sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, val); /* reset delay line settings in IMX_SDHCI_DLL_CTRL */ - esdhc_write32(host, IMX_SDHCI_DLL_CTRL, 0x0); + sdhci_write32(&host->sdhci, IMX_SDHCI_DLL_CTRL, 0x0); } - start = get_time_ns(); /* hardware clears the bit when it is done */ - while (1) { - if (!(esdhc_read32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET) - & SYSCTL_RSTA)) - break; - if (is_timeout(start, 100 * MSECOND)) { - dev_err(host->dev, "Reset never completed.\n"); - return -EIO; - } + if (esdhc_poll(host, + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + SYSCTL_RSTA, 0, 100 * MSECOND)) { + dev_err(host->dev, "Reset never completed.\n"); + return -EIO; } return 0; } -static int esdhc_init(struct mci_host *mci, struct device_d *dev) +static int esdhc_init(struct mci_host *mci, struct device *dev) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); int ret; @@ -595,26 +257,28 @@ static int esdhc_init(struct mci_host *mci, struct device_d *dev) if (ret) return ret; - esdhc_write32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, SYSCTL_HCKEN | SYSCTL_IPGEN); /* RSTA doesn't reset MMC_BOOT register, so manually reset it */ - esdhc_write32(host, SDHCI_MMC_BOOT, 0); + sdhci_write32(&host->sdhci, SDHCI_MMC_BOOT, 0); - /* Enable cache snooping */ - if (host->socdata->flags & ESDHC_FLAG_CACHE_SNOOPING) - esdhc_setbits32(host, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP); + if (esdhc_is_layerscape(host)) + esdhc_setbits32(host, ESDHC_DMA_SYSCTL, + ESDHC_SYSCTL_DMA_SNOOP | /* Enable cache snooping */ + ESDHC_SYSCTL_PERIPHERAL_CLK_SEL); /* Set the initial clock speed */ - set_sysctl(mci, 400000); + set_sysctl(mci, 400000, false); - esdhc_write32(host, SDHCI_INT_ENABLE, IRQSTATEN_CC | IRQSTATEN_TC | - IRQSTATEN_CINT | IRQSTATEN_CTOE | IRQSTATEN_CCE | - IRQSTATEN_CEBE | IRQSTATEN_CIE | IRQSTATEN_DTOE | - IRQSTATEN_DCE | IRQSTATEN_DEBE | IRQSTATEN_DINT); + sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, SDHCI_INT_CMD_COMPLETE | + SDHCI_INT_XFER_COMPLETE | SDHCI_INT_CARD_INT | + SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_END_BIT | + SDHCI_INT_INDEX | SDHCI_INT_DATA_TIMEOUT | + SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DMA); /* Put the PROCTL reg back to the default */ - esdhc_write32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, + sdhci_write32(&host->sdhci, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, PROCTL_INIT); /* Set timout to the maximum value */ @@ -624,19 +288,11 @@ static int esdhc_init(struct mci_host *mci, struct device_d *dev) return ret; } -static int fsl_esdhc_detect(struct device_d *dev) -{ - struct fsl_esdhc_host *host = dev->priv; - - return mci_detect_card(&host->mci); -} - -static int fsl_esdhc_probe(struct device_d *dev) +static int fsl_esdhc_probe(struct device *dev) { struct resource *iores; struct fsl_esdhc_host *host; struct mci_host *mci; - u32 caps; int ret; unsigned long rate; struct esdhc_platform_data *pdata = dev->platform_data; @@ -671,16 +327,9 @@ static int fsl_esdhc_probe(struct device_d *dev) ret = PTR_ERR(iores); goto err_clk_disable; } - host->regs = IOMEM(iores->start); - - caps = esdhc_read32(host, SDHCI_CAPABILITIES); + host->sdhci.base = IOMEM(iores->start); - if (caps & ESDHC_HOSTCAPBLT_VS18) - mci->voltages |= MMC_VDD_165_195; - if (caps & ESDHC_HOSTCAPBLT_VS30) - mci->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; - if (caps & ESDHC_HOSTCAPBLT_VS33) - mci->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; + esdhc_populate_sdhci(host); if (pdata) { mci->host_caps = pdata->caps; @@ -688,16 +337,19 @@ static int fsl_esdhc_probe(struct device_d *dev) mci->devname = pdata->devname; } - if (caps & ESDHC_HOSTCAPBLT_HSS) - mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; - host->mci.send_cmd = esdhc_send_cmd; host->mci.set_ios = esdhc_set_ios; host->mci.init = esdhc_init; host->mci.card_present = esdhc_card_present; host->mci.hw_dev = dev; + host->sdhci.mci = &host->mci; - dev->detect = fsl_esdhc_detect, + ret = sdhci_setup_host(&host->sdhci); + if (ret) + goto err_clk_disable; + + if (esdhc_is_usdhc(host) || esdhc_is_layerscape(host)) + mci->host_caps |= MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR; rate = clk_get_rate(host->clk); host->mci.f_min = rate >> 12; @@ -711,8 +363,6 @@ static int fsl_esdhc_probe(struct device_d *dev) mci_of_parse(&host->mci); - dev->priv = host; - ret = mci_register(&host->mci); if (ret) goto err_release_res; @@ -758,9 +408,13 @@ static struct esdhc_soc_data usdhc_imx6sx_data = { .clkidx = "per", }; -static struct esdhc_soc_data esdhc_ls_data = { +static struct esdhc_soc_data esdhc_ls_be_data = { .flags = ESDHC_FLAG_MULTIBLK_NO_INT | ESDHC_FLAG_BIGENDIAN | - ESDHC_FLAG_CACHE_SNOOPING, + ESDHC_FLAG_LAYERSCAPE, +}; + +static struct esdhc_soc_data esdhc_ls_le_data = { + .flags = ESDHC_FLAG_MULTIBLK_NO_INT | ESDHC_FLAG_LAYERSCAPE, }; static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = { @@ -772,9 +426,14 @@ static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = { { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data }, { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data }, { .compatible = "fsl,imx8mq-usdhc", .data = &usdhc_imx6sx_data }, - { .compatible = "fsl,ls1046a-esdhc",.data = &esdhc_ls_data }, + { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx6sx_data }, + { .compatible = "fsl,imx8mn-usdhc", .data = &usdhc_imx6sx_data }, + { .compatible = "fsl,imx8mp-usdhc", .data = &usdhc_imx6sx_data }, + { .compatible = "fsl,ls1028a-esdhc",.data = &esdhc_ls_le_data }, + { .compatible = "fsl,ls1046a-esdhc",.data = &esdhc_ls_be_data }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, fsl_esdhc_compatible); static struct platform_device_id imx_esdhc_ids[] = { { @@ -788,7 +447,7 @@ static struct platform_device_id imx_esdhc_ids[] = { } }; -static struct driver_d fsl_esdhc_driver = { +static struct driver fsl_esdhc_driver = { .name = "imx-esdhc", .probe = fsl_esdhc_probe, .of_compatible = DRV_OF_COMPAT(fsl_esdhc_compatible), |