/*******************************************************************************
Copyright (C) 2016 Marvell International Ltd.

SPDX-License-Identifier: BSD-2-Clause-Patent

*******************************************************************************/

#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/IoLib.h>

#include <Protocol/PciIo.h>
#include <Protocol/SdMmcOverride.h>

#include "XenonPciHci.h"

#define SD_BAR_INDEX 0

#define SIZE_512B    0x200

/* Register Offset of SD Host Controller */
#define SDHC_SDMA_ADDR                0x0000
#define SDHC_ARG2                     0x0000
#define SDHC_BLK_SIZE                 0x0004
#define SDHC_BLK_COUNT                0x0006
#define SDHC_ARG1                     0x0008
#define SDHC_TRANS_MOD                0x000C
#define SDHC_COMMAND                  0x000E
#define SDHC_RESPONSE                 0x0010
#define SDHC_BUF_DAT_PORT             0x0020
#define SDHC_PRESENT_STATE            0x0024
#define SDHC_HOST_CTRL1               0x0028
#define SDHC_POWER_CTRL               0x0029
#define SDHC_BLK_GAP_CTRL             0x002A
#define SDHC_WAKEUP_CTRL              0x002B
#define SDHC_CLOCK_CTRL               0x002C
#define SDHC_TIMEOUT_CTRL             0x002E
#define SDHC_SW_RST                   0x002F
#define SDHC_NOR_INT_STS              0x0030
#define SDHC_ERR_INT_STS              0x0032
#define SDHC_NOR_INT_STS_EN           0x0034
#define SDHC_ERR_INT_STS_EN           0x0036
#define SDHC_NOR_INT_SIG_EN           0x0038
#define SDHC_ERR_INT_SIG_EN           0x003A
#define SDHC_AUTO_CMD_ERR_STS         0x003C
#define SDHC_HOST_CTRL2               0x003E
#define UHS_MODE_SELECT_MASK          0x7
#define SDHC_CAP                      0x0040
#define SDHC_CAP_BUS_WIDTH8           BIT18
#define SDHC_CAP_VOLTAGE_33           BIT24
#define SDHC_CAP_VOLTAGE_30           BIT25
#define SDHC_CAP_VOLTAGE_18           BIT26
#define SDHC_CAP_SLOT_TYPE_OFFSET     30
#define SDHC_CAP_SLOT_TYPE_MASK       (BIT30 | BIT31)
#define SDHC_CAP_SDR50                BIT32
#define SDHC_CAP_SDR104               BIT33
#define SDHC_CAP_DDR50                BIT34
#define SDHC_CAP_HS400                BIT63
#define SDHC_MAX_CURRENT_CAP          0x0048
#define SDHC_FORCE_EVT_AUTO_CMD       0x0050
#define SDHC_FORCE_EVT_ERR_INT        0x0052
#define SDHC_ADMA_ERR_STS             0x0054
#define SDHC_ADMA_SYS_ADDR            0x0058
#define SDHC_PRESET_VAL               0x0060
#define SDHC_SHARED_BUS_CTRL          0x00E0
#define SDHC_SLOT_INT_STS             0x00FC
#define SDHC_CTRL_VER                 0x00FE

#define SDHC_IPID                     0x0100
#define SDHC_SYS_CFG_INFO             0x0104
#define SLOT_TYPE_SDIO_SHIFT          24
#define SLOT_TYPE_EMMC_MASK           0xff
#define SLOT_TYPE_EMMC_SHIFT          16
#define SLOT_TYPE_SD_SDIO_MMC_MASK    0xff
#define SLOT_TYPE_SD_SDIO_MMC_SHIFT   8

#define SDHC_SYS_OP_CTRL              0x0108
#define AUTO_CLKGATE_DISABLE_MASK     (0x1<<20)
#define SDCLK_IDLEOFF_ENABLE_MASK     (1 << 8)
#define SLOT_ENABLE_SHIFT             0

#define SDHC_SYS_EXT_OP_CTRL          0x010c
#define MASK_CMD_CONFLICT_ERR         (1 << 8)

#define SDHC_TEST_OUT                 0x0110
#define SDHC_TESTOUT_MUXSEL           0x0114

