2 This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
4 Copyright (c) 2011-2012, ARM Limited. All rights reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/DevicePathLib.h>
13 #include <Library/BaseMemoryLib.h>
15 EFI_MMC_HOST_PROTOCOL
*gpMmcHost
;
20 #define MMCI0_BLOCKLEN 512
21 #define MMCI0_POW2_BLOCKLEN 9
22 #define MMCI0_TIMEOUT 1000
24 #define SYS_MCI_CARDIN BIT0
25 #define SYS_MCI_WPROT BIT1
32 return ((MmioRead32 (MCI_POWER_CONTROL_REG
) & MCI_POWER_ON
) == MCI_POWER_ON
);
40 MCI_TRACE ("MciInitialize()");
46 IN EFI_MMC_HOST_PROTOCOL
*This
49 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress
)) & SYS_MCI_CARDIN
);
54 IN EFI_MMC_HOST_PROTOCOL
*This
57 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress
)) & SYS_MCI_WPROT
);
60 // Convert block size to 2^n
73 Loop
= (Loop
>> 1) & 0xFFFF;
75 } while (Pow2BlockLen
&& (!(Loop
& BlockLen
)));
82 IN UINTN TransferDirection
85 // Set Data Length & Data Timer
86 MmioWrite32 (MCI_DATA_TIMER_REG
, 0xFFFFFFF);
87 MmioWrite32 (MCI_DATA_LENGTH_REG
, MMCI0_BLOCKLEN
);
90 //Note: we are using a hardcoded BlockLen (==512). If we decide to use a variable size, we could
91 // compute the pow2 of BlockLen with the above function GetPow2BlockLen ()
92 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_DMA_ENABLE
| TransferDirection
| (MMCI0_POW2_BLOCKLEN
<< 4));
94 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_DMA_ENABLE
| TransferDirection
| MCI_DATACTL_STREAM_TRANS
);
100 IN EFI_MMC_HOST_PROTOCOL
*This
,
111 RetVal
= EFI_SUCCESS
;
113 if ((MmcCmd
== MMC_CMD17
) || (MmcCmd
== MMC_CMD11
)) {
114 MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT
);
115 } else if ((MmcCmd
== MMC_CMD24
) || (MmcCmd
== MMC_CMD20
)) {
116 MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD
);
117 } else if (MmcCmd
== MMC_CMD6
) {
118 MmioWrite32 (MCI_DATA_TIMER_REG
, 0xFFFFFFF);
119 MmioWrite32 (MCI_DATA_LENGTH_REG
, 64);
121 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_CARD_TO_CONT
| GetPow2BlockLen (64));
123 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_CARD_TO_CONT
| MCI_DATACTL_STREAM_TRANS
);
125 } else if (MmcCmd
== MMC_ACMD51
) {
126 MmioWrite32 (MCI_DATA_TIMER_REG
, 0xFFFFFFF);
127 /* SCR register is 8 bytes long. */
128 MmioWrite32 (MCI_DATA_LENGTH_REG
, 8);
130 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_CARD_TO_CONT
| GetPow2BlockLen (8));
132 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_CARD_TO_CONT
| MCI_DATACTL_STREAM_TRANS
);
136 // Create Command for PL180
137 Cmd
= (MMC_GET_INDX (MmcCmd
) & INDX_MASK
) | MCI_CPSM_ENABLE
;
138 if (MmcCmd
& MMC_CMD_WAIT_RESPONSE
) {
139 Cmd
|= MCI_CPSM_WAIT_RESPONSE
;
142 if (MmcCmd
& MMC_CMD_LONG_RESPONSE
) {
143 Cmd
|= MCI_CPSM_LONG_RESPONSE
;
146 // Clear Status register static flags
147 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_CLR_ALL_STATUS
);
149 // Write to command argument register
150 MmioWrite32 (MCI_ARGUMENT_REG
, Argument
);
152 // Write to command register
153 MmioWrite32 (MCI_COMMAND_REG
, Cmd
);
155 DoneMask
= (Cmd
& MCI_CPSM_WAIT_RESPONSE
)
156 ? (MCI_STATUS_CMD_RESPEND
| MCI_STATUS_CMD_ERROR
)
157 : (MCI_STATUS_CMD_SENT
| MCI_STATUS_CMD_ERROR
);
159 Status
= MmioRead32 (MCI_STATUS_REG
);
160 } while (! (Status
& DoneMask
));
162 if ((Status
& MCI_STATUS_CMD_ERROR
)) {
163 // Clear Status register error flags
164 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_STATUS_CMD_ERROR
);
166 if ((Status
& MCI_STATUS_CMD_START_BIT_ERROR
)) {
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
));
168 RetVal
= EFI_NO_RESPONSE
;
169 } else if ((Status
& MCI_STATUS_CMD_CMDTIMEOUT
)) {
170 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
171 RetVal
= EFI_TIMEOUT
;
172 } else if ((!(MmcCmd
& MMC_CMD_NO_CRC_RESPONSE
)) && (Status
& MCI_STATUS_CMD_CMDCRCFAIL
)) {
173 // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
174 RetVal
= EFI_CRC_ERROR
;
178 // Disable Command Path
179 CmdCtrlReg
= MmioRead32 (MCI_COMMAND_REG
);
180 MmioWrite32 (MCI_COMMAND_REG
, (CmdCtrlReg
& ~MCI_CPSM_ENABLE
));
186 IN EFI_MMC_HOST_PROTOCOL
*This
,
187 IN MMC_RESPONSE_TYPE Type
,
191 if (Buffer
== NULL
) {
192 return EFI_INVALID_PARAMETER
;
195 if ( (Type
== MMC_RESPONSE_TYPE_R1
)
196 || (Type
== MMC_RESPONSE_TYPE_R1b
)
197 || (Type
== MMC_RESPONSE_TYPE_R3
)
198 || (Type
== MMC_RESPONSE_TYPE_R6
)
199 || (Type
== MMC_RESPONSE_TYPE_R7
))
201 Buffer
[0] = MmioRead32 (MCI_RESPONSE3_REG
);
202 } else if (Type
== MMC_RESPONSE_TYPE_R2
) {
203 Buffer
[0] = MmioRead32 (MCI_RESPONSE0_REG
);
204 Buffer
[1] = MmioRead32 (MCI_RESPONSE1_REG
);
205 Buffer
[2] = MmioRead32 (MCI_RESPONSE2_REG
);
206 Buffer
[3] = MmioRead32 (MCI_RESPONSE3_REG
);
214 IN EFI_MMC_HOST_PROTOCOL
*This
,
227 RetVal
= EFI_SUCCESS
;
229 // Read data from the RX FIFO
231 if (Length
< MMCI0_BLOCKLEN
) {
234 Finish
= MMCI0_BLOCKLEN
/ 4;
237 // Raise the TPL at the highest level to disable Interrupts.
238 Tpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
241 // Read the Status flags
242 Status
= MmioRead32 (MCI_STATUS_REG
);
244 // Do eight reads if possible else a single read
245 if (Status
& MCI_STATUS_CMD_RXFIFOHALFFULL
) {
246 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
248 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
250 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
252 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
254 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
256 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
258 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
260 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
262 } else if (Status
& MCI_STATUS_CMD_RXDATAAVAILBL
) {
263 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
266 //Check for error conditions and timeouts
267 if (Status
& MCI_STATUS_CMD_DATATIMEOUT
) {
268 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
269 RetVal
= EFI_TIMEOUT
;
271 } else if (Status
& MCI_STATUS_CMD_DATACRCFAIL
) {
272 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
273 RetVal
= EFI_CRC_ERROR
;
275 } else if (Status
& MCI_STATUS_CMD_START_BIT_ERROR
) {
276 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
277 RetVal
= EFI_NO_RESPONSE
;
281 //clear RX over run flag
282 if(Status
& MCI_STATUS_CMD_RXOVERRUN
) {
283 MmioWrite32(MCI_CLEAR_STATUS_REG
, MCI_STATUS_CMD_RXOVERRUN
);
285 } while ((Loop
< Finish
));
288 gBS
->RestoreTPL (Tpl
);
290 // Clear Status flags
291 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_CLR_ALL_STATUS
);
294 DataCtrlReg
= MmioRead32 (MCI_DATA_CTL_REG
);
295 MmioWrite32 (MCI_DATA_CTL_REG
, (DataCtrlReg
& MCI_DATACTL_DISABLE_MASK
));
302 IN EFI_MMC_HOST_PROTOCOL
*This
,
316 RetVal
= EFI_SUCCESS
;
318 // Write the data to the TX FIFO
320 Finish
= MMCI0_BLOCKLEN
/ 4;
321 Timer
= MMCI0_TIMEOUT
* 100;
323 // Raise the TPL at the highest level to disable Interrupts.
324 Tpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
327 // Read the Status flags
328 Status
= MmioRead32 (MCI_STATUS_REG
);
330 // Do eight writes if possible else a single write
331 if (Status
& MCI_STATUS_CMD_TXFIFOHALFEMPTY
) {
332 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
334 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
336 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
338 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
340 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
342 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
344 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
346 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
348 } else if (!(Status
& MCI_STATUS_CMD_TXFIFOFULL
)) {
349 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
352 // Check for error conditions and timeouts
353 if (Status
& MCI_STATUS_CMD_DATATIMEOUT
) {
354 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
355 RetVal
= EFI_TIMEOUT
;
357 } else if (Status
& MCI_STATUS_CMD_DATACRCFAIL
) {
358 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG
), Status
));
359 RetVal
= EFI_CRC_ERROR
;
361 } else if (Status
& MCI_STATUS_CMD_TX_UNDERRUN
) {
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
));
363 RetVal
= EFI_BUFFER_TOO_SMALL
;
368 } while (Loop
< Finish
);
371 gBS
->RestoreTPL (Tpl
);
373 // Wait for FIFO to drain
374 Timer
= MMCI0_TIMEOUT
* 60;
375 Status
= MmioRead32 (MCI_STATUS_REG
);
378 while (((Status
& MCI_STATUS_TXDONE
) != MCI_STATUS_TXDONE
) && Timer
) {
381 while (((Status
& MCI_STATUS_CMD_DATAEND
) != MCI_STATUS_CMD_DATAEND
) && Timer
) {
384 Status
= MmioRead32 (MCI_STATUS_REG
);
388 // Clear Status flags
389 MmioWrite32 (MCI_CLEAR_STATUS_REG
, MCI_CLR_ALL_STATUS
);
392 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): Data End timeout Number of words written 0x%x\n", Loop
));
393 RetVal
= EFI_TIMEOUT
;
398 DataCtrlReg
= MmioRead32 (MCI_DATA_CTL_REG
);
399 MmioWrite32 (MCI_DATA_CTL_REG
, (DataCtrlReg
& MCI_DATACTL_DISABLE_MASK
));
405 IN EFI_MMC_HOST_PROTOCOL
*This
,
412 case MmcInvalidState
:
415 case MmcHwInitializationState
:
416 // If device already turn on then restart it
417 Data32
= MmioRead32 (MCI_POWER_CONTROL_REG
);
418 if ((Data32
& 0x2) == MCI_POWER_UP
) {
419 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI");
422 MmioWrite32 (MCI_CLOCK_CONTROL_REG
, 0);
423 MmioWrite32 (MCI_POWER_CONTROL_REG
, 0);
424 MicroSecondDelay (100);
427 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI");
429 // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
430 MmioWrite32 (MCI_CLOCK_CONTROL_REG
, 0x1D | MCI_CLOCK_ENABLE
| MCI_CLOCK_POWERSAVE
);
433 MmioWrite32 (MCI_POWER_CONTROL_REG
, MCI_POWER_OPENDRAIN
| (15<<2));
434 MmioWrite32 (MCI_POWER_CONTROL_REG
, MCI_POWER_ROD
| MCI_POWER_OPENDRAIN
| (15<<2) | MCI_POWER_UP
);
435 MicroSecondDelay (10);
436 MmioWrite32 (MCI_POWER_CONTROL_REG
, MCI_POWER_ROD
| MCI_POWER_OPENDRAIN
| (15<<2) | MCI_POWER_ON
);
437 MicroSecondDelay (100);
439 // Set Data Length & Data Timer
440 MmioWrite32 (MCI_DATA_TIMER_REG
, 0xFFFFF);
441 MmioWrite32 (MCI_DATA_LENGTH_REG
, 8);
443 ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG
) & 0x3) == MCI_POWER_ON
);
446 MCI_TRACE ("MciNotifyState(MmcIdleState)");
449 MCI_TRACE ("MciNotifyState(MmcReadyState)");
451 case MmcIdentificationState
:
452 MCI_TRACE ("MciNotifyState (MmcIdentificationState)");
454 case MmcStandByState
:{
455 volatile UINT32 PwrCtrlReg
;
456 MCI_TRACE ("MciNotifyState (MmcStandByState)");
458 // Enable MCICMD push-pull drive
459 PwrCtrlReg
= MmioRead32 (MCI_POWER_CONTROL_REG
);
460 //Disable Open Drain output
461 PwrCtrlReg
&= ~ (MCI_POWER_OPENDRAIN
);
462 MmioWrite32 (MCI_POWER_CONTROL_REG
, PwrCtrlReg
);
464 // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)
466 // Note: Increasing clock speed causes TX FIFO under-run errors.
467 // So careful when optimising this driver for higher performance.
469 MmioWrite32(MCI_CLOCK_CONTROL_REG
,0x02 | MCI_CLOCK_ENABLE
| MCI_CLOCK_POWERSAVE
);
470 // Set MMCI0 clock to 24MHz (by bypassing the divider)
471 //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);
474 case MmcTransferState
:
475 //MCI_TRACE ("MciNotifyState(MmcTransferState)");
477 case MmcSendingDataState
:
478 MCI_TRACE ("MciNotifyState(MmcSendingDataState)");
480 case MmcReceiveDataState
:
481 MCI_TRACE ("MciNotifyState(MmcReceiveDataState)");
483 case MmcProgrammingState
:
484 MCI_TRACE ("MciNotifyState(MmcProgrammingState)");
486 case MmcDisconnectState
:
487 MCI_TRACE ("MciNotifyState(MmcDisconnectState)");
495 EFI_GUID mPL180MciDevicePathGuid
= EFI_CALLER_ID_GUID
;
499 IN EFI_MMC_HOST_PROTOCOL
*This
,
500 IN EFI_DEVICE_PATH_PROTOCOL
**DevicePath
503 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePathNode
;
505 NewDevicePathNode
= CreateDeviceNode (HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, sizeof (VENDOR_DEVICE_PATH
));
506 CopyGuid (& ((VENDOR_DEVICE_PATH
*)NewDevicePathNode
)->Guid
, &mPL180MciDevicePathGuid
);
508 *DevicePath
= NewDevicePathNode
;
512 EFI_MMC_HOST_PROTOCOL gMciHost
= {
513 MMC_HOST_PROTOCOL_REVISION
,
525 PL180MciDxeInitialize (
526 IN EFI_HANDLE ImageHandle
,
527 IN EFI_SYSTEM_TABLE
*SystemTable
533 DEBUG ((EFI_D_WARN
, "Probing ID registers at 0x%lx for a PL180\n",
534 MCI_PERIPH_ID_REG0
));
536 // Check if this is a PL180
537 if (MmioRead8 (MCI_PERIPH_ID_REG0
) != MCI_PERIPH_ID0
||
538 MmioRead8 (MCI_PERIPH_ID_REG1
) != MCI_PERIPH_ID1
||
539 MmioRead8 (MCI_PERIPH_ID_REG2
) != MCI_PERIPH_ID2
||
540 MmioRead8 (MCI_PCELL_ID_REG0
) != MCI_PCELL_ID0
||
541 MmioRead8 (MCI_PCELL_ID_REG1
) != MCI_PCELL_ID1
||
542 MmioRead8 (MCI_PCELL_ID_REG2
) != MCI_PCELL_ID2
||
543 MmioRead8 (MCI_PCELL_ID_REG3
) != MCI_PCELL_ID3
) {
545 DEBUG ((EFI_D_WARN
, "Probing ID registers at 0x%lx for a PL180"
546 " failed\n", MCI_PERIPH_ID_REG0
));
547 return EFI_NOT_FOUND
;
552 MCI_TRACE ("PL180MciDxeInitialize()");
554 //Publish Component Name, BlockIO protocol interfaces
555 Status
= gBS
->InstallMultipleProtocolInterfaces (
557 &gEfiMmcHostProtocolGuid
, &gMciHost
,
560 ASSERT_EFI_ERROR (Status
);