1/*	$NetBSD: icsphy.c,v 1.41 2006/11/16 21:24:07 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1997 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#include <sys/cdefs.h>
58__FBSDID("$FreeBSD$");
59
60/*
61 * driver for Integrated Circuit Systems' ICS1889-1893 ethernet 10/100 PHY
62 * datasheet from www.icst.com
63 */
64
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/kernel.h>
68#include <sys/module.h>
69#include <sys/socket.h>
70#include <sys/bus.h>
71
72#include <net/if.h>
73#include <net/if_media.h>
74
75#include <dev/mii/mii.h>
76#include <dev/mii/miivar.h>
77#include "miidevs.h"
78
79#include <dev/mii/icsphyreg.h>
80
81#include "miibus_if.h"
82
83static int	icsphy_probe(device_t dev);
84static int	icsphy_attach(device_t dev);
85
86static device_method_t icsphy_methods[] = {
87	/* device interface */
88	DEVMETHOD(device_probe,		icsphy_probe),
89	DEVMETHOD(device_attach,	icsphy_attach),
90	DEVMETHOD(device_detach,	mii_phy_detach),
91	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
92	DEVMETHOD_END
93};
94
95static devclass_t icsphy_devclass;
96
97static driver_t icsphy_driver = {
98	"icsphy",
99	icsphy_methods,
100	sizeof(struct mii_softc)
101};
102
103DRIVER_MODULE(icsphy, miibus, icsphy_driver, icsphy_devclass, 0, 0);
104
105static int	icsphy_service(struct mii_softc *, struct mii_data *, int);
106static void	icsphy_status(struct mii_softc *);
107static void	icsphy_reset(struct mii_softc *);
108
109static const struct mii_phydesc icsphys[] = {
110	MII_PHY_DESC(ICS, 1889),
111	MII_PHY_DESC(ICS, 1890),
112	MII_PHY_DESC(ICS, 1892),
113	MII_PHY_DESC(ICS, 1893),
114	MII_PHY_END
115};
116
117static const struct mii_phy_funcs icsphy_funcs = {
118	icsphy_service,
119	icsphy_status,
120	icsphy_reset
121};
122
123static int
124icsphy_probe(device_t dev)
125{
126
127	return (mii_phy_dev_probe(dev, icsphys, BUS_PROBE_DEFAULT));
128}
129
130static int
131icsphy_attach(device_t dev)
132{
133
134	mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE,
135	    &icsphy_funcs, 1);
136	return (0);
137}
138
139static int
140icsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
141{
142
143	switch (cmd) {
144	case MII_POLLSTAT:
145		break;
146
147	case MII_MEDIACHG:
148		/*
149		 * If the interface is not up, don't do anything.
150		 */
151		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
152			break;
153
154		mii_phy_setmedia(sc);
155		break;
156
157	case MII_TICK:
158		if (mii_phy_tick(sc) == EJUSTRETURN)
159			return (0);
160		break;
161	}
162
163	/* Update the media status. */
164	PHY_STATUS(sc);
165
166	/* Callback if something changed. */
167	mii_phy_update(sc, cmd);
168	return (0);
169}
170
171static void
172icsphy_status(struct mii_softc *sc)
173{
174	struct mii_data *mii = sc->mii_pdata;
175	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
176	int bmcr, qpr;
177
178	mii->mii_media_status = IFM_AVALID;
179	mii->mii_media_active = IFM_ETHER;
180
181	/*
182	 * Don't get link from the BMSR.  It's available in the QPR,
183	 * and we have to read it twice to unlatch it anyhow.  This
184	 * gives us fewer register reads.
185	 */
186	qpr = PHY_READ(sc, MII_ICSPHY_QPR);		/* unlatch */
187	qpr = PHY_READ(sc, MII_ICSPHY_QPR);		/* real value */
188
189	if (qpr & QPR_LINK)
190		mii->mii_media_status |= IFM_ACTIVE;
191
192	bmcr = PHY_READ(sc, MII_BMCR);
193	if (bmcr & BMCR_ISO) {
194		mii->mii_media_active |= IFM_NONE;
195		mii->mii_media_status = 0;
196		return;
197	}
198
199	if (bmcr & BMCR_LOOP)
200		mii->mii_media_active |= IFM_LOOP;
201
202	if (bmcr & BMCR_AUTOEN) {
203		if ((qpr & QPR_ACOMP) == 0) {
204			/* Erg, still trying, I guess... */
205			mii->mii_media_active |= IFM_NONE;
206			return;
207		}
208		if (qpr & QPR_SPEED)
209			mii->mii_media_active |= IFM_100_TX;
210		else
211			mii->mii_media_active |= IFM_10_T;
212		if (qpr & QPR_FDX)
213			mii->mii_media_active |=
214			    IFM_FDX | mii_phy_flowstatus(sc);
215		else
216			mii->mii_media_active |= IFM_HDX;
217	} else
218		mii->mii_media_active = ife->ifm_media;
219}
220
221static void
222icsphy_reset(struct mii_softc *sc)
223{
224
225	mii_phy_reset(sc);
226	/* set powerdown feature */
227	switch (sc->mii_mpd_model) {
228		case MII_MODEL_ICS_1890:
229		case MII_MODEL_ICS_1893:
230			PHY_WRITE(sc, MII_ICSPHY_ECR2, ECR2_100AUTOPWRDN);
231			break;
232		case MII_MODEL_ICS_1892:
233			PHY_WRITE(sc, MII_ICSPHY_ECR2,
234			    ECR2_10AUTOPWRDN|ECR2_100AUTOPWRDN);
235			break;
236		default:
237			/* 1889 have no ECR2 */
238			break;
239	}
240	/*
241	 * There is no description that the reset do auto-negotiation in the
242	 * data sheet.
243	 */
244	PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_STARTNEG|BMCR_FDX);
245}
246