From 01595708f3ff37e1c86f32548fc48a7a6a5d4be7 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 26 Aug 2006 15:48:41 +0000 Subject: [PATCH] * Changed EHCI register access from port to memory mapped io (which is required) * Added individual register operations for operational and capability registers * Added resetting the host controller which appearantly actually works Note that you shouldn't install the ehci module if you want uhci to work. It disables the companion host controller drivers (uhci and ohci) because it takes port ownership and does not yet give it back for low and fullspeed devices. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18648 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/busses/usb/ehci.cpp | 163 ++++++++++-------- src/add-ons/kernel/busses/usb/ehci.h | 21 +-- src/add-ons/kernel/busses/usb/ehci_hardware.h | 19 +- src/add-ons/kernel/busses/usb/uhci.cpp | 8 +- 4 files changed, 120 insertions(+), 91 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index e644afb5a0..f5d8ec3537 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -11,6 +11,7 @@ #include #include +#define TRACE_USB #include "ehci.h" pci_module_info *EHCI::sPCIModule = NULL; @@ -60,8 +61,6 @@ EHCI::EHCI(pci_info *info, Stack *stack) fStack(stack), fPeriodicFrameListArea(-1), fPeriodicFrameList(NULL), - fAsyncFrameListArea(-1), - fAsyncFrameList(NULL), fFirstTransfer(NULL), fLastTransfer(NULL), fFinishTransfers(false), @@ -70,7 +69,7 @@ EHCI::EHCI(pci_info *info, Stack *stack) fRootHub(NULL), fRootHubAddress(0) { - if (!fInitOK) { + if (BusManager::InitCheck() < B_OK) { TRACE_ERROR(("usb_ehci: bus manager failed to init\n")); return; } @@ -78,49 +77,49 @@ EHCI::EHCI(pci_info *info, Stack *stack) TRACE(("usb_ehci: constructing new EHCI Host Controller Driver\n")); fInitOK = false; - fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus, - fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4); - fRegisterBase &= PCI_address_io_mask; - TRACE(("usb_ehci: register base: 0x%08x\n", fRegisterBase)); - - // enable pci address access - uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory; - command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, - fPCIInfo->function, PCI_command, 2); - - sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, - fPCIInfo->function, PCI_command, 2, command); - // make sure we take the controller away from BIOS sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2, PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN); - // disable interrupts - WriteReg16(EHCI_USBINTR, 0); + // enable busmaster and memory mapped access + uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, + fPCIInfo->device, fPCIInfo->function, PCI_command, 2); + command &= ~PCI_command_io; + command |= PCI_command_master | PCI_command_memory; - // reset the host controller - // ToDo... + sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, + fPCIInfo->function, PCI_command, 2, command); - // allocate the periodic frame list - void *physicalAddress; - fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList, - &physicalAddress, B_PAGE_SIZE, "USB EHCI Periodic Framelist"); - if (fPeriodicFrameListArea < B_OK) { - TRACE_ERROR(("usb_ehci: unable to allocate periodic framelist\n")); + // map the registers + uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1); + addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset; + size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset + + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); + + TRACE(("usb_ehci: map physical memory 0x%08x (base: 0x%08x; offset: %x); size: %d -> %d\n", fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, fPCIInfo->u.h0.base_register_sizes[0], mapSize)); + fRegisterArea = map_physical_memory("EHCI memory mapped registers", + (void *)physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, + (void **)&fCapabilityRegisters); + if (fRegisterArea < B_OK) { + TRACE(("usb_ehci: failed to map register memory\n")); return; } - WriteReg32(EHCI_PERIODICLISTBASE, (uint32)physicalAddress); + fCapabilityRegisters += offset; + fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH); + TRACE(("usb_ehci: mapped capability registers: 0x%08x\n", fCapabilityRegisters)); + TRACE(("usb_ehci: mapped operational registers: 0x%08x\n", fOperationalRegisters)); - // allocate the async frame list - fAsyncFrameListArea = fStack->AllocateArea((void **)&fAsyncFrameList, - &physicalAddress, B_PAGE_SIZE, "USB EHCI Async Framelist"); - if (fAsyncFrameListArea < B_OK) { - TRACE_ERROR(("usb_ehci: unable to allocate async framelist\n")); + // disable interrupts + WriteOpReg(EHCI_USBINTR, 0); + + // reset the host controller + if (ControllerReset() < B_OK) { + TRACE_ERROR(("usb_ehci: host controller failed to reset\n")); + return; } - WriteReg32(EHCI_ASYNCLISTADDR, (uint32)physicalAddress); - // create finisher service thread fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread", B_NORMAL_PRIORITY, (void *)this); @@ -129,9 +128,26 @@ EHCI::EHCI(pci_info *info, Stack *stack) // install the interrupt handler and enable interrupts install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, InterruptHandler, (void *)this, 0); - WriteReg16(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR + WriteOpReg(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR | EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT); + // allocate the periodic frame list + fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList, + (void **)&physicalAddress, B_PAGE_SIZE, "USB EHCI Periodic Framelist"); + if (fPeriodicFrameListArea < B_OK) { + TRACE_ERROR(("usb_ehci: unable to allocate periodic framelist\n")); + return; + } + + // terminate all elements + for (int32 i = 0; i < 1024; i++) + fPeriodicFrameList[i] = EHCI_PFRAMELIST_TERM; + + WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress); + + // route all ports to us + WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG); + TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n")); fInitOK = true; } @@ -149,8 +165,7 @@ EHCI::~EHCI() delete fRootHub; delete_area(fPeriodicFrameListArea); - delete_area(fAsyncFrameListArea); - + delete_area(fRegisterArea); put_module(B_PCI_MODULE_NAME); } @@ -159,13 +174,13 @@ status_t EHCI::Start() { TRACE(("usb_ehci: starting EHCI Host Controller\n")); - TRACE(("usb_ehci: usbcmd: 0x%08x; usbsts: 0x%08x\n", ReadReg32(EHCI_USBCMD), ReadReg32(EHCI_USBSTS))); + TRACE(("usb_ehci: usbcmd: 0x%08x; usbsts: 0x%08x\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS))); - WriteReg32(EHCI_USBCMD, ReadReg32(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP); + WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP); bool running = false; for (int32 i = 0; i < 10; i++) { - uint32 status = ReadReg32(EHCI_USBSTS); + uint32 status = ReadOpReg(EHCI_USBSTS); TRACE(("usb_ehci: try %ld: status 0x%08x\n", i, status)); if (status & EHCI_USBSTS_HCHALTED) { @@ -295,7 +310,16 @@ EHCI::ResetPort(int32 index) status_t EHCI::ControllerReset() { - return B_ERROR; + WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET); + + int32 tries = 5; + while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) { + snooze(10000); + if (tries-- < 0) + return B_ERROR; + } + + return B_OK; } @@ -534,42 +558,35 @@ EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) inline void -EHCI::WriteReg8(uint32 reg, uint8 value) +EHCI::WriteOpReg(uint32 reg, uint32 value) { - sPCIModule->write_io_8(fRegisterBase + reg, value); -} - - -inline void -EHCI::WriteReg16(uint32 reg, uint16 value) -{ - sPCIModule->write_io_16(fRegisterBase + reg, value); -} - - -inline void -EHCI::WriteReg32(uint32 reg, uint32 value) -{ - sPCIModule->write_io_32(fRegisterBase + reg, value); -} - - -inline uint8 -EHCI::ReadReg8(uint32 reg) -{ - return sPCIModule->read_io_8(fRegisterBase + reg); -} - - -inline uint16 -EHCI::ReadReg16(uint32 reg) -{ - return sPCIModule->read_io_16(fRegisterBase + reg); + *(volatile uint32 *)(fOperationalRegisters + reg) = value; } inline uint32 -EHCI::ReadReg32(uint32 reg) +EHCI::ReadOpReg(uint32 reg) { - return sPCIModule->read_io_32(fRegisterBase + reg); + return *(volatile uint32 *)(fOperationalRegisters + reg); +} + + +inline uint8 +EHCI::ReadCapReg8(uint32 reg) +{ + return *(volatile uint8 *)(fCapabilityRegisters + reg); +} + + +inline uint16 +EHCI::ReadCapReg16(uint32 reg) +{ + return *(volatile uint16 *)(fCapabilityRegisters + reg); +} + + +inline uint32 +EHCI::ReadCapReg32(uint32 reg) +{ + return *(volatile uint32 *)(fCapabilityRegisters + reg); } diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index 41dcccbe1a..0ca47aa026 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -87,25 +87,26 @@ static int32 FinishThread(void *data); size_t ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle); - // Register functions -inline void WriteReg8(uint32 reg, uint8 value); -inline void WriteReg16(uint32 reg, uint16 value); -inline void WriteReg32(uint32 reg, uint32 value); -inline uint8 ReadReg8(uint32 reg); -inline uint16 ReadReg16(uint32 reg); -inline uint32 ReadReg32(uint32 reg); + // Operational register functions +inline void WriteOpReg(uint32 reg, uint32 value); +inline uint32 ReadOpReg(uint32 reg); + + // Capability register functions +inline uint8 ReadCapReg8(uint32 reg); +inline uint16 ReadCapReg16(uint32 reg); +inline uint32 ReadCapReg32(uint32 reg); static pci_module_info *sPCIModule; - uint32 fRegisterBase; + uint8 *fCapabilityRegisters; + uint8 *fOperationalRegisters; + area_id fRegisterArea; pci_info *fPCIInfo; Stack *fStack; // Framelist memory area_id fPeriodicFrameListArea; addr_t *fPeriodicFrameList; - area_id fAsyncFrameListArea; - addr_t *fAsyncFrameList; // Maintain a linked list of transfers transfer_data *fFirstTransfer; diff --git a/src/add-ons/kernel/busses/usb/ehci_hardware.h b/src/add-ons/kernel/busses/usb/ehci_hardware.h index 942152c82d..44c53456d9 100644 --- a/src/add-ons/kernel/busses/usb/ehci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ehci_hardware.h @@ -9,6 +9,14 @@ #ifndef EHCI_HARDWARE_H #define EHCI_HARDWARE_H +// Host Controller Capability Registers (EHCI Spec 2.2) +#define EHCI_CAPLENGTH 0x00 // Capability Register Length +#define EHCI_HCIVERSION 0x02 // Interface Version Number +#define EHCI_HCSPARAMS 0x04 // Structural Parameters +#define EHCI_HCCPARAMS 0x08 // Capability Parameters +#define EHCI_HCSP_PORTROUTE 0x0c // Companion Port Route Description + + // Host Controller Operational Registers (EHCI Spec 2.3) #define EHCI_USBCMD 0x00 // USB Command #define EHCI_USBSTS 0x04 // USB Status @@ -88,16 +96,17 @@ // PCI Registers #define PCI_LEGSUP 0xc0 // PCI Legacy Support -#define PCI_LEGSUP_USBPIRQDEN 0x2000 // USBP IRQ Deny +#define PCI_LEGSUP_USBPIRQDEN 0x2000 // USB PIRQ // Data Structures (EHCI Spec 3) // Periodic Frame List Element Flags (EHCI Spec 3.1) -#define EHCI_PFRAMELIST_ITD 0x00 // Isochronous Transfer Descriptor -#define EHCI_PFRAMELIST_QH 0x01 // Queue Head -#define EHCI_PFRAMELIST_SITD 0x10 // Split Transaction Isochronous TD -#define EHCI_PFRAMELIST_FSTN 0x11 // Frame Span Traversal Node +#define EHCI_PFRAMELIST_TERM (1 << 0) // Terminate +#define EHCI_PFRAMELIST_ITD (0 << 1) // Isochronous Transfer Descriptor +#define EHCI_PFRAMELIST_QH (1 << 1) // Queue Head +#define EHCI_PFRAMELIST_SITD (2 << 1) // Split Transaction Isochronous TD +#define EHCI_PFRAMELIST_FSTN (3 << 1) // Frame Span Traversal Node // ToDo: Isochronous (High-Speed) Transfer Descriptors (iTD, EHCI Spec 3.2) diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index f2801f0bc2..e17806ef43 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -339,10 +339,12 @@ UHCI::UHCI(pci_info *info, Stack *stack) fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4); fRegisterBase &= PCI_address_io_mask; - TRACE(("usb_uhci: iospace offset: 0x%08x\n", fRegisterBase)); + TRACE_ERROR(("usb_uhci: iospace offset: 0x%08x\n", fRegisterBase)); - //fRegisterBase = fPCIInfo->u.h0.base_registers[0]; - //TRACE(("usb_uhci: register base: 0x%08x\n", fRegisterBase)); + if (fRegisterBase == 0) { + fRegisterBase = fPCIInfo->u.h0.base_registers[0]; + TRACE_ERROR(("usb_uhci: register base: 0x%08x\n", fRegisterBase)); + } // enable pci address access uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;