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.3759.1588589902186008285 for ; Mon, 04 May 2020 03:58:22 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=w4Z/N4h/; spf=pass (domain: nuviainc.com, ip: 209.85.128.67, mailfrom: leif@nuviainc.com) Received: by mail-wm1-f67.google.com with SMTP id 188so7909851wmc.2 for ; Mon, 04 May 2020 03:58:21 -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=FzgcBvormNaHReWgmA+TVJCWcKeH6mjACwHHf6P0Rfg=; b=w4Z/N4h/wufi6e4A7klSp9ooM89xkeQd+y+m/6LbwGubPh2o3TWIozYM0bkBWgDOSP NYUqRby7gKabs24DB/DHD0M7036H0bEd3MvTY/bE+PvH1+QxNu97hMAJaf2c2V6xHcWC R7x2/ahKub9HfhiEIKPUZU/APlmy4umb5QhjI565s3/edecq/DuN+shHdAbqemTSWuNo Vc8+qsR4wDZkUhzPPeftKWTswutrYM/wR/jhRo3bxQlupdBaLMmcbVV2Zl2M8mPVZIqD iw6uSaaETdsRJ8ocTcZlEkNv/NRxdJACraPfDZMI+s5m0L9g34h20h+gUkkJJRRIQnD1 BO7w== 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=FzgcBvormNaHReWgmA+TVJCWcKeH6mjACwHHf6P0Rfg=; b=p3lstbYb4bNjEwYUDTWa0jwLOq+RVITO9ShWdiwspCF/lCdRMIFRd3NiAnLJDcdrTB OSJyzHuXLYuG6WDBguuKbNaweb2ylkzi0m5M83K1oqiQiNe6QGe9+ZiCz/Sb5NWHVQMM B0W77r8sg4JkuvvD5payEptvRTPIthJDV1ieRRIfSMiVpcVim8se7zYRidyY7B5XAp6+ W3b5+0Go9st9ShhkZNpjGtclOOPWkLD2xWKq+cBN9lDejvUBwCb/FvTR5k2iUGpYoGOE B0VW6Op3WeZ1jQICP9pkruKqTFKTvcTp1jMikKBaiBTvyJzg4dfmteSrBWNscNqKrU9+ huhQ== X-Gm-Message-State: AGi0PuZIoOCxX0UQE/XnFGg3OxZt9fIyTSWwfYMVplI4RJAFLpKbpEED XC1XUdQAsU6eAi3X0RmQjcetnowUBl8= X-Google-Smtp-Source: APiQypJHbTwCxmHOIMyB6rqGWQ+Pw/mm6LyoEXmvrlbawRAnA4FGqduBMMtUPp6gATC+Vx0pAj9gVQ== X-Received: by 2002:a1c:f306:: with SMTP id q6mr13912000wmq.169.1588589900620; Mon, 04 May 2020 03:58:20 -0700 (PDT) Return-Path: Received: from vanye ([2001:470:1f09:12f0:b26e:bfff:fea9:f1b8]) by smtp.gmail.com with ESMTPSA id x16sm11504223wrn.76.2020.05.04.03.58.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 03:58:20 -0700 (PDT) Date: Mon, 4 May 2020 11:58:18 +0100 From: "Leif Lindholm" To: Ard Biesheuvel Cc: devel@edk2.groups.io Subject: Re: [PATCH edk2-platforms v3 4/8] Silicon/Synopsys/DesignWare: import eMMC DXE driver from EmbeddedPkg Message-ID: <20200504105818.GD21486@vanye> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> <20200430171650.24139-5-ard.biesheuvel@arm.com> MIME-Version: 1.0 In-Reply-To: <20200430171650.24139-5-ard.biesheuvel@arm.com> User-Agent: Mutt/1.10.1 (2018-07-13) Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Apr 30, 2020 at 19:16:45 +0200, Ard Biesheuvel wrote: > Incorporate the driver for the DesignWare eMMC host controller that is > based on the obsolete MMC host controller protocol that is defined in > EmbeddedPkg. > > This driver does not follow the UEFI driver model, and is only kept > around for its only users, which is the HiKey platform, which is > rapidly reaching obsolescence itself, at which point this driver may > be removed again. > > To prevent inadvertent use in new platforms, add a PCD that needs to > be changed from its default value in order for the driver to be > functional. > > Signed-off-by: Ard Biesheuvel > --- > Silicon/Synopsys/DesignWare/DesignWare.dec | 9 + > Silicon/Synopsys/DesignWare/DesignWare.dsc | 2 + > Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h | 132 ++++ > Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c | 693 ++++++++++++++++++++ > Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf | 56 ++ > 5 files changed, 892 insertions(+) > > diff --git a/Silicon/Synopsys/DesignWare/DesignWare.dec b/Silicon/Synopsys/DesignWare/DesignWare.dec > index 71ddd24b7404..f7ec7927543c 100755 > --- a/Silicon/Synopsys/DesignWare/DesignWare.dec > +++ b/Silicon/Synopsys/DesignWare/DesignWare.dec > @@ -21,4 +21,13 @@ [Guids.common] > gDesignWareTokenSpaceGuid = { 0x89cb1241, 0xd283, 0x4543, { 0x88, 0x9c, 0x6b, 0x62, 0x36, 0x1a, 0x95, 0x7a } } > gDwEmacNetNonDiscoverableDeviceGuid = { 0x401950CD, 0xF9CD, 0x4A65, { 0xAD, 0x8E, 0x84, 0x9F, 0x3B, 0xAF, 0x23, 0x04 } } > > +[PcdsFixedAtBuild.common] > + # > + # Permit the use of obsolete drivers in this package > + # > + gDesignWareTokenSpaceGuid.PcdDwPermitObsoleteDrivers|FALSE|BOOLEAN|0x00000001 > > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeBaseAddress|0x0|UINT32|0x00000002 > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz|0x0|UINT32|0x00000003 > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeMaxClockFreqInHz|0x0|UINT32|0x00000004 > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeFifoDepth|0x0|UINT32|0x00000005 > diff --git a/Silicon/Synopsys/DesignWare/DesignWare.dsc b/Silicon/Synopsys/DesignWare/DesignWare.dsc > index ad6a5ede4ae0..098bba3f7d68 100755 > --- a/Silicon/Synopsys/DesignWare/DesignWare.dsc > +++ b/Silicon/Synopsys/DesignWare/DesignWare.dsc > @@ -20,6 +20,7 @@ [LibraryClasses] > ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf > BaseLib|MdePkg/Library/BaseLib/BaseLib.inf > BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf > + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf > DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf > DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf > DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf > @@ -39,3 +40,4 @@ [LibraryClasses] > > [Components] > Silicon/Synopsys/DesignWare/Drivers/DwEmacSnpDxe/DwEmacSnpDxe.inf > + Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf > diff --git a/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h > new file mode 100644 > index 000000000000..09ad9b8428c4 > --- /dev/null > +++ b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h > @@ -0,0 +1,132 @@ > +/** @file > +* > +* WARNING: > +* This driver fails to follow the UEFI driver model without a good > +* reason, and only remains in the tree because it is still used by > +* a small number of platforms. It will be removed when no longer used. > +* > +* Copyright (c) 2014-2017, Linaro Limited. All rights reserved. > +* > +* SPDX-License-Identifier: BSD-2-Clause-Patent > +* > +**/ > + > + > +#ifndef __DWEMMC_H__ > +#define __DWEMMC_H__ > + > +#include > + > +// DW MMC Registers > +#define DWEMMC_CTRL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x000) > +#define DWEMMC_PWREN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x004) > +#define DWEMMC_CLKDIV ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x008) > +#define DWEMMC_CLKSRC ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x00c) > +#define DWEMMC_CLKENA ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x010) > +#define DWEMMC_TMOUT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x014) > +#define DWEMMC_CTYPE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x018) > +#define DWEMMC_BLKSIZ ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x01c) > +#define DWEMMC_BYTCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x020) > +#define DWEMMC_INTMASK ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x024) > +#define DWEMMC_CMDARG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x028) > +#define DWEMMC_CMD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x02c) > +#define DWEMMC_RESP0 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x030) > +#define DWEMMC_RESP1 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x034) > +#define DWEMMC_RESP2 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x038) > +#define DWEMMC_RESP3 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x03c) > +#define DWEMMC_RINTSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x044) > +#define DWEMMC_STATUS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x048) > +#define DWEMMC_FIFOTH ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x04c) > +#define DWEMMC_TCBCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x05c) > +#define DWEMMC_TBBCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x060) > +#define DWEMMC_DEBNCE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x064) > +#define DWEMMC_HCON ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x070) > +#define DWEMMC_UHSREG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x074) > +#define DWEMMC_BMOD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x080) > +#define DWEMMC_DBADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x088) > +#define DWEMMC_IDSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x08c) > +#define DWEMMC_IDINTEN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x090) > +#define DWEMMC_DSCADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x094) > +#define DWEMMC_BUFADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x098) > +#define DWEMMC_CARDTHRCTL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0X100) > +#define DWEMMC_DATA ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0X200) > + > +#define CMD_UPDATE_CLK 0x80202000 > +#define CMD_START_BIT (1 << 31) > + > +#define MMC_8BIT_MODE (1 << 16) > + > +#define BIT_CMD_RESPONSE_EXPECT (1 << 6) > +#define BIT_CMD_LONG_RESPONSE (1 << 7) > +#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8) > +#define BIT_CMD_DATA_EXPECTED (1 << 9) > +#define BIT_CMD_READ (0 << 10) > +#define BIT_CMD_WRITE (1 << 10) > +#define BIT_CMD_BLOCK_TRANSFER (0 << 11) > +#define BIT_CMD_STREAM_TRANSFER (1 << 11) > +#define BIT_CMD_SEND_AUTO_STOP (1 << 12) > +#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13) > +#define BIT_CMD_STOP_ABORT_CMD (1 << 14) > +#define BIT_CMD_SEND_INIT (1 << 15) > +#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21) > +#define BIT_CMD_READ_CEATA_DEVICE (1 << 22) > +#define BIT_CMD_CCS_EXPECTED (1 << 23) > +#define BIT_CMD_ENABLE_BOOT (1 << 24) > +#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25) > +#define BIT_CMD_DISABLE_BOOT (1 << 26) > +#define BIT_CMD_MANDATORY_BOOT (0 << 27) > +#define BIT_CMD_ALTERNATE_BOOT (1 << 27) > +#define BIT_CMD_VOLT_SWITCH (1 << 28) > +#define BIT_CMD_USE_HOLD_REG (1 << 29) > +#define BIT_CMD_START (1 << 31) > + > +#define DWEMMC_INT_EBE (1 << 15) /* End-bit Err */ > +#define DWEMMC_INT_SBE (1 << 13) /* Start-bit Err */ > +#define DWEMMC_INT_HLE (1 << 12) /* Hardware-lock Err */ > +#define DWEMMC_INT_FRUN (1 << 11) /* FIFO UN/OV RUN */ > +#define DWEMMC_INT_DRT (1 << 9) /* Data timeout */ > +#define DWEMMC_INT_RTO (1 << 8) /* Response timeout */ > +#define DWEMMC_INT_DCRC (1 << 7) /* Data CRC err */ > +#define DWEMMC_INT_RCRC (1 << 6) /* Response CRC err */ > +#define DWEMMC_INT_RXDR (1 << 5) > +#define DWEMMC_INT_TXDR (1 << 4) > +#define DWEMMC_INT_DTO (1 << 3) /* Data trans over */ > +#define DWEMMC_INT_CMD_DONE (1 << 2) > +#define DWEMMC_INT_RE (1 << 1) > + > +#define DWEMMC_IDMAC_DES0_DIC (1 << 1) > +#define DWEMMC_IDMAC_DES0_LD (1 << 2) > +#define DWEMMC_IDMAC_DES0_FS (1 << 3) > +#define DWEMMC_IDMAC_DES0_CH (1 << 4) > +#define DWEMMC_IDMAC_DES0_ER (1 << 5) > +#define DWEMMC_IDMAC_DES0_CES (1 << 30) > +#define DWEMMC_IDMAC_DES0_OWN (1 << 31) > +#define DWEMMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff) > +#define DWEMMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) > +#define DWEMMC_IDMAC_SWRESET (1 << 0) > +#define DWEMMC_IDMAC_FB (1 << 1) > +#define DWEMMC_IDMAC_ENABLE (1 << 7) > + > +#define EMMC_FIX_RCA 6 > + > +/* bits in MMC0_CTRL */ > +#define DWEMMC_CTRL_RESET (1 << 0) > +#define DWEMMC_CTRL_FIFO_RESET (1 << 1) > +#define DWEMMC_CTRL_DMA_RESET (1 << 2) > +#define DWEMMC_CTRL_INT_EN (1 << 4) > +#define DWEMMC_CTRL_DMA_EN (1 << 5) > +#define DWEMMC_CTRL_IDMAC_EN (1 << 25) > +#define DWEMMC_CTRL_RESET_ALL (DWEMMC_CTRL_RESET | DWEMMC_CTRL_FIFO_RESET | DWEMMC_CTRL_DMA_RESET) > + > +#define DWEMMC_STS_DATA_BUSY (1 << 9) > + > +#define DWEMMC_FIFO_TWMARK(x) (x & 0xfff) > +#define DWEMMC_FIFO_RWMARK(x) ((x & 0x1ff) << 16) > +#define DWEMMC_DMA_BURST_SIZE(x) ((x & 0x7) << 28) > + > +#define DWEMMC_CARD_RD_THR(x) ((x & 0xfff) << 16) > +#define DWEMMC_CARD_RD_THR_EN (1 << 0) > + > +#define DWEMMC_GET_HDATA_WIDTH(x) (((x) >> 7) & 0x7) > + > +#endif // __DWEMMC_H__ > diff --git a/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c > new file mode 100644 > index 000000000000..eed5fc57fc22 > --- /dev/null > +++ b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c > @@ -0,0 +1,693 @@ > +/** @file > + This file implement the MMC Host Protocol for the DesignWare eMMC. > + > + Copyright (c) 2014-2017, Linaro Limited. All rights reserved. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent Comment only: This file, unlike some other .c files in this series, does not include the WARNING header. Feel free to fold one in before pushing. / Leif > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include "DwEmmc.h" > + > +#define DWEMMC_DESC_PAGE 1 > +#define DWEMMC_BLOCK_SIZE 512 > +#define DWEMMC_DMA_BUF_SIZE (512 * 8) > +#define DWEMMC_MAX_DESC_PAGES 512 > + > +typedef struct { > + UINT32 Des0; > + UINT32 Des1; > + UINT32 Des2; > + UINT32 Des3; > +} DWEMMC_IDMAC_DESCRIPTOR; > + > +EFI_MMC_HOST_PROTOCOL *gpMmcHost; > +DWEMMC_IDMAC_DESCRIPTOR *gpIdmacDesc; > +EFI_GUID mDwEmmcDevicePathGuid = EFI_CALLER_ID_GUID; > +STATIC UINT32 mDwEmmcCommand; > +STATIC UINT32 mDwEmmcArgument; > + > +EFI_STATUS > +DwEmmcReadBlockData ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + IN UINT32* Buffer > + ); > + > +BOOLEAN > +DwEmmcIsPowerOn ( > + VOID > + ) > +{ > + return TRUE; > +} > + > +EFI_STATUS > +DwEmmcInitialize ( > + VOID > + ) > +{ > + DEBUG ((DEBUG_BLKIO, "DwEmmcInitialize()")); > + return EFI_SUCCESS; > +} > + > +BOOLEAN > +DwEmmcIsCardPresent ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return TRUE; > +} > + > +BOOLEAN > +DwEmmcIsReadOnly ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return FALSE; > +} > + > +BOOLEAN > +DwEmmcIsDmaSupported ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return TRUE; > +} > + > +EFI_STATUS > +DwEmmcBuildDevicePath ( > + 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, &mDwEmmcDevicePathGuid); > + > + *DevicePath = NewDevicePathNode; > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +DwEmmcUpdateClock ( > + VOID > + ) > +{ > + UINT32 Data; > + > + /* CMD_UPDATE_CLK */ > + Data = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY | > + BIT_CMD_START; > + MmioWrite32 (DWEMMC_CMD, Data); > + while (1) { > + Data = MmioRead32 (DWEMMC_CMD); > + if (!(Data & CMD_START_BIT)) { > + break; > + } > + Data = MmioRead32 (DWEMMC_RINTSTS); > + if (Data & DWEMMC_INT_HLE) { > + Print (L"failed to update mmc clock frequency\n"); > + return EFI_DEVICE_ERROR; > + } > + } > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +DwEmmcSetClock ( > + IN UINTN ClockFreq > + ) > +{ > + UINT32 Divider, Rate, Data; > + EFI_STATUS Status; > + BOOLEAN Found = FALSE; > + > + for (Divider = 1; Divider < 256; Divider++) { > + Rate = PcdGet32 (PcdDwEmmcDxeClockFrequencyInHz); > + if ((Rate / (2 * Divider)) <= ClockFreq) { > + Found = TRUE; > + break; > + } > + } > + if (Found == FALSE) { > + return EFI_NOT_FOUND; > + } > + > + // Wait until MMC is idle > + do { > + Data = MmioRead32 (DWEMMC_STATUS); > + } while (Data & DWEMMC_STS_DATA_BUSY); > + > + // Disable MMC clock first > + MmioWrite32 (DWEMMC_CLKENA, 0); > + Status = DwEmmcUpdateClock (); > + ASSERT (!EFI_ERROR (Status)); > + > + MmioWrite32 (DWEMMC_CLKDIV, Divider); > + Status = DwEmmcUpdateClock (); > + ASSERT (!EFI_ERROR (Status)); > + > + // Enable MMC clock > + MmioWrite32 (DWEMMC_CLKENA, 1); > + MmioWrite32 (DWEMMC_CLKSRC, 0); > + Status = DwEmmcUpdateClock (); > + ASSERT (!EFI_ERROR (Status)); > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +DwEmmcNotifyState ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN MMC_STATE State > + ) > +{ > + UINT32 Data; > + EFI_STATUS Status; > + > + switch (State) { > + case MmcInvalidState: > + return EFI_INVALID_PARAMETER; > + case MmcHwInitializationState: > + MmioWrite32 (DWEMMC_PWREN, 1); > + > + // If device already turn on then restart it > + Data = DWEMMC_CTRL_RESET_ALL; > + MmioWrite32 (DWEMMC_CTRL, Data); > + do { > + // Wait until reset operation finished > + Data = MmioRead32 (DWEMMC_CTRL); > + } while (Data & DWEMMC_CTRL_RESET_ALL); > + > + // Setup clock that could not be higher than 400KHz. > + Status = DwEmmcSetClock (400000); > + ASSERT (!EFI_ERROR (Status)); > + // Wait clock stable > + MicroSecondDelay (100); > + > + MmioWrite32 (DWEMMC_RINTSTS, ~0); > + MmioWrite32 (DWEMMC_INTMASK, 0); > + MmioWrite32 (DWEMMC_TMOUT, ~0); > + MmioWrite32 (DWEMMC_IDINTEN, 0); > + MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET); > + > + MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE); > + do { > + Data = MmioRead32 (DWEMMC_BMOD); > + } while (Data & DWEMMC_IDMAC_SWRESET); > + break; > + case MmcIdleState: > + break; > + case MmcReadyState: > + break; > + case MmcIdentificationState: > + break; > + case MmcStandByState: > + break; > + case MmcTransferState: > + break; > + case MmcSendingDataState: > + break; > + case MmcReceiveDataState: > + break; > + case MmcProgrammingState: > + break; > + case MmcDisconnectState: > + break; > + default: > + return EFI_INVALID_PARAMETER; > + } > + return EFI_SUCCESS; > +} > + > +// Need to prepare DMA buffer first before sending commands to MMC card > +BOOLEAN > +IsPendingReadCommand ( > + IN MMC_CMD MmcCmd > + ) > +{ > + UINTN Mask; > + > + Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_READ; > + if ((MmcCmd & Mask) == Mask) { > + return TRUE; > + } > + return FALSE; > +} > + > +BOOLEAN > +IsPendingWriteCommand ( > + IN MMC_CMD MmcCmd > + ) > +{ > + UINTN Mask; > + > + Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE; > + if ((MmcCmd & Mask) == Mask) { > + return TRUE; > + } > + return FALSE; > +} > + > +EFI_STATUS > +SendCommand ( > + IN MMC_CMD MmcCmd, > + IN UINT32 Argument > + ) > +{ > + UINT32 Data, ErrMask; > + > + // Wait until MMC is idle > + do { > + Data = MmioRead32 (DWEMMC_STATUS); > + } while (Data & DWEMMC_STS_DATA_BUSY); > + > + MmioWrite32 (DWEMMC_RINTSTS, ~0); > + MmioWrite32 (DWEMMC_CMDARG, Argument); > + MmioWrite32 (DWEMMC_CMD, MmcCmd); > + > + ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO | > + DWEMMC_INT_RCRC | DWEMMC_INT_RE; > + ErrMask |= DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE; > + do { > + MicroSecondDelay(500); > + Data = MmioRead32 (DWEMMC_RINTSTS); > + > + if (Data & ErrMask) { > + return EFI_DEVICE_ERROR; > + } > + if (Data & DWEMMC_INT_DTO) { // Transfer Done > + break; > + } > + } while (!(Data & DWEMMC_INT_CMD_DONE)); > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +DwEmmcSendCommand ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN MMC_CMD MmcCmd, > + IN UINT32 Argument > + ) > +{ > + UINT32 Cmd = 0; > + EFI_STATUS Status = EFI_SUCCESS; > + > + switch (MMC_GET_INDX(MmcCmd)) { > + case MMC_INDX(0): > + Cmd = BIT_CMD_SEND_INIT; > + break; > + case MMC_INDX(1): > + Cmd = BIT_CMD_RESPONSE_EXPECT; > + break; > + case MMC_INDX(2): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE | > + BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT; > + break; > + case MMC_INDX(3): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_SEND_INIT; > + break; > + case MMC_INDX(7): > + if (Argument) > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; > + else > + Cmd = 0; > + break; > + case MMC_INDX(8): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | > + BIT_CMD_WAIT_PRVDATA_COMPLETE; > + break; > + case MMC_INDX(9): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_LONG_RESPONSE; > + break; > + case MMC_INDX(12): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_STOP_ABORT_CMD; > + break; > + case MMC_INDX(13): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_WAIT_PRVDATA_COMPLETE; > + break; > + case MMC_INDX(16): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | > + BIT_CMD_WAIT_PRVDATA_COMPLETE; > + break; > + case MMC_INDX(17): > + case MMC_INDX(18): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | > + BIT_CMD_WAIT_PRVDATA_COMPLETE; > + break; > + case MMC_INDX(24): > + case MMC_INDX(25): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE | > + BIT_CMD_WAIT_PRVDATA_COMPLETE; > + break; > + case MMC_INDX(30): > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_DATA_EXPECTED; > + break; > + default: > + Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; > + break; > + } > + > + Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START; > + if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) { > + mDwEmmcCommand = Cmd; > + mDwEmmcArgument = Argument; > + } else { > + Status = SendCommand (Cmd, Argument); > + } > + return Status; > +} > + > +EFI_STATUS > +DwEmmcReceiveResponse ( > + 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 (DWEMMC_RESP0); > + } else if (Type == MMC_RESPONSE_TYPE_R2) { > + Buffer[0] = MmioRead32 (DWEMMC_RESP0); > + Buffer[1] = MmioRead32 (DWEMMC_RESP1); > + Buffer[2] = MmioRead32 (DWEMMC_RESP2); > + Buffer[3] = MmioRead32 (DWEMMC_RESP3); > + } > + return EFI_SUCCESS; > +} > + > +VOID > +DwEmmcAdjustFifoThreshold ( > + VOID > + ) > +{ > + /* DMA multiple transaction size map to reg value as array index */ > + CONST UINT32 BurstSize[] = {1, 4, 8, 16, 32, 64, 128, 256}; > + UINT32 BlkDepthInFifo, FifoThreshold, FifoWidth, FifoDepth; > + UINT32 BlkSize = DWEMMC_BLOCK_SIZE, Idx = 0, RxWatermark = 1, TxWatermark, TxWatermarkInvers; > + > + /* Skip FIFO adjustment if we do not have platform FIFO depth info */ > + FifoDepth = PcdGet32 (PcdDwEmmcDxeFifoDepth); > + if (!FifoDepth) { > + return; > + } > + > + TxWatermark = FifoDepth / 2; > + TxWatermarkInvers = FifoDepth - TxWatermark; > + > + FifoWidth = DWEMMC_GET_HDATA_WIDTH (MmioRead32 (DWEMMC_HCON)); > + if (!FifoWidth) { > + FifoWidth = 2; > + } else if (FifoWidth == 2) { > + FifoWidth = 8; > + } else { > + FifoWidth = 4; > + } > + > + BlkDepthInFifo = BlkSize / FifoWidth; > + > + Idx = ARRAY_SIZE (BurstSize) - 1; > + while (Idx && ((BlkDepthInFifo % BurstSize[Idx]) || (TxWatermarkInvers % BurstSize[Idx]))) { > + Idx--; > + } > + > + RxWatermark = BurstSize[Idx] - 1; > + FifoThreshold = DWEMMC_DMA_BURST_SIZE (Idx) | DWEMMC_FIFO_TWMARK (TxWatermark) > + | DWEMMC_FIFO_RWMARK (RxWatermark); > + MmioWrite32 (DWEMMC_FIFOTH, FifoThreshold); > +} > + > +EFI_STATUS > +PrepareDmaData ( > + IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc, > + IN UINTN Length, > + IN UINT32* Buffer > + ) > +{ > + UINTN Cnt, Blks, Idx, LastIdx; > + > + Cnt = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; > + Blks = (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE; > + Length = DWEMMC_BLOCK_SIZE * Blks; > + > + for (Idx = 0; Idx < Cnt; Idx++) { > + (IdmacDesc + Idx)->Des0 = DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_CH | > + DWEMMC_IDMAC_DES0_DIC; > + (IdmacDesc + Idx)->Des1 = DWEMMC_IDMAC_DES1_BS1(DWEMMC_DMA_BUF_SIZE); > + /* Buffer Address */ > + (IdmacDesc + Idx)->Des2 = (UINT32)((UINTN)Buffer + DWEMMC_DMA_BUF_SIZE * Idx); > + /* Next Descriptor Address */ > + (IdmacDesc + Idx)->Des3 = (UINT32)((UINTN)IdmacDesc + > + (sizeof(DWEMMC_IDMAC_DESCRIPTOR) * (Idx + 1))); > + } > + /* First Descriptor */ > + IdmacDesc->Des0 |= DWEMMC_IDMAC_DES0_FS; > + /* Last Descriptor */ > + LastIdx = Cnt - 1; > + (IdmacDesc + LastIdx)->Des0 |= DWEMMC_IDMAC_DES0_LD; > + (IdmacDesc + LastIdx)->Des0 &= ~(DWEMMC_IDMAC_DES0_DIC | DWEMMC_IDMAC_DES0_CH); > + (IdmacDesc + LastIdx)->Des1 = DWEMMC_IDMAC_DES1_BS1(Length - > + (LastIdx * DWEMMC_DMA_BUF_SIZE)); > + /* Set the Next field of Last Descriptor */ > + (IdmacDesc + LastIdx)->Des3 = 0; > + MmioWrite32 (DWEMMC_DBADDR, (UINT32)((UINTN)IdmacDesc)); > + > + return EFI_SUCCESS; > +} > + > +VOID > +StartDma ( > + UINTN Length > + ) > +{ > + UINT32 Data; > + > + Data = MmioRead32 (DWEMMC_CTRL); > + Data |= DWEMMC_CTRL_INT_EN | DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN; > + MmioWrite32 (DWEMMC_CTRL, Data); > + Data = MmioRead32 (DWEMMC_BMOD); > + Data |= DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB; > + MmioWrite32 (DWEMMC_BMOD, Data); > + > + MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE); > + MmioWrite32 (DWEMMC_BYTCNT, Length); > +} > + > +EFI_STATUS > +DwEmmcReadBlockData ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + IN UINT32* Buffer > + ) > +{ > + EFI_STATUS Status; > + UINT32 DescPages, CountPerPage, Count; > + EFI_TPL Tpl; > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + CountPerPage = EFI_PAGE_SIZE / 16; > + Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; > + DescPages = (Count + CountPerPage - 1) / CountPerPage; > + > + InvalidateDataCacheRange (Buffer, Length); > + > + Status = PrepareDmaData (gpIdmacDesc, Length, Buffer); > + if (EFI_ERROR (Status)) { > + goto out; > + } > + > + WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE); > + StartDma (Length); > + > + Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status)); > + goto out; > + } > +out: > + // Restore Tpl > + gBS->RestoreTPL (Tpl); > + return Status; > +} > + > +EFI_STATUS > +DwEmmcWriteBlockData ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + IN UINT32* Buffer > + ) > +{ > + EFI_STATUS Status; > + UINT32 DescPages, CountPerPage, Count; > + EFI_TPL Tpl; > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + CountPerPage = EFI_PAGE_SIZE / 16; > + Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; > + DescPages = (Count + CountPerPage - 1) / CountPerPage; > + > + WriteBackDataCacheRange (Buffer, Length); > + > + Status = PrepareDmaData (gpIdmacDesc, Length, Buffer); > + if (EFI_ERROR (Status)) { > + goto out; > + } > + > + WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE); > + StartDma (Length); > + > + Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status)); > + goto out; > + } > +out: > + // Restore Tpl > + gBS->RestoreTPL (Tpl); > + return Status; > +} > + > +EFI_STATUS > +DwEmmcSetIos ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN UINT32 BusClockFreq, > + IN UINT32 BusWidth, > + IN UINT32 TimingMode > + ) > +{ > + EFI_STATUS Status = EFI_SUCCESS; > + UINT32 Data; > + > + if ((PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz) != 0) && > + (BusClockFreq > PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz))) { > + return EFI_UNSUPPORTED; > + } > + if (TimingMode != EMMCBACKWARD) { > + Data = MmioRead32 (DWEMMC_UHSREG); > + switch (TimingMode) { > + case EMMCHS52DDR1V2: > + case EMMCHS52DDR1V8: > + Data |= 1 << 16; > + break; > + case EMMCHS52: > + case EMMCHS26: > + Data &= ~(1 << 16); > + break; > + default: > + return EFI_UNSUPPORTED; > + } > + MmioWrite32 (DWEMMC_UHSREG, Data); > + } > + > + switch (BusWidth) { > + case 1: > + MmioWrite32 (DWEMMC_CTYPE, 0); > + break; > + case 4: > + MmioWrite32 (DWEMMC_CTYPE, 1); > + break; > + case 8: > + MmioWrite32 (DWEMMC_CTYPE, 1 << 16); > + break; > + default: > + return EFI_UNSUPPORTED; > + } > + if (BusClockFreq) { > + Status = DwEmmcSetClock (BusClockFreq); > + } > + return Status; > +} > + > +BOOLEAN > +DwEmmcIsMultiBlock ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return TRUE; > +} > + > +EFI_MMC_HOST_PROTOCOL gMciHost = { > + MMC_HOST_PROTOCOL_REVISION, > + DwEmmcIsCardPresent, > + DwEmmcIsReadOnly, > + DwEmmcBuildDevicePath, > + DwEmmcNotifyState, > + DwEmmcSendCommand, > + DwEmmcReceiveResponse, > + DwEmmcReadBlockData, > + DwEmmcWriteBlockData, > + DwEmmcSetIos, > + DwEmmcIsMultiBlock > +}; > + > +EFI_STATUS > +DwEmmcDxeInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE Handle; > + > + if (!FixedPcdGetBool (PcdDwPermitObsoleteDrivers)) { > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > + } > + > + Handle = NULL; > + > + DwEmmcAdjustFifoThreshold (); > + gpIdmacDesc = (DWEMMC_IDMAC_DESCRIPTOR *)AllocatePages (DWEMMC_MAX_DESC_PAGES); > + if (gpIdmacDesc == NULL) { > + return EFI_BUFFER_TOO_SMALL; > + } > + > + DEBUG ((DEBUG_BLKIO, "DwEmmcDxeInitialize()\n")); > + > + //Publish Component Name, BlockIO protocol interfaces > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &Handle, > + &gEmbeddedMmcHostProtocolGuid, &gMciHost, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > diff --git a/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf > new file mode 100644 > index 000000000000..7f70fe1e2a38 > --- /dev/null > +++ b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf > @@ -0,0 +1,56 @@ > +#/** @file > +# INF file for the eMMC Host Protocol implementation for the DesignWare MMC. > +# > +# WARNING: > +# This driver fails to follow the UEFI driver model without a good > +# reason, and only remains in the tree because it is still used by > +# a small number of platforms. It will be removed when no longer used. > +# > +# Copyright (c) 2014-2017, Linaro Limited. All rights reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +#**/ > + > +[Defines] > + INF_VERSION = 0x00010019 > + BASE_NAME = DwEmmcDxe > + FILE_GUID = b549f005-4bd4-4020-a0cb-06f42bda68c3 > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + > + ENTRY_POINT = DwEmmcDxeInitialize > + > +[Sources.common] > + DwEmmcDxe.c > + > +[Packages] > + EmbeddedPkg/EmbeddedPkg.dec > + MdePkg/MdePkg.dec > + Silicon/Synopsys/DesignWare/DesignWare.dec > + > +[LibraryClasses] > + ArmLib > + BaseLib > + BaseMemoryLib > + CacheMaintenanceLib > + IoLib > + MemoryAllocationLib > + TimerLib > + UefiDriverEntryPoint > + UefiLib > + > +[Protocols] > + gEfiCpuArchProtocolGuid > + gEfiDevicePathProtocolGuid > + gEmbeddedMmcHostProtocolGuid > + > +[Pcd] > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeBaseAddress > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeMaxClockFreqInHz > + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeFifoDepth > + gDesignWareTokenSpaceGuid.PcdDwPermitObsoleteDrivers > + > +[Depex] > + TRUE > -- > 2.17.1 >