From: BigfootACA Date: 星期二, 3 May 2022 04:47:12 +0000 (+0800) Subject: sdm845Pkg: Drivers: add SynapticsTouchDxe X-Git-Tag: v2.0rc2~29 X-Git-Url: https://git.renegade-project.org/?a=commitdiff_plain;h=de0700fa969b1d827ddc188c569cdb5a7b3f1d78;p=edk2-sdm845.git sdm845Pkg: Drivers: add SynapticsTouchDxe https://github.com/WOA-Project/Lumia950XLPkg/tree/master/Driver/SynapticsTouchDxe --- diff --git a/sdm845Pkg/Drivers/SynapticsTouchDxe/ComponentName.c b/sdm845Pkg/Drivers/SynapticsTouchDxe/ComponentName.c new file mode 100644 index 0000000..9e2dad8 --- /dev/null +++ b/sdm845Pkg/Drivers/SynapticsTouchDxe/ComponentName.c @@ -0,0 +1,82 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "SynapticsRmi4.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL + gRmi4DriverComponentName = {Rmi4DriverComponentNameGetDriverName, + Rmi4DriverComponentNameGetControllerName, + "eng"}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL + gRmi4DriverComponentName2 = {(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) + Rmi4DriverComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) + Rmi4DriverComponentNameGetControllerName, + "en"}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mRmi4DriverNameTable[] = + {{"eng;en", L"Synaptics RMI4 Absolute Pointer Driver"}, {NULL, NULL}}; + +EFI_STATUS +EFIAPI +Rmi4DriverComponentNameGetDriverName( + IN EFI_COMPONENT_NAME_PROTOCOL *This, IN CHAR8 *Language, + OUT CHAR16 **DriverName) +{ + return LookupUnicodeString2( + Language, This->SupportedLanguages, mRmi4DriverNameTable, DriverName, + (BOOLEAN)(This == &gRmi4DriverComponentName)); +} + +EFI_STATUS +EFIAPI +Rmi4DriverComponentNameGetControllerName( + IN EFI_COMPONENT_NAME_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, + OUT CHAR16 **ControllerName) +{ + EFI_STATUS Status; + RMI4_INTERNAL_DATA * Instance; + EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointerProtocol; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol( + ControllerHandle, &gEfiAbsolutePointerProtocolGuid, + (VOID **)&AbsolutePointerProtocol, gRmi4DriverBinding.DriverBindingHandle, + ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(Status)) { + return Status; + } + + Instance = RMI4_TCH_INSTANCE_FROM_ABSTCH_THIS(AbsolutePointerProtocol); + + return LookupUnicodeString2( + Language, This->SupportedLanguages, Instance->ControllerNameTable, + ControllerName, (BOOLEAN)(This == &gRmi4DriverComponentName)); +} diff --git a/sdm845Pkg/Drivers/SynapticsTouchDxe/I2cOps.c b/sdm845Pkg/Drivers/SynapticsTouchDxe/I2cOps.c new file mode 100644 index 0000000..321e146 --- /dev/null +++ b/sdm845Pkg/Drivers/SynapticsTouchDxe/I2cOps.c @@ -0,0 +1,97 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "SynapticsRmi4.h" + +EFI_STATUS +EFIAPI +SynaI2cRead( + RMI4_INTERNAL_DATA *Instance, IN UINT8 Address, IN UINT8 *Data, + IN UINT16 ReadBytes) +{ + UINT32 Reads = 0; + I2C_STATUS I2CStatus = I2C_SUCCESS; + EFI_STATUS Status = EFI_SUCCESS; + + if (Instance == NULL || Instance->Rmi4Device == NULL || + Instance->I2cController == NULL || + Instance->Rmi4Device->I2cQupProtocol == NULL) { + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + if (Data == NULL) { + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + I2CStatus = Instance->Rmi4Device->I2cQupProtocol->Read( + Instance->I2cController, + &Instance->Rmi4Device->SlaveCfg, + Address, + sizeof(Address), + Data, + ReadBytes, + &Reads, + 0 + ); + + if (I2C_ERROR (I2CStatus)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: I2C Read Failed: %d\n", I2CStatus)); + Status = EFI_DEVICE_ERROR; + } + +exit: + return Status; +} + +EFI_STATUS +EFIAPI +SynaI2cWrite( + RMI4_INTERNAL_DATA *Instance, IN UINT8 Address, IN UINT8 *Data, + IN UINT16 WriteBytes) +{ + UINT32 Writes = 0; + I2C_STATUS I2CStatus = I2C_SUCCESS; + EFI_STATUS Status = EFI_SUCCESS; + + if (Instance == NULL || Instance->Rmi4Device == NULL || + Instance->I2cController == NULL || + Instance->Rmi4Device->I2cQupProtocol == NULL) { + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + if (Data == NULL) { + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + I2CStatus = Instance->Rmi4Device->I2cQupProtocol->Write( + Instance->I2cController, + &Instance->Rmi4Device->SlaveCfg, + Address, + sizeof(Address), + Data, + WriteBytes, + &Writes, + 0 + ); + + if (I2C_ERROR (I2CStatus)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: I2C Read Failed: %d\n", I2CStatus)); + Status = EFI_DEVICE_ERROR; + } + +exit: + return Status; +} diff --git a/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsRmi4.h b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsRmi4.h new file mode 100644 index 0000000..bd1031e --- /dev/null +++ b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsRmi4.h @@ -0,0 +1,142 @@ +#ifndef _SYNAPTICS_RMI4_H_ +#define _SYNAPTICS_RMI4_H_ + +#define TOUCH_RMI_PAGE_INFO_BYTES 6 +#define TOUCH_RMI_PAGE_INFO_ADDRESS 0xE9 +#define TOUCH_RMI_MAX_FUNCTIONS 10 +#define TOUCH_RMI_F12_FUNCTION 0x12 + +#define TOUCH_DELAY_TO_COMMUNICATE 200000 +#define TOUCH_POWER_RAIL_STABLE_TIME 2000 + +#define RMI_CHANGE_PAGE_ADDRESS 0xFF + +#define TIMER_INTERVAL_TOUCH_POLL 100000 +#define TOUCH_BUFFER_SIZE 25 +#define TOUCH_DATA_BYTES 8 + +#define FAILURE_THRESHOLD 25 + +typedef struct _TOUCH_DATA { + UINT16 TouchX; + UINT16 TouchY; + UINT8 TouchStatus; +} TOUCH_DATA, *PTOUCH_DATA; + +// RMI4 device + +extern EFI_GUID gSynapticsTouchDeviceProtocolGuid; + +typedef struct _SYNAPTICS_I2C_DEVICE { + UINT32 Signature; + UINT32 XMax; + UINT32 YMax; + UINT32 XMin; + UINT32 YMin; + BOOLEAN XInverted; + BOOLEAN YInverted; + UINT32 ControllerResetPin; + UINT32 ControllerInterruptPin; + UINT32 ControllerI2cDevice; + EFI_QCOM_TLMM_PROTOCOL *GpioTlmmProtocol; + EFI_QCOM_I2C_PROTOCOL *I2cQupProtocol; + I2C_SLAVE_CONFIG SlaveCfg; +} SYNAPTICS_I2C_DEVICE; + +#define RMI4_DEV_INSTANCE_SIGNATURE SIGNATURE_32('r', 'm', '4', 'd') + +// RMI4 driver internals + +typedef struct _RMI4_INTERNAL_DATA { + UINT32 Signature; + UINT16 LastX; + UINT16 LastY; + EFI_ABSOLUTE_POINTER_PROTOCOL AbsPointerProtocol; + EFI_ABSOLUTE_POINTER_MODE AbsPointerMode; + EFI_EVENT PollingTimerEvent; + BOOLEAN Initialized; + UINT8 PageF12; + UINT32 TouchDataAddress; + UINT32 FailureCount; + VOID *I2cController; + BOOLEAN StateChanged; + SYNAPTICS_I2C_DEVICE *Rmi4Device; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} RMI4_INTERNAL_DATA; + +#define RMI4_TCH_INSTANCE_SIGNATURE SIGNATURE_32('r', 'm', 'i', '4') +#define RMI4_TCH_INSTANCE_FROM_ABSTCH_THIS(a) \ + CR(a, RMI4_INTERNAL_DATA, AbsPointerProtocol, RMI4_TCH_INSTANCE_SIGNATURE) + +// Below is the driver binding section + +extern EFI_DRIVER_BINDING_PROTOCOL gRmi4DriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gRmi4DriverComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gRmi4DriverComponentName2; + +EFI_STATUS +EFIAPI +Rmi4AbsolutePointerDriverBindingSupported( + IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); + +EFI_STATUS +EFIAPI +Rmi4AbsolutePointerDriverBindingStart( + IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); + +EFI_STATUS +EFIAPI +Rmi4AbsolutePointerDriverBindingStop( + IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer); + +EFI_STATUS +EFIAPI +Rmi4DriverComponentNameGetDriverName( + IN EFI_COMPONENT_NAME_PROTOCOL *This, IN CHAR8 *Language, + OUT CHAR16 **DriverName); + +EFI_STATUS +EFIAPI +Rmi4DriverComponentNameGetControllerName( + IN EFI_COMPONENT_NAME_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, + OUT CHAR16 **ControllerName); + +// Below is RMI4 driver code +EFI_STATUS +EFIAPI +SynaI2cRead( + RMI4_INTERNAL_DATA *Instance, IN UINT8 Address, IN UINT8 *Data, + IN UINT16 ReadBytes); + +EFI_STATUS +EFIAPI +SynaI2cWrite( + RMI4_INTERNAL_DATA *Instance, IN UINT8 Address, IN UINT8 *Data, + IN UINT16 WriteBytes); + +EFI_STATUS AbsPReset( + IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, IN BOOLEAN ExtendedVerification); + +EFI_STATUS AbsPGetState( + IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, + IN OUT EFI_ABSOLUTE_POINTER_STATE *State); + +EFI_STATUS AbsStartPolling(IN RMI4_INTERNAL_DATA *Instance); + +VOID EFIAPI AbsPWaitForInput(IN EFI_EVENT Event, IN VOID *Context); + +VOID EFIAPI SyncPollCallback(IN EFI_EVENT Event, IN VOID *Context); + +EFI_STATUS EFIAPI SynaPowerUpController(RMI4_INTERNAL_DATA *Instance); + +EFI_STATUS +EFIAPI +SyncGetTouchData(RMI4_INTERNAL_DATA *Instance, IN PTOUCH_DATA DataBuffer); + +VOID EFIAPI SyncPollCallback(IN EFI_EVENT Event, IN VOID *Context); + +#endif \ No newline at end of file diff --git a/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDevice.c b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDevice.c new file mode 100644 index 0000000..7702369 --- /dev/null +++ b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDevice.c @@ -0,0 +1,102 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "SynapticsRmi4.h" +#include + +SYNAPTICS_I2C_DEVICE mTemplate = { + .Signature = RMI4_DEV_INSTANCE_SIGNATURE, + .XMax = 0, + .YMax = 0, + .XMin = 0, + .YMin = 0, + .XInverted = FALSE, + .YInverted = FALSE, + .ControllerResetPin = 0, + .ControllerInterruptPin = 0, + .ControllerI2cDevice = 0, + .GpioTlmmProtocol = 0, + .GpioTlmmProtocol = NULL, + .I2cQupProtocol = NULL, + .SlaveCfg = { + .BusFrequency = I2C_FAST_MODE_FREQ_KHZ, + .SlaveAddress = 0, + .Mode = I2C, + .SlaveMaxClockStretch = 500, + .CoreConfiguration1 = 0, + .CoreConfiguration2 = 0, + }, +}; + +EFI_STATUS EFIAPI SynaDeviceInitialize( + IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) +{ + SYNAPTICS_I2C_DEVICE *Instance; + EFI_STATUS Status; + + // Device instance + Instance = AllocateCopyPool(sizeof(SYNAPTICS_I2C_DEVICE), &mTemplate); + if (Instance == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto exit; + } + + // Config + Instance->SlaveCfg.SlaveAddress = PcdGet16(PcdTouchCtlrAddress); + Instance->ControllerI2cDevice = PcdGet32(PcdTouchCtlrI2cDevice); + Instance->ControllerResetPin = PcdGet32(PcdTouchCtlrResetPin); + Instance->ControllerInterruptPin = PcdGet32(PcdTouchCtlrIntPin); + Instance->XMax = PcdGet32(PcdTouchMaxX); + Instance->XMin = PcdGet32(PcdTouchMinX); + Instance->XInverted = PcdGetBool(PcdTouchInvertedX); + Instance->YMax = PcdGet32(PcdTouchMaxY); + Instance->YMin = PcdGet32(PcdTouchMinY); + Instance->YInverted = PcdGetBool(PcdTouchInvertedY); + DEBUG((EFI_D_INFO, + "SynapticsTouchDevice: " + "Address: 0x%X Device: %d " + "ResetPin: %d IntPin: %d " + "X: %d - %d (Inverted: %d) " + "Y: %d - %d (Inverted: %d)\n", + Instance->SlaveCfg.SlaveAddress, Instance->ControllerI2cDevice, + Instance->ControllerResetPin, Instance->ControllerInterruptPin, + Instance->XMin, Instance->XMax, Instance->XInverted, + Instance->YMax, Instance->YMax, Instance->YInverted + )); + + // I2C Protocol + Status = gBS->LocateProtocol( + &gQcomI2cProtocolGuid, NULL, (VOID *)&Instance->I2cQupProtocol); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDevice: Unable to locate I2C protocol: %r\n", Status)); + goto exit; + } + + // GPIO Processing + Status = gBS->LocateProtocol( + &gQcomTlmmProtocolGuid, NULL, (VOID *)&Instance->GpioTlmmProtocol); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDevice: Unable to locate GPIO protocol: %r\n", Status)); + goto exit; + } + + // Looks good and publish the protocol + Status = gBS->InstallMultipleProtocolInterfaces( + &ImageHandle, &gSynapticsTouchDeviceProtocolGuid, Instance, + &gEfiDevicePathProtocolGuid, &TouchDxeDevicePath, NULL); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDevice: Unable to install protocol: %r\n", Status)); + } + +exit: + return Status; +} diff --git a/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDevice.inf b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDevice.inf new file mode 100644 index 0000000..1cdf67b --- /dev/null +++ b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDevice.inf @@ -0,0 +1,56 @@ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SynapticsTouchDeviceDxe + FILE_GUID = f0d87c5e-4d5d-4fb5-939f-a6768ae8a310 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SynaDeviceInitialize + +[Sources.common] + SynapticsTouchDevice.c + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + sdm845Pkg/sdm845Pkg.dec + +[BuildOptions.AARCH64] + GCC:*_*_*_CC_FLAGS = -Werror -Wno-error=unused-variable + +[LibraryClasses] + ArmLib + UefiDriverEntryPoint + IoLib + TimerLib + BaseLib + DebugLib + PrintLib + CompilerIntrinsicsLib + CacheMaintenanceLib + UefiLib + +[Pcd] + gsdm845PkgTokenSpaceGuid.PcdMipiFrameBufferWidth + gsdm845PkgTokenSpaceGuid.PcdMipiFrameBufferHeight + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrAddress + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrResetPin + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrIntPin + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrI2cDevice + gsdm845PkgTokenSpaceGuid.PcdTouchMinX + gsdm845PkgTokenSpaceGuid.PcdTouchMaxX + gsdm845PkgTokenSpaceGuid.PcdTouchInvertedX + gsdm845PkgTokenSpaceGuid.PcdTouchMinY + gsdm845PkgTokenSpaceGuid.PcdTouchMaxY + gsdm845PkgTokenSpaceGuid.PcdTouchInvertedY + +[Protocols] + gQcomI2cProtocolGuid + gQcomTlmmProtocolGuid + gHardwareInterruptProtocolGuid + gSynapticsTouchDeviceProtocolGuid + gEfiDevicePathProtocolGuid + +[Depex] + gQcomI2cProtocolGuid AND gQcomTlmmProtocolGuid + diff --git a/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDxe.c b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDxe.c new file mode 100644 index 0000000..3dee7de --- /dev/null +++ b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDxe.c @@ -0,0 +1,477 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "SynapticsRmi4.h" + +// Instance Template +RMI4_INTERNAL_DATA mInstanceTemplate = { + RMI4_TCH_INSTANCE_SIGNATURE, + 0, + 0, + { + AbsPReset, + AbsPGetState, + NULL, + NULL, + }, + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, + NULL, + FALSE, + 0, + 0, + 0, + NULL, + FALSE, + NULL, + NULL, +}; + +// Binding +EFI_DRIVER_BINDING_PROTOCOL gRmi4DriverBinding = { + Rmi4AbsolutePointerDriverBindingSupported, + Rmi4AbsolutePointerDriverBindingStart, + Rmi4AbsolutePointerDriverBindingStop, + 0x1, + NULL, + NULL, +}; + +EFI_STATUS +EFIAPI +Rmi4AbsolutePointerDriverBindingSupported( + IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) +{ + EFI_STATUS Status; + SYNAPTICS_I2C_DEVICE *Rmi4I2cDeviceIo; + + Status = gBS->OpenProtocol( + Controller, &gSynapticsTouchDeviceProtocolGuid, (VOID **)&Rmi4I2cDeviceIo, + This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER); + + if (EFI_ERROR(Status)) { + return Status; + } + + Status = EFI_SUCCESS; + gBS->CloseProtocol( + Controller, &gSynapticsTouchDeviceProtocolGuid, This->DriverBindingHandle, + Controller); + + return Status; +} + +EFI_STATUS +EFIAPI +Rmi4AbsolutePointerDriverBindingStart( + IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) +{ + EFI_TPL OldTpl; + EFI_STATUS Status; + I2C_STATUS I2CStatus; + SYNAPTICS_I2C_DEVICE *Rmi4I2cDeviceIo; + RMI4_INTERNAL_DATA * Instance; + + UINT8 InfoData[TOUCH_RMI_PAGE_INFO_BYTES] = {0}; + UINT8 Address = TOUCH_RMI_PAGE_INFO_ADDRESS; + + UINT8 Page = 0; + UINT8 Function = 0; + + OldTpl = gBS->RaiseTPL(TPL_CALLBACK); + Status = gBS->OpenProtocol( + Controller, &gSynapticsTouchDeviceProtocolGuid, (VOID **)&Rmi4I2cDeviceIo, + This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR(Status)) { + goto exit; + } + + Instance = AllocateCopyPool(sizeof(RMI4_INTERNAL_DATA), &mInstanceTemplate); + ASSERT(Instance != NULL); + ASSERT(Rmi4I2cDeviceIo != NULL); + + Instance->Rmi4Device = Rmi4I2cDeviceIo; + Instance->AbsPointerMode.AbsoluteMaxX = Rmi4I2cDeviceIo->XMax - Rmi4I2cDeviceIo->XMin; + Instance->AbsPointerMode.AbsoluteMaxY = Rmi4I2cDeviceIo->YMax - Rmi4I2cDeviceIo->YMin; + Instance->AbsPointerProtocol.Mode = &Instance->AbsPointerMode; + I2CStatus = Rmi4I2cDeviceIo->I2cQupProtocol->Open( + Instance->Rmi4Device->ControllerI2cDevice, + &Instance->I2cController); + + if (I2C_ERROR(I2CStatus)) { + DEBUG((EFI_D_ERROR, + "SynapticsTouchDxe: Failed to open I2C%d: %d \n", + Instance->Rmi4Device->ControllerI2cDevice, + I2CStatus)); + Status = EFI_DEVICE_ERROR; + goto exit; + } + + Status = SynaPowerUpController(Instance); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Failed to power on controller: %r\n", Status)); + goto exit; + } + + DEBUG((EFI_D_INFO, "SynapticsTouchDxe: Probe Synaptics RMI4 F12 Function \n")); + + // Probe device to locate F12 function + do { + Status = + SynaI2cRead(Instance, Address, &InfoData[0], TOUCH_RMI_PAGE_INFO_BYTES); + + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: I2C Read failed: %r\n", Status)); + goto exit; + } + + if (InfoData[5] == TOUCH_RMI_F12_FUNCTION) { + DEBUG((EFI_D_INFO, "SynapticsTouchDxe: RMI4 F12 Function Found. \n")); + Instance->PageF12 = Page; + Instance->TouchDataAddress = InfoData[3]; + break; + } + + // Last page. Go out + if (InfoData[5] == 0 && Address == TOUCH_RMI_PAGE_INFO_ADDRESS) { + break; + } + // Switch page + else if (InfoData[5] == 0 && Address != TOUCH_RMI_PAGE_INFO_ADDRESS) { + DEBUG((EFI_D_INFO, "SynapticsTouchDxe: Switching to next Synaptics RMI4 Page........")); + + Page++; + Address = TOUCH_RMI_PAGE_INFO_ADDRESS; + + Status = SynaI2cWrite(Instance, RMI_CHANGE_PAGE_ADDRESS, &Page, 1); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Unable to switch RMI4 page: %r\n", Status)); + goto exit; + } + } + else { + Function++; + Address = Address - TOUCH_RMI_PAGE_INFO_BYTES; + } + } while ((Address > 0) && (Function < TOUCH_RMI_MAX_FUNCTIONS)); + + // Determine final result + if (Function >= TOUCH_RMI_MAX_FUNCTIONS) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Invalid RMI4 function index \n")); + Status = EFI_DEVICE_ERROR; + goto exit; + } + + if (Address <= 0) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Invalid RMI4 address \n")); + Status = EFI_DEVICE_ERROR; + goto exit; + } + + // Flag device as initialized + Instance->Initialized = TRUE; + + // Set touch event + Status = gBS->CreateEvent( + EVT_NOTIFY_WAIT, TPL_NOTIFY, AbsPWaitForInput, Instance, + &Instance->AbsPointerProtocol.WaitForInput); + ASSERT_EFI_ERROR(Status); + + // Start polling + Status = AbsStartPolling(Instance); + ASSERT_EFI_ERROR(Status); + + // Install protocols + Status = gBS->InstallProtocolInterface( + &Controller, &gEfiAbsolutePointerProtocolGuid, EFI_NATIVE_INTERFACE, + &Instance->AbsPointerProtocol); + + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Failed to install protocol interface: %r\n", Status)); + } + + // Name table + Instance->ControllerNameTable = NULL; + AddUnicodeString2( + "eng", gRmi4DriverComponentName.SupportedLanguages, + &Instance->ControllerNameTable, L"Synaptics RMI4 Absolute Pointer", TRUE); + AddUnicodeString2( + "en", gRmi4DriverComponentName.SupportedLanguages, + &Instance->ControllerNameTable, L"Synaptics RMI4 Absolute Pointer", + FALSE); + +exit: + gBS->RestoreTPL(OldTpl); + return Status; +} + +EFI_STATUS +EFIAPI +Rmi4AbsolutePointerDriverBindingStop( + IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer) +{ + EFI_STATUS Status; + EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointerProtocol; + RMI4_INTERNAL_DATA * Instance; + + Status = gBS->OpenProtocol( + Controller, &gEfiAbsolutePointerProtocolGuid, + (VOID **)&AbsolutePointerProtocol, This->DriverBindingHandle, Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + Instance = RMI4_TCH_INSTANCE_FROM_ABSTCH_THIS(AbsolutePointerProtocol); + + Status = gBS->UninstallProtocolInterface( + Controller, &gEfiAbsolutePointerProtocolGuid, + &Instance->AbsPointerProtocol); + if (EFI_ERROR(Status)) { + return Status; + } + + gBS->CloseEvent(Instance->PollingTimerEvent); + gBS->CloseEvent(Instance->AbsPointerProtocol.WaitForInput); + + return EFI_SUCCESS; +} + +EFI_STATUS AbsPReset( + IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, IN BOOLEAN ExtendedVerification) +{ + RMI4_INTERNAL_DATA *Instance; + + Instance = RMI4_TCH_INSTANCE_FROM_ABSTCH_THIS(This); + Instance->LastX = 0; + Instance->LastY = 0; + Instance->StateChanged = FALSE; + + return EFI_SUCCESS; +} + +EFI_STATUS AbsStartPolling(IN RMI4_INTERNAL_DATA *Instance) +{ + EFI_STATUS Status = EFI_SUCCESS; + + // Set event routines + Status = gBS->CreateEvent( + EVT_NOTIFY_SIGNAL | EVT_TIMER, TPL_CALLBACK, SyncPollCallback, Instance, + &Instance->PollingTimerEvent); + ASSERT_EFI_ERROR(Status); + + Status = gBS->SetTimer(Instance->PollingTimerEvent, TimerPeriodic, 200000); + ASSERT_EFI_ERROR(Status); + + return Status; +} + +EFI_STATUS AbsPGetState( + IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, + IN OUT EFI_ABSOLUTE_POINTER_STATE *State) +{ + EFI_STATUS Status = EFI_SUCCESS; + RMI4_INTERNAL_DATA *Instance; + + if (This == NULL || State == NULL) { + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + Instance = RMI4_TCH_INSTANCE_FROM_ABSTCH_THIS(This); + if (!Instance->StateChanged) { + Status = EFI_NOT_READY; + goto exit; + } + + State->CurrentX = Instance->LastX; + State->CurrentY = Instance->LastY; + State->CurrentZ = 0; + State->ActiveButtons = 1; + Instance->StateChanged = FALSE; + +exit: + return Status; +} + +VOID EFIAPI AbsPWaitForInput(IN EFI_EVENT Event, IN VOID *Context) +{ + RMI4_INTERNAL_DATA *Instance = (RMI4_INTERNAL_DATA *)Context; + EFI_TPL OldTpl; + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL(TPL_NOTIFY); + + SyncPollCallback(NULL, Instance); + + if (Instance->StateChanged) { + gBS->SignalEvent(Event); + } + + // + // Leave critical section and return + // + gBS->RestoreTPL(OldTpl); +} + +EFI_STATUS +EFIAPI +SynaPowerUpController(RMI4_INTERNAL_DATA *Instance) +{ + UINT32 Config; + UINT32 ResetLine; + EFI_STATUS Status; + + if (Instance == NULL || Instance->Rmi4Device == NULL || + Instance->Rmi4Device->GpioTlmmProtocol == NULL) { + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + // Pin Sanity check + ResetLine = Instance->Rmi4Device->ControllerResetPin; + if (ResetLine <= 0) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Invalid GPIO configuration \n")); + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + // Power Seq + Config = EFI_GPIO_CFG( ResetLine, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA ); + Status = Instance->Rmi4Device->GpioTlmmProtocol->ConfigGpio(Config, TLMM_GPIO_ENABLE); + + // Configure MSM GPIO RESET line to Low + Instance->Rmi4Device->GpioTlmmProtocol->GpioOut(Config, GPIO_LOW_VALUE); + gBS->Stall(TOUCH_POWER_RAIL_STABLE_TIME); + + // configure MSM GPIO RESET line to High + Instance->Rmi4Device->GpioTlmmProtocol->GpioOut(Config, GPIO_HIGH_VALUE); + gBS->Stall(TOUCH_DELAY_TO_COMMUNICATE); + + DEBUG((EFI_D_INFO, "SynapticsTouchDxe: Touch controller powered on \n")); + Status = EFI_SUCCESS; + +exit: + return Status; +} + +EFI_STATUS +EFIAPI +SyncGetTouchData(RMI4_INTERNAL_DATA *Instance, IN PTOUCH_DATA DataBuffer) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT8 TouchCoordinates[TOUCH_DATA_BYTES] = {0}; + + if (Instance == NULL || DataBuffer == NULL) { + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + if (!Instance->Initialized) { + Status = EFI_NOT_READY; + goto exit; + } + + // Change RMI page to F12 + Status = + SynaI2cWrite(Instance, RMI_CHANGE_PAGE_ADDRESS, &Instance->PageF12, 1); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Failed to change RMI4 page address: %r\n", Status)); + goto exit; + } + + // Read a fingerprint + Status = SynaI2cRead( + Instance, Instance->TouchDataAddress, &TouchCoordinates[0], + TOUCH_DATA_BYTES); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Failed to read RMI4 F12 page data: %r\n", Status)); + goto exit; + } + + DataBuffer->TouchStatus = TouchCoordinates[0]; + DataBuffer->TouchX = + ((TouchCoordinates[1] & 0xFF) | ((TouchCoordinates[2] & 0xFF) << 8)); + DataBuffer->TouchY = + ((TouchCoordinates[3] & 0xFF) | ((TouchCoordinates[4] & 0xFF) << 8)); + +exit: + return Status; +} + +VOID EFIAPI SyncPollCallback(IN EFI_EVENT Event, IN VOID *Context) +{ + EFI_STATUS Status; + RMI4_INTERNAL_DATA *Instance = (RMI4_INTERNAL_DATA *)Context; + TOUCH_DATA TouchPointerData; + //EFI_TPL OldTpl; + + // + // Enter critical section + // + //OldTpl = gBS->RaiseTPL(TPL_NOTIFY); + + Status = SyncGetTouchData(Instance, &TouchPointerData); + + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "SynapticsTouchDxe: Failed to get Synaptics RMI4 F12 Data: %r\n", Status)); + } + else { + if (TouchPointerData.TouchStatus > 0) { + Instance->LastX = TouchPointerData.TouchX + Instance->Rmi4Device->XMin; + Instance->LastY = TouchPointerData.TouchY + Instance->Rmi4Device->YMin; + Instance->StateChanged = TRUE; + if (Instance->Rmi4Device->XInverted) { + Instance->LastX = Instance->AbsPointerMode.AbsoluteMaxX - Instance->LastX; + } + if (Instance->Rmi4Device->YInverted) { + Instance->LastY = Instance->AbsPointerMode.AbsoluteMaxY - Instance->LastY; + } + + DEBUG( + (EFI_D_INFO, "SynapticsTouchDxe: Touch: X: %d, Y: %d \n", Instance->LastX, + Instance->LastY)); + } + } + + // + // Leave critical section and return + // + //gBS->RestoreTPL(OldTpl); +} + +EFI_STATUS +EFIAPI +SynaInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + + Status = EfiLibInstallDriverBindingComponentName2( + ImageHandle, SystemTable, &gRmi4DriverBinding, ImageHandle, + &gRmi4DriverComponentName, &gRmi4DriverComponentName2); + ASSERT_EFI_ERROR(Status); + + return EFI_SUCCESS; +} diff --git a/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDxe.inf b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDxe.inf new file mode 100644 index 0000000..279360d --- /dev/null +++ b/sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDxe.inf @@ -0,0 +1,44 @@ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SynapticsTouchDxe + FILE_GUID = f0d87c5e-4d5d-4fb5-939f-a6768ae8a309 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SynaInitialize + +[Sources.common] + SynapticsTouchDxe.c + I2cOps.c + ComponentName.c + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + sdm845Pkg/sdm845Pkg.dec + +[BuildOptions.AARCH64] + GCC:*_*_*_CC_FLAGS = -Werror -Wno-error=unused-variable + +[LibraryClasses] + ArmLib + UefiDriverEntryPoint + IoLib + TimerLib + BaseLib + DebugLib + PrintLib + CompilerIntrinsicsLib + CacheMaintenanceLib + UefiLib + +[Protocols] + gQcomI2cProtocolGuid + gQcomTlmmProtocolGuid + gHardwareInterruptProtocolGuid + gEfiAbsolutePointerProtocolGuid + gSynapticsTouchDeviceProtocolGuid + gEfiDevicePathProtocolGuid + +[Depex] + gSynapticsTouchDeviceProtocolGuid diff --git a/sdm845Pkg/Include/Device/TouchDevicePath.h b/sdm845Pkg/Include/Device/TouchDevicePath.h new file mode 100644 index 0000000..d5913ff --- /dev/null +++ b/sdm845Pkg/Include/Device/TouchDevicePath.h @@ -0,0 +1,39 @@ +#ifndef _TOUCH_DEVICE_PATH_H_ +#define _TOUCH_DEVICE_PATH_H_ + +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} EFI_TOUCH_DEVICE_PATH; + +#define TOUCH_DEVICE_GUID \ + { \ + 0x0A861D79, 0x6D25, 0x4170, \ + { \ + 0xB6, 0xC4, 0x48, 0x7A, 0xA3, 0x57, 0xCC, 0x79 \ + } \ + } + +EFI_TOUCH_DEVICE_PATH TouchDxeDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + sizeof(VENDOR_DEVICE_PATH), + 0, + }, + }, + TOUCH_DEVICE_GUID, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof(EFI_DEVICE_PATH_PROTOCOL), + 0, + }, + }, +}; + +#endif diff --git a/sdm845Pkg/sdm845Pkg.dec b/sdm845Pkg/sdm845Pkg.dec index 1c6be1e..b766381 100644 --- a/sdm845Pkg/sdm845Pkg.dec +++ b/sdm845Pkg/sdm845Pkg.dec @@ -43,6 +43,7 @@ [Protocols] gEFIDroidKeypadDeviceProtocolGuid = { 0xb27625b5, 0x0b6c, 0x4614, { 0xaa, 0x3c, 0x33, 0x13, 0xb5, 0x1d, 0x36, 0x46 } } gEfiMemCardInfoProtocolGuid = { 0x85c1f7d2, 0xbce6, 0x4f31, { 0x8f, 0x4d, 0xd3, 0x7e, 0x03, 0xd0, 0x5e, 0xaa } } + gSynapticsTouchDeviceProtocolGuid = { 0xf6ba192f, 0x9ee4, 0x4e3b, { 0xb1, 0x7a, 0xda, 0x75, 0x40, 0x3f, 0xa5, 0xa7 } } gQcomI2cProtocolGuid = { 0xb27ae8b1, 0x3e10, 0x4d07, { 0xab, 0x5c, 0xeb, 0x9a, 0x6d, 0xc6, 0xfa, 0x8f } } gQcomTlmmProtocolGuid = { 0xad9aec18, 0x7bf0, 0x4809, { 0x9e, 0x96, 0x30, 0x12, 0x30, 0x9f, 0x3d, 0xf7 } } gQcomTlmmRTProtocolGuid = { 0xcc3f4da6, 0xa51e, 0x4fb7, { 0x98, 0xd1, 0xa0, 0x6e, 0xb8, 0x5d, 0x8e, 0x1e } } @@ -64,3 +65,14 @@ gsdm845PkgTokenSpaceGuid.PcdDeviceVendor|"Qualcomm"|VOID*|0x0000a301 gsdm845PkgTokenSpaceGuid.PcdDeviceProduct|"Snapdragon 845 Device"|VOID*|0x0000a302 gsdm845PkgTokenSpaceGuid.PcdDeviceCodeName|"sdm845"|VOID*|0x0000a303 + # Touch Screen + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrAddress|0|UINT16|0x0000a501 + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrResetPin|0|UINT32|0x0000a502 + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrIntPin|0|UINT32|0x0000a503 + gsdm845PkgTokenSpaceGuid.PcdTouchCtlrI2cDevice|0|UINT32|0x0000a504 + gsdm845PkgTokenSpaceGuid.PcdTouchMinX|0|UINT32|0x0000a505 + gsdm845PkgTokenSpaceGuid.PcdTouchMaxX|0|UINT32|0x0000a506 + gsdm845PkgTokenSpaceGuid.PcdTouchInvertedX|FALSE|BOOLEAN|0x0000a507 + gsdm845PkgTokenSpaceGuid.PcdTouchMinY|0|UINT32|0x0000a508 + gsdm845PkgTokenSpaceGuid.PcdTouchMaxY|0|UINT32|0x0000a509 + gsdm845PkgTokenSpaceGuid.PcdTouchInvertedY|FALSE|BOOLEAN|0x0000a50a diff --git a/sdm845Pkg/sdm845Pkg.dsc b/sdm845Pkg/sdm845Pkg.dsc index f947a8a..1962e5d 100644 --- a/sdm845Pkg/sdm845Pkg.dsc +++ b/sdm845Pkg/sdm845Pkg.dsc @@ -344,5 +344,8 @@ sdm845Pkg/Binary/845/LinuxSimpleMassStorage/LinuxSimpleMassStorage.inf + sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDevice.inf + sdm845Pkg/Drivers/SynapticsTouchDxe/SynapticsTouchDxe.inf + [BuildOptions.common] GCC:*_*_AARCH64_CC_FLAGS = -Wno-unused-variable