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