From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by mx.groups.io with SMTP id smtpd.web12.1208.1588197065853656041 for ; Wed, 29 Apr 2020 14:51:06 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=hovRFJBE; spf=pass (domain: nuviainc.com, ip: 209.85.128.67, mailfrom: leif@nuviainc.com) Received: by mail-wm1-f67.google.com with SMTP id k12so3698319wmj.3 for ; Wed, 29 Apr 2020 14:51:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=Bs5/prYGC5QAGa2kk1/9F/XRAcDgmtGXWZW3UMhc4x8=; b=hovRFJBEZ27A3RuayW2OAhSviV9IVi6mlQAWo9WMdtlS0Y4FujRR06Ywpfv07ALmJG /XlRLFDod+tFzTJz+lRcKbf6dMz+KNxKXrDIqkNtNpJjMkB4xbhnLlpuLgGN24hDAfN8 L5Dhq4gfMfhNWVALO0xrmt+Lt+OfK4dvduUB3cXu6+OYJLNKVQ/NSfkYbX2JY0RkyY4g v4jyqS7Gr9sG1Q3Zmhvhg2iatTwfPEFXoIbAL/kLelZy6Gq2/jtHjigETubZr+cWcXxY IZzCKlMqJDrx2wZ96j82f7zya4cTzUNqmjpkflOEEoASiMsGC3UYoIFNoi9r6AZJQpYP fLuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=Bs5/prYGC5QAGa2kk1/9F/XRAcDgmtGXWZW3UMhc4x8=; b=DBmjW0Nb69Cpubg9a2JjbBvXjLRz0KtcUAfshlUDWx124uVKNKMpHJgxkcieunw9ZH KW4EWVQIVb17ST1pxbossZW5h7MczHI+/oDytWYJnvC3ZLxoIoVGu7LAT1yYPQgsFlpn K+a4Zivo+Qujq9sCIrhNV96YsntgmRhs+liYI+w92jMDyjCK2fz7pIqARN9lAkqEZKi0 0PjF3gp+T7XE0S0XgXZvysP6o6+cvCSdmsxSkXiGP/lbYUN2REGIWS8hxk7hlZ98qFxh 12iO0jKdumEK+MsFd2ELuS3m/dUuIv0AzbbIyV2AMNJXtsbiFn8hQp94gmO7ASbxFIaF Fc2Q== X-Gm-Message-State: AGi0Puao3suz4s+U//Dt6b7wI5pe5Q347uTDr2XkJY2WutyNJCjTxmb4 bRxKw8kYQMuoKepix/NJHYzaHw== X-Google-Smtp-Source: APiQypJft7IQtPjt5SWhe9dNJ9u2m6uWDBcZWl7cMkJ+qSZiEYCNZU75pBJlHTz0JFZmzTSdM/GSCA== X-Received: by 2002:a1c:7212:: with SMTP id n18mr5747424wmc.53.1588197064072; Wed, 29 Apr 2020 14:51:04 -0700 (PDT) Return-Path: Received: from vanye ([2001:470:1f09:12f0:b26e:bfff:fea9:f1b8]) by smtp.gmail.com with ESMTPSA id e21sm928391wrc.1.2020.04.29.14.51.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 14:51:03 -0700 (PDT) Date: Wed, 29 Apr 2020 22:51:01 +0100 From: "Leif Lindholm" To: Ard Biesheuvel Cc: devel@edk2.groups.io Subject: Re: [PATCH edk2-platforms 2/2] Platform/ARM/VExpressPkg: incorporate PL180 driver Message-ID: <20200429215101.GO21486@vanye> References: <20200429184705.20934-1-ard.biesheuvel@arm.com> <20200429184705.20934-2-ard.biesheuvel@arm.com> MIME-Version: 1.0 In-Reply-To: <20200429184705.20934-2-ard.biesheuvel@arm.com> User-Agent: Mutt/1.10.1 (2018-07-13) Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, Apr 29, 2020 at 20:47:05 +0200, Ard Biesheuvel wrote: > The PL180 SD host controller driver is only used on emulated ARM > platforms, uses an obsolete version of the MMC host protocol and > does not adhere to the UEFI driver model. > > Given the above, let's just move it into VExpressPkg where it > belongs. > > Signed-off-by: Ard Biesheuvel I agree with the change, but will want the warning message added wherever we decide in the separate bikeshedding thread. / Leif > --- > Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc | 6 +- > Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf | 2 +- > Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc | 6 +- > Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf | 2 +- > Platform/ARM/VExpressPkg/ArmVExpressPkg.dec | 4 + > Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c | 563 ++++++++++++++++++++ > Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h | 162 ++++++ > Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf | 46 ++ > 8 files changed, 783 insertions(+), 8 deletions(-) > > diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc > index 2f8021d3eabc..6dad31026aa5 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc > +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc > @@ -146,8 +146,8 @@ [PcdsFixedAtBuild.common] > # > # PL180 MMC/SD card controller > # > - gArmPlatformTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 > - gArmPlatformTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 > + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 > + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 > > > # > @@ -249,7 +249,7 @@ [Components.common] > # Multimedia Card Interface > # > EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf > - ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > + Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > > # SMSC LAN 9118 > EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf > diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf > index 082f80d9996d..64da1102ff07 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf > +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf > @@ -103,7 +103,7 @@ [FV.FvMain] > # Multimedia Card Interface > # > INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf > - INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > + INF Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > > # > # Filesystems > diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc > index 63d79a488500..a6f536a33228 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc > +++ b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc > @@ -151,8 +151,8 @@ [PcdsFixedAtBuild.common] > !endif > > ## PL180 MMC/SD card controller > - gArmPlatformTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 > - gArmPlatformTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 > + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 > + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 > > # > # ARM Generic Interrupt Controller > @@ -290,7 +290,7 @@ [Components.common] > # Multimedia Card Interface > # > EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf > - ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > + Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > > # > # Platform Driver > diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf > index 8f49ed3dba3c..f18ead75eaec 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf > +++ b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf > @@ -139,7 +139,7 @@ [FV.FvMain] > # Multimedia Card Interface > # > INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf > - INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > + INF Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > > # > # SMBIOS Support > diff --git a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > index a659cda2e44a..a4e9bfd73eb6 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > +++ b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > @@ -52,3 +52,7 @@ [PcdsFixedAtBuild.common] > # > gArmVExpressTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|""|VOID*|0x00000006 > gArmVExpressTokenSpaceGuid.PcdAndroidFastbootProductName|""|VOID*|0x00000007 > + > + ## PL180 MCI > + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x00000000|UINT32|0x00000009 > + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x00000000|UINT32|0x0000000A > diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c > new file mode 100644 > index 000000000000..0c9e4b7ce15e > --- /dev/null > +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c > @@ -0,0 +1,563 @@ > +/** @file > + This file implement the MMC Host Protocol for the ARM PrimeCell PL180. > + > + Copyright (c) 2011-2012, ARM Limited. All rights reserved. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "PL180Mci.h" > + > +#include > +#include > + > +EFI_MMC_HOST_PROTOCOL *gpMmcHost; > + > +// Untested ... > +//#define USE_STREAM > + > +#define MMCI0_BLOCKLEN 512 > +#define MMCI0_POW2_BLOCKLEN 9 > +#define MMCI0_TIMEOUT 1000 > + > +#define SYS_MCI_CARDIN BIT0 > +#define SYS_MCI_WPROT BIT1 > + > +BOOLEAN > +MciIsPowerOn ( > + VOID > + ) > +{ > + return ((MmioRead32 (MCI_POWER_CONTROL_REG) & MCI_POWER_ON) == MCI_POWER_ON); > +} > + > +EFI_STATUS > +MciInitialize ( > + VOID > + ) > +{ > + MCI_TRACE ("MciInitialize()"); > + return EFI_SUCCESS; > +} > + > +BOOLEAN > +MciIsCardPresent ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_CARDIN); > +} > + > +BOOLEAN > +MciIsReadOnly ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_WPROT); > +} > + > +// Convert block size to 2^n > +STATIC > +UINT32 > +GetPow2BlockLen ( > + IN UINT32 BlockLen > + ) > +{ > + UINTN Loop; > + UINTN Pow2BlockLen; > + > + Loop = 0x8000; > + Pow2BlockLen = 15; > + do { > + Loop = (Loop >> 1) & 0xFFFF; > + Pow2BlockLen--; > + } while (Pow2BlockLen && (!(Loop & BlockLen))); > + > + return Pow2BlockLen; > +} > + > +VOID > +MciPrepareDataPath ( > + IN UINTN TransferDirection > + ) > +{ > + // Set Data Length & Data Timer > + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF); > + MmioWrite32 (MCI_DATA_LENGTH_REG, MMCI0_BLOCKLEN); > + > +#ifndef USE_STREAM > + //Note: we are using a hardcoded BlockLen (==512). If we decide to use a variable size, we could > + // compute the pow2 of BlockLen with the above function GetPow2BlockLen () > + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4)); > +#else > + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS); > +#endif > +} > + > +EFI_STATUS > +MciSendCommand ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN MMC_CMD MmcCmd, > + IN UINT32 Argument > + ) > +{ > + UINT32 Status; > + UINT32 Cmd; > + UINTN RetVal; > + UINTN CmdCtrlReg; > + UINT32 DoneMask; > + > + RetVal = EFI_SUCCESS; > + > + if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) { > + MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT); > + } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) { > + MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD); > + } else if (MmcCmd == MMC_CMD6) { > + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF); > + MmioWrite32 (MCI_DATA_LENGTH_REG, 64); > +#ifndef USE_STREAM > + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (64)); > +#else > + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS); > +#endif > + } else if (MmcCmd == MMC_ACMD51) { > + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF); > + /* SCR register is 8 bytes long. */ > + MmioWrite32 (MCI_DATA_LENGTH_REG, 8); > +#ifndef USE_STREAM > + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (8)); > +#else > + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS); > +#endif > + } > + > + // Create Command for PL180 > + Cmd = (MMC_GET_INDX (MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLE; > + if (MmcCmd & MMC_CMD_WAIT_RESPONSE) { > + Cmd |= MCI_CPSM_WAIT_RESPONSE; > + } > + > + if (MmcCmd & MMC_CMD_LONG_RESPONSE) { > + Cmd |= MCI_CPSM_LONG_RESPONSE; > + } > + > + // Clear Status register static flags > + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); > + > + // Write to command argument register > + MmioWrite32 (MCI_ARGUMENT_REG, Argument); > + > + // Write to command register > + MmioWrite32 (MCI_COMMAND_REG, Cmd); > + > + DoneMask = (Cmd & MCI_CPSM_WAIT_RESPONSE) > + ? (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_ERROR) > + : (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_ERROR); > + do { > + Status = MmioRead32 (MCI_STATUS_REG); > + } while (! (Status & DoneMask)); > + > + if ((Status & MCI_STATUS_CMD_ERROR)) { > + // Clear Status register error flags > + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_ERROR); > + > + if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) { > + DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status)); > + RetVal = EFI_NO_RESPONSE; > + } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) { > + //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status)); > + RetVal = EFI_TIMEOUT; > + } else if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) { > + // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status. > + RetVal = EFI_CRC_ERROR; > + } > + } > + > + // Disable Command Path > + CmdCtrlReg = MmioRead32 (MCI_COMMAND_REG); > + MmioWrite32 (MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLE)); > + return RetVal; > +} > + > +EFI_STATUS > +MciReceiveResponse ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN MMC_RESPONSE_TYPE Type, > + IN UINT32* Buffer > + ) > +{ > + if (Buffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ( (Type == MMC_RESPONSE_TYPE_R1) > + || (Type == MMC_RESPONSE_TYPE_R1b) > + || (Type == MMC_RESPONSE_TYPE_R3) > + || (Type == MMC_RESPONSE_TYPE_R6) > + || (Type == MMC_RESPONSE_TYPE_R7)) > + { > + Buffer[0] = MmioRead32 (MCI_RESPONSE3_REG); > + } else if (Type == MMC_RESPONSE_TYPE_R2) { > + Buffer[0] = MmioRead32 (MCI_RESPONSE0_REG); > + Buffer[1] = MmioRead32 (MCI_RESPONSE1_REG); > + Buffer[2] = MmioRead32 (MCI_RESPONSE2_REG); > + Buffer[3] = MmioRead32 (MCI_RESPONSE3_REG); > + } > + > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +MciReadBlockData ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + IN UINT32* Buffer > + ) > +{ > + UINTN Loop; > + UINTN Finish; > + UINTN Status; > + EFI_STATUS RetVal; > + UINTN DataCtrlReg; > + EFI_TPL Tpl; > + > + RetVal = EFI_SUCCESS; > + > + // Read data from the RX FIFO > + Loop = 0; > + if (Length < MMCI0_BLOCKLEN) { > + Finish = Length / 4; > + } else { > + Finish = MMCI0_BLOCKLEN / 4; > + } > + > + // Raise the TPL at the highest level to disable Interrupts. > + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); > + > + do { > + // Read the Status flags > + Status = MmioRead32 (MCI_STATUS_REG); > + > + // Do eight reads if possible else a single read > + if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) { > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) { > + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); > + Loop++; > + } else { > + //Check for error conditions and timeouts > + if (Status & MCI_STATUS_CMD_DATATIMEOUT) { > + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); > + RetVal = EFI_TIMEOUT; > + break; > + } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) { > + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); > + RetVal = EFI_CRC_ERROR; > + break; > + } else if (Status & MCI_STATUS_CMD_START_BIT_ERROR) { > + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); > + RetVal = EFI_NO_RESPONSE; > + break; > + } > + } > + //clear RX over run flag > + if(Status & MCI_STATUS_CMD_RXOVERRUN) { > + MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN); > + } > + } while ((Loop < Finish)); > + > + // Restore Tpl > + gBS->RestoreTPL (Tpl); > + > + // Clear Status flags > + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); > + > + //Disable Data path > + DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG); > + MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK)); > + > + return RetVal; > +} > + > +EFI_STATUS > +MciWriteBlockData ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + IN UINT32* Buffer > + ) > +{ > + UINTN Loop; > + UINTN Finish; > + UINTN Timer; > + UINTN Status; > + EFI_STATUS RetVal; > + UINTN DataCtrlReg; > + EFI_TPL Tpl; > + > + RetVal = EFI_SUCCESS; > + > + // Write the data to the TX FIFO > + Loop = 0; > + Finish = MMCI0_BLOCKLEN / 4; > + Timer = MMCI0_TIMEOUT * 100; > + > + // Raise the TPL at the highest level to disable Interrupts. > + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); > + > + do { > + // Read the Status flags > + Status = MmioRead32 (MCI_STATUS_REG); > + > + // Do eight writes if possible else a single write > + if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) { > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + } else if (!(Status & MCI_STATUS_CMD_TXFIFOFULL)) { > + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); > + Loop++; > + } else { > + // Check for error conditions and timeouts > + if (Status & MCI_STATUS_CMD_DATATIMEOUT) { > + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); > + RetVal = EFI_TIMEOUT; > + goto Exit; > + } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) { > + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); > + RetVal = EFI_CRC_ERROR; > + goto Exit; > + } else if (Status & MCI_STATUS_CMD_TX_UNDERRUN) { > + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TX buffer Underrun! Response:0x%X Status:0x%x, Number of bytes written 0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status, Loop)); > + RetVal = EFI_BUFFER_TOO_SMALL; > + ASSERT(0); > + goto Exit; > + } > + } > + } while (Loop < Finish); > + > + // Restore Tpl > + gBS->RestoreTPL (Tpl); > + > + // Wait for FIFO to drain > + Timer = MMCI0_TIMEOUT * 60; > + Status = MmioRead32 (MCI_STATUS_REG); > +#ifndef USE_STREAM > + // Single block > + while (((Status & MCI_STATUS_TXDONE) != MCI_STATUS_TXDONE) && Timer) { > +#else > + // Stream > + while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) { > +#endif > + NanoSecondDelay(10); > + Status = MmioRead32 (MCI_STATUS_REG); > + Timer--; > + } > + > + // Clear Status flags > + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); > + > + if (Timer == 0) { > + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of words written 0x%x\n", Loop)); > + RetVal = EFI_TIMEOUT; > + } > + > +Exit: > + // Disable Data path > + DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG); > + MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK)); > + return RetVal; > +} > + > +EFI_STATUS > +MciNotifyState ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN MMC_STATE State > + ) > +{ > + UINT32 Data32; > + > + switch (State) { > + case MmcInvalidState: > + ASSERT (0); > + break; > + case MmcHwInitializationState: > + // If device already turn on then restart it > + Data32 = MmioRead32 (MCI_POWER_CONTROL_REG); > + if ((Data32 & 0x2) == MCI_POWER_UP) { > + MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI"); > + > + // Turn off > + MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0); > + MmioWrite32 (MCI_POWER_CONTROL_REG, 0); > + MicroSecondDelay (100); > + } > + > + MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI"); > + // Setup clock > + // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz > + MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE); > + > + // Set the voltage > + MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_OPENDRAIN | (15<<2)); > + MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP); > + MicroSecondDelay (10); > + MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON); > + MicroSecondDelay (100); > + > + // Set Data Length & Data Timer > + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFF); > + MmioWrite32 (MCI_DATA_LENGTH_REG, 8); > + > + ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON); > + break; > + case MmcIdleState: > + MCI_TRACE ("MciNotifyState(MmcIdleState)"); > + break; > + case MmcReadyState: > + MCI_TRACE ("MciNotifyState(MmcReadyState)"); > + break; > + case MmcIdentificationState: > + MCI_TRACE ("MciNotifyState (MmcIdentificationState)"); > + break; > + case MmcStandByState:{ > + volatile UINT32 PwrCtrlReg; > + MCI_TRACE ("MciNotifyState (MmcStandByState)"); > + > + // Enable MCICMD push-pull drive > + PwrCtrlReg = MmioRead32 (MCI_POWER_CONTROL_REG); > + //Disable Open Drain output > + PwrCtrlReg &= ~ (MCI_POWER_OPENDRAIN); > + MmioWrite32 (MCI_POWER_CONTROL_REG, PwrCtrlReg); > + > + // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled) > + // > + // Note: Increasing clock speed causes TX FIFO under-run errors. > + // So careful when optimising this driver for higher performance. > + // > + MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE); > + // Set MMCI0 clock to 24MHz (by bypassing the divider) > + //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE); > + break; > + } > + case MmcTransferState: > + //MCI_TRACE ("MciNotifyState(MmcTransferState)"); > + break; > + case MmcSendingDataState: > + MCI_TRACE ("MciNotifyState(MmcSendingDataState)"); > + break; > + case MmcReceiveDataState: > + MCI_TRACE ("MciNotifyState(MmcReceiveDataState)"); > + break; > + case MmcProgrammingState: > + MCI_TRACE ("MciNotifyState(MmcProgrammingState)"); > + break; > + case MmcDisconnectState: > + MCI_TRACE ("MciNotifyState(MmcDisconnectState)"); > + break; > + default: > + ASSERT (0); > + } > + return EFI_SUCCESS; > +} > + > +EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID; > + > +EFI_STATUS > +MciBuildDevicePath ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_DEVICE_PATH_PROTOCOL **DevicePath > + ) > +{ > + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; > + > + NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH)); > + CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mPL180MciDevicePathGuid); > + > + *DevicePath = NewDevicePathNode; > + return EFI_SUCCESS; > +} > + > +EFI_MMC_HOST_PROTOCOL gMciHost = { > + MMC_HOST_PROTOCOL_REVISION, > + MciIsCardPresent, > + MciIsReadOnly, > + MciBuildDevicePath, > + MciNotifyState, > + MciSendCommand, > + MciReceiveResponse, > + MciReadBlockData, > + MciWriteBlockData > +}; > + > +EFI_STATUS > +PL180MciDxeInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE Handle; > + > + DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180\n", > + MCI_PERIPH_ID_REG0)); > + > + // Check if this is a PL180 > + if (MmioRead8 (MCI_PERIPH_ID_REG0) != MCI_PERIPH_ID0 || > + MmioRead8 (MCI_PERIPH_ID_REG1) != MCI_PERIPH_ID1 || > + MmioRead8 (MCI_PERIPH_ID_REG2) != MCI_PERIPH_ID2 || > + MmioRead8 (MCI_PCELL_ID_REG0) != MCI_PCELL_ID0 || > + MmioRead8 (MCI_PCELL_ID_REG1) != MCI_PCELL_ID1 || > + MmioRead8 (MCI_PCELL_ID_REG2) != MCI_PCELL_ID2 || > + MmioRead8 (MCI_PCELL_ID_REG3) != MCI_PCELL_ID3) { > + > + DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180" > + " failed\n", MCI_PERIPH_ID_REG0)); > + return EFI_NOT_FOUND; > + } > + > + Handle = NULL; > + > + MCI_TRACE ("PL180MciDxeInitialize()"); > + > + //Publish Component Name, BlockIO protocol interfaces > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &Handle, > + &gEdkiiMmcHostProtocolGuid, &gMciHost, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h > new file mode 100644 > index 000000000000..a5bfe0b2eceb > --- /dev/null > +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h > @@ -0,0 +1,162 @@ > +/** @file > + Header for the MMC Host Protocol implementation for the ARM PrimeCell PL180. > + > + Copyright (c) 2011-2012, ARM Limited. All rights reserved. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef __PL180_MCI_H > +#define __PL180_MCI_H > + > +#include > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define PL180_MCI_DXE_VERSION 0x10 > + > +#define MCI_SYSCTL FixedPcdGet32 (PcdPL180MciBaseAddress) > + > +#define MCI_POWER_CONTROL_REG (MCI_SYSCTL + 0x000) > +#define MCI_CLOCK_CONTROL_REG (MCI_SYSCTL + 0x004) > +#define MCI_ARGUMENT_REG (MCI_SYSCTL + 0x008) > +#define MCI_COMMAND_REG (MCI_SYSCTL + 0x00C) > +#define MCI_RESPCMD_REG (MCI_SYSCTL + 0x010) > +#define MCI_RESPONSE3_REG (MCI_SYSCTL + 0x014) > +#define MCI_RESPONSE2_REG (MCI_SYSCTL + 0x018) > +#define MCI_RESPONSE1_REG (MCI_SYSCTL + 0x01C) > +#define MCI_RESPONSE0_REG (MCI_SYSCTL + 0x020) > +#define MCI_DATA_TIMER_REG (MCI_SYSCTL + 0x024) > +#define MCI_DATA_LENGTH_REG (MCI_SYSCTL + 0x028) > +#define MCI_DATA_CTL_REG (MCI_SYSCTL + 0x02C) > +#define MCI_DATA_COUNTER (MCI_SYSCTL + 0x030) > +#define MCI_STATUS_REG (MCI_SYSCTL + 0x034) > +#define MCI_CLEAR_STATUS_REG (MCI_SYSCTL + 0x038) > +#define MCI_INT0_MASK_REG (MCI_SYSCTL + 0x03C) > +#define MCI_INT1_MASK_REG (MCI_SYSCTL + 0x040) > +#define MCI_SELECT_REG (MCI_SYSCTL + 0x044) > +#define MCI_FIFOCOUNT_REG (MCI_SYSCTL + 0x048) > +#define MCI_FIFO_REG (MCI_SYSCTL + 0x080) > +#define MCI_PERIPH_ID_REG0 (MCI_SYSCTL + 0xFE0) > +#define MCI_PERIPH_ID_REG1 (MCI_SYSCTL + 0xFE4) > +#define MCI_PERIPH_ID_REG2 (MCI_SYSCTL + 0xFE8) > +#define MCI_PERIPH_ID_REG3 (MCI_SYSCTL + 0xFEC) > +#define MCI_PCELL_ID_REG0 (MCI_SYSCTL + 0xFF0) > +#define MCI_PCELL_ID_REG1 (MCI_SYSCTL + 0xFF4) > +#define MCI_PCELL_ID_REG2 (MCI_SYSCTL + 0xFF8) > +#define MCI_PCELL_ID_REG3 (MCI_SYSCTL + 0xFFC) > + > +#define MCI_PERIPH_ID0 0x80 > +#define MCI_PERIPH_ID1 0x11 > +#define MCI_PERIPH_ID2 0x04 > +#define MCI_PERIPH_ID3 0x00 > +#define MCI_PCELL_ID0 0x0D > +#define MCI_PCELL_ID1 0xF0 > +#define MCI_PCELL_ID2 0x05 > +#define MCI_PCELL_ID3 0xB1 > + > +#define MCI_POWER_OFF 0 > +#define MCI_POWER_UP BIT1 > +#define MCI_POWER_ON (BIT1 | BIT0) > +#define MCI_POWER_OPENDRAIN BIT6 > +#define MCI_POWER_ROD BIT7 > + > +#define MCI_CLOCK_ENABLE BIT8 > +#define MCI_CLOCK_POWERSAVE BIT9 > +#define MCI_CLOCK_BYPASS BIT10 > +#define MCI_CLOCK_WIDEBUS BIT11 > + > +#define MCI_STATUS_CMD_CMDCRCFAIL BIT0 > +#define MCI_STATUS_CMD_DATACRCFAIL BIT1 > +#define MCI_STATUS_CMD_CMDTIMEOUT BIT2 > +#define MCI_STATUS_CMD_DATATIMEOUT BIT3 > +#define MCI_STATUS_CMD_TX_UNDERRUN BIT4 > +#define MCI_STATUS_CMD_RXOVERRUN BIT5 > +#define MCI_STATUS_CMD_RESPEND BIT6 > +#define MCI_STATUS_CMD_SENT BIT7 > +#define MCI_STATUS_CMD_DATAEND BIT8 > +#define MCI_STATUS_CMD_START_BIT_ERROR BIT9 > +#define MCI_STATUS_CMD_DATABLOCKEND BIT10 > +#define MCI_STATUS_CMD_ACTIVE BIT11 > +#define MCI_STATUS_CMD_TXACTIVE BIT12 > +#define MCI_STATUS_CMD_RXACTIVE BIT13 > +#define MCI_STATUS_CMD_TXFIFOHALFEMPTY BIT14 > +#define MCI_STATUS_CMD_RXFIFOHALFFULL BIT15 > +#define MCI_STATUS_CMD_TXFIFOFULL BIT16 > +#define MCI_STATUS_CMD_RXFIFOFULL BIT17 > +#define MCI_STATUS_CMD_TXFIFOEMPTY BIT18 > +#define MCI_STATUS_CMD_RXFIFOEMPTY BIT19 > +#define MCI_STATUS_CMD_TXDATAAVAILBL BIT20 > +#define MCI_STATUS_CMD_RXDATAAVAILBL BIT21 > + > +#define MCI_STATUS_TXDONE (MCI_STATUS_CMD_DATAEND | MCI_STATUS_CMD_DATABLOCKEND) > +#define MCI_STATUS_RXDONE (MCI_STATUS_CMD_DATAEND | MCI_STATUS_CMD_DATABLOCKEND) > +#define MCI_STATUS_READ_ERROR ( MCI_STATUS_CMD_DATACRCFAIL \ > + | MCI_STATUS_CMD_DATATIMEOUT \ > + | MCI_STATUS_CMD_RXOVERRUN \ > + | MCI_STATUS_CMD_START_BIT_ERROR ) > +#define MCI_STATUS_WRITE_ERROR ( MCI_STATUS_CMD_DATACRCFAIL \ > + | MCI_STATUS_CMD_DATATIMEOUT \ > + | MCI_STATUS_CMD_TX_UNDERRUN ) > +#define MCI_STATUS_CMD_ERROR ( MCI_STATUS_CMD_CMDCRCFAIL \ > + | MCI_STATUS_CMD_CMDTIMEOUT \ > + | MCI_STATUS_CMD_START_BIT_ERROR ) > + > +#define MCI_CLR_CMD_STATUS ( MCI_STATUS_CMD_RESPEND \ > + | MCI_STATUS_CMD_SENT \ > + | MCI_STATUS_CMD_ERROR ) > + > +#define MCI_CLR_READ_STATUS ( MCI_STATUS_RXDONE \ > + | MCI_STATUS_READ_ERROR ) > + > +#define MCI_CLR_WRITE_STATUS ( MCI_STATUS_TXDONE \ > + | MCI_STATUS_WRITE_ERROR ) > + > +#define MCI_CLR_ALL_STATUS (BIT11 - 1) > + > +#define MCI_DATACTL_DISABLE_MASK 0xFE > +#define MCI_DATACTL_ENABLE BIT0 > +#define MCI_DATACTL_CONT_TO_CARD 0 > +#define MCI_DATACTL_CARD_TO_CONT BIT1 > +#define MCI_DATACTL_BLOCK_TRANS 0 > +#define MCI_DATACTL_STREAM_TRANS BIT2 > +#define MCI_DATACTL_DMA_DISABLED 0 > +#define MCI_DATACTL_DMA_ENABLE BIT3 > + > +#define INDX_MASK 0x3F > + > +#define MCI_CPSM_WAIT_RESPONSE BIT6 > +#define MCI_CPSM_LONG_RESPONSE BIT7 > +#define MCI_CPSM_LONG_INTERRUPT BIT8 > +#define MCI_CPSM_LONG_PENDING BIT9 > +#define MCI_CPSM_ENABLE BIT10 > + > +#define MCI_TRACE(txt) DEBUG ((EFI_D_BLKIO, "ARM_MCI: " txt "\n")) > + > +EFI_STATUS > +EFIAPI > +MciGetDriverName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN CHAR8 *Language, > + OUT CHAR16 **DriverName > + ); > + > +EFI_STATUS > +EFIAPI > +MciGetControllerName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN EFI_HANDLE ControllerHandle, > + IN EFI_HANDLE ChildHandle OPTIONAL, > + IN CHAR8 *Language, > + OUT CHAR16 **ControllerName > + ); > + > +#endif > diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > new file mode 100644 > index 000000000000..3519de857ebb > --- /dev/null > +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf > @@ -0,0 +1,46 @@ > +#/** @file > +# INF file for the MMC Host Protocol implementation for the ARM PrimeCell PL180. > +# > +# Copyright (c) 2011, ARM Limited. All rights reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +#**/ > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = PL180MciDxe > + FILE_GUID = 09831032-6fa3-4484-af4f-0a000a8d3a82 > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + > + ENTRY_POINT = PL180MciDxeInitialize > + > +[Sources.common] > + PL180Mci.c > + > +[Packages] > + EmbeddedPkg/EmbeddedPkg.dec > + MdePkg/MdePkg.dec > + Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > + > +[LibraryClasses] > + BaseLib > + UefiLib > + UefiDriverEntryPoint > + BaseMemoryLib > + ArmLib > + IoLib > + TimerLib > + > +[Protocols] > + gEfiCpuArchProtocolGuid > + gEfiDevicePathProtocolGuid > + gEdkiiMmcHostProtocolGuid > + > +[Pcd] > + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress > + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress > + > +[Depex] > + gEfiCpuArchProtocolGuid > -- > 2.17.1 >