diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2019-03-06 16:30:17 -0500 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2019-03-06 16:30:17 -0500 |
| commit | b6019755aa832f443483043fb76810aa5e96a002 (patch) | |
| tree | 454feb3caaebe564c77bfdf9721b013255e2308f /drivers | |
| parent | 7733f69288572c5f2b1c291e033401a13abd0bb3 (diff) | |
| parent | d13af797154f4e033a446ff759431c03e0f832d9 (diff) | |
Merge branch 'remotes/lorenzo/pci/altera'
- Extend altera to support Stratix 10 (Ley Foon Tan)
- Allow building altera driver on ARM64 (Ley Foon Tan)
* remotes/lorenzo/pci/altera:
dt-bindings: PCI: altera: Add altr,pcie-root-port-2.0
PCI: altera: Enable driver on ARM64
PCI: altera: Add Stratix 10 PCIe support
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pci/controller/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/pci/controller/pcie-altera.c | 270 |
2 files changed, 247 insertions, 25 deletions
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 6671946dbf66..6012f3059acd 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig | |||
| @@ -175,7 +175,7 @@ config PCIE_IPROC_MSI | |||
| 175 | 175 | ||
| 176 | config PCIE_ALTERA | 176 | config PCIE_ALTERA |
| 177 | bool "Altera PCIe controller" | 177 | bool "Altera PCIe controller" |
| 178 | depends on ARM || NIOS2 || COMPILE_TEST | 178 | depends on ARM || NIOS2 || ARM64 || COMPILE_TEST |
| 179 | help | 179 | help |
| 180 | Say Y here if you want to enable PCIe controller support on Altera | 180 | Say Y here if you want to enable PCIe controller support on Altera |
| 181 | FPGA. | 181 | FPGA. |
diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c index 7d05e51205b3..27edcebd1726 100644 --- a/drivers/pci/controller/pcie-altera.c +++ b/drivers/pci/controller/pcie-altera.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/irqchip/chained_irq.h> | 11 | #include <linux/irqchip/chained_irq.h> |
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/of_address.h> | 13 | #include <linux/of_address.h> |
| 14 | #include <linux/of_device.h> | ||
| 14 | #include <linux/of_irq.h> | 15 | #include <linux/of_irq.h> |
| 15 | #include <linux/of_pci.h> | 16 | #include <linux/of_pci.h> |
| 16 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
| @@ -37,7 +38,12 @@ | |||
| 37 | #define RP_LTSSM_MASK 0x1f | 38 | #define RP_LTSSM_MASK 0x1f |
| 38 | #define LTSSM_L0 0xf | 39 | #define LTSSM_L0 0xf |
| 39 | 40 | ||
| 40 | #define PCIE_CAP_OFFSET 0x80 | 41 | #define S10_RP_TX_CNTRL 0x2004 |
| 42 | #define S10_RP_RXCPL_REG 0x2008 | ||
| 43 | #define S10_RP_RXCPL_STATUS 0x200C | ||
| 44 | #define S10_RP_CFG_ADDR(pcie, reg) \ | ||
| 45 | (((pcie)->hip_base) + (reg) + (1 << 20)) | ||
| 46 | |||
| 41 | /* TLP configuration type 0 and 1 */ | 47 | /* TLP configuration type 0 and 1 */ |
| 42 | #define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ | 48 | #define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ |
| 43 | #define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ | 49 | #define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ |
| @@ -49,18 +55,19 @@ | |||
| 49 | #define RP_DEVFN 0 | 55 | #define RP_DEVFN 0 |
| 50 | #define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) | 56 | #define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) |
| 51 | #define TLP_CFGRD_DW0(pcie, bus) \ | 57 | #define TLP_CFGRD_DW0(pcie, bus) \ |
| 52 | ((((bus == pcie->root_bus_nr) ? TLP_FMTTYPE_CFGRD0 \ | 58 | ((((bus == pcie->root_bus_nr) ? pcie->pcie_data->cfgrd0 \ |
| 53 | : TLP_FMTTYPE_CFGRD1) << 24) | \ | 59 | : pcie->pcie_data->cfgrd1) << 24) | \ |
| 54 | TLP_PAYLOAD_SIZE) | 60 | TLP_PAYLOAD_SIZE) |
| 55 | #define TLP_CFGWR_DW0(pcie, bus) \ | 61 | #define TLP_CFGWR_DW0(pcie, bus) \ |
| 56 | ((((bus == pcie->root_bus_nr) ? TLP_FMTTYPE_CFGWR0 \ | 62 | ((((bus == pcie->root_bus_nr) ? pcie->pcie_data->cfgwr0 \ |
| 57 | : TLP_FMTTYPE_CFGWR1) << 24) | \ | 63 | : pcie->pcie_data->cfgwr1) << 24) | \ |
| 58 | TLP_PAYLOAD_SIZE) | 64 | TLP_PAYLOAD_SIZE) |
| 59 | #define TLP_CFG_DW1(pcie, tag, be) \ | 65 | #define TLP_CFG_DW1(pcie, tag, be) \ |
| 60 | (((TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN)) << 16) | (tag << 8) | (be)) | 66 | (((TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN)) << 16) | (tag << 8) | (be)) |
| 61 | #define TLP_CFG_DW2(bus, devfn, offset) \ | 67 | #define TLP_CFG_DW2(bus, devfn, offset) \ |
| 62 | (((bus) << 24) | ((devfn) << 16) | (offset)) | 68 | (((bus) << 24) | ((devfn) << 16) | (offset)) |
| 63 | #define TLP_COMP_STATUS(s) (((s) >> 13) & 7) | 69 | #define TLP_COMP_STATUS(s) (((s) >> 13) & 7) |
| 70 | #define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff) | ||
| 64 | #define TLP_HDR_SIZE 3 | 71 | #define TLP_HDR_SIZE 3 |
| 65 | #define TLP_LOOP 500 | 72 | #define TLP_LOOP 500 |
| 66 | 73 | ||
| @@ -69,14 +76,47 @@ | |||
| 69 | 76 | ||
| 70 | #define DWORD_MASK 3 | 77 | #define DWORD_MASK 3 |
| 71 | 78 | ||
| 79 | #define S10_TLP_FMTTYPE_CFGRD0 0x05 | ||
| 80 | #define S10_TLP_FMTTYPE_CFGRD1 0x04 | ||
| 81 | #define S10_TLP_FMTTYPE_CFGWR0 0x45 | ||
| 82 | #define S10_TLP_FMTTYPE_CFGWR1 0x44 | ||
| 83 | |||
| 84 | enum altera_pcie_version { | ||
| 85 | ALTERA_PCIE_V1 = 0, | ||
| 86 | ALTERA_PCIE_V2, | ||
| 87 | }; | ||
| 88 | |||
| 72 | struct altera_pcie { | 89 | struct altera_pcie { |
| 73 | struct platform_device *pdev; | 90 | struct platform_device *pdev; |
| 74 | void __iomem *cra_base; /* DT Cra */ | 91 | void __iomem *cra_base; |
| 92 | void __iomem *hip_base; | ||
| 75 | int irq; | 93 | int irq; |
| 76 | u8 root_bus_nr; | 94 | u8 root_bus_nr; |
| 77 | struct irq_domain *irq_domain; | 95 | struct irq_domain *irq_domain; |
| 78 | struct resource bus_range; | 96 | struct resource bus_range; |
| 79 | struct list_head resources; | 97 | struct list_head resources; |
| 98 | const struct altera_pcie_data *pcie_data; | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct altera_pcie_ops { | ||
| 102 | int (*tlp_read_pkt)(struct altera_pcie *pcie, u32 *value); | ||
| 103 | void (*tlp_write_pkt)(struct altera_pcie *pcie, u32 *headers, | ||
| 104 | u32 data, bool align); | ||
| 105 | bool (*get_link_status)(struct altera_pcie *pcie); | ||
| 106 | int (*rp_read_cfg)(struct altera_pcie *pcie, int where, | ||
| 107 | int size, u32 *value); | ||
| 108 | int (*rp_write_cfg)(struct altera_pcie *pcie, u8 busno, | ||
| 109 | int where, int size, u32 value); | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct altera_pcie_data { | ||
| 113 | const struct altera_pcie_ops *ops; | ||
| 114 | enum altera_pcie_version version; | ||
| 115 | u32 cap_offset; /* PCIe capability structure register offset */ | ||
| 116 | u32 cfgrd0; | ||
| 117 | u32 cfgrd1; | ||
| 118 | u32 cfgwr0; | ||
| 119 | u32 cfgwr1; | ||
| 80 | }; | 120 | }; |
| 81 | 121 | ||
| 82 | struct tlp_rp_regpair_t { | 122 | struct tlp_rp_regpair_t { |
| @@ -101,6 +141,15 @@ static bool altera_pcie_link_up(struct altera_pcie *pcie) | |||
| 101 | return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0); | 141 | return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0); |
| 102 | } | 142 | } |
| 103 | 143 | ||
| 144 | static bool s10_altera_pcie_link_up(struct altera_pcie *pcie) | ||
| 145 | { | ||
| 146 | void __iomem *addr = S10_RP_CFG_ADDR(pcie, | ||
| 147 | pcie->pcie_data->cap_offset + | ||
| 148 | PCI_EXP_LNKSTA); | ||
| 149 | |||
| 150 | return !!(readw(addr) & PCI_EXP_LNKSTA_DLLLA); | ||
| 151 | } | ||
| 152 | |||
| 104 | /* | 153 | /* |
| 105 | * Altera PCIe port uses BAR0 of RC's configuration space as the translation | 154 | * Altera PCIe port uses BAR0 of RC's configuration space as the translation |
| 106 | * from PCI bus to native BUS. Entire DDR region is mapped into PCIe space | 155 | * from PCI bus to native BUS. Entire DDR region is mapped into PCIe space |
| @@ -128,12 +177,18 @@ static void tlp_write_tx(struct altera_pcie *pcie, | |||
| 128 | cra_writel(pcie, tlp_rp_regdata->ctrl, RP_TX_CNTRL); | 177 | cra_writel(pcie, tlp_rp_regdata->ctrl, RP_TX_CNTRL); |
| 129 | } | 178 | } |
| 130 | 179 | ||
| 180 | static void s10_tlp_write_tx(struct altera_pcie *pcie, u32 reg0, u32 ctrl) | ||
| 181 | { | ||
| 182 | cra_writel(pcie, reg0, RP_TX_REG0); | ||
| 183 | cra_writel(pcie, ctrl, S10_RP_TX_CNTRL); | ||
| 184 | } | ||
| 185 | |||
| 131 | static bool altera_pcie_valid_device(struct altera_pcie *pcie, | 186 | static bool altera_pcie_valid_device(struct altera_pcie *pcie, |
| 132 | struct pci_bus *bus, int dev) | 187 | struct pci_bus *bus, int dev) |
| 133 | { | 188 | { |
| 134 | /* If there is no link, then there is no device */ | 189 | /* If there is no link, then there is no device */ |
| 135 | if (bus->number != pcie->root_bus_nr) { | 190 | if (bus->number != pcie->root_bus_nr) { |
| 136 | if (!altera_pcie_link_up(pcie)) | 191 | if (!pcie->pcie_data->ops->get_link_status(pcie)) |
| 137 | return false; | 192 | return false; |
| 138 | } | 193 | } |
| 139 | 194 | ||
| @@ -183,6 +238,53 @@ static int tlp_read_packet(struct altera_pcie *pcie, u32 *value) | |||
| 183 | return PCIBIOS_DEVICE_NOT_FOUND; | 238 | return PCIBIOS_DEVICE_NOT_FOUND; |
| 184 | } | 239 | } |
| 185 | 240 | ||
| 241 | static int s10_tlp_read_packet(struct altera_pcie *pcie, u32 *value) | ||
| 242 | { | ||
| 243 | u32 ctrl; | ||
| 244 | u32 comp_status; | ||
| 245 | u32 dw[4]; | ||
| 246 | u32 count; | ||
| 247 | struct device *dev = &pcie->pdev->dev; | ||
| 248 | |||
| 249 | for (count = 0; count < TLP_LOOP; count++) { | ||
| 250 | ctrl = cra_readl(pcie, S10_RP_RXCPL_STATUS); | ||
| 251 | if (ctrl & RP_RXCPL_SOP) { | ||
| 252 | /* Read first DW */ | ||
| 253 | dw[0] = cra_readl(pcie, S10_RP_RXCPL_REG); | ||
| 254 | break; | ||
| 255 | } | ||
| 256 | |||
| 257 | udelay(5); | ||
| 258 | } | ||
| 259 | |||
| 260 | /* SOP detection failed, return error */ | ||
| 261 | if (count == TLP_LOOP) | ||
| 262 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
| 263 | |||
| 264 | count = 1; | ||
| 265 | |||
| 266 | /* Poll for EOP */ | ||
| 267 | while (count < ARRAY_SIZE(dw)) { | ||
| 268 | ctrl = cra_readl(pcie, S10_RP_RXCPL_STATUS); | ||
| 269 | dw[count++] = cra_readl(pcie, S10_RP_RXCPL_REG); | ||
| 270 | if (ctrl & RP_RXCPL_EOP) { | ||
| 271 | comp_status = TLP_COMP_STATUS(dw[1]); | ||
| 272 | if (comp_status) | ||
| 273 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
| 274 | |||
| 275 | if (value && TLP_BYTE_COUNT(dw[1]) == sizeof(u32) && | ||
| 276 | count == 4) | ||
| 277 | *value = dw[3]; | ||
| 278 | |||
| 279 | return PCIBIOS_SUCCESSFUL; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | dev_warn(dev, "Malformed TLP packet\n"); | ||
| 284 | |||
| 285 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
| 286 | } | ||
| 287 | |||
| 186 | static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers, | 288 | static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers, |
| 187 | u32 data, bool align) | 289 | u32 data, bool align) |
| 188 | { | 290 | { |
| @@ -210,6 +312,15 @@ static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers, | |||
| 210 | tlp_write_tx(pcie, &tlp_rp_regdata); | 312 | tlp_write_tx(pcie, &tlp_rp_regdata); |
| 211 | } | 313 | } |
| 212 | 314 | ||
| 315 | static void s10_tlp_write_packet(struct altera_pcie *pcie, u32 *headers, | ||
| 316 | u32 data, bool dummy) | ||
| 317 | { | ||
| 318 | s10_tlp_write_tx(pcie, headers[0], RP_TX_SOP); | ||
| 319 | s10_tlp_write_tx(pcie, headers[1], 0); | ||
| 320 | s10_tlp_write_tx(pcie, headers[2], 0); | ||
| 321 | s10_tlp_write_tx(pcie, data, RP_TX_EOP); | ||
| 322 | } | ||
| 323 | |||
| 213 | static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn, | 324 | static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn, |
| 214 | int where, u8 byte_en, u32 *value) | 325 | int where, u8 byte_en, u32 *value) |
| 215 | { | 326 | { |
| @@ -219,9 +330,9 @@ static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn, | |||
| 219 | headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); | 330 | headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); |
| 220 | headers[2] = TLP_CFG_DW2(bus, devfn, where); | 331 | headers[2] = TLP_CFG_DW2(bus, devfn, where); |
| 221 | 332 | ||
| 222 | tlp_write_packet(pcie, headers, 0, false); | 333 | pcie->pcie_data->ops->tlp_write_pkt(pcie, headers, 0, false); |
| 223 | 334 | ||
| 224 | return tlp_read_packet(pcie, value); | 335 | return pcie->pcie_data->ops->tlp_read_pkt(pcie, value); |
| 225 | } | 336 | } |
| 226 | 337 | ||
| 227 | static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn, | 338 | static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn, |
| @@ -236,11 +347,13 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn, | |||
| 236 | 347 | ||
| 237 | /* check alignment to Qword */ | 348 | /* check alignment to Qword */ |
| 238 | if ((where & 0x7) == 0) | 349 | if ((where & 0x7) == 0) |
| 239 | tlp_write_packet(pcie, headers, value, true); | 350 | pcie->pcie_data->ops->tlp_write_pkt(pcie, headers, |
| 351 | value, true); | ||
| 240 | else | 352 | else |
| 241 | tlp_write_packet(pcie, headers, value, false); | 353 | pcie->pcie_data->ops->tlp_write_pkt(pcie, headers, |
| 354 | value, false); | ||
| 242 | 355 | ||
| 243 | ret = tlp_read_packet(pcie, NULL); | 356 | ret = pcie->pcie_data->ops->tlp_read_pkt(pcie, NULL); |
| 244 | if (ret != PCIBIOS_SUCCESSFUL) | 357 | if (ret != PCIBIOS_SUCCESSFUL) |
| 245 | return ret; | 358 | return ret; |
| 246 | 359 | ||
| @@ -254,6 +367,53 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn, | |||
| 254 | return PCIBIOS_SUCCESSFUL; | 367 | return PCIBIOS_SUCCESSFUL; |
| 255 | } | 368 | } |
| 256 | 369 | ||
| 370 | static int s10_rp_read_cfg(struct altera_pcie *pcie, int where, | ||
| 371 | int size, u32 *value) | ||
| 372 | { | ||
| 373 | void __iomem *addr = S10_RP_CFG_ADDR(pcie, where); | ||
| 374 | |||
| 375 | switch (size) { | ||
| 376 | case 1: | ||
| 377 | *value = readb(addr); | ||
| 378 | break; | ||
| 379 | case 2: | ||
| 380 | *value = readw(addr); | ||
| 381 | break; | ||
| 382 | default: | ||
| 383 | *value = readl(addr); | ||
| 384 | break; | ||
| 385 | } | ||
| 386 | |||
| 387 | return PCIBIOS_SUCCESSFUL; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int s10_rp_write_cfg(struct altera_pcie *pcie, u8 busno, | ||
| 391 | int where, int size, u32 value) | ||
| 392 | { | ||
| 393 | void __iomem *addr = S10_RP_CFG_ADDR(pcie, where); | ||
| 394 | |||
| 395 | switch (size) { | ||
| 396 | case 1: | ||
| 397 | writeb(value, addr); | ||
| 398 | break; | ||
| 399 | case 2: | ||
| 400 | writew(value, addr); | ||
| 401 | break; | ||
| 402 | default: | ||
| 403 | writel(value, addr); | ||
| 404 | break; | ||
| 405 | } | ||
| 406 | |||
| 407 | /* | ||
| 408 | * Monitor changes to PCI_PRIMARY_BUS register on root port | ||
| 409 | * and update local copy of root bus number accordingly. | ||
| 410 | */ | ||
| 411 | if (busno == pcie->root_bus_nr && where == PCI_PRIMARY_BUS) | ||
| 412 | pcie->root_bus_nr = value & 0xff; | ||
| 413 | |||
| 414 | return PCIBIOS_SUCCESSFUL; | ||
| 415 | } | ||
| 416 | |||
| 257 | static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno, | 417 | static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno, |
| 258 | unsigned int devfn, int where, int size, | 418 | unsigned int devfn, int where, int size, |
| 259 | u32 *value) | 419 | u32 *value) |
| @@ -262,6 +422,10 @@ static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno, | |||
| 262 | u32 data; | 422 | u32 data; |
| 263 | u8 byte_en; | 423 | u8 byte_en; |
| 264 | 424 | ||
| 425 | if (busno == pcie->root_bus_nr && pcie->pcie_data->ops->rp_read_cfg) | ||
| 426 | return pcie->pcie_data->ops->rp_read_cfg(pcie, where, | ||
| 427 | size, value); | ||
| 428 | |||
| 265 | switch (size) { | 429 | switch (size) { |
| 266 | case 1: | 430 | case 1: |
| 267 | byte_en = 1 << (where & 3); | 431 | byte_en = 1 << (where & 3); |
| @@ -302,6 +466,10 @@ static int _altera_pcie_cfg_write(struct altera_pcie *pcie, u8 busno, | |||
| 302 | u32 shift = 8 * (where & 3); | 466 | u32 shift = 8 * (where & 3); |
| 303 | u8 byte_en; | 467 | u8 byte_en; |
| 304 | 468 | ||
| 469 | if (busno == pcie->root_bus_nr && pcie->pcie_data->ops->rp_write_cfg) | ||
| 470 | return pcie->pcie_data->ops->rp_write_cfg(pcie, busno, | ||
| 471 | where, size, value); | ||
| 472 | |||
| 305 | switch (size) { | 473 | switch (size) { |
| 306 | case 1: | 474 | case 1: |
| 307 | data32 = (value & 0xff) << shift; | 475 | data32 = (value & 0xff) << shift; |
| @@ -365,7 +533,8 @@ static int altera_read_cap_word(struct altera_pcie *pcie, u8 busno, | |||
| 365 | int ret; | 533 | int ret; |
| 366 | 534 | ||
| 367 | ret = _altera_pcie_cfg_read(pcie, busno, devfn, | 535 | ret = _altera_pcie_cfg_read(pcie, busno, devfn, |
| 368 | PCIE_CAP_OFFSET + offset, sizeof(*value), | 536 | pcie->pcie_data->cap_offset + offset, |
| 537 | sizeof(*value), | ||
| 369 | &data); | 538 | &data); |
| 370 | *value = data; | 539 | *value = data; |
| 371 | return ret; | 540 | return ret; |
| @@ -375,7 +544,8 @@ static int altera_write_cap_word(struct altera_pcie *pcie, u8 busno, | |||
| 375 | unsigned int devfn, int offset, u16 value) | 544 | unsigned int devfn, int offset, u16 value) |
| 376 | { | 545 | { |
| 377 | return _altera_pcie_cfg_write(pcie, busno, devfn, | 546 | return _altera_pcie_cfg_write(pcie, busno, devfn, |
| 378 | PCIE_CAP_OFFSET + offset, sizeof(value), | 547 | pcie->pcie_data->cap_offset + offset, |
| 548 | sizeof(value), | ||
| 379 | value); | 549 | value); |
| 380 | } | 550 | } |
| 381 | 551 | ||
| @@ -403,7 +573,7 @@ static void altera_wait_link_retrain(struct altera_pcie *pcie) | |||
| 403 | /* Wait for link is up */ | 573 | /* Wait for link is up */ |
| 404 | start_jiffies = jiffies; | 574 | start_jiffies = jiffies; |
| 405 | for (;;) { | 575 | for (;;) { |
| 406 | if (altera_pcie_link_up(pcie)) | 576 | if (pcie->pcie_data->ops->get_link_status(pcie)) |
| 407 | break; | 577 | break; |
| 408 | 578 | ||
| 409 | if (time_after(jiffies, start_jiffies + LINK_UP_TIMEOUT)) { | 579 | if (time_after(jiffies, start_jiffies + LINK_UP_TIMEOUT)) { |
| @@ -418,7 +588,7 @@ static void altera_pcie_retrain(struct altera_pcie *pcie) | |||
| 418 | { | 588 | { |
| 419 | u16 linkcap, linkstat, linkctl; | 589 | u16 linkcap, linkstat, linkctl; |
| 420 | 590 | ||
| 421 | if (!altera_pcie_link_up(pcie)) | 591 | if (!pcie->pcie_data->ops->get_link_status(pcie)) |
| 422 | return; | 592 | return; |
| 423 | 593 | ||
| 424 | /* | 594 | /* |
| @@ -540,12 +710,20 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie) | |||
| 540 | struct device *dev = &pcie->pdev->dev; | 710 | struct device *dev = &pcie->pdev->dev; |
| 541 | struct platform_device *pdev = pcie->pdev; | 711 | struct platform_device *pdev = pcie->pdev; |
| 542 | struct resource *cra; | 712 | struct resource *cra; |
| 713 | struct resource *hip; | ||
| 543 | 714 | ||
| 544 | cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra"); | 715 | cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra"); |
| 545 | pcie->cra_base = devm_ioremap_resource(dev, cra); | 716 | pcie->cra_base = devm_ioremap_resource(dev, cra); |
| 546 | if (IS_ERR(pcie->cra_base)) | 717 | if (IS_ERR(pcie->cra_base)) |
| 547 | return PTR_ERR(pcie->cra_base); | 718 | return PTR_ERR(pcie->cra_base); |
| 548 | 719 | ||
| 720 | if (pcie->pcie_data->version == ALTERA_PCIE_V2) { | ||
| 721 | hip = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Hip"); | ||
| 722 | pcie->hip_base = devm_ioremap_resource(&pdev->dev, hip); | ||
| 723 | if (IS_ERR(pcie->hip_base)) | ||
| 724 | return PTR_ERR(pcie->hip_base); | ||
| 725 | } | ||
| 726 | |||
| 549 | /* setup IRQ */ | 727 | /* setup IRQ */ |
| 550 | pcie->irq = platform_get_irq(pdev, 0); | 728 | pcie->irq = platform_get_irq(pdev, 0); |
| 551 | if (pcie->irq < 0) { | 729 | if (pcie->irq < 0) { |
| @@ -562,6 +740,48 @@ static void altera_pcie_host_init(struct altera_pcie *pcie) | |||
| 562 | altera_pcie_retrain(pcie); | 740 | altera_pcie_retrain(pcie); |
| 563 | } | 741 | } |
| 564 | 742 | ||
| 743 | static const struct altera_pcie_ops altera_pcie_ops_1_0 = { | ||
| 744 | .tlp_read_pkt = tlp_read_packet, | ||
| 745 | .tlp_write_pkt = tlp_write_packet, | ||
| 746 | .get_link_status = altera_pcie_link_up, | ||
| 747 | }; | ||
| 748 | |||
| 749 | static const struct altera_pcie_ops altera_pcie_ops_2_0 = { | ||
| 750 | .tlp_read_pkt = s10_tlp_read_packet, | ||
| 751 | .tlp_write_pkt = s10_tlp_write_packet, | ||
| 752 | .get_link_status = s10_altera_pcie_link_up, | ||
| 753 | .rp_read_cfg = s10_rp_read_cfg, | ||
| 754 | .rp_write_cfg = s10_rp_write_cfg, | ||
| 755 | }; | ||
| 756 | |||
| 757 | static const struct altera_pcie_data altera_pcie_1_0_data = { | ||
| 758 | .ops = &altera_pcie_ops_1_0, | ||
| 759 | .cap_offset = 0x80, | ||
| 760 | .version = ALTERA_PCIE_V1, | ||
| 761 | .cfgrd0 = TLP_FMTTYPE_CFGRD0, | ||
| 762 | .cfgrd1 = TLP_FMTTYPE_CFGRD1, | ||
| 763 | .cfgwr0 = TLP_FMTTYPE_CFGWR0, | ||
| 764 | .cfgwr1 = TLP_FMTTYPE_CFGWR1, | ||
| 765 | }; | ||
| 766 | |||
| 767 | static const struct altera_pcie_data altera_pcie_2_0_data = { | ||
| 768 | .ops = &altera_pcie_ops_2_0, | ||
| 769 | .version = ALTERA_PCIE_V2, | ||
| 770 | .cap_offset = 0x70, | ||
| 771 | .cfgrd0 = S10_TLP_FMTTYPE_CFGRD0, | ||
| 772 | .cfgrd1 = S10_TLP_FMTTYPE_CFGRD1, | ||
| 773 | .cfgwr0 = S10_TLP_FMTTYPE_CFGWR0, | ||
| 774 | .cfgwr1 = S10_TLP_FMTTYPE_CFGWR1, | ||
| 775 | }; | ||
| 776 | |||
| 777 | static const struct of_device_id altera_pcie_of_match[] = { | ||
| 778 | {.compatible = "altr,pcie-root-port-1.0", | ||
| 779 | .data = &altera_pcie_1_0_data }, | ||
| 780 | {.compatible = "altr,pcie-root-port-2.0", | ||
| 781 | .data = &altera_pcie_2_0_data }, | ||
| 782 | {}, | ||
| 783 | }; | ||
| 784 | |||
| 565 | static int altera_pcie_probe(struct platform_device *pdev) | 785 | static int altera_pcie_probe(struct platform_device *pdev) |
| 566 | { | 786 | { |
| 567 | struct device *dev = &pdev->dev; | 787 | struct device *dev = &pdev->dev; |
| @@ -570,6 +790,7 @@ static int altera_pcie_probe(struct platform_device *pdev) | |||
| 570 | struct pci_bus *child; | 790 | struct pci_bus *child; |
| 571 | struct pci_host_bridge *bridge; | 791 | struct pci_host_bridge *bridge; |
| 572 | int ret; | 792 | int ret; |
| 793 | const struct of_device_id *match; | ||
| 573 | 794 | ||
| 574 | bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); | 795 | bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); |
| 575 | if (!bridge) | 796 | if (!bridge) |
| @@ -578,6 +799,12 @@ static int altera_pcie_probe(struct platform_device *pdev) | |||
| 578 | pcie = pci_host_bridge_priv(bridge); | 799 | pcie = pci_host_bridge_priv(bridge); |
| 579 | pcie->pdev = pdev; | 800 | pcie->pdev = pdev; |
| 580 | 801 | ||
| 802 | match = of_match_device(altera_pcie_of_match, &pdev->dev); | ||
| 803 | if (!match) | ||
| 804 | return -ENODEV; | ||
| 805 | |||
| 806 | pcie->pcie_data = match->data; | ||
| 807 | |||
| 581 | ret = altera_pcie_parse_dt(pcie); | 808 | ret = altera_pcie_parse_dt(pcie); |
| 582 | if (ret) { | 809 | if (ret) { |
| 583 | dev_err(dev, "Parsing DT failed\n"); | 810 | dev_err(dev, "Parsing DT failed\n"); |
| @@ -628,11 +855,6 @@ static int altera_pcie_probe(struct platform_device *pdev) | |||
| 628 | return ret; | 855 | return ret; |
| 629 | } | 856 | } |
| 630 | 857 | ||
| 631 | static const struct of_device_id altera_pcie_of_match[] = { | ||
| 632 | { .compatible = "altr,pcie-root-port-1.0", }, | ||
| 633 | {}, | ||
| 634 | }; | ||
| 635 | |||
| 636 | static struct platform_driver altera_pcie_driver = { | 858 | static struct platform_driver altera_pcie_driver = { |
| 637 | .probe = altera_pcie_probe, | 859 | .probe = altera_pcie_probe, |
| 638 | .driver = { | 860 | .driver = { |
