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