If no ATU resource is defined in the devicetree, then driver´s default
value '0x300000' [1] is set. This is done during probing in the function
'dw_pcie_get_resources()' [2] by dwc core.
The driver overwrites this again when its own init callback
'pp->ops->init()' [3] function 'intel_pcie_host_setup()' [4] is called.
This is done, because the 'atu_base' value for this IP is '0xC0000'
rather than '0x300000'.
callstack:
intel_pcie_probe()
dw_pcie_host_init()
dw_pcie_host_get_resources()
dw_pcie_get_resources() [2]
pp->ops->init = intel_pcie_rc_init() [3]
intel_pcie_host_setup() [4]
However, this is a problem because, the callback 'pp->ops->init' is called
after 'dw_pcie_get_resources()' in dwc core (see callstack). The 'atu_base'
must be set before, so that this value is not set by dwc core. Therefor
the assignment of 'atu_base' is moved to driver´s probe function.
While we’re at it, the change also adds the option to load ATU information
from the device tree. For reasons of backwards compatibility, this is not
mandatory. If ‘atu’ is still not specified in the devicetree, then driver’s
default value is still used and set in driver´s probe function. If the 'atu'
resource is present in the devicetree, then dwc core loads it via the
function 'dw_pcie_get_resources()' and not in the driver´s probe function.
[1] https://elixir.bootlin.com/linux/v6.19.10/source/drivers/pci/controller/dwc/pcie-designware.h#L292
[2] https://elixir.bootlin.com/linux/v6.19.10/source/drivers/pci/controller/dwc/pcie-designware.c#L150
[3] https://elixir.bootlin.com/linux/v6.19.10/source/drivers/pci/controller/dwc/pcie-designware-host.c#L589
[4] https://elixir.bootlin.com/linux/v6.19.10/source/drivers/pci/controller/dwc/pcie-intel-gw.c#L301
Signed-off-by: Florian Eckert <fe@dev.tdt.de>
---
drivers/pci/controller/dwc/pcie-intel-gw.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index afd933050c92ee31c477e0b1738ab1136bdcfbf6..59b11e45944e199aac0f599f96d6cc90e2104708 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -310,8 +310,6 @@ static int intel_pcie_host_setup(struct intel_pcie *pcie)
goto clk_err;
}
- pci->atu_base = pci->dbi_base + 0xC0000;
-
ret = phy_init(pcie->phy);
if (ret)
goto phy_err;
@@ -395,6 +393,7 @@ static int intel_pcie_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct intel_pcie *pcie;
struct dw_pcie_rp *pp;
+ struct resource *res;
struct dw_pcie *pci;
int ret;
@@ -419,6 +418,31 @@ static int intel_pcie_probe(struct platform_device *pdev)
pci->ops = &intel_pcie_ops;
pp->ops = &intel_pcie_dw_ops;
+ /*
+ * If the 'atu' resource is not available in the devicetree,
+ * then use the driver default value for backward compatibility.
+ * The 'atu' should always be set in the devicetree, as this is
+ * hardware specific setting that should not be defined in the
+ * source.
+ */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
+ if (!res) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+ pci->dbi_base = devm_pci_remap_cfg_resource(pci->dev, res);
+ if (IS_ERR(pci->dbi_base))
+ return PTR_ERR(pci->dbi_base);
+ pci->dbi_phys_addr = res->start;
+ pci->atu_base = devm_ioremap(dev, res->start + 0xC0000, SZ_4K);
+ if (!pci->atu_base) {
+ dev_err(dev, "failed to remap ATU space\n");
+ return -ENOMEM;
+
+ }
+ pci->atu_size = SZ_4K;
+ pci->atu_phys_addr = res->start + 0xC0000;
+ dev_warn(dev, "devicetree ATU resource is missing; driver`s default value is being used\n");
+ }
+
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "Cannot initialize host\n");
--
2.47.3