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