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