Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pci / cxgb_mv88e1xxx.c
blob42a2e2e3c015c85c5c50e4ce71858a1c9ae8e4a4
1 /**************************************************************************
3 Copyright (c) 2007, Chelsio Inc.
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 2. Neither the name of the Chelsio Corporation nor the names of its
13 contributors may be used to endorse or promote products derived from
14 this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 POSSIBILITY OF SUCH DAMAGE.
28 ***************************************************************************/
30 #include <sys/cdefs.h>
31 #ifdef __NetBSD__
32 __KERNEL_RCSID(0, "$NetBSD: cxgb_mv88e1xxx.c,v 1.2 2007/12/11 11:25:48 lukem Exp $");
33 #endif
34 #ifdef __FreeBSD__
35 __FBSDID("$FreeBSD: src/sys/dev/cxgb/common/cxgb_mv88e1xxx.c,v 1.2 2007/05/28 22:57:26 kmacy Exp $");
36 #endif
38 #ifdef CONFIG_DEFINED
39 #include <cxgb_include.h>
40 #else
41 #ifdef __FreeBSD__
42 #include <dev/cxgb/cxgb_include.h>
43 #endif
44 #ifdef __NetBSD__
45 #include <dev/pci/cxgb_include.h>
46 #endif
47 #endif
49 /* Marvell PHY interrupt status bits. */
50 #define MV_INTR_JABBER 0x0001
51 #define MV_INTR_POLARITY_CHNG 0x0002
52 #define MV_INTR_ENG_DETECT_CHNG 0x0010
53 #define MV_INTR_DOWNSHIFT 0x0020
54 #define MV_INTR_MDI_XOVER_CHNG 0x0040
55 #define MV_INTR_FIFO_OVER_UNDER 0x0080
56 #define MV_INTR_FALSE_CARRIER 0x0100
57 #define MV_INTR_SYMBOL_ERROR 0x0200
58 #define MV_INTR_LINK_CHNG 0x0400
59 #define MV_INTR_AUTONEG_DONE 0x0800
60 #define MV_INTR_PAGE_RECV 0x1000
61 #define MV_INTR_DUPLEX_CHNG 0x2000
62 #define MV_INTR_SPEED_CHNG 0x4000
63 #define MV_INTR_AUTONEG_ERR 0x8000
65 /* Marvell PHY specific registers. */
66 #define MV88E1XXX_SPECIFIC_CNTRL 16
67 #define MV88E1XXX_SPECIFIC_STATUS 17
68 #define MV88E1XXX_INTR_ENABLE 18
69 #define MV88E1XXX_INTR_STATUS 19
70 #define MV88E1XXX_EXT_SPECIFIC_CNTRL 20
71 #define MV88E1XXX_RECV_ERR 21
72 #define MV88E1XXX_EXT_ADDR 22
73 #define MV88E1XXX_GLOBAL_STATUS 23
74 #define MV88E1XXX_LED_CNTRL 24
75 #define MV88E1XXX_LED_OVERRIDE 25
76 #define MV88E1XXX_EXT_SPECIFIC_CNTRL2 26
77 #define MV88E1XXX_EXT_SPECIFIC_STATUS 27
78 #define MV88E1XXX_VIRTUAL_CABLE_TESTER 28
79 #define MV88E1XXX_EXTENDED_ADDR 29
80 #define MV88E1XXX_EXTENDED_DATA 30
82 /* PHY specific control register fields */
83 #define S_PSCR_MDI_XOVER_MODE 5
84 #define M_PSCR_MDI_XOVER_MODE 0x3
85 #define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
87 /* Extended PHY specific control register fields */
88 #define S_DOWNSHIFT_ENABLE 8
89 #define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
91 #define S_DOWNSHIFT_CNT 9
92 #define M_DOWNSHIFT_CNT 0x7
93 #define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
95 /* PHY specific status register fields */
96 #define S_PSSR_JABBER 0
97 #define V_PSSR_JABBER (1 << S_PSSR_JABBER)
99 #define S_PSSR_POLARITY 1
100 #define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
102 #define S_PSSR_RX_PAUSE 2
103 #define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
105 #define S_PSSR_TX_PAUSE 3
106 #define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
108 #define S_PSSR_ENERGY_DETECT 4
109 #define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
111 #define S_PSSR_DOWNSHIFT_STATUS 5
112 #define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
114 #define S_PSSR_MDI 6
115 #define V_PSSR_MDI (1 << S_PSSR_MDI)
117 #define S_PSSR_CABLE_LEN 7
118 #define M_PSSR_CABLE_LEN 0x7
119 #define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
120 #define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
122 #define S_PSSR_LINK 10
123 #define V_PSSR_LINK (1 << S_PSSR_LINK)
125 #define S_PSSR_STATUS_RESOLVED 11
126 #define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
128 #define S_PSSR_PAGE_RECEIVED 12
129 #define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
131 #define S_PSSR_DUPLEX 13
132 #define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
134 #define S_PSSR_SPEED 14
135 #define M_PSSR_SPEED 0x3
136 #define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
137 #define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
139 /* MV88E1XXX MDI crossover register values */
140 #define CROSSOVER_MDI 0
141 #define CROSSOVER_MDIX 1
142 #define CROSSOVER_AUTO 3
144 #define INTR_ENABLE_MASK (MV_INTR_SPEED_CHNG | MV_INTR_DUPLEX_CHNG | \
145 MV_INTR_AUTONEG_DONE | MV_INTR_LINK_CHNG | MV_INTR_FIFO_OVER_UNDER | \
146 MV_INTR_ENG_DETECT_CHNG)
149 * Reset the PHY. If 'wait' is set wait until the reset completes.
151 static int mv88e1xxx_reset(struct cphy *cphy, int wait)
153 return t3_phy_reset(cphy, 0, wait);
156 static int mv88e1xxx_intr_enable(struct cphy *cphy)
158 return mdio_write(cphy, 0, MV88E1XXX_INTR_ENABLE, INTR_ENABLE_MASK);
161 static int mv88e1xxx_intr_disable(struct cphy *cphy)
163 return mdio_write(cphy, 0, MV88E1XXX_INTR_ENABLE, 0);
166 static int mv88e1xxx_intr_clear(struct cphy *cphy)
168 u32 val;
170 /* Clear PHY interrupts by reading the register. */
171 return mdio_read(cphy, 0, MV88E1XXX_INTR_STATUS, &val);
174 static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
176 return t3_mdio_change_bits(cphy, 0, MV88E1XXX_SPECIFIC_CNTRL,
177 V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE),
178 V_PSCR_MDI_XOVER_MODE(crossover));
181 static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
183 mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
185 /* restart autoneg for change to take effect */
186 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
187 BMCR_ANENABLE | BMCR_ANRESTART);
190 static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
192 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
193 BMCR_ANRESTART);
196 static int mv88e1xxx_set_loopback(struct cphy *cphy, int mmd, int dir, int on)
198 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_LOOPBACK,
199 on ? BMCR_LOOPBACK : 0);
202 static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
203 int *speed, int *duplex, int *fc)
205 u32 status;
206 int sp = -1, dplx = -1, pause = 0;
208 mdio_read(cphy, 0, MV88E1XXX_SPECIFIC_STATUS, &status);
209 if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
210 if (status & V_PSSR_RX_PAUSE)
211 pause |= PAUSE_RX;
212 if (status & V_PSSR_TX_PAUSE)
213 pause |= PAUSE_TX;
214 dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
215 sp = G_PSSR_SPEED(status);
216 if (sp == 0)
217 sp = SPEED_10;
218 else if (sp == 1)
219 sp = SPEED_100;
220 else
221 sp = SPEED_1000;
223 if (link_ok)
224 *link_ok = (status & V_PSSR_LINK) != 0;
225 if (speed)
226 *speed = sp;
227 if (duplex)
228 *duplex = dplx;
229 if (fc)
230 *fc = pause;
231 return 0;
234 static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
237 * Set the downshift counter to 2 so we try to establish Gb link
238 * twice before downshifting.
240 return t3_mdio_change_bits(cphy, 0, MV88E1XXX_EXT_SPECIFIC_CNTRL,
241 V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT),
242 downshift_enable ? V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2) : 0);
245 static int mv88e1xxx_power_down(struct cphy *cphy, int enable)
247 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
248 enable ? BMCR_PDOWN : 0);
251 static int mv88e1xxx_intr_handler(struct cphy *cphy)
253 const u32 link_change_intrs = MV_INTR_LINK_CHNG |
254 MV_INTR_AUTONEG_DONE | MV_INTR_DUPLEX_CHNG |
255 MV_INTR_SPEED_CHNG | MV_INTR_DOWNSHIFT;
257 u32 cause;
258 int cphy_cause = 0;
260 mdio_read(cphy, 0, MV88E1XXX_INTR_STATUS, &cause);
261 cause &= INTR_ENABLE_MASK;
262 if (cause & link_change_intrs)
263 cphy_cause |= cphy_cause_link_change;
264 if (cause & MV_INTR_FIFO_OVER_UNDER)
265 cphy_cause |= cphy_cause_fifo_error;
266 return cphy_cause;
269 #ifdef C99_NOT_SUPPORTED
270 static struct cphy_ops mv88e1xxx_ops = {
271 NULL,
272 mv88e1xxx_reset,
273 mv88e1xxx_intr_enable,
274 mv88e1xxx_intr_disable,
275 mv88e1xxx_intr_clear,
276 mv88e1xxx_intr_handler,
277 mv88e1xxx_autoneg_enable,
278 mv88e1xxx_autoneg_restart,
279 t3_phy_advertise,
280 mv88e1xxx_set_loopback,
281 t3_set_phy_speed_duplex,
282 mv88e1xxx_get_link_status,
283 mv88e1xxx_power_down,
285 #else
286 static struct cphy_ops mv88e1xxx_ops = {
287 .reset = mv88e1xxx_reset,
288 .intr_enable = mv88e1xxx_intr_enable,
289 .intr_disable = mv88e1xxx_intr_disable,
290 .intr_clear = mv88e1xxx_intr_clear,
291 .intr_handler = mv88e1xxx_intr_handler,
292 .autoneg_enable = mv88e1xxx_autoneg_enable,
293 .autoneg_restart = mv88e1xxx_autoneg_restart,
294 .advertise = t3_phy_advertise,
295 .set_loopback = mv88e1xxx_set_loopback,
296 .set_speed_duplex = t3_set_phy_speed_duplex,
297 .get_link_status = mv88e1xxx_get_link_status,
298 .power_down = mv88e1xxx_power_down,
300 #endif
302 void t3_mv88e1xxx_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
303 const struct mdio_ops *mdio_ops)
305 cphy_init(phy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
307 /* Configure copper PHY transmitter as class A to reduce EMI. */
308 mdio_write(phy, 0, MV88E1XXX_EXTENDED_ADDR, 0xb);
309 mdio_write(phy, 0, MV88E1XXX_EXTENDED_DATA, 0x8004);
311 mv88e1xxx_downshift_set(phy, 1); /* Enable downshift */