# DesignWare On-The-Go USB Host Controller notes

The datasheets for this controller, which is the USB controller on the Raspberry
Pi, aren't publicly available. To whoever is involved in this decision: fuck you
dearly, there's some people stuck with your crappy hardware out there.

There are some indirect information sources, however, under the form of drivers.
This document include notes from information garnered from these drivers:

* Linux kernel v6.4, under drivers/usb/dwc2 by Synopsys
* https://github.com/Chadderz121/csud by Alex Chadwick

The Linux kernel DWC driver has been written by Synopsys itself, so their naming
scheme is what is documented below. Alex's "csud" was used as a way to grok the
theory of operation better since it has simpler code.

## Indirect information

Out of desperation, I was studying QEMU's dwc2 code for clues and did a "git
blame" for fun. Bingo! Paul Zimmerman (big thanks Paul!), the author of the
DWC2 emulator, mentions his source information (huge thanks for mentioning this
Paul!) in his commit.

http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf page 370.

At the time of this writing, the direct link is broken, but you can get the PDF
from the Internet Archive. and... bingo! This is it! The specs for that damn
controller. Now *this* should facilitate things...

## Driver documentation

Here's some documentation about the driver implemented at [drv/rpi/dwc.fs].

### DWCChannel

The DWC does its transfers over what it calls "channels". You set it up with
a target endpoint, payload, type and all that stuff, then enable it, then wait
until its done. It doesn't operate at the transfer level, but rathe at the
transaction level. This means, for example, that for a SETUP transfer, you'll
have to fire your channel 3 times (one for each stage), and thus manage the
IN/OUT dance that it implies. The structure below tracks the status of a
particular channel. It's an in-memory struture, but it also has a set of
fields to access hardware registers associated with that channel.

## Glossary

When reading the Linux DWC driver (which is well commented BTW) and other
sources, I could infer the meaning for a few strings in the names below:

HST  USB Host
DEV  USB Device
OTG  On-The-Go (being able to be both a Host and a Device)
EP   Endpoint
AHB  Advanced High-performance Bus
     https://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture
PHY  Physical layer. For example, Linux has a "PHY mode" for
     Low/Full/High/Super speeds (LS/FS/HS/SS) both in Host and Device mode.
     Ethernet, SATA, LVDS are other PHY modes.
UTMI USB Transceiver Macrocell Interface
ULPI UTMI Low Pin Interface
CH   Channel
A/B  Reference to "A-Device" and "B-Device" in USB OTG specs
Q    A USB queue structure
P    Periodic
NP   Non-Periodic
I2C  The bus with the same name
ADP  Attach Detection Protocol
SRP  Session Request Protocol
HNP  Host Negociation Protocol
LPM  Link Power Management
LS   Low Speed
FS   Full Speed
HS   High Speed
SNS  ???
SES  ???


And for the generally obvious:

RX   Receive
TX   Transmit
STS  Status
INT  Interrupt
MSK  Mask
SEL  Select
CTL  Control
CFG  Configuration
RST  Reset
SIZ  Size
VND  Vendor
CLK  Clock
PKT  Packet
DMA  Direct Memory Access
CAP  Capabilities

## Registers

As the BCM2835 documentation says, registers for the DWC live at MMIO+$980000.
At this address are the "Core" registers. At core+$400, there's the "Host mode"
registers and at core+$800, the "Device mode" registers.

I list all registers and associated bit assignments, along with the "pretty
names" from csud, but in most cases, I have no idea what it does. When I do, I
write a note.

### Core

+000 GOTGCTL
  b31:28 ???
  b27    CHIRPEN
  b26:22 MULT
  b21    CURMODE_HOST
  b20    OTGVER
  b19    BSESVLD
  b18    ASESVLD
  b17    DBNC_SHORT
  b16    CONID_B
  b15    DBNCE_FLTR_BYPASS
  b14:12 ???
  b11    DEVHNPEN
  b10    HSTSETHNPEN
  b9     HNPREQ
  b8     HSTNEGSCS
  b7     BVALOVAL
  b6     BVALOEN
  b5     AVALOVAL
  b4     AVALOEN
  b3     VBVALOVAL
  b2     VBVALOEN
  b1     SESREQ
  b0     SESREQSCS
