root/drivers/phy/qualcomm/phy-qcom-pcie2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qcom_pcie2_phy_init
  2. qcom_pcie2_phy_power_on
  3. qcom_pcie2_phy_power_off
  4. qcom_pcie2_phy_exit
  5. phy_pipe_clksrc_register
  6. qcom_pcie2_phy_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
   4  * Copyright (c) 2019, Linaro Ltd.
   5  */
   6 
   7 #include <linux/clk-provider.h>
   8 #include <linux/clk.h>
   9 #include <linux/iopoll.h>
  10 #include <linux/module.h>
  11 #include <linux/phy/phy.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/reset.h>
  14 #include <linux/slab.h>
  15 
  16 #include <dt-bindings/phy/phy.h>
  17 
  18 #define PCIE20_PARF_PHY_STTS         0x3c
  19 #define PCIE2_PHY_RESET_CTRL         0x44
  20 #define PCIE20_PARF_PHY_REFCLK_CTRL2 0xa0
  21 #define PCIE20_PARF_PHY_REFCLK_CTRL3 0xa4
  22 #define PCIE20_PARF_PCS_SWING_CTRL1  0x88
  23 #define PCIE20_PARF_PCS_SWING_CTRL2  0x8c
  24 #define PCIE20_PARF_PCS_DEEMPH1      0x74
  25 #define PCIE20_PARF_PCS_DEEMPH2      0x78
  26 #define PCIE20_PARF_PCS_DEEMPH3      0x7c
  27 #define PCIE20_PARF_CONFIGBITS       0x84
  28 #define PCIE20_PARF_PHY_CTRL3        0x94
  29 #define PCIE20_PARF_PCS_CTRL         0x80
  30 
  31 #define TX_AMP_VAL                   120
  32 #define PHY_RX0_EQ_GEN1_VAL          0
  33 #define PHY_RX0_EQ_GEN2_VAL          4
  34 #define TX_DEEMPH_GEN1_VAL           24
  35 #define TX_DEEMPH_GEN2_3_5DB_VAL     26
  36 #define TX_DEEMPH_GEN2_6DB_VAL       36
  37 #define PHY_TX0_TERM_OFFST_VAL       0
  38 
  39 struct qcom_phy {
  40         struct device *dev;
  41         void __iomem *base;
  42 
  43         struct regulator_bulk_data vregs[2];
  44 
  45         struct reset_control *phy_reset;
  46         struct reset_control *pipe_reset;
  47         struct clk *pipe_clk;
  48 };
  49 
  50 static int qcom_pcie2_phy_init(struct phy *phy)
  51 {
  52         struct qcom_phy *qphy = phy_get_drvdata(phy);
  53         int ret;
  54 
  55         ret = reset_control_deassert(qphy->phy_reset);
  56         if (ret) {
  57                 dev_err(qphy->dev, "cannot deassert pipe reset\n");
  58                 return ret;
  59         }
  60 
  61         ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
  62         if (ret)
  63                 reset_control_assert(qphy->phy_reset);
  64 
  65         return ret;
  66 }
  67 
  68 static int qcom_pcie2_phy_power_on(struct phy *phy)
  69 {
  70         struct qcom_phy *qphy = phy_get_drvdata(phy);
  71         int ret;
  72         u32 val;
  73 
  74         /* Program REF_CLK source */
  75         val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
  76         val &= ~BIT(1);
  77         writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
  78 
  79         usleep_range(1000, 2000);
  80 
  81         /* Don't use PAD for refclock */
  82         val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
  83         val &= ~BIT(0);
  84         writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
  85 
  86         /* Program SSP ENABLE */
  87         val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
  88         val |= BIT(0);
  89         writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
  90 
  91         usleep_range(1000, 2000);
  92 
  93         /* Assert Phy SW Reset */
  94         val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
  95         val |= BIT(0);
  96         writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
  97 
  98         /* Program Tx Amplitude */
  99         val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
 100         val &= ~0x7f;
 101         val |= TX_AMP_VAL;
 102         writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
 103 
 104         val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
 105         val &= ~0x7f;
 106         val |= TX_AMP_VAL;
 107         writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
 108 
 109         /* Program De-Emphasis */
 110         val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH1);
 111         val &= ~0x3f;
 112         val |= TX_DEEMPH_GEN2_6DB_VAL;
 113         writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH1);
 114 
 115         val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH2);
 116         val &= ~0x3f;
 117         val |= TX_DEEMPH_GEN2_3_5DB_VAL;
 118         writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH2);
 119 
 120         val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH3);
 121         val &= ~0x3f;
 122         val |= TX_DEEMPH_GEN1_VAL;
 123         writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH3);
 124 
 125         /* Program Rx_Eq */
 126         val = readl(qphy->base + PCIE20_PARF_CONFIGBITS);
 127         val &= ~0x7;
 128         val |= PHY_RX0_EQ_GEN2_VAL;
 129         writel(val, qphy->base + PCIE20_PARF_CONFIGBITS);
 130 
 131         /* Program Tx0_term_offset */
 132         val = readl(qphy->base + PCIE20_PARF_PHY_CTRL3);
 133         val &= ~0x1f;
 134         val |= PHY_TX0_TERM_OFFST_VAL;
 135         writel(val, qphy->base + PCIE20_PARF_PHY_CTRL3);
 136 
 137         /* disable Tx2Rx Loopback */
 138         val = readl(qphy->base + PCIE20_PARF_PCS_CTRL);
 139         val &= ~BIT(1);
 140         writel(val, qphy->base + PCIE20_PARF_PCS_CTRL);
 141 
 142         /* De-assert Phy SW Reset */
 143         val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
 144         val &= ~BIT(0);
 145         writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
 146 
 147         usleep_range(1000, 2000);
 148 
 149         ret = reset_control_deassert(qphy->pipe_reset);
 150         if (ret) {
 151                 dev_err(qphy->dev, "cannot deassert pipe reset\n");
 152                 goto out;
 153         }
 154 
 155         clk_set_rate(qphy->pipe_clk, 250000000);
 156 
 157         ret = clk_prepare_enable(qphy->pipe_clk);
 158         if (ret) {
 159                 dev_err(qphy->dev, "failed to enable pipe clock\n");
 160                 goto out;
 161         }
 162 
 163         ret = readl_poll_timeout(qphy->base + PCIE20_PARF_PHY_STTS, val,
 164                                  !(val & BIT(0)), 1000, 10);
 165         if (ret)
 166                 dev_err(qphy->dev, "phy initialization failed\n");
 167 
 168 out:
 169         return ret;
 170 }
 171 
 172 static int qcom_pcie2_phy_power_off(struct phy *phy)
 173 {
 174         struct qcom_phy *qphy = phy_get_drvdata(phy);
 175         u32 val;
 176 
 177         val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
 178         val |= BIT(0);
 179         writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
 180 
 181         clk_disable_unprepare(qphy->pipe_clk);
 182         reset_control_assert(qphy->pipe_reset);
 183 
 184         return 0;
 185 }
 186 
 187 static int qcom_pcie2_phy_exit(struct phy *phy)
 188 {
 189         struct qcom_phy *qphy = phy_get_drvdata(phy);
 190 
 191         regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
 192         reset_control_assert(qphy->phy_reset);
 193 
 194         return 0;
 195 }
 196 
 197 static const struct phy_ops qcom_pcie2_ops = {
 198         .init = qcom_pcie2_phy_init,
 199         .power_on = qcom_pcie2_phy_power_on,
 200         .power_off = qcom_pcie2_phy_power_off,
 201         .exit = qcom_pcie2_phy_exit,
 202         .owner = THIS_MODULE,
 203 };
 204 
 205 /*
 206  * Register a fixed rate pipe clock.
 207  *
 208  * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
 209  * controls it. The <s>_pipe_clk coming out of the GCC is requested
 210  * by the PHY driver for its operations.
 211  * We register the <s>_pipe_clksrc here. The gcc driver takes care
 212  * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
 213  * Below picture shows this relationship.
 214  *
 215  *         +---------------+
 216  *         |   PHY block   |<<---------------------------------------+
 217  *         |               |                                         |
 218  *         |   +-------+   |                   +-----+               |
 219  *   I/P---^-->|  PLL  |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
 220  *    clk  |   +-------+   |                   +-----+
 221  *         +---------------+
 222  */
 223 static int phy_pipe_clksrc_register(struct qcom_phy *qphy)
 224 {
 225         struct device_node *np = qphy->dev->of_node;
 226         struct clk_fixed_rate *fixed;
 227         struct clk_init_data init = { };
 228         int ret;
 229 
 230         ret = of_property_read_string(np, "clock-output-names", &init.name);
 231         if (ret) {
 232                 dev_err(qphy->dev, "%s: No clock-output-names\n", np->name);
 233                 return ret;
 234         }
 235 
 236         fixed = devm_kzalloc(qphy->dev, sizeof(*fixed), GFP_KERNEL);
 237         if (!fixed)
 238                 return -ENOMEM;
 239 
 240         init.ops = &clk_fixed_rate_ops;
 241 
 242         /* controllers using QMP phys use 250MHz pipe clock interface */
 243         fixed->fixed_rate = 250000000;
 244         fixed->hw.init = &init;
 245 
 246         return devm_clk_hw_register(qphy->dev, &fixed->hw);
 247 }
 248 
 249 static int qcom_pcie2_phy_probe(struct platform_device *pdev)
 250 {
 251         struct phy_provider *phy_provider;
 252         struct qcom_phy *qphy;
 253         struct resource *res;
 254         struct device *dev = &pdev->dev;
 255         struct phy *phy;
 256         int ret;
 257 
 258         qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
 259         if (!qphy)
 260                 return -ENOMEM;
 261 
 262         qphy->dev = dev;
 263 
 264         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 265         qphy->base = devm_ioremap_resource(dev, res);
 266         if (IS_ERR(qphy->base))
 267                 return PTR_ERR(qphy->base);
 268 
 269         ret = phy_pipe_clksrc_register(qphy);
 270         if (ret) {
 271                 dev_err(dev, "failed to register pipe_clk\n");
 272                 return ret;
 273         }
 274 
 275         qphy->vregs[0].supply = "vdda-vp";
 276         qphy->vregs[1].supply = "vdda-vph";
 277         ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(qphy->vregs), qphy->vregs);
 278         if (ret < 0)
 279                 return ret;
 280 
 281         qphy->pipe_clk = devm_clk_get(dev, NULL);
 282         if (IS_ERR(qphy->pipe_clk)) {
 283                 dev_err(dev, "failed to acquire pipe clock\n");
 284                 return PTR_ERR(qphy->pipe_clk);
 285         }
 286 
 287         qphy->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
 288         if (IS_ERR(qphy->phy_reset)) {
 289                 dev_err(dev, "failed to acquire phy reset\n");
 290                 return PTR_ERR(qphy->phy_reset);
 291         }
 292 
 293         qphy->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
 294         if (IS_ERR(qphy->pipe_reset)) {
 295                 dev_err(dev, "failed to acquire pipe reset\n");
 296                 return PTR_ERR(qphy->pipe_reset);
 297         }
 298 
 299         phy = devm_phy_create(dev, dev->of_node, &qcom_pcie2_ops);
 300         if (IS_ERR(phy)) {
 301                 dev_err(dev, "failed to create phy\n");
 302                 return PTR_ERR(phy);
 303         }
 304 
 305         phy_set_drvdata(phy, qphy);
 306 
 307         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 308         if (IS_ERR(phy_provider))
 309                 dev_err(dev, "failed to register phy provider\n");
 310 
 311         return PTR_ERR_OR_ZERO(phy_provider);
 312 }
 313 
 314 static const struct of_device_id qcom_pcie2_phy_match_table[] = {
 315         { .compatible = "qcom,pcie2-phy" },
 316         {}
 317 };
 318 MODULE_DEVICE_TABLE(of, qcom_pcie2_phy_match_table);
 319 
 320 static struct platform_driver qcom_pcie2_phy_driver = {
 321         .probe = qcom_pcie2_phy_probe,
 322         .driver = {
 323                 .name = "phy-qcom-pcie2",
 324                 .of_match_table = qcom_pcie2_phy_match_table,
 325         },
 326 };
 327 
 328 module_platform_driver(qcom_pcie2_phy_driver);
 329 
 330 MODULE_DESCRIPTION("Qualcomm PCIe PHY driver");
 331 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */