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