+004 GOTGINT
  b31:20 ???
  b19    DBNCE_DONE
  b18    A_DEV_TOUT_CHG
  b17    HST_NEG_DET
  b16:10 ???
  b9     HST_NEG_SUC_STS_CHNG
  b8     SES_REQ_SUC_STS_CHNG
  b7:3   ???
  b2     SES_END_DET
  b1:0   ???
+008 GAHBCFG
  b31:24 ???
  b23    AHB_SINGLE
  b22    NOTI_ALL_DMA_WRIT
  b21    REM_MEM_SUPP
  b20:9  ???
  b8     P_TXF_EMP_LVL
  b7     NP_TXF_EMP_LVL
  b6     ???
  b5     DMA_EN
  b4:1   HBSTLEN
  b0     GLBL_INTR_EN
+00c GUSBCFG
  b31    ???
  b30    FORCEDEVMODE
  b29    FORCEHOSTMODE
  b28    TXENDDELAY
  b27    ICTRAFFICPULLREMOVE
  b26    ICUSBCAP
  b25    ULPI_INT_PROT_DIS
  b24    INDICATORPASSTHROUGH
  b23    INDICATORCOMPLEMENT
  b22    TERMSELDLPULSE
  b21    ULPI_INT_VBUS_IND
  b20    ULPI_EXT_VBUS_DRV
  b19    ULPI_CLK_SUSP_M
  b18    ULPI_AUTO_RES
  b17    ULPI_FS_LS
  b16    OTG_UTMI_FS_SEL
  b15    PHY_LP_CLK_SEL
  b14:10 USBTRDTIM
  b9     HNPCAP
  b8     SRPCAP
  b7     DDRSEL
  b6     PHYSEL
  b5     FSINTF
  b4     ULPI_UTMI_SEL
  b3     PHYIF16/8
  b2:0   TOUTCAL
+010 GRSTCTL
  b31    AHBIDLE
  b30    DMAREQ
  b29    CSFTRST_DONE
  b28:12 ???
  b11:6  TXFNUM
  b5     TXFFLSH
  b4     RXFFLSH
  b3     IN_TKNQ_FLSH
  b2     FRMCNTRRST
  b1     HSFTRST
  b0     CSFTRST
+014 GINTSTS
  b31    WKUPINT
  b30    SESREQINT
  b29    DISCONNINT
  b28    CONIDSTSCHNG
  b27    LPMTRANRCVD
  b26    PTXFEMP
  b25    HCHINT
  b24    PRTINT
  b23    RESETDET
  b22    FET_SUSP
  b21    INCOMPL_IP
  b21    INCOMPL_SOOUT ??? yup, b21 too
  b20    INCOMPL_SOIN
  b19    OEPINT
  b18    IEPINT
  b17    EPMIS
  b16    RESTOREDONE
  b15    EOPF
  b14    ISOUTDROP
  b13    ENUMDONE
  b12    USBRST
  b11    USBSUSP
  b10    ERYLSUSP
  b9     I2CINT
  b8     ULPI_CK_INT
  b7     GOUTNAKEFF
  b6     GINNAKEFF
  b5     NPTXFEMP
  b4     RXFLVL
  b3     SOF
  b2     OTGINT
  b1     MODEMIS
  b0     CURMODE_HOST
+018 GINTMSK
  (same as GINTSTS)
+01c GRXSTSR  R=Read
  b31:25 FN
  b24:21 ???
  b20:17 PKTSTS
    1=GLOBALOUTNAK
    2=OUTRX/HCHIN
    3=OUTDONE/HCHIN_XFER_COMP
    4=SETUPDONE
    5=DATATOGGLEERR
    6=SETUPRX
    7=HCHHALTED
  b16:15 DPID
  b14:4  BYTECNT
  b3:0   EPNUM         Channel Number
+020 GRXSTSP    P=Pop
  (same as GRXSTSR)
+024 GRXFSIZ    F=FIFO
+028 GNPTXFSIZ
  b31:16 Depth
  b15:0  Start Address
+02c GNPTXSTS
  b31    ??? (csud says "Odd")
  b30:24 NP_TXQ_TOP
  b23:16 NP_TXQ_SPC_AVAIL
  b15:0  NP_TXF_SPC_AVAIL
