]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c
EmbeddedPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmbeddedPkg / Drivers / Isp1761UsbDxe / Isp1761UsbDxe.c
CommitLineData
dbfd80d8
OM
1/** @file\r
2\r
eff98cf9 3 Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>\r
dbfd80d8 4\r
878b807a 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
dbfd80d8
OM
6\r
7**/\r
8\r
dbfd80d8
OM
9#include <Library/DebugLib.h>\r
10#include <Library/UefiBootServicesTableLib.h>\r
11#include <Library/UefiDriverEntryPoint.h>\r
12#include <Library/IoLib.h>\r
13#include <Library/MemoryAllocationLib.h>\r
14\r
15#include <IndustryStandard/Usb.h>\r
16\r
17#include <Protocol/UsbDevice.h>\r
18\r
19#include "Isp1761UsbDxe.h"\r
20\r
21/*\r
22 Driver for using the NXP ISP1761 as a USB Peripheral controller.\r
23 Doesn't use USB OTG - just sets it in Pure Peripheral mode.\r
24\r
25 The ISP1582 datasheet has a little more info on the Peripheral controller\r
26 registers than the ISP1761 datasheet\r
27\r
28 We don't do string descriptors. They're optional.\r
29 We currently assume the device has one configuration, one interface, one IN\r
30 endpoint, and one OUT endpoint (plus the default control endpoint).\r
31\r
32 In fact, this driver is the minimum required to implement fastboot.\r
33*/\r
34\r
35// TODO Make sure the controller isn't sending empty packets when it shouldn't\r
36// (check behaviour in cases when Buffer Length isn't explcitly set)\r
37\r
38// ISP1582 Datasheet:\r
39// "Data transfers preceding the status stage must first be fully\r
40// completed before the STATUS bit can be set."\r
41// This variable stores whether some control data has been pended in the EP0TX\r
42// Tx buffer, so that when an EP0TX interrupt is received we can set the STATUS\r
43// bit to go to the Status stage of the control transfer.\r
44STATIC BOOLEAN mControlTxPending = FALSE;\r
45\r
46STATIC USB_DEVICE_DESCRIPTOR *mDeviceDescriptor;\r
47\r
48// The config descriptor, interface descriptor, and endpoint descriptors in a\r
49// buffer (in that order)\r
50STATIC VOID *mDescriptors;\r
51// Convenience pointers to those descriptors inside the buffer:\r
52STATIC USB_INTERFACE_DESCRIPTOR *mInterfaceDescriptor;\r
53STATIC USB_CONFIG_DESCRIPTOR *mConfigDescriptor;\r
54STATIC USB_ENDPOINT_DESCRIPTOR *mEndpointDescriptors;\r
55\r
56STATIC USB_DEVICE_RX_CALLBACK mDataReceivedCallback;\r
57STATIC USB_DEVICE_TX_CALLBACK mDataSentCallback;\r
58\r
59// The time between interrupt polls, in units of 100 nanoseconds\r
60// 10 Microseconds\r
61#define ISP1761_INTERRUPT_POLL_PERIOD 10000\r
62\r
63STATIC\r
64VOID\r
65SelectEndpoint (\r
66 IN UINT8 Endpoint\r
67 )\r
68{\r
69 // The DMA Endpoint Index must not point to the same as the\r
70 // Endpoint Index Register.\r
71 WRITE_REG32 (ISP1761_DMA_ENDPOINT_INDEX, ((Endpoint + 2) % ISP1761_NUM_ENDPOINTS));\r
72 WRITE_REG32 (ISP1761_ENDPOINT_INDEX, Endpoint);\r
73}\r
74\r
75// Enable going to the Data stage of a control transfer\r
76STATIC\r
77VOID\r
78DataStageEnable (\r
79 IN UINT8 Endpoint\r
80 )\r
81{\r
82 SelectEndpoint (Endpoint);\r
83 WRITE_REG32 (ISP1761_CTRL_FUNCTION, ISP1761_CTRL_FUNCTION_DSEN);\r
84}\r
85\r
86// Go to the Status stage of a successful control transfer\r
87STATIC\r
88VOID\r
89StatusAcknowledge (\r
90 IN UINT8 Endpoint\r
91)\r
92{\r
93 SelectEndpoint (Endpoint);\r
94 WRITE_REG32 (ISP1761_CTRL_FUNCTION, ISP1761_CTRL_FUNCTION_STATUS);\r
95}\r
96\r
97// Read the FIFO for the endpoint indexed by Endpoint, into the buffer pointed\r
98// at by Buffer, whose size is *Size bytes.\r
99//\r
100// If *Size is less than the number of bytes in the FIFO, return EFI_BUFFER_TOO_SMALL\r
101//\r
102// Update *Size with the number of bytes of data in the FIFO.\r
103STATIC\r
104EFI_STATUS\r
105ReadEndpointBuffer (\r
106 IN UINT8 Endpoint,\r
107 IN OUT UINTN *Size,\r
108 IN OUT VOID *Buffer\r
109 )\r
110{\r
111 UINT16 NumBytesAvailable;\r
112 UINT32 Val32;\r
113 UINTN Index;\r
114 UINTN NumBytesRead;\r
115\r
116 SelectEndpoint (Endpoint);\r
117\r
118 NumBytesAvailable = READ_REG16 (ISP1761_BUFFER_LENGTH);\r
119\r
120 if (NumBytesAvailable > *Size) {\r
121 *Size = NumBytesAvailable;\r
122 return EFI_BUFFER_TOO_SMALL;\r
123 }\r
124 *Size = NumBytesAvailable;\r
125\r
126 /* -- NB! --\r
127 The datasheet says the Data Port is 16 bits but it actually appears to\r
128 be 32 bits.\r
129 */\r
130\r
131 // Read 32-bit chunks\r
132 for (Index = 0; Index < NumBytesAvailable / 4; Index++) {\r
133 ((UINT32 *) Buffer)[Index] = READ_REG32 (ISP1761_DATA_PORT);\r
134 }\r
135\r
136 // Read remaining bytes\r
137\r
138 // Round NumBytesAvailable down to nearest power of 4\r
139 NumBytesRead = NumBytesAvailable & (~0x3);\r
140 if (NumBytesRead != NumBytesAvailable) {\r
141 Val32 = READ_REG32 (ISP1761_DATA_PORT);\r
142 // Copy each required byte of 32-bit word into buffer\r
143 for (Index = 0; Index < NumBytesAvailable % 4; Index++) {\r
144 ((UINT8 *) Buffer)[NumBytesRead + Index] = Val32 >> (Index * 8);\r
145 }\r
146 }\r
147 return EFI_SUCCESS;\r
148}\r
149\r
150/*\r
151 Write an endpoint buffer. Parameters:\r
152 Endpoint Endpoint index (see Endpoint Index Register in datasheet)\r
153 MaxPacketSize The MaxPacketSize this endpoint is configured for\r
154 Size The size of the Buffer\r
155 Buffer The data\r
156\r
157 Assumes MaxPacketSize is a multiple of 4.\r
158 (It seems that all valid values for MaxPacketSize _are_ multiples of 4)\r
159*/\r
160STATIC\r
161EFI_STATUS\r
162WriteEndpointBuffer (\r
163 IN UINT8 Endpoint,\r
164 IN UINTN MaxPacketSize,\r
165 IN UINTN Size,\r
166 IN CONST VOID *Buffer\r
167 )\r
168{\r
169 UINTN Index;\r
170 UINT32 *DwordBuffer;\r
171\r
172 DwordBuffer = (UINT32 *) Buffer;\r
173 SelectEndpoint (Endpoint);\r
174\r
175 /* -- NB! --\r
176 The datasheet says the Data Port is 16 bits but it actually appears to\r
177 be 32 bits.\r
178 */\r
179\r
180 // Write packets of size MaxPacketSize\r
181 while (Size > MaxPacketSize) {\r
182 for (Index = 0; Index < MaxPacketSize / 4; Index++) {\r
183 WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[Index]);\r
184 }\r
185 Size -= MaxPacketSize;\r
186 DwordBuffer += (MaxPacketSize / sizeof (UINT32));\r
187 }\r
188\r
189 // Write remaining data\r
190\r
191 if (Size > 0) {\r
192 WRITE_REG32 (ISP1761_BUFFER_LENGTH, Size);\r
193\r
194 while (Size > 4) {\r
195 WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[0]);\r
196 Size -= 4;\r
197 DwordBuffer++;\r
198 }\r
199\r
200 if (Size > 0) {\r
201 WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[0]);\r
202 }\r
203 }\r
204\r
205 return EFI_SUCCESS;\r
206}\r
207\r
208STATIC\r
209EFI_STATUS\r
210HandleGetDescriptor (\r
211 IN USB_DEVICE_REQUEST *Request\r
212 )\r
213{\r
214 EFI_STATUS Status;\r
215 UINT8 DescriptorType;\r
216 UINTN ResponseSize;\r
217 VOID *ResponseData;\r
218\r
219 ResponseSize = 0;\r
220 ResponseData = NULL;\r
221 Status = EFI_SUCCESS;\r
222\r
223 // Pretty confused if bmRequestType is anything but this:\r
224 ASSERT (Request->RequestType == USB_DEV_GET_DESCRIPTOR_REQ_TYPE);\r
225\r
226 // Choose the response\r
227 DescriptorType = Request->Value >> 8;\r
228 switch (DescriptorType) {\r
229 case USB_DESC_TYPE_DEVICE:\r
230 DEBUG ((EFI_D_INFO, "USB: Got a request for device descriptor\n"));\r
231 ResponseSize = sizeof (USB_DEVICE_DESCRIPTOR);\r
232 ResponseData = mDeviceDescriptor;\r
233 break;\r
234 case USB_DESC_TYPE_CONFIG:\r
235 DEBUG ((EFI_D_INFO, "USB: Got a request for config descriptor\n"));\r
236 ResponseSize = mConfigDescriptor->TotalLength;\r
237 ResponseData = mDescriptors;\r
238 break;\r
239 case USB_DESC_TYPE_STRING:\r
240 DEBUG ((EFI_D_INFO, "USB: Got a request for String descriptor %d\n", Request->Value & 0xFF));\r
241 break;\r
242 default:\r
243 DEBUG ((EFI_D_INFO, "USB: Didn't understand request for descriptor 0x%04x\n", Request->Value));\r
244 Status = EFI_NOT_FOUND;\r
245 break;\r
246 }\r
247\r
248 // Send the response\r
249 if (ResponseData) {\r
250 ASSERT (ResponseSize != 0);\r
251\r
252 if (Request->Length < ResponseSize) {\r
253 // Truncate response\r
254 ResponseSize = Request->Length;\r
255 } else if (Request->Length > ResponseSize) {\r
256 DEBUG ((EFI_D_INFO, "USB: Info: ResponseSize < wLength\n"));\r
257 }\r
258\r
259 DataStageEnable (ISP1761_EP0TX);\r
260 Status = WriteEndpointBuffer (\r
261 ISP1761_EP0TX,\r
262 MAX_PACKET_SIZE_CONTROL,\r
263 ResponseSize,\r
264 ResponseData\r
265 );\r
266 if (!EFI_ERROR (Status)) {\r
267 // Setting this value should cause us to go to the Status stage on the\r
268 // next EP0TX interrupt\r
269 mControlTxPending = TRUE;\r
270 }\r
271 }\r
272\r
273 return EFI_SUCCESS;\r
274}\r
275\r
276STATIC\r
277EFI_STATUS\r
278HandleSetAddress (\r
279 IN USB_DEVICE_REQUEST *Request\r
280 )\r
281{\r
282 // Pretty confused if bmRequestType is anything but this:\r
283 ASSERT (Request->RequestType == USB_DEV_SET_ADDRESS_REQ_TYPE);\r
284 // USB Spec: "The USB device does not change its device address until after\r
285 // the Status stage of this request is completed successfully."\r
286 // ISP1582 datasheet: "The new device address is activated when the\r
287 // device receives an acknowledgment from the host for the empty packet\r
288 // token". (StatusAcknowledge causes an empty packet to be sent).\r
289 // So, we write the Address register _before_ acking the SET_ADDRESS.\r
290 DEBUG ((EFI_D_INFO, "USB: Setting address to %d\n", Request->Value));\r
291 WRITE_REG32 (ISP1761_ADDRESS, Request->Value | ISP1761_ADDRESS_DEVEN);\r
292 StatusAcknowledge (ISP1761_EP0TX);\r
293\r
294 return EFI_SUCCESS;\r
295}\r
296\r
297// Move the device to the Configured state.\r
298// (This code only supports one configuration for a device, so the configuration\r
299// index is ignored)\r
300STATIC\r
301EFI_STATUS\r
302HandleSetConfiguration (\r
303 IN USB_DEVICE_REQUEST *Request\r
304 )\r
305{\r
306 USB_ENDPOINT_DESCRIPTOR *EPDesc;\r
307 UINTN Index;\r
308 UINT8 EndpointIndex;\r
309\r
310 ASSERT (Request->RequestType == USB_DEV_SET_CONFIGURATION_REQ_TYPE);\r
311 DEBUG ((EFI_D_INFO, "USB: Setting configuration.\n"));\r
312\r
313 // Configure endpoints\r
314 for (Index = 0; Index < mInterfaceDescriptor->NumEndpoints; Index++) {\r
315 EPDesc = &mEndpointDescriptors[Index];\r
316\r
317 // To simplify for now, assume endpoints aren't "sparse", and are in order.\r
318 ASSERT ((EPDesc->EndpointAddress & 0xF) == ((Index / 2) + 1));\r
319\r
320 // Convert from USB endpoint index to ISP1761 endpoint Index\r
321 // USB: Endpoint number is bits [3:0], IN/OUT is bit [7]\r
322 // ISP1761: Endpoint number is bits [4:1], IN/OUT is bit [0]\r
323 EndpointIndex = ((EPDesc->EndpointAddress & 0xF) << 1) |\r
324 ((EPDesc->EndpointAddress & BIT7) >> 7);\r
325 SelectEndpoint (EndpointIndex);\r
326 // Set endpoint type (Bulk/Isochronous/Interrupt)\r
327 WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, EPDesc->MaxPacketSize);\r
328 // Hardware foible (bug?): Although the datasheet seems to suggest it should\r
329 // automatically be set to MaxPacketSize, the Buffer Length register appears\r
330 // to be reset to 0, which causes an empty packet to be sent in response to\r
331 // the first IN token of the session. The NOEMPKT field of the Endpoint Type\r
332 // register sounds like it might fix this problem, but it doesn't\r
333 // (it's "applicable only in the DMA mode").\r
334 WRITE_REG32 (ISP1761_BUFFER_LENGTH, EPDesc->MaxPacketSize);\r
335 WRITE_REG32 (ISP1761_ENDPOINT_TYPE, (EPDesc->Attributes & 0x3) |\r
336 ISP1761_ENDPOINT_TYPE_ENABLE);\r
337 }\r
338\r
339 StatusAcknowledge (ISP1761_EP0TX);\r
340 return EFI_SUCCESS;\r
341}\r
342\r
343STATIC\r
344EFI_STATUS\r
345HandleDeviceRequest (\r
346 IN USB_DEVICE_REQUEST *Request\r
347 )\r
348{\r
349 EFI_STATUS Status;\r
350\r
351 Status = EFI_SUCCESS;\r
352\r
353 switch (Request->Request) {\r
354 case USB_DEV_GET_DESCRIPTOR:\r
355 Status = HandleGetDescriptor (Request);\r
356 break;\r
357 case USB_DEV_SET_ADDRESS:\r
358 Status = HandleSetAddress (Request);\r
359 break;\r
360 case USB_DEV_SET_CONFIGURATION:\r
361 Status = HandleSetConfiguration (Request);\r
362 break;\r
363 default:\r
364 DEBUG ((EFI_D_ERROR,\r
365 "Didn't understand RequestType 0x%x Request 0x%x\n",\r
366 Request->RequestType, Request->Request));\r
367 Status = EFI_INVALID_PARAMETER;\r
368 break;\r
369 }\r
370\r
371 return Status;\r
372}\r
373\r
374// Instead of actually registering interrupt handlers, we poll the controller's\r
375// interrupt source register in this function.\r
376STATIC\r
377VOID\r
378CheckInterrupts (\r
379 IN EFI_EVENT Event,\r
380 IN VOID *Context\r
381 )\r
382{\r
383 UINT32 DcInterrupts;\r
384 UINTN NumBytes;\r
385 UINTN MoreBytes;\r
386 UINT8 Packet[512];\r
387 VOID *DataPacket;\r
388 UINT32 HandledInterrupts;\r
389 UINT32 UnhandledInterrupts;\r
390 EFI_STATUS Status;\r
391\r
392 // Set bits in HandledInterrupts to mark the interrupt source handled.\r
393 HandledInterrupts = 0;\r
394\r
395 WRITE_REG32 (ISP1761_DEVICE_UNLOCK, ISP1761_DEVICE_UNLOCK_MAGIC);\r
396\r
397 DcInterrupts = READ_REG32 (ISP1761_DC_INTERRUPT);\r
398 if (DcInterrupts & ISP1761_DC_INTERRUPT_SUSP) {\r
399 DEBUG ((EFI_D_INFO, "USB: Suspend\n"));\r
400 HandledInterrupts |= ISP1761_DC_INTERRUPT_SUSP;\r
401 }\r
402 if (DcInterrupts & ISP1761_DC_INTERRUPT_RESUME) {\r
403 DEBUG ((EFI_D_INFO, "USB: Resume\n"));\r
404 HandledInterrupts |= ISP1761_DC_INTERRUPT_RESUME;\r
405 }\r
406 if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0SETUP) {\r
407 NumBytes = 512;\r
408 ReadEndpointBuffer (0x20, &NumBytes, &Packet);\r
409 ASSERT (NumBytes == 8);\r
410 HandleDeviceRequest ((USB_DEVICE_REQUEST *) Packet);\r
411 HandledInterrupts |= ISP1761_DC_INTERRUPT_EP0SETUP;\r
412 }\r
413 if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0RX) {\r
414 HandledInterrupts |= ISP1761_DC_INTERRUPT_EP0RX;\r
415 }\r
416 if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0TX) {\r
417 if (mControlTxPending) {\r
418 // We previously put some data in the Control Endpoint's IN (Tx) FIFO.\r
419 // We assume that that data has now been sent in response to the IN token\r
420 // that triggered this interrupt. We can therefore go to the Status stage\r
421 // of the control transfer.\r
422 StatusAcknowledge (ISP1761_EP0TX);\r
423 mControlTxPending = FALSE;\r
424 }\r
425 HandledInterrupts |= ISP1761_DC_INTERRUPT_EP0TX;\r
426 }\r
427 if (DcInterrupts & ISP1761_DC_INTERRUPT_EP1RX) {\r
428 NumBytes = 512;\r
429 DataPacket = AllocatePool (NumBytes);\r
430 Status = ReadEndpointBuffer (ISP1761_EP1RX, &NumBytes, DataPacket);\r
431 if (EFI_ERROR (Status) || NumBytes == 0) {\r
432 if (EFI_ERROR (Status)) {\r
433 DEBUG ((EFI_D_ERROR, "Couldn't read EP1RX data: %r\n", Status));\r
434 }\r
435 FreePool (DataPacket);\r
436 } else {\r
437 // Signal this event again so we poll again ASAP\r
438 gBS->SignalEvent (Event);\r
439 mDataReceivedCallback (NumBytes, DataPacket);\r
440 }\r
441 HandledInterrupts |= ISP1761_DC_INTERRUPT_EP1RX;\r
442 }\r
443 if (DcInterrupts & ISP1761_DC_INTERRUPT_EP1TX) {\r
444 mDataSentCallback (1);\r
445 HandledInterrupts |= ISP1761_DC_INTERRUPT_EP1TX;\r
446 }\r
447 if (DcInterrupts & (ISP1761_DC_INTERRUPT_SOF | ISP1761_DC_INTERRUPT_PSOF)) {\r
448 // Don't care about SOFs or pseudo-SOFs\r
449 HandledInterrupts |= (ISP1761_DC_INTERRUPT_SOF | ISP1761_DC_INTERRUPT_PSOF);\r
450 }\r
451 if (ISP1761_DC_INTERRUPT_BRESET) {\r
452 HandledInterrupts |= ISP1761_DC_INTERRUPT_BRESET;\r
453 }\r
454 if (ISP1761_DC_INTERRUPT_HS_STAT) {\r
455 HandledInterrupts |= ISP1761_DC_INTERRUPT_HS_STAT;\r
456 }\r
457 if (ISP1761_DC_INTERRUPT_VBUS) {\r
458 HandledInterrupts |= ISP1761_DC_INTERRUPT_VBUS;\r
459 }\r
460\r
461 UnhandledInterrupts = DcInterrupts & (~HandledInterrupts) & ISP1761_DC_INTERRUPT_MASK;\r
462 if (UnhandledInterrupts) {\r
463 DEBUG ((EFI_D_ERROR, "USB: Unhandled DC Interrupts: 0x%08x\n",\r
464 UnhandledInterrupts));\r
465 }\r
466\r
467 // Check if we received any more data while we were handling the interrupt.\r
468 SelectEndpoint (ISP1761_EP1RX);\r
469 MoreBytes = READ_REG16 (ISP1761_BUFFER_LENGTH);\r
470 if (MoreBytes) {\r
471 HandledInterrupts &= ~ISP1761_DC_INTERRUPT_EP1RX;\r
472 }\r
473\r
474 WRITE_REG32 (ISP1761_DC_INTERRUPT, HandledInterrupts);\r
475}\r
476\r
477EFI_STATUS\r
478Isp1761PeriphSend (\r
479 IN UINT8 EndpointIndex,\r
480 IN UINTN Size,\r
481 IN CONST VOID *Buffer\r
482 )\r
483{\r
484 return WriteEndpointBuffer (\r
485 (EndpointIndex << 1) | 0x1, //Convert to ISP1761 endpoint index, Tx\r
486 MAX_PACKET_SIZE_BULK,\r
487 Size,\r
488 Buffer\r
489 );\r
490}\r
491\r
492EFI_STATUS\r
493EFIAPI\r
494Isp1761PeriphStart (\r
495 IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor,\r
496 IN VOID **Descriptors,\r
497 IN USB_DEVICE_RX_CALLBACK RxCallback,\r
498 IN USB_DEVICE_TX_CALLBACK TxCallback\r
499 )\r
500{\r
501 UINT16 OtgStatus;\r
502 UINT8 *Ptr;\r
503 EFI_STATUS Status;\r
504 EFI_EVENT TimerEvent;\r
505\r
506 ASSERT (DeviceDescriptor != NULL);\r
507 ASSERT (Descriptors[0] != NULL);\r
508 ASSERT (RxCallback != NULL);\r
509 ASSERT (TxCallback != NULL);\r
510\r
511 WRITE_REG32 (ISP1761_DEVICE_UNLOCK, ISP1761_DEVICE_UNLOCK_MAGIC);\r
512\r
513 WRITE_REG32 (ISP1761_SW_RESET_REG, ISP1761_SW_RESET_ALL);\r
514 while (READ_REG32 (ISP1761_SW_RESET_REG) & ISP1761_SW_RESET_ALL) {\r
515 //busy wait\r
516 }\r
517 WRITE_REG32 (ISP1761_MODE, ISP1761_MODE_SFRESET);\r
518 while (READ_REG32 (ISP1761_MODE) & ISP1761_MODE_SFRESET) {\r
519 //busy wait\r
520 }\r
521 DEBUG ((EFI_D_INFO, "USB: Software reset done\n"));\r
522\r
523 WRITE_REG32 (ISP1761_DC_INTERRUPT_ENABLE, 0x03FFFFFF);\r
524 WRITE_REG32 (ISP1761_OTG_INTERRUPT_ENABLE_RISE, 0x07FF);\r
525\r
526 WRITE_REG8 (ISP1761_ADDRESS, ISP1761_ADDRESS_DEVEN);\r
527 WRITE_REG8 (ISP1761_MODE, ISP1761_MODE_WKUPCS | ISP1761_MODE_CLKAON);\r
528\r
529 // Use port 1 as peripheral controller (magic - disagrees with datasheet)\r
530 WRITE_REG32 (ISP1761_OTG_CTRL_SET, 0xffff0000);\r
531 WRITE_REG32 (ISP1761_OTG_CTRL_SET, 0x000014d1);\r
532\r
533 OtgStatus = READ_REG16 (ISP1761_OTG_STATUS);\r
534 if ((OtgStatus & ISP1761_OTG_STATUS_B_SESS_END) != 0) {\r
535 DEBUG ((EFI_D_ERROR, "USB: Vbus not powered.\n"));\r
536 }\r
537 if ((OtgStatus & ISP1761_OTG_STATUS_A_B_SESS_VLD) == 0) {\r
538 DEBUG ((EFI_D_ERROR, "USB: Session not valid.\n"));\r
539 }\r
540\r
541 // Configure Control endpoints\r
542 SelectEndpoint (0x20);\r
543 WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL);\r
544 WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE);\r
545 SelectEndpoint (0x0);\r
546 WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL);\r
547 WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE);\r
548 SelectEndpoint (0x1);\r
549 WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL);\r
550 WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE);\r
551\r
552 // Interrupt on all ACK and NAK\r
553 WRITE_REG32 (ISP1761_INTERRUPT_CONFIG, ISP1761_INTERRUPT_CONFIG_ACK_ONLY);\r
554\r
555 mDeviceDescriptor = DeviceDescriptor;\r
556 mDescriptors = Descriptors[0];\r
557\r
558 // Right now we just support one configuration\r
559 ASSERT (mDeviceDescriptor->NumConfigurations == 1);\r
560 // ... and one interface\r
561 mConfigDescriptor = (USB_CONFIG_DESCRIPTOR *)mDescriptors;\r
562 ASSERT (mConfigDescriptor->NumInterfaces == 1);\r
563\r
564 Ptr = ((UINT8 *) mDescriptors) + sizeof (USB_CONFIG_DESCRIPTOR);\r
565 mInterfaceDescriptor = (USB_INTERFACE_DESCRIPTOR *) Ptr;\r
566 Ptr += sizeof (USB_INTERFACE_DESCRIPTOR);\r
567\r
568 mEndpointDescriptors = (USB_ENDPOINT_DESCRIPTOR *) Ptr;\r
569\r
570 mDataReceivedCallback = RxCallback;\r
571 mDataSentCallback = TxCallback;\r
572\r
573 // Register a timer event so CheckInterupts gets called periodically\r
574 Status = gBS->CreateEvent (\r
575 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
576 TPL_CALLBACK,\r
577 CheckInterrupts,\r
578 NULL,\r
579 &TimerEvent\r
580 );\r
581 ASSERT_EFI_ERROR (Status);\r
582 if (EFI_ERROR (Status)) {\r
583 return Status;\r
584 }\r
585\r
586 Status = gBS->SetTimer (\r
587 TimerEvent,\r
588 TimerPeriodic,\r
589 ISP1761_INTERRUPT_POLL_PERIOD\r
590 );\r
591 ASSERT_EFI_ERROR (Status);\r
592\r
593 return Status;\r
594}\r
595\r
596USB_DEVICE_PROTOCOL mUsbDevice = {\r
597 Isp1761PeriphStart,\r
598 Isp1761PeriphSend\r
599};\r
600\r
601\r
602EFI_STATUS\r
603EFIAPI\r
604Isp1761PeriphEntryPoint (\r
605 IN EFI_HANDLE ImageHandle,\r
606 IN EFI_SYSTEM_TABLE *SystemTable\r
607 )\r
608{\r
609 UINT32 DeviceId;\r
610 EFI_HANDLE Handle;\r
611\r
612 DeviceId = READ_REG32 (ISP1761_DEVICE_ID);\r
613\r
614 if (DeviceId != ISP1761_DEVICE_ID_VAL) {\r
615 DEBUG ((EFI_D_ERROR,\r
616 "ERROR: Read incorrect device ID for ISP1761: 0x%08x, expected 0x%08x\n",\r
617 DeviceId , ISP1761_DEVICE_ID_VAL\r
618 ));\r
619 return EFI_DEVICE_ERROR;\r
620 }\r
621\r
622 Handle = NULL;\r
623 return gBS->InstallProtocolInterface (\r
624 &Handle,\r
625 &gUsbDeviceProtocolGuid,\r
626 EFI_NATIVE_INTERFACE,\r
627 &mUsbDevice\r
628 );\r
629}\r