EHCI for USB2.0 in imxrt1052
Here’s a clear, practical breakdown of each macro, how they map to the EHCI spec, and how to use them correctly in your host driver code. I’ll also include some ready‑to‑drop‑in helper functions/macros.What these macros representPointer/link fields in EHCIMany EHCI structures (e.g., Periodic Frame List entries, Queue Heads (QH), iTD, siTD, FSTN) contain 32‑bit link pointers with encoded control bits:Bit 0: T (Terminate). When set to 1, the pointer is invalid (end oflist).Bits 2:1: Type field:00b → iTD (isochronous high-speed)01b → QH (queue head)10b → siTD (split transaction isochronous, FS/LS via TT)11b → FSTN (frame span traversal node)Bits 31:5: Physical address of the next structure (aligned to 32bytes; hence the low 5 bits are reserved for flags).Your masks/values align with this:#define EHCI_HOST_T_INVALID_VALUE (1U) // bit0 1 - Terminate #define EHCI_HOST_POINTER_TYPE_ITD (0x00U) // (00b 1) #define EHCI_HOST_POINTER_TYPE_QH (0x00000002U) // (01b 1) #define EHCI_HOST_POINTER_TYPE_SITD (0x00000004U) // (10b 1) #define EHCI_HOST_POINTER_TYPE_FSTN (0x00000006U) // (11b 1) #define EHCI_HOST_POINTER_TYPE_MASK (0x00000006U) // mask bits 2:1 #define EHCI_HOST_POINTER_ADDRESS_MASK (0xFFFFFFE0U) // keep bits 31:5USB PID for qTDsFor Queue Element Transfer Descriptors (qTDs), the PID field selects the transaction type:#define EHCI_HOST_PID_OUT (0UL) // 0b00 #define EHCI_HOST_PID_IN (1UL) // 0b01 #define EHCI_HOST_PID_SETUP (2UL) // 0b10These values map directly to the PID Code in the qTD token field.⚙️ Context: EHCI requires 32‑byte alignment on many structures (hence the address mask). The link’s low bits are overloaded for control (T Type).How to compose and parse EHCI link pointersUse these helpers to build and read the link fields safely:// Compose a valid link pointer: address must be 32-byte aligned. static inline uint32_t ehci_make_link(uint32_t phys_addr, uint32_t type) { // Clear low 5 bits of the address, OR in the type (bits 2:1). return (phys_addr EHCI_HOST_POINTER_ADDRESS_MASK) | (type EHCI_HOST_POINTER_TYPE_MASK); } // Terminate a link (end of list). static inline uint32_t ehci_make_terminate(void) { return EHCI_HOST_T_INVALID_VALUE; // bit0 1, other bits 0 } // Check if link is terminated. static inline int ehci_link_is_terminate(uint32_t link) { return (link EHCI_HOST_T_INVALID_VALUE) ! 0; } // Extract the pointer type (returns one of EHCI_HOST_POINTER_TYPE_* or 0x06, etc.). static inline uint32_t ehci_link_type(uint32_t link) { return (link EHCI_HOST_POINTER_TYPE_MASK); } // Extract the physical address (bits 31:5). static inline uint32_t ehci_link_addr(uint32_t link) { return (link EHCI_HOST_POINTER_ADDRESS_MASK); }Example usage:// Given a physical address of a QH: uint32_t qh_phys /* 32-byte aligned */; // Create a frame list entry that points to this QH: uint32_t flp ehci_make_link(qh_phys, EHCI_HOST_POINTER_TYPE_QH); // Mark end of list: uint32_t end ehci_make_terminate(); // Parse: if (!ehci_link_is_terminate(flp)) { uint32_t type ehci_link_type(flp); uint32_t addr ehci_link_addr(flp); // type EHCI_HOST_POINTER_TYPE_QH, addr qh_phys (masked) }Setting qTD PIDs correctlyThe qTD Token word encodes PID, data toggle, bytes to transfer, interrupt on complete, error counters, etc. A typical pattern:// Token field bits (commonly used) #define QTD_TOKEN_STATUS_ACTIVE (1U 7) #define QTD_TOKEN_TOGGLE (1U 31) // DT bit when using toggle from token #define QTD_TOKEN_IOC (1U 15) // Interrupt On Complete #define QTD_TOKEN_PID_SHIFT 8U #define QTD_TOKEN_PID_MASK (3U QTD_TOKEN_PID_SHIFT) static inline uint32_t ehci_qtd_token(uint32_t pid, uint32_t bytes, int ioc, int data_toggle) { uint32_t token 0; token | (pid 0x3U) QTD_TOKEN_PID_SHIFT; token | (bytes 0x7FFFU) 16; // total bytes to transfer (15 bits) if (ioc) token | QTD_TOKEN_IOC; if (data_toggle) token | QTD_TOKEN_TOGGLE; // if using explicit DT in token token | QTD_TOKEN_STATUS_ACTIVE; // mark active return token; } // Example: SETUP stage of a control transfer (always DATA0) uint32_t setup_tok ehci_qtd_token(EHCI_HOST_PID_SETUP, 8, /*ioc*/0, /*toggle*/0); // Example: IN data stage with IOC uint32_t in_tok ehci_qtd_token(EHCI_HOST_PID_IN, 64, /*ioc*/1, /*toggle*/1); // Example: OUT data stage uint32_t out_tok ehci_qtd_token(EHCI_HOST_PID_OUT, 64, /*ioc*/0, /*toggle*/0); Note: Whether you set the Data Toggle (DT) in the qTD token or let the QH manage toggling via the DT Control bit depends on how you configure the QH (QH.EPCHAR.DTC). Many stacks use QH-based toggling for bulk/interrupt, explicit token DT for control SETUP/DATA0 consistency.Correctness tips common pitfallsAlignment is mandatoryiTD/QH/siTD/FSTN must be 32‑byte aligned. The link address mask enforces this.2. Don’t forget the Terminate bitThe end of a list must have T1. A non‑terminated dangling pointer can lock up the schedule.3. Type must match the pointed structureIf you point to a QH, set TypeQH (01b). Mismatches cause undefined behavior.Volatile and barriersEHCI structures are DMA‑visible. Use volatile for doorbells/status and insert memory barriers before ringing the doorbell or enabling schedules:wmb(); // ensure descriptors are written before enabling ehci_regs-usbcmd | (1U 0); // Run/Stop 1, etc.5. Physical vs virtual addressesThe controller needs physical addresses in link fields and buffer pointers. Ensure proper DMA mapping and cache coherency (flush/invalidate as needed).6. PID use in control transfersSETUP stage: PIDSETUP, always DATA0.DATA stage: IN or OUT, toggle per spec (DATA1 typically for firstdata stage).STATUS stage: the opposite direction of DATA, one packet, DATA1.Quick reference: Type values// Bits: [0]T, [2:1]Type, [31:5]addr // Type encodings: EHCI_HOST_POINTER_TYPE_ITD // 00b 1 0x0 EHCI_HOST_POINTER_TYPE_QH // 01b 1 0x2 EHCI_HOST_POINTER_TYPE_SITD // 10b 1 0x4 EHCI_HOST_POINTER_TYPE_FSTN // 11b 1 0x6What’s the relationship between them?The pointer-type macros and the PID macros live at different layers of the EHCI scheduling pipeline—but they work together end‑to‑end during a transfer. The pointer Type bits route the controller through the scheduling structures (frame list → iTD/siTD/QH), and once a QH leads to a qTD, the PID in the qTD defines the USB transaction direction/stage the host actually performs on the bus.Below is a clear mapping of where each set of macros applies and how data flows.Big picture: where each one is used1) Pointer Type Link/Address macros (structure navigation)These control how the EHCI hardware walks the schedule:Periodic Frame List entries (and the next/alt next in descriptors)use:T bit (EHCI_HOST_T_INVALID_VALUE) to indicate end-of-list.Type bits (EHCI_HOST_POINTER_TYPE_*) to indicate what the pointer targets:iTD high-speed isochronoussiTD FS/LS split isochronous via TTQH queue head (bulk/interrupt/control use qTD chains)FSTN frame span traversal nodeAddress mask (EHCI_HOST_POINTER_ADDRESS_MASK) to carry the 32‑bytealigned physical address of the next structure.In other words, these macros are about linked-list traversal throughEHCI memory structures.2) PID macros (qTD token → USB transaction semantics)These are used inside a qTD’s Token word to specify what kind of packet to send on the USB wire:EHCI_HOST_PID_OUT → Host → Device data stageEHCI_HOST_PID_IN → Device → Host data stageEHCI_HOST_PID_SETUP → Control transfer SETUP stageThese macros are about the actual USB transaction type once thecontroller reaches a qTD.How they interact during a transfer (control/bulk/interrupt)A typical control/bulk/interrupt transfer path looks like this:[Frame List Entry] └──(TypeQH)── [QH] └── [qTD #1: Token(PIDSETUP/OUT/IN, bytes, DT, Active...)] └── alt/next qTDs...Frame List entry says “this is a QH” using the Type bits.EHCI follows the pointer (address masked/aligned) to the QH.From the QH, EHCI fetches the qTD chain.In each qTD, the PID determines the transaction (SETUP/IN/OUT) thatthe host performs on the USB bus.When a list ends, the T bit terminates traversal cleanly.So, Type bits get you to the right structure; PID tells the controller what to do once it’s there.How they interact during isochronous (HS/FS) transfersFor high‑speed isochronous, the frame list points directly to an iTD:[Frame List Entry] └──(TypeiTD)── [iTD with up to 8 transactions per micro‑frame]iTD/siTD embed transaction contexts per microframe. You typicallydon’t use qTDs or PID macros here; the transaction info is encodeddifferently in iTD/siTD.Type bits are still how the hardware knows it’s looking at aniTD/siTD instead of a QH.Relationship summary- Same address field, different meanings for low bits:- Low 1–3 bits of link words are control (T Type). - High bits form the 32‑byte aligned physical address (EHCI_HOST_POINTER_ADDRESS_MASK).- Traversal vs. execution:- Traversal: TypeT select and walk which structure comes next (iTD/siTD/QH/FSTN). - Execution: Once a qTD is reached (via a QH), the PID in the qTD token controls the USB packet type sent/expected.- Scope:- Pointer macros apply to frame-list entries, QH link pointers, iTD/siTD link fields, etc. - PID macros apply only to qTD tokens (i.e., bulk/interrupt/control transfers through QHs).Quick visual cheat-sheetPeriodic Schedule (Frame List) | -- TypeQH --- QH --- qTD(Token.PIDIN/OUT/SETUP) --- executes on USB bus | -- TypeiTD --- iTD (isoch transactions per microframe; not using qTD PIDs) | -- TypesiTD -- siTD (split-isochronous) | -- TypeFSTN -- FSTN (span control) | -- T1 (Terminate)Practical tipsEnsure 32‑byte alignment on all EHCI structures; the address maskassumes the lower 5 bits are free.Type must match the actual structure you point to—don’t point to a QHwith TypeiTD.Terminate properly with T1 to avoid schedule walks into garbage.PID sequencing:Control: SETUP(DATA0) → DATA(IN/OUT) (toggle) → STATUS(opposite dir, DATA1)Bulk/Interrupt: use QH-managed data toggle (DTC) or set DT in tokenconsistently.DATA0 DATA DATA1DATA0 / DATA1 / DATA — the USB Data Toggle mechanism — and how it relates to EHCI transfers (qTD, QH, PID).Perfect, let’s break it down very clearly.✅ What DATA0 / DATA1 / DATA meanUSB uses data toggle synchronization to ensure both host and device know whether a data packet is new or a retry.Each direction (IN or OUT) on each endpoint keeps its own toggle state:DATA0 → toggle 0DATA1 → toggle 1DATA → means “use the current toggle state”, whichever it is (somedocumentation writes “DATA” as “don’t care / follow QH state”). How EHCI handles DATA0 / DATA1In EHCI, the Data Toggle comes from exactly one of these:Option A: Toggle handled by QH(i.e., “Data Toggle Control 1” in QH.EPCHAR.DTC)C)Then:qTD Token → does NOT specify DATA0/DATA1QH maintains the toggle automaticallyAfter each successful qTD, the toggle flips Recommended for bulk and interrupt transfers Simplifies driver logicOption B: Toggle comes from qTD Token(i.e., DTC 0)Then:qTD Token bit31 encodes DATA0 or DATA1Hardware uses whatever the qTD saysDoes not flip automaticallyRequired for control transfers, because:SETUP stage → always DATA0DATA stage → DATA1 (usually)STATUS → DATA1So for control transfers the driver must explicitly set DATA0/DATA1 in each qTD. How DATA0 / DATA1 apply in real transfer types1️⃣ Control Transfer (always needs explicit DATA toggles)Sequence:SETUP : PIDSETUP, DATA0 DATA : PIDIN or OUT, usually DATA1 STATUS : PID opposite direction, DATA1EHCI encoding:qTD.Token.PID SETUP/IN/OUTqTD.Token.DT (bit31) DATA0 or DATA1 (explicit!)QH.DTC must be 0 (meaning “use token’s toggle”)2️⃣ Bulk TransferTwo styles possible:RecommendedLet QH manage DATA toggles:QH.DTC 1 (data-toggle-control mode)qTD.Token.DT is ignoredHardware automatically:tracks sync stateflips toggle on successful transferThis is how Linux, Windows, and major USB stacks do it.If you manually control:QH.DTC 0qTD.Token.DT specifies DATA0 or DATA1Driver must track toggle (error-prone)3️⃣ Interrupt TransferSame as Bulk.Most drivers let QH do auto-toggle management. What does “DATA” mean in your question?When documentation or comments say:DATA0 → toggle 0DATA1 → toggle 1DATA → “follow the current toggle state automatically”“DATA” means:Let the controller (QH) manage the toggle automaticallyIt’s not a third toggle state.It means automatic mode, not DATA2 or anything new. Summary Table