/** @file
 *
 *  RK3588 SoC Processor Properties Topology Table
 *
 *  This table is based on the ACPI 6.2 spec because Windows
 *  (tested with build 22621.1992) is not able to properly parse
 *  newer revisions:
 *    - ACPI 6.3 (rev 2) leads to doubled L3 cache size.
 *    - ACPI 6.4 (rev 3) leads to a 0x7E bug check due to the new
 *      Cache ID field in the Cache Type Structure (see Table 5.140).
 *
 *  It also entirely ignores cache sizes described here, relying on
 *  CCSIDR instead. The info there is mostly correct, except for L3.
 *
 *  Linux parses and displays all this data correctly.
 *
 *  Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
 *
 *  SPDX-License-Identifier: BSD-2-Clause-Patent
 *
 **/

#include "AcpiTables.h"

#pragma pack(1)
typedef struct {
  EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR  Package;
  UINT32                                 L3CacheRef;
} RK3588_PPTT_PACKAGE_NODE;

typedef struct {
  EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR  Cluster;
} RK3588_PPTT_CLUSTER_NODE;

typedef struct {
  EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR  Core;
  UINT32                                 L1DCacheRef;
  UINT32                                 L1ICacheRef;
  UINT32                                 L2CacheRef;
} RK3588_PPTT_CORE_NODE;

typedef struct {
  EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER  Header;
  RK3588_PPTT_PACKAGE_NODE                                 Package;
  RK3588_PPTT_CLUSTER_NODE                                 Clusters[3];
  RK3588_PPTT_CORE_NODE                                    Cores[8];
  EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE                        PackageL3Cache;
  EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE                        A55L1DCache;
  EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE                        A55L1ICache;
  EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE                        A55L2Cache;
  EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE                        A76L1DCache;
  EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE                        A76L1ICache;
  EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE                        A76L2Cache;
} RK3588_PPTT;
#pragma pack()

///
/// For PPTT struct processor flags
///
#define EFI_ACPI_6_2_PPTT_PACKAGE_NOT_PHYSICAL          0x0
#define EFI_ACPI_6_2_PPTT_PACKAGE_PHYSICAL              0x1
#define EFI_ACPI_6_2_PPTT_PROCESSOR_ID_INVALID          0x0
#define EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID            0x1

///
/// For PPTT struct cache flags
///
#define EFI_ACPI_6_2_PPTT_CACHE_SIZE_INVALID            0x0
#define EFI_ACPI_6_2_PPTT_CACHE_SIZE_VALID              0x1
#define EFI_ACPI_6_2_PPTT_NUMBER_OF_SETS_INVALID        0x0
#define EFI_ACPI_6_2_PPTT_NUMBER_OF_SETS_VALID          0x1
#define EFI_ACPI_6_2_PPTT_ASSOCIATIVITY_INVALID         0x0
#define EFI_ACPI_6_2_PPTT_ASSOCIATIVITY_VALID           0x1
#define EFI_ACPI_6_2_PPTT_ALLOCATION_TYPE_INVALID       0x0
#define EFI_ACPI_6_2_PPTT_ALLOCATION_TYPE_VALID         0x1
#define EFI_ACPI_6_2_PPTT_CACHE_TYPE_INVALID            0x0
#define EFI_ACPI_6_2_PPTT_CACHE_TYPE_VALID              0x1
#define EFI_ACPI_6_2_PPTT_WRITE_POLICY_INVALID          0x0
#define EFI_ACPI_6_2_PPTT_WRITE_POLICY_VALID            0x1
#define EFI_ACPI_6_2_PPTT_LINE_SIZE_INVALID             0x0
#define EFI_ACPI_6_2_PPTT_LINE_SIZE_VALID               0x1

#define PPTT_DATA_CACHE_ATTRIBUTES                                                \
  {                                                                               \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE,                          \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_DATA,                                \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK                         \
  }

#define PPTT_INST_CACHE_ATTRIBUTES                                                \
  {                                                                               \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ,                                \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_INSTRUCTION,                         \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK                         \
  }

#define PPTT_UNIFIED_CACHE_ATTRIBUTES                                             \
  {                                                                               \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE,                          \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_UNIFIED,                             \
    EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK                         \
  }

