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