Skip to content

Commit 2fe6de6

Browse files
committed
Merge branch 'bits/140-pci' into asahi-wip
2 parents 9b9dd96 + 83fb58e commit 2fe6de6

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
@@ -85,6 +85,27 @@ properties:
8585
power-domains:
8686
maxItems: 1
8787

88+
patternProperties:
89+
"^pci@":
90+
$ref: /schemas/pci/pci-bus.yaml#
91+
type: object
92+
description: A single PCI root port
93+
94+
properties:
95+
reg:
96+
maxItems: 1
97+
98+
pwren-gpios:
99+
description: Optional GPIO to power on the device
100+
maxItems: 1
101+
102+
required:
103+
- reset-gpios
104+
- interrupt-controller
105+
- "#interrupt-cells"
106+
- interrupt-map-mask
107+
- interrupt-map
108+
88109
required:
89110
- compatible
90111
- reg
@@ -164,34 +185,58 @@ examples:
164185
pinctrl-0 = <&pcie_pins>;
165186
pinctrl-names = "default";
166187
167-
pci@0,0 {
188+
port00: pci@0,0 {
168189
device_type = "pci";
169190
reg = <0x0 0x0 0x0 0x0 0x0>;
170191
reset-gpios = <&pinctrl_ap 152 0>;
171192
172193
#address-cells = <3>;
173194
#size-cells = <2>;
174195
ranges;
196+
197+
interrupt-controller;
198+
#interrupt-cells = <1>;
199+
interrupt-map-mask = <0 0 0 7>;
200+
interrupt-map = <0 0 0 1 &port00 0 0 0 0>,
201+
<0 0 0 2 &port00 0 0 0 1>,
202+
<0 0 0 3 &port00 0 0 0 2>,
203+
<0 0 0 4 &port00 0 0 0 3>;
175204
};
176205
177-
pci@1,0 {
206+
port01: pci@1,0 {
178207
device_type = "pci";
179208
reg = <0x800 0x0 0x0 0x0 0x0>;
180209
reset-gpios = <&pinctrl_ap 153 0>;
181210
182211
#address-cells = <3>;
183212
#size-cells = <2>;
184213
ranges;
214+
215+
interrupt-controller;
216+
#interrupt-cells = <1>;
217+
interrupt-map-mask = <0 0 0 7>;
218+
interrupt-map = <0 0 0 1 &port01 0 0 0 0>,
219+
<0 0 0 2 &port01 0 0 0 1>,
220+
<0 0 0 3 &port01 0 0 0 2>,
221+
<0 0 0 4 &port01 0 0 0 3>;
185222
};
186223
187-
pci@2,0 {
224+
port02: pci@2,0 {
188225
device_type = "pci";
189226
reg = <0x1000 0x0 0x0 0x0 0x0>;
190227
reset-gpios = <&pinctrl_ap 33 0>;
191228
192229
#address-cells = <3>;
193230
#size-cells = <2>;
194231
ranges;
232+
233+
interrupt-controller;
234+
#interrupt-cells = <1>;
235+
interrupt-map-mask = <0 0 0 7>;
236+
interrupt-map = <0 0 0 1 &port02 0 0 0 0>,
237+
<0 0 0 2 &port02 0 0 0 1>,
238+
<0 0 0 3 &port02 0 0 0 2>,
239+
<0 0 0 4 &port02 0 0 0 3>;
195240
};
196241
};
197242
};

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)