Skip to content

Commit

Permalink
Silicon/Rockchip: I2cDxe: Add runtime support
Browse files Browse the repository at this point in the history
  • Loading branch information
mariobalanica committed Aug 5, 2023
1 parent 4b862ed commit 9ec1e44
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 36 deletions.
135 changes: 110 additions & 25 deletions edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/********************************************************************************
Copyright (C) 2021 Rockchip Electronics Co., Ltd
SPDX-License-Identifier: BSD-2-Clause-Patent
*******************************************************************************/
/** @file
*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
* Copyright (c) 2023, Mario Bălănică <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/

#include <Protocol/I2cMaster.h>
#include <Protocol/I2cEnumerate.h>
Expand All @@ -16,10 +18,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/BaseLib.h>
#include <Library/IoLib.h>
#include <Library/DebugLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeLib.h>
#include <Library/RockchipPlatformLib.h>

#include <Soc.h>
Expand Down Expand Up @@ -147,18 +151,36 @@ I2cGetVersion(
return Version >>= I2C_CON_VERSION_SHIFT;
}

STATIC
VOID
EFIAPI
I2cVirtualAddressChangeNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
I2C_MASTER_CONTEXT *I2cMasterContext = Context;

EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->BaseAddress);
EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->I2cMaster.SetBusFrequency);
EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->I2cMaster.Reset);
EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->I2cMaster.StartRequest);
}

EFI_STATUS
EFIAPI
I2cInitialiseController (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT32 BusId
IN UINT32 BusId,
IN BOOLEAN RuntimeSupport
)
{
EFI_STATUS Status;
I2C_MASTER_CONTEXT *I2cMasterContext;
I2C_DEVICE_PATH *DevicePath;
EFI_EVENT VirtualAddressChangeEvent = NULL;

DEBUG ((EFI_D_VERBOSE, "I2cInitialiseController\n"));
DevicePath = AllocateCopyPool (sizeof(I2cDevicePathProtocol),
Expand All @@ -169,8 +191,12 @@ I2cInitialiseController (
}
DevicePath->Instance = BusId;

/* if attachment succeeds, this gets freed at ExitBootServices */
I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT));
if (RuntimeSupport) {
I2cMasterContext = AllocateRuntimeZeroPool (sizeof (I2C_MASTER_CONTEXT));
} else {
I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT));
}

if (I2cMasterContext == NULL) {
DEBUG((DEBUG_ERROR, "I2cDxe: I2C master context allocation failed\n"));
return EFI_OUT_OF_RESOURCES;
Expand All @@ -185,7 +211,43 @@ I2cInitialiseController (
I2cMasterContext->TclkFrequency = PcdGet32 (PcdI2cClockFrequency);
I2cMasterContext->BaseAddress = BaseAddress;
I2cMasterContext->Bus = BusId;
EfiInitializeLock(&I2cMasterContext->Lock, TPL_NOTIFY);
I2cMasterContext->RuntimeSupport = RuntimeSupport;

if (RuntimeSupport) {
Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeMemoryMappedIo,
BaseAddress,
I2C_PERIPHERAL_SIZE,
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: AddMemorySpace failed. Status=%r\n",
__FUNCTION__, Status));
goto fail;
}

Status = gDS->SetMemorySpaceAttributes (
BaseAddress,
I2C_PERIPHERAL_SIZE,
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: SetMemorySpaceAttributes failed. Status=%r\n",
__FUNCTION__, Status));
goto fail;
}

Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
I2cVirtualAddressChangeNotify,
I2cMasterContext,
&gEfiEventVirtualAddressChangeGuid,
&VirtualAddressChangeEvent);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to register for virtual address change. Status=%r\n",
__FUNCTION__, Status));
goto fail;
}
}

