Skip to content

Commit d2bb1d2

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 a4aac29 commit d2bb1d2

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
@@ -576,16 +576,13 @@ static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port,
576576
return readl_relaxed(port_rid2sid_addr(port, idx));
577577
}
578578

579-
static int apple_pcie_setup_port(struct apple_pcie *pcie,
579+
static int apple_pcie_setup_link(struct apple_pcie *pcie,
580+
struct apple_pcie_port *port,
580581
struct device_node *np)
581582
{
582-
struct platform_device *platform = to_platform_device(pcie->dev);
583-
struct apple_pcie_port *port;
584583
struct gpio_desc *reset, *pwren = NULL;
585-
struct resource *res;
586-
char name[16];
587-
u32 stat, idx;
588-
int ret, i;
584+
u32 stat;
585+
int ret;
589586

590587
reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset",
591588
GPIOD_OUT_LOW, "PERST#");
@@ -601,6 +598,54 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
601598
return PTR_ERR(pwren);
602599
}
603600

601+
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
602+
603+
/* Assert PERST# before setting up the clock */
604+
gpiod_set_value_cansleep(reset, 1);
605+
606+
/* Power on the device if required */
607+
gpiod_set_value_cansleep(pwren, 1);
608+
609+
ret = apple_pcie_setup_refclk(pcie, port);
610+
if (ret < 0)
611+
return ret;
612+
613+
/*
614+
* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2)
615+
* If powering up, the minimal Tpvperl is 100ms
616+
*/
617+
if (pwren)
618+
msleep(100);
619+
else
620+
usleep_range(100, 200);
621+
622+
/* Deassert PERST# */
623+
rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
624+
gpiod_set_value_cansleep(reset, 0);
625+
626+
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
627+
msleep(100);
628+
629+
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
630+
stat & PORT_STATUS_READY, 100, 250000);
631+
if (ret < 0) {
632+
dev_err(pcie->dev, "port %pOF ready wait timeout\n", np);
633+
return ret;
634+
}
635+
636+
return 0;
637+
}
638+
639+
static int apple_pcie_setup_port(struct apple_pcie *pcie,
640+
struct device_node *np)
641+
{
642+
struct platform_device *platform = to_platform_device(pcie->dev);
643+
struct apple_pcie_port *port;
644+
struct resource *res;
645+
char name[16];
646+
u32 link_stat, idx;
647+
int ret, i;
648+
604649
port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL);
605650
if (!port)
606651
return -ENOMEM;
@@ -636,39 +681,12 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
636681
else
637682
port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx);
638683

639-
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
640-
641-
/* Assert PERST# before setting up the clock */
642-
gpiod_set_value_cansleep(reset, 1);
643-
644-
/* Power on the device if required */
645-
gpiod_set_value_cansleep(pwren, 1);
646-
647-
ret = apple_pcie_setup_refclk(pcie, port);
648-
if (ret < 0)
649-
return ret;
650-
651-
/*
652-
* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2)
653-
* If powering up, the minimal Tpvperl is 100ms
654-
*/
655-
if (pwren)
656-
msleep(100);
657-
else
658-
usleep_range(100, 200);
659-
660-
/* Deassert PERST# */
661-
rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
662-
gpiod_set_value_cansleep(reset, 0);
663-
664-
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
665-
msleep(100);
666-
667-
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
668-
stat & PORT_STATUS_READY, 100, 250000);
669-
if (ret < 0) {
670-
dev_err(pcie->dev, "port %pOF ready wait timeout\n", np);
671-
return ret;
684+
/* link might be already brought up by u-boot, skip setup then */
685+
link_stat = readl_relaxed(port->base + PORT_LINKSTS);
686+
if (!(link_stat & PORT_LINKSTS_UP)) {
687+
ret = apple_pcie_setup_link(pcie, port, np);
688+
if (ret)
689+
return ret;
672690
}
673691

674692
if (pcie->hw->port_refclk)
@@ -702,6 +720,10 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
702720
ret = apple_pcie_port_register_irqs(port);
703721
WARN_ON(ret);
704722

723+
if (link_stat & PORT_LINKSTS_UP)
724+
return 0;
725+
726+
/* start link training */
705727
writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL);
706728

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

0 commit comments

Comments
 (0)