--- /dev/null
+/** @file\r
+\r
+The SD host controller driver model and HC protocol routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#include "SDController.h"\r
+\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding = {\r
+ SDControllerSupported,\r
+ SDControllerStart,\r
+ SDControllerStop,\r
+ 0x20,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+\r
+EFI_SD_HOST_IO_PROTOCOL mSDHostIo = {\r
+ EFI_SD_HOST_IO_PROTOCOL_REVISION_01,\r
+ {\r
+ 0, // HighSpeedSupport\r
+ 0, // V18Support\r
+ 0, // V30Support\r
+ 0, // V33Support\r
+ 0, // Reserved0\r
+ 0, // BusWidth4\r
+ 0, // BusWidth8\r
+ 0, // Reserved1\r
+ 0, // Reserved1\r
+ (512 * 1024) //BoundarySize\r
+ },\r
+ SendCommand,\r
+ SetClockFrequency,\r
+ SetBusWidth,\r
+ SetHostVoltage,\r
+ ResetSDHost,\r
+ EnableAutoStopCmd,\r
+ DetectCardAndInitHost,\r
+ SetBlockLength,\r
+ SetHighSpeedMode,\r
+ SetDDRMode\r
+};\r
+\r
+/**\r
+ Find sdclk_freq_sel and upr_sdclk_freq_sel bits\r
+ for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit\r
+ divided clock mode.\r
+\r
+ @param BaseClockFreg Base Clock Frequency in Hz For SD Clock in the\r
+ Capabilities register.\r
+ @param TargetFreq Target Frequency in Hz to reach.\r
+ @param Is8BitMode True if 8-bit Divided Clock Mode else 10bit mode.\r
+ @param Bits sdclk_freq_sel and upr_sdclk_freq_sel bits for\r
+ TargetFreq.\r
+\r
+ @return EFI_SUCCESS // Bits setup.\r
+ @return EFI_UNSUPPORTED // Cannot divide base clock to reach target clock.\r
+**/\r
+EFI_STATUS\r
+DividedClockModeBits (\r
+ IN CONST UINTN BaseClockFreg,\r
+ IN CONST UINTN TargetFreq,\r
+ IN CONST BOOLEAN Is8BitMode,\r
+ OUT UINT16 *Bits\r
+ )\r
+{\r
+ UINTN N;\r
+ UINTN CurrFreq;\r
+\r
+ *Bits = 0;\r
+ CurrFreq = BaseClockFreg;\r
+ N = 0;\r
+ //\r
+ // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.\r
+ //\r
+ if (TargetFreq < CurrFreq) {\r
+ if (Is8BitMode) {\r
+ N = 1;\r
+ do {\r
+ //\r
+ // N values for 8bit mode when N > 0.\r
+ // Bit[15:8] SDCLK Frequency Select at offset 2Ch\r
+ // 80h - base clock divided by 256\r
+ // 40h - base clock divided by 128\r
+ // 20h - base clock divided by 64\r
+ // 10h - base clock divided by 32\r
+ // 08h - base clock divided by 16\r
+ // 04h - base clock divided by 8\r
+ // 02h - base clock divided by 4\r
+ // 01h - base clock divided by 2\r
+ //\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ if (TargetFreq >= CurrFreq) {\r
+ break;\r
+ }\r
+ N *= 2;\r
+ if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ } while (TRUE);\r
+ } else {\r
+ N = 1;\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ //\r
+ // (try N = 0 or 1 first since don't want divide by 0).\r
+ //\r
+ if (TargetFreq < CurrFreq) {\r
+ //\r
+ // If still no match then calculate it for 10bit.\r
+ // N values for 10bit mode.\r
+ // N 1/2N Divided Clock (Duty 50%).\r
+ // from Spec "The length of divider is extended to 10 bits and all\r
+ // divider values shall be supported.\r
+ //\r
+ N = (BaseClockFreg / TargetFreq) / 2;\r
+\r
+ //\r
+ // Can only be N or N+1;\r
+ //\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ if (TargetFreq < CurrFreq) {\r
+ N++;\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ }\r
+\r
+ if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).\r
+ //\r
+ *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).\r
+ //\r
+ *Bits |= ((UINT16) ((UINT8) N) << 8);\r
+ DEBUG (\r
+ (EFI_D_INFO,\r
+ "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",\r
+ (Is8BitMode) ? 8 : 10,\r
+ TargetFreq,\r
+ CurrFreq,\r
+ (UINTN) *Bits\r
+ ));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Print type of error and command index\r
+\r
+ @param CommandIndex Command index to set the command index field of command register.\r
+ @param ErrorCode Error interrupt status read from host controller\r
+\r
+ @return EFI_DEVICE_ERROR\r
+ @return EFI_TIMEOUT\r
+ @return EFI_CRC_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+GetErrorReason (\r
+ IN UINT16 CommandIndex,\r
+ IN UINT16 ErrorCode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ DEBUG((EFI_D_ERROR, "[%2d] -- ", CommandIndex));\r
+\r
+ if (ErrorCode & BIT0) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG((EFI_D_ERROR, "Command Timeout Erro"));\r
+ }\r
+\r
+ if (ErrorCode & BIT1) {\r
+ Status = EFI_CRC_ERROR;\r
+ DEBUG((EFI_D_ERROR, "Command CRC Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT2) {\r
+ DEBUG((EFI_D_ERROR, "Command End Bit Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT3) {\r
+ DEBUG((EFI_D_ERROR, "Command Index Error"));\r
+ }\r
+ if (ErrorCode & BIT4) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG((EFI_D_ERROR, "Data Timeout Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT5) {\r
+ Status = EFI_CRC_ERROR;\r
+ DEBUG((EFI_D_ERROR, "Data CRC Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT6) {\r
+ DEBUG((EFI_D_ERROR, "Data End Bit Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT7) {\r
+ DEBUG((EFI_D_ERROR, "Current Limit Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT8) {\r
+ DEBUG((EFI_D_ERROR, "Auto CMD12 Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT9) {\r
+ DEBUG((EFI_D_ERROR, "ADMA Error"));\r
+ }\r
+\r
+ DEBUG((EFI_D_ERROR, "\n"));\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Enable/Disable High Speed transfer mode\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to Enable, FALSE to Disable\r
+\r
+ @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+SetHighSpeedMode (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ UINT32 Data;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (Enable) {\r
+ if (PcdGetBool(PcdSdHciQuirkNoHiSpd)) {\r
+ DEBUG ((EFI_D_INFO, "SDIO: Quirk never set High Speed Enable bit\r\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));\r
+ Data |= BIT2;\r
+ } else {\r
+ Data &= ~BIT2;\r
+ }\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+EFI_STATUS\r
+EFIAPI\r
+SetDDRMode (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ UINT16 Data;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL2,\r
+ 1,\r
+ &Data\r
+ );\r
+ Data &= 0xFFF0;\r
+ if (Enable) {\r
+ Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400\r
+ Data |= BIT3; // Enable 1.8V Signaling\r
+ }\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL2,\r
+ 1,\r
+ &Data\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Power on/off the LED associated with the slot\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to set LED on, FALSE to set LED off\r
+\r
+ @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+HostLEDEnable (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 Data;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (Enable) {\r
+ //\r
+ //LED On\r
+ //\r
+ Data |= BIT0;\r
+ } else {\r
+ //\r
+ //LED Off\r
+ //\r
+ Data &= ~BIT0;\r
+ }\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ The main function used to send the command to the card inserted into the SD host slot.\r
+ It will assemble the arguments to set the command register and wait for the command\r
+ and transfer completed until timeout. Then it will read the response register to fill\r
+ the ResponseData.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_OUT_OF_RESOURCES\r
+ @retval EFI_TIMEOUT\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SendCommand (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData OPTIONAL\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ The main function used to send the command to the card inserted into the SD host\r
+ slot.\r
+ It will assemble the arguments to set the command register and wait for the command\r
+ and transfer completed until timeout. Then it will read the response register to fill\r
+ the ResponseData\r
+\r
+ Arguments:\r
+ This - Pointer to EFI_SD_HOST_IO_PROTOCOL\r
+ CommandIndex - The command index to set the command index field of command register\r
+ Argument - Command argument to set the argument field of command register\r
+ DataType - TRANSFER_TYPE, indicates no data, data in or data out\r
+ Buffer - Contains the data read from / write to the device\r
+ BufferSize - The size of the buffer\r
+ ResponseType - RESPONSE_TYPE\r
+ TimeOut - Time out value in 1 ms unit\r
+ ResponseData - Depending on the ResponseType, such as CSD or card status\r
+\r
+ Returns:\r
+ EFI_SUCCESS\r
+ EFI_INVALID_PARAMETER\r
+ EFI_OUT_OF_RESOURCES\r
+ EFI_TIMEOUT\r
+ EFI_DEVICE_ERROR\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 ResponseDataCount;\r
+ UINT32 Data;\r
+ UINT64 Data64;\r
+ UINT8 Index;\r
+ INTN TimeOut2;\r
+ BOOLEAN AutoCMD12Enable = FALSE;\r
+\r
+\r
+ Status = EFI_SUCCESS;\r
+ ResponseDataCount = 1;\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ AutoCMD12Enable = (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;\r
+ CommandIndex = CommandIndex & CMD_INDEX_MASK;\r
+\r
+ if (Buffer != NULL && DataType == NoData) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ if (((UINTN)Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN)NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));\r
+ //\r
+ TimeOut2 = 1000; // 10 ms\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_PSTATE,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (10);\r
+ }while ((TimeOut2-- > 0) && (Data & BIT0));\r
+ TimeOut2 = 1000; // 10 ms\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_PSTATE,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (10);\r
+ }while ((TimeOut2-- > 0) && (Data & BIT1));\r
+ //Clear status bits\r
+ //\r
+ Data = 0xFFFF;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_NINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ Data = 0xFFFF;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ if (Buffer != NULL) {\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_DMAADR,\r
+ 1,\r
+ &Buffer\r
+ );\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKSZ,\r
+ 1,\r
+ &Data\r
+ );\r
+ Data &= ~(0xFFF);\r
+ if (BufferSize <= SDHostData->BlockLength) {\r
+ Data |= (BufferSize | 0x7000);\r
+ } else {\r
+ Data |= (SDHostData->BlockLength | 0x7000);\r
+ }\r
+\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKSZ,\r
+ 1,\r
+ &Data\r
+ );\r
+ if (BufferSize <= SDHostData->BlockLength) {\r
+ Data = 1;\r
+ } else {\r
+ Data = BufferSize / SDHostData->BlockLength;\r
+ }\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKCNT,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ } else {\r
+ Data = 0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKSZ,\r
+ 1,\r
+ &Data\r
+ );\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKCNT,\r
+ 1,\r
+ &Data\r
+ );\r
+ }\r
+\r
+ //\r
+ //Argument\r
+ //\r
+ Data = Argument;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_CMDARG,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_XFRMODE,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ DEBUG ((EFI_D_INFO, "Transfer mode read = 0x%x \r\n", (Data & 0xFFFF)));\r
+ //\r
+ //BIT0 - DMA Enable\r
+ //BIT2 - Auto Cmd12\r
+ //\r
+ if (DataType == InData) {\r
+ Data |= BIT4 | BIT0;\r
+ } else if (DataType == OutData){\r
+ Data &= ~BIT4;\r
+ Data |= BIT0;\r
+ } else {\r
+ Data &= ~(BIT4 | BIT0);\r
+ }\r
+\r
+ if (BufferSize <= SDHostData->BlockLength) {\r
+ Data &= ~ (BIT5 | BIT1 | BIT2);\r
+ Data |= BIT1; // Enable block count always\r
+ } else {\r
+ if (SDHostData->IsAutoStopCmd && AutoCMD12Enable) {\r
+ Data |= (BIT5 | BIT1 | BIT2);\r
+ } else {\r
+ Data |= (BIT5 | BIT1);\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_XFRMODE,\r
+ 1,\r
+ &Data\r
+ );\r
+ //\r
+ //Command\r
+ //\r
+ //ResponseTypeSelect IndexCheck CRCCheck ResponseType\r
+ // 00 0 0 NoResponse\r
+ // 01 0 1 R2\r
+ // 10 0 0 R3, R4\r
+ // 10 1 1 R1, R5, R6, R7\r
+ // 11 1 1 R1b, R5b\r
+ //\r
+ switch (ResponseType) {\r
+ case ResponseNo:\r
+ Data = (CommandIndex << 8);\r
+ ResponseDataCount = 0;\r
+ break;\r
+\r
+ case ResponseR1:\r
+ case ResponseR5:\r
+ case ResponseR6:\r
+ case ResponseR7:\r
+ Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;\r
+ ResponseDataCount = 1;\r
+ break;\r
+\r
+ case ResponseR1b:\r
+ case ResponseR5b:\r
+ Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;\r
+ ResponseDataCount = 1;\r
+ break;\r
+\r
+ case ResponseR2:\r
+ Data = (CommandIndex << 8) | BIT0 | BIT3;\r
+ ResponseDataCount = 4;\r
+ break;\r
+\r
+ case ResponseR3:\r
+ case ResponseR4:\r
+ Data = (CommandIndex << 8) | BIT1;\r
+ ResponseDataCount = 1;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (0);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ if (DataType != NoData) {\r
+ Data |= BIT5;\r
+ }\r
+\r
+ HostLEDEnable (This, TRUE);\r
+\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_SDCMD,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ Data = 0;\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if ((Data & 0x07FF) != 0) {\r
+ Status = GetErrorReason (CommandIndex, (UINT16)Data);\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_NINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if ((Data & BIT0) == BIT0) {\r
+ //\r
+ //Command completed, can read response\r
+ //\r
+ if (DataType == NoData) {\r
+ break;\r
+ } else {\r
+ //\r
+ //Transfer completed\r
+ //\r
+ if ((Data & BIT1) == BIT1) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ gBS->Stall (1 * 1000);\r
+\r
+ TimeOut --;\r
+\r
+ } while (TimeOut > 0);\r
+\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ if (ResponseData != NULL) {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_RESP,\r
+ ResponseDataCount,\r
+ ResponseData\r
+ );\r
+ if (ResponseType == ResponseR2) {\r
+ //\r
+ // Adjustment for R2 response\r
+ //\r
+ Data = 1;\r
+ for (Index = 0; Index < ResponseDataCount; Index++) {\r
+ Data64 = LShiftU64(*ResponseData, 8);\r
+ *ResponseData = (UINT32)((Data64 & 0xFFFFFFFF) | Data);\r
+ Data = (UINT32)RShiftU64 (Data64, 32);\r
+ ResponseData++;\r
+ }\r
+ }\r
+ }\r
+\r
+Exit:\r
+ HostLEDEnable (This, FALSE);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.\r
+ It depends on the max frequency the host can support, divider, and host speed mode.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param MaxFrequency Max frequency in HZ.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetClockFrequency (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 MaxFrequency\r
+ )\r
+{\r
+ UINT32 Data;\r
+ UINT16 FreqSelBits;\r
+ EFI_STATUS Status;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 TimeOutCount;\r
+ UINT32 Revision;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Data = 0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_CTRLRVER,\r
+ 1,\r
+ &Revision\r
+ );\r
+ Revision &= 0x000000FF;\r
+\r
+ Status = DividedClockModeBits (\r
+ SDHostData->BaseClockInMHz * 1000 * 1000,\r
+ MaxFrequency,\r
+ (Revision < SDHCI_SPEC_300),\r
+ &FreqSelBits\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Cannot reach MaxFrequency with SDHostData->BaseClockInMHz.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+ }\r
+\r
+ Data = 0;\r
+\r
+ //\r
+ //Enable internal clock and Stop Clock Enable\r
+ //\r
+ Data = BIT0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ TimeOutCount = TIME_OUT_1S;\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (1 * 1000);\r
+ TimeOutCount --;\r
+ if (TimeOutCount == 0) {\r
+ DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+ } while ((Data & BIT1) != BIT1);\r
+\r
+ DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SDHostData->BaseClockInMHz));\r
+\r
+ Data = (BIT0 | ((UINT32) FreqSelBits));\r
+ DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ TimeOutCount = TIME_OUT_1S;\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (1 * 1000);\r
+ TimeOutCount --;\r
+ if (TimeOutCount == 0) {\r
+ DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+ } while ((Data & BIT1) != BIT1);\r
+ gBS->Stall (20 * 1000);\r
+ Data |= BIT2;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set bus width of the host controller\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BusWidth Bus width in 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBusWidth (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BusWidth\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT8 Data;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+\r
+ if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {\r
+ DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((SDHostData->SDHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {\r
+ DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PciIo = SDHostData->PciIo;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ //\r
+ // BIT5 8-bit MMC Support (MMC8):\r
+ // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature\r
+ //\r
+ if (BusWidth == 8) {\r
+ DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));\r
+ Data |= BIT5;\r
+ } else if (BusWidth == 4) {\r
+ DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));\r
+ Data &= ~BIT5;\r
+ Data |= BIT1;\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));\r
+ Data &= ~BIT5;\r
+ Data &= ~BIT1;\r
+ }\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Set voltage which could supported by the host controller.\r
+ Support 0(Power off the host), 1.8V, 3.0V, 3.3V\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Voltage Units in 0.1 V.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetHostVoltage (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 Voltage\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT8 Data;\r
+ EFI_STATUS Status;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Status = EFI_SUCCESS;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_PWRCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (Voltage == 0) {\r
+ //\r
+ //Power Off the host\r
+ //\r
+ Data &= ~BIT0;\r
+ } else if (Voltage <= 18 && This->HostCapability.V18Support) {\r
+ //\r
+ //1.8V\r
+ //\r
+ Data |= (BIT1 | BIT3 | BIT0);\r
+ } else if (Voltage > 18 && Voltage <= 30 && This->HostCapability.V30Support) {\r
+ //\r
+ //3.0V\r
+ //\r
+ Data |= (BIT2 | BIT3 | BIT0);\r
+ } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {\r
+ //\r
+ //3.3V\r
+ //\r
+ Data |= (BIT1 | BIT2 | BIT3 | BIT0);\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Exit;\r
+ }\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_PWRCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (10 * 1000);\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Reset the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param ResetAll TRUE to reset all.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ResetSDHost (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN RESET_TYPE ResetType\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 Data;\r
+ UINT16 ErrStatus;\r
+ UINT32 Mask;\r
+ UINT32 TimeOutCount;\r
+ UINT16 SaveClkCtl;\r
+ UINT16 ZeroClkCtl;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Mask = 0;\r
+ ErrStatus = 0;\r
+\r
+ if (ResetType == Reset_Auto) {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTSTS,\r
+ 1,\r
+ &ErrStatus\r
+ );\r
+ if ((ErrStatus & 0xF) != 0) {\r
+ //\r
+ //Command Line\r
+ //\r
+ Mask |= BIT1;\r
+ }\r
+ if ((ErrStatus & 0x70) != 0) {\r
+ //\r
+ //Data Line\r
+ //\r
+ Mask |= BIT2;\r
+ }\r
+ }\r
+\r
+\r
+ if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {\r
+ Mask |= BIT2;\r
+ }\r
+ if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {\r
+ Mask |= BIT1;\r
+ }\r
+ if (ResetType == Reset_All) {\r
+ Mask = BIT0;\r
+ }\r
+\r
+ if (Mask == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // To improve SD stability, we zero the MMIO_CLKCTL register and\r
+ // stall for 50 microseconds before reseting the controller. We\r
+ // restore the register setting following the reset operation.\r
+ //\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &SaveClkCtl\r
+ );\r
+\r
+ ZeroClkCtl = (UINT16) 0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &ZeroClkCtl\r
+ );\r
+\r
+ gBS->Stall (50);\r
+\r
+ //\r
+ // Reset the SD host controller\r
+ //\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_SWRST,\r
+ 1,\r
+ &Mask\r
+ );\r
+\r
+ Data = 0;\r
+ TimeOutCount = TIME_OUT_1S;\r
+ do {\r
+\r
+ gBS->Stall (1 * 1000);\r
+\r
+ TimeOutCount --;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_SWRST,\r
+ 1,\r
+ &Data\r
+ );\r
+ if ((Data & Mask) == 0) {\r
+ break;\r
+ }\r
+ } while (TimeOutCount > 0);\r
+\r
+ //\r
+ // We now restore the MMIO_CLKCTL register which we set to 0 above.\r
+ //\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &SaveClkCtl\r
+ );\r
+\r
+ if (TimeOutCount == 0) {\r
+ DEBUG ((EFI_D_ERROR, "ResetSDHost: Time out \r\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Enable auto stop on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to enable, FALSE to disable.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableAutoStopCmd (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+ SDHostData->IsAutoStopCmd = Enable;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set the Block length on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BlockLength card supportes block length.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBlockLength (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BlockLength\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+ DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));\r
+ SDHostData->BlockLength = BlockLength;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Find whether these is a card inserted into the slot. If so init the host.\r
+ If not, return EFI_NOT_FOUND.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_NOT_FOUND\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DetectCardAndInitHost (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+ UINT8 Voltages[] = { 33, 30, 18 };\r
+ UINTN Loop;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ Data = 0;\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_PSTATE,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {\r
+ //\r
+ // Has no card inserted\r
+ //\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));\r
+ Status = EFI_NOT_FOUND;\r
+ goto Exit;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ for (Loop = 0; Loop < sizeof (Voltages); Loop++) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",\r
+ Voltages[Loop] / 10,\r
+ Voltages[Loop] % 10\r
+ ));\r
+ Status = SetHostVoltage (This, Voltages[Loop]);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));\r
+ break;\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ Status = SetClockFrequency (This, FREQUENCY_OD);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));\r
+ goto Exit;\r
+ }\r
+ SetBusWidth (This, 1);\r
+\r
+ //\r
+ //Enable normal status change\r
+ //\r
+\r
+ Data = (BIT0 | BIT1);\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_NINTEN,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ //\r
+ //Enable error status change\r
+ //\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTEN,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTEN,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ //\r
+ //Data transfer Timeout control\r
+ //\r
+ Data = 0x0E;\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_TOCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ //\r
+ //Set Default Bus width as 1 bit\r
+ //\r
+\r
+Exit:\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ Entry point for EFI drivers.\r
+\r
+ @param ImageHandle EFI_HANDLE.\r
+ @param SystemTable EFI_SYSTEM_TABLE.\r
+\r
+ @retval EFI_SUCCESS Driver is successfully loaded.\r
+ @return Others Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSDController (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSDControllerDriverBinding,\r
+ ImageHandle,\r
+ &gSDControllerName,\r
+ &gSDControllerName2\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has SDHostIoProtocol installed will be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @return EFI_SUCCESS This driver supports this device.\r
+ @return EFI_UNSUPPORTED This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS OpenStatus;\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ PCI_CLASSC PciClass;\r
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ (VOID **)&SdHostIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ //\r
+ // Test whether there is PCI IO Protocol attached on the controller handle.\r
+ //\r
+ OpenStatus = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (OpenStatus)) {\r
+ return OpenStatus;\r
+ }\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ PCI_CLASSCODE_OFFSET,\r
+ sizeof (PCI_CLASSC) / sizeof (UINT8),\r
+ &PciClass\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Test whether the controller belongs to SD type\r
+ //\r
+ if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||\r
+ (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||\r
+ ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))\r
+ ) {\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Starting the SD Host Controller Driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ SDHOST_DATA *SDHostData;\r
+ UINT32 Data;\r
+\r
+\r
+ SDHostData = NULL;\r
+ Data = 0;\r
+\r
+ //\r
+ // Open PCI I/O Protocol and save pointer to open protocol\r
+ // in private data area.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Enable the SD Host Controller MMIO space\r
+ //\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_DEVICE_ENABLE,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ SDHostData = (SDHOST_DATA*)AllocateZeroPool(sizeof (SDHOST_DATA));\r
+ if (SDHostData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ SDHostData->Signature = SDHOST_DATA_SIGNATURE;\r
+ SDHostData->PciIo = PciIo;\r
+\r
+ CopyMem (&SDHostData->SDHostIo, &mSDHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));\r
+\r
+ ResetSDHost (&SDHostData->SDHostIo, Reset_All);\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CTRLRVER,\r
+ 1,\r
+ &Data\r
+ );\r
+ SDHostData->SDHostIo.HostCapability.HostVersion = Data & 0xFF;\r
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SDHostData->SDHostIo.HostCapability.HostVersion));\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_CAP,\r
+ 1,\r
+ &Data\r
+ );\r
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));\r
+ if ((Data & BIT18) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.BusWidth8 = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT21) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.HighSpeedSupport = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT24) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.V33Support = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT25) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.V30Support = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT26) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.V18Support = TRUE;\r
+ }\r
+\r
+ SDHostData->SDHostIo.HostCapability.BusWidth4 = TRUE;\r
+\r
+ if(SDHostData->SDHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {\r
+\r
+\r
+\r
+ SDHostData->BaseClockInMHz = (Data >> 8) & 0x3F;\r
+ }\r
+ else {\r
+ SDHostData->BaseClockInMHz = (Data >> 8) & 0xFF;\r
+\r
+ }\r
+\r
+ SDHostData->BlockLength = 512 << ((Data >> 16) & 0x03);\r
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SDHostData->BlockLength));\r
+ SDHostData->IsAutoStopCmd = TRUE;\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &SDHostData->SDHostIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Install the component name protocol\r
+ //\r
+ SDHostData->ControllerNameTable = NULL;\r
+\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gSDControllerName.SupportedLanguages,\r
+ &SDHostData->ControllerNameTable,\r
+ L"SD Host Controller",\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gSDControllerName2.SupportedLanguages,\r
+ &SDHostData->ControllerNameTable,\r
+ L"SD Host Controller",\r
+ FALSE\r
+ );\r
+\r
+Exit:\r
+ if (EFI_ERROR (Status)) {\r
+ if (SDHostData != NULL) {\r
+ FreePool (SDHostData);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
+ @param ChildHandleBuffer List of handles for the children we need to stop.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SDHOST_DATA *SDHostData;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ (VOID **) &SDHostIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ //\r
+ // Test whether the Controller handler passed in is a valid\r
+ // Usb controller handle that should be supported, if not,\r
+ // return the error status directly\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SetHostVoltage (SDHostIo, 0);\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo);\r
+\r
+ //\r
+ // Uninstall Block I/O protocol from the device handle\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ SDHostIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FreeUnicodeStringTable (SDHostData->ControllerNameTable);\r
+\r
+ FreePool (SDHostData);\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r