if (I2cGetVersion(I2cMasterContext) >= RkI2cVersion1) {
I2cAdapterBaudRate(I2cMasterContext,
Expand Down Expand Up @@ -222,6 +284,10 @@ I2cInitialiseController (
return EFI_SUCCESS;

fail:
if (VirtualAddressChangeEvent && RuntimeSupport) {
gBS->CloseEvent (VirtualAddressChangeEvent);
}

FreePool(I2cMasterContext);
return Status;
}
Expand Down Expand Up @@ -280,12 +346,14 @@ I2cInitialise (
EFI_EVENT EndOfDxeEvent;
UINT8 *DeviceBusPcd;
UINT32 DeviceBusCount;
UINT8 *BusRuntimeSupport;
EFI_STATUS Status;
UINTN Index;
BOOLEAN ConfiguredBuses[I2C_COUNT] = {0};

DeviceBusPcd = PcdGetPtr (PcdI2cSlaveBuses);
DeviceBusCount = PcdGetSize (PcdI2cSlaveBuses);
BusRuntimeSupport = PcdGetPtr (PcdI2cSlaveBusesRuntimeSupport);

/* Initialize enabled chips */
for (Index = 0; Index < DeviceBusCount; Index++) {
Expand Down Expand Up @@ -315,9 +383,10 @@ I2cInitialise (
ImageHandle,
SystemTable,
BaseAddress,
DeviceBusPcd[Index]
DeviceBusPcd[Index],
BusRuntimeSupport[Index]
);

if (EFI_ERROR(Status))
return Status;
}
Expand Down Expand Up @@ -462,11 +531,9 @@ I2cDisable (
{
DEBUG ((EFI_D_VERBOSE, "I2c I2cDisable.\n"));

EfiAcquireLock (&I2cMasterContext->Lock);
I2cWrite(I2cMasterContext, I2C_IEN, 0);
I2cWrite(I2cMasterContext, I2C_IPD, I2C_IPD_ALL_CLEAN);
I2cWrite(I2cMasterContext, I2C_CON, 0);
EfiReleaseLock (&I2cMasterContext->Lock);
}

/*
Expand Down Expand Up @@ -496,7 +563,6 @@ I2cStartEnable (
if (Timeout <= 0) {
DEBUG ((EFI_D_ERROR, "I2C Send Start Bit Timeout\n"));
I2cShowRegs(I2cMasterContext);
EfiReleaseLock (&I2cMasterContext->Lock);
return EFI_TIMEOUT;
}

Expand All @@ -513,8 +579,6 @@ I2cStop (

DEBUG ((EFI_D_VERBOSE, "I2c Send Stop bit.\n"));

EfiAcquireLock (&I2cMasterContext->Lock);

I2cWrite(I2cMasterContext, I2C_IPD, I2C_IPD_ALL_CLEAN);
I2cWrite(I2cMasterContext, I2C_CON, I2C_CON_EN | I2C_CON_STOP |I2cMasterContext->Config);
I2cWrite(I2cMasterContext, I2C_IEN, I2C_CON_STOP);
Expand All @@ -530,12 +594,9 @@ I2cStop (
if (TimeOut <= 0) {
DEBUG ((EFI_D_ERROR, "I2C Send Stop Bit Timeout\n"));
I2cShowRegs(I2cMasterContext);
EfiReleaseLock (&I2cMasterContext->Lock);
return EFI_TIMEOUT;
}

EfiReleaseLock (&I2cMasterContext->Lock);

return EFI_SUCCESS;
}

Expand Down Expand Up @@ -565,7 +626,6 @@ I2cReadOperation (
DEBUG ((EFI_D_VERBOSE, "I2cRead: base_addr = 0x%x buf = %p, Length = %d\n",
I2cMasterContext->BaseAddress, Buf, Length));

EfiAcquireLock (&I2cMasterContext->Lock);
/* If the second message for TRX read, resetting internal state. */
if (Snd) {
I2cWrite(I2cMasterContext, I2C_CON, 0);
Expand Down Expand Up @@ -602,7 +662,7 @@ I2cReadOperation (
goto out;
}

I2cWrite(I2cMasterContext, I2C_IEN, I2C_MBRFIEN | I2C_NAKRCVIEN);
I2cWrite(I2cMasterContext, I2C_IEN, I2C_MBRFIEN | I2C_NAKRCVIEN);
I2cWrite(I2cMasterContext, I2C_MRXCNT, BytesTranferedLen);

while (TimeOut--) {
Expand Down Expand Up @@ -645,7 +705,6 @@ I2cReadOperation (
(*Read) = Length;

out:
EfiReleaseLock (&I2cMasterContext->Lock);
return (Status);
}

Expand Down Expand Up @@ -673,7 +732,6 @@ I2cWriteOperation (
DEBUG ((EFI_D_VERBOSE, "I2cWrite: base_addr = 0x%x buf = %p, Length = %d\n",
I2cMasterContext->BaseAddress, Buf, Length));

EfiAcquireLock (&I2cMasterContext->Lock);
(*Sent) = 0;

while (BytesRemainLen) {
Expand Down Expand Up @@ -744,7 +802,6 @@ I2cWriteOperation (
(*Sent) = Length;
Status = EFI_SUCCESS;
out:
EfiReleaseLock (&I2cMasterContext->Lock);
return (Status);
}

Expand All @@ -770,12 +827,34 @@ I2cStartRequest (
EFI_I2C_OPERATION *Operation;
EFI_STATUS Status = EFI_SUCCESS;
UINTN i;
BOOLEAN AtRuntime;
EFI_TPL Tpl;

ASSERT (RequestPacket != NULL);
ASSERT (I2cMasterContext != NULL);

AtRuntime = EfiAtRuntime ();

// Events do not fire at runtime, so we can't support asynchronous requests.
if (AtRuntime && Event != NULL) {
return EFI_UNSUPPORTED;
}

DEBUG ((EFI_D_VERBOSE, "I2cStartRequest.\n"));

if (!AtRuntime) {
// Disable (timer) interrupts.
Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
} else if (I2cMasterContext->RuntimeSupport) {
//
// TO-DO:
// Implement some synchronization mechanism between this code path
// and the HLOS I2C driver, to prevent a race condition.
//
// See: https://github.com/edk2-porting/edk2-rk3588/issues/70
//
}

if (Count > 2 || ((Count == 2) && (RequestPacket->Operation->Flags & I2C_FLAG_READ))) {
DEBUG ((EFI_D_VERBOSE, "Not support more messages now, split them\n"));
return EFI_INVALID_PARAMETER;
Expand Down Expand Up @@ -815,6 +894,12 @@ I2cStartRequest (
I2cStop (I2cMasterContext);
I2cDisable (I2cMasterContext);

if (!AtRuntime) {
gBS->RestoreTPL (Tpl);
} else if (I2cMasterContext->RuntimeSupport) {
// TO-DO: See above.
}

if (I2cStatus != NULL)
*I2cStatus = EFI_SUCCESS;
if (Event != NULL)
Expand Down
18 changes: 10 additions & 8 deletions edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
/********************************************************************************
Copyright (C) 2021 Rockchip Electronics Co., Ltd
SPDX-License-Identifier: BSD-2-Clause-Patent
*******************************************************************************/
/** @file
*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
* Copyright (c) 2023, Mario Bălănică <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/

#ifndef __RK_I2C_DXE_H__
#define __RK_I2C_DXE_H__

#include <Uefi.h>

#define I2C_BASE_ADDRESS 0xf0511000
#define I2C_PERIPHERAL_SIZE 0x1000

#define I2C_SLAVE_ADDR 0x00
#define I2C_EXT_SLAVE_ADDR 0x10
Expand Down Expand Up @@ -146,11 +148,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
typedef struct {
UINT32 Signature;
EFI_HANDLE Controller;
EFI_LOCK Lock;
UINTN TclkFrequency;
UINTN BaseAddress;
INTN Bus;
UINTN Config;
BOOLEAN RuntimeSupport;
EFI_I2C_MASTER_PROTOCOL I2cMaster;
EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate;
EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cBusConf;
Expand Down
15 changes: 12 additions & 3 deletions edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
#/** @file
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
# Copyright (c) 2021 Rockchip Electronics Co., Ltd.
# Copyright (c) 2023, Mario Bălănică <[email protected]>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#**/

[Defines]
INF_VERSION = 0x00010005
BASE_NAME = I2cDxe
FILE_GUID = 9335a854-4b88-11ec-a8ee-f42a7dcb925d
MODULE_TYPE = DXE_DRIVER
MODULE_TYPE = DXE_RUNTIME_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = I2cInitialise

Expand All @@ -26,9 +31,11 @@
PcdLib
BaseLib
DebugLib
DxeServicesTableLib
UefiLib
UefiDriverEntryPoint
UefiBootServicesTableLib
UefiRuntimeLib
RockchipPlatformLib
TimerLib

Expand All @@ -42,11 +49,13 @@
[Pcd]
gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses
gRockchipTokenSpaceGuid.PcdI2cSlaveBuses
gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport
gRockchipTokenSpaceGuid.PcdI2cClockFrequency
gRockchipTokenSpaceGuid.PcdI2cBaudRate

[Guids]
gEfiEndOfDxeEventGroupGuid
gEfiEventVirtualAddressChangeGuid

[Depex]
TRUE
gEfiCpuArchProtocolGuid
1 change: 1 addition & 0 deletions edk2-rockchip/Silicon/Rockchip/RockchipPkg.dec
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x0 }|VOID*|0x02000001
gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0 }|VOID*|0x02000002
gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ 0x0 }|VOID*|0x02000003
gRockchipTokenSpaceGuid.PcdI2cClockFrequency|0|UINT32|0x02000004
gRockchipTokenSpaceGuid.PcdI2cBaudRate|0|UINT32|0x02000005
gRockchipTokenSpaceGuid.PcdI2cDemoAddresses|{ 0x0 }|VOID*|0x02000007
Expand Down

0 comments on commit 9ec1e44

Please sign in to comment.