xref: /freebsd/sys/dev/dpaa/fman_mdio.c (revision 47cabd046d160d7c790185955ceab3e1ef432afa)
1*47cabd04SJustin Hibbits /*-
2*47cabd04SJustin Hibbits  * Copyright (c) 2016 Justin Hibbits
3*47cabd04SJustin Hibbits  * All rights reserved.
4*47cabd04SJustin Hibbits  *
5*47cabd04SJustin Hibbits  * Redistribution and use in source and binary forms, with or without
6*47cabd04SJustin Hibbits  * modification, are permitted provided that the following conditions
7*47cabd04SJustin Hibbits  * are met:
8*47cabd04SJustin Hibbits  * 1. Redistributions of source code must retain the above copyright
9*47cabd04SJustin Hibbits  *    notice, this list of conditions and the following disclaimer.
10*47cabd04SJustin Hibbits  * 2. Redistributions in binary form must reproduce the above copyright
11*47cabd04SJustin Hibbits  *    notice, this list of conditions and the following disclaimer in the
12*47cabd04SJustin Hibbits  *    documentation and/or other materials provided with the distribution.
13*47cabd04SJustin Hibbits  *
14*47cabd04SJustin Hibbits  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*47cabd04SJustin Hibbits  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*47cabd04SJustin Hibbits  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*47cabd04SJustin Hibbits  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*47cabd04SJustin Hibbits  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*47cabd04SJustin Hibbits  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*47cabd04SJustin Hibbits  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*47cabd04SJustin Hibbits  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*47cabd04SJustin Hibbits  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*47cabd04SJustin Hibbits  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*47cabd04SJustin Hibbits  * SUCH DAMAGE.
25*47cabd04SJustin Hibbits  */
26*47cabd04SJustin Hibbits 
27*47cabd04SJustin Hibbits #include <sys/cdefs.h>
28*47cabd04SJustin Hibbits __FBSDID("$FreeBSD$");
29*47cabd04SJustin Hibbits 
30*47cabd04SJustin Hibbits #include <sys/param.h>
31*47cabd04SJustin Hibbits #include <sys/systm.h>
32*47cabd04SJustin Hibbits #include <sys/kernel.h>
33*47cabd04SJustin Hibbits #include <sys/bus.h>
34*47cabd04SJustin Hibbits #include <sys/module.h>
35*47cabd04SJustin Hibbits #include <sys/mutex.h>
36*47cabd04SJustin Hibbits #include <sys/resource.h>
37*47cabd04SJustin Hibbits #include <sys/socket.h>
38*47cabd04SJustin Hibbits 
39*47cabd04SJustin Hibbits #include <machine/bus.h>
40*47cabd04SJustin Hibbits 
41*47cabd04SJustin Hibbits #include <net/if.h>
42*47cabd04SJustin Hibbits #include <net/if_media.h>
43*47cabd04SJustin Hibbits #include <net/if_types.h>
44*47cabd04SJustin Hibbits #include <net/if_var.h>
45*47cabd04SJustin Hibbits 
46*47cabd04SJustin Hibbits #include <dev/mii/mii.h>
47*47cabd04SJustin Hibbits #include <dev/mii/miivar.h>
48*47cabd04SJustin Hibbits 
49*47cabd04SJustin Hibbits #include <dev/ofw/ofw_bus.h>
50*47cabd04SJustin Hibbits #include <dev/ofw/ofw_bus_subr.h>
51*47cabd04SJustin Hibbits 
52*47cabd04SJustin Hibbits #include <contrib/ncsw/inc/Peripherals/fm_ext.h>
53*47cabd04SJustin Hibbits 
54*47cabd04SJustin Hibbits #include "fman.h"
55*47cabd04SJustin Hibbits #include "miibus_if.h"
56*47cabd04SJustin Hibbits 
57*47cabd04SJustin Hibbits #define MDIO_LOCK()	mtx_lock(&sc->sc_lock)
58*47cabd04SJustin Hibbits #define MDIO_UNLOCK()	mtx_unlock(&sc->sc_lock)
59*47cabd04SJustin Hibbits #define	MDIO_WRITE4(sc,r,v) \
60*47cabd04SJustin Hibbits 	bus_space_write_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r, v)
61*47cabd04SJustin Hibbits #define	MDIO_READ4(sc, r) \
62*47cabd04SJustin Hibbits 	bus_space_read_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r)
63*47cabd04SJustin Hibbits 
64*47cabd04SJustin Hibbits #define	MDIO_MIIMCFG	0x0
65*47cabd04SJustin Hibbits #define	MDIO_MIIMCOM	0x4
66*47cabd04SJustin Hibbits #define	  MIIMCOM_SCAN_CYCLE	  0x00000002
67*47cabd04SJustin Hibbits #define	  MIIMCOM_READ_CYCLE	  0x00000001
68*47cabd04SJustin Hibbits #define	MDIO_MIIMADD	0x8
69*47cabd04SJustin Hibbits #define	MDIO_MIIMCON	0xc
70*47cabd04SJustin Hibbits #define	MDIO_MIIMSTAT	0x10
71*47cabd04SJustin Hibbits #define	MDIO_MIIMIND	0x14
72*47cabd04SJustin Hibbits #define	  MIIMIND_BUSY	  0x1
73*47cabd04SJustin Hibbits 
74*47cabd04SJustin Hibbits static int pqmdio_fdt_probe(device_t dev);
75*47cabd04SJustin Hibbits static int pqmdio_fdt_attach(device_t dev);
76*47cabd04SJustin Hibbits static int pqmdio_detach(device_t dev);
77*47cabd04SJustin Hibbits static int pqmdio_miibus_readreg(device_t dev, int phy, int reg);
78*47cabd04SJustin Hibbits static int pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value);
79*47cabd04SJustin Hibbits 
80*47cabd04SJustin Hibbits struct pqmdio_softc {
81*47cabd04SJustin Hibbits 	struct mtx sc_lock;
82*47cabd04SJustin Hibbits 	bus_space_handle_t sc_handle;
83*47cabd04SJustin Hibbits 	int sc_offset;
84*47cabd04SJustin Hibbits };
85*47cabd04SJustin Hibbits 
86*47cabd04SJustin Hibbits static device_method_t pqmdio_methods[] = {
87*47cabd04SJustin Hibbits 	/* Device interface */
88*47cabd04SJustin Hibbits 	DEVMETHOD(device_probe,		pqmdio_fdt_probe),
89*47cabd04SJustin Hibbits 	DEVMETHOD(device_attach,	pqmdio_fdt_attach),
90*47cabd04SJustin Hibbits 	DEVMETHOD(device_detach,	pqmdio_detach),
91*47cabd04SJustin Hibbits 
92*47cabd04SJustin Hibbits 	/* MII interface */
93*47cabd04SJustin Hibbits 	DEVMETHOD(miibus_readreg,	pqmdio_miibus_readreg),
94*47cabd04SJustin Hibbits 	DEVMETHOD(miibus_writereg,	pqmdio_miibus_writereg),
95*47cabd04SJustin Hibbits 
96*47cabd04SJustin Hibbits 	{ 0, 0 }
97*47cabd04SJustin Hibbits };
98*47cabd04SJustin Hibbits 
99*47cabd04SJustin Hibbits static struct ofw_compat_data mdio_compat_data[] = {
100*47cabd04SJustin Hibbits 	{"fsl,fman-mdio", 0},
101*47cabd04SJustin Hibbits 	{NULL, 0}
102*47cabd04SJustin Hibbits };
103*47cabd04SJustin Hibbits 
104*47cabd04SJustin Hibbits static driver_t pqmdio_driver = {
105*47cabd04SJustin Hibbits 	"pq_mdio",
106*47cabd04SJustin Hibbits 	pqmdio_methods,
107*47cabd04SJustin Hibbits 	sizeof(struct pqmdio_softc),
108*47cabd04SJustin Hibbits };
109*47cabd04SJustin Hibbits 
110*47cabd04SJustin Hibbits static int
111*47cabd04SJustin Hibbits pqmdio_fdt_probe(device_t dev)
112*47cabd04SJustin Hibbits {
113*47cabd04SJustin Hibbits 
114*47cabd04SJustin Hibbits 	if (!ofw_bus_status_okay(dev))
115*47cabd04SJustin Hibbits 		return (ENXIO);
116*47cabd04SJustin Hibbits 
117*47cabd04SJustin Hibbits 	if (!ofw_bus_search_compatible(dev, mdio_compat_data)->ocd_str)
118*47cabd04SJustin Hibbits 		return (ENXIO);
119*47cabd04SJustin Hibbits 
120*47cabd04SJustin Hibbits 	device_set_desc(dev, "Freescale QorIQ MDIO");
121*47cabd04SJustin Hibbits 
122*47cabd04SJustin Hibbits 	return (BUS_PROBE_DEFAULT);
123*47cabd04SJustin Hibbits }
124*47cabd04SJustin Hibbits 
125*47cabd04SJustin Hibbits static int
126*47cabd04SJustin Hibbits pqmdio_fdt_attach(device_t dev)
127*47cabd04SJustin Hibbits {
128*47cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
129*47cabd04SJustin Hibbits 	rman_res_t start, count;
130*47cabd04SJustin Hibbits 
131*47cabd04SJustin Hibbits 	sc = device_get_softc(dev);
132*47cabd04SJustin Hibbits 
133*47cabd04SJustin Hibbits 	fman_get_bushandle(&sc->sc_handle);
134*47cabd04SJustin Hibbits 	bus_get_resource(dev, SYS_RES_MEMORY, 0, &start, &count);
135*47cabd04SJustin Hibbits 	sc->sc_offset = start;
136*47cabd04SJustin Hibbits 
137*47cabd04SJustin Hibbits 	mtx_init(&sc->sc_lock, device_get_nameunit(dev), "QorIQ MDIO lock",
138*47cabd04SJustin Hibbits 	    MTX_DEF);
139*47cabd04SJustin Hibbits 
140*47cabd04SJustin Hibbits 	return (0);
141*47cabd04SJustin Hibbits }
142*47cabd04SJustin Hibbits 
143*47cabd04SJustin Hibbits static int
144*47cabd04SJustin Hibbits pqmdio_detach(device_t dev)
145*47cabd04SJustin Hibbits {
146*47cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
147*47cabd04SJustin Hibbits 
148*47cabd04SJustin Hibbits 	sc = device_get_softc(dev);
149*47cabd04SJustin Hibbits 
150*47cabd04SJustin Hibbits 	mtx_destroy(&sc->sc_lock);
151*47cabd04SJustin Hibbits 
152*47cabd04SJustin Hibbits 	return (0);
153*47cabd04SJustin Hibbits }
154*47cabd04SJustin Hibbits 
155*47cabd04SJustin Hibbits int
156*47cabd04SJustin Hibbits pqmdio_miibus_readreg(device_t dev, int phy, int reg)
157*47cabd04SJustin Hibbits {
158*47cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
159*47cabd04SJustin Hibbits 	int                  rv;
160*47cabd04SJustin Hibbits 
161*47cabd04SJustin Hibbits 	sc = device_get_softc(dev);
162*47cabd04SJustin Hibbits 
163*47cabd04SJustin Hibbits 	MDIO_LOCK();
164*47cabd04SJustin Hibbits 
165*47cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMADD, (phy << 8) | reg);
166*47cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCOM, MIIMCOM_READ_CYCLE);
167*47cabd04SJustin Hibbits 
168*47cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCOM);
169*47cabd04SJustin Hibbits 
170*47cabd04SJustin Hibbits 	while ((MDIO_READ4(sc, MDIO_MIIMIND)) & MIIMIND_BUSY)
171*47cabd04SJustin Hibbits 		;
172*47cabd04SJustin Hibbits 
173*47cabd04SJustin Hibbits 	rv = MDIO_READ4(sc, MDIO_MIIMSTAT);
174*47cabd04SJustin Hibbits 
175*47cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCOM, 0);
176*47cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCOM);
177*47cabd04SJustin Hibbits 	MDIO_UNLOCK();
178*47cabd04SJustin Hibbits 
179*47cabd04SJustin Hibbits 	return (rv);
180*47cabd04SJustin Hibbits }
181*47cabd04SJustin Hibbits 
182*47cabd04SJustin Hibbits int
183*47cabd04SJustin Hibbits pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value)
184*47cabd04SJustin Hibbits {
185*47cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
186*47cabd04SJustin Hibbits 
187*47cabd04SJustin Hibbits 	sc = device_get_softc(dev);
188*47cabd04SJustin Hibbits 
189*47cabd04SJustin Hibbits 	MDIO_LOCK();
190*47cabd04SJustin Hibbits 	/* Stop the MII management read cycle */
191*47cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCOM, 0);
192*47cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCOM);
193*47cabd04SJustin Hibbits 
194*47cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMADD, (phy << 8) | reg);
195*47cabd04SJustin Hibbits 
196*47cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCON, value);
197*47cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCON);
198*47cabd04SJustin Hibbits 
199*47cabd04SJustin Hibbits 	/* Wait till MII management write is complete */
200*47cabd04SJustin Hibbits 	while ((MDIO_READ4(sc, MDIO_MIIMIND)) & MIIMIND_BUSY)
201*47cabd04SJustin Hibbits 		;
202*47cabd04SJustin Hibbits 	MDIO_UNLOCK();
203*47cabd04SJustin Hibbits 
204*47cabd04SJustin Hibbits 	return (0);
205*47cabd04SJustin Hibbits }
206*47cabd04SJustin Hibbits 
207*47cabd04SJustin Hibbits static devclass_t pqmdio_devclass;
208*47cabd04SJustin Hibbits DRIVER_MODULE(pqmdio, fman, pqmdio_driver, pqmdio_devclass, 0, 0);
209*47cabd04SJustin Hibbits DRIVER_MODULE(miibus, pqmdio, miibus_driver, miibus_devclass, 0, 0);
210*47cabd04SJustin Hibbits MODULE_DEPEND(pqmdio, miibus, 1, 1, 1);
211*47cabd04SJustin Hibbits 
212