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