From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by mx.groups.io with SMTP id smtpd.web11.129.1617079017709733676 for ; Mon, 29 Mar 2021 21:36:58 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@intel.onmicrosoft.com header.s=selector2-intel-onmicrosoft-com header.b=vLVHQaNj; spf=pass (domain: intel.com, ip: 134.134.136.126, mailfrom: tien.hock.loh@intel.com) IronPort-SDR: uqLgIwYCY/on9bzKnkaEgFMKEcCzC8UdoOTYqBoAlrH4voPXEUlQiaiaNVHtblEQQpQypxIGpM zGCCvsVnws2Q== X-IronPort-AV: E=McAfee;i="6000,8403,9938"; a="179227875" X-IronPort-AV: E=Sophos;i="5.81,289,1610438400"; d="scan'208";a="179227875" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Mar 2021 21:36:55 -0700 IronPort-SDR: CiqSq9S5n/x87WQHAN5Z3rEqZWwBdUrmfEZM+hejok45pKlotp2Z780VOGvT4Wn7F59mLKqttT 49CnmPuRIomA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,289,1610438400"; d="scan'208";a="411420074" Received: from orsmsx601.amr.corp.intel.com ([10.22.229.14]) by fmsmga008.fm.intel.com with ESMTP; 29 Mar 2021 21:36:54 -0700 Received: from orsmsx608.amr.corp.intel.com (10.22.229.21) by ORSMSX601.amr.corp.intel.com (10.22.229.14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2106.2; Mon, 29 Mar 2021 21:36:53 -0700 Received: from orsmsx605.amr.corp.intel.com (10.22.229.18) by ORSMSX608.amr.corp.intel.com (10.22.229.21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2106.2; Mon, 29 Mar 2021 21:36:52 -0700 Received: from ORSEDG601.ED.cps.intel.com (10.7.248.6) by orsmsx605.amr.corp.intel.com (10.22.229.18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2106.2 via Frontend Transport; Mon, 29 Mar 2021 21:36:52 -0700 Received: from NAM12-DM6-obe.outbound.protection.outlook.com (104.47.59.175) by edgegateway.intel.com (134.134.137.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2106.2; Mon, 29 Mar 2021 21:36:52 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=SglnxtJQkP5cljObwfYgByk6zmsawWY4PlQNtgV3OlhUM3WCjQMBU+M3ECUMraSUAL5U7Wff1h7ABuY9DhHalGSeRsqeVNdCprLxXCEIhP0CjCwKbPiLWeq9aEsYAlrG2AUeU4pdf90phRrdCVpnommCi8MWKQWJzeZ6KEpPFnHT12a5OrAIkNXFuZH4eymzoGhxy0x3TPoqriJXzgEjC3SXRiRzkrvk+RZ4na+e1onleDQrkW3ZBuETy0CERQ/7BuWvmQ1J1ORNYKUPyrbq/Lv/4F1fA3shts0Y9jZhx50gVDBsocCFawTdw7c7+SmDn6WdCNx4BP4ldKSDOUvScw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Netc919l0+txM1cDSeVxSMGlNLpLBGeo9No4FPn/omQ=; b=GABVgriWCk/O+s14L1CWEcZr/0lnCcStTkXeXCj6KzqS6wqYgrHBs2PRjsuAlyvjo8JKSaMg5zcUxpTJAfOtmvZbnGS+Gh3z5YQroUyWpD9BJxvgy5BlL0D7LgOotwgSNuGqiKL58QL6We4HTl4kC1JbvZMrC8kY9KcMzRj20s8xFMpaIpQ2Czq8n7HdcX4RMT8nqXoivwqnkDBVc/cpMgBOFR8Tz73DFk5kw4mjuKtnzjCqVcg0n6LrHQJm2q8u8xvSxLsINcTGQVJRtndJazB5JEdIWQbWApOwG33P9jn9CwhnoELT5G58zOxSox5WrBH/J2icXENFlJhzkRY+Uw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=intel.onmicrosoft.com; s=selector2-intel-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Netc919l0+txM1cDSeVxSMGlNLpLBGeo9No4FPn/omQ=; b=vLVHQaNju/jI8h869bLf+Pst5m9FtmqaJLbXGCkRMiI7yWS6i54ffg0XejNTEIt42GOXc+2iojSVj01XOc5xqXdTe28QlA1FIXgvB/96pzpIN/unoi4/o6WN9q8aHGAmAzosX4DfvERrdftbGOY5CvAYq4yCh0XzRkgIKVHo2LU= Received: from SJ0PR11MB5136.namprd11.prod.outlook.com (2603:10b6:a03:2d1::18) by BYAPR11MB3111.namprd11.prod.outlook.com (2603:10b6:a03:90::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.33; Tue, 30 Mar 2021 04:36:47 +0000 Received: from SJ0PR11MB5136.namprd11.prod.outlook.com ([fe80::ac08:c378:ad50:dc67]) by SJ0PR11MB5136.namprd11.prod.outlook.com ([fe80::ac08:c378:ad50:dc67%7]) with mapi id 15.20.3977.033; Tue, 30 Mar 2021 04:36:47 +0000 From: "Loh, Tien Hock" To: "devel@edk2.groups.io" CC: "thloh85@gmail.com" , "Kinney, Michael D" , Leif Lindholm , "Ard Biesheuvel" Subject: Re: [PATCH V5 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver Thread-Topic: [PATCH V5 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver Thread-Index: AQHXHsr8+cCyDCxc+UWpketwaiWuOaqPWDKAgAymniA= Date: Tue, 30 Mar 2021 04:36:47 +0000 Message-ID: References: <20210322032439.9312-1-tien.hock.loh@intel.com> <20210322032439.9312-2-tien.hock.loh@intel.com> In-Reply-To: <20210322032439.9312-2-tien.hock.loh@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-reaction: no-action dlp-version: 11.5.1.3 dlp-product: dlpe-windows authentication-results: edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=none action=none header.from=intel.com; x-originating-ip: [42.189.202.134] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: b150bf22-4ba4-4670-157e-08d8f3356dc5 x-ms-traffictypediagnostic: BYAPR11MB3111: x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:10000; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: gdfbNWiSxozIUOLF2GvzNeps6C4qoWKu1iWEbWtoKSar/ee4dIo6Ouk/9T8glj3EmQmD5i9jVdd4kOxlQfaYMepL3K6UfJPgH2Gwb63Qgxky48sZHPtSU6yNDRZAQV55eObsx4YXy3e0zG1+bZ0vgPaH7hX918Usbg+GIsJpfQYxyJVtO60KZjMOfIJJ7r/lgH33WF7vdMqiWuztICzRBG5wrC4HtFfZ6capqaw6qCwtI8vyrNpoTytMy+Yy5qBSoap8Sc5S1zcG+Z4Bmr8iGV1WlUIGU3c1VM2ZwoQb1iWiR5ktC3mBTnfR8zlGc8bvppS4myviwhMzJcWt00VbRpLh5bhSDm2m2cdCCSaqUp3zWV3EGDokSivnTjG/forNTc7R3FT15kyNm7UI2CTcSKUJZHPSGShB+dev/Q624s500rOvSQR46F1jL+n11+697kM8PF/62Rqa91SVdnYLHJC6NUl6MfC6pqn6SgJsyXCBhaKIl0mi08kgwei7SyqL09ltbfJrC8iadV8UsytNcTIaFlVGZ0wevP+kTV1QvLNt3YjUtDVkfZX1TXKXzuaJum3u9ULeB2y7YLyaE94UdRD3zXbXZIHngQStxKsJVwUhAY1BaBp8hPq+I+xRCe6utgi8IcsJnGtOH6z0wZFODSh+QFsDOQw3YSZyAeRjY+bUKDjGhIhBbKx5Ci9lcRML7RqsKUfO0ROqXBlfYIWIAg9R4zg9vOBC8t6bG8yHCcILFDVvu98emksqTOq4O1FRqY0yiytbdQAraxX5UXaU7ugUa9kZdvzbJfdj0PSwY4g= x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SJ0PR11MB5136.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(6029001)(346002)(366004)(39860400002)(396003)(136003)(376002)(6916009)(316002)(71200400001)(26005)(76116006)(33656002)(55016002)(66446008)(83380400001)(4326008)(5660300002)(66946007)(9686003)(30864003)(52536014)(64756008)(19627235002)(66476007)(7696005)(966005)(478600001)(8676002)(15188155005)(16799955002)(6506007)(186003)(53546011)(8936002)(66556008)(54906003)(38100700001)(86362001)(2906002)(290074003)(569008);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata: =?us-ascii?Q?xmgXr9I1sXUUqv8tourycKbH85abtL5yTxpLwdYS8n3JwuLh21j3EIhcK5CU?= =?us-ascii?Q?MQHite1JGxDeKXl5JlyrcWuHnNbFB/IMzBYmQrIg73IlO81yeYN2uLVj0pvZ?= =?us-ascii?Q?HTfZoc+iiZvTD9XMTHSpznZ/Dk44dbrtiJMH6kEN43ZdPutZAh6f1YgmIN7c?= =?us-ascii?Q?VjgWIP6nMh3DC/gpqaRxWyTB7rPyYGSDPKzpxPVB2GsFTkWYJZ87Wt3FoSZL?= =?us-ascii?Q?Ky1ZVfhvR3a1KQwJy9bqLsFt0qOdMTKyiAy3aSo4uK7vh12vEx9bD4P/x22S?= =?us-ascii?Q?XpDPUl9TqsQTwPxtt6YazWvDXtU7Q4lfByUz0HbQokEyqtHLjvq3WFihhTh+?= =?us-ascii?Q?rck6vRch488Pa1CX4aT9iiiwExoZQTlnqyBuYu4ZJXvB+Nmvj7dqyGqYO/oI?= =?us-ascii?Q?fiI4j5kCMSW8RU/4LgJRbTi4bLiGPeT5GIdhsefVDBgrIA3F2QJfX1A8sz3r?= =?us-ascii?Q?KZdU9/UbToKdBenzwLQL69lTRHJrskUpdoDlkhCSEgLYhDDPTW+hxLrvtW3d?= =?us-ascii?Q?rEd/dLxoZCpzUlijzO1ijHo3+8KVRfoFHINy8mmr1nU61w+aEMW4lUSqD/Ti?= =?us-ascii?Q?JdDqQ14LzNVGpNurVEyvgbmP5dsKXR++ZcX3rw2jqK6wgJ3KLW0CFl4xNPBo?= =?us-ascii?Q?KxC7kqbjEVKiQSwrplJ66b2JF63hQiUOTtZTzVIAzg1GhJhzIQ+S/TKBb95k?= =?us-ascii?Q?Qu+CSHSWb5odrXsu9S+qFb4YLG6KGhk4ie9AnLh+IoR7xbJefcZ8luluitv+?= =?us-ascii?Q?D5p4gptQmYa05KubkVrleM/fL+YJwrQW2hSdRdf3OzFQpargbjZtL0rK1eME?= =?us-ascii?Q?Cn05ytQBwSTUkKSwWgq7zWBpMF5a1JOrDpMT9iDWXfLBDLxLp9+r7TLt8Sg4?= =?us-ascii?Q?OgiqF7XNvUu7/bQAEL3T9KfMbWf9x46cfZMeC1ufbvXI7k0I02BBPemPC3OG?= =?us-ascii?Q?F7bpmTqbpernojcnlUCbWmYOcvkHdOfeJ+/X0sVSWeybin6cYCL6ArtDE5Xx?= =?us-ascii?Q?lt9wB5xLesBKk/h5Hnj5VQy/yT1Q+MFqafoxWveaxQVX86BSM1lC+RcI+W/J?= =?us-ascii?Q?y6oV5O6qycIfc6mjmRiRrcnGkzzEJER7xCrWEzfnFd/e3x4QlVWRI6bap3L7?= =?us-ascii?Q?TKoqaawi3AyL/helN3tenJ/iboECs++6mEujsTqlXPQPDags21n0nec8M9Xc?= =?us-ascii?Q?XUy9f0MocOj+IqJOTWeD0kKnUX5ud3urS7npqvAEYYKJjlKkggvHwjugpOUx?= =?us-ascii?Q?+8tP2lyFQKPFJyRUaSqY1SD/bdtNkHlgECpMMyAZ1yBy6cwuGZjUGeshwfZ9?= =?us-ascii?Q?D3dU9CsNPETPsZAi1HU8DcPS?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: SJ0PR11MB5136.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: b150bf22-4ba4-4670-157e-08d8f3356dc5 X-MS-Exchange-CrossTenant-originalarrivaltime: 30 Mar 2021 04:36:47.1173 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: sd20VKeubsaB/ARO/gm3Hpvxp1dYSBypOL6Onrq8/4n6kpa++A4mBBZ5hw793ocUCbPxAQ3eHZU3Y1fhTl1u9Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR11MB3111 Return-Path: tien.hock.loh@intel.com X-OriginatorOrg: intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Ard, Leif, Michael, Any issues or comments on the patch? Thanks > -----Original Message----- > From: Loh, Tien Hock > Sent: Monday, March 22, 2021 11:25 AM > To: devel@edk2.groups.io > Cc: thloh85@gmail.com; Loh, Tien Hock ; Kinney, > Michael D ; Leif Lindholm > ; Ard Biesheuvel > Subject: [PATCH V5 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for > Designware SDMMC driver >=20 > From: "Tien Hock, Loh" >=20 > This adds support for Designware SDMMC driver. The SDMMC driver > depends on > MdeModulePkg/Bus/Sd/, and produces > EFI_SD_MMC_PASS_THRU_PROTOCOL. The > driver uses MMIO to read/write, and uses > gEdkiiNonDiscoverableDeviceProtocolGuid. Platform needs to register devic= e > with gEdkiiNonDiscoverableDeviceProtocolGuid. >=20 > Signed-off-by: Loh Tien Hock > Cc: Leif Lindholm > Cc: Ard Biesheuvel > --- > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec | 40 + > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf | 70 + > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h | 817 > ++++++++++ > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h | 985 > ++++++++++++ > EmbeddedPkg/Include/Protocol/PlatformDwMmc.h | 79 + > EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c | 214 +++ > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c | 1296 > ++++++++++++++++ > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c | 1602 > ++++++++++++++++++++ > EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c | 1042 > +++++++++++++ > EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c | 1105 > ++++++++++++++ > 10 files changed, 7250 insertions(+) >=20 > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec > b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec > new file mode 100644 > index 000000000000..cf85ccb1a030 > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec > @@ -0,0 +1,40 @@ > +#/** @file > +# Framework Module Development Environment Industry Standards > +# > +# This Package provides headers and libraries that conform to EFI/PI > Industry standards. > +# Copyright (c) 2007, Intel Corporation. All rights reserved.
> +# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.
> +# Copyright (c) 2018, Linaro. All rights reserved.
> +# > +# 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] > + DEC_SPECIFICATION =3D 0x00010019 > + PACKAGE_NAME =3D DwMmcHcDxePkg > + PACKAGE_GUID =3D e73097ce-1fe2-41a6-a930-3136bc6d23e= f > + PACKAGE_VERSION =3D 0.1 > + > + > +######################################################### > ####################### > +# > +# Include Section - list of Include Paths that are provided by this pack= age. > +# Comments are used for Keywords and Module Types. > +# > +# Supported Module Types: > +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER > DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER > UEFI_APPLICATION > +# > +######################################################### > ####################### > + > +[Guids.common] > + gDwMmcHcDxeTokenSpaceGuid =3D { 0x576c132e, 0x7d51, 0x4abb, { 0xbc= , > 0x60, 0x13, 0x08, 0x04, 0x0e, 0x90, 0x92 }} > + > +[Protocols.common] > + gPlatformDwMmcProtocolGuid =3D { 0x1d6dfde5, 0x76a7, 0x4404, { 0x85= , > 0x74, 0x7a, 0xdf, 0x1a, 0x8a, 0xa2, 0x0d }} > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf > b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf > new file mode 100644 > index 000000000000..4cd0960ef9c3 > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf > @@ -0,0 +1,70 @@ > +## @file > +# DwSdMmcHcDxe driver is used to manage those host controllers which > comply with > +# Designware SD Host Controller. > +# > +# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending > SD/MMC/eMMC cmds > +# to specified devices from upper layer. > +# > +# Copyright (c) 2015, Intel Corporation. All rights reserved.
> +# Copyright (C) 2016, Marvell International Ltd. All rights reserved. > +# Copyright (c) 2018, Linaro Ltd. All rights reserved.
> +# > +# 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 =3D 0x00010019 > + BASE_NAME =3D DwMmcHcDxe > + MODULE_UNI_FILE =3D DwMmcHcDxe.uni > + FILE_GUID =3D 9be4d260-208c-4efe-a524-0b5d3bf77f9= d > + MODULE_TYPE =3D UEFI_DRIVER > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D InitializeDwMmcHcDxe > + > +[Sources] > + ComponentName.c > + DwMmcHcDxe.c > + DwMmcHcDxe.h > + DwMmcHci.c > + DwMmcHci.h > + EmmcDevice.c > + SdDevice.c > + > +[Packages] > + ArmPkg/ArmPkg.dec > + EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec > + EmbeddedPkg/EmbeddedPkg.dec > + MdeModulePkg/MdeModulePkg.dec > + MdePkg/MdePkg.dec > + > +[LibraryClasses] > + ArmLib > + BaseLib > + BaseMemoryLib > + CacheMaintenanceLib > + DebugLib > + DevicePathLib > + DmaLib > + MemoryAllocationLib > + TimerLib > + UefiBootServicesTableLib > + UefiDriverEntryPoint > + UefiLib > + UefiRuntimeServicesTableLib > + > +[Protocols] > + gEdkiiNonDiscoverableDeviceProtocolGuid > + gEfiDevicePathProtocolGuid ## TO_START > + gEfiPciIoProtocolGuid ## TO_START > + gEfiSdMmcPassThruProtocolGuid ## BY_START > + gPlatformDwMmcProtocolGuid > + > +[UserExtensions.TianoCore."ExtraFiles"] > + DwMmcHcDxeExtra.uni > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h > b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h > new file mode 100644 > index 000000000000..b783d9830325 > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h > @@ -0,0 +1,817 @@ > +/** @file > + > + Provides some data structure definitions used by the Designware SD/MMC > + host controller driver. > + > + Copyright (c) 2015, Intel Corporation. All rights reserved.
> + Copyright (C) 2018, Linaro Ltd. All rigths reserved.
> + > + This program and the accompanying materials are licensed and made > available > + under the terms and conditions of the BSD License which accompanies th= is > + 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 _DW_MMC_HC_DXE_H_ > +#define _DW_MMC_HC_DXE_H_ > + > +#include > + > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "DwMmcHci.h" > + > +extern EFI_COMPONENT_NAME_PROTOCOL > gDwMmcHcComponentName; > +extern EFI_COMPONENT_NAME2_PROTOCOL > gDwMmcHcComponentName2; > +extern EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding; > + > +#define DW_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('d', 'w', 's', > 'd') > + > +#define DW_MMC_HC_PRIVATE_FROM_THIS(a) \ > + CR(a, DW_MMC_HC_PRIVATE_DATA, PassThru, > DW_MMC_HC_PRIVATE_SIGNATURE) > + > +// > +// Generic time out value, 1 microsecond as unit. > +// > +#define DW_MMC_HC_GENERIC_TIMEOUT (1 * 1000 * 1000) > + > +// > +// SD/MMC async transfer timer interval, set by experience. > +// The unit is 100us, takes 1ms as interval. > +// > +#define DW_MMC_HC_ASYNC_TIMER > EFI_TIMER_PERIOD_MILLISECONDS(1) > +// > +// SD/MMC removable device enumeration timer interval, set by > experience. > +// The unit is 100us, takes 100ms as interval. > +// > +#define DW_MMC_HC_ENUM_TIMER > EFI_TIMER_PERIOD_MILLISECONDS(100) > + > +typedef struct { > + BOOLEAN Enable; > + EFI_SD_MMC_SLOT_TYPE SlotType; > + BOOLEAN MediaPresent; > + BOOLEAN Initialized; > + SD_MMC_CARD_TYPE CardType; > +} DW_MMC_HC_SLOT; > + > +typedef struct { > + UINTN Signature; > + > + EFI_HANDLE ControllerHandle; > + > + // Mmio base address > + UINTN DevBase; > + > + EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru; > + > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; > + // > + // The field is used to record the previous slot in GetNextSlot(). > + // > + UINT8 PreviousSlot; > + // > + // For Non-blocking operation. > + // > + EFI_EVENT TimerEvent; > + // > + // For Sd removable device enumeration. > + // > + EFI_EVENT ConnectEvent; > + LIST_ENTRY Queue; > + > + DW_MMC_HC_SLOT Slot[DW_MMC_HC_MAX_SLOT]; > + DW_MMC_HC_SLOT_CAP Capability[DW_MMC_HC_MAX_SLOT]; > + UINT64 MaxCurrent[DW_MMC_HC_MAX_SLOT]; > + > + UINT32 ControllerVersion; > +} DW_MMC_HC_PRIVATE_DATA; > + > +#define DW_MMC_HC_TRB_SIG SIGNATURE_32 ('D', 'T', 'R', 'B') > + > +// > +// TRB (Transfer Request Block) contains information for the cmd request= . > +// > +typedef struct { > + UINT32 Signature; > + LIST_ENTRY TrbList; > + > + UINT8 Slot; > + UINT16 BlockSize; > + > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + VOID *Data; > + UINT32 DataLen; > + BOOLEAN Read; > + EFI_PHYSICAL_ADDRESS DataPhy; > + VOID *DataMap; > + DW_MMC_HC_TRANSFER_MODE Mode; > + > + EFI_EVENT Event; > + BOOLEAN Started; > + UINT64 Timeout; > + > + DW_MMC_HC_DMA_DESC_LINE *DmaDesc; > + EFI_PHYSICAL_ADDRESS DmaDescPhy; > + UINT32 DmaDescPages; > + VOID *DmaMap; > + > + BOOLEAN UseFifo; > + BOOLEAN UseBE; // Big-end= ian > + > + DW_MMC_HC_PRIVATE_DATA *Private; > +} DW_MMC_HC_TRB; > + > +#define DW_MMC_HC_TRB_FROM_THIS(a) \ > + CR(a, DW_MMC_HC_TRB, TrbList, DW_MMC_HC_TRB_SIG) > + > +// > +// Task for Non-blocking mode. > +// > +typedef struct { > + UINT32 Signature; > + LIST_ENTRY Link; > + > + UINT8 Slot; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + BOOLEAN IsStart; > + EFI_EVENT Event; > + UINT64 RetryTimes; > + BOOLEAN InfiniteWait; > + VOID *Map; > + VOID *MapAddress; > +} DW_MMC_HC_QUEUE; > + > +// > +// Prototypes > +// > +/** > + Execute card identification procedure. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + > + @retval EFI_SUCCESS The card is identified correctly. > + @retval Others The card can't be identified. > + > +**/ > +typedef > +EFI_STATUS > +(*DWMMC_CARD_TYPE_DETECT_ROUTINE) ( > + IN DW_MMC_HC_PRIVATE_DATA *Private > + ); > + > +/** > + Sends SD command to an SD card that is attached to the SD controller. > + > + The PassThru() function sends the SD command specified by Packet to th= e > SD > + card specified by Slot. > + > + If Packet is successfully sent to the SD card, then EFI_SUCCESS is ret= urned. > + > + If a device error occurs while sending the Packet, then EFI_DEVICE_ERR= OR > is > + returned. > + > + If Slot is not in a valid range for the SD controller, then > + EFI_INVALID_PARAMETER is returned. > + > + If Packet defines a data command but both InDataBuffer and > OutDataBuffer are > + NULL, EFI_INVALID_PARAMETER is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Slot The slot number of the SD card to send t= he > + command to. > + @param[in,out] Packet A pointer to the SD command data structu= re. > + @param[in] Event If Event is NULL, blocking I/O is perfor= med. If > + Event is not NULL, then nonblocking I/O = is > + performed, and Event will be signaled wh= en the > + Packet completes. > + > + @retval EFI_SUCCESS The SD Command Packet was sent by the ho= st. > + @retval EFI_DEVICE_ERROR A device error occurred while attempting= to > send > + the SD command Packet. > + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the > Packet is > + invalid. > + @retval EFI_INVALID_PARAMETER Packet defines a data command but > both > + InDataBuffer and OutDataBuffer are NULL. > + @retval EFI_NO_MEDIA SD Device not present in the Slot. > + @retval EFI_UNSUPPORTED The command described by the SD > Command Packet > + is not supported by the host controller. > + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or > OutTransferLength > + exceeds the limit supported by SD card (= i.e. if > + the number of bytes exceed the Last LBA)= . > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruPassThru ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN UINT8 Slot, > + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, > + IN EFI_EVENT Event OPTIONAL > + ); > + > +/** > + Used to retrieve next slot numbers supported by the SD controller. The > + function returns information about all available slots (populated or > + not-populated). > + > + The GetNextSlot() function retrieves the next slot number on an SD > controller. > + If on input Slot is 0xFF, then the slot number of the first slot on th= e SD > + controller is returned. > + > + If Slot is a slot number that was returned on a previous call to > + GetNextSlot(), then the slot number of the next slot on the SD control= ler is > + returned. > + > + If Slot is not 0xFF and Slot was not returned on a previous call to > + GetNextSlot(), EFI_INVALID_PARAMETER is returned. > + > + If Slot is the slot number of the last slot on the SD controller, then > + EFI_NOT_FOUND is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMMC_PASS_THRU_PROTOCOL > + instance. > + @param[in,out] Slot On input, a pointer to a slot number on = the SD > + controller. > + On output, a pointer to the next slot nu= mber on > + the SD controller. > + An input value of 0xFF retrieves the fir= st slot > + number on the SD controller. > + > + @retval EFI_SUCCESS The next slot number on the SD controlle= r was > + returned in Slot. > + @retval EFI_NOT_FOUND There are no more slots on this SD > controller. > + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not > returned on a > + previous call to GetNextSlot(). > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruGetNextSlot ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN OUT UINT8 *Slot > + ); > + > +/** > + Used to allocate and build a device path node for an SD card on the SD > + controller. > + > + The BuildDevicePath() function allocates and builds a single device no= de > + for the SD > + card specified by Slot. > + > + If the SD card specified by Slot is not present on the SD controller, = then > + EFI_NOT_FOUND is returned. > + > + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. > + > + If there are not enough resources to allocate the device path node, th= en > + EFI_OUT_OF_RESOURCES is returned. > + > + Otherwise, DevicePath is allocated with the boot service AllocatePool(= ), > the > + contents of DevicePath are initialized to describe the SD card specifi= ed by > + Slot, and EFI_SUCCESS is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Slot Specifies the slot number of the SD card= for > + which a device path node is to be alloca= ted and > + built. > + @param[in,out] DevicePath A pointer to a single device path node t= hat > + describes the SD card specified by Slot.= This > + function is responsible for allocating t= he > + buffer DevicePath with the boot service > + AllocatePool(). It is the caller's respo= nsibi- > + lity to free DevicePath when the caller = is > + finished with DevicePath. > + > + @retval EFI_SUCCESS The device path node that describes the = SD > card > + specified by Slot was allocated and retu= rned in > + DevicePath. > + @retval EFI_NOT_FOUND The SD card specified by Slot does not e= xist > on > + the SD controller. > + @retval EFI_INVALID_PARAMETER DevicePath is NULL. > + @retval EFI_OUT_OF_RESOURCES There are not enough resources to > allocate > + DevicePath. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruBuildDevicePath ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN UINT8 Slot, > + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath > + ); > + > +/** > + This function retrieves an SD card slot number based on the input devi= ce > path. > + > + The GetSlotNumber() function retrieves slot number for the SD card > specified > + by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER > is > + returned. > + > + If DevicePath is not a device path node type that the SD Pass Thru dri= ver > + supports, EFI_UNSUPPORTED is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] DevicePath A pointer to the device path node that > describes > + a SD card on the SD controller. > + @param[out] Slot On return, points to the slot number of = an SD > + card on the SD controller. > + > + @retval EFI_SUCCESS SD card slot number is returned in Slot. > + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL. > + @retval EFI_UNSUPPORTED DevicePath is not a device path node typ= e > that > + the SD Pass Thru driver supports. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruGetSlotNumber ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, > + OUT UINT8 *Slot > + ); > + > +/** > + Resets an SD card that is connected to the SD controller. > + > + The ResetDevice() function resets the SD card specified by Slot. > + > + If this SD controller does not support a device reset operation, > + EFI_UNSUPPORTED is returned. > + > + If Slot is not in a valid slot number for this SD controller, > + EFI_INVALID_PARAMETER is returned. > + > + If the device reset operation is completed, EFI_SUCCESS is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Slot Specifies the slot number of the SD card= to be > + reset. > + > + @retval EFI_SUCCESS The SD card specified by Slot was reset. > + @retval EFI_UNSUPPORTED The SD controller does not support a > device > + reset operation. > + @retval EFI_INVALID_PARAMETER Slot number is invalid. > + @retval EFI_NO_MEDIA SD Device not present in the Slot. > + @retval EFI_DEVICE_ERROR The reset command failed due to a device > error > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruResetDevice ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN UINT8 Slot > + ); > + > +// > +// Driver model protocol interfaces > +// > +/** > + Tests to see if this driver supports a given controller. If a child de= vice is > + provided, it further tests to see if this driver supports creating a h= andle > + for the specified child device. > + > + This function checks to see if the driver specified by This supports t= he > + device specified by ControllerHandle. Drivers will typically use the d= evice > + path attached to ControllerHandle and/or the services from the bus I/O > + abstraction attached to ControllerHandle to determine if the driver > supports > + ControllerHandle. This function may be called many times during platfo= rm > + initialization. In order to reduce boot times, the tests performed by = this > + function must be very small, and take as little time as possible to ex= ecute. > + This function must not change the state of any hardware devices, and t= his > + function must be aware that the device specified by ControllerHandle m= ay > + already be managed by the same driver or a different driver. This func= tion > + must match its calls to AllocatePages() with FreePages(), AllocatePool= () > with > + FreePool(), and OpenProtocol() with CloseProtocol(). > + Since ControllerHandle may have been previously started by the same > driver, if > + a protocol is already in the opened state, then it must not be closed = with > + CloseProtocol(). This is required to guarantee the state of Controller= Handle > + is not modified by this function. > + > + @param[in] This A pointer to the > EFI_DRIVER_BINDING_PROTOCOL > + instance. > + @param[in] ControllerHandle The handle of the controller to test.= This > + handle must support a protocol interf= ace that > + supplies an I/O abstraction to the dr= iver. > + @param[in] RemainingDevicePath A pointer to the remaining portion of= a > + device path. This parameter is ignor= ed by > + device drivers, and is optional for b= us > + drivers. For bus drivers, if this par= ameter > + is not NULL, then the bus driver must= deter- > + mine if the bus controller specified = by > + ControllerHandle and the child contro= ller > + specified by RemainingDevicePath are = both > + supported by this bus driver. > + > + @retval EFI_SUCCESS The device specified by ControllerHan= dle and > + RemainingDevicePath is supported by t= he > + driver specified by This. > + @retval EFI_ALREADY_STARTED The device specified by > ControllerHandle and > + RemainingDevicePath is already being = managed > + by the driver specified by This. > + @retval EFI_ACCESS_DENIED The device specified by ControllerHan= dle > and > + RemainingDevicePath is already being = managed > + by a different driver or an applicati= on that > + requires exclusive access. > + Currently not implemented. > + @retval EFI_UNSUPPORTED The device specified by ControllerHan= dle > and > + RemainingDevicePath is not supported = by the > + driver specified by This. > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcDriverBindingSupported ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ); > + > +/** > + Starts a device controller or a bus controller. > + > + The Start() function is designed to be invoked from the EFI boot servi= ce > + ConnectController(). > + As a result, much of the error checking on the parameters to Start() h= as > been > + moved into this common boot service. It is legal to call Start() from = other > + locations, > + but the following calling restrictions must be followed or the system > behavior > + will not be deterministic. > + 1. ControllerHandle must be a valid EFI_HANDLE. > + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a > natural- > + ly aligned EFI_DEVICE_PATH_PROTOCOL. > + 3. Prior to calling Start(), the Supported() function for the driver s= pecified > + by This must have been called with the same calling parameters, and > + Supported() must have returned EFI_SUCCESS. > + > + @param[in] This A pointer to the > EFI_DRIVER_BINDING_PROTOCOL > + instance. > + @param[in] ControllerHandle The handle of the controller to start= . This > + handle must support a protocol interf= ace that > + supplies an I/O abstraction to the dr= iver. > + @param[in] RemainingDevicePath A pointer to the remaining portion of= a > + device path. This parameter is ignor= ed by > + device drivers, and is optional for b= us dri- > + vers. For a bus driver, if this param= eter is > + NULL, then handles for all the childr= en of > + Controller are created by this driver= . > + If this parameter is not NULL and the= first > + Device Path Node is not the End of De= vice > + Path Node, then only the handle for t= he > + child device specified by the first D= evice > + Path Node of RemainingDevicePath is c= reated > + by this driver. > + If the first Device Path Node of > + RemainingDevicePath is the End of Dev= ice Path > + Node, no child handle is created by t= his > + driver. > + > + @retval EFI_SUCCESS The device was started. > + @retval EFI_DEVICE_ERROR The device could not be started due t= o a > + device error. Currently not implement= ed. > + @retval EFI_OUT_OF_RESOURCES The request could not be completed > due to a > + lack of resources. > + @retval Others The driver failded to start the devic= e. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcDriverBindingStart ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ); > + > +/** > + Stops a device controller or a bus controller. > + > + The Stop() function is designed to be invoked from the EFI boot servic= e > + DisconnectController(). > + As a result, much of the error checking on the parameters to Stop() ha= s > been > + moved into this common boot service. It is legal to call Stop() from o= ther > + locations, but the following calling restrictions must be followed or = the > + system behavior will not be deterministic. > + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a > previous > + call to this same driver's Start() function. > + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be= a > valid > + EFI_HANDLE. In addition, all of these handles must have been create= d in > + this driver's Start() function, and the Start() function must have = called > + OpenProtocol() on ControllerHandle with an Attribute of > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. > + > + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROT= OCOL > + instance. > + @param[in] ControllerHandle A handle to the device being stopped. Th= e > handle > + must support a bus specific I/O protocol= for the > + driver to use to stop the device. > + @param[in] NumberOfChildren The number of child device handles in > + ChildHandleBuffer. > + @param[in] ChildHandleBuffer An array of child handles to be freed. M= ay > be > + NULL if NumberOfChildren is 0. > + > + @retval EFI_SUCCESS The device was stopped. > + @retval EFI_DEVICE_ERROR The device could not be stopped due to a > device > + error. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcDriverBindingStop ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN UINTN NumberOfChildren, > + IN EFI_HANDLE *ChildHandleBuffer > + ); > + > +// > +// EFI Component Name Functions > +// > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + This function retrieves the user readable name of a driver in the form= of a > + Unicode string. If the driver specified by This has a user readable na= me in > + the language specified by Language, then a pointer to the driver name = is > + returned in DriverName, and EFI_SUCCESS is returned. If the driver > specified > + by This does not support the language specified by Language, > + then EFI_UNSUPPORTED is returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + This Unicode string is the name of the > + driver specified by This in the language > + specified by Language. > + > + @retval EFI_SUCCESS The Unicode string for the Driver specif= ied by > + This and the language specified by Langu= age was > + returned in DriverName. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER DriverName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not > support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcComponentNameGetDriverName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN CHAR8 *Language, > + OUT CHAR16 **DriverName > + ); > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > by > + Language, then a pointer to the controller name is returned in > ControllerName, > + and EFI_SUCCESS is returned. If the driver specified by This is not c= urrently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This doe= s > not > + support the language specified by Language, then EFI_UNSUPPORTED is > returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param ControllerHandle[in] The handle of a controller that the driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter that > + may be NULL. It will be NULL for device > + drivers. It will also be NULL for a bus= drivers > + that wish to retrieve the name of the bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + This Unicode string is the name of the > + controller specified by ControllerHandle= and > + ChildHandle in the language specified by > + Language from the point of view of the d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + driver specified by This was returned in > + DriverName. > + > + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid > EFI_HANDLE. > + > + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a > valid > + EFI_HANDLE. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER ControllerName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This is not curr= ently > + managing the controller specified by > + ControllerHandle and ChildHandle. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not > support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcComponentNameGetControllerName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN EFI_HANDLE ControllerHandle, > + IN EFI_HANDLE ChildHandle, OPTIONAL > + IN CHAR8 *Language, > + OUT CHAR16 **ControllerName > + ); > + > +/** > + Create a new TRB for the SD/MMC cmd request. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Slot The slot number of the SD card to send the > command > + to. > + @param[in] Packet A pointer to the SD command data structure. > + @param[in] Event If Event is NULL, blocking I/O is performed. > + If Event is not NULL, then nonblocking I/O i= s > + performed, and Event will be signaled when t= he > + Packet completes. > + > + @return Created Trb or NULL. > + > +**/ > +DW_MMC_HC_TRB * > +DwMmcCreateTrb ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN UINT8 Slot, > + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, > + IN EFI_EVENT Event > + ); > + > +/** > + Free the resource used by the TRB. > + > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > +**/ > +VOID > +DwMmcFreeTrb ( > + IN DW_MMC_HC_TRB *Trb > + ); > + > +/** > + Check if the env is ready for execute specified TRB. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The env is ready for TRB execution. > + @retval EFI_NOT_READY The env is not ready for TRB execution. > + @retval Others Some erros happen. > + > +**/ > +EFI_STATUS > +DwMmcCheckTrbEnv ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ); > + > +/** > + Wait for the env to be ready for execute specified TRB. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The env is ready for TRB execution. > + @retval EFI_TIMEOUT The env is not ready for TRB execution in ti= me. > + @retval Others Some erros happen. > + > +**/ > +EFI_STATUS > +DwMmcWaitTrbEnv ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ); > + > +/** > + Execute the specified TRB. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The TRB is sent to host controller successfu= lly. > + @retval Others Some erros happen when sending this request = to the > + host controller. > + > +**/ > +EFI_STATUS > +DwMmcExecTrb ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ); > + > +/** > + Check the TRB execution result. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The TRB is executed successfully. > + @retval EFI_NOT_READY The TRB is not completed for execution. > + @retval Others Some erros happen when executing this reques= t. > + > +**/ > +EFI_STATUS > +DwMmcCheckTrbResult ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ); > + > +/** > + Wait for the TRB execution result. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The TRB is executed successfully. > + @retval Others Some erros happen when executing this reques= t. > + > +**/ > +EFI_STATUS > +DwMmcWaitTrbResult ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ); > + > +/** > + Execute EMMC device identification procedure. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + > + @retval EFI_SUCCESS There is a EMMC card. > + @retval Others There is not a EMMC card. > + > +**/ > +EFI_STATUS > +EmmcIdentification ( > + IN DW_MMC_HC_PRIVATE_DATA *Private > + ); > + > +/** > + Execute EMMC device identification procedure. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + > + @retval EFI_SUCCESS There is a EMMC card. > + @retval Others There is not a EMMC card. > + > +**/ > +EFI_STATUS > +SdCardIdentification ( > + IN DW_MMC_HC_PRIVATE_DATA *Private > + ); > + > +#endif /* _DW_MMC_HC_DXE_H_ */ > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h > b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h > new file mode 100644 > index 000000000000..12ef58a37368 > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h > @@ -0,0 +1,985 @@ > +/** @file > + > + Provides some data structure definitions used by the SD/MMC host > controller > + driver. > + > + Copyright (c) 2015, Intel Corporation. All rights reserved.
> + Copyright (c) 2018, Linaro Ltd. All rights reserved.
> + > + This program and the accompanying materials are licensed and made > available > + under the terms and conditions of the BSD License which accompanies th= is > + 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 _DW_MMC_HCI_H_ > +#define _DW_MMC_HCI_H_ > + > +#include > +#include > + > +#include > + > +// > +// SD Host Controller SlotInfo Register Offset > +// > +#define DW_MMC_HC_SLOT_OFFSET 0x40 > + > +#define DW_MMC_HC_MAX_SLOT 1 > + > +// > +// SD Host Controller MMIO Register Offset > +// > +#define DW_MMC_CTRL 0x000 > +#define DW_MMC_PWREN 0x004 > +#define DW_MMC_CLKDIV 0x008 > +#define DW_MMC_CLKSRC 0x00c > +#define DW_MMC_CLKENA 0x010 > +#define DW_MMC_TMOUT 0x014 > +#define DW_MMC_CTYPE 0x018 > +#define DW_MMC_BLKSIZ 0x01c > +#define DW_MMC_BYTCNT 0x020 > +#define DW_MMC_INTMASK 0x024 > +#define DW_MMC_CMDARG 0x028 > +#define DW_MMC_CMD 0x02c > +#define DW_MMC_RESP0 0x030 > +#define DW_MMC_RESP1 0x034 > +#define DW_MMC_RESP2 0x038 > +#define DW_MMC_RESP3 0x03c > +#define DW_MMC_RINTSTS 0x044 > +#define DW_MMC_STATUS 0x048 > +#define DW_MMC_FIFOTH 0x04c > +#define DW_MMC_GPIO 0x058 > +#define DW_MMC_DEBNCE 0x064 > +#define DW_MMC_USRID 0x068 > +#define DW_MMC_VERID 0x06c > +#define DW_MMC_HCON 0x070 > +#define DW_MMC_UHSREG 0x074 > +#define DW_MMC_BMOD 0x080 > +#define DW_MMC_DBADDR 0x088 > +#define DW_MMC_IDSTS 0x08c > +#define DW_MMC_IDINTEN 0x090 > +#define DW_MMC_DSCADDR 0x094 > +#define DW_MMC_BUFADDR 0x098 > +#define DW_MMC_CARDTHRCTL 0x100 > +#define DW_MMC_UHSREG_EXT 0x108 > +#define DW_MMC_ENABLE_SHIFT 0x110 > +#define DW_MMC_FIFO_START 0x200 > + > +#define GET_IDSTS_DMAC_FSM(x) (((x) >> 13) & 0xf) > +#define IDSTS_FSM_DMA_IDLE 0 > +#define IDSTS_FSM_DMA_SUSPEND 1 > +#define IDSTS_FSM_DESC_RD 2 > +#define IDSTS_FSM_DESC_CHK 3 > +#define IDSTS_FSM_DMA_RD_REQ_WAIT 4 > +#define IDSTS_FSM_DMA_WR_REQ_WAIT 5 > +#define IDSTS_FSM_DMA_RD 6 > +#define IDSTS_FSM_DMA_WR 7 > +#define IDSTS_FSM_DESC_CLOSE 8 > +#define IDSTS_FSM_MASK 0xf > + > +#define CMD_UPDATE_CLK 0x80202000 > +#define CMD_START_BIT (1 << 31) > + > +#define MMC_8BIT_MODE (1 << 16) > +#define MMC_4BIT_MODE (1 << 0) > +#define MMC_1BIT_MODE 0 > + > +#define DW_MMC_BLOCK_SIZE 512 > + > +#define CMD_INDEX_MASK 0x3F > +#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 CMD_INDEX(x) ((x) & CMD_INDEX_MASK) > + > +#define DW_MMC_INT_EBE (1 << 15) /* End-b= it Err */ > +#define DW_MMC_INT_SBE (1 << 13) /* Start= -bit Err */ > +#define DW_MMC_INT_HLE (1 << 12) /* Hardw= are-lock Err > */ > +#define DW_MMC_INT_FRUN (1 << 11) /* FIFO = UN/OV RUN > */ > +#define DW_MMC_INT_DRT (1 << 9) /* Data = timeout */ > +#define DW_MMC_INT_RTO (1 << 8) /* Respo= nse timeout > */ > +#define DW_MMC_INT_DCRC (1 << 7) /* Data = CRC err */ > +#define DW_MMC_INT_RCRC (1 << 6) /* Respo= nse CRC err > */ > +#define DW_MMC_INT_RXDR (1 << 5) /* Recei= ve FIFO data > request */ > +#define DW_MMC_INT_TXDR (1 << 4) /* Trans= mit FIFO data > request */ > +#define DW_MMC_INT_DTO (1 << 3) /* Data = trans over */ > +#define DW_MMC_INT_CMD_DONE (1 << 2) /* Comma= nd > done */ > +#define DW_MMC_INT_RE (1 << 1) /* Respo= nse error */ > + > +#define DW_MMC_IDMAC_DES0_DIC (1 << 1) > +#define DW_MMC_IDMAC_DES0_LD (1 << 2) > +#define DW_MMC_IDMAC_DES0_FS (1 << 3) > +#define DW_MMC_IDMAC_DES0_CH (1 << 4) > +#define DW_MMC_IDMAC_DES0_ER (1 << 5) > +#define DW_MMC_IDMAC_DES0_CES (1 << 30) > +#define DW_MMC_IDMAC_DES0_OWN (1 << 31) > +#define DW_MMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff) > +#define DW_MMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) > +#define DW_MMC_IDMAC_SWRESET (1 << 0) > +#define DW_MMC_IDMAC_FB (1 << 1) > +#define DW_MMC_IDMAC_ENABLE (1 << 7) > + > +#define DW_MMC_CTRL_RESET (1 << 0) > +#define DW_MMC_CTRL_FIFO_RESET (1 << 1) > +#define DW_MMC_CTRL_DMA_RESET (1 << 2) > +#define DW_MMC_CTRL_INT_EN (1 << 4) > +#define DW_MMC_CTRL_DMA_EN (1 << 5) > +#define DW_MMC_CTRL_IDMAC_EN (1 << 25) > +#define DW_MMC_CTRL_RESET_ALL (DW_MMC_CTRL_RESET | > DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET) > + > +#define DW_MMC_STS_DATA_BUSY (1 << 9) > +#define DW_MMC_STS_FIFO_COUNT(x) (((x) & 0x1fff) << 17) = /* > Number of filled locations in FIFO */ > +#define GET_STS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff) > +#define DW_MMC_STS_FIFO_FULL(x) (((x) >> 3) & 1) > + > +#define DW_MMC_BMOD_SWR (1 << 0) /* Soft= ware Reset > */ > +#define DW_MMC_BMOD_FB (1 << 1) /* Fix = Burst */ > +#define DW_MMC_BMOD_DE (1 << 7) /* IDMA= C Enable */ > + > +#define DW_MMC_IDSTS_TI (1 << 0) /* Tran= smit Interrupt > */ > +#define DW_MMC_IDSTS_RI (1 << 1) /* Rece= ive Interrupt > */ > + > +#define DW_MMC_FIFO_TWMARK(x) ((x) & 0xfff) > +#define DW_MMC_FIFO_RWMARK(x) (((x) & 0x1ff) << 16) > +#define DW_MMC_DMA_BURST_SIZE(x) (((x) & 0x7) << 28) > + > +#define DW_MMC_CARD_RD_THR(x) (((x) & 0xfff) << 16) > +#define DW_MMC_CARD_RD_THR_EN (1 << 0) > + > +#define UHS_DDR_MODE (1 << 16) > + > +#define GENCLK_DIV 7 > + > +#define DW_MMC_GPIO_CLK_DIV(x) (((x) & 0xf) << 8) > +#define DW_MMC_GPIO_USE_SAMPLE_DLY(x) (((x) & 1) << 13) > +#define DW_MMC_GPIO_CLK_ENABLE BIT16 > + > +#define UHSEXT_SAMPLE_PHASE(x) (((x) & 0x1f) << 16) > +#define UHSEXT_SAMPLE_DRVPHASE(x) (((x) & 0x1f) << 21) > +#define UHSEXT_SAMPLE_DLY(x) (((x) & 0x1f) << 26) > + > +#define DWMMC_DMA_BUF_SIZE (512 * 8) > +#define DWMMC_FIFO_THRESHOLD 16 > + > +#define DWMMC_INIT_CLOCK_FREQ 400 /* KHz = */ > + > +// > +// The transfer modes supported by SD Host Controller > +// Simplified Spec 3.0 Table 1-2 > +// > +typedef enum { > + SdMmcNoData, > + SdMmcPioMode, > + SdMmcSdmaMode, > + SdMmcAdmaMode > +} DW_MMC_HC_TRANSFER_MODE; > + > +// > +// The maximum data length of each descriptor line > +// > +#define ADMA_MAX_DATA_PER_LINE 0x10000 > + > +typedef struct { > + UINT32 Des0; > + UINT32 Des1; > + UINT32 Des2; > + UINT32 Des3; > +} DW_MMC_HC_DMA_DESC_LINE; > + > +#define SD_MMC_SDMA_BOUNDARY 512 * 1024 > +#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1)) > + > +typedef struct { > + UINT8 FirstBar:3; // bit 0:2 > + UINT8 Reserved:1; // bit 3 > + UINT8 SlotNum:3; // bit 4:6 > + UINT8 Reserved1:1; // bit 7 > +} DW_MMC_HC_SLOT_INFO; > + > +/** > + Dump the content of SD/MMC host controller's Capability Register. > + > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[in] Capability The buffer to store the capability data. > + > +**/ > +VOID > +DumpCapabilityReg ( > + IN UINT8 Slot, > + IN DW_MMC_HC_SLOT_CAP *Capability > + ); > + > +#if 0 > +/** > + Read SlotInfo register from SD/MMC host controller pci config space. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[out] FirstBar The buffer to store the first BAR value. > + @param[out] SlotNum The buffer to store the supported slot number= . > + > + @retval EFI_SUCCESS The operation succeeds. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcGetSlotInfo ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + OUT UINT8 *FirstBar, > + OUT UINT8 *SlotNum > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Read/Write specified SD/MMC host controller mmio register. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] BarIndex The BAR index of the standard PCI Configu= ration > + header to use as the base address for the= memory > + operation to perform. > + @param[in] Offset The offset within the selected BAR to sta= rt the > + memory operation. > + @param[in] Read A boolean to indicate it's read or write = operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2 , 4 or 8 bytes. > + @param[in, out] Data For read operations, the destination buff= er to > store > + the results. For write operations, the so= urce buffer > + to write data from. The caller is respons= ible for > + having ownership of the data buffer and e= nsuring its > + size not less than Count bytes. > + > + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count i= s > not valid. > + @retval EFI_SUCCESS The read/write operation succeeds. > + @retval Others The read/write operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcRwMmio ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 BarIndex, > + IN UINT32 Offset, > + IN BOOLEAN Read, > + IN UINT8 Count, > + IN OUT VOID *Data > + ); > +#else > +/** > + Read/Write specified SD/MMC host controller mmio register. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Offset The offset within the selected BAR to sta= rt the > + memory operation. > + @param[in] Read A boolean to indicate it's read or write = operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2 , 4 or 8 bytes. > + @param[in, out] Data For read operations, the destination buff= er to > store > + the results. For write operations, the so= urce buffer > + to write data from. The caller is respons= ible for > + having ownership of the data buffer and e= nsuring its > + size not less than Count bytes. > + > + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count i= s > not valid. > + @retval EFI_SUCCESS The read/write operation succeeds. > + @retval Others The read/write operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcRwMmio ( > + IN UINTN DevBase, > + IN UINT32 Offset, > + IN BOOLEAN Read, > + IN UINT8 Count, > + IN OUT VOID *Data > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Do OR operation with the value of the specified SD/MMC host controller > mmio register. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] BarIndex The BAR index of the standard PCI Configu= ration > + header to use as the base address for the= memory > + operation to perform. > + @param[in] Offset The offset within the selected BAR to sta= rt the > + memory operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2 , 4 or 8 bytes. > + @param[in] OrData The pointer to the data used to do OR ope= ration. > + The caller is responsible for having owne= rship of > + the data buffer and ensuring its size not= less than > + Count bytes. > + > + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the > Count is not valid. > + @retval EFI_SUCCESS The OR operation succeeds. > + @retval Others The OR operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcOrMmio ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 BarIndex, > + IN UINT32 Offset, > + IN UINT8 Count, > + IN VOID *OrData > + ); > +#else > +/** > + Do OR operation with the value of the specified SD/MMC host controller > mmio register. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] BarIndex The BAR index of the standard PCI Configu= ration > + header to use as the base address for the= memory > + operation to perform. > + @param[in] Offset The offset within the selected BAR to sta= rt the > + memory operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2 , 4 or 8 bytes. > + @param[in] OrData The pointer to the data used to do OR ope= ration. > + The caller is responsible for having owne= rship of > + the data buffer and ensuring its size not= less than > + Count bytes. > + > + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the > Count is not valid. > + @retval EFI_SUCCESS The OR operation succeeds. > + @retval Others The OR operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcOrMmio ( > + IN UINTN DevBase, > + IN UINT32 Offset, > + IN UINT8 Count, > + IN VOID *OrData > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Do AND operation with the value of the specified SD/MMC host controlle= r > mmio register. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] BarIndex The BAR index of the standard PCI Configu= ration > + header to use as the base address for the= memory > + operation to perform. > + @param[in] Offset The offset within the selected BAR to sta= rt the > + memory operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2 , 4 or 8 bytes. > + @param[in] AndData The pointer to the data used to do AND > operation. > + The caller is responsible for having owne= rship of > + the data buffer and ensuring its size not= less than > + Count bytes. > + > + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the > Count is not valid. > + @retval EFI_SUCCESS The AND operation succeeds. > + @retval Others The AND operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcAndMmio ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 BarIndex, > + IN UINT32 Offset, > + IN UINT8 Count, > + IN VOID *AndData > + ); > +#else > +/** > + Do AND operation with the value of the specified SD/MMC host controlle= r > mmio register. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Offset The offset within the selected BAR to sta= rt the > + memory operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2 , 4 or 8 bytes. > + @param[in] AndData The pointer to the data used to do AND > operation. > + The caller is responsible for having owne= rship of > + the data buffer and ensuring its size not= less than > + Count bytes. > + > + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the > Count is not valid. > + @retval EFI_SUCCESS The AND operation succeeds. > + @retval Others The AND operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcAndMmio ( > + IN UINTN DevBase, > + IN UINT32 Offset, > + IN UINT8 Count, > + IN VOID *AndData > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Wait for the value of the specified MMIO register set to the test valu= e. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] BarIndex The BAR index of the standard PCI Configurat= ion > + header to use as the base address for the me= mory > + operation to perform. > + @param[in] Offset The offset within the selected BAR to start = the > + memory operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2, 4 or 8 bytes. > + @param[in] MaskValue The mask value of memory. > + @param[in] TestValue The test value of memory. > + @param[in] Timeout The time out value for wait memory set, uses= 1 > + microsecond as a unit. > + > + @retval EFI_TIMEOUT The MMIO register hasn't expected value in > timeout > + range. > + @retval EFI_SUCCESS The MMIO register has expected value. > + @retval Others The MMIO operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcWaitMmioSet ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 BarIndex, > + IN UINT32 Offset, > + IN UINT8 Count, > + IN UINT64 MaskValue, > + IN UINT64 TestValue, > + IN UINT64 Timeout > + ); > +#else > +/** > + Wait for the value of the specified MMIO register set to the test valu= e. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Offset The offset within the selected BAR to start = the > + memory operation. > + @param[in] Count The width of the mmio register in bytes. > + Must be 1, 2, 4 or 8 bytes. > + @param[in] MaskValue The mask value of memory. > + @param[in] TestValue The test value of memory. > + @param[in] Timeout The time out value for wait memory set, uses= 1 > + microsecond as a unit. > + > + @retval EFI_TIMEOUT The MMIO register hasn't expected value in > timeout > + range. > + @retval EFI_SUCCESS The MMIO register has expected value. > + @retval Others The MMIO operation fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcWaitMmioSet ( > + IN UINTN DevBase, > + IN UINT32 Offset, > + IN UINT8 Count, > + IN UINT64 MaskValue, > + IN UINT64 TestValue, > + IN UINT64 Timeout > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Software reset the specified SD/MMC host controller. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + > + @retval EFI_SUCCESS The software reset executes successfully. > + @retval Others The software reset fails. > + > +**/ > +EFI_STATUS > +DwMmcHcReset ( > +fark > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#else > +/** > + Software reset the specified SD/MMC host controller. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + > + @retval EFI_SUCCESS The software reset executes successfully. > + @retval Others The software reset fails. > + > +**/ > +EFI_STATUS > +DwMmcHcReset ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Set all interrupt status bits in Normal and Error Interrupt Status Ena= ble > + register. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + > + @retval EFI_SUCCESS The operation executes successfully. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +DwMmcHcEnableInterrupt ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot > + ); > +#else > +/** > + Set all interrupt status bits in Normal and Error Interrupt Status Ena= ble > + register. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + > + @retval EFI_SUCCESS The operation executes successfully. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +DwMmcHcEnableInterrupt ( > + IN UINTN DevBase > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Get the capability data from the specified slot. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[out] Capability The buffer to store the capability data. > + > + @retval EFI_SUCCESS The operation executes successfully. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +DwMmcHcGetCapability ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN EFI_HANDLE Controller, > + IN UINT8 Slot, > + OUT DW_MMC_HC_SLOT_CAP *Capability > + ); > +#else > +/** > + Get the capability data from the specified slot. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[out] Capability The buffer to store the capability data. > + > + @retval EFI_SUCCESS The operation executes successfully. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +DwMmcHcGetCapability ( > + IN UINTN DevBase, > + IN EFI_HANDLE Controller, > + IN UINT8 Slot, > + OUT DW_MMC_HC_SLOT_CAP *Capability > + ); > +#endif > + > +#if 0 > +/** > + Get the maximum current capability data from the specified slot. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[out] MaxCurrent The buffer to store the maximum current > capability data. > + > + @retval EFI_SUCCESS The operation executes successfully. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +DwMmcHcGetMaxCurrent ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + OUT UINT64 *MaxCurrent > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Detect whether there is a SD/MMC card attached at the specified > SD/MMC host controller > + slot. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for detail= s. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[out] MediaPresent The pointer to the media present boolean > value. > + > + @retval EFI_SUCCESS There is no media change happened. > + @retval EFI_MEDIA_CHANGED There is media change happened. > + @retval Others The detection fails. > + > +**/ > +EFI_STATUS > +DwMmcHcCardDetect ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN EFI_HANDLE Controller, > + IN UINT8 Slot, > + OUT BOOLEAN *MediaPresent > + ); > +#else > +/** > + Detect whether there is a SD/MMC card attached at the specified > SD/MMC host controller > + slot. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for detail= s. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[out] MediaPresent The pointer to the media present boolean > value. > + > + @retval EFI_SUCCESS There is no media change happened. > + @retval EFI_MEDIA_CHANGED There is media change happened. > + @retval Others The detection fails. > + > +**/ > +EFI_STATUS > +DwMmcHcCardDetect ( > + IN UINTN DevBase, > + IN EFI_HANDLE Controller, > + IN UINT8 Slot, > + OUT BOOLEAN *MediaPresent > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Stop SD/MMC card clock. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for deta= ils. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + > + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. > + @retval Others Fail to stop SD/MMC clock. > + > +**/ > +EFI_STATUS > +DwMmcHcStopClock ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot > + ); > + > +/** > + SD/MMC card clock supply. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for deta= ils. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[in] ClockFreq The max clock frequency to be set. The unit = is > KHz. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The clock is supplied successfully. > + @retval Others The clock isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcClockSupply ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + IN UINT64 ClockFreq, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#else > +/** > + Stop SD/MMC card clock. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for deta= ils. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + > + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. > + @retval Others Fail to stop SD/MMC clock. > + > +**/ > +EFI_STATUS > +DwMmcHcStopClock ( > + IN UINTN DevBase > + ); > + > +/** > + SD/MMC card clock supply. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for deta= ils. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] ClockFreq The max clock frequency to be set. The unit = is > KHz. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The clock is supplied successfully. > + @retval Others The clock isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcClockSupply ( > + IN UINTN DevBase, > + IN UINT64 ClockFreq, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#endif > + > +#if 0 > +/** > + SD/MMC bus power control. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for detail= s. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[in] PowerCtrl The value setting to the power control regis= ter. > + > + @retval TRUE There is a SD/MMC card attached. > + @retval FALSE There is no a SD/MMC card attached. > + > +**/ > +EFI_STATUS > +DwMmcHcPowerControl ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + IN UINT8 PowerCtrl > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Set the SD/MMC bus width. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for detail= s. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[in] BusWidth The bus width used by the SD/MMC device, it > must be 1, 4 or 8. > + > + @retval EFI_SUCCESS The bus width is set successfully. > + @retval Others The bus width isn't set successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcSetBusWidth ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + IN BOOLEAN IsDdr, > + IN UINT16 BusWidth > + ); > +#else > +/** > + Set the SD/MMC bus width. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for detail= s. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] BusWidth The bus width used by the SD/MMC device, it > must be 1, 4 or 8. > + > + @retval EFI_SUCCESS The bus width is set successfully. > + @retval Others The bus width isn't set successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcSetBusWidth ( > + IN UINTN DevBase, > + IN BOOLEAN IsDdr, > + IN UINT16 BusWidth > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Supply SD/MMC card with lowest clock frequency at initialization. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The clock is supplied successfully. > + @retval Others The clock isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitClockFreq ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#else > +/** > + Supply SD/MMC card with lowest clock frequency at initialization. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The clock is supplied successfully. > + @retval Others The clock isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitClockFreq ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Supply SD/MMC card with maximum voltage at initialization. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for detail= s. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The voltage is supplied successfully. > + @retval Others The voltage isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitPowerVoltage ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#else > +/** > + Supply SD/MMC card with maximum voltage at initialization. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for detail= s. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The voltage is supplied successfully. > + @retval Others The voltage isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitPowerVoltage ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Initialize the Timeout Control register with most conservative value a= t > initialization. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for det= ails. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + > + @retval EFI_SUCCESS The timeout control register is configured > successfully. > + @retval Others The timeout control register isn't configure= d > successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitTimeoutCtrl ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot > + ); > +#else > +/** > + Initialize the Timeout Control register with most conservative value a= t > initialization. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for det= ails. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + > + @retval EFI_SUCCESS The timeout control register is configured > successfully. > + @retval Others The timeout control register isn't configure= d > successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitTimeoutCtrl ( > + IN UINTN DevBase > + ); > +#endif > + > +#ifdef DWMMC_PCI > +/** > + Initial SD/MMC host controller with lowest clock frequency, max power > and max timeout value > + at initialization. > + > + @param[in] PciIo The PCI IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command to. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The host controller is initialized successfu= lly. > + @retval Others The host controller isn't initialized succes= sfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitHost ( > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN UINT8 Slot, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#else > +/** > + Initial SD/MMC host controller with lowest clock frequency, max power > and > + max timeout value at initialization. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The host controller is initialized successfu= lly. > + @retval Others The host controller isn't initialized succes= sfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitHost ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ); > +#endif > + > +#endif /* _DW_MMC_HCI_H_ */ > diff --git a/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h > b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h > new file mode 100644 > index 000000000000..acbc3e153dac > --- /dev/null > +++ b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h > @@ -0,0 +1,79 @@ > +/** @file > + > + Copyright (c) 2018, Linaro. All rights reserved. > + > + This program and the accompanying materials are licensed and made > available > + under the terms and conditions of the BSD License which accompanies th= is > + 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 __PLATFORM_DW_MMC_H__ > +#define __PLATFORM_DW_MMC_H__ > + > +typedef enum { > + RemovableSlot, > + EmbeddedSlot, > + SharedBusSlot, > + UnknownSlot > +} EFI_SD_MMC_SLOT_TYPE; > + > +typedef enum { > + UnknownCardType, > + SdCardType, > + SdioCardType, > + MmcCardType, > + EmmcCardType > +} SD_MMC_CARD_TYPE; > + > +typedef struct { > + UINT32 DefaultSpeed:1; // bit 0 > + UINT32 HighSpeed:1; // bit 1 > + UINT32 Sdr12:1; // bit 2 > + UINT32 Sdr25:1; // bit 3 > + UINT32 Sdr50:1; // bit 4 > + UINT32 Sdr104:1; // bit 5 > + UINT32 Ddr50:1; // bit 6 > + UINT32 SysBus64:1; // bit 7 > + UINT32 BusWidth:4; // bit 11:8 > + UINT32 SlotType:2; // bit 13:12 > + UINT32 CardType:3; // bit 16:14 > + UINT32 Voltage18:1; // bit 17 > + UINT32 Voltage30:1; // bit 18 > + UINT32 Voltage33:1; // bit 19 > + UINT32 BaseClkFreq; > + EFI_HANDLE Controller; > +} DW_MMC_HC_SLOT_CAP; > + > +// > +// Protocol interface structure > +// > +typedef struct _PLATFORM_DW_MMC_PROTOCOL > PLATFORM_DW_MMC_PROTOCOL; > + > +typedef > +EFI_STATUS > +(EFIAPI *PLATFORM_DW_MMC_GET_CAPABILITY) ( > + IN EFI_HANDLE Controller, > + IN UINT8 Slot, > + OUT DW_MMC_HC_SLOT_CAP *Capability > + ); > + > +typedef > +BOOLEAN > +(EFIAPI *PLATFORM_DW_MMC_CARD_DETECT) ( > + IN EFI_HANDLE Controller, > + IN UINT8 Slot > + ); > + > +struct _PLATFORM_DW_MMC_PROTOCOL { > + PLATFORM_DW_MMC_GET_CAPABILITY GetCapability; > + PLATFORM_DW_MMC_CARD_DETECT CardDetect; > +}; > + > +extern EFI_GUID gPlatformDwMmcProtocolGuid; > + > +#endif /* __PLATFORM_DW_MMC_H__ */ > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c > b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c > new file mode 100644 > index 000000000000..1edade69d091 > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c > @@ -0,0 +1,214 @@ > +/** @file > + UEFI Component Name(2) protocol implementation for Designware > SD/MMC host > + controller driver. > + > + Copyright (c) 2015, Intel Corporation. All rights reserved.
> + Copyright (c) 2018, Linaro Ltd. All rights reserved.
> + > + This program and the accompanying materials are licensed and made > available > + under the terms and conditions of the BSD License which accompanies th= is > + 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 "DwMmcHcDxe.h" > + > +// > +// EFI Component Name Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName =3D { > + DwMmcHcComponentNameGetDriverName, > + DwMmcHcComponentNameGetControllerName, > + "eng" > +}; > + > +// > +// EFI Component Name 2 Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2 =3D { > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) > DwMmcHcComponentNameGetDriverName, > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) > DwMmcHcComponentNameGetControllerName, > + "en" > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mDwMmcHcDriverNameTable[] =3D { > + { "eng;en", L"Designware Sd/Mmc Host Controller Driver" }, > + { NULL , NULL } > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mDwMmcHcControllerNameTable[] =3D { > + { "eng;en", L"Designware Sd/Mmc Host Controller" }, > + { NULL , NULL } > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + This function retrieves the user readable name of a driver in the form= of a > + Unicode string. If the driver specified by This has a user readable na= me in > + the language specified by Language, then a pointer to the driver name = is > + returned in DriverName, and EFI_SUCCESS is returned. If the driver > specified > + by This does not support the language specified by Language, > + then EFI_UNSUPPORTED is returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + This Unicode string is the name of the > + driver specified by This in the language > + specified by Language. > + > + @retval EFI_SUCCESS The Unicode string for the Driver specif= ied by > + This and the language specified by Langu= age was > + returned in DriverName. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER DriverName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not > support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcComponentNameGetDriverName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN CHAR8 *Language, > + OUT CHAR16 **DriverName > + ) > +{ > + return LookupUnicodeString2 ( > + Language, > + This->SupportedLanguages, > + mDwMmcHcDriverNameTable, > + DriverName, > + (BOOLEAN)(This =3D=3D &gDwMmcHcComponentName) > + ); > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > by > + Language, then a pointer to the controller name is returned in > ControllerName, > + and EFI_SUCCESS is returned. If the driver specified by This is not c= urrently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This doe= s > not > + support the language specified by Language, then EFI_UNSUPPORTED is > returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param ControllerHandle[in] The handle of a controller that the driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter that > + may be NULL. It will be NULL for device > + drivers. It will also be NULL for a bus= drivers > + that wish to retrieve the name of the bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + This Unicode string is the name of the > + controller specified by ControllerHandle= and > + ChildHandle in the language specified by > + Language from the point of view of the d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + driver specified by This was returned in > + DriverName. > + > + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid > EFI_HANDLE. > + > + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a > valid > + EFI_HANDLE. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER ControllerName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This is not curr= ently > + managing the controller specified by > + ControllerHandle and ChildHandle. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not > support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcComponentNameGetControllerName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN EFI_HANDLE ControllerHandle, > + IN EFI_HANDLE ChildHandle, OPTIONAL > + IN CHAR8 *Language, > + OUT CHAR16 **ControllerName > + ) > +{ > + EFI_STATUS Status; > + > + if (Language =3D=3D NULL || ControllerName =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // This is a device driver, so ChildHandle must be NULL. > + // > + if (ChildHandle !=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // Make sure this driver is currently managing ControllerHandle > + // > + Status =3D EfiTestManagedDevice ( > + ControllerHandle, > + gDwMmcHcDriverBinding.DriverBindingHandle, > + &gEfiPciIoProtocolGuid > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return LookupUnicodeString2 ( > + Language, > + This->SupportedLanguages, > + mDwMmcHcControllerNameTable, > + ControllerName, > + (BOOLEAN)(This =3D=3D &gDwMmcHcComponentName) > + ); > +} > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c > b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c > new file mode 100644 > index 000000000000..aea12170d2cc > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c > @@ -0,0 +1,1296 @@ > +/** @file > + This driver is used to manage Designware SD/MMC host controller. > + > + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer > use. > + > + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.
> + Copyright (C) 2016 Marvell International Ltd. All rigths reserved.
> + Copyright (C) 2018, Linaro Ltd. All rigths reserved.
> + > + 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 > +#include > +#include > +#include > + > +#include > +#include > + > +#include "DwMmcHcDxe.h" > + > +// > +// Driver Global Variables > +// > +EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding =3D { > + DwMmcHcDriverBindingSupported, > + DwMmcHcDriverBindingStart, > + DwMmcHcDriverBindingStop, > + 0x10, > + NULL, > + NULL > +}; > + > +// > +// Template for Designware SD/MMC host controller private data. > +// > +DW_MMC_HC_PRIVATE_DATA gDwMmcHcTemplate =3D { > + DW_MMC_HC_PRIVATE_SIGNATURE, // Signature > + NULL, // ControllerHandle > + 0x0, // Mmio base address > + { // PassThru > + sizeof (UINT32), > + DwMmcPassThruPassThru, > + DwMmcPassThruGetNextSlot, > + DwMmcPassThruBuildDevicePath, > + DwMmcPassThruGetSlotNumber, > + DwMmcPassThruResetDevice > + }, > + NULL, // PlatformDwMmc > + 0, // PreviousSlot > + NULL, // TimerEvent > + NULL, // ConnectEvent > + // Queue > + INITIALIZE_LIST_HEAD_VARIABLE (gDwMmcHcTemplate.Queue), > + { // Slot > + {0, UnknownSlot, 0, 0, 0} > + }, > + { // Capability > + {0} > + }, > + { // MaxCurrent > + 0 > + }, > + 0 // ControllerVersion > +}; > + > +SD_DEVICE_PATH mSdDpTemplate =3D { > + { > + MESSAGING_DEVICE_PATH, > + MSG_SD_DP, > + { > + (UINT8) (sizeof (SD_DEVICE_PATH)), > + (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8) > + } > + }, > + 0 > +}; > + > +EMMC_DEVICE_PATH mEmmcDpTemplate =3D { > + { > + MESSAGING_DEVICE_PATH, > + MSG_EMMC_DP, > + { > + (UINT8) (sizeof (EMMC_DEVICE_PATH)), > + (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8) > + } > + }, > + 0 > +}; > + > +// > +// Prioritized function list to detect card type. > +// User could add other card detection logic here. > +// > +DWMMC_CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] > =3D { > + EmmcIdentification, > + SdCardIdentification, > + NULL > +}; > + > +/** > + The entry point for SD host controller driver, used to install this dr= iver on > the ImageHandle. > + > + @param[in] ImageHandle The firmware allocated handle for this drive= r > image. > + @param[in] SystemTable Pointer to the EFI system table. > + > + @retval EFI_SUCCESS Driver loaded. > + @retval other Driver not loaded. > + > +**/ > +EFI_STATUS > +EFIAPI > +InitializeDwMmcHcDxe ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D EfiLibInstallDriverBindingComponentName2 ( > + ImageHandle, > + SystemTable, > + &gDwMmcHcDriverBinding, > + ImageHandle, > + &gDwMmcHcComponentName, > + &gDwMmcHcComponentName2 > + ); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > + > +/** > + Call back function when the timer event is signaled. > + > + @param[in] Event The Event this notify function registered to. > + @param[in] Context Pointer to the context data registered to the > + Event. > + > +**/ > +VOID > +EFIAPI > +ProcessAsyncTaskList ( > + IN EFI_EVENT Event, > + IN VOID* Context > + ) > +{ > + DW_MMC_HC_PRIVATE_DATA *Private; > + LIST_ENTRY *Link; > + DW_MMC_HC_TRB *Trb; > + EFI_STATUS Status; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + BOOLEAN InfiniteWait; > + EFI_EVENT TrbEvent; > + > + Private =3D (DW_MMC_HC_PRIVATE_DATA *)Context; > + > + // > + // Check if the first entry in the async I/O queue is done or not. > + // > + Status =3D EFI_SUCCESS; > + Trb =3D NULL; > + Link =3D GetFirstNode (&Private->Queue); > + if (!IsNull (&Private->Queue, Link)) { > + Trb =3D DW_MMC_HC_TRB_FROM_THIS (Link); > + if (!Private->Slot[Trb->Slot].MediaPresent) { > + Status =3D EFI_NO_MEDIA; > + goto Done; > + } > + if (!Trb->Started) { > + // > + // Check whether the cmd/data line is ready for transfer. > + // > + Status =3D DwMmcCheckTrbEnv (Private, Trb); > + if (!EFI_ERROR (Status)) { > + Trb->Started =3D TRUE; > + Status =3D DwMmcExecTrb (Private, Trb); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + } else { > + goto Done; > + } > + } > + Status =3D DwMmcCheckTrbResult (Private, Trb); > + } > + > +Done: > + if ((Trb !=3D NULL) && (Status =3D=3D EFI_NOT_READY)) { > + Packet =3D Trb->Packet; > + if (Packet->Timeout =3D=3D 0) { > + InfiniteWait =3D TRUE; > + } else { > + InfiniteWait =3D FALSE; > + } > + if ((!InfiniteWait) && (Trb->Timeout-- =3D=3D 0)) { > + RemoveEntryList (Link); > + Trb->Packet->TransactionStatus =3D EFI_TIMEOUT; > + TrbEvent =3D Trb->Event; > + DwMmcFreeTrb (Trb); > + DEBUG (( > + DEBUG_VERBOSE, > + "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", > + TrbEvent > + )); > + gBS->SignalEvent (TrbEvent); > + return; > + } > + } > + if ((Trb !=3D NULL) && (Status !=3D EFI_NOT_READY)) { > + RemoveEntryList (Link); > + Trb->Packet->TransactionStatus =3D Status; > + TrbEvent =3D Trb->Event; > + DwMmcFreeTrb (Trb); > + DEBUG (( > + DEBUG_VERBOSE, > + "ProcessAsyncTaskList(): Signal Event %p with %r\n", > + TrbEvent, > + Status > + )); > + gBS->SignalEvent (TrbEvent); > + } > + return; > +} > + > +/** > + Sd removable device enumeration callback function when the timer event > is signaled. > + > + @param[in] Event The Event this notify function registered to. > + @param[in] Context Pointer to the context data registered to the > + Event. > + > +**/ > +VOID > +EFIAPI > +DwMmcHcEnumerateDevice ( > + IN EFI_EVENT Event, > + IN VOID* Context > + ) > +{ > + DW_MMC_HC_PRIVATE_DATA *Private; > + EFI_STATUS Status; > + BOOLEAN MediaPresent; > + UINT32 RoutineNum; > + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine; > + UINTN Index; > + LIST_ENTRY *Link; > + LIST_ENTRY *NextLink; > + DW_MMC_HC_TRB *Trb; > + EFI_TPL OldTpl; > + > + Private =3D (DW_MMC_HC_PRIVATE_DATA *)Context; > + > + if ((Private->Slot[0].Enable) && > + (Private->Slot[0].SlotType =3D=3D RemovableSlot)) { > + Status =3D DwMmcHcCardDetect ( > + Private->DevBase, > + Private->ControllerHandle, > + 0, > + &MediaPresent > + ); > + if ((Status =3D=3D EFI_MEDIA_CHANGED) && !MediaPresent) { > + DEBUG (( > + DEBUG_INFO, > + "DwMmcHcEnumerateDevice: device disconnected at %p\n", > + Private->DevBase > + )); > + Private->Slot[0].MediaPresent =3D FALSE; > + // > + // Signal all async task events at the slot with EFI_NO_MEDIA stat= us. > + // > + OldTpl =3D gBS->RaiseTPL (TPL_NOTIFY); > + for (Link =3D GetFirstNode (&Private->Queue); > + !IsNull (&Private->Queue, Link); > + Link =3D NextLink) { > + NextLink =3D GetNextNode (&Private->Queue, Link); > + Trb =3D DW_MMC_HC_TRB_FROM_THIS (Link); > + if (Trb->Slot =3D=3D 0) { > + RemoveEntryList (Link); > + Trb->Packet->TransactionStatus =3D EFI_NO_MEDIA; > + gBS->SignalEvent (Trb->Event); > + DwMmcFreeTrb (Trb); > + } > + } > + gBS->RestoreTPL (OldTpl); > + // > + // Notify the upper layer the connect state change through > + // ReinstallProtocolInterface. > + // > + gBS->ReinstallProtocolInterface ( > + Private->ControllerHandle, > + &gEfiSdMmcPassThruProtocolGuid, > + &Private->PassThru, > + &Private->PassThru > + ); > + } > + if ((Status =3D=3D EFI_MEDIA_CHANGED) && MediaPresent) { > + DEBUG (( > + DEBUG_INFO, > + "DwMmcHcEnumerateDevice: device connected at %p\n", > + Private->DevBase > + )); > + // > + // Initialize slot and start identification process for the new > + // attached device > + // > + Status =3D DwMmcHcInitHost (Private->DevBase, Private->Capability[= 0]); > + if (EFI_ERROR (Status)) { > + return; > + } > + // > + // Reset the specified slot of the SD/MMC Pci Host Controller > + // > + Status =3D DwMmcHcReset (Private->DevBase, Private->Capability[0])= ; > + if (EFI_ERROR (Status)) { > + return; > + } > + > + Private->Slot[0].MediaPresent =3D TRUE; > + RoutineNum =3D sizeof (mCardTypeDetectRoutineTable) / > + sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE); > + for (Index =3D 0; Index < RoutineNum; Index++) { > + Routine =3D &mCardTypeDetectRoutineTable[Index]; > + if (*Routine !=3D NULL) { > + Status =3D (*Routine) (Private); > + if (!EFI_ERROR (Status)) { > + break; > + } > + } > + } > + // > + // This card doesn't get initialized correctly. > + // > + if (Index =3D=3D RoutineNum) { > + return; > + } > + > + // > + // Notify the upper layer the connect state change through > + // ReinstallProtocolInterface. > + // > + gBS->ReinstallProtocolInterface ( > + Private->ControllerHandle, > + &gEfiSdMmcPassThruProtocolGuid, > + &Private->PassThru, > + &Private->PassThru > + ); > + } > + } > + > + return; > +} > + > +/** > + Reset the specified SD/MMC host controller and enable all interrupts. > + > + @param[in] DevBase The Mmio Device Base Address. > + > + @retval EFI_SUCCESS The software reset executes successfully. > + @retval Others The software reset fails. > + > +**/ > +EFI_STATUS > +DwMmcHcReset ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ) > +{ > + EFI_STATUS Status; > + UINT32 BlkSize; > + > + // > + // Enable all interrupt after reset all. > + // > + Status =3D DwMmcHcEnableInterrupt (DevBase); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "DwMmcHcReset: enable interrupts fail: %r\n", > Status)); > + return Status; > + } > + Status =3D DwMmcHcInitTimeoutCtrl (DevBase); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + BlkSize =3D DW_MMC_BLOCK_SIZE; > + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize); > + > + Status =3D DwMmcHcInitClockFreq (DevBase, Capability); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D DwMmcHcSetBusWidth (DevBase, FALSE, 1); > + > + return Status; > +} > + > +/** > + Tests to see if this driver supports a given controller. If a child de= vice > + is provided, it further tests to see if this driver supports creating = a > + handle for the specified child device. > + > + This function checks to see if the driver specified by This supports t= he > + device specified by ControllerHandle. Drivers will typically use the d= evice > + path attached to ControllerHandle and/or the services from the bus I/O > + abstraction attached to ControllerHandle to determine if the driver > supports > + ControllerHandle. This function may be called many times during platfo= rm > + initialization. In order to reduce boot times, the tests performed by = this > + function must be very small, and take as little time as possible to ex= ecute. > + This function must not change the state of any hardware devices, and t= his > + function must be aware that the device specified by ControllerHandle m= ay > + already be managed by the same driver or a different driver. This func= tion > + must match its calls to AllocatePages() with FreePages(), AllocatePool= () > with > + FreePool(), and OpenProtocol() with CloseProtocol(). Since > ControllerHandle > + may have been previously started by the same driver, if a protocol is > already > + in the opened state, then it must not be closed with CloseProtocol(). = This is > + required to guarantee the state of ControllerHandle is not modified by= this > + function. > + > + @param[in] This A pointer to the > EFI_DRIVER_BINDING_PROTOCOL > + instance. > + @param[in] ControllerHandle The handle of the controller to test.= This > + handle must support a protocol interf= ace that > + supplies an I/O abstraction to the dr= iver. > + @param[in] RemainingDevicePath A pointer to the remaining portion of= a > + device path. This parameter is ignor= ed by > + device drivers, and is optional for b= us > + drivers. For bus drivers, if this par= ameter > + is not NULL, then the bus driver must= deter- > + mine if the bus controller specified = by > + ControllerHandle and the child contro= ller > + specified by RemainingDevicePath are = both > + supported by this bus driver. > + > + @retval EFI_SUCCESS The device specified by ControllerHan= dle and > + RemainingDevicePath is supported by t= he > + driver specified by This. > + @retval EFI_ALREADY_STARTED The device specified by > ControllerHandle and > + RemainingDevicePath is already being = managed > + by the driver specified by This. > + @retval EFI_ACCESS_DENIED The device specified by ControllerHan= dle > and > + RemainingDevicePath is already being = managed > + by a different driver or an applicati= on that > + requires exclusive access. > + Currently not implemented. > + @retval EFI_UNSUPPORTED The device specified by ControllerHan= dle > and > + RemainingDevicePath is not supported = by the > + driver specified by This. > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcDriverBindingSupported ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ) > +{ > + EFI_STATUS Status; > + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; > + NON_DISCOVERABLE_DEVICE *Dev; > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; > + > + ParentDevicePath =3D NULL; > + > + Status =3D gBS->LocateProtocol ( > + &gPlatformDwMmcProtocolGuid, > + NULL, > + (VOID **) &PlatformDwMmc > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID *) &ParentDevicePath, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status)) { > + // > + // EFI_ALREADY_STARTED is also an error. > + // > + return Status; > + } > + // > + // Close the protocol because we don't use it here. > + // > + gBS->CloseProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + // > + // Now test the EmbeddedNonDiscoverableIoProtocol. > + // > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEdkiiNonDiscoverableDeviceProtocolGuid, > + (VOID **) &Dev, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + gBS->CloseProtocol ( > + Controller, > + &gEdkiiNonDiscoverableDeviceProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + return EFI_SUCCESS; > +} > + > +/** > + Starts a device controller or a bus controller. > + > + The Start() function is designed to be invoked from the EFI boot servi= ce > + ConnectController(). > + As a result, much of the error checking on the parameters to Start() h= as > + been moved into this > + common boot service. It is legal to call Start() from other locations, > + but the following calling restrictions must be followed or the system > + behavior will not be deterministic. > + 1. ControllerHandle must be a valid EFI_HANDLE. > + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a > + naturally aligned EFI_DEVICE_PATH_PROTOCOL. > + 3. Prior to calling Start(), the Supported() function for the driver > + specified by This must have been called with the same calling > parameters, > + and Supported() must have returned EFI_SUCCESS. > + > + @param[in] This A pointer to the > EFI_DRIVER_BINDING_PROTOCOL > + instance. > + @param[in] ControllerHandle The handle of the controller to start= . This > + handle must support a protocol interf= ace > + that supplies an I/O abstraction to t= he > + driver. > + @param[in] RemainingDevicePath A pointer to the remaining portion of= a > + device path. This parameter is ignor= ed by > + device drivers, and is optional for b= us > + drivers. > + For a bus driver, if this parameter i= s NULL, > + then handles for all the children of > + Controller are created by this driver= . > + If this parameter is not NULL and the= first > + Device Path Node is not the End of De= vice > + Path Node, then only the handle for t= he > + child device specified by the first D= evice > + Path Node of RemainingDevicePath is c= reated > + by this driver. > + If the first Device Path Node of > + RemainingDevicePath is the End of Dev= ice Path > + Node, no child handle is created by t= his > + driver. > + > + @retval EFI_SUCCESS The device was started. > + @retval EFI_DEVICE_ERROR The device could not be started due t= o a > + device error. Currently not implement= ed. > + @retval EFI_OUT_OF_RESOURCES The request could not be completed > due to a > + lack of resources. > + @retval Others The driver failded to start the devic= e. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcDriverBindingStart ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ) > +{ > + EFI_STATUS Status; > + DW_MMC_HC_PRIVATE_DATA *Private; > + > + NON_DISCOVERABLE_DEVICE *Dev; > + > + BOOLEAN MediaPresent; > + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine; > + UINT8 Index; > + UINT32 RoutineNum; > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; > + > + Status =3D gBS->LocateProtocol ( > + &gPlatformDwMmcProtocolGuid, > + NULL, > + (VOID **) &PlatformDwMmc > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "err %d", __LINE__)); > + return Status; > + } > + > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEdkiiNonDiscoverableDeviceProtocolGuid, > + (VOID **) &Dev, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "err %d", __LINE__)); > + return Status; > + } > + > + Private =3D AllocateCopyPool (sizeof (DW_MMC_HC_PRIVATE_DATA), > &gDwMmcHcTemplate); > + if (Private =3D=3D NULL) { > + DEBUG ((DEBUG_ERROR, "err %d", __LINE__)); > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + Private->ControllerHandle =3D Controller; > + Private->DevBase =3D Dev->Resources[0].AddrRangeMin; > + Private->PlatformDwMmc =3D PlatformDwMmc; > + InitializeListHead (&Private->Queue); > + > + Status =3D Private->PlatformDwMmc->GetCapability (Controller, 0, &Priv= ate- > >Capability[0]); > + > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + if (Private->Capability[0].BaseClkFreq =3D=3D 0) { > + goto Done; > + } > + > + DumpCapabilityReg (0, &Private->Capability[0]); > + > + MediaPresent =3D FALSE; > + > + Status =3D Private->PlatformDwMmc->CardDetect (Controller, 0); > + Status =3D DwMmcHcCardDetect (Private->DevBase, Controller, 0, > &MediaPresent); > + if (MediaPresent =3D=3D FALSE) { > + goto Done; > + } > + > + // > + // Initialize slot and start identification process for the new attach= ed device > + // > + Status =3D DwMmcHcInitHost (Private->DevBase, Private->Capability[0]); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Reset HC > + // > + Status =3D DwMmcHcReset (Private->DevBase, Private->Capability[0]); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Private->Slot[0].CardType =3D Private->Capability[0].CardType; > + Private->Slot[0].Enable =3D TRUE; > + Private->Slot[0].MediaPresent =3D TRUE; > + > + RoutineNum =3D sizeof (mCardTypeDetectRoutineTable) / sizeof > (DWMMC_CARD_TYPE_DETECT_ROUTINE); > + for (Index =3D 0; Index < RoutineNum; Index++) { > + Routine =3D &mCardTypeDetectRoutineTable[Index]; > + if (*Routine !=3D NULL) { > + Status =3D (*Routine) (Private); > + if (!EFI_ERROR (Status)) { > + break; > + } > + } > + } > + > + // > + // Start the asynchronous I/O monitor > + // > + Status =3D gBS->CreateEvent ( > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + ProcessAsyncTaskList, > + Private, > + &Private->TimerEvent > + ); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D gBS->SetTimer (Private->TimerEvent, TimerPeriodic, > DW_MMC_HC_ASYNC_TIMER); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Start the Sd removable device connection enumeration > + // > + Status =3D gBS->CreateEvent ( > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > + TPL_CALLBACK, > + DwMmcHcEnumerateDevice, > + Private, > + &Private->ConnectEvent > + ); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, > DW_MMC_HC_ENUM_TIMER); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &Controller, > + &gEfiSdMmcPassThruProtocolGuid, > + &(Private->PassThru), > + NULL > + ); > + > + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStart: %r End on %x\n", > Status, Controller)); > + > +Done: > + if (EFI_ERROR (Status)) { > + if ((Private !=3D NULL) && (Private->TimerEvent !=3D NULL)) { > + gBS->CloseEvent (Private->TimerEvent); > + } > + > + if ((Private !=3D NULL) && (Private->ConnectEvent !=3D NULL)) { > + gBS->CloseEvent (Private->ConnectEvent); > + } > + > + if (Private !=3D NULL) { > + FreePool (Private); > + } > + } > + > + return Status; > +} > + > +/** > + Stops a device controller or a bus controller. > + > + The Stop() function is designed to be invoked from the EFI boot servic= e > + DisconnectController(). > + As a result, much of the error checking on the parameters to Stop() ha= s > been > + moved into this common boot service. It is legal to call Stop() from o= ther > + locations, but the following calling restrictions must be followed or = the > + system behavior will not be deterministic. > + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a > previous > + call to this same driver's Start() function. > + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be= a > valid > + EFI_HANDLE. In addition, all of these handles must have been create= d in > + this driver's Start() function, and the Start() function must have = called > + OpenProtocol() on ControllerHandle with an Attribute of > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. > + > + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROT= OCOL > + instance. > + @param[in] ControllerHandle A handle to the device being stopped. Th= e > handle > + must support a bus specific I/O protocol= for the > + driver to use to stop the device. > + @param[in] NumberOfChildren The number of child device handles in > + ChildHandleBuffer. > + @param[in] ChildHandleBuffer An array of child handles to be freed. M= ay > be > + NULL if NumberOfChildren is 0. > + > + @retval EFI_SUCCESS The device was stopped. > + @retval EFI_DEVICE_ERROR The device could not be stopped due to a > device > + error. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcHcDriverBindingStop ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN UINTN NumberOfChildren, > + IN EFI_HANDLE *ChildHandleBuffer > + ) > +{ > + EFI_STATUS Status; > + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; > + DW_MMC_HC_PRIVATE_DATA *Private; > + LIST_ENTRY *Link; > + LIST_ENTRY *NextLink; > + DW_MMC_HC_TRB *Trb; > + > + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: Start\n")); > + > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiSdMmcPassThruProtocolGuid, > + (VOID**) &PassThru, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); > + // > + // Close Non-Blocking timer and free Task list. > + // > + if (Private->TimerEvent !=3D NULL) { > + gBS->CloseEvent (Private->TimerEvent); > + Private->TimerEvent =3D NULL; > + } > + if (Private->ConnectEvent !=3D NULL) { > + gBS->CloseEvent (Private->ConnectEvent); > + Private->ConnectEvent =3D NULL; > + } > + // > + // As the timer is closed, there is no needs to use TPL lock to > + // protect the critical region "queue". > + // > + for (Link =3D GetFirstNode (&Private->Queue); > + !IsNull (&Private->Queue, Link); > + Link =3D NextLink) { > + NextLink =3D GetNextNode (&Private->Queue, Link); > + RemoveEntryList (Link); > + Trb =3D DW_MMC_HC_TRB_FROM_THIS (Link); > + Trb->Packet->TransactionStatus =3D EFI_ABORTED; > + gBS->SignalEvent (Trb->Event); > + DwMmcFreeTrb (Trb); > + } > + > + // > + // Uninstall Block I/O protocol from the device handle > + // > + Status =3D gBS->UninstallProtocolInterface ( > + Controller, > + &gEfiSdMmcPassThruProtocolGuid, > + &(Private->PassThru) > + ); > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + gBS->CloseProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + FreePool (Private); > + > + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: End with %r\n", > Status)); > + > + return Status; > +} > + > +/** > + Sends SD command to an SD card that is attached to the SD controller. > + > + The PassThru() function sends the SD command specified by Packet to th= e > SD > + card specified by Slot. > + > + If Packet is successfully sent to the SD card, then EFI_SUCCESS is ret= urned. > + > + If a device error occurs while sending the Packet, then EFI_DEVICE_ERR= OR > is > + returned. > + > + If Slot is not in a valid range for the SD controller, then > + EFI_INVALID_PARAMETER is returned. > + > + If Packet defines a data command but both InDataBuffer and > OutDataBuffer are > + NULL, EFI_INVALID_PARAMETER is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Slot The slot number of the SD card to send t= he > + command to. > + @param[in,out] Packet A pointer to the SD command data structu= re. > + @param[in] Event If Event is NULL, blocking I/O is perfor= med. If > + Event is not NULL, then nonblocking I/O = is > + performed, and Event will be signaled wh= en the > + Packet completes. > + > + @retval EFI_SUCCESS The SD Command Packet was sent by the ho= st. > + @retval EFI_DEVICE_ERROR A device error occurred while attempting= to > send > + the SD command Packet. > + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the > Packet is > + invalid. > + @retval EFI_INVALID_PARAMETER Packet defines a data command but > both > + InDataBuffer and OutDataBuffer are NULL. > + @retval EFI_NO_MEDIA SD Device not present in the Slot. > + @retval EFI_UNSUPPORTED The command described by the SD > Command Packet > + is not supported by the host controller. > + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or > OutTransferLength > + exceeds the limit supported by SD card > + ( i.e. if the number of bytes exceed the= Last > + LBA). > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruPassThru ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN UINT8 Slot, > + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, > + IN EFI_EVENT Event OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + DW_MMC_HC_PRIVATE_DATA *Private; > + DW_MMC_HC_TRB *Trb; > + EFI_TPL OldTpl; > + > + if ((This =3D=3D NULL) || (Packet =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Packet->SdMmcCmdBlk =3D=3D NULL) || (Packet->SdMmcStatusBlk =3D= =3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Packet->OutDataBuffer =3D=3D NULL) && (Packet->OutTransferLength = !=3D > 0)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Packet->InDataBuffer =3D=3D NULL) && (Packet->InTransferLength != =3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (This); > + > + if (!Private->Slot[Slot].Enable) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!Private->Slot[Slot].MediaPresent) { > + return EFI_NO_MEDIA; > + } > + > + Trb =3D DwMmcCreateTrb (Private, Slot, Packet, Event); > + if (Trb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + // > + // Immediately return for async I/O. > + // > + if (Event !=3D NULL) { > + return EFI_SUCCESS; > + } > + > + // > + // Wait async I/O list is empty before execute sync I/O operation. > + // > + while (TRUE) { > + OldTpl =3D gBS->RaiseTPL (TPL_NOTIFY); > + if (IsListEmpty (&Private->Queue)) { > + gBS->RestoreTPL (OldTpl); > + break; > + } > + gBS->RestoreTPL (OldTpl); > + } > + > + Status =3D DwMmcWaitTrbEnv (Private, Trb); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D DwMmcExecTrb (Private, Trb); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D DwMmcWaitTrbResult (Private, Trb); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > +Done: > + if (Trb !=3D NULL) { > + DwMmcFreeTrb (Trb); > + } > + > + return Status; > +} > + > +/** > + Used to retrieve next slot numbers supported by the SD controller. The > + function returns information about all available slots (populated or > + not-populated). > + > + The GetNextSlot() function retrieves the next slot number on an SD > controller. > + If on input Slot is 0xFF, then the slot number of the first slot on th= e SD > + controller is returned. > + > + If Slot is a slot number that was returned on a previous call to > + GetNextSlot(), then the slot number of the next slot on the SD control= ler is > + returned. > + > + If Slot is not 0xFF and Slot was not returned on a previous call to > + GetNextSlot(), EFI_INVALID_PARAMETER is returned. > + > + If Slot is the slot number of the last slot on the SD controller, then > + EFI_NOT_FOUND is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMMC_PASS_THRU_PROTOCOL > + instance. > + @param[in,out] Slot On input, a pointer to a slot number on = the SD > + controller. > + On output, a pointer to the next slot nu= mber on > + the SD controller. > + An input value of 0xFF retrieves the fir= st slot > + number on the SD controller. > + > + @retval EFI_SUCCESS The next slot number on the SD controlle= r was > + returned in Slot. > + @retval EFI_NOT_FOUND There are no more slots on this SD > controller. > + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not > returned on a > + previous call to GetNextSlot(). > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruGetNextSlot ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN OUT UINT8 *Slot > + ) > +{ > + DW_MMC_HC_PRIVATE_DATA *Private; > + > + if ((This =3D=3D NULL) || (Slot =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (This); > + > + if (*Slot =3D=3D 0xFF) { > + if (Private->Slot[0].Enable) { > + *Slot =3D 0; > + Private->PreviousSlot =3D 0; > + return EFI_SUCCESS; > + } > + return EFI_NOT_FOUND; > + } else if (*Slot =3D=3D Private->PreviousSlot) { > + return EFI_NOT_FOUND; > + } else { > + return EFI_INVALID_PARAMETER; > + } > +} > + > +/** > + Used to allocate and build a device path node for an SD card on the SD > + controller. > + > + The BuildDevicePath() function allocates and builds a single device no= de > + for the SD card specified by Slot. > + > + If the SD card specified by Slot is not present on the SD controller, = then > + EFI_NOT_FOUND is returned. > + > + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. > + > + If there are not enough resources to allocate the device path node, th= en > + EFI_OUT_OF_RESOURCES is returned. > + > + Otherwise, DevicePath is allocated with the boot service AllocatePool(= ), > + the contents of DevicePath are initialized to describe the SD card spe= cified > + by Slot, and EFI_SUCCESS is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Slot Specifies the slot number of the SD card= for > + which a device path node is to be alloca= ted and > + built. > + @param[in,out] DevicePath A pointer to a single device path node t= hat > + describes the SD card specified by Slot.= This > + function is responsible for allocating t= he > + buffer DevicePath with the boot service > + AllocatePool(). It is the caller's respo= nsi- > + bility to free DevicePath when the calle= r is > + finished with DevicePath. > + > + @retval EFI_SUCCESS The device path node that describes the = SD > card > + specified by Slot was allocated and retu= rned in > + DevicePath. > + @retval EFI_NOT_FOUND The SD card specified by Slot does not e= xist > on > + the SD controller. > + @retval EFI_INVALID_PARAMETER DevicePath is NULL. > + @retval EFI_OUT_OF_RESOURCES There are not enough resources to > allocate > + DevicePath. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruBuildDevicePath ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN UINT8 Slot, > + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath > + ) > +{ > + DW_MMC_HC_PRIVATE_DATA *Private; > + SD_DEVICE_PATH *SdNode; > + EMMC_DEVICE_PATH *EmmcNode; > + > + if ((This =3D=3D NULL) || (DevicePath =3D=3D NULL) || (Slot >=3D > DW_MMC_HC_MAX_SLOT)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (This); > + > + if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresen= t)) { > + return EFI_NOT_FOUND; > + } > + > + if (Private->Slot[Slot].CardType =3D=3D SdCardType) { > + SdNode =3D AllocateCopyPool (sizeof (SD_DEVICE_PATH), > &mSdDpTemplate); > + if (SdNode =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + SdNode->SlotNumber =3D Slot; > + > + *DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *) SdNode; > + } else if (Private->Slot[Slot].CardType =3D=3D EmmcCardType) { > + EmmcNode =3D AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), > &mEmmcDpTemplate); > + if (EmmcNode =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + EmmcNode->SlotNumber =3D Slot; > + > + *DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode; > + } else { > + // > + // Currently we only support SD and EMMC two device nodes. > + // > + return EFI_NOT_FOUND; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function retrieves an SD card slot number based on the input devi= ce > path. > + > + The GetSlotNumber() function retrieves slot number for the SD card > specified > + by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER > is > + returned. > + > + If DevicePath is not a device path node type that the SD Pass Thru dri= ver > + supports, EFI_UNSUPPORTED is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] DevicePath A pointer to the device path node that > describes > + a SD card on the SD controller. > + @param[out] Slot On return, points to the slot number of = an SD > + card on the SD controller. > + > + @retval EFI_SUCCESS SD card slot number is returned in Slot. > + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL. > + @retval EFI_UNSUPPORTED DevicePath is not a device path node typ= e > that > + the SD Pass Thru driver supports. > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruGetSlotNumber ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, > + OUT UINT8 *Slot > + ) > +{ > + DW_MMC_HC_PRIVATE_DATA *Private; > + SD_DEVICE_PATH *SdNode; > + EMMC_DEVICE_PATH *EmmcNode; > + UINT8 SlotNumber; > + > + if ((This =3D=3D NULL) || (DevicePath =3D=3D NULL) || (Slot =3D=3D NUL= L)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (This); > + > + // > + // Check whether the DevicePath belongs to SD_DEVICE_PATH or > EMMC_DEVICE_PATH > + // > + if ((DevicePath->Type !=3D MESSAGING_DEVICE_PATH) || > + ((DevicePath->SubType !=3D MSG_SD_DP) && > + (DevicePath->SubType !=3D MSG_EMMC_DP)) || > + (DevicePathNodeLength(DevicePath) !=3D sizeof(SD_DEVICE_PATH)) || > + (DevicePathNodeLength(DevicePath) !=3D sizeof(EMMC_DEVICE_PATH))) > { > + return EFI_UNSUPPORTED; > + } > + > + if (DevicePath->SubType =3D=3D MSG_SD_DP) { > + SdNode =3D (SD_DEVICE_PATH *) DevicePath; > + SlotNumber =3D SdNode->SlotNumber; > + } else { > + EmmcNode =3D (EMMC_DEVICE_PATH *) DevicePath; > + SlotNumber =3D EmmcNode->SlotNumber; > + } > + > + if (SlotNumber >=3D DW_MMC_HC_MAX_SLOT) { > + return EFI_NOT_FOUND; > + } > + > + if (Private->Slot[SlotNumber].Enable) { > + *Slot =3D SlotNumber; > + return EFI_SUCCESS; > + } else { > + return EFI_NOT_FOUND; > + } > +} > + > +/** > + Resets an SD card that is connected to the SD controller. > + > + The ResetDevice() function resets the SD card specified by Slot. > + > + If this SD controller does not support a device reset operation, > + EFI_UNSUPPORTED is returned. > + > + If Slot is not in a valid slot number for this SD controller, > + EFI_INVALID_PARAMETER is returned. > + > + If the device reset operation is completed, EFI_SUCCESS is returned. > + > + @param[in] This A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Slot Specifies the slot number of the SD card= to be > + reset. > + > + @retval EFI_SUCCESS The SD card specified by Slot was reset. > + @retval EFI_UNSUPPORTED The SD controller does not support a > device > + reset operation. > + @retval EFI_INVALID_PARAMETER Slot number is invalid. > + @retval EFI_NO_MEDIA SD Device not present in the Slot. > + @retval EFI_DEVICE_ERROR The reset command failed due to a device > error > + > +**/ > +EFI_STATUS > +EFIAPI > +DwMmcPassThruResetDevice ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, > + IN UINT8 Slot > + ) > +{ > + DW_MMC_HC_PRIVATE_DATA *Private; > + LIST_ENTRY *Link; > + LIST_ENTRY *NextLink; > + DW_MMC_HC_TRB *Trb; > + EFI_TPL OldTpl; > + > + if (This =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (This); > + > + if (!Private->Slot[Slot].Enable) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!Private->Slot[Slot].MediaPresent) { > + return EFI_NO_MEDIA; > + } > + > + // > + // Free all async I/O requests in the queue > + // > + OldTpl =3D gBS->RaiseTPL (TPL_NOTIFY); > + > + for (Link =3D GetFirstNode (&Private->Queue); > + !IsNull (&Private->Queue, Link); > + Link =3D NextLink) { > + NextLink =3D GetNextNode (&Private->Queue, Link); > + RemoveEntryList (Link); > + Trb =3D DW_MMC_HC_TRB_FROM_THIS (Link); > + Trb->Packet->TransactionStatus =3D EFI_ABORTED; > + gBS->SignalEvent (Trb->Event); > + DwMmcFreeTrb (Trb); > + } > + > + gBS->RestoreTPL (OldTpl); > + > + return EFI_SUCCESS; > +} > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c > b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c > new file mode 100644 > index 000000000000..b091f9803b2e > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c > @@ -0,0 +1,1602 @@ > +/** @file > + This driver is used to manage Designware SD/MMC PCI host controllers. > + > + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer > use. > + > + Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
> + Copyright (c) 2018, Linaro Ltd. All rights reserved.
> + > + This program and the accompanying materials are licensed and made > available > + under the terms and conditions of the BSD License which accompanies th= is > + 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 > +#include > +#include > +#include > +#include > + > +#include "DwMmcHcDxe.h" > + > +/** > + Dump the content of SD/MMC host controller's Capability Register. > + > + @param[in] Slot The slot number of the SD card to send the > + command to. > + @param[in] Capability The buffer to store the capability data. > + > +**/ > +VOID > +DumpCapabilityReg ( > + IN UINT8 Slot, > + IN DW_MMC_HC_SLOT_CAP *Capability > + ) > +{ > + // > + // Dump Capability Data > + // > + DEBUG (( > + DEBUG_INFO, > + " =3D=3D Slot [%d] Capability is 0x%x =3D=3D\n", > + Slot, > + Capability > + )); > + DEBUG (( > + DEBUG_INFO, > + " Base Clk Freq %dKHz\n", > + Capability->BaseClkFreq > + )); > + DEBUG (( > + DEBUG_INFO, > + " BusWidth %d\n", > + Capability->BusWidth > + )); > + DEBUG (( > + DEBUG_INFO, > + " HighSpeed Support %a\n", > + Capability->HighSpeed ? "TRUE" : "FALSE" > + )); > + DEBUG (( > + DEBUG_INFO, > + " Voltage 1.8 %a\n", > + Capability->Voltage18 ? "TRUE" : "FALSE" > + )); > + DEBUG (( > + DEBUG_INFO, > + " 64-bit Sys Bus %a\n", > + Capability->SysBus64 ? "TRUE" : "FALSE" > + )); > + DEBUG ((DEBUG_INFO, " SlotType ")); > + if (Capability->SlotType =3D=3D 0x00) { > + DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot")); > + } else if (Capability->SlotType =3D=3D 0x01) { > + DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot")); > + } else if (Capability->SlotType =3D=3D 0x02) { > + DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot")); > + } else { > + DEBUG ((DEBUG_INFO, "%a\n", "Reserved")); > + } > + DEBUG (( > + DEBUG_INFO, > + " SDR50 Support %a\n", > + Capability->Sdr50 ? "TRUE" : "FALSE" > + )); > + DEBUG (( > + DEBUG_INFO, > + " SDR104 Support %a\n", > + Capability->Sdr104 ? "TRUE" : "FALSE" > + )); > + DEBUG (( > + DEBUG_INFO, > + " DDR50 Support %a\n", > + Capability->Ddr50 ? "TRUE" : "FALSE" > + )); > + return; > +} > + > +/** > + Set all interrupt status bits in Normal and Error Interrupt Status Ena= ble > + register. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + > + @retval EFI_SUCCESS The operation executes successfully. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +DwMmcHcEnableInterrupt ( > + UINTN DevBase > + ) > +{ > + UINT32 IntStatus; > + UINT32 IdIntEn; > + UINT32 IdSts; > + > + // > + // Enable all bits in Interrupt Mask Register > + // > + IntStatus =3D 0; > + MmioWrite32 (DevBase + DW_MMC_INTMASK, IntStatus); > + > + // > + // Clear status in Interrupt Status Register > + // > + IntStatus =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus); > + > + IdIntEn =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_IDINTEN, IdIntEn); > + > + IdSts =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_IDSTS, IdSts); > + > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +DwMmcHcGetCapability ( > + IN UINTN DevBase, > + IN EFI_HANDLE Controller, > + IN UINT8 Slot, > + OUT DW_MMC_HC_SLOT_CAP *Capacity > + ) > +{ > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; > + EFI_STATUS Status; > + > + if (Capacity =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + Status =3D gBS->LocateProtocol ( > + &gPlatformDwMmcProtocolGuid, > + NULL, > + (VOID **) &PlatformDwMmc > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + Status =3D PlatformDwMmc->GetCapability (Controller, Slot, Capacity); > + return Status; > +} > + > +/** > + Detect whether there is a SD/MMC card attached at the specified > SD/MMC host > + controller slot. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for detail= s. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command > + to. > + @param[out] MediaPresent The pointer to the media present boolean > value. > + > + @retval EFI_SUCCESS There is no media change happened. > + @retval EFI_MEDIA_CHANGED There is media change happened. > + @retval Others The detection fails. > + > +**/ > +EFI_STATUS > +DwMmcHcCardDetect ( > + IN UINTN DevBase, > + IN EFI_HANDLE Controller, > + IN UINT8 Slot, > + OUT BOOLEAN *MediaPresent > + ) > +{ > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; > + EFI_STATUS Status; > + > + if (MediaPresent =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + Status =3D gBS->LocateProtocol ( > + &gPlatformDwMmcProtocolGuid, > + NULL, > + (VOID **) &PlatformDwMmc > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + *MediaPresent =3D PlatformDwMmc->CardDetect (Controller, Slot); > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +DwMmcHcUpdateClock ( > + IN UINTN DevBase > + ) > +{ > + UINT32 Cmd; > + UINT32 IntStatus; > + > + Cmd =3D BIT_CMD_WAIT_PRVDATA_COMPLETE | > BIT_CMD_UPDATE_CLOCK_ONLY | > + BIT_CMD_START; > + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd); > + > + while (1) { > + Cmd =3D MmioRead32 (DevBase + DW_MMC_CMD); > + > + if (!(Cmd & CMD_START_BIT)) { > + break; > + } > + > + IntStatus =3D MmioRead32 (DevBase + DW_MMC_RINTSTS); > + > + if (IntStatus & DW_MMC_INT_HLE) { > + DEBUG (( > + DEBUG_ERROR, > + "DwMmcHcUpdateClock: failed to update mmc clock frequency\n" > + )); > + return EFI_DEVICE_ERROR; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Stop SD/MMC card clock. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + > + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. > + @retval Others Fail to stop SD/MMC clock. > + > +**/ > +EFI_STATUS > +DwMmcHcStopClock ( > + IN UINTN DevBase > + ) > +{ > + EFI_STATUS Status; > + UINT32 ClkEna; > + > + // > + // Disable MMC clock first > + // > + ClkEna =3D 0; > + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna); > + > + Status =3D DwMmcHcUpdateClock (DevBase); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + return Status; > +} > + > +/** > + SD/MMC card clock supply. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] ClockFreq The max clock frequency to be set. The unit = is > KHz. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The clock is supplied successfully. > + @retval Others The clock isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcClockSupply ( > + IN UINTN DevBase, > + IN UINT64 ClockFreq, > + IN DW_MMC_HC_SLOT_CAP Capability > + ) > +{ > + EFI_STATUS Status; > + UINT32 BaseClkFreq; > + UINT32 SettingFreq; > + UINT32 Divisor; > + UINT32 Remainder; > + UINT32 MmcStatus; > + UINT32 ClkEna; > + UINT32 ClkSrc; > + > + // > + // Calculate a divisor for SD clock frequency > + // > + ASSERT (Capability.BaseClkFreq !=3D 0); > + > + BaseClkFreq =3D Capability.BaseClkFreq; > + if (ClockFreq =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (ClockFreq > BaseClkFreq) { > + ClockFreq =3D BaseClkFreq; > + } > + > + // > + // Calculate the divisor of base frequency. > + // > + Divisor =3D 0; > + SettingFreq =3D BaseClkFreq; > + while (ClockFreq < SettingFreq) { > + Divisor++; > + > + SettingFreq =3D BaseClkFreq / (2 * Divisor); > + Remainder =3D BaseClkFreq % (2 * Divisor); > + if ((ClockFreq =3D=3D SettingFreq) && (Remainder =3D=3D 0)) { > + break; > + } > + if ((ClockFreq =3D=3D SettingFreq) && (Remainder !=3D 0)) { > + SettingFreq ++; > + } > + } > + > + DEBUG (( > + DEBUG_INFO, > + "BaseClkFreq %dKHz Divisor %d ClockFreq %dKhz\n", > + BaseClkFreq, > + Divisor, > + ClockFreq > + )); > + > + // > + // Wait until MMC is idle > + // > + do { > + MmcStatus =3D MmioRead32 (DevBase + DW_MMC_STATUS); > + } while (MmcStatus & DW_MMC_STS_DATA_BUSY); > + > + do { > + Status =3D DwMmcHcStopClock (DevBase); > + } while (EFI_ERROR (Status)); > + > + do { > + ClkSrc =3D 0; > + MmioWrite32 (DevBase + DW_MMC_CLKSRC, ClkSrc); > + // > + // Set clock divisor > + // > + MmioWrite32 (DevBase + DW_MMC_CLKDIV, Divisor); > + // > + // Enable MMC clock > + // > + ClkEna =3D 1; > + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna); > + > + Status =3D DwMmcHcUpdateClock (DevBase); > + } while (EFI_ERROR (Status)); > + > + return EFI_SUCCESS; > +} > + > +/** > + Set the SD/MMC bus width. > + > + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for detail= s. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] IsDdr A boolean to indicate it's dual data rate or= not. > + @param[in] BusWidth The bus width used by the SD/MMC device, it > must be > + 1, 4 or 8. > + > + @retval EFI_SUCCESS The bus width is set successfully. > + @retval Others The bus width isn't set successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcSetBusWidth ( > + IN UINTN DevBase, > + IN BOOLEAN IsDdr, > + IN UINT16 BusWidth > + ) > +{ > + UINT32 Ctype; > + UINT32 Uhs; > + > + switch (BusWidth) { > + case 1: > + Ctype =3D MMC_1BIT_MODE; > + break; > + case 4: > + Ctype =3D MMC_4BIT_MODE; > + break; > + case 8: > + Ctype =3D MMC_8BIT_MODE; > + break; > + default: > + return EFI_INVALID_PARAMETER; > + } > + MmioWrite32 (DevBase + DW_MMC_CTYPE, Ctype); > + > + Uhs =3D MmioRead32 (DevBase + DW_MMC_UHSREG); > + > + if (IsDdr) { > + Uhs |=3D UHS_DDR_MODE; > + } else { > + Uhs &=3D ~(UHS_DDR_MODE); > + } > + > + MmioWrite32 (DevBase + DW_MMC_UHSREG, Uhs); > + > + return EFI_SUCCESS; > +} > + > +/** > + Supply SD/MMC card with lowest clock frequency at initialization. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The clock is supplied successfully. > + @retval Others The clock isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitClockFreq ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ) > +{ > + EFI_STATUS Status; > + UINT32 InitFreq; > + > + // > + // Calculate a divisor for SD clock frequency > + // > + if (Capability.BaseClkFreq =3D=3D 0) { > + // > + // Don't support get Base Clock Frequency information via another > method > + // > + return EFI_UNSUPPORTED; > + } > + // > + // Supply 400KHz clock frequency at initialization phase. > + // > + InitFreq =3D DWMMC_INIT_CLOCK_FREQ; > + Status =3D DwMmcHcClockSupply (DevBase, InitFreq, Capability); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + MicroSecondDelay (100); > + return Status; > +} > + > +/** > + Supply SD/MMC card with maximum voltage at initialization. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The voltage is supplied successfully. > + @retval Others The voltage isn't supplied successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitPowerVoltage ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ) > +{ > + UINT32 Data; > + UINT32 Timeout; > + > + Data =3D 0x1; > + MmioWrite32 (DevBase + DW_MMC_PWREN, Data); > + > + Data =3D DW_MMC_CTRL_RESET_ALL; > + MmioWrite32 (DevBase + DW_MMC_CTRL, Data); > + > + Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + while (Timeout > 0) { > + Data =3D MmioRead32 (DevBase + DW_MMC_CTRL); > + > + if ((Data & DW_MMC_CTRL_RESET_ALL) =3D=3D 0) { > + break; > + } > + gBS->Stall (1); > + > + Timeout--; > + } > + > + if (Timeout <=3D 0) { > + DEBUG ((DEBUG_INFO, > + "DwMmcHcInitPowerVoltage: reset failed due to timeout")); > + > + return EFI_TIMEOUT; > + } > + > + Data =3D DW_MMC_CTRL_INT_EN; > + MmioWrite32 (DevBase + DW_MMC_CTRL, Data); > + > + return EFI_SUCCESS; > +} > + > +/** > + Initialize the Timeout Control register with most conservative value a= t > + initialization. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + > + @retval EFI_SUCCESS The timeout control register is configured > + successfully. > + @retval Others The timeout control register isn't configure= d > + successfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitTimeoutCtrl ( > + IN UINTN DevBase > + ) > +{ > + UINT32 Data; > + > + Data =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_TMOUT, Data); > + > + Data =3D 0x00FFFFFF; > + MmioWrite32 (DevBase + DW_MMC_DEBNCE, Data); > + > + return EFI_SUCCESS; > +} > + > +/** > + Initial SD/MMC host controller with lowest clock frequency, max power > and > + max timeout value at initialization. > + > + @param[in] DevIo The DEVICE IO protocol instance. > + @param[in] Slot The slot number of the SD card to send the > command > + to. > + @param[in] Capability The capability of the slot. > + > + @retval EFI_SUCCESS The host controller is initialized successfu= lly. > + @retval Others The host controller isn't initialized succes= sfully. > + > +**/ > +EFI_STATUS > +DwMmcHcInitHost ( > + IN UINTN DevBase, > + IN DW_MMC_HC_SLOT_CAP Capability > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D DwMmcHcInitPowerVoltage (DevBase, Capability); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + return Status; > +} > + > +EFI_STATUS > +DwMmcHcStartDma ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + UINTN DevBase; > + UINT32 Ctrl; > + UINT32 Bmod; > + UINT32 Timeout; > + UINT32 Data; > + > +// DevIo =3D Trb->Private->DevIo; > + DevBase =3D Trb->Private->DevBase; > + > + // > + // Reset DMA > + // > + Ctrl =3D DW_MMC_CTRL_DMA_RESET; > + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl); > + > + Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + while (Timeout > 0) { > + Data =3D MmioRead32 (DevBase + DW_MMC_CTRL); > + > + if ((Data & DW_MMC_CTRL_DMA_RESET) =3D=3D 0) { > + break; > + } > + gBS->Stall (1); > + > + Timeout--; > + } > + > + if (Timeout <=3D 0) { > + DEBUG ((DEBUG_ERROR, "Timed out waiting for CTRL_DMA_RESET")); > + > + return EFI_TIMEOUT; > + } > + > + Bmod =3D DW_MMC_IDMAC_SWRESET | MmioRead32 (DevBase + > DW_MMC_BMOD); > + > + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod); > + > + // > + // Select IDMAC > + // > + Ctrl =3D DW_MMC_CTRL_IDMAC_EN; > + Ctrl |=3D MmioRead32 (DevBase + DW_MMC_CTRL); > + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl); > + > + // > + // Enable IDMAC > + // > + Bmod =3D DW_MMC_IDMAC_ENABLE | DW_MMC_IDMAC_FB; > + Bmod |=3D MmioRead32 (DevBase + DW_MMC_BMOD); > + > + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod); > + > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +DwMmcHcStopDma ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + UINTN DevBase; > + UINT32 Ctrl; > + UINT32 Bmod; > + > + DevBase =3D Trb->Private->DevBase; > + > + // > + // Disable and reset IDMAC > + // > + Ctrl =3D MmioRead32 (DevBase + DW_MMC_CTRL); > + Ctrl &=3D ~DW_MMC_CTRL_IDMAC_EN; > + Ctrl |=3D DW_MMC_CTRL_DMA_RESET; > + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl); > + > + // > + // Stop IDMAC > + // > + Bmod =3D MmioRead32 (DevBase + DW_MMC_BMOD); > + Bmod &=3D ~(DW_MMC_BMOD_FB | DW_MMC_BMOD_DE); > + Bmod |=3D DW_MMC_BMOD_SWR; > + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod); > + > + return EFI_SUCCESS; > +} > + > +/** > + Build DMA descriptor table for transfer. > + > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The DMA descriptor table is created successf= ully. > + @retval Others The DMA descriptor table isn't created succe= ssfully. > + > +**/ > +EFI_STATUS > +BuildDmaDescTable ( > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + EFI_PHYSICAL_ADDRESS Data; > + UINT64 DataLen; > + UINT64 Entries; > + UINT32 Index; > + UINT64 Remaining; > + UINTN TableSize; > + UINTN DevBase; > + EFI_STATUS Status; > + UINTN Bytes; > + UINTN Blocks; > + DW_MMC_HC_DMA_DESC_LINE *DmaDesc; > + UINT32 DmaDescPhy; > + UINT32 Idsts; > + UINT32 BytCnt; > + UINT32 BlkSize; > + > + Data =3D Trb->DataPhy; > + DataLen =3D Trb->DataLen; > + DevBase =3D Trb->Private->DevBase; > + // > + // Only support 32bit DMA Descriptor Table > + // > + if ((Data >=3D 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) { > + return EFI_INVALID_PARAMETER; > + } > + // > + // Address field shall be set on 32-bit boundary (Lower 2-bit is alway= s set > + // to 0) for 32-bit address descriptor table. > + // > + if ((Data & (BIT0 | BIT1)) !=3D 0) { > + DEBUG (( > + DEBUG_INFO, > + "The buffer [0x%x] to construct DMA desc is not aligned to 4 bytes= !\n", > + Data > + )); > + } > + > + Entries =3D (DataLen + DWMMC_DMA_BUF_SIZE - 1) / > DWMMC_DMA_BUF_SIZE; > + TableSize =3D Entries * sizeof (DW_MMC_HC_DMA_DESC_LINE); > + Blocks =3D (DataLen + DW_MMC_BLOCK_SIZE - 1) / > DW_MMC_BLOCK_SIZE; > + > + Trb->DmaDescPages =3D (UINT32)EFI_SIZE_TO_PAGES (Entries * > DWMMC_DMA_BUF_SIZE); > +/* Status =3D DevIo->AllocateBuffer ( > + DevIo, > + AllocateAnyPages, > + EfiBootServicesData, > + EFI_SIZE_TO_PAGES (TableSize), > + (EFI_PHYSICAL_ADDRESS *)&Trb->DmaDesc > + );*/ > + Status =3D DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES > (TableSize), > + (VOID *)&Trb->DmaDesc); > + if (EFI_ERROR (Status)) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + ZeroMem (Trb->DmaDesc, TableSize); > + Bytes =3D TableSize; > + > + Status =3D DmaMap (MapOperationBusMasterCommonBuffer, > + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc, > + &Bytes, &Trb->DmaDescPhy, &Trb->DmaMap); > +/* Status =3D DevIo->Map ( > + DevIo, > + EfiBusMasterCommonBuffer, > + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc, > + &Bytes, > + &Trb->DmaDescPhy, > + &Trb->DmaMap > + );*/ > + > + if (EFI_ERROR (Status) || (Bytes !=3D TableSize)) { > + // > + // Map error or unable to map the whole RFis buffer into a contiguou= s > + // region. > + // > +/* DevIo->FreeBuffer ( > + DevIo, > + EFI_SIZE_TO_PAGES (TableSize), > + (EFI_PHYSICAL_ADDRESS)Trb->DmaDesc > + );*/ > + return EFI_OUT_OF_RESOURCES; > + } > + > + if ((UINT64)(UINTN)Trb->DmaDescPhy > 0x100000000ul) { > + // > + // The DMA doesn't support 64bit addressing. > + // > + DmaUnmap (Trb->DmaMap); > +/* DevIo->Unmap ( > + DevIo, > + Trb->DmaMap > + );*/ > + return EFI_DEVICE_ERROR; > + } > + > + if (DataLen < DW_MMC_BLOCK_SIZE) { > + BlkSize =3D DataLen; > + BytCnt =3D DataLen; > + Remaining =3D DataLen; > + } else { > + BlkSize =3D DW_MMC_BLOCK_SIZE; > + BytCnt =3D DW_MMC_BLOCK_SIZE * Blocks; > + Remaining =3D DW_MMC_BLOCK_SIZE * Blocks; > + } > + > + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize); > + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt); > + DmaDesc =3D Trb->DmaDesc; > + for (Index =3D 0; Index < Entries; Index++, DmaDesc++) { > + DmaDesc->Des0 =3D DW_MMC_IDMAC_DES0_OWN | > DW_MMC_IDMAC_DES0_CH | > + DW_MMC_IDMAC_DES0_DIC; > + DmaDesc->Des1 =3D DW_MMC_IDMAC_DES1_BS1 > (DWMMC_DMA_BUF_SIZE); > + // > + // Buffer Address > + // > + DmaDesc->Des2 =3D (UINT32)((UINTN)Trb->DataPhy + > + (DWMMC_DMA_BUF_SIZE * Index)); > + // > + // Next Descriptor Address > + // > + DmaDesc->Des3 =3D (UINT32)((UINTN)Trb->DmaDescPhy + > + sizeof (DW_MMC_HC_DMA_DESC_LINE) * (Index + 1)); > + Remaining =3D Remaining - DWMMC_DMA_BUF_SIZE; > + } > + // > + // First Descriptor > + // > + Trb->DmaDesc[0].Des0 |=3D DW_MMC_IDMAC_DES0_FS; > + // > + // Last Descriptor > + // > + Trb->DmaDesc[Entries - 1].Des0 &=3D ~(DW_MMC_IDMAC_DES0_CH | > + DW_MMC_IDMAC_DES0_DIC); > + Trb->DmaDesc[Entries - 1].Des0 |=3D DW_MMC_IDMAC_DES0_OWN | > + DW_MMC_IDMAC_DES0_LD; > + Trb->DmaDesc[Entries - 1].Des1 =3D DW_MMC_IDMAC_DES1_BS1 > (Remaining + > + DWMMC_DMA_BUF_SIZE); > + // > + // Set the next field of the Last Descriptor > + // > + Trb->DmaDesc[Entries - 1].Des3 =3D 0; > + DmaDescPhy =3D (UINT32)Trb->DmaDescPhy; > + > + MmioWrite32 (DevBase + DW_MMC_DBADDR, DmaDescPhy); > + > + ArmDataSynchronizationBarrier (); > + ArmInstructionSynchronizationBarrier (); > + // > + // Clear interrupts > + // > + Idsts =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts); > + > + return Status; > +} > + > +EFI_STATUS > +TransferFifo ( > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + UINTN DevBase; > + UINT32 Data; > + UINT32 Received; > + UINT32 Count; > + UINT32 Intsts; > + UINT32 Sts; > + UINT32 FifoCount; > + UINT32 Index; /* count with bytes */ > + UINT32 Ascending; > + UINT32 Descending; > + > + DevBase =3D Trb->Private->DevBase; > + Received =3D 0; > + Count =3D 0; > + Index =3D 0; > + Ascending =3D 0; > + Descending =3D ((Trb->DataLen + 3) & ~3) - 4; > + do { > + Intsts =3D MmioRead32 (DevBase + DW_MMC_RINTSTS); > + > + if (Trb->DataLen && (Intsts & DW_MMC_INT_TXDR) && !Trb->Read) { > + Sts =3D MmioRead32 (DevBase + DW_MMC_STATUS); > + > + while (!(DW_MMC_STS_FIFO_FULL(Sts)) > + && (Received < Trb->DataLen) > + && (Intsts & DW_MMC_INT_TXDR)) { > + if (Trb->UseBE) { > + Data =3D SwapBytes32 (*(UINT32 *)((UINTN)Trb->Data + Descendin= g)); > + Descending =3D Descending - 4; > + } else { > + Data =3D *(UINT32 *)((UINTN)Trb->Data + Ascending); > + Ascending +=3D 4; > + } > + Index +=3D 4; > + Received +=3D 4; > + > + MmioWrite32 (DevBase + DW_MMC_FIFO_START, Data); > + > + Intsts =3D DW_MMC_INT_TXDR; > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts); > + > + Intsts =3D MmioRead32 (DevBase + DW_MMC_RINTSTS); > + Sts =3D MmioRead32 (DevBase + DW_MMC_STATUS); > + } > + continue; > + } > + > + if (Trb->DataLen && ((Intsts & DW_MMC_INT_RXDR) || > + (Intsts & DW_MMC_INT_DTO)) && Trb->Read) { > + Sts =3D MmioRead32 (DevBase + DW_MMC_STATUS); > + // > + // Convert to bytes > + // > + FifoCount =3D GET_STS_FIFO_COUNT (Sts) << 2; > + if ((FifoCount =3D=3D 0) && (Received < Trb->DataLen)) { > + continue; > + } > + Index =3D 0; > + Count =3D (MIN (FifoCount, Trb->DataLen) + 3) & ~3; > + while (Index < Count) { > + Data =3D MmioRead32 (DevBase + DW_MMC_FIFO_START); > + > + if (Trb->UseBE) { > + *(UINT32 *)((UINTN)Trb->Data + Descending) =3D SwapBytes32 (Da= ta); > + Descending =3D Descending - 4; > + } else { > + *(UINT32 *)((UINTN)Trb->Data + Ascending) =3D Data; > + Ascending +=3D 4; > + } > + Index +=3D 4; > + Received +=3D 4; > + } /* while */ > + } /* if */ > + } while (((Intsts & DW_MMC_INT_CMD_DONE) =3D=3D 0) || (Received < Trb- > >DataLen)); > + // > + // Clear RINTSTS > + // > + Intsts =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts); > + return EFI_SUCCESS; > +} > + > +/** > + Create a new TRB for the SD/MMC cmd request. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Slot The slot number of the SD card to send the > command > + to. > + @param[in] Packet A pointer to the SD command data structure. > + @param[in] Event If Event is NULL, blocking I/O is performed.= If > + Event is not NULL, then nonblocking I/O is > + performed, and Event will be signaled when t= he > + Packet completes. > + > + @return Created Trb or NULL. > + > +**/ > +DW_MMC_HC_TRB * > +DwMmcCreateTrb ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN UINT8 Slot, > + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, > + IN EFI_EVENT Event > + ) > +{ > + DW_MMC_HC_TRB *Trb; > + EFI_STATUS Status; > + EFI_TPL OldTpl; > + EFI_IO_OPERATION_TYPE Flag; > + UINTN MapLength; > + > + Trb =3D AllocateZeroPool (sizeof (DW_MMC_HC_TRB)); > + if (Trb =3D=3D NULL) { > + return NULL; > + } > + > + Trb->Signature =3D DW_MMC_HC_TRB_SIG; > + Trb->Slot =3D Slot; > + Trb->BlockSize =3D 0x200; > + Trb->Packet =3D Packet; > + Trb->Event =3D Event; > + Trb->Started =3D FALSE; > + Trb->Timeout =3D Packet->Timeout; > + Trb->Private =3D Private; > + > + if ((Packet->InTransferLength !=3D 0) && (Packet->InDataBuffer !=3D NU= LL)) { > + Trb->Data =3D Packet->InDataBuffer; > + Trb->DataLen =3D Packet->InTransferLength; > + Trb->Read =3D TRUE; > + ZeroMem (Trb->Data, Trb->DataLen); > + } else if (Packet->OutTransferLength && (Packet->OutDataBuffer !=3D > NULL)) { > + Trb->Data =3D Packet->OutDataBuffer; > + Trb->DataLen =3D Packet->OutTransferLength; > + Trb->Read =3D FALSE; > + } else if (!Packet->InTransferLength && !Packet->OutTransferLength) { > + Trb->Data =3D NULL; > + Trb->DataLen =3D 0; > + } else { > + goto Error; > + } > + > + if (((Private->Slot[Trb->Slot].CardType =3D=3D EmmcCardType) && > + (Packet->SdMmcCmdBlk->CommandIndex =3D=3D > EMMC_SEND_TUNING_BLOCK)) || > + ((Private->Slot[Trb->Slot].CardType =3D=3D SdCardType) && > + (Packet->SdMmcCmdBlk->CommandIndex =3D=3D > SD_SEND_TUNING_BLOCK))) { > + Trb->Mode =3D SdMmcPioMode; > + } else { > + if (Trb->Read) { > + Flag =3D EfiBusMasterWrite; > + } else { > + Flag =3D EfiBusMasterRead; > + } > + > + if (Private->Slot[Trb->Slot].CardType =3D=3D SdCardType) { > + Trb->UseFifo =3D TRUE; > + } else { > + Trb->UseFifo =3D FALSE; > + if (Trb->DataLen) { > + MapLength =3D Trb->DataLen; > + Status =3D DmaMap (Flag, Trb->Data, &MapLength, &Trb->DataPhy, &= Trb- > >DataMap); > +/* Status =3D DevIo->Map ( > + DevIo, > + Flag, > + Trb->Data, > + &MapLength, > + &Trb->DataPhy, > + &Trb->DataMap > + );*/ > + if (EFI_ERROR (Status) || (Trb->DataLen !=3D MapLength)) { > + Status =3D EFI_BAD_BUFFER_SIZE; > + goto Error; > + } > + > + Status =3D BuildDmaDescTable (Trb); > + if (EFI_ERROR (Status)) { > + DmaUnmap(Trb->DataMap); > + goto Error; > + } > + Status =3D DwMmcHcStartDma (Private, Trb); > + if (EFI_ERROR (Status)) { > + DmaUnmap(Trb->DataMap); > + goto Error; > + } > + } > + } > + } /* TuningBlock */ > + > + if (Event !=3D NULL) { > + OldTpl =3D gBS->RaiseTPL (TPL_NOTIFY); > + InsertTailList (&Private->Queue, &Trb->TrbList); > + gBS->RestoreTPL (OldTpl); > + } > + > + return Trb; > + > +Error: > + return NULL; > +} > + > +/** > + Free the resource used by the TRB. > + > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > +**/ > +VOID > +DwMmcFreeTrb ( > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + if (Trb->DmaMap !=3D NULL) { > + DmaUnmap (Trb->DmaMap); > + } > + if (Trb->DataMap !=3D NULL) { > + DmaUnmap (Trb->DataMap); > + } > + FreePool (Trb); > +} > + > +/** > + Check if the env is ready for execute specified TRB. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The env is ready for TRB execution. > + @retval EFI_NOT_READY The env is not ready for TRB execution. > + @retval Others Some erros happen. > + > +**/ > +EFI_STATUS > +DwMmcCheckTrbEnv ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + return EFI_SUCCESS; > +} > + > +/** > + Wait for the env to be ready for execute specified TRB. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The env is ready for TRB execution. > + @retval EFI_TIMEOUT The env is not ready for TRB execution in ti= me. > + @retval Others Some erros happen. > + > +**/ > +EFI_STATUS > +DwMmcWaitTrbEnv ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + EFI_STATUS Status; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + UINT64 Timeout; > + BOOLEAN InfiniteWait; > + > + // > + // Wait Command Complete Interrupt Status bit in Normal Interrupt Stat= us > + // Register > + // > + Packet =3D Trb->Packet; > + Timeout =3D Packet->Timeout; > + if (Timeout =3D=3D 0) { > + InfiniteWait =3D TRUE; > + } else { > + InfiniteWait =3D FALSE; > + } > + > + while (InfiniteWait || (Timeout > 0)) { > + // > + // Check Trb execution result by reading Normal Interrupt Status reg= ister. > + // > + Status =3D DwMmcCheckTrbEnv (Private, Trb); > + if (Status !=3D EFI_NOT_READY) { > + return Status; > + } > + // > + // Stall for 1 microsecond. > + // > + gBS->Stall (1); > + > + Timeout--; > + } > + > + return EFI_TIMEOUT; > +} > + > +EFI_STATUS > +DwEmmcExecTrb ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + UINTN DevBase; > + UINT32 Cmd; > + UINT32 MmcStatus; > + UINT32 IntStatus; > + UINT32 Argument; > + UINT32 ErrMask; > + UINT32 Timeout; > + > + Packet =3D Trb->Packet; > + DevBase =3D Trb->Private->DevBase; > + > + ArmDataSynchronizationBarrier (); > + ArmInstructionSynchronizationBarrier (); > + // > + // Wait until MMC is idle > + // > + do { > + MmcStatus =3D MmioRead32 (DevBase + DW_MMC_STATUS); > + } while (MmcStatus & DW_MMC_STS_DATA_BUSY); > + > + IntStatus =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus); > + Cmd =3D CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex); > + if ((Packet->SdMmcCmdBlk->CommandType =3D=3D SdMmcCommandTypeAc) > || > + (Packet->SdMmcCmdBlk->CommandType =3D=3D > SdMmcCommandTypeAdtc)) { > + switch (Packet->SdMmcCmdBlk->CommandIndex) { > + case EMMC_SET_RELATIVE_ADDR: > + Cmd |=3D BIT_CMD_SEND_INIT; > + break; > + case EMMC_SEND_STATUS: > + Cmd |=3D BIT_CMD_WAIT_PRVDATA_COMPLETE; > + break; > + case EMMC_STOP_TRANSMISSION: > + Cmd |=3D BIT_CMD_STOP_ABORT_CMD; > + break; > + } > + if (Packet->InTransferLength) { > + Cmd |=3D BIT_CMD_WAIT_PRVDATA_COMPLETE | > BIT_CMD_DATA_EXPECTED | > + BIT_CMD_READ; > + } else if (Packet->OutTransferLength) { > + Cmd |=3D BIT_CMD_WAIT_PRVDATA_COMPLETE | > BIT_CMD_DATA_EXPECTED | > + BIT_CMD_WRITE; > + } > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT | > BIT_CMD_CHECK_RESPONSE_CRC; > + } else { > + switch (Packet->SdMmcCmdBlk->CommandIndex) { > + case EMMC_GO_IDLE_STATE: > + Cmd |=3D BIT_CMD_SEND_INIT; > + break; > + case EMMC_SEND_OP_COND: > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT; > + break; > + case EMMC_ALL_SEND_CID: > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE | > + BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT; > + break; > + } > + } > + switch (Packet->SdMmcCmdBlk->ResponseType) { > + case SdMmcResponseTypeR2: > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT | > BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_LONG_RESPONSE; > + break; > + case SdMmcResponseTypeR3: > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT; > + break; > + } > + Cmd |=3D BIT_CMD_USE_HOLD_REG | BIT_CMD_START; > + > + Argument =3D Packet->SdMmcCmdBlk->CommandArgument; > + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument); > + > + ArmDataSynchronizationBarrier (); > + ArmInstructionSynchronizationBarrier (); > + > + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd); > + ArmDataSynchronizationBarrier (); > + ArmInstructionSynchronizationBarrier (); > + > + ErrMask =3D DW_MMC_INT_EBE | DW_MMC_INT_HLE | > DW_MMC_INT_RTO | > + DW_MMC_INT_RCRC | DW_MMC_INT_RE; > + ErrMask |=3D DW_MMC_INT_DCRC | DW_MMC_INT_DRT | > DW_MMC_INT_SBE; > + do { > + Timeout =3D 10000; > + if (--Timeout =3D=3D 0) { > + break; > + } > + IntStatus =3D MmioRead32 (DevBase + DW_MMC_RINTSTS); > + if (IntStatus & ErrMask) { > + return EFI_DEVICE_ERROR; > + } > + if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) =3D=3D 0)) { > + // > + // Transfer Not Done > + // > + MicroSecondDelay (10); > + continue; > + } > + MicroSecondDelay (10); > + } while (!(IntStatus & DW_MMC_INT_CMD_DONE)); > + switch (Packet->SdMmcCmdBlk->ResponseType) { > + case SdMmcResponseTypeR1: > + case SdMmcResponseTypeR1b: > + case SdMmcResponseTypeR3: > + case SdMmcResponseTypeR4: > + case SdMmcResponseTypeR5: > + Packet->SdMmcStatusBlk->Resp0 =3D MmioRead32 (DevBase + > DW_MMC_RESP0); > + break; > + case SdMmcResponseTypeR2: > + Packet->SdMmcStatusBlk->Resp0 =3D MmioRead32 (DevBase + > DW_MMC_RESP0); > + Packet->SdMmcStatusBlk->Resp1 =3D MmioRead32 (DevBase + > DW_MMC_RESP1); > + Packet->SdMmcStatusBlk->Resp2 =3D MmioRead32 (DevBase + > DW_MMC_RESP2); > + Packet->SdMmcStatusBlk->Resp3 =3D MmioRead32 (DevBase + > DW_MMC_RESP3); > + break; > + } > + > + // > + // The workaround on EMMC_SEND_CSD is used to be compatible with > SDHC. > + // > + if (Packet->SdMmcCmdBlk->CommandIndex =3D=3D EMMC_SEND_CSD) { > + { > + UINT32 Buf[4]; > + ZeroMem (Buf, sizeof (Buf)); > + CopyMem ( > + (UINT8 *)Buf, > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1, > + sizeof (Buf) - 1 > + ); > + CopyMem ( > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0, > + (UINT8 *)Buf, > + sizeof (Buf) - 1 > + ); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +DwSdExecTrb ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + UINTN DevBase; > + UINT32 Cmd; > + UINT32 MmcStatus; > + UINT32 IntStatus; > + UINT32 Argument; > + UINT32 ErrMask; > + UINT32 Timeout; > + UINT32 Idsts; > + UINT32 BytCnt; > + UINT32 BlkSize; > + EFI_STATUS Status; > + > + Packet =3D Trb->Packet; > + DevBase =3D Trb->Private->DevBase; > + > + ArmDataSynchronizationBarrier (); > + ArmInstructionSynchronizationBarrier (); > + // > + // Wait until MMC is idle > + // > + do { > + MmcStatus =3D MmioRead32 (DevBase + DW_MMC_STATUS); > + } while (MmcStatus & DW_MMC_STS_DATA_BUSY); > + > + IntStatus =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus); > + Cmd =3D CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex); > + if ((Packet->SdMmcCmdBlk->CommandType =3D=3D SdMmcCommandTypeAc) > || > + (Packet->SdMmcCmdBlk->CommandType =3D=3D > SdMmcCommandTypeAdtc)) { > + switch (Packet->SdMmcCmdBlk->CommandIndex) { > + case SD_SET_RELATIVE_ADDR: > + Cmd |=3D BIT_CMD_SEND_INIT; > + break; > + case SD_STOP_TRANSMISSION: > + Cmd |=3D BIT_CMD_STOP_ABORT_CMD; > + break; > + case SD_SEND_SCR: > + Trb->UseBE =3D TRUE; > + break; > + } > + if (Packet->InTransferLength) { > + Cmd |=3D BIT_CMD_WAIT_PRVDATA_COMPLETE | > BIT_CMD_DATA_EXPECTED | > + BIT_CMD_READ; > + } else if (Packet->OutTransferLength) { > + Cmd |=3D BIT_CMD_WAIT_PRVDATA_COMPLETE | > BIT_CMD_DATA_EXPECTED | > + BIT_CMD_WRITE; > + } > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT | > BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_SEND_AUTO_STOP; > + } else { > + switch (Packet->SdMmcCmdBlk->CommandIndex) { > + case SD_GO_IDLE_STATE: > + Cmd |=3D BIT_CMD_SEND_INIT; > + break; > + } > + } > + switch (Packet->SdMmcCmdBlk->ResponseType) { > + case SdMmcResponseTypeR2: > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT | > BIT_CMD_CHECK_RESPONSE_CRC | > + BIT_CMD_LONG_RESPONSE; > + break; > + case SdMmcResponseTypeR3: > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT; > + break; > + case SdMmcResponseTypeR1b: > + case SdMmcResponseTypeR4: > + case SdMmcResponseTypeR6: > + case SdMmcResponseTypeR7: > + Cmd |=3D BIT_CMD_RESPONSE_EXPECT | > BIT_CMD_CHECK_RESPONSE_CRC; > + break; > + } > + Cmd |=3D BIT_CMD_USE_HOLD_REG | BIT_CMD_START; > + > + if (Trb->UseFifo =3D=3D TRUE) { > + BytCnt =3D Trb->Read ? Packet->InTransferLength : Packet- > >OutTransferLength; > + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt); > + if (Trb->Read) { > + if (Packet->InTransferLength > DW_MMC_BLOCK_SIZE) { > + BlkSize =3D DW_MMC_BLOCK_SIZE; > + } else { > + BlkSize =3D Packet->InTransferLength; > + } > + } > + else { > + if (Packet->OutTransferLength > DW_MMC_BLOCK_SIZE) { > + BlkSize =3D DW_MMC_BLOCK_SIZE; > + } else { > + BlkSize =3D Packet->OutTransferLength; > + } > + } > + > + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize); > + } > + > + Argument =3D Packet->SdMmcCmdBlk->CommandArgument; > + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument); > + ArmDataSynchronizationBarrier (); > + ArmInstructionSynchronizationBarrier (); > + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd); > + ArmDataSynchronizationBarrier (); > + ArmInstructionSynchronizationBarrier (); > + > + ErrMask =3D DW_MMC_INT_EBE | DW_MMC_INT_HLE | > DW_MMC_INT_RTO | > + DW_MMC_INT_RCRC | DW_MMC_INT_RE; > + ErrMask |=3D DW_MMC_INT_DRT | DW_MMC_INT_SBE; > + if (Packet->InTransferLength || Packet->OutTransferLength) { > + ErrMask |=3D DW_MMC_INT_DCRC; > + } > + if (Trb->UseFifo =3D=3D TRUE) { > + Status =3D TransferFifo (Trb); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } else { > + Timeout =3D 10000; > + do { > + if (--Timeout =3D=3D 0) { > + break; > + } > + IntStatus =3D MmioRead32 (DevBase + DW_MMC_RINTSTS); > + if (IntStatus & ErrMask) { > + return EFI_DEVICE_ERROR; > + } > + if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) =3D=3D 0)) { > + // > + // Transfer not Done > + // > + MicroSecondDelay (10); > + continue; > + } > + MicroSecondDelay (10); > + } while (!(IntStatus & DW_MMC_INT_CMD_DONE)); > + if (Packet->InTransferLength) { > + do { > + Idsts =3D MmioRead32 (DevBase + DW_MMC_IDSTS); > + } while ((Idsts & DW_MMC_IDSTS_RI) =3D=3D 0); > + Status =3D DwMmcHcStopDma (Private, Trb); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } else if (Packet->OutTransferLength) { > + do { > + Idsts =3D MmioRead32 (DevBase + DW_MMC_IDSTS); > + } while ((Idsts & DW_MMC_IDSTS_TI) =3D=3D 0); > + Status =3D DwMmcHcStopDma (Private, Trb); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } /* Packet->InTransferLength */ > + } /* UseFifo */ > + switch (Packet->SdMmcCmdBlk->ResponseType) { > + case SdMmcResponseTypeR1: > + case SdMmcResponseTypeR1b: > + case SdMmcResponseTypeR3: > + case SdMmcResponseTypeR4: > + case SdMmcResponseTypeR5: > + case SdMmcResponseTypeR6: > + case SdMmcResponseTypeR7: > + Packet->SdMmcStatusBlk->Resp0 =3D MmioRead32 (DevBase + > DW_MMC_RESP0); > + break; > + case SdMmcResponseTypeR2: > + Packet->SdMmcStatusBlk->Resp0 =3D MmioRead32 (DevBase + > DW_MMC_RESP0); > + Packet->SdMmcStatusBlk->Resp1 =3D MmioRead32 (DevBase + > DW_MMC_RESP1); > + Packet->SdMmcStatusBlk->Resp2 =3D MmioRead32 (DevBase + > DW_MMC_RESP2); > + Packet->SdMmcStatusBlk->Resp3 =3D MmioRead32 (DevBase + > DW_MMC_RESP3); > + break; > + } > + > + // > + // The workaround on SD_SEND_CSD is used to be compatible with SDHC. > + // > + if (Packet->SdMmcCmdBlk->CommandIndex =3D=3D SD_SEND_CSD) { > + { > + UINT32 Buf[4]; > + ZeroMem (Buf, sizeof (Buf)); > + CopyMem ( > + (UINT8 *)Buf, > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1, > + sizeof (Buf) - 1 > + ); > + CopyMem ( > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0, > + (UINT8 *)Buf, > + sizeof (Buf) - 1 > + ); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Execute the specified TRB. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The TRB is sent to host controller successfu= lly. > + @retval Others Some erros happen when sending this request = to the > + host controller. > + > +**/ > +EFI_STATUS > +DwMmcExecTrb ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + EFI_STATUS Status =3D EFI_SUCCESS; > + UINT32 Slot; > + > + Slot =3D Trb->Slot; > + if (Private->Slot[Slot].CardType =3D=3D EmmcCardType) { > + Status =3D DwEmmcExecTrb (Private, Trb); > + } else if (Private->Slot[Slot].CardType =3D=3D SdCardType) { > + Status =3D DwSdExecTrb (Private, Trb); > + } else { > + ASSERT (0); > + } > + return Status; > +} > + > +/** > + Check the TRB execution result. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The TRB is executed successfully. > + @retval EFI_NOT_READY The TRB is not completed for execution. > + @retval Others Some erros happen when executing this reques= t. > + > +**/ > +EFI_STATUS > +DwMmcCheckTrbResult ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + UINT32 Idsts; > + UINTN DevBase; > + > + DevBase =3D Private->DevBase; > + Packet =3D Trb->Packet; > + if (Trb->UseFifo =3D=3D TRUE) { > + return EFI_SUCCESS; > + } > + if (Packet->InTransferLength) { > + do { > + Idsts =3D MmioRead32 (DevBase + DW_MMC_IDSTS); > + } while ((Idsts & BIT1) =3D=3D 0); > + } else if (Packet->OutTransferLength) { > + do { > + Idsts =3D MmioRead32 (DevBase + DW_MMC_IDSTS); > + } while ((Idsts & BIT0) =3D=3D 0); > + } else { > + return EFI_SUCCESS; > + } > + Idsts =3D ~0; > + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts); > + > + return EFI_SUCCESS; > +} > + > +/** > + Wait for the TRB execution result. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. > + > + @retval EFI_SUCCESS The TRB is executed successfully. > + @retval Others Some erros happen when executing this reques= t. > + > +**/ > +EFI_STATUS > +DwMmcWaitTrbResult ( > + IN DW_MMC_HC_PRIVATE_DATA *Private, > + IN DW_MMC_HC_TRB *Trb > + ) > +{ > + EFI_STATUS Status; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; > + UINT64 Timeout; > + BOOLEAN InfiniteWait; > + > + Packet =3D Trb->Packet; > + // > + // Wait Command Complete Interrupt Status bit in Normal Interrupt Stat= us > + // Register > + // > + Timeout =3D Packet->Timeout; > + if (Timeout =3D=3D 0) { > + InfiniteWait =3D TRUE; > + } else { > + InfiniteWait =3D FALSE; > + } > + > + while (InfiniteWait || (Timeout > 0)) { > + // > + // Check Trb execution result by reading Normal Interrupt Status reg= ister. > + // > + Status =3D DwMmcCheckTrbResult (Private, Trb); > + if (Status !=3D EFI_NOT_READY) { > + return Status; > + } > + // > + // Stall for 1 microsecond. > + // > + gBS->Stall (1); > + > + Timeout--; > + } > + > + return EFI_TIMEOUT; > +} > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c > b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c > new file mode 100644 > index 000000000000..b7a8688c4d2e > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c > @@ -0,0 +1,1042 @@ > +/** @file > + This file provides some helper functions which are specific for EMMC > device. > + > + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.
> + Copyright (c) 2018, Linaro. All rights reserved.
> + > + This program and the accompanying materials are licensed and made > available > + under the terms and conditions of the BSD License which accompanies th= is > + 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 "DwMmcHcDxe.h" > + > +#define EMMC_GET_STATE(x) (((x) >> 9) & 0xf) > +#define EMMC_STATE_IDLE 0 > +#define EMMC_STATE_READY 1 > +#define EMMC_STATE_IDENT 2 > +#define EMMC_STATE_STBY 3 > +#define EMMC_STATE_TRAN 4 > +#define EMMC_STATE_DATA 5 > +#define EMMC_STATE_RCV 6 > +#define EMMC_STATE_PRG 7 > +#define EMMC_STATE_DIS 8 > +#define EMMC_STATE_BTST 9 > +#define EMMC_STATE_SLP 10 > + > +#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // > Capacity <=3D 2GB, byte addressing used > +#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // > Capacity > 2GB, 512-byte sector addressing used > + > +/** > + Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to > the device to > + make it go to Idle State. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Slot The slot number of the SD card to send the > command > + to. > + > + @retval EFI_SUCCESS The EMMC device is reset correctly. > + @retval Others The device reset fails. > + > +**/ > +EFI_STATUS > +EmmcReset ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_GO_IDLE_STATE; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBc; > + SdMmcCmdBlk.ResponseType =3D 0; > + SdMmcCmdBlk.CommandArgument =3D 0; > + > + gBS->Stall (1000); > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SEND_OP_COND to the EMMC device to get the data of > the OCR > + register. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in, out] Argument On input, the argument of SEND_OP_COND is > to send > + to the device. > + On output, the argument is the value of OCR > + register. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcGetOcr ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN OUT UINT32 *Argument > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SEND_OP_COND; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBcr; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR3; > + SdMmcCmdBlk.CommandArgument =3D *Argument; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (!EFI_ERROR (Status)) { > + // > + // For details, refer to SD Host Controller Simplified Spec 3.0 Tabl= e 2-12. > + // > + *Argument =3D SdMmcStatusBlk.Resp0; > + } > + > + return Status; > +} > + > +/** > + Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices > to send > + the data of their CID registers. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcGetAllCid ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_ALL_SEND_CID; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBcr; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR2; > + SdMmcCmdBlk.CommandArgument =3D 0; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SET_RELATIVE_ADDR to the EMMC device to assign a > Relative device > + Address (RCA). > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSetRca ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SET_RELATIVE_ADDR; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SEND_CSD to the EMMC device to get the data of the CSD > register. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of selected devi= ce. > + @param[out] Csd The buffer to store the content of the CSD r= egister. > + Note the caller should ignore the lowest byt= e of > + this buffer as the content of this byte is > + meaningless even if the operation succeeds. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcGetCsd ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + OUT EMMC_CSD *Csd > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SEND_CSD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR2; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (!EFI_ERROR (Status)) { > + // > + // Copy 128bit data for CSD structure. > + // > + CopyMem ((VOID *)Csd + 1, &SdMmcStatusBlk.Resp0, sizeof > (EMMC_CSD) - 1); > + } > + > + return Status; > +} > + > +/** > + Send command SELECT_DESELECT_CARD to the EMMC device to > select/deselect it. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of selected devi= ce. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSelect ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SELECT_DESELECT_CARD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SEND_EXT_CSD to the EMMC device to get the data of the > EXT_CSD > + register. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[out] ExtCsd The buffer to store the content of the EXT_C= SD > + register. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcGetExtCsd ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + OUT EMMC_EXT_CSD *ExtCsd > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SEND_EXT_CSD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAdtc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D 0x00000000; > + > + Packet.InDataBuffer =3D ExtCsd; > + Packet.InTransferLength =3D sizeof (EMMC_EXT_CSD); > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + return Status; > +} > + > +/** > + Send command SWITCH to the EMMC device to switch the mode of > operation of the > + selected Device or modifies the EXT_CSD registers. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Access The access mode of SWTICH command. > + @param[in] Index The offset of the field to be access. > + @param[in] Value The value to be set to the specified field o= f > + EXT_CSD register. > + @param[in] CmdSet The value of CmdSet field of EXT_CSD registe= r. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSwitch ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT8 Access, > + IN UINT8 Index, > + IN UINT8 Value, > + IN UINT8 CmdSet > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SWITCH; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1b; > + SdMmcCmdBlk.CommandArgument =3D (Access << 24) | (Index << 16) | \ > + (Value << 8) | CmdSet; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SEND_STATUS to the addressed EMMC device to get its > status > + register. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of addressed dev= ice. > + @param[out] DevStatus The returned device status. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSendStatus ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + OUT UINT32 *DevStatus > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SEND_STATUS; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (!EFI_ERROR (Status)) { > + *DevStatus =3D SdMmcStatusBlk.Resp0; > + } > + > + return Status; > +} > + > +/** > + Send command SEND_TUNING_BLOCK to the EMMC device for HS200 > optimal sampling > + point detection. > + > + It may be sent up to 40 times until the host finishes the tuning proce= dure. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] BusWidth The bus width to work. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSendTuningBlk ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT8 BusWidth > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + UINT8 TuningBlock[128]; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D EMMC_SEND_TUNING_BLOCK; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAdtc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D 0; > + > + Packet.InDataBuffer =3D TuningBlock; > + if (BusWidth =3D=3D 8) { > + Packet.InTransferLength =3D sizeof (TuningBlock); > + } else { > + Packet.InTransferLength =3D 64; > + } > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Tunning the clock to get HS200 optimal sampling point. > + > + Command SEND_TUNING_BLOCK may be sent up to 40 times until the > host finishes > + the tuning procedure. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. > + > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL > instance. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] BusWidth The bus width to work. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcTuningClkForHs200 ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT8 BusWidth > + ) > +{ > + return EFI_SUCCESS; > +} > + > +/** > + Switch the bus width to specified width. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9. > + > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL > instance. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + @param[in] IsDdr If TRUE, use dual data rate data simpling me= thod. > + Otherwise use single data rate data simpling= method. > + @param[in] BusWidth The bus width to be set, it could be 4 or 8. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSwitchBusWidth ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN BOOLEAN IsDdr, > + IN UINT8 BusWidth > + ) > +{ > + EFI_STATUS Status; > + UINT8 Access; > + UINT8 Index; > + UINT8 Value; > + UINT8 CmdSet; > + UINT32 DevStatus; > + > + // > + // Write Byte, the Value field is written into the byte pointed by Ind= ex. > + // > + Access =3D 0x03; > + Index =3D OFFSET_OF (EMMC_EXT_CSD, BusWidth); > + if (BusWidth =3D=3D 1) { > + Value =3D 0; > + } else { > + if (BusWidth =3D=3D 4) { > + Value =3D 1; > + } else if (BusWidth =3D=3D 8) { > + Value =3D 2; > + } else { > + return EFI_INVALID_PARAMETER; > + } > + > + if (IsDdr) { > + Value +=3D 4; > + } > + } > + > + CmdSet =3D 0; > + Status =3D EmmcSwitch (PassThru, Access, Index, Value, CmdSet); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", > + BusWidth, > + Status > + )); > + return Status; > + } > + > + do { > + Status =3D EmmcSendStatus (PassThru, Rca, &DevStatus); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "EmmcSwitchBusWidth: Send status fails with %r\n", > + Status > + )); > + return Status; > + } > + // > + // Check the switch operation is really successful or not. > + // > + } while ((DevStatus & 0xf) =3D=3D EMMC_STATE_PRG); > + > + Status =3D DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return Status; > +} > + > +/** > + Switch the clock frequency to the specified value. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6. > + > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL > instance. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + @param[in] HsTiming The value to be written to HS_TIMING field o= f > + EXT_CSD register. > + @param[in] ClockFreq The max clock frequency to be set, the unit = is > MHz. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSwitchClockFreq ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN UINT8 HsTiming, > + IN UINT32 ClockFreq > + ) > +{ > + EFI_STATUS Status; > + UINT8 Access; > + UINT8 Index; > + UINT8 Value; > + UINT8 CmdSet; > + UINT32 DevStatus; > + DW_MMC_HC_PRIVATE_DATA *Private; > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); > + // > + // Write Byte, the Value field is written into the byte pointed by Ind= ex. > + // > + Access =3D 0x03; > + Index =3D OFFSET_OF (EMMC_EXT_CSD, HsTiming); > + Value =3D HsTiming; > + CmdSet =3D 0; > + > + Status =3D EmmcSwitch (PassThru, Access, Index, Value, CmdSet); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n", > + HsTiming, > + Status > + )); > + return Status; > + } > + > + Status =3D EmmcSendStatus (PassThru, Rca, &DevStatus); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "EmmcSwitchClockFreq: Send status fails with %r\n", > + Status > + )); > + return Status; > + } > + // > + // Check the switch operation is really successful or not. > + // > + if ((DevStatus & BIT7) !=3D 0) { > + DEBUG (( > + DEBUG_ERROR, > + "EmmcSwitchClockFreq: The switch operation fails as DevStatus > 0x%08x\n", > + DevStatus > + )); > + return EFI_DEVICE_ERROR; > + } > + // > + // Convert the clock freq unit from MHz to KHz. > + // > + Status =3D DwMmcHcClockSupply (DevBase, ClockFreq * 1000, Private- > >Capability[0]); > + > + return Status; > +} > + > +/** > + Switch to the High Speed timing according to request. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. > + > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL > instance. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + @param[in] ClockFreq The max clock frequency to be set. > + @param[in] IsDdr If TRUE, use dual data rate data simpling me= thod. > + Otherwise use single data rate data simpling= method. > + @param[in] BusWidth The bus width to be set, it could be 4 or 8. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSwitchToHighSpeed ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN UINT32 ClockFreq, > + IN BOOLEAN IsDdr, > + IN UINT8 BusWidth > + ) > +{ > + EFI_STATUS Status; > + UINT8 HsTiming; > + > + HsTiming =3D 1; > + Status =3D EmmcSwitchClockFreq (DevBase, PassThru, Rca, HsTiming, > ClockFreq); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + Status =3D EmmcSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, BusWidth= ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + return EFI_SUCCESS; > +} > + > +/** > + Switch to the HS200 timing according to request. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. > + > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL > instance. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + @param[in] ClockFreq The max clock frequency to be set. > + @param[in] BusWidth The bus width to be set, it could be 4 or 8. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSwitchToHS200 ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN UINT32 ClockFreq, > + IN UINT8 BusWidth > + ) > +{ > + return EFI_SUCCESS; > +} > + > +/** > + Switch the high speed timing according to request. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. > + > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL > instance. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +EmmcSetBusMode ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca > + ) > +{ > + EFI_STATUS Status; > + EMMC_CSD Csd; > + EMMC_EXT_CSD ExtCsd; > + UINT8 HsTiming; > + BOOLEAN IsDdr; > + UINT32 DevStatus; > + UINT32 ClockFreq; > + UINT8 BusWidth; > + DW_MMC_HC_PRIVATE_DATA *Private; > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); > + ASSERT (Private->Capability[0].BaseClkFreq !=3D 0); > + > + Status =3D EmmcGetCsd (PassThru, Rca, &Csd); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", > Status)); > + return Status; > + } > + > + Status =3D EmmcSelect (PassThru, Rca); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", > Status)); > + return Status; > + } > + > + do { > + Status =3D EmmcSendStatus (PassThru, Rca, &DevStatus); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "EmmcSetBusMode: Get Status fails with %r\n", > + Status > + )); > + return Status; > + } > + } while (EMMC_GET_STATE (DevStatus) !=3D EMMC_STATE_TRAN); > + > + BusWidth =3D 1; > + Status =3D EmmcSwitchBusWidth (DevBase, PassThru, Rca, FALSE, > BusWidth); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + BusWidth =3D Private->Capability[0].BusWidth; > + // > + // Get Deivce_Type from EXT_CSD register. > + // > + Status =3D EmmcGetExtCsd (PassThru, &ExtCsd); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", > Status)); > + return Status; > + } > + > + // > + // Calculate supported bus speed/bus width/clock frequency. > + // > + HsTiming =3D 0; > + IsDdr =3D FALSE; > + ClockFreq =3D 0; > + if (((ExtCsd.DeviceType & (BIT4 | BIT5)) !=3D 0) && > + (Private->Capability[0].Sdr104 !=3D 0)) { > + HsTiming =3D 2; > + IsDdr =3D FALSE; > + ClockFreq =3D 200; > + } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) !=3D 0) && > + (Private->Capability[0].Ddr50 !=3D 0)) { > + HsTiming =3D 1; > + IsDdr =3D TRUE; > + ClockFreq =3D 52; > + } else if (((ExtCsd.DeviceType & BIT1) !=3D 0) && > + (Private->Capability[0].HighSpeed !=3D 0)) { > + HsTiming =3D 1; > + IsDdr =3D FALSE; > + ClockFreq =3D 52; > + } else if (((ExtCsd.DeviceType & BIT0) !=3D 0) && > + (Private->Capability[0].HighSpeed !=3D 0)) { > + HsTiming =3D 1; > + IsDdr =3D FALSE; > + ClockFreq =3D 26; > + } > + > + if ((ClockFreq =3D=3D 0) || (HsTiming =3D=3D 0)) { > + // > + // Continue using default setting. > + // > + return EFI_SUCCESS; > + } > + > + DEBUG (( > + DEBUG_INFO, > + "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", > + HsTiming, > + ClockFreq, > + BusWidth, > + IsDdr ? "TRUE" : "FALSE" > + )); > + > + if (HsTiming =3D=3D 2) { > + // > + // Execute HS200 timing switch procedure > + // > + Status =3D EmmcSwitchToHS200 (DevBase, PassThru, Rca, ClockFreq, > BusWidth); > + } else { > + // > + // Execute High Speed timing switch procedure > + // > + Status =3D EmmcSwitchToHighSpeed ( > + DevBase, > + PassThru, > + Rca, > + ClockFreq, > + IsDdr, > + BusWidth > + ); > + } > + > + DEBUG (( > + DEBUG_INFO, > + "EmmcSetBusMode: Switch to %a %r\n", > + (HsTiming =3D=3D 3) ? "HS400" : ((HsTiming =3D=3D 2) ? "HS200" : "Hi= ghSpeed"), > + Status > + )); > + > + return Status; > +} > + > +/** > + Execute EMMC device identification procedure. > + > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. > + > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA > instance. > + > + @retval EFI_SUCCESS There is a EMMC card. > + @retval Others There is not a EMMC card. > + > +**/ > +EFI_STATUS > +EmmcIdentification ( > + IN DW_MMC_HC_PRIVATE_DATA *Private > + ) > +{ > + EFI_STATUS Status; > + UINTN DevBase; > + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; > + UINT32 Ocr; > + UINT16 Rca; > + UINT32 DevStatus; > + UINT32 Timeout; > + > + DevBase =3D Private->DevBase; > + PassThru =3D &Private->PassThru; > + > + Status =3D EmmcReset (PassThru); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "EmmcIdentification: Executing Cmd0 fails with %r\n", > + Status > + )); > + return Status; > + } > + > + Timeout =3D 100; > + do { > + Ocr =3D EMMC_CMD1_CAPACITY_GREATER_THAN_2GB; > + Status =3D EmmcGetOcr (PassThru, &Ocr); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "EmmcIdentification: Executing Cmd1 fails with %r\n", > + Status > + )); > + return Status; > + } > + if (--Timeout <=3D 0) { > + return EFI_DEVICE_ERROR; > + } > + MicroSecondDelay (100); > + } while ((Ocr & BIT31) =3D=3D 0); > + > + Status =3D EmmcGetAllCid (PassThru); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "EmmcIdentification: Executing Cmd2 fails with %r\n", > + Status > + )); > + return Status; > + } > + // > + // valid RCA starts from 1. > + // Here we takes a simple formula to calculate the RCA. > + // Don't support multiple devices on the slot, that is > + // shared bus slot feature. > + // > + Rca =3D 1; > + Status =3D EmmcSetRca (PassThru, Rca); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "EmmcIdentification: Executing Cmd3 fails with %r\n", > + Status > + )); > + return Status; > + } > + // > + // Enter Data Tranfer Mode. > + // > + DEBUG (( > + DEBUG_INFO, > + "EmmcIdentification: Found a EMMC device at RCA [%d]\n", > + Rca > + )); > + Private->Slot[0].CardType =3D EmmcCardType; > + > + Status =3D EmmcSetBusMode (DevBase, PassThru, Rca); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Exit DATA Mode. > + // > + do { > + Status =3D EmmcSendStatus (PassThru, Rca, &DevStatus); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "EmmcSwitchBusWidth: Send status fails with %r\n", > + Status > + )); > + return Status; > + } > + } while ((DevStatus & 0xf) =3D=3D EMMC_STATE_DATA); > + > + return Status; > +} > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c > b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c > new file mode 100644 > index 000000000000..63246637b6dd > --- /dev/null > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c > @@ -0,0 +1,1105 @@ > +/** @file > + This file provides some helper functions which are specific for SD car= d > + device. > + > + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.
> + Copyright (c) 2018, Linaro. All rights reserved.
> + > + This program and the accompanying materials are licensed and made > available > + under the terms and conditions of the BSD License which accompanies th= is > + 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 "DwMmcHcDxe.h" > + > +/** > + Send command GO_IDLE_STATE to the device to make it go to Idle State. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + > + @retval EFI_SUCCESS The SD device is reset correctly. > + @retval Others The device reset fails. > + > +**/ > +EFI_STATUS > +SdCardReset ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_GO_IDLE_STATE; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBc; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + //Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SEND_IF_COND to the device to inquiry the SD Memory > Card > + interface condition. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] SupplyVoltage The supplied voltage by the host. > + @param[in] CheckPattern The check pattern to be sent to the device. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardVoltageCheck ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT8 SupplyVoltage, > + IN UINT8 CheckPattern > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_SEND_IF_COND; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBcr; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR7; > + SdMmcCmdBlk.CommandArgument =3D (SupplyVoltage << 8) | > CheckPattern; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + if (!EFI_ERROR (Status)) { > + if (SdMmcStatusBlk.Resp0 !=3D SdMmcCmdBlk.CommandArgument) { > + return EFI_DEVICE_ERROR; > + } > + } > + > + return Status; > +} > + > +/** > + Send command SDIO_SEND_OP_COND to the device to see whether it is > SDIO device. > + > + Refer to SDIO Simplified Spec 3 Section 3.2 for details. > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] VoltageWindow The supply voltage window. > + @param[in] S18R The boolean to show if it should switch to 1= .8v. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdioSendOpCond ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT32 VoltageWindow, > + IN BOOLEAN S18R > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + UINT32 Switch; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SDIO_SEND_OP_COND; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBcr; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR4; > + > + Switch =3D S18R ? BIT24 : 0; > + > + SdMmcCmdBlk.CommandArgument =3D (VoltageWindow & 0xFFFFFF) | > Switch; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SD_SEND_OP_COND to the device to see whether it is > SDIO device. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of addressed de= vice. > + @param[in] VoltageWindow The supply voltage window. > + @param[in] S18R The boolean to show if it should switch to = 1.8v. > + @param[in] Xpc The boolean to show if it should provide 0.= 36w > + power control. > + @param[in] Hcs The boolean to show if it support host capa= city > + info. > + @param[out] Ocr The buffer to store returned OCR register v= alue. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSendOpCond ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN UINT32 VoltageWindow, > + IN BOOLEAN S18R, > + IN BOOLEAN Xpc, > + IN BOOLEAN Hcs, > + OUT UINT32 *Ocr > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + UINT32 Switch; > + UINT32 MaxPower; > + UINT32 HostCapacity; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_APP_CMD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + SdMmcCmdBlk.CommandIndex =3D SD_SEND_OP_COND; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBcr; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR3; > + > + Switch =3D S18R ? BIT24 : 0; > + MaxPower =3D Xpc ? BIT28 : 0; > + HostCapacity =3D Hcs ? BIT30 : 0; > + > + SdMmcCmdBlk.CommandArgument =3D (VoltageWindow & 0xFFFFFF) | > Switch | \ > + MaxPower | HostCapacity; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (!EFI_ERROR (Status)) { > + *Ocr =3D SdMmcStatusBlk.Resp0; > + } > + > + return Status; > +} > + > +/** > + Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to > send > + the data of their CID registers. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardAllSendCid ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_ALL_SEND_CID; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBcr; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR2; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SET_RELATIVE_ADDR to the SD device to assign a Relative > device > + Address (RCA). > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[out] Rca The relative device address to assign. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSetRca ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + OUT UINT16 *Rca > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_SET_RELATIVE_ADDR; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeBcr; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR6; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (!EFI_ERROR (Status)) { > + *Rca =3D (UINT16)(SdMmcStatusBlk.Resp0 >> 16); > + } > + > + return Status; > +} > + > +/** > + Send command SEND_CSD to the SD device to get the data of the CSD > register. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of selected devi= ce. > + @param[out] Csd The buffer to store the content of the CSD r= egister. > + Note the caller should ignore the lowest byt= e of > + this buffer as the content of this byte is m= eaning- > + less even if the operation succeeds. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardGetCsd ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + OUT SD_CSD *Csd > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_SEND_CSD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR2; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (!EFI_ERROR (Status)) { > + CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) > - 1); > + } > + > + return Status; > +} > + > +/** > + Send command SEND_CSD to the SD device to get the data of the CSD > register. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of selected devi= ce. > + @param[out] Scr The buffer to store the content of the SCR r= egister. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardGetScr ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + OUT SD_SCR *Scr > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_APP_CMD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + SdMmcCmdBlk.CommandIndex =3D SD_SEND_SCR; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAdtc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + > + Packet.InDataBuffer =3D Scr; > + Packet.InTransferLength =3D sizeof (SD_SCR); > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SELECT_DESELECT_CARD to the SD device to > select/deselect it. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of selected devi= ce. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSelect ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_SELECT_DESELECT_CARD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + if (Rca !=3D 0) { > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1b; > + } > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command VOLTAGE_SWITCH to the SD device to switch the voltage > of the > + device. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardVoltageSwitch ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_VOLTAGE_SWITCH; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D 0; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SET_BUS_WIDTH to the SD device to set the bus width. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of addressed dev= ice. > + @param[in] BusWidth The bus width to be set, it could be 1 or 4. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSetBusWidth ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN UINT8 BusWidth > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + UINT8 Value; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_APP_CMD; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + SdMmcCmdBlk.CommandIndex =3D SD_SET_BUS_WIDTH; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + > + if (BusWidth =3D=3D 1) { > + Value =3D 0; > + } else if (BusWidth =3D=3D 4) { > + Value =3D 2; > + } else { > + return EFI_INVALID_PARAMETER; > + } > + > + SdMmcCmdBlk.CommandArgument =3D Value & 0x3; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + return Status; > +} > + > +/** > + Send command SWITCH_FUNC to the SD device to check switchable > function or > + switch card function. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] AccessMode The value for access mode group. > + @param[in] CommandSystem The value for command set group. > + @param[in] DriveStrength The value for drive length group. > + @param[in] PowerLimit The value for power limit group. > + @param[in] Mode Switch or check function. > + @param[out] SwitchResp The return switch function status. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSwitch ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT8 AccessMode, > + IN UINT8 CommandSystem, > + IN UINT8 DriveStrength, > + IN UINT8 PowerLimit, > + IN BOOLEAN Mode, > + OUT UINT8 *SwitchResp > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + UINT32 ModeValue; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_SWITCH_FUNC; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAdtc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + > + ModeValue =3D Mode ? BIT31 : 0; > + SdMmcCmdBlk.CommandArgument =3D (AccessMode & 0xF) | \ > + ((PowerLimit & 0xF) << 4) | \ > + ((DriveStrength & 0xF) << 8) | \ > + ((DriveStrength & 0xF) << 12) | \ > + ModeValue; > + > + Packet.InDataBuffer =3D SwitchResp; > + Packet.InTransferLength =3D 64; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Send command SEND_STATUS to the addressed SD device to get its status > + register. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address of addressed dev= ice. > + @param[out] DevStatus The returned device status. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSendStatus ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + OUT UINT32 *DevStatus > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_SEND_STATUS; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D (UINT32)Rca << 16; > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + if (!EFI_ERROR (Status)) { > + *DevStatus =3D SdMmcStatusBlk.Resp0; > + } > + > + return Status; > +} > + > +/** > + Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal > sampling > + point detection. > + > + It may be sent up to 40 times until the host finishes the tuning proce= dure. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSendTuningBlk ( > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru > + ) > +{ > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; > + EFI_STATUS Status; > + UINT8 TuningBlock[64]; > + > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); > + ZeroMem (&Packet, sizeof (Packet)); > + > + Packet.SdMmcCmdBlk =3D &SdMmcCmdBlk; > + Packet.SdMmcStatusBlk =3D &SdMmcStatusBlk; > + Packet.Timeout =3D DW_MMC_HC_GENERIC_TIMEOUT; > + > + SdMmcCmdBlk.CommandIndex =3D SD_SEND_TUNING_BLOCK; > + SdMmcCmdBlk.CommandType =3D SdMmcCommandTypeAdtc; > + SdMmcCmdBlk.ResponseType =3D SdMmcResponseTypeR1; > + SdMmcCmdBlk.CommandArgument =3D 0; > + > + Packet.InDataBuffer =3D TuningBlock; > + Packet.InTransferLength =3D sizeof (TuningBlock); > + > + Status =3D PassThru->PassThru (PassThru, 0, &Packet, NULL); > + > + return Status; > +} > + > +/** > + Switch the bus width to specified width. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and > + SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details. > + > + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instanc= e. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + @param[in] BusWidth The bus width to be set, it could be 4 or 8. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSwitchBusWidth ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN BOOLEAN IsDdr, > + IN UINT8 BusWidth > + ) > +{ > + EFI_STATUS Status; > + UINT32 DevStatus; > + > + Status =3D SdCardSetBusWidth (PassThru, Rca, BusWidth); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", > + BusWidth, > + Status > + )); > + return Status; > + } > + > + Status =3D SdCardSendStatus (PassThru, Rca, &DevStatus); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardSwitchBusWidth: Send status fails with %r\n", > + Status > + )); > + return Status; > + } > + // > + // Check the switch operation is really successful or not. > + // > + if ((DevStatus >> 16) !=3D 0) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardSwitchBusWidth: The switch operation fails as DevStatus > 0x%08x\n", > + DevStatus > + )); > + return EFI_DEVICE_ERROR; > + } > + > + Status =3D DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth); > + > + return Status; > +} > + > +/** > + Switch the high speed timing according to request. > + > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details= . > + > + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instanc= e. > + @param[in] PassThru A pointer to the > EFI_SD_MMC_PASS_THRU_PROTOCOL > + instance. > + @param[in] Rca The relative device address to be assigned. > + @param[in] S18A The boolean to show if it's a UHS-I SD card. > + @param[in] BusWidths The bus width of the SD card. > + > + @retval EFI_SUCCESS The operation is done correctly. > + @retval Others The operation fails. > + > +**/ > +EFI_STATUS > +SdCardSetBusMode ( > + IN UINTN DevBase, > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, > + IN UINT16 Rca, > + IN BOOLEAN S18A, > + IN UINT32 BusWidths > + ) > +{ > + EFI_STATUS Status; > + DW_MMC_HC_SLOT_CAP *Capability; > + UINT32 ClockFreq; > + UINT8 AccessMode; > + UINT8 SwitchResp[64]; > + DW_MMC_HC_PRIVATE_DATA *Private; > + BOOLEAN IsDdr; > + > + Private =3D DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); > + > + Capability =3D &Private->Capability[0]; > + > + if ((Capability->BusWidth =3D=3D 1) || (Capability->BusWidth =3D=3D 4)= ) { > + BusWidths &=3D Capability[0].BusWidth; > + } else { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardSetBusMode: BusWidths (%d) in capability are wrong\n", > + Capability->BusWidth > + )); > + return EFI_INVALID_PARAMETER; > + } > + > + if (BusWidths =3D=3D 0) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardSetBusMode: Get wrong BusWidths:%d\n", > + BusWidths > + )); > + return EFI_INVALID_PARAMETER; > + } > + > + if (Private->Capability[0].Ddr50) { > + IsDdr =3D TRUE; > + } else { > + IsDdr =3D FALSE; > + } > + > + Status =3D SdCardSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, > BusWidths); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardSetBusMode: Executing SdCardSwitchBusWidth fails with %r\n"= , > + Status > + )); > + return Status; > + } > + > + // > + // Get the supported bus speed from SWITCH cmd return data group #1. > + // > + Status =3D SdCardSwitch (PassThru, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchRe= sp); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Calculate supported bus speed/bus width/clock frequency by host and > device > + // capability. > + // > + ClockFreq =3D 0; > + if (S18A && (Capability->Sdr104 !=3D 0) && ((SwitchResp[13] & BIT3) != =3D 0)) { > + ClockFreq =3D 208; > + AccessMode =3D 3; > + } else if (S18A && (Capability->Sdr50 !=3D 0) && > + ((SwitchResp[13] & BIT2) !=3D 0)) { > + ClockFreq =3D 100; > + AccessMode =3D 2; > + } else if (S18A && (Capability->Ddr50 !=3D 0) && > + ((SwitchResp[13] & BIT4) !=3D 0)) { > + ClockFreq =3D 50; > + AccessMode =3D 4; > + } else if ((SwitchResp[13] & BIT1) !=3D 0) { > + ClockFreq =3D 50; > + AccessMode =3D 1; > + } else { > + ClockFreq =3D 25; > + AccessMode =3D 0; > + } > + > + Status =3D SdCardSwitch (PassThru, AccessMode, 0xF, 0xF, 0xF, TRUE, > SwitchResp); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + if ((SwitchResp[16] & 0xF) !=3D AccessMode) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d fails! The > Switch response is 0x%1x\n", > + AccessMode, > + ClockFreq, > + SwitchResp[16] & 0xF > + )); > + return EFI_DEVICE_ERROR; > + } > + > + DEBUG (( > + DEBUG_INFO, > + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d \n", > + AccessMode, > + ClockFreq > + )); > + > + Status =3D DwMmcHcClockSupply (DevBase, ClockFreq * 1000, *Capability)= ; > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return Status; > +} > + > +EFI_STATUS > +SdCardIdentification ( > + IN DW_MMC_HC_PRIVATE_DATA *Private > + ) > +{ > + EFI_STATUS Status; > + UINTN DevBase; > + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; > + UINT32 Ocr; > + UINT16 Rca; > + BOOLEAN Xpc; > + BOOLEAN S18r; > + UINT64 MaxCurrent; > + SD_SCR Scr; > + SD_CSD Csd; > + > + DevBase =3D Private->DevBase; > + PassThru =3D &Private->PassThru; > + // > + // 1. Send Cmd0 to the device > + // > + Status =3D SdCardReset (PassThru); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "SdCardIdentification: Executing Cmd0 fails with %r\n", > + Status > + )); > + return Status; > + } > + MicroSecondDelay (10000); > + // > + // 2. Send Cmd8 to the device > + // > + Status =3D SdCardVoltageCheck (PassThru, 0x1, 0xFF); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "SdCardIdentification: Executing Cmd8 fails with %r\n", > + Status > + )); > + return Status; > + } > + // > + // 3. Send Acmd41 with voltage window 0 to the device > + // > + Status =3D SdCardSendOpCond (PassThru, 0, 0, FALSE, FALSE, FALSE, &Ocr= ); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n"= , > + Status > + )); > + return EFI_DEVICE_ERROR; > + } > + > + if (Private->Capability[0].Voltage33 !=3D 0) { > + // > + // Support 3.3V > + // > + MaxCurrent =3D ((UINT32)Private->MaxCurrent[0] & 0xFF) * 4; > + S18r =3D FALSE; > + } else if (Private->Capability[0].Voltage30 !=3D 0) { > + // > + // Support 3.0V > + // > + MaxCurrent =3D (((UINT32)Private->MaxCurrent[0] >> 8) & 0xFF) * 4; > + S18r =3D FALSE; > + } else if (Private->Capability[0].Voltage18 !=3D 0) { > + // > + // Support 1.8V > + // > + MaxCurrent =3D (((UINT32)Private->MaxCurrent[0] >> 16) & 0xFF) * 4; > + S18r =3D TRUE; > + } else { > + ASSERT (FALSE); > + return EFI_DEVICE_ERROR; > + } > + > + if (MaxCurrent >=3D 150) { > + Xpc =3D TRUE; > + } else { > + Xpc =3D FALSE; > + } > + > + // > + // 4. Repeatly send Acmd41 with supply voltage window to the device. > + // Note here we only support the cards complied with SD physical > + // layer simplified spec version 2.0 and version 3.0 and above. > + // > + do { > + Status =3D SdCardSendOpCond (PassThru, 0, Ocr, S18r, Xpc, TRUE, &Ocr= ); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S1= 8r > %x, Xpc %x\n", > + Status, > + Ocr, > + S18r, > + Xpc > + )); > + return EFI_DEVICE_ERROR; > + } > + } while ((Ocr & BIT31) =3D=3D 0); > + > + Status =3D SdCardAllSendCid (PassThru); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n"= , > + Status > + )); > + return Status; > + } > + > + Status =3D SdCardSetRca (PassThru, &Rca); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardIdentification: Executing SdCardSetRca fails with %r\n", > + Status > + )); > + return Status; > + } > + > + Status =3D SdCardGetCsd (PassThru, Rca, &Csd); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardIdentification: Executing SdCardGetCsd fails with %r\n", > + Status > + )); > + return Status; > + } > + > + Status =3D SdCardSelect (PassThru, Rca); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardIdentification: Selecting card fails with %r\n", > + Status > + )); > + return Status; > + } > + > + Status =3D SdCardGetScr (PassThru, Rca, &Scr); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "SdCardIdentification: Executing SdCardGetScr fails with %r\n", > + Status > + )); > + return Status; > + } > + > + // > + // Enter Data Tranfer Mode. > + // > + DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device\n")); > + Private->Slot[0].CardType =3D SdCardType; > + > + Status =3D SdCardSetBusMode (DevBase, PassThru, Rca, S18r, > Scr.SdBusWidths); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Private->Slot[0].Initialized =3D TRUE; > + > + return Status; > +} > -- > 2.12.3