lab.nexedi.com will be down from Thursday, 20 March 2025, 07:30:00 UTC for a duration of approximately 2 hours

Commit ee91cb57 authored by Marc Zyngier's avatar Marc Zyngier Committed by Bjorn Helgaas

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: 1e33888f ("PCI: apple: Add initial hardware bring-up")
Link: https://lore.kernel.org/r/20211123180636.80558-2-maz@kernel.orgSigned-off-by: default avatarMarc Zyngier <maz@kernel.org>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarLuca Ceresoli <luca@lucaceresoli.net>
Acked-by: default avatarPali Rohár <pali@kernel.org>
Cc: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
parent 39bd54d4
......@@ -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) {
......
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