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