+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2|Þa\9e'\99(O\9f=2\a\ 5Ø\18\ 1\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 2ÐÇåô9ÒËGªÍ\7ffïv28\ 2E\z\15²!ÅCº|\82/î_å\99\ 2\8e\b\97ëßÏÆI¾KÙ\ 6¥²\ e\86\ 3\ 3\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2ê³\90(=\ 5C\16\fÖH\bÚ?ñ\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2\18øAdbcDNµp}º1Ý$S\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2E\z\15²!ÅCº|\82/î_å\99\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 2A|ï[`¥[C\83[<>¿+ÑQ\ 2-ø¿Á\92lûH\83UÇûB\18¤ê\ 2OÌf©lîMB§b\8eÓµ¤¥\ 1\ 2ÿ\1d\86GoUiB\9b(\ 6.Ãì³\r\ 2\18ì\9að{ H\9e\960\120\9f=÷\ 2±èz²\10>\aM«\ë\9amÆú\8f\ 2\86\v\94Ý®\98&D\96»k¯I\84\9c×\ 2æú\1a$_\88lO§êÂ\8e«yÃå\ 3\ 3\ 3\ 3\ 3\ 3\ 3\ 3\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2tiÙ\ fª#ÜL¹Ë\98ÑwP2*\ 2rÁ\9fﲡ\93F³'m2üA`B\ 2×r~XPÌyO\82 Ê)\1fÁ¡\ f\ 3\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2tiÙ\ fª#ÜL¹Ë\98ÑwP2*\ 2rÁ\9fﲡ\93F³'m2üA`B\ 2×r~XPÌyO\82 Ê)\1fÁ¡\ f\ 3\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-#include "MMCHS.h"\r
-\r
-STATIC struct mmc_device *\r
-PlatformCallbackInitSlot(struct mmc_config_data *config)\r
-{\r
- EFI_STATUS Status;\r
- BIO_INSTANCE *Instance;\r
-\r
- // Initialize MMC device\r
- struct mmc_device *dev = mmc_init(config);\r
- if (dev == NULL) {\r
- return NULL;\r
- }\r
-\r
- // Allocate instance\r
- Status = BioInstanceContructor(&Instance);\r
- if (EFI_ERROR(Status)) {\r
- return dev;\r
- }\r
-\r
- // Set data\r
- Instance->MmcDev = dev;\r
- Instance->BlockMedia.BlockSize = dev->card.block_size;\r
- Instance->BlockMedia.LastBlock =\r
- dev->card.capacity / Instance->BlockMedia.BlockSize - 1;\r
-\r
- // Give every device a slighty different GUID\r
- Instance->DevicePath.Mmc.Guid.Data4[7] = config->slot;\r
-\r
- // Register for ExitBS event\r
- Status = gBS->CreateEventEx(\r
- EVT_NOTIFY_SIGNAL, TPL_NOTIFY, MMCHSExitBsUninit, (VOID *)Instance,\r
- &gEfiEventExitBootServicesGuid, &Instance->ExitBsEvent);\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- // Publish BlockIO\r
- Status = gBS->InstallMultipleProtocolInterfaces(\r
- &Instance->Handle, &gEfiBlockIoProtocolGuid, &Instance->BlockIo,\r
- &gEfiDevicePathProtocolGuid, &Instance->DevicePath, NULL);\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- return dev;\r
-}\r
-\r
-STATIC BIO_INSTANCE mBioTemplate = {\r
- BIO_INSTANCE_SIGNATURE,\r
- NULL, // Handle\r
- {\r
- // BlockIo\r
- EFI_BLOCK_IO_INTERFACE_REVISION, // Revision\r
- NULL, // *Media\r
- MMCHSReset, // Reset\r
- MMCHSReadBlocks, // ReadBlocks\r
- MMCHSWriteBlocks, // WriteBlocks\r
- MMCHSFlushBlocks // FlushBlocks\r
- },\r
- {\r
- // BlockMedia\r
- BIO_INSTANCE_SIGNATURE, // MediaId\r
- FALSE, // RemovableMedia\r
- TRUE, // MediaPresent\r
- FALSE, // LogicalPartition\r
- FALSE, // ReadOnly\r
- FALSE, // WriteCaching\r
- 0, // BlockSize\r
- 4, // IoAlign\r
- 0, // Pad\r
- 0 // LastBlock\r
- },\r
- {\r
- // DevicePath\r
- {\r
- {\r
- HARDWARE_DEVICE_PATH,\r
- HW_VENDOR_DP,\r
- {(UINT8)(sizeof(VENDOR_DEVICE_PATH)),\r
- (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)},\r
- },\r
- // Hardware Device Path for Bio\r
- EFI_CALLER_ID_GUID // Use the driver's GUID\r
- },\r
-\r
- {\r
- END_DEVICE_PATH_TYPE,\r
- END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
- {sizeof(EFI_DEVICE_PATH_PROTOCOL), 0},\r
- },\r
- },\r
- NULL, // MMCDev\r
- NULL, // ExitBS Event\r
-};\r
-\r
-/*\r
- * Function: mmc_write\r
- * Arg : Data address on card, data length, i/p buffer\r
- * Return : 0 on Success, non zero on failure\r
- * Flow : Write the data from in to the card\r
- */\r
-STATIC UINT32\r
-mmc_write(BIO_INSTANCE *Instance, UINT64 data_addr, UINT32 data_len, VOID *in)\r
-{\r
- UINT32 val = 0;\r
- UINT32 block_size = 0;\r
- UINT32 write_size = SDHCI_ADMA_MAX_TRANS_SZ;\r
- UINT8 *sptr = (UINT8 *)in;\r
-\r
- block_size = Instance->BlockMedia.BlockSize;\r
-\r
- ASSERT(!(data_addr % block_size));\r
-\r
- if (data_len % block_size)\r
- data_len = ROUNDUP(data_len, block_size);\r
-\r
- /*\r
- * Flush the cache before handing over the data to\r
- * storage driver\r
- */\r
- arch_clean_invalidate_cache_range((addr_t)in, data_len);\r
-\r
- /* TODO: This function is aware of max data that can be\r
- * tranferred using sdhci adma mode, need to have a cleaner\r
- * implementation to keep this function independent of sdhci\r
- * limitations\r
- */\r
- while (data_len > write_size) {\r
- val = mmc_sdhci_write(\r
- Instance->MmcDev, (VOID *)sptr, (data_addr / block_size),\r
- (write_size / block_size));\r
- if (val) {\r
- DEBUG(\r
- (EFI_D_ERROR, "Failed Writing block @ %x\n",\r
- (UINTN)(data_addr / block_size)));\r
- return val;\r
- }\r
- sptr += write_size;\r
- data_addr += write_size;\r
- data_len -= write_size;\r
- }\r
-\r
- if (data_len)\r
- val = mmc_sdhci_write(\r
- Instance->MmcDev, (VOID *)sptr, (data_addr / block_size),\r
- (data_len / block_size));\r
-\r
- if (val)\r
- DEBUG(\r
- (EFI_D_ERROR, "Failed Writing block @ %x\n",\r
- (UINTN)(data_addr / block_size)));\r
-\r
- return val;\r
-}\r
-\r
-/*\r
- * Function: mmc_read\r
- * Arg : Data address on card, o/p buffer & data length\r
- * Return : 0 on Success, non zero on failure\r
- * Flow : Read data from the card to out\r
- */\r
-STATIC UINT32\r
-mmc_read(BIO_INSTANCE *Instance, UINT64 data_addr, UINT32 *out, UINT32 data_len)\r
-{\r
- UINT32 ret = 0;\r
- UINT32 block_size;\r
- UINT32 read_size = SDHCI_ADMA_MAX_TRANS_SZ;\r
- UINT8 *sptr = (UINT8 *)out;\r
-\r
- block_size = Instance->BlockMedia.BlockSize;\r
-\r
- ASSERT(!(data_addr % block_size));\r
- ASSERT(!(data_len % block_size));\r
-\r
- /*\r
- * dma onto write back memory is unsafe/nonportable,\r
- * but callers to this routine normally provide\r
- * write back buffers. Invalidate cache\r
- * before read data from mmc.\r
- */\r
- arch_clean_invalidate_cache_range((addr_t)(out), data_len);\r
-\r
- /* TODO: This function is aware of max data that can be\r
- * tranferred using sdhci adma mode, need to have a cleaner\r
- * implementation to keep this function independent of sdhci\r
- * limitations\r
- */\r
- while (data_len > read_size) {\r
- ret = mmc_sdhci_read(\r
- Instance->MmcDev, (VOID *)sptr, (data_addr / block_size),\r
- (read_size / block_size));\r
- if (ret) {\r
- DEBUG(\r
- (EFI_D_ERROR, "Failed Reading block @ %x\n",\r
- (UINTN)(data_addr / block_size)));\r
- return ret;\r
- }\r
- sptr += read_size;\r
- data_addr += read_size;\r
- data_len -= read_size;\r
- }\r
-\r
- if (data_len)\r
- ret = mmc_sdhci_read(\r
- Instance->MmcDev, (VOID *)sptr, (data_addr / block_size),\r
- (data_len / block_size));\r
-\r
- if (ret)\r
- DEBUG(\r
- (EFI_D_ERROR, "Failed Reading block @ %x\n",\r
- (UINTN)(data_addr / block_size)));\r
-\r
- return ret;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSReset(IN EFI_BLOCK_IO_PROTOCOL *This, IN BOOLEAN ExtendedVerification)\r
-{\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSReadBlocks(\r
- IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba,\r
- IN UINTN BufferSize, OUT VOID *Buffer)\r
-{\r
- BIO_INSTANCE * Instance;\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- EFI_TPL OldTpl;\r
- UINTN BlockSize;\r
- UINTN RC;\r
-\r
- Instance = BIO_INSTANCE_FROM_BLOCKIO_THIS(This);\r
- Media = &Instance->BlockMedia;\r
- BlockSize = Media->BlockSize;\r
-\r
- if (MediaId != Media->MediaId) {\r
- return EFI_MEDIA_CHANGED;\r
- }\r
-\r
- if (Lba > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (BufferSize % BlockSize != 0) {\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
-\r
- if (Buffer == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (BufferSize == 0) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- OldTpl = gBS->RaiseTPL(TPL_NOTIFY);\r
- RC = mmc_read(Instance, (UINT64)Lba * BlockSize, Buffer, BufferSize);\r
- gBS->RestoreTPL(OldTpl);\r
-\r
- if (RC == 0)\r
- return EFI_SUCCESS;\r
- else\r
- return EFI_DEVICE_ERROR;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSWriteBlocks(\r
- IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba,\r
- IN UINTN BufferSize, IN VOID *Buffer)\r
-{\r
- BIO_INSTANCE * Instance;\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- UINTN BlockSize;\r
- UINTN RC;\r
- EFI_TPL OldTpl;\r
-\r
- Instance = BIO_INSTANCE_FROM_BLOCKIO_THIS(This);\r
- Media = &Instance->BlockMedia;\r
- BlockSize = Media->BlockSize;\r
-\r
- if (MediaId != Media->MediaId) {\r
- return EFI_MEDIA_CHANGED;\r
- }\r
-\r
- if (Lba > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (BufferSize % BlockSize != 0) {\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
-\r
- if (Buffer == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (BufferSize == 0) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- // Here goes a fail-safe design (see issue #5)\r
- // Assume the partition layout before partition 36 is identical on our target\r
- // devices\r
- // Only slot 1 (eMMC) is protected\r
- if (Instance->MmcDev->config.slot <= 1 && (0 <= Lba && Lba <= 253951)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- OldTpl = gBS->RaiseTPL(TPL_NOTIFY);\r
- RC = mmc_write(Instance, (UINT64)Lba * BlockSize, BufferSize, Buffer);\r
- gBS->RestoreTPL(OldTpl);\r
-\r
- if (RC == 0)\r
- return EFI_SUCCESS;\r
- else\r
- return EFI_DEVICE_ERROR;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL *This)\r
-{\r
- // Nothing required\r
- return EFI_SUCCESS;\r
-}\r
-\r
-VOID EFIAPI MMCHSExitBsUninit(IN EFI_EVENT Event, IN VOID *Context)\r
-{\r
- EFI_TPL OldTpl;\r
-\r
- BIO_INSTANCE *Instance = (BIO_INSTANCE *)Context;\r
- ASSERT(Instance != NULL);\r
-\r
- OldTpl = gBS->RaiseTPL(TPL_NOTIFY);\r
-\r
- // Put card into sleep\r
- mmc_put_card_to_sleep(Instance->MmcDev);\r
-\r
- gBS->RestoreTPL(OldTpl);\r
-}\r
-\r
-EFI_STATUS\r
-BioInstanceContructor(OUT BIO_INSTANCE **NewInstance)\r
-{\r
- BIO_INSTANCE *Instance;\r
-\r
- Instance = AllocateCopyPool(sizeof(BIO_INSTANCE), &mBioTemplate);\r
- if (Instance == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Instance->BlockIo.Media = &Instance->BlockMedia;\r
-\r
- *NewInstance = Instance;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)\r
-{\r
- // let the target register MMC devices\r
- LibQcomTargetMmcSdhciInit(PlatformCallbackInitSlot);\r
-\r
- return EFI_SUCCESS;\r
-}\r
+++ /dev/null
-#ifndef _MMCHS_H_\r
-#define _MMCHS_H_\r
-\r
-#include <Uefi.h>\r
-\r
-#include <Library/LKEnvLib.h>\r
-\r
-#include <Library/BaseLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/PcdLib.h>\r
-#include <Library/QcomPlatformMmcLib.h>\r
-#include <Library/QcomTargetMmcSdhciLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-\r
-#include <Chipset/mmc_sdhci.h>\r
-\r
-#include <Protocol/BlockIo.h>\r
-#include <Protocol/DevicePath.h>\r
-\r
-//#include "mmc_p.h"\r
-\r
-//\r
-// Device structures\r
-//\r
-typedef struct {\r
- VENDOR_DEVICE_PATH Mmc;\r
- EFI_DEVICE_PATH End;\r
-} MMCHS_DEVICE_PATH;\r
-\r
-typedef struct {\r
- UINT32 Signature;\r
- EFI_HANDLE Handle;\r
- EFI_BLOCK_IO_PROTOCOL BlockIo;\r
- EFI_BLOCK_IO_MEDIA BlockMedia;\r
- MMCHS_DEVICE_PATH DevicePath;\r
- struct mmc_device * MmcDev;\r
- EFI_EVENT ExitBsEvent;\r
-} BIO_INSTANCE;\r
-\r
-#define BIO_INSTANCE_SIGNATURE SIGNATURE_32('e', 'm', 'm', 'c')\r
-\r
-#define BIO_INSTANCE_FROM_BLOCKIO_THIS(a) \\r
- CR(a, BIO_INSTANCE, BlockIo, BIO_INSTANCE_SIGNATURE)\r
-\r
-#ifdef DEBUG_SDHCI\r
-#define DBG(...) dprintf(ALWAYS, __VA_ARGS__)\r
-#else\r
-#define DBG(...)\r
-#endif\r
-\r
-//\r
-// Function Prototypes\r
-//\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSReset(IN EFI_BLOCK_IO_PROTOCOL *This, IN BOOLEAN ExtendedVerification);\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSReadBlocks(\r
- IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba,\r
- IN UINTN BufferSize, OUT VOID *Buffer);\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSWriteBlocks(\r
- IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba,\r
- IN UINTN BufferSize, IN VOID *Buffer);\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-MMCHSFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL *This);\r
-\r
-EFI_STATUS\r
-BioInstanceContructor(OUT BIO_INSTANCE **NewInstance);\r
-\r
-VOID EFIAPI MMCHSExitBsUninit(IN EFI_EVENT Event, IN VOID *Context);\r
-\r
-/* API: to initialize the controller */\r
-void sdhci_init(struct sdhci_host *);\r
-/* API: Send the command & transfer data using adma */\r
-uint32_t sdhci_send_command(struct sdhci_host *, struct mmc_command *);\r
-/* API: Set the bus width for the contoller */\r
-uint8_t sdhci_set_bus_width(struct sdhci_host *, uint16_t);\r
-/* API: Clock supply for the controller */\r
-uint32_t sdhci_clk_supply(struct sdhci_host *, uint32_t);\r
-/* API: To enable SDR/DDR mode */\r
-void sdhci_set_uhs_mode(struct sdhci_host *, uint32_t);\r
-/* API: Soft reset for the controller */\r
-void sdhci_reset(struct sdhci_host *host, uint8_t mask);\r
-\r
-/*\r
- * APIS exposed to block level driver\r
- */\r
-/* API: Initialize the mmc card */\r
-struct mmc_device *mmc_init(struct mmc_config_data *);\r
-/* API: Read required number of blocks from card into destination */\r
-uint32_t mmc_sdhci_read(\r
- struct mmc_device *dev, void *dest, uint64_t blk_addr, uint32_t num_blocks);\r
-/* API: Write requried number of blocks from source to card */\r
-uint32_t mmc_sdhci_write(\r
- struct mmc_device *dev, void *src, uint64_t blk_addr, uint32_t num_blocks);\r
-/* API: Erase len bytes (after converting to number of erase groups), from\r
- * specified address */\r
-uint32_t\r
-mmc_sdhci_erase(struct mmc_device *dev, uint32_t blk_addr, uint64_t len);\r
-/* API: Write protect or release len bytes (after converting to number of write\r
- * protect groups) from specified start address*/\r
-uint32_t mmc_set_clr_power_on_wp_user(\r
- struct mmc_device *dev, uint32_t addr, uint64_t len, uint8_t set_clr);\r
-/* API: Get the WP status of write protect groups starting at addr */\r
-uint32_t\r
-mmc_get_wp_status(struct mmc_device *dev, uint32_t addr, uint8_t *wp_status);\r
-/* API: Put the mmc card in sleep mode */\r
-void mmc_put_card_to_sleep(struct mmc_device *dev);\r
-/* API: Change the driver type of the card */\r
-bool mmc_set_drv_type(\r
- struct sdhci_host *host, struct mmc_card *card, uint8_t drv_type);\r
-/* API: Send the read & write command sequence to rpmb */\r
-uint32_t mmc_sdhci_rpmb_send(struct mmc_device *dev, struct mmc_command *cmd);\r
-/* API: De-init the card */\r
-void mmc_put_card_to_sleep_disable_hc(struct mmc_device *dev);\r
-\r
-#endif\r
+++ /dev/null
-[Defines]\r
- INF_VERSION = 0x00010005\r
- BASE_NAME = MMCHS\r
- FILE_GUID = 891F2B63-4ED3-4305-A660-016D02810541\r
- MODULE_TYPE = DXE_DRIVER\r
- VERSION_STRING = 1.0\r
- ENTRY_POINT = MMCHSInitialize\r
-\r
-\r
-[Sources.common]\r
- MMCHS.c\r
- mmc_sdhci.c\r
- sdhci.c\r
- sdhci_msm.c\r
-\r
-#[Packages]\r
-# MdePkg/MdePkg.dec\r
-# ArmPkg/ArmPkg.dec\r
-# EmbeddedPkg/EmbeddedPkg.dec\r
-# Lumia950XLPkg/Lumia950XLPkg.dec\r
-\r
-[LibraryClasses]\r
- UefiLib\r
- UefiDriverEntryPoint\r
- ArmLib\r
- IoLib\r
- TimerLib\r
- #LcmLib\r
- #MallocLib\r
- CacheMaintenanceLib\r
- #InterruptsLib\r
- #QcomPlatformMmcLib\r
- #QcomTargetMmcSdhciLib\r
-\r
-[BuildOptions.AARCH64]\r
- GCC:*_*_*_CC_FLAGS = -Wno-pointer-to-int-cast\r
-\r
-[Protocols]\r
- gEfiBlockIoProtocolGuid\r
- gEfiDevicePathProtocolGuid\r
-\r
-[Guids]\r
- gEfiEventVirtualAddressChangeGuid\r
- gEfiEventExitBootServicesGuid\r
-\r
-[FeaturePcd]\r
- gQcomTokenSpaceGuid.PcdMmcHs200Caps\r
-\r
-[Pcd.common]\r
- gQcomTokenSpaceGuid.PcdSdccMciHcMode\r
- gQcomTokenSpaceGuid.PcdSdccHcPwrctlStatusReg\r
- gQcomTokenSpaceGuid.PcdSdccHcPwrctlMaskReg\r
- gQcomTokenSpaceGuid.PcdSdccHcPwrctlClearReg\r
- gQcomTokenSpaceGuid.PcdSdccHcPwrctlCtlReg\r
- gQcomTokenSpaceGuid.PcdMmcSdhciDdrCfgVal\r
-\r
-[Depex]\r
- TRUE\r
+++ /dev/null
-URL: https://source.codeaurora.org/quic/la/kernel/lk
-BRANCH: LA.BF64.1.2.3-01510-8x94.0
+++ /dev/null
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <Library/LKEnvLib.h>
-
-#include <Library/MallocLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-
-#include <Chipset/mmc_sdhci.h>
-// Must come in order
-#include <Chipset/sdhci.h>
-
-#include "sdhci_msm.h"
-// Must come in order
-#include "MMCHS.h"
-
-/* data access time unit in ns */
-static const uint32_t taac_unit[] = {1, 10, 100, 1000,
- 10000, 100000, 1000000, 10000000};
-
-/* data access time value x 10 */
-static const uint32_t taac_value[] = {0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80};
-
-/* data transfer rate in kbit/s */
-static const uint32_t xfer_rate_unit[] = {100, 1000, 10000, 100000, 0, 0, 0, 0};
-
-/* data transfer rate value x 10*/
-static const uint32_t xfer_rate_value[] = {0, 10, 12, 13, 15, 20, 26, 30,
- 35, 40, 45, 52, 55, 60, 70, 80};
-
-/*
- * Function: mmc decode and save csd
- * Arg : Card structure & raw csd
- * Return : 0 on Success, 1 on Failure
- * Flow : Decodes CSD response received from the card.
- * Note that we have defined only few of the CSD elements
- * in csd structure. We'll only decode those values.
- */
-static uint32_t mmc_decode_and_save_csd(struct mmc_card *card)
-{
- uint32_t mmc_sizeof = 0;
- uint32_t mmc_unit = 0;
- uint32_t mmc_value = 0;
- uint32_t mmc_temp = 0;
- uint32_t *raw_csd = card->raw_csd;
-
- struct mmc_csd mmc_csd;
-
- mmc_sizeof = sizeof(uint32_t) * 8;
-
- mmc_csd.cmmc_structure = UNPACK_BITS(raw_csd, 126, 2, mmc_sizeof);
-
- if (MMC_CARD_SD(card)) {
- /* Parse CSD according to SD card spec. */
-
- /* CSD register is little bit differnet for CSD version 2.0 High
- * Capacity and CSD version 1.0/2.0 Standard memory cards.
- * In Version 2.0 some of the fields have fixed values and it's
- * not necessary for host to refer these fields in CSD sent by
- * card
- */
-
- if (mmc_csd.cmmc_structure == 1) {
- /* CSD Version 2.0 */
- mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
- /* Fixed value is 9 = 2^9 = 512 */
- mmc_csd.write_blk_len = 512;
- /* Fixed value is 9 = 512 */
- mmc_csd.read_blk_len = 512;
- /* Fixed value: 010b */
- mmc_csd.r2w_factor = 0x2;
- /* Not there in version 2.0 */
- mmc_csd.c_size_mult = 0;
- mmc_csd.c_size = UNPACK_BITS(raw_csd, 48, 22, mmc_sizeof);
- mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100;
-
- mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
- mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
- mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;
-
- mmc_csd.erase_blk_len = 1;
- mmc_csd.read_blk_misalign = 0;
- mmc_csd.write_blk_misalign = 0;
- mmc_csd.read_blk_partial = 0;
- mmc_csd.write_blk_partial = 0;
-
- mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof);
- mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof);
- mmc_csd.tran_speed =
- (xfer_rate_value[mmc_value] * xfer_rate_unit[mmc_unit]) / 10;
-
- mmc_csd.wp_grp_size = 0x0;
- mmc_csd.wp_grp_enable = 0x0;
- mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
- mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
-
- /* Calculate the card capcity */
- card->capacity = (unsigned long long)(1 + mmc_csd.c_size) * 512 * 1024;
- }
- else {
- /* CSD Version 1.0 */
- mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
-
- mmc_temp = UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof);
- mmc_csd.write_blk_len =
- (mmc_temp > 8 && mmc_temp < 12) ? (1 << mmc_temp) : 512;
-
- mmc_temp = UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof);
- mmc_csd.read_blk_len =
- (mmc_temp > 8 && mmc_temp < 12) ? (1 << mmc_temp) : 512;
-
- mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
- mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
- mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;
-
- mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof);
- mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof);
- mmc_csd.tran_speed =
- (xfer_rate_value[mmc_value] * xfer_rate_unit[mmc_unit]) / 10;
-
- mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100;
-
- mmc_csd.r2w_factor = UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof);
- mmc_csd.sector_size = UNPACK_BITS(raw_csd, 39, 7, mmc_sizeof) + 1;
-
- mmc_csd.erase_blk_len = UNPACK_BITS(raw_csd, 46, 1, mmc_sizeof);
- mmc_csd.read_blk_misalign = UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof);
- mmc_csd.write_blk_misalign = UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof);
- mmc_csd.read_blk_partial = UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof);
- mmc_csd.write_blk_partial = UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof);
-
- mmc_csd.c_size_mult = UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof);
- mmc_csd.c_size = UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof);
- mmc_csd.wp_grp_size = UNPACK_BITS(raw_csd, 32, 7, mmc_sizeof);
- mmc_csd.wp_grp_enable = UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof);
- mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
- mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
-
- /* Calculate the card capacity */
- mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1);
- card->capacity = (unsigned long long)mmc_temp * mmc_csd.read_blk_len;
- }
- }
- else {
- /* Parse CSD according to MMC card spec. */
- mmc_csd.spec_vers = UNPACK_BITS(raw_csd, 122, 4, mmc_sizeof);
- mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
- mmc_csd.write_blk_len = 1 << UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof);
- mmc_csd.read_blk_len = 1 << UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof);
- mmc_csd.r2w_factor = UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof);
- mmc_csd.c_size_mult = UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof);
- mmc_csd.c_size = UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof);
- mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100;
-
- mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
- mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
- mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;
-
- mmc_csd.read_blk_misalign = UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof);
- mmc_csd.write_blk_misalign = UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof);
- mmc_csd.read_blk_partial = UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof);
- mmc_csd.write_blk_partial = UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof);
-
- /* Ignore -- no use of this value. */
- mmc_csd.tran_speed = 0x00;
-
- mmc_csd.erase_grp_size = UNPACK_BITS(raw_csd, 42, 5, mmc_sizeof);
- mmc_csd.erase_grp_mult = UNPACK_BITS(raw_csd, 37, 5, mmc_sizeof);
- mmc_csd.wp_grp_size = UNPACK_BITS(raw_csd, 32, 5, mmc_sizeof);
- mmc_csd.wp_grp_enable = UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof);
- mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
- mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
-
- /* Calculate the card capcity */
- if (mmc_csd.c_size != 0xFFF) {
- /* For cards less than or equal to 2GB */
- mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1);
- card->capacity = (unsigned long long)mmc_temp * mmc_csd.read_blk_len;
- }
- else {
- /* For cards greater than 2GB, Ext CSD register's SEC_COUNT
- * is used to calculate the size.
- */
- uint64_t sec_count;
-
- sec_count = (card->ext_csd[MMC_SEC_COUNT4] << MMC_SEC_COUNT4_SHIFT) |
- (card->ext_csd[MMC_SEC_COUNT3] << MMC_SEC_COUNT3_SHIFT) |
- (card->ext_csd[MMC_SEC_COUNT2] << MMC_SEC_COUNT2_SHIFT) |
- card->ext_csd[MMC_SEC_COUNT1];
- card->capacity = sec_count * MMC_BLK_SZ;
- }
- }
-
- /* save the information in card structure */
- memcpy(
- (struct mmc_csd *)&card->csd, (struct mmc_csd *)&mmc_csd,
- sizeof(struct mmc_csd));
-
- /* Calculate the wp grp size */
- if (MMC_CARD_MMC(card)) {
- if (card->ext_csd[MMC_ERASE_GRP_DEF])
- card->wp_grp_size =
- MMC_HC_ERASE_MULT * card->ext_csd[MMC_HC_ERASE_GRP_SIZE] / MMC_BLK_SZ;
- else
- card->wp_grp_size = (card->csd.wp_grp_size + 1) *
- (card->csd.erase_grp_size + 1) *
- (card->csd.erase_grp_mult + 1);
-
- card->rpmb_size = RPMB_PART_MIN_SIZE * card->ext_csd[RPMB_SIZE_MULT];
- card->rel_wr_count = card->ext_csd[REL_WR_SEC_C];
- }
-
- dprintf(SPEW, "Decoded CSD fields:\n");
- dprintf(SPEW, "cmmc_structure: %u\n", mmc_csd.cmmc_structure);
- dprintf(SPEW, "card_cmd_class: %x\n", mmc_csd.card_cmd_class);
- dprintf(SPEW, "write_blk_len: %u\n", mmc_csd.write_blk_len);
- dprintf(SPEW, "read_blk_len: %u\n", mmc_csd.read_blk_len);
- dprintf(SPEW, "r2w_factor: %u\n", mmc_csd.r2w_factor);
- dprintf(SPEW, "sector_size: %u\n", mmc_csd.sector_size);
- dprintf(SPEW, "c_size_mult:%u\n", mmc_csd.c_size_mult);
- dprintf(SPEW, "c_size: %u\n", mmc_csd.c_size);
- dprintf(SPEW, "nsac_clk_cycle: %u\n", mmc_csd.nsac_clk_cycle);
- dprintf(SPEW, "taac_ns: %u\n", mmc_csd.taac_ns);
- dprintf(SPEW, "tran_speed: %u kbps\n", mmc_csd.tran_speed);
- dprintf(SPEW, "erase_blk_len: %u\n", mmc_csd.erase_blk_len);
- dprintf(SPEW, "read_blk_misalign: %u\n", mmc_csd.read_blk_misalign);
- dprintf(SPEW, "write_blk_misalign: %u\n", mmc_csd.write_blk_misalign);
- dprintf(SPEW, "read_blk_partial: %u\n", mmc_csd.read_blk_partial);
- dprintf(SPEW, "write_blk_partial: %u\n", mmc_csd.write_blk_partial);
- dprintf(SPEW, "wp_grp_size: %u\n", card->wp_grp_size);
- dprintf(SPEW, "Card Capacity: %llu Bytes\n", card->capacity);
-
- return 0;
-}
-
-/*
- * Function: mmc decode & save cid
- * Arg : card structure & raw cid
- * Return : 0 on Success, 1 on Failure
- * Flow : Decode CID sent by the card.
- */
-static uint32_t
-mmc_decode_and_save_cid(struct mmc_card *card, uint32_t *raw_cid)
-{
- struct mmc_cid mmc_cid;
- uint32_t mmc_sizeof = 0;
- int i = 0;
-
- if (!raw_cid) {
- return 1;
- }
-
- mmc_sizeof = sizeof(uint32_t) * 8;
-
- if (MMC_CARD_SD(card)) {
- mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof);
- mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof);
-
- for (i = 0; i < 5; i++) {
- mmc_cid.pnm[i] =
- (uint8_t)UNPACK_BITS(raw_cid, (104 - 8 * (i + 1)), 8, mmc_sizeof);
- }
- mmc_cid.pnm[5] = 0;
- mmc_cid.pnm[6] = 0;
-
- mmc_cid.prv = UNPACK_BITS(raw_cid, 56, 8, mmc_sizeof);
- mmc_cid.psn = UNPACK_BITS(raw_cid, 24, 32, mmc_sizeof);
- mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof);
- mmc_cid.year = UNPACK_BITS(raw_cid, 12, 8, mmc_sizeof);
- mmc_cid.year += 2000;
- }
- else {
- mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof);
- mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof);
-
- for (i = 0; i < 6; i++) {
- mmc_cid.pnm[i] =
- (uint8_t)UNPACK_BITS(raw_cid, (104 - 8 * (i + 1)), 8, mmc_sizeof);
- }
- mmc_cid.pnm[6] = 0;
-
- mmc_cid.prv = UNPACK_BITS(raw_cid, 48, 8, mmc_sizeof);
- mmc_cid.psn = UNPACK_BITS(raw_cid, 16, 32, mmc_sizeof);
- mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof);
- mmc_cid.year = UNPACK_BITS(raw_cid, 12, 4, mmc_sizeof);
- mmc_cid.year += 1997;
- }
-
- /* save it in card database */
- memcpy(
- (struct mmc_cid *)&card->cid, (struct mmc_cid *)&mmc_cid,
- sizeof(struct mmc_cid));
-
- dprintf(SPEW, "Decoded CID fields:\n");
- dprintf(SPEW, "Manufacturer ID: %x\n", mmc_cid.mid);
- dprintf(SPEW, "OEM ID: 0x%x\n", mmc_cid.oid);
- dprintf(SPEW, "Product Name: %s\n", mmc_cid.pnm);
- dprintf(
- SPEW, "Product revision: %d.%d\n", (mmc_cid.prv >> 4),
- (mmc_cid.prv & 0xF));
- dprintf(SPEW, "Product serial number: %X\n", mmc_cid.psn);
- dprintf(SPEW, "Manufacturing date: %d %d\n", mmc_cid.month, mmc_cid.year);
-
- return 0;
-}
-
-/*
- * Function: mmc reset cards
- * Arg : host structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Reset all the cards to idle condition (CMD 0)
- */
-static uint8_t mmc_reset_card(struct sdhci_host *host)
-{
- struct mmc_command cmd;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- cmd.cmd_index = CMD0_GO_IDLE_STATE;
- cmd.argument = 0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_NONE;
-
- /* send command */
- return sdhci_send_command(host, &cmd);
-}
-
-/*
- * Function: mmc operations command
- * Arg : host & card structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Send CMD1 to know whether the card supports host VDD profile or
- * not.
- */
-static uint32_t mmc_send_op_cond(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd;
- uint32_t mmc_resp = 0;
- uint32_t mmc_ret = 0;
- uint32_t mmc_retry = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD1 format:
- * [31] Busy bit
- * [30:29] Access mode
- * [28:24] reserved
- * [23:15] 2.7-3.6
- * [14:8] 2.0-2.6
- * [7] 1.7-1.95
- * [6:0] reserved
- */
-
- cmd.cmd_index = CMD1_SEND_OP_COND;
- cmd.argument = card->ocr;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R3;
-
- do {
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret)
- return mmc_ret;
-
- /* Command returned success, now it's time to examine response */
- mmc_resp = cmd.resp[0];
-
- /* Check the response for busy status */
- if (!(mmc_resp & MMC_OCR_BUSY)) {
- mmc_retry++;
- gBS->Stall(1000);
- continue;
- }
- else
- break;
- } while (mmc_retry < MMC_MAX_COMMAND_RETRY);
-
- /* If we reached here after max retries, we failed to get OCR */
- if (mmc_retry == MMC_MAX_COMMAND_RETRY && !(mmc_resp & MMC_OCR_BUSY)) {
- dprintf(CRITICAL, "Card has busy status set. Init did not complete\n");
- return 1;
- }
-
- /* Response contains card's ocr. Update card's information */
- card->ocr = mmc_resp;
-
- if (mmc_resp & MMC_OCR_SEC_MODE)
- card->type = MMC_TYPE_MMCHC;
- else
- card->type = MMC_TYPE_STD_MMC;
-
- return 0;
-}
-
-/*
- * Function: mmc send cid
- * Arg : host & card structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Request any card to send its uniquie card identification
- * (CID) number (CMD2).
- */
-static uint32_t mmc_all_send_cid(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd;
- uint32_t mmc_ret = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD2 Format:
- * [31:0] stuff bits
- */
- cmd.cmd_index = CMD2_ALL_SEND_CID;
- cmd.argument = 0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R2;
-
- /* send command */
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret) {
- return mmc_ret;
- }
-
- /* Response contains card's 128 bits CID register */
- mmc_ret = mmc_decode_and_save_cid(card, cmd.resp);
- if (mmc_ret) {
- return mmc_ret;
- }
-
- return 0;
-}
-
-/*
- * Function: mmc send relative address
- * Arg : host & card structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Ask card to send it's relative card address (RCA).
- * This RCA number is shorter than CID and is used by
- * the host to address the card in future (CMD3)
- */
-static uint32_t
-mmc_send_relative_address(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd;
- uint32_t mmc_ret = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD3 Format:
- * [31:0] stuff bits
- */
- if (MMC_CARD_SD(card)) {
- cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;
- cmd.argument = 0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R6;
-
- /* send command */
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret)
- return mmc_ret;
-
- /* For sD, card will send RCA. Store it */
- card->rca = (cmd.resp[0] >> 16);
- }
- else {
- cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;
- cmd.argument = (MMC_RCA << 16);
- card->rca = (cmd.argument >> 16);
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R6;
-
- /* send command */
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret)
- return mmc_ret;
- }
-
- return 0;
-}
-
-/*
- * Function: mmc send csd
- * Arg : host, card structure & o/p arg to store csd
- * Return : 0 on Success, 1 on Failure
- * Flow : Requests card to send it's CSD register's contents. (CMD9)
- */
-static uint32_t mmc_send_csd(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd;
- uint32_t mmc_arg = 0;
- uint32_t mmc_ret = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD9 Format:
- * [31:16] RCA
- * [15:0] stuff bits
- */
- mmc_arg |= card->rca << 16;
-
- cmd.cmd_index = CMD9_SEND_CSD;
- cmd.argument = mmc_arg;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R2;
-
- /* send command */
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret)
- return mmc_ret;
-
- /* response contains the card csd */
- memcpy(card->raw_csd, cmd.resp, sizeof(cmd.resp));
-
- return 0;
-}
-
-/*
- * Function: mmc select card
- * Arg : host, card structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Selects a card by sending CMD7 to the card with its RCA.
- * If RCA field is set as 0 ( or any other address ),
- * the card will be de-selected. (CMD7)
- */
-static uint32_t mmc_select_card(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd;
- uint32_t mmc_arg = 0;
- uint32_t mmc_ret = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD7 Format:
- * [31:16] RCA
- * [15:0] stuff bits
- */
- mmc_arg |= card->rca << 16;
-
- cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
- cmd.argument = mmc_arg;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
-
- /* If we are deselecting card, we do not get response */
- if (card->rca) {
- if (MMC_CARD_SD(card))
- cmd.resp_type = SDHCI_CMD_RESP_R1B;
- else
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- }
- else
- cmd.resp_type = SDHCI_CMD_RESP_NONE;
-
- /* send command */
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret)
- return mmc_ret;
-
- return 0;
-}
-
-/*
- * Function: mmc get card status
- * Arg : host, card structure & o/p argument card status
- * Return : 0 on Success, 1 on Failure
- * Flow : Get the current status of the card
- */
-static uint32_t mmc_get_card_status(
- struct sdhci_host *host, struct mmc_card *card, uint32_t *status)
-{
- struct mmc_command cmd;
- uint32_t mmc_ret = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD13 Format:
- * [31:16] RCA
- * [15:0] stuff bits
- */
- cmd.cmd_index = CMD13_SEND_STATUS;
- cmd.argument = card->rca << 16;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
-
- /* send command */
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret)
- return mmc_ret;
-
- /* Checking ADDR_OUT_OF_RANGE error in CMD13 response */
- if ((cmd.resp[0] >> 31) & 0x01)
- return 1;
-
- *status = cmd.resp[0];
- return 0;
-}
-
-/*
- * Function: mmc get ext csd
- * Arg : host, card structure & array to hold ext attributes
- * Return : 0 on Success, 1 on Failure
- * Flow : Send ext csd command & get the card attributes
- */
-static uint32_t mmc_get_ext_csd(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd;
- uint32_t mmc_ret = 0;
-
- card->ext_csd = memalign(CACHE_LINE, ROUNDUP(512, CACHE_LINE));
-
- ASSERT(card->ext_csd);
-
- memset(card->ext_csd, 0, sizeof(card->ext_csd));
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD8 */
- cmd.cmd_index = CMD8_SEND_EXT_CSD;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.data.data_ptr = card->ext_csd;
- cmd.data.num_blocks = 1;
- cmd.data_present = 0x1;
- cmd.trans_mode = SDHCI_MMC_READ;
-
- /* send command */
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret)
- return mmc_ret;
-
- return mmc_ret;
-}
-
-/*
- * Function: mmc switch command
- * Arg : Host, card structure, access mode, index & value to be set
- * Return : 0 on Success, 1 on Failure
- * Flow : Send switch command to the card to set the ext attribute @ index
- */
-static uint32_t mmc_switch_cmd(
- struct sdhci_host *host, struct mmc_card *card, uint32_t access,
- uint32_t index, uint32_t value)
-{
-
- struct mmc_command cmd;
- uint32_t mmc_ret = 0;
- uint32_t mmc_status;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD6 Format:
- * [31:26] set to 0
- * [25:24] access
- * [23:16] index
- * [15:8] value
- * [7:3] set to 0
- * [2:0] cmd set
- */
- cmd.cmd_index = CMD6_SWITCH_FUNC;
- cmd.argument |= (access << 24);
- cmd.argument |= (index << 16);
- cmd.argument |= (value << 8);
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1B;
-
- mmc_ret = sdhci_send_command(host, &cmd);
- if (mmc_ret) {
- dprintf(CRITICAL, "CMD6 send failed\n");
- return mmc_ret;
- }
-
- /* Check if the card completed the switch command processing */
- mmc_ret = mmc_get_card_status(host, card, &mmc_status);
- if (mmc_ret) {
- dprintf(CRITICAL, "Get card status failed\n");
- return mmc_ret;
- }
-
- if (MMC_CARD_STATUS(mmc_status) != MMC_TRAN_STATE) {
- dprintf(
- CRITICAL, "Switch cmd failed. Card not in tran state %x\n", mmc_status);
- mmc_ret = 1;
- }
-
- if (mmc_status & MMC_SWITCH_FUNC_ERR_FLAG) {
- dprintf(CRITICAL, "Switch cmd failed. Switch Error.\n");
- mmc_ret = 1;
- }
-
- return mmc_ret;
-}
-
-bool mmc_set_drv_type(
- struct sdhci_host *host, struct mmc_card *card, uint8_t drv_type)
-{
- uint32_t ret = 0;
- bool drv_type_changed = false;
-
- uint32_t value = ((drv_type << 4) | MMC_HS200_TIMING);
-
- if (card->ext_csd[MMC_EXT_MMC_DRV_STRENGTH] & (1 << drv_type))
- ret = mmc_switch_cmd(
- host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, value);
- if (!ret)
- drv_type_changed = true;
-
- return drv_type_changed;
-}
-/*
- * Function: mmc set bus width
- * Arg : Host, card structure & width
- * Return : 0 on Success, 1 on Failure
- * Flow : Send switch command to set bus width
- */
-static uint32_t mmc_set_bus_width(
- struct sdhci_host *host, struct mmc_card *card, uint32_t width)
-{
- uint32_t mmc_ret = 0;
-
- mmc_ret = mmc_switch_cmd(
- host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_BUS_WIDTH, width);
-
- if (mmc_ret) {
- dprintf(CRITICAL, "Switch cmd failed\n");
- return mmc_ret;
- }
-
- return 0;
-}
-
-/*
- * Function: mmc card supports hs400 mode
- * Arg : None
- * Return : 1 if hs400 mode is supported, 0 otherwise
- * Flow : Check the ext csd attributes of the card
- */
-static uint8_t mmc_card_supports_hs400_mode(struct mmc_card *card)
-{
- if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_HS400_MODE)
- return 1;
- else
- return 0;
-}
-
-/*
- * Function: mmc card supports hs200 mode
- * Arg : None
- * Return : 1 if HS200 mode is supported, 0 otherwise
- * Flow : Check the ext csd attributes of the card
- */
-static uint8_t mmc_card_supports_hs200_mode(struct mmc_card *card)
-{
- if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_HS200_MODE)
- return 1;
- else
- return 0;
-}
-
-/*
- * Function: mmc card supports ddr mode
- * Arg : None
- * Return : 1 if DDR mode is supported, 0 otherwise
- * Flow : Check the ext csd attributes of the card
- */
-static uint8_t mmc_card_supports_ddr_mode(struct mmc_card *card)
-{
- if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_DDR_MODE)
- return 1;
- else
- return 0;
-}
-
-/*
- * Function : Enable HS200 mode
- * Arg : Host, card structure and bus width
- * Return : 0 on Success, 1 on Failure
- * Flow :
- * - Set the bus width to 4/8 bit SDR as supported by the target &
- * host
- * - Set the HS_TIMING on ext_csd 185 for the card
- */
-static uint32_t mmc_set_hs200_mode(
- struct sdhci_host *host, struct mmc_card *card, uint32_t width)
-{
- uint32_t mmc_ret = 0;
-
- DBG("\n Enabling HS200 Mode Start\n");
-
- /* Set 4/8 bit SDR bus width */
- mmc_ret = mmc_set_bus_width(host, card, width);
- if (mmc_ret) {
- dprintf(CRITICAL, "Failure to set wide bus for Card(RCA:%x)\n", card->rca);
- return mmc_ret;
- }
-
- /* Setting HS200 in HS_TIMING using EXT_CSD (CMD6) */
- mmc_ret = mmc_switch_cmd(
- host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, MMC_HS200_TIMING);
-
- if (mmc_ret) {
- dprintf(CRITICAL, "Switch cmd returned failure %d\n", __LINE__);
- return mmc_ret;
- }
-
- /* Enable SDR104 mode in controller */
- sdhci_set_uhs_mode(host, SDHCI_SDR104_MODE);
-
- /* Run the clock @ 400 Mhz */
- if (host->caps.hs400_support && mmc_card_supports_hs400_mode(card)) {
- /* Save the timing value, before changing the clock */
- MMC_SAVE_TIMING(host, MMC_HS400_TIMING);
- /*
- * Set the MCI_CLK divider before changing the sdcc core
- * core clk to ensure card receives no more than 200 MHZ
- * clock frequency
- */
- sdhci_msm_set_mci_clk(host);
- LibQcomPlatformMmcClockConfig(host->msm_host->slot, SDHCI_CLK_400MHZ);
- }
-
- /* Execute Tuning for hs200 mode */
- if ((mmc_ret = sdhci_msm_execute_tuning(host, card, width)))
- dprintf(CRITICAL, "Tuning for hs200 failed\n");
-
- /* Once the tuning is executed revert back the clock to 200MHZ
- * and disable the MCI_CLK divider so that we can use SDHC clock
- * divider to supply clock to the card
- */
- if (host->timing == MMC_HS400_TIMING) {
- MMC_SAVE_TIMING(host, MMC_HS200_TIMING);
- sdhci_msm_set_mci_clk(host);
- LibQcomPlatformMmcClockConfig(host->msm_host->slot, MMC_CLK_192MHZ);
- }
- else {
- /* Save the timing value, before changing the clock */
- MMC_SAVE_TIMING(host, MMC_HS200_TIMING);
- }
-
- DBG("\n Enabling HS200 Mode Done\n");
-
- return mmc_ret;
-}
-
-/*
- * Function: mmc set ddr mode
- * Arg : Host & card structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Set bus width for ddr mode & set controller in DDR mode
- */
-static uint8_t mmc_set_ddr_mode(struct sdhci_host *host, struct mmc_card *card)
-{
- uint8_t mmc_ret = 0;
-
- DBG("\n Enabling DDR Mode Start\n");
-
- /* Set width for 8 bit DDR mode by default */
- mmc_ret = mmc_set_bus_width(host, card, DATA_DDR_BUS_WIDTH_8BIT);
-
- if (mmc_ret) {
- dprintf(CRITICAL, "Failure to set DDR mode for Card(RCA:%x)\n", card->rca);
- return mmc_ret;
- }
-
- /* Save the timing value, before changing the clock */
- MMC_SAVE_TIMING(host, SDHCI_DDR50_MODE);
-
- /* Set the DDR mode in controller */
- sdhci_set_uhs_mode(host, SDHCI_DDR50_MODE);
-
- DBG("\n Enabling DDR Mode Done\n");
-
- return 0;
-}
-
-/*
- * Function: mmc set high speed interface
- * Arg : Host & card structure
- * Return : None
- * Flow : Sets the sdcc clock & clock divider in the host controller
- * Adjust the interface speed to optimal speed
- */
-static uint32_t
-mmc_set_hs_interface(struct sdhci_host *host, struct mmc_card *card)
-{
- uint32_t mmc_ret = 0;
-
- /* Setting HS_TIMING in EXT_CSD (CMD6) */
- mmc_ret = mmc_switch_cmd(
- host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, MMC_HS_TIMING);
-
- if (mmc_ret) {
- dprintf(CRITICAL, "Switch cmd returned failure %d\n", __LINE__);
- return mmc_ret;
- }
-
- /* Save the timing value, before changing the clock */
- MMC_SAVE_TIMING(host, SDHCI_SDR25_MODE);
-
- /* Set the SDR25 mode in controller */
- sdhci_set_uhs_mode(host, SDHCI_SDR25_MODE);
-
- return 0;
-}
-
-/*
- * Function : Enable HS400 mode
- * Arg : Host, card structure and bus width
- * Return : 0 on Success, 1 on Failure
- * Flow :
- * - Set the bus width to 8 bit DDR
- * - Set the HS_TIMING on ext_csd 185 for the card
- */
-uint32_t mmc_set_hs400_mode(
- struct sdhci_host *host, struct mmc_card *card, uint32_t width)
-{
- uint32_t mmc_ret = 0;
-
- /*
- * Emmc 5.0 spec does not allow changing to hs400 mode directly
- * Need to follow the sequence to change to hs400 mode
- * 1. Enable HS200 mode, perform tuning
- * 2. Change to high speed mode
- * 3. Enable DDR mode
- * 4. Enable HS400 mode & execute tuning
- */
-
- DBG("\n Enabling HS400 Mode Start\n");
- /* HS400 mode is supported only in DDR 8-bit */
- if (width != DATA_BUS_WIDTH_8BIT) {
- dprintf(
- CRITICAL, "Bus width is not 8-bit, cannot switch to hs400: %u\n",
- width);
- return 1;
- }
-
- /* 1.Enable HS200 mode */
- mmc_ret = mmc_set_hs200_mode(host, card, width);
-
- if (mmc_ret) {
- dprintf(
- CRITICAL, "Failure Setting HS200 mode %s\t%d\n", __func__, __LINE__);
- return mmc_ret;
- }
-
- /* 2. Enable High speed mode */
- /* This is needed to set the clock to a low value &
- * so that we can switch to hs_timing --> 0x1 */
- /* Save the timing value, before changing the clock */
- MMC_SAVE_TIMING(host, SDHCI_SDR12_MODE);
- sdhci_set_uhs_mode(host, SDHCI_SDR12_MODE);
-
- /* 3. Set HS_TIMING to 0x1 */
- mmc_ret = mmc_set_hs_interface(host, card);
- if (mmc_ret) {
- dprintf(
- CRITICAL, "Error adjusting interface speed!:%s\t%d\n", __func__,
- __LINE__);
- return mmc_ret;
- }
-
- /*4. Enable DDR mode */
- mmc_ret = mmc_set_ddr_mode(host, card);
- if (mmc_ret) {
- dprintf(CRITICAL, "Failure setting DDR mode:%s\t%d\n", __func__, __LINE__);
- return mmc_ret;
- }
-
- /*5. Set hs400 timing */
- mmc_ret = mmc_switch_cmd(
- host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, MMC_HS400_TIMING);
-
- if (mmc_ret) {
- dprintf(
- CRITICAL, "Switch cmd returned failure %s\t%d\n", __func__, __LINE__);
- return mmc_ret;
- }
-
- /* 6. Enable SDR104 mode in controller */
- /* Save the timing value, before changing the clock */
- MMC_SAVE_TIMING(host, MMC_HS400_TIMING);
- sdhci_set_uhs_mode(host, SDHCI_SDR104_MODE);
- /*
- * Enable HS400 mode
- */
- sdhci_msm_set_mci_clk(host);
- /* Set the clock back to 400 MHZ */
- LibQcomPlatformMmcClockConfig(host->msm_host->slot, SDHCI_CLK_400MHZ);
-
- /* 7. Execute Tuning for hs400 mode */
- if ((mmc_ret = sdhci_msm_execute_tuning(host, card, width)))
- dprintf(CRITICAL, "Tuning for hs400 failed\n");
-
- DBG("\n Enabling HS400 Mode Done\n");
-
- return mmc_ret;
-}
-
-/*
- * Function: mmc_host_init
- * Arg : mmc device structure
- * Return : 0 on success, 1 on Failure
- * Flow : Initialize the host contoller
- * Set the clock rate to 400 KHZ for init
- */
-static uint8_t mmc_host_init(struct mmc_device *dev)
-{
- uint8_t mmc_ret = 0;
- EFI_STATUS Status;
-
- struct sdhci_host * host;
- struct mmc_config_data *cfg;
- struct sdhci_msm_data * data;
-
- EFI_EVENT sdhc_event = (EFI_EVENT)NULL;
-
- host = &dev->host;
- cfg = &dev->config;
-
- Status = gBS->CreateEvent(0, 0, NULL, NULL, &sdhc_event);
- ASSERT_EFI_ERROR(Status);
-
- host->base = cfg->sdhc_base;
- host->sdhc_event = sdhc_event;
- host->caps.hs200_support = cfg->hs200_support;
- host->caps.hs400_support = cfg->hs400_support;
-
- data = (struct sdhci_msm_data *)malloc(sizeof(struct sdhci_msm_data));
- ASSERT(data);
-
- data->sdhc_event = sdhc_event;
- data->pwrctl_base = cfg->pwrctl_base;
- data->pwr_irq = cfg->pwr_irq;
- data->slot = cfg->slot;
- data->use_io_switch = cfg->use_io_switch;
-
- host->msm_host = data;
-
- /* Initialize any clocks needed for SDC controller */
- LibQcomPlatformMmcClockInit(cfg->slot);
-
- LibQcomPlatformMmcClockConfig(cfg->slot, cfg->max_clk_rate);
-
- /* Configure the CDC clocks needed for emmc storage
- * we use slot '1' for emmc
- */
- if (cfg->slot == 1)
- LibQcomPlatformMmcClockConfigCdc(cfg->slot);
-
- /*
- * MSM specific sdhc init
- */
- sdhci_msm_init(host, data);
-
- /*
- * Initialize the controller, read the host capabilities
- * set power on mode
- */
- sdhci_init(host);
-
- /* Setup initial freq to 400KHz */
- mmc_ret = sdhci_clk_supply(host, SDHCI_CLK_400KHZ);
-
- return mmc_ret;
-}
-
-/*
- * Function: mmc identify card
- * Arg : host & card structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Performs card identification process:
- * 1. Get card's unique identification number (CID)
- * 2. Get(for sd)/set (for mmc) relative card address (RCA)
- * 3. Select the card to put it in TRAN state
- */
-static uint32_t
-mmc_identify_card(struct sdhci_host *host, struct mmc_card *card)
-{
- uint32_t mmc_return = 0;
-
- /* Ask card to send its unique card identification (CID) number (CMD2) */
- mmc_return = mmc_all_send_cid(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure getting card's CID number!\n");
- return mmc_return;
- }
-
- /* Ask card to send a relative card address (RCA) (CMD3) */
- mmc_return = mmc_send_relative_address(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure getting card's RCA!\n");
- return mmc_return;
- }
-
- /* Get card's CSD register (CMD9) */
- mmc_return = mmc_send_csd(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure getting card's CSD information!\n");
- return mmc_return;
- }
-
- /* Select the card (CMD7) */
- mmc_return = mmc_select_card(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure selecting the Card with RCA: %x\n", card->rca);
- return mmc_return;
- }
-
- /* Set the card status as active */
- card->status = MMC_STATUS_ACTIVE;
-
- return 0;
-}
-
-/*
- * Function: mmc_reset_card_and_send_op
- * Arg : Host & Card structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Routine to initialize MMC card. It resets a card to idle state,
- * verify operating voltage and set the card in ready state.
- */
-static uint32_t
-mmc_reset_card_and_send_op(struct sdhci_host *host, struct mmc_card *card)
-{
- uint32_t mmc_return = 0;
-
- /* 1. Card Reset - CMD0 */
- mmc_return = mmc_reset_card(host);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure resetting MMC cards!\n");
- return mmc_return;
- }
-
- /* 2. Card Initialization process */
-
- /*
- * Send CMD1 to identify and reject cards that do not match host's VDD range
- * profile. Cards sends its OCR register in response.
- */
-
- mmc_return = mmc_send_op_cond(host, card);
-
- /* OCR is not received, init could not complete */
- if (mmc_return) {
- dprintf(CRITICAL, "Failure getting OCR response from MMC Card\n");
- return mmc_return;
- }
-
- return 0;
-}
-
-static uint32_t mmc_send_app_cmd(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd = {0};
-
- cmd.cmd_index = CMD55_APP_CMD;
- cmd.argument = (card->rca << 16);
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
-
- if (sdhci_send_command(host, &cmd)) {
- dprintf(CRITICAL, "Failed Sending CMD55\n");
- return 1;
- }
- return 0;
-}
-
-uint32_t mmc_sd_card_init(struct sdhci_host *host, struct mmc_card *card)
-{
- uint8_t i;
- struct mmc_command cmd;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* Use the SD card RCA 0x0 during init */
- card->rca = SD_CARD_RCA;
-
- /* Send CMD8 for voltage check*/
- for (i = 0; i < SD_CMD8_MAX_RETRY; i++) {
- cmd.cmd_index = CMD8_SEND_IF_COND;
- cmd.argument = MMC_SD_HC_VOLT_SUPPLIED;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R7;
-
- if (sdhci_send_command(host, &cmd)) {
- dprintf(
- CRITICAL,
- "The response for CMD8 does not match the supplied value\n");
- return 1;
- }
- else {
- /* If the command response echos the voltage back */
- if (cmd.resp[0] == MMC_SD_HC_VOLT_SUPPLIED)
- break;
- }
- /* As per SDCC the spec try for max three times with
- * 1 ms delay
- */
- gBS->Stall(1000);
- }
-
- if (i == SD_CMD8_MAX_RETRY && (cmd.resp[0] != MMC_SD_HC_VOLT_SUPPLIED)) {
- dprintf(CRITICAL, "Error: CMD8 response timed out\n");
- return 1;
- }
-
- /* Send ACMD41 for OCR */
- for (i = 0; i < SD_ACMD41_MAX_RETRY; i++) {
- /* Send APP_CMD before ACMD41*/
- if (mmc_send_app_cmd(host, card)) {
- dprintf(CRITICAL, "Failed sending App command\n");
- return 1;
- }
-
- /* APP_CMD is successful, send ACMD41 now */
- cmd.cmd_index = ACMD41_SEND_OP_COND;
- cmd.argument = MMC_SD_OCR | MMC_SD_HC_HCS;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R3;
-
- if (sdhci_send_command(host, &cmd)) {
- dprintf(CRITICAL, "Failure sending ACMD41\n");
- return 1;
- }
- else {
- if (cmd.resp[0] & MMC_SD_DEV_READY) {
- if (cmd.resp[0] & (1 << 30))
- card->type = MMC_CARD_TYPE_SDHC;
- else
- card->type = MMC_CARD_TYPE_STD_SD;
-
- break;
- }
- }
- /*
- * As per SDCC spec try for max 1 second
- */
- gBS->Stall(50 * 1000);
- }
-
- if (i == SD_ACMD41_MAX_RETRY && !(cmd.resp[0] & MMC_SD_DEV_READY)) {
- dprintf(CRITICAL, "Error: ACMD41 response timed out\n");
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Function to read SD card information from SD status
- */
-static uint32_t
-mmc_sd_get_card_ssr(struct sdhci_host *host, struct mmc_card *card)
-{
- void * raw_sd_status;
- struct mmc_command cmd = {0};
- uint32_t sd_status[16];
- uint32_t * status = sd_status;
- uint32_t au_size;
- int i;
- int j;
-
- if (mmc_send_app_cmd(host, card)) {
- dprintf(CRITICAL, "Failed sending App command\n");
- return 1;
- }
-
- raw_sd_status = memalign(CACHE_LINE, ROUNDUP(64, CACHE_LINE));
-
- cmd.cmd_index = ACMD13_SEND_SD_STATUS;
- cmd.argument = 0x0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_READ;
- cmd.data_present = 0x1;
- cmd.data.data_ptr = raw_sd_status;
- cmd.data.num_blocks = 0x1;
- cmd.data.blk_sz = 0x40;
-
- /* send command */
- if (sdhci_send_command(host, &cmd)) {
- free(raw_sd_status);
- return 1;
- }
-
- memcpy(sd_status, raw_sd_status, sizeof(sd_status));
-
- for (i = 15, j = 0; i >= 0; i--, j++)
- sd_status[i] = swap_endian32(sd_status[j]);
-
- au_size = UNPACK_BITS(status, MMC_SD_AU_SIZE_BIT, MMC_SD_AU_SIZE_LEN, 32);
- /* Card AU size in sectors */
- card->ssr.au_size = 1 << (au_size + 4);
- card->ssr.num_aus =
- UNPACK_BITS(status, MMC_SD_ERASE_SIZE_BIT, MMC_SD_ERASE_SIZE_LEN, 32);
-
- free(raw_sd_status);
-
- return 0;
-}
-
-/*
- * Function to read the SD CARD configuration register
- */
-static uint32_t
-mmc_sd_get_card_scr(struct sdhci_host *host, struct mmc_card *card)
-{
- void * scr_resp;
- struct mmc_command cmd = {0};
- uint32_t raw_scr[2];
-
- /* Now read the SCR register */
- /* Send APP_CMD before ACMD51*/
- if (mmc_send_app_cmd(host, card)) {
- dprintf(CRITICAL, "Failed sending App command\n");
- return 1;
- }
-
- scr_resp = memalign(CACHE_LINE, ROUNDUP(8, CACHE_LINE));
-
- cmd.cmd_index = ACMD51_READ_CARD_SCR;
- cmd.argument = 0x0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_READ;
- cmd.data_present = 0x1;
- cmd.data.data_ptr = scr_resp;
- cmd.data.num_blocks = 0x1;
- cmd.data.blk_sz = 0x8;
-
- /* send command */
- if (sdhci_send_command(host, &cmd)) {
- free(scr_resp);
- return 1;
- }
-
- memcpy(raw_scr, scr_resp, sizeof(raw_scr));
-
- card->raw_scr[0] = swap_endian32(raw_scr[0]);
- card->raw_scr[1] = swap_endian32(raw_scr[1]);
-
- /*
- * Parse & Populate the SCR data as per sdcc spec
- */
- card->scr.bus_widths =
- (card->raw_scr[0] & SD_SCR_BUS_WIDTH_MASK) >> SD_SCR_BUS_WIDTH;
- card->scr.cmd23_support = (card->raw_scr[0] & SD_SCR_CMD23_SUPPORT);
- card->scr.sd_spec =
- (card->raw_scr[0] & SD_SCR_SD_SPEC_MASK) >> SD_SCR_SD_SPEC;
- card->scr.sd3_spec =
- (card->raw_scr[0] & SD_SCR_SD_SPEC3_MASK) >> SD_SCR_SD_SPEC3;
-
- free(scr_resp);
-
- return 0;
-}
-
-/*
- * Function: mmc_set_sd_bus_width
- * Arg : host, device structure & width
- * Return : 0 on Success, 1 on Failure
- * Flow : Set the bus width for the card
- */
-uint32_t mmc_sd_set_bus_width(
- struct sdhci_host *host, struct mmc_card *card, uint8_t width)
-{
- struct mmc_command cmd = {0};
-
- /* Send APP_CMD before ACMD6*/
- if (mmc_send_app_cmd(host, card)) {
- dprintf(CRITICAL, "Failed sending App command\n");
- return 1;
- }
-
- cmd.cmd_index = ACMD6_SET_BUS_WIDTH;
- cmd.argument = (width == DATA_BUS_WIDTH_4BIT) ? (1 << 1) : 0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
-
- /* send command */
- if (sdhci_send_command(host, &cmd))
- return 1;
-
- return 0;
-}
-
-uint32_t mmc_sd_set_hs(struct sdhci_host *host, struct mmc_card *card)
-{
- struct mmc_command cmd = {0};
- void * switch_resp;
-
- switch_resp = memalign(CACHE_LINE, ROUNDUP(64, CACHE_LINE));
-
- cmd.cmd_index = CMD6_SWITCH_FUNC;
- cmd.argument = MMC_SD_SWITCH_HS;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_READ;
- cmd.data_present = 0x1;
- cmd.data.data_ptr = switch_resp;
- cmd.data.num_blocks = 0x1;
- cmd.data.blk_sz = 0x40;
-
- /* send command */
- if (sdhci_send_command(host, &cmd)) {
- free(switch_resp);
- return 1;
- }
-
- /* Set the SDR25 mode in controller*/
- sdhci_set_uhs_mode(host, SDHCI_SDR25_MODE);
-
- free(switch_resp);
-
- return 0;
-}
-
-/*
- * Function: mmc_init_card
- * Arg : mmc device structure
- * Return : 0 on Success, 1 on Failure
- * Flow : Performs initialization and identification of eMMC cards connected
- * to the host.
- */
-
-static uint32_t mmc_card_init(struct mmc_device *dev)
-{
- uint32_t mmc_return = 0;
- uint8_t bus_width = 0;
-
- struct sdhci_host * host;
- struct mmc_card * card;
- struct mmc_config_data *cfg;
-
- host = &dev->host;
- card = &dev->card;
- cfg = &dev->config;
-
- /* Initialize MMC card structure */
- card->status = MMC_STATUS_INACTIVE;
-
- /* TODO: Get the OCR params from target */
- card->ocr = MMC_OCR_27_36 | MMC_OCR_SEC_MODE;
-
- /* Initialize the internal MMC */
- mmc_return = mmc_reset_card_and_send_op(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "MMC card failed to respond, try for SD card\n");
- /* Reset the card & get the OCR */
- mmc_return = mmc_sd_card_init(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failed to initialize SD card\n");
- return mmc_return;
- }
- }
-
- /* Identify (CMD2, CMD3 & CMD9) and select the card (CMD7) */
- mmc_return = mmc_identify_card(host, card);
- if (mmc_return)
- return mmc_return;
-
- /* set interface speed */
- if (MMC_CARD_SD(card)) {
- mmc_return = mmc_sd_set_hs(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failed to set HS for SD card\n");
- return mmc_return;
- }
- }
- else {
- mmc_return = mmc_set_hs_interface(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Error adjusting interface speed!\n");
- return mmc_return;
- }
- }
-
- /* Now get the extended CSD for the card */
- if (MMC_CARD_MMC(card)) {
- /* For MMC cards, also get the extended csd */
- mmc_return = mmc_get_ext_csd(host, card);
-
- if (mmc_return) {
- dprintf(CRITICAL, "Failure getting card's ExtCSD information!\n");
- return mmc_return;
- }
- }
- else {
- /*Read SCR for sd card */
- if (mmc_sd_get_card_scr(host, card)) {
- dprintf(CRITICAL, "Failure getting card's SCR register\n");
- return 1;
- }
- /* Read SSR for the SD card */
- if (mmc_sd_get_card_ssr(host, card)) {
- dprintf(CRITICAL, "Failed to get SSR from the card\n");
- return 1;
- }
- }
-
- /* Decode and save the CSD register */
- mmc_return = mmc_decode_and_save_csd(card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure decoding card's CSD information!\n");
- return mmc_return;
- }
-
- if (MMC_CARD_MMC(card)) {
- /* Set the bus width based on host, target capbilities */
- if (cfg->bus_width == DATA_BUS_WIDTH_8BIT && host->caps.bus_width_8bit)
- bus_width = DATA_BUS_WIDTH_8BIT;
- /*
- * Host contoller by default supports 4 bit & 1 bit mode.
- * No need to check for host support here
- */
- else if (cfg->bus_width == DATA_BUS_WIDTH_4BIT)
- bus_width = DATA_BUS_WIDTH_4BIT;
- else
- bus_width = DATA_BUS_WIDTH_1BIT;
-
- /* Set 4/8 bit SDR bus width in controller */
- mmc_return = sdhci_set_bus_width(host, bus_width);
-
- if (mmc_return) {
- dprintf(CRITICAL, "Failed to set bus width for host controller\n");
- return 1;
- }
-
- /* Enable high speed mode in the follwing order:
- * 1. HS400 mode if supported by host & card
- * 1. HS200 mode if supported by host & card
- * 2. DDR mode host, if supported by host & card
- * 3. Use normal speed mode with supported bus width
- */
- if (host->caps.hs400_support && mmc_card_supports_hs400_mode(card)) {
- dprintf(INFO, "SDHC Running in HS400 mode\n");
- mmc_return = mmc_set_hs400_mode(host, card, bus_width);
- if (mmc_return) {
- dprintf(
- CRITICAL, "Failure to set HS400 mode for Card(RCA:%x)\n",
- card->rca);
- return mmc_return;
- }
- }
- else if (
- (FeaturePcdGet(PcdMmcHs200Caps) &&
- (host->caps.hs200_support && host->caps.sdr104_support &&
- mmc_card_supports_hs200_mode(card))) ||
- (!FeaturePcdGet(PcdMmcHs200Caps) &&
- (host->caps.sdr104_support && mmc_card_supports_hs200_mode(card)))) {
- dprintf(INFO, "SDHC Running in HS200 mode\n");
- mmc_return = mmc_set_hs200_mode(host, card, bus_width);
-
- if (mmc_return) {
- dprintf(
- CRITICAL, "Failure to set HS200 mode for Card(RCA:%x)\n",
- card->rca);
- return mmc_return;
- }
- }
- else if (host->caps.ddr_support && mmc_card_supports_ddr_mode(card)) {
- dprintf(INFO, "SDHC Running in DDR mode\n");
- mmc_return = mmc_set_ddr_mode(host, card);
-
- if (mmc_return) {
- dprintf(
- CRITICAL, "Failure to set DDR mode for Card(RCA:%x)\n", card->rca);
- return mmc_return;
- }
- }
- else {
- dprintf(INFO, "SDHC Running in High Speed mode\n");
- /* Set HS_TIMING mode */
- mmc_return = mmc_set_hs_interface(host, card);
- if (mmc_return) {
- dprintf(
- CRITICAL, "Failure to enalbe HS mode for Card(RCA:%x)\n",
- card->rca);
- return mmc_return;
- }
- /* Set wide bus mode */
- mmc_return = mmc_set_bus_width(host, card, bus_width);
- if (mmc_return) {
- dprintf(
- CRITICAL, "Failure to set wide bus for Card(RCA:%x)\n", card->rca);
- return mmc_return;
- }
- }
- }
- else {
- /* Check the supported bus width for the card from SCR register */
- if (card->scr.bus_widths & SD_SCR_WIDTH_4BIT)
- bus_width = DATA_BUS_WIDTH_4BIT;
- else
- bus_width = DATA_BUS_WIDTH_1BIT;
-
- mmc_return = mmc_sd_set_bus_width(host, card, bus_width);
- if (mmc_return) {
- dprintf(CRITICAL, "Failed to set bus width for the card\n");
- return mmc_return;
- }
-
- /* Set bit SDR bus width in controller */
- mmc_return = sdhci_set_bus_width(host, bus_width);
- if (mmc_return) {
- dprintf(CRITICAL, "Failed to set bus width for host controller\n");
- return mmc_return;
- }
- }
-
- card->block_size = MMC_BLK_SZ;
-
- /* Enable RST_n_FUNCTION */
- if (MMC_CARD_MMC(card) && !card->ext_csd[MMC_EXT_CSD_RST_N_FUNC]) {
- mmc_return = mmc_switch_cmd(
- host, card, MMC_SET_BIT, MMC_EXT_CSD_RST_N_FUNC, RST_N_FUNC_ENABLE);
-
- if (mmc_return) {
- dprintf(CRITICAL, "Failed to enable RST_n_FUNCTION\n");
- return mmc_return;
- }
- }
-
- return mmc_return;
-}
-
-/*
- * Function: mmc display csd
- * Arg : None
- * Return : None
- * Flow : Displays the csd information
- */
-static void mmc_display_csd(struct mmc_card *card)
-{
- dprintf(SPEW, "erase_grpsize: %d\n", card->csd.erase_grp_size);
- dprintf(SPEW, "erase_grpmult: %d\n", card->csd.erase_grp_mult);
- dprintf(SPEW, "wp_grpsize: %d\n", card->csd.wp_grp_size);
- dprintf(SPEW, "wp_grpen: %d\n", card->csd.wp_grp_enable);
- dprintf(SPEW, "perm_wp: %d\n", card->csd.perm_wp);
- dprintf(SPEW, "temp_wp: %d\n", card->csd.temp_wp);
-}
-
-/*
- * Function: mmc_init
- * Arg : MMC configuration data
- * Return : Pointer to mmc device
- * Flow : Entry point to MMC boot process
- * Initialize the sd host controller
- * Initialize the mmc card
- * Set the clock & high speed mode
- */
-struct mmc_device *mmc_init(struct mmc_config_data *data)
-{
- uint8_t mmc_ret = 0;
- struct mmc_device *dev;
-
- dev = (struct mmc_device *)malloc(sizeof(struct mmc_device));
-
- if (!dev) {
- dprintf(CRITICAL, "Error allocating mmc device\n");
- return NULL;
- }
-
- ASSERT(data);
-
- memcpy((void *)&dev->config, (void *)data, sizeof(struct mmc_config_data));
-
- memset((struct mmc_card *)&dev->card, 0, sizeof(struct mmc_card));
- dev->card.slot = data->slot;
-
- /* Initialize the host & clock */
- dprintf(SPEW, " Initializing MMC host data structure and clock!\n");
-
- mmc_ret = mmc_host_init(dev);
- if (mmc_ret) {
- dprintf(CRITICAL, "Error Initializing MMC host : %u\n", mmc_ret);
- return NULL;
- }
-
- /* Initialize and identify cards connected to host */
- mmc_ret = mmc_card_init(dev);
- if (mmc_ret) {
- dprintf(CRITICAL, "Failed detecting MMC/SDC @ slot%d\n", dev->config.slot);
- return NULL;
- }
-
- dprintf(INFO, "Done initialization of the card\n");
-
- mmc_display_csd(&dev->card);
-
- return dev;
-}
-
-static uint32_t mmc_parse_response(uint32_t resp)
-{
- /* Trying to write beyond card capacity */
- if (resp & MMC_R1_ADDR_OUT_OF_RANGE) {
- dprintf(
- CRITICAL, "Attempting to read or write beyond the Device capacity\n");
- return 1;
- }
-
- /* Misaligned address not matching block length */
- if (resp & MMC_R1_ADDR_ERR) {
- dprintf(
- CRITICAL,
- "The misaligned address did not match the block length used\n");
- return 1;
- }
-
- /* Invalid block length */
- if (resp & MMC_R1_BLOCK_LEN_ERR) {
- dprintf(
- CRITICAL, "The transferred bytes does not match the block length\n");
- return 1;
- }
-
- /* Tried to program write protected block */
- if (resp & MMC_R1_WP_VIOLATION) {
- dprintf(CRITICAL, "Attempt to program a write protected block\n");
- return 1;
- }
-
- /* card controller error */
- if (resp & MMC_R1_CC_ERROR) {
- dprintf(
- CRITICAL,
- "Device error occurred, which is not related to the host command\n");
- return 1;
- }
-
- /* Generic error */
- if (resp & MMC_R1_GENERIC_ERR) {
- dprintf(CRITICAL, "A generic Device error\n");
- return 1;
- }
-
- /* Finally check for card in TRAN state */
- if (MMC_CARD_STATUS(resp) != MMC_TRAN_STATE) {
- dprintf(CRITICAL, "MMC card is not in TRAN state\n");
- return 1;
- }
-
- return 0;
-}
-
-static uint32_t mmc_stop_command(struct mmc_device *dev)
-{
- struct mmc_command cmd;
- uint32_t mmc_ret = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- cmd.cmd_index = CMD12_STOP_TRANSMISSION;
- cmd.argument = (dev->card.rca << 16);
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
-
- mmc_ret = sdhci_send_command(&dev->host, &cmd);
- if (mmc_ret) {
- dprintf(CRITICAL, "Failed to send stop command\n");
- return mmc_ret;
- }
-
- /* Response contains 32 bit Card status.
- * Parse the errors & provide relevant information */
-
- return mmc_parse_response(cmd.resp[0]);
-}
-
-/*
- * Function: mmc sdhci read
- * Arg : mmc device structure, block address, number of blocks & destination
- * Return : 0 on Success, non zero on success
- * Flow : Fill in the command structure & send the command
- */
-uint32_t mmc_sdhci_read(
- struct mmc_device *dev, void *dest, uint64_t blk_addr, uint32_t num_blocks)
-{
- uint32_t mmc_ret = 0;
- struct mmc_command cmd;
- struct mmc_card * card = &dev->card;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD17/18 Format:
- * [31:0] Data Address
- */
- if (num_blocks == 1)
- cmd.cmd_index = CMD17_READ_SINGLE_BLOCK;
- else
- cmd.cmd_index = CMD18_READ_MULTIPLE_BLOCK;
-
- /*
- * Standard emmc cards use byte mode addressing
- * convert the block address to byte address before
- * sending the command
- */
- if (card->type == MMC_TYPE_STD_MMC)
- cmd.argument = blk_addr * card->block_size;
- else
- cmd.argument = blk_addr;
-
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_READ;
- cmd.data_present = 0x1;
-
- /* Use CMD23 If card supports CMD23:
- * For SD card use the value read from SCR register
- * For emmc by default use CMD23.
- * Also as per SDCC spec always use CMD23 to stop
- * multiblock read/write if UHS (Ultra High Speed) is
- * enabled
- */
- if (MMC_CARD_SD(card))
- cmd.cmd23_support = dev->card.scr.cmd23_support;
- else
- cmd.cmd23_support = 0x1;
-
- cmd.data.data_ptr = dest;
- cmd.data.num_blocks = num_blocks;
-
- /* send command */
- mmc_ret = sdhci_send_command(&dev->host, &cmd);
-
- /* For multi block read failures send stop command */
- if (mmc_ret && num_blocks > 1) {
- return mmc_stop_command(dev);
- }
-
- /*
- * Response contains 32 bit Card status.
- * Parse the errors & provide relevant information
- */
- return mmc_parse_response(cmd.resp[0]);
-}
-
-/*
- * Function: mmc sdhci write
- * Arg : mmc device structure, block address, number of blocks & source
- * Return : 0 on Success, non zero on success
- * Flow : Fill in the command structure & send the command
- */
-uint32_t mmc_sdhci_write(
- struct mmc_device *dev, void *src, uint64_t blk_addr, uint32_t num_blocks)
-{
- uint32_t mmc_ret = 0;
- struct mmc_command cmd;
- struct mmc_card * card = &dev->card;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* CMD24/25 Format:
- * [31:0] Data Address
- */
-
- if (num_blocks == 1)
- cmd.cmd_index = CMD24_WRITE_SINGLE_BLOCK;
- else
- cmd.cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
-
- /*
- * Standard emmc cards use byte mode addressing
- * convert the block address to byte address before
- * sending the command
- */
- if (card->type == MMC_TYPE_STD_MMC)
- cmd.argument = blk_addr * card->block_size;
- else
- cmd.argument = blk_addr;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_WRITE;
-
- /* Use CMD23 If card supports CMD23:
- * For SD card use the value read from SCR register
- * For emmc by default use CMD23.
- * Also as per SDCC spec always use CMD23 to stop
- * multiblock read/write if UHS (Ultra High Speed) is
- * enabled
- */
- if (MMC_CARD_SD(card))
- cmd.cmd23_support = dev->card.scr.cmd23_support;
- else
- cmd.cmd23_support = 0x1;
-
- cmd.data_present = 0x1;
- cmd.data.data_ptr = src;
- cmd.data.num_blocks = num_blocks;
-
- /* send command */
- mmc_ret = sdhci_send_command(&dev->host, &cmd);
-
- /* For multi block write failures send stop command */
- if (mmc_ret && num_blocks > 1) {
- return mmc_stop_command(dev);
- }
-
- /*
- * Response contains 32 bit Card status.
- * Parse the errors & provide relevant information
- */
- return mmc_parse_response(cmd.resp[0]);
-}
-
-/*
- * Send the erase group start address using CMD35
- */
-static uint32_t
-mmc_send_erase_grp_start(struct mmc_device *dev, uint32_t erase_start)
-{
- struct mmc_command cmd;
- struct mmc_card * card = &dev->card;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- if (MMC_CARD_MMC(card))
- cmd.cmd_index = CMD35_ERASE_GROUP_START;
- else
- cmd.cmd_index = CMD32_ERASE_WR_BLK_START;
-
- /*
- * Standard emmc cards use byte mode addressing
- * convert the block address to byte address before
- * sending the command
- */
- if (card->type == MMC_TYPE_STD_MMC)
- cmd.argument = erase_start * card->block_size;
- else
- cmd.argument = erase_start;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
-
- /* send command */
- if (sdhci_send_command(&dev->host, &cmd))
- return 1;
-
- /*
- * CMD35 on failure returns address out of range error
- */
- if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
- dprintf(CRITICAL, "Address for CMD35 is out of range\n");
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Send the erase group end address using CMD36
- */
-static uint32_t
-mmc_send_erase_grp_end(struct mmc_device *dev, uint32_t erase_end)
-{
- struct mmc_command cmd;
- struct mmc_card * card = &dev->card;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- if (MMC_CARD_MMC(card))
- cmd.cmd_index = CMD36_ERASE_GROUP_END;
- else
- cmd.cmd_index = CMD33_ERASE_WR_BLK_END;
-
- /*
- * Standard emmc cards use byte mode addressing
- * convert the block address to byte address before
- * sending the command
- */
- if (card->type == MMC_TYPE_STD_MMC)
- cmd.argument = erase_end * card->block_size;
- else
- cmd.argument = erase_end;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
-
- /* send command */
- if (sdhci_send_command(&dev->host, &cmd))
- return 1;
-
- /*
- * CMD3 on failure returns address out of range error
- */
- if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
- dprintf(CRITICAL, "Address for CMD36 is out of range\n");
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Send the erase CMD38, to erase the selected erase groups
- */
-static uint32_t mmc_send_erase(struct mmc_device *dev, uint64_t erase_timeout)
-{
- struct mmc_command cmd;
- uint32_t status;
- uint32_t retry = 0;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- cmd.cmd_index = CMD38_ERASE;
- cmd.argument = 0x00000000;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1B;
- cmd.cmd_timeout = erase_timeout;
-
- /* send command */
- if (sdhci_send_command(&dev->host, &cmd))
- return 1;
-
- do {
- if (mmc_get_card_status(&dev->host, &dev->card, &status)) {
- dprintf(CRITICAL, "Failed to get card status after erase\n");
- return 1;
- }
- /* Check if the response of erase command has eras skip status set */
- if (status & MMC_R1_WP_ERASE_SKIP)
- dprintf(
- CRITICAL,
- "Write Protect set for the region, only partial space was erased\n");
-
- retry++;
- gBS->Stall(1000);
- if (retry == MMC_MAX_CARD_STAT_RETRY) {
- dprintf(
- CRITICAL,
- "Card status check timed out after sending erase command\n");
- return 1;
- }
- } while (!(status & MMC_READY_FOR_DATA) ||
- (MMC_CARD_STATUS(status) == MMC_PROG_STATE));
-
- return 0;
-}
-
-/*
- * Function: mmc sdhci erase
- * Arg : mmc device structure, block address and length
- * Return : 0 on Success, non zero on failure
- * Flow : Fill in the command structure & send the command
- */
-uint32_t
-mmc_sdhci_erase(struct mmc_device *dev, uint32_t blk_addr, uint64_t len)
-{
- uint32_t erase_unit_sz = 0;
- uint32_t erase_start;
- uint32_t erase_end;
- uint32_t blk_end;
- uint32_t num_erase_grps;
- uint64_t erase_timeout = 0;
- struct mmc_card *card;
-
- card = &dev->card;
-
- /*
- * Calculate the erase unit size,
- * 1. Based on emmc 4.5 spec for emmc card
- * 2. Use SD Card Status info for SD cards
- */
- if (MMC_CARD_MMC(card)) {
- /*
- * Calculate the erase unit size as per the emmc specification v4.5
- */
- if (dev->card.ext_csd[MMC_ERASE_GRP_DEF])
- erase_unit_sz =
- (MMC_HC_ERASE_MULT * dev->card.ext_csd[MMC_HC_ERASE_GRP_SIZE]) /
- MMC_BLK_SZ;
- else
- erase_unit_sz = (dev->card.csd.erase_grp_size + 1) *
- (dev->card.csd.erase_grp_mult + 1);
- }
- else
- erase_unit_sz = dev->card.ssr.au_size * dev->card.ssr.num_aus;
-
- /* Convert length in blocks */
- len = len / MMC_BLK_SZ;
-
- if (len < erase_unit_sz) {
- dprintf(CRITICAL, "Requested length is less than min erase group size\n");
- return 1;
- }
-
- /* Calculate erase groups based on the length in blocks */
- num_erase_grps = len / erase_unit_sz;
-
- /* Start address of the erase range */
- erase_start = blk_addr;
-
- /* Last address of the erase range */
- erase_end = blk_addr + ((num_erase_grps - 1) * erase_unit_sz);
-
- /* Boundary check for overlap */
- blk_end = blk_addr + len;
-
- if (erase_end > blk_end) {
- dprintf(CRITICAL, "The erase group overlaps the max requested for erase\n");
- erase_end -= erase_unit_sz;
- }
-
- /* Send CMD35 for erase group start */
- if (mmc_send_erase_grp_start(dev, erase_start)) {
- dprintf(CRITICAL, "Failed to send erase grp start address\n");
- return 1;
- }
-
- /* Send CMD36 for erase group end */
- if (mmc_send_erase_grp_end(dev, erase_end)) {
- dprintf(CRITICAL, "Failed to send erase grp end address\n");
- return 1;
- }
-
- /*
- * As per emmc 4.5 spec section 7.4.27, calculate the erase timeout
- * erase_timeout = 300ms * ERASE_TIMEOUT_MULT * num_erase_grps
- */
- erase_timeout =
- (300 * 1000 * card->ext_csd[MMC_ERASE_TIMEOUT_MULT] * num_erase_grps);
-
- /* Send CMD38 to perform erase */
- if (mmc_send_erase(dev, erase_timeout)) {
- dprintf(CRITICAL, "Failed to erase the specified partition\n");
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Function: mmc get wp status
- * Arg : mmc device structure, block address and buffer for getting wp
- * status Return : 0 on Success, 1 on Failure Flow : Get the WP group status
- * by sending CMD31
- */
-uint32_t
-mmc_get_wp_status(struct mmc_device *dev, uint32_t addr, uint8_t *wp_status)
-{
- struct mmc_command cmd;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- cmd.cmd_index = CMD31_SEND_WRITE_PROT_TYPE;
- cmd.argument = addr;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_READ;
- cmd.data_present = 0x1;
- cmd.data.data_ptr = wp_status;
- cmd.data.num_blocks = 0x1;
- cmd.data.blk_sz = 0x8;
-
- if (sdhci_send_command(&dev->host, &cmd)) {
- dprintf(CRITICAL, "Failed to get status of write protect bits\n");
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Function: mmc set/clear WP on user area
- * Arg : mmc device structure, block address,len, & flag to set or clear
- * Return : 0 on success, 1 on failure
- * Flow : Function to set/clear power on write protect on user area
- */
-
-uint32_t mmc_set_clr_power_on_wp_user(
- struct mmc_device *dev, uint32_t addr, uint64_t len, uint8_t set_clr)
-{
- struct mmc_command cmd;
- struct mmc_card * card = &dev->card;
- uint32_t wp_grp_size;
- uint32_t status;
- uint32_t num_wp_grps;
- uint32_t ret;
- uint32_t retry = 0;
- uint32_t i;
-
- memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
-
- /* Convert len into blocks */
- len = len / MMC_BLK_SZ;
- wp_grp_size = dev->card.wp_grp_size;
-
- /* Disable PERM WP */
- ret = mmc_switch_cmd(
- &dev->host, &dev->card, MMC_SET_BIT, MMC_USR_WP, MMC_US_PERM_WP_DIS);
-
- if (ret) {
- dprintf(CRITICAL, "Failed to Disable PERM WP\n");
- return ret;
- }
-
- /* Read the default values for user WP */
- ret = mmc_get_ext_csd(&dev->host, &dev->card);
-
- if (ret) {
- dprintf(CRITICAL, "Failed to read ext csd for the card\n");
- return ret;
- }
-
- /* Check if user power on WP is disabled or perm WP is enabled */
- if ((dev->card.ext_csd[MMC_USR_WP] & MMC_US_PWR_WP_DIS) ||
- (dev->card.ext_csd[MMC_USR_WP] & MMC_US_PERM_WP_EN)) {
- dprintf(CRITICAL, "Power on protection is disabled, cannot be set\n");
- return 1;
- }
-
- if (len < wp_grp_size) {
- dprintf(CRITICAL, "Length is less than min WP size, WP was not set\n");
- return 1;
- }
-
- /* Set power on USER WP */
- ret = mmc_switch_cmd(
- &dev->host, &dev->card, MMC_SET_BIT, MMC_USR_WP, MMC_US_PWR_WP_EN);
-
- if (ret) {
- dprintf(CRITICAL, "Failed to set power on WP for user\n");
- return ret;
- }
-
- num_wp_grps = ROUNDUP(len, wp_grp_size) / wp_grp_size;
-
- if (set_clr)
- cmd.cmd_index = CMD28_SET_WRITE_PROTECT;
- else
- cmd.cmd_index = CMD29_CLEAR_WRITE_PROTECT;
-
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1B;
-
- for (i = 0; i < num_wp_grps; i++) {
- /*
- * Standard emmc cards use byte mode addressing
- * convert the block address to byte address before
- * sending the command
- */
- if (card->type == MMC_TYPE_STD_MMC)
- cmd.argument = (addr + (i * wp_grp_size)) * card->block_size;
- else
- cmd.argument = addr + (i * wp_grp_size);
-
- if (sdhci_send_command(&dev->host, &cmd))
- return 1;
-
- /* CMD28/CMD29 On failure returns address out of range error */
- if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
- dprintf(CRITICAL, "Address for CMD28/29 is out of range\n");
- return 1;
- }
-
- /* Check the card status */
- do {
- if (mmc_get_card_status(&dev->host, &dev->card, &status)) {
- dprintf(
- CRITICAL,
- "Failed to get card status afterapplying write protect\n");
- return 1;
- }
-
- /* Time out for WP command */
- retry++;
- gBS->Stall(1000);
- if (retry == MMC_MAX_CARD_STAT_RETRY) {
- dprintf(
- CRITICAL,
- "Card status timed out after sending write protect command\n");
- return 1;
- }
- } while (!(status & MMC_READY_FOR_DATA) ||
- (MMC_CARD_STATUS(status) == MMC_PROG_STATE));
- }
-
- return 0;
-}
-
-/* Function to put the mmc card to sleep and disable HC */
-void mmc_put_card_to_sleep_disable_hc(struct mmc_device *dev)
-{
- mmc_put_card_to_sleep(dev);
- sdhci_mode_disable(&dev->host);
-}
-
-/* Function to put the mmc card to sleep */
-void mmc_put_card_to_sleep(struct mmc_device *dev)
-{
- struct mmc_command cmd = {0};
- struct mmc_card * card = &dev->card;
-
- cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
- cmd.argument = 0x00000000;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_NONE;
-
- /* send command */
- if (sdhci_send_command(&dev->host, &cmd)) {
- dprintf(CRITICAL, "card deselect error: %s\n", __func__);
- return;
- }
-
- cmd.cmd_index = CMD5_SLEEP_AWAKE;
- cmd.argument = (card->rca << MMC_CARD_RCA_BIT) | MMC_CARD_SLEEP;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1B;
-
- /* send command */
- if (sdhci_send_command(&dev->host, &cmd))
- dprintf(CRITICAL, "card sleep error: %s\n", __func__);
-}
-
-/*
- * Switch the partition access type to rpmb or default
- */
-static uint32_t mmc_sdhci_switch_part(struct mmc_device *dev, uint32_t type)
-{
- uint32_t part_access;
- uint32_t ret;
-
- /* Clear the partition access */
- part_access =
- dev->card.ext_csd[MMC_PARTITION_CONFIG] & ~PARTITION_ACCESS_MASK;
- part_access |= type;
-
- ret = mmc_switch_cmd(
- &dev->host, &dev->card, MMC_ACCESS_WRITE, MMC_PARTITION_CONFIG,
- part_access);
-
- if (ret) {
- dprintf(CRITICAL, "Failed to switch partition to type: %u\n", type);
- return 1;
- }
-
- dev->card.ext_csd[MMC_PARTITION_CONFIG] = part_access;
- return 0;
-}
-
-static uint32_t mmc_sdhci_set_blk_cnt(
- struct mmc_device *dev, uint32_t blk_cnt, uint32_t rel_write)
-{
- struct mmc_command cmd = {0};
-
- cmd.cmd_index = CMD23_SET_BLOCK_COUNT;
- cmd.argument = blk_cnt & 0x0000ffff;
- cmd.argument |= rel_write;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
-
- if (sdhci_send_command(&dev->host, &cmd)) {
- dprintf(CRITICAL, "Set block count failed: %s\n", __func__);
- return 1;
- }
-
- return 0;
-}
-
-uint32_t mmc_sdhci_rpmb_send(struct mmc_device *dev, struct mmc_command *cmd)
-{
- int i;
- uint32_t retry = 5;
- uint32_t status;
- uint32_t rel_write = 0;
- uint32_t ret = 1;
-
- ASSERT(cmd);
-
- /* 1. Set the partition type to rpmb */
- if (mmc_sdhci_switch_part(dev, PART_ACCESS_RPMB))
- return 1;
-
- for (i = 0; i < MAX_RPMB_CMDS; i++) {
- if (!cmd[i].cmd_index)
- break;
-
- if (cmd[i].write_flag == true)
- rel_write = BIT(31);
- else
- rel_write = 0;
-
- /* 2. Set the block count using cmd23 */
- if (mmc_sdhci_set_blk_cnt(dev, cmd[i].data.num_blocks, rel_write))
- goto err;
-
- /* 3. Send the command */
- if (sdhci_send_command(&dev->host, &cmd[i]))
- goto err;
- do {
- /* 4. Poll for card status to ensure rpmb operation completeness */
- if (mmc_get_card_status(&dev->host, &dev->card, &status)) {
- dprintf(CRITICAL, "Failed to get card status after rpmb operations\n");
- goto err;
- }
-
- retry--;
- gBS->Stall(500);
- if (!retry) {
- dprintf(
- CRITICAL, "Card status check timed out after rpmb operations\n");
- goto err;
- }
- } while (!(status & MMC_READY_FOR_DATA) ||
- (MMC_CARD_STATUS(status) == MMC_PROG_STATE));
- }
-
- /* If we reach here, that means success */
- ret = 0;
-
-err:
- /* 5. Switch the partition back to default type */
- if (mmc_sdhci_switch_part(dev, PART_ACCESS_DEFAULT))
- ret = 1;
-
- return ret;
-}
+++ /dev/null
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <Library/LKEnvLib.h>
-
-#include <Library/LcmLib.h>
-#include <Library/MallocLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-
-#include <Chipset/sdhci.h>
-
-#include "sdhci_msm.h"
-// Must come in order
-#include "MMCHS.h"
-
-static void sdhci_dumpregs(struct sdhci_host *host)
-{
- DBG("****************** SDHC REG DUMP START ********************\n");
-
- DBG("Version: 0x%08x\n", REG_READ32(host, SDHCI_ARG2_REG));
- DBG("Arg2: 0x%08x\t Blk Cnt: 0x%08x\n",
- REG_READ32(host, SDHCI_ARG2_REG), REG_READ16(host, SDHCI_BLK_CNT_REG));
- DBG("Arg1: 0x%08x\t Blk Sz : 0x%08x\n",
- REG_READ32(host, SDHCI_ARGUMENT_REG), REG_READ16(host, SDHCI_BLKSZ_REG));
- DBG("Command: 0x%08x\t Trans mode: 0x%08x\n",
- REG_READ16(host, SDHCI_CMD_REG), REG_READ16(host, SDHCI_TRANS_MODE_REG));
- DBG("Resp0: 0x%08x\t Resp1: 0x%08x\n",
- REG_READ32(host, SDHCI_RESP_REG), REG_READ32(host, SDHCI_RESP_REG + 0x4));
- DBG("Resp2: 0x%08x\t Resp3: 0x%08x\n",
- REG_READ32(host, SDHCI_RESP_REG + 0x8),
- REG_READ32(host, SDHCI_RESP_REG + 0xC));
- DBG("Prsnt State: 0x%08x\t Host Ctrl1: 0x%08x\n",
- REG_READ32(host, SDHCI_PRESENT_STATE_REG),
- REG_READ8(host, SDHCI_HOST_CTRL1_REG));
- DBG("Timeout ctrl: 0x%08x\t Power Ctrl: 0x%08x\n",
- REG_READ8(host, SDHCI_TIMEOUT_REG), REG_READ8(host, SDHCI_PWR_CTRL_REG));
- DBG("Error stat: 0x%08x\t Int Status: 0x%08x\n",
- REG_READ16(host, SDHCI_ERR_INT_STS_REG),
- REG_READ16(host, SDHCI_NRML_INT_STS_REG));
- DBG("Host Ctrl2: 0x%08x\t Clock ctrl: 0x%08x\n",
- REG_READ16(host, SDHCI_HOST_CTRL2_REG),
- REG_READ16(host, SDHCI_CLK_CTRL_REG));
- DBG("Caps1: 0x%08x\t Caps2: 0x%08x\n",
- REG_READ32(host, SDHCI_CAPS_REG1), REG_READ32(host, SDHCI_CAPS_REG1));
- DBG("Adma Err: 0x%08x\t Auto Cmd err: 0x%08x\n",
- REG_READ8(host, SDHCI_ADM_ERR_REG), REG_READ16(host, SDHCI_AUTO_CMD_ERR));
- DBG("Adma addr1: 0x%08x\t Adma addr2: 0x%08x\n",
- REG_READ32(host, SDHCI_ADM_ADDR_REG),
- REG_READ32(host, SDHCI_ADM_ADDR_REG + 0x4));
-
- DBG("****************** SDHC REG DUMP END ********************\n");
-
- DBG("************* SDHC VENDOR REG DUMPS START ***************\n");
- DBG("SDCC_DLL_CONFIG_REG: 0x%08x\n",
- REG_READ32(host, SDCC_DLL_CONFIG_REG));
- DBG("SDCC_VENDOR_SPECIFIC_FUNC: 0x%08x\n",
- REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC));
- DBG("SDCC_REG_DLL_STATUS: 0x%08x\n",
- REG_READ32(host, SDCC_REG_DLL_STATUS));
- DBG("************* SDHC VENDOR REG DUMPS END ***************\n");
-}
-
-/*
- * Function: sdhci reset
- * Arg : Host structure & mask to write to reset register
- * Return : None
- * Flow: : Reset the host controller
- */
-void sdhci_reset(struct sdhci_host *host, uint8_t mask)
-{
- uint32_t reg;
- uint32_t timeout = SDHCI_RESET_MAX_TIMEOUT;
-
- REG_WRITE8(host, mask, SDHCI_RESET_REG);
-
- /* Wait for the reset to complete */
- do {
- reg = REG_READ8(host, SDHCI_RESET_REG);
- reg &= mask;
-
- if (!reg)
- break;
- if (!timeout) {
- dprintf(CRITICAL, "Error: sdhci reset failed for: %x\n", mask);
- break;
- }
-
- timeout--;
- gBS->Stall(1000);
-
- } while (1);
-}
-
-/*
- * Function: sdhci error status enable
- * Arg : Host structure
- * Return : None
- * Flow: : Enable command error status
- */
-static void sdhci_error_status_enable(struct sdhci_host *host)
-{
- /* Enable all interrupt status */
- REG_WRITE16(host, SDHCI_NRML_INT_STS_EN, SDHCI_NRML_INT_STS_EN_REG);
- REG_WRITE16(host, SDHCI_ERR_INT_STS_EN, SDHCI_ERR_INT_STS_EN_REG);
- /* Enable all interrupt signal */
- REG_WRITE16(host, SDHCI_NRML_INT_SIG_EN, SDHCI_NRML_INT_SIG_EN_REG);
- REG_WRITE16(host, SDHCI_ERR_INT_SIG_EN, SDHCI_ERR_INT_SIG_EN_REG);
-}
-
-/*
- * Function: sdhci clock supply
- * Arg : Host structure
- * Return : 0 on Success, 1 on Failure
- * Flow: : 1. Calculate the clock divider
- * 2. Set the clock divider
- * 3. Check if clock stable
- * 4. Enable Clock
- */
-uint32_t sdhci_clk_supply(struct sdhci_host *host, uint32_t clk)
-{
- uint32_t div = 0;
- uint32_t freq = 0;
- uint16_t clk_val = 0;
-
- if (clk >= host->caps.base_clk_rate)
- goto clk_ctrl;
-
- /* As per the sd spec div should be a multiplier of 2 */
- for (div = 2; div < SDHCI_CLK_MAX_DIV; div += 2) {
- freq = host->caps.base_clk_rate / div;
- if (freq <= clk)
- break;
- }
-
- div >>= 1;
-
-clk_ctrl:
- /* As per the sdhci spec 3.0, bits 6-7 of the clock
- * control registers will be mapped to bit 8-9, to
- * support a 10 bit divider value.
- * This is needed when the divider value overflows
- * the 8 bit range.
- */
- clk_val = ((div & SDHCI_SDCLK_FREQ_MASK) << SDHCI_SDCLK_FREQ_SEL);
- clk_val |= ((div & SDHC_SDCLK_UP_BIT_MASK) >> SDHCI_SDCLK_FREQ_SEL)
- << SDHCI_SDCLK_UP_BIT_SEL;
-
- clk_val |= SDHCI_INT_CLK_EN;
- REG_WRITE16(host, clk_val, SDHCI_CLK_CTRL_REG);
-
- /* Check for clock stable */
- while (!(REG_READ16(host, SDHCI_CLK_CTRL_REG) & SDHCI_CLK_STABLE))
- ;
-
- /* Now clock is stable, enable it */
- clk_val = REG_READ16(host, SDHCI_CLK_CTRL_REG);
- clk_val |= SDHCI_CLK_EN;
- REG_WRITE16(host, clk_val, SDHCI_CLK_CTRL_REG);
-
- host->cur_clk_rate = clk;
-
- DBG("\n %s: clock_rate: %d clock_div:0x%08x\n", __func__, clk, div);
-
- return 0;
-}
-
-/*
- * Function: sdhci set bus power
- * Arg : Host structure
- * Return : None
- * Flow: : 1. Set the voltage
- * 2. Set the sd power control register
- */
-static void sdhci_set_bus_power_on(struct sdhci_host *host)
-{
- uint8_t voltage;
-
- voltage = host->caps.voltage;
-
- voltage <<= SDHCI_BUS_VOL_SEL;
- REG_WRITE8(host, voltage, SDHCI_PWR_CTRL_REG);
-
- voltage |= SDHCI_BUS_PWR_EN;
-
- DBG("\n %s: voltage: 0x%02x\n", __func__, voltage);
-
- REG_WRITE8(host, voltage, SDHCI_PWR_CTRL_REG);
-}
-
-/*
- * Function: sdhci set SDR mode
- * Arg : Host structure, UHS mode
- * Return : None
- * Flow: : 1. Disable the clock
- * 2. Enable UHS mode
- * 3. Enable the clock
- * Details : SDR50/SDR104 mode is nothing but HS200
- * mode SDCC spec refers to it as SDR mode
- * & emmc spec refers as HS200 mode.
- */
-void sdhci_set_uhs_mode(struct sdhci_host *host, uint32_t mode)
-{
- uint16_t clk;
- uint16_t ctrl = 0;
- uint32_t clk_val = 0;
-
- /* Disable the clock */
- clk = REG_READ16(host, SDHCI_CLK_CTRL_REG);
- clk &= ~SDHCI_CLK_EN;
- REG_WRITE16(host, clk, SDHCI_CLK_CTRL_REG);
-
- ctrl = REG_READ16(host, SDHCI_HOST_CTRL2_REG);
-
- ctrl &= ~SDHCI_UHS_MODE_MASK;
-
- /* Enable SDR50/SDR104/DDR50 mode */
- switch (mode) {
- case SDHCI_SDR104_MODE:
- ctrl |= SDHCI_SDR104_MODE_EN;
- clk_val = SDHCI_CLK_200MHZ;
- break;
- case SDHCI_SDR50_MODE:
- ctrl |= SDHCI_SDR50_MODE_EN;
- clk_val = SDHCI_CLK_100MHZ;
- break;
- case SDHCI_DDR50_MODE:
- ctrl |= SDHCI_DDR50_MODE_EN;
- clk_val = SDHCI_CLK_50MHZ;
- break;
- case SDHCI_SDR25_MODE:
- ctrl |= SDHCI_SDR25_MODE_EN;
- clk_val = SDHCI_CLK_50MHZ;
- break;
- case SDHCI_SDR12_MODE_EN:
- ctrl |= SDHCI_SDR12_MODE_EN;
- clk_val = SDHCI_CLK_25MHZ;
- break;
- default:
- dprintf(CRITICAL, "Error: Invalid UHS mode: %x\n", mode);
- ASSERT(0);
- };
-
- REG_WRITE16(host, ctrl, SDHCI_HOST_CTRL2_REG);
-
- /* Run the clock back */
- sdhci_clk_supply(host, clk_val);
-}
-
-/*
- * Function: sdhci set adma mode
- * Arg : Host structure
- * Return : None
- * Flow: : Set adma mode
- */
-static void sdhci_set_adma_mode(struct sdhci_host *host)
-{
- /* Select 32 Bit ADMA2 type */
- REG_WRITE8(host, SDHCI_ADMA_32BIT, SDHCI_HOST_CTRL1_REG);
-}
-
-/*
- * Function: sdhci set bus width
- * Arg : Host & width
- * Return : 0 on Sucess, 1 on Failure
- * Flow: : Set the bus width for controller
- */
-uint8_t sdhci_set_bus_width(struct sdhci_host *host, uint16_t width)
-{
- uint16_t reg = 0;
-
- reg = REG_READ8(host, SDHCI_HOST_CTRL1_REG);
-
- switch (width) {
- case DATA_BUS_WIDTH_8BIT:
- width = SDHCI_BUS_WITDH_8BIT;
- break;
- case DATA_BUS_WIDTH_4BIT:
- width = SDHCI_BUS_WITDH_4BIT;
- break;
- case DATA_BUS_WIDTH_1BIT:
- width = SDHCI_BUS_WITDH_1BIT;
- break;
- default:
- dprintf(CRITICAL, "Bus width is invalid: %u\n", width);
- return 1;
- }
-
- DBG("\n %s: bus width:0x%04x\n", __func__, width);
-
- REG_WRITE8(host, (reg | width), SDHCI_HOST_CTRL1_REG);
-
- return 0;
-}
-
-/*
- * Function: sdhci command err status
- * Arg : Host structure
- * Return : 0 on Sucess, 1 on Failure
- * Flow: : Look for error status
- */
-static uint8_t sdhci_cmd_err_status(struct sdhci_host *host)
-{
- uint32_t err;
-
- err = REG_READ16(host, SDHCI_ERR_INT_STS_REG);
-
- if (err & SDHCI_CMD_TIMEOUT_MASK) {
- dprintf(CRITICAL, "Error: Command timeout error\n");
- return 1;
- }
- else if (err & SDHCI_CMD_CRC_MASK) {
- dprintf(CRITICAL, "Error: Command CRC error\n");
- return 1;
- }
- else if (err & SDHCI_CMD_END_BIT_MASK) {
- dprintf(CRITICAL, "Error: CMD end bit error\n");
- return 1;
- }
- else if (err & SDHCI_CMD_IDX_MASK) {
- dprintf(CRITICAL, "Error: Command Index error\n");
- return 1;
- }
- else if (err & SDHCI_DAT_TIMEOUT_MASK) {
- dprintf(CRITICAL, "Error: DATA time out error\n");
- return 1;
- }
- else if (err & SDHCI_DAT_CRC_MASK) {
- dprintf(CRITICAL, "Error: DATA CRC error\n");
- return 1;
- }
- else if (err & SDHCI_DAT_END_BIT_MASK) {
- dprintf(CRITICAL, "Error: DATA end bit error\n");
- return 1;
- }
- else if (err & SDHCI_CUR_LIM_MASK) {
- dprintf(CRITICAL, "Error: Current limit error\n");
- return 1;
- }
- else if (err & SDHCI_AUTO_CMD12_MASK) {
- dprintf(CRITICAL, "Error: Auto CMD12 error\n");
- return 1;
- }
- else if (err & SDHCI_ADMA_MASK) {
- dprintf(CRITICAL, "Error: ADMA error\n");
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Function: sdhci command complete
- * Arg : Host & command structure
- * Return : 0 on Sucess, 1 on Failure
- * Flow: : 1. Check for command complete
- * 2. Check for transfer complete
- * 3. Get the command response
- * 4. Check for errors
- */
-static uint8_t
-sdhci_cmd_complete(struct sdhci_host *host, struct mmc_command *cmd)
-{
- uint8_t i;
- uint8_t ret = 0;
- uint8_t need_reset = 0;
- uint64_t retry = 0;
- uint32_t int_status;
- uint32_t trans_complete = 0;
- uint32_t err_status;
- uint64_t max_trans_retry =
- (cmd->cmd_timeout ? cmd->cmd_timeout : SDHCI_MAX_TRANS_RETRY);
-
- do {
- int_status = REG_READ16(host, SDHCI_NRML_INT_STS_REG);
-
- if (int_status & SDHCI_INT_STS_CMD_COMPLETE)
- break;
- else if (int_status & SDHCI_ERR_INT_STAT_MASK && !host->tuning_in_progress)
- goto err;
-
- /*
- * If Tuning is in progress ignore cmd crc, cmd timeout & cmd end bit errors
- */
- if (host->tuning_in_progress) {
- err_status = REG_READ16(host, SDHCI_ERR_INT_STS_REG);
- if ((err_status & SDHCI_CMD_CRC_MASK) ||
- (err_status & SDHCI_CMD_END_BIT_MASK) ||
- err_status & SDHCI_CMD_TIMEOUT_MASK) {
- sdhci_reset(host, (SOFT_RESET_CMD | SOFT_RESET_DATA));
- return 0;
- }
- }
-
- retry++;
- gBS->Stall(1);
- if (retry == SDHCI_MAX_CMD_RETRY) {
- dprintf(CRITICAL, "Error: Command never completed\n");
- ret = 1;
- goto err;
- }
- } while (1);
-
- /* Command is complete, clear the interrupt bit */
- REG_WRITE16(host, SDHCI_INT_STS_CMD_COMPLETE, SDHCI_NRML_INT_STS_REG);
-
- /* Copy the command response,
- * The valid bits for R2 response are 0-119, & but the actual response
- * is stored in bits 8-128. We need to move 8 bits of MSB of each
- * response to register 8 bits of LSB of next response register.
- * As:
- * MSB 8 bits of RESP0 --> LSB 8 bits of RESP1
- * MSB 8 bits of RESP1 --> LSB 8 bits of RESP2
- * MSB 8 bits of RESP2 --> LSB 8 bits of RESP3
- */
- if (cmd->resp_type == SDHCI_CMD_RESP_R2) {
- for (i = 0; i < 4; i++) {
- cmd->resp[i] = REG_READ32(host, SDHCI_RESP_REG + (i * 4));
- cmd->resp[i] <<= SDHCI_RESP_LSHIFT;
-
- if (i != 0)
- cmd->resp[i] |=
- (REG_READ32(host, SDHCI_RESP_REG + ((i - 1) * 4)) >>
- SDHCI_RESP_RSHIFT);
- }
- }
- else
- cmd->resp[0] = REG_READ32(host, SDHCI_RESP_REG);
-
- retry = 0;
-
- /*
- * Clear the transfer complete interrupt
- */
- if (cmd->data_present || cmd->resp_type == SDHCI_CMD_RESP_R1B) {
- do {
- int_status = REG_READ16(host, SDHCI_NRML_INT_STS_REG);
-
- if (int_status & SDHCI_INT_STS_TRANS_COMPLETE) {
- trans_complete = 1;
- break;
- }
- /*
- * Some controllers set the data timout first on issuing an erase & take
- * time to set data complete interrupt. We need to wait hoping the
- * controller would set data complete
- */
- else if (
- int_status & SDHCI_ERR_INT_STAT_MASK && !host->tuning_in_progress &&
- !((REG_READ16(host, SDHCI_ERR_INT_STS_REG) & SDHCI_DAT_TIMEOUT_MASK)))
- goto err;
-
- /*
- * If we are in tuning then we need to wait until Data timeout , Data end
- * or Data CRC error
- */
- if (host->tuning_in_progress) {
- err_status = REG_READ16(host, SDHCI_ERR_INT_STS_REG);
- if ((err_status & SDHCI_DAT_TIMEOUT_MASK) ||
- (err_status & SDHCI_DAT_CRC_MASK)) {
- sdhci_reset(host, (SOFT_RESET_CMD | SOFT_RESET_DATA));
- return 0;
- }
- }
-
- retry++;
- gBS->Stall(1);
- if (retry == max_trans_retry) {
- dprintf(CRITICAL, "Error: Transfer never completed\n");
- ret = 1;
- goto err;
- }
- } while (1);
-
- /* Transfer is complete, clear the interrupt bit */
- REG_WRITE16(host, SDHCI_INT_STS_TRANS_COMPLETE, SDHCI_NRML_INT_STS_REG);
- }
-
-err:
- /* Look for errors */
- int_status = REG_READ16(host, SDHCI_NRML_INT_STS_REG);
-
- if (int_status & SDHCI_ERR_INT_STAT_MASK) {
- /*
- * As per SDHC spec transfer complete has higher priority than data timeout
- * If both transfer complete & data timeout are set then we should ignore
- * data timeout error.
- * ---------------------------------------------------------------------------
- * | Transfer complete | Data timeout error | Meaning of the Status |
- * |--------------------------------------------------------------------------|
- * | 0 | 0 | Interrupted by another factor
- * |
- * |--------------------------------------------------------------------------|
- * | 0 | 1 | Time out occured during
- * transfer|
- * |--------------------------------------------------------------------------|
- * | 1 | Don't Care | Command execution complete |
- * --------------------------------------------------------------------------
- */
- if ((REG_READ16(host, SDHCI_ERR_INT_STS_REG) & SDHCI_DAT_TIMEOUT_MASK) &&
- trans_complete) {
- ret = 0;
- }
- else if (sdhci_cmd_err_status(host)) {
- ret = 1;
- /* Dump sdhc registers on error */
- sdhci_dumpregs(host);
- }
- /* Reset Command & Dat lines on error */
- need_reset = 1;
- }
-
- /* Reset data & command line */
- if (need_reset)
- sdhci_reset(host, (SOFT_RESET_CMD | SOFT_RESET_DATA));
-
- return ret;
-}
-
-/*
- * Function: sdhci prep desc table
- * Arg : Pointer data & length
- * Return : Pointer to desc table
- * Flow: : Prepare the adma table as per the sd spec v 3.0
- */
-static struct desc_entry *sdhci_prep_desc_table(void *data, uint32_t len)
-{
- struct desc_entry *sg_list;
- uint32_t sg_len = 0;
- uint32_t remain = 0;
- uint32_t i;
- uint32_t table_len = 0;
-
- if (len <= SDHCI_ADMA_DESC_LINE_SZ) {
- /* Allocate only one descriptor */
- sg_list = (struct desc_entry *)memalign(
- lcm(4, CACHE_LINE), ROUNDUP(sizeof(struct desc_entry), CACHE_LINE));
-
- if (!sg_list) {
- dprintf(CRITICAL, "Error allocating memory\n");
- ASSERT(0);
- }
-
- sg_list[0].addr = (uint32_t)data;
- sg_list[0].len = (len < SDHCI_ADMA_DESC_LINE_SZ)
- ? len
- : (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
- sg_list[0].tran_att =
- SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA | SDHCI_ADMA_TRANS_END;
-
- sg_len = 1;
- table_len = sizeof(struct desc_entry);
- }
- else {
- /* Calculate the number of entries in desc table */
- sg_len = len / SDHCI_ADMA_DESC_LINE_SZ;
- remain = len - (sg_len * SDHCI_ADMA_DESC_LINE_SZ);
-
- /* Allocate sg_len + 1 entries if there are remaining bytes at the end */
- if (remain)
- sg_len++;
-
- table_len = (sg_len * sizeof(struct desc_entry));
-
- sg_list = (struct desc_entry *)memalign(
- lcm(4, CACHE_LINE), ROUNDUP(table_len, CACHE_LINE));
-
- if (!sg_list) {
- dprintf(CRITICAL, "Error allocating memory\n");
- ASSERT(0);
- }
-
- memset((void *)sg_list, 0, table_len);
-
- /*
- * Prepare sglist in the format:
- * ___________________________________________________
- * |Transfer Len | Transfer ATTR | Data Address |
- * | (16 bit) | (16 bit) | (32 bit) |
- * |_____________|_______________|_____________________|
- */
- for (i = 0; i < (sg_len - 1); i++) {
- sg_list[i].addr = (uint32_t)data;
- /*
- * Length attribute is 16 bit value & max transfer size for one
- * descriptor line is 65536 bytes, As per SD Spec3.0 'len = 0'
- * implies 65536 bytes. Truncate the length to limit to 16 bit
- * range.
- */
- sg_list[i].len = (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
- sg_list[i].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA;
- data += SDHCI_ADMA_DESC_LINE_SZ;
- len -= SDHCI_ADMA_DESC_LINE_SZ;
- }
-
- /* Fill the last entry of the table with Valid & End
- * attributes
- */
- sg_list[sg_len - 1].addr = (uint32_t)data;
- sg_list[sg_len - 1].len = (len < SDHCI_ADMA_DESC_LINE_SZ)
- ? len
- : (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
- sg_list[sg_len - 1].tran_att =
- SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA | SDHCI_ADMA_TRANS_END;
- }
-
- arch_clean_invalidate_cache_range((addr_t)sg_list, table_len);
-
- for (i = 0; i < sg_len; i++) {
- DBG("\n %s: sg_list: addr: 0x%08x len: 0x%04x attr: 0x%04x\n", __func__,
- sg_list[i].addr,
- (sg_list[i].len ? sg_list[i].len : SDHCI_ADMA_DESC_LINE_SZ),
- sg_list[i].tran_att);
- }
-
- return sg_list;
-}
-
-/*
- * Function: sdhci adma transfer
- * Arg : Host structure & command stucture
- * Return : Pointer to desc table
- * Flow : 1. Prepare descriptor table
- * 2. Write adma register
- * 3. Write block size & block count register
- */
-static struct desc_entry *
-sdhci_adma_transfer(struct sdhci_host *host, struct mmc_command *cmd)
-{
- uint32_t num_blks = 0;
- uint32_t sz;
- void * data;
- struct desc_entry *adma_addr;
-
- num_blks = cmd->data.num_blocks;
- data = cmd->data.data_ptr;
-
- /*
- * Some commands send data on DAT lines which is less
- * than SDHCI_MMC_BLK_SZ, in that case trying to read
- * more than the data sent by the card results in data
- * CRC errors. To avoid such errors allow data to pass
- * the required block size, if the block size is not
- * passed use the default value
- */
- if (cmd->data.blk_sz)
- sz = num_blks * cmd->data.blk_sz;
- else
- sz = num_blks * SDHCI_MMC_BLK_SZ;
-
- /* Prepare adma descriptor table */
- adma_addr = sdhci_prep_desc_table(data, sz);
-
- /* Write adma address to adma register */
- REG_WRITE32(host, (uint32_t)adma_addr, SDHCI_ADM_ADDR_REG);
-
- /* Write the block size */
- if (cmd->data.blk_sz)
- REG_WRITE16(host, cmd->data.blk_sz, SDHCI_BLKSZ_REG);
- else
- REG_WRITE16(host, SDHCI_MMC_BLK_SZ, SDHCI_BLKSZ_REG);
-
- /*
- * Set block count in block count register
- */
- REG_WRITE16(host, num_blks, SDHCI_BLK_CNT_REG);
-
- return adma_addr;
-}
-
-/*
- * Function: sdhci send command
- * Arg : Host structure & command stucture
- * Return : 0 on Success, 1 on Failure
- * Flow: : 1. Prepare the command register
- * 2. If data is present, prepare adma table
- * 3. Run the command
- * 4. Check for command results & take action
- */
-uint32_t sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
-{
- uint32_t ret = 0;
- uint8_t retry = 0;
- uint32_t resp_type = 0;
- uint16_t trans_mode = 0;
- uint16_t present_state;
- uint32_t flags;
- struct desc_entry *sg_list = NULL;
-
- DBG("\n %s: START: cmd:%04d, arg:0x%08x, resp_type:0x%04x, data_present:%d\n",
- __func__, cmd->cmd_index, cmd->argument, cmd->resp_type,
- cmd->data_present);
-
- if (cmd->data_present)
- ASSERT(cmd->data.data_ptr);
-
- /*
- * Assert if the data buffer is not aligned to cache
- * line size for read operations.
- * For write operations this function assumes that
- * the cache is already flushed by the caller. As
- * the data buffer we receive for write operation
- * may not be aligned to cache boundary due to
- * certain image formats like sparse image.
- */
- if (cmd->trans_mode == SDHCI_READ_MODE)
- ASSERT(IS_CACHE_LINE_ALIGNED(cmd->data.data_ptr));
-
- do {
- present_state = REG_READ32(host, SDHCI_PRESENT_STATE_REG);
- /* check if CMD & DAT lines are free */
- present_state &= SDHCI_STATE_CMD_DAT_MASK;
-
- if (!present_state)
- break;
- gBS->Stall(1000);
- retry++;
- if (retry == 10) {
- dprintf(CRITICAL, "Error: CMD or DAT lines were never freed\n");
- return 1;
- }
- } while (1);
-
- switch (cmd->resp_type) {
- case SDHCI_CMD_RESP_R1:
- case SDHCI_CMD_RESP_R3:
- case SDHCI_CMD_RESP_R6:
- case SDHCI_CMD_RESP_R7:
- /* Response of length 48 have 32 bits
- * of response data stored in RESP0[0:31]
- */
- resp_type = SDHCI_CMD_RESP_48;
- break;
-
- case SDHCI_CMD_RESP_R2:
- /* Response of length 136 have 120 bits
- * of response data stored in RESP0[0:119]
- */
- resp_type = SDHCI_CMD_RESP_136;
- break;
-
- case SDHCI_CMD_RESP_R1B:
- /* Response of length 48 have 32 bits
- * of response data stored in RESP0[0:31]
- * & set CARD_BUSY status if card is busy
- */
- resp_type = SDHCI_CMD_RESP_48_BUSY;
- break;
-
- case SDHCI_CMD_RESP_NONE:
- resp_type = SDHCI_CMD_RESP_NONE;
- break;
-
- default:
- dprintf(CRITICAL, "Invalid response type for the command\n");
- return 1;
- };
-
- flags = (resp_type << SDHCI_CMD_RESP_TYPE_SEL_BIT);
- flags |= (cmd->data_present << SDHCI_CMD_DATA_PRESENT_BIT);
- flags |= (cmd->cmd_type << SDHCI_CMD_CMD_TYPE_BIT);
-
- /* Enable Command CRC & Index check for commands with response
- * R1, R6, R7 & R1B. Also only CRC check for R2 response
- */
- switch (cmd->resp_type) {
- case SDHCI_CMD_RESP_R1:
- case SDHCI_CMD_RESP_R6:
- case SDHCI_CMD_RESP_R7:
- case SDHCI_CMD_RESP_R1B:
- flags |= (1 << SDHCI_CMD_CRC_CHECK_BIT) | (1 << SDHCI_CMD_IDX_CHECK_BIT);
- break;
- case SDHCI_CMD_RESP_R2:
- flags |= (1 << SDHCI_CMD_CRC_CHECK_BIT);
- break;
- default:
- break;
- };
-
- /* Set the timeout value */
- REG_WRITE8(host, SDHCI_CMD_TIMEOUT, SDHCI_TIMEOUT_REG);
-
- /* Check if data needs to be processed */
- if (cmd->data_present)
- sg_list = sdhci_adma_transfer(host, cmd);
-
- /* Write the argument 1 */
- REG_WRITE32(host, cmd->argument, SDHCI_ARGUMENT_REG);
-
- /* Set the Transfer mode */
- if (cmd->data_present) {
- /* Enable DMA */
- trans_mode |= SDHCI_DMA_EN;
-
- if (cmd->trans_mode == SDHCI_MMC_READ) {
- trans_mode |= SDHCI_READ_MODE;
- if (cmd->cmd_index == CMD21_SEND_TUNING_BLOCK)
- sdhci_msm_toggle_cdr(host, false);
- else
- sdhci_msm_toggle_cdr(host, true);
- }
- else {
- sdhci_msm_toggle_cdr(host, false);
- }
-
- /* Enable auto cmd23 or cmd12 for multi block transfer
- * based on what command card supports
- */
- if (cmd->data.num_blocks > 1) {
- if (cmd->cmd23_support) {
- trans_mode |=
- SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD23_EN | SDHCI_BLK_CNT_EN;
- REG_WRITE32(host, cmd->data.num_blocks, SDHCI_ARG2_REG);
- }
- else
- trans_mode |=
- SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD12_EN | SDHCI_BLK_CNT_EN;
- }
- }
-
- /* Write to transfer mode register */
- REG_WRITE16(host, trans_mode, SDHCI_TRANS_MODE_REG);
-
- /* Write the command register */
- REG_WRITE16(host, SDHCI_PREP_CMD(cmd->cmd_index, flags), SDHCI_CMD_REG);
-
- /* Command complete sequence */
- if (sdhci_cmd_complete(host, cmd)) {
- ret = 1;
- goto err;
- }
-
- /* Invalidate the cache only for read operations */
- if (cmd->trans_mode == SDHCI_MMC_READ) {
- /* Read can be performed on block size < SDHCI_MMC_BLK_SZ, make sure to
- * flush the data only for the read size instead
- */
- arch_invalidate_cache_range(
- (addr_t)cmd->data.data_ptr,
- (cmd->data.blk_sz) ? (cmd->data.num_blocks * cmd->data.blk_sz)
- : (cmd->data.num_blocks * SDHCI_MMC_BLK_SZ));
- }
-
- DBG("\n %s: END: cmd:%04d, arg:0x%08x, resp:0x%08x 0x%08x 0x%08x 0x%08x\n",
- __func__, cmd->cmd_index, cmd->argument, cmd->resp[0], cmd->resp[1],
- cmd->resp[2], cmd->resp[3]);
-err:
- /* Free the scatter/gather list */
- if (sg_list)
- free(sg_list);
-
- return ret;
-}
-
-/*
- * Function: sdhci init
- * Arg : Host structure
- * Return : None
- * Flow: : 1. Reset the controller
- * 2. Read the capabilities register & populate the host
- * controller capabilities for use by other functions
- * 3. Enable the power control
- * 4. Set initial bus width
- * 5. Set Adma mode
- * 6. Enable the error status
- */
-void sdhci_init(struct sdhci_host *host)
-{
- uint32_t caps[2];
- uint32_t version;
- UINTN Index;
- EFI_STATUS Status;
-
- /* Read the capabilities register & store the info */
- caps[0] = REG_READ32(host, SDHCI_CAPS_REG1);
- caps[1] = REG_READ32(host, SDHCI_CAPS_REG2);
-
- DBG("\n %s: Host capability: cap1:0x%08x, cap2: 0x%08x\n", __func__, caps[0],
- caps[1]);
-
- host->caps.base_clk_rate =
- (caps[0] & SDHCI_CLK_RATE_MASK) >> SDHCI_CLK_RATE_BIT;
- host->caps.base_clk_rate *= 1000000;
-
- /* Get the max block length for mmc */
- host->caps.max_blk_len = (caps[0] & SDHCI_BLK_LEN_MASK) >> SDHCI_BLK_LEN_BIT;
-
- /* 8 bit Bus width */
- if (caps[0] & SDHCI_8BIT_WIDTH_MASK)
- host->caps.bus_width_8bit = 1;
-
- /* Adma support */
- if (caps[0] & SDHCI_BLK_ADMA_MASK)
- host->caps.adma_support = 1;
-
- /* Supported voltage */
- if (caps[0] & SDHCI_3_3_VOL_MASK)
- host->caps.voltage = SDHCI_VOL_3_3;
- else if (caps[0] & SDHCI_3_0_VOL_MASK)
- host->caps.voltage = SDHCI_VOL_3_0;
- else if (caps[0] & SDHCI_1_8_VOL_MASK)
- host->caps.voltage = SDHCI_VOL_1_8;
-
- /* DDR mode support */
- host->caps.ddr_support = (caps[1] & SDHCI_DDR50_MODE_MASK) ? 1 : 0;
-
- /* SDR50 mode support */
- host->caps.sdr50_support = (caps[1] & SDHCI_SDR50_MODE_MASK) ? 1 : 0;
-
- /* SDR104 mode support */
- host->caps.sdr104_support = (caps[1] & SDHCI_SDR104_MODE_MASK) ? 1 : 0;
-
- version = readl(host->msm_host->pwrctl_base + MCI_VERSION);
-
- host->major = (version & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT;
- host->minor = (version & CORE_VERSION_MINOR_MASK);
-
- if (host->major == 0x1 && host->minor < 0x34)
- host->use_cdclp533 = true;
- else
- host->use_cdclp533 = false;
-
- /* Set bus power on */
- sdhci_set_bus_power_on(host);
-
- /* Wait for power interrupt to be handled */
- Status = gBS->WaitForEvent(1, &host->sdhc_event, &Index);
- ASSERT_EFI_ERROR(Status);
-
- /* Complete */
- gBS->CloseEvent(&host->sdhc_event);
- host->sdhc_event = NULL;
- host->msm_host->sdhc_event = NULL;
-
- /* Set bus width */
- sdhci_set_bus_width(host, SDHCI_BUS_WITDH_1BIT);
-
- /* Set Adma mode */
- sdhci_set_adma_mode(host);
-
- /*
- * Enable error status
- */
- sdhci_error_status_enable(host);
-}
+++ /dev/null
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <Library/LKEnvLib.h>
-
-#include <Library/InterruptsLib.h>
-#include <Library/MallocLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-
-#include <Chipset/mmc_sdhci.h>
-// Must come in order
-#include <Chipset/sdhci.h>
-
-#include "sdhci_msm.h"
-// Must come in order
-#include "MMCHS.h"
-
-/* SDHCI */
-#define SDCC_MCI_HC_MODE ((UINTN)PcdGet64(PcdSdccMciHcMode))
-#define SDCC_HC_PWRCTL_STATUS_REG ((UINTN)PcdGet64(PcdSdccHcPwrctlStatusReg))
-#define SDCC_HC_PWRCTL_MASK_REG ((UINTN)PcdGet64(PcdSdccHcPwrctlMaskReg))
-#define SDCC_HC_PWRCTL_CLEAR_REG ((UINTN)PcdGet64(PcdSdccHcPwrctlClearReg))
-#define SDCC_HC_PWRCTL_CTL_REG ((UINTN)PcdGet64(PcdSdccHcPwrctlCtlReg))
-
-#define MX_DRV_SUPPORTED_HS200 3
-static bool attempt_cdr_unlock;
-
-/* Known data stored in the card & read during tuning
- * process. 64 bytes for 4bit bus width & 128 bytes
- * of data for 8 bit bus width.
- * These values are derived from HPG
- */
-static const uint32_t tuning_block_64[] = {
- 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE, 0xDDFFDFFF, 0xFBFFFBFF,
- 0xFF7FFFBF, 0xEFBDF777, 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
- 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7};
-
-static const uint32_t tuning_block_128[] = {
- 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC, 0xCC3333CC, 0xFFFFCCCC,
- 0xFFFFEEFF, 0xFFEEEEFF, 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
- 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB, 0x00FFFFFF, 0x00FFFFFF,
- 0xCCFFFF00, 0xCC33CCCC, 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
- 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB, 0xFFFFBBBB, 0xFFFF77FF,
- 0xFF7777FF, 0xEEDDBB77};
-
-/*
- * Function: sdhci int handler
- * Arg : MSM specific data for sdhci
- * Return : 0
- * Flow: : 1. Read the power control mask register
- * 2. Check if bus is ON
- * 3. Write success to ack regiser
- * Details : This is power control interrupt handler.
- * Once we receive the interrupt, we will ack the power control
- * register that we have successfully completed pmic transactions
- */
-static enum handler_return sdhci_int_handler(struct sdhci_msm_data *data)
-{
- uint32_t ack;
- uint32_t status;
-
- /*
- * Read the mask register to check if BUS & IO level
- * interrupts are enabled
- */
- status = readl(data->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG);
-
- if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
- ack = SDCC_HC_BUS_ON_OFF_SUCC;
- if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
- ack |= SDCC_HC_IO_SIG_SUCC;
-
- /* Write success to power control register */
- writel(ack, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
-
- if (data->sdhc_event != NULL) {
- gBS->SignalEvent(data->sdhc_event);
- }
-
- return 0;
-}
-
-/*
- * Function: sdhci clear pending interrupts
- * Arg : MSM specific data for sdhci
- * Return : None
- * Flow: : Clear pending interrupts
- */
-static void sdhci_clear_power_ctrl_irq(struct sdhci_msm_data *data)
-{
- uint32_t irq_ctl;
- uint32_t irq_stat;
-
- /*
- * Read the power control status register to know
- * the status of BUS & IO_HIGH_V
- */
- irq_stat = readl(data->pwrctl_base + SDCC_HC_PWRCTL_STATUS_REG);
-
- /* Clear the power control status */
- writel(irq_stat, (data->pwrctl_base + SDCC_HC_PWRCTL_CLEAR_REG));
-
- /*
- * Handle the pending irq by ack'ing the bus & IO switch
- */
- irq_ctl = readl(data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG);
-
- if (irq_stat & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
- irq_ctl |= SDCC_HC_BUS_ON_OFF_SUCC;
- if (irq_stat & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
- irq_ctl |= SDCC_HC_IO_SIG_SUCC;
-
- writel(irq_ctl, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
-}
-
-/*
- * Function: sdhci msm init
- * Arg : MSM specific config data for sdhci
- * Return : None
- * Flow: : Enable sdhci mode & do msm specific init
- */
-void sdhci_msm_init(struct sdhci_host *host, struct sdhci_msm_data *config)
-{
- uint32_t io_switch;
- uint32_t caps = 0;
- uint32_t version;
-
- REG_WRITE32(host, 0xA1C, SDCC_VENDOR_SPECIFIC_FUNC);
-
- /* Enable sdhc mode */
- RMWREG32(
- (config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT,
- SDHCI_HC_WIDTH, SDHCI_HC_MODE_EN);
-
- /* Set the FF_CLK_SW_RST_DIS to 1 */
- RMWREG32(
- (config->pwrctl_base + SDCC_MCI_HC_MODE), FF_CLK_SW_RST_DIS_START,
- FF_CLK_SW_RST_DIS_WIDTH, 1);
-
- /*
- * Reset the controller
- */
- sdhci_reset(host, SDHCI_SOFT_RESET);
-
- /*
- * Some platforms have same SDC instance shared between emmc & sd card.
- * For such platforms the emmc IO voltage has to be switched from 3.3 to
- * 1.8 for the contoller to work with emmc.
- */
-
- if (config->use_io_switch) {
- io_switch = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC);
- io_switch |= HC_IO_PAD_PWR_SWITCH | HC_IO_PAD_PWR_SWITCH_EN;
- REG_WRITE32(host, io_switch, SDCC_VENDOR_SPECIFIC_FUNC);
- }
-
- /*
- * CORE_SW_RST may trigger power irq if previous status of PWRCTL
- * was either BUS_ON or IO_HIGH. So before we enable the power irq
- * interrupt in GIC (by registering the interrupt handler), we need to
- * ensure that any pending power irq interrupt status is acknowledged
- * otherwise power irq interrupt handler would be fired prematurely.
- */
- sdhci_clear_power_ctrl_irq(config);
-
- /*
- * Register the interrupt handler for pwr irq
- */
- register_int_handler(
- config->pwr_irq, (int_handler)sdhci_int_handler, (void *)config);
-
- unmask_interrupt(config->pwr_irq);
-
- /* Enable pwr control interrupt */
- writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG));
-
- version = readl(host->msm_host->pwrctl_base + MCI_VERSION);
-
- host->major = (version & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT;
- host->minor = (version & CORE_VERSION_MINOR_MASK);
-
- /*
- * For SDCC5 the capabilities registers does not have voltage advertised
- * Override the values using SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0
- */
- if (host->major >= 1 && host->minor != 0x11 && host->minor != 0x12) {
- caps = REG_READ32(host, SDHCI_CAPS_REG1);
-
- if (config->slot == 0x1)
- REG_WRITE32(
- host, (caps | SDHCI_1_8_VOL_MASK),
- SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0);
- else
- REG_WRITE32(
- host, (caps | SDHCI_3_0_VOL_MASK),
- SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0);
- }
-
- config->tuning_done = false;
- config->calibration_done = false;
- host->tuning_in_progress = false;
-}
-
-/*
- * Function: sdhci msm set mci clk
- * Arg : Host structure
- * Return : None
- * Flow: : Set HC_SELECT & HC_SELECT_EN for hs400
- */
-void sdhci_msm_set_mci_clk(struct sdhci_host *host)
-{
- struct sdhci_msm_data *msm_host;
-
- msm_host = host->msm_host;
-
- if (host->timing == MMC_HS400_TIMING) {
- /*
- * If the current tuning mode is HS400 then we should set the MCLK to run
- * the clock @ MCLK/2. Also set HS400 mode in SELECT_IN of vendor specific
- * register
- */
- REG_RMW32(
- host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_HS400_START,
- SDCC_HC_MCLK_HS400_WIDTH, SDCC_HC_MCLK_SEL_HS400);
-
- /* Enable HS400 mode from HC_SELECT_IN bit of VENDOR_SPEC register
- * As the SDCC spec does not have matching mode for HS400
- */
- if (msm_host->tuning_done && !msm_host->calibration_done) {
- REG_RMW32(
- host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_START,
- SDCC_HC_MCLK_SEL_IN_WIDTH, SDCC_HC_MCLK_SEL_IN_HS400);
- REG_RMW32(
- host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_EN_START,
- SDCC_HC_MCLK_SEL_IN_EN_WIDTH, SDCC_HC_MCLK_SEL_IN_EN);
- }
- }
- else {
- /*
- * Set 0x0 mode in SELECT_IN of vendor specific register so that the
- * host control2 register settings from sdhc spec are used for
- * speed mode
- */
- REG_RMW32(
- host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_START,
- SDCC_HC_MCLK_SEL_IN_WIDTH, 0x0);
- REG_RMW32(
- host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_EN_START,
- SDCC_HC_MCLK_SEL_IN_EN_WIDTH, 0x0);
- }
-}
-
-/*
- * Set the value based on sdcc clock frequency
- */
-static void msm_set_dll_freq(struct sdhci_host *host)
-{
- uint32_t reg_val = 0;
-
- /* Set clock freq value based on clock range */
- if (host->cur_clk_rate <= 112000000)
- reg_val = 0x0;
- else if (host->cur_clk_rate <= 125000000)
- reg_val = 0x1;
- else if (host->cur_clk_rate <= 137000000)
- reg_val = 0x2;
- else if (host->cur_clk_rate <= 150000000)
- reg_val = 0x3;
- else if (host->cur_clk_rate <= 162000000)
- reg_val = 0x4;
- else if (host->cur_clk_rate <= 175000000)
- reg_val = 0x5;
- else if (host->cur_clk_rate <= 187000000)
- reg_val = 0x6;
- else if (host->cur_clk_rate <= 200000000)
- reg_val = 0x7;
-
- DBG("\n %s: DLL freq: 0x%08x\n", __func__, reg_val);
-
- REG_RMW32(
- host, SDCC_DLL_CONFIG_REG, SDCC_DLL_CONFIG_MCLK_START,
- SDCC_DLL_CONFIG_MCLK_WIDTH, reg_val);
-}
-
-static void sdhci_dll_clk_enable(struct sdhci_host *host, int enable)
-{
- if (enable) {
- REG_WRITE32(
- host,
- (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) & ~SDCC_DLL_CLOCK_DISABLE),
- SDCC_HC_REG_DLL_CONFIG_2);
- }
- else {
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_CLK_OUT_EN),
- SDCC_DLL_CONFIG_REG);
- REG_WRITE32(
- host,
- (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) | SDCC_DLL_CLOCK_DISABLE),
- SDCC_HC_REG_DLL_CONFIG_2);
- }
-}
-
-/* Initialize DLL (Programmable Delay Line) */
-static uint32_t sdhci_msm_init_dll(struct sdhci_host *host)
-{
- uint32_t pwr_save = 0;
- uint32_t timeout = SDHCI_DLL_TIMEOUT;
- uint32_t dll_cfg2;
- uint32_t mclk_clk_freq = 0;
-
- pwr_save = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & SDCC_DLL_PWR_SAVE_EN;
-
- /* Dll sequence needs additional steps for sdcc core version 42 */
- if (host->major == 1 && host->minor >= 0x42) {
- /* Disable DLL clock before configuring */
- sdhci_dll_clk_enable(host, 0);
- }
-
- /* PWR SAVE to 0 */
- if (pwr_save)
- REG_WRITE32(
- host,
- (REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & ~SDCC_DLL_PWR_SAVE_EN),
- SDCC_VENDOR_SPECIFIC_FUNC);
- /* Set DLL_RST to 1 */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_RESET_EN),
- SDCC_DLL_CONFIG_REG);
- /* Set DLL_PDN to 1 */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PDN_EN),
- SDCC_DLL_CONFIG_REG);
-
- /* Set frequency field in DLL_CONFIG */
- msm_set_dll_freq(host);
-
- /* Configure the mclk freq based on the current clock rate
- * and fll cycle count
- */
- if (host->major == 1 && host->minor >= 0x42) {
- dll_cfg2 = REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2);
- if (dll_cfg2 & SDCC_FLL_CYCLE_CNT)
- mclk_clk_freq = (host->cur_clk_rate / TCXO_FREQ) * 8;
- else
- mclk_clk_freq = (host->cur_clk_rate / TCXO_FREQ) * 4;
-
- REG_WRITE32(
- host,
- ((REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) & ~(0xFF << 10)) |
- (mclk_clk_freq << 10)),
- SDCC_HC_REG_DLL_CONFIG_2);
-
- gBS->Stall(5);
- }
-
- /* Write 0 to DLL_RST */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_RESET_EN),
- SDCC_DLL_CONFIG_REG);
- /* Write 0 to DLL_PDN */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_PDN_EN),
- SDCC_DLL_CONFIG_REG);
-
- /* Set the mclk clock and enable the dll clock */
- if (host->major == 1 && host->minor >= 0x42) {
- msm_set_dll_freq(host);
- sdhci_dll_clk_enable(host, 1);
- }
- /* Write 1 to DLL_EN */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_EN),
- SDCC_DLL_CONFIG_REG);
- /* Write 1 to CLK_OUT_EN */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN),
- SDCC_DLL_CONFIG_REG);
- /* Wait for DLL_LOCK in DLL_STATUS register, wait time 50us */
- while (!((REG_READ32(host, SDCC_REG_DLL_STATUS)) & SDCC_DLL_LOCK_STAT)) {
- gBS->Stall(1);
- timeout--;
- if (!timeout) {
- dprintf(
- CRITICAL, "%s: Failed to get DLL lock: 0x%08x\n", __func__,
- REG_READ32(host, SDCC_REG_DLL_STATUS));
- return 1;
- }
- }
-
- /* Set the powersave back on */
- if (pwr_save)
- REG_WRITE32(
- host,
- (REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) | SDCC_DLL_PWR_SAVE_EN),
- SDCC_VENDOR_SPECIFIC_FUNC);
-
- return 0;
-}
-
-void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
-{
- uint32_t core_cfg;
-
- core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
-
- if (enable) {
- core_cfg |= SDCC_DLL_CDR_EN;
- core_cfg &= ~SDCC_DLL_CDR_EXT_EN;
- }
- else {
- core_cfg &= ~SDCC_DLL_CDR_EN;
- core_cfg |= SDCC_DLL_CDR_EXT_EN;
- }
-
- REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
-}
-
-/* Configure DLL with delay value based on 'phase' */
-static uint32_t sdhci_msm_config_dll(struct sdhci_host *host, uint32_t phase)
-{
- uint32_t core_cfg = 0;
- uint32_t timeout = SDHCI_DLL_TIMEOUT;
-
- /* Gray code values from SWI */
- uint32_t gray_code[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
- 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8};
-
- /* set CDR_EN & CLK_OUT_EN to 0 and
- * CDR_EXT_EN & DLL_EN to 1*/
- core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
- core_cfg &= ~(SDCC_DLL_CDR_EN | SDCC_DLL_CLK_OUT_EN);
- core_cfg |= (SDCC_DLL_CDR_EXT_EN | SDCC_DLL_EN);
- REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
-
- /* Wait until CLK_OUT_EN is 0 */
- while (REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN)
- ;
-
- REG_RMW32(
- host, SDCC_DLL_CONFIG_REG, SDCC_DLL_GRAY_CODE_START,
- SDCC_DLL_GRAY_CODE_WIDTH, gray_code[phase]);
-
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN),
- SDCC_DLL_CONFIG_REG);
-
- /* Wait until CLK_OUT_EN is 1, wait time 50us */
- while (!(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN)) {
- timeout--;
- gBS->Stall(1);
- if (!timeout) {
- dprintf(
- CRITICAL, "%s: clk_out_en timed out: %08x\n", __func__,
- REG_READ32(host, SDCC_DLL_CONFIG_REG));
- return 1;
- }
- }
-
- core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
-
- core_cfg |= SDCC_DLL_CDR_EN;
- core_cfg &= ~SDCC_DLL_CDR_EXT_EN;
-
- REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
-
- return 0;
-}
-
-/*
- * Find the right tuning delay, this function finds the largest
- * consecutive sequence of phases & then selects the 3/4 th of
- * the range which has max entries
- * For eg: If we get the following sequence in phase_table[]
- * (A) phase_table[] = 0x1, 0x2, 0x3, 0x4 , 0x5
- * (B) phase_table[] = 0xA, 0xB, 0xC
- * In the above case the (A) has maximum consecutive entries with '5' entries
- * So delay would be phase_table[(0x5 * 3) / 4] = 0x3
- */
-static int sdhci_msm_find_appropriate_phase(
- struct sdhci_host *host, uint32_t *phase_table, uint32_t total_phases)
-{
- int sub_phases[MAX_PHASES][MAX_PHASES] = {{0}};
- uint32_t phases_per_row[MAX_PHASES] = {0};
- uint32_t i, j;
- int selected_phase = 0;
- uint32_t row_index = 0;
- uint32_t col_index = 0;
- uint32_t phase_15_row_idx = 0;
- uint32_t phases_0_row_idx = 0;
- uint32_t max_phases_3_4_idx = 0;
- uint32_t max_phases = 0;
- uint32_t max_phases_row = 0;
- bool found_loop = false;
-
- if (!phase_table[0] && phase_table[total_phases - 1] == (MAX_PHASES - 1))
- found_loop = true;
-
- for (i = 0; i < total_phases; i++) {
- /* Break the phase table entries into different sub arrays based
- * on the consecutive entries. Each row will have one sub array
- * of consecutive entries.
- * for eg: phase_table [] = { 0x0, 0x1, 0x2, 0xA, 0xB}
- * sub_phases [0][] = { 0x0, 0x1, 0x2}
- * sub_phases [1][] = { 0xA, 0xB}
- */
- sub_phases[row_index][col_index] = phase_table[i];
- phases_per_row[row_index]++;
- col_index++;
-
- /* If we are at the last phase no need to check further */
- if ((i + 1) == total_phases)
- break;
-
- /* If phase_table does not have consecutive entries, move to next entry */
- if (phase_table[i] + 1 != phase_table[i + 1]) {
- row_index++;
- col_index = 0;
- }
- }
-
- if (found_loop && total_phases < MAX_PHASES) {
- /* For consecutive entries we need to consider loops.
- * If the phase_table contains 0x0 & 0xF then we have
- * a loop, the number after 0xF in the sequence would be
- * 0x0.
- * for eg:
- * phase_table = { 0x0, 0x1, 0x2, 0xD, 0xE, 0xF }
- * then
- * sub_phase [0][] = { 0x0, 0x1, 0x2 }
- * sub_phase [1][] = { 0xD, 0xE, 0xF }
- * Since we have a loop here, we need to merge the sub arrays as:
- * sub_phase [1][] = { 0xD, 0xE, 0xF, 0x0, 0x1, 0x2 }
- */
-
- /* The entry 0xF will always be in the last row
- * and entry 0x0 will always be in the first row
- */
- phase_15_row_idx = row_index;
- j = 0;
- for (i = phases_per_row[phase_15_row_idx]; i < MAX_PHASES; i++) {
- sub_phases[phase_15_row_idx][i] = sub_phases[phases_0_row_idx][j];
- if (++j >= phases_per_row[phases_0_row_idx])
- break;
- }
-
- /* Update the number of entries for the sub_phase after the merger */
- phases_per_row[phase_15_row_idx] =
- phases_per_row[phase_15_row_idx] + phases_per_row[phases_0_row_idx];
- phases_per_row[phases_0_row_idx] = 0;
- }
-
- for (i = 0; i <= row_index; i++) {
- if (phases_per_row[i] > max_phases) {
- max_phases = phases_per_row[i];
- max_phases_row = i;
- }
- }
-
- max_phases_3_4_idx = (max_phases * 3) / 4;
- if (max_phases_3_4_idx)
- max_phases_3_4_idx--;
-
- selected_phase = sub_phases[max_phases_row][max_phases_3_4_idx];
-
- return selected_phase;
-}
-
-static uint32_t sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
-{
- uint32_t timeout = 0;
-
- DBG("\n CM_DLL_SDC4 Calibration Start\n");
-
- /*1.Write the DDR config value to SDCC_HC_REG_DDR_CONFIG register*/
- REG_WRITE32(
- host, (UINTN)PcdGet64(PcdMmcSdhciDdrCfgVal), SDCC_HC_REG_DDR_CONFIG);
-
- /*2. Write DDR_CAL_EN to '1' */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) | DDR_CAL_EN),
- SDCC_HC_REG_DLL_CONFIG_2);
-
- /*3. Wait for DLL_LOCK for hs400 to be set */
- timeout = DDR_CAL_TIMEOUT_MAX;
- while (!(REG_READ32(host, SDCC_REG_DLL_STATUS) & DDR_DLL_LOCK_JDR)) {
- timeout--;
- gBS->Stall(1000);
- if (!timeout) {
- dprintf(CRITICAL, "Error: DLL lock for hs400 operation is not set\n");
- return 1;
- }
- }
-
- /*4. Set powersave dll */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_HC_VENDOR_SPECIFIC_FUNC3) | PWRSAVE_DLL),
- SDCC_HC_VENDOR_SPECIFIC_FUNC3);
-
- DBG("\n CM_DLL_SDC4 Calibration Done\n");
-
- return 0;
-}
-
-static uint32_t sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
-{
- uint32_t timeout;
- uint32_t cdc_err;
-
- DBG("\n CDCLP533 Calibration Start\n");
-
- /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~CDC_T4_DLY_SEL),
- SDCC_CDC_DDR200_CFG);
-
- /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC),
- SDCC_CDC_DDR200_CFG);
-
- /* Write 0 to CDC_SWITCH_BYPASS_OFF field in CSR_CDC_GEN_CFG */
- REG_WRITE32(
- host,
- (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) & ~CDC_SWITCH_BYPASS_OFF),
- SDCC_VENDOR_SPEC_CSR_CDC_CFG);
-
- /* Write 1 to CDC_SWITCH_RC_EN field in CSR_CDC_GEN_CFG */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) | CDC_SWITCH_RC_EN),
- SDCC_VENDOR_SPEC_CSR_CDC_CFG);
-
- /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC),
- SDCC_CDC_DDR200_CFG);
-
- /* Perform CDCLP533 initialization sequence
- * SDCC_CSR_CDC_CTRL_CFG0 --> 0x11800EC
- * SDCC_CSR_CDC_CTRL_CFG1 --> 0x3011111
- * SDCC_CSR_CDC_CAL_TIMER_CFG0 --> 0x1201000
- * SDCC_CSR_CDC_CAL_TIMER_CFG1 --> 0x4
- * SDCC_CSR_CDC_REFCOUNT_CFG --> 0xCB732020
- * SDCC_CSR_CDC_COARSE_CAL_CFG --> 0xB19
- * SDCC_CSR_CDC_DELAY_CFG --> 0x4E2
- * SDCC_CDC_OFFSET_CFG --> 0x0
- * SDCC_CDC_SLAVE_DDA_CFG --> 0x16334
- */
-
- REG_WRITE32(host, 0x11800EC, SDCC_CSR_CDC_CTRL_CFG0);
- REG_WRITE32(host, 0x3011111, SDCC_CSR_CDC_CTRL_CFG1);
- REG_WRITE32(host, 0x1201000, SDCC_CSR_CDC_CAL_TIMER_CFG0);
- REG_WRITE32(host, 0x4, SDCC_CSR_CDC_CAL_TIMER_CFG1);
- REG_WRITE32(host, 0xCB732020, SDCC_CSR_CDC_REFCOUNT_CFG);
- REG_WRITE32(host, 0xB19, SDCC_CSR_CDC_COARSE_CAL_CFG);
- REG_WRITE32(host, 0x4E2, SDCC_CSR_CDC_DELAY_CFG);
- REG_WRITE32(host, 0x0, SDCC_CDC_OFFSET_CFG);
- REG_WRITE32(host, 0x16334, SDCC_CDC_SLAVE_DDA_CFG);
-
- /* Write 1 to SW_TRIGGER_FULL_CALIB */
- REG_WRITE32(
- host,
- (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_SW_TRIGGER_FULL_CALIB),
- SDCC_CSR_CDC_CTRL_CFG0);
-
- /* Write 0 to SW_TRIGGER_FULL_CALIB */
- REG_WRITE32(
- host,
- (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) & ~CDC_SW_TRIGGER_FULL_CALIB),
- SDCC_CSR_CDC_CTRL_CFG0);
-
- /* Write 1 to HW_AUTO_CAL_EN */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_HW_AUTO_CAL_EN),
- SDCC_CSR_CDC_CTRL_CFG0);
-
- /* Write 1 to TIMER_ENA */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_CSR_CDC_CAL_TIMER_CFG0) | CDC_TIMER_EN),
- SDCC_CSR_CDC_CAL_TIMER_CFG0);
-
- /* Wait for CALIBRATION_DONE in CDC_STATUS */
- timeout = CDC_STATUS_TIMEOUT;
- while (!(REG_READ32(host, SDCC_CSR_CDC_STATUS0) & BIT(0))) {
- timeout--;
- gBS->Stall(1000);
- if (!timeout) {
- dprintf(CRITICAL, "Error: Calibration done in CDC status not set\n");
- return 1;
- }
- }
-
- cdc_err = REG_READ32(host, SDCC_CSR_CDC_STATUS0) & CSR_CDC_ERROR_MASK;
- if (cdc_err) {
- dprintf(CRITICAL, "CDC error set during calibration: %x\n", cdc_err);
- return 1;
- }
- /* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) | START_CDC_TRAFFIC),
- SDCC_CDC_DDR200_CFG);
-
- DBG("\n CDCLP533 Calibration Done\n");
-
- return 0;
-}
-
-static uint32_t sdhci_msm_hs400_calibration(struct sdhci_host *host)
-{
- DBG("\n HS400 Calibration Start\n");
-
- /* Reset & Initialize the DLL block */
- if (sdhci_msm_init_dll(host))
- return 1;
-
- /* Write the save phase */
- if (sdhci_msm_config_dll(host, host->msm_host->saved_phase))
- return 1;
-
- /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
- REG_WRITE32(
- host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL),
- SDCC_DLL_CONFIG_REG);
-
- if (host->use_cdclp533)
- return sdhci_msm_cdclp533_calibration(host);
- else
- return sdhci_msm_cm_dll_sdc4_calibration(host);
-
- DBG("\n HS400 Calibration Done\n");
-
- return 0;
-}
-
-/*
- * Function: sdhci msm execute tuning
- * Arg : Host structure & bus width
- * Return : 0 on Success, 1 on Failure
- * Flow: : Execute Tuning sequence for HS200 and calibration for hs400
- */
-uint32_t sdhci_msm_execute_tuning(
- struct sdhci_host *host, struct mmc_card *card, uint32_t bus_width)
-{
- uint32_t * tuning_block;
- uint32_t * tuning_data;
- uint32_t tuned_phases[MAX_PHASES] = {0};
- uint32_t size;
- uint32_t phase = 0;
- uint32_t tuned_phase_cnt = 0;
- uint8_t drv_type = 0;
- bool drv_type_changed = false;
- int ret = 0;
- uint32_t i;
- struct sdhci_msm_data *msm_host;
-
- msm_host = host->msm_host;
-
- /* In Tuning mode */
- host->tuning_in_progress = true;
-
- if (bus_width == DATA_BUS_WIDTH_8BIT) {
- tuning_block = (uint32_t *)tuning_block_128;
- size = sizeof(tuning_block_128);
- }
- else {
- tuning_block = (uint32_t *)tuning_block_64;
- size = sizeof(tuning_block_64);
- }
-
- tuning_data = (uint32_t *)memalign(CACHE_LINE, ROUNDUP(size, CACHE_LINE));
-
- ASSERT(tuning_data);
-
- /* Calibration for CDCLP533 needed for HS400 mode */
- if (msm_host->tuning_done && !msm_host->calibration_done &&
- host->timing == MMC_HS400_TIMING) {
- ret = sdhci_msm_hs400_calibration(host);
- if (!ret)
- msm_host->calibration_done = true;
- goto out;
- }
-
- /* Reset & Initialize the DLL block */
- if (sdhci_msm_init_dll(host)) {
- ret = 1;
- goto out;
- }
-
-retry_tuning:
- tuned_phase_cnt = 0;
- phase = 0;
- struct mmc_command cmd = {0};
-
- while (phase < MAX_PHASES) {
- /* configure dll to set phase delay */
- if (sdhci_msm_config_dll(host, phase)) {
- ret = 1;
- goto out;
- }
-
- cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
- cmd.argument = 0x0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_READ;
- cmd.data_present = 0x1;
- cmd.data.data_ptr = tuning_data;
- cmd.data.blk_sz = size;
- cmd.data.num_blocks = 0x1;
-
- /* send command */
- if (!sdhci_send_command(host, &cmd) &&
- !memcmp(tuning_data, tuning_block, size))
- tuned_phases[tuned_phase_cnt++] = phase;
-
- phase++;
- }
-
- /*
- * Check if all the tuning phases passed */
- if (tuned_phase_cnt == MAX_PHASES) {
- /* Change the driver type & rerun tuning */
- while (++drv_type <= MX_DRV_SUPPORTED_HS200) {
- drv_type_changed = mmc_set_drv_type(host, card, drv_type);
- if (drv_type_changed) {
- goto retry_tuning;
- }
- }
- }
-
- /* Restore the driver strength to default value */
- if (drv_type_changed)
- mmc_set_drv_type(host, card, 0);
-
- if (tuned_phase_cnt == MAX_PHASES) {
- attempt_cdr_unlock = true;
- dprintf(
- CRITICAL,
- "WARNING: All phase passed.The selected phase may not be optimal\n");
- }
-
- /* Find the appropriate tuned phase */
- if (tuned_phase_cnt) {
- DBG("\n Tuned phase\n");
- for (i = 0; i < tuned_phase_cnt; i++) {
- DBG("%d\t", tuned_phases[i]);
- }
-
- ret = sdhci_msm_find_appropriate_phase(host, tuned_phases, tuned_phase_cnt);
-
- if (ret < 0) {
- dprintf(CRITICAL, "Failed in selecting the tuning phase\n");
- ret = 1;
- goto out;
- }
-
- phase = (uint32_t)ret;
- ret = 0;
-
- DBG("\n: %s: Tuned Phase: 0x%08x\n", __func__, phase);
-
- if (sdhci_msm_config_dll(host, phase))
- goto out;
-
- /* Save the tuned phase */
- host->msm_host->saved_phase = phase;
- }
- else {
- dprintf(CRITICAL, "Failed to get tuned phase\n");
- ret = 1;
- }
-
-out:
- /* If all the tuning phases passed, send CMD21 after enabling
- * CDR to make sure right tuning phase is selected by CDR
- */
- if (attempt_cdr_unlock) {
- cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
- cmd.argument = 0x0;
- cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
- cmd.resp_type = SDHCI_CMD_RESP_R1;
- cmd.trans_mode = SDHCI_MMC_READ;
- cmd.data_present = 0x1;
- cmd.data.data_ptr = tuning_data;
- cmd.data.blk_sz = size;
- cmd.data.num_blocks = 0x1;
-
- /* send command */
- if (!sdhci_send_command(host, &cmd)) {
- DBG("\n: %s: Sending CMD21 after CDR enable with default phases fail\n",
- __func__);
- }
- }
-
- free(tuning_data);
- /* Tuning done */
- host->tuning_in_progress = false;
- host->msm_host->tuning_done = true;
- return ret;
-}
-
-/*
- * API to disable HC mode
- */
-void sdhci_mode_disable(struct sdhci_host *host)
-{
- /* Disable HC mode */
- RMWREG32(
- (host->msm_host->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT,
- SDHCI_HC_WIDTH, 0);
-}
+++ /dev/null
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __SDHCI_MSM_H__
-#define __SDHCI_MSM_H__
-
-#include <Chipset/mmc_sdhci.h>
-
-#define SDHCI_HC_START_BIT 0x0
-#define SDHCI_HC_WIDTH 0x1
-
-#define SDCC_MCI_POWER 0x0
-#define CORE_SW_RST_START 0x7
-#define CORE_SW_RST_WIDTH 0x1
-
-/* DLL & CDC registers
- * DLL: Delay Line
- * CDC: Calibrated Delay Circuit
- */
-#define SDCC_DLL_CONFIG_REG 0x100
-#define SDCC_VENDOR_SPECIFIC_FUNC 0x10C
-#define SDCC_REG_DLL_STATUS 0x108
-#define SDCC_CDC_DDR200_CFG 0x184
-#define SDCC_VENDOR_SPEC_CSR_CDC_CFG 0x178
-#define SDCC_CSR_CDC_CTRL_CFG0 0x130
-#define SDCC_CSR_CDC_CTRL_CFG1 0x134
-#define SDCC_CSR_CDC_CAL_TIMER_CFG0 0x138
-#define SDCC_CSR_CDC_CAL_TIMER_CFG1 0x13C
-#define SDCC_CSR_CDC_REFCOUNT_CFG 0x140
-#define SDCC_CSR_CDC_COARSE_CAL_CFG 0x144
-#define SDCC_CSR_CDC_DELAY_CFG 0x150
-#define SDCC_CDC_OFFSET_CFG 0x14C
-#define SDCC_CDC_SLAVE_DDA_CFG 0x160
-#define SDCC_CSR_CDC_STATUS0 0x164
-
-/* Macros for CM_DLL_SDC4 related macros */
-#define SDCC_HC_VENDOR_SPECIFIC_FUNC3 0x1B0
-#define SDCC_HC_REG_DLL_CONFIG_2 0x1B4
-#define SDCC_HC_REG_DDR_CONFIG 0x1B8
-
-#define DDR_CAL_EN BIT(0)
-#define DDR_CAL_TIMEOUT_MAX 50
-#define DDR_DLL_LOCK_JDR BIT(11)
-#define PWRSAVE_DLL BIT(3)
-#define DDR_CONFIG_VAL 0x80040853
-
-/* DLL & CDC helper macros */
-#define SDCC_DLL_PWR_SAVE_EN BIT(1)
-#define SDCC_DLL_LOCK_STAT BIT(7)
-#define SDCC_DLL_EN BIT(16)
-#define SDCC_DLL_CDR_EN BIT(17)
-#define SDCC_DLL_CLK_OUT_EN BIT(18)
-#define SDCC_FLL_CYCLE_CNT BIT(18)
-#define SDCC_DLL_CDR_EXT_EN BIT(19)
-#define SDCC_DLL_CLOCK_DISABLE BIT(21)
-#define SDCC_DLL_PDN_EN BIT(29)
-#define SDCC_DLL_RESET_EN BIT(30)
-#define SDCC_DLL_CONFIG_MCLK_START 0x18
-#define SDCC_DLL_CONFIG_MCLK_WIDTH 0x3
-#define SDCC_DLL_GRAY_CODE_START 0x14
-#define SDCC_DLL_GRAY_CODE_WIDTH 0x4
-#define CMD_DAT_TRACK_SEL BIT(0)
-#define CDC_T4_DLY_SEL BIT(0)
-#define CDC_SWITCH_BYPASS_OFF BIT(0)
-#define CDC_SWITCH_RC_EN BIT(1)
-#define START_CDC_TRAFFIC BIT(6)
-#define FF_CLK_SW_RST_DIS_START 0xD
-#define FF_CLK_SW_RST_DIS_WIDTH 0x1
-#define CDC_SW_TRIGGER_FULL_CALIB BIT(16)
-#define CDC_HW_AUTO_CAL_EN BIT(17)
-#define CDC_TIMER_EN BIT(16)
-#define CSR_CDC_ERROR_MASK 0x7000000
-
-/* SDCC macros for HS400 */
-#define SDCC_HC_MCLK_SEL_HS400 0x3
-#define SDCC_HC_MCLK_HS400_START 0x8
-#define SDCC_HC_MCLK_HS400_WIDTH 0x2
-#define SDCC_HC_MCLK_SEL_IN_HS400 0x6
-#define SDCC_HC_MCLK_SEL_IN_DFLT 0x2
-#define SDCC_HC_MCLK_SEL_IN_UHS 0x4
-#define SDCC_HC_MCLK_SEL_IN_START 0x13
-#define SDCC_HC_MCLK_SEL_IN_WIDTH 0x3
-#define SDCC_HC_MCLK_SEL_IN_EN 0x1
-#define SDCC_HC_MCLK_SEL_IN_EN_START 0x12
-#define SDCC_HC_MCLK_SEL_IN_EN_WIDTH 0x1
-
-#define MAX_PHASES 16
-
-/* SDCC version macros */
-#define MCI_VERSION 0x50
-#define CORE_VERSION_MAJOR_MASK 0xF0000000
-#define CORE_VERSION_MAJOR_SHIFT 0x1C
-#define CORE_VERSION_MINOR_MASK 0x000000FF
-
-#define SDHCI_DLL_TIMEOUT 50
-#define CDC_STATUS_TIMEOUT 50
-
-#define HC_IO_PAD_PWR_SWITCH_EN BIT(15)
-#define HC_IO_PAD_PWR_SWITCH BIT(16)
-
-#define SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0 0x11C
-
-#define TCXO_FREQ 19200000
-
-struct sdhci_msm_data {
- uint32_t pwrctl_base;
- uint32_t pwr_irq;
- uint8_t tuning_done;
- uint8_t calibration_done;
- uint8_t saved_phase;
- uint8_t slot;
- uint8_t use_io_switch;
- EFI_EVENT sdhc_event;
-};
-
-void sdhci_msm_init(struct sdhci_host *host, struct sdhci_msm_data *data);
-uint32_t sdhci_msm_execute_tuning(
- struct sdhci_host *host, struct mmc_card *card, uint32_t bus_width);
-void sdhci_mode_disable(struct sdhci_host *host);
-/* API: Toggle the bit for clock-data recovery */
-void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable);
-void sdhci_msm_set_mci_clk(struct sdhci_host *host);
-#endif
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 26)!\86v\ eÈA :*òü\1c9â\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2|Þa\9e'\99(O\9f=2\a\ 5Ø\18\ 1\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 2ÐÇåô9ÒËGªÍ\7ffïv28\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\b
\ No newline at end of file
+++ /dev/null
-\ 2B¹7®\7fE\91L¡\96Ùf\9fÓG£\ 2k0_ú}ôÄJ¤}\88/\82\ 4ì0\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 2i\ 4v°\f\97zH¤µ(Û{EÎñ\ 2ÐÇåô9ÒËGªÍ\7ffïv28\ 2E\z\15²!ÅCº|\82/î_å\99\ 2\8e\b\97ëßÏÆI¾KÙ\ 6¥²\ e\86\ 3\ 3\ 3\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
+++ /dev/null
-\ 6\b
\ No newline at end of file
SECTION UI = "ChipInfo"\r
}\r
\r
- #FILE DRIVER = 7a32bd23-f735-4f57-aa1a-447d2fe3be0d {\r
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/beryllium/SPI/SPI.depex\r
- # SECTION PE32 = sdm845Pkg/Binary/beryllium/SPI/SPI.efi\r
- # SECTION UI = "SPI"\r
- #}\r
-\r
\r
#\r
# USB Host Support\r
INF EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
INF EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
- # FILE DRIVER = af9763a2-033b-4109-8e17-56a98d380c92 {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/HWIODxeDriver/HWIODxeDriver.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/HWIODxeDriver/HWIODxeDriver.efi
- # SECTION UI = "HWIODxeDriver"
- # }
-
- # FILE DRIVER = 4db5dea6-5302-4d1a-8a82-677a683b0d29 {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/ClockDxe/ClockDxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/ClockDxe/ClockDxe.efi
- # SECTION UI = "ClockDxe"
- # }
-
- # FILE DRIVER = 5776232e-082d-4b75-9a0e-fe1d13f7a5d9 {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/PmicDxe/PmicDxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/PmicDxe/PmicDxe.efi
- # SECTION UI = "PmicDxe"
- # }
-
- # FILE DRIVER = 5bd181db-0487-4f1a-ae73-820e165611b3 {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/ButtonsDxe/ButtonsDxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/ButtonsDxe/ButtonsDxe.efi
- # SECTION UI = "ButtonsDxe"
- # }
-
#
# Multiple Console IO support
#
INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
- # FILE DRIVER = 3299a266-15f0-4346-8318-716336736d3e {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/UsbDeviceDxe/UsbDeviceDxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/UsbDeviceDxe/UsbDeviceDxe.efi
- # SECTION UI = "UsbDeviceDxe"
- # }
-
- # FILE DRIVER = 11faed4c-b21f-4d88-8e48-c4c28a1e50df {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/UsbPwrCtrlDxe/UsbPwrCtrlDxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/UsbPwrCtrlDxe/UsbPwrCtrlDxe.efi
- # SECTION UI = "UsbPwrCtrlDxe"
- # }
-
- # FILE DRIVER = 5af77f10-90df-4e7e-8325-a17ec09d5443 {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/UsbMsdDxe/UsbMsdDxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/UsbMsdDxe/UsbMsdDxe.efi
- # SECTION UI = "UsbMsdDxe"
- # }
-
- # FILE DRIVER = 94f8a6a7-dc34-4101-88c1-99179cceae83 {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/UsbfnDwc3Dxe/UsbfnDwc3Dxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/UsbfnDwc3Dxe/UsbfnDwc3Dxe.efi
- # SECTION UI = "UsbfnDwc3Dxe"
- # }
-
- # FILE DRIVER = cd823a4d-7dec-4531-ae5d-4134fa4127b8 {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/UsbConfigDxe/UsbConfigDxe.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/UsbConfigDxe/UsbConfigDxe.efi
- # SECTION UI = "UsbConfigDxe"
- # }
-
- #
- # GPIO
- #
#
# Virtual Keyboard
SECTION UI = "UFSDxe"
}
- # FILE DRIVER = 2a7b4bef-80cd-49e1-b473-374ba4d673fc {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/SPMI/SPMI.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/SPMI/SPMI.efi
- # SECTION UI = "SPMI"
- # }
-
FILE DRIVER = f541d663-4a48-40aa-aabf-ff158ccae34c {
SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/SmemDxe/SmemDxe.depex
SECTION PE32 = sdm845Pkg/Binary/polaris/SmemDxe/SmemDxe.efi
SECTION UI = "SmemDxe"
}
-
- # FILE DRIVER = 10e193df-9966-44e7-b17c-59dd831e20fc {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/ChipInfo/ChipInfo.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/ChipInfo/ChipInfo.efi
- # SECTION UI = "ChipInfo"
- # }
-
- # FILE DRIVER = 7a32bd23-f735-4f57-aa1a-447d2fe3be0d {
- # SECTION DXE_DEPEX = sdm845Pkg/Binary/polaris/SPI/SPI.depex
- # SECTION PE32 = sdm845Pkg/Binary/polaris/SPI/SPI.efi
- # SECTION UI = "SPI"
- # }
-
#
# USB Host Support