Unit DWCOTG
Return to Unit Reference
Description
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_NUM_CHANNELS = 8;
|
Number of DWC host channels |
DWC_SCHEDULER_THREAD_STACK_SIZE = SIZE_32K;
|
Stack size of USB request scheduler thread |
DWC_SCHEDULER_THREAD_PRIORITY = THREAD_PRIORITY_HIGHEST;
|
Priority of USB request scheduler thread (should be fairly high so that USB transfers can be started as soon as possible) |
DWC_SCHEDULER_THREAD_NAME = 'DWC Transfer Scheduler';
|
Name of USB request scheduler thread |
DWC_COMPLETION_THREAD_STACK_SIZE = SIZE_32K;
|
Stack size of USB request completion thread |
DWC_COMPLETION_THREAD_PRIORITY = THREAD_PRIORITY_HIGHEST;
|
Priority of USB request completion thread (should be fairly high so that USB transfers can be completed as soon as possible) |
DWC_COMPLETION_THREAD_NAME = 'DWC Transfer Completion';
|
Name of USB request completion thread |
DWC_RESUBMIT_THREAD_STACK_SIZE = SIZE_32K;
|
Stack size of USB request resubmit threads |
DWC_RESUBMIT_THREAD_PRIORITY = THREAD_PRIORITY_CRITICAL;
|
Priority of USB request resubmit threads (should be very high since these threads are used for the necessary software polling of interrupt endpoints, which are supposed to have guaranteed bandwidth). |
DWC_RESUBMIT_THREAD_NAME = 'DWC Transfer Resubmit';
|
Name of USB request resubmit threads |
DWC_START_SPLIT_INTR_TRANSFERS_ON_SOF = True;
|
Start Split Interrupt Transfers on Start of Frame (SOF) |
DWC_USB_PID_*
Recognized by the DWC hardware | |
DWC_USB_PID_DATA0 = 0;
|
|
DWC_USB_PID_DATA1 = 2;
|
|
DWC_USB_PID_DATA2 = 1;
|
|
DWC_USB_PID_SETUP = 3;
|
DWC_RECEIVE_*
DWC_RECEIVE_WORDS = 1024;
|
Size of Rx FIFO in 4-byte words |
DWC_TRANSMIT_WORDS = 1024;
|
Size of Non-periodic Tx FIFO in 4-byte words |
DWC_PERIODIC_TRANSMIT_WORDS = 1024;
|
Size of Periodic Tx FIFO in 4-byte words |
DWC_STATUS_*
DWC_STATUS_SUCCESS = 0;
|
|
DWC_STATUS_STALLED = 1;
|
|
DWC_STATUS_FAILED = 2;
|
|
DWC_STATUS_TRANSFER_RESUBMIT = 3;
|
|
DWC_STATUS_TRANSFER_RESTART = 4;
|
|
DWC_STATUS_TRANSACTION_RESTART = 5;
|
|
DWC_STATUS_HOST_PORT_CHANGE = 6;
|
|
DWC_STATUS_ROOT_HUB_REQUEST = 7;
|
|
DWC_STATUS_INVALID = 8;
|
|
DWC_STATUS_CANCELLED = 9;
|
DWC_COMPLETE_SPLIT_*
DWC_COMPLETE_SPLIT_RETRIES = 10;
|
DWC_OTG_CTRL_*
TDWCRegisters: 0x0000 : OTG Control Register | |
DWC_OTG_CTRL_HST_SET_HNP_EN = (1 shl 10);
|
DWC_AHB_*
TDWCRegisters: 0x0008 : AHB Configuration Register | |
DWC_AHB_INTERRUPT_ENABLE = (1 shl 0);
|
Enable interrupts from the USB controller. Disabled by default |
Bits [4:1] of the AHB Configuration register were redefined by Broadcom for the BCM2835 | |
BCM_DWC_AHB_AXI_BURST_MASK = (3 shl 1);
|
Max AXI burst length |
BCM_DWC_AHB_AXI_WAIT = (1 shl 4);
|
Wait for all outstanding AXI writes to complete before signalling (internally) that DMA is done |
DWC_AHB_DMA_ENABLE = (1 shl 5);
|
Writing 1 to this bit in the AHB Configuration Register allows the USB controller to perform DMA (Disabled by default) |
DWC_AHB_MASTER_IDLE = (1 shl 31);
|
Unknown |
DWC_USB_CFG_*
TDWCRegisters: 0x000c : Core USB Configuration Register | |
DWC_USB_CFG_TOUTCAL_NASK = (7 shl 0);
|
|
DWC_USB_CFG_PHYIF16 = (1 shl 3);
|
|
DWC_USB_CFG_ULPI_UTMI_SEL = (1 shl 4);
|
|
DWC_USB_CFG_FS_INTF = (1 shl 5);
|
|
DWC_USB_CFG_PHY_SEL = (1 shl 6);
|
|
DWC_USB_CFG_DDR_SEL = (1 shl 7);
|
|
DWC_USB_CFG_SRP_CAPABLE = (1 shl 8);
|
|
DWC_USB_CFG_HNP_CAPABLE = (1 shl 9);
|
|
DWC_USB_CFG_USB_TRDTIM_MASK = ($F shl 10);
|
|
DWC_USB_CFG_RESERVED14 = (1 shl 14);
|
|
DWC_USB_CFG_PHY_LOW_PWR_CLK_SEL = (1 shl 15);
|
|
DWC_USB_CFG_OTG_UTMI_FS_SEL = (1 shl 16);
|
|
DWC_USB_CFG_ULPI_FSLS = (1 shl 17);
|
|
DWC_USB_CFG_ULPI_AUTO_RES = (1 shl 18);
|
|
DWC_USB_CFG_ULPI_CLK_SUS_M = (1 shl 19);
|
|
DWC_USB_CFG_ULPI_EXT_VBUS_DRV = (1 shl 20);
|
|
DWC_USB_CFG_ULPI_INT_VBUS_INDICATOR = (1 shl 21);
|
|
DWC_USB_CFG_TERM_SEL_DL_PULSE = (1 shl 22);
|
|
DWC_USB_CFG_INDICATOR_COMPLEMENT = (1 shl 23);
|
|
DWC_USB_CFG_INDICATOR_PASS_THROUGH = (1 shl 24);
|
|
DWC_USB_CFG_ULPI_INT_PROT_DIS = (1 shl 25);
|
|
DWC_USB_CFG_IC_USB_CAP = (1 shl 26);
|
|
DWC_USB_CFG_IC_TRAFFIC_PULL_REMOVE = (1 shl 27);
|
|
DWC_USB_CFG_TX_END_DELAY = (1 shl 28);
|
|
DWC_USB_CFG_FORCE_HOST_MODE = (1 shl 29);
|
|
DWC_USB_CFG_FORCE_DEV_MODE = (1 shl 30);
|
|
DWC_USB_CFG_RESERVED31 = (1 shl 31);
|
DWC_SOFT_RESET*
TDWCRegisters: 0x0010 : Core Reset Register | |
DWC_SOFT_RESET = (1 shl 0);
|
Write 1 to this location in the Core Reset Register to start a soft reset. This bit will then be cleared by the hardware when the reset is complete. |
DWC_CORE_INTERRUPTS_*
TDWCRegisters: 0x0014 : Core Interrupt Register | |
DWC_CORE_INTERRUPTS_SOF_INTR = (1 shl 3);
|
Bit 3 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. |
DWC_CORE_INTERRUPTS_PORT_INTR = (1 shl 24);
|
Bit 24 Host port status changed. Software must examine the Host Port Control and Status Register to determine the current status of the host port and clear any flags in it that indicate a status change. |
DWC_CORE_INTERRUPTS_HOST_CHANNEL_INTR = (1 shl 25);
|
Bit 25 Channel interrupt occurred. Software must examine the Host All Channels Interrupt Register to determine which channel(s) have pending interrupts, then handle and clear the interrupts for these channels. |
DWC_VENDOR_ID_*
TDWCRegisters: 0x0040 : Vendor Id Register | |
DWC_VENDOR_ID_OTG2 = $4f542000;
|
|
DWC_VENDOR_ID_OTG3 = $4f543000;
|
|
DWC_VENDOR_ID_MASK = $fffff000;
|
DWC_HWCFG2_*
TDWCRegisters: 0x0048 : Hardware Configuration 2 | |
DWC_HWCFG2_OP_MODE_MASK = (7 shl 0);
|
|
DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG = (0 shl 0);
|
|
DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG = (1 shl 0);
|
|
DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG = (2 shl 0);
|
|
DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE = (3 shl 0);
|
|
DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE = (4 shl 0);
|
|
DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST = (5 shl 0);
|
|
DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST = (6 shl 0);
|
|
DWC_HWCFG2_ARCHITECTURE_MASK = (3 shl 3);
|
|
DWC_HWCFG2_ARCHITECTURE_SLAVE_ONLY = (0 shl 3);
|
|
DWC_HWCFG2_ARCHITECTURE_EXT_DMA = (1 shl 3);
|
|
DWC_HWCFG2_ARCHITECTURE_INT_DMA = (2 shl 3);
|
|
DWC_HWCFG2_POINT2POINT = (1 shl 5);
|
|
DWC_HWCFG2_HS_PHY_TYPE_MASK = (3 shl 6);
|
|
DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED = (0 shl 6);
|
|
DWC_HWCFG2_HS_PHY_TYPE_UTMI = (1 shl 6);
|
|
DWC_HWCFG2_HS_PHY_TYPE_ULPI = (2 shl 6);
|
|
DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI = (3 shl 6);
|
|
DWC_HWCFG2_FS_PHY_TYPE_MASK = (3 shl 8);
|
|
DWC_HWCFG2_FS_PHY_TYPE_NOT_SUPPORTED = (0 shl 8);
|
|
DWC_HWCFG2_FS_PHY_TYPE_DEDICATED = (1 shl 8);
|
|
DWC_HWCFG2_FS_PHY_TYPE_SHARED_UTMI = (2 shl 8);
|
|
DWC_HWCFG2_FS_PHY_TYPE_SHARED_ULPI = (3 shl 8);
|
|
DWC_HWCFG2_NUM_DEV_ENDPOINTS = ($F shl 10);
|
|
DWC_HWCFG2_NUM_HOST_CHANNELS = ($F shl 14);
|
|
DWC_HWCFG2_PERIODIC_ENDPOINT_SUPPORTED = (1 shl 18);
|
|
DWC_HWCFG2_DYNAMIC_FIFO = (1 shl 19);
|
|
DWC_HWCFG2_MULTI_PROC_INT = (1 shl 20);
|
|
DWC_HWCFG2_RESERVED21 = (1 shl 21);
|
|
DWC_HWCFG2_NON_PERIODIC_TX_QUEUE_DEPTH = (3 shl 22);
|
|
DWC_HWCFG2_HOST_PERIODIC_TX_QUEUE_DEPTH = (3 shl 24);
|
|
DWC_HWCFG2_DEV_TOKEN_QUEUE_DEPTH = ($1F shl 26);
|
|
DWC_HWCFG2_OTG_ENABLE_IC_USB = (1 shl 31);
|
DWC_HFIR_*
TDWCRegisters: 0x0404 : Host Frame Interval Register | |
DWC_HFIR_FRAME_INTERVAL_MASK = ($FFFF shl 0);
|
|
DWC_HFIR_FRAME_INT_RELOAD_CTL = (1 shl 16);
|
|
DWC_HFIR_RESERVED1 = ($FFFE shl 17);
|
DWC_HOST_PORT_CTRLSTATUS_*
TDWCRegisters: 0x0440 : Host Port Control and Status Register | |
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. | |
DWC_HOST_PORT_CTRLSTATUS_CONNECTED = (1 shl 0);
|
Bit 0 1: a device is connected to this port. 0: no device is connected to this port. Changed by hardware only. |
DWC_HOST_PORT_CTRLSTATUS_CONNECTED_CHANGED = (1 shl 1);
|
Bit 1 Set by hardware when connected bit changes. Software can write 1 to acknowledge and clear. The setting of this bit by hardware generates an interrupt that can be enabled by setting port_intr in the core_interrupt_mask register. |
DWC_HOST_PORT_CTRLSTATUS_ENABLED = (1 shl 2);
|
Bit 2 1: port is enabled. 0: port is disabled. Note: the host port is enabled by default after it is reset. Note: Writing 1 here appears to disable the port. |
DWC_HOST_PORT_CTRLSTATUS_ENABLED_CHANGED = (1 shl 3);
|
Bit 3 Set by hardware when enabled bit changes. Software can write 1 to acknowledge and clear. The setting of this bit by hardware generates an interrupt that can be enabled by setting port_intr in the core_interrupt_mask register. |
DWC_HOST_PORT_CTRLSTATUS_OVERCURRENT = (1 shl 4);
|
Bit 4 1: overcurrent condition active on this port 0: no overcurrent condition active on this port. Changed by hardware only. |
DWC_HOST_PORT_CTRLSTATUS_OVERCURRENT_CHANGED = (1 shl 5);
|
Bit 5 Set by hardware when the overcurrent bit changes. The software can write 1 to acknowledge and clear. The setting of this bit by hardware generates the interrupt that can be enabled by setting port_intr in the core_interrupt_mask register. |
DWC_HOST_PORT_CTRLSTATUS_RESUME = (1 shl 6);
|
Bit 6 Set by software to set resume signalling |
DWC_HOST_PORT_CTRLSTATUS_SUSPENDED = (1 shl 7);
|
Bit 7 Set by software to suspend the port |
DWC_HOST_PORT_CTRLSTATUS_RESET = (1 shl 8);
|
Bit 8 Software can set this to start a reset on this port. Software must clear this after waiting 60 milliseconds for the reset is complete. |
DWC_HOST_PORT_CTRLSTATUS_RESERVED = (1 shl 9);
|
Bit 9 |
DWC_HOST_PORT_CTRLSTATUS_LINE_STATUS = (3 shl 10);
|
Bits 10-11 Current logic of data lines (10: logic of D+; 11: logic of D-). Changed by hardware only. |
DWC_HOST_PORT_CTRLSTATUS_POWERED = (1 shl 12);
|
Bit 12 1: port is powered. 0: port is not powered. Software can change this bit to power on (1) or power off (0) the port. |
DWC_HOST_PORT_CTRLSTATUS_TEST_CONTROL = ($0F shl 13);
|
Bits 13-16 |
DWC_HOST_PORT_CTRLSTATUS_SPEED = (3 shl 17);
|
Bits 17-18 Speed of attached device (if any). This should only be considered meaningful if the connected bit is set. 00: high speed; 01: full speed; 10: low speed Changed by hardware only. |
DWC_HOST_PORT_CTRLSTATUS_RESERVED2 = ($1FFF shl 19);
|
Bits 19-32 |
DWC_HOST_CHANNEL_CHARACTERISTICS_*
TDWCHostChannel: 0x0000 : Channel Characteristics Register | |
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. | |
DWC_HOST_CHANNEL_CHARACTERISTICS_MAX_PACKET_SIZE = ($7FF shl 0);
|
Bits 0-10 Maximum packet size the endpoint is capable of sending or receiving. Must be programmed by software before starting the transfer. |
DWC_HOST_CHANNEL_CHARACTERISTICS_ENDPOINT_NUMBER = ($0F shl 11);
|
Bits 11-14 Endpoint number (low 4 bits of bEndpointAddress). Must be programmed by software before starting the transfer. |
DWC_HOST_CHANNEL_CHARACTERISTICS_ENDPOINT_DIRECTION = (1 shl 15);
|
Bit 15 Endpoint direction (high bit of bEndpointAddress). Must be programmed by software before starting the transfer. |
DWC_HOST_CHANNEL_CHARACTERISTICS_RESERVED = (1 shl 16);
|
Bit 16 |
DWC_HOST_CHANNEL_CHARACTERISTICS_LOWSPEED = (1 shl 17);
|
Bit 17 1 when the device being communicated with is attached at low speed; 0 otherwise. Must be programmed by software before starting the transfer. |
DWC_HOST_CHANNEL_CHARACTERISTICS_ENDPOINT_TYPE = (3 shl 18);
|
Bits 18-19 Endpoint type (low 2 bits of bmAttributes). Must be programmed by software before starting the transfer. |
DWC_HOST_CHANNEL_CHARACTERISTICS_PACKETS_PER_FRAME = (3 shl 20);
|
Bits 20-21 Maximum number of transactions that can be executed per microframe as part of this transfer. Normally 1, but should be set to 1 + (bits 11 and 12 of wMaxPacketSize) for high-speed interrupt and isochronous endpoints. Must be programmed by software before starting the transfer. |
DWC_HOST_CHANNEL_CHARACTERISTICS_DEVICE_ADDRESS = ($7F shl 22);
|
Bits 22-28 USB device address of the device on which the endpoint is located. Must be programmed by software before starting the transfer. |
DWC_HOST_CHANNEL_CHARACTERISTICS_ODD_FRAME = (1 shl 29);
|
Bit 29 Just before enabling the channel (for all transactions), software needs to set this to the opposite of the low bit of the host_frame_number register. Otherwise the hardware will issue frame overrun errors on some transactions. |
DWC_HOST_CHANNEL_CHARACTERISTICS_CHANNEL_DISABLE = (1 shl 30);
|
Bit 30 Software can set this to 1 to halt the channel. Not needed during normal operation as the channel halts automatically when a transaction completes or an error occurs. |
DWC_HOST_CHANNEL_CHARACTERISTICS_CHANNEL_ENABLE = (1 shl 31);
|
Bit 31 Software can set this to 1 to enable the channel, thereby actually starting the transaction on the USB. This must only be done after the characteristics, split_control, and transfer registers, and possibly other registers (depending on the transfer) have been programmed. |
DWC_HOST_CHANNEL_SPLIT_CONTROL_*
TDWCHostChannel: 0x0004 : Channel Split Control Register | |
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. | |
DWC_HOST_CHANNEL_SPLIT_CONTROL_PORT_ADDRESS = ($7F shl 0);
|
Bits 0-6 0-based index of the port on the high-speed hub on which the low or full-speed device is attached. |
DWC_HOST_CHANNEL_SPLIT_CONTROL_HUB_ADDRESS = ($7F shl 7);
|
Bits 7-13 USB device address of the high-speed hub that acts as the Transaction Translator for this low or full-speed device. This is not necessarily the hub the device is physically connected to, since that could be a full-speed or low-speed hub. Instead, software must walk up the USB device tree (towards the root hub) until a high-speed hub is found and use its device address here. |
DWC_HOST_CHANNEL_SPLIT_CONTROL_TRANSACTION_POSITION = (3 shl 14);
|
Bits 14-15 |
DWC_HOST_CHANNEL_SPLIT_CONTROL_COMPLETE_SPLIT = (1 shl 16);
|
Bit 16 0: Do a Start Split transaction 1: Do a Complete Split transaction. When split transactions are enabled, this must be programmed by software before enabling the channel. Note that you must begin with a Start Split transaction and alternate this bit for each transaction until the transfer is complete. |
DWC_HOST_CHANNEL_SPLIT_CONTROL_RESERVED = ($3FFF shl 17);
|
Bits 17-30 |
DWC_HOST_CHANNEL_SPLIT_CONTROL_SPLIT_ENABLE = (1 shl 31);
|
Bit 31 Set to 1 to enable Split Transactions |
DWC_HOST_CHANNEL_INTERRUPTS_*
TDWCHostChannel: 0x0008 : Channel Interrupts Register | |
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. | |
DWC_HOST_CHANNEL_INTERRUPTS_TRANSFER_COMPLETED = (1 shl 0);
|
Bit 0 The requested USB transfer has successfully completed
Exceptions and caveats: - When doing split transactions, this bit will be set after a Complete Split transaction has finished, even though the overall transfer may not actually be complete. - The transfer will only be complete up to the extent that data was programmed into the channel. For example, control transfers have 3 phases, each of which must be programmed into the channel separately. This flag will be set after each of these phases has successfully completed. - An OUT transfer is otherwise considered complete when exactly the requested number of bytes of data have been successfully transferred, while an IN transfer is otherwise considered complete when exactly the requested number of bytes of data have been successfully transferred or a shorter-than-expected packet was received} |
DWC_HOST_CHANNEL_INTERRUPTS_CHANNEL_HALTED = (1 shl 1);
|
Bit 1 The channel has halted. After this bit has been set, the channel sits idle and nothing else will happen until software takes action. Channels may halt for several reasons. From our experience these cover all possible situations in which software needs to take action, so this is the only channel interrupt that actually needs to be enabled. At least in DMA mode, the controller to some extent will act autonomously to complete transfers and only issue this interrupt when software needs to take action.
|
DWC_HOST_CHANNEL_INTERRUPTS_AHB_ERROR = (1 shl 2);
|
Bit 2 An error occurred on the ARM Advanced High-Performance Bus (AHB) |
DWC_HOST_CHANNEL_INTERRUPTS_STALL_RESPONSE_RECEIVED = (1 shl 3);
|
Bit 3 The device issued a STALL handshake packet (endpoint is halted or control pipe request is not supported). |
DWC_HOST_CHANNEL_INTERRUPTS_NAK_RESPONSE_RECEIVED = (1 shl 4);
|
Bit 4 The device issued a NAK handshake packet (receiving device cannot accept data or transmitting device cannot send data). The channel will halt with this bit set when performing an IN transfer from an interrupt endpoint that has no data to send. As this requires software intervention to restart the channel, this means that polling of interrupt endpoints (e.g. on hubs and HID devices) must be done in software, even if the actual transactions themselves are interrupt-driven. |
DWC_HOST_CHANNEL_INTERRUPTS_ACK_RESPONSE_RECEIVED = (1 shl 5);
|
Bit 5 The device issued an ACK handshake packet (receiving device acknowledged error-free packet). |
DWC_HOST_CHANNEL_INTERRUPTS_NYET_RESPONSE_RECEIVED = (1 shl 6);
|
Bit 6 The device issued a NYET handshake packet. |
DWC_HOST_CHANNEL_INTERRUPTS_TRANSACTION_ERROR = (1 shl 7);
|
Bit 7 From our experience this seems to usually indicate that software programmed the channel incorrectly. |
DWC_HOST_CHANNEL_INTERRUPTS_BABBLE_ERROR = (1 shl 8);
|
Bit 8 Unexpected bus activity occurred. |
DWC_HOST_CHANNEL_INTERRUPTS_FRAME_OVERRUN = (1 shl 9);
|
Bit 9 |
DWC_HOST_CHANNEL_INTERRUPTS_DATA_TOGGLE_ERROR = (1 shl 10);
|
Bit 10 When issuing a series of DATA transactions to an endpoint, the correct DATA0 or DATA1 packet ID was not specified in the packet_id member of the transfer register. |
DWC_HOST_CHANNEL_INTERRUPTS_BUFFER_NOT_AVAILABLE = (1 shl 11);
|
Bit 11 |
DWC_HOST_CHANNEL_INTERRUPTS_EXCESS_TRANSACTION_ERROR = (1 shl 12);
|
Bit 12 |
DWC_HOST_CHANNEL_INTERRUPTS_FRAME_LIST_ROLLOVER = (1 shl 13);
|
Bit 13 |
DWC_HOST_CHANNEL_INTERRUPTS_RESERVED = ($3FFFF shl 14);
|
Bits 14-31 |
DWC_HOST_CHANNEL_INTERRUPT_MASK_*
TDWCHostChannel: 0x000c : Channel Interrupts Mask Register | |
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. | |
DWC_HOST_CHANNEL_INTERRUPT_MASK_TRANSFER_COMPLETED = DWC_HOST_CHANNEL_INTERRUPTS_TRANSFER_COMPLETED;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_CHANNEL_HALTED = DWC_HOST_CHANNEL_INTERRUPTS_CHANNEL_HALTED;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_AHB_ERROR = DWC_HOST_CHANNEL_INTERRUPTS_AHB_ERROR;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_STALL_RESPONSE_RECEIVED = DWC_HOST_CHANNEL_INTERRUPTS_STALL_RESPONSE_RECEIVED;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_NAK_RESPONSE_RECEIVED = DWC_HOST_CHANNEL_INTERRUPTS_NAK_RESPONSE_RECEIVED;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_ACK_RESPONSE_RECEIVED = DWC_HOST_CHANNEL_INTERRUPTS_ACK_RESPONSE_RECEIVED;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_NYET_RESPONSE_RECEIVED = DWC_HOST_CHANNEL_INTERRUPTS_NYET_RESPONSE_RECEIVED;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_TRANSACTION_ERROR = DWC_HOST_CHANNEL_INTERRUPTS_TRANSACTION_ERROR;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_BABBLE_ERROR = DWC_HOST_CHANNEL_INTERRUPTS_BABBLE_ERROR;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_FRAME_OVERRUN = DWC_HOST_CHANNEL_INTERRUPTS_FRAME_OVERRUN;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_DATA_TOGGLE_ERROR = DWC_HOST_CHANNEL_INTERRUPTS_DATA_TOGGLE_ERROR;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_BUFFER_NOT_AVAILABLE = DWC_HOST_CHANNEL_INTERRUPTS_BUFFER_NOT_AVAILABLE;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_EXCESS_TRANSACTION_ERROR = DWC_HOST_CHANNEL_INTERRUPTS_EXCESS_TRANSACTION_ERROR;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_FRAME_LIST_ROLLOVER = DWC_HOST_CHANNEL_INTERRUPTS_FRAME_LIST_ROLLOVER;
|
|
DWC_HOST_CHANNEL_INTERRUPT_MASK_RESERVED = DWC_HOST_CHANNEL_INTERRUPTS_RESERVED;
|
DWC_HOST_CHANNEL_TRANSFER_*
TDWCHostChannel: 0x0010 : Channel Transfer Register | |
Used to store additional information about the transfer. This must be programmed before beginning the transfer. | |
DWC_HOST_CHANNEL_TRANSFER_SIZE = ($7FFFF shl 0);
|
Bits 0-18 Size of the data to send or receive, in bytes. Software must program this before beginning the transfer. This can be greater than the maximum packet length. For IN transfers, the hardware decrements this field for each packet received by the number of bytes received. For split transactions, the decrement happens after the Complete Split rather than the Start Split. Software can subtract this field from the original transfer size in order to determine the number of bytes received at any given point, including when the transfer has encountered an error or has completed with either the full size or a short size. For OUT transfers, the hardware does not update this field as expected. It will not be decremented when data is transmitted, at least not in every case; hence, software cannot rely on its value to indicate how many bytes of data have been transmitted so far. Instead, software must inspect the packet_count field and assume that all data was transmitted if packet_count is 0, or that the amount of data transmitted is equal to the endpoint's maximum packet size times (the original packet count minus packet_count) if packet_count is nonzero. |
DWC_HOST_CHANNEL_TRANSFER_PACKET_COUNT = ($3FF shl 19);
|
Bits 19-28 Number of packets left to transmit or maximum number of packets left to receive. Software must program this before beginning the transfer. The packet count is calculated as the size divided by the maximum packet size, rounded up to the nearest whole packet. As a special case, if the transfer size is 0 bytes, the packet count must be set to 1. The hardware will decrement this register when a packet is successfully sent or received. In the case of split transactions, this happens after the Complete Split rather than after the Start Split. If the final received packet of an IN transfer is short, it is still counted. |
DWC_HOST_CHANNEL_TRANSFER_PACKET_ID = ($03 shl 29);
|
Bits 29-30 High 2 bits of the Packet ID used in the USB protocol. When performing the SETUP phase of a control transfer, specify 0x3 here to generate the needed SETUP token. When performing the DATA phase of a control transfer, initially specify 0x2 here to begin the DATA packets with the needed DATA1 Packet ID. When performing the STATUS phase of a control transfer, specify 0x2 here to generate the neeed DATA1 Packet ID. When starting a bulk, isochronous, or interrupt transfer, specify 0x0 here to generate the needed DATA0 Packet ID. In the case of a transfer consisting of multiple DATA packets, the hardware will update this field with the Packet ID to use for the next packet. This field therefore only needs to be re-programmed if the transfer is moved to a different channel or the channel is re-used before the transfer is complete. When doing so, software must save this field so that it can be re-programmed correctly. |
DWC_HOST_CHANNEL_TRANSFER_DO_PING = (1 shl 31);
|
Bit 31 |
Type definitions
To be documented
Public variables
To be documented
Function declarations
Initialization functions
procedure DWCInit;
Note | None documented |
---|
DWCOTG functions
function DWCHostStart(Host:PUSBHost):LongWord;
Note | See usb.pas for the documentation of this interface of the Host Controller Driver |
---|
function DWCHostStop(Host:PUSBHost):LongWord;
Note | See usb.pas for the documentation of this interface of the Host Controller Driver |
---|
function DWCHostReset(Host:PUSBHost):LongWord;
Note | None documented |
---|
function DWCHostResetEx(Host:PDWCUSBHost):LongWord;
Note | Caller must hold the Host lock |
---|
function DWCHostSubmit(Host:PUSBHost; Request:PUSBRequest):LongWord;
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
---|---|
Note | See usb.pas for the documentation of this interface of the Host Controller Driver
This Host Controller Driver implements this interface asynchronously, as intended. Furthermore, it uses a simplistic scheduling algorithm where it places requests into a single queue and executes them in the order they were submitted. Transfers that need to be retried, including periodic transfers that receive a NAK reply and split transactions that receive a NYET reply when doing the Complete Split transaction, are scheduled to be retried at an appropriate time by separate code that shortcuts the main queue when the timer expires.
|
function DWCHostCancel(Host:PUSBHost; Request:PUSBRequest):LongWord;
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
---|---|
Note | See usb.pas for the documentation of thisinterface of the Host Controller Driver
Caller must hold the device lock |
function DWCHostResubmit(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Request | USB transfer to resubmit |
---|---|
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
Note | For periodic transfers (e.g. polling an interrupt endpoint), the exact time at which the transfer must be retried is specified by the bInterval member of the endpoint descriptor. For low and full-speed devices, bInterval specifies the number of millisconds to wait before the next poll, while for high-speed devices it specifies the exponent (plus one) of a power-of-two number of milliseconds to wait before the next poll.
To actually implement delaying a transfer, we associate each transfer with a thread created on-demand. Each such thread simply enters a loop where it calls sleep() for the appropriate number of milliseconds, then retries the transfer. A semaphore is needed to make the thread do nothing until the request has actually been resubmitted.
|
function DWCHostPowerOn(Host:PDWCUSBHost):LongWord;
Host | The DWCOTG host to power on |
---|---|
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
function DWCHostPowerOff(Host:PDWCUSBHost):LongWord;
Host | The DWCOTG host to power off |
---|---|
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
function DWCHostCheck(Host:PDWCUSBHost):LongWord;
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
---|
function DWCHostInit(Host:PDWCUSBHost):LongWord;
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
---|
function DWCHostSetup(Host:PDWCUSBHost):LongWord;
Note | None documented |
---|
function DWCHostSetupDMA(Host:PDWCUSBHost):LongWord;
Note | None documented |
---|
function DWCHostSetupInterrupts(Host:PDWCUSBHost):LongWord;
Note | The DWC contains several levels of interrupt registers, detailed in the following list. Note that for each level, each bit of the "interrupt" register contains the state of a pending interrupt (1 means interrupt pending; write 1 to clear), while the "interrupt mask" register has the same format but is used to turn the corresponding interrupt on or off (1 means on; write 1 to turn on; write 0 to turn off).
- The AHB configuration register contains a mask bit used to enable/disable all interrupts whatsoever from the DWC hardware.
|
---|
function DWCHostStartFrameInterrupt(Host:PDWCUSBHost; Enable:Boolean):LongWord;
Note | None documented |
---|
function DWCAllocateChannel(Host:PDWCUSBHost):LongWord;
Host | The DWC host to get available channel from |
---|---|
Return | Channel number of the next available channel |
function DWCReleaseChannel(Host:PDWCUSBHost; Channel:LongWord):LongWord;
Host | The DWC host to mark available channel on |
---|---|
Channel | The channel number to mark as available |
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
function DWCChannelStartTransfer(Host:PDWCUSBHost; Channel:LongWord; Request:PUSBRequest):LongWord;
Host | The DWC host to start the request on |
---|---|
Channel | The channel number to start the request on |
Request | USB request to start |
Note | Caller must hold the host lock
Can be called by the interrupt handler |
function DWCChannelStartTransaction(Host:PDWCUSBHost; Channel:LongWord; Request:PUSBRequest):LongWord;
Host | The DWC host to start the transaction on |
---|---|
Channel | The host channel number to start the transaction on |
Request | USB request set up for the next transaction |
Note | Caller must hold the host lock
Can be called by the interrupt handler |
function DWCHostPortReset(Host:PDWCUSBHost):LongWord;
Note | Caller must hold the Host lock |
---|
function DWCHostPortPowerOn(Host:PDWCUSBHost):LongWord;
Note | Caller must hold the Host lock |
---|
function DWCHostPortGetStatus(Host:PDWCUSBHost):LongWord;
Note | Caller must hold the Host lock |
---|
function DWCHostPortSetFeature(Host:PDWCUSBHost; Feature:Word):LongWord;
Note | Caller must hold the Host lock |
---|
function DWCHostPortClearFeature(Host:PDWCUSBHost; Feature:Word):LongWord;
Note | Caller must hold the Host lock |
---|
procedure DWCHostPortStatusChanged(Host:PDWCUSBHost);
Host | The DWCOTG host for the change request |
---|---|
Note | Caller must hold the Host lock
Can be called by the interrupt handler |
function DWCRootHubRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Host | The DWCOTG host for the request |
---|---|
Request | The USB request to perform |
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
Note | Caller must hold the Host lock |
function DWCRootHubControlRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Host | The DWCOTG host for the request |
---|---|
Request | The USB request to perform |
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
Note | Caller must hold the Host lock |
function DWCRootHubClassRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Host | The DWCOTG host for the request |
---|---|
Request | Hub specific request to the root hub |
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
Note | Caller must hold the Host lock |
function DWCRootHubStandardRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Host | The DWCOTG host for the request |
---|---|
Request | Standard request to the root hub |
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
Note | Caller must hold the Host lock |
function DWCSchedulerStart(Host:PDWCUSBHost):LongWord;
Note | None documented |
---|
function DWCSchedulerExecute(Host:PDWCUSBHost):PtrInt;
Host | USB host to service submitted requests for |
---|---|
Note | This thread receives requests that have been submitted and schedules them on the next available channel.
This is a very simplistic scheduler that does not take into account bandwidth requirements or which endpoint a transfer is for. |
function DWCCompletionExecute(Host:PDWCUSBHost):PtrInt;
Host | USB host to service completed requests for |
---|---|
Note | This thread receives completed requests which have either succeeded or failed and calls the completion handler which will call the registered callback for the request.
This thread also receives requests that need to be resubmitted and resubmits them for later processing by another thread.
|
function DWCResubmitExecute(Request:PUSBRequest):PtrInt;
Request | USB request to resubmit |
---|---|
Note | An instance of this thread is created for each request that needs to be resubmitted, this thread then either waits for a predetermined number of milliseconds before scheduling the request on the next available channel or waits for a signal from the interrupt handler to indicate a start of frame before scheduling the request on the allocated channel.
Once the request has been resubmitted the thread waits for the semaphore to be signaled again. If the request is a periodic polling of an endpoint then it will be resubmitted continuously at the predetermined interval, otherwise the semaphore will be destroyed by the completion handler and the thread will terminate. |
procedure DWCInterruptHandler(Host:PDWCUSBHost);
Host | The DWC host where the interrupt occurred |
---|
function DWCChannelInterrupt(Host:PDWCUSBHost; Channel:LongWord):LongWord;
Host | The DWC host where the interrupt occurred |
---|---|
Channel | DWC host channel where the channel interrupt occurred |
Return | USB_STATUS_SUCCESS if completed or another error code on failure |
Note | Only called by DWCInterruptHandler
Caller must hold the host lock |
function DWCChannelCompleted(Host:PDWCUSBHost; Request:PUSBRequest; Channel,Interrupts:LongWord):LongWord;
Request | The USB request currently scheduled on this channel |
---|---|
Host | The DWC host where the interrupt occurred |
Channel | DWC host channel where the channel interrupt occurred |
Interrupts | The currently pending interrupts on this channel |
Note | Only called by DWCChannelInterrupt
Caller must hold the host lock |
DWCOTG helper functions
function DWCDivRoundUp(Number,Denominator:LongWord):LongWord;
Note | None documented |
---|
function DWCCalculateFrameInterval(Host:PDWCUSBHost):LongWord;
Host | The DWCOTG host to calculate the interval for |
---|---|
Note | The host frame interval register can only be modified when the port enabled bit is set in the host port control and status register
Caller must hold the Host lock |
Return to Unit Reference