if_cs.c revision 1.1
1/*	$NetBSD: if_cs.c,v 1.1 2004/01/03 14:31:28 chris Exp $	*/
2
3/*
4 * Copyright 1997
5 * Digital Equipment Corporation. All rights reserved.
6 *
7 * This software is furnished under license and may be used and
8 * copied only in accordance with the following terms and conditions.
9 * Subject to these conditions, you may download, copy, install,
10 * use, modify and distribute this software in source and/or binary
11 * form. No title or ownership is transferred hereby.
12 *
13 * 1) Any source code used, modified or distributed must reproduce
14 *    and retain this copyright notice and list of conditions as
15 *    they appear in the source file.
16 *
17 * 2) No right is granted to use any trade name, trademark, or logo of
18 *    Digital Equipment Corporation. Neither the "Digital Equipment
19 *    Corporation" name nor any trademark or logo of Digital Equipment
20 *    Corporation may be used to endorse or promote products derived
21 *    from this software without the prior written permission of
22 *    Digital Equipment Corporation.
23 *
24 * 3) This software is provided "AS-IS" and any express or implied
25 *    warranties, including but not limited to, any implied warranties
26 *    of merchantability, fitness for a particular purpose, or
27 *    non-infringement are disclaimed. In no event shall DIGITAL be
28 *    liable for any damages whatsoever, and in particular, DIGITAL
29 *    shall not be liable for special, indirect, consequential, or
30 *    incidental damages or damages for lost profits, loss of
31 *    revenue or loss of use, whether such damages arise in contract,
32 *    negligence, tort, under statute, in equity, at law or otherwise,
33 *    even if advised of the possibility of such damage.
34 */
35
36#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: if_cs.c,v 1.1 2004/01/03 14:31:28 chris Exp $");
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/socket.h>
42#include <sys/device.h>
43
44#include "rnd.h"
45#if NRND > 0
46#include <sys/rnd.h>
47#endif
48
49#include <net/if.h>
50#include <net/if_ether.h>
51#include <net/if_media.h>
52
53#include <machine/bus.h>
54#include <machine/intr.h>
55
56#include <sys/queue.h>
57#include <uvm/uvm.h>
58#include <machine/pmap.h>
59
60#include <acorn32/eb7500atx/rsbus.h>
61
62#include <dev/ic/cs89x0reg.h>
63#include <dev/ic/cs89x0var.h>
64
65/*
66 * the CS network interface is accessed at the following address locations:
67 * 030104f1 		CS8920 PNP Low
68 * 03010600 03010640	CS8920 Default I/O registers
69 * 030114f1 		CS8920 PNP High
70 * 03014000 03016000	CS8920 Default Memory
71 *
72 * IRQ is mapped as:
73 * CS8920 IRQ 3 	INT5
74 *
75 * It must be configured as the following:
76 * The CS8920 PNP address should be configured for ISA base at 0x300
77 * to achieve the default register mapping as specified.
78 * Note memory addresses are all have bit 23 tied high in hardware.
79 * This only effects the value programmed into the CS8920 memory offset
80 * registers.
81 *
82 * Just to add to the fun the I/O registers are layed out as:
83 * xxxxR1R0
84 * xxxxR3R2
85 * xxxxR5R4
86 *
87 * This makes access to single registers hard (which does happen on a reset,
88 * as we've got to toggle the chip into 16bit mode)
89 *
90 * Network DRQ is connected to DRQ5
91 */
92
93/*
94 * make a private tag so that we can use mainbus's map/unmap
95 */
96static struct bus_space cs_rsbus_bs_tag;
97
98int	cs_pioc_probe __P((struct device *, struct cfdata *, void *));
99void	cs_pioc_attach __P((struct device *, struct device *, void *));
100
101static u_int8_t cs_rbus_read_1(struct cs_softc *, bus_size_t);
102
103CFATTACH_DECL(cs_rsbus, sizeof(struct cs_softc),
104	cs_pioc_probe, cs_pioc_attach, NULL, NULL);
105
106/* Available media */
107int cs_rbus_media [] = {
108	IFM_ETHER|IFM_10_T,
109	IFM_ETHER|IFM_10_T|IFM_FDX
110};
111
112
113int
114cs_pioc_probe(parent, cf, aux)
115	struct device *parent;
116	struct cfdata *cf;
117	void *aux;
118{
119	/* for now it'll always attach */
120	return 1;
121}
122#if 0
123	struct isa_attach_args *ia = aux;
124	bus_space_tag_t iot = ia->ia_iot;
125	bus_space_tag_t memt = ia->ia_memt;
126	bus_space_handle_t ioh, memh;
127	struct cs_softc sc;
128	int rv = 0, have_io = 0, have_mem = 0;
129	u_int16_t isa_cfg, isa_membase;
130	int maddr, irq;
131
132	if (ia->ia_nio < 1)
133		return (0);
134	if (ia->ia_nirq < 1)
135		return (0);
136
137	if (ISA_DIRECT_CONFIG(ia))
138		return (0);
139
140	/*
141	 * Disallow wildcarded I/O base.
142	 */
143	if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
144		return (0);
145
146	if (ia->ia_niomem > 0)
147		maddr = ia->ia_iomem[0].ir_addr;
148	else
149		maddr = ISACF_IOMEM_DEFAULT;
150
151	/*
152	 * Map the I/O space.
153	 */
154	if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, CS8900_IOSIZE,
155	    0, &ioh))
156		goto out;
157	have_io = 1;
158
159	memset(&sc, 0, sizeof sc);
160	sc.sc_iot = iot;
161	sc.sc_ioh = ioh;
162	/* Verify that it's a Crystal product. */
163	if (CS_READ_PACKET_PAGE_IO(&sc, PKTPG_EISA_NUM) !=
164	    EISA_NUM_CRYSTAL)
165		goto out;
166
167	/*
168	 * Verify that it's a supported chip.
169	 */
170	switch (CS_READ_PACKET_PAGE_IO(&sc, PKTPG_PRODUCT_ID) &
171	    PROD_ID_MASK) {
172	case PROD_ID_CS8900:
173#ifdef notyet
174	case PROD_ID_CS8920:
175	case PROD_ID_CS8920M:
176#endif
177		rv = 1;
178	}
179
180	/*
181	 * If the IRQ or memory address were not specified, read the
182	 * ISA_CFG EEPROM location.
183	 */
184	if (maddr == ISACF_IOMEM_DEFAULT ||
185	    ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT) {
186		if (cs_verify_eeprom(&sc) == CS_ERROR) {
187			printf("cs_isa_probe: EEPROM bad or missing\n");
188			goto out;
189		}
190		if (cs_read_eeprom(&sc, EEPROM_ISA_CFG, &isa_cfg)
191		    == CS_ERROR) {
192			printf("cs_isa_probe: unable to read ISA_CFG\n");
193			goto out;
194		}
195	}
196
197	/*
198	 * If the IRQ wasn't specified, get it from the EEPROM.
199	 */
200	if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT) {
201		irq = isa_cfg & ISA_CFG_IRQ_MASK;
202		if (irq == 3)
203			irq = 5;
204		else
205			irq += 10;
206	} else
207		irq = ia->ia_irq[0].ir_irq;
208
209	/*
210	 * If the memory address wasn't specified, get it from the EEPROM.
211	 */
212	if (maddr == ISACF_IOMEM_DEFAULT) {
213		if ((isa_cfg & ISA_CFG_MEM_MODE) == 0) {
214			/* EEPROM says don't use memory mode. */
215			goto out;
216		}
217		if (cs_read_eeprom(&sc, EEPROM_MEM_BASE, &isa_membase)
218		    == CS_ERROR) {
219			printf("cs_isa_probe: unable to read MEM_BASE\n");
220			goto out;
221		}
222
223		isa_membase &= MEM_BASE_MASK;
224		maddr = (int)isa_membase << 8;
225	}
226
227	/*
228	 * We now have a valid mem address; attempt to map it.
229	 */
230	if (bus_space_map(ia->ia_memt, maddr, CS8900_MEMSIZE, 0, &memh)) {
231		/* Can't map it; fall back on i/o-only mode. */
232		printf("cs_isa_probe: unable to map memory space\n");
233		maddr = ISACF_IOMEM_DEFAULT;
234	} else
235		have_mem = 1;
236
237 out:
238	if (have_io)
239		bus_space_unmap(iot, ioh, CS8900_IOSIZE);
240	if (have_mem)
241		bus_space_unmap(memt, memh, CS8900_MEMSIZE);
242
243	if (rv) {
244		ia->ia_nio = 1;
245		ia->ia_io[0].ir_size = CS8900_IOSIZE;
246
247		if (maddr == ISACF_IOMEM_DEFAULT)
248			ia->ia_niomem = 0;
249		else {
250			ia->ia_niomem = 1;
251			ia->ia_iomem[0].ir_addr = maddr;
252			ia->ia_iomem[0].ir_size = CS8900_MEMSIZE;
253		}
254
255		ia->ia_nirq = 1;
256		ia->ia_irq[0].ir_irq = irq;
257	}
258	return (rv);
259}
260#endif
261void
262cs_pioc_attach(parent, self, aux)
263	struct device *parent, *self;
264	void *aux;
265{
266	struct cs_softc *sc = (struct cs_softc *)self;
267	struct rsbus_attach_args *rs = (void *)aux;
268	u_int iobase;
269
270	/* member copy */
271	cs_rsbus_bs_tag = *rs->sa_iot;
272
273	/* registers are 4 byte aligned */
274	cs_rsbus_bs_tag.bs_cookie = (void *) 1;
275
276	sc->sc_iot = sc->sc_memt = &cs_rsbus_bs_tag;
277
278	/*
279	 * Do DMA later
280	if (ia->ia_ndrq > 0)
281		isc->sc_drq = ia->ia_drq[0].ir_drq;
282	else
283		isc->sc_drq = -1;
284	*/
285
286	/* device always interrupts on 3 but that routes to IRQ 5 */
287	sc->sc_irq = 3;
288
289	printf("\n");
290
291	/*
292	 * Map the device.
293	 */
294	iobase = 0x03010600;
295	printf("mapping iobase=0x%08x, for 0x%08x\n", iobase, CS8900_IOSIZE * 4);
296	if (bus_space_map(sc->sc_iot, iobase, CS8900_IOSIZE * 4,
297	    0, &sc->sc_ioh)) {
298		printf("%s: unable to map i/o space\n", sc->sc_dev.dv_xname);
299		return;
300	}
301
302#if 0
303	bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, PORT_PKTPG_PTR, PKTPG_EISA_NUM);
304
305	productID = bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, PORT_PKTPG_DATA);
306
307	printf("Result ID = 0x%08x\n", productID);
308	printf("cookie = %p\n", sc->sc_iot->bs_cookie);
309	{
310		volatile uint32_t *ptr =  (void*) ((char *)((sc)->sc_ioh) + (PORT_PKTPG_PTR  << 1));
311		volatile uint32_t *data =(void *)((char *)((sc)->sc_ioh) + (PORT_PKTPG_DATA  << 1));
312		volatile char *pnplow = (char *)trunc_page((sc)->sc_ioh) + 0x4f1;
313		bus_space_handle_t tag2;
314		pt_entry_t *pte;
315
316		printf("ioh = %p, ptr = %p, data = %p\n", (void*)(sc)->sc_ioh, ptr, data);
317		*ptr = PKTPG_EISA_NUM;
318		productID = *data;
319		printf("Result ID2 = 0x%08x\n", productID);
320
321		pte = vtopte(trunc_page((sc)->sc_ioh));
322		printf("pte = %p, *pte =  0x%08x\n", pte, *pte);
323		printf("pnplow = %p, *pnplow = 0x%02x\n", pnplow, *pnplow);
324
325		if (bus_space_map(sc->sc_iot, 0x03011000, 0x1000,
326					0, &tag2)) {
327		printf("%s: unable to map i/o space\n", sc->sc_dev.dv_xname);
328		return;
329		}
330		pnplow = (char *)trunc_page(tag2) + 0x4f1;
331		printf("pnplow = %p, *pnplow = 0x%02x\n", pnplow, *pnplow);
332
333		*pnplow = 0x3;
334
335		*ptr = PKTPG_EISA_NUM;
336		productID = *data;
337		printf("Result ID2 = 0x%08x\n", productID);
338	}
339#endif
340
341#if 0
342	/*
343	 * Map the memory space if it was specified.  If we can do this,
344	 * we set ourselves up to use memory mode forever.  Otherwise,
345	 * we fall back on I/O mode.
346	 */
347	if (ia->ia_iomem[0].ir_addr != ISACF_IOMEM_DEFAULT &&
348	    ia->ia_iomem[0].ir_size == CS8900_MEMSIZE &&
349	    CS8900_MEMBASE_ISVALID(ia->ia_iomem[0].ir_addr)) {
350#endif
351#if 0
352	printf("mapping iobase=0x%08x, for 0x%08x\n", iobase + 0x3A00,
353			CS8900_MEMSIZE * 4);
354		if (bus_space_map(sc->sc_memt, iobase + 0x3A00,
355					CS8900_MEMSIZE * 4, 0, &sc->sc_memh)) {
356			printf("%s: unable to map memory space\n",
357			    sc->sc_dev.dv_xname);
358		} else {
359			sc->sc_cfgflags |= CFGFLG_MEM_MODE;
360			sc->sc_pktpgaddr = iobase + 0x3A00;
361		}
362#endif
363
364	printf("Claiming IRQ\n");
365		sc->sc_ih = intr_claim(0x0B, IPL_NET, "cs", cs_intr, sc);
366	if (sc->sc_ih == NULL) {
367		printf("%s: unable to establish interrupt\n",
368		    sc->sc_dev.dv_xname);
369		return;
370	}
371
372	/* DMA is for later */
373	sc->sc_dma_chipinit = NULL;
374	sc->sc_dma_attach = NULL;
375	sc->sc_dma_process_rx = NULL;
376
377	printf("Cs attach addr: 0x%04x\n", CS_READ_PACKET_PAGE(sc, PKTPG_IND_ADDR));
378
379	/* don't talk to the EEPROM, it seems that the cs driver doesn't use a
380	 * normal layout */
381	sc->sc_cfgflags |= CFGFLG_NOT_EEPROM;
382	sc->sc_io_read_1 = cs_rbus_read_1;
383	cs_attach(sc, NULL, cs_rbus_media, sizeof(cs_rbus_media) / sizeof(cs_rbus_media[0]),
384			IFM_ETHER|IFM_10_T|IFM_FDX);
385}
386
387static u_int8_t
388cs_rbus_read_1(struct cs_softc *sc, bus_size_t a)
389{
390	bus_size_t offset;
391	/* this is rather warped if it's an even address then just use the
392	 * bus_space_read_1
393	 */
394	if ((a & 1) == 0)
395	{
396		return bus_space_read_1(sc->sc_iot, sc->sc_ioh, a);
397	}
398	/* otherwise we've get to work out the aligned address and then add
399	 * one */
400	/* first work out the offset */
401	offset = (a & ~1) << 1;
402	/* add the one */
403	offset++;
404
405	/* and read it, with no shift */
406	return sc->sc_iot->bs_r_1(0, (sc)->sc_ioh, offset);
407}
408