summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2021-11-23 18:06:34 +0000
committerBjorn Helgaas <bhelgaas@google.com>2021-12-07 10:37:31 -0600
commitee91cb570d9b12ae8cfcb96f7ea6fb80983b6a0a (patch)
treefde81c377ef0beea9a9c2bafddc792fe5071289a /drivers/pci
parent39bd54d43b3f8b3c7b3a75f5d868d8bb858860e7 (diff)
PCI: apple: Follow the PCIe specifications when resetting the port
While the Apple PCIe driver works correctly when directly booted from the firmware, it fails to initialise when the kernel is booted from a bootloader using PCIe such as u-boot. That's because we're missing a proper reset of the port (we only clear the reset, but never assert it). The PCIe spec requirements are two-fold: - PERST# must be asserted before setting up the clocks and stay asserted for at least 100us (Tperst-clk) - Once PERST# is deasserted, the OS must wait for at least 100ms "from the end of a Conventional Reset" before we can start talking to the devices Implementing this results in a booting system. [bhelgaas: #PERST -> PERST#, update spec references to current] Fixes: 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up") Link: https://lore.kernel.org/r/20211123180636.80558-2-maz@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Luca Ceresoli <luca@lucaceresoli.net> Acked-by: Pali Rohár <pali@kernel.org> Cc: Alyssa Rosenzweig <alyssa@rosenzweig.io> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/controller/pcie-apple.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c
index 1bf4d75b61be..c384777b0374 100644
--- a/drivers/pci/controller/pcie-apple.c
+++ b/drivers/pci/controller/pcie-apple.c
@@ -516,7 +516,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
int ret, i;
reset = gpiod_get_from_of_node(np, "reset-gpios", 0,
- GPIOD_OUT_LOW, "#PERST");
+ GPIOD_OUT_LOW, "PERST#");
if (IS_ERR(reset))
return PTR_ERR(reset);
@@ -539,13 +539,23 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
+ /* Assert PERST# before setting up the clock */
+ gpiod_set_value(reset, 0);
+
ret = apple_pcie_setup_refclk(pcie, port);
if (ret < 0)
return ret;
+ /* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */
+ usleep_range(100, 200);
+
+ /* Deassert PERST# */
rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
gpiod_set_value(reset, 1);
+ /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
+ msleep(100);
+
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
stat & PORT_STATUS_READY, 100, 250000);
if (ret < 0) {