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