* [PATCH v3 0/8] Marvell EBU PCIe driver @ 2014-07-30 8:39 Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 1/8] bus: mvebu: fix resource size handling Sebastian Hesselbarth ` (9 more replies) 0 siblings, 10 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox Third and hopefully last round of the Marvell EBU PCIe driver patch set. Compared to v2, I disabled MBUS error propagation on Armada 370/XP as it hangs the SoC on unanswered PCIe accesses. Also, 64b BARs are now properly handled. I added two more pci core fixes that move PCI device registration after BAR setup and temporarely disable PCI_COMMAND' IO and MEM bits during BAR setup. The MVEBU PCIe driver now gained support for Armada XP PHY setup which is anticipating a minor DT binding tweak to allow more than one marvell,pcie-lane passed to the node. Also, PCI address space does now also start at where we see it on MBUS. Some devices were not so happy about starting at 0. The whole series has been tested on Armada 370 Mirabox and Armada XP Lenovo Iomega ix4-300d (not mainline yet). Sebastian Sebastian Hesselbarth (8): bus: mvebu: fix resource size handling ARM: mvebu: armada-370-xp: disable MBUS error propagation pci: pci_scan_bus: respect 64b BARs pci: register device after BAR setup pci: ensure device does ignore BAR mangling pci: set auto-incremented bus number of: pci: import of_pci_get_devfn() pci: mvebu: Add PCIe driver arch/arm/Kconfig | 1 + arch/arm/mach-mvebu/armada-370-xp.c | 6 + .../mach-mvebu/include/mach/armada-370-xp-regs.h | 2 + drivers/bus/mvebu-mbus.c | 8 +- drivers/of/Kconfig | 6 + drivers/of/Makefile | 1 + drivers/of/of_pci.c | 27 ++ drivers/pci/Kconfig | 6 + drivers/pci/Makefile | 2 + drivers/pci/pci-mvebu-phy.c | 208 ++++++++++ drivers/pci/pci-mvebu.c | 446 +++++++++++++++++++++ drivers/pci/pci-mvebu.h | 37 ++ drivers/pci/pci.c | 28 +- include/linux/pci.h | 12 +- include/of_pci.h | 17 + 15 files changed, 790 insertions(+), 17 deletions(-) create mode 100644 drivers/of/of_pci.c create mode 100644 drivers/pci/pci-mvebu-phy.c create mode 100644 drivers/pci/pci-mvebu.c create mode 100644 drivers/pci/pci-mvebu.h create mode 100644 include/of_pci.h --- Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/8] bus: mvebu: fix resource size handling 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 2/8] ARM: mvebu: armada-370-xp: disable MBUS error propagation Sebastian Hesselbarth ` (8 subsequent siblings) 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox A resource_size is defined as res->end - res->start + 1. Marvell MBUS driver gets some ranges from DT as start and size but mis-calculates end of range. This fixes 4 occurences of those mistakes. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Acked-by: Lucas Stach <l.stach@pengutronix.de> --- Changelog: v2->v3: - still none v1->v2: - none Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- drivers/bus/mvebu-mbus.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 11e3777a6094..c67646f61722 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -187,7 +187,7 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus, phys_addr_t base, size_t size, u8 target, u8 attr) { - u64 end = (u64)base + size; + u64 end = (u64)base + size - 1; int win; for (win = 0; win < mbus->soc->num_wins; win++) { @@ -203,7 +203,7 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus, if (!enabled) continue; - wend = wbase + wsize; + wend = wbase + wsize - 1; /* * Check if the current window overlaps with the @@ -661,7 +661,7 @@ static void mvebu_mbus_get_pcie_resources(struct device_node *np, reg, ARRAY_SIZE(reg)); if (!ret) { mem->start = reg[0]; - mem->end = mem->start + reg[1]; + mem->end = mem->start + reg[1] - 1; mem->flags = IORESOURCE_MEM; } @@ -669,7 +669,7 @@ static void mvebu_mbus_get_pcie_resources(struct device_node *np, reg, ARRAY_SIZE(reg)); if (!ret) { io->start = reg[0]; - io->end = io->start + reg[1]; + io->end = io->start + reg[1] - 1; io->flags = IORESOURCE_IO; } } -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/8] ARM: mvebu: armada-370-xp: disable MBUS error propagation 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 1/8] bus: mvebu: fix resource size handling Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 3/8] pci: pci_scan_bus: respect 64b BARs Sebastian Hesselbarth ` (7 subsequent siblings) 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox Accessing MBUS windows not backed-up by e.g. PCIe devices will hang the SoC. Disable MBUS error propagation back to CPU allows to read 0xffffffff instead of hanging the SoC. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> --- Changelog: v2->v3: - new patch Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- arch/arm/mach-mvebu/armada-370-xp.c | 6 ++++++ arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index e416a3876539..4eda6d539aab 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -46,10 +46,16 @@ static inline void armada_370_xp_memory_find(unsigned long *phys_base, static int armada_370_xp_init_soc(void) { unsigned long phys_base, phys_size; + u32 reg; barebox_set_model("Marvell Armada 370/XP"); barebox_set_hostname("armada"); + /* Disable MBUS error propagation */ + reg = readl(ARMADA_370_XP_FABRIC_BASE); + reg &= ~BIT(8); + writel(reg, ARMADA_370_XP_FABRIC_BASE); + armada_370_xp_memory_find(&phys_base, &phys_size); arm_add_mem_device("ram0", phys_base, phys_size); diff --git a/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h b/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h index 5fd16e5733bb..ccc687c03b6e 100644 --- a/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h +++ b/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h @@ -42,6 +42,8 @@ #define DDR_SIZE_CS_SHIFT 2 #define DDR_SIZE_MASK 0xff000000 +#define ARMADA_370_XP_FABRIC_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x20200) + #define ARMADA_370_XP_TIMER_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x20300) #endif /* __MACH_MVEBU_DOVE_REGS_H */ -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 3/8] pci: pci_scan_bus: respect 64b BARs 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 1/8] bus: mvebu: fix resource size handling Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 2/8] ARM: mvebu: armada-370-xp: disable MBUS error propagation Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 4/8] pci: register device after BAR setup Sebastian Hesselbarth ` (6 subsequent siblings) 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox In PCI 64-bit BARs span two 32-bit BARs, therefore if BAR type indicates a 64-bit BAR we have to skip the next BAR register. While at it, also set proper IORESOURCE flags for I/O and 32b MEM. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Acked-by: Lucas Stach <l.stach@pengutronix.de> --- Changelog: v2->v3: - IORESOURCE_MEM_64 is ORed with IORESOURCE_MEM - write 0 to upper 64b BAR register v1->v2: - set resource flags for all resources found (Suggested by Lucas Stach) - use MEM_64 resource flag for BAR64 detection (Suggested by Lucas Stach) Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- drivers/pci/pci.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 3d88b0ff5fd0..83d44fc103f7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -211,19 +211,29 @@ unsigned int pci_scan_bus(struct pci_bus *bus) size = -(mask & 0xfffffffe); DBG(" PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size); pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_io); + dev->resource[bar].flags = IORESOURCE_IO; last_addr = last_io; last_io += size; - } else { /* MEM */ size = -(mask & 0xfffffff0); DBG(" PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size); pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem); + dev->resource[bar].flags = IORESOURCE_MEM; last_addr = last_mem; last_mem += size; + + if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) { + dev->resource[bar].flags |= IORESOURCE_MEM_64; + pci_write_config_dword(dev, + PCI_BASE_ADDRESS_1 + bar * 4, 0); + } } dev->resource[bar].start = last_addr; dev->resource[bar].end = last_addr + size - 1; + if (dev->resource[bar].flags & IORESOURCE_MEM_64) + bar++; } } -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 4/8] pci: register device after BAR setup 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth ` (2 preceding siblings ...) 2014-07-30 8:39 ` [PATCH v3 3/8] pci: pci_scan_bus: respect 64b BARs Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 5/8] pci: ensure device does ignore BAR mangling Sebastian Hesselbarth ` (5 subsequent siblings) 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox As soon as pci_register_device is called, a potential driver will access its registers. This requires BARs to be set up properly, so move pci_register_device after BAR setup. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> --- Changelog: v2->v3: - new patch Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- drivers/pci/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 83d44fc103f7..f58e2c98f185 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -186,9 +186,6 @@ unsigned int pci_scan_bus(struct pci_bus *bus) DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn, dev->vendor, dev->device); - list_add_tail(&dev->bus_list, &bus->devices); - pci_register_device(dev); - if (class == PCI_CLASS_BRIDGE_HOST) { DBG("PCI: skip pci host bridge\n"); continue; @@ -235,6 +232,9 @@ unsigned int pci_scan_bus(struct pci_bus *bus) if (dev->resource[bar].flags & IORESOURCE_MEM_64) bar++; } + + list_add_tail(&dev->bus_list, &bus->devices); + pci_register_device(dev); } /* -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 5/8] pci: ensure device does ignore BAR mangling 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth ` (3 preceding siblings ...) 2014-07-30 8:39 ` [PATCH v3 4/8] pci: register device after BAR setup Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 6/8] pci: set auto-incremented bus number Sebastian Hesselbarth ` (4 subsequent siblings) 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox Disable access to PCI devices I/O and memory regions while mangling BAR registers. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> --- Changelog: v2->v3: - new patch Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- drivers/pci/pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f58e2c98f185..b64f25d13282 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -191,6 +191,10 @@ unsigned int pci_scan_bus(struct pci_bus *bus) continue; } + pci_read_config_byte(dev, PCI_COMMAND, &cmd); + pci_write_config_byte(dev, PCI_COMMAND, + cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + for (bar = 0; bar < 6; bar++) { resource_size_t last_addr; @@ -233,6 +237,7 @@ unsigned int pci_scan_bus(struct pci_bus *bus) bar++; } + pci_write_config_byte(dev, PCI_COMMAND, cmd); list_add_tail(&dev->bus_list, &bus->devices); pci_register_device(dev); } -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 6/8] pci: set auto-incremented bus number 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth ` (4 preceding siblings ...) 2014-07-30 8:39 ` [PATCH v3 5/8] pci: ensure device does ignore BAR mangling Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 7/8] of: pci: import of_pci_get_devfn() Sebastian Hesselbarth ` (3 subsequent siblings) 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox When using more than one PCI bus, we have to assign unique numbers to each bus. Use an auto-incremented bus index and assign it to each registered bus. Also, allow the PCI host controller to update internal registers by calling set_busno with assigned bus number. While at it, add pci_controller struct to set_busno callback, add a back reference to pci_controller to pci_bus, and clean up unused left-overs from Linux import. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> --- Changelog: v2->v3: - none v1->v2: - set pci_controller reference to bus->bus (Suggested by Lucas Stach) - auto-increment pci_bus number for each registered bus - call pci_controller set_busno() before pci_scan_bus - remove sysdata and proc_dir_entry from pci_dev and pci_bus - pass pci_controller to set_busno callback Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- drivers/pci/pci.c | 5 +++++ include/linux/pci.h | 12 +++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b64f25d13282..a1b768025484 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -11,6 +11,7 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head; LIST_HEAD(pci_root_buses); EXPORT_SYMBOL(pci_root_buses); +static u8 bus_index; static struct pci_bus *pci_alloc_bus(void) { @@ -36,10 +37,14 @@ void register_pci_controller(struct pci_controller *hose) bus = pci_alloc_bus(); hose->bus = bus; + bus->host = hose; bus->ops = hose->pci_ops; bus->resource[0] = hose->mem_resource; bus->resource[1] = hose->io_resource; + bus->number = bus_index++; + if (hose->set_busno) + hose->set_busno(hose, bus->number); pci_scan_bus(bus); list_add_tail(&bus->node, &pci_root_buses); diff --git a/include/linux/pci.h b/include/linux/pci.h index 6caed01c9939..0ec1320b2f71 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -91,9 +91,6 @@ struct pci_dev { struct list_head bus_list; /* node in per-bus list */ struct pci_bus *bus; /* bus this device is on */ struct pci_bus *subordinate; /* bus this device bridges to */ - - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */ struct pci_slot *slot; /* Physical slot this device is in */ struct device_d dev; @@ -118,6 +115,7 @@ struct pci_dev { #define to_pci_dev(dev) container_of(dev, struct pci_dev, dev) struct pci_bus { + struct pci_controller *host; /* associated host controller */ struct list_head node; /* node in list of buses */ struct list_head children; /* list of child buses */ struct list_head devices; /* list of devices on this bus */ @@ -126,8 +124,6 @@ struct pci_bus { struct list_head resources; /* address space routed to this bus */ struct pci_ops *ops; /* configuration access functions */ - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */ unsigned char number; /* bus number */ unsigned char primary; /* number of primary bridge */ @@ -167,10 +163,8 @@ struct pci_controller { unsigned int index; - /* Optional access methods for reading/writing the bus number - of the PCI controller */ - int (*get_busno)(void); - void (*set_busno)(int busno); + /* Optional access method for writing the bus number */ + void (*set_busno)(struct pci_controller *host, int busno); }; struct pci_driver { -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 7/8] of: pci: import of_pci_get_devfn() 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth ` (5 preceding siblings ...) 2014-07-30 8:39 ` [PATCH v3 6/8] pci: set auto-incremented bus number Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 8/8] pci: mvebu: Add PCIe driver Sebastian Hesselbarth ` (2 subsequent siblings) 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox Marvell MVEBU PCIe driver requires of_pcie_get_devfn(), import it from Linux. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Acked-by: Lucas Stach <l.stach@pengutronix.de> --- Changelog: v2->v3: - still none v1->v2: - none Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- drivers/of/Kconfig | 6 ++++++ drivers/of/Makefile | 1 + drivers/of/of_pci.c | 27 +++++++++++++++++++++++++++ include/of_pci.h | 17 +++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 drivers/of/of_pci.c create mode 100644 include/of_pci.h diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 2b28cf3fb425..81955063d70c 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -27,6 +27,12 @@ config OF_GPIO depends on OFDEVICE def_bool y +config OF_PCI + bool + depends on PCI + help + OpenFirmware PCI bus accessors + config OF_BAREBOX_DRIVERS depends on OFDEVICE depends on ENV_HANDLING diff --git a/drivers/of/Makefile b/drivers/of/Makefile index c883e516c834..0dc2f8d63ed0 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,6 +1,7 @@ obj-y += address.o base.o fdt.o platform.o obj-$(CONFIG_OFTREE_MEM_GENERIC) += mem_generic.o obj-$(CONFIG_OF_GPIO) += of_gpio.o +obj-$(CONFIG_OF_PCI) += of_pci.o obj-y += partition.o obj-y += of_net.o obj-$(CONFIG_MTD) += of_mtd.o diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c new file mode 100644 index 000000000000..2d0fbd2e5f69 --- /dev/null +++ b/drivers/of/of_pci.c @@ -0,0 +1,27 @@ +#include <common.h> +#include <errno.h> +#include <of.h> +#include <of_pci.h> + +/** + * of_pci_get_devfn() - Get device and function numbers for a device node + * @np: device node + * + * Parses a standard 5-cell PCI resource and returns an 8-bit value that can + * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device + * and function numbers respectively. On error a negative error code is + * returned. + */ +int of_pci_get_devfn(struct device_node *np) +{ + unsigned int size; + const __be32 *reg; + + reg = of_get_property(np, "reg", &size); + + if (!reg || size < 5 * sizeof(__be32)) + return -EINVAL; + + return (be32_to_cpup(reg) >> 8) & 0xff; +} +EXPORT_SYMBOL_GPL(of_pci_get_devfn); diff --git a/include/of_pci.h b/include/of_pci.h new file mode 100644 index 000000000000..c95cb0135ae0 --- /dev/null +++ b/include/of_pci.h @@ -0,0 +1,17 @@ +#ifndef __OF_PCI_H +#define __OF_PCI_H + +#include <linux/pci.h> + +#ifdef CONFIG_OF_PCI +int of_pci_get_devfn(struct device_node *np); + +#else +static inline int of_pci_get_devfn(struct device_node *np) +{ + return -EINVAL; +} + +#endif + +#endif -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 8/8] pci: mvebu: Add PCIe driver 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth ` (6 preceding siblings ...) 2014-07-30 8:39 ` [PATCH v3 7/8] of: pci: import of_pci_get_devfn() Sebastian Hesselbarth @ 2014-07-30 8:39 ` Sebastian Hesselbarth 2014-07-30 9:16 ` [PATCH v3 0/8] Marvell EBU " Lucas Stach 2014-07-31 5:30 ` Sascha Hauer 9 siblings, 0 replies; 11+ messages in thread From: Sebastian Hesselbarth @ 2014-07-30 8:39 UTC (permalink / raw) To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox This adds a PCI driver for the controllers found on Marvell MVEBU SoCs. Besides the functional driver itself, it also adds SoC specific PHY setup required for PCIe. Currently, only Armada 370 is fully supported. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Acked-by: Lucas Stach <l.stach@pengutronix.de> --- Changelog: v2->v3: - clarify Armada 370 PHY setup - add Armada XP PHY setup for x1 and x4 - map PCI address spaces to non-0 addresses - anticipate DT binding update for marvell,pcie-lane with multiple lanes and build up a lane mask v1->v2: - rework on top of pci controller changes - properly check for devfn passed from DT in mvebu_pcie_indirect_{rd,wr}_conf Cc: barebox@lists.infradead.org Cc: Antony Pavlov <antonynpavlov@gmail.com> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> --- arch/arm/Kconfig | 1 + drivers/pci/Kconfig | 6 + drivers/pci/Makefile | 2 + drivers/pci/pci-mvebu-phy.c | 208 +++++++++++++++++++++ drivers/pci/pci-mvebu.c | 446 ++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci-mvebu.h | 37 ++++ 6 files changed, 700 insertions(+) create mode 100644 drivers/pci/pci-mvebu-phy.c create mode 100644 drivers/pci/pci-mvebu.c create mode 100644 drivers/pci/pci-mvebu.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8465d4a7f739..be5c7bd1981b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -93,6 +93,7 @@ config ARCH_MVEBU select GPIOLIB select HAS_DEBUG_LL select HAVE_PBL_MULTI_IMAGES + select HW_HAS_PCI select MVEBU_MBUS select OFTREE select OF_ADDRESS_PCI diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 9e4659270d25..d17a1510821f 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -24,6 +24,12 @@ config PCI_DEBUG When in doubt, say N. +config PCI_MVEBU + bool "Marvell EBU PCIe driver" + depends on ARCH_MVEBU + select OF_PCI + select PCI + endmenu endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index edac1a53de78..442353173c9e 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -6,3 +6,5 @@ obj-y += pci.o bus.o pci_iomap.o ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG CPPFLAGS += $(ccflags-y) + +obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o pci-mvebu-phy.o diff --git a/drivers/pci/pci-mvebu-phy.c b/drivers/pci/pci-mvebu-phy.c new file mode 100644 index 000000000000..55a1d39f62b9 --- /dev/null +++ b/drivers/pci/pci-mvebu-phy.c @@ -0,0 +1,208 @@ +/* + * SoC specific PCIe PHY setup for Marvell MVEBU SoCs + * + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * + * based on Marvell BSP code (C) Marvell International Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <common.h> +#include <of.h> +#include <of_address.h> + +#include "pci-mvebu.h" + +static u32 mvebu_pcie_phy_indirect(void __iomem *phybase, u8 lane, + u8 off, u16 val, bool is_read) +{ + u32 reg = (lane << 24) | (off << 16) | val; + + if (is_read) + reg |= BIT(31); + writel(reg, phybase); + + return (is_read) ? readl(phybase) & 0xffff : 0; +} + +static inline u32 mvebu_pcie_phy_read(void __iomem *phybase, u8 lane, + u8 off) +{ + return mvebu_pcie_phy_indirect(phybase, lane, off, 0, true); +} + +static inline void mvebu_pcie_phy_write(void __iomem *phybase, u8 lane, + u8 off, u16 val) +{ + mvebu_pcie_phy_indirect(phybase, lane, off, val, false); +} + +/* PCIe registers */ +#define ARMADA_370_XP_PCIE_LINK_CAPS 0x6c +#define MAX_LINK_WIDTH_MASK MAX_LINK_WIDTH(0x3f) +#define MAX_LINK_WIDTH(x) ((x) << 4) +#define MAX_LINK_SPEED_MASK 0xf +#define MAX_LINK_SPEED_5G0 0x2 +#define MAX_LINK_SPEED_2G5 0x1 +#define ARMADA_370_XP_PHY_OFFSET 0x1b00 +/* System Control registers */ +#define ARMADA_370_XP_SOC_CTRL 0x04 +#define PCIE1_QUADX1_EN BIT(8) /* Armada XP */ +#define PCIE0_QUADX1_EN BIT(7) /* Armada XP */ +#define PCIE0_EN BIT(0) +#define ARMADA_370_XP_SERDES03_SEL 0x70 +#define ARMADA_370_XP_SERDES47_SEL 0x74 +#define SERDES(x, v) ((v) << ((x) * 0x4)) +#define SERDES_MASK(x) SERDES((x), 0xf) + +int armada_370_phy_setup(struct mvebu_pcie *pcie) +{ + struct device_node *np = of_find_compatible_node(NULL, NULL, + "marvell,armada-370-xp-system-controller"); + void __iomem *sysctrl = of_iomap(np, 0); + void __iomem *phybase = pcie->base + ARMADA_370_XP_PHY_OFFSET; + u32 reg; + + if (!sysctrl) + return -ENODEV; + + /* Enable PEX */ + reg = readl(sysctrl + ARMADA_370_XP_SOC_CTRL); + reg |= PCIE0_EN << pcie->port; + writel(reg, sysctrl + ARMADA_370_XP_SOC_CTRL); + + /* Set SERDES selector */ + reg = readl(sysctrl + ARMADA_370_XP_SERDES03_SEL); + reg &= ~SERDES_MASK(pcie->port); + reg |= SERDES(pcie->port, 0x1); + writel(reg, sysctrl + ARMADA_370_XP_SERDES03_SEL); + + /* BTS #232 - PCIe clock (undocumented) */ + writel(0x00000077, sysctrl + 0x2f0); + + /* Set x1 Link Capability */ + reg = readl(pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS); + reg &= ~(MAX_LINK_WIDTH_MASK | MAX_LINK_SPEED_MASK); + reg |= MAX_LINK_WIDTH(0x1) | MAX_LINK_SPEED_5G0; + writel(reg, pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS); + + /* PEX pipe configuration */ + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0025); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc3, 0x000f); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc8, 0x0005); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xd0, 0x0100); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xd1, 0x3014); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc5, 0x011f); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x80, 0x1000); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x81, 0x0011); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x0f, 0x2a21); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x45, 0x00df); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x4f, 0x6219); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x01, 0xfc60); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x46, 0x0000); + + reg = mvebu_pcie_phy_read(phybase, pcie->lane, 0x48) & ~0x4; + mvebu_pcie_phy_write(phybase, pcie->lane, 0x48, reg & 0xffff); + + mvebu_pcie_phy_write(phybase, pcie->lane, 0x02, 0x0040); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0024); + + mdelay(15); + + return 0; +} + +/* + * MV78230: 2 PCIe units Gen2.0, one unit 1x4 or 4x1, one unit 1x1 + * MV78260: 3 PCIe units Gen2.0, two units 1x4 or 4x1, one unit 1x1/1x4 + * MV78460: 4 PCIe units Gen2.0, two units 1x4 or 4x1, two units 1x1/1x4 + */ +#define ARMADA_XP_COMM_PHY_REFCLK_ALIGN 0xf8 +#define REFCLK_ALIGN(x) (0xf << ((x) * 0x4)) +int armada_xp_phy_setup(struct mvebu_pcie *pcie) +{ + struct device_node *np = of_find_compatible_node(NULL, NULL, + "marvell,armada-370-xp-system-controller"); + void __iomem *sysctrl = of_iomap(np, 0); + void __iomem *phybase = pcie->base + ARMADA_370_XP_PHY_OFFSET; + u32 serdes_off = (pcie->port < 2) ? ARMADA_370_XP_SERDES03_SEL : + ARMADA_370_XP_SERDES47_SEL; + bool single_x4 = (pcie->lane_mask == 0xf); + u32 reg, mask; + + if (!sysctrl) + return -ENODEV; + + /* Prepare PEX */ + reg = readl(sysctrl + ARMADA_370_XP_SOC_CTRL); + reg &= ~(PCIE0_EN << pcie->port); + writel(reg, sysctrl + ARMADA_370_XP_SOC_CTRL); + + if (pcie->port < 2) { + mask = PCIE0_QUADX1_EN << pcie->port; + if (single_x4) + reg &= ~mask; + else + reg |= mask; + } + reg |= PCIE0_EN << pcie->port; + writel(reg, sysctrl + ARMADA_370_XP_SOC_CTRL); + + /* Set SERDES selector */ + reg = readl(sysctrl + serdes_off); + for (mask = pcie->lane_mask; mask;) { + u32 l = ffs(mask)-1; + u32 off = 4 * (pcie->port % 2); + reg &= ~SERDES_MASK(off + l); + reg |= SERDES(off + l, 0x1); + mask &= ~BIT(l); + } + reg &= ~SERDES_MASK(pcie->port % 2); + reg |= SERDES(pcie->port % 2, 0x1); + writel(reg, sysctrl + serdes_off); + + /* Reference Clock Alignment for 1x4 */ + reg = readl(sysctrl + ARMADA_XP_COMM_PHY_REFCLK_ALIGN); + if (single_x4) + reg |= REFCLK_ALIGN(pcie->port); + else + reg &= ~REFCLK_ALIGN(pcie->port); + writel(reg, sysctrl + ARMADA_XP_COMM_PHY_REFCLK_ALIGN); + + /* Set x1/x4 Link Capability */ + reg = readl(pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS); + reg &= ~(MAX_LINK_WIDTH_MASK | MAX_LINK_SPEED_MASK); + if (single_x4) + reg |= MAX_LINK_WIDTH(0x4); + else + reg |= MAX_LINK_WIDTH(0x1); + reg |= MAX_LINK_SPEED_5G0; + writel(reg, pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS); + + /* PEX pipe configuration */ + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0025); + if (single_x4) { + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc2, 0x0200); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc3, 0x0001); + } else { + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc2, 0x0000); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc3, 0x000f); + } + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc8, 0x0005); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x01, 0xfc60); + mvebu_pcie_phy_write(phybase, pcie->lane, 0x46, 0x0000); + + mvebu_pcie_phy_write(phybase, pcie->lane, 0x02, 0x0040); + mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0024); + if (single_x4) + mvebu_pcie_phy_write(phybase, pcie->lane, 0x48, 0x1080); + else + mvebu_pcie_phy_write(phybase, pcie->lane, 0x48, 0x9080); + + mdelay(15); + + return 0; +} diff --git a/drivers/pci/pci-mvebu.c b/drivers/pci/pci-mvebu.c new file mode 100644 index 000000000000..45befbba2098 --- /dev/null +++ b/drivers/pci/pci-mvebu.c @@ -0,0 +1,446 @@ +/* + * PCIe driver for Marvell MVEBU SoCs + * + * Based on Linux drivers/pci/host/pci-mvebu.c + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <common.h> +#include <gpio.h> +#include <init.h> +#include <io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/mbus.h> +#include <linux/pci_regs.h> +#include <malloc.h> +#include <of_address.h> +#include <of_gpio.h> +#include <of_pci.h> +#include <sizes.h> + +#include "pci-mvebu.h" + +/* PCIe unit register offsets */ +#define PCIE_DEV_ID_OFF 0x0000 +#define PCIE_CMD_OFF 0x0004 +#define PCIE_DEV_REV_OFF 0x0008 +#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3)) +#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3)) +#define PCIE_HEADER_LOG_4_OFF 0x0128 +#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4)) +#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4)) +#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4)) +#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4)) +#define PCIE_WIN5_CTRL_OFF 0x1880 +#define PCIE_WIN5_BASE_OFF 0x1884 +#define PCIE_WIN5_REMAP_OFF 0x188c +#define PCIE_CONF_ADDR_OFF 0x18f8 +#define PCIE_CONF_ADDR_EN BIT(31) +#define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc)) +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 16) +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11) +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8) +#define PCIE_CONF_ADDR(bus, devfn, where) \ + (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \ + PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where) | \ + PCIE_CONF_ADDR_EN) +#define PCIE_CONF_DATA_OFF 0x18fc +#define PCIE_MASK_OFF 0x1910 +#define PCIE_MASK_ENABLE_INTS (0xf << 24) +#define PCIE_CTRL_OFF 0x1a00 +#define PCIE_CTRL_X1_MODE BIT(0) +#define PCIE_STAT_OFF 0x1a04 +#define PCIE_STAT_BUS (0xff << 8) +#define PCIE_STAT_DEV (0x1f << 16) +#define PCIE_STAT_LINK_DOWN BIT(0) +#define PCIE_DEBUG_CTRL 0x1a60 +#define PCIE_DEBUG_SOFT_RESET BIT(20) + +#define to_pcie(_hc) container_of(_hc, struct mvebu_pcie, pci) + +/* + * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped + * into SoCs address space. Each controller will map 32M of MEM + * and 64K of I/O space when registered. + */ +static void __iomem *mvebu_pcie_membase = IOMEM(0xe0000000); +static void __iomem *mvebu_pcie_iobase = IOMEM(0xffe00000); + +static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) +{ + return !(readl(pcie->base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); +} + +static void mvebu_pcie_set_local_bus_nr(struct pci_controller *host, int busno) +{ + struct mvebu_pcie *pcie = to_pcie(host); + u32 stat; + + stat = readl(pcie->base + PCIE_STAT_OFF); + stat &= ~PCIE_STAT_BUS; + stat |= busno << 8; + writel(stat, pcie->base + PCIE_STAT_OFF); +} + +static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno) +{ + u32 stat; + + stat = readl(pcie->base + PCIE_STAT_OFF); + stat &= ~PCIE_STAT_DEV; + stat |= devno << 16; + writel(stat, pcie->base + PCIE_STAT_OFF); +} + +static int mvebu_pcie_indirect_rd_conf(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 *val) +{ + struct mvebu_pcie *pcie = to_pcie(bus->host); + + /* Skip all requests not directed to device behind bridge */ + if (devfn != pcie->devfn || !mvebu_pcie_link_up(pcie)) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + writel(PCIE_CONF_ADDR(bus->number, devfn, where), + pcie->base + PCIE_CONF_ADDR_OFF); + + *val = readl(pcie->base + PCIE_CONF_DATA_OFF); + + if (size == 1) + *val = (*val >> (8 * (where & 3))) & 0xff; + else if (size == 2) + *val = (*val >> (8 * (where & 3))) & 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int mvebu_pcie_indirect_wr_conf(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 val) +{ + struct mvebu_pcie *pcie = to_pcie(bus->host); + u32 _val, shift = 8 * (where & 3); + + /* Skip all requests not directed to device behind bridge */ + if (devfn != pcie->devfn || !mvebu_pcie_link_up(pcie)) + return PCIBIOS_DEVICE_NOT_FOUND; + + writel(PCIE_CONF_ADDR(bus->number, devfn, where), + pcie->base + PCIE_CONF_ADDR_OFF); + _val = readl(pcie->base + PCIE_CONF_DATA_OFF); + + if (size == 4) + _val = val; + else if (size == 2) + _val = (_val & ~(0xffff << shift)) | ((val & 0xffff) << shift); + else if (size == 1) + _val = (_val & ~(0xff << shift)) | ((val & 0xff) << shift); + else + return PCIBIOS_BAD_REGISTER_NUMBER; + + writel(_val, pcie->base + PCIE_CONF_DATA_OFF); + + return PCIBIOS_SUCCESSFUL; +} + +static int mvebu_pcie_res_start(struct pci_bus *bus, resource_size_t res_addr) +{ + struct mvebu_pcie *pcie = to_pcie(bus->host); + + return (int)pcie->membase + (res_addr & (resource_size(&pcie->mem)-1)); +} + +static struct pci_ops mvebu_pcie_indirect_ops = { + .read = mvebu_pcie_indirect_rd_conf, + .write = mvebu_pcie_indirect_wr_conf, + .res_start = mvebu_pcie_res_start, +}; + +/* + * Setup PCIE BARs and Address Decode Wins: + * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks + * WIN[0-3] -> DRAM bank[0-3] + */ +static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) +{ + const struct mbus_dram_target_info *dram = mvebu_mbus_dram_info(); + u32 size; + int i; + + /* First, disable and clear BARs and windows. */ + for (i = 1; i < 3; i++) { + writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i)); + writel(0, pcie->base + PCIE_BAR_LO_OFF(i)); + writel(0, pcie->base + PCIE_BAR_HI_OFF(i)); + } + + for (i = 0; i < 5; i++) { + writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i)); + writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i)); + writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i)); + } + + writel(0, pcie->base + PCIE_WIN5_CTRL_OFF); + writel(0, pcie->base + PCIE_WIN5_BASE_OFF); + writel(0, pcie->base + PCIE_WIN5_REMAP_OFF); + + /* Setup windows for DDR banks. Count total DDR size on the fly. */ + size = 0; + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + + writel(cs->base & 0xffff0000, + pcie->base + PCIE_WIN04_BASE_OFF(i)); + writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i)); + writel(((cs->size - 1) & 0xffff0000) | + (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + pcie->base + PCIE_WIN04_CTRL_OFF(i)); + + size += cs->size; + } + + /* Round up 'size' to the nearest power of two. */ + if ((size & (size - 1)) != 0) + size = 1 << fls(size); + + /* Setup BAR[1] to all DRAM banks. */ + writel(dram->cs[0].base, pcie->base + PCIE_BAR_LO_OFF(1)); + writel(0, pcie->base + PCIE_BAR_HI_OFF(1)); + writel(((size - 1) & 0xffff0000) | 1, + pcie->base + PCIE_BAR_CTRL_OFF(1)); +} + +#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03) +#define DT_TYPE_IO 0x1 +#define DT_TYPE_MEM32 0x2 +#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF) +#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) + +static int mvebu_get_target_attr(struct device_node *np, int devfn, + unsigned long type, unsigned int *target, unsigned int *attr) +{ + const int na = 3, ns = 2; + const __be32 *range; + int rlen, nranges, rangesz, pna, i; + + *target = -1; + *attr = -1; + + range = of_get_property(np, "ranges", &rlen); + if (!range) + return -EINVAL; + + pna = of_n_addr_cells(np); + rangesz = pna + na + ns; + nranges = rlen / sizeof(__be32) / rangesz; + + for (i = 0; i < nranges; i++) { + u32 flags = of_read_number(range, 1); + u32 slot = of_read_number(range + 1, 1); + u64 cpuaddr = of_read_number(range + na, pna); + unsigned long rtype; + + if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO) + rtype = IORESOURCE_IO; + else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32) + rtype = IORESOURCE_MEM; + + if (slot == PCI_SLOT(devfn) && type == rtype) { + *target = DT_CPUADDR_TO_TARGET(cpuaddr); + *attr = DT_CPUADDR_TO_ATTR(cpuaddr); + return 0; + } + + range += rangesz; + } + + return -ENOENT; +} + +static struct mvebu_pcie *mvebu_pcie_port_probe(struct device_d *dev, + struct device_node *np) +{ + struct mvebu_pcie *pcie; + struct clk *clk; + enum of_gpio_flags flags; + struct property *prop; + const __be32 *p; + int reset_gpio; + u32 u, port, lane, lane_mask, devfn; + int mem_target, mem_attr; + int io_target, io_attr; + int ret; + + if (of_property_read_u32(np, "marvell,pcie-port", &port)) { + dev_err(dev, "missing pcie-port property\n"); + return ERR_PTR(-EINVAL); + } + + lane_mask = 0; + of_property_for_each_u32(np, "marvell,pcie-lane", prop, p, u) + lane_mask |= BIT(u); + lane = ffs(lane_mask)-1; + + devfn = of_pci_get_devfn(np); + if (devfn < 0) { + dev_err(dev, "unable to parse devfn\n"); + return ERR_PTR(-EINVAL); + } + + if (mvebu_get_target_attr(dev->device_node, devfn, IORESOURCE_MEM, + &mem_target, &mem_attr)) { + dev_err(dev, "unable to get target/attr for mem window\n"); + return ERR_PTR(-EINVAL); + } + + /* I/O windows are optional */ + mvebu_get_target_attr(dev->device_node, devfn, IORESOURCE_IO, + &io_target, &io_attr); + + reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags); + if (gpio_is_valid(reset_gpio)) { + int reset_active_low = flags & OF_GPIO_ACTIVE_LOW; + char *reset_name = asprintf("pcie%d.%d-reset", port, lane); + u32 reset_udelay = 20000; + + of_property_read_u32(np, "reset-delay-us", &reset_udelay); + + ret = gpio_request_one(reset_gpio, GPIOF_DIR_OUT, reset_name); + if (ret) + return ERR_PTR(ret); + + /* Ensure a full reset cycle*/ + gpio_set_value(reset_gpio, 1 ^ reset_active_low); + udelay(reset_udelay); + gpio_set_value(reset_gpio, 0 ^ reset_active_low); + udelay(reset_udelay); + } + + pcie = xzalloc(sizeof(*pcie)); + pcie->port = port; + pcie->lane = lane; + pcie->lane_mask = lane_mask; + pcie->name = asprintf("pcie%d.%d", port, lane); + pcie->devfn = devfn; + + pcie->base = of_iomap(np, 0); + if (!pcie->base) { + dev_err(dev, "PCIe%d.%d unable to map registers\n", port, lane); + free(pcie); + return ERR_PTR(-ENOMEM); + } + + pcie->membase = mvebu_pcie_membase; + pcie->mem.start = (u32)mvebu_pcie_membase; + pcie->mem.end = pcie->mem.start + SZ_32M - 1; + if (mvebu_mbus_add_window_remap_by_id(mem_target, mem_attr, + (resource_size_t)pcie->membase, resource_size(&pcie->mem), + (u32)pcie->mem.start)) { + dev_err(dev, "PCIe%d.%d unable to add mbus window for mem at %08x+%08x", + port, lane, (u32)pcie->mem.start, resource_size(&pcie->mem)); + + free(pcie); + return ERR_PTR(-EBUSY); + } + mvebu_pcie_membase += SZ_32M; + + if (io_target >= 0 && io_attr >= 0) { + pcie->iobase = mvebu_pcie_iobase; + pcie->io.start = (u32)mvebu_pcie_iobase; + pcie->io.end = pcie->io.start + SZ_64K - 1; + + mvebu_mbus_add_window_remap_by_id(io_target, io_attr, + (resource_size_t)pcie->iobase, resource_size(&pcie->io), + (u32)pcie->io.start); + mvebu_pcie_iobase += SZ_64K; + } + + clk = of_clk_get(np, 0); + if (!IS_ERR(clk)) + clk_enable(clk); + + pcie->pci.set_busno = mvebu_pcie_set_local_bus_nr; + pcie->pci.pci_ops = &mvebu_pcie_indirect_ops; + pcie->pci.mem_resource = &pcie->mem; + pcie->pci.io_resource = &pcie->io; + + return pcie; +} + +static struct mvebu_pcie_ops __maybe_unused armada_370_ops = { + .phy_setup = armada_370_phy_setup, +}; + +static struct mvebu_pcie_ops __maybe_unused armada_xp_ops = { + .phy_setup = armada_xp_phy_setup, +}; + +static struct of_device_id mvebu_pcie_dt_ids[] = { +#if defined(CONFIG_ARCH_ARMADA_XP) + { .compatible = "marvell,armada-xp-pcie", .data = (u32)&armada_xp_ops, }, +#endif +#if defined(CONFIG_ARCH_ARMADA_370) + { .compatible = "marvell,armada-370-pcie", .data = (u32)&armada_370_ops, }, +#endif +#if defined(CONFIG_ARCH_DOVE) + { .compatible = "marvell,dove-pcie", }, +#endif +#if defined(CONFIG_ARCH_KIRKWOOD) + { .compatible = "marvell,kirkwood-pcie", }, +#endif + { }, +}; + +static int mvebu_pcie_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + const struct of_device_id *match = of_match_node(mvebu_pcie_dt_ids, np); + struct mvebu_pcie_ops *ops = (struct mvebu_pcie_ops *)match->data; + struct device_node *pnp; + + for_each_child_of_node(np, pnp) { + struct mvebu_pcie *pcie; + u32 reg; + + if (!of_device_is_available(pnp)) + continue; + + pcie = mvebu_pcie_port_probe(dev, pnp); + if (IS_ERR(pcie)) + continue; + + if (ops && ops->phy_setup) + ops->phy_setup(pcie); + + mvebu_pcie_set_local_dev_nr(pcie, 0); + mvebu_pcie_setup_wins(pcie); + + /* Master + slave enable. */ + reg = readl(pcie->base + PCIE_CMD_OFF); + reg |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + reg |= PCI_COMMAND_MASTER; + writel(reg, pcie->base + PCIE_CMD_OFF); + + /* Disable interrupts */ + reg = readl(pcie->base + PCIE_MASK_OFF); + reg &= ~PCIE_MASK_ENABLE_INTS; + writel(reg, pcie->base + PCIE_MASK_OFF); + + register_pci_controller(&pcie->pci); + } + + return 0; +} + +static struct driver_d mvebu_pcie_driver = { + .name = "mvebu-pcie", + .probe = mvebu_pcie_probe, + .of_compatible = mvebu_pcie_dt_ids, +}; +device_platform_driver(mvebu_pcie_driver); diff --git a/drivers/pci/pci-mvebu.h b/drivers/pci/pci-mvebu.h new file mode 100644 index 000000000000..8ced9fefca94 --- /dev/null +++ b/drivers/pci/pci-mvebu.h @@ -0,0 +1,37 @@ +/* + * PCIe include for Marvell MVEBU SoCs + * + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MVEBU_PCI_H +#define __MVEBU_PCI_H + +#include <linux/pci.h> + +struct mvebu_pcie { + struct pci_controller pci; + char *name; + void __iomem *base; + void __iomem *membase; + struct resource mem; + void __iomem *iobase; + struct resource io; + u32 port; + u32 lane; + u32 lane_mask; + int devfn; +}; + +struct mvebu_pcie_ops { + int (*phy_setup)(struct mvebu_pcie *pcie); +}; + +int armada_370_phy_setup(struct mvebu_pcie *pcie); +int armada_xp_phy_setup(struct mvebu_pcie *pcie); + +#endif -- 2.0.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 0/8] Marvell EBU PCIe driver 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth ` (7 preceding siblings ...) 2014-07-30 8:39 ` [PATCH v3 8/8] pci: mvebu: Add PCIe driver Sebastian Hesselbarth @ 2014-07-30 9:16 ` Lucas Stach 2014-07-31 5:30 ` Sascha Hauer 9 siblings, 0 replies; 11+ messages in thread From: Lucas Stach @ 2014-07-30 9:16 UTC (permalink / raw) To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox Am Mittwoch, den 30.07.2014, 10:39 +0200 schrieb Sebastian Hesselbarth: > Third and hopefully last round of the Marvell EBU PCIe driver patch > set. Compared to v2, I disabled MBUS error propagation on Armada > 370/XP as it hangs the SoC on unanswered PCIe accesses. Also, 64b > BARs are now properly handled. I added two more pci core fixes that > move PCI device registration after BAR setup and temporarely disable > PCI_COMMAND' IO and MEM bits during BAR setup. > > The MVEBU PCIe driver now gained support for Armada XP PHY setup > which is anticipating a minor DT binding tweak to allow more than > one marvell,pcie-lane passed to the node. Also, PCI address space > does now also start at where we see it on MBUS. Some devices were > not so happy about starting at 0. > > The whole series has been tested on Armada 370 Mirabox and > Armada XP Lenovo Iomega ix4-300d (not mainline yet). > > Sebastian > This looks good to me. Patches 3-7 are Reviewed-by: Lucas Stach <l.stach@pengutronix.de Series is Acked-by: Lucas Stach <l.stach@pengutronix.de> -- Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 0/8] Marvell EBU PCIe driver 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth ` (8 preceding siblings ...) 2014-07-30 9:16 ` [PATCH v3 0/8] Marvell EBU " Lucas Stach @ 2014-07-31 5:30 ` Sascha Hauer 9 siblings, 0 replies; 11+ messages in thread From: Sascha Hauer @ 2014-07-31 5:30 UTC (permalink / raw) To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox On Wed, Jul 30, 2014 at 10:39:32AM +0200, Sebastian Hesselbarth wrote: > Third and hopefully last round of the Marvell EBU PCIe driver patch > set. Compared to v2, I disabled MBUS error propagation on Armada > 370/XP as it hangs the SoC on unanswered PCIe accesses. Also, 64b > BARs are now properly handled. I added two more pci core fixes that > move PCI device registration after BAR setup and temporarely disable > PCI_COMMAND' IO and MEM bits during BAR setup. > > The MVEBU PCIe driver now gained support for Armada XP PHY setup > which is anticipating a minor DT binding tweak to allow more than > one marvell,pcie-lane passed to the node. Also, PCI address space > does now also start at where we see it on MBUS. Some devices were > not so happy about starting at 0. > > The whole series has been tested on Armada 370 Mirabox and > Armada XP Lenovo Iomega ix4-300d (not mainline yet). > > Sebastian Ok, applied, thanks Sascha > > Sebastian Hesselbarth (8): > bus: mvebu: fix resource size handling > ARM: mvebu: armada-370-xp: disable MBUS error propagation > pci: pci_scan_bus: respect 64b BARs > pci: register device after BAR setup > pci: ensure device does ignore BAR mangling > pci: set auto-incremented bus number > of: pci: import of_pci_get_devfn() > pci: mvebu: Add PCIe driver > > arch/arm/Kconfig | 1 + > arch/arm/mach-mvebu/armada-370-xp.c | 6 + > .../mach-mvebu/include/mach/armada-370-xp-regs.h | 2 + > drivers/bus/mvebu-mbus.c | 8 +- > drivers/of/Kconfig | 6 + > drivers/of/Makefile | 1 + > drivers/of/of_pci.c | 27 ++ > drivers/pci/Kconfig | 6 + > drivers/pci/Makefile | 2 + > drivers/pci/pci-mvebu-phy.c | 208 ++++++++++ > drivers/pci/pci-mvebu.c | 446 +++++++++++++++++++++ > drivers/pci/pci-mvebu.h | 37 ++ > drivers/pci/pci.c | 28 +- > include/linux/pci.h | 12 +- > include/of_pci.h | 17 + > 15 files changed, 790 insertions(+), 17 deletions(-) > create mode 100644 drivers/of/of_pci.c > create mode 100644 drivers/pci/pci-mvebu-phy.c > create mode 100644 drivers/pci/pci-mvebu.c > create mode 100644 drivers/pci/pci-mvebu.h > create mode 100644 include/of_pci.h > > --- > Cc: barebox@lists.infradead.org > Cc: Antony Pavlov <antonynpavlov@gmail.com> > Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> > Cc: Lucas Stach <l.stach@pengutronix.de> > Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> > Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> > -- > 2.0.0 > > -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-07-31 5:30 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-07-30 8:39 [PATCH v3 0/8] Marvell EBU PCIe driver Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 1/8] bus: mvebu: fix resource size handling Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 2/8] ARM: mvebu: armada-370-xp: disable MBUS error propagation Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 3/8] pci: pci_scan_bus: respect 64b BARs Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 4/8] pci: register device after BAR setup Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 5/8] pci: ensure device does ignore BAR mangling Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 6/8] pci: set auto-incremented bus number Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 7/8] of: pci: import of_pci_get_devfn() Sebastian Hesselbarth 2014-07-30 8:39 ` [PATCH v3 8/8] pci: mvebu: Add PCIe driver Sebastian Hesselbarth 2014-07-30 9:16 ` [PATCH v3 0/8] Marvell EBU " Lucas Stach 2014-07-31 5:30 ` Sascha Hauer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox