1*fa687038SWan Ahmad Zainie // SPDX-License-Identifier: GPL-2.0 2*fa687038SWan Ahmad Zainie /* 3*fa687038SWan Ahmad Zainie * Intel eMMC PHY driver 4*fa687038SWan Ahmad Zainie * Copyright (C) 2019 Intel, Corp. 5*fa687038SWan Ahmad Zainie */ 6*fa687038SWan Ahmad Zainie 7*fa687038SWan Ahmad Zainie #include <linux/bits.h> 8*fa687038SWan Ahmad Zainie #include <linux/clk.h> 9*fa687038SWan Ahmad Zainie #include <linux/delay.h> 10*fa687038SWan Ahmad Zainie #include <linux/mfd/syscon.h> 11*fa687038SWan Ahmad Zainie #include <linux/module.h> 12*fa687038SWan Ahmad Zainie #include <linux/of.h> 13*fa687038SWan Ahmad Zainie #include <linux/of_address.h> 14*fa687038SWan Ahmad Zainie #include <linux/phy/phy.h> 15*fa687038SWan Ahmad Zainie #include <linux/platform_device.h> 16*fa687038SWan Ahmad Zainie #include <linux/regmap.h> 17*fa687038SWan Ahmad Zainie 18*fa687038SWan Ahmad Zainie /* eMMC phy register definitions */ 19*fa687038SWan Ahmad Zainie #define EMMC_PHYCTRL0_REG 0xa8 20*fa687038SWan Ahmad Zainie #define DR_TY_MASK GENMASK(30, 28) 21*fa687038SWan Ahmad Zainie #define DR_TY_SHIFT(x) (((x) << 28) & DR_TY_MASK) 22*fa687038SWan Ahmad Zainie #define OTAPDLYENA BIT(14) 23*fa687038SWan Ahmad Zainie #define OTAPDLYSEL_MASK GENMASK(13, 10) 24*fa687038SWan Ahmad Zainie #define OTAPDLYSEL_SHIFT(x) (((x) << 10) & OTAPDLYSEL_MASK) 25*fa687038SWan Ahmad Zainie 26*fa687038SWan Ahmad Zainie #define EMMC_PHYCTRL1_REG 0xac 27*fa687038SWan Ahmad Zainie #define PDB_MASK BIT(0) 28*fa687038SWan Ahmad Zainie #define PDB_SHIFT(x) (((x) << 0) & PDB_MASK) 29*fa687038SWan Ahmad Zainie #define ENDLL_MASK BIT(7) 30*fa687038SWan Ahmad Zainie #define ENDLL_SHIFT(x) (((x) << 7) & ENDLL_MASK) 31*fa687038SWan Ahmad Zainie 32*fa687038SWan Ahmad Zainie #define EMMC_PHYCTRL2_REG 0xb0 33*fa687038SWan Ahmad Zainie #define FRQSEL_25M 0 34*fa687038SWan Ahmad Zainie #define FRQSEL_50M 1 35*fa687038SWan Ahmad Zainie #define FRQSEL_100M 2 36*fa687038SWan Ahmad Zainie #define FRQSEL_150M 3 37*fa687038SWan Ahmad Zainie #define FRQSEL_MASK GENMASK(24, 22) 38*fa687038SWan Ahmad Zainie #define FRQSEL_SHIFT(x) (((x) << 22) & FRQSEL_MASK) 39*fa687038SWan Ahmad Zainie 40*fa687038SWan Ahmad Zainie #define EMMC_PHYSTAT_REG 0xbc 41*fa687038SWan Ahmad Zainie #define CALDONE_MASK BIT(9) 42*fa687038SWan Ahmad Zainie #define DLLRDY_MASK BIT(8) 43*fa687038SWan Ahmad Zainie #define IS_CALDONE(x) ((x) & CALDONE_MASK) 44*fa687038SWan Ahmad Zainie #define IS_DLLRDY(x) ((x) & DLLRDY_MASK) 45*fa687038SWan Ahmad Zainie 46*fa687038SWan Ahmad Zainie struct intel_emmc_phy { 47*fa687038SWan Ahmad Zainie struct regmap *syscfg; 48*fa687038SWan Ahmad Zainie struct clk *emmcclk; 49*fa687038SWan Ahmad Zainie }; 50*fa687038SWan Ahmad Zainie 51*fa687038SWan Ahmad Zainie static int intel_emmc_phy_power(struct phy *phy, bool on_off) 52*fa687038SWan Ahmad Zainie { 53*fa687038SWan Ahmad Zainie struct intel_emmc_phy *priv = phy_get_drvdata(phy); 54*fa687038SWan Ahmad Zainie unsigned int caldone; 55*fa687038SWan Ahmad Zainie unsigned int dllrdy; 56*fa687038SWan Ahmad Zainie unsigned int freqsel; 57*fa687038SWan Ahmad Zainie unsigned long rate; 58*fa687038SWan Ahmad Zainie int ret, quot; 59*fa687038SWan Ahmad Zainie 60*fa687038SWan Ahmad Zainie /* 61*fa687038SWan Ahmad Zainie * Keep phyctrl_pdb and phyctrl_endll low to allow 62*fa687038SWan Ahmad Zainie * initialization of CALIO state M/C DFFs 63*fa687038SWan Ahmad Zainie */ 64*fa687038SWan Ahmad Zainie ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL1_REG, PDB_MASK, 65*fa687038SWan Ahmad Zainie PDB_SHIFT(0)); 66*fa687038SWan Ahmad Zainie if (ret) { 67*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "CALIO power down bar failed: %d\n", ret); 68*fa687038SWan Ahmad Zainie return ret; 69*fa687038SWan Ahmad Zainie } 70*fa687038SWan Ahmad Zainie 71*fa687038SWan Ahmad Zainie /* Already finish power_off above */ 72*fa687038SWan Ahmad Zainie if (!on_off) 73*fa687038SWan Ahmad Zainie return 0; 74*fa687038SWan Ahmad Zainie 75*fa687038SWan Ahmad Zainie rate = clk_get_rate(priv->emmcclk); 76*fa687038SWan Ahmad Zainie quot = DIV_ROUND_CLOSEST(rate, 50000000); 77*fa687038SWan Ahmad Zainie if (quot > FRQSEL_150M) 78*fa687038SWan Ahmad Zainie dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate); 79*fa687038SWan Ahmad Zainie freqsel = clamp_t(int, quot, FRQSEL_25M, FRQSEL_150M); 80*fa687038SWan Ahmad Zainie 81*fa687038SWan Ahmad Zainie /* 82*fa687038SWan Ahmad Zainie * According to the user manual, calpad calibration 83*fa687038SWan Ahmad Zainie * cycle takes more than 2us without the minimal recommended 84*fa687038SWan Ahmad Zainie * value, so we may need a little margin here 85*fa687038SWan Ahmad Zainie */ 86*fa687038SWan Ahmad Zainie udelay(5); 87*fa687038SWan Ahmad Zainie 88*fa687038SWan Ahmad Zainie ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL1_REG, PDB_MASK, 89*fa687038SWan Ahmad Zainie PDB_SHIFT(1)); 90*fa687038SWan Ahmad Zainie if (ret) { 91*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "CALIO power down bar failed: %d\n", ret); 92*fa687038SWan Ahmad Zainie return ret; 93*fa687038SWan Ahmad Zainie } 94*fa687038SWan Ahmad Zainie 95*fa687038SWan Ahmad Zainie /* 96*fa687038SWan Ahmad Zainie * According to the user manual, it asks driver to wait 5us for 97*fa687038SWan Ahmad Zainie * calpad busy trimming. However it is documented that this value is 98*fa687038SWan Ahmad Zainie * PVT(A.K.A process,voltage and temperature) relevant, so some 99*fa687038SWan Ahmad Zainie * failure cases are found which indicates we should be more tolerant 100*fa687038SWan Ahmad Zainie * to calpad busy trimming. 101*fa687038SWan Ahmad Zainie */ 102*fa687038SWan Ahmad Zainie ret = regmap_read_poll_timeout(priv->syscfg, EMMC_PHYSTAT_REG, 103*fa687038SWan Ahmad Zainie caldone, IS_CALDONE(caldone), 104*fa687038SWan Ahmad Zainie 0, 50); 105*fa687038SWan Ahmad Zainie if (ret) { 106*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "caldone failed, ret=%d\n", ret); 107*fa687038SWan Ahmad Zainie return ret; 108*fa687038SWan Ahmad Zainie } 109*fa687038SWan Ahmad Zainie 110*fa687038SWan Ahmad Zainie /* Set the frequency of the DLL operation */ 111*fa687038SWan Ahmad Zainie ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL2_REG, FRQSEL_MASK, 112*fa687038SWan Ahmad Zainie FRQSEL_SHIFT(freqsel)); 113*fa687038SWan Ahmad Zainie if (ret) { 114*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "set the frequency of dll failed:%d\n", ret); 115*fa687038SWan Ahmad Zainie return ret; 116*fa687038SWan Ahmad Zainie } 117*fa687038SWan Ahmad Zainie 118*fa687038SWan Ahmad Zainie /* Turn on the DLL */ 119*fa687038SWan Ahmad Zainie ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL1_REG, ENDLL_MASK, 120*fa687038SWan Ahmad Zainie ENDLL_SHIFT(1)); 121*fa687038SWan Ahmad Zainie if (ret) { 122*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "turn on the dll failed: %d\n", ret); 123*fa687038SWan Ahmad Zainie return ret; 124*fa687038SWan Ahmad Zainie } 125*fa687038SWan Ahmad Zainie 126*fa687038SWan Ahmad Zainie /* 127*fa687038SWan Ahmad Zainie * After enabling analog DLL circuits docs say that we need 10.2 us if 128*fa687038SWan Ahmad Zainie * our source clock is at 50 MHz and that lock time scales linearly 129*fa687038SWan Ahmad Zainie * with clock speed. If we are powering on the PHY and the card clock 130*fa687038SWan Ahmad Zainie * is super slow (like 100 kHZ) this could take as long as 5.1 ms as 131*fa687038SWan Ahmad Zainie * per the math: 10.2 us * (50000000 Hz / 100000 Hz) => 5.1 ms 132*fa687038SWan Ahmad Zainie * Hopefully we won't be running at 100 kHz, but we should still make 133*fa687038SWan Ahmad Zainie * sure we wait long enough. 134*fa687038SWan Ahmad Zainie * 135*fa687038SWan Ahmad Zainie * NOTE: There appear to be corner cases where the DLL seems to take 136*fa687038SWan Ahmad Zainie * extra long to lock for reasons that aren't understood. In some 137*fa687038SWan Ahmad Zainie * extreme cases we've seen it take up to over 10ms (!). We'll be 138*fa687038SWan Ahmad Zainie * generous and give it 50ms. 139*fa687038SWan Ahmad Zainie */ 140*fa687038SWan Ahmad Zainie ret = regmap_read_poll_timeout(priv->syscfg, 141*fa687038SWan Ahmad Zainie EMMC_PHYSTAT_REG, 142*fa687038SWan Ahmad Zainie dllrdy, IS_DLLRDY(dllrdy), 143*fa687038SWan Ahmad Zainie 0, 50 * USEC_PER_MSEC); 144*fa687038SWan Ahmad Zainie if (ret) { 145*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "dllrdy failed. ret=%d\n", ret); 146*fa687038SWan Ahmad Zainie return ret; 147*fa687038SWan Ahmad Zainie } 148*fa687038SWan Ahmad Zainie 149*fa687038SWan Ahmad Zainie return 0; 150*fa687038SWan Ahmad Zainie } 151*fa687038SWan Ahmad Zainie 152*fa687038SWan Ahmad Zainie static int intel_emmc_phy_init(struct phy *phy) 153*fa687038SWan Ahmad Zainie { 154*fa687038SWan Ahmad Zainie struct intel_emmc_phy *priv = phy_get_drvdata(phy); 155*fa687038SWan Ahmad Zainie 156*fa687038SWan Ahmad Zainie /* 157*fa687038SWan Ahmad Zainie * We purposely get the clock here and not in probe to avoid the 158*fa687038SWan Ahmad Zainie * circular dependency problem. We expect: 159*fa687038SWan Ahmad Zainie * - PHY driver to probe 160*fa687038SWan Ahmad Zainie * - SDHCI driver to start probe 161*fa687038SWan Ahmad Zainie * - SDHCI driver to register it's clock 162*fa687038SWan Ahmad Zainie * - SDHCI driver to get the PHY 163*fa687038SWan Ahmad Zainie * - SDHCI driver to init the PHY 164*fa687038SWan Ahmad Zainie * 165*fa687038SWan Ahmad Zainie * The clock is optional, so upon any error just return it like 166*fa687038SWan Ahmad Zainie * any other error to user. 167*fa687038SWan Ahmad Zainie * 168*fa687038SWan Ahmad Zainie */ 169*fa687038SWan Ahmad Zainie priv->emmcclk = clk_get_optional(&phy->dev, "emmcclk"); 170*fa687038SWan Ahmad Zainie if (IS_ERR(priv->emmcclk)) { 171*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "ERROR: getting emmcclk\n"); 172*fa687038SWan Ahmad Zainie return PTR_ERR(priv->emmcclk); 173*fa687038SWan Ahmad Zainie } 174*fa687038SWan Ahmad Zainie 175*fa687038SWan Ahmad Zainie return 0; 176*fa687038SWan Ahmad Zainie } 177*fa687038SWan Ahmad Zainie 178*fa687038SWan Ahmad Zainie static int intel_emmc_phy_exit(struct phy *phy) 179*fa687038SWan Ahmad Zainie { 180*fa687038SWan Ahmad Zainie struct intel_emmc_phy *priv = phy_get_drvdata(phy); 181*fa687038SWan Ahmad Zainie 182*fa687038SWan Ahmad Zainie clk_put(priv->emmcclk); 183*fa687038SWan Ahmad Zainie 184*fa687038SWan Ahmad Zainie return 0; 185*fa687038SWan Ahmad Zainie } 186*fa687038SWan Ahmad Zainie 187*fa687038SWan Ahmad Zainie static int intel_emmc_phy_power_on(struct phy *phy) 188*fa687038SWan Ahmad Zainie { 189*fa687038SWan Ahmad Zainie struct intel_emmc_phy *priv = phy_get_drvdata(phy); 190*fa687038SWan Ahmad Zainie int ret; 191*fa687038SWan Ahmad Zainie 192*fa687038SWan Ahmad Zainie /* Drive impedance: 50 Ohm */ 193*fa687038SWan Ahmad Zainie ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL0_REG, DR_TY_MASK, 194*fa687038SWan Ahmad Zainie DR_TY_SHIFT(6)); 195*fa687038SWan Ahmad Zainie if (ret) { 196*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "ERROR set drive-impednce-50ohm: %d\n", ret); 197*fa687038SWan Ahmad Zainie return ret; 198*fa687038SWan Ahmad Zainie } 199*fa687038SWan Ahmad Zainie 200*fa687038SWan Ahmad Zainie /* Output tap delay: disable */ 201*fa687038SWan Ahmad Zainie ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL0_REG, OTAPDLYENA, 202*fa687038SWan Ahmad Zainie 0); 203*fa687038SWan Ahmad Zainie if (ret) { 204*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "ERROR Set output tap delay : %d\n", ret); 205*fa687038SWan Ahmad Zainie return ret; 206*fa687038SWan Ahmad Zainie } 207*fa687038SWan Ahmad Zainie 208*fa687038SWan Ahmad Zainie /* Output tap delay */ 209*fa687038SWan Ahmad Zainie ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL0_REG, 210*fa687038SWan Ahmad Zainie OTAPDLYSEL_MASK, OTAPDLYSEL_SHIFT(4)); 211*fa687038SWan Ahmad Zainie if (ret) { 212*fa687038SWan Ahmad Zainie dev_err(&phy->dev, "ERROR: output tap dly select: %d\n", ret); 213*fa687038SWan Ahmad Zainie return ret; 214*fa687038SWan Ahmad Zainie } 215*fa687038SWan Ahmad Zainie 216*fa687038SWan Ahmad Zainie /* Power up eMMC phy analog blocks */ 217*fa687038SWan Ahmad Zainie return intel_emmc_phy_power(phy, true); 218*fa687038SWan Ahmad Zainie } 219*fa687038SWan Ahmad Zainie 220*fa687038SWan Ahmad Zainie static int intel_emmc_phy_power_off(struct phy *phy) 221*fa687038SWan Ahmad Zainie { 222*fa687038SWan Ahmad Zainie /* Power down eMMC phy analog blocks */ 223*fa687038SWan Ahmad Zainie return intel_emmc_phy_power(phy, false); 224*fa687038SWan Ahmad Zainie } 225*fa687038SWan Ahmad Zainie 226*fa687038SWan Ahmad Zainie static const struct phy_ops ops = { 227*fa687038SWan Ahmad Zainie .init = intel_emmc_phy_init, 228*fa687038SWan Ahmad Zainie .exit = intel_emmc_phy_exit, 229*fa687038SWan Ahmad Zainie .power_on = intel_emmc_phy_power_on, 230*fa687038SWan Ahmad Zainie .power_off = intel_emmc_phy_power_off, 231*fa687038SWan Ahmad Zainie .owner = THIS_MODULE, 232*fa687038SWan Ahmad Zainie }; 233*fa687038SWan Ahmad Zainie 234*fa687038SWan Ahmad Zainie static int intel_emmc_phy_probe(struct platform_device *pdev) 235*fa687038SWan Ahmad Zainie { 236*fa687038SWan Ahmad Zainie struct device *dev = &pdev->dev; 237*fa687038SWan Ahmad Zainie struct device_node *np = dev->of_node; 238*fa687038SWan Ahmad Zainie struct intel_emmc_phy *priv; 239*fa687038SWan Ahmad Zainie struct phy *generic_phy; 240*fa687038SWan Ahmad Zainie struct phy_provider *phy_provider; 241*fa687038SWan Ahmad Zainie 242*fa687038SWan Ahmad Zainie priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 243*fa687038SWan Ahmad Zainie if (!priv) 244*fa687038SWan Ahmad Zainie return -ENOMEM; 245*fa687038SWan Ahmad Zainie 246*fa687038SWan Ahmad Zainie /* Get eMMC phy (accessed via chiptop) regmap */ 247*fa687038SWan Ahmad Zainie priv->syscfg = syscon_regmap_lookup_by_phandle(np, "intel,syscon"); 248*fa687038SWan Ahmad Zainie if (IS_ERR(priv->syscfg)) { 249*fa687038SWan Ahmad Zainie dev_err(dev, "failed to find syscon\n"); 250*fa687038SWan Ahmad Zainie return PTR_ERR(priv->syscfg); 251*fa687038SWan Ahmad Zainie } 252*fa687038SWan Ahmad Zainie 253*fa687038SWan Ahmad Zainie generic_phy = devm_phy_create(dev, np, &ops); 254*fa687038SWan Ahmad Zainie if (IS_ERR(generic_phy)) { 255*fa687038SWan Ahmad Zainie dev_err(dev, "failed to create PHY\n"); 256*fa687038SWan Ahmad Zainie return PTR_ERR(generic_phy); 257*fa687038SWan Ahmad Zainie } 258*fa687038SWan Ahmad Zainie 259*fa687038SWan Ahmad Zainie phy_set_drvdata(generic_phy, priv); 260*fa687038SWan Ahmad Zainie phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 261*fa687038SWan Ahmad Zainie 262*fa687038SWan Ahmad Zainie return PTR_ERR_OR_ZERO(phy_provider); 263*fa687038SWan Ahmad Zainie } 264*fa687038SWan Ahmad Zainie 265*fa687038SWan Ahmad Zainie static const struct of_device_id intel_emmc_phy_dt_ids[] = { 266*fa687038SWan Ahmad Zainie { .compatible = "intel,lgm-emmc-phy" }, 267*fa687038SWan Ahmad Zainie {} 268*fa687038SWan Ahmad Zainie }; 269*fa687038SWan Ahmad Zainie 270*fa687038SWan Ahmad Zainie MODULE_DEVICE_TABLE(of, intel_emmc_phy_dt_ids); 271*fa687038SWan Ahmad Zainie 272*fa687038SWan Ahmad Zainie static struct platform_driver intel_emmc_driver = { 273*fa687038SWan Ahmad Zainie .probe = intel_emmc_phy_probe, 274*fa687038SWan Ahmad Zainie .driver = { 275*fa687038SWan Ahmad Zainie .name = "intel-emmc-phy", 276*fa687038SWan Ahmad Zainie .of_match_table = intel_emmc_phy_dt_ids, 277*fa687038SWan Ahmad Zainie }, 278*fa687038SWan Ahmad Zainie }; 279*fa687038SWan Ahmad Zainie 280*fa687038SWan Ahmad Zainie module_platform_driver(intel_emmc_driver); 281*fa687038SWan Ahmad Zainie 282*fa687038SWan Ahmad Zainie MODULE_AUTHOR("Peter Harliman Liem <peter.harliman.liem@intel.com>"); 283*fa687038SWan Ahmad Zainie MODULE_DESCRIPTION("Intel eMMC PHY driver"); 284*fa687038SWan Ahmad Zainie MODULE_LICENSE("GPL v2"); 285