aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHu Ziji <huziji@marvell.com>2017-03-30 11:23:01 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2017-04-24 15:42:17 -0400
commit298269c602b54dd56e1424cb8e706fc30bc7d489 (patch)
tree4e21fbd4cae6314f5ab846eaf4dba6a72060c30e
parent06c8b667ff5b984ac3aa901c4928e4a427987a56 (diff)
mmc: sdhci-xenon: Add SoC PHY PAD voltage control
Some SoCs have PHY PAD outside Xenon IP. PHY PAD voltage should match signalling voltage in use. Add generic SoC PHY PAD voltage control interface. Implement Aramda-3700 SoC PHY PAD voltage control. Signed-off-by: Hu Ziji <huziji@marvell.com> Tested-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/host/sdhci-xenon-phy.c110
-rw-r--r--drivers/mmc/host/sdhci-xenon.c2
-rw-r--r--drivers/mmc/host/sdhci-xenon.h2
3 files changed, 113 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c
index b14544e91b65..4bdbcd3f2645 100644
--- a/drivers/mmc/host/sdhci-xenon-phy.c
+++ b/drivers/mmc/host/sdhci-xenon-phy.c
@@ -143,6 +143,21 @@ enum xenon_phy_type_enum {
143 NR_PHY_TYPES 143 NR_PHY_TYPES
144}; 144};
145 145
146enum soc_pad_ctrl_type {
147 SOC_PAD_SD,
148 SOC_PAD_FIXED_1_8V,
149};
150
151struct soc_pad_ctrl {
152 /* Register address of SoC PHY PAD ctrl */
153 void __iomem *reg;
154 /* SoC PHY PAD ctrl type */
155 enum soc_pad_ctrl_type pad_type;
156 /* SoC specific operation to set SoC PHY PAD */
157 void (*set_soc_pad)(struct sdhci_host *host,
158 unsigned char signal_voltage);
159};
160
146static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = { 161static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = {
147 .timing_adj = XENON_EMMC_5_0_PHY_TIMING_ADJUST, 162 .timing_adj = XENON_EMMC_5_0_PHY_TIMING_ADJUST,
148 .func_ctrl = XENON_EMMC_5_0_PHY_FUNC_CONTROL, 163 .func_ctrl = XENON_EMMC_5_0_PHY_FUNC_CONTROL,
@@ -176,6 +191,8 @@ struct xenon_emmc_phy_params {
176 u8 nr_tun_times; 191 u8 nr_tun_times;
177 /* Divider for calculating Tuning Step */ 192 /* Divider for calculating Tuning Step */
178 u8 tun_step_divider; 193 u8 tun_step_divider;
194
195 struct soc_pad_ctrl pad_ctrl;
179}; 196};
180 197
181static int xenon_alloc_emmc_phy(struct sdhci_host *host) 198static int xenon_alloc_emmc_phy(struct sdhci_host *host)
@@ -254,6 +271,45 @@ static int xenon_emmc_phy_init(struct sdhci_host *host)
254 return 0; 271 return 0;
255} 272}
256 273
274#define ARMADA_3700_SOC_PAD_1_8V 0x1
275#define ARMADA_3700_SOC_PAD_3_3V 0x0
276
277static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host,
278 unsigned char signal_voltage)
279{
280 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
281 struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
282 struct xenon_emmc_phy_params *params = priv->phy_params;
283
284 if (params->pad_ctrl.pad_type == SOC_PAD_FIXED_1_8V) {
285 writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg);
286 } else if (params->pad_ctrl.pad_type == SOC_PAD_SD) {
287 if (signal_voltage == MMC_SIGNAL_VOLTAGE_180)
288 writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg);
289 else if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
290 writel(ARMADA_3700_SOC_PAD_3_3V, params->pad_ctrl.reg);
291 }
292}
293
294/*
295 * Set SoC PHY voltage PAD control register,
296 * according to the operation voltage on PAD.
297 * The detailed operation depends on SoC implementation.
298 */
299static void xenon_emmc_phy_set_soc_pad(struct sdhci_host *host,
300 unsigned char signal_voltage)
301{
302 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
303 struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
304 struct xenon_emmc_phy_params *params = priv->phy_params;
305
306 if (!params->pad_ctrl.reg)
307 return;
308
309 if (params->pad_ctrl.set_soc_pad)
310 params->pad_ctrl.set_soc_pad(host, signal_voltage);
311}
312
257/* 313/*
258 * Enable eMMC PHY HW DLL 314 * Enable eMMC PHY HW DLL
259 * DLL should be enabled and stable before HS200/SDR104 tuning, 315 * DLL should be enabled and stable before HS200/SDR104 tuning,
@@ -562,6 +618,51 @@ phy_init:
562 dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n"); 618 dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n");
563} 619}
564 620
621static int get_dt_pad_ctrl_data(struct sdhci_host *host,
622 struct device_node *np,
623 struct xenon_emmc_phy_params *params)
624{
625 int ret = 0;
626 const char *name;
627 struct resource iomem;
628
629 if (of_device_is_compatible(np, "marvell,armada-3700-sdhci"))
630 params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set;
631 else
632 return 0;
633
634 if (of_address_to_resource(np, 1, &iomem)) {
635 dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %s\n",
636 np->name);
637 return -EINVAL;
638 }
639
640 params->pad_ctrl.reg = devm_ioremap_resource(mmc_dev(host->mmc),
641 &iomem);
642 if (IS_ERR(params->pad_ctrl.reg)) {
643 dev_err(mmc_dev(host->mmc), "Unable to get SoC PHY PAD ctrl register for %s\n",
644 np->name);
645 return PTR_ERR(params->pad_ctrl.reg);
646 }
647
648 ret = of_property_read_string(np, "marvell,pad-type", &name);
649 if (ret) {
650 dev_err(mmc_dev(host->mmc), "Unable to determine SoC PHY PAD ctrl type\n");
651 return ret;
652 }
653 if (!strcmp(name, "sd")) {
654 params->pad_ctrl.pad_type = SOC_PAD_SD;
655 } else if (!strcmp(name, "fixed-1-8v")) {
656 params->pad_ctrl.pad_type = SOC_PAD_FIXED_1_8V;
657 } else {
658 dev_err(mmc_dev(host->mmc), "Unsupported SoC PHY PAD ctrl type %s\n",
659 name);
660 return -EINVAL;
661 }
662
663 return ret;
664}
665
565static int xenon_emmc_phy_parse_param_dt(struct sdhci_host *host, 666static int xenon_emmc_phy_parse_param_dt(struct sdhci_host *host,
566 struct device_node *np, 667 struct device_node *np,
567 struct xenon_emmc_phy_params *params) 668 struct xenon_emmc_phy_params *params)
@@ -590,7 +691,14 @@ static int xenon_emmc_phy_parse_param_dt(struct sdhci_host *host,
590 &value)) 691 &value))
591 params->tun_step_divider = value & 0xFF; 692 params->tun_step_divider = value & 0xFF;
592 693
593 return 0; 694 return get_dt_pad_ctrl_data(host, np, params);
695}
696
697/* Set SoC PHY Voltage PAD */
698void xenon_soc_pad_ctrl(struct sdhci_host *host,
699 unsigned char signal_voltage)
700{
701 xenon_emmc_phy_set_soc_pad(host, signal_voltage);
594} 702}
595 703
596/* 704/*
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
index 36e22bd2b8cc..8e56b9ccfb39 100644
--- a/drivers/mmc/host/sdhci-xenon.c
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -280,6 +280,8 @@ static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
280 */ 280 */
281 xenon_enable_internal_clk(host); 281 xenon_enable_internal_clk(host);
282 282
283 xenon_soc_pad_ctrl(host, ios->signal_voltage);
284
283 /* 285 /*
284 * If Vqmmc is fixed on platform, vqmmc regulator should be unavailable. 286 * If Vqmmc is fixed on platform, vqmmc regulator should be unavailable.
285 * Thus SDHCI_CTRL_VDD_180 bit might not work then. 287 * Thus SDHCI_CTRL_VDD_180 bit might not work then.
diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h
index b29d45358de8..6e6523ea01ce 100644
--- a/drivers/mmc/host/sdhci-xenon.h
+++ b/drivers/mmc/host/sdhci-xenon.h
@@ -96,4 +96,6 @@ int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
96void xenon_clean_phy(struct sdhci_host *host); 96void xenon_clean_phy(struct sdhci_host *host);
97int xenon_phy_parse_dt(struct device_node *np, 97int xenon_phy_parse_dt(struct device_node *np,
98 struct sdhci_host *host); 98 struct sdhci_host *host);
99void xenon_soc_pad_ctrl(struct sdhci_host *host,
100 unsigned char signal_voltage);
99#endif 101#endif