]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkSouthCluster / Sdio / Dxe / SDControllerDxe / SDController.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2\r
3The SD host controller driver model and HC protocol routines.\r
4\r
5Copyright (c) 2013-2015 Intel Corporation.\r
6\r
7This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17\r
18\r
19#include "SDController.h"\r
20\r
21\r
22EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding = {\r
23 SDControllerSupported,\r
24 SDControllerStart,\r
25 SDControllerStop,\r
26 0x20,\r
27 NULL,\r
28 NULL\r
29};\r
30\r
31\r
32EFI_SD_HOST_IO_PROTOCOL mSDHostIo = {\r
33 EFI_SD_HOST_IO_PROTOCOL_REVISION_01,\r
34 {\r
35 0, // HighSpeedSupport\r
36 0, // V18Support\r
37 0, // V30Support\r
38 0, // V33Support\r
39 0, // Reserved0\r
40 0, // BusWidth4\r
41 0, // BusWidth8\r
42 0, // Reserved1\r
43 0, // Reserved1\r
44 (512 * 1024) //BoundarySize\r
45 },\r
46 SendCommand,\r
47 SetClockFrequency,\r
48 SetBusWidth,\r
49 SetHostVoltage,\r
50 ResetSDHost,\r
51 EnableAutoStopCmd,\r
52 DetectCardAndInitHost,\r
53 SetBlockLength,\r
54 SetHighSpeedMode,\r
55 SetDDRMode\r
56};\r
57\r
58/**\r
59 Find sdclk_freq_sel and upr_sdclk_freq_sel bits\r
60 for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit\r
61 divided clock mode.\r
62\r
63 @param BaseClockFreg Base Clock Frequency in Hz For SD Clock in the\r
64 Capabilities register.\r
65 @param TargetFreq Target Frequency in Hz to reach.\r
66 @param Is8BitMode True if 8-bit Divided Clock Mode else 10bit mode.\r
67 @param Bits sdclk_freq_sel and upr_sdclk_freq_sel bits for\r
68 TargetFreq.\r
69\r
70 @return EFI_SUCCESS // Bits setup.\r
71 @return EFI_UNSUPPORTED // Cannot divide base clock to reach target clock.\r
72**/\r
73EFI_STATUS\r
74DividedClockModeBits (\r
75 IN CONST UINTN BaseClockFreg,\r
76 IN CONST UINTN TargetFreq,\r
77 IN CONST BOOLEAN Is8BitMode,\r
78 OUT UINT16 *Bits\r
79 )\r
80{\r
81 UINTN N;\r
82 UINTN CurrFreq;\r
83\r
84 *Bits = 0;\r
85 CurrFreq = BaseClockFreg;\r
86 N = 0;\r
87 //\r
88 // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.\r
89 //\r
90 if (TargetFreq < CurrFreq) {\r
91 if (Is8BitMode) {\r
92 N = 1;\r
93 do {\r
94 //\r
95 // N values for 8bit mode when N > 0.\r
96 // Bit[15:8] SDCLK Frequency Select at offset 2Ch\r
97 // 80h - base clock divided by 256\r
98 // 40h - base clock divided by 128\r
99 // 20h - base clock divided by 64\r
100 // 10h - base clock divided by 32\r
101 // 08h - base clock divided by 16\r
102 // 04h - base clock divided by 8\r
103 // 02h - base clock divided by 4\r
104 // 01h - base clock divided by 2\r
105 //\r
106 CurrFreq = BaseClockFreg / (2 * N);\r
107 if (TargetFreq >= CurrFreq) {\r
108 break;\r
109 }\r
110 N *= 2;\r
111 if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {\r
112 return EFI_UNSUPPORTED;\r
113 }\r
114 } while (TRUE);\r
115 } else {\r
116 N = 1;\r
117 CurrFreq = BaseClockFreg / (2 * N);\r
118 //\r
119 // (try N = 0 or 1 first since don't want divide by 0).\r
120 //\r
121 if (TargetFreq < CurrFreq) {\r
122 //\r
123 // If still no match then calculate it for 10bit.\r
124 // N values for 10bit mode.\r
125 // N 1/2N Divided Clock (Duty 50%).\r
126 // from Spec "The length of divider is extended to 10 bits and all\r
127 // divider values shall be supported.\r
128 //\r
129 N = (BaseClockFreg / TargetFreq) / 2;\r
130\r
131 //\r
132 // Can only be N or N+1;\r
133 //\r
134 CurrFreq = BaseClockFreg / (2 * N);\r
135 if (TargetFreq < CurrFreq) {\r
136 N++;\r
137 CurrFreq = BaseClockFreg / (2 * N);\r
138 }\r
139\r
140 if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {\r
141 return EFI_UNSUPPORTED;\r
142 }\r
143\r
144 //\r
145 // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).\r
146 //\r
147 *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));\r
148 }\r
149 }\r
150 }\r
151\r
152 //\r
153 // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).\r
154 //\r
155 *Bits |= ((UINT16) ((UINT8) N) << 8);\r
156 DEBUG (\r
157 (EFI_D_INFO,\r
158 "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",\r
159 (Is8BitMode) ? 8 : 10,\r
160 TargetFreq,\r
161 CurrFreq,\r
162 (UINTN) *Bits\r
163 ));\r
164\r
165 return EFI_SUCCESS;\r
166}\r
167\r
168/**\r
169 Print type of error and command index\r
170\r
171 @param CommandIndex Command index to set the command index field of command register.\r
172 @param ErrorCode Error interrupt status read from host controller\r
173\r
174 @return EFI_DEVICE_ERROR\r
175 @return EFI_TIMEOUT\r
176 @return EFI_CRC_ERROR\r
177\r
178**/\r
179EFI_STATUS\r
180GetErrorReason (\r
181 IN UINT16 CommandIndex,\r
182 IN UINT16 ErrorCode\r
183 )\r
184{\r
185 EFI_STATUS Status;\r
186\r
187 Status = EFI_DEVICE_ERROR;\r
188\r
189 DEBUG((EFI_D_ERROR, "[%2d] -- ", CommandIndex));\r
190\r
191 if (ErrorCode & BIT0) {\r
192 Status = EFI_TIMEOUT;\r
193 DEBUG((EFI_D_ERROR, "Command Timeout Erro"));\r
194 }\r
195\r
196 if (ErrorCode & BIT1) {\r
197 Status = EFI_CRC_ERROR;\r
198 DEBUG((EFI_D_ERROR, "Command CRC Error"));\r
199 }\r
200\r
201 if (ErrorCode & BIT2) {\r
202 DEBUG((EFI_D_ERROR, "Command End Bit Error"));\r
203 }\r
204\r
205 if (ErrorCode & BIT3) {\r
206 DEBUG((EFI_D_ERROR, "Command Index Error"));\r
207 }\r
208 if (ErrorCode & BIT4) {\r
209 Status = EFI_TIMEOUT;\r
210 DEBUG((EFI_D_ERROR, "Data Timeout Error"));\r
211 }\r
212\r
213 if (ErrorCode & BIT5) {\r
214 Status = EFI_CRC_ERROR;\r
215 DEBUG((EFI_D_ERROR, "Data CRC Error"));\r
216 }\r
217\r
218 if (ErrorCode & BIT6) {\r
219 DEBUG((EFI_D_ERROR, "Data End Bit Error"));\r
220 }\r
221\r
222 if (ErrorCode & BIT7) {\r
223 DEBUG((EFI_D_ERROR, "Current Limit Error"));\r
224 }\r
225\r
226 if (ErrorCode & BIT8) {\r
227 DEBUG((EFI_D_ERROR, "Auto CMD12 Error"));\r
228 }\r
229\r
230 if (ErrorCode & BIT9) {\r
231 DEBUG((EFI_D_ERROR, "ADMA Error"));\r
232 }\r
233\r
234 DEBUG((EFI_D_ERROR, "\n"));\r
235\r
236 return Status;\r
237}\r
238/**\r
239 Enable/Disable High Speed transfer mode\r
240\r
241 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
242 @param Enable TRUE to Enable, FALSE to Disable\r
243\r
244 @return EFI_SUCCESS\r
245**/\r
246EFI_STATUS\r
247SetHighSpeedMode (\r
248 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
249 IN BOOLEAN Enable\r
250 )\r
251{\r
252 UINT32 Data;\r
253 SDHOST_DATA *SDHostData;\r
254 EFI_PCI_IO_PROTOCOL *PciIo;\r
255\r
256 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
257 PciIo = SDHostData->PciIo;\r
258\r
259 PciIo->Mem.Read (\r
260 PciIo,\r
261 EfiPciIoWidthUint8,\r
262 0,\r
263 (UINT64)MMIO_HOSTCTL,\r
264 1,\r
265 &Data\r
266 );\r
267\r
268 if (Enable) {\r
269 if (PcdGetBool(PcdSdHciQuirkNoHiSpd)) {\r
270 DEBUG ((EFI_D_INFO, "SDIO: Quirk never set High Speed Enable bit\r\n"));\r
271 return EFI_SUCCESS;\r
272 }\r
273 DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));\r
274 Data |= BIT2;\r
275 } else {\r
276 Data &= ~BIT2;\r
277 }\r
278 PciIo->Mem.Write (\r
279 PciIo,\r
280 EfiPciIoWidthUint8,\r
281 0,\r
282 (UINT64)MMIO_HOSTCTL,\r
283 1,\r
284 &Data\r
285 );\r
286 return EFI_SUCCESS;\r
287}\r
288EFI_STATUS\r
289EFIAPI\r
290SetDDRMode (\r
291 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
292 IN BOOLEAN Enable\r
293 )\r
294{\r
295 UINT16 Data;\r
296 SDHOST_DATA *SDHostData;\r
297 EFI_PCI_IO_PROTOCOL *PciIo;\r
298 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
299 PciIo = SDHostData->PciIo;\r
300 PciIo->Mem.Read (\r
301 PciIo,\r
302 EfiPciIoWidthUint16,\r
303 0,\r
304 (UINT64)MMIO_HOSTCTL2,\r
305 1,\r
306 &Data\r
307 );\r
308 Data &= 0xFFF0;\r
309 if (Enable) {\r
310 Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400\r
311 Data |= BIT3; // Enable 1.8V Signaling\r
312 }\r
313 PciIo->Mem.Write (\r
314 PciIo,\r
315 EfiPciIoWidthUint16,\r
316 0,\r
317 (UINT64)MMIO_HOSTCTL2,\r
318 1,\r
319 &Data\r
320 );\r
321 return EFI_SUCCESS;\r
322}\r
323/**\r
324 Power on/off the LED associated with the slot\r
325\r
326 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
327 @param Enable TRUE to set LED on, FALSE to set LED off\r
328\r
329 @return EFI_SUCCESS\r
330**/\r
331EFI_STATUS\r
332HostLEDEnable (\r
333 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
334 IN BOOLEAN Enable\r
335 )\r
336{\r
337 SDHOST_DATA *SDHostData;\r
338 EFI_PCI_IO_PROTOCOL *PciIo;\r
339 UINT32 Data;\r
340\r
341 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
342 PciIo = SDHostData->PciIo;\r
343\r
344 PciIo->Mem.Read (\r
345 PciIo,\r
346 EfiPciIoWidthUint8,\r
347 0,\r
348 (UINT64)MMIO_HOSTCTL,\r
349 1,\r
350 &Data\r
351 );\r
352\r
353 if (Enable) {\r
354 //\r
355 //LED On\r
356 //\r
357 Data |= BIT0;\r
358 } else {\r
359 //\r
360 //LED Off\r
361 //\r
362 Data &= ~BIT0;\r
363 }\r
364\r
365 PciIo->Mem.Write (\r
366 PciIo,\r
367 EfiPciIoWidthUint8,\r
368 0,\r
369 (UINT64)MMIO_HOSTCTL,\r
370 1,\r
371 &Data\r
372 );\r
373\r
374 return EFI_SUCCESS;\r
375}\r
376\r
377\r
378/**\r
379 The main function used to send the command to the card inserted into the SD host slot.\r
380 It will assemble the arguments to set the command register and wait for the command\r
381 and transfer completed until timeout. Then it will read the response register to fill\r
382 the ResponseData.\r
383\r
384 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
385 @param CommandIndex The command index to set the command index field of command register.\r
386 @param Argument Command argument to set the argument field of command register.\r
387 @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
388 @param Buffer Contains the data read from / write to the device.\r
389 @param BufferSize The size of the buffer.\r
390 @param ResponseType RESPONSE_TYPE.\r
391 @param TimeOut Time out value in 1 ms unit.\r
392 @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
393\r
394 @retval EFI_SUCCESS\r
395 @retval EFI_INVALID_PARAMETER\r
396 @retval EFI_OUT_OF_RESOURCES\r
397 @retval EFI_TIMEOUT\r
398 @retval EFI_DEVICE_ERROR\r
399\r
400**/\r
401\r
402EFI_STATUS\r
403EFIAPI\r
404SendCommand (\r
405 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
406 IN UINT16 CommandIndex,\r
407 IN UINT32 Argument,\r
408 IN TRANSFER_TYPE DataType,\r
409 IN UINT8 *Buffer, OPTIONAL\r
410 IN UINT32 BufferSize,\r
411 IN RESPONSE_TYPE ResponseType,\r
412 IN UINT32 TimeOut,\r
413 OUT UINT32 *ResponseData OPTIONAL\r
414 )\r
415/*++\r
416\r
417 Routine Description:\r
418 The main function used to send the command to the card inserted into the SD host\r
419 slot.\r
420 It will assemble the arguments to set the command register and wait for the command\r
421 and transfer completed until timeout. Then it will read the response register to fill\r
422 the ResponseData\r
423\r
424 Arguments:\r
425 This - Pointer to EFI_SD_HOST_IO_PROTOCOL\r
426 CommandIndex - The command index to set the command index field of command register\r
427 Argument - Command argument to set the argument field of command register\r
428 DataType - TRANSFER_TYPE, indicates no data, data in or data out\r
429 Buffer - Contains the data read from / write to the device\r
430 BufferSize - The size of the buffer\r
431 ResponseType - RESPONSE_TYPE\r
432 TimeOut - Time out value in 1 ms unit\r
433 ResponseData - Depending on the ResponseType, such as CSD or card status\r
434\r
435 Returns:\r
436 EFI_SUCCESS\r
437 EFI_INVALID_PARAMETER\r
438 EFI_OUT_OF_RESOURCES\r
439 EFI_TIMEOUT\r
440 EFI_DEVICE_ERROR\r
441\r
442--*/\r
443{\r
444 EFI_STATUS Status;\r
445 SDHOST_DATA *SDHostData;\r
446 EFI_PCI_IO_PROTOCOL *PciIo;\r
447 UINT32 ResponseDataCount;\r
448 UINT32 Data;\r
449 UINT64 Data64;\r
450 UINT8 Index;\r
451 INTN TimeOut2;\r
452 BOOLEAN AutoCMD12Enable = FALSE;\r
453\r
454\r
455 Status = EFI_SUCCESS;\r
456 ResponseDataCount = 1;\r
457 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
458 PciIo = SDHostData->PciIo;\r
459 AutoCMD12Enable = (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;\r
460 CommandIndex = CommandIndex & CMD_INDEX_MASK;\r
461\r
462 if (Buffer != NULL && DataType == NoData) {\r
463 Status = EFI_INVALID_PARAMETER;\r
464 DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
465 goto Exit;\r
466 }\r
467\r
468 if (((UINTN)Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN)NULL) {\r
469 Status = EFI_INVALID_PARAMETER;\r
470 DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
471 goto Exit;\r
472 }\r
473\r
474 DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));\r
475 //\r
476 TimeOut2 = 1000; // 10 ms\r
477 do {\r
478 PciIo->Mem.Read (\r
479 PciIo,\r
480 EfiPciIoWidthUint32,\r
481 0,\r
482 (UINT64)MMIO_PSTATE,\r
483 1,\r
484 &Data\r
485 );\r
486 gBS->Stall (10);\r
487 }while ((TimeOut2-- > 0) && (Data & BIT0));\r
488 TimeOut2 = 1000; // 10 ms\r
489 do {\r
490 PciIo->Mem.Read (\r
491 PciIo,\r
492 EfiPciIoWidthUint32,\r
493 0,\r
494 (UINT64)MMIO_PSTATE,\r
495 1,\r
496 &Data\r
497 );\r
498 gBS->Stall (10);\r
499 }while ((TimeOut2-- > 0) && (Data & BIT1));\r
500 //Clear status bits\r
501 //\r
502 Data = 0xFFFF;\r
503 PciIo->Mem.Write (\r
504 PciIo,\r
505 EfiPciIoWidthUint16,\r
506 0,\r
507 (UINT64)MMIO_NINTSTS,\r
508 1,\r
509 &Data\r
510 );\r
511\r
512 Data = 0xFFFF;\r
513 PciIo->Mem.Write (\r
514 PciIo,\r
515 EfiPciIoWidthUint16,\r
516 0,\r
517 (UINT64)MMIO_ERINTSTS,\r
518 1,\r
519 &Data\r
520 );\r
521\r
522\r
523 if (Buffer != NULL) {\r
524 PciIo->Mem.Write (\r
525 PciIo,\r
526 EfiPciIoWidthUint32,\r
527 0,\r
528 (UINT64)MMIO_DMAADR,\r
529 1,\r
530 &Buffer\r
531 );\r
532\r
533 PciIo->Mem.Read (\r
534 PciIo,\r
535 EfiPciIoWidthUint16,\r
536 0,\r
537 (UINT64)MMIO_BLKSZ,\r
538 1,\r
539 &Data\r
540 );\r
541 Data &= ~(0xFFF);\r
542 if (BufferSize <= SDHostData->BlockLength) {\r
543 Data |= (BufferSize | 0x7000);\r
544 } else {\r
545 Data |= (SDHostData->BlockLength | 0x7000);\r
546 }\r
547\r
548\r
549 PciIo->Mem.Write (\r
550 PciIo,\r
551 EfiPciIoWidthUint16,\r
552 0,\r
553 (UINT64)MMIO_BLKSZ,\r
554 1,\r
555 &Data\r
556 );\r
557 if (BufferSize <= SDHostData->BlockLength) {\r
558 Data = 1;\r
559 } else {\r
560 Data = BufferSize / SDHostData->BlockLength;\r
561 }\r
562 PciIo->Mem.Write (\r
563 PciIo,\r
564 EfiPciIoWidthUint16,\r
565 0,\r
566 (UINT64)MMIO_BLKCNT,\r
567 1,\r
568 &Data\r
569 );\r
570\r
571 } else {\r
572 Data = 0;\r
573 PciIo->Mem.Write (\r
574 PciIo,\r
575 EfiPciIoWidthUint16,\r
576 0,\r
577 (UINT64)MMIO_BLKSZ,\r
578 1,\r
579 &Data\r
580 );\r
581 PciIo->Mem.Write (\r
582 PciIo,\r
583 EfiPciIoWidthUint16,\r
584 0,\r
585 (UINT64)MMIO_BLKCNT,\r
586 1,\r
587 &Data\r
588 );\r
589 }\r
590\r
591 //\r
592 //Argument\r
593 //\r
594 Data = Argument;\r
595 PciIo->Mem.Write (\r
596 PciIo,\r
597 EfiPciIoWidthUint32,\r
598 0,\r
599 (UINT64)MMIO_CMDARG,\r
600 1,\r
601 &Data\r
602 );\r
603\r
604\r
605 PciIo->Mem.Read (\r
606 PciIo,\r
607 EfiPciIoWidthUint16,\r
608 0,\r
609 (UINT64)MMIO_XFRMODE,\r
610 1,\r
611 &Data\r
612 );\r
613\r
614\r
615 DEBUG ((EFI_D_INFO, "Transfer mode read = 0x%x \r\n", (Data & 0xFFFF)));\r
616 //\r
617 //BIT0 - DMA Enable\r
618 //BIT2 - Auto Cmd12\r
619 //\r
620 if (DataType == InData) {\r
621 Data |= BIT4 | BIT0;\r
622 } else if (DataType == OutData){\r
623 Data &= ~BIT4;\r
624 Data |= BIT0;\r
625 } else {\r
626 Data &= ~(BIT4 | BIT0);\r
627 }\r
628\r
629 if (BufferSize <= SDHostData->BlockLength) {\r
630 Data &= ~ (BIT5 | BIT1 | BIT2);\r
631 Data |= BIT1; // Enable block count always\r
632 } else {\r
633 if (SDHostData->IsAutoStopCmd && AutoCMD12Enable) {\r
634 Data |= (BIT5 | BIT1 | BIT2);\r
635 } else {\r
636 Data |= (BIT5 | BIT1);\r
637 }\r
638 }\r
639\r
640 DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));\r
641 PciIo->Mem.Write (\r
642 PciIo,\r
643 EfiPciIoWidthUint16,\r
644 0,\r
645 (UINT64)MMIO_XFRMODE,\r
646 1,\r
647 &Data\r
648 );\r
649 //\r
650 //Command\r
651 //\r
652 //ResponseTypeSelect IndexCheck CRCCheck ResponseType\r
653 // 00 0 0 NoResponse\r
654 // 01 0 1 R2\r
655 // 10 0 0 R3, R4\r
656 // 10 1 1 R1, R5, R6, R7\r
657 // 11 1 1 R1b, R5b\r
658 //\r
659 switch (ResponseType) {\r
660 case ResponseNo:\r
661 Data = (CommandIndex << 8);\r
662 ResponseDataCount = 0;\r
663 break;\r
664\r
665 case ResponseR1:\r
666 case ResponseR5:\r
667 case ResponseR6:\r
668 case ResponseR7:\r
669 Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;\r
670 ResponseDataCount = 1;\r
671 break;\r
672\r
673 case ResponseR1b:\r
674 case ResponseR5b:\r
675 Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;\r
676 ResponseDataCount = 1;\r
677 break;\r
678\r
679 case ResponseR2:\r
680 Data = (CommandIndex << 8) | BIT0 | BIT3;\r
681 ResponseDataCount = 4;\r
682 break;\r
683\r
684 case ResponseR3:\r
685 case ResponseR4:\r
686 Data = (CommandIndex << 8) | BIT1;\r
687 ResponseDataCount = 1;\r
688 break;\r
689\r
690 default:\r
691 ASSERT (0);\r
692 Status = EFI_INVALID_PARAMETER;\r
693 DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
694 goto Exit;\r
695 }\r
696\r
697 if (DataType != NoData) {\r
698 Data |= BIT5;\r
699 }\r
700\r
701 HostLEDEnable (This, TRUE);\r
702\r
703\r
704 PciIo->Mem.Write (\r
705 PciIo,\r
706 EfiPciIoWidthUint16,\r
707 0,\r
708 (UINT64)MMIO_SDCMD,\r
709 1,\r
710 &Data\r
711 );\r
712\r
713\r
714 Data = 0;\r
715 do {\r
716 PciIo->Mem.Read (\r
717 PciIo,\r
718 EfiPciIoWidthUint16,\r
719 0,\r
720 (UINT64)MMIO_ERINTSTS,\r
721 1,\r
722 &Data\r
723 );\r
724\r
725 if ((Data & 0x07FF) != 0) {\r
726 Status = GetErrorReason (CommandIndex, (UINT16)Data);\r
727 DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));\r
728 goto Exit;\r
729 }\r
730\r
731 PciIo->Mem.Read (\r
732 PciIo,\r
733 EfiPciIoWidthUint16,\r
734 0,\r
735 (UINT64)MMIO_NINTSTS,\r
736 1,\r
737 &Data\r
738 );\r
739\r
740 if ((Data & BIT0) == BIT0) {\r
741 //\r
742 //Command completed, can read response\r
743 //\r
744 if (DataType == NoData) {\r
745 break;\r
746 } else {\r
747 //\r
748 //Transfer completed\r
749 //\r
750 if ((Data & BIT1) == BIT1) {\r
751 break;\r
752 }\r
753 }\r
754 }\r
755\r
756 gBS->Stall (1 * 1000);\r
757\r
758 TimeOut --;\r
759\r
760 } while (TimeOut > 0);\r
761\r
762 if (TimeOut == 0) {\r
763 Status = EFI_TIMEOUT;\r
764 DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));\r
765 goto Exit;\r
766 }\r
767\r
768 if (ResponseData != NULL) {\r
769 PciIo->Mem.Read (\r
770 PciIo,\r
771 EfiPciIoWidthUint32,\r
772 0,\r
773 (UINT64)MMIO_RESP,\r
774 ResponseDataCount,\r
775 ResponseData\r
776 );\r
777 if (ResponseType == ResponseR2) {\r
778 //\r
779 // Adjustment for R2 response\r
780 //\r
781 Data = 1;\r
782 for (Index = 0; Index < ResponseDataCount; Index++) {\r
783 Data64 = LShiftU64(*ResponseData, 8);\r
784 *ResponseData = (UINT32)((Data64 & 0xFFFFFFFF) | Data);\r
785 Data = (UINT32)RShiftU64 (Data64, 32);\r
786 ResponseData++;\r
787 }\r
788 }\r
789 }\r
790\r
791Exit:\r
792 HostLEDEnable (This, FALSE);\r
793 return Status;\r
794}\r
795\r
796/**\r
797 Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.\r
798 It depends on the max frequency the host can support, divider, and host speed mode.\r
799\r
800 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
801 @param MaxFrequency Max frequency in HZ.\r
802\r
803 @retval EFI_SUCCESS\r
804 @retval EFI_TIMEOUT\r
805\r
806**/\r
807EFI_STATUS\r
808EFIAPI\r
809SetClockFrequency (\r
810 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
811 IN UINT32 MaxFrequency\r
812 )\r
813{\r
814 UINT32 Data;\r
815 UINT16 FreqSelBits;\r
816 EFI_STATUS Status;\r
817 SDHOST_DATA *SDHostData;\r
818 EFI_PCI_IO_PROTOCOL *PciIo;\r
819 UINT32 TimeOutCount;\r
820 UINT32 Revision;\r
821\r
822 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
823 PciIo = SDHostData->PciIo;\r
824 Data = 0;\r
825 PciIo->Mem.Write (\r
826 PciIo,\r
827 EfiPciIoWidthUint16,\r
828 0,\r
829 (UINT64)MMIO_CLKCTL,\r
830 1,\r
831 &Data\r
832 );\r
833\r
834 PciIo->Mem.Read (\r
835 PciIo,\r
836 EfiPciIoWidthUint8,\r
837 0,\r
838 (UINT64)MMIO_CTRLRVER,\r
839 1,\r
840 &Revision\r
841 );\r
842 Revision &= 0x000000FF;\r
843\r
844 Status = DividedClockModeBits (\r
845 SDHostData->BaseClockInMHz * 1000 * 1000,\r
846 MaxFrequency,\r
847 (Revision < SDHCI_SPEC_300),\r
848 &FreqSelBits\r
849 );\r
850\r
851 if (EFI_ERROR (Status)) {\r
852 //\r
853 // Cannot reach MaxFrequency with SDHostData->BaseClockInMHz.\r
854 //\r
855 ASSERT_EFI_ERROR (Status);\r
856 return Status;\r
857 }\r
858\r
859 Data = 0;\r
860\r
861 //\r
862 //Enable internal clock and Stop Clock Enable\r
863 //\r
864 Data = BIT0;\r
865 PciIo->Mem.Write (\r
866 PciIo,\r
867 EfiPciIoWidthUint16,\r
868 0,\r
869 (UINT64)MMIO_CLKCTL,\r
870 1,\r
871 &Data\r
872 );\r
873\r
874 TimeOutCount = TIME_OUT_1S;\r
875 do {\r
876 PciIo->Mem.Read (\r
877 PciIo,\r
878 EfiPciIoWidthUint16,\r
879 0,\r
880 (UINT64)MMIO_CLKCTL,\r
881 1,\r
882 &Data\r
883 );\r
884 gBS->Stall (1 * 1000);\r
885 TimeOutCount --;\r
886 if (TimeOutCount == 0) {\r
887 DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
888 return EFI_TIMEOUT;\r
889 }\r
890 } while ((Data & BIT1) != BIT1);\r
891\r
892 DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SDHostData->BaseClockInMHz));\r
893\r
894 Data = (BIT0 | ((UINT32) FreqSelBits));\r
895 DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));\r
896 PciIo->Mem.Write (\r
897 PciIo,\r
898 EfiPciIoWidthUint16,\r
899 0,\r
900 (UINT64)MMIO_CLKCTL,\r
901 1,\r
902 &Data\r
903 );\r
904\r
905 TimeOutCount = TIME_OUT_1S;\r
906 do {\r
907 PciIo->Mem.Read (\r
908 PciIo,\r
909 EfiPciIoWidthUint16,\r
910 0,\r
911 (UINT64)MMIO_CLKCTL,\r
912 1,\r
913 &Data\r
914 );\r
915 gBS->Stall (1 * 1000);\r
916 TimeOutCount --;\r
917 if (TimeOutCount == 0) {\r
918 DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
919 return EFI_TIMEOUT;\r
920 }\r
921 } while ((Data & BIT1) != BIT1);\r
922 gBS->Stall (20 * 1000);\r
923 Data |= BIT2;\r
924 PciIo->Mem.Write (\r
925 PciIo,\r
926 EfiPciIoWidthUint16,\r
927 0,\r
928 (UINT64)MMIO_CLKCTL,\r
929 1,\r
930 &Data\r
931 );\r
932\r
933 return EFI_SUCCESS;\r
934}\r
935\r
936/**\r
937 Set bus width of the host controller\r
938\r
939 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
940 @param BusWidth Bus width in 1, 4, 8 bits.\r
941\r
942 @retval EFI_SUCCESS\r
943 @retval EFI_INVALID_PARAMETER\r
944\r
945**/\r
946EFI_STATUS\r
947EFIAPI\r
948SetBusWidth (\r
949 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
950 IN UINT32 BusWidth\r
951 )\r
952{\r
953 SDHOST_DATA *SDHostData;\r
954 EFI_PCI_IO_PROTOCOL *PciIo;\r
955 UINT8 Data;\r
956\r
957 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
958\r
959\r
960 if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {\r
961 DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
962 return EFI_INVALID_PARAMETER;\r
963 }\r
964\r
965 if ((SDHostData->SDHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {\r
966 DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
967 return EFI_INVALID_PARAMETER;\r
968 }\r
969\r
970 PciIo = SDHostData->PciIo;\r
971\r
972 PciIo->Mem.Read (\r
973 PciIo,\r
974 EfiPciIoWidthUint8,\r
975 0,\r
976 (UINT64)MMIO_HOSTCTL,\r
977 1,\r
978 &Data\r
979 );\r
980 //\r
981 // BIT5 8-bit MMC Support (MMC8):\r
982 // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature\r
983 //\r
984 if (BusWidth == 8) {\r
985 DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));\r
986 Data |= BIT5;\r
987 } else if (BusWidth == 4) {\r
988 DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));\r
989 Data &= ~BIT5;\r
990 Data |= BIT1;\r
991 } else {\r
992 DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));\r
993 Data &= ~BIT5;\r
994 Data &= ~BIT1;\r
995 }\r
996\r
997 PciIo->Mem.Write (\r
998 PciIo,\r
999 EfiPciIoWidthUint8,\r
1000 0,\r
1001 (UINT64)MMIO_HOSTCTL,\r
1002 1,\r
1003 &Data\r
1004 );\r
1005\r
1006 return EFI_SUCCESS;\r
1007}\r
1008\r
1009\r
1010/**\r
1011 Set voltage which could supported by the host controller.\r
1012 Support 0(Power off the host), 1.8V, 3.0V, 3.3V\r
1013\r
1014 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
1015 @param Voltage Units in 0.1 V.\r
1016\r
1017 @retval EFI_SUCCESS\r
1018 @retval EFI_INVALID_PARAMETER\r
1019\r
1020**/\r
1021EFI_STATUS\r
1022EFIAPI\r
1023SetHostVoltage (\r
1024 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
1025 IN UINT32 Voltage\r
1026 )\r
1027{\r
1028 SDHOST_DATA *SDHostData;\r
1029 EFI_PCI_IO_PROTOCOL *PciIo;\r
1030 UINT8 Data;\r
1031 EFI_STATUS Status;\r
1032\r
1033 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
1034 PciIo = SDHostData->PciIo;\r
1035 Status = EFI_SUCCESS;\r
1036\r
1037 PciIo->Mem.Read (\r
1038 PciIo,\r
1039 EfiPciIoWidthUint8,\r
1040 0,\r
1041 (UINT64)MMIO_PWRCTL,\r
1042 1,\r
1043 &Data\r
1044 );\r
1045\r
1046 if (Voltage == 0) {\r
1047 //\r
1048 //Power Off the host\r
1049 //\r
1050 Data &= ~BIT0;\r
1051 } else if (Voltage <= 18 && This->HostCapability.V18Support) {\r
1052 //\r
1053 //1.8V\r
1054 //\r
1055 Data |= (BIT1 | BIT3 | BIT0);\r
1056 } else if (Voltage > 18 && Voltage <= 30 && This->HostCapability.V30Support) {\r
1057 //\r
1058 //3.0V\r
1059 //\r
1060 Data |= (BIT2 | BIT3 | BIT0);\r
1061 } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {\r
1062 //\r
1063 //3.3V\r
1064 //\r
1065 Data |= (BIT1 | BIT2 | BIT3 | BIT0);\r
1066 } else {\r
1067 Status = EFI_UNSUPPORTED;\r
1068 goto Exit;\r
1069 }\r
1070\r
1071 PciIo->Mem.Write (\r
1072 PciIo,\r
1073 EfiPciIoWidthUint8,\r
1074 0,\r
1075 (UINT64)MMIO_PWRCTL,\r
1076 1,\r
1077 &Data\r
1078 );\r
1079 gBS->Stall (10 * 1000);\r
1080\r
1081Exit:\r
1082 return Status;\r
1083}\r
1084\r
1085\r
1086\r
1087/**\r
1088 Reset the host controller.\r
1089\r
1090 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
1091 @param ResetAll TRUE to reset all.\r
1092\r
1093 @retval EFI_SUCCESS\r
1094 @retval EFI_TIMEOUT\r
1095\r
1096**/\r
1097EFI_STATUS\r
1098EFIAPI\r
1099ResetSDHost (\r
1100 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
1101 IN RESET_TYPE ResetType\r
1102 )\r
1103{\r
1104 SDHOST_DATA *SDHostData;\r
1105 EFI_PCI_IO_PROTOCOL *PciIo;\r
1106 UINT32 Data;\r
1107 UINT16 ErrStatus;\r
1108 UINT32 Mask;\r
1109 UINT32 TimeOutCount;\r
1110 UINT16 SaveClkCtl;\r
1111 UINT16 ZeroClkCtl;\r
1112\r
1113 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
1114 PciIo = SDHostData->PciIo;\r
1115 Mask = 0;\r
1116 ErrStatus = 0;\r
1117\r
1118 if (ResetType == Reset_Auto) {\r
1119 PciIo->Mem.Read (\r
1120 PciIo,\r
1121 EfiPciIoWidthUint16,\r
1122 0,\r
1123 (UINT64)MMIO_ERINTSTS,\r
1124 1,\r
1125 &ErrStatus\r
1126 );\r
1127 if ((ErrStatus & 0xF) != 0) {\r
1128 //\r
1129 //Command Line\r
1130 //\r
1131 Mask |= BIT1;\r
1132 }\r
1133 if ((ErrStatus & 0x70) != 0) {\r
1134 //\r
1135 //Data Line\r
1136 //\r
1137 Mask |= BIT2;\r
1138 }\r
1139 }\r
1140\r
1141\r
1142 if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {\r
1143 Mask |= BIT2;\r
1144 }\r
1145 if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {\r
1146 Mask |= BIT1;\r
1147 }\r
1148 if (ResetType == Reset_All) {\r
1149 Mask = BIT0;\r
1150 }\r
1151\r
1152 if (Mask == 0) {\r
1153 return EFI_SUCCESS;\r
1154 }\r
1155\r
1156 //\r
1157 // To improve SD stability, we zero the MMIO_CLKCTL register and\r
1158 // stall for 50 microseconds before reseting the controller. We\r
1159 // restore the register setting following the reset operation.\r
1160 //\r
1161 PciIo->Mem.Read (\r
1162 PciIo,\r
1163 EfiPciIoWidthUint16,\r
1164 0,\r
1165 (UINT64)MMIO_CLKCTL,\r
1166 1,\r
1167 &SaveClkCtl\r
1168 );\r
1169\r
1170 ZeroClkCtl = (UINT16) 0;\r
1171 PciIo->Mem.Write (\r
1172 PciIo,\r
1173 EfiPciIoWidthUint16,\r
1174 0,\r
1175 (UINT64)MMIO_CLKCTL,\r
1176 1,\r
1177 &ZeroClkCtl\r
1178 );\r
1179\r
1180 gBS->Stall (50);\r
1181\r
1182 //\r
1183 // Reset the SD host controller\r
1184 //\r
1185 PciIo->Mem.Write (\r
1186 PciIo,\r
1187 EfiPciIoWidthUint8,\r
1188 0,\r
1189 (UINT64)MMIO_SWRST,\r
1190 1,\r
1191 &Mask\r
1192 );\r
1193\r
1194 Data = 0;\r
1195 TimeOutCount = TIME_OUT_1S;\r
1196 do {\r
1197\r
1198 gBS->Stall (1 * 1000);\r
1199\r
1200 TimeOutCount --;\r
1201\r
1202 PciIo->Mem.Read (\r
1203 PciIo,\r
1204 EfiPciIoWidthUint8,\r
1205 0,\r
1206 (UINT64)MMIO_SWRST,\r
1207 1,\r
1208 &Data\r
1209 );\r
1210 if ((Data & Mask) == 0) {\r
1211 break;\r
1212 }\r
1213 } while (TimeOutCount > 0);\r
1214\r
1215 //\r
1216 // We now restore the MMIO_CLKCTL register which we set to 0 above.\r
1217 //\r
1218 PciIo->Mem.Write (\r
1219 PciIo,\r
1220 EfiPciIoWidthUint16,\r
1221 0,\r
1222 (UINT64)MMIO_CLKCTL,\r
1223 1,\r
1224 &SaveClkCtl\r
1225 );\r
1226\r
1227 if (TimeOutCount == 0) {\r
1228 DEBUG ((EFI_D_ERROR, "ResetSDHost: Time out \r\n"));\r
1229 return EFI_TIMEOUT;\r
1230 }\r
1231\r
1232 return EFI_SUCCESS;\r
1233}\r
1234\r
1235\r
1236/**\r
1237 Enable auto stop on the host controller.\r
1238\r
1239 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
1240 @param Enable TRUE to enable, FALSE to disable.\r
1241\r
1242 @retval EFI_SUCCESS\r
1243 @retval EFI_TIMEOUT\r
1244\r
1245**/\r
1246EFI_STATUS\r
1247EFIAPI\r
1248EnableAutoStopCmd (\r
1249 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
1250 IN BOOLEAN Enable\r
1251 )\r
1252{\r
1253 SDHOST_DATA *SDHostData;\r
1254\r
1255 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
1256\r
1257 SDHostData->IsAutoStopCmd = Enable;\r
1258\r
1259 return EFI_SUCCESS;\r
1260}\r
1261\r
1262/**\r
1263 Set the Block length on the host controller.\r
1264\r
1265 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
1266 @param BlockLength card supportes block length.\r
1267\r
1268 @retval EFI_SUCCESS\r
1269 @retval EFI_TIMEOUT\r
1270\r
1271**/\r
1272EFI_STATUS\r
1273EFIAPI\r
1274SetBlockLength (\r
1275 IN EFI_SD_HOST_IO_PROTOCOL *This,\r
1276 IN UINT32 BlockLength\r
1277 )\r
1278{\r
1279 SDHOST_DATA *SDHostData;\r
1280\r
1281 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
1282\r
1283 DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));\r
1284 SDHostData->BlockLength = BlockLength;\r
1285\r
1286 return EFI_SUCCESS;\r
1287}\r
1288\r
1289\r
1290/**\r
1291 Find whether these is a card inserted into the slot. If so init the host.\r
1292 If not, return EFI_NOT_FOUND.\r
1293\r
1294 @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
1295\r
1296 @retval EFI_SUCCESS\r
1297 @retval EFI_NOT_FOUND\r
1298\r
1299**/\r
1300EFI_STATUS\r
1301EFIAPI\r
1302DetectCardAndInitHost (\r
1303 IN EFI_SD_HOST_IO_PROTOCOL *This\r
1304 )\r
1305{\r
1306 SDHOST_DATA *SDHostData;\r
1307 EFI_PCI_IO_PROTOCOL *PciIo;\r
1308 UINT32 Data;\r
1309 EFI_STATUS Status;\r
1310 UINT8 Voltages[] = { 33, 30, 18 };\r
1311 UINTN Loop;\r
1312\r
1313 SDHostData = SDHOST_DATA_FROM_THIS (This);\r
1314 PciIo = SDHostData->PciIo;\r
1315 Status = EFI_NOT_FOUND;\r
1316\r
1317 Data = 0;\r
1318 PciIo->Mem.Read (\r
1319 PciIo,\r
1320 EfiPciIoWidthUint32,\r
1321 0,\r
1322 (UINT64)MMIO_PSTATE,\r
1323 1,\r
1324 &Data\r
1325 );\r
1326\r
1327 if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {\r
1328 //\r
1329 // Has no card inserted\r
1330 //\r
1331 DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));\r
1332 Status = EFI_NOT_FOUND;\r
1333 goto Exit;\r
1334 }\r
1335 DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));\r
1336\r
1337 Status = EFI_NOT_FOUND;\r
1338 for (Loop = 0; Loop < sizeof (Voltages); Loop++) {\r
1339 DEBUG ((\r
1340 EFI_D_INFO,\r
1341 "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",\r
1342 Voltages[Loop] / 10,\r
1343 Voltages[Loop] % 10\r
1344 ));\r
1345 Status = SetHostVoltage (This, Voltages[Loop]);\r
1346 if (EFI_ERROR (Status)) {\r
1347 DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));\r
1348 } else {\r
1349 DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));\r
1350 break;\r
1351 }\r
1352 }\r
1353 if (EFI_ERROR (Status)) {\r
1354 DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));\r
1355 goto Exit;\r
1356 }\r
1357\r
1358 Status = SetClockFrequency (This, FREQUENCY_OD);\r
1359 if (EFI_ERROR (Status)) {\r
1360 DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));\r
1361 goto Exit;\r
1362 }\r
1363 SetBusWidth (This, 1);\r
1364\r
1365 //\r
1366 //Enable normal status change\r
1367 //\r
1368\r
1369 Data = (BIT0 | BIT1);\r
1370\r
1371 PciIo->Mem.Write (\r
1372 PciIo,\r
1373 EfiPciIoWidthUint16,\r
1374 0,\r
1375 (UINT64)MMIO_NINTEN,\r
1376 1,\r
1377 &Data\r
1378 );\r
1379\r
1380 //\r
1381 //Enable error status change\r
1382 //\r
1383 PciIo->Mem.Read (\r
1384 PciIo,\r
1385 EfiPciIoWidthUint16,\r
1386 0,\r
1387 (UINT64)MMIO_ERINTEN,\r
1388 1,\r
1389 &Data\r
1390 );\r
1391\r
1392 Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);\r
1393\r
1394 PciIo->Mem.Write (\r
1395 PciIo,\r
1396 EfiPciIoWidthUint16,\r
1397 0,\r
1398 (UINT64)MMIO_ERINTEN,\r
1399 1,\r
1400 &Data\r
1401 );\r
1402\r
1403 //\r
1404 //Data transfer Timeout control\r
1405 //\r
1406 Data = 0x0E;\r
1407\r
1408 PciIo->Mem.Write (\r
1409 PciIo,\r
1410 EfiPciIoWidthUint8,\r
1411 0,\r
1412 (UINT64)MMIO_TOCTL,\r
1413 1,\r
1414 &Data\r
1415 );\r
1416 //\r
1417 //Set Default Bus width as 1 bit\r
1418 //\r
1419\r
1420Exit:\r
1421 return Status;\r
1422\r
1423}\r
1424\r
1425/**\r
1426 Entry point for EFI drivers.\r
1427\r
1428 @param ImageHandle EFI_HANDLE.\r
1429 @param SystemTable EFI_SYSTEM_TABLE.\r
1430\r
1431 @retval EFI_SUCCESS Driver is successfully loaded.\r
1432 @return Others Failed.\r
1433\r
1434**/\r
1435EFI_STATUS\r
1436EFIAPI\r
1437InitializeSDController (\r
1438 IN EFI_HANDLE ImageHandle,\r
1439 IN EFI_SYSTEM_TABLE *SystemTable\r
1440 )\r
1441{\r
1442 return EfiLibInstallDriverBindingComponentName2 (\r
1443 ImageHandle,\r
1444 SystemTable,\r
1445 &gSDControllerDriverBinding,\r
1446 ImageHandle,\r
1447 &gSDControllerName,\r
1448 &gSDControllerName2\r
1449 );\r
1450}\r
1451\r
1452\r
1453/**\r
1454 Test to see if this driver supports ControllerHandle. Any\r
1455 ControllerHandle that has SDHostIoProtocol installed will be supported.\r
1456\r
1457 @param This Protocol instance pointer.\r
1458 @param Controller Handle of device to test.\r
1459 @param RemainingDevicePath Not used.\r
1460\r
1461 @return EFI_SUCCESS This driver supports this device.\r
1462 @return EFI_UNSUPPORTED This driver does not support this device.\r
1463\r
1464**/\r
1465EFI_STATUS\r
1466EFIAPI\r
1467SDControllerSupported (\r
1468 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1469 IN EFI_HANDLE Controller,\r
1470 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1471 )\r
1472{\r
1473 EFI_STATUS OpenStatus;\r
1474 EFI_STATUS Status;\r
1475 EFI_PCI_IO_PROTOCOL *PciIo;\r
1476 PCI_CLASSC PciClass;\r
1477 EFI_SD_HOST_IO_PROTOCOL *SdHostIo;\r
1478 Status = gBS->OpenProtocol (\r
1479 Controller,\r
1480 &gEfiSDHostIoProtocolGuid,\r
1481 (VOID **)&SdHostIo,\r
1482 This->DriverBindingHandle,\r
1483 Controller,\r
1484 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1485 );\r
1486 if (!EFI_ERROR (Status)) {\r
1487 DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));\r
1488 return EFI_ALREADY_STARTED;\r
1489 }\r
1490\r
1491 //\r
1492 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1493 //\r
1494 OpenStatus = gBS->OpenProtocol (\r
1495 Controller,\r
1496 &gEfiPciIoProtocolGuid,\r
1497 (VOID **) &PciIo,\r
1498 This->DriverBindingHandle,\r
1499 Controller,\r
1500 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1501 );\r
1502\r
1503 if (EFI_ERROR (OpenStatus)) {\r
1504 return OpenStatus;\r
1505 }\r
1506\r
1507 Status = PciIo->Pci.Read (\r
1508 PciIo,\r
1509 EfiPciIoWidthUint8,\r
1510 PCI_CLASSCODE_OFFSET,\r
1511 sizeof (PCI_CLASSC) / sizeof (UINT8),\r
1512 &PciClass\r
1513 );\r
1514\r
1515 if (EFI_ERROR (Status)) {\r
1516 Status = EFI_UNSUPPORTED;\r
1517 goto ON_EXIT;\r
1518 }\r
1519\r
1520 //\r
1521 // Test whether the controller belongs to SD type\r
1522 //\r
1523 if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||\r
1524 (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||\r
1525 ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))\r
1526 ) {\r
1527\r
1528 Status = EFI_UNSUPPORTED;\r
1529 }\r
1530\r
1531ON_EXIT:\r
1532 gBS->CloseProtocol (\r
1533 Controller,\r
1534 &gEfiPciIoProtocolGuid,\r
1535 This->DriverBindingHandle,\r
1536 Controller\r
1537 );\r
1538\r
1539 return Status;\r
1540}\r
1541/**\r
1542 Starting the SD Host Controller Driver.\r
1543\r
1544 @param This Protocol instance pointer.\r
1545 @param Controller Handle of device to test.\r
1546 @param RemainingDevicePath Not used.\r
1547\r
1548 @retval EFI_SUCCESS This driver supports this device.\r
1549 @retval EFI_UNSUPPORTED This driver does not support this device.\r
1550 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
1551 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
1552\r
1553**/\r
1554EFI_STATUS\r
1555EFIAPI\r
1556SDControllerStart (\r
1557 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1558 IN EFI_HANDLE Controller,\r
1559 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1560 )\r
1561{\r
1562 EFI_STATUS Status;\r
1563 EFI_PCI_IO_PROTOCOL *PciIo;\r
1564 SDHOST_DATA *SDHostData;\r
1565 UINT32 Data;\r
1566\r
1567\r
1568 SDHostData = NULL;\r
1569 Data = 0;\r
1570\r
1571 //\r
1572 // Open PCI I/O Protocol and save pointer to open protocol\r
1573 // in private data area.\r
1574 //\r
1575 Status = gBS->OpenProtocol (\r
1576 Controller,\r
1577 &gEfiPciIoProtocolGuid,\r
1578 (VOID **) &PciIo,\r
1579 This->DriverBindingHandle,\r
1580 Controller,\r
1581 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1582 );\r
1583\r
1584 if (EFI_ERROR (Status)) {\r
1585 goto Exit;\r
1586 }\r
1587\r
1588 //\r
1589 // Enable the SD Host Controller MMIO space\r
1590 //\r
1591 Status = PciIo->Attributes (\r
1592 PciIo,\r
1593 EfiPciIoAttributeOperationEnable,\r
1594 EFI_PCI_DEVICE_ENABLE,\r
1595 NULL\r
1596 );\r
1597 if (EFI_ERROR (Status)) {\r
1598 Status = EFI_OUT_OF_RESOURCES;\r
1599 goto Exit;\r
1600 }\r
1601\r
1602\r
1603 SDHostData = (SDHOST_DATA*)AllocateZeroPool(sizeof (SDHOST_DATA));\r
1604 if (SDHostData == NULL) {\r
1605 Status = EFI_OUT_OF_RESOURCES;\r
1606 goto Exit;\r
1607 }\r
1608\r
1609 SDHostData->Signature = SDHOST_DATA_SIGNATURE;\r
1610 SDHostData->PciIo = PciIo;\r
1611\r
1612 CopyMem (&SDHostData->SDHostIo, &mSDHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));\r
1613\r
1614 ResetSDHost (&SDHostData->SDHostIo, Reset_All);\r
1615\r
1616 PciIo->Mem.Read (\r
1617 PciIo,\r
1618 EfiPciIoWidthUint16,\r
1619 0,\r
1620 (UINT64)MMIO_CTRLRVER,\r
1621 1,\r
1622 &Data\r
1623 );\r
1624 SDHostData->SDHostIo.HostCapability.HostVersion = Data & 0xFF;\r
1625 DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SDHostData->SDHostIo.HostCapability.HostVersion));\r
1626\r
1627 PciIo->Mem.Read (\r
1628 PciIo,\r
1629 EfiPciIoWidthUint32,\r
1630 0,\r
1631 (UINT64)MMIO_CAP,\r
1632 1,\r
1633 &Data\r
1634 );\r
1635 DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));\r
1636 if ((Data & BIT18) != 0) {\r
1637 SDHostData->SDHostIo.HostCapability.BusWidth8 = TRUE;\r
1638 }\r
1639\r
1640 if ((Data & BIT21) != 0) {\r
1641 SDHostData->SDHostIo.HostCapability.HighSpeedSupport = TRUE;\r
1642 }\r
1643\r
1644 if ((Data & BIT24) != 0) {\r
1645 SDHostData->SDHostIo.HostCapability.V33Support = TRUE;\r
1646 }\r
1647\r
1648 if ((Data & BIT25) != 0) {\r
1649 SDHostData->SDHostIo.HostCapability.V30Support = TRUE;\r
1650 }\r
1651\r
1652 if ((Data & BIT26) != 0) {\r
1653 SDHostData->SDHostIo.HostCapability.V18Support = TRUE;\r
1654 }\r
1655\r
1656 SDHostData->SDHostIo.HostCapability.BusWidth4 = TRUE;\r
1657\r
1658 if(SDHostData->SDHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {\r
1659\r
1660\r
1661\r
1662 SDHostData->BaseClockInMHz = (Data >> 8) & 0x3F;\r
1663 }\r
1664 else {\r
1665 SDHostData->BaseClockInMHz = (Data >> 8) & 0xFF;\r
1666\r
1667 }\r
1668\r
1669 SDHostData->BlockLength = 512 << ((Data >> 16) & 0x03);\r
1670 DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SDHostData->BlockLength));\r
1671 SDHostData->IsAutoStopCmd = TRUE;\r
1672\r
1673 Status = gBS->InstallProtocolInterface (\r
1674 &Controller,\r
1675 &gEfiSDHostIoProtocolGuid,\r
1676 EFI_NATIVE_INTERFACE,\r
1677 &SDHostData->SDHostIo\r
1678 );\r
1679 if (EFI_ERROR (Status)) {\r
1680 goto Exit;\r
1681 }\r
1682\r
1683 //\r
1684 // Install the component name protocol\r
1685 //\r
1686 SDHostData->ControllerNameTable = NULL;\r
1687\r
1688 AddUnicodeString2 (\r
1689 "eng",\r
1690 gSDControllerName.SupportedLanguages,\r
1691 &SDHostData->ControllerNameTable,\r
1692 L"SD Host Controller",\r
1693 TRUE\r
1694 );\r
1695 AddUnicodeString2 (\r
1696 "en",\r
1697 gSDControllerName2.SupportedLanguages,\r
1698 &SDHostData->ControllerNameTable,\r
1699 L"SD Host Controller",\r
1700 FALSE\r
1701 );\r
1702\r
1703Exit:\r
1704 if (EFI_ERROR (Status)) {\r
1705 if (SDHostData != NULL) {\r
1706 FreePool (SDHostData);\r
1707 }\r
1708 }\r
1709\r
1710 return Status;\r
1711}\r
1712\r
1713\r
1714/**\r
1715 Stop this driver on ControllerHandle. Support stoping any child handles\r
1716 created by this driver.\r
1717\r
1718 @param This Protocol instance pointer.\r
1719 @param Controller Handle of device to stop driver on.\r
1720 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
1721 @param ChildHandleBuffer List of handles for the children we need to stop.\r
1722\r
1723 @return EFI_SUCCESS\r
1724 @return others\r
1725\r
1726**/\r
1727EFI_STATUS\r
1728EFIAPI\r
1729SDControllerStop (\r
1730 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1731 IN EFI_HANDLE Controller,\r
1732 IN UINTN NumberOfChildren,\r
1733 IN EFI_HANDLE *ChildHandleBuffer\r
1734 )\r
1735{\r
1736 EFI_STATUS Status;\r
1737 EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
1738 SDHOST_DATA *SDHostData;\r
1739\r
1740 Status = gBS->OpenProtocol (\r
1741 Controller,\r
1742 &gEfiSDHostIoProtocolGuid,\r
1743 (VOID **) &SDHostIo,\r
1744 This->DriverBindingHandle,\r
1745 Controller,\r
1746 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1747 );\r
1748\r
1749 //\r
1750 // Test whether the Controller handler passed in is a valid\r
1751 // Usb controller handle that should be supported, if not,\r
1752 // return the error status directly\r
1753 //\r
1754 if (EFI_ERROR (Status)) {\r
1755 return Status;\r
1756 }\r
1757\r
1758 SetHostVoltage (SDHostIo, 0);\r
1759\r
1760 SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo);\r
1761\r
1762 //\r
1763 // Uninstall Block I/O protocol from the device handle\r
1764 //\r
1765 Status = gBS->UninstallProtocolInterface (\r
1766 Controller,\r
1767 &gEfiSDHostIoProtocolGuid,\r
1768 SDHostIo\r
1769 );\r
1770 if (EFI_ERROR (Status)) {\r
1771 return Status;\r
1772 }\r
1773\r
1774 FreeUnicodeStringTable (SDHostData->ControllerNameTable);\r
1775\r
1776 FreePool (SDHostData);\r
1777\r
1778 gBS->CloseProtocol (\r
1779 Controller,\r
1780 &gEfiPciIoProtocolGuid,\r
1781 This->DriverBindingHandle,\r
1782 Controller\r
1783 );\r
1784\r
1785 return EFI_SUCCESS;\r
1786}\r
1787\r
1788\r
1789\r