/** @file Copyright (c) 2018, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include STATIC MEZZANINE_PROTOCOL *mMezzanine; typedef struct { EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate; EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cConfigManagement; EFI_HANDLE I2cMasterHandle; UINT32 BusFrequency; UINTN NumDevices; CONST EFI_I2C_DEVICE *Devices; } I2C_BUS; STATIC EFI_STATUS EFIAPI I2cEnumerate ( IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This, IN OUT CONST EFI_I2C_DEVICE **Device ) { I2C_BUS *Bus; if (Device == NULL) { return EFI_INVALID_PARAMETER; } Bus = BASE_CR (This, I2C_BUS, I2cEnumerate); if (Bus->NumDevices == 0 || (Bus->NumDevices > 0 && *Device == &Bus->Devices[Bus->NumDevices - 1])) { *Device = NULL; } else if (*Device == NULL) { *Device = &Bus->Devices[0]; } else if (Bus->NumDevices > 1 && *Device >= &Bus->Devices[0] && *Device < &Bus->Devices[Bus->NumDevices - 1]) { ++*Device; } else { return EFI_NO_MAPPING; } return EFI_SUCCESS; } STATIC EFI_STATUS EFIAPI I2cGetBusFrequency ( IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This, IN UINTN I2cBusConfiguration, OUT UINTN *BusClockHertz ) { I2C_BUS *Bus; if (BusClockHertz == NULL) { return EFI_INVALID_PARAMETER; } if (I2cBusConfiguration > 0) { return EFI_NO_MAPPING; } Bus = BASE_CR (This, I2C_BUS, I2cEnumerate); *BusClockHertz = Bus->BusFrequency; return EFI_SUCCESS; } STATIC EFI_STATUS EFIAPI EnableI2cBusConfiguration ( IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This, IN UINTN I2cBusConfiguration, IN EFI_EVENT Event OPTIONAL, IN EFI_STATUS *I2cStatus OPTIONAL ) { EFI_I2C_MASTER_PROTOCOL *I2cMaster; EFI_STATUS Status; UINTN BusClockHertz; I2C_BUS *Bus; if (I2cBusConfiguration > 0) { return EFI_NO_MAPPING; } Bus = BASE_CR (This, I2C_BUS, I2cConfigManagement); Status = gBS->HandleProtocol (Bus->I2cMasterHandle, &gEfiI2cMasterProtocolGuid, (VOID **)&I2cMaster); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: gBS->HandleProtocol() failed - %r\n", __FUNCTION__, Status)); return Status; } BusClockHertz = Bus->BusFrequency; Status = I2cMaster->SetBusFrequency (I2cMaster, &BusClockHertz); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: I2cMaster->SetBusFrequency() failed - %r\n", __FUNCTION__, Status)); return Status; } if (Event != NULL) { *I2cStatus = EFI_SUCCESS; gBS->SignalEvent (Event); } return EFI_SUCCESS; } STATIC I2C_BUS mI2cBus0 = { { I2cEnumerate, I2cGetBusFrequency }, { EnableI2cBusConfiguration }, NULL, FixedPcdGet32 (PcdI2c0BusFrequencyHz), 0, NULL, }; STATIC I2C_BUS mI2cBus1 = { { I2cEnumerate, I2cGetBusFrequency }, { EnableI2cBusConfiguration }, NULL, FixedPcdGet32 (PcdI2c1BusFrequencyHz), 0, NULL, }; STATIC VOID RegisterI2cBus ( IN EFI_GUID *Guid, IN I2C_BUS *I2cBus, IN UINTN NumDevices, IN CONST EFI_I2C_DEVICE *Devices ) { EFI_STATUS Status; UINTN BufferSize; BufferSize = sizeof (EFI_HANDLE); Status = gBS->LocateHandle (ByProtocol, Guid, NULL, &BufferSize, &I2cBus->I2cMasterHandle); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "%a: gBS->LocateHandle() failed - %r\n", __FUNCTION__, Status)); return; } I2cBus->NumDevices = NumDevices; I2cBus->Devices = Devices; Status = gBS->InstallMultipleProtocolInterfaces (&I2cBus->I2cMasterHandle, &gEfiI2cEnumerateProtocolGuid, &I2cBus->I2cEnumerate, &gEfiI2cBusConfigurationManagementProtocolGuid, &I2cBus->I2cConfigManagement, NULL); ASSERT_EFI_ERROR (Status); } STATIC VOID EFIAPI OnEndOfDxe ( IN EFI_EVENT Event, IN VOID *Context ) { gBS->CloseEvent (Event); gBS->ConnectController (mI2cBus0.I2cMasterHandle, NULL, NULL, TRUE); gBS->ConnectController (mI2cBus1.I2cMasterHandle, NULL, NULL, TRUE); } EFI_STATUS EFIAPI EntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_EVENT EndOfDxeEvent; Status = gBS->LocateProtocol (&g96BoardsMezzanineProtocolGuid, NULL, (VOID **)&mMezzanine); ASSERT_EFI_ERROR (Status); RegisterI2cBus (&g96BoardsI2c0MasterGuid, &mI2cBus0, mMezzanine->I2c0NumDevices, mMezzanine->I2c0DeviceArray); RegisterI2cBus (&g96BoardsI2c1MasterGuid, &mI2cBus1, mMezzanine->I2c1NumDevices, mMezzanine->I2c1DeviceArray); Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, OnEndOfDxe, NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }