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 |
