1 /* $NetBSD: emac3.c,v 1.16 2024/05/24 20:09:09 andvar Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * EMAC3 (Ethernet Media Access Controller) 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: emac3.c,v 1.16 2024/05/24 20:09:09 andvar Exp $"); 38 39 #include "debug_playstation2.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 44 #include <sys/device.h> 45 #include <sys/socket.h> 46 #include <sys/pmf.h> 47 48 #include <net/if.h> 49 #include <net/if_ether.h> 50 #include <net/if_media.h> 51 52 #include <dev/mii/mii.h> 53 #include <dev/mii/miivar.h> 54 55 #include <playstation2/ee/eevar.h> 56 #include <playstation2/dev/emac3reg.h> 57 #include <playstation2/dev/emac3var.h> 58 59 #ifdef EMAC3_DEBUG 60 #define STATIC 61 int emac3_debug = 0; 62 #define DPRINTF(fmt, args...) \ 63 if (emac3_debug) \ 64 printf("%s: " fmt, __func__ , ##args) 65 #define DPRINTFN(n, arg) \ 66 if (emac3_debug > (n)) \ 67 printf("%s: " fmt, __func__ , ##args) 68 #else 69 #define STATIC static 70 #define DPRINTF(arg...) ((void)0) 71 #define DPRINTFN(n, arg...) ((void)0) 72 #endif 73 74 /* SMAP specific EMAC3 define */ 75 #define EMAC3_BASE MIPS_PHYS_TO_KSEG1(0x14002000) 76 static inline u_int32_t 77 _emac3_reg_read_4(int ofs) 78 { 79 bus_addr_t a_ = EMAC3_BASE + ofs; 80 81 return (_reg_read_2(a_) << 16) | _reg_read_2(a_ + 2); 82 } 83 84 static inline void 85 _emac3_reg_write_4(int ofs, u_int32_t v) 86 { 87 bus_addr_t a_ = EMAC3_BASE + ofs; 88 89 _reg_write_2(a_, (v >> 16) & 0xffff); 90 _reg_write_2(a_ + 2, v & 0xffff); 91 } 92 93 STATIC int emac3_phy_ready(void); 94 STATIC int emac3_soft_reset(void); 95 STATIC void emac3_config(const u_int8_t *); 96 97 int 98 emac3_init(struct emac3_softc *sc) 99 { 100 u_int32_t r; 101 102 /* save current mode before reset */ 103 r = _emac3_reg_read_4(EMAC3_MR1); 104 105 if (emac3_soft_reset() != 0) { 106 printf("%s: reset failed.\n", device_xname(sc->dev)); 107 return (1); 108 } 109 110 /* set operation mode */ 111 r |= MR1_RFS_2KB | MR1_TFS_1KB | MR1_TR0_SINGLE | MR1_TR1_SINGLE; 112 _emac3_reg_write_4(EMAC3_MR1, r); 113 114 sc->mode1_reg = _emac3_reg_read_4(EMAC3_MR1); 115 116 emac3_intr_clear(); 117 emac3_intr_disable(); 118 119 emac3_config(sc->eaddr); 120 121 return (0); 122 } 123 124 void 125 emac3_exit(struct emac3_softc *sc) 126 { 127 int retry = 10000; 128 129 /* wait for kicked transmission */ 130 while (((_emac3_reg_read_4(EMAC3_TMR0) & TMR0_GNP0) != 0) && 131 --retry > 0) 132 ; 133 134 if (retry == 0) 135 printf("%s: still running.\n", device_xname(sc->dev)); 136 } 137 138 int 139 emac3_reset(struct emac3_softc *sc) 140 { 141 142 if (emac3_soft_reset() != 0) { 143 printf("%s: reset failed.\n", device_xname(sc->dev)); 144 return (1); 145 } 146 147 /* restore previous mode */ 148 _emac3_reg_write_4(EMAC3_MR1, sc->mode1_reg); 149 150 emac3_config(sc->eaddr); 151 152 return (0); 153 } 154 155 void 156 emac3_enable(void) 157 { 158 159 _emac3_reg_write_4(EMAC3_MR0, MR0_TXE | MR0_RXE); 160 } 161 162 void 163 emac3_disable(void) 164 { 165 int retry = 10000; 166 167 _emac3_reg_write_4(EMAC3_MR0, 168 _emac3_reg_read_4(EMAC3_MR0) & ~(MR0_TXE | MR0_RXE)); 169 170 /* wait for idling state */ 171 while (((_emac3_reg_read_4(EMAC3_MR0) & (MR0_RXI | MR0_TXI)) != 172 (MR0_RXI | MR0_TXI)) && --retry > 0) 173 ; 174 175 if (retry == 0) 176 printf("emac3 running.\n"); 177 } 178 179 void 180 emac3_intr_enable(void) 181 { 182 183 _emac3_reg_write_4(EMAC3_ISER, ~0); 184 } 185 186 void 187 emac3_intr_disable(void) 188 { 189 190 _emac3_reg_write_4(EMAC3_ISER, 0); 191 } 192 193 void 194 emac3_intr_clear(void) 195 { 196 197 _emac3_reg_write_4(EMAC3_ISR, _emac3_reg_read_4(EMAC3_ISR)); 198 } 199 200 int 201 emac3_intr(void *arg) 202 { 203 u_int32_t r = _emac3_reg_read_4(EMAC3_ISR); 204 205 DPRINTF("%08x\n", r); 206 _emac3_reg_write_4(EMAC3_ISR, r); 207 208 return (1); 209 } 210 211 void 212 emac3_tx_kick(void) 213 { 214 215 _emac3_reg_write_4(EMAC3_TMR0, TMR0_GNP0); 216 } 217 218 int 219 emac3_tx_done(void) 220 { 221 222 return (_emac3_reg_read_4(EMAC3_TMR0) & TMR0_GNP0); 223 } 224 225 void 226 emac3_setmulti(struct emac3_softc *sc, struct ethercom *ec) 227 { 228 struct ether_multi *enm; 229 struct ether_multistep step; 230 struct ifnet *ifp = &ec->ec_if; 231 u_int32_t r; 232 233 r = _emac3_reg_read_4(EMAC3_RMR); 234 r &= ~(RMR_PME | RMR_PMME | RMR_MIAE); 235 236 if (ifp->if_flags & IFF_PROMISC) { 237 allmulti: 238 ifp->if_flags |= IFF_ALLMULTI; 239 r |= RMR_PME; 240 _emac3_reg_write_4(EMAC3_RMR, r); 241 242 return; 243 } 244 245 ETHER_LOCK(ec); 246 ETHER_FIRST_MULTI(step, ec, enm); 247 while (enm != NULL) { 248 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 249 ETHER_ADDR_LEN) != 0) { 250 ETHER_UNLOCK(ec); 251 goto allmulti; 252 } 253 254 ETHER_NEXT_MULTI(step, enm); 255 } 256 ETHER_UNLOCK(ec); 257 258 /* XXX always multicast promiscuous mode. XXX use hash table.. */ 259 ifp->if_flags |= IFF_ALLMULTI; 260 r |= RMR_PMME; 261 _emac3_reg_write_4(EMAC3_RMR, r); 262 } 263 264 int 265 emac3_soft_reset(void) 266 { 267 int retry = 10000; 268 269 _emac3_reg_write_4(EMAC3_MR0, MR0_SRST); 270 271 while ((_emac3_reg_read_4(EMAC3_MR0) & MR0_SRST) == MR0_SRST && 272 --retry > 0) 273 ; 274 275 return (retry == 0); 276 } 277 278 void 279 emac3_config(const u_int8_t *eaddr) 280 { 281 282 /* set ethernet address */ 283 _emac3_reg_write_4(EMAC3_IAHR, (eaddr[0] << 8) | eaddr[1]); 284 _emac3_reg_write_4(EMAC3_IALR, (eaddr[2] << 24) | (eaddr[3] << 16) | 285 (eaddr[4] << 8) | eaddr[5]); 286 287 /* inter-frame GAP */ 288 _emac3_reg_write_4(EMAC3_IPGVR, 4); 289 290 /* RX mode */ 291 _emac3_reg_write_4(EMAC3_RMR, 292 RMR_SP | /* strip padding */ 293 RMR_SFCS | /* strip FCS */ 294 RMR_IAE | /* individual address enable */ 295 RMR_BAE); /* broadcast address enable */ 296 297 /* TX mode */ 298 _emac3_reg_write_4(EMAC3_TMR1, 299 ((7 << TMR1_TLR_SHIFT) & TMR1_TLR_MASK) | /* 16 word burst */ 300 ((15 << TMR1_TUR_SHIFT) & TMR1_TUR_MASK)); 301 302 /* TX threshold */ 303 _emac3_reg_write_4(EMAC3_TRTR, 304 (12 << TRTR_SHIFT) & TRTR_MASK); /* 832 bytes */ 305 306 /* RX watermark */ 307 _emac3_reg_write_4(EMAC3_RWMR, 308 ((16 << RWMR_RLWM_SHIFT) & RWMR_RLWM_MASK) | 309 ((128 << RWMR_RHWM_SHIFT) & RWMR_RHWM_MASK)); 310 } 311 312 /* 313 * PHY/MII 314 */ 315 int 316 emac3_phy_writereg(device_t self, int phy, int reg, uint16_t val) 317 { 318 int rv; 319 320 if ((rv = emac3_phy_ready()) != 0) 321 return rv; 322 323 _emac3_reg_write_4(EMAC3_STACR, STACR_WRITE | 324 ((phy << STACR_PCDASHIFT) & STACR_PCDA) | /* command dest addr*/ 325 ((reg << STACR_PRASHIFT) & STACR_PRA) | /* register addr */ 326 ((val << STACR_PHYDSHIFT) & STACR_PHYD)); /* data */ 327 328 return emac3_phy_ready(); 329 } 330 331 int 332 emac3_phy_readreg(device_t self, int phy, int reg, uint16_t *val) 333 { 334 int rv; 335 336 if ((rv = emac3_phy_ready()) != 0) 337 return rv; 338 339 _emac3_reg_write_4(EMAC3_STACR, STACR_READ | 340 ((phy << STACR_PCDASHIFT) & STACR_PCDA) | /* command dest addr*/ 341 ((reg << STACR_PRASHIFT) & STACR_PRA)); /* register addr */ 342 343 if ((rv = emac3_phy_ready()) != 0) 344 return rv; 345 346 *val =(_emac3_reg_read_4(EMAC3_STACR) >> STACR_PHYDSHIFT) & 0xffff; 347 return 0; 348 } 349 350 void 351 emac3_phy_statchg(struct ifnet *ifp) 352 { 353 #define EMAC3_FDX (MR1_FDE | MR1_EIFC | MR1_APP) 354 struct emac3_softc *sc = ifp->if_softc; 355 int media; 356 u_int32_t r; 357 358 media = sc->mii.mii_media_active; 359 360 r = _emac3_reg_read_4(EMAC3_MR1); 361 362 r &= ~(MR1_MF_MASK | MR1_IST | EMAC3_FDX); 363 364 switch (media & 0x1f) { 365 default: 366 printf("unknown media type. %08x", media); 367 /* FALLTHROUGH */ 368 case IFM_100_TX: 369 r |= (MR1_MF_100MBS | MR1_IST); 370 if (media & IFM_FDX) 371 r |= EMAC3_FDX; 372 373 break; 374 case IFM_10_T: 375 r |= MR1_MF_10MBS; 376 if (media & IFM_FDX) 377 r |= (EMAC3_FDX | MR1_IST); 378 break; 379 } 380 381 _emac3_reg_write_4(EMAC3_MR1, r); 382 383 /* store current state for re-initialize */ 384 sc->mode1_reg = _emac3_reg_read_4(EMAC3_MR1); 385 #undef EMAC3_FDX 386 } 387 388 int 389 emac3_phy_ready(void) 390 { 391 int retry = 10000; 392 393 while ((_emac3_reg_read_4(EMAC3_STACR) & STACR_OC) == 0 && 394 --retry > 0) 395 ; 396 if (retry == 0) { 397 printf("emac3: phy busy.\n"); 398 return ETIMEDOUT; 399 } 400 401 return (0); 402 } 403 404