summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2022-02-13 12:02:22 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2022-02-13 12:02:22 +0000
commit9970946c1e740a8d235a8352319b4b93da019d4a (patch)
treeda3418d4708985d8bff6f862121df4e94e3e46b8 /sys/arch
parent4a64d53e60458371ad054350e2664eca6f596585 (diff)
Some PCIe devices on the M1 and M1 Pro/Max need to be explicitly powered on
(most notably the WiFi chip). This is done through a GPIO controlled by the SMC. Add support for this and make sure we wait for the 100ms required by the PCIe standard when we use that GPIO to turn on power. This makes sure these devices are available even if U-Boot doesn't turn them on for us. ok patrick@
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/arm64/dev/aplpcie.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/sys/arch/arm64/dev/aplpcie.c b/sys/arch/arm64/dev/aplpcie.c
index 026fcce4f32..e64ba3ccb9a 100644
--- a/sys/arch/arm64/dev/aplpcie.c
+++ b/sys/arch/arm64/dev/aplpcie.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aplpcie.c,v 1.10 2022/01/07 19:03:57 kettenis Exp $ */
+/* $OpenBSD: aplpcie.c,v 1.11 2022/02/13 12:02:21 kettenis Exp $ */
/*
* Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
*
@@ -381,8 +381,9 @@ void
aplpcie_init_port(struct aplpcie_softc *sc, int node)
{
uint32_t reg[5];
+ uint32_t *pwren_gpio;
uint32_t *reset_gpio;
- int reset_gpiolen;
+ int pwren_gpiolen, reset_gpiolen;
uint32_t stat;
int port, timo;
@@ -393,6 +394,7 @@ aplpcie_init_port(struct aplpcie_softc *sc, int node)
if (port >= APLPCIE_MAX_PORTS || sc->sc_port_ios[port] == 0)
return;
+ pwren_gpiolen = OF_getproplen(node, "pwren-gpios");
reset_gpiolen = OF_getproplen(node, "reset-gpios");
if (reset_gpiolen <= 0)
return;
@@ -419,6 +421,16 @@ aplpcie_init_port(struct aplpcie_softc *sc, int node)
gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT);
gpio_controller_set_pin(reset_gpio, 1);
+ /* Power up the device if necessary. */
+ if (pwren_gpiolen > 0) {
+ pwren_gpio = malloc(pwren_gpiolen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "pwren-gpios",
+ pwren_gpio, pwren_gpiolen);
+ gpio_controller_config_pin(pwren_gpio, GPIO_CONFIG_OUTPUT);
+ gpio_controller_set_pin(pwren_gpio, 1);
+ free(pwren_gpio, M_TEMP, pwren_gpiolen);
+ }
+
/* Setup Refclk. */
RSET4(sc, PCIE_CORE_LANE_CTRL(port), PCIE_CORE_LANE_CTRL_CFGACC);
RSET4(sc, PCIE_CORE_LANE_CONF(port), PCIE_CORE_LANE_CONF_REFCLK0REQ);
@@ -442,9 +454,13 @@ aplpcie_init_port(struct aplpcie_softc *sc, int node)
/*
* PERST# must remain asserted for at least 100us after the
- * reference clock becomes stable.
+ * reference clock becomes stable. But also has to remain
+ * active at least 100ms after power up.
*/
- delay(100);
+ if (pwren_gpiolen > 0)
+ delay(100000);
+ else
+ delay(100);
/* Deassert PERST#. */
PSET4(sc, port, PCIE_PORT_PERST, PCIE_PORT_PERST_DIS);