0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <linux/delay.h>
0008 #include <linux/io.h>
0009 #include <linux/module.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/of.h>
0012 #include <linux/phy/phy.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/regmap.h>
0015
0016
0017 #define SR_NR_PCIE_PHYS 9
0018 #define SR_PAXC_PHY_IDX (SR_NR_PCIE_PHYS - 1)
0019
0020 #define PCIE_PIPEMUX_CFG_OFFSET 0x10c
0021 #define PCIE_PIPEMUX_SELECT_STRAP 0xf
0022
0023 #define CDRU_STRAP_DATA_LSW_OFFSET 0x5c
0024 #define PCIE_PIPEMUX_SHIFT 19
0025 #define PCIE_PIPEMUX_MASK 0xf
0026
0027 #define MHB_MEM_PW_PAXC_OFFSET 0x1c0
0028 #define MHB_PWR_ARR_POWERON 0x8
0029 #define MHB_PWR_ARR_POWEROK 0x4
0030 #define MHB_PWR_POWERON 0x2
0031 #define MHB_PWR_POWEROK 0x1
0032 #define MHB_PWR_STATUS_MASK (MHB_PWR_ARR_POWERON | \
0033 MHB_PWR_ARR_POWEROK | \
0034 MHB_PWR_POWERON | \
0035 MHB_PWR_POWEROK)
0036
0037 struct sr_pcie_phy_core;
0038
0039
0040
0041
0042
0043
0044
0045
0046 struct sr_pcie_phy {
0047 struct sr_pcie_phy_core *core;
0048 unsigned int index;
0049 struct phy *phy;
0050 };
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 struct sr_pcie_phy_core {
0063 struct device *dev;
0064 void __iomem *base;
0065 struct regmap *cdru;
0066 struct regmap *mhb;
0067 u32 pipemux;
0068 struct sr_pcie_phy phys[SR_NR_PCIE_PHYS];
0069 };
0070
0071
0072
0073
0074
0075
0076
0077
0078 static const u8 pipemux_table[] = {
0079
0080 0x00,
0081
0082 0x80,
0083
0084 0x00,
0085
0086 0x81,
0087
0088 0xc3,
0089
0090 0xff,
0091
0092 0xcd,
0093
0094 0xfd,
0095
0096 0xf0,
0097
0098 0xc0,
0099
0100 0x42,
0101
0102 0x3c,
0103
0104 0xfc,
0105
0106 0x4c,
0107 };
0108
0109
0110
0111
0112 static bool pipemux_strap_is_valid(u32 pipemux)
0113 {
0114 return !!(pipemux < ARRAY_SIZE(pipemux_table));
0115 }
0116
0117
0118
0119
0120 static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
0121 {
0122 u32 pipemux;
0123
0124
0125
0126
0127
0128
0129
0130 pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
0131 pipemux &= PCIE_PIPEMUX_MASK;
0132 if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
0133 regmap_read(core->cdru, CDRU_STRAP_DATA_LSW_OFFSET, &pipemux);
0134 pipemux >>= PCIE_PIPEMUX_SHIFT;
0135 pipemux &= PCIE_PIPEMUX_MASK;
0136 }
0137
0138 return pipemux;
0139 }
0140
0141
0142
0143
0144
0145 static bool pcie_core_is_for_rc(struct sr_pcie_phy *phy)
0146 {
0147 struct sr_pcie_phy_core *core = phy->core;
0148 unsigned int core_idx = phy->index;
0149
0150 return !!((pipemux_table[core->pipemux] >> core_idx) & 0x1);
0151 }
0152
0153 static int sr_pcie_phy_init(struct phy *p)
0154 {
0155 struct sr_pcie_phy *phy = phy_get_drvdata(p);
0156
0157
0158
0159
0160
0161
0162 if (pcie_core_is_for_rc(phy))
0163 return 0;
0164
0165 return -ENODEV;
0166 }
0167
0168 static int sr_paxc_phy_init(struct phy *p)
0169 {
0170 struct sr_pcie_phy *phy = phy_get_drvdata(p);
0171 struct sr_pcie_phy_core *core = phy->core;
0172 unsigned int core_idx = phy->index;
0173 u32 val;
0174
0175 if (core_idx != SR_PAXC_PHY_IDX)
0176 return -EINVAL;
0177
0178 regmap_read(core->mhb, MHB_MEM_PW_PAXC_OFFSET, &val);
0179 if ((val & MHB_PWR_STATUS_MASK) != MHB_PWR_STATUS_MASK) {
0180 dev_err(core->dev, "PAXC is not powered up\n");
0181 return -ENODEV;
0182 }
0183
0184 return 0;
0185 }
0186
0187 static const struct phy_ops sr_pcie_phy_ops = {
0188 .init = sr_pcie_phy_init,
0189 .owner = THIS_MODULE,
0190 };
0191
0192 static const struct phy_ops sr_paxc_phy_ops = {
0193 .init = sr_paxc_phy_init,
0194 .owner = THIS_MODULE,
0195 };
0196
0197 static struct phy *sr_pcie_phy_xlate(struct device *dev,
0198 struct of_phandle_args *args)
0199 {
0200 struct sr_pcie_phy_core *core;
0201 int phy_idx;
0202
0203 core = dev_get_drvdata(dev);
0204 if (!core)
0205 return ERR_PTR(-EINVAL);
0206
0207 phy_idx = args->args[0];
0208
0209 if (WARN_ON(phy_idx >= SR_NR_PCIE_PHYS))
0210 return ERR_PTR(-ENODEV);
0211
0212 return core->phys[phy_idx].phy;
0213 }
0214
0215 static int sr_pcie_phy_probe(struct platform_device *pdev)
0216 {
0217 struct device *dev = &pdev->dev;
0218 struct device_node *node = dev->of_node;
0219 struct sr_pcie_phy_core *core;
0220 struct phy_provider *provider;
0221 unsigned int phy_idx = 0;
0222
0223 core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
0224 if (!core)
0225 return -ENOMEM;
0226
0227 core->dev = dev;
0228 core->base = devm_platform_ioremap_resource(pdev, 0);
0229 if (IS_ERR(core->base))
0230 return PTR_ERR(core->base);
0231
0232 core->cdru = syscon_regmap_lookup_by_phandle(node, "brcm,sr-cdru");
0233 if (IS_ERR(core->cdru)) {
0234 dev_err(core->dev, "unable to find CDRU device\n");
0235 return PTR_ERR(core->cdru);
0236 }
0237
0238 core->mhb = syscon_regmap_lookup_by_phandle(node, "brcm,sr-mhb");
0239 if (IS_ERR(core->mhb)) {
0240 dev_err(core->dev, "unable to find MHB device\n");
0241 return PTR_ERR(core->mhb);
0242 }
0243
0244
0245 core->pipemux = pipemux_strap_read(core);
0246 if (!pipemux_strap_is_valid(core->pipemux)) {
0247 dev_err(core->dev, "invalid PCIe PIPEMUX strap %u\n",
0248 core->pipemux);
0249 return -EIO;
0250 }
0251
0252 for (phy_idx = 0; phy_idx < SR_NR_PCIE_PHYS; phy_idx++) {
0253 struct sr_pcie_phy *p = &core->phys[phy_idx];
0254 const struct phy_ops *ops;
0255
0256 if (phy_idx == SR_PAXC_PHY_IDX)
0257 ops = &sr_paxc_phy_ops;
0258 else
0259 ops = &sr_pcie_phy_ops;
0260
0261 p->phy = devm_phy_create(dev, NULL, ops);
0262 if (IS_ERR(p->phy)) {
0263 dev_err(dev, "failed to create PCIe PHY\n");
0264 return PTR_ERR(p->phy);
0265 }
0266
0267 p->core = core;
0268 p->index = phy_idx;
0269 phy_set_drvdata(p->phy, p);
0270 }
0271
0272 dev_set_drvdata(dev, core);
0273
0274 provider = devm_of_phy_provider_register(dev, sr_pcie_phy_xlate);
0275 if (IS_ERR(provider)) {
0276 dev_err(dev, "failed to register PHY provider\n");
0277 return PTR_ERR(provider);
0278 }
0279
0280 dev_info(dev, "Stingray PCIe PHY driver initialized\n");
0281
0282 return 0;
0283 }
0284
0285 static const struct of_device_id sr_pcie_phy_match_table[] = {
0286 { .compatible = "brcm,sr-pcie-phy" },
0287 { }
0288 };
0289 MODULE_DEVICE_TABLE(of, sr_pcie_phy_match_table);
0290
0291 static struct platform_driver sr_pcie_phy_driver = {
0292 .driver = {
0293 .name = "sr-pcie-phy",
0294 .of_match_table = sr_pcie_phy_match_table,
0295 },
0296 .probe = sr_pcie_phy_probe,
0297 };
0298 module_platform_driver(sr_pcie_phy_driver);
0299
0300 MODULE_AUTHOR("Ray Jui <ray.jui@broadcom.com>");
0301 MODULE_DESCRIPTION("Broadcom Stingray PCIe PHY driver");
0302 MODULE_LICENSE("GPL v2");