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