Skip to content

Commit 06b791a

Browse files
committed
Merge branch 'bits/140-pci' into asahi-wip
2 parents da06105 + 83fb58e commit 06b791a

3 files changed

Lines changed: 197 additions & 37 deletions

File tree

Documentation/devicetree/bindings/pci/apple,pcie.yaml

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ properties:
8282
power-domains:
8383
maxItems: 1
8484

85+
patternProperties:
86+
"^pci@":
87+
$ref: /schemas/pci/pci-bus.yaml#
88+
type: object
89+
description: A single PCI root port
90+
91+
properties:
92+
reg:
93+
maxItems: 1
94+
95+
pwren-gpios:
96+
description: Optional GPIO to power on the device
97+
maxItems: 1
98+
99+
required:
100+
- reset-gpios
101+
- interrupt-controller
102+
- "#interrupt-cells"
103+
- interrupt-map-mask
104+
- interrupt-map
105+
85106
required:
86107
- compatible
87108
- reg
@@ -161,34 +182,58 @@ examples:
161182
pinctrl-0 = <&pcie_pins>;
162183
pinctrl-names = "default";
163184
164-
pci@0,0 {
185+
port00: pci@0,0 {
165186
device_type = "pci";
166187
reg = <0x0 0x0 0x0 0x0 0x0>;
167188
reset-gpios = <&pinctrl_ap 152 0>;
168189
169190
#address-cells = <3>;
170191
#size-cells = <2>;
171192
ranges;
193+
194+
interrupt-controller;
195+
#interrupt-cells = <1>;
196+
interrupt-map-mask = <0 0 0 7>;
197+
interrupt-map = <0 0 0 1 &port00 0 0 0 0>,
198+
<0 0 0 2 &port00 0 0 0 1>,
199+
<0 0 0 3 &port00 0 0 0 2>,
200+
<0 0 0 4 &port00 0 0 0 3>;
172201
};
173202
174-
pci@1,0 {
203+
port01: pci@1,0 {
175204
device_type = "pci";
176205
reg = <0x800 0x0 0x0 0x0 0x0>;
177206
reset-gpios = <&pinctrl_ap 153 0>;
178207
179208
#address-cells = <3>;
180209
#size-cells = <2>;
181210
ranges;
211+
212+
interrupt-controller;
213+
#interrupt-cells = <1>;
214+
interrupt-map-mask = <0 0 0 7>;
215+
interrupt-map = <0 0 0 1 &port01 0 0 0 0>,
216+
<0 0 0 2 &port01 0 0 0 1>,
217+
<0 0 0 3 &port01 0 0 0 2>,
218+
<0 0 0 4 &port01 0 0 0 3>;
182219
};
183220
184-
pci@2,0 {
221+
port02: pci@2,0 {
185222
device_type = "pci";
186223
reg = <0x1000 0x0 0x0 0x0 0x0>;
187224
reset-gpios = <&pinctrl_ap 33 0>;
188225
189226
#address-cells = <3>;
190227
#size-cells = <2>;
191228
ranges;
229+
230+
interrupt-controller;
231+
#interrupt-cells = <1>;
232+
interrupt-map-mask = <0 0 0 7>;
233+
interrupt-map = <0 0 0 1 &port02 0 0 0 0>,
234+
<0 0 0 2 &port02 0 0 0 1>,
235+
<0 0 0 3 &port02 0 0 0 2>,
236+
<0 0 0 4 &port02 0 0 0 3>;
192237
};
193238
};
194239
};

drivers/pci/controller/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ config PCIE_APPLE
4545
depends on ARCH_APPLE || COMPILE_TEST
4646
depends on OF
4747
depends on PCI_MSI
48+
depends on PAGE_SIZE_16KB || COMPILE_TEST
4849
select PCI_HOST_COMMON
4950
select IRQ_MSI_LIB
5051
help

drivers/pci/controller/pcie-apple.c

Lines changed: 148 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333

3434
#include "pci-host-common.h"
3535

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+
3640
/* T8103 (original M1) and related SoCs */
3741
#define CORE_RC_PHYIF_CTL 0x00024
3842
#define CORE_RC_PHYIF_CTL_RUN BIT(0)
@@ -550,22 +554,105 @@ static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port,
550554
return readl_relaxed(port_rid2sid_addr(port, idx));
551555
}
552556

