/**
 * @file
 *
 * Routines for IOMMU.
 *
 * Implement the IOMMU init and ACPI feature.
 *
 * @xrefitem bom "File Content Label" "Release Content"
 * @e project:      CIMx-NB
 * @e sub-project:
 * @e \$Revision:$   @e \$Date:$
 *
 */
/*****************************************************************************
 *
 * Copyright (C) 2012 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 ***************************************************************************/

// Identifying an IOMMU:
// RD890S - IOMMU present
// all other (including RD890) - IOMMU not present
// Class = System Base Peripheral (08h)
// Subclass = IOMMU (06h)
// Programming Interface Code = 0h
// Must reside on top/root complex PCI hierarchy
// There is always a NB device at bus 0 device 0 function 0 (fcn 2 for IOMMU) - device ID 0x5A23

// Inputs:
// From OEM: Get exclusion table
// From OEM: Get text buffer

// Outputs:
// To OEM: Complete IVRS table for linking

#ifndef _NBIOMMU_H_
#define _NBIOMMU_H_

/*----------------------------------------------------------------------------------------
 *                          E X P O R T E D    F U N C T I O N S
 *----------------------------------------------------------------------------------------
 */

AGESA_STATUS
NbIommuInit (
  IN OUT   AMD_NB_CONFIG_BLOCK   *ConfigPtr
  );

AGESA_STATUS
NbIommuInitS3 (
  IN OUT   AMD_NB_CONFIG_BLOCK   *ConfigPtr
  );

AGESA_STATUS
NbIommuAcpiInit (
  IN OUT   AMD_NB_CONFIG_BLOCK   *ConfigPtr
  );

AGESA_STATUS
NbIommuAcpiFixup (
  IN OUT   AMD_NB_CONFIG_BLOCK   *ConfigPtr
  );

VOID
NbIommuDisconnectPcieCore (
  IN      CORE            CoreId,
  IN      AMD_NB_CONFIG   *pConfig
  );

/*----------------------------------------------------------------------------------------
 *                   D E F I N I T I O N S    A N D    M A C R O S
 *----------------------------------------------------------------------------------------
 */

// IOMMU Architectural
#define IVRS_BUFFER_SIZE        0x2000      // Default 8KB allocated to table
//#define IVHD_MIN_8BYTE_ALIGNMENT          // Align IVHD entries on 8 byte boundary
#define IVHD_SIZE_ALIGNMENT                 // Align IVHD entries on MOD entry-size boundary
#define IVHD_HPET_SUPPORT                   // Create HPET entries
#define IVHD_APIC_SUPPORT                   // Create IOAPIC entries

// IOMMU Northbridge
#define RD890S_CAP_MISC         0x50        // RD890/S Capabilities Misc Info
#define NB_PCI_DEV              0           // PCI NB device number
#define NB_HOST                 0           // Function 0 = NB HOST
#define NB_IOMMU                2           // Function 2 = IOMMU
#define SB_DEV                  0x14        // PCI SB device number
#define SB_SMBUS                3           // Function 3 = SMBUS
#define SB_SATA                 0x11        // SB SATA
#define SATA_ENABLE_REG         0xAD        // Dev. 0x14, Func 0, Reg 0xAD for SATA combined mode
#define SATA_COMBINED_MODE      BIT3        // Bit 3 of SB_ENABLE_REG., 1 = Combined mode

#define IOMMU_CAP_HEADER_OFFSET 0x00
#define IOMMU_BASE_LOW_OFFSET   0x04
#define IOMMU_BASE_HIGH_OFFSET  0x08
#define IOMMU_RANGE_OFFSET      0x0C
#define IOMMU_MISC_OFFSET       0x10

#define DEVICEID_NB       ((0 << 8) + (NB_PCI_DEV << 3) + NB_HOST)
#define DEVICEID_IOMMU    ((0 << 8) + (NB_PCI_DEV << 3) + NB_IOMMU)
#define DEVICEID_GPP1_0   ((0 << 8) + (0x2 << 3) + 0)
#define DEVICEID_GPP1_1   ((0 << 8) + (0x3 << 3) + 0)
#define DEVICEID_GPP2_0   ((0 << 8) + (0xB << 3) + 0)
#define DEVICEID_GPP2_1   ((0 << 8) + (0xC << 3) + 0)
#define DEVICEID_GPP3A_0  ((0 << 8) + (0x4 << 3) + 0)
#define DEVICEID_GPP3A_1  ((0 << 8) + (0x5 << 3) + 0)
#define DEVICEID_GPP3A_2  ((0 << 8) + (0x6 << 3) + 0)
#define DEVICEID_GPP3A_3  ((0 << 8) + (0x7 << 3) + 0)
#define DEVICEID_GPP3A_4  ((0 << 8) + (0x9 << 3) + 0)
#define DEVICEID_GPP3A_5  ((0 << 8) + (0xA << 3) + 0)
#define DEVICEID_GPP3B_0  ((0 << 8) + (0xD << 3) + 0)

