aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci-pxav3.c
diff options
context:
space:
mode:
authorMarcin Wojtas <mw@semihalf.com>2015-01-29 06:36:27 -0500
committerUlf Hansson <ulf.hansson@linaro.org>2015-01-29 07:08:46 -0500
commit1140011ee9d9ca34a2d3e4950c2e6c388188c5e6 (patch)
tree3613ff3d3923280cea6e00ecb52af0f56ce609d4 /drivers/mmc/host/sdhci-pxav3.c
parentd58a2ea5cbd64c3bcc9f8a30db9db4d0ef4aaf51 (diff)
mmc: sdhci-pxav3: Modify clock settings for the SDR50 and DDR50 modes
According to erratum 'FE-2946959' both SDR50 and DDR50 modes require specific clock adjustments in SDIO3 Configuration register. This commit add the support of this register and for SDR50 or DDR50 mode use it as suggested by the erratum: - Set the SDIO3 Clock Inv field in SDIO3 Configuration register to not inverted. - Set the Sample FeedBack Clock field to 0x1 [gregory.clement@free-electrons.com: port from 3.10] Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/sdhci-pxav3.c')
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c58
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 {
62 struct clk *clk_core; 62 struct clk *clk_core;
63 struct clk *clk_io; 63 struct clk *clk_io;
64 u8 power_mode; 64 u8 power_mode;
65 void __iomem *sdio3_conf_reg;
65}; 66};
66 67
67/* 68/*
@@ -72,6 +73,14 @@ struct sdhci_pxa {
72#define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3)) 73#define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3))
73#define SDHCI_MAX_WIN_NUM 8 74#define SDHCI_MAX_WIN_NUM 8
74 75
76/*
77 * Fields below belong to SDIO3 Configuration Register (third register
78 * region for the Armada 38x flavor)
79 */
80
81#define SDIO3_CONF_CLK_INV BIT(0)
82#define SDIO3_CONF_SD_FB_CLK BIT(2)
83
75static int mv_conf_mbus_windows(struct platform_device *pdev, 84static int mv_conf_mbus_windows(struct platform_device *pdev,
76 const struct mbus_dram_target_info *dram) 85 const struct mbus_dram_target_info *dram)
77{ 86{
@@ -122,16 +131,29 @@ static int armada_38x_quirks(struct platform_device *pdev,
122 struct sdhci_host *host) 131 struct sdhci_host *host)
123{ 132{
124 struct device_node *np = pdev->dev.of_node; 133 struct device_node *np = pdev->dev.of_node;
134 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
135 struct sdhci_pxa *pxa = pltfm_host->priv;
136 struct resource *res;
125 137
126 host->quirks |= SDHCI_QUIRK_MISSING_CAPS; 138 host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
127 /* 139 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
128 * According to erratum 'FE-2946959' both SDR50 and DDR50 140 "conf-sdio3");
129 * modes require specific clock adjustments in SDIO3 141 if (res) {
130 * Configuration register, if the adjustment is not done, 142 pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res);
131 * remove them from the capabilities. 143 if (IS_ERR(pxa->sdio3_conf_reg))
132 */ 144 return PTR_ERR(pxa->sdio3_conf_reg);
133 host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); 145 } else {
134 host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); 146 /*
147 * According to erratum 'FE-2946959' both SDR50 and DDR50
148 * modes require specific clock adjustments in SDIO3
149 * Configuration register, if the adjustment is not done,
150 * remove them from the capabilities.
151 */
152 host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
153 host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
154
155 dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n");
156 }
135 157
136 /* 158 /*
137 * According to erratum 'ERR-7878951' Armada 38x SDHCI 159 * 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)
226 248
227static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) 249static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
228{ 250{
251 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
252 struct sdhci_pxa *pxa = pltfm_host->priv;
229 u16 ctrl_2; 253 u16 ctrl_2;
230 254
231 /* 255 /*
@@ -255,6 +279,24 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
255 break; 279 break;
256 } 280 }
257 281
282 /*
283 * Update SDIO3 Configuration register according to erratum
284 * FE-2946959
285 */
286 if (pxa->sdio3_conf_reg) {
287 u8 reg_val = readb(pxa->sdio3_conf_reg);
288
289 if (uhs == MMC_TIMING_UHS_SDR50 ||
290 uhs == MMC_TIMING_UHS_DDR50) {
291 reg_val &= ~SDIO3_CONF_CLK_INV;
292 reg_val |= SDIO3_CONF_SD_FB_CLK;
293 } else {
294 reg_val |= SDIO3_CONF_CLK_INV;
295 reg_val &= ~SDIO3_CONF_SD_FB_CLK;
296 }
297 writeb(reg_val, pxa->sdio3_conf_reg);
298 }
299
258 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 300 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
259 dev_dbg(mmc_dev(host->mmc), 301 dev_dbg(mmc_dev(host->mmc),
260 "%s uhs = %d, ctrl_2 = %04X\n", 302 "%s uhs = %d, ctrl_2 = %04X\n",