#define RK3588_PPTT_CLUSTER_NODE_INIT(ClusterUid) {                               \
  {                                               /* Cluster */                   \
    EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR,             /* Type */                      \
    sizeof (RK3588_PPTT_CLUSTER_NODE),            /* Length */                    \
    {                                             /* Reserved[2] */               \
      EFI_ACPI_RESERVED_BYTE,                                                     \
      EFI_ACPI_RESERVED_BYTE                                                      \
    },                                                                            \
    {                                             /* Flags */                     \
      EFI_ACPI_6_2_PPTT_PACKAGE_NOT_PHYSICAL,                                     \
      EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID                                        \
    },                                                                            \
    OFFSET_OF (RK3588_PPTT, Package),             /* Parent */                    \
    ClusterUid,                                   /* AcpiProcessorId */           \
    0                                             /* NumberOfPrivateResources */  \
  }                                                                               \
}

#define RK3588_PPTT_CORE_NODE_INIT(ClusterIndex, CoreUid,                         \
  L1DCacheField, L1ICacheField, L2CacheField) {                                   \
  {                                               /* Core */                      \
    EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR,             /* Type */                      \
    sizeof (RK3588_PPTT_CORE_NODE),               /* Length */                    \
    {                                             /* Reserved[2] */               \
      EFI_ACPI_RESERVED_BYTE,                                                     \
      EFI_ACPI_RESERVED_BYTE                                                      \
    },                                                                            \
    {                                             /* Flags */                     \
      EFI_ACPI_6_2_PPTT_PACKAGE_NOT_PHYSICAL,                                     \
      EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID                                        \
    },                                                                            \
    OFFSET_OF (RK3588_PPTT,                                                       \
               Clusters[ClusterIndex]),           /* Parent */                    \
    CoreUid,                                      /* AcpiProcessorId */           \
    3                                             /* NumberOfPrivateResources */  \
  },                                                                              \
  OFFSET_OF (RK3588_PPTT, L1DCacheField),         /* L1DCacheRef */               \
  OFFSET_OF (RK3588_PPTT, L1ICacheField),         /* L1ICacheRef */               \
  OFFSET_OF (RK3588_PPTT, L2CacheField)           /* L2CacheRef */                \
}

#define RK3588_PPTT_A55_CORE_NODE_INIT(ClusterIndex, CoreUid)                     \
  RK3588_PPTT_CORE_NODE_INIT (                                                    \
    ClusterIndex, CoreUid,                                                        \
    A55L1DCache, A55L1ICache, A55L2Cache                                          \
  )

#define RK3588_PPTT_A76_CORE_NODE_INIT(ClusterIndex, CoreUid)                     \
  RK3588_PPTT_CORE_NODE_INIT (                                                    \
    ClusterIndex, CoreUid,                                                        \
    A76L1DCache, A76L1ICache, A76L2Cache                                          \
  )

#define RK3588_PPTT_CACHE_NODE_INIT(NextLevelOfCache, Size,                       \
  NumberOfSets, Attributes) {                                                     \
  EFI_ACPI_6_2_PPTT_TYPE_CACHE,                   /* Type */                      \
  sizeof (EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE),     /* Length */                    \
  {                                               /* Reserved[2] */               \
    EFI_ACPI_RESERVED_BYTE,                                                       \
    EFI_ACPI_RESERVED_BYTE                                                        \
  },                                                                              \
  {                                               /* Flags */                     \
    EFI_ACPI_6_2_PPTT_CACHE_SIZE_VALID,                                           \
    EFI_ACPI_6_2_PPTT_NUMBER_OF_SETS_VALID,                                       \
    EFI_ACPI_6_2_PPTT_ASSOCIATIVITY_VALID,                                        \
    EFI_ACPI_6_2_PPTT_ALLOCATION_TYPE_VALID,                                      \
    EFI_ACPI_6_2_PPTT_CACHE_TYPE_VALID,                                           \
    EFI_ACPI_6_2_PPTT_WRITE_POLICY_VALID,                                         \
    EFI_ACPI_6_2_PPTT_LINE_SIZE_VALID                                             \
  },                                                                              \
  NextLevelOfCache,                               /* NextLevelOfCache */          \
  Size,                                           /* Size */                      \
  NumberOfSets,                                   /* NumberOfSets */              \
  Size / NumberOfSets / 64,                       /* Associativity */             \
  Attributes,                                     /* Attributes */                \
  64                                              /* LineSize */                  \
}

