Lines Matching +full:phy +full:- +full:dll +full:- +full:delay +full:- +full:sdclk

1 // SPDX-License-Identifier: GPL-2.0-only
3 * PHY support for Xenon SDHC
8 * Date: 2016-8-24
12 #include <linux/delay.h>
16 #include "sdhci-pltfm.h"
17 #include "sdhci-xenon.h"
19 /* Register base for eMMC PHY 5.0 Version */
21 /* Register base for eMMC PHY 5.1 Version */
113 * List offset of PHY registers and some special register values
114 * in eMMC PHY 5.0 or eMMC PHY 5.1
125 /* Offset of DLL Control register */
129 /* DLL Update Enable bit */
136 "emmc 5.0 phy",
137 "emmc 5.1 phy"
152 /* Register address of SoC PHY PAD ctrl */
154 /* SoC PHY PAD ctrl type */
156 /* SoC specific operation to set SoC PHY PAD */
184 * eMMC PHY configuration and operations
206 params = devm_kzalloc(mmc_dev(host->mmc), sizeof(*params), GFP_KERNEL); in xenon_alloc_emmc_phy()
208 return -ENOMEM; in xenon_alloc_emmc_phy()
210 priv->phy_params = params; in xenon_alloc_emmc_phy()
211 if (priv->phy_type == EMMC_5_0_PHY) in xenon_alloc_emmc_phy()
212 priv->emmc_phy_regs = &xenon_emmc_5_0_phy_regs; in xenon_alloc_emmc_phy()
214 priv->emmc_phy_regs = &xenon_emmc_5_1_phy_regs; in xenon_alloc_emmc_phy()
220 * eMMC 5.0/5.1 PHY init/re-init.
221 * eMMC PHY init should be executed after:
222 * 1. SDCLK frequency changes.
223 * 2. SDCLK is stopped and re-enabled.
224 * 3. config in emmc_phy_regs->timing_adj and emmc_phy_regs->func_ctrl
233 struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; in xenon_emmc_phy_init()
235 reg = sdhci_readl(host, phy_regs->timing_adj); in xenon_emmc_phy_init()
237 sdhci_writel(host, reg, phy_regs->timing_adj); in xenon_emmc_phy_init()
248 /* Add duration of waiting for PHY */ in xenon_emmc_phy_init()
255 clock = host->clock; in xenon_emmc_phy_init()
262 /* wait for host eMMC PHY init completes */ in xenon_emmc_phy_init()
265 reg = sdhci_readl(host, phy_regs->timing_adj); in xenon_emmc_phy_init()
268 dev_err(mmc_dev(host->mmc), "eMMC PHY init cannot complete after %d us\n", in xenon_emmc_phy_init()
270 return -ETIMEDOUT; in xenon_emmc_phy_init()
284 struct xenon_emmc_phy_params *params = priv->phy_params; in armada_3700_soc_pad_voltage_set()
286 if (params->pad_ctrl.pad_type == SOC_PAD_FIXED_1_8V) { in armada_3700_soc_pad_voltage_set()
287 writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg); in armada_3700_soc_pad_voltage_set()
288 } else if (params->pad_ctrl.pad_type == SOC_PAD_SD) { in armada_3700_soc_pad_voltage_set()
290 writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg); in armada_3700_soc_pad_voltage_set()
292 writel(ARMADA_3700_SOC_PAD_3_3V, params->pad_ctrl.reg); in armada_3700_soc_pad_voltage_set()
297 * Set SoC PHY voltage PAD control register,
306 struct xenon_emmc_phy_params *params = priv->phy_params; in xenon_emmc_phy_set_soc_pad()
308 if (!params->pad_ctrl.reg) in xenon_emmc_phy_set_soc_pad()
311 if (params->pad_ctrl.set_soc_pad) in xenon_emmc_phy_set_soc_pad()
312 params->pad_ctrl.set_soc_pad(host, signal_voltage); in xenon_emmc_phy_set_soc_pad()
316 * Enable eMMC PHY HW DLL
317 * DLL should be enabled and stable before HS200/SDR104 tuning,
325 struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; in xenon_emmc_phy_enable_dll()
328 if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR)) in xenon_emmc_phy_enable_dll()
329 return -EINVAL; in xenon_emmc_phy_enable_dll()
331 reg = sdhci_readl(host, phy_regs->dll_ctrl); in xenon_emmc_phy_enable_dll()
335 /* Enable DLL */ in xenon_emmc_phy_enable_dll()
336 reg = sdhci_readl(host, phy_regs->dll_ctrl); in xenon_emmc_phy_enable_dll()
350 reg |= phy_regs->dll_update; in xenon_emmc_phy_enable_dll()
351 if (priv->phy_type == EMMC_5_1_PHY) in xenon_emmc_phy_enable_dll()
353 sdhci_writel(host, reg, phy_regs->dll_ctrl); in xenon_emmc_phy_enable_dll()
364 dev_err(mmc_dev(host->mmc), "Wait for DLL Lock time-out\n"); in xenon_emmc_phy_enable_dll()
365 return -ETIMEDOUT; in xenon_emmc_phy_enable_dll()
373 * Config to eMMC PHY to prepare for tuning.
374 * Enable HW DLL and set the TUNING_STEP
380 struct xenon_emmc_phy_params *params = priv->phy_params; in xenon_emmc_phy_config_tuning()
384 if (host->clock <= MMC_HIGH_52_MAX_DTR) in xenon_emmc_phy_config_tuning()
385 return -EINVAL; in xenon_emmc_phy_config_tuning()
391 /* Achieve TUNING_STEP with HW DLL help */ in xenon_emmc_phy_config_tuning()
393 tuning_step = reg / params->tun_step_divider; in xenon_emmc_phy_config_tuning()
395 dev_warn(mmc_dev(host->mmc), in xenon_emmc_phy_config_tuning()
405 reg |= (params->nr_tun_times << XENON_TUN_CONSECUTIVE_TIMES_SHIFT); in xenon_emmc_phy_config_tuning()
425 if (priv->phy_type == EMMC_5_0_PHY) { in xenon_emmc_phy_disable_strobe()
443 if (WARN_ON(host->timing != MMC_TIMING_MMC_HS400)) in xenon_emmc_phy_strobe_delay_adj()
446 if (host->clock <= MMC_HIGH_52_MAX_DTR) in xenon_emmc_phy_strobe_delay_adj()
449 dev_dbg(mmc_dev(host->mmc), "starts HS400 strobe delay adjustment\n"); in xenon_emmc_phy_strobe_delay_adj()
460 * 2. SDCLK is higher than 52MHz in xenon_emmc_phy_strobe_delay_adj()
461 * 3. DLL is enabled in xenon_emmc_phy_strobe_delay_adj()
463 if (host->mmc->ios.enhanced_strobe) in xenon_emmc_phy_strobe_delay_adj()
468 if (priv->phy_type == EMMC_5_0_PHY) { in xenon_emmc_phy_strobe_delay_adj()
482 * If eMMC PHY Slow Mode is required in lower speed mode (SDCLK < 55MHz)
483 * in SDR mode, enable Slow Mode to bypass eMMC PHY.
494 struct xenon_emmc_phy_params *params = priv->phy_params; in xenon_emmc_phy_slow_mode()
495 struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; in xenon_emmc_phy_slow_mode()
499 if (host->clock > MMC_HIGH_52_MAX_DTR) in xenon_emmc_phy_slow_mode()
502 reg = sdhci_readl(host, phy_regs->timing_adj); in xenon_emmc_phy_slow_mode()
512 if (params->slow_mode) { in xenon_emmc_phy_slow_mode()
524 if ((priv->init_card_type == MMC_TYPE_SDIO) || in xenon_emmc_phy_slow_mode()
525 params->slow_mode) { in xenon_emmc_phy_slow_mode()
536 sdhci_writel(host, reg, phy_regs->timing_adj); in xenon_emmc_phy_slow_mode()
541 * Set-up eMMC 5.0/5.1 PHY.
550 struct xenon_emmc_phy_params *params = priv->phy_params; in xenon_emmc_phy_set()
551 struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; in xenon_emmc_phy_set()
553 dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting starts\n"); in xenon_emmc_phy_set()
556 reg = sdhci_readl(host, phy_regs->pad_ctrl); in xenon_emmc_phy_set()
561 sdhci_writel(host, reg, phy_regs->pad_ctrl); in xenon_emmc_phy_set()
564 if (priv->phy_type == EMMC_5_0_PHY) { in xenon_emmc_phy_set()
585 reg = sdhci_readl(host, phy_regs->timing_adj); in xenon_emmc_phy_set()
586 if (priv->init_card_type == MMC_TYPE_SDIO) in xenon_emmc_phy_set()
590 sdhci_writel(host, reg, phy_regs->timing_adj); in xenon_emmc_phy_set()
598 * Define them both in sdhci-xenon-emmc-phy.h. in xenon_emmc_phy_set()
600 reg = sdhci_readl(host, phy_regs->pad_ctrl2); in xenon_emmc_phy_set()
602 reg |= ((params->znr << XENON_ZNR_SHIFT) | params->zpr); in xenon_emmc_phy_set()
603 sdhci_writel(host, reg, phy_regs->pad_ctrl2); in xenon_emmc_phy_set()
613 reg = sdhci_readl(host, phy_regs->func_ctrl); in xenon_emmc_phy_set()
630 sdhci_writel(host, reg, phy_regs->func_ctrl); in xenon_emmc_phy_set()
639 sdhci_writel(host, phy_regs->logic_timing_val, in xenon_emmc_phy_set()
640 phy_regs->logic_timing_adj); in xenon_emmc_phy_set()
647 dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n"); in xenon_emmc_phy_set()
658 if (of_device_is_compatible(np, "marvell,armada-3700-sdhci")) in get_dt_pad_ctrl_data()
659 params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set; in get_dt_pad_ctrl_data()
664 dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %pOFn\n", in get_dt_pad_ctrl_data()
666 return -EINVAL; in get_dt_pad_ctrl_data()
669 params->pad_ctrl.reg = devm_ioremap_resource(mmc_dev(host->mmc), in get_dt_pad_ctrl_data()
671 if (IS_ERR(params->pad_ctrl.reg)) in get_dt_pad_ctrl_data()
672 return PTR_ERR(params->pad_ctrl.reg); in get_dt_pad_ctrl_data()
674 ret = of_property_read_string(np, "marvell,pad-type", &name); in get_dt_pad_ctrl_data()
676 dev_err(mmc_dev(host->mmc), "Unable to determine SoC PHY PAD ctrl type\n"); in get_dt_pad_ctrl_data()
680 params->pad_ctrl.pad_type = SOC_PAD_SD; in get_dt_pad_ctrl_data()
681 } else if (!strcmp(name, "fixed-1-8v")) { in get_dt_pad_ctrl_data()
682 params->pad_ctrl.pad_type = SOC_PAD_FIXED_1_8V; in get_dt_pad_ctrl_data()
684 dev_err(mmc_dev(host->mmc), "Unsupported SoC PHY PAD ctrl type %s\n", in get_dt_pad_ctrl_data()
686 return -EINVAL; in get_dt_pad_ctrl_data()
698 params->slow_mode = false; in xenon_emmc_phy_parse_param_dt()
699 if (of_property_read_bool(np, "marvell,xenon-phy-slow-mode")) in xenon_emmc_phy_parse_param_dt()
700 params->slow_mode = true; in xenon_emmc_phy_parse_param_dt()
702 params->znr = XENON_ZNR_DEF_VALUE; in xenon_emmc_phy_parse_param_dt()
703 if (!of_property_read_u32(np, "marvell,xenon-phy-znr", &value)) in xenon_emmc_phy_parse_param_dt()
704 params->znr = value & XENON_ZNR_MASK; in xenon_emmc_phy_parse_param_dt()
706 params->zpr = XENON_ZPR_DEF_VALUE; in xenon_emmc_phy_parse_param_dt()
707 if (!of_property_read_u32(np, "marvell,xenon-phy-zpr", &value)) in xenon_emmc_phy_parse_param_dt()
708 params->zpr = value & XENON_ZPR_MASK; in xenon_emmc_phy_parse_param_dt()
710 params->nr_tun_times = XENON_TUN_CONSECUTIVE_TIMES; in xenon_emmc_phy_parse_param_dt()
711 if (!of_property_read_u32(np, "marvell,xenon-phy-nr-success-tun", in xenon_emmc_phy_parse_param_dt()
713 params->nr_tun_times = value & XENON_TUN_CONSECUTIVE_TIMES_MASK; in xenon_emmc_phy_parse_param_dt()
715 params->tun_step_divider = XENON_TUNING_STEP_DIVIDER; in xenon_emmc_phy_parse_param_dt()
716 if (!of_property_read_u32(np, "marvell,xenon-phy-tun-step-divider", in xenon_emmc_phy_parse_param_dt()
718 params->tun_step_divider = value & 0xFF; in xenon_emmc_phy_parse_param_dt()
723 /* Set SoC PHY Voltage PAD */
731 * Setting PHY when card is working in High Speed Mode.
739 if (WARN_ON(host->clock <= XENON_DEFAULT_SDCLK_FREQ)) in xenon_hs_delay_adj()
740 return -EINVAL; in xenon_hs_delay_adj()
742 switch (host->timing) { in xenon_hs_delay_adj()
752 * DDR Mode requires driver to scan Sampling Fixed Delay Line, in xenon_hs_delay_adj()
756 * Thus so far just keep PHY Sampling Fixed Delay in in xenon_hs_delay_adj()
762 dev_warn_once(mmc_dev(host->mmc), "Timing issue might occur in DDR mode\n"); in xenon_hs_delay_adj()
770 * Adjust PHY setting.
771 * PHY setting should be adjusted when SDCLK frequency, Bus Width
782 if (!host->clock) { in xenon_phy_adj()
783 priv->clock = 0; in xenon_phy_adj()
789 * better to set eMMC PHY based on current setting in xenon_phy_adj()
790 * and adjust Xenon SDHC delay. in xenon_phy_adj()
792 if ((host->clock == priv->clock) && in xenon_phy_adj()
793 (ios->bus_width == priv->bus_width) && in xenon_phy_adj()
794 (ios->timing == priv->timing)) in xenon_phy_adj()
797 xenon_emmc_phy_set(host, ios->timing); in xenon_phy_adj()
800 priv->bus_width = ios->bus_width; in xenon_phy_adj()
802 priv->timing = ios->timing; in xenon_phy_adj()
803 priv->clock = host->clock; in xenon_phy_adj()
806 if (ios->timing == MMC_TIMING_LEGACY) in xenon_phy_adj()
809 if (host->clock > XENON_DEFAULT_SDCLK_FREQ) in xenon_phy_adj()
821 priv->phy_type = match_string(phy_types, NR_PHY_TYPES, phy_name); in xenon_add_phy()
822 if (priv->phy_type < 0) { in xenon_add_phy()
823 dev_err(mmc_dev(host->mmc), in xenon_add_phy()
824 "Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n", in xenon_add_phy()
826 priv->phy_type = EMMC_5_1_PHY; in xenon_add_phy()
833 return xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params); in xenon_add_phy()
840 if (!of_property_read_string(np, "marvell,xenon-phy-type", &phy_type)) in xenon_phy_parse_dt()
843 return xenon_add_phy(np, host, "emmc 5.1 phy"); in xenon_phy_parse_dt()