summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2014-02-10 14:56:46 +0800
committerRichard Zhu <r65037@freescale.com>2014-02-13 13:09:44 +0800
commit912e09484adf2cbf05b0338fe696b305f2e481ee (patch)
tree0772162711adf78a3184c1141d36c71f0a8fe49f /drivers
parent90c7fd0ac4540a25586db99913d01d17b970b829 (diff)
ENGR00298392 pcie: imx pcie ep rc msi demo
- add one imx pcie ep simple skeleton driver to demo the msi trigger capability in imx6 pcie rc/ep validation system - in order to avoid the modification of common codes, force the msi address to be 0x01ff8000 Test howto: - Enable CONFIG_PCI_MSI=y, when rebuild the rc/ep images - EP side(console command and kernel message): root@sabresd_6dq:/ # memtool 0x1ff8000=0 Writing 32-bit value 0x0 to address 0x01FF8000 root@sabresd_6dq:/ # - RC side(console command and kernel message): root@sabresd_6dq:/ # cat /proc/interrupts | grep MSI 384: 1 0 0 0 PCI-MSI - EP side(console command and kernel message): root@sabresd_6dq:/ # memtool 0x1ff8000=0 Writing 32-bit value 0x0 to address 0x01FF8000 - RC side(console command and kernel message): root@sabresd_6dq:/ # cat /proc/interrupts | grep MSI 384: 2 0 0 0 PCI-MSI Signed-off-by: Richard Zhu <r65037@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/host/Kconfig5
-rw-r--r--drivers/pci/host/Makefile1
-rw-r--r--drivers/pci/host/pci-imx6-ep-driver.c159
3 files changed, 165 insertions, 0 deletions
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 4e81a8d7eef5..120714876e83 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -32,6 +32,11 @@ config RC_MODE_IN_EP_RC_SYS
bool "PCI Express RC mode in the IMX6 RC/EP interconnection system"
depends on PCI_IMX6
+config PCI_IMX_EP_DRV
+ bool "i.MX6 PCI Express EP skeleton driver"
+ depends on RC_MODE_IN_EP_RC_SYS
+ default y
+
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 3fe390083b49..df45c7f52fda 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_PCIE_DW) += pcie-designware.o
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+obj-$(CONFIG_PCI_IMX_EP_DRV) += pci-imx6-ep-driver.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
diff --git a/drivers/pci/host/pci-imx6-ep-driver.c b/drivers/pci/host/pci-imx6-ep-driver.c
new file mode 100644
index 000000000000..0f5d4df1d13c
--- /dev/null
+++ b/drivers/pci/host/pci-imx6-ep-driver.c
@@ -0,0 +1,159 @@
+/*
+ * PCIe endpoint skeleton driver for IMX6 SOCs
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#define DRV_DESCRIPTION "i.MX PCIE endpoint device driver"
+#define DRV_VERSION "version 0.1"
+#define DRV_NAME "imx_pcie_ep"
+
+struct imx_pcie_ep_priv {
+ struct pci_dev *pci_dev;
+ void __iomem *hw_base;
+};
+
+/**
+ * imx_pcie_ep_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @id: entry in id_tbl
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int imx_pcie_ep_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret = 0;
+ struct device *dev = &pdev->dev;
+ struct imx_pcie_ep_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(dev, "can't alloc imx pcie priv\n");
+ return -ENOMEM;
+ }
+
+ priv->pci_dev = pdev;
+
+ if (pci_enable_device(pdev)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ pci_set_master(pdev);
+
+ pci_set_drvdata(pdev, priv);
+
+ priv->hw_base = pci_iomap(pdev, 0, 0);
+ if (!priv->hw_base) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ pr_info("pci_resource_len = 0x%08llx\n",
+ (unsigned long long) pci_resource_len(pdev, 0));
+ pr_info("pci_resource_base = %p\n", priv->hw_base);
+
+ ret = pci_enable_msi(priv->pci_dev);
+ if (ret < 0) {
+ dev_err(dev, "can't enable msi\n");
+ return ret;
+ }
+
+ /*
+ * Force to use 0x01FF8000 as the MSI address,
+ * to do the MSI demo
+ */
+ pci_bus_write_config_dword(pdev->bus, 0, 0x54, 0x01FF8000);
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x820, 0x01FF8000);
+
+ /* configure rc's msi cap */
+ pci_bus_read_config_dword(pdev->bus->parent, 0, 0x50, &ret);
+ ret |= (PCI_MSI_FLAGS_ENABLE << 16);
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x50, ret);
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x828, 0x1);
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x82C, 0xFFFFFFFE);
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static void imx_pcie_ep_remove(struct pci_dev *pdev)
+{
+ struct imx_pcie_ep_priv *priv = pci_get_drvdata(pdev);
+
+ if (!priv)
+ return;
+ pr_info("***imx pcie ep driver unload***\n");
+}
+
+static struct pci_device_id imx_pcie_ep_ids[] = {
+ {
+ .class = PCI_CLASS_MEMORY_RAM << 8,
+ .class_mask = ~0,
+ .vendor = 0xbeaf,
+ .device = 0xdead,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ { } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, imx_pcie_ep_ids);
+
+static struct pci_driver imx_pcie_ep_driver = {
+ .name = DRV_NAME,
+ .id_table = imx_pcie_ep_ids,
+ .probe = imx_pcie_ep_probe,
+ .remove = imx_pcie_ep_remove,
+};
+
+static int __init imx_pcie_ep_init(void)
+{
+ int ret;
+ pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+
+ ret = pci_register_driver(&imx_pcie_ep_driver);
+ if (ret)
+ pr_err("Unable to initialize PCI module\n");
+
+ return ret;
+}
+
+static void __exit imx_pcie_ep_exit(void)
+{
+ pci_unregister_driver(&imx_pcie_ep_driver);
+}
+
+module_exit(imx_pcie_ep_exit);
+module_init(imx_pcie_ep_init);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("imx_pcie_ep");