1 /* $OpenBSD: mvmdio.c,v 1.3 2020/11/28 20:06:05 kettenis Exp $ */ 2 /* $NetBSD: if_mvneta.c,v 1.41 2015/04/15 10:15:40 hsuenaga Exp $ */ 3 /* 4 * Copyright (c) 2007, 2008, 2013 KIYOHARA Takashi 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/device.h> 32 #include <sys/socket.h> 33 #include <sys/sockio.h> 34 #include <sys/mutex.h> 35 36 #include <machine/bus.h> 37 #include <machine/fdt.h> 38 39 #ifdef __armv7__ 40 #include <arm/simplebus/simplebusvar.h> 41 #else 42 #include <arm64/dev/simplebusvar.h> 43 #endif 44 45 #include <dev/ofw/openfirm.h> 46 #include <dev/ofw/ofw_clock.h> 47 #include <dev/ofw/ofw_pinctrl.h> 48 #include <dev/ofw/ofw_misc.h> 49 #include <dev/ofw/fdt.h> 50 51 #include <dev/fdt/if_mvnetareg.h> 52 53 #include <net/if.h> 54 55 #define MVNETA_READ(sc, reg) \ 56 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) 57 #define MVNETA_WRITE(sc, reg, val) \ 58 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 59 60 struct mvmdio_softc { 61 struct simplebus_softc sc_sbus; 62 63 bus_space_tag_t sc_iot; 64 bus_space_handle_t sc_ioh; 65 66 struct mutex sc_mtx; 67 struct mii_bus sc_mii; 68 }; 69 70 static int mvmdio_match(struct device *, void *, void *); 71 static void mvmdio_attach(struct device *, struct device *, void *); 72 73 int mvmdio_smi_readreg(struct device *, int, int); 74 void mvmdio_smi_writereg(struct device *, int, int, int); 75 76 struct cfdriver mvmdio_cd = { 77 NULL, "mvmdio", DV_DULL 78 }; 79 80 struct cfattach mvmdio_ca = { 81 sizeof (struct mvmdio_softc), mvmdio_match, mvmdio_attach, 82 }; 83 84 static int 85 mvmdio_match(struct device *parent, void *cfdata, void *aux) 86 { 87 struct fdt_attach_args *faa = aux; 88 89 return OF_is_compatible(faa->fa_node, "marvell,orion-mdio"); 90 } 91 92 static void 93 mvmdio_attach(struct device *parent, struct device *self, void *aux) 94 { 95 struct mvmdio_softc *sc = (struct mvmdio_softc *) self; 96 struct fdt_attach_args *faa = aux; 97 98 if (faa->fa_nreg < 1) { 99 printf(": no registers\n"); 100 return; 101 } 102 103 sc->sc_iot = faa->fa_iot; 104 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 105 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 106 printf(": can't map registers\n"); 107 return; 108 } 109 110 pinctrl_byname(faa->fa_node, "default"); 111 clock_enable_all(faa->fa_node); 112 113 mtx_init(&sc->sc_mtx, IPL_NET); 114 115 sc->sc_mii.md_node = faa->fa_node; 116 sc->sc_mii.md_cookie = sc; 117 sc->sc_mii.md_readreg = mvmdio_smi_readreg; 118 sc->sc_mii.md_writereg = mvmdio_smi_writereg; 119 mii_register(&sc->sc_mii); 120 121 simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa); 122 } 123 124 int 125 mvmdio_smi_readreg(struct device *dev, int phy, int reg) 126 { 127 struct mvmdio_softc *sc = (struct mvmdio_softc *) dev; 128 uint32_t smi, val; 129 int i; 130 131 mtx_enter(&sc->sc_mtx); 132 133 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 134 DELAY(1); 135 if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY)) 136 break; 137 } 138 if (i == MVNETA_PHY_TIMEOUT) { 139 printf("%s: SMI busy timeout\n", sc->sc_sbus.sc_dev.dv_xname); 140 mtx_leave(&sc->sc_mtx); 141 return -1; 142 } 143 144 smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg) 145 | MVNETA_SMI_OPCODE_READ; 146 MVNETA_WRITE(sc, 0, smi); 147 148 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 149 DELAY(1); 150 smi = MVNETA_READ(sc, 0); 151 if (smi & MVNETA_SMI_READVALID) 152 break; 153 } 154 155 mtx_leave(&sc->sc_mtx); 156 157 val = smi & MVNETA_SMI_DATA_MASK; 158 159 return val; 160 } 161 162 void 163 mvmdio_smi_writereg(struct device *dev, int phy, int reg, int val) 164 { 165 struct mvmdio_softc *sc = (struct mvmdio_softc *) dev; 166 uint32_t smi; 167 int i; 168 169 mtx_enter(&sc->sc_mtx); 170 171 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 172 DELAY(1); 173 if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY)) 174 break; 175 } 176 if (i == MVNETA_PHY_TIMEOUT) { 177 printf("%s: SMI busy timeout\n", sc->sc_sbus.sc_dev.dv_xname); 178 mtx_leave(&sc->sc_mtx); 179 return; 180 } 181 182 smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg) | 183 MVNETA_SMI_OPCODE_WRITE | (val & MVNETA_SMI_DATA_MASK); 184 MVNETA_WRITE(sc, 0, smi); 185 186 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 187 DELAY(1); 188 if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY)) 189 break; 190 } 191 192 mtx_leave(&sc->sc_mtx); 193 194 if (i == MVNETA_PHY_TIMEOUT) 195 printf("%s: phy write timed out\n", sc->sc_sbus.sc_dev.dv_xname); 196 } 197