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