diff options
author | Richard Zhu <Richard.Zhu@freescale.com> | 2015-09-01 14:29:55 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@nxp.com> | 2016-01-14 11:01:30 -0600 |
commit | e840f69359fd2ee1839a63ed47389eb5b0edf7b9 (patch) | |
tree | aaadd2eb4ef016ea8ec85cbc1168203198eea405 /drivers/pci | |
parent | 142d31f5c7ea733b467e887c150f4a8ec6e666fd (diff) |
MLK-11484-6 pci: imx: enable pcie ep rc msi test
Regarding to the limitation of the iMX ADAP(pcie connector),
only imx7d 12x12 arm2 board is used to verify the pcie
ep/rc validation system on imx7d platforms
Enalbe the msi pcie ep rc on it.
Test howto:
- Enable CONFIG_PCI_MSI=y, when rebuild the rc/ep images
- EP side(console command and kernel message):
root@imx6sxsabresd:~# ./memtool -32 <msi_addr>=0
Writing 32-bit value 0x0 to address <msi_addr>
- RC side(console command and kernel message):
root@imx6sxsabresd:~# cat /proc/interrupts | grep MSI
384: 1 PCI-MSI
Note:
imx6q msi_addr 0x01ff_8000
imx6sx msi_addr 0x08ff_8000
imx7d msi_addr 0x4ffc_0000
Signed-off-by: Richard Zhu <Richard.Zhu@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 | 171 |
3 files changed, 177 insertions, 0 deletions
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index a80a0e8e94ad..1d0981f5d310 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -38,6 +38,11 @@ config RC_MODE_IN_EP_RC_SYS bool "PCI Express RC mode in the IMX6 RC/EP interconnection system" depends on PCI_IMX6 && EP_MODE_IN_EP_RC_SYS!=y +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 && !ARM64 diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index f733b4e27642..a99dc369ee8b 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.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 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.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..192ced7cbffc --- /dev/null +++ b/drivers/pci/host/pci-imx6-ep-driver.c @@ -0,0 +1,171 @@ +/* + * PCIe endpoint skeleton driver for IMX6 SOCs + * + * Copyright (C) 2014-2015 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> +#include <linux/of.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; + unsigned int msi_addr = 0; + struct device_node *np; + 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; + } + + np = of_find_compatible_node(NULL, NULL, "snps,dw-pcie"); + + /* + * Force to use the hardcode MSI address to do the MSI demo + */ + if (of_device_is_compatible(np, "fsl,imx7d-pcie")) + msi_addr = 0x4FFC0000; + else if (of_device_is_compatible(np, "fsl,imx6sx-pcie")) + msi_addr = 0x08FF8000; + else + msi_addr = 0x01FF8000; + + pr_info("pci_msi_addr = 0x%08x\n", msi_addr); + pci_bus_write_config_dword(pdev->bus, 0, 0x54, msi_addr); + pci_bus_write_config_dword(pdev->bus->parent, 0, 0x820, msi_addr); + + /* 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"); |