summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorHaijun Zhang <Haijun.Zhang@freescale.com>2014-05-09 03:04:28 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:37:50 (GMT)
commit53a3bb65a928123d2a001840ecb774408cfc1ce0 (patch)
tree0cc65b0f2e7101b3b08e3d8b3d99922ccbdbad8c /drivers/mmc
parent3338d67019795bd214211932045e17baff22d5f3 (diff)
downloadlinux-fsl-qoriq-53a3bb65a928123d2a001840ecb774408cfc1ce0.tar.xz
mmc:esdhc: add esdhc support on ls1021a-qds
Ls1021a-qds has the same ip block as esdhc on powerpc platform. But they have diferent endian mode and different IO entry. So we change the IO entry to generic IO to support working on different architecture with different endian mode. Also add some properties to support esdhc on ls1021a-qds. Signed-off-by: Qiu WeiJie <B49553@freescale.com> Signed-off-by: Haijun Zhang <Haijun.Zhang@freescale.com> --- This patch has sent to linux-mmc maillist. URL: https://patchwork.kernel.org/patch/3976141/ Change-Id: I4959b07bf9e38a442316f0f45425018fa7d6f579 Reviewed-on: http://git.am.freescale.net:8181/14824 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Xiaobo Xie <X.Xie@freescale.com> Reviewed-by: Zhengxiong Jin <Jason.Jin@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c119
-rw-r--r--drivers/mmc/host/sdhci-of-hlwd.c12
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c11
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h74
4 files changed, 148 insertions, 68 deletions
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 0f9f36b..2e747cc 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -32,7 +32,7 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg)
{
u32 ret;
- ret = in_be32(host->ioaddr + reg);
+ ret = sdhci_32bs_readl(host, reg);
/*
* The bit of ADMA flag in eSDHC is not compatible with standard
* SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
@@ -44,7 +44,7 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg)
* the verdor version number, oxFE is SDHCI_HOST_VERSION.
*/
if ((reg == SDHCI_CAPABILITIES) && (ret & SDHCI_CAN_DO_ADMA1)) {
- u32 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+ u32 tmp = sdhci_32bs_readl(host, SDHCI_SLOT_INT_STATUS);
tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
if (tmp > VENDOR_V_22)
ret |= SDHCI_CAN_DO_ADMA2;
@@ -68,9 +68,9 @@ static u16 esdhc_readw(struct sdhci_host *host, int reg)
int shift = (reg & 0x2) * 8;
if (unlikely(reg == SDHCI_HOST_VERSION))
- ret = in_be32(host->ioaddr + base) & 0xffff;
+ ret = sdhci_32bs_readl(host, base) & 0xffff;
else
- ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff;
+ ret = (sdhci_32bs_readl(host, base) >> shift) & 0xffff;
/* T4240-R1.0-R2.0 had a incorrect vendor version and spec version */
if ((reg == SDHCI_HOST_VERSION) &&
@@ -85,7 +85,10 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
{
int base = reg & ~0x3;
int shift = (reg & 0x3) * 8;
- u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff;
+ u32 ret;
+ u8 val;
+
+ ret = sdhci_32bs_readl(host, base);
/*
* "DMA select" locates at offset 0x28 in SD specification, but on
@@ -94,16 +97,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
if (reg == SDHCI_HOST_CONTROL) {
u32 dma_bits;
- dma_bits = in_be32(host->ioaddr + reg);
/* DMA select is 22,23 bits in Protocol Control Register */
- dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK;
+ dma_bits = (ret >> 5) & SDHCI_CTRL_DMA_MASK;
/* fixup the result */
ret &= ~SDHCI_CTRL_DMA_MASK;
ret |= dma_bits;
+ val = (ret & 0xff);
}
- return ret;
+ val = (ret >> shift) & 0xff;
+
+ return val;
}
static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
@@ -115,11 +120,28 @@ static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
*/
if (reg == SDHCI_INT_ENABLE)
val |= SDHCI_INT_BLK_GAP;
- sdhci_be32bs_writel(host, val, reg);
+ sdhci_32bs_writel(host, val, reg);
}
static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ switch (reg) {
+ case SDHCI_TRANSFER_MODE:
+ /*
+ * Postpone this write, we must do it together with a
+ * command write that is down below.
+ */
+ pltfm_host->xfer_mode_shadow = val;
+ return;
+ case SDHCI_COMMAND:
+ sdhci_32bs_writel(host, val << 16 |
+ pltfm_host->xfer_mode_shadow,
+ SDHCI_TRANSFER_MODE);
+ return;
+ }
+
if (reg == SDHCI_BLOCK_SIZE) {
/*
* Two last DMA bits are reserved, and first one is used for
@@ -128,7 +150,7 @@ static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
*/
val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
}
- sdhci_be32bs_writew(host, val, reg);
+ sdhci_clrsetbits(host, 0xffff, val, reg);
}
static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
@@ -149,10 +171,10 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
/* DMA select is 22,23 bits in Protocol Control Register */
dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
- clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
- dma_bits);
+ sdhci_clrsetbits(host, SDHCI_CTRL_DMA_MASK << 5, dma_bits,
+ SDHCI_HOST_CONTROL);
val &= ~SDHCI_CTRL_DMA_MASK;
- val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK;
+ val |= sdhci_32bs_readl(host, reg) & SDHCI_CTRL_DMA_MASK;
}
/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
@@ -174,7 +196,7 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
temp &= ~ESDHC_CLOCK_CRDEN;
esdhc_writel(host, temp, ESDHC_SYSTEM_CONTROL);
- sdhci_be32bs_writeb(host, val, reg);
+ sdhci_32bs_writeb(host, val, reg);
temp |= ESDHC_CLOCK_CRDEN;
esdhc_writel(host, temp, ESDHC_SYSTEM_CONTROL);
@@ -190,7 +212,7 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
if (SVR_SOC_VER(svr) == SVR_T4240) {
u8 vol;
- vol = sdhci_be32bs_readb(host, reg);
+ vol = sdhci_32bs_readb(host, reg);
if (host->pwr == SDHCI_POWER_180)
vol &= ~ESDHC_VOL_SEL;
else
@@ -199,7 +221,7 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
return;
}
- sdhci_be32bs_writeb(host, val, reg);
+ sdhci_clrsetbits(host, 0xff, val, reg);
}
/*
@@ -216,7 +238,7 @@ static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
dma_addr_t dmastart;
dma_addr_t dmanow;
- tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+ tmp = esdhc_readl(host, SDHCI_SLOT_INT_STATUS);
tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
applicable = (intmask & SDHCI_INT_DATA_END) &&
@@ -234,7 +256,7 @@ static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
SDHCI_DEFAULT_BOUNDARY_SIZE;
host->data->bytes_xfered = dmanow - dmastart;
- sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+ esdhc_writel(host, dmanow, SDHCI_DMA_ADDRESS);
return;
}
@@ -316,7 +338,8 @@ static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
static int esdhc_of_enable_dma(struct sdhci_host *host)
{
- setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
+ esdhc_writel(host, esdhc_readl(host, ESDHC_DMA_SYSCTL)
+ | ESDHC_DMA_SNOOP, ESDHC_DMA_SYSCTL);
return 0;
}
@@ -352,12 +375,12 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
static u32 esdhc_proctl;
static void esdhc_of_suspend(struct sdhci_host *host)
{
- esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
+ esdhc_proctl = esdhc_readl(host, SDHCI_HOST_CONTROL);
}
static void esdhc_of_resume(struct sdhci_host *host)
{
- sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
+ esdhc_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
}
#endif
@@ -390,7 +413,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
u32 vvn;
svr = mfspr(SPRN_SVR);
- vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+ vvn = esdhc_readl(host, SDHCI_SLOT_INT_STATUS);
vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
if (vvn == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
@@ -437,18 +460,18 @@ static int esdhc_of_get_cd(struct sdhci_host *host)
if (host->quirks2 & SDHCI_QUIRK2_FORCE_CMD13_DETECT_CARD)
return -ENOSYS;
- sysctl = sdhci_be32bs_readl(host, SDHCI_CLOCK_CONTROL);
+ sysctl = sdhci_32bs_readl(host, SDHCI_CLOCK_CONTROL);
/* Enable the controller clock to update the present state */
- sdhci_be32bs_writel(host, sysctl | SDHCI_CLOCK_INT_EN,
+ sdhci_32bs_writel(host, sysctl | SDHCI_CLOCK_INT_EN,
SDHCI_CLOCK_CONTROL);
/* Detect the card present or absent */
- present = sdhci_be32bs_readl(host, SDHCI_PRESENT_STATE);
+ present = sdhci_32bs_readl(host, SDHCI_PRESENT_STATE);
present &= (SDHCI_CARD_PRESENT | SDHCI_CARD_CDPL);
/* Resave the previous to System control register */
- sdhci_be32bs_writel(host, sysctl, SDHCI_CLOCK_CONTROL);
+ sdhci_32bs_writel(host, sysctl, SDHCI_CLOCK_CONTROL);
return !!present;
}
@@ -486,8 +509,8 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
break;
}
- clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
- ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
+ sdhci_clrsetbits(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
+ SDHCI_HOST_CONTROL);
return 0;
}
@@ -528,19 +551,18 @@ static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
.ops = &sdhci_esdhc_ops,
};
-static int sdhci_esdhc_probe(struct platform_device *pdev)
+static void esdhc_get_property(struct platform_device *pdev)
{
- struct sdhci_host *host;
- struct device_node *np;
- int ret;
-
- host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
- if (IS_ERR(host))
- return PTR_ERR(host);
+ struct device_node *np = pdev->dev.of_node;
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
sdhci_get_of_property(pdev);
- np = pdev->dev.of_node;
+ /* call to generic mmc_of_parse to support additional capabilities */
+ mmc_of_parse(host->mmc);
+ mmc_of_parse_voltage(np, &host->ocr_mask);
+
if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
/*
* Freescale messed up with P2020 as it has a non-standard
@@ -549,10 +571,27 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
}
- /* call to generic mmc_of_parse to support additional capabilities */
- mmc_of_parse(host->mmc);
- mmc_of_parse_voltage(np, &host->ocr_mask);
+ if (of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
+ host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+ if (!pltfm_host->clock) {
+ pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
+ pltfm_host->clock = clk_get_rate(pltfm_host->clk);
+ clk_prepare_enable(pltfm_host->clk);
+ }
+}
+
+static int sdhci_esdhc_probe(struct platform_device *pdev)
+{
+ struct sdhci_host *host;
+ int ret;
+
+
+ host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+ esdhc_get_property(pdev);
ret = sdhci_add_host(host);
if (ret)
sdhci_pltfm_free(pdev);
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 57c514a..3605665 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -35,26 +35,26 @@
static void sdhci_hlwd_writel(struct sdhci_host *host, u32 val, int reg)
{
- sdhci_be32bs_writel(host, val, reg);
+ sdhci_32bs_writel(host, val, reg);
udelay(SDHCI_HLWD_WRITE_DELAY);
}
static void sdhci_hlwd_writew(struct sdhci_host *host, u16 val, int reg)
{
- sdhci_be32bs_writew(host, val, reg);
+ sdhci_32bs_writew(host, val, reg);
udelay(SDHCI_HLWD_WRITE_DELAY);
}
static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
{
- sdhci_be32bs_writeb(host, val, reg);
+ sdhci_32bs_writeb(host, val, reg);
udelay(SDHCI_HLWD_WRITE_DELAY);
}
static const struct sdhci_ops sdhci_hlwd_ops = {
- .read_l = sdhci_be32bs_readl,
- .read_w = sdhci_be32bs_readw,
- .read_b = sdhci_be32bs_readb,
+ .read_l = sdhci_32bs_readl,
+ .read_w = sdhci_32bs_readw,
+ .read_b = sdhci_32bs_readb,
.write_l = sdhci_hlwd_writel,
.write_w = sdhci_hlwd_writew,
.write_b = sdhci_hlwd_writeb,
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index f0b2030..2512c11 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -135,6 +135,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
{
struct sdhci_host *host;
struct device_node *np = pdev->dev.of_node;
+ struct sdhci_pltfm_host *pltfm_host;
struct resource *iomem;
int ret;
@@ -160,6 +161,14 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
goto err;
}
+ pltfm_host = sdhci_priv(host);
+ pltfm_host->endian_mode = BIG_ENDIAN_MODE;
+
+#ifdef CONFIG_OF
+ if (of_get_property(np, "little-endian", NULL))
+ pltfm_host->endian_mode = LITTLE_ENDIAN_MODE;
+#endif /* CONFIG_OF */
+
host->hw_name = dev_name(&pdev->dev);
if (pdata && pdata->ops)
host->ops = pdata->ops;
@@ -245,7 +254,7 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_register);
int sdhci_pltfm_unregister(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
- int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+ int dead = (sdhci_readl(host, SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
sdhci_pltfm_free(pdev);
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index e15ced79..c31aa94 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -28,6 +28,10 @@ struct sdhci_pltfm_host {
/* migrate from sdhci_of_host */
unsigned int clock;
u16 xfer_mode_shadow;
+ enum endian_mode {
+ LITTLE_ENDIAN_MODE,
+ BIG_ENDIAN_MODE,
+ } endian_mode;
unsigned long private[0] ____cacheline_aligned;
};
@@ -37,33 +41,61 @@ struct sdhci_pltfm_host {
* These accessors are designed for big endian hosts doing I/O to
* little endian controllers incorporating a 32-bit hardware byte swapper.
*/
-static inline u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
+static inline void sdhci_clrsetbits(struct sdhci_host *host, u32 mask,
+ u32 val, int reg)
{
- return in_be32(host->ioaddr + reg);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ void __iomem *base = host->ioaddr + (reg & ~0x3);
+ u32 shift = (reg & 0x3) * 8;
+
+ if (pltfm_host->endian_mode == BIG_ENDIAN_MODE)
+ iowrite32be(((ioread32be(base) & ~(mask << shift)) |
+ (val << shift)), base);
+ else
+ iowrite32(((ioread32(base) & ~(mask << shift)) |
+ (val << shift)), base);
}
-static inline u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
+static inline u32 sdhci_32bs_readl(struct sdhci_host *host, int reg)
{
- return in_be16(host->ioaddr + (reg ^ 0x2));
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ if (pltfm_host->endian_mode == BIG_ENDIAN_MODE)
+ return ioread32be(host->ioaddr + reg);
+ else
+ return ioread32(host->ioaddr + reg);
}
-static inline u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
+static inline u16 sdhci_32bs_readw(struct sdhci_host *host, int reg)
{
- return in_8(host->ioaddr + (reg ^ 0x3));
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ if (pltfm_host->endian_mode == BIG_ENDIAN_MODE)
+ return ioread16be(host->ioaddr + (reg ^ 0x2));
+ else
+ return ioread16(host->ioaddr + (reg ^ 0x2));
}
-static inline void sdhci_be32bs_writel(struct sdhci_host *host,
- u32 val, int reg)
+static inline u8 sdhci_32bs_readb(struct sdhci_host *host, int reg)
{
- out_be32(host->ioaddr + reg, val);
+ return ioread8(host->ioaddr + (reg ^ 0x3));
}
-static inline void sdhci_be32bs_writew(struct sdhci_host *host,
+static inline void sdhci_32bs_writel(struct sdhci_host *host,
+ u32 val, int reg)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ if (pltfm_host->endian_mode == BIG_ENDIAN_MODE)
+ iowrite32be(val, host->ioaddr + reg);
+ else
+ iowrite32(val, host->ioaddr + reg);
+}
+
+static inline void sdhci_32bs_writew(struct sdhci_host *host,
u16 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- int base = reg & ~0x3;
- int shift = (reg & 0x2) * 8;
switch (reg) {
case SDHCI_TRANSFER_MODE:
@@ -74,20 +106,20 @@ static inline void sdhci_be32bs_writew(struct sdhci_host *host,
pltfm_host->xfer_mode_shadow = val;
return;
case SDHCI_COMMAND:
- sdhci_be32bs_writel(host,
- val << 16 | pltfm_host->xfer_mode_shadow,
- SDHCI_TRANSFER_MODE);
+ if (pltfm_host->endian_mode == BIG_ENDIAN_MODE)
+ iowrite32be(val << 16 | pltfm_host->xfer_mode_shadow,
+ host->ioaddr + SDHCI_TRANSFER_MODE);
+ else
+ iowrite32(val << 16 | pltfm_host->xfer_mode_shadow,
+ host->ioaddr + SDHCI_TRANSFER_MODE);
return;
}
- clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
+ sdhci_clrsetbits(host, 0xffff, val, reg);
}
-static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
+static inline void sdhci_32bs_writeb(struct sdhci_host *host, u8 val, int reg)
{
- int base = reg & ~0x3;
- int shift = (reg & 0x3) * 8;
-
- clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
+ sdhci_clrsetbits(host, 0xff, val, reg);
}
#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */