1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 Broadcom
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <generic-phy.h>
9 #include <asm/io.h>
10 #include <linux/bitops.h>
11 
12 /* we have up to 8 PAXB based RC. The 9th one is always PAXC */
13 #define SR_NR_PCIE_PHYS               8
14 
15 #define PCIE_PIPEMUX_CFG_OFFSET       0x10c
16 #define PCIE_PIPEMUX_SELECT_STRAP     GENMASK(3, 0)
17 
18 #define CDRU_STRAP_DATA_LSW_OFFSET    0x5c
19 #define PCIE_PIPEMUX_SHIFT            19
20 #define PCIE_PIPEMUX_MASK             GENMASK(3, 0)
21 
22 /**
23  * struct sr_pcie_phy_core - Stingray PCIe PHY core control
24  *
25  * @dev: pointer to device
26  * @base: base register of PCIe SS
27  * @cdru: CDRU base address
28  * @pipemux: pipemuex strap
29  */
30 struct sr_pcie_phy_core {
31 	struct udevice *dev;
32 	void __iomem *base;
33 	void __iomem *cdru;
34 	u32 pipemux;
35 };
36 
37 /*
38  * PCIe PIPEMUX lookup table
39  *
40  * Each array index represents a PIPEMUX strap setting
41  * The array element represents a bitmap where a set bit means the PCIe
42  * core and associated serdes has been enabled as RC and is available for use
43  */
44 static const u8 pipemux_table[] = {
45 	/* PIPEMUX = 0, EP 1x16 */
46 	0x00,
47 	/* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
48 	0x80,
49 	/* PIPEMUX = 2, EP 4x4 */
50 	0x00,
51 	/* PIPEMUX = 3, RC 2x8, cores 0, 7 */
52 	0x81,
53 	/* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
54 	0xc3,
55 	/* PIPEMUX = 5, RC 8x2, all 8 cores */
56 	0xff,
57 	/* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
58 	0xcd,
59 	/* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
60 	0xfd,
61 	/* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
62 	0xf0,
63 	/* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
64 	0xc0,
65 	/* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
66 	0x42,
67 	/* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
68 	0x3c,
69 	/* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
70 	0xfc,
71 	/* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
72 	0x4c,
73 };
74 
75 /*
76  * Return true if the strap setting is valid
77  */
pipemux_strap_is_valid(u32 pipemux)78 static bool pipemux_strap_is_valid(u32 pipemux)
79 {
80 	return !!(pipemux < ARRAY_SIZE(pipemux_table));
81 }
82 
83 /*
84  * Read the PCIe PIPEMUX from strap
85  */
pipemux_strap_read(struct sr_pcie_phy_core * core)86 static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
87 {
88 	u32 pipemux;
89 
90 	/*
91 	 * Read PIPEMUX configuration register to determine the pipemux setting
92 	 *
93 	 * In the case when the value indicates using HW strap, fall back to
94 	 * use HW strap
95 	 */
96 	pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
97 	pipemux &= PCIE_PIPEMUX_MASK;
98 	if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
99 		pipemux = readl(core->cdru + CDRU_STRAP_DATA_LSW_OFFSET);
100 		pipemux >>= PCIE_PIPEMUX_SHIFT;
101 		pipemux &= PCIE_PIPEMUX_MASK;
102 	}
103 
104 	return pipemux;
105 }
106 
sr_pcie_phy_init(struct phy * phy)107 static int sr_pcie_phy_init(struct phy *phy)
108 {
109 	struct sr_pcie_phy_core *core = dev_get_priv(phy->dev);
110 	unsigned int core_idx = phy->id;
111 
112 	debug("%s %lx\n", __func__, phy->id);
113 	/*
114 	 * Check whether this PHY is for root complex or not. If yes, return
115 	 * zero so the host driver can proceed to enumeration. If not, return
116 	 * an error and that will force the host driver to bail out
117 	 */
118 	if (!!((pipemux_table[core->pipemux] >> core_idx) & 0x1))
119 		return 0;
120 
121 	return -ENODEV;
122 }
123 
sr_pcie_phy_xlate(struct phy * phy,struct ofnode_phandle_args * args)124 static int sr_pcie_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
125 {
126 	debug("%s %d\n", __func__, args->args[0]);
127 	if (args->args_count && args->args[0] < SR_NR_PCIE_PHYS)
128 		phy->id = args->args[0];
129 	else
130 		return -ENODEV;
131 
132 	return 0;
133 }
134 
135 static const struct phy_ops sr_pcie_phy_ops = {
136 	.of_xlate = sr_pcie_phy_xlate,
137 	.init = sr_pcie_phy_init,
138 };
139 
sr_pcie_phy_probe(struct udevice * dev)140 static int sr_pcie_phy_probe(struct udevice *dev)
141 {
142 	struct sr_pcie_phy_core *core = dev_get_priv(dev);
143 
144 	core->dev = dev;
145 
146 	core->base = (void __iomem *)devfdt_get_addr_name(dev, "reg_base");
147 	core->cdru = (void __iomem *)devfdt_get_addr_name(dev, "cdru_base");
148 	debug("ip base %p\n", core->base);
149 	debug("cdru base %p\n", core->cdru);
150 
151 	/* read the PCIe PIPEMUX strap setting */
152 	core->pipemux = pipemux_strap_read(core);
153 	if (!pipemux_strap_is_valid(core->pipemux)) {
154 		pr_err("invalid PCIe PIPEMUX strap %u\n", core->pipemux);
155 		return -EIO;
156 	}
157 	debug("%s %#x\n", __func__, core->pipemux);
158 
159 	pr_info("Stingray PCIe PHY driver initialized\n");
160 
161 	return 0;
162 }
163 
164 static const struct udevice_id sr_pcie_phy_match_table[] = {
165 	{ .compatible = "brcm,sr-pcie-phy" },
166 	{ }
167 };
168 
169 U_BOOT_DRIVER(sr_pcie_phy) = {
170 	.name = "sr-pcie-phy",
171 	.id = UCLASS_PHY,
172 	.probe = sr_pcie_phy_probe,
173 	.of_match = sr_pcie_phy_match_table,
174 	.ops = &sr_pcie_phy_ops,
175 	.plat_auto	= sizeof(struct sr_pcie_phy_core),
176 	.priv_auto	= sizeof(struct sr_pcie_phy_core),
177 };
178