.. | .. |
---|
10 | 10 | #include <linux/interrupt.h> |
---|
11 | 11 | #include <linux/irqchip/chained_irq.h> |
---|
12 | 12 | #include <linux/init.h> |
---|
| 13 | +#include <linux/module.h> |
---|
13 | 14 | #include <linux/of_address.h> |
---|
| 15 | +#include <linux/of_device.h> |
---|
14 | 16 | #include <linux/of_irq.h> |
---|
15 | 17 | #include <linux/of_pci.h> |
---|
16 | 18 | #include <linux/pci.h> |
---|
.. | .. |
---|
37 | 39 | #define RP_LTSSM_MASK 0x1f |
---|
38 | 40 | #define LTSSM_L0 0xf |
---|
39 | 41 | |
---|
40 | | -#define PCIE_CAP_OFFSET 0x80 |
---|
| 42 | +#define S10_RP_TX_CNTRL 0x2004 |
---|
| 43 | +#define S10_RP_RXCPL_REG 0x2008 |
---|
| 44 | +#define S10_RP_RXCPL_STATUS 0x200C |
---|
| 45 | +#define S10_RP_CFG_ADDR(pcie, reg) \ |
---|
| 46 | + (((pcie)->hip_base) + (reg) + (1 << 20)) |
---|
| 47 | +#define S10_RP_SECONDARY(pcie) \ |
---|
| 48 | + readb(S10_RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS)) |
---|
| 49 | + |
---|
41 | 50 | /* TLP configuration type 0 and 1 */ |
---|
42 | 51 | #define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ |
---|
43 | 52 | #define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ |
---|
.. | .. |
---|
48 | 57 | #define TLP_WRITE_TAG 0x10 |
---|
49 | 58 | #define RP_DEVFN 0 |
---|
50 | 59 | #define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) |
---|
51 | | -#define TLP_CFGRD_DW0(pcie, bus) \ |
---|
52 | | - ((((bus == pcie->root_bus_nr) ? TLP_FMTTYPE_CFGRD0 \ |
---|
53 | | - : TLP_FMTTYPE_CFGRD1) << 24) | \ |
---|
54 | | - TLP_PAYLOAD_SIZE) |
---|
55 | | -#define TLP_CFGWR_DW0(pcie, bus) \ |
---|
56 | | - ((((bus == pcie->root_bus_nr) ? TLP_FMTTYPE_CFGWR0 \ |
---|
57 | | - : TLP_FMTTYPE_CFGWR1) << 24) | \ |
---|
58 | | - TLP_PAYLOAD_SIZE) |
---|
| 60 | +#define TLP_CFG_DW0(pcie, cfg) \ |
---|
| 61 | + (((cfg) << 24) | \ |
---|
| 62 | + TLP_PAYLOAD_SIZE) |
---|
59 | 63 | #define TLP_CFG_DW1(pcie, tag, be) \ |
---|
60 | | - (((TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN)) << 16) | (tag << 8) | (be)) |
---|
| 64 | + (((TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN)) << 16) | (tag << 8) | (be)) |
---|
61 | 65 | #define TLP_CFG_DW2(bus, devfn, offset) \ |
---|
62 | 66 | (((bus) << 24) | ((devfn) << 16) | (offset)) |
---|
63 | 67 | #define TLP_COMP_STATUS(s) (((s) >> 13) & 7) |
---|
| 68 | +#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff) |
---|
64 | 69 | #define TLP_HDR_SIZE 3 |
---|
65 | 70 | #define TLP_LOOP 500 |
---|
66 | 71 | |
---|
.. | .. |
---|
69 | 74 | |
---|
70 | 75 | #define DWORD_MASK 3 |
---|
71 | 76 | |
---|
| 77 | +#define S10_TLP_FMTTYPE_CFGRD0 0x05 |
---|
| 78 | +#define S10_TLP_FMTTYPE_CFGRD1 0x04 |
---|
| 79 | +#define S10_TLP_FMTTYPE_CFGWR0 0x45 |
---|
| 80 | +#define S10_TLP_FMTTYPE_CFGWR1 0x44 |
---|
| 81 | + |
---|
| 82 | +enum altera_pcie_version { |
---|
| 83 | + ALTERA_PCIE_V1 = 0, |
---|
| 84 | + ALTERA_PCIE_V2, |
---|
| 85 | +}; |
---|
| 86 | + |
---|
72 | 87 | struct altera_pcie { |
---|
73 | 88 | struct platform_device *pdev; |
---|
74 | | - void __iomem *cra_base; /* DT Cra */ |
---|
| 89 | + void __iomem *cra_base; |
---|
| 90 | + void __iomem *hip_base; |
---|
75 | 91 | int irq; |
---|
76 | 92 | u8 root_bus_nr; |
---|
77 | 93 | struct irq_domain *irq_domain; |
---|
78 | 94 | struct resource bus_range; |
---|
79 | | - struct list_head resources; |
---|
| 95 | + const struct altera_pcie_data *pcie_data; |
---|
| 96 | +}; |
---|
| 97 | + |
---|
| 98 | +struct altera_pcie_ops { |
---|
| 99 | + int (*tlp_read_pkt)(struct altera_pcie *pcie, u32 *value); |
---|
| 100 | + void (*tlp_write_pkt)(struct altera_pcie *pcie, u32 *headers, |
---|
| 101 | + u32 data, bool align); |
---|
| 102 | + bool (*get_link_status)(struct altera_pcie *pcie); |
---|
| 103 | + int (*rp_read_cfg)(struct altera_pcie *pcie, int where, |
---|
| 104 | + int size, u32 *value); |
---|
| 105 | + int (*rp_write_cfg)(struct altera_pcie *pcie, u8 busno, |
---|
| 106 | + int where, int size, u32 value); |
---|
| 107 | +}; |
---|
| 108 | + |
---|
| 109 | +struct altera_pcie_data { |
---|
| 110 | + const struct altera_pcie_ops *ops; |
---|
| 111 | + enum altera_pcie_version version; |
---|
| 112 | + u32 cap_offset; /* PCIe capability structure register offset */ |
---|
| 113 | + u32 cfgrd0; |
---|
| 114 | + u32 cfgrd1; |
---|
| 115 | + u32 cfgwr0; |
---|
| 116 | + u32 cfgwr1; |
---|
80 | 117 | }; |
---|
81 | 118 | |
---|
82 | 119 | struct tlp_rp_regpair_t { |
---|
.. | .. |
---|
99 | 136 | static bool altera_pcie_link_up(struct altera_pcie *pcie) |
---|
100 | 137 | { |
---|
101 | 138 | return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0); |
---|
| 139 | +} |
---|
| 140 | + |
---|
| 141 | +static bool s10_altera_pcie_link_up(struct altera_pcie *pcie) |
---|
| 142 | +{ |
---|
| 143 | + void __iomem *addr = S10_RP_CFG_ADDR(pcie, |
---|
| 144 | + pcie->pcie_data->cap_offset + |
---|
| 145 | + PCI_EXP_LNKSTA); |
---|
| 146 | + |
---|
| 147 | + return !!(readw(addr) & PCI_EXP_LNKSTA_DLLLA); |
---|
102 | 148 | } |
---|
103 | 149 | |
---|
104 | 150 | /* |
---|
.. | .. |
---|
128 | 174 | cra_writel(pcie, tlp_rp_regdata->ctrl, RP_TX_CNTRL); |
---|
129 | 175 | } |
---|
130 | 176 | |
---|
| 177 | +static void s10_tlp_write_tx(struct altera_pcie *pcie, u32 reg0, u32 ctrl) |
---|
| 178 | +{ |
---|
| 179 | + cra_writel(pcie, reg0, RP_TX_REG0); |
---|
| 180 | + cra_writel(pcie, ctrl, S10_RP_TX_CNTRL); |
---|
| 181 | +} |
---|
| 182 | + |
---|
131 | 183 | static bool altera_pcie_valid_device(struct altera_pcie *pcie, |
---|
132 | 184 | struct pci_bus *bus, int dev) |
---|
133 | 185 | { |
---|
134 | 186 | /* If there is no link, then there is no device */ |
---|
135 | 187 | if (bus->number != pcie->root_bus_nr) { |
---|
136 | | - if (!altera_pcie_link_up(pcie)) |
---|
| 188 | + if (!pcie->pcie_data->ops->get_link_status(pcie)) |
---|
137 | 189 | return false; |
---|
138 | 190 | } |
---|
139 | 191 | |
---|
.. | .. |
---|
141 | 193 | if (bus->number == pcie->root_bus_nr && dev > 0) |
---|
142 | 194 | return false; |
---|
143 | 195 | |
---|
144 | | - return true; |
---|
| 196 | + return true; |
---|
145 | 197 | } |
---|
146 | 198 | |
---|
147 | 199 | static int tlp_read_packet(struct altera_pcie *pcie, u32 *value) |
---|
.. | .. |
---|
183 | 235 | return PCIBIOS_DEVICE_NOT_FOUND; |
---|
184 | 236 | } |
---|
185 | 237 | |
---|
| 238 | +static int s10_tlp_read_packet(struct altera_pcie *pcie, u32 *value) |
---|
| 239 | +{ |
---|
| 240 | + u32 ctrl; |
---|
| 241 | + u32 comp_status; |
---|
| 242 | + u32 dw[4]; |
---|
| 243 | + u32 count; |
---|
| 244 | + struct device *dev = &pcie->pdev->dev; |
---|
| 245 | + |
---|
| 246 | + for (count = 0; count < TLP_LOOP; count++) { |
---|
| 247 | + ctrl = cra_readl(pcie, S10_RP_RXCPL_STATUS); |
---|
| 248 | + if (ctrl & RP_RXCPL_SOP) { |
---|
| 249 | + /* Read first DW */ |
---|
| 250 | + dw[0] = cra_readl(pcie, S10_RP_RXCPL_REG); |
---|
| 251 | + break; |
---|
| 252 | + } |
---|
| 253 | + |
---|
| 254 | + udelay(5); |
---|
| 255 | + } |
---|
| 256 | + |
---|
| 257 | + /* SOP detection failed, return error */ |
---|
| 258 | + if (count == TLP_LOOP) |
---|
| 259 | + return PCIBIOS_DEVICE_NOT_FOUND; |
---|
| 260 | + |
---|
| 261 | + count = 1; |
---|
| 262 | + |
---|
| 263 | + /* Poll for EOP */ |
---|
| 264 | + while (count < ARRAY_SIZE(dw)) { |
---|
| 265 | + ctrl = cra_readl(pcie, S10_RP_RXCPL_STATUS); |
---|
| 266 | + dw[count++] = cra_readl(pcie, S10_RP_RXCPL_REG); |
---|
| 267 | + if (ctrl & RP_RXCPL_EOP) { |
---|
| 268 | + comp_status = TLP_COMP_STATUS(dw[1]); |
---|
| 269 | + if (comp_status) |
---|
| 270 | + return PCIBIOS_DEVICE_NOT_FOUND; |
---|
| 271 | + |
---|
| 272 | + if (value && TLP_BYTE_COUNT(dw[1]) == sizeof(u32) && |
---|
| 273 | + count == 4) |
---|
| 274 | + *value = dw[3]; |
---|
| 275 | + |
---|
| 276 | + return PCIBIOS_SUCCESSFUL; |
---|
| 277 | + } |
---|
| 278 | + } |
---|
| 279 | + |
---|
| 280 | + dev_warn(dev, "Malformed TLP packet\n"); |
---|
| 281 | + |
---|
| 282 | + return PCIBIOS_DEVICE_NOT_FOUND; |
---|
| 283 | +} |
---|
| 284 | + |
---|
186 | 285 | static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers, |
---|
187 | 286 | u32 data, bool align) |
---|
188 | 287 | { |
---|
.. | .. |
---|
210 | 309 | tlp_write_tx(pcie, &tlp_rp_regdata); |
---|
211 | 310 | } |
---|
212 | 311 | |
---|
| 312 | +static void s10_tlp_write_packet(struct altera_pcie *pcie, u32 *headers, |
---|
| 313 | + u32 data, bool dummy) |
---|
| 314 | +{ |
---|
| 315 | + s10_tlp_write_tx(pcie, headers[0], RP_TX_SOP); |
---|
| 316 | + s10_tlp_write_tx(pcie, headers[1], 0); |
---|
| 317 | + s10_tlp_write_tx(pcie, headers[2], 0); |
---|
| 318 | + s10_tlp_write_tx(pcie, data, RP_TX_EOP); |
---|
| 319 | +} |
---|
| 320 | + |
---|
| 321 | +static void get_tlp_header(struct altera_pcie *pcie, u8 bus, u32 devfn, |
---|
| 322 | + int where, u8 byte_en, bool read, u32 *headers) |
---|
| 323 | +{ |
---|
| 324 | + u8 cfg; |
---|
| 325 | + u8 cfg0 = read ? pcie->pcie_data->cfgrd0 : pcie->pcie_data->cfgwr0; |
---|
| 326 | + u8 cfg1 = read ? pcie->pcie_data->cfgrd1 : pcie->pcie_data->cfgwr1; |
---|
| 327 | + u8 tag = read ? TLP_READ_TAG : TLP_WRITE_TAG; |
---|
| 328 | + |
---|
| 329 | + if (pcie->pcie_data->version == ALTERA_PCIE_V1) |
---|
| 330 | + cfg = (bus == pcie->root_bus_nr) ? cfg0 : cfg1; |
---|
| 331 | + else |
---|
| 332 | + cfg = (bus > S10_RP_SECONDARY(pcie)) ? cfg0 : cfg1; |
---|
| 333 | + |
---|
| 334 | + headers[0] = TLP_CFG_DW0(pcie, cfg); |
---|
| 335 | + headers[1] = TLP_CFG_DW1(pcie, tag, byte_en); |
---|
| 336 | + headers[2] = TLP_CFG_DW2(bus, devfn, where); |
---|
| 337 | +} |
---|
| 338 | + |
---|
213 | 339 | static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn, |
---|
214 | 340 | int where, u8 byte_en, u32 *value) |
---|
215 | 341 | { |
---|
216 | 342 | u32 headers[TLP_HDR_SIZE]; |
---|
217 | 343 | |
---|
218 | | - headers[0] = TLP_CFGRD_DW0(pcie, bus); |
---|
219 | | - headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); |
---|
220 | | - headers[2] = TLP_CFG_DW2(bus, devfn, where); |
---|
| 344 | + get_tlp_header(pcie, bus, devfn, where, byte_en, true, |
---|
| 345 | + headers); |
---|
221 | 346 | |
---|
222 | | - tlp_write_packet(pcie, headers, 0, false); |
---|
| 347 | + pcie->pcie_data->ops->tlp_write_pkt(pcie, headers, 0, false); |
---|
223 | 348 | |
---|
224 | | - return tlp_read_packet(pcie, value); |
---|
| 349 | + return pcie->pcie_data->ops->tlp_read_pkt(pcie, value); |
---|
225 | 350 | } |
---|
226 | 351 | |
---|
227 | 352 | static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn, |
---|
.. | .. |
---|
230 | 355 | u32 headers[TLP_HDR_SIZE]; |
---|
231 | 356 | int ret; |
---|
232 | 357 | |
---|
233 | | - headers[0] = TLP_CFGWR_DW0(pcie, bus); |
---|
234 | | - headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en); |
---|
235 | | - headers[2] = TLP_CFG_DW2(bus, devfn, where); |
---|
| 358 | + get_tlp_header(pcie, bus, devfn, where, byte_en, false, |
---|
| 359 | + headers); |
---|
236 | 360 | |
---|
237 | 361 | /* check alignment to Qword */ |
---|
238 | 362 | if ((where & 0x7) == 0) |
---|
239 | | - tlp_write_packet(pcie, headers, value, true); |
---|
| 363 | + pcie->pcie_data->ops->tlp_write_pkt(pcie, headers, |
---|
| 364 | + value, true); |
---|
240 | 365 | else |
---|
241 | | - tlp_write_packet(pcie, headers, value, false); |
---|
| 366 | + pcie->pcie_data->ops->tlp_write_pkt(pcie, headers, |
---|
| 367 | + value, false); |
---|
242 | 368 | |
---|
243 | | - ret = tlp_read_packet(pcie, NULL); |
---|
| 369 | + ret = pcie->pcie_data->ops->tlp_read_pkt(pcie, NULL); |
---|
244 | 370 | if (ret != PCIBIOS_SUCCESSFUL) |
---|
245 | 371 | return ret; |
---|
246 | 372 | |
---|
.. | .. |
---|
254 | 380 | return PCIBIOS_SUCCESSFUL; |
---|
255 | 381 | } |
---|
256 | 382 | |
---|
| 383 | +static int s10_rp_read_cfg(struct altera_pcie *pcie, int where, |
---|
| 384 | + int size, u32 *value) |
---|
| 385 | +{ |
---|
| 386 | + void __iomem *addr = S10_RP_CFG_ADDR(pcie, where); |
---|
| 387 | + |
---|
| 388 | + switch (size) { |
---|
| 389 | + case 1: |
---|
| 390 | + *value = readb(addr); |
---|
| 391 | + break; |
---|
| 392 | + case 2: |
---|
| 393 | + *value = readw(addr); |
---|
| 394 | + break; |
---|
| 395 | + default: |
---|
| 396 | + *value = readl(addr); |
---|
| 397 | + break; |
---|
| 398 | + } |
---|
| 399 | + |
---|
| 400 | + return PCIBIOS_SUCCESSFUL; |
---|
| 401 | +} |
---|
| 402 | + |
---|
| 403 | +static int s10_rp_write_cfg(struct altera_pcie *pcie, u8 busno, |
---|
| 404 | + int where, int size, u32 value) |
---|
| 405 | +{ |
---|
| 406 | + void __iomem *addr = S10_RP_CFG_ADDR(pcie, where); |
---|
| 407 | + |
---|
| 408 | + switch (size) { |
---|
| 409 | + case 1: |
---|
| 410 | + writeb(value, addr); |
---|
| 411 | + break; |
---|
| 412 | + case 2: |
---|
| 413 | + writew(value, addr); |
---|
| 414 | + break; |
---|
| 415 | + default: |
---|
| 416 | + writel(value, addr); |
---|
| 417 | + break; |
---|
| 418 | + } |
---|
| 419 | + |
---|
| 420 | + /* |
---|
| 421 | + * Monitor changes to PCI_PRIMARY_BUS register on root port |
---|
| 422 | + * and update local copy of root bus number accordingly. |
---|
| 423 | + */ |
---|
| 424 | + if (busno == pcie->root_bus_nr && where == PCI_PRIMARY_BUS) |
---|
| 425 | + pcie->root_bus_nr = value & 0xff; |
---|
| 426 | + |
---|
| 427 | + return PCIBIOS_SUCCESSFUL; |
---|
| 428 | +} |
---|
| 429 | + |
---|
257 | 430 | static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno, |
---|
258 | 431 | unsigned int devfn, int where, int size, |
---|
259 | 432 | u32 *value) |
---|
.. | .. |
---|
261 | 434 | int ret; |
---|
262 | 435 | u32 data; |
---|
263 | 436 | u8 byte_en; |
---|
| 437 | + |
---|
| 438 | + if (busno == pcie->root_bus_nr && pcie->pcie_data->ops->rp_read_cfg) |
---|
| 439 | + return pcie->pcie_data->ops->rp_read_cfg(pcie, where, |
---|
| 440 | + size, value); |
---|
264 | 441 | |
---|
265 | 442 | switch (size) { |
---|
266 | 443 | case 1: |
---|
.. | .. |
---|
301 | 478 | u32 data32; |
---|
302 | 479 | u32 shift = 8 * (where & 3); |
---|
303 | 480 | u8 byte_en; |
---|
| 481 | + |
---|
| 482 | + if (busno == pcie->root_bus_nr && pcie->pcie_data->ops->rp_write_cfg) |
---|
| 483 | + return pcie->pcie_data->ops->rp_write_cfg(pcie, busno, |
---|
| 484 | + where, size, value); |
---|
304 | 485 | |
---|
305 | 486 | switch (size) { |
---|
306 | 487 | case 1: |
---|
.. | .. |
---|
365 | 546 | int ret; |
---|
366 | 547 | |
---|
367 | 548 | ret = _altera_pcie_cfg_read(pcie, busno, devfn, |
---|
368 | | - PCIE_CAP_OFFSET + offset, sizeof(*value), |
---|
| 549 | + pcie->pcie_data->cap_offset + offset, |
---|
| 550 | + sizeof(*value), |
---|
369 | 551 | &data); |
---|
370 | 552 | *value = data; |
---|
371 | 553 | return ret; |
---|
.. | .. |
---|
375 | 557 | unsigned int devfn, int offset, u16 value) |
---|
376 | 558 | { |
---|
377 | 559 | return _altera_pcie_cfg_write(pcie, busno, devfn, |
---|
378 | | - PCIE_CAP_OFFSET + offset, sizeof(value), |
---|
| 560 | + pcie->pcie_data->cap_offset + offset, |
---|
| 561 | + sizeof(value), |
---|
379 | 562 | value); |
---|
380 | 563 | } |
---|
381 | 564 | |
---|
.. | .. |
---|
403 | 586 | /* Wait for link is up */ |
---|
404 | 587 | start_jiffies = jiffies; |
---|
405 | 588 | for (;;) { |
---|
406 | | - if (altera_pcie_link_up(pcie)) |
---|
| 589 | + if (pcie->pcie_data->ops->get_link_status(pcie)) |
---|
407 | 590 | break; |
---|
408 | 591 | |
---|
409 | 592 | if (time_after(jiffies, start_jiffies + LINK_UP_TIMEOUT)) { |
---|
.. | .. |
---|
418 | 601 | { |
---|
419 | 602 | u16 linkcap, linkstat, linkctl; |
---|
420 | 603 | |
---|
421 | | - if (!altera_pcie_link_up(pcie)) |
---|
| 604 | + if (!pcie->pcie_data->ops->get_link_status(pcie)) |
---|
422 | 605 | return; |
---|
423 | 606 | |
---|
424 | 607 | /* |
---|
.. | .. |
---|
486 | 669 | chained_irq_exit(chip, desc); |
---|
487 | 670 | } |
---|
488 | 671 | |
---|
489 | | -static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie) |
---|
490 | | -{ |
---|
491 | | - int err, res_valid = 0; |
---|
492 | | - struct device *dev = &pcie->pdev->dev; |
---|
493 | | - struct resource_entry *win; |
---|
494 | | - |
---|
495 | | - err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, |
---|
496 | | - &pcie->resources, NULL); |
---|
497 | | - if (err) |
---|
498 | | - return err; |
---|
499 | | - |
---|
500 | | - err = devm_request_pci_bus_resources(dev, &pcie->resources); |
---|
501 | | - if (err) |
---|
502 | | - goto out_release_res; |
---|
503 | | - |
---|
504 | | - resource_list_for_each_entry(win, &pcie->resources) { |
---|
505 | | - struct resource *res = win->res; |
---|
506 | | - |
---|
507 | | - if (resource_type(res) == IORESOURCE_MEM) |
---|
508 | | - res_valid |= !(res->flags & IORESOURCE_PREFETCH); |
---|
509 | | - } |
---|
510 | | - |
---|
511 | | - if (res_valid) |
---|
512 | | - return 0; |
---|
513 | | - |
---|
514 | | - dev_err(dev, "non-prefetchable memory resource required\n"); |
---|
515 | | - err = -EINVAL; |
---|
516 | | - |
---|
517 | | -out_release_res: |
---|
518 | | - pci_free_resource_list(&pcie->resources); |
---|
519 | | - return err; |
---|
520 | | -} |
---|
521 | | - |
---|
522 | 672 | static int altera_pcie_init_irq_domain(struct altera_pcie *pcie) |
---|
523 | 673 | { |
---|
524 | 674 | struct device *dev = &pcie->pdev->dev; |
---|
.. | .. |
---|
535 | 685 | return 0; |
---|
536 | 686 | } |
---|
537 | 687 | |
---|
| 688 | +static void altera_pcie_irq_teardown(struct altera_pcie *pcie) |
---|
| 689 | +{ |
---|
| 690 | + irq_set_chained_handler_and_data(pcie->irq, NULL, NULL); |
---|
| 691 | + irq_domain_remove(pcie->irq_domain); |
---|
| 692 | + irq_dispose_mapping(pcie->irq); |
---|
| 693 | +} |
---|
| 694 | + |
---|
538 | 695 | static int altera_pcie_parse_dt(struct altera_pcie *pcie) |
---|
539 | 696 | { |
---|
540 | | - struct device *dev = &pcie->pdev->dev; |
---|
541 | 697 | struct platform_device *pdev = pcie->pdev; |
---|
542 | | - struct resource *cra; |
---|
543 | 698 | |
---|
544 | | - cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra"); |
---|
545 | | - pcie->cra_base = devm_ioremap_resource(dev, cra); |
---|
| 699 | + pcie->cra_base = devm_platform_ioremap_resource_byname(pdev, "Cra"); |
---|
546 | 700 | if (IS_ERR(pcie->cra_base)) |
---|
547 | 701 | return PTR_ERR(pcie->cra_base); |
---|
548 | 702 | |
---|
| 703 | + if (pcie->pcie_data->version == ALTERA_PCIE_V2) { |
---|
| 704 | + pcie->hip_base = |
---|
| 705 | + devm_platform_ioremap_resource_byname(pdev, "Hip"); |
---|
| 706 | + if (IS_ERR(pcie->hip_base)) |
---|
| 707 | + return PTR_ERR(pcie->hip_base); |
---|
| 708 | + } |
---|
| 709 | + |
---|
549 | 710 | /* setup IRQ */ |
---|
550 | 711 | pcie->irq = platform_get_irq(pdev, 0); |
---|
551 | | - if (pcie->irq < 0) { |
---|
552 | | - dev_err(dev, "failed to get IRQ: %d\n", pcie->irq); |
---|
| 712 | + if (pcie->irq < 0) |
---|
553 | 713 | return pcie->irq; |
---|
554 | | - } |
---|
555 | 714 | |
---|
556 | 715 | irq_set_chained_handler_and_data(pcie->irq, altera_pcie_isr, pcie); |
---|
557 | 716 | return 0; |
---|
.. | .. |
---|
562 | 721 | altera_pcie_retrain(pcie); |
---|
563 | 722 | } |
---|
564 | 723 | |
---|
| 724 | +static const struct altera_pcie_ops altera_pcie_ops_1_0 = { |
---|
| 725 | + .tlp_read_pkt = tlp_read_packet, |
---|
| 726 | + .tlp_write_pkt = tlp_write_packet, |
---|
| 727 | + .get_link_status = altera_pcie_link_up, |
---|
| 728 | +}; |
---|
| 729 | + |
---|
| 730 | +static const struct altera_pcie_ops altera_pcie_ops_2_0 = { |
---|
| 731 | + .tlp_read_pkt = s10_tlp_read_packet, |
---|
| 732 | + .tlp_write_pkt = s10_tlp_write_packet, |
---|
| 733 | + .get_link_status = s10_altera_pcie_link_up, |
---|
| 734 | + .rp_read_cfg = s10_rp_read_cfg, |
---|
| 735 | + .rp_write_cfg = s10_rp_write_cfg, |
---|
| 736 | +}; |
---|
| 737 | + |
---|
| 738 | +static const struct altera_pcie_data altera_pcie_1_0_data = { |
---|
| 739 | + .ops = &altera_pcie_ops_1_0, |
---|
| 740 | + .cap_offset = 0x80, |
---|
| 741 | + .version = ALTERA_PCIE_V1, |
---|
| 742 | + .cfgrd0 = TLP_FMTTYPE_CFGRD0, |
---|
| 743 | + .cfgrd1 = TLP_FMTTYPE_CFGRD1, |
---|
| 744 | + .cfgwr0 = TLP_FMTTYPE_CFGWR0, |
---|
| 745 | + .cfgwr1 = TLP_FMTTYPE_CFGWR1, |
---|
| 746 | +}; |
---|
| 747 | + |
---|
| 748 | +static const struct altera_pcie_data altera_pcie_2_0_data = { |
---|
| 749 | + .ops = &altera_pcie_ops_2_0, |
---|
| 750 | + .version = ALTERA_PCIE_V2, |
---|
| 751 | + .cap_offset = 0x70, |
---|
| 752 | + .cfgrd0 = S10_TLP_FMTTYPE_CFGRD0, |
---|
| 753 | + .cfgrd1 = S10_TLP_FMTTYPE_CFGRD1, |
---|
| 754 | + .cfgwr0 = S10_TLP_FMTTYPE_CFGWR0, |
---|
| 755 | + .cfgwr1 = S10_TLP_FMTTYPE_CFGWR1, |
---|
| 756 | +}; |
---|
| 757 | + |
---|
| 758 | +static const struct of_device_id altera_pcie_of_match[] = { |
---|
| 759 | + {.compatible = "altr,pcie-root-port-1.0", |
---|
| 760 | + .data = &altera_pcie_1_0_data }, |
---|
| 761 | + {.compatible = "altr,pcie-root-port-2.0", |
---|
| 762 | + .data = &altera_pcie_2_0_data }, |
---|
| 763 | + {}, |
---|
| 764 | +}; |
---|
| 765 | + |
---|
565 | 766 | static int altera_pcie_probe(struct platform_device *pdev) |
---|
566 | 767 | { |
---|
567 | 768 | struct device *dev = &pdev->dev; |
---|
568 | 769 | struct altera_pcie *pcie; |
---|
569 | | - struct pci_bus *bus; |
---|
570 | | - struct pci_bus *child; |
---|
571 | 770 | struct pci_host_bridge *bridge; |
---|
572 | 771 | int ret; |
---|
| 772 | + const struct of_device_id *match; |
---|
573 | 773 | |
---|
574 | 774 | bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); |
---|
575 | 775 | if (!bridge) |
---|
.. | .. |
---|
577 | 777 | |
---|
578 | 778 | pcie = pci_host_bridge_priv(bridge); |
---|
579 | 779 | pcie->pdev = pdev; |
---|
| 780 | + platform_set_drvdata(pdev, pcie); |
---|
| 781 | + |
---|
| 782 | + match = of_match_device(altera_pcie_of_match, &pdev->dev); |
---|
| 783 | + if (!match) |
---|
| 784 | + return -ENODEV; |
---|
| 785 | + |
---|
| 786 | + pcie->pcie_data = match->data; |
---|
580 | 787 | |
---|
581 | 788 | ret = altera_pcie_parse_dt(pcie); |
---|
582 | 789 | if (ret) { |
---|
583 | 790 | dev_err(dev, "Parsing DT failed\n"); |
---|
584 | | - return ret; |
---|
585 | | - } |
---|
586 | | - |
---|
587 | | - INIT_LIST_HEAD(&pcie->resources); |
---|
588 | | - |
---|
589 | | - ret = altera_pcie_parse_request_of_pci_ranges(pcie); |
---|
590 | | - if (ret) { |
---|
591 | | - dev_err(dev, "Failed add resources\n"); |
---|
592 | 791 | return ret; |
---|
593 | 792 | } |
---|
594 | 793 | |
---|
.. | .. |
---|
604 | 803 | cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE); |
---|
605 | 804 | altera_pcie_host_init(pcie); |
---|
606 | 805 | |
---|
607 | | - list_splice_init(&pcie->resources, &bridge->windows); |
---|
608 | | - bridge->dev.parent = dev; |
---|
609 | 806 | bridge->sysdata = pcie; |
---|
610 | 807 | bridge->busnr = pcie->root_bus_nr; |
---|
611 | 808 | bridge->ops = &altera_pcie_ops; |
---|
612 | | - bridge->map_irq = of_irq_parse_and_map_pci; |
---|
613 | | - bridge->swizzle_irq = pci_common_swizzle; |
---|
614 | 809 | |
---|
615 | | - ret = pci_scan_root_bus_bridge(bridge); |
---|
616 | | - if (ret < 0) |
---|
617 | | - return ret; |
---|
618 | | - |
---|
619 | | - bus = bridge->bus; |
---|
620 | | - |
---|
621 | | - pci_assign_unassigned_bus_resources(bus); |
---|
622 | | - |
---|
623 | | - /* Configure PCI Express setting. */ |
---|
624 | | - list_for_each_entry(child, &bus->children, node) |
---|
625 | | - pcie_bus_configure_settings(child); |
---|
626 | | - |
---|
627 | | - pci_bus_add_devices(bus); |
---|
628 | | - return ret; |
---|
| 810 | + return pci_host_probe(bridge); |
---|
629 | 811 | } |
---|
630 | 812 | |
---|
631 | | -static const struct of_device_id altera_pcie_of_match[] = { |
---|
632 | | - { .compatible = "altr,pcie-root-port-1.0", }, |
---|
633 | | - {}, |
---|
634 | | -}; |
---|
| 813 | +static int altera_pcie_remove(struct platform_device *pdev) |
---|
| 814 | +{ |
---|
| 815 | + struct altera_pcie *pcie = platform_get_drvdata(pdev); |
---|
| 816 | + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); |
---|
| 817 | + |
---|
| 818 | + pci_stop_root_bus(bridge->bus); |
---|
| 819 | + pci_remove_root_bus(bridge->bus); |
---|
| 820 | + altera_pcie_irq_teardown(pcie); |
---|
| 821 | + |
---|
| 822 | + return 0; |
---|
| 823 | +} |
---|
635 | 824 | |
---|
636 | 825 | static struct platform_driver altera_pcie_driver = { |
---|
637 | 826 | .probe = altera_pcie_probe, |
---|
| 827 | + .remove = altera_pcie_remove, |
---|
638 | 828 | .driver = { |
---|
639 | 829 | .name = "altera-pcie", |
---|
640 | 830 | .of_match_table = altera_pcie_of_match, |
---|
641 | | - .suppress_bind_attrs = true, |
---|
642 | 831 | }, |
---|
643 | 832 | }; |
---|
644 | 833 | |
---|
645 | | -builtin_platform_driver(altera_pcie_driver); |
---|
| 834 | +MODULE_DEVICE_TABLE(of, altera_pcie_of_match); |
---|
| 835 | +module_platform_driver(altera_pcie_driver); |
---|
| 836 | +MODULE_LICENSE("GPL v2"); |
---|