From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.32.45; helo=nam01-sn1-obe.outbound.protection.outlook.com; envelope-from=vabhav.sharma@nxp.com; receiver=edk2-devel@lists.01.org Received: from NAM01-SN1-obe.outbound.protection.outlook.com (mail-sn1nam01on0045.outbound.protection.outlook.com [104.47.32.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 4C0AE22183C83 for ; Fri, 1 Dec 2017 08:16:13 -0800 (PST) Received: from MWHPR03CA0003.namprd03.prod.outlook.com (10.175.133.141) by BN3PR03MB2356.namprd03.prod.outlook.com (10.166.74.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.282.5; Fri, 1 Dec 2017 16:20:37 +0000 Received: from BN1AFFO11FD035.protection.gbl (2a01:111:f400:7c10::172) by MWHPR03CA0003.outlook.office365.com (2603:10b6:300:117::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.282.5 via Frontend Transport; Fri, 1 Dec 2017 16:20:37 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=nxp.com; nxp.com; dkim=none (message not signed) header.d=none;nxp.com; dmarc=fail action=none header.from=nxp.com; Received-SPF: Fail (protection.outlook.com: domain of nxp.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BN1AFFO11FD035.mail.protection.outlook.com (10.58.52.159) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.20.239.4 via Frontend Transport; Fri, 1 Dec 2017 16:20:36 +0000 Received: from uefi-OptiPlex-790.ap.freescale.net ([10.232.132.56]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id vB1GKSHc013131; Fri, 1 Dec 2017 09:20:32 -0700 From: Vabhav To: , , , Date: Fri, 1 Dec 2017 09:48:48 +0530 Message-ID: <1512101930-11887-2-git-send-email-vabhav.sharma@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1512101930-11887-1-git-send-email-vabhav.sharma@nxp.com> References: <1512101930-11887-1-git-send-email-vabhav.sharma@nxp.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131566188363827979; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7966004)(336005)(376002)(39860400002)(39380400002)(346002)(2980300002)(1110001)(1109001)(339900001)(199003)(189002)(110136005)(316002)(36756003)(54906003)(8656006)(356003)(50226002)(4326008)(8936002)(6666003)(85426001)(19625735003)(77096006)(305945005)(2950100002)(51416003)(97736004)(8676002)(47776003)(5660300001)(76176011)(81156014)(81166006)(16586007)(2201001)(2906002)(68736007)(6306002)(16799955002)(104016004)(105606002)(575784001)(966005)(86362001)(498600001)(48376002)(15188155005)(53946003)(50466002)(53936002)(53376002)(189998001)(33646002)(106466001)(579004)(393754007); DIR:OUT; SFP:1101; SCL:1; SRVR:BN3PR03MB2356; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1AFFO11FD035; 1:ynGxmFkZGFClMxxrOupngK0j4arokGdiHu3YM6jQTslL6SUPyR9T2vpO875WvYZyVw0ZfA66fXN1Ey4kjVScmDGqzVYd+/cPQ2hpL8gIY9/GmGqIbKWKlHQj4XENGH6g MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 40851997-0e6f-4e5d-69aa-08d538d77455 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(4534020)(4628075)(201703131517081)(5600026)(4604075)(2017052603286); SRVR:BN3PR03MB2356; X-Microsoft-Exchange-Diagnostics: 1; BN3PR03MB2356; 3:dNQJgYSXJr/3MwkMyq4oLUFE1x14Nu/ajJXRAsAcMH8Kwd0PyTdZ7vKWxbinKi7NdzwxdY5F+8LthGG1pFmUF7W1n+lmb1mQCNb6dF7ZDc3FrPg5uAnelQJJqCffpMyoZn4TTcLJElBmqT8BWPLFSi0MX+UKJ3lR781yXwSR7uorcf80dxHaML0EQoiV1JPW901BFTBAmKxXqT0bJpYeMcxfVCGkoIGCEUpElk+ekfKqI9bJKpyRJyHRxzYV7074c3/tnGGd/E7kQoraETtNi0aiIpLNreQXcB3Cq7EfV8DxNExDTZacM7oUGTjAG/qNgBCYnZASiRULtC95TjfWJFSLL72I63lwWLEFZmmTJrc=; 25:sbcBBwx5ilZRV4J5fPxZzUXCd95ALdN4BiWXWjlhcJwsspfaz8vEdRMekkmXO9LYL8i1KvEymfxt7g2hQuCbF6Q+i5Cp9jkasOQtLTqW1mGazNQPmv75aJ0ljTRCRQlzfYJp56Mv5m/X3wnXUvx5/Bqhq3m/DEkG/rHLN11oJ68q5OvaIuElCEcrd9vvEbVeLSIGeXuTWpjUWY5t1pop9Ws90zasXNNiPofy3MECLnpny11whDvv1dqg20JQd5tkx9ZvKrP/mEPwCeRfgubCHi/Ifke3pWMwhhsppJhs5J1GTriJWrYC2DY1ECngY10w58GBfRzQFl86QYYGhhniqw== X-MS-TrafficTypeDiagnostic: BN3PR03MB2356: X-Microsoft-Exchange-Diagnostics: 1; BN3PR03MB2356; 31:dgJCfxnImEun0XEcinAkNEVw5ykZolWMNFcvhraEpfzbMSyGSjw8/eC5wza/s6XIpvSSvmfci93a2982LRJVHwsje4cyo1OysvioCcqJDhBpwZUURRvac/GqR6CMoD4o15k0Mn7nJBs5TRAd4YnfLJ+TZHAFrCkO5vF4VwYIAsLN0YJPcsSLb86mx7RWCtqNwL8V0WQrpftKNgxKmIqoGvIos4mHD2xkffx+4kvVxto=; 4:uQbBXCdRMzmqSsVfAdqYPn7RlYAbpBXzUqNffO2JCWwuYxdNODYyOxr4noXS0OpLHFlTx8AF4g8rtgRc5H2ahGz6SNegrlskXLTIaLaqmF+FJqCn2n2QSmLwV1MNxN5ubnVaVMOO7lbs0Bxz8JBvQ838amYnbpEdnisyMnY6dVXtIIsym28gyt1TmLgIQiEN8Jhyy7JVvfBWz9NuuN6En5l1C84SghfMQVKtcaMZ9U8FlOn7Ic5mCdZLd/stG50014R/wc+0IbQIJ+pNduaEkUh6i8RSbSqZF7YvRN6uefDJ3wCxIdsjv46/awyqSmzd X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6095135)(2401047)(5005006)(8121501046)(3231022)(10201501046)(3002001)(93006095)(93001095)(6055026)(6096035)(20161123561025)(20161123559100)(201703131430075)(201703131433075)(201703131441075)(201703131448075)(201703161259150)(20161123563025)(20161123565025)(20161123556025)(201708071742011); SRVR:BN3PR03MB2356; BCL:0; PCL:0; RULEID:(100000803101)(100110400095)(400006); SRVR:BN3PR03MB2356; X-Forefront-PRVS: 05087F0C24 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN3PR03MB2356; 23:BDiq4ZHtuxBLWl9EISmhAEt+pRBdBrj0cYS01XQ6q?= =?us-ascii?Q?I2kUk1QRWPlZz5TfZajPuWPLj7qcCdu4GqM6Iq8Vk71+ZCrHn6p9EtyEwkGl?= =?us-ascii?Q?M52GH97/yzn3Q3uqDkcDzv61v0CTnEbS0alqLkgg4rynHzdOpQ8ZqPazYjPB?= =?us-ascii?Q?yRu/Ecc/3YdkFvP4QU2amU8qXz4D3IZIYPFeD3z9fChJq73YHbsE5U8Wuoci?= =?us-ascii?Q?LpsLec8K0IQUcY46S6Zd3MiizqsP1ujxX6Q3aBpAeDIXfxaaRW0FK88pdD0J?= =?us-ascii?Q?ARPQHr6H136awTUh5TVDi/VGPbTZmKeXA02rJMs2NIsIQUYGK0j1oLdW3pwV?= =?us-ascii?Q?ueZjqAstHCbjhovj4XX4RqwedaGx0LJ7PcN8ksqtKnuFaV0gzbj9f9EpGIBa?= =?us-ascii?Q?/ggDpvNNAQBMWWlmEgNtMysvZrcWZMA3D6N/nDBsnc47VGHAoZs335ZHu2V+?= =?us-ascii?Q?BIzpBIGc8h4/Dc2DIr9VWdCIsfZ56NPV/kRfTaoza4OWqZnzSMZTln1nh8Un?= =?us-ascii?Q?zOIHrN6LQg8VixnagbAPM8oM93bn1Gn3zzi/sRPmbhXVM152xryKUzmFpr+j?= =?us-ascii?Q?7yUwhIwm6upxBI5ELvyxi9R6EGAuA00CTYp4jjdJoj3ACcbIOwf1mjFEQcnS?= =?us-ascii?Q?cswFr1ZdrbnargRC2JEztxwURP/qrDhiUa9N0eiJGlfydvBVgKw7VKW611cY?= =?us-ascii?Q?7JRR0L5mEujeFztBcJD63z4BvL05mM3KIqglYaWZ3ryGF7Sp7h5NUNw8JNbz?= =?us-ascii?Q?i1QIG1mLpGxh7unAbHW3NgiULu35AaB6ZTItwWqJULSC3bcwga8YyzSX9aQt?= =?us-ascii?Q?8yITXKInbPKc+/yYHrY5djPC5l8qkEk+mXqQmJSwejj5dZ8lcKPRZKKuIXnc?= =?us-ascii?Q?r3YGd3MrxrgrT2UzV4urKIA96Yoblr2SJb3eL2gUQgiIJR6H8U+U6S2+4+tX?= =?us-ascii?Q?mltQa+sMj9EoEayenGAt1Z+m75upTXe3x60WKSCblAgCKqRL0YtrvAfkaXBz?= =?us-ascii?Q?EbmTHxIB0eRFu7vmC4Cocu7865Xb4Eebi7gKCsI6zft7/PA9ej+lbb9l+xU2?= =?us-ascii?Q?7gjEJ4iwoolzlEXn5p8RYJItJuH5iPxvQZQCcc9GPXpnCcB86M3x3CEFBtee?= =?us-ascii?Q?ohLazADgFaNGxsVL9bTmA6/MgpZi5oV1NuHnpC6Q5hg/+0Aks/K3udt3cSrR?= =?us-ascii?Q?6OdQzcmZVbqZi/ve2CFCDFP5dBws7KUL5Hk4zq2f20b07RzLCRtNtwEKO2k5?= =?us-ascii?Q?/71Fqvr1SL0grKZRP5+LCjjy9Gwa3U0VmWqJoK4g+K/cwH+6xMLTx868ONR8?= =?us-ascii?Q?zpxvdC64veawTvDFqYEPOObtIPw9zEzYkQ+PQqmaxPcGHP2lTuE6IewLS72Z?= =?us-ascii?Q?r4WP9D9yHJGeh2g+flSsQjf9X8=3D?= X-Microsoft-Exchange-Diagnostics: 1; BN3PR03MB2356; 6:I1qBnfid6mt4mrDZApTI2ksW+p9rsvrdgXVNNf7JAy6ff4O10fTSengTMLjjV8XmDCOYCRViVzFmnQ2gQd45+a+wzgasbH5sYOXjXt3gxCOnmaLTn8l101BsLPxhjLxbnhYonudPhR6VtdQshAZ9d/tTvJdSh88Tp7rqtV4WWIGMtVirdmedQiqOfsw5vimklhj+4oJnlEUk+Va+YXR0uPPxMdGW1EoPPEoBkrH+P/Q6KMjQREmZozGwdDgYuzv5EilaX1RXcT1pJiryZh9yiMG7xHSZcEdTcs8FKQINbeKoqCRKLVgG5BvmLXHfH+z+rpa4dyAOXoq+KzqzLrJBaECzVXOXsxNY7TnoGGKtAzg=; 5:JEstXHHuxw2tsw+FQpcIiXecDeX5CEF+hfMlGuIUL2OafuDsTtjQaDb/WINy1WvERSG5kDMRus/A5R4ySPSefQpCZSvgw7wdGIcfPaAA8S5jiwDO7VqqCs0l7hAD8dnxeiWSAehwyZfTBrzVA3SN8g2A7Ow8u8eZLFRINE76U/o=; 24:mDgLs3Sxh1U77a4BJvnCdrvFj4jBUWLhxVo44JdH9RrtKyBolYwAl1uLx4Y7A2E8EdvlCoYQJ7C1A9aWuMtSM/lBjk4N0DawNTVl+K5UjOU=; 7:msViODacGrpx02fMd793niiVqpfplU/kA791o8CpkH9+8XOZif/SJNm1v0HCCO3jKry+4pA2YYtv/gRfetuSnzVK5vWnutS4de5Eui36jC+86TXwjR7L7BmQ+1g7vMFaluKEaTRmhwW+9KuXQw7zHksAD1YLMrQHOmKav3QDUmgq/esz8z9EBs5zyfE+y2T7d8PVhV9Q2BO3+kJRGRhotXy4JgH0T0YHsD5evOGvYVfERUpp5mwfTs/GSqP1KRer SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Dec 2017 16:20:36.1955 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 40851997-0e6f-4e5d-69aa-08d538d77455 X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN3PR03MB2356 Subject: [PATCH 1/3] Platform/NXP :Add Support for MMC Library X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Dec 2017 16:16:13 -0000 Content-Type: text/plain This patch adds support for MMC library(MmcLib)to provide functions which will be used by MMC Host driver. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Meenakshi Aggarwal Signed-off-by: Vabhav --- Platform/NXP/Include/Library/MmcLib.h | 138 +++++++ Platform/NXP/Library/MmcLib/MmcInterface.c | 544 ++++++++++++++++++++++++++ Platform/NXP/Library/MmcLib/MmcInternal.h | 350 +++++++++++++++++ Platform/NXP/Library/MmcLib/MmcLib.c | 597 +++++++++++++++++++++++++++++ Platform/NXP/Library/MmcLib/MmcLib.inf | 39 ++ 5 files changed, 1668 insertions(+) create mode 100644 Platform/NXP/Include/Library/MmcLib.h create mode 100644 Platform/NXP/Library/MmcLib/MmcInterface.c create mode 100644 Platform/NXP/Library/MmcLib/MmcInternal.h create mode 100644 Platform/NXP/Library/MmcLib/MmcLib.c create mode 100644 Platform/NXP/Library/MmcLib/MmcLib.inf diff --git a/Platform/NXP/Include/Library/MmcLib.h b/Platform/NXP/Include/Library/MmcLib.h new file mode 100644 index 0000000..36941bc --- /dev/null +++ b/Platform/NXP/Include/Library/MmcLib.h @@ -0,0 +1,138 @@ +/** @file + Header Defining The MMC Memory Controller Constants, Function Prototype, Structures Etc + + Copyright 2017 NXP + + This Program And The Accompanying Materials + Are Licensed And Made Available Under The Terms And Conditions Of The BSD + License Which Accompanies This Distribution. The Full Text Of The License + May Be Found At + Http://Opensource.Org/Licenses/Bsd-License.Php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __MMCLIB_H__ +#define __MMCLIB_H__ + +#include +#include + +//define MMC_DEBUG to enable debug feature +//#define MMC_DEBUG 1 +#ifdef MMC_DEBUG +#define DEBUG_MSG(_Fmt,...) DEBUG ((DEBUG_ERROR, "MMC: " _Fmt, ##__VA_ARGS__)); +#else +#define DEBUG_MSG(_Fmt,...) +#endif + +/** + MMC RESPONSE TYPE +**/ +#define MMC_RSP_PRESENT (1 << 0) +#define MMC_RSP_136 (1 << 1) // 136 Bit Response +#define MMC_RSP_CRC (1 << 2) // Expect Valid Crc +#define MMC_RSP_BUSY (1 << 3) // Card May Send Busy +#define MMC_RSP_OPCODE (1 << 4) // Response Contains Opcode + +#define MMC_RSP_NONE (0) +#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R1b (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE| \ + MMC_RSP_BUSY) +#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) +#define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) + +/** + Find most significant set + + @param X word to search + + @retval most significant set bit number + +**/ +static inline INT32 GenericFls (INT32 X) +{ + + INT32 I = 31; + + for (I=31; I >= 0; I--) { + if(X & (1< +#include +#include +#include +#include + +#include "MmcInternal.h" + +struct Mmc *mMmc; + +/** + Function to detect card presence by checking host controller + present state register + + @retval Returns the card presence as TRUE/FALSE + +**/ +BOOLEAN +DetectCardPresence ( + IN VOID + ) +{ + struct SdxcRegs *Regs; + INT32 Timeout; + + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + Timeout = 1000; + + while (!(MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_CINS) && --Timeout) + MicroSecondDelay (10); + + if (Timeout > 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Function to check whether card is read only by verifying host controller + present state register + + @retval Returns the card read only or not as TRUE/FALSE + +**/ +BOOLEAN +IsCardReadOnly ( + IN VOID + ) +{ + struct SdxcRegs *Regs; + + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + + if (MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_WPSPL) { + return FALSE; + } else { + DEBUG ((DEBUG_ERROR, "SD/MMC : Write Protection PIN is high\n")); + return TRUE; + } +} + +/** + Function to prepare state(Wait for bus,Set up host controller + data,Transfer type) for command to be send + + @param Cmd Command to be used + @param Data Data with command + + @retval Returns the command status + +**/ +EFI_STATUS +SendCmd ( + IN struct SdCmd *Cmd, + IN struct SdData *Data + ) +{ + EFI_STATUS Status; + UINT32 Xfertype; + UINT32 Irqstat; + INT32 Timeout; + struct SdxcRegs *Regs; + + Status = 0; + Timeout = 100000; + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + + DEBUG_MSG ("0x%x : Cmd.Id %d, Arg 0x%x SdCmd.RespType 0x%x \n", + Regs, Cmd->CmdIdx, Cmd->CmdArg, Cmd->RespType); + + MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF); + + asm ("Dmb :"); + + // Wait for The Bus To Be Idle + while ((MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_CICHB) || + (MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_CIDHB)) + NanoSecondDelay (10); + + // Wait for data line to be active + while (MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_DLA) + NanoSecondDelay (10); + + // Wait Before The Next Command + MicroSecondDelay (1000); + + // Set Up for A Data Transfer if We Have One + if (Data) { + Status = SdxcSetupData (Data); + if (Status) { + return Status; + } + } + + // Figure Out The Transfer Arguments + Xfertype = SdxcXfertype (Cmd, Data); + + // Mask All Irqs + MmcWrite ((UINTN)&Regs->Irqsigen, 0); + + // Send The Command + MmcWrite ((UINTN)&Regs->CmdArg, Cmd->CmdArg); + MmcWrite ((UINTN)&Regs->Xfertype, Xfertype); + + // Wait for The Command To Complete + Timeout = 100000; + while ((!(MmcRead ((UINTN)&Regs->Irqstat) & (IRQSTATE_CC | IRQSTATE_CTOE))) + && Timeout--); + + if (Timeout <= 0) { + DEBUG ((DEBUG_ERROR, "Command not completed %d\n", Cmd->CmdIdx)); + return EFI_TIMEOUT; + } + + Irqstat = MmcRead ((UINTN)&Regs->Irqstat); + + if (Irqstat & CMD_ERR) { + Status = EFI_DEVICE_ERROR; + DEBUG ((DEBUG_ERROR, "SdxcSendCmd: Device Error(0x%x) for Cmd(%d)\n", + Irqstat, Cmd->CmdIdx)); + goto Out; + } + + if (Irqstat & IRQSTATE_CTOE) { + Status = EFI_TIMEOUT; + DEBUG ((DEBUG_ERROR, "SdxcSendCmd: Timeout for Cmd(%d)\n", Cmd->CmdIdx)); + goto Out; + } + +Out: + if (Status) { + ResetCmdFailedData (Regs, (Data != NULL)); + } + else { + MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF); + } + return Status; + +} + +/** + Function to receive command response + + @param RespType Type of response + @param Data Data of response + + @param Response Pointer to response buffer + + @retval Returns the command response status + +**/ +EFI_STATUS +RcvResp ( + IN UINT32 RespType, + OUT UINT32* Response, + IN UINT8 Data + ) +{ + if (RespType != 0xFF) { + INT32 Timeout; + struct SdxcRegs *Regs; + + Timeout = 25000; + Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr); + + // Workaround for SDXC Errata ENGcm03648 + if (!Data && (RespType & MMC_RSP_BUSY)) { + Timeout = 25000; + + // Poll On DATA0 Line for Cmd With Busy Signal for 250 Ms + while (Timeout > 0 && !(MmcRead ((UINTN)&Regs->Prsstat) & + PRSSTATE_DAT0)) { + MicroSecondDelay (100); + Timeout--; + } + + if (Timeout <= 0) { + DEBUG ((DEBUG_ERROR, "Timeout Waiting for DAT0 To Go High!\n")); + ResetCmdFailedData (Regs, Data); + return EFI_TIMEOUT; + } + } + + // Copy The Response To The Response Buffer + if (RespType & MMC_RSP_136) { + UINT32 Rspns3, Rspns2, Rspns1, Rspns0; + + Rspns3 = MmcRead ((UINTN)&Regs->Rspns3); + Rspns2 = MmcRead ((UINTN)&Regs->Rspns2); + Rspns1 = MmcRead ((UINTN)&Regs->Rspns1); + Rspns0 = MmcRead ((UINTN)&Regs->Rspns0); + Response[3] = (Rspns3 << 8) | (Rspns2 >> 24); + Response[2] = (Rspns2 << 8) | (Rspns1 >> 24); + Response[1] = (Rspns1 << 8) | (Rspns0 >> 24); + Response[0] = (Rspns0 << 8); + DEBUG_MSG ("RESP : 0x%x : 0x%x : 0x%x : 0x%x \n", + Response[0], Response[1], Response[2], Response[3]); + } else { + Response[0] = MmcRead ((UINTN)&Regs->Rspns0); + } + } + + return EFI_SUCCESS; +} + +/** + Function to prepare command transfer + + @param Flags Flags for transferType of response + @param Length Length of block + @param Cmd Pointer to command structure + + @retval Returns the command status + +**/ +EFI_STATUS +PrepareTransfer ( + UINT32 Flags, + IN UINTN Length, + IN VOID* Buffer, + IN struct SdCmd *Cmd + ) +{ + EFI_STATUS Status; + struct SdData Data; + + Data.Flags = Flags; + + if (Length > MMC_MAX_BLOCK_LEN) { + Data.Blocks = (Length / MMC_MAX_BLOCK_LEN) + + ((Length % MMC_MAX_BLOCK_LEN) ? 1 : 0); + Data.Blocksize = MMC_MAX_BLOCK_LEN; + } else { + Data.Blocks = 1; + Data.Blocksize = Length; + } + + Data.Addr = Buffer; + + Status = SendCmd (Cmd, &Data); + + return Status; +} + +/** + Function to Read MMC Block + + @param Offset Offset to read from + @param Length Length of block + @param Cmd Pointer to command structure + + @param Buffer Pointer to buffer for data read + + @retval Returns the read block command status + +**/ +EFI_STATUS +ReadBlock ( + IN UINTN Offset, + IN UINTN Length, + OUT UINT32* Buffer, + IN struct SdCmd Cmd + ) +{ + EFI_STATUS Status; + struct DmaData DmaData; + VOID * Temp; + + Temp = NULL; + + DmaData.Bytes = Length; + DmaData.MapOperation = MapOperationBusMasterRead; + + Temp = GetDmaBuffer (&DmaData); + if (Temp == NULL) { + DEBUG ((DEBUG_ERROR,"Mmc Read : Failed to get DMA buffer \n")); + return EFI_OUT_OF_RESOURCES; + } + + Status = PrepareTransfer (MMC_DATA_READ, Length, Temp, &Cmd); + if (Status) { + DEBUG((DEBUG_ERROR,"Mmc Read: Fail to setup controller 0x%x \n", Status)); + FreeDmaBuffer (&DmaData); + return Status; + } + + Status = Transfer (); + if (Status) { + DEBUG ((DEBUG_ERROR,"Mmc Read Failed (0x%x) \n", Status)); + FreeDmaBuffer (&DmaData); + return Status; + } + + InternalMemCopyMem (Buffer, Temp , DmaData.Bytes); + + Status = FreeDmaBuffer (&DmaData); + if (Status) { + DEBUG ((DEBUG_ERROR,"Mmc Read : Failed to release DMA buffer \n")); + return Status; + } + + return Status; +} + +/** + Function to Write MMC Block + + @param Offset Offset to write to + @param Length Length of block + @param Buffer Pointer to buffer for data to be written + @param Cmd Pointer to command structure + + @retval Returns the write block command status + +**/ +EFI_STATUS +WriteBlock ( + IN UINTN Offset, + IN UINTN Length, + IN UINT32* Buffer, + IN struct SdCmd Cmd + ) +{ + EFI_STATUS Status; + struct DmaData DmaData; + VOID * Temp; + + Temp = NULL; + + DmaData.Bytes = Length; + DmaData.MapOperation = MapOperationBusMasterWrite; + + Temp = GetDmaBuffer (&DmaData); + if (Temp == NULL) { + DEBUG ((DEBUG_ERROR,"Mmc Write : Failed to get DMA buffer \n")); + return EFI_OUT_OF_RESOURCES; + } + + InternalMemCopyMem (Temp, Buffer, DmaData.Bytes); + + Status = PrepareTransfer (MMC_DATA_WRITE, Length, Temp, &Cmd); + if (Status) { + DEBUG ((DEBUG_ERROR,"Mmc Write: Fail to setup controller 0x%x \n", Status)); + FreeDmaBuffer (&DmaData); + return Status; + } + + Status = Transfer (); + if (Status) { + DEBUG((DEBUG_ERROR,"Mmc Write Failed (0x%x) \n", Status)); + FreeDmaBuffer (&DmaData); + return Status; + } + + Status = FreeDmaBuffer (&DmaData); + if (Status) { + DEBUG ((DEBUG_ERROR,"Mmc Write : Failed to release DMA buffer \n")); + return Status; + } + + return Status; +} + +/** + Function to Initialize MMC + + // Set Bus width + // Set protocol register + + @retval Returns the initialization status + +**/ +EFI_STATUS +InitMmc ( + IN VOID + ) +{ + EFI_STATUS Status; + struct SdxcRegs *Regs; + + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + + Status = SdxcInit (mMmc); + if (Status) { + return Status; + } + + mMmc->DdrMode = 0; + SdxcSetBusWidth (mMmc, 1); + + MmcAnd ((UINTN)&Regs->Proctl, ~PRCTL_BE); + + return Status; +} + +/** + Function to set MMC clock speed + + @param BusClockFreq Bus clock frequency to be set Offset to write to + @param BusWidth Bus width + @param TimingMode Timing mode to be set + +**/ +VOID +SetIos ( + IN UINT32 BusClockFreq, + IN UINT32 BusWidth, + IN UINT32 TimingMode + ) +{ + struct SdxcRegs *Regs; + + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + + DEBUG_MSG ("BusClockFreq %d, BusWidth %d\n", BusClockFreq, BusWidth); + + // Set The Clock Speed + if (BusClockFreq) { + SetSysctl (BusClockFreq); + } + + // Set The Bus Width + if (BusWidth) { + MmcAnd ((UINTN)&Regs->Proctl, ~(PRCTL_DTW_4 | PRCTL_DTW_8)); + } + + if (BusWidth == 4) { + MmcOr ((UINTN)&Regs->Proctl, PRCTL_DTW_4); + } + else if (BusWidth == 8) { + MmcOr ((UINTN)&Regs->Proctl, PRCTL_DTW_8); + } +} + +/** + Helper Function to initialize MMC + + // Reset MMC controller + // Set host voltage capabilities + // Set MMC clock + +**/ +EFI_STATUS +MmcInitialize ( + VOID + ) +{ + EFI_STATUS Status; + struct SdxcRegs *Regs; + + UINT32 Caps, VoltageCaps; + UINTN Voltages; + + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + + // First Reset The SDXC Controller + SdxcReset (Regs); + + VoltageCaps = 0; + Caps = MmcRead ((UINTN)&Regs->Hostcapblt); + + Caps = Caps | SDXC_HOSTCAPBLT_VS33; + + if (Caps & SDXC_HOSTCAPBLT_VS30) { + VoltageCaps |= MMC_VDD_29_30 | MMC_VDD_30_31; + } + if (Caps & SDXC_HOSTCAPBLT_VS33) { + VoltageCaps |= MMC_VDD_32_33 | MMC_VDD_33_34; + } + if (Caps & SDXC_HOSTCAPBLT_VS18) { + VoltageCaps |= MMC_VDD_165_195; + } + + Voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + if ((Voltages & VoltageCaps) == 0) { + DEBUG ((DEBUG_ERROR, "Voltage Not Supported By Controller\n")); + return EFI_DEVICE_ERROR; + } + + mMmc = (struct Mmc*)AllocatePool (sizeof (struct Mmc)); + if (mMmc == NULL) { + DEBUG ((DEBUG_ERROR, "Memory Allocation failed for gMMC\n")); + return EFI_OUT_OF_RESOURCES; + } + + InternalMemZeroMem (mMmc, sizeof (struct Mmc)); + + mMmc->SdhcClk = GetSdxcFrequency (); + + mMmc->HostCaps = MMC_MODE_4_BIT | MMC_MODE_8_BIT | MMC_MODE_HC; + + if (Caps & SDXC_HOSTCAPBLT_HSS) { + mMmc->HostCaps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + } + + mMmc->FMin = MIN_CLK_FREQUENCY; + mMmc->FMax = MIN ((UINT32)mMmc->SdhcClk, MAX_CLK_FREQUENCY); + + Status = InitMmc (); + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR,"Failed to initialize MMC\n")); + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Platform/NXP/Library/MmcLib/MmcInternal.h b/Platform/NXP/Library/MmcLib/MmcInternal.h new file mode 100644 index 0000000..0e56764 --- /dev/null +++ b/Platform/NXP/Library/MmcLib/MmcInternal.h @@ -0,0 +1,350 @@ +/** @file + Header Defining The MMC Memory Controller Constants, Function Prototype, Structures Etc + + Copyright 2017 NXP + + This Program And The Accompanying Materials + Are Licensed And Made Available Under The Terms And Conditions Of The BSD + License Which Accompanies This Distribution. The Full Text Of The License + May Be Found At + Http://Opensource.Org/Licenses/Bsd-License.Php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __MMC_INTERNAL_H__ +#define __MMC_INTERNAL_H__ + +#include + +#define MIN_CLK_FREQUENCY 400000 +#define MAX_CLK_FREQUENCY 52000000 + +#define ENABLE_CACHE_SNOOPING 0x00000040 +#define CMD_STOP_TRANSMISSION 12 +/** + Pre Div factor for DDR mode +**/ +#define DIV_2 2 +#define DIV_1 1 + +/** + SDXC-Specific Constants +**/ +#define SYSCTL 0x0002e02c +#define SYSCTL_INITA 0x08000000 +#define SYSCTL_TIMEOUT_MASK 0x000f0000 +#define SYSCTL_CLOCK_MASK 0x0000fff0 +#define SYSCTL_CKEN 0x00000008 +#define SYSCTL_PEREN 0x00000004 +#define SYSCTL_HCKEN 0x00000002 +#define SYSCTL_IPGEN 0x00000001 +#define SYSCTL_RSTA 0x01000000 +#define SYSCTL_RSTC 0x02000000 +#define SYSCTL_RSTD 0x04000000 + +/** + Host Capabilities +**/ +#define SDXC_HOSTCAPBLT_VS18 0x04000000 +#define SDXC_HOSTCAPBLT_VS30 0x02000000 +#define SDXC_HOSTCAPBLT_VS33 0x01000000 +#define SDXC_HOSTCAPBLT_SRS 0x00800000 +#define SDXC_HOSTCAPBLT_DMAS 0x00400000 +#define SDXC_HOSTCAPBLT_HSS 0x00200000 + +/** + VDD Voltage Range +**/ +#define MMC_VDD_165_195 0x00000080 // VDD Voltage 1.65 - 1.95 +#define MMC_VDD_20_21 0x00000100 // VDD Voltage 2.0 ~ 2.1 +#define MMC_VDD_21_22 0x00000200 // VDD Voltage 2.1 ~ 2.2 +#define MMC_VDD_22_23 0x00000400 // VDD Voltage 2.2 ~ 2.3 +#define MMC_VDD_23_24 0x00000800 // VDD Voltage 2.3 ~ 2.4 +#define MMC_VDD_24_25 0x00001000 // VDD Voltage 2.4 ~ 2.5 +#define MMC_VDD_25_26 0x00002000 // VDD Voltage 2.5 ~ 2.6 +#define MMC_VDD_26_27 0x00004000 // VDD Voltage 2.6 ~ 2.7 +#define MMC_VDD_27_28 0x00008000 // VDD Voltage 2.7 ~ 2.8 +#define MMC_VDD_28_29 0x00010000 // VDD Voltage 2.8 ~ 2.9 +#define MMC_VDD_29_30 0x00020000 // VDD Voltage 2.9 ~ 3.0 +#define MMC_VDD_30_31 0x00040000 // VDD Voltage 3.0 ~ 3.1 +#define MMC_VDD_31_32 0x00080000 // VDD Voltage 3.1 ~ 3.2 +#define MMC_VDD_32_33 0x00100000 // VDD Voltage 3.2 ~ 3.3 +#define MMC_VDD_33_34 0x00200000 // VDD Voltage 3.3 ~ 3.4 +#define MMC_VDD_34_35 0x00400000 // VDD Voltage 3.4 ~ 3.5 +#define MMC_VDD_35_36 0x00800000 // VDD Voltage 3.5 ~ 3.6 + +/** + MMC Operating Modes +**/ +#define MMC_MODE_HS (1 << 0) +#define MMC_MODE_HS_52MHz (1 << 1) +#define MMC_MODE_4_BIT (1 << 2) +#define MMC_MODE_8_BIT (1 << 3) +#define MMC_MODE_SPI (1 << 4) +#define MMC_MODE_HC (1 << 5) +#define MMC_MODE_DDR_52MHz (1 << 6) + +#define MMC_DATA_READ 1 +#define MMC_DATA_WRITE 2 + +/** + Maximum Block Size for MMC +**/ +#define MMC_MAX_BLOCK_LEN 512 + +#define WML_RD_MAX 0x10 +#define WML_WR_MAX 0x80 +#define WML_RD_MAX_VAL 0x00 +#define WML_WR_MAX_VAL 0x80 +#define WML_RD_MASK 0xff +#define WML_WR_MASK 0xff0000 + +#define XFERTYPE 0x0002e00c +#define XFERTYPE_CMD(X) ((X & 0x3f) << 24) +#define XFERTYPE_CMDTYP_NORMAL 0x0 +#define XFERTYPE_CMDTYP_SUSPEND 0x00400000 +#define XFERTYPE_CMDTYP_RESUME 0x00800000 +#define XFERTYPE_CMDTYP_ABORT 0x00c00000 +#define XFERTYPE_DPSEL 0x00200000 +#define XFERTYPE_CICEN 0x00100000 +#define XFERTYPE_CCCEN 0x00080000 +#define XFERTYPE_RSPTYP_NONE 0 +#define XFERTYPE_RSPTYP_136 0x00010000 +#define XFERTYPE_RSPTYP_48 0x00020000 +#define XFERTYPE_RSPTYP_48_BUSY 0x00030000 +#define XFERTYPE_MSBSEL 0x00000020 +#define XFERTYPE_DTDSEL 0x00000010 +#define XFERTYPE_AC12EN 0x00000004 +#define XFERTYPE_BCEN 0x00000002 +#define XFERTYPE_DMAEN 0x00000001 + +/** + IRQSTAT bits +**/ +#define IRQSTAT (0x0002e030) +#define IRQSTATE_DMAE (0x10000000) +#define IRQSTATE_AC12E (0x01000000) +#define IRQSTATE_DEBE (0x00400000) +#define IRQSTATE_DCE (0x00200000) +#define IRQSTATE_DTOE (0x00100000) +#define IRQSTATE_CIE (0x00080000) +#define IRQSTATE_CEBE (0x00040000) +#define IRQSTATE_CCE (0x00020000) +#define IRQSTATE_CTOE (0x00010000) +#define IRQSTATE_CINT (0x00000100) +#define IRQSTATE_CRM (0x00000080) +#define IRQSTATE_CINS (0x00000040) +#define IRQSTATE_BRR (0x00000020) +#define IRQSTATE_BWR (0x00000010) +#define IRQSTATE_DINT (0x00000008) +#define IRQSTATE_BGE (0x00000004) +#define IRQSTATE_TC (0x00000002) +#define IRQSTATE_CC (0x00000001) + +#define CMD_ERR (IRQSTATE_CIE | IRQSTATE_CEBE | IRQSTATE_CCE) +#define DATA_ERR (IRQSTATE_DEBE | IRQSTATE_DCE | IRQSTATE_DTOE | \ + IRQSTATE_DMAE) +#define DATA_COMPLETE (IRQSTATE_TC | IRQSTATE_DINT) + +#define IRQSTATE_EN (0x0002e034) +#define IRQSTATE_EN_DMAE (0x10000000) +#define IRQSTATE_EN_AC12E (0x01000000) +#define IRQSTATE_EN_DEBE (0x00400000) +#define IRQSTATE_EN_DCE (0x00200000) +#define IRQSTATE_EN_DTOE (0x00100000) +#define IRQSTATE_EN_CIE (0x00080000) +#define IRQSTATE_EN_CEBE (0x00040000) +#define IRQSTATE_EN_CCE (0x00020000) +#define IRQSTATE_EN_CTOE (0x00010000) +#define IRQSTATE_EN_CINT (0x00000100) +#define IRQSTATE_EN_CRM (0x00000080) +#define IRQSTATE_EN_CINS (0x00000040) +#define IRQSTATE_EN_BRR (0x00000020) +#define IRQSTATE_EN_BWR (0x00000010) +#define IRQSTATE_EN_DINT (0x00000008) +#define IRQSTATE_EN_BGE (0x00000004) +#define IRQSTATE_EN_TC (0x00000002) +#define IRQSTATE_EN_CC (0x00000001) + +#define PRSSTATE (0x0002e024) +#define PRSSTATE_DAT0 (0x01000000) +#define PRSSTATE_CLSL (0x00800000) +#define PRSSTATE_WPSPL (0x00080000) +#define PRSSTATE_CDPL (0x00040000) +#define PRSSTATE_CINS (0x00010000) +#define PRSSTATE_BREN (0x00000800) +#define PRSSTATE_BWEN (0x00000400) +#define PRSSTATE_DLA (0x00000004) +#define PRSSTATE_CICHB (0x00000002) +#define PRSSTATE_CIDHB (0x00000001) + +#define PRCTL 0x0002e028 +#define PRCTL_INIT 0x00000020 +#define PRCTL_DTW_4 0x00000002 +#define PRCTL_DTW_8 0x00000004 +#define PRCTL_BE 0x00000030 + +struct SdxcRegs { + UINT32 Dsaddr; // SDMA System Address Register + UINT32 Blkattr; // Block Attributes Register + UINT32 CmdArg; // Command Argument Register + UINT32 Xfertype; // Transfer Type Register + UINT32 Rspns0; // Command Response 0 Register + UINT32 Rspns1; // Command Response 1 Register + UINT32 Rspns2; // Command Response 2 Register + UINT32 Rspns3; // Command Response 3 Register + UINT32 Datport; // Buffer Data Port Register + UINT32 Prsstat; // Present State Register + UINT32 Proctl; // Protocol Control Register + UINT32 Sysctl; // System Control Register + UINT32 Irqstat; // Interrupt Status Register + UINT32 Irqstaten; // Interrupt Status Enable Register + UINT32 Irqsigen; // Interrupt Signal Enable Register + UINT32 Autoc12err; // Auto CMD Error Status Register + UINT32 Hostcapblt; // Host Controller Capabilities Register + UINT32 Wml; // Watermark Level Register + UINT32 Mixctrl; // for USDHC + CHAR8 Reserved1[4]; // Reserved + UINT32 Fevt; // Force Event Register + UINT32 Admaes; // ADMA Error Status Register + UINT32 Adsaddr; // ADMA System Address Register + CHAR8 Reserved2[100];// Reserved + UINT32 VendorSpec; //Vendor Specific Register + CHAR8 Reserved3[56];// Reserved + UINT32 Hostver; // Host Controller Version Register + CHAR8 Reserved4[4];// Reserved + UINT32 Dmaerraddr; // DMA Error Address Register + CHAR8 Reserved5[4];// Reserved + UINT32 Dmaerrattr; // DMA Error Attribute Register + CHAR8 Reserved6[4];// Reserved + UINT32 Hostcapblt2; // Host Controller Capabilities Register 2 + CHAR8 Reserved7[8];// Reserved + UINT32 Tcr; // Tuning Control Register + CHAR8 Reserved8[28];// Reserved + UINT32 Sddirctl; // SD Direction Control Register + CHAR8 Reserved9[712];// Reserved + UINT32 Scr; // SDXC Control Register +}; + +struct DmaData { + VOID *DmaAddr; + UINTN Bytes; + VOID *Mapping; + DMA_MAP_OPERATION MapOperation; +}; + +struct Mmc { + UINT32 SdhcClk; + UINT32 HostCaps; + UINT32 HasInit; + UINT32 FMin; + UINT32 FMax; + UINT32 BusWidth; + UINT32 Clock; + UINT32 CardCaps; + INT32 DdrMode; +}; + +VOID +SdxcSetClock ( + IN struct Mmc *Mmc, + IN UINT32 Clock + ); + +EFI_STATUS +SdxcInit ( + IN struct Mmc *Mmc + ); + +EFI_STATUS +SdxcGoIdle ( + IN struct Mmc *Mmc + ); + +VOID +SdxcReset ( + IN struct SdxcRegs *Regs + ); + +VOID * +GetDmaBuffer ( + IN struct DmaData *DmaData + ); + +EFI_STATUS +FreeDmaBuffer ( + IN struct DmaData *DmaData + ); + +EFI_STATUS +SdxcSetupData ( + IN struct SdData *Data + ); + +UINT32 +SdxcXfertype ( + IN struct SdCmd *Cmd, + IN struct SdData *Data + ); + +VOID +ResetCmdFailedData ( + IN struct SdxcRegs *Regs, + IN UINT8 Data + ); + +VOID +SdxcSetBusWidth ( + IN struct Mmc *Mmc, + IN UINT32 BWidth + ); + +EFI_STATUS +Transfer ( + IN VOID + ); + +VOID +SetSysctl ( + UINT32 Clock + ); + +UINT32 +EFIAPI +MmcRead ( + IN UINTN Address + ); + +UINT32 +EFIAPI +MmcWrite ( + IN UINTN Address, + IN UINT32 Value + ); + +UINT32 +EFIAPI +MmcAndThenOr ( + IN UINTN Address, + IN UINT32 AndData, + IN UINT32 OrData + ); + +UINT32 +EFIAPI +MmcOr ( + IN UINTN Address, + IN UINT32 OrData + ); + +UINT32 +EFIAPI +MmcAnd ( + IN UINTN Address, + IN UINT32 AndData + ); + +#endif diff --git a/Platform/NXP/Library/MmcLib/MmcLib.c b/Platform/NXP/Library/MmcLib/MmcLib.c new file mode 100644 index 0000000..83b12c9 --- /dev/null +++ b/Platform/NXP/Library/MmcLib/MmcLib.c @@ -0,0 +1,597 @@ +/**@file + + Copyright 2017 NXP + + This Program And The Accompanying Materials + Are Licensed And Made Available Under The Terms And Conditions Of The BSD License + Which Accompanies This Distribution. The Full Text Of The License May Be Found At + Http://Opensource.Org/Licenses/Bsd-License.Php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include "MmcInternal.h" + +extern struct Mmc *mMmc; + +/** + Function to read from MMC depending upon pcd + + @param Address MMC register to read + + @retval Read Value from register + +**/ +UINT32 +EFIAPI +MmcRead ( + IN UINTN Address + ) +{ + if (FixedPcdGetBool (PcdMmcBigEndian)) { + return BeMmioRead32(Address); + } else { + return MmioRead32 (Address); + } +} + +/** + Function to write on MMC depeding upon pcd + + @param Address MMC register to write + +**/ +UINT32 +EFIAPI +MmcWrite ( + IN UINTN Address, + IN UINT32 Value + ) +{ + if (FixedPcdGetBool (PcdMmcBigEndian)) { + return BeMmioWrite32 (Address, Value); + } else { + return MmioWrite32 (Address, Value); + } +} + +/** + Function to call MmioAndThenOr32 depending upon pcd + + @param Address MMC register + @param AndData The value to AND with the read value from the MMC register + @param OrData The value to OR with the result of the AND operation. + + @retval Value written back to register + +**/ +UINT32 +EFIAPI +MmcAndThenOr ( + IN UINTN Address, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + if (FixedPcdGetBool (PcdMmcBigEndian)) { + return BeMmioAndThenOr32 (Address, AndData, OrData); + } else { + return MmioAndThenOr32 (Address, AndData, OrData); + } +} + +/** + Function to call MmioOr32 depending upon pcd + + @param Address MMC register + @param OrData The value to OR with the result of the AND operation. + + @retval Value written back to register + +**/ +UINT32 +EFIAPI +MmcOr ( + IN UINTN Address, + IN UINT32 OrData + ) +{ + if (FixedPcdGetBool (PcdMmcBigEndian)) { + return BeMmioOr32 (Address, OrData); + } else { + return MmioOr32 (Address, OrData); + } +} + +/** + Function to call MmioAnd32 depending upon pcd + + @param Address MMC register + @param AndData The value to AND with the read value from the MMC register + + @retval Value written back to register + +**/ +UINT32 +EFIAPI +MmcAnd ( + IN UINTN Address, + IN UINT32 AndData + ) +{ + if (FixedPcdGetBool (PcdMmcBigEndian)) { + return BeMmioAnd32 (Address, AndData); + } else { + return MmioAnd32 (Address, AndData); + } +} + +/** + Function to Dump MMC Controller register +**/ +VOID +DumpMmcRegs ( + IN VOID + ) +{ + struct SdxcRegs *Regs; + + Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr); + + DEBUG ((DEBUG_ERROR, "Dsaddr : 0x%x \n", Regs->Dsaddr)); + DEBUG ((DEBUG_ERROR, "Blkattr : 0x%x \n", Regs->Blkattr)); + DEBUG ((DEBUG_ERROR, "CmdArg : 0x%x \n", Regs->CmdArg)); + DEBUG ((DEBUG_ERROR, "Xfertype : 0x%x \n", Regs->Xfertype)); + DEBUG ((DEBUG_ERROR, "Rspns0 : 0x%x \n", Regs->Rspns0)); + DEBUG ((DEBUG_ERROR, "Rspns1 : 0x%x \n", Regs->Rspns1)); + DEBUG ((DEBUG_ERROR, "Rspns1 : 0x%x \n", Regs->Rspns1)); + DEBUG ((DEBUG_ERROR, "Rspns3 : 0x%x \n", Regs->Rspns3)); + DEBUG ((DEBUG_ERROR, "Datport : 0x%x \n", Regs->Datport)); + DEBUG ((DEBUG_ERROR, "Prsstat : 0x%x \n", Regs->Prsstat)); + DEBUG ((DEBUG_ERROR, "Proctl : 0x%x \n", Regs->Proctl)); + DEBUG ((DEBUG_ERROR, "Sysctl : 0x%x \n", Regs->Sysctl)); + DEBUG ((DEBUG_ERROR, "Irqstat : 0x%x \n", Regs->Irqstat)); + DEBUG ((DEBUG_ERROR, "Irqstaten : 0x%x \n", Regs->Irqstaten)); + DEBUG ((DEBUG_ERROR, "Irqsigen : 0x%x \n", Regs->Irqsigen)); + DEBUG ((DEBUG_ERROR, "Autoc12err : 0x%x \n", Regs->Autoc12err)); + DEBUG ((DEBUG_ERROR, "Hostcapblt : 0x%x \n", Regs->Hostcapblt)); + DEBUG ((DEBUG_ERROR, "Wml : 0x%x \n", Regs->Wml)); + DEBUG ((DEBUG_ERROR, "Mixctrl : 0x%x \n", Regs->Mixctrl)); + DEBUG ((DEBUG_ERROR, "Fevt : 0x%x \n", Regs->Fevt)); + DEBUG ((DEBUG_ERROR, "Admaes : 0x%x \n", Regs->Admaes)); + DEBUG ((DEBUG_ERROR, "Adsaddr : 0x%x \n", Regs->Adsaddr)); + DEBUG ((DEBUG_ERROR, "Hostver : 0x%x \n", Regs->Hostver)); + DEBUG ((DEBUG_ERROR, "Dmaerraddr : 0x%x \n", Regs->Dmaerraddr)); + DEBUG ((DEBUG_ERROR, "Dmaerrattr : 0x%x \n", Regs->Dmaerrattr)); + DEBUG ((DEBUG_ERROR, "Hostcapblt2 : 0x%x \n", Regs->Hostcapblt2)); + DEBUG ((DEBUG_ERROR, "Tcr : 0x%x \n", Regs->Tcr)); + DEBUG ((DEBUG_ERROR, "Sddirctl : 0x%x \n", Regs->Sddirctl)); + DEBUG ((DEBUG_ERROR, "Scr : 0x%x \n", Regs->Scr)); +} + +/** + Function to create dma map for read/write operation + + @param DmaData Pointer to Dma data Structure + + @retval Address of dma map + +**/ +VOID * +GetDmaBuffer ( + IN struct DmaData *DmaData + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhyAddr; + + Status = DmaAllocateBuffer (EfiBootServicesData, + EFI_SIZE_TO_PAGES (DmaData->Bytes), + &(DmaData->DmaAddr)); + if (Status) { + DEBUG((DEBUG_ERROR,"DmaAllocateBuffer failed\n")); + return NULL; + } + + Status = DmaMap (DmaData->MapOperation, DmaData->DmaAddr, + &DmaData->Bytes, &PhyAddr, &DmaData->Mapping); + if (Status) { + DEBUG((DEBUG_ERROR,"DmaMap failed %d \n", Status)); + + DmaFreeBuffer(EFI_SIZE_TO_PAGES (DmaData->Bytes), DmaData->DmaAddr); + + return NULL; + } + return (VOID *)PhyAddr; +} + +/** + Function to free dma map + + @param DmaData Pointer to Dma data Structure + + @retval Address of dma map + +**/ +EFI_STATUS +FreeDmaBuffer ( + IN struct DmaData *DmaData + ) +{ + EFI_STATUS Status; + + Status = DmaUnmap (DmaData->Mapping); + if (Status) { + DEBUG((DEBUG_ERROR,"DmaUnmap failed 0x%x\n", Status)); + } + + Status = DmaFreeBuffer (EFI_SIZE_TO_PAGES (DmaData->Bytes), DmaData->DmaAddr); + if (Status) { + DEBUG((DEBUG_ERROR,"DmaFreeBuffer failed 0x%x\n", Status)); + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Function to select the transfer type flags depending upon given + command and data packet + + @param Cmd Pointer to MMC command + @param Data Pointer to MMC data + + @retval Returns the XFERTYPE flags + +**/ +UINT32 +SdxcXfertype ( + IN struct SdCmd *Cmd, + IN struct SdData *Data + ) +{ + UINT32 Xfertype; + + Xfertype = 0; + + if (Data) { + Xfertype |= XFERTYPE_DPSEL; + Xfertype |= XFERTYPE_DMAEN; //DMA Support + + if (Data->Blocks > 1) { + Xfertype |= XFERTYPE_MSBSEL; + Xfertype |= XFERTYPE_BCEN; + } + + if (Data->Flags & MMC_DATA_READ) { + Xfertype |= XFERTYPE_DTDSEL; + } + } + + if (Cmd->RespType & MMC_RSP_CRC) { + Xfertype |= XFERTYPE_CCCEN; + } + if (Cmd->RespType & MMC_RSP_OPCODE) { + Xfertype |= XFERTYPE_CICEN; + } + if (Cmd->RespType & MMC_RSP_136) { + Xfertype |= XFERTYPE_RSPTYP_136; + } + else if (Cmd->RespType & MMC_RSP_BUSY) { + Xfertype |= XFERTYPE_RSPTYP_48_BUSY; + } + else if (Cmd->RespType & MMC_RSP_PRESENT) { + Xfertype |= XFERTYPE_RSPTYP_48; + } + + if (Cmd->CmdIdx == CMD_STOP_TRANSMISSION) { + Xfertype |= XFERTYPE_CMDTYP_ABORT; + } + + return XFERTYPE_CMD (Cmd->CmdIdx) | Xfertype; +} + +/** + Function to set up MMC data(timeout value,watermark level, + system address,block attributes etc.) + + @param Data Pointer to MMC data + +**/ +EFI_STATUS +SdxcSetupData ( + IN struct SdData *Data + ) +{ + struct SdxcRegs *Regs; + INT32 Timeout; + UINT32 WmlVal; + + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + Timeout = 0; + WmlVal = 0; + + WmlVal = Data->Blocksize/4; + + if (Data->Flags & MMC_DATA_READ) { + + if (WmlVal > WML_RD_MAX) { + WmlVal = WML_RD_MAX_VAL; + } + + MmcAndThenOr ((UINTN)&Regs->Wml, ~WML_RD_MASK, WmlVal); + + } else { + if (WmlVal > WML_WR_MAX) { + WmlVal = WML_WR_MAX_VAL; + } + + if ((MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_WPSPL) == 0) { + DEBUG ((DEBUG_ERROR, "The SD Card Is Locked. Can Not Write To A Locked Card.\n")); + return EFI_TIMEOUT; + } + + MmcAndThenOr ((UINTN)&Regs->Wml, ~WML_WR_MASK, WmlVal << 16); + } + + EFI_PHYSICAL_ADDRESS Addr = (EFI_PHYSICAL_ADDRESS)Data->Addr; + MmcWrite ((UINTN)&Regs->Dsaddr, Addr); + + MmcWrite ((UINTN)&Regs->Blkattr, Data->Blocks << 16 | Data->Blocksize); + + // Calculate The Timeout Period for Data Transactions + Timeout = GenericFls (mMmc->Clock/4); + Timeout -= 13; + + if (Timeout > 14) { + Timeout = 14; + } + + if (Timeout < 0) { + Timeout = 0; + } + + MmcAndThenOr ((UINTN)&Regs->Sysctl, ~SYSCTL_TIMEOUT_MASK, Timeout << 16); + + return EFI_SUCCESS; +} + +/** + Function to peform reset of MMC command and data + +**/ +VOID +ResetCmdFailedData ( + IN struct SdxcRegs *Regs, + IN UINT8 Data + ) +{ + INT32 Timeout; + + Timeout = 10000; + + // Reset CMD And DATA Portions On Error + MmcWrite ((UINTN)&Regs->Sysctl, MmcRead ((UINTN)&Regs->Sysctl) | + SYSCTL_RSTC); + + while ((MmcRead((UINTN)&Regs->Sysctl) & SYSCTL_RSTC) && Timeout--); + if (Timeout <= 0) { + DEBUG((DEBUG_ERROR, "Failed to reset CMD Portion On Error\n")); + return; + } + + Timeout = 10000; + if (Data) { + MmcWrite ((UINTN)&Regs->Sysctl, + MmcRead ((UINTN)&Regs->Sysctl) | SYSCTL_RSTD); + while ((MmcRead ((UINTN)&Regs->Sysctl) & SYSCTL_RSTD) && Timeout--); + if (Timeout <= 0) { + DEBUG ((DEBUG_ERROR, "Failed to reset DATA Portion On Error\n")); + } + } + + MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF); +} + +/** + Function to do MMC read/write transfer using DMA and checks + whether transfer is completed or not + +**/ +EFI_STATUS +Transfer ( + IN VOID + ) +{ + UINT32 Irqstat; + UINT32 Timeout; + struct SdxcRegs *Regs; + + Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr); + Timeout = 10000000; + do { + Irqstat = MmcRead ((UINTN)&Regs->Irqstat); + + if (Irqstat & IRQSTATE_DTOE) { + DumpMmcRegs (); + ResetCmdFailedData (Regs, 1); + return EFI_TIMEOUT; + } + + if (Irqstat & DATA_ERR) { + ResetCmdFailedData (Regs, 1); + return EFI_DEVICE_ERROR; + } + + MicroSecondDelay (10); + + } while ((!(Irqstat & DATA_COMPLETE)) && Timeout--); + + if (Timeout <= 0) { + DEBUG ((DEBUG_ERROR, "Timeout Waiting for DATA_COMPLETE to set\n")); + ResetCmdFailedData (Regs, 1); + return EFI_TIMEOUT; + } + + MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF); + return EFI_SUCCESS; +} + +/** + Function to set MMC host controller system control register + + @param Clock Clock value for setting the register + +**/ +VOID +SetSysctl ( + UINT32 Clock + ) +{ + INT32 Div, PreDiv; + struct SdxcRegs *Regs; + INT32 SdhcClk; + UINT32 Clk; + + Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr); + SdhcClk = mMmc->SdhcClk; + + if (Clock < mMmc->FMin) { + Clock = mMmc->FMin; + } else if (Clock > mMmc->FMax) { + Clock = mMmc->FMax; + } + + mMmc->Clock = Clock; + + if (SdhcClk / 16 > Clock) { + for (PreDiv = 2; PreDiv < 256; PreDiv *= 2) + if ((SdhcClk / PreDiv) <= (Clock * 16)) { + break; + } + } else { + PreDiv = 2; + } + + for (Div = 1; Div <= 16; Div++) + if ((SdhcClk / (Div * PreDiv)) <= Clock) { + break; + } + + PreDiv >>= mMmc->DdrMode ? DIV_2 : DIV_1; + Div -= 1; + + Clk = (PreDiv << 8) | (Div << 4); + + MmcAnd ((UINTN)&Regs->Sysctl, ~SYSCTL_CKEN); + + MmcAndThenOr ((UINTN)&Regs->Sysctl, ~SYSCTL_CLOCK_MASK, Clk); + + MicroSecondDelay (100); + + Clk = SYSCTL_PEREN | SYSCTL_CKEN; + + MmcOr ((UINTN)&Regs->Sysctl, Clk); +} + +/** + Function to set MMC host controller bus width + + @param Mmc Pointer to MMC data structure + @param BWidth Bus width to be set + +**/ +VOID +SdxcSetBusWidth ( + IN struct Mmc *Mmc, + IN UINT32 BWidth + ) +{ + Mmc->BusWidth = BWidth; + + SetIos (Mmc->Clock, Mmc->BusWidth, 0); +} + +/** + Function to Initialize MMC host controller + + @param Mmc Pointer to MMC data structure + +**/ +EFI_STATUS +SdxcInit ( + IN struct Mmc *Mmc + ) +{ + struct SdxcRegs *Regs; + INT32 Timeout; + + Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr); + Timeout = 1000; + + // Reset The Entire Host Controller + MmcOr ((UINTN)&Regs->Sysctl, SYSCTL_RSTA); + + // Wait Until The Controller Is Available + while ((MmcRead ((UINTN)&Regs->Sysctl) & SYSCTL_RSTA) && --Timeout) + MicroSecondDelay (1000); + + if (Timeout <= 0) { + DEBUG ((DEBUG_ERROR, "Host controller failed to reset \n")); + return EFI_DEVICE_ERROR; + } + + // Enable Cache Snooping + MmcWrite ((UINTN)&Regs->Scr, ENABLE_CACHE_SNOOPING); + + MmcOr ((UINTN)&Regs->Sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); + + // Set The Initial Clock Speed + SetIos (MIN_CLK_FREQUENCY, Mmc->BusWidth, 0); + + // Disable The BRR And BWR Bits In IRQSTAT + MmcAnd ((UINTN)&Regs->Irqstaten, + ~(IRQSTATE_EN_BRR | IRQSTATE_EN_BWR)); + + // Set Little Endian mode for data Buffer + MmcWrite ((UINTN)&Regs->Proctl, PRCTL_INIT); + + // Set Timeout To The Maximum Value + MmcAndThenOr ((UINTN)&Regs->Sysctl, + ~SYSCTL_TIMEOUT_MASK, 14 << 16); + + return EFI_SUCCESS; +} + +/** + Function to reset MMC host controller + + @param Regs Pointer to MMC host Controller + +**/ +VOID +SdxcReset ( + IN struct SdxcRegs *Regs + ) +{ + UINT64 Timeout; + + Timeout = 100; + + // Reset The Controller + MmcWrite ((UINTN)&Regs->Sysctl, SYSCTL_RSTA); + + // Hardware Clears The Bit When It Is Done + while ((MmcRead ((UINTN)&Regs->Sysctl) & SYSCTL_RSTA) && --Timeout) + MicroSecondDelay (10); + + if (!Timeout) { + DEBUG((DEBUG_ERROR, "MMC/SD: Reset Never Completed.\n")); + } +} diff --git a/Platform/NXP/Library/MmcLib/MmcLib.inf b/Platform/NXP/Library/MmcLib/MmcLib.inf new file mode 100644 index 0000000..017c6ad --- /dev/null +++ b/Platform/NXP/Library/MmcLib/MmcLib.inf @@ -0,0 +1,39 @@ +##@file +# +# Copyright 2017 NXP +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = MmcLib + FILE_GUID = c0f5dfa0-7599-11e0-9866-0002a5d5c61b + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MmcLib + +[Sources.common] + MmcLib.c + MmcInterface.c + +[LibraryClasses] + BaseMemoryLib + BeIoLib + DmaLib + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Platform/NXP/NxpQoriqLs.dec + +[FixedPcd] + gNxpQoriqLsTokenSpaceGuid.PcdSdxcBaseAddr + gNxpQoriqLsTokenSpaceGuid.PcdMmcBigEndian -- 1.9.1