ep->phys_base = res->start;
        ep->addr_size = resource_size(res);
 
-       ret = of_property_read_u32(np, "num-ib-windows", &pci->num_ib_windows);
-       if (ret < 0) {
-               dev_err(dev, "Unable to read *num-ib-windows* property\n");
-               return ret;
-       }
-       if (pci->num_ib_windows > MAX_IATU_IN) {
-               dev_err(dev, "Invalid *num-ib-windows*\n");
-               return -EINVAL;
-       }
-
-       ret = of_property_read_u32(np, "num-ob-windows", &pci->num_ob_windows);
-       if (ret < 0) {
-               dev_err(dev, "Unable to read *num-ob-windows* property\n");
-               return ret;
-       }
-       if (pci->num_ob_windows > MAX_IATU_OUT) {
-               dev_err(dev, "Invalid *num-ob-windows*\n");
-               return -EINVAL;
-       }
-
        ep->ib_window_map = devm_kcalloc(dev,
                                         BITS_TO_LONGS(pci->num_ib_windows),
                                         sizeof(long),
 
                }
        }
 
-       ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
-       if (ret)
-               pci->num_viewport = 2;
-
        if (pci->link_gen < 1)
                pci->link_gen = of_pci_get_max_link_speed(np);
 
        dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
 
        /* Ensure all outbound windows are disabled so there are multiple matches */
-       for (i = 0; i < pci->num_viewport; i++)
+       for (i = 0; i < pci->num_ob_windows; i++)
                dw_pcie_disable_atu(pci, i, DW_PCIE_REGION_OUTBOUND);
 
        /*
                        if (resource_type(entry->res) != IORESOURCE_MEM)
                                continue;
 
-                       if (pci->num_viewport <= ++atu_idx)
+                       if (pci->num_ob_windows <= ++atu_idx)
                                break;
 
                        dw_pcie_prog_outbound_atu(pci, atu_idx,
                }
 
                if (pp->io_size) {
-                       if (pci->num_viewport > ++atu_idx)
+                       if (pci->num_ob_windows > ++atu_idx)
                                dw_pcie_prog_outbound_atu(pci, atu_idx,
                                                          PCIE_ATU_TYPE_IO, pp->io_base,
                                                          pp->io_bus_addr, pp->io_size);
                                pci->io_cfg_atu_shared = true;
                }
 
-               if (pci->num_viewport <= atu_idx)
+               if (pci->num_ob_windows <= atu_idx)
                        dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)",
-                                pci->num_viewport);
+                                pci->num_ob_windows);
        }
 
        dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
 
        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;
        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);