1 /* $OpenBSD: mvmdio.c,v 1.2 2020/06/25 12:39:19 patrick 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 #include <dev/ofw/openfirm.h> 40 #include <dev/ofw/ofw_clock.h> 41 #include <dev/ofw/ofw_pinctrl.h> 42 #include <dev/ofw/ofw_misc.h> 43 #include <dev/ofw/fdt.h> 44 45 #include <dev/fdt/if_mvnetareg.h> 46 47 #include <net/if.h> 48 49 #define MVNETA_READ(sc, reg) \ 50 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) 51 #define MVNETA_WRITE(sc, reg, val) \ 52 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 53 54 struct mvmdio_softc { 55 struct device sc_dev; 56 57 bus_space_tag_t sc_iot; 58 bus_space_handle_t sc_ioh; 59 60 struct mutex sc_mtx; 61 struct mii_bus sc_mii; 62 }; 63 64 static int mvmdio_match(struct device *, void *, void *); 65 static void mvmdio_attach(struct device *, struct device *, void *); 66 67 int mvmdio_smi_readreg(struct device *, int, int); 68 void mvmdio_smi_writereg(struct device *, int, int, int); 69 70 struct cfdriver mvmdio_cd = { 71 NULL, "mvmdio", DV_DULL 72 }; 73 74 struct cfattach mvmdio_ca = { 75 sizeof (struct mvmdio_softc), mvmdio_match, mvmdio_attach, 76 }; 77 78 static int 79 mvmdio_match(struct device *parent, void *cfdata, void *aux) 80 { 81 struct fdt_attach_args *faa = aux; 82 83 return OF_is_compatible(faa->fa_node, "marvell,orion-mdio"); 84 } 85 86 static void 87 mvmdio_attach(struct device *parent, struct device *self, void *aux) 88 { 89 struct mvmdio_softc *sc = (struct mvmdio_softc *) self; 90 struct fdt_attach_args *faa = aux; 91 92 printf("\n"); 93 94 sc->sc_iot = faa->fa_iot; 95 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 96 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 97 panic("%s: cannot map registers", sc->sc_dev.dv_xname); 98 99 pinctrl_byname(faa->fa_node, "default"); 100 clock_enable_all(faa->fa_node); 101 102 mtx_init(&sc->sc_mtx, IPL_NET); 103 104 sc->sc_mii.md_node = faa->fa_node; 105 sc->sc_mii.md_cookie = sc; 106 sc->sc_mii.md_readreg = mvmdio_smi_readreg; 107 sc->sc_mii.md_writereg = mvmdio_smi_writereg; 108 mii_register(&sc->sc_mii); 109 } 110 111 int 112 mvmdio_smi_readreg(struct device *dev, int phy, int reg) 113 { 114 struct mvmdio_softc *sc = (struct mvmdio_softc *) dev; 115 uint32_t smi, val; 116 int i; 117 118 mtx_enter(&sc->sc_mtx); 119 120 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 121 DELAY(1); 122 if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY)) 123 break; 124 } 125 if (i == MVNETA_PHY_TIMEOUT) { 126 printf("%s: SMI busy timeout\n", sc->sc_dev.dv_xname); 127 mtx_leave(&sc->sc_mtx); 128 return -1; 129 } 130 131 smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg) 132 | MVNETA_SMI_OPCODE_READ; 133 MVNETA_WRITE(sc, 0, smi); 134 135 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 136 DELAY(1); 137 smi = MVNETA_READ(sc, 0); 138 if (smi & MVNETA_SMI_READVALID) 139 break; 140 } 141 142 mtx_leave(&sc->sc_mtx); 143 144 val = smi & MVNETA_SMI_DATA_MASK; 145 146 return val; 147 } 148 149 void 150 mvmdio_smi_writereg(struct device *dev, int phy, int reg, int val) 151 { 152 struct mvmdio_softc *sc = (struct mvmdio_softc *) dev; 153 uint32_t smi; 154 int i; 155 156 mtx_enter(&sc->sc_mtx); 157 158 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 159 DELAY(1); 160 if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY)) 161 break; 162 } 163 if (i == MVNETA_PHY_TIMEOUT) { 164 printf("%s: SMI busy timeout\n", sc->sc_dev.dv_xname); 165 mtx_leave(&sc->sc_mtx); 166 return; 167 } 168 169 smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg) | 170 MVNETA_SMI_OPCODE_WRITE | (val & MVNETA_SMI_DATA_MASK); 171 MVNETA_WRITE(sc, 0, smi); 172 173 for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 174 DELAY(1); 175 if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY)) 176 break; 177 } 178 179 mtx_leave(&sc->sc_mtx); 180 181 if (i == MVNETA_PHY_TIMEOUT) 182 printf("%s: phy write timed out\n", sc->sc_dev.dv_xname); 183 } 184