mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
cc52e15397
Add support for the ExynosAuto v9 SoC. This requires controlling the UFS IP shareability register via syscon and regmap. The offset of the register can be different according to the UFS instance and SoC specific offset value. As a result, we need to get the offset value from DT property. Unlike exynos7, this implementation has a different M-PHY setting which must be configured via exynosauto_ufs_pre_link. Link: https://lore.kernel.org/r/20211018124216.153072-12-chanho61.park@samsung.com Cc: Alim Akhtar <alim.akhtar@samsung.com> Cc: Kiwoong Kim <kwmad.kim@samsung.com> Cc: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> Signed-off-by: Chanho Park <chanho61.park@samsung.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
270 lines
7.4 KiB
C
270 lines
7.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* UFS Host Controller driver for Exynos specific extensions
|
|
*
|
|
* Copyright (C) 2014-2015 Samsung Electronics Co., Ltd.
|
|
*
|
|
*/
|
|
|
|
#ifndef _UFS_EXYNOS_H_
|
|
#define _UFS_EXYNOS_H_
|
|
|
|
/*
|
|
* UNIPRO registers
|
|
*/
|
|
#define UNIPRO_DBG_FORCE_DME_CTRL_STATE 0x150
|
|
|
|
/*
|
|
* MIBs for PA debug registers
|
|
*/
|
|
#define PA_DBG_CLK_PERIOD 0x9514
|
|
#define PA_DBG_TXPHY_CFGUPDT 0x9518
|
|
#define PA_DBG_RXPHY_CFGUPDT 0x9519
|
|
#define PA_DBG_MODE 0x9529
|
|
#define PA_DBG_SKIP_RESET_PHY 0x9539
|
|
#define PA_DBG_OV_TM 0x9540
|
|
#define PA_DBG_SKIP_LINE_RESET 0x9541
|
|
#define PA_DBG_LINE_RESET_REQ 0x9543
|
|
#define PA_DBG_OPTION_SUITE 0x9564
|
|
#define PA_DBG_OPTION_SUITE_DYN 0x9565
|
|
|
|
/*
|
|
* 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 VND_TX_CLK_PRD 0xAA
|
|
#define VND_TX_CLK_PRD_EN 0xA9
|
|
#define VND_TX_LINERESET_PVALUE0 0xAD
|
|
#define VND_TX_LINERESET_PVALUE1 0xAC
|
|
#define VND_TX_LINERESET_PVALUE2 0xAB
|
|
|
|
#define TX_LINE_RESET_TIME 3200
|
|
|
|
#define VND_RX_CLK_PRD 0x12
|
|
#define VND_RX_CLK_PRD_EN 0x11
|
|
#define VND_RX_LINERESET_VALUE0 0x1D
|
|
#define VND_RX_LINERESET_VALUE1 0x1C
|
|
#define VND_RX_LINERESET_VALUE2 0x1B
|
|
|
|
#define RX_LINE_RESET_TIME 1000
|
|
|
|
#define RX_FILLER_ENABLE 0x0316
|
|
#define RX_FILLER_EN (1 << 1)
|
|
#define RX_LINERESET_VAL 0x0317
|
|
#define RX_LINERESET(v) (((v) >> 12) & 0xFF)
|
|
#define RX_LCC_IGNORE 0x0318
|
|
#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_CLK_CTRL 0x0402
|
|
#define PWM_CLK_CTRL_MASK 0x3
|
|
|
|
#define IATOVAL_NSEC 20000 /* unit: ns */
|
|
#define UNIPRO_PCLK_PERIOD(ufs) (NSEC_PER_SEC / ufs->pclk_rate)
|
|
|
|
struct exynos_ufs;
|
|
|
|
/* vendor specific pre-defined parameters */
|
|
#define SLOW 1
|
|
#define FAST 2
|
|
|
|
#define RX_ADV_FINE_GRAN_SUP_EN 0x1
|
|
#define RX_ADV_FINE_GRAN_STEP_VAL 0x3
|
|
#define RX_ADV_MIN_ACTV_TIME_CAP 0x9
|
|
|
|
#define PA_GRANULARITY_VAL 0x6
|
|
#define PA_TACTIVATE_VAL 0x3
|
|
#define PA_HIBERN8TIME_VAL 0x20
|
|
|
|
#define PCLK_AVAIL_MIN 70000000
|
|
#define PCLK_AVAIL_MAX 167000000
|
|
|
|
struct exynos_ufs_uic_attr {
|
|
/* TX Attributes */
|
|
unsigned int tx_trailingclks;
|
|
unsigned int tx_dif_p_nsec;
|
|
unsigned int tx_dif_n_nsec;
|
|
unsigned int tx_high_z_cnt_nsec;
|
|
unsigned int tx_base_unit_nsec;
|
|
unsigned int tx_gran_unit_nsec;
|
|
unsigned int tx_sleep_cnt;
|
|
unsigned int tx_min_activatetime;
|
|
/* RX Attributes */
|
|
unsigned int rx_filler_enable;
|
|
unsigned int rx_dif_p_nsec;
|
|
unsigned int rx_hibern8_wait_nsec;
|
|
unsigned int rx_base_unit_nsec;
|
|
unsigned int rx_gran_unit_nsec;
|
|
unsigned int rx_sleep_cnt;
|
|
unsigned int rx_stall_cnt;
|
|
unsigned int rx_hs_g1_sync_len_cap;
|
|
unsigned int rx_hs_g2_sync_len_cap;
|
|
unsigned int rx_hs_g3_sync_len_cap;
|
|
unsigned int rx_hs_g1_prep_sync_len_cap;
|
|
unsigned int rx_hs_g2_prep_sync_len_cap;
|
|
unsigned int rx_hs_g3_prep_sync_len_cap;
|
|
/* Common Attributes */
|
|
unsigned int cmn_pwm_clk_ctrl;
|
|
/* Internal Attributes */
|
|
unsigned int pa_dbg_option_suite;
|
|
/* Changeable Attributes */
|
|
unsigned int rx_adv_fine_gran_sup_en;
|
|
unsigned int rx_adv_fine_gran_step;
|
|
unsigned int rx_min_actv_time_cap;
|
|
unsigned int rx_hibern8_time_cap;
|
|
unsigned int rx_adv_min_actv_time_cap;
|
|
unsigned int rx_adv_hibern8_time_cap;
|
|
unsigned int pa_granularity;
|
|
unsigned int pa_tactivate;
|
|
unsigned int pa_hibern8time;
|
|
};
|
|
|
|
struct exynos_ufs_drv_data {
|
|
const struct ufs_hba_variant_ops *vops;
|
|
struct exynos_ufs_uic_attr *uic_attr;
|
|
unsigned int quirks;
|
|
unsigned int opts;
|
|
/* SoC's specific operations */
|
|
int (*drv_init)(struct device *dev, struct exynos_ufs *ufs);
|
|
int (*pre_link)(struct exynos_ufs *ufs);
|
|
int (*post_link)(struct exynos_ufs *ufs);
|
|
int (*pre_pwr_change)(struct exynos_ufs *ufs,
|
|
struct ufs_pa_layer_attr *pwr);
|
|
int (*post_pwr_change)(struct exynos_ufs *ufs,
|
|
struct ufs_pa_layer_attr *pwr);
|
|
int (*pre_hce_enable)(struct exynos_ufs *ufs);
|
|
int (*post_hce_enable)(struct exynos_ufs *ufs);
|
|
};
|
|
|
|
struct ufs_phy_time_cfg {
|
|
u32 tx_linereset_p;
|
|
u32 tx_linereset_n;
|
|
u32 tx_high_z_cnt;
|
|
u32 tx_base_n_val;
|
|
u32 tx_gran_n_val;
|
|
u32 tx_sleep_cnt;
|
|
u32 rx_linereset;
|
|
u32 rx_hibern8_wait;
|
|
u32 rx_base_n_val;
|
|
u32 rx_gran_n_val;
|
|
u32 rx_sleep_cnt;
|
|
u32 rx_stall_cnt;
|
|
};
|
|
|
|
struct exynos_ufs {
|
|
struct ufs_hba *hba;
|
|
struct phy *phy;
|
|
void __iomem *reg_hci;
|
|
void __iomem *reg_unipro;
|
|
void __iomem *reg_ufsp;
|
|
struct clk *clk_hci_core;
|
|
struct clk *clk_unipro_main;
|
|
struct clk *clk_apb;
|
|
u32 pclk_rate;
|
|
u32 pclk_div;
|
|
u32 pclk_avail_min;
|
|
u32 pclk_avail_max;
|
|
unsigned long mclk_rate;
|
|
int avail_ln_rx;
|
|
int avail_ln_tx;
|
|
int rx_sel_idx;
|
|
struct ufs_pa_layer_attr dev_req_params;
|
|
struct ufs_phy_time_cfg t_cfg;
|
|
ktime_t entry_hibern8_t;
|
|
const struct exynos_ufs_drv_data *drv_data;
|
|
struct regmap *sysreg;
|
|
u32 shareability_reg_offset;
|
|
|
|
u32 opts;
|
|
#define EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL BIT(0)
|
|
#define EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB BIT(1)
|
|
#define EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL BIT(2)
|
|
#define EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX BIT(3)
|
|
#define EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER BIT(4)
|
|
#define EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR BIT(5)
|
|
};
|
|
|
|
#define for_each_ufs_rx_lane(ufs, i) \
|
|
for (i = (ufs)->rx_sel_idx; \
|
|
i < (ufs)->rx_sel_idx + (ufs)->avail_ln_rx; i++)
|
|
#define for_each_ufs_tx_lane(ufs, i) \
|
|
for (i = 0; i < (ufs)->avail_ln_tx; i++)
|
|
|
|
#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);
|
|
#undef EXYNOS_UFS_MMIO_FUNC
|
|
|
|
long exynos_ufs_calc_time_cntr(struct exynos_ufs *, long);
|
|
|
|
static inline void exynos_ufs_enable_ov_tm(struct ufs_hba *hba)
|
|
{
|
|
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OV_TM), TRUE);
|
|
}
|
|
|
|
static inline void exynos_ufs_disable_ov_tm(struct ufs_hba *hba)
|
|
{
|
|
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OV_TM), FALSE);
|
|
}
|
|
|
|
static inline void exynos_ufs_enable_dbg_mode(struct ufs_hba *hba)
|
|
{
|
|
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), TRUE);
|
|
}
|
|
|
|
static inline void exynos_ufs_disable_dbg_mode(struct ufs_hba *hba)
|
|
{
|
|
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), FALSE);
|
|
}
|
|
|
|
#endif /* _UFS_EXYNOS_H_ */
|