Home | History | Annotate | Line # | Download | only in dev
if_cs_mainbus.c revision 1.6.6.1
      1 /*	$NetBSD: if_cs_mainbus.c,v 1.6.6.1 2012/02/18 07:31:59 mrg Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Lennart Augustsson (lennart (at) augustsson.net) at Sandburst Corp.
      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 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: if_cs_mainbus.c,v 1.6.6.1 2012/02/18 07:31:59 mrg Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/device.h>
     37 #include <sys/systm.h>
     38 #include <sys/socket.h>
     39 #include <sys/bus.h>
     40 
     41 #include <sys/rnd.h>
     42 
     43 #include <net/if.h>
     44 #include <net/if_ether.h>
     45 #include <net/if_media.h>
     46 #ifdef INET
     47 #include <netinet/in.h>
     48 #include <netinet/if_inarp.h>
     49 #endif
     50 
     51 #include <powerpc/psl.h>
     52 
     53 #include <machine/pio.h>
     54 #include <machine/pmppc.h>
     55 #include <evbppc/pmppc/dev/mainbus.h>
     56 
     57 #include <dev/ic/cs89x0reg.h>
     58 #include <dev/ic/cs89x0var.h>
     59 
     60 #include <sys/callout.h>
     61 
     62 #define ATSN_EEPROM_MAC_OFFSET           0x20
     63 
     64 
     65 static void	cs_check_eeprom(struct cs_softc *sc);
     66 
     67 static int	cs_mainbus_match(device_t, cfdata_t, void *);
     68 static void	cs_mainbus_attach(device_t, device_t, void *);
     69 
     70 CFATTACH_DECL_NEW(cs_mainbus, sizeof(struct cs_softc),
     71     cs_mainbus_match, cs_mainbus_attach, NULL, NULL);
     72 
     73 int
     74 cs_mainbus_match(device_t parent, cfdata_t cf, void *aux)
     75 {
     76 	struct mainbus_attach_args *maa = aux;
     77 
     78 	return (strcmp(maa->mb_name, "cs") == 0);
     79 }
     80 
     81 #if 0
     82 static u_int64_t
     83 in64(uint a)
     84 {
     85 	union {
     86 		double d;
     87 		u_int64_t i;
     88 	} u;
     89 	double save, *dp = (double *)a;
     90 	u_int32_t msr, nmsr;
     91 
     92 	__asm volatile("mfmsr %0" : "=r"(msr));
     93 	nmsr = (msr | PSL_FP) & ~(PSL_FE0 | PSL_FE1);
     94 	__asm volatile("mtmsr %0" :: "r"(nmsr));
     95 	__asm volatile("mfmsr %0" : "=r"(nmsr)); /* some interlock nonsense */
     96 	__asm volatile(
     97        "stfd 0,%0\n\
     98 	lfd 0,%1\n\
     99 	stfd 0,%2\n\
    100 	lfd 0,%0"
    101 		 : "=m"(save), "=m"(*dp)
    102 		 : "m"(u.d)
    103 		);
    104 	__asm volatile ("eieio; sync");
    105 	__asm volatile("mtmsr %0" :: "r"(msr));
    106 	return (u.i);
    107 }
    108 #endif
    109 
    110 static void
    111 out64(uint a, u_int64_t v)
    112 {
    113 	union {
    114 		double d;
    115 		u_int64_t i;
    116 	} u;
    117 	double save, *dp = (double *)a;
    118 	u_int32_t msr, nmsr;
    119 	int s;
    120 
    121 	s = splhigh();
    122 	u.i = v;
    123 	__asm volatile("mfmsr %0" : "=r"(msr));
    124 	nmsr = (msr | PSL_FP) & ~(PSL_FE0 | PSL_FE1);
    125 	__asm volatile("mtmsr %0" :: "r"(nmsr));
    126 	__asm volatile("mfmsr %0" : "=r"(nmsr)); /* some interlock nonsense */
    127 	__asm volatile(
    128        "stfd 0,%0\n\
    129 	lfd 0,%2\n\
    130 	stfd 0,%1\n\
    131 	lfd 0,%0"
    132 		 : "=m"(save), "=m"(*dp)
    133 		 : "m"(u.d)
    134 		);
    135 	__asm volatile ("eieio; sync");
    136 	__asm volatile("mtmsr %0" :: "r"(msr));
    137 	splx(s);
    138 }
    139 
    140 static u_int8_t
    141 cs_io_read_1(struct cs_softc *sc, bus_size_t offs)
    142 {
    143 	u_int32_t a, v;
    144 
    145 	a = sc->sc_ioh + (offs << 2);
    146 	v = in8(a);
    147 	return v;
    148 }
    149 
    150 static u_int16_t
    151 cs_io_read_2(struct cs_softc *sc, bus_size_t offs)
    152 {
    153 	u_int32_t a, v;
    154 
    155 	a = sc->sc_ioh + (offs << 2);
    156 	v = in16(a);
    157 	return v;
    158 }
    159 
    160 static void
    161 cs_io_read_multi_2(struct cs_softc *sc, bus_size_t offs, u_int16_t *buf,
    162 		   bus_size_t cnt)
    163 {
    164 	u_int32_t a, v;
    165 
    166 	a = sc->sc_ioh + (offs << 2);
    167 	while (cnt--) {
    168 		v = in16(a);
    169 		*buf++ = bswap16(v);
    170 	}
    171 }
    172 
    173 static void
    174 cs_io_write_2(struct cs_softc *sc, bus_size_t offs, u_int16_t data)
    175 {
    176 	u_int32_t a;
    177 	u_int64_t v;
    178 
    179 	a = sc->sc_ioh + (offs << 2);
    180 	v = (u_int64_t)data << 48;
    181 	out64(a, v);
    182 
    183 	(void)in16(a);		/* CPC700 write post bug */
    184 }
    185 
    186 static void
    187 cs_io_write_multi_2(struct cs_softc *sc, bus_size_t offs,
    188 		    const u_int16_t *buf, bus_size_t cnt)
    189 {
    190 	u_int16_t v;
    191 	double save, *dp;
    192 	union {
    193 		double d;
    194 		u_int64_t i;
    195 	} u;
    196 	u_int32_t msr, nmsr;
    197 	int s;
    198 
    199 	dp = (double *)(sc->sc_ioh + (offs << 2));
    200 
    201 	s = splhigh();
    202 	__asm volatile("mfmsr %0" : "=r"(msr));
    203 	nmsr = (msr | PSL_FP) & ~(PSL_FE0 | PSL_FE1);
    204 	__asm volatile("mtmsr %0" :: "r"(nmsr));
    205 	__asm volatile("mfmsr %0" : "=r"(nmsr)); /* some interlock nonsense */
    206 	__asm volatile("stfd 0,%0" : "=m"(save));
    207 
    208 	while (cnt--) {
    209 		v = *buf++;
    210 		v = bswap16(v);
    211 		u.i = (u_int64_t)v << 48;
    212 		__asm volatile("lfd 0,%1\nstfd 0,%0" : "=m"(*dp) : "m"(u.d) );
    213 		__asm volatile ("eieio; sync");
    214 	}
    215 	__asm volatile("lfd 0,%0" :: "m"(save));
    216 	__asm volatile("mtmsr %0" :: "r"(msr));
    217 	splx(s);
    218 }
    219 
    220 static u_int16_t
    221 cs_mem_read_2(struct cs_softc *sc, bus_size_t offs)
    222 {
    223 	panic("cs_mem_read_2");
    224 }
    225 
    226 static void
    227 cs_mem_write_2(struct cs_softc *sc, bus_size_t offs, u_int16_t data)
    228 {
    229 	panic("cs_mem_write_2");
    230 }
    231 
    232 static void
    233 cs_mem_write_region_2(struct cs_softc *sc, bus_size_t offs,
    234 		      const u_int16_t *buf, bus_size_t cnt)
    235 {
    236 	panic("cs_mem_write_region_2");
    237 }
    238 
    239 void
    240 cs_mainbus_attach(device_t parent, device_t self, void *aux)
    241 {
    242 	struct cs_softc *sc = device_private(self);
    243 	struct mainbus_attach_args *maa = aux;
    244 	int media[1] = { IFM_ETHER | IFM_10_T };
    245 
    246 	printf("\n");
    247 
    248 	sc->sc_dev = self;
    249 	sc->sc_iot = maa->mb_bt;
    250 	sc->sc_memt = maa->mb_bt;
    251 	sc->sc_irq = maa->mb_irq;
    252 
    253 	if (bus_space_map(sc->sc_iot, PMPPC_CS_IO, CS8900_IOSIZE*4,
    254 			  0, &sc->sc_ioh)) {
    255 		printf("%s: failed to map io\n", device_xname(self));
    256 		return;
    257 	}
    258 
    259 	cs_check_eeprom(sc);
    260 
    261 	sc->sc_ih = intr_establish(sc->sc_irq, IST_LEVEL, IPL_NET, cs_intr, sc);
    262 	if (!sc->sc_ih) {
    263 		printf("%s: unable to establish interrupt\n",
    264 		    device_xname(self));
    265 		goto fail;
    266 	}
    267 
    268 	sc->sc_cfgflags = CFGFLG_NOT_EEPROM;
    269 
    270 	sc->sc_io_read_1 = cs_io_read_1;
    271 	sc->sc_io_read_2 = cs_io_read_2;
    272 	sc->sc_io_read_multi_2 = cs_io_read_multi_2;
    273 	sc->sc_io_write_2 = cs_io_write_2;
    274 	sc->sc_io_write_multi_2 = cs_io_write_multi_2;
    275 	sc->sc_mem_read_2 = cs_mem_read_2;
    276 	sc->sc_mem_write_2 = cs_mem_write_2;
    277 	sc->sc_mem_write_region_2 = cs_mem_write_region_2;
    278 
    279 	/*
    280 	 * We need interrupt on INTRQ0 from the CS8900 (that's what wired
    281 	 * to the UIC).  The MI driver subtracts 10 from the irq, so
    282 	 * use 10 as the irq.
    283 	 */
    284 	sc->sc_irq = 10;
    285 
    286 	/* Use half duplex 10baseT. */
    287 	if (cs_attach(sc, NULL, media, 1, IFM_ETHER | IFM_10_T)) {
    288 		printf("%s: unable to attach\n", device_xname(self));
    289 		goto fail;
    290 	}
    291 
    292 	return;
    293 
    294  fail:
    295 	/* XXX disestablish, unmap */
    296 	return;
    297 }
    298 
    299 
    300 /*
    301  * EEPROM initialization code.
    302  */
    303 
    304 static uint16_t default_eeprom_cfg[] =
    305 { 0xA100, 0x2020, 0x0300, 0x0000, 0x0000,
    306   0x102C, 0x1000, 0x0008, 0x2158, 0x0000,
    307   0x0000, 0x0000 };
    308 
    309 static uint16_t
    310 cs_readreg(struct cs_softc *sc, uint pp_offset)
    311 {
    312 	cs_io_write_2(sc, PORT_PKTPG_PTR, pp_offset);
    313 	(void)cs_io_read_2(sc, PORT_PKTPG_PTR);
    314 	return (cs_io_read_2(sc, PORT_PKTPG_DATA));
    315 }
    316 
    317 static void
    318 cs_writereg(struct cs_softc *sc, uint pp_offset, uint16_t value)
    319 {
    320 	cs_io_write_2(sc, PORT_PKTPG_PTR, pp_offset);
    321 	(void)cs_io_read_2(sc, PORT_PKTPG_PTR);
    322 	cs_io_write_2(sc, PORT_PKTPG_DATA, value);
    323 	(void)cs_io_read_2(sc, PORT_PKTPG_DATA);
    324 }
    325 
    326 static int
    327 cs_wait_eeprom_ready(struct cs_softc *sc)
    328 {
    329 	int ms;
    330 
    331 	/*
    332 	 * Check to see if the EEPROM is ready, a timeout is used -
    333 	 * just in case EEPROM is ready when SI_BUSY in the
    334 	 * PP_SelfST is clear.
    335 	 */
    336 	ms = 0;
    337 	while(cs_readreg(sc, PKTPG_SELF_ST) & SELF_ST_SI_BUSY) {
    338 		delay(1000);
    339 		if (ms++ > 20)
    340 			return 0;
    341 	}
    342 	return 1;
    343 }
    344 
    345 static void
    346 cs_wr_eeprom(struct cs_softc *sc, uint16_t offset, uint16_t data)
    347 {
    348 
    349 	/* Check to make sure EEPROM is ready. */
    350 	if (!cs_wait_eeprom_ready(sc)) {
    351 		printf("%s: write EEPROM not ready\n",
    352 		    device_xname(sc->sc_dev));
    353 		return;
    354 	}
    355 
    356 	/* Enable writing. */
    357 	cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_WRITE_ENABLE);
    358 
    359 	/* Wait for WRITE_ENABLE command to complete. */
    360 	if (!cs_wait_eeprom_ready(sc)) {
    361 		printf("%s: EEPROM WRITE_ENABLE timeout",
    362 		    device_xname(sc->sc_dev));
    363 	} else {
    364 		/* Write data into EEPROM_DATA register. */
    365 		cs_writereg(sc, PKTPG_EEPROM_DATA, data);
    366 		delay(1000);
    367 		cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_CMD_WRITE | offset);
    368 
    369 		/* Wait for WRITE_REGISTER command to complete. */
    370 		if (!cs_wait_eeprom_ready(sc)) {
    371 			printf("%s: EEPROM WRITE_REGISTER timeout\n",
    372 			    device_xname(sc->sc_dev));
    373 		}
    374 	}
    375 
    376 	/* Disable writing. */
    377 	cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_WRITE_DISABLE);
    378 
    379 	/* Wait for WRITE_DISABLE command to complete. */
    380 	if (!cs_wait_eeprom_ready(sc)) {
    381 		printf("%s: WRITE_DISABLE timeout\n", device_xname(sc->sc_dev));
    382 	}
    383 }
    384 
    385 static uint16_t
    386 cs_rd_eeprom(struct cs_softc *sc, uint16_t offset)
    387 {
    388 
    389 	if (!cs_wait_eeprom_ready(sc)) {
    390 		printf("%s: read EEPROM not ready\n", device_xname(sc->sc_dev));
    391 		return 0;
    392 	}
    393 	cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_CMD_READ | offset);
    394 
    395 	if (!cs_wait_eeprom_ready(sc)) {
    396 		printf("%s: EEPROM_READ timeout\n", device_xname(sc->sc_dev));
    397 		return 0;
    398 	}
    399 	return cs_readreg(sc, PKTPG_EEPROM_DATA);
    400 }
    401 
    402 static void
    403 cs_check_eeprom(struct cs_softc *sc)
    404 {
    405 	uint8_t checksum;
    406 	int i;
    407         uint16_t tmp;
    408 
    409 	/*
    410 	 * If the SELFST[EEPROMOK] is set, then assume EEPROM configuration
    411 	 * is valid.
    412 	 */
    413 	if (cs_readreg(sc, PKTPG_SELF_ST) & SELF_ST_EEP_OK) {
    414 		printf("%s: EEPROM OK, skipping initialization\n",
    415 		    device_xname(sc->sc_dev));
    416 		return;
    417 	}
    418 	printf("%s: updating EEPROM\n", device_xname(sc->sc_dev));
    419 
    420 	/*
    421 	 * Calculate the size (in bytes) of the default config array and write
    422 	 * it to the lower byte of the array itself.
    423 	 */
    424 	default_eeprom_cfg[0] |= sizeof(default_eeprom_cfg);
    425 
    426 	/*
    427 	 * Read the MAC address from its Artesyn-specified offset in the EEPROM.
    428 	 */
    429 	for (i = 0; i < 3; i++) {
    430 		tmp = cs_rd_eeprom(sc, ATSN_EEPROM_MAC_OFFSET + i);
    431 		default_eeprom_cfg[EEPROM_MAC + i] = bswap16(tmp);
    432 	}
    433 
    434 	/*
    435 	 * Program the EEPROM with our default configuration,
    436 	 * calculating checksum as we proceed.
    437 	 */
    438 	checksum = 0;
    439 	for (i = 0; i < sizeof(default_eeprom_cfg)/2 ; i++) {
    440 		tmp = default_eeprom_cfg[i];
    441 		cs_wr_eeprom(sc, i, tmp);
    442 		checksum += tmp >> 8;
    443 		checksum += tmp & 0xff;
    444 	}
    445 
    446 	/*
    447 	 * The CS8900a datasheet calls for the two's complement of the checksum
    448 	 * to be prgrammed in the most significant byte of the last word of the
    449 	 * header.
    450 	 */
    451 	checksum = ~checksum + 1;
    452 	cs_wr_eeprom(sc, i++, checksum << 8);
    453 	/* write "end of data" flag */
    454 	cs_wr_eeprom(sc, i, 0xffff);
    455 }
    456