Commit 89473aa9 authored by Serge Semin's avatar Serge Semin Committed by Bjorn Helgaas

PCI: dwc: Add iATU regions size detection procedure

The DWC PCIe RC/EP/DM IP core configuration parameters determine the number
of inbound and outbound iATU windows, alignment requirements (which is also
the minimum window size), minimum and maximum sizes.  If internal ATU is
enabled, the former settings are determined by CX_ATU_MIN_REGION_SIZE; the
latter are determined by CX_ATU_MAX_REGION_SIZE.

Determine the required alignment and maximum size supported by the
controller and log it to help verify whether the requested inbound or
outbound memory mappings can be fully created.

Note 1. The extended iATU regions have been supported since DWC PCIe
v4.60a. There is no need in testing the upper limit register availability
for the older cores.

Note 2. The regions alignment is determined with using the fls() method
since the lower four bits of the ATU Limit register can be occupied with
the Circular Buffer Increment setting, which can be initialized with zeros.

Link: https://lore.kernel.org/r/20220624143947.8991-13-Sergey.Semin@baikalelectronics.ruSigned-off-by: default avatarSerge Semin <Sergey.Semin@baikalelectronics.ru>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarRob Herring <robh@kernel.org>
Reviewed-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
parent 5a163f59
......@@ -8,9 +8,11 @@
* Author: Jingoo Han <jg1.han@samsung.com>
*/
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/sizes.h>
#include <linux/types.h>
#include "../../pci.h"
......@@ -522,7 +524,8 @@ static bool dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
{
int max_region, ob, ib;
u32 val;
u32 val, min, dir;
u64 max;
if (pci->iatu_unroll_enabled) {
max_region = min((int)pci->atu_size / 512, 256);
......@@ -545,8 +548,29 @@ static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
break;
}
pci->num_ib_windows = ib;
if (ob) {
dir = PCIE_ATU_REGION_DIR_OB;
} else if (ib) {
dir = PCIE_ATU_REGION_DIR_IB;
} else {
dev_err(pci->dev, "No iATU regions found\n");
return;
}
dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_LIMIT, 0x0);
min = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_LIMIT);
if (dw_pcie_ver_is_ge(pci, 460A)) {
dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT, 0xFFFFFFFF);
max = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT);
} else {
max = 0;
}
pci->num_ob_windows = ob;
pci->num_ib_windows = ib;
pci->region_align = 1 << fls(min);
pci->region_limit = (max << 32) | (SZ_4G - 1);
}
void dw_pcie_iatu_detect(struct dw_pcie *pci)
......@@ -579,8 +603,9 @@ void dw_pcie_iatu_detect(struct dw_pcie *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\n",
pci->num_ob_windows, pci->num_ib_windows);
dev_info(pci->dev, "iATU regions: %u ob, %u ib, align %uK, limit %lluG\n",
pci->num_ob_windows, pci->num_ib_windows,
pci->region_align / SZ_1K, (pci->region_limit + 1) / SZ_1G);
}
void dw_pcie_setup(struct dw_pcie *pci)
......
......@@ -272,6 +272,8 @@ struct dw_pcie {
size_t atu_size;
u32 num_ib_windows;
u32 num_ob_windows;
u32 region_align;
u64 region_limit;
struct dw_pcie_rp pp;
struct dw_pcie_ep ep;
const struct dw_pcie_ops *ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment