root/drivers/phy/socionext/phy-uniphier-pcie.c

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

DEFINITIONS

This source file includes following definitions.
  1. uniphier_pciephy_testio_write
  2. uniphier_pciephy_set_param
  3. uniphier_pciephy_assert
  4. uniphier_pciephy_deassert
  5. uniphier_pciephy_init
  6. uniphier_pciephy_exit
  7. uniphier_pciephy_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller
   4  * Copyright 2018, Socionext Inc.
   5  * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
   6  */
   7 
   8 #include <linux/bitops.h>
   9 #include <linux/bitfield.h>
  10 #include <linux/clk.h>
  11 #include <linux/iopoll.h>
  12 #include <linux/mfd/syscon.h>
  13 #include <linux/module.h>
  14 #include <linux/of_device.h>
  15 #include <linux/phy/phy.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/regmap.h>
  18 #include <linux/reset.h>
  19 #include <linux/resource.h>
  20 
  21 /* PHY */
  22 #define PCL_PHY_TEST_I          0x2000
  23 #define PCL_PHY_TEST_O          0x2004
  24 #define TESTI_DAT_MASK          GENMASK(13, 6)
  25 #define TESTI_ADR_MASK          GENMASK(5, 1)
  26 #define TESTI_WR_EN             BIT(0)
  27 
  28 #define PCL_PHY_RESET           0x200c
  29 #define PCL_PHY_RESET_N_MNMODE  BIT(8)  /* =1:manual */
  30 #define PCL_PHY_RESET_N         BIT(0)  /* =1:deasssert */
  31 
  32 /* SG */
  33 #define SG_USBPCIESEL           0x590
  34 #define SG_USBPCIESEL_PCIE      BIT(0)
  35 
  36 #define PCL_PHY_R00             0
  37 #define   RX_EQ_ADJ_EN          BIT(3)          /* enable for EQ adjustment */
  38 #define PCL_PHY_R06             6
  39 #define   RX_EQ_ADJ             GENMASK(5, 0)   /* EQ adjustment value */
  40 #define   RX_EQ_ADJ_VAL         0
  41 #define PCL_PHY_R26             26
  42 #define   VCO_CTRL              GENMASK(7, 4)   /* Tx VCO adjustment value */
  43 #define   VCO_CTRL_INIT_VAL     5
  44 
  45 struct uniphier_pciephy_priv {
  46         void __iomem *base;
  47         struct device *dev;
  48         struct clk *clk;
  49         struct reset_control *rst;
  50         const struct uniphier_pciephy_soc_data *data;
  51 };
  52 
  53 struct uniphier_pciephy_soc_data {
  54         bool has_syscon;
  55 };
  56 
  57 static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv,
  58                                           u32 data)
  59 {
  60         /* need to read TESTO twice after accessing TESTI */
  61         writel(data, priv->base + PCL_PHY_TEST_I);
  62         readl(priv->base + PCL_PHY_TEST_O);
  63         readl(priv->base + PCL_PHY_TEST_O);
  64 }
  65 
  66 static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv,
  67                                        u32 reg, u32 mask, u32 param)
  68 {
  69         u32 val;
  70 
  71         /* read previous data */
  72         val  = FIELD_PREP(TESTI_DAT_MASK, 1);
  73         val |= FIELD_PREP(TESTI_ADR_MASK, reg);
  74         uniphier_pciephy_testio_write(priv, val);
  75         val = readl(priv->base + PCL_PHY_TEST_O);
  76 
  77         /* update value */
  78         val &= ~FIELD_PREP(TESTI_DAT_MASK, mask);
  79         val  = FIELD_PREP(TESTI_DAT_MASK, mask & param);
  80         val |= FIELD_PREP(TESTI_ADR_MASK, reg);
  81         uniphier_pciephy_testio_write(priv, val);
  82         uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN);
  83         uniphier_pciephy_testio_write(priv, val);
  84 
  85         /* read current data as dummy */
  86         val  = FIELD_PREP(TESTI_DAT_MASK, 1);
  87         val |= FIELD_PREP(TESTI_ADR_MASK, reg);
  88         uniphier_pciephy_testio_write(priv, val);
  89         readl(priv->base + PCL_PHY_TEST_O);
  90 }
  91 
  92 static void uniphier_pciephy_assert(struct uniphier_pciephy_priv *priv)
  93 {
  94         u32 val;
  95 
  96         val = readl(priv->base + PCL_PHY_RESET);
  97         val &= ~PCL_PHY_RESET_N;
  98         val |= PCL_PHY_RESET_N_MNMODE;
  99         writel(val, priv->base + PCL_PHY_RESET);
 100 }
 101 
 102 static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv)
 103 {
 104         u32 val;
 105 
 106         val = readl(priv->base + PCL_PHY_RESET);
 107         val |= PCL_PHY_RESET_N_MNMODE | PCL_PHY_RESET_N;
 108         writel(val, priv->base + PCL_PHY_RESET);
 109 }
 110 
 111 static int uniphier_pciephy_init(struct phy *phy)
 112 {
 113         struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
 114         int ret;
 115 
 116         ret = clk_prepare_enable(priv->clk);
 117         if (ret)
 118                 return ret;
 119 
 120         ret = reset_control_deassert(priv->rst);
 121         if (ret)
 122                 goto out_clk_disable;
 123 
 124         uniphier_pciephy_set_param(priv, PCL_PHY_R00,
 125                                    RX_EQ_ADJ_EN, RX_EQ_ADJ_EN);
 126         uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ,
 127                                    FIELD_PREP(RX_EQ_ADJ, RX_EQ_ADJ_VAL));
 128         uniphier_pciephy_set_param(priv, PCL_PHY_R26, VCO_CTRL,
 129                                    FIELD_PREP(VCO_CTRL, VCO_CTRL_INIT_VAL));
 130         usleep_range(1, 10);
 131 
 132         uniphier_pciephy_deassert(priv);
 133         usleep_range(1, 10);
 134 
 135         return 0;
 136 
 137 out_clk_disable:
 138         clk_disable_unprepare(priv->clk);
 139 
 140         return ret;
 141 }
 142 
 143 static int uniphier_pciephy_exit(struct phy *phy)
 144 {
 145         struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
 146 
 147         uniphier_pciephy_assert(priv);
 148         reset_control_assert(priv->rst);
 149         clk_disable_unprepare(priv->clk);
 150 
 151         return 0;
 152 }
 153 
 154 static const struct phy_ops uniphier_pciephy_ops = {
 155         .init  = uniphier_pciephy_init,
 156         .exit  = uniphier_pciephy_exit,
 157         .owner = THIS_MODULE,
 158 };
 159 
 160 static int uniphier_pciephy_probe(struct platform_device *pdev)
 161 {
 162         struct uniphier_pciephy_priv *priv;
 163         struct phy_provider *phy_provider;
 164         struct device *dev = &pdev->dev;
 165         struct regmap *regmap;
 166         struct resource *res;
 167         struct phy *phy;
 168 
 169         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 170         if (!priv)
 171                 return -ENOMEM;
 172 
 173         priv->data = of_device_get_match_data(dev);
 174         if (WARN_ON(!priv->data))
 175                 return -EINVAL;
 176 
 177         priv->dev = dev;
 178 
 179         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 180         priv->base = devm_ioremap_resource(dev, res);
 181         if (IS_ERR(priv->base))
 182                 return PTR_ERR(priv->base);
 183 
 184         priv->clk = devm_clk_get(dev, NULL);
 185         if (IS_ERR(priv->clk))
 186                 return PTR_ERR(priv->clk);
 187 
 188         priv->rst = devm_reset_control_get_shared(dev, NULL);
 189         if (IS_ERR(priv->rst))
 190                 return PTR_ERR(priv->rst);
 191 
 192         phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops);
 193         if (IS_ERR(phy))
 194                 return PTR_ERR(phy);
 195 
 196         regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
 197                                                  "socionext,syscon");
 198         if (!IS_ERR(regmap) && priv->data->has_syscon)
 199                 regmap_update_bits(regmap, SG_USBPCIESEL,
 200                                    SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
 201 
 202         phy_set_drvdata(phy, priv);
 203         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 204 
 205         return PTR_ERR_OR_ZERO(phy_provider);
 206 }
 207 
 208 static const struct uniphier_pciephy_soc_data uniphier_ld20_data = {
 209         .has_syscon = true,
 210 };
 211 
 212 static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = {
 213         .has_syscon = false,
 214 };
 215 
 216 static const struct of_device_id uniphier_pciephy_match[] = {
 217         {
 218                 .compatible = "socionext,uniphier-ld20-pcie-phy",
 219                 .data = &uniphier_ld20_data,
 220         },
 221         {
 222                 .compatible = "socionext,uniphier-pxs3-pcie-phy",
 223                 .data = &uniphier_pxs3_data,
 224         },
 225         { /* sentinel */ },
 226 };
 227 MODULE_DEVICE_TABLE(of, uniphier_pciephy_match);
 228 
 229 static struct platform_driver uniphier_pciephy_driver = {
 230         .probe = uniphier_pciephy_probe,
 231         .driver = {
 232                 .name = "uniphier-pcie-phy",
 233                 .of_match_table = uniphier_pciephy_match,
 234         },
 235 };
 236 module_platform_driver(uniphier_pciephy_driver);
 237 
 238 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
 239 MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller");
 240 MODULE_LICENSE("GPL v2");

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