/** @file

  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
  This program and the accompanying materials
  are licensed and made available under the terms and conditions of the BSD License
  which accompanies this distribution.  The full text of the license may be found at
  http://opensource.org/licenses/bsd-license.php.

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#ifndef _EMMC_HCI_H_
#define _EMMC_HCI_H_

//
// EMMC Host Controller MMIO Register Offset
//
#define EMMC_HC_SDMA_ADDR           0x00
#define EMMC_HC_ARG2                0x00
#define EMMC_HC_BLK_SIZE            0x04
#define EMMC_HC_BLK_COUNT           0x06
#define EMMC_HC_ARG1                0x08
#define EMMC_HC_TRANS_MOD           0x0C
#define EMMC_HC_COMMAND             0x0E
#define EMMC_HC_RESPONSE            0x10
#define EMMC_HC_BUF_DAT_PORT        0x20
#define EMMC_HC_PRESENT_STATE       0x24
#define EMMC_HC_HOST_CTRL1          0x28
#define EMMC_HC_POWER_CTRL          0x29
#define EMMC_HC_BLK_GAP_CTRL        0x2A
#define EMMC_HC_WAKEUP_CTRL         0x2B
#define EMMC_HC_CLOCK_CTRL          0x2C
#define EMMC_HC_TIMEOUT_CTRL        0x2E
#define EMMC_HC_SW_RST              0x2F
#define EMMC_HC_NOR_INT_STS         0x30
#define EMMC_HC_ERR_INT_STS         0x32
#define EMMC_HC_NOR_INT_STS_EN      0x34
#define EMMC_HC_ERR_INT_STS_EN      0x36
#define EMMC_HC_NOR_INT_SIG_EN      0x38
#define EMMC_HC_ERR_INT_SIG_EN      0x3A
#define EMMC_HC_AUTO_CMD_ERR_STS    0x3C
#define EMMC_HC_HOST_CTRL2          0x3E
#define EMMC_HC_CAP                 0x40
#define EMMC_HC_MAX_CURRENT_CAP     0x48
#define EMMC_HC_FORCE_EVT_AUTO_CMD  0x50
#define EMMC_HC_FORCE_EVT_ERR_INT   0x52
#define EMMC_HC_ADMA_ERR_STS        0x54
#define EMMC_HC_ADMA_SYS_ADDR       0x58
#define EMMC_HC_PRESET_VAL          0x60
#define EMMC_HC_SHARED_BUS_CTRL     0xE0
#define EMMC_HC_SLOT_INT_STS        0xFC
#define EMMC_HC_CTRL_VER            0xFE

//
// The transfer modes supported by SD Host Controller
// Simplified Spec 3.0 Table 1-2
//
typedef enum {
  EmmcNoData,
  EmmcPioMode,
  EmmcSdmaMode,
  EmmcAdmaMode
} EMMC_HC_TRANSFER_MODE;

//
// The maximum data length of each descriptor line
//
#define ADMA_MAX_DATA_PER_LINE      0x10000
#define EMMC_SDMA_BOUNDARY          512 * 1024
#define EMMC_SDMA_ROUND_UP(x, n)    (((x) + n) & ~(n - 1))

typedef enum {
  EmmcCommandTypeBc,  // Broadcast commands, no response
  EmmcCommandTypeBcr, // Broadcast commands with response
  EmmcCommandTypeAc,  // Addressed(point-to-point) commands
  EmmcCommandTypeAdtc // Addressed(point-to-point) data transfer commands
} EMMC_COMMAND_TYPE;

typedef enum {
  EmmcResponceTypeR1,
  EmmcResponceTypeR1b,
  EmmcResponceTypeR2,
  EmmcResponceTypeR3,
  EmmcResponceTypeR4,
  EmmcResponceTypeR5,
  EmmcResponceTypeR5b,
  EmmcResponceTypeR6,
  EmmcResponceTypeR7
} EMMC_RESPONSE_TYPE;

typedef struct _EMMC_COMMAND_BLOCK {
  UINT16                            CommandIndex;
  UINT32                            CommandArgument;
  UINT32                            CommandType;      // One of the EMMC_COMMAND_TYPE values
  UINT32                            ResponseType;     // One of the EMMC_RESPONSE_TYPE values
} EMMC_COMMAND_BLOCK;

typedef struct _EMMC_STATUS_BLOCK {
  UINT32                            Resp0;
  UINT32                            Resp1;
  UINT32                            Resp2;
  UINT32                            Resp3;
} EMMC_STATUS_BLOCK;

typedef struct _EMMC_COMMAND_PACKET {
  UINT64                            Timeout;
  EMMC_COMMAND_BLOCK                *EmmcCmdBlk;
  EMMC_STATUS_BLOCK                 *EmmcStatusBlk;
  VOID                              *InDataBuffer;
  VOID                              *OutDataBuffer;
  UINT32                            InTransferLength;
  UINT32                            OutTransferLength;
} EMMC_COMMAND_PACKET;

#pragma pack(1)

typedef struct {
  UINT32 Valid:1;
  UINT32 End:1;
  UINT32 Int:1;
  UINT32 Reserved:1;
  UINT32 Act:2;
  UINT32 Reserved1:10;
  UINT32 Length:16;
  UINT32 Address;
} EMMC_HC_ADMA_DESC_LINE;

typedef struct {
  UINT32   TimeoutFreq:6;     // bit 0:5
  UINT32   Reserved:1;        // bit 6
  UINT32   TimeoutUnit:1;     // bit 7
  UINT32   BaseClkFreq:8;     // bit 8:15
  UINT32   MaxBlkLen:2;       // bit 16:17
  UINT32   BusWidth8:1;       // bit 18
  UINT32   Adma2:1;           // bit 19
  UINT32   Reserved2:1;       // bit 20
  UINT32   HighSpeed:1;       // bit 21
  UINT32   Sdma:1;            // bit 22
  UINT32   SuspRes:1;         // bit 23
  UINT32   Voltage33:1;       // bit 24
  UINT32   Voltage30:1;       // bit 25
  UINT32   Voltage18:1;       // bit 26
  UINT32   Reserved3:1;       // bit 27
  UINT32   SysBus64:1;        // bit 28
  UINT32   AsyncInt:1;        // bit 29
  UINT32   SlotType:2;        // bit 30:31
  UINT32   Sdr50:1;           // bit 32
  UINT32   Sdr104:1;          // bit 33
  UINT32   Ddr50:1;           // bit 34
  UINT32   Reserved4:1;       // bit 35
  UINT32   DriverTypeA:1;     // bit 36
  UINT32   DriverTypeC:1;     // bit 37
  UINT32   DriverTypeD:1;     // bit 38
  UINT32   DriverType4:1;     // bit 39
  UINT32   TimerCount:4;      // bit 40:43
  UINT32   Reserved5:1;       // bit 44
  UINT32   TuningSDR50:1;     // bit 45
  UINT32   RetuningMod:2;     // bit 46:47
  UINT32   ClkMultiplier:8;   // bit 48:55
  UINT32   Reserved6:7;       // bit 56:62
  UINT32   Hs400:1;           // bit 63
} EMMC_HC_SLOT_CAP;

#pragma pack()

/**
  Software reset the specified EMMC host controller and enable all interrupts.

  @param[in] Bar            The mmio base address of the slot to be accessed.

  @retval EFI_SUCCESS       The software reset executes successfully.
  @retval Others            The software reset fails.

**/
EFI_STATUS
EmmcPeimHcReset (
  IN UINTN                  Bar
  );

