lan966x_serdes.c (14562B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2 3#include <linux/err.h> 4#include <linux/module.h> 5#include <linux/of.h> 6#include <linux/of_platform.h> 7#include <linux/phy.h> 8#include <linux/phy/phy.h> 9#include <linux/platform_device.h> 10 11#include <dt-bindings/phy/phy-lan966x-serdes.h> 12#include "lan966x_serdes_regs.h" 13 14#define PLL_CONF_MASK GENMASK(4, 3) 15#define PLL_CONF_25MHZ 0 16#define PLL_CONF_125MHZ 1 17#define PLL_CONF_SERDES_125MHZ 2 18#define PLL_CONF_BYPASS 3 19 20#define lan_offset_(id, tinst, tcnt, \ 21 gbase, ginst, gcnt, gwidth, \ 22 raddr, rinst, rcnt, rwidth) \ 23 (gbase + ((ginst) * gwidth) + raddr + ((rinst) * rwidth)) 24#define lan_offset(...) lan_offset_(__VA_ARGS__) 25 26#define lan_rmw(val, mask, reg, off) \ 27 lan_rmw_(val, mask, reg, lan_offset(off)) 28 29#define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \ 30 .idx = _idx, \ 31 .port = _port, \ 32 .mode = _mode, \ 33 .submode = _submode, \ 34 .mask = _mask, \ 35 .mux = _mux, \ 36} 37 38#define SERDES_MUX_GMII(i, p, m, c) \ 39 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_GMII, m, c) 40#define SERDES_MUX_SGMII(i, p, m, c) \ 41 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_SGMII, m, c) 42#define SERDES_MUX_QSGMII(i, p, m, c) \ 43 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c) 44#define SERDES_MUX_RGMII(i, p, m, c) \ 45 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c) 46 47static void lan_rmw_(u32 val, u32 mask, void __iomem *mem, u32 offset) 48{ 49 u32 v; 50 51 v = readl(mem + offset); 52 v = (v & ~mask) | (val & mask); 53 writel(v, mem + offset); 54} 55 56struct serdes_mux { 57 u8 idx; 58 u8 port; 59 enum phy_mode mode; 60 int submode; 61 u32 mask; 62 u32 mux; 63}; 64 65static const struct serdes_mux lan966x_serdes_muxes[] = { 66 SERDES_MUX_QSGMII(SERDES6G(1), 0, HSIO_HW_CFG_QSGMII_ENA, 67 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))), 68 SERDES_MUX_QSGMII(SERDES6G(1), 1, HSIO_HW_CFG_QSGMII_ENA, 69 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))), 70 SERDES_MUX_QSGMII(SERDES6G(1), 2, HSIO_HW_CFG_QSGMII_ENA, 71 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))), 72 SERDES_MUX_QSGMII(SERDES6G(1), 3, HSIO_HW_CFG_QSGMII_ENA, 73 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))), 74 75 SERDES_MUX_QSGMII(SERDES6G(2), 4, HSIO_HW_CFG_QSGMII_ENA, 76 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))), 77 SERDES_MUX_QSGMII(SERDES6G(2), 5, HSIO_HW_CFG_QSGMII_ENA, 78 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))), 79 SERDES_MUX_QSGMII(SERDES6G(2), 6, HSIO_HW_CFG_QSGMII_ENA, 80 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))), 81 SERDES_MUX_QSGMII(SERDES6G(2), 7, HSIO_HW_CFG_QSGMII_ENA, 82 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))), 83 84 SERDES_MUX_GMII(CU(0), 0, HSIO_HW_CFG_GMII_ENA, 85 HSIO_HW_CFG_GMII_ENA_SET(BIT(0))), 86 SERDES_MUX_GMII(CU(1), 1, HSIO_HW_CFG_GMII_ENA, 87 HSIO_HW_CFG_GMII_ENA_SET(BIT(1))), 88 89 SERDES_MUX_SGMII(SERDES6G(0), 0, HSIO_HW_CFG_SD6G_0_CFG, 0), 90 SERDES_MUX_SGMII(SERDES6G(1), 1, HSIO_HW_CFG_SD6G_1_CFG, 0), 91 SERDES_MUX_SGMII(SERDES6G(0), 2, HSIO_HW_CFG_SD6G_0_CFG, 92 HSIO_HW_CFG_SD6G_0_CFG_SET(1)), 93 SERDES_MUX_SGMII(SERDES6G(1), 3, HSIO_HW_CFG_SD6G_1_CFG, 94 HSIO_HW_CFG_SD6G_1_CFG_SET(1)), 95 96 SERDES_MUX_RGMII(RGMII(0), 2, HSIO_HW_CFG_RGMII_0_CFG | 97 HSIO_HW_CFG_RGMII_ENA, 98 HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) | 99 HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))), 100 SERDES_MUX_RGMII(RGMII(1), 3, HSIO_HW_CFG_RGMII_1_CFG | 101 HSIO_HW_CFG_RGMII_ENA, 102 HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) | 103 HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))), 104 SERDES_MUX_RGMII(RGMII(0), 5, HSIO_HW_CFG_RGMII_0_CFG | 105 HSIO_HW_CFG_RGMII_ENA, 106 HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) | 107 HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))), 108 SERDES_MUX_RGMII(RGMII(1), 6, HSIO_HW_CFG_RGMII_1_CFG | 109 HSIO_HW_CFG_RGMII_ENA, 110 HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) | 111 HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))), 112}; 113 114struct serdes_ctrl { 115 void __iomem *regs; 116 struct device *dev; 117 struct phy *phys[SERDES_MAX]; 118 int ref125; 119}; 120 121struct serdes_macro { 122 u8 idx; 123 int port; 124 struct serdes_ctrl *ctrl; 125 int speed; 126 phy_interface_t mode; 127}; 128 129enum lan966x_sd6g40_mode { 130 LAN966X_SD6G40_MODE_QSGMII, 131 LAN966X_SD6G40_MODE_SGMII, 132}; 133 134enum lan966x_sd6g40_ltx2rx { 135 LAN966X_SD6G40_TX2RX_LOOP_NONE, 136 LAN966X_SD6G40_LTX2RX 137}; 138 139struct lan966x_sd6g40_setup_args { 140 enum lan966x_sd6g40_mode mode; 141 enum lan966x_sd6g40_ltx2rx tx2rx_loop; 142 bool txinvert; 143 bool rxinvert; 144 bool refclk125M; 145 bool mute; 146}; 147 148struct lan966x_sd6g40_mode_args { 149 enum lan966x_sd6g40_mode mode; 150 u8 lane_10bit_sel; 151 u8 mpll_multiplier; 152 u8 ref_clkdiv2; 153 u8 tx_rate; 154 u8 rx_rate; 155}; 156 157struct lan966x_sd6g40_setup { 158 u8 rx_term_en; 159 u8 lane_10bit_sel; 160 u8 tx_invert; 161 u8 rx_invert; 162 u8 mpll_multiplier; 163 u8 lane_loopbk_en; 164 u8 ref_clkdiv2; 165 u8 tx_rate; 166 u8 rx_rate; 167}; 168 169static int lan966x_sd6g40_reg_cfg(struct serdes_macro *macro, 170 struct lan966x_sd6g40_setup *res_struct, 171 u32 idx) 172{ 173 u32 value; 174 175 /* Note: SerDes HSIO is configured in 1G_LAN mode */ 176 lan_rmw(HSIO_SD_CFG_LANE_10BIT_SEL_SET(res_struct->lane_10bit_sel) | 177 HSIO_SD_CFG_RX_RATE_SET(res_struct->rx_rate) | 178 HSIO_SD_CFG_TX_RATE_SET(res_struct->tx_rate) | 179 HSIO_SD_CFG_TX_INVERT_SET(res_struct->tx_invert) | 180 HSIO_SD_CFG_RX_INVERT_SET(res_struct->rx_invert) | 181 HSIO_SD_CFG_LANE_LOOPBK_EN_SET(res_struct->lane_loopbk_en) | 182 HSIO_SD_CFG_RX_RESET_SET(0) | 183 HSIO_SD_CFG_TX_RESET_SET(0), 184 HSIO_SD_CFG_LANE_10BIT_SEL | 185 HSIO_SD_CFG_RX_RATE | 186 HSIO_SD_CFG_TX_RATE | 187 HSIO_SD_CFG_TX_INVERT | 188 HSIO_SD_CFG_RX_INVERT | 189 HSIO_SD_CFG_LANE_LOOPBK_EN | 190 HSIO_SD_CFG_RX_RESET | 191 HSIO_SD_CFG_TX_RESET, 192 macro->ctrl->regs, HSIO_SD_CFG(idx)); 193 194 lan_rmw(HSIO_MPLL_CFG_MPLL_MULTIPLIER_SET(res_struct->mpll_multiplier) | 195 HSIO_MPLL_CFG_REF_CLKDIV2_SET(res_struct->ref_clkdiv2), 196 HSIO_MPLL_CFG_MPLL_MULTIPLIER | 197 HSIO_MPLL_CFG_REF_CLKDIV2, 198 macro->ctrl->regs, HSIO_MPLL_CFG(idx)); 199 200 lan_rmw(HSIO_SD_CFG_RX_TERM_EN_SET(res_struct->rx_term_en), 201 HSIO_SD_CFG_RX_TERM_EN, 202 macro->ctrl->regs, HSIO_SD_CFG(idx)); 203 204 lan_rmw(HSIO_MPLL_CFG_REF_SSP_EN_SET(1), 205 HSIO_MPLL_CFG_REF_SSP_EN, 206 macro->ctrl->regs, HSIO_MPLL_CFG(idx)); 207 208 usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); 209 210 lan_rmw(HSIO_SD_CFG_PHY_RESET_SET(0), 211 HSIO_SD_CFG_PHY_RESET, 212 macro->ctrl->regs, HSIO_SD_CFG(idx)); 213 214 usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); 215 216 lan_rmw(HSIO_MPLL_CFG_MPLL_EN_SET(1), 217 HSIO_MPLL_CFG_MPLL_EN, 218 macro->ctrl->regs, HSIO_MPLL_CFG(idx)); 219 220 usleep_range(7 * USEC_PER_MSEC, 8 * USEC_PER_MSEC); 221 222 value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx))); 223 value = HSIO_SD_STAT_MPLL_STATE_GET(value); 224 if (value != 0x1) { 225 dev_err(macro->ctrl->dev, 226 "Unexpected sd_sd_stat[%u] mpll_state was 0x1 but is 0x%x\n", 227 idx, value); 228 return -EIO; 229 } 230 231 lan_rmw(HSIO_SD_CFG_TX_CM_EN_SET(1), 232 HSIO_SD_CFG_TX_CM_EN, 233 macro->ctrl->regs, HSIO_SD_CFG(idx)); 234 235 usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); 236 237 value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx))); 238 value = HSIO_SD_STAT_TX_CM_STATE_GET(value); 239 if (value != 0x1) { 240 dev_err(macro->ctrl->dev, 241 "Unexpected sd_sd_stat[%u] tx_cm_state was 0x1 but is 0x%x\n", 242 idx, value); 243 return -EIO; 244 } 245 246 lan_rmw(HSIO_SD_CFG_RX_PLL_EN_SET(1) | 247 HSIO_SD_CFG_TX_EN_SET(1), 248 HSIO_SD_CFG_RX_PLL_EN | 249 HSIO_SD_CFG_TX_EN, 250 macro->ctrl->regs, HSIO_SD_CFG(idx)); 251 252 usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); 253 254 /* Waiting for serdes 0 rx DPLL to lock... */ 255 value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx))); 256 value = HSIO_SD_STAT_RX_PLL_STATE_GET(value); 257 if (value != 0x1) { 258 dev_err(macro->ctrl->dev, 259 "Unexpected sd_sd_stat[%u] rx_pll_state was 0x1 but is 0x%x\n", 260 idx, value); 261 return -EIO; 262 } 263 264 /* Waiting for serdes 0 tx operational... */ 265 value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx))); 266 value = HSIO_SD_STAT_TX_STATE_GET(value); 267 if (value != 0x1) { 268 dev_err(macro->ctrl->dev, 269 "Unexpected sd_sd_stat[%u] tx_state was 0x1 but is 0x%x\n", 270 idx, value); 271 return -EIO; 272 } 273 274 lan_rmw(HSIO_SD_CFG_TX_DATA_EN_SET(1) | 275 HSIO_SD_CFG_RX_DATA_EN_SET(1), 276 HSIO_SD_CFG_TX_DATA_EN | 277 HSIO_SD_CFG_RX_DATA_EN, 278 macro->ctrl->regs, HSIO_SD_CFG(idx)); 279 280 return 0; 281} 282 283static int lan966x_sd6g40_get_conf_from_mode(struct serdes_macro *macro, 284 enum lan966x_sd6g40_mode f_mode, 285 bool ref125M, 286 struct lan966x_sd6g40_mode_args *ret_val) 287{ 288 switch (f_mode) { 289 case LAN966X_SD6G40_MODE_QSGMII: 290 ret_val->lane_10bit_sel = 0; 291 if (ref125M) { 292 ret_val->mpll_multiplier = 40; 293 ret_val->ref_clkdiv2 = 0x1; 294 ret_val->tx_rate = 0x0; 295 ret_val->rx_rate = 0x0; 296 } else { 297 ret_val->mpll_multiplier = 100; 298 ret_val->ref_clkdiv2 = 0x0; 299 ret_val->tx_rate = 0x0; 300 ret_val->rx_rate = 0x0; 301 } 302 break; 303 304 case LAN966X_SD6G40_MODE_SGMII: 305 ret_val->lane_10bit_sel = 1; 306 if (ref125M) { 307 ret_val->mpll_multiplier = macro->speed == SPEED_2500 ? 50 : 40; 308 ret_val->ref_clkdiv2 = 0x1; 309 ret_val->tx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2; 310 ret_val->rx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2; 311 } else { 312 ret_val->mpll_multiplier = macro->speed == SPEED_2500 ? 125 : 100; 313 ret_val->ref_clkdiv2 = 0x0; 314 ret_val->tx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2; 315 ret_val->rx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2; 316 } 317 break; 318 319 default: 320 return -EOPNOTSUPP; 321 } 322 323 return 0; 324} 325 326static int lan966x_calc_sd6g40_setup_lane(struct serdes_macro *macro, 327 struct lan966x_sd6g40_setup_args config, 328 struct lan966x_sd6g40_setup *ret_val) 329{ 330 struct lan966x_sd6g40_mode_args sd6g40_mode; 331 struct lan966x_sd6g40_mode_args *mode_args = &sd6g40_mode; 332 int ret; 333 334 ret = lan966x_sd6g40_get_conf_from_mode(macro, config.mode, 335 config.refclk125M, mode_args); 336 if (ret) 337 return ret; 338 339 ret_val->lane_10bit_sel = mode_args->lane_10bit_sel; 340 ret_val->rx_rate = mode_args->rx_rate; 341 ret_val->tx_rate = mode_args->tx_rate; 342 ret_val->mpll_multiplier = mode_args->mpll_multiplier; 343 ret_val->ref_clkdiv2 = mode_args->ref_clkdiv2; 344 ret_val->rx_term_en = 0; 345 346 if (config.tx2rx_loop == LAN966X_SD6G40_LTX2RX) 347 ret_val->lane_loopbk_en = 1; 348 else 349 ret_val->lane_loopbk_en = 0; 350 351 ret_val->tx_invert = !!config.txinvert; 352 ret_val->rx_invert = !!config.rxinvert; 353 354 return 0; 355} 356 357static int lan966x_sd6g40_setup_lane(struct serdes_macro *macro, 358 struct lan966x_sd6g40_setup_args config, 359 u32 idx) 360{ 361 struct lan966x_sd6g40_setup calc_results = {}; 362 int ret; 363 364 ret = lan966x_calc_sd6g40_setup_lane(macro, config, &calc_results); 365 if (ret) 366 return ret; 367 368 return lan966x_sd6g40_reg_cfg(macro, &calc_results, idx); 369} 370 371static int lan966x_sd6g40_setup(struct serdes_macro *macro, u32 idx, int mode) 372{ 373 struct lan966x_sd6g40_setup_args conf = {}; 374 375 conf.refclk125M = macro->ctrl->ref125; 376 377 if (mode == PHY_INTERFACE_MODE_QSGMII) 378 conf.mode = LAN966X_SD6G40_MODE_QSGMII; 379 else 380 conf.mode = LAN966X_SD6G40_MODE_SGMII; 381 382 return lan966x_sd6g40_setup_lane(macro, conf, idx); 383} 384 385static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) 386{ 387 struct serdes_macro *macro = phy_get_drvdata(phy); 388 unsigned int i; 389 int val; 390 391 /* As of now only PHY_MODE_ETHERNET is supported */ 392 if (mode != PHY_MODE_ETHERNET) 393 return -EOPNOTSUPP; 394 395 if (submode == PHY_INTERFACE_MODE_2500BASEX) 396 macro->speed = SPEED_2500; 397 else 398 macro->speed = SPEED_1000; 399 400 if (submode == PHY_INTERFACE_MODE_1000BASEX || 401 submode == PHY_INTERFACE_MODE_2500BASEX) 402 submode = PHY_INTERFACE_MODE_SGMII; 403 404 for (i = 0; i < ARRAY_SIZE(lan966x_serdes_muxes); i++) { 405 if (macro->idx != lan966x_serdes_muxes[i].idx || 406 mode != lan966x_serdes_muxes[i].mode || 407 submode != lan966x_serdes_muxes[i].submode || 408 macro->port != lan966x_serdes_muxes[i].port) 409 continue; 410 411 val = readl(macro->ctrl->regs + lan_offset(HSIO_HW_CFG)); 412 val |= lan966x_serdes_muxes[i].mux; 413 lan_rmw(val, lan966x_serdes_muxes[i].mask, 414 macro->ctrl->regs, HSIO_HW_CFG); 415 416 macro->mode = lan966x_serdes_muxes[i].submode; 417 418 if (macro->idx < CU_MAX) 419 return 0; 420 421 if (macro->idx < SERDES6G_MAX) 422 return lan966x_sd6g40_setup(macro, 423 macro->idx - (CU_MAX + 1), 424 macro->mode); 425 426 if (macro->idx < RGMII_MAX) 427 return 0; 428 429 return -EOPNOTSUPP; 430 } 431 432 return -EINVAL; 433} 434 435static const struct phy_ops serdes_ops = { 436 .set_mode = serdes_set_mode, 437 .owner = THIS_MODULE, 438}; 439 440static struct phy *serdes_simple_xlate(struct device *dev, 441 struct of_phandle_args *args) 442{ 443 struct serdes_ctrl *ctrl = dev_get_drvdata(dev); 444 unsigned int port, idx, i; 445 446 if (args->args_count != 2) 447 return ERR_PTR(-EINVAL); 448 449 port = args->args[0]; 450 idx = args->args[1]; 451 452 for (i = 0; i < SERDES_MAX; i++) { 453 struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]); 454 455 if (idx != macro->idx) 456 continue; 457 458 macro->port = port; 459 return ctrl->phys[i]; 460 } 461 462 return ERR_PTR(-ENODEV); 463} 464 465static int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx, struct phy **phy) 466{ 467 struct serdes_macro *macro; 468 469 *phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops); 470 if (IS_ERR(*phy)) 471 return PTR_ERR(*phy); 472 473 macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL); 474 if (!macro) 475 return -ENOMEM; 476 477 macro->idx = idx; 478 macro->ctrl = ctrl; 479 macro->port = -1; 480 481 phy_set_drvdata(*phy, macro); 482 483 return 0; 484} 485 486static int serdes_probe(struct platform_device *pdev) 487{ 488 struct phy_provider *provider; 489 struct serdes_ctrl *ctrl; 490 void __iomem *hw_stat; 491 unsigned int i; 492 u32 val; 493 int ret; 494 495 ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 496 if (!ctrl) 497 return -ENOMEM; 498 499 ctrl->dev = &pdev->dev; 500 ctrl->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 501 if (IS_ERR(ctrl->regs)) 502 return PTR_ERR(ctrl->regs); 503 504 hw_stat = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); 505 if (IS_ERR(hw_stat)) 506 return PTR_ERR(hw_stat); 507 508 for (i = 0; i < SERDES_MAX; i++) { 509 ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]); 510 if (ret) 511 return ret; 512 } 513 514 val = readl(hw_stat); 515 val = FIELD_GET(PLL_CONF_MASK, val); 516 ctrl->ref125 = (val == PLL_CONF_125MHZ || 517 val == PLL_CONF_SERDES_125MHZ); 518 519 dev_set_drvdata(&pdev->dev, ctrl); 520 521 provider = devm_of_phy_provider_register(ctrl->dev, 522 serdes_simple_xlate); 523 524 return PTR_ERR_OR_ZERO(provider); 525} 526 527static const struct of_device_id serdes_ids[] = { 528 { .compatible = "microchip,lan966x-serdes", }, 529 {}, 530}; 531MODULE_DEVICE_TABLE(of, serdes_ids); 532 533static struct platform_driver mscc_lan966x_serdes = { 534 .probe = serdes_probe, 535 .driver = { 536 .name = "microchip,lan966x-serdes", 537 .of_match_table = of_match_ptr(serdes_ids), 538 }, 539}; 540 541module_platform_driver(mscc_lan966x_serdes); 542 543MODULE_DESCRIPTION("Microchip lan966x switch serdes driver"); 544MODULE_AUTHOR("Horatiu Vultur <horatiu.vultur@microchip.com>"); 545MODULE_LICENSE("GPL v2");