]>
Commit | Line | Data |
---|---|---|
bdebb00d MK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * PCIe host bridge driver for Apple system-on-chips. | |
4 | * | |
5 | * The HW is ECAM compliant. | |
6 | * | |
7 | * Initialization requires enabling power and clocks, along with a | |
8 | * number of register pokes. | |
9 | * | |
10 | * Copyright (C) 2021 Alyssa Rosenzweig <[email protected]> | |
11 | * Copyright (C) 2021 Google LLC | |
12 | * Copyright (C) 2021 Corellium LLC | |
13 | * Copyright (C) 2021 Mark Kettenis <[email protected]> | |
14 | * | |
15 | * Author: Alyssa Rosenzweig <[email protected]> | |
16 | * Author: Marc Zyngier <[email protected]> | |
17 | */ | |
18 | ||
bdebb00d MK |
19 | #include <dm.h> |
20 | #include <dm/device_compat.h> | |
21 | #include <dm/devres.h> | |
22 | #include <mapmem.h> | |
23 | #include <pci.h> | |
24 | #include <asm/io.h> | |
25 | #include <asm-generic/gpio.h> | |
26 | #include <linux/delay.h> | |
27 | #include <linux/iopoll.h> | |
28 | ||
29 | #define CORE_RC_PHYIF_CTL 0x00024 | |
30 | #define CORE_RC_PHYIF_CTL_RUN BIT(0) | |
31 | #define CORE_RC_PHYIF_STAT 0x00028 | |
32 | #define CORE_RC_PHYIF_STAT_REFCLK BIT(4) | |
33 | #define CORE_RC_CTL 0x00050 | |
34 | #define CORE_RC_CTL_RUN BIT(0) | |
35 | #define CORE_RC_STAT 0x00058 | |
36 | #define CORE_RC_STAT_READY BIT(0) | |
37 | #define CORE_FABRIC_STAT 0x04000 | |
38 | #define CORE_FABRIC_STAT_MASK 0x001F001F | |
159f4157 MK |
39 | |
40 | #define CORE_PHY_DEFAULT_BASE(port) (0x84000 + 0x4000 * (port)) | |
41 | ||
42 | #define PHY_LANE_CFG 0x00000 | |
43 | #define PHY_LANE_CFG_REFCLK0REQ BIT(0) | |
44 | #define PHY_LANE_CFG_REFCLK1REQ BIT(1) | |
45 | #define PHY_LANE_CFG_REFCLK0ACK BIT(2) | |
46 | #define PHY_LANE_CFG_REFCLK1ACK BIT(3) | |
47 | #define PHY_LANE_CFG_REFCLKEN (BIT(9) | BIT(10)) | |
48 | #define PHY_LANE_CFG_REFCLKCGEN (BIT(30) | BIT(31)) | |
49 | #define PHY_LANE_CTL 0x00004 | |
50 | #define PHY_LANE_CTL_CFGACC BIT(15) | |
bdebb00d MK |
51 | |
52 | #define PORT_LTSSMCTL 0x00080 | |
53 | #define PORT_LTSSMCTL_START BIT(0) | |
54 | #define PORT_INTSTAT 0x00100 | |
55 | #define PORT_INT_TUNNEL_ERR 31 | |
56 | #define PORT_INT_CPL_TIMEOUT 23 | |
57 | #define PORT_INT_RID2SID_MAPERR 22 | |
58 | #define PORT_INT_CPL_ABORT 21 | |
59 | #define PORT_INT_MSI_BAD_DATA 19 | |
60 | #define PORT_INT_MSI_ERR 18 | |
61 | #define PORT_INT_REQADDR_GT32 17 | |
62 | #define PORT_INT_AF_TIMEOUT 15 | |
63 | #define PORT_INT_LINK_DOWN 14 | |
64 | #define PORT_INT_LINK_UP 12 | |
65 | #define PORT_INT_LINK_BWMGMT 11 | |
66 | #define PORT_INT_AER_MASK (15 << 4) | |
67 | #define PORT_INT_PORT_ERR 4 | |
68 | #define PORT_INT_INTx(i) i | |
69 | #define PORT_INT_INTx_MASK 15 | |
70 | #define PORT_INTMSK 0x00104 | |
71 | #define PORT_INTMSKSET 0x00108 | |
72 | #define PORT_INTMSKCLR 0x0010c | |
73 | #define PORT_MSICFG 0x00124 | |
74 | #define PORT_MSICFG_EN BIT(0) | |
75 | #define PORT_MSICFG_L2MSINUM_SHIFT 4 | |
76 | #define PORT_MSIBASE 0x00128 | |
77 | #define PORT_MSIBASE_1_SHIFT 16 | |
78 | #define PORT_MSIADDR 0x00168 | |
79 | #define PORT_LINKSTS 0x00208 | |
80 | #define PORT_LINKSTS_UP BIT(0) | |
81 | #define PORT_LINKSTS_BUSY BIT(2) | |
82 | #define PORT_LINKCMDSTS 0x00210 | |
83 | #define PORT_OUTS_NPREQS 0x00284 | |
84 | #define PORT_OUTS_NPREQS_REQ BIT(24) | |
85 | #define PORT_OUTS_NPREQS_CPL BIT(16) | |
86 | #define PORT_RXWR_FIFO 0x00288 | |
87 | #define PORT_RXWR_FIFO_HDR GENMASK(15, 10) | |
88 | #define PORT_RXWR_FIFO_DATA GENMASK(9, 0) | |
89 | #define PORT_RXRD_FIFO 0x0028C | |
90 | #define PORT_RXRD_FIFO_REQ GENMASK(6, 0) | |
91 | #define PORT_OUTS_CPLS 0x00290 | |
92 | #define PORT_OUTS_CPLS_SHRD GENMASK(14, 8) | |
93 | #define PORT_OUTS_CPLS_WAIT GENMASK(6, 0) | |
94 | #define PORT_APPCLK 0x00800 | |
95 | #define PORT_APPCLK_EN BIT(0) | |
96 | #define PORT_APPCLK_CGDIS BIT(8) | |
97 | #define PORT_STATUS 0x00804 | |
98 | #define PORT_STATUS_READY BIT(0) | |
99 | #define PORT_REFCLK 0x00810 | |
100 | #define PORT_REFCLK_EN BIT(0) | |
101 | #define PORT_REFCLK_CGDIS BIT(8) | |
102 | #define PORT_PERST 0x00814 | |
103 | #define PORT_PERST_OFF BIT(0) | |
104 | #define PORT_RID2SID(i16) (0x00828 + 4 * (i16)) | |
105 | #define PORT_RID2SID_VALID BIT(31) | |
106 | #define PORT_RID2SID_SID_SHIFT 16 | |
107 | #define PORT_RID2SID_BUS_SHIFT 8 | |
108 | #define PORT_RID2SID_DEV_SHIFT 3 | |
109 | #define PORT_RID2SID_FUNC_SHIFT 0 | |
110 | #define PORT_OUTS_PREQS_HDR 0x00980 | |
111 | #define PORT_OUTS_PREQS_HDR_MASK GENMASK(9, 0) | |
112 | #define PORT_OUTS_PREQS_DATA 0x00984 | |
113 | #define PORT_OUTS_PREQS_DATA_MASK GENMASK(15, 0) | |
114 | #define PORT_TUNCTRL 0x00988 | |
115 | #define PORT_TUNCTRL_PERST_ON BIT(0) | |
116 | #define PORT_TUNCTRL_PERST_ACK_REQ BIT(1) | |
117 | #define PORT_TUNSTAT 0x0098c | |
118 | #define PORT_TUNSTAT_PERST_ON BIT(0) | |
119 | #define PORT_TUNSTAT_PERST_ACK_PEND BIT(1) | |
120 | #define PORT_PREFMEM_ENABLE 0x00994 | |
121 | ||
159f4157 MK |
122 | struct reg_info { |
123 | u32 phy_lane_ctl; | |
124 | u32 port_refclk; | |
125 | u32 port_perst; | |
126 | }; | |
127 | ||
128 | const struct reg_info t8103_hw = { | |
129 | .phy_lane_ctl = PHY_LANE_CTL, | |
130 | .port_refclk = PORT_REFCLK, | |
131 | .port_perst = PORT_PERST, | |
132 | }; | |
133 | ||
134 | #define PORT_T602X_PERST 0x082c | |
135 | ||
136 | const struct reg_info t602x_hw = { | |
137 | .phy_lane_ctl = 0, | |
138 | .port_refclk = 0, | |
139 | .port_perst = PORT_T602X_PERST, | |
140 | }; | |
141 | ||
bdebb00d MK |
142 | struct apple_pcie_priv { |
143 | struct udevice *dev; | |
144 | void __iomem *base; | |
145 | void __iomem *cfg_base; | |
146 | struct list_head ports; | |
159f4157 | 147 | const struct reg_info *hw; |
bdebb00d MK |
148 | }; |
149 | ||
150 | struct apple_pcie_port { | |
151 | struct apple_pcie_priv *pcie; | |
152 | struct gpio_desc reset; | |
153 | ofnode np; | |
154 | void __iomem *base; | |
159f4157 | 155 | void __iomem *phy; |
bdebb00d MK |
156 | struct list_head entry; |
157 | int idx; | |
158 | }; | |
159 | ||
160 | static void rmw_set(u32 set, void __iomem *addr) | |
161 | { | |
162 | writel_relaxed(readl_relaxed(addr) | set, addr); | |
163 | } | |
164 | ||
165 | static void rmw_clear(u32 clr, void __iomem *addr) | |
166 | { | |
167 | writel_relaxed(readl_relaxed(addr) & ~clr, addr); | |
168 | } | |
169 | ||
170 | static int apple_pcie_config_address(const struct udevice *bus, | |
171 | pci_dev_t bdf, uint offset, | |
172 | void **paddress) | |
173 | { | |
174 | struct apple_pcie_priv *pcie = dev_get_priv(bus); | |
175 | void *addr; | |
176 | ||
177 | addr = pcie->cfg_base; | |
178 | addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), | |
179 | PCI_FUNC(bdf), offset); | |
180 | *paddress = addr; | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
185 | static int apple_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, | |
186 | uint offset, ulong *valuep, | |
187 | enum pci_size_t size) | |
188 | { | |
189 | int ret; | |
190 | ||
191 | ret = pci_generic_mmap_read_config(bus, apple_pcie_config_address, | |
192 | bdf, offset, valuep, size); | |
193 | return ret; | |
194 | } | |
195 | ||
196 | static int apple_pcie_write_config(struct udevice *bus, pci_dev_t bdf, | |
197 | uint offset, ulong value, | |
198 | enum pci_size_t size) | |
199 | { | |
200 | return pci_generic_mmap_write_config(bus, apple_pcie_config_address, | |
201 | bdf, offset, value, size); | |
202 | } | |
203 | ||
204 | static const struct dm_pci_ops apple_pcie_ops = { | |
205 | .read_config = apple_pcie_read_config, | |
206 | .write_config = apple_pcie_write_config, | |
207 | }; | |
208 | ||
209 | static int apple_pcie_setup_refclk(struct apple_pcie_priv *pcie, | |
210 | struct apple_pcie_port *port) | |
211 | { | |
212 | u32 stat; | |
213 | int res; | |
214 | ||
159f4157 MK |
215 | if (pcie->hw->phy_lane_ctl) |
216 | rmw_set(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl); | |
bdebb00d | 217 | |
159f4157 | 218 | rmw_set(PHY_LANE_CFG_REFCLK0REQ, port->phy + PHY_LANE_CFG); |
bdebb00d | 219 | |
159f4157 MK |
220 | res = readl_poll_sleep_timeout(port->phy + PHY_LANE_CFG, |
221 | stat, stat & PHY_LANE_CFG_REFCLK0ACK, | |
bdebb00d MK |
222 | 100, 50000); |
223 | if (res < 0) | |
224 | return res; | |
225 | ||
159f4157 MK |
226 | rmw_set(PHY_LANE_CFG_REFCLK1REQ, port->phy + PHY_LANE_CFG); |
227 | res = readl_poll_sleep_timeout(port->phy + PHY_LANE_CFG, | |
228 | stat, stat & PHY_LANE_CFG_REFCLK1ACK, | |
bdebb00d MK |
229 | 100, 50000); |
230 | ||
231 | if (res < 0) | |
232 | return res; | |
233 | ||
159f4157 MK |
234 | if (pcie->hw->phy_lane_ctl) |
235 | rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl); | |
236 | ||
237 | rmw_set(PHY_LANE_CFG_REFCLKEN, port->phy + PHY_LANE_CFG); | |
bdebb00d | 238 | |
159f4157 MK |
239 | if (pcie->hw->port_refclk) |
240 | rmw_set(PORT_REFCLK_EN, port->base + pcie->hw->port_refclk); | |
bdebb00d MK |
241 | |
242 | return 0; | |
243 | } | |
244 | ||
245 | static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np) | |
246 | { | |
247 | struct apple_pcie_port *port; | |
248 | struct gpio_desc reset; | |
249 | fdt_addr_t addr; | |
250 | u32 stat, idx; | |
251 | int ret; | |
159f4157 | 252 | char name[16]; |
bdebb00d MK |
253 | |
254 | ret = gpio_request_by_name_nodev(np, "reset-gpios", 0, &reset, 0); | |
255 | if (ret) | |
256 | return ret; | |
257 | ||
258 | port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL); | |
259 | if (!port) | |
260 | return -ENOMEM; | |
261 | ||
262 | ret = ofnode_read_u32_index(np, "reg", 0, &idx); | |
263 | if (ret) | |
264 | return ret; | |
265 | ||
266 | /* Use the first reg entry to work out the port index */ | |
267 | port->idx = idx >> 11; | |
268 | port->pcie = pcie; | |
269 | port->reset = reset; | |
270 | port->np = np; | |
271 | ||
159f4157 MK |
272 | snprintf(name, sizeof(name), "port%d", port->idx); |
273 | addr = dev_read_addr_name(pcie->dev, name); | |
274 | if (addr == FDT_ADDR_T_NONE) | |
275 | addr = dev_read_addr_index(pcie->dev, port->idx + 2); | |
bdebb00d MK |
276 | if (addr == FDT_ADDR_T_NONE) |
277 | return -EINVAL; | |
278 | port->base = map_sysmem(addr, 0); | |
279 | ||
159f4157 MK |
280 | snprintf(name, sizeof(name), "phy%d", port->idx); |
281 | addr = dev_read_addr_name(pcie->dev, name); | |
282 | if (addr == FDT_ADDR_T_NONE) | |
283 | port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx); | |
284 | else | |
285 | port->phy = map_sysmem(addr, 0); | |
286 | ||
bdebb00d MK |
287 | rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK); |
288 | ||
289 | /* Assert PERST# before setting up the clock */ | |
290 | dm_gpio_set_value(&reset, 1); | |
291 | ||
292 | ret = apple_pcie_setup_refclk(pcie, port); | |
293 | if (ret < 0) | |
294 | return ret; | |
295 | ||
296 | /* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */ | |
297 | udelay(100); | |
298 | ||
299 | /* Deassert PERST# */ | |
159f4157 | 300 | rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst); |
bdebb00d MK |
301 | dm_gpio_set_value(&reset, 0); |
302 | ||
303 | /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ | |
304 | udelay(100 * 1000); | |
305 | ||
306 | ret = readl_poll_sleep_timeout(port->base + PORT_STATUS, stat, | |
307 | stat & PORT_STATUS_READY, 100, 250000); | |
308 | if (ret < 0) { | |
309 | dev_err(pcie->dev, "port %d ready wait timeout\n", port->idx); | |
310 | return ret; | |
311 | } | |
312 | ||
bdebb00d MK |
313 | list_add_tail(&port->entry, &pcie->ports); |
314 | ||
315 | writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL); | |
316 | ||
317 | /* | |
318 | * Deliberately ignore the link not coming up as connected | |
319 | * devices (e.g. the WiFi controller) may not be powerd up. | |
320 | */ | |
321 | readl_poll_sleep_timeout(port->base + PORT_LINKSTS, stat, | |
322 | (stat & PORT_LINKSTS_UP), 100, 100000); | |
323 | ||
159f4157 MK |
324 | if (pcie->hw->port_refclk) |
325 | rmw_clear(PORT_REFCLK_CGDIS, port->base + PORT_REFCLK); | |
326 | else | |
327 | rmw_set(PHY_LANE_CFG_REFCLKCGEN, port->phy + PHY_LANE_CFG); | |
328 | rmw_clear(PORT_APPCLK_CGDIS, port->base + PORT_APPCLK); | |
329 | ||
bdebb00d MK |
330 | return 0; |
331 | } | |
332 | ||
333 | static int apple_pcie_probe(struct udevice *dev) | |
334 | { | |
335 | struct apple_pcie_priv *pcie = dev_get_priv(dev); | |
336 | fdt_addr_t addr; | |
337 | ofnode of_port; | |
338 | int i, ret; | |
339 | ||
159f4157 MK |
340 | pcie->hw = (struct reg_info *)dev_get_driver_data(dev); |
341 | ||
bdebb00d MK |
342 | pcie->dev = dev; |
343 | addr = dev_read_addr_index(dev, 0); | |
344 | if (addr == FDT_ADDR_T_NONE) | |
345 | return -EINVAL; | |
346 | pcie->cfg_base = map_sysmem(addr, 0); | |
347 | ||
348 | addr = dev_read_addr_index(dev, 1); | |
349 | if (addr == FDT_ADDR_T_NONE) | |
350 | return -EINVAL; | |
351 | pcie->base = map_sysmem(addr, 0); | |
352 | ||
353 | INIT_LIST_HEAD(&pcie->ports); | |
354 | ||
355 | for (of_port = ofnode_first_subnode(dev_ofnode(dev)); | |
356 | ofnode_valid(of_port); | |
357 | of_port = ofnode_next_subnode(of_port)) { | |
6ee2c8ad JG |
358 | if (!ofnode_is_enabled(of_port)) |
359 | continue; | |
bdebb00d MK |
360 | ret = apple_pcie_setup_port(pcie, of_port); |
361 | if (ret) { | |
362 | dev_err(pcie->dev, "Port %d setup fail: %d\n", i, ret); | |
363 | return ret; | |
364 | } | |
365 | } | |
366 | ||
367 | return 0; | |
368 | } | |
369 | ||
370 | static int apple_pcie_remove(struct udevice *dev) | |
371 | { | |
372 | struct apple_pcie_priv *pcie = dev_get_priv(dev); | |
373 | struct apple_pcie_port *port, *tmp; | |
374 | ||
375 | list_for_each_entry_safe(port, tmp, &pcie->ports, entry) { | |
376 | gpio_free_list_nodev(&port->reset, 1); | |
377 | free(port); | |
378 | } | |
379 | ||
380 | return 0; | |
381 | } | |
382 | ||
383 | static const struct udevice_id apple_pcie_of_match[] = { | |
159f4157 MK |
384 | { .compatible = "apple,t6020-pcie", .data = (ulong)&t602x_hw }, |
385 | { .compatible = "apple,pcie", .data = (ulong)&t8103_hw }, | |
bdebb00d MK |
386 | { /* sentinel */ } |
387 | }; | |
388 | ||
389 | U_BOOT_DRIVER(apple_pcie) = { | |
390 | .name = "apple_pcie", | |
391 | .id = UCLASS_PCI, | |
392 | .of_match = apple_pcie_of_match, | |
393 | .probe = apple_pcie_probe, | |
394 | .remove = apple_pcie_remove, | |
395 | .priv_auto = sizeof(struct apple_pcie_priv), | |
396 | .ops = &apple_pcie_ops, | |
397 | }; |