1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Marvell 88E6xxx SERDES manipulation, via SMI bus
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2008 Marvell Semiconductor
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/irqdomain.h>
12*4882a593Smuzhiyun #include <linux/mii.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "chip.h"
15*4882a593Smuzhiyun #include "global2.h"
16*4882a593Smuzhiyun #include "phy.h"
17*4882a593Smuzhiyun #include "port.h"
18*4882a593Smuzhiyun #include "serdes.h"
19*4882a593Smuzhiyun
mv88e6352_serdes_read(struct mv88e6xxx_chip * chip,int reg,u16 * val)20*4882a593Smuzhiyun static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
21*4882a593Smuzhiyun u16 *val)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
24*4882a593Smuzhiyun MV88E6352_SERDES_PAGE_FIBER,
25*4882a593Smuzhiyun reg, val);
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
mv88e6352_serdes_write(struct mv88e6xxx_chip * chip,int reg,u16 val)28*4882a593Smuzhiyun static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
29*4882a593Smuzhiyun u16 val)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
32*4882a593Smuzhiyun MV88E6352_SERDES_PAGE_FIBER,
33*4882a593Smuzhiyun reg, val);
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
mv88e6390_serdes_read(struct mv88e6xxx_chip * chip,int lane,int device,int reg,u16 * val)36*4882a593Smuzhiyun static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
37*4882a593Smuzhiyun int lane, int device, int reg, u16 *val)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun return mv88e6xxx_phy_read(chip, lane, reg_c45, val);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
mv88e6390_serdes_write(struct mv88e6xxx_chip * chip,int lane,int device,int reg,u16 val)44*4882a593Smuzhiyun static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
45*4882a593Smuzhiyun int lane, int device, int reg, u16 val)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip * chip,u16 status,u16 lpa,struct phylink_link_state * state)52*4882a593Smuzhiyun static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
53*4882a593Smuzhiyun u16 status, u16 lpa,
54*4882a593Smuzhiyun struct phylink_link_state *state)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
57*4882a593Smuzhiyun state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
58*4882a593Smuzhiyun state->duplex = status &
59*4882a593Smuzhiyun MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
60*4882a593Smuzhiyun DUPLEX_FULL : DUPLEX_HALF;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (status & MV88E6390_SGMII_PHY_STATUS_TX_PAUSE)
63*4882a593Smuzhiyun state->pause |= MLO_PAUSE_TX;
64*4882a593Smuzhiyun if (status & MV88E6390_SGMII_PHY_STATUS_RX_PAUSE)
65*4882a593Smuzhiyun state->pause |= MLO_PAUSE_RX;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
68*4882a593Smuzhiyun case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
69*4882a593Smuzhiyun if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
70*4882a593Smuzhiyun state->speed = SPEED_2500;
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun state->speed = SPEED_1000;
73*4882a593Smuzhiyun break;
74*4882a593Smuzhiyun case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
75*4882a593Smuzhiyun state->speed = SPEED_100;
76*4882a593Smuzhiyun break;
77*4882a593Smuzhiyun case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
78*4882a593Smuzhiyun state->speed = SPEED_10;
79*4882a593Smuzhiyun break;
80*4882a593Smuzhiyun default:
81*4882a593Smuzhiyun dev_err(chip->dev, "invalid PHY speed\n");
82*4882a593Smuzhiyun return -EINVAL;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun } else {
85*4882a593Smuzhiyun state->link = false;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
89*4882a593Smuzhiyun mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
90*4882a593Smuzhiyun ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
91*4882a593Smuzhiyun else if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
92*4882a593Smuzhiyun mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
93*4882a593Smuzhiyun ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
mv88e6352_serdes_power(struct mv88e6xxx_chip * chip,int port,u8 lane,bool up)98*4882a593Smuzhiyun int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
99*4882a593Smuzhiyun bool up)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun u16 val, new_val;
102*4882a593Smuzhiyun int err;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
105*4882a593Smuzhiyun if (err)
106*4882a593Smuzhiyun return err;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (up)
109*4882a593Smuzhiyun new_val = val & ~BMCR_PDOWN;
110*4882a593Smuzhiyun else
111*4882a593Smuzhiyun new_val = val | BMCR_PDOWN;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun if (val != new_val)
114*4882a593Smuzhiyun err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return err;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip * chip,int port,u8 lane,unsigned int mode,phy_interface_t interface,const unsigned long * advertise)119*4882a593Smuzhiyun int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
120*4882a593Smuzhiyun u8 lane, unsigned int mode,
121*4882a593Smuzhiyun phy_interface_t interface,
122*4882a593Smuzhiyun const unsigned long *advertise)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun u16 adv, bmcr, val;
125*4882a593Smuzhiyun bool changed;
126*4882a593Smuzhiyun int err;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun switch (interface) {
129*4882a593Smuzhiyun case PHY_INTERFACE_MODE_SGMII:
130*4882a593Smuzhiyun adv = 0x0001;
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun case PHY_INTERFACE_MODE_1000BASEX:
134*4882a593Smuzhiyun adv = linkmode_adv_to_mii_adv_x(advertise,
135*4882a593Smuzhiyun ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
136*4882a593Smuzhiyun break;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun default:
139*4882a593Smuzhiyun return 0;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MII_ADVERTISE, &val);
143*4882a593Smuzhiyun if (err)
144*4882a593Smuzhiyun return err;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun changed = val != adv;
147*4882a593Smuzhiyun if (changed) {
148*4882a593Smuzhiyun err = mv88e6352_serdes_write(chip, MII_ADVERTISE, adv);
149*4882a593Smuzhiyun if (err)
150*4882a593Smuzhiyun return err;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
154*4882a593Smuzhiyun if (err)
155*4882a593Smuzhiyun return err;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (phylink_autoneg_inband(mode))
158*4882a593Smuzhiyun bmcr = val | BMCR_ANENABLE;
159*4882a593Smuzhiyun else
160*4882a593Smuzhiyun bmcr = val & ~BMCR_ANENABLE;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (bmcr == val)
163*4882a593Smuzhiyun return changed;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip * chip,int port,u8 lane,struct phylink_link_state * state)168*4882a593Smuzhiyun int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
169*4882a593Smuzhiyun u8 lane, struct phylink_link_state *state)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun u16 lpa, status;
172*4882a593Smuzhiyun int err;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, 0x11, &status);
175*4882a593Smuzhiyun if (err) {
176*4882a593Smuzhiyun dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
177*4882a593Smuzhiyun return err;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MII_LPA, &lpa);
181*4882a593Smuzhiyun if (err) {
182*4882a593Smuzhiyun dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err);
183*4882a593Smuzhiyun return err;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip * chip,int port,u8 lane)189*4882a593Smuzhiyun int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
190*4882a593Smuzhiyun u8 lane)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun u16 bmcr;
193*4882a593Smuzhiyun int err;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MII_BMCR, &bmcr);
196*4882a593Smuzhiyun if (err)
197*4882a593Smuzhiyun return err;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun return mv88e6352_serdes_write(chip, MII_BMCR, bmcr | BMCR_ANRESTART);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip * chip,int port,u8 lane,int speed,int duplex)202*4882a593Smuzhiyun int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
203*4882a593Smuzhiyun u8 lane, int speed, int duplex)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun u16 val, bmcr;
206*4882a593Smuzhiyun int err;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
209*4882a593Smuzhiyun if (err)
210*4882a593Smuzhiyun return err;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000);
213*4882a593Smuzhiyun switch (speed) {
214*4882a593Smuzhiyun case SPEED_1000:
215*4882a593Smuzhiyun bmcr |= BMCR_SPEED1000;
216*4882a593Smuzhiyun break;
217*4882a593Smuzhiyun case SPEED_100:
218*4882a593Smuzhiyun bmcr |= BMCR_SPEED100;
219*4882a593Smuzhiyun break;
220*4882a593Smuzhiyun case SPEED_10:
221*4882a593Smuzhiyun break;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (duplex == DUPLEX_FULL)
225*4882a593Smuzhiyun bmcr |= BMCR_FULLDPLX;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun if (bmcr == val)
228*4882a593Smuzhiyun return 0;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
mv88e6352_serdes_get_lane(struct mv88e6xxx_chip * chip,int port)233*4882a593Smuzhiyun u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun u8 cmode = chip->ports[port].cmode;
236*4882a593Smuzhiyun u8 lane = 0;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
239*4882a593Smuzhiyun (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
240*4882a593Smuzhiyun (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
241*4882a593Smuzhiyun lane = 0xff; /* Unused */
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun return lane;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
mv88e6352_port_has_serdes(struct mv88e6xxx_chip * chip,int port)246*4882a593Smuzhiyun static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun if (mv88e6xxx_serdes_get_lane(chip, port))
249*4882a593Smuzhiyun return true;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return false;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun struct mv88e6352_serdes_hw_stat {
255*4882a593Smuzhiyun char string[ETH_GSTRING_LEN];
256*4882a593Smuzhiyun int sizeof_stat;
257*4882a593Smuzhiyun int reg;
258*4882a593Smuzhiyun };
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
261*4882a593Smuzhiyun { "serdes_fibre_rx_error", 16, 21 },
262*4882a593Smuzhiyun { "serdes_PRBS_error", 32, 24 },
263*4882a593Smuzhiyun };
264*4882a593Smuzhiyun
mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip * chip,int port)265*4882a593Smuzhiyun int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun if (mv88e6352_port_has_serdes(chip, port))
268*4882a593Smuzhiyun return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun return 0;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
mv88e6352_serdes_get_strings(struct mv88e6xxx_chip * chip,int port,uint8_t * data)273*4882a593Smuzhiyun int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
274*4882a593Smuzhiyun int port, uint8_t *data)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun struct mv88e6352_serdes_hw_stat *stat;
277*4882a593Smuzhiyun int i;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (!mv88e6352_port_has_serdes(chip, port))
280*4882a593Smuzhiyun return 0;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
283*4882a593Smuzhiyun stat = &mv88e6352_serdes_hw_stats[i];
284*4882a593Smuzhiyun memcpy(data + i * ETH_GSTRING_LEN, stat->string,
285*4882a593Smuzhiyun ETH_GSTRING_LEN);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
mv88e6352_serdes_get_stat(struct mv88e6xxx_chip * chip,struct mv88e6352_serdes_hw_stat * stat)290*4882a593Smuzhiyun static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
291*4882a593Smuzhiyun struct mv88e6352_serdes_hw_stat *stat)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun u64 val = 0;
294*4882a593Smuzhiyun u16 reg;
295*4882a593Smuzhiyun int err;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, stat->reg, ®);
298*4882a593Smuzhiyun if (err) {
299*4882a593Smuzhiyun dev_err(chip->dev, "failed to read statistic\n");
300*4882a593Smuzhiyun return 0;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun val = reg;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (stat->sizeof_stat == 32) {
306*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, stat->reg + 1, ®);
307*4882a593Smuzhiyun if (err) {
308*4882a593Smuzhiyun dev_err(chip->dev, "failed to read statistic\n");
309*4882a593Smuzhiyun return 0;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun val = val << 16 | reg;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun return val;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
mv88e6352_serdes_get_stats(struct mv88e6xxx_chip * chip,int port,uint64_t * data)317*4882a593Smuzhiyun int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
318*4882a593Smuzhiyun uint64_t *data)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
321*4882a593Smuzhiyun struct mv88e6352_serdes_hw_stat *stat;
322*4882a593Smuzhiyun u64 value;
323*4882a593Smuzhiyun int i;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (!mv88e6352_port_has_serdes(chip, port))
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
329*4882a593Smuzhiyun ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
332*4882a593Smuzhiyun stat = &mv88e6352_serdes_hw_stats[i];
333*4882a593Smuzhiyun value = mv88e6352_serdes_get_stat(chip, stat);
334*4882a593Smuzhiyun mv88e6xxx_port->serdes_stats[i] += value;
335*4882a593Smuzhiyun data[i] = mv88e6xxx_port->serdes_stats[i];
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
mv88e6352_serdes_irq_link(struct mv88e6xxx_chip * chip,int port)341*4882a593Smuzhiyun static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun u16 bmsr;
344*4882a593Smuzhiyun int err;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* If the link has dropped, we want to know about it. */
347*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MII_BMSR, &bmsr);
348*4882a593Smuzhiyun if (err) {
349*4882a593Smuzhiyun dev_err(chip->dev, "can't read Serdes BMSR: %d\n", err);
350*4882a593Smuzhiyun return;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun dsa_port_phylink_mac_change(chip->ds, port, !!(bmsr & BMSR_LSTATUS));
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
mv88e6352_serdes_irq_status(struct mv88e6xxx_chip * chip,int port,u8 lane)356*4882a593Smuzhiyun irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
357*4882a593Smuzhiyun u8 lane)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun irqreturn_t ret = IRQ_NONE;
360*4882a593Smuzhiyun u16 status;
361*4882a593Smuzhiyun int err;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
364*4882a593Smuzhiyun if (err)
365*4882a593Smuzhiyun return ret;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
368*4882a593Smuzhiyun ret = IRQ_HANDLED;
369*4882a593Smuzhiyun mv88e6352_serdes_irq_link(chip, port);
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return ret;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip * chip,int port,u8 lane,bool enable)375*4882a593Smuzhiyun int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
376*4882a593Smuzhiyun bool enable)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun u16 val = 0;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (enable)
381*4882a593Smuzhiyun val |= MV88E6352_SERDES_INT_LINK_CHANGE;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, val);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip * chip,int port)386*4882a593Smuzhiyun unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip * chip,int port)391*4882a593Smuzhiyun int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun if (!mv88e6352_port_has_serdes(chip, port))
394*4882a593Smuzhiyun return 0;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun return 32 * sizeof(u16);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
mv88e6352_serdes_get_regs(struct mv88e6xxx_chip * chip,int port,void * _p)399*4882a593Smuzhiyun void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun u16 *p = _p;
402*4882a593Smuzhiyun u16 reg;
403*4882a593Smuzhiyun int i;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun if (!mv88e6352_port_has_serdes(chip, port))
406*4882a593Smuzhiyun return;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun for (i = 0 ; i < 32; i++) {
409*4882a593Smuzhiyun mv88e6352_serdes_read(chip, i, ®);
410*4882a593Smuzhiyun p[i] = reg;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
mv88e6341_serdes_get_lane(struct mv88e6xxx_chip * chip,int port)414*4882a593Smuzhiyun u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun u8 cmode = chip->ports[port].cmode;
417*4882a593Smuzhiyun u8 lane = 0;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun switch (port) {
420*4882a593Smuzhiyun case 5:
421*4882a593Smuzhiyun if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
422*4882a593Smuzhiyun cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
423*4882a593Smuzhiyun cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
424*4882a593Smuzhiyun lane = MV88E6341_PORT5_LANE;
425*4882a593Smuzhiyun break;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun return lane;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
mv88e6390_serdes_get_lane(struct mv88e6xxx_chip * chip,int port)431*4882a593Smuzhiyun u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun u8 cmode = chip->ports[port].cmode;
434*4882a593Smuzhiyun u8 lane = 0;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun switch (port) {
437*4882a593Smuzhiyun case 9:
438*4882a593Smuzhiyun if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
439*4882a593Smuzhiyun cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
440*4882a593Smuzhiyun cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
441*4882a593Smuzhiyun lane = MV88E6390_PORT9_LANE0;
442*4882a593Smuzhiyun break;
443*4882a593Smuzhiyun case 10:
444*4882a593Smuzhiyun if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
445*4882a593Smuzhiyun cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
446*4882a593Smuzhiyun cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
447*4882a593Smuzhiyun lane = MV88E6390_PORT10_LANE0;
448*4882a593Smuzhiyun break;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun return lane;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip * chip,int port)454*4882a593Smuzhiyun u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun u8 cmode_port = chip->ports[port].cmode;
457*4882a593Smuzhiyun u8 cmode_port10 = chip->ports[10].cmode;
458*4882a593Smuzhiyun u8 cmode_port9 = chip->ports[9].cmode;
459*4882a593Smuzhiyun u8 lane = 0;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun switch (port) {
462*4882a593Smuzhiyun case 2:
463*4882a593Smuzhiyun if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
464*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
465*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
466*4882a593Smuzhiyun if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
467*4882a593Smuzhiyun lane = MV88E6390_PORT9_LANE1;
468*4882a593Smuzhiyun break;
469*4882a593Smuzhiyun case 3:
470*4882a593Smuzhiyun if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
471*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
472*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
473*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
474*4882a593Smuzhiyun if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
475*4882a593Smuzhiyun lane = MV88E6390_PORT9_LANE2;
476*4882a593Smuzhiyun break;
477*4882a593Smuzhiyun case 4:
478*4882a593Smuzhiyun if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
479*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
480*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
481*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
482*4882a593Smuzhiyun if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
483*4882a593Smuzhiyun lane = MV88E6390_PORT9_LANE3;
484*4882a593Smuzhiyun break;
485*4882a593Smuzhiyun case 5:
486*4882a593Smuzhiyun if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
487*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
488*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
489*4882a593Smuzhiyun if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
490*4882a593Smuzhiyun lane = MV88E6390_PORT10_LANE1;
491*4882a593Smuzhiyun break;
492*4882a593Smuzhiyun case 6:
493*4882a593Smuzhiyun if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
494*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
495*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
496*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
497*4882a593Smuzhiyun if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
498*4882a593Smuzhiyun lane = MV88E6390_PORT10_LANE2;
499*4882a593Smuzhiyun break;
500*4882a593Smuzhiyun case 7:
501*4882a593Smuzhiyun if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
502*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
503*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
504*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
505*4882a593Smuzhiyun if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
506*4882a593Smuzhiyun lane = MV88E6390_PORT10_LANE3;
507*4882a593Smuzhiyun break;
508*4882a593Smuzhiyun case 9:
509*4882a593Smuzhiyun if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
510*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
511*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
512*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
513*4882a593Smuzhiyun cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
514*4882a593Smuzhiyun lane = MV88E6390_PORT9_LANE0;
515*4882a593Smuzhiyun break;
516*4882a593Smuzhiyun case 10:
517*4882a593Smuzhiyun if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
518*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
519*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
520*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
521*4882a593Smuzhiyun cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
522*4882a593Smuzhiyun lane = MV88E6390_PORT10_LANE0;
523*4882a593Smuzhiyun break;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun return lane;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
mv88e6390_serdes_power_10g(struct mv88e6xxx_chip * chip,u8 lane,bool up)530*4882a593Smuzhiyun static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
531*4882a593Smuzhiyun bool up)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun u16 val, new_val;
534*4882a593Smuzhiyun int err;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
537*4882a593Smuzhiyun MV88E6390_10G_CTRL1, &val);
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun if (err)
540*4882a593Smuzhiyun return err;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun if (up)
543*4882a593Smuzhiyun new_val = val & ~(MDIO_CTRL1_RESET |
544*4882a593Smuzhiyun MDIO_PCS_CTRL1_LOOPBACK |
545*4882a593Smuzhiyun MDIO_CTRL1_LPOWER);
546*4882a593Smuzhiyun else
547*4882a593Smuzhiyun new_val = val | MDIO_CTRL1_LPOWER;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (val != new_val)
550*4882a593Smuzhiyun err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
551*4882a593Smuzhiyun MV88E6390_10G_CTRL1, new_val);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun return err;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /* Set power up/down for SGMII and 1000Base-X */
mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip * chip,u8 lane,bool up)557*4882a593Smuzhiyun static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
558*4882a593Smuzhiyun bool up)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun u16 val, new_val;
561*4882a593Smuzhiyun int err;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
564*4882a593Smuzhiyun MV88E6390_SGMII_BMCR, &val);
565*4882a593Smuzhiyun if (err)
566*4882a593Smuzhiyun return err;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (up)
569*4882a593Smuzhiyun new_val = val & ~(BMCR_RESET | BMCR_LOOPBACK | BMCR_PDOWN);
570*4882a593Smuzhiyun else
571*4882a593Smuzhiyun new_val = val | BMCR_PDOWN;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun if (val != new_val)
574*4882a593Smuzhiyun err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
575*4882a593Smuzhiyun MV88E6390_SGMII_BMCR, new_val);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun return err;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun struct mv88e6390_serdes_hw_stat {
581*4882a593Smuzhiyun char string[ETH_GSTRING_LEN];
582*4882a593Smuzhiyun int reg;
583*4882a593Smuzhiyun };
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = {
586*4882a593Smuzhiyun { "serdes_rx_pkts", 0xf021 },
587*4882a593Smuzhiyun { "serdes_rx_bytes", 0xf024 },
588*4882a593Smuzhiyun { "serdes_rx_pkts_error", 0xf027 },
589*4882a593Smuzhiyun };
590*4882a593Smuzhiyun
mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip * chip,int port)591*4882a593Smuzhiyun int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun if (mv88e6xxx_serdes_get_lane(chip, port) == 0)
594*4882a593Smuzhiyun return 0;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
mv88e6390_serdes_get_strings(struct mv88e6xxx_chip * chip,int port,uint8_t * data)599*4882a593Smuzhiyun int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
600*4882a593Smuzhiyun int port, uint8_t *data)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun struct mv88e6390_serdes_hw_stat *stat;
603*4882a593Smuzhiyun int i;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun if (mv88e6xxx_serdes_get_lane(chip, port) == 0)
606*4882a593Smuzhiyun return 0;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
609*4882a593Smuzhiyun stat = &mv88e6390_serdes_hw_stats[i];
610*4882a593Smuzhiyun memcpy(data + i * ETH_GSTRING_LEN, stat->string,
611*4882a593Smuzhiyun ETH_GSTRING_LEN);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
mv88e6390_serdes_get_stat(struct mv88e6xxx_chip * chip,int lane,struct mv88e6390_serdes_hw_stat * stat)616*4882a593Smuzhiyun static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane,
617*4882a593Smuzhiyun struct mv88e6390_serdes_hw_stat *stat)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun u16 reg[3];
620*4882a593Smuzhiyun int err, i;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
623*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
624*4882a593Smuzhiyun stat->reg + i, ®[i]);
625*4882a593Smuzhiyun if (err) {
626*4882a593Smuzhiyun dev_err(chip->dev, "failed to read statistic\n");
627*4882a593Smuzhiyun return 0;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32);
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
mv88e6390_serdes_get_stats(struct mv88e6xxx_chip * chip,int port,uint64_t * data)634*4882a593Smuzhiyun int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
635*4882a593Smuzhiyun uint64_t *data)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun struct mv88e6390_serdes_hw_stat *stat;
638*4882a593Smuzhiyun int lane;
639*4882a593Smuzhiyun int i;
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun lane = mv88e6xxx_serdes_get_lane(chip, port);
642*4882a593Smuzhiyun if (lane == 0)
643*4882a593Smuzhiyun return 0;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
646*4882a593Smuzhiyun stat = &mv88e6390_serdes_hw_stats[i];
647*4882a593Smuzhiyun data[i] = mv88e6390_serdes_get_stat(chip, lane, stat);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip * chip,u8 lane)653*4882a593Smuzhiyun static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun u16 reg;
656*4882a593Smuzhiyun int err;
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
659*4882a593Smuzhiyun MV88E6390_PG_CONTROL, ®);
660*4882a593Smuzhiyun if (err)
661*4882a593Smuzhiyun return err;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun reg |= MV88E6390_PG_CONTROL_ENABLE_PC;
664*4882a593Smuzhiyun return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
665*4882a593Smuzhiyun MV88E6390_PG_CONTROL, reg);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
mv88e6390_serdes_power(struct mv88e6xxx_chip * chip,int port,u8 lane,bool up)668*4882a593Smuzhiyun int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
669*4882a593Smuzhiyun bool up)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun u8 cmode = chip->ports[port].cmode;
672*4882a593Smuzhiyun int err = 0;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun switch (cmode) {
675*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_SGMII:
676*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
677*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
678*4882a593Smuzhiyun err = mv88e6390_serdes_power_sgmii(chip, lane, up);
679*4882a593Smuzhiyun break;
680*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_XAUI:
681*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_RXAUI:
682*4882a593Smuzhiyun err = mv88e6390_serdes_power_10g(chip, lane, up);
683*4882a593Smuzhiyun break;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun if (!err && up)
687*4882a593Smuzhiyun err = mv88e6390_serdes_enable_checker(chip, lane);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun return err;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip * chip,int port,u8 lane,unsigned int mode,phy_interface_t interface,const unsigned long * advertise)692*4882a593Smuzhiyun int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
693*4882a593Smuzhiyun u8 lane, unsigned int mode,
694*4882a593Smuzhiyun phy_interface_t interface,
695*4882a593Smuzhiyun const unsigned long *advertise)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun u16 val, bmcr, adv;
698*4882a593Smuzhiyun bool changed;
699*4882a593Smuzhiyun int err;
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun switch (interface) {
702*4882a593Smuzhiyun case PHY_INTERFACE_MODE_SGMII:
703*4882a593Smuzhiyun adv = 0x0001;
704*4882a593Smuzhiyun break;
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun case PHY_INTERFACE_MODE_1000BASEX:
707*4882a593Smuzhiyun adv = linkmode_adv_to_mii_adv_x(advertise,
708*4882a593Smuzhiyun ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
709*4882a593Smuzhiyun break;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun case PHY_INTERFACE_MODE_2500BASEX:
712*4882a593Smuzhiyun adv = linkmode_adv_to_mii_adv_x(advertise,
713*4882a593Smuzhiyun ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
714*4882a593Smuzhiyun break;
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun default:
717*4882a593Smuzhiyun return 0;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
721*4882a593Smuzhiyun MV88E6390_SGMII_ADVERTISE, &val);
722*4882a593Smuzhiyun if (err)
723*4882a593Smuzhiyun return err;
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun changed = val != adv;
726*4882a593Smuzhiyun if (changed) {
727*4882a593Smuzhiyun err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
728*4882a593Smuzhiyun MV88E6390_SGMII_ADVERTISE, adv);
729*4882a593Smuzhiyun if (err)
730*4882a593Smuzhiyun return err;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
734*4882a593Smuzhiyun MV88E6390_SGMII_BMCR, &val);
735*4882a593Smuzhiyun if (err)
736*4882a593Smuzhiyun return err;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun if (phylink_autoneg_inband(mode))
739*4882a593Smuzhiyun bmcr = val | BMCR_ANENABLE;
740*4882a593Smuzhiyun else
741*4882a593Smuzhiyun bmcr = val & ~BMCR_ANENABLE;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun /* setting ANENABLE triggers a restart of negotiation */
744*4882a593Smuzhiyun if (bmcr == val)
745*4882a593Smuzhiyun return changed;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
748*4882a593Smuzhiyun MV88E6390_SGMII_BMCR, bmcr);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip * chip,int port,u8 lane,struct phylink_link_state * state)751*4882a593Smuzhiyun static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
752*4882a593Smuzhiyun int port, u8 lane, struct phylink_link_state *state)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun u16 lpa, status;
755*4882a593Smuzhiyun int err;
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
758*4882a593Smuzhiyun MV88E6390_SGMII_PHY_STATUS, &status);
759*4882a593Smuzhiyun if (err) {
760*4882a593Smuzhiyun dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
761*4882a593Smuzhiyun return err;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
765*4882a593Smuzhiyun MV88E6390_SGMII_LPA, &lpa);
766*4882a593Smuzhiyun if (err) {
767*4882a593Smuzhiyun dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err);
768*4882a593Smuzhiyun return err;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun
mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip * chip,int port,u8 lane,struct phylink_link_state * state)774*4882a593Smuzhiyun static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
775*4882a593Smuzhiyun int port, u8 lane, struct phylink_link_state *state)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun u16 status;
778*4882a593Smuzhiyun int err;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
781*4882a593Smuzhiyun MV88E6390_10G_STAT1, &status);
782*4882a593Smuzhiyun if (err)
783*4882a593Smuzhiyun return err;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun state->link = !!(status & MDIO_STAT1_LSTATUS);
786*4882a593Smuzhiyun if (state->link) {
787*4882a593Smuzhiyun state->speed = SPEED_10000;
788*4882a593Smuzhiyun state->duplex = DUPLEX_FULL;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun return 0;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip * chip,int port,u8 lane,struct phylink_link_state * state)794*4882a593Smuzhiyun int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
795*4882a593Smuzhiyun u8 lane, struct phylink_link_state *state)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun switch (state->interface) {
798*4882a593Smuzhiyun case PHY_INTERFACE_MODE_SGMII:
799*4882a593Smuzhiyun case PHY_INTERFACE_MODE_1000BASEX:
800*4882a593Smuzhiyun case PHY_INTERFACE_MODE_2500BASEX:
801*4882a593Smuzhiyun return mv88e6390_serdes_pcs_get_state_sgmii(chip, port, lane,
802*4882a593Smuzhiyun state);
803*4882a593Smuzhiyun case PHY_INTERFACE_MODE_XAUI:
804*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RXAUI:
805*4882a593Smuzhiyun return mv88e6390_serdes_pcs_get_state_10g(chip, port, lane,
806*4882a593Smuzhiyun state);
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun default:
809*4882a593Smuzhiyun return -EOPNOTSUPP;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun
mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip * chip,int port,u8 lane)813*4882a593Smuzhiyun int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
814*4882a593Smuzhiyun u8 lane)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun u16 bmcr;
817*4882a593Smuzhiyun int err;
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
820*4882a593Smuzhiyun MV88E6390_SGMII_BMCR, &bmcr);
821*4882a593Smuzhiyun if (err)
822*4882a593Smuzhiyun return err;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
825*4882a593Smuzhiyun MV88E6390_SGMII_BMCR,
826*4882a593Smuzhiyun bmcr | BMCR_ANRESTART);
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip * chip,int port,u8 lane,int speed,int duplex)829*4882a593Smuzhiyun int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
830*4882a593Smuzhiyun u8 lane, int speed, int duplex)
831*4882a593Smuzhiyun {
832*4882a593Smuzhiyun u16 val, bmcr;
833*4882a593Smuzhiyun int err;
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
836*4882a593Smuzhiyun MV88E6390_SGMII_BMCR, &val);
837*4882a593Smuzhiyun if (err)
838*4882a593Smuzhiyun return err;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000);
841*4882a593Smuzhiyun switch (speed) {
842*4882a593Smuzhiyun case SPEED_2500:
843*4882a593Smuzhiyun case SPEED_1000:
844*4882a593Smuzhiyun bmcr |= BMCR_SPEED1000;
845*4882a593Smuzhiyun break;
846*4882a593Smuzhiyun case SPEED_100:
847*4882a593Smuzhiyun bmcr |= BMCR_SPEED100;
848*4882a593Smuzhiyun break;
849*4882a593Smuzhiyun case SPEED_10:
850*4882a593Smuzhiyun break;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun if (duplex == DUPLEX_FULL)
854*4882a593Smuzhiyun bmcr |= BMCR_FULLDPLX;
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun if (bmcr == val)
857*4882a593Smuzhiyun return 0;
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
860*4882a593Smuzhiyun MV88E6390_SGMII_BMCR, bmcr);
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun
mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip * chip,int port,u8 lane)863*4882a593Smuzhiyun static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
864*4882a593Smuzhiyun int port, u8 lane)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun u16 bmsr;
867*4882a593Smuzhiyun int err;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun /* If the link has dropped, we want to know about it. */
870*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
871*4882a593Smuzhiyun MV88E6390_SGMII_BMSR, &bmsr);
872*4882a593Smuzhiyun if (err) {
873*4882a593Smuzhiyun dev_err(chip->dev, "can't read Serdes BMSR: %d\n", err);
874*4882a593Smuzhiyun return;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun dsa_port_phylink_mac_change(chip->ds, port, !!(bmsr & BMSR_LSTATUS));
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip * chip,u8 lane,bool enable)880*4882a593Smuzhiyun static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
881*4882a593Smuzhiyun u8 lane, bool enable)
882*4882a593Smuzhiyun {
883*4882a593Smuzhiyun u16 val = 0;
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun if (enable)
886*4882a593Smuzhiyun val |= MV88E6390_SGMII_INT_LINK_DOWN |
887*4882a593Smuzhiyun MV88E6390_SGMII_INT_LINK_UP;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
890*4882a593Smuzhiyun MV88E6390_SGMII_INT_ENABLE, val);
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun
mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip * chip,int port,u8 lane,bool enable)893*4882a593Smuzhiyun int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
894*4882a593Smuzhiyun bool enable)
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun u8 cmode = chip->ports[port].cmode;
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun switch (cmode) {
899*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_SGMII:
900*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
901*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
902*4882a593Smuzhiyun return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun return 0;
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun
mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip * chip,u8 lane,u16 * status)908*4882a593Smuzhiyun static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
909*4882a593Smuzhiyun u8 lane, u16 *status)
910*4882a593Smuzhiyun {
911*4882a593Smuzhiyun int err;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
914*4882a593Smuzhiyun MV88E6390_SGMII_INT_STATUS, status);
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun return err;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
mv88e6390_serdes_irq_status(struct mv88e6xxx_chip * chip,int port,u8 lane)919*4882a593Smuzhiyun irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
920*4882a593Smuzhiyun u8 lane)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun u8 cmode = chip->ports[port].cmode;
923*4882a593Smuzhiyun irqreturn_t ret = IRQ_NONE;
924*4882a593Smuzhiyun u16 status;
925*4882a593Smuzhiyun int err;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun switch (cmode) {
928*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_SGMII:
929*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
930*4882a593Smuzhiyun case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
931*4882a593Smuzhiyun err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
932*4882a593Smuzhiyun if (err)
933*4882a593Smuzhiyun return ret;
934*4882a593Smuzhiyun if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
935*4882a593Smuzhiyun MV88E6390_SGMII_INT_LINK_UP)) {
936*4882a593Smuzhiyun ret = IRQ_HANDLED;
937*4882a593Smuzhiyun mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun return ret;
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun
mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip * chip,int port)944*4882a593Smuzhiyun unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
945*4882a593Smuzhiyun {
946*4882a593Smuzhiyun return irq_find_mapping(chip->g2_irq.domain, port);
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun static const u16 mv88e6390_serdes_regs[] = {
950*4882a593Smuzhiyun /* SERDES common registers */
951*4882a593Smuzhiyun 0xf00a, 0xf00b, 0xf00c,
952*4882a593Smuzhiyun 0xf010, 0xf011, 0xf012, 0xf013,
953*4882a593Smuzhiyun 0xf016, 0xf017, 0xf018,
954*4882a593Smuzhiyun 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
955*4882a593Smuzhiyun 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
956*4882a593Smuzhiyun 0xf028, 0xf029,
957*4882a593Smuzhiyun 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
958*4882a593Smuzhiyun 0xf038, 0xf039,
959*4882a593Smuzhiyun /* SGMII */
960*4882a593Smuzhiyun 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
961*4882a593Smuzhiyun 0x2008,
962*4882a593Smuzhiyun 0x200f,
963*4882a593Smuzhiyun 0xa000, 0xa001, 0xa002, 0xa003,
964*4882a593Smuzhiyun /* 10Gbase-X */
965*4882a593Smuzhiyun 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
966*4882a593Smuzhiyun 0x1008,
967*4882a593Smuzhiyun 0x100e, 0x100f,
968*4882a593Smuzhiyun 0x1018, 0x1019,
969*4882a593Smuzhiyun 0x9000, 0x9001, 0x9002, 0x9003, 0x9004,
970*4882a593Smuzhiyun 0x9006,
971*4882a593Smuzhiyun 0x9010, 0x9011, 0x9012, 0x9013, 0x9014, 0x9015, 0x9016,
972*4882a593Smuzhiyun /* 10Gbase-R */
973*4882a593Smuzhiyun 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
974*4882a593Smuzhiyun 0x1028, 0x1029, 0x102a, 0x102b,
975*4882a593Smuzhiyun };
976*4882a593Smuzhiyun
mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip * chip,int port)977*4882a593Smuzhiyun int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
978*4882a593Smuzhiyun {
979*4882a593Smuzhiyun if (mv88e6xxx_serdes_get_lane(chip, port) == 0)
980*4882a593Smuzhiyun return 0;
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun
mv88e6390_serdes_get_regs(struct mv88e6xxx_chip * chip,int port,void * _p)985*4882a593Smuzhiyun void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun u16 *p = _p;
988*4882a593Smuzhiyun int lane;
989*4882a593Smuzhiyun u16 reg;
990*4882a593Smuzhiyun int i;
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun lane = mv88e6xxx_serdes_get_lane(chip, port);
993*4882a593Smuzhiyun if (lane == 0)
994*4882a593Smuzhiyun return;
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
997*4882a593Smuzhiyun mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
998*4882a593Smuzhiyun mv88e6390_serdes_regs[i], ®);
999*4882a593Smuzhiyun p[i] = reg;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun }
1002