root/drivers/phy/broadcom/phy-bcm-sr-pcie.c

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

DEFINITIONS

This source file includes following definitions.
  1. pipemux_strap_is_valid
  2. pipemux_strap_read
  3. pcie_core_is_for_rc
  4. sr_pcie_phy_init
  5. sr_paxc_phy_init
  6. sr_pcie_phy_xlate
  7. sr_pcie_phy_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2016-2018 Broadcom
   4  */
   5 
   6 #include <linux/clk.h>
   7 #include <linux/delay.h>
   8 #include <linux/io.h>
   9 #include <linux/module.h>
  10 #include <linux/mfd/syscon.h>
  11 #include <linux/of.h>
  12 #include <linux/phy/phy.h>
  13 #include <linux/platform_device.h>
  14 #include <linux/regmap.h>
  15 
  16 /* we have up to 8 PAXB based RC. The 9th one is always PAXC */
  17 #define SR_NR_PCIE_PHYS               9
  18 #define SR_PAXC_PHY_IDX               (SR_NR_PCIE_PHYS - 1)
  19 
  20 #define PCIE_PIPEMUX_CFG_OFFSET       0x10c
  21 #define PCIE_PIPEMUX_SELECT_STRAP     0xf
  22 
  23 #define CDRU_STRAP_DATA_LSW_OFFSET    0x5c
  24 #define PCIE_PIPEMUX_SHIFT            19
  25 #define PCIE_PIPEMUX_MASK             0xf
  26 
  27 #define MHB_MEM_PW_PAXC_OFFSET        0x1c0
  28 #define MHB_PWR_ARR_POWERON           0x8
  29 #define MHB_PWR_ARR_POWEROK           0x4
  30 #define MHB_PWR_POWERON               0x2
  31 #define MHB_PWR_POWEROK               0x1
  32 #define MHB_PWR_STATUS_MASK           (MHB_PWR_ARR_POWERON | \
  33                                        MHB_PWR_ARR_POWEROK | \
  34                                        MHB_PWR_POWERON | \
  35                                        MHB_PWR_POWEROK)
  36 
  37 struct sr_pcie_phy_core;
  38 
  39 /**
  40  * struct sr_pcie_phy - Stingray PCIe PHY
  41  *
  42  * @core: pointer to the Stingray PCIe PHY core control
  43  * @index: PHY index
  44  * @phy: pointer to the kernel PHY device
  45  */
  46 struct sr_pcie_phy {
  47         struct sr_pcie_phy_core *core;
  48         unsigned int index;
  49         struct phy *phy;
  50 };
  51 
  52 /**
  53  * struct sr_pcie_phy_core - Stingray PCIe PHY core control
  54  *
  55  * @dev: pointer to device
  56  * @base: base register of PCIe SS
  57  * @cdru: regmap to the CDRU device
  58  * @mhb: regmap to the MHB device
  59  * @pipemux: pipemuex strap
  60  * @phys: array of PCIe PHYs
  61  */
  62 struct sr_pcie_phy_core {
  63         struct device *dev;
  64         void __iomem *base;
  65         struct regmap *cdru;
  66         struct regmap *mhb;
  67         u32 pipemux;
  68         struct sr_pcie_phy phys[SR_NR_PCIE_PHYS];
  69 };
  70 
  71 /*
  72  * PCIe PIPEMUX lookup table
  73  *
  74  * Each array index represents a PIPEMUX strap setting
  75  * The array element represents a bitmap where a set bit means the PCIe
  76  * core and associated serdes has been enabled as RC and is available for use
  77  */
  78 static const u8 pipemux_table[] = {
  79         /* PIPEMUX = 0, EP 1x16 */
  80         0x00,
  81         /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
  82         0x80,
  83         /* PIPEMUX = 2, EP 4x4 */
  84         0x00,
  85         /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
  86         0x81,
  87         /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
  88         0xc3,
  89         /* PIPEMUX = 5, RC 8x2, all 8 cores */
  90         0xff,
  91         /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
  92         0xcd,
  93         /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
  94         0xfd,
  95         /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
  96         0xf0,
  97         /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
  98         0xc0,
  99         /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
 100         0x42,
 101         /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
 102         0x3c,
 103         /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
 104         0xfc,
 105         /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
 106         0x4c,
 107 };
 108 
 109 /*
 110  * Return true if the strap setting is valid
 111  */
 112 static bool pipemux_strap_is_valid(u32 pipemux)
 113 {
 114         return !!(pipemux < ARRAY_SIZE(pipemux_table));
 115 }
 116 
 117 /*
 118  * Read the PCIe PIPEMUX from strap
 119  */
 120 static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
 121 {
 122         u32 pipemux;
 123 
 124         /*
 125          * Read PIPEMUX configuration register to determine the pipemux setting
 126          *
 127          * In the case when the value indicates using HW strap, fall back to
 128          * use HW strap
 129          */
 130         pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
 131         pipemux &= PCIE_PIPEMUX_MASK;
 132         if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
 133                 regmap_read(core->cdru, CDRU_STRAP_DATA_LSW_OFFSET, &pipemux);
 134                 pipemux >>= PCIE_PIPEMUX_SHIFT;
 135                 pipemux &= PCIE_PIPEMUX_MASK;
 136         }
 137 
 138         return pipemux;
 139 }
 140 
 141 /*
 142  * Given a PIPEMUX strap and PCIe core index, this function returns true if the
 143  * PCIe core needs to be enabled
 144  */
 145 static bool pcie_core_is_for_rc(struct sr_pcie_phy *phy)
 146 {
 147         struct sr_pcie_phy_core *core = phy->core;
 148         unsigned int core_idx = phy->index;
 149 
 150         return !!((pipemux_table[core->pipemux] >> core_idx) & 0x1);
 151 }
 152 
 153 static int sr_pcie_phy_init(struct phy *p)
 154 {
 155         struct sr_pcie_phy *phy = phy_get_drvdata(p);
 156 
 157         /*
 158          * Check whether this PHY is for root complex or not. If yes, return
 159          * zero so the host driver can proceed to enumeration. If not, return
 160          * an error and that will force the host driver to bail out
 161          */
 162         if (pcie_core_is_for_rc(phy))
 163                 return 0;
 164 
 165         return -ENODEV;
 166 }
 167 
 168 static int sr_paxc_phy_init(struct phy *p)
 169 {
 170         struct sr_pcie_phy *phy = phy_get_drvdata(p);
 171         struct sr_pcie_phy_core *core = phy->core;
 172         unsigned int core_idx = phy->index;
 173         u32 val;
 174 
 175         if (core_idx != SR_PAXC_PHY_IDX)
 176                 return -EINVAL;
 177 
 178         regmap_read(core->mhb, MHB_MEM_PW_PAXC_OFFSET, &val);
 179         if ((val & MHB_PWR_STATUS_MASK) != MHB_PWR_STATUS_MASK) {
 180                 dev_err(core->dev, "PAXC is not powered up\n");
 181                 return -ENODEV;
 182         }
 183 
 184         return 0;
 185 }
 186 
 187 static const struct phy_ops sr_pcie_phy_ops = {
 188         .init = sr_pcie_phy_init,
 189         .owner = THIS_MODULE,
 190 };
 191 
 192 static const struct phy_ops sr_paxc_phy_ops = {
 193         .init = sr_paxc_phy_init,
 194         .owner = THIS_MODULE,
 195 };
 196 
 197 static struct phy *sr_pcie_phy_xlate(struct device *dev,
 198                                      struct of_phandle_args *args)
 199 {
 200         struct sr_pcie_phy_core *core;
 201         int phy_idx;
 202 
 203         core = dev_get_drvdata(dev);
 204         if (!core)
 205                 return ERR_PTR(-EINVAL);
 206 
 207         phy_idx = args->args[0];
 208 
 209         if (WARN_ON(phy_idx >= SR_NR_PCIE_PHYS))
 210                 return ERR_PTR(-ENODEV);
 211 
 212         return core->phys[phy_idx].phy;
 213 }
 214 
 215 static int sr_pcie_phy_probe(struct platform_device *pdev)
 216 {
 217         struct device *dev = &pdev->dev;
 218         struct device_node *node = dev->of_node;
 219         struct sr_pcie_phy_core *core;
 220         struct resource *res;
 221         struct phy_provider *provider;
 222         unsigned int phy_idx = 0;
 223 
 224         core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
 225         if (!core)
 226                 return -ENOMEM;
 227 
 228         core->dev = dev;
 229 
 230         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 231         core->base = devm_ioremap_resource(core->dev, res);
 232         if (IS_ERR(core->base))
 233                 return PTR_ERR(core->base);
 234 
 235         core->cdru = syscon_regmap_lookup_by_phandle(node, "brcm,sr-cdru");
 236         if (IS_ERR(core->cdru)) {
 237                 dev_err(core->dev, "unable to find CDRU device\n");
 238                 return PTR_ERR(core->cdru);
 239         }
 240 
 241         core->mhb = syscon_regmap_lookup_by_phandle(node, "brcm,sr-mhb");
 242         if (IS_ERR(core->mhb)) {
 243                 dev_err(core->dev, "unable to find MHB device\n");
 244                 return PTR_ERR(core->mhb);
 245         }
 246 
 247         /* read the PCIe PIPEMUX strap setting */
 248         core->pipemux = pipemux_strap_read(core);
 249         if (!pipemux_strap_is_valid(core->pipemux)) {
 250                 dev_err(core->dev, "invalid PCIe PIPEMUX strap %u\n",
 251                         core->pipemux);
 252                 return -EIO;
 253         }
 254 
 255         for (phy_idx = 0; phy_idx < SR_NR_PCIE_PHYS; phy_idx++) {
 256                 struct sr_pcie_phy *p = &core->phys[phy_idx];
 257                 const struct phy_ops *ops;
 258 
 259                 if (phy_idx == SR_PAXC_PHY_IDX)
 260                         ops = &sr_paxc_phy_ops;
 261                 else
 262                         ops = &sr_pcie_phy_ops;
 263 
 264                 p->phy = devm_phy_create(dev, NULL, ops);
 265                 if (IS_ERR(p->phy)) {
 266                         dev_err(dev, "failed to create PCIe PHY\n");
 267                         return PTR_ERR(p->phy);
 268                 }
 269 
 270                 p->core = core;
 271                 p->index = phy_idx;
 272                 phy_set_drvdata(p->phy, p);
 273         }
 274 
 275         dev_set_drvdata(dev, core);
 276 
 277         provider = devm_of_phy_provider_register(dev, sr_pcie_phy_xlate);
 278         if (IS_ERR(provider)) {
 279                 dev_err(dev, "failed to register PHY provider\n");
 280                 return PTR_ERR(provider);
 281         }
 282 
 283         dev_info(dev, "Stingray PCIe PHY driver initialized\n");
 284 
 285         return 0;
 286 }
 287 
 288 static const struct of_device_id sr_pcie_phy_match_table[] = {
 289         { .compatible = "brcm,sr-pcie-phy" },
 290         { }
 291 };
 292 MODULE_DEVICE_TABLE(of, sr_pcie_phy_match_table);
 293 
 294 static struct platform_driver sr_pcie_phy_driver = {
 295         .driver = {
 296                 .name           = "sr-pcie-phy",
 297                 .of_match_table = sr_pcie_phy_match_table,
 298         },
 299         .probe  = sr_pcie_phy_probe,
 300 };
 301 module_platform_driver(sr_pcie_phy_driver);
 302 
 303 MODULE_AUTHOR("Ray Jui <ray.jui@broadcom.com>");
 304 MODULE_DESCRIPTION("Broadcom Stingray PCIe PHY driver");
 305 MODULE_LICENSE("GPL v2");

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