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