+030 GI2CCTL
  b31    BSYDNE
  b30    RW
  b29    ???
  b28    I2CDATSE0
  b27:26 I2CDEVADDR
  b25    I2CSUSPCTL
  b24    ACK
  b23    I2CEN
  b22:16 ADDR
  b15:8  REGADDR
  b7:0   RWDATA
+034 GPVNDCTL
+038 GGPIO
  b22    STM32_OTG_GCCFG_IDEN
  b21    STM32_OTG_GCCFG_VBDEN
  b16    STM32_OTG_GCCFG_PWRDWN
+03c GUID       UID=User ID
+040 GSNPSID    Vendor ID, supposed to be $4f542XXX
+044 GHWCFG1    HW=Hardware
+048 GHWCFG2
  b31    OTG_ENABLE_IC_USB
  b30:26 DEV_TOKEN_Q_DEPTH
  b25:24 HOST_PERIO_TX_Q_DEPTH
  b23:22 NONPERIO_TX_Q_DEPTH
  b21    ???
  b20    MULTI_PROC_INT
  b19    DYNAMIC_FIFO
  b18    PERIO_EP_SUPPORTED
  b17:14 NUM_HOST_CHAN
  b13:10 NUM_DEV_EP
  b9:8   FS_PHY_TYPE
    0=NOT_SUPPORTED
    1=DEDICATED
    2=SHARED_UTMI
    3=SHARED_ULPI
  b7:6   HS_PHY_TYPE
    0=NOT_SUPPORTED
    1=UTMI
    2=ULPI
    3=UTMI_ULPI
  b5     POINT2POINT
  b4:3   ARCHITECTURE
    0=SLAVE_ONLY
    1=EXT_DMA
    2=INT_DMA
  b2:0   OP_MODE
    0=HNP_SRP_CAPABLE
    1=SRP_ONLY_CAPABLE
    2=NO_HNP_SRP_CAPABLE
    3=SRP_CAPABLE_DEVICE
    4=NO_SRP_CAPABLE_DEVICE
    5=SRP_CAPABLE_HOST
    6=NO_SRP_CAPABLE_HOST
    7=UNDEFINED
+04c GHWCFG3
  b31:16 DFIFO_DEPTH
  b15    OTG_LPM_EN
  b14    BC_SUPPORT
  b13    OTG_ENABLE_HSIC
  b12    ADP_SUPP
  b11    SYNCH_RESET_TYPE
  b10    OPTIONAL_FEATURES
  b9     VENDOR_CTRL_IF
  b8     I2C
  b7     OTG_FUNC
  b6:4   PACKET_SIZE_CNTR_WIDTH
  b3:0   XFER_SIZE_CNTR_WIDTH
+050 GHWCFG4
  b31    DESC_DMA_DYN
  b30    DESC_DMA
  b29:26 NUM_IN_EPS
  b25    DED_FIFO_EN
  b24    SESSION_END_FILT_EN
  b23    B_VALID_FILT_EN
  b22    A_VALID_FILT_EN
  b21    VBUS_VALID_FILT_EN
  b20    IDDIG_FILT_EN
  b19:16 NUM_DEV_MODE_CTRL_EP
  b15:14 UTMI_PHY_DATA_WIDTH 0=8 1=16 2=8-or-16
  b13    ???
  b12    ACG_SUPPORTED
  b11    IPG_ISOC_SUPPORTED
  b10    SERVICE_INTERVAL_SUPPORTED
  b9:8   ???
  b7     XHIBER
  b6     HIBER
  b5     MIN_AHB_FREQ
  b4     POWER_OPTIMIZ
  b3:0   NUM_DEV_PERIO_IN_EP
+054 GLPMCFG
  b31    INVSELHSIC
  b30    HSICCON
  b29    RSTRSLPSTS
  b28    ENBESL
  b27:25 LPM_RETRYCNT_STS
  b24    SNDLPM
  b23:21 RETRY_CNT (WTF: conflict with LPM_xx on b21 and b22)
  b20:17 LPM_CHNL_INDX
  b16    L1RESUMEOK
  b15    SLPSTS
  b14:13 COREL1RES
  b12:8  HIRD_THRES
  b7     ENBLSLPM
  b6     BREMOTEWAKE
  b5:2   HIRD
  b1     APPL1RES
  b0     LPMCAP
