Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: qcom-ufs: add support for 20nm phy

This change adds a support for a 20nm qcom-ufs phy that is required in
platforms that use ufs-qcom controller.

Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
Reviewed-by: Dov Levenglick <dovl@codeaurora.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>

authored by

Yaniv Gardi and committed by
Christoph Hellwig
39e794bf adaafaa3

+594 -1
+1
drivers/phy/Makefile
··· 35 35 obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o 36 36 obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o 37 37 obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o 38 + obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
+42 -1
drivers/phy/phy-qcom-ufs-i.h
··· 15 15 #ifndef UFS_QCOM_PHY_I_H_ 16 16 #define UFS_QCOM_PHY_I_H_ 17 17 18 + #include <linux/module.h> 18 19 #include <linux/clk.h> 20 + #include <linux/regulator/consumer.h> 19 21 #include <linux/slab.h> 20 - #include <linux/phy/phy.h> 22 + #include <linux/phy/phy-qcom-ufs.h> 21 23 #include <linux/platform_device.h> 22 24 #include <linux/io.h> 23 25 #include <linux/delay.h> 24 26 27 + #define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ 28 + ({ \ 29 + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ 30 + might_sleep_if(timeout_us); \ 31 + for (;;) { \ 32 + (val) = readl(addr); \ 33 + if (cond) \ 34 + break; \ 35 + if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \ 36 + (val) = readl(addr); \ 37 + break; \ 38 + } \ 39 + if (sleep_us) \ 40 + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ 41 + } \ 42 + (cond) ? 0 : -ETIMEDOUT; \ 43 + }) 44 + 45 + #define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ 46 + { \ 47 + .reg_offset = reg, \ 48 + .cfg_value = val, \ 49 + } 50 + 25 51 #define UFS_QCOM_PHY_NAME_LEN 30 52 + 53 + enum { 54 + MASK_SERDES_START = 0x1, 55 + MASK_PCS_READY = 0x1, 56 + }; 57 + 58 + enum { 59 + OFFSET_SERDES_START = 0x0, 60 + }; 61 + 62 + struct ufs_qcom_phy_stored_attributes { 63 + u32 att; 64 + u32 value; 65 + }; 66 + 26 67 27 68 struct ufs_qcom_phy_calibration { 28 69 u32 reg_offset;
+257
drivers/phy/phy-qcom-ufs-qmp-20nm.c
··· 1 + /* 2 + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + */ 14 + 15 + #include "phy-qcom-ufs-qmp-20nm.h" 16 + 17 + #define UFS_PHY_NAME "ufs_phy_qmp_20nm" 18 + 19 + static 20 + int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, 21 + bool is_rate_B) 22 + { 23 + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; 24 + int tbl_size_A, tbl_size_B; 25 + u8 major = ufs_qcom_phy->host_ctrl_rev_major; 26 + u16 minor = ufs_qcom_phy->host_ctrl_rev_minor; 27 + u16 step = ufs_qcom_phy->host_ctrl_rev_step; 28 + int err; 29 + 30 + if ((major == 0x1) && (minor == 0x002) && (step == 0x0000)) { 31 + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); 32 + tbl_A = phy_cal_table_rate_A_1_2_0; 33 + } else if ((major == 0x1) && (minor == 0x003) && (step == 0x0000)) { 34 + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); 35 + tbl_A = phy_cal_table_rate_A_1_3_0; 36 + } else { 37 + dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, no calibration values\n", 38 + __func__); 39 + err = -ENODEV; 40 + goto out; 41 + } 42 + 43 + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); 44 + tbl_B = phy_cal_table_rate_B; 45 + 46 + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, 47 + tbl_B, tbl_size_B, is_rate_B); 48 + 49 + if (err) 50 + dev_err(ufs_qcom_phy->dev, "%s: ufs_qcom_phy_calibrate() failed %d\n", 51 + __func__, err); 52 + 53 + out: 54 + return err; 55 + } 56 + 57 + static 58 + void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct ufs_qcom_phy *phy_common) 59 + { 60 + phy_common->quirks = 61 + UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; 62 + } 63 + 64 + static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy) 65 + { 66 + struct ufs_qcom_phy_qmp_20nm *phy = phy_get_drvdata(generic_phy); 67 + struct ufs_qcom_phy *phy_common = &phy->common_cfg; 68 + int err = 0; 69 + 70 + err = ufs_qcom_phy_init_clks(generic_phy, phy_common); 71 + if (err) { 72 + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n", 73 + __func__, err); 74 + goto out; 75 + } 76 + 77 + err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common); 78 + if (err) { 79 + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n", 80 + __func__, err); 81 + goto out; 82 + } 83 + 84 + ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common); 85 + 86 + out: 87 + return err; 88 + } 89 + 90 + static 91 + void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, bool val) 92 + { 93 + bool hibern8_exit_after_pwr_collapse = phy->quirks & 94 + UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; 95 + 96 + if (val) { 97 + writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); 98 + /* 99 + * Before any transactions involving PHY, ensure PHY knows 100 + * that it's analog rail is powered ON. 101 + */ 102 + mb(); 103 + 104 + if (hibern8_exit_after_pwr_collapse) { 105 + /* 106 + * Give atleast 1us delay after restoring PHY analog 107 + * power. 108 + */ 109 + usleep_range(1, 2); 110 + writel_relaxed(0x0A, phy->mmio + 111 + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); 112 + writel_relaxed(0x08, phy->mmio + 113 + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); 114 + /* 115 + * Make sure workaround is deactivated before proceeding 116 + * with normal PHY operations. 117 + */ 118 + mb(); 119 + } 120 + } else { 121 + if (hibern8_exit_after_pwr_collapse) { 122 + writel_relaxed(0x0A, phy->mmio + 123 + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); 124 + writel_relaxed(0x02, phy->mmio + 125 + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); 126 + /* 127 + * Make sure that above workaround is activated before 128 + * PHY analog power collapse. 129 + */ 130 + mb(); 131 + } 132 + 133 + writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); 134 + /* 135 + * ensure that PHY knows its PHY analog rail is going 136 + * to be powered down 137 + */ 138 + mb(); 139 + } 140 + } 141 + 142 + static 143 + void ufs_qcom_phy_qmp_20nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val) 144 + { 145 + writel_relaxed(val & UFS_PHY_TX_LANE_ENABLE_MASK, 146 + phy->mmio + UFS_PHY_TX_LANE_ENABLE); 147 + mb(); 148 + } 149 + 150 + static inline void ufs_qcom_phy_qmp_20nm_start_serdes(struct ufs_qcom_phy *phy) 151 + { 152 + u32 tmp; 153 + 154 + tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START); 155 + tmp &= ~MASK_SERDES_START; 156 + tmp |= (1 << OFFSET_SERDES_START); 157 + writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START); 158 + mb(); 159 + } 160 + 161 + static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) 162 + { 163 + int err = 0; 164 + u32 val; 165 + 166 + err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS, 167 + val, (val & MASK_PCS_READY), 10, 1000000); 168 + if (err) 169 + dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n", 170 + __func__, err); 171 + return err; 172 + } 173 + 174 + static struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { 175 + .init = ufs_qcom_phy_qmp_20nm_init, 176 + .exit = ufs_qcom_phy_exit, 177 + .power_on = ufs_qcom_phy_power_on, 178 + .power_off = ufs_qcom_phy_power_off, 179 + .owner = THIS_MODULE, 180 + }; 181 + 182 + static struct ufs_qcom_phy_specific_ops phy_20nm_ops = { 183 + .calibrate_phy = ufs_qcom_phy_qmp_20nm_phy_calibrate, 184 + .start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes, 185 + .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready, 186 + .set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable, 187 + .power_control = ufs_qcom_phy_qmp_20nm_power_control, 188 + }; 189 + 190 + static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev) 191 + { 192 + struct device *dev = &pdev->dev; 193 + struct phy *generic_phy; 194 + struct ufs_qcom_phy_qmp_20nm *phy; 195 + int err = 0; 196 + 197 + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 198 + if (!phy) { 199 + dev_err(dev, "%s: failed to allocate phy\n", __func__); 200 + err = -ENOMEM; 201 + goto out; 202 + } 203 + 204 + generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg, 205 + &ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops); 206 + 207 + if (!generic_phy) { 208 + dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", 209 + __func__); 210 + err = -EIO; 211 + goto out; 212 + } 213 + 214 + phy_set_drvdata(generic_phy, phy); 215 + 216 + strlcpy(phy->common_cfg.name, UFS_PHY_NAME, 217 + sizeof(phy->common_cfg.name)); 218 + 219 + out: 220 + return err; 221 + } 222 + 223 + static int ufs_qcom_phy_qmp_20nm_remove(struct platform_device *pdev) 224 + { 225 + struct device *dev = &pdev->dev; 226 + struct phy *generic_phy = to_phy(dev); 227 + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); 228 + int err = 0; 229 + 230 + err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy); 231 + if (err) 232 + dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n", 233 + __func__, err); 234 + 235 + return err; 236 + } 237 + 238 + static const struct of_device_id ufs_qcom_phy_qmp_20nm_of_match[] = { 239 + {.compatible = "qcom,ufs-phy-qmp-20nm"}, 240 + {}, 241 + }; 242 + MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_20nm_of_match); 243 + 244 + static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = { 245 + .probe = ufs_qcom_phy_qmp_20nm_probe, 246 + .remove = ufs_qcom_phy_qmp_20nm_remove, 247 + .driver = { 248 + .of_match_table = ufs_qcom_phy_qmp_20nm_of_match, 249 + .name = "ufs_qcom_phy_qmp_20nm", 250 + .owner = THIS_MODULE, 251 + }, 252 + }; 253 + 254 + module_platform_driver(ufs_qcom_phy_qmp_20nm_driver); 255 + 256 + MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 20nm"); 257 + MODULE_LICENSE("GPL v2");
+235
drivers/phy/phy-qcom-ufs-qmp-20nm.h
··· 1 + /* 2 + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + */ 14 + 15 + #ifndef UFS_QCOM_PHY_QMP_20NM_H_ 16 + #define UFS_QCOM_PHY_QMP_20NM_H_ 17 + 18 + #include "phy-qcom-ufs-i.h" 19 + 20 + /* QCOM UFS PHY control registers */ 21 + 22 + #define COM_OFF(x) (0x000 + x) 23 + #define PHY_OFF(x) (0xC00 + x) 24 + #define TX_OFF(n, x) (0x400 + (0x400 * n) + x) 25 + #define RX_OFF(n, x) (0x600 + (0x400 * n) + x) 26 + 27 + /* UFS PHY PLL block registers */ 28 + #define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x0) 29 + #define QSERDES_COM_PLL_VCOTAIL_EN COM_OFF(0x04) 30 + #define QSERDES_COM_PLL_CNTRL COM_OFF(0x14) 31 + #define QSERDES_COM_PLL_IP_SETI COM_OFF(0x24) 32 + #define QSERDES_COM_CORE_CLK_IN_SYNC_SEL COM_OFF(0x28) 33 + #define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x30) 34 + #define QSERDES_COM_PLL_CP_SETI COM_OFF(0x34) 35 + #define QSERDES_COM_PLL_IP_SETP COM_OFF(0x38) 36 + #define QSERDES_COM_PLL_CP_SETP COM_OFF(0x3C) 37 + #define QSERDES_COM_SYSCLK_EN_SEL_TXBAND COM_OFF(0x48) 38 + #define QSERDES_COM_RESETSM_CNTRL COM_OFF(0x4C) 39 + #define QSERDES_COM_RESETSM_CNTRL2 COM_OFF(0x50) 40 + #define QSERDES_COM_PLLLOCK_CMP1 COM_OFF(0x90) 41 + #define QSERDES_COM_PLLLOCK_CMP2 COM_OFF(0x94) 42 + #define QSERDES_COM_PLLLOCK_CMP3 COM_OFF(0x98) 43 + #define QSERDES_COM_PLLLOCK_CMP_EN COM_OFF(0x9C) 44 + #define QSERDES_COM_BGTC COM_OFF(0xA0) 45 + #define QSERDES_COM_DEC_START1 COM_OFF(0xAC) 46 + #define QSERDES_COM_PLL_AMP_OS COM_OFF(0xB0) 47 + #define QSERDES_COM_RES_CODE_UP_OFFSET COM_OFF(0xD8) 48 + #define QSERDES_COM_RES_CODE_DN_OFFSET COM_OFF(0xDC) 49 + #define QSERDES_COM_DIV_FRAC_START1 COM_OFF(0x100) 50 + #define QSERDES_COM_DIV_FRAC_START2 COM_OFF(0x104) 51 + #define QSERDES_COM_DIV_FRAC_START3 COM_OFF(0x108) 52 + #define QSERDES_COM_DEC_START2 COM_OFF(0x10C) 53 + #define QSERDES_COM_PLL_RXTXEPCLK_EN COM_OFF(0x110) 54 + #define QSERDES_COM_PLL_CRCTRL COM_OFF(0x114) 55 + #define QSERDES_COM_PLL_CLKEPDIV COM_OFF(0x118) 56 + 57 + /* TX LANE n (0, 1) registers */ 58 + #define QSERDES_TX_EMP_POST1_LVL(n) TX_OFF(n, 0x08) 59 + #define QSERDES_TX_DRV_LVL(n) TX_OFF(n, 0x0C) 60 + #define QSERDES_TX_LANE_MODE(n) TX_OFF(n, 0x54) 61 + 62 + /* RX LANE n (0, 1) registers */ 63 + #define QSERDES_RX_CDR_CONTROL1(n) RX_OFF(n, 0x0) 64 + #define QSERDES_RX_CDR_CONTROL_HALF(n) RX_OFF(n, 0x8) 65 + #define QSERDES_RX_RX_EQ_GAIN1_LSB(n) RX_OFF(n, 0xA8) 66 + #define QSERDES_RX_RX_EQ_GAIN1_MSB(n) RX_OFF(n, 0xAC) 67 + #define QSERDES_RX_RX_EQ_GAIN2_LSB(n) RX_OFF(n, 0xB0) 68 + #define QSERDES_RX_RX_EQ_GAIN2_MSB(n) RX_OFF(n, 0xB4) 69 + #define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(n) RX_OFF(n, 0xBC) 70 + #define QSERDES_RX_CDR_CONTROL_QUARTER(n) RX_OFF(n, 0xC) 71 + #define QSERDES_RX_SIGDET_CNTRL(n) RX_OFF(n, 0x100) 72 + 73 + /* UFS PHY registers */ 74 + #define UFS_PHY_PHY_START PHY_OFF(0x00) 75 + #define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x4) 76 + #define UFS_PHY_TX_LANE_ENABLE PHY_OFF(0x44) 77 + #define UFS_PHY_PWM_G1_CLK_DIVIDER PHY_OFF(0x08) 78 + #define UFS_PHY_PWM_G2_CLK_DIVIDER PHY_OFF(0x0C) 79 + #define UFS_PHY_PWM_G3_CLK_DIVIDER PHY_OFF(0x10) 80 + #define UFS_PHY_PWM_G4_CLK_DIVIDER PHY_OFF(0x14) 81 + #define UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER PHY_OFF(0x34) 82 + #define UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER PHY_OFF(0x38) 83 + #define UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER PHY_OFF(0x3C) 84 + #define UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER PHY_OFF(0x40) 85 + #define UFS_PHY_OMC_STATUS_RDVAL PHY_OFF(0x68) 86 + #define UFS_PHY_LINE_RESET_TIME PHY_OFF(0x28) 87 + #define UFS_PHY_LINE_RESET_GRANULARITY PHY_OFF(0x2C) 88 + #define UFS_PHY_TSYNC_RSYNC_CNTL PHY_OFF(0x48) 89 + #define UFS_PHY_PLL_CNTL PHY_OFF(0x50) 90 + #define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x54) 91 + #define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x5C) 92 + #define UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL PHY_OFF(0x58) 93 + #define UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL PHY_OFF(0x60) 94 + #define UFS_PHY_CFG_CHANGE_CNT_VAL PHY_OFF(0x64) 95 + #define UFS_PHY_RX_SYNC_WAIT_TIME PHY_OFF(0x6C) 96 + #define UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB4) 97 + #define UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE0) 98 + #define UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB8) 99 + #define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE4) 100 + #define UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xBC) 101 + #define UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xE8) 102 + #define UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY PHY_OFF(0xFC) 103 + #define UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY PHY_OFF(0x100) 104 + #define UFS_PHY_RX_SIGDET_CTRL3 PHY_OFF(0x14c) 105 + #define UFS_PHY_RMMI_ATTR_CTRL PHY_OFF(0x160) 106 + #define UFS_PHY_RMMI_RX_CFGUPDT_L1 (1 << 7) 107 + #define UFS_PHY_RMMI_TX_CFGUPDT_L1 (1 << 6) 108 + #define UFS_PHY_RMMI_CFGWR_L1 (1 << 5) 109 + #define UFS_PHY_RMMI_CFGRD_L1 (1 << 4) 110 + #define UFS_PHY_RMMI_RX_CFGUPDT_L0 (1 << 3) 111 + #define UFS_PHY_RMMI_TX_CFGUPDT_L0 (1 << 2) 112 + #define UFS_PHY_RMMI_CFGWR_L0 (1 << 1) 113 + #define UFS_PHY_RMMI_CFGRD_L0 (1 << 0) 114 + #define UFS_PHY_RMMI_ATTRID PHY_OFF(0x164) 115 + #define UFS_PHY_RMMI_ATTRWRVAL PHY_OFF(0x168) 116 + #define UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS PHY_OFF(0x16C) 117 + #define UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS PHY_OFF(0x170) 118 + #define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x174) 119 + 120 + #define UFS_PHY_TX_LANE_ENABLE_MASK 0x3 121 + 122 + /* 123 + * This structure represents the 20nm specific phy. 124 + * common_cfg MUST remain the first field in this structure 125 + * in case extra fields are added. This way, when calling 126 + * get_ufs_qcom_phy() of generic phy, we can extract the 127 + * common phy structure (struct ufs_qcom_phy) out of it 128 + * regardless of the relevant specific phy. 129 + */ 130 + struct ufs_qcom_phy_qmp_20nm { 131 + struct ufs_qcom_phy common_cfg; 132 + }; 133 + 134 + static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_2_0[] = { 135 + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), 136 + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D), 137 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1), 138 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc), 139 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08), 140 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03), 141 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10), 142 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82), 143 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03), 144 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80), 145 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80), 146 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40), 147 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff), 148 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19), 149 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00), 150 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03), 151 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90), 152 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03), 153 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2), 154 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c), 155 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12), 156 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2), 157 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c), 158 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12), 159 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff), 160 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff), 161 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff), 162 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00), 163 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff), 164 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff), 165 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff), 166 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00), 167 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f), 168 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x1b), 169 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x0f), 170 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01), 171 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(0), 0x2F), 172 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(0), 0x20), 173 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(1), 0x2F), 174 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(1), 0x20), 175 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68), 176 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68), 177 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc), 178 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc), 179 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3), 180 + }; 181 + 182 + static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_3_0[] = { 183 + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), 184 + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D), 185 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1), 186 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc), 187 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08), 188 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03), 189 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10), 190 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82), 191 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03), 192 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80), 193 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80), 194 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40), 195 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff), 196 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19), 197 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00), 198 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03), 199 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90), 200 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03), 201 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2), 202 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c), 203 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12), 204 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2), 205 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c), 206 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12), 207 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff), 208 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff), 209 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff), 210 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00), 211 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff), 212 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff), 213 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff), 214 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00), 215 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x2b), 216 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x38), 217 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x3c), 218 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_UP_OFFSET, 0x02), 219 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_DN_OFFSET, 0x02), 220 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01), 221 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CNTRL, 0x40), 222 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68), 223 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68), 224 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc), 225 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc), 226 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3), 227 + }; 228 + 229 + static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { 230 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98), 231 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65), 232 + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e), 233 + }; 234 + 235 + #endif
+59
include/linux/phy/phy-qcom-ufs.h
··· 1 + /* 2 + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + */ 14 + 15 + #ifndef PHY_QCOM_UFS_H_ 16 + #define PHY_QCOM_UFS_H_ 17 + 18 + #include "phy.h" 19 + 20 + /** 21 + * ufs_qcom_phy_enable_ref_clk() - Enable the phy 22 + * ref clock. 23 + * @phy: reference to a generic phy 24 + * 25 + * returns 0 for success, and non-zero for error. 26 + */ 27 + int ufs_qcom_phy_enable_ref_clk(struct phy *phy); 28 + 29 + /** 30 + * ufs_qcom_phy_disable_ref_clk() - Disable the phy 31 + * ref clock. 32 + * @phy: reference to a generic phy. 33 + */ 34 + void ufs_qcom_phy_disable_ref_clk(struct phy *phy); 35 + 36 + /** 37 + * ufs_qcom_phy_enable_dev_ref_clk() - Enable the device 38 + * ref clock. 39 + * @phy: reference to a generic phy. 40 + */ 41 + void ufs_qcom_phy_enable_dev_ref_clk(struct phy *phy); 42 + 43 + /** 44 + * ufs_qcom_phy_disable_dev_ref_clk() - Disable the device 45 + * ref clock. 46 + * @phy: reference to a generic phy. 47 + */ 48 + void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy); 49 + 50 + int ufs_qcom_phy_enable_iface_clk(struct phy *phy); 51 + void ufs_qcom_phy_disable_iface_clk(struct phy *phy); 52 + int ufs_qcom_phy_start_serdes(struct phy *phy); 53 + int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes); 54 + int ufs_qcom_phy_calibrate_phy(struct phy *phy, bool is_rate_B); 55 + int ufs_qcom_phy_is_pcs_ready(struct phy *phy); 56 + void ufs_qcom_phy_save_controller_version(struct phy *phy, 57 + u8 major, u16 minor, u16 step); 58 + 59 + #endif /* PHY_QCOM_UFS_H_ */