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