xref: /freebsd/sys/dev/mii/micphy.c (revision 8b62915e24d271b9e3a28f396bb54c76a764762b)
1*8b62915eSRuslan Bukin /*-
2*8b62915eSRuslan Bukin  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3*8b62915eSRuslan Bukin  * All rights reserved.
4*8b62915eSRuslan Bukin  *
5*8b62915eSRuslan Bukin  * This software was developed by SRI International and the University of
6*8b62915eSRuslan Bukin  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7*8b62915eSRuslan Bukin  * ("CTSRD"), as part of the DARPA CRASH research programme.
8*8b62915eSRuslan Bukin  *
9*8b62915eSRuslan Bukin  * Redistribution and use in source and binary forms, with or without
10*8b62915eSRuslan Bukin  * modification, are permitted provided that the following conditions
11*8b62915eSRuslan Bukin  * are met:
12*8b62915eSRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
13*8b62915eSRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
14*8b62915eSRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
15*8b62915eSRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
16*8b62915eSRuslan Bukin  *    documentation and/or other materials provided with the distribution.
17*8b62915eSRuslan Bukin  *
18*8b62915eSRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*8b62915eSRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*8b62915eSRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*8b62915eSRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*8b62915eSRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*8b62915eSRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*8b62915eSRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*8b62915eSRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*8b62915eSRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*8b62915eSRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*8b62915eSRuslan Bukin  * SUCH DAMAGE.
29*8b62915eSRuslan Bukin  */
30*8b62915eSRuslan Bukin 
31*8b62915eSRuslan Bukin #include <sys/cdefs.h>
32*8b62915eSRuslan Bukin __FBSDID("$FreeBSD$");
33*8b62915eSRuslan Bukin 
34*8b62915eSRuslan Bukin /*
35*8b62915eSRuslan Bukin  * Micrel KSZ9021 Gigabit Ethernet Transceiver
36*8b62915eSRuslan Bukin  */
37*8b62915eSRuslan Bukin 
38*8b62915eSRuslan Bukin #include <sys/param.h>
39*8b62915eSRuslan Bukin #include <sys/systm.h>
40*8b62915eSRuslan Bukin #include <sys/kernel.h>
41*8b62915eSRuslan Bukin #include <sys/socket.h>
42*8b62915eSRuslan Bukin #include <sys/errno.h>
43*8b62915eSRuslan Bukin #include <sys/module.h>
44*8b62915eSRuslan Bukin #include <sys/bus.h>
45*8b62915eSRuslan Bukin #include <sys/malloc.h>
46*8b62915eSRuslan Bukin 
47*8b62915eSRuslan Bukin #include <machine/bus.h>
48*8b62915eSRuslan Bukin 
49*8b62915eSRuslan Bukin #include <net/if.h>
50*8b62915eSRuslan Bukin #include <net/if_media.h>
51*8b62915eSRuslan Bukin 
52*8b62915eSRuslan Bukin #include <dev/mii/mii.h>
53*8b62915eSRuslan Bukin #include <dev/mii/miivar.h>
54*8b62915eSRuslan Bukin #include "miidevs.h"
55*8b62915eSRuslan Bukin 
56*8b62915eSRuslan Bukin #include "miibus_if.h"
57*8b62915eSRuslan Bukin 
58*8b62915eSRuslan Bukin #include <dev/fdt/fdt_common.h>
59*8b62915eSRuslan Bukin #include <dev/ofw/openfirm.h>
60*8b62915eSRuslan Bukin #include <dev/ofw/ofw_bus.h>
61*8b62915eSRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
62*8b62915eSRuslan Bukin 
63*8b62915eSRuslan Bukin #define	MII_KSZPHY_EXTREG			0x0b
64*8b62915eSRuslan Bukin #define	 KSZPHY_EXTREG_WRITE			(1 << 15)
65*8b62915eSRuslan Bukin #define	MII_KSZPHY_EXTREG_WRITE			0x0c
66*8b62915eSRuslan Bukin #define	MII_KSZPHY_EXTREG_READ			0x0d
67*8b62915eSRuslan Bukin #define	MII_KSZPHY_CLK_CONTROL_PAD_SKEW		0x104
68*8b62915eSRuslan Bukin #define	MII_KSZPHY_RX_DATA_PAD_SKEW		0x105
69*8b62915eSRuslan Bukin #define	MII_KSZPHY_TX_DATA_PAD_SKEW		0x106
70*8b62915eSRuslan Bukin 
71*8b62915eSRuslan Bukin #define	PS_TO_REG(p)	(p / 200)
72*8b62915eSRuslan Bukin 
73*8b62915eSRuslan Bukin static int micphy_probe(device_t);
74*8b62915eSRuslan Bukin static int micphy_attach(device_t);
75*8b62915eSRuslan Bukin static int micphy_service(struct mii_softc *, struct mii_data *, int);
76*8b62915eSRuslan Bukin 
77*8b62915eSRuslan Bukin static device_method_t micphy_methods[] = {
78*8b62915eSRuslan Bukin 	/* device interface */
79*8b62915eSRuslan Bukin 	DEVMETHOD(device_probe,		micphy_probe),
80*8b62915eSRuslan Bukin 	DEVMETHOD(device_attach,	micphy_attach),
81*8b62915eSRuslan Bukin 	DEVMETHOD(device_detach,	mii_phy_detach),
82*8b62915eSRuslan Bukin 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
83*8b62915eSRuslan Bukin 	DEVMETHOD_END
84*8b62915eSRuslan Bukin };
85*8b62915eSRuslan Bukin 
86*8b62915eSRuslan Bukin static devclass_t micphy_devclass;
87*8b62915eSRuslan Bukin 
88*8b62915eSRuslan Bukin static driver_t micphy_driver = {
89*8b62915eSRuslan Bukin 	"micphy",
90*8b62915eSRuslan Bukin 	micphy_methods,
91*8b62915eSRuslan Bukin 	sizeof(struct mii_softc)
92*8b62915eSRuslan Bukin };
93*8b62915eSRuslan Bukin 
94*8b62915eSRuslan Bukin DRIVER_MODULE(micphy, miibus, micphy_driver, micphy_devclass, 0, 0);
95*8b62915eSRuslan Bukin 
96*8b62915eSRuslan Bukin static const struct mii_phydesc micphys[] = {
97*8b62915eSRuslan Bukin 	MII_PHY_DESC(MICREL, KSZ9021),
98*8b62915eSRuslan Bukin 	MII_PHY_END
99*8b62915eSRuslan Bukin };
100*8b62915eSRuslan Bukin 
101*8b62915eSRuslan Bukin static const struct mii_phy_funcs micphy_funcs = {
102*8b62915eSRuslan Bukin 	micphy_service,
103*8b62915eSRuslan Bukin 	ukphy_status,
104*8b62915eSRuslan Bukin 	mii_phy_reset
105*8b62915eSRuslan Bukin };
106*8b62915eSRuslan Bukin 
107*8b62915eSRuslan Bukin static void micphy_write(struct mii_softc *sc, uint32_t reg, uint32_t val)
108*8b62915eSRuslan Bukin {
109*8b62915eSRuslan Bukin 
110*8b62915eSRuslan Bukin 	PHY_WRITE(sc, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | reg);
111*8b62915eSRuslan Bukin 	PHY_WRITE(sc, MII_KSZPHY_EXTREG_WRITE, val);
112*8b62915eSRuslan Bukin }
113*8b62915eSRuslan Bukin 
114*8b62915eSRuslan Bukin static int
115*8b62915eSRuslan Bukin ksz9021_load_values(struct mii_softc *sc, phandle_t node, uint32_t reg,
116*8b62915eSRuslan Bukin 			char *field1, char *field2,
117*8b62915eSRuslan Bukin 			char *field3, char *field4)
118*8b62915eSRuslan Bukin {
119*8b62915eSRuslan Bukin 	pcell_t dts_value[1];
120*8b62915eSRuslan Bukin 	int len;
121*8b62915eSRuslan Bukin 	int val;
122*8b62915eSRuslan Bukin 
123*8b62915eSRuslan Bukin 	val = 0;
124*8b62915eSRuslan Bukin 
125*8b62915eSRuslan Bukin 	if ((len = OF_getproplen(node, field1)) > 0) {
126*8b62915eSRuslan Bukin 		OF_getencprop(node, field1, dts_value, len);
127*8b62915eSRuslan Bukin 		val = PS_TO_REG(dts_value[0]);
128*8b62915eSRuslan Bukin 	}
129*8b62915eSRuslan Bukin 
130*8b62915eSRuslan Bukin 	if ((len = OF_getproplen(node, field2)) > 0) {
131*8b62915eSRuslan Bukin 		OF_getencprop(node, field2, dts_value, len);
132*8b62915eSRuslan Bukin 		val |= PS_TO_REG(dts_value[0]) << 4;
133*8b62915eSRuslan Bukin 	}
134*8b62915eSRuslan Bukin 
135*8b62915eSRuslan Bukin 	if ((len = OF_getproplen(node, field3)) > 0) {
136*8b62915eSRuslan Bukin 		OF_getencprop(node, field3, dts_value, len);
137*8b62915eSRuslan Bukin 		val |= PS_TO_REG(dts_value[0]) << 8;
138*8b62915eSRuslan Bukin 	}
139*8b62915eSRuslan Bukin 
140*8b62915eSRuslan Bukin 	if ((len = OF_getproplen(node, field4)) > 0) {
141*8b62915eSRuslan Bukin 		OF_getencprop(node, field4, dts_value, len);
142*8b62915eSRuslan Bukin 		val |= PS_TO_REG(dts_value[0]) << 12;
143*8b62915eSRuslan Bukin 	}
144*8b62915eSRuslan Bukin 
145*8b62915eSRuslan Bukin 	micphy_write(sc, reg, val);
146*8b62915eSRuslan Bukin 
147*8b62915eSRuslan Bukin 	return (0);
148*8b62915eSRuslan Bukin }
149*8b62915eSRuslan Bukin 
150*8b62915eSRuslan Bukin static int
151*8b62915eSRuslan Bukin micphy_probe(device_t dev)
152*8b62915eSRuslan Bukin {
153*8b62915eSRuslan Bukin 
154*8b62915eSRuslan Bukin 	return (mii_phy_dev_probe(dev, micphys, BUS_PROBE_DEFAULT));
155*8b62915eSRuslan Bukin }
156*8b62915eSRuslan Bukin 
157*8b62915eSRuslan Bukin static int
158*8b62915eSRuslan Bukin micphy_attach(device_t dev)
159*8b62915eSRuslan Bukin {
160*8b62915eSRuslan Bukin 	struct mii_softc *sc;
161*8b62915eSRuslan Bukin 	phandle_t node;
162*8b62915eSRuslan Bukin 	device_t miibus;
163*8b62915eSRuslan Bukin 	device_t parent;
164*8b62915eSRuslan Bukin 
165*8b62915eSRuslan Bukin 	sc = device_get_softc(dev);
166*8b62915eSRuslan Bukin 
167*8b62915eSRuslan Bukin 	mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &micphy_funcs, 1);
168*8b62915eSRuslan Bukin 	mii_phy_setmedia(sc);
169*8b62915eSRuslan Bukin 
170*8b62915eSRuslan Bukin 	miibus = device_get_parent(dev);
171*8b62915eSRuslan Bukin 	parent = device_get_parent(miibus);
172*8b62915eSRuslan Bukin 
173*8b62915eSRuslan Bukin 	if ((node = ofw_bus_get_node(parent)) == -1)
174*8b62915eSRuslan Bukin 		return (ENXIO);
175*8b62915eSRuslan Bukin 
176*8b62915eSRuslan Bukin 	ksz9021_load_values(sc, node, MII_KSZPHY_CLK_CONTROL_PAD_SKEW,
177*8b62915eSRuslan Bukin 			"txen-skew-ps", "txc-skew-ps",
178*8b62915eSRuslan Bukin 			"rxdv-skew-ps", "rxc-skew-ps");
179*8b62915eSRuslan Bukin 
180*8b62915eSRuslan Bukin 	ksz9021_load_values(sc, node, MII_KSZPHY_RX_DATA_PAD_SKEW,
181*8b62915eSRuslan Bukin 			"rxd0-skew-ps", "rxd1-skew-ps",
182*8b62915eSRuslan Bukin 			"rxd2-skew-ps", "rxd3-skew-ps");
183*8b62915eSRuslan Bukin 
184*8b62915eSRuslan Bukin 	ksz9021_load_values(sc, node, MII_KSZPHY_TX_DATA_PAD_SKEW,
185*8b62915eSRuslan Bukin 			"txd0-skew-ps", "txd1-skew-ps",
186*8b62915eSRuslan Bukin 			"txd2-skew-ps", "txd3-skew-ps");
187*8b62915eSRuslan Bukin 
188*8b62915eSRuslan Bukin 	return (0);
189*8b62915eSRuslan Bukin }
190*8b62915eSRuslan Bukin 
191*8b62915eSRuslan Bukin static int
192*8b62915eSRuslan Bukin micphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
193*8b62915eSRuslan Bukin {
194*8b62915eSRuslan Bukin 
195*8b62915eSRuslan Bukin 	switch (cmd) {
196*8b62915eSRuslan Bukin 	case MII_POLLSTAT:
197*8b62915eSRuslan Bukin 		break;
198*8b62915eSRuslan Bukin 
199*8b62915eSRuslan Bukin 	case MII_MEDIACHG:
200*8b62915eSRuslan Bukin 		mii_phy_setmedia(sc);
201*8b62915eSRuslan Bukin 		break;
202*8b62915eSRuslan Bukin 
203*8b62915eSRuslan Bukin 	case MII_TICK:
204*8b62915eSRuslan Bukin 		if (mii_phy_tick(sc) == EJUSTRETURN)
205*8b62915eSRuslan Bukin 			return (0);
206*8b62915eSRuslan Bukin 		break;
207*8b62915eSRuslan Bukin 	}
208*8b62915eSRuslan Bukin 
209*8b62915eSRuslan Bukin 	/* Update the media status. */
210*8b62915eSRuslan Bukin 	PHY_STATUS(sc);
211*8b62915eSRuslan Bukin 
212*8b62915eSRuslan Bukin 	/* Callback if something changed. */
213*8b62915eSRuslan Bukin 	mii_phy_update(sc, cmd);
214*8b62915eSRuslan Bukin 	return (0);
215*8b62915eSRuslan Bukin }
216