2 This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
4 Copyright (c) 2011, 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
35 return ((MmioRead32(MCI_POWER_CONTROL_REG
) & 0x3) == MCI_POWER_ON
);
43 MCI_TRACE("MciInitialize()");
49 IN EFI_MMC_HOST_PROTOCOL
*This
52 return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress
)) & 1);
57 IN EFI_MMC_HOST_PROTOCOL
*This
60 return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress
)) & 2);
64 //Note: This function has been commented out because it is not used yet.
65 // This function could be used to remove the hardcoded BlockLen used
66 // in MciPrepareDataPath
68 // Convert block size to 2^n
81 Loop
= (Loop
>> 1) & 0xFFFF;
83 } while (Pow2BlockLen
&& (!(Loop
& BlockLen
)));
91 IN UINTN TransferDirection
94 // Set Data Length & Data Timer
95 MmioWrite32 (MCI_DATA_TIMER_REG
,0xFFFFFFF);
96 MmioWrite32 (MCI_DATA_LENGTH_REG
,MMCI0_BLOCKLEN
);
99 //Note: we are using a hardcoded BlockLen (=512). If we decide to use a variable size, we could
100 // compute the pow2 of BlockLen with the above function GetPow2BlockLen()
101 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_DMA_ENABLE
| TransferDirection
| (MMCI0_POW2_BLOCKLEN
<< 4));
103 MmioWrite32 (MCI_DATA_CTL_REG
, MCI_DATACTL_ENABLE
| MCI_DATACTL_DMA_ENABLE
| TransferDirection
| MCI_DATACTL_STREAM_TRANS
);
109 IN EFI_MMC_HOST_PROTOCOL
*This
,
119 RetVal
= EFI_SUCCESS
;
121 if ((MmcCmd
== MMC_CMD17
) || (MmcCmd
== MMC_CMD11
)) {
122 MciPrepareDataPath(MCI_DATACTL_CARD_TO_CONT
);
123 } else if ((MmcCmd
== MMC_CMD24
) || (MmcCmd
== MMC_CMD20
)) {
124 MciPrepareDataPath(MCI_DATACTL_CONT_TO_CARD
);
127 // Create Command for PL180
128 Cmd
= (MMC_GET_INDX(MmcCmd
) & INDX_MASK
) | MCI_CPSM_ENABLED
;
129 if (MmcCmd
& MMC_CMD_WAIT_RESPONSE
) {
130 Cmd
|= MCI_CPSM_WAIT_RESPONSE
;
133 if (MmcCmd
& MMC_CMD_LONG_RESPONSE
) {
134 Cmd
|= MCI_CPSM_LONG_RESPONSE
;
137 // Clear Status register static flags
138 MmioWrite32(MCI_CLEAR_STATUS_REG
,0x7FF);
140 //Write to command argument register
141 MmioWrite32(MCI_ARGUMENT_REG
,Argument
);
143 //Write to command register
144 MmioWrite32(MCI_COMMAND_REG
,Cmd
);
146 if (Cmd
& MCI_CPSM_WAIT_RESPONSE
) {
147 Status
= MmioRead32(MCI_STATUS_REG
);
148 while (!(Status
& (MCI_STATUS_CMD_RESPEND
| MCI_STATUS_CMD_CMDCRCFAIL
| MCI_STATUS_CMD_CMDTIMEOUT
| MCI_STATUS_CMD_START_BIT_ERROR
))) {
149 Status
= MmioRead32(MCI_STATUS_REG
);
152 if ((Status
& MCI_STATUS_CMD_START_BIT_ERROR
)) {
153 DEBUG ((EFI_D_ERROR
, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n",(Cmd
& 0x3F),MmioRead32(MCI_RESPONSE0_REG
),Status
));
154 RetVal
= EFI_NO_RESPONSE
;
156 } else if ((Status
& MCI_STATUS_CMD_CMDTIMEOUT
)) {
157 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
158 RetVal
= EFI_TIMEOUT
;
160 } else if ((!(MmcCmd
& MMC_CMD_NO_CRC_RESPONSE
)) && (Status
& MCI_STATUS_CMD_CMDCRCFAIL
)) {
161 // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
162 RetVal
= EFI_CRC_ERROR
;
165 RetVal
= EFI_SUCCESS
;
169 Status
= MmioRead32(MCI_STATUS_REG
);
170 while (!(Status
& (MCI_STATUS_CMD_SENT
| MCI_STATUS_CMD_CMDCRCFAIL
| MCI_STATUS_CMD_CMDTIMEOUT
| MCI_STATUS_CMD_START_BIT_ERROR
))) {
171 Status
= MmioRead32(MCI_STATUS_REG
);
174 if ((Status
& MCI_STATUS_CMD_START_BIT_ERROR
)) {
175 DEBUG ((EFI_D_ERROR
, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n",(Cmd
& 0x3F),MmioRead32(MCI_RESPONSE0_REG
),Status
));
176 RetVal
= EFI_NO_RESPONSE
;
178 } else if ((Status
& MCI_STATUS_CMD_CMDTIMEOUT
)) {
179 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
180 RetVal
= EFI_TIMEOUT
;
183 if ((!(MmcCmd
& MMC_CMD_NO_CRC_RESPONSE
)) && (Status
& MCI_STATUS_CMD_CMDCRCFAIL
)) {
184 // The CMD1 does not contain CRC. We should ignore the CRC failed Status.
185 RetVal
= EFI_CRC_ERROR
;
188 RetVal
= EFI_SUCCESS
;
194 // Disable Command Path
195 CmdCtrlReg
= MmioRead32(MCI_COMMAND_REG
);
196 MmioWrite32(MCI_COMMAND_REG
, (CmdCtrlReg
& ~MCI_CPSM_ENABLED
));
202 IN EFI_MMC_HOST_PROTOCOL
*This
,
203 IN MMC_RESPONSE_TYPE Type
,
207 if (Buffer
== NULL
) {
208 return EFI_INVALID_PARAMETER
;
211 if ((Type
== MMC_RESPONSE_TYPE_R1
) || (Type
== MMC_RESPONSE_TYPE_R1b
) ||
212 (Type
== MMC_RESPONSE_TYPE_R3
) || (Type
== MMC_RESPONSE_TYPE_R6
) ||
213 (Type
== MMC_RESPONSE_TYPE_R7
))
215 Buffer
[0] = MmioRead32(MCI_RESPONSE3_REG
);
216 } else if (Type
== MMC_RESPONSE_TYPE_R2
) {
217 Buffer
[0] = MmioRead32(MCI_RESPONSE0_REG
);
218 Buffer
[1] = MmioRead32(MCI_RESPONSE1_REG
);
219 Buffer
[2] = MmioRead32(MCI_RESPONSE2_REG
);
220 Buffer
[3] = MmioRead32(MCI_RESPONSE3_REG
);
228 IN EFI_MMC_HOST_PROTOCOL
*This
,
240 RetVal
= EFI_SUCCESS
;
242 // Read data from the RX FIFO
244 Finish
= MMCI0_BLOCKLEN
/ 4;
246 // Read the Status flags
247 Status
= MmioRead32(MCI_STATUS_REG
);
249 // Do eight reads if possible else a single read
250 if (Status
& MCI_STATUS_CMD_RXFIFOHALFFULL
) {
251 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
253 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
255 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
257 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
259 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
261 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
263 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
265 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
267 } else if (Status
& MCI_STATUS_CMD_RXDATAAVAILBL
) {
268 Buffer
[Loop
] = MmioRead32(MCI_FIFO_REG
);
271 //Check for error conditions and timeouts
272 if(Status
& MCI_STATUS_CMD_DATATIMEOUT
) {
273 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG
),Status
));
274 RetVal
= EFI_TIMEOUT
;
276 } else if(Status
& MCI_STATUS_CMD_DATACRCFAIL
) {
277 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG
),Status
));
278 RetVal
= EFI_CRC_ERROR
;
280 } else if(Status
& MCI_STATUS_CMD_START_BIT_ERROR
) {
281 DEBUG ((EFI_D_ERROR
, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG
),Status
));
282 RetVal
= EFI_NO_RESPONSE
;
286 //clear RX over run flag
287 if(Status
& MCI_STATUS_CMD_RXOVERRUN
) {
288 MmioWrite32(MCI_CLEAR_STATUS_REG
, MCI_STATUS_CMD_RXOVERRUN
);
290 } while ((Loop
< Finish
));
293 MmioWrite32(MCI_CLEAR_STATUS_REG
, 0x7FF);
296 DataCtrlReg
= MmioRead32(MCI_DATA_CTL_REG
);
297 MmioWrite32(MCI_DATA_CTL_REG
, (DataCtrlReg
& 0xFE));
304 IN EFI_MMC_HOST_PROTOCOL
*This
,
317 RetVal
= EFI_SUCCESS
;
319 // Write the data to the TX FIFO
321 Finish
= MMCI0_BLOCKLEN
/ 4;
322 Timer
= MMCI0_TIMEOUT
* 100;
324 // Read the Status flags
325 Status
= MmioRead32(MCI_STATUS_REG
);
327 // Do eight writes if possible else a single write
328 if (Status
& MCI_STATUS_CMD_TXFIFOHALFEMPTY
) {
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 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
341 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
343 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
345 } else if ((Status
& MCI_STATUS_CMD_TXFIFOEMPTY
)) {
346 MmioWrite32(MCI_FIFO_REG
, Buffer
[Loop
]);
349 //Check for error conditions and timeouts
350 if(Status
& MCI_STATUS_CMD_DATATIMEOUT
) {
351 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG
),Status
));
352 RetVal
= EFI_TIMEOUT
;
354 } else if(Status
& MCI_STATUS_CMD_DATACRCFAIL
) {
355 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG
),Status
));
356 RetVal
= EFI_CRC_ERROR
;
358 } else if(Status
& MCI_STATUS_CMD_TX_UNDERRUN
) {
359 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
));
360 RetVal
= EFI_BUFFER_TOO_SMALL
;
365 } while (Loop
< Finish
);
367 // Wait for FIFO to drain
368 Timer
= MMCI0_TIMEOUT
* 60;
369 Status
= MmioRead32(MCI_STATUS_REG
);
372 while (((Status
& MCI_STATUS_CMD_TXDONE
) != MCI_STATUS_CMD_TXDONE
) && Timer
) {
375 while (((Status
& MCI_STATUS_CMD_DATAEND
) != MCI_STATUS_CMD_DATAEND
) && Timer
) {
378 Status
= MmioRead32(MCI_STATUS_REG
);
383 DEBUG ((EFI_D_ERROR
, "MciWriteBlockData(): Data End timeout Number of bytes written 0x%x\n",Loop
));
389 MmioWrite32(MCI_CLEAR_STATUS_REG
, 0x7FF);
391 RetVal
= EFI_TIMEOUT
;
396 DataCtrlReg
= MmioRead32(MCI_DATA_CTL_REG
);
397 MmioWrite32(MCI_DATA_CTL_REG
, (DataCtrlReg
& 0xFE));
403 IN EFI_MMC_HOST_PROTOCOL
*This
,
410 case MmcInvalidState
:
413 case MmcHwInitializationState
:
414 // If device already turn on then restart it
415 Data32
= MmioRead32(MCI_POWER_CONTROL_REG
);
416 if ((Data32
& 0x2) == MCI_POWER_UP
) {
417 MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOff MCI");
420 MmioWrite32(MCI_CLOCK_CONTROL_REG
, 0);
421 MmioWrite32(MCI_POWER_CONTROL_REG
, 0);
422 MicroSecondDelay(100);
425 MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOn MCI");
427 // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
428 MmioWrite32(MCI_CLOCK_CONTROL_REG
,0x1D | MCI_CLOCK_ENABLE
| MCI_CLOCK_POWERSAVE
);
429 //MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE);
432 MmioWrite32(MCI_POWER_CONTROL_REG
,MCI_POWER_OPENDRAIN
| (15<<2));
433 MmioWrite32(MCI_POWER_CONTROL_REG
,MCI_POWER_ROD
| MCI_POWER_OPENDRAIN
| (15<<2) | MCI_POWER_UP
);
434 MicroSecondDelay(10);
435 MmioWrite32(MCI_POWER_CONTROL_REG
,MCI_POWER_ROD
| MCI_POWER_OPENDRAIN
| (15<<2) | MCI_POWER_ON
);
436 MicroSecondDelay(100);
438 // Set Data Length & Data Timer
439 MmioWrite32(MCI_DATA_TIMER_REG
,0xFFFFF);
440 MmioWrite32(MCI_DATA_LENGTH_REG
,8);
442 ASSERT((MmioRead32(MCI_POWER_CONTROL_REG
) & 0x3) == MCI_POWER_ON
);
445 MCI_TRACE("MciNotifyState(MmcIdleState)");
448 MCI_TRACE("MciNotifyState(MmcReadyState)");
450 case MmcIdentificationState
:
451 MCI_TRACE("MciNotifyState(MmcIdentificationState)");
453 case MmcStandByState
:{
454 volatile UINT32 PwrCtrlReg
;
455 MCI_TRACE("MciNotifyState(MmcStandByState)");
457 // Enable MCICMD push-pull drive
458 PwrCtrlReg
= MmioRead32(MCI_POWER_CONTROL_REG
);
459 //Disable Open Drain output
460 PwrCtrlReg
&=~(MCI_POWER_OPENDRAIN
);
461 MmioWrite32(MCI_POWER_CONTROL_REG
,PwrCtrlReg
);
463 // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)
465 // Note: Increasing clock speed causes TX FIFO under-run errors.
466 // So careful when optimising this driver for higher performance.
468 MmioWrite32(MCI_CLOCK_CONTROL_REG
,0x02 | MCI_CLOCK_ENABLE
| MCI_CLOCK_POWERSAVE
);
469 // Set MMCI0 clock to 24MHz (by bypassing the divider)
470 //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);
473 case MmcTransferState
:
474 //MCI_TRACE("MciNotifyState(MmcTransferState)");
476 case MmcSendingDataState
:
477 MCI_TRACE("MciNotifyState(MmcSendingDataState)");
479 case MmcReceiveDataState
:
480 MCI_TRACE("MciNotifyState(MmcReceiveDataState)");
482 case MmcProgrammingState
:
483 MCI_TRACE("MciNotifyState(MmcProgrammingState)");
485 case MmcDisconnectState
:
486 MCI_TRACE("MciNotifyState(MmcDisconnectState)");
494 EFI_GUID mPL180MciDevicePathGuid
= EFI_CALLER_ID_GUID
;
498 IN EFI_MMC_HOST_PROTOCOL
*This
,
499 IN EFI_DEVICE_PATH_PROTOCOL
**DevicePath
502 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePathNode
;
504 NewDevicePathNode
= CreateDeviceNode(HARDWARE_DEVICE_PATH
,HW_VENDOR_DP
,sizeof(VENDOR_DEVICE_PATH
));
505 CopyGuid(&((VENDOR_DEVICE_PATH
*)NewDevicePathNode
)->Guid
,&mPL180MciDevicePathGuid
);
507 *DevicePath
= NewDevicePathNode
;
511 EFI_MMC_HOST_PROTOCOL gMciHost
= {
512 MMC_HOST_PROTOCOL_REVISION
,
524 PL180MciDxeInitialize (
525 IN EFI_HANDLE ImageHandle
,
526 IN EFI_SYSTEM_TABLE
*SystemTable
530 EFI_HANDLE Handle
= NULL
;
532 MCI_TRACE("PL180MciDxeInitialize()");
534 //Publish Component Name, BlockIO protocol interfaces
535 Status
= gBS
->InstallMultipleProtocolInterfaces (
537 &gEfiMmcHostProtocolGuid
, &gMciHost
,
540 ASSERT_EFI_ERROR (Status
);