/** * * Copyright (c) 2018, Marvell International Ltd. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include "MvGpioDxe.h" STATIC MV_GPIO *mGpioInstance; STATIC MV_GPIO_DEVICE_PATH mDevicePathTemplate = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8) (sizeof (VENDOR_DEVICE_PATH) + sizeof (MV_GPIO_DRIVER_TYPE)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH) + sizeof (MV_GPIO_DRIVER_TYPE)) >> 8), }, }, EFI_CALLER_ID_GUID }, MV_GPIO_DRIVER_TYPE_SOC_CONTROLLER, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 } } }; #if !defined(MDEPKG_NDEBUG) /** Routine Description: Verifies if controller index / GPIO pin values are within proper boundaries. Arguments: ControllerIndex - index of controller GpioPin - which pin to read Returns: EFI_SUCCESS - GPIO pin / controller index are proper EFI_INVALID_PARAMETER - GPIO pin / controller index is out of range **/ STATIC EFI_STATUS MvGpioValidate ( IN UINTN ControllerIndex, IN UINTN GpioPin ) { if (ControllerIndex >= mGpioInstance->GpioDeviceCount) { DEBUG ((DEBUG_ERROR, "%a: Invalid GPIO ControllerIndex: %d\n", __FUNCTION__, ControllerIndex)); return EFI_INVALID_PARAMETER; } if (GpioPin >= mGpioInstance->SoCGpio[ControllerIndex].InternalGpioCount) { DEBUG ((DEBUG_ERROR, "%a: GPIO pin #%d not available in Controller#%d\n", __FUNCTION__, GpioPin, ControllerIndex)); return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; } #endif /** Routine Description: Gets the mode (function) of a GPIO pin Arguments: This - pointer to protocol Gpio - which pin Mode - pointer to output mode value Returns: EFI_SUCCESS - mode value retrieved EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range **/ STATIC EFI_STATUS MvGpioGetMode ( IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, OUT EMBEDDED_GPIO_MODE *Mode ) { UINTN ControllerIndex; UINTN BaseAddress; UINTN GpioPin; GpioPin = GPIO_PIN (Gpio); ControllerIndex = GPIO_PORT (Gpio); ASSERT_EFI_ERROR (MvGpioValidate (ControllerIndex, GpioPin)); BaseAddress = mGpioInstance->SoCGpio[ControllerIndex].RegisterBase; if (MmioRead32 (BaseAddress + MV_GPIO_OUT_EN_REG) & (1 << GpioPin)) { *Mode = GPIO_MODE_INPUT; } else { if (MmioRead32 (BaseAddress + MV_GPIO_DATA_IN_REG) & (1 << GpioPin)) { *Mode = GPIO_MODE_OUTPUT_1; } else { *Mode = GPIO_MODE_OUTPUT_0; } } return EFI_SUCCESS; } /** Routine Description: Gets the state of a GPIO pin Arguments: This - pointer to protocol Gpio - which pin to read Value - state of the pin Returns: EFI_SUCCESS - GPIO state returned in Value EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range **/ STATIC EFI_STATUS MvGpioGet ( IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, OUT UINTN *Value ) { UINTN ControllerIndex; UINTN BaseAddress; UINTN GpioPin; GpioPin = GPIO_PIN (Gpio); ControllerIndex = GPIO_PORT (Gpio); ASSERT_EFI_ERROR (MvGpioValidate (ControllerIndex, GpioPin)); BaseAddress = mGpioInstance->SoCGpio[ControllerIndex].RegisterBase; if (MmioRead32 (BaseAddress + MV_GPIO_DATA_IN_REG) & (1 << GpioPin)) { *Value = 1; } else { *Value = 0; } return EFI_SUCCESS; } /** Routine Description: Sets the state of a GPIO pin Arguments: This - pointer to protocol Gpio - which pin to modify Mode - mode to set Returns: EFI_SUCCESS - GPIO set as requested EFI_UNSUPPORTED - Mode is not supported EFI_INVALID_PARAMETER - Gpio pin is out of range **/ STATIC EFI_STATUS MvGpioSet ( IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, IN EMBEDDED_GPIO_MODE Mode ) { UINTN ControllerIndex; UINTN BaseAddress; UINTN GpioPin; GpioPin = GPIO_PIN (Gpio); ControllerIndex = GPIO_PORT (Gpio); ASSERT_EFI_ERROR (MvGpioValidate (ControllerIndex, GpioPin)); BaseAddress = mGpioInstance->SoCGpio[ControllerIndex].RegisterBase; switch (Mode) { case GPIO_MODE_OUTPUT_0: MmioAnd32 (BaseAddress + MV_GPIO_DATA_OUT_REG, ~(1 << GpioPin)); MmioAnd32 (BaseAddress + MV_GPIO_OUT_EN_REG, ~(1 << GpioPin)); break; case GPIO_MODE_OUTPUT_1: MmioOr32 (BaseAddress + MV_GPIO_DATA_OUT_REG, (1 << GpioPin)); MmioAnd32 (BaseAddress + MV_GPIO_OUT_EN_REG, ~(1 << GpioPin)); break; case GPIO_MODE_INPUT: MmioOr32 (BaseAddress + MV_GPIO_OUT_EN_REG, (1 << GpioPin)); break; default: return EFI_UNSUPPORTED; } return EFI_SUCCESS; } /** Routine Description: Sets the pull-up / pull-down resistor of a GPIO pin Arguments: This - pointer to protocol Gpio - which pin Direction - pull-up, pull-down, or none Returns: EFI_UNSUPPORTED - Can not perform the requested operation **/ EFI_STATUS EFIAPI MvGpioSetPull ( IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, IN EMBEDDED_GPIO_PULL Direction ) { return EFI_UNSUPPORTED; } STATIC VOID MvGpioInitProtocol ( IN EMBEDDED_GPIO *GpioProtocol ) { GpioProtocol->Get = MvGpioGet; GpioProtocol->Set = MvGpioSet; GpioProtocol->GetMode = MvGpioGetMode; GpioProtocol->SetPull = MvGpioSetPull; } EFI_STATUS EFIAPI MvGpioEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { MARVELL_BOARD_DESC_PROTOCOL *MvBoardProtocol; MV_BOARD_GPIO_DESCRIPTION *GpioDescription; MV_GPIO_DEVICE_PATH *GpioDevicePath; EFI_STATUS Status; GpioDevicePath = AllocateCopyPool (sizeof (MV_GPIO_DEVICE_PATH), &mDevicePathTemplate); if (GpioDevicePath == NULL) { return EFI_OUT_OF_RESOURCES; } mGpioInstance = AllocateZeroPool (sizeof (MV_GPIO)); if (mGpioInstance == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ErrGpioInstanceAlloc; } /* Obtain list of available controllers */ Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid, NULL, (VOID **)&MvBoardProtocol); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Cannot locate BoardDesc protocol\n", __FUNCTION__)); goto ErrLocateBoardDesc; } Status = MvBoardProtocol->GpioDescriptionGet (MvBoardProtocol, &GpioDescription); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Cannot get GPIO board desc from BoardDesc protocol\n", __FUNCTION__)); goto ErrLocateBoardDesc; } mGpioInstance->Signature = MV_GPIO_SIGNATURE; mGpioInstance->GpioDeviceCount = GpioDescription->GpioDeviceCount; mGpioInstance->SoCGpio = GpioDescription->SoCGpio; MvGpioInitProtocol (&mGpioInstance->GpioProtocol); Status = gBS->InstallMultipleProtocolInterfaces (&(mGpioInstance->Handle), &gEmbeddedGpioProtocolGuid, &(mGpioInstance->GpioProtocol), &gEfiDevicePathProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL *)GpioDevicePath, NULL); if (EFI_ERROR (Status)) { goto ErrLocateBoardDesc; } return EFI_SUCCESS; ErrLocateBoardDesc: gBS->FreePool (mGpioInstance); ErrGpioInstanceAlloc: gBS->FreePool (GpioDevicePath); return Status; }