tnt4882.c revision 150157
1/*-
2 * Copyright (c) 2005 Poul-Henning Kamp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/ieee488/tnt4882.c 150157 2005-09-15 13:27:16Z phk $
27 */
28
29#include <sys/param.h>
30#include <sys/kernel.h>
31#include <sys/systm.h>
32#include <sys/module.h>
33#include <sys/bus.h>
34#include <dev/pci/pcireg.h>
35#include <dev/pci/pcivar.h>
36
37#include <machine/bus.h>
38#include <machine/resource.h>
39#include <machine/stdarg.h>
40#include <sys/rman.h>
41
42/* vtophys */
43#include <vm/vm.h>
44#include <vm/pmap.h>
45#include <machine/pmap.h>
46
47#define UPD7210_HW_DRIVER 1
48#include <dev/ieee488/upd7210.h>
49
50struct tnt_softc {
51	int foo;
52	struct upd7210		upd7210;
53
54	struct resource		*res0, *res1, *res2;
55	bus_space_tag_t		bt0, bt1;
56	bus_space_handle_t	bh0, bh1;
57	void			*intr_handler;
58};
59
60enum tnt4882reg {
61	dir = 0x00,
62	cdor = 0x00,
63	isr1 = 0x02,
64	imr1 = 0x02,
65	isr2 = 0x04,
66	imr2 = 0x04,
67	accwr = 0x05,
68	spsr = 0x06,
69	spmr = 0x06,
70	intr = 0x07,
71	adsr = 0x08,
72	admr = 0x08,
73	cnt2 = 0x09,
74	cptr = 0x0a,
75	auxmr = 0x0a,
76	tauxcr = 0x0a,	/* 9914 mode register */
77	cnt3 = 0x0b,
78	adr0 = 0x0c,
79	adr = 0x0c,
80	hssel = 0x0d,
81	adr1 = 0x0e,
82	eosr = 0x0e,
83	sts1 = 0x10,
84	cfg = 0x10,
85	dsr = 0x11,
86	sh_cnt = 0x11,
87	imr3 = 0x12,
88	hier = 0x13,
89	cnt0 = 0x14,
90	misc = 0x15,
91	cnt1 = 0x16,
92	csr = 0x17,
93	keyreg = 0x17,
94	fifob = 0x18,
95	fifoa = 0x19,
96	isr3 = 0x1a,
97	ccr = 0x1a,
98	sasr = 0x1b,
99	dcr = 0x1b,
100	sts2 = 0x1c,
101	cmdr = 0x1c,
102	isr0 = 0x1d,
103	imr0 = 0x1d,
104	timer = 0x1e,
105	bsr = 0x1f,
106	bcr = 0x1f
107};
108
109struct tst {
110	enum {RD, WT, xDELAY, END}
111				action;
112	enum tnt4882reg 	reg;
113	uint8_t			val;
114};
115
116/*
117 * From NI Application note 095:
118 *   Writing Functional Self-Tests for the TNT4882 GPIB Interface Chip
119 * XXX: fill in the rest ?
120 */
121static struct tst tst_reset[] = {
122	{WT, tauxcr, 0x80},	/* chip reset if in 9914 mode */
123	{WT, auxmr, 0x80},	/* swrst if swapped */
124	{WT, tauxcr, 0x99},	/* switch to 7210 mode */
125	{WT, auxmr, 0x99},	/* switch to 7210 mode if swapped */
126	{WT, auxmr, 0x02},	/* execute chip reset */
127	{WT, keyreg, 0x00},	/* important! clear the swap bit */
128	{WT, eosr, 0x00},	/* clear EOS register */
129	{WT, cdor, 0x00},	/* clear data lines */
130	{WT, imr1, 0x00},	/* disable all interrupts */
131	{WT, imr2, 0x00},
132	{WT, imr0, 0x80},
133	{WT, adr, 0x80},
134	{WT, adr, 0x00},
135	{WT, admr, 0x00},	/* clear addressing modes */
136	{WT, auxmr, 0x00},	/* release from idle state with pon */
137	{WT, auxmr, 0x60},	/* reset ppr */
138	{WT, bcr, 0x00},	/* reset bcr */
139	{WT, misc, 0x04},	/* set wrap plug bit */
140	{WT, cmdr, 0xB2},	/* issue soft reset */
141	{WT, hssel, 0x00},	/* select two-chip mode */
142	{END, 0, 0}
143};
144
145static struct tst tst_read_reg[] = {
146	{RD, isr1, 0x00},	/* Verify mask registers are clear */
147	{RD, isr2, 0x00},
148	{RD, adsr, 0x40},	/* Verify ATN is not asserted */
149	{RD, adr0, 0x00},	/* Verify Primary address not set */
150	{RD, adr1, 0x00},	/* Verify Secondary address not set */
151	{RD, sts1, 0x8B},	/* Verify DONE, STOP, HALT, and GSYNC set */
152	{RD, isr3, 0x19},	/* Verify STOP, Not Full FIFO, & DONE set */
153	{RD, sts2, 0x9A},	/* Verify FIFO A/B is empty */
154	{RD, sasr, 0x00},	/* Verify clear */
155	{RD, isr0, 0x01},	/* Verify SYNC bit is set */
156	{END, 0, 0}
157};
158
159static struct tst tst_bsr_dcr[] = {
160	{WT, bcr, 0x55},	/* Set DAV, NRFD, SRQ, and REN */
161	{WT, dcr, 0xAA},	/* Write pattern to GPIB data lines */
162	{RD, bsr, 0x55},	/* Verify DAV, NRFD, SRQ, and REN are set */
163	{RD, dsr, 0xAA},	/* Verify data pattern written previously */
164	{WT, bcr, 0xAA},	/* Set ATN, NDAC, EOI, & IFC */
165	{WT, dcr, 0x55},	/* Write pattern to GPIB data lines */
166	{RD, bsr, 0xAA},	/* Verify ATN, NDAC, EOI, & IFC are set */
167	{RD, dsr, 0x55},	/* Verify data pattern written previously */
168	{WT, bcr, 0x00},	/* Clear control lines */
169	{WT, dcr, 0x00},	/* Clear data lines */
170	{RD, bsr, 0x00},	/* Verify control lines are clear */
171	{RD, dsr, 0x00},	/* Verify data lines are clear */
172	{END, 0, 0}
173};
174
175static struct tst tst_adr0_1[] = {
176	{WT, adr, 0x55},	/* Set Primary talk address */
177	{WT, adr, 0xAA},	/* Set Secondary listen address */
178	{RD, adr0, 0x55},	/* Read Primary address */
179	{RD, adr1, 0x2A},	/* Read Secondary address */
180	{WT, adr, 0x2A},	/* Set Primay listen address */
181	{WT, adr, 0xD5},	/* Set Secondary talk address */
182	{RD, adr0, 0x2A},	/* Read Primary address */
183	{RD, adr1, 0x55},	/* Read Secondary address */
184	{END, 0, 0}
185};
186
187static struct tst tst_cdor_dir[] = {
188	{WT, admr, 0xF0},	/* program AT-GPIB as talker only and
189				 * listener only */
190	{RD, isr1, 0x02},	/* check DO bit set */
191	{RD, adsr, 0x46},	/* check AT-GPIB is both talker active
192				 * and listener active */
193	{WT, cdor, 0xAA},	/* write out data byte */
194	{xDELAY, 0, 1},		/* One ISA I/O Cycle (500-ns) */
195	{RD, isr1, 0x03},	/* check DO and DI bits set */
196	{RD, dir, 0xAA},	/* verify data received */
197	{WT, cdor, 0x55},	/* write out data byte */
198	{xDELAY, 0, 1},		/* One ISA I/O Cycle (500-ns) */
199	{RD, dir, 0x55},	/* verify data received */
200	{END, 0, 0}
201};
202
203static struct tst tst_spmr_spsr[] = {
204	{WT, spsr, 0x00},	/* Write pattern to SPSR register */
205	{RD, spmr, 0x00},	/* Read back previously written pattern */
206	{WT, spsr, 0xBF},	/* Write pattern to SPSR register */
207	{RD, spmr, 0xBF},	/* Read back previously written pattern */
208	{END, 0, 0}
209};
210
211static struct tst tst_count0_1[] = {
212	{WT, cnt0, 0x55}, 	/* Verify every other bit can be set */
213	{WT, cnt1, 0xAA},
214	{RD, cnt0, 0x55}, 	/* Read back previously written pattern */
215	{RD, cnt1, 0xAA},
216	{WT, cnt0, 0xAA}, 	/* Verify every other bit can be set */
217	{WT, cnt1, 0x55},
218	{RD, cnt0, 0xAA}, 	/* Read back previously written pattern */
219	{RD, cnt1, 0x55},
220	{END, 0, 0}
221};
222
223static int
224tst_exec(struct tnt_softc *sc, struct tst *tp, const char *name)
225{
226	uint8_t u;
227	int step;
228
229	for (step = 0; tp->action != END; tp++, step++) {
230		switch (tp->action) {
231		case WT:
232			bus_space_write_1(sc->bt1, sc->bh1, tp->reg, tp->val);
233			break;
234		case RD:
235			u = bus_space_read_1(sc->bt1, sc->bh1, tp->reg);
236			if (u != tp->val) {
237				printf(
238				    "Test %s, step %d: reg(%02x) = %02x",
239				    name, step, tp->reg, u);
240				printf( "should have been %02x\n", tp->val);
241				return (1);
242			}
243			break;
244		case xDELAY:
245			DELAY(tp->val);
246			break;
247		default:
248			printf("Unknown action in test %s, step %d: %d\n",
249			name, step, tp->action);
250			return (1);
251		}
252	}
253	if (bootverbose)
254		printf("Test %s passed\n", name);
255	return (0);
256}
257
258static int
259bus_dwiw(device_t dev, ...)
260{
261	va_list ap, ap2;
262	int	rid;
263	int	type;
264	int	flags;
265	struct resource **rp;
266	bus_space_tag_t *bt;
267	bus_space_handle_t *bh;
268
269	va_start(ap, dev);
270	va_copy(ap2, ap);
271	while (1) {
272		type = va_arg(ap, int);
273		if (type == -1) {
274			va_end(ap);
275			return (0);
276		}
277		rid = va_arg(ap, int);
278		flags = va_arg(ap, int);
279		rp = va_arg(ap, struct resource **);
280		*rp = bus_alloc_resource_any(dev, type, &rid, flags);
281		if (*rp == NULL)
282			break;
283		if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) {
284			bt = va_arg(ap, bus_space_tag_t *);
285			*bt = rman_get_bustag(*rp);
286			bh = va_arg(ap, bus_space_handle_t *);
287			*bh = rman_get_bushandle(*rp);
288		}
289	}
290	while (1) {
291		type = va_arg(ap2, int);
292		KASSERT(type != -1, ("bus_dwiw() internal mess"));
293		rid = va_arg(ap2, int);
294		flags = va_arg(ap2, int);
295		rp = va_arg(ap2, struct resource **);
296		if (*rp != NULL)
297			bus_release_resource(dev, type, rid, *rp);
298		else {
299			va_end(ap2);
300			return (ENXIO);
301		}
302		if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) {
303			bt = va_arg(ap2, bus_space_tag_t *);
304			bh = va_arg(ap2, bus_space_handle_t *);
305		}
306	}
307}
308static int
309tnt_probe(device_t dev)
310{
311
312	if (pci_get_vendor(dev) == 0x1093 && pci_get_device(dev) == 0xc801) {
313		device_set_desc(dev, "NI PCI-GPIB");
314		return (BUS_PROBE_DEFAULT);
315	}
316	return (ENXIO);
317}
318
319static int
320tnt_attach(device_t dev)
321{
322	struct tnt_softc *sc;
323	int error, i;
324
325	sc = device_get_softc(dev);
326
327	error = bus_dwiw(dev,
328	    SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE,
329		&sc->res0, &sc->bt0, &sc->bh0,
330	    SYS_RES_MEMORY, PCIR_BAR(1), RF_ACTIVE,
331		&sc->res1, &sc->bt1, &sc->bh1,
332	    SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE, &sc->res2,
333	    -1);
334	if (error)
335		return (error);
336
337	error = bus_setup_intr(dev, sc->res2, INTR_TYPE_MISC | INTR_MPSAFE,
338	    upd7210intr, &sc->upd7210, &sc->intr_handler);
339
340	/* Necessary magic for MITE */
341	bus_space_write_4(sc->bt0, sc->bh0, 0xc0, vtophys(sc->bh1) | 0x80);
342
343	tst_exec(sc, tst_reset, "Reset");
344	tst_exec(sc, tst_read_reg, "Read registers");
345	tst_exec(sc, tst_bsr_dcr, "BSR & DCR");
346	tst_exec(sc, tst_adr0_1, "ADR0,1");
347	tst_exec(sc, tst_cdor_dir, "CDOR/DIR");
348	tst_exec(sc, tst_spmr_spsr, "CPMR/SPSR");
349	tst_exec(sc, tst_count0_1, "COUNT0:1");
350	tst_exec(sc, tst_reset, "Reset");
351
352	/* pass 7210 interrupts through */
353	bus_space_write_1(sc->bt1, sc->bh1, imr3, 0x02);
354
355	for (i = 0; i < 8; i++) {
356		sc->upd7210.reg_tag[i] = sc->bt1;
357		sc->upd7210.reg_handle[i] = sc->bh1;
358		sc->upd7210.reg_offset[i] = i * 2;
359	}
360
361	/* No DMA help */
362	sc->upd7210.dmachan = -1;
363
364	upd7210attach(&sc->upd7210);
365
366	return (0);
367}
368
369static int
370tnt_detach(device_t dev)
371{
372	struct tnt_softc *sc;
373
374	sc = device_get_softc(dev);
375	bus_teardown_intr(dev, sc->res2, sc->intr_handler);
376	upd7210detach(&sc->upd7210);
377
378	bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->res0);
379	bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(1), sc->res1);
380	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->res2);
381
382	return (0);
383}
384
385static device_method_t	tnt4882_methods[] = {
386	DEVMETHOD(device_probe,		tnt_probe),
387	DEVMETHOD(device_attach,	tnt_attach),
388	DEVMETHOD(device_detach,	tnt_detach),
389	{ 0, 0 }
390};
391
392static driver_t pci_gpib_driver = {
393	"tnt4882",
394	tnt4882_methods,
395	sizeof(struct tnt_softc)
396};
397
398static devclass_t pci_gpib_devclass;
399
400DRIVER_MODULE(pci_gpib, pci, pci_gpib_driver, pci_gpib_devclass, 0, 0);
401