Difference between revisions of "Unit DWCOTG"
Line 784: | Line 784: | ||
---- | ---- | ||
− | ''To be documented'' | + | |
+ | '''DWC host channel''' | ||
+ | |||
+ | <div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial;"> | ||
+ | <code>PDWCHostChannel = ^TDWCHostChannel;</code> | ||
+ | |||
+ | <code>TDWCHostChannel = record</code> | ||
+ | <div class="mw-collapsible-content" style="text-align: left; padding-left: 5px;"> | ||
+ | {| class="wikitable" style="font-size: 14px; background: white;" | ||
+ | |- | ||
+ | |colspan="2"|Note: TDWCRegisters: 0x0500 : Array of host channels. Each host channel can be used to execute an independent USB transfer or transaction simultaneously. A USB transfer may consist of multiple transactions, or packets. To avoid having to re-program the channel, it may be useful to use one channel for all transactions of a transfer before allowing other transfers to be scheduled on it. | ||
+ | |- | ||
+ | | <code>Characteristics:LongWord;</code> | ||
+ | | (0x0000 : Channel Characteristics) Contains various fields that must be set to prepare this channel for a transfer to or from a particular endpoint on a particular USB device. This register only needs to be programmed one time when doing a transfer, regardless of how many packets it consists of, unless the channel is re-programmed for a different transfer or the transfer is moved to a different channel. | ||
+ | |- | ||
+ | | <code>SplitControl:LongWord;</code> | ||
+ | | (0x0004 : Channel Split Control) This register is used to set up Split Transactions for communicating with low or full-speed devices attached to a high-speed hub. When doing so, set split_enable to 1 and the other fields as documented. Otherwise, software must clear this register before starting the transfer. Like the Channel Characteristics register, this register only needs to be programmed one time if the channel is enabled multiple times to send all the packets of a single transfer. | ||
+ | |- | ||
+ | | <code>Interrupts:LongWord;</code> | ||
+ | | (0x0008 : Channel Interrupts) Bitmask of status conditions that have occurred on this channel. These bits can be used with or without "real" interrupts. To have the CPU get a real interrupt when one of these bits gets set, set the appropriate bit in the interrupt_mask, and also ensure that interrupts from the channel are enabled in the host_channels_interrupt_mask register, channel interrupts overall are enabled in the core_interrupt_mask register, and interrupts from the DWC hardware overall are enabled in the ahb_configuration register and by any system-specific interrupt controller. | ||
+ | |- | ||
+ | | <code>InterruptMask:LongWord;</code> | ||
+ | | (0x000c : Channel Interrupts Mask) This has the same format as the Channel Interrupts Register, but software uses this to enable (1) or disable (0) the corresponding interrupt. Defaults to all 0's after a reset. | ||
+ | |- | ||
+ | | <code>Transfer:LongWord;</code> | ||
+ | | (0x0010 : Channel Transfer) Used to store additional information about the transfer. This must be programmed before beginning the transfer. | ||
+ | |- | ||
+ | | <code>DMAAddress:LongWord;</code> | ||
+ | | (0x0014 : Channel DMA Address) Word-aligned address at which the hardware will read or write data using Direct Memory Access. This must be programmed before beginning the transfer, unless the size of the data to send or receive is 0. The hardware will increment this address by the number of bytes successfully received or sent, which will correspond to the size decrease in transfer.size. Note: DMA must be enabled in the AHB Configuration Register before this register can be used. Otherwise, the hardware is considered to be in Slave mode and must be controlled a different way, which we do not use in our driver and do not attempt to document. BCM2835-specific note: Addresses written to this register must be bus addresses, not ARM physical addresses. | ||
+ | |- | ||
+ | | <code>Reserved0x0018:LongWord;</code> | ||
+ | | (0x0018 : Reserved) | ||
+ | |- | ||
+ | | <code>Reserved0x001C:LongWord;</code> | ||
+ | | (0x001C : Reserved) | ||
+ | |- | ||
+ | |} | ||
+ | </div></div> | ||
+ | |||
+ | '''DWC registers''' | ||
+ | |||
+ | <div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial;"> | ||
+ | <code>PDWCRegisters = ^TDWCRegisters;</code> | ||
+ | |||
+ | <code>TDWCRegisters = record</code> | ||
+ | <div class="mw-collapsible-content" style="text-align: left; padding-left: 5px;"> | ||
+ | {| class="wikitable" style="font-size: 14px; background: white;" | ||
+ | |- | ||
+ | |colspan="2"|Note: Layout of the registers of the DesignWare Hi-Speed USB 2.0 On-The-Go Controller. There is no official documentation for these, however, the register locations (and to some extent the meanings) can be found in other code, such as the Linux driver for this hardware that Synopsys contributed. | ||
+ | |||
+ | We do not explicitly define every bit in the registers because the majority are not used by our driver and would complicate this file. For example, we do not attempt to document any features that are specific to suspend, hibernation, the OTG protocol, or to the core acting in device mode rather than host mode. | ||
+ | |||
+ | The bits and fields we do use in our driver we have tried to completely document based on our understanding of what they do. We cannot guarantee that all the information is correct, as we do not have access to any official documentation. | ||
+ | |- | ||
+ | |colspan="2"|''Core registers'' | ||
+ | |- | ||
+ | | <code>OTGControl:LongWord;</code> | ||
+ | | (0x0000 : OTG Control and Status) | ||
+ | |- | ||
+ | | <code>OTGInterrupt:LongWord;</code> | ||
+ | | (0x0004 : OTG Interrupt) | ||
+ | |- | ||
+ | | <code>AHBConfiguration:LongWord;</code> | ||
+ | | (0x0008 : Core AHB Configuration) This register configures some of the interactions the DWC has with the rest of the system. | ||
+ | |- | ||
+ | | <code>CoreUSBConfiguration:LongWord;</code> | ||
+ | | (0x000c : Core USB Configuration) | ||
+ | |- | ||
+ | | <code>CoreReset:LongWord;</code> | ||
+ | | (0x0010 : Core Reset) Software can use this register to cause the DWC to reset itself. | ||
+ | |- | ||
+ | | <code>CoreInterrupts:LongWord;</code> | ||
+ | | (0x0014 : Core Interrupt) This register contains the state of pending top-level DWC interrupts. 1 means interrupt pending while 0 means no interrupt pending. Note that at least for port_intr and host_channel_intr, software must clear the interrupt somewhere else rather than by writing to this register. | ||
+ | |- | ||
+ | | <code>CoreInterruptMask:LongWord;</code> | ||
+ | | (0x0018 : Core Interrupt Mask) This register has the same format as the Core Interrupt Register and configures whether the corresponding interrupt is enabled (1) or disabled (0). Initial state after reset is all 0's. | ||
+ | |- | ||
+ | | <code>ReceiveStatus:LongWord;</code> | ||
+ | | (0x001c : Receive Status Queue Read (Read Only)) | ||
+ | |- | ||
+ | | <code>ReceiveStatusPop:LongWord;</code> | ||
+ | | (0x0020 : Receive Status Queue Read & POP (Read Only)) | ||
+ | |- | ||
+ | | <code>ReceiveFIFOSize:LongWord;</code> | ||
+ | | (0x0024 : Receive FIFO Size) This register contains the size of the Receive FIFO, in 4-byte words. This register must be set by software before using the controller (see the note in the documentation for the hwcfg3 register about configuring the dynamic FIFOs). | ||
+ | |- | ||
+ | | <code>NonPeriodicTransmitFIFOSize:LongWord;</code> | ||
+ | | (0x0028 : Non Periodic Transmit FIFO Size) The low 16 bits of this register contain the offset of the Nonperiodic Transmit FIFO, in 4-byte words, from the start of the memory reserved by the controller for dynamic FIFOs. The high 16 bits of this register contain its size, in 4-byte words. This register must be set by software before using the controller (see the note in the documentation for the hwcfg3 register about configuring the dynamic FIFOs). | ||
+ | |- | ||
+ | | <code>NonPeriodicTransmitFIFOStatus:LongWord;</code> | ||
+ | | (0x002c : Non Periodic Transmit FIFO/Queue Status (Read Only)) | ||
+ | |- | ||
+ | | <code>I2CControl:LongWord;</code> | ||
+ | | (0x0030 : I2C Access) | ||
+ | |- | ||
+ | | <code>PHYVendorControl:LongWord;</code> | ||
+ | | (0x0034 : PHY Vendor Control) | ||
+ | |- | ||
+ | | <code>GPIO:LongWord;</code> | ||
+ | | (0x0038 : General Purpose Input/Output) | ||
+ | |- | ||
+ | | <code>UserId:LongWord;</code> | ||
+ | | (0x003c : User ID) | ||
+ | |- | ||
+ | | <code>VendorId:LongWord;</code> | ||
+ | | (0x0040 : Vendor ID (Read Only)) | ||
+ | |- | ||
+ | | <code>HWCfg1:LongWord;</code> | ||
+ | | (0x0044 : User HW Config1 (Read Only)) | ||
+ | |- | ||
+ | | <code>HWCfg2:LongWord;</code> | ||
+ | | (0x0048 : User HW Config2 (Read Only)) | ||
+ | |- | ||
+ | | <code>HWCfg3:LongWord;</code> | ||
+ | | (0x004c : User HW Config3 (Read Only)) The high 16 bits of this read-only register contain the maximum total size, in words, of the dynamic FIFOs (Rx, Nonperiodic Tx, and Periodic Tx). Software must set up these three dynamic FIFOs in the rx_fifo_size, nonperiodic_tx_fifo_size, and host_periodic_tx_fifo_size registers such that their total size does not exceed this maximum total size and no FIFOs overlap. Note: Software must explicitly configure the dynamic FIFOs even if the controller is operating in DMA mode, since the default values for the FIFO sizes and offsets may be invalid. For example, in Broadcom's instantiation of this controller for the BCM2835, only 4080 words are available for dynamic FIFOs, but the dynamic FIFO sizes are set to 4096, 32, and 0, which are invalid as they add up to more than 4080. IF YOU DO NOT DO THIS YOU WILL GET SILENT MEMORY CORRUPTION. The low 16 bits of this register contain various flags that are not documented here as we don't use any in our driver. | ||
+ | |- | ||
+ | | <code>HWCfg4:LongWord;</code> | ||
+ | | (0x0050 : User HW Config4 (Read Only)) | ||
+ | |- | ||
+ | | <code>CoreLPMConfiguration:LongWord;</code> | ||
+ | | (0x0054 : Core LPM Configuration) | ||
+ | |- | ||
+ | | <code>GlobalPowerDown:LongWord;</code> | ||
+ | | (0x0058 : Global PowerDown) | ||
+ | |- | ||
+ | | <code>GlobalFIFOConfig:LongWord;</code> | ||
+ | | (0x005c : Global DFIFO SW Config) | ||
+ | |- | ||
+ | | <code>ADPControl:LongWord;</code> | ||
+ | | (0x0060 : ADP Control (Attach Detection Protocol)) | ||
+ | |- | ||
+ | | <code>Reserved0x0064:array[1..39] of LongWord;</code> | ||
+ | | (0x0064 : Reserved) | ||
+ | |- | ||
+ | | <code>HostPeriodicTransmitFIFOSize:LongWord;</code> | ||
+ | | (0x0100 : Host Periodic Transmit FIFO Size) The low 16 bits of this register configure the offset of the Periodic Transmit FIFO, in 4-byte words, from the start of the memory reserved by the controller for dynamic FIFOs. The high 16 bits of this register configure its size, in 4-byte words. This register should be set by software before using the controller (see the note in the documentation for the hwcfg3 register about configuring the dynamic FIFOs). | ||
+ | |- | ||
+ | | <code>Reserved0x0104:array[1..191] of LongWord;</code> | ||
+ | | (0x0104 : Device Periodic Transmit FIFO#n) If dedicated fifos are disabled, otherwise Device Transmit FIFO#n. | ||
+ | |- | ||
+ | |colspan="2"|''Host registers'' | ||
+ | |- | ||
+ | |colspan="2"|Note: The registers beginning at this point are considered to be the "Host" registers. These are used for the "Host" half of the OTG (On-The-Go) protocol, which allows this hardware to act as either a USB host or a USB device. This is the only half we are concerned with in this driver and we do not declare the corresponding Device registers. | ||
+ | |- | ||
+ | | <code>HostConfiguration:LongWord;</code> | ||
+ | | (0x0400 : Host Configuration) | ||
+ | |- | ||
+ | | <code>HostFrameInterval:LongWord;</code> | ||
+ | | (0x0404 : Host Frame Interval) | ||
+ | |- | ||
+ | | <code>HostFrameNumber:LongWord;</code> | ||
+ | | (0x0408 : Host Frame Number / Frame Remaining) | ||
+ | |- | ||
+ | | <code>Reserved0x040c:LongWord;</code> | ||
+ | | (0x040c : Reserved) | ||
+ | |- | ||
+ | | <code>HostFIFOStatus:LongWord;</code> | ||
+ | | (0x0410 : Host Periodic Transmit FIFO/ Queue Status) | ||
+ | |- | ||
+ | | <code>HostChannelsInterrupt:LongWord;</code> | ||
+ | | (0x0414 : Host All Channels Interrupt) This register contains a bit for each host channel that indicates whether an interrupt has occurred on that host channel. You cannot clear the interrupts by writing to this register, use the channel-specific interrupt registers instead. | ||
+ | |- | ||
+ | | <code>HostChannelsInterruptMask:LongWord;</code> | ||
+ | | (0x0418 : Host All Channels Interrupt Mask) Same format as the Host All Channels Interrupt Register, but a 1 in this register indicates that the corresponding host channel interrupt is enabled. Software can change this register. Defaults to all 0's after a reset. | ||
+ | |- | ||
+ | | <code>HostFrameList:LongWord;</code> | ||
+ | | (0x041c : Host Frame List Base Address Register) | ||
+ | |- | ||
+ | | <code>Reserved0x0420:array[1..8] of LongWord;</code> | ||
+ | | (0x0420) | ||
+ | |- | ||
+ | | <code>HostPortControlStatus:LongWord;</code> | ||
+ | | (0x0440 : Host Port Control and Status) This register provides the information needed to respond to status queries about the "host port", which is the port that is logically attached to the root hub. When changing this register, software must read its value, then clear the enabled, connected_changed, enabled_changed, and overcurrent_changed members to avoid changing them, as those particular bits are cleared by writing 1. | ||
+ | |- | ||
+ | | <code>Reserved0x0444:array[1..47] of LongWord;</code> | ||
+ | | (0x0444) | ||
+ | |- | ||
+ | |colspan="2"|''Host channel registers'' | ||
+ | |- | ||
+ | | <code>HostChannels:array[0..DWC_NUM_CHANNELS - 1] of TDWCHostChannel;</code> | ||
+ | | (0x0500 : Array of Host Channels) Each host channel can be used to execute an independent USB transfer or transaction simultaneously. A USB transfer may consist of multiple transactions, or packets. To avoid having to re-program the channel, it may be useful to use one channel for all transactions of a transfer before allowing other transfers to be scheduled on it. | ||
+ | |- | ||
+ | | <code>Reserved0x0600:array[1..((($800 - $500) - (DWC_NUM_CHANNELS * SizeOf(TDWCHostChannel))) div SizeOf(LongWord))] of LongWord;</code> | ||
+ | | (0x0600) | ||
+ | |- | ||
+ | |colspan="2"|''Device registers'' | ||
+ | |- | ||
+ | | <code>Reserved0x0800:array[1..(($E00 - $800) div SizeOf(LongWord))] of LongWord;</code> | ||
+ | | (0x0800) | ||
+ | |- | ||
+ | | <code>Power:LongWord;</code> | ||
+ | | (0x0e00 : Power and Clock Gating Control) | ||
+ | |- | ||
+ | |} | ||
+ | </div></div> | ||
+ | |||
+ | '''DWC root hub configuration''' | ||
+ | |||
+ | <div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial;"> | ||
+ | <code>PDWCRootHubConfiguration = ^TDWCRootHubConfiguration;</code> | ||
+ | |||
+ | <code>TDWCRootHubConfiguration = packed record</code> | ||
+ | <div class="mw-collapsible-content" style="text-align: left; padding-left: 5px;"> | ||
+ | {| class="wikitable" style="font-size: 14px; background: white;" | ||
+ | |- | ||
+ | | <code>ConfigurationDescriptor:TUSBConfigurationDescriptor;</code> | ||
+ | | style="width: 50%;"| | ||
+ | |- | ||
+ | | <code>InterfaceDescriptor:TUSBInterfaceDescriptor;</code> | ||
+ | | | ||
+ | |- | ||
+ | | <code>EndpointDescriptor:TUSBEndpointDescriptor;</code> | ||
+ | | | ||
+ | |- | ||
+ | |} | ||
+ | </div></div> | ||
+ | |||
+ | '''DWC USB host''' | ||
+ | |||
+ | <div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial;"> | ||
+ | <code>PDWCUSBHost = ^TDWCUSBHost;</code> | ||
+ | |||
+ | <code>TDWCUSBHost = record</code> | ||
+ | <div class="mw-collapsible-content" style="text-align: left; padding-left: 5px;"> | ||
+ | {| class="wikitable" style="font-size: 14px; background: white;" | ||
+ | |- | ||
+ | |colspan="2"|''USB Properties'' | ||
+ | |- | ||
+ | | <code>Host:TUSBHost;</code> | ||
+ | | | ||
+ | |- | ||
+ | |colspan="2"|''DWCOTG Properties'' | ||
+ | |- | ||
+ | | <code>Lock:TSpinHandle;</code> | ||
+ | | Host lock (Differs from lock in Host portion) (Spin lock due to use by interrupt handler) | ||
+ | |- | ||
+ | | <code>Registers:PDWCRegisters;</code> | ||
+ | | Memory mapped registers of the Synopsys DesignWare Hi-Speed USB 2.0 OTG Controller | ||
+ | |- | ||
+ | | <code>SchedulerThread:TThreadHandle;</code> | ||
+ | | Thread ID of USB request scheduler thread | ||
+ | |- | ||
+ | | <code>CompletionThread:TThreadHandle;</code> | ||
+ | | Thread ID of USB request completion thread | ||
+ | |- | ||
+ | | <code>SchedulerMailslot:TMailslotHandle;</code> | ||
+ | | USB requests that have been submitted to the Host but not yet started on a channel | ||
+ | |- | ||
+ | |colspan="2"|''Channel Properties'' | ||
+ | |- | ||
+ | | <code>DMABuffers:array[0..DWC_NUM_CHANNELS - 1] of Pointer;</code> | ||
+ | | DMA buffers allocated for each hardware channel (4 byte aligned / 1 per channel) | ||
+ | |- | ||
+ | | <code>ChannelRequests:array[0..DWC_NUM_CHANNELS - 1] of PUSBRequest;</code> | ||
+ | | Current USB request pending on each hardware channel (or nil of no request is pending) | ||
+ | |- | ||
+ | | <code>ChannelFreeMask:LongWord;</code> | ||
+ | | Bitmap of channel free (1) or used (0) status | ||
+ | |- | ||
+ | | <code>ChannelFreeLock:TMutexHandle;</code> | ||
+ | | Lock for access to ChannelFreeMask | ||
+ | |- | ||
+ | | <code>ChannelFreeWait:TSemaphoreHandle;</code> | ||
+ | | Number of free channels in ChannelFreeMask | ||
+ | |- | ||
+ | | <code>StartOfFrameMask:LongWord;</code> | ||
+ | | Bitmap of channels waiting for Start of Frame | ||
+ | |- | ||
+ | | <code>StartOfFrameLock:TSpinHandle;</code> | ||
+ | | Lock for access to StartOfFrameMask (Spin lock due to use by interrupt handler) | ||
+ | |- | ||
+ | |colspan="2"|''Root Hub Properties'' | ||
+ | |- | ||
+ | | <code>HubStatus:PUSBHubStatus;</code> | ||
+ | | Hub status for the root hub | ||
+ | |- | ||
+ | | <code>PortStatus:PUSBPortStatus;</code> | ||
+ | | Host port status for the root hub (Obtained from port interrupt due to status change) | ||
+ | |- | ||
+ | | <code>DeviceStatus:PUSBDeviceStatus;</code> | ||
+ | | Device status for the root hub | ||
+ | |- | ||
+ | | <code>HubDescriptor:PUSBHubDescriptor;</code> | ||
+ | | Hub descriptor for the root hub | ||
+ | |- | ||
+ | | <code>DeviceDescriptor:PUSBDeviceDescriptor;</code> | ||
+ | | Device descriptor for the root hub | ||
+ | |- | ||
+ | | <code>HubConfiguration:PDWCRootHubConfiguration;</code> | ||
+ | | Configuration, Interface and Endpoint descriptors for the root hub | ||
+ | |- | ||
+ | | <code>HubStringTable:array[0..2] of PUSBStringDescriptor;</code> | ||
+ | | String table for Language, Product and Manufacturer strings for the root hub | ||
+ | |- | ||
+ | | <code>HubProductString:PUSBStringDescriptor;</code> | ||
+ | | Product identifier string for the root hub | ||
+ | |- | ||
+ | | <code>HubLanguageString:PUSBStringDescriptor;</code> | ||
+ | | Language identifier string for the root hub | ||
+ | |- | ||
+ | | <code>HubManufacturerString:PUSBStringDescriptor;</code> | ||
+ | | Manufacturer identifier string for the root hub | ||
+ | |- | ||
+ | | <code>HubStatusChange:PUSBRequest;</code> | ||
+ | | Status change request to the root hub interrupt endpoint (nil if no request is pending) | ||
+ | |- | ||
+ | |colspan="2"|''Statistics Properties'' | ||
+ | |- | ||
+ | | <code>InterruptCount:LongWord;</code> | ||
+ | | Number of interrupt requests received by the host controller | ||
+ | |- | ||
+ | | <code>PortInterruptCount:LongWord;</code> | ||
+ | | Number of port interrupts received by the host controller | ||
+ | |- | ||
+ | | <code>ChannelInterruptCount:LongWord;</code> | ||
+ | | Number of channel interrupts received by the host controller | ||
+ | |- | ||
+ | | <code>StartOfFrameInterruptCount:LongWord;</code> | ||
+ | | Number of start of frame interrupts received by the host controller | ||
+ | |- | ||
+ | | <code>ResubmitCount:LongWord;</code> | ||
+ | | Number of requests resubmitted for later retry | ||
+ | |- | ||
+ | | <code>StartOfFrameCount:LongWord;</code> | ||
+ | | Number of requests resubmitted to wait for start of frame | ||
+ | |- | ||
+ | | <code>DMABufferReadCount:LongWord;</code> | ||
+ | | Number of IN requests that required a DMA buffer copy | ||
+ | |- | ||
+ | | <code>DMABufferWriteCount:LongWord;</code> | ||
+ | | Number of OUT requests that required a DMA buffer copy | ||
+ | |- | ||
+ | |colspan="2"| | ||
+ | |- | ||
+ | | <code>NAKReponseCount:LongWord;</code> | ||
+ | | Number of NAK responses received by the host controller | ||
+ | |- | ||
+ | | <code>NYETResponseCount:LongWord;</code> | ||
+ | | Number of NYET responses received by the host controller | ||
+ | |- | ||
+ | | <code>StallResponseCount:LongWord;</code> | ||
+ | | Number of Stall responses received by the host controller | ||
+ | |- | ||
+ | |colspan="2"| | ||
+ | |- | ||
+ | | <code>AHBErrorCount:LongWord;</code> | ||
+ | | Number of AHB errors received by the host controller | ||
+ | |- | ||
+ | | <code>TransactionErrorCount:LongWord;</code> | ||
+ | | Number of transaction errors received by the host controller | ||
+ | |- | ||
+ | | <code>BabbleErrorCount:LongWord;</code> | ||
+ | | Number of babble errors received by the host controller | ||
+ | |- | ||
+ | | <code>ExcessTransactionCount:LongWord;</code> | ||
+ | | Number of excess transaction errors received by the host controller | ||
+ | |- | ||
+ | | <code>FrameListRolloverCount:LongWord;</code> | ||
+ | | Number of frame list rollover errors received by the host controller | ||
+ | |- | ||
+ | | <code>DataToggleErrorCount:LongWord;</code> | ||
+ | | Number of data toggle errors received by the host controller | ||
+ | |- | ||
+ | | <code>FrameOverrunCount:LongWord;</code> | ||
+ | | Number of frame overrun errors received by the host controller | ||
+ | |- | ||
+ | |} | ||
+ | </div></div> | ||
+ | <br /> | ||
=== Public variables === | === Public variables === |
Revision as of 04:05, 18 January 2017
Return to Unit Reference
Contents
[hide]Description
USB Host Controller Driver for the Synopsys DesignWare Hi-Speed USB 2.0 On-The-Go Controller unit
This is a USB Host Controller Driver (HCD) that interfaces with the Synopsys DesignWare Hi-Speed USB 2.0 On-The-Go Controller, henceforth abbreviated as "DWC". This is the USB Host Controller used on the BCM2835 SoC used on the Raspberry Pi.
Please note that there is no publicly available official documentation for this particular piece of hardware, and it uses its own custom host controller interface rather than a standard one such as EHCI. Therefore, this driver was written on a best-effort basis using several sources to glean the necessary hardware details, including the extremely complicated and difficult to understand vendor provided Linux driver.
This file implements the Host Controller Driver Interface defined in TUSBHost. Most importantly, it implements a function to power on and start the host controller (HostStart) and a function to send and receive messages over the USB (HostSubmit).
The DWC is controlled by reading and writing to/from memory-mapped registers. The most important registers are the host channel registers. On this particular hardware, a "host channel", or simply "channel", is a set of registers to which software can read and write to cause transactions to take place on the USB. A fixed number of host channels exist, on the Raspberry Pi there are 8. From the software's perspective, transactions using different host channels can be executed at the same time.
Some of the host channel registers, as well as other registers, deal with interrupts. This driver makes heavy use of these and performs all USB transfers in an interrupt-driven manner. However, due to design flaws in this hardware and in USB 2.0 itself, "interrupt" and "isochronous" transfers still need to make use of software polling when checking for new data, even though each individual transfer is itself interrupt-driven. This means that, for example, if your USB mouse specifies a polling rate of 100 times per second, then it will, unfortunately, be polled 100 times per second in software. For more detail about how interrupts can be controlled on this particular hardware, see the comment above DWCSetupInterrupts. Another important concept is the idea of "packets", "transactions", and "transfers". A USB transfer, such as a single control message or bulk request, may need to be split into multiple packets if it exceeds the endpoint's maximum packet size. Unfortunately, this has to be dealt with explicitly in this code, as this hardware doesn't do it for us. But at least, from the viewpoint of this software, a "transaction" is essentially the same as a "packet".
The "On-The-Go" in the name of this hardware means that it supports the USB On-The-Go protocol, which allows it to act either as a host or a device. However, we only are concerned with it acting as a host, which simplifies our driver.
To simplify the USB core software, a useful design technique (as recommended by the USB 2.0 standard and used in other implementations such as Linux's) is to have the HCD present the root hub as a standard USB hub, even if the root hub is integrated with the host controller and does not appear as a standard hub at the hardware level. This is the case with the DWC, and we implement this design. Therefore, some code in this file deals with faking requests sent to the root hub.
Constants
DWC_*
DWC_USB_PID_*
DWC_RECEIVE_*
DWC_STATUS_*
DWC_COMPLETE_SPLIT_*
DWC_OTG_CTRL_*
DWC_AHB_*
DWC_USB_CFG_*
DWC_SOFT_RESET*
DWC_CORE_INTERRUPTS_*
DWC_VENDOR_ID_*
DWC_HWCFG2_*
DWC_HFIR_*
DWC_HOST_PORT_CTRLSTATUS_*
DWC_HOST_CHANNEL_CHARACTERISTICS_*
DWC_HOST_CHANNEL_SPLIT_CONTROL_*
DWC_HOST_CHANNEL_INTERRUPTS_*
DWC_HOST_CHANNEL_INTERRUPT_MASK_*
DWC_HOST_CHANNEL_TRANSFER_*
Type definitions
DWC host channel
DWC registers
DWC root hub configuration
PDWCRootHubConfiguration = ^TDWCRootHubConfiguration;
TDWCRootHubConfiguration = packed record
DWC USB host
Public variables
None defined
Function declarations
Initialization functions
DWCOTG functions
function DWCHostStart(Host:PUSBHost):LongWord;
function DWCHostStop(Host:PUSBHost):LongWord;
function DWCHostReset(Host:PUSBHost):LongWord;
function DWCHostResetEx(Host:PDWCUSBHost):LongWord;
function DWCHostSubmit(Host:PUSBHost; Request:PUSBRequest):LongWord;
function DWCHostCancel(Host:PUSBHost; Request:PUSBRequest):LongWord;
function DWCHostResubmit(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
function DWCHostPowerOn(Host:PDWCUSBHost):LongWord;
function DWCHostPowerOff(Host:PDWCUSBHost):LongWord;
function DWCHostCheck(Host:PDWCUSBHost):LongWord;
function DWCHostInit(Host:PDWCUSBHost):LongWord;
function DWCHostSetup(Host:PDWCUSBHost):LongWord;
function DWCHostSetupDMA(Host:PDWCUSBHost):LongWord;
function DWCHostSetupInterrupts(Host:PDWCUSBHost):LongWord;
function DWCHostStartFrameInterrupt(Host:PDWCUSBHost; Enable:Boolean):LongWord;
function DWCAllocateChannel(Host:PDWCUSBHost):LongWord;
function DWCReleaseChannel(Host:PDWCUSBHost; Channel:LongWord):LongWord;
function DWCChannelStartTransfer(Host:PDWCUSBHost; Channel:LongWord; Request:PUSBRequest):LongWord;
function DWCChannelStartTransaction(Host:PDWCUSBHost; Channel:LongWord; Request:PUSBRequest):LongWord;
function DWCHostPortReset(Host:PDWCUSBHost):LongWord;
function DWCHostPortPowerOn(Host:PDWCUSBHost):LongWord;
function DWCHostPortGetStatus(Host:PDWCUSBHost):LongWord;
function DWCHostPortSetFeature(Host:PDWCUSBHost; Feature:Word):LongWord;
function DWCHostPortClearFeature(Host:PDWCUSBHost; Feature:Word):LongWord;
procedure DWCHostPortStatusChanged(Host:PDWCUSBHost);
function DWCRootHubRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
function DWCRootHubControlRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
function DWCRootHubClassRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
function DWCRootHubStandardRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
function DWCSchedulerStart(Host:PDWCUSBHost):LongWord;
function DWCSchedulerExecute(Host:PDWCUSBHost):PtrInt;
function DWCCompletionExecute(Host:PDWCUSBHost):PtrInt;
function DWCResubmitExecute(Request:PUSBRequest):PtrInt;
procedure DWCInterruptHandler(Host:PDWCUSBHost);
function DWCChannelInterrupt(Host:PDWCUSBHost; Channel:LongWord):LongWord;
function DWCChannelCompleted(Host:PDWCUSBHost; Request:PUSBRequest; Channel,Interrupts:LongWord):LongWord;
DWCOTG helper functions
function DWCDivRoundUp(Number,Denominator:LongWord):LongWord;
function DWCCalculateFrameInterval(Host:PDWCUSBHost):LongWord;
Return to Unit Reference