-/** @file
-*
-* Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
-* Copyright (c) 2011, ARM Limited. All rights reserved.
-*
-* This program and the accompanying materials
-* are licensed and made available under the terms and conditions of the BSD License
-* which accompanies this distribution. The full text of the license may be found at
-* http://opensource.org/licenses/bsd-license.php
-*
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-*
-**/
-
-#include "MmcHostDxe.h"
-
-EMBEDDED_EXTERNAL_DEVICE *gTPS65950;
-UINT8 MaxDataTransferRate = 0;
-UINT32 Rca = 0;
-BOOLEAN BitModeSet = FALSE;
-
-
-typedef struct {
- VENDOR_DEVICE_PATH Mmc;
- EFI_DEVICE_PATH End;
-} MMCHS_DEVICE_PATH;
-
-MMCHS_DEVICE_PATH gMMCDevicePath = {
- {
- HARDWARE_DEVICE_PATH,
- HW_VENDOR_DP,
- (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
- (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
- 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- sizeof (EFI_DEVICE_PATH_PROTOCOL),
- 0
- }
-};
-
-BOOLEAN
-IgnoreCommand (
- UINT32 Command
- )
-{
- switch(Command) {
- case MMC_CMD12:
- return TRUE;
- case MMC_CMD13:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-UINT32
-TranslateCommand (
- UINT32 Command
- )
-{
- UINT32 Translation;
-
- switch(Command) {
- case MMC_CMD2:
- Translation = CMD2;
- break;
- case MMC_CMD3:
- Translation = CMD3;
- break;
- /*case MMC_CMD6:
- Translation = CMD6;
- break;*/
- case MMC_CMD7:
- Translation = CMD7;
- break;
- case MMC_CMD8:
- Translation = CMD8;
- break;
- case MMC_CMD9:
- Translation = CMD9;
- break;
- /*case MMC_CMD12:
- Translation = CMD12;
- break;
- case MMC_CMD13:
- Translation = CMD13;
- break;*/
- case MMC_CMD16:
- Translation = CMD16;
- break;
- case MMC_CMD17:
- Translation = 0x113A0014;//CMD17;
- break;
- case MMC_CMD24:
- Translation = CMD24 | 4;
- break;
- case MMC_CMD55:
- Translation = CMD55;
- break;
- case MMC_ACMD41:
- Translation = ACMD41;
- break;
- default:
- Translation = Command;
- }
-
- return Translation;
-}
-
-VOID
-CalculateCardCLKD (
- UINTN *ClockFrequencySelect
- )
-{
- DEBUG((EFI_D_ERROR, "CalculateCardCLKD()\n"));
- UINTN TransferRateValue = 0;
- UINTN TimeValue = 0 ;
- UINTN Frequency = 0;
-
- // For SD Cards we would need to send CMD6 to set
- // speeds abouve 25MHz. High Speed mode 50 MHz and up
-
- //Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
- switch (MaxDataTransferRate & 0x7) { // 2
- case 0:
- TransferRateValue = 100 * 1000;
- break;
-
- case 1:
- TransferRateValue = 1 * 1000 * 1000;
- break;
-
- case 2:
- TransferRateValue = 10 * 1000 * 1000;
- break;
-
- case 3:
- TransferRateValue = 100 * 1000 * 1000;
- break;
-
- default:
- DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
- ASSERT(FALSE);
- }
-
- //Calculate Time value (Bits 6:3 of TRAN_SPEED)
- switch ((MaxDataTransferRate >> 3) & 0xF) { // 6
- case 1:
- TimeValue = 10;
- break;
-
- case 2:
- TimeValue = 12;
- break;
-
- case 3:
- TimeValue = 13;
- break;
-
- case 4:
- TimeValue = 15;
- break;
-
- case 5:
- TimeValue = 20;
- break;
-
- case 6:
- TimeValue = 25;
- break;
-
- case 7:
- TimeValue = 30;
- break;
-
- case 8:
- TimeValue = 35;
- break;
-
- case 9:
- TimeValue = 40;
- break;
-
- case 10:
- TimeValue = 45;
- break;
-
- case 11:
- TimeValue = 50;
- break;
-
- case 12:
- TimeValue = 55;
- break;
-
- case 13:
- TimeValue = 60;
- break;
-
- case 14:
- TimeValue = 70;
- break;
-
- case 15:
- TimeValue = 80;
- break;
-
- default:
- DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
- ASSERT(FALSE);
- }
-
- Frequency = TransferRateValue * TimeValue/10;
-
- //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.
- *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);
-
- DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));
-}
-
-VOID
-UpdateMMCHSClkFrequency (
- UINTN NewCLKD
- )
-{
- DEBUG((EFI_D_ERROR, "UpdateMMCHSClkFrequency()\n"));
- //Set Clock enable to 0x0 to not provide the clock to the card
- MmioAnd32 (MMCHS_SYSCTL, ~CEN);
-
- //Set new clock frequency.
- MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6);
-
- //Poll till Internal Clock Stable
- while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);
-
- //Set Clock enable to 0x1 to provide the clock to the card
- MmioOr32 (MMCHS_SYSCTL, CEN);
-}
-
-EFI_STATUS
-InitializeMMCHS (
- VOID
- )
-{
- DEBUG((EFI_D_ERROR, "InitializeMMCHS()\n"));
- UINT8 Data = 0;
- EFI_STATUS Status;
-
- //Select Device group to belong to P1 device group in Power IC.
- Data = DEV_GRP_P1;
- Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);
- ASSERT_EFI_ERROR(Status);
-
- //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.
- Data = VSEL_3_00V;
- Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);
- ASSERT_EFI_ERROR(Status);
-
- //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.
- MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));
-
- // Enable WP GPIO
- MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);
-
- // Enable Card Detect
- Data = CARD_DETECT_ENABLE;
- gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);
-
-
- return Status;
-}
-
-BOOLEAN
-MMCIsCardPresent (
- VOID
- )
-{
- //DEBUG((EFI_D_ERROR, "MMCIsCardPresent()\n"));
- EFI_STATUS Status;
- UINT8 Data;
-
- //
- // Card detect is a GPIO0 on the TPS65950
- //
- Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);
- if (EFI_ERROR (Status)) {
- return FALSE;
- }
-
- return !(Data & CARD_DETECT_BIT);
-}
-
-BOOLEAN
-MMCIsReadOnly (
- VOID
- )
-{
- /* Note:
- * On our BeagleBoard the SD card WP pin is always read as TRUE.
- * Probably something wrong with GPIO configuration.
- * BeagleBoard-xM uses microSD cards so there is no write protect at all.
- * Hence commenting out SD card WP pin read status.
- */
- //return (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;
- return 0;
-
-}
-
-// TODO
-EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
-
-EFI_STATUS
-MMCBuildDevicePath (
- IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
- )
-{
- EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
-
- NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH));
- CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid);
- *DevicePath = NewDevicePathNode;
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
-MMCSendCommand (
- IN MMC_CMD MmcCmd,
- IN UINT32 Argument
- )
-{
- if (IgnoreCommand(MmcCmd))
- return EFI_SUCCESS;
-
- MmcCmd = TranslateCommand(MmcCmd);
-
- //DEBUG((EFI_D_ERROR, "MMCSendCommand(%d)\n", MmcCmd));
- UINTN MmcStatus;
- UINTN RetryCount = 0;
-
- //Check if command line is in use or not. Poll till command line is available.
- while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);
-
- //Provide the block size.
- MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);
-
- //Setting Data timeout counter value to max value.
- MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);
-
- //Clear Status register.
- MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);
-
- //Set command argument register
- MmioWrite32 (MMCHS_ARG, Argument);
-
- //TODO: fix this
- //Enable interrupt enable events to occur
- //MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);
-
- //Send a command
- MmioWrite32 (MMCHS_CMD, MmcCmd);
-
- //Check for the command status.
- while (RetryCount < MAX_RETRY_COUNT) {
- do {
- MmcStatus = MmioRead32 (MMCHS_STAT);
- } while (MmcStatus == 0);
-
- //Read status of command response
- if ((MmcStatus & ERRI) != 0) {
-
- //Perform soft-reset for mmci_cmd line.
- MmioOr32 (MMCHS_SYSCTL, SRC);
- while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
-
- //DEBUG ((EFI_D_INFO, "MmcStatus: 0x%x\n", MmcStatus));
- return EFI_DEVICE_ERROR;
- }
-
- //Check if command is completed.
- if ((MmcStatus & CC) == CC) {
- MmioWrite32 (MMCHS_STAT, CC);
- break;
- }
-
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- DEBUG((EFI_D_ERROR, "MMCSendCommand: Timeout\n"));
- return EFI_TIMEOUT;
- }
-
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
-MMCNotifyState (
- IN MMC_STATE State
- )
-{
- EFI_STATUS Status;
- UINTN freqSel;
- switch(State) {
- case MmcInvalidState:
- ASSERT(0);
- break;
- case MmcHwInitializationState:
- BitModeSet = FALSE;
-
- DEBUG((EFI_D_ERROR, "MMCHwInitializationState()\n"));
- Status = InitializeMMCHS ();
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status));
- return Status;
- }
-
- //Software reset of the MMCHS host controller.
- MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);
- gBS->Stall(1000);
- while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);
-
- //Soft reset for all.
- MmioWrite32 (MMCHS_SYSCTL, SRA);
- gBS->Stall(1000);
- while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);
-
- //Voltage capabilities initialization. Activate VS18 and VS30.
- MmioOr32 (MMCHS_CAPA, (VS30 | VS18));
-
- //Wakeup configuration
- MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);
- MmioOr32 (MMCHS_HCTL, IWE);
-
- //MMCHS Controller default initialization
- MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));
-
- MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));
-
- //Enable internal clock
- MmioOr32 (MMCHS_SYSCTL, ICE);
-
- //Set the clock frequency to 80KHz.
- UpdateMMCHSClkFrequency (CLKD_80KHZ);
-
- //Enable SD bus power.
- MmioOr32 (MMCHS_HCTL, (SDBP_ON));
-
- //Poll till SD bus power bit is set.
- while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);
-
- //Enable interrupts.
- MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |
- CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));
-
- //Controller INIT procedure start.
- MmioOr32 (MMCHS_CON, INIT);
- MmioWrite32 (MMCHS_CMD, 0x00000000);
- while (!(MmioRead32 (MMCHS_STAT) & CC));
-
- //Wait for 1 ms
- gBS->Stall(1000);
-
- //Set CC bit to 0x1 to clear the flag
- MmioOr32 (MMCHS_STAT, CC);
-
- //Retry INIT procedure.
- MmioWrite32 (MMCHS_CMD, 0x00000000);
- while (!(MmioRead32 (MMCHS_STAT) & CC));
-
- //End initialization sequence
- MmioAnd32 (MMCHS_CON, ~INIT);
-
- MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));
-
- //Change clock frequency to 400KHz to fit protocol
- UpdateMMCHSClkFrequency(CLKD_400KHZ);
-
- MmioOr32 (MMCHS_CON, OD);
- break;
- case MmcIdleState:
- break;
- case MmcReadyState:
- break;
- case MmcIdentificationState:
- break;
- case MmcStandByState:
- CalculateCardCLKD(&freqSel);
- UpdateMMCHSClkFrequency(freqSel);
- break;
- case MmcTransferState:
- if (!BitModeSet) {
- Status = MMCSendCommand (CMD55, Rca << 16);
- if (!EFI_ERROR (Status)) {
- // set device into 4-bit data bus mode
- Status = MMCSendCommand (ACMD6, 0x2);
- if (!EFI_ERROR (Status)) {
- // Set host controler into 4-bit mode
- MmioOr32 (MMCHS_HCTL, DTW_4_BIT);
- DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n"));
- BitModeSet = TRUE;
- }
- }
- }
- break;
- case MmcSendingDataState:
- break;
- case MmcReceiveDataState:
- break;
- case MmcProgrammingState:
- break;
- case MmcDisconnectState:
- default:
- ASSERT(0);
- }
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
-MMCReceiveResponse (
- IN MMC_RESPONSE_TYPE Type,
- IN UINT32* Buffer
- )
-{
- //DEBUG((EFI_D_ERROR, "MMCReceiveResponse()\n"));
- if (Buffer == NULL) {
- DEBUG((EFI_D_ERROR, "Buffer was NULL\n"));
- return EFI_INVALID_PARAMETER;
- }
-
- if (Type == MMC_RESPONSE_TYPE_R2) {
- Buffer[0] = MmioRead32 (MMCHS_RSP10);
- Buffer[1] = MmioRead32 (MMCHS_RSP32);
- Buffer[2] = MmioRead32 (MMCHS_RSP54);
- Buffer[3] = MmioRead32 (MMCHS_RSP76);
- } else {
- Buffer[0] = MmioRead32 (MMCHS_RSP10);
- }
-
- if (Type == MMC_RESPONSE_TYPE_CSD) {
- MaxDataTransferRate = Buffer[3] & 0xFF;
- } else if (Type == MMC_RESPONSE_TYPE_RCA) {
- Rca = Buffer[0] >> 16;
- }
-
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
-MMCReadBlockData (
- IN EFI_LBA Lba,
- IN UINTN Length,
- IN UINT32* Buffer
- )
-{
- //DEBUG((EFI_D_ERROR, "MMCReadBlockData(LBA: 0x%x, ", Lba));
- //DEBUG((EFI_D_ERROR, "Length: 0x%x, ", Length));
- //DEBUG((EFI_D_ERROR, "Buffer: 0x%x)\n", Buffer));
- UINTN MmcStatus;
- UINTN Count;
- UINTN RetryCount = 0;
-
- //Check controller status to make sure there is no error.
- while (RetryCount < MAX_RETRY_COUNT) {
- do {
- //Read Status.
- MmcStatus = MmioRead32 (MMCHS_STAT);
- } while(MmcStatus == 0);
-
- //Check if Buffer read ready (BRR) bit is set?
- if (MmcStatus & BRR) {
-
- //Clear BRR bit
- MmioOr32 (MMCHS_STAT, BRR);
-
- for (Count = 0; Count < Length / 4; Count++) {
- *Buffer++ = MmioRead32(MMCHS_DATA);
- }
- break;
- }
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- return EFI_TIMEOUT;
- }
-
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
-MMCWriteBlockData (
- IN EFI_LBA Lba,
- IN UINTN Length,
- IN UINT32* Buffer
- )
-{
- UINTN MmcStatus;
- UINTN Count;
- UINTN RetryCount = 0;
-
- //Check controller status to make sure there is no error.
- while (RetryCount < MAX_RETRY_COUNT) {
- do {
- //Read Status.
- MmcStatus = MmioRead32 (MMCHS_STAT);
- } while(MmcStatus == 0);
-
- //Check if Buffer write ready (BWR) bit is set?
- if (MmcStatus & BWR) {
-
- //Clear BWR bit
- MmioOr32 (MMCHS_STAT, BWR);
-
- //Write block worth of data.
- for (Count = 0; Count < Length / 4; Count++) {
- MmioWrite32 (MMCHS_DATA, *Buffer++);
- }
-
- break;
- }
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- return EFI_TIMEOUT;
- }
-
- return EFI_SUCCESS;
-}
-
-EFI_MMC_HOST_PROTOCOL gMMCHost = {
- MMCIsCardPresent,
- MMCIsReadOnly,
- MMCBuildDevicePath,
- MMCNotifyState,
- MMCSendCommand,
- MMCReceiveResponse,
- MMCReadBlockData,
- MMCWriteBlockData
-};
-
-EFI_STATUS
-MMCInitialize (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- DEBUG((EFI_D_ERROR, "MMCInitialize()\n"));
- EFI_STATUS Status;
- EFI_HANDLE Handle = NULL;
-
- Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
- ASSERT_EFI_ERROR(Status);
-
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Handle,
- &gEfiMmcHostProtocolGuid, &gMMCHost,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/** @file\r
+*\r
+* Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.\r
+* Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.\r
+*\r
+* SPDX-License-Identifier: BSD-2-Clause-Patent\r
+*\r
+**/\r
+\r
+#include "MmcHostDxe.h"\r
+\r
+EMBEDDED_EXTERNAL_DEVICE *gTPS65950;\r
+UINT8 mMaxDataTransferRate = 0;\r
+UINT32 mRca = 0;\r
+BOOLEAN mBitModeSet = FALSE;\r
+\r
+\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH Mmc;\r
+ EFI_DEVICE_PATH End;\r
+} MMCHS_DEVICE_PATH;\r
+\r
+MMCHS_DEVICE_PATH gMMCDevicePath = {\r
+ {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ { (UINT8)(sizeof(VENDOR_DEVICE_PATH)), (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) },\r
+ },\r
+ { 0xb615f1f5, 0x5088, 0x43cd, { 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 } }\r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
+ }\r
+};\r
+\r
+BOOLEAN\r
+IgnoreCommand (\r
+ UINT32 Command\r
+ )\r
+{\r
+ switch(Command) {\r
+ case MMC_CMD12:\r
+ return TRUE;\r
+ case MMC_CMD13:\r
+ return TRUE;\r
+ default:\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+UINT32\r
+TranslateCommand (\r
+ UINT32 Command\r
+ )\r
+{\r
+ UINT32 Translation;\r
+\r
+ switch(Command) {\r
+ case MMC_CMD2:\r
+ Translation = CMD2;\r
+ break;\r
+ case MMC_CMD3:\r
+ Translation = CMD3;\r
+ break;\r
+ /*case MMC_CMD6:\r
+ Translation = CMD6;\r
+ break;*/\r
+ case MMC_CMD7:\r
+ Translation = CMD7;\r
+ break;\r
+ case MMC_CMD8:\r
+ Translation = CMD8;\r
+ break;\r
+ case MMC_CMD9:\r
+ Translation = CMD9;\r
+ break;\r
+ /*case MMC_CMD12:\r
+ Translation = CMD12;\r
+ break;\r
+ case MMC_CMD13:\r
+ Translation = CMD13;\r
+ break;*/\r
+ case MMC_CMD16:\r
+ Translation = CMD16;\r
+ break;\r
+ case MMC_CMD17:\r
+ Translation = 0x113A0014;//CMD17;\r
+ break;\r
+ case MMC_CMD24:\r
+ Translation = CMD24 | 4;\r
+ break;\r
+ case MMC_CMD55:\r
+ Translation = CMD55;\r
+ break;\r
+ case MMC_ACMD41:\r
+ Translation = ACMD41;\r
+ break;\r
+ default:\r
+ Translation = Command;\r
+ }\r
+\r
+ return Translation;\r
+}\r
+\r
+VOID\r
+CalculateCardCLKD (\r
+ UINTN *ClockFrequencySelect\r
+ )\r
+{\r
+ UINTN TransferRateValue = 0;\r
+ UINTN TimeValue = 0 ;\r
+ UINTN Frequency = 0;\r
+\r
+ DEBUG ((DEBUG_BLKIO, "CalculateCardCLKD()\n"));\r
+\r
+ // For SD Cards we would need to send CMD6 to set\r
+ // speeds abouve 25MHz. High Speed mode 50 MHz and up\r
+\r
+ // Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)\r
+ switch (mMaxDataTransferRate & 0x7) { // 2\r
+ case 0:\r
+ TransferRateValue = 100 * 1000;\r
+ break;\r
+\r
+ case 1:\r
+ TransferRateValue = 1 * 1000 * 1000;\r
+ break;\r
+\r
+ case 2:\r
+ TransferRateValue = 10 * 1000 * 1000;\r
+ break;\r
+\r
+ case 3:\r
+ TransferRateValue = 100 * 1000 * 1000;\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));\r
+ ASSERT(FALSE);\r
+ return;\r
+ }\r
+\r
+ //Calculate Time value (Bits 6:3 of TRAN_SPEED)\r
+ switch ((mMaxDataTransferRate >> 3) & 0xF) { // 6\r
+ case 1:\r
+ TimeValue = 10;\r
+ break;\r
+\r
+ case 2:\r
+ TimeValue = 12;\r
+ break;\r
+\r
+ case 3:\r
+ TimeValue = 13;\r
+ break;\r
+\r
+ case 4:\r
+ TimeValue = 15;\r
+ break;\r
+\r
+ case 5:\r
+ TimeValue = 20;\r
+ break;\r
+\r
+ case 6:\r
+ TimeValue = 25;\r
+ break;\r
+\r
+ case 7:\r
+ TimeValue = 30;\r
+ break;\r
+\r
+ case 8:\r
+ TimeValue = 35;\r
+ break;\r
+\r
+ case 9:\r
+ TimeValue = 40;\r
+ break;\r
+\r
+ case 10:\r
+ TimeValue = 45;\r
+ break;\r
+\r
+ case 11:\r
+ TimeValue = 50;\r
+ break;\r
+\r
+ case 12:\r
+ TimeValue = 55;\r
+ break;\r
+\r
+ case 13:\r
+ TimeValue = 60;\r
+ break;\r
+\r
+ case 14:\r
+ TimeValue = 70;\r
+ break;\r
+\r
+ case 15:\r
+ TimeValue = 80;\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));\r
+ ASSERT(FALSE);\r
+ return;\r
+ }\r
+\r
+ Frequency = TransferRateValue * TimeValue/10;\r
+\r
+ // Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.\r
+ *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);\r
+\r
+ DEBUG ((DEBUG_BLKIO, "mMaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", mMaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));\r
+}\r
+\r
+VOID\r
+UpdateMMCHSClkFrequency (\r
+ UINTN NewCLKD\r
+ )\r
+{\r
+ DEBUG ((DEBUG_BLKIO, "UpdateMMCHSClkFrequency()\n"));\r
+\r
+ // Set Clock enable to 0x0 to not provide the clock to the card\r
+ MmioAnd32 (MMCHS_SYSCTL, ~CEN);\r
+\r
+ // Set new clock frequency.\r
+ MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6);\r
+\r
+ // Poll till Internal Clock Stable\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);\r
+\r
+ // Set Clock enable to 0x1 to provide the clock to the card\r
+ MmioOr32 (MMCHS_SYSCTL, CEN);\r
+}\r
+\r
+EFI_STATUS\r
+InitializeMMCHS (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 Data;\r
+ EFI_STATUS Status;\r
+\r
+ DEBUG ((DEBUG_BLKIO, "InitializeMMCHS()\n"));\r
+\r
+ // Select Device group to belong to P1 device group in Power IC.\r
+ Data = DEV_GRP_P1;\r
+ Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ // Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.\r
+ Data = VSEL_3_00V;\r
+ Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ // After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.\r
+ MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));\r
+\r
+ // Enable WP GPIO\r
+ MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);\r
+\r
+ // Enable Card Detect\r
+ Data = CARD_DETECT_ENABLE;\r
+ gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);\r
+\r
+ return Status;\r
+}\r
+\r
+BOOLEAN\r
+MMCIsCardPresent (\r
+ IN EFI_MMC_HOST_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Data;\r
+\r
+ //\r
+ // Card detect is a GPIO0 on the TPS65950\r
+ //\r
+ Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return !(Data & CARD_DETECT_BIT);\r
+}\r
+\r
+BOOLEAN\r
+MMCIsReadOnly (\r
+ IN EFI_MMC_HOST_PROTOCOL *This\r
+ )\r
+{\r
+ /* Note:\r
+ * On our BeagleBoard the SD card WP pin is always read as TRUE.\r
+ * Probably something wrong with GPIO configuration.\r
+ * BeagleBoard-xM uses microSD cards so there is no write protect at all.\r
+ * Hence commenting out SD card WP pin read status.\r
+ */\r
+ //return (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;\r
+ return 0;\r
+\r
+}\r
+\r
+// TODO\r
+EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;\r
+\r
+EFI_STATUS\r
+MMCBuildDevicePath (\r
+ IN EFI_MMC_HOST_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
+\r
+ NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH));\r
+ CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid);\r
+ *DevicePath = NewDevicePathNode;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+MMCSendCommand (\r
+ IN EFI_MMC_HOST_PROTOCOL *This,\r
+ IN MMC_CMD MmcCmd,\r
+ IN UINT32 Argument\r
+ )\r
+{\r
+ UINTN MmcStatus;\r
+ UINTN RetryCount = 0;\r
+\r
+ if (IgnoreCommand(MmcCmd))\r
+ return EFI_SUCCESS;\r
+\r
+ MmcCmd = TranslateCommand(MmcCmd);\r
+\r
+ //DEBUG ((EFI_D_ERROR, "MMCSendCommand(%d)\n", MmcCmd));\r
+\r
+ // Check if command line is in use or not. Poll till command line is available.\r
+ while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);\r
+\r
+ // Provide the block size.\r
+ MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);\r
+\r
+ // Setting Data timeout counter value to max value.\r
+ MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);\r
+\r
+ // Clear Status register.\r
+ MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);\r
+\r
+ // Set command argument register\r
+ MmioWrite32 (MMCHS_ARG, Argument);\r
+\r
+ //TODO: fix this\r
+ //Enable interrupt enable events to occur\r
+ //MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);\r
+\r
+ // Send a command\r
+ MmioWrite32 (MMCHS_CMD, MmcCmd);\r
+\r
+ // Check for the command status.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ do {\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while (MmcStatus == 0);\r
+\r
+ // Read status of command response\r
+ if ((MmcStatus & ERRI) != 0) {\r
+\r
+ // Perform soft-reset for mmci_cmd line.\r
+ MmioOr32 (MMCHS_SYSCTL, SRC);\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
+\r
+ //DEBUG ((EFI_D_INFO, "MmcStatus: 0x%x\n", MmcStatus));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ // Check if command is completed.\r
+ if ((MmcStatus & CC) == CC) {\r
+ MmioWrite32 (MMCHS_STAT, CC);\r
+ break;\r
+ }\r
+\r
+ RetryCount++;\r
+ }\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ DEBUG ((DEBUG_BLKIO, "MMCSendCommand: Timeout\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+MMCNotifyState (\r
+ IN EFI_MMC_HOST_PROTOCOL *This,\r
+ IN MMC_STATE State\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN FreqSel;\r
+\r
+ switch(State) {\r
+ case MmcInvalidState:\r
+ ASSERT(0);\r
+ break;\r
+ case MmcHwInitializationState:\r
+ mBitModeSet = FALSE;\r
+\r
+ DEBUG ((DEBUG_BLKIO, "MMCHwInitializationState()\n"));\r
+ Status = InitializeMMCHS ();\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_BLKIO, "Initialize MMC host controller fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ // Software reset of the MMCHS host controller.\r
+ MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);\r
+ gBS->Stall(1000);\r
+ while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);\r
+\r
+ // Soft reset for all.\r
+ MmioWrite32 (MMCHS_SYSCTL, SRA);\r
+ gBS->Stall(1000);\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);\r
+\r
+ //Voltage capabilities initialization. Activate VS18 and VS30.\r
+ MmioOr32 (MMCHS_CAPA, (VS30 | VS18));\r
+\r
+ // Wakeup configuration\r
+ MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);\r
+ MmioOr32 (MMCHS_HCTL, IWE);\r
+\r
+ // MMCHS Controller default initialization\r
+ MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));\r
+\r
+ MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));\r
+\r
+ // Enable internal clock\r
+ MmioOr32 (MMCHS_SYSCTL, ICE);\r
+\r
+ // Set the clock frequency to 80KHz.\r
+ UpdateMMCHSClkFrequency (CLKD_80KHZ);\r
+\r
+ // Enable SD bus power.\r
+ MmioOr32 (MMCHS_HCTL, (SDBP_ON));\r
+\r
+ // Poll till SD bus power bit is set.\r
+ while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);\r
+\r
+ // Enable interrupts.\r
+ MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |\r
+ CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));\r
+\r
+ // Controller INIT procedure start.\r
+ MmioOr32 (MMCHS_CON, INIT);\r
+ MmioWrite32 (MMCHS_CMD, 0x00000000);\r
+ while (!(MmioRead32 (MMCHS_STAT) & CC));\r
+\r
+ // Wait for 1 ms\r
+ gBS->Stall (1000);\r
+\r
+ // Set CC bit to 0x1 to clear the flag\r
+ MmioOr32 (MMCHS_STAT, CC);\r
+\r
+ // Retry INIT procedure.\r
+ MmioWrite32 (MMCHS_CMD, 0x00000000);\r
+ while (!(MmioRead32 (MMCHS_STAT) & CC));\r
+\r
+ // End initialization sequence\r
+ MmioAnd32 (MMCHS_CON, ~INIT);\r
+\r
+ MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));\r
+\r
+ // Change clock frequency to 400KHz to fit protocol\r
+ UpdateMMCHSClkFrequency(CLKD_400KHZ);\r
+\r
+ MmioOr32 (MMCHS_CON, OD);\r
+ break;\r
+ case MmcIdleState:\r
+ break;\r
+ case MmcReadyState:\r
+ break;\r
+ case MmcIdentificationState:\r
+ break;\r
+ case MmcStandByState:\r
+ CalculateCardCLKD (&FreqSel);\r
+ UpdateMMCHSClkFrequency (FreqSel);\r
+ break;\r
+ case MmcTransferState:\r
+ if (!mBitModeSet) {\r
+ Status = MMCSendCommand (This, CMD55, mRca << 16);\r
+ if (!EFI_ERROR (Status)) {\r
+ // Set device into 4-bit data bus mode\r
+ Status = MMCSendCommand (This, ACMD6, 0x2);\r
+ if (!EFI_ERROR (Status)) {\r
+ // Set host controler into 4-bit mode\r
+ MmioOr32 (MMCHS_HCTL, DTW_4_BIT);\r
+ DEBUG ((DEBUG_BLKIO, "SD Memory Card set to 4-bit mode\n"));\r
+ mBitModeSet = TRUE;\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ case MmcSendingDataState:\r
+ break;\r
+ case MmcReceiveDataState:\r
+ break;\r
+ case MmcProgrammingState:\r
+ break;\r
+ case MmcDisconnectState:\r
+ default:\r
+ ASSERT(0);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+MMCReceiveResponse (\r
+ IN EFI_MMC_HOST_PROTOCOL *This,\r
+ IN MMC_RESPONSE_TYPE Type,\r
+ IN UINT32* Buffer\r
+ )\r
+{\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Type == MMC_RESPONSE_TYPE_R2) {\r
+ Buffer[0] = MmioRead32 (MMCHS_RSP10);\r
+ Buffer[1] = MmioRead32 (MMCHS_RSP32);\r
+ Buffer[2] = MmioRead32 (MMCHS_RSP54);\r
+ Buffer[3] = MmioRead32 (MMCHS_RSP76);\r
+ } else {\r
+ Buffer[0] = MmioRead32 (MMCHS_RSP10);\r
+ }\r
+\r
+ if (Type == MMC_RESPONSE_TYPE_CSD) {\r
+ mMaxDataTransferRate = Buffer[3] & 0xFF;\r
+ } else if (Type == MMC_RESPONSE_TYPE_RCA) {\r
+ mRca = Buffer[0] >> 16;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+MMCReadBlockData (\r
+ IN EFI_MMC_HOST_PROTOCOL *This,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN Length,\r
+ IN UINT32* Buffer\r
+ )\r
+{\r
+ UINTN MmcStatus;\r
+ UINTN Count;\r
+ UINTN RetryCount = 0;\r
+\r
+ DEBUG ((DEBUG_BLKIO, "MMCReadBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n", Lba, Length, Buffer));\r
+\r
+ // Check controller status to make sure there is no error.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ do {\r
+ // Read Status.\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while(MmcStatus == 0);\r
+\r
+ // Check if Buffer read ready (BRR) bit is set?\r
+ if (MmcStatus & BRR) {\r
+\r
+ // Clear BRR bit\r
+ MmioOr32 (MMCHS_STAT, BRR);\r
+\r
+ for (Count = 0; Count < Length / 4; Count++) {\r
+ *Buffer++ = MmioRead32(MMCHS_DATA);\r
+ }\r
+ break;\r
+ }\r
+ RetryCount++;\r
+ }\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+MMCWriteBlockData (\r
+ IN EFI_MMC_HOST_PROTOCOL *This,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN Length,\r
+ IN UINT32* Buffer\r
+ )\r
+{\r
+ UINTN MmcStatus;\r
+ UINTN Count;\r
+ UINTN RetryCount = 0;\r
+\r
+ // Check controller status to make sure there is no error.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ do {\r
+ // Read Status.\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while(MmcStatus == 0);\r
+\r
+ // Check if Buffer write ready (BWR) bit is set?\r
+ if (MmcStatus & BWR) {\r
+\r
+ // Clear BWR bit\r
+ MmioOr32 (MMCHS_STAT, BWR);\r
+\r
+ // Write block worth of data.\r
+ for (Count = 0; Count < Length / 4; Count++) {\r
+ MmioWrite32 (MMCHS_DATA, *Buffer++);\r
+ }\r
+\r
+ break;\r
+ }\r
+ RetryCount++;\r
+ }\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_MMC_HOST_PROTOCOL gMMCHost = {\r
+ MMC_HOST_PROTOCOL_REVISION,\r
+ MMCIsCardPresent,\r
+ MMCIsReadOnly,\r
+ MMCBuildDevicePath,\r
+ MMCNotifyState,\r
+ MMCSendCommand,\r
+ MMCReceiveResponse,\r
+ MMCReadBlockData,\r
+ MMCWriteBlockData\r
+};\r
+\r
+EFI_STATUS\r
+MMCInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle = NULL;\r
+\r
+ DEBUG ((DEBUG_BLKIO, "MMCInitialize()\n"));\r
+\r
+ Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Handle,\r
+ &gEfiMmcHostProtocolGuid, &gMMCHost,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r