diff --git a/arch/arm/mach-imx/devices.c b/arch/arm/mach-imx/devices.c index 11444ef..a0609e2 100644 --- a/arch/arm/mach-imx/devices.c +++ b/arch/arm/mach-imx/devices.c @@ -68,9 +68,14 @@ return imx_add_device("imx-mmc", id, base, 0x1000, pdata); } -struct device_d *imx_add_esdhc(void *base, int id, struct esdhc_platform_data *pdata) +struct device_d *imx_add_esdhc_imx25(void *base, int id, struct esdhc_platform_data *pdata) { - return imx_add_device("imx-esdhc", id, base, 0x1000, pdata); + return imx_add_device("imx25-esdhc", id, base, 0x1000, pdata); +} + +struct device_d *imx_add_esdhc_imx5(void *base, int id, struct esdhc_platform_data *pdata) +{ + return imx_add_device("imx5-esdhc", id, base, 0x1000, pdata); } struct device_d *imx_add_kpp(void *base, struct matrix_keymap_data *pdata) diff --git a/arch/arm/mach-imx/include/mach/devices-imx25.h b/arch/arm/mach-imx/include/mach/devices-imx25.h index eea8a60..7779a02 100644 --- a/arch/arm/mach-imx/include/mach/devices-imx25.h +++ b/arch/arm/mach-imx/include/mach/devices-imx25.h @@ -74,10 +74,10 @@ static inline struct device_d *imx25_add_mmc0(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX25_ESDHC1_BASE_ADDR, 0, pdata); + return imx_add_esdhc_imx25((void *)MX25_ESDHC1_BASE_ADDR, 0, pdata); } static inline struct device_d *imx25_add_mmc1(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX25_ESDHC2_BASE_ADDR, 1, pdata); + return imx_add_esdhc_imx25((void *)MX25_ESDHC2_BASE_ADDR, 1, pdata); } diff --git a/arch/arm/mach-imx/include/mach/devices-imx35.h b/arch/arm/mach-imx/include/mach/devices-imx35.h index 3e53167..922bb58 100644 --- a/arch/arm/mach-imx/include/mach/devices-imx35.h +++ b/arch/arm/mach-imx/include/mach/devices-imx35.h @@ -59,15 +59,15 @@ static inline struct device_d *imx35_add_mmc0(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX35_ESDHC1_BASE_ADDR, 0, pdata); + return imx_add_esdhc_imx25((void *)MX35_ESDHC1_BASE_ADDR, 0, pdata); } static inline struct device_d *imx35_add_mmc1(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX35_ESDHC2_BASE_ADDR, 1, pdata); + return imx_add_esdhc_imx25((void *)MX35_ESDHC2_BASE_ADDR, 1, pdata); } static inline struct device_d *imx35_add_mmc2(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX35_ESDHC3_BASE_ADDR, 2, pdata); + return imx_add_esdhc_imx25((void *)MX35_ESDHC3_BASE_ADDR, 2, pdata); } diff --git a/arch/arm/mach-imx/include/mach/devices-imx50.h b/arch/arm/mach-imx/include/mach/devices-imx50.h index 9e0eaa8..7e5141a 100644 --- a/arch/arm/mach-imx/include/mach/devices-imx50.h +++ b/arch/arm/mach-imx/include/mach/devices-imx50.h @@ -59,22 +59,22 @@ static inline struct device_d *imx50_add_mmc0(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX50_ESDHC1_BASE_ADDR, 0, pdata); + return imx5_add_esdhc((void *)MX50_ESDHC1_BASE_ADDR, 0, pdata); } static inline struct device_d *imx50_add_mmc1(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX50_ESDHC2_BASE_ADDR, 1, pdata); + return imx5_add_esdhc((void *)MX50_ESDHC2_BASE_ADDR, 1, pdata); } static inline struct device_d *imx50_add_mmc2(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX50_ESDHC3_BASE_ADDR, 2, pdata); + return imx5_add_esdhc((void *)MX50_ESDHC3_BASE_ADDR, 2, pdata); } static inline struct device_d *imx50_add_mmc3(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX50_ESDHC4_BASE_ADDR, 3, pdata); + return imx5_add_esdhc((void *)MX50_ESDHC4_BASE_ADDR, 3, pdata); } static inline struct device_d *imx50_add_kpp(struct matrix_keymap_data *pdata) diff --git a/arch/arm/mach-imx/include/mach/devices-imx51.h b/arch/arm/mach-imx/include/mach/devices-imx51.h index 66fe643..5a968a3 100644 --- a/arch/arm/mach-imx/include/mach/devices-imx51.h +++ b/arch/arm/mach-imx/include/mach/devices-imx51.h @@ -50,17 +50,17 @@ static inline struct device_d *imx51_add_mmc0(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX51_MMC_SDHC1_BASE_ADDR, 0, pdata); + return imx_add_esdhc_imx5((void *)MX51_MMC_SDHC1_BASE_ADDR, 0, pdata); } static inline struct device_d *imx51_add_mmc1(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX51_MMC_SDHC2_BASE_ADDR, 1, pdata); + return imx_add_esdhc_imx5((void *)MX51_MMC_SDHC2_BASE_ADDR, 1, pdata); } static inline struct device_d *imx51_add_mmc2(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX51_MMC_SDHC3_BASE_ADDR, 2, pdata); + return imx_add_esdhc_imx5((void *)MX51_MMC_SDHC3_BASE_ADDR, 2, pdata); } static inline struct device_d *imx51_add_nand(struct imx_nand_platform_data *pdata) diff --git a/arch/arm/mach-imx/include/mach/devices-imx53.h b/arch/arm/mach-imx/include/mach/devices-imx53.h index 27200a2..e5c257a 100644 --- a/arch/arm/mach-imx/include/mach/devices-imx53.h +++ b/arch/arm/mach-imx/include/mach/devices-imx53.h @@ -59,22 +59,22 @@ static inline struct device_d *imx53_add_mmc0(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX53_ESDHC1_BASE_ADDR, 0, pdata); + return imx_add_esdhc_imx5((void *)MX53_ESDHC1_BASE_ADDR, 0, pdata); } static inline struct device_d *imx53_add_mmc1(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX53_ESDHC2_BASE_ADDR, 1, pdata); + return imx_add_esdhc_imx5((void *)MX53_ESDHC2_BASE_ADDR, 1, pdata); } static inline struct device_d *imx53_add_mmc2(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX53_ESDHC3_BASE_ADDR, 2, pdata); + return imx_add_esdhc_imx5((void *)MX53_ESDHC3_BASE_ADDR, 2, pdata); } static inline struct device_d *imx53_add_mmc3(struct esdhc_platform_data *pdata) { - return imx_add_esdhc((void *)MX53_ESDHC4_BASE_ADDR, 3, pdata); + return imx_add_esdhc_imx5((void *)MX53_ESDHC4_BASE_ADDR, 3, pdata); } static inline struct device_d *imx53_add_nand(struct imx_nand_platform_data *pdata) diff --git a/arch/arm/mach-imx/include/mach/devices-imx6.h b/arch/arm/mach-imx/include/mach/devices-imx6.h index 3a1bfb6..9471f57 100644 --- a/arch/arm/mach-imx/include/mach/devices-imx6.h +++ b/arch/arm/mach-imx/include/mach/devices-imx6.h @@ -21,26 +21,6 @@ return imx_add_uart_imx21((void *)MX6_UART4_BASE_ADDR, 3); } -static inline struct device_d *imx6_add_mmc0(struct esdhc_platform_data *pdata) -{ - return imx_add_esdhc((void *)MX6_USDHC1_BASE_ADDR, 0, pdata); -} - -static inline struct device_d *imx6_add_mmc1(struct esdhc_platform_data *pdata) -{ - return imx_add_esdhc((void *)MX6_USDHC2_BASE_ADDR, 1, pdata); -} - -static inline struct device_d *imx6_add_mmc2(struct esdhc_platform_data *pdata) -{ - return imx_add_esdhc((void *)MX6_USDHC3_BASE_ADDR, 2, pdata); -} - -static inline struct device_d *imx6_add_mmc3(struct esdhc_platform_data *pdata) -{ - return imx_add_esdhc((void *)MX6_USDHC4_BASE_ADDR, 3, pdata); -} - static inline struct device_d *imx6_add_fec(struct fec_platform_data *pdata) { return imx_add_fec_imx6((void *)MX6_ENET_BASE_ADDR, pdata); diff --git a/arch/arm/mach-imx/include/mach/devices.h b/arch/arm/mach-imx/include/mach/devices.h index 6a045dd..4754b92 100644 --- a/arch/arm/mach-imx/include/mach/devices.h +++ b/arch/arm/mach-imx/include/mach/devices.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include struct device_d *imx_add_fec_imx27(void *base, struct fec_platform_data *pdata); @@ -21,7 +21,8 @@ struct device_d *imx_add_fb(void *base, struct imx_fb_platform_data *pdata); struct device_d *imx_add_ipufb(void *base, struct imx_ipu_fb_platform_data *pdata); struct device_d *imx_add_mmc(void *base, int id, void *pdata); -struct device_d *imx_add_esdhc(void *base, int id, struct esdhc_platform_data *pdata); +struct device_d *imx_add_esdhc_imx25(void *base, int id, struct esdhc_platform_data *pdata); +struct device_d *imx_add_esdhc_imx5(void *base, int id, struct esdhc_platform_data *pdata); struct device_d *imx_add_kpp(void *base, struct matrix_keymap_data *pdata); struct device_d *imx_add_pata(void *base); struct device_d *imx_add_usb(void *base, int id, struct imxusb_platformdata *pdata); diff --git a/arch/arm/mach-imx/include/mach/esdhc.h b/arch/arm/mach-imx/include/mach/esdhc.h deleted file mode 100644 index fb7380a..0000000 --- a/arch/arm/mach-imx/include/mach/esdhc.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010 Wolfram Sang - * - * 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; version 2 - * of the License. - */ - -#ifndef __ASM_ARCH_IMX_ESDHC_H -#define __ASM_ARCH_IMX_ESDHC_H - -enum wp_types { - ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ - ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ - ESDHC_WP_GPIO, /* external gpio pin for WP */ -}; - -enum cd_types { - ESDHC_CD_NONE, /* no CD, neither controller nor gpio */ - ESDHC_CD_CONTROLLER, /* mmc controller internal CD */ - ESDHC_CD_GPIO, /* external gpio pin for CD */ - ESDHC_CD_PERMANENT, /* no CD, card permanently wired to host */ -}; - -/** - * struct esdhc_platform_data - platform data for esdhc on i.MX - * - * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35. - * - * @wp_gpio: gpio for write_protect - * @cd_gpio: gpio for card_detect interrupt - * @wp_type: type of write_protect method (see wp_types enum above) - * @cd_type: type of card_detect method (see cd_types enum above) - * @caps: supported bus width capabilities (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA) - */ - -struct esdhc_platform_data { - unsigned int wp_gpio; - unsigned int cd_gpio; - enum wp_types wp_type; - enum cd_types cd_type; - unsigned caps; - char *devname; - unsigned dsr_val; - int use_dsr; -}; -#endif /* __ASM_ARCH_IMX_ESDHC_H */ diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig index 954f957..2075151 100644 --- a/drivers/mci/Kconfig +++ b/drivers/mci/Kconfig @@ -82,7 +82,7 @@ config MCI_IMX_ESDHC bool "i.MX esdhc" - depends on ARCH_IMX + depends on ARCH_IMX || ARCH_LAYERSCAPE help Enable this entry to add support to read and write SD cards on a Freescale i.MX25/35/51 based system. diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 09df794..a9c5440 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -32,8 +32,7 @@ #include #include #include -#include -#include +#include #include #include @@ -68,6 +67,11 @@ #define ESDHC_FLAG_STD_TUNING BIT(5) /* The IP has SDHCI_CAPABILITIES_1 register */ #define ESDHC_FLAG_HAVE_CAP1 BIT(6) +/* Need to access registers in bigendian mode */ +#define ESDHC_FLAG_BIGENDIAN BIT(7) +/* Enable cache snooping */ +#define ESDHC_FLAG_CACHE_SNOOPING BIT(8) + /* * The IP has errata ERR004536 * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, @@ -85,8 +89,12 @@ #define IMX_SDHCI_DLL_CTRL 0x60 #define IMX_SDHCI_MIX_CTRL_FBCLK_SEL (BIT(25)) +#define ESDHC_DMA_SYSCTL 0x40c /* Layerscape specific */ +#define ESDHC_SYSCTL_DMA_SNOOP BIT(6) + struct esdhc_soc_data { u32 flags; + const char *clkidx; }; struct fsl_esdhc_host { @@ -106,6 +114,45 @@ 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, @@ -152,7 +199,6 @@ esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; u32 blocks; char *buffer; u32 databuf; @@ -166,8 +212,8 @@ while (blocks) { timeout = PIO_TIMEOUT; size = data->blocksize; - irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); - while (!(esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_BREN) + 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"); @@ -175,8 +221,8 @@ } while (size && (!(irqstat & IRQSTAT_TC))) { udelay(100); /* Wait before last byte transfer complete */ - irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); - databuf = esdhc_read32(regs + SDHCI_BUFFER); + irqstat = esdhc_read32(host, SDHCI_INT_STATUS); + databuf = esdhc_read32(host, SDHCI_BUFFER); *((u32 *)buffer) = databuf; buffer += 4; size -= 4; @@ -189,8 +235,8 @@ while (blocks) { timeout = PIO_TIMEOUT; size = data->blocksize; - irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); - while (!(esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_BWEN) + 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"); @@ -201,8 +247,8 @@ databuf = *((u32 *)buffer); buffer += 4; size -= 4; - irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); - esdhc_write32(regs+ SDHCI_BUFFER, databuf); + irqstat = esdhc_read32(host, SDHCI_INT_STATUS); + esdhc_write32(host, SDHCI_BUFFER, databuf); } blocks--; } @@ -215,7 +261,6 @@ dma_addr_t dma) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; u32 wml_value; if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) { @@ -225,18 +270,18 @@ if (wml_value > 0x10) wml_value = 0x10; - esdhc_clrsetbits32(regs + IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value); + esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value); } else { if (wml_value > 0x80) wml_value = 0x80; - esdhc_clrsetbits32(regs + IMX_SDHCI_WML, WML_WR_WML_MASK, + esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK, wml_value << 16); } - esdhc_write32(regs + SDHCI_DMA_ADDRESS, dma); + esdhc_write32(host, SDHCI_DMA_ADDRESS, dma); } - esdhc_write32(regs + SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize); + esdhc_write32(host, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize); return 0; } @@ -244,14 +289,13 @@ static int esdhc_do_data(struct mci_host *mci, struct mci_data *data) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; u32 irqstat; if (IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) return esdhc_pio_read_write(mci, data); do { - irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); + irqstat = esdhc_read32(host, SDHCI_INT_STATUS); if (irqstat & DATA_ERR) return -EIO; @@ -259,7 +303,7 @@ if (irqstat & IRQSTAT_DTOE) return -ETIMEDOUT; } while (!(irqstat & IRQSTAT_TC) && - (esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); + (esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); return 0; } @@ -274,14 +318,13 @@ u32 xfertyp, mixctrl; u32 irqstat; struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; unsigned int num_bytes = 0; int ret; void *ptr; enum dma_data_direction dir = 0; dma_addr_t dma = 0; - esdhc_write32(regs + SDHCI_INT_STATUS, -1); + esdhc_write32(host, SDHCI_INT_STATUS, -1); /* Wait at least 8 SD clock cycles before the next command */ udelay(1); @@ -315,28 +358,28 @@ xfertyp = esdhc_xfertyp(host, cmd, data); /* Send the command */ - esdhc_write32(regs + SDHCI_ARGUMENT, cmd->cmdarg); + 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(regs + IMX_SDHCI_MIXCTRL) & (0xF << 22)); - esdhc_write32(regs + IMX_SDHCI_MIXCTRL, mixctrl); + mixctrl |= (esdhc_read32(host, IMX_SDHCI_MIXCTRL) & (0xF << 22)); + esdhc_write32(host, IMX_SDHCI_MIXCTRL, mixctrl); } - esdhc_write32(regs + SDHCI_TRANSFER_MODE__COMMAND, xfertyp); + esdhc_write32(host, SDHCI_TRANSFER_MODE__COMMAND, xfertyp); /* Wait for the command to complete */ ret = wait_on_timeout(100 * MSECOND, - esdhc_read32(regs + SDHCI_INT_STATUS) & IRQSTAT_CC); + esdhc_read32(host, SDHCI_INT_STATUS) & IRQSTAT_CC); if (ret) { dev_dbg(host->dev, "timeout 1\n"); return -ETIMEDOUT; } - irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); - esdhc_write32(regs + SDHCI_INT_STATUS, irqstat); + irqstat = esdhc_read32(host, SDHCI_INT_STATUS); + esdhc_write32(host, SDHCI_INT_STATUS, irqstat); if (irqstat & CMD_ERR) return -EIO; @@ -351,7 +394,7 @@ * timout / 10 usec since DLA polling can be insecure. */ ret = wait_on_timeout(2500 * MSECOND, - (esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_DAT0)); + (esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DAT0)); if (ret) { dev_err(host->dev, "timeout PRSSTAT_DAT0\n"); @@ -363,16 +406,16 @@ if (cmd->resp_type & MMC_RSP_136) { u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; - cmdrsp3 = esdhc_read32(regs + SDHCI_RESPONSE_3); - cmdrsp2 = esdhc_read32(regs + SDHCI_RESPONSE_2); - cmdrsp1 = esdhc_read32(regs + SDHCI_RESPONSE_1); - cmdrsp0 = esdhc_read32(regs + SDHCI_RESPONSE_0); + 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(regs + SDHCI_RESPONSE_0); + cmd->response[0] = esdhc_read32(host, SDHCI_RESPONSE_0); /* Wait until all of the blocks are transferred */ if (data) { @@ -384,11 +427,11 @@ dma_unmap_single(host->dev, dma, num_bytes, dir); } - esdhc_write32(regs + SDHCI_INT_STATUS, -1); + esdhc_write32(host, SDHCI_INT_STATUS, -1); /* Wait for the bus to be idle */ ret = wait_on_timeout(SECOND, - !(esdhc_read32(regs + SDHCI_PRESENT_STATE) & + !(esdhc_read32(host, SDHCI_PRESENT_STATE) & (PRSSTAT_CICHB | PRSSTAT_CIDHB))); if (ret) { dev_err(host->dev, "timeout 2\n"); @@ -396,7 +439,7 @@ } ret = wait_on_timeout(100 * MSECOND, - !(esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); + !(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); if (ret) { dev_err(host->dev, "timeout 3\n"); return -ETIMEDOUT; @@ -409,7 +452,6 @@ { int div, pre_div; struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; int sdhc_clk = clk_get_rate(host->clk); u32 clk; unsigned long cur_clock; @@ -446,43 +488,42 @@ clk = (pre_div << 8) | (div << 4); - esdhc_clrbits32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + esdhc_clrbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, SYSCTL_CKEN); - esdhc_clrsetbits32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + esdhc_clrsetbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, SYSCTL_CLOCK_MASK, clk); wait_on_timeout(10 * MSECOND, - esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_SDSTB); + esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_SDSTB); clk = SYSCTL_PEREN | SYSCTL_CKEN | SYSCTL_INITA; - esdhc_setbits32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + esdhc_setbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, clk); wait_on_timeout(1 * MSECOND, - !(esdhc_read32(regs + SDHCI_CLOCK_CONTROL) & SYSCTL_INITA)); + !(esdhc_read32(host, SDHCI_CLOCK_CONTROL) & SYSCTL_INITA)); } static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; /* Set the clock speed */ set_sysctl(mci, ios->clock); /* Set the bus width */ - esdhc_clrbits32(regs + SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, + esdhc_clrbits32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, PROCTL_DTW_4 | PROCTL_DTW_8); switch (ios->bus_width) { case MMC_BUS_WIDTH_4: - esdhc_setbits32(regs + SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, + esdhc_setbits32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, PROCTL_DTW_4); break; case MMC_BUS_WIDTH_8: - esdhc_setbits32(regs + SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, + esdhc_setbits32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, PROCTL_DTW_8); break; case MMC_BUS_WIDTH_1: @@ -496,7 +537,6 @@ static int esdhc_card_present(struct mci_host *mci) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; struct esdhc_platform_data *pdata = host->dev->platform_data; int ret; @@ -508,7 +548,7 @@ case ESDHC_CD_PERMANENT: return 1; case ESDHC_CD_CONTROLLER: - return !(esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL); + return !(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL); case ESDHC_CD_GPIO: ret = gpio_direction_input(pdata->cd_gpio); if (ret) @@ -519,71 +559,30 @@ return 0; } -static int esdhc_init(struct mci_host *mci, struct device_d *dev) -{ - struct fsl_esdhc_host *host = to_fsl_esdhc(mci); - void __iomem *regs = host->regs; - int timeout = 1000; - int ret = 0; - - /* Reset the entire host controller */ - esdhc_write32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, - SYSCTL_RSTA); - - /* Wait until the controller is available */ - while ((esdhc_read32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET) - & SYSCTL_RSTA) && --timeout) - udelay(1000); - - esdhc_write32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, - SYSCTL_HCKEN | SYSCTL_IPGEN); - - /* RSTA doesn't reset MMC_BOOT register, so manually reset it */ - esdhc_write32(regs + SDHCI_MMC_BOOT, 0); - - /* Set the initial clock speed */ - set_sysctl(mci, 400000); - - writel(IRQSTATEN_CC | IRQSTATEN_TC | IRQSTATEN_CINT | IRQSTATEN_CTOE | - IRQSTATEN_CCE | IRQSTATEN_CEBE | IRQSTATEN_CIE | IRQSTATEN_DTOE | - IRQSTATEN_DCE | IRQSTATEN_DEBE | IRQSTATEN_DINT, regs + SDHCI_INT_ENABLE); - - /* Put the PROCTL reg back to the default */ - esdhc_write32(regs + SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, - PROCTL_INIT); - - /* Set timout to the maximum value */ - esdhc_clrsetbits32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, - SYSCTL_TIMEOUT_MASK, 14 << 16); - - return ret; -} - static int esdhc_reset(struct fsl_esdhc_host *host) { - void __iomem *regs = host->regs; uint64_t start; int val; /* reset the controller */ - esdhc_write32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + esdhc_write32(host, 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(regs + IMX_SDHCI_MIXCTRL); + val = esdhc_read32(host, IMX_SDHCI_MIXCTRL); val &= ~IMX_SDHCI_MIX_CTRL_FBCLK_SEL; - esdhc_write32(regs + IMX_SDHCI_MIXCTRL, val); + esdhc_write32(host, IMX_SDHCI_MIXCTRL, val); /* reset delay line settings in IMX_SDHCI_DLL_CTRL */ - esdhc_write32(regs + IMX_SDHCI_DLL_CTRL, 0x0); + esdhc_write32(host, IMX_SDHCI_DLL_CTRL, 0x0); } start = get_time_ns(); /* hardware clears the bit when it is done */ while (1) { - if (!(esdhc_read32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET) + if (!(esdhc_read32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET) & SYSCTL_RSTA)) break; if (is_timeout(start, 100 * MSECOND)) { @@ -595,6 +594,44 @@ return 0; } +static int esdhc_init(struct mci_host *mci, struct device_d *dev) +{ + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + int ret; + + ret = esdhc_reset(host); + if (ret) + return ret; + + esdhc_write32(host, 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); + + /* Enable cache snooping */ + if (host->socdata->flags & ESDHC_FLAG_CACHE_SNOOPING) + esdhc_setbits32(host, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP); + + /* Set the initial clock speed */ + set_sysctl(mci, 400000); + + 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); + + /* Put the PROCTL reg back to the default */ + esdhc_write32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, + PROCTL_INIT); + + /* Set timout to the maximum value */ + esdhc_clrsetbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + SYSCTL_TIMEOUT_MASK, 14 << 16); + + return ret; +} + static int fsl_esdhc_detect(struct device_d *dev) { struct fsl_esdhc_host *host = dev->priv; @@ -602,9 +639,6 @@ return mci_detect_card(&host->mci); } -static struct esdhc_soc_data esdhc_imx25_data; -static struct esdhc_soc_data esdhc_imx53_data; - static int fsl_esdhc_probe(struct device_d *dev) { struct resource *iores; @@ -614,24 +648,19 @@ int ret; unsigned long rate; struct esdhc_platform_data *pdata = dev->platform_data; + const struct esdhc_soc_data *socdata; + + ret = dev_get_drvdata(dev, (const void **)&socdata); + if (ret) + return ret; host = xzalloc(sizeof(*host)); + host->socdata = socdata; mci = &host->mci; - if (IS_ENABLED(CONFIG_OFDEVICE)) { - host->socdata = of_device_get_match_data(dev); - if (!host->socdata) - return -EINVAL; - } else { - if (cpu_is_mx50() || cpu_is_mx51() || cpu_is_mx53()) - host->socdata = &esdhc_imx53_data; - else - host->socdata = &esdhc_imx25_data; - } - dma_set_mask(dev, DMA_BIT_MASK(32)); - host->clk = clk_get(dev, "per"); + host->clk = clk_get(dev, socdata->clkidx); if (IS_ERR(host->clk)) return PTR_ERR(host->clk); @@ -648,14 +677,7 @@ return PTR_ERR(iores); host->regs = IOMEM(iores->start); - /* First reset the eSDHC controller */ - ret = esdhc_reset(host); - if (ret) { - free(host); - return ret; - } - - caps = esdhc_read32(host->regs + SDHCI_CAPABILITIES); + caps = esdhc_read32(host, SDHCI_CAPABILITIES); if (caps & ESDHC_HOSTCAPBLT_VS18) mci->voltages |= MMC_VDD_165_195; @@ -700,25 +722,34 @@ static struct esdhc_soc_data esdhc_imx25_data = { .flags = ESDHC_FLAG_ENGCM07207, + .clkidx = "per", }; static struct esdhc_soc_data esdhc_imx53_data = { .flags = ESDHC_FLAG_MULTIBLK_NO_INT, + .clkidx = "per", }; static struct esdhc_soc_data usdhc_imx6q_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, + .clkidx = "per", }; static struct esdhc_soc_data usdhc_imx6sl_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 | ESDHC_FLAG_HS200, + .clkidx = "per", }; static struct esdhc_soc_data usdhc_imx6sx_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, + .clkidx = "per", +}; + +static struct esdhc_soc_data esdhc_ls_data = { + .flags = ESDHC_FLAG_MULTIBLK_NO_INT | ESDHC_FLAG_BIGENDIAN, }; static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = { @@ -730,12 +761,26 @@ { .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 }, { /* sentinel */ } }; +static struct platform_device_id imx_esdhc_ids[] = { + { + .name = "imx25-esdhc", + .driver_data = (unsigned long)&esdhc_imx25_data, + }, { + .name = "imx5-esdhc", + .driver_data = (unsigned long)&esdhc_imx53_data, + }, { + /* sentinel */ + } +}; + static struct driver_d fsl_esdhc_driver = { .name = "imx-esdhc", .probe = fsl_esdhc_probe, .of_compatible = DRV_OF_COMPAT(fsl_esdhc_compatible), + .id_table = imx_esdhc_ids, }; device_platform_driver(fsl_esdhc_driver); diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h index 44aff9d..9003843 100644 --- a/drivers/mci/imx-esdhc.h +++ b/drivers/mci/imx-esdhc.h @@ -63,10 +63,4 @@ u32 no_snoop; }; -#define esdhc_read32(a) readl(a) -#define esdhc_write32(a, v) writel(v,a) -#define esdhc_clrsetbits32(a, c, s) writel((readl(a) & ~(c)) | (s), (a)) -#define esdhc_clrbits32(a, c) writel(readl(a) & ~(c), (a)) -#define esdhc_setbits32(a, s) writel(readl(a) | (s), (a)) - #endif /* __FSL_ESDHC_H__ */ diff --git a/include/platform_data/mmc-esdhc-imx.h b/include/platform_data/mmc-esdhc-imx.h new file mode 100644 index 0000000..fb7380a --- /dev/null +++ b/include/platform_data/mmc-esdhc-imx.h @@ -0,0 +1,48 @@ +/* + * Copyright 2010 Wolfram Sang + * + * 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; version 2 + * of the License. + */ + +#ifndef __ASM_ARCH_IMX_ESDHC_H +#define __ASM_ARCH_IMX_ESDHC_H + +enum wp_types { + ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ + ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ + ESDHC_WP_GPIO, /* external gpio pin for WP */ +}; + +enum cd_types { + ESDHC_CD_NONE, /* no CD, neither controller nor gpio */ + ESDHC_CD_CONTROLLER, /* mmc controller internal CD */ + ESDHC_CD_GPIO, /* external gpio pin for CD */ + ESDHC_CD_PERMANENT, /* no CD, card permanently wired to host */ +}; + +/** + * struct esdhc_platform_data - platform data for esdhc on i.MX + * + * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35. + * + * @wp_gpio: gpio for write_protect + * @cd_gpio: gpio for card_detect interrupt + * @wp_type: type of write_protect method (see wp_types enum above) + * @cd_type: type of card_detect method (see cd_types enum above) + * @caps: supported bus width capabilities (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA) + */ + +struct esdhc_platform_data { + unsigned int wp_gpio; + unsigned int cd_gpio; + enum wp_types wp_type; + enum cd_types cd_type; + unsigned caps; + char *devname; + unsigned dsr_val; + int use_dsr; +}; +#endif /* __ASM_ARCH_IMX_ESDHC_H */