#define SDHC_SLOT_EXT_INT_STATUS      0x0120
#define SDHC_SLOT_EXT_ERR_STATUS      0x0122
#define SDHC_SLOT_EXT_INT_STATUS_EN   0x0124
#define SDHC_SLOT_EXT_ERR_STATUS_EN   0x0126

#define SDHC_SLOT_OP_STATUS_CTRL      0x0128
#define TUNING_PROG_FIXED_DELAY_MASK  0x7ff
#define FORCE_SEL_INVERSE_CLK_SHIFT   11

#define SDHC_SLOT_FIFO_CTRL           0x012c
#define SDHC_SLOT_FIFO_DEFAULT_CONFIG 0x315

#define SDHC_SLOT_eMMC_CTRL           0x0130
#define ENABLE_DATA_STROBE_SHIFT      24
#define SET_EMMC_RSTN_SHIFT           16
#define eMMC_VCCQ_MASK                0x3
#define eMMC_VCCQ_1_8V                0x1
#define eMMC_VCCQ_1_2V                0x2
#define eMMC_VCCQ_3_3V                0x3

#define SDHC_SLOT_OUTPUT_DLY_CTRL     0x0134
#define SDHC_SLOT_DCM_CTRL            0x0137

#define SDHC_SLOT_DLL_CTRL            0x0138
#define SELECT_DEF_DLL                0x1

#define SDHC_SLOT_DLL_PHASE_SEL       0x013c
#define DLL_UPDATE_STROBE             7

#define SDHC_SLOT_STROBE_DLY_CTRL     0x0140
#define STROBE_DELAY_FIXED_MASK       0xffff

#define SDHC_SLOT_RETUNING_REQ_CTRL   0x0144
#define RETUNING_COMPATIBLE           0x1

#define SDHC_SLOT_AUTO_RETUNING_CTRL  0x0148
#define ENABLE_AUTO_RETUNING          0x1

#define SDHC_SLOT_EXT_PRESENT_STATE   0x014c
#define SDHC_SLOT_DLL_CUR_DLY_VAL     0x0150
#define SDHC_SLOT_TUNING_CUR_DLY_VAL  0x0154
#define SDHC_SLOT_STROBE_CUR_DLY_VAL  0x0158
#define SDHC_SLOT_SUB_CMD_STRL        0x015c

#define SDHC_SLOT_CQ_TASK_INFO        0x0160

#define SDHC_SLOT_TUNING_DEBUG_INFO   0x01f0
#define SDHC_SLOT_DATAIN_DEBUG_INFO   0x01f4

#define SDHC_CMD_RESET_BIT            (1 << 1)
#define SDHC_DATA_RESET_BIT           (1 << 2)

#define SDHC_CMD_INHIBIT              (1 << 0)
#define SDHC_DATA_INHIBIT             (1 << 1)

#define SDHC_REG_SIZE_1B              1
#define SDHC_REG_SIZE_2B              2
#define SDHC_REG_SIZE_4B              4

#define SDHC_DAT_BUF_PORT_ADDR        0xF06E0020

/* Command register bits description */
#define RESP_TYPE_136_BITS            (1 << 0)
#define RESP_TYPE_48_BITS             (1 << 1)
#define RESP_TYPE_48_BITS_NO_CRC      ((1 << 0) | (1 << 1))
#define CMD_CRC_CHK_EN                (1 << 3)
#define CMD_INDEX_CHK_EN              (1 << 4)
#define DATA_PRESENT                  (1 << 5)

/* Transfer mode register bits description */
#define SDHC_TRNS_BLK_CNT_EN          (1 << 1)
#define SDHC_TRNS_MULTI_BLK_SEL       (1 << 5)
#define SDHC_TRNS_TO_HOST_DIR         (1 << 4)

/* Block size register bits description */
#define BLK_SIZE_HOST_DMA_BDRY_OFFSET 12
#define BLK_SIZE_512KB                0x7

