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.ru
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
This commit is contained in:
Serge Semin 2022-06-24 17:39:44 +03:00 committed by Bjorn Helgaas
parent 5a163f5998
commit 89473aa9ab
2 changed files with 31 additions and 4 deletions

View File

@ -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)

View File

@ -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;