mirror of
https://github.com/brain-hackers/linux-brain.git
synced 2024-06-09 23:36:23 +09:00
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:
commit
8a60512601
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
176
drivers/pci/controller/dwc/pci-imx6-ep.c
Normal file
176
drivers/pci/controller/dwc/pci-imx6-ep.c
Normal 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
|
@ -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 },
|
||||
|
|
|
@ -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 */
|
||||
|
|
31
include/dt-bindings/soc/imx8_hsio.h
Normal file
31
include/dt-bindings/soc/imx8_hsio.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user