blob: ab678ce4494ab8404156ba8e0856e5c02e246be6 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2 *
3 * (C)Copyright 2013 Marvell. All Rights Reserved.
4 *
5 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
6 * The copyright notice above does not evidence any actual or intended
7 * publication of such source code.
8 * This Module contains Proprietary Information of Marvell and should be
9 * treated as Confidential.
10 * The information in this file is provided for the exclusive use of the
11 * licensees of Marvell.
12 * Such users have the right to use, modify, and incorporate this code into
13 * products for purposes authorized by the license agreement provided they
14 * include this notice and the associated copyright notice with any such
15 * product.
16 * The information in this file is provided "AS IS" without warranty.
17 *
18 ******************************************************************************/
19
20
21#include "Typedef.h"
22#include "misc.h"
23#include "timer.h"
24#include "usb_descriptors.h"
25#include "usb2_main.h"
26#include "usb2_memory.h"
27#include "usb2_enumeration.h"
28#include "ProtocolManager.h"
29
30UINT_T USB2D_Initialize(UINT base_address, UINT int_number)
31{
32 P_DC_Properties_T pDCProps;
33#if !USB_DEVICE_ONLY
34 UINT session;
35#endif
36 //Try and get a new USB 2 'Object'
37 pDCProps = Allocate_USB2_Device(int_number);
38
39 //Check for error
40 if(pDCProps == NULL)
41 return NotFoundError; //mdb make new error code
42
43 //store the base_address
44 pDCProps->pUSBRegs = (P_USB2Device_Regs_T) base_address;
45
46 //reset and restore the controller
47 USB2D_Controller_Setup(pDCProps);
48
49 //setup EP 0
50 USB2D_Endpoint_Setup(pDCProps, USB_ENDPOINT_0, USB_IN, USB_CNTRL);
51 USB2D_Endpoint_Setup(pDCProps, USB_ENDPOINT_0, USB_OUT, USB_CNTRL);
52
53 //device only: there is no OTGSC register, so we cannot check B/A session valid bits
54#if USB_DEVICE_ONLY
55 //no way to check if a device is connect. assume it is and hit the RUN bit
56 reg_bit_set(&pDCProps->pUSBRegs->USB_CMD, BIT0);
57#else
58
59 //are we A or B device?
60 session = (pDCProps->pUSBRegs->OTGSC & BIT8) >> 8;
61
62 //is the session (A or B) valid?
63 if(pDCProps->pUSBRegs->OTGSC & (BIT10 << session))
64 { // -yes- set run bit
65 reg_bit_set(&pDCProps->pUSBRegs->USB_CMD, BIT0);
66 }
67 else
68 { // -no- set session INT bit
69 reg_bit_set(&pDCProps->pUSBRegs->OTGSC, (BIT26 << session));
70 }
71#endif
72
73 return NoError;
74}
75
76void USB2D_Shutdown(UINT intnum)
77{
78 UINT32 start_time;
79 P_DC_Properties_T pDCProps = Get_DC_Properties(intnum);
80
81 //bogus input. caller screwed up. return
82 if (pDCProps == NULL)
83 return;
84
85 //First check for any primed endpoint and wait a short time for them to complete
86 start_time = GetOSCR0();
87 while(pDCProps->pUSBRegs->ENDPTSTATUS)
88 {
89 if(OSCR0IntervalInMilli(start_time, GetOSCR0()) > USB2D_SHUTDOWN_TIME_MS)
90 break; //timed out. break from loop
91 }
92
93 //Second, check for any remaining endpoint activity and flush it
94 if(pDCProps->pUSBRegs->ENDPTSTATUS)
95 pDCProps->pUSBRegs->ENDPTFLUSH = pDCProps->pUSBRegs->ENDPTSTATUS;
96
97 //third, clear up the controller
98 //Reset the usb address
99 reg_write(&pDCProps->pUSBRegs->DEVICE_ADDR, BIT24);
100 //clear the EP SETUP statuses (stati?)
101 reg_write(&pDCProps->pUSBRegs->ENDPT_SETUP_STAT, 0xFFFF);
102 //clear any complete bits
103 reg_write(&pDCProps->pUSBRegs->ENDPTCOMPLETE, 0xFFFFFFFF);
104 //make sure to clear ALL status bits (write 1 to clear register)
105 pDCProps->pUSBRegs->USB_STS |= 1;
106 //disable individual status enables
107 pDCProps->pUSBRegs->USB_INTR = 0;
108
109 //lastly, shut off the controller
110 reg_bit_clr(&pDCProps->pUSBRegs->USB_CMD, BIT0);
111}
112
113void USB2D_ISR(UINT intnum)
114{
115 UINT status_bits;
116 P_DC_Properties_T pDCProps = Get_DC_Properties(intnum);
117
118 //bogus input. caller screwed up. return
119 if (pDCProps == NULL)
120 return;
121
122#if !USB_DEVICE_ONLY
123 //check and see if A or B session triggered the interrupt
124 if( pDCProps->pUSBRegs->OTGSC & (BIT19 | BIT18) )
125 { //clear the session interrupts
126 reg_bit_clr(&pDCProps->pUSBRegs->OTGSC, (BIT26 | BIT27));
127 //hit GO on the controller
128 reg_bit_set(&pDCProps->pUSBRegs->USB_CMD, BIT0);
129 return;
130 }
131#endif
132
133 //read the status bits and clear them
134 status_bits = pDCProps->pUSBRegs->USB_STS;
135 pDCProps->pUSBRegs->USB_STS |= status_bits;
136
137 //Normal Interrupt
138 if(status_bits & USB2D_INT_STS_INT)
139 {
140 //Check for transaction complete ints
141 if(pDCProps->pUSBRegs->ENDPTCOMPLETE)
142 USB2D_Complete_Int(pDCProps);
143
144 //Check for any Setup Ints
145 if(pDCProps->pUSBRegs->ENDPT_SETUP_STAT) {
146 if (pDCProps->pUSBRegs->PORTSC & (BIT26 | BIT27) == 0x0)
147 UpdateUSBFsDeviceConfigDesc();
148 USB2D_Setup_Int(pDCProps);
149 }
150 }
151
152 //Reset Interrupt
153 if(status_bits & USB2D_INT_STS_RESET)
154 USB2D_Reset_Int(pDCProps);
155}
156
157
158void USB2D_Controller_Setup(P_DC_Properties_T pDCProps)
159{
160 UINT start_time;
161
162 reg_bit_clr(&pDCProps->pUSBRegs->USB_CMD, BIT0); //STOP the controller
163 reg_bit_set(&pDCProps->pUSBRegs->USB_CMD, BIT1); //RESET the controller
164
165 //wait a bit for RESET bit to clear
166 start_time = GetOSCR0();
167 while( (pDCProps->pUSBRegs->USB_CMD & BIT1) == BIT1)
168 {
169 if(OSCR0IntervalInMilli(start_time, GetOSCR0()) > USB2D_CTRL_RESET_TIME_MS)
170 break; //timed out. break from loop
171 }
172
173 //set mode: DEVICE + SLOM
174 reg_write(&pDCProps->pUSBRegs->USB_MODE, BIT3 | BIT1);
175
176 //clear Endpoint Setup Status (Write 1 to clear)
177 reg_write(&pDCProps->pUSBRegs->ENDPT_SETUP_STAT, 0xFFFF);
178
179#if FORCE_FULL_SPEED_USB && !SLE_TESTING
180 //force FULL SPEED: Port Control PFSC
181 reg_bit_set(&pDCProps->pUSBRegs->PORTSC, BIT24);
182#endif
183
184 //store the Queue Head pointer into the List Register
185 pDCProps->pUSBRegs->EP_LIST_ADDR = ((UINT)pDCProps->pdQHHead) & 0xFFFFF800; //mask off lower 11 bits
186
187 //Reset Endpoint 0 RX and TX
188 reg_bit_set(&pDCProps->pUSBRegs->ENDPTCTRLX[0], BIT22 | BIT6);
189
190 //Clear the stall fields for Endpoint 0
191 reg_bit_clr(&pDCProps->pUSBRegs->ENDPTCTRLX[0], BIT16 | BIT0);
192
193 //Set the value USB Interrupts: Reset and USB Int
194 reg_bit_set(&pDCProps->pUSBRegs->USB_INTR, USB2D_INT_STS_INT | USB2D_INT_STS_PORT_CHANGE | USB2D_INT_STS_RESET);
195
196 //Clear any latent status bits (Write 1 to clear)
197 reg_bit_set(&pDCProps->pUSBRegs->USB_STS, USB2D_INT_STS_INT | USB2D_INT_STS_PORT_CHANGE | USB2D_INT_STS_RESET);
198
199 return;
200}
201
202
203//Configures an endpoint
204void USB2D_Endpoint_Setup(P_DC_Properties_T pDCProps, XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T direction, XLLP_USB_EP_TYPE_T type)
205{
206 UINT shift_amt;
207
208 //get the corresponding dQH
209 P_dQH_T pQH = (P_dQH_T)&(pDCProps->pdQHHead[ep_num*2+direction]);
210
211 //initialize the QH
212 pQH->dTD_Overlay.pNext_dTD = BIT0; //set the STOP bit for all QHs
213
214 //type specific settings
215 if(type == USB_BULK)
216 {
217 pQH->EP_Caps.MaxPacketLen = (pDCProps->pUSBRegs->PORTSC & BIT27) ? 512 : 64; //initialize packet size based on speed
218 pQH->EP_Caps.ZLT = 1; //zero length terminate
219 }
220 if(type == USB_CNTRL)
221 {
222 pQH->EP_Caps.MaxPacketLen = 64; //initialize packet size based on type
223 pQH->EP_Caps.IOS = 1; //set the IOS bit
224 }
225
226 //set the ENABLE + TYPE fields
227 shift_amt = (direction == USB_IN) ? 16 : 0; //helper to sort out RX/TX
228 reg_bit_clr(&pDCProps->pUSBRegs->ENDPTCTRLX[ep_num], 0xFFFF << shift_amt);
229 reg_bit_set(&pDCProps->pUSBRegs->ENDPTCTRLX[ep_num], ((type << 2) | BIT7 | BIT6) << shift_amt);
230
231 //for the other half of the EP, the TYPE must get changed to BULK (only if *not* enabled)
232 shift_amt = (direction == USB_IN) ? 0 : 16; //swap since checking other side
233 if (!( pDCProps->pUSBRegs->ENDPTCTRLX[ep_num] & (BIT7 << shift_amt) ))
234 { reg_bit_clr(&pDCProps->pUSBRegs->ENDPTCTRLX[ep_num], 0xC << shift_amt);
235 reg_bit_set(&pDCProps->pUSBRegs->ENDPTCTRLX[ep_num], USB_BULK << (2+shift_amt));
236 }
237}
238
239
240//reset interrupt handler
241void USB2D_Reset_Int(P_DC_Properties_T pDCProps)
242{
243 //Flush all EPs
244 reg_write(&pDCProps->pUSBRegs->ENDPTFLUSH, 0xFFFFFFFF);
245
246 //Reset the usb address
247 reg_write(&pDCProps->pUSBRegs->DEVICE_ADDR, BIT24);
248
249 //clear the EP SETUP statuses (stati?)
250 reg_write(&pDCProps->pUSBRegs->ENDPT_SETUP_STAT, 0xFFFF);
251
252 //clear any complete bits
253 reg_write(&pDCProps->pUSBRegs->ENDPTCOMPLETE, 0xFFFFFFFF);
254
255 //Lastly, reset EP0
256 USB2D_Endpoint_Setup(pDCProps, USB_ENDPOINT_0, USB_OUT, USB_CNTRL);
257 USB2D_Endpoint_Setup(pDCProps, USB_ENDPOINT_0, USB_IN, USB_CNTRL);
258}
259
260//endpoint setup interrupt handler - means an endpoint received a SETUP packet
261void USB2D_Setup_Int(P_DC_Properties_T pDCProps)
262{
263 UINT status_bits;
264 XLLP_USB_SETUP_DATA_T setup_packet;
265
266 //read the status bits
267 status_bits = pDCProps->pUSBRegs->ENDPT_SETUP_STAT;
268
269 //Clear all other Setup packets (we only handles Setup packets on EP0!)
270 reg_bit_set(&pDCProps->pUSBRegs->ENDPT_SETUP_STAT, 0xFFFE);
271
272 //Check for EP0 Setup packet
273 if(status_bits & BIT0)
274 {
275 //read the 8 setup bytes into the variable (all stuff inside '[]' will equal 0)
276 memcpy(&setup_packet, &pDCProps->pdQHHead[USB_ENDPOINT_0*2+USB_OUT].Setup, 8);
277
278 //make sure to clear the SETUP STATUS bit for EP0
279 reg_bit_set(&pDCProps->pUSBRegs->ENDPT_SETUP_STAT, BIT0);
280
281 //call the handler to deal with the new packet
282 USB2D_EnumerationHandler(pDCProps, &setup_packet);
283 }
284}
285
286//endpoint complete interrupt handler - means a dTD finish (IOC bit)
287void USB2D_Complete_Int(P_DC_Properties_T pDCProps)
288{
289 UINT counter, index;
290 UINT complete_bits;
291
292 //Read the EP Complete bits, then write 1 to clear them
293 complete_bits = pDCProps->pUSBRegs->ENDPTCOMPLETE;
294 pDCProps->pUSBRegs->ENDPTCOMPLETE = complete_bits;
295
296 //for each complete bit reset the QH and clear the used dTD chain
297 for(counter = 0; counter < (2*MAX_USB2_EPS); counter++)
298 { //check for a complete bit and only then do the releasing
299 if( (1 << counter) & complete_bits)
300 { //find the correct QH index
301 index = (counter > 15) ? (counter - 16) * 2 + 1 : counter * 2;
302
303 //now, make sure this isn't a false interrupt (check the status of the dToken)
304 if(pDCProps->pdQHHead[index].dTD_Overlay.dTDToken.Status & BIT7)
305 { //false interrupt signature.
306 //ignore EPCOMPLETE for this EP
307 complete_bits &= ~(1 << counter);
308 }
309 else //real IOC interrupt
310 { //find the dTD chain and release it back
311 ReleasedTDChain((P_dTD_T)(pDCProps->pdQHHead[index].initial_dTD));
312 }
313
314 //update size counter for the last packet being a short packet
315 pDCProps->pdQHHead[index].tot_size -= pDCProps->pdQHHead[index].dTD_Overlay.dTDToken.Size;
316 }
317 }
318
319 //Endpoint 2 RX serve call here
320 if(complete_bits & BIT2)
321 USB2D_PM_Call(pDCProps);
322
323}
324
325void USB2D_PM_Call(P_DC_Properties_T pDCProps)
326{
327 UINT bytes, buffer;
328 P_USBAPI_T pUsbApi;
329
330 //grab info from the last RECEIVE operation
331 pUsbApi = GetUSBAPIhandle_InterruptNum(pDCProps->InterruptNum);
332 if (pUsbApi != NULL)
333 {
334 bytes = pDCProps->pdQHHead[USB_ENDPOINT_B*2].tot_size;
335 buffer = pDCProps->pdQHHead[USB_ENDPOINT_B*2].buffer;
336
337 //call into Protocol Manager
338 PM_ISR(pUsbApi, bytes, (UINT*)buffer);
339 }
340}
341
342void USB2D_SendWrapper(UINT *buffer, UINT size, void * pUSBAPI)
343{
344 P_DC_Properties_T pDCProps;
345
346 //get the correct structure
347 pDCProps = Get_DC_Properties(((P_USBAPI_T)pUSBAPI)->interruptNum);
348 if (pDCProps != NULL)
349 {
350 //call the trasmit routine
351 USB2D_EndpointTransmit(pDCProps, USB_ENDPOINT_A, USB_IN, (UINT)buffer, size);
352 }
353 return;
354}
355
356void USB2D_RecieveWrapper(UINT *buffer, UINT size, void * pUSBAPI)
357{
358 P_DC_Properties_T pDCProps;
359
360 //get the correct structure
361 pDCProps = Get_DC_Properties(((P_USBAPI_T)pUSBAPI)->interruptNum);
362 if (pDCProps != NULL)
363 {
364 //call the trasmit routine
365 USB2D_EndpointTransmit(pDCProps, USB_ENDPOINT_B, USB_OUT, (UINT)buffer, size);
366 }
367 return;
368}
369
370void USB2D_EndpointTransmit(P_DC_Properties_T pDCProps, XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T direction, UINT buffer, UINT size)
371{
372 UINT qh_index, packet_size, dtd_size;
373 P_dTD_T pdTD, pdTD_first, pdTD_next;
374
375 //calculate which Queue Head to service
376 qh_index = ep_num*2+direction;
377
378 //find our packet size
379 packet_size = pDCProps->pdQHHead[qh_index].EP_Caps.MaxPacketLen;;
380
381 //grab an initial dTD
382 pdTD_first = pdTD = GetdTD();
383
384 //check for memory shortage
385 if(pdTD == NULL)
386 {
387 obm_printf("there is no dTD\n\r");
388 return;
389 }
390
391 //save off info for software cleanup later on
392 pDCProps->pdQHHead[qh_index].initial_dTD = (UINT_T)(pdTD_first);
393 pDCProps->pdQHHead[qh_index].buffer = (UINT)buffer;
394 pDCProps->pdQHHead[qh_index].tot_size = 0; //will be updated in the loop below
395
396 //now lets build our dTD chain
397 do
398 {
399 //adjust the size for this dTD
400 dtd_size = (size > MAX_LENGTH_TRANSFER) ? MAX_LENGTH_TRANSFER : size;
401
402 //input buffer
403 pdTD->BuffPtr[0] = (UINT)buffer;
404 pdTD->BuffPtr[1] = pdTD->BuffPtr[0] + 4096;
405 pdTD->BuffPtr[2] = pdTD->BuffPtr[1] + 4096;
406 pdTD->BuffPtr[3] = pdTD->BuffPtr[2] + 4096;
407 pdTD->BuffPtr[4] = pdTD->BuffPtr[3] + 4096;
408
409 //adjust counters
410 buffer += dtd_size;
411 size -= dtd_size;
412 pDCProps->pdQHHead[qh_index].tot_size += dtd_size;
413
414 //input size
415 pdTD->dTDToken.Size = dtd_size;
416
417 //set the dTD as active
418 pdTD->dTDToken.Status = 0x80;
419
420 //do we need to chain some descriptors?
421 if(size > 0)
422 {
423 //Grab a new dTD (only if needed)
424 pdTD_next = GetdTD();
425
426 //check for memory shortage
427 if(pdTD_next == NULL)
428 break;
429
430 //link the dTDs
431 pdTD->pNext_dTD = (UINT)pdTD_next;
432
433 //update dTD pointer
434 pdTD = pdTD_next;
435 }
436 }
437 while(size);
438
439 //for the LAST dTD, we need to set the stop bit and Interrupt on Complete
440 pdTD->pNext_dTD = BIT0;
441 pdTD->dTDToken.IOC = 1;
442
443 //link the FIRST dTD pointer to the Queue Head
444 pDCProps->pdQHHead[ep_num*2+direction].dTD_Overlay.pNext_dTD = (UINT)pdTD_first;
445
446 //make sure memory operation is finished before prime
447 dsb();
448
449 //lastly prime the endpoint
450 pDCProps->pUSBRegs->ENDPTPRIME = 0x1 << (ep_num + direction*16);
451}
452
453
454