From b65adc160adc43bf226f6d18a81f484f30eb8801 Mon Sep 17 00:00:00 2001 From: hgchu Date: Fri, 12 Jan 2018 19:19:25 +0900 Subject: [PATCH] BOARD: EXYNOS9810: ufs: add exynos specific files Change-Id: I94018923d8fffc48e4e1e231093ff3ee3bca8c20 Signed-off-by: hgchu --- drivers/scsi/ufs/Makefile | 2 +- drivers/scsi/ufs/ufs-cal-9810.c | 656 +++++++++++++++ drivers/scsi/ufs/ufs-cal-9810.h | 52 ++ drivers/scsi/ufs/ufs-exynos-dbg.c | 1193 ++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-exynos.c | 1237 +++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-exynos.h | 666 ++++++++++++++++ 6 files changed, 3805 insertions(+), 1 deletion(-) create mode 100644 drivers/scsi/ufs/ufs-cal-9810.c create mode 100644 drivers/scsi/ufs/ufs-cal-9810.h create mode 100644 drivers/scsi/ufs/ufs-exynos-dbg.c create mode 100644 drivers/scsi/ufs/ufs-exynos.c create mode 100644 drivers/scsi/ufs/ufs-exynos.h diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 04691d93ee66..79955d9d7d58 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o -obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o ufs-exynos-dbg.o +obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o ufs-exynos-dbg.o ufs-cal-9810.o diff --git a/drivers/scsi/ufs/ufs-cal-9810.c b/drivers/scsi/ufs/ufs-cal-9810.c new file mode 100644 index 000000000000..4293d9ec0a03 --- /dev/null +++ b/drivers/scsi/ufs/ufs-cal-9810.c @@ -0,0 +1,656 @@ +#if defined(__UFS_CAL_U_BOOT__) +#include +#include +#elif defined(__UFS_CAL_FW__) +#include +#include +#else +#include +#include "ufs-cal-9810.h" +#endif + +#ifndef _UFS_CAL_ +#define _UFS_CAL_ + +/* UFSHCI */ +#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\ + ((sel) & 0xFFFF)) +#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0) + +/* Unipro.h */ +#define IS_PWR_MODE_HS(m) (((m) == FAST_MODE) || ((m) == FASTAUTO_MODE)) +#define IS_PWR_MODE_PWM(m) (((m) == SLOW_MODE) || ((m) == SLOWAUTO_MODE)) + +enum { + PA_HS_MODE_A = 1, + PA_HS_MODE_B = 2, +}; + +enum { + FAST_MODE = 1, + SLOW_MODE = 2, + FASTAUTO_MODE = 4, + SLOWAUTO_MODE = 5, + UNCHANGED = 7, +}; + +/* User defined */ +#define UNIPRO_MCLK_PERIOD(p) (1000000000L / p->mclk_rate) + +#define PHY_PMA_COMN_ADDR(reg) (reg) +#define PHY_PMA_TRSV_ADDR(reg, lane) ((reg) + (0x140 * (lane))) + +#define NUM_OF_UFS_HOST 2 + +enum { + PHY_CFG_NONE = 0, + PHY_PCS_COMN, + PHY_PCS_RXTX, + PHY_PMA_COMN, + PHY_PMA_TRSV, + PHY_PLL_WAIT, + PHY_CDR_WAIT, + UNIPRO_STD_MIB, + UNIPRO_DBG_MIB, + UNIPRO_DBG_APB, + + /* Since exynos8895 */ + PHY_PCS_RX, + PHY_PCS_TX, + PHY_PCS_RX_PRD, + PHY_PCS_TX_PRD, + UNIPRO_DBG_PRD, + PHY_PMA_TRSV_LANE1_SQ_OFF, + COMMON_WAIT, +}; + +enum { + TX_LANE_0 = 0, + TX_LANE_1 = 1, + TX_LANE_2 = 2, + TX_LANE_3 = 3, + RX_LANE_0 = 4, + RX_LANE_1 = 5, + RX_LANE_2 = 6, + RX_LANE_3 = 7, +}; + +enum { + __PMD_PWM_G1_L1, + __PMD_PWM_G1_L2, + __PMD_PWM_G2_L1, + __PMD_PWM_G2_L2, + __PMD_PWM_G3_L1, + __PMD_PWM_G3_L2, + __PMD_PWM_G4_L1, + __PMD_PWM_G4_L2, + __PMD_PWM_G5_L1, + __PMD_PWM_G5_L2, + __PMD_HS_G1_L1, + __PMD_HS_G1_L2, + __PMD_HS_G2_L1, + __PMD_HS_G2_L2, + __PMD_HS_G3_L1, + __PMD_HS_G3_L2, +}; + +#define PMD_PWM_G1_L1 (1U << __PMD_PWM_G1_L1) +#define PMD_PWM_G1_L2 (1U << __PMD_PWM_G1_L2) +#define PMD_PWM_G2_L1 (1U << __PMD_PWM_G2_L1) +#define PMD_PWM_G2_L2 (1U << __PMD_PWM_G2_L2) +#define PMD_PWM_G3_L1 (1U << __PMD_PWM_G3_L1) +#define PMD_PWM_G3_L2 (1U << __PMD_PWM_G3_L2) +#define PMD_PWM_G4_L1 (1U << __PMD_PWM_G4_L1) +#define PMD_PWM_G4_L2 (1U << __PMD_PWM_G4_L2) +#define PMD_PWM_G5_L1 (1U << __PMD_PWM_G5_L1) +#define PMD_PWM_G5_L2 (1U << __PMD_PWM_G5_L2) +#define PMD_HS_G1_L1 (1U << __PMD_HS_G1_L1) +#define PMD_HS_G1_L2 (1U << __PMD_HS_G1_L2) +#define PMD_HS_G2_L1 (1U << __PMD_HS_G2_L1) +#define PMD_HS_G2_L2 (1U << __PMD_HS_G2_L2) +#define PMD_HS_G3_L1 (1U << __PMD_HS_G3_L1) +#define PMD_HS_G3_L2 (1U << __PMD_HS_G3_L2) + +#define PMD_ALL (PMD_HS_G3_L2 - 1) +#define PMD_PWM (PMD_PWM_G4_L2 - 1) +#define PMD_HS (PMD_ALL ^ PMD_PWM) + +struct ufs_cal_phy_cfg { + u32 addr; + u32 val; + u32 flg; + u32 lyr; + u8 board; +}; + +#define for_each_phy_cfg(cfg) \ + for (; (cfg)->flg != PHY_CFG_NONE; (cfg)++) + +#endif /*_UFS_CAL_ */ + +static struct ufs_cal_param *ufs_cal[NUM_OF_UFS_HOST]; +static unsigned long ufs_cal_lock_timeout = 0xFFFFFFFF; + +static const struct ufs_cal_phy_cfg init_cfg[] = { + {0x9514, 0x00, PMD_ALL, UNIPRO_DBG_PRD, 0}, + {0x200, 0x40, PMD_ALL, PHY_PCS_COMN, 0}, + {0x12, 0x00, PMD_ALL, PHY_PCS_RX_PRD, 0}, + {0xAA, 0x00, PMD_ALL, PHY_PCS_TX_PRD, 0}, + {0x5C, 0x38, PMD_ALL, PHY_PCS_RX, 0}, + {0x0F, 0x0, PMD_ALL, PHY_PCS_RX, 0}, + {0x65, 0x01, PMD_ALL, PHY_PCS_RX, 0}, + {0x69, 0x01, PMD_ALL, PHY_PCS_RX, 0}, + {0x21, 0x00, PMD_ALL, PHY_PCS_RX, 0}, + {0x22, 0x00, PMD_ALL, PHY_PCS_RX, 0}, + {0x84, 0x01, PMD_ALL, PHY_PCS_RX, 0}, + {0x04, 0x01, PMD_ALL, PHY_PCS_TX, 0}, + {0x8F, 0x3E, PMD_ALL, PHY_PCS_TX, 0}, + {0x200, 0x0, PMD_ALL, PHY_PCS_COMN, 0}, + {0x9536, 0x4E20, PMD_ALL, UNIPRO_DBG_MIB, 0}, + {0x9564, 0x2e820183, PMD_ALL, UNIPRO_DBG_MIB, 0}, + {0x155E, 0x0, PMD_ALL, UNIPRO_STD_MIB, 0}, + {0x3000, 0x0, PMD_ALL, UNIPRO_STD_MIB, 0}, + {0x3001, 0x1, PMD_ALL, UNIPRO_STD_MIB, 0}, + {0x4021, 0x1, PMD_ALL, UNIPRO_STD_MIB, 0}, + {0x4020, 0x1, PMD_ALL, UNIPRO_STD_MIB, 0}, + {0x8C, 0x80, PMD_ALL, PHY_PMA_COMN, 0}, + {0x74, 0x10, PMD_ALL, PHY_PMA_COMN, 0}, + {0x110, 0xB5, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x134, 0x43, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x16C, 0x20, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x178, 0xC0, PMD_ALL, PHY_PMA_TRSV, 0}, + {0xE0, 0x12, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x164, 0x58, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x1B0, 0x18, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x8C, 0xC0, PMD_ALL, PHY_PMA_COMN, 0}, + {0x8C, 0x00, PMD_ALL, PHY_PMA_COMN, 0}, + {0x00, 0xC8, PMD_ALL, COMMON_WAIT, 0}, + {}, +}; + +static struct ufs_cal_phy_cfg post_init_cfg[] = { + {0x9529, 0x01, PMD_ALL, UNIPRO_DBG_MIB, 0}, + {0x15A4, 0xFA, PMD_ALL, UNIPRO_STD_MIB, 0}, + {0x9529, 0x00, PMD_ALL, UNIPRO_DBG_MIB, 0}, + {0x200, 0x40, PMD_ALL, PHY_PCS_COMN, 0}, + {0x35, 0x05, PMD_ALL, PHY_PCS_RX, 0}, + {0x73, 0x01, PMD_ALL, PHY_PCS_RX, 0}, + {0x41, 0x02, PMD_ALL, PHY_PCS_RX, 0}, + {0x42, 0xAC, PMD_ALL, PHY_PCS_RX, 0}, + {0x200, 0x00, PMD_ALL, PHY_PCS_COMN, 0}, + {}, +}; + +static struct ufs_cal_phy_cfg calib_of_pwm[] = { + {0x2041, 8064, PMD_PWM, UNIPRO_STD_MIB, 0}, + {0x2042, 28224, PMD_PWM, UNIPRO_STD_MIB, 0}, + {0x2043, 20160, PMD_PWM, UNIPRO_STD_MIB, 0}, + {0x15B0, 12000, PMD_PWM, UNIPRO_STD_MIB, 0}, + {0x15B1, 32000, PMD_PWM, UNIPRO_STD_MIB, 0}, + {0x15B2, 16000, PMD_PWM, UNIPRO_STD_MIB, 0}, + + {0x7888, 8064, PMD_PWM, UNIPRO_DBG_APB, 0}, + {0x788C, 28224, PMD_PWM, UNIPRO_DBG_APB, 0}, + {0x7890, 20160, PMD_PWM, UNIPRO_DBG_APB, 0}, + {0x78B8, 12000, PMD_PWM, UNIPRO_DBG_APB, 0}, + {0x78BC, 32000, PMD_PWM, UNIPRO_DBG_APB, 0}, + {0x78C0, 16000, PMD_PWM, UNIPRO_DBG_APB, 0}, + + //MPHY tuning value + {0xC8, 0x40, PMD_PWM, PHY_PMA_TRSV, 0}, + {0xF0, 0x77, PMD_PWM, PHY_PMA_TRSV, 0}, + {0x120, 0x80, PMD_PWM, PHY_PMA_TRSV, 0}, + {0x128, 0x00, PMD_PWM, PHY_PMA_TRSV, 0}, + {0x12C, 0x00, PMD_PWM, PHY_PMA_TRSV, 0}, + {0x134, 0x43, PMD_PWM, PHY_PMA_TRSV, 0}, + {}, +}; + +static struct ufs_cal_phy_cfg post_calib_of_pwm[] = { + {}, +}; +static struct ufs_cal_phy_cfg calib_of_hs_rate_a[] = { + {0x2041, 8064, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x2042, 28224, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x2043, 20160, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x15B0, 12000, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x15B1, 32000, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x15B2, 16000, PMD_HS, UNIPRO_STD_MIB, 0}, + + {0x7888, 8064, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x788C, 28224, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x7890, 20160, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x78B8, 12000, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x78BC, 32000, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x78C0, 16000, PMD_HS, UNIPRO_DBG_APB, 0}, + + //MPHY tuning value + {0xC8, 0xBC, PMD_HS, PHY_PMA_TRSV, 0}, + {0xF0, 0x7F, PMD_HS, PHY_PMA_TRSV, 0}, + {0x120, 0xC0, PMD_HS, PHY_PMA_TRSV, 0}, + {0x128, 0x08, PMD_HS_G1_L2, PHY_PMA_TRSV, 0}, + {0x128, 0x02, PMD_HS_G2_L2, PHY_PMA_TRSV, 0}, + {0x128, 0x00, PMD_HS_G3_L2, PHY_PMA_TRSV, 0}, + {0x12C, 0x00, PMD_HS_G1_L2|PMD_HS_G3_L2, PHY_PMA_TRSV, 1}, + {0x12C, 0x10, PMD_HS_G1_L2|PMD_HS_G3_L2, PHY_PMA_TRSV, 2}, + {0x12C, 0x00, PMD_HS_G2_L2, PHY_PMA_TRSV, 0}, + {0x134, 0xd3, PMD_HS_G1_L2, PHY_PMA_TRSV, 0}, + {0x134, 0x73, PMD_HS_G2_L2, PHY_PMA_TRSV, 0}, + {0x134, 0x63, PMD_HS_G3_L2, PHY_PMA_TRSV, 0}, + {0x108, 0x5D, PMD_HS, PHY_PMA_TRSV, 1}, + {0x10C, 0x90, PMD_HS, PHY_PMA_TRSV, 1}, + {}, +}; + +static struct ufs_cal_phy_cfg post_calib_of_hs_rate_a[] = { + {0x1fc, 0x40, PMD_HS, PHY_CDR_WAIT, 0}, + {}, +}; + +static struct ufs_cal_phy_cfg calib_of_hs_rate_b[] = { + {0x2041, 8064, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x2042, 28224, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x2043, 20160, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x15B0, 12000, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x15B1, 32000, PMD_HS, UNIPRO_STD_MIB, 0}, + {0x15B2, 16000, PMD_HS, UNIPRO_STD_MIB, 0}, + + {0x7888, 8064, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x788C, 28224, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x7890, 20160, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x78B8, 12000, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x78BC, 32000, PMD_HS, UNIPRO_DBG_APB, 0}, + {0x78C0, 16000, PMD_HS, UNIPRO_DBG_APB, 0}, + /*MPHY tuning value*/ + {0xC8, 0xBC, PMD_HS, PHY_PMA_TRSV, 0}, + {0xF0, 0x7F, PMD_HS, PHY_PMA_TRSV, 0}, + {0x120, 0xC0, PMD_HS, PHY_PMA_TRSV, 0}, + {0x128, 0x08, PMD_HS_G1_L2, PHY_PMA_TRSV, 0}, + {0x128, 0x02, PMD_HS_G2_L2, PHY_PMA_TRSV, 0}, + {0x128, 0x00, PMD_HS_G3_L2, PHY_PMA_TRSV, 0}, + {0x12C, 0x00, PMD_HS_G1_L2|PMD_HS_G3_L2, PHY_PMA_TRSV, 1}, + {0x12C, 0x10, PMD_HS_G1_L2|PMD_HS_G3_L2, PHY_PMA_TRSV, 2}, + {0x12C, 0x00, PMD_HS_G2_L2, PHY_PMA_TRSV, 0}, + {0x134, 0xd3, PMD_HS_G1_L2, PHY_PMA_TRSV, 0}, + {0x134, 0x73, PMD_HS_G2_L2, PHY_PMA_TRSV, 0}, + {0x134, 0x63, PMD_HS_G3_L2, PHY_PMA_TRSV, 0}, + {0x108, 0x5D, PMD_HS, PHY_PMA_TRSV, 1}, + {0x10C, 0x90, PMD_HS, PHY_PMA_TRSV, 1}, + {}, +}; + +static struct ufs_cal_phy_cfg post_calib_of_hs_rate_b[] = { + {0x1fc, 0x40, PMD_HS, PHY_CDR_WAIT, 0}, + {}, +}; + +static struct ufs_cal_phy_cfg lane1_sq_off[] = { + {0x0C4, 0x19, PMD_ALL, PHY_PMA_TRSV_LANE1_SQ_OFF, 0}, + {0x0E8, 0xFF, PMD_ALL, PHY_PMA_TRSV_LANE1_SQ_OFF, 0}, + {}, +}; + +static struct ufs_cal_phy_cfg post_h8_enter[] = { + {0x0C4, 0x99, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x0E8, 0x7F, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x004, 0x02, PMD_ALL, PHY_PMA_COMN, 0}, + {}, +}; + +static struct ufs_cal_phy_cfg pre_h8_exit[] = { + {0x004, 0x00, PMD_ALL, PHY_PMA_COMN, 0}, + {0x0C4, 0xD9, PMD_ALL, PHY_PMA_TRSV, 0}, + {0x0E8, 0x77, PMD_ALL, PHY_PMA_TRSV, 0}, + {}, +}; + +static inline ufs_cal_errno __match_board_by_cfg(u8 board, u8 cfg_board) +{ + ufs_cal_errno match = UFS_CAL_ERROR; + + if (cfg_board == 0) + match = UFS_CAL_NO_ERROR; + else if (board == cfg_board) + match = UFS_CAL_NO_ERROR; + + return match; +} + +static inline ufs_cal_errno __match_mode_by_cfg(struct uic_pwr_mode *pmd, + int mode) +{ + ufs_cal_errno match = UFS_CAL_ERROR; + u8 _m, _l, _g; + + _m = pmd->mode; + _g = pmd->gear; + _l = pmd->lane; + + if (mode == PMD_ALL) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_HS(_m) && mode == PMD_HS) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && mode == PMD_PWM) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_HS(_m) && _g == 1 && _l == 1 + && (mode & (PMD_HS_G1_L1|PMD_HS_G1_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_HS(_m) && _g == 1 && _l == 2 + && (mode & (PMD_HS_G1_L1|PMD_HS_G1_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_HS(_m) && _g == 2 && _l == 1 + && (mode & (PMD_HS_G2_L1|PMD_HS_G2_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_HS(_m) && _g == 2 && _l == 2 + && (mode & (PMD_HS_G2_L1|PMD_HS_G2_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_HS(_m) && _g == 3 && _l == 1 + && (mode & (PMD_HS_G3_L1|PMD_HS_G3_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_HS(_m) && _g == 3 && _l == 2 + && (mode & (PMD_HS_G3_L1|PMD_HS_G3_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 1 && _l == 1 + && (mode & (PMD_PWM_G1_L1|PMD_PWM_G1_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 1 && _l == 2 + && (mode & (PMD_PWM_G1_L1|PMD_PWM_G1_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 2 && _l == 1 + && (mode & (PMD_PWM_G2_L1|PMD_PWM_G2_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 2 && _l == 2 + && (mode & (PMD_PWM_G2_L1|PMD_PWM_G2_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 3 && _l == 1 + && (mode & (PMD_PWM_G3_L1|PMD_PWM_G3_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 3 && _l == 2 + && (mode & (PMD_PWM_G3_L1|PMD_PWM_G3_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 4 && _l == 1 + && (mode & (PMD_PWM_G4_L1|PMD_PWM_G4_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 4 && _l == 2 + && (mode & (PMD_PWM_G4_L1|PMD_PWM_G4_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 5 && _l == 1 + && (mode & (PMD_PWM_G5_L1|PMD_PWM_G5_L2))) + match = UFS_CAL_NO_ERROR; + else if (IS_PWR_MODE_PWM(_m) && _g == 5 && _l == 2 + && (mode & (PMD_PWM_G5_L1|PMD_PWM_G5_L2))) + match = UFS_CAL_NO_ERROR; + + return match; +} + +static inline ufs_cal_errno ufs_cal_wait_pll_lock(void *hba, + u32 addr, u32 mask) +{ + u32 delay_us = 1; + u32 period_ms = 1; + u32 reg; + unsigned long timeout = ufs_lld_get_time_count(0) + ufs_cal_lock_timeout; + + do { + reg = ufs_lld_pma_read(hba, PHY_PMA_COMN_ADDR(addr)); + if (mask == (reg & mask)) + return UFS_CAL_NO_ERROR; + ufs_lld_usleep_delay(delay_us, delay_us); + } while ((long)(ufs_lld_get_time_count(period_ms) - timeout) >= 0); + + return UFS_CAL_ERROR; +} + +static inline ufs_cal_errno ufs_cal_wait_cdr_lock(void *hba, + u32 addr, u32 mask, int lane) +{ + u32 delay_us = 1; + u32 period_ms = 1; + u32 reg; + unsigned long timeout = ufs_lld_get_time_count(0) + ufs_cal_lock_timeout; + + do { + reg = ufs_lld_pma_read(hba, PHY_PMA_TRSV_ADDR(addr, lane)); + if (mask == (reg & mask)) + return UFS_CAL_NO_ERROR; + ufs_lld_usleep_delay(delay_us, delay_us); + } while ((long)(ufs_lld_get_time_count(period_ms) - timeout) >= 0); + + return UFS_CAL_ERROR; + +} + +static ufs_cal_errno ufs_cal_config_uic(struct ufs_cal_param *p, + const struct ufs_cal_phy_cfg *cfg, + struct uic_pwr_mode *pmd) +{ + void *hba = p->host; + u8 i = 0; + + if (!cfg) + return UFS_CAL_INV_ARG; + + for_each_phy_cfg(cfg) { + for (i = 0; i < p->target_lane; i++) { + if (UFS_CAL_ERROR == + __match_board_by_cfg(p->board, cfg->board)) + continue; + if (pmd && UFS_CAL_ERROR == + __match_mode_by_cfg(pmd, cfg->flg)) + continue; + + switch (cfg->lyr) { + case PHY_PCS_COMN: + case UNIPRO_STD_MIB: + case UNIPRO_DBG_MIB: + if (i == 0) + ufs_lld_dme_set(hba, UIC_ARG_MIB(cfg->addr), + cfg->val); + break; + case PHY_PCS_RXTX: + ufs_lld_dme_set(hba, UIC_ARG_MIB_SEL(cfg->addr, i), + cfg->val); + break; + case UNIPRO_DBG_PRD: + if (i == 0) + ufs_lld_dme_set(hba, UIC_ARG_MIB(cfg->addr), + UNIPRO_MCLK_PERIOD(p)); + break; + case PHY_PCS_RX: + ufs_lld_dme_set(hba, UIC_ARG_MIB_SEL(cfg->addr, + RX_LANE_0+i), cfg->val); + break; + case PHY_PCS_TX: + ufs_lld_dme_set(hba, UIC_ARG_MIB_SEL(cfg->addr, + TX_LANE_0+i), cfg->val); + break; + case PHY_PCS_RX_PRD: + ufs_lld_dme_set(hba, UIC_ARG_MIB_SEL(cfg->addr, + RX_LANE_0+i), UNIPRO_MCLK_PERIOD(p)); + break; + + case PHY_PCS_TX_PRD: + ufs_lld_dme_set(hba, UIC_ARG_MIB_SEL(cfg->addr, + TX_LANE_0+i), UNIPRO_MCLK_PERIOD(p)); + break; + case PHY_PMA_COMN: + if (i == 0) + ufs_lld_pma_write(hba, cfg->val, + PHY_PMA_COMN_ADDR(cfg->addr)); + break; + case PHY_PMA_TRSV: + ufs_lld_pma_write(hba, cfg->val, + PHY_PMA_TRSV_ADDR(cfg->addr, i)); + break; + case PHY_PMA_TRSV_LANE1_SQ_OFF: + if (i == 1) + ufs_lld_pma_write(hba, cfg->val, + PHY_PMA_TRSV_ADDR(cfg->addr, i)); + break; + case UNIPRO_DBG_APB: + ufs_lld_unipro_write(hba, cfg->val, cfg->addr); + break; + case PHY_PLL_WAIT: + if (i == 0) { + if (ufs_cal_wait_pll_lock(hba, + cfg->addr, cfg->val) == + UFS_CAL_ERROR) + return UFS_CAL_TIMEOUT; + } + break; + case PHY_CDR_WAIT: + if (ufs_cal_wait_cdr_lock(hba, + cfg->addr, cfg->val, i) == + UFS_CAL_ERROR) + return UFS_CAL_TIMEOUT; + break; + case COMMON_WAIT: + if (i == 0) + ufs_lld_udelay(cfg->val); + break; + default: + break; + } + } + } + + return UFS_CAL_NO_ERROR; +} + +/* + * This is a recommendation from Samsung UFS device vendor. + * + * Activate time: host < device + * Hibern time: host > device + */ +static void ufs_cal_calib_hibern8_values(void *hba) +{ + u32 hw_cap_min_tactivate; + u32 peer_rx_min_actv_time_cap; + u32 max_rx_hibern8_time_cap; + + ufs_lld_dme_get(hba, UIC_ARG_MIB_SEL(0x8F, RX_LANE_0), + &hw_cap_min_tactivate); /* HW Capability of MIN_TACTIVATE */ + + ufs_lld_dme_get(hba, UIC_ARG_MIB(0x15A8), + &peer_rx_min_actv_time_cap); /* PA_TActivate */ + ufs_lld_dme_get(hba, UIC_ARG_MIB(0x15A7), + &max_rx_hibern8_time_cap); /* PA_Hibern8Time */ + + if (peer_rx_min_actv_time_cap >= hw_cap_min_tactivate) + ufs_lld_dme_peer_set(hba, UIC_ARG_MIB(0x15A8), + peer_rx_min_actv_time_cap + 1); + ufs_lld_dme_set(hba, UIC_ARG_MIB(0x15A7), max_rx_hibern8_time_cap + 1); +} + +ufs_cal_errno ufs_cal_post_h8_enter(struct ufs_cal_param *p) +{ + ufs_cal_errno ret = UFS_CAL_NO_ERROR; + + ret = ufs_cal_config_uic(p, post_h8_enter, p->pmd); + + return ret; +} + +ufs_cal_errno ufs_cal_pre_h8_exit(struct ufs_cal_param *p) +{ + ufs_cal_errno ret = UFS_CAL_NO_ERROR; + + ret = ufs_cal_config_uic(p, pre_h8_exit, p->pmd); + + return ret; +} + +/* + * This currently uses only SLOW_MODE and FAST_MODE. + * If you want others, you should modify this function. + */ +ufs_cal_errno ufs_cal_pre_pmc(struct ufs_cal_param *p) +{ + ufs_cal_errno ret = UFS_CAL_NO_ERROR; + struct ufs_cal_phy_cfg *cfg; + + if ((p->pmd->mode == SLOW_MODE) || (p->pmd->mode == SLOWAUTO_MODE)) + cfg = calib_of_pwm; + else if (p->pmd->hs_series == PA_HS_MODE_B) + cfg = calib_of_hs_rate_b; + else if (p->pmd->hs_series == PA_HS_MODE_A) + cfg = calib_of_hs_rate_a; + else + return UFS_CAL_INV_ARG; + + /* + * If a number of target lanes is 1 and a host's + * a number of available lanes is 2, + * you should turn off phy power of lane #1. + * + * This must be modified when a number of avaiable lanes + * would grow in the future. + */ + if ((p->available_lane == 2) && (p->target_lane == 1)) + ret = ufs_cal_config_uic(p, lane1_sq_off, NULL); + + ret = ufs_cal_config_uic(p, cfg, p->pmd); + + return ret; +} + +/* + * This currently uses only SLOW_MODE and FAST_MODE. + * If you want others, you should modify this function. + */ +ufs_cal_errno ufs_cal_post_pmc(struct ufs_cal_param *p) +{ + ufs_cal_errno ret = UFS_CAL_NO_ERROR; + struct ufs_cal_phy_cfg *cfg; + + if ((p->pmd->mode == SLOWAUTO_MODE) || (p->pmd->mode == SLOW_MODE)) + cfg = post_calib_of_pwm; + else if (p->pmd->hs_series == PA_HS_MODE_B) + cfg = post_calib_of_hs_rate_b; + else if (p->pmd->hs_series == PA_HS_MODE_A) + cfg = post_calib_of_hs_rate_a; + else + return UFS_CAL_INV_ARG; + + ret = ufs_cal_config_uic(p, cfg, p->pmd); + + return ret; +} + +ufs_cal_errno ufs_cal_post_link(struct ufs_cal_param *p) +{ + ufs_cal_errno ret = UFS_CAL_NO_ERROR; + + ufs_cal_calib_hibern8_values(p->host); + + ret = ufs_cal_config_uic(p, post_init_cfg, NULL); + + return ret; +} + +ufs_cal_errno ufs_cal_pre_link(struct ufs_cal_param *p) +{ + ufs_cal_errno ret = UFS_CAL_NO_ERROR; + + ret = ufs_cal_config_uic(p, init_cfg, NULL); + + return ret; +} + +ufs_cal_errno ufs_cal_init(struct ufs_cal_param *p, int idx) +{ + /* + * Return if innput index is greater than + * the maximum that cal supports + */ + if (idx >= NUM_OF_UFS_HOST) + return UFS_CAL_INV_ARG; + + ufs_cal[idx] = p; + + ufs_cal_lock_timeout = ufs_lld_calc_timeout(100); + + return UFS_CAL_NO_ERROR; +} diff --git a/drivers/scsi/ufs/ufs-cal-9810.h b/drivers/scsi/ufs/ufs-cal-9810.h new file mode 100644 index 000000000000..464545054a90 --- /dev/null +++ b/drivers/scsi/ufs/ufs-cal-9810.h @@ -0,0 +1,52 @@ +struct uic_pwr_mode { + u8 lane; + u8 gear; + u8 mode; + u8 hs_series; +}; + +struct ufs_cal_param { + void *host; /* Host adaptor */ + u8 available_lane; + u8 target_lane; + u32 mclk_rate; + u8 board; + struct uic_pwr_mode *pmd; +}; + +typedef enum { + UFS_CAL_NO_ERROR = 0, + UFS_CAL_TIMEOUT, + UFS_CAL_ERROR, + UFS_CAL_INV_ARG, +} ufs_cal_errno; + +enum { + __BRD_COMMON, + __BRD_UNIV, + __BRD_SMDK, +}; +#define BRD_COMMON (1U << __BRD_COMMON) +#define BRD_UNIV (1U << __BRD_UNIV) +#define BRD_SMDK (1U << __BRD_SMDK) + +/* UFS CAL interface */ +ufs_cal_errno ufs_cal_post_h8_enter(struct ufs_cal_param *p); +ufs_cal_errno ufs_cal_pre_h8_exit(struct ufs_cal_param *p); +ufs_cal_errno ufs_cal_post_pmc(struct ufs_cal_param *p); +ufs_cal_errno ufs_cal_pre_pmc(struct ufs_cal_param *p); +ufs_cal_errno ufs_cal_post_link(struct ufs_cal_param *p); +ufs_cal_errno ufs_cal_pre_link(struct ufs_cal_param *p); +ufs_cal_errno ufs_cal_init(struct ufs_cal_param *p, int idx); + +/* Adaptor for UFS CAL */ +void ufs_lld_dme_set(void *h, u32 addr, u32 val); +void ufs_lld_dme_get(void *h, u32 addr, u32 *val); +void ufs_lld_dme_peer_set(void *h, u32 addr, u32 val); +void ufs_lld_pma_write(void *h, u32 val, u32 addr); +u32 ufs_lld_pma_read(void *h, u32 addr); +void ufs_lld_unipro_write(void *h, u32 val, u32 addr); +void ufs_lld_udelay(u32 val); +void ufs_lld_usleep_delay(u32 min, u32 max); +unsigned long ufs_lld_get_time_count(unsigned long offset); +unsigned long ufs_lld_calc_timeout(const unsigned int ms); diff --git a/drivers/scsi/ufs/ufs-exynos-dbg.c b/drivers/scsi/ufs/ufs-exynos-dbg.c new file mode 100644 index 000000000000..c06e9e762a9b --- /dev/null +++ b/drivers/scsi/ufs/ufs-exynos-dbg.c @@ -0,0 +1,1193 @@ +/* + * UFS debugging functions for Exynos specific extensions + * + * Copyright (C) 2016 Samsung Electronics Co., Ltd. + * + * Authors: + * Kiwoong + */ + +#include +#include + +#include "ufshcd.h" +#include "unipro.h" +#include "mphy.h" +#include "ufs-exynos.h" + +#if !defined(CONFIG_SOC_EXYNOS7420) && !defined(CONFIG_SOC_EXYNOS8890) +/* + * This is a list for latest SoC. + */ +static struct exynos_ufs_sfr_log ufs_log_sfr[] = { + {"STD HCI SFR" , LOG_STD_HCI_SFR, 0}, + + {"INTERRUPT STATUS" , REG_INTERRUPT_STATUS, 0}, + {"INTERRUPT ENABLE" , REG_INTERRUPT_ENABLE, 0}, + {"CONTROLLER STATUS" , REG_CONTROLLER_STATUS, 0}, + {"CONTROLLER ENABLE" , REG_CONTROLLER_ENABLE, 0}, + {"UTP TRANSF REQ INT AGG CNTRL" , REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL, 0}, + {"UTP TRANSF REQ LIST BASE L" , REG_UTP_TRANSFER_REQ_LIST_BASE_L, 0}, + {"UTP TRANSF REQ LIST BASE H" , REG_UTP_TRANSFER_REQ_LIST_BASE_H, 0}, + {"UTP TRANSF REQ DOOR BELL" , REG_UTP_TRANSFER_REQ_DOOR_BELL, 0}, + {"UTP TRANSF REQ LIST CLEAR" , REG_UTP_TRANSFER_REQ_LIST_CLEAR, 0}, + {"UTP TRANSF REQ LIST RUN STOP" , REG_UTP_TRANSFER_REQ_LIST_RUN_STOP, 0}, + {"UTP TRANSF REQ LIST CNR" , REG_UTP_TRANSFER_REQ_LIST_CNR, 0}, + {"UTP TASK REQ LIST BASE L" , REG_UTP_TASK_REQ_LIST_BASE_L, 0}, + {"UTP TASK REQ LIST BASE H" , REG_UTP_TASK_REQ_LIST_BASE_H, 0}, + {"UTP TASK REQ DOOR BELL" , REG_UTP_TASK_REQ_DOOR_BELL, 0}, + {"UTP TASK REQ LIST CLEAR" , REG_UTP_TASK_REQ_LIST_CLEAR, 0}, + {"UTP TASK REQ LIST RUN STOP" , REG_UTP_TASK_REQ_LIST_RUN_STOP, 0}, + {"UIC COMMAND" , REG_UIC_COMMAND, 0}, + {"UIC COMMAND ARG1" , REG_UIC_COMMAND_ARG_1, 0}, + {"UIC COMMAND ARG2" , REG_UIC_COMMAND_ARG_2, 0}, + {"UIC COMMAND ARG3" , REG_UIC_COMMAND_ARG_3, 0}, + {"CCAP" , REG_CRYPTO_CAPABILITY, 0}, + + + {"VS HCI SFR" , LOG_VS_HCI_SFR, 0}, + + {"TXPRDT ENTRY SIZE" , HCI_TXPRDT_ENTRY_SIZE, 0}, + {"RXPRDT ENTRY SIZE" , HCI_RXPRDT_ENTRY_SIZE, 0}, + {"TO CNT DIV VAL" , HCI_TO_CNT_DIV_VAL, 0}, + {"1US TO CNT VAL" , HCI_1US_TO_CNT_VAL, 0}, + {"INVALID UPIU CTRL" , HCI_INVALID_UPIU_CTRL, 0}, + {"INVALID UPIU BADDR" , HCI_INVALID_UPIU_BADDR, 0}, + {"INVALID UPIU UBADDR" , HCI_INVALID_UPIU_UBADDR, 0}, + {"INVALID UTMR OFFSET ADDR" , HCI_INVALID_UTMR_OFFSET_ADDR, 0}, + {"INVALID UTR OFFSET ADDR" , HCI_INVALID_UTR_OFFSET_ADDR, 0}, + {"INVALID DIN OFFSET ADDR" , HCI_INVALID_DIN_OFFSET_ADDR, 0}, + {"VENDOR SPECIFIC IS" , HCI_VENDOR_SPECIFIC_IS, 0}, + {"VENDOR SPECIFIC IE" , HCI_VENDOR_SPECIFIC_IE, 0}, + {"UTRL NEXUS TYPE" , HCI_UTRL_NEXUS_TYPE, 0}, + {"UTMRL NEXUS TYPE" , HCI_UTMRL_NEXUS_TYPE, 0}, + {"SW RST" , HCI_SW_RST, 0}, + {"RX UPIU MATCH ERROR CODE" , HCI_RX_UPIU_MATCH_ERROR_CODE, 0}, + {"DATA REORDER" , HCI_DATA_REORDER, 0}, + {"AXIDMA RWDATA BURST LEN" , HCI_AXIDMA_RWDATA_BURST_LEN, 0}, + {"WRITE DMA CTRL" , HCI_WRITE_DMA_CTRL, 0}, + {"V2P1 CTRL" , HCI_UFSHCI_V2P1_CTRL, 0}, + {"CLKSTOP CTRL" , HCI_CLKSTOP_CTRL, 0}, + {"FORCE HCS" , HCI_FORCE_HCS, 0}, + {"FSM MONITOR" , HCI_FSM_MONITOR, 0}, + {"DMA0 MONITOR STATE" , HCI_DMA0_MONITOR_STATE, 0}, + {"DMA0 MONITOR CNT" , HCI_DMA0_MONITOR_CNT, 0}, + {"DMA1 MONITOR STATE" , HCI_DMA1_MONITOR_STATE, 0}, + {"DMA1 MONITOR CNT" , HCI_DMA1_MONITOR_CNT, 0}, + {"AXI DMA IF CTRL" , HCI_UFS_AXI_DMA_IF_CTRL, 0}, + {"UFS ACG DISABLE" , HCI_UFS_ACG_DISABLE, 0}, + {"MPHY REFCLK SEL" , HCI_MPHY_REFCLK_SEL, 0}, + {"SMU ABORT MATCH INFO" , HCI_SMU_ABORT_MATCH_INFO, 0}, + {"DBR DUPLICATION INFO" , HCI_DBR_DUPLICATION_INFO, 0}, + {"DBR TIMER CONFIG" , HCI_DBR_TIMER_CONFIG, 0}, + {"DBR TIMER ENABLE" , HCI_DBR_TIMER_ENABLE, 0}, + {"DBR TIMER STATUS" , HCI_DBR_TIMER_STATUS, 0}, + {"UTRL DBR 3 0 TIMER EXPIRED VALUE" , HCI_UTRL_DBR_3_0_TIMER_EXPIRED_VALUE, 0}, + {"UTRL DBR 7 4 TIMER EXPIRED VALUE" , HCI_UTRL_DBR_7_4_TIMER_EXPIRED_VALUE, 0}, + {"UTRL DBR 11 8 TIMER EXPIRED VALUE" , HCI_UTRL_DBR_11_8_TIMER_EXPIRED_VALUE, 0}, + {"UTRL DBR 15 12 TIMER EXPIRED VALUE" , HCI_UTRL_DBR_15_12_TIMER_EXPIRED_VALUE, 0}, + {"UTMRL DBR 3 0 TIMER EXPIRED VALUE" , HCI_UTMRL_DBR_3_0_TIMER_EXPIRED_VALUE, 0}, + + {"FMP SFR" , LOG_FMP_SFR, 0}, + + {"UFSPRCTRL" , UFSPRCTRL, 0}, + {"UFSPRSTAT" , UFSPRSTAT, 0}, + {"UFSPRSECURITY" , UFSPRSECURITY, 0}, + {"UFSPWCTRL" , UFSPWCTRL, 0}, + {"UFSPWSTAT" , UFSPWSTAT, 0}, + {"UFSPSBEGIN0" , UFSPSBEGIN0, 0}, + {"UFSPSEND0" , UFSPSEND0, 0}, + {"UFSPSLUN0" , UFSPSLUN0, 0}, + {"UFSPSCTRL0" , UFSPSCTRL0, 0}, + {"UFSPSBEGIN1" , UFSPSBEGIN1, 0}, + {"UFSPSEND1" , UFSPSEND1, 0}, + {"UFSPSLUN1" , UFSPSLUN1, 0}, + {"UFSPSCTRL1" , UFSPSCTRL1, 0}, + {"UFSPSBEGIN2" , UFSPSBEGIN2, 0}, + {"UFSPSEND2" , UFSPSEND2, 0}, + {"UFSPSLUN2" , UFSPSLUN2, 0}, + {"UFSPSCTRL2" , UFSPSCTRL2, 0}, + {"UFSPSBEGIN3" , UFSPSBEGIN3, 0}, + {"UFSPSEND3" , UFSPSEND3, 0}, + {"UFSPSLUN3" , UFSPSLUN3, 0}, + {"UFSPSCTRL3" , UFSPSCTRL3, 0}, + {"UFSPSBEGIN4" , UFSPSBEGIN4, 0}, + {"UFSPSLUN4" , UFSPSLUN4, 0}, + {"UFSPSCTRL4" , UFSPSCTRL4, 0}, + {"UFSPSBEGIN5" , UFSPSBEGIN5, 0}, + {"UFSPSEND5" , UFSPSEND5, 0}, + {"UFSPSLUN5" , UFSPSLUN5, 0}, + {"UFSPSCTRL5" , UFSPSCTRL5, 0}, + {"UFSPSBEGIN6" , UFSPSBEGIN6, 0}, + {"UFSPSEND6" , UFSPSEND6, 0}, + {"UFSPSLUN6" , UFSPSLUN6, 0}, + {"UFSPSCTRL6" , UFSPSCTRL6, 0}, + {"UFSPSBEGIN7" , UFSPSBEGIN7, 0}, + {"UFSPSEND7" , UFSPSEND7, 0}, + {"UFSPSLUN7" , UFSPSLUN7, 0}, + {"UFSPSCTRL7" , UFSPSCTRL7, 0}, + + {"UNIPRO SFR" , LOG_UNIPRO_SFR, 0}, + + {"DME_LINKSTARTUP_CNF_RESULT" , UNIP_DME_LINKSTARTUP_CNF_RESULT , 0}, + {"DME_HIBERN8_ENTER_CNF_RESULT" , UNIP_DME_HIBERN8_ENTER_CNF_RESULT, 0}, + {"DME_HIBERN8_ENTER_IND_RESULT" , UNIP_DME_HIBERN8_ENTER_IND_RESULT, 0}, + {"DME_HIBERN8_EXIT_CNF_RESULT" , UNIP_DME_HIBERN8_EXIT_CNF_RESULT, 0}, + {"DME_HIBERN8_EXIT_IND_RESULT" , UNIP_DME_HIBERN8_EXIT_IND_RESULT, 0}, + {"DME_PWR_IND_RESULT" , UNIP_DME_PWR_IND_RESULT , 0}, + {"DME_INTR_STATUS_LSB" , UNIP_DME_INTR_STATUS_LSB, 0}, + {"DME_INTR_STATUS_MSB" , UNIP_DME_INTR_STATUS_MSB, 0}, + {"DME_INTR_ERROR_CODE" , UNIP_DME_INTR_ERROR_CODE, 0}, + {"DME_DISCARD_PORT_ID" , UNIP_DME_DISCARD_PORT_ID, 0}, + {"DME_DBG_OPTION_SUITE" , UNIP_DME_DBG_OPTION_SUITE, 0}, + {"DME_DBG_CTRL_FSM" , UNIP_DME_DBG_CTRL_FSM, 0}, + {"DME_DBG_FLAG_STATUS" , UNIP_DME_DBG_FLAG_STATUS, 0}, + {"DME_DBG_LINKCFG_FSM" , UNIP_DME_DBG_LINKCFG_FSM, 0}, + + {"PMA SFR" , LOG_PMA_SFR, 0}, + + {"COMN 0x2f" , (0x00BC), 0}, + {"TRSV_L0 0x4b" , (0x01EC), 0}, + {"TRSV_L0 0x4f" , (0x01FC), 0}, + {"TRSV_L1 0x4b" , (0x032C), 0}, + {"TRSV_L1 0x4f" , (0x033C), 0}, + + {}, +}; + +static struct exynos_ufs_attr_log ufs_log_attr[] = { + /* PA Standard */ + {UIC_ARG_MIB(0x1520), 0, 0}, + {UIC_ARG_MIB(0x1540), 0, 0}, + {UIC_ARG_MIB(0x1543), 0, 0}, + {UIC_ARG_MIB(0x155C), 0, 0}, + {UIC_ARG_MIB(0x155D), 0, 0}, + {UIC_ARG_MIB(0x155E), 0, 0}, + {UIC_ARG_MIB(0x155F), 0, 0}, + {UIC_ARG_MIB(0x1560), 0, 0}, + {UIC_ARG_MIB(0x1561), 0, 0}, + {UIC_ARG_MIB(0x1564), 0, 0}, + {UIC_ARG_MIB(0x1567), 0, 0}, + {UIC_ARG_MIB(0x1568), 0, 0}, + {UIC_ARG_MIB(0x1569), 0, 0}, + {UIC_ARG_MIB(0x156A), 0, 0}, + {UIC_ARG_MIB(0x1571), 0, 0}, + {UIC_ARG_MIB(0x1580), 0, 0}, + {UIC_ARG_MIB(0x1581), 0, 0}, + {UIC_ARG_MIB(0x1582), 0, 0}, + {UIC_ARG_MIB(0x1583), 0, 0}, + {UIC_ARG_MIB(0x1584), 0, 0}, + {UIC_ARG_MIB(0x1585), 0, 0}, + {UIC_ARG_MIB(0x1590), 0, 0}, + {UIC_ARG_MIB(0x1591), 0, 0}, + {UIC_ARG_MIB(0x15A1), 0, 0}, + {UIC_ARG_MIB(0x15A2), 0, 0}, + {UIC_ARG_MIB(0x15A3), 0, 0}, + {UIC_ARG_MIB(0x15A4), 0, 0}, + {UIC_ARG_MIB(0x15A7), 0, 0}, + {UIC_ARG_MIB(0x15A8), 0, 0}, + {UIC_ARG_MIB(0x15C0), 0, 0}, + {UIC_ARG_MIB(0x15C1), 0, 0}, + /* PA Debug */ + {UIC_ARG_MIB(0x9514), 0, 0}, + {UIC_ARG_MIB(0x9536), 0, 0}, + {UIC_ARG_MIB(0x9556), 0, 0}, + {UIC_ARG_MIB(0x9564), 0, 0}, + {UIC_ARG_MIB(0x9566), 0, 0}, + {UIC_ARG_MIB(0x9567), 0, 0}, + {UIC_ARG_MIB(0x9568), 0, 0}, + {UIC_ARG_MIB(0x956A), 0, 0}, + {UIC_ARG_MIB(0x9595), 0, 0}, + {UIC_ARG_MIB(0x9596), 0, 0}, + {UIC_ARG_MIB(0x9597), 0, 0}, + /* DL Standard */ + {UIC_ARG_MIB(0x2046), 0, 0}, + {UIC_ARG_MIB(0x2047), 0, 0}, + {UIC_ARG_MIB(0x2066), 0, 0}, + {UIC_ARG_MIB(0x2067), 0, 0}, + /* DL Debug */ + {UIC_ARG_MIB(0xA000), 0, 0}, + {UIC_ARG_MIB(0xA005), 0, 0}, + {UIC_ARG_MIB(0xA007), 0, 0}, + {UIC_ARG_MIB(0xA010), 0, 0}, + {UIC_ARG_MIB(0xA011), 0, 0}, + {UIC_ARG_MIB(0xA020), 0, 0}, + {UIC_ARG_MIB(0xA021), 0, 0}, + {UIC_ARG_MIB(0xA022), 0, 0}, + {UIC_ARG_MIB(0xA023), 0, 0}, + {UIC_ARG_MIB(0xA024), 0, 0}, + {UIC_ARG_MIB(0xA025), 0, 0}, + {UIC_ARG_MIB(0xA026), 0, 0}, + {UIC_ARG_MIB(0xA027), 0, 0}, + {UIC_ARG_MIB(0xA028), 0, 0}, + {UIC_ARG_MIB(0xA029), 0, 0}, + {UIC_ARG_MIB(0xA02A), 0, 0}, + {UIC_ARG_MIB(0xA02B), 0, 0}, + {UIC_ARG_MIB(0xA100), 0, 0}, + {UIC_ARG_MIB(0xA101), 0, 0}, + {UIC_ARG_MIB(0xA102), 0, 0}, + {UIC_ARG_MIB(0xA103), 0, 0}, + {UIC_ARG_MIB(0xA114), 0, 0}, + {UIC_ARG_MIB(0xA115), 0, 0}, + {UIC_ARG_MIB(0xA116), 0, 0}, + {UIC_ARG_MIB(0xA120), 0, 0}, + {UIC_ARG_MIB(0xA121), 0, 0}, + {UIC_ARG_MIB(0xA122), 0, 0}, + /* NL Standard */ + {UIC_ARG_MIB(0x3000), 0, 0}, + {UIC_ARG_MIB(0x3001), 0, 0}, + /* NL Debug */ + {UIC_ARG_MIB(0xB010), 0, 0}, + {UIC_ARG_MIB(0xB011), 0, 0}, + /* TL Standard */ + {UIC_ARG_MIB(0x4020), 0, 0}, + {UIC_ARG_MIB(0x4021), 0, 0}, + {UIC_ARG_MIB(0x4022), 0, 0}, + {UIC_ARG_MIB(0x4023), 0, 0}, + {UIC_ARG_MIB(0x4025), 0, 0}, + {UIC_ARG_MIB(0x402B), 0, 0}, + /* TL Debug */ + {UIC_ARG_MIB(0xC001), 0, 0}, + {UIC_ARG_MIB(0xC024), 0, 0}, + {UIC_ARG_MIB(0xC025), 0, 0}, + {UIC_ARG_MIB(0xC026), 0, 0}, + /* MPHY PCS Lane 0*/ + {UIC_ARG_MIB_SEL(0x0021, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0022, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0023, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0024, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0028, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0029, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002A, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002B, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002C, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002D, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0033, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0035, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0036, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0041, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A1, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A2, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A3, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A4, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A7, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00C1, RX_LANE_0+0), 0, 0}, + /* MPHY PCS Lane 1*/ + {UIC_ARG_MIB_SEL(0x0021, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0022, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0023, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0024, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0028, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0029, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002A, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002B, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002C, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002D, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0033, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0035, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0036, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0041, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A1, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A2, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A3, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A4, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A7, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00C1, RX_LANE_0+1), 0, 0}, + {}, +}; + +static struct exynos_ufs_sfr_log ufs_show_sfr[] = { + {"STD HCI SFR" , LOG_STD_HCI_SFR, 0}, + + {"INTERRUPT STATUS" , REG_INTERRUPT_STATUS, 0}, + {"CONTROLLER STATUS" , REG_CONTROLLER_STATUS, 0}, + {"UTP TRANSF REQ DOOR BELL" , REG_UTP_TRANSFER_REQ_DOOR_BELL, 0}, + {"UTP TASK REQ DOOR BELL" , REG_UTP_TASK_REQ_DOOR_BELL, 0}, + + {"VS HCI SFR" , LOG_VS_HCI_SFR, 0}, + + {"VENDOR SPECIFIC IS" , HCI_VENDOR_SPECIFIC_IS, 0}, + {"RX UPIU MATCH ERROR CODE" , HCI_RX_UPIU_MATCH_ERROR_CODE, 0}, + {"CLKSTOP CTRL", HCI_CLKSTOP_CTRL, 0}, + {"FORCE HCS", HCI_FORCE_HCS, 0}, + {"DMA0 MONITOR STATE" , HCI_DMA0_MONITOR_STATE, 0}, + {"DMA1 MONITOR STATE" , HCI_DMA1_MONITOR_STATE, 0}, + {"SMU ABORT MATCH INFO" , HCI_SMU_ABORT_MATCH_INFO, 0}, + + {"FMP SFR" , LOG_FMP_SFR, 0}, + + {"UFSPRSECURITY" , UFSPRSECURITY, 0}, + + + {"UNIPRO SFR" , LOG_UNIPRO_SFR, 0}, + + {"DME_HIBERN8_ENTER_IND_RESULT" , UNIP_DME_HIBERN8_ENTER_IND_RESULT , 0}, + {"DME_HIBERN8_EXIT_IND_RESULT" , UNIP_DME_HIBERN8_EXIT_IND_RESULT , 0}, + {"DME_PWR_IND_RESULT" , UNIP_DME_PWR_IND_RESULT , 0}, + {"DME_DBG_CTRL_FSM" , UNIP_DME_DBG_CTRL_FSM , 0}, + + {"PMA SFR" , LOG_PMA_SFR, 0}, + + {"COMN 0x2f" , (0x00BC), 0}, + {"TRSV_L0 0x4b" , (0x01EC), 0}, + {"TRSV_L0 0x4f" , (0x01FC), 0}, + {"TRSV_L1 0x4b" , (0x032C), 0}, + {"TRSV_L1 0x4f" , (0x033C), 0}, + {}, +}; + +static struct exynos_ufs_attr_log ufs_show_attr[] = { + /* PA Standard */ + {UIC_ARG_MIB(0x1560), 0, 0}, + {UIC_ARG_MIB(0x1571), 0, 0}, + {UIC_ARG_MIB(0x1580), 0, 0}, + /* PA Debug */ + {UIC_ARG_MIB(0x9595), 0, 0}, + {UIC_ARG_MIB(0x9597), 0, 0}, + /* DL Debug */ + {UIC_ARG_MIB(0xA000), 0, 0}, + {UIC_ARG_MIB(0xA005), 0, 0}, + {UIC_ARG_MIB(0xA010), 0, 0}, + {UIC_ARG_MIB(0xA114), 0, 0}, + {UIC_ARG_MIB(0xA116), 0, 0}, + /* MPHY PCS Lane 0*/ + {UIC_ARG_MIB_SEL(0x0021, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0022, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0023, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0024, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0028, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0029, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002A, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002B, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002C, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x002D, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0033, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0035, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0036, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x0041, TX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A1, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A2, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A3, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A4, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A7, RX_LANE_0+0), 0, 0}, + {UIC_ARG_MIB_SEL(0x00C1, RX_LANE_0+0), 0, 0}, + /* MPHY PCS Lane 1*/ + {UIC_ARG_MIB_SEL(0x0021, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0022, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0023, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0024, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0028, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0029, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002A, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002B, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002C, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x002D, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0033, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0035, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0036, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x0041, TX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A1, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A2, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A3, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A4, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00A7, RX_LANE_0+1), 0, 0}, + {UIC_ARG_MIB_SEL(0x00C1, RX_LANE_0+1), 0, 0}, + {}, +}; +#else +static struct exynos_ufs_sfr_log ufs_log_sfr[] = { + {"STD HCI SFR" , LOG_STD_HCI_SFR, 0}, + + {"CAPABILITIES" , REG_CONTROLLER_CAPABILITIES, 0}, + {"UFS VERSION" , REG_UFS_VERSION, 0}, + {"PRODUCT ID" , REG_CONTROLLER_DEV_ID, 0}, + {"MANUFACTURE ID" , REG_CONTROLLER_PROD_ID, 0}, + {"INTERRUPT STATUS" , REG_INTERRUPT_STATUS, 0}, + {"INTERRUPT ENABLE" , REG_INTERRUPT_ENABLE, 0}, + {"CONTROLLER STATUS" , REG_CONTROLLER_STATUS, 0}, + {"CONTROLLER ENABLE" , REG_CONTROLLER_ENABLE, 0}, + {"UTP TRANSF REQ INT AGG CNTRL" , REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL, 0}, + {"UTP TRANSF REQ LIST BASE L" , REG_UTP_TRANSFER_REQ_LIST_BASE_L, 0}, + {"UTP TRANSF REQ LIST BASE H" , REG_UTP_TRANSFER_REQ_LIST_BASE_H, 0}, + {"UTP TRANSF REQ DOOR BELL" , REG_UTP_TRANSFER_REQ_DOOR_BELL, 0}, + {"UTP TRANSF REQ LIST CLEAR" , REG_UTP_TRANSFER_REQ_LIST_CLEAR, 0}, + {"UTP TRANSF REQ LIST RUN STOP" , REG_UTP_TRANSFER_REQ_LIST_RUN_STOP, 0}, + {"UTP TASK REQ LIST BASE L" , REG_UTP_TASK_REQ_LIST_BASE_L, 0}, + {"UTP TASK REQ LIST BASE H" , REG_UTP_TASK_REQ_LIST_BASE_H, 0}, + {"UTP TASK REQ DOOR BELL" , REG_UTP_TASK_REQ_DOOR_BELL, 0}, + {"UTP TASK REQ LIST CLEAR" , REG_UTP_TASK_REQ_LIST_CLEAR, 0}, + {"UTP TASK REQ LIST RUN STOP" , REG_UTP_TASK_REQ_LIST_RUN_STOP, 0}, + {"UIC COMMAND" , REG_UIC_COMMAND, 0}, + {"UIC COMMAND ARG1" , REG_UIC_COMMAND_ARG_1, 0}, + {"UIC COMMAND ARG2" , REG_UIC_COMMAND_ARG_2, 0}, + {"UIC COMMAND ARG3" , REG_UIC_COMMAND_ARG_3, 0}, + + {"VS HCI SFR" , LOG_VS_HCI_SFR, 0}, + + {"TXPRDT ENTRY SIZE" , HCI_TXPRDT_ENTRY_SIZE, 0}, + {"RXPRDT ENTRY SIZE" , HCI_RXPRDT_ENTRY_SIZE, 0}, + {"TO CNT DIV VAL" , HCI_TO_CNT_DIV_VAL, 0}, + {"1US TO CNT VAL" , HCI_1US_TO_CNT_VAL, 0}, + {"INVALID UPIU CTRL" , HCI_INVALID_UPIU_CTRL, 0}, + {"INVALID UPIU BADDR" , HCI_INVALID_UPIU_BADDR, 0}, + {"INVALID UPIU UBADDR" , HCI_INVALID_UPIU_UBADDR, 0}, + {"INVALID UTMR OFFSET ADDR" , HCI_INVALID_UTMR_OFFSET_ADDR, 0}, + {"INVALID UTR OFFSET ADDR" , HCI_INVALID_UTR_OFFSET_ADDR, 0}, + {"INVALID DIN OFFSET ADDR" , HCI_INVALID_DIN_OFFSET_ADDR, 0}, + {"DBR TIMER CONFIG" , HCI_DBR_TIMER_CONFIG, 0}, + {"DBR TIMER STATUS" , HCI_DBR_TIMER_STATUS, 0}, + {"VENDOR SPECIFIC IS" , HCI_VENDOR_SPECIFIC_IS, 0}, + {"VENDOR SPECIFIC IE" , HCI_VENDOR_SPECIFIC_IE, 0}, + {"UTRL NEXUS TYPE" , HCI_UTRL_NEXUS_TYPE, 0}, + {"UTMRL NEXUS TYPE" , HCI_UTMRL_NEXUS_TYPE, 0}, + {"E2EFC CTRL" , HCI_E2EFC_CTRL, 0}, + {"SW RST" , HCI_SW_RST, 0}, + {"LINK VERSION" , HCI_LINK_VERSION, 0}, + {"IDLE TIMER CONFIG" , HCI_IDLE_TIMER_CONFIG, 0}, + {"RX UPIU MATCH ERROR CODE" , HCI_RX_UPIU_MATCH_ERROR_CODE, 0}, + {"DATA REORDER" , HCI_DATA_REORDER, 0}, + {"MAX DOUT DATA SIZE" , HCI_MAX_DOUT_DATA_SIZE, 0}, + {"UNIPRO APB CLK CTRL" , HCI_UNIPRO_APB_CLK_CTRL, 0}, + {"AXIDMA RWDATA BURST LEN" , HCI_AXIDMA_RWDATA_BURST_LEN, 0}, + {"GPIO OUT" , HCI_GPIO_OUT, 0}, + {"WRITE DMA CTRL" , HCI_WRITE_DMA_CTRL, 0}, + {"ERROR EN PA LAYER" , HCI_ERROR_EN_PA_LAYER, 0}, + {"ERROR EN DL LAYER" , HCI_ERROR_EN_DL_LAYER, 0}, + {"ERROR EN N LAYER" , HCI_ERROR_EN_N_LAYER, 0}, + {"ERROR EN T LAYER" , HCI_ERROR_EN_T_LAYER, 0}, + {"ERROR EN DME LAYER" , HCI_ERROR_EN_DME_LAYER, 0}, + {"REQ HOLD EN" , HCI_REQ_HOLD_EN, 0}, + {"CLKSTOP CTRL" , HCI_CLKSTOP_CTRL, 0}, + {"FORCE HCS" , HCI_FORCE_HCS, 0}, + {"FSM MONITOR" , HCI_FSM_MONITOR, 0}, + {"PRDT HIT RATIO" , HCI_PRDT_HIT_RATIO, 0}, + {"DMA0 MONITOR STATE" , HCI_DMA0_MONITOR_STATE, 0}, + {"DMA0 MONITOR CNT" , HCI_DMA0_MONITOR_CNT, 0}, + {"DMA1 MONITOR STATE" , HCI_DMA1_MONITOR_STATE, 0}, + {"DMA1 MONITOR CNT" , HCI_DMA1_MONITOR_CNT, 0}, + + {"FMP SFR" , LOG_FMP_SFR, 0}, + + {"UFSPRCTRL" , UFSPRCTRL, 0}, + {"UFSPRSTAT" , UFSPRSTAT, 0}, + {"UFSPRSECURITY" , UFSPRSECURITY, 0}, + {"UFSPVERSION" , UFSPVERSION, 0}, + {"UFSPWCTRL" , UFSPWCTRL, 0}, + {"UFSPWSTAT" , UFSPWSTAT, 0}, + {"UFSPSBEGIN0" , UFSPSBEGIN0, 0}, + {"UFSPSEND0" , UFSPSEND0, 0}, + {"UFSPSLUN0" , UFSPSLUN0, 0}, + {"UFSPSCTRL0" , UFSPSCTRL0, 0}, + {"UFSPSBEGIN1" , UFSPSBEGIN1, 0}, + {"UFSPSEND1" , UFSPSEND1, 0}, + {"UFSPSLUN1" , UFSPSLUN1, 0}, + {"UFSPSCTRL1" , UFSPSCTRL1, 0}, + {"UFSPSBEGIN2" , UFSPSBEGIN2, 0}, + {"UFSPSEND2" , UFSPSEND2, 0}, + {"UFSPSLUN2" , UFSPSLUN2, 0}, + {"UFSPSCTRL2" , UFSPSCTRL2, 0}, + {"UFSPSBEGIN3" , UFSPSBEGIN3, 0}, + {"UFSPSEND3" , UFSPSEND3, 0}, + {"UFSPSLUN3" , UFSPSLUN3, 0}, + {"UFSPSCTRL3" , UFSPSCTRL3, 0}, + {"UFSPSBEGIN4" , UFSPSBEGIN4, 0}, + {"UFSPSLUN4" , UFSPSLUN4, 0}, + {"UFSPSCTRL4" , UFSPSCTRL4, 0}, + {"UFSPSBEGIN5" , UFSPSBEGIN5, 0}, + {"UFSPSEND5" , UFSPSEND5, 0}, + {"UFSPSLUN5" , UFSPSLUN5, 0}, + {"UFSPSCTRL5" , UFSPSCTRL5, 0}, + {"UFSPSBEGIN6" , UFSPSBEGIN6, 0}, + {"UFSPSEND6" , UFSPSEND6, 0}, + {"UFSPSLUN6" , UFSPSLUN6, 0}, + {"UFSPSCTRL6" , UFSPSCTRL6, 0}, + {"UFSPSBEGIN7" , UFSPSBEGIN7, 0}, + {"UFSPSEND7" , UFSPSEND7, 0}, + {"UFSPSLUN7" , UFSPSLUN7, 0}, + {"UFSPSCTRL7" , UFSPSCTRL7, 0}, + + {"UNIPRO SFR" , LOG_UNIPRO_SFR, 0}, + + {"COMP_VERSION" , UNIP_COMP_VERSION , 0}, + {"COMP_INFO" , UNIP_COMP_INFO , 0}, + {"COMP_RESET" , UNIP_COMP_RESET , 0}, + {"DME_POWERON_REQ" , UNIP_DME_POWERON_REQ , 0}, + {"DME_POWERON_CNF_RESULT" , UNIP_DME_POWERON_CNF_RESULT , 0}, + {"DME_POWEROFF_REQ" , UNIP_DME_POWEROFF_REQ , 0}, + {"DME_POWEROFF_CNF_RESULT" , UNIP_DME_POWEROFF_CNF_RESULT , 0}, + {"DME_RESET_REQ" , UNIP_DME_RESET_REQ , 0}, + {"DME_RESET_REQ_LEVEL" , UNIP_DME_RESET_REQ_LEVEL , 0}, + {"DME_ENABLE_REQ" , UNIP_DME_ENABLE_REQ , 0}, + {"DME_ENABLE_CNF_RESULT" , UNIP_DME_ENABLE_CNF_RESULT , 0}, + {"DME_ENDPOINTRESET_REQ" , UNIP_DME_ENDPOINTRESET_REQ , 0}, + {"DME_ENDPOINTRESET_CNF_RESULT" , UNIP_DME_ENDPOINTRESET_CNF_RESULT , 0}, + {"DME_LINKSTARTUP_REQ" , UNIP_DME_LINKSTARTUP_REQ , 0}, + {"DME_LINKSTARTUP_CNF_RESULT" , UNIP_DME_LINKSTARTUP_CNF_RESULT , 0}, + {"DME_HIBERN8_ENTER_REQ" , UNIP_DME_HIBERN8_ENTER_REQ , 0}, + {"DME_HIBERN8_ENTER_CNF_RESULT" , UNIP_DME_HIBERN8_ENTER_CNF_RESULT , 0}, + {"DME_HIBERN8_ENTER_IND_RESULT" , UNIP_DME_HIBERN8_ENTER_IND_RESULT , 0}, + {"DME_HIBERN8_EXIT_REQ" , UNIP_DME_HIBERN8_EXIT_REQ , 0}, + {"DME_HIBERN8_EXIT_CNF_RESULT" , UNIP_DME_HIBERN8_EXIT_CNF_RESULT , 0}, + {"DME_HIBERN8_EXIT_IND_RESULT" , UNIP_DME_HIBERN8_EXIT_IND_RESULT , 0}, + {"DME_PWR_REQ" , UNIP_DME_PWR_REQ , 0}, + {"DME_PWR_REQ_POWERMODE " , UNIP_DME_PWR_REQ_POWERMODE , 0}, + {"DME_PWR_REQ_LOCALL2TIMER0" , UNIP_DME_PWR_REQ_LOCALL2TIMER0 , 0}, + {"DME_PWR_REQ_LOCALL2TIMER1" , UNIP_DME_PWR_REQ_LOCALL2TIMER1 , 0}, + {"DME_PWR_REQ_LOCALL2TIMER2" , UNIP_DME_PWR_REQ_LOCALL2TIMER2 , 0}, + {"DME_PWR_REQ_REMOTEL2TIMER0" , UNIP_DME_PWR_REQ_REMOTEL2TIMER0 , 0}, + {"DME_PWR_REQ_REMOTEL2TIMER1" , UNIP_DME_PWR_REQ_REMOTEL2TIMER1 , 0}, + {"DME_PWR_REQ_REMOTEL2TIMER2" , UNIP_DME_PWR_REQ_REMOTEL2TIMER2 , 0}, + {"DME_PWR_CNF_RESULT" , UNIP_DME_PWR_CNF_RESULT , 0}, + {"DME_PWR_IND_RESULT" , UNIP_DME_PWR_IND_RESULT , 0}, + {"DME_TEST_MODE_REQ" , UNIP_DME_TEST_MODE_REQ , 0}, + {"DME_TEST_MODE_CNF_RESULT" , UNIP_DME_TEST_MODE_CNF_RESULT , 0}, + {"DME_ERROR_IND_LAYER" , UNIP_DME_ERROR_IND_LAYER , 0}, + {"DME_ERROR_IND_ERRCODE" , UNIP_DME_ERROR_IND_ERRCODE , 0}, + {"DME_PACP_CNFBIT" , UNIP_DME_PACP_CNFBIT , 0}, + {"DME_DL_FRAME_IND" , UNIP_DME_DL_FRAME_IND , 0}, + {"DME_INTR_STATUS" , UNIP_DME_INTR_STATUS , 0}, + {"DME_INTR_ENABLE" , UNIP_DME_INTR_ENABLE , 0}, + {"DME_GETSET_ADDR" , UNIP_DME_GETSET_ADDR , 0}, + {"DME_GETSET_WDATA" , UNIP_DME_GETSET_WDATA , 0}, + {"DME_GETSET_RDATA" , UNIP_DME_GETSET_RDATA , 0}, + {"DME_GETSET_CONTROL" , UNIP_DME_GETSET_CONTROL , 0}, + {"DME_GETSET_RESULT" , UNIP_DME_GETSET_RESULT , 0}, + {"DME_PEER_GETSET_ADDR" , UNIP_DME_PEER_GETSET_ADDR , 0}, + {"DME_PEER_GETSET_WDATA" , UNIP_DME_PEER_GETSET_WDATA , 0}, + {"DME_PEER_GETSET_RDATA" , UNIP_DME_PEER_GETSET_RDATA , 0}, + {"DME_PEER_GETSET_CONTROL" , UNIP_DME_PEER_GETSET_CONTROL , 0}, + {"DME_PEER_GETSET_RESULT" , UNIP_DME_PEER_GETSET_RESULT , 0}, + {"DME_DIRECT_GETSET_BASE" , UNIP_DME_DIRECT_GETSET_BASE , 0}, + {"DME_DIRECT_GETSET_ERR_ADDR" , UNIP_DME_DIRECT_GETSET_ERR_ADDR , 0}, + {"DME_DIRECT_GETSET_ERR_CODE" , UNIP_DME_DIRECT_GETSET_ERR_CODE , 0}, + {"DME_INTR_ERROR_CODE" , UNIP_DME_INTR_ERROR_CODE , 0}, + {"DME_DEEPSTALL_ENTER_REQ" , UNIP_DME_DEEPSTALL_ENTER_REQ , 0}, + {"DME_DISCARD_CPORT_ID" , UNIP_DME_DISCARD_CPORT_ID , 0}, + {"DBG_DME_CTRL_STATE" , UNIP_DBG_DME_CTRL_STATE , 0}, + {"DBG_FORCE_DME_CTRL_STATE" , UNIP_DBG_FORCE_DME_CTRL_STATE , 0}, + {"DBG_AUTO_DME_LINKSTARTUP" , UNIP_DBG_AUTO_DME_LINKSTARTUP, 0}, + {"DBG_PA_CTRLSTATE" , UNIP_DBG_PA_CTRLSTATE , 0}, + {"DBG_PA_TX_STATE" , UNIP_DBG_PA_TX_STATE , 0}, + {"DBG_BREAK_DME_CTRL_STATE" , UNIP_DBG_BREAK_DME_CTRL_STATE , 0}, + {"DBG_STEP_DME_CTRL_STATE" , UNIP_DBG_STEP_DME_CTRL_STATE , 0}, + {"DBG_NEXT_DME_CTRL_STATE" , UNIP_DBG_NEXT_DME_CTRL_STATE , 0}, + + {"PMA SFR" , LOG_PMA_SFR, 0}, + + {"COMN 0x00" , (0x00<<2), 0}, + {"COMN 0x01" , (0x01<<2), 0}, + {"COMN 0x02" , (0x02<<2), 0}, + {"COMN 0x03" , (0x03<<2), 0}, + {"COMN 0x04" , (0x04<<2), 0}, + {"COMN 0x05" , (0x05<<2), 0}, + {"COMN 0x06" , (0x06<<2), 0}, + {"COMN 0x07" , (0x07<<2), 0}, + {"COMN 0x08" , (0x08<<2), 0}, + {"COMN 0x0a" , (0x0a<<2), 0}, + {"COMN 0x0b" , (0x0b<<2), 0}, + {"COMN 0x0c" , (0x0c<<2), 0}, + {"COMN 0x0d" , (0x0d<<2), 0}, + {"COMN 0x0e" , (0x0e<<2), 0}, + {"COMN 0x0f" , (0x0f<<2), 0}, + {"COMN 0x10" , (0x10<<2), 0}, + {"COMN 0x11" , (0x11<<2), 0}, + {"COMN 0x12" , (0x12<<2), 0}, + {"COMN 0x13" , (0x13<<2), 0}, + {"COMN 0x14" , (0x14<<2), 0}, + {"COMN 0x15" , (0x15<<2), 0}, + {"COMN 0x16" , (0x16<<2), 0}, + {"COMN 0x17" , (0x17<<2), 0}, + {"COMN 0x18" , (0x18<<2), 0}, + {"COMN 0x19" , (0x19<<2), 0}, + {"COMN 0x1a" , (0x1a<<2), 0}, + {"COMN 0x1b" , (0x1b<<2), 0}, + {"COMN 0x1c" , (0x1c<<2), 0}, + {"COMN 0x1d" , (0x1d<<2), 0}, + {"COMN 0x1e" , (0x1e<<2), 0}, + {"COMN 0x1f" , (0x1f<<2), 0}, + {"COMN 0x20" , (0x20<<2), 0}, + {"COMN 0x21" , (0x21<<2), 0}, + {"COMN 0x22" , (0x22<<2), 0}, + {"COMN 0x23" , (0x23<<2), 0}, + {"COMN 0x24" , (0x24<<2), 0}, + {"COMN 0x25" , (0x25<<2), 0}, + {"COMN 0x26" , (0x26<<2), 0}, + {"COMN 0x27" , (0x27<<2), 0}, + {"COMN 0x28" , (0x28<<2), 0}, + {"COMN 0x29" , (0x29<<2), 0}, + {"COMN 0x2a" , (0x2a<<2), 0}, + {"COMN 0x2b" , (0x2b<<2), 0}, + {"COMN 0x2c" , (0x2c<<2), 0}, + {"COMN 0x2d" , (0x2d<<2), 0}, + {"COMN 0x2e" , (0x2e<<2), 0}, + {"COMN 0x2f" , (0x2f<<2), 0}, + {"COMN 0x30" , (0x30<<2), 0}, + {"TRSV 0x31" , (0x31<<2), 0}, + {"TRSV 0x32" , (0x32<<2), 0}, + {"TRSV 0x33" , (0x33<<2), 0}, + {"TRSV 0x34" , (0x34<<2), 0}, + {"TRSV 0x35" , (0x35<<2), 0}, + {"TRSV 0x36" , (0x36<<2), 0}, + {"TRSV 0x37" , (0x37<<2), 0}, + {"TRSV 0x38" , (0x38<<2), 0}, + {"TRSV 0x3a" , (0x3a<<2), 0}, + {"TRSV 0x3b" , (0x3b<<2), 0}, + {"TRSV 0x3c" , (0x3c<<2), 0}, + {"TRSV 0x3d" , (0x3d<<2), 0}, + {"TRSV 0x3e" , (0x3e<<2), 0}, + {"TRSV 0x3f" , (0x3f<<2), 0}, + {"TRSV 0x40" , (0x40<<2), 0}, + {"TRSV 0x41" , (0x41<<2), 0}, + {"TRSV 0x42" , (0x42<<2), 0}, + {"TRSV 0x43" , (0x43<<2), 0}, + {"TRSV 0x44" , (0x44<<2), 0}, + {"TRSV 0x45" , (0x45<<2), 0}, + {"TRSV 0x46" , (0x46<<2), 0}, + {"TRSV 0x47" , (0x47<<2), 0}, + {"TRSV 0x48" , (0x48<<2), 0}, + {"TRSV 0x49" , (0x49<<2), 0}, + {"TRSV 0x4a" , (0x4a<<2), 0}, + {"TRSV 0x4b" , (0x4b<<2), 0}, + {"TRSV 0x4c" , (0x4c<<2), 0}, + {"TRSV 0x4d" , (0x4d<<2), 0}, + {"TRSV 0x4e" , (0x4e<<2), 0}, + {"TRSV 0x4f" , (0x4f<<2), 0}, + {"TRSV 0x50" , (0x50<<2), 0}, + {"TRSV 0x51" , (0x51<<2), 0}, + {"TRSV 0x52" , (0x52<<2), 0}, + {"TRSV 0x53" , (0x53<<2), 0}, + {"TRSV 0x54" , (0x54<<2), 0}, + {"TRSV 0x55" , (0x55<<2), 0}, + {"TRSV 0x56" , (0x56<<2), 0}, + {"TRSV 0x57" , (0x57<<2), 0}, + {"TRSV 0x58" , (0x58<<2), 0}, + {"TRSV 0x59" , (0x59<<2), 0}, + {"TRSV 0x5a" , (0x5a<<2), 0}, + {"TRSV 0x5b" , (0x5b<<2), 0}, + {"TRSV 0x5c" , (0x5c<<2), 0}, + {"TRSV 0x5d" , (0x5d<<2), 0}, + {"TRSV 0x5e" , (0x5e<<2), 0}, + {"TRSV 0x5f" , (0x5f<<2), 0}, + {"TRSV 0x60" , (0x60<<2), 0}, + {"TRSV 0x61" , (0x61<<2), 0}, + {"TRSV 0x62" , (0x62<<2), 0}, + {"TRSV 0x63" , (0x63<<2), 0}, + {"TRSV 0x64" , (0x64<<2), 0}, + {"TRSV 0x65" , (0x65<<2), 0}, + {"TRSV 0x66" , (0x66<<2), 0}, + {"TRSV 0x67" , (0x67<<2), 0}, + {"TRSV 0x68" , (0x68<<2), 0}, + {"TRSV 0x6a" , (0x6a<<2), 0}, + {"TRSV 0x6b" , (0x6b<<2), 0}, + {"TRSV 0x6c" , (0x6c<<2), 0}, + {"TRSV 0x6d" , (0x6d<<2), 0}, + {"TRSV 0x6e" , (0x6e<<2), 0}, + {"TRSV 0x6f" , (0x6f<<2), 0}, + {"TRSV 0x70" , (0x70<<2), 0}, + {"TRSV 0x71" , (0x71<<2), 0}, + {"TRSV 0x72" , (0x72<<2), 0}, + {"TRSV 0x73" , (0x73<<2), 0}, + {"TRSV 0x74" , (0x74<<2), 0}, + {"TRSV 0x75" , (0x75<<2), 0}, + {"TRSV 0x76" , (0x76<<2), 0}, + {"TRSV 0x77" , (0x77<<2), 0}, + {"TRSV 0x78" , (0x78<<2), 0}, + {"TRSV 0x79" , (0x79<<2), 0}, + {"TRSV 0x7a" , (0x7a<<2), 0}, + {"TRSV 0x7b" , (0x7b<<2), 0}, + {"TRSV 0x7c" , (0x7c<<2), 0}, + {"TRSV 0x7d" , (0x7d<<2), 0}, + {"TRSV 0x7e" , (0x7e<<2), 0}, + {"TRSV 0x7f" , (0x7f<<2), 0}, + + {}, +}; + +static struct exynos_ufs_attr_log ufs_log_attr[] = { + /* PA Standard */ + {UIC_ARG_MIB(0x1520), 0, 0}, + {UIC_ARG_MIB(0x1540), 0, 0}, + {UIC_ARG_MIB(0x1543), 0, 0}, + {UIC_ARG_MIB(0x155C), 0, 0}, + {UIC_ARG_MIB(0x155D), 0, 0}, + {UIC_ARG_MIB(0x155E), 0, 0}, + {UIC_ARG_MIB(0x155F), 0, 0}, + {UIC_ARG_MIB(0x1560), 0, 0}, + {UIC_ARG_MIB(0x1561), 0, 0}, + {UIC_ARG_MIB(0x1564), 0, 0}, + {UIC_ARG_MIB(0x1567), 0, 0}, + {UIC_ARG_MIB(0x1568), 0, 0}, + {UIC_ARG_MIB(0x1569), 0, 0}, + {UIC_ARG_MIB(0x156A), 0, 0}, + {UIC_ARG_MIB(0x1571), 0, 0}, + {UIC_ARG_MIB(0x1580), 0, 0}, + {UIC_ARG_MIB(0x1581), 0, 0}, + {UIC_ARG_MIB(0x1582), 0, 0}, + {UIC_ARG_MIB(0x1583), 0, 0}, + {UIC_ARG_MIB(0x1584), 0, 0}, + {UIC_ARG_MIB(0x1585), 0, 0}, + {UIC_ARG_MIB(0x1590), 0, 0}, + {UIC_ARG_MIB(0x1591), 0, 0}, + {UIC_ARG_MIB(0x15A1), 0, 0}, + {UIC_ARG_MIB(0x15A2), 0, 0}, + {UIC_ARG_MIB(0x15A3), 0, 0}, + {UIC_ARG_MIB(0x15A4), 0, 0}, + {UIC_ARG_MIB(0x15A7), 0, 0}, + {UIC_ARG_MIB(0x15A8), 0, 0}, + {UIC_ARG_MIB(0x15C0), 0, 0}, + {UIC_ARG_MIB(0x15C1), 0, 0}, + /* PA Debug */ + {UIC_ARG_MIB(0x9500), 0, 0}, + {UIC_ARG_MIB(0x9501), 0, 0}, + {UIC_ARG_MIB(0x9502), 0, 0}, + {UIC_ARG_MIB(0x9503), 0, 0}, + {UIC_ARG_MIB(0x9510), 0, 0}, + {UIC_ARG_MIB(0x9511), 0, 0}, + {UIC_ARG_MIB(0x9514), 0, 0}, + {UIC_ARG_MIB(0x9515), 0, 0}, + {UIC_ARG_MIB(0x9516), 0, 0}, + {UIC_ARG_MIB(0x9517), 0, 0}, + {UIC_ARG_MIB(0x9520), 0, 0}, + {UIC_ARG_MIB(0x9521), 0, 0}, + {UIC_ARG_MIB(0x9522), 0, 0}, + {UIC_ARG_MIB(0x9523), 0, 0}, + {UIC_ARG_MIB(0x9525), 0, 0}, + {UIC_ARG_MIB(0x9528), 0, 0}, + {UIC_ARG_MIB(0x9529), 0, 0}, + {UIC_ARG_MIB(0x952A), 0, 0}, + {UIC_ARG_MIB(0x952B), 0, 0}, + {UIC_ARG_MIB(0x952C), 0, 0}, + {UIC_ARG_MIB(0x9534), 0, 0}, + {UIC_ARG_MIB(0x9535), 0, 0}, + {UIC_ARG_MIB(0x9536), 0, 0}, + {UIC_ARG_MIB(0x9539), 0, 0}, + {UIC_ARG_MIB(0x9540), 0, 0}, + {UIC_ARG_MIB(0x9541), 0, 0}, + {UIC_ARG_MIB(0x9542), 0, 0}, + {UIC_ARG_MIB(0x9543), 0, 0}, + {UIC_ARG_MIB(0x9546), 0, 0}, + {UIC_ARG_MIB(0x9551), 0, 0}, + {UIC_ARG_MIB(0x9552), 0, 0}, + {UIC_ARG_MIB(0x9554), 0, 0}, + {UIC_ARG_MIB(0x9556), 0, 0}, + {UIC_ARG_MIB(0x9557), 0, 0}, + {UIC_ARG_MIB(0x9558), 0, 0}, + {UIC_ARG_MIB(0x9559), 0, 0}, + {UIC_ARG_MIB(0x9560), 0, 0}, + {UIC_ARG_MIB(0x9561), 0, 0}, + {UIC_ARG_MIB(0x9562), 0, 0}, + {UIC_ARG_MIB(0x9563), 0, 0}, + {UIC_ARG_MIB(0x9564), 0, 0}, + {UIC_ARG_MIB(0x9565), 0, 0}, + {UIC_ARG_MIB(0x9566), 0, 0}, + {UIC_ARG_MIB(0x9567), 0, 0}, + {UIC_ARG_MIB(0x9568), 0, 0}, + {UIC_ARG_MIB(0x9569), 0, 0}, + {UIC_ARG_MIB(0x9570), 0, 0}, + {UIC_ARG_MIB(0x9571), 0, 0}, + {UIC_ARG_MIB(0x9572), 0, 0}, + {UIC_ARG_MIB(0x9573), 0, 0}, + /* DL Standard */ + {UIC_ARG_MIB(0x2002), 0, 0}, + {UIC_ARG_MIB(0x2003), 0, 0}, + {UIC_ARG_MIB(0x2004), 0, 0}, + {UIC_ARG_MIB(0x2005), 0, 0}, + {UIC_ARG_MIB(0x2006), 0, 0}, + {UIC_ARG_MIB(0x2040), 0, 0}, + {UIC_ARG_MIB(0x2041), 0, 0}, + {UIC_ARG_MIB(0x2042), 0, 0}, + {UIC_ARG_MIB(0x2043), 0, 0}, + {UIC_ARG_MIB(0x2044), 0, 0}, + {UIC_ARG_MIB(0x2045), 0, 0}, + {UIC_ARG_MIB(0x2046), 0, 0}, + {UIC_ARG_MIB(0x2047), 0, 0}, + {UIC_ARG_MIB(0x2060), 0, 0}, + {UIC_ARG_MIB(0x2061), 0, 0}, + {UIC_ARG_MIB(0x2062), 0, 0}, + {UIC_ARG_MIB(0x2063), 0, 0}, + {UIC_ARG_MIB(0x2064), 0, 0}, + {UIC_ARG_MIB(0x2065), 0, 0}, + {UIC_ARG_MIB(0x2066), 0, 0}, + {UIC_ARG_MIB(0x2067), 0, 0}, + /* DL Debug */ + {UIC_ARG_MIB(0xA000), 0, 0}, + {UIC_ARG_MIB(0xA003), 0, 0}, + {UIC_ARG_MIB(0xA004), 0, 0}, + {UIC_ARG_MIB(0xA005), 0, 0}, + {UIC_ARG_MIB(0xA006), 0, 0}, + {UIC_ARG_MIB(0xA007), 0, 0}, + {UIC_ARG_MIB(0xA009), 0, 0}, + {UIC_ARG_MIB(0xA010), 0, 0}, + {UIC_ARG_MIB(0xA011), 0, 0}, + {UIC_ARG_MIB(0xA012), 0, 0}, + {UIC_ARG_MIB(0xA013), 0, 0}, + {UIC_ARG_MIB(0xA014), 0, 0}, + {UIC_ARG_MIB(0xA015), 0, 0}, + {UIC_ARG_MIB(0xA016), 0, 0}, + {UIC_ARG_MIB(0xA020), 0, 0}, + {UIC_ARG_MIB(0xA021), 0, 0}, + {UIC_ARG_MIB(0xA022), 0, 0}, + {UIC_ARG_MIB(0xA023), 0, 0}, + {UIC_ARG_MIB(0xA024), 0, 0}, + {UIC_ARG_MIB(0xA025), 0, 0}, + {UIC_ARG_MIB(0xA026), 0, 0}, + {UIC_ARG_MIB(0xA027), 0, 0}, + {UIC_ARG_MIB(0xA028), 0, 0}, + {UIC_ARG_MIB(0xA029), 0, 0}, + {UIC_ARG_MIB(0xA02A), 0, 0}, + {UIC_ARG_MIB(0xA02B), 0, 0}, + {UIC_ARG_MIB(0xA02C), 0, 0}, + {UIC_ARG_MIB(0xA02D), 0, 0}, + {UIC_ARG_MIB(0xA02E), 0, 0}, + {UIC_ARG_MIB(0xA02F), 0, 0}, + {UIC_ARG_MIB(0xA030), 0, 0}, + {UIC_ARG_MIB(0xA031), 0, 0}, + {UIC_ARG_MIB(0xA041), 0, 0}, + {UIC_ARG_MIB(0xA042), 0, 0}, + {UIC_ARG_MIB(0xA043), 0, 0}, + {UIC_ARG_MIB(0xA044), 0, 0}, + {UIC_ARG_MIB(0xA045), 0, 0}, + {UIC_ARG_MIB(0xA046), 0, 0}, + {UIC_ARG_MIB(0xA047), 0, 0}, + {UIC_ARG_MIB(0xA060), 0, 0}, + {UIC_ARG_MIB(0xA061), 0, 0}, + {UIC_ARG_MIB(0xA062), 0, 0}, + {UIC_ARG_MIB(0xA063), 0, 0}, + {UIC_ARG_MIB(0xA064), 0, 0}, + {UIC_ARG_MIB(0xA065), 0, 0}, + {UIC_ARG_MIB(0xA066), 0, 0}, + {UIC_ARG_MIB(0xA067), 0, 0}, + {UIC_ARG_MIB(0xA068), 0, 0}, + {UIC_ARG_MIB(0xA069), 0, 0}, + {UIC_ARG_MIB(0xA06A), 0, 0}, + {UIC_ARG_MIB(0xA06B), 0, 0}, + {UIC_ARG_MIB(0xA06C), 0, 0}, + {UIC_ARG_MIB(0xA080), 0, 0}, + /* NL Standard */ + {UIC_ARG_MIB(0x3000), 0, 0}, + {UIC_ARG_MIB(0x3001), 0, 0}, + {UIC_ARG_MIB(0x4020), 0, 0}, + {UIC_ARG_MIB(0x4021), 0, 0}, + {UIC_ARG_MIB(0x4022), 0, 0}, + {UIC_ARG_MIB(0x4023), 0, 0}, + {UIC_ARG_MIB(0x4025), 0, 0}, + {UIC_ARG_MIB(0x402B), 0, 0}, + /* MPHY */ + {UIC_ARG_MIB(0x0021), 0, 0}, + {UIC_ARG_MIB(0x0022), 0, 0}, + {UIC_ARG_MIB(0x0023), 0, 0}, + {UIC_ARG_MIB(0x0024), 0, 0}, + {UIC_ARG_MIB(0x0028), 0, 0}, + {UIC_ARG_MIB(0x0029), 0, 0}, + {UIC_ARG_MIB(0x002A), 0, 0}, + {UIC_ARG_MIB(0x002B), 0, 0}, + {UIC_ARG_MIB(0x002C), 0, 0}, + {UIC_ARG_MIB(0x002D), 0, 0}, + {UIC_ARG_MIB(0x0033), 0, 0}, + {UIC_ARG_MIB(0x0035), 0, 0}, + {UIC_ARG_MIB(0x0036), 0, 0}, + {UIC_ARG_MIB(0x0041), 0, 0}, + {UIC_ARG_MIB(0x00A1), 0, 0}, + {UIC_ARG_MIB(0x00A2), 0, 0}, + {UIC_ARG_MIB(0x00A3), 0, 0}, + {UIC_ARG_MIB(0x00A4), 0, 0}, + {UIC_ARG_MIB(0x00A7), 0, 0}, + {UIC_ARG_MIB(0x00C1), 0, 0}, + {UIC_ARG_MIB(0x029b), 0, 0}, + {UIC_ARG_MIB(0x035d), 0, 0}, + {UIC_ARG_MIB(0x028B), 0, 0}, + {UIC_ARG_MIB(0x029A), 0, 0}, + {UIC_ARG_MIB(0x0277), 0, 0}, + + {}, +}; + +static struct exynos_ufs_sfr_log ufs_show_sfr[] = { + {}, +}; + +static struct exynos_ufs_attr_log ufs_show_attr[] = { + {}, +}; + +#endif +static void exynos_ufs_get_misc(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + struct exynos_ufs_clk_info *clki; + struct list_head *head = &ufs->debug.misc.clk_list_head; + + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk)) + clki->freq = clk_get_rate(clki->clk); + } + ufs->debug.misc.isolation = readl(ufs->phy.reg_pmu); +} + +static void exynos_ufs_get_sfr(struct ufs_hba *hba, + struct exynos_ufs_sfr_log* cfg) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + int sel_api = 0; + + while(cfg) { + if (!cfg->name) + break; + + if (cfg->offset >= LOG_STD_HCI_SFR) { + /* Select an API to get SFRs */ + sel_api = cfg->offset; + } else { + /* Fetch value */ + if (sel_api == LOG_STD_HCI_SFR) + cfg->val = ufshcd_readl(hba, cfg->offset); + else if (sel_api == LOG_VS_HCI_SFR) + cfg->val = hci_readl(ufs, cfg->offset); +// else if (sel_api == LOG_FMP_SFR) +// cfg->val = exynos_smc(SMC_CMD_FMP_DUMP, 0, 0, cfg->offset); + else if (sel_api == LOG_UNIPRO_SFR) + cfg->val = unipro_readl(ufs, cfg->offset); + else if (sel_api == LOG_PMA_SFR) + cfg->val = phy_pma_readl(ufs, cfg->offset); + else + cfg->val = 0xFFFFFFFF; + } + + /* Next SFR */ + cfg++; + } +} + +static void exynos_ufs_get_attr(struct ufs_hba *hba, + struct exynos_ufs_attr_log* cfg) +{ + u32 i; + u32 intr_enable; + + /* Disable and backup interrupts */ + intr_enable = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE); + + while(cfg) { + if (cfg->offset == 0) + break; + + /* Send DME_GET */ + ufshcd_writel(hba, cfg->offset, REG_UIC_COMMAND_ARG_1); + ufshcd_writel(hba, UIC_CMD_DME_GET, REG_UIC_COMMAND); + + i = 0; + while(!(ufshcd_readl(hba, REG_INTERRUPT_STATUS) & + UIC_COMMAND_COMPL)) { + if (i++ > 20000) { + dev_err(hba->dev, + "Failed to fetch a value of %x", + cfg->offset); + goto out; + } + } + + /* Clear UIC command completion */ + ufshcd_writel(hba, UIC_COMMAND_COMPL, REG_INTERRUPT_STATUS); + + /* Fetch result and value */ + cfg->res = ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2 & + MASK_UIC_COMMAND_RESULT); + cfg->val = ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); + + /* Next attribute */ + cfg++; + } + +out: + /* Restore and enable interrupts */ + ufshcd_writel(hba, intr_enable, REG_INTERRUPT_ENABLE); +} + +static void exynos_ufs_dump_misc(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + struct exynos_ufs_misc_log* cfg = &ufs->debug.misc; + struct exynos_ufs_clk_info *clki; + struct list_head *head = &cfg->clk_list_head; + + dev_err(hba->dev, ": --------------------------------------------------- \n"); + dev_err(hba->dev, ": \t\tMISC DUMP\n"); + dev_err(hba->dev, ": --------------------------------------------------- \n"); + + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk)) { + dev_err(hba->dev, "%s: %lu\n", + clki->name, clki->freq); + } + } + dev_err(hba->dev, "iso: %d\n", ufs->debug.misc.isolation); +} + +static void exynos_ufs_dump_sfr(struct ufs_hba *hba, + struct exynos_ufs_sfr_log* cfg) +{ + dev_err(hba->dev, ": --------------------------------------------------- \n"); + dev_err(hba->dev, ": \t\tREGISTER DUMP\n"); + dev_err(hba->dev, ": --------------------------------------------------- \n"); + + while(cfg) { + if (!cfg->name) + break; + + /* Dump */ + dev_err(hba->dev, ": %s(0x%04x):\t\t\t\t0x%08x\n", + cfg->name, cfg->offset, cfg->val); + + /* Next SFR */ + cfg++; + } +} + +static void exynos_ufs_dump_attr(struct ufs_hba *hba, + struct exynos_ufs_attr_log* cfg) +{ + dev_err(hba->dev, ": --------------------------------------------------- \n"); + dev_err(hba->dev, ": \t\tATTRIBUTE DUMP\n"); + dev_err(hba->dev, ": --------------------------------------------------- \n"); + + while(cfg) { + if (!cfg->offset) + break; + + /* Dump */ + dev_err(hba->dev, ": 0x%04x:\t\t0x%08x\t\t0x%08x\n", + cfg->offset, cfg->val, cfg->res); + + /* Next SFR */ + cfg++; + } +} + +/* + * Functions to be provied externally + * + * There are two classes that are to initialize data structures for debug + * and to define actual behavior. + */ +void exynos_ufs_get_uic_info(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + + if (!(ufs->misc_flags & EXYNOS_UFS_MISC_TOGGLE_LOG)) + return; + + exynos_ufs_get_sfr(hba, ufs->debug.sfr); + exynos_ufs_get_attr(hba, ufs->debug.attr); + exynos_ufs_get_misc(hba); + + ufs->misc_flags &= ~(EXYNOS_UFS_MISC_TOGGLE_LOG); +} + +void exynos_ufs_dump_uic_info(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + +// /* secure log */ +// exynos_smc(SMC_CMD_UFS_LOG, 1, 0, hba->secure_log.paddr); + + exynos_ufs_get_sfr(hba, ufs->debug.sfr); + exynos_ufs_get_attr(hba, ufs->debug.attr); + exynos_ufs_get_misc(hba); + + exynos_ufs_dump_sfr(hba, ufs->debug.sfr); + exynos_ufs_dump_attr(hba, ufs->debug.attr); + exynos_ufs_dump_misc(hba); +} + +void exynos_ufs_show_uic_info(struct ufs_hba *hba) +{ + exynos_ufs_get_sfr(hba, ufs_show_sfr); + exynos_ufs_get_attr(hba, ufs_show_attr); + + exynos_ufs_dump_sfr(hba, ufs_show_sfr); + exynos_ufs_dump_attr(hba, ufs_show_attr); +} + + +int exynos_ufs_init_dbg(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + struct list_head *head = &hba->clk_list_head; + struct ufs_clk_info *clki; + struct exynos_ufs_clk_info *exynos_clki; + + ufs->debug.sfr = ufs_log_sfr; + ufs->debug.attr = ufs_log_attr; + INIT_LIST_HEAD(&ufs->debug.misc.clk_list_head); + + if (!head || list_empty(head)) + return 0; + + list_for_each_entry(clki, head, list) { + exynos_clki = devm_kzalloc(hba->dev, sizeof(*exynos_clki), GFP_KERNEL); + if (!exynos_clki) { + return -ENOMEM; + } + exynos_clki->clk = clki->clk; + exynos_clki->name = clki->name; + exynos_clki->freq = 0; + list_add_tail(&exynos_clki->list, &ufs->debug.misc.clk_list_head); + } + +// hba->secure_log.paddr = exynos_ss_get_spare_paddr(0); +// hba->secure_log.vaddr = (u32 *)exynos_ss_get_spare_vaddr(0); + + return 0; +} + +static struct ufs_cmd_info ufs_cmd_queue; +static struct ufs_cmd_logging_category ufs_cmd_log; + +static void exynos_ufs_putItem_start(struct ufs_cmd_info *cmdQueue, struct ufs_cmd_logging_category *cmdData) +{ + cmdQueue->addr_per_tag[cmdData->tag] = &cmdQueue->data[cmdQueue->last]; + cmdQueue->data[cmdQueue->last].cmd_opcode = cmdData->cmd_opcode; + cmdQueue->data[cmdQueue->last].tag = cmdData->tag; + cmdQueue->data[cmdQueue->last].lba = cmdData->lba; + cmdQueue->data[cmdQueue->last].sct = cmdData->sct; + cmdQueue->data[cmdQueue->last].retries = cmdData->retries; + cmdQueue->data[cmdQueue->last].start_time = cmdData->start_time; + cmdQueue->data[cmdQueue->last].outstanding_reqs = cmdData->outstanding_reqs; + cmdQueue->last = (cmdQueue->last + 1) % MAX_CMD_LOGS; +} + + + +void exynos_ufs_cmd_log_start(struct ufs_hba *hba, struct scsi_cmnd *cmd) +{ + int cpu = raw_smp_processor_id(); + + unsigned long lba = (cmd->cmnd[2] << 24) | + (cmd->cmnd[3] << 16) | + (cmd->cmnd[4] << 8) | + (cmd->cmnd[5] << 0); + unsigned int sct = (cmd->cmnd[7] << 8) | + (cmd->cmnd[8] << 0); + + ufs_cmd_log.start_time = cpu_clock(cpu); + ufs_cmd_log.cmd_opcode = cmd->cmnd[0]; + ufs_cmd_log.tag = cmd->request->tag; + ufs_cmd_log.outstanding_reqs = hba->outstanding_reqs; + + if(cmd->cmnd[0] != UNMAP) + ufs_cmd_log.lba = lba; + + ufs_cmd_log.sct = sct; + ufs_cmd_log.retries = cmd->allowed; + + exynos_ufs_putItem_start(&ufs_cmd_queue, &ufs_cmd_log); +} + + +void exynos_ufs_cmd_log_end(struct ufs_hba *hba, int tag) +{ + int cpu = raw_smp_processor_id(); + + ufs_cmd_queue.addr_per_tag[tag]->end_time = cpu_clock(cpu); +} diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c new file mode 100644 index 000000000000..d7124a498c2d --- /dev/null +++ b/drivers/scsi/ufs/ufs-exynos.c @@ -0,0 +1,1237 @@ +/* + * UFS Host Controller driver for Exynos specific extensions + * + * Copyright (C) 2013-2014 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +//#include +//#include +#include "ufshcd.h" +#include "unipro.h" +#include "mphy.h" +#include "ufshcd-pltfrm.h" +#include "ufs-exynos.h" + + +/* + * Unipro attribute value + */ +#define TXTRAILINGCLOCKS 0x10 +#define TACTIVATE_10_USEC 400 /* unit: 10us */ + +/* Device ID */ +#define DEV_ID 0x00 +#define PEER_DEV_ID 0x01 +#define PEER_CPORT_ID 0x00 +#define TRAFFIC_CLASS 0x00 + +#define IATOVAL_NSEC 20000 /* unit: ns */ + +/* UFS CAL interface */ + +/* + * Debugging information, SFR/attributes/misc + */ +static struct exynos_ufs *ufs_host_backup[1]; +static int ufs_host_index = 0; + +static struct exynos_ufs_sfr_log ufs_log_std_sfr[] = { + {"CAPABILITIES" , REG_CONTROLLER_CAPABILITIES, 0}, + {"UFS VERSION" , REG_UFS_VERSION, 0}, + {"PRODUCT ID" , REG_CONTROLLER_DEV_ID, 0}, + {"MANUFACTURE ID" , REG_CONTROLLER_PROD_ID, 0}, + {"INTERRUPT STATUS" , REG_INTERRUPT_STATUS, 0}, + {"INTERRUPT ENABLE" , REG_INTERRUPT_ENABLE, 0}, + {"CONTROLLER STATUS" , REG_CONTROLLER_STATUS, 0}, + {"CONTROLLER ENABLE" , REG_CONTROLLER_ENABLE, 0}, + {"UTP TRANSF REQ INT AGG CNTRL" , REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL, 0}, + {"UTP TRANSF REQ LIST BASE L" , REG_UTP_TRANSFER_REQ_LIST_BASE_L, 0}, + {"UTP TRANSF REQ LIST BASE H" , REG_UTP_TRANSFER_REQ_LIST_BASE_H, 0}, + {"UTP TRANSF REQ DOOR BELL" , REG_UTP_TRANSFER_REQ_DOOR_BELL, 0}, + {"UTP TRANSF REQ LIST CLEAR" , REG_UTP_TRANSFER_REQ_LIST_CLEAR, 0}, + {"UTP TRANSF REQ LIST RUN STOP" , REG_UTP_TRANSFER_REQ_LIST_RUN_STOP, 0}, + {"UTP TASK REQ LIST BASE L" , REG_UTP_TASK_REQ_LIST_BASE_L, 0}, + {"UTP TASK REQ LIST BASE H" , REG_UTP_TASK_REQ_LIST_BASE_H, 0}, + {"UTP TASK REQ DOOR BELL" , REG_UTP_TASK_REQ_DOOR_BELL, 0}, + {"UTP TASK REQ LIST CLEAR" , REG_UTP_TASK_REQ_LIST_CLEAR, 0}, + {"UTP TASK REQ LIST RUN STOP" , REG_UTP_TASK_REQ_LIST_RUN_STOP, 0}, + {"UIC COMMAND" , REG_UIC_COMMAND, 0}, + {"UIC COMMAND ARG1" , REG_UIC_COMMAND_ARG_1, 0}, + {"UIC COMMAND ARG2" , REG_UIC_COMMAND_ARG_2, 0}, + {"UIC COMMAND ARG3" , REG_UIC_COMMAND_ARG_3, 0}, + + {}, +}; + +/* Helper for UFS CAL interface */ +static inline int ufs_init_cal(struct exynos_ufs *ufs, int idx, + struct platform_device *pdev) +{ + int ret = 0; + struct device *dev = &pdev->dev; + struct ufs_cal_param *p = NULL; + + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); + if (!p) { + dev_err(ufs->dev, "cannot allocate mem for cal param\n"); + return -ENOMEM; + } + ufs->cal_param = p; + + p->host = ufs; + p->board = 0; /* ken: need a dt node for board */ + if ((ret = ufs_cal_init(p, idx)) != UFS_CAL_NO_ERROR) { + dev_err(ufs->dev, "ufs_init_cal = %d!!!\n", ret); + return -EPERM; + } + + return 0; +} + +static inline int ufs_pre_link(struct exynos_ufs *ufs) +{ + int ret = 0; + struct ufs_cal_param *p = ufs->cal_param; + + p->mclk_rate = ufs->mclk_rate; + p->target_lane = ufs->num_rx_lanes; + p->available_lane = ufs->num_rx_lanes; + + if ((ret = ufs_cal_pre_link(p)) != UFS_CAL_NO_ERROR) { + dev_err(ufs->dev, "ufs_pre_link = %d!!!\n", ret); + return -EPERM; + } + + return 0; +} + +static inline int ufs_post_link(struct exynos_ufs *ufs) +{ + int ret = 0; + + if ((ret = ufs_cal_post_link(ufs->cal_param)) != UFS_CAL_NO_ERROR) { + dev_err(ufs->dev, "ufs_post_link = %d!!!\n", ret); + return -EPERM; + } + + return 0; +} + +static inline int ufs_pre_gear_change(struct exynos_ufs *ufs, + struct uic_pwr_mode *pmd) +{ + struct ufs_cal_param *p = ufs->cal_param; + int ret = 0; + + p->pmd = pmd; + p->target_lane = pmd->lane; + if ((ret = ufs_cal_pre_pmc(p)) != UFS_CAL_NO_ERROR) { + dev_err(ufs->dev, "ufs_pre_gear_change = %d!!!\n", ret); + return -EPERM; + } + + return 0; +} + +static inline int ufs_post_gear_change(struct exynos_ufs *ufs) +{ + int ret = 0; + + if ((ret = ufs_cal_post_pmc(ufs->cal_param)) != UFS_CAL_NO_ERROR) { + dev_err(ufs->dev, "ufs_post_gear_change = %d!!!\n", ret); + return -EPERM; + } + + return 0; +} + +static inline int ufs_post_h8_enter(struct exynos_ufs *ufs) +{ + int ret = 0; + + if ((ret = ufs_cal_post_h8_enter(ufs->cal_param)) != UFS_CAL_NO_ERROR) { + dev_err(ufs->dev, "ufs_post_h8_enter = %d!!!\n", ret); + return -EPERM; + } + + return 0; +} + +static inline int ufs_pre_h8_exit(struct exynos_ufs *ufs) +{ + int ret = 0; + + if ((ret = ufs_cal_pre_h8_exit(ufs->cal_param)) != UFS_CAL_NO_ERROR) { + dev_err(ufs->dev, "ufs_pre_h8_exit = %d!!!\n", ret); + return -EPERM; + } + + return 0; +} + +/* Adaptor for UFS CAL */ +void ufs_lld_dme_set(void *h, u32 addr, u32 val) +{ + ufshcd_dme_set(((struct exynos_ufs *)h)->hba, addr, val); +} + +void ufs_lld_dme_get(void *h, u32 addr, u32 *val) +{ + ufshcd_dme_get(((struct exynos_ufs *)h)->hba, addr, val); +} + +void ufs_lld_dme_peer_set(void *h, u32 addr, u32 val) +{ + ufshcd_dme_peer_set(((struct exynos_ufs *)h)->hba, addr, val); +} + +void ufs_lld_pma_write(void *h, u32 val, u32 addr) +{ + phy_pma_writel((struct exynos_ufs *)h, val, addr); +} + +u32 ufs_lld_pma_read(void *h, u32 addr) +{ + return phy_pma_readl((struct exynos_ufs *)h, addr); +} + +void ufs_lld_unipro_write(void *h, u32 val, u32 addr) +{ + unipro_writel((struct exynos_ufs *)h, val, addr); +} + +void ufs_lld_udelay(u32 val) +{ + udelay(val); +} + +void ufs_lld_usleep_delay(u32 min, u32 max) +{ + usleep_range(min, max); +} + +unsigned long ufs_lld_get_time_count(unsigned long offset) +{ + return jiffies; +} + +unsigned long ufs_lld_calc_timeout(const unsigned int ms) +{ + return msecs_to_jiffies(ms); +} + +static inline void exynos_ufs_ctrl_phy_pwr(struct exynos_ufs *ufs, bool en) +{ + u32 reg; + + reg = readl(ufs->phy.reg_pmu); + + if (en) + writel(reg | BIT(0), ufs->phy.reg_pmu); + else + writel(reg & ~(BIT(0)), ufs->phy.reg_pmu); +} + +#ifndef __EXYNOS_UFS_VS_DEBUG__ +static void exynos_ufs_dump_std_sfr(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + struct exynos_ufs_sfr_log* cfg = ufs->debug.std_sfr; + + dev_err(hba->dev, ": --------------------------------------------------- \n"); + dev_err(hba->dev, ": \t\tREGISTER DUMP\n"); + dev_err(hba->dev, ": --------------------------------------------------- \n"); + + while(cfg) { + if (!cfg->name) + break; + cfg->val = ufshcd_readl(hba, cfg->offset); + + /* Dump */ + dev_err(hba->dev, ": %s(0x%04x):\t\t\t\t0x%08x\n", + cfg->name, cfg->offset, cfg->val); + + /* Next SFR */ + cfg++; + } +} +#endif + +/* + * Exynos debugging main function + */ +static void exynos_ufs_dump_debug_info(struct ufs_hba *hba) +{ +#ifdef __EXYNOS_UFS_VS_DEBUG__ + exynos_ufs_get_uic_info(hba); +#else + exynos_ufs_dump_std_sfr(hba); +#endif +} + +static void exynos_ufs_select_refclk(struct exynos_ufs *ufs, bool en) +{ + u32 reg; + if (ufs->hw_rev != UFS_VER_0004) + return; + + /* + * true : alternative clock path, false : active clock path + */ + reg = hci_readl(ufs, HCI_MPHY_REFCLK_SEL); + if (en) + hci_writel(ufs, reg | MPHY_REFCLK_SEL, HCI_MPHY_REFCLK_SEL); + else + hci_writel(ufs, reg & ~MPHY_REFCLK_SEL, HCI_MPHY_REFCLK_SEL); +} + +inline void exynos_ufs_set_hwacg_control(struct exynos_ufs *ufs, bool en) +{ + u32 reg; + if ((ufs->hw_rev != UFS_VER_0004) && (ufs->hw_rev != UFS_VER_0005)) + return; + + /* + * default value 1->0 at KC. so, + * need to set "1(disable HWACG)" during UFS init + */ + reg = hci_readl(ufs, HCI_UFS_ACG_DISABLE); + if (en) + hci_writel(ufs, reg & (~HCI_UFS_ACG_DISABLE_EN), HCI_UFS_ACG_DISABLE); + else + hci_writel(ufs, reg | HCI_UFS_ACG_DISABLE_EN, HCI_UFS_ACG_DISABLE); + +} + +inline void exynos_ufs_ctrl_auto_hci_clk(struct exynos_ufs *ufs, bool en) +{ + u32 reg = hci_readl(ufs, HCI_FORCE_HCS); + + if (en) + hci_writel(ufs, reg | HCI_CORECLK_STOP_EN, HCI_FORCE_HCS); + else + hci_writel(ufs, reg & ~HCI_CORECLK_STOP_EN, HCI_FORCE_HCS); +} + +static inline void exynos_ufs_ctrl_clk(struct exynos_ufs *ufs, bool en) +{ + u32 reg = hci_readl(ufs, HCI_FORCE_HCS); + + if (en) + hci_writel(ufs, reg | CLK_STOP_CTRL_EN_ALL, HCI_FORCE_HCS); + else + hci_writel(ufs, reg & ~CLK_STOP_CTRL_EN_ALL, HCI_FORCE_HCS); +} + +static inline void exynos_ufs_gate_clk(struct exynos_ufs *ufs, bool en) +{ + + u32 reg = hci_readl(ufs, HCI_CLKSTOP_CTRL); + + if (en) + hci_writel(ufs, reg | CLK_STOP_ALL, HCI_CLKSTOP_CTRL); + else + hci_writel(ufs, reg & ~CLK_STOP_ALL, HCI_CLKSTOP_CTRL); +} + +static void exynos_ufs_set_unipro_mclk(struct exynos_ufs *ufs) +{ + ufs->mclk_rate = (u32)clk_get_rate(ufs->clk_unipro); +} + +static void exynos_ufs_fit_aggr_timeout(struct exynos_ufs *ufs) +{ + u32 cnt_val; + unsigned long nVal; + + /* IA_TICK_SEL : 1(1us_TO_CNT_VAL) */ + nVal = hci_readl(ufs, HCI_UFSHCI_V2P1_CTRL); + nVal |= IA_TICK_SEL; + hci_writel(ufs, nVal, HCI_UFSHCI_V2P1_CTRL); + + cnt_val = ufs->mclk_rate / 1000000 ; + hci_writel(ufs, cnt_val & CNT_VAL_1US_MASK, HCI_1US_TO_CNT_VAL); +} + +static void exynos_ufs_init_pmc_req(struct ufs_hba *hba, + struct ufs_pa_layer_attr *pwr_max, + struct ufs_pa_layer_attr *pwr_req) +{ + + struct exynos_ufs *ufs = to_exynos_ufs(hba); + struct uic_pwr_mode *req_pmd = &ufs->req_pmd_parm; + struct uic_pwr_mode *act_pmd = &ufs->act_pmd_parm; + + /* update lane variable after link */ + ufs->num_rx_lanes = pwr_max->lane_rx; + ufs->num_tx_lanes = pwr_max->lane_tx; + + pwr_req->gear_rx + = act_pmd->gear= min_t(u8, pwr_max->gear_rx, req_pmd->gear); + pwr_req->gear_tx + = act_pmd->gear = min_t(u8, pwr_max->gear_tx, req_pmd->gear); + pwr_req->lane_rx + = act_pmd->lane = min_t(u8, pwr_max->lane_rx, req_pmd->lane); + pwr_req->lane_tx + = act_pmd->lane = min_t(u8, pwr_max->lane_tx, req_pmd->lane); + pwr_req->pwr_rx = act_pmd->mode = req_pmd->mode; + pwr_req->pwr_tx = act_pmd->mode = req_pmd->mode; + pwr_req->hs_rate = act_pmd->hs_series = req_pmd->hs_series; +} + +static void exynos_ufs_config_intr(struct exynos_ufs *ufs, u32 errs, u8 index) +{ + switch(index) { + case UNIP_PA_LYR: + hci_writel(ufs, DFES_ERR_EN | errs, HCI_ERROR_EN_PA_LAYER); + break; + case UNIP_DL_LYR: + hci_writel(ufs, DFES_ERR_EN | errs, HCI_ERROR_EN_DL_LAYER); + break; + case UNIP_N_LYR: + hci_writel(ufs, DFES_ERR_EN | errs, HCI_ERROR_EN_N_LAYER); + break; + case UNIP_T_LYR: + hci_writel(ufs, DFES_ERR_EN | errs, HCI_ERROR_EN_T_LAYER); + break; + case UNIP_DME_LYR: + hci_writel(ufs, DFES_ERR_EN | errs, HCI_ERROR_EN_DME_LAYER); + break; + } +} + +static void exynos_ufs_dev_hw_reset(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + + /* bit[1] for resetn */ + hci_writel(ufs, 0 << 0, HCI_GPIO_OUT); + udelay(5); + hci_writel(ufs, 1 << 0, HCI_GPIO_OUT); +} + +static void exynos_ufs_init_host(struct exynos_ufs *ufs) +{ + u32 reg; + + /* internal clock control */ + exynos_ufs_ctrl_auto_hci_clk(ufs, false); + exynos_ufs_set_unipro_mclk(ufs); + + /* period for interrupt aggregation */ + exynos_ufs_fit_aggr_timeout(ufs); + + /* misc HCI configurations */ + hci_writel(ufs, 0xA, HCI_DATA_REORDER); + hci_writel(ufs, PRDT_PREFECT_EN | PRDT_SET_SIZE(12), + HCI_TXPRDT_ENTRY_SIZE); + hci_writel(ufs, PRDT_SET_SIZE(12), HCI_RXPRDT_ENTRY_SIZE); + hci_writel(ufs, 0xFFFFFFFF, HCI_UTRL_NEXUS_TYPE); + hci_writel(ufs, 0xFFFFFFFF, HCI_UTMRL_NEXUS_TYPE); + + reg = hci_readl(ufs, HCI_AXIDMA_RWDATA_BURST_LEN) & + ~BURST_LEN(0); + hci_writel(ufs, WLU_EN | BURST_LEN(3), + HCI_AXIDMA_RWDATA_BURST_LEN); + + /* + * Enable HWAGC control by IOP + * + * default value 1->0 at KC. + * always "0"(controlled by UFS_ACG_DISABLE) + */ + reg = hci_readl(ufs, HCI_IOP_ACG_DISABLE); + hci_writel(ufs, reg & (~HCI_IOP_ACG_DISABLE_EN), HCI_IOP_ACG_DISABLE); +} + +static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter) +{ +} + +static void exynos_ufs_post_hibern8(struct ufs_hba *hba, u8 enter) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + + if (!enter) { + struct uic_pwr_mode *act_pmd = &ufs->act_pmd_parm; + u32 mode = 0; + + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &mode); + if (mode != (act_pmd->mode << 4 | act_pmd->mode)) { + dev_warn(hba->dev, "%s: power mode not matched, mode : 0x%x, act_mode : 0x%x\n", + __func__, mode, act_pmd->mode); + hba->pwr_info.pwr_rx = (mode >> 4) & 0xf; + hba->pwr_info.pwr_tx = mode & 0xf; + ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info); + } + } +} + +static void exynos_ufs_modify_sysreg(struct exynos_ufs *ufs, int index) +{ + struct exynos_ufs_sys *sys = &ufs->sys; + void __iomem *reg_sys = sys->reg_sys[index]; + const char *const name[NUM_OF_SYSREG] = { + "ufs-io-coherency", + }; + u32 reg; + + if (!of_get_child_by_name(ufs->dev->of_node, name[index])) + return; + + reg = readl(reg_sys); + writel((reg & ~(sys->mask[index])) | sys->bits[index], reg_sys); +} + +static int exynos_ufs_init_system(struct exynos_ufs *ufs) +{ + struct device *dev = ufs->dev; + int ret = 0; + + /* PHY isolation bypass */ + exynos_ufs_ctrl_phy_pwr(ufs, true); + + /* IO cohernecy */ + if (!of_get_child_by_name(dev->of_node, "ufs-io-coherency")) { + dev_err(dev, "Not configured to use IO coherency\n"); + } else { + if (!of_find_property(dev->of_node, "dma-coherent", NULL)) + BUG(); + + exynos_ufs_modify_sysreg(ufs, 0); + } + + return ret; +} + +static int exynos_ufs_get_clks(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + struct list_head *head = &hba->clk_list_head; + struct ufs_clk_info *clki; + + ufs_host_backup[ufs_host_index++] = ufs; + ufs->debug.std_sfr = ufs_log_std_sfr; + + if (!head || list_empty(head)) + goto out; + + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk)) { + if (!strcmp(clki->name, "GATE_UFS_EMBD")) + ufs->clk_hci = clki->clk; + if (!strcmp(clki->name, "UFS_EMBD")) { + ufs->clk_unipro = clki->clk; + } + } + } +out: + if (!ufs->clk_hci || !ufs->clk_unipro) + return -EINVAL; + + return 0; +} + +static void exynos_ufs_set_features(struct ufs_hba *hba, u32 hw_rev) +{ + /* caps */ + hba->caps = UFSHCD_CAP_CLK_GATING | + UFSHCD_CAP_HIBERN8_WITH_CLK_GATING | + UFSHCD_CAP_INTR_AGGR; + + /* quirks of common driver */ + hba->quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN | + UFSHCI_QUIRK_SKIP_INTR_AGGR | + UFSHCD_QUIRK_UNRESET_INTR_AGGR | + UFSHCD_QUIRK_BROKEN_REQ_LIST_CLR; + + hba->quirks |= UFSHCD_QUIRK_GET_UPMCRS_DIRECT | + UFSHCD_QUIRK_GET_GENERRCODE_DIRECT; + + /* quirks of exynos-specific driver */ +} + +/* + * Exynos-specific callback functions + * + * init | Pure SW init & system-related init + * host_reset | Host SW reset & init + * pre_setup_clocks | specific power down + * setup_clocks | specific power up + * ... + * + * Initializations for software, host controller and system + * should be contained only in ->host_reset() as possible. + */ + +static int exynos_ufs_init(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + int ret; + + /* set features, such as caps or quirks */ + exynos_ufs_set_features(hba, ufs->hw_rev); + + /* get some clock sources and debug infomation structures */ + ret = exynos_ufs_get_clks(hba); + if (ret) + return ret; + + /* system init */ + ret = exynos_ufs_init_system(ufs); + if (ret) + return ret; + + + /* Enable log */ + ret = exynos_ufs_init_dbg(hba); + + if (ret) + return ret; + + ufs->misc_flags = EXYNOS_UFS_MISC_TOGGLE_LOG; + + return 0; +} + +static void exynos_ufs_host_reset(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + unsigned long timeout = jiffies + msecs_to_jiffies(1); + + exynos_ufs_ctrl_auto_hci_clk(ufs, false); + + hci_writel(ufs, UFS_SW_RST_MASK, HCI_SW_RST); + + do { + if (!(hci_readl(ufs, HCI_SW_RST) & UFS_SW_RST_MASK)) + goto success; + } while (time_before(jiffies, timeout)); + + dev_err(ufs->dev, "timeout host sw-reset\n"); + + exynos_ufs_dump_uic_info(hba); + + goto out; + +success: + /* host init */ + exynos_ufs_init_host(ufs); + + /* device reset */ + exynos_ufs_dev_hw_reset(hba); + + /* secure log */ +// exynos_smc(SMC_CMD_LOG, 0, 0, 2); +out: + return; +} + +static inline void exynos_ufs_dev_reset_ctrl(struct exynos_ufs *ufs, bool en) +{ + + if (en) + hci_writel(ufs, 1 << 0, HCI_GPIO_OUT); + else + hci_writel(ufs, 0 << 0, HCI_GPIO_OUT); +} + +static int exynos_ufs_pre_setup_clocks(struct ufs_hba *hba, bool on) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + int ret = 0; + + if (on) { +#ifdef CONFIG_CPU_IDLE + exynos_update_ip_idle_status(ufs->idle_ip_index, 0); +#endif + /* + * Now all used blocks would not be turned off in a host. + */ + exynos_ufs_ctrl_auto_hci_clk(ufs, false); + exynos_ufs_gate_clk(ufs, false); + + /* HWAGC disable */ + exynos_ufs_set_hwacg_control(ufs, false); + } else { +// pm_qos_update_request(&ufs->pm_qos_int, 0); + + /* + * BG/SQ off + */ + ret = ufs_post_h8_enter(ufs); + } + + return ret; +} + +static int exynos_ufs_setup_clocks(struct ufs_hba *hba, bool on) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + int ret = 0; + + if (on) { + /* + * BG/SQ on + */ + ret = ufs_pre_h8_exit(ufs); + +// pm_qos_update_request(&ufs->pm_qos_int, ufs->pm_qos_int_value); + + } else { + /* + * Now all used blocks would be turned off in a host. + */ + exynos_ufs_gate_clk(ufs, true); + exynos_ufs_ctrl_auto_hci_clk(ufs, true); + + /* HWAGC enable */ + exynos_ufs_set_hwacg_control(ufs, true); + +#ifdef CONFIG_CPU_IDLE + exynos_update_ip_idle_status(ufs->idle_ip_index, 1); +#endif + } + + return ret; +} + +static int exynos_ufs_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + int ret = 0; + + switch (status) { + case PRE_CHANGE: + /* refer to hba */ + ufs->hba = hba; + + /* hci */ + exynos_ufs_config_intr(ufs, DFES_DEF_DL_ERRS, UNIP_DL_LYR); + exynos_ufs_config_intr(ufs, DFES_DEF_N_ERRS, UNIP_N_LYR); + exynos_ufs_config_intr(ufs, DFES_DEF_T_ERRS, UNIP_T_LYR); + + exynos_ufs_ctrl_clk(ufs, true); + exynos_ufs_select_refclk(ufs, true); + exynos_ufs_gate_clk(ufs, false); + exynos_ufs_set_hwacg_control(ufs, false); + + if (ufs->num_rx_lanes == 0 || ufs->num_tx_lanes == 0) { + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILRXDATALANES), + &ufs->num_rx_lanes); + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILTXDATALANES), + &ufs->num_tx_lanes); + WARN(ufs->num_rx_lanes != ufs->num_tx_lanes, + "available data lane is not equal(rx:%d, tx:%d)\n", + ufs->num_rx_lanes, ufs->num_tx_lanes); + } + + ufs->mclk_rate = clk_get_rate(ufs->clk_unipro); + + ret = ufs_pre_link(ufs); + break; + case POST_CHANGE: + /* UIC configuration table after link startup */ + ret = ufs_post_link(ufs); + break; + default: + break; + } + + return ret; +} + +static int exynos_ufs_pwr_change_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status, + struct ufs_pa_layer_attr *pwr_max, + struct ufs_pa_layer_attr *pwr_req) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + struct uic_pwr_mode *act_pmd = &ufs->act_pmd_parm; + int ret = 0; + + switch (status) { + case PRE_CHANGE: + + /* Set PMC parameters to be requested */ + exynos_ufs_init_pmc_req(hba, pwr_max, pwr_req); + + /* UIC configuration table before power mode change */ + ret = ufs_pre_gear_change(ufs, act_pmd); + + break; + case POST_CHANGE: + /* UIC configuration table after power mode change */ + ret = ufs_post_gear_change(ufs); + + dev_info(ufs->dev, + "Power mode change(%d): M(%d)G(%d)L(%d)HS-series(%d)\n", + ret, act_pmd->mode, act_pmd->gear, + act_pmd->lane, act_pmd->hs_series); + break; + default: + break; + } + + return ret; +} + +static void exynos_ufs_set_nexus_t_xfer_req(struct ufs_hba *hba, + int tag, struct scsi_cmnd *cmd) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + u32 type; + + type = hci_readl(ufs, HCI_UTRL_NEXUS_TYPE); + + if (cmd) + type |= (1 << tag); + else + type &= ~(1 << tag); + + hci_writel(ufs, type, HCI_UTRL_NEXUS_TYPE); +} + +static void exynos_ufs_set_nexus_t_task_mgmt(struct ufs_hba *hba, int tag, u8 tm_func) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + u32 type; + + type = hci_readl(ufs, HCI_UTMRL_NEXUS_TYPE); + + switch (tm_func) { + case UFS_ABORT_TASK: + case UFS_QUERY_TASK: + type |= (1 << tag); + break; + case UFS_ABORT_TASK_SET: + case UFS_CLEAR_TASK_SET: + case UFS_LOGICAL_RESET: + case UFS_QUERY_TASK_SET: + type &= ~(1 << tag); + break; + } + + hci_writel(ufs, type, HCI_UTMRL_NEXUS_TYPE); +} + +static void exynos_ufs_hibern8_notify(struct ufs_hba *hba, + u8 enter, bool notify) +{ + switch (notify) { + case PRE_CHANGE: + exynos_ufs_pre_hibern8(hba, enter); + break; + case POST_CHANGE: + exynos_ufs_post_hibern8(hba, enter); + break; + default: + break; + } +} + +static int __exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + +// pm_qos_update_request(&ufs->pm_qos_int, 0); + + exynos_ufs_dev_reset_ctrl(ufs, false); + + exynos_ufs_ctrl_phy_pwr(ufs, false); + + return 0; +} + +static int __exynos_ufs_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + int ret = 0; + + exynos_ufs_ctrl_phy_pwr(ufs, true); + + /* system init */ + ret = exynos_ufs_init_system(ufs); + if (ret) + return ret; + + if (ufshcd_is_clkgating_allowed(hba)) + clk_prepare_enable(ufs->clk_hci); + exynos_ufs_ctrl_auto_hci_clk(ufs, false); + /* secure log */ +// exynos_smc(SMC_CMD_LOG, 0, 0, 2); + + if (ufshcd_is_clkgating_allowed(hba)) + clk_disable_unprepare(ufs->clk_hci); + + return 0; +} + +static u8 exynos_ufs_get_unipro_direct(struct ufs_hba *hba, int num) +{ + u32 offset[] = { + UNIP_DME_LINKSTARTUP_CNF_RESULT, + UNIP_DME_HIBERN8_ENTER_CNF_RESULT, + UNIP_DME_HIBERN8_EXIT_CNF_RESULT, + UNIP_DME_PWR_IND_RESULT, + UNIP_DME_HIBERN8_ENTER_IND_RESULT, + UNIP_DME_HIBERN8_EXIT_IND_RESULT + }; + + struct exynos_ufs *ufs = to_exynos_ufs(hba); + + return unipro_readl(ufs, offset[num]); +} + +static struct ufs_hba_variant_ops exynos_ufs_ops = { + .init = exynos_ufs_init, + .host_reset = exynos_ufs_host_reset, + .pre_setup_clocks = exynos_ufs_pre_setup_clocks, + .setup_clocks = exynos_ufs_setup_clocks, + .link_startup_notify = exynos_ufs_link_startup_notify, + .pwr_change_notify = exynos_ufs_pwr_change_notify, + .set_nexus_t_xfer_req = exynos_ufs_set_nexus_t_xfer_req, + .set_nexus_t_task_mgmt = exynos_ufs_set_nexus_t_task_mgmt, + .hibern8_notify = exynos_ufs_hibern8_notify, + .dbg_register_dump = exynos_ufs_dump_debug_info, + .suspend = __exynos_ufs_suspend, + .resume = __exynos_ufs_resume, + .get_unipro_result = exynos_ufs_get_unipro_direct, +}; + +static int exynos_ufs_populate_dt_sys_per_feature(struct device *dev, + struct exynos_ufs *ufs, int index) +{ + struct device_node *np; + struct exynos_ufs_sys *sys = &ufs->sys; + struct resource io_res; + int ret; + const char *const name[NUM_OF_SYSREG] = { + "ufs-io-coherency", + }; + + np = of_get_child_by_name(dev->of_node, name[index]); + if (!np) { + dev_err(dev, "failed to get ufs-sys node\n"); + return -ENODEV; + } + + ret = of_address_to_resource(np, 0, &io_res); + if (ret) { + dev_err(dev, "failed to get i/o address %s\n", name[index]); + if (ret == -EINVAL) + ret = 0; + } else { + sys->reg_sys[index] = devm_ioremap_resource(dev, &io_res); + if (IS_ERR(sys->reg_sys[index])) { + dev_err(dev, "failed to ioremap sysreg\n"); + ret = -ENOMEM; + } else { + ret = of_property_read_u32(np, "mask", + &sys->mask[index]); + ret = of_property_read_u32(np, "bits", + &sys->bits[index]); + if (ret) + ret = -EINVAL; + } + } + + of_node_put(np); + + return ret; +} + +static int exynos_ufs_populate_dt_sys(struct device *dev, struct exynos_ufs *ufs) +{ + int i = 0; + int ret; + + for (i = 0 ; i < NUM_OF_SYSREG ; i++) { + ret = exynos_ufs_populate_dt_sys_per_feature(dev, ufs, i); + if (ret && ret != -ENODEV) + break; + } + + return ret; +} + +static int exynos_ufs_populate_dt_phy(struct device *dev, struct exynos_ufs *ufs) +{ + struct device_node *ufs_phy, *phy_sys; + struct exynos_ufs_phy *phy = &ufs->phy; + struct resource io_res; + int ret; + + ufs_phy = of_get_child_by_name(dev->of_node, "ufs-phy"); + if (!ufs_phy) { + dev_err(dev, "failed to get ufs-phy node\n"); + return -ENODEV; + } + + ret = of_address_to_resource(ufs_phy, 0, &io_res); + if (ret) { + dev_err(dev, "failed to get i/o address phy pma\n"); + goto err_0; + } + + phy->reg_pma = devm_ioremap_resource(dev, &io_res); + if (!phy->reg_pma) { + dev_err(dev, "failed to ioremap for phy pma\n"); + ret = -ENOMEM; + goto err_0; + } + + phy_sys = of_get_child_by_name(ufs_phy, "ufs-phy-sys"); + if (!phy_sys) { + dev_err(dev, "failed to get ufs-phy-sys node\n"); + ret = -ENODEV; + goto err_0; + } + + ret = of_address_to_resource(phy_sys, 0, &io_res); + if (ret) { + dev_err(dev, "failed to get i/o address ufs-phy pmu\n"); + goto err_1; + } + + phy->reg_pmu = devm_ioremap_resource(dev, &io_res); + if (!phy->reg_pmu) { + dev_err(dev, "failed to ioremap for ufs-phy pmu\n"); + ret = -ENOMEM; + } + +err_1: + of_node_put(phy_sys); +err_0: + of_node_put(ufs_phy); + + return ret; +} + +static int exynos_ufs_get_pwr_mode(struct device_node *np, + struct exynos_ufs *ufs) +{ + struct uic_pwr_mode *pmd = &ufs->req_pmd_parm; + + pmd->mode = FAST_MODE; + + if (of_property_read_u8(np, "ufs,pmd-attr-lane", &pmd->lane)) + pmd->lane = 1; + + if (of_property_read_u8(np, "ufs,pmd-attr-gear", &pmd->gear)) + pmd->gear = 1; + + pmd->hs_series = PA_HS_MODE_B; + + return 0; +} + +static int exynos_ufs_populate_dt(struct device *dev, struct exynos_ufs *ufs) +{ + struct device_node *np = dev->of_node; + int ret; + + /* Get exynos-specific version for featuring */ + if (of_property_read_u32(np, "hw-rev", &ufs->hw_rev)) + ufs->hw_rev = UFS_VER_0004; + + ret = exynos_ufs_populate_dt_phy(dev, ufs); + if (ret) { + dev_err(dev, "failed to populate dt-phy\n"); + goto out; + } + + ret = exynos_ufs_populate_dt_sys(dev, ufs); + if (ret) + dev_err(dev, "failed to populate ufs-sys\n"); + + exynos_ufs_get_pwr_mode(np, ufs); + + if (of_property_read_u8(np, "brd-for-cal", &ufs->cal_param->board)) + ufs->cal_param->board = 0; + + if (of_property_read_u32(np, "ufs-pm-qos-int", &ufs->pm_qos_int_value)) + ufs->pm_qos_int_value = 0; + + if (of_property_read_u32(np, "ufs-pm-qos-fsys0", &ufs->pm_qos_fsys0_value)) + ufs->pm_qos_fsys0_value = 0; + + +out: + return ret; +} + +static u64 exynos_ufs_dma_mask = DMA_BIT_MASK(32); + +static int exynos_ufs_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct exynos_ufs *ufs; + struct resource *res; + int ret; + + ufs = devm_kzalloc(dev, sizeof(*ufs), GFP_KERNEL); + if (!ufs) { + dev_err(dev, "cannot allocate mem for exynos-ufs\n"); + return -ENOMEM; + } + + /* exynos-specific hci */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ufs->reg_hci = devm_ioremap_resource(dev, res); + if (!ufs->reg_hci) { + dev_err(dev, "cannot ioremap for hci vendor register\n"); + return -ENOMEM; + } + + /* unipro */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + ufs->reg_unipro = devm_ioremap_resource(dev, res); + if (!ufs->reg_unipro) { + dev_err(dev, "cannot ioremap for unipro register\n"); + return -ENOMEM; + } + + /* ufs protector */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 3); + ufs->reg_ufsp = devm_ioremap_resource(dev, res); + if (!ufs->reg_ufsp) { + dev_err(dev, "cannot ioremap for ufs protector register\n"); + return -ENOMEM; + } + + /* This must be before calling exynos_ufs_populate_dt */ + ret = ufs_init_cal(ufs, ufs_host_index, pdev); + if (ret) + return ret; + + ret = exynos_ufs_populate_dt(dev, ufs); + if (ret) { + dev_err(dev, "failed to get dt info.\n"); + return ret; + } + +#ifdef CONFIG_CPU_IDLE + ufs->idle_ip_index = exynos_get_idle_ip_index(dev_name(&pdev->dev)); + exynos_update_ip_idle_status(ufs->idle_ip_index, 0); +#endif + + ufs->dev = dev; + dev->platform_data = ufs; + dev->dma_mask = &exynos_ufs_dma_mask; + +// pm_qos_add_request(&ufs->pm_qos_int, PM_QOS_DEVICE_THROUGHPUT, 0); + + ret = ufshcd_pltfrm_init(pdev, &exynos_ufs_ops); + + return ret; +} + +static int exynos_ufs_remove(struct platform_device *pdev) +{ + struct exynos_ufs *ufs = dev_get_platdata(&pdev->dev); + + ufshcd_pltfrm_exit(pdev); + + pm_qos_remove_request(&ufs->pm_qos_fsys0); + + ufs->misc_flags = EXYNOS_UFS_MISC_TOGGLE_LOG; + + exynos_ufs_ctrl_phy_pwr(ufs, false); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int exynos_ufs_suspend(struct device *dev) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return ufshcd_system_suspend(hba); +} + +static int exynos_ufs_resume(struct device *dev) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return ufshcd_system_resume(hba); +} +#else +#define exynos_ufs_suspend NULL +#define exynos_ufs_resume NULL +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_RUNTIME +static int exynos_ufs_runtime_suspend(struct device *dev) +{ + return ufshcd_system_suspend(dev_get_drvdata(dev)); +} + +static int exynos_ufs_runtime_resume(struct device *dev) +{ + return ufshcd_system_resume(dev_get_drvdata(dev)); +} + +static int exynos_ufs_runtime_idle(struct device *dev) +{ + return ufshcd_runtime_idle(dev_get_drvdata(dev)); +} + +#else +#define exynos_ufs_runtime_suspend NULL +#define exynos_ufs_runtime_resume NULL +#define exynos_ufs_runtime_idle NULL +#endif /* CONFIG_PM_RUNTIME */ + +static void exynos_ufs_shutdown(struct platform_device *pdev) +{ + ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev)); +} + +static const struct dev_pm_ops exynos_ufs_dev_pm_ops = { + .suspend = exynos_ufs_suspend, + .resume = exynos_ufs_resume, + .runtime_suspend = exynos_ufs_runtime_suspend, + .runtime_resume = exynos_ufs_runtime_resume, + .runtime_idle = exynos_ufs_runtime_idle, +}; + +static const struct ufs_hba_variant exynos_ufs_drv_data = { + .ops = &exynos_ufs_ops, +}; + +static const struct of_device_id exynos_ufs_match[] = { + { .compatible = "samsung,exynos-ufs", }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_ufs_match); + +static struct platform_driver exynos_ufs_driver = { + .driver = { + .name = "exynos-ufs", + .owner = THIS_MODULE, + .pm = &exynos_ufs_dev_pm_ops, + .of_match_table = exynos_ufs_match, + .suppress_bind_attrs = true, + }, + .probe = exynos_ufs_probe, + .remove = exynos_ufs_remove, + .shutdown = exynos_ufs_shutdown, +}; + +module_platform_driver(exynos_ufs_driver); +MODULE_DESCRIPTION("Exynos Specific UFSHCI driver"); +MODULE_AUTHOR("Seungwon Jeon "); +MODULE_AUTHOR("Kiwoong Kim "); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/ufs/ufs-exynos.h b/drivers/scsi/ufs/ufs-exynos.h new file mode 100644 index 000000000000..4f24951185a4 --- /dev/null +++ b/drivers/scsi/ufs/ufs-exynos.h @@ -0,0 +1,666 @@ +/* + * UFS Host Controller driver for Exynos specific extensions + * + * Copyright (C) 2013-2014 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _UFS_EXYNOS_H_ +#define _UFS_EXYNOS_H_ + +#include +#include "ufs-cal-9810.h" + +#define UFS_VER_0004 4 +#define UFS_VER_0005 5 + +/* + * Exynos's Vendor specific registers for UFSHCI + */ +#define HCI_TXPRDT_ENTRY_SIZE 0x00 +#define HCI_RXPRDT_ENTRY_SIZE 0x04 +#define HCI_TO_CNT_DIV_VAL 0x08 +#define HCI_1US_TO_CNT_VAL 0x0C + #define CNT_VAL_1US_MASK 0x3ff +#define HCI_INVALID_UPIU_CTRL 0x10 +#define HCI_INVALID_UPIU_BADDR 0x14 +#define HCI_INVALID_UPIU_UBADDR 0x18 +#define HCI_INVALID_UTMR_OFFSET_ADDR 0x1C +#define HCI_INVALID_UTR_OFFSET_ADDR 0x20 +#define HCI_INVALID_DIN_OFFSET_ADDR 0x24 +#define HCI_VENDOR_SPECIFIC_IS 0x38 +#define HCI_VENDOR_SPECIFIC_IE 0x3C +#define HCI_UTRL_NEXUS_TYPE 0x40 +#define HCI_UTMRL_NEXUS_TYPE 0x44 +#define HCI_E2EFC_CTRL 0x48 +#define HCI_SW_RST 0x50 + #define UFS_LINK_SW_RST (1 << 0) + #define UFS_UNIPRO_SW_RST (1 << 1) + #define UFS_SW_RST_MASK (UFS_UNIPRO_SW_RST | UFS_LINK_SW_RST) +#define HCI_LINK_VERSION 0x54 +#define HCI_IDLE_TIMER_CONFIG 0x58 +#define HCI_RX_UPIU_MATCH_ERROR_CODE 0x5C +#define HCI_DATA_REORDER 0x60 +#define HCI_MAX_DOUT_DATA_SIZE 0x64 +#define HCI_UNIPRO_APB_CLK_CTRL 0x68 +#define HCI_AXIDMA_RWDATA_BURST_LEN 0x6C + #define BURST_LEN(x) ((x) << 27 | (x)) + #define WLU_EN (1 << 31) + #define AXIDMA_RWDATA_BURST_LEN (0xF) +#define HCI_GPIO_OUT 0x70 +#define HCI_WRITE_DMA_CTRL 0x74 +#define HCI_ERROR_EN_PA_LAYER 0x78 +#define HCI_ERROR_EN_DL_LAYER 0x7C +#define HCI_ERROR_EN_N_LAYER 0x80 +#define HCI_ERROR_EN_T_LAYER 0x84 +#define HCI_ERROR_EN_DME_LAYER 0x88 +#define HCI_UFSHCI_V2P1_CTRL 0X8C +#define IA_TICK_SEL BIT(16) +#define HCI_REQ_HOLD_EN 0xAC + +#define HCI_CLKSTOP_CTRL 0xB0 + #define REFCLKOUT_STOP BIT(4) + #define MPHY_APBCLK_STOP BIT(3) + #define REFCLK_STOP BIT(2) + #define UNIPRO_MCLK_STOP BIT(1) + #define UNIPRO_PCLK_STOP BIT(0) + #define CLK_STOP_ALL (REFCLKOUT_STOP |\ + REFCLK_STOP |\ + UNIPRO_MCLK_STOP |\ + UNIPRO_PCLK_STOP) + +#define HCI_FORCE_HCS 0xB4 + #define REFCLKOUT_STOP_EN BIT(11) + #define MPHY_APBCLK_STOP_EN BIT(10) + #define UFSP_DRCG_EN BIT(8) //FMP + #define REFCLK_STOP_EN BIT(7) + #define UNIPRO_PCLK_STOP_EN BIT(6) + #define UNIPRO_MCLK_STOP_EN BIT(5) + #define HCI_CORECLK_STOP_EN BIT(4) + #define CLK_STOP_CTRL_EN_ALL (UFSP_DRCG_EN |\ + MPHY_APBCLK_STOP_EN |\ + REFCLKOUT_STOP_EN |\ + REFCLK_STOP_EN |\ + UNIPRO_PCLK_STOP_EN |\ + UNIPRO_MCLK_STOP_EN) + +#define HCI_FSM_MONITOR 0xC0 +#define HCI_PRDT_HIT_RATIO 0xC4 +#define HCI_DMA0_MONITOR_STATE 0xC8 +#define HCI_DMA0_MONITOR_CNT 0xCC +#define HCI_DMA1_MONITOR_STATE 0xD0 +#define HCI_DMA1_MONITOR_CNT 0xD4 + +#define HCI_UFS_AXI_DMA_IF_CTRL 0xF8 +#define HCI_UFS_ACG_DISABLE 0xFC + #define HCI_UFS_ACG_DISABLE_EN BIT(0) +#define HCI_IOP_ACG_DISABLE 0x100 + #define HCI_IOP_ACG_DISABLE_EN BIT(0) +#define HCI_MPHY_REFCLK_SEL 0x108 + #define MPHY_REFCLK_SEL BIT(0) +#define HCI_SMU_ABORT_MATCH_INFO 0x10C +#define HCI_DBR_DUPLICATION_INFO 0x120 + +#define HCI_DBR_TIMER_CONFIG 0x140 +#define HCI_DBR_TIMER_ENABLE 0x144 +#define HCI_DBR_TIMER_STATUS 0x148 + +#define HCI_UTRL_DBR_3_0_TIMER_EXPIRED_VALUE 0x150 +#define HCI_UTRL_DBR_7_4_TIMER_EXPIRED_VALUE 0x154 +#define HCI_UTRL_DBR_11_8_TIMER_EXPIRED_VALUE 0x158 +#define HCI_UTRL_DBR_15_12_TIMER_EXPIRED_VALUE 0x15C +#define HCI_UTMRL_DBR_3_0_TIMER_EXPIRED_VALUE 0x160 + +/* Device fatal error */ +#define DFES_ERR_EN BIT(31) +#define DFES_DEF_DL_ERRS (UIC_DATA_LINK_LAYER_ERROR_RX_BUF_OF |\ + UIC_DATA_LINK_LAYER_ERROR_PA_INIT) +#define DFES_DEF_N_ERRS (UIC_NETWORK_UNSUPPORTED_HEADER_TYPE |\ + UIC_NETWORK_BAD_DEVICEID_ENC |\ + UIC_NETWORK_LHDR_TRAP_PACKET_DROPPING) +#define DFES_DEF_T_ERRS (UIC_TRANSPORT_UNSUPPORTED_HEADER_TYPE |\ + UIC_TRANSPORT_UNKNOWN_CPORTID |\ + UIC_TRANSPORT_NO_CONNECTION_RX |\ + UIC_TRANSPORT_BAD_TC) + +/* TXPRDT defines */ +#define PRDT_PREFECT_EN BIT(31) +#define PRDT_SET_SIZE(x) ((x) & 0x1F) + +enum { + UNIP_PA_LYR = 0, + UNIP_DL_LYR, + UNIP_N_LYR, + UNIP_T_LYR, + UNIP_DME_LYR, +}; + +/* + * UNIPRO registers + */ +#define UNIP_COMP_VERSION 0x000 +#define UNIP_COMP_INFO 0x004 +#define UNIP_COMP_RESET 0x010 + +#define UNIP_DME_POWERON_REQ 0x7800 +#define UNIP_DME_POWERON_CNF_RESULT 0x7804 +#define UNIP_DME_POWEROFF_REQ 0x7810 +#define UNIP_DME_POWEROFF_CNF_RESULT 0x7814 +#define UNIP_DME_RESET_REQ 0x7820 +#define UNIP_DME_RESET_REQ_LEVEL 0x7824 +#define UNIP_DME_ENABLE_REQ 0x7830 +#define UNIP_DME_ENABLE_CNF_RESULT 0x7834 +#define UNIP_DME_ENDPOINTRESET_REQ 0x7840 +#define UNIP_DME_ENDPOINTRESET_CNF_RESULT 0x7844 +#define UNIP_DME_LINKSTARTUP_REQ 0x7850 +#define UNIP_DME_LINKSTARTUP_CNF_RESULT 0x7854 +#define UNIP_DME_HIBERN8_ENTER_REQ 0x7860 +#define UNIP_DME_HIBERN8_ENTER_CNF_RESULT 0x7864 +#define UNIP_DME_HIBERN8_ENTER_IND_RESULT 0x7868 +#define UNIP_DME_HIBERN8_EXIT_REQ 0x7870 +#define UNIP_DME_HIBERN8_EXIT_CNF_RESULT 0x7874 +#define UNIP_DME_HIBERN8_EXIT_IND_RESULT 0x7878 +#define UNIP_DME_PWR_REQ 0x7880 +#define UNIP_DME_PWR_REQ_POWERMODE 0x7884 +#define UNIP_DME_PWR_REQ_LOCALL2TIMER0 0x7888 +#define UNIP_DME_PWR_REQ_LOCALL2TIMER1 0x788C +#define UNIP_DME_PWR_REQ_LOCALL2TIMER2 0x7890 +#define UNIP_DME_PWR_REQ_REMOTEL2TIMER0 0x78B8 +#define UNIP_DME_PWR_REQ_REMOTEL2TIMER1 0x78BC +#define UNIP_DME_PWR_REQ_REMOTEL2TIMER2 0x78C0 +#define UNIP_DME_PWR_CNF_RESULT 0x78E8 +#define UNIP_DME_PWR_IND_RESULT 0x78EC +#define UNIP_DME_TEST_MODE_REQ 0x7900 +#define UNIP_DME_TEST_MODE_CNF_RESULT 0x7904 + +#define UNIP_DME_ERROR_IND_LAYER 0x0C0 +#define UNIP_DME_ERROR_IND_ERRCODE 0x0C4 +#define UNIP_DME_PACP_CNFBIT 0x0C8 +#define UNIP_DME_DL_FRAME_IND 0x0D0 +#define UNIP_DME_INTR_STATUS 0x0E0 +#define UNIP_DME_INTR_ENABLE 0x0E4 + +#define UNIP_DME_GETSET_CONTROL 0x7A00 +#define UNIP_DME_GETSET_ADDR 0x7A04 +#define UNIP_DME_GETSET_WDATA 0x7A08 +#define UNIP_DME_GETSET_RDATA 0x7A0C +#define UNIP_DME_GETSET_RESULT 0x7A10 +#define UNIP_DME_PEER_GETSET_CONTROL 0x7A20 +#define UNIP_DME_PEER_GETSET_ADDR 0x7A24 +#define UNIP_DME_PEER_GETSET_WDATA 0x7A28 +#define UNIP_DME_PEER_GETSET_RDATA 0x7A2C +#define UNIP_DME_PEER_GETSET_RESULT 0x7A30 + +#define UNIP_DME_INTR_STATUS_LSB 0x7B00 +#define UNIP_DME_INTR_STATUS_MSB 0x7B04 +#define UNIP_DME_INTR_ERROR_CODE 0x7B20 +#define UNIP_DME_DISCARD_PORT_ID 0x7B24 +#define UNIP_DME_DBG_OPTION_SUITE 0x7C00 +#define UNIP_DME_DBG_CTRL_FSM 0x7D00 +#define UNIP_DME_DBG_FLAG_STATUS 0x7D14 +#define UNIP_DME_DBG_LINKCFG_FSM 0x7D18 + +#define UNIP_DME_INTR_ERROR_CODE 0x7B20 +#define UNIP_DME_DEEPSTALL_ENTER_REQ 0x7910 +#define UNIP_DME_DISCARD_CPORT_ID 0x7B24 + +#define UNIP_DBG_FORCE_DME_CTRL_STATE 0x150 +#define UNIP_DBG_AUTO_DME_LINKSTARTUP 0x158 +#define UNIP_DBG_PA_CTRLSTATE 0x15C +#define UNIP_DBG_PA_TX_STATE 0x160 +#define UNIP_DBG_BREAK_DME_CTRL_STATE 0x164 +#define UNIP_DBG_STEP_DME_CTRL_STATE 0x168 +#define UNIP_DBG_NEXT_DME_CTRL_STATE 0x16C + +/* + * UFS Protector registers + */ +#define UFSPRCTRL 0x000 +#define UFSPRSTAT 0x008 +#define UFSPRSECURITY 0x010 + #define NSSMU BIT(14) +#define DESCTYPE(type) ((type & 0x3) << 19) +#define ARPROTPRDT(type) ((type & 0x3) << 16) +#define ARPROTDESC(type) ((type & 0x3) << 9) +#define ARPROTDATA(type) ((type & 0x3) << 6) +#define AWPROTDESC(type) ((type & 0x3) << 3) +#define AWPROTDATA(type) ((type & 0x3)) +#define CFG_AXPROT(type) (ARPROTPRDT(type) | ARPROTDESC(type) | \ + ARPROTDATA(type) | AWPROTDESC(type) | \ + AWPROTDATA(type)) +#define UFSPVERSION 0x01C +#define UFSPRENCKEY0 0x020 +#define UFSPRENCKEY1 0x024 +#define UFSPRENCKEY2 0x028 +#define UFSPRENCKEY3 0x02C +#define UFSPRENCKEY4 0x030 +#define UFSPRENCKEY5 0x034 +#define UFSPRENCKEY6 0x038 +#define UFSPRENCKEY7 0x03C +#define UFSPRTWKEY0 0x040 +#define UFSPRTWKEY1 0x044 +#define UFSPRTWKEY2 0x048 +#define UFSPRTWKEY3 0x04C +#define UFSPRTWKEY4 0x050 +#define UFSPRTWKEY5 0x054 +#define UFSPRTWKEY6 0x058 +#define UFSPRTWKEY7 0x05C +#define UFSPWCTRL 0x100 +#define UFSPWSTAT 0x108 +#define UFSPWSECURITY 0x110 +#define UFSPWENCKEY0 0x120 +#define UFSPWENCKEY1 0x124 +#define UFSPWENCKEY2 0x128 +#define UFSPWENCKEY3 0x12C +#define UFSPWENCKEY4 0x130 +#define UFSPWENCKEY5 0x134 +#define UFSPWENCKEY6 0x138 +#define UFSPWENCKEY7 0x13C +#define UFSPWTWKEY0 0x140 +#define UFSPWTWKEY1 0x144 +#define UFSPWTWKEY2 0x148 +#define UFSPWTWKEY3 0x14C +#define UFSPWTWKEY4 0x150 +#define UFSPWTWKEY5 0x154 +#define UFSPWTWKEY6 0x158 +#define UFSPWTWKEY7 0x15C +#define UFSPSBEGIN0 0x200 +#define UFSPSEND0 0x204 +#define UFSPSLUN0 0x208 +#define UFSPSCTRL0 0x20C +#define UFSPSBEGIN1 0x210 +#define UFSPSEND1 0x214 +#define UFSPSLUN1 0x218 +#define UFSPSCTRL1 0x21C +#define UFSPSBEGIN2 0x220 +#define UFSPSEND2 0x224 +#define UFSPSLUN2 0x228 +#define UFSPSCTRL2 0x22C +#define UFSPSBEGIN3 0x230 +#define UFSPSEND3 0x234 +#define UFSPSLUN3 0x238 +#define UFSPSCTRL3 0x23C +#define UFSPSBEGIN4 0x240 +#define UFSPSEND4 0x244 +#define UFSPSLUN4 0x248 +#define UFSPSCTRL4 0x24C +#define UFSPSBEGIN5 0x250 +#define UFSPSEND5 0x254 +#define UFSPSLUN5 0x258 +#define UFSPSCTRL5 0x25C +#define UFSPSBEGIN6 0x260 +#define UFSPSEND6 0x264 +#define UFSPSLUN6 0x268 +#define UFSPSCTRL6 0x26C +#define UFSPSBEGIN7 0x270 +#define UFSPSEND7 0x274 +#define UFSPSLUN7 0x278 +#define UFSPSCTRL7 0x27C + +/* + * MIBs for PA debug registers + */ +#define PA_DBG_CLK_PERIOD 0x9514 +#define PA_DBG_RXPHY_CFGUPDT 0x9519 +#define PA_DBG_MODE 0x9529 +#define PA_DBG_AUTOMODE_THLD 0x9536 +#define PA_DBG_OV_TM 0x200 +#define PA_DBG_RESUME_HIBERN8 0x9550 +#define PA_DBG_OPTION_SUITE 0x9564 + +/* + * MIBs for Transport Layer debug registers + */ +#define T_DBG_SKIP_INIT_HIBERN8_EXIT 0xc001 + +/* + * Exynos MPHY attributes + */ +#define TX_LINERESET_N_VAL 0x0277 + #define TX_LINERESET_N(v) (((v) >> 10) & 0xff) +#define TX_LINERESET_P_VAL 0x027D + #define TX_LINERESET_P(v) (((v) >> 12) & 0xff) +#define TX_OV_SLEEP_CNT_TIMER 0x028E + #define TX_OV_H8_ENTER_EN (1 << 7) + #define TX_OV_SLEEP_CNT(v) (((v) >> 5) & 0x7f) + +#define TX_HIGH_Z_CNT_11_08 0x028c + #define TX_HIGH_Z_CNT_H(v) (((v) >> 8) & 0xf) +#define TX_HIGH_Z_CNT_07_00 0x028d + #define TX_HIGH_Z_CNT_L(v) ((v) & 0xff) +#define TX_BASE_NVAL_07_00 0x0293 + #define TX_BASE_NVAL_L(v) ((v) & 0xff) +#define TX_BASE_NVAL_15_08 0x0294 + #define TX_BASE_NVAL_H(v) (((v) >> 8) & 0xff) +#define TX_GRAN_NVAL_07_00 0x0295 + #define TX_GRAN_NVAL_L(v) ((v) & 0xff) +#define TX_GRAN_NVAL_10_08 0x0296 + #define TX_GRAN_NVAL_H(v) (((v) >> 8) & 0x3) + +#define RX_FILLER_ENABLE 0x0316 + #define RX_FILLER_EN (1 << 1) +#define RX_LCC_IGNORE 0x0318 +#define RX_LINERESET_VAL 0x0317 + #define RX_LINERESET(v) (((v) >> 12) & 0xff) +#define RX_SYNC_MASK_LENGTH 0x0321 +#define RX_HIBERN8_WAIT_VAL_BIT_20_16 0x0331 +#define RX_HIBERN8_WAIT_VAL_BIT_15_08 0x0332 +#define RX_HIBERN8_WAIT_VAL_BIT_07_00 0x0333 + +#define RX_OV_SLEEP_CNT_TIMER 0x0340 + #define RX_OV_SLEEP_CNT(v) (((v) >> 6) & 0x1f) +#define RX_OV_STALL_CNT_TIMER 0x0341 + #define RX_OV_STALL_CNT(v) (((v) >> 4) & 0xff) +#define RX_BASE_NVAL_07_00 0x0355 + #define RX_BASE_NVAL_L(v) ((v) & 0xff) +#define RX_BASE_NVAL_15_08 0x0354 + #define RX_BASE_NVAL_H(v) (((v) >> 8) & 0xff) +#define RX_GRAN_NVAL_07_00 0x0353 + #define RX_GRAN_NVAL_L(v) ((v) & 0xff) +#define RX_GRAN_NVAL_10_08 0x0352 + #define RX_GRAN_NVAL_H(v) (((v) >> 8) & 0x3) + +#define CMN_PWM_CMN_CTRL 0x0402 + #define PWM_CMN_CTRL_MASK 0x3 +#define CMN_REFCLK_PLL_LOCK 0x0406 +#define CMN_REFCLK_STREN 0x044C +#define CMN_REFCLK_OUT 0x044E +#define CMN_REFCLK_SEL_PLL 0x044F + +#define PHY_PMA_COMN_ADDR(reg) (reg) +#define PHY_PMA_TRSV_ADDR(reg, lane) ((reg) + (0x140 * (lane))) + +/* + * Driver specific definitions + */ + +enum { + PHY_CFG_NONE = 0, + PHY_PCS_COMN, + PHY_PCS_RXTX, + PHY_PMA_COMN, + PHY_PMA_TRSV, + PHY_PLL_WAIT, + PHY_CDR_WAIT, + UNIPRO_STD_MIB, + UNIPRO_DBG_MIB, + UNIPRO_DBG_APB, + + // Since exynos8895 + PHY_PCS_RX, + PHY_PCS_TX, + PHY_PCS_RX_PRD, + PHY_PCS_TX_PRD, + UNIPRO_DBG_PRD, + PHY_PMA_TRSV_LANE1_SQ_OFF, + COMMON_WAIT, +}; + +enum { + TX_LANE_0 = 0, + TX_LANE_1 = 1, + TX_LANE_2 = 2, + TX_LANE_3 = 3, + RX_LANE_0 = 4, + RX_LANE_1 = 5, + RX_LANE_2 = 6, + RX_LANE_3 = 7, +}; + +enum { + __PMD_PWM_G1_L1, + __PMD_PWM_G1_L2, + __PMD_PWM_G2_L1, + __PMD_PWM_G2_L2, + __PMD_PWM_G3_L1, + __PMD_PWM_G3_L2, + __PMD_PWM_G4_L1, + __PMD_PWM_G4_L2, + __PMD_PWM_G5_L1, + __PMD_PWM_G5_L2, + __PMD_HS_G1_L1, + __PMD_HS_G1_L2, + __PMD_HS_G2_L1, + __PMD_HS_G2_L2, + __PMD_HS_G3_L1, + __PMD_HS_G3_L2, +}; + +#define PMD_PWM_G1_L1 (1U << __PMD_PWM_G1_L1) +#define PMD_PWM_G1_L2 (1U << __PMD_PWM_G1_L2) +#define PMD_PWM_G2_L1 (1U << __PMD_PWM_G2_L1) +#define PMD_PWM_G2_L2 (1U << __PMD_PWM_G2_L2) +#define PMD_PWM_G3_L1 (1U << __PMD_PWM_G3_L1) +#define PMD_PWM_G3_L2 (1U << __PMD_PWM_G3_L2) +#define PMD_PWM_G4_L1 (1U << __PMD_PWM_G4_L1) +#define PMD_PWM_G4_L2 (1U << __PMD_PWM_G4_L2) +#define PMD_PWM_G5_L1 (1U << __PMD_PWM_G5_L1) +#define PMD_PWM_G5_L2 (1U << __PMD_PWM_G5_L2) +#define PMD_HS_G1_L1 (1U << __PMD_HS_G1_L1) +#define PMD_HS_G1_L2 (1U << __PMD_HS_G1_L2) +#define PMD_HS_G2_L1 (1U << __PMD_HS_G2_L1) +#define PMD_HS_G2_L2 (1U << __PMD_HS_G2_L2) +#define PMD_HS_G3_L1 (1U << __PMD_HS_G3_L1) +#define PMD_HS_G3_L2 (1U << __PMD_HS_G3_L2) + +#define PMD_ALL (PMD_HS_G3_L2 - 1) +#define PMD_PWM (PMD_PWM_G4_L2 - 1) +#define PMD_HS (PMD_ALL ^ PMD_PWM) + +struct ufs_phy_cfg { + u32 addr; + u32 val; + u32 flg; + u32 lyr; +}; + +struct exynos_ufs_soc { + struct ufs_phy_cfg *tbl_phy_init; + struct ufs_phy_cfg *tbl_post_phy_init; + struct ufs_phy_cfg *tbl_calib_of_pwm; + struct ufs_phy_cfg *tbl_calib_of_hs_rate_a; + struct ufs_phy_cfg *tbl_calib_of_hs_rate_b; + struct ufs_phy_cfg *tbl_post_calib_of_pwm; + struct ufs_phy_cfg *tbl_post_calib_of_hs_rate_a; + struct ufs_phy_cfg *tbl_post_calib_of_hs_rate_b; + struct ufs_phy_cfg *tbl_lpa_restore; + struct ufs_phy_cfg *tbl_pre_clk_off; + struct ufs_phy_cfg *tbl_post_clk_on; + struct ufs_phy_cfg *tbl_lane1_sq_off; +}; + +struct exynos_ufs_phy { + void __iomem *reg_pma; + void __iomem *reg_pmu; + struct exynos_ufs_soc *soc; +}; + +#define NUM_OF_SYSREG 1 +struct exynos_ufs_sys { + void __iomem *reg_sys[NUM_OF_SYSREG]; + u32 mask[NUM_OF_SYSREG]; + u32 bits[NUM_OF_SYSREG]; +}; + +struct exynos_ufs_clk_info { + struct list_head list; + struct clk *clk; + const char *name; + unsigned long freq; +}; + +struct exynos_ufs_misc_log { + struct list_head clk_list_head; + bool isolation; +}; + +struct exynos_ufs_sfr_log { + const char* name; + const u32 offset; +#define LOG_STD_HCI_SFR 0xFFFFFFF0 +#define LOG_VS_HCI_SFR 0xFFFFFFF1 +#define LOG_FMP_SFR 0xFFFFFFF2 +#define LOG_UNIPRO_SFR 0xFFFFFFF3 +#define LOG_PMA_SFR 0xFFFFFFF4 + u32 val; +}; + +struct exynos_ufs_attr_log { + const u32 offset; + u32 res; + u32 val; +}; + +struct exynos_ufs_debug { + struct exynos_ufs_sfr_log* std_sfr; + struct exynos_ufs_sfr_log* sfr; + struct exynos_ufs_attr_log* attr; + struct exynos_ufs_misc_log misc; +}; + +struct exynos_smu_data { + struct exynos_smu_variant_ops *vops; + struct platform_device *pdev; +}; + +struct exynos_fmp_data { + struct exynos_fmp_variant_ops *vops; + struct platform_device *pdev; +}; + +struct exynos_ufs { + struct device *dev; + struct ufs_hba *hba; + + void __iomem *reg_hci; + void __iomem *reg_unipro; + void __iomem *reg_ufsp; + + struct clk *clk_hci; + struct clk *pclk; + struct clk *clk_unipro; + struct clk *clk_refclk_1; + struct clk *clk_refclk_2; + struct clk *clk_phy_symb[4]; + u32 mclk_rate; + u32 pwm_freq; + + int num_rx_lanes; + int num_tx_lanes; + + struct exynos_ufs_phy phy; + struct exynos_ufs_sys sys; + struct uic_pwr_mode req_pmd_parm; + struct uic_pwr_mode act_pmd_parm; + + struct exynos_smu_data smu; + struct exynos_fmp_data fmp; + + u32 rx_min_actv_time_cap; + u32 rx_hibern8_time_cap; + u32 tx_hibern8_time_cap; + + u32 opts; +#define EXYNOS_UFS_OPTS_SET_LINE_INIT_PREP_LEN BIT(1) + + /* for miscellaneous control */ + unsigned long misc_flags; +#define EXYNOS_UFS_MISC_TOGGLE_LOG BIT(0) + + struct exynos_ufs_debug debug; + + /* Support system power mode */ + int idle_ip_index; + + u32 hw_rev; + + struct pm_qos_request pm_qos_int; + s32 pm_qos_int_value; + struct pm_qos_request pm_qos_fsys0; + s32 pm_qos_fsys0_value; + bool lane1_poweroff; + struct ufs_cal_param *cal_param; +}; + +static inline struct exynos_ufs *to_exynos_ufs(struct ufs_hba *hba) +{ + return dev_get_platdata(hba->dev); +} + +#ifndef __EXYNOS_UFS_MMIO_FUNC__ +#define __EXYNOS_UFS_MMIO_FUNC__ +#define EXYNOS_UFS_MMIO_FUNC(name) \ +static inline void name##_writel(struct exynos_ufs *ufs, u32 val, u32 reg) \ +{ \ + writel(val, ufs->reg_##name + reg); \ +} \ + \ +static inline u32 name##_readl(struct exynos_ufs *ufs, u32 reg) \ +{ \ + return readl(ufs->reg_##name + reg); \ +} + +EXYNOS_UFS_MMIO_FUNC(hci); +EXYNOS_UFS_MMIO_FUNC(unipro); +EXYNOS_UFS_MMIO_FUNC(ufsp); + +static inline void phy_pma_writel(struct exynos_ufs *ufs, u32 val, u32 reg) +{ + u32 reg1 = hci_readl(ufs, HCI_CLKSTOP_CTRL); + + hci_writel(ufs, reg1 & ~MPHY_APBCLK_STOP, HCI_CLKSTOP_CTRL); + writel(val, ufs->phy.reg_pma + reg); + hci_writel(ufs, reg1 | MPHY_APBCLK_STOP, HCI_CLKSTOP_CTRL); +} + +static inline u32 phy_pma_readl(struct exynos_ufs *ufs, u32 reg) +{ + u32 reg1 = hci_readl(ufs, HCI_CLKSTOP_CTRL); + + hci_writel(ufs, reg1 & ~MPHY_APBCLK_STOP, HCI_CLKSTOP_CTRL); + reg = readl(ufs->phy.reg_pma + reg); + hci_writel(ufs, reg1 | MPHY_APBCLK_STOP, HCI_CLKSTOP_CTRL); + + return reg; +} +#endif + +/* Structure for ufs cmd logging */ +#define MAX_CMD_LOGS 128 + +struct ufs_cmd_logging_category { + unsigned char cmd_opcode; + unsigned int tag; + unsigned long lba; + unsigned int sct; + int retries; + u64 start_time; + u64 end_time; + unsigned long outstanding_reqs; + +}; + +struct ufs_cmd_info { + int first; + int last; + struct ufs_cmd_logging_category *addr_per_tag[16]; + struct ufs_cmd_logging_category data[MAX_CMD_LOGS]; + +}; + +extern void exynos_ufs_get_uic_info(struct ufs_hba *hba); +extern void exynos_ufs_dump_uic_info(struct ufs_hba *hba); +extern int exynos_ufs_init_dbg(struct ufs_hba *hba); +extern void exynos_ufs_show_uic_info(struct ufs_hba *hba); +extern void exynos_ufs_cmd_log_start(struct ufs_hba *hba, struct scsi_cmnd *cmd); +extern void exynos_ufs_cmd_log_end(struct ufs_hba *hba, int tag); + +#ifndef __EXYNOS_UFS_VS_DEBUG__ +#define __EXYNOS_UFS_VS_DEBUG__ +#endif + +#endif /* _UFS_EXYNOS_H_ */ -- 2.20.1