]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/PL180MciDxe/PL180Mci.c
ArmPlatformPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL180MciDxe / PL180Mci.c
CommitLineData
633724f4 1/** @file\r
2 This file implement the MMC Host Protocol for the ARM PrimeCell PL180.\r
3\r
93b429fc 4 Copyright (c) 2011-2012, ARM Limited. All rights reserved.\r
633724f4 5\r
f4dfad05 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
633724f4 7\r
8**/\r
9\r
10#include "PL180Mci.h"\r
11\r
12#include <Library/DevicePathLib.h>\r
13#include <Library/BaseMemoryLib.h>\r
14\r
15EFI_MMC_HOST_PROTOCOL *gpMmcHost;\r
16\r
17// Untested ...\r
18//#define USE_STREAM\r
19\r
20#define MMCI0_BLOCKLEN 512\r
21#define MMCI0_POW2_BLOCKLEN 9\r
22#define MMCI0_TIMEOUT 1000\r
23\r
93b429fc 24#define SYS_MCI_CARDIN BIT0\r
25#define SYS_MCI_WPROT BIT1\r
26\r
633724f4 27BOOLEAN\r
28MciIsPowerOn (\r
29 VOID\r
30 )\r
31{\r
93b429fc 32 return ((MmioRead32 (MCI_POWER_CONTROL_REG) & MCI_POWER_ON) == MCI_POWER_ON);\r
633724f4 33}\r
34\r
35EFI_STATUS\r
36MciInitialize (\r
37 VOID\r
38 )\r
39{\r
93b429fc 40 MCI_TRACE ("MciInitialize()");\r
633724f4 41 return EFI_SUCCESS;\r
42}\r
43\r
44BOOLEAN\r
45MciIsCardPresent (\r
16d88c2d 46 IN EFI_MMC_HOST_PROTOCOL *This\r
633724f4 47 )\r
48{\r
93b429fc 49 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_CARDIN);\r
633724f4 50}\r
51\r
52BOOLEAN\r
53MciIsReadOnly (\r
16d88c2d 54 IN EFI_MMC_HOST_PROTOCOL *This\r
633724f4 55 )\r
56{\r
93b429fc 57 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_WPROT);\r
633724f4 58}\r
59\r
633724f4 60// Convert block size to 2^n\r
61STATIC\r
62UINT32\r
63GetPow2BlockLen (\r
64 IN UINT32 BlockLen\r
65 )\r
66{\r
67 UINTN Loop;\r
68 UINTN Pow2BlockLen;\r
69\r
70 Loop = 0x8000;\r
71 Pow2BlockLen = 15;\r
72 do {\r
73 Loop = (Loop >> 1) & 0xFFFF;\r
74 Pow2BlockLen--;\r
75 } while (Pow2BlockLen && (!(Loop & BlockLen)));\r
76\r
77 return Pow2BlockLen;\r
78}\r
633724f4 79\r
80VOID\r
81MciPrepareDataPath (\r
82 IN UINTN TransferDirection\r
83 )\r
84{\r
85 // Set Data Length & Data Timer\r
93b429fc 86 MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);\r
87 MmioWrite32 (MCI_DATA_LENGTH_REG, MMCI0_BLOCKLEN);\r
633724f4 88\r
89#ifndef USE_STREAM\r
93b429fc 90 //Note: we are using a hardcoded BlockLen (==512). If we decide to use a variable size, we could\r
91 // compute the pow2 of BlockLen with the above function GetPow2BlockLen ()\r
92 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4));\r
633724f4 93#else\r
16d88c2d 94 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS);\r
633724f4 95#endif\r
96}\r
97\r
98EFI_STATUS\r
99MciSendCommand (\r
16d88c2d 100 IN EFI_MMC_HOST_PROTOCOL *This,\r
101 IN MMC_CMD MmcCmd,\r
102 IN UINT32 Argument\r
633724f4 103 )\r
104{\r
93b429fc 105 UINT32 Status;\r
106 UINT32 Cmd;\r
107 UINTN RetVal;\r
108 UINTN CmdCtrlReg;\r
dad28de1 109 UINT32 DoneMask;\r
633724f4 110\r
111 RetVal = EFI_SUCCESS;\r
112\r
113 if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) {\r
93b429fc 114 MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT);\r
633724f4 115 } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) {\r
93b429fc 116 MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD);\r
1df2fe14
HZ
117 } else if (MmcCmd == MMC_CMD6) {\r
118 MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);\r
119 MmioWrite32 (MCI_DATA_LENGTH_REG, 64);\r
120#ifndef USE_STREAM\r
121 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (64));\r
122#else\r
123 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS);\r
124#endif\r
125 } else if (MmcCmd == MMC_ACMD51) {\r
126 MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);\r
127 /* SCR register is 8 bytes long. */\r
128 MmioWrite32 (MCI_DATA_LENGTH_REG, 8);\r
129#ifndef USE_STREAM\r
130 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (8));\r
131#else\r
132 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS);\r
133#endif\r
633724f4 134 }\r
135\r
136 // Create Command for PL180\r
93b429fc 137 Cmd = (MMC_GET_INDX (MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLE;\r
633724f4 138 if (MmcCmd & MMC_CMD_WAIT_RESPONSE) {\r
139 Cmd |= MCI_CPSM_WAIT_RESPONSE;\r
140 }\r
141\r
142 if (MmcCmd & MMC_CMD_LONG_RESPONSE) {\r
143 Cmd |= MCI_CPSM_LONG_RESPONSE;\r
144 }\r
145\r
146 // Clear Status register static flags\r
93b429fc 147 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);\r
633724f4 148\r
93b429fc 149 // Write to command argument register\r
150 MmioWrite32 (MCI_ARGUMENT_REG, Argument);\r
633724f4 151\r
93b429fc 152 // Write to command register\r
153 MmioWrite32 (MCI_COMMAND_REG, Cmd);\r
633724f4 154\r
dad28de1 155 DoneMask = (Cmd & MCI_CPSM_WAIT_RESPONSE)\r
156 ? (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_ERROR)\r
157 : (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_ERROR);\r
158 do {\r
93b429fc 159 Status = MmioRead32 (MCI_STATUS_REG);\r
dad28de1 160 } while (! (Status & DoneMask));\r
633724f4 161\r
dad28de1 162 if ((Status & MCI_STATUS_CMD_ERROR)) {\r
163 // Clear Status register error flags\r
164 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_ERROR);\r
3402aac7 165\r
633724f4 166 if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) {\r
93b429fc 167 DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));\r
633724f4 168 RetVal = EFI_NO_RESPONSE;\r
633724f4 169 } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) {\r
93b429fc 170 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));\r
633724f4 171 RetVal = EFI_TIMEOUT;\r
dad28de1 172 } else if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) {\r
633724f4 173 // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.\r
174 RetVal = EFI_CRC_ERROR;\r
633724f4 175 }\r
176 }\r
177\r
93b429fc 178 // Disable Command Path\r
179 CmdCtrlReg = MmioRead32 (MCI_COMMAND_REG);\r
180 MmioWrite32 (MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLE));\r
181 return RetVal;\r
633724f4 182}\r
183\r
184EFI_STATUS\r
185MciReceiveResponse (\r
16d88c2d 186 IN EFI_MMC_HOST_PROTOCOL *This,\r
187 IN MMC_RESPONSE_TYPE Type,\r
188 IN UINT32* Buffer\r
633724f4 189 )\r
190{\r
191 if (Buffer == NULL) {\r
192 return EFI_INVALID_PARAMETER;\r
193 }\r
194\r
93b429fc 195 if ( (Type == MMC_RESPONSE_TYPE_R1)\r
196 || (Type == MMC_RESPONSE_TYPE_R1b)\r
197 || (Type == MMC_RESPONSE_TYPE_R3)\r
198 || (Type == MMC_RESPONSE_TYPE_R6)\r
199 || (Type == MMC_RESPONSE_TYPE_R7))\r
633724f4 200 {\r
93b429fc 201 Buffer[0] = MmioRead32 (MCI_RESPONSE3_REG);\r
633724f4 202 } else if (Type == MMC_RESPONSE_TYPE_R2) {\r
93b429fc 203 Buffer[0] = MmioRead32 (MCI_RESPONSE0_REG);\r
204 Buffer[1] = MmioRead32 (MCI_RESPONSE1_REG);\r
205 Buffer[2] = MmioRead32 (MCI_RESPONSE2_REG);\r
206 Buffer[3] = MmioRead32 (MCI_RESPONSE3_REG);\r
633724f4 207 }\r
208\r
209 return EFI_SUCCESS;\r
210}\r
211\r
212EFI_STATUS\r
213MciReadBlockData (\r
16d88c2d 214 IN EFI_MMC_HOST_PROTOCOL *This,\r
215 IN EFI_LBA Lba,\r
216 IN UINTN Length,\r
217 IN UINT32* Buffer\r
633724f4 218 )\r
219{\r
220 UINTN Loop;\r
221 UINTN Finish;\r
222 UINTN Status;\r
223 EFI_STATUS RetVal;\r
224 UINTN DataCtrlReg;\r
bb058bcd 225 EFI_TPL Tpl;\r
633724f4 226\r
227 RetVal = EFI_SUCCESS;\r
228\r
229 // Read data from the RX FIFO\r
230 Loop = 0;\r
1df2fe14
HZ
231 if (Length < MMCI0_BLOCKLEN) {\r
232 Finish = Length / 4;\r
233 } else {\r
234 Finish = MMCI0_BLOCKLEN / 4;\r
235 }\r
3402aac7 236\r
bb058bcd
OM
237 // Raise the TPL at the highest level to disable Interrupts.\r
238 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
239\r
633724f4 240 do {\r
241 // Read the Status flags\r
93b429fc 242 Status = MmioRead32 (MCI_STATUS_REG);\r
633724f4 243\r
244 // Do eight reads if possible else a single read\r
245 if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) {\r
246 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
247 Loop++;\r
248 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
249 Loop++;\r
250 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
251 Loop++;\r
252 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
253 Loop++;\r
254 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
255 Loop++;\r
256 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
257 Loop++;\r
258 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
259 Loop++;\r
260 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
261 Loop++;\r
262 } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) {\r
263 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);\r
264 Loop++;\r
265 } else {\r
266 //Check for error conditions and timeouts\r
93b429fc 267 if (Status & MCI_STATUS_CMD_DATATIMEOUT) {\r
268 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));\r
633724f4 269 RetVal = EFI_TIMEOUT;\r
270 break;\r
93b429fc 271 } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {\r
272 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));\r
633724f4 273 RetVal = EFI_CRC_ERROR;\r
274 break;\r
93b429fc 275 } else if (Status & MCI_STATUS_CMD_START_BIT_ERROR) {\r
276 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));\r
633724f4 277 RetVal = EFI_NO_RESPONSE;\r
278 break;\r
279 }\r
280 }\r
281 //clear RX over run flag\r
282 if(Status & MCI_STATUS_CMD_RXOVERRUN) {\r
283 MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN);\r
284 }\r
285 } while ((Loop < Finish));\r
286\r
bb058bcd
OM
287 // Restore Tpl\r
288 gBS->RestoreTPL (Tpl);\r
289\r
93b429fc 290 // Clear Status flags\r
291 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);\r
633724f4 292\r
93b429fc 293 //Disable Data path\r
294 DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);\r
295 MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));\r
633724f4 296\r
93b429fc 297 return RetVal;\r
633724f4 298}\r
299\r
300EFI_STATUS\r
301MciWriteBlockData (\r
16d88c2d 302 IN EFI_MMC_HOST_PROTOCOL *This,\r
303 IN EFI_LBA Lba,\r
304 IN UINTN Length,\r
305 IN UINT32* Buffer\r
633724f4 306 )\r
307{\r
308 UINTN Loop;\r
309 UINTN Finish;\r
310 UINTN Timer;\r
311 UINTN Status;\r
312 EFI_STATUS RetVal;\r
313 UINTN DataCtrlReg;\r
bb058bcd 314 EFI_TPL Tpl;\r
633724f4 315\r
316 RetVal = EFI_SUCCESS;\r
317\r
318 // Write the data to the TX FIFO\r
319 Loop = 0;\r
320 Finish = MMCI0_BLOCKLEN / 4;\r
321 Timer = MMCI0_TIMEOUT * 100;\r
bb058bcd
OM
322\r
323 // Raise the TPL at the highest level to disable Interrupts.\r
324 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
325\r
633724f4 326 do {\r
327 // Read the Status flags\r
93b429fc 328 Status = MmioRead32 (MCI_STATUS_REG);\r
633724f4 329\r
330 // Do eight writes if possible else a single write\r
331 if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) {\r
332 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
333 Loop++;\r
334 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
335 Loop++;\r
336 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
337 Loop++;\r
338 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
339 Loop++;\r
340 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
341 Loop++;\r
342 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
343 Loop++;\r
344 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
345 Loop++;\r
346 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
347 Loop++;\r
4f8c9ae0 348 } else if (!(Status & MCI_STATUS_CMD_TXFIFOFULL)) {\r
633724f4 349 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);\r
350 Loop++;\r
351 } else {\r
93b429fc 352 // Check for error conditions and timeouts\r
353 if (Status & MCI_STATUS_CMD_DATATIMEOUT) {\r
354 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));\r
633724f4 355 RetVal = EFI_TIMEOUT;\r
356 goto Exit;\r
93b429fc 357 } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {\r
358 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));\r
633724f4 359 RetVal = EFI_CRC_ERROR;\r
360 goto Exit;\r
93b429fc 361 } else if (Status & MCI_STATUS_CMD_TX_UNDERRUN) {\r
633724f4 362 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TX buffer Underrun! Response:0x%X Status:0x%x, Number of bytes written 0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status, Loop));\r
363 RetVal = EFI_BUFFER_TOO_SMALL;\r
364 ASSERT(0);\r
365 goto Exit;\r
366 }\r
367 }\r
368 } while (Loop < Finish);\r
369\r
bb058bcd
OM
370 // Restore Tpl\r
371 gBS->RestoreTPL (Tpl);\r
372\r
633724f4 373 // Wait for FIFO to drain\r
93b429fc 374 Timer = MMCI0_TIMEOUT * 60;\r
375 Status = MmioRead32 (MCI_STATUS_REG);\r
633724f4 376#ifndef USE_STREAM\r
377 // Single block\r
93b429fc 378 while (((Status & MCI_STATUS_TXDONE) != MCI_STATUS_TXDONE) && Timer) {\r
633724f4 379#else\r
380 // Stream\r
381 while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) {\r
382#endif\r
383 NanoSecondDelay(10);\r
93b429fc 384 Status = MmioRead32 (MCI_STATUS_REG);\r
633724f4 385 Timer--;\r
386 }\r
387\r
93b429fc 388 // Clear Status flags\r
389 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);\r
dad28de1 390\r
633724f4 391 if (Timer == 0) {\r
dad28de1 392 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of words written 0x%x\n", Loop));\r
633724f4 393 RetVal = EFI_TIMEOUT;\r
394 }\r
395\r
396Exit:\r
93b429fc 397 // Disable Data path\r
398 DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);\r
399 MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));\r
400 return RetVal;\r
633724f4 401}\r
402\r
403EFI_STATUS\r
404MciNotifyState (\r
16d88c2d 405 IN EFI_MMC_HOST_PROTOCOL *This,\r
406 IN MMC_STATE State\r
633724f4 407 )\r
408{\r
409 UINT32 Data32;\r
410\r
93b429fc 411 switch (State) {\r
633724f4 412 case MmcInvalidState:\r
93b429fc 413 ASSERT (0);\r
633724f4 414 break;\r
415 case MmcHwInitializationState:\r
416 // If device already turn on then restart it\r
93b429fc 417 Data32 = MmioRead32 (MCI_POWER_CONTROL_REG);\r
633724f4 418 if ((Data32 & 0x2) == MCI_POWER_UP) {\r
93b429fc 419 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI");\r
633724f4 420\r
421 // Turn off\r
93b429fc 422 MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0);\r
423 MmioWrite32 (MCI_POWER_CONTROL_REG, 0);\r
424 MicroSecondDelay (100);\r
633724f4 425 }\r
426\r
93b429fc 427 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI");\r
633724f4 428 // Setup clock\r
429 // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz\r
93b429fc 430 MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);\r
633724f4 431\r
432 // Set the voltage\r
93b429fc 433 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_OPENDRAIN | (15<<2));\r
434 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP);\r
435 MicroSecondDelay (10);\r
436 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON);\r
437 MicroSecondDelay (100);\r
633724f4 438\r
439 // Set Data Length & Data Timer\r
93b429fc 440 MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFF);\r
441 MmioWrite32 (MCI_DATA_LENGTH_REG, 8);\r
633724f4 442\r
93b429fc 443 ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON);\r
633724f4 444 break;\r
445 case MmcIdleState:\r
93b429fc 446 MCI_TRACE ("MciNotifyState(MmcIdleState)");\r
633724f4 447 break;\r
448 case MmcReadyState:\r
93b429fc 449 MCI_TRACE ("MciNotifyState(MmcReadyState)");\r
633724f4 450 break;\r
451 case MmcIdentificationState:\r
93b429fc 452 MCI_TRACE ("MciNotifyState (MmcIdentificationState)");\r
633724f4 453 break;\r
454 case MmcStandByState:{\r
455 volatile UINT32 PwrCtrlReg;\r
93b429fc 456 MCI_TRACE ("MciNotifyState (MmcStandByState)");\r
633724f4 457\r
458 // Enable MCICMD push-pull drive\r
93b429fc 459 PwrCtrlReg = MmioRead32 (MCI_POWER_CONTROL_REG);\r
633724f4 460 //Disable Open Drain output\r
93b429fc 461 PwrCtrlReg &= ~ (MCI_POWER_OPENDRAIN);\r
462 MmioWrite32 (MCI_POWER_CONTROL_REG, PwrCtrlReg);\r
633724f4 463\r
464 // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)\r
465 //\r
466 // Note: Increasing clock speed causes TX FIFO under-run errors.\r
467 // So careful when optimising this driver for higher performance.\r
468 //\r
469 MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);\r
470 // Set MMCI0 clock to 24MHz (by bypassing the divider)\r
471 //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);\r
472 break;\r
473 }\r
474 case MmcTransferState:\r
93b429fc 475 //MCI_TRACE ("MciNotifyState(MmcTransferState)");\r
633724f4 476 break;\r
477 case MmcSendingDataState:\r
93b429fc 478 MCI_TRACE ("MciNotifyState(MmcSendingDataState)");\r
633724f4 479 break;\r
480 case MmcReceiveDataState:\r
93b429fc 481 MCI_TRACE ("MciNotifyState(MmcReceiveDataState)");\r
633724f4 482 break;\r
483 case MmcProgrammingState:\r
93b429fc 484 MCI_TRACE ("MciNotifyState(MmcProgrammingState)");\r
633724f4 485 break;\r
486 case MmcDisconnectState:\r
93b429fc 487 MCI_TRACE ("MciNotifyState(MmcDisconnectState)");\r
633724f4 488 break;\r
489 default:\r
93b429fc 490 ASSERT (0);\r
633724f4 491 }\r
492 return EFI_SUCCESS;\r
493}\r
494\r
495EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;\r
496\r
497EFI_STATUS\r
498MciBuildDevicePath (\r
16d88c2d 499 IN EFI_MMC_HOST_PROTOCOL *This,\r
500 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
633724f4 501 )\r
502{\r
503 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
504\r
93b429fc 505 NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));\r
506 CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mPL180MciDevicePathGuid);\r
633724f4 507\r
508 *DevicePath = NewDevicePathNode;\r
509 return EFI_SUCCESS;\r
510}\r
511\r
512EFI_MMC_HOST_PROTOCOL gMciHost = {\r
16d88c2d 513 MMC_HOST_PROTOCOL_REVISION,\r
633724f4 514 MciIsCardPresent,\r
515 MciIsReadOnly,\r
516 MciBuildDevicePath,\r
517 MciNotifyState,\r
518 MciSendCommand,\r
519 MciReceiveResponse,\r
520 MciReadBlockData,\r
521 MciWriteBlockData\r
522};\r
523\r
524EFI_STATUS\r
525PL180MciDxeInitialize (\r
526 IN EFI_HANDLE ImageHandle,\r
527 IN EFI_SYSTEM_TABLE *SystemTable\r
528 )\r
529{\r
530 EFI_STATUS Status;\r
93b429fc 531 EFI_HANDLE Handle;\r
532\r
300fc77a
AB
533 DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180\n",\r
534 MCI_PERIPH_ID_REG0));\r
535\r
536 // Check if this is a PL180\r
537 if (MmioRead8 (MCI_PERIPH_ID_REG0) != MCI_PERIPH_ID0 ||\r
538 MmioRead8 (MCI_PERIPH_ID_REG1) != MCI_PERIPH_ID1 ||\r
539 MmioRead8 (MCI_PERIPH_ID_REG2) != MCI_PERIPH_ID2 ||\r
300fc77a
AB
540 MmioRead8 (MCI_PCELL_ID_REG0) != MCI_PCELL_ID0 ||\r
541 MmioRead8 (MCI_PCELL_ID_REG1) != MCI_PCELL_ID1 ||\r
542 MmioRead8 (MCI_PCELL_ID_REG2) != MCI_PCELL_ID2 ||\r
543 MmioRead8 (MCI_PCELL_ID_REG3) != MCI_PCELL_ID3) {\r
544\r
b5ffaf7d
RH
545 DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180"\r
546 " failed\n", MCI_PERIPH_ID_REG0));\r
300fc77a
AB
547 return EFI_NOT_FOUND;\r
548 }\r
549\r
93b429fc 550 Handle = NULL;\r
633724f4 551\r
93b429fc 552 MCI_TRACE ("PL180MciDxeInitialize()");\r
633724f4 553\r
554 //Publish Component Name, BlockIO protocol interfaces\r
555 Status = gBS->InstallMultipleProtocolInterfaces (\r
3402aac7 556 &Handle,\r
633724f4 557 &gEfiMmcHostProtocolGuid, &gMciHost,\r
558 NULL\r
559 );\r
560 ASSERT_EFI_ERROR (Status);\r
561\r
562 return EFI_SUCCESS;\r
563}\r