/** @file
  Base IPC library implementation.

 @copyright
  INTEL CONFIDENTIAL
  Copyright 2014 - 2017 Intel Corporation.

  The source code contained or described herein and all documents related to the
  source code ("Material") are owned by Intel Corporation or its suppliers or
  licensors. Title to the Material remains with Intel Corporation or its suppliers
  and licensors. The Material may contain trade secrets and proprietary and
  confidential information of Intel Corporation and its suppliers and licensors,
  and is protected by worldwide copyright and trade secret laws and treaty
  provisions. No part of the Material may be used, copied, reproduced, modified,
  published, uploaded, posted, transmitted, distributed, or disclosed in any way
  without Intel's prior express written permission.

  No license under any patent, copyright, trade secret or other intellectual
  property right is granted to or conferred upon you by disclosure or delivery
  of the Materials, either expressly, by implication, inducement, estoppel or
  otherwise. Any license under such intellectual property rights must be
  express and approved by Intel in writing.

  Unless otherwise agreed by Intel in writing, you may not remove or alter
  this notice or any other notice embedded in Materials by Intel or
  Intel's suppliers or licensors in any way.

  This file contains an 'Intel Peripheral Driver' and is uniquely identified as
  "Intel Reference Module" and is licensed for Intel CPUs and chipsets under
  the terms of your license agreement with Intel or your vendor. This file may
  be modified by the user, subject to additional terms of the license agreement.

@par Specification Reference:
**/

#ifndef _PMC_IPC_LIB_
#define _PMC_IPC_LIB_

//
// IPC Register Offsets to PMC BAR0 (IPC1: 0x0000 ~ 0xFFF; GCR: 0x1000 ~ 0x1FFF)
//
#define R_IPC_CMD_OFFSET           0x00
#define R_IPC_STS_OFFSET           0x04
#define R_IPC_SPTR_OFFSET          0x08
#define R_IPC_DPTR_OFFSET          0x0C
#define R_IPC_WBUF_OFFSET          0x80
#define R_IPC_RBUF_OFFSET          0x90
#define S_IPC_RWBUF_SIZE           16

//
// IPC_CMD type
//
typedef enum {
  IPC_CMD_NONE,
  IPC_CMD_READ,
  IPC_CMD_WRITE,
  IPC_CMD_MAX
} IPC_CMD_TYPE;


//
// IPC_CMD register
//
typedef union {
  struct {
    UINT32  CommandId   :8;
    UINT32  Msi         :1;
    UINT32  Reserved1   :3;
    UINT32  SubCmdId    :4;
    UINT32  Size        :8;
    UINT32  Reserved2   :8;
  } Bits;
  UINT32  Uint32;
} IPC_COMMAND;

//
// IPC_STS register
//
typedef union {
  struct {
    UINT32  Busy        :1;
    UINT32  Error       :1;
    UINT32  Reserved1   :2;
    UINT32  CmdId       :4;
    UINT32  IndicatorId :8;
    UINT32  ErrCode     :8;
    UINT32  Reserved2   :8;
  } Bits;
  UINT32  Uint32;
} IPC_STATUS;

///
/// IPC command opcodes
///
/// @note: These commands need to double-confirm since FAS has conflicting definitions
///

