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