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