Difference between revisions of "Unit DWCOTG"

From Ultibo.org
Jump to: navigation, search
 
(2 intermediate revisions by the same user not shown)
Line 30: Line 30:
 
{| class="wikitable" style="font-size: 14px; background: white;"
 
{| class="wikitable" style="font-size: 14px; background: white;"
 
|-
 
|-
| <code>DWC_NUM_CHANNELS = 8;</code>
+
| <code>DWCOTG_USBHOST_DESCRIPTION = 'DWCOTG USB Host';</code>
| Number of DWC host channels
+
| Description of DWCOTG host
 +
|-
 +
|colspan="2"|&nbsp;
 +
|-
 +
| <code>DWC_MAX_CHANNELS = 16;</code>
 +
| Maximum number of DWC host channels
 +
|-
 +
|colspan="2"|&nbsp;
 +
|-
 +
| <code>DWC_SCHEDULER_MAILSLOT_SIZE = SIZE_1K;</code>
 +
| Mailslot size for USB request scheduler
 
|-
 
|-
 
|colspan="2"|&nbsp;  
 
|colspan="2"|&nbsp;  
Line 1,071: Line 1,081:
 
|colspan="2"|''Host channel registers''
 
|colspan="2"|''Host channel registers''
 
|-
 
|-
| <code>HostChannels:array[0..DWC_NUM_CHANNELS - 1] of TDWCHostChannel;</code>
+
| <code>HostChannels:array[0..DWC_MAX_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.
 
| (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>
+
| <code>Reserved0x0700:array[1..((($800 - $500) - (DWC_MAX_CHANNELS * SizeOf(TDWCHostChannel))) div SizeOf(LongWord))] of LongWord;</code>
| (0x0600)
+
| (0x0700)
 
|-
 
|-
 
|colspan="2"|''Device registers''
 
|colspan="2"|''Device registers''
Line 1,142: Line 1,152:
 
| <code>Lock:TSpinHandle;</code>
 
| <code>Lock:TSpinHandle;</code>
 
| Host lock (Differs from lock in Host portion) (Spin lock due to use by interrupt handler)
 
| Host lock (Differs from lock in Host portion) (Spin lock due to use by interrupt handler)
 +
|-
 +
| <code>IRQ:LongWord;</code>
 +
| The IRQ assigned to this host
 +
|-
 +
| <code>PowerID:LongWord;</code>
 +
| The Power ID required to power on this host
 
|-
 
|-
 
| <code>Registers:PDWCRegisters;</code>
 
| <code>Registers:PDWCRegisters;</code>
 
| Memory mapped registers of the Synopsys DesignWare Hi-Speed USB 2.0 OTG Controller
 
| Memory mapped registers of the Synopsys DesignWare Hi-Speed USB 2.0 OTG Controller
 +
|-
 +
| <code>ChannelCount:LongWord;</code>
 +
| The number of channels available on this host
 
|-
 
|-
 
| <code>SchedulerThread:TThreadHandle;</code>
 
| <code>SchedulerThread:TThreadHandle;</code>
Line 1,157: Line 1,176:
 
|colspan="2"|''Channel Properties''
 
|colspan="2"|''Channel Properties''
 
|-
 
|-
| <code>DMABuffers:array[0..DWC_NUM_CHANNELS - 1] of Pointer;</code>
+
| <code>DMABuffers:array[0..DWC_MAX_CHANNELS - 1] of Pointer;</code>
| DMA buffers allocated for each hardware channel (4 byte aligned/1 per channel)
+
| DMA buffers allocated for each hardware channel (4 byte aligned / 1 per channel)
 
|-
 
|-
| <code>ChannelRequests:array[0..DWC_NUM_CHANNELS - 1] of PUSBRequest;</code>
+
| <code>ChannelRequests:array[0..DWC_MAX_CHANNELS - 1] of PUSBRequest;</code>
 
| Current USB request pending on each hardware channel (or nil of no request is pending)
 
| Current USB request pending on each hardware channel (or nil of no request is pending)
 
|-
 
|-
Line 1,341: Line 1,360:
  
 
'''DWCOTG functions'''
 
'''DWCOTG functions'''
 +
 +
<div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial; padding-top: 0px; padding-bottom: 15px;">
 +
<pre style="border: 0; padding-bottom:0px;">function DWCHostCreate(Address:PtrUInt; IRQ,PowerID:LongWord):PUSBHost;</pre>
 +
<div style="font-size: 14px; padding-left: 12px;">'''Description:''' Create and register a new DWCOTG host which can be accessed using the USB API</div>
 +
<div class="mw-collapsible-content" style="text-align: left; padding-left: 5px;">
 +
{| class="wikitable" style="font-size: 14px; background: white;"
 +
|-
 +
! Address
 +
| The address of the DWCOTG registers
 +
|-
 +
! IRQ
 +
| The interrupt number for the DWCOTG host
 +
|-
 +
! PowerID
 +
| The power ID value to power on the host using PowerOn (or POWER_ID_UNKNOWN if not applicable)
 +
|-
 +
! Return
 +
| Pointer to the new USB host or nil if the USB host could not be created
 +
|-
 +
|}
 +
</div></div>
 +
<br />
 +
<div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial; padding-top: 0px; padding-bottom: 15px;">
 +
<pre style="border: 0; padding-bottom:0px;">function DWCHostDestroy(Host:PUSBHost):LongWord;</pre>
 +
<div style="font-size: 14px; padding-left: 12px;">'''Description:''' Stop, deregister and destroy a DWCOTG USB host created by this driver</div>
 +
<div class="mw-collapsible-content" style="text-align: left; padding-left: 5px;">
 +
{| class="wikitable" style="font-size: 14px; background: white;"
 +
|-
 +
! Host
 +
| The USB host to destroy
 +
|-
 +
! Return
 +
| ERROR_SUCCESS if completed or another error code on failure
 +
|-
 +
|}
 +
</div></div>
 +
<br />
 +
 +
'''DWCOTG USB functions'''
  
 
<div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial; padding-top: 0px; padding-bottom: 15px;">
 
<div class="toccolours mw-collapsible mw-collapsed" style="border: 1; font-family: arial; padding-top: 0px; padding-bottom: 15px;">
Line 1,438: Line 1,496:
 
| 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.
 
| 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.
 
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.
<br />This code gets used to scheduling polling of IN interrupt endpoints, including those on hubs and HID devices. Thus, polling of these devices for status changes (in the case of hubs) or new input (in the case of HID devices) is done in software. This wakes up the CPU a lot and wastes time and energy. But with USB 2.0, there is no way around this, other than by suspending the USB device which we don't support.
+
<br />This code gets used to schedule polling of IN interrupt endpoints, including those on hubs and HID devices. Thus, polling of these devices for status changes (in the case of hubs) or new input (in the case of HID devices) is done in software. This wakes up the CPU a lot and wastes time and energy. But with USB 2.0, there is no way around this, other than by suspending the USB device which we don't support.
 
|-
 
|-
 
|}
 
|}

Latest revision as of 04:10, 23 March 2023

Return to Unit Reference


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



[Expand]
DWCOTG specific constants DWC_*


[Expand]
DWC USB packet ID DWC_USB_PID_*


[Expand]
DWC FIFO value DWC_RECEIVE_*


[Expand]
DWC status code DWC_STATUS_*


[Expand]
DWC complete split DWC_COMPLETE_SPLIT_*


[Expand]
DWC register value DWC_OTG_CTRL_*


[Expand]
DWC AHB configuration DWC_AHB_*


[Expand]
DWC core USB configuration DWC_USB_CFG_*


[Expand]
DWC core reset DWC_SOFT_RESET*


[Expand]
DWC core interrupt DWC_CORE_INTERRUPTS_*


[Expand]
DWC vendor Id DWC_VENDOR_ID_*


[Expand]
DWC hardware configuration 2 DWC_HWCFG2_*


[Expand]
DWC host configuration DWC_HCFG_*


[Expand]
DWC host frame interval DWC_HFIR_*


[Expand]
DWC host frame register DWC_HFNUM_*


[Expand]
DWC host port control and status DWC_HOST_PORT_CTRLSTATUS_*


[Expand]
DWC channel characteristics DWC_HOST_CHANNEL_CHARACTERISTICS_*


[Expand]
DWC channel split control DWC_HOST_CHANNEL_SPLIT_CONTROL_*


[Expand]
DWC channel interrupt DWC_HOST_CHANNEL_INTERRUPTS_*


[Expand]
DWC channel interrupt mask DWC_HOST_CHANNEL_INTERRUPT_MASK_*


[Expand]
DWC channel transfer DWC_HOST_CHANNEL_TRANSFER_*


Type definitions



DWC host channel

[Expand]

PDWCHostChannel = ^TDWCHostChannel;

TDWCHostChannel = record

DWC registers

[Expand]

PDWCRegisters = ^TDWCRegisters;

TDWCRegisters = record

DWC root hub configuration

[Expand]

PDWCRootHubConfiguration = ^TDWCRootHubConfiguration;

TDWCRootHubConfiguration = packed record

DWC USB transfer

[Expand]

PDWCUSBTransfer = ^TDWCUSBTransfer;

TDWCUSBTransfer = record

DWC USB host

[Expand]

PDWCUSBHost = ^TDWCUSBHost;

TDWCUSBHost = record


Public variables


None defined

Function declarations



Initialization functions

[Expand]
procedure DWCInit;
Description: To be documented


DWCOTG functions

[Expand]
function DWCHostCreate(Address:PtrUInt; IRQ,PowerID:LongWord):PUSBHost;
Description: Create and register a new DWCOTG host which can be accessed using the USB API


[Expand]
function DWCHostDestroy(Host:PUSBHost):LongWord;
Description: Stop, deregister and destroy a DWCOTG USB host created by this driver


DWCOTG USB functions

[Expand]
function DWCHostStart(Host:PUSBHost):LongWord;
Description: Implementation of USBHostStart for the DesignWare Hi-Speed USB 2.0 On-The-Go Controller


[Expand]
function DWCHostStop(Host:PUSBHost):LongWord;
Description: Implementation of USBHostStop for the DesignWare Hi-Speed USB 2.0 On-The-Go Controller


[Expand]
function DWCHostReset(Host:PUSBHost):LongWord;
Description: Performs a software reset of the DWC OTG Controller


[Expand]
function DWCHostResetEx(Host:PDWCUSBHost):LongWord;
Description: Performs a software reset of the DWC OTG Controller


[Expand]
function DWCHostSubmit(Host:PUSBHost; Request:PUSBRequest):LongWord;
Description: Implementation of USBHostSubmit for the DesignWare Hi-Speed USB 2.0 On-The-Go Controller


[Expand]
function DWCHostCancel(Host:PUSBHost; Request:PUSBRequest):LongWord;
Description: Implementation of USBHostCancel for the DesignWare Hi-Speed USB 2.0 On-The-Go Controller


[Expand]
function DWCHostResubmit(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Description: Called when a USB transfer needs to be retried at a later time due to no data being available from the endpoint


[Expand]
function DWCHostPowerOn(Host:PDWCUSBHost):LongWord;
Description: Power on the DWCOTG Host controller


[Expand]
function DWCHostPowerOff(Host:PDWCUSBHost):LongWord;
Description: Powers off the DWCOTG Host controller


[Expand]
function DWCHostCheck(Host:PDWCUSBHost):LongWord;
Description: Check the DWC OTG USB Host Controller to confirm it is valid


[Expand]
function DWCHostInit(Host:PDWCUSBHost):LongWord;
Description: Initialize the DWC OTG USB Host Controller with core USB settings and perform a host reset


[Expand]
function DWCHostSetup(Host:PDWCUSBHost):LongWord;
Description: Configure the DWC OTG USB Host Controller with....


[Expand]
function DWCHostStartFrameInterrupt(Host:PDWCUSBHost; Enable:Boolean):LongWord;
Description: To be documented


[Expand]
function DWCAllocateChannel(Host:PDWCUSBHost):LongWord;
Description: Get the next available host channel on the supplied DWC host


[Expand]
function DWCReleaseChannel(Host:PDWCUSBHost; Channel:LongWord):LongWord;
Description: Mark the specified host channel on the supplied DWC host as available


[Expand]
function DWCChannelStartTransfer(Host:PDWCUSBHost; Channel:LongWord; Request:PUSBRequest):LongWord;
Description: Start or restart a USB request on a channel of the supplied DWC host


[Expand]
function DWCChannelStartTransaction(Host:PDWCUSBHost; Channel:LongWord; Request:PUSBRequest):LongWord;
Description: Start a USB transaction on a channel of the supplied DWC host


[Expand]
function DWCHostPortReset(Host:PDWCUSBHost):LongWord;
Description: Resets the DWC host port (The USB port that is attached to the root hub)


[Expand]
function DWCHostPortPowerOn(Host:PDWCUSBHost):LongWord;
Description: Powers on the DWC host port (The USB port that is attached to the root hub)


[Expand]
function DWCHostPortGetStatus(Host:PDWCUSBHost):LongWord;
Description: Read the Host Port Control and Status register with the intention of modifying it. Due to the inconsistent design of the bits in this register, this requires zeroing the write-clear bits so they aren't unintentionally cleared by writing back 1's to them.


[Expand]
function DWCHostPortSetFeature(Host:PDWCUSBHost; Feature:Word):LongWord;
Description: Handle a SetPortFeature request on the port attached to the root hub


[Expand]
function DWCHostPortClearFeature(Host:PDWCUSBHost; Feature:Word):LongWord;
Description: Handle a ClearPortFeature request on the port attached to the root hub


[Expand]
procedure DWCHostPortStatusChanged(Host:PDWCUSBHost);
Description: Complete any outstanding IN interrupt status change request


[Expand]
function DWCRootHubRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Description: Perform a request to the root hub


[Expand]
function DWCRootHubControlRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Description: Perform a control request to or from the root hub


[Expand]
function DWCRootHubClassRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Description: Perform a hub specific control request to the root hub


[Expand]
function DWCRootHubStandardRequest(Host:PDWCUSBHost; Request:PUSBRequest):LongWord;
Description: Perform a standard (non hub specific) control request to the root hub


[Expand]
function DWCSchedulerStart(Host:PDWCUSBHost):LongWord;
Description: Initialize a bitmask and semaphore that keep track of the Free/Used status of the host channels and a queue in which to place submitted USB transfer requests, then start the USB request scheduler thread


[Expand]
function DWCSchedulerExecute(Host:PDWCUSBHost):PtrInt;
Description: USB request scheduler thread


[Expand]
function DWCCompletionExecute(Host:PDWCUSBHost):PtrInt;
Description: USB request completion thread


[Expand]
function DWCResubmitExecute(Request:PUSBRequest):PtrInt;
Description: USB request resubmit thread


[Expand]
procedure DWCInterruptHandler(Host:PDWCUSBHost);
Description: Interrupt handler for the DWCOTG controller


[Expand]
function DWCChannelInterrupt(Host:PDWCUSBHost; Channel:LongWord):LongWord;
Description: Handle a channel interrupt on the specified channel


[Expand]
function DWCChannelCompleted(Host:PDWCUSBHost; Request:PUSBRequest; Channel,Interrupts:LongWord):LongWord;
Description: Handle a channel interrupt where no error occurred


DWCOTG helper functions

[Expand]
function DWCDivRoundUp(Number,Denominator:LongWord):LongWord;
Description: To be documented


[Expand]
function DWCCalculateFrameInterval(Host:PDWCUSBHost):LongWord;
Description: Calculate the frame interval register value based on USB configuration and port speed


Return to Unit Reference