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