1/* $NetBSD: ikphy.c,v 1.12 2016/11/02 07:01:54 msaitoh Exp $ */
2
3/*******************************************************************************
4Copyright (c) 2001-2005, Intel Corporation
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. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16
17 3. Neither the name of the Intel Corporation nor the names of its
18 contributors may be used to endorse or promote products derived from
19 this software without specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31POSSIBILITY OF SUCH DAMAGE.
32*******************************************************************************/
33/*
34 * Copyright (c) 2006 Manuel Bouyer. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 */
56
57/*
58 * driver for Intel's i82563 ethernet 10/100/1000 PHY
59 */
60
61#include <sys/cdefs.h>
62__KERNEL_RCSID(0, "$NetBSD: ikphy.c,v 1.12 2016/11/02 07:01:54 msaitoh Exp $");
63
64#include <sys/param.h>
65#include <sys/systm.h>
66#include <sys/kernel.h>
67#include <sys/device.h>
68#include <sys/socket.h>
69#include <sys/errno.h>
70
71#include <net/if.h>
72#include <net/if_media.h>
73
74#include <dev/mii/mii.h>
75#include <dev/mii/miivar.h>
76#include <dev/mii/miidevs.h>
77
78#include <dev/mii/ikphyreg.h>
79
80static int ikphymatch(device_t, cfdata_t, void *);
81static void ikphyattach(device_t, device_t, void *);
82
83CFATTACH_DECL_NEW(ikphy, sizeof(struct mii_softc),
84 ikphymatch, ikphyattach, mii_phy_detach, mii_phy_activate);
85
86static int ikphy_service(struct mii_softc *, struct mii_data *, int);
87static void ikphy_status(struct mii_softc *);
88static void ikphy_setmedia(struct mii_softc *);
89
90static const struct mii_phy_funcs ikphy_funcs = {
91 ikphy_service, ikphy_status, mii_phy_reset,
92};
93
94static const struct mii_phydesc ikphys[] = {
95 { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_I82563,
96 MII_STR_xxMARVELL_I82563 },
97
98 { 0, 0,
99 NULL },
100};
101
102static int
103ikphymatch(device_t parent, cfdata_t match, void *aux)
104{
105 struct mii_attach_args *ma = aux;
106
107 if (mii_phy_match(ma, ikphys) != NULL)
108 return (10);
109
110 return (0);
111}
112
113static void
114ikphyattach(device_t parent, device_t self, void *aux)
115{
116 struct mii_softc *sc = device_private(self);
117 struct mii_attach_args *ma = aux;
118 struct mii_data *mii = ma->mii_data;
119 const struct mii_phydesc *mpd;
120
121 mpd = mii_phy_match(ma, ikphys);
122 aprint_naive(": Media interface\n");
123 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
124
125 sc->mii_dev = self;
126 sc->mii_inst = mii->mii_instance;
127 sc->mii_phy = ma->mii_phyno;
128 sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
129 sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
130 sc->mii_mpd_rev = MII_REV(ma->mii_id2);
131 sc->mii_funcs = &ikphy_funcs;
132 sc->mii_pdata = mii;
133 sc->mii_flags = ma->mii_flags;
134 sc->mii_anegticks = MII_ANEGTICKS;
135
136 PHY_RESET(sc);
137
138 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
139 if (sc->mii_capabilities & BMSR_EXTSTAT)
140 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
141 aprint_normal_dev(self, "");
142 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
143 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
144 aprint_error("no media present");
145 else
146 mii_phy_add_media(sc);
147 aprint_normal("\n");
148}
149
150static int
151ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
152{
153 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
154 int reg;
155
156 switch (cmd) {
157 case MII_POLLSTAT:
158 /*
159 * If we're not polling our PHY instance, just return.
160 */
161 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
162 return (0);
163 break;
164
165 case MII_MEDIACHG:
166 /*
167 * If the media indicates a different PHY instance,
168 * isolate ourselves.
169 */
170 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
171 reg = PHY_READ(sc, MII_BMCR);
172 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
173 return (0);
174 }
175
176 /*
177 * If the interface is not up, don't do anything.
178 */
179 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
180 break;
181
182 ikphy_setmedia(sc);
183 break;
184
185 case MII_TICK:
186 /*
187 * If we're not currently selected, just return.
188 */
189 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
190 return (0);
191
192 if (mii_phy_tick(sc) == EJUSTRETURN)
193 return (0);
194 break;
195
196 case MII_DOWN:
197 mii_phy_down(sc);
198 return (0);
199 }
200
201 /* Update the media status. */
202 mii_phy_status(sc);
203
204 /* Callback if something changed. */
205 mii_phy_update(sc, cmd);
206 return (0);
207}
208
209static void
210ikphy_setmedia(struct mii_softc *sc)
211{
212 uint16_t phy_data;
213 struct mii_data *mii = sc->mii_pdata;
214 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
215
216 /* Enable CRS on TX for half-duplex operation. */
217 phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL);
218 phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
219 /* Use 25MHz for both link down and 1000BASE-T for Tx clock */
220 phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
221 PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
222
223 /* set mdi/mid-x options */
224 phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL);
225 phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
226 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
227 phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
228 else
229 phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
230 /* set polarity correction */
231 phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
232 PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data);
233
234 /* SW Reset the PHY so all changes take effect */
235 PHY_RESET(sc);
236
237 /* for the i80003 */
238 phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2);
239 phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
240 PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data);
241
242 /* Enable Electrical Idle on the PHY */
243 phy_data = PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL);
244 phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
245 PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data);
246
247 phy_data = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL);
248 phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
249 PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data);
250
251 /*
252 * Workaround: Disable padding in Kumeran interface in the MAC
253 * and in the PHY to avoid CRC errors.
254 */
255 phy_data = PHY_READ(sc, GG82563_PHY_INBAND_CTRL);
256 phy_data |= GG82563_ICR_DIS_PADDING;
257 PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data);
258
259 mii_phy_setmedia(sc);
260 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
261 /*
262 * when not in auto mode, we need to restart nego
263 * anyway, or a switch from a fixed mode to another
264 * fixed mode may not be seen by the switch.
265 */
266 PHY_WRITE(sc, MII_BMCR,
267 PHY_READ(sc, MII_BMCR) | BMCR_STARTNEG);
268 }
269 phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL);
270 phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
271 switch(IFM_SUBTYPE(ife->ifm_media)) {
272 case IFM_10_T:
273 phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
274 break;
275 case IFM_100_TX:
276 phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
277 break;
278 case IFM_1000_T:
279 phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
280 break;
281 }
282 phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
283 PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
284}
285
286static void
287ikphy_status(struct mii_softc *sc)
288{
289 struct mii_data *mii = sc->mii_pdata;
290 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
291 int pssr, bmcr, gtsr, kmrn;
292
293 mii->mii_media_status = IFM_AVALID;
294 mii->mii_media_active = IFM_ETHER;
295
296 pssr = PHY_READ(sc, GG82563_PHY_SPEC_STATUS);
297
298 if (pssr & GG82563_PSSR_LINK)
299 mii->mii_media_status |= IFM_ACTIVE;
300
301 bmcr = PHY_READ(sc, MII_BMCR);
302 if (bmcr & BMCR_ISO) {
303 mii->mii_media_active |= IFM_NONE;
304 mii->mii_media_status = 0;
305 return;
306 }
307
308 if (bmcr & BMCR_LOOP)
309 mii->mii_media_active |= IFM_LOOP;
310
311 if (bmcr & BMCR_AUTOEN) {
312 /*
313 * The media status bits are only valid of autonegotiation
314 * has completed (or it's disabled).
315 */
316 if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) {
317 /* Erg, still trying, I guess... */
318 mii->mii_media_active |= IFM_NONE;
319 return;
320 }
321
322 switch (pssr & GG82563_PSSR_SPEED_MASK) {
323 case GG82563_PSSR_SPEED_1000MBPS:
324 mii->mii_media_active |= IFM_1000_T;
325 gtsr = PHY_READ(sc, MII_100T2SR);
326 if (gtsr & GTSR_MS_RES)
327 mii->mii_media_active |= IFM_ETH_MASTER;
328 break;
329
330 case GG82563_PSSR_SPEED_100MBPS:
331 mii->mii_media_active |= IFM_100_TX;
332 break;
333
334 case GG82563_PSSR_SPEED_10MBPS:
335 mii->mii_media_active |= IFM_10_T;
336 break;
337
338 default:
339 mii->mii_media_active |= IFM_NONE;
340 mii->mii_media_status = 0;
341 return;
342 }
343
344 if (pssr & GG82563_PSSR_DUPLEX)
345 mii->mii_media_active |=
346 IFM_FDX | mii_phy_flowstatus(sc);
347 else
348 mii->mii_media_active |= IFM_HDX;
349 } else
350 mii->mii_media_active = ife->ifm_media;
351 kmrn = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL);
352 if (mii->mii_media_active & IFM_FDX)
353 kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
354 else
355 kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER;
356 PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn);
357}
358