Skip to content

Commit ee91cb5

Browse files
Marc Zyngierbjorn-helgaas
authored andcommitted
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: 1e33888 ("PCI: apple: Add initial hardware bring-up") Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Luca Ceresoli <[email protected]> Acked-by: Pali Rohár <[email protected]> Cc: Alyssa Rosenzweig <[email protected]> Cc: Lorenzo Pieralisi <[email protected]>
1 parent 39bd54d commit ee91cb5

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

drivers/pci/controller/pcie-apple.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
516516
int ret, i;
517517

518518
reset = gpiod_get_from_of_node(np, "reset-gpios", 0,
519-
GPIOD_OUT_LOW, "#PERST");
519+
GPIOD_OUT_LOW, "PERST#");
520520
if (IS_ERR(reset))
521521
return PTR_ERR(reset);
522522

@@ -539,13 +539,23 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
539539

540540
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
541541

542+
/* Assert PERST# before setting up the clock */
543+
gpiod_set_value(reset, 0);
544+
542545
ret = apple_pcie_setup_refclk(pcie, port);
543546
if (ret < 0)
544547
return ret;
545548

549+
/* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */
550+
usleep_range(100, 200);
551+
552+
/* Deassert PERST# */
546553
rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
547554
gpiod_set_value(reset, 1);
548555

556+
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
557+
msleep(100);
558+
549559
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
550560
stat & PORT_STATUS_READY, 100, 250000);
551561
if (ret < 0) {

0 commit comments

Comments
 (0)