/** @file Platform Hook Library instance for the UpXtreme Board Copyright (c) 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #define LCR_OFFSET (FixedPcdGet32 (PcdSerialRegisterStride) * 0x03) STATIC GPIO_INIT_CONFIG mUartGpioTable[] = { {GPIO_CNL_LP_GPP_C20, {GpioPadModeNative1, GpioHostOwnGpio, GpioDirNone, GpioOutDefault, GpioIntDis, GpioHostDeepReset, GpioTermNone}},//SERIALIO_UART2_RXD {GPIO_CNL_LP_GPP_C21, {GpioPadModeNative1, GpioHostOwnGpio, GpioDirNone, GpioOutDefault, GpioIntDis, GpioHostDeepReset, GpioTermNone}},//SERIALIO_UART2_TXD }; /** Retrieve the I/O or MMIO base address register for the PCI UART device. @retval The base address register of the UART device. **/ STATIC UINTN GetSerialRegisterBase ( VOID ) { UINT64 PciAddress; UINT32 BaseAddressBuffer[2]; UINT16 Cmd16; PciAddress = PCI_SEGMENT_LIB_ADDRESS ( DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_SERIAL_IO_UART2, PCI_FUNCTION_NUMBER_PCH_SERIAL_IO_UART2, 0 ); Cmd16 = PciSegmentRead16 (PciAddress + PCI_VENDOR_ID_OFFSET); if (Cmd16 == 0xFFFF) { // // Device might be hidden, return the fixed serial register base address // return (UINTN) FixedPcdGet32 (PcdSerialRegisterBase); } else { if (PciSegmentRead32 (PciAddress + PCI_COMMAND_OFFSET) & EFI_PCI_COMMAND_MEMORY_SPACE) { BaseAddressBuffer[0] = PciSegmentRead32 (PciAddress + R_SERIAL_IO_CFG_BAR0_LOW) & B_SERIAL_IO_CFG_BAR0_LOW_BAR; BaseAddressBuffer[1] = 0; if ((PciSegmentRead32 (PciAddress + PCI_BASE_ADDRESSREG_OFFSET) & 0x6) == 0x4) { BaseAddressBuffer[1] = PciSegmentRead32 (PciAddress + R_SERIAL_IO_CFG_BAR0_HIGH); } return *((UINTN *) (&BaseAddressBuffer[0])); } else { return 0; } } } /** Performs platform specific initialization required for the CPU to access the hardware associated with a SerialPortLib instance. This function does not initialize the serial port hardware itself. Instead, it initializes hardware devices that are required for the CPU to access the serial port hardware. This function may be called more than once. @retval RETURN_SUCCESS The platform specific initialization succeeded. @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed. **/ RETURN_STATUS EFIAPI PlatformHookSerialPortInitialize ( VOID ) { UINT64 PciAddress; UINTN SerialRegisterBase; UINTN SerialRegisterBase1; PciAddress = PCI_SEGMENT_LIB_ADDRESS ( DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_SERIAL_IO_UART2, PCI_FUNCTION_NUMBER_PCH_SERIAL_IO_UART2, 0 ); SerialRegisterBase = GetSerialRegisterBase (); if (SerialRegisterBase == 0 || SerialRegisterBase == (UINTN) ~0) { return RETURN_DEVICE_ERROR; } SerialRegisterBase1 = SerialRegisterBase + V_SERIAL_IO_CFG_BAR_SIZE; if ( (MmioRead8 (SerialRegisterBase + LCR_OFFSET) & 0x3F) != (FixedPcdGet8 (PcdSerialLineControl) & 0x3F) ) { GpioConfigurePads ((sizeof (mUartGpioTable) / sizeof (GPIO_INIT_CONFIG)), mUartGpioTable); PciSegmentWrite32 (PciAddress + R_SERIAL_IO_CFG_BAR0_LOW, (UINT32) SerialRegisterBase); PciSegmentWrite32 (PciAddress + R_SERIAL_IO_CFG_BAR1_LOW, (UINT32) SerialRegisterBase1); if (sizeof (UINTN) == sizeof (UINT32)) { PciSegmentWrite32 (PciAddress + R_SERIAL_IO_CFG_BAR0_HIGH, 0x0); PciSegmentWrite32 (PciAddress + R_SERIAL_IO_CFG_BAR1_HIGH, 0x0); } else { PciSegmentWrite32 (PciAddress + R_SERIAL_IO_CFG_BAR0_HIGH, (UINT32) RShiftU64 (SerialRegisterBase, 32)); PciSegmentWrite32 (PciAddress + R_SERIAL_IO_CFG_BAR1_HIGH, (UINT32) RShiftU64 (SerialRegisterBase1, 32)); } PciSegmentWrite32 (PciAddress + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE); PciSegmentOr32 (PciAddress + R_SERIAL_IO_CFG_D0I3MAXDEVPG, BIT18 | BIT17 | BIT16); // // Get controller out of reset // MmioOr32 (SerialRegisterBase + R_SERIAL_IO_MEM_PPR_RESETS, B_SERIAL_IO_MEM_PPR_RESETS_FUNC | B_SERIAL_IO_MEM_PPR_RESETS_APB | B_SERIAL_IO_MEM_PPR_RESETS_IDMA); // // Program clock dividers for UARTs // MmioWrite32 (SerialRegisterBase + R_SERIAL_IO_MEM_PPR_CLK, (B_SERIAL_IO_MEM_PPR_CLK_UPDATE | (V_SERIAL_IO_MEM_PPR_CLK_N_DIV << 16) | (V_SERIAL_IO_MEM_PPR_CLK_M_DIV << 1) | B_SERIAL_IO_MEM_PPR_CLK_EN ) ); } return RETURN_SUCCESS; }