#define DEVICEID_SATA     ((0 << 8) + (0x11 << 3) + 0)
#define DEVICEID_IDE      ((0 << 8) + (0x14 << 3) + 1)

#define L1CFG_INDEX             0xF8
// There is an L1 for each device (6), which is selected by [19:16] of L1CFG_INDEX
// e.g. (LibNbPciIndexRead (Address | L1CFGIND, L1_REG_0C | L1_CFG_SEL, AccessWidth32, &Value, pConfig)
#define L1CFG_SEL_WR_EN         0x80000000
#define L1CFG_SEL_GPP1          0x00000000
#define L1CFG_SEL_GPP2          0x00010000
#define L1CFG_SEL_SB            0x00020000
#define L1CFG_SEL_GPP3A         0x00030000
#define L1CFG_SEL_GPP3B         0x00040000
#define L1CFG_SEL_VC1           0x00050000
#define L1REG_06                0x6
#define L1REG_0C                0xC
#define L1REG_0D                0xD
#define L1REG_07                0x7
#define L1CFG_DATA              0xFC

#define L2CFG_INDEX             0xF0
// e.g. (LibNbPciIndexRead (Address | L2CFGIND, L2_REG_0C, AccessWidth16, &Value, pConfig)
#define L2CFG_SEL_WR_EN         0x100
#define L2REG_06                0x6
#define L2REG_07                0x7
#define L2REG_0C                0xC
#define L2REG_10                0x10
#define L2REG_11                0x11
#define L2REG_14                0x14
#define L2REG_15                0x15
#define L2REG_18                0x18
#define L2REG_19                0x19
#define L2REG_1C                0x1C
#define L2REG_1D                0x1D
#define L2REG_46                0x46
#define L2REG_47                0x47
#define L2REG_50                0x50
#define L2REG_51                0x51
#define L2REG_52                0x52
#define L2REG_56                0x56
#define L2REG_30                0x30
#define L2REG_80                0x80
#define L2CFG_DATA              0xF4

// PCI/PCIe Architectural
#define PCIE_CAPID              0x10
#define PCIE_PORTMASK           0xF0              // Device cap reg 2
#define PCIE_PCIE2PCIX          0x70              // Device cap reg 2
#define PCIE_PHANTOMMASK        0x18              // Device cap reg 4
#define PCIX_CAPID              0x07
#define IOMMU_CAPID             0x0F

#define PCI_DVID                0x00
#define PCI_INVALID             0xFFFFFFFF
#define PCI_CLASS               0x08
#define PCI_HEADER              0x0C
#define PCI_MULTIFUNCTION       0x00800000
#define PCI_BUS                 0x18
#define PCI_SUBMASK             0xFF0000
#define PCI_SECMASK             0xFF00
#define PCI_PRIMASK             0xFF
#define PCI_BRIDGE_CLASS        0x0604

// IVRS Table Access
#define TYPE_IVHD               0x10
#define IVINFO_ATSMASK          0x00400000          // [22] = ATS
#define IVINFO_VAMASK           0x003F8000          // [21:15] = Virtual Address Size
#define IVINFO_PAMASK           0x00007F00          // [14:8] = Physical Address Size
#define FLAGS_COHERENT          BIT5
#define FLAGS_IOTLBSUP          BIT4
#define FLAGS_ISOC              BIT3
#define FLAGS_RESPASSPW         BIT2
#define FLAGS_PASSPW            BIT1

#define TYPE_IVMD_ALL           0x20
#define TYPE_IVMD_SELECT        0x21
#define TYPE_IVMD_RANGE         0x22

