/** @file * * GPIO manipulation. * * Copyright (c) 2020, Pete Batard * Copyright (c) 2018, Andrei Warkentin * Copyright (c) 2021, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include #include #include #include #include #include #include #include STATIC VOID GpioFSELModify ( IN UINTN RegIndex, IN UINT32 ModifyMask, IN UINT32 FunctionMask ) { UINT32 Val; EFI_PHYSICAL_ADDRESS Reg; Reg = RegIndex * sizeof (UINT32) + GPIO_GPFSEL0; ASSERT (Reg <= GPIO_GPFSEL5); ASSERT ((~ModifyMask & FunctionMask) == 0); Val = MmioRead32 (Reg); Val &= ~ModifyMask; Val |= FunctionMask; MmioWrite32 (Reg, Val); } VOID GpioPinFuncSet ( IN UINTN Pin, IN UINTN Function ) { UINTN RegIndex; UINTN SelIndex; UINT32 ModifyMask; UINT32 FunctionMask; ASSERT (Pin < GPIO_PINS); ASSERT (Function <= GPIO_FSEL_MASK); RegIndex = Pin / 10; SelIndex = Pin % 10; ModifyMask = GPIO_FSEL_MASK << (SelIndex * GPIO_FSEL_BITS_PER_PIN); FunctionMask = Function << (SelIndex * GPIO_FSEL_BITS_PER_PIN); GpioFSELModify (RegIndex, ModifyMask, FunctionMask); } UINTN GpioPinFuncGet ( IN UINTN Pin ) { UINT32 Val; UINTN RegIndex; UINTN SelIndex; EFI_PHYSICAL_ADDRESS Reg; ASSERT (Pin < GPIO_PINS); RegIndex = Pin / 10; SelIndex = Pin % 10; Reg = RegIndex * sizeof (UINT32) + GPIO_GPFSEL0; Val = MmioRead32 (Reg); Val >>= SelIndex * GPIO_FSEL_BITS_PER_PIN; Val &= GPIO_FSEL_MASK; return Val; } VOID GpioPinConfigure ( IN UINTN Pin, IN BOOLEAN Config ) { EFI_PHYSICAL_ADDRESS Reg; UINTN RegIndex; UINTN SelIndex; ASSERT (Pin < GPIO_PINS); RegIndex = Pin / 32; SelIndex = Pin % 32; // // Different base addresses are used for clear and set // Reg = (Config == CLEAR_GPIO) ? GPIO_GPCLR0 : GPIO_GPSET0; Reg += RegIndex * sizeof (UINT32); MmioWrite32 (Reg, 1 << SelIndex); } UINTN GpioPinGet ( IN UINTN Pin ) { EFI_PHYSICAL_ADDRESS Reg; UINTN RegIndex; UINTN SelIndex; UINT32 Val; ASSERT (Pin < GPIO_PINS); RegIndex = Pin / 32; SelIndex = Pin % 32; Reg = RegIndex * sizeof (UINT32) + GPIO_GPLEV0; Val = MmioRead32 (Reg) >> SelIndex; return Val & 1; } VOID GpioSetPull ( IN UINTN Pin, IN UINTN Pud ) { EFI_PHYSICAL_ADDRESS Reg; UINTN RegIndex; UINTN SelIndex; UINT32 Val; ASSERT (Pin < GPIO_PINS); ASSERT (Pud <= GPIO_PULL_UP); // // Check if we should use the legacy or newer method of // enabling pullup/pulldown by querying GPPUPPDN3, which // is unused on Bcm2835/2836/2837 and returns 'gpio'. // if (MmioRead32 (GPIO_GPPUPPDN3) == 0x6770696f) { RegIndex = Pin / 32; SelIndex = Pin % 32; MmioWrite32 (GPIO_GPPUD, Pud); MicroSecondDelay (5); Reg = RegIndex * sizeof (UINT32) + GPIO_GPPUDCLK0; MmioWrite32 (Reg, 1 << SelIndex); MicroSecondDelay (5); MmioWrite32 (GPIO_GPPUD, 0); MmioWrite32 (Reg, 0); } else { // // The newer method uses inverted values for up/down. // if (Pud != 0) Pud ^= 0x3; RegIndex = Pin / 16; SelIndex = (Pin % 16) * 2; Reg = RegIndex * sizeof (UINT32) + GPIO_GPPUPPDN0; Val = MmioRead32 (Reg); Val &= ~(0x3 << SelIndex); Val |= Pud << SelIndex; MmioWrite32 (Reg, Val); } }