STATIC RK3588_PPTT Pptt = {
  {
    ACPI_HEADER (
      EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE,
      RK3588_PPTT,
      EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION
    ),
  },
  {
    {                                             /* Package */
      EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR,           /* Type */
      sizeof (RK3588_PPTT_PACKAGE_NODE),          /* Length */
      {                                           /* Reserved[2] */
        EFI_ACPI_RESERVED_BYTE,
        EFI_ACPI_RESERVED_BYTE
      },
      {                                           /* Flags */
        EFI_ACPI_6_2_PPTT_PACKAGE_PHYSICAL,
        EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID
      },
      0,                                          /* Parent */
      8,                                          /* AcpiProcessorId */
      1                                           /* NumberOfPrivateResources */
    },
    OFFSET_OF (RK3588_PPTT, PackageL3Cache)
  },
  {                                               /* Clusters */
    RK3588_PPTT_CLUSTER_NODE_INIT (9),            /* Little cluster */
    RK3588_PPTT_CLUSTER_NODE_INIT (10),           /* Big cluster 0 */
    RK3588_PPTT_CLUSTER_NODE_INIT (11)            /* Big cluster 1 */
  },
  {                                               /* Cores */
    RK3588_PPTT_A55_CORE_NODE_INIT (0, 0),        /* 4x Cortex-A55 (Little cluster) */
    RK3588_PPTT_A55_CORE_NODE_INIT (0, 1),
    RK3588_PPTT_A55_CORE_NODE_INIT (0, 2),
    RK3588_PPTT_A55_CORE_NODE_INIT (0, 3),
    RK3588_PPTT_A76_CORE_NODE_INIT (1, 4),        /* 2x Cortex-A76 (Big cluster 0) */
    RK3588_PPTT_A76_CORE_NODE_INIT (1, 5),
    RK3588_PPTT_A76_CORE_NODE_INIT (2, 6),        /* 2x Cortex-A76 (Big cluster 1) */
    RK3588_PPTT_A76_CORE_NODE_INIT (2, 7)
  },
  RK3588_PPTT_CACHE_NODE_INIT (                   /* PackageL3Cache */
    0,                                            /* NextLevelOfCache */
    SIZE_1MB * 3,                                 /* Size */
    4096,                                         /* NumberOfSets */
    PPTT_UNIFIED_CACHE_ATTRIBUTES                 /* Attributes */
  ),
  RK3588_PPTT_CACHE_NODE_INIT (                   /* A55L1DCache */
    OFFSET_OF (RK3588_PPTT, A55L2Cache),          /* NextLevelOfCache */
    SIZE_32KB,                                    /* Size */
    128,                                          /* NumberOfSets */
    PPTT_DATA_CACHE_ATTRIBUTES                    /* Attributes */
  ),
  RK3588_PPTT_CACHE_NODE_INIT (                   /* A55L1ICache */
    OFFSET_OF (RK3588_PPTT, A55L2Cache),          /* NextLevelOfCache */
    SIZE_32KB,                                    /* Size */
    128,                                          /* NumberOfSets */
    PPTT_INST_CACHE_ATTRIBUTES                    /* Attributes */
  ),
  RK3588_PPTT_CACHE_NODE_INIT (                   /* A55L2Cache */
    0,                                            /* NextLevelOfCache */
    SIZE_128KB,                                   /* Size */
    512,                                          /* NumberOfSets */
    PPTT_UNIFIED_CACHE_ATTRIBUTES                 /* Attributes */
  ),
  RK3588_PPTT_CACHE_NODE_INIT (                   /* A76L1DCache */
    OFFSET_OF (RK3588_PPTT, A76L2Cache),          /* NextLevelOfCache */
    SIZE_64KB,                                    /* Size */
    256,                                          /* NumberOfSets */
    PPTT_DATA_CACHE_ATTRIBUTES                    /* Attributes */
  ),
  RK3588_PPTT_CACHE_NODE_INIT (                   /* A76L1ICache */
    OFFSET_OF (RK3588_PPTT, A76L2Cache),          /* NextLevelOfCache */
    SIZE_64KB,                                    /* Size */
    256,                                          /* NumberOfSets */
    PPTT_INST_CACHE_ATTRIBUTES                    /* Attributes */
  ),
  RK3588_PPTT_CACHE_NODE_INIT (                   /* A76L2Cache */
    0,                                            /* NextLevelOfCache */
    SIZE_512KB,                                   /* Size */
    1024,                                         /* NumberOfSets */
    PPTT_UNIFIED_CACHE_ATTRIBUTES                 /* Attributes */
  )
};

VOID* CONST ReferenceAcpiTable = &Pptt;