/* Int status register bits description */
#define NOR_INT_STS_CMD_COMPLETE      (1 << 0)
#define NOR_INT_STS_XFER_COMPLETE     (1 << 1)
#define NOR_INT_STS_TX_RDY            (1 << 4)
#define NOR_INT_STS_RX_RDY            (1 << 5)
#define NOR_INT_STS_CARD_INS          (1 << 6)
#define NOR_INT_STS_CARD_INT          (1 << 8)
#define NOR_INT_STS_ERR_INT           (1 << 15)
#define ERR_INT_STS_CMD_TIMEOUT_ERR   (1 << 16)
#define ERR_INT_STS_DATA_TIMEOUT_ERR  (1 << 20)

#define NOR_INT_SIG_EN_CARD_INT       (1 << 8)

#define PRESENT_STATE_BUFFER_RD_EN    (1 << 11)
#define PRESENT_STATE_BUFFER_WR_EN    (1 << 10)

#define SDHC_CLR_IRQ_STS_MASK         0xFFFF
#define SDHC_CLR_ALL_IRQ_MASK         0xFFFFFFFFUL

/* Max clock in Hz */
#define XENON_MMC_MAX_CLK             400000000
#define XENON_MMC_CLK_RATIO           2046
#define XENON_MMC_BASE_CLK            XENON_MMC_MAX_CLK / XENON_MMC_CLK_RATIO
#define XENON_MMC_MIN_CLK             100000

#define XENON_MMC_CMD_MAX_TIMEOUT     3200
#define XENON_MMC_CMD_DEFAULT_TIMEOUT 100

/* Tuning Parameter */
#define TMR_RETUN_NO_PRESENT          0xf
#define XENON_MAX_TUN_COUNT           0xb

#define XENON_SLOT_OP_STATUS_CTRL     0x0128
#define TUN_CONSECUTIVE_TIMES_SHIFT   16
#define TUN_CONSECUTIVE_TIMES_MASK    0x7
#define TUN_CONSECUTIVE_TIMES         0x4
#define TUNING_STEP_SHIFT             12
#define TUNING_STEP_MASK              0xF

#define XENON_SLOT_EMMC_CTRL          0x130
#define ENABLE_DATA_STROBE            (1 << 24)

#define XENON_SLOT_EXT_PRESENT_STATE  0x014C
#define DLL_LOCK_STATE                0x1

#define XENON_SLOT_DLL_CUR_DLY_VAL    0x0150

#define EMMC_PHY_REG_BASE                 0x170
#define EMMC_PHY_TIMING_ADJUST            EMMC_PHY_REG_BASE
#define OUTPUT_QSN_PHASE_SELECT           (1 << 17)
#define SAMPL_INV_QSP_PHASE_SELECT        (1 << 18)
#define SAMPL_INV_QSP_PHASE_SELECT_SHIFT  18
#define QSN_PHASE_SLOW_MODE_BIT           (1 << 29)
#define PHY_INITIALIZAION                 (1 << 31)
#define WAIT_CYCLE_BEFORE_USING_MASK      0xf
#define WAIT_CYCLE_BEFORE_USING_SHIFT     12
#define FC_SYNC_EN_DURATION_MASK          0xf
#define FC_SYNC_EN_DURATION_SHIFT         8
#define FC_SYNC_RST_EN_DURATION_MASK      0xf
#define FC_SYNC_RST_EN_DURATION_SHIFT     4
#define FC_SYNC_RST_DURATION_MASK         0xf
#define FC_SYNC_RST_DURATION_SHIFT        0

#define EMMC_PHY_FUNC_CONTROL     (EMMC_PHY_REG_BASE + 0x4)
#define DQ_ASYNC_MODE             (1 << 4)
#define DQ_DDR_MODE_SHIFT         8
#define DQ_DDR_MODE_MASK          0xff
#define CMD_DDR_MODE              (1 << 16)

#define EMMC_PHY_PAD_CONTROL      (EMMC_PHY_REG_BASE + 0x8)
#define REC_EN_SHIFT              24
#define REC_EN_MASK               0xf
#define FC_DQ_RECEN               (1 << 24)
#define FC_CMD_RECEN              (1 << 25)
#define FC_QSP_RECEN              (1 << 26)
#define FC_QSN_RECEN              (1 << 27)
#define OEN_QSN                   (1 << 28)
#define AUTO_RECEN_CTRL           (1 << 30)
#define FC_ALL_CMOS_RECEIVER      0xF000