557+
static int apple_pcie_setup_link(struct apple_pcie *pcie,
558+
struct apple_pcie_port *port,
559+
struct device_node *np)
560+
{
561+
#define MAX_AUX_PERST 3
562+
struct gpio_desc *aux_reset[MAX_AUX_PERST] = { NULL };
563+
u32 num_aux_resets = 0;
564+
struct gpio_desc *reset, *pwren = NULL;
565+
u32 stat;
566+
int ret;
567+
568+
/*
569+
* Assert PERST# and configure the pin as output.
570+
* The Aquantia AQC113 10GB nic used desktop macs is sensitive to
571+
* deasserting it without prior clock setup.
572+
* Observed on M1 Max/Ultra Mac Studios under m1n1's hypervisor.
573+
*/
574+
reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset",
575+
GPIOD_OUT_HIGH, "PERST#");
576+
if (IS_ERR(reset))
577+
return PTR_ERR(reset);
578+
// HACK: use additional "reset-gpios" until pci-pwrctrl gains PERST# support.
579+
for (u32 idx = 0; idx < MAX_AUX_PERST; idx++) {
580+
aux_reset[idx] = devm_fwnode_gpiod_get_index(pcie->dev,
581+
of_fwnode_handle(np),
582+
"reset", idx + 1,
583+
GPIOD_OUT_HIGH,
584+
"PERST#");
585+
if (IS_ERR(aux_reset[idx])) {
586+
if (PTR_ERR(aux_reset[idx]) == -ENOENT)
587+
break;
588+
else
589+
return PTR_ERR(aux_reset[idx]);
590+
}
591+
num_aux_resets++;
592+
}
593+
dev_info(pcie->dev, "Using %u auxiliary PERST#\n", num_aux_resets);
594+
595+
pwren = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "pwren",
596+
GPIOD_ASIS, "PWREN");
597+
if (IS_ERR(pwren)) {
598+
if (PTR_ERR(pwren) == -ENOENT)
599+
pwren = NULL;
600+
else
601+
return PTR_ERR(pwren);
602+
}
603+
604+
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
605+
606+
/* Assert PERST# before setting up the clock */
607+
gpiod_set_value_cansleep(reset, 1);
608+
for (u32 idx = 0; idx < num_aux_resets; idx++)
609+
gpiod_set_value_cansleep(aux_reset[idx], 1);
610+
611+
/* Power on the device if required */
612+
gpiod_set_value_cansleep(pwren, 1);
613+
614+
ret = apple_pcie_setup_refclk(pcie, port);
615+
if (ret < 0)
616+
return ret;
617+
618+
/*
619+
* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2)
620+
* If powering up, the minimal Tpvperl is 100ms
621+
*/
622+
if (pwren)
623+
msleep(100);
624+
else
625+
usleep_range(100, 200);
626+
627+
/* Deassert PERST# */
628+
rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
629+
gpiod_set_value_cansleep(reset, 0);
630+
for (u32 idx = 0; idx < num_aux_resets; idx++)
631+
gpiod_set_value_cansleep(aux_reset[idx], 0);
632+
633+
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
634+
msleep(100);
635+
636+
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
637+
stat & PORT_STATUS_READY, 100, 250000);
638+
if (ret < 0) {
639+
dev_err(pcie->dev, "port %pOF ready wait timeout\n", np);
640+
return ret;
641+
}
642+
643+
return 0;
644+
}
645+
553646
static int apple_pcie_setup_port(struct apple_pcie *pcie,
554647
struct device_node *np)
555648
{
556649
struct platform_device *platform = to_platform_device(pcie->dev);
557650
struct apple_pcie_port *port;
558-
struct gpio_desc *reset;
559651
struct resource *res;
560652
char name[16];
561-
u32 stat, idx;
653+
u32 link_stat, idx;
562654
int ret, i;
563655

564-
reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset",
565-
GPIOD_OUT_LOW, "PERST#");
566-
if (IS_ERR(reset))
567-
return PTR_ERR(reset);
568-
569656
port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL);
570657
if (!port)
571658
return -ENOMEM;
@@ -601,30 +688,12 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
601688
else
602689
port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx);
603690

