diff options
author | Ian Moffett <ian@osmora.org> | 2025-10-11 18:54:34 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-10-11 18:54:34 -0400 |
commit | f07c51164e75ffa25b570e2233713b5a2cfa275a (patch) | |
tree | ffab76799d7604783d176b20b1c6e33b93f33c68 /src/sys/io/usb/hcd/xhci.c | |
parent | 306ce899c22efccea03a2ea196f8fa550383b40f (diff) |
kern: xhci: Implement controller hard reset
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'src/sys/io/usb/hcd/xhci.c')
-rw-r--r-- | src/sys/io/usb/hcd/xhci.c | 99 |
1 files changed, 97 insertions, 2 deletions
diff --git a/src/sys/io/usb/hcd/xhci.c b/src/sys/io/usb/hcd/xhci.c index 4cfbdc5..8d3b0a0 100644 --- a/src/sys/io/usb/hcd/xhci.c +++ b/src/sys/io/usb/hcd/xhci.c @@ -32,6 +32,7 @@ #include <sys/errno.h> #include <os/bus.h> #include <os/mmio.h> +#include <os/clkdev.h> #include <io/usb/xhcivar.h> #include <io/usb/xhciregs.h> #include <io/pci/bar.h> @@ -48,12 +49,106 @@ static struct pci_adv adv; static struct pci_device dev; static struct xhci_hcd hcd; +static struct clkdev *clk; + +/* + * Poll a register until it is either set or unset + * + * @reg: Register pointer to poll + * @mask: Mask to poll + * @pollset: If true, poll until set + */ +static int +xhci_poll32(volatile uint32_t *reg, uint32_t mask, bool pollset) +{ + uint16_t msec = 0; + uint32_t v, tmp; + + if (reg == NULL) { + return -EINVAL; + } + + for (;;) { + if (msec >= XHCI_TIMEOUT_MSEC) { + break; + } + + v = mmio_read32(reg); + v &= mask; + + if (pollset && v == mask) + return 0; + if (!pollset && v == 0) + return 0; + + clk->msleep(1); + ++msec; + } + + return -ETIME; +} + +/* + * Perform a hard host controller reset + */ +static int +xhci_reset_hc(struct xhci_hcd *hcd) +{ + struct xhci_opregs *opregs; + uint32_t usbcmd; + int error; + + if (hcd == NULL) { + return -EINVAL; + } + + opregs = XHCI_OPBASE(hcd->capspace); + + /* Reset the controller */ + usbcmd = mmio_read32(&opregs->usbcmd); + usbcmd |= USBCMD_HCRST; + mmio_write32(&opregs->usbcmd, usbcmd); + + /* Wait for it to be done */ + error = xhci_poll32(&opregs->usbcmd, USBCMD_HCRST, false); + if (error < 0) { + pr_trace("failed to initialize controller\n"); + return error; + } + + return 0; +} + +/* + * Initialize the host controller + */ +static int +xhci_init_hc(struct xhci_hcd *hcd) +{ + struct xhci_opregs *opregs; + uint32_t usbcmd; + int error; + + if (hcd == NULL) { + return -EINVAL; + } + + if ((error = xhci_reset_hc(hcd)) < 0) { + return error; + } + return 0; +} static int xhci_init(struct module *modp) { int error; + error = clkdev_get(CLKDEV_MSLEEP | CLKDEV_GET_USEC, &clk); + if (error < 0) { + return error; + } + if ((error = pci_advoc(&adv)) < 0) { return error; } @@ -84,8 +179,8 @@ xhci_attach(struct pci_adv *ap) return error; } - hcd.io = bs.va_base; - return 0; + hcd.capspace = bs.va_base; + return xhci_init_hc(&hcd); } static struct pci_adv adv = { |