diff --git a/kernel-src/include/kernel/pci.h b/kernel-src/include/kernel/pci.h index 0c9e9129..d110fcfe 100644 --- a/kernel-src/include/kernel/pci.h +++ b/kernel-src/include/kernel/pci.h @@ -22,6 +22,7 @@ #define PCI_CONFIG_REVISION 0x8 #define PCI_CONFIG_PROGIF 0x9 #define PCI_PROGIF_STORAGE_SATA_AHCI 0x1 + #define PCI_PROGIF_USB_EHCI 0x20 #define PCI_PROGIF_USB_XHCI 0x30 #define PCI_CONFIG_SUBCLASS 0xa #define PCI_SUBCLASS_STORAGE_NVM 0x8 diff --git a/kernel-src/include/kernel/xhci.h b/kernel-src/include/kernel/xhci.h index 45648a18..89b8906b 100644 --- a/kernel-src/include/kernel/xhci.h +++ b/kernel-src/include/kernel/xhci.h @@ -200,10 +200,16 @@ _Static_assert(sizeof(xhci_input_ctx_t) == XHCI_CONTEXT_SIZE, "xHCI input contro #define XHCI_PORTSC_PP (1 << 9) // port power #define XHCI_PORTSC_CSC (1 << 17) // connect status change #define XHCI_PORTSC_PEC (1 << 18) // port enabled change +#define XHCI_PORTSC_WRC (1 << 19) // warm reset change #define XHCI_PORTSC_OCC (1 << 20) // over current change #define XHCI_PORTSC_PRC (1 << 21) // port reset change +#define XHCI_PORTSC_PLC (1 << 22) // port link state change +#define XHCI_PORTSC_CEC (1 << 23) // config error change +#define XHCI_PORTSC_CAS (1 << 24) // cold attach status +#define XHCI_PORTSC_DR (1 << 30) // device removable +#define XHCI_PORTSC_WPR (1u << 31) // warm port reset -#define XHCI_PORTSC_CHANGE_BITS (XHCI_PORTSC_CSC | XHCI_PORTSC_PEC | XHCI_PORTSC_OCC | XHCI_PORTSC_PRC) +#define XHCI_PORTSC_CHANGE_BITS (XHCI_PORTSC_CSC | XHCI_PORTSC_PEC | XHCI_PORTSC_WRC | XHCI_PORTSC_OCC | XHCI_PORTSC_PRC | XHCI_PORTSC_PLC | XHCI_PORTSC_CEC) #define XHCI_PORTSC_PRESERVE_BITS XHCI_PORTSC_PP #define XHCI_TRB_DW2_TR_LEN(LEN) (uint32_t)((LEN) & 0x1ffff) diff --git a/kernel-src/io/usb/ctrl/xhci.c b/kernel-src/io/usb/ctrl/xhci.c index 18dd63da..abd545bc 100644 --- a/kernel-src/io/usb/ctrl/xhci.c +++ b/kernel-src/io/usb/ctrl/xhci.c @@ -398,7 +398,6 @@ static int xhci_run(xhci_ctrl_t *ctrl) { return 0; } - static volatile uint32_t *xhci_ext_caps(pcibar_t bar0) { volatile xhci_caps_t *caps = (xhci_caps_t *)bar0.address; uint32_t xecp = (caps->hccparams1 >> 16) & 0xffff; @@ -449,6 +448,39 @@ static int xhci_handoff(pcibar_t bar0) { return 0; } +#define XHCI_INTEL_VENDOR_ID 0x8086 +#define XHCI_INTEL_XUSB2PR 0xd0 +#define XHCI_INTEL_USB2PRM 0xd4 +#define XHCI_INTEL_USB3_PSSEN 0xd8 +#define XHCI_INTEL_USB3PRM 0xdc + +static bool xhci_intel_has_ehci_companion(void) { + return pci_getenum(PCI_CLASS_SERIAL_BUS, PCI_SUBCLASS_SERIAL_BUS_USB, PCI_PROGIF_USB_EHCI, XHCI_INTEL_VENDOR_ID, -1, -1, 0) != NULL; +} + +static void xhci_intel_route_ports_to_xhci(pcienum_t *e) { + if (e->vendor != XHCI_INTEL_VENDOR_ID) + return; + + if (!xhci_intel_has_ehci_companion()) + return; + + uint32_t usb2_mask = PCI_READ32(e, XHCI_INTEL_USB2PRM); + uint32_t usb3_mask = PCI_READ32(e, XHCI_INTEL_USB3PRM); + uint32_t usb2_before = PCI_READ32(e, XHCI_INTEL_XUSB2PR); + uint32_t usb3_before = PCI_READ32(e, XHCI_INTEL_USB3_PSSEN); + + if (usb3_mask != 0 && usb3_mask != UINT32_MAX) + PCI_WRITE32(e, XHCI_INTEL_USB3_PSSEN, usb3_mask); + if (usb2_mask != 0 && usb2_mask != UINT32_MAX) + PCI_WRITE32(e, XHCI_INTEL_XUSB2PR, usb2_mask); + + uint32_t usb2_after = PCI_READ32(e, XHCI_INTEL_XUSB2PR); + uint32_t usb3_after = PCI_READ32(e, XHCI_INTEL_USB3_PSSEN); + + printf("xhci: Intel routed ports to xHCI: usb2 %08x->%08x usb3 %08x->%08x\n", usb2_before, usb2_after, usb3_before, usb3_after); +} + static int xhci_ctrl_start(usb_ctrl_t *ctrl) { int ret = 0; @@ -689,6 +721,8 @@ static void init_ctrl(pcienum_t *e) { if (xhci_handoff(bar0) != 0) return; + xhci_intel_route_ports_to_xhci(e); + pci_setcommand(e, PCI_COMMAND_IO, 0); pci_setcommand(e, PCI_COMMAND_IRQDISABLE, 1); pci_setcommand(e, PCI_COMMAND_BUSMASTER, 1);