a3f98646 |
1 | /** @file |
2 | |
3 | Copyright (c) 2008-2009, Apple Inc. All rights reserved. |
4 | |
5 | All rights reserved. This program and the accompanying materials |
6 | are licensed and made available under the terms and conditions of the BSD License |
7 | which accompanies this distribution. The full text of the license may be found at |
8 | http://opensource.org/licenses/bsd-license.php |
9 | |
10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
12 | |
13 | **/ |
14 | |
15 | #include <Uefi.h> |
16 | |
17 | #include "MMCHS.h" |
18 | |
19 | EFI_BLOCK_IO_MEDIA MMCHSMedia = { |
20 | SIGNATURE_32('s','d','i','o'), // MediaId |
21 | TRUE, // RemovableMedia |
22 | TRUE, // MediaPresent |
23 | FALSE, // LogicalPartition |
24 | FALSE, // ReadOnly |
25 | FALSE, // WriteCaching |
26 | 512, // BlockSize |
27 | 4, // IoAlign |
28 | 0, // Pad |
29 | 0 // LastBlock |
30 | }; |
31 | |
32 | typedef struct { |
33 | VENDOR_DEVICE_PATH Mmc; |
34 | EFI_DEVICE_PATH End; |
35 | } MMCHS_DEVICE_PATH; |
36 | |
37 | MMCHS_DEVICE_PATH gMmcHsDevicePath = |
38 | { |
39 | { |
40 | HARDWARE_DEVICE_PATH, |
41 | HW_VENDOR_DP, |
42 | (UINT8)(sizeof(VENDOR_DEVICE_PATH)), |
43 | (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), |
44 | 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 |
45 | }, |
46 | { |
47 | END_DEVICE_PATH_TYPE, |
48 | END_ENTIRE_DEVICE_PATH_SUBTYPE, |
49 | sizeof (EFI_DEVICE_PATH_PROTOCOL), |
50 | 0 |
51 | } |
52 | }; |
53 | |
54 | CARD_INFO *gCardInfo; |
55 | EMBEDDED_EXTERNAL_DEVICE *gTPS65950; |
56 | |
57 | // |
58 | // Internal Functions |
59 | // |
60 | |
61 | STATIC |
62 | VOID |
63 | ParseCardCIDData ( |
64 | UINT32 Response0, |
65 | UINT32 Response1, |
66 | UINT32 Response2, |
67 | UINT32 Response3 |
68 | ) |
69 | { |
70 | gCardInfo->CIDData.MDT = ((Response0 >> 8) & 0xFFF); |
71 | gCardInfo->CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8)); |
72 | gCardInfo->CIDData.PRV = ((Response1 >> 24) & 0xFF); |
73 | gCardInfo->CIDData.PNM[4] = ((Response2) & 0xFF); |
74 | gCardInfo->CIDData.PNM[3] = ((Response2 >> 8) & 0xFF); |
75 | gCardInfo->CIDData.PNM[2] = ((Response2 >> 16) & 0xFF); |
76 | gCardInfo->CIDData.PNM[1] = ((Response2 >> 24) & 0xFF); |
77 | gCardInfo->CIDData.PNM[0] = ((Response3) & 0xFF); |
78 | gCardInfo->CIDData.OID = ((Response3 >> 8) & 0xFFFF); |
79 | gCardInfo->CIDData.MID = ((Response3 >> 24) & 0xFF); |
80 | } |
81 | |
82 | STATIC |
83 | VOID |
84 | UpdateMMCHSClkFrequency ( |
85 | UINTN NewCLKD |
86 | ) |
87 | { |
88 | //Set Clock enable to 0x0 to not provide the clock to the card |
89 | MmioAnd32(MMCHS_SYSCTL, ~CEN); |
90 | |
91 | //Set new clock frequency. |
92 | MmioAndThenOr32(MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6); |
93 | |
94 | //Poll till Internal Clock Stable |
95 | while ((MmioRead32(MMCHS_SYSCTL) & ICS_MASK) != ICS); |
96 | |
97 | //Set Clock enable to 0x1 to provide the clock to the card |
98 | MmioOr32(MMCHS_SYSCTL, CEN); |
99 | } |
100 | |
101 | STATIC |
102 | EFI_STATUS |
103 | SendCmd ( |
104 | UINTN Cmd, |
105 | UINTN CmdInterruptEnableVal, |
106 | UINTN CmdArgument |
107 | ) |
108 | { |
109 | UINTN MmcStatus; |
110 | UINTN RetryCount = 0; |
111 | |
112 | //Check if command line is in use or not. Poll till command line is available. |
113 | while ((MmioRead32(MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED); |
114 | |
115 | //Provide the block size. |
026e30c4 |
116 | MmioWrite32 (MMCHS_BLK, BLEN_512BYTES); |
a3f98646 |
117 | |
118 | //Setting Data timeout counter value to max value. |
119 | MmioAndThenOr32(MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL); |
120 | |
121 | //Clear Status register. |
026e30c4 |
122 | MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF); |
a3f98646 |
123 | |
124 | //Set command argument register |
026e30c4 |
125 | MmioWrite32 (MMCHS_ARG, CmdArgument); |
a3f98646 |
126 | |
127 | //Enable interrupt enable events to occur |
026e30c4 |
128 | MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal); |
a3f98646 |
129 | |
130 | //Send a command |
026e30c4 |
131 | MmioWrite32 (MMCHS_CMD, Cmd); |
a3f98646 |
132 | |
133 | //Check for the command status. |
134 | while (RetryCount < MAX_RETRY_COUNT) { |
135 | do { |
136 | MmcStatus = MmioRead32(MMCHS_STAT); |
137 | } while (MmcStatus == 0); |
138 | |
139 | //Read status of command response |
140 | if ((MmcStatus & ERRI) != 0) { |
141 | |
142 | //Perform soft-reset for mmci_cmd line. |
143 | MmioOr32(MMCHS_SYSCTL, SRC); |
144 | while ((MmioRead32(MMCHS_SYSCTL) & SRC)); |
145 | |
146 | DEBUG ((EFI_D_INFO, "MmcStatus: %x\n", MmcStatus)); |
147 | return EFI_DEVICE_ERROR; |
148 | } |
149 | |
150 | //Check if command is completed. |
151 | if ((MmcStatus & CC) == CC) { |
026e30c4 |
152 | MmioWrite32 (MMCHS_STAT, CC); |
a3f98646 |
153 | break; |
154 | } |
155 | |
156 | RetryCount++; |
157 | } |
158 | |
159 | if (RetryCount == MAX_RETRY_COUNT) { |
160 | return EFI_TIMEOUT; |
161 | } |
162 | |
163 | return EFI_SUCCESS; |
164 | } |
165 | |
166 | STATIC |
167 | VOID |
168 | GetBlockInformation ( |
169 | UINTN *BlockSize, |
170 | UINTN *NumBlocks |
171 | ) |
172 | { |
173 | CSD_SDV2 *CsdSDV2Data; |
174 | UINTN CardSize; |
175 | |
176 | if (gCardInfo->CardType == SD_CARD_2_HIGH) { |
177 | CsdSDV2Data = (CSD_SDV2 *)&gCardInfo->CSDData; |
178 | |
179 | //Populate BlockSize. |
180 | *BlockSize = (0x1UL << CsdSDV2Data->READ_BL_LEN); |
181 | |
182 | //Calculate Total number of blocks. |
183 | CardSize = CsdSDV2Data->C_SIZELow16 | (CsdSDV2Data->C_SIZEHigh6 << 2); |
184 | *NumBlocks = ((CardSize + 1) * 1024); |
185 | } else { |
186 | //Populate BlockSize. |
187 | *BlockSize = (0x1UL << gCardInfo->CSDData.READ_BL_LEN); |
188 | |
189 | //Calculate Total number of blocks. |
190 | CardSize = gCardInfo->CSDData.C_SIZELow2 | (gCardInfo->CSDData.C_SIZEHigh10 << 2); |
191 | *NumBlocks = (CardSize + 1) * (1 << (gCardInfo->CSDData.C_SIZE_MULT + 2)); |
192 | } |
193 | |
194 | //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes. |
195 | if (*BlockSize > 512) { |
196 | *NumBlocks = MultU64x32(*NumBlocks, *BlockSize/2); |
197 | *BlockSize = 512; |
198 | } |
199 | |
200 | DEBUG ((EFI_D_INFO, "Card type: %x, BlockSize: %x, NumBlocks: %x\n", gCardInfo->CardType, *BlockSize, *NumBlocks)); |
201 | } |
202 | |
203 | STATIC |
204 | VOID |
205 | CalculateCardCLKD ( |
206 | UINTN *ClockFrequencySelect |
207 | ) |
208 | { |
209 | UINT8 MaxDataTransferRate; |
210 | UINTN TransferRateValue = 0; |
211 | UINTN TimeValue = 0 ; |
212 | UINTN Frequency = 0; |
213 | |
214 | MaxDataTransferRate = gCardInfo->CSDData.TRAN_SPEED; |
215 | |
216 | //Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED) |
217 | switch (MaxDataTransferRate & 0x7) { |
218 | case 0: |
219 | TransferRateValue = 100 * 1000; |
220 | break; |
221 | |
222 | case 1: |
223 | TransferRateValue = 1 * 1000 * 1000; |
224 | break; |
225 | |
226 | case 2: |
227 | TransferRateValue = 10 * 1000 * 1000; |
228 | break; |
229 | |
230 | case 3: |
231 | TransferRateValue = 100 * 1000 * 1000; |
232 | break; |
233 | |
234 | default: |
235 | DEBUG((EFI_D_ERROR, "Invalid parameter.\n")); |
236 | ASSERT(FALSE); |
237 | } |
238 | |
239 | //Calculate Time value (Bits 6:3 of TRAN_SPEED) |
240 | switch ((MaxDataTransferRate >> 3) & 0xF) { |
241 | case 1: |
242 | TimeValue = 10; |
243 | break; |
244 | |
245 | case 2: |
246 | TimeValue = 12; |
247 | break; |
248 | |
249 | case 3: |
250 | TimeValue = 13; |
251 | break; |
252 | |
253 | case 4: |
254 | TimeValue = 15; |
255 | break; |
256 | |
257 | case 5: |
258 | TimeValue = 20; |
259 | break; |
260 | |
261 | case 6: |
262 | TimeValue = 25; |
263 | break; |
264 | |
265 | case 7: |
266 | TimeValue = 30; |
267 | break; |
268 | |
269 | case 8: |
270 | TimeValue = 35; |
271 | break; |
272 | |
273 | case 9: |
274 | TimeValue = 40; |
275 | break; |
276 | |
277 | case 10: |
278 | TimeValue = 45; |
279 | break; |
280 | |
281 | case 11: |
282 | TimeValue = 50; |
283 | break; |
284 | |
285 | case 12: |
286 | TimeValue = 55; |
287 | break; |
288 | |
289 | case 13: |
290 | TimeValue = 60; |
291 | break; |
292 | |
293 | case 14: |
294 | TimeValue = 70; |
295 | break; |
296 | |
297 | case 15: |
298 | TimeValue = 80; |
299 | break; |
300 | |
301 | default: |
302 | DEBUG((EFI_D_ERROR, "Invalid parameter.\n")); |
303 | ASSERT(FALSE); |
304 | } |
305 | |
306 | Frequency = TransferRateValue * TimeValue/10; |
307 | |
308 | //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field. |
309 | *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1); |
310 | |
311 | DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect)); |
312 | } |
313 | |
314 | STATIC |
315 | VOID |
316 | GetCardConfigurationData ( |
317 | VOID |
318 | ) |
319 | { |
320 | UINTN BlockSize; |
321 | UINTN NumBlocks; |
322 | UINTN ClockFrequencySelect; |
323 | |
324 | //Calculate BlockSize and Total number of blocks in the detected card. |
325 | GetBlockInformation(&BlockSize, &NumBlocks); |
326 | gCardInfo->BlockSize = BlockSize; |
327 | gCardInfo->NumBlocks = NumBlocks; |
328 | |
329 | //Calculate Card clock divider value. |
330 | CalculateCardCLKD(&ClockFrequencySelect); |
331 | gCardInfo->ClockFrequencySelect = ClockFrequencySelect; |
332 | } |
333 | |
334 | STATIC |
335 | EFI_STATUS |
336 | InitializeMMCHS ( |
337 | VOID |
338 | ) |
339 | { |
340 | UINT8 Data = 0; |
341 | EFI_STATUS Status; |
342 | |
343 | //Select Device group to belong to P1 device group in Power IC. |
344 | Data = DEV_GRP_P1; |
345 | Status = gTPS65950->Write(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data); |
346 | ASSERT_EFI_ERROR(Status); |
347 | |
348 | //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage. |
349 | Data = VSEL_3_00V; |
350 | Status = gTPS65950->Write(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data); |
351 | ASSERT_EFI_ERROR(Status); |
352 | |
353 | //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable. |
354 | MmioOr32(CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1)); |
355 | |
356 | //Software reset of the MMCHS host controller. |
026e30c4 |
357 | MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET); |
a3f98646 |
358 | gBS->Stall(1000); |
359 | while ((MmioRead32(MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE); |
360 | |
361 | //Soft reset for all. |
026e30c4 |
362 | MmioWrite32 (MMCHS_SYSCTL, SRA); |
a3f98646 |
363 | gBS->Stall(1000); |
364 | while ((MmioRead32(MMCHS_SYSCTL) & SRA) != 0x0); |
365 | |
366 | //Voltage capabilities initialization. Activate VS18 and VS30. |
367 | MmioOr32(MMCHS_CAPA, (VS30 | VS18)); |
368 | |
369 | //Wakeup configuration |
370 | MmioOr32(MMCHS_SYSCONFIG, ENAWAKEUP); |
371 | MmioOr32(MMCHS_HCTL, IWE); |
372 | |
373 | //MMCHS Controller default initialization |
374 | MmioOr32(MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF)); |
375 | |
026e30c4 |
376 | MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF)); |
a3f98646 |
377 | |
378 | //Enable internal clock |
379 | MmioOr32(MMCHS_SYSCTL, ICE); |
380 | |
381 | //Set the clock frequency to 80KHz. |
382 | UpdateMMCHSClkFrequency(CLKD_80KHZ); |
383 | |
384 | //Enable SD bus power. |
385 | MmioOr32(MMCHS_HCTL, (SDBP_ON)); |
386 | |
387 | //Poll till SD bus power bit is set. |
388 | while ((MmioRead32(MMCHS_HCTL) & SDBP_MASK) != SDBP_ON); |
389 | |
390 | return Status; |
391 | } |
392 | |
393 | STATIC |
394 | EFI_STATUS |
395 | PerformCardIdenfication ( |
396 | VOID |
397 | ) |
398 | { |
399 | EFI_STATUS Status; |
400 | UINTN CmdArgument = 0; |
401 | UINTN Response = 0; |
402 | UINTN RetryCount = 0; |
403 | BOOLEAN SDCmd8Supported = FALSE; |
404 | |
405 | //Enable interrupts. |
026e30c4 |
406 | MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN | |
a3f98646 |
407 | CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN)); |
408 | |
409 | //Controller INIT procedure start. |
410 | MmioOr32(MMCHS_CON, INIT); |
026e30c4 |
411 | MmioWrite32 (MMCHS_CMD, 0x00000000); |
a3f98646 |
412 | while (!(MmioRead32(MMCHS_STAT) & CC)); |
413 | |
414 | //Wait for 1 ms |
415 | gBS->Stall(1000); |
416 | |
417 | //Set CC bit to 0x1 to clear the flag |
418 | MmioOr32(MMCHS_STAT, CC); |
419 | |
420 | //Retry INIT procedure. |
026e30c4 |
421 | MmioWrite32 (MMCHS_CMD, 0x00000000); |
a3f98646 |
422 | while (!(MmioRead32(MMCHS_STAT) & CC)); |
423 | |
424 | //End initialization sequence |
425 | MmioAnd32(MMCHS_CON, ~INIT); |
426 | |
427 | MmioOr32(MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON)); |
428 | |
429 | //Change clock frequency to 400KHz to fit protocol |
430 | UpdateMMCHSClkFrequency(CLKD_400KHZ); |
431 | |
432 | MmioOr32(MMCHS_CON, OD); |
433 | |
434 | //Send CMD0 command. |
435 | Status = SendCmd(CMD0, CMD0_INT_EN, CmdArgument); |
436 | if (EFI_ERROR(Status)) { |
437 | DEBUG ((EFI_D_ERROR, "Cmd0 fails.\n")); |
438 | return Status; |
439 | } |
440 | |
441 | DEBUG ((EFI_D_INFO, "CMD0 response: %x\n", MmioRead32(MMCHS_RSP10))); |
442 | |
443 | //Send CMD5 command. |
444 | Status = SendCmd(CMD5, CMD5_INT_EN, CmdArgument); |
445 | if (Status == EFI_SUCCESS) { |
446 | DEBUG ((EFI_D_ERROR, "CMD5 Success. SDIO card. Follow SDIO card specification.\n")); |
447 | DEBUG ((EFI_D_INFO, "CMD5 response: %x\n", MmioRead32(MMCHS_RSP10))); |
448 | //NOTE: Returning unsupported error for now. Need to implement SDIO specification. |
449 | return EFI_UNSUPPORTED; |
450 | } else { |
451 | DEBUG ((EFI_D_INFO, "CMD5 fails. Not an SDIO card.\n")); |
452 | } |
453 | |
454 | MmioOr32(MMCHS_SYSCTL, SRC); |
455 | gBS->Stall(1000); |
456 | while ((MmioRead32(MMCHS_SYSCTL) & SRC)); |
457 | |
458 | //Send CMD8 command. (New v2.00 command for Voltage check) |
459 | //Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass. |
460 | //MMC & SD1.1 card will fail this command. |
461 | CmdArgument = CMD8_ARG; |
462 | Status = SendCmd(CMD8, CMD8_INT_EN, CmdArgument); |
463 | if (Status == EFI_SUCCESS) { |
464 | Response = MmioRead32(MMCHS_RSP10); |
465 | DEBUG ((EFI_D_INFO, "CMD8 success. CMD8 response: %x\n", Response)); |
466 | if (Response != CmdArgument) { |
467 | return EFI_DEVICE_ERROR; |
468 | } |
469 | DEBUG ((EFI_D_INFO, "Card is SD2.0\n")); |
470 | SDCmd8Supported = TRUE; //Supports high capacity. |
471 | } else { |
472 | DEBUG ((EFI_D_INFO, "CMD8 fails. Not an SD2.0 card.\n")); |
473 | } |
474 | |
475 | MmioOr32(MMCHS_SYSCTL, SRC); |
476 | gBS->Stall(1000); |
477 | while ((MmioRead32(MMCHS_SYSCTL) & SRC)); |
478 | |
479 | //Poll till card is busy |
480 | while (RetryCount < MAX_RETRY_COUNT) { |
481 | //Send CMD55 command. |
482 | CmdArgument = 0; |
483 | Status = SendCmd(CMD55, CMD55_INT_EN, CmdArgument); |
484 | if (Status == EFI_SUCCESS) { |
485 | DEBUG ((EFI_D_INFO, "CMD55 success. CMD55 response: %x\n", MmioRead32(MMCHS_RSP10))); |
486 | gCardInfo->CardType = SD_CARD; |
487 | } else { |
488 | DEBUG ((EFI_D_INFO, "CMD55 fails.\n")); |
489 | gCardInfo->CardType = MMC_CARD; |
490 | } |
491 | |
492 | //Send appropriate command for the card type which got detected. |
493 | if (gCardInfo->CardType == SD_CARD) { |
494 | CmdArgument = ((UINTN *) &(gCardInfo->OCRData))[0]; |
495 | |
496 | //Set HCS bit. |
497 | if (SDCmd8Supported) { |
498 | CmdArgument |= HCS; |
499 | } |
500 | |
501 | Status = SendCmd(ACMD41, ACMD41_INT_EN, CmdArgument); |
502 | if (EFI_ERROR(Status)) { |
503 | DEBUG ((EFI_D_INFO, "ACMD41 fails.\n")); |
504 | return Status; |
505 | } |
506 | ((UINT32 *) &(gCardInfo->OCRData))[0] = MmioRead32(MMCHS_RSP10); |
507 | DEBUG ((EFI_D_INFO, "SD card detected. ACMD41 OCR: %x\n", ((UINT32 *) &(gCardInfo->OCRData))[0])); |
508 | } else if (gCardInfo->CardType == MMC_CARD) { |
509 | CmdArgument = 0; |
510 | Status = SendCmd(CMD1, CMD1_INT_EN, CmdArgument); |
511 | if (EFI_ERROR(Status)) { |
512 | DEBUG ((EFI_D_INFO, "CMD1 fails.\n")); |
513 | return Status; |
514 | } |
515 | Response = MmioRead32(MMCHS_RSP10); |
516 | DEBUG ((EFI_D_INFO, "MMC card detected.. CMD1 response: %x\n", Response)); |
517 | |
518 | //NOTE: For now, I am skipping this since I only have an SD card. |
519 | //Compare card OCR and host OCR (Section 22.6.1.3.2.4) |
520 | return EFI_UNSUPPORTED; //For now, MMC is not supported. |
521 | } |
522 | |
523 | //Poll the card until it is out of its power-up sequence. |
524 | if (gCardInfo->OCRData.Busy == 1) { |
525 | |
526 | if (SDCmd8Supported) { |
527 | gCardInfo->CardType = SD_CARD_2; |
528 | } |
529 | |
530 | //Card is ready. Check CCS (Card capacity status) bit (bit#30). |
531 | //SD 2.0 standard card will response with CCS 0, SD high capacity card will respond with CCS 1. |
532 | if (gCardInfo->OCRData.AccessMode & BIT1) { |
533 | gCardInfo->CardType = SD_CARD_2_HIGH; |
534 | DEBUG ((EFI_D_INFO, "High capacity card.\n")); |
535 | } else { |
536 | DEBUG ((EFI_D_INFO, "Standard capacity card.\n")); |
537 | } |
538 | |
539 | break; |
540 | } |
541 | |
542 | gBS->Stall(1000); |
543 | RetryCount++; |
544 | } |
545 | |
546 | if (RetryCount == MAX_RETRY_COUNT) { |
547 | DEBUG ((EFI_D_ERROR, "Timeout error. RetryCount: %d\n", RetryCount)); |
548 | return EFI_TIMEOUT; |
549 | } |
550 | |
551 | //Read CID data. |
552 | CmdArgument = 0; |
553 | Status = SendCmd(CMD2, CMD2_INT_EN, CmdArgument); |
554 | if (EFI_ERROR(Status)) { |
555 | DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status)); |
556 | return Status; |
557 | } |
558 | |
559 | DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32(MMCHS_RSP10), MmioRead32(MMCHS_RSP32), MmioRead32(MMCHS_RSP54), MmioRead32(MMCHS_RSP76))); |
560 | |
561 | //Parse CID register data. |
562 | ParseCardCIDData(MmioRead32(MMCHS_RSP10), MmioRead32(MMCHS_RSP32), MmioRead32(MMCHS_RSP54), MmioRead32(MMCHS_RSP76)); |
563 | |
564 | //Read RCA |
565 | CmdArgument = 0; |
566 | Status = SendCmd(CMD3, CMD3_INT_EN, CmdArgument); |
567 | if (EFI_ERROR(Status)) { |
568 | DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status)); |
569 | return Status; |
570 | } |
571 | |
572 | //Set RCA for the detected card. RCA is CMD3 response. |
573 | gCardInfo->RCA = (MmioRead32(MMCHS_RSP10) >> 16); |
574 | DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo->RCA)); |
575 | |
576 | //MMC Bus setting change after card identification. |
577 | MmioAnd32(MMCHS_CON, ~OD); |
578 | MmioOr32(MMCHS_HCTL, SDVS_3_0_V); |
579 | UpdateMMCHSClkFrequency(CLKD_400KHZ); //Set the clock frequency to 400KHz. |
580 | |
581 | return EFI_SUCCESS; |
582 | } |
583 | |
584 | STATIC |
585 | EFI_STATUS |
586 | GetCardSpecificData ( |
587 | VOID |
588 | ) |
589 | { |
590 | EFI_STATUS Status; |
591 | UINTN CmdArgument; |
592 | |
593 | //Send CMD9 to retrieve CSD. |
594 | CmdArgument = gCardInfo->RCA << 16; |
595 | Status = SendCmd(CMD9, CMD9_INT_EN, CmdArgument); |
596 | if (EFI_ERROR(Status)) { |
597 | DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status)); |
598 | return Status; |
599 | } |
600 | |
601 | //Populate 128-bit CSD register data. |
602 | ((UINT32 *)&(gCardInfo->CSDData))[0] = MmioRead32(MMCHS_RSP10); |
603 | ((UINT32 *)&(gCardInfo->CSDData))[1] = MmioRead32(MMCHS_RSP32); |
604 | ((UINT32 *)&(gCardInfo->CSDData))[2] = MmioRead32(MMCHS_RSP54); |
605 | ((UINT32 *)&(gCardInfo->CSDData))[3] = MmioRead32(MMCHS_RSP76); |
606 | |
607 | DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", MmioRead32(MMCHS_RSP10), MmioRead32(MMCHS_RSP32), MmioRead32(MMCHS_RSP54), MmioRead32(MMCHS_RSP76))); |
608 | |
609 | //Calculate total number of blocks and max. data transfer rate supported by the detected card. |
610 | GetCardConfigurationData(); |
611 | |
612 | //Change MMCHS clock frequency to what detected card can support. |
613 | UpdateMMCHSClkFrequency(gCardInfo->ClockFrequencySelect); |
614 | |
615 | return Status; |
616 | } |
617 | |
618 | STATIC |
619 | EFI_STATUS |
620 | PerformCardConfiguration ( |
621 | VOID |
622 | ) |
623 | { |
624 | UINTN CmdArgument = 0; |
625 | EFI_STATUS Status; |
626 | |
627 | //Send CMD7 |
628 | CmdArgument = gCardInfo->RCA << 16; |
629 | Status = SendCmd(CMD7, CMD7_INT_EN, CmdArgument); |
630 | if (EFI_ERROR(Status)) { |
631 | DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", Status)); |
632 | return Status; |
633 | } |
634 | |
635 | //Send CMD16 to set the block length |
636 | CmdArgument = gCardInfo->BlockSize; |
637 | Status = SendCmd(CMD16, CMD16_INT_EN, CmdArgument); |
638 | if (EFI_ERROR(Status)) { |
639 | DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status)); |
640 | return Status; |
641 | } |
642 | |
643 | return EFI_SUCCESS; |
644 | } |
645 | |
646 | STATIC |
647 | EFI_STATUS |
648 | ReadBlockData( |
649 | IN EFI_BLOCK_IO_PROTOCOL *This, |
650 | OUT VOID *Buffer |
651 | ) |
652 | { |
653 | UINTN MmcStatus; |
654 | UINTN *DataBuffer = Buffer; |
655 | UINTN DataSize = This->Media->BlockSize/4; |
656 | UINTN Count; |
657 | UINTN RetryCount = 0; |
658 | |
659 | //Check controller status to make sure there is no error. |
660 | while (RetryCount < MAX_RETRY_COUNT) { |
661 | do { |
662 | //Read Status. |
663 | MmcStatus = MmioRead32(MMCHS_STAT); |
664 | } while(MmcStatus == 0); |
665 | |
666 | //Check if Buffer read ready (BRR) bit is set? |
667 | if (MmcStatus & BRR) { |
668 | |
669 | //Clear BRR bit |
670 | MmioOr32(MMCHS_STAT, BRR); |
671 | |
672 | //Read block worth of data. |
673 | for (Count = 0; Count < DataSize; Count++) { |
674 | *DataBuffer++ = MmioRead32(MMCHS_DATA); |
675 | } |
676 | break; |
677 | } |
678 | RetryCount++; |
679 | } |
680 | |
681 | if (RetryCount == MAX_RETRY_COUNT) { |
682 | return EFI_TIMEOUT; |
683 | } |
684 | |
685 | return EFI_SUCCESS; |
686 | } |
687 | |
688 | STATIC |
689 | EFI_STATUS |
690 | WriteBlockData( |
691 | IN EFI_BLOCK_IO_PROTOCOL *This, |
692 | OUT VOID *Buffer |
693 | ) |
694 | { |
695 | UINTN MmcStatus; |
696 | UINTN *DataBuffer = Buffer; |
697 | UINTN DataSize = This->Media->BlockSize/4; |
698 | UINTN Count; |
699 | UINTN RetryCount = 0; |
700 | |
701 | //Check controller status to make sure there is no error. |
702 | while (RetryCount < MAX_RETRY_COUNT) { |
703 | do { |
704 | //Read Status. |
705 | MmcStatus = MmioRead32(MMCHS_STAT); |
706 | } while(MmcStatus == 0); |
707 | |
708 | //Check if Buffer write ready (BWR) bit is set? |
709 | if (MmcStatus & BWR) { |
710 | |
711 | //Clear BWR bit |
712 | MmioOr32(MMCHS_STAT, BWR); |
713 | |
714 | //Write block worth of data. |
715 | for (Count = 0; Count < DataSize; Count++) { |
026e30c4 |
716 | MmioWrite32 (MMCHS_DATA, *DataBuffer++); |
a3f98646 |
717 | } |
718 | |
719 | break; |
720 | } |
721 | RetryCount++; |
722 | } |
723 | |
724 | if (RetryCount == MAX_RETRY_COUNT) { |
725 | return EFI_TIMEOUT; |
726 | } |
727 | |
728 | return EFI_SUCCESS; |
729 | } |
730 | |
731 | STATIC |
732 | EFI_STATUS |
733 | TransferBlockData( |
734 | IN EFI_BLOCK_IO_PROTOCOL *This, |
735 | OUT VOID *Buffer, |
736 | IN OPERATION_TYPE OperationType |
737 | ) |
738 | { |
739 | EFI_STATUS Status; |
740 | UINTN MmcStatus; |
741 | UINTN RetryCount = 0; |
742 | |
743 | //Read or Write data. |
744 | if (OperationType == READ) { |
745 | Status = ReadBlockData(This, Buffer); |
746 | if (EFI_ERROR(Status)) { |
747 | DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n")); |
748 | return Status; |
749 | } |
750 | } else if (OperationType == WRITE) { |
751 | Status = WriteBlockData(This, Buffer); |
752 | if (EFI_ERROR(Status)) { |
753 | DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n")); |
754 | return Status; |
755 | } |
756 | } |
757 | |
758 | //Check for the Transfer completion. |
759 | while (RetryCount < MAX_RETRY_COUNT) { |
760 | //Read Status |
761 | do { |
762 | MmcStatus = MmioRead32(MMCHS_STAT); |
763 | } while (MmcStatus == 0); |
764 | |
765 | //Check if Transfer complete (TC) bit is set? |
766 | if (MmcStatus & TC) { |
767 | break; |
768 | } else { |
769 | DEBUG ((EFI_D_ERROR, "MmcStatus for TC: %x\n", MmcStatus)); |
770 | //Check if DEB, DCRC or DTO interrupt occured. |
771 | if ((MmcStatus & DEB) | (MmcStatus & DCRC) | (MmcStatus & DTO)) { |
772 | //There was an error during the data transfer. |
773 | |
774 | //Set SRD bit to 1 and wait until it return to 0x0. |
775 | MmioOr32(MMCHS_SYSCTL, SRD); |
776 | while((MmioRead32(MMCHS_SYSCTL) & SRD) != 0x0); |
777 | |
778 | return EFI_DEVICE_ERROR; |
779 | } |
780 | } |
781 | RetryCount++; |
782 | } |
783 | |
784 | if (RetryCount == MAX_RETRY_COUNT) { |
785 | DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n")); |
786 | return EFI_TIMEOUT; |
787 | } |
788 | |
789 | return EFI_SUCCESS; |
790 | } |
791 | |
792 | STATIC |
793 | EFI_STATUS |
794 | SdReadWrite ( |
795 | IN EFI_BLOCK_IO_PROTOCOL *This, |
796 | IN UINTN Lba, |
797 | OUT VOID *Buffer, |
798 | IN UINTN BufferSize, |
799 | IN OPERATION_TYPE OperationType |
800 | ) |
801 | { |
802 | EFI_STATUS Status; |
803 | UINTN RetryCount = 0; |
804 | UINTN NumBlocks; |
805 | UINTN Cmd = 0; |
806 | UINTN CmdInterruptEnable = 0; |
807 | UINTN CmdArgument = 0; |
808 | |
809 | //Check if the data lines are not in use. |
810 | while ((RetryCount++ < MAX_RETRY_COUNT) && ((MmioRead32(MMCHS_PSTATE) & DATI_MASK) != DATI_ALLOWED)); |
811 | if (RetryCount == MAX_RETRY_COUNT) { |
812 | return EFI_TIMEOUT; |
813 | } |
814 | |
815 | //Populate the command information based on the operation type. |
816 | if (OperationType == READ) { |
817 | Cmd = CMD17; //Single block read |
818 | CmdInterruptEnable = CMD17_INT_EN; |
819 | } else if (OperationType == WRITE) { |
820 | Cmd = CMD24; //Single block write |
821 | CmdInterruptEnable = CMD24_INT_EN; |
822 | } |
823 | |
824 | //Calculate total number of blocks its going to read. |
825 | NumBlocks = (BufferSize + (This->Media->BlockSize - 1))/This->Media->BlockSize; |
826 | |
827 | //Set command argument based on the card access mode (Byte mode or Block mode) |
828 | if (gCardInfo->OCRData.AccessMode & BIT1) { |
829 | CmdArgument = (UINTN)Lba; |
830 | } else { |
831 | CmdArgument = (UINTN)Lba * This->Media->BlockSize; |
832 | } |
833 | |
834 | while(NumBlocks) { |
835 | //Send Command. |
836 | Status = SendCmd(Cmd, CmdInterruptEnable, CmdArgument); |
837 | if (EFI_ERROR(Status)) { |
838 | DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status)); |
839 | return Status; |
840 | } |
841 | |
842 | //Transfer a block worth of data. |
843 | Status = TransferBlockData(This, Buffer, OperationType); |
844 | if (EFI_ERROR(Status)) { |
845 | DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status)); |
846 | return Status; |
847 | } |
848 | |
849 | //Adjust command argument. |
850 | if (gCardInfo->OCRData.AccessMode & BIT1) { |
851 | CmdArgument++; //Increase BlockIndex by one. |
852 | } else { |
853 | CmdArgument += This->Media->BlockSize; //Increase BlockIndex by BlockSize |
854 | } |
855 | |
856 | //Adjust Buffer. |
857 | Buffer = (UINT8 *)Buffer + This->Media->BlockSize; |
858 | NumBlocks--; |
859 | } |
860 | |
861 | return EFI_SUCCESS; |
862 | } |
863 | |
864 | EFI_STATUS |
865 | EFIAPI |
866 | MMCHSReset ( |
867 | IN EFI_BLOCK_IO_PROTOCOL *This, |
868 | IN BOOLEAN ExtendedVerification |
869 | ) |
870 | { |
871 | return EFI_SUCCESS; |
872 | } |
873 | |
874 | EFI_STATUS |
875 | EFIAPI |
876 | MMCHSReadBlocks ( |
877 | IN EFI_BLOCK_IO_PROTOCOL *This, |
878 | IN UINT32 MediaId, |
879 | IN EFI_LBA Lba, |
880 | IN UINTN BufferSize, |
881 | OUT VOID *Buffer |
882 | ) |
883 | { |
884 | EFI_STATUS Status; |
885 | |
886 | if (Buffer == NULL) |
887 | { |
888 | return EFI_INVALID_PARAMETER; |
889 | } |
890 | |
891 | if (Lba > This->Media->LastBlock) |
892 | { |
893 | return EFI_INVALID_PARAMETER; |
894 | } |
895 | |
896 | if ((BufferSize % This->Media->BlockSize) != 0) |
897 | { |
898 | return EFI_BAD_BUFFER_SIZE; |
899 | } |
900 | |
901 | //Perform Read operation. |
902 | Status = SdReadWrite(This, (UINTN)Lba, Buffer, BufferSize, READ); |
903 | if (EFI_ERROR(Status)) { |
904 | DEBUG ((EFI_D_ERROR, "Read operation fails.\n")); |
905 | } |
906 | |
907 | return Status; |
908 | } |
909 | |
910 | EFI_STATUS |
911 | EFIAPI |
912 | MMCHSWriteBlocks ( |
913 | IN EFI_BLOCK_IO_PROTOCOL *This, |
914 | IN UINT32 MediaId, |
915 | IN EFI_LBA Lba, |
916 | IN UINTN BufferSize, |
917 | IN VOID *Buffer |
918 | ) |
919 | { |
920 | EFI_STATUS Status; |
921 | |
922 | if (Buffer == NULL) { |
923 | return EFI_INVALID_PARAMETER; |
924 | } |
925 | |
926 | if (Lba > This->Media->LastBlock) { |
927 | return EFI_INVALID_PARAMETER; |
928 | } |
929 | |
930 | if ((BufferSize % This->Media->BlockSize) != 0) { |
931 | return EFI_BAD_BUFFER_SIZE; |
932 | } |
933 | |
934 | if (This->Media->ReadOnly) { |
935 | return EFI_WRITE_PROTECTED; |
936 | } |
937 | |
938 | //Perform write operation. |
939 | Status = SdReadWrite(This, (UINTN)Lba, Buffer, BufferSize, WRITE); |
940 | if (EFI_ERROR(Status)) { |
941 | DEBUG ((EFI_D_ERROR, "Write operation fails.\n")); |
942 | } |
943 | |
944 | return Status; |
945 | } |
946 | |
947 | EFI_STATUS |
948 | EFIAPI |
949 | MMCHSFlushBlocks ( |
950 | IN EFI_BLOCK_IO_PROTOCOL *This |
951 | ) |
952 | { |
953 | return EFI_SUCCESS; |
954 | } |
955 | |
956 | EFI_BLOCK_IO_PROTOCOL BlockIo = |
957 | { |
958 | EFI_BLOCK_IO_INTERFACE_REVISION, // Revision |
959 | &MMCHSMedia, // *Media |
960 | MMCHSReset, // Reset |
961 | MMCHSReadBlocks, // ReadBlocks |
962 | MMCHSWriteBlocks, // WriteBlocks |
963 | MMCHSFlushBlocks // FlushBlocks |
964 | }; |
965 | |
966 | EFI_STATUS |
967 | MMCHSInitialize ( |
968 | IN EFI_HANDLE ImageHandle, |
969 | IN EFI_SYSTEM_TABLE *SystemTable |
970 | ) |
971 | { |
972 | EFI_STATUS Status; |
973 | |
974 | Status = gBS->LocateProtocol(&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950); |
975 | ASSERT_EFI_ERROR(Status); |
976 | |
977 | gCardInfo = (CARD_INFO *)AllocateZeroPool(sizeof(CARD_INFO)); |
978 | if (gCardInfo == NULL) { |
979 | return EFI_OUT_OF_RESOURCES; |
980 | } |
981 | |
982 | //Initialize MMC host controller. |
983 | Status = InitializeMMCHS(); |
984 | if (EFI_ERROR(Status)) { |
985 | DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status)); |
986 | return Status; |
987 | } |
988 | |
989 | //Card idenfication |
990 | Status = PerformCardIdenfication(); |
991 | if (EFI_ERROR(Status)) { |
992 | DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n")); |
993 | return EFI_SUCCESS; //NOTE: Check if this is correct.. |
994 | } |
995 | |
996 | //Get CSD (Card specific data) for the detected card. |
997 | Status = GetCardSpecificData(); |
998 | if (EFI_ERROR(Status)) { |
999 | return Status; |
1000 | } |
1001 | |
1002 | //Configure the card in data transfer mode. |
1003 | Status = PerformCardConfiguration(); |
1004 | if (EFI_ERROR(Status)) { |
1005 | return Status; |
1006 | } |
1007 | |
1008 | //Patch the Media structure. |
1009 | MMCHSMedia.LastBlock = (gCardInfo->NumBlocks - 1); |
1010 | MMCHSMedia.BlockSize = gCardInfo->BlockSize; |
1011 | |
1012 | //Publish BlockIO. |
1013 | Status = gBS->InstallMultipleProtocolInterfaces(&ImageHandle, |
1014 | &gEfiBlockIoProtocolGuid, &BlockIo, |
1015 | &gEfiDevicePathProtocolGuid, &gMmcHsDevicePath, |
1016 | NULL); |
1017 | return Status; |
1018 | } |