necpb.c revision 1.14
1/*	$NetBSD: necpb.c,v 1.14 2003/01/01 00:32:05 thorpej Exp $	*/
2
3/*-
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the NetBSD
22 *	Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 *    contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
42 * Copyright (c) 1994 Charles M. Hannum.  All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 *    notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 *    notice, this list of conditions and the following disclaimer in the
51 *    documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 *    must display the following acknowledgement:
54 *	This product includes software developed by Charles M. Hannum.
55 * 4. The name of the author may not be used to endorse or promote products
56 *    derived from this software without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
59 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
60 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
61 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
62 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
63 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
64 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
65 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
66 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
67 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68 */
69
70#include <sys/types.h>
71#include <sys/param.h>
72#include <sys/time.h>
73#include <sys/systm.h>
74#include <sys/errno.h>
75#include <sys/device.h>
76#include <sys/malloc.h>
77#include <sys/extent.h>
78
79#include <uvm/uvm_extern.h>
80
81#define _ARC_BUS_DMA_PRIVATE
82#include <machine/bus.h>
83
84#include <machine/pio.h>
85
86#include <machine/autoconf.h>
87#include <machine/cpu.h>
88#include <machine/platform.h>
89
90#include <dev/pci/pcivar.h>
91#include <dev/pci/pcireg.h>
92
93#include <arc/jazz/rd94.h>
94#include <arc/pci/necpbvar.h>
95
96int	necpbmatch __P((struct device *, struct cfdata *, void *));
97void	necpbattach __P((struct device *, struct device *, void *));
98
99static	int	necpbprint __P((void *, const char *));
100
101void		necpb_attach_hook __P((struct device *, struct device *,
102		    struct pcibus_attach_args *));
103int		necpb_bus_maxdevs __P((pci_chipset_tag_t, int));
104pcitag_t	necpb_make_tag __P((pci_chipset_tag_t, int, int, int));
105void		necpb_decompose_tag __P((pci_chipset_tag_t, pcitag_t, int *,
106		    int *, int *));
107pcireg_t	necpb_conf_read __P((pci_chipset_tag_t, pcitag_t, int));
108void		necpb_conf_write __P((pci_chipset_tag_t, pcitag_t, int,
109		    pcireg_t));
110int		necpb_intr_map __P((struct pci_attach_args *,
111		    pci_intr_handle_t *));
112const char *	necpb_intr_string __P((pci_chipset_tag_t, pci_intr_handle_t));
113void *		necpb_intr_establish __P((pci_chipset_tag_t, pci_intr_handle_t,
114		    int, int (*func)(void *), void *));
115void		necpb_intr_disestablish __P((pci_chipset_tag_t, void *));
116
117int		necpb_intr(unsigned, struct clockframe *);
118
119
120CFATTACH_DECL(necpb, sizeof(struct necpb_softc),
121    necpbmatch, necpbattach, NULL, NULL);
122
123extern struct cfdriver necpb_cd;
124
125static struct necpb_intrhand	*necpb_inttbl[4];
126
127/* There can be only one. */
128int necpbfound;
129struct necpb_context necpb_main_context;
130static long necpb_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(10) / sizeof(long)];
131static long necpb_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(10) / sizeof(long)];
132
133int
134necpbmatch(parent, match, aux)
135	struct device *parent;
136	struct cfdata *match;
137	void *aux;
138{
139	struct confargs *ca = aux;
140
141	if (strcmp(ca->ca_name, necpb_cd.cd_name) != 0)
142		return (0);
143
144	if (necpbfound)
145		return (0);
146
147	return (1);
148}
149
150/*
151 * Set up the chipset's function pointers.
152 */
153void
154necpb_init(ncp)
155	struct necpb_context *ncp;
156{
157	pcitag_t tag;
158	pcireg_t csr;
159
160	if (ncp->nc_initialized)
161		return;
162
163	arc_large_bus_space_init(&ncp->nc_memt, "necpcimem",
164	    RD94_P_PCI_MEM, 0, RD94_S_PCI_MEM);
165	arc_bus_space_init_extent(&ncp->nc_memt, (caddr_t)necpb_mem_ex_storage,
166	    sizeof(necpb_mem_ex_storage));
167
168	arc_bus_space_init(&ncp->nc_iot, "necpciio",
169	    RD94_P_PCI_IO, RD94_V_PCI_IO, 0, RD94_S_PCI_IO);
170	arc_bus_space_init_extent(&ncp->nc_iot, (caddr_t)necpb_io_ex_storage,
171	    sizeof(necpb_io_ex_storage));
172
173	jazz_bus_dma_tag_init(&ncp->nc_dmat);
174
175	ncp->nc_pc.pc_attach_hook = necpb_attach_hook;
176	ncp->nc_pc.pc_bus_maxdevs = necpb_bus_maxdevs;
177	ncp->nc_pc.pc_make_tag = necpb_make_tag;
178	ncp->nc_pc.pc_decompose_tag = necpb_decompose_tag;
179	ncp->nc_pc.pc_conf_read = necpb_conf_read;
180	ncp->nc_pc.pc_conf_write = necpb_conf_write;
181	ncp->nc_pc.pc_intr_map = necpb_intr_map;
182	ncp->nc_pc.pc_intr_string = necpb_intr_string;
183	ncp->nc_pc.pc_intr_establish = necpb_intr_establish;
184	ncp->nc_pc.pc_intr_disestablish = necpb_intr_disestablish;
185
186	/*
187	 * XXX:
188	 *  NEC's firmware does not configure PCI devices completely.
189	 *  We need to disable expansion ROM and enable mem/io/busmaster
190	 *  bits here.
191	 */
192	tag = necpb_make_tag(&ncp->nc_pc, 0, 3, 0);
193	csr = necpb_conf_read(&ncp->nc_pc, tag, PCI_COMMAND_STATUS_REG);
194	csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
195	    PCI_COMMAND_MASTER_ENABLE;
196	necpb_conf_write(&ncp->nc_pc, tag, PCI_COMMAND_STATUS_REG, csr);
197	necpb_conf_write(&ncp->nc_pc, tag, PCI_MAPREG_ROM, 0);
198
199	tag = necpb_make_tag(&ncp->nc_pc, 0, 4, 0);
200	csr = necpb_conf_read(&ncp->nc_pc, tag, PCI_COMMAND_STATUS_REG);
201	csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
202	    PCI_COMMAND_MASTER_ENABLE;
203	necpb_conf_write(&ncp->nc_pc, tag, PCI_COMMAND_STATUS_REG, csr);
204	necpb_conf_write(&ncp->nc_pc, tag, PCI_MAPREG_ROM, 0);
205
206	tag = necpb_make_tag(&ncp->nc_pc, 0, 5, 0);
207	csr = necpb_conf_read(&ncp->nc_pc, tag, PCI_COMMAND_STATUS_REG);
208	csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
209	    PCI_COMMAND_MASTER_ENABLE;
210	necpb_conf_write(&ncp->nc_pc, tag, PCI_COMMAND_STATUS_REG, csr);
211	necpb_conf_write(&ncp->nc_pc, tag, PCI_MAPREG_ROM, 0);
212
213	ncp->nc_initialized = 1;
214}
215
216void
217necpbattach(parent, self, aux)
218	struct device *parent, *self;
219	void *aux;
220{
221	struct necpb_softc *sc = (struct necpb_softc *)self;
222	struct pcibus_attach_args pba;
223	int i;
224
225	necpbfound = 1;
226
227	printf("\n");
228
229	sc->sc_ncp = &necpb_main_context;
230	necpb_init(sc->sc_ncp);
231
232	out32(RD94_SYS_PCI_INTMASK, 0xf);
233
234	for (i = 0; i < 4; i++)
235		necpb_inttbl[i] = NULL;
236
237	(*platform->set_intr)(MIPS_INT_MASK_2, necpb_intr, 3);
238
239	pba.pba_busname = "pci";
240	pba.pba_iot = &sc->sc_ncp->nc_iot;
241	pba.pba_memt = &sc->sc_ncp->nc_memt;
242	pba.pba_dmat = &sc->sc_ncp->nc_dmat;
243	pba.pba_pc = &sc->sc_ncp->nc_pc;
244	pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
245	pba.pba_bus = 0;
246	pba.pba_bridgetag = NULL;
247
248	config_found(self, &pba, necpbprint);
249}
250
251static int
252necpbprint(aux, pnp)
253	void *aux;
254	const char *pnp;
255{
256	struct pcibus_attach_args *pba = aux;
257
258	if (pnp)
259		aprint_normal("%s at %s", pba->pba_busname, pnp);
260	aprint_normal(" bus %d", pba->pba_bus);
261	return (UNCONF);
262}
263
264void
265necpb_attach_hook(parent, self, pba)
266	struct device *parent, *self;
267	struct pcibus_attach_args *pba;
268{
269}
270
271int
272necpb_bus_maxdevs(pc, busno)
273	pci_chipset_tag_t pc;
274	int busno;
275{
276	return (32);
277}
278
279pcitag_t
280necpb_make_tag(pc, bus, device, function)
281	pci_chipset_tag_t pc;
282	int bus, device, function;
283{
284	pcitag_t tag;
285
286	if (bus >= 256 || device >= 32 || function >= 8)
287		panic("necpb_make_tag: bad request");
288
289	tag = 0x80000000 | (bus << 16) | (device << 11) | (function << 8);
290	return (tag);
291}
292
293void
294necpb_decompose_tag(pc, tag, bp, dp, fp)
295	pci_chipset_tag_t pc;
296	pcitag_t tag;
297	int *bp, *dp, *fp;
298{
299	if (bp != NULL)
300		*bp = (tag >> 16) & 0xff;
301	if (dp != NULL)
302		*dp = (tag >> 11) & 0x1f;
303	if (fp != NULL)
304		*fp = (tag >> 8) & 0x07;
305}
306
307pcireg_t
308necpb_conf_read(pc, tag, reg)
309	pci_chipset_tag_t pc;
310	pcitag_t tag;
311	int reg;
312{
313	pcireg_t data;
314	int s;
315
316	s = splhigh();
317	out32(RD94_SYS_PCI_CONFADDR, tag | reg);
318	data = in32(RD94_SYS_PCI_CONFDATA);
319	out32(RD94_SYS_PCI_CONFADDR, 0);
320	splx(s);
321
322	return (data);
323}
324
325void
326necpb_conf_write(pc, tag, reg, data)
327	pci_chipset_tag_t pc;
328	pcitag_t tag;
329	int reg;
330	pcireg_t data;
331{
332	int s;
333
334	s = splhigh();
335	out32(RD94_SYS_PCI_CONFADDR, tag | reg);
336	out32(RD94_SYS_PCI_CONFDATA, data);
337	out32(RD94_SYS_PCI_CONFADDR, 0);
338	splx(s);
339}
340
341int
342necpb_intr_map(pa, ihp)
343	struct pci_attach_args *pa;
344	pci_intr_handle_t *ihp;
345{
346	pci_chipset_tag_t pc = pa->pa_pc;
347	pcitag_t intrtag = pa->pa_intrtag;
348	int pin = pa->pa_intrpin;
349	int bus, dev;
350
351	if (pin == 0) {
352		/* No IRQ used. */
353		*ihp = -1;
354		return (1);
355	}
356
357	if (pin > 4) {
358		printf("necpb_intr_map: bad interrupt pin %d\n", pin);
359		*ihp = -1;
360		return (1);
361	}
362
363	necpb_decompose_tag(pc, intrtag, &bus, &dev, NULL);
364	if (bus != 0) {
365		*ihp = -1;
366		return (1);
367	}
368
369	switch (dev) {
370	case 3:
371		*ihp = (pin+2) % 4;
372		break;
373	case 4:
374		*ihp = (pin+1) % 4;
375		break;
376	case 5:
377		*ihp = (pin) % 4;
378		break;
379	default:
380		*ihp = -1;
381		return (1);
382	}
383
384	return (0);
385}
386
387const char *
388necpb_intr_string(pc, ih)
389	pci_chipset_tag_t pc;
390	pci_intr_handle_t ih;
391{
392	static char str[8];
393
394	if (ih >= 4)
395		panic("necpb_intr_string: bogus handle %ld", ih);
396	sprintf(str, "int %c", 'A' + (int)ih);
397	return (str);
398}
399
400void *
401necpb_intr_establish(pc, ih, level, func, arg)
402	pci_chipset_tag_t pc;
403	pci_intr_handle_t ih;
404	int level, (*func) __P((void *));
405	void *arg;
406{
407	struct necpb_intrhand *n, *p;
408	u_int32_t	mask;
409
410	if (ih >= 4)
411		panic("necpb_intr_establish: bogus handle");
412
413	n = malloc(sizeof(struct necpb_intrhand), M_DEVBUF, M_NOWAIT);
414	if (n == NULL)
415		panic("necpb_intr_establish: can't malloc interrupt handle");
416
417	n->ih_func = func;
418	n->ih_arg = arg;
419	n->ih_next = NULL;
420	n->ih_intn = ih;
421
422	if (necpb_inttbl[ih] == NULL) {
423		necpb_inttbl[ih] = n;
424		mask = in32(RD94_SYS_PCI_INTMASK);
425		mask |= 1 << ih;
426		out32(RD94_SYS_PCI_INTMASK, mask);
427	} else {
428		p = necpb_inttbl[ih];
429		while (p->ih_next != NULL)
430			p = p->ih_next;
431		p->ih_next = n;
432	}
433
434	return n;
435}
436
437void
438necpb_intr_disestablish(pc, cookie)
439	pci_chipset_tag_t pc;
440	void *cookie;
441{
442	struct necpb_intrhand *n, *p, *q;
443	u_int32_t	mask;
444
445	n = cookie;
446
447	q = NULL;
448	p = necpb_inttbl[n->ih_intn];
449	while (p != n) {
450		if (p == NULL)
451			panic("necpb_intr_disestablish: broken intr table");
452		q = p;
453		p = p->ih_next;
454	}
455
456	if (q == NULL) {
457		necpb_inttbl[n->ih_intn] = n->ih_next;
458		if (n->ih_next == NULL) {
459			mask = in32(RD94_SYS_PCI_INTMASK);
460			mask &= ~(1 << n->ih_intn);
461			out32(RD94_SYS_PCI_INTMASK, mask);
462		}
463	} else
464		q->ih_next = n->ih_next;
465
466	free(n, M_DEVBUF);
467}
468
469/*
470 *   Handle PCI/EISA interrupt.
471 */
472int
473necpb_intr(mask, cf)
474	unsigned mask;
475	struct clockframe *cf;
476{
477	u_int32_t vector, stat;
478	struct necpb_intrhand *p;
479	int a;
480
481	vector = in32(RD94_SYS_INTSTAT2) & 0xffff;
482
483	if (vector == 0x4000) {
484		stat = in32(RD94_SYS_PCI_INTSTAT);
485		stat &= in32(RD94_SYS_PCI_INTMASK);
486		for (a=0; a<4; a++) {
487			if (stat & (1 << a)) {
488#if 0
489				printf("pint %d\n", a);
490#endif
491				p = necpb_inttbl[a];
492				while (p != NULL) {
493					(*p->ih_func)(p->ih_arg);
494					p = p->ih_next;
495				}
496			}
497		}
498	} else if (vector == 0x8000) {
499		printf("eisa_nmi\n");
500	} else {
501		printf("eint %d\n", vector & 0xff);
502#if 0
503		eisa_intr(vector & 0xff);
504#endif
505	}
506
507	return (~0);
508}
509