Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pci / cxgb_vsc8211.c
blob0f04bf5a3c7b9d9880c82c074395ff480abe6582
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_vsc8211.c,v 1.2 2007/12/11 11:25:50 lukem Exp $");
33 #endif
34 #ifdef __FreeBSD__
35 __FBSDID("$FreeBSD: src/sys/dev/cxgb/common/cxgb_vsc8211.c,v 1.3 2007/08/25 21:07:37 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 /* VSC8211 PHY specific registers. */
50 enum {
51 VSC8211_INTR_ENABLE = 25,
52 VSC8211_INTR_STATUS = 26,
53 VSC8211_AUX_CTRL_STAT = 28,
56 enum {
57 VSC_INTR_RX_ERR = 1 << 0,
58 VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
59 VSC_INTR_CABLE = 1 << 2, /* cable impairment */
60 VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
61 VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
62 VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
63 VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
64 VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
65 VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
66 VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
67 VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
68 VSC_INTR_LINK_CHG = 1 << 13, /* link change */
69 VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
72 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
73 VSC_INTR_NEG_DONE)
74 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
75 VSC_INTR_ENABLE)
77 /* PHY specific auxiliary control & status register fields */
78 #define S_ACSR_ACTIPHY_TMR 0
79 #define M_ACSR_ACTIPHY_TMR 0x3
80 #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
82 #define S_ACSR_SPEED 3
83 #define M_ACSR_SPEED 0x3
84 #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
86 #define S_ACSR_DUPLEX 5
87 #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
89 #define S_ACSR_ACTIPHY 6
90 #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
93 * Reset the PHY. This PHY completes reset immediately so we never wait.
95 static int vsc8211_reset(struct cphy *cphy, int wait)
97 return t3_phy_reset(cphy, 0, 0);
100 static int vsc8211_intr_enable(struct cphy *cphy)
102 return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
105 static int vsc8211_intr_disable(struct cphy *cphy)
107 return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
110 static int vsc8211_intr_clear(struct cphy *cphy)
112 u32 val;
114 /* Clear PHY interrupts by reading the register. */
115 return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
118 static int vsc8211_autoneg_enable(struct cphy *cphy)
120 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
121 BMCR_ANENABLE | BMCR_ANRESTART);
124 static int vsc8211_autoneg_restart(struct cphy *cphy)
126 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
127 BMCR_ANRESTART);
130 static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
131 int *speed, int *duplex, int *fc)
133 unsigned int bmcr, status, lpa, adv;
134 int err, sp = -1, dplx = -1, pause = 0;
136 err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
137 if (!err)
138 err = mdio_read(cphy, 0, MII_BMSR, &status);
139 if (err)
140 return err;
142 if (link_ok) {
144 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
145 * once more to get the current link state.
147 if (!(status & BMSR_LSTATUS))
148 err = mdio_read(cphy, 0, MII_BMSR, &status);
149 if (err)
150 return err;
151 *link_ok = (status & BMSR_LSTATUS) != 0;
153 if (!(bmcr & BMCR_ANENABLE)) {
154 dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
155 if (bmcr & BMCR_SPEED1000)
156 sp = SPEED_1000;
157 else if (bmcr & BMCR_SPEED100)
158 sp = SPEED_100;
159 else
160 sp = SPEED_10;
161 } else if (status & BMSR_ANEGCOMPLETE) {
162 err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
163 if (err)
164 return err;
166 dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
167 sp = G_ACSR_SPEED(status);
168 if (sp == 0)
169 sp = SPEED_10;
170 else if (sp == 1)
171 sp = SPEED_100;
172 else
173 sp = SPEED_1000;
175 if (fc && dplx == DUPLEX_FULL) {
176 err = mdio_read(cphy, 0, MII_LPA, &lpa);
177 if (!err)
178 err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
179 if (err)
180 return err;
182 if (lpa & adv & ADVERTISE_PAUSE_CAP)
183 pause = PAUSE_RX | PAUSE_TX;
184 else if ((lpa & ADVERTISE_PAUSE_CAP) &&
185 (lpa & ADVERTISE_PAUSE_ASYM) &&
186 (adv & ADVERTISE_PAUSE_ASYM))
187 pause = PAUSE_TX;
188 else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
189 (adv & ADVERTISE_PAUSE_CAP))
190 pause = PAUSE_RX;
193 if (speed)
194 *speed = sp;
195 if (duplex)
196 *duplex = dplx;
197 if (fc)
198 *fc = pause;
199 return 0;
202 static int vsc8211_power_down(struct cphy *cphy, int enable)
204 return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
205 enable ? BMCR_PDOWN : 0);
208 static int vsc8211_intr_handler(struct cphy *cphy)
210 unsigned int cause;
211 int err, cphy_cause = 0;
213 err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
214 if (err)
215 return err;
217 cause &= INTR_MASK;
218 if (cause & CFG_CHG_INTR_MASK)
219 cphy_cause |= cphy_cause_link_change;
220 if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
221 cphy_cause |= cphy_cause_fifo_error;
222 return cphy_cause;
225 #ifdef C99_NOT_SUPPORTED
226 static struct cphy_ops vsc8211_ops = {
227 NULL,
228 vsc8211_reset,
229 vsc8211_intr_enable,
230 vsc8211_intr_disable,
231 vsc8211_intr_clear,
232 vsc8211_intr_handler,
233 vsc8211_autoneg_enable,
234 vsc8211_autoneg_restart,
235 t3_phy_advertise,
236 NULL,
237 t3_set_phy_speed_duplex,
238 vsc8211_get_link_status,
239 vsc8211_power_down,
241 #else
242 static struct cphy_ops vsc8211_ops = {
243 .reset = vsc8211_reset,
244 .intr_enable = vsc8211_intr_enable,
245 .intr_disable = vsc8211_intr_disable,
246 .intr_clear = vsc8211_intr_clear,
247 .intr_handler = vsc8211_intr_handler,
248 .autoneg_enable = vsc8211_autoneg_enable,
249 .autoneg_restart = vsc8211_autoneg_restart,
250 .advertise = t3_phy_advertise,
251 .set_speed_duplex = t3_set_phy_speed_duplex,
252 .get_link_status = vsc8211_get_link_status,
253 .power_down = vsc8211_power_down,
255 #endif
257 void t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
258 const struct mdio_ops *mdio_ops)
260 cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
261 t3_os_sleep(20); /* PHY needs ~10ms to start responding to MDIO */