From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM10-DM6-obe.outbound.protection.outlook.com (NAM10-DM6-obe.outbound.protection.outlook.com [40.107.93.113]) by mx.groups.io with SMTP id smtpd.web08.237.1623775672538946939 for ; Tue, 15 Jun 2021 09:47:52 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@os.amperecomputing.com header.s=selector2 header.b=fHZym7o4; spf=pass (domain: os.amperecomputing.com, ip: 40.107.93.113, mailfrom: nhi@os.amperecomputing.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=adzwp/yDSd87hKYUkvfH84j24zt9eJQOMEpBW0eoLpCEqlzOhPSJPzZ/krk/9Omg3igHRtyDQk4V2MQAL6mcUJ3Q1gkVMeTUsgIZu0mNTpKHE3QxxSTT+/ATBdbGiX4A7c7MsDxPpHuEbm2JyiEs/HybRjtfGf6G76vmhbLZ0pzjQ3hhACdKIQCPP/op7oFS43RvcfCtrHYDd3UNwj2DESDVykZnTu9T4Obt6UcyA4bIEXcQH+bqBZL0zbXJvIbxQkK5P/STxADHNl4HH1tQHSThjsD91JyNW8L4HvIh0CQ3eg72VIHxhwx1EtlHnQ64k3uW6sxlUpZwgbze94WdRg== 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=tjI8gTQ3jTwN9w4xd1ipXrlmFVQ9OS7eRoCh1NpqdhI=; b=LzLUsYq178/m0YEF00GKnpNjURgpOJomZETTRkTGBYLDo+hb8mvvftnJg00SL1SfGEjKo97MUBljftWENvrYk897d6OtcV7UrYeXx1ASkSQSUBKzLSz3ogaixY+a8xqZbl/T1T458cq4f32WEMlLSV5Pd7F0Lur/pD2w7x3exkreCqJrABmUlJNQ+bC7ltsUr2gJiMai8iSD9H5dIhyxGNEr1Oyexhf5Bx+UT8w6gxrrJLUNaJw6XshXNvEiNXFfjXXzzy60+LLpv3pfHrleYySaSBdquiHcwPlqwqmTwIOpUAVT47BL601tjYPPIxaVz9EiF21qxIbcTG/Y5JhfIA== 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=tjI8gTQ3jTwN9w4xd1ipXrlmFVQ9OS7eRoCh1NpqdhI=; b=fHZym7o4j2F4vSyEwmQIp0zzQ5F8lJtBV1nzGpGCp6zEEvHXBtMHSNenqCHeFKV6ZCoJ5Y+Za5eg9GhKttkvND61hs4pA9z2JfRWQY0Wvo3qqCaZ02vFwfVhTLwuzde5JqsPPGur7n/7OXKVExa7wdW0DeQk2nRxqfxk3keDFdw= Authentication-Results: intel.com; dkim=none (message not signed) header.d=none;intel.com; dmarc=none action=none header.from=os.amperecomputing.com; Received: from DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) by DM5PR0101MB3147.prod.exchangelabs.com (2603:10b6:4:2e::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4195.30; Tue, 15 Jun 2021 16:47:50 +0000 Received: from DM6PR01MB5849.prod.exchangelabs.com ([fe80::4d8d:74e3:6747:75a2]) by DM6PR01MB5849.prod.exchangelabs.com ([fe80::4d8d:74e3:6747:75a2%7]) with mapi id 15.20.4219.025; Tue, 15 Jun 2021 16:47:50 +0000 Subject: Re: [edk2-platforms][PATCH v2 05/32] AmpereAltraPkg: Add DwI2cLib library To: Leif Lindholm Cc: devel@edk2.groups.io, Vu Nguyen , Thang Nguyen , Chuong Tran , Phong Vo , Michael D Kinney , Ard Biesheuvel , Nate DeSimone References: <20210526100724.5359-1-nhi@os.amperecomputing.com> <20210526100724.5359-7-nhi@os.amperecomputing.com> <20210604232141.asjuirz52gxvis7a@leviathan> From: "Nhi Pham" Message-ID: <4e4129b8-958f-db65-c3b0-56a609024acc@os.amperecomputing.com> Date: Tue, 15 Jun 2021 23:47:42 +0700 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 In-Reply-To: <20210604232141.asjuirz52gxvis7a@leviathan> X-Originating-IP: [116.110.40.240] X-ClientProxiedBy: HKAPR03CA0014.apcprd03.prod.outlook.com (2603:1096:203:c8::19) To DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) Return-Path: nhi@os.amperecomputing.com MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from [192.168.1.7] (116.110.40.240) by HKAPR03CA0014.apcprd03.prod.outlook.com (2603:1096:203:c8::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4242.9 via Frontend Transport; Tue, 15 Jun 2021 16:47:47 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 56b2f8fb-3856-4a38-26b1-08d9301d4ff7 X-MS-TrafficTypeDiagnostic: DM5PR0101MB3147: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:9508; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: /xJV1YR1LOSN8XFfDFKUGmBkKeywNAoRW0WbIALYbYr/aV9aE4UTsOCo4ZY3LjS4WeJT6kC9kSMR3ke9JYumpleiFiUTr8c5D4+YtuGk2T5VgbNYCjR/hrsL6T/VuzKiQw2+K5FRbCLNor5uokEV02bn/QSEAVJ8iY37GrUjY6tPMxbZ5CH9WMZ7VqMpilBSQZDLzejK2m0nLTSWDxwSg34y5AwLJbia7DyhTnMblmDgTy55F9Itx2tEyoW3AwQdnuDrLM7KCpC96MzEnczO3kBzYQ2oUXInBQqOZNvSMNRYfAvXf+QShCayB5imfUzZ5l3AoLzAh7WDv7VIZG+OSSgCGkYsETuRV3V6YuVQ0Le0UzZFtK3e0cnN03EqCP+Jvpvpypf9k6wqyYhUwYcCEAIsSItNTGM5UoHERd7m5/tEZfgAkGAj+Qrm3/ibbP6OEXfZbUXvHkSp0gw5m2eJF0+62HB1UjT5CCQsWO3jIlavYTYqccmTcijqq/5jDXzIlefQ+jDNf48GKseew0zrBnql+nK++xkPC15OFjzPJ6n85x9n4qA4+uNveNl6UdKRhCnp9uBscJisFUYf7XoiFAF6rUHZU4kobolyulJF5ssRY5Fdp9AXdHftYHWDrWjD7laZX7RuRDREWgFtajgZsWTEoUEWoiZpmNs4od5R/6ls75d4ATEIjnbyBqTykiL5DL83vR7g3Y3fp12v7Mx/peRjzbHRo29/7f4nkuIHiAk= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM6PR01MB5849.prod.exchangelabs.com;PTR:;CAT:NONE;SFS:(4636009)(136003)(366004)(346002)(39840400004)(396003)(376002)(8676002)(31686004)(26005)(52116002)(86362001)(38100700002)(6666004)(2906002)(316002)(16576012)(8936002)(4326008)(54906003)(6916009)(38350700002)(5660300002)(30864003)(6486002)(53546011)(66946007)(478600001)(31696002)(83380400001)(66556008)(186003)(19627235002)(16526019)(956004)(66476007)(2616005)(43740500002)(45980500001);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Y0FLMjVBWk9jZzNvVXNWWnpNQzlQUjd2Q0kzMmhraDdrUnZQSHhkc1Y1UFU0?= =?utf-8?B?QS9rTHkzVFJEbEZRT0hKSHVRSndoRkVtOERGY3lzU2FYeHc1ZEYveDFoYXpD?= =?utf-8?B?ejNYYm9Eb0JVUGUzOHRORy9rT0lNZzZ2bG52R1o2RkN0NHUrWlMwZUs3L3VP?= =?utf-8?B?VVJ5K2VmWVV0VWkzbjFHZndqU3ZWZ1dBeU5SOTlQRWtmcmNMSU54cTZ3NDF4?= =?utf-8?B?eGFXSC9BT25qd0NXMTVWS2Q3R0RDN3FuSnFoVDJFRU5nQkNZOXJkWWxpcURt?= =?utf-8?B?b1hKV2x0VVhMTklkMnR2Z1VtWW1sRmlPSE0yRWtCVm8rZjU1Mjg2SVdLeTh0?= =?utf-8?B?enlqNi9yMGEwSldhVUNzejlxQ1oxdzBBZnhBNU5sVEI1RHNwN2RGMzI0NWRj?= =?utf-8?B?cThDWmNybW4yVTlxQkNUSDBJNWpwUHFhQzhpc2dGRFordmpnMnJBdU5RUStl?= =?utf-8?B?MVNJU0FFTzdSRFJxNjdKd3haMWp1UWpLb3hvaWl2RGJwUkZiMGF3cUczaE5U?= =?utf-8?B?Q0hEdDJCTisybHByc2RkcG41NWh0QzREVDFDQk45NkFjakFkUXZxeU5JWitn?= =?utf-8?B?bE1SeFVkUmwwS0ZWenhUeFRrYzQ1S1NPL0FjMEV5NXpNak14RFF6RXl5M0kr?= =?utf-8?B?NWRmOUM4c3VtK2hhb3Z6OGFJdzVVajdTVWhZNDdCTHBJMEh3NG4xOU5FNy95?= =?utf-8?B?SkxQMVRhMXpFVy9sVGZUczdIQkl6UG15U1NwMjBoN24vK2FhVFplaWxubkZi?= =?utf-8?B?K0pZRUplbjFjQ283UnI0cnpyMWNlZDd4VnVRYlNEYmVSNklEMDZyRldjT3F0?= =?utf-8?B?bTVNdjI2SFhyQ1AzOUFpaTJSMUk5SnQzcDVPekp1RFdQSTlXb3E2c0hTaHND?= =?utf-8?B?N1pXOXA1cngxTlQyRFd5cnZwQ0NFTGRXSWtWQzhhZGxQUTNjVkw3dzNKdDZw?= =?utf-8?B?NE9jYlljK09BMDRsMytzNlpQeWluL3Mwd2RjUnRRRlp5RmUzV1hKRTJJR3lM?= =?utf-8?B?SUVoQmVoSUVyTTUwdHoweFdJR3U2ZTR0ME1UVWdndHVrUlBHWUYvK3h0UVNl?= =?utf-8?B?U0p4a2VnNVpib3Fya1grM2JSSS9RaWFLaC9leE1ublRSbHBXMTNRTlV3R1Qz?= =?utf-8?B?WnY2aTR4UVZIeDB6cDNJb3hUZHNRVEZWSzM4SGtNZ25sVFU2bWJQWWxKVWxI?= =?utf-8?B?YjBySjdNZ2c3Vk9LN09UYTVodGRwendSQUJDYURSalh0K3VTZUUvZS95UTFl?= =?utf-8?B?YVlJSHFETHFqSGtpVXpJQkxidjlRcmo1T3FwRS9FSWc4WHdMTTJuS1ZBWnJl?= =?utf-8?B?NTlnTlhWb3IvQ3F2dXM2S0RYVzFFQjU3TjBUUTJmM21KOFRPa2tsRFNDbmFO?= =?utf-8?B?ZHRNYms3ZDFhRmttcm9mTmlieVBBcG5PMkpMQXViOCtsOFhrRlZMOUtFdDI3?= =?utf-8?B?Q0N0a2EvU1dROEVIbWhTemx5eWMrQ3V2Z253Z21DOHhVZHpHK1RyOXZrcXBi?= =?utf-8?B?M2loRURBT1UzYXVVcjB4dU1TVGF3TkdCWmNKd3N2SmZpR1M4THIvVXRpbVk2?= =?utf-8?B?ZEJHNjRwbVJSNUFxcHRjMk5qT3lOOW1WdVZrWUYrdXRyWUVTc2pFZERLbTBE?= =?utf-8?B?UzNSajFOS09QYWVKYTZYYXFMdllQdjBOaTcreWpsS1U0RUpDUjFXUC9Zdlo4?= =?utf-8?B?bkZFU0dFc241c1hwZnZCNEtRTGd6L3drdldYKzJaaEk2MmFzeGkwY3U0T2lG?= =?utf-8?Q?4braambLf+cQok+2rW2Q63Nslnl0mMVSOkz26q6?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: 56b2f8fb-3856-4a38-26b1-08d9301d4ff7 X-MS-Exchange-CrossTenant-AuthSource: DM6PR01MB5849.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 Jun 2021 16:47:50.6686 (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: 4fAtWRpBJPgwUrTrDERRgF+1xn+yX4T+o4Nss9LKTwTjPChYdHaEJEVzTp8S1Mxd77HA+KCh8B/5jK+esF1B8Ww/8s3/uRl43IHOJGDfsCg= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR0101MB3147 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-US On 6/5/21 06:21, Leif Lindholm wrote: > On Wed, May 26, 2021 at 17:06:57 +0700, Nhi Pham wrote: >> 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: Vu Nguyen > Reviewed-by: Leif Lindholm > (but I think this was one of the ones that have issues that should be > addressed - please ensure build with CLANG38 before v3) Thanks, Leif. I will fix the clang compilation issues in the v3. Best regards, Nhi > > / > Leif > >> --- >> 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/Library/DwI2cLib/DwI2cLib.c | 883 ++++++++++++++++++++ >> 4 files changed, 1024 insertions(+) >> >> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec >> index 73097afaf841..8be6a329bb26 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 >> >> + ## @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 parition over MM interface. >> MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h >> >> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf >> new file mode 100644 >> index 000000000000..091f5f9b310c >> --- /dev/null >> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf >> @@ -0,0 +1,38 @@ >> +## @file >> +# Component description for DwI2cLib library for the Designware I2C controller. >> +# >> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
>> +# >> +# SPDX-License-Identifier: BSD-2-Clause-Patent >> +# >> +## >> + >> +[Defines] >> + INF_VERSION = 0x0001001B >> + BASE_NAME = DwI2cLib >> + FILE_GUID = 222609E2-C181-11E6-A4A6-CEC0C932CE01 >> + MODULE_TYPE = BASE >> + VERSION_STRING = 1.0 >> + LIBRARY_CLASS = I2cLib >> + CONSTRUCTOR = 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 >> + gPlatformHobGuid >> diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h b/Silicon/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/Library/DwI2cLib/DwI2cLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c >> new file mode 100644 >> index 000000000000..5e7cd020223c >> --- /dev/null >> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c >> @@ -0,0 +1,883 @@ >> +/** @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 >> +#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 = 0, >> + I2cSpeedModeFast, >> +} I2C_SPEED_MODE; >> + >> +#define DW_I2C_MAXIMUM_SPEED_HZ 400000 >> + >> +typedef enum { >> + I2cSclSpkLen = 0, >> + I2cSclHcnt, >> + I2cSclLcnt, >> +} I2C_SCL_PARAM; >> + >> +STATIC UINT32 I2cSclParam[][3] = { >> + /* SPK_LEN, HCNT, LCNT */ >> + [I2cSpeedModeStandard] = { 10, 0x3E2, 0x47D }, // SS (Standard Speed) >> + [I2cSpeedModeFast] = { 10, 0xA4, 0x13F }, // FS (Fast Speed) >> +}; >> + >> +STATIC BOOLEAN mI2cRuntimeEnableArray[MAX_PLATFORM_I2C_BUS_NUM] = {FALSE}; >> +STATIC UINTN mI2cBaseArray[MAX_PLATFORM_I2C_BUS_NUM] = {PLATFORM_I2C_REGISTER_BASE}; >> +STATIC DW_I2C_CONTEXT_T mI2cBusList[MAX_PLATFORM_I2C_BUS_NUM]; >> +STATIC UINTN mI2cClock = 0; >> +STATIC EFI_EVENT mVirtualAddressChangeEvent = 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 = mI2cBaseArray[Bus]; >> + >> + Param = MmioRead32 (mI2cBusList[Bus].Base + DW_IC_COMP_PARAM_1); >> + >> + mI2cBusList[Bus].PollingTime = DW_POLL_INTERVAL_US (mI2cBusList[Bus].BusSpeed); >> + mI2cBusList[Bus].RxFifo = DW_IC_COMP_PARAM_1_RX_BUFFER_DEPTH (Param); >> + mI2cBusList[Bus].TxFifo = DW_IC_COMP_PARAM_1_TX_BUFFER_DEPTH (Param); >> + mI2cBusList[Bus].Enabled = 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 = mI2cBusList[Bus].Base; >> + I2cStatusCnt = DW_MAX_STATUS_POLL_COUNT; >> + mI2cBusList[Bus].Enabled = Enable; >> + >> + MmioWrite32 (Base + DW_IC_ENABLE, Enable); >> + >> + do { >> + if ((MmioRead32 (Base + DW_IC_ENABLE_STATUS) & 0x01) == Enable) { >> + break; >> + } >> + MicroSecondDelay (mI2cBusList[Bus].PollingTime); >> + } while (I2cStatusCnt-- != 0); >> + >> + if (I2cStatusCnt == 0) { >> + DEBUG ((DEBUG_ERROR, "%a: Enable/disable timeout\n", __FUNCTION__)); >> + } >> + >> + if ((Enable == 0) || (I2cStatusCnt == 0)) { >> + /* Unset the target adddress */ >> + MmioWrite32 (Base + DW_IC_TAR, 0); >> + mI2cBusList[Bus].Enabled = 0; >> + } >> +} >> + >> +/** >> + Setup Slave address >> + **/ >> +VOID >> +I2cSetSlaveAddr ( >> + UINT32 Bus, >> + UINT32 SlaveAddr >> + ) >> +{ >> + UINTN Base; >> + UINT32 OldEnableStatus; >> + >> + Base = mI2cBusList[Bus].Base; >> + OldEnableStatus = mI2cBusList[Bus].Enabled; >> + >> + I2cEnable (Bus, 0); >> + MmioWrite32 (Base + DW_IC_TAR, SlaveAddr); >> + if (OldEnableStatus != 0) { >> + I2cEnable (Bus, 1); >> + } >> +} >> + >> +/** >> + Check for errors on I2C Bus >> + **/ >> +UINT32 >> +I2cCheckErrors ( >> + UINT32 Bus >> + ) >> +{ >> + UINTN Base; >> + UINT32 ErrorStatus; >> + >> + Base = mI2cBusList[Bus].Base; >> + >> + ErrorStatus = MmioRead32 (Base + DW_IC_RAW_INTR_STAT) & DW_IC_ERR_CONDITION; >> + >> + if ((ErrorStatus & DW_IC_INTR_RX_UNDER) != 0) { >> + DEBUG ((DEBUG_ERROR, "%a: RX_UNDER error on i2c bus %d error status %08x\n", >> + __FUNCTION__, >> + Bus, >> + ErrorStatus >> + )); >> + MmioRead32 (Base + DW_IC_CLR_RX_UNDER); >> + } >> + >> + if ((ErrorStatus & DW_IC_INTR_RX_OVER) != 0) { >> + DEBUG ((DEBUG_ERROR, "%a: RX_OVER error on i2c bus %d error status %08x\n", >> + __FUNCTION__, >> + Bus, >> + ErrorStatus >> + )); >> + MmioRead32 (Base + DW_IC_CLR_RX_OVER); >> + } >> + >> + if ((ErrorStatus & DW_IC_INTR_TX_ABRT) != 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 = mI2cBusList[Bus].Base; >> + PollCount = DW_MAX_MST_ACTIVITY_POLL_COUNT; >> + >> + while ((MmioRead32 (Base + DW_IC_STATUS) & DW_IC_STATUS_MST_ACTIVITY) != 0) { >> + if (PollCount == 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 implementation. >> + */ >> + 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 = mI2cBusList[Bus].Base; >> + PollCount = 0; >> + >> + while (MmioRead32 (Base + DW_IC_TXFLR) == mI2cBusList[Bus].TxFifo) { >> + if (PollCount++ >= 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 = mI2cBusList[Bus].Base; >> + PollCount = 0; >> + >> + while ((MmioRead32 (Base + DW_IC_STATUS) & DW_IC_STATUS_RFNE) == 0) { >> + if (PollCount++ >= 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) != 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 Fast Speed (FS) mode. >> + **/ >> +VOID >> +I2cSclInit ( >> + UINT32 Bus, >> + UINT32 I2cClkFreq, >> + UINT32 I2cSpeed >> + ) >> +{ >> + UINT16 IcCon; >> + UINTN Base; >> + UINT32 I2cSpeedKhz; >> + >> + Base = mI2cBusList[Bus].Base; >> + I2cSpeedKhz = I2cSpeed / 1000; >> + >> + DEBUG ((DEBUG_VERBOSE, "%a: Bus %d I2cClkFreq %d I2cSpeed %d\n", >> + __FUNCTION__, >> + Bus, >> + I2cClkFreq, >> + I2cSpeed >> + )); >> + >> + IcCon = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART_EN; >> + >> + if (I2cSpeedKhz <= 100) { >> + IcCon |= 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[I2cSpeedModeStandard][I2cSclHcnt]); >> + MmioWrite32 (Base + DW_IC_SS_SCL_LCNT, I2cSclParam[I2cSpeedModeStandard][I2cSclLcnt]); >> + } else if (I2cSpeedKhz > 100 && I2cSpeedKhz <= 400) { >> + IcCon |= DW_IC_CON_SPEED_FAST; >> + // Fast speed mode >> + MmioWrite32 (Base + DW_IC_FS_SPKLEN, I2cSclParam[I2cSpeedModeFast][I2cSclSpkLen]); >> + MmioWrite32 (Base + DW_IC_FS_SCL_HCNT, I2cSclParam[I2cSpeedModeFast][I2cSclHcnt]); >> + MmioWrite32 (Base + DW_IC_FS_SCL_LCNT, I2cSclParam[I2cSpeedModeFast][I2cSclLcnt]); >> + } >> + MmioWrite32 (Base + DW_IC_CON, IcCon); >> +} >> + >> +/** >> + Initialize the designware i2c master hardware >> + **/ >> +EFI_STATUS >> +I2cInit ( >> + UINT32 Bus, >> + UINTN BusSpeed >> + ) >> +{ >> + UINTN Base; >> + >> + ASSERT (mI2cClock != 0); >> + >> + mI2cBusList[Bus].BusSpeed = BusSpeed; >> + I2cHWInit (Bus); >> + >> + Base = 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 = mI2cBusList[Bus].Base; >> + PollCount = 0; >> + >> + /* Wait for TX FIFO empty */ >> + do { >> + if ((MmioRead32 (Base + DW_IC_STATUS) & DW_IC_STATUS_TFE) != 0) { >> + break; >> + } >> + MicroSecondDelay (mI2cBusList[Bus].PollingTime); >> + } while (PollCount++ < DW_MAX_TRANSFER_POLL_COUNT); >> + >> + if (PollCount >= DW_MAX_TRANSFER_POLL_COUNT) { >> + DEBUG ((DEBUG_ERROR, "%a: Timeout waiting for TX FIFO empty\n", __FUNCTION__)); >> + return EFI_TIMEOUT; >> + } >> + >> + /* Wait for STOP signal detected on the bus */ >> + PollCount = 0; >> + do { >> + if ((MmioRead32 (Base + DW_IC_RAW_INTR_STAT) & DW_IC_INTR_STOP_DET) != 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 = EFI_SUCCESS; >> + Base = mI2cBusList[Bus].Base; >> + >> + DEBUG ((DEBUG_VERBOSE, "%a: Write Bus %d Buf %p Length %d\n", >> + __FUNCTION__, >> + Bus, >> + Buf, >> + *Length >> + )); >> + I2cEnable (Bus, 1); >> + >> + WriteCount = 0; >> + while ((*Length - WriteCount) != 0) { >> + Status = I2cWaitTxData (Bus); >> + if (EFI_ERROR (Status)) { >> + MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); >> + I2cSync (); >> + goto Exit; >> + } >> + >> + if (WriteCount == *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 = 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 = EFI_SUCCESS; >> + Base = mI2cBusList[Bus].Base; >> + Count = 0; >> + >> + DEBUG ((DEBUG_VERBOSE, "%a: Read Bus %d Buf %p Length:%d\n", >> + __FUNCTION__, >> + Bus, >> + Buf, >> + *Length >> + )); >> + >> + I2cEnable (Bus, 1); >> + >> + /* Write command data */ >> + WriteCount = 0; >> + while (CmdLength != 0) { >> + TxLimit = mI2cBusList[Bus].TxFifo - MmioRead32 (Base + DW_IC_TXFLR); >> + Count = CmdLength > TxLimit ? TxLimit : CmdLength; >> + >> + for (Idx = 0; Idx < Count; Idx++ ) { >> + CmdSend = BufCmd[WriteCount++] & DW_IC_DATA_CMD_DAT_MASK; >> + MmioWrite32 (Base + DW_IC_DATA_CMD, CmdSend); >> + I2cSync (); >> + >> + if (I2cCheckErrors (Bus) != 0) { >> + Status = EFI_CRC_ERROR; >> + goto Exit; >> + } >> + CmdLength--; >> + } >> + >> + Status = I2cWaitTxData (Bus); >> + if (EFI_ERROR (Status)) { >> + MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); >> + I2cSync (); >> + goto Exit; >> + } >> + } >> + >> + ReadCount = 0; >> + WriteCount = 0; >> + while ((*Length - ReadCount) != 0) { >> + TxLimit = mI2cBusList[Bus].TxFifo - MmioRead32 (Base + DW_IC_TXFLR); >> + RxLimit = mI2cBusList[Bus].RxFifo - MmioRead32 (Base + DW_IC_RXFLR); >> + Count = *Length - ReadCount; >> + Count = Count > RxLimit ? RxLimit : Count; >> + Count = Count > TxLimit ? TxLimit : Count; >> + >> + for (Idx = 0; Idx < Count; Idx++ ) { >> + CmdSend = DW_IC_DATA_CMD_CMD; >> + if (WriteCount == *Length - 1) { >> + CmdSend |= DW_IC_DATA_CMD_STOP; >> + } >> + MmioWrite32 (Base + DW_IC_DATA_CMD, CmdSend); >> + I2cSync (); >> + WriteCount++; >> + >> + if (I2cCheckErrors (Bus) != 0) { >> + DEBUG ((DEBUG_VERBOSE, >> + "%a: Sending reading command remaining length %d CRC error\n", >> + __FUNCTION__, >> + *Length >> + )); >> + Status = EFI_CRC_ERROR; >> + goto Exit; >> + } >> + } >> + >> + for (Idx = 0; Idx < Count; Idx++ ) { >> + Status = I2cWaitRxData (Bus); >> + if (EFI_ERROR (Status)) { >> + DEBUG ((DEBUG_VERBOSE, >> + "%a: Reading remaining length %d failed to wait data\n", >> + __FUNCTION__, >> + *Length >> + )); >> + >> + if (Status != EFI_ABORTED) { >> + MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP); >> + I2cSync (); >> + } >> + >> + goto Exit; >> + } >> + >> + Buf[ReadCount++] = MmioRead32 (Base + DW_IC_DATA_CMD) & DW_IC_DATA_CMD_DAT_MASK; >> + I2cSync (); >> + >> + if (I2cCheckErrors (Bus) != 0) { >> + DEBUG ((DEBUG_VERBOSE, "%a: Reading remaining length %d CRC error\n", >> + __FUNCTION__, >> + *Length >> + )); >> + Status = EFI_CRC_ERROR; >> + goto Exit; >> + } >> + } >> + } >> + >> +Exit: >> + *Length = 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 >= MAX_PLATFORM_I2C_BUS_NUM >> + || Buf == NULL >> + || WriteLength == 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 >= MAX_PLATFORM_I2C_BUS_NUM >> + || Buf == NULL >> + || ReadLength == 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 >= MAX_PLATFORM_I2C_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_ADDRESS_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 = 0; Count < MAX_PLATFORM_I2C_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 >= MAX_PLATFORM_I2C_BUS_NUM) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + if (mVirtualAddressChangeEvent == NULL) { >> + /* >> + * Register for the virtual address change event >> + */ >> + Status = gBS->CreateEventEx ( >> + EVT_NOTIFY_SIGNAL, >> + TPL_NOTIFY, >> + I2cVirtualAddressChangeEvent, >> + NULL, >> + &gEfiEventVirtualAddressChangeGuid, >> + &mVirtualAddressChangeEvent >> + ); >> + ASSERT_EFI_ERROR (Status); >> + } >> + >> + Status = gDS->GetMemorySpaceDescriptor ( >> + mI2cBaseArray[Bus] & RUNTIME_ADDRESS_MASK, >> + &Descriptor >> + ); >> + if (EFI_ERROR (Status)) { >> + return Status; >> + } >> + >> + Status = gDS->SetMemorySpaceAttributes ( >> + mI2cBaseArray[Bus] & RUNTIME_ADDRESS_MASK, >> + RUNTIME_ADDRESS_LENGTH, >> + Descriptor.Attributes | EFI_MEMORY_RUNTIME >> + ); >> + if (EFI_ERROR (Status)) { >> + return Status; >> + } >> + >> + mI2cRuntimeEnableArray[Bus] = TRUE; >> + >> + return Status; >> +} >> + >> +EFI_STATUS >> +EFIAPI >> +I2cLibConstructor ( >> + VOID >> + ) >> +{ >> + VOID *Hob; >> + PLATFORM_INFO_HOB *PlatformHob; >> + >> + /* Get I2C Clock from the Platform HOB */ >> + Hob = GetFirstGuidHob (&gPlatformHobGuid); >> + if (Hob == NULL) { >> + return EFI_NOT_FOUND; >> + } >> + PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob); >> + mI2cClock = PlatformHob->AhbClk; >> + ASSERT (mI2cClock != 0); >> + >> + return EFI_SUCCESS; >> +} >> -- >> 2.17.1 >>