necpb.c revision 1.23
1/*	$NetBSD: necpb.c,v 1.23 2006/04/15 09:01:11 tsutsui 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/cdefs.h>
71__KERNEL_RCSID(0, "$NetBSD: necpb.c,v 1.23 2006/04/15 09:01:11 tsutsui Exp $");
72
73#include <sys/types.h>
74#include <sys/param.h>
75#include <sys/time.h>
76#include <sys/systm.h>
77#include <sys/errno.h>
78#include <sys/device.h>
79#include <sys/malloc.h>
80#include <sys/extent.h>
81
82#include <uvm/uvm_extern.h>
83
84#define _ARC_BUS_DMA_PRIVATE
85#include <machine/bus.h>
86
87#include <machine/pio.h>
88
89#include <machine/autoconf.h>
90#include <machine/cpu.h>
91#include <machine/platform.h>
92
93#include <dev/pci/pcivar.h>
94#include <dev/pci/pcireg.h>
95
96#include <arc/jazz/rd94.h>
97#include <arc/pci/necpbvar.h>
98
99#include "ioconf.h"
100
101int	necpbmatch(struct device *, struct cfdata *, void *);
102void	necpbattach(struct device *, struct device *, void *);
103
104void		necpb_attach_hook(struct device *, struct device *,
105		    struct pcibus_attach_args *);
106int		necpb_bus_maxdevs(pci_chipset_tag_t, int);
107pcitag_t	necpb_make_tag(pci_chipset_tag_t, int, int, int);
108void		necpb_decompose_tag(pci_chipset_tag_t, pcitag_t, int *,
109		    int *, int *);
110pcireg_t	necpb_conf_read(pci_chipset_tag_t, pcitag_t, int);
111void		necpb_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t);
112int		necpb_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
113const char *	necpb_intr_string(pci_chipset_tag_t, pci_intr_handle_t);
114void *		necpb_intr_establish(pci_chipset_tag_t, pci_intr_handle_t,
115		    int, int (*func)(void *), void *);
116void		necpb_intr_disestablish(pci_chipset_tag_t, void *);
117
118uint32_t	necpb_intr(uint32_t, struct clockframe *);
119
120
121CFATTACH_DECL(necpb, sizeof(struct necpb_softc),
122    necpbmatch, necpbattach, NULL, NULL);
123
124static struct necpb_intrhand	*necpb_inttbl[4];
125
126/* There can be only one. */
127int necpbfound;
128struct necpb_context necpb_main_context;
129static long necpb_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(10) / sizeof(long)];
130static long necpb_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(10) / sizeof(long)];
131
132int
133necpbmatch(struct device *parent, struct cfdata *match, void *aux)
134{
135	struct confargs *ca = aux;
136
137	if (strcmp(ca->ca_name, necpb_cd.cd_name) != 0)
138		return 0;
139
140	if (necpbfound)
141		return 0;
142
143	return 1;
144}
145
146/*
147 * Set up the chipset's function pointers.
148 */
149void
150necpb_init(struct necpb_context *ncp)
151{
152	pci_chipset_tag_t pc;
153	pcitag_t tag;
154	pcireg_t csr;
155
156	if (ncp->nc_initialized)
157		return;
158
159	arc_large_bus_space_init(&ncp->nc_memt, "necpcimem",
160	    RD94_P_PCI_MEM, 0, RD94_S_PCI_MEM);
161	arc_bus_space_init_extent(&ncp->nc_memt, (caddr_t)necpb_mem_ex_storage,
162	    sizeof(necpb_mem_ex_storage));
163
164	arc_bus_space_init(&ncp->nc_iot, "necpciio",
165	    RD94_P_PCI_IO, RD94_V_PCI_IO, 0, RD94_S_PCI_IO);
166	arc_bus_space_init_extent(&ncp->nc_iot, (caddr_t)necpb_io_ex_storage,
167	    sizeof(necpb_io_ex_storage));
168
169	jazz_bus_dma_tag_init(&ncp->nc_dmat);
170
171	pc = &ncp->nc_pc;
172	pc->pc_attach_hook = necpb_attach_hook;
173	pc->pc_bus_maxdevs = necpb_bus_maxdevs;
174	pc->pc_make_tag = necpb_make_tag;
175	pc->pc_decompose_tag = necpb_decompose_tag;
176	pc->pc_conf_read = necpb_conf_read;
177	pc->pc_conf_write = necpb_conf_write;
178	pc->pc_intr_map = necpb_intr_map;
179	pc->pc_intr_string = necpb_intr_string;
180	pc->pc_intr_establish = necpb_intr_establish;
181	pc->pc_intr_disestablish = necpb_intr_disestablish;
182
183	/*
184	 * XXX:
185	 *  NEC's firmware does not configure PCI devices completely.
186	 *  We need to disable expansion ROM and enable mem/io/busmaster
187	 *  bits here.
188	 */
189	tag = necpb_make_tag(pc, 0, 3, 0);
190	csr = necpb_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
191	csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
192	    PCI_COMMAND_MASTER_ENABLE;
193	necpb_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
194	necpb_conf_write(pc, tag, PCI_MAPREG_ROM, 0);
195
196	tag = necpb_make_tag(pc, 0, 4, 0);
197	csr = necpb_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
198	csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
199	    PCI_COMMAND_MASTER_ENABLE;
200	necpb_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
201	necpb_conf_write(pc, tag, PCI_MAPREG_ROM, 0);
202
203	tag = necpb_make_tag(pc, 0, 5, 0);
204	csr = necpb_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
205	csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
206	    PCI_COMMAND_MASTER_ENABLE;
207	necpb_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
208	necpb_conf_write(pc, tag, PCI_MAPREG_ROM, 0);
209
210	ncp->nc_initialized = 1;
211}
212
213void
214necpbattach(struct device *parent, struct device *self, void *aux)
215{
216	struct necpb_softc *sc = (struct necpb_softc *)self;
217	struct pcibus_attach_args pba;
218	pci_chipset_tag_t pc;
219	int i;
220
221	necpbfound = 1;
222
223	printf("\n");
224
225	sc->sc_ncp = &necpb_main_context;
226	necpb_init(sc->sc_ncp);
227
228	pc = &sc->sc_ncp->nc_pc;
229
230	out32(RD94_SYS_PCI_INTMASK, 0xf);
231
232	for (i = 0; i < 4; i++)
233		necpb_inttbl[i] = NULL;
234
235	(*platform->set_intr)(MIPS_INT_MASK_2, necpb_intr, 3);
236
237	pba.pba_iot = &sc->sc_ncp->nc_iot;
238	pba.pba_memt = &sc->sc_ncp->nc_memt;
239	pba.pba_dmat = &sc->sc_ncp->nc_dmat;
240	pba.pba_dmat64 = NULL;
241	pba.pba_pc = pc;
242	pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
243	pba.pba_bus = 0;
244	pba.pba_bridgetag = NULL;
245
246	config_found_ia(self, "pcibus", &pba, pcibusprint);
247}
248
249void
250necpb_attach_hook(struct device *parent, struct device *self,
251    struct pcibus_attach_args *pba)
252{
253}
254
255int
256necpb_bus_maxdevs(pci_chipset_tag_t pc, int busno)
257{
258
259	return 32;
260}
261
262pcitag_t
263necpb_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
264{
265	pcitag_t tag;
266
267	if (bus >= 256 || device >= 32 || function >= 8)
268		panic("necpb_make_tag: bad request");
269
270	tag = 0x80000000 | (bus << 16) | (device << 11) | (function << 8);
271	return tag;
272}
273
274void
275necpb_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp,
276   int *fp)
277{
278
279	if (bp != NULL)
280		*bp = (tag >> 16) & 0xff;
281	if (dp != NULL)
282		*dp = (tag >> 11) & 0x1f;
283	if (fp != NULL)
284		*fp = (tag >> 8) & 0x07;
285}
286
287pcireg_t
288necpb_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
289{
290	pcireg_t data;
291	int s;
292
293	s = splhigh();
294	out32(RD94_SYS_PCI_CONFADDR, tag | reg);
295	data = in32(RD94_SYS_PCI_CONFDATA);
296	out32(RD94_SYS_PCI_CONFADDR, 0);
297	splx(s);
298
299	return data;
300}
301
302void
303necpb_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
304{
305	int s;
306
307	s = splhigh();
308	out32(RD94_SYS_PCI_CONFADDR, tag | reg);
309	out32(RD94_SYS_PCI_CONFDATA, data);
310	out32(RD94_SYS_PCI_CONFADDR, 0);
311	splx(s);
312}
313
314int
315necpb_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
316{
317	pci_chipset_tag_t pc = pa->pa_pc;
318	pcitag_t intrtag = pa->pa_intrtag;
319	int pin = pa->pa_intrpin;
320	int bus, dev;
321
322	if (pin == 0) {
323		/* No IRQ used. */
324		*ihp = -1;
325		return 1;
326	}
327
328	if (pin > 4) {
329		printf("necpb_intr_map: bad interrupt pin %d\n", pin);
330		*ihp = -1;
331		return 1;
332	}
333
334	necpb_decompose_tag(pc, intrtag, &bus, &dev, NULL);
335	if (bus != 0) {
336		*ihp = -1;
337		return 1;
338	}
339
340	switch (dev) {
341	case 3:
342		*ihp = (pin + 2) % 4;
343		break;
344	case 4:
345		*ihp = (pin + 1) % 4;
346		break;
347	case 5:
348		*ihp = (pin + 0) % 4;
349		break;
350	default:
351		*ihp = -1;
352		return 1;
353	}
354
355	return 0;
356}
357
358const char *
359necpb_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
360{
361	static char str[8];
362
363	if (ih >= 4)
364		panic("necpb_intr_string: bogus handle %ld", ih);
365	sprintf(str, "int %c", 'A' + (int)ih);
366	return str;
367}
368
369void *
370necpb_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
371    int (*func)(void *), void *arg)
372{
373	struct necpb_intrhand *n, *p;
374	uint32_t mask;
375
376	if (ih >= 4)
377		panic("necpb_intr_establish: bogus handle");
378
379	n = malloc(sizeof(struct necpb_intrhand), M_DEVBUF, M_NOWAIT);
380	if (n == NULL)
381		panic("necpb_intr_establish: can't malloc interrupt handle");
382
383	n->ih_func = func;
384	n->ih_arg = arg;
385	n->ih_next = NULL;
386	n->ih_intn = ih;
387	strlcpy(n->ih_evname, necpb_intr_string(pc, ih), sizeof(n->ih_evname));
388	evcnt_attach_dynamic(&n->ih_evcnt, EVCNT_TYPE_INTR, NULL, "necpb",
389	    n->ih_evname);
390
391	if (necpb_inttbl[ih] == NULL) {
392		necpb_inttbl[ih] = n;
393		mask = in32(RD94_SYS_PCI_INTMASK);
394		mask |= 1 << ih;
395		out32(RD94_SYS_PCI_INTMASK, mask);
396	} else {
397		p = necpb_inttbl[ih];
398		while (p->ih_next != NULL)
399			p = p->ih_next;
400		p->ih_next = n;
401	}
402
403	return n;
404}
405
406void
407necpb_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
408{
409	struct necpb_intrhand *n, *p, *q;
410	uint32_t mask;
411
412	n = cookie;
413
414	q = NULL;
415	p = necpb_inttbl[n->ih_intn];
416	while (p != n) {
417		if (p == NULL)
418			panic("necpb_intr_disestablish: broken intr table");
419		q = p;
420		p = p->ih_next;
421	}
422
423	if (q == NULL) {
424		necpb_inttbl[n->ih_intn] = n->ih_next;
425		if (n->ih_next == NULL) {
426			mask = in32(RD94_SYS_PCI_INTMASK);
427			mask &= ~(1 << n->ih_intn);
428			out32(RD94_SYS_PCI_INTMASK, mask);
429		}
430	} else
431		q->ih_next = n->ih_next;
432
433	evcnt_detach(&n->ih_evcnt);
434
435	free(n, M_DEVBUF);
436}
437
438/*
439 *   Handle PCI/EISA interrupt.
440 */
441uint32_t
442necpb_intr(uint32_t mask, struct clockframe *cf)
443{
444	uint32_t vector, stat;
445	struct necpb_intrhand *p;
446	int i;
447
448	vector = in32(RD94_SYS_INTSTAT2) & 0xffff;
449
450	if (vector == 0x4000) {
451		stat = in32(RD94_SYS_PCI_INTSTAT);
452		stat &= in32(RD94_SYS_PCI_INTMASK);
453		for (i = 0; i < 4; i++) {
454			if (stat & (1 << i)) {
455#if 0
456				printf("pint %d\n", i);
457#endif
458				p = necpb_inttbl[i];
459				while (p != NULL) {
460					(*p->ih_func)(p->ih_arg);
461					p->ih_evcnt.ev_count++;
462					p = p->ih_next;
463				}
464			}
465		}
466	} else if (vector == 0x8000) {
467		printf("eisa_nmi\n");
468	} else {
469		printf("eint %d\n", vector & 0xff);
470#if 0
471		eisa_intr(vector & 0xff);
472#endif
473	}
474
475	return ~MIPS_INT_MASK_2;
476}
477