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