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