1 /* 2 * Driver for USB OHCI ported from CoreBoot 3 * 4 * Copyright (C) 2014 BALATON Zoltan 5 * 6 * This file was part of the libpayload project. 7 * 8 * Copyright (C) 2010 Patrick Georgi 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 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. 20 * 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 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef __OHCI_PRIVATE_H 35 #define __OHCI_PRIVATE_H 36 37 #include "libc/byteorder.h" 38 #include "usb.h" 39 40 #define READ_OPREG(ohci, field) (__le32_to_cpu((ohci)->opreg->field)) 41 #define MASK(startbit, lenbit) (((1<<(lenbit))-1)<<(startbit)) 42 43 // FIXME: fake 44 typedef enum { CMD} reg; 45 46 extern enum { 47 NumberDownstreamPorts = 1<<0, 48 PowerSwitchingMode = 1<<8, 49 NoPowerSwitching = 1<<9, 50 DeviceType = 1<<10, 51 OverCurrentProtectionMode = 1<<11, 52 NoOverCurrentProtection = 1<<12, 53 PowerOnToPowerGoodTime = 1<<24 54 } HcRhDescriptorAReg; 55 56 extern enum { 57 NumberDownstreamPortsMask = MASK(0, 8), 58 PowerOnToPowerGoodTimeMask = MASK(24, 8) 59 } HcRhDescriptorAMask; 60 61 extern enum { 62 DeviceRemovable = 1<<0, 63 PortPowerControlMask = 1<<16 64 } HcRhDescriptorBReg; 65 66 extern enum { 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 79 } HcRhPortStatusRead; 80 extern enum { 81 ClearPortEnable = 1<<0, 82 SetPortEnable = 1<<1, 83 SetPortSuspend = 1<<2, 84 ClearSuspendStatus = 1<<3, 85 SetPortReset = 1<<4, 86 SetPortPower = 1<<8, 87 ClearPortPower = 1<<9, 88 } HcRhPortStatusSet; 89 90 extern enum { 91 LocalPowerStatus = 1<<0, 92 OverCurrentIndicator = 1<<1, 93 DeviceRemoteWakeupEnable = 1<<15, 94 LocalPowerStatusChange = 1<<16, 95 OverCurrentIndicatorChange = 1<<17, 96 ClearRemoteWakeupEnable = 1<<31 97 } HcRhStatusReg; 98 99 extern enum { 100 FrameInterval = 1<<0, 101 FSLargestDataPacket = 1<<16, 102 FrameIntervalToggle = 1<<31 103 } HcFmIntervalOffset; 104 extern enum { 105 FrameIntervalMask = MASK(0, 14), 106 FSLargestDataPacketMask = MASK(16, 15), 107 FrameIntervalToggleMask = MASK(31, 1) 108 } HcFmIntervalMask; 109 110 extern enum { 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 120 } HcControlReg; 121 122 extern enum { 123 ControlBulkServiceRatioMask = MASK(0, 2), 124 HostControllerFunctionalStateMask = MASK(6, 2) 125 } HcControlMask; 126 127 enum { 128 USBReset = 0*HostControllerFunctionalState, 129 USBResume = 1*HostControllerFunctionalState, 130 USBOperational = 2*HostControllerFunctionalState, 131 USBSuspend = 3*HostControllerFunctionalState 132 }; 133 134 extern enum { 135 HostControllerReset = 1<<0, 136 ControlListFilled = 1<<1, 137 BulkListFilled = 1<<2, 138 OwnershipChangeRequest = 1<<3, 139 SchedulingOverrunCount = 1<<16 140 } HcCommandStatusReg; 141 142 extern enum { 143 SchedulingOverrunCountMask = MASK(16, 2) 144 } HcCommandStatusMask; 145 146 extern enum { 147 FrameRemaining = 1<<0, 148 FrameRemainingToggle = 1<<31 149 } HcFmRemainingReg; 150 151 extern enum { 152 SchedulingOverrung = 1<<0, 153 WritebackDoneHead = 1<<1, 154 StartofFrame = 1<<2, 155 ResumeDetected = 1<<3, 156 UnrecoverableError = 1<<4, 157 FrameNumberOverflow = 1<<5, 158 RootHubStatusChange = 1<<6, 159 OwnershipChange = 1<<30 160 } HcInterruptStatusReg; 161 162 typedef struct { 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; 170 171 // Memory Pointer Partition 172 volatile u32 HcHCCA; 173 volatile u32 HcPeriodCurrentED; 174 volatile u32 HcControlHeadED; 175 volatile u32 HcControlCurrentED; 176 volatile u32 HcBulkHeadED; 177 volatile u32 HcBulkCurrentED; 178 volatile u32 HcDoneHead; 179 180 // Frame Counter Partition 181 volatile u32 HcFmInterval; 182 volatile u32 HcFmRemaining; 183 volatile u32 HcFmNumber; 184 volatile u32 HcPeriodicStart; 185 volatile u32 HcLSThreshold; 186 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; 196 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; 205 206 typedef volatile struct { 207 u32 config; 208 u32 tail_pointer; 209 u32 head_pointer; 210 u32 next_ed; 211 } __attribute__ ((packed)) ed_t; 212 #define ED_HALTED 1 213 #define ED_TOGGLE 2 214 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 223 224 typedef volatile struct { 225 u32 config; 226 u32 current_buffer_pointer; 227 u32 next_td; 228 u32 buffer_end; 229 } __attribute__ ((packed)) td_t; 230 /* 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 234 * purpose. 235 */ 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) 240 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 >= */ 258 259 #define OHCI_INST(controller) ((ohci_t*)((controller)->instance)) 260 261 typedef struct ohci { 262 opreg_t *opreg; 263 hcca_t *hcca; 264 usbdev_t *roothub; 265 ed_t *periodic_ed; 266 } ohci_t; 267 268 typedef enum { OHCI_SETUP=0, OHCI_OUT=1, OHCI_IN=2, OHCI_FROM_TD=3 } ohci_pid_t; 269 270 #endif 271