diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2020-05-22 20:14:05 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2020-05-22 20:14:05 +0000 |
commit | 396a70befc8163330ba08acb62ad0b763ba8f0ce (patch) | |
tree | 08580f5a09037e0c2617207bdd3ee4b360afd069 /sys/dev/fdt | |
parent | e331e0d8d3268c48234565c5776c7a9fd8530b0e (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.c | 22 |
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; |