Merge remote-tracking branch 'origin/pcie/dwc' into pcie/next

* origin/pcie/dwc: (22 commits)
  LF-128 PCI: imx: turn off the clocks and regulators when link is down
  PCI: imx: add the imx pcie ep verification solution
  MLK-22995: pci: controller: dwc: pci-imx6: fix regulator warning complains on i.mx6sx-sdb
  PCI: dwc: fix the msi failure after pm operations
  Revert "MLK-11484-3 PCI: designware: Refine setup_rc and add msi data restore"
  ...
This commit is contained in:
Dong Aisheng 2019-12-02 18:01:51 +08:00
commit 8a60512601
9 changed files with 1732 additions and 149 deletions

View File

@ -10,6 +10,9 @@ Required properties:
- "fsl,imx6qp-pcie"
- "fsl,imx7d-pcie"
- "fsl,imx8mq-pcie"
- "fsl,imx8mm-pcie"
- "fsl,imx8qm-pcie"
- "fsl,imx8qxp-pcie"
- reg: base address and length of the PCIe controller
- interrupts: A list of interrupt outputs of the controller. Must contain an
entry for each entry in the interrupt-names property.
@ -60,6 +63,17 @@ Additional required properties for imx8mq-pcie:
- clock-names: Must include the following additional entries:
- "pcie_aux"
Additional required properties for imx8 pcie:
- hsio-cfg: hsio configration mode when the pcie node is supported.
mode 1: pciea 2 lanes and one sata ahci port.
mode 2: pciea 1 lane, pcieb 1 lane and one sata ahci port.
mode 3: pciea 2 lanes, pcieb 1 lane.
- local-addr: the local address used in hsio module.
Example:
hsio-cfg = <PCIEAX2PCIEBX1>;
hsio = <&hsio>;
local-addr = <0x80000000>;
Example:
pcie@01000000 {

View File

@ -21,6 +21,7 @@ Required properties:
"fsl,ls1046a-pcie"
"fsl,ls1043a-pcie"
"fsl,ls1012a-pcie"
"fsl,ls1028a-pcie"
EP mode:
"fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep"
- reg: base addresses and lengths of the PCIe controller register blocks.

View File

@ -94,6 +94,27 @@ config PCI_IMX6
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST
config PCI_IMX6_COMPLIANCE_TEST
bool "Enable pcie compliance tests on imx6"
depends on PCI_IMX6
default n
help
Say Y here if you want do the compliance tests on imx6 pcie rc found
on FSL iMX SoCs.
config EP_MODE_IN_EP_RC_SYS
bool "PCI Express EP mode in the IMX6 RC/EP interconnection system"
depends on PCI_IMX6
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_IMX6_EP
bool "i.MX6 PCI Express EP skeleton driver"
depends on RC_MODE_IN_EP_RC_SYS
default y
config PCIE_SPEAR13XX
bool "STMicroelectronics SPEAr PCIe controller"
depends on ARCH_SPEAR13XX || COMPILE_TEST

View File

@ -6,6 +6,7 @@ obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.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_IMX6_EP) += pci-imx6-ep.o
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o

View File

@ -0,0 +1,176 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.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>
#include <linux/of_address.h>
#include <linux/of_irq.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;
};
/**
* 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, index = 0, found = 0;
unsigned int hard_wired = 0, msi_addr = 0, local_addr;
struct resource cfg_res;
const char *name = NULL;
struct device_node *np = NULL;
struct device *dev = &pdev->dev;
struct imx_pcie_ep_priv *priv;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->pci_dev = pdev;
if (pci_enable_device(pdev)) {
ret = -ENODEV;
goto out;
}
pci_set_master(pdev);
pci_set_drvdata(pdev, priv);
ret = pci_enable_msi(priv->pci_dev);
if (ret < 0) {
dev_err(dev, "can't enable msi\n");
goto err_pci_unmap_mmio;
}
/* Use the first none-hard-wired port as ep */
while ((np = of_find_node_by_type(np, "pci"))) {
if (!of_device_is_available(np))
continue;
if (of_property_read_u32(np, "hard-wired", &hard_wired)) {
if (hard_wired == 0)
break;
}
}
if (of_property_read_u32(np, "local-addr", &local_addr))
local_addr = 0;
while (!of_property_read_string_index(np, "reg-names", index, &name)) {
if (strcmp("config", name)) {
index++;
continue;
}
found = 1;
break;
}
if (!found) {
dev_err(dev, "can't find config reg space.\n");
ret = -EINVAL;
goto err_pci_disable_msi;
}
ret = of_address_to_resource(np, index, &cfg_res);
if (ret) {
dev_err(dev, "can't get cfg_res.\n");
ret = -EINVAL;
goto err_pci_disable_msi;
} else {
msi_addr = cfg_res.start + resource_size(&cfg_res);
}
pr_info("msi_addr 0x%08x, local_addr 0x%08x\n", msi_addr, local_addr);
pci_bus_write_config_dword(pdev->bus, 0, 0x54, msi_addr);
if (local_addr) {
msi_addr = msi_addr & 0xFFFFFFF;
msi_addr |= (local_addr & 0xF0000000);
}
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;
err_pci_disable_msi:
pci_disable_msi(pdev);
err_pci_unmap_mmio:
pci_disable_device(pdev);
out:
kfree(priv);
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");

File diff suppressed because it is too large Load Diff

View File

@ -263,6 +263,7 @@ static const struct ls_pcie_drvdata ls2088_drvdata = {
static const struct of_device_id ls_pcie_of_match[] = {
{ .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata },
{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
{ .compatible = "fsl,ls1028a-pcie", .data = &ls2088_drvdata },
{ .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
{ .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
{ .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },

View File

@ -156,8 +156,8 @@ static void dw_pci_bottom_mask(struct irq_data *d)
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
pp->irq_mask[ctrl] |= BIT(bit);
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
pp->irq_mask[ctrl]);
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
~pp->irq_mask[ctrl]);
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
@ -175,8 +175,8 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
pp->irq_mask[ctrl] &= ~BIT(bit);
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
pp->irq_mask[ctrl]);
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
~pp->irq_mask[ctrl]);
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
@ -653,18 +653,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
dw_pcie_setup(pci);
if (!pp->ops->msi_host_init) {
/* Program the msi_data */
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
lower_32_bits((u64)pp->msi_data));
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
upper_32_bits((u64)pp->msi_data));
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
/* Initialize IRQ Status array */
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
pp->irq_mask[ctrl] = ~0;
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
for (ctrl = 0; ctrl < num_ctrls; ctrl++)
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
4, pp->irq_mask[ctrl]);
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
4, ~0);
}
4, &pp->irq_mask[ctrl]);
}
/* Setup RC BARs */

View File

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2019 NXP
*
* 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.
*/
#ifndef __DT_BINDINGS_IMX8_HSIO_H
#define __DT_BINDINGS_IMX8_HSIO_H
/*
* imx8qm hsio has pciea, pcieb and sata modules, and hsio
* can be configured to the following different work modes.
* 1 - pciea 2 lanes and one sata ahci port.
* 2 - pciea 1 lane, pcieb 1 lane and one sata ahci port.
* 3 - pciea 2 lanes, pcieb 1 lane.
* Choose one mode, refer to the exact hardware board design.
*/
#define PCIEAX2SATA 1
#define PCIEAX1PCIEBX1SATA 2
#define PCIEAX2PCIEBX1 3
#endif /* __DT_BINDINGS_IMX8_HSIO_H */