diff mbox

add new platform driver for PCI RC

Message ID 56c2031ee4b5d6d9d5452ac6cca724a15942cbf7.1447411031.git.jpinto@synopsys.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Joao Pinto Nov. 13, 2015, 11 a.m. UTC
This patch goal is to add a new platform driver called pcie-snpsdev for PCI RC 
using Synopsys' PCI RC DesignWare Core.

This driver will be used extensively because it is going to be the official 
platform driver of the DesignWare PCI RC IP Prototyping Kit which provides a 
FPGA containing a DW PCI RC controller and a software development environment.

Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
 drivers/pci/host/Kconfig        |   5 +
 drivers/pci/host/Makefile       |   1 +
 drivers/pci/host/pcie-snpsdev.c | 337 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 343 insertions(+)
 create mode 100644 drivers/pci/host/pcie-snpsdev.c

Comments

kernel test robot Nov. 13, 2015, 11:36 a.m. UTC | #1
Hi Joao,

[auto build test ERROR on: v4.3-rc7]
[cannot apply to: pci/next next-20151113]

url:    https://github.com/0day-ci/linux/commits/Joao-Pinto/add-new-platform-driver-for-PCI-RC/20151113-190212
config: i386-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/pci/host/pcie-designware.c:76:52: warning: 'struct pci_sys_data' declared inside parameter list
    static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
                                                       ^
   drivers/pci/host/pcie-designware.c:76:52: warning: its scope is only this definition or declaration, which is probably not what you want
   In file included from include/uapi/linux/stddef.h:1:0,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/smp.h:10,
                    from include/linux/irq.h:12,
                    from drivers/pci/host/pcie-designware.c:14:
   drivers/pci/host/pcie-designware.c: In function 'sys_to_pcie':
>> drivers/pci/host/pcie-designware.c:78:13: error: dereferencing pointer to incomplete type 'struct pci_sys_data'
     BUG_ON(!sys->private_data);
                ^
   include/linux/compiler.h:166:42: note: in definition of macro 'unlikely'
    # define unlikely(x) __builtin_expect(!!(x), 0)
                                             ^
   drivers/pci/host/pcie-designware.c:78:2: note: in expansion of macro 'BUG_ON'
     BUG_ON(!sys->private_data);
     ^
   drivers/pci/host/pcie-designware.c: In function 'dw_pcie_host_init':
   drivers/pci/host/pcie-designware.c:530:2: error: invalid use of undefined type 'struct hw_pci'
     dw_pci.nr_controllers = 1;
     ^
   drivers/pci/host/pcie-designware.c:531:2: error: invalid use of undefined type 'struct hw_pci'
     dw_pci.private_data = (void **)&pp;
     ^
   drivers/pci/host/pcie-designware.c:533:2: error: implicit declaration of function 'pci_common_init_dev' [-Werror=implicit-function-declaration]
     pci_common_init_dev(pp->dev, &dw_pci);
     ^
   drivers/pci/host/pcie-designware.c: At top level:
   drivers/pci/host/pcie-designware.c:682:41: warning: 'struct pci_sys_data' declared inside parameter list
    static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
                                            ^
   drivers/pci/host/pcie-designware.c: In function 'dw_pcie_setup':
   drivers/pci/host/pcie-designware.c:686:19: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [-Wincompatible-pointer-types]
     pp = sys_to_pcie(sys);
                      ^
   drivers/pci/host/pcie-designware.c:76:33: note: expected 'struct pci_sys_data *' but argument is of type 'struct pci_sys_data *'
    static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
                                    ^
