Skip to content

Commit 1a6b96f

Browse files
committed
PCI: apple: Skip controller port setup for online links
U-boot gained recently support for PCIe controller on Apple silicon devices. It is currently unkown how to reset / retrain already brought up ports. Redoing the controller level setup breaks the links. Check the link status before performing controller level port/link setup. Link: https://lore.kernel.org/u-boot/20230121192800.82428-1-kettenis@openbsd.org/ Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 6172c2b commit 1a6b96f

1 file changed

Lines changed: 62 additions & 40 deletions

File tree

drivers/pci/controller/pcie-apple.c

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -554,16 +554,13 @@ static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port,
554554
return readl_relaxed(port_rid2sid_addr(port, idx));
555555
}
556556

557-
static int apple_pcie_setup_port(struct apple_pcie *pcie,
557+
static int apple_pcie_setup_link(struct apple_pcie *pcie,
558+
struct apple_pcie_port *port,
558559
struct device_node *np)
559560
{
560-
struct platform_device *platform = to_platform_device(pcie->dev);
561-
struct apple_pcie_port *port;
562561
struct gpio_desc *reset, *pwren = NULL;
563-
struct resource *res;
564-
char name[16];
565-
u32 stat, idx;
566-
int ret, i;
562+
u32 stat;
563+
int ret;
567564

568565
reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset",
569566
GPIOD_OUT_LOW, "PERST#");
@@ -579,6 +576,54 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
579576
return PTR_ERR(pwren);
580577
}
581578

579+
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
580+
581+
/* Assert PERST# before setting up the clock */
582+
gpiod_set_value_cansleep(reset, 1);
583+
584+
/* Power on the device if required */
585+
gpiod_set_value_cansleep(pwren, 1);
586+
587+
ret = apple_pcie_setup_refclk(pcie, port);
588+
if (ret < 0)
589+
return ret;
590+
591+
/*
592+
* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2)
593+
* If powering up, the minimal Tpvperl is 100ms
594+
*/
595+
if (pwren)
596+
msleep(100);
597+
else
598+
usleep_range(100, 200);
599+
600+
/* Deassert PERST# */
601+
rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
602+
gpiod_set_value_cansleep(reset, 0);
603+
604+
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
605+
msleep(100);
606+
607+
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
608+
stat & PORT_STATUS_READY, 100, 250000);
609+
if (ret < 0) {
610+
dev_err(pcie->dev, "port %pOF ready wait timeout\n", np);
611+
return ret;
612+
}
613+
614+
return 0;
615+
}
616+
617+
static int apple_pcie_setup_port(struct apple_pcie *pcie,
618+
struct device_node *np)
619+
{
620+
struct platform_device *platform = to_platform_device(pcie->dev);
621+
struct apple_pcie_port *port;
622+
struct resource *res;
623+
char name[16];
624+
u32 link_stat, idx;
625+
int ret, i;
626+
582627
port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL);
583628
if (!port)
584629
return -ENOMEM;
@@ -614,39 +659,12 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
614659
else
615660
port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx);
616661

617-
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
618-
619-
/* Assert PERST# before setting up the clock */
620-
gpiod_set_value_cansleep(reset, 1);
621-
622-
/* Power on the device if required */
623-
gpiod_set_value_cansleep(pwren, 1);
624-
625-
ret = apple_pcie_setup_refclk(pcie, port);
626-
if (ret < 0)
627-
return ret;
628-
629-
/*
630-
* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2)
631-
* If powering up, the minimal Tpvperl is 100ms
632-
*/
633-
if (pwren)
634-
msleep(100);
635-
else
636-
usleep_range(100, 200);
637-
638-
/* Deassert PERST# */
639-
rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
640-
gpiod_set_value_cansleep(reset, 0);
641-
642-
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
643-
msleep(100);
644-
645-
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
646-
stat & PORT_STATUS_READY, 100, 250000);
647-
if (ret < 0) {
648-
dev_err(pcie->dev, "port %pOF ready wait timeout\n", np);
649-
return ret;
662+
/* link might be already brought up by u-boot, skip setup then */
663+
link_stat = readl_relaxed(port->base + PORT_LINKSTS);
664+
if (!(link_stat & PORT_LINKSTS_UP)) {
665+
ret = apple_pcie_setup_link(pcie, port, np);
666+
if (ret)
667+
return ret;
650668
}
651669

652670
if (pcie->hw->port_refclk)
@@ -680,6 +698,10 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
680698
ret = apple_pcie_port_register_irqs(port);
681699
WARN_ON(ret);
682700

701+
if (link_stat & PORT_LINKSTS_UP)
702+
return 0;
703+
704+
/* start link training */
683705
writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL);
684706

685707
if (!wait_for_completion_timeout(&pcie->event, HZ / 10))

0 commit comments

Comments
 (0)