Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * UFS PHY driver for Samsung EXYNOS SoC
0004  *
0005  * Copyright (C) 2020 Samsung Electronics Co., Ltd.
0006  * Author: Seungwon Jeon <essuuj@gmail.com>
0007  * Author: Alim Akhtar <alim.akhtar@samsung.com>
0008  *
0009  */
0010 #ifndef _PHY_SAMSUNG_UFS_
0011 #define _PHY_SAMSUNG_UFS_
0012 
0013 #include <linux/phy/phy.h>
0014 #include <linux/regmap.h>
0015 
0016 #define PHY_COMN_BLK    1
0017 #define PHY_TRSV_BLK    2
0018 #define END_UFS_PHY_CFG { 0 }
0019 #define PHY_TRSV_CH_OFFSET  0x30
0020 #define PHY_APB_ADDR(off)   ((off) << 2)
0021 
0022 #define PHY_COMN_REG_CFG(o, v, d) { \
0023     .off_0 = PHY_APB_ADDR((o)), \
0024     .off_1 = 0,     \
0025     .val = (v),     \
0026     .desc = (d),        \
0027     .id = PHY_COMN_BLK, \
0028 }
0029 
0030 #define PHY_TRSV_REG_CFG_OFFSET(o, v, d, c) {   \
0031     .off_0 = PHY_APB_ADDR((o)), \
0032     .off_1 = PHY_APB_ADDR((o) + (c)),   \
0033     .val = (v),     \
0034     .desc = (d),        \
0035     .id = PHY_TRSV_BLK, \
0036 }
0037 
0038 #define PHY_TRSV_REG_CFG(o, v, d)   \
0039     PHY_TRSV_REG_CFG_OFFSET(o, v, d, PHY_TRSV_CH_OFFSET)
0040 
0041 /* UFS PHY registers */
0042 #define PHY_PLL_LOCK_STATUS 0x1e
0043 
0044 #define PHY_PLL_LOCK_BIT    BIT(5)
0045 #define PHY_CDR_LOCK_BIT    BIT(4)
0046 
0047 /* description for PHY calibration */
0048 enum {
0049     /* applicable to any */
0050     PWR_DESC_ANY    = 0,
0051     /* mode */
0052     PWR_DESC_PWM    = 1,
0053     PWR_DESC_HS = 2,
0054     /* series */
0055     PWR_DESC_SER_A  = 1,
0056     PWR_DESC_SER_B  = 2,
0057     /* gear */
0058     PWR_DESC_G1 = 1,
0059     PWR_DESC_G2 = 2,
0060     PWR_DESC_G3 = 3,
0061     /* field mask */
0062     MD_MASK     = 0x3,
0063     SR_MASK     = 0x3,
0064     GR_MASK     = 0x7,
0065 };
0066 
0067 #define PWR_MODE_HS_G1_ANY  PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_ANY)
0068 #define PWR_MODE_HS_G1_SER_A    PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_SER_A)
0069 #define PWR_MODE_HS_G1_SER_B    PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_SER_B)
0070 #define PWR_MODE_HS_G2_ANY  PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_ANY)
0071 #define PWR_MODE_HS_G2_SER_A    PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_SER_A)
0072 #define PWR_MODE_HS_G2_SER_B    PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_SER_B)
0073 #define PWR_MODE_HS_G3_ANY  PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_ANY)
0074 #define PWR_MODE_HS_G3_SER_A    PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_SER_A)
0075 #define PWR_MODE_HS_G3_SER_B    PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_SER_B)
0076 #define PWR_MODE(g, s, m)   ((((g) & GR_MASK) << 4) |\
0077                  (((s) & SR_MASK) << 2) | ((m) & MD_MASK))
0078 #define PWR_MODE_PWM_ANY    PWR_MODE(PWR_DESC_ANY,\
0079                      PWR_DESC_ANY, PWR_DESC_PWM)
0080 #define PWR_MODE_HS(g, s)   ((((g) & GR_MASK) << 4) |\
0081                  (((s) & SR_MASK) << 2) | PWR_DESC_HS)
0082 #define PWR_MODE_HS_ANY     PWR_MODE(PWR_DESC_ANY,\
0083                      PWR_DESC_ANY, PWR_DESC_HS)
0084 #define PWR_MODE_ANY        PWR_MODE(PWR_DESC_ANY,\
0085                      PWR_DESC_ANY, PWR_DESC_ANY)
0086 /* PHY calibration point/state */
0087 enum {
0088     CFG_PRE_INIT,
0089     CFG_POST_INIT,
0090     CFG_PRE_PWR_HS,
0091     CFG_POST_PWR_HS,
0092     CFG_TAG_MAX,
0093 };
0094 
0095 struct samsung_ufs_phy_cfg {
0096     u32 off_0;
0097     u32 off_1;
0098     u32 val;
0099     u8 desc;
0100     u8 id;
0101 };
0102 
0103 struct samsung_ufs_phy_pmu_isol {
0104     u32 offset;
0105     u32 mask;
0106     u32 en;
0107 };
0108 
0109 struct samsung_ufs_phy_drvdata {
0110     const struct samsung_ufs_phy_cfg **cfgs;
0111     struct samsung_ufs_phy_pmu_isol isol;
0112     const char * const *clk_list;
0113     int num_clks;
0114     u32 cdr_lock_status_offset;
0115 };
0116 
0117 struct samsung_ufs_phy {
0118     struct device *dev;
0119     void __iomem *reg_pma;
0120     struct regmap *reg_pmu;
0121     struct clk_bulk_data *clks;
0122     const struct samsung_ufs_phy_drvdata *drvdata;
0123     const struct samsung_ufs_phy_cfg * const *cfgs;
0124     struct samsung_ufs_phy_pmu_isol isol;
0125     u8 lane_cnt;
0126     int ufs_phy_state;
0127     enum phy_mode mode;
0128 };
0129 
0130 static inline struct samsung_ufs_phy *get_samsung_ufs_phy(struct phy *phy)
0131 {
0132     return (struct samsung_ufs_phy *)phy_get_drvdata(phy);
0133 }
0134 
0135 static inline void samsung_ufs_phy_ctrl_isol(
0136         struct samsung_ufs_phy *phy, u32 isol)
0137 {
0138     regmap_update_bits(phy->reg_pmu, phy->isol.offset,
0139                phy->isol.mask, isol ? 0 : phy->isol.en);
0140 }
0141 
0142 extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy;
0143 extern const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy;
0144 extern const struct samsung_ufs_phy_drvdata fsd_ufs_phy;
0145 
0146 #endif /* _PHY_SAMSUNG_UFS_ */