]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.c
EmbeddedPkg: import DesignWare EMMC driver
[mirror_edk2.git] / EmbeddedPkg / Drivers / DwEmmcDxe / DwEmmcDxe.c
CommitLineData
ee660531
LL
1/** @file\r
2 This file implement the MMC Host Protocol for the DesignWare eMMC.\r
3\r
4 Copyright (c) 2014-2017, Linaro Limited. All rights reserved.\r
5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Library/BaseMemoryLib.h>\r
17#include <Library/CacheMaintenanceLib.h>\r
18#include <Library/DebugLib.h>\r
19#include <Library/DevicePathLib.h>\r
20#include <Library/IoLib.h>\r
21#include <Library/MemoryAllocationLib.h>\r
22#include <Library/PcdLib.h>\r
23#include <Library/TimerLib.h>\r
24#include <Library/UefiBootServicesTableLib.h>\r
25#include <Library/UefiLib.h>\r
26\r
27#include <Protocol/MmcHost.h>\r
28\r
29#include "DwEmmc.h"\r
30\r
31#define DWEMMC_DESC_PAGE 1\r
32#define DWEMMC_BLOCK_SIZE 512\r
33#define DWEMMC_DMA_BUF_SIZE (512 * 8)\r
34#define DWEMMC_MAX_DESC_PAGES 512\r
35\r
36typedef struct {\r
37 UINT32 Des0;\r
38 UINT32 Des1;\r
39 UINT32 Des2;\r
40 UINT32 Des3;\r
41} DWEMMC_IDMAC_DESCRIPTOR;\r
42\r
43EFI_MMC_HOST_PROTOCOL *gpMmcHost;\r
44DWEMMC_IDMAC_DESCRIPTOR *gpIdmacDesc;\r
45EFI_GUID mDwEmmcDevicePathGuid = EFI_CALLER_ID_GUID;\r
46STATIC UINT32 mDwEmmcCommand;\r
47STATIC UINT32 mDwEmmcArgument;\r
48\r
49EFI_STATUS\r
50DwEmmcReadBlockData (\r
51 IN EFI_MMC_HOST_PROTOCOL *This,\r
52 IN EFI_LBA Lba,\r
53 IN UINTN Length,\r
54 IN UINT32* Buffer\r
55 );\r
56\r
57BOOLEAN\r
58DwEmmcIsPowerOn (\r
59 VOID\r
60 )\r
61{\r
62 return TRUE;\r
63}\r
64\r
65EFI_STATUS\r
66DwEmmcInitialize (\r
67 VOID\r
68 )\r
69{\r
70 DEBUG ((DEBUG_BLKIO, "DwEmmcInitialize()"));\r
71 return EFI_SUCCESS;\r
72}\r
73\r
74BOOLEAN\r
75DwEmmcIsCardPresent (\r
76 IN EFI_MMC_HOST_PROTOCOL *This\r
77 )\r
78{\r
79 return TRUE;\r
80}\r
81\r
82BOOLEAN\r
83DwEmmcIsReadOnly (\r
84 IN EFI_MMC_HOST_PROTOCOL *This\r
85 )\r
86{\r
87 return FALSE;\r
88}\r
89\r
90BOOLEAN\r
91DwEmmcIsDmaSupported (\r
92 IN EFI_MMC_HOST_PROTOCOL *This\r
93 )\r
94{\r
95 return TRUE;\r
96}\r
97\r
98EFI_STATUS\r
99DwEmmcBuildDevicePath (\r
100 IN EFI_MMC_HOST_PROTOCOL *This,\r
101 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
102 )\r
103{\r
104 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
105\r
106 NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));\r
107 CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mDwEmmcDevicePathGuid);\r
108\r
109 *DevicePath = NewDevicePathNode;\r
110 return EFI_SUCCESS;\r
111}\r
112\r
113EFI_STATUS\r
114DwEmmcUpdateClock (\r
115 VOID\r
116 )\r
117{\r
118 UINT32 Data;\r
119\r
120 /* CMD_UPDATE_CLK */\r
121 Data = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |\r
122 BIT_CMD_START;\r
123 MmioWrite32 (DWEMMC_CMD, Data);\r
124 while (1) {\r
125 Data = MmioRead32 (DWEMMC_CMD);\r
126 if (!(Data & CMD_START_BIT)) {\r
127 break;\r
128 }\r
129 Data = MmioRead32 (DWEMMC_RINTSTS);\r
130 if (Data & DWEMMC_INT_HLE) {\r
131 Print (L"failed to update mmc clock frequency\n");\r
132 return EFI_DEVICE_ERROR;\r
133 }\r
134 }\r
135 return EFI_SUCCESS;\r
136}\r
137\r
138EFI_STATUS\r
139DwEmmcSetClock (\r
140 IN UINTN ClockFreq\r
141 )\r
142{\r
143 UINT32 Divider, Rate, Data;\r
144 EFI_STATUS Status;\r
145 BOOLEAN Found = FALSE;\r
146\r
147 for (Divider = 1; Divider < 256; Divider++) {\r
148 Rate = PcdGet32 (PcdDwEmmcDxeClockFrequencyInHz);\r
149 if ((Rate / (2 * Divider)) <= ClockFreq) {\r
150 Found = TRUE;\r
151 break;\r
152 }\r
153 }\r
154 if (Found == FALSE) {\r
155 return EFI_NOT_FOUND;\r
156 }\r
157\r
158 // Wait until MMC is idle\r
159 do {\r
160 Data = MmioRead32 (DWEMMC_STATUS);\r
161 } while (Data & DWEMMC_STS_DATA_BUSY);\r
162\r
163 // Disable MMC clock first\r
164 MmioWrite32 (DWEMMC_CLKENA, 0);\r
165 Status = DwEmmcUpdateClock ();\r
166 ASSERT (!EFI_ERROR (Status));\r
167\r
168 MmioWrite32 (DWEMMC_CLKDIV, Divider);\r
169 Status = DwEmmcUpdateClock ();\r
170 ASSERT (!EFI_ERROR (Status));\r
171\r
172 // Enable MMC clock\r
173 MmioWrite32 (DWEMMC_CLKENA, 1);\r
174 MmioWrite32 (DWEMMC_CLKSRC, 0);\r
175 Status = DwEmmcUpdateClock ();\r
176 ASSERT (!EFI_ERROR (Status));\r
177 return EFI_SUCCESS;\r
178}\r
179\r
180EFI_STATUS\r
181DwEmmcNotifyState (\r
182 IN EFI_MMC_HOST_PROTOCOL *This,\r
183 IN MMC_STATE State\r
184 )\r
185{\r
186 UINT32 Data;\r
187 EFI_STATUS Status;\r
188\r
189 switch (State) {\r
190 case MmcInvalidState:\r
191 return EFI_INVALID_PARAMETER;\r
192 case MmcHwInitializationState:\r
193 MmioWrite32 (DWEMMC_PWREN, 1);\r
194\r
195 // If device already turn on then restart it\r
196 Data = DWEMMC_CTRL_RESET_ALL;\r
197 MmioWrite32 (DWEMMC_CTRL, Data);\r
198 do {\r
199 // Wait until reset operation finished\r
200 Data = MmioRead32 (DWEMMC_CTRL);\r
201 } while (Data & DWEMMC_CTRL_RESET_ALL);\r
202\r
203 // Setup clock that could not be higher than 400KHz.\r
204 Status = DwEmmcSetClock (400000);\r
205 ASSERT (!EFI_ERROR (Status));\r
206 // Wait clock stable\r
207 MicroSecondDelay (100);\r
208\r
209 MmioWrite32 (DWEMMC_RINTSTS, ~0);\r
210 MmioWrite32 (DWEMMC_INTMASK, 0);\r
211 MmioWrite32 (DWEMMC_TMOUT, ~0);\r
212 MmioWrite32 (DWEMMC_IDINTEN, 0);\r
213 MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET);\r
214\r
215 MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);\r
216 do {\r
217 Data = MmioRead32 (DWEMMC_BMOD);\r
218 } while (Data & DWEMMC_IDMAC_SWRESET);\r
219 break;\r
220 case MmcIdleState:\r
221 break;\r
222 case MmcReadyState:\r
223 break;\r
224 case MmcIdentificationState:\r
225 break;\r
226 case MmcStandByState:\r
227 break;\r
228 case MmcTransferState:\r
229 break;\r
230 case MmcSendingDataState:\r
231 break;\r
232 case MmcReceiveDataState:\r
233 break;\r
234 case MmcProgrammingState:\r
235 break;\r
236 case MmcDisconnectState:\r
237 break;\r
238 default:\r
239 return EFI_INVALID_PARAMETER;\r
240 }\r
241 return EFI_SUCCESS;\r
242}\r
243\r
244// Need to prepare DMA buffer first before sending commands to MMC card\r
245BOOLEAN\r
246IsPendingReadCommand (\r
247 IN MMC_CMD MmcCmd\r
248 )\r
249{\r
250 UINTN Mask;\r
251\r
252 Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_READ;\r
253 if ((MmcCmd & Mask) == Mask) {\r
254 return TRUE;\r
255 }\r
256 return FALSE;\r
257}\r
258\r
259BOOLEAN\r
260IsPendingWriteCommand (\r
261 IN MMC_CMD MmcCmd\r
262 )\r
263{\r
264 UINTN Mask;\r
265\r
266 Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE;\r
267 if ((MmcCmd & Mask) == Mask) {\r
268 return TRUE;\r
269 }\r
270 return FALSE;\r
271}\r
272\r
273EFI_STATUS\r
274SendCommand (\r
275 IN MMC_CMD MmcCmd,\r
276 IN UINT32 Argument\r
277 )\r
278{\r
279 UINT32 Data, ErrMask;\r
280\r
281 // Wait until MMC is idle\r
282 do {\r
283 Data = MmioRead32 (DWEMMC_STATUS);\r
284 } while (Data & DWEMMC_STS_DATA_BUSY);\r
285\r
286 MmioWrite32 (DWEMMC_RINTSTS, ~0);\r
287 MmioWrite32 (DWEMMC_CMDARG, Argument);\r
288 MmioWrite32 (DWEMMC_CMD, MmcCmd);\r
289\r
290 ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO |\r
291 DWEMMC_INT_RCRC | DWEMMC_INT_RE;\r
292 ErrMask |= DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE;\r
293 do {\r
294 MicroSecondDelay(500);\r
295 Data = MmioRead32 (DWEMMC_RINTSTS);\r
296\r
297 if (Data & ErrMask) {\r
298 return EFI_DEVICE_ERROR;\r
299 }\r
300 if (Data & DWEMMC_INT_DTO) { // Transfer Done\r
301 break;\r
302 }\r
303 } while (!(Data & DWEMMC_INT_CMD_DONE));\r
304 return EFI_SUCCESS;\r
305}\r
306\r
307EFI_STATUS\r
308DwEmmcSendCommand (\r
309 IN EFI_MMC_HOST_PROTOCOL *This,\r
310 IN MMC_CMD MmcCmd,\r
311 IN UINT32 Argument\r
312 )\r
313{\r
314 UINT32 Cmd = 0;\r
315 EFI_STATUS Status = EFI_SUCCESS;\r
316\r
317 switch (MMC_GET_INDX(MmcCmd)) {\r
318 case MMC_INDX(0):\r
319 Cmd = BIT_CMD_SEND_INIT;\r
320 break;\r
321 case MMC_INDX(1):\r
322 Cmd = BIT_CMD_RESPONSE_EXPECT;\r
323 break;\r
324 case MMC_INDX(2):\r
325 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |\r
326 BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;\r
327 break;\r
328 case MMC_INDX(3):\r
329 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
330 BIT_CMD_SEND_INIT;\r
331 break;\r
332 case MMC_INDX(7):\r
333 if (Argument)\r
334 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;\r
335 else\r
336 Cmd = 0;\r
337 break;\r
338 case MMC_INDX(8):\r
339 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
340 BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |\r
341 BIT_CMD_WAIT_PRVDATA_COMPLETE;\r
342 break;\r
343 case MMC_INDX(9):\r
344 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
345 BIT_CMD_LONG_RESPONSE;\r
346 break;\r
347 case MMC_INDX(12):\r
348 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
349 BIT_CMD_STOP_ABORT_CMD;\r
350 break;\r
351 case MMC_INDX(13):\r
352 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
353 BIT_CMD_WAIT_PRVDATA_COMPLETE;\r
354 break;\r
355 case MMC_INDX(16):\r
356 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
357 BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |\r
358 BIT_CMD_WAIT_PRVDATA_COMPLETE;\r
359 break;\r
360 case MMC_INDX(17):\r
361 case MMC_INDX(18):\r
362 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
363 BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |\r
364 BIT_CMD_WAIT_PRVDATA_COMPLETE;\r
365 break;\r
366 case MMC_INDX(24):\r
367 case MMC_INDX(25):\r
368 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
369 BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE |\r
370 BIT_CMD_WAIT_PRVDATA_COMPLETE;\r
371 break;\r
372 case MMC_INDX(30):\r
373 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |\r
374 BIT_CMD_DATA_EXPECTED;\r
375 break;\r
376 default:\r
377 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;\r
378 break;\r
379 }\r
380\r
381 Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START;\r
382 if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) {\r
383 mDwEmmcCommand = Cmd;\r
384 mDwEmmcArgument = Argument;\r
385 } else {\r
386 Status = SendCommand (Cmd, Argument);\r
387 }\r
388 return Status;\r
389}\r
390\r
391EFI_STATUS\r
392DwEmmcReceiveResponse (\r
393 IN EFI_MMC_HOST_PROTOCOL *This,\r
394 IN MMC_RESPONSE_TYPE Type,\r
395 IN UINT32* Buffer\r
396 )\r
397{\r
398 if (Buffer == NULL) {\r
399 return EFI_INVALID_PARAMETER;\r
400 }\r
401\r
402 if ( (Type == MMC_RESPONSE_TYPE_R1)\r
403 || (Type == MMC_RESPONSE_TYPE_R1b)\r
404 || (Type == MMC_RESPONSE_TYPE_R3)\r
405 || (Type == MMC_RESPONSE_TYPE_R6)\r
406 || (Type == MMC_RESPONSE_TYPE_R7))\r
407 {\r
408 Buffer[0] = MmioRead32 (DWEMMC_RESP0);\r
409 } else if (Type == MMC_RESPONSE_TYPE_R2) {\r
410 Buffer[0] = MmioRead32 (DWEMMC_RESP0);\r
411 Buffer[1] = MmioRead32 (DWEMMC_RESP1);\r
412 Buffer[2] = MmioRead32 (DWEMMC_RESP2);\r
413 Buffer[3] = MmioRead32 (DWEMMC_RESP3);\r
414 }\r
415 return EFI_SUCCESS;\r
416}\r
417\r
418EFI_STATUS\r
419PrepareDmaData (\r
420 IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc,\r
421 IN UINTN Length,\r
422 IN UINT32* Buffer\r
423 )\r
424{\r
425 UINTN Cnt, Blks, Idx, LastIdx;\r
426\r
427 Cnt = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;\r
428 Blks = (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE;\r
429 Length = DWEMMC_BLOCK_SIZE * Blks;\r
430\r
431 for (Idx = 0; Idx < Cnt; Idx++) {\r
432 (IdmacDesc + Idx)->Des0 = DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_CH |\r
433 DWEMMC_IDMAC_DES0_DIC;\r
434 (IdmacDesc + Idx)->Des1 = DWEMMC_IDMAC_DES1_BS1(DWEMMC_DMA_BUF_SIZE);\r
435 /* Buffer Address */\r
436 (IdmacDesc + Idx)->Des2 = (UINT32)((UINTN)Buffer + DWEMMC_DMA_BUF_SIZE * Idx);\r
437 /* Next Descriptor Address */\r
438 (IdmacDesc + Idx)->Des3 = (UINT32)((UINTN)IdmacDesc +\r
439 (sizeof(DWEMMC_IDMAC_DESCRIPTOR) * (Idx + 1)));\r
440 }\r
441 /* First Descriptor */\r
442 IdmacDesc->Des0 |= DWEMMC_IDMAC_DES0_FS;\r
443 /* Last Descriptor */\r
444 LastIdx = Cnt - 1;\r
445 (IdmacDesc + LastIdx)->Des0 |= DWEMMC_IDMAC_DES0_LD;\r
446 (IdmacDesc + LastIdx)->Des0 &= ~(DWEMMC_IDMAC_DES0_DIC | DWEMMC_IDMAC_DES0_CH);\r
447 (IdmacDesc + LastIdx)->Des1 = DWEMMC_IDMAC_DES1_BS1(Length -\r
448 (LastIdx * DWEMMC_DMA_BUF_SIZE));\r
449 /* Set the Next field of Last Descriptor */\r
450 (IdmacDesc + LastIdx)->Des3 = 0;\r
451 MmioWrite32 (DWEMMC_DBADDR, (UINT32)((UINTN)IdmacDesc));\r
452\r
453 return EFI_SUCCESS;\r
454}\r
455\r
456VOID\r
457StartDma (\r
458 UINTN Length\r
459 )\r
460{\r
461 UINT32 Data;\r
462\r
463 Data = MmioRead32 (DWEMMC_CTRL);\r
464 Data |= DWEMMC_CTRL_INT_EN | DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN;\r
465 MmioWrite32 (DWEMMC_CTRL, Data);\r
466 Data = MmioRead32 (DWEMMC_BMOD);\r
467 Data |= DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB;\r
468 MmioWrite32 (DWEMMC_BMOD, Data);\r
469\r
470 MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);\r
471 MmioWrite32 (DWEMMC_BYTCNT, Length);\r
472}\r
473\r
474EFI_STATUS\r
475DwEmmcReadBlockData (\r
476 IN EFI_MMC_HOST_PROTOCOL *This,\r
477 IN EFI_LBA Lba,\r
478 IN UINTN Length,\r
479 IN UINT32* Buffer\r
480 )\r
481{\r
482 EFI_STATUS Status;\r
483 UINT32 DescPages, CountPerPage, Count;\r
484 EFI_TPL Tpl;\r
485\r
486 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
487\r
488 CountPerPage = EFI_PAGE_SIZE / 16;\r
489 Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;\r
490 DescPages = (Count + CountPerPage - 1) / CountPerPage;\r
491\r
492 InvalidateDataCacheRange (Buffer, Length);\r
493\r
494 Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);\r
495 if (EFI_ERROR (Status)) {\r
496 goto out;\r
497 }\r
498\r
499 WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);\r
500 StartDma (Length);\r
501\r
502 Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);\r
503 if (EFI_ERROR (Status)) {\r
504 DEBUG ((DEBUG_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));\r
505 goto out;\r
506 }\r
507out:\r
508 // Restore Tpl\r
509 gBS->RestoreTPL (Tpl);\r
510 return Status;\r
511}\r
512\r
513EFI_STATUS\r
514DwEmmcWriteBlockData (\r
515 IN EFI_MMC_HOST_PROTOCOL *This,\r
516 IN EFI_LBA Lba,\r
517 IN UINTN Length,\r
518 IN UINT32* Buffer\r
519 )\r
520{\r
521 EFI_STATUS Status;\r
522 UINT32 DescPages, CountPerPage, Count;\r
523 EFI_TPL Tpl;\r
524\r
525 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
526\r
527 CountPerPage = EFI_PAGE_SIZE / 16;\r
528 Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;\r
529 DescPages = (Count + CountPerPage - 1) / CountPerPage;\r
530\r
531 WriteBackDataCacheRange (Buffer, Length);\r
532\r
533 Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);\r
534 if (EFI_ERROR (Status)) {\r
535 goto out;\r
536 }\r
537\r
538 WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);\r
539 StartDma (Length);\r
540\r
541 Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);\r
542 if (EFI_ERROR (Status)) {\r
543 DEBUG ((DEBUG_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));\r
544 goto out;\r
545 }\r
546out:\r
547 // Restore Tpl\r
548 gBS->RestoreTPL (Tpl);\r
549 return Status;\r
550}\r
551\r
552EFI_STATUS\r
553DwEmmcSetIos (\r
554 IN EFI_MMC_HOST_PROTOCOL *This,\r
555 IN UINT32 BusClockFreq,\r
556 IN UINT32 BusWidth,\r
557 IN UINT32 TimingMode\r
558 )\r
559{\r
560 EFI_STATUS Status = EFI_SUCCESS;\r
561 UINT32 Data;\r
562\r
563 if (TimingMode != EMMCBACKWARD) {\r
564 Data = MmioRead32 (DWEMMC_UHSREG);\r
565 switch (TimingMode) {\r
566 case EMMCHS52DDR1V2:\r
567 case EMMCHS52DDR1V8:\r
568 Data |= 1 << 16;\r
569 break;\r
570 case EMMCHS52:\r
571 case EMMCHS26:\r
572 Data &= ~(1 << 16);\r
573 break;\r
574 default:\r
575 return EFI_UNSUPPORTED;\r
576 }\r
577 MmioWrite32 (DWEMMC_UHSREG, Data);\r
578 }\r
579\r
580 switch (BusWidth) {\r
581 case 1:\r
582 MmioWrite32 (DWEMMC_CTYPE, 0);\r
583 break;\r
584 case 4:\r
585 MmioWrite32 (DWEMMC_CTYPE, 1);\r
586 break;\r
587 case 8:\r
588 MmioWrite32 (DWEMMC_CTYPE, 1 << 16);\r
589 break;\r
590 default:\r
591 return EFI_UNSUPPORTED;\r
592 }\r
593 if (BusClockFreq) {\r
594 Status = DwEmmcSetClock (BusClockFreq);\r
595 }\r
596 return Status;\r
597}\r
598\r
599BOOLEAN\r
600DwEmmcIsMultiBlock (\r
601 IN EFI_MMC_HOST_PROTOCOL *This\r
602 )\r
603{\r
604 return TRUE;\r
605}\r
606\r
607EFI_MMC_HOST_PROTOCOL gMciHost = {\r
608 MMC_HOST_PROTOCOL_REVISION,\r
609 DwEmmcIsCardPresent,\r
610 DwEmmcIsReadOnly,\r
611 DwEmmcBuildDevicePath,\r
612 DwEmmcNotifyState,\r
613 DwEmmcSendCommand,\r
614 DwEmmcReceiveResponse,\r
615 DwEmmcReadBlockData,\r
616 DwEmmcWriteBlockData,\r
617 DwEmmcSetIos,\r
618 DwEmmcIsMultiBlock\r
619};\r
620\r
621EFI_STATUS\r
622DwEmmcDxeInitialize (\r
623 IN EFI_HANDLE ImageHandle,\r
624 IN EFI_SYSTEM_TABLE *SystemTable\r
625 )\r
626{\r
627 EFI_STATUS Status;\r
628 EFI_HANDLE Handle;\r
629\r
630 Handle = NULL;\r
631\r
632 gpIdmacDesc = (DWEMMC_IDMAC_DESCRIPTOR *)AllocatePages (DWEMMC_MAX_DESC_PAGES);\r
633 if (gpIdmacDesc == NULL) {\r
634 return EFI_BUFFER_TOO_SMALL;\r
635 }\r
636\r
637 DEBUG ((DEBUG_BLKIO, "DwEmmcDxeInitialize()\n"));\r
638\r
639 //Publish Component Name, BlockIO protocol interfaces\r
640 Status = gBS->InstallMultipleProtocolInterfaces (\r
641 &Handle,\r
642 &gEfiMmcHostProtocolGuid, &gMciHost,\r
643 NULL\r
644 );\r
645 ASSERT_EFI_ERROR (Status);\r
646\r
647 return EFI_SUCCESS;\r
648}\r