#define EMMC_PHY_PAD_CONTROL1        (EMMC_PHY_REG_BASE + 0xc)
#define EMMC5_1_FC_QSP_PD            (1 << 9)
#define EMMC5_1_FC_QSP_PU            (1 << 25)
#define EMMC5_1_FC_CMD_PD            (1 << 8)
#define EMMC5_1_FC_CMD_PU            (1 << 24)
#define EMMC5_1_FC_DQ_PD             0xFF
#define EMMC5_1_FC_DQ_PU             (0xFF << 16)

#define EMMC_PHY_PAD_CONTROL2        (EMMC_PHY_REG_BASE + 0x10)
#define ZNR_MASK                     0x1F
#define ZNR_SHIFT                    8
#define ZPR_MASK                     0x1F
#define ZNR_DEF_VALUE                0xF
#define ZPR_DEF_VALUE                0xF

#define EMMC_PHY_DLL_CONTROL         (EMMC_PHY_REG_BASE + 0x14)
#define DLL_ENABLE                   (1 << 31)
#define DLL_UPDATE_STROBE_5_0        (1 << 30)
#define DLL_REFCLK_SEL               (1 << 30)
#define DLL_UPDATE                   (1 << 23)
#define DLL_PHSEL1_SHIFT             24
#define DLL_PHSEL0_SHIFT             16
#define DLL_PHASE_MASK               0x3F
#define DLL_PHASE_90_DEGREE          0x1F
#define DLL_FAST_LOCK                (1 << 5)
#define DLL_GAIN2X                   (1 << 3)
#define DLL_BYPASS_EN                (1 << 0)

#define EMMC_LOGIC_TIMING_ADJUST       (EMMC_PHY_REG_BASE + 0x18)
#define EMMC_LOGIC_TIMING_ADJUST_LOW   (EMMC_PHY_REG_BASE + 0x1c)

#define LOGIC_TIMING_VALUE             0x5a54 /* Recommend by HW team */

#define TUNING_STEP_DIVIDER_SHIFT      6

/* XENON only have one slot 0 */
#define XENON_MMC_SLOT_ID              (0)

#define MMC_TIMING_LEGACY     0
#define MMC_TIMING_MMC_HS     1
#define MMC_TIMING_SD_HS      2
#define MMC_TIMING_UHS_SDR12  3
#define MMC_TIMING_UHS_SDR25  4
#define MMC_TIMING_UHS_SDR50  5
#define MMC_TIMING_UHS_SDR104 6
#define MMC_TIMING_UHS_DDR50  7
#define MMC_TIMING_MMC_HS200  8
#define MMC_TIMING_MMC_HS400  10
#define MMC_TIMING_MMC_DDR52  11

/* Custom UHS signaling field values */
#define XENON_SD_MMC_HC_CTRL_HS200    0x5
#define XENON_SD_MMC_HC_CTRL_HS400    0x6

/* Data time out default value 0xE: TMCLK x 227 */
#define DATA_TIMEOUT_DEF_VAL          0xE

/* Max retry count for INT status ready */
#define SDHC_INT_STATUS_POLL_RETRY              1000
#define SDHC_INT_STATUS_POLL_RETRY_DATA_TRAN    100000

/* Take 2.5 seconds as generic time out value, 1 microsecond as unit */
#define SD_GENERIC_TIMEOUT            2500 * 1000

/* SDMA start address should allign with 0x8, align mask 0x7 */
#define DMA_START_ADDR_ALIGN_MASK 0x7

#define  SDHCI_RETUNE_EVT_INTSIG  0x00001000

/* MMC modes */
#define XENON_MMC_MODE_EMMC     0
#define XENON_MMC_MODE_SD_SDIO  1