#define IPC_CMD_ID_TRUSTED_SIDEBAND_TUNNEL          0xE4  ///< Trusted Sideband Tunnel
#define IPC_SUBCMD_ID_TRUSTED_SIDEBAND_TUNNEL_READ  0x00  ///<   Read
#define IPC_SUBCMD_ID_TRUSTED_SIDEBAND_TUNNEL_WRITE 0x01  ///<   Write
#define IPC_SCC_SDMMC0_RX_CMD_DATA_DLY_2            0x1
#define IPC_SCC_SDMMC0_AUTO_TUNING                  0x2
#define IPC_SCC_SDCARD_NORMALINTRSTSENA             0x3
#define IPC_SCC_SDMMC2_TX_DAT_DLY_1                 0x4
#define IPC_USB_LPM                                 0x5
#define IPC_GPIO_NORTH_FAM_CFG_I2C_3P3_A            0x6
#define IPC_GPIO_NORTH_FAM_CFG_I2C_3P3_B            0x7
#define IPC_GPIO_NORTH_FAM_RCOMP_B_DW1_I2C_3P3_A    0x8
#define IPC_GPIO_NORTH_FAM_RCOMP_B_DW1_I2C_3P3_B    0x9
#define IPC_GPIO_NORTH_FAM_CFG_PCIE_3P3             0xA
#define IPC_GPIO_NORTH_FAM_CFG_DISP_3P3_A           0xB
#define IPC_GPIO_NORTH_FAM_CFG_DISP_3P3_B           0xC
#define IPC_GPIO_NORTH_FAM_CFG_GPHS3_3P3_A          0xD
#define IPC_GPIO_NORTH_FAM_CFG_GPHS3_3P3_B          0xE
#define IPC_GPIO_NORTH_FAM_CFG_SDCARD_3P3           0xF
#define IPC_GPIO_SCC_MISCSECCFG                     0x10


 

#define IPC_CMD_ID_CAPSULE_UPDATE_RESET             0xE5  ///< PMC Capsule Update Reset
#define IPC_SUBCMD_ID_CAPSULE_UPDATE_RESET          0x00  ///<   Reserved, ignore by PMC

#define IPC_CMD_ID_PMC_VER                          0xE7  ///< PMC FW version
#define IPC_SUBCMD_ID_PMC_VER_READ                  0x00  ///<   Read PMC FW version

#define IPC_CMD_ID_EMI_RFI_SUPPORT                  0xE8  ///< PMC EMI/RFI Support, Note that this command is not valid on BXT-A
#define IPC_SUBCMD_ID_SSC_APPLY_NOW                 0x01  ///<   Apply the SSC setting immidiately
#define IPC_SUBCMD_ID_SSC_DO_NOT_APPLY_NOW          0x00  ///<   Apply the SSC setting on next cold reset or s0ix exit

#define IPC_CMD_ID_CCP_FREF_SEL  					0xE8  ///< IPC_CMD.CMD_ID 0xE8 – EMI/RFI SUPPORT
#define IPC_SUBCMD_ID_CCP_FREF_SEL 					0x04  ///< Read CCP_FREF_SEL fuse (0x0 = 1.6 GHz, 0x1 = 2.0 GHz) 
	
#define IPC_CMD_ID_TELEMETRY                        0xEB  ///< Cmds used to read and write PMC telemetry registers
#define IPC_SUBID_TELEMETRY_EVENT_READ              0x00  ///<    Reads a TELEM_EVENT register
#define IPC_SUBID_TELEMETRY_EVENT_WRITE             0x01  ///<    Writes a TELEM_EVENT register

#define IPC_SUBID_TELEMETRY_INFO_READ               0x02  ///<  Reads the TELEM_INFO register

#define IPC_SUBID_TELEMETRY_TRACE_READ              0x03  ///<  Read MBB_TELEM_TRACE_MASK register
#define IPC_SUBID_TELEMETRY_TRACE_WRITE             0x04  ///<  Writes the MBB_TELEM_TRACE_MASK register

#define IPC_SUBID_TELEMETRY_TRACE_CTL_READ          0x05  ///<  Reads the MBB_TELEM_CONTROL register
#define IPC_SUBID_TELEMETRY_TRACE_CTL_WRITE         0x06  ///<  Writes the MBB_TELEM_CONTROL register

#define IPC_SUBID_TELEMETRY_EVENT_CTL_READ          0x07  ///<  Reads the TELEM_EVENT_CTL register
#define IPC_SUBID_TELEMETRY_EVENT_CTL_WRITE         0x08  ///<  Writes the TELEM_EVENT_CTL register

