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