summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/dwc/pcie-designware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-designware.c')
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c93
1 files changed, 86 insertions, 7 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index b5e438b70cd5..645fa1892375 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -546,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;
@@ -556,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);