#define IPC_CMD_ID_SOUTH_IP_UNGATE                  0xE9  ///< Control South IP powergating for Visa Programming
#define IPC_SUBCMD_ID_SOUTH_IP_ALLOW_GATING         0x0   ///<   South IP allow gating
#define IPC_SUBCMD_ID_SOUTH_IP_UN_GATING            0x1   ///<   South IP Ungate

#define IPC_CMD_ID_FW_MSG_CTRL                      0xEA  ///< Read and write the PMC FW_MSG_CTL register
#define IPC_SUBCMD_ID_FW_MSG_CTRL_READ              0x0   ///<   Read PMC FW_MSG_CTL register (1 byte returned from PMC)
#define IPC_SUBCMD_ID_FW_MSG_CTRL_WRITE             0x1   ///<  Write PMC FW_MSG_CTL register (1 byte written to PMC)

#define IPC_CMD_ID_PM_DEBUG                         0xEC  ///< Cmds supported for PM debug
#define IPC_SUBCMD_ID_LPSS_DEBUG_UART_ENABLE        0X0B  ///<   LPSS Debug UART Enable
#define IPC_SUBCMD_ID_LPSS_DEBUG_UART_DISABLE       0X0C  ///<   LPSS Debug UART Disable
#define IPC_SUBCMD_ID_PM_DEBUG_LTR_IGNORE_REPORT    0x0D  ///<   LTR Report (IP to report is specified via IPC_WBUF)
#define IPC_SUBCMD_ID_PM_DEBUG_LTR_IGNORE_READ      0x0E  ///<   LTR ignore read
#define IPC_SUBCMD_ID_PM_DEBUG_LTR_IGNORE_WRITE     0x0F  ///<   LTR ignore write

#define IPC_CMD_ID_NPK                              0xED  ///< North Peak Enable, Disable during S0
#define IPC_SUBCMD_ID_NPK_DISABLE                   0x00  ///<   NPK Disable
#define IPC_SUBCMD_ID_NPK_ENABLE                    0x01  ///<   NPK Enable

#define IPC_CMD_ID_PHY_CFG                          0xEE  ///< Used by BIOS to communicate mphy configuration information, which MPHY is specified in IPC_WBUF
#define IPC_SUBCMD_ID_PHY_CFG_COMPLETE              0x00  ///<   PHY configuration is complete
#define IPC_SUBCMD_ID_PHY_WILL_NOT_CFG              0x01  ///<   PHY will not be configured

#define IPC_CMD_ID_USB3P3                           0xF0  ///< Cause PMC to turn on, off USB 3.3V rail
#define IPC_SUBCMD_ID_USB3P3_OFF                    0x00  ///<   Turn off USB 3.3V rail
#define IPC_SUBCMD_ID_USB3P3_ON                     0x01  ///<   Turn on USB 3.3V rail

#define IPC_CMD_ID_BLACKLIST_SEL                    0xEF  ///< PMIC Blacklist Select IPC1
#define IPC_SUBCMD_BLACKLIST_IAIns                  0x00  ///<   Use IA Insecure Blacklist to filter PMIC Accesses
#define IPC_SUBCMD_BLACKLIST_IASec                  0x02  ///<   Use IA Secure Blacklist to filter PMIC Accesses

#define IPC_CMD_ID_PMIC                             0xFF  ///< PMIC Register read and write
#define IPC_SUBCMD_ID_PMIC_READ                     0x00  ///<   PMIC Register write
#define IPC_SUBCMD_ID_PMIC_WRITE                    0x01  ///<   PMIC Register read
#define IPC_SUBCMD_ID_PMIC_READ_MOD_WRITE           0x02  ///<   PMIC Register read-modify-write

#define INVALID_IPC_CMD                             0x80000000

