/******************************************************************************** Copyright (C) 2016 Marvell International Ltd. SPDX-License-Identifier: BSD-2-Clause-Patent *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MvEepromDxe.h" 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; }