/** @file
  OpromUpdateDxeNeonCityFPGA - UEFI DXE driver header.

  Unified Board Architecture (UBA) driver for the NeonCityFPGA platform.
  Provides Option ROM (OpROM) update configuration by registering PCIe slot
  data with the UBA board protocol. The driver identifies the ROM layout,
  locates the HOB list from the system configuration table, resolves the
  UBA board-type protocol, and registers slot configuration function callbacks.

  Copyright (c) Lenovo. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef OPCROM_UPDATE_DXE_NEON_CITY_FPGA_H_
#define OPCROM_UPDATE_DXE_NEON_CITY_FPGA_H_

#include "../uefi_headers/Uefi.h"

///
/// EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL GUID
/// {BB7E702F-1A4A-11D4-9A38-0090273FC14D}
///
#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
  { 0x2F707EBB, 0x4A1A, 0x11D4, { 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }

///
/// DebugLib Protocol GUID (EDK2 DebugLib protocol)
/// {36232936-0E76-31C8-A13A-3AF2FC1C3932}
///
#define DEBUG_LIB_PROTOCOL_GUID \
  { 0x36232936, 0x0E76, 0x31C8, { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }

///
/// UBA NeonCityFPGA Board-Type Protocol GUID
/// {E03E0D46-5263-4845-B0A4-58D57B3177E2}
///
#define UBA_NEONCITY_FPGA_BOARD_TYPE_PROTOCOL_GUID \
  { 0xE03E0D46, 0x5263, 0x4845, { 0xB0, 0xA4, 0x58, 0xD5, 0x7B, 0x31, 0x77, 0xE2 } }

///
/// EFI_HOB_LIST_GUID
/// {7739F24C-93D7-11D4-9A3A-0090273FC14D}
///
#define EFI_HOB_LIST_GUID \
  { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }

///
/// OpROM update configuration GUID for NeonCityFPGA
/// {371BD79C-DE79-4C5F-AA2B-BC9EBEFA988F}
///
#define OPCROM_UPDATE_CONFIG_GUID \
  { 0x9CD71B37, 0x79DE, 0x4C5F, { 0xAA, 0x2B, 0xBC, 0x9E, 0xBE, 0xFA, 0x98, 0x8F } }

///
/// CMOS RTC I/O ports
///
#define RTC_INDEX_PORT       0x70
#define RTC_DATA_PORT        0x71
#define RTC_INDEX_DEBUG_LEVEL  0x4B

///
/// Debug level / error severity mask
/// Used with DebugPrint to control output verbosity
///
#define DEBUG_ERROR_MASK  0x80000000

///
/// Maximum number of PCIe slots (PCI bus/device/function combinations)
/// tested by the slot checker callback
///
#define PCIE_SLOT_CHECK_BIT_COUNT  8

///
/// Number of entries in the first slot configuration table (at 0xD40)
///
#define PCIE_SLOT_TABLE_1_COUNT  6

///
/// Number of entries in the second slot configuration table (at 0xE40)
///
#define PCIE_SLOT_TABLE_2_COUNT  10

///
/// Size of each slot table entry: 40 bytes (0x28)
///
#define PCIE_SLOT_TABLE_ENTRY_SIZE  40

///
/// UBA OpROM Update Configuration Table signature ("PBDS")
///
#define UBA_OPROM_UPDATE_CONFIG_SIGNATURE  0x53444250  ///< "PBDS" in little-endian

///
/// Size of the UBA OpROM Update configuration table passed to RegisterOpromUpdate
/// 4 (Signature) + 4 (Version) + 5 * 8 (Function pointers) = 48
///
#define UBA_OPROM_UPDATE_CONFIG_SIZE  48

///
/// UBA OpROM Update Configuration Table structure
/// This structure is packed into .rdata at offset 0xEB8.
/// It contains function callback pointers registered with the UBA protocol.
///
#pragma pack(push, 1)
typedef struct {
  ///
  /// Signature "PBDS" (0x53444250)
  ///
  UINT32    Signature;
  ///
  /// Version (1)
  ///
  UINT32    Version;
  ///
  /// Function pointer 0: PcieSlotChecker
  /// Checks whether a given PCIe bus/dev/func corresponds to a configured slot.
  /// Signature: BOOLEAN (EFIAPI *)(UINT64 PcieAddress, UINT32 SlotBitmap)
  ///
  UINT64    PcieSlotChecker;
  ///
  /// Function pointer 1: GetPcieSlotProtocol
  /// Returns a pointer to a slot configuration protocol/structure.
  /// Signature: UINT64 (EFIAPI *)(VOID **Protocol)
  ///
  UINT64    GetPcieSlotProtocol;
  ///
  /// Function pointer 2: GetPcieSlotTable1
  /// Returns the first PCIe slot configuration table (6 entries at 0xD40).
  /// Signature: UINT64 (EFIAPI *)(VOID **Table, UINTN *Count)
  ///
  UINT64    GetPcieSlotTable1;
  ///
  /// Function pointer 3: GetPcieSlotTable2
  /// Returns the second PCIe slot configuration table (10 entries at 0xE40).
  /// Signature: UINT64 (EFIAPI *)(VOID **Table, UINTN *Count)
  ///
  UINT64    GetPcieSlotTable2;
  ///
  /// Function pointer 4: SetPcieSlotNumberCallback
  /// Sets the PCIe slot number for a given slot.
  /// Signature: UINT64 (EFIAPI *)(UINT8 *SlotNumber)
  ///
  UINT64    SetPcieSlotNumberCallback;
} UBA_OPROM_UPDATE_CONFIG;
#pragma pack(pop)

///
/// UBA NeonCityFPGA Board Protocol Interface Structure
/// Located dynamically via gBS->LocateProtocol().
///
#pragma pack(push, 1)
typedef struct {
  ///
  /// Offset 0x00: Unknown field (revision/flags)
  ///
  UINT64    Revision;
  ///
  /// Offset 0x08: Unknown field (reserved)
  ///
  UINT64    Reserved;
  ///
  /// Offset 0x10: RegisterOpromUpdate function
  /// Registers OpROM update configuration callbacks with the UBA board protocol.
  ///
  /// EFI_STATUS (EFIAPI *RegisterOpromUpdate)(
  ///   IN  UBA_NEONCITY_BOARD_PROTOCOL  *This,
  ///   IN  EFI_GUID                     *ConfigGuid,      ///< GUID identifying the config
  ///   IN  UBA_OPROM_UPDATE_CONFIG      *ConfigData,       ///< Function callback table
  ///   IN  UINTN                        ConfigDataSize     ///< Size of config data (48)
  ///   );
  ///
  UINT64    RegisterOpromUpdate;
} UBA_NEONCITY_BOARD_PROTOCOL;
#pragma pack(pop)

///
/// Debug Library Protocol Interface Structure
///
#pragma pack(push, 1)
typedef struct {
  ///
  /// Offset 0x00: DebugPrint function
  ///
  UINT64    DebugPrint;
  ///
  /// Offset 0x08: DebugAssert function
  ///
  UINT64    DebugAssert;
} DEBUG_LIB_PROTOCOL;
#pragma pack(pop)

///
/// PCIe slot bit configuration entry (4 bytes each, 8 entries at 0xEF1)
/// Used by PcieSlotChecker to determine which PCIe addresses correspond
/// to physical slots on the NeonCityFPGA platform.
///
#pragma pack(push, 1)
typedef struct {
  UINT8    Bus;          ///< PCI bus number
  UINT8    Device;       ///< PCI device number
  UINT8    Function;     ///< PCI function number
  UINT8    SlotBit;      ///< Slot bit position in the bitmap
} PCIE_SLOT_BIT_CONFIG;
#pragma pack(pop)

///
/// PCIe slot table entry structure (40 bytes each)
/// Defines a single PCIe slot configuration.
///
#pragma pack(push, 1)
typedef struct {
  UINT32    Flags;              ///< +0x00: Slot flags/enable bits
  UINT32    VendorDeviceId;     ///< +0x04: Vendor/device ID encoding (0x00020001 style)
  UINT32    VendorDeviceIdHi;   ///< +0x08: High part of PCI vendor/device ID (e.g., 0x15288086 = Intel 0x8086 0x1528)
  UINT32    BusDeviceFunction;  ///< +0x0C: BDF encoding (e.g., 0x48010802)
  UINT32    SegmentBus;         ///< +0x10: PCI segment group number / bus
  UINT32    SegmentBusHi;       ///< +0x14: High part of segment/bus
  UINT32    Reserved1;          ///< +0x18
  UINT32    Reserved2;          ///< +0x1C
  UINT32    Reserved3;          ///< +0x20
  UINT32    Reserved4;          ///< +0x24
} PCIE_SLOT_TABLE_ENTRY;

///
/// System Configuration Table Entry Format
/// Used to scan SystemTable->ConfigurationTable[] for EFI_HOB_LIST_GUID
///
#pragma pack(push, 1)
typedef struct {
  EFI_GUID    VendorGuid;       ///< +0x00: 16-byte GUID
  VOID        *VendorTable;     ///< +0x10: 8-byte pointer
} CONFIG_TABLE_ENTRY;           ///< Total: 0x18 (24 bytes)
#pragma pack(pop)

///
/// Global variables
///
extern EFI_HANDLE              gImageHandle;      ///< @ 0xF20: Driver image handle
extern EFI_SYSTEM_TABLE        *gST;              ///< @ 0xF10: System table pointer
extern EFI_BOOT_SERVICES       *gBS;              ///< @ 0xF18: Boot services pointer
extern EFI_RUNTIME_SERVICES    *gRT;              ///< @ 0xF28: Runtime services pointer
extern VOID                    *gDebugProtocol;   ///< @ 0xF30: Cached DebugLib protocol
extern VOID                    *gHobList;         ///< @ 0xF38: Cached HOB list pointer

#endif // OPCROM_UPDATE_DXE_NEON_CITY_FPGA_H_