2 * Driver for USB OHCI ported from CoreBoot
4 * Copyright (C) 2014 BALATON Zoltan
6 * This file was part of the libpayload project.
8 * Copyright (C) 2010 Patrick Georgi
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #ifndef __OHCI_PRIVATE_H
35 #define __OHCI_PRIVATE_H
37 #include "libc/byteorder.h"
40 #define READ_OPREG(ohci, field) (__le32_to_cpu((ohci)->opreg->field))
41 #define MASK(startbit, lenbit) (((1<<(lenbit))-1)<<(startbit))
44 typedef enum { CMD} reg;
47 NumberDownstreamPorts = 1<<0,
48 PowerSwitchingMode = 1<<8,
49 NoPowerSwitching = 1<<9,
51 OverCurrentProtectionMode = 1<<11,
52 NoOverCurrentProtection = 1<<12,
53 PowerOnToPowerGoodTime = 1<<24
57 NumberDownstreamPortsMask = MASK(0, 8),
58 PowerOnToPowerGoodTimeMask = MASK(24, 8)
59 } HcRhDescriptorAMask;
62 DeviceRemovable = 1<<0,
63 PortPowerControlMask = 1<<16
67 CurrentConnectStatus = 1<<0,
68 PortEnableStatus = 1<<1,
69 PortSuspendStatus = 1<<2,
70 PortOverCurrentIndicator = 1<<3,
71 PortResetStatus = 1<<4,
72 PortPowerStatus = 1<<8,
73 LowSpeedDeviceAttached = 1<<9,
74 ConnectStatusChange = 1<<16,
75 PortEnableStatusChange = 1<<17,
76 PortSuspendStatusChange = 1<<18,
77 PortOverCurrentIndicatorChange = 1<<19,
78 PortResetStatusChange = 1<<20
81 ClearPortEnable = 1<<0,
83 SetPortSuspend = 1<<2,
84 ClearSuspendStatus = 1<<3,
87 ClearPortPower = 1<<9,
91 LocalPowerStatus = 1<<0,
92 OverCurrentIndicator = 1<<1,
93 DeviceRemoteWakeupEnable = 1<<15,
94 LocalPowerStatusChange = 1<<16,
95 OverCurrentIndicatorChange = 1<<17,
96 ClearRemoteWakeupEnable = 1<<31
100 FrameInterval = 1<<0,
101 FSLargestDataPacket = 1<<16,
102 FrameIntervalToggle = 1<<31
103 } HcFmIntervalOffset;
105 FrameIntervalMask = MASK(0, 14),
106 FSLargestDataPacketMask = MASK(16, 15),
107 FrameIntervalToggleMask = MASK(31, 1)
111 ControlBulkServiceRatio = 1<<0,
112 PeriodicListEnable = 1<<2,
113 IsochronousEnable = 1<<3,
114 ControlListEnable = 1<<4,
115 BulkListEnable = 1<<5,
116 HostControllerFunctionalState = 1<<6,
117 InterruptRouting = 1<<8,
118 RemoteWakeupConnected = 1<<9,
119 RemoteWakeupEnable = 1<<10
123 ControlBulkServiceRatioMask = MASK(0, 2),
124 HostControllerFunctionalStateMask = MASK(6, 2)
128 USBReset = 0*HostControllerFunctionalState,
129 USBResume = 1*HostControllerFunctionalState,
130 USBOperational = 2*HostControllerFunctionalState,
131 USBSuspend = 3*HostControllerFunctionalState
135 HostControllerReset = 1<<0,
136 ControlListFilled = 1<<1,
137 BulkListFilled = 1<<2,
138 OwnershipChangeRequest = 1<<3,
139 SchedulingOverrunCount = 1<<16
140 } HcCommandStatusReg;
143 SchedulingOverrunCountMask = MASK(16, 2)
144 } HcCommandStatusMask;
147 FrameRemaining = 1<<0,
148 FrameRemainingToggle = 1<<31
152 SchedulingOverrung = 1<<0,
153 WritebackDoneHead = 1<<1,
155 ResumeDetected = 1<<3,
156 UnrecoverableError = 1<<4,
157 FrameNumberOverflow = 1<<5,
158 RootHubStatusChange = 1<<6,
159 OwnershipChange = 1<<30
160 } HcInterruptStatusReg;
163 // Control and Status Partition
164 volatile u32 HcRevision;
165 volatile u32 HcControl;
166 volatile u32 HcCommandStatus;
167 volatile u32 HcInterruptStatus;
168 volatile u32 HcInterruptEnable;
169 volatile u32 HcInterruptDisable;
171 // Memory Pointer Partition
173 volatile u32 HcPeriodCurrentED;
174 volatile u32 HcControlHeadED;
175 volatile u32 HcControlCurrentED;
176 volatile u32 HcBulkHeadED;
177 volatile u32 HcBulkCurrentED;
178 volatile u32 HcDoneHead;
180 // Frame Counter Partition
181 volatile u32 HcFmInterval;
182 volatile u32 HcFmRemaining;
183 volatile u32 HcFmNumber;
184 volatile u32 HcPeriodicStart;
185 volatile u32 HcLSThreshold;
187 // Root Hub Partition
188 volatile u32 HcRhDescriptorA;
189 volatile u32 HcRhDescriptorB;
190 volatile u32 HcRhStatus;
191 /* all bits in HcRhPortStatus registers are R/WC, so
192 _DO NOT_ use |= to set the bits,
193 this clears the entire state */
194 volatile u32 HcRhPortStatus[];
195 } __attribute__ ((packed)) opreg_t;
197 typedef struct { /* should be 256 bytes according to spec */
198 u32 HccaInterruptTable[32];
199 volatile u16 HccaFrameNumber;
200 volatile u16 HccaPad1;
201 volatile u32 HccaDoneHead;
202 u8 reserved[116]; /* pad according to spec */
203 u8 what[4]; /* really pad to 256 as spec only covers 252 */
204 } __attribute__ ((packed)) hcca_t;
206 typedef volatile struct {
211 } __attribute__ ((packed)) ed_t;
215 #define ED_FUNC_SHIFT 0
216 #define ED_FUNC_MASK MASK(0, 7)
217 #define ED_EP_SHIFT 7
218 #define ED_EP_MASK MASK(7, 4)
219 #define ED_DIR_SHIFT 11
220 #define ED_DIR_MASK MASK(11, 2)
221 #define ED_LOWSPEED (1 << 13)
222 #define ED_MPS_SHIFT 16
224 typedef volatile struct {
226 u32 current_buffer_pointer;
229 } __attribute__ ((packed)) td_t;
231 * Bits 0 through 17 of .config won't be interpreted by the host controller
232 * (HC) and, after processing the TD, the HC has to ensure those bits have
233 * the same state as before. So we are free to use those bits for our own
236 #define TD_QUEUETYPE_SHIFT 0
237 #define TD_QUEUETYPE_MASK MASK(TD_QUEUETYPE_SHIFT, 2)
238 #define TD_QUEUETYPE_ASYNC (0 << TD_QUEUETYPE_SHIFT)
239 #define TD_QUEUETYPE_INTR (1 << TD_QUEUETYPE_SHIFT)
241 #define TD_DIRECTION_SHIFT 19
242 #define TD_DIRECTION_MASK MASK(TD_DIRECTION_SHIFT, 2)
243 #define TD_DIRECTION_SETUP OHCI_SETUP << TD_DIRECTION_SHIFT
244 #define TD_DIRECTION_IN OHCI_IN << TD_DIRECTION_SHIFT
245 #define TD_DIRECTION_OUT OHCI_OUT << TD_DIRECTION_SHIFT
246 #define TD_DELAY_INTERRUPT_SHIFT 21
247 #define TD_DELAY_INTERRUPT_MASK MASK(TD_DELAY_INTERRUPT_SHIFT, 3)
248 #define TD_DELAY_INTERRUPT_ZERO 0
249 #define TD_DELAY_INTERRUPT_NOINTR (7 << TD_DELAY_INTERRUPT_SHIFT)
250 #define TD_TOGGLE_DATA0 0
251 #define TD_TOGGLE_DATA1 (1 << 24)
252 #define TD_TOGGLE_FROM_ED 0
253 #define TD_TOGGLE_FROM_TD (1 << 25)
254 #define TD_CC_SHIFT 28
255 #define TD_CC_MASK MASK(TD_CC_SHIFT, 4)
256 #define TD_CC_NOERR 0
257 #define TD_CC_NOACCESS (14 << TD_CC_SHIFT) /* the lower of the two values, so "no access" can be tested with >= */
259 #define OHCI_INST(controller) ((ohci_t*)((controller)->instance))
261 typedef struct ohci {
268 typedef enum { OHCI_SETUP=0, OHCI_OUT=1, OHCI_IN=2, OHCI_FROM_TD=3 } ohci_pid_t;