cxgb_vsc8211.c revision 1.1.2.2 1 1.1.2.2 uebayasi /**************************************************************************
2 1.1.2.2 uebayasi
3 1.1.2.2 uebayasi Copyright (c) 2007, Chelsio Inc.
4 1.1.2.2 uebayasi All rights reserved.
5 1.1.2.2 uebayasi
6 1.1.2.2 uebayasi Redistribution and use in source and binary forms, with or without
7 1.1.2.2 uebayasi modification, are permitted provided that the following conditions are met:
8 1.1.2.2 uebayasi
9 1.1.2.2 uebayasi 1. Redistributions of source code must retain the above copyright notice,
10 1.1.2.2 uebayasi this list of conditions and the following disclaimer.
11 1.1.2.2 uebayasi
12 1.1.2.2 uebayasi 2. Neither the name of the Chelsio Corporation nor the names of its
13 1.1.2.2 uebayasi contributors may be used to endorse or promote products derived from
14 1.1.2.2 uebayasi this software without specific prior written permission.
15 1.1.2.2 uebayasi
16 1.1.2.2 uebayasi THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 1.1.2.2 uebayasi AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1.2.2 uebayasi IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1.2.2 uebayasi ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 1.1.2.2 uebayasi LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1.2.2 uebayasi CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1.2.2 uebayasi SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1.2.2 uebayasi INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1.2.2 uebayasi CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1.2.2 uebayasi ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1.2.2 uebayasi POSSIBILITY OF SUCH DAMAGE.
27 1.1.2.2 uebayasi
28 1.1.2.2 uebayasi ***************************************************************************/
29 1.1.2.2 uebayasi
30 1.1.2.2 uebayasi #include <sys/cdefs.h>
31 1.1.2.2 uebayasi __KERNEL_RCSID(0, "$NetBSD: cxgb_vsc8211.c,v 1.1.2.2 2010/04/30 14:43:45 uebayasi Exp $");
32 1.1.2.2 uebayasi
33 1.1.2.2 uebayasi #ifdef CONFIG_DEFINED
34 1.1.2.2 uebayasi #include <cxgb_include.h>
35 1.1.2.2 uebayasi #else
36 1.1.2.2 uebayasi #include <dev/pci/cxgb/cxgb_include.h>
37 1.1.2.2 uebayasi #endif
38 1.1.2.2 uebayasi
39 1.1.2.2 uebayasi /* VSC8211 PHY specific registers. */
40 1.1.2.2 uebayasi enum {
41 1.1.2.2 uebayasi VSC8211_INTR_ENABLE = 25,
42 1.1.2.2 uebayasi VSC8211_INTR_STATUS = 26,
43 1.1.2.2 uebayasi VSC8211_AUX_CTRL_STAT = 28,
44 1.1.2.2 uebayasi };
45 1.1.2.2 uebayasi
46 1.1.2.2 uebayasi enum {
47 1.1.2.2 uebayasi VSC_INTR_RX_ERR = 1 << 0,
48 1.1.2.2 uebayasi VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
49 1.1.2.2 uebayasi VSC_INTR_CABLE = 1 << 2, /* cable impairment */
50 1.1.2.2 uebayasi VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
51 1.1.2.2 uebayasi VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
52 1.1.2.2 uebayasi VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
53 1.1.2.2 uebayasi VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
54 1.1.2.2 uebayasi VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
55 1.1.2.2 uebayasi VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
56 1.1.2.2 uebayasi VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
57 1.1.2.2 uebayasi VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
58 1.1.2.2 uebayasi VSC_INTR_LINK_CHG = 1 << 13, /* link change */
59 1.1.2.2 uebayasi VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
60 1.1.2.2 uebayasi };
61 1.1.2.2 uebayasi
62 1.1.2.2 uebayasi #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
63 1.1.2.2 uebayasi VSC_INTR_NEG_DONE)
64 1.1.2.2 uebayasi #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
65 1.1.2.2 uebayasi VSC_INTR_ENABLE)
66 1.1.2.2 uebayasi
67 1.1.2.2 uebayasi /* PHY specific auxiliary control & status register fields */
68 1.1.2.2 uebayasi #define S_ACSR_ACTIPHY_TMR 0
69 1.1.2.2 uebayasi #define M_ACSR_ACTIPHY_TMR 0x3
70 1.1.2.2 uebayasi #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
71 1.1.2.2 uebayasi
72 1.1.2.2 uebayasi #define S_ACSR_SPEED 3
73 1.1.2.2 uebayasi #define M_ACSR_SPEED 0x3
74 1.1.2.2 uebayasi #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
75 1.1.2.2 uebayasi
76 1.1.2.2 uebayasi #define S_ACSR_DUPLEX 5
77 1.1.2.2 uebayasi #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
78 1.1.2.2 uebayasi
79 1.1.2.2 uebayasi #define S_ACSR_ACTIPHY 6
80 1.1.2.2 uebayasi #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
81 1.1.2.2 uebayasi
82 1.1.2.2 uebayasi /*
83 1.1.2.2 uebayasi * Reset the PHY. This PHY completes reset immediately so we never wait.
84 1.1.2.2 uebayasi */
85 1.1.2.2 uebayasi static int vsc8211_reset(struct cphy *cphy, int wait)
86 1.1.2.2 uebayasi {
87 1.1.2.2 uebayasi return t3_phy_reset(cphy, 0, 0);
88 1.1.2.2 uebayasi }
89 1.1.2.2 uebayasi
90 1.1.2.2 uebayasi static int vsc8211_intr_enable(struct cphy *cphy)
91 1.1.2.2 uebayasi {
92 1.1.2.2 uebayasi return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
93 1.1.2.2 uebayasi }
94 1.1.2.2 uebayasi
95 1.1.2.2 uebayasi static int vsc8211_intr_disable(struct cphy *cphy)
96 1.1.2.2 uebayasi {
97 1.1.2.2 uebayasi return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
98 1.1.2.2 uebayasi }
99 1.1.2.2 uebayasi
100 1.1.2.2 uebayasi static int vsc8211_intr_clear(struct cphy *cphy)
101 1.1.2.2 uebayasi {
102 1.1.2.2 uebayasi u32 val;
103 1.1.2.2 uebayasi
104 1.1.2.2 uebayasi /* Clear PHY interrupts by reading the register. */
105 1.1.2.2 uebayasi return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
106 1.1.2.2 uebayasi }
107 1.1.2.2 uebayasi
108 1.1.2.2 uebayasi static int vsc8211_autoneg_enable(struct cphy *cphy)
109 1.1.2.2 uebayasi {
110 1.1.2.2 uebayasi return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
111 1.1.2.2 uebayasi BMCR_ANENABLE | BMCR_ANRESTART);
112 1.1.2.2 uebayasi }
113 1.1.2.2 uebayasi
114 1.1.2.2 uebayasi static int vsc8211_autoneg_restart(struct cphy *cphy)
115 1.1.2.2 uebayasi {
116 1.1.2.2 uebayasi return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
117 1.1.2.2 uebayasi BMCR_ANRESTART);
118 1.1.2.2 uebayasi }
119 1.1.2.2 uebayasi
120 1.1.2.2 uebayasi static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
121 1.1.2.2 uebayasi int *speed, int *duplex, int *fc)
122 1.1.2.2 uebayasi {
123 1.1.2.2 uebayasi unsigned int bmcr, status, lpa, adv;
124 1.1.2.2 uebayasi int err, sp = -1, dplx = -1, pause = 0;
125 1.1.2.2 uebayasi
126 1.1.2.2 uebayasi err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
127 1.1.2.2 uebayasi if (!err)
128 1.1.2.2 uebayasi err = mdio_read(cphy, 0, MII_BMSR, &status);
129 1.1.2.2 uebayasi if (err)
130 1.1.2.2 uebayasi return err;
131 1.1.2.2 uebayasi
132 1.1.2.2 uebayasi if (link_ok) {
133 1.1.2.2 uebayasi /*
134 1.1.2.2 uebayasi * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
135 1.1.2.2 uebayasi * once more to get the current link state.
136 1.1.2.2 uebayasi */
137 1.1.2.2 uebayasi if (!(status & BMSR_LSTATUS))
138 1.1.2.2 uebayasi err = mdio_read(cphy, 0, MII_BMSR, &status);
139 1.1.2.2 uebayasi if (err)
140 1.1.2.2 uebayasi return err;
141 1.1.2.2 uebayasi *link_ok = (status & BMSR_LSTATUS) != 0;
142 1.1.2.2 uebayasi }
143 1.1.2.2 uebayasi if (!(bmcr & BMCR_ANENABLE)) {
144 1.1.2.2 uebayasi dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
145 1.1.2.2 uebayasi if (bmcr & BMCR_SPEED1000)
146 1.1.2.2 uebayasi sp = SPEED_1000;
147 1.1.2.2 uebayasi else if (bmcr & BMCR_SPEED100)
148 1.1.2.2 uebayasi sp = SPEED_100;
149 1.1.2.2 uebayasi else
150 1.1.2.2 uebayasi sp = SPEED_10;
151 1.1.2.2 uebayasi } else if (status & BMSR_ANEGCOMPLETE) {
152 1.1.2.2 uebayasi err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
153 1.1.2.2 uebayasi if (err)
154 1.1.2.2 uebayasi return err;
155 1.1.2.2 uebayasi
156 1.1.2.2 uebayasi dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
157 1.1.2.2 uebayasi sp = G_ACSR_SPEED(status);
158 1.1.2.2 uebayasi if (sp == 0)
159 1.1.2.2 uebayasi sp = SPEED_10;
160 1.1.2.2 uebayasi else if (sp == 1)
161 1.1.2.2 uebayasi sp = SPEED_100;
162 1.1.2.2 uebayasi else
163 1.1.2.2 uebayasi sp = SPEED_1000;
164 1.1.2.2 uebayasi
165 1.1.2.2 uebayasi if (fc && dplx == DUPLEX_FULL) {
166 1.1.2.2 uebayasi err = mdio_read(cphy, 0, MII_LPA, &lpa);
167 1.1.2.2 uebayasi if (!err)
168 1.1.2.2 uebayasi err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
169 1.1.2.2 uebayasi if (err)
170 1.1.2.2 uebayasi return err;
171 1.1.2.2 uebayasi
172 1.1.2.2 uebayasi if (lpa & adv & ADVERTISE_PAUSE_CAP)
173 1.1.2.2 uebayasi pause = PAUSE_RX | PAUSE_TX;
174 1.1.2.2 uebayasi else if ((lpa & ADVERTISE_PAUSE_CAP) &&
175 1.1.2.2 uebayasi (lpa & ADVERTISE_PAUSE_ASYM) &&
176 1.1.2.2 uebayasi (adv & ADVERTISE_PAUSE_ASYM))
177 1.1.2.2 uebayasi pause = PAUSE_TX;
178 1.1.2.2 uebayasi else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
179 1.1.2.2 uebayasi (adv & ADVERTISE_PAUSE_CAP))
180 1.1.2.2 uebayasi pause = PAUSE_RX;
181 1.1.2.2 uebayasi }
182 1.1.2.2 uebayasi }
183 1.1.2.2 uebayasi if (speed)
184 1.1.2.2 uebayasi *speed = sp;
185 1.1.2.2 uebayasi if (duplex)
186 1.1.2.2 uebayasi *duplex = dplx;
187 1.1.2.2 uebayasi if (fc)
188 1.1.2.2 uebayasi *fc = pause;
189 1.1.2.2 uebayasi return 0;
190 1.1.2.2 uebayasi }
191 1.1.2.2 uebayasi
192 1.1.2.2 uebayasi static int vsc8211_power_down(struct cphy *cphy, int enable)
193 1.1.2.2 uebayasi {
194 1.1.2.2 uebayasi return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
195 1.1.2.2 uebayasi enable ? BMCR_PDOWN : 0);
196 1.1.2.2 uebayasi }
197 1.1.2.2 uebayasi
198 1.1.2.2 uebayasi static int vsc8211_intr_handler(struct cphy *cphy)
199 1.1.2.2 uebayasi {
200 1.1.2.2 uebayasi unsigned int cause;
201 1.1.2.2 uebayasi int err, cphy_cause = 0;
202 1.1.2.2 uebayasi
203 1.1.2.2 uebayasi err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
204 1.1.2.2 uebayasi if (err)
205 1.1.2.2 uebayasi return err;
206 1.1.2.2 uebayasi
207 1.1.2.2 uebayasi cause &= INTR_MASK;
208 1.1.2.2 uebayasi if (cause & CFG_CHG_INTR_MASK)
209 1.1.2.2 uebayasi cphy_cause |= cphy_cause_link_change;
210 1.1.2.2 uebayasi if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
211 1.1.2.2 uebayasi cphy_cause |= cphy_cause_fifo_error;
212 1.1.2.2 uebayasi return cphy_cause;
213 1.1.2.2 uebayasi }
214 1.1.2.2 uebayasi
215 1.1.2.2 uebayasi #ifdef C99_NOT_SUPPORTED
216 1.1.2.2 uebayasi static struct cphy_ops vsc8211_ops = {
217 1.1.2.2 uebayasi NULL,
218 1.1.2.2 uebayasi vsc8211_reset,
219 1.1.2.2 uebayasi vsc8211_intr_enable,
220 1.1.2.2 uebayasi vsc8211_intr_disable,
221 1.1.2.2 uebayasi vsc8211_intr_clear,
222 1.1.2.2 uebayasi vsc8211_intr_handler,
223 1.1.2.2 uebayasi vsc8211_autoneg_enable,
224 1.1.2.2 uebayasi vsc8211_autoneg_restart,
225 1.1.2.2 uebayasi t3_phy_advertise,
226 1.1.2.2 uebayasi NULL,
227 1.1.2.2 uebayasi t3_set_phy_speed_duplex,
228 1.1.2.2 uebayasi vsc8211_get_link_status,
229 1.1.2.2 uebayasi vsc8211_power_down,
230 1.1.2.2 uebayasi };
231 1.1.2.2 uebayasi #else
232 1.1.2.2 uebayasi static struct cphy_ops vsc8211_ops = {
233 1.1.2.2 uebayasi .reset = vsc8211_reset,
234 1.1.2.2 uebayasi .intr_enable = vsc8211_intr_enable,
235 1.1.2.2 uebayasi .intr_disable = vsc8211_intr_disable,
236 1.1.2.2 uebayasi .intr_clear = vsc8211_intr_clear,
237 1.1.2.2 uebayasi .intr_handler = vsc8211_intr_handler,
238 1.1.2.2 uebayasi .autoneg_enable = vsc8211_autoneg_enable,
239 1.1.2.2 uebayasi .autoneg_restart = vsc8211_autoneg_restart,
240 1.1.2.2 uebayasi .advertise = t3_phy_advertise,
241 1.1.2.2 uebayasi .set_speed_duplex = t3_set_phy_speed_duplex,
242 1.1.2.2 uebayasi .get_link_status = vsc8211_get_link_status,
243 1.1.2.2 uebayasi .power_down = vsc8211_power_down,
244 1.1.2.2 uebayasi };
245 1.1.2.2 uebayasi #endif
246 1.1.2.2 uebayasi
247 1.1.2.2 uebayasi void t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
248 1.1.2.2 uebayasi const struct mdio_ops *mdio_ops)
249 1.1.2.2 uebayasi {
250 1.1.2.2 uebayasi cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
251 1.1.2.2 uebayasi t3_os_sleep(20); /* PHY needs ~10ms to start responding to MDIO */
252 1.1.2.2 uebayasi }
253