GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / pcs / pcs-mtk-lynxi.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018-2019 MediaTek Inc.
3 /* A library for MediaTek SGMII circuit
4  *
5  * Author: Sean Wang <sean.wang@mediatek.com>
6  * Author: Alexander Couzens <lynxis@fe80.eu>
7  * Author: Daniel Golle <daniel@makrotopia.org>
8  *
9  */
10
11 #include <linux/mdio.h>
12 #include <linux/of.h>
13 #include <linux/pcs/pcs-mtk-lynxi.h>
14 #include <linux/phylink.h>
15 #include <linux/regmap.h>
16
17 /* SGMII subsystem config registers */
18 /* BMCR (low 16) BMSR (high 16) */
19 #define SGMSYS_PCS_CONTROL_1            0x0
20 #define SGMII_BMCR                      GENMASK(15, 0)
21 #define SGMII_BMSR                      GENMASK(31, 16)
22
23 #define SGMSYS_PCS_DEVICE_ID            0x4
24 #define SGMII_LYNXI_DEV_ID              0x4d544950
25
26 #define SGMSYS_PCS_ADVERTISE            0x8
27 #define SGMII_ADVERTISE                 GENMASK(15, 0)
28 #define SGMII_LPA                       GENMASK(31, 16)
29
30 #define SGMSYS_PCS_SCRATCH              0x14
31 #define SGMII_DEV_VERSION               GENMASK(31, 16)
32
33 /* Register to programmable link timer, the unit in 2 * 8ns */
34 #define SGMSYS_PCS_LINK_TIMER           0x18
35 #define SGMII_LINK_TIMER_MASK           GENMASK(19, 0)
36 #define SGMII_LINK_TIMER_VAL(ns)        FIELD_PREP(SGMII_LINK_TIMER_MASK, \
37                                                    ((ns) / 2 / 8))
38
39 /* Register to control remote fault */
40 #define SGMSYS_SGMII_MODE               0x20
41 #define SGMII_IF_MODE_SGMII             BIT(0)
42 #define SGMII_SPEED_DUPLEX_AN           BIT(1)
43 #define SGMII_SPEED_MASK                GENMASK(3, 2)
44 #define SGMII_SPEED_10                  FIELD_PREP(SGMII_SPEED_MASK, 0)
45 #define SGMII_SPEED_100                 FIELD_PREP(SGMII_SPEED_MASK, 1)
46 #define SGMII_SPEED_1000                FIELD_PREP(SGMII_SPEED_MASK, 2)
47 #define SGMII_DUPLEX_HALF               BIT(4)
48 #define SGMII_REMOTE_FAULT_DIS          BIT(8)
49
50 /* Register to reset SGMII design */
51 #define SGMSYS_RESERVED_0               0x34
52 #define SGMII_SW_RESET                  BIT(0)
53
54 /* Register to set SGMII speed, ANA RG_ Control Signals III */
55 #define SGMII_PHY_SPEED_MASK            GENMASK(3, 2)
56 #define SGMII_PHY_SPEED_1_25G           FIELD_PREP(SGMII_PHY_SPEED_MASK, 0)
57 #define SGMII_PHY_SPEED_3_125G          FIELD_PREP(SGMII_PHY_SPEED_MASK, 1)
58
59 /* Register to power up QPHY */
60 #define SGMSYS_QPHY_PWR_STATE_CTRL      0xe8
61 #define SGMII_PHYA_PWD                  BIT(4)
62
63 /* Register to QPHY wrapper control */
64 #define SGMSYS_QPHY_WRAP_CTRL           0xec
65 #define SGMII_PN_SWAP_MASK              GENMASK(1, 0)
66 #define SGMII_PN_SWAP_TX_RX             (BIT(0) | BIT(1))
67
68 /* struct mtk_pcs_lynxi -  This structure holds each sgmii regmap andassociated
69  *                         data
70  * @regmap:                The register map pointing at the range used to setup
71  *                         SGMII modes
72  * @dev:                   Pointer to device owning the PCS
73  * @ana_rgc3:              The offset of register ANA_RGC3 relative to regmap
74  * @interface:             Currently configured interface mode
75  * @pcs:                   Phylink PCS structure
76  * @flags:                 Flags indicating hardware properties
77  */
78 struct mtk_pcs_lynxi {
79         struct regmap           *regmap;
80         u32                     ana_rgc3;
81         phy_interface_t         interface;
82         struct                  phylink_pcs pcs;
83         u32                     flags;
84 };
85
86 static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
87 {
88         return container_of(pcs, struct mtk_pcs_lynxi, pcs);
89 }
90
91 static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
92                                     struct phylink_link_state *state)
93 {
94         struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
95         unsigned int bm, adv;
96
97         /* Read the BMSR and LPA */
98         regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
99         regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
100
101         phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm),
102                                          FIELD_GET(SGMII_LPA, adv));
103 }
104
105 static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
106                                 phy_interface_t interface,
107                                 const unsigned long *advertising,
108                                 bool permit_pause_to_mac)
109 {
110         struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
111         bool mode_changed = false, changed;
112         unsigned int rgc3, sgm_mode, bmcr;
113         int advertise, link_timer;
114
115         advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
116                                                              advertising);
117         if (advertise < 0)
118                 return advertise;
119
120         /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and
121          * we assume that fixes it's speed at bitrate = line rate (in
122          * other words, 1000Mbps or 2500Mbps).
123          */
124         if (interface == PHY_INTERFACE_MODE_SGMII)
125                 sgm_mode = SGMII_IF_MODE_SGMII;
126         else
127                 sgm_mode = 0;
128
129         if (neg_mode & PHYLINK_PCS_NEG_INBAND)
130                 sgm_mode |= SGMII_REMOTE_FAULT_DIS;
131
132         if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
133                 if (interface == PHY_INTERFACE_MODE_SGMII)
134                         sgm_mode |= SGMII_SPEED_DUPLEX_AN;
135                 bmcr = BMCR_ANENABLE;
136         } else {
137                 bmcr = 0;
138         }
139
140         if (mpcs->interface != interface) {
141                 link_timer = phylink_get_link_timer_ns(interface);
142                 if (link_timer < 0)
143                         return link_timer;
144
145                 /* PHYA power down */
146                 regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
147                                 SGMII_PHYA_PWD);
148
149                 /* Reset SGMII PCS state */
150                 regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
151                                 SGMII_SW_RESET);
152
153                 if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP)
154                         regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
155                                            SGMII_PN_SWAP_MASK,
156                                            SGMII_PN_SWAP_TX_RX);
157
158                 if (interface == PHY_INTERFACE_MODE_2500BASEX)
159                         rgc3 = SGMII_PHY_SPEED_3_125G;
160                 else
161                         rgc3 = SGMII_PHY_SPEED_1_25G;
162
163                 /* Configure the underlying interface speed */
164                 regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
165                                    SGMII_PHY_SPEED_MASK, rgc3);
166
167                 /* Setup the link timer */
168                 regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
169                              SGMII_LINK_TIMER_VAL(link_timer));
170
171                 mpcs->interface = interface;
172                 mode_changed = true;
173         }
174
175         /* Update the advertisement, noting whether it has changed */
176         regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
177                                  SGMII_ADVERTISE, advertise, &changed);
178
179         /* Update the sgmsys mode register */
180         regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
181                            SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN |
182                            SGMII_IF_MODE_SGMII, sgm_mode);
183
184         /* Update the BMCR */
185         regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
186                            BMCR_ANENABLE, bmcr);
187
188         /* Release PHYA power down state
189          * Only removing bit SGMII_PHYA_PWD isn't enough.
190          * There are cases when the SGMII_PHYA_PWD register contains 0x9 which
191          * prevents SGMII from working. The SGMII still shows link but no traffic
192          * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was
193          * taken from a good working state of the SGMII interface.
194          * Unknown how much the QPHY needs but it is racy without a sleep.
195          * Tested on mt7622 & mt7986.
196          */
197         usleep_range(50, 100);
198         regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
199
200         return changed || mode_changed;
201 }
202
203 static void mtk_pcs_lynxi_restart_an(struct phylink_pcs *pcs)
204 {
205         struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
206
207         regmap_set_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, BMCR_ANRESTART);
208 }
209
210 static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs,
211                                   unsigned int neg_mode,
212                                   phy_interface_t interface, int speed,
213                                   int duplex)
214 {
215         struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
216         unsigned int sgm_mode;
217
218         if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) {
219                 /* Force the speed and duplex setting */
220                 if (speed == SPEED_10)
221                         sgm_mode = SGMII_SPEED_10;
222                 else if (speed == SPEED_100)
223                         sgm_mode = SGMII_SPEED_100;
224                 else
225                         sgm_mode = SGMII_SPEED_1000;
226
227                 if (duplex != DUPLEX_FULL)
228                         sgm_mode |= SGMII_DUPLEX_HALF;
229
230                 regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
231                                    SGMII_DUPLEX_HALF | SGMII_SPEED_MASK,
232                                    sgm_mode);
233         }
234 }
235
236 static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs)
237 {
238         struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
239
240         mpcs->interface = PHY_INTERFACE_MODE_NA;
241 }
242
243 static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
244         .pcs_get_state = mtk_pcs_lynxi_get_state,
245         .pcs_config = mtk_pcs_lynxi_config,
246         .pcs_an_restart = mtk_pcs_lynxi_restart_an,
247         .pcs_link_up = mtk_pcs_lynxi_link_up,
248         .pcs_disable = mtk_pcs_lynxi_disable,
249 };
250
251 struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
252                                          struct regmap *regmap, u32 ana_rgc3,
253                                          u32 flags)
254 {
255         struct mtk_pcs_lynxi *mpcs;
256         u32 id, ver;
257         int ret;
258
259         ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id);
260         if (ret < 0)
261                 return NULL;
262
263         if (id != SGMII_LYNXI_DEV_ID) {
264                 dev_err(dev, "unknown PCS device id %08x\n", id);
265                 return NULL;
266         }
267
268         ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver);
269         if (ret < 0)
270                 return NULL;
271
272         ver = FIELD_GET(SGMII_DEV_VERSION, ver);
273         if (ver != 0x1) {
274                 dev_err(dev, "unknown PCS device version %04x\n", ver);
275                 return NULL;
276         }
277
278         dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id,
279                 ver);
280
281         mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
282         if (!mpcs)
283                 return NULL;
284
285         mpcs->ana_rgc3 = ana_rgc3;
286         mpcs->regmap = regmap;
287         mpcs->flags = flags;
288         mpcs->pcs.ops = &mtk_pcs_lynxi_ops;
289         mpcs->pcs.neg_mode = true;
290         mpcs->pcs.poll = true;
291         mpcs->interface = PHY_INTERFACE_MODE_NA;
292
293         return &mpcs->pcs;
294 }
295 EXPORT_SYMBOL(mtk_pcs_lynxi_create);
296
297 void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs)
298 {
299         if (!pcs)
300                 return;
301
302         kfree(pcs_to_mtk_pcs_lynxi(pcs));
303 }
304 EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
305
306 MODULE_LICENSE("GPL");