/**
  Set all interrupt status bits in Normal and Error Interrupt Status Enable
  register.

  @param[in] Bar            The mmio base address of the slot to be accessed.

  @retval EFI_SUCCESS       The operation executes successfully.
  @retval Others            The operation fails.

**/
EFI_STATUS
EmmcPeimHcEnableInterrupt (
  IN UINTN                  Bar
  );

/**
  Get the capability data from the specified slot.

  @param[in]  Bar             The mmio base address of the slot to be accessed.
  @param[out] Capability      The buffer to store the capability data.

  @retval EFI_SUCCESS         The operation executes successfully.
  @retval Others              The operation fails.

**/
EFI_STATUS
EmmcPeimHcGetCapability (
  IN     UINTN              Bar,
     OUT EMMC_HC_SLOT_CAP   *Capability
  );

/**
  Detect whether there is a EMMC card attached at the specified EMMC host controller
  slot.

  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.

  @param[in]  Bar           The mmio base address of the slot to be accessed.

  @retval EFI_SUCCESS       There is a EMMC card attached.
  @retval EFI_NO_MEDIA      There is not a EMMC card attached.
  @retval Others            The detection fails.

**/
EFI_STATUS
EmmcPeimHcCardDetect (
  IN UINTN                  Bar
  );

/**
  Initial EMMC host controller with lowest clock frequency, max power and max timeout value
  at initialization.

  @param[in] Bar            The mmio base address of the slot to be accessed.

  @retval EFI_SUCCESS       The host controller is initialized successfully.
  @retval Others            The host controller isn't initialized successfully.

**/
EFI_STATUS
EmmcPeimHcInitHost (
  IN UINTN                  Bar
  );

