summaryrefslogtreecommitdiff
path: root/sys/dev/fdt
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2020-05-22 20:14:05 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2020-05-22 20:14:05 +0000
commit396a70befc8163330ba08acb62ad0b763ba8f0ce (patch)
tree08580f5a09037e0c2617207bdd3ee4b360afd069 /sys/dev/fdt
parente331e0d8d3268c48234565c5776c7a9fd8530b0e (diff)
Improve resetting PCIe devices by making use of the reset-gpios property,
which is supposed to be PERST. Before issuing PERST, we must disable link training. This makes my PCIe device come up reliably after warm reboots. Promped by, with feedback from and ok kettenis@
Diffstat (limited to 'sys/dev/fdt')
-rw-r--r--sys/dev/fdt/mvkpcie.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/sys/dev/fdt/mvkpcie.c b/sys/dev/fdt/mvkpcie.c
index b2b5ddd8520..0944d6a1e7e 100644
--- a/sys/dev/fdt/mvkpcie.c
+++ b/sys/dev/fdt/mvkpcie.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mvkpcie.c,v 1.2 2020/05/22 18:48:42 kettenis Exp $ */
+/* $OpenBSD: mvkpcie.c,v 1.3 2020/05/22 20:14:04 patrick Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
* Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
@@ -262,6 +262,8 @@ mvkpcie_attach(struct device *parent, struct device *self, void *aux)
struct mvkpcie_softc *sc = (struct mvkpcie_softc *)self;
struct fdt_attach_args *faa = aux;
struct pcibus_attach_args pba;
+ uint32_t *reset_gpio;
+ ssize_t reset_gpiolen;
bus_addr_t iobase, iolimit;
bus_addr_t membase, memlimit;
uint32_t bus_range[2];
@@ -348,6 +350,24 @@ mvkpcie_attach(struct device *parent, struct device *self, void *aux)
clock_set_assigned(sc->sc_node);
clock_enable_all(sc->sc_node);
+ reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpios");
+ if (reset_gpiolen > 0) {
+ /* Link training needs to be disabled during PCIe reset. */
+ HCLR4(sc, PCIE_CORE_CTRL0, PCIE_CORE_CTRL0_LINK_TRAINING);
+
+ reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "reset-gpios", reset_gpio,
+ reset_gpiolen);
+
+ /* Issue PCIe reset. */
+ gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT);
+ gpio_controller_set_pin(reset_gpio, 1);
+ delay(10000);
+ gpio_controller_set_pin(reset_gpio, 0);
+
+ free(reset_gpio, M_TEMP, reset_gpiolen);
+ }
+
reg = HREAD4(sc, CTRL_CORE_CONFIG);
reg &= ~CTRL_CORE_CONFIG_MODE_MASK;
reg |= CTRL_CORE_CONFIG_MODE_DIRECT;