typedef enum
{
  ipcStsCode_none = 0,             ///< 0, No error
  ipcStsCode_cmdNotSupported,      ///< 1, IPC_CMD.CMD_ID is correct, but there is a problem in formatting of the other IPC_CMD fields.  Example: wrong IPC_CMD.SIZE.
  ipcStsCode_cmdNotServiced,       ///< 2, IPC_CMD is correct, but service you asked for is permanently disabled (fused off, blacklisted, etc).
  ipcStsCode_unableToServiceNow,   ///< 3, IPC_CMD is correct, but PMC cannot service at this time. Example: command which can only be called once, or can only happen at a particular time.
  ipcStsCode_cmdInvalid,           ///< 4, IPC_CMD.CMD_ID is invalid
  ipcStsCode_cmdFailed,            ///< 5, Attempted to service the command, but it failed for some reason!  Example: pmic access failed/timed out.
}ipcStsCode_t;

#pragma pack(1)
typedef struct {
  UINT16  Address;
  UINT8   Value;
} IPC_CMD_ID_PMIC_READ_WRITE_FORMAT;

typedef struct {
  UINT16  Address;
  UINT8   Value;
  UINT8   Mask;
} IPC_CMD_ID_PMIC_READ_MODIFY_WRITE_FORMAT;

typedef union {
  IPC_CMD_ID_PMIC_READ_WRITE_FORMAT         ReadWrite[5];
  IPC_CMD_ID_PMIC_READ_MODIFY_WRITE_FORMAT  ReadModifyWrite[4];
  UINT32                                    Uint32[4];
} IPC_CMD_ID_PMIC_BUFFER;
#pragma pack()

/**
  Checks the IPC channel is available for a new request

  @retval  EFI_SUCCESS    Ready for a new IPC
  @retval  EFI_NOT_READY  Not ready for a new IPC
**/
RETURN_STATUS
EFIAPI
ReadyForNewIpc (
  VOID
  );

/**
  Sends an IPC from the x86 CPU to the PMC and waits for the PMC to process the
  specified opcode.

  @param[in]  MessageId   The message identifier to send in the IPC packet.
**/
RETURN_STATUS
EFIAPI
IpcSendCommand (
  IN UINT32  MessageId
  );

/**
  Sends an IPC from the x86 CPU to the PMC and waits for the PMC to process the
  specified opcode.

  @param[in] Command                    The Command identifier to send in the IPC packet.
  @param[in] SubCommand                 The SubCommand identifier to send in the IPC packet.
  @param[in, out] Buffer                Pointer to buffer associated with MessageId.  This is an optional
                                        patrametert that may be NULL for some MessageId values.
  @param[in, out] BufferSize            The size, in bytes, of Buffer.  Ignored if Buffer is NULL.
**/
RETURN_STATUS
EFIAPI
IpcSendCommandEx (
  IN      UINT32  Command,
  IN      UINT8   SubCommand,
  IN OUT  VOID    *Buffer,    OPTIONAL
  IN OUT  UINTN   BufferSize
  );


/**
  Sends an IPC from the x86 CPU to the PMC and waits for the PMC to process the
  specified opcode.

  !! Use it only when you are sure that IPC PCI config space is no longer valid !!

  @param[in] PciBar0                    PCI config BAR0 for IPC.
  @param[in] Command                    The Command identifier to send in the IPC packet.
  @param[in] SubCommand                 The SubCommand identifier to send in the IPC packet.
  @param[in, out] Buffer                Pointer to buffer associated with MessageId.  This is an optional
                                        patrametert that may be NULL for some MessageId values.
  @param[in, out] BufferSize            The size, in bytes, of Buffer.  Ignored if Buffer is NULL.
**/
RETURN_STATUS
EFIAPI
IpcSendCommandBar0Ex (
  IN      UINT32  PciBar0,
  IN      UINT32  Command,
  IN      UINT8   SubCommand,
  IN OUT  VOID    *Buffer,    OPTIONAL
  IN OUT  UINTN   BufferSize
  );

#endif    // __BXT_PMC_IPC_LIB__
