From patchwork Fri Nov 10 14:21:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 118565 Delivered-To: patch@linaro.org Received: by 10.80.225.132 with SMTP id k4csp2260302edl; Fri, 10 Nov 2017 06:24:22 -0800 (PST) X-Google-Smtp-Source: AGs4zMaeqS5cIqAd6QBa87dLVNMB+Ngc2DZmD1mpnM2cIqWkm+8YHOVvSHwgJQSVNbJR9ZRL/ao+ X-Received: by 10.84.214.150 with SMTP id j22mr541716pli.408.1510323862007; Fri, 10 Nov 2017 06:24:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1510323862; cv=none; d=google.com; s=arc-20160816; b=XKw4XkmKCLCiDZIVT1ESneM2h4BJX/4n204/fg0n0gu2AeHr/lAIllAQjMldfFrKvM gSTcdKy9P3N0GgaqQsU5VHBW/GNZG54vJGnakkWVgqVYsQz4DkhPKwCraEsMthna8FpY buwwzKebgglOmhHAMpgP7bA2fkmKOEHuIQgcLNgjvnb60AZE4kmGq5A0Lxvu+0yfBlQU SXt2BRybWnfXfn3tYkDbPdvtvcIx5+5jJTv7gKl3Jv5tQ1DeUtzVo8t/P8xxOrNtFCPs k+KkSwUj3KTYFk4HjjfHRxF8mEpUPTJ6UDIGwpgsxqpV9gXbja6j1G67yK0dY4EjeS68 TX4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=m6nNSM6WB0GxTknJfRQJkSETUrgnOcXsCjNFhG5KQGk=; b=IiL0dJXzfyhR5c3oI30v4IsTLnUWZjvK6P0IH3xHE6452X0Hc6CBSMdoArMhZ8mbq2 PuaxsDC9pGT8hbURtu7AZYXVvNqs8Bk2mnZCiVwKjyx15e1PRXMwJcOeGatDcpq52CiH cxBPKZMzdQkzMZD5cDc6Z5nqblS4qoCN7u098E9PfHAiy70khXQu5BX8f0uq5IstH9Na 3x0qSQnBk8MrBhq+dNMoDrqJ1MzhpW8v33lKa8Baw4Dg/aKgc9em0V7XNeuLmfgSfgWb mr7IzBIDjiD5zod62WLT5zhWTL6LJYh6S9jNZGhNEHNUGREPiEowkgk4cpC+JGtOXMdV N5xQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=YJ0ixxKF; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id a14si5221672pgv.479.2017.11.10.06.24.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Nov 2017 06:24:21 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=YJ0ixxKF; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 8E03821C913C7; Fri, 10 Nov 2017 06:19:08 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:400c:c0c::22f; helo=mail-wr0-x22f.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-wr0-x22f.google.com (mail-wr0-x22f.google.com [IPv6:2a00:1450:400c:c0c::22f]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 2EADA21C913BF for ; Fri, 10 Nov 2017 06:19:06 -0800 (PST) Received: by mail-wr0-x22f.google.com with SMTP id j23so8740779wra.9 for ; Fri, 10 Nov 2017 06:23:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=m7AYTN9pbZbAewJXHaZ4Mfagc+ryWhmyd0nb82FjVBU=; b=YJ0ixxKFj51uyADfaBzKbW4lfHXg4sgNbrThclpzmlhdKbF0C7gKS/+uVHfxRiC1ot g7UGsMKLsOj+Qznh4iB6zpd1lRgfEn4lMxUx8O3isIshc/nktqmgwXa51dUlzZZg2JZZ S8FC2DCQCd3L3OmtlOP3WE39udTBgsMrPsmUc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=m7AYTN9pbZbAewJXHaZ4Mfagc+ryWhmyd0nb82FjVBU=; b=GILP81w8P3adOfi1MiOSzd5uIgRwSNwQHc4qUCNBQIkp3+3reqfHQPBxuzJ0QfBpop 3cEpqA6fHVmXgeHeM47IqMG03DzTU9K5vQcZqFICLFLUS4kZCO35JkwWOFlBZI5YuLhP 0MNQ3z1FNkfGu6sqYF3OwX5NK6uHJeetqtnSoqn8H+P2xSaXInf7b35gb87mf+5HiKBN LIHXlWoa02TtT2lXtFZr3xLUBb51j1fSIyYFm2zQ+mMA7Qn/RhfJ7MPEk+BMU10TIS+1 zLeOfL6cG+R/8v0UtH8d0uik51mbxFiYY1wqQ8npDnuv85LqigMV/81FhP6IPlymlop3 hv0w== X-Gm-Message-State: AJaThX4INrtEGPBmhVT7oiWxy/0mJtPk6uE1sxwIXZ88xCJpRRE1Eo01 1ggsBAFNyWDZRDd+jNNL06hR4+BqLC0= X-Received: by 10.223.185.121 with SMTP id b54mr458772wrg.264.1510323786851; Fri, 10 Nov 2017 06:23:06 -0800 (PST) Received: from localhost.localdomain ([160.167.170.128]) by smtp.gmail.com with ESMTPSA id e131sm1036477wmg.15.2017.11.10.06.23.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Nov 2017 06:23:06 -0800 (PST) From: Ard Biesheuvel To: edk2-devel@lists.01.org, leif.lindholm@linaro.org, daniel.thompson@linaro.org Date: Fri, 10 Nov 2017 14:21:24 +0000 Message-Id: <20171110142127.12018-32-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171110142127.12018-1-ard.biesheuvel@linaro.org> References: <20171110142127.12018-1-ard.biesheuvel@linaro.org> Subject: [edk2] [PATCH edk2-platforms v4 31/34] Silicon/Socionext: implement I2C master protocol for SynQuacer I2C X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: masahisa.kojima@linaro.org, masami.hiramatsu@linaro.org, Ard Biesheuvel MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" Add a driver that produces the I2C master protocol on top of the I2C controllers that are implemented in the SynQuacer Socionext SoC. Note that this supports two modes simultaneously: I2C controllers that are only usable at boot time, and usable via the I2C protocol stack, and I2C controllers that are dedicated for the RTC or other runtime components. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel --- Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/ComponentName.c | 185 ++++++ Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/DriverBinding.c | 238 ++++++++ Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c | 586 ++++++++++++++++++++ Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.h | 162 ++++++ Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.inf | 59 ++ Silicon/Socionext/SynQuacer/SynQuacer.dec | 5 + 6 files changed, 1235 insertions(+) -- 2.11.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/ComponentName.c b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/ComponentName.c new file mode 100644 index 000000000000..8d7aa417505b --- /dev/null +++ b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/ComponentName.c @@ -0,0 +1,185 @@ +/** @file + + Copyright (c) 2017, Linaro Ltd. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SynQuacerI2cDxe.h" + +STATIC EFI_UNICODE_STRING_TABLE mSynQuacerI2cDriverNameTable[] = { + { + "en", + (CHAR16 *)L"Socionext SynQuacer I2C Driver" + }, + { } +}; + +STATIC EFI_UNICODE_STRING_TABLE mSynQuacerI2cControllerNameTable[] = { + { + "en", + (CHAR16 *)L"Socionext SynQuacer I2C Controller" + }, + { } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cGetDriverName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 (Language, + This->SupportedLanguages, + mSynQuacerI2cDriverNameTable, + DriverName, + FALSE); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString2 (Language, + This->SupportedLanguages, + mSynQuacerI2cControllerNameTable, + ControllerName, + FALSE); +} + +// +// EFI Component Name 2 Protocol +// +EFI_COMPONENT_NAME2_PROTOCOL gSynQuacerI2cDriverComponentName2 = { + SynQuacerI2cGetDriverName, + SynQuacerI2cGetControllerName, + "en" +}; diff --git a/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/DriverBinding.c b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/DriverBinding.c new file mode 100644 index 000000000000..22e53408f419 --- /dev/null +++ b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/DriverBinding.c @@ -0,0 +1,238 @@ +/** @file + + Copyright (c) 2017, Linaro Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD + License which accompanies this distribution. The full text of the license may + be found at http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SynQuacerI2cDxe.h" + +/** + Tests to see if this driver supports a given controller. + + @param This[in] A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param ControllerHandle[in] The handle of the controller to test. + @param RemainingDevicePath[in] The remaining device path. + (Ignored - this is not a bus driver.) + + @retval EFI_SUCCESS The driver supports this controller. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle is + already being managed by the driver specified + by This. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle is + not supported by the driver specified by This. + +**/ +EFI_STATUS +EFIAPI +SynQuacerI2cDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + NON_DISCOVERABLE_DEVICE *Dev; + EFI_STATUS Status; + + // + // Connect to the USB stack + // + Status = gBS->OpenProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + (VOID **) &Dev, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CompareGuid (Dev->Type, &gSynQuacerNonDiscoverableI2cMasterGuid) || + CompareGuid (Dev->Type, &gSynQuacerNonDiscoverableRuntimeI2cMasterGuid)) { + Status = EFI_SUCCESS; + } else { + Status = EFI_UNSUPPORTED; + } + + // + // Clean up. + // + gBS->CloseProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + This->DriverBindingHandle, + ControllerHandle); + + return Status; +} + + +/** + Starts a device controller or a bus controller. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle The handle of the device to start. This + handle must support a protocol interface that + supplies an I/O abstraction to the driver. + @param[in] RemainingDevicePath The remaining portion of the device path. + (Ignored - this is not a bus driver.) + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a + device error. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + +**/ +EFI_STATUS +EFIAPI +SynQuacerI2cDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return SynQuacerI2cInit (This->DriverBindingHandle, ControllerHandle); +} + + +/** + Stops a device controller or a bus controller. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle + must support a bus specific I/O protocol for the + driver to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in + ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be + NULL if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device + error. + +**/ +EFI_STATUS +EFIAPI +SynQuacerI2cDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + return SynQuacerI2cRelease (This->DriverBindingHandle, ControllerHandle); +} + + +STATIC EFI_DRIVER_BINDING_PROTOCOL gSynQuacerI2cDriverBinding = { + SynQuacerI2cDriverBindingSupported, + SynQuacerI2cDriverBindingStart, + SynQuacerI2cDriverBindingStop, + 0xa, + NULL, + NULL +}; + + +/** + The entry point of I2c UEFI Driver. + + @param ImageHandle The image handle of the UEFI Driver. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The Driver or UEFI Driver exited normally. + @retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than + SystemTable->Hdr.Revision. + +**/ +EFI_STATUS +EFIAPI +SynQuacerI2cDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Add the driver to the list of drivers + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, SystemTable, &gSynQuacerI2cDriverBinding, ImageHandle, + NULL, &gSynQuacerI2cDriverComponentName2); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "*** Installed SynQuacer I2C UEFI driver! ***\n")); + + return EFI_SUCCESS; +} + + +/** + Unload function for the I2c UEFI Driver. + + @param ImageHandle[in] The allocated handle for the EFI image + + @retval EFI_SUCCESS The driver was unloaded successfully + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. + +**/ +EFI_STATUS +EFIAPI +SynQuacerI2cDxeUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + + // + // Retrieve all USB I/O handles in the handle database + // + Status = gBS->LocateHandleBuffer (ByProtocol, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Disconnect the driver from the handles in the handle database + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->DisconnectController (HandleBuffer[Index], + gImageHandle, + NULL); + } + + // + // Free the handle array + // + gBS->FreePool (HandleBuffer); + + // + // Uninstall protocols installed by the driver in its entrypoint + // + Status = gBS->UninstallMultipleProtocolInterfaces (ImageHandle, + &gEfiDriverBindingProtocolGuid, + &gSynQuacerI2cDriverBinding, + NULL + ); + + return EFI_SUCCESS; +} diff --git a/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c new file mode 100644 index 000000000000..0a2d0528e0a7 --- /dev/null +++ b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c @@ -0,0 +1,586 @@ +/** @file + + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SynQuacerI2cDxe.h" + +#define __DEBUG(x) do { if (!EfiAtRuntime()) DEBUG (x); } while (0) + +// +// We cannot use Stall () or timer events at runtime, so we need to busy-wait +// for the controller to signal the completion interrupts. This value was +// arbitrarily chosen, and does not appear to produce any premature timeouts +// nor does it result in noticeable stalls in case of bus errors. +// +#define WAIT_FOR_INTERRUPT_TIMEOUT 50000 + +/** + Set the frequency for the I2C clock line. + + This routine must be called at or below TPL_NOTIFY. + + The software and controller do a best case effort of using the specified + frequency for the I2C bus. If the frequency does not match exactly then + the I2C master protocol selects the next lower frequency to avoid + exceeding the operating conditions for any of the I2C devices on the bus. + For example if 400 KHz was specified and the controller's divide network + only supports 402 KHz or 398 KHz then the I2C master protocol selects 398 + KHz. If there are not lower frequencies available, then return + EFI_UNSUPPORTED. + + @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure + @param[in] BusClockHertz Pointer to the requested I2C bus clock frequency + in Hertz. Upon return this value contains the + actual frequency in use by the I2C controller. + + @retval EFI_SUCCESS The bus frequency was set successfully. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_INVALID_PARAMETER BusClockHertz is NULL + @retval EFI_UNSUPPORTED The controller does not support this frequency. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cSetBusFrequency ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN OUT UINTN *BusClockHertz + ) +{ + SYNQUACER_I2C_MASTER *I2c; + UINT8 Ccr, Csr; + + I2c = SYNQUACER_I2C_FROM_THIS (This); + + if (BusClockHertz == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*BusClockHertz >= F_I2C_SPEED_FM) { + if (REFCLK_RATE <= F_I2C_CLK_RATE_18M) { + Ccr = F_I2C_CCR_CS_FAST_MAX_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_FAST_MAX_18M (REFCLK_RATE); + } else { + Ccr = F_I2C_CCR_CS_FAST_MIN_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_FAST_MIN_18M (REFCLK_RATE); + } + + // Set Clock and enable, Set fast mode + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, + Ccr | F_I2C_CCR_FM | F_I2C_CCR_EN); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, Csr); + + *BusClockHertz = F_I2C_SPEED_FM; + + } else if (*BusClockHertz >= F_I2C_SPEED_SM) { + if (REFCLK_RATE <= F_I2C_CLK_RATE_18M) { + Ccr = F_I2C_CCR_CS_STANDARD_MAX_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_STANDARD_MAX_18M (REFCLK_RATE); + } else { + Ccr = F_I2C_CCR_CS_STANDARD_MIN_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_STANDARD_MIN_18M (REFCLK_RATE); + } + + // Set Clock and enable, Set standard mode + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, Ccr | F_I2C_CCR_EN); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, Csr); + + *BusClockHertz = F_I2C_SPEED_SM; + } else { + return EFI_UNSUPPORTED; + } + + MemoryFence (); + + return EFI_SUCCESS; +} + +/** + Reset the I2C controller and configure it for use + + This routine must be called at or below TPL_NOTIFY. + + The I2C controller is reset. The caller must call SetBusFrequench() after + calling Reset(). + + @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure. + + @retval EFI_SUCCESS The reset completed successfully. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_DEVICE_ERROR The reset operation failed. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cReset ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This + ) +{ + SYNQUACER_I2C_MASTER *I2c; + + I2c = SYNQUACER_I2C_FROM_THIS (This); + + // Disable the clock + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, 0); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, 0); + + MemoryFence (); + + // Set own Address + MmioWrite8 (I2c->MmioBase + F_I2C_REG_ADR, 0); + + // Set PCLK frequency + MmioWrite8 (I2c->MmioBase + F_I2C_REG_FSR, F_I2C_BUS_CLK_FR (REFCLK_RATE)); + + // clear IRQ (INT=0, BER=0), Interrupt Disable + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, 0); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BC2R, 0); + + MemoryFence (); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SynQuacerI2cMasterStart ( + IN SYNQUACER_I2C_MASTER *I2c, + IN UINTN SlaveAddress, + IN EFI_I2C_OPERATION *Op + ) +{ + UINT8 Bsr; + UINT8 Bcr; + + if (Op->Flags & I2C_FLAG_READ) { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, (SlaveAddress << 1) | 1); + } else { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, SlaveAddress << 1); + } + + __DEBUG ((DEBUG_INFO, "%a: slave:0x%02x\n", __FUNCTION__, SlaveAddress)); + + Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR); + Bcr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); + + if ((Bsr & F_I2C_BSR_BB) && !(Bcr & F_I2C_BCR_MSS)) { + __DEBUG ((DEBUG_INFO, "%a: bus is busy\n", __FUNCTION__)); + return EFI_ALREADY_STARTED; + } + + if (Bsr & F_I2C_BSR_BB) { // Bus is busy + __DEBUG ((DEBUG_INFO, "%a: Continuous Start\n", __FUNCTION__)); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, Bcr | F_I2C_BCR_SCC); + } else { + if (Bcr & F_I2C_BCR_MSS) { + __DEBUG ((DEBUG_WARN, "%a: is not in master mode\n", __FUNCTION__)); + return EFI_DEVICE_ERROR; + } + __DEBUG ((DEBUG_INFO, "%a: Start Condition\n", __FUNCTION__)); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + Bcr | F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +WaitForInterrupt ( + IN SYNQUACER_I2C_MASTER *I2c + ) +{ + UINT8 Bsr; + UINTN Timeout = WAIT_FOR_INTERRUPT_TIMEOUT; + + do { + MemoryFence (); + + Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); + if (Bsr & F_I2C_BCR_INT) { + return EFI_SUCCESS; + } + } while (Timeout--); + + return EFI_DEVICE_ERROR; +} + +/** + Start an I2C transaction on the host controller. + + This routine must be called at or below TPL_NOTIFY. For synchronous + requests this routine must be called at or below TPL_CALLBACK. + + This function initiates an I2C transaction on the controller. To + enable proper error handling by the I2C protocol stack, the I2C + master protocol does not support queuing but instead only manages + one I2C transaction at a time. This API requires that the I2C bus + is in the correct configuration for the I2C transaction. + + The transaction is performed by sending a start-bit and selecting the + I2C device with the specified I2C slave address and then performing + the specified I2C operations. When multiple operations are requested + they are separated with a repeated start bit and the slave address. + The transaction is terminated with a stop bit. + + When Event is NULL, StartRequest operates synchronously and returns + the I2C completion status as its return value. + + When Event is not NULL, StartRequest synchronously returns EFI_SUCCESS + indicating that the I2C transaction was started asynchronously. The + transaction status value is returned in the buffer pointed to by + I2cStatus upon the completion of the I2C transaction when I2cStatus + is not NULL. After the transaction status is returned the Event is + signaled. + + Note: The typical consumer of this API is the I2C host protocol. + Extreme care must be taken by other consumers of this API to prevent + confusing the third party I2C drivers due to a state change at the + I2C device which the third party I2C drivers did not initiate. I2C + platform specific code may use this API within these guidelines. + + @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure. + @param[in] SlaveAddress Address of the device on the I2C bus. Set the + I2C_ADDRESSING_10_BIT when using 10-bit addresses, + clear this bit for 7-bit addressing. Bits 0-6 + are used for 7-bit I2C slave addresses and bits + 0-9 are used for 10-bit I2C slave addresses. + @param[in] RequestPacket Pointer to an EFI_I2C_REQUEST_PACKET + structure describing the I2C transaction. + @param[in] Event Event to signal for asynchronous transactions, + NULL for synchronous transactions + @param[out] I2cStatus Optional buffer to receive the I2C transaction + completion status + + @retval EFI_SUCCESS The asynchronous transaction was successfully + started when Event is not NULL. + @retval EFI_SUCCESS The transaction completed successfully when + Event is NULL. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_BAD_BUFFER_SIZE The RequestPacket->LengthInBytes value is too + large. + @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the + transaction. + @retval EFI_INVALID_PARAMETER RequestPacket is NULL + @retval EFI_NOT_FOUND Reserved bit set in the SlaveAddress parameter + @retval EFI_NO_RESPONSE The I2C device is not responding to the slave + address. EFI_DEVICE_ERROR will be returned if + the controller cannot distinguish when the NACK + occurred. + @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C transaction + @retval EFI_UNSUPPORTED The controller does not support the requested + transaction. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cStartRequest ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN UINTN SlaveAddress, + IN EFI_I2C_REQUEST_PACKET *RequestPacket, + IN EFI_EVENT Event OPTIONAL, + OUT EFI_STATUS *I2cStatus OPTIONAL + ) +{ + SYNQUACER_I2C_MASTER *I2c; + UINTN Idx; + EFI_I2C_OPERATION *Op; + UINTN BufIdx; + EFI_STATUS Status; + EFI_TPL Tpl; + BOOLEAN AtRuntime; + UINT8 Bsr; + UINT8 Bcr; + + I2c = SYNQUACER_I2C_FROM_THIS (This); + + // + // We can only do synchronous operations at runtime + // + AtRuntime = EfiAtRuntime (); + if (AtRuntime && Event != NULL) { + return EFI_UNSUPPORTED; + } + + if (!AtRuntime) { + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + } + + for (Idx = 0, Op = RequestPacket->Operation, Status = EFI_SUCCESS; + Idx < RequestPacket->OperationCount && !EFI_ERROR (Status); + Idx++, Op++) { + + Status = SynQuacerI2cMasterStart (I2c, SlaveAddress, Op); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = WaitForInterrupt (I2c); + if (EFI_ERROR (Status)) { + __DEBUG ((DEBUG_WARN, "%a: Timeout waiting for interrupt - %r\n", + Status)); + break; + } + + if (MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_LRB) { + __DEBUG ((DEBUG_WARN, "%a: No ack received - %r\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + + BufIdx = 0; + do { + Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR); + Bcr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); + + if (Bcr & F_I2C_BCR_BER) { + __DEBUG ((DEBUG_WARN, "%a: Bus error detected\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + + if ((Bsr & F_I2C_BSR_AL) || !(Bcr & F_I2C_BCR_MSS)) { + __DEBUG ((DEBUG_WARN, "%a: Arbitration lost\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + + if (Op->Flags & I2C_FLAG_READ) { + if (BufIdx == Op->LengthInBytes - 1) { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); + } else { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE | F_I2C_BCR_ACK); + } + + Status = WaitForInterrupt (I2c); + if (EFI_ERROR (Status)) { + __DEBUG ((DEBUG_WARN, "%a: Timeout waiting for interrupt - %r\n", + __FUNCTION__, Status)); + break; + } + + if (!(MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_FBT)) { + Op->Buffer [BufIdx++] = MmioRead8 (I2c->MmioBase + F_I2C_REG_DAR); + } + } else { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, Op->Buffer [BufIdx++]); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); + + Status = WaitForInterrupt (I2c); + if (EFI_ERROR (Status)) { + __DEBUG ((DEBUG_WARN, "%a: Timeout waiting for interrupt - %r\n", + __FUNCTION__, Status)); + break; + } + + if (MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_LRB) { + __DEBUG ((DEBUG_WARN, "%a: No ack received\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + } + } while (BufIdx < Op->LengthInBytes); + } + + // Stop the transfer + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, 0); + + if (!AtRuntime) { + gBS->RestoreTPL (Tpl); + } + + if (Event) { + *I2cStatus = Status; + gBS->SignalEvent (Event); + } + return Status; +} + +STATIC CONST EFI_I2C_CONTROLLER_CAPABILITIES mI2cControllerCapabilities = { + sizeof (EFI_I2C_CONTROLLER_CAPABILITIES), // StructureSizeInBytes + MAX_UINT32, // MaximumReceiveBytes + MAX_UINT32, // MaximumTransmitBytes + MAX_UINT32, // MaximumTotalBytes +}; + +STATIC +VOID +EFIAPI +SynQuacerI2cVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + SYNQUACER_I2C_MASTER *I2c = Context; + + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.SetBusFrequency); + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.Reset); + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.StartRequest); + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.I2cControllerCapabilities); + EfiConvertPointer (0x0, (VOID **)&I2c->MmioBase); +} + +EFI_STATUS +SynQuacerI2cInit ( + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_STATUS Status; + NON_DISCOVERABLE_DEVICE *Dev; + SYNQUACER_I2C_MASTER *I2c; + BOOLEAN Runtime; + + Status = gBS->OpenProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + (VOID **)&Dev, DriverBindingHandle, + ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR (Status)) { + return Status; + } + + Runtime = CompareGuid (Dev->Type, + &gSynQuacerNonDiscoverableRuntimeI2cMasterGuid); + + // Allocate Resources + if (Runtime) { + I2c = AllocateRuntimeZeroPool (sizeof (SYNQUACER_I2C_MASTER)); + } else { + I2c = AllocateZeroPool (sizeof (SYNQUACER_I2C_MASTER)); + } + if (I2c == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto CloseProtocol; + } + + I2c->Signature = SYNQUACER_I2C_SIGNATURE; + I2c->I2cMaster.SetBusFrequency = SynQuacerI2cSetBusFrequency; + I2c->I2cMaster.Reset = SynQuacerI2cReset; + I2c->I2cMaster.StartRequest = SynQuacerI2cStartRequest; + I2c->I2cMaster.I2cControllerCapabilities = &mI2cControllerCapabilities; + I2c->MmioBase = Dev->Resources[0].AddrRangeMin; + I2c->Dev = Dev; + + if (Runtime) { + I2c->Runtime = TRUE; + + // Declare the controller as EFI_MEMORY_RUNTIME + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + Dev->Resources[0].AddrRangeMin, + Dev->Resources[0].AddrLen, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + if (EFI_ERROR (Status)) { + __DEBUG ((DEBUG_WARN, "%a: failed to add memory space - %r\n", + __FUNCTION__, Status)); + } + + Status = gDS->SetMemorySpaceAttributes ( + Dev->Resources[0].AddrRangeMin, + Dev->Resources[0].AddrLen, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + if (EFI_ERROR (Status)) { + goto FreeDevice; + } + + // + // Register for the virtual address change event + // + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, + SynQuacerI2cVirtualNotifyEvent, I2c, + &gEfiEventVirtualAddressChangeGuid, + &I2c->VirtualAddressChangeEvent); + if (EFI_ERROR (Status)) { + goto FreeDevice; + } + } + + CopyGuid (&I2c->DevicePath.Vendor.Guid, &gEfiCallerIdGuid); + I2c->DevicePath.MmioBase = I2c->MmioBase; + SetDevicePathNodeLength (&I2c->DevicePath.Vendor, + sizeof (I2c->DevicePath) - sizeof (I2c->DevicePath.End)); + SetDevicePathEndNode (&I2c->DevicePath.End); + + Status = gBS->InstallMultipleProtocolInterfaces (&ControllerHandle, + &gEfiI2cMasterProtocolGuid, &I2c->I2cMaster, + &gEfiDevicePathProtocolGuid, &I2c->DevicePath, + NULL); + if (EFI_ERROR (Status)) { + goto CloseEvent; + } + return EFI_SUCCESS; + +CloseEvent: + if (Runtime) { + gBS->CloseEvent (I2c->VirtualAddressChangeEvent); + } + +FreeDevice: + FreePool (I2c); + +CloseProtocol: + gBS->CloseProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + DriverBindingHandle, + ControllerHandle); + return Status; +} + +EFI_STATUS +SynQuacerI2cRelease ( + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_I2C_MASTER_PROTOCOL *I2cMaster; + SYNQUACER_I2C_MASTER *I2c; + EFI_STATUS Status; + + Status = gBS->HandleProtocol (ControllerHandle, + &gEfiI2cMasterProtocolGuid, + (VOID **)&I2cMaster); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + I2c = SYNQUACER_I2C_FROM_THIS (I2cMaster); + + Status = gBS->UninstallMultipleProtocolInterfaces (ControllerHandle, + &gEfiI2cMasterProtocolGuid, I2cMaster, + &gEfiDevicePathProtocolGuid, &I2c->DevicePath, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + if (I2c->Runtime) { + gBS->CloseEvent (I2c->VirtualAddressChangeEvent); + } + + Status = gBS->CloseProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + DriverBindingHandle, + ControllerHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->FreePool (I2c); + + return EFI_SUCCESS; +} diff --git a/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.h b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.h new file mode 100644 index 000000000000..8c3d7ef67103 --- /dev/null +++ b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.h @@ -0,0 +1,162 @@ +/** @file + + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SYNQUACER_I2C_DXE_H__ +#define __SYNQUACER_I2C_DXE_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern EFI_COMPONENT_NAME2_PROTOCOL gSynQuacerI2cDriverComponentName2; + +#define SYNQUACER_I2C_SIGNATURE SIGNATURE_32 ('S', 'I', '2', 'C') +#define SYNQUACER_I2C_FROM_THIS(a) CR (a, SYNQUACER_I2C_MASTER, \ + I2cMaster, SYNQUACER_I2C_SIGNATURE) + +#pragma pack(1) +typedef struct { + VENDOR_DEVICE_PATH Vendor; + UINT64 MmioBase; + EFI_DEVICE_PATH_PROTOCOL End; +} SYNQUACER_I2C_DEVICE_PATH; +#pragma pack() + +typedef struct { + UINT32 Signature; + EFI_I2C_MASTER_PROTOCOL I2cMaster; + EFI_PHYSICAL_ADDRESS MmioBase; + SYNQUACER_I2C_DEVICE_PATH DevicePath; + NON_DISCOVERABLE_DEVICE *Dev; + EFI_EVENT VirtualAddressChangeEvent; + BOOLEAN Runtime; +} SYNQUACER_I2C_MASTER; + +EFI_STATUS +SynQuacerI2cInit ( + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle + ); + +EFI_STATUS +SynQuacerI2cRelease ( + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle + ); + +#define REFCLK_RATE FixedPcdGet32 (PcdI2cReferenceClock) + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +#define F_I2C_SPEED_SM 100000 +#define F_I2C_SPEED_FM 400000 + +// I2C register adress definitions +#define F_I2C_REG_BSR (0x00 << 2) // Bus Status Regster +#define F_I2C_REG_BCR (0x01 << 2) // Bus Control Register +#define F_I2C_REG_CCR (0x02 << 2) // Clock Control Register +#define F_I2C_REG_ADR (0x03 << 2) // Address Register +#define F_I2C_REG_DAR (0x04 << 2) // Data Register +#define F_I2C_REG_CSR (0x05 << 2) // Expansion CS Register +#define F_I2C_REG_FSR (0x06 << 2) // Bus Clock Frequency Register +#define F_I2C_REG_BC2R (0x07 << 2) // Bus Control 2 Register + +// I2C register bit definitions +#define F_I2C_BSR_FBT BIT0 // First Byte Transfer +#define F_I2C_BSR_GCA BIT1 // General Call Address +#define F_I2C_BSR_AAS BIT2 // Address as Slave +#define F_I2C_BSR_TRX BIT3 // Transfer/Receive +#define F_I2C_BSR_LRB BIT4 // Last Received Bit +#define F_I2C_BSR_AL BIT5 // Arbitration Lost +#define F_I2C_BSR_RSC BIT6 // Repeated Start Condition +#define F_I2C_BSR_BB BIT7 // Bus Busy + +#define F_I2C_BCR_INT BIT0 // Interrupt +#define F_I2C_BCR_INTE BIT1 // Interrupt Enable +#define F_I2C_BCR_GCAA BIT2 // General Call Access Acknowledge +#define F_I2C_BCR_ACK BIT3 // Acknowledge +#define F_I2C_BCR_MSS BIT4 // Master Slave Select +#define F_I2C_BCR_SCC BIT5 // Start Condition Continue +#define F_I2C_BCR_BEIE BIT6 // Bus Error Interrupt Enable +#define F_I2C_BCR_BER BIT7 // Bus Error + +#define F_I2C_CCR_CS_MASK 0x1f // CCR Clock Period Select +#define F_I2C_CCR_EN BIT5 // Enable +#define F_I2C_CCR_FM BIT6 // Speed Mode Select + +#define F_I2C_CSR_CS_MASK 0x3f // CSR Clock Period Select + +#define F_I2C_BC2R_SCLL BIT0 // SCL Low Drive +#define F_I2C_BC2R_SDAL BIT1 // SDA Low Drive +#define F_I2C_BC2R_SCLS BIT4 // SCL Status +#define F_I2C_BC2R_SDAS BIT5 // SDA Status + +// PCLK frequency +#define F_I2C_BUS_CLK_FR(rate) ((rate) / 20000000 + 1) + +#define F_I2C_MIN_CLK_RATE (14 * 1000000) // min frequency 14 MHz +#define F_I2C_MAX_CLK_RATE (200 * 1000000) // max frequency 200 MHz +#define F_I2C_CLK_RATE_18M (18 * 1000000) // threshold freq 18 MHz + +// STANDARD MODE frequency +#define F_I2C_CLK_MASTER_STANDARD(rate) \ + DIV_ROUND_UP (DIV_ROUND_UP ((rate), 100000) - 2, 2) + +// FAST MODE frequency +#define F_I2C_CLK_MASTER_FAST(rate) \ + DIV_ROUND_UP ((DIV_ROUND_UP ((rate), 400000) - 2) * 2, 3) + +// (clkrate <= 18000000) +// calculate the value of CS bits in CCR register in standard mode +#define F_I2C_CCR_CS_STANDARD_MAX_18M(rate) \ + ((F_I2C_CLK_MASTER_STANDARD (rate) - 65) & F_I2C_CCR_CS_MASK) + +// calculate the value of CS bits in CSR register in standard mode +#define F_I2C_CSR_CS_STANDARD_MAX_18M(rate) 0x00 + +// calculate the value of CS bits in CCR register in fast mode +#define F_I2C_CCR_CS_FAST_MAX_18M(rate) \ + ((F_I2C_CLK_MASTER_FAST (rate) - 1) & F_I2C_CCR_CS_MASK) + +// calculate the value of CS bits in CSR register in fast mode +#define F_I2C_CSR_CS_FAST_MAX_18M(rate) 0x00 + +// (clkrate > 18000000) +// calculate the value of CS bits in CCR register in standard mode */ +#define F_I2C_CCR_CS_STANDARD_MIN_18M(rate) \ + ((F_I2C_CLK_MASTER_STANDARD (rate) - 1) & F_I2C_CCR_CS_MASK) + +// calculate the value of CS bits in CSR register in standard mode +#define F_I2C_CSR_CS_STANDARD_MIN_18M(rate) \ + (((F_I2C_CLK_MASTER_STANDARD (rate) - 1) >> 5) & F_I2C_CSR_CS_MASK) + +// calculate the value of CS bits in CCR register in fast mode +#define F_I2C_CCR_CS_FAST_MIN_18M(rate) \ + ((F_I2C_CLK_MASTER_FAST (rate) - 1) & F_I2C_CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register in fast mode */ +#define F_I2C_CSR_CS_FAST_MIN_18M(rate) \ + (((F_I2C_CLK_MASTER_FAST (rate) - 1) >> 5) & F_I2C_CSR_CS_MASK) + +#endif diff --git a/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.inf b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.inf new file mode 100644 index 000000000000..fa715366878c --- /dev/null +++ b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.inf @@ -0,0 +1,59 @@ +#/** @file +# +# Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = SynQuacerI2cDxe + FILE_GUID = ab5ed376-dd38-4d22-ae89-b645a4a3236e + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SynQuacerI2cDxeEntryPoint + UNLOAD = SynQuacerI2cDxeUnload + +[Sources.common] + ComponentName.c + DriverBinding.c + SynQuacerI2cDxe.c + SynQuacerI2cDxe.h + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Socionext/SynQuacer/SynQuacer.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + DevicePathLib + DxeServicesTableLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiLib + UefiDriverEntryPoint + UefiRuntimeLib + +[Guids] + gEfiEventVirtualAddressChangeGuid + gSynQuacerNonDiscoverableI2cMasterGuid + gSynQuacerNonDiscoverableRuntimeI2cMasterGuid + +[Protocols] + gEdkiiNonDiscoverableDeviceProtocolGuid ## TO_START + gEfiI2cMasterProtocolGuid ## BY_START + +[FixedPcd] + gSynQuacerTokenSpaceGuid.PcdI2cReferenceClock + +[Depex] + TRUE diff --git a/Silicon/Socionext/SynQuacer/SynQuacer.dec b/Silicon/Socionext/SynQuacer/SynQuacer.dec index c11550469cd0..76a9b70bc81e 100644 --- a/Silicon/Socionext/SynQuacer/SynQuacer.dec +++ b/Silicon/Socionext/SynQuacer/SynQuacer.dec @@ -22,6 +22,9 @@ [Includes] [Guids] gSynQuacerTokenSpaceGuid = { 0x4d04555b, 0xdfdc, 0x418a, { 0x8a, 0xab, 0x07, 0xce, 0xef, 0x46, 0x82, 0xbb } } + gSynQuacerNonDiscoverableI2cMasterGuid = { 0x364ee675, 0x9e44, 0x42b7, { 0xa5, 0xe4, 0x92, 0x84, 0xdb, 0x85, 0xda, 0x09 } } + gSynQuacerNonDiscoverableRuntimeI2cMasterGuid = { 0x5f35aa9b, 0x8c6f, 0x4828, { 0xbd, 0x44, 0x7c, 0xc0, 0xeb, 0x2d, 0xfe, 0xb9 } } + [Ppis] gSynQuacerDramInfoPpiGuid = { 0x3e1d7356, 0xdda4, 0x4b1a, { 0x93, 0x46, 0xbf, 0x89, 0x1c, 0x86, 0x46, 0xcc } } @@ -32,3 +35,5 @@ [PcdsFixedAtBuild] gSynQuacerTokenSpaceGuid.PcdNetsecPhyAddress|0|UINT8|0x00000003 gSynQuacerTokenSpaceGuid.PcdClearSettingsGpioPin|0|UINT32|0x00000004 + + gSynQuacerTokenSpaceGuid.PcdI2cReferenceClock|62500000|UINT32|0x00000005