text: /** @file
    Header file for AHCI mode of ATA host controller.
  
    Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
    SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  #ifndef __ATA_HC_AHCI_MODE_H__
  #define __ATA_HC_AHCI_MODE_H__
  
  #define EFI_AHCI_BAR_INDEX                     0x05
  
  #define EFI_AHCI_CAPABILITY_OFFSET             0x0000
  #define   EFI_AHCI_CAP_SAM                     BIT18
  #define   EFI_AHCI_CAP_SSS                     BIT27
  #define   EFI_AHCI_CAP_S64A                    BIT31
  #define EFI_AHCI_GHC_OFFSET                    0x0004
  #define   EFI_AHCI_GHC_RESET                   BIT0
  #define   EFI_AHCI_GHC_IE                      BIT1
  #define   EFI_AHCI_GHC_ENABLE                  BIT31
  #define EFI_AHCI_IS_OFFSET                     0x0008
  #define EFI_AHCI_PI_OFFSET                     0x000C
  
  #define EFI_AHCI_MAX_PORTS                     32
  
  #define AHCI_CAPABILITY2_OFFSET                0x0024
  #define   AHCI_CAP2_SDS                        BIT3
  #define   AHCI_CAP2_SADM                       BIT4
  
  typedef struct {
    UINT32  Lower32;
    UINT32  Upper32;
  } DATA_32;
  
  typedef union {
    DATA_32   Uint32;
    UINT64    Uint64;
  } DATA_64;
  
  //
  // Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms.
  // Add a bit of margin for robustness.
  //
  #define  EFI_AHCI_BUS_PHY_DETECT_TIMEOUT       15
  //
  // Refer SATA1.0a spec, the FIS enable time should be less than 500ms.
  //
  #define  EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT    EFI_TIMER_PERIOD_MILLISECONDS(500)
  //
  // Refer SATA1.0a spec, the bus reset time should be less than 1s.
  //
  #define  EFI_AHCI_BUS_RESET_TIMEOUT            EFI_TIMER_PERIOD_SECONDS(1)
  
  #define  EFI_AHCI_ATAPI_DEVICE_SIG             0xEB140000
  #define  EFI_AHCI_ATA_DEVICE_SIG               0x00000000
  #define  EFI_AHCI_PORT_MULTIPLIER_SIG          0x96690000
  #define  EFI_AHCI_ATAPI_SIG_MASK               0xFFFF0000
  
  //
  // Each PRDT entry can point to a memory block up to 4M byte
  //
  #define EFI_AHCI_MAX_DATA_PER_PRDT             0x400000
  
  #define EFI_AHCI_FIS_REGISTER_H2D              0x27      //Register FIS - Host to Device
  #define   EFI_AHCI_FIS_REGISTER_H2D_LENGTH     20
  #define EFI_AHCI_FIS_REGISTER_D2H              0x34      //Register FIS - Device to Host
  #define   EFI_AHCI_FIS_REGISTER_D2H_LENGTH     20
  #define EFI_AHCI_FIS_DMA_ACTIVATE              0x39      //DMA Activate FIS - Device to Host
  #define   EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH     4
  #define EFI_AHCI_FIS_DMA_SETUP                 0x41      //DMA Setup FIS - Bi-directional
  #define   EFI_AHCI_FIS_DMA_SETUP_LENGTH        28
  #define EFI_AHCI_FIS_DATA                      0x46      //Data FIS - Bi-directional
  #define EFI_AHCI_FIS_BIST                      0x58      //BIST Activate FIS - Bi-directional
  #define   EFI_AHCI_FIS_BIST_LENGTH             12
  #define EFI_AHCI_FIS_PIO_SETUP                 0x5F      //PIO Setup FIS - Device to Host
  #define   EFI_AHCI_FIS_PIO_SETUP_LENGTH        20
  #define EFI_AHCI_FIS_SET_DEVICE                0xA1      //Set Device Bits FIS - Device to Host
  #define   EFI_AHCI_FIS_SET_DEVICE_LENGTH       8
  
  #define EFI_AHCI_D2H_FIS_OFFSET                0x40
  #define EFI_AHCI_DMA_FIS_OFFSET                0x00
  #define EFI_AHCI_PIO_FIS_OFFSET                0x20
  #define EFI_AHCI_SDB_FIS_OFFSET                0x58
  #define EFI_AHCI_FIS_TYPE_MASK                 0xFF
  #define EFI_AHCI_U_FIS_OFFSET                  0x60
  
  //
  // Port register
  //
  #define EFI_AHCI_PORT_START                    0x0100
  #define EFI_AHCI_PORT_REG_WIDTH                0x0080
  #define EFI_AHCI_PORT_CLB                      0x0000
  #define EFI_AHCI_PORT_CLBU                     0x0004
  #define EFI_AHCI_PORT_FB                       0x0008
  #define EFI_AHCI_PORT_FBU                      0x000C
  #define EFI_AHCI_PORT_IS                       0x0010
  #define   EFI_AHCI_PORT_IS_DHRS                BIT0
  #define   EFI_AHCI_PORT_IS_PSS                 BIT1
  #define   EFI_AHCI_PORT_IS_SSS                 BIT2
  #define   EFI_AHCI_PORT_IS_SDBS                BIT3
  #define   EFI_AHCI_PORT_IS_UFS                 BIT4
  #define   EFI_AHCI_PORT_IS_DPS                 BIT5
  #define   EFI_AHCI_PORT_IS_PCS                 BIT6
  #define   EFI_AHCI_PORT_IS_DIS                 BIT7
  #define   EFI_AHCI_PORT_IS_PRCS                BIT22
  #define   EFI_AHCI_PORT_IS_IPMS                BIT23
  #define   EFI_AHCI_PORT_IS_OFS                 BIT24
  #define   EFI_AHCI_PORT_IS_INFS                BIT26
  #define   EFI_AHCI_PORT_IS_IFS                 BIT27
  #define   EFI_AHCI_PORT_IS_HBDS                BIT28
  #define   EFI_AHCI_PORT_IS_HBFS                BIT29
  #define   EFI_AHCI_PORT_IS_TFES                BIT30
  #define   EFI_AHCI_PORT_IS_CPDS                BIT31
  #define   EFI_AHCI_PORT_IS_CLEAR               0xFFFFFFFF
  #define   EFI_AHCI_PORT_IS_FIS_CLEAR           0x0000000F
  
  #define EFI_AHCI_PORT_IE                       0x0014
  #define EFI_AHCI_PORT_CMD                      0x0018
  #define   EFI_AHCI_PORT_CMD_ST_MASK            0xFFFFFFFE
  #define   EFI_AHCI_PORT_CMD_ST                 BIT0
  #define   EFI_AHCI_PORT_CMD_SUD                BIT1
  #define   EFI_AHCI_PORT_CMD_POD                BIT2
  #define   EFI_AHCI_PORT_CMD_CLO                BIT3
  #define   EFI_AHCI_PORT_CMD_CR                 BIT15
  #define   EFI_AHCI_PORT_CMD_FRE                BIT4
  #define   EFI_AHCI_PORT_CMD_FR                 BIT14
  #define   EFI_AHCI_PORT_CMD_MASK               ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)
  #define   EFI_AHCI_PORT_CMD_PMA                BIT17
  #define   EFI_AHCI_PORT_CMD_HPCP               BIT18
  #define   EFI_AHCI_PORT_CMD_MPSP               BIT19
  #define   EFI_AHCI_PORT_CMD_CPD                BIT20
  #define   EFI_AHCI_PORT_CMD_ESP                BIT21
  #define   EFI_AHCI_PORT_CMD_ATAPI              BIT24
  #define   EFI_AHCI_PORT_CMD_DLAE               BIT25
  #define   EFI_AHCI_PORT_CMD_ALPE               BIT26
  #define   EFI_AHCI_PORT_CMD_ASP                BIT27
  #define   EFI_AHCI_PORT_CMD_ICC_MASK           (BIT28 | BIT29 | BIT30 | BIT31)
  #define   EFI_AHCI_PORT_CMD_ACTIVE             (1 << 28 )
  #define EFI_AHCI_PORT_TFD                      0x0020
  #define   EFI_AHCI_PORT_TFD_MASK               (BIT7 | BIT3 | BIT0)
  #define   EFI_AHCI_PORT_TFD_BSY                BIT7
  #define   EFI_AHCI_PORT_TFD_DRQ                BIT3
  #define   EFI_AHCI_PORT_TFD_ERR                BIT0
  #define   EFI_AHCI_PORT_TFD_ERR_MASK           0x00FF00
  #define EFI_AHCI_PORT_SIG                      0x0024
  #define EFI_AHCI_PORT_SSTS                     0x0028
  #define   EFI_AHCI_PORT_SSTS_DET_MASK          0x000F
  #define   EFI_AHCI_PORT_SSTS_DET               0x0001
  #define   EFI_AHCI_PORT_SSTS_DET_PCE           0x0003
  #define   EFI_AHCI_PORT_SSTS_SPD_MASK          0x00F0
  #define EFI_AHCI_PORT_SCTL                     0x002C
  #define   EFI_AHCI_PORT_SCTL_DET_MASK          0x000F
  #define   EFI_AHCI_PORT_SCTL_MASK              (~EFI_AHCI_PORT_SCTL_DET_MASK)
  #define   EFI_AHCI_PORT_SCTL_DET_INIT          0x0001
  #define   EFI_AHCI_PORT_SCTL_DET_PHYCOMM       0x0003
  #define   EFI_AHCI_PORT_SCTL_SPD_MASK          0x00F0
  #define   EFI_AHCI_PORT_SCTL_IPM_MASK          0x0F00
  #define   EFI_AHCI_PORT_SCTL_IPM_INIT          0x0300
  #define   EFI_AHCI_PORT_SCTL_IPM_PSD           0x0100
  #define   EFI_AHCI_PORT_SCTL_IPM_SSD           0x0200
  #define EFI_AHCI_PORT_SERR                     0x0030
  #define   EFI_AHCI_PORT_SERR_RDIE              BIT0
  #define   EFI_AHCI_PORT_SERR_RCE               BIT1
  #define   EFI_AHCI_PORT_SERR_TDIE              BIT8
  #define   EFI_AHCI_PORT_SERR_PCDIE             BIT9
  #define   EFI_AHCI_PORT_SERR_PE                BIT10
  #define   EFI_AHCI_PORT_SERR_IE                BIT11
  #define   EFI_AHCI_PORT_SERR_PRC               BIT16
  #define   EFI_AHCI_PORT_SERR_PIE               BIT17
  #define   EFI_AHCI_PORT_SERR_CW                BIT18
  #define   EFI_AHCI_PORT_SERR_BDE               BIT19
  #define   EFI_AHCI_PORT_SERR_DE                BIT20
  #define   EFI_AHCI_PORT_SERR_CRCE              BIT21
  #define   EFI_AHCI_PORT_SERR_HE                BIT22
  #define   EFI_AHCI_PORT_SERR_LSE               BIT23
  #define   EFI_AHCI_PORT_SERR_TSTE              BIT24
  #define   EFI_AHCI_PORT_SERR_UFT               BIT25
  #define   EFI_AHCI_PORT_SERR_EX                BIT26
  #define   EFI_AHCI_PORT_ERR_CLEAR              0xFFFFFFFF
  #define EFI_AHCI_PORT_SACT                     0x0034
  #define EFI_AHCI_PORT_CI                       0x0038
  #define EFI_AHCI_PORT_SNTF                     0x003C
  #define AHCI_PORT_DEVSLP                       0x0044
  #define   AHCI_PORT_DEVSLP_ADSE                BIT0
  #define   AHCI_PORT_DEVSLP_DSP                 BIT1
  #define   AHCI_PORT_DEVSLP_DETO_MASK           0x000003FC
  #define   AHCI_PORT_DEVSLP_MDAT_MASK           0x00007C00
  #define   AHCI_PORT_DEVSLP_DITO_MASK           0x01FF8000
  #define   AHCI_PORT_DEVSLP_DM_MASK             0x1E000000
  
  #pragma pack(1)
  //
  // Command List structure includes total 32 entries.
  // The entry data structure is listed at the following.
  //
  typedef struct {
    UINT32   AhciCmdCfl:5;      //Command FIS Length
    UINT32   AhciCmdA:1;        //ATAPI
    UINT32   AhciCmdW:1;        //Write
    UINT32   AhciCmdP:1;        //Prefetchable
    UINT32   AhciCmdR:1;        //Reset
    UINT32   AhciCmdB:1;        //BIST
    UINT32   AhciCmdC:1;        //Clear Busy upon R_OK
    UINT32   AhciCmdRsvd:1;
    UINT32   AhciCmdPmp:4;      //Port Multiplier Port
    UINT32   AhciCmdPrdtl:16;   //Physical Region Descriptor Table Length
    UINT32   AhciCmdPrdbc;      //Physical Region Descriptor Byte Count
    UINT32   AhciCmdCtba;       //Command Table Descriptor Base Address
    UINT32   AhciCmdCtbau;      //Command Table Descriptor Base Address Upper 32-BITs
    UINT32   AhciCmdRsvd1[4];
  } EFI_AHCI_COMMAND_LIST;
  
  //
  // This is a software constructed FIS.
  // For data transfer operations, this is the H2D Register FIS format as
  // specified in the Serial ATA Revision 2.6 specification.
  //
  typedef struct {
    UINT8    AhciCFisType;
    UINT8    AhciCFisPmNum:4;
    UINT8    AhciCFisRsvd:1;
    UINT8    AhciCFisRsvd1:1;
    UINT8    AhciCFisRsvd2:1;
    UINT8    AhciCFisCmdInd:1;
    UINT8    AhciCFisCmd;
    UINT8    AhciCFisFeature;
    UINT8    AhciCFisSecNum;
    UINT8    AhciCFisClyLow;
    UINT8    AhciCFisClyHigh;
    UINT8    AhciCFisDevHead;
    UINT8    AhciCFisSecNumExp;
    UINT8    AhciCFisClyLowExp;
    UINT8    AhciCFisClyHighExp;
    UINT8    AhciCFisFeatureExp;
    UINT8    AhciCFisSecCount;
    UINT8    AhciCFisSecCountExp;
    UINT8    AhciCFisRsvd3;
    UINT8    AhciCFisControl;
    UINT8    AhciCFisRsvd4[4];
    UINT8    AhciCFisRsvd5[44];
  } EFI_AHCI_COMMAND_FIS;
  
  //
  // ACMD: ATAPI command (12 or 16 bytes)
  //
  typedef struct {
    UINT8    AtapiCmd[0x10];
  } EFI_AHCI_ATAPI_COMMAND;
  
  //
  // Physical Region Descriptor Table includes up to 65535 entries
  // The entry data structure is listed at the following.
  // the actual entry number comes from the PRDTL field in the command
  // list entry for this command slot.
  //
  typedef struct {
    UINT32   AhciPrdtDba;       //Data Base Address
    UINT32   AhciPrdtDbau;      //Data Base Address Upper 32-BITs
    UINT32   AhciPrdtRsvd;
    UINT32   AhciPrdtDbc:22;    //Data Byte Count
    UINT32   AhciPrdtRsvd1:9;
    UINT32   AhciPrdtIoc:1;     //Interrupt on Completion
  } EFI_AHCI_COMMAND_PRDT;
  
  //
  // Command table data strucute which is pointed to by the entry in the command list
  //
  typedef struct {
    EFI_AHCI_COMMAND_FIS      CommandFis;       // A software constructed FIS.
    EFI_AHCI_ATAPI_COMMAND    AtapiCmd;         // 12 or 16 bytes ATAPI cmd.
    UINT8                     Reserved[0x30];
    EFI_AHCI_COMMAND_PRDT     PrdtTable[65535];     // The scatter/gather list for data transfer
  } EFI_AHCI_COMMAND_TABLE;
  
  //
  // Received FIS structure
  //
  typedef struct {
    UINT8    AhciDmaSetupFis[0x1C];         // Dma Setup Fis: offset 0x00
    UINT8    AhciDmaSetupFisRsvd[0x04];
    UINT8    AhciPioSetupFis[0x14];         // Pio Setup Fis: offset 0x20
    UINT8    AhciPioSetupFisRsvd[0x0C];
    UINT8    AhciD2HRegisterFis[0x14];      // D2H Register Fis: offset 0x40
    UINT8    AhciD2HRegisterFisRsvd[0x04];
    UINT64   AhciSetDeviceBitsFis;          // Set Device Bits Fix: offset 0x58
    UINT8    AhciUnknownFis[0x40];          // Unkonwn Fis: offset 0x60
    UINT8    AhciUnknownFisRsvd[0x60];
  } EFI_AHCI_RECEIVED_FIS;
  
  typedef struct {
    UINT8  Madt : 5;
    UINT8  Reserved_5 : 3;
    UINT8  Deto;
    UINT16 Reserved_16;
    UINT32 Reserved_32 : 31;
    UINT32 Supported : 1;
  } DEVSLP_TIMING_VARIABLES;
  
  #pragma pack()
  
  typedef struct {
    EFI_AHCI_RECEIVED_FIS     *AhciRFis;
    EFI_AHCI_COMMAND_LIST     *AhciCmdList;
    EFI_AHCI_COMMAND_TABLE    *AhciCommandTable;
    EFI_AHCI_RECEIVED_FIS     *AhciRFisPciAddr;
    EFI_AHCI_COMMAND_LIST     *AhciCmdListPciAddr;
    EFI_AHCI_COMMAND_TABLE    *AhciCommandTablePciAddr;
    UINT64                    MaxCommandListSize;
    UINT64                    MaxCommandTableSize;
    UINT64                    MaxReceiveFisSize;
    VOID                      *MapRFis;
    VOID                      *MapCmdList;
    VOID                      *MapCommandTable;
  } EFI_AHCI_REGISTERS;
  
  /**
    This function is used to send out ATAPI commands conforms to the Packet Command
    with PIO Protocol.
  
    @param PciIo              The PCI IO protocol instance.
    @param AhciRegisters      The pointer to the EFI_AHCI_REGISTERS.
    @param Port               The number of port.
    @param PortMultiplier     The number of port multiplier.
    @param Packet             A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
  
    @retval EFI_SUCCESS       send out the ATAPI packet command successfully
                              and device sends data successfully.
    @retval EFI_DEVICE_ERROR  the device failed to send data.
  
  **/
  EFI_STATUS
  EFIAPI
  AhciPacketCommandExecute (
    IN  EFI_PCI_IO_PROTOCOL                           *PciIo,
    IN  EFI_AHCI_REGISTERS                            *AhciRegisters,
    IN  UINT8                                         Port,
    IN  UINT8                                         PortMultiplier,
    IN  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
    );
  
  /**
    Start command for give slot on specific port.
  
    @param  PciIo              The PCI IO protocol instance.
    @param  Port               The number of port.
    @param  CommandSlot        The number of CommandSlot.
    @param  Timeout            The timeout value of start, uses 100ns as a unit.
  
    @retval EFI_DEVICE_ERROR   The command start unsuccessfully.
    @retval EFI_TIMEOUT        The operation is time out.
    @retval EFI_SUCCESS        The command start successfully.
  
  **/
  EFI_STATUS
  EFIAPI
  AhciStartCommand (
    IN  EFI_PCI_IO_PROTOCOL       *PciIo,
    IN  UINT8                     Port,
    IN  UINT8                     CommandSlot,
    IN  UINT64                    Timeout
    );
  
  /**
    Stop command running for giving port
  
    @param  PciIo              The PCI IO protocol instance.
    @param  Port               The number of port.
    @param  Timeout            The timeout value of stop, uses 100ns as a unit.
  
    @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.
    @retval EFI_TIMEOUT        The operation is time out.
    @retval EFI_SUCCESS        The command stop successfully.
  
  **/
  EFI_STATUS
  EFIAPI
  AhciStopCommand (
    IN  EFI_PCI_IO_PROTOCOL       *PciIo,
    IN  UINT8                     Port,
    IN  UINT64                    Timeout
    );
  
  #endif
  
  