Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 
0003 #include <linux/err.h>
0004 #include <linux/module.h>
0005 #include <linux/of.h>
0006 #include <linux/of_platform.h>
0007 #include <linux/phy.h>
0008 #include <linux/phy/phy.h>
0009 #include <linux/platform_device.h>
0010 
0011 #include <dt-bindings/phy/phy-lan966x-serdes.h>
0012 #include "lan966x_serdes_regs.h"
0013 
0014 #define PLL_CONF_MASK       GENMASK(4, 3)
0015 #define PLL_CONF_25MHZ      0
0016 #define PLL_CONF_125MHZ     1
0017 #define PLL_CONF_SERDES_125MHZ  2
0018 #define PLL_CONF_BYPASS     3
0019 
0020 #define lan_offset_(id, tinst, tcnt,            \
0021            gbase, ginst, gcnt, gwidth,      \
0022            raddr, rinst, rcnt, rwidth)      \
0023     (gbase + ((ginst) * gwidth) + raddr + ((rinst) * rwidth))
0024 #define lan_offset(...) lan_offset_(__VA_ARGS__)
0025 
0026 #define lan_rmw(val, mask, reg, off)        \
0027     lan_rmw_(val, mask, reg, lan_offset(off))
0028 
0029 #define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \
0030     .idx = _idx,                        \
0031     .port = _port,                      \
0032     .mode = _mode,                      \
0033     .submode = _submode,                    \
0034     .mask = _mask,                      \
0035     .mux = _mux,                        \
0036 }
0037 
0038 #define SERDES_MUX_GMII(i, p, m, c) \
0039     SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_GMII, m, c)
0040 #define SERDES_MUX_SGMII(i, p, m, c) \
0041     SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_SGMII, m, c)
0042 #define SERDES_MUX_QSGMII(i, p, m, c) \
0043     SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c)
0044 #define SERDES_MUX_RGMII(i, p, m, c) \
0045     SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c)
0046 
0047 static void lan_rmw_(u32 val, u32 mask, void __iomem *mem, u32 offset)
0048 {
0049     u32 v;
0050 
0051     v = readl(mem + offset);
0052     v = (v & ~mask) | (val & mask);
0053     writel(v, mem + offset);
0054 }
0055 
0056 struct serdes_mux {
0057     u8          idx;
0058     u8          port;
0059     enum phy_mode       mode;
0060     int         submode;
0061     u32         mask;
0062     u32         mux;
0063 };
0064 
0065 static const struct serdes_mux lan966x_serdes_muxes[] = {
0066     SERDES_MUX_QSGMII(SERDES6G(1), 0, HSIO_HW_CFG_QSGMII_ENA,
0067               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
0068     SERDES_MUX_QSGMII(SERDES6G(1), 1, HSIO_HW_CFG_QSGMII_ENA,
0069               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
0070     SERDES_MUX_QSGMII(SERDES6G(1), 2, HSIO_HW_CFG_QSGMII_ENA,
0071               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
0072     SERDES_MUX_QSGMII(SERDES6G(1), 3, HSIO_HW_CFG_QSGMII_ENA,
0073               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
0074 
0075     SERDES_MUX_QSGMII(SERDES6G(2), 4, HSIO_HW_CFG_QSGMII_ENA,
0076               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
0077     SERDES_MUX_QSGMII(SERDES6G(2), 5, HSIO_HW_CFG_QSGMII_ENA,
0078               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
0079     SERDES_MUX_QSGMII(SERDES6G(2), 6, HSIO_HW_CFG_QSGMII_ENA,
0080               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
0081     SERDES_MUX_QSGMII(SERDES6G(2), 7, HSIO_HW_CFG_QSGMII_ENA,
0082               HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
0083 
0084     SERDES_MUX_GMII(CU(0), 0, HSIO_HW_CFG_GMII_ENA,
0085             HSIO_HW_CFG_GMII_ENA_SET(BIT(0))),
0086     SERDES_MUX_GMII(CU(1), 1, HSIO_HW_CFG_GMII_ENA,
0087             HSIO_HW_CFG_GMII_ENA_SET(BIT(1))),
0088 
0089     SERDES_MUX_SGMII(SERDES6G(0), 0, HSIO_HW_CFG_SD6G_0_CFG, 0),
0090     SERDES_MUX_SGMII(SERDES6G(1), 1, HSIO_HW_CFG_SD6G_1_CFG, 0),
0091     SERDES_MUX_SGMII(SERDES6G(0), 2, HSIO_HW_CFG_SD6G_0_CFG,
0092              HSIO_HW_CFG_SD6G_0_CFG_SET(1)),
0093     SERDES_MUX_SGMII(SERDES6G(1), 3, HSIO_HW_CFG_SD6G_1_CFG,
0094              HSIO_HW_CFG_SD6G_1_CFG_SET(1)),
0095 
0096     SERDES_MUX_RGMII(RGMII(0), 2, HSIO_HW_CFG_RGMII_0_CFG |
0097              HSIO_HW_CFG_RGMII_ENA,
0098              HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) |
0099              HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))),
0100     SERDES_MUX_RGMII(RGMII(1), 3, HSIO_HW_CFG_RGMII_1_CFG |
0101              HSIO_HW_CFG_RGMII_ENA,
0102              HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) |
0103              HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))),
0104     SERDES_MUX_RGMII(RGMII(0), 5, HSIO_HW_CFG_RGMII_0_CFG |
0105              HSIO_HW_CFG_RGMII_ENA,
0106              HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) |
0107              HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))),
0108     SERDES_MUX_RGMII(RGMII(1), 6, HSIO_HW_CFG_RGMII_1_CFG |
0109              HSIO_HW_CFG_RGMII_ENA,
0110              HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) |
0111              HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))),
0112 };
0113 
0114 struct serdes_ctrl {
0115     void __iomem        *regs;
0116     struct device       *dev;
0117     struct phy      *phys[SERDES_MAX];
0118     int         ref125;
0119 };
0120 
0121 struct serdes_macro {
0122     u8          idx;
0123     int         port;
0124     struct serdes_ctrl  *ctrl;
0125     int         speed;
0126     phy_interface_t     mode;
0127 };
0128 
0129 enum lan966x_sd6g40_mode {
0130     LAN966X_SD6G40_MODE_QSGMII,
0131     LAN966X_SD6G40_MODE_SGMII,
0132 };
0133 
0134 enum lan966x_sd6g40_ltx2rx {
0135     LAN966X_SD6G40_TX2RX_LOOP_NONE,
0136     LAN966X_SD6G40_LTX2RX
0137 };
0138 
0139 struct lan966x_sd6g40_setup_args {
0140     enum lan966x_sd6g40_mode    mode;
0141     enum lan966x_sd6g40_ltx2rx  tx2rx_loop;
0142     bool                txinvert;
0143     bool                rxinvert;
0144     bool                refclk125M;
0145     bool                mute;
0146 };
0147 
0148 struct lan966x_sd6g40_mode_args {
0149     enum lan966x_sd6g40_mode    mode;
0150     u8               lane_10bit_sel;
0151     u8               mpll_multiplier;
0152     u8               ref_clkdiv2;
0153     u8               tx_rate;
0154     u8               rx_rate;
0155 };
0156 
0157 struct lan966x_sd6g40_setup {
0158     u8  rx_term_en;
0159     u8  lane_10bit_sel;
0160     u8  tx_invert;
0161     u8  rx_invert;
0162     u8  mpll_multiplier;
0163     u8  lane_loopbk_en;
0164     u8  ref_clkdiv2;
0165     u8  tx_rate;
0166     u8  rx_rate;
0167 };
0168 
0169 static int lan966x_sd6g40_reg_cfg(struct serdes_macro *macro,
0170                   struct lan966x_sd6g40_setup *res_struct,
0171                   u32 idx)
0172 {
0173     u32 value;
0174 
0175     /* Note: SerDes HSIO is configured in 1G_LAN mode */
0176     lan_rmw(HSIO_SD_CFG_LANE_10BIT_SEL_SET(res_struct->lane_10bit_sel) |
0177         HSIO_SD_CFG_RX_RATE_SET(res_struct->rx_rate) |
0178         HSIO_SD_CFG_TX_RATE_SET(res_struct->tx_rate) |
0179         HSIO_SD_CFG_TX_INVERT_SET(res_struct->tx_invert) |
0180         HSIO_SD_CFG_RX_INVERT_SET(res_struct->rx_invert) |
0181         HSIO_SD_CFG_LANE_LOOPBK_EN_SET(res_struct->lane_loopbk_en) |
0182         HSIO_SD_CFG_RX_RESET_SET(0) |
0183         HSIO_SD_CFG_TX_RESET_SET(0),
0184         HSIO_SD_CFG_LANE_10BIT_SEL |
0185         HSIO_SD_CFG_RX_RATE |
0186         HSIO_SD_CFG_TX_RATE |
0187         HSIO_SD_CFG_TX_INVERT |
0188         HSIO_SD_CFG_RX_INVERT |
0189         HSIO_SD_CFG_LANE_LOOPBK_EN |
0190         HSIO_SD_CFG_RX_RESET |
0191         HSIO_SD_CFG_TX_RESET,
0192         macro->ctrl->regs, HSIO_SD_CFG(idx));
0193 
0194     lan_rmw(HSIO_MPLL_CFG_MPLL_MULTIPLIER_SET(res_struct->mpll_multiplier) |
0195         HSIO_MPLL_CFG_REF_CLKDIV2_SET(res_struct->ref_clkdiv2),
0196         HSIO_MPLL_CFG_MPLL_MULTIPLIER |
0197         HSIO_MPLL_CFG_REF_CLKDIV2,
0198         macro->ctrl->regs, HSIO_MPLL_CFG(idx));
0199 
0200     lan_rmw(HSIO_SD_CFG_RX_TERM_EN_SET(res_struct->rx_term_en),
0201         HSIO_SD_CFG_RX_TERM_EN,
0202         macro->ctrl->regs, HSIO_SD_CFG(idx));
0203 
0204     lan_rmw(HSIO_MPLL_CFG_REF_SSP_EN_SET(1),
0205         HSIO_MPLL_CFG_REF_SSP_EN,
0206         macro->ctrl->regs, HSIO_MPLL_CFG(idx));
0207 
0208     usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
0209 
0210     lan_rmw(HSIO_SD_CFG_PHY_RESET_SET(0),
0211         HSIO_SD_CFG_PHY_RESET,
0212         macro->ctrl->regs, HSIO_SD_CFG(idx));
0213 
0214     usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
0215 
0216     lan_rmw(HSIO_MPLL_CFG_MPLL_EN_SET(1),
0217         HSIO_MPLL_CFG_MPLL_EN,
0218         macro->ctrl->regs, HSIO_MPLL_CFG(idx));
0219 
0220     usleep_range(7 * USEC_PER_MSEC, 8 * USEC_PER_MSEC);
0221 
0222     value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
0223     value = HSIO_SD_STAT_MPLL_STATE_GET(value);
0224     if (value != 0x1) {
0225         dev_err(macro->ctrl->dev,
0226             "Unexpected sd_sd_stat[%u] mpll_state was 0x1 but is 0x%x\n",
0227             idx, value);
0228         return -EIO;
0229     }
0230 
0231     lan_rmw(HSIO_SD_CFG_TX_CM_EN_SET(1),
0232         HSIO_SD_CFG_TX_CM_EN,
0233         macro->ctrl->regs, HSIO_SD_CFG(idx));
0234 
0235     usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
0236 
0237     value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
0238     value = HSIO_SD_STAT_TX_CM_STATE_GET(value);
0239     if (value != 0x1) {
0240         dev_err(macro->ctrl->dev,
0241             "Unexpected sd_sd_stat[%u] tx_cm_state was 0x1 but is 0x%x\n",
0242             idx, value);
0243         return -EIO;
0244     }
0245 
0246     lan_rmw(HSIO_SD_CFG_RX_PLL_EN_SET(1) |
0247         HSIO_SD_CFG_TX_EN_SET(1),
0248         HSIO_SD_CFG_RX_PLL_EN |
0249         HSIO_SD_CFG_TX_EN,
0250         macro->ctrl->regs, HSIO_SD_CFG(idx));
0251 
0252     usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
0253 
0254     /* Waiting for serdes 0 rx DPLL to lock...  */
0255     value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
0256     value = HSIO_SD_STAT_RX_PLL_STATE_GET(value);
0257     if (value != 0x1) {
0258         dev_err(macro->ctrl->dev,
0259             "Unexpected sd_sd_stat[%u] rx_pll_state was 0x1 but is 0x%x\n",
0260             idx, value);
0261         return -EIO;
0262     }
0263 
0264     /* Waiting for serdes 0 tx operational...  */
0265     value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
0266     value = HSIO_SD_STAT_TX_STATE_GET(value);
0267     if (value != 0x1) {
0268         dev_err(macro->ctrl->dev,
0269             "Unexpected sd_sd_stat[%u] tx_state was 0x1 but is 0x%x\n",
0270             idx, value);
0271         return -EIO;
0272     }
0273 
0274     lan_rmw(HSIO_SD_CFG_TX_DATA_EN_SET(1) |
0275         HSIO_SD_CFG_RX_DATA_EN_SET(1),
0276         HSIO_SD_CFG_TX_DATA_EN |
0277         HSIO_SD_CFG_RX_DATA_EN,
0278         macro->ctrl->regs, HSIO_SD_CFG(idx));
0279 
0280     return 0;
0281 }
0282 
0283 static int lan966x_sd6g40_get_conf_from_mode(struct serdes_macro *macro,
0284                          enum lan966x_sd6g40_mode f_mode,
0285                          bool ref125M,
0286                          struct lan966x_sd6g40_mode_args *ret_val)
0287 {
0288     switch (f_mode) {
0289     case LAN966X_SD6G40_MODE_QSGMII:
0290         ret_val->lane_10bit_sel = 0;
0291         if (ref125M) {
0292             ret_val->mpll_multiplier = 40;
0293             ret_val->ref_clkdiv2 = 0x1;
0294             ret_val->tx_rate = 0x0;
0295             ret_val->rx_rate = 0x0;
0296         } else {
0297             ret_val->mpll_multiplier = 100;
0298             ret_val->ref_clkdiv2 = 0x0;
0299             ret_val->tx_rate = 0x0;
0300             ret_val->rx_rate = 0x0;
0301         }
0302         break;
0303 
0304     case LAN966X_SD6G40_MODE_SGMII:
0305         ret_val->lane_10bit_sel = 1;
0306         if (ref125M) {
0307             ret_val->mpll_multiplier = macro->speed == SPEED_2500 ? 50 : 40;
0308             ret_val->ref_clkdiv2 = 0x1;
0309             ret_val->tx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
0310             ret_val->rx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
0311         } else {
0312             ret_val->mpll_multiplier = macro->speed == SPEED_2500 ? 125 : 100;
0313             ret_val->ref_clkdiv2 = 0x0;
0314             ret_val->tx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
0315             ret_val->rx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
0316         }
0317         break;
0318 
0319     default:
0320         return -EOPNOTSUPP;
0321     }
0322 
0323     return 0;
0324 }
0325 
0326 static int lan966x_calc_sd6g40_setup_lane(struct serdes_macro *macro,
0327                       struct lan966x_sd6g40_setup_args config,
0328                       struct lan966x_sd6g40_setup *ret_val)
0329 {
0330     struct lan966x_sd6g40_mode_args sd6g40_mode;
0331     struct lan966x_sd6g40_mode_args *mode_args = &sd6g40_mode;
0332     int ret;
0333 
0334     ret = lan966x_sd6g40_get_conf_from_mode(macro, config.mode,
0335                         config.refclk125M, mode_args);
0336     if (ret)
0337         return ret;
0338 
0339     ret_val->lane_10bit_sel = mode_args->lane_10bit_sel;
0340     ret_val->rx_rate = mode_args->rx_rate;
0341     ret_val->tx_rate = mode_args->tx_rate;
0342     ret_val->mpll_multiplier = mode_args->mpll_multiplier;
0343     ret_val->ref_clkdiv2 = mode_args->ref_clkdiv2;
0344     ret_val->rx_term_en = 0;
0345 
0346     if (config.tx2rx_loop == LAN966X_SD6G40_LTX2RX)
0347         ret_val->lane_loopbk_en = 1;
0348     else
0349         ret_val->lane_loopbk_en = 0;
0350 
0351     ret_val->tx_invert = !!config.txinvert;
0352     ret_val->rx_invert = !!config.rxinvert;
0353 
0354     return 0;
0355 }
0356 
0357 static int lan966x_sd6g40_setup_lane(struct serdes_macro *macro,
0358                      struct lan966x_sd6g40_setup_args config,
0359                      u32 idx)
0360 {
0361     struct lan966x_sd6g40_setup calc_results = {};
0362     int ret;
0363 
0364     ret = lan966x_calc_sd6g40_setup_lane(macro, config, &calc_results);
0365     if (ret)
0366         return ret;
0367 
0368     return lan966x_sd6g40_reg_cfg(macro, &calc_results, idx);
0369 }
0370 
0371 static int lan966x_sd6g40_setup(struct serdes_macro *macro, u32 idx, int mode)
0372 {
0373     struct lan966x_sd6g40_setup_args conf = {};
0374 
0375     conf.refclk125M = macro->ctrl->ref125;
0376 
0377     if (mode == PHY_INTERFACE_MODE_QSGMII)
0378         conf.mode = LAN966X_SD6G40_MODE_QSGMII;
0379     else
0380         conf.mode = LAN966X_SD6G40_MODE_SGMII;
0381 
0382     return lan966x_sd6g40_setup_lane(macro, conf, idx);
0383 }
0384 
0385 static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode)
0386 {
0387     struct serdes_macro *macro = phy_get_drvdata(phy);
0388     unsigned int i;
0389     int val;
0390 
0391     /* As of now only PHY_MODE_ETHERNET is supported */
0392     if (mode != PHY_MODE_ETHERNET)
0393         return -EOPNOTSUPP;
0394 
0395     if (submode == PHY_INTERFACE_MODE_2500BASEX)
0396         macro->speed = SPEED_2500;
0397     else
0398         macro->speed = SPEED_1000;
0399 
0400     if (submode == PHY_INTERFACE_MODE_1000BASEX ||
0401         submode == PHY_INTERFACE_MODE_2500BASEX)
0402         submode = PHY_INTERFACE_MODE_SGMII;
0403 
0404     for (i = 0; i < ARRAY_SIZE(lan966x_serdes_muxes); i++) {
0405         if (macro->idx != lan966x_serdes_muxes[i].idx ||
0406             mode != lan966x_serdes_muxes[i].mode ||
0407             submode != lan966x_serdes_muxes[i].submode ||
0408             macro->port != lan966x_serdes_muxes[i].port)
0409             continue;
0410 
0411         val = readl(macro->ctrl->regs + lan_offset(HSIO_HW_CFG));
0412         val |= lan966x_serdes_muxes[i].mux;
0413         lan_rmw(val, lan966x_serdes_muxes[i].mask,
0414             macro->ctrl->regs, HSIO_HW_CFG);
0415 
0416         macro->mode = lan966x_serdes_muxes[i].submode;
0417 
0418         if (macro->idx < CU_MAX)
0419             return 0;
0420 
0421         if (macro->idx < SERDES6G_MAX)
0422             return lan966x_sd6g40_setup(macro,
0423                             macro->idx - (CU_MAX + 1),
0424                             macro->mode);
0425 
0426         if (macro->idx < RGMII_MAX)
0427             return 0;
0428 
0429         return -EOPNOTSUPP;
0430     }
0431 
0432     return -EINVAL;
0433 }
0434 
0435 static const struct phy_ops serdes_ops = {
0436     .set_mode   = serdes_set_mode,
0437     .owner      = THIS_MODULE,
0438 };
0439 
0440 static struct phy *serdes_simple_xlate(struct device *dev,
0441                        struct of_phandle_args *args)
0442 {
0443     struct serdes_ctrl *ctrl = dev_get_drvdata(dev);
0444     unsigned int port, idx, i;
0445 
0446     if (args->args_count != 2)
0447         return ERR_PTR(-EINVAL);
0448 
0449     port = args->args[0];
0450     idx = args->args[1];
0451 
0452     for (i = 0; i < SERDES_MAX; i++) {
0453         struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]);
0454 
0455         if (idx != macro->idx)
0456             continue;
0457 
0458         macro->port = port;
0459         return ctrl->phys[i];
0460     }
0461 
0462     return ERR_PTR(-ENODEV);
0463 }
0464 
0465 static int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx, struct phy **phy)
0466 {
0467     struct serdes_macro *macro;
0468 
0469     *phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops);
0470     if (IS_ERR(*phy))
0471         return PTR_ERR(*phy);
0472 
0473     macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL);
0474     if (!macro)
0475         return -ENOMEM;
0476 
0477     macro->idx = idx;
0478     macro->ctrl = ctrl;
0479     macro->port = -1;
0480 
0481     phy_set_drvdata(*phy, macro);
0482 
0483     return 0;
0484 }
0485 
0486 static int serdes_probe(struct platform_device *pdev)
0487 {
0488     struct phy_provider *provider;
0489     struct serdes_ctrl *ctrl;
0490     void __iomem *hw_stat;
0491     unsigned int i;
0492     u32 val;
0493     int ret;
0494 
0495     ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
0496     if (!ctrl)
0497         return -ENOMEM;
0498 
0499     ctrl->dev = &pdev->dev;
0500     ctrl->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
0501     if (IS_ERR(ctrl->regs))
0502         return PTR_ERR(ctrl->regs);
0503 
0504     hw_stat = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
0505     if (IS_ERR(hw_stat))
0506         return PTR_ERR(hw_stat);
0507 
0508     for (i = 0; i < SERDES_MAX; i++) {
0509         ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]);
0510         if (ret)
0511             return ret;
0512     }
0513 
0514     val = readl(hw_stat);
0515     val = FIELD_GET(PLL_CONF_MASK, val);
0516     ctrl->ref125 = (val == PLL_CONF_125MHZ ||
0517             val == PLL_CONF_SERDES_125MHZ);
0518 
0519     dev_set_drvdata(&pdev->dev, ctrl);
0520 
0521     provider = devm_of_phy_provider_register(ctrl->dev,
0522                          serdes_simple_xlate);
0523 
0524     return PTR_ERR_OR_ZERO(provider);
0525 }
0526 
0527 static const struct of_device_id serdes_ids[] = {
0528     { .compatible = "microchip,lan966x-serdes", },
0529     {},
0530 };
0531 MODULE_DEVICE_TABLE(of, serdes_ids);
0532 
0533 static struct platform_driver mscc_lan966x_serdes = {
0534     .probe      = serdes_probe,
0535     .driver     = {
0536         .name   = "microchip,lan966x-serdes",
0537         .of_match_table = of_match_ptr(serdes_ids),
0538     },
0539 };
0540 
0541 module_platform_driver(mscc_lan966x_serdes);
0542 
0543 MODULE_DESCRIPTION("Microchip lan966x switch serdes driver");
0544 MODULE_AUTHOR("Horatiu Vultur <horatiu.vultur@microchip.com>");
0545 MODULE_LICENSE("GPL v2");