diff options
author | Leif Lindholm <leif.lindholm@linaro.org> | 2017-08-03 12:24:42 +0100 |
---|---|---|
committer | Leif Lindholm <leif.lindholm@linaro.org> | 2017-08-03 12:24:42 +0100 |
commit | 7d9c4946890fe5ea37037a18d7c154986d0adc6a (patch) | |
tree | 481788a26d43fdad9f762256111ece2926b7835a /Platform/Marvell/Drivers/I2c | |
parent | 600081b52debde8d06585fdaf09fac16d323670f (diff) | |
download | edk2-platforms-7d9c4946890fe5ea37037a18d7c154986d0adc6a.tar.xz |
Platform: import Marvell Armada support
Import Armada 70x0 suppport from OpenPlatformPkg,
together with its documentation and utilities.
Imported from commit efd798c1eb of
https://git.linaro.org/uefi/OpenPlatformPkg.git
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Diffstat (limited to 'Platform/Marvell/Drivers/I2c')
-rw-r--r-- | Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c | 292 | ||||
-rw-r--r-- | Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h | 103 | ||||
-rw-r--r-- | Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf | 70 | ||||
-rwxr-xr-x | Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c | 740 | ||||
-rw-r--r-- | Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h | 269 | ||||
-rwxr-xr-x | Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf | 75 |
6 files changed, 1549 insertions, 0 deletions
diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c new file mode 100644 index 0000000000..d8fd1bfe62 --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c @@ -0,0 +1,292 @@ +/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/I2cIo.h>
+#include <Protocol/Eeprom.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Pi/PiI2c.h>
+
+#include "MvEeprom.h"
+
+#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)
+
+STATIC CONST EFI_GUID I2cGuid = I2C_GUID;
+
+EFI_DRIVER_BINDING_PROTOCOL gDriverBindingProtocol = {
+ MvEepromSupported,
+ MvEepromStart,
+ MvEepromStop
+};
+
+EFI_STATUS
+EFIAPI
+MvEepromSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status = EFI_UNSUPPORTED;
+ EFI_I2C_IO_PROTOCOL *TmpI2cIo;
+ UINT8 *EepromAddresses;
+ UINT8 *EepromBuses;
+ UINTN i;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ (VOID **) &TmpI2cIo,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ /* get EEPROM devices' addresses from PCD */
+ EepromAddresses = PcdGetPtr (PcdEepromI2cAddresses);
+ EepromBuses = PcdGetPtr (PcdEepromI2cBuses);
+ if (EepromAddresses == 0) {
+ Status = EFI_UNSUPPORTED;
+ DEBUG((DEBUG_INFO, "MvEepromSupported: I2C device found, but it's not EEPROM\n"));
+ goto out;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ for (i = 0; EepromAddresses[i] != '\0'; i++) {
+ /* I2C guid must fit and valid DeviceIndex must be provided */
+ if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) &&
+ TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(EepromBuses[i],
+ EepromAddresses[i])) {
+ DEBUG((DEBUG_INFO, "MvEepromSupported: attached to EEPROM device\n"));
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+out:
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromTransfer (
+ IN CONST MARVELL_EEPROM_PROTOCOL *This,
+ IN UINT16 Address,
+ IN UINT32 Length,
+ IN UINT8 *Buffer,
+ IN UINT8 Operation
+ )
+{
+ EFI_I2C_REQUEST_PACKET *RequestPacket;
+ UINTN RequestPacketSize;
+ EFI_STATUS Status = EFI_SUCCESS;
+ EEPROM_CONTEXT *EepromContext = EEPROM_SC_FROM_EEPROM(This);
+ UINT32 BufferLength;
+ UINT32 Transmitted = 0;
+ UINT32 CurrentAddress = Address;
+
+ ASSERT(EepromContext != NULL);
+ ASSERT(EepromContext->I2cIo != NULL);
+
+ RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2;
+ RequestPacket = AllocateZeroPool (RequestPacketSize);
+ if (RequestPacket == NULL)
+ return EFI_OUT_OF_RESOURCES;
+ /* First operation contains address, the second is buffer */
+ RequestPacket->OperationCount = 2;
+ RequestPacket->Operation[0].LengthInBytes = 2;
+ RequestPacket->Operation[0].Buffer = AllocateZeroPool ( RequestPacket->Operation[0].LengthInBytes );
+ if (RequestPacket->Operation[0].Buffer == NULL) {
+ FreePool(RequestPacket);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ RequestPacket->Operation[1].Flags = (Operation == EEPROM_READ ? I2C_FLAG_READ : I2C_FLAG_NORESTART);
+
+ while (Length > 0) {
+ CurrentAddress = Address + Transmitted;
+ BufferLength = (Length <= MAX_BUFFER_LENGTH ? Length : MAX_BUFFER_LENGTH);
+ RequestPacket->Operation[0].Buffer[0] = (CurrentAddress >> 8) & 0xff;
+ RequestPacket->Operation[0].Buffer[1] = CurrentAddress & 0xff;
+ RequestPacket->Operation[1].LengthInBytes = BufferLength;
+ RequestPacket->Operation[1].Buffer = Buffer + Transmitted;
+ Status = EepromContext->I2cIo->QueueRequest(EepromContext->I2cIo, 0, NULL, RequestPacket, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvEepromTransfer: error %d during transmission\n", Status));
+ break;
+ }
+ Length -= BufferLength;
+ Transmitted += BufferLength;
+ }
+
+ FreePool(RequestPacket->Operation[0].Buffer);
+ FreePool(RequestPacket);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ EEPROM_CONTEXT *EepromContext;
+
+ EepromContext = AllocateZeroPool (sizeof(EEPROM_CONTEXT));
+ if (EepromContext == NULL) {
+ DEBUG((DEBUG_ERROR, "MvEeprom: allocation fail\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EepromContext->ControllerHandle = ControllerHandle;
+ EepromContext->Signature = EEPROM_SIGNATURE;
+ EepromContext->EepromProtocol.Transfer = MvEepromTransfer;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ (VOID **) &EepromContext->I2cIo,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvEeprom: failed to open I2cIo\n"));
+ FreePool(EepromContext);
+ return EFI_UNSUPPORTED;
+ }
+
+ EepromContext->EepromProtocol.Identifier = EepromContext->I2cIo->DeviceIndex;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvEeprom: failed to install EEPROM protocol\n"));
+ goto fail;
+ }
+
+ return Status;
+
+fail:
+ FreePool(EepromContext);
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ MARVELL_EEPROM_PROTOCOL *EepromProtocol;
+ EFI_STATUS Status;
+ EEPROM_CONTEXT *EepromContext;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gMarvellEepromProtocolGuid,
+ (VOID **) &EepromProtocol,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ EepromContext = EEPROM_SC_FROM_EEPROM(EepromProtocol);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol,
+ &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
+ NULL
+ );
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+ FreePool(EepromContext);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
+ NULL
+ );
+ return Status;
+}
diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h new file mode 100644 index 0000000000..b1af645050 --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h @@ -0,0 +1,103 @@ +/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MV_EEPROM_H__
+#define __MV_EEPROM_H__
+
+#include <Uefi.h>
+
+#define EEPROM_SIGNATURE SIGNATURE_32 ('E', 'E', 'P', 'R')
+
+#define MAX_BUFFER_LENGTH 64
+
+/*
+ * I2C_FLAG_NORESTART is not part of PI spec, it allows to continue
+ * transmission without repeated start operation.
+ * FIXME: This flag is also defined in Drivers/I2c/MvI2cDxe/MvI2cDxe.h
+ * and it's important to have both version synced. This solution is
+ * temporary and shared flag should be used by both files.
+ * Situation is analogous with I2C_GUID, which also should be common, but is
+ * for now defined same way in two header files.
+ */
+#define I2C_FLAG_NORESTART 0x00000002
+#define I2C_GUID \
+ { \
+ 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \
+ }
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE ControllerHandle;
+ EFI_I2C_IO_PROTOCOL *I2cIo;
+ MARVELL_EEPROM_PROTOCOL EepromProtocol;
+} EEPROM_CONTEXT;
+
+#define EEPROM_SC_FROM_IO(a) CR (a, EEPROM_CONTEXT, I2cIo, EEPROM_SIGNATURE)
+#define EEPROM_SC_FROM_EEPROM(a) CR (a, EEPROM_CONTEXT, EepromProtocol, EEPROM_SIGNATURE)
+
+EFI_STATUS
+EFIAPI
+MvEepromSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MvEepromStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MvEepromStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MvEepromTransfer (
+ IN CONST MARVELL_EEPROM_PROTOCOL *This,
+ IN UINT16 Address,
+ IN UINT32 Length,
+ IN UINT8 *Buffer,
+ IN UINT8 Operation
+ );
+#endif // __MV_EEPROM_H__
diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf new file mode 100644 index 0000000000..a50f8b9b4e --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf @@ -0,0 +1,70 @@ +#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MvEeprom
+ FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvEepromInitialise
+
+[Sources.common]
+ MvEeprom.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ IoLib
+ PcdLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiI2cIoProtocolGuid
+ gEfiDriverBindingProtocolGuid
+ gMarvellEepromProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdEepromI2cAddresses
+ gMarvellTokenSpaceGuid.PcdEepromI2cBuses
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c new file mode 100755 index 0000000000..fa79ebccfa --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c @@ -0,0 +1,740 @@ +/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/I2cMaster.h>
+#include <Protocol/I2cEnumerate.h>
+#include <Protocol/I2cBusConfigurationManagement.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ParsePcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "MvI2cDxe.h"
+
+STATIC MV_I2C_BAUD_RATE baud_rate;
+
+STATIC MV_I2C_DEVICE_PATH MvI2cDevicePathProtocol = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof(VENDOR_DEVICE_PATH)),
+ (UINT8) (sizeof(VENDOR_DEVICE_PATH) >> 8),
+ },
+ },
+ EFI_CALLER_ID_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ sizeof(EFI_DEVICE_PATH_PROTOCOL),
+ 0
+ }
+ }
+};
+
+STATIC
+UINT32
+I2C_READ(
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off)
+{
+ ASSERT (I2cMasterContext != NULL);
+ return MmioRead32 (I2cMasterContext->BaseAddress + off);
+}
+
+STATIC
+EFI_STATUS
+I2C_WRITE (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off,
+ IN UINT32 Value)
+{
+ ASSERT (I2cMasterContext != NULL);
+ return MmioWrite32 (I2cMasterContext->BaseAddress + off, Value);
+}
+
+EFI_STATUS
+EFIAPI
+MvI2cInitialiseController (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ EFI_STATUS Status;
+ I2C_MASTER_CONTEXT *I2cMasterContext;
+ STATIC INTN Bus = 0;
+ MV_I2C_DEVICE_PATH *DevicePath;
+
+ DevicePath = AllocateCopyPool (sizeof(MvI2cDevicePathProtocol),
+ &MvI2cDevicePathProtocol);
+ if (DevicePath == NULL) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device path allocation failed\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DevicePath->Guid.Guid.Data4[0] = Bus;
+
+ /* if attachment succeeds, this gets freed at ExitBootServices */
+ I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT));
+ if (I2cMasterContext == NULL) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C master context allocation failed\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ I2cMasterContext->Signature = I2C_MASTER_SIGNATURE;
+ I2cMasterContext->I2cMaster.Reset = MvI2cReset;
+ I2cMasterContext->I2cMaster.StartRequest = MvI2cStartRequest;
+ I2cMasterContext->I2cEnumerate.Enumerate = MvI2cEnumerate;
+ I2cMasterContext->I2cBusConf.EnableI2cBusConfiguration = MvI2cEnableConf;
+ I2cMasterContext->TclkFrequency = PcdGet32 (PcdI2cClockFrequency);
+ I2cMasterContext->BaseAddress = BaseAddress;
+ I2cMasterContext->Bus = Bus;
+ /* I2cMasterContext->Lock is responsible for serializing I2C operations */
+ EfiInitializeLock(&I2cMasterContext->Lock, TPL_NOTIFY);
+
+ MvI2cCalBaudRate( I2cMasterContext,
+ PcdGet32 (PcdI2cBaudRate),
+ &baud_rate,
+ I2cMasterContext->TclkFrequency
+ );
+
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &I2cMasterContext->Controller,
+ &gEfiI2cMasterProtocolGuid,
+ &I2cMasterContext->I2cMaster,
+ &gEfiI2cEnumerateProtocolGuid,
+ &I2cMasterContext->I2cEnumerate,
+ &gEfiI2cBusConfigurationManagementProtocolGuid,
+ &I2cMasterContext->I2cBusConf,
+ &gEfiDevicePathProtocolGuid,
+ (EFI_DEVICE_PATH_PROTOCOL *) DevicePath,
+ NULL);
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Installing protocol interfaces failed!\n"));
+ goto fail;
+ }
+ DEBUG((DEBUG_ERROR, "Succesfully installed controller %d at 0x%llx\n", Bus,
+ I2cMasterContext->BaseAddress));
+
+ Bus++;
+
+ return EFI_SUCCESS;
+
+fail:
+ FreePool(I2cMasterContext);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvI2cInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BusCount;
+ EFI_PHYSICAL_ADDRESS I2cBaseAddresses[PcdGet32 (PcdI2cBusCount)];
+ INTN i;
+
+ BusCount = PcdGet32 (PcdI2cBusCount);
+ if (BusCount == 0)
+ return EFI_SUCCESS;
+
+ Status = ParsePcdString (
+ (CHAR16 *) PcdGetPtr (PcdI2cBaseAddresses),
+ BusCount,
+ I2cBaseAddresses,
+ NULL
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+
+ for (i = 0; i < BusCount; i++) {
+ Status = MvI2cInitialiseController(
+ ImageHandle,
+ SystemTable,
+ I2cBaseAddresses[i]
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+ }
+
+ return Status;
+}
+
+STATIC
+VOID
+MvI2cControlClear (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 Mask)
+{
+ UINT32 Value;
+
+ /* clears given bits in I2C_CONTROL register */
+ Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
+ Value &= ~Mask;
+ I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
+}
+
+STATIC
+VOID
+MvI2cControlSet (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 Mask)
+{
+ UINT32 Value;
+
+ /* sets given bits in I2C_CONTROL register */
+ Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
+ Value |= Mask;
+ I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
+}
+
+STATIC
+VOID
+MvI2cClearIflg (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ )
+{
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ MvI2cControlClear(I2cMasterContext, I2C_CONTROL_IFLG);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+}
+
+/* Timeout is given in us */
+STATIC
+UINTN
+MvI2cPollCtrl (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN Timeout,
+ IN UINT32 Mask)
+{
+ Timeout /= 10;
+ while (!(I2C_READ(I2cMasterContext, I2C_CONTROL) & Mask)) {
+ gBS->Stall(10);
+ if (--Timeout == 0)
+ return (Timeout);
+ }
+ return (0);
+}
+
+/*
+ * 'Timeout' is given in us. Note also that Timeout handling is not exact --
+ * MvI2cLockedStart() total wait can be more than 2 x Timeout
+ * (MvI2cPollCtrl() is called twice). 'Mask' can be either I2C_STATUS_START
+ * or I2C_STATUS_RPTD_START
+ */
+STATIC
+EFI_STATUS
+MvI2cLockedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN INT32 Mask,
+ IN UINT8 Slave,
+ IN UINTN Timeout
+ )
+{
+ UINTN ReadAccess, IflgSet = 0;
+ UINT32 I2cStatus;
+
+ if (Mask == I2C_STATUS_RPTD_START) {
+ /* read IFLG to know if it should be cleared later */
+ IflgSet = I2C_READ(I2cMasterContext, I2C_CONTROL) & I2C_CONTROL_IFLG;
+ }
+
+ MvI2cControlSet(I2cMasterContext, I2C_CONTROL_START);
+
+ if (Mask == I2C_STATUS_RPTD_START && IflgSet) {
+ DEBUG((DEBUG_INFO, "MvI2cDxe: IFLG set, clearing\n"));
+ MvI2cClearIflg(I2cMasterContext);
+ }
+
+ /* Without this delay we Timeout checking IFLG if the Timeout is 0 */
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+
+ if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending %sSTART condition\n",
+ Mask == I2C_STATUS_START ? "" : "repeated "));
+ return EFI_NO_RESPONSE;
+ }
+
+ I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (I2cStatus != Mask) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) after sending %sSTART condition\n",
+ I2cStatus, Mask == I2C_STATUS_START ? "" : "repeated "));
+ return EFI_DEVICE_ERROR;
+ }
+
+ I2C_WRITE(I2cMasterContext, I2C_DATA, Slave);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ MvI2cClearIflg(I2cMasterContext);
+
+ if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending Slave address\n"));
+ return EFI_NO_RESPONSE;
+ }
+
+ ReadAccess = (Slave & 0x1) ? 1 : 0;
+ I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (I2cStatus != (ReadAccess ?
+ I2C_STATUS_ADDR_R_ACK : I2C_STATUS_ADDR_W_ACK)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: no ACK (I2cStatus: %02x) after sending Slave address\n",
+ I2cStatus));
+ return EFI_NO_RESPONSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+#define ABSSUB(a,b) (((a) > (b)) ? (a) - (b) : (b) - (a))
+STATIC
+VOID
+MvI2cCalBaudRate (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN CONST UINT32 target,
+ IN OUT MV_I2C_BAUD_RATE *rate,
+ UINT32 clk
+ )
+{
+ UINT32 cur, diff, diff0, baud;
+ UINTN m, n, m0, n0;
+
+ /* Read initial m0, n0 values from register */
+ baud = I2C_READ(I2cMasterContext, I2C_BAUD_RATE);
+ m0 = I2C_M_FROM_BAUD(baud);
+ n0 = I2C_N_FROM_BAUD(baud);
+ /* Calculate baud rate. */
+ diff0 = 0xffffffff;
+
+ for (n = 0; n < 8; n++) {
+ for (m = 0; m < 16; m++) {
+ cur = I2C_BAUD_RATE_RAW(clk,m,n);
+ diff = ABSSUB(target, cur);
+ if (diff < diff0) {
+ m0 = m;
+ n0 = n;
+ diff0 = diff;
+ }
+ }
+ }
+ rate->raw = I2C_BAUD_RATE_RAW(clk, m0, n0);
+ rate->param = I2C_BAUD_RATE_PARAM(m0, n0);
+ rate->m = m0;
+ rate->n = n0;
+}
+
+EFI_STATUS
+EFIAPI
+MvI2cReset (
+ IN CONST EFI_I2C_MASTER_PROTOCOL *This
+ )
+{
+ UINT32 param;
+ I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
+
+ param = baud_rate.param;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ I2C_WRITE(I2cMasterContext, I2C_SOFT_RESET, 0x0);
+ gBS->Stall(2 * I2C_OPERATION_TIMEOUT);
+ I2C_WRITE(I2cMasterContext, I2C_BAUD_RATE, param);
+ I2C_WRITE(I2cMasterContext, I2C_CONTROL, I2C_CONTROL_I2CEN | I2C_CONTROL_ACK);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ return EFI_SUCCESS;
+}
+
+/*
+ * Timeout is given in us
+ */
+STATIC
+EFI_STATUS
+MvI2cRepeatedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 Slave,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_RPTD_START, Slave,
+ Timeout);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ if (EFI_ERROR(Status)) {
+ MvI2cStop(I2cMasterContext);
+ }
+ return Status;
+}
+
+/*
+ * Timeout is given in us
+ */
+STATIC
+EFI_STATUS
+MvI2cStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 Slave,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_START, Slave, Timeout);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ if (EFI_ERROR(Status)) {
+ MvI2cStop(I2cMasterContext);
+ }
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+MvI2cStop (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ )
+{
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ MvI2cControlSet(I2cMasterContext, I2C_CONTROL_STOP);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ MvI2cClearIflg(I2cMasterContext);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvI2cRead (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT UINT8 *Buf,
+ IN UINTN Length,
+ IN OUT UINTN *read,
+ IN UINTN last,
+ IN UINTN delay
+ )
+{
+ UINT32 I2cStatus;
+ UINTN LastByte;
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ *read = 0;
+ while (*read < Length) {
+ /*
+ * Check if we are reading last byte of the last Buffer,
+ * do not send ACK then, per I2C specs
+ */
+ LastByte = ((*read == Length - 1) && last) ? 1 : 0;
+ if (LastByte)
+ MvI2cControlClear(I2cMasterContext, I2C_CONTROL_ACK);
+ else
+ MvI2cControlSet(I2cMasterContext, I2C_CONTROL_ACK);
+
+ gBS->Stall (I2C_OPERATION_TIMEOUT);
+ MvI2cClearIflg(I2cMasterContext);
+
+ if (MvI2cPollCtrl(I2cMasterContext, delay, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout reading data\n"));
+ Status = EFI_NO_RESPONSE;
+ goto out;
+ }
+
+ I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (I2cStatus != (LastByte ?
+ I2C_STATUS_DATA_RD_NOACK : I2C_STATUS_DATA_RD_ACK)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) while reading\n", I2cStatus));
+ Status = EFI_DEVICE_ERROR;
+ goto out;
+ }
+
+ *Buf++ = I2C_READ(I2cMasterContext, I2C_DATA);
+ (*read)++;
+ }
+ Status = EFI_SUCCESS;
+out:
+ EfiReleaseLock (&I2cMasterContext->Lock);
+ return (Status);
+}
+
+STATIC
+EFI_STATUS
+MvI2cWrite (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT CONST UINT8 *Buf,
+ IN UINTN Length,
+ IN OUT UINTN *Sent,
+ IN UINTN Timeout
+ )
+{
+ UINT32 status;
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ *Sent = 0;
+ while (*Sent < Length) {
+ I2C_WRITE(I2cMasterContext, I2C_DATA, *Buf++);
+
+ MvI2cClearIflg(I2cMasterContext);
+ if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout writing data\n"));
+ Status = EFI_NO_RESPONSE;
+ goto out;
+ }
+
+ status = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (status != I2C_STATUS_DATA_WR_ACK) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong status (%02x) while writing\n", status));
+ Status = EFI_DEVICE_ERROR;
+ goto out;
+ }
+ (*Sent)++;
+ }
+ Status = EFI_SUCCESS;
+out:
+ EfiReleaseLock (&I2cMasterContext->Lock);
+ return (Status);
+}
+
+/*
+ * MvI2cStartRequest should be called only by I2cHost.
+ * I2C device drivers ought to use EFI_I2C_IO_PROTOCOL instead.
+ */
+STATIC
+EFI_STATUS
+MvI2cStartRequest (
+ 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
+ )
+{
+ UINTN Count;
+ UINTN ReadMode;
+ UINTN Transmitted;
+ I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
+ EFI_I2C_OPERATION *Operation;
+
+ ASSERT (RequestPacket != NULL);
+ ASSERT (I2cMasterContext != NULL);
+
+ for (Count = 0; Count < RequestPacket->OperationCount; Count++) {
+ Operation = &RequestPacket->Operation[Count];
+ ReadMode = Operation->Flags & I2C_FLAG_READ;
+
+ if (Count == 0) {
+ MvI2cStart ( I2cMasterContext,
+ (SlaveAddress << 1) | ReadMode,
+ I2C_TRANSFER_TIMEOUT
+ );
+ } else if (!(Operation->Flags & I2C_FLAG_NORESTART)) {
+ MvI2cRepeatedStart ( I2cMasterContext,
+ (SlaveAddress << 1) | ReadMode,
+ I2C_TRANSFER_TIMEOUT
+ );
+ }
+
+ if (ReadMode) {
+ MvI2cRead ( I2cMasterContext,
+ Operation->Buffer,
+ Operation->LengthInBytes,
+ &Transmitted,
+ Count == 1,
+ I2C_TRANSFER_TIMEOUT
+ );
+ } else {
+ MvI2cWrite ( I2cMasterContext,
+ Operation->Buffer,
+ Operation->LengthInBytes,
+ &Transmitted,
+ I2C_TRANSFER_TIMEOUT
+ );
+ }
+ if (Count == RequestPacket->OperationCount - 1) {
+ MvI2cStop ( I2cMasterContext );
+ }
+ }
+
+ if (I2cStatus != NULL)
+ I2cStatus = EFI_SUCCESS;
+ if (Event != NULL)
+ gBS->SignalEvent(Event);
+ return EFI_SUCCESS;
+}
+
+STATIC CONST EFI_GUID DevGuid = I2C_GUID;
+
+#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)
+#define I2C_DEVICE_ADDRESS(index) ((index) & 0xffff)
+
+STATIC
+EFI_STATUS
+MvI2cAllocDevice (
+ IN UINT8 SlaveAddress,
+ IN UINT8 Bus,
+ IN OUT CONST EFI_I2C_DEVICE **Device
+ )
+{
+ EFI_STATUS Status;
+ EFI_I2C_DEVICE *Dev;
+ UINT32 *TmpSlaveArray;
+ EFI_GUID *TmpGuidP;
+
+ Status = gBS->AllocatePool ( EfiBootServicesData,
+ sizeof(EFI_I2C_DEVICE),
+ (VOID **) &Dev );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device memory allocation failed\n"));
+ return Status;
+ }
+ *Device = Dev;
+ Dev->DeviceIndex = SlaveAddress;
+ Dev->DeviceIndex = I2C_DEVICE_INDEX(Bus, SlaveAddress);
+ Dev->SlaveAddressCount = 1;
+ Dev->I2cBusConfiguration = 0;
+ Status = gBS->AllocatePool ( EfiBootServicesData,
+ sizeof(UINT32),
+ (VOID **) &TmpSlaveArray);
+ if (EFI_ERROR(Status)) {
+ goto fail1;
+ }
+ TmpSlaveArray[0] = SlaveAddress;
+ Dev->SlaveAddressArray = TmpSlaveArray;
+
+ Status = gBS->AllocatePool ( EfiBootServicesData,
+ sizeof(EFI_GUID),
+ (VOID **) &TmpGuidP);
+ if (EFI_ERROR(Status)) {
+ goto fail2;
+ }
+ *TmpGuidP = DevGuid;
+ Dev->DeviceGuid = TmpGuidP;
+
+ DEBUG((DEBUG_INFO, "MvI2c: allocated device with address %x\n", (UINTN)SlaveAddress));
+ return EFI_SUCCESS;
+
+fail2:
+ FreePool(TmpSlaveArray);
+fail1:
+ FreePool(Dev);
+
+ return Status;
+}
+
+/*
+ * It is called by I2cBus to enumerate devices on I2C bus. In this case,
+ * enumeration is based on PCD configuration - all Slave addresses specified
+ * in PCD get their corresponding EFI_I2C_DEVICE structures here.
+ *
+ * After enumeration succeeds, Supported() function of drivers that installed
+ * DriverBinding protocol is called.
+ */
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnumerate (
+ IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
+ IN OUT CONST EFI_I2C_DEVICE **Device
+ )
+{
+ UINT8 *DevicesPcd;
+ UINT8 *DeviceBusPcd;
+ UINTN Index, NextIndex, DevCount;
+ UINT8 NextDeviceAddress;
+ I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_ENUMERATE(This);
+
+ DevCount = PcdGetSize (PcdI2cSlaveAddresses);
+ DevicesPcd = PcdGetPtr (PcdI2cSlaveAddresses);
+ DeviceBusPcd = PcdGetPtr (PcdI2cSlaveBuses);
+ if (*Device == NULL) {
+ for (Index = 0; Index < DevCount ; Index++) {
+ if (DeviceBusPcd[Index] != I2cMasterContext->Bus)
+ continue;
+ if (Index < DevCount)
+ MvI2cAllocDevice (DevicesPcd[Index], I2cMasterContext->Bus, Device);
+ return EFI_SUCCESS;
+ }
+ } else {
+ /* Device is not NULL, so something was already allocated */
+ for (Index = 0; Index < DevCount; Index++) {
+ if (DeviceBusPcd[Index] != I2cMasterContext->Bus)
+ continue;
+ if (DevicesPcd[Index] == I2C_DEVICE_ADDRESS((*Device)->DeviceIndex)) {
+ for (NextIndex = Index + 1; NextIndex < DevCount; NextIndex++) {
+ if (DeviceBusPcd[NextIndex] != I2cMasterContext->Bus)
+ continue;
+ NextDeviceAddress = DevicesPcd[NextIndex];
+ if (NextIndex < DevCount)
+ MvI2cAllocDevice(NextDeviceAddress, I2cMasterContext->Bus, Device);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ *Device = NULL;
+ return EFI_SUCCESS;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnableConf (
+ IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
+ IN UINTN I2cBusConfiguration,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_STATUS *I2cStatus OPTIONAL
+ )
+{
+ /* do nothing */
+ if (I2cStatus != NULL)
+ I2cStatus = EFI_SUCCESS;
+ if (Event != NULL)
+ gBS->SignalEvent(Event);
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h new file mode 100644 index 0000000000..028fd5461f --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h @@ -0,0 +1,269 @@ +/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MV_I2C_H__
+#define __MV_I2C_H__
+
+#include <Uefi.h>
+
+#define I2C_BASE_ADDRESS 0xf0511000
+
+#define I2C_SLAVE_ADDR 0x00
+#define I2C_EXT_SLAVE_ADDR 0x10
+#define I2C_DATA 0x04
+
+#define I2C_CONTROL 0x08
+#define I2C_CONTROL_ACK (1 << 2)
+#define I2C_CONTROL_IFLG (1 << 3)
+#define I2C_CONTROL_STOP (1 << 4)
+#define I2C_CONTROL_START (1 << 5)
+#define I2C_CONTROL_I2CEN (1 << 6)
+#define I2C_CONTROL_INTEN (1 << 7)
+
+#define I2C_STATUS 0x0c
+#define I2C_STATUS_START 0x08
+#define I2C_STATUS_RPTD_START 0x10
+#define I2C_STATUS_ADDR_W_ACK 0x18
+#define I2C_STATUS_DATA_WR_ACK 0x28
+#define I2C_STATUS_ADDR_R_ACK 0x40
+#define I2C_STATUS_DATA_RD_ACK 0x50
+#define I2C_STATUS_DATA_RD_NOACK 0x58
+
+#define I2C_BAUD_RATE 0x0c
+#define I2C_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f)
+#define I2C_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1)))
+#define I2C_M_FROM_BAUD(baud) (((baud) >> 3) & 0xf)
+#define I2C_N_FROM_BAUD(baud) ((baud) & 0x7)
+
+#define I2C_SOFT_RESET 0x1c
+#define I2C_TRANSFER_TIMEOUT 10000
+#define I2C_OPERATION_TIMEOUT 1000
+
+#define I2C_UNKNOWN 0x0
+#define I2C_SLOW 0x1
+#define I2C_FAST 0x2
+#define I2C_FASTEST 0x3
+
+/*
+ * I2C_FLAG_NORESTART is not part of PI spec, it allows to continue
+ * transmission without repeated start operation.
+ * FIXME: This flag is also defined in
+ * Platforms/Marvell/Include/Protocol/Eeprom.h and it's important to have both
+ * version synced. This solution is temporary and shared flag should be used by
+ * both files.
+ * Situation is analogous with I2C_GUID, which also should be common, but is
+ * for now defined same way in two header files.
+ */
+#define I2C_FLAG_NORESTART 0x00000002
+#define I2C_GUID \
+ { \
+ 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \
+ }
+
+#define I2C_MASTER_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'M')
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Controller;
+ EFI_LOCK Lock;
+ UINTN TclkFrequency;
+ UINTN BaseAddress;
+ INTN Bus;
+ EFI_I2C_MASTER_PROTOCOL I2cMaster;
+ EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate;
+ EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cBusConf;
+} I2C_MASTER_CONTEXT;
+
+#define I2C_SC_FROM_MASTER(a) CR (a, I2C_MASTER_CONTEXT, I2cMaster, I2C_MASTER_SIGNATURE)
+#define I2C_SC_FROM_ENUMERATE(a) CR (a, I2C_MASTER_CONTEXT, I2cEnumerate, I2C_MASTER_SIGNATURE)
+#define I2C_SC_FROM_BUSCONF(a) CR (a, I2C_MASTER_CONTEXT, I2cBusConf, I2C_MASTER_SIGNATURE)
+
+typedef struct {
+ UINT32 raw;
+ UINTN param;
+ UINTN m;
+ UINTN n;
+} MV_I2C_BAUD_RATE;
+
+typedef struct {
+ VENDOR_DEVICE_PATH Guid;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} MV_I2C_DEVICE_PATH;
+
+STATIC
+UINT32
+I2C_READ(
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off
+ );
+
+STATIC
+EFI_STATUS
+I2C_WRITE (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off,
+ IN UINT32 val
+ );
+
+EFI_STATUS
+EFIAPI
+MvI2cInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+STATIC
+VOID
+MvI2cControlClear (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 mask
+ );
+
+STATIC
+VOID
+MvI2cControlSet (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 mask
+ );
+
+STATIC
+VOID
+MvI2cClearIflg (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ );
+STATIC
+UINTN
+MvI2cPollCtrl (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN timeout,
+ IN UINT32 mask
+ );
+
+STATIC
+EFI_STATUS
+MvI2cLockedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN INT32 mask,
+ IN UINT8 slave,
+ IN UINTN timeout
+ );
+
+STATIC
+VOID
+MvI2cCalBaudRate (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN CONST UINT32 target,
+ IN OUT MV_I2C_BAUD_RATE *rate,
+ UINT32 clk
+ );
+
+EFI_STATUS
+EFIAPI
+MvI2cReset (
+ IN CONST EFI_I2C_MASTER_PROTOCOL *This
+ );
+
+STATIC
+EFI_STATUS
+MvI2cRepeatedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 slave,
+ IN UINTN timeout
+ );
+
+STATIC
+EFI_STATUS
+MvI2cStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 slave,
+ IN UINTN timeout
+ );
+
+STATIC
+EFI_STATUS
+MvI2cStop (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ );
+
+STATIC
+EFI_STATUS
+MvI2cRead (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT UINT8 *buf,
+ IN UINTN len,
+ IN OUT UINTN *read,
+ IN UINTN last,
+ IN UINTN delay
+ );
+
+STATIC
+EFI_STATUS
+MvI2cWrite (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT CONST UINT8 *buf,
+ IN UINTN len,
+ IN OUT UINTN *sent,
+ IN UINTN timeout
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cStartRequest (
+ 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
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnumerate (
+ IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
+ IN OUT CONST EFI_I2C_DEVICE **Device
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnableConf (
+ IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
+ IN UINTN I2cBusConfiguration,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_STATUS *I2cStatus OPTIONAL
+ );
+
+#endif // __MV_I2C_H__
diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf new file mode 100755 index 0000000000..16374ef5e7 --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf @@ -0,0 +1,75 @@ +#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MvI2cDxe
+ FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509b
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvI2cInitialise
+
+[Sources.common]
+ MvI2cDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ IoLib
+ PcdLib
+ BaseLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ ParsePcdLib
+
+[Protocols]
+ gEfiI2cMasterProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiI2cEnumerateProtocolGuid
+ gEfiI2cBusConfigurationManagementProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses
+ gMarvellTokenSpaceGuid.PcdI2cSlaveBuses
+ gMarvellTokenSpaceGuid.PcdI2cBaseAddresses
+ gMarvellTokenSpaceGuid.PcdI2cClockFrequency
+ gMarvellTokenSpaceGuid.PcdI2cBaudRate
+ gMarvellTokenSpaceGuid.PcdI2cBusCount
+
+[Depex]
+ TRUE
|