xref: /freebsd/sys/dev/dpaa/fman_mdio.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
147cabd04SJustin Hibbits /*-
247cabd04SJustin Hibbits  * Copyright (c) 2016 Justin Hibbits
347cabd04SJustin Hibbits  * All rights reserved.
447cabd04SJustin Hibbits  *
547cabd04SJustin Hibbits  * Redistribution and use in source and binary forms, with or without
647cabd04SJustin Hibbits  * modification, are permitted provided that the following conditions
747cabd04SJustin Hibbits  * are met:
847cabd04SJustin Hibbits  * 1. Redistributions of source code must retain the above copyright
947cabd04SJustin Hibbits  *    notice, this list of conditions and the following disclaimer.
1047cabd04SJustin Hibbits  * 2. Redistributions in binary form must reproduce the above copyright
1147cabd04SJustin Hibbits  *    notice, this list of conditions and the following disclaimer in the
1247cabd04SJustin Hibbits  *    documentation and/or other materials provided with the distribution.
1347cabd04SJustin Hibbits  *
1447cabd04SJustin Hibbits  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1547cabd04SJustin Hibbits  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1647cabd04SJustin Hibbits  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1747cabd04SJustin Hibbits  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1847cabd04SJustin Hibbits  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1947cabd04SJustin Hibbits  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2047cabd04SJustin Hibbits  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2147cabd04SJustin Hibbits  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2247cabd04SJustin Hibbits  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2347cabd04SJustin Hibbits  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2447cabd04SJustin Hibbits  * SUCH DAMAGE.
2547cabd04SJustin Hibbits  */
2647cabd04SJustin Hibbits 
2747cabd04SJustin Hibbits #include <sys/param.h>
2847cabd04SJustin Hibbits #include <sys/systm.h>
2947cabd04SJustin Hibbits #include <sys/kernel.h>
3047cabd04SJustin Hibbits #include <sys/bus.h>
3147cabd04SJustin Hibbits #include <sys/module.h>
3247cabd04SJustin Hibbits #include <sys/mutex.h>
3347cabd04SJustin Hibbits #include <sys/resource.h>
3447cabd04SJustin Hibbits #include <sys/socket.h>
3547cabd04SJustin Hibbits 
3647cabd04SJustin Hibbits #include <machine/bus.h>
3747cabd04SJustin Hibbits 
3847cabd04SJustin Hibbits #include <net/if.h>
3947cabd04SJustin Hibbits #include <net/if_media.h>
4047cabd04SJustin Hibbits #include <net/if_types.h>
4147cabd04SJustin Hibbits #include <net/if_var.h>
4247cabd04SJustin Hibbits 
4347cabd04SJustin Hibbits #include <dev/mii/mii.h>
4447cabd04SJustin Hibbits #include <dev/mii/miivar.h>
4547cabd04SJustin Hibbits 
4647cabd04SJustin Hibbits #include <dev/ofw/ofw_bus.h>
4747cabd04SJustin Hibbits #include <dev/ofw/ofw_bus_subr.h>
4847cabd04SJustin Hibbits 
4947cabd04SJustin Hibbits #include <contrib/ncsw/inc/Peripherals/fm_ext.h>
5047cabd04SJustin Hibbits 
5147cabd04SJustin Hibbits #include "fman.h"
5247cabd04SJustin Hibbits #include "miibus_if.h"
5347cabd04SJustin Hibbits 
5447cabd04SJustin Hibbits #define MDIO_LOCK()	mtx_lock(&sc->sc_lock)
5547cabd04SJustin Hibbits #define MDIO_UNLOCK()	mtx_unlock(&sc->sc_lock)
5647cabd04SJustin Hibbits #define	MDIO_WRITE4(sc,r,v) \
5747cabd04SJustin Hibbits 	bus_space_write_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r, v)
5847cabd04SJustin Hibbits #define	MDIO_READ4(sc, r) \
5947cabd04SJustin Hibbits 	bus_space_read_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r)
6047cabd04SJustin Hibbits 
6147cabd04SJustin Hibbits #define	MDIO_MIIMCFG	0x0
6247cabd04SJustin Hibbits #define	MDIO_MIIMCOM	0x4
6347cabd04SJustin Hibbits #define	  MIIMCOM_SCAN_CYCLE	  0x00000002
6447cabd04SJustin Hibbits #define	  MIIMCOM_READ_CYCLE	  0x00000001
6547cabd04SJustin Hibbits #define	MDIO_MIIMADD	0x8
6647cabd04SJustin Hibbits #define	MDIO_MIIMCON	0xc
6747cabd04SJustin Hibbits #define	MDIO_MIIMSTAT	0x10
6847cabd04SJustin Hibbits #define	MDIO_MIIMIND	0x14
6947cabd04SJustin Hibbits #define	  MIIMIND_BUSY	  0x1
7047cabd04SJustin Hibbits 
7147cabd04SJustin Hibbits static int pqmdio_fdt_probe(device_t dev);
7247cabd04SJustin Hibbits static int pqmdio_fdt_attach(device_t dev);
7347cabd04SJustin Hibbits static int pqmdio_detach(device_t dev);
7447cabd04SJustin Hibbits static int pqmdio_miibus_readreg(device_t dev, int phy, int reg);
7547cabd04SJustin Hibbits static int pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value);
7647cabd04SJustin Hibbits 
7747cabd04SJustin Hibbits struct pqmdio_softc {
7847cabd04SJustin Hibbits 	struct mtx sc_lock;
7947cabd04SJustin Hibbits 	bus_space_handle_t sc_handle;
8047cabd04SJustin Hibbits 	int sc_offset;
8147cabd04SJustin Hibbits };
8247cabd04SJustin Hibbits 
8347cabd04SJustin Hibbits static device_method_t pqmdio_methods[] = {
8447cabd04SJustin Hibbits 	/* Device interface */
8547cabd04SJustin Hibbits 	DEVMETHOD(device_probe,		pqmdio_fdt_probe),
8647cabd04SJustin Hibbits 	DEVMETHOD(device_attach,	pqmdio_fdt_attach),
8747cabd04SJustin Hibbits 	DEVMETHOD(device_detach,	pqmdio_detach),
8847cabd04SJustin Hibbits 
8947cabd04SJustin Hibbits 	/* MII interface */
9047cabd04SJustin Hibbits 	DEVMETHOD(miibus_readreg,	pqmdio_miibus_readreg),
9147cabd04SJustin Hibbits 	DEVMETHOD(miibus_writereg,	pqmdio_miibus_writereg),
9247cabd04SJustin Hibbits 
9347cabd04SJustin Hibbits 	{ 0, 0 }
9447cabd04SJustin Hibbits };
9547cabd04SJustin Hibbits 
9647cabd04SJustin Hibbits static struct ofw_compat_data mdio_compat_data[] = {
9747cabd04SJustin Hibbits 	{"fsl,fman-mdio", 0},
9847cabd04SJustin Hibbits 	{NULL, 0}
9947cabd04SJustin Hibbits };
10047cabd04SJustin Hibbits 
10147cabd04SJustin Hibbits static driver_t pqmdio_driver = {
10247cabd04SJustin Hibbits 	"pq_mdio",
10347cabd04SJustin Hibbits 	pqmdio_methods,
10447cabd04SJustin Hibbits 	sizeof(struct pqmdio_softc),
10547cabd04SJustin Hibbits };
10647cabd04SJustin Hibbits 
10747cabd04SJustin Hibbits static int
pqmdio_fdt_probe(device_t dev)10847cabd04SJustin Hibbits pqmdio_fdt_probe(device_t dev)
10947cabd04SJustin Hibbits {
11047cabd04SJustin Hibbits 
11147cabd04SJustin Hibbits 	if (!ofw_bus_status_okay(dev))
11247cabd04SJustin Hibbits 		return (ENXIO);
11347cabd04SJustin Hibbits 
11447cabd04SJustin Hibbits 	if (!ofw_bus_search_compatible(dev, mdio_compat_data)->ocd_str)
11547cabd04SJustin Hibbits 		return (ENXIO);
11647cabd04SJustin Hibbits 
11747cabd04SJustin Hibbits 	device_set_desc(dev, "Freescale QorIQ MDIO");
11847cabd04SJustin Hibbits 
11947cabd04SJustin Hibbits 	return (BUS_PROBE_DEFAULT);
12047cabd04SJustin Hibbits }
12147cabd04SJustin Hibbits 
12247cabd04SJustin Hibbits static int
pqmdio_fdt_attach(device_t dev)12347cabd04SJustin Hibbits pqmdio_fdt_attach(device_t dev)
12447cabd04SJustin Hibbits {
12547cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
12647cabd04SJustin Hibbits 	rman_res_t start, count;
12747cabd04SJustin Hibbits 
12847cabd04SJustin Hibbits 	sc = device_get_softc(dev);
12947cabd04SJustin Hibbits 
1301c41f28fSJustin Hibbits 	fman_get_bushandle(device_get_parent(dev), &sc->sc_handle);
13147cabd04SJustin Hibbits 	bus_get_resource(dev, SYS_RES_MEMORY, 0, &start, &count);
13247cabd04SJustin Hibbits 	sc->sc_offset = start;
13347cabd04SJustin Hibbits 
134*82abe70fSJustin Hibbits 	OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
135*82abe70fSJustin Hibbits 
13647cabd04SJustin Hibbits 	mtx_init(&sc->sc_lock, device_get_nameunit(dev), "QorIQ MDIO lock",
13747cabd04SJustin Hibbits 	    MTX_DEF);
13847cabd04SJustin Hibbits 
13947cabd04SJustin Hibbits 	return (0);
14047cabd04SJustin Hibbits }
14147cabd04SJustin Hibbits 
14247cabd04SJustin Hibbits static int
pqmdio_detach(device_t dev)14347cabd04SJustin Hibbits pqmdio_detach(device_t dev)
14447cabd04SJustin Hibbits {
14547cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
14647cabd04SJustin Hibbits 
14747cabd04SJustin Hibbits 	sc = device_get_softc(dev);
14847cabd04SJustin Hibbits 
14947cabd04SJustin Hibbits 	mtx_destroy(&sc->sc_lock);
15047cabd04SJustin Hibbits 
15147cabd04SJustin Hibbits 	return (0);
15247cabd04SJustin Hibbits }
15347cabd04SJustin Hibbits 
15447cabd04SJustin Hibbits int
pqmdio_miibus_readreg(device_t dev,int phy,int reg)15547cabd04SJustin Hibbits pqmdio_miibus_readreg(device_t dev, int phy, int reg)
15647cabd04SJustin Hibbits {
15747cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
15847cabd04SJustin Hibbits 	int                  rv;
15947cabd04SJustin Hibbits 
16047cabd04SJustin Hibbits 	sc = device_get_softc(dev);
16147cabd04SJustin Hibbits 
16247cabd04SJustin Hibbits 	MDIO_LOCK();
16347cabd04SJustin Hibbits 
16447cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMADD, (phy << 8) | reg);
16547cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCOM, MIIMCOM_READ_CYCLE);
16647cabd04SJustin Hibbits 
16747cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCOM);
16847cabd04SJustin Hibbits 
16947cabd04SJustin Hibbits 	while ((MDIO_READ4(sc, MDIO_MIIMIND)) & MIIMIND_BUSY)
17047cabd04SJustin Hibbits 		;
17147cabd04SJustin Hibbits 
17247cabd04SJustin Hibbits 	rv = MDIO_READ4(sc, MDIO_MIIMSTAT);
17347cabd04SJustin Hibbits 
17447cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCOM, 0);
17547cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCOM);
17647cabd04SJustin Hibbits 	MDIO_UNLOCK();
17747cabd04SJustin Hibbits 
17847cabd04SJustin Hibbits 	return (rv);
17947cabd04SJustin Hibbits }
18047cabd04SJustin Hibbits 
18147cabd04SJustin Hibbits int
pqmdio_miibus_writereg(device_t dev,int phy,int reg,int value)18247cabd04SJustin Hibbits pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value)
18347cabd04SJustin Hibbits {
18447cabd04SJustin Hibbits 	struct pqmdio_softc *sc;
18547cabd04SJustin Hibbits 
18647cabd04SJustin Hibbits 	sc = device_get_softc(dev);
18747cabd04SJustin Hibbits 
18847cabd04SJustin Hibbits 	MDIO_LOCK();
18947cabd04SJustin Hibbits 	/* Stop the MII management read cycle */
19047cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCOM, 0);
19147cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCOM);
19247cabd04SJustin Hibbits 
19347cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMADD, (phy << 8) | reg);
19447cabd04SJustin Hibbits 
19547cabd04SJustin Hibbits 	MDIO_WRITE4(sc, MDIO_MIIMCON, value);
19647cabd04SJustin Hibbits 	MDIO_READ4(sc, MDIO_MIIMCON);
19747cabd04SJustin Hibbits 
19847cabd04SJustin Hibbits 	/* Wait till MII management write is complete */
19947cabd04SJustin Hibbits 	while ((MDIO_READ4(sc, MDIO_MIIMIND)) & MIIMIND_BUSY)
20047cabd04SJustin Hibbits 		;
20147cabd04SJustin Hibbits 	MDIO_UNLOCK();
20247cabd04SJustin Hibbits 
20347cabd04SJustin Hibbits 	return (0);
20447cabd04SJustin Hibbits }
20547cabd04SJustin Hibbits 
206fae4c649SJustin Hibbits EARLY_DRIVER_MODULE(pqmdio, fman, pqmdio_driver, 0, 0,
207598e073fSJustin Hibbits     BUS_PASS_SUPPORTDEV);
2083e38757dSJohn Baldwin DRIVER_MODULE(miibus, pqmdio, miibus_driver, 0, 0);
20947cabd04SJustin Hibbits MODULE_DEPEND(pqmdio, miibus, 1, 1, 1);
21047cabd04SJustin Hibbits 
211