1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2016-2018 Broadcom
7 #include <linux/delay.h>
9 #include <linux/module.h>
10 #include <linux/mfd/syscon.h>
12 #include <linux/phy/phy.h>
13 #include <linux/platform_device.h>
14 #include <linux/regmap.h>
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)
20 #define PCIE_PIPEMUX_CFG_OFFSET 0x10c
21 #define PCIE_PIPEMUX_SELECT_STRAP 0xf
23 #define CDRU_STRAP_DATA_LSW_OFFSET 0x5c
24 #define PCIE_PIPEMUX_SHIFT 19
25 #define PCIE_PIPEMUX_MASK 0xf
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 | \
37 struct sr_pcie_phy_core
;
40 * struct sr_pcie_phy - Stingray PCIe PHY
42 * @core: pointer to the Stingray PCIe PHY core control
44 * @phy: pointer to the kernel PHY device
47 struct sr_pcie_phy_core
*core
;
53 * struct sr_pcie_phy_core - Stingray PCIe PHY core control
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
62 struct sr_pcie_phy_core
{
68 struct sr_pcie_phy phys
[SR_NR_PCIE_PHYS
];
72 * PCIe PIPEMUX lookup table
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
78 static const u8 pipemux_table
[] = {
79 /* PIPEMUX = 0, EP 1x16 */
81 /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
83 /* PIPEMUX = 2, EP 4x4 */
85 /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
87 /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
89 /* PIPEMUX = 5, RC 8x2, all 8 cores */
91 /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
93 /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
95 /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
97 /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
99 /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
101 /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
103 /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
105 /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
110 * Return true if the strap setting is valid
112 static bool pipemux_strap_is_valid(u32 pipemux
)
114 return !!(pipemux
< ARRAY_SIZE(pipemux_table
));
118 * Read the PCIe PIPEMUX from strap
120 static u32
pipemux_strap_read(struct sr_pcie_phy_core
*core
)
125 * Read PIPEMUX configuration register to determine the pipemux setting
127 * In the case when the value indicates using HW strap, fall back to
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
;
142 * Given a PIPEMUX strap and PCIe core index, this function returns true if the
143 * PCIe core needs to be enabled
145 static bool pcie_core_is_for_rc(struct sr_pcie_phy
*phy
)
147 struct sr_pcie_phy_core
*core
= phy
->core
;
148 unsigned int core_idx
= phy
->index
;
150 return !!((pipemux_table
[core
->pipemux
] >> core_idx
) & 0x1);
153 static int sr_pcie_phy_init(struct phy
*p
)
155 struct sr_pcie_phy
*phy
= phy_get_drvdata(p
);
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
162 if (pcie_core_is_for_rc(phy
))
168 static int sr_paxc_phy_init(struct phy
*p
)
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
;
175 if (core_idx
!= SR_PAXC_PHY_IDX
)
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");
187 static const struct phy_ops sr_pcie_phy_ops
= {
188 .init
= sr_pcie_phy_init
,
189 .owner
= THIS_MODULE
,
192 static const struct phy_ops sr_paxc_phy_ops
= {
193 .init
= sr_paxc_phy_init
,
194 .owner
= THIS_MODULE
,
197 static struct phy
*sr_pcie_phy_xlate(struct device
*dev
,
198 struct of_phandle_args
*args
)
200 struct sr_pcie_phy_core
*core
;
203 core
= dev_get_drvdata(dev
);
205 return ERR_PTR(-EINVAL
);
207 phy_idx
= args
->args
[0];
209 if (WARN_ON(phy_idx
>= SR_NR_PCIE_PHYS
))
210 return ERR_PTR(-ENODEV
);
212 return core
->phys
[phy_idx
].phy
;
215 static int sr_pcie_phy_probe(struct platform_device
*pdev
)
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;
224 core
= devm_kzalloc(dev
, sizeof(*core
), GFP_KERNEL
);
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
);
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
);
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
);
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",
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
;
259 if (phy_idx
== SR_PAXC_PHY_IDX
)
260 ops
= &sr_paxc_phy_ops
;
262 ops
= &sr_pcie_phy_ops
;
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
);
272 phy_set_drvdata(p
->phy
, p
);
275 dev_set_drvdata(dev
, core
);
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
);
283 dev_info(dev
, "Stingray PCIe PHY driver initialized\n");
288 static const struct of_device_id sr_pcie_phy_match_table
[] = {
289 { .compatible
= "brcm,sr-pcie-phy" },
292 MODULE_DEVICE_TABLE(of
, sr_pcie_phy_match_table
);
294 static struct platform_driver sr_pcie_phy_driver
= {
296 .name
= "sr-pcie-phy",
297 .of_match_table
= sr_pcie_phy_match_table
,
299 .probe
= sr_pcie_phy_probe
,
301 module_platform_driver(sr_pcie_phy_driver
);
303 MODULE_AUTHOR("Ray Jui <ray.jui@broadcom.com>");
304 MODULE_DESCRIPTION("Broadcom Stingray PCIe PHY driver");
305 MODULE_LICENSE("GPL v2");