* [PATCH v4 1/2] PCI support added to ARC
2016-01-11 17:24 [PATCH v4 0/2] adding PCI support to AXS10x Joao Pinto
@ 2016-01-11 17:24 ` Joao Pinto
2016-01-12 5:58 ` Vineet Gupta
2016-01-12 6:05 ` Vineet Gupta
2016-01-11 17:24 ` [PATCH v4 2/2] add new platform driver for PCI RC Joao Pinto
1 sibling, 2 replies; 7+ messages in thread
From: Joao Pinto @ 2016-01-11 17:24 UTC (permalink / raw)
To: linux-snps-arc
This patch adds PCI support to ARC and updates drivers/pci Makefile enabling
the ARC arch to use the generic PCI setup functions.
Signed-off-by: Joao Pinto <jpinto at synopsys.com>
---
Change v3 -> v4:
- Nothing changed (just to keep up with patch set version).
Change v2 -> v3 (Bjorn Helgaas):
- arch/arc/kernel/pcibios.c unused functions were removed and also the
arch/arc/include/asm/mach/pci.h was removed because was no longer necessary
Change v1 -> v2:
- In arch/arc/Kconfig, the new menu entry (Bus Configuration) was moved to the
slot between sourcing of drivers/Kconfig and fs/Kconfig (Vineet Gupta)
- In arch/arc/plat-axs10x/Kconfig the "select MIGHT_HAVE_PCI" option was placed
in order as suggested (Vineet Gupta)
- ioport_map() and ioport_unmap() were static inlined and included in
the io.h (Vineet Gupta)
- pcibios_min_io and pcibios_min_mem declaration moved to
pcibios.c (Vineet Gupta)
- pr_err() replaced by dev_err() in pcibios_enable_device() (Bjorn Helgaas)
- string simplified in pcibios_enable_device() (Vineet Gupta)
- pci_host_bridge_window structure was replaced by resource_entry structure, and
list_for_each_entry() for resource_list_for_each_entry() in pcibios.c
arch/arc/Kconfig | 23 ++++++++++++++++++
arch/arc/include/asm/dma.h | 5 ++++
arch/arc/include/asm/io.h | 10 ++++++++
arch/arc/include/asm/pci.h | 43 ++++++++++++++++++++++++++++++++++
arch/arc/kernel/Makefile | 1 +
arch/arc/kernel/pcibios.c | 55 ++++++++++++++++++++++++++++++++++++++++++++
arch/arc/mm/ioremap.c | 10 +++++++-
arch/arc/plat-axs10x/Kconfig | 1 +
drivers/pci/Makefile | 1 +
9 files changed, 148 insertions(+), 1 deletion(-)
create mode 100644 arch/arc/include/asm/pci.h
create mode 100644 arch/arc/kernel/pcibios.c
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 2c2ac3f..98b32c1 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -19,6 +19,7 @@ config ARC
select GENERIC_FIND_FIRST_BIT
# for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP
select GENERIC_IRQ_SHOW
+ select GENERIC_PCI_IOMAP
select GENERIC_PENDING_IRQ if SMP
select GENERIC_SMP_IDLE_THREAD
select HAVE_ARCH_KGDB
@@ -39,6 +40,9 @@ config ARC
select PERF_USE_VMALLOC
select HAVE_DEBUG_STACKOVERFLOW
+config MIGHT_HAVE_PCI
+ bool
+
config TRACE_IRQFLAGS_SUPPORT
def_bool y
@@ -570,6 +574,25 @@ endmenu # "ARC Architecture Configuration"
source "mm/Kconfig"
source "net/Kconfig"
source "drivers/Kconfig"
+
+menu "Bus Support"
+
+config PCI
+ bool "PCI support" if MIGHT_HAVE_PCI
+ help
+ PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside
+ your box.Find out if your board/platform have PCI.
+ Note: PCIE support for Synopsys Device will be available only when
+ HAPS DX is configured with PCIE RC bitmap. If you have PCI, say Y, otherwise N.
+
+config PCI_SYSCALL
+ def_bool PCI
+
+source "drivers/pci/Kconfig"
+source "drivers/pci/pcie/Kconfig"
+
+endmenu
+
source "fs/Kconfig"
source "arch/arc/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/arc/include/asm/dma.h b/arch/arc/include/asm/dma.h
index ca7c451..37942fa 100644
--- a/arch/arc/include/asm/dma.h
+++ b/arch/arc/include/asm/dma.h
@@ -10,5 +10,10 @@
#define ASM_ARC_DMA_H
#define MAX_DMA_ADDRESS 0xC0000000
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy (0)
+#endif
#endif
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index 694ece8..2ec3cf4 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -16,7 +16,17 @@
extern void __iomem *ioremap(unsigned long physaddr, unsigned long size);
extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
unsigned long flags);
+static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+ return (void __iomem *)port;
+}
+
+static inline void ioport_unmap(void __iomem *addr)
+{
+}
+
extern void iounmap(const void __iomem *addr);
+extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
#define ioremap_nocache(phy, sz) ioremap(phy, sz)
#define ioremap_wc(phy, sz) ioremap(phy, sz)
diff --git a/arch/arc/include/asm/pci.h b/arch/arc/include/asm/pci.h
new file mode 100644
index 0000000..a0a0fa5
--- /dev/null
+++ b/arch/arc/include/asm/pci.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_ARC_PCI_H
+#define _ASM_ARC_PCI_H
+
+#ifdef __KERNEL__
+#include <asm-generic/pci-dma-compat.h>
+#include <asm-generic/pci-bridge.h>
+
+#include <linux/ioport.h>
+
+extern unsigned long pcibios_min_io;
+#define PCIBIOS_MIN_IO pcibios_min_io
+extern unsigned long pcibios_min_mem;
+#define PCIBIOS_MIN_MEM pcibios_min_mem
+
+#define pcibios_assign_all_busses() 1
+/*
+ * The PCI address space does equal the physical memory address space.
+ * The networking and block device layers use this boolean for bounce
+ * buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS (1)
+
+/*
+ * Setup early fixed I/O mapping.
+ */
+#if defined(CONFIG_PCI)
+extern void pci_map_io_early(unsigned long pfn);
+#else
+static inline void pci_map_io_early(unsigned long pfn) {}
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_ARC_PCI_H */
+
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index e7f3625..1bc2036 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -12,6 +12,7 @@ obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o
obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o
obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o
obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o
+obj-$(CONFIG_PCI) += pcibios.o
obj-$(CONFIG_MODULES) += arcksyms.o module.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/arc/kernel/pcibios.c b/arch/arc/kernel/pcibios.c
new file mode 100644
index 0000000..99ee329
--- /dev/null
+++ b/arch/arc/kernel/pcibios.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014-2015 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+#include <asm/pci.h>
+
+unsigned long pcibios_min_io = 0x100;
+EXPORT_SYMBOL(pcibios_min_io);
+
+unsigned long pcibios_min_mem = 0x100000;
+EXPORT_SYMBOL(pcibios_min_mem);
+
+/*
+ * We don't have to worry about legacy ISA devices, so nothing to do here
+ */
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ resource_size_t size, resource_size_t align)
+{
+ return res->start;
+}
+
+/*
+ * If the bus contains any of these devices, then we must not turn on
+ * parity checking of any kind. Currently this is CyberPro 20x0 only.
+ */
+static inline int pdev_bad_for_parity(struct pci_dev *dev)
+{
+ return ((dev->vendor == PCI_VENDOR_ID_INTERG &&
+ (dev->device == PCI_DEVICE_ID_INTERG_2000 ||
+ dev->device == PCI_DEVICE_ID_INTERG_2010)) ||
+ (dev->vendor == PCI_VENDOR_ID_ITE &&
+ dev->device == PCI_DEVICE_ID_ITE_8152));
+
+}
+
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+EXPORT_SYMBOL(pcibios_fixup_bus);
diff --git a/arch/arc/mm/ioremap.c b/arch/arc/mm/ioremap.c
index 739e65f..fe807b0 100644
--- a/arch/arc/mm/ioremap.c
+++ b/arch/arc/mm/ioremap.c
@@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/cache.h>
+#include <linux/sizes.h>
void __iomem *ioremap(unsigned long paddr, unsigned long size)
{
@@ -80,7 +81,6 @@ void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
}
EXPORT_SYMBOL(ioremap_prot);
-
void iounmap(const void __iomem *addr)
{
if (addr >= (void __force __iomem *)ARC_UNCACHED_ADDR_SPACE)
@@ -89,3 +89,11 @@ void iounmap(const void __iomem *addr)
vfree((void *)(PAGE_MASK & (unsigned long __force)addr));
}
EXPORT_SYMBOL(iounmap);
+
+#ifdef CONFIG_PCI
+int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
+{
+ return ioremap_nocache(phys_addr + offset, SZ_64K);
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_io);
+#endif
diff --git a/arch/arc/plat-axs10x/Kconfig b/arch/arc/plat-axs10x/Kconfig
index d475f9d..426ac4b 100644
--- a/arch/arc/plat-axs10x/Kconfig
+++ b/arch/arc/plat-axs10x/Kconfig
@@ -11,6 +11,7 @@ menuconfig ARC_PLAT_AXS10X
select DW_APB_ICTL
select GPIO_DWAPB
select OF_GPIO
+ select MIGHT_HAVE_PCI
select GENERIC_IRQ_CHIP
select ARCH_REQUIRE_GPIOLIB
help
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index be3f631..2154092 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o
# Some architectures use the generic PCI setup functions
#
obj-$(CONFIG_ALPHA) += setup-irq.o
+obj-$(CONFIG_ARC) += setup-irq.o
obj-$(CONFIG_ARM) += setup-irq.o
obj-$(CONFIG_ARM64) += setup-irq.o
obj-$(CONFIG_UNICORE32) += setup-irq.o
--
1.8.1.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 2/2] add new platform driver for PCI RC
2016-01-11 17:24 [PATCH v4 0/2] adding PCI support to AXS10x Joao Pinto
2016-01-11 17:24 ` [PATCH v4 1/2] PCI support added to ARC Joao Pinto
@ 2016-01-11 17:24 ` Joao Pinto
1 sibling, 0 replies; 7+ messages in thread
From: Joao Pinto @ 2016-01-11 17:24 UTC (permalink / raw)
To: linux-snps-arc
This patch adds a new driver that will be the reference platform driver for all
PCI RC IP Protoyping Kits based on ARC SDP. This patch is composed by:
-Changes to pcie-designware driver add a function that enables the feature of
starting the LTSSM (Link Train Status State) used by the new driver
-MAINTAINERS file was updated to include the new driver
-Documentation/devicetree/bindings/pci was updated to include the new driver
documentation
-New driver called pcie-snpsdev
Signed-off-by: Joao Pinto <jpinto at synopsys.com>
---
Changes v3 -> v4 (Bjorn Helgaas):
- ARCH dependencies were added to the drivers/pci/host/kconfig for the
PCIE_SNPSDEV.
Changes v2 -> v3 (Bjorn Helgaas):
- link init stuff was moved to a snpsdev_pcie_establish_link() function in
pcie-snpsdev
- pcie-snpsdev driver declaration was changed to be more
standard (Bjorn Helgaas)
- pcie-designware' dw_pcie_link_retrain() now use standard registers from
pci-regs.h (Bjorn Helgaas)
- pcie-snpsdev.txt was complemented with more info (Mark Rutland)
Changes v1 -> v2 (Bjorn Helgaas):
- Fixups snpsdev_pcie_fixup_bridge() and snpsdev_pcie_fixup_res() were removed
from the driver (these functions were for specific tests only and not usefull
in mainline)
- Driver' comments were reviewed (fix Typos and excessive comments removal)
- Removed unnecessary definitions in the driver source (PCIE_PHY_CTRL and
PCIE_PHY_STAT)
.../devicetree/bindings/pci/pcie-snpsdev.txt | 33 +++
MAINTAINERS | 7 +
drivers/pci/host/Kconfig | 8 +
drivers/pci/host/Makefile | 1 +
drivers/pci/host/pcie-designware.c | 11 +
drivers/pci/host/pcie-designware.h | 1 +
drivers/pci/host/pcie-snpsdev.c | 286 +++++++++++++++++++++
7 files changed, 347 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/pcie-snpsdev.txt
create mode 100644 drivers/pci/host/pcie-snpsdev.c
diff --git a/Documentation/devicetree/bindings/pci/pcie-snpsdev.txt b/Documentation/devicetree/bindings/pci/pcie-snpsdev.txt
new file mode 100644
index 0000000..cae548b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pcie-snpsdev.txt
@@ -0,0 +1,33 @@
+Synopsys PCI RC IP Prototyping Kit
+----------------------------------
+
+This is the reference platform driver to be used in the Synopsys PCI Root
+Complex IP Prototyping Kit.
+
+Required properties:
+- compatible: set to "snps,pcie-snpsdev";
+- reg: base address and length of the pcie controller registers.
+- #address-cells: set to <3>
+- #size-cells: set to <2>
+- device_type: set to "pci"
+- ranges: ranges for the PCI memory and I/O regions.
+- interrupts: one interrupt source for MSI interrupts, followed by interrupt
+ source for hardware related interrupts.
+- #interrupt-cells: set to <1>
+- num-lanes: set to <1>;
+
+Example configuration:
+
+ pcie: pcie at 0xdffff000 {
+ compatible = "snps,pcie-snpsdev";
+ reg = <0xdffff000 0x1000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x00000800 0 0xd0000000 0xd0000000 0 0x00002000>,
+ <0x81000000 0 0x00000000 0xde000000 0 0x00010000>,
+ <0x82000000 0 0xd0400000 0xd0400000 0 0x0d000000>;
+ interrupts = <25>, <24>;
+ #interrupt-cells = <1>;
+ num-lanes = <1>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index e9caa4b..d2e4506 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8230,6 +8230,13 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
F: drivers/pci/host/pcie-hisi.c
+PCI DRIVER FOR SYNOPSYS PROTOTYPING DEVICE
+M: Joao Pinto <jpinto at synopsys.com>
+L: linux-pci at vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/pci/pcie-snpsdev.txt
+F: drivers/pci/host/pcie-snpsdev.c
+
PCMCIA SUBSYSTEM
P: Linux PCMCIA Team
L: linux-pcmcia at lists.infradead.org
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index f131ba9..589bc15 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -172,4 +172,12 @@ config PCI_HISI
help
Say Y here if you want PCIe controller support on HiSilicon HIP05 SoC
+config PCIE_SNPSDEV
+ bool "Platform Driver for Synopsys Device"
+ depends on ARC && OF
+ select PCIEPORTBUS
+ select PCIE_DW
+ help
+ Say Y here if you want to enable PCIe controller support on the
+ Synopsys IP Prototyping Kits.
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 9d4d3c6..e422f65 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
+obj-$(CONFIG_PCIE_SNPSDEV) += pcie-snpsdev.o
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 540f077..a5fa046 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -22,6 +22,8 @@
#include <linux/pci_regs.h>
#include <linux/platform_device.h>
#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
#include "pcie-designware.h"
@@ -706,6 +708,15 @@ static struct pci_ops dw_pcie_ops = {
.write = dw_pcie_wr_conf,
};
+void dw_pcie_link_retrain(struct pcie_port *pp)
+{
+ u32 val = 0;
+
+ dw_pcie_readl_rc(pp, PCI_EXP_LNKCTL+0x70, &val);
+ val = val | PCI_EXP_LNKCTL_RL;
+ dw_pcie_writel_rc(pp, val, PCI_EXP_LNKCTL+0x70);
+}
+
void dw_pcie_setup_rc(struct pcie_port *pp)
{
u32 val;
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 2356d29..249b631 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -79,5 +79,6 @@ void dw_pcie_msi_init(struct pcie_port *pp);
int dw_pcie_link_up(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
+void dw_pcie_link_retrain(struct pcie_port *pp);
#endif /* _PCIE_DESIGNWARE_H */
diff --git a/drivers/pci/host/pcie-snpsdev.c b/drivers/pci/host/pcie-snpsdev.c
new file mode 100644
index 0000000..4ca7ec5
--- /dev/null
+++ b/drivers/pci/host/pcie-snpsdev.c
@@ -0,0 +1,286 @@
+/*
+ * PCIe RC driver for Synopsys Designware Core
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Manjunath Bettegowda <manjumb at synopsys.com>,
+ * Jie Deng <jiedeng at synopsys.com>
+ * Joao Pinto <jpinto at synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+#define to_snpsdev_pcie(x) container_of(x, struct snpsdev_pcie, pp)
+
+struct snpsdev_pcie {
+ void __iomem *mem_base; /* Memory Base to access Core's [RC]
+ * Config Space Layout
+ */
+ struct pcie_port pp; /* RC Root Port specific structure -
+ * DWC_PCIE_RC stuff
+ */
+};
+
+#define PCI_EQUAL_CONTROL_PHY 0x00000707
+
+/* PCIe Port Logic registers (memory-mapped) */
+#define PLR_OFFSET 0x700
+#define PCIE_PHY_DEBUG_R0 (PLR_OFFSET + 0x28) /* 0x728 */
+#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c) /* 0x72c */
+
+/* This handler was created for future work */
+static irqreturn_t snpsdev_pcie_irq_handler(int irq, void *arg)
+{
+ return IRQ_NONE;
+}
+
+static irqreturn_t snpsdev_pcie_msi_irq_handler(int irq, void *arg)
+{
+ struct pcie_port *pp = arg;
+
+ dw_handle_msi_irq(pp);
+
+ return IRQ_HANDLED;
+}
+
+static void snpsdev_pcie_init_phy(struct pcie_port *pp)
+{
+ /* write Lane 0 Equalization Control fields register */
+ writel(PCI_EQUAL_CONTROL_PHY, pp->dbi_base + 0x154);
+}
+
+static int snpsdev_pcie_deassert_core_reset(struct pcie_port *pp)
+{
+ return 0;
+}
+
+static void snpsdev_pcie_establish_link(struct pcie_port *pp)
+{
+ int count = 0;
+
+ /* Initialize Phy (Reset/poweron/control-inputs ) */
+ snpsdev_pcie_init_phy(pp);
+
+ /* de-assert core reset */
+ snpsdev_pcie_deassert_core_reset(pp);
+
+ /* We expect the PCIe Link to be up by this time */
+ dw_pcie_setup_rc(pp);
+
+ /* Start LTSSM here */
+ dw_pcie_link_retrain(pp);
+
+ while (!dw_pcie_link_up(pp)) {
+ usleep_range(1000, 1100);
+ count++;
+ if (count == 20) {
+ dev_err(pp->dev, "phy link never came up\n");
+ dev_dbg(pp->dev,
+ "PL_DEBUG0: 0x%08x, DEBUG_R1: 0x%08x\n",
+ readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
+ readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
+ break;
+ }
+ }
+}
+
+/*
+ * snpsdev_pcie_host_init()
+ * Platform specific host/RC initialization
+ * a. Assert the core reset
+ * b. Assert and deassert phy reset and initialize the phy
+ * c. De-Assert the core reset
+ * d. Initializet the Root Port (BARs/Memory Or IO/ Interrupt/ Commnad Reg)
+ * e. Initiate Link startup procedure
+ *
+ */
+static void snpsdev_pcie_host_init(struct pcie_port *pp)
+{
+ /* Establish link */
+ snpsdev_pcie_establish_link(pp);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ dw_pcie_msi_init(pp);
+}
+
+static int snpsdev_pcie_link_up(struct pcie_port *pp)
+{
+ u32 status;
+
+ /* Bit number 36: reports LTSSM PHY Link UP; Available in bit 3 of
+ * PCIE_PHY_DEBUG_R1
+ */
+ status = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << 4);
+ if (status != 0)
+ return 1;
+
+ /* TODO:Now Link is in L0;Initiate GEN2/GEN3 migration if RC Supports*/
+ return 0;
+}
+
+/**
+ * This is RC operation structure
+ * snpsdev_pcie_link_up: the function which initiates the phy link up procedure
+ * snpsdev_pcie_host_init: the function which does the host/RC Root port
+ * initialization.
+ */
+static struct pcie_host_ops snpsdev_pcie_host_ops = {
+ .link_up = snpsdev_pcie_link_up,
+ .host_init = snpsdev_pcie_host_init,
+};
+
+/**
+ * snpsdev_add_pcie_port
+ * This function
+ * a. installs the interrupt handler
+ * b. registers host operations in the pcie_port structure
+ */
+static int snpsdev_add_pcie_port(struct pcie_port *pp,
+ struct platform_device *pdev)
+{
+ int ret;
+
+ pp->irq = platform_get_irq(pdev, 1);
+
+ if (pp->irq < 0) {
+ if (pp->irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "cannot get irq\n");
+ return pp->irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, pp->irq, snpsdev_pcie_irq_handler,
+ IRQF_SHARED, "snpsdev-pcie", pp);
+
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ pp->msi_irq = platform_get_irq(pdev, 0);
+
+ if (pp->msi_irq < 0) {
+ if (pp->msi_irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "cannot get msi irq\n");
+ return pp->msi_irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, pp->msi_irq,
+ snpsdev_pcie_msi_irq_handler,
+ IRQF_SHARED, "snpsdev-pcie-msi", pp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request msi irq\n");
+ return ret;
+ }
+ }
+
+ pp->root_bus_nr = -1;
+ pp->ops = &snpsdev_pcie_host_ops;
+
+ /* Below function:
+ * Checks for range property from DT
+ * Gets the IO and MEMORY and CONFIG-Space ranges from DT
+ * Does IOREMAPS on the physical addresses
+ * Gets the num-lanes from DT
+ * Gets MSI capability from DT
+ * Calls the platform specific host initialization
+ * Program the correct class, BAR0, Link width, in Config space
+ * Then it calls pci common init routine
+ * Then it calls function to assign "unassigned resources"
+ */
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * snpsdev_pcie_rc_probe()
+ * This function gets called as part of pcie registration. if the id matches
+ * the platform driver framework will call this function.
+ *
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Returns zero on success; Negative errorno on failure
+ */
+static int snpsdev_pcie_rc_probe(struct platform_device *pdev)
+{
+ struct snpsdev_pcie *snpsdev_pcie;
+ struct pcie_port *pp;
+ struct resource *dwc_pcie_rc_res; /* Resource from DT */
+ int ret;
+
+ snpsdev_pcie = devm_kzalloc(&pdev->dev, sizeof(*snpsdev_pcie),
+ GFP_KERNEL);
+ if (!snpsdev_pcie)
+ return -ENOMEM;
+
+ pp = &snpsdev_pcie->pp;
+ pp->dev = &pdev->dev;
+
+ dwc_pcie_rc_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!dwc_pcie_rc_res)
+ return -ENODEV;
+
+ snpsdev_pcie->mem_base = devm_ioremap_resource(&pdev->dev,
+ dwc_pcie_rc_res);
+ if (IS_ERR(snpsdev_pcie->mem_base)) {
+ ret = PTR_ERR(snpsdev_pcie->mem_base);
+ return ret;
+ }
+ pp->dbi_base = snpsdev_pcie->mem_base;
+
+ ret = snpsdev_add_pcie_port(pp, pdev);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, snpsdev_pcie);
+
+ return 0;
+}
+
+static int snpsdev_pcie_rc_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id snpsdev_pcie_rc_of_match[] = {
+ { .compatible = "snps,pcie-snpsdev", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snpsdev_pcie_rc_of_match);
+
+static struct platform_driver snpsdev_pcie_rc_driver = {
+ .driver = {
+ .name = "pcie-snpsdev",
+ .of_match_table = snpsdev_pcie_rc_of_match,
+ },
+ .probe = snpsdev_pcie_rc_probe,
+};
+
+module_platform_driver(snpsdev_pcie_rc_driver);
+
+MODULE_AUTHOR("Manjunath Bettegowda <manjumb at synopsys.com>");
+MODULE_DESCRIPTION("Platform Driver for Synopsys Device");
+MODULE_LICENSE("GPL v2");
--
1.8.1.5
^ permalink raw reply related [flat|nested] 7+ messages in thread