xref: /netbsd-src/sys/arch/evbppc/pmppc/dev/if_cs_mainbus.c (revision cde8f271ec30c028c5652673e0e3c4a6298637d1)
1*cde8f271Sriastradh /*	$NetBSD: if_cs_mainbus.c,v 1.9 2022/02/16 23:49:26 riastradh Exp $	*/
2d974db0aSgarbled 
3d974db0aSgarbled /*
4d974db0aSgarbled  * Copyright (c) 2002 The NetBSD Foundation, Inc.
5d974db0aSgarbled  * All rights reserved.
6d974db0aSgarbled  *
7d974db0aSgarbled  * This code is derived from software contributed to The NetBSD Foundation
8d974db0aSgarbled  * by Lennart Augustsson (lennart@augustsson.net) at Sandburst Corp.
9d974db0aSgarbled  *
10d974db0aSgarbled  * Redistribution and use in source and binary forms, with or without
11d974db0aSgarbled  * modification, are permitted provided that the following conditions
12d974db0aSgarbled  * are met:
13d974db0aSgarbled  * 1. Redistributions of source code must retain the above copyright
14d974db0aSgarbled  *    notice, this list of conditions and the following disclaimer.
15d974db0aSgarbled  * 2. Redistributions in binary form must reproduce the above copyright
16d974db0aSgarbled  *    notice, this list of conditions and the following disclaimer in the
17d974db0aSgarbled  *    documentation and/or other materials provided with the distribution.
18d974db0aSgarbled  *
19d974db0aSgarbled  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d974db0aSgarbled  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d974db0aSgarbled  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d974db0aSgarbled  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d974db0aSgarbled  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d974db0aSgarbled  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d974db0aSgarbled  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d974db0aSgarbled  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d974db0aSgarbled  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d974db0aSgarbled  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d974db0aSgarbled  * POSSIBILITY OF SUCH DAMAGE.
30d974db0aSgarbled  */
31d974db0aSgarbled 
32d974db0aSgarbled #include <sys/cdefs.h>
33*cde8f271Sriastradh __KERNEL_RCSID(0, "$NetBSD: if_cs_mainbus.c,v 1.9 2022/02/16 23:49:26 riastradh Exp $");
34d974db0aSgarbled 
35d974db0aSgarbled #include <sys/param.h>
36d974db0aSgarbled #include <sys/device.h>
37d974db0aSgarbled #include <sys/systm.h>
38d974db0aSgarbled #include <sys/socket.h>
397443d538Smatt #include <sys/bus.h>
40d974db0aSgarbled 
41d974db0aSgarbled #include <net/if.h>
42d974db0aSgarbled #include <net/if_ether.h>
43d974db0aSgarbled #include <net/if_media.h>
44d974db0aSgarbled #ifdef INET
45d974db0aSgarbled #include <netinet/in.h>
46d974db0aSgarbled #include <netinet/if_inarp.h>
47d974db0aSgarbled #endif
48d974db0aSgarbled 
497443d538Smatt #include <powerpc/psl.h>
507443d538Smatt 
51d974db0aSgarbled #include <machine/pio.h>
52d974db0aSgarbled #include <machine/pmppc.h>
537443d538Smatt #include <evbppc/pmppc/dev/mainbus.h>
54d974db0aSgarbled 
55d974db0aSgarbled #include <dev/ic/cs89x0reg.h>
56d974db0aSgarbled #include <dev/ic/cs89x0var.h>
57d974db0aSgarbled 
58d974db0aSgarbled #include <sys/callout.h>
59d974db0aSgarbled 
60d974db0aSgarbled #define ATSN_EEPROM_MAC_OFFSET           0x20
61d974db0aSgarbled 
62d974db0aSgarbled 
63d974db0aSgarbled static void	cs_check_eeprom(struct cs_softc *sc);
64d974db0aSgarbled 
6551a2be50Smatt static int	cs_mainbus_match(device_t, cfdata_t, void *);
6651a2be50Smatt static void	cs_mainbus_attach(device_t, device_t, void *);
67d974db0aSgarbled 
683b0a685fStsutsui CFATTACH_DECL_NEW(cs_mainbus, sizeof(struct cs_softc),
69d974db0aSgarbled     cs_mainbus_match, cs_mainbus_attach, NULL, NULL);
70d974db0aSgarbled 
71d974db0aSgarbled int
cs_mainbus_match(device_t parent,cfdata_t cf,void * aux)723b0a685fStsutsui cs_mainbus_match(device_t parent, cfdata_t cf, void *aux)
73d974db0aSgarbled {
74d974db0aSgarbled 	struct mainbus_attach_args *maa = aux;
75d974db0aSgarbled 
76d974db0aSgarbled 	return (strcmp(maa->mb_name, "cs") == 0);
77d974db0aSgarbled }
78d974db0aSgarbled 
79d974db0aSgarbled #if 0
80d974db0aSgarbled static u_int64_t
81d974db0aSgarbled in64(uint a)
82d974db0aSgarbled {
83d974db0aSgarbled 	union {
84d974db0aSgarbled 		double d;
85d974db0aSgarbled 		u_int64_t i;
86d974db0aSgarbled 	} u;
87d974db0aSgarbled 	double save, *dp = (double *)a;
88d974db0aSgarbled 	u_int32_t msr, nmsr;
89d974db0aSgarbled 
90d974db0aSgarbled 	__asm volatile("mfmsr %0" : "=r"(msr));
91d974db0aSgarbled 	nmsr = (msr | PSL_FP) & ~(PSL_FE0 | PSL_FE1);
92d974db0aSgarbled 	__asm volatile("mtmsr %0" :: "r"(nmsr));
93d974db0aSgarbled 	__asm volatile("mfmsr %0" : "=r"(nmsr)); /* some interlock nonsense */
94d974db0aSgarbled 	__asm volatile(
95d974db0aSgarbled        "stfd 0,%0\n\
96d974db0aSgarbled 	lfd 0,%1\n\
97d974db0aSgarbled 	stfd 0,%2\n\
98d974db0aSgarbled 	lfd 0,%0"
99d974db0aSgarbled 		 : "=m"(save), "=m"(*dp)
100d974db0aSgarbled 		 : "m"(u.d)
101d974db0aSgarbled 		);
102*cde8f271Sriastradh 	__asm volatile("eieio; sync" ::: "memory");
103d974db0aSgarbled 	__asm volatile("mtmsr %0" :: "r"(msr));
104d974db0aSgarbled 	return (u.i);
105d974db0aSgarbled }
106d974db0aSgarbled #endif
107d974db0aSgarbled 
108d974db0aSgarbled static void
out64(uint a,u_int64_t v)109d974db0aSgarbled out64(uint a, u_int64_t v)
110d974db0aSgarbled {
111d974db0aSgarbled 	union {
112d974db0aSgarbled 		double d;
113d974db0aSgarbled 		u_int64_t i;
114d974db0aSgarbled 	} u;
115d974db0aSgarbled 	double save, *dp = (double *)a;
116d974db0aSgarbled 	u_int32_t msr, nmsr;
117d974db0aSgarbled 	int s;
118d974db0aSgarbled 
119d974db0aSgarbled 	s = splhigh();
120d974db0aSgarbled 	u.i = v;
121d974db0aSgarbled 	__asm volatile("mfmsr %0" : "=r"(msr));
122d974db0aSgarbled 	nmsr = (msr | PSL_FP) & ~(PSL_FE0 | PSL_FE1);
123d974db0aSgarbled 	__asm volatile("mtmsr %0" :: "r"(nmsr));
124d974db0aSgarbled 	__asm volatile("mfmsr %0" : "=r"(nmsr)); /* some interlock nonsense */
125d974db0aSgarbled 	__asm volatile(
126d974db0aSgarbled        "stfd 0,%0\n\
127d974db0aSgarbled 	lfd 0,%2\n\
128d974db0aSgarbled 	stfd 0,%1\n\
129d974db0aSgarbled 	lfd 0,%0"
130d974db0aSgarbled 		 : "=m"(save), "=m"(*dp)
131d974db0aSgarbled 		 : "m"(u.d)
132d974db0aSgarbled 		);
133*cde8f271Sriastradh 	__asm volatile("eieio; sync" ::: "memory");
134d974db0aSgarbled 	__asm volatile("mtmsr %0" :: "r"(msr));
135d974db0aSgarbled 	splx(s);
136d974db0aSgarbled }
137d974db0aSgarbled 
138d974db0aSgarbled static u_int8_t
cs_io_read_1(struct cs_softc * sc,bus_size_t offs)139d974db0aSgarbled cs_io_read_1(struct cs_softc *sc, bus_size_t offs)
140d974db0aSgarbled {
141d974db0aSgarbled 	u_int32_t a, v;
142d974db0aSgarbled 
143d974db0aSgarbled 	a = sc->sc_ioh + (offs << 2);
144d974db0aSgarbled 	v = in8(a);
145d974db0aSgarbled 	return v;
146d974db0aSgarbled }
147d974db0aSgarbled 
148d974db0aSgarbled static u_int16_t
cs_io_read_2(struct cs_softc * sc,bus_size_t offs)149d974db0aSgarbled cs_io_read_2(struct cs_softc *sc, bus_size_t offs)
150d974db0aSgarbled {
151d974db0aSgarbled 	u_int32_t a, v;
152d974db0aSgarbled 
153d974db0aSgarbled 	a = sc->sc_ioh + (offs << 2);
154d974db0aSgarbled 	v = in16(a);
155d974db0aSgarbled 	return v;
156d974db0aSgarbled }
157d974db0aSgarbled 
158d974db0aSgarbled static void
cs_io_read_multi_2(struct cs_softc * sc,bus_size_t offs,u_int16_t * buf,bus_size_t cnt)159d974db0aSgarbled cs_io_read_multi_2(struct cs_softc *sc, bus_size_t offs, u_int16_t *buf,
160d974db0aSgarbled 		   bus_size_t cnt)
161d974db0aSgarbled {
162d974db0aSgarbled 	u_int32_t a, v;
163d974db0aSgarbled 
164d974db0aSgarbled 	a = sc->sc_ioh + (offs << 2);
165d974db0aSgarbled 	while (cnt--) {
166d974db0aSgarbled 		v = in16(a);
167d974db0aSgarbled 		*buf++ = bswap16(v);
168d974db0aSgarbled 	}
169d974db0aSgarbled }
170d974db0aSgarbled 
171d974db0aSgarbled static void
cs_io_write_2(struct cs_softc * sc,bus_size_t offs,u_int16_t data)172d974db0aSgarbled cs_io_write_2(struct cs_softc *sc, bus_size_t offs, u_int16_t data)
173d974db0aSgarbled {
174d974db0aSgarbled 	u_int32_t a;
175d974db0aSgarbled 	u_int64_t v;
176d974db0aSgarbled 
177d974db0aSgarbled 	a = sc->sc_ioh + (offs << 2);
178d974db0aSgarbled 	v = (u_int64_t)data << 48;
179d974db0aSgarbled 	out64(a, v);
180d974db0aSgarbled 
181d974db0aSgarbled 	(void)in16(a);		/* CPC700 write post bug */
182d974db0aSgarbled }
183d974db0aSgarbled 
184d974db0aSgarbled static void
cs_io_write_multi_2(struct cs_softc * sc,bus_size_t offs,const u_int16_t * buf,bus_size_t cnt)185d974db0aSgarbled cs_io_write_multi_2(struct cs_softc *sc, bus_size_t offs,
186d974db0aSgarbled 		    const u_int16_t *buf, bus_size_t cnt)
187d974db0aSgarbled {
188d974db0aSgarbled 	u_int16_t v;
189d974db0aSgarbled 	double save, *dp;
190d974db0aSgarbled 	union {
191d974db0aSgarbled 		double d;
192d974db0aSgarbled 		u_int64_t i;
193d974db0aSgarbled 	} u;
194d974db0aSgarbled 	u_int32_t msr, nmsr;
195d974db0aSgarbled 	int s;
196d974db0aSgarbled 
197d974db0aSgarbled 	dp = (double *)(sc->sc_ioh + (offs << 2));
198d974db0aSgarbled 
199d974db0aSgarbled 	s = splhigh();
200d974db0aSgarbled 	__asm volatile("mfmsr %0" : "=r"(msr));
201d974db0aSgarbled 	nmsr = (msr | PSL_FP) & ~(PSL_FE0 | PSL_FE1);
202d974db0aSgarbled 	__asm volatile("mtmsr %0" :: "r"(nmsr));
203d974db0aSgarbled 	__asm volatile("mfmsr %0" : "=r"(nmsr)); /* some interlock nonsense */
204d974db0aSgarbled 	__asm volatile("stfd 0,%0" : "=m"(save));
205d974db0aSgarbled 
206d974db0aSgarbled 	while (cnt--) {
207d974db0aSgarbled 		v = *buf++;
208d974db0aSgarbled 		v = bswap16(v);
209d974db0aSgarbled 		u.i = (u_int64_t)v << 48;
210d974db0aSgarbled 		__asm volatile("lfd 0,%1\nstfd 0,%0" : "=m"(*dp) : "m"(u.d) );
211*cde8f271Sriastradh 		__asm volatile("eieio; sync" ::: "memory");
212d974db0aSgarbled 	}
213d974db0aSgarbled 	__asm volatile("lfd 0,%0" :: "m"(save));
214d974db0aSgarbled 	__asm volatile("mtmsr %0" :: "r"(msr));
215d974db0aSgarbled 	splx(s);
216d974db0aSgarbled }
217d974db0aSgarbled 
218d974db0aSgarbled static u_int16_t
cs_mem_read_2(struct cs_softc * sc,bus_size_t offs)219d974db0aSgarbled cs_mem_read_2(struct cs_softc *sc, bus_size_t offs)
220d974db0aSgarbled {
221d974db0aSgarbled 	panic("cs_mem_read_2");
222d974db0aSgarbled }
223d974db0aSgarbled 
224d974db0aSgarbled static void
cs_mem_write_2(struct cs_softc * sc,bus_size_t offs,u_int16_t data)225d974db0aSgarbled cs_mem_write_2(struct cs_softc *sc, bus_size_t offs, u_int16_t data)
226d974db0aSgarbled {
227d974db0aSgarbled 	panic("cs_mem_write_2");
228d974db0aSgarbled }
229d974db0aSgarbled 
230d974db0aSgarbled static void
cs_mem_write_region_2(struct cs_softc * sc,bus_size_t offs,const u_int16_t * buf,bus_size_t cnt)231d974db0aSgarbled cs_mem_write_region_2(struct cs_softc *sc, bus_size_t offs,
232d974db0aSgarbled 		      const u_int16_t *buf, bus_size_t cnt)
233d974db0aSgarbled {
234d974db0aSgarbled 	panic("cs_mem_write_region_2");
235d974db0aSgarbled }
236d974db0aSgarbled 
237d974db0aSgarbled void
cs_mainbus_attach(device_t parent,device_t self,void * aux)2383b0a685fStsutsui cs_mainbus_attach(device_t parent, device_t self, void *aux)
239d974db0aSgarbled {
2403b0a685fStsutsui 	struct cs_softc *sc = device_private(self);
241d974db0aSgarbled 	struct mainbus_attach_args *maa = aux;
242d974db0aSgarbled 	int media[1] = { IFM_ETHER | IFM_10_T };
243d974db0aSgarbled 
244d974db0aSgarbled 	printf("\n");
245d974db0aSgarbled 
2463b0a685fStsutsui 	sc->sc_dev = self;
247d974db0aSgarbled 	sc->sc_iot = maa->mb_bt;
248d974db0aSgarbled 	sc->sc_memt = maa->mb_bt;
249d974db0aSgarbled 	sc->sc_irq = maa->mb_irq;
250d974db0aSgarbled 
251d974db0aSgarbled 	if (bus_space_map(sc->sc_iot, PMPPC_CS_IO, CS8900_IOSIZE*4,
252d974db0aSgarbled 			  0, &sc->sc_ioh)) {
2533b0a685fStsutsui 		printf("%s: failed to map io\n", device_xname(self));
254d974db0aSgarbled 		return;
255d974db0aSgarbled 	}
256d974db0aSgarbled 
257d974db0aSgarbled 	cs_check_eeprom(sc);
258d974db0aSgarbled 
259d974db0aSgarbled 	sc->sc_ih = intr_establish(sc->sc_irq, IST_LEVEL, IPL_NET, cs_intr, sc);
260d974db0aSgarbled 	if (!sc->sc_ih) {
261d974db0aSgarbled 		printf("%s: unable to establish interrupt\n",
2623b0a685fStsutsui 		    device_xname(self));
263d974db0aSgarbled 		goto fail;
264d974db0aSgarbled 	}
265d974db0aSgarbled 
266d974db0aSgarbled 	sc->sc_cfgflags = CFGFLG_NOT_EEPROM;
267d974db0aSgarbled 
268d974db0aSgarbled 	sc->sc_io_read_1 = cs_io_read_1;
269d974db0aSgarbled 	sc->sc_io_read_2 = cs_io_read_2;
270d974db0aSgarbled 	sc->sc_io_read_multi_2 = cs_io_read_multi_2;
271d974db0aSgarbled 	sc->sc_io_write_2 = cs_io_write_2;
272d974db0aSgarbled 	sc->sc_io_write_multi_2 = cs_io_write_multi_2;
273d974db0aSgarbled 	sc->sc_mem_read_2 = cs_mem_read_2;
274d974db0aSgarbled 	sc->sc_mem_write_2 = cs_mem_write_2;
275d974db0aSgarbled 	sc->sc_mem_write_region_2 = cs_mem_write_region_2;
276d974db0aSgarbled 
277d974db0aSgarbled 	/*
278d974db0aSgarbled 	 * We need interrupt on INTRQ0 from the CS8900 (that's what wired
279d974db0aSgarbled 	 * to the UIC).  The MI driver subtracts 10 from the irq, so
280d974db0aSgarbled 	 * use 10 as the irq.
281d974db0aSgarbled 	 */
282d974db0aSgarbled 	sc->sc_irq = 10;
283d974db0aSgarbled 
284d974db0aSgarbled 	/* Use half duplex 10baseT. */
285d974db0aSgarbled 	if (cs_attach(sc, NULL, media, 1, IFM_ETHER | IFM_10_T)) {
2863b0a685fStsutsui 		printf("%s: unable to attach\n", device_xname(self));
287d974db0aSgarbled 		goto fail;
288d974db0aSgarbled 	}
289d974db0aSgarbled 
290d974db0aSgarbled 	return;
291d974db0aSgarbled 
292d974db0aSgarbled  fail:
293d974db0aSgarbled 	/* XXX disestablish, unmap */
294d974db0aSgarbled 	return;
295d974db0aSgarbled }
296d974db0aSgarbled 
297d974db0aSgarbled 
298d974db0aSgarbled /*
299d974db0aSgarbled  * EEPROM initialization code.
300d974db0aSgarbled  */
301d974db0aSgarbled 
302d974db0aSgarbled static uint16_t default_eeprom_cfg[] =
303d974db0aSgarbled { 0xA100, 0x2020, 0x0300, 0x0000, 0x0000,
304d974db0aSgarbled   0x102C, 0x1000, 0x0008, 0x2158, 0x0000,
305d974db0aSgarbled   0x0000, 0x0000 };
306d974db0aSgarbled 
307d974db0aSgarbled static uint16_t
cs_readreg(struct cs_softc * sc,uint pp_offset)308d974db0aSgarbled cs_readreg(struct cs_softc *sc, uint pp_offset)
309d974db0aSgarbled {
310d974db0aSgarbled 	cs_io_write_2(sc, PORT_PKTPG_PTR, pp_offset);
311d974db0aSgarbled 	(void)cs_io_read_2(sc, PORT_PKTPG_PTR);
312d974db0aSgarbled 	return (cs_io_read_2(sc, PORT_PKTPG_DATA));
313d974db0aSgarbled }
314d974db0aSgarbled 
315d974db0aSgarbled static void
cs_writereg(struct cs_softc * sc,uint pp_offset,uint16_t value)316d974db0aSgarbled cs_writereg(struct cs_softc *sc, uint pp_offset, uint16_t value)
317d974db0aSgarbled {
318d974db0aSgarbled 	cs_io_write_2(sc, PORT_PKTPG_PTR, pp_offset);
319d974db0aSgarbled 	(void)cs_io_read_2(sc, PORT_PKTPG_PTR);
320d974db0aSgarbled 	cs_io_write_2(sc, PORT_PKTPG_DATA, value);
321d974db0aSgarbled 	(void)cs_io_read_2(sc, PORT_PKTPG_DATA);
322d974db0aSgarbled }
323d974db0aSgarbled 
324d974db0aSgarbled static int
cs_wait_eeprom_ready(struct cs_softc * sc)325d974db0aSgarbled cs_wait_eeprom_ready(struct cs_softc *sc)
326d974db0aSgarbled {
327d974db0aSgarbled 	int ms;
328d974db0aSgarbled 
329d974db0aSgarbled 	/*
330d974db0aSgarbled 	 * Check to see if the EEPROM is ready, a timeout is used -
331d974db0aSgarbled 	 * just in case EEPROM is ready when SI_BUSY in the
332d974db0aSgarbled 	 * PP_SelfST is clear.
333d974db0aSgarbled 	 */
334d974db0aSgarbled 	ms = 0;
335d974db0aSgarbled 	while(cs_readreg(sc, PKTPG_SELF_ST) & SELF_ST_SI_BUSY) {
336d974db0aSgarbled 		delay(1000);
337d974db0aSgarbled 		if (ms++ > 20)
338d974db0aSgarbled 			return 0;
339d974db0aSgarbled 	}
340d974db0aSgarbled 	return 1;
341d974db0aSgarbled }
342d974db0aSgarbled 
343d974db0aSgarbled static void
cs_wr_eeprom(struct cs_softc * sc,uint16_t offset,uint16_t data)344d974db0aSgarbled cs_wr_eeprom(struct cs_softc *sc, uint16_t offset, uint16_t data)
345d974db0aSgarbled {
346d974db0aSgarbled 
347d974db0aSgarbled 	/* Check to make sure EEPROM is ready. */
348d974db0aSgarbled 	if (!cs_wait_eeprom_ready(sc)) {
3493b0a685fStsutsui 		printf("%s: write EEPROM not ready\n",
3503b0a685fStsutsui 		    device_xname(sc->sc_dev));
351d974db0aSgarbled 		return;
352d974db0aSgarbled 	}
353d974db0aSgarbled 
354d974db0aSgarbled 	/* Enable writing. */
355d974db0aSgarbled 	cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_WRITE_ENABLE);
356d974db0aSgarbled 
357d974db0aSgarbled 	/* Wait for WRITE_ENABLE command to complete. */
358d974db0aSgarbled 	if (!cs_wait_eeprom_ready(sc)) {
3593b0a685fStsutsui 		printf("%s: EEPROM WRITE_ENABLE timeout",
3603b0a685fStsutsui 		    device_xname(sc->sc_dev));
361d974db0aSgarbled 	} else {
362d974db0aSgarbled 		/* Write data into EEPROM_DATA register. */
363d974db0aSgarbled 		cs_writereg(sc, PKTPG_EEPROM_DATA, data);
364d974db0aSgarbled 		delay(1000);
365d974db0aSgarbled 		cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_CMD_WRITE | offset);
366d974db0aSgarbled 
367d974db0aSgarbled 		/* Wait for WRITE_REGISTER command to complete. */
368d974db0aSgarbled 		if (!cs_wait_eeprom_ready(sc)) {
369d974db0aSgarbled 			printf("%s: EEPROM WRITE_REGISTER timeout\n",
3703b0a685fStsutsui 			    device_xname(sc->sc_dev));
371d974db0aSgarbled 		}
372d974db0aSgarbled 	}
373d974db0aSgarbled 
374d974db0aSgarbled 	/* Disable writing. */
375d974db0aSgarbled 	cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_WRITE_DISABLE);
376d974db0aSgarbled 
377d974db0aSgarbled 	/* Wait for WRITE_DISABLE command to complete. */
378d974db0aSgarbled 	if (!cs_wait_eeprom_ready(sc)) {
3793b0a685fStsutsui 		printf("%s: WRITE_DISABLE timeout\n", device_xname(sc->sc_dev));
380d974db0aSgarbled 	}
381d974db0aSgarbled }
382d974db0aSgarbled 
383d974db0aSgarbled static uint16_t
cs_rd_eeprom(struct cs_softc * sc,uint16_t offset)384d974db0aSgarbled cs_rd_eeprom(struct cs_softc *sc, uint16_t offset)
385d974db0aSgarbled {
386d974db0aSgarbled 
387d974db0aSgarbled 	if (!cs_wait_eeprom_ready(sc)) {
3883b0a685fStsutsui 		printf("%s: read EEPROM not ready\n", device_xname(sc->sc_dev));
389d974db0aSgarbled 		return 0;
390d974db0aSgarbled 	}
391d974db0aSgarbled 	cs_writereg(sc, PKTPG_EEPROM_CMD, EEPROM_CMD_READ | offset);
392d974db0aSgarbled 
393d974db0aSgarbled 	if (!cs_wait_eeprom_ready(sc)) {
3943b0a685fStsutsui 		printf("%s: EEPROM_READ timeout\n", device_xname(sc->sc_dev));
395d974db0aSgarbled 		return 0;
396d974db0aSgarbled 	}
397d974db0aSgarbled 	return cs_readreg(sc, PKTPG_EEPROM_DATA);
398d974db0aSgarbled }
399d974db0aSgarbled 
400d974db0aSgarbled static void
cs_check_eeprom(struct cs_softc * sc)401d974db0aSgarbled cs_check_eeprom(struct cs_softc *sc)
402d974db0aSgarbled {
403d974db0aSgarbled 	uint8_t checksum;
404d974db0aSgarbled 	int i;
405d974db0aSgarbled         uint16_t tmp;
406d974db0aSgarbled 
407d974db0aSgarbled 	/*
408d974db0aSgarbled 	 * If the SELFST[EEPROMOK] is set, then assume EEPROM configuration
409d974db0aSgarbled 	 * is valid.
410d974db0aSgarbled 	 */
411d974db0aSgarbled 	if (cs_readreg(sc, PKTPG_SELF_ST) & SELF_ST_EEP_OK) {
412d974db0aSgarbled 		printf("%s: EEPROM OK, skipping initialization\n",
4133b0a685fStsutsui 		    device_xname(sc->sc_dev));
414d974db0aSgarbled 		return;
415d974db0aSgarbled 	}
4163b0a685fStsutsui 	printf("%s: updating EEPROM\n", device_xname(sc->sc_dev));
417d974db0aSgarbled 
418d974db0aSgarbled 	/*
419d974db0aSgarbled 	 * Calculate the size (in bytes) of the default config array and write
420d974db0aSgarbled 	 * it to the lower byte of the array itself.
421d974db0aSgarbled 	 */
422d974db0aSgarbled 	default_eeprom_cfg[0] |= sizeof(default_eeprom_cfg);
423d974db0aSgarbled 
424d974db0aSgarbled 	/*
425d974db0aSgarbled 	 * Read the MAC address from its Artesyn-specified offset in the EEPROM.
426d974db0aSgarbled 	 */
427d974db0aSgarbled 	for (i = 0; i < 3; i++) {
428d974db0aSgarbled 		tmp = cs_rd_eeprom(sc, ATSN_EEPROM_MAC_OFFSET + i);
429d974db0aSgarbled 		default_eeprom_cfg[EEPROM_MAC + i] = bswap16(tmp);
430d974db0aSgarbled 	}
431d974db0aSgarbled 
432d974db0aSgarbled 	/*
433d974db0aSgarbled 	 * Program the EEPROM with our default configuration,
434d974db0aSgarbled 	 * calculating checksum as we proceed.
435d974db0aSgarbled 	 */
436d974db0aSgarbled 	checksum = 0;
437d974db0aSgarbled 	for (i = 0; i < sizeof(default_eeprom_cfg)/2 ; i++) {
438d974db0aSgarbled 		tmp = default_eeprom_cfg[i];
439d974db0aSgarbled 		cs_wr_eeprom(sc, i, tmp);
440d974db0aSgarbled 		checksum += tmp >> 8;
441d974db0aSgarbled 		checksum += tmp & 0xff;
442d974db0aSgarbled 	}
443d974db0aSgarbled 
444d974db0aSgarbled 	/*
445d974db0aSgarbled 	 * The CS8900a datasheet calls for the two's complement of the checksum
446d974db0aSgarbled 	 * to be prgrammed in the most significant byte of the last word of the
447d974db0aSgarbled 	 * header.
448d974db0aSgarbled 	 */
449d974db0aSgarbled 	checksum = ~checksum + 1;
450d974db0aSgarbled 	cs_wr_eeprom(sc, i++, checksum << 8);
451d974db0aSgarbled 	/* write "end of data" flag */
452d974db0aSgarbled 	cs_wr_eeprom(sc, i, 0xffff);
453d974db0aSgarbled }
454