Skip to content

Commit c55705e

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/[email protected]/ Signed-off-by: Janne Grunau <[email protected]>
1 parent dde1efe commit c55705e

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
@@ -550,16 +550,13 @@ static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port,
550550
return readl_relaxed(port_rid2sid_addr(port, idx));
551551
}
552552

553-
static int apple_pcie_setup_port(struct apple_pcie *pcie,
553+
static int apple_pcie_setup_link(struct apple_pcie *pcie,
554+
struct apple_pcie_port *port,
554555
struct device_node *np)
555556
{
556-
struct platform_device *platform = to_platform_device(pcie->dev);
557-
struct apple_pcie_port *port;
558557
struct gpio_desc *reset, *pwren = NULL;
559-
struct resource *res;
560-
char name[16];
561-
u32 stat, idx;
562-
int ret, i;
558+
u32 stat;
559+
int ret;
563560

564561
reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset",
565562
GPIOD_OUT_LOW, "PERST#");
@@ -575,6 +572,54 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
575572
return PTR_ERR(pwren);
576573
}
577574

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

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

648666
if (pcie->hw->port_refclk)
@@ -676,6 +694,10 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
676694
ret = apple_pcie_port_register_irqs(port);
677695
WARN_ON(ret);
678696

697+
if (link_stat & PORT_LINKSTS_UP)
698+
return 0;
699+
700+
/* start link training */
679701
writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL);
680702

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

0 commit comments

Comments
 (0)