1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2022 Bootlin
4  *
5  * Maxime Chevallier <maxime.chevallier@bootlin.com>
6  */
7 
8 #include <linux/netdevice.h>
9 #include <linux/phy.h>
10 #include <linux/phylink.h>
11 #include <linux/pcs-altera-tse.h>
12 
13 /* SGMII PCS register addresses
14  */
15 #define SGMII_PCS_SCRATCH	0x10
16 #define SGMII_PCS_REV		0x11
17 #define SGMII_PCS_LINK_TIMER_0	0x12
18 #define   SGMII_PCS_LINK_TIMER_REG(x)		(0x12 + (x))
19 #define SGMII_PCS_LINK_TIMER_1	0x13
20 #define SGMII_PCS_IF_MODE	0x14
21 #define   PCS_IF_MODE_SGMII_ENA		BIT(0)
22 #define   PCS_IF_MODE_USE_SGMII_AN	BIT(1)
23 #define   PCS_IF_MODE_SGMI_SPEED_MASK	GENMASK(3, 2)
24 #define   PCS_IF_MODE_SGMI_SPEED_10	(0 << 2)
25 #define   PCS_IF_MODE_SGMI_SPEED_100	(1 << 2)
26 #define   PCS_IF_MODE_SGMI_SPEED_1000	(2 << 2)
27 #define   PCS_IF_MODE_SGMI_HALF_DUPLEX	BIT(4)
28 #define   PCS_IF_MODE_SGMI_PHY_AN	BIT(5)
29 #define SGMII_PCS_DIS_READ_TO	0x15
30 #define SGMII_PCS_READ_TO	0x16
31 #define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */
32 
33 struct altera_tse_pcs {
34 	struct phylink_pcs pcs;
35 	void __iomem *base;
36 	int reg_width;
37 };
38 
phylink_pcs_to_tse_pcs(struct phylink_pcs * pcs)39 static struct altera_tse_pcs *phylink_pcs_to_tse_pcs(struct phylink_pcs *pcs)
40 {
41 	return container_of(pcs, struct altera_tse_pcs, pcs);
42 }
43 
tse_pcs_read(struct altera_tse_pcs * tse_pcs,int regnum)44 static u16 tse_pcs_read(struct altera_tse_pcs *tse_pcs, int regnum)
45 {
46 	if (tse_pcs->reg_width == 4)
47 		return readl(tse_pcs->base + regnum * 4);
48 	else
49 		return readw(tse_pcs->base + regnum * 2);
50 }
51 
tse_pcs_write(struct altera_tse_pcs * tse_pcs,int regnum,u16 value)52 static void tse_pcs_write(struct altera_tse_pcs *tse_pcs, int regnum,
53 			  u16 value)
54 {
55 	if (tse_pcs->reg_width == 4)
56 		writel(value, tse_pcs->base + regnum * 4);
57 	else
58 		writew(value, tse_pcs->base + regnum * 2);
59 }
60 
tse_pcs_reset(struct altera_tse_pcs * tse_pcs)61 static int tse_pcs_reset(struct altera_tse_pcs *tse_pcs)
62 {
63 	int i = 0;
64 	u16 bmcr;
65 
66 	/* Reset PCS block */
67 	bmcr = tse_pcs_read(tse_pcs, MII_BMCR);
68 	bmcr |= BMCR_RESET;
69 	tse_pcs_write(tse_pcs, MII_BMCR, bmcr);
70 
71 	for (i = 0; i < SGMII_PCS_SW_RESET_TIMEOUT; i++) {
72 		if (!(tse_pcs_read(tse_pcs, MII_BMCR) & BMCR_RESET))
73 			return 0;
74 		udelay(1);
75 	}
76 
77 	return -ETIMEDOUT;
78 }
79 
alt_tse_pcs_validate(struct phylink_pcs * pcs,unsigned long * supported,const struct phylink_link_state * state)80 static int alt_tse_pcs_validate(struct phylink_pcs *pcs,
81 				unsigned long *supported,
82 				const struct phylink_link_state *state)
83 {
84 	if (state->interface == PHY_INTERFACE_MODE_SGMII ||
85 	    state->interface == PHY_INTERFACE_MODE_1000BASEX)
86 		return 1;
87 
88 	return -EINVAL;
89 }
90 
alt_tse_pcs_config(struct phylink_pcs * pcs,unsigned int mode,phy_interface_t interface,const unsigned long * advertising,bool permit_pause_to_mac)91 static int alt_tse_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
92 			      phy_interface_t interface,
93 			      const unsigned long *advertising,
94 			      bool permit_pause_to_mac)
95 {
96 	struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
97 	u32 ctrl, if_mode;
98 
99 	ctrl = tse_pcs_read(tse_pcs, MII_BMCR);
100 	if_mode = tse_pcs_read(tse_pcs, SGMII_PCS_IF_MODE);
101 
102 	/* Set link timer to 1.6ms, as per the MegaCore Function User Guide */
103 	tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_0, 0x0D40);
104 	tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_1, 0x03);
105 
106 	if (interface == PHY_INTERFACE_MODE_SGMII) {
107 		if_mode |= PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA;
108 	} else if (interface == PHY_INTERFACE_MODE_1000BASEX) {
109 		if_mode &= ~(PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA);
110 		if_mode |= PCS_IF_MODE_SGMI_SPEED_1000;
111 	}
112 
113 	ctrl |= (BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE);
114 
115 	tse_pcs_write(tse_pcs, MII_BMCR, ctrl);
116 	tse_pcs_write(tse_pcs, SGMII_PCS_IF_MODE, if_mode);
117 
118 	return tse_pcs_reset(tse_pcs);
119 }
120 
alt_tse_pcs_get_state(struct phylink_pcs * pcs,struct phylink_link_state * state)121 static void alt_tse_pcs_get_state(struct phylink_pcs *pcs,
122 				  struct phylink_link_state *state)
123 {
124 	struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
125 	u16 bmsr, lpa;
126 
127 	bmsr = tse_pcs_read(tse_pcs, MII_BMSR);
128 	lpa = tse_pcs_read(tse_pcs, MII_LPA);
129 
130 	phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
131 }
132 
alt_tse_pcs_an_restart(struct phylink_pcs * pcs)133 static void alt_tse_pcs_an_restart(struct phylink_pcs *pcs)
134 {
135 	struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
136 	u16 bmcr;
137 
138 	bmcr = tse_pcs_read(tse_pcs, MII_BMCR);
139 	bmcr |= BMCR_ANRESTART;
140 	tse_pcs_write(tse_pcs, MII_BMCR, bmcr);
141 
142 	/* This PCS seems to require a soft reset to re-sync the AN logic */
143 	tse_pcs_reset(tse_pcs);
144 }
145 
146 static const struct phylink_pcs_ops alt_tse_pcs_ops = {
147 	.pcs_validate = alt_tse_pcs_validate,
148 	.pcs_get_state = alt_tse_pcs_get_state,
149 	.pcs_config = alt_tse_pcs_config,
150 	.pcs_an_restart = alt_tse_pcs_an_restart,
151 };
152 
alt_tse_pcs_create(struct net_device * ndev,void __iomem * pcs_base,int reg_width)153 struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev,
154 				       void __iomem *pcs_base, int reg_width)
155 {
156 	struct altera_tse_pcs *tse_pcs;
157 
158 	if (reg_width != 4 && reg_width != 2)
159 		return ERR_PTR(-EINVAL);
160 
161 	tse_pcs = devm_kzalloc(&ndev->dev, sizeof(*tse_pcs), GFP_KERNEL);
162 	if (!tse_pcs)
163 		return ERR_PTR(-ENOMEM);
164 
165 	tse_pcs->pcs.ops = &alt_tse_pcs_ops;
166 	tse_pcs->base = pcs_base;
167 	tse_pcs->reg_width = reg_width;
168 
169 	return &tse_pcs->pcs;
170 }
171 EXPORT_SYMBOL_GPL(alt_tse_pcs_create);
172 
173 MODULE_LICENSE("GPL");
174 MODULE_DESCRIPTION("Altera TSE PCS driver");
175 MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");
176