From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM11-CO1-obe.outbound.protection.outlook.com (NAM11-CO1-obe.outbound.protection.outlook.com [40.107.220.134]) by mx.groups.io with SMTP id smtpd.web10.9739.1637167785254487283 for ; Wed, 17 Nov 2021 08:49:45 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@os.amperecomputing.com header.s=selector2 header.b=Y6n5Q59Z; spf=pass (domain: os.amperecomputing.com, ip: 40.107.220.134, mailfrom: nhi@os.amperecomputing.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=JaNGQcMrDuY409gCp5ph97DzgJvTi43hS94fDX1gpqnbmBPD9IpQ7wxEuv5/wfvykLX9efRnp2N1cD3sFavC7vS2KGip3s4/0s+a48ug9Op23TZ5ToFrQfm0yrBxMG0EeHX+hD+0n4mN8xIPRSMmyaDS9MvkJ6wx0xM7J/8IkzaifYlsLWmj5kyUkxm/2urwYFihA26JwgA592srNqNBcwpAw91Zs4++w52MQ+hn2m2AblHsKxGNp9enTtbQmx9bNdFGisImtJkI0g3Setqb8kCFfal9U/VO7zMgGQvRs7BUD8hfXtsUn4wM9GkPIETtYoe7Zd0pRIcNjGG7cDJMUw== 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-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=PA3RTErQOtQ0ARiiaS6tUC4U8UgkqnVOoRxc1eF3PEY=; b=KFPWzIqB2do9+G6d3k6/6hOKTZmFQgNvlCmu8JzBHMecuOi1CRxApQ3eQuk2tIzF3cE18USOKVx/CkpI3sEqBZ9sQVbG+Zape8s+t86ukQJQud0BxZXmtIP7QoiWs1sZmQyMbo8WvFh+Jvv64JzBHY6+rGXy2I42scAq1y0OFPMu0F5G/OG/xXsZTtl3P8MR5Ihpb4lwiP1JElm+ARh2daY79wGOiOi2FnGVfrVjgX9VncxQTJ2yY1XuAldP2DbzagnhFGwVsGnnuKY/9GL37d32nv3FlNX76Zoi+Ejz2vWqeodNxdtOe5GHkcScmYoys3u21zcCLpHRLdJpD671Nw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=os.amperecomputing.com; dmarc=pass action=none header.from=os.amperecomputing.com; dkim=pass header.d=os.amperecomputing.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=PA3RTErQOtQ0ARiiaS6tUC4U8UgkqnVOoRxc1eF3PEY=; b=Y6n5Q59ZlBq88Ly9+Lbrmx6htYJbHK8QzvguM5rgAa3cJnq2t25WjgNwxBMfxFZmencBNSGNCtPxzzUdhXO36olsyTa5sF+KdwqCFSZDsOgFnre4fI3eKEYDSHbQnY3hx6/vLoFRx8SimYUPL9e6K+FnplSleg4ZdY/CbsTLrnU= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=os.amperecomputing.com; Received: from PH0PR01MB7287.prod.exchangelabs.com (2603:10b6:510:10a::21) by PH0PR01MB6454.prod.exchangelabs.com (2603:10b6:510:1b::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4713.20; Wed, 17 Nov 2021 16:49:43 +0000 Received: from PH0PR01MB7287.prod.exchangelabs.com ([fe80::254c:9533:7f35:aee]) by PH0PR01MB7287.prod.exchangelabs.com ([fe80::254c:9533:7f35:aee%4]) with mapi id 15.20.4713.019; Wed, 17 Nov 2021 16:49:43 +0000 From: "Nhi Pham" To: devel@edk2.groups.io CC: patches@amperecomputing.com, nhi@os.amperecomputing.com, vunguyen@os.amperecomputing.com, Thang Nguyen , Chuong Tran , Phong Vo , Leif Lindholm , Michael D Kinney , Ard Biesheuvel , Nate DeSimone Subject: [edk2-platforms][PATCH v5 03/30] AmpereAltraPkg: Add DwI2cLib library instance Date: Wed, 17 Nov 2021 23:47:00 +0700 Message-ID: <20211117164727.10922-4-nhi@os.amperecomputing.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211117164727.10922-1-nhi@os.amperecomputing.com> References: <20211117164727.10922-1-nhi@os.amperecomputing.com> X-ClientProxiedBy: HKAPR04CA0001.apcprd04.prod.outlook.com (2603:1096:203:d0::11) To PH0PR01MB7287.prod.exchangelabs.com (2603:10b6:510:10a::21) Return-Path: nhi@os.amperecomputing.com MIME-Version: 1.0 Received: from sw004.amperecomputing.com (118.69.219.201) by HKAPR04CA0001.apcprd04.prod.outlook.com (2603:1096:203:d0::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4713.21 via Frontend Transport; Wed, 17 Nov 2021 16:49:40 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: d6589372-15c9-455d-6293-08d9a9ea4151 X-MS-TrafficTypeDiagnostic: PH0PR01MB6454: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:5797; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: lzpI47C71PZHk1+xdH9S5txeZuHs7KiYUcIC6lZnluR6+YPtMOPn8YCILgRk9y8gPftKsY5vTv4a4QmXWyU6MU7cGnPEIrfDt6LPVlvm0XXcFsdD88A7XCdbaHQKEx5Dm8o8hPHAg3hevP3qAAs954NYJVCVUWEb5wgNZe4fXisHAOnRgHp0PCCP8R+RRHJdZGdNvU8WRRRdPzqp2ux7s0xwkrByrLPO53RwAAiKXhkhEn71c370cTU5gI+neJn9X4lipmMSXx64HFritKHCTRlC77J0TG9KP2YXbh5+RbJyrK9s84HQq5As1hVFEounRlZbLKJRIb3PfgV/91ppRR0EIskO2Y24fKUQn6OT7gxglQ9J8CSbR/WI18UhxivthoQEjspumbMQF/n/IAiVIig/7jBM3u0/fpqe4aQ+K0rLg+xMMlBMW2tByDF/s/dPQ5nkRup1nci8edJ5TbnmzVU1XzrB3h2G/bvw31oLu5fkoVVHvGC5CwApN6VDmBzRifwJq9O5UDEAQ+3ZZ/EbifDtR98ZTeEBS3755e+zDxyrax38jzImlUXzHguxe0wti35D98xxMNZU4CsXyo/MZHVmJYOaZY6vIYEc00/Du5pzDyQVjIsbDJEE6jXoBN+32TmOvqEIU2kxiKn5zSEz+qTGP5z7ZlwN8g5WjZjIHDA3Eaox0z+yD6pruDIICZPGOuvHacmBOggnV1y8Rrf3pA== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PH0PR01MB7287.prod.exchangelabs.com;PTR:;CAT:NONE;SFS:(4636009)(366004)(6666004)(8936002)(66476007)(52116002)(186003)(86362001)(2906002)(1076003)(83380400001)(54906003)(4326008)(66556008)(26005)(38100700002)(38350700002)(19627235002)(30864003)(6506007)(6916009)(6486002)(2616005)(956004)(5660300002)(6512007)(316002)(8676002)(66946007)(508600001);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Yu+cvcARAYE/zi9l26R+I0hhB4VckO3kPdDurVTkk8Q4XDOHw/3j+cQOBqbg?= =?us-ascii?Q?ToWU38l7gksPJdg+iffgOIuoLIFUWr7HE66X1GF20CRfV8S2nODP9UEMuZXg?= =?us-ascii?Q?ra4Encz0CJ0zkArM9rtVZRFL4WXNpAfp6vDP+JWtCtrtcKn1/bsH7yNWFDu4?= =?us-ascii?Q?EES96cKtRogpNZxLPDhs69RkGDx/lPSG80TdYls4X/XUdo36c0wavMdBOFPN?= =?us-ascii?Q?mXKtYETlzJ0PMhSQHwCG34pHQQDejPRfjX6/DSSmDVo9IEiwiGyvVm7Z3AWt?= =?us-ascii?Q?LDvg3PdlSyVMjt28V5ofuxi5wMaHRcx3jlt499EfmQYmls1EXtDOI3Ue8wuv?= =?us-ascii?Q?7OCXYUzLaBe2j1K0Ws6CbpDJJ2g1mdVRIxQdAR+0WqWN/DoQwX2anhEMpykX?= =?us-ascii?Q?MKlXYHm+PVeFZ+uWxBbM9ixqVgvqSiuWzXiLwMFXM4gwifaB5QaSnW9RmA4t?= =?us-ascii?Q?SsQRU05W4BA8nzRiFkQzCdSPH4NcSXM3hV7FaDjRuQw7ZSfB79AJCOYKF10n?= =?us-ascii?Q?H66jLv2GR/gXC4fuzLhRd6rZ8MoWd3INL5At/XyzMpnZitRm3mQfuVmS5GW+?= =?us-ascii?Q?SuCOQUVjSFewK9P4QqNjKIwBWi/Za7+X1FS+m4sbD6BBHyWvuCsGyfD4eK8E?= =?us-ascii?Q?FOU8mjpCUWsVH7YUNoY00mkgO9ue7HObs4+zZjZH2cMhIIR17i7f2Z1PXGPF?= =?us-ascii?Q?RF8T3Ye+9yAEmv3ZneDF8QgKMrDwmwfG8/KMO5uYReVZ56ViButWPjZD+RnT?= =?us-ascii?Q?AkJURlkolKJJrpurPQmHDuYr03WeCwwbqRNA5ntHeqnXQf01oOOU7/n2S/cy?= =?us-ascii?Q?dkfpfBqJoKieYT2/T1Q5k22uneVyb/ddLFZBBz7b1sNNKU7K9GQ1vMzzJjBj?= =?us-ascii?Q?LgFs9CMyhC+XjyMrkiMYMcSv/gr9ZX82kcUDnkVLpOr+vKo9xX6XkV2OBdoy?= =?us-ascii?Q?cfhg6Q2Jf6SSwcbIS0Whgh8pbYbkJE/8Ctr7ktim+wYsgMSJkrHMZVIdVhNc?= =?us-ascii?Q?xdwwpkBeiZRdDbBQCPxzGXOqQFQ4NW6YhHN+zHpPgz7v9OZpZAUHkdZh1YD6?= =?us-ascii?Q?lcYeRMxAQoGKRH0Ird26GYlzFTqxT742sTHwSnnyrhYSkp3o8zsTaH5dEQCV?= =?us-ascii?Q?kqhi5Yaqej95v2LgYhEAjJ2+7j2KbWwwDwIxEXoLsSEbv0MhnyRC7b1KtMQW?= =?us-ascii?Q?suSHMovrm8cobOx1Czz7F51CzEH3bm10Kv+M5NuZvnKbdejiOe+MOPsILi1a?= =?us-ascii?Q?+jv6B/5Ga773haxoeM02LQeo+EPtEhDg4tP0RhUjRnWHYZfV8mfucbRwumGW?= =?us-ascii?Q?OVNSe73V96k0gFpjtQdRR9CL7ySgVW6BuQ1O84kxauwf7q/7t5piq3iDB6Tp?= =?us-ascii?Q?OgAa30wpAx/+gDtlvKMbfZvD31WWmIC+CC5iz3i7CW+LRIyo8OmFWffjk81t?= =?us-ascii?Q?eg80WTTphdn8/rc5f7eCgJujbmZ+3s4Jr71azKQ7WKF/f+O3OI8ErC+2jqeP?= =?us-ascii?Q?v+UZwwZ7HFoUeO0jxXryybZYr5FHcj84xEzZt7d3CNtW0NVd8HoAWPXZxUcM?= =?us-ascii?Q?PlcvYUGxBpbRSdhtmXZaXgLXDRjwrS82+kKCBOKvh3s35ZvcxqqxqR8CnAbP?= =?us-ascii?Q?OgyRak00ZJniKPy6yZXsoo1ITk6zqh1OgAqrKvz0h2aYBsWemoqmUM3MidDI?= =?us-ascii?Q?0WtR2g=3D=3D?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: d6589372-15c9-455d-6293-08d9a9ea4151 X-MS-Exchange-CrossTenant-AuthSource: PH0PR01MB7287.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Nov 2021 16:49:43.5478 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: cBBbjdQFRhSLL1kabe8FsNzjZlKS2OSuWDysNl6zCJUZ2afvfsTZ80tpmFOG74XXR6EWKPLtqtgeKhp/uFKAcM8G8J2sywFZOXaos8GBS9g= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR01MB6454 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain From: Vu Nguyen The DwI2cLib library provides basic functions to control the I2C controller on Ampere Altra processor. Cc: Thang Nguyen Cc: Chuong Tran Cc: Phong Vo Cc: Leif Lindholm Cc: Michael D Kinney Cc: Ard Biesheuvel Cc: Nate DeSimone Signed-off-by: Nhi Pham Reviewed-by: Leif Lindholm --- Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 + Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf | 38 + Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h | 100 +++ Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h | 10 + Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c | 882 ++++++++= ++++++++++++ 5 files changed, 1033 insertions(+) diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Amp= ere/AmpereAltraPkg/AmpereAltraPkg.dec index ac778674266d..57ee7aafe545 100644 --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec @@ -28,6 +28,9 @@ [LibraryClasses] ## @libraryclass Defines a set of methods to communicate with SCP. SystemFirmwareInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Include/Library= /SystemFirmwareInterfaceLib.h =20 + ## @libraryclass Defines a set of methods to read/write to I2C devices= . + I2cLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h + ## @libraryclass Defines a set of methods to communicate with secure p= arition over MM interface. MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommu= nicationLib.h =20 diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf b/= Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf new file mode 100644 index 000000000000..7e697558cfb1 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf @@ -0,0 +1,38 @@ +## @file +# Component description for DwI2cLib library for the Designware I2C contro= ller. +# +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D DwI2cLib + FILE_GUID =3D 222609E2-C181-11E6-A4A6-CEC0C932CE01 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D I2cLib + CONSTRUCTOR =3D I2cLibConstructor + +[Sources] + DwI2cLib.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdePkg/MdePkg.dec + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + HobLib + IoLib + TimerLib + +[Guids] + gEfiEventVirtualAddressChangeGuid + gPlatformInfoHobGuid diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h b/Silic= on/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h new file mode 100644 index 000000000000..f13794171029 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h @@ -0,0 +1,100 @@ +/** @file + Library implementation for the Designware I2C controller. + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef I2C_LIB_H_ +#define I2C_LIB_H_ + +#include + +/** + Write to I2C bus. + + @param[in] Bus I2C bus Id. + @param[in] SlaveAddr The address of slave device on the bus. + @param[in,out] Buf Buffer that holds data to write. + @param[in,out] WriteLength Pointer to length of buffer. + + @return EFI_SUCCESS Write successfully. + @return EFI_INVALID_PARAMETER A parameter is invalid. + @return EFI_UNSUPPORTED The bus is not supported. + @return EFI_NOT_READY The device/bus is not ready. + @return EFI_TIMEOUT Timeout why transferring data. + +**/ +EFI_STATUS +EFIAPI +I2cWrite ( + IN UINT32 Bus, + IN UINT32 SlaveAddr, + IN OUT UINT8 *Buf, + IN OUT UINT32 *WriteLength + ); + +/** + Read data from I2C bus. + + @param[in] Bus I2C bus Id. + @param[in] SlaveAddr The address of slave device on the bus. + @param[in] BufCmd Buffer where to send the command. + @param[in] CmdLength Pointer to length of BufCmd. + @param[in,out] Buf Buffer where to put the read data to. + @param[in,out] ReadLength Pointer to length of buffer. + + @return EFI_SUCCESS Read successfully. + @return EFI_INVALID_PARAMETER A parameter is invalid. + @return EFI_UNSUPPORTED The bus is not supported. + @return EFI_NOT_READY The device/bus is not ready. + @return EFI_TIMEOUT Timeout why transferring data. + @return EFI_CRC_ERROR There are errors on receiving data. + +**/ +EFI_STATUS +EFIAPI +I2cRead ( + IN UINT32 Bus, + IN UINT32 SlaveAddr, + IN UINT8 *BufCmd, + IN UINT32 CmdLength, + IN OUT UINT8 *Buf, + IN OUT UINT32 *ReadLength + ); + +/** + Setup new transaction with I2C slave device. + + @param[in] Bus I2C bus Id. + @param[in] BusSpeed I2C bus speed in Hz. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + +**/ +EFI_STATUS +EFIAPI +I2cProbe ( + IN UINT32 Bus, + IN UINTN BusSpeed + ); + +/** + Setup a bus that to be used in runtime service. + + @param[in] Bus I2C bus Id. + + @retval EFI_SUCCESS Success. + @retval Otherwise Error code. + +**/ +EFI_STATUS +EFIAPI +I2cSetupRuntime ( + IN UINT32 Bus + ); + +#endif /* I2C_LIB_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h b/Silico= n/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h index c5774dca7a0a..453d966d6058 100644 --- a/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h @@ -59,4 +59,14 @@ // #define SLAVE_PRESENT_N BIT1 =20 +// +// The maximum number of I2C bus +// +#define AC01_I2C_MAX_BUS_NUM 2 + +// +// The base address of DW I2C +// +#define AC01_I2C_BASE_ADDRESS_LIST 0x1000026B0000ULL, 0x10000275000= 0ULL + #endif /* PLATFORM_AC01_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c b/Si= licon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c new file mode 100644 index 000000000000..669ba2ea98a4 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c @@ -0,0 +1,882 @@ +/** @file + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2cSync() { asm volatile ("dmb ish" : : : "memory"); } + +// +// Runtime needs to be 64K alignment +// +#define RUNTIME_ADDRESS_MASK (~(SIZE_64KB - 1)) +#define RUNTIME_ADDRESS_LENGTH SIZE_64KB + +// +// Private I2C bus data +// +typedef struct { + UINTN Base; + UINT32 BusSpeed; + UINT32 RxFifo; + UINT32 TxFifo; + UINT32 PollingTime; + UINT32 Enabled; +} DW_I2C_CONTEXT_T; + +// +// I2C SCL counter macros +// +typedef enum { + I2cSpeedModeStandard =3D 0, + I2cSpeedModeFast, +} I2C_SPEED_MODE; + +#define DW_I2C_MAXIMUM_SPEED_HZ 400000 + +typedef enum { + I2cSclSpkLen =3D 0, + I2cSclHcnt, + I2cSclLcnt, +} I2C_SCL_PARAM; + +STATIC UINT32 I2cSclParam[][3] =3D { + /* SPK_LEN, HCNT, LCNT */ + [I2cSpeedModeStandard] =3D { 10, 0x3E2, 0x47D }, // SS (Standard Speed= ) + [I2cSpeedModeFast] =3D { 10, 0xA4, 0x13F }, // FS (Fast Speed) +}; + +STATIC BOOLEAN mI2cRuntimeEnableArray[AC01_I2C_MAX_BUS_NUM] =3D {= FALSE}; +STATIC UINTN mI2cBaseArray[AC01_I2C_MAX_BUS_NUM] =3D {AC01_I2C_= BASE_ADDRESS_LIST}; +STATIC DW_I2C_CONTEXT_T mI2cBusList[AC01_I2C_MAX_BUS_NUM]; +STATIC UINTN mI2cClock =3D 0; +STATIC EFI_EVENT mVirtualAddressChangeEvent =3D NULL; + +// +// Registers +// +#define DW_IC_CON 0x0 +#define DW_IC_CON_MASTER BIT0 +#define DW_IC_CON_SPEED_STD BIT1 +#define DW_IC_CON_SPEED_FAST BIT2 +#define DW_IC_CON_10BITADDR_MASTER BIT4 +#define DW_IC_CON_RESTART_EN BIT5 +#define DW_IC_CON_SLAVE_DISABLE BIT6 +#define DW_IC_TAR 0x4 +#define DW_IC_TAR_10BITS BIT12 +#define DW_IC_SAR 0x8 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_DATA_CMD_RESTART BIT10 +#define DW_IC_DATA_CMD_STOP BIT9 +#define DW_IC_DATA_CMD_CMD BIT8 +#define DW_IC_DATA_CMD_DAT_MASK 0xFF +#define DW_IC_SS_SCL_HCNT 0x14 +#define DW_IC_SS_SCL_LCNT 0x18 +#define DW_IC_FS_SCL_HCNT 0x1c +#define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_HS_SCL_HCNT 0x24 +#define DW_IC_HS_SCL_LCNT 0x28 +#define DW_IC_INTR_STAT 0x2c +#define DW_IC_INTR_MASK 0x30 +#define DW_IC_INTR_RX_UNDER BIT0 +#define DW_IC_INTR_RX_OVER BIT1 +#define DW_IC_INTR_RX_FULL BIT2 +#define DW_IC_INTR_TX_EMPTY BIT4 +#define DW_IC_INTR_TX_ABRT BIT6 +#define DW_IC_INTR_ACTIVITY BIT8 +#define DW_IC_INTR_STOP_DET BIT9 +#define DW_IC_INTR_START_DET BIT10 +#define DW_IC_ERR_CONDITION \ + (DW_IC_INTR_RX_UNDER | DW_IC_INTR_RX_OVER | DW_IC_INTR_TX_= ABRT) +#define DW_IC_RAW_INTR_STAT 0x34 +#define DW_IC_CLR_INTR 0x40 +#define DW_IC_CLR_RX_UNDER 0x44 +#define DW_IC_CLR_RX_OVER 0x48 +#define DW_IC_CLR_TX_ABRT 0x54 +#define DW_IC_CLR_ACTIVITY 0x5c +#define DW_IC_CLR_STOP_DET 0x60 +#define DW_IC_CLR_START_DET 0x64 +#define DW_IC_ENABLE 0x6c +#define DW_IC_STATUS 0x70 +#define DW_IC_STATUS_ACTIVITY BIT0 +#define DW_IC_STATUS_TFE BIT2 +#define DW_IC_STATUS_RFNE BIT3 +#define DW_IC_STATUS_MST_ACTIVITY BIT5 +#define DW_IC_TXFLR 0x74 +#define DW_IC_RXFLR 0x78 +#define DW_IC_SDA_HOLD 0x7c +#define DW_IC_TX_ABRT_SOURCE 0x80 +#define DW_IC_ENABLE_STATUS 0x9c +#define DW_IC_COMP_PARAM_1 0xf4 +#define DW_IC_COMP_PARAM_1_RX_BUFFER_DEPTH(x) \ + ((((x) >> 8) & 0xFF) + 1) +#define DW_IC_COMP_PARAM_1_TX_BUFFER_DEPTH(x) \ + ((((x) >> 16) & 0xFF) + 1) +#define DW_IC_COMP_TYPE 0xfc +#define SB_DW_IC_CON 0xa8 +#define SB_DW_IC_SCL_TMO_CNT 0xac +#define SB_DW_IC_RX_PEC 0xb0 +#define SB_DW_IC_ACK 0xb4 +#define SB_DW_IC_FLG 0xb8 +#define SB_DW_IC_FLG_CLR 0xbc +#define SB_DW_IC_INTR_STAT 0xc0 +#define SB_DW_IC_INTR_STAT_MASK 0xc4 +#define SB_DW_IC_DEBUG_SEL 0xec +#define SB_DW_IC_ACK_DEBUG 0xf0 +#define DW_IC_FS_SPKLEN 0xa0 +#define DW_IC_HS_SPKLEN 0xa4 + +// +// Timeout interval +// +// The interval is equal to the 10 times the signaling period +// for the highest I2C transfer speed used in the system. +// +#define DW_POLL_INTERVAL_US(x) (10 * (1000000 / (x))) + +// +// Maximum timeout count +// +#define DW_MAX_TRANSFER_POLL_COUNT 100000 // Maximum timeout: 10s +#define DW_MAX_STATUS_POLL_COUNT 100 + +#define DW_POLL_MST_ACTIVITY_INTERVAL_US 1000 // 1ms +#define DW_MAX_MST_ACTIVITY_POLL_COUNT 20 + +/** + Initialize I2C Bus + **/ +VOID +I2cHWInit ( + UINT32 Bus + ) +{ + UINT32 Param; + + mI2cBusList[Bus].Base =3D mI2cBaseArray[Bus]; + + Param =3D MmioRead32 (mI2cBusList[Bus].Base + DW_IC_COMP_PARAM_1); + + mI2cBusList[Bus].PollingTime =3D DW_POLL_INTERVAL_US (mI2cBusList[Bus].B= usSpeed); + mI2cBusList[Bus].RxFifo =3D DW_IC_COMP_PARAM_1_RX_BUFFER_DEPTH (Param); + mI2cBusList[Bus].TxFifo =3D DW_IC_COMP_PARAM_1_TX_BUFFER_DEPTH (Param); + mI2cBusList[Bus].Enabled =3D 0; + + DEBUG ((DEBUG_VERBOSE, "%a: Bus %d, Rx_Buffer %d, Tx_Buffer %d\n", + __FUNCTION__, + Bus, + mI2cBusList[Bus].RxFifo, + mI2cBusList[Bus].TxFifo + )); +} + +/** + Enable or disable I2C Bus + */ +VOID +I2cEnable ( + UINT32 Bus, + UINT32 Enable + ) +{ + UINT32 I2cStatusCnt; + UINTN Base; + + Base =3D mI2cBusList[Bus].Base; + I2cStatusCnt =3D DW_MAX_STATUS_POLL_COUNT; + mI2cBusList[Bus].Enabled =3D Enable; + + MmioWrite32 (Base + DW_IC_ENABLE, Enable); + + do { + if ((MmioRead32 (Base + DW_IC_ENABLE_STATUS) & 0x01) =3D=3D Enable) { + break; + } + MicroSecondDelay (mI2cBusList[Bus].PollingTime); + } while (I2cStatusCnt-- !=3D 0); + + if (I2cStatusCnt =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: Enable/disable timeout\n", __FUNCTION__)); + } + + if ((Enable =3D=3D 0) || (I2cStatusCnt =3D=3D 0)) { + /* Unset the target adddress */ + MmioWrite32 (Base + DW_IC_TAR, 0); + mI2cBusList[Bus].Enabled =3D 0; + } +} + +/** + Setup Slave address + **/ +VOID +I2cSetSlaveAddr ( + UINT32 Bus, + UINT32 SlaveAddr + ) +{ + UINTN Base; + UINT32 OldEnableStatus; + + Base =3D mI2cBusList[Bus].Base; + OldEnableStatus =3D mI2cBusList[Bus].Enabled; + + I2cEnable (Bus, 0); + MmioWrite32 (Base + DW_IC_TAR, SlaveAddr); + if (OldEnableStatus !=3D 0) { + I2cEnable (Bus, 1); + } +} + +/** + Check for errors on I2C Bus + **/ +UINT32 +I2cCheckErrors ( + UINT32 Bus + ) +{ + UINTN Base; + UINT32 ErrorStatus; + + Base =3D mI2cBusList[Bus].Base; + + ErrorStatus =3D MmioRead32 (Base + DW_IC_RAW_INTR_STAT) & DW_IC_ERR_COND= ITION; + + if ((ErrorStatus & DW_IC_INTR_RX_UNDER) !=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: RX_UNDER error on i2c bus %d error status %0= 8x\n", + __FUNCTION__, + Bus, + ErrorStatus + )); + MmioRead32 (Base + DW_IC_CLR_RX_UNDER); + } + + if ((ErrorStatus & DW_IC_INTR_RX_OVER) !=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: RX_OVER error on i2c bus %d error status %08= x\n", + __FUNCTION__, + Bus, + ErrorStatus + )); + MmioRead32 (Base + DW_IC_CLR_RX_OVER); + } + + if ((ErrorStatus & DW_IC_INTR_TX_ABRT) !=3D 0) { + DEBUG ((DEBUG_VERBOSE, "%a: TX_ABORT at source %08x\n", + __FUNCTION__, + MmioRead32 (Base + DW_IC_TX_ABRT_SOURCE) + )); + MmioRead32 (Base + DW_IC_CLR_TX_ABRT); + } + + return ErrorStatus; +} + +/** + Waiting for bus to not be busy + **/ +BOOLEAN +I2cWaitBusNotBusy ( + UINT32 Bus + ) +{ + UINTN Base; + UINTN PollCount; + + Base =3D mI2cBusList[Bus].Base; + PollCount =3D DW_MAX_MST_ACTIVITY_POLL_COUNT; + + while ((MmioRead32 (Base + DW_IC_STATUS) & DW_IC_STATUS_MST_ACTIVITY) != =3D 0) { + if (PollCount =3D=3D 0) { + DEBUG ((DEBUG_VERBOSE, "%a: Timeout while waiting for bus ready\n", = __FUNCTION__)); + return FALSE; + } + PollCount--; + /* + * A delay isn't absolutely necessary. + * But to ensure that we don't hammer the bus constantly, + * delay for DW_POLL_MST_ACTIVITY_INTERVAL_US as with other implementa= tion. + */ + MicroSecondDelay (DW_POLL_MST_ACTIVITY_INTERVAL_US); + } + + return TRUE; +} + +/** + Waiting for TX FIFO buffer available + **/ +EFI_STATUS +I2cWaitTxData ( + UINT32 Bus + ) +{ + UINTN Base; + UINTN PollCount; + + Base =3D mI2cBusList[Bus].Base; + PollCount =3D 0; + + while (MmioRead32 (Base + DW_IC_TXFLR) =3D=3D mI2cBusList[Bus].TxFifo) { + if (PollCount++ >=3D DW_MAX_TRANSFER_POLL_COUNT) { + DEBUG ((DEBUG_ERROR, "%a: Timeout waiting for TX buffer available\n"= , __FUNCTION__)); + return EFI_TIMEOUT; + } + MicroSecondDelay (mI2cBusList[Bus].PollingTime); + } + + return EFI_SUCCESS; +} + +/** + Waiting for RX FIFO buffer available + **/ +EFI_STATUS +I2cWaitRxData ( + UINT32 Bus + ) +{ + UINTN Base; + UINTN PollCount; + + Base =3D mI2cBusList[Bus].Base; + PollCount =3D 0; + + while ((MmioRead32 (Base + DW_IC_STATUS) & DW_IC_STATUS_RFNE) =3D=3D 0) = { + if (PollCount++ >=3D DW_MAX_TRANSFER_POLL_COUNT) { + DEBUG ((DEBUG_ERROR, "%a: Timeout waiting for RX buffer available\n"= , __FUNCTION__)); + return EFI_TIMEOUT; + } + + if ((I2cCheckErrors (Bus) & DW_IC_INTR_TX_ABRT) !=3D 0) { + return EFI_ABORTED; + } + + MicroSecondDelay (mI2cBusList[Bus].PollingTime); + } + + return EFI_SUCCESS; +} + +/** + Initialize the Designware I2C SCL Counts + + This functions configures SCL clock Count for Standard Speed (SS) and Fas= t Speed (FS) mode. + **/ +VOID +I2cSclInit ( + UINT32 Bus, + UINT32 I2cClkFreq, + UINT32 I2cSpeed + ) +{ + UINT16 IcCon; + UINTN Base; + UINT32 I2cSpeedKhz; + + Base =3D mI2cBusList[Bus].Base; + I2cSpeedKhz =3D I2cSpeed / 1000; + + DEBUG ((DEBUG_VERBOSE, "%a: Bus %d I2cClkFreq %d I2cSpeed %d\n", + __FUNCTION__, + Bus, + I2cClkFreq, + I2cSpeed + )); + + IcCon =3D DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART= _EN; + + if (I2cSpeedKhz <=3D 100) { + IcCon |=3D DW_IC_CON_SPEED_STD; + // Standard speed mode + MmioWrite32 (Base + DW_IC_FS_SPKLEN, I2cSclParam[I2cSpeedModeStandard]= [I2cSclSpkLen]); + MmioWrite32 (Base + DW_IC_SS_SCL_HCNT, I2cSclParam[I2cSpeedModeStandar= d][I2cSclHcnt]); + MmioWrite32 (Base + DW_IC_SS_SCL_LCNT, I2cSclParam[I2cSpeedModeStandar= d][I2cSclLcnt]); + } else if (I2cSpeedKhz > 100 && I2cSpeedKhz <=3D 400) { + IcCon |=3D DW_IC_CON_SPEED_FAST; + // Fast speed mode + MmioWrite32 (Base + DW_IC_FS_SPKLEN, I2cSclParam[I2cSpeedModeFast][I2c= SclSpkLen]); + MmioWrite32 (Base + DW_IC_FS_SCL_HCNT, I2cSclParam[I2cSpeedModeFast][I= 2cSclHcnt]); + MmioWrite32 (Base + DW_IC_FS_SCL_LCNT, I2cSclParam[I2cSpeedModeFast][I= 2cSclLcnt]); + } + MmioWrite32 (Base + DW_IC_CON, IcCon); +} + +/** + Initialize the designware i2c master hardware + **/ +EFI_STATUS +I2cInit ( + UINT32 Bus, + UINTN BusSpeed + ) +{ + UINTN Base; + + ASSERT (mI2cClock !=3D 0); + + mI2cBusList[Bus].BusSpeed =3D BusSpeed; + I2cHWInit (Bus); + + Base =3D mI2cBusList[Bus].Base; + + /* Disable the adapter and interrupt */ + I2cEnable (Bus, 0); + MmioWrite32 (Base + DW_IC_INTR_MASK, 0); + + /* Set standard and fast speed divider for high/low periods */ + I2cSclInit (Bus, mI2cClock, BusSpeed); + MmioWrite32 (Base + DW_IC_SDA_HOLD, 0x4b); + + return EFI_SUCCESS; +} + +/** + Wait the transaction finished + **/ +EFI_STATUS +I2cFinish ( + UINT32 Bus + ) +{ + UINTN Base; + UINTN PollCount; + + Base =3D mI2cBusList[Bus].Base; + PollCount =3D 0; + + /* Wait for TX FIFO empty */ + do { + if ((MmioRead32 (Base + DW_IC_STATUS) & DW_IC_STATUS_TFE) !=3D 0) { + break; + } + MicroSecondDelay (mI2cBusList[Bus].PollingTime); + } while (PollCount++ < DW_MAX_TRANSFER_POLL_COUNT); + + if (PollCount >=3D DW_MAX_TRANSFER_POLL_COUNT) { + DEBUG ((DEBUG_ERROR, "%a: Timeout waiting for TX FIFO empty\n", __FUNC= TION__)); + return EFI_TIMEOUT; + } + + /* Wait for STOP signal detected on the bus */ + PollCount =3D 0; + do { + if ((MmioRead32 (Base + DW_IC_RAW_INTR_STAT) & DW_IC_INTR_STOP_DET) != =3D 0) { + MmioRead32 (Base + DW_IC_CLR_STOP_DET); + return EFI_SUCCESS; + } + MicroSecondDelay (mI2cBusList[Bus].PollingTime); + } while (PollCount++ < DW_MAX_TRANSFER_POLL_COUNT); + + DEBUG ((DEBUG_ERROR, "%a: Timeout waiting for transaction finished\n", _= _FUNCTION__)); + return EFI_TIMEOUT; +} + +EFI_STATUS +InternalI2cWrite ( + UINT32 Bus, + UINT8 *Buf, + UINT32 *Length + ) +{ + EFI_STATUS Status; + UINTN WriteCount; + UINTN Base; + + Status =3D EFI_SUCCESS; + Base =3D mI2cBusList[Bus].Base; + + DEBUG ((DEBUG_VERBOSE, "%a: Write Bus %d Buf %p Length %d\n", + __FUNCTION__, + Bus, + Buf, + *Length + )); + I2cEnable (Bus, 1); + + WriteCount =3D 0; + while ((*Length - WriteCount) !=3D 0) { + Status =3D I2cWaitTxData (Bus); + if (EFI_ERROR (Status)) { + MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); + I2cSync (); + goto Exit; + } + + if (WriteCount =3D=3D *Length - 1) { + MmioWrite32 ( + Base + DW_IC_DATA_CMD, + (Buf[WriteCount] & DW_IC_DATA_CMD_DAT_MASK) | DW_IC_DATA_CMD_STOP + ); + } else { + MmioWrite32 ( + Base + DW_IC_DATA_CMD, + Buf[WriteCount] & DW_IC_DATA_CMD_DAT_MASK + ); + } + I2cSync (); + WriteCount++; + } + +Exit: + *Length =3D WriteCount; + I2cFinish (Bus); + I2cWaitBusNotBusy (Bus); + I2cEnable (Bus, 0); + + return Status; +} + +EFI_STATUS +InternalI2cRead ( + UINT32 Bus, + UINT8 *BufCmd, + UINT32 CmdLength, + UINT8 *Buf, + UINT32 *Length + ) +{ + EFI_STATUS Status; + UINTN Base; + UINT32 CmdSend; + UINT32 TxLimit, RxLimit; + UINTN Idx; + UINTN Count; + UINTN ReadCount; + UINTN WriteCount; + + Status =3D EFI_SUCCESS; + Base =3D mI2cBusList[Bus].Base; + Count =3D 0; + ReadCount =3D 0; + + DEBUG ((DEBUG_VERBOSE, "%a: Read Bus %d Buf %p Length:%d\n", + __FUNCTION__, + Bus, + Buf, + *Length + )); + + I2cEnable (Bus, 1); + + /* Write command data */ + WriteCount =3D 0; + while (CmdLength !=3D 0) { + TxLimit =3D mI2cBusList[Bus].TxFifo - MmioRead32 (Base + DW_IC_TXFLR); + Count =3D CmdLength > TxLimit ? TxLimit : CmdLength; + + for (Idx =3D 0; Idx < Count; Idx++ ) { + CmdSend =3D BufCmd[WriteCount++] & DW_IC_DATA_CMD_DAT_MASK; + MmioWrite32 (Base + DW_IC_DATA_CMD, CmdSend); + I2cSync (); + + if (I2cCheckErrors (Bus) !=3D 0) { + Status =3D EFI_CRC_ERROR; + goto Exit; + } + CmdLength--; + } + + Status =3D I2cWaitTxData (Bus); + if (EFI_ERROR (Status)) { + MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); + I2cSync (); + goto Exit; + } + } + + WriteCount =3D 0; + while ((*Length - ReadCount) !=3D 0) { + TxLimit =3D mI2cBusList[Bus].TxFifo - MmioRead32 (Base + DW_IC_TXFLR); + RxLimit =3D mI2cBusList[Bus].RxFifo - MmioRead32 (Base + DW_IC_RXFLR); + Count =3D *Length - ReadCount; + Count =3D Count > RxLimit ? RxLimit : Count; + Count =3D Count > TxLimit ? TxLimit : Count; + + for (Idx =3D 0; Idx < Count; Idx++ ) { + CmdSend =3D DW_IC_DATA_CMD_CMD; + if (WriteCount =3D=3D *Length - 1) { + CmdSend |=3D DW_IC_DATA_CMD_STOP; + } + MmioWrite32 (Base + DW_IC_DATA_CMD, CmdSend); + I2cSync (); + WriteCount++; + + if (I2cCheckErrors (Bus) !=3D 0) { + DEBUG ((DEBUG_VERBOSE, + "%a: Sending reading command remaining length %d CRC error\n", + __FUNCTION__, + *Length + )); + Status =3D EFI_CRC_ERROR; + goto Exit; + } + } + + for (Idx =3D 0; Idx < Count; Idx++ ) { + Status =3D I2cWaitRxData (Bus); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, + "%a: Reading remaining length %d failed to wait data\n", + __FUNCTION__, + *Length + )); + + if (Status !=3D EFI_ABORTED) { + MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); + I2cSync (); + } + + goto Exit; + } + + Buf[ReadCount++] =3D MmioRead32 (Base + DW_IC_DATA_CMD) & DW_IC_DATA= _CMD_DAT_MASK; + I2cSync (); + + if (I2cCheckErrors (Bus) !=3D 0) { + DEBUG ((DEBUG_VERBOSE, "%a: Reading remaining length %d CRC error\= n", + __FUNCTION__, + *Length + )); + Status =3D EFI_CRC_ERROR; + goto Exit; + } + } + } + +Exit: + *Length =3D ReadCount; + I2cFinish (Bus); + I2cWaitBusNotBusy (Bus); + I2cEnable (Bus, 0); + + return Status; +} + +/** + Write to I2C bus. + + @param[in] Bus I2C bus Id. + @param[in] SlaveAddr The address of slave device on the bus. + @param[in,out] Buf Buffer that holds data to write. + @param[in,out] WriteLength Pointer to length of buffer. + + @return EFI_SUCCESS Write successfully. + @return EFI_INVALID_PARAMETER A parameter is invalid. + @return EFI_UNSUPPORTED The bus is not supported. + @return EFI_NOT_READY The device/bus is not ready. + @return EFI_TIMEOUT Timeout why transferring data. + +**/ +EFI_STATUS +EFIAPI +I2cWrite ( + IN UINT32 Bus, + IN UINT32 SlaveAddr, + IN OUT UINT8 *Buf, + IN OUT UINT32 *WriteLength + ) +{ + if (Bus >=3D AC01_I2C_MAX_BUS_NUM + || Buf =3D=3D NULL + || WriteLength =3D=3D NULL) + { + return EFI_INVALID_PARAMETER; + } + + I2cSetSlaveAddr (Bus, SlaveAddr); + + return InternalI2cWrite (Bus, Buf, WriteLength); +} + +/** + Read data from I2C bus. + + @param[in] Bus I2C bus Id. + @param[in] SlaveAddr The address of slave device on the bus. + @param[in] BufCmd Buffer where to send the command. + @param[in] CmdLength Pointer to length of BufCmd. + @param[in,out] Buf Buffer where to put the read data to. + @param[in,out] ReadLength Pointer to length of buffer. + + @return EFI_SUCCESS Read successfully. + @return EFI_INVALID_PARAMETER A parameter is invalid. + @return EFI_UNSUPPORTED The bus is not supported. + @return EFI_NOT_READY The device/bus is not ready. + @return EFI_TIMEOUT Timeout why transferring data. + @return EFI_CRC_ERROR There are errors on receiving data. + +**/ +EFI_STATUS +EFIAPI +I2cRead ( + IN UINT32 Bus, + IN UINT32 SlaveAddr, + IN UINT8 *BufCmd, + IN UINT32 CmdLength, + IN OUT UINT8 *Buf, + IN OUT UINT32 *ReadLength + ) +{ + if (Bus >=3D AC01_I2C_MAX_BUS_NUM + || Buf =3D=3D NULL + || ReadLength =3D=3D NULL) + { + return EFI_INVALID_PARAMETER; + } + + I2cSetSlaveAddr (Bus, SlaveAddr); + + return InternalI2cRead (Bus, BufCmd, CmdLength, Buf, ReadLength); +} + +/** + Setup new transaction with I2C slave device. + + @param[in] Bus I2C bus Id. + @param[in] BusSpeed I2C bus speed in Hz. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + +**/ +EFI_STATUS +EFIAPI +I2cProbe ( + IN UINT32 Bus, + IN UINTN BusSpeed + ) +{ + if (Bus >=3D AC01_I2C_MAX_BUS_NUM + || BusSpeed > DW_I2C_MAXIMUM_SPEED_HZ) + { + return EFI_INVALID_PARAMETER; + } + + return I2cInit (Bus, BusSpeed); +} + +/** + * Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + * + * This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRES= S_CHANGE event. + * It convers pointer to new virtual address. + * + * @param Event Event whose notification function is being invoked= . + * @param Context Pointer to the notification function's context. + */ +VOID +EFIAPI +I2cVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Count; + + EfiConvertPointer (0x0, (VOID **)&mI2cBusList); + EfiConvertPointer (0x0, (VOID **)&mI2cBaseArray); + EfiConvertPointer (0x0, (VOID **)&mI2cClock); + for (Count =3D 0; Count < AC01_I2C_MAX_BUS_NUM; Count++) { + if (!mI2cRuntimeEnableArray[Count]) { + continue; + } + EfiConvertPointer (0x0, (VOID **)&mI2cBaseArray[Count]); + EfiConvertPointer (0x0, (VOID **)&mI2cBusList[Count].Base); + } +} + +/** + Setup a bus that to be used in runtime service. + + @param[in] Bus I2C bus Id. + + @retval EFI_SUCCESS Success. + @retval Otherwise Error code. + +**/ +EFI_STATUS +EFIAPI +I2cSetupRuntime ( + IN UINT32 Bus + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + + if (Bus >=3D AC01_I2C_MAX_BUS_NUM) { + return EFI_INVALID_PARAMETER; + } + + if (mVirtualAddressChangeEvent =3D=3D NULL) { + /* + * Register for the virtual address change event + */ + Status =3D gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + I2cVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + } + + Status =3D gDS->GetMemorySpaceDescriptor ( + mI2cBaseArray[Bus] & RUNTIME_ADDRESS_MASK, + &Descriptor + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gDS->SetMemorySpaceAttributes ( + mI2cBaseArray[Bus] & RUNTIME_ADDRESS_MASK, + RUNTIME_ADDRESS_LENGTH, + Descriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + return Status; + } + + mI2cRuntimeEnableArray[Bus] =3D TRUE; + + return Status; +} + +EFI_STATUS +EFIAPI +I2cLibConstructor ( + VOID + ) +{ + VOID *Hob; + PLATFORM_INFO_HOB *PlatformHob; + + /* Get I2C Clock from the Platform HOB */ + Hob =3D GetFirstGuidHob (&gPlatformInfoHobGuid); + if (Hob =3D=3D NULL) { + return EFI_NOT_FOUND; + } + PlatformHob =3D (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob); + mI2cClock =3D PlatformHob->AhbClk; + ASSERT (mI2cClock !=3D 0); + + return EFI_SUCCESS; +} --=20 2.17.1