+058 GPWRDN
  b31:29 ???
  b28:24 MULT_VAL_ID_BC
  b23    ADP_INT
  b22    BSESSVLD
  b21    IDSTS
  b20:19 LINESTATE
  b18    STS_CHGINT_MSK
  b17    STS_CHGINT
  b16    SRP_DET_MSK
  b15    SRP_DET
  b14    CONNECT_DET_MSK
  b13    CONNECT_DET
  b12    DISCONN_DET_MSK
  b11    DISCONN_DET
  b10    RST_DET_MSK
  b9     RST_DET
  b8     LNSTSCHK_MSK
  b7     LNSTSCHK
  b6     DIS_VBUS
  b5     PWRDNSWTCH
  b4     PWRDNRSTN
  b3     PWRDNCLMP
  b2     RESTORE
  b1     PMUACTV
  b0     PMUINTSEL
+05c GDFIFOCFG
  b31:16 EPINFOBASE
  b15:0  GDFIFOCFG
+060 ADPCTL
  b31:29 ???
  b28:27 AR
  b26    ADP_TMOUT_INT_MSK
  b25    ADP_SNS_INT_MSK
  b24    ADP_PRB_INT_MSK
  b23    ADP_TMOUT_INT
  b22    ADP_SNS_INT
  b21    ADP_PRB_INT
  b20    ADPENA
  b19    ADPRES
  b18    ENASNS
  b17    ENAPRB
  b16:6  RTIM
  b5:4   PRB_PER
  b3:2   PRB_DELTA
  b1:0   PRB_DSCHRG
+064 GREFCLK
  b31:15 REFCLKPER
  b14    REF_CLK_MODE
  b13:0  SOF_CNT_WKUP_ALERT
+068 GINTMSK2
  b0     WKUP_ALERT_INT_MSK
+06c GINTSTS2
  b0     WKUP_ALERT_INT
...
+100 HPTXFSIZ   P=Periodic
  (same as GNPTXFSIZ)
+104 DPTXFSIZN (array of data like GNPTXFSIZ)
...
+400 Host mode (see below)
...
+800 Device mode (see below)
...
+e00 PCGCTL     Power Control
  b31    IF_DEV_MODE
  b30:29 P2HD_PRT_SPD
  b28:27 P2HD_DEV_ENUM_SPD
  b26:20 MAC_DEV_ADDR
  b19    MAX_TERMSEL
  b18:17 MAX_XCVRSELECT
  b16    PORT_POWER
  b15:14 PRT_CLK_SEL
  b13    RSS_REG_RESTORED
  b12    EXTND_HIBER_SWITCH
  b11    EXTND_HIBER_PWRCLMP
  b10    ENBL_EXTND_HIBER
  b9     RESTOREMODE
  b8     RESETAFTSUSP
  b7     DEEP_SLEEP
  b6     PHY_IN_SLEEP
  b5     ENBL_SLEEP_GATING
  b4     ???
  b3     RSTPDWNMODULE
  b2     PWRCLMP
  b1     GATEHCLK
  b0     STOPPCLK
+e04 PCGCCTL1
  b2:1   TIMER
  b0     GATEEN
...
+1000 FIFO (array with $1000 bytes elements)

### Host mode

+400 HCFG
  b31    MODECHTIMEN
  b30:27 ???
  b26    PERSCHEDENA
  b25:24 FRLISTEN 0=8 1=16 2=32 3=65
  b23    DESCDMA
  b22:16 ???
  b15:8  RESVALID
  b7     ENA32KHZ
  b6:3   ???
  b2     FSLSSUPP
  b1:0   FSLSPCLKSEL
    0=30_60_MHZ
    1=48_HMZ
    2=6_MHZ
+404 HFIR       Frame Interval
  b16    RLDCTRL
  b15:0  FRINT
+408 HFNUM      Frame Number
  b31:16 FRREM
  b15:0  FRNUM
...
+410 HPTXSTS    Host FIFO Status
  b31    QTOP_ODD
  b30:27 QTOP_CHNEP
  b26:25 QTOP_TOKEN
  b24    QTOP_TERMINATE
  b23:16 QSPCAVAIL
  b15:0  FSPCAVAIL
