diff options
author | Richard Zhu <r65037@freescale.com> | 2014-02-10 14:56:46 +0800 |
---|---|---|
committer | Richard Zhu <r65037@freescale.com> | 2014-02-13 13:09:44 +0800 |
commit | 912e09484adf2cbf05b0338fe696b305f2e481ee (patch) | |
tree | 0772162711adf78a3184c1141d36c71f0a8fe49f /drivers/pci | |
parent | 90c7fd0ac4540a25586db99913d01d17b970b829 (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/pci')
-rw-r--r-- | drivers/pci/host/Kconfig | 5 | ||||
-rw-r--r-- | drivers/pci/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/host/pci-imx6-ep-driver.c | 159 |
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"); |