]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c
MdeModulePkg EmmcDxe: Fix GCC build failure with set but unused variables
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / EmmcBlockIoPei / EmmcHci.c
CommitLineData
48555339
FT
1/** @file\r
2\r
3 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
4 This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution. The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php.\r
8\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12**/\r
13\r
14#include "EmmcBlockIoPei.h"\r
15\r
16/**\r
17 Read/Write specified EMMC host controller mmio register.\r
18\r
19 @param[in] Address The address of the mmio register to be read/written.\r
20 @param[in] Read A boolean to indicate it's read or write operation.\r
21 @param[in] Count The width of the mmio register in bytes.\r
22 Must be 1, 2 , 4 or 8 bytes.\r
23 @param[in, out] Data For read operations, the destination buffer to store\r
24 the results. For write operations, the source buffer\r
25 to write data from. The caller is responsible for\r
26 having ownership of the data buffer and ensuring its\r
27 size not less than Count bytes.\r
28\r
29 @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.\r
30 @retval EFI_SUCCESS The read/write operation succeeds.\r
31 @retval Others The read/write operation fails.\r
32\r
33**/\r
34EFI_STATUS\r
35EFIAPI\r
36EmmcPeimHcRwMmio (\r
37 IN UINTN Address,\r
38 IN BOOLEAN Read,\r
39 IN UINT8 Count,\r
40 IN OUT VOID *Data\r
41 )\r
42{\r
43 if ((Address == 0) || (Data == NULL)) {\r
44 return EFI_INVALID_PARAMETER;\r
45 }\r
46\r
47 if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
48 return EFI_INVALID_PARAMETER;\r
49 }\r
50\r
51 switch (Count) {\r
52 case 1:\r
53 if (Read) {\r
54 *(UINT8*)Data = MmioRead8 (Address);\r
55 } else {\r
56 MmioWrite8 (Address, *(UINT8*)Data);\r
57 }\r
58 break;\r
59 case 2:\r
60 if (Read) {\r
61 *(UINT16*)Data = MmioRead16 (Address);\r
62 } else {\r
63 MmioWrite16 (Address, *(UINT16*)Data);\r
64 }\r
65 break;\r
66 case 4:\r
67 if (Read) {\r
68 *(UINT32*)Data = MmioRead32 (Address);\r
69 } else {\r
70 MmioWrite32 (Address, *(UINT32*)Data);\r
71 }\r
72 break;\r
73 case 8:\r
74 if (Read) {\r
75 *(UINT64*)Data = MmioRead64 (Address);\r
76 } else {\r
77 MmioWrite64 (Address, *(UINT64*)Data);\r
78 }\r
79 break;\r
80 default:\r
81 ASSERT (FALSE);\r
82 return EFI_INVALID_PARAMETER;\r
83 }\r
84\r
85 return EFI_SUCCESS;\r
86}\r
87\r
88/**\r
89 Do OR operation with the value of the specified EMMC host controller mmio register.\r
90\r
91 @param[in] Address The address of the mmio register to be read/written.\r
92 @param[in] Count The width of the mmio register in bytes.\r
93 Must be 1, 2 , 4 or 8 bytes.\r
94 @param[in] OrData The pointer to the data used to do OR operation.\r
95 The caller is responsible for having ownership of\r
96 the data buffer and ensuring its size not less than\r
97 Count bytes.\r
98\r
99 @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.\r
100 @retval EFI_SUCCESS The OR operation succeeds.\r
101 @retval Others The OR operation fails.\r
102\r
103**/\r
104EFI_STATUS\r
105EFIAPI\r
106EmmcPeimHcOrMmio (\r
107 IN UINTN Address,\r
108 IN UINT8 Count,\r
109 IN VOID *OrData\r
110 )\r
111{\r
112 EFI_STATUS Status;\r
113 UINT64 Data;\r
114 UINT64 Or;\r
115\r
116 Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);\r
117 if (EFI_ERROR (Status)) {\r
118 return Status;\r
119 }\r
120\r
121 if (Count == 1) {\r
122 Or = *(UINT8*) OrData;\r
123 } else if (Count == 2) {\r
124 Or = *(UINT16*) OrData;\r
125 } else if (Count == 4) {\r
126 Or = *(UINT32*) OrData;\r
127 } else if (Count == 8) {\r
128 Or = *(UINT64*) OrData;\r
129 } else {\r
130 return EFI_INVALID_PARAMETER;\r
131 }\r
132\r
133 Data |= Or;\r
134 Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);\r
135\r
136 return Status;\r
137}\r
138\r
139/**\r
140 Do AND operation with the value of the specified EMMC host controller mmio register.\r
141\r
142 @param[in] Address The address of the mmio register to be read/written.\r
143 @param[in] Count The width of the mmio register in bytes.\r
144 Must be 1, 2 , 4 or 8 bytes.\r
145 @param[in] AndData The pointer to the data used to do AND operation.\r
146 The caller is responsible for having ownership of\r
147 the data buffer and ensuring its size not less than\r
148 Count bytes.\r
149\r
150 @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.\r
151 @retval EFI_SUCCESS The AND operation succeeds.\r
152 @retval Others The AND operation fails.\r
153\r
154**/\r
155EFI_STATUS\r
156EFIAPI\r
157EmmcPeimHcAndMmio (\r
158 IN UINTN Address,\r
159 IN UINT8 Count,\r
160 IN VOID *AndData\r
161 )\r
162{\r
163 EFI_STATUS Status;\r
164 UINT64 Data;\r
165 UINT64 And;\r
166\r
167 Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);\r
168 if (EFI_ERROR (Status)) {\r
169 return Status;\r
170 }\r
171\r
172 if (Count == 1) {\r
173 And = *(UINT8*) AndData;\r
174 } else if (Count == 2) {\r
175 And = *(UINT16*) AndData;\r
176 } else if (Count == 4) {\r
177 And = *(UINT32*) AndData;\r
178 } else if (Count == 8) {\r
179 And = *(UINT64*) AndData;\r
180 } else {\r
181 return EFI_INVALID_PARAMETER;\r
182 }\r
183\r
184 Data &= And;\r
185 Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);\r
186\r
187 return Status;\r
188}\r
189\r
190/**\r
191 Wait for the value of the specified MMIO register set to the test value.\r
192\r
193 @param[in] Address The address of the mmio register to be checked.\r
194 @param[in] Count The width of the mmio register in bytes.\r
195 Must be 1, 2, 4 or 8 bytes.\r
196 @param[in] MaskValue The mask value of memory.\r
197 @param[in] TestValue The test value of memory.\r
198\r
199 @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.\r
200 @retval EFI_SUCCESS The MMIO register has expected value.\r
201 @retval Others The MMIO operation fails.\r
202\r
203**/\r
204EFI_STATUS\r
205EFIAPI\r
206EmmcPeimHcCheckMmioSet (\r
207 IN UINTN Address,\r
208 IN UINT8 Count,\r
209 IN UINT64 MaskValue,\r
210 IN UINT64 TestValue\r
211 )\r
212{\r
213 EFI_STATUS Status;\r
214 UINT64 Value;\r
215\r
216 //\r
217 // Access PCI MMIO space to see if the value is the tested one.\r
218 //\r
219 Value = 0;\r
220 Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Value);\r
221 if (EFI_ERROR (Status)) {\r
222 return Status;\r
223 }\r
224\r
225 Value &= MaskValue;\r
226\r
227 if (Value == TestValue) {\r
228 return EFI_SUCCESS;\r
229 }\r
230\r
231 return EFI_NOT_READY;\r
232}\r
233\r
234/**\r
235 Wait for the value of the specified MMIO register set to the test value.\r
236\r
237 @param[in] Address The address of the mmio register to wait.\r
238 @param[in] Count The width of the mmio register in bytes.\r
239 Must be 1, 2, 4 or 8 bytes.\r
240 @param[in] MaskValue The mask value of memory.\r
241 @param[in] TestValue The test value of memory.\r
242 @param[in] Timeout The time out value for wait memory set, uses 1\r
243 microsecond as a unit.\r
244\r
245 @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout\r
246 range.\r
247 @retval EFI_SUCCESS The MMIO register has expected value.\r
248 @retval Others The MMIO operation fails.\r
249\r
250**/\r
251EFI_STATUS\r
252EFIAPI\r
253EmmcPeimHcWaitMmioSet (\r
254 IN UINTN Address,\r
255 IN UINT8 Count,\r
256 IN UINT64 MaskValue,\r
257 IN UINT64 TestValue,\r
258 IN UINT64 Timeout\r
259 )\r
260{\r
261 EFI_STATUS Status;\r
262 BOOLEAN InfiniteWait;\r
263\r
264 if (Timeout == 0) {\r
265 InfiniteWait = TRUE;\r
266 } else {\r
267 InfiniteWait = FALSE;\r
268 }\r
269\r
270 while (InfiniteWait || (Timeout > 0)) {\r
271 Status = EmmcPeimHcCheckMmioSet (\r
272 Address,\r
273 Count,\r
274 MaskValue,\r
275 TestValue\r
276 );\r
277 if (Status != EFI_NOT_READY) {\r
278 return Status;\r
279 }\r
280\r
281 //\r
282 // Stall for 1 microsecond.\r
283 //\r
284 MicroSecondDelay (1);\r
285\r
286 Timeout--;\r
287 }\r
288\r
289 return EFI_TIMEOUT;\r
290}\r
291\r
292/**\r
293 Software reset the specified EMMC host controller and enable all interrupts.\r
294\r
295 @param[in] Bar The mmio base address of the slot to be accessed.\r
296\r
297 @retval EFI_SUCCESS The software reset executes successfully.\r
298 @retval Others The software reset fails.\r
299\r
300**/\r
301EFI_STATUS\r
302EmmcPeimHcReset (\r
303 IN UINTN Bar\r
304 )\r
305{\r
306 EFI_STATUS Status;\r
307 UINT8 SwReset;\r
308\r
309 SwReset = 0xFF;\r
310 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
311\r
312 if (EFI_ERROR (Status)) {\r
313 DEBUG ((EFI_D_ERROR, "EmmcPeimHcReset: write full 1 fails: %r\n", Status));\r
314 return Status;\r
315 }\r
316\r
317 Status = EmmcPeimHcWaitMmioSet (\r
318 Bar + EMMC_HC_SW_RST,\r
319 sizeof (SwReset),\r
320 0xFF,\r
321 0x00,\r
322 EMMC_TIMEOUT\r
323 );\r
324 if (EFI_ERROR (Status)) {\r
325 DEBUG ((EFI_D_INFO, "EmmcPeimHcReset: reset done with %r\n", Status));\r
326 return Status;\r
327 }\r
328 //\r
329 // Enable all interrupt after reset all.\r
330 //\r
331 Status = EmmcPeimHcEnableInterrupt (Bar);\r
332\r
333 return Status;\r
334}\r
335\r
336/**\r
337 Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
338 register.\r
339\r
340 @param[in] Bar The mmio base address of the slot to be accessed.\r
341\r
342 @retval EFI_SUCCESS The operation executes successfully.\r
343 @retval Others The operation fails.\r
344\r
345**/\r
346EFI_STATUS\r
347EmmcPeimHcEnableInterrupt (\r
348 IN UINTN Bar\r
349 )\r
350{\r
351 EFI_STATUS Status;\r
352 UINT16 IntStatus;\r
353\r
354 //\r
355 // Enable all bits in Error Interrupt Status Enable Register\r
356 //\r
357 IntStatus = 0xFFFF;\r
358 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
359 if (EFI_ERROR (Status)) {\r
360 return Status;\r
361 }\r
362 //\r
363 // Enable all bits in Normal Interrupt Status Enable Register\r
364 //\r
365 IntStatus = 0xFFFF;\r
366 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
367\r
368 return Status;\r
369}\r
370\r
371/**\r
372 Get the capability data from the specified slot.\r
373\r
374 @param[in] Bar The mmio base address of the slot to be accessed.\r
375 @param[out] Capability The buffer to store the capability data.\r
376\r
377 @retval EFI_SUCCESS The operation executes successfully.\r
378 @retval Others The operation fails.\r
379\r
380**/\r
381EFI_STATUS\r
382EmmcPeimHcGetCapability (\r
383 IN UINTN Bar,\r
384 OUT EMMC_HC_SLOT_CAP *Capability\r
385 )\r
386{\r
387 EFI_STATUS Status;\r
388 UINT64 Cap;\r
389\r
390 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CAP, TRUE, sizeof (Cap), &Cap);\r
391 if (EFI_ERROR (Status)) {\r
392 return Status;\r
393 }\r
394\r
395 CopyMem (Capability, &Cap, sizeof (Cap));\r
396\r
397 return EFI_SUCCESS;\r
398}\r
399\r
400/**\r
401 Detect whether there is a EMMC card attached at the specified EMMC host controller\r
402 slot.\r
403\r
404 Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
405\r
406 @param[in] Bar The mmio base address of the slot to be accessed.\r
407\r
408 @retval EFI_SUCCESS There is a EMMC card attached.\r
409 @retval EFI_NO_MEDIA There is not a EMMC card attached.\r
410 @retval Others The detection fails.\r
411\r
412**/\r
413EFI_STATUS\r
414EmmcPeimHcCardDetect (\r
415 IN UINTN Bar\r
416 )\r
417{\r
418 EFI_STATUS Status;\r
419 UINT16 Data;\r
420 UINT32 PresentState;\r
421\r
422 //\r
423 // Check Normal Interrupt Status Register\r
424 //\r
425 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);\r
426 if (EFI_ERROR (Status)) {\r
427 return Status;\r
428 }\r
429\r
430 if ((Data & (BIT6 | BIT7)) != 0) {\r
431 //\r
432 // Clear BIT6 and BIT7 by writing 1 to these two bits if set.\r
433 //\r
434 Data &= BIT6 | BIT7;\r
435 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);\r
436 if (EFI_ERROR (Status)) {\r
437 return Status;\r
438 }\r
439 }\r
440\r
441 //\r
442 // Check Present State Register to see if there is a card presented.\r
443 //\r
444 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
445 if (EFI_ERROR (Status)) {\r
446 return Status;\r
447 }\r
448\r
449 if ((PresentState & BIT16) != 0) {\r
450 return EFI_SUCCESS;\r
451 } else {\r
452 return EFI_NO_MEDIA;\r
453 }\r
454}\r
455\r
456/**\r
457 Stop EMMC card clock.\r
458\r
459 Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
460\r
461 @param[in] Bar The mmio base address of the slot to be accessed.\r
462\r
463 @retval EFI_SUCCESS Succeed to stop EMMC clock.\r
464 @retval Others Fail to stop EMMC clock.\r
465\r
466**/\r
467EFI_STATUS\r
468EmmcPeimHcStopClock (\r
469 IN UINTN Bar\r
470 )\r
471{\r
472 EFI_STATUS Status;\r
473 UINT32 PresentState;\r
474 UINT16 ClockCtrl;\r
475\r
476 //\r
477 // Ensure no SD transactions are occurring on the SD Bus by\r
478 // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)\r
479 // in the Present State register to be 0.\r
480 //\r
481 Status = EmmcPeimHcWaitMmioSet (\r
482 Bar + EMMC_HC_PRESENT_STATE,\r
483 sizeof (PresentState),\r
484 BIT0 | BIT1,\r
485 0,\r
486 EMMC_TIMEOUT\r
487 );\r
488 if (EFI_ERROR (Status)) {\r
489 return Status;\r
490 }\r
491\r
492 //\r
493 // Set SD Clock Enable in the Clock Control register to 0\r
494 //\r
495 ClockCtrl = (UINT16)~BIT2;\r
496 Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
497\r
498 return Status;\r
499}\r
500\r
501/**\r
502 EMMC card clock supply.\r
503\r
504 Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
505\r
506 @param[in] Bar The mmio base address of the slot to be accessed.\r
507 @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.\r
508\r
509 @retval EFI_SUCCESS The clock is supplied successfully.\r
510 @retval Others The clock isn't supplied successfully.\r
511\r
512**/\r
513EFI_STATUS\r
514EmmcPeimHcClockSupply (\r
515 IN UINTN Bar,\r
516 IN UINT64 ClockFreq\r
517 )\r
518{\r
519 EFI_STATUS Status;\r
520 EMMC_HC_SLOT_CAP Capability;\r
521 UINT32 BaseClkFreq;\r
522 UINT32 SettingFreq;\r
523 UINT32 Divisor;\r
524 UINT32 Remainder;\r
525 UINT16 ControllerVer;\r
526 UINT16 ClockCtrl;\r
527\r
528 //\r
529 // Calculate a divisor for SD clock frequency\r
530 //\r
531 Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
532 if (EFI_ERROR (Status)) {\r
533 return Status;\r
534 }\r
535 ASSERT (Capability.BaseClkFreq != 0);\r
536\r
537 BaseClkFreq = Capability.BaseClkFreq;\r
538 if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
539 return EFI_INVALID_PARAMETER;\r
540 }\r
541 //\r
542 // Calculate the divisor of base frequency.\r
543 //\r
544 Divisor = 0;\r
545 SettingFreq = BaseClkFreq * 1000;\r
546 while (ClockFreq < SettingFreq) {\r
547 Divisor++;\r
548\r
549 SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);\r
550 Remainder = (BaseClkFreq * 1000) % (2 * Divisor);\r
551 if ((ClockFreq == SettingFreq) && (Remainder == 0)) {\r
552 break;\r
553 }\r
554 if ((ClockFreq == SettingFreq) && (Remainder != 0)) {\r
555 SettingFreq ++;\r
556 }\r
557 }\r
558\r
559 DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
560\r
561 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
562 if (EFI_ERROR (Status)) {\r
563 return Status;\r
564 }\r
565 //\r
566 // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
567 //\r
568 if ((ControllerVer & 0xFF) == 2) {\r
569 ASSERT (Divisor <= 0x3FF);\r
570 ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
571 } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
572 //\r
573 // Only the most significant bit can be used as divisor.\r
574 //\r
575 if (((Divisor - 1) & Divisor) != 0) {\r
576 Divisor = 1 << (HighBitSet32 (Divisor) + 1);\r
577 }\r
578 ASSERT (Divisor <= 0x80);\r
579 ClockCtrl = (Divisor & 0xFF) << 8;\r
580 } else {\r
581 DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));\r
582 return EFI_UNSUPPORTED;\r
583 }\r
584\r
585 //\r
586 // Stop bus clock at first\r
587 //\r
588 Status = EmmcPeimHcStopClock (Bar);\r
589 if (EFI_ERROR (Status)) {\r
590 return Status;\r
591 }\r
592\r
593 //\r
594 // Supply clock frequency with specified divisor\r
595 //\r
596 ClockCtrl |= BIT0;\r
597 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);\r
598 if (EFI_ERROR (Status)) {\r
599 DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));\r
600 return Status;\r
601 }\r
602\r
603 //\r
604 // Wait Internal Clock Stable in the Clock Control register to be 1\r
605 //\r
606 Status = EmmcPeimHcWaitMmioSet (\r
607 Bar + EMMC_HC_CLOCK_CTRL,\r
608 sizeof (ClockCtrl),\r
609 BIT1,\r
610 BIT1,\r
611 EMMC_TIMEOUT\r
612 );\r
613 if (EFI_ERROR (Status)) {\r
614 return Status;\r
615 }\r
616\r
617 //\r
618 // Set SD Clock Enable in the Clock Control register to 1\r
619 //\r
620 ClockCtrl = BIT2;\r
621 Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
622\r
623 return Status;\r
624}\r
625\r
626/**\r
627 EMMC bus power control.\r
628\r
629 Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
630\r
631 @param[in] Bar The mmio base address of the slot to be accessed.\r
632 @param[in] PowerCtrl The value setting to the power control register.\r
633\r
634 @retval TRUE There is a EMMC card attached.\r
635 @retval FALSE There is no a EMMC card attached.\r
636\r
637**/\r
638EFI_STATUS\r
639EmmcPeimHcPowerControl (\r
640 IN UINTN Bar,\r
641 IN UINT8 PowerCtrl\r
642 )\r
643{\r
644 EFI_STATUS Status;\r
645\r
646 //\r
647 // Clr SD Bus Power\r
648 //\r
649 PowerCtrl &= (UINT8)~BIT0;\r
650 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
651 if (EFI_ERROR (Status)) {\r
652 return Status;\r
653 }\r
654\r
655 //\r
656 // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
657 //\r
658 PowerCtrl |= BIT0;\r
659 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
660\r
661 return Status;\r
662}\r
663\r
664/**\r
665 Set the EMMC bus width.\r
666\r
667 Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
668\r
669 @param[in] Bar The mmio base address of the slot to be accessed.\r
670 @param[in] BusWidth The bus width used by the EMMC device, it must be 1, 4 or 8.\r
671\r
672 @retval EFI_SUCCESS The bus width is set successfully.\r
673 @retval Others The bus width isn't set successfully.\r
674\r
675**/\r
676EFI_STATUS\r
677EmmcPeimHcSetBusWidth (\r
678 IN UINTN Bar,\r
679 IN UINT16 BusWidth\r
680 )\r
681{\r
682 EFI_STATUS Status;\r
683 UINT8 HostCtrl1;\r
684\r
685 if (BusWidth == 1) {\r
686 HostCtrl1 = (UINT8)~(BIT5 | BIT1);\r
687 Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
688 } else if (BusWidth == 4) {\r
689 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
690 if (EFI_ERROR (Status)) {\r
691 return Status;\r
692 }\r
693 HostCtrl1 |= BIT1;\r
694 HostCtrl1 &= (UINT8)~BIT5;\r
695 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
696 } else if (BusWidth == 8) {\r
697 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
698 if (EFI_ERROR (Status)) {\r
699 return Status;\r
700 }\r
701 HostCtrl1 &= (UINT8)~BIT1;\r
702 HostCtrl1 |= BIT5;\r
703 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
704 } else {\r
705 ASSERT (FALSE);\r
706 return EFI_INVALID_PARAMETER;\r
707 }\r
708\r
709 return Status;\r
710}\r
711\r
712/**\r
713 Supply EMMC card with lowest clock frequency at initialization.\r
714\r
715 @param[in] Bar The mmio base address of the slot to be accessed.\r
716\r
717 @retval EFI_SUCCESS The clock is supplied successfully.\r
718 @retval Others The clock isn't supplied successfully.\r
719\r
720**/\r
721EFI_STATUS\r
722EmmcPeimHcInitClockFreq (\r
723 IN UINTN Bar\r
724 )\r
725{\r
726 EFI_STATUS Status;\r
727 EMMC_HC_SLOT_CAP Capability;\r
728 UINT32 InitFreq;\r
729\r
730 //\r
731 // Calculate a divisor for SD clock frequency\r
732 //\r
733 Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
734 if (EFI_ERROR (Status)) {\r
735 return Status;\r
736 }\r
737\r
738 if (Capability.BaseClkFreq == 0) {\r
739 //\r
740 // Don't support get Base Clock Frequency information via another method\r
741 //\r
742 return EFI_UNSUPPORTED;\r
743 }\r
744 //\r
745 // Supply 400KHz clock frequency at initialization phase.\r
746 //\r
747 InitFreq = 400;\r
748 Status = EmmcPeimHcClockSupply (Bar, InitFreq);\r
749 return Status;\r
750}\r
751\r
752/**\r
753 Supply EMMC card with maximum voltage at initialization.\r
754\r
755 Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
756\r
757 @param[in] Bar The mmio base address of the slot to be accessed.\r
758\r
759 @retval EFI_SUCCESS The voltage is supplied successfully.\r
760 @retval Others The voltage isn't supplied successfully.\r
761\r
762**/\r
763EFI_STATUS\r
764EmmcPeimHcInitPowerVoltage (\r
765 IN UINTN Bar\r
766 )\r
767{\r
768 EFI_STATUS Status;\r
769 EMMC_HC_SLOT_CAP Capability;\r
770 UINT8 MaxVoltage;\r
771 UINT8 HostCtrl2;\r
772\r
773 //\r
774 // Get the support voltage of the Host Controller\r
775 //\r
776 Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
777 if (EFI_ERROR (Status)) {\r
778 return Status;\r
779 }\r
780 //\r
781 // Calculate supported maximum voltage according to SD Bus Voltage Select\r
782 //\r
783 if (Capability.Voltage33 != 0) {\r
784 //\r
785 // Support 3.3V\r
786 //\r
787 MaxVoltage = 0x0E;\r
788 } else if (Capability.Voltage30 != 0) {\r
789 //\r
790 // Support 3.0V\r
791 //\r
792 MaxVoltage = 0x0C;\r
793 } else if (Capability.Voltage18 != 0) {\r
794 //\r
795 // Support 1.8V\r
796 //\r
797 MaxVoltage = 0x0A;\r
798 HostCtrl2 = BIT3;\r
799 Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
800 if (EFI_ERROR (Status)) {\r
801 return Status;\r
802 }\r
803 MicroSecondDelay (5000);\r
804 } else {\r
805 ASSERT (FALSE);\r
806 return EFI_DEVICE_ERROR;\r
807 }\r
808\r
809 //\r
810 // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
811 //\r
812 Status = EmmcPeimHcPowerControl (Bar, MaxVoltage);\r
813\r
814 return Status;\r
815}\r
816\r
817/**\r
818 Initialize the Timeout Control register with most conservative value at initialization.\r
819\r
820 Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
821\r
822 @param[in] Bar The mmio base address of the slot to be accessed.\r
823\r
824 @retval EFI_SUCCESS The timeout control register is configured successfully.\r
825 @retval Others The timeout control register isn't configured successfully.\r
826\r
827**/\r
828EFI_STATUS\r
829EmmcPeimHcInitTimeoutCtrl (\r
830 IN UINTN Bar\r
831 )\r
832{\r
833 EFI_STATUS Status;\r
834 UINT8 Timeout;\r
835\r
836 Timeout = 0x0E;\r
837 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);\r
838\r
839 return Status;\r
840}\r
841\r
842/**\r
843 Initial EMMC host controller with lowest clock frequency, max power and max timeout value\r
844 at initialization.\r
845\r
846 @param[in] Bar The mmio base address of the slot to be accessed.\r
847\r
848 @retval EFI_SUCCESS The host controller is initialized successfully.\r
849 @retval Others The host controller isn't initialized successfully.\r
850\r
851**/\r
852EFI_STATUS\r
853EmmcPeimHcInitHost (\r
854 IN UINTN Bar\r
855 )\r
856{\r
857 EFI_STATUS Status;\r
858\r
859 Status = EmmcPeimHcInitClockFreq (Bar);\r
860 if (EFI_ERROR (Status)) {\r
861 return Status;\r
862 }\r
863\r
864 Status = EmmcPeimHcInitPowerVoltage (Bar);\r
865 if (EFI_ERROR (Status)) {\r
866 return Status;\r
867 }\r
868\r
869 Status = EmmcPeimHcInitTimeoutCtrl (Bar);\r
870 return Status;\r
871}\r
872\r
873/**\r
874 Turn on/off LED.\r
875\r
876 @param[in] Bar The mmio base address of the slot to be accessed.\r
877 @param[in] On The boolean to turn on/off LED.\r
878\r
879 @retval EFI_SUCCESS The LED is turned on/off successfully.\r
880 @retval Others The LED isn't turned on/off successfully.\r
881\r
882**/\r
883EFI_STATUS\r
884EmmcPeimHcLedOnOff (\r
885 IN UINTN Bar,\r
886 IN BOOLEAN On\r
887 )\r
888{\r
889 EFI_STATUS Status;\r
890 UINT8 HostCtrl1;\r
891\r
892 if (On) {\r
893 HostCtrl1 = BIT0;\r
894 Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
895 } else {\r
896 HostCtrl1 = (UINT8)~BIT0;\r
897 Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
898 }\r
899\r
900 return Status;\r
901}\r
902\r
903/**\r
904 Build ADMA descriptor table for transfer.\r
905\r
906 Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
907\r
908 @param[in] Trb The pointer to the EMMC_TRB instance.\r
909\r
910 @retval EFI_SUCCESS The ADMA descriptor table is created successfully.\r
911 @retval Others The ADMA descriptor table isn't created successfully.\r
912\r
913**/\r
914EFI_STATUS\r
915BuildAdmaDescTable (\r
916 IN EMMC_TRB *Trb\r
917 )\r
918{\r
919 EFI_PHYSICAL_ADDRESS Data;\r
920 UINT64 DataLen;\r
921 UINT64 Entries;\r
922 UINT32 Index;\r
923 UINT64 Remaining;\r
924 UINT32 Address;\r
925\r
926 Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Trb->Data;\r
927 DataLen = Trb->DataLen;\r
928 //\r
929 // Only support 32bit ADMA Descriptor Table\r
930 //\r
931 if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
932 return EFI_INVALID_PARAMETER;\r
933 }\r
934 //\r
935 // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
936 // for 32-bit address descriptor table.\r
937 //\r
938 if ((Data & (BIT0 | BIT1)) != 0) {\r
939 DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
940 }\r
941\r
942 Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
943\r
944 Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (EMMC_HC_ADMA_DESC_LINE));\r
945 Trb->AdmaDesc = EmmcPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);\r
946 if (Trb->AdmaDesc == NULL) {\r
947 return EFI_OUT_OF_RESOURCES;\r
948 }\r
949\r
950 Remaining = DataLen;\r
951 Address = (UINT32)Data;\r
952 for (Index = 0; Index < Entries; Index++) {\r
953 if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
954 Trb->AdmaDesc[Index].Valid = 1;\r
955 Trb->AdmaDesc[Index].Act = 2;\r
956 Trb->AdmaDesc[Index].Length = (UINT16)Remaining;\r
957 Trb->AdmaDesc[Index].Address = Address;\r
958 break;\r
959 } else {\r
960 Trb->AdmaDesc[Index].Valid = 1;\r
961 Trb->AdmaDesc[Index].Act = 2;\r
962 Trb->AdmaDesc[Index].Length = 0;\r
963 Trb->AdmaDesc[Index].Address = Address;\r
964 }\r
965\r
966 Remaining -= ADMA_MAX_DATA_PER_LINE;\r
967 Address += ADMA_MAX_DATA_PER_LINE;\r
968 }\r
969\r
970 //\r
971 // Set the last descriptor line as end of descriptor table\r
972 //\r
973 Trb->AdmaDesc[Index].End = 1;\r
974 return EFI_SUCCESS;\r
975}\r
976\r
977/**\r
978 Create a new TRB for the EMMC cmd request.\r
979\r
980 @param[in] Slot The slot number of the EMMC card to send the command to.\r
981 @param[in] Packet A pointer to the SD command data structure.\r
982\r
983 @return Created Trb or NULL.\r
984\r
985**/\r
986EMMC_TRB *\r
987EmmcPeimCreateTrb (\r
988 IN EMMC_PEIM_HC_SLOT *Slot,\r
989 IN EMMC_COMMAND_PACKET *Packet\r
990 )\r
991{\r
992 EMMC_TRB *Trb;\r
993 EFI_STATUS Status;\r
994 EMMC_HC_SLOT_CAP Capability;\r
995\r
996 //\r
997 // Calculate a divisor for SD clock frequency\r
998 //\r
999 Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);\r
1000 if (EFI_ERROR (Status)) {\r
1001 return NULL;\r
1002 }\r
1003\r
1004 Trb = EmmcPeimAllocateMem (Slot->Private->Pool, sizeof (EMMC_TRB));\r
1005 if (Trb == NULL) {\r
1006 return NULL;\r
1007 }\r
1008\r
1009 Trb->Slot = Slot;\r
1010 Trb->BlockSize = 0x200;\r
1011 Trb->Packet = Packet;\r
1012 Trb->Timeout = Packet->Timeout;\r
1013\r
1014 if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
1015 Trb->Data = Packet->InDataBuffer;\r
1016 Trb->DataLen = Packet->InTransferLength;\r
1017 Trb->Read = TRUE;\r
1018 } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {\r
1019 Trb->Data = Packet->OutDataBuffer;\r
1020 Trb->DataLen = Packet->OutTransferLength;\r
1021 Trb->Read = FALSE;\r
1022 } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {\r
1023 Trb->Data = NULL;\r
1024 Trb->DataLen = 0;\r
1025 } else {\r
1026 goto Error;\r
1027 }\r
1028\r
1029 if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
1030 if (Trb->DataLen < Trb->BlockSize) {\r
1031 Trb->BlockSize = (UINT16)Trb->DataLen;\r
1032 }\r
1033 }\r
1034\r
1035 if (Trb->DataLen == 0) {\r
1036 Trb->Mode = EmmcNoData;\r
1037 } else if (Capability.Adma2 != 0) {\r
1038 Trb->Mode = EmmcAdmaMode;\r
1039 Status = BuildAdmaDescTable (Trb);\r
1040 if (EFI_ERROR (Status)) {\r
1041 goto Error;\r
1042 }\r
1043 } else if (Capability.Sdma != 0) {\r
1044 Trb->Mode = EmmcSdmaMode;\r
1045 } else {\r
1046 Trb->Mode = EmmcPioMode;\r
1047 }\r
1048\r
1049 return Trb;\r
1050\r
1051Error:\r
1052 EmmcPeimFreeTrb (Trb);\r
1053 return NULL;\r
1054}\r
1055\r
1056/**\r
1057 Free the resource used by the TRB.\r
1058\r
1059 @param[in] Trb The pointer to the EMMC_TRB instance.\r
1060\r
1061**/\r
1062VOID\r
1063EmmcPeimFreeTrb (\r
1064 IN EMMC_TRB *Trb\r
1065 )\r
1066{\r
1067 if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
1068 EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);\r
1069 }\r
1070\r
1071 if (Trb != NULL) {\r
1072 EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb, sizeof (EMMC_TRB));\r
1073 }\r
1074 return;\r
1075}\r
1076\r
1077/**\r
1078 Check if the env is ready for execute specified TRB.\r
1079\r
1080 @param[in] Bar The mmio base address of the slot to be accessed.\r
1081 @param[in] Trb The pointer to the EMMC_TRB instance.\r
1082\r
1083 @retval EFI_SUCCESS The env is ready for TRB execution.\r
1084 @retval EFI_NOT_READY The env is not ready for TRB execution.\r
1085 @retval Others Some erros happen.\r
1086\r
1087**/\r
1088EFI_STATUS\r
1089EmmcPeimCheckTrbEnv (\r
1090 IN UINTN Bar,\r
1091 IN EMMC_TRB *Trb\r
1092 )\r
1093{\r
1094 EFI_STATUS Status;\r
1095 EMMC_COMMAND_PACKET *Packet;\r
1096 UINT32 PresentState;\r
1097\r
1098 Packet = Trb->Packet;\r
1099\r
1100 if ((Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) ||\r
1101 (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR1b) ||\r
1102 (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR5b)) {\r
1103 //\r
1104 // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in\r
1105 // the Present State register to be 0\r
1106 //\r
1107 PresentState = BIT0 | BIT1;\r
1108 if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {\r
1109 PresentState = BIT0;\r
1110 }\r
1111 } else {\r
1112 //\r
1113 // Wait Command Inhibit (CMD) in the Present State register\r
1114 // to be 0\r
1115 //\r
1116 PresentState = BIT0;\r
1117 }\r
1118\r
1119 Status = EmmcPeimHcCheckMmioSet (\r
1120 Bar + EMMC_HC_PRESENT_STATE,\r
1121 sizeof (PresentState),\r
1122 PresentState,\r
1123 0\r
1124 );\r
1125\r
1126 return Status;\r
1127}\r
1128\r
1129/**\r
1130 Wait for the env to be ready for execute specified TRB.\r
1131\r
1132 @param[in] Bar The mmio base address of the slot to be accessed.\r
1133 @param[in] Trb The pointer to the EMMC_TRB instance.\r
1134\r
1135 @retval EFI_SUCCESS The env is ready for TRB execution.\r
1136 @retval EFI_TIMEOUT The env is not ready for TRB execution in time.\r
1137 @retval Others Some erros happen.\r
1138\r
1139**/\r
1140EFI_STATUS\r
1141EmmcPeimWaitTrbEnv (\r
1142 IN UINTN Bar,\r
1143 IN EMMC_TRB *Trb\r
1144 )\r
1145{\r
1146 EFI_STATUS Status;\r
1147 EMMC_COMMAND_PACKET *Packet;\r
1148 UINT64 Timeout;\r
1149 BOOLEAN InfiniteWait;\r
1150\r
1151 //\r
1152 // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
1153 //\r
1154 Packet = Trb->Packet;\r
1155 Timeout = Packet->Timeout;\r
1156 if (Timeout == 0) {\r
1157 InfiniteWait = TRUE;\r
1158 } else {\r
1159 InfiniteWait = FALSE;\r
1160 }\r
1161\r
1162 while (InfiniteWait || (Timeout > 0)) {\r
1163 //\r
1164 // Check Trb execution result by reading Normal Interrupt Status register.\r
1165 //\r
1166 Status = EmmcPeimCheckTrbEnv (Bar, Trb);\r
1167 if (Status != EFI_NOT_READY) {\r
1168 return Status;\r
1169 }\r
1170 //\r
1171 // Stall for 1 microsecond.\r
1172 //\r
1173 MicroSecondDelay (1);\r
1174\r
1175 Timeout--;\r
1176 }\r
1177\r
1178 return EFI_TIMEOUT;\r
1179}\r
1180\r
1181/**\r
1182 Execute the specified TRB.\r
1183\r
1184 @param[in] Bar The mmio base address of the slot to be accessed.\r
1185 @param[in] Trb The pointer to the EMMC_TRB instance.\r
1186\r
1187 @retval EFI_SUCCESS The TRB is sent to host controller successfully.\r
1188 @retval Others Some erros happen when sending this request to the host controller.\r
1189\r
1190**/\r
1191EFI_STATUS\r
1192EmmcPeimExecTrb (\r
1193 IN UINTN Bar,\r
1194 IN EMMC_TRB *Trb\r
1195 )\r
1196{\r
1197 EFI_STATUS Status;\r
1198 EMMC_COMMAND_PACKET *Packet;\r
1199 UINT16 Cmd;\r
1200 UINT16 IntStatus;\r
1201 UINT32 Argument;\r
1202 UINT16 BlkCount;\r
1203 UINT16 BlkSize;\r
1204 UINT16 TransMode;\r
1205 UINT8 HostCtrl1;\r
1206 UINT32 SdmaAddr;\r
1207 UINT64 AdmaAddr;\r
1208\r
1209 Packet = Trb->Packet;\r
1210 //\r
1211 // Clear all bits in Error Interrupt Status Register\r
1212 //\r
1213 IntStatus = 0xFFFF;\r
1214 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
1215 if (EFI_ERROR (Status)) {\r
1216 return Status;\r
1217 }\r
1218 //\r
1219 // Clear all bits in Normal Interrupt Status Register\r
1220 //\r
1221 IntStatus = 0xFFFF;\r
1222 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
1223 if (EFI_ERROR (Status)) {\r
1224 return Status;\r
1225 }\r
1226 //\r
1227 // Set Host Control 1 register DMA Select field\r
1228 //\r
1229 if (Trb->Mode == EmmcAdmaMode) {\r
1230 HostCtrl1 = BIT4;\r
1231 Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
1232 if (EFI_ERROR (Status)) {\r
1233 return Status;\r
1234 }\r
1235 }\r
1236\r
1237 EmmcPeimHcLedOnOff (Bar, TRUE);\r
1238\r
1239 if (Trb->Mode == EmmcSdmaMode) {\r
1240 if ((UINT64)(UINTN)Trb->Data >= 0x100000000ul) {\r
1241 return EFI_INVALID_PARAMETER;\r
1242 }\r
1243\r
1244 SdmaAddr = (UINT32)(UINTN)Trb->Data;\r
1245 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
1246 if (EFI_ERROR (Status)) {\r
1247 return Status;\r
1248 }\r
1249 } else if (Trb->Mode == EmmcAdmaMode) {\r
1250 AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;\r
1251 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
1252 if (EFI_ERROR (Status)) {\r
1253 return Status;\r
1254 }\r
1255 }\r
1256\r
1257 BlkSize = Trb->BlockSize;\r
1258 if (Trb->Mode == EmmcSdmaMode) {\r
1259 //\r
1260 // Set SDMA boundary to be 512K bytes.\r
1261 //\r
1262 BlkSize |= 0x7000;\r
1263 }\r
1264\r
1265 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);\r
1266 if (EFI_ERROR (Status)) {\r
1267 return Status;\r
1268 }\r
1269\r
1270 BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
1271 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
1272 if (EFI_ERROR (Status)) {\r
1273 return Status;\r
1274 }\r
1275\r
1276 Argument = Packet->EmmcCmdBlk->CommandArgument;\r
1277 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);\r
1278 if (EFI_ERROR (Status)) {\r
1279 return Status;\r
1280 }\r
1281\r
1282 TransMode = 0;\r
1283 if (Trb->Mode != EmmcNoData) {\r
1284 if (Trb->Mode != EmmcPioMode) {\r
1285 TransMode |= BIT0;\r
1286 }\r
1287 if (Trb->Read) {\r
1288 TransMode |= BIT4;\r
1289 }\r
1290 if (BlkCount != 0) {\r
1291 TransMode |= BIT5 | BIT1;\r
1292 }\r
1293 }\r
1294\r
1295 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);\r
1296 if (EFI_ERROR (Status)) {\r
1297 return Status;\r
1298 }\r
1299\r
1300 Cmd = (UINT16)LShiftU64(Packet->EmmcCmdBlk->CommandIndex, 8);\r
1301 if (Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) {\r
1302 Cmd |= BIT5;\r
1303 }\r
1304 //\r
1305 // Convert ResponseType to value\r
1306 //\r
1307 if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {\r
1308 switch (Packet->EmmcCmdBlk->ResponseType) {\r
1309 case EmmcResponceTypeR1:\r
1310 case EmmcResponceTypeR5:\r
1311 case EmmcResponceTypeR6:\r
1312 case EmmcResponceTypeR7:\r
1313 Cmd |= (BIT1 | BIT3 | BIT4);\r
1314 break;\r
1315 case EmmcResponceTypeR2:\r
1316 Cmd |= (BIT0 | BIT3);\r
1317 break;\r
1318 case EmmcResponceTypeR3:\r
1319 case EmmcResponceTypeR4:\r
1320 Cmd |= BIT1;\r
1321 break;\r
1322 case EmmcResponceTypeR1b:\r
1323 case EmmcResponceTypeR5b:\r
1324 Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);\r
1325 break;\r
1326 default:\r
1327 ASSERT (FALSE);\r
1328 break;\r
1329 }\r
1330 }\r
1331 //\r
1332 // Execute cmd\r
1333 //\r
1334 Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);\r
1335 return Status;\r
1336}\r
1337\r
1338/**\r
1339 Check the TRB execution result.\r
1340\r
1341 @param[in] Bar The mmio base address of the slot to be accessed.\r
1342 @param[in] Trb The pointer to the EMMC_TRB instance.\r
1343\r
1344 @retval EFI_SUCCESS The TRB is executed successfully.\r
1345 @retval EFI_NOT_READY The TRB is not completed for execution.\r
1346 @retval Others Some erros happen when executing this request.\r
1347\r
1348**/\r
1349EFI_STATUS\r
1350EmmcPeimCheckTrbResult (\r
1351 IN UINTN Bar,\r
1352 IN EMMC_TRB *Trb\r
1353 )\r
1354{\r
1355 EFI_STATUS Status;\r
1356 EMMC_COMMAND_PACKET *Packet;\r
1357 UINT16 IntStatus;\r
1358 UINT32 Response[4];\r
1359 UINT32 SdmaAddr;\r
1360 UINT8 Index;\r
1361 UINT8 SwReset;\r
1362\r
1363 SwReset = 0;\r
1364 Packet = Trb->Packet;\r
1365 //\r
1366 // Check Trb execution result by reading Normal Interrupt Status register.\r
1367 //\r
1368 Status = EmmcPeimHcRwMmio (\r
1369 Bar + EMMC_HC_NOR_INT_STS,\r
1370 TRUE,\r
1371 sizeof (IntStatus),\r
1372 &IntStatus\r
1373 );\r
1374 if (EFI_ERROR (Status)) {\r
1375 goto Done;\r
1376 }\r
1377 //\r
1378 // Check Transfer Complete bit is set or not.\r
1379 //\r
1380 if ((IntStatus & BIT1) == BIT1) {\r
1381 if ((IntStatus & BIT15) == BIT15) {\r
1382 //\r
1383 // Read Error Interrupt Status register to check if the error is\r
1384 // Data Timeout Error.\r
1385 // If yes, treat it as success as Transfer Complete has higher\r
1386 // priority than Data Timeout Error.\r
1387 //\r
1388 Status = EmmcPeimHcRwMmio (\r
1389 Bar + EMMC_HC_ERR_INT_STS,\r
1390 TRUE,\r
1391 sizeof (IntStatus),\r
1392 &IntStatus\r
1393 );\r
1394 if (!EFI_ERROR (Status)) {\r
1395 if ((IntStatus & BIT4) == BIT4) {\r
1396 Status = EFI_SUCCESS;\r
1397 } else {\r
1398 Status = EFI_DEVICE_ERROR;\r
1399 }\r
1400 }\r
1401 }\r
1402\r
1403 goto Done;\r
1404 }\r
1405 //\r
1406 // Check if there is a error happened during cmd execution.\r
1407 // If yes, then do error recovery procedure to follow SD Host Controller\r
1408 // Simplified Spec 3.0 section 3.10.1.\r
1409 //\r
1410 if ((IntStatus & BIT15) == BIT15) {\r
1411 Status = EmmcPeimHcRwMmio (\r
1412 Bar + EMMC_HC_ERR_INT_STS,\r
1413 TRUE,\r
1414 sizeof (IntStatus),\r
1415 &IntStatus\r
1416 );\r
1417 if (EFI_ERROR (Status)) {\r
1418 goto Done;\r
1419 }\r
1420\r
1421 if ((IntStatus & 0x0F) != 0) {\r
1422 SwReset |= BIT1;\r
1423 }\r
1424 if ((IntStatus & 0xF0) != 0) {\r
1425 SwReset |= BIT2;\r
1426 }\r
1427\r
1428 Status = EmmcPeimHcRwMmio (\r
1429 Bar + EMMC_HC_SW_RST,\r
1430 FALSE,\r
1431 sizeof (SwReset),\r
1432 &SwReset\r
1433 );\r
1434 if (EFI_ERROR (Status)) {\r
1435 goto Done;\r
1436 }\r
1437 Status = EmmcPeimHcWaitMmioSet (\r
1438 Bar + EMMC_HC_SW_RST,\r
1439 sizeof (SwReset),\r
1440 0xFF,\r
1441 0,\r
1442 EMMC_TIMEOUT\r
1443 );\r
1444 if (EFI_ERROR (Status)) {\r
1445 goto Done;\r
1446 }\r
1447\r
1448 Status = EFI_DEVICE_ERROR;\r
1449 goto Done;\r
1450 }\r
1451 //\r
1452 // Check if DMA interrupt is signalled for the SDMA transfer.\r
1453 //\r
1454 if ((Trb->Mode == EmmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {\r
1455 //\r
1456 // Clear DMA interrupt bit.\r
1457 //\r
1458 IntStatus = BIT3;\r
1459 Status = EmmcPeimHcRwMmio (\r
1460 Bar + EMMC_HC_NOR_INT_STS,\r
1461 FALSE,\r
1462 sizeof (IntStatus),\r
1463 &IntStatus\r
1464 );\r
1465 if (EFI_ERROR (Status)) {\r
1466 goto Done;\r
1467 }\r
1468 //\r
1469 // Update SDMA Address register.\r
1470 //\r
1471 SdmaAddr = EMMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->Data, EMMC_SDMA_BOUNDARY);\r
1472 Status = EmmcPeimHcRwMmio (\r
1473 Bar + EMMC_HC_SDMA_ADDR,\r
1474 FALSE,\r
1475 sizeof (UINT32),\r
1476 &SdmaAddr\r
1477 );\r
1478 if (EFI_ERROR (Status)) {\r
1479 goto Done;\r
1480 }\r
1481 Trb->Data = (VOID*)(UINTN)SdmaAddr;\r
1482 }\r
1483\r
1484 if ((Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeAdtc) &&\r
1485 (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR1b) &&\r
1486 (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR5b)) {\r
1487 if ((IntStatus & BIT0) == BIT0) {\r
1488 Status = EFI_SUCCESS;\r
1489 goto Done;\r
1490 }\r
1491 }\r
1492\r
1493 if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {\r
1494 Status = EFI_SUCCESS;\r
1495 goto Done;\r
1496 }\r
1497\r
1498 Status = EFI_NOT_READY;\r
1499Done:\r
1500 //\r
1501 // Get response data when the cmd is executed successfully.\r
1502 //\r
1503 if (!EFI_ERROR (Status)) {\r
1504 if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {\r
1505 for (Index = 0; Index < 4; Index++) {\r
1506 Status = EmmcPeimHcRwMmio (\r
1507 Bar + EMMC_HC_RESPONSE + Index * 4,\r
1508 TRUE,\r
1509 sizeof (UINT32),\r
1510 &Response[Index]\r
1511 );\r
1512 if (EFI_ERROR (Status)) {\r
1513 EmmcPeimHcLedOnOff (Bar, FALSE);\r
1514 return Status;\r
1515 }\r
1516 }\r
1517 CopyMem (Packet->EmmcStatusBlk, Response, sizeof (Response));\r
1518 }\r
1519 }\r
1520\r
1521 if (Status != EFI_NOT_READY) {\r
1522 EmmcPeimHcLedOnOff (Bar, FALSE);\r
1523 }\r
1524\r
1525 return Status;\r
1526}\r
1527\r
1528/**\r
1529 Wait for the TRB execution result.\r
1530\r
1531 @param[in] Bar The mmio base address of the slot to be accessed.\r
1532 @param[in] Trb The pointer to the EMMC_TRB instance.\r
1533\r
1534 @retval EFI_SUCCESS The TRB is executed successfully.\r
1535 @retval Others Some erros happen when executing this request.\r
1536\r
1537**/\r
1538EFI_STATUS\r
1539EmmcPeimWaitTrbResult (\r
1540 IN UINTN Bar,\r
1541 IN EMMC_TRB *Trb\r
1542 )\r
1543{\r
1544 EFI_STATUS Status;\r
1545 EMMC_COMMAND_PACKET *Packet;\r
1546 UINT64 Timeout;\r
1547 BOOLEAN InfiniteWait;\r
1548\r
1549 Packet = Trb->Packet;\r
1550 //\r
1551 // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
1552 //\r
1553 Timeout = Packet->Timeout;\r
1554 if (Timeout == 0) {\r
1555 InfiniteWait = TRUE;\r
1556 } else {\r
1557 InfiniteWait = FALSE;\r
1558 }\r
1559\r
1560 while (InfiniteWait || (Timeout > 0)) {\r
1561 //\r
1562 // Check Trb execution result by reading Normal Interrupt Status register.\r
1563 //\r
1564 Status = EmmcPeimCheckTrbResult (Bar, Trb);\r
1565 if (Status != EFI_NOT_READY) {\r
1566 return Status;\r
1567 }\r
1568 //\r
1569 // Stall for 1 microsecond.\r
1570 //\r
1571 MicroSecondDelay (1);\r
1572\r
1573 Timeout--;\r
1574 }\r
1575\r
1576 return EFI_TIMEOUT;\r
1577}\r
1578\r
1579/**\r
1580 Sends EMMC command to an EMMC card that is attached to the EMMC controller.\r
1581\r
1582 If Packet is successfully sent to the EMMC card, then EFI_SUCCESS is returned.\r
1583\r
1584 If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
1585\r
1586 If Slot is not in a valid range for the EMMC controller, then EFI_INVALID_PARAMETER\r
1587 is returned.\r
1588\r
1589 If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
1590 EFI_INVALID_PARAMETER is returned.\r
1591\r
1592 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1593 @param[in,out] Packet A pointer to the EMMC command data structure.\r
1594\r
1595 @retval EFI_SUCCESS The EMMC Command Packet was sent by the host.\r
1596 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD\r
1597 command Packet.\r
1598 @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
1599 @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
1600 OutDataBuffer are NULL.\r
1601 @retval EFI_NO_MEDIA SD Device not present in the Slot.\r
1602 @retval EFI_UNSUPPORTED The command described by the EMMC Command Packet is not\r
1603 supported by the host controller.\r
1604 @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the\r
1605 limit supported by EMMC card ( i.e. if the number of bytes\r
1606 exceed the Last LBA).\r
1607\r
1608**/\r
1609EFI_STATUS\r
1610EFIAPI\r
1611EmmcPeimExecCmd (\r
1612 IN EMMC_PEIM_HC_SLOT *Slot,\r
1613 IN OUT EMMC_COMMAND_PACKET *Packet\r
1614 )\r
1615{\r
1616 EFI_STATUS Status;\r
1617 EMMC_TRB *Trb;\r
1618\r
1619 if (Packet == NULL) {\r
1620 return EFI_INVALID_PARAMETER;\r
1621 }\r
1622\r
1623 if ((Packet->EmmcCmdBlk == NULL) || (Packet->EmmcStatusBlk == NULL)) {\r
1624 return EFI_INVALID_PARAMETER;\r
1625 }\r
1626\r
1627 if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {\r
1628 return EFI_INVALID_PARAMETER;\r
1629 }\r
1630\r
1631 if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {\r
1632 return EFI_INVALID_PARAMETER;\r
1633 }\r
1634\r
1635 Trb = EmmcPeimCreateTrb (Slot, Packet);\r
1636 if (Trb == NULL) {\r
1637 return EFI_OUT_OF_RESOURCES;\r
1638 }\r
1639\r
1640 Status = EmmcPeimWaitTrbEnv (Slot->EmmcHcBase, Trb);\r
1641 if (EFI_ERROR (Status)) {\r
1642 goto Done;\r
1643 }\r
1644\r
1645 Status = EmmcPeimExecTrb (Slot->EmmcHcBase, Trb);\r
1646 if (EFI_ERROR (Status)) {\r
1647 goto Done;\r
1648 }\r
1649\r
1650 Status = EmmcPeimWaitTrbResult (Slot->EmmcHcBase, Trb);\r
1651 if (EFI_ERROR (Status)) {\r
1652 goto Done;\r
1653 }\r
1654\r
1655Done:\r
1656 EmmcPeimFreeTrb (Trb);\r
1657\r
1658 return Status;\r
1659}\r
1660\r
1661/**\r
1662 Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to\r
1663 make it go to Idle State.\r
1664\r
1665 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
1666\r
1667 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1668\r
1669 @retval EFI_SUCCESS The EMMC device is reset correctly.\r
1670 @retval Others The device reset fails.\r
1671\r
1672**/\r
1673EFI_STATUS\r
1674EmmcPeimReset (\r
1675 IN EMMC_PEIM_HC_SLOT *Slot\r
1676 )\r
1677{\r
1678 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1679 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1680 EMMC_COMMAND_PACKET Packet;\r
1681 EFI_STATUS Status;\r
1682\r
1683 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1684 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1685 ZeroMem (&Packet, sizeof (Packet));\r
1686\r
1687 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
1688 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
1689 Packet.Timeout = EMMC_TIMEOUT;\r
1690\r
1691 EmmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;\r
1692 EmmcCmdBlk.CommandType = EmmcCommandTypeBc;\r
1693 EmmcCmdBlk.ResponseType = 0;\r
1694 EmmcCmdBlk.CommandArgument = 0;\r
1695\r
1696 Status = EmmcPeimExecCmd (Slot, &Packet);\r
1697\r
1698 return Status;\r
1699}\r
1700\r
1701/**\r
1702 Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.\r
1703\r
1704 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
1705\r
1706 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1707 @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.\r
1708 On output, the argument is the value of OCR register.\r
1709\r
1710 @retval EFI_SUCCESS The operation is done correctly.\r
1711 @retval Others The operation fails.\r
1712\r
1713**/\r
1714EFI_STATUS\r
1715EmmcPeimGetOcr (\r
1716 IN EMMC_PEIM_HC_SLOT *Slot,\r
1717 IN OUT UINT32 *Argument\r
1718 )\r
1719{\r
1720 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1721 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1722 EMMC_COMMAND_PACKET Packet;\r
1723 EFI_STATUS Status;\r
1724\r
1725 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1726 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1727 ZeroMem (&Packet, sizeof (Packet));\r
1728\r
1729 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
1730 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
1731 Packet.Timeout = EMMC_TIMEOUT;\r
1732\r
1733 EmmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;\r
1734 EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;\r
1735 EmmcCmdBlk.ResponseType = EmmcResponceTypeR3;\r
1736 EmmcCmdBlk.CommandArgument = *Argument;\r
1737\r
1738 Status = EmmcPeimExecCmd (Slot, &Packet);\r
1739 if (!EFI_ERROR (Status)) {\r
1740 //\r
1741 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
1742 //\r
1743 *Argument = EmmcStatusBlk.Resp0;\r
1744 }\r
1745\r
1746 return Status;\r
1747}\r
1748\r
1749/**\r
1750 Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the\r
1751 data of their CID registers.\r
1752\r
1753 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
1754\r
1755 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1756\r
1757 @retval EFI_SUCCESS The operation is done correctly.\r
1758 @retval Others The operation fails.\r
1759\r
1760**/\r
1761EFI_STATUS\r
1762EmmcPeimGetAllCid (\r
1763 IN EMMC_PEIM_HC_SLOT *Slot\r
1764 )\r
1765{\r
1766 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1767 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1768 EMMC_COMMAND_PACKET Packet;\r
1769 EFI_STATUS Status;\r
1770\r
1771 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1772 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1773 ZeroMem (&Packet, sizeof (Packet));\r
1774\r
1775 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
1776 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
1777 Packet.Timeout = EMMC_TIMEOUT;\r
1778\r
1779 EmmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;\r
1780 EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;\r
1781 EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;\r
1782 EmmcCmdBlk.CommandArgument = 0;\r
1783\r
1784 Status = EmmcPeimExecCmd (Slot, &Packet);\r
1785\r
1786 return Status;\r
1787}\r
1788\r
1789/**\r
1790 Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device\r
1791 Address (RCA).\r
1792\r
1793 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
1794\r
1795 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1796 @param[in] Rca The relative device address to be assigned.\r
1797\r
1798 @retval EFI_SUCCESS The operation is done correctly.\r
1799 @retval Others The operation fails.\r
1800\r
1801**/\r
1802EFI_STATUS\r
1803EmmcPeimSetRca (\r
1804 IN EMMC_PEIM_HC_SLOT *Slot,\r
1805 IN UINT32 Rca\r
1806 )\r
1807{\r
1808 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1809 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1810 EMMC_COMMAND_PACKET Packet;\r
1811 EFI_STATUS Status;\r
1812\r
1813 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1814 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1815 ZeroMem (&Packet, sizeof (Packet));\r
1816\r
1817 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
1818 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
1819 Packet.Timeout = EMMC_TIMEOUT;\r
1820\r
1821 EmmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;\r
1822 EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
1823 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
1824 EmmcCmdBlk.CommandArgument = Rca << 16;\r
1825\r
1826 Status = EmmcPeimExecCmd (Slot, &Packet);\r
1827\r
1828 return Status;\r
1829}\r
1830\r
1831/**\r
1832 Send command SEND_CSD to the EMMC device to get the data of the CSD register.\r
1833\r
1834 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
1835\r
1836 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1837 @param[in] Rca The relative device address of selected device.\r
1838 @param[out] Csd The buffer to store the content of the CSD register.\r
1839 Note the caller should ignore the lowest byte of this\r
1840 buffer as the content of this byte is meaningless even\r
1841 if the operation succeeds.\r
1842\r
1843 @retval EFI_SUCCESS The operation is done correctly.\r
1844 @retval Others The operation fails.\r
1845\r
1846**/\r
1847EFI_STATUS\r
1848EmmcPeimGetCsd (\r
1849 IN EMMC_PEIM_HC_SLOT *Slot,\r
1850 IN UINT32 Rca,\r
1851 OUT EMMC_CSD *Csd\r
1852 )\r
1853{\r
1854 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1855 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1856 EMMC_COMMAND_PACKET Packet;\r
1857 EFI_STATUS Status;\r
1858\r
1859 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1860 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1861 ZeroMem (&Packet, sizeof (Packet));\r
1862\r
1863 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
1864 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
1865 Packet.Timeout = EMMC_TIMEOUT;\r
1866\r
1867 EmmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
1868 EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
1869 EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;\r
1870 EmmcCmdBlk.CommandArgument = Rca << 16;\r
1871\r
1872 Status = EmmcPeimExecCmd (Slot, &Packet);\r
1873 if (!EFI_ERROR (Status)) {\r
1874 //\r
1875 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
1876 //\r
1877 CopyMem (((UINT8*)Csd) + 1, &EmmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
1878 }\r
1879\r
1880 return Status;\r
1881}\r
1882\r
1883/**\r
1884 Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.\r
1885\r
1886 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
1887\r
1888 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1889 @param[in] Rca The relative device address of selected device.\r
1890\r
1891 @retval EFI_SUCCESS The operation is done correctly.\r
1892 @retval Others The operation fails.\r
1893\r
1894**/\r
1895EFI_STATUS\r
1896EmmcPeimSelect (\r
1897 IN EMMC_PEIM_HC_SLOT *Slot,\r
1898 IN UINT32 Rca\r
1899 )\r
1900{\r
1901 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1902 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1903 EMMC_COMMAND_PACKET Packet;\r
1904 EFI_STATUS Status;\r
1905\r
1906 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1907 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1908 ZeroMem (&Packet, sizeof (Packet));\r
1909\r
1910 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
1911 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
1912 Packet.Timeout = EMMC_TIMEOUT;\r
1913\r
1914 EmmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
1915 EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
1916 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
1917 EmmcCmdBlk.CommandArgument = Rca << 16;\r
1918\r
1919 Status = EmmcPeimExecCmd (Slot, &Packet);\r
1920\r
1921 return Status;\r
1922}\r
1923\r
1924/**\r
1925 Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.\r
1926\r
1927 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
1928\r
1929 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1930 @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.\r
1931\r
1932 @retval EFI_SUCCESS The operation is done correctly.\r
1933 @retval Others The operation fails.\r
1934\r
1935**/\r
1936EFI_STATUS\r
1937EmmcPeimGetExtCsd (\r
1938 IN EMMC_PEIM_HC_SLOT *Slot,\r
1939 OUT EMMC_EXT_CSD *ExtCsd\r
1940 )\r
1941{\r
1942 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1943 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1944 EMMC_COMMAND_PACKET Packet;\r
1945 EFI_STATUS Status;\r
1946\r
1947 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1948 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1949 ZeroMem (&Packet, sizeof (Packet));\r
1950\r
1951 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
1952 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
1953 Packet.Timeout = EMMC_TIMEOUT;\r
1954\r
1955 EmmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
1956 EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
1957 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
1958 EmmcCmdBlk.CommandArgument = 0x00000000;\r
1959\r
1960 Packet.InDataBuffer = ExtCsd;\r
1961 Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
1962\r
1963 Status = EmmcPeimExecCmd (Slot, &Packet);\r
1964 return Status;\r
1965}\r
1966\r
1967/**\r
1968 Send command SWITCH to the EMMC device to switch the mode of operation of the\r
1969 selected Device or modifies the EXT_CSD registers.\r
1970\r
1971 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
1972\r
1973 @param[in] Slot The slot number of the Emmc card to send the command to.\r
1974 @param[in] Access The access mode of SWTICH command.\r
1975 @param[in] Index The offset of the field to be access.\r
1976 @param[in] Value The value to be set to the specified field of EXT_CSD register.\r
1977 @param[in] CmdSet The value of CmdSet field of EXT_CSD register.\r
1978\r
1979 @retval EFI_SUCCESS The operation is done correctly.\r
1980 @retval Others The operation fails.\r
1981\r
1982**/\r
1983EFI_STATUS\r
1984EmmcPeimSwitch (\r
1985 IN EMMC_PEIM_HC_SLOT *Slot,\r
1986 IN UINT8 Access,\r
1987 IN UINT8 Index,\r
1988 IN UINT8 Value,\r
1989 IN UINT8 CmdSet\r
1990 )\r
1991{\r
1992 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
1993 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
1994 EMMC_COMMAND_PACKET Packet;\r
1995 EFI_STATUS Status;\r
1996\r
1997 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
1998 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
1999 ZeroMem (&Packet, sizeof (Packet));\r
2000\r
2001 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
2002 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
2003 Packet.Timeout = EMMC_TIMEOUT;\r
2004\r
2005 EmmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
2006 EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
2007 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1b;\r
2008 EmmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;\r
2009\r
2010 Status = EmmcPeimExecCmd (Slot, &Packet);\r
2011\r
2012 return Status;\r
2013}\r
2014\r
2015/**\r
2016 Send command SEND_STATUS to the addressed EMMC device to get its status register.\r
2017\r
2018 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
2019\r
2020 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2021 @param[in] Rca The relative device address of addressed device.\r
2022 @param[out] DevStatus The returned device status.\r
2023\r
2024 @retval EFI_SUCCESS The operation is done correctly.\r
2025 @retval Others The operation fails.\r
2026\r
2027**/\r
2028EFI_STATUS\r
2029EmmcPeimSendStatus (\r
2030 IN EMMC_PEIM_HC_SLOT *Slot,\r
2031 IN UINT32 Rca,\r
2032 OUT UINT32 *DevStatus\r
2033 )\r
2034{\r
2035 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
2036 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
2037 EMMC_COMMAND_PACKET Packet;\r
2038 EFI_STATUS Status;\r
2039\r
2040 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
2041 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
2042 ZeroMem (&Packet, sizeof (Packet));\r
2043\r
2044 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
2045 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
2046 Packet.Timeout = EMMC_TIMEOUT;\r
2047\r
2048 EmmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
2049 EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
2050 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
2051 EmmcCmdBlk.CommandArgument = Rca << 16;\r
2052\r
2053 Status = EmmcPeimExecCmd (Slot, &Packet);\r
2054 if (!EFI_ERROR (Status)) {\r
2055 *DevStatus = EmmcStatusBlk.Resp0;\r
2056 }\r
2057\r
2058 return Status;\r
2059}\r
2060\r
2061/**\r
2062 Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of\r
2063 blocks for the following block read/write cmd.\r
2064\r
2065 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
2066\r
2067 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2068 @param[in] BlockCount The number of the logical block to access.\r
2069\r
2070 @retval EFI_SUCCESS The operation is done correctly.\r
2071 @retval Others The operation fails.\r
2072\r
2073**/\r
2074EFI_STATUS\r
2075EmmcPeimSetBlkCount (\r
2076 IN EMMC_PEIM_HC_SLOT *Slot,\r
2077 IN UINT16 BlockCount\r
2078 )\r
2079{\r
2080 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
2081 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
2082 EMMC_COMMAND_PACKET Packet;\r
2083 EFI_STATUS Status;\r
2084\r
2085 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
2086 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
2087 ZeroMem (&Packet, sizeof (Packet));\r
2088\r
2089 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
2090 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
2091 Packet.Timeout = EMMC_TIMEOUT;\r
2092\r
2093 EmmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;\r
2094 EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
2095 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
2096 EmmcCmdBlk.CommandArgument = BlockCount;\r
2097\r
2098 Status = EmmcPeimExecCmd (Slot, &Packet);\r
2099\r
2100 return Status;\r
2101}\r
2102\r
2103/**\r
2104 Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device\r
2105 to read/write the specified number of blocks.\r
2106\r
2107 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
2108\r
2109 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2110 @param[in] Lba The logical block address of starting access.\r
2111 @param[in] BlockSize The block size of specified EMMC device partition.\r
2112 @param[in] Buffer The pointer to the transfer buffer.\r
2113 @param[in] BufferSize The size of transfer buffer.\r
2114 @param[in] IsRead Boolean to show the operation direction.\r
2115\r
2116 @retval EFI_SUCCESS The operation is done correctly.\r
2117 @retval Others The operation fails.\r
2118\r
2119**/\r
2120EFI_STATUS\r
2121EmmcPeimRwMultiBlocks (\r
2122 IN EMMC_PEIM_HC_SLOT *Slot,\r
2123 IN EFI_LBA Lba,\r
2124 IN UINT32 BlockSize,\r
2125 IN VOID *Buffer,\r
2126 IN UINTN BufferSize,\r
2127 IN BOOLEAN IsRead\r
2128 )\r
2129{\r
2130 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
2131 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
2132 EMMC_COMMAND_PACKET Packet;\r
2133 EFI_STATUS Status;\r
2134\r
2135 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
2136 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
2137 ZeroMem (&Packet, sizeof (Packet));\r
2138\r
2139 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
2140 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
2141 //\r
2142 // Calculate timeout value through the below formula.\r
2143 // Timeout = (transfer size) / (2MB/s).\r
2144 // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest\r
2145 // transfer speed (2.4MB/s).\r
2146 // Refer to eMMC 5.0 spec section 6.9.1 for details.\r
2147 //\r
2148 Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;\r
2149\r
2150 if (IsRead) {\r
2151 Packet.InDataBuffer = Buffer;\r
2152 Packet.InTransferLength = (UINT32)BufferSize;\r
2153\r
2154 EmmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;\r
2155 EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
2156 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
2157 } else {\r
2158 Packet.OutDataBuffer = Buffer;\r
2159 Packet.OutTransferLength = (UINT32)BufferSize;\r
2160\r
2161 EmmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;\r
2162 EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
2163 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
2164 }\r
2165\r
2166 if (Slot->SectorAddressing) {\r
2167 EmmcCmdBlk.CommandArgument = (UINT32)Lba;\r
2168 } else {\r
2169 EmmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);\r
2170 }\r
2171\r
2172 Status = EmmcPeimExecCmd (Slot, &Packet);\r
2173\r
2174 return Status;\r
2175}\r
2176\r
2177/**\r
2178 Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point\r
2179 detection.\r
2180\r
2181 It may be sent up to 40 times until the host finishes the tuning procedure.\r
2182\r
2183 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.\r
2184\r
2185 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2186 @param[in] BusWidth The bus width to work.\r
2187\r
2188 @retval EFI_SUCCESS The operation is done correctly.\r
2189 @retval Others The operation fails.\r
2190\r
2191**/\r
2192EFI_STATUS\r
2193EmmcPeimSendTuningBlk (\r
2194 IN EMMC_PEIM_HC_SLOT *Slot,\r
2195 IN UINT8 BusWidth\r
2196 )\r
2197{\r
2198 EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
2199 EMMC_STATUS_BLOCK EmmcStatusBlk;\r
2200 EMMC_COMMAND_PACKET Packet;\r
2201 EFI_STATUS Status;\r
2202 UINT8 TuningBlock[128];\r
2203\r
2204 ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
2205 ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
2206 ZeroMem (&Packet, sizeof (Packet));\r
2207\r
2208 Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
2209 Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
2210 Packet.Timeout = EMMC_TIMEOUT;\r
2211\r
2212 EmmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;\r
2213 EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
2214 EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
2215 EmmcCmdBlk.CommandArgument = 0;\r
2216\r
2217 Packet.InDataBuffer = TuningBlock;\r
2218 if (BusWidth == 8) {\r
2219 Packet.InTransferLength = sizeof (TuningBlock);\r
2220 } else {\r
2221 Packet.InTransferLength = 64;\r
2222 }\r
2223\r
2224 Status = EmmcPeimExecCmd (Slot, &Packet);\r
2225\r
2226 return Status;\r
2227}\r
2228\r
2229/**\r
2230 Tunning the clock to get HS200 optimal sampling point.\r
2231\r
2232 Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
2233 tuning procedure.\r
2234\r
2235 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
2236 Simplified Spec 3.0 section Figure 2-29 for details.\r
2237\r
2238 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2239 @param[in] BusWidth The bus width to work.\r
2240\r
2241 @retval EFI_SUCCESS The operation is done correctly.\r
2242 @retval Others The operation fails.\r
2243\r
2244**/\r
2245EFI_STATUS\r
2246EmmcPeimTuningClkForHs200 (\r
2247 IN EMMC_PEIM_HC_SLOT *Slot,\r
2248 IN UINT8 BusWidth\r
2249 )\r
2250{\r
2251 EFI_STATUS Status;\r
2252 UINT8 HostCtrl2;\r
2253 UINT8 Retry;\r
2254\r
2255 //\r
2256 // Notify the host that the sampling clock tuning procedure starts.\r
2257 //\r
2258 HostCtrl2 = BIT6;\r
2259 Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
2260 if (EFI_ERROR (Status)) {\r
2261 return Status;\r
2262 }\r
2263 //\r
2264 // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
2265 //\r
2266 Retry = 0;\r
2267 do {\r
2268 Status = EmmcPeimSendTuningBlk (Slot, BusWidth);\r
2269 if (EFI_ERROR (Status)) {\r
2270 return Status;\r
2271 }\r
2272\r
2273 Status = EmmcPeimHcRwMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
2274 if (EFI_ERROR (Status)) {\r
2275 return Status;\r
2276 }\r
2277\r
2278 if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
2279 break;\r
2280 }\r
2281 } while (++Retry < 40);\r
2282\r
2283 if (Retry == 40) {\r
2284 Status = EFI_TIMEOUT;\r
2285 }\r
2286 return Status;\r
2287}\r
2288\r
2289/**\r
2290 Switch the bus width to specified width.\r
2291\r
2292 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller\r
2293 Simplified Spec 3.0 section Figure 3-7 for details.\r
2294\r
2295 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2296 @param[in] Rca The relative device address to be assigned.\r
2297 @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
2298 use single data rate data simpling method.\r
2299 @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
2300\r
2301 @retval EFI_SUCCESS The operation is done correctly.\r
2302 @retval Others The operation fails.\r
2303\r
2304**/\r
2305EFI_STATUS\r
2306EmmcPeimSwitchBusWidth (\r
2307 IN EMMC_PEIM_HC_SLOT *Slot,\r
2308 IN UINT32 Rca,\r
2309 IN BOOLEAN IsDdr,\r
2310 IN UINT8 BusWidth\r
2311 )\r
2312{\r
2313 EFI_STATUS Status;\r
2314 UINT8 Access;\r
2315 UINT8 Index;\r
2316 UINT8 Value;\r
2317 UINT8 CmdSet;\r
2318 UINT32 DevStatus;\r
2319\r
2320 //\r
2321 // Write Byte, the Value field is written into the byte pointed by Index.\r
2322 //\r
2323 Access = 0x03;\r
2324 Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);\r
2325 if (BusWidth == 4) {\r
2326 Value = 1;\r
2327 } else if (BusWidth == 8) {\r
2328 Value = 2;\r
2329 } else {\r
2330 return EFI_INVALID_PARAMETER;\r
2331 }\r
2332\r
2333 if (IsDdr) {\r
2334 Value += 4;\r
2335 }\r
2336\r
2337 CmdSet = 0;\r
2338 Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);\r
2339 if (EFI_ERROR (Status)) {\r
2340 return Status;\r
2341 }\r
2342\r
2343 Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);\r
2344 if (EFI_ERROR (Status)) {\r
2345 return Status;\r
2346 }\r
2347 //\r
2348 // Check the switch operation is really successful or not.\r
2349 //\r
2350 if ((DevStatus & BIT7) != 0) {\r
2351 return EFI_DEVICE_ERROR;\r
2352 }\r
2353\r
2354 Status = EmmcPeimHcSetBusWidth (Slot->EmmcHcBase, BusWidth);\r
2355\r
2356 return Status;\r
2357}\r
2358\r
2359/**\r
2360 Switch the clock frequency to the specified value.\r
2361\r
2362 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller\r
2363 Simplified Spec 3.0 section Figure 3-3 for details.\r
2364\r
2365 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2366 @param[in] Rca The relative device address to be assigned.\r
2367 @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register.\r
2368 @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.\r
2369\r
2370 @retval EFI_SUCCESS The operation is done correctly.\r
2371 @retval Others The operation fails.\r
2372\r
2373**/\r
2374EFI_STATUS\r
2375EmmcPeimSwitchClockFreq (\r
2376 IN EMMC_PEIM_HC_SLOT *Slot,\r
2377 IN UINT32 Rca,\r
2378 IN UINT8 HsTiming,\r
2379 IN UINT32 ClockFreq\r
2380 )\r
2381{\r
2382 EFI_STATUS Status;\r
2383 UINT8 Access;\r
2384 UINT8 Index;\r
2385 UINT8 Value;\r
2386 UINT8 CmdSet;\r
2387 UINT32 DevStatus;\r
2388\r
2389 //\r
2390 // Write Byte, the Value field is written into the byte pointed by Index.\r
2391 //\r
2392 Access = 0x03;\r
2393 Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);\r
2394 Value = HsTiming;\r
2395 CmdSet = 0;\r
2396\r
2397 Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);\r
2398 if (EFI_ERROR (Status)) {\r
2399 return Status;\r
2400 }\r
2401\r
2402 Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);\r
2403 if (EFI_ERROR (Status)) {\r
2404 return Status;\r
2405 }\r
2406 //\r
2407 // Check the switch operation is really successful or not.\r
2408 //\r
2409 if ((DevStatus & BIT7) != 0) {\r
2410 return EFI_DEVICE_ERROR;\r
2411 }\r
2412 //\r
2413 // Convert the clock freq unit from MHz to KHz.\r
2414 //\r
2415 Status = EmmcPeimHcClockSupply (Slot->EmmcHcBase, ClockFreq * 1000);\r
2416\r
2417 return Status;\r
2418}\r
2419\r
2420/**\r
2421 Switch to the High Speed timing according to request.\r
2422\r
2423 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
2424 Simplified Spec 3.0 section Figure 2-29 for details.\r
2425\r
2426 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2427 @param[in] Rca The relative device address to be assigned.\r
2428 @param[in] ClockFreq The max clock frequency to be set.\r
2429 @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
2430 use single data rate data simpling method.\r
2431 @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
2432\r
2433 @retval EFI_SUCCESS The operation is done correctly.\r
2434 @retval Others The operation fails.\r
2435\r
2436**/\r
2437EFI_STATUS\r
2438EmmcPeimSwitchToHighSpeed (\r
2439 IN EMMC_PEIM_HC_SLOT *Slot,\r
2440 IN UINT32 Rca,\r
2441 IN UINT32 ClockFreq,\r
2442 IN BOOLEAN IsDdr,\r
2443 IN UINT8 BusWidth\r
2444 )\r
2445{\r
2446 EFI_STATUS Status;\r
2447 UINT8 HsTiming;\r
2448 UINT8 HostCtrl1;\r
2449 UINT8 HostCtrl2;\r
2450\r
2451 Status = EmmcPeimSwitchBusWidth (Slot, Rca, IsDdr, BusWidth);\r
2452 if (EFI_ERROR (Status)) {\r
2453 return Status;\r
2454 }\r
2455 //\r
2456 // Set to Hight Speed timing\r
2457 //\r
2458 HostCtrl1 = BIT2;\r
2459 Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
2460 if (EFI_ERROR (Status)) {\r
2461 return Status;\r
2462 }\r
2463\r
2464 HostCtrl2 = (UINT8)~0x7;\r
2465 Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
2466 if (EFI_ERROR (Status)) {\r
2467 return Status;\r
2468 }\r
2469 if (IsDdr) {\r
2470 HostCtrl2 = BIT2;\r
2471 } else if (ClockFreq == 52) {\r
2472 HostCtrl2 = BIT0;\r
2473 } else {\r
2474 HostCtrl2 = 0;\r
2475 }\r
2476 Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
2477 if (EFI_ERROR (Status)) {\r
2478 return Status;\r
2479 }\r
2480\r
2481 HsTiming = 1;\r
2482 Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
2483 if (EFI_ERROR (Status)) {\r
2484 return Status;\r
2485 }\r
2486\r
2487 return Status;\r
2488}\r
2489\r
2490/**\r
2491 Switch to the HS200 timing according to request.\r
2492\r
2493 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
2494 Simplified Spec 3.0 section Figure 2-29 for details.\r
2495\r
2496 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2497 @param[in] Rca The relative device address to be assigned.\r
2498 @param[in] ClockFreq The max clock frequency to be set.\r
2499 @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
2500\r
2501 @retval EFI_SUCCESS The operation is done correctly.\r
2502 @retval Others The operation fails.\r
2503\r
2504**/\r
2505EFI_STATUS\r
2506EmmcPeimSwitchToHS200 (\r
2507 IN EMMC_PEIM_HC_SLOT *Slot,\r
2508 IN UINT32 Rca,\r
2509 IN UINT32 ClockFreq,\r
2510 IN UINT8 BusWidth\r
2511 )\r
2512{\r
2513 EFI_STATUS Status;\r
2514 UINT8 HsTiming;\r
2515 UINT8 HostCtrl2;\r
2516 UINT16 ClockCtrl;\r
2517\r
2518 if ((BusWidth != 4) && (BusWidth != 8)) {\r
2519 return EFI_INVALID_PARAMETER;\r
2520 }\r
2521\r
2522 Status = EmmcPeimSwitchBusWidth (Slot, Rca, FALSE, BusWidth);\r
2523 if (EFI_ERROR (Status)) {\r
2524 return Status;\r
2525 }\r
2526 //\r
2527 // Set to HS200/SDR104 timing\r
2528 //\r
2529 //\r
2530 // Stop bus clock at first\r
2531 //\r
2532 Status = EmmcPeimHcStopClock (Slot->EmmcHcBase);\r
2533 if (EFI_ERROR (Status)) {\r
2534 return Status;\r
2535 }\r
2536\r
2537 HostCtrl2 = (UINT8)~0x7;\r
2538 Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
2539 if (EFI_ERROR (Status)) {\r
2540 return Status;\r
2541 }\r
2542 HostCtrl2 = BIT0 | BIT1;\r
2543 Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
2544 if (EFI_ERROR (Status)) {\r
2545 return Status;\r
2546 }\r
2547\r
2548 //\r
2549 // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit\r
2550 //\r
2551 Status = EmmcPeimHcWaitMmioSet (\r
2552 Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL,\r
2553 sizeof (ClockCtrl),\r
2554 BIT1,\r
2555 BIT1,\r
2556 EMMC_TIMEOUT\r
2557 );\r
2558 if (EFI_ERROR (Status)) {\r
2559 return Status;\r
2560 }\r
2561 //\r
2562 // Set SD Clock Enable in the Clock Control register to 1\r
2563 //\r
2564 ClockCtrl = BIT2;\r
2565 Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
2566\r
2567 HsTiming = 2;\r
2568 Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
2569 if (EFI_ERROR (Status)) {\r
2570 return Status;\r
2571 }\r
2572\r
2573 Status = EmmcPeimTuningClkForHs200 (Slot, BusWidth);\r
2574\r
2575 return Status;\r
2576}\r
2577\r
2578/**\r
2579 Switch to the HS400 timing according to request.\r
2580\r
2581 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
2582 Simplified Spec 3.0 section Figure 2-29 for details.\r
2583\r
2584 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2585 @param[in] Rca The relative device address to be assigned.\r
2586 @param[in] ClockFreq The max clock frequency to be set.\r
2587\r
2588 @retval EFI_SUCCESS The operation is done correctly.\r
2589 @retval Others The operation fails.\r
2590\r
2591**/\r
2592EFI_STATUS\r
2593EmmcPeimSwitchToHS400 (\r
2594 IN EMMC_PEIM_HC_SLOT *Slot,\r
2595 IN UINT32 Rca,\r
2596 IN UINT32 ClockFreq\r
2597 )\r
2598{\r
2599 EFI_STATUS Status;\r
2600 UINT8 HsTiming;\r
2601 UINT8 HostCtrl2;\r
2602\r
2603 Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, 8);\r
2604 if (EFI_ERROR (Status)) {\r
2605 return Status;\r
2606 }\r
2607 //\r
2608 // Set to Hight Speed timing and set the clock frequency to a value less than 52MHz.\r
2609 //\r
2610 HsTiming = 1;\r
2611 Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, 52);\r
2612 if (EFI_ERROR (Status)) {\r
2613 return Status;\r
2614 }\r
2615 //\r
2616 // HS400 mode must use 8 data lines.\r
2617 //\r
2618 Status = EmmcPeimSwitchBusWidth (Slot, Rca, TRUE, 8);\r
2619 if (EFI_ERROR (Status)) {\r
2620 return Status;\r
2621 }\r
2622 //\r
2623 // Set to HS400 timing\r
2624 //\r
2625 HostCtrl2 = (UINT8)~0x7;\r
2626 Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
2627 if (EFI_ERROR (Status)) {\r
2628 return Status;\r
2629 }\r
2630 HostCtrl2 = BIT0 | BIT2;\r
2631 Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
2632 if (EFI_ERROR (Status)) {\r
2633 return Status;\r
2634 }\r
2635\r
2636 HsTiming = 3;\r
2637 Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
2638\r
2639 return Status;\r
2640}\r
2641\r
2642/**\r
2643 Switch the high speed timing according to request.\r
2644\r
2645 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
2646 Simplified Spec 3.0 section Figure 2-29 for details.\r
2647\r
2648 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2649 @param[in] Rca The relative device address to be assigned.\r
2650\r
2651 @retval EFI_SUCCESS The operation is done correctly.\r
2652 @retval Others The operation fails.\r
2653\r
2654**/\r
2655EFI_STATUS\r
2656EmmcPeimSetBusMode (\r
2657 IN EMMC_PEIM_HC_SLOT *Slot,\r
2658 IN UINT32 Rca\r
2659 )\r
2660{\r
2661 EFI_STATUS Status;\r
2662 EMMC_HC_SLOT_CAP Capability;\r
2663 UINT8 HsTiming;\r
2664 BOOLEAN IsDdr;\r
2665 UINT32 ClockFreq;\r
2666 UINT8 BusWidth;\r
2667\r
2668 Status = EmmcPeimGetCsd (Slot, Rca, &Slot->Csd);\r
2669 if (EFI_ERROR (Status)) {\r
2670 DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetCsd fails with %r\n", Status));\r
2671 return Status;\r
2672 }\r
2673\r
2674 if ((Slot->Csd.CSizeLow | Slot->Csd.CSizeHigh << 2) == 0xFFF) {\r
2675 Slot->SectorAddressing = TRUE;\r
2676 } else {\r
2677 Slot->SectorAddressing = FALSE;\r
2678 }\r
2679\r
2680 Status = EmmcPeimSelect (Slot, Rca);\r
2681 if (EFI_ERROR (Status)) {\r
2682 DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimSelect fails with %r\n", Status));\r
2683 return Status;\r
2684 }\r
2685\r
2686 Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);\r
2687 if (EFI_ERROR (Status)) {\r
2688 DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimHcGetCapability fails with %r\n", Status));\r
2689 return Status;\r
2690 }\r
2691\r
2692 ASSERT (Capability.BaseClkFreq != 0);\r
2693 //\r
2694 // Check if the Host Controller support 8bits bus width.\r
2695 //\r
2696 if (Capability.BusWidth8 != 0) {\r
2697 BusWidth = 8;\r
2698 } else {\r
2699 BusWidth = 4;\r
2700 }\r
2701 //\r
2702 // Get Deivce_Type from EXT_CSD register.\r
2703 //\r
2704 Status = EmmcPeimGetExtCsd (Slot, &Slot->ExtCsd);\r
2705 if (EFI_ERROR (Status)) {\r
2706 DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetExtCsd fails with %r\n", Status));\r
2707 return Status;\r
2708 }\r
2709 //\r
2710 // Calculate supported bus speed/bus width/clock frequency.\r
2711 //\r
2712 HsTiming = 0;\r
2713 IsDdr = FALSE;\r
2714 ClockFreq = 0;\r
2715 if (((Slot->ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Capability.Sdr104 != 0)) {\r
2716 HsTiming = 2;\r
2717 IsDdr = FALSE;\r
2718 ClockFreq = 200;\r
2719 } else if (((Slot->ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Capability.Ddr50 != 0)) {\r
2720 HsTiming = 1;\r
2721 IsDdr = TRUE;\r
2722 ClockFreq = 52;\r
2723 } else if (((Slot->ExtCsd.DeviceType & BIT1) != 0) && (Capability.HighSpeed != 0)) {\r
2724 HsTiming = 1;\r
2725 IsDdr = FALSE;\r
2726 ClockFreq = 52;\r
2727 } else if (((Slot->ExtCsd.DeviceType & BIT0) != 0) && (Capability.HighSpeed != 0)) {\r
2728 HsTiming = 1;\r
2729 IsDdr = FALSE;\r
2730 ClockFreq = 26;\r
2731 }\r
2732 //\r
2733 // Check if both of the device and the host controller support HS400 DDR mode.\r
2734 //\r
2735 if (((Slot->ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Capability.Hs400 != 0)) {\r
2736 //\r
2737 // The host controller supports 8bits bus.\r
2738 //\r
2739 ASSERT (BusWidth == 8);\r
2740 HsTiming = 3;\r
2741 IsDdr = TRUE;\r
2742 ClockFreq = 200;\r
2743 }\r
2744\r
2745 if ((ClockFreq == 0) || (HsTiming == 0)) {\r
2746 //\r
2747 // Continue using default setting.\r
2748 //\r
2749 return EFI_SUCCESS;\r
2750 }\r
2751\r
2752 DEBUG ((EFI_D_INFO, "HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE"));\r
2753\r
2754 if (HsTiming == 3) {\r
2755 //\r
2756 // Execute HS400 timing switch procedure\r
2757 //\r
2758 Status = EmmcPeimSwitchToHS400 (Slot, Rca, ClockFreq);\r
2759 } else if (HsTiming == 2) {\r
2760 //\r
2761 // Execute HS200 timing switch procedure\r
2762 //\r
2763 Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, BusWidth);\r
2764 } else {\r
2765 //\r
2766 // Execute High Speed timing switch procedure\r
2767 //\r
2768 Status = EmmcPeimSwitchToHighSpeed (Slot, Rca, ClockFreq, BusWidth, IsDdr);\r
2769 }\r
2770\r
2771 return Status;\r
2772}\r
2773\r
2774/**\r
2775 Execute EMMC device identification procedure.\r
2776\r
2777 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
2778\r
2779 @param[in] Slot The slot number of the Emmc card to send the command to.\r
2780\r
2781 @retval EFI_SUCCESS There is a EMMC card.\r
2782 @retval Others There is not a EMMC card.\r
2783\r
2784**/\r
2785EFI_STATUS\r
2786EmmcPeimIdentification (\r
2787 IN EMMC_PEIM_HC_SLOT *Slot\r
2788 )\r
2789{\r
2790 EFI_STATUS Status;\r
2791 UINT32 Ocr;\r
2792 UINT32 Rca;\r
2793\r
2794 Status = EmmcPeimReset (Slot);\r
2795 if (EFI_ERROR (Status)) {\r
2796 DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimReset fails with %r\n", Status));\r
2797 return Status;\r
2798 }\r
2799\r
2800 Ocr = 0;\r
2801 do {\r
2802 Status = EmmcPeimGetOcr (Slot, &Ocr);\r
2803 if (EFI_ERROR (Status)) {\r
2804 DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails with %r\n", Status));\r
2805 return Status;\r
2806 }\r
2807 } while ((Ocr & BIT31) == 0);\r
2808\r
2809 Status = EmmcPeimGetAllCid (Slot);\r
2810 if (EFI_ERROR (Status)) {\r
2811 DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetAllCid fails with %r\n", Status));\r
2812 return Status;\r
2813 }\r
2814 //\r
2815 // Don't support multiple devices on the slot, that is\r
2816 // shared bus slot feature.\r
2817 //\r
2818 Rca = 1;\r
2819 Status = EmmcPeimSetRca (Slot, Rca);\r
2820 if (EFI_ERROR (Status)) {\r
2821 DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimSetRca fails with %r\n", Status));\r
2822 return Status;\r
2823 }\r
2824 //\r
2825 // Enter Data Tranfer Mode.\r
2826 //\r
2827 DEBUG ((EFI_D_INFO, "Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));\r
2828\r
2829 Status = EmmcPeimSetBusMode (Slot, Rca);\r
2830\r
2831 return Status;\r
2832}\r
2833\r