blob: aa1903e547ce83d54e225ba74f50113f8a810006 [file] [log] [blame]
Ley Foon Tan7c458622018-04-20 21:55:45 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel FPGA PCIe host controller driver
4 *
5 * Copyright (C) 2013-2018 Intel Corporation. All rights reserved
6 *
7 */
8
9#include <common.h>
10#include <dm.h>
11#include <pci.h>
12#include <asm/io.h>
Simon Glass336d4612020-02-03 07:36:16 -070013#include <dm/device_compat.h>
Simon Glasscd93d622020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060015#include <linux/delay.h>
Ley Foon Tan7c458622018-04-20 21:55:45 +080016
17#define RP_TX_REG0 0x2000
18#define RP_TX_CNTRL 0x2004
19#define RP_TX_SOP BIT(0)
20#define RP_TX_EOP BIT(1)
21#define RP_RXCPL_STATUS 0x200C
22#define RP_RXCPL_SOP BIT(0)
23#define RP_RXCPL_EOP BIT(1)
24#define RP_RXCPL_REG 0x2008
25#define P2A_INT_STATUS 0x3060
26#define P2A_INT_STS_ALL 0xf
27#define P2A_INT_ENABLE 0x3070
28#define RP_CAP_OFFSET 0x70
29
30/* TLP configuration type 0 and 1 */
31#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */
32#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */
33#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */
34#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */
35#define TLP_PAYLOAD_SIZE 0x01
36#define TLP_READ_TAG 0x1d
37#define TLP_WRITE_TAG 0x10
38#define RP_DEVFN 0
39
40#define RP_CFG_ADDR(pcie, reg) \
41 ((pcie->hip_base) + (reg) + (1 << 20))
Ley Foon Tand44f7932019-05-24 10:30:00 +080042#define RP_SECONDARY(pcie) \
43 readb(RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS))
Ley Foon Tan7c458622018-04-20 21:55:45 +080044#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn))
45
46#define TLP_CFGRD_DW0(pcie, bus) \
Ley Foon Tand44f7932019-05-24 10:30:00 +080047 ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGRD1 \
48 : TLP_FMTTYPE_CFGRD0) << 24) | \
Ley Foon Tan7c458622018-04-20 21:55:45 +080049 TLP_PAYLOAD_SIZE)
50
51#define TLP_CFGWR_DW0(pcie, bus) \
Ley Foon Tand44f7932019-05-24 10:30:00 +080052 ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGWR1 \
53 : TLP_FMTTYPE_CFGWR0) << 24) | \
Ley Foon Tan7c458622018-04-20 21:55:45 +080054 TLP_PAYLOAD_SIZE)
55
56#define TLP_CFG_DW1(pcie, tag, be) \
57 (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be))
58#define TLP_CFG_DW2(bus, dev, fn, offset) \
59 (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset))
60
61#define TLP_COMP_STATUS(s) (((s) >> 13) & 7)
62#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff)
63#define TLP_HDR_SIZE 3
Ley Foon Tand0e52c62019-05-24 10:29:58 +080064#define TLP_LOOP 20000
Ley Foon Tan7c458622018-04-20 21:55:45 +080065#define DWORD_MASK 3
66
67#define IS_ROOT_PORT(pcie, bdf) \
68 ((PCI_BUS(bdf) == pcie->first_busno) ? true : false)
69
70#define PCI_EXP_LNKSTA 18 /* Link Status */
71#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */
72
73/**
74 * struct intel_fpga_pcie - Intel FPGA PCIe controller state
75 * @bus: Pointer to the PCI bus
76 * @cra_base: The base address of CRA register space
77 * @hip_base: The base address of Rootport configuration space
78 * @first_busno: This driver supports multiple PCIe controllers.
79 * first_busno stores the bus number of the PCIe root-port
80 * number which may vary depending on the PCIe setup.
81 */
82struct intel_fpga_pcie {
83 struct udevice *bus;
84 void __iomem *cra_base;
85 void __iomem *hip_base;
86 int first_busno;
87};
88
89/**
90 * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the
91 * translation from PCI bus to native BUS. Entire DDR region is mapped
92 * into PCIe space using these registers, so it can be reached by DMA from
93 * EP devices.
94 * The BAR0 of bridge should be hidden during enumeration to avoid the
95 * sizing and resource allocation by PCIe core.
96 */
97static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie,
98 pci_dev_t bdf, int offset)
99{
100 if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 &&
101 PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0)
102 return true;
103
104 return false;
105}
106
107static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value,
108 const u32 reg)
109{
110 writel(value, pcie->cra_base + reg);
111}
112
113static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg)
114{
115 return readl(pcie->cra_base + reg);
116}
117
118static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie)
119{
120 return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA))
121 & PCI_EXP_LNKSTA_DLLLA);
122}
123
124static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie,
125 pci_dev_t bdf)
126{
127 /* If there is no link, then there is no device */
128 if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie))
129 return false;
130
131 /* access only one slot on each root port */
132 if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0)
133 return false;
134
135 if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0)
136 return false;
137
138 return true;
139}
140
141static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl)
142{
143 cra_writel(pcie, reg0, RP_TX_REG0);
144 cra_writel(pcie, ctrl, RP_TX_CNTRL);
145}
146
147static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value)
148{
149 int i;
150 u32 ctrl;
151 u32 comp_status;
152 u32 dw[4];
153 u32 count = 0;
154
155 for (i = 0; i < TLP_LOOP; i++) {
156 ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
157 if (!(ctrl & RP_RXCPL_SOP))
158 continue;
159
160 /* read first DW */
161 dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
162
163 /* Poll for EOP */
164 for (i = 0; i < TLP_LOOP; i++) {
165 ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
166 dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
167 if (ctrl & RP_RXCPL_EOP) {
168 comp_status = TLP_COMP_STATUS(dw[1]);
Ley Foon Tanbf9b9812019-05-24 10:29:59 +0800169 if (comp_status) {
170 *value = pci_get_ff(PCI_SIZE_32);
171 return 0;
172 }
Ley Foon Tan7c458622018-04-20 21:55:45 +0800173
174 if (value &&
175 TLP_BYTE_COUNT(dw[1]) == sizeof(u32) &&
176 count >= 3)
177 *value = dw[3];
178
179 return 0;
180 }
181 }
182
183 udelay(5);
184 }
185
186 dev_err(pcie->dev, "read TLP packet timed out\n");
187 return -ENODEV;
188}
189
190static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers,
191 u32 data)
192{
193 tlp_write_tx(pcie, headers[0], RP_TX_SOP);
194
195 tlp_write_tx(pcie, headers[1], 0);
196
197 tlp_write_tx(pcie, headers[2], 0);
198
199 tlp_write_tx(pcie, data, RP_TX_EOP);
200}
201
202static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
203 int offset, u8 byte_en, u32 *value)
204{
205 u32 headers[TLP_HDR_SIZE];
206 u8 busno = PCI_BUS(bdf);
207
208 headers[0] = TLP_CFGRD_DW0(pcie, busno);
209 headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en);
210 headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
211
212 tlp_write_packet(pcie, headers, 0);
213
214 return tlp_read_packet(pcie, value);
215}
216
217static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
218 int offset, u8 byte_en, u32 value)
219{
220 u32 headers[TLP_HDR_SIZE];
221 u8 busno = PCI_BUS(bdf);
222
223 headers[0] = TLP_CFGWR_DW0(pcie, busno);
224 headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en);
225 headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
226
227 tlp_write_packet(pcie, headers, value);
228
229 return tlp_read_packet(pcie, NULL);
230}
231
Simon Glassc4e72c42020-01-27 08:49:37 -0700232int intel_fpga_rp_conf_addr(const struct udevice *bus, pci_dev_t bdf,
Ley Foon Tan7c458622018-04-20 21:55:45 +0800233 uint offset, void **paddress)
234{
235 struct intel_fpga_pcie *pcie = dev_get_priv(bus);
236
237 *paddress = RP_CFG_ADDR(pcie, offset);
238
239 return 0;
240}
241
242static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf,
243 uint offset, ulong *valuep,
244 enum pci_size_t size)
245{
246 return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr,
247 bdf, offset, valuep, size);
248}
249
250static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf,
251 uint offset, ulong value,
252 enum pci_size_t size)
253{
254 int ret;
255 struct intel_fpga_pcie *pcie = dev_get_priv(bus);
256
257 ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr,
258 bdf, offset, value, size);
259 if (!ret) {
260 /* Monitor changes to PCI_PRIMARY_BUS register on root port
261 * and update local copy of root bus number accordingly.
262 */
263 if (offset == PCI_PRIMARY_BUS)
264 pcie->first_busno = (u8)(value);
265 }
266
267 return ret;
268}
269
270static u8 pcie_get_byte_en(uint offset, enum pci_size_t size)
271{
272 switch (size) {
273 case PCI_SIZE_8:
274 return 1 << (offset & 3);
275 case PCI_SIZE_16:
276 return 3 << (offset & 3);
277 default:
278 return 0xf;
279 }
280}
281
282static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie,
283 pci_dev_t bdf, uint offset,
284 ulong *valuep, enum pci_size_t size)
285{
286 int ret;
287 u32 data;
288 u8 byte_en;
289
290 /* Uses memory mapped method to read rootport config registers */
291 if (IS_ROOT_PORT(pcie, bdf))
292 return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf,
293 offset, valuep, size);
294
295 byte_en = pcie_get_byte_en(offset, size);
296 ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK,
297 byte_en, &data);
298 if (ret)
299 return ret;
300
301 dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n",
302 offset, size, data);
303 *valuep = pci_conv_32_to_size(data, offset, size);
304
305 return 0;
306}
307
308static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie,
309 pci_dev_t bdf, uint offset,
310 ulong value, enum pci_size_t size)
311{
312 u32 data;
313 u8 byte_en;
314
315 dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n",
316 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
317 dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n",
318 offset, size, value);
319
320 /* Uses memory mapped method to read rootport config registers */
321 if (IS_ROOT_PORT(pcie, bdf))
322 return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset,
323 value, size);
324
325 byte_en = pcie_get_byte_en(offset, size);
326 data = pci_conv_size_to_32(0, value, offset, size);
327
328 return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK,
329 byte_en, data);
330}
331
Simon Glassc4e72c42020-01-27 08:49:37 -0700332static int pcie_intel_fpga_read_config(const struct udevice *bus, pci_dev_t bdf,
Ley Foon Tan7c458622018-04-20 21:55:45 +0800333 uint offset, ulong *valuep,
334 enum pci_size_t size)
335{
336 struct intel_fpga_pcie *pcie = dev_get_priv(bus);
337
338 dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n",
339 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
340
341 if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) {
342 *valuep = (u32)pci_get_ff(size);
343 return 0;
344 }
345
346 if (!intel_fpga_pcie_addr_valid(pcie, bdf)) {
347 *valuep = (u32)pci_get_ff(size);
348 return 0;
349 }
350
351 return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size);
352}
353
354static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf,
355 uint offset, ulong value,
356 enum pci_size_t size)
357{
358 struct intel_fpga_pcie *pcie = dev_get_priv(bus);
359
360 if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset))
361 return 0;
362
363 if (!intel_fpga_pcie_addr_valid(pcie, bdf))
364 return 0;
365
366 return _pcie_intel_fpga_write_config(pcie, bdf, offset, value,
367 size);
368}
369
370static int pcie_intel_fpga_probe(struct udevice *dev)
371{
372 struct intel_fpga_pcie *pcie = dev_get_priv(dev);
373
374 pcie->bus = pci_get_controller(dev);
375 pcie->first_busno = dev->seq;
376
377 /* clear all interrupts */
378 cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
379 /* disable all interrupts */
380 cra_writel(pcie, 0, P2A_INT_ENABLE);
381
382 return 0;
383}
384
385static int pcie_intel_fpga_ofdata_to_platdata(struct udevice *dev)
386{
387 struct intel_fpga_pcie *pcie = dev_get_priv(dev);
388 struct fdt_resource reg_res;
389 int node = dev_of_offset(dev);
390 int ret;
391
392 DECLARE_GLOBAL_DATA_PTR;
393
394 ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
395 "Cra", &reg_res);
396 if (ret) {
397 dev_err(dev, "resource \"Cra\" not found\n");
398 return ret;
399 }
400
401 pcie->cra_base = map_physmem(reg_res.start,
402 fdt_resource_size(&reg_res),
403 MAP_NOCACHE);
404
405 ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
406 "Hip", &reg_res);
407 if (ret) {
408 dev_err(dev, "resource \"Hip\" not found\n");
409 return ret;
410 }
411
412 pcie->hip_base = map_physmem(reg_res.start,
413 fdt_resource_size(&reg_res),
414 MAP_NOCACHE);
415
416 return 0;
417}
418
419static const struct dm_pci_ops pcie_intel_fpga_ops = {
420 .read_config = pcie_intel_fpga_read_config,
421 .write_config = pcie_intel_fpga_write_config,
422};
423
424static const struct udevice_id pcie_intel_fpga_ids[] = {
425 { .compatible = "altr,pcie-root-port-2.0" },
426 {},
427};
428
429U_BOOT_DRIVER(pcie_intel_fpga) = {
430 .name = "pcie_intel_fpga",
431 .id = UCLASS_PCI,
432 .of_match = pcie_intel_fpga_ids,
433 .ops = &pcie_intel_fpga_ops,
434 .ofdata_to_platdata = pcie_intel_fpga_ofdata_to_platdata,
435 .probe = pcie_intel_fpga_probe,
436 .priv_auto_alloc_size = sizeof(struct intel_fpga_pcie),
437};