diff options
Diffstat (limited to 'drivers/phy/qualcomm/phy-qcom-qmp-ufs.c')
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 305 |
1 files changed, 165 insertions, 140 deletions
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 3c2e6255e2..590432d581 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -20,6 +20,9 @@ #include <linux/slab.h> #include <ufs/unipro.h> + +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-ufs-v2.h" #include "phy-qcom-qmp-pcs-ufs-v3.h" @@ -29,41 +32,12 @@ #include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -/* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) /* QPHY_PCS_READY_STATUS bit */ #define PCS_READY BIT(0) #define PHY_INIT_COMPLETE_TIMEOUT 10000 -struct qmp_phy_init_tbl { - unsigned int offset; - unsigned int val; - /* - * mask of lanes for which this register is written - * for cases when second lane needs different values - */ - u8 lane_mask; -}; - -#define QMP_PHY_INIT_CFG(o, v) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = 0xff, \ - } - -#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = l, \ - } +#define NUM_OVERLAY 2 /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { @@ -754,15 +728,22 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11), QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c), QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), @@ -771,19 +752,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07), }; -static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = { - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), }; static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c), }; static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2), @@ -799,16 +785,45 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), }; +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30), +}; + static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = { QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), }; +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e), +}; + static const struct qmp_phy_init_tbl sm8650_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9), QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), @@ -889,6 +904,8 @@ struct qmp_phy_cfg_tbls { int rx_num; const struct qmp_phy_init_tbl *pcs; int pcs_num; + /* Maximum supported Gear of this tbls */ + u32 max_gear; }; /* struct qmp_phy_cfg - per-PHY initialization config */ @@ -896,17 +913,16 @@ struct qmp_phy_cfg { int lanes; const struct qmp_ufs_offsets *offsets; + /* Maximum supported Gear of this config */ + u32 max_supported_gear; /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_cfg_tbls tbls; /* Additional sequence for HS Series B */ const struct qmp_phy_cfg_tbls tbls_hs_b; - /* Additional sequence for HS G4 */ - const struct qmp_phy_cfg_tbls tbls_hs_g4; + /* Additional sequence for different HS Gears */ + const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY]; - /* clock ids to be requested */ - const char * const *clk_list; - int num_clks; /* regulators to be requested */ const char * const *vreg_list; int num_vregs; @@ -932,6 +948,7 @@ struct qmp_ufs { void __iomem *rx2; struct clk_bulk_data *clks; + int num_clks; struct regulator_bulk_data *vregs; struct reset_control *ufs_reset; @@ -964,20 +981,6 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* list of clocks required by phy */ -static const char * const msm8996_ufs_phy_clk_l[] = { - "ref", -}; - -/* the primary usb3 phy on sm8250 doesn't have a ref clock */ -static const char * const sm8450_ufs_phy_clk_l[] = { - "qref", "ref", "ref_aux", -}; - -static const char * const sdm845_ufs_phy_clk_l[] = { - "ref", "ref_aux", -}; - /* list of regulators */ static const char * const qmp_phy_vreg_l[] = { "vdda-phy", "vdda-pll", @@ -1005,6 +1008,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = msm8996_ufsphy_serdes, @@ -1015,9 +1019,6 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .rx_num = ARRAY_SIZE(msm8996_ufsphy_rx), }, - .clk_list = msm8996_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(msm8996_ufs_phy_clk_l), - .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), @@ -1030,6 +1031,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1045,16 +1047,15 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1064,6 +1065,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1079,16 +1081,15 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8250_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx), .rx = sc7280_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1098,6 +1099,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1113,16 +1115,15 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1132,6 +1133,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sdm845_ufsphy_serdes, @@ -1147,8 +1149,6 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v3_regs_layout, @@ -1160,6 +1160,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sm6115_ufsphy_serdes, @@ -1175,8 +1176,6 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .serdes = sm6115_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v2_regs_layout, @@ -1188,6 +1187,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sdm845_ufsphy_serdes, @@ -1203,8 +1203,6 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v3_regs_layout, @@ -1216,6 +1214,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1231,16 +1230,15 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8150_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx), .rx = sm8150_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1250,6 +1248,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1265,16 +1264,15 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8250_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx), .rx = sm8250_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1284,6 +1282,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1299,16 +1298,15 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1318,6 +1316,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1333,16 +1332,15 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1352,6 +1350,7 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G5, .tbls = { .serdes = sm8550_ufsphy_serdes, @@ -1367,8 +1366,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .serdes = sm8550_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .tbls_hs_overlay[0] = { + .serdes = sm8550_ufsphy_g4_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes), + .tx = sm8550_ufsphy_g4_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx), + .rx = sm8550_ufsphy_g4_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx), + .pcs = sm8550_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, + }, + .tbls_hs_overlay[1] = { + .serdes = sm8550_ufsphy_g5_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes), + .rx = sm8550_ufsphy_g5_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx), + .pcs = sm8550_ufsphy_g5_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs), + .max_gear = UFS_HS_G5, + }, .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v6_regs_layout, @@ -1378,6 +1395,7 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G5, .tbls = { .serdes = sm8650_ufsphy_serdes, @@ -1389,44 +1407,16 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .pcs = sm8650_ufsphy_pcs, .pcs_num = ARRAY_SIZE(sm8650_ufsphy_pcs), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v6_regs_layout, }; -static void qmp_ufs_configure_lane(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num, - u8 lane_mask) -{ - int i; - const struct qmp_phy_init_tbl *t = tbl; - - if (!t) - return; - - for (i = 0; i < num; i++, t++) { - if (!(t->lane_mask & lane_mask)) - continue; - - writel(t->val, base + t->offset); - } -} - -static void qmp_ufs_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_ufs_configure_lane(base, tbl, num, 0xff); -} - static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls) { void __iomem *serdes = qmp->serdes; - qmp_ufs_configure(serdes, tbls->serdes, tbls->serdes_num); + qmp_configure(serdes, tbls->serdes, tbls->serdes_num); } static void qmp_ufs_lanes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls) @@ -1435,12 +1425,12 @@ static void qmp_ufs_lanes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbl void __iomem *tx = qmp->tx; void __iomem *rx = qmp->rx; - qmp_ufs_configure_lane(tx, tbls->tx, tbls->tx_num, 1); - qmp_ufs_configure_lane(rx, tbls->rx, tbls->rx_num, 1); + qmp_configure_lane(tx, tbls->tx, tbls->tx_num, 1); + qmp_configure_lane(rx, tbls->rx, tbls->rx_num, 1); if (cfg->lanes >= 2) { - qmp_ufs_configure_lane(qmp->tx2, tbls->tx, tbls->tx_num, 2); - qmp_ufs_configure_lane(qmp->rx2, tbls->rx, tbls->rx_num, 2); + qmp_configure_lane(qmp->tx2, tbls->tx, tbls->tx_num, 2); + qmp_configure_lane(qmp->rx2, tbls->rx, tbls->rx_num, 2); } } @@ -1448,20 +1438,52 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls { void __iomem *pcs = qmp->pcs; - qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num); + qmp_configure(pcs, tbls->pcs, tbls->pcs_num); +} + +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg) +{ + u32 max_gear, floor_max_gear = cfg->max_supported_gear; + int idx, ret = -EINVAL; + + for (idx = NUM_OVERLAY - 1; idx >= 0; idx--) { + max_gear = cfg->tbls_hs_overlay[idx].max_gear; + + /* Skip if the table is not available */ + if (max_gear == 0) + continue; + + /* Direct matching, bail */ + if (qmp->submode == max_gear) + return idx; + + /* If no direct matching, the lowest gear is the best matching */ + if (max_gear < floor_max_gear) { + ret = idx; + floor_max_gear = max_gear; + } + } + + return ret; } static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg) { + int i; + qmp_ufs_serdes_init(qmp, &cfg->tbls); - if (qmp->mode == PHY_MODE_UFS_HS_B) - qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b); qmp_ufs_lanes_init(qmp, &cfg->tbls); - if (qmp->submode == UFS_HS_G4) - qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_g4); qmp_ufs_pcs_init(qmp, &cfg->tbls); - if (qmp->submode == UFS_HS_G4) - qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_g4); + + i = qmp_ufs_get_gear_overlay(qmp, cfg); + if (i >= 0) { + qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[i]); + qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[i]); + qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_overlay[i]); + } + + if (qmp->mode == PHY_MODE_UFS_HS_B) + qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b); } static int qmp_ufs_com_init(struct qmp_ufs *qmp) @@ -1476,7 +1498,7 @@ static int qmp_ufs_com_init(struct qmp_ufs *qmp) return ret; } - ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); if (ret) goto err_disable_regulators; @@ -1496,7 +1518,7 @@ static int qmp_ufs_com_exit(struct qmp_ufs *qmp) reset_control_assert(qmp->ufs_reset); - clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); regulator_bulk_disable(cfg->num_vregs, qmp->vregs); @@ -1633,6 +1655,12 @@ static int qmp_ufs_disable(struct phy *phy) static int qmp_ufs_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct qmp_ufs *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + if (submode > cfg->max_supported_gear || submode == 0) { + dev_err(qmp->dev, "Invalid PHY submode %d\n", submode); + return -EINVAL; + } qmp->mode = mode; qmp->submode = submode; @@ -1666,19 +1694,13 @@ static int qmp_ufs_vreg_init(struct qmp_ufs *qmp) static int qmp_ufs_clk_init(struct qmp_ufs *qmp) { - const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; - int num = cfg->num_clks; - int i; - qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); - if (!qmp->clks) - return -ENOMEM; - - for (i = 0; i < num; i++) - qmp->clks[i].id = cfg->clk_list[i]; + qmp->num_clks = devm_clk_bulk_get_all(dev, &qmp->clks); + if (qmp->num_clks < 0) + return qmp->num_clks; - return devm_clk_bulk_get(dev, num, qmp->clks); + return 0; } static void qmp_ufs_clk_release_provider(void *res) @@ -1881,6 +1903,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = { .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = &sa8775p_ufsphy_cfg, }, { + .compatible = "qcom,sc7180-qmp-ufs-phy", + .data = &sm7150_ufsphy_cfg, + }, { .compatible = "qcom,sc7280-qmp-ufs-phy", .data = &sc7280_ufsphy_cfg, }, { |