The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/dpaa2/memac_mdio_common.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause
    3  *
    4  * Copyright © 2021-2022 Bjoern A. Zeeb
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/bus.h>
   34 #include <sys/rman.h>
   35 #include <sys/endian.h>
   36 #include <sys/socket.h>
   37 
   38 #include <machine/bus.h>
   39 #include <machine/resource.h>
   40 
   41 #include <net/if.h>
   42 #include <net/if_var.h>
   43 #include <net/if_media.h>
   44 
   45 #include <dev/mii/mii.h>
   46 #include <dev/mii/miivar.h>
   47 
   48 #include "memac_mdio.h"
   49 #include "miibus_if.h"
   50 
   51 /* #define      MEMAC_MDIO_DEBUG */
   52 
   53 /* -------------------------------------------------------------------------- */
   54 
   55 int
   56 memacphy_miibus_readreg(device_t dev, int phy, int reg)
   57 {
   58 
   59         return (MIIBUS_READREG(device_get_parent(dev), phy, reg));
   60 }
   61 
   62 int
   63 memacphy_miibus_writereg(device_t dev, int phy, int reg, int data)
   64 {
   65 
   66         return (MIIBUS_WRITEREG(device_get_parent(dev), phy, reg, data));
   67 }
   68 
   69 void
   70 memacphy_miibus_statchg(struct memacphy_softc_common *sc)
   71 {
   72 
   73         if (sc->dpnidev != NULL)
   74                 MIIBUS_STATCHG(sc->dpnidev);
   75 }
   76 
   77 int
   78 memacphy_set_ni_dev(struct memacphy_softc_common *sc, device_t nidev)
   79 {
   80 
   81         if (nidev == NULL)
   82                 return (EINVAL);
   83 
   84 #if defined(MEMAC_MDIO_DEBUG)
   85         if (bootverbose)
   86                 device_printf(sc->dev, "setting nidev %p (%s)\n",
   87                     nidev, device_get_nameunit(nidev));
   88 #endif
   89 
   90         if (sc->dpnidev != NULL)
   91                 return (EBUSY);
   92 
   93         sc->dpnidev = nidev;
   94         return (0);
   95 }
   96 
   97 int
   98 memacphy_get_phy_loc(struct memacphy_softc_common *sc, int *phy_loc)
   99 {
  100         int error;
  101 
  102         if (phy_loc == NULL)
  103                 return (EINVAL);
  104 
  105         if (sc->phy == -1) {
  106                 *phy_loc = MII_PHY_ANY;
  107                 error = ENODEV;
  108         } else {
  109                 *phy_loc = sc->phy;
  110                 error = 0;
  111         }
  112 
  113 #if defined(MEMAC_MDIO_DEBUG)
  114         if (bootverbose)
  115                 device_printf(sc->dev, "returning phy_loc %d, error %d\n",
  116                     *phy_loc, error);
  117 #endif
  118 
  119         return (error);
  120 }
  121 
  122 /* -------------------------------------------------------------------------- */
  123 
  124 /*
  125  * MDIO Ethernet Management Interface Registers (internal PCS MDIO PHY)
  126  * 0x0030       MDIO Configuration Register (MDIO_CFG)
  127  * 0x0034       MDIO Control Register (MDIO_CTL)
  128  * 0x0038       MDIO Data Register (MDIO_DATA)
  129  * 0x003c       MDIO Register Address Register (MDIO_ADDR)
  130  *
  131  * External MDIO interfaces
  132  * 0x0030       External MDIO Configuration Register (EMDIO_CFG)
  133  * 0x0034       External MDIO Control Register (EMDIO_CTL)
  134  * 0x0038       External MDIO Data Register (EMDIO_DATA)
  135  * 0x003c       External MDIO Register Address Register (EMDIO_ADDR)
  136  */
  137 #define MDIO_CFG                        0x00030
  138 #define MDIO_CFG_MDIO_RD_ER             (1 << 1)
  139 #define MDIO_CFG_ENC45                  (1 << 6)
  140 #define MDIO_CFG_BUSY                   (1 << 31)
  141 #define MDIO_CTL                        0x00034
  142 #define MDIO_CTL_READ                   (1 << 15)
  143 #define MDIO_CTL_PORT_ADDR(_x)          (((_x) & 0x1f) << 5)
  144 #define MDIO_CTL_DEV_ADDR(_x)           ((_x) & 0x1f)
  145 #define MDIO_DATA                       0x00038
  146 #define MDIO_ADDR                       0x0003c
  147 
  148 static uint32_t
  149 memac_read_4(struct memac_mdio_softc_common *sc, uint32_t reg)
  150 {
  151         uint32_t v, r;
  152 
  153         v = bus_read_4(sc->mem_res, reg);
  154         if (sc->is_little_endian)
  155                 r = le32toh(v);
  156         else
  157                 r = be32toh(v);
  158 
  159         return (r);
  160 }
  161 
  162 static void
  163 memac_write_4(struct memac_mdio_softc_common *sc, uint32_t reg, uint32_t val)
  164 {
  165         uint32_t v;
  166 
  167         if (sc->is_little_endian)
  168                 v = htole32(val);
  169         else
  170                 v = htobe32(val);
  171         bus_write_4(sc->mem_res, reg, v);
  172 }
  173 
  174 static uint32_t
  175 memac_miibus_wait_no_busy(struct memac_mdio_softc_common *sc)
  176 {
  177         uint32_t count, val;
  178 
  179         for (count = 1000; count > 0; count--) {
  180                 val = memac_read_4(sc, MDIO_CFG);
  181                 if ((val & MDIO_CFG_BUSY) == 0)
  182                         break;
  183                 DELAY(1);
  184         }
  185 
  186         if (count == 0)
  187                 return (0xffff);
  188 
  189         return (0);
  190 }
  191 
  192 int
  193 memac_miibus_readreg(struct memac_mdio_softc_common *sc, int phy, int reg)
  194 {
  195         uint32_t cfg, ctl, val;
  196 
  197         /* Set proper Clause 45 mode. */
  198         cfg = memac_read_4(sc, MDIO_CFG);
  199         /* XXX 45 support? */
  200         cfg &= ~MDIO_CFG_ENC45; /* Use Clause 22 */
  201         memac_write_4(sc, MDIO_CFG, cfg);
  202 
  203         val = memac_miibus_wait_no_busy(sc);
  204         if (val != 0)
  205                 return (0xffff);
  206 
  207         /* To whom do we want to talk to.. */
  208         ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(reg);
  209         /* XXX do we need two writes for this to work reliably? */
  210         memac_write_4(sc, MDIO_CTL, ctl | MDIO_CTL_READ);
  211 
  212         val = memac_miibus_wait_no_busy(sc);
  213         if (val != 0)
  214                 return (0xffff);
  215 
  216         cfg = memac_read_4(sc, MDIO_CFG);
  217         if (cfg & MDIO_CFG_MDIO_RD_ER)
  218                 return (0xffff);
  219 
  220         val = memac_read_4(sc, MDIO_DATA);
  221         val &= 0xffff;
  222 
  223 #if defined(MEMAC_MDIO_DEBUG)
  224         device_printf(sc->dev, "phy read %d:%d = %#06x\n", phy, reg, val);
  225 #endif
  226 
  227         return (val);
  228 }
  229 
  230 int
  231 memac_miibus_writereg(struct memac_mdio_softc_common *sc, int phy, int reg, int data)
  232 {
  233         uint32_t cfg, ctl, val;
  234 
  235 #if defined(MEMAC_MDIO_DEBUG)
  236         device_printf(sc->dev, "phy write %d:%d\n", phy, reg);
  237 #endif
  238 
  239         /* Set proper Clause 45 mode. */
  240         cfg = memac_read_4(sc, MDIO_CFG);
  241         /* XXX 45 support? */
  242         cfg &= ~MDIO_CFG_ENC45; /* Use Clause 22 */
  243         memac_write_4(sc, MDIO_CFG, cfg);
  244 
  245         val = memac_miibus_wait_no_busy(sc);
  246         if (val != 0)
  247                 return (0xffff);
  248 
  249         /* To whom do we want to talk to.. */
  250         ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(reg);
  251         memac_write_4(sc, MDIO_CTL, ctl);
  252 
  253         memac_write_4(sc, MDIO_DATA, data & 0xffff);
  254 
  255         val = memac_miibus_wait_no_busy(sc);
  256         if (val != 0)
  257                 return (0xffff);
  258 
  259         return (0);
  260 }
  261 
  262 ssize_t
  263 memac_mdio_get_property(device_t dev, device_t child, const char *propname,
  264     void *propvalue, size_t size, device_property_type_t type)
  265 {
  266 
  267         return (bus_generic_get_property(dev, child, propname, propvalue, size, type));
  268 }
  269 
  270 int
  271 memac_mdio_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  272 {
  273 
  274         return (BUS_READ_IVAR(device_get_parent(dev), dev, index, result));
  275 }
  276 
  277 
  278 int
  279 memac_mdio_generic_attach(struct memac_mdio_softc_common *sc)
  280 {
  281         int rid;
  282 
  283         rid = 0;
  284         sc->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
  285             &rid, RF_ACTIVE | RF_SHAREABLE);
  286         if (sc->mem_res == NULL) {
  287                 device_printf(sc->dev, "%s: cannot allocate mem resource\n",
  288                     __func__);
  289                 return (ENXIO);
  290         }
  291 
  292         sc->is_little_endian = device_has_property(sc->dev, "little-endian");
  293 
  294         return (0);
  295 }
  296 
  297 int
  298 memac_mdio_generic_detach(struct memac_mdio_softc_common *sc)
  299 {
  300 
  301         if (sc->mem_res != NULL)
  302                 bus_release_resource(sc->dev, SYS_RES_MEMORY,
  303                     rman_get_rid(sc->mem_res), sc->mem_res);
  304 
  305         return (0);
  306 }

Cache object: ac981289dce5ff8cd58dad8b6fb8976f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.