1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Salvo PHY is a 28nm PHY, it is a legacy PHY, and only 4 * for USB3 and USB2. 5 * 6 * Copyright (c) 2019-2020 NXP 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/io.h> 11 #include <linux/module.h> 12 #include <linux/phy/phy.h> 13 #include <linux/platform_device.h> 14 #include <linux/delay.h> 15 #include <linux/of.h> 16 #include <linux/of_platform.h> 17 18 /* PHY register definition */ 19 #define PHY_PMA_CMN_CTRL1 0xC800 20 #define TB_ADDR_CMN_DIAG_HSCLK_SEL 0x01e0 21 #define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR 0x0084 22 #define TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR 0x0085 23 #define TB_ADDR_CMN_PLL0_INTDIV 0x0094 24 #define TB_ADDR_CMN_PLL0_FRACDIV 0x0095 25 #define TB_ADDR_CMN_PLL0_HIGH_THR 0x0096 26 #define TB_ADDR_CMN_PLL0_SS_CTRL1 0x0098 27 #define TB_ADDR_CMN_PLL0_SS_CTRL2 0x0099 28 #define TB_ADDR_CMN_PLL0_DSM_DIAG 0x0097 29 #define TB_ADDR_CMN_DIAG_PLL0_OVRD 0x01c2 30 #define TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD 0x01c0 31 #define TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD 0x01c1 32 #define TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE 0x01C5 33 #define TB_ADDR_CMN_DIAG_PLL0_CP_TUNE 0x01C6 34 #define TB_ADDR_CMN_DIAG_PLL0_LF_PROG 0x01C7 35 #define TB_ADDR_CMN_DIAG_PLL0_TEST_MODE 0x01c4 36 #define TB_ADDR_CMN_PSM_CLK_CTRL 0x0061 37 #define TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR 0x40ea 38 #define TB_ADDR_XCVR_PSM_RCTRL 0x4001 39 #define TB_ADDR_TX_PSC_A0 0x4100 40 #define TB_ADDR_TX_PSC_A1 0x4101 41 #define TB_ADDR_TX_PSC_A2 0x4102 42 #define TB_ADDR_TX_PSC_A3 0x4103 43 #define TB_ADDR_TX_DIAG_ECTRL_OVRD 0x41f5 44 #define TB_ADDR_TX_PSC_CAL 0x4106 45 #define TB_ADDR_TX_PSC_RDY 0x4107 46 #define TB_ADDR_RX_PSC_A0 0x8000 47 #define TB_ADDR_RX_PSC_A1 0x8001 48 #define TB_ADDR_RX_PSC_A2 0x8002 49 #define TB_ADDR_RX_PSC_A3 0x8003 50 #define TB_ADDR_RX_PSC_CAL 0x8006 51 #define TB_ADDR_RX_PSC_RDY 0x8007 52 #define TB_ADDR_TX_TXCC_MGNLS_MULT_000 0x4058 53 #define TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY 0x41e7 54 #define TB_ADDR_RX_SLC_CU_ITER_TMR 0x80e3 55 #define TB_ADDR_RX_SIGDET_HL_FILT_TMR 0x8090 56 #define TB_ADDR_RX_SAMP_DAC_CTRL 0x8058 57 #define TB_ADDR_RX_DIAG_SIGDET_TUNE 0x81dc 58 #define TB_ADDR_RX_DIAG_LFPSDET_TUNE2 0x81df 59 #define TB_ADDR_RX_DIAG_BS_TM 0x81f5 60 #define TB_ADDR_RX_DIAG_DFE_CTRL1 0x81d3 61 #define TB_ADDR_RX_DIAG_ILL_IQE_TRIM4 0x81c7 62 #define TB_ADDR_RX_DIAG_ILL_E_TRIM0 0x81c2 63 #define TB_ADDR_RX_DIAG_ILL_IQ_TRIM0 0x81c1 64 #define TB_ADDR_RX_DIAG_ILL_IQE_TRIM6 0x81c9 65 #define TB_ADDR_RX_DIAG_RXFE_TM3 0x81f8 66 #define TB_ADDR_RX_DIAG_RXFE_TM4 0x81f9 67 #define TB_ADDR_RX_DIAG_LFPSDET_TUNE 0x81dd 68 #define TB_ADDR_RX_DIAG_DFE_CTRL3 0x81d5 69 #define TB_ADDR_RX_DIAG_SC2C_DELAY 0x81e1 70 #define TB_ADDR_RX_REE_VGA_GAIN_NODFE 0x81bf 71 #define TB_ADDR_XCVR_PSM_CAL_TMR 0x4002 72 #define TB_ADDR_XCVR_PSM_A0BYP_TMR 0x4004 73 #define TB_ADDR_XCVR_PSM_A0IN_TMR 0x4003 74 #define TB_ADDR_XCVR_PSM_A1IN_TMR 0x4005 75 #define TB_ADDR_XCVR_PSM_A2IN_TMR 0x4006 76 #define TB_ADDR_XCVR_PSM_A3IN_TMR 0x4007 77 #define TB_ADDR_XCVR_PSM_A4IN_TMR 0x4008 78 #define TB_ADDR_XCVR_PSM_A5IN_TMR 0x4009 79 #define TB_ADDR_XCVR_PSM_A0OUT_TMR 0x400a 80 #define TB_ADDR_XCVR_PSM_A1OUT_TMR 0x400b 81 #define TB_ADDR_XCVR_PSM_A2OUT_TMR 0x400c 82 #define TB_ADDR_XCVR_PSM_A3OUT_TMR 0x400d 83 #define TB_ADDR_XCVR_PSM_A4OUT_TMR 0x400e 84 #define TB_ADDR_XCVR_PSM_A5OUT_TMR 0x400f 85 #define TB_ADDR_TX_RCVDET_EN_TMR 0x4122 86 #define TB_ADDR_TX_RCVDET_ST_TMR 0x4123 87 #define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40f2 88 #define TB_ADDR_TX_RCVDETSC_CTRL 0x4124 89 90 /* TB_ADDR_TX_RCVDETSC_CTRL */ 91 #define RXDET_IN_P3_32KHZ BIT(0) 92 93 struct cdns_reg_pairs { 94 u16 val; 95 u32 off; 96 }; 97 98 struct cdns_salvo_data { 99 u8 reg_offset_shift; 100 const struct cdns_reg_pairs *init_sequence_val; 101 u8 init_sequence_length; 102 }; 103 104 struct cdns_salvo_phy { 105 struct phy *phy; 106 struct clk *clk; 107 void __iomem *base; 108 struct cdns_salvo_data *data; 109 }; 110 111 static const struct of_device_id cdns_salvo_phy_of_match[]; 112 static u16 cdns_salvo_read(struct cdns_salvo_phy *salvo_phy, u32 reg) 113 { 114 return (u16)readl(salvo_phy->base + 115 reg * (1 << salvo_phy->data->reg_offset_shift)); 116 } 117 118 static void cdns_salvo_write(struct cdns_salvo_phy *salvo_phy, 119 u32 reg, u16 val) 120 { 121 writel(val, salvo_phy->base + 122 reg * (1 << salvo_phy->data->reg_offset_shift)); 123 } 124 125 /* 126 * Below bringup sequence pair are from Cadence PHY's User Guide 127 * and NXP platform tuning results. 128 */ 129 static const struct cdns_reg_pairs cdns_nxp_sequence_pair[] = { 130 {0x0830, PHY_PMA_CMN_CTRL1}, 131 {0x0010, TB_ADDR_CMN_DIAG_HSCLK_SEL}, 132 {0x00f0, TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR}, 133 {0x0018, TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR}, 134 {0x00d0, TB_ADDR_CMN_PLL0_INTDIV}, 135 {0x4aaa, TB_ADDR_CMN_PLL0_FRACDIV}, 136 {0x0034, TB_ADDR_CMN_PLL0_HIGH_THR}, 137 {0x01ee, TB_ADDR_CMN_PLL0_SS_CTRL1}, 138 {0x7f03, TB_ADDR_CMN_PLL0_SS_CTRL2}, 139 {0x0020, TB_ADDR_CMN_PLL0_DSM_DIAG}, 140 {0x0000, TB_ADDR_CMN_DIAG_PLL0_OVRD}, 141 {0x0000, TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD}, 142 {0x0000, TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD}, 143 {0x0007, TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE}, 144 {0x0027, TB_ADDR_CMN_DIAG_PLL0_CP_TUNE}, 145 {0x0008, TB_ADDR_CMN_DIAG_PLL0_LF_PROG}, 146 {0x0022, TB_ADDR_CMN_DIAG_PLL0_TEST_MODE}, 147 {0x000a, TB_ADDR_CMN_PSM_CLK_CTRL}, 148 {0x0139, TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR}, 149 {0xbefc, TB_ADDR_XCVR_PSM_RCTRL}, 150 151 {0x7799, TB_ADDR_TX_PSC_A0}, 152 {0x7798, TB_ADDR_TX_PSC_A1}, 153 {0x509b, TB_ADDR_TX_PSC_A2}, 154 {0x0003, TB_ADDR_TX_DIAG_ECTRL_OVRD}, 155 {0x509b, TB_ADDR_TX_PSC_A3}, 156 {0x2090, TB_ADDR_TX_PSC_CAL}, 157 {0x2090, TB_ADDR_TX_PSC_RDY}, 158 159 {0xA6FD, TB_ADDR_RX_PSC_A0}, 160 {0xA6FD, TB_ADDR_RX_PSC_A1}, 161 {0xA410, TB_ADDR_RX_PSC_A2}, 162 {0x2410, TB_ADDR_RX_PSC_A3}, 163 164 {0x23FF, TB_ADDR_RX_PSC_CAL}, 165 {0x2010, TB_ADDR_RX_PSC_RDY}, 166 167 {0x0020, TB_ADDR_TX_TXCC_MGNLS_MULT_000}, 168 {0x00ff, TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY}, 169 {0x0002, TB_ADDR_RX_SLC_CU_ITER_TMR}, 170 {0x0013, TB_ADDR_RX_SIGDET_HL_FILT_TMR}, 171 {0x0000, TB_ADDR_RX_SAMP_DAC_CTRL}, 172 {0x1004, TB_ADDR_RX_DIAG_SIGDET_TUNE}, 173 {0x4041, TB_ADDR_RX_DIAG_LFPSDET_TUNE2}, 174 {0x0480, TB_ADDR_RX_DIAG_BS_TM}, 175 {0x8006, TB_ADDR_RX_DIAG_DFE_CTRL1}, 176 {0x003f, TB_ADDR_RX_DIAG_ILL_IQE_TRIM4}, 177 {0x543f, TB_ADDR_RX_DIAG_ILL_E_TRIM0}, 178 {0x543f, TB_ADDR_RX_DIAG_ILL_IQ_TRIM0}, 179 {0x0000, TB_ADDR_RX_DIAG_ILL_IQE_TRIM6}, 180 {0x8000, TB_ADDR_RX_DIAG_RXFE_TM3}, 181 {0x0003, TB_ADDR_RX_DIAG_RXFE_TM4}, 182 {0x2408, TB_ADDR_RX_DIAG_LFPSDET_TUNE}, 183 {0x05ca, TB_ADDR_RX_DIAG_DFE_CTRL3}, 184 {0x0258, TB_ADDR_RX_DIAG_SC2C_DELAY}, 185 {0x1fff, TB_ADDR_RX_REE_VGA_GAIN_NODFE}, 186 187 {0x02c6, TB_ADDR_XCVR_PSM_CAL_TMR}, 188 {0x0002, TB_ADDR_XCVR_PSM_A0BYP_TMR}, 189 {0x02c6, TB_ADDR_XCVR_PSM_A0IN_TMR}, 190 {0x0010, TB_ADDR_XCVR_PSM_A1IN_TMR}, 191 {0x0010, TB_ADDR_XCVR_PSM_A2IN_TMR}, 192 {0x0010, TB_ADDR_XCVR_PSM_A3IN_TMR}, 193 {0x0010, TB_ADDR_XCVR_PSM_A4IN_TMR}, 194 {0x0010, TB_ADDR_XCVR_PSM_A5IN_TMR}, 195 196 {0x0002, TB_ADDR_XCVR_PSM_A0OUT_TMR}, 197 {0x0002, TB_ADDR_XCVR_PSM_A1OUT_TMR}, 198 {0x0002, TB_ADDR_XCVR_PSM_A2OUT_TMR}, 199 {0x0002, TB_ADDR_XCVR_PSM_A3OUT_TMR}, 200 {0x0002, TB_ADDR_XCVR_PSM_A4OUT_TMR}, 201 {0x0002, TB_ADDR_XCVR_PSM_A5OUT_TMR}, 202 /* Change rx detect parameter */ 203 {0x0960, TB_ADDR_TX_RCVDET_EN_TMR}, 204 {0x01e0, TB_ADDR_TX_RCVDET_ST_TMR}, 205 {0x0090, TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR}, 206 }; 207 208 static int cdns_salvo_phy_init(struct phy *phy) 209 { 210 struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy); 211 struct cdns_salvo_data *data = salvo_phy->data; 212 int ret, i; 213 u16 value; 214 215 ret = clk_prepare_enable(salvo_phy->clk); 216 if (ret) 217 return ret; 218 219 for (i = 0; i < data->init_sequence_length; i++) { 220 const struct cdns_reg_pairs *reg_pair = data->init_sequence_val + i; 221 222 cdns_salvo_write(salvo_phy, reg_pair->off, reg_pair->val); 223 } 224 225 /* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */ 226 value = cdns_salvo_read(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL); 227 value |= RXDET_IN_P3_32KHZ; 228 cdns_salvo_write(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL, 229 RXDET_IN_P3_32KHZ); 230 231 udelay(10); 232 233 clk_disable_unprepare(salvo_phy->clk); 234 235 return ret; 236 } 237 238 static int cdns_salvo_phy_power_on(struct phy *phy) 239 { 240 struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy); 241 242 return clk_prepare_enable(salvo_phy->clk); 243 } 244 245 static int cdns_salvo_phy_power_off(struct phy *phy) 246 { 247 struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy); 248 249 clk_disable_unprepare(salvo_phy->clk); 250 251 return 0; 252 } 253 254 static const struct phy_ops cdns_salvo_phy_ops = { 255 .init = cdns_salvo_phy_init, 256 .power_on = cdns_salvo_phy_power_on, 257 .power_off = cdns_salvo_phy_power_off, 258 .owner = THIS_MODULE, 259 }; 260 261 static int cdns_salvo_phy_probe(struct platform_device *pdev) 262 { 263 struct phy_provider *phy_provider; 264 struct device *dev = &pdev->dev; 265 struct cdns_salvo_phy *salvo_phy; 266 const struct of_device_id *match; 267 struct cdns_salvo_data *data; 268 269 match = of_match_device(cdns_salvo_phy_of_match, dev); 270 if (!match) 271 return -EINVAL; 272 273 data = (struct cdns_salvo_data *)match->data; 274 salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL); 275 if (!salvo_phy) 276 return -ENOMEM; 277 278 salvo_phy->data = data; 279 salvo_phy->clk = devm_clk_get_optional(dev, "salvo_phy_clk"); 280 if (IS_ERR(salvo_phy->clk)) 281 return PTR_ERR(salvo_phy->clk); 282 283 salvo_phy->base = devm_platform_ioremap_resource(pdev, 0); 284 if (IS_ERR(salvo_phy->base)) 285 return PTR_ERR(salvo_phy->base); 286 287 salvo_phy->phy = devm_phy_create(dev, NULL, &cdns_salvo_phy_ops); 288 if (IS_ERR(salvo_phy->phy)) 289 return PTR_ERR(salvo_phy->phy); 290 291 phy_set_drvdata(salvo_phy->phy, salvo_phy); 292 293 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 294 return PTR_ERR_OR_ZERO(phy_provider); 295 } 296 297 static const struct cdns_salvo_data cdns_nxp_salvo_data = { 298 2, 299 cdns_nxp_sequence_pair, 300 ARRAY_SIZE(cdns_nxp_sequence_pair), 301 }; 302 303 static const struct of_device_id cdns_salvo_phy_of_match[] = { 304 { 305 .compatible = "nxp,salvo-phy", 306 .data = &cdns_nxp_salvo_data, 307 }, 308 {} 309 }; 310 MODULE_DEVICE_TABLE(of, cdns_salvo_phy_of_match); 311 312 static struct platform_driver cdns_salvo_phy_driver = { 313 .probe = cdns_salvo_phy_probe, 314 .driver = { 315 .name = "cdns-salvo-phy", 316 .of_match_table = cdns_salvo_phy_of_match, 317 } 318 }; 319 module_platform_driver(cdns_salvo_phy_driver); 320 321 MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>"); 322 MODULE_LICENSE("GPL v2"); 323 MODULE_DESCRIPTION("Cadence SALVO PHY Driver"); 324