2 This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
4 Copyright (c) 2011-2012, ARM Limited. All rights reserved.
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/DevicePathLib.h>
19 #include <Library/BaseMemoryLib.h>
21 EFI_MMC_HOST_PROTOCOL
*gpMmcHost
;
26 #define MMCI0_BLOCKLEN 512
27 #define MMCI0_POW2_BLOCKLEN 9
28 #define MMCI0_TIMEOUT 1000
30 #define SYS_MCI_CARDIN BIT0
31 #define SYS_MCI_WPROT BIT1
38 return ((MmioRead32 (MCI_POWER_CONTROL_REG
) & MCI_POWER_ON
) == MCI_POWER_ON
);
46 MCI_TRACE ("MciInitialize()");
52 IN EFI_MMC_HOST_PROTOCOL
*This
55 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress
)) & SYS_MCI_CARDIN
);
60 IN EFI_MMC_HOST_PROTOCOL
*This
63 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress
)) & SYS_MCI_WPROT
);
67 //Note: This function has been commented out because it is not used yet.
68 // This function could be used to remove the hardcoded BlockLen used
69 // in MciPrepareDataPath
71 // Convert block size to 2^n
84 Loop
= (Loop
>> 1) & 0xFFFF;
86 } while (Pow2BlockLen
&& (!(Loop
& BlockLen
)));
94 IN UINTN TransferDirection
97 // Set Data Length & Data Timer
98 MmioWrite32 (MCI_DATA_TIMER_REG
, 0xFFFFFFF);
99 MmioWrite32 (MCI_DATA_LENGTH_REG
, MMCI0_BLOCKLEN
);
102 //Note: we are using a hardcoded BlockLen (==512). If we decide to use a variable size, we could
103 // compute the pow2 of BlockLen with the above function GetPow2BlockLen ()
104 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_DMA_ENABLE
| TransferDirection
| (MMCI0_POW2_BLOCKLEN
<< 4));
106 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_DMA_ENABLE
| TransferDirection
| MCI_DATACTL_STREAM_TRANS
);
112 IN EFI_MMC_HOST_PROTOCOL
*This
,
123 RetVal
= EFI_SUCCESS
;
125 if ((MmcCmd
== MMC_CMD17
) || (MmcCmd
== MMC_CMD11
)) {
126 MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT
);
127 } else if ((MmcCmd
== MMC_CMD24
) || (MmcCmd
== MMC_CMD20
)) {
128 MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD
);
131 // Create Command for PL180
132 Cmd
= (MMC_GET_INDX (MmcCmd
) & INDX_MASK
) | MCI_CPSM_ENABLE
;
133 if (MmcCmd
& MMC_CMD_WAIT_RESPONSE
) {
134 Cmd
|= MCI_CPSM_WAIT_RESPONSE
;
137 if (MmcCmd
& MMC_CMD_LONG_RESPONSE
) {
138 Cmd
|= MCI_CPSM_LONG_RESPONSE
;
141 // Clear Status register static flags
142 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_CLR_ALL_STATUS
);
144 // Write to command argument register
145 MmioWrite32 (MCI_ARGUMENT_REG
, Argument
);
147 // Write to command register
148 MmioWrite32 (MCI_COMMAND_REG
, Cmd
);
150 DoneMask
= (Cmd
& MCI_CPSM_WAIT_RESPONSE
)
151 ? (MCI_STATUS_CMD_RESPEND
| MCI_STATUS_CMD_ERROR
)
152 : (MCI_STATUS_CMD_SENT
| MCI_STATUS_CMD_ERROR
);
154 Status
= MmioRead32 (MCI_STATUS_REG
);
155 } while (! (Status
& DoneMask
));
157 if ((Status
& MCI_STATUS_CMD_ERROR
)) {
158 // Clear Status register error flags
159 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_STATUS_CMD_ERROR
);
161 if ((Status
& MCI_STATUS_CMD_START_BIT_ERROR
)) {
162 DEBUG ((EFI_D_ERROR
, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n", (Cmd
& 0x3F), MmioRead32 (MCI_RESPONSE0_REG
), Status
));
163 RetVal
= EFI_NO_RESPONSE
;
164 } else if ((Status
& MCI_STATUS_CMD_CMDTIMEOUT
)) {
165 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
166 RetVal
= EFI_TIMEOUT
;
167 } else if ((!(MmcCmd
& MMC_CMD_NO_CRC_RESPONSE
)) && (Status
& MCI_STATUS_CMD_CMDCRCFAIL
)) {
168 // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
169 RetVal
= EFI_CRC_ERROR
;
173 // Disable Command Path
174 CmdCtrlReg
= MmioRead32 (MCI_COMMAND_REG
);
175 MmioWrite32 (MCI_COMMAND_REG
, (CmdCtrlReg
& ~MCI_CPSM_ENABLE
));
181 IN EFI_MMC_HOST_PROTOCOL
*This
,
182 IN MMC_RESPONSE_TYPE Type
,
186 if (Buffer
== NULL
) {
187 return EFI_INVALID_PARAMETER
;
190 if ( (Type
== MMC_RESPONSE_TYPE_R1
)
191 || (Type
== MMC_RESPONSE_TYPE_R1b
)
192 || (Type
== MMC_RESPONSE_TYPE_R3
)
193 || (Type
== MMC_RESPONSE_TYPE_R6
)
194 || (Type
== MMC_RESPONSE_TYPE_R7
))
196 Buffer
[0] = MmioRead32 (MCI_RESPONSE3_REG
);
197 } else if (Type
== MMC_RESPONSE_TYPE_R2
) {
198 Buffer
[0] = MmioRead32 (MCI_RESPONSE0_REG
);
199 Buffer
[1] = MmioRead32 (MCI_RESPONSE1_REG
);
200 Buffer
[2] = MmioRead32 (MCI_RESPONSE2_REG
);
201 Buffer
[3] = MmioRead32 (MCI_RESPONSE3_REG
);
209 IN EFI_MMC_HOST_PROTOCOL
*This
,
222 RetVal
= EFI_SUCCESS
;
224 // Read data from the RX FIFO
226 Finish
= MMCI0_BLOCKLEN
/ 4;
228 // Raise the TPL at the highest level to disable Interrupts.
229 Tpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
232 // Read the Status flags
233 Status
= MmioRead32 (MCI_STATUS_REG
);
235 // Do eight reads if possible else a single read
236 if (Status
& MCI_STATUS_CMD_RXFIFOHALFFULL
) {
237 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
239 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
241 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
243 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
245 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
247 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
249 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
251 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
253 } else if (Status
& MCI_STATUS_CMD_RXDATAAVAILBL
) {
254 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
257 //Check for error conditions and timeouts
258 if (Status
& MCI_STATUS_CMD_DATATIMEOUT
) {
259 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
260 RetVal
= EFI_TIMEOUT
;
262 } else if (Status
& MCI_STATUS_CMD_DATACRCFAIL
) {
263 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
264 RetVal
= EFI_CRC_ERROR
;
266 } else if (Status
& MCI_STATUS_CMD_START_BIT_ERROR
) {
267 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
268 RetVal
= EFI_NO_RESPONSE
;
272 //clear RX over run flag
273 if(Status
& MCI_STATUS_CMD_RXOVERRUN
) {
274 MmioWrite32(MCI_CLEAR_STATUS_REG
, MCI_STATUS_CMD_RXOVERRUN
);
276 } while ((Loop
< Finish
));
279 gBS
->RestoreTPL (Tpl
);
281 // Clear Status flags
282 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_CLR_ALL_STATUS
);
285 DataCtrlReg
= MmioRead32 (MCI_DATA_CTL_REG
);
286 MmioWrite32 (MCI_DATA_CTL_REG
, (DataCtrlReg
& MCI_DATACTL_DISABLE_MASK
));
293 IN EFI_MMC_HOST_PROTOCOL
*This
,
307 RetVal
= EFI_SUCCESS
;
309 // Write the data to the TX FIFO
311 Finish
= MMCI0_BLOCKLEN
/ 4;
312 Timer
= MMCI0_TIMEOUT
* 100;
314 // Raise the TPL at the highest level to disable Interrupts.
315 Tpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
318 // Read the Status flags
319 Status
= MmioRead32 (MCI_STATUS_REG
);
321 // Do eight writes if possible else a single write
322 if (Status
& MCI_STATUS_CMD_TXFIFOHALFEMPTY
) {
323 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
325 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
327 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
329 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
331 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
333 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
335 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
337 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
339 } else if (!(Status
& MCI_STATUS_CMD_TXFIFOFULL
)) {
340 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
343 // Check for error conditions and timeouts
344 if (Status
& MCI_STATUS_CMD_DATATIMEOUT
) {
345 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
346 RetVal
= EFI_TIMEOUT
;
348 } else if (Status
& MCI_STATUS_CMD_DATACRCFAIL
) {
349 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
350 RetVal
= EFI_CRC_ERROR
;
352 } else if (Status
& MCI_STATUS_CMD_TX_UNDERRUN
) {
353 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
));
354 RetVal
= EFI_BUFFER_TOO_SMALL
;
359 } while (Loop
< Finish
);
362 gBS
->RestoreTPL (Tpl
);
364 // Wait for FIFO to drain
365 Timer
= MMCI0_TIMEOUT
* 60;
366 Status
= MmioRead32 (MCI_STATUS_REG
);
369 while (((Status
& MCI_STATUS_TXDONE
) != MCI_STATUS_TXDONE
) && Timer
) {
372 while (((Status
& MCI_STATUS_CMD_DATAEND
) != MCI_STATUS_CMD_DATAEND
) && Timer
) {
375 Status
= MmioRead32 (MCI_STATUS_REG
);
379 // Clear Status flags
380 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_CLR_ALL_STATUS
);
383 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): Data End timeout Number of words written 0x%x\n", Loop
));
384 RetVal
= EFI_TIMEOUT
;
389 DataCtrlReg
= MmioRead32 (MCI_DATA_CTL_REG
);
390 MmioWrite32 (MCI_DATA_CTL_REG
, (DataCtrlReg
& MCI_DATACTL_DISABLE_MASK
));
396 IN EFI_MMC_HOST_PROTOCOL
*This
,
403 case MmcInvalidState
:
406 case MmcHwInitializationState
:
407 // If device already turn on then restart it
408 Data32
= MmioRead32 (MCI_POWER_CONTROL_REG
);
409 if ((Data32
& 0x2) == MCI_POWER_UP
) {
410 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI");
413 MmioWrite32 (MCI_CLOCK_CONTROL_REG
, 0);
414 MmioWrite32 (MCI_POWER_CONTROL_REG
, 0);
415 MicroSecondDelay (100);
418 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI");
420 // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
421 MmioWrite32 (MCI_CLOCK_CONTROL_REG
, 0x1D | MCI_CLOCK_ENABLE
| MCI_CLOCK_POWERSAVE
);
424 MmioWrite32 (MCI_POWER_CONTROL_REG
, MCI_POWER_OPENDRAIN
| (15<<2));
425 MmioWrite32 (MCI_POWER_CONTROL_REG
, MCI_POWER_ROD
| MCI_POWER_OPENDRAIN
| (15<<2) | MCI_POWER_UP
);
426 MicroSecondDelay (10);
427 MmioWrite32 (MCI_POWER_CONTROL_REG
, MCI_POWER_ROD
| MCI_POWER_OPENDRAIN
| (15<<2) | MCI_POWER_ON
);
428 MicroSecondDelay (100);
430 // Set Data Length & Data Timer
431 MmioWrite32 (MCI_DATA_TIMER_REG
, 0xFFFFF);
432 MmioWrite32 (MCI_DATA_LENGTH_REG
, 8);
434 ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG
) & 0x3) == MCI_POWER_ON
);
437 MCI_TRACE ("MciNotifyState(MmcIdleState)");
440 MCI_TRACE ("MciNotifyState(MmcReadyState)");
442 case MmcIdentificationState
:
443 MCI_TRACE ("MciNotifyState (MmcIdentificationState)");
445 case MmcStandByState
:{
446 volatile UINT32 PwrCtrlReg
;
447 MCI_TRACE ("MciNotifyState (MmcStandByState)");
449 // Enable MCICMD push-pull drive
450 PwrCtrlReg
= MmioRead32 (MCI_POWER_CONTROL_REG
);
451 //Disable Open Drain output
452 PwrCtrlReg
&= ~ (MCI_POWER_OPENDRAIN
);
453 MmioWrite32 (MCI_POWER_CONTROL_REG
, PwrCtrlReg
);
455 // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)
457 // Note: Increasing clock speed causes TX FIFO under-run errors.
458 // So careful when optimising this driver for higher performance.
460 MmioWrite32(MCI_CLOCK_CONTROL_REG
,0x02 | MCI_CLOCK_ENABLE
| MCI_CLOCK_POWERSAVE
);
461 // Set MMCI0 clock to 24MHz (by bypassing the divider)
462 //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);
465 case MmcTransferState
:
466 //MCI_TRACE ("MciNotifyState(MmcTransferState)");
468 case MmcSendingDataState
:
469 MCI_TRACE ("MciNotifyState(MmcSendingDataState)");
471 case MmcReceiveDataState
:
472 MCI_TRACE ("MciNotifyState(MmcReceiveDataState)");
474 case MmcProgrammingState
:
475 MCI_TRACE ("MciNotifyState(MmcProgrammingState)");
477 case MmcDisconnectState
:
478 MCI_TRACE ("MciNotifyState(MmcDisconnectState)");
486 EFI_GUID mPL180MciDevicePathGuid
= EFI_CALLER_ID_GUID
;
490 IN EFI_MMC_HOST_PROTOCOL
*This
,
491 IN EFI_DEVICE_PATH_PROTOCOL
**DevicePath
494 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePathNode
;
496 NewDevicePathNode
= CreateDeviceNode (HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, sizeof (VENDOR_DEVICE_PATH
));
497 CopyGuid (& ((VENDOR_DEVICE_PATH
*)NewDevicePathNode
)->Guid
, &mPL180MciDevicePathGuid
);
499 *DevicePath
= NewDevicePathNode
;
503 EFI_MMC_HOST_PROTOCOL gMciHost
= {
504 MMC_HOST_PROTOCOL_REVISION
,
516 PL180MciDxeInitialize (
517 IN EFI_HANDLE ImageHandle
,
518 IN EFI_SYSTEM_TABLE
*SystemTable
524 DEBUG ((EFI_D_WARN
, "Probing ID registers at 0x%lx for a PL180\n",
525 MCI_PERIPH_ID_REG0
));
527 // Check if this is a PL180
528 if (MmioRead8 (MCI_PERIPH_ID_REG0
) != MCI_PERIPH_ID0
||
529 MmioRead8 (MCI_PERIPH_ID_REG1
) != MCI_PERIPH_ID1
||
530 MmioRead8 (MCI_PERIPH_ID_REG2
) != MCI_PERIPH_ID2
||
531 MmioRead8 (MCI_PCELL_ID_REG0
) != MCI_PCELL_ID0
||
532 MmioRead8 (MCI_PCELL_ID_REG1
) != MCI_PCELL_ID1
||
533 MmioRead8 (MCI_PCELL_ID_REG2
) != MCI_PCELL_ID2
||
534 MmioRead8 (MCI_PCELL_ID_REG3
) != MCI_PCELL_ID3
) {
536 DEBUG ((EFI_D_WARN
, "Probing ID registers at 0x%lx for a PL180"
537 " failed\n", MCI_PERIPH_ID_REG0
));
538 return EFI_NOT_FOUND
;
543 MCI_TRACE ("PL180MciDxeInitialize()");
545 //Publish Component Name, BlockIO protocol interfaces
546 Status
= gBS
->InstallMultipleProtocolInterfaces (
548 &gEfiMmcHostProtocolGuid
, &gMciHost
,
551 ASSERT_EFI_ERROR (Status
);