From nobody Mon Feb 9 11:28:49 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+68503+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+68503+1787277+3901457@groups.io; arc=fail (BodyHash is different from the expected one) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1607505860163265.0054977969138; Wed, 9 Dec 2020 01:24:20 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id rEW4YY1788612xvdojVYj4ej; Wed, 09 Dec 2020 01:24:19 -0800 X-Received: from NAM11-CO1-obe.outbound.protection.outlook.com (NAM11-CO1-obe.outbound.protection.outlook.com [40.107.220.90]) by mx.groups.io with SMTP id smtpd.web12.4048.1607505858083891275 for ; Wed, 09 Dec 2020 01:24:18 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=A0Y0Awcw4KjbYY/BJBn+yMjWhA73UHhRtvdWCUp3lF9P1yhy8drRlWGzoI5RHAAgsXxAM7fD1Cws1OBfwWQA4Ufj2MFjyrHUuGXYaDxuOs/X08aoQpv7aW5sSXOzfReI49xdWwjj9tFSvxKbTRLZzz1RYFuw+BTboIqpydWkytG8HCixBtc7DhWx41dbn9uuAFgV1URte/3PQPKX4qfGmip+fv0xOIMChChLLgOXO7OpnpgTBj376+vRoyq8uV2NpftHL4Ufy1/9QC+bnoq6ALo6QcTLsK93rfhWMIBQQwBlbC7RZtXU2zLaeBTxxlr60Uz9AInZ5tYUQLp90OfYGw== 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=Hf1vtMV0vsrLg0Z3y8FHTzhB8K77OmOi3kBzwuw4us4=; b=ebR/W/pyvA7Ge13vzTKQqTCSqpBjf9aHXFvv7oLiGzvmQL7JXKmUMQfup663UbIm5UufT7zpx3zRf6hGdLzlm5MTrZ/avK4yNchzRq1akCEKSVLNHvIFBfEif+Jig9RomRnTm46UhwK+LwIY2VjYwm9w+XgB8axoj3tVWkZ/NRxC5gufsUXNyKr3LQmx78Fdf+jw7EzIJqPkp7m0w2vaQNhTCJ56BhTXahbu+fGICWZ0A3cCAFSi51mW4IVxKOR+PKEYIFjR7cvFrOmNpaMxjp0GulBc+ad5S47i2qTcfpS1fXXImGDiiC++6hztkAiw0c92RfRj/xwfvbDIulmvUw== 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 X-Received: from DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) by DM6PR01MB5609.prod.exchangelabs.com (2603:10b6:5:157::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3632.21; Wed, 9 Dec 2020 09:24:16 +0000 X-Received: from DM6PR01MB5849.prod.exchangelabs.com ([fe80::c814:9a08:5c2e:4076]) by DM6PR01MB5849.prod.exchangelabs.com ([fe80::c814:9a08:5c2e:4076%5]) with mapi id 15.20.3632.023; Wed, 9 Dec 2020 09:24:16 +0000 From: "Nhi Pham via groups.io" To: devel@edk2.groups.io Cc: Vu Nguyen Subject: [edk2-devel] [edk2-platforms][PATCH 04/34] AmpereAltraPkg: Implement GpioLib and I2cLib modules Date: Wed, 9 Dec 2020 16:25:01 +0700 Message-Id: <20201209092531.30867-5-nhi@os.amperecomputing.com> In-Reply-To: <20201209092531.30867-1-nhi@os.amperecomputing.com> References: <20201209092531.30867-1-nhi@os.amperecomputing.com> X-Originating-IP: [118.69.219.201] X-ClientProxiedBy: HK0PR01CA0054.apcprd01.prod.exchangelabs.com (2603:1096:203:a6::18) To DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-Received: from sw004.amperecomputing.com (118.69.219.201) by HK0PR01CA0054.apcprd01.prod.exchangelabs.com (2603:1096:203:a6::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3654.12 via Frontend Transport; Wed, 9 Dec 2020 09:24:15 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: bf0242bc-e0cf-4555-351c-08d89c243322 X-MS-TrafficTypeDiagnostic: DM6PR01MB5609: 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-Message-Info: lIAi6Sd5lLjsQ9UQe2zlzmUn+21FQD4KFWVZ/ELK/ZXfrTQS8UXxFPSnp7yQowyZWHE4rNCuKJvGgOpNILau/hREJ9sxbqU8qlQVHnnZgNCgswvmKZrX7d0899goQh4NBmDGf/+rMr1tnxHsSWXWO1EKd3obIDmxIIv2fHVwTCQYre8mBotiixdBZQDH2pge3PYAQ07g/wIrwpnQSpp72nYF223eMSfqByiwVb/L+9PO6v93hhqyxQ2JOdB6T5Z1rfDunEYWpPynoNNTNKQUydebmhmN/XHEANluue3xLCDgEAuCCA7zPsbPtboJ2FL1ynfkiaNx76/RYCPAGjM5qbxjxZ/KrqyBTvl+6uWDOQ5+y8I6eT+Sz5gGjJzKxH1F X-MS-Exchange-AntiSpam-MessageData: =?us-ascii?Q?XN+9SugJqENm5RfHqmda6O6cJ+7tmXBUaRmVQ3pHCd1YMGNKXfUOhlwPrVPd?= =?us-ascii?Q?Rc+S9Da+bwCFrzf7y1yYU4ODrVuTjkz/NOK8jFSsFuuSsge6Q3zneJrpDRZi?= =?us-ascii?Q?HUts3OL6srmDgTYzFQ1B+MsAusTuv3UAn1yZ74ljwbDjPEmV95P41FJqNZQI?= =?us-ascii?Q?3G9+u+MM2Y8v4bEXdj55agrDsPNV6UKGIlW0cK2n1hX0Oggg2XGKOBNs4h6w?= =?us-ascii?Q?qRRR0aJ+DeYloZ88raobZz1aKGTRvDeh4amd3ClfcAT1F7SriXT18HJOG7HQ?= =?us-ascii?Q?3+WvC9W13COhQLBxuoAjpq7kXcdT9DnajyAUDyKRftOKnjx+xabu4heA6kun?= =?us-ascii?Q?kNh9awjvxmTf3vhpL2euMxA/1kuvLamTqnh3unO68iYNIi4j1S4wc9Lf8xdq?= =?us-ascii?Q?k6piw8Uvm1VHfp7nAXV/4QO9dOZpyOnJ9gQ4+xefNikapMivSjrPZF7Dh+mX?= =?us-ascii?Q?bNYX5OLFzi/tcpx/OlCuw9zQRc+lNUlHfmjMKVynDMwAuD9/GkIetiZLyJ8h?= =?us-ascii?Q?GwB//VzOQnGHOGovWzzcIBWLkKCWL/qLZvWIamJQQ1yWXb5PubpqaKsl4OAU?= =?us-ascii?Q?LXerJEXZSGPDgR8xQ3ceagnwPkfJsiyPDy9j3oyn59xoKpqFCxiskuyvzsK5?= =?us-ascii?Q?diX/+lVpHwyrRJd7rvhBYWvYYv6C26TdHO8li+1pd18w0U+EdNusFt4RX2QY?= =?us-ascii?Q?H7AlSbQy7OgCT2FgxREM4+ogjL97tQcVuLYdj68BbIffoRGafq/tPKAou1gn?= =?us-ascii?Q?85O6c7hEdXpQFd4WukaGeD9YyN8+3czJKnlXvifCnyrskf89dGAEz0YHRiN6?= =?us-ascii?Q?gK27OpATIh8thJjsVK8U7CWVtdHrkGUJK3AyLOo2nK+P8cA6ExLhYnnmmyyD?= =?us-ascii?Q?4IYUmoU+DSep6meCiGcUsqam0R3hPOxGKluVIvVvYcvb5j/VfW3YRoJmhh+M?= =?us-ascii?Q?5iFE0I9w2icNnxmx9iOQUJpYamSX81ZPMWHeLFM/9vv3jdbSB2vVP80JPTdB?= =?us-ascii?Q?jXiU?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-AuthSource: DM6PR01MB5849.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Dec 2020 09:24:16.2281 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-Network-Message-Id: bf0242bc-e0cf-4555-351c-08d89c243322 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: zqEuHNNS1d3s5N+HbmwqcBUVfzGaZxDSjL8CYt/x7FnORb8zst8dadJjUWtTshjFmuCiHKV8D8rZZweAjfQC9GlRFjb306372ubZ+MVJP+U= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR01MB5609 Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,nhi@os.amperecomputing.com X-Gm-Message-State: JDnXnDahu3zAEH7lYbrwGNpgx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1607505859; bh=TL8VW35p8ekEzjaS1/t+bWCTNq2Orls2prtlDEIB1ZI=; h=Cc:Content-Type:Date:From:Reply-To:Subject:To; b=RwNL5IGmI8KDQmEBq8kpV04xAREdBRrJDhgTQrHHDVTA3l5vdt9NMj94O9ipsWrVVzv y0AgDqyOgawoC/wA1GFRBUEj907ZBquWYPXjpwwMuK+acliB06sSSHDwo3RDN1E30jqX2 wutVbMmbd3Fee4ceUMlkdEvRULQi15Cdyjg= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Vu Nguyen Provide basic functions for GPIO and I2C on Ampere Altra. Signed-off-by: Vu Nguyen --- Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec | 6 + Silicon/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.inf | 36 + Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLib.inf | 32 + Silicon/Ampere/AmpereAltraPkg/Include/Library/DwapbGpioLib.h | 75 = ++ Silicon/Ampere/AmpereAltraPkg/Include/Library/I2CLib.h | 92 = ++ Silicon/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.c | 937 = ++++++++++++++++++++ Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLib.c | 313 = +++++++ 7 files changed, 1491 insertions(+) diff --git a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec b/Silicon/Ampere/Amp= ereAltraPkg/Ac01Pkg.dec index acf5a9621a4c..c34d580255b9 100644 --- a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec +++ b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec @@ -25,6 +25,12 @@ [LibraryClasses] ## @libraryclass Defines a set of methods to communicate with SMPro. SMProLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/SMProLib.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 get/set GPIO. + DwapbGpioLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/DwapbGpioLib.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/I2CLib.inf b/Si= licon/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.inf new file mode 100644 index 000000000000..c41571f53c18 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.inf @@ -0,0 +1,36 @@ +## @file +# +# Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D I2CLib + 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] + I2CLib.c + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec + +[LibraryClasses] + IoLib + DebugLib + BaseLib + BaseMemoryLib + TimerLib + HobLib + +[Guids] + gEfiEventVirtualAddressChangeGuid diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLi= b.inf b/Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLib.inf new file mode 100644 index 000000000000..95ebf861e358 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLib.inf @@ -0,0 +1,32 @@ +## @file +# +# Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D DwGpioLib + FILE_GUID =3D E7D9CAE1-6930-46E3-BDF9-0027446E7DF2 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D DwGpioSocLib + +[Sources.common] + DwapbGpioLib.c + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec + +[LibraryClasses] + IoLib + BaseLib + BaseMemoryLib + +[Guids] + gEfiEventVirtualAddressChangeGuid diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/DwapbGpioLib.h b= /Silicon/Ampere/AmpereAltraPkg/Include/Library/DwapbGpioLib.h new file mode 100755 index 000000000000..9c151da55600 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/DwapbGpioLib.h @@ -0,0 +1,75 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DWAPB_GPIO_LIB_H_ +#define _DWAPB_GPIO_LIB_H_ + +enum SocGpioConfigMode { + GPIO_CONFIG_OUT_LOW =3D 0, + GPIO_CONFIG_OUT_HI, + GPIO_CONFIG_OUT_LOW_TO_HIGH, + GPIO_CONFIG_OUT_HIGH_TO_LOW, + GPIO_CONFIG_IN, + MAX_GPIO_CONFIG_MODE +}; + +/* + * DwapbGpioWriteBit: Use to Set/Clear GPIOs + * Input: + * Pin : Pin Identification + * Val : 1 to Set, 0 to Clear + */ +VOID +EFIAPI +DwapbGpioWriteBit ( + IN UINT32 Pin, + IN UINT32 Val + ); + +/* + * DwapbGpioReadBit: + * Input: + * Pin : Pin Identification + * Return: + * 1 : On/High + * 0 : Off/Low + */ +UINTN +EFIAPI +DwapbGpioReadBit ( + IN UINT32 Pin + ); + +/* + * DwapbGPIOModeConfig: Use to configure GPIOs as Input/Output + * Input: + * Pin : Pin Identification + * InOut : GPIO_OUT/1 as Output + * GPIO_IN/0 as Input + */ +EFI_STATUS +EFIAPI +DwapbGPIOModeConfig ( + UINT8 Pin, + UINTN Mode + ); + +/* + * Setup a controller that to be used in runtime service. + * Input: + * Pin: Pin belongs to the controller. + * return: 0 for success. + * Otherwise, error code. + */ +EFI_STATUS +EFIAPI +DwapbGPIOSetupRuntime ( + IN UINT32 Pin + ); + +#endif /* _DWAPB_GPIO_LIB_H_ */ 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..587f6814f5b9 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2CLib.h @@ -0,0 +1,92 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _I2CLIB_H_ +#define _I2CLIB_H_ + +#include +#include + +/** + Write to I2C bus. + + @Bus: Bus ID. + @SlaveAddr: The address of slave device in the bus. + @Buf: Buffer that holds data to write. + @WriteLength: Pointer to length of buffer. + @return: EFI_INVALID_PARAMETER if parameter is invalid. + EFI_UNSUPPORTED if the bus is not supported. + EFI_NOT_READY if the device/bus is not ready. + EFI_TIMEOUT if timeout why transferring data. + Otherwise, 0 for success. + **/ +EFI_STATUS +EFIAPI +I2CWrite ( + IN UINT32 Bus, + IN UINT32 SlaveAddr, + IN OUT UINT8 *Buf, + IN OUT UINT32 *WriteLength + ); + +/** + Read data from I2C bus. + + @Bus: Bus ID. + @SlaveAddr: The address of slave device in the bus. + @BufCmd: Buffer where to send the command. + @CmdLength: Pointer to length of BufCmd. + @Buf: Buffer where to put the read data to. + @ReadLength: Pointer to length of buffer. + @return: EFI_INVALID_PARAMETER if parameter is invalid. + EFI_UNSUPPORTED if the bus is not supported. + EFI_NOT_READY if the device/bus is not ready. + EFI_TIMEOUT if timeout why transferring data. + EFI_CRC_ERROR if there are errors on receiving data. + Otherwise, 0 for success. + **/ +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. + + @Bus: Bus ID. + @BusSpeed: Bus speed in Hz. + @return: EFI_INVALID_PARAMETER if parameter is invalid. + Otherwise, 0 for success. + **/ +EFI_STATUS +EFIAPI +I2CProbe ( + IN UINT32 Bus, + IN UINTN BusSpeed + ); + +/** + Setup a bus that to be used in runtime service. + + @Bus: Bus ID. + @return: 0 for success. + Otherwise, error code. + **/ +EFI_STATUS +EFIAPI +I2CSetupRuntime ( + IN UINT32 Bus + ); + +#endif /* _I2CLIB_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.c b/Sili= con/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.c new file mode 100755 index 000000000000..37a7463549df --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.c @@ -0,0 +1,937 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef I2C_DBG +#undef I2C_PRINT + +#ifdef I2C_DBG +#define DBG(arg...) DEBUG ((DEBUG_ERROR, "DW_I2C(DBG): "));DEBUG ((DEBUG_E= RROR,## arg)) +#else +#define DBG(arg...) +#endif + +#define ERROR(arg...) DEBUG ((DEBUG_ERROR, "DW_I2C(ERROR): "));DEBUG ((DEB= UG_ERROR,## arg)) + +#ifdef I2C_PRINT +#define PRINT(arg...) DEBUG ((DEBUG_INFO, "DW_I2C(INFO): "));DEBUG ((DEBUG= _INFO,## arg)) +#else +#define PRINT(arg...) +#endif + +/* Runtime needs to be 64K alignment */ +#define RUNTIME_ADDRESS_MASK (~(SIZE_64KB - 1)) +#define RUNTIME_ADDRESS_LENGTH SIZE_64KB + +/* Bus specific values */ +typedef struct DW_I2C_CONTEXT { + UINTN Base; + UINT32 BusSpeed; + UINT32 RxFifo; + UINT32 TxFifo; + UINT32 PollingTime; + UINT32 Enabled; +} DW_I2C_CONTEXT_T; + +/* I2C SCL counter macros */ +enum { + I2C_SS =3D 0, + I2C_FS, + I2C_PS, + I2C_HS_400PF, + I2C_HS_100PF, +}; +#define I2C_HS I2C_HS_400PF + +enum { + I2C_SCL_HIGH =3D 0, + I2C_SCL_LOW, + I2C_SCL_TF, +}; + +enum { + I2C_SPKLEN =3D 0, + I2C_OFFSET, +}; + +#define SS_SCL_HCNT 250 +#define SS_SCL_LCNT 250 +#define FS_SCL_HCNT 62 +#define FS_SCL_LCNT 63 + +#define I2CSync() { asm volatile ("dmb ish" : : : "memory"); } + +STATIC UINT32 I2CSclMin[][3] =3D { /* in nano seconds */ + /* High, Low, tf */ + [I2C_SS] =3D {4000, 4700, 300}, /* SS (Standard Speed) */ + [I2C_FS] =3D { 600, 1300, 300}, /* FS (Fast Speed) */ + [I2C_PS] =3D { 260, 500, 120}, /* PS (Fast Plus Speed) */ + [I2C_HS_400PF] =3D { 160, 320, 300}, /* HS (High Speed) 400pf */ + [I2C_HS_100PF] =3D { 60, 120, 300}, /* HS (High Speed) 100pf */ +}; + +STATIC UINT32 I2CSclParam[][2] =3D { + /* Spklen, offset */ + [I2C_SS] =3D {10, 300}, /* SS (Standard Speed) */ + [I2C_FS] =3D {10, 0}, /* FS (Fast Speed) */ + [I2C_PS] =3D {10, 0}, /* PS (Fast Plus Speed) */ + [I2C_HS_400PF] =3D {0, 0}, /* HS (High Speed) 400pf */ + [I2C_HS_100PF] =3D {0, 0}, /* HS (High Speed) 100pf */ +}; + +STATIC BOOLEAN I2CRuntimeEnableArray[MAX_PLATFORM_I2C_BUS_NUM] = =3D {FALSE}; +STATIC UINTN I2CBaseArray[MAX_PLATFORM_I2C_BUS_NUM] =3D {PLAT= FORM_I2C_REGISTER_BASE}; +STATIC DW_I2C_CONTEXT_T I2CBusList[MAX_PLATFORM_I2C_BUS_NUM]; +STATIC UINTN I2CClock =3D 0; +STATIC EFI_EVENT mVirtualAddressChangeEvent =3D NULL; + +#ifndef BIT +#define BIT(nr) (1 << (nr)) +#endif + +#define DW_SIGNATURE 0x44570000 /* 'D' 'W' */ + +/* + * Registers + */ +#define DW_IC_CON 0x0 +#define DW_IC_CON_MASTER BIT(0) +#define DW_IC_CON_SPEED_STD BIT(1) +#define DW_IC_CON_SPEED_FAST BIT(2) +#define DW_IC_CON_10BITADDR_MASTER BIT(4) +#define DW_IC_CON_RESTART_EN BIT(5) +#define DW_IC_CON_SLAVE_DISABLE BIT(6) +#define DW_IC_TAR 0x4 +#define DW_IC_TAR_10BITS BIT(12) +#define DW_IC_SAR 0x8 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_DATA_CMD_RESTART BIT(10) +#define DW_IC_DATA_CMD_STOP BIT(9) +#define DW_IC_DATA_CMD_CMD BIT(8) +#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 BIT(0) +#define DW_IC_INTR_RX_OVER BIT(1) +#define DW_IC_INTR_RX_FULL BIT(2) +#define DW_IC_INTR_TX_EMPTY BIT(4) +#define DW_IC_INTR_TX_ABRT BIT(6) +#define DW_IC_INTR_ACTIVITY BIT(8) +#define DW_IC_INTR_STOP_DET BIT(9) +#define DW_IC_INTR_START_DET BIT(10) +#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 BIT(0) +#define DW_IC_STATUS_TFE BIT(2) +#define DW_IC_STATUS_RFNE BIT(3) +#define DW_IC_STATUS_MST_ACTIVITY BIT(5) +#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_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 + +#define DW_BUS_WAIT_SLEEP 1000 /* 1ms */ +#define DW_BUS_WAIT_TIMEOUT_RETRY 20 +#define DW_TRANSFER_DATA_TIMEOUT 10000000 /* Max 10s */ +#define DW_STATUS_WAIT_RETRY 100 + +UINT32 +Read32 ( + UINTN Addr + ) +{ + return MmioRead32 (Addr); +} + +VOID +Write32 ( + UINTN Addr, + UINT32 Val + ) +{ + MmioWrite32 (Addr, Val); +} + +/** + Initialize I2C Bus + **/ +VOID +I2CHWInit ( + UINT32 Bus + ) +{ + UINT32 Param; + + I2CBusList[Bus].Base =3D I2CBaseArray[Bus]; + Param =3D Read32 (I2CBusList[Bus].Base + DW_IC_COMP_PARAM_1); + I2CBusList[Bus].PollingTime =3D (10 * 1000000) / I2CBusList[Bus].BusSpee= d; + I2CBusList[Bus].RxFifo =3D ((Param >> 8) & 0xff) + 1; + I2CBusList[Bus].TxFifo =3D ((Param >> 16) & 0xff) + 1; + I2CBusList[Bus].Enabled =3D 0; + DBG ("Bus %d Rx_Buffer %d Tx_Buffer %d\n", + Bus, I2CBusList[Bus].RxFifo, I2CBusList[Bus].TxFifo); +} + +/** + Enable or disable I2C Bus + */ +VOID +I2CEnable ( + UINT32 Bus, + UINT32 Enable + ) +{ + UINT32 I2CStatusCnt =3D DW_STATUS_WAIT_RETRY; + UINTN Base =3D I2CBusList[Bus].Base; + + I2CBusList[Bus].Enabled =3D Enable; + + Write32 (Base + DW_IC_ENABLE, Enable); + do { + if ((Read32 (Base + DW_IC_ENABLE_STATUS) & 0x01) =3D=3D Enable) { + break; + } + MicroSecondDelay (I2CBusList[Bus].PollingTime); + } while (I2CStatusCnt-- !=3D 0); + + if (I2CStatusCnt =3D=3D 0) { + ERROR ("Enable/disable timeout\n"); + } + + if ((Enable =3D=3D 0) || (I2CStatusCnt =3D=3D 0)) { + /* Unset the target adddress */ + Write32 (Base + DW_IC_TAR, 0); + I2CBusList[Bus].Enabled =3D 0; + } +} + +/** + Setup Slave address + **/ +VOID +I2CSetSlaveAddr ( + UINT32 Bus, + UINT32 SlaveAddr + ) +{ + UINTN Base =3D I2CBusList[Bus].Base; + UINT32 OldEnableStatus =3D I2CBusList[Bus].Enabled; + + I2CEnable (Bus, 0); + Write32 (Base + DW_IC_TAR, SlaveAddr); + if (OldEnableStatus !=3D 0) { + I2CEnable (Bus, 1); + } +} + +/** + Check for errors on I2C Bus + **/ +UINT32 +I2CCheckErrors ( + UINT32 Bus + ) +{ + UINTN Base =3D I2CBusList[Bus].Base; + UINT32 ErrorStatus; + + ErrorStatus =3D Read32 (Base + DW_IC_RAW_INTR_STAT) & DW_IC_ERR_CONDITIO= N; + if (ErrorStatus !=3D 0) { + ERROR ("Errors on i2c bus %d error status %08x\n", Bus, ErrorStatus); + } + + if ((ErrorStatus & DW_IC_INTR_RX_UNDER) !=3D 0) { + Read32 (Base + DW_IC_CLR_RX_UNDER); + } + + if ((ErrorStatus & DW_IC_INTR_RX_OVER) !=3D 0) { + Read32 (Base + DW_IC_CLR_RX_OVER); + } + + if ((ErrorStatus & DW_IC_INTR_TX_ABRT) !=3D 0) { + DBG ("TX_ABORT at source %08x\n", Read32 (Base + DW_IC_TX_ABRT_SOURCE)= ); + Read32 (Base + DW_IC_CLR_TX_ABRT); + } + + return ErrorStatus; +} + +/** + Waiting for bus to not be busy + **/ +BOOLEAN +I2CWaitBusNotBusy ( + UINT32 Bus + ) +{ + UINTN Base =3D I2CBusList[Bus].Base; + UINTN Timeout =3D DW_BUS_WAIT_TIMEOUT_RETRY; + + while ((Read32 (Base + DW_IC_STATUS) & DW_IC_STATUS_MST_ACTIVITY) !=3D 0= ) { + if (Timeout =3D=3D 0) { + DBG ("Timeout while waiting for bus ready\n"); + return FALSE; + } + Timeout--; + /* + * A delay isn't absolutely necessary. + * But to ensure that we don't hammer the bus constantly, + * delay for DW_BUS_WAIT_SLEEP as with other implementation. + */ + MicroSecondDelay (DW_BUS_WAIT_SLEEP); + } + + return TRUE; +} + +/** + Waiting for TX FIFO buffer available + **/ +EFI_STATUS +I2CWaitTxData ( + UINT32 Bus + ) +{ + UINTN Base =3D I2CBusList[Bus].Base; + UINTN Timeout =3D DW_TRANSFER_DATA_TIMEOUT; + + while (Read32 (Base + DW_IC_TXFLR) =3D=3D I2CBusList[Bus].TxFifo) { + if (Timeout <=3D 0) { + ERROR ("Timeout waiting for TX buffer available\n"); + return EFI_TIMEOUT; + } + MicroSecondDelay (I2CBusList[Bus].PollingTime); + Timeout -=3D MicroSecondDelay (I2CBusList[Bus].PollingTime); + } + + return EFI_SUCCESS; +} + +/** + Waiting for RX FIFO buffer available + **/ +EFI_STATUS +I2CWaitRxData ( + UINT32 Bus + ) +{ + UINTN Base =3D I2CBusList[Bus].Base; + UINTN Timeout =3D DW_TRANSFER_DATA_TIMEOUT; + + while ((Read32 (Base + DW_IC_STATUS) & DW_IC_STATUS_RFNE) =3D=3D 0) { + if (Timeout <=3D 0) { + ERROR ("Timeout waiting for RX buffer available\n"); + return EFI_TIMEOUT; + } + + if ((I2CCheckErrors (Bus) & DW_IC_INTR_TX_ABRT) !=3D 0) { + return EFI_ABORTED; + } + + MicroSecondDelay (I2CBusList[Bus].PollingTime); + Timeout -=3D MicroSecondDelay (I2CBusList[Bus].PollingTime); + } + + return EFI_SUCCESS; +} + +UINT32 +I2CSclHcnt ( + UINT32 IcClk, + UINT32 tSYMBOL, + UINT32 Tf, + UINT32 Spklen, + INTN Cond, + INTN Offset + ) +{ + /* + * DesignWare I2C core doesn't seem to have solid strategy to meet + * the tHD;STA timing spec. Configuring _HCNT. Based on tHIGH spec + * will result in violation of the tHD;STA spec. + */ + if (Cond !=3D 0) { + /* + * Conditional expression: + * + * IC_[FS]S_SCL_HCNT + (1+4+3) >=3D IC_CLK * tHIGH + * + * This is.Based on the DW manuals, and represents an ideal + * configuration. The resulting I2C bus speed will be + * faster than any of the others. + * + * If your hardware is free from tHD;STA issue, try this one. + */ + return (((IcClk * tSYMBOL + 500000) / 1000000) - 8 + Offset); + } + + /* + * Conditional expression: + * + * IC_[FS]S_SCL_HCNT + IC_[FH]S_SPKLEN + 6 >=3D IC_CLK * + * (tHD;STA + tf) + * + * This is just experimental rule; the tHD;STA period turned + * out to be proportinal to (_HCNT _SPKLEN + 6). + * With this setting, we could meet both tHIGH and tHD;STA + * timing specs. + * + * If unsure, you'd better to take this alternative. + * + * The reason why we need to take into account "tf" here, + * is the same as described in I2c_Dw_Scl_Lcnt(). + */ + return (((IcClk * (tSYMBOL + Tf) + 500000) / 1000000) - + Spklen - 6 + Offset); +} + +UINT32 +I2CSclLcnt ( + UINT32 IcClk, + UINT32 tLOW, + UINT32 Tf, + INTN Offset + ) +{ + /* + * Conditional expression: + * + * IC_[FS]S_SCL_LCNT + 1 >=3D IC_CLK * (tLOW + tf) + * + * DW I2C core starts Counting the SCL CNTs for the LOW period + * of the SCL clock (tLOW) as soon as it pulls the SCL line. + * In order to meet the tLOW timing spec, we need to take INTNo + * acCount the fall time of SCL signal (tf). Default tf value + * should be 0.3 us, for safety. + */ + return (((IcClk * (tLOW + Tf) + 500000) / 1000000) - 1 + Offset); +} + +/** + Initialize the designware i2c scl Counts + + This functions configures scl clock Count for SS, FS, and HS. + **/ +VOID +I2CSclInit ( + UINT32 Bus, + UINT32 I2CClkFreq, + UINT32 I2CSpeed + ) +{ + UINT32 Hcnt, Lcnt; + UINT16 IcCon; + UINTN Base =3D I2CBusList[Bus].Base; + UINT32 InputClockKhz =3D I2CClkFreq / 1000; + UINT32 SsClockKhz =3D InputClockKhz; + UINT32 FsClockKhz =3D InputClockKhz; + UINT32 HsClockKhz =3D InputClockKhz; + UINT32 PsClockKhz =3D InputClockKhz; + UINT32 I2CSpeedKhz =3D I2CSpeed / 1000; + + DBG("Bus %d I2CClkFreq %d I2CSpeed %d\n", 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; + SsClockKhz =3D (SsClockKhz * 100) / I2CSpeedKhz; + /* Standard speed mode */ + Hcnt =3D I2CSclHcnt (SsClockKhz, + I2CSclMin[I2C_SS][I2C_SCL_HIGH], /* tHD;STA =3D tHIGH =3D 4.0 us */ + I2CSclMin[I2C_SS][I2C_SCL_TF], /* tf =3D 0.3 us */ + I2CSclParam[I2C_SS][I2C_SPKLEN], /* spklen =3D 10 */ + 0, /* 0: DW default, 1: Ideal */ + I2CSclParam[I2C_SS][I2C_OFFSET]); /* offset =3D 300 */ + Write32 (Base + DW_IC_FS_SPKLEN, I2CSclParam[I2C_SS][I2C_SPKLEN]); + Lcnt =3D I2CSclLcnt (SsClockKhz, + I2CSclMin[I2C_SS][I2C_SCL_LOW], /* tLOW =3D 4.7 us */ + I2CSclMin[I2C_SS][I2C_SCL_TF], /* tf =3D 0.3 us */ + 0); /* No Offset */ + Write32 (Base + DW_IC_SS_SCL_HCNT, Hcnt); + Write32 (Base + DW_IC_SS_SCL_LCNT, Lcnt); + } else if (I2CSpeedKhz > 100 && I2CSpeedKhz <=3D 400) { + IcCon |=3D DW_IC_CON_SPEED_FAST; + FsClockKhz =3D (FsClockKhz * 400) / I2CSpeedKhz; + /* Fast speed mode */ + Hcnt =3D I2CSclHcnt (FsClockKhz, + I2CSclMin[I2C_FS][I2C_SCL_HIGH], /* tHD;STA =3D tHIGH =3D 0.6 us */ + I2CSclMin[I2C_FS][I2C_SCL_TF], /* tf =3D 0.3 us */ + I2CSclParam[I2C_FS][I2C_SPKLEN], /* spklen =3D 0xA */ + 0, /* 0: DW default, 1: Ideal */ + I2CSclParam[I2C_FS][I2C_OFFSET]); /* No Offset */ + Write32 (Base + DW_IC_FS_SPKLEN, I2CSclParam[I2C_FS][I2C_SPKLEN]); + Lcnt =3D I2CSclLcnt (FsClockKhz, + I2CSclMin[I2C_FS][I2C_SCL_LOW], /* tLOW =3D 1.3 us */ + I2CSclMin[I2C_FS][I2C_SCL_TF], /* tf =3D 0.3 us */ + 0); /* No Offset */ + Write32 (Base + DW_IC_FS_SCL_HCNT, Hcnt); + Write32 (Base + DW_IC_FS_SCL_LCNT, Lcnt); + } else if (I2CSpeedKhz > 400 && I2CSpeedKhz <=3D 1000) { + IcCon |=3D DW_IC_CON_SPEED_FAST; + PsClockKhz =3D (PsClockKhz * 1000) / I2CSpeedKhz; + /* Fast speed plus mode */ + Hcnt =3D I2CSclHcnt (PsClockKhz, + I2CSclMin[I2C_PS][I2C_SCL_HIGH], /* tHD;STA =3D tHIGH =3D 0.26 us */ + I2CSclMin[I2C_PS][I2C_SCL_TF], /* tf =3D 0.12 us */ + I2CSclParam[I2C_PS][I2C_SPKLEN], /* spklen =3D 0xA */ + 0, /* 0: DW default, 1: Ideal */ + I2CSclParam[I2C_PS][I2C_OFFSET]); /* No Offset */ + Lcnt =3D I2CSclLcnt (PsClockKhz, + I2CSclMin[I2C_PS][I2C_SCL_LOW], /* tLOW =3D 0.5 us */ + I2CSclMin[I2C_PS][I2C_SCL_TF], /* tf =3D 0.12 us */ + 0); /* No Offset */ + Write32 (Base + DW_IC_FS_SCL_HCNT, Hcnt); + Write32 (Base + DW_IC_FS_SCL_LCNT, Lcnt); + Write32 (Base + DW_IC_FS_SPKLEN, I2CSclParam[I2C_PS][I2C_SPKLEN]); + } else if (I2CSpeedKhz > 1000 && I2CSpeedKhz <=3D 3400) { + IcCon |=3D (DW_IC_CON_SPEED_STD | DW_IC_CON_SPEED_FAST); + HsClockKhz =3D (HsClockKhz * 3400) / I2CSpeedKhz; + /* High speed mode */ + Hcnt =3D I2CSclHcnt (HsClockKhz, + I2CSclMin[I2C_HS][I2C_SCL_HIGH], /* tHD;STA =3D tHIGH =3D 0.06 us f= or 100pf 0.16 for 400pf */ + I2CSclMin[I2C_HS][I2C_SCL_TF], /* tf =3D 0.3 us */ + I2CSclParam[I2C_HS][I2C_SPKLEN], /* No spklen */ + 0, /* 0: DW default, 1: Ideal */ + I2CSclParam[I2C_HS][I2C_OFFSET]); /* No Offset */ + Lcnt =3D I2CSclLcnt (HsClockKhz, + I2CSclMin[I2C_HS][I2C_SCL_LOW], /* tLOW =3D 0.12 us for 100pf 0.32= us for 400pf */ + I2CSclMin[I2C_HS][I2C_SCL_TF], /* tf =3D 0.3 us */ + 0); /* No Offset */ + Write32 (Base + DW_IC_HS_SCL_HCNT, Hcnt); + Write32 (Base + DW_IC_HS_SCL_LCNT, Lcnt); + } + Write32 (Base + DW_IC_CON, IcCon); +} + +/** + Initialize the designware i2c master hardware + **/ +EFI_STATUS +I2CInit ( + UINT32 Bus, + UINTN BusSpeed + ) +{ + UINTN Base; + + ASSERT (I2CClock !=3D 0); + + I2CBusList[Bus].BusSpeed =3D BusSpeed; + I2CHWInit (Bus); + + Base =3D I2CBusList[Bus].Base; + + /* Disable the adapter and interrupt */ + I2CEnable (Bus, 0); + Write32 (Base + DW_IC_INTR_MASK, 0); + + /* Set standard and fast speed divider for high/low periods */ + I2CSclInit (Bus, I2CClock, BusSpeed); + Write32 (Base + DW_IC_SDA_HOLD, 0x4b); + + return EFI_SUCCESS; +} + +/** + Wait the transaction finished + **/ +EFI_STATUS +I2CFinish ( + UINT32 Bus + ) +{ + UINTN Base =3D I2CBusList[Bus].Base; + UINTN Timeout =3D DW_TRANSFER_DATA_TIMEOUT; + + /* Wait for TX FIFO empty */ + do { + if ((Read32 (Base + DW_IC_STATUS) & DW_IC_STATUS_TFE) !=3D 0) { + break; + } + MicroSecondDelay (I2CBusList[Bus].PollingTime); + Timeout -=3D MicroSecondDelay (I2CBusList[Bus].PollingTime); + } while (Timeout > 0); + + if (Timeout =3D=3D 0) { + ERROR ("Timeout waiting for TX FIFO empty\n"); + return EFI_TIMEOUT; + } + + /* Wait for STOP signal detected on the bus */ + Timeout =3D DW_TRANSFER_DATA_TIMEOUT; + do { + if ((Read32 (Base + DW_IC_RAW_INTR_STAT) & DW_IC_INTR_STOP_DET) !=3D 0= ) { + Read32 (Base + DW_IC_CLR_STOP_DET); + return EFI_SUCCESS; + } + MicroSecondDelay (I2CBusList[Bus].PollingTime); + Timeout -=3D MicroSecondDelay (I2CBusList[Bus].PollingTime); + } while (Timeout > 0); + + ERROR ("Timeout waiting for transaction finished\n"); + return EFI_TIMEOUT; +} + +EFI_STATUS +InternalI2CWrite ( + UINT32 Bus, + UINT8 *Buf, + UINT32 *Length + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + UINTN WriteCount; + UINTN Base =3D I2CBusList[Bus].Base; + + DBG ("Write Bus %d Buf %p Length %d\n", Bus, Buf, *Length); + I2CEnable (Bus, 1); + + WriteCount =3D 0; + while ((*Length - WriteCount) !=3D 0) { + Status =3D I2CWaitTxData (Bus); + if (EFI_ERROR (Status)) { + Write32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); + I2CSync (); + goto Exit; + } + + if (WriteCount =3D=3D *Length - 1) { + Write32 (Base + DW_IC_DATA_CMD, + (Buf[WriteCount] & DW_IC_DATA_CMD_DAT_MASK) + | DW_IC_DATA_CMD_STOP); + } else { + Write32 (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, + IN UINT32 CmdLength, + UINT8 *Buf, + UINT32 *Length + ) +{ + UINTN Base =3D I2CBusList[Bus].Base; + UINT32 CmdSend; + UINT32 TxLimit, RxLimit; + UINTN Idx =3D 0; + UINTN Count =3D 0; + UINTN ReadCount =3D 0; + UINTN WriteCount =3D 0; + EFI_STATUS Status =3D EFI_SUCCESS; + + DBG ("Read Bus %d Buf %p Length:%d\n", Bus, Buf, *Length); + I2CEnable (Bus, 1); + + /* Write command data */ + WriteCount =3D 0; + while (CmdLength !=3D 0) { + TxLimit =3D I2CBusList[Bus].TxFifo - Read32 (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; + Write32 (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)) { + Write32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); + I2CSync (); + goto Exit; + } + } + + ReadCount =3D 0; + WriteCount =3D 0; + while ((*Length - ReadCount) !=3D 0) { + TxLimit =3D I2CBusList[Bus].TxFifo - Read32 (Base + DW_IC_TXFLR); + RxLimit =3D I2CBusList[Bus].RxFifo - Read32 (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; + } + Write32 (Base + DW_IC_DATA_CMD, CmdSend); + I2CSync (); + WriteCount++; + + if (I2CCheckErrors (Bus) !=3D 0) { + DBG ("Sending reading command remaining length %d CRC error\n", *L= ength); + Status =3D EFI_CRC_ERROR; + goto Exit; + } + } + + for (Idx =3D 0; Idx < Count ; Idx++ ) { + Status =3D I2CWaitRxData (Bus); + if (EFI_ERROR (Status)) { + DBG ("Reading remaining length %d failed to wait data\n", *Length); + + if (Status !=3D EFI_ABORTED) { + Write32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); + I2CSync (); + } + + goto Exit; + } + + Buf[ReadCount++] =3D Read32 (Base + DW_IC_DATA_CMD) & DW_IC_DATA_CMD= _DAT_MASK; + I2CSync (); + + if (I2CCheckErrors (Bus) !=3D 0) { + DBG ("Reading remaining length %d CRC error\n", *Length); + Status =3D EFI_CRC_ERROR; + goto Exit; + } + } + } + +Exit: + *Length =3D ReadCount; + I2CFinish (Bus); + I2CWaitBusNotBusy (Bus); + I2CEnable (Bus, 0); + + return Status; +} + +EFI_STATUS +EFIAPI +I2CWrite ( + IN UINT32 Bus, + IN UINT32 SlaveAddr, + IN OUT UINT8 *Buf, + IN OUT UINT32 *WriteLength + ) +{ + if (Bus >=3D MAX_PLATFORM_I2C_BUS_NUM) { + return EFI_INVALID_PARAMETER; + } + + I2CSetSlaveAddr (Bus, SlaveAddr); + + return InternalI2CWrite (Bus, Buf, WriteLength); +} + +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 MAX_PLATFORM_I2C_BUS_NUM) { + return EFI_INVALID_PARAMETER; + } + + I2CSetSlaveAddr (Bus, SlaveAddr); + + return InternalI2CRead (Bus, BufCmd, CmdLength, Buf, ReadLength); +} + +EFI_STATUS +EFIAPI +I2CProbe ( + IN UINT32 Bus, + IN UINTN BusSpeed + ) +{ + if (Bus >=3D MAX_PLATFORM_I2C_BUS_NUM) { + 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**) &I2CBusList); + EfiConvertPointer (0x0, (VOID**) &I2CBaseArray); + EfiConvertPointer (0x0, (VOID**) &I2CClock); + for (Count =3D 0; Count < MAX_PLATFORM_I2C_BUS_NUM; Count++) { + if (!I2CRuntimeEnableArray[Count]) { + continue; + } + EfiConvertPointer (0x0, (VOID**) &I2CBaseArray[Count]); + EfiConvertPointer (0x0, (VOID**) &I2CBusList[Count].Base); + } +} + +/** + Setup a bus that to be used in runtime service. + + @Bus: Bus ID. + @return: 0 for success. + Otherwise, error code. + **/ +EFI_STATUS +EFIAPI +I2CSetupRuntime ( + IN UINT32 Bus + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + + 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 ( + I2CBaseArray[Bus] & RUNTIME_ADDRESS_MASK, + &Descriptor + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gDS->SetMemorySpaceAttributes ( + I2CBaseArray[Bus] & RUNTIME_ADDRESS_MASK, + RUNTIME_ADDRESS_LENGTH, + Descriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + return Status; + } + + I2CRuntimeEnableArray[Bus] =3D TRUE; + + return Status; +} + +EFI_STATUS +EFIAPI +I2CLibConstructor ( + VOID + ) +{ + VOID *Hob; + PlatformInfoHob *PlatformHob; + PlatformInfoHob_V2 *PlatformHob_V2; + CONST EFI_GUID PlatformHobGuid =3D PLATFORM_INFO_HOB_GUID; + CONST EFI_GUID PlatformHobGuid_V2 =3D PLATFORM_INFO_HOB_GUID_V2; + + /* Get I2C Clock from the Platform HOB */ + Hob =3D GetFirstGuidHob (&PlatformHobGuid); + if (Hob =3D=3D NULL) { + Hob =3D GetFirstGuidHob (&PlatformHobGuid_V2); + if (Hob =3D=3D NULL) { + return EFI_NOT_FOUND; + } + PlatformHob_V2 =3D (PlatformInfoHob_V2 *) GET_GUID_HOB_DATA (Hob); + I2CClock =3D PlatformHob_V2->AhbClk; + } else { + PlatformHob =3D (PlatformInfoHob *) GET_GUID_HOB_DATA (Hob); + I2CClock =3D PlatformHob->ApbClk; + } + ASSERT (I2CClock !=3D 0); + + return EFI_SUCCESS; +} diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLi= b.c b/Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLib.c new file mode 100755 index 000000000000..ec316a70dce8 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwapbGpioLib/DwapbGpioLib.c @@ -0,0 +1,313 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Runtime needs to be 64K alignment */ +#define RUNTIME_ADDRESS_MASK (~(SIZE_64KB - 1)) +#define RUNTIME_ADDRESS_LENGTH SIZE_64KB + +#define GPIO_MUX_VAL(Gpio) (0x00000001 << (Gpio)) +#define GPIO_IN 0 +#define GPIO_OUT 1 + +/* Address GPIO_REG Registers */ +#define GPIO_SWPORTA_DR_ADDR 0x00000000 +#define GPIO_SWPORTA_DDR_ADDR 0x00000004 +#define GPIO_EXT_PORTA_ADDR 0x00000050 + +STATIC UINT64 GpioBaseAddr[] =3D { GPIO_DWAPB_BASE_ADDR } ; +STATIC UINT64 GpiBaseAddr[] =3D { GPI_DWAPB_BASE_ADDR } ; +STATIC BOOLEAN GpioRuntimeEnableArray[sizeof (GpioBaseAddr) / sizeof = (GpioBaseAddr[0])] =3D { FALSE }; +STATIC EFI_EVENT mVirtualAddressChangeEvent =3D NULL; + +UINT64 +GetBaseAddr ( + IN UINT32 Pin + ) +{ + UINT32 NumberOfControllers =3D sizeof (GpioBaseAddr) / sizeof (GpioBaseA= ddr[0]); + UINT32 TotalPins =3D GPIO_DWAPB_PINS_PER_CONTROLLER * NumberOfController= s; + + if (NumberOfControllers =3D=3D 0 || Pin >=3D TotalPins) { + return 0; + } + + return GpioBaseAddr[Pin / GPIO_DWAPB_PINS_PER_CONTROLLER]; +} + +VOID +DwapbGpioWrite ( + IN UINT64 Base, + IN UINT32 Val + ) +{ + MmioWrite32 ((UINTN) Base, Val); +} + +VOID +DwapbGpioRead ( + IN UINT64 Base, + OUT UINT32 *Val + ) +{ + ASSERT (Val !=3D NULL); + *Val =3D MmioRead32 (Base); +} + +VOID +EFIAPI +DwapbGpioWriteBit ( + IN UINT32 Pin, + IN UINT32 Val + ) +{ + UINT64 Reg; + UINT32 GpioPin; + UINT32 ReadVal; + + Reg =3D GetBaseAddr (Pin); + if (Reg =3D=3D 0) { + return; + } + + GpioPin =3D Pin % GPIO_DWAPB_PINS_PER_CONTROLLER; + + Reg +=3D GPIO_SWPORTA_DR_ADDR; + DwapbGpioRead (Reg, &ReadVal); + + if (Val !=3D 0) { + DwapbGpioWrite (Reg, ReadVal | GPIO_MUX_VAL (GpioPin)); + } else { + DwapbGpioWrite (Reg, ReadVal & ~GPIO_MUX_VAL (GpioPin)); + } +} + +UINTN +EFIAPI +DwapbGpioReadBit ( + IN UINT32 Pin + ) +{ + UINT64 Reg; + UINT32 Val; + UINT32 GpioPin; + UINT8 Index; + UINT32 MaxIndex; + + Reg =3D GetBaseAddr (Pin); + if (Reg =3D=3D 0) { + return 0; + } + + GpioPin =3D Pin % GPIO_DWAPB_PINS_PER_CONTROLLER; + + /* Check if a base address is GPI */ + MaxIndex =3D sizeof (GpiBaseAddr) / sizeof (GpiBaseAddr[0]); + for (Index =3D 0; Index < MaxIndex; Index++) { + if (Reg =3D=3D GpiBaseAddr[Index]) { + break; + } + } + if (Index =3D=3D MaxIndex) { + /* Only GPIO has GPIO_EXT_PORTA register, not for GPI */ + Reg +=3D GPIO_EXT_PORTA_ADDR; + } + + DwapbGpioRead (Reg, &Val); + + return Val & GPIO_MUX_VAL (GpioPin) ? 1 : 0; +} + +EFI_STATUS +DwapbGpioConfig ( + IN UINT32 Pin, + IN UINT32 InOut + ) +{ + INTN GpioPin; + UINT32 Val; + UINT64 Reg; + + /* + * Caculate GPIO Pin Number for Direction Register + * GPIO_SWPORTA_DDR for GPIO[31...0] + * GPIO_SWPORTB_DDR for GPIO[51...32] + */ + + Reg =3D GetBaseAddr (Pin); + if (Reg =3D=3D 0) { + return EFI_UNSUPPORTED; + } + + Reg +=3D GPIO_SWPORTA_DDR_ADDR; + GpioPin =3D Pin % GPIO_DWAPB_PINS_PER_CONTROLLER; + DwapbGpioRead (Reg, &Val); + + if (InOut =3D=3D GPIO_OUT) { + Val |=3D GPIO_MUX_VAL (GpioPin); + } else { + Val &=3D ~GPIO_MUX_VAL (GpioPin); + } + DwapbGpioWrite (Reg, Val); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DwapbGPIOModeConfig ( + UINT8 Pin, + UINTN Mode + ) +{ + UINT32 NumberOfControllers =3D sizeof (GpioBaseAddr) / sizeof (UINT64); + UINT32 NumersOfPins =3D NumberOfControllers * GPIO_DWAPB_PINS_PER_CONTRO= LLER; + UINT32 Delay =3D 10; + + if (Mode < GPIO_CONFIG_OUT_LOW + || Mode >=3D MAX_GPIO_CONFIG_MODE + || Pin > NumersOfPins - 1 + || Pin < 0) { + return EFI_INVALID_PARAMETER; + } + + switch (Mode) { + case GPIO_CONFIG_OUT_LOW: + DwapbGpioConfig (Pin, GPIO_OUT); + DwapbGpioWriteBit (Pin, 0); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output low\n", Pin)); + break; + + case GPIO_CONFIG_OUT_HI: + DwapbGpioConfig (Pin, GPIO_OUT); + DwapbGpioWriteBit (Pin, 1); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output high\n", Pin)); + break; + + case GPIO_CONFIG_OUT_LOW_TO_HIGH: + DwapbGpioConfig (Pin, GPIO_OUT); + DwapbGpioWriteBit (Pin, 0); + MicroSecondDelay (1000 * Delay); + DwapbGpioWriteBit (Pin, 1); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output low->high\n", Pi= n)); + break; + + case GPIO_CONFIG_OUT_HIGH_TO_LOW: + DwapbGpioConfig (Pin, GPIO_OUT); + DwapbGpioWriteBit (Pin, 1); + MicroSecondDelay (1000 * Delay); + DwapbGpioWriteBit (Pin, 0); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output high->low\n", Pi= n)); + break; + + case GPIO_CONFIG_IN: + DwapbGpioConfig (Pin, GPIO_IN); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as input\n", Pin)); + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +/** + * 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 +GpioVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Count; + + EfiConvertPointer (0x0, (VOID**) &GpioBaseAddr); + for (Count =3D 0; Count < sizeof (GpioBaseAddr) / sizeof (GpioBaseAddr[0= ]); Count++) { + if (!GpioRuntimeEnableArray[Count]) { + continue; + } + EfiConvertPointer (0x0, (VOID**) &GpioBaseAddr[Count]); + } +} + +/** + Setup a controller that to be used in runtime service. + + @Bus: Bus ID. + @return: 0 for success. + Otherwise, error code. + **/ +EFI_STATUS +EFIAPI +DwapbGPIOSetupRuntime ( + IN UINT32 Pin + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + + if (GetBaseAddr (Pin) =3D=3D 0) { + 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, + GpioVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + } + + Status =3D gDS->GetMemorySpaceDescriptor ( + GetBaseAddr (Pin) & RUNTIME_ADDRESS_MASK, + &Descriptor + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gDS->SetMemorySpaceAttributes ( + GetBaseAddr (Pin) & RUNTIME_ADDRESS_MASK, + RUNTIME_ADDRESS_LENGTH, + Descriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + return Status; + } + + GpioRuntimeEnableArray[Pin / GPIO_DWAPB_PINS_PER_CONTROLLER] =3D TRUE; + + return Status; +} --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#68503): https://edk2.groups.io/g/devel/message/68503 Mute This Topic: https://groups.io/mt/78825484/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-