1 /** @file
2   This file implement the MMC Host Protocol for the DesignWare SD.
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 "DwSd.h"
33 
34 #define DWSD_DESC_PAGE		1
35 #define DWSD_BLOCK_SIZE	        512
36 #define DWSD_DMA_BUF_SIZE	(512 * 8)
37 
38 #define DWSD_DMA_THRESHOLD	16
39 
40 #define MAX_IDLE_LOOPS		1000000
41 
42 typedef struct {
43   UINT32		Des0;
44   UINT32		Des1;
45   UINT32		Des2;
46   UINT32		Des3;
47 } DWSD_IDMAC_DESCRIPTOR;
48 
49 EFI_MMC_HOST_PROTOCOL     *gpMmcHost;
50 DWSD_IDMAC_DESCRIPTOR     *gpIdmacDesc;
51 EFI_GUID mDwSdDevicePathGuid = EFI_CALLER_ID_GUID;
52 STATIC UINT32 mDwSdCommand;
53 STATIC UINT32 mDwSdArgument;
54 
55 EFI_STATUS
56 DwSdSendCommand (
57   IN EFI_MMC_HOST_PROTOCOL     *This,
58   IN MMC_CMD                    MmcCmd,
59   IN UINT32                     Argument
60   );
61 EFI_STATUS
62 DwSdReceiveResponse (
63   IN EFI_MMC_HOST_PROTOCOL     *This,
64   IN MMC_RESPONSE_TYPE          Type,
65   IN UINT32*                    Buffer
66   );
67 
68 EFI_STATUS
69 DwSdReadBlockData (
70   IN EFI_MMC_HOST_PROTOCOL     *This,
71   IN EFI_LBA                    Lba,
72   IN UINTN                      Length,
73   IN UINT32*                    Buffer
74   );
75 
76 BOOLEAN
DwSdIsPowerOn(VOID)77 DwSdIsPowerOn (
78   VOID
79   )
80 {
81     return TRUE;
82 }
83 
84 EFI_STATUS
DwSdInitialize(VOID)85 DwSdInitialize (
86   VOID
87   )
88 {
89     DEBUG ((EFI_D_BLKIO, "DwSdInitialize()"));
90     return EFI_SUCCESS;
91 }
92 
93 BOOLEAN
DwSdIsCardPresent(IN EFI_MMC_HOST_PROTOCOL * This)94 DwSdIsCardPresent (
95   IN EFI_MMC_HOST_PROTOCOL     *This
96   )
97 {
98   UINT32    Value;
99 
100   /*
101    * FIXME
102    * At first, reading GPIO pin shouldn't exist in SD driver. We need to
103    * add some callbacks to handle settings for hardware platform.
104    * In the second, reading GPIO pin should be based on GPIO driver. Now
105    * GPIO driver could only be used for one PL061 gpio controller. And it's
106    * used to detect jumper setting. As a workaround, we have to read the gpio
107    * register instead at here.
108    *
109    */
110   Value = MmioRead32 (0xf8012000 + (1 << 2));
111   if (Value)
112     return FALSE;
113   return TRUE;
114 }
115 
116 BOOLEAN
DwSdIsReadOnly(IN EFI_MMC_HOST_PROTOCOL * This)117 DwSdIsReadOnly (
118   IN EFI_MMC_HOST_PROTOCOL     *This
119   )
120 {
121   /* FIXME */
122   return FALSE;
123 }
124 
125 EFI_STATUS
DwSdBuildDevicePath(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL ** DevicePath)126 DwSdBuildDevicePath (
127   IN EFI_MMC_HOST_PROTOCOL      *This,
128   IN EFI_DEVICE_PATH_PROTOCOL   **DevicePath
129   )
130 {
131   EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
132 
133   NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
134   CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mDwSdDevicePathGuid);
135 
136   *DevicePath = NewDevicePathNode;
137   return EFI_SUCCESS;
138 }
139 
140 EFI_STATUS
DwSdUpdateClock(VOID)141 DwSdUpdateClock (
142   VOID
143   )
144 {
145   UINT32 Data;
146 
147   /* CMD_UPDATE_CLK */
148   Data = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |
149 	 BIT_CMD_START;
150   MmioWrite32 (DWSD_CMD, Data);
151   while (1) {
152     Data = MmioRead32 (DWSD_CMD);
153     if (!(Data & CMD_START_BIT))
154       break;
155     Data = MmioRead32 (DWSD_RINTSTS);
156     if (Data & DWSD_INT_HLE)
157     {
158       Print (L"failed to update mmc clock frequency\n");
159       return EFI_DEVICE_ERROR;
160     }
161   }
162   return EFI_SUCCESS;
163 }
164 
165 EFI_STATUS
DwSdSetClock(IN UINTN ClockFreq)166 DwSdSetClock (
167   IN UINTN                     ClockFreq
168   )
169 {
170   UINT32 Divider, Rate, Data, Count;
171   EFI_STATUS Status;
172   BOOLEAN Found = FALSE;
173 
174   for (Divider = 1; Divider < 256; Divider++) {
175     Rate = PcdGet32 (PcdDwSdDxeClockFrequencyInHz);
176     if ((Rate / (2 * Divider)) <= ClockFreq) {
177       Found = TRUE;
178       break;
179     }
180   }
181   if (Found == FALSE)
182     return EFI_NOT_FOUND;
183 
184   // Wait until MMC is idle
185   Count = 0;
186   do {
187     Data = MmioRead32 (DWSD_STATUS);
188     if (Count++ > MAX_IDLE_LOOPS)
189       break;
190   } while (Data & DWSD_STS_DATA_BUSY);
191 
192   // Disable MMC clock first
193   MmioWrite32 (DWSD_CLKENA, 0);
194   Status = DwSdUpdateClock ();
195   ASSERT (!EFI_ERROR (Status));
196 
197   MmioWrite32 (DWSD_CLKDIV, Divider);
198   Status = DwSdUpdateClock ();
199   ASSERT (!EFI_ERROR (Status));
200 
201   // Enable MMC clock
202   MmioWrite32 (DWSD_CLKENA, 1);
203   MmioWrite32 (DWSD_CLKSRC, 0);
204   Status = DwSdUpdateClock ();
205   ASSERT (!EFI_ERROR (Status));
206   return EFI_SUCCESS;
207 }
208 
209 EFI_STATUS
DwSdNotifyState(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_STATE State)210 DwSdNotifyState (
211   IN EFI_MMC_HOST_PROTOCOL     *This,
212   IN MMC_STATE                 State
213   )
214 {
215   UINT32      Data;
216   EFI_STATUS  Status;
217 
218   switch (State) {
219   case MmcInvalidState:
220     ASSERT (0);
221     break;
222   case MmcHwInitializationState:
223     MmioWrite32 (DWSD_PWREN, 1);
224 
225     // If device already turn on then restart it
226     Data = DWSD_CTRL_RESET_ALL;
227     MmioWrite32 (DWSD_CTRL, Data);
228     do {
229       // Wait until reset operation finished
230       Data = MmioRead32 (DWSD_CTRL);
231     } while (Data & DWSD_CTRL_RESET_ALL);
232 
233     MmioWrite32 (DWSD_RINTSTS, ~0);
234     MmioWrite32 (DWSD_INTMASK, 0);
235     MmioWrite32 (DWSD_TMOUT, ~0);
236     MmioWrite32 (DWSD_IDINTEN, 0);
237     MmioWrite32 (DWSD_BMOD, DWSD_IDMAC_SWRESET);
238 
239     MmioWrite32 (DWSD_BLKSIZ, DWSD_BLOCK_SIZE);
240     do {
241       Data = MmioRead32 (DWSD_BMOD);
242     } while (Data & DWSD_IDMAC_SWRESET);
243 
244 
245     Data = DWSD_DMA_BURST_SIZE(2) | DWSD_FIFO_TWMARK(8) | DWSD_FIFO_RWMARK(7) | (2 << 28);
246     MmioWrite32 (DWSD_FIFOTH, Data);
247     Data = DWSD_CARD_RD_THR(512) | DWSD_CARD_RD_THR_EN;
248     MmioWrite32 (DWSD_CARDTHRCTL, Data);
249 
250     // Set Data Length & Data Timer
251     MmioWrite32 (DWSD_CTYPE, 0);
252     MmioWrite32 (DWSD_DEBNCE, 0x00ffffff);
253 
254     // Setup clock that could not be higher than 400KHz.
255     Status = DwSdSetClock (400000);
256     ASSERT (!EFI_ERROR (Status));
257     MicroSecondDelay (100);
258 
259     break;
260   case MmcIdleState:
261     break;
262   case MmcReadyState:
263     break;
264   case MmcIdentificationState:
265     break;
266   case MmcStandByState:
267     break;
268   case MmcTransferState:
269     break;
270   case MmcSendingDataState:
271     break;
272   case MmcReceiveDataState:
273     break;
274   case MmcProgrammingState:
275     break;
276   case MmcDisconnectState:
277     break;
278   default:
279     ASSERT (0);
280   }
281   return EFI_SUCCESS;
282 }
283 
284 EFI_STATUS
SendCommand(IN MMC_CMD MmcCmd,IN UINT32 Argument)285 SendCommand (
286   IN MMC_CMD                    MmcCmd,
287   IN UINT32                     Argument
288   )
289 {
290   UINT32      Data, ErrMask, Count;
291 
292   MmioWrite32 (DWSD_RINTSTS, ~0);
293   MmioWrite32 (DWSD_CMDARG, Argument);
294   MicroSecondDelay(500);
295   // Wait until MMC is idle
296   Count = 0;
297   do {
298     Data = MmioRead32 (DWSD_STATUS);
299     if (Count++ > MAX_IDLE_LOOPS)
300       break;
301   } while (Data & DWSD_STS_DATA_BUSY);
302 
303   MmioWrite32 (DWSD_CMD, MmcCmd);
304 
305   ErrMask = DWSD_INT_EBE | DWSD_INT_HLE | DWSD_INT_RTO |
306             DWSD_INT_RCRC | DWSD_INT_RE;
307   ErrMask |= DWSD_INT_DCRC | DWSD_INT_DRT | DWSD_INT_SBE;
308   do {
309     MicroSecondDelay(500);
310     Data = MmioRead32 (DWSD_RINTSTS);
311 
312     if (Data & ErrMask) {
313       DEBUG ((EFI_D_ERROR, "Data:%x, ErrMask:%x, TBBCNT:%x, TCBCNT:%x, BYTCNT:%x, BLKSIZ:%x\n", Data, ErrMask, MmioRead32 (DWSD_TBBCNT), MmioRead32 (DWSD_TCBCNT), MmioRead32 (DWSD_BYTCNT), MmioRead32 (DWSD_BLKSIZ)));
314       return EFI_DEVICE_ERROR;
315     }
316     if (Data & DWSD_INT_DTO)	// Transfer Done
317       break;
318   } while (!(Data & DWSD_INT_CMD_DONE));
319   MmcCmd &= 0x3f;
320   if (MmcCmd == 17)
321     MicroSecondDelay(100);
322   else if (MmcCmd != 13)
323     MicroSecondDelay(5000);
324 
325   return EFI_SUCCESS;
326 }
327 
328 UINTN ACmd = 0;
329 
330 EFI_STATUS
DwSdSendCommand(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_CMD MmcCmd,IN UINT32 Argument)331 DwSdSendCommand (
332   IN EFI_MMC_HOST_PROTOCOL     *This,
333   IN MMC_CMD                    MmcCmd,
334   IN UINT32                     Argument
335   )
336 {
337   UINT32       Cmd = 0;
338   EFI_STATUS   Status = EFI_SUCCESS;
339   BOOLEAN      Pending = FALSE;
340   UINT32       Data;
341 
342   switch (MMC_GET_INDX(MmcCmd)) {
343   case MMC_INDX(0):
344     //Cmd = BIT_CMD_SEND_INIT;
345     Cmd = BIT_CMD_WAIT_PRVDATA_COMPLETE;
346     break;
347   case MMC_INDX(1):
348     Cmd = BIT_CMD_RESPONSE_EXPECT;
349     break;
350   case MMC_INDX(2):
351     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
352            BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_WAIT_PRVDATA_COMPLETE;
353     break;
354   case MMC_INDX(3):
355     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
356            BIT_CMD_WAIT_PRVDATA_COMPLETE;
357     break;
358   case MMC_INDX(6):
359     if (!ACmd) {
360       Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
361 	    BIT_CMD_DATA_EXPECTED | BIT_CMD_WAIT_PRVDATA_COMPLETE;
362     } else {
363       Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
364 	    BIT_CMD_WAIT_PRVDATA_COMPLETE;
365     }
366     if (!ACmd)
367       Pending = TRUE;
368     break;
369   case MMC_INDX(7):
370     if (Argument)
371         Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
372 	       BIT_CMD_WAIT_PRVDATA_COMPLETE;
373     else
374         Cmd = 0;
375     break;
376   case MMC_INDX(8):
377     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
378            BIT_CMD_READ |
379            BIT_CMD_WAIT_PRVDATA_COMPLETE;
380     break;
381   case MMC_INDX(9):
382     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
383            BIT_CMD_LONG_RESPONSE | BIT_CMD_WAIT_PRVDATA_COMPLETE;
384     break;
385   case MMC_INDX(12):
386     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
387            BIT_CMD_STOP_ABORT_CMD;
388     break;
389   case MMC_INDX(13):
390     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
391     break;
392   case MMC_INDX(17):
393   case MMC_INDX(18):
394     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
395            BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
396            BIT_CMD_WAIT_PRVDATA_COMPLETE;
397     Pending = TRUE;
398     Data = MmioRead32 (DWSD_CTRL);
399     Data |= DWSD_CTRL_FIFO_RESET;
400     MmioWrite32 (DWSD_CTRL, Data);
401     while (MmioRead32 (DWSD_CTRL) & DWSD_CTRL_FIFO_RESET) {
402     };
403     break;
404   case MMC_INDX(24):
405   case MMC_INDX(25):
406     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
407            BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE |
408            BIT_CMD_WAIT_PRVDATA_COMPLETE;
409     Pending = TRUE;
410     break;
411   case MMC_INDX(30):
412     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
413            BIT_CMD_DATA_EXPECTED;
414     break;
415   case MMC_INDX(41):
416     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_WAIT_PRVDATA_COMPLETE;
417     break;
418   case MMC_INDX(51):
419     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
420            BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
421            BIT_CMD_WAIT_PRVDATA_COMPLETE;
422     Pending = TRUE;
423     break;
424   case MMC_INDX(55):
425     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
426     ACmd = 1;
427     break;
428   default:
429     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
430     break;
431   }
432 
433   Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
434   if (Pending) {
435     mDwSdCommand = Cmd;
436     mDwSdArgument = Argument;
437   } else {
438     mDwSdCommand = 0;
439     mDwSdArgument = 0;
440     Status = SendCommand (Cmd, Argument);
441   }
442   /* Clear ACMD */
443   if (MMC_GET_INDX(MmcCmd) != MMC_INDX(55))
444     ACmd = 0;
445   return Status;
446 }
447 
448 EFI_STATUS
DwSdReceiveResponse(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_RESPONSE_TYPE Type,IN UINT32 * Buffer)449 DwSdReceiveResponse (
450   IN EFI_MMC_HOST_PROTOCOL     *This,
451   IN MMC_RESPONSE_TYPE          Type,
452   IN UINT32*                    Buffer
453   )
454 {
455   if (Buffer == NULL) {
456     return EFI_INVALID_PARAMETER;
457   }
458 
459   if (   (Type == MMC_RESPONSE_TYPE_R1)
460       || (Type == MMC_RESPONSE_TYPE_R1b)
461       || (Type == MMC_RESPONSE_TYPE_R3)
462       || (Type == MMC_RESPONSE_TYPE_R6)
463       || (Type == MMC_RESPONSE_TYPE_R7))
464   {
465     Buffer[0] = MmioRead32 (DWSD_RESP0);
466   } else if (Type == MMC_RESPONSE_TYPE_R2) {
467     Buffer[0] = MmioRead32 (DWSD_RESP0);
468     Buffer[1] = MmioRead32 (DWSD_RESP1);
469     Buffer[2] = MmioRead32 (DWSD_RESP2);
470     Buffer[3] = MmioRead32 (DWSD_RESP3);
471   }
472   return EFI_SUCCESS;
473 }
474 
475 EFI_STATUS
PrepareDmaData(IN DWSD_IDMAC_DESCRIPTOR * IdmacDesc,IN UINTN Length,IN UINT32 * Buffer)476 PrepareDmaData (
477   IN DWSD_IDMAC_DESCRIPTOR*    IdmacDesc,
478   IN UINTN                      Length,
479   IN UINT32*                    Buffer
480   )
481 {
482   UINTN  Cnt, Idx, LastIdx, Blks;
483 
484   if (Length % 4) {
485     DEBUG ((EFI_D_ERROR, "Length isn't aligned with 4\n"));
486     return EFI_BAD_BUFFER_SIZE;
487   }
488   if (Length < DWSD_DMA_THRESHOLD) {
489     return EFI_BUFFER_TOO_SMALL;
490   }
491   Cnt = (Length + DWSD_DMA_BUF_SIZE - 1) / DWSD_DMA_BUF_SIZE;
492   Blks = (Length + DWSD_BLOCK_SIZE - 1 ) / DWSD_BLOCK_SIZE;
493   Length = DWSD_BLOCK_SIZE * Blks;
494 
495   for (Idx = 0; Idx < Cnt; Idx++) {
496     (IdmacDesc + Idx)->Des0 = DWSD_IDMAC_DES0_OWN | DWSD_IDMAC_DES0_CH |
497 	    		      DWSD_IDMAC_DES0_DIC;
498     (IdmacDesc + Idx)->Des1 = DWSD_IDMAC_DES1_BS1(DWSD_DMA_BUF_SIZE);
499     /* Buffer Address */
500     (IdmacDesc + Idx)->Des2 = (UINT32)((UINTN)Buffer + DWSD_DMA_BUF_SIZE * Idx);
501     /* Next Descriptor Address */
502     (IdmacDesc + Idx)->Des3 = (UINT32)((UINTN)IdmacDesc +
503    	                               (sizeof(DWSD_IDMAC_DESCRIPTOR) * (Idx + 1)));
504   }
505   /* First Descriptor */
506   IdmacDesc->Des0 |= DWSD_IDMAC_DES0_FS;
507   /* Last Descriptor */
508   LastIdx = Cnt - 1;
509   (IdmacDesc + LastIdx)->Des0 |= DWSD_IDMAC_DES0_LD;
510   (IdmacDesc + LastIdx)->Des0 &= ~(DWSD_IDMAC_DES0_DIC | DWSD_IDMAC_DES0_CH);
511   (IdmacDesc + LastIdx)->Des1 = DWSD_IDMAC_DES1_BS1(Length -
512    		                (LastIdx * DWSD_DMA_BUF_SIZE));
513   /* Set the Next field of Last Descriptor */
514   (IdmacDesc + LastIdx)->Des3 = 0;
515   MmioWrite32 (DWSD_DBADDR, (UINT32)((UINTN)IdmacDesc));
516 
517   return EFI_SUCCESS;
518 }
519 
520 VOID
StartDma(UINTN Length)521 StartDma (
522   UINTN    Length
523   )
524 {
525   UINT32 Data;
526 
527   Data = MmioRead32 (DWSD_CTRL);
528   Data |= DWSD_CTRL_INT_EN | DWSD_CTRL_DMA_EN | DWSD_CTRL_IDMAC_EN;
529   MmioWrite32 (DWSD_CTRL, Data);
530   Data = MmioRead32 (DWSD_BMOD);
531   Data |= DWSD_IDMAC_ENABLE | DWSD_IDMAC_FB;
532   MmioWrite32 (DWSD_BMOD, Data);
533 
534   MmioWrite32 (DWSD_BLKSIZ, DWSD_BLOCK_SIZE);
535   MmioWrite32 (DWSD_BYTCNT, Length);
536 }
537 
538 STATIC
539 EFI_STATUS
ReadFifo(IN UINTN Length,IN UINT32 * Buffer)540 ReadFifo (
541   IN UINTN                      Length,
542   IN UINT32*                    Buffer
543   )
544 {
545   UINT32      Data, Received, Count;
546 
547   Received = 0;
548   Count = (Length + 3) / 4;
549   while (Received < Count) {
550     Data = MmioRead32 (DWSD_RINTSTS);
551     if (Data & DWSD_INT_CMD_DONE) {
552       *(Buffer + Received) = MmioRead32 (DWSD_FIFO_START);
553       Received++;
554     } else {
555       DEBUG ((EFI_D_ERROR, "Received:%d, RINTSTS:%x\n", Received, Data));
556     }
557   }
558   while (1) {
559     Data = MmioRead32 (DWSD_RINTSTS);
560     if (Data & DWSD_INT_DTO)
561       break;
562   }
563   /* FIXME */
564   MicroSecondDelay (1000);
565   return EFI_SUCCESS;
566 }
567 
568 EFI_STATUS
DwSdReadBlockData(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Length,IN UINT32 * Buffer)569 DwSdReadBlockData (
570   IN EFI_MMC_HOST_PROTOCOL     *This,
571   IN EFI_LBA                    Lba,
572   IN UINTN                      Length,
573   IN UINT32*                   Buffer
574   )
575 {
576   EFI_STATUS  Status;
577   UINT32      DescPages, CountPerPage, Count, Data;
578   EFI_TPL     Tpl;
579 
580   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
581 
582   CountPerPage = EFI_PAGE_SIZE / 16;
583   Count = (Length + DWSD_DMA_BUF_SIZE - 1) / DWSD_DMA_BUF_SIZE;
584   DescPages = (Count + CountPerPage - 1) / CountPerPage;
585 
586   InvalidateDataCacheRange (Buffer, Length);
587 
588   Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
589   if (EFI_ERROR (Status)) {
590     if (Status == EFI_BUFFER_TOO_SMALL) {
591       Data = MmioRead32 (DWSD_CTRL);
592       Data |= DWSD_CTRL_FIFO_RESET;
593       MmioWrite32 (DWSD_CTRL, Data);
594       while (MmioRead32 (DWSD_CTRL) & DWSD_CTRL_FIFO_RESET) {
595       };
596 
597       Status = SendCommand (mDwSdCommand, mDwSdArgument);
598       if (EFI_ERROR (Status)) {
599 	DEBUG ((EFI_D_ERROR, "Failed to read data from FIFO, mDwSdCommand:%x, mDwSdArgument:%x, Status:%r\n", mDwSdCommand, mDwSdArgument, Status));
600 	goto out;
601       }
602       Status = ReadFifo (Length, Buffer);
603     }
604     goto out;
605   } else {
606 
607     WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
608     StartDma (Length);
609 
610     Status = SendCommand (mDwSdCommand, mDwSdArgument);
611     if (EFI_ERROR (Status)) {
612       DEBUG ((EFI_D_ERROR, "Failed to read data, mDwSdCommand:%x, mDwSdArgument:%x, Status:%r\n", mDwSdCommand, mDwSdArgument, Status));
613       goto out;
614     }
615 
616     /* Wait until data transfer finished */
617     while (MmioRead32 (DWSD_TCBCNT) < MmioRead32 (DWSD_BYTCNT)) {
618     }
619 
620   }
621 out:
622   // Restore Tpl
623   gBS->RestoreTPL (Tpl);
624   return Status;
625 }
626 
627 EFI_STATUS
DwSdWriteBlockData(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Length,IN UINT32 * Buffer)628 DwSdWriteBlockData (
629   IN EFI_MMC_HOST_PROTOCOL     *This,
630   IN EFI_LBA                    Lba,
631   IN UINTN                      Length,
632   IN UINT32*                    Buffer
633   )
634 {
635   EFI_STATUS  Status;
636   UINT32      DescPages, CountPerPage, Count;
637   EFI_TPL     Tpl;
638 
639   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
640 
641   CountPerPage = EFI_PAGE_SIZE / 16;
642   Count = (Length + DWSD_DMA_BUF_SIZE - 1) / DWSD_DMA_BUF_SIZE;
643   DescPages = (Count + CountPerPage - 1) / CountPerPage;
644 
645   WriteBackDataCacheRange (Buffer, Length);
646 
647   Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
648   if (EFI_ERROR (Status))
649     goto out;
650 
651   WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
652   StartDma (Length);
653 
654   Status = SendCommand (mDwSdCommand, mDwSdArgument);
655   if (EFI_ERROR (Status)) {
656     DEBUG ((EFI_D_ERROR, "Failed to write data, mDwSdCommand:%x, mDwSdArgument:%x, Status:%r\n", mDwSdCommand, mDwSdArgument, Status));
657     goto out;
658   }
659 out:
660   // Restore Tpl
661   gBS->RestoreTPL (Tpl);
662   return Status;
663 }
664 
665 EFI_STATUS
DwSdSetIos(IN EFI_MMC_HOST_PROTOCOL * This,IN UINT32 BusClockFreq,IN UINT32 BusWidth,IN UINT32 TimingMode)666 DwSdSetIos (
667   IN EFI_MMC_HOST_PROTOCOL      *This,
668   IN  UINT32                    BusClockFreq,
669   IN  UINT32                    BusWidth,
670   IN  UINT32                    TimingMode
671   )
672 {
673   EFI_STATUS Status = EFI_SUCCESS;
674   UINT32    Data;
675 
676   if (TimingMode != EMMCBACKWARD) {
677     Data = MmioRead32 (DWSD_UHSREG);
678     switch (TimingMode) {
679     case EMMCHS52DDR1V2:
680     case EMMCHS52DDR1V8:
681       Data |= 1 << 16;
682       break;
683     case EMMCHS52:
684     case EMMCHS26:
685       Data &= ~(1 << 16);
686       break;
687     default:
688       return EFI_UNSUPPORTED;
689     }
690     MmioWrite32 (DWSD_UHSREG, Data);
691   }
692 
693   switch (BusWidth) {
694   case 1:
695     MmioWrite32 (DWSD_CTYPE, 0);
696     break;
697   case 4:
698     MmioWrite32 (DWSD_CTYPE, 1);
699     break;
700   case 8:
701     MmioWrite32 (DWSD_CTYPE, 1 << 16);
702     break;
703   default:
704     return EFI_UNSUPPORTED;
705   }
706   if (BusClockFreq) {
707     Status = DwSdSetClock (BusClockFreq);
708   }
709   return Status;
710 }
711 
712 BOOLEAN
DwSdIsMultiBlock(IN EFI_MMC_HOST_PROTOCOL * This)713 DwSdIsMultiBlock (
714   IN EFI_MMC_HOST_PROTOCOL      *This
715   )
716 {
717   return TRUE;
718 }
719 
720 EFI_MMC_HOST_PROTOCOL gMciHost = {
721   MMC_HOST_PROTOCOL_REVISION,
722   DwSdIsCardPresent,
723   DwSdIsReadOnly,
724   DwSdBuildDevicePath,
725   DwSdNotifyState,
726   DwSdSendCommand,
727   DwSdReceiveResponse,
728   DwSdReadBlockData,
729   DwSdWriteBlockData,
730   DwSdSetIos,
731   DwSdIsMultiBlock
732 };
733 
734 EFI_STATUS
DwSdDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)735 DwSdDxeInitialize (
736   IN EFI_HANDLE         ImageHandle,
737   IN EFI_SYSTEM_TABLE   *SystemTable
738   )
739 {
740   EFI_STATUS    Status;
741   EFI_HANDLE    Handle;
742 
743   Handle = NULL;
744 
745   DEBUG ((EFI_D_BLKIO, "DwSdDxeInitialize()\n"));
746 
747   //Publish Component Name, BlockIO protocol interfaces
748   Status = gBS->InstallMultipleProtocolInterfaces (
749                   &Handle,
750                   &gEfiMmcHostProtocolGuid,         &gMciHost,
751                   NULL
752                   );
753   ASSERT_EFI_ERROR (Status);
754 
755   return EFI_SUCCESS;
756 }
757