/**
  Send command SWITCH to the EMMC device to switch the mode of operation of the
  selected Device or modifies the EXT_CSD registers.

  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.

  @param[in] Slot           The slot number of the Emmc card to send the command to.
  @param[in] Access         The access mode of SWTICH command.
  @param[in] Index          The offset of the field to be access.
  @param[in] Value          The value to be set to the specified field of EXT_CSD register.
  @param[in] CmdSet         The value of CmdSet field of EXT_CSD register.

  @retval EFI_SUCCESS       The operation is done correctly.
  @retval Others            The operation fails.

**/
EFI_STATUS
EmmcPeimSwitch (
  IN EMMC_PEIM_HC_SLOT                  *Slot,
  IN UINT8                              Access,
  IN UINT8                              Index,
  IN UINT8                              Value,
  IN UINT8                              CmdSet
  );

/**
  Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of
  blocks for the following block read/write cmd.

  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.

  @param[in] Slot           The slot number of the Emmc card to send the command to.
  @param[in] BlockCount     The number of the logical block to access.

  @retval EFI_SUCCESS       The operation is done correctly.
  @retval Others            The operation fails.

**/
EFI_STATUS
EmmcPeimSetBlkCount (
  IN EMMC_PEIM_HC_SLOT              *Slot,
  IN UINT16                         BlockCount
  );

/**
  Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device
  to read/write the specified number of blocks.

  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.

  @param[in] Slot           The slot number of the Emmc card to send the command to.
  @param[in] Lba            The logical block address of starting access.
  @param[in] BlockSize      The block size of specified EMMC device partition.
  @param[in] Buffer         The pointer to the transfer buffer.
  @param[in] BufferSize     The size of transfer buffer.
  @param[in] IsRead         Boolean to show the operation direction.

  @retval EFI_SUCCESS       The operation is done correctly.
  @retval Others            The operation fails.

**/
EFI_STATUS
EmmcPeimRwMultiBlocks (
  IN EMMC_PEIM_HC_SLOT              *Slot,
  IN EFI_LBA                        Lba,
  IN UINT32                         BlockSize,
  IN VOID                           *Buffer,
  IN UINTN                          BufferSize,
  IN BOOLEAN                        IsRead
  );

/**
  Execute EMMC device identification procedure.

  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.

  @param[in] Slot           The slot number of the Emmc card to send the command to.

  @retval EFI_SUCCESS       There is a EMMC card.
  @retval Others            There is not a EMMC card.

**/
EFI_STATUS
EmmcPeimIdentification (
  IN EMMC_PEIM_HC_SLOT           *Slot
  );

/**
  Free the resource used by the TRB.

  @param[in] Trb        The pointer to the EMMC_TRB instance.

**/
VOID
EmmcPeimFreeTrb (
  IN EMMC_TRB           *Trb
  );

#endif

