162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/err.h>
462306a36Sopenharmony_ci#include <linux/module.h>
562306a36Sopenharmony_ci#include <linux/of.h>
662306a36Sopenharmony_ci#include <linux/of_platform.h>
762306a36Sopenharmony_ci#include <linux/phy.h>
862306a36Sopenharmony_ci#include <linux/phy/phy.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <dt-bindings/phy/phy-lan966x-serdes.h>
1262306a36Sopenharmony_ci#include "lan966x_serdes_regs.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define PLL_CONF_MASK		GENMASK(4, 3)
1562306a36Sopenharmony_ci#define PLL_CONF_25MHZ		0
1662306a36Sopenharmony_ci#define PLL_CONF_125MHZ		1
1762306a36Sopenharmony_ci#define PLL_CONF_SERDES_125MHZ	2
1862306a36Sopenharmony_ci#define PLL_CONF_BYPASS		3
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define lan_offset_(id, tinst, tcnt,			\
2162306a36Sopenharmony_ci		   gbase, ginst, gcnt, gwidth,		\
2262306a36Sopenharmony_ci		   raddr, rinst, rcnt, rwidth)		\
2362306a36Sopenharmony_ci	(gbase + ((ginst) * gwidth) + raddr + ((rinst) * rwidth))
2462306a36Sopenharmony_ci#define lan_offset(...) lan_offset_(__VA_ARGS__)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define lan_rmw(val, mask, reg, off)		\
2762306a36Sopenharmony_ci	lan_rmw_(val, mask, reg, lan_offset(off))
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \
3062306a36Sopenharmony_ci	.idx = _idx,						\
3162306a36Sopenharmony_ci	.port = _port,						\
3262306a36Sopenharmony_ci	.mode = _mode,						\
3362306a36Sopenharmony_ci	.submode = _submode,					\
3462306a36Sopenharmony_ci	.mask = _mask,						\
3562306a36Sopenharmony_ci	.mux = _mux,						\
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define SERDES_MUX_GMII(i, p, m, c) \
3962306a36Sopenharmony_ci	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_GMII, m, c)
4062306a36Sopenharmony_ci#define SERDES_MUX_SGMII(i, p, m, c) \
4162306a36Sopenharmony_ci	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_SGMII, m, c)
4262306a36Sopenharmony_ci#define SERDES_MUX_QSGMII(i, p, m, c) \
4362306a36Sopenharmony_ci	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c)
4462306a36Sopenharmony_ci#define SERDES_MUX_RGMII(i, p, m, c) \
4562306a36Sopenharmony_ci	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c), \
4662306a36Sopenharmony_ci	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_TXID, m, c), \
4762306a36Sopenharmony_ci	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_RXID, m, c), \
4862306a36Sopenharmony_ci	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_ID, m, c)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void lan_rmw_(u32 val, u32 mask, void __iomem *mem, u32 offset)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	u32 v;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	v = readl(mem + offset);
5562306a36Sopenharmony_ci	v = (v & ~mask) | (val & mask);
5662306a36Sopenharmony_ci	writel(v, mem + offset);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct serdes_mux {
6062306a36Sopenharmony_ci	u8			idx;
6162306a36Sopenharmony_ci	u8			port;
6262306a36Sopenharmony_ci	enum phy_mode		mode;
6362306a36Sopenharmony_ci	int			submode;
6462306a36Sopenharmony_ci	u32			mask;
6562306a36Sopenharmony_ci	u32			mux;
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic const struct serdes_mux lan966x_serdes_muxes[] = {
6962306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(1), 0, HSIO_HW_CFG_QSGMII_ENA,
7062306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
7162306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(1), 1, HSIO_HW_CFG_QSGMII_ENA,
7262306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
7362306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(1), 2, HSIO_HW_CFG_QSGMII_ENA,
7462306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
7562306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(1), 3, HSIO_HW_CFG_QSGMII_ENA,
7662306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(2), 4, HSIO_HW_CFG_QSGMII_ENA,
7962306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
8062306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(2), 5, HSIO_HW_CFG_QSGMII_ENA,
8162306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
8262306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(2), 6, HSIO_HW_CFG_QSGMII_ENA,
8362306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
8462306a36Sopenharmony_ci	SERDES_MUX_QSGMII(SERDES6G(2), 7, HSIO_HW_CFG_QSGMII_ENA,
8562306a36Sopenharmony_ci			  HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	SERDES_MUX_GMII(CU(0), 0, HSIO_HW_CFG_GMII_ENA,
8862306a36Sopenharmony_ci			HSIO_HW_CFG_GMII_ENA_SET(BIT(0))),
8962306a36Sopenharmony_ci	SERDES_MUX_GMII(CU(1), 1, HSIO_HW_CFG_GMII_ENA,
9062306a36Sopenharmony_ci			HSIO_HW_CFG_GMII_ENA_SET(BIT(1))),
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	SERDES_MUX_SGMII(SERDES6G(0), 0, HSIO_HW_CFG_SD6G_0_CFG, 0),
9362306a36Sopenharmony_ci	SERDES_MUX_SGMII(SERDES6G(1), 1, HSIO_HW_CFG_SD6G_1_CFG, 0),
9462306a36Sopenharmony_ci	SERDES_MUX_SGMII(SERDES6G(0), 2, HSIO_HW_CFG_SD6G_0_CFG,
9562306a36Sopenharmony_ci			 HSIO_HW_CFG_SD6G_0_CFG_SET(1)),
9662306a36Sopenharmony_ci	SERDES_MUX_SGMII(SERDES6G(1), 3, HSIO_HW_CFG_SD6G_1_CFG,
9762306a36Sopenharmony_ci			 HSIO_HW_CFG_SD6G_1_CFG_SET(1)),
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	SERDES_MUX_RGMII(RGMII(0), 2, HSIO_HW_CFG_RGMII_0_CFG |
10062306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA |
10162306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA,
10262306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_0_CFG_SET(0) |
10362306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) |
10462306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA_SET(BIT(2))),
10562306a36Sopenharmony_ci	SERDES_MUX_RGMII(RGMII(1), 3, HSIO_HW_CFG_RGMII_1_CFG |
10662306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA |
10762306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA,
10862306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_1_CFG_SET(0) |
10962306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) |
11062306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA_SET(BIT(3))),
11162306a36Sopenharmony_ci	SERDES_MUX_RGMII(RGMII(0), 5, HSIO_HW_CFG_RGMII_0_CFG |
11262306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA |
11362306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA,
11462306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) |
11562306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) |
11662306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA_SET(BIT(5))),
11762306a36Sopenharmony_ci	SERDES_MUX_RGMII(RGMII(1), 6, HSIO_HW_CFG_RGMII_1_CFG |
11862306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA |
11962306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA,
12062306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) |
12162306a36Sopenharmony_ci			 HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) |
12262306a36Sopenharmony_ci			 HSIO_HW_CFG_GMII_ENA_SET(BIT(6))),
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistruct serdes_ctrl {
12662306a36Sopenharmony_ci	void __iomem		*regs;
12762306a36Sopenharmony_ci	struct device		*dev;
12862306a36Sopenharmony_ci	struct phy		*phys[SERDES_MAX];
12962306a36Sopenharmony_ci	int			ref125;
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistruct serdes_macro {
13362306a36Sopenharmony_ci	u8			idx;
13462306a36Sopenharmony_ci	int			port;
13562306a36Sopenharmony_ci	struct serdes_ctrl	*ctrl;
13662306a36Sopenharmony_ci	int			speed;
13762306a36Sopenharmony_ci	phy_interface_t		mode;
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cienum lan966x_sd6g40_mode {
14162306a36Sopenharmony_ci	LAN966X_SD6G40_MODE_QSGMII,
14262306a36Sopenharmony_ci	LAN966X_SD6G40_MODE_SGMII,
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cienum lan966x_sd6g40_ltx2rx {
14662306a36Sopenharmony_ci	LAN966X_SD6G40_TX2RX_LOOP_NONE,
14762306a36Sopenharmony_ci	LAN966X_SD6G40_LTX2RX
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistruct lan966x_sd6g40_setup_args {
15162306a36Sopenharmony_ci	enum lan966x_sd6g40_mode	mode;
15262306a36Sopenharmony_ci	enum lan966x_sd6g40_ltx2rx	tx2rx_loop;
15362306a36Sopenharmony_ci	bool				txinvert;
15462306a36Sopenharmony_ci	bool				rxinvert;
15562306a36Sopenharmony_ci	bool				refclk125M;
15662306a36Sopenharmony_ci	bool				mute;
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistruct lan966x_sd6g40_mode_args {
16062306a36Sopenharmony_ci	enum lan966x_sd6g40_mode	mode;
16162306a36Sopenharmony_ci	u8				 lane_10bit_sel;
16262306a36Sopenharmony_ci	u8				 mpll_multiplier;
16362306a36Sopenharmony_ci	u8				 ref_clkdiv2;
16462306a36Sopenharmony_ci	u8				 tx_rate;
16562306a36Sopenharmony_ci	u8				 rx_rate;
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistruct lan966x_sd6g40_setup {
16962306a36Sopenharmony_ci	u8	rx_term_en;
17062306a36Sopenharmony_ci	u8	lane_10bit_sel;
17162306a36Sopenharmony_ci	u8	tx_invert;
17262306a36Sopenharmony_ci	u8	rx_invert;
17362306a36Sopenharmony_ci	u8	mpll_multiplier;
17462306a36Sopenharmony_ci	u8	lane_loopbk_en;
17562306a36Sopenharmony_ci	u8	ref_clkdiv2;
17662306a36Sopenharmony_ci	u8	tx_rate;
17762306a36Sopenharmony_ci	u8	rx_rate;
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic int lan966x_sd6g40_reg_cfg(struct serdes_macro *macro,
18162306a36Sopenharmony_ci				  struct lan966x_sd6g40_setup *res_struct,
18262306a36Sopenharmony_ci				  u32 idx)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	u32 value;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* Note: SerDes HSIO is configured in 1G_LAN mode */
18762306a36Sopenharmony_ci	lan_rmw(HSIO_SD_CFG_LANE_10BIT_SEL_SET(res_struct->lane_10bit_sel) |
18862306a36Sopenharmony_ci		HSIO_SD_CFG_RX_RATE_SET(res_struct->rx_rate) |
18962306a36Sopenharmony_ci		HSIO_SD_CFG_TX_RATE_SET(res_struct->tx_rate) |
19062306a36Sopenharmony_ci		HSIO_SD_CFG_TX_INVERT_SET(res_struct->tx_invert) |
19162306a36Sopenharmony_ci		HSIO_SD_CFG_RX_INVERT_SET(res_struct->rx_invert) |
19262306a36Sopenharmony_ci		HSIO_SD_CFG_LANE_LOOPBK_EN_SET(res_struct->lane_loopbk_en) |
19362306a36Sopenharmony_ci		HSIO_SD_CFG_RX_RESET_SET(0) |
19462306a36Sopenharmony_ci		HSIO_SD_CFG_TX_RESET_SET(0),
19562306a36Sopenharmony_ci		HSIO_SD_CFG_LANE_10BIT_SEL |
19662306a36Sopenharmony_ci		HSIO_SD_CFG_RX_RATE |
19762306a36Sopenharmony_ci		HSIO_SD_CFG_TX_RATE |
19862306a36Sopenharmony_ci		HSIO_SD_CFG_TX_INVERT |
19962306a36Sopenharmony_ci		HSIO_SD_CFG_RX_INVERT |
20062306a36Sopenharmony_ci		HSIO_SD_CFG_LANE_LOOPBK_EN |
20162306a36Sopenharmony_ci		HSIO_SD_CFG_RX_RESET |
20262306a36Sopenharmony_ci		HSIO_SD_CFG_TX_RESET,
20362306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_SD_CFG(idx));
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	lan_rmw(HSIO_MPLL_CFG_MPLL_MULTIPLIER_SET(res_struct->mpll_multiplier) |
20662306a36Sopenharmony_ci		HSIO_MPLL_CFG_REF_CLKDIV2_SET(res_struct->ref_clkdiv2),
20762306a36Sopenharmony_ci		HSIO_MPLL_CFG_MPLL_MULTIPLIER |
20862306a36Sopenharmony_ci		HSIO_MPLL_CFG_REF_CLKDIV2,
20962306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_MPLL_CFG(idx));
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	lan_rmw(HSIO_SD_CFG_RX_TERM_EN_SET(res_struct->rx_term_en),
21262306a36Sopenharmony_ci		HSIO_SD_CFG_RX_TERM_EN,
21362306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_SD_CFG(idx));
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	lan_rmw(HSIO_MPLL_CFG_REF_SSP_EN_SET(1),
21662306a36Sopenharmony_ci		HSIO_MPLL_CFG_REF_SSP_EN,
21762306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_MPLL_CFG(idx));
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	lan_rmw(HSIO_SD_CFG_PHY_RESET_SET(0),
22262306a36Sopenharmony_ci		HSIO_SD_CFG_PHY_RESET,
22362306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_SD_CFG(idx));
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	lan_rmw(HSIO_MPLL_CFG_MPLL_EN_SET(1),
22862306a36Sopenharmony_ci		HSIO_MPLL_CFG_MPLL_EN,
22962306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_MPLL_CFG(idx));
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	usleep_range(7 * USEC_PER_MSEC, 8 * USEC_PER_MSEC);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
23462306a36Sopenharmony_ci	value = HSIO_SD_STAT_MPLL_STATE_GET(value);
23562306a36Sopenharmony_ci	if (value != 0x1) {
23662306a36Sopenharmony_ci		dev_err(macro->ctrl->dev,
23762306a36Sopenharmony_ci			"Unexpected sd_sd_stat[%u] mpll_state was 0x1 but is 0x%x\n",
23862306a36Sopenharmony_ci			idx, value);
23962306a36Sopenharmony_ci		return -EIO;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	lan_rmw(HSIO_SD_CFG_TX_CM_EN_SET(1),
24362306a36Sopenharmony_ci		HSIO_SD_CFG_TX_CM_EN,
24462306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_SD_CFG(idx));
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
24962306a36Sopenharmony_ci	value = HSIO_SD_STAT_TX_CM_STATE_GET(value);
25062306a36Sopenharmony_ci	if (value != 0x1) {
25162306a36Sopenharmony_ci		dev_err(macro->ctrl->dev,
25262306a36Sopenharmony_ci			"Unexpected sd_sd_stat[%u] tx_cm_state was 0x1 but is 0x%x\n",
25362306a36Sopenharmony_ci			idx, value);
25462306a36Sopenharmony_ci		return -EIO;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	lan_rmw(HSIO_SD_CFG_RX_PLL_EN_SET(1) |
25862306a36Sopenharmony_ci		HSIO_SD_CFG_TX_EN_SET(1),
25962306a36Sopenharmony_ci		HSIO_SD_CFG_RX_PLL_EN |
26062306a36Sopenharmony_ci		HSIO_SD_CFG_TX_EN,
26162306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_SD_CFG(idx));
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* Waiting for serdes 0 rx DPLL to lock...  */
26662306a36Sopenharmony_ci	value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
26762306a36Sopenharmony_ci	value = HSIO_SD_STAT_RX_PLL_STATE_GET(value);
26862306a36Sopenharmony_ci	if (value != 0x1) {
26962306a36Sopenharmony_ci		dev_err(macro->ctrl->dev,
27062306a36Sopenharmony_ci			"Unexpected sd_sd_stat[%u] rx_pll_state was 0x1 but is 0x%x\n",
27162306a36Sopenharmony_ci			idx, value);
27262306a36Sopenharmony_ci		return -EIO;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Waiting for serdes 0 tx operational...  */
27662306a36Sopenharmony_ci	value = readl(macro->ctrl->regs + lan_offset(HSIO_SD_STAT(idx)));
27762306a36Sopenharmony_ci	value = HSIO_SD_STAT_TX_STATE_GET(value);
27862306a36Sopenharmony_ci	if (value != 0x1) {
27962306a36Sopenharmony_ci		dev_err(macro->ctrl->dev,
28062306a36Sopenharmony_ci			"Unexpected sd_sd_stat[%u] tx_state was 0x1 but is 0x%x\n",
28162306a36Sopenharmony_ci			idx, value);
28262306a36Sopenharmony_ci		return -EIO;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	lan_rmw(HSIO_SD_CFG_TX_DATA_EN_SET(1) |
28662306a36Sopenharmony_ci		HSIO_SD_CFG_RX_DATA_EN_SET(1),
28762306a36Sopenharmony_ci		HSIO_SD_CFG_TX_DATA_EN |
28862306a36Sopenharmony_ci		HSIO_SD_CFG_RX_DATA_EN,
28962306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_SD_CFG(idx));
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int lan966x_sd6g40_get_conf_from_mode(struct serdes_macro *macro,
29562306a36Sopenharmony_ci					     enum lan966x_sd6g40_mode f_mode,
29662306a36Sopenharmony_ci					     bool ref125M,
29762306a36Sopenharmony_ci					     struct lan966x_sd6g40_mode_args *ret_val)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	switch (f_mode) {
30062306a36Sopenharmony_ci	case LAN966X_SD6G40_MODE_QSGMII:
30162306a36Sopenharmony_ci		ret_val->lane_10bit_sel = 0;
30262306a36Sopenharmony_ci		if (ref125M) {
30362306a36Sopenharmony_ci			ret_val->mpll_multiplier = 40;
30462306a36Sopenharmony_ci			ret_val->ref_clkdiv2 = 0x1;
30562306a36Sopenharmony_ci			ret_val->tx_rate = 0x0;
30662306a36Sopenharmony_ci			ret_val->rx_rate = 0x0;
30762306a36Sopenharmony_ci		} else {
30862306a36Sopenharmony_ci			ret_val->mpll_multiplier = 100;
30962306a36Sopenharmony_ci			ret_val->ref_clkdiv2 = 0x0;
31062306a36Sopenharmony_ci			ret_val->tx_rate = 0x0;
31162306a36Sopenharmony_ci			ret_val->rx_rate = 0x0;
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	case LAN966X_SD6G40_MODE_SGMII:
31662306a36Sopenharmony_ci		ret_val->lane_10bit_sel = 1;
31762306a36Sopenharmony_ci		if (ref125M) {
31862306a36Sopenharmony_ci			ret_val->mpll_multiplier = macro->speed == SPEED_2500 ? 50 : 40;
31962306a36Sopenharmony_ci			ret_val->ref_clkdiv2 = 0x1;
32062306a36Sopenharmony_ci			ret_val->tx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
32162306a36Sopenharmony_ci			ret_val->rx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
32262306a36Sopenharmony_ci		} else {
32362306a36Sopenharmony_ci			ret_val->mpll_multiplier = macro->speed == SPEED_2500 ? 125 : 100;
32462306a36Sopenharmony_ci			ret_val->ref_clkdiv2 = 0x0;
32562306a36Sopenharmony_ci			ret_val->tx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
32662306a36Sopenharmony_ci			ret_val->rx_rate = macro->speed == SPEED_2500 ? 0x1 : 0x2;
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci		break;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	default:
33162306a36Sopenharmony_ci		return -EOPNOTSUPP;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	return 0;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic int lan966x_calc_sd6g40_setup_lane(struct serdes_macro *macro,
33862306a36Sopenharmony_ci					  struct lan966x_sd6g40_setup_args config,
33962306a36Sopenharmony_ci					  struct lan966x_sd6g40_setup *ret_val)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct lan966x_sd6g40_mode_args sd6g40_mode;
34262306a36Sopenharmony_ci	struct lan966x_sd6g40_mode_args *mode_args = &sd6g40_mode;
34362306a36Sopenharmony_ci	int ret;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	ret = lan966x_sd6g40_get_conf_from_mode(macro, config.mode,
34662306a36Sopenharmony_ci						config.refclk125M, mode_args);
34762306a36Sopenharmony_ci	if (ret)
34862306a36Sopenharmony_ci		return ret;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ret_val->lane_10bit_sel = mode_args->lane_10bit_sel;
35162306a36Sopenharmony_ci	ret_val->rx_rate = mode_args->rx_rate;
35262306a36Sopenharmony_ci	ret_val->tx_rate = mode_args->tx_rate;
35362306a36Sopenharmony_ci	ret_val->mpll_multiplier = mode_args->mpll_multiplier;
35462306a36Sopenharmony_ci	ret_val->ref_clkdiv2 = mode_args->ref_clkdiv2;
35562306a36Sopenharmony_ci	ret_val->rx_term_en = 0;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (config.tx2rx_loop == LAN966X_SD6G40_LTX2RX)
35862306a36Sopenharmony_ci		ret_val->lane_loopbk_en = 1;
35962306a36Sopenharmony_ci	else
36062306a36Sopenharmony_ci		ret_val->lane_loopbk_en = 0;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	ret_val->tx_invert = !!config.txinvert;
36362306a36Sopenharmony_ci	ret_val->rx_invert = !!config.rxinvert;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int lan966x_sd6g40_setup_lane(struct serdes_macro *macro,
36962306a36Sopenharmony_ci				     struct lan966x_sd6g40_setup_args config,
37062306a36Sopenharmony_ci				     u32 idx)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct lan966x_sd6g40_setup calc_results = {};
37362306a36Sopenharmony_ci	int ret;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	ret = lan966x_calc_sd6g40_setup_lane(macro, config, &calc_results);
37662306a36Sopenharmony_ci	if (ret)
37762306a36Sopenharmony_ci		return ret;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return lan966x_sd6g40_reg_cfg(macro, &calc_results, idx);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int lan966x_sd6g40_setup(struct serdes_macro *macro, u32 idx, int mode)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct lan966x_sd6g40_setup_args conf = {};
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	conf.refclk125M = macro->ctrl->ref125;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (mode == PHY_INTERFACE_MODE_QSGMII)
38962306a36Sopenharmony_ci		conf.mode = LAN966X_SD6G40_MODE_QSGMII;
39062306a36Sopenharmony_ci	else
39162306a36Sopenharmony_ci		conf.mode = LAN966X_SD6G40_MODE_SGMII;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return lan966x_sd6g40_setup_lane(macro, conf, idx);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int lan966x_rgmii_setup(struct serdes_macro *macro, u32 idx, int mode)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	bool tx_delay = false;
39962306a36Sopenharmony_ci	bool rx_delay = false;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* Configure RGMII */
40262306a36Sopenharmony_ci	lan_rmw(HSIO_RGMII_CFG_RGMII_RX_RST_SET(0) |
40362306a36Sopenharmony_ci		HSIO_RGMII_CFG_RGMII_TX_RST_SET(0) |
40462306a36Sopenharmony_ci		HSIO_RGMII_CFG_TX_CLK_CFG_SET(macro->speed == SPEED_1000 ? 1 :
40562306a36Sopenharmony_ci					      macro->speed == SPEED_100 ? 2 :
40662306a36Sopenharmony_ci					      macro->speed == SPEED_10 ? 3 : 0),
40762306a36Sopenharmony_ci		HSIO_RGMII_CFG_RGMII_RX_RST |
40862306a36Sopenharmony_ci		HSIO_RGMII_CFG_RGMII_TX_RST |
40962306a36Sopenharmony_ci		HSIO_RGMII_CFG_TX_CLK_CFG,
41062306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_RGMII_CFG(idx));
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (mode == PHY_INTERFACE_MODE_RGMII ||
41362306a36Sopenharmony_ci	    mode == PHY_INTERFACE_MODE_RGMII_TXID)
41462306a36Sopenharmony_ci		rx_delay = true;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (mode == PHY_INTERFACE_MODE_RGMII ||
41762306a36Sopenharmony_ci	    mode == PHY_INTERFACE_MODE_RGMII_RXID)
41862306a36Sopenharmony_ci		tx_delay = true;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Setup DLL configuration */
42162306a36Sopenharmony_ci	lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) |
42262306a36Sopenharmony_ci		HSIO_DLL_CFG_DLL_ENA_SET(rx_delay),
42362306a36Sopenharmony_ci		HSIO_DLL_CFG_DLL_RST |
42462306a36Sopenharmony_ci		HSIO_DLL_CFG_DLL_ENA,
42562306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x0 : 0x2));
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(rx_delay),
42862306a36Sopenharmony_ci		HSIO_DLL_CFG_DELAY_ENA,
42962306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x0 : 0x2));
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) |
43262306a36Sopenharmony_ci		HSIO_DLL_CFG_DLL_ENA_SET(tx_delay),
43362306a36Sopenharmony_ci		HSIO_DLL_CFG_DLL_RST |
43462306a36Sopenharmony_ci		HSIO_DLL_CFG_DLL_ENA,
43562306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x1 : 0x3));
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(tx_delay),
43862306a36Sopenharmony_ci		HSIO_DLL_CFG_DELAY_ENA,
43962306a36Sopenharmony_ci		macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x1 : 0x3));
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return 0;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int serdes_set_speed(struct phy *phy, int speed)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct serdes_macro *macro = phy_get_drvdata(phy);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (!phy_interface_mode_is_rgmii(macro->mode))
44962306a36Sopenharmony_ci		return 0;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	macro->speed = speed;
45262306a36Sopenharmony_ci	lan966x_rgmii_setup(macro, macro->idx - (SERDES6G_MAX + 1), macro->mode);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct serdes_macro *macro = phy_get_drvdata(phy);
46062306a36Sopenharmony_ci	unsigned int i;
46162306a36Sopenharmony_ci	int val;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* As of now only PHY_MODE_ETHERNET is supported */
46462306a36Sopenharmony_ci	if (mode != PHY_MODE_ETHERNET)
46562306a36Sopenharmony_ci		return -EOPNOTSUPP;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (submode == PHY_INTERFACE_MODE_2500BASEX)
46862306a36Sopenharmony_ci		macro->speed = SPEED_2500;
46962306a36Sopenharmony_ci	else
47062306a36Sopenharmony_ci		macro->speed = SPEED_1000;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (submode == PHY_INTERFACE_MODE_1000BASEX ||
47362306a36Sopenharmony_ci	    submode == PHY_INTERFACE_MODE_2500BASEX)
47462306a36Sopenharmony_ci		submode = PHY_INTERFACE_MODE_SGMII;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (submode == PHY_INTERFACE_MODE_QUSGMII)
47762306a36Sopenharmony_ci		submode = PHY_INTERFACE_MODE_QSGMII;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(lan966x_serdes_muxes); i++) {
48062306a36Sopenharmony_ci		if (macro->idx != lan966x_serdes_muxes[i].idx ||
48162306a36Sopenharmony_ci		    mode != lan966x_serdes_muxes[i].mode ||
48262306a36Sopenharmony_ci		    submode != lan966x_serdes_muxes[i].submode ||
48362306a36Sopenharmony_ci		    macro->port != lan966x_serdes_muxes[i].port)
48462306a36Sopenharmony_ci			continue;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		val = readl(macro->ctrl->regs + lan_offset(HSIO_HW_CFG));
48762306a36Sopenharmony_ci		val |= lan966x_serdes_muxes[i].mux;
48862306a36Sopenharmony_ci		lan_rmw(val, lan966x_serdes_muxes[i].mask,
48962306a36Sopenharmony_ci			macro->ctrl->regs, HSIO_HW_CFG);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		macro->mode = lan966x_serdes_muxes[i].submode;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		if (macro->idx < CU_MAX)
49462306a36Sopenharmony_ci			return 0;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci		if (macro->idx < SERDES6G_MAX)
49762306a36Sopenharmony_ci			return lan966x_sd6g40_setup(macro,
49862306a36Sopenharmony_ci						    macro->idx - (CU_MAX + 1),
49962306a36Sopenharmony_ci						    macro->mode);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		if (macro->idx < RGMII_MAX)
50262306a36Sopenharmony_ci			return lan966x_rgmii_setup(macro,
50362306a36Sopenharmony_ci						   macro->idx - (SERDES6G_MAX + 1),
50462306a36Sopenharmony_ci						   macro->mode);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		return -EOPNOTSUPP;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return -EINVAL;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic const struct phy_ops serdes_ops = {
51362306a36Sopenharmony_ci	.set_mode	= serdes_set_mode,
51462306a36Sopenharmony_ci	.set_speed	= serdes_set_speed,
51562306a36Sopenharmony_ci	.owner		= THIS_MODULE,
51662306a36Sopenharmony_ci};
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic struct phy *serdes_simple_xlate(struct device *dev,
51962306a36Sopenharmony_ci				       struct of_phandle_args *args)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct serdes_ctrl *ctrl = dev_get_drvdata(dev);
52262306a36Sopenharmony_ci	unsigned int port, idx, i;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (args->args_count != 2)
52562306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	port = args->args[0];
52862306a36Sopenharmony_ci	idx = args->args[1];
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	for (i = 0; i < SERDES_MAX; i++) {
53162306a36Sopenharmony_ci		struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		if (idx != macro->idx)
53462306a36Sopenharmony_ci			continue;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		macro->port = port;
53762306a36Sopenharmony_ci		return ctrl->phys[i];
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx, struct phy **phy)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	struct serdes_macro *macro;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	*phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops);
54862306a36Sopenharmony_ci	if (IS_ERR(*phy))
54962306a36Sopenharmony_ci		return PTR_ERR(*phy);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL);
55262306a36Sopenharmony_ci	if (!macro)
55362306a36Sopenharmony_ci		return -ENOMEM;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	macro->idx = idx;
55662306a36Sopenharmony_ci	macro->ctrl = ctrl;
55762306a36Sopenharmony_ci	macro->port = -1;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	phy_set_drvdata(*phy, macro);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	return 0;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic int serdes_probe(struct platform_device *pdev)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct phy_provider *provider;
56762306a36Sopenharmony_ci	struct serdes_ctrl *ctrl;
56862306a36Sopenharmony_ci	void __iomem *hw_stat;
56962306a36Sopenharmony_ci	unsigned int i;
57062306a36Sopenharmony_ci	u32 val;
57162306a36Sopenharmony_ci	int ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
57462306a36Sopenharmony_ci	if (!ctrl)
57562306a36Sopenharmony_ci		return -ENOMEM;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	ctrl->dev = &pdev->dev;
57862306a36Sopenharmony_ci	ctrl->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
57962306a36Sopenharmony_ci	if (IS_ERR(ctrl->regs))
58062306a36Sopenharmony_ci		return PTR_ERR(ctrl->regs);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	hw_stat = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
58362306a36Sopenharmony_ci	if (IS_ERR(hw_stat))
58462306a36Sopenharmony_ci		return PTR_ERR(hw_stat);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	for (i = 0; i < SERDES_MAX; i++) {
58762306a36Sopenharmony_ci		ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]);
58862306a36Sopenharmony_ci		if (ret)
58962306a36Sopenharmony_ci			return ret;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	val = readl(hw_stat);
59362306a36Sopenharmony_ci	val = FIELD_GET(PLL_CONF_MASK, val);
59462306a36Sopenharmony_ci	ctrl->ref125 = (val == PLL_CONF_125MHZ ||
59562306a36Sopenharmony_ci			val == PLL_CONF_SERDES_125MHZ);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	dev_set_drvdata(&pdev->dev, ctrl);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	provider = devm_of_phy_provider_register(ctrl->dev,
60062306a36Sopenharmony_ci						 serdes_simple_xlate);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(provider);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic const struct of_device_id serdes_ids[] = {
60662306a36Sopenharmony_ci	{ .compatible = "microchip,lan966x-serdes", },
60762306a36Sopenharmony_ci	{},
60862306a36Sopenharmony_ci};
60962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, serdes_ids);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic struct platform_driver mscc_lan966x_serdes = {
61262306a36Sopenharmony_ci	.probe		= serdes_probe,
61362306a36Sopenharmony_ci	.driver		= {
61462306a36Sopenharmony_ci		.name	= "microchip,lan966x-serdes",
61562306a36Sopenharmony_ci		.of_match_table = of_match_ptr(serdes_ids),
61662306a36Sopenharmony_ci	},
61762306a36Sopenharmony_ci};
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cimodule_platform_driver(mscc_lan966x_serdes);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ciMODULE_DESCRIPTION("Microchip lan966x switch serdes driver");
62262306a36Sopenharmony_ciMODULE_AUTHOR("Horatiu Vultur <horatiu.vultur@microchip.com>");
62362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
624