/** @file

  Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <IndustryStandard/IoRemappingTable.h>
#include <Platform/MemoryMap.h>

#include "AcpiTables.h"

#define FIELD_OFFSET(type, name)            __builtin_offsetof(type, name)

#pragma pack(1)
typedef struct {
  EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE        Node;
  UINT32                                    Identifiers[1];
} SYNQUACER_ITS_NODE;

typedef struct {
  EFI_ACPI_6_0_IO_REMAPPING_RC_NODE         Node;
  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE        RcIdMapping;
} SYNQUACER_RC_NODE;

typedef struct {
  EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE       Node;
  EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT        Context[8];
} SYNQUACER_SMMU_NODE;

typedef struct {
  EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE Node;
  CONST CHAR8                               Name[11];
  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE        RcIdMapping;
} SYNQUACER_NC_NODE;

typedef struct {
  EFI_ACPI_6_0_IO_REMAPPING_TABLE           Iort;
  SYNQUACER_ITS_NODE                        ItsNode;
  SYNQUACER_RC_NODE                         RcNode[2];
  SYNQUACER_SMMU_NODE                       SmmuNode;
  SYNQUACER_NC_NODE                         NamedCompNode[2];
} SYNQUACER_IO_REMAPPING_STRUCTURE;

#define __SYNQUACER_ID_MAPPING(In, Num, Out, Ref, Flags)    \
  {                                                         \
    In,                                                     \
    Num,                                                    \
    Out,                                                    \
    FIELD_OFFSET(SYNQUACER_IO_REMAPPING_STRUCTURE, Ref),    \
    Flags                                                   \
  }

STATIC SYNQUACER_IO_REMAPPING_STRUCTURE Iort = {
  {
    __ACPI_HEADER(EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE,
                  SYNQUACER_IO_REMAPPING_STRUCTURE,
                  EFI_ACPI_IO_REMAPPING_TABLE_REVISION),
    6,                                              // NumNodes
    sizeof(EFI_ACPI_6_0_IO_REMAPPING_TABLE),        // NodeOffset
    0                                               // Reserved
  }, {
    // ItsNode
    {
      {
        EFI_ACPI_IORT_TYPE_ITS_GROUP,                       // Type
        sizeof(SYNQUACER_ITS_NODE),                         // Length
        0x0,                                                // Revision
        0x0,                                                // Reserved
        0x0,                                                // NumIdMappings
        0x0,                                                // IdReference
      },
      1,
    }, {
      0x0
    },
  }, {
    {
      // PciRcNode
      {
        {
          EFI_ACPI_IORT_TYPE_ROOT_COMPLEX,                    // Type
          sizeof(SYNQUACER_RC_NODE),                          // Length
          0x0,                                                // Revision
          0x0,                                                // Reserved
          0x1,                                                // NumIdMappings
          FIELD_OFFSET(SYNQUACER_RC_NODE, RcIdMapping),       // IdReference
        },
        EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA,                    // CacheCoherent
        0x0,                                                  // AllocationHints
        0x0,                                                  // Reserved
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_CPM |
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_DACS,                  // MemoryAccessFlags
        EFI_ACPI_IORT_ROOT_COMPLEX_ATS_UNSUPPORTED,           // AtsAttribute
        0x0,                                                  // PciSegmentNumber
      },
      //
      // The SynQuacer pre-ITS cannot be modeled in ACPI, and all accesses to the
      // GICv3 ITS doorbell register are reported as originating from device ID #0
      // So map all requester IDs to device ID #0
      //
      __SYNQUACER_ID_MAPPING(0x0, 0x0, 0x0, ItsNode,
                             EFI_ACPI_IORT_ID_MAPPING_FLAGS_SINGLE),
    }, {
      // PciRcNode
      {
        {
          EFI_ACPI_IORT_TYPE_ROOT_COMPLEX,                    // Type
          sizeof(SYNQUACER_RC_NODE),                          // Length
          0x0,                                                // Revision
          0x0,                                                // Reserved
          0x1,                                                // NumIdMappings
          FIELD_OFFSET(SYNQUACER_RC_NODE, RcIdMapping),       // IdReference
        },
        EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA,                    // CacheCoherent
        0x0,                                                  // AllocationHints
        0x0,                                                  // Reserved
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_CPM |
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_DACS,                  // MemoryAccessFlags
        EFI_ACPI_IORT_ROOT_COMPLEX_ATS_UNSUPPORTED,           // AtsAttribute
        0x1,                                                  // PciSegmentNumber
      },
      //
      // The SynQuacer pre-ITS cannot be modeled in ACPI, and all accesses to the
      // GICv3 ITS doorbell register are reported as originating from device ID #0
      // So map all requester IDs to device ID #0
      //
      __SYNQUACER_ID_MAPPING(0x0, 0x0, 0x0, ItsNode,
                             EFI_ACPI_IORT_ID_MAPPING_FLAGS_SINGLE),
    }
  }, {
    // NETSEC/eMMC SMMU node
    {
      {
        EFI_ACPI_IORT_TYPE_SMMUv1v2,
        sizeof(SYNQUACER_SMMU_NODE),
        0x0,
        0x0,
        0x0,
        0x0,
      },
      SYNQUACER_SCB_SMMU_BASE,
      SYNQUACER_SCB_SMMU_SIZE,
      EFI_ACPI_IORT_SMMUv1v2_MODEL_MMU500,
      EFI_ACPI_IORT_SMMUv1v2_FLAG_COH_WALK,
      FIELD_OFFSET(EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE,
                   SMMU_NSgIrpt),
      0x8,
      sizeof(EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE),
      0x0,
      0x0,
      228,
      EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL,
      0x0,
      0x0,
    }, {
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
      { 228, EFI_ACPI_IORT_SMMUv1v2_INT_FLAG_LEVEL, },
    },
  }, {
    {
      // NETSEC named component node
      {
        {
          EFI_ACPI_IORT_TYPE_NAMED_COMP,
          sizeof(SYNQUACER_NC_NODE),
          0x0,
          0x0,
          0x1,
          FIELD_OFFSET(SYNQUACER_NC_NODE, RcIdMapping),
        },
        0x0,
        EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA,
        0x0,
        0x0,
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_CPM |
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_DACS,
        40,
      }, {
        "\\_SB_.NET0"
      }, {
        0x0,
        0x0,
        0x0,
        FIELD_OFFSET(SYNQUACER_IO_REMAPPING_STRUCTURE, SmmuNode),
        EFI_ACPI_IORT_ID_MAPPING_FLAGS_SINGLE
      }
    }, {
      // eMMC named component node
      {
        {
          EFI_ACPI_IORT_TYPE_NAMED_COMP,
          sizeof(SYNQUACER_NC_NODE),
          0x0,
          0x0,
          0x1,
          FIELD_OFFSET(SYNQUACER_NC_NODE, RcIdMapping),
        },
        0x0,
        EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA,
        0x0,
        0x0,
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_CPM |
        EFI_ACPI_IORT_MEM_ACCESS_FLAGS_DACS,
        40,
      }, {
        "\\_SB_.MMC0"
      }, {
        0x0,
        0x0,
        0x0,
        FIELD_OFFSET(SYNQUACER_IO_REMAPPING_STRUCTURE, SmmuNode),
        EFI_ACPI_IORT_ID_MAPPING_FLAGS_SINGLE
      }
    }
  }
};

#pragma pack()

VOID* CONST ReferenceAcpiTable = &Iort;
