|
33 | 33 |
|
34 | 34 | #include "pci-host-common.h" |
35 | 35 |
|
| 36 | +static int link_up_timeout = 500; |
| 37 | +module_param(link_up_timeout, int, 0644); |
| 38 | +MODULE_PARM_DESC(link_up_timeout, "PCIe link training timeout in milliseconds"); |
| 39 | + |
36 | 40 | /* T8103 (original M1) and related SoCs */ |
37 | 41 | #define CORE_RC_PHYIF_CTL 0x00024 |
38 | 42 | #define CORE_RC_PHYIF_CTL_RUN BIT(0) |
@@ -554,22 +558,105 @@ static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port, |
554 | 558 | return readl_relaxed(port_rid2sid_addr(port, idx)); |
555 | 559 | } |
556 | 560 |
|
| 561 | +static int apple_pcie_setup_link(struct apple_pcie *pcie, |
| 562 | + struct apple_pcie_port *port, |
| 563 | + struct device_node *np) |
| 564 | +{ |
| 565 | +#define MAX_AUX_PERST 3 |
| 566 | + struct gpio_desc *aux_reset[MAX_AUX_PERST] = { NULL }; |
| 567 | + u32 num_aux_resets = 0; |
| 568 | + struct gpio_desc *reset, *pwren = NULL; |
| 569 | + u32 stat; |
| 570 | + int ret; |
| 571 | + |
| 572 | + /* |
| 573 | + * Assert PERST# and configure the pin as output. |
| 574 | + * The Aquantia AQC113 10GB nic used desktop macs is sensitive to |
| 575 | + * deasserting it without prior clock setup. |
| 576 | + * Observed on M1 Max/Ultra Mac Studios under m1n1's hypervisor. |
| 577 | + */ |
| 578 | + reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset", |
| 579 | + GPIOD_OUT_HIGH, "PERST#"); |
| 580 | + if (IS_ERR(reset)) |
| 581 | + return PTR_ERR(reset); |
| 582 | + // HACK: use additional "reset-gpios" until pci-pwrctrl gains PERST# support. |
| 583 | + for (u32 idx = 0; idx < MAX_AUX_PERST; idx++) { |
| 584 | + aux_reset[idx] = devm_fwnode_gpiod_get_index(pcie->dev, |
| 585 | + of_fwnode_handle(np), |
| 586 | + "reset", idx + 1, |
| 587 | + GPIOD_OUT_HIGH, |
| 588 | + "PERST#"); |
| 589 | + if (IS_ERR(aux_reset[idx])) { |
| 590 | + if (PTR_ERR(aux_reset[idx]) == -ENOENT) |
| 591 | + break; |
| 592 | + else |
| 593 | + return PTR_ERR(aux_reset[idx]); |
| 594 | + } |
| 595 | + num_aux_resets++; |
| 596 | + } |
| 597 | + dev_info(pcie->dev, "Using %u auxiliary PERST#\n", num_aux_resets); |
| 598 | + |
| 599 | + pwren = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "pwren", |
| 600 | + GPIOD_ASIS, "PWREN"); |
| 601 | + if (IS_ERR(pwren)) { |
| 602 | + if (PTR_ERR(pwren) == -ENOENT) |
| 603 | + pwren = NULL; |
| 604 | + else |
| 605 | + return PTR_ERR(pwren); |
| 606 | + } |
| 607 | + |
| 608 | + rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK); |
| 609 | + |
| 610 | + /* Assert PERST# before setting up the clock */ |
| 611 | + gpiod_set_value_cansleep(reset, 1); |
| 612 | + for (u32 idx = 0; idx < num_aux_resets; idx++) |
| 613 | + gpiod_set_value_cansleep(aux_reset[idx], 1); |
| 614 | + |
| 615 | + /* Power on the device if required */ |
| 616 | + gpiod_set_value_cansleep(pwren, 1); |
| 617 | + |
| 618 | + ret = apple_pcie_setup_refclk(pcie, port); |
| 619 | + if (ret < 0) |
| 620 | + return ret; |
| 621 | + |
| 622 | + /* |
| 623 | + * The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) |
| 624 | + * If powering up, the minimal Tpvperl is 100ms |
| 625 | + */ |
| 626 | + if (pwren) |
| 627 | + msleep(100); |
| 628 | + else |
| 629 | + usleep_range(100, 200); |
| 630 | + |
| 631 | + /* Deassert PERST# */ |
| 632 | + rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst); |
| 633 | + gpiod_set_value_cansleep(reset, 0); |
| 634 | + for (u32 idx = 0; idx < num_aux_resets; idx++) |
| 635 | + gpiod_set_value_cansleep(aux_reset[idx], 0); |
| 636 | + |
| 637 | + /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ |
| 638 | + msleep(100); |
| 639 | + |
| 640 | + ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat, |
| 641 | + stat & PORT_STATUS_READY, 100, 250000); |
| 642 | + if (ret < 0) { |
| 643 | + dev_err(pcie->dev, "port %pOF ready wait timeout\n", np); |
| 644 | + return ret; |
| 645 | + } |
| 646 | + |
| 647 | + return 0; |
| 648 | +} |
| 649 | + |
557 | 650 | static int apple_pcie_setup_port(struct apple_pcie *pcie, |
558 | 651 | struct device_node *np) |
559 | 652 | { |
560 | 653 | struct platform_device *platform = to_platform_device(pcie->dev); |
561 | 654 | struct apple_pcie_port *port; |
562 | | - struct gpio_desc *reset; |
563 | 655 | struct resource *res; |
564 | 656 | char name[16]; |
565 | | - u32 stat, idx; |
| 657 | + u32 link_stat, idx; |
566 | 658 | int ret, i; |
567 | 659 |
|
568 | | - reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset", |
569 | | - GPIOD_OUT_LOW, "PERST#"); |
570 | | - if (IS_ERR(reset)) |
571 | | - return PTR_ERR(reset); |
572 | | - |
573 | 660 | port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL); |
574 | 661 | if (!port) |
575 | 662 | return -ENOMEM; |
@@ -605,30 +692,12 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, |
605 | 692 | else |
606 | 693 | port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx); |
607 | 694 |
|
608 | | - rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK); |
609 | | - |
610 | | - /* Assert PERST# before setting up the clock */ |
611 | | - gpiod_set_value_cansleep(reset, 1); |
612 | | - |
613 | | - ret = apple_pcie_setup_refclk(pcie, port); |
614 | | - if (ret < 0) |
615 | | - return ret; |
616 | | - |
617 | | - /* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */ |
618 | | - usleep_range(100, 200); |
619 | | - |
620 | | - /* Deassert PERST# */ |
621 | | - rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst); |
622 | | - gpiod_set_value_cansleep(reset, 0); |
623 | | - |
624 | | - /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ |
625 | | - msleep(100); |
626 | | - |
627 | | - ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat, |
628 | | - stat & PORT_STATUS_READY, 100, 250000); |
629 | | - if (ret < 0) { |
630 | | - dev_err(pcie->dev, "port %pOF ready wait timeout\n", np); |
631 | | - return ret; |
| 695 | + /* link might be already brought up by u-boot, skip setup then */ |
| 696 | + link_stat = readl_relaxed(port->base + PORT_LINKSTS); |
| 697 | + if (!(link_stat & PORT_LINKSTS_UP)) { |
| 698 | + ret = apple_pcie_setup_link(pcie, port, np); |
| 699 | + if (ret) |
| 700 | + return ret; |
632 | 701 | } |
633 | 702 |
|
634 | 703 | if (pcie->hw->port_refclk) |
@@ -662,10 +731,21 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, |
662 | 731 | ret = apple_pcie_port_register_irqs(port); |
663 | 732 | WARN_ON(ret); |
664 | 733 |
|
665 | | - writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL); |
| 734 | + link_stat = readl_relaxed(port->base + PORT_LINKSTS); |
| 735 | + if (!(link_stat & PORT_LINKSTS_UP)) { |
| 736 | + unsigned long timeout, left; |
| 737 | + /* start link training */ |
| 738 | + writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL); |
666 | 739 |
|
667 | | - if (!wait_for_completion_timeout(&pcie->event, HZ / 10)) |
668 | | - dev_warn(pcie->dev, "%pOF link didn't come up\n", np); |
| 740 | + timeout = link_up_timeout * HZ / 1000; |
| 741 | + left = wait_for_completion_timeout(&pcie->event, timeout); |
| 742 | + if (!left) |
| 743 | + dev_warn(pcie->dev, "%pOF link didn't come up\n", np); |
| 744 | + else |
| 745 | + dev_info(pcie->dev, "%pOF link up after %ldms\n", np, |
| 746 | + (timeout - left) * 1000 / HZ); |
| 747 | + |
| 748 | + } |
669 | 749 |
|
670 | 750 | return 0; |
671 | 751 | } |
@@ -872,12 +952,46 @@ static const struct pci_ecam_ops apple_pcie_cfg_ecam_ops = { |
872 | 952 | } |
873 | 953 | }; |
874 | 954 |
|
| 955 | +static int apple_pcie_probe_port(struct device_node *np) |
| 956 | +{ |
| 957 | + struct gpio_desc *gd; |
| 958 | + |
| 959 | + /* check whether the GPPIO pin exists but leave it as is */ |
| 960 | + gd = fwnode_gpiod_get_index(of_fwnode_handle(np), "reset", 0, |
| 961 | + GPIOD_ASIS, "PERST#"); |
| 962 | + if (IS_ERR(gd)) |
| 963 | + return PTR_ERR(gd); |
| 964 | + |
| 965 | + gpiod_put(gd); |
| 966 | + |
| 967 | + gd = fwnode_gpiod_get_index(of_fwnode_handle(np), "pwren", 0, |
| 968 | + GPIOD_ASIS, "PWREN"); |
| 969 | + if (IS_ERR(gd)) { |
| 970 | + if (PTR_ERR(gd) != -ENOENT) |
| 971 | + return PTR_ERR(gd); |
| 972 | + } else { |
| 973 | + gpiod_put(gd); |
| 974 | + } |
| 975 | + |
| 976 | + return 0; |
| 977 | +} |
| 978 | + |
875 | 979 | static int apple_pcie_probe(struct platform_device *pdev) |
876 | 980 | { |
877 | 981 | struct device *dev = &pdev->dev; |
| 982 | + struct device_node *of_port; |
878 | 983 | struct apple_pcie *pcie; |
879 | 984 | int ret; |
880 | 985 |
|
| 986 | + /* Check for probe dependencies for all ports first */ |
| 987 | + for_each_available_child_of_node(dev->of_node, of_port) { |
| 988 | + ret = apple_pcie_probe_port(of_port); |
| 989 | + if (ret) { |
| 990 | + of_node_put(of_port); |
| 991 | + return dev_err_probe(dev, ret, "Port %pOF probe fail\n", of_port); |
| 992 | + } |
| 993 | + } |
| 994 | + |
881 | 995 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); |
882 | 996 | if (!pcie) |
883 | 997 | return -ENOMEM; |
|
0 commit comments