phy-cadence-salvo.c (10043B)
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 93struct cdns_reg_pairs { 94 u16 val; 95 u32 off; 96}; 97 98struct cdns_salvo_data { 99 u8 reg_offset_shift; 100 const struct cdns_reg_pairs *init_sequence_val; 101 u8 init_sequence_length; 102}; 103 104struct cdns_salvo_phy { 105 struct phy *phy; 106 struct clk *clk; 107 void __iomem *base; 108 struct cdns_salvo_data *data; 109}; 110 111static const struct of_device_id cdns_salvo_phy_of_match[]; 112static 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 118static 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 */ 129static 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 208static 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 238static 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 245static 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 254static 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 261static 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 struct cdns_salvo_data *data; 267 268 data = (struct cdns_salvo_data *)of_device_get_match_data(dev); 269 salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL); 270 if (!salvo_phy) 271 return -ENOMEM; 272 273 salvo_phy->data = data; 274 salvo_phy->clk = devm_clk_get_optional(dev, "salvo_phy_clk"); 275 if (IS_ERR(salvo_phy->clk)) 276 return PTR_ERR(salvo_phy->clk); 277 278 salvo_phy->base = devm_platform_ioremap_resource(pdev, 0); 279 if (IS_ERR(salvo_phy->base)) 280 return PTR_ERR(salvo_phy->base); 281 282 salvo_phy->phy = devm_phy_create(dev, NULL, &cdns_salvo_phy_ops); 283 if (IS_ERR(salvo_phy->phy)) 284 return PTR_ERR(salvo_phy->phy); 285 286 phy_set_drvdata(salvo_phy->phy, salvo_phy); 287 288 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 289 return PTR_ERR_OR_ZERO(phy_provider); 290} 291 292static const struct cdns_salvo_data cdns_nxp_salvo_data = { 293 2, 294 cdns_nxp_sequence_pair, 295 ARRAY_SIZE(cdns_nxp_sequence_pair), 296}; 297 298static const struct of_device_id cdns_salvo_phy_of_match[] = { 299 { 300 .compatible = "nxp,salvo-phy", 301 .data = &cdns_nxp_salvo_data, 302 }, 303 {} 304}; 305MODULE_DEVICE_TABLE(of, cdns_salvo_phy_of_match); 306 307static struct platform_driver cdns_salvo_phy_driver = { 308 .probe = cdns_salvo_phy_probe, 309 .driver = { 310 .name = "cdns-salvo-phy", 311 .of_match_table = cdns_salvo_phy_of_match, 312 } 313}; 314module_platform_driver(cdns_salvo_phy_driver); 315 316MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>"); 317MODULE_LICENSE("GPL v2"); 318MODULE_DESCRIPTION("Cadence SALVO PHY Driver");