]> git.proxmox.com Git - mirror_edk2.git/blame - Omap35xxPkg/MMCHSDxe/MMCHS.c
Removed connect/disconnect in device command and replace with simple BlockIo readbloc...
[mirror_edk2.git] / Omap35xxPkg / MMCHSDxe / MMCHS.c
CommitLineData
a3f98646 1/** @file
8c6151f2 2 MMC/SD Card driver for OMAP 35xx (SDIO not supported)
3
4 This driver always produces a BlockIo protocol but it starts off with no Media
5 present. A TimerCallBack detects when media is inserted or removed and after
6 a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the
7 media to be detected (or removed) and the BlockIo Media structure will get
8 updated. No MMC/SD Card harward registers are updated until the first BlockIo
9 ReadBlocks/WriteBlocks after media has been insterted (booting with a card
10 plugged in counts as an insertion event).
a3f98646 11
3d70643b 12 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
a3f98646 13
3d70643b 14 This program and the accompanying materials
a3f98646 15 are licensed and made available under the terms and conditions of the BSD License
16 which accompanies this distribution. The full text of the license may be found at
17 http://opensource.org/licenses/bsd-license.php
18
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21
22**/
23
24#include <Uefi.h>
25
26#include "MMCHS.h"
27
8c6151f2 28EFI_BLOCK_IO_MEDIA gMMCHSMedia = {
a3f98646 29 SIGNATURE_32('s','d','i','o'), // MediaId
30 TRUE, // RemovableMedia
8c6151f2 31 FALSE, // MediaPresent
a3f98646 32 FALSE, // LogicalPartition
33 FALSE, // ReadOnly
34 FALSE, // WriteCaching
35 512, // BlockSize
36 4, // IoAlign
37 0, // Pad
38 0 // LastBlock
39};
40
41typedef struct {
42 VENDOR_DEVICE_PATH Mmc;
43 EFI_DEVICE_PATH End;
44} MMCHS_DEVICE_PATH;
45
8c6151f2 46MMCHS_DEVICE_PATH gMmcHsDevicePath = {
a3f98646 47 {
48 HARDWARE_DEVICE_PATH,
49 HW_VENDOR_DP,
50 (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
51 (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
52 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00
53 },
54 {
55 END_DEVICE_PATH_TYPE,
56 END_ENTIRE_DEVICE_PATH_SUBTYPE,
57 sizeof (EFI_DEVICE_PATH_PROTOCOL),
58 0
59 }
60};
61
8c6151f2 62CARD_INFO gCardInfo;
a3f98646 63EMBEDDED_EXTERNAL_DEVICE *gTPS65950;
8c6151f2 64EFI_EVENT gTimerEvent;
65BOOLEAN gMediaChange = FALSE;
a3f98646 66
67//
68// Internal Functions
69//
70
8c6151f2 71
a3f98646 72VOID
73ParseCardCIDData (
74 UINT32 Response0,
75 UINT32 Response1,
76 UINT32 Response2,
77 UINT32 Response3
78 )
79{
8c6151f2 80 gCardInfo.CIDData.MDT = ((Response0 >> 8) & 0xFFF);
81 gCardInfo.CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8));
82 gCardInfo.CIDData.PRV = ((Response1 >> 24) & 0xFF);
83 gCardInfo.CIDData.PNM[4] = ((Response2) & 0xFF);
84 gCardInfo.CIDData.PNM[3] = ((Response2 >> 8) & 0xFF);
85 gCardInfo.CIDData.PNM[2] = ((Response2 >> 16) & 0xFF);
86 gCardInfo.CIDData.PNM[1] = ((Response2 >> 24) & 0xFF);
87 gCardInfo.CIDData.PNM[0] = ((Response3) & 0xFF);
88 gCardInfo.CIDData.OID = ((Response3 >> 8) & 0xFFFF);
89 gCardInfo.CIDData.MID = ((Response3 >> 24) & 0xFF);
a3f98646 90}
91
8c6151f2 92
a3f98646 93VOID
94UpdateMMCHSClkFrequency (
95 UINTN NewCLKD
96 )
97{
98 //Set Clock enable to 0x0 to not provide the clock to the card
8c6151f2 99 MmioAnd32 (MMCHS_SYSCTL, ~CEN);
a3f98646 100
101 //Set new clock frequency.
8c6151f2 102 MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6);
a3f98646 103
104 //Poll till Internal Clock Stable
43263288 105 while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);
a3f98646 106
107 //Set Clock enable to 0x1 to provide the clock to the card
43263288 108 MmioOr32 (MMCHS_SYSCTL, CEN);
a3f98646 109}
110
8c6151f2 111
a3f98646 112EFI_STATUS
113SendCmd (
114 UINTN Cmd,
115 UINTN CmdInterruptEnableVal,
116 UINTN CmdArgument
117 )
118{
119 UINTN MmcStatus;
120 UINTN RetryCount = 0;
121
122 //Check if command line is in use or not. Poll till command line is available.
43263288 123 while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);
a3f98646 124
125 //Provide the block size.
026e30c4 126 MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);
a3f98646 127
128 //Setting Data timeout counter value to max value.
8c6151f2 129 MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);
a3f98646 130
131 //Clear Status register.
026e30c4 132 MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);
a3f98646 133
134 //Set command argument register
026e30c4 135 MmioWrite32 (MMCHS_ARG, CmdArgument);
a3f98646 136
137 //Enable interrupt enable events to occur
026e30c4 138 MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);
a3f98646 139
140 //Send a command
026e30c4 141 MmioWrite32 (MMCHS_CMD, Cmd);
a3f98646 142
143 //Check for the command status.
144 while (RetryCount < MAX_RETRY_COUNT) {
145 do {
43263288 146 MmcStatus = MmioRead32 (MMCHS_STAT);
a3f98646 147 } while (MmcStatus == 0);
148
149 //Read status of command response
150 if ((MmcStatus & ERRI) != 0) {
151
152 //Perform soft-reset for mmci_cmd line.
43263288 153 MmioOr32 (MMCHS_SYSCTL, SRC);
154 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
a3f98646 155
156 DEBUG ((EFI_D_INFO, "MmcStatus: %x\n", MmcStatus));
157 return EFI_DEVICE_ERROR;
158 }
159
160 //Check if command is completed.
161 if ((MmcStatus & CC) == CC) {
026e30c4 162 MmioWrite32 (MMCHS_STAT, CC);
a3f98646 163 break;
164 }
165
166 RetryCount++;
167 }
168
169 if (RetryCount == MAX_RETRY_COUNT) {
170 return EFI_TIMEOUT;
171 }
172
173 return EFI_SUCCESS;
174}
175
8c6151f2 176
a3f98646 177VOID
178GetBlockInformation (
179 UINTN *BlockSize,
180 UINTN *NumBlocks
181 )
182{
183 CSD_SDV2 *CsdSDV2Data;
184 UINTN CardSize;
185
8c6151f2 186 if (gCardInfo.CardType == SD_CARD_2_HIGH) {
187 CsdSDV2Data = (CSD_SDV2 *)&gCardInfo.CSDData;
a3f98646 188
189 //Populate BlockSize.
190 *BlockSize = (0x1UL << CsdSDV2Data->READ_BL_LEN);
191
192 //Calculate Total number of blocks.
193 CardSize = CsdSDV2Data->C_SIZELow16 | (CsdSDV2Data->C_SIZEHigh6 << 2);
194 *NumBlocks = ((CardSize + 1) * 1024);
195 } else {
196 //Populate BlockSize.
8c6151f2 197 *BlockSize = (0x1UL << gCardInfo.CSDData.READ_BL_LEN);
a3f98646 198
199 //Calculate Total number of blocks.
8c6151f2 200 CardSize = gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2);
201 *NumBlocks = (CardSize + 1) * (1 << (gCardInfo.CSDData.C_SIZE_MULT + 2));
a3f98646 202 }
203
204 //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
205 if (*BlockSize > 512) {
206 *NumBlocks = MultU64x32(*NumBlocks, *BlockSize/2);
207 *BlockSize = 512;
208 }
209
8c6151f2 210 DEBUG ((EFI_D_INFO, "Card type: %x, BlockSize: %x, NumBlocks: %x\n", gCardInfo.CardType, *BlockSize, *NumBlocks));
a3f98646 211}
212
8c6151f2 213
a3f98646 214VOID
215CalculateCardCLKD (
216 UINTN *ClockFrequencySelect
217 )
218{
219 UINT8 MaxDataTransferRate;
220 UINTN TransferRateValue = 0;
221 UINTN TimeValue = 0 ;
222 UINTN Frequency = 0;
223
8c6151f2 224 MaxDataTransferRate = gCardInfo.CSDData.TRAN_SPEED;
a3f98646 225
226 //Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
227 switch (MaxDataTransferRate & 0x7) {
228 case 0:
229 TransferRateValue = 100 * 1000;
230 break;
231
232 case 1:
233 TransferRateValue = 1 * 1000 * 1000;
234 break;
235
236 case 2:
237 TransferRateValue = 10 * 1000 * 1000;
238 break;
239
240 case 3:
241 TransferRateValue = 100 * 1000 * 1000;
242 break;
243
244 default:
245 DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
246 ASSERT(FALSE);
247 }
248
249 //Calculate Time value (Bits 6:3 of TRAN_SPEED)
250 switch ((MaxDataTransferRate >> 3) & 0xF) {
251 case 1:
252 TimeValue = 10;
253 break;
254
255 case 2:
256 TimeValue = 12;
257 break;
258
259 case 3:
260 TimeValue = 13;
261 break;
262
263 case 4:
264 TimeValue = 15;
265 break;
266
267 case 5:
268 TimeValue = 20;
269 break;
270
271 case 6:
272 TimeValue = 25;
273 break;
274
275 case 7:
276 TimeValue = 30;
277 break;
278
279 case 8:
280 TimeValue = 35;
281 break;
282
283 case 9:
284 TimeValue = 40;
285 break;
286
287 case 10:
288 TimeValue = 45;
289 break;
290
291 case 11:
292 TimeValue = 50;
293 break;
294
295 case 12:
296 TimeValue = 55;
297 break;
298
299 case 13:
300 TimeValue = 60;
301 break;
302
303 case 14:
304 TimeValue = 70;
305 break;
306
307 case 15:
308 TimeValue = 80;
309 break;
310
311 default:
312 DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
313 ASSERT(FALSE);
314 }
315
316 Frequency = TransferRateValue * TimeValue/10;
317
318 //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.
319 *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);
320
321 DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));
322}
323
8c6151f2 324
a3f98646 325VOID
326GetCardConfigurationData (
327 VOID
328 )
329{
330 UINTN BlockSize;
331 UINTN NumBlocks;
332 UINTN ClockFrequencySelect;
333
334 //Calculate BlockSize and Total number of blocks in the detected card.
335 GetBlockInformation(&BlockSize, &NumBlocks);
8c6151f2 336 gCardInfo.BlockSize = BlockSize;
337 gCardInfo.NumBlocks = NumBlocks;
a3f98646 338
339 //Calculate Card clock divider value.
340 CalculateCardCLKD(&ClockFrequencySelect);
8c6151f2 341 gCardInfo.ClockFrequencySelect = ClockFrequencySelect;
a3f98646 342}
343
8c6151f2 344
a3f98646 345EFI_STATUS
346InitializeMMCHS (
347 VOID
348 )
349{
350 UINT8 Data = 0;
351 EFI_STATUS Status;
352
353 //Select Device group to belong to P1 device group in Power IC.
354 Data = DEV_GRP_P1;
8c6151f2 355 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);
a3f98646 356 ASSERT_EFI_ERROR(Status);
357
358 //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.
359 Data = VSEL_3_00V;
8c6151f2 360 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);
a3f98646 361 ASSERT_EFI_ERROR(Status);
362
363 //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.
43263288 364 MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));
a3f98646 365
8c6151f2 366 // Enable WP GPIO
367 MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);
a3f98646 368
8c6151f2 369 // Enable Card Detect
370 Data = CARD_DETECT_ENABLE;
371 gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);
a3f98646 372
a3f98646 373
374 return Status;
375}
376
8c6151f2 377
a3f98646 378EFI_STATUS
379PerformCardIdenfication (
380 VOID
381 )
382{
383 EFI_STATUS Status;
384 UINTN CmdArgument = 0;
385 UINTN Response = 0;
386 UINTN RetryCount = 0;
387 BOOLEAN SDCmd8Supported = FALSE;
388
389 //Enable interrupts.
8c6151f2 390 MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |
a3f98646 391 CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));
392
393 //Controller INIT procedure start.
43263288 394 MmioOr32 (MMCHS_CON, INIT);
026e30c4 395 MmioWrite32 (MMCHS_CMD, 0x00000000);
43263288 396 while (!(MmioRead32 (MMCHS_STAT) & CC));
a3f98646 397
398 //Wait for 1 ms
399 gBS->Stall(1000);
400
401 //Set CC bit to 0x1 to clear the flag
43263288 402 MmioOr32 (MMCHS_STAT, CC);
a3f98646 403
404 //Retry INIT procedure.
026e30c4 405 MmioWrite32 (MMCHS_CMD, 0x00000000);
43263288 406 while (!(MmioRead32 (MMCHS_STAT) & CC));
a3f98646 407
408 //End initialization sequence
8c6151f2 409 MmioAnd32 (MMCHS_CON, ~INIT);
a3f98646 410
43263288 411 MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));
a3f98646 412
413 //Change clock frequency to 400KHz to fit protocol
414 UpdateMMCHSClkFrequency(CLKD_400KHZ);
415
43263288 416 MmioOr32 (MMCHS_CON, OD);
a3f98646 417
418 //Send CMD0 command.
8c6151f2 419 Status = SendCmd (CMD0, CMD0_INT_EN, CmdArgument);
a3f98646 420 if (EFI_ERROR(Status)) {
421 DEBUG ((EFI_D_ERROR, "Cmd0 fails.\n"));
422 return Status;
423 }
424
43263288 425 DEBUG ((EFI_D_INFO, "CMD0 response: %x\n", MmioRead32 (MMCHS_RSP10)));
a3f98646 426
427 //Send CMD5 command.
8c6151f2 428 Status = SendCmd (CMD5, CMD5_INT_EN, CmdArgument);
a3f98646 429 if (Status == EFI_SUCCESS) {
430 DEBUG ((EFI_D_ERROR, "CMD5 Success. SDIO card. Follow SDIO card specification.\n"));
43263288 431 DEBUG ((EFI_D_INFO, "CMD5 response: %x\n", MmioRead32 (MMCHS_RSP10)));
a3f98646 432 //NOTE: Returning unsupported error for now. Need to implement SDIO specification.
433 return EFI_UNSUPPORTED;
434 } else {
435 DEBUG ((EFI_D_INFO, "CMD5 fails. Not an SDIO card.\n"));
436 }
437
43263288 438 MmioOr32 (MMCHS_SYSCTL, SRC);
a3f98646 439 gBS->Stall(1000);
43263288 440 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
a3f98646 441
442 //Send CMD8 command. (New v2.00 command for Voltage check)
443 //Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass.
444 //MMC & SD1.1 card will fail this command.
445 CmdArgument = CMD8_ARG;
8c6151f2 446 Status = SendCmd (CMD8, CMD8_INT_EN, CmdArgument);
a3f98646 447 if (Status == EFI_SUCCESS) {
43263288 448 Response = MmioRead32 (MMCHS_RSP10);
a3f98646 449 DEBUG ((EFI_D_INFO, "CMD8 success. CMD8 response: %x\n", Response));
450 if (Response != CmdArgument) {
451 return EFI_DEVICE_ERROR;
452 }
453 DEBUG ((EFI_D_INFO, "Card is SD2.0\n"));
454 SDCmd8Supported = TRUE; //Supports high capacity.
455 } else {
456 DEBUG ((EFI_D_INFO, "CMD8 fails. Not an SD2.0 card.\n"));
457 }
458
43263288 459 MmioOr32 (MMCHS_SYSCTL, SRC);
a3f98646 460 gBS->Stall(1000);
43263288 461 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
a3f98646 462
463 //Poll till card is busy
464 while (RetryCount < MAX_RETRY_COUNT) {
465 //Send CMD55 command.
466 CmdArgument = 0;
8c6151f2 467 Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);
a3f98646 468 if (Status == EFI_SUCCESS) {
43263288 469 DEBUG ((EFI_D_INFO, "CMD55 success. CMD55 response: %x\n", MmioRead32 (MMCHS_RSP10)));
8c6151f2 470 gCardInfo.CardType = SD_CARD;
a3f98646 471 } else {
472 DEBUG ((EFI_D_INFO, "CMD55 fails.\n"));
8c6151f2 473 gCardInfo.CardType = MMC_CARD;
a3f98646 474 }
475
476 //Send appropriate command for the card type which got detected.
8c6151f2 477 if (gCardInfo.CardType == SD_CARD) {
478 CmdArgument = ((UINTN *) &(gCardInfo.OCRData))[0];
a3f98646 479
480 //Set HCS bit.
481 if (SDCmd8Supported) {
482 CmdArgument |= HCS;
483 }
484
8c6151f2 485 Status = SendCmd (ACMD41, ACMD41_INT_EN, CmdArgument);
a3f98646 486 if (EFI_ERROR(Status)) {
487 DEBUG ((EFI_D_INFO, "ACMD41 fails.\n"));
488 return Status;
489 }
8c6151f2 490 ((UINT32 *) &(gCardInfo.OCRData))[0] = MmioRead32 (MMCHS_RSP10);
491 DEBUG ((EFI_D_INFO, "SD card detected. ACMD41 OCR: %x\n", ((UINT32 *) &(gCardInfo.OCRData))[0]));
492 } else if (gCardInfo.CardType == MMC_CARD) {
a3f98646 493 CmdArgument = 0;
8c6151f2 494 Status = SendCmd (CMD1, CMD1_INT_EN, CmdArgument);
a3f98646 495 if (EFI_ERROR(Status)) {
496 DEBUG ((EFI_D_INFO, "CMD1 fails.\n"));
497 return Status;
498 }
43263288 499 Response = MmioRead32 (MMCHS_RSP10);
a3f98646 500 DEBUG ((EFI_D_INFO, "MMC card detected.. CMD1 response: %x\n", Response));
501
502 //NOTE: For now, I am skipping this since I only have an SD card.
503 //Compare card OCR and host OCR (Section 22.6.1.3.2.4)
504 return EFI_UNSUPPORTED; //For now, MMC is not supported.
505 }
506
507 //Poll the card until it is out of its power-up sequence.
8c6151f2 508 if (gCardInfo.OCRData.Busy == 1) {
a3f98646 509
510 if (SDCmd8Supported) {
8c6151f2 511 gCardInfo.CardType = SD_CARD_2;
a3f98646 512 }
513
514 //Card is ready. Check CCS (Card capacity status) bit (bit#30).
515 //SD 2.0 standard card will response with CCS 0, SD high capacity card will respond with CCS 1.
8c6151f2 516 if (gCardInfo.OCRData.AccessMode & BIT1) {
517 gCardInfo.CardType = SD_CARD_2_HIGH;
a3f98646 518 DEBUG ((EFI_D_INFO, "High capacity card.\n"));
519 } else {
520 DEBUG ((EFI_D_INFO, "Standard capacity card.\n"));
521 }
522
523 break;
524 }
525
526 gBS->Stall(1000);
527 RetryCount++;
528 }
529
530 if (RetryCount == MAX_RETRY_COUNT) {
531 DEBUG ((EFI_D_ERROR, "Timeout error. RetryCount: %d\n", RetryCount));
532 return EFI_TIMEOUT;
533 }
534
535 //Read CID data.
536 CmdArgument = 0;
8c6151f2 537 Status = SendCmd (CMD2, CMD2_INT_EN, CmdArgument);
a3f98646 538 if (EFI_ERROR(Status)) {
539 DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status));
540 return Status;
541 }
542
43263288 543 DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));
a3f98646 544
545 //Parse CID register data.
43263288 546 ParseCardCIDData(MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76));
a3f98646 547
548 //Read RCA
549 CmdArgument = 0;
8c6151f2 550 Status = SendCmd (CMD3, CMD3_INT_EN, CmdArgument);
a3f98646 551 if (EFI_ERROR(Status)) {
552 DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status));
553 return Status;
554 }
555
556 //Set RCA for the detected card. RCA is CMD3 response.
8c6151f2 557 gCardInfo.RCA = (MmioRead32 (MMCHS_RSP10) >> 16);
558 DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo.RCA));
a3f98646 559
560 //MMC Bus setting change after card identification.
8c6151f2 561 MmioAnd32 (MMCHS_CON, ~OD);
43263288 562 MmioOr32 (MMCHS_HCTL, SDVS_3_0_V);
a3f98646 563 UpdateMMCHSClkFrequency(CLKD_400KHZ); //Set the clock frequency to 400KHz.
564
565 return EFI_SUCCESS;
566}
567
8c6151f2 568
a3f98646 569EFI_STATUS
570GetCardSpecificData (
571 VOID
572 )
573{
574 EFI_STATUS Status;
575 UINTN CmdArgument;
576
577 //Send CMD9 to retrieve CSD.
8c6151f2 578 CmdArgument = gCardInfo.RCA << 16;
579 Status = SendCmd (CMD9, CMD9_INT_EN, CmdArgument);
a3f98646 580 if (EFI_ERROR(Status)) {
581 DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status));
582 return Status;
583 }
584
585 //Populate 128-bit CSD register data.
8c6151f2 586 ((UINT32 *)&(gCardInfo.CSDData))[0] = MmioRead32 (MMCHS_RSP10);
587 ((UINT32 *)&(gCardInfo.CSDData))[1] = MmioRead32 (MMCHS_RSP32);
588 ((UINT32 *)&(gCardInfo.CSDData))[2] = MmioRead32 (MMCHS_RSP54);
589 ((UINT32 *)&(gCardInfo.CSDData))[3] = MmioRead32 (MMCHS_RSP76);
a3f98646 590
43263288 591 DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));
a3f98646 592
593 //Calculate total number of blocks and max. data transfer rate supported by the detected card.
594 GetCardConfigurationData();
595
596 //Change MMCHS clock frequency to what detected card can support.
8c6151f2 597 UpdateMMCHSClkFrequency(gCardInfo.ClockFrequencySelect);
a3f98646 598
599 return Status;
600}
601
8c6151f2 602
a3f98646 603EFI_STATUS
604PerformCardConfiguration (
605 VOID
606 )
607{
608 UINTN CmdArgument = 0;
609 EFI_STATUS Status;
610
611 //Send CMD7
8c6151f2 612 CmdArgument = gCardInfo.RCA << 16;
613 Status = SendCmd (CMD7, CMD7_INT_EN, CmdArgument);
a3f98646 614 if (EFI_ERROR(Status)) {
615 DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", Status));
616 return Status;
617 }
618
2b649f74 619 if ((gCardInfo.CardType != UNKNOWN_CARD) && (gCardInfo.CardType != MMC_CARD)) {
620 // We could read SCR register, but SD Card Phys spec stats any SD Card shall
621 // set SCR.SD_BUS_WIDTHS to support 4-bit mode, so why bother?
622
623 // Send ACMD6 (application specific commands must be prefixed with CMD55)
624 Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);
625 if (!EFI_ERROR (Status)) {
626 // set device into 4-bit data bus mode
627 Status = SendCmd (ACMD6, ACMD6_INT_EN, 0x2);
628 if (!EFI_ERROR (Status)) {
629 // Set host controler into 4-bit mode
630 MmioOr32 (MMCHS_HCTL, DTW_4_BIT);
631 DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n"));
632 }
633 }
634 }
635
a3f98646 636 //Send CMD16 to set the block length
8c6151f2 637 CmdArgument = gCardInfo.BlockSize;
638 Status = SendCmd (CMD16, CMD16_INT_EN, CmdArgument);
a3f98646 639 if (EFI_ERROR(Status)) {
640 DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status));
641 return Status;
642 }
643
644 return EFI_SUCCESS;
645}
646
8c6151f2 647
a3f98646 648EFI_STATUS
8c6151f2 649ReadBlockData (
a3f98646 650 IN EFI_BLOCK_IO_PROTOCOL *This,
651 OUT VOID *Buffer
652 )
653{
654 UINTN MmcStatus;
655 UINTN *DataBuffer = Buffer;
656 UINTN DataSize = This->Media->BlockSize/4;
657 UINTN Count;
658 UINTN RetryCount = 0;
659
660 //Check controller status to make sure there is no error.
661 while (RetryCount < MAX_RETRY_COUNT) {
662 do {
663 //Read Status.
43263288 664 MmcStatus = MmioRead32 (MMCHS_STAT);
a3f98646 665 } while(MmcStatus == 0);
666
667 //Check if Buffer read ready (BRR) bit is set?
668 if (MmcStatus & BRR) {
669
670 //Clear BRR bit
43263288 671 MmioOr32 (MMCHS_STAT, BRR);
a3f98646 672
673 //Read block worth of data.
674 for (Count = 0; Count < DataSize; Count++) {
43263288 675 *DataBuffer++ = MmioRead32 (MMCHS_DATA);
a3f98646 676 }
677 break;
678 }
679 RetryCount++;
680 }
681
682 if (RetryCount == MAX_RETRY_COUNT) {
683 return EFI_TIMEOUT;
684 }
685
686 return EFI_SUCCESS;
687}
688
8c6151f2 689
a3f98646 690EFI_STATUS
8c6151f2 691WriteBlockData (
a3f98646 692 IN EFI_BLOCK_IO_PROTOCOL *This,
693 OUT VOID *Buffer
694 )
695{
696 UINTN MmcStatus;
697 UINTN *DataBuffer = Buffer;
698 UINTN DataSize = This->Media->BlockSize/4;
699 UINTN Count;
700 UINTN RetryCount = 0;
701
702 //Check controller status to make sure there is no error.
703 while (RetryCount < MAX_RETRY_COUNT) {
704 do {
705 //Read Status.
43263288 706 MmcStatus = MmioRead32 (MMCHS_STAT);
a3f98646 707 } while(MmcStatus == 0);
708
709 //Check if Buffer write ready (BWR) bit is set?
710 if (MmcStatus & BWR) {
711
712 //Clear BWR bit
43263288 713 MmioOr32 (MMCHS_STAT, BWR);
a3f98646 714
715 //Write block worth of data.
716 for (Count = 0; Count < DataSize; Count++) {
026e30c4 717 MmioWrite32 (MMCHS_DATA, *DataBuffer++);
a3f98646 718 }
719
720 break;
721 }
722 RetryCount++;
723 }
724
725 if (RetryCount == MAX_RETRY_COUNT) {
726 return EFI_TIMEOUT;
727 }
728
729 return EFI_SUCCESS;
730}
731
8c6151f2 732
a3f98646 733EFI_STATUS
8c6151f2 734TransferBlockData (
a3f98646 735 IN EFI_BLOCK_IO_PROTOCOL *This,
736 OUT VOID *Buffer,
737 IN OPERATION_TYPE OperationType
738 )
739{
740 EFI_STATUS Status;
741 UINTN MmcStatus;
742 UINTN RetryCount = 0;
743
744 //Read or Write data.
745 if (OperationType == READ) {
746 Status = ReadBlockData(This, Buffer);
747 if (EFI_ERROR(Status)) {
748 DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n"));
749 return Status;
750 }
751 } else if (OperationType == WRITE) {
752 Status = WriteBlockData(This, Buffer);
753 if (EFI_ERROR(Status)) {
754 DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n"));
755 return Status;
756 }
757 }
758
759 //Check for the Transfer completion.
760 while (RetryCount < MAX_RETRY_COUNT) {
761 //Read Status
762 do {
43263288 763 MmcStatus = MmioRead32 (MMCHS_STAT);
a3f98646 764 } while (MmcStatus == 0);
765
766 //Check if Transfer complete (TC) bit is set?
767 if (MmcStatus & TC) {
768 break;
769 } else {
770 DEBUG ((EFI_D_ERROR, "MmcStatus for TC: %x\n", MmcStatus));
771 //Check if DEB, DCRC or DTO interrupt occured.
772 if ((MmcStatus & DEB) | (MmcStatus & DCRC) | (MmcStatus & DTO)) {
773 //There was an error during the data transfer.
774
775 //Set SRD bit to 1 and wait until it return to 0x0.
43263288 776 MmioOr32 (MMCHS_SYSCTL, SRD);
777 while((MmioRead32 (MMCHS_SYSCTL) & SRD) != 0x0);
a3f98646 778
779 return EFI_DEVICE_ERROR;
780 }
781 }
782 RetryCount++;
783 }
784
785 if (RetryCount == MAX_RETRY_COUNT) {
786 DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n"));
787 return EFI_TIMEOUT;
788 }
789
790 return EFI_SUCCESS;
791}
792
8c6151f2 793BOOLEAN
794CardPresent (
795 VOID
796 )
797{
798 EFI_STATUS Status;
799 UINT8 Data;
800
801 //
802 // Card detect is a GPIO0 on the TPS65950
803 //
804 Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);
805 if (EFI_ERROR (Status)) {
806 return FALSE;
807 }
808
809 if ((Data & CARD_DETECT_BIT) == CARD_DETECT_BIT) {
810 // No Card present
811 return FALSE;
812 } else {
813 return TRUE;
814 }
815}
816
817EFI_STATUS
818DetectCard (
819 VOID
820 )
821{
822 EFI_STATUS Status;
823
824 if (!CardPresent ()) {
825 return EFI_NO_MEDIA;
826 }
827
828 //Initialize MMC host controller clocks.
829 Status = InitializeMMCHS ();
830 if (EFI_ERROR(Status)) {
831 DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status));
832 return Status;
833 }
834
835 //Software reset of the MMCHS host controller.
836 MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);
837 gBS->Stall(1000);
838 while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);
839
840 //Soft reset for all.
841 MmioWrite32 (MMCHS_SYSCTL, SRA);
842 gBS->Stall(1000);
843 while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);
844
845 //Voltage capabilities initialization. Activate VS18 and VS30.
846 MmioOr32 (MMCHS_CAPA, (VS30 | VS18));
847
848 //Wakeup configuration
849 MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);
850 MmioOr32 (MMCHS_HCTL, IWE);
851
852 //MMCHS Controller default initialization
853 MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));
854
855 MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));
856
857 //Enable internal clock
858 MmioOr32 (MMCHS_SYSCTL, ICE);
859
860 //Set the clock frequency to 80KHz.
861 UpdateMMCHSClkFrequency (CLKD_80KHZ);
862
863 //Enable SD bus power.
864 MmioOr32 (MMCHS_HCTL, (SDBP_ON));
865
866 //Poll till SD bus power bit is set.
867 while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);
868
869 //Card idenfication
870 Status = PerformCardIdenfication ();
871 if (EFI_ERROR(Status)) {
872 DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n"));
873 return Status;
874 }
875
876 //Get CSD (Card specific data) for the detected card.
877 Status = GetCardSpecificData();
878 if (EFI_ERROR(Status)) {
879 return Status;
880 }
881
882 //Configure the card in data transfer mode.
883 Status = PerformCardConfiguration();
884 if (EFI_ERROR(Status)) {
885 return Status;
886 }
887
888 //Patch the Media structure.
889 gMMCHSMedia.LastBlock = (gCardInfo.NumBlocks - 1);
890 gMMCHSMedia.BlockSize = gCardInfo.BlockSize;
891 gMMCHSMedia.ReadOnly = (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;
892 gMMCHSMedia.MediaPresent = TRUE;
893 gMMCHSMedia.MediaId++;
894 gMediaChange = FALSE;
895
2b649f74 896 DEBUG ((EFI_D_INFO, "SD Card Media Change\n"));
897
8c6151f2 898 return Status;
899}
900
901
a3f98646 902EFI_STATUS
903SdReadWrite (
904 IN EFI_BLOCK_IO_PROTOCOL *This,
905 IN UINTN Lba,
906 OUT VOID *Buffer,
907 IN UINTN BufferSize,
908 IN OPERATION_TYPE OperationType
909 )
910{
8c6151f2 911 EFI_STATUS Status = EFI_SUCCESS;
a3f98646 912 UINTN RetryCount = 0;
913 UINTN NumBlocks;
914 UINTN Cmd = 0;
915 UINTN CmdInterruptEnable = 0;
916 UINTN CmdArgument = 0;
8c6151f2 917 EFI_TPL OldTpl;\r
918 BOOLEAN MediaPresentLastTime;\r
919 BOOLEAN Update;\r
920
921 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
922
923
924 if (Buffer == NULL) {
925 Status = EFI_INVALID_PARAMETER;
926 goto Done;
927 }
928
929 Update = FALSE;
930 MediaPresentLastTime = gMMCHSMedia.MediaPresent;
931
932 if (gMediaChange) {
933 Status = DetectCard ();
934 if (EFI_ERROR (Status)) {
935 // We detected a removal
936 gMMCHSMedia.MediaPresent = FALSE;
937 gMMCHSMedia.LastBlock = 0;
938 gMMCHSMedia.BlockSize = 512; // Should be zero but there is a bug in DiskIo
939 gMMCHSMedia.ReadOnly = FALSE;
940 } else {
941 Update = TRUE;
942 }
943 gMediaChange = FALSE;
944 } else if (!gMMCHSMedia.MediaPresent) {
945 Status = EFI_NO_MEDIA;
946 goto Done;
947 }
948
949 if ((MediaPresentLastTime != gMMCHSMedia.MediaPresent) || Update) {
950 gBS->ReinstallProtocolInterface (\r
951 gImageHandle,\r
952 &gEfiBlockIoProtocolGuid,\r
953 &gBlockIo,\r
954 &gBlockIo\r
955 );\r
956 }
957
958 if (EFI_ERROR (Status)) {
959 goto Done;
960 }
961
962 if (Lba > This->Media->LastBlock) {
963 Status = EFI_INVALID_PARAMETER;
964 goto Done;
965 }
966
967 if ((BufferSize % This->Media->BlockSize) != 0) {
968 Status = EFI_BAD_BUFFER_SIZE;
969 goto Done;
970 }
a3f98646 971
972 //Check if the data lines are not in use.
43263288 973 while ((RetryCount++ < MAX_RETRY_COUNT) && ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) != DATI_ALLOWED));
a3f98646 974 if (RetryCount == MAX_RETRY_COUNT) {
8c6151f2 975 Status = EFI_TIMEOUT;
976 goto Done;
a3f98646 977 }
978
979 //Populate the command information based on the operation type.
980 if (OperationType == READ) {
981 Cmd = CMD17; //Single block read
982 CmdInterruptEnable = CMD17_INT_EN;
8c6151f2 983 } else if (OperationType == WRITE) {
a3f98646 984 Cmd = CMD24; //Single block write
985 CmdInterruptEnable = CMD24_INT_EN;
986 }
987
988 //Calculate total number of blocks its going to read.
989 NumBlocks = (BufferSize + (This->Media->BlockSize - 1))/This->Media->BlockSize;
990
991 //Set command argument based on the card access mode (Byte mode or Block mode)
8c6151f2 992 if (gCardInfo.OCRData.AccessMode & BIT1) {
a3f98646 993 CmdArgument = (UINTN)Lba;
994 } else {
995 CmdArgument = (UINTN)Lba * This->Media->BlockSize;
996 }
997
998 while(NumBlocks) {
999 //Send Command.
8c6151f2 1000 Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);
a3f98646 1001 if (EFI_ERROR(Status)) {
1002 DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));
8c6151f2 1003 goto Done;
a3f98646 1004 }
1005
1006 //Transfer a block worth of data.
1007 Status = TransferBlockData(This, Buffer, OperationType);
1008 if (EFI_ERROR(Status)) {
1009 DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status));
8c6151f2 1010 goto Done;
a3f98646 1011 }
1012
1013 //Adjust command argument.
8c6151f2 1014 if (gCardInfo.OCRData.AccessMode & BIT1) {
a3f98646 1015 CmdArgument++; //Increase BlockIndex by one.
1016 } else {
1017 CmdArgument += This->Media->BlockSize; //Increase BlockIndex by BlockSize
1018 }
1019
1020 //Adjust Buffer.
1021 Buffer = (UINT8 *)Buffer + This->Media->BlockSize;
1022 NumBlocks--;
1023 }
1024
8c6151f2 1025Done:\r
1026 gBS->RestoreTPL (OldTpl);\r
1027 return Status;\r
a3f98646 1028}
1029
8c6151f2 1030
1031/**\r
1032 Reset the Block Device.\r
1033\r
1034 @param This Indicates a pointer to the calling context.\r
1035 @param ExtendedVerification Driver may perform diagnostics on reset.\r
1036\r
1037 @retval EFI_SUCCESS The device was reset.\r
1038 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
1039 not be reset.\r
1040\r
1041**/
a3f98646 1042EFI_STATUS
1043EFIAPI
1044MMCHSReset (
1045 IN EFI_BLOCK_IO_PROTOCOL *This,
1046 IN BOOLEAN ExtendedVerification
1047 )
1048{
8c6151f2 1049 return EFI_SUCCESS;
a3f98646 1050}
1051
8c6151f2 1052
1053/**\r
1054 Read BufferSize bytes from Lba into Buffer.\r
1055\r
1056 @param This Indicates a pointer to the calling context.\r
1057 @param MediaId Id of the media, changes every time the media is replaced.\r
1058 @param Lba The starting Logical Block Address to read from\r
1059 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
1060 @param Buffer A pointer to the destination buffer for the data. The caller is\r
1061 responsible for either having implicit or explicit ownership of the buffer.\r
1062\r
1063 @retval EFI_SUCCESS The data was read correctly from the device.\r
1064 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
1065 @retval EFI_NO_MEDIA There is no media in the device.\r
1066 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
1067 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
1068 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
1069 or the buffer is not on proper alignment.\r
1070EFI_STATUS
1071
1072**/
a3f98646 1073EFI_STATUS
1074EFIAPI
1075MMCHSReadBlocks (
1076 IN EFI_BLOCK_IO_PROTOCOL *This,
1077 IN UINT32 MediaId,
1078 IN EFI_LBA Lba,
1079 IN UINTN BufferSize,
1080 OUT VOID *Buffer
1081 )
1082{
1083 EFI_STATUS Status;
1084
a3f98646 1085 //Perform Read operation.
8c6151f2 1086 Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ);
a3f98646 1087
8c6151f2 1088 return Status;\r
a3f98646 1089}
1090
8c6151f2 1091
1092/**\r
1093 Write BufferSize bytes from Lba into Buffer.\r
1094\r
1095 @param This Indicates a pointer to the calling context.\r
1096 @param MediaId The media ID that the write request is for.\r
1097 @param Lba The starting logical block address to be written. The caller is\r
1098 responsible for writing to only legitimate locations.\r
1099 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
1100 @param Buffer A pointer to the source buffer for the data.\r
1101\r
1102 @retval EFI_SUCCESS The data was written correctly to the device.\r
1103 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
1104 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
1105 @retval EFI_NO_MEDIA There is no media in the device.\r
1106 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
1107 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
1108 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
1109 or the buffer is not on proper alignment.\r
1110\r
1111**/
a3f98646 1112EFI_STATUS
1113EFIAPI
1114MMCHSWriteBlocks (
1115 IN EFI_BLOCK_IO_PROTOCOL *This,
1116 IN UINT32 MediaId,
1117 IN EFI_LBA Lba,
1118 IN UINTN BufferSize,
1119 IN VOID *Buffer
1120 )
1121{
8c6151f2 1122 EFI_STATUS Status;
a3f98646 1123
1124 //Perform write operation.
8c6151f2 1125 Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, WRITE);
1126\r
1127 return Status;\r
a3f98646 1128}
1129
8c6151f2 1130
1131/**\r
1132 Flush the Block Device.\r
1133\r
1134 @param This Indicates a pointer to the calling context.\r
1135\r
1136 @retval EFI_SUCCESS All outstanding data was written to the device\r
1137 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data\r
1138 @retval EFI_NO_MEDIA There is no media in the device.\r
1139\r
1140**/
a3f98646 1141EFI_STATUS
1142EFIAPI
1143MMCHSFlushBlocks (
1144 IN EFI_BLOCK_IO_PROTOCOL *This
1145 )
1146{
1147 return EFI_SUCCESS;
1148}
1149
8c6151f2 1150
1151EFI_BLOCK_IO_PROTOCOL gBlockIo = {
a3f98646 1152 EFI_BLOCK_IO_INTERFACE_REVISION, // Revision
8c6151f2 1153 &gMMCHSMedia, // *Media
a3f98646 1154 MMCHSReset, // Reset
1155 MMCHSReadBlocks, // ReadBlocks
1156 MMCHSWriteBlocks, // WriteBlocks
1157 MMCHSFlushBlocks // FlushBlocks
1158};
1159
8c6151f2 1160
1161/**\r
1162 Timer callback to convert card present hardware into a boolean that indicates\r
1163 a media change event has happened. If you just check the GPIO you could see \r
1164 card 1 and then check again after card 1 was removed and card 2 was inserted\r
1165 and you would still see media present. Thus you need the timer tick to catch\r
1166 the toggle event.\r
1167\r
1168 @param Event Event whose notification function is being invoked.\r
1169 @param Context The pointer to the notification function's context,\r
1170 which is implementation-dependent. Not used.\r
1171\r
1172**/
1173VOID
1174EFIAPI
1175TimerCallback (
1176 IN EFI_EVENT Event,
1177 IN VOID *Context
1178 )
1179{
1180 BOOLEAN Present;
1181
1182 Present = CardPresent ();
1183 if (gMMCHSMedia.MediaPresent) {
1184 if (!Present && !gMediaChange) {
1185 gMediaChange = TRUE;
1186 }
1187 } else {
1188 if (Present && !gMediaChange) {
1189 gMediaChange = TRUE;
1190 }
1191 }
1192}
1193
1194
a3f98646 1195EFI_STATUS
8c6151f2 1196EFIAPI
a3f98646 1197MMCHSInitialize (
1198 IN EFI_HANDLE ImageHandle,
1199 IN EFI_SYSTEM_TABLE *SystemTable
1200 )
1201{
1202 EFI_STATUS Status;
1203
8c6151f2 1204 Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
a3f98646 1205 ASSERT_EFI_ERROR(Status);
1206
8c6151f2 1207 ZeroMem (&gCardInfo, sizeof (CARD_INFO));
1208
1209 Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, TimerCallback, NULL, &gTimerEvent);
1210 ASSERT_EFI_ERROR (Status);
1211
2b649f74 1212 Status = gBS->SetTimer (gTimerEvent, TimerPeriodic, 1000000ULL); // make me a PCD
8c6151f2 1213 ASSERT_EFI_ERROR (Status);
a3f98646 1214
1215 //Publish BlockIO.
8c6151f2 1216 Status = gBS->InstallMultipleProtocolInterfaces (
1217 &ImageHandle,
1218 &gEfiBlockIoProtocolGuid, &gBlockIo,
1219 &gEfiDevicePathProtocolGuid, &gMmcHsDevicePath,
1220 NULL
1221 );
a3f98646 1222 return Status;
1223}