#define DE_PAD4                 1
#define DE_BYTE0                0
#define DE_BYTE1                1
#define DE_BYTE2                2
#define DE_BYTE3                3
#define DE_SELECT               2
#define DATA_NOINTS             0
#define DATA_LINT_EINT_INIT     BIT7 + BIT6 + BIT1 + BIT0
#define DATA_ALLINTS            0xD7
#define DE_START                3
#define DE_END                  4
#define DE_PAD8                 64
#define DE_BYTE4                4
#define DE_BYTE5                5
#define DE_BYTE6                6
#define DE_BYTE7                7
#define DE_ALIASSELECT          66
#define DE_ALIASSTART           67
#define DE_SPECIAL              72
#define VARIETY_IOAPIC          0x1
#define VARIETY_HPET            0x2
#define DE_SPECIAL_VARIETY      7
#define DE_DEVICEID             5
#define DE_SPECIAL_ID           4

// MADT Table Access
#define MADT_APIC_TYPE          0x1
#define MADT_APIC_ID            0x2
#define MADT_APIC_BASE          0x4

/*----------------------------------------------------------------------------------------
 *                  T Y P E D E F S     A N D     S T R U C T U  R E S
 *----------------------------------------------------------------------------------------
 */



#pragma pack (push, 1)

/// IVRS header
typedef struct {
  UINT32  Signature;                        ///< see IOMMU specification for details
  UINT32  Length;                           ///< see IOMMU specification for details
  UINT8   Revision;                         ///< see IOMMU specification for details
  UINT8   Checksum;                         ///< see IOMMU specification for details
  CHAR8   OemId[6];                         ///< see IOMMU specification for details
  CHAR8   OemTableId[8];                    ///< see IOMMU specification for details
  CHAR8   OemRevision[4];                   ///< see IOMMU specification for details
  CHAR8   CreatorId[4];                     ///< see IOMMU specification for details
  CHAR8   CreatorRevision[4];               ///< see IOMMU specification for details
  UINT32  IvInfo;                           ///< see IOMMU specification for details
  UINT64  Reserved;                         ///< see IOMMU specification for details
} IOMMU_IVRS_HEADER;

/// DeviceID
typedef struct {
  UINT16  TableLength;                      ///< length of table
  UINT16  Device[];                         ///< DeviceID
} IOMMU_DEVICELIST;

/// PCI Topology Based Settings
typedef struct {
//  BOOLEAN PhantomFunction;                    ///< phantom functions present
  UINT8   MaxBus;                           ///< max bus accumulator
  UINT8   MaxDevice;                        ///< max device accumulator
  UINT16  MaxFunction;                      ///< max function accumulator
} IOMMU_PCI_TOPOLOGY;

/// IVHD for each hardware definition (i.e. # of northbridges)
typedef struct {
  UINT8   Type;                             ///< see IOMMU specification for details
  UINT8   Flags;                            ///< see IOMMU specification for details
  UINT16  Length;                           ///< see IOMMU specification for details
  UINT16  DeviceId;                         ///< see IOMMU specification for details
  UINT16  CapabilityOffset;                 ///< see IOMMU specification for details
  UINT64  BaseAddress;                      ///< see IOMMU specification for details
  UINT16  PciSegment;                       ///< see IOMMU specification for details
  UINT16  IommuInfo;                        ///< see IOMMU specification for details
  UINT32  Reserved;                         ///< see IOMMU specification for details
  UINT32  DeviceEntry[];                    ///< see IOMMU specification for details
} IOMMU_IVHD_ENTRY;

/// IVMD for each memory range
typedef struct {
  UINT8   Type;                             ///< see IOMMU specification for details
  UINT8   Flags;                            ///< see IOMMU specification for details
  UINT16  Length;                           ///< see IOMMU specification for details
  UINT16  DeviceId;                         ///< see IOMMU specification for details
  UINT16  AuxData;                          ///< see IOMMU specification for details
  UINT64  Reserved;                         ///< see IOMMU specification for details
  UINT64  BlockStartAddress;                ///< see IOMMU specification for details
  UINT64  BlockLength;                      ///< see IOMMU specification for details
} IOMMU_IVMD_ENTRY;

//#define IVRS_HANDLE 'SRVI'
#define IVRS_HANDLE Int32FromChar ('S', 'R', 'V', 'I')

#define L2_DTC_CONTROL    0x10
#define L2_ITC_CONTROL    0x14
#define L2_PTC_A_CONTROL  0x18
#define L2_PTC_B_CONTROL  0x1C
#define L2_PDC_CONTROL    0x50

#define EXCLUDE_SB_DEVICE_FROM_L2_HASH

/// L2 cache init
typedef struct {
  UINT8 HashControl;                        ///<Control regsiter block address
} L2_HASH_CONTROL;

#pragma pack (pop)

#endif