diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/host/sdhci-pxav3.c | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 90cbf016894e..b5103a247bc1 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -62,6 +62,7 @@ struct sdhci_pxa { struct clk *clk_core; struct clk *clk_io; u8 power_mode; + void __iomem *sdio3_conf_reg; }; /* @@ -72,6 +73,14 @@ struct sdhci_pxa { #define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3)) #define SDHCI_MAX_WIN_NUM 8 +/* + * Fields below belong to SDIO3 Configuration Register (third register + * region for the Armada 38x flavor) + */ + +#define SDIO3_CONF_CLK_INV BIT(0) +#define SDIO3_CONF_SD_FB_CLK BIT(2) + static int mv_conf_mbus_windows(struct platform_device *pdev, const struct mbus_dram_target_info *dram) { @@ -122,16 +131,29 @@ static int armada_38x_quirks(struct platform_device *pdev, struct sdhci_host *host) { struct device_node *np = pdev->dev.of_node; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; + struct resource *res; host->quirks |= SDHCI_QUIRK_MISSING_CAPS; - /* - * According to erratum 'FE-2946959' both SDR50 and DDR50 - * modes require specific clock adjustments in SDIO3 - * Configuration register, if the adjustment is not done, - * remove them from the capabilities. - */ - host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); - host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "conf-sdio3"); + if (res) { + pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pxa->sdio3_conf_reg)) + return PTR_ERR(pxa->sdio3_conf_reg); + } else { + /* + * According to erratum 'FE-2946959' both SDR50 and DDR50 + * modes require specific clock adjustments in SDIO3 + * Configuration register, if the adjustment is not done, + * remove them from the capabilities. + */ + host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + + dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n"); + } /* * According to erratum 'ERR-7878951' Armada 38x SDHCI @@ -226,6 +248,8 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; u16 ctrl_2; /* @@ -255,6 +279,24 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) break; } + /* + * Update SDIO3 Configuration register according to erratum + * FE-2946959 + */ + if (pxa->sdio3_conf_reg) { + u8 reg_val = readb(pxa->sdio3_conf_reg); + + if (uhs == MMC_TIMING_UHS_SDR50 || + uhs == MMC_TIMING_UHS_DDR50) { + reg_val &= ~SDIO3_CONF_CLK_INV; + reg_val |= SDIO3_CONF_SD_FB_CLK; + } else { + reg_val |= SDIO3_CONF_CLK_INV; + reg_val &= ~SDIO3_CONF_SD_FB_CLK; + } + writeb(reg_val, pxa->sdio3_conf_reg); + } + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); dev_dbg(mmc_dev(host->mmc), "%s uhs = %d, ctrl_2 = %04X\n", |