+414 HAINT      A=???
+418 HAINTMSK
+41c HFLBADDR   Frame List Addr
...
+440 HPRT0
  b31:19 ???
  b18:17 SPD
    0=HIGH_SPEED
    1=FULL_SPEED
    2=LOW_SPEED
  b16:13 TSTCTL
  b12    PWR
  b11:10 LNSTS
  b9     ???
  b8     RST
  b7     SUSP
  b6     RES
  b5     OVRCURRCHG
  b4     OVRCURRACT
  b3     ENACHG
  b2     ENA
  b1     CONNDET
  b0     CONNSTS
...
+500 Channel, an array with $20b elements:
  +00 HCCHAR    Characteristic
    b31    CHENA     Channel Enable
    b30    CHDIS     Channel Disable
    b29    ODDFRM    Odd Frame
    b28:22 DEVADDR   Device Address
    b21:20 MULTICNT
    b19:18 EPTYPE    Transfer Type 0=Control 1=Iso 2=Bulk 3=Interrupt
    b17    LSPDDEV
    b16    ???
    b15    EPDIR     Endpoint direction 0=Host->Dev 1=Dev->Host
    b14:11 EPNUM     Endpoint Number
    b10:0  MPS       Maximum Packet Size
  +04 HCSPLT    Split Control
    b31    SPLTENA   Split Enable
    b30:17 ???
    b16    COMPSPLT
    b15:14 XACTPOS 0=MID 1=END 2=BEGIN 3=ALL
    b13:7  HUBADDR
    b6:0   PRTADDR
  +08 HCINT     Interrupt
    b31:14 ???
    b13    FRM_LIST_ROLL
    b12    XCS_XACT
    b11    BNA
    b10    DATATGLERR
    b9     FRMOVRUN
    b8     BBLERR
    b7     XACTERR
    b6     BYET
    b5     ACK
    b4     NAK
    b3     STALL
    b2     AHBERR
    b1     CHHLTD
    b0     XFERCOMPL
  +0c HCINTMSK
  +10 HCTSIZ    Transfer Size
    b31    DOPNG
    b30:29 SC_MC_PID 0=DATA0 1=DATA2 2=DATA1 3=MDATA/SETUP
    b28:19 PKTCNT
    b18:0  XFERSIZ   Transfer Size
  +14 HCDMA     DMA Address
  ...
  +1c HCFIFO    DMA Buffer
...

### Device mode

TODO: fill this with details, maybe one day...

+800 DCFG
+804 DCTL
+808 DSTS
...
+810 DIEPMSK
+814 DOEPMSK
+818 DAINT
+81c DAINTMSK
+820 DTKNQR1
+824 DTKNQR2
+828 DVBUSDIS
+82c DVBUSPULSE
+830 DTKNQR3
+834 DTKNQR4
+834 DIEPEMPMSK (??? confused pikachu)
...
+900 DIEPCTL0 (array with $20 bytes elements)
...
+b00 DOEPCTL0 (array with $20 bytes elements)
...

## Theory of operation

(This hasn't been tested yet, it's only what I can read from csud. To avoid
weighting the text down with "seems" and "looks like", I write as if I knew,
but actually I don't. Everything I write down here is what *seems* to me like
the real thing.)

Unlike with UHCI, there isn't a requirement to manage TDs and QHs in system
memory. Requests and associated data are supplied directly to the hardware
through what is called a "channel". Channels can be seen as active communication
pipelines between the host and an endpoint.

What controls whether a channel is actively "working" is its CHENA/CHDIS fields.
I don't know why there's two such fields, but an active channel is set to 1/0.

But before that, you have to configure it. For example, you'll want to set HCINT
to -1 (no interrupt set) and set all characteristics, which mostly have straight
mappings to UHCI concepts.

I don't know why, but csud sets MULTICNT to 1 before each transfer.

A side of the configuration that doesn't map to UHCI because we don't manage TDs
and QHs are the HCTSIZ and HCDMA registers. The principle is rather simple:
HCDMA is a pointer to the data and HCTSIZ is the buffer size along with
"packaging" instructions, that is, how many packets of what type will be sent.

csud only uses the Setup and Data1 packet types (SC_MC_PID). I guess that the
Data0/Data1 little dance from the USB specs is handled by hardware.

As for the PKTCNT part, csud does a simple division by MPS.

To initiate a transaction, CHENA/CHDIS are set to 1/0 and a loop is initiated to
check on HCINT: XFERCOMPL goes low when the transfer is complete, or one of the
error interrupt goes low if there's an error.

HCTSIZ is updated as transfers progresses.
