diff options
-rw-r--r-- | drivers/mmc/host/sdhci-xenon-phy.c | 110 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-xenon.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-xenon.h | 2 |
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 | ||
146 | enum soc_pad_ctrl_type { | ||
147 | SOC_PAD_SD, | ||
148 | SOC_PAD_FIXED_1_8V, | ||
149 | }; | ||
150 | |||
151 | struct 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 | |||
146 | static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = { | 161 | static 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 | ||
181 | static int xenon_alloc_emmc_phy(struct sdhci_host *host) | 198 | static 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 | |||
277 | static 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 | */ | ||
299 | static 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 | ||
621 | static 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 | |||
565 | static int xenon_emmc_phy_parse_param_dt(struct sdhci_host *host, | 666 | static 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 */ | ||
698 | void 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); | |||
96 | void xenon_clean_phy(struct sdhci_host *host); | 96 | void xenon_clean_phy(struct sdhci_host *host); |
97 | int xenon_phy_parse_dt(struct device_node *np, | 97 | int xenon_phy_parse_dt(struct device_node *np, |
98 | struct sdhci_host *host); | 98 | struct sdhci_host *host); |
99 | void xenon_soc_pad_ctrl(struct sdhci_host *host, | ||
100 | unsigned char signal_voltage); | ||
99 | #endif | 101 | #endif |