FreeBSD kernel CXGB device code
cxgb_mv88e1xxx.c
Go to the documentation of this file.
1/**************************************************************************
2SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
4Copyright (c) 2007, Chelsio Inc.
5All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12
13 2. Neither the name of the Chelsio Corporation nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27POSSIBILITY OF SUCH DAMAGE.
28
29***************************************************************************/
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <cxgb_include.h>
35
36/* Marvell PHY interrupt status bits. */
37#define MV_INTR_JABBER 0x0001
38#define MV_INTR_POLARITY_CHNG 0x0002
39#define MV_INTR_ENG_DETECT_CHNG 0x0010
40#define MV_INTR_DOWNSHIFT 0x0020
41#define MV_INTR_MDI_XOVER_CHNG 0x0040
42#define MV_INTR_FIFO_OVER_UNDER 0x0080
43#define MV_INTR_FALSE_CARRIER 0x0100
44#define MV_INTR_SYMBOL_ERROR 0x0200
45#define MV_INTR_LINK_CHNG 0x0400
46#define MV_INTR_AUTONEG_DONE 0x0800
47#define MV_INTR_PAGE_RECV 0x1000
48#define MV_INTR_DUPLEX_CHNG 0x2000
49#define MV_INTR_SPEED_CHNG 0x4000
50#define MV_INTR_AUTONEG_ERR 0x8000
51
52/* Marvell PHY specific registers. */
53#define MV88E1XXX_SPECIFIC_CNTRL 16
54#define MV88E1XXX_SPECIFIC_STATUS 17
55#define MV88E1XXX_INTR_ENABLE 18
56#define MV88E1XXX_INTR_STATUS 19
57#define MV88E1XXX_EXT_SPECIFIC_CNTRL 20
58#define MV88E1XXX_RECV_ERR 21
59#define MV88E1XXX_EXT_ADDR 22
60#define MV88E1XXX_GLOBAL_STATUS 23
61#define MV88E1XXX_LED_CNTRL 24
62#define MV88E1XXX_LED_OVERRIDE 25
63#define MV88E1XXX_EXT_SPECIFIC_CNTRL2 26
64#define MV88E1XXX_EXT_SPECIFIC_STATUS 27
65#define MV88E1XXX_VIRTUAL_CABLE_TESTER 28
66#define MV88E1XXX_EXTENDED_ADDR 29
67#define MV88E1XXX_EXTENDED_DATA 30
68
69/* PHY specific control register fields */
70#define S_PSCR_MDI_XOVER_MODE 5
71#define M_PSCR_MDI_XOVER_MODE 0x3
72#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
73
74/* Extended PHY specific control register fields */
75#define S_DOWNSHIFT_ENABLE 8
76#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
77
78#define S_DOWNSHIFT_CNT 9
79#define M_DOWNSHIFT_CNT 0x7
80#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
81
82/* PHY specific status register fields */
83#define S_PSSR_JABBER 0
84#define V_PSSR_JABBER (1 << S_PSSR_JABBER)
85
86#define S_PSSR_POLARITY 1
87#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
88
89#define S_PSSR_RX_PAUSE 2
90#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
91
92#define S_PSSR_TX_PAUSE 3
93#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
94
95#define S_PSSR_ENERGY_DETECT 4
96#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
97
98#define S_PSSR_DOWNSHIFT_STATUS 5
99#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
100
101#define S_PSSR_MDI 6
102#define V_PSSR_MDI (1 << S_PSSR_MDI)
103
104#define S_PSSR_CABLE_LEN 7
105#define M_PSSR_CABLE_LEN 0x7
106#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
107#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
108
109#define S_PSSR_LINK 10
110#define V_PSSR_LINK (1 << S_PSSR_LINK)
111
112#define S_PSSR_STATUS_RESOLVED 11
113#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
114
115#define S_PSSR_PAGE_RECEIVED 12
116#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
117
118#define S_PSSR_DUPLEX 13
119#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
120
121#define S_PSSR_SPEED 14
122#define M_PSSR_SPEED 0x3
123#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
124#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
125
126/* MV88E1XXX MDI crossover register values */
127#define CROSSOVER_MDI 0
128#define CROSSOVER_MDIX 1
129#define CROSSOVER_AUTO 3
130
131#define INTR_ENABLE_MASK (MV_INTR_SPEED_CHNG | MV_INTR_DUPLEX_CHNG | \
132 MV_INTR_AUTONEG_DONE | MV_INTR_LINK_CHNG | MV_INTR_FIFO_OVER_UNDER | \
133 MV_INTR_ENG_DETECT_CHNG)
134
135/*
136 * Reset the PHY. If 'wait' is set wait until the reset completes.
137 */
138static int mv88e1xxx_reset(struct cphy *cphy, int wait)
139{
140 return t3_phy_reset(cphy, 0, wait);
141}
142
143static int mv88e1xxx_intr_enable(struct cphy *cphy)
144{
146}
147
149{
151}
152
153static int mv88e1xxx_intr_clear(struct cphy *cphy)
154{
155 u32 val;
156
157 /* Clear PHY interrupts by reading the register. */
158 return mdio_read(cphy, 0, MV88E1XXX_INTR_STATUS, &val);
159}
160
161static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
162{
165 V_PSCR_MDI_XOVER_MODE(crossover));
166}
167
169{
171
172 /* restart autoneg for change to take effect */
173 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
175}
176
178{
179 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
181}
182
183static int mv88e1xxx_set_loopback(struct cphy *cphy, int mmd, int dir, int on)
184{
185 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_LOOPBACK,
186 on ? BMCR_LOOPBACK : 0);
187}
188
189static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_state,
190 int *speed, int *duplex, int *fc)
191{
192 u32 status;
193 int sp = -1, dplx = -1, pause = 0;
194
196 if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
197 if (status & V_PSSR_RX_PAUSE)
198 pause |= PAUSE_RX;
199 if (status & V_PSSR_TX_PAUSE)
200 pause |= PAUSE_TX;
201 dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
202 sp = G_PSSR_SPEED(status);
203 if (sp == 0)
204 sp = SPEED_10;
205 else if (sp == 1)
206 sp = SPEED_100;
207 else
208 sp = SPEED_1000;
209 }
210 if (link_state)
211 *link_state = status & V_PSSR_LINK ? PHY_LINK_UP :
213 if (speed)
214 *speed = sp;
215 if (duplex)
216 *duplex = dplx;
217 if (fc)
218 *fc = pause;
219 return 0;
220}
221
222static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
223{
224 int err = t3_set_phy_speed_duplex(phy, speed, duplex);
225
226 /* PHY needs reset for new settings to take effect */
227 if (!err)
228 err = mv88e1xxx_reset(phy, 0);
229 return err;
230}
231
232static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
233{
234 /*
235 * Set the downshift counter to 2 so we try to establish Gb link
236 * twice before downshifting.
237 */
240 downshift_enable ? V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2) : 0);
241}
242
243static int mv88e1xxx_power_down(struct cphy *cphy, int enable)
244{
245 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
246 enable ? BMCR_PDOWN : 0);
247}
248
250{
251 const u32 link_change_intrs = MV_INTR_LINK_CHNG |
254
255 u32 cause;
256 int cphy_cause = 0;
257
259 cause &= INTR_ENABLE_MASK;
260 if (cause & link_change_intrs)
261 cphy_cause |= cphy_cause_link_change;
262 if (cause & MV_INTR_FIFO_OVER_UNDER)
263 cphy_cause |= cphy_cause_fifo_error;
264 return cphy_cause;
265}
266
267#ifdef C99_NOT_SUPPORTED
268static struct cphy_ops mv88e1xxx_ops = {
281};
282#else
283static struct cphy_ops mv88e1xxx_ops = {
285 .intr_enable = mv88e1xxx_intr_enable,
286 .intr_disable = mv88e1xxx_intr_disable,
287 .intr_clear = mv88e1xxx_intr_clear,
288 .intr_handler = mv88e1xxx_intr_handler,
289 .autoneg_enable = mv88e1xxx_autoneg_enable,
290 .autoneg_restart = mv88e1xxx_autoneg_restart,
291 .advertise = t3_phy_advertise,
292 .set_loopback = mv88e1xxx_set_loopback,
293 .set_speed_duplex = mv88e1xxx_set_speed_duplex,
294 .get_link_status = mv88e1xxx_get_link_status,
295 .power_down = mv88e1xxx_power_down,
296};
297#endif
298
299int t3_mv88e1xxx_phy_prep(pinfo_t *pinfo, int phy_addr,
300 const struct mdio_ops *mdio_ops)
301{
302 struct cphy *phy = &pinfo->phy;
303 int err;
304
308 SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");
309
310 /* Configure copper PHY transmitter as class A to reduce EMI. */
311 err = mdio_write(phy, 0, MV88E1XXX_EXTENDED_ADDR, 0xb);
312 if (!err)
313 err = mdio_write(phy, 0, MV88E1XXX_EXTENDED_DATA, 0x8004);
314
315 if (!err)
316 err = mv88e1xxx_downshift_set(phy, 1); /* Enable downshift */
317 return err;
318}
struct cphy phy
Definition: cxgb_adapter.h:5
static int mdio_read(struct cphy *phy, int mmd, int reg, unsigned int *valp)
Definition: cxgb_common.h:592
@ PAUSE_TX
Definition: cxgb_common.h:55
@ PAUSE_RX
Definition: cxgb_common.h:54
int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, unsigned int set)
Definition: cxgb_t3_hw.c:372
int t3_phy_reset(struct cphy *phy, int mmd, int wait)
Definition: cxgb_t3_hw.c:396
@ PHY_LINK_DOWN
Definition: cxgb_common.h:548
@ PHY_LINK_UP
Definition: cxgb_common.h:549
@ cphy_cause_fifo_error
Definition: cxgb_common.h:531
@ cphy_cause_link_change
Definition: cxgb_common.h:530
int t3_phy_advertise(struct cphy *phy, unsigned int advert)
Definition: cxgb_t3_hw.c:425
static int mdio_write(struct cphy *phy, int mmd, int reg, unsigned int val)
Definition: cxgb_common.h:598
@ SUPPORTED_IRQ
Definition: cxgb_common.h:63
int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
Definition: cxgb_t3_hw.c:492
static void cphy_init(struct cphy *phy, adapter_t *adapter, pinfo_t *pinfo, int phy_addr, struct cphy_ops *phy_ops, const struct mdio_ops *mdio_ops, unsigned int caps, const char *desc)
Definition: cxgb_common.h:605
#define INTR_ENABLE_MASK
#define G_PSSR_SPEED(x)
#define M_PSCR_MDI_XOVER_MODE
static struct cphy_ops mv88e1xxx_ops
static int mv88e1xxx_intr_clear(struct cphy *cphy)
#define V_PSCR_MDI_XOVER_MODE(x)
static int mv88e1xxx_reset(struct cphy *cphy, int wait)
#define MV88E1XXX_EXTENDED_DATA
#define MV_INTR_LINK_CHNG
static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
#define MV_INTR_SPEED_CHNG
#define V_DOWNSHIFT_CNT(x)
#define MV_INTR_AUTONEG_DONE
static int mv88e1xxx_intr_handler(struct cphy *cphy)
__FBSDID("$FreeBSD$")
#define MV88E1XXX_INTR_ENABLE
#define V_DOWNSHIFT_ENABLE
#define V_PSSR_STATUS_RESOLVED
#define MV_INTR_DOWNSHIFT
#define MV88E1XXX_EXT_SPECIFIC_CNTRL
static int mv88e1xxx_intr_enable(struct cphy *cphy)
#define V_PSSR_TX_PAUSE
static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
#define MV88E1XXX_INTR_STATUS
static int mv88e1xxx_set_loopback(struct cphy *cphy, int mmd, int dir, int on)
static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
#define MV_INTR_DUPLEX_CHNG
#define MV88E1XXX_EXTENDED_ADDR
static int mv88e1xxx_power_down(struct cphy *cphy, int enable)
#define V_PSSR_DUPLEX
#define MV88E1XXX_SPECIFIC_CNTRL
#define MV88E1XXX_SPECIFIC_STATUS
#define CROSSOVER_AUTO
static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
static int mv88e1xxx_intr_disable(struct cphy *cphy)
static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
#define V_PSSR_LINK
int t3_mv88e1xxx_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops)
static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_state, int *speed, int *duplex, int *fc)
#define V_PSSR_RX_PAUSE
#define M_DOWNSHIFT_CNT
#define MV_INTR_FIFO_OVER_UNDER
#define SPEED_100
Definition: cxgb_osdep.h:264
#define SUPPORTED_MII
Definition: cxgb_osdep.h:233
#define SPEED_1000
Definition: cxgb_osdep.h:265
#define SUPPORTED_TP
Definition: cxgb_osdep.h:231
#define DUPLEX_FULL
Definition: cxgb_osdep.h:268
#define SUPPORTED_Autoneg
Definition: cxgb_osdep.h:230
#define SUPPORTED_1000baseT_Full
Definition: cxgb_osdep.h:229
#define DUPLEX_HALF
Definition: cxgb_osdep.h:267
#define BMCR_ANRESTART
Definition: cxgb_osdep.h:140
#define SPEED_10
Definition: cxgb_osdep.h:263
#define BMCR_ANENABLE
Definition: cxgb_osdep.h:137
#define BMCR_LOOPBACK
Definition: cxgb_osdep.h:135
#define SUPPORTED_10baseT_Full
Definition: cxgb_osdep.h:225
#define SUPPORTED_100baseT_Full
Definition: cxgb_osdep.h:227
#define BMCR_ISOLATE
Definition: cxgb_osdep.h:136
uint32_t u32
Definition: cxgb_osdep.h:202
int(* reset)(struct cphy *phy, int wait)
Definition: cxgb_common.h:555
pinfo_t * pinfo
Definition: cxgb_common.h:581
struct cphy phy
Definition: cxgb_adapter.h:97
struct adapter * adapter
Definition: cxgb_adapter.h:92