604-
rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
605-
606-
/* Assert PERST# before setting up the clock */
607-
gpiod_set_value_cansleep(reset, 1);
608-
609-
ret = apple_pcie_setup_refclk(pcie, port);
610-
if (ret < 0)
611-
return ret;
612-
613-
/* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */
614-
usleep_range(100, 200);
615-
616-
/* Deassert PERST# */
617-
rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
618-
gpiod_set_value_cansleep(reset, 0);
619-
620-
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
621-
msleep(100);
622-
623-
ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
624-
stat & PORT_STATUS_READY, 100, 250000);
625-
if (ret < 0) {
626-
dev_err(pcie->dev, "port %pOF ready wait timeout\n", np);
627-
return ret;
691+
/* link might be already brought up by u-boot, skip setup then */
692+
link_stat = readl_relaxed(port->base + PORT_LINKSTS);
693+
if (!(link_stat & PORT_LINKSTS_UP)) {
694+
ret = apple_pcie_setup_link(pcie, port, np);
695+
if (ret)
696+
return ret;
628697
}
629698

630699
if (pcie->hw->port_refclk)
@@ -658,10 +727,21 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
658727
ret = apple_pcie_port_register_irqs(port);
659728
WARN_ON(ret);
660729

661-
writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL);
730+
link_stat = readl_relaxed(port->base + PORT_LINKSTS);
731+
if (!(link_stat & PORT_LINKSTS_UP)) {
732+
unsigned long timeout, left;
733+
/* start link training */
734+
writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL);
662735

663-
if (!wait_for_completion_timeout(&pcie->event, HZ / 10))
664-
dev_warn(pcie->dev, "%pOF link didn't come up\n", np);
736+
timeout = link_up_timeout * HZ / 1000;
737+
left = wait_for_completion_timeout(&pcie->event, timeout);
738+
if (!left)
739+
dev_warn(pcie->dev, "%pOF link didn't come up\n", np);
740+
else
741+
dev_info(pcie->dev, "%pOF link up after %ldms\n", np,
742+
(timeout - left) * 1000 / HZ);
743+
744+
}
665745

666746
return 0;
667747
}
@@ -845,13 +925,47 @@ static const struct pci_ecam_ops apple_pcie_cfg_ecam_ops = {
845925
}
846926
};
847927

928+
static int apple_pcie_probe_port(struct device_node *np)
929+
{
930+
struct gpio_desc *gd;
931+
932+
/* check whether the GPPIO pin exists but leave it as is */
933+
gd = fwnode_gpiod_get_index(of_fwnode_handle(np), "reset", 0,
934+
GPIOD_ASIS, "PERST#");
935+
if (IS_ERR(gd))
936+
return PTR_ERR(gd);
937+
938+
gpiod_put(gd);
939+
940+
gd = fwnode_gpiod_get_index(of_fwnode_handle(np), "pwren", 0,
941+
GPIOD_ASIS, "PWREN");
942+
if (IS_ERR(gd)) {
943+
if (PTR_ERR(gd) != -ENOENT)
944+
return PTR_ERR(gd);
945+
} else {
946+
gpiod_put(gd);
947+
}
948+
949+
return 0;
950+
}
951+
848952
static int apple_pcie_probe(struct platform_device *pdev)
849953
{
850954
struct device *dev = &pdev->dev;
851955
struct pci_host_bridge *bridge;
956+
struct device_node *of_port;
852957
struct apple_pcie *pcie;
853958
int ret;
854959

960+
/* Check for probe dependencies for all ports first */
961+
for_each_available_child_of_node(dev->of_node, of_port) {
962+
ret = apple_pcie_probe_port(of_port);
963+
if (ret) {
964+
of_node_put(of_port);
965+
return dev_err_probe(dev, ret, "Port %pOF probe fail\n", of_port);
966+
}
967+
}
968+
855969
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
856970
if (!bridge)
857971
return -ENOMEM;

0 commit comments

Comments
 (0)