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