>> drivers/pci/host/pcie-designware.c:688:25: error: 'SZ_1M' undeclared (first use in this function)
     if (global_io_offset < SZ_1M && pp->io_size > 0) {
                            ^
   drivers/pci/host/pcie-designware.c:688:25: note: each undeclared identifier is reported only once for each function it appears in
   drivers/pci/host/pcie-designware.c:689:6: error: dereferencing pointer to incomplete type 'struct pci_sys_data'
      sys->io_offset = global_io_offset - pp->io_bus_addr;
         ^
   drivers/pci/host/pcie-designware.c:690:3: error: implicit declaration of function 'pci_ioremap_io' [-Werror=implicit-function-declaration]
      pci_ioremap_io(global_io_offset, pp->io_base);
      ^
>> drivers/pci/host/pcie-designware.c:691:23: error: 'SZ_64K' undeclared (first use in this function)
      global_io_offset += SZ_64K;
                          ^
   drivers/pci/host/pcie-designware.c: At top level:
   drivers/pci/host/pcie-designware.c:703:56: warning: 'struct pci_sys_data' declared inside parameter list
    static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
                                                           ^
   drivers/pci/host/pcie-designware.c: In function 'dw_pcie_scan_bus':
   drivers/pci/host/pcie-designware.c:706:37: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [-Wincompatible-pointer-types]
     struct pcie_port *pp = sys_to_pcie(sys);
                                        ^
   drivers/pci/host/pcie-designware.c:76:33: note: expected 'struct pci_sys_data *' but argument is of type 'struct pci_sys_data *'
    static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
                                    ^
   drivers/pci/host/pcie-designware.c:708:23: error: dereferencing pointer to incomplete type 'struct pci_sys_data'
     pp->root_bus_nr = sys->busnr;
                          ^
   drivers/pci/host/pcie-designware.c: At top level:
   drivers/pci/host/pcie-designware.c:739:15: error: variable 'dw_pci' has initializer but incomplete type
    static struct hw_pci dw_pci = {
                  ^
   drivers/pci/host/pcie-designware.c:740:2: error: unknown field 'setup' specified in initializer
     .setup  = dw_pcie_setup,
     ^
   drivers/pci/host/pcie-designware.c:740:12: warning: excess elements in struct initializer
     .setup  = dw_pcie_setup,
               ^
   drivers/pci/host/pcie-designware.c:740:12: note: (near initialization for 'dw_pci')
   drivers/pci/host/pcie-designware.c:741:2: error: unknown field 'scan' specified in initializer
     .scan  = dw_pcie_scan_bus,
     ^
   drivers/pci/host/pcie-designware.c:741:11: warning: excess elements in struct initializer
     .scan  = dw_pcie_scan_bus,
              ^
   drivers/pci/host/pcie-designware.c:741:11: note: (near initialization for 'dw_pci')
   drivers/pci/host/pcie-designware.c:742:2: error: unknown field 'map_irq' specified in initializer
     .map_irq = dw_pcie_map_irq,
     ^
   drivers/pci/host/pcie-designware.c:742:13: warning: excess elements in struct initializer
     .map_irq = dw_pcie_map_irq,
                ^
   drivers/pci/host/pcie-designware.c:742:13: note: (near initialization for 'dw_pci')
   drivers/pci/host/pcie-designware.c: In function 'sys_to_pcie':
   drivers/pci/host/pcie-designware.c:81:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   cc1: some warnings being treated as errors
--
   drivers/pci/host/pcie-snpsdev.c: In function 'snpsdev_pcie_host_init':
>> drivers/pci/host/pcie-snpsdev.c:139:2: error: implicit declaration of function 'dw_pcie_link_retrain' [-Werror=implicit-function-declaration]
     dw_pcie_link_retrain(pp);
     ^
   cc1: some warnings being treated as errors

coccinelle warnings: (new ones prefixed by >>)

>> drivers/pci/host/pcie-designware.c:158:23-47: Move constant to right.
--
>> drivers/pci/host/pcie-snpsdev.c:323:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

vim +/dw_pcie_link_retrain +139 drivers/pci/host/pcie-snpsdev.c

   133		snpsdev_pcie_deassert_core_reset(pp);
   134	 
   135		/*We expect the PCIE Link to be up by this time*/
   136		dw_pcie_setup_rc(pp);
   137		
   138		/*Start LTSSM here*/
 > 139		dw_pcie_link_retrain(pp);
   140	
   141		/* Check for Link up indication */
   142		while (!dw_pcie_link_up(pp)) {
   143			usleep_range(1000,1100);
   144			count++;
   145			if (count == 20) {
   146				dev_err(pp->dev, "phy link never came up\n");
   147				dev_dbg(pp->dev,
   148					"PL_DEBUG0: 0x%08x, DEBUG_R1: 0x%08x\n",
   149					readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
   150					readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
   151				break;
   152			}
   153		}
   154	
   155		if (IS_ENABLED(CONFIG_PCI_MSI))
   156			dw_pcie_msi_init(pp);
   157	
   158		return;
   159	}
   160	/**
   161	 *
   162	 * Let all outof band signalling be handled by cfg_phy_control[31:0]
   163	 * which is selected through optional config attribute PHY_CONTROL_REG
   164	 *
   165	 * Monitor cxpl_debug_info as required to take necessary action
   166	 * This is available in the register PCIE_PHY_DEBUG_R0 & PCIE_PHY_DEBUG_R1
   167	 *
   168	 */ 
   169	static int snpsdev_pcie_link_up(struct pcie_port *pp)
   170	{
   171		u32 status;
   172	
   173		/* Bit number 36: reports LTSSM PHY Link UP; Available in bit 3 of
   174	         *  PCIE_PHY_DEBUG_R1 */
   175		status = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << 4);
   176		if(status != 0)
   177			return 1;
   178	
   179		/* TODO: Now Link is in L0; Initiate GEN2/GEN3 migration if RC Supports */
   180		return 0;
   181	}
   182	
   183	
   184	/**
   185	 * This is RC operation structure
   186	 * snpsdev_pcie_link_up: the function which initiates the phy link up procedure
   187	 * snpsdev_pcie_host_init: the function whihc does the host/RC Root port initialization
   188	 */ 
   189	static struct pcie_host_ops snpsdev_pcie_host_ops = {
   190		.link_up = snpsdev_pcie_link_up,
   191		.host_init = snpsdev_pcie_host_init,
   192	};
   193	
   194	/**
   195	 * snpsdev_add_pcie_port
   196	 * This function 
   197	 * a. installs the interrupt handler
   198	 * b. registers host operations int he pcie_port structure
   199	 */ 
   200	static int snpsdev_add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
   201	{
   202		int ret;
   203	
   204		pp->irq = platform_get_irq(pdev, 1);
   205	
   206		if (pp->irq < 0) {
   207			if (pp->irq != -EPROBE_DEFER)
   208				dev_err(&pdev->dev, "cannot get irq\n");
   209			return pp->irq;
   210		}
   211	
   212		ret = devm_request_irq(&pdev->dev, pp->irq, snpsdev_pcie_irq_handler,
   213					IRQF_SHARED, "snpsdev-pcie", pp);
   214	
   215		if (ret) {
   216			dev_err(&pdev->dev, "failed to request irq\n");
   217			return ret;
   218		}
   219	
   220		if (IS_ENABLED(CONFIG_PCI_MSI)) {
   221			pp->msi_irq = platform_get_irq(pdev, 0);
   222	
   223			if (pp->msi_irq < 0) {
   224				if (pp->msi_irq != -EPROBE_DEFER)
   225					dev_err(&pdev->dev, "cannot get msi irq\n");
   226				return pp->msi_irq;
   227			}
   228	
   229			ret = devm_request_irq(&pdev->dev, pp->msi_irq,
   230						snpsdev_pcie_msi_irq_handler,
   231						IRQF_SHARED, "snpsdev-pcie-msi", pp);
   232			if (ret) {
   233				dev_err(&pdev->dev, "failed to request msi irq\n");
   234				return ret;
   235			}
   236		}
   237	
   238		pp->root_bus_nr = -1;
   239		pp->ops = &snpsdev_pcie_host_ops;
   240	
   241		/* Below function: 
   242	 	 * Checks for range property from DT
   243	 	 * Gets the IO and MEMORY and CONFIG-Space ranges from DT
   244	 	 * Does IOREMAPS on the physical addresses 
   245	 	 * Gets the num-lanes from DT
   246	 	 * Gets MSI capability from DT
   247	 	 * Calls the platform specific host initialization
   248	 	 * Program the correct class, BAR0, Link width,  in Config space
   249	 	 * Then it calls pci common init routine
   250	 	 * Then it calls funtion to assign "unassigend reources"
   251	         */
   252		ret = dw_pcie_host_init(pp);
   253		if (ret) {
   254			dev_err(&pdev->dev, "failed to initialize host\n");
   255			return ret;
   256		}
   257	
   258		return 0;
   259	}
   260	
   261	/**
   262	 * snpsdev_pcie_rc_probe()
   263	 * This function gets called as part of pcie registration. if the id matches
   264	 * the platform driver framework will call this function.
   265	 *
   266	 * @pdev: Pointer to the platform_device structure
   267	 *
   268	 * Returns zero on success; Negative errorno on failure
   269	 */
   270	static int __init snpsdev_pcie_rc_probe(struct platform_device *pdev)
   271	{
   272		struct snpsdev_pcie *snpsdev_pcie;
   273		struct pcie_port *pp;
   274		struct resource *dwc_pcie_rc_res;  /* Resource from DT */
   275		int ret;
   276	
   277		snpsdev_pcie = devm_kzalloc(&pdev->dev, sizeof(*snpsdev_pcie), GFP_KERNEL);
   278		if (!snpsdev_pcie) {
   279			dev_err(&pdev->dev, "no memory for snpsdev pcie\n");
   280			return -ENOMEM;
   281		}
   282	
   283		pp = &snpsdev_pcie->pp;
   284		pp->dev = &pdev->dev;
   285	
   286		dwc_pcie_rc_res= platform_get_resource(pdev, IORESOURCE_MEM, 0);
   287		if (!dwc_pcie_rc_res) {
   288			dev_err(&pdev->dev, "dwc_pcie_rc_res resource not found\n");
   289			return -ENODEV;
   290		}
   291	
   292		snpsdev_pcie->mem_base = devm_ioremap_resource(&pdev->dev, dwc_pcie_rc_res);
   293		if (IS_ERR(snpsdev_pcie->mem_base)) {
   294			ret = PTR_ERR(snpsdev_pcie->mem_base);
   295			return ret;
   296		}
   297		pp->dbi_base = snpsdev_pcie->mem_base;	
   298	
   299		ret = snpsdev_add_pcie_port(pp, pdev);
   300		if (ret < 0)
   301			return ret;
   302	
   303		platform_set_drvdata(pdev, snpsdev_pcie);
   304	
   305		return 0;
   306	}
   307	
   308	static int __exit snpsdev_pcie_rc_remove(struct platform_device *pdev)
   309	{
   310		return 0;
   311	}
   312	
   313	static const struct of_device_id snpsdev_pcie_rc_of_match[] = {
   314		{ .compatible = "snps,pcie-snpsdev", },
   315		{},
   316	};
   317	MODULE_DEVICE_TABLE(of, snpsdev_pcie_rc_of_match);
   318	
   319	static struct platform_driver snpsdev_pcie_rc_driver = {
   320		.remove		= __exit_p(snpsdev_pcie_rc_remove),
   321		.driver = {
   322			.name	= "pcie-snpsdev",
 > 323			.owner	= THIS_MODULE,
   324			.of_match_table = snpsdev_pcie_rc_of_match,
   325		},
   326	};

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index d5e58ba..b9d59f6 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -145,4 +145,9 @@  config PCIE_IPROC_BCMA
 	  Say Y here if you want to use the Broadcom iProc PCIe controller
 	  through the BCMA bus interface
 
+config PCIE_SNPSDEV 
+	bool "Platform Driver for Synopsys Device" 
+	select PCIEPORTBUS 
+	select PCIE_DW 
+
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 140d66f..c35c42a 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -17,3 +17,4 @@  obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
 obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
 obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o
 obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
+obj-$(CONFIG_PCIE_SNPSDEV) += pcie-snpsdev.o
diff --git a/drivers/pci/host/pcie-snpsdev.c b/drivers/pci/host/pcie-snpsdev.c
new file mode 100644
index 0000000..7389097
--- /dev/null
+++ b/drivers/pci/host/pcie-snpsdev.c
@@ -0,0 +1,337 @@ 
+/*
+ * PCIe RC driver for Synopsys Designware Core
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Manjunath Bettegowda <manjumb@synopsys.com>,
+ *	    Jie Deng <jiedeng@synopsys.com>
+ *	    Joao Pinto <jpinto@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 structrue - DWC_PCIE_RC stuff */
+};
+
+#define SIZE_1GB 0x40000000
+#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 */
+
+/* PCIE PHY CONTROL REGISTER: Useful for cfg_phy_control GPIO outputs */
+#define PCIE_PHY_CTRL (PLR_OFFSET + 0x114)    /* 0x814 */
+/* PCIE PHY STATUS REGISTER: Useful for phy_cfg_status GPIO inputs */
+#define PCIE_PHY_STAT (PLR_OFFSET + 0x110)    /* 0x810 */
+
+static void snpsdev_pcie_fixup_bridge(struct pci_dev *dev)
+{
+	u32 slot_cap;
+	u16 caps_reg = pcie_caps_reg(dev) | PCI_EXP_FLAGS_SLOT;
+	pcie_capability_write_word(dev, PCI_EXP_FLAGS, caps_reg);
+	dev->pcie_flags_reg = caps_reg;
+
+	pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, &slot_cap);
+	slot_cap = slot_cap & (~PCI_EXP_SLTCAP_SPLV);
+	slot_cap = slot_cap | (0x30 << 7);
+	pcie_capability_write_dword(dev, PCI_EXP_SLTCAP, slot_cap);
+
+	if (pcibios_enable_device(dev, ~0) < 0) {
+		pr_err("PCI: synopsys device enable failed\n");
+		return;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, snpsdev_pcie_fixup_bridge);
+
+static void snpsdev_pcie_fixup_res(struct pci_dev *dev)
+{
+	struct resource *res;
+	resource_size_t size;
+	int bar;
+
+	for (bar = 0; bar < 6; bar++) {
+		res = dev->resource + bar;
+		size = resource_size(res);
+
+		if (size == SIZE_1GB)
+		{
+			res->start = 0;
+			res->end   = 0;
+			res->flags = 0;
+		}
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, snpsdev_pcie_fixup_res);
+
+/* 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;
+}
+
+/*
+ * 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)
+{
+	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);
+
+	/* Check for Link up indication */
+	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;
+		}
+	}
+
+	if (IS_ENABLED(CONFIG_PCI_MSI))
+		dw_pcie_msi_init(pp);
+
+	return;
+}
+/**
+ *
+ * Let all outof band signalling be handled by cfg_phy_control[31:0]
+ * which is selected through optional config attribute PHY_CONTROL_REG
+ *
+ * Monitor cxpl_debug_info as required to take necessary action
+ * This is available in the register PCIE_PHY_DEBUG_R0 & PCIE_PHY_DEBUG_R1
+ *
+ */ 
+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 whihc 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 int he 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 funtion to assign "unassigend reources"
+         */
+	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 __init 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) {
+		dev_err(&pdev->dev, "no memory for snpsdev pcie\n");
+		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) {
+		dev_err(&pdev->dev, "dwc_pcie_rc_res resource not found\n");
+		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 __exit 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 = {
+	.remove		= __exit_p(snpsdev_pcie_rc_remove),
+	.driver = {
+		.name	= "pcie-snpsdev",
+		.owner	= THIS_MODULE,
+		.of_match_table = snpsdev_pcie_rc_of_match,
+	},
+};
+
+static int __init snpsdev_pcie_init(void)
+{
+	return platform_driver_probe(&snpsdev_pcie_rc_driver, snpsdev_pcie_rc_probe);
+}
+subsys_initcall(snpsdev_pcie_init);
+
+MODULE_AUTHOR("Manjunath Bettegowda <manjumb@synopsys.com>");
+MODULE_DESCRIPTION("Platform Driver for Synopsys Device");
+MODULE_LICENSE("GPL v2");
+