/* MMC Voltage */
#define MMC_VDD_165_195   0x00000080  /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21     0x00000100  /* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22     0x00000200  /* VDD voltage 2.1 ~ 2.2 */
#define MMC_VDD_22_23     0x00000400  /* VDD voltage 2.2 ~ 2.3 */
#define MMC_VDD_23_24     0x00000800  /* VDD voltage 2.3 ~ 2.4 */
#define MMC_VDD_24_25     0x00001000  /* VDD voltage 2.4 ~ 2.5 */
#define MMC_VDD_25_26     0x00002000  /* VDD voltage 2.5 ~ 2.6 */
#define MMC_VDD_26_27     0x00004000  /* VDD voltage 2.6 ~ 2.7 */
#define MMC_VDD_27_28     0x00008000  /* VDD voltage 2.7 ~ 2.8 */
#define MMC_VDD_28_29     0x00010000  /* VDD voltage 2.8 ~ 2.9 */
#define MMC_VDD_29_30     0x00020000  /* VDD voltage 2.9 ~ 3.0 */
#define MMC_VDD_30_31     0x00040000  /* VDD voltage 3.0 ~ 3.1 */
#define MMC_VDD_31_32     0x00080000  /* VDD voltage 3.1 ~ 3.2 */
#define MMC_VDD_32_33     0x00100000  /* VDD voltage 3.2 ~ 3.3 */
#define MMC_VDD_33_34     0x00200000  /* VDD voltage 3.3 ~ 3.4 */
#define MMC_VDD_34_35     0x00400000  /* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36     0x00800000  /* VDD voltage 3.5 ~ 3.6 */

/* SDHCI FLAGS */
#define SDHCI_POWER_ON   0x01
#define SDHCI_POWER_180  0x0A
#define SDHCI_POWER_300  0x0C
#define SDHCI_POWER_330  0x0E

#define SDHCI_DIVIDER_SHIFT     8
#define SDHCI_DIVIDER_HI_SHIFT  6
#define SDHCI_DIV_MASK          0xFF
#define SDHCI_DIV_MASK_LEN      8
#define SDHCI_DIV_HI_MASK       0x300
#define SDHCI_CLOCK_CARD_EN     0x0004
#define SDHCI_CLOCK_INT_STABLE  0x0002
#define SDHCI_CLOCK_INT_EN      0x0001

#define SDHCI_VENDOR_VER_MASK   0xFF00
#define SDHCI_VENDOR_VER_SHIFT  8
#define SDHCI_SPEC_VER_MASK     0x00FF
#define SDHCI_SPEC_VER_SHIFT    0
#define SDHCI_SPEC_100          0
#define SDHCI_SPEC_200          1
#define SDHCI_SPEC_300          2

#define SDHCI_SIGNAL_ENABLE     0x38

#define SDHCI_MAX_DIV_SPEC_200  256
#define SDHCI_MAX_DIV_SPEC_300  2046

/* SD DEVICE STATUS FLAGS */
#define CURRENT_STATE_MASK           (0xF << 9)
#define CURRENT_STATE_N_READY_MASK   (7 << 9)
#define READY_FOR_DATA               (1 << 8)
#define CARD_STATUS_ERROR_MASK       (~0x0206BF7F)

#define RCA_BITS_OFFSET              16

UINTN
XenonSetClk (
  IN EFI_PCI_IO_PROTOCOL   *PciIo,
  IN UINT32 Clock
  );

VOID
XenonPhyInit (
  IN EFI_PCI_IO_PROTOCOL   *PciIo
  );

VOID
XenonReset (
  IN EFI_PCI_IO_PROTOCOL *PciIo,
  IN UINT8 Slot,
  IN UINT8 Mask
  );

EFI_STATUS
XenonTransferData (
  IN EFI_PCI_IO_PROTOCOL *PciIo,
  IN UINT8 Slot,
  IN OUT VOID *Buffer,
  IN UINT32 DataLen,
  IN UINT16 BlockSize,
  IN UINT16 Blocks,
  IN BOOLEAN Read
  );

EFI_STATUS
XenonInit (
  IN EFI_PCI_IO_PROTOCOL   *PciIo,
  IN BOOLEAN               Support1v8,
  IN BOOLEAN               SlowMode,
  IN UINT8                 TuningStepDivisor
  );

EFI_STATUS
XenonSetPhy (
  IN EFI_PCI_IO_PROTOCOL   *PciIo,
  IN BOOLEAN               SlowMode,
  IN UINT8                 TuningStepDivisor,
  IN SD_MMC_BUS_MODE       Timing
  );
