On 28 March 2015 at 04:42, Yangbo Lu <yangbo.lu@xxxxxxxxxxxxx> wrote: > This patch is to support little-endian mode for ARM > eSDHC that has the same IP block with PowerPC but has > different endian mode. > > Signed-off-by: Yangbo Lu <yangbo.lu@xxxxxxxxxxxxx> I would suggest you to split this patch into a few pieces. The common part in sdhci-pltfm, then one for sdhci-of-esdhc and on for sdhci-of-hlwd. In case you _really_ need to change all files in one patch, please update the commit message header to explain that. Kind regards Uffe > --- > drivers/mmc/host/sdhci-of-esdhc.c | 105 +++++++++++++++++++++++++------------- > drivers/mmc/host/sdhci-of-hlwd.c | 12 ++--- > drivers/mmc/host/sdhci-pltfm.c | 12 ++++- > drivers/mmc/host/sdhci-pltfm.h | 74 +++++++++++++++++++-------- > 4 files changed, 139 insertions(+), 64 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c > index 17fe02e..a39b789 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -28,7 +28,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 > @@ -40,7 +40,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; > @@ -56,9 +56,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; > return ret; > } > > @@ -66,7 +66,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 > @@ -75,16 +78,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) > @@ -96,11 +101,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 > @@ -109,7 +131,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) > @@ -130,16 +152,16 @@ 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). */ > if (reg == SDHCI_HOST_CONTROL) > val &= ~ESDHC_HOST_CONTROL_RES; > - sdhci_be32bs_writeb(host, val, reg); > + sdhci_clrsetbits(host, 0xff, val, reg); > } > > /* > @@ -156,7 +178,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) && > @@ -174,12 +196,13 @@ 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); > } > > 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; > } > > @@ -245,7 +268,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host) > { > u32 vvn; > > - 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; > @@ -272,8 +295,8 @@ static void esdhc_pltfm_set_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); > } > > static void esdhc_reset(struct sdhci_host *host, u8 mask) > @@ -309,7 +332,7 @@ static int esdhc_of_suspend(struct device *dev) > { > struct sdhci_host *host = dev_get_drvdata(dev); > > - esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL); > + esdhc_proctl = esdhc_readl(host, SDHCI_HOST_CONTROL); > > return sdhci_suspend_host(host); > } > @@ -322,7 +345,7 @@ static int esdhc_of_resume(struct device *dev) > if (ret == 0) { > /* Isn't this already done by sdhci_resume_host() ? --rmk */ > esdhc_of_enable_dma(host); > - sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); > + esdhc_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); > } > > return ret; > @@ -348,19 +371,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 > @@ -369,13 +391,24 @@ 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 */ > - ret = mmc_of_parse(host->mmc); > - if (ret) > - goto err; > + 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); > + } > +} > > - mmc_of_parse_voltage(np, &host->ocr_mask); > +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) > goto err; > diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c > index be47927..9384c2a 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 c5b01d6..781f90f 100644 > --- a/drivers/mmc/host/sdhci-pltfm.c > +++ b/drivers/mmc/host/sdhci-pltfm.c > @@ -123,6 +123,8 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, > size_t priv_size) > { > struct sdhci_host *host; > + struct device_node *np = pdev->dev.of_node; > + struct sdhci_pltfm_host *pltfm_host; > struct resource *iomem; > int ret; > > @@ -143,6 +145,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; > @@ -225,7 +235,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 04bc248..a8cf954 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 */ > > -- > 2.1.0.27.g96db324 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html