summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/dwc/pcie-designware.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2020-12-16 00:11:11 +0300
committerBjorn Helgaas <bhelgaas@google.com>2020-12-16 00:11:11 +0300
commitff9f1683b63022035981045ce0368ec047d0ed1c (patch)
tree91672c7eca70ecf77a2b835f98376ef5c264875c /drivers/pci/controller/dwc/pcie-designware.c
parentee4871d0102b09d1b23b95f2f746baf327205876 (diff)
parent660c486590aa4190969653218643b3a4e5660f2b (diff)
downloadlinux-ff9f1683b63022035981045ce0368ec047d0ed1c.tar.xz
Merge branch 'remotes/lorenzo/pci/dwc'
- Support multiple ATU memory regions (Rob Herring) - Warn if non-prefetchable memory aperture is > 32-bit (Vidya Sagar) - Allow programming ATU for >4GB memory (Vidya Sagar) - Move ATU offset out of driver match data (Rob Herring) - Move "dbi", "dbi2", and "addr_space" resource setup to common code (Rob Herring) - Remove unneeded function wrappers (Rob Herring) - Ensure all outbound ATU windows are reset to reduce dependencies on bootloader (Rob Herring) - Use the default MSI irq_chip for dra7xx (Rob Herring) - Drop the .set_num_vectors() host op (Rob Herring) - Move MSI interrupt setup into DWC common code (Rob Herring) - Rework and simplify DWC MSI initialization (Rob Herring) - Move link handling to DWC common code (Rob Herring) - Move dw_pcie_msi_init() calls to DWC common code (Rob Herring) - Move dw_pcie_setup_rc() calls to DWC common code (Rob Herring) - Remove unnecessary wrappers around dw_pcie_host_init() (Rob Herring) - Revert "keystone: Drop duplicated 'num-viewport'" to prepare for detecting number of iATU regions without help from DT (Rob Herring) - Move inbound and outbound windows to common struct (Rob Herring) - Detect number of DWC iATU windows from device registers (Rob Herring) - Drop samsung,exynos5440-pcie binding (Marek Szyprowski) - Add samsung,exynos-pcie and samsung,exynos-pcie-phy bindings for Exynos5433 variant (Marek Szyprowski) - Rework phy-exynos-pcie driver to support Exynos5433 PCIe PHY (Jaehoon Chung) - Rework pci-exynos.c to support Exynos5433 PCIe host (Jaehoon Chung) - Move tegra "dbi" accesses to post common DWC initialization (Vidya Sagar) - Read tegra dbi" base address in application logic (Vidya Sagar) - Fix tegra ASPM-L1SS advertisement disable code (Vidya Sagar) - Set Tegra194 DesignWare IP version to 0x490A (Vidya Sagar) - Continue tegra unconfig sequence even if parts fail (Vidya Sagar) - Check return value of tegra_pcie_init_controller() (Vidya Sagar) - Disable tegra LTSSM during L2 entry (Vidya Sagar) - Add SM8250 SoC PCIe DT bindings and support (Manivannan Sadhasivam) - Add SM8250 BDF to SID mapping (Manivannan Sadhasivam) - Set 32-bit DMA mask for DWC MSI target address allocation (Vidya Sagar) * remotes/lorenzo/pci/dwc: PCI: dwc: Set 32-bit DMA mask for MSI target address allocation PCI: qcom: Add support for configuring BDF to SID mapping for SM8250 PCI: qcom: Add SM8250 SoC support dt-bindings: pci: qcom: Document PCIe bindings for SM8250 SoC PCI: tegra: Disable LTSSM during L2 entry PCI: tegra: Check return value of tegra_pcie_init_controller() PCI: tegra: Continue unconfig sequence even if parts fail PCI: tegra: Set DesignWare IP version PCI: tegra: Fix ASPM-L1SS advertisement disable code PCI: tegra: Read "dbi" base address to program in application logic PCI: tegra: Move "dbi" accesses to post common DWC initialization PCI: dwc: exynos: Rework the driver to support Exynos5433 variant phy: samsung: phy-exynos-pcie: rework driver to support Exynos5433 PCIe PHY dt-bindings: phy: exynos: add the samsung,exynos-pcie-phy binding dt-bindings: PCI: exynos: add the samsung,exynos-pcie binding dt-bindings: PCI: exynos: drop samsung,exynos5440-pcie binding PCI: dwc: Detect number of iATU windows PCI: dwc: Move inbound and outbound windows to common struct Revert "PCI: dwc/keystone: Drop duplicated 'num-viewport'" PCI: dwc: Remove unnecessary wrappers around dw_pcie_host_init() PCI: dwc: Move dw_pcie_setup_rc() to DWC common code PCI: dwc: Move dw_pcie_msi_init() into core PCI: dwc: Move link handling into common code PCI: dwc: Rework MSI initialization PCI: dwc: Move MSI interrupt setup into DWC common code PCI: dwc: Drop the .set_num_vectors() host op PCI: dwc/dra7xx: Use the common MSI irq_chip PCI: dwc: Ensure all outbound ATU windows are reset PCI: dwc/intel-gw: Remove some unneeded function wrappers PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource setup into common code PCI: dwc/intel-gw: Move ATU offset out of driver match data PCI: dwc: Add support to program ATU for >4GB memory PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit PCI: dwc: Support multiple ATU memory regions
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-designware.c')
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c105
1 files changed, 93 insertions, 12 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..645fa1892375 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
int index, int type,
u64 cpu_addr, u64 pci_addr,
- u32 size)
+ u64 size)
{
u32 retries, val;
u64 limit_addr = cpu_addr + size - 1;
@@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
upper_32_bits(pci_addr));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
- type | PCIE_ATU_FUNC_NUM(func_no));
+ val = type | PCIE_ATU_FUNC_NUM(func_no);
+ val = upper_32_bits(size - 1) ?
+ val | PCIE_ATU_INCREASE_REGION_SIZE : val;
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
PCIE_ATU_ENABLE);
@@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
int index, int type, u64 cpu_addr,
- u64 pci_addr, u32 size)
+ u64 pci_addr, u64 size)
{
u32 retries, val;
@@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
}
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
- u64 cpu_addr, u64 pci_addr, u32 size)
+ u64 cpu_addr, u64 pci_addr, u64 size)
{
__dw_pcie_prog_outbound_atu(pci, 0, index, type,
cpu_addr, pci_addr, size);
@@ -544,6 +546,70 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
return 0;
}
+static void dw_pcie_iatu_detect_regions_unroll(struct dw_pcie *pci)
+{
+ int max_region, i, ob = 0, ib = 0;
+ u32 val;
+
+ max_region = min((int)pci->atu_size / 512, 256);
+
+ for (i = 0; i < max_region; i++) {
+ dw_pcie_writel_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
+ 0x11110000);
+
+ val = dw_pcie_readl_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
+ if (val == 0x11110000)
+ ob++;
+ else
+ break;
+ }
+
+ for (i = 0; i < max_region; i++) {
+ dw_pcie_writel_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
+ 0x11110000);
+
+ val = dw_pcie_readl_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
+ if (val == 0x11110000)
+ ib++;
+ else
+ break;
+ }
+ pci->num_ib_windows = ib;
+ pci->num_ob_windows = ob;
+}
+
+static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
+{
+ int max_region, i, ob = 0, ib = 0;
+ u32 val;
+
+ dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
+ max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
+
+ for (i = 0; i < max_region; i++) {
+ dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i);
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
+ val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
+ if (val == 0x11110000)
+ ob++;
+ else
+ break;
+ }
+
+ for (i = 0; i < max_region; i++) {
+ dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i);
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
+ val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
+ if (val == 0x11110000)
+ ib++;
+ else
+ break;
+ }
+
+ pci->num_ib_windows = ib;
+ pci->num_ob_windows = ob;
+}
+
void dw_pcie_setup(struct dw_pcie *pci)
{
u32 val;
@@ -554,15 +620,30 @@ void dw_pcie_setup(struct dw_pcie *pci)
if (pci->version >= 0x480A || (!pci->version &&
dw_pcie_iatu_unroll_enabled(pci))) {
pci->iatu_unroll_enabled = true;
- if (!pci->atu_base)
- pci->atu_base =
- devm_platform_ioremap_resource_byname(pdev, "atu");
- if (IS_ERR(pci->atu_base))
- pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
- }
- dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
+ if (!pci->atu_base) {
+ struct resource *res =
+ platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
+ if (res)
+ pci->atu_size = resource_size(res);
+ pci->atu_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pci->atu_base))
+ pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+ }
+
+ if (!pci->atu_size)
+ /* Pick a minimal default, enough for 8 in and 8 out windows */
+ pci->atu_size = SZ_4K;
+
+ dw_pcie_iatu_detect_regions_unroll(pci);
+ } else
+ dw_pcie_iatu_detect_regions(pci);
+
+ dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
"enabled" : "disabled");
+ dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound",
+ pci->num_ob_windows, pci->num_ib_windows);
+
if (pci->link_gen > 0)
dw_pcie_link_set_max_speed(pci, pci->link_gen);