xref: /netbsd-src/sys/arch/arc/pci/necpb.c (revision 5c255dd2d0805ff3d827b666d7cf4d14c1156a03)
1*5c255dd2Sthorpej /*	$NetBSD: necpb.c,v 1.49 2023/12/07 03:46:10 thorpej Exp $	*/
21258a246Ssoda 
31258a246Ssoda /*-
41258a246Ssoda  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
51258a246Ssoda  * All rights reserved.
61258a246Ssoda  *
71258a246Ssoda  * This code is derived from software contributed to The NetBSD Foundation
81258a246Ssoda  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
91258a246Ssoda  * NASA Ames Research Center.
101258a246Ssoda  *
111258a246Ssoda  * Redistribution and use in source and binary forms, with or without
121258a246Ssoda  * modification, are permitted provided that the following conditions
131258a246Ssoda  * are met:
141258a246Ssoda  * 1. Redistributions of source code must retain the above copyright
151258a246Ssoda  *    notice, this list of conditions and the following disclaimer.
161258a246Ssoda  * 2. Redistributions in binary form must reproduce the above copyright
171258a246Ssoda  *    notice, this list of conditions and the following disclaimer in the
181258a246Ssoda  *    documentation and/or other materials provided with the distribution.
191258a246Ssoda  *
201258a246Ssoda  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
211258a246Ssoda  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
221258a246Ssoda  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
231258a246Ssoda  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
241258a246Ssoda  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
251258a246Ssoda  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
261258a246Ssoda  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
271258a246Ssoda  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
281258a246Ssoda  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
291258a246Ssoda  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
301258a246Ssoda  * POSSIBILITY OF SUCH DAMAGE.
311258a246Ssoda  */
321258a246Ssoda 
331258a246Ssoda /*
341258a246Ssoda  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
351258a246Ssoda  * Copyright (c) 1994 Charles M. Hannum.  All rights reserved.
361258a246Ssoda  *
371258a246Ssoda  * Redistribution and use in source and binary forms, with or without
381258a246Ssoda  * modification, are permitted provided that the following conditions
391258a246Ssoda  * are met:
401258a246Ssoda  * 1. Redistributions of source code must retain the above copyright
411258a246Ssoda  *    notice, this list of conditions and the following disclaimer.
421258a246Ssoda  * 2. Redistributions in binary form must reproduce the above copyright
431258a246Ssoda  *    notice, this list of conditions and the following disclaimer in the
441258a246Ssoda  *    documentation and/or other materials provided with the distribution.
451258a246Ssoda  * 3. All advertising materials mentioning features or use of this software
461258a246Ssoda  *    must display the following acknowledgement:
471258a246Ssoda  *	This product includes software developed by Charles M. Hannum.
481258a246Ssoda  * 4. The name of the author may not be used to endorse or promote products
491258a246Ssoda  *    derived from this software without specific prior written permission.
501258a246Ssoda  *
511258a246Ssoda  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
521258a246Ssoda  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
531258a246Ssoda  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
541258a246Ssoda  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
551258a246Ssoda  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
561258a246Ssoda  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
571258a246Ssoda  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
581258a246Ssoda  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
591258a246Ssoda  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
601258a246Ssoda  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
611258a246Ssoda  */
621258a246Ssoda 
63a4183603Slukem #include <sys/cdefs.h>
64*5c255dd2Sthorpej __KERNEL_RCSID(0, "$NetBSD: necpb.c,v 1.49 2023/12/07 03:46:10 thorpej Exp $");
650d0bf3b5Stsutsui 
660d0bf3b5Stsutsui #include "opt_pci.h"
67a4183603Slukem 
681258a246Ssoda #include <sys/types.h>
691258a246Ssoda #include <sys/param.h>
701258a246Ssoda #include <sys/time.h>
711258a246Ssoda #include <sys/systm.h>
721258a246Ssoda #include <sys/errno.h>
731258a246Ssoda #include <sys/device.h>
746f97a7c1Sthorpej #include <sys/kmem.h>
75*5c255dd2Sthorpej #include <sys/vmem_impl.h>
761258a246Ssoda 
772f159a1bSmrg #include <uvm/uvm_extern.h>
781258a246Ssoda 
791258a246Ssoda #define _ARC_BUS_DMA_PRIVATE
80cf10107dSdyoung #include <sys/bus.h>
811258a246Ssoda 
821258a246Ssoda #include <machine/pio.h>
831258a246Ssoda 
841258a246Ssoda #include <machine/autoconf.h>
851258a246Ssoda #include <machine/cpu.h>
861aa14913Ssoda #include <machine/platform.h>
871258a246Ssoda 
88f66776b1Stsutsui #include <mips/cache.h>
89f66776b1Stsutsui 
901258a246Ssoda #include <dev/pci/pcivar.h>
911258a246Ssoda #include <dev/pci/pcireg.h>
92edf0da13Stsutsui #include <dev/pci/pcidevs.h>
930d0bf3b5Stsutsui #ifdef PCI_NETBSD_CONFIGURE
940d0bf3b5Stsutsui #include <dev/pci/pciconf.h>
950d0bf3b5Stsutsui #endif
961258a246Ssoda 
97459f2585Sur #include <arc/jazz/rd94.h>
981258a246Ssoda #include <arc/pci/necpbvar.h>
991258a246Ssoda 
100c234c43aStsutsui #include "ioconf.h"
101c234c43aStsutsui 
102cbab9cadSchs static int	necpbmatch(device_t, cfdata_t, void *);
103cbab9cadSchs static void	necpbattach(device_t, device_t, void *);
1041258a246Ssoda 
105cbab9cadSchs static void	necpb_attach_hook(device_t, device_t,
1067fe2a5a0Stsutsui 		    struct pcibus_attach_args *);
1070f31d9deStsutsui static int	necpb_bus_maxdevs(pci_chipset_tag_t, int);
1080f31d9deStsutsui static pcitag_t	necpb_make_tag(pci_chipset_tag_t, int, int, int);
1090f31d9deStsutsui static void	necpb_decompose_tag(pci_chipset_tag_t, pcitag_t, int *,
1107fe2a5a0Stsutsui 		    int *, int *);
1110f31d9deStsutsui static pcireg_t	necpb_conf_read(pci_chipset_tag_t, pcitag_t, int);
1120f31d9deStsutsui static void	necpb_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t);
113a184f1f4Sdyoung static int	necpb_intr_map(const struct pci_attach_args *,
114a184f1f4Sdyoung 		    pci_intr_handle_t *);
115e58a356cSchristos static const char *necpb_intr_string(pci_chipset_tag_t, pci_intr_handle_t,
116e58a356cSchristos 		    char *, size_t);
1170f31d9deStsutsui static void	*necpb_intr_establish(pci_chipset_tag_t, pci_intr_handle_t,
1187fe2a5a0Stsutsui 		    int, int (*func)(void *), void *);
1190f31d9deStsutsui static void	necpb_intr_disestablish(pci_chipset_tag_t, void *);
1200d0bf3b5Stsutsui #ifdef PCI_NETBSD_CONFIGURE
1210f31d9deStsutsui static void	necpb_conf_interrupt(pci_chipset_tag_t, int, int, int, int,
1220d0bf3b5Stsutsui 		    int *);
1230f31d9deStsutsui static int	necpb_conf_hook(pci_chipset_tag_t, int, int, int, pcireg_t);
1240d0bf3b5Stsutsui #endif
1251258a246Ssoda 
1260f31d9deStsutsui static uint32_t	necpb_intr(uint32_t, struct clockframe *);
1271258a246Ssoda 
1281258a246Ssoda 
1290f31d9deStsutsui CFATTACH_DECL_NEW(necpb, sizeof(struct necpb_softc),
130c5e91d44Sthorpej     necpbmatch, necpbattach, NULL, NULL);
1311258a246Ssoda 
1321258a246Ssoda static struct necpb_intrhand	*necpb_inttbl[4];
1331258a246Ssoda 
13449e5e093Ssoda /* There can be only one. */
13549e5e093Ssoda int necpbfound;
1361aa14913Ssoda struct necpb_context necpb_main_context;
137*5c255dd2Sthorpej 
138*5c255dd2Sthorpej #define	NECPB_MEM_BTAG_COUNT	VMEM_EST_BTCOUNT(1, 10)
139*5c255dd2Sthorpej #define	NECPB_IO_BTAG_COUNT	VMEM_EST_BTCOUNT(1, 10)
140*5c255dd2Sthorpej 
141*5c255dd2Sthorpej static struct vmem necpb_mem_arena_store;
142*5c255dd2Sthorpej static struct vmem necpb_io_arena_store;
143*5c255dd2Sthorpej static struct vmem_btag necpb_mem_btag_store[NECPB_MEM_BTAG_COUNT];
144*5c255dd2Sthorpej static struct vmem_btag necpb_io_btag_store[NECPB_IO_BTAG_COUNT];
14549e5e093Ssoda 
146ca8ce3aeSthorpej #define	PCI_IO_START	0x00100000
147ca8ce3aeSthorpej #define	PCI_IO_END	0x01ffffff
148ca8ce3aeSthorpej #define	PCI_IO_SIZE	((PCI_IO_END - PCI_IO_START) + 1)
149ca8ce3aeSthorpej 
150ca8ce3aeSthorpej #define	PCI_MEM_START	0x08000000
151ca8ce3aeSthorpej #define	PCI_MEM_END	0x3fffffff
152ca8ce3aeSthorpej #define	PCI_MEM_SIZE	((PCI_MEM_END - PCI_MEM_START) + 1)
153ca8ce3aeSthorpej 
1540f31d9deStsutsui static int
necpbmatch(device_t parent,cfdata_t cf,void * aux)1550f31d9deStsutsui necpbmatch(device_t parent, cfdata_t cf, void *aux)
1561258a246Ssoda {
1571258a246Ssoda 	struct confargs *ca = aux;
1581258a246Ssoda 
1591258a246Ssoda 	if (strcmp(ca->ca_name, necpb_cd.cd_name) != 0)
1607fe2a5a0Stsutsui 		return 0;
1611258a246Ssoda 
16249e5e093Ssoda 	if (necpbfound)
1637fe2a5a0Stsutsui 		return 0;
16449e5e093Ssoda 
1657fe2a5a0Stsutsui 	return 1;
1661258a246Ssoda }
1671258a246Ssoda 
16849e5e093Ssoda /*
16949e5e093Ssoda  * Set up the chipset's function pointers.
17049e5e093Ssoda  */
17149e5e093Ssoda void
necpb_init(struct necpb_context * ncp)1727fe2a5a0Stsutsui necpb_init(struct necpb_context *ncp)
17349e5e093Ssoda {
174b34ad9c5Stsutsui 	pci_chipset_tag_t pc;
1750d0bf3b5Stsutsui #ifndef PCI_NETBSD_CONFIGURE
17649e5e093Ssoda 	pcitag_t tag;
177edf0da13Stsutsui 	pcireg_t id, class, csr;
178edf0da13Stsutsui 	u_int dev;
1790d0bf3b5Stsutsui #endif
18049e5e093Ssoda 
18149e5e093Ssoda 	if (ncp->nc_initialized)
18249e5e093Ssoda 		return;
18349e5e093Ssoda 
18449e5e093Ssoda 	arc_large_bus_space_init(&ncp->nc_memt, "necpcimem",
18549e5e093Ssoda 	    RD94_P_PCI_MEM, 0, RD94_S_PCI_MEM);
186*5c255dd2Sthorpej 	arc_bus_space_init_arena(&ncp->nc_memt, &necpb_mem_arena_store,
187*5c255dd2Sthorpej 	    necpb_mem_btag_store, NECPB_MEM_BTAG_COUNT);
18849e5e093Ssoda 
18949e5e093Ssoda 	arc_bus_space_init(&ncp->nc_iot, "necpciio",
19049e5e093Ssoda 	    RD94_P_PCI_IO, RD94_V_PCI_IO, 0, RD94_S_PCI_IO);
191*5c255dd2Sthorpej 	arc_bus_space_init_arena(&ncp->nc_iot, &necpb_io_arena_store,
192*5c255dd2Sthorpej 	    necpb_io_btag_store, NECPB_IO_BTAG_COUNT);
19349e5e093Ssoda 
19449e5e093Ssoda 	jazz_bus_dma_tag_init(&ncp->nc_dmat);
19549e5e093Ssoda 
196b34ad9c5Stsutsui 	pc = &ncp->nc_pc;
197b34ad9c5Stsutsui 	pc->pc_attach_hook = necpb_attach_hook;
198b34ad9c5Stsutsui 	pc->pc_bus_maxdevs = necpb_bus_maxdevs;
199b34ad9c5Stsutsui 	pc->pc_make_tag = necpb_make_tag;
200b34ad9c5Stsutsui 	pc->pc_decompose_tag = necpb_decompose_tag;
201b34ad9c5Stsutsui 	pc->pc_conf_read = necpb_conf_read;
202b34ad9c5Stsutsui 	pc->pc_conf_write = necpb_conf_write;
203b34ad9c5Stsutsui 	pc->pc_intr_map = necpb_intr_map;
204b34ad9c5Stsutsui 	pc->pc_intr_string = necpb_intr_string;
205b34ad9c5Stsutsui 	pc->pc_intr_establish = necpb_intr_establish;
206b34ad9c5Stsutsui 	pc->pc_intr_disestablish = necpb_intr_disestablish;
2070d0bf3b5Stsutsui #ifdef PCI_NETBSD_CONFIGURE
2080d0bf3b5Stsutsui 	pc->pc_conf_interrupt = necpb_conf_interrupt;
2090d0bf3b5Stsutsui 	pc->pc_conf_hook = necpb_conf_hook;
2100d0bf3b5Stsutsui #endif
21149e5e093Ssoda 
2120d0bf3b5Stsutsui #ifndef PCI_NETBSD_CONFIGURE
213e6c008bbSur 	/*
214e6c008bbSur 	 * XXX:
215e6c008bbSur 	 *  NEC's firmware does not configure PCI devices completely.
216e6c008bbSur 	 *  We need to disable expansion ROM and enable mem/io/busmaster
217e6c008bbSur 	 *  bits here.
218e6c008bbSur 	 */
219edf0da13Stsutsui 	for (dev = 3; dev <= 5; dev++) {
220edf0da13Stsutsui 		tag = necpb_make_tag(pc, 0, dev, 0);
221edf0da13Stsutsui 		id = necpb_conf_read(pc, tag, PCI_ID_REG);
22249e5e093Ssoda 
223edf0da13Stsutsui 		if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
224edf0da13Stsutsui 			continue;
22549e5e093Ssoda 
226edf0da13Stsutsui 		class = necpb_conf_read(pc, tag, PCI_CLASS_REG);
227b34ad9c5Stsutsui 		csr = necpb_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
228edf0da13Stsutsui 		if (PCI_CLASS(class) != PCI_CLASS_BRIDGE ||
229edf0da13Stsutsui 		    PCI_SUBCLASS(class) != PCI_SUBCLASS_BRIDGE_PCI) {
230edf0da13Stsutsui 			csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE;
231b34ad9c5Stsutsui 			necpb_conf_write(pc, tag, PCI_MAPREG_ROM, 0);
232edf0da13Stsutsui 		}
233edf0da13Stsutsui 		csr |= PCI_COMMAND_MASTER_ENABLE;
234edf0da13Stsutsui 		necpb_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
235edf0da13Stsutsui 	}
2360d0bf3b5Stsutsui #endif
23749e5e093Ssoda 
23849e5e093Ssoda 	ncp->nc_initialized = 1;
23949e5e093Ssoda }
24049e5e093Ssoda 
2410f31d9deStsutsui static void
necpbattach(device_t parent,device_t self,void * aux)2420f31d9deStsutsui necpbattach(device_t parent, device_t self, void *aux)
2431258a246Ssoda {
2440f31d9deStsutsui 	struct necpb_softc *sc = device_private(self);
2451258a246Ssoda 	struct pcibus_attach_args pba;
246b34ad9c5Stsutsui 	pci_chipset_tag_t pc;
2471258a246Ssoda 	int i;
2481258a246Ssoda 
2490f31d9deStsutsui 	sc->sc_dev = self;
2500f31d9deStsutsui 
25149e5e093Ssoda 	necpbfound = 1;
25249e5e093Ssoda 
2530f31d9deStsutsui 	aprint_normal("\n");
2541258a246Ssoda 
2551aa14913Ssoda 	sc->sc_ncp = &necpb_main_context;
25649e5e093Ssoda 	necpb_init(sc->sc_ncp);
2571258a246Ssoda 
258b34ad9c5Stsutsui 	pc = &sc->sc_ncp->nc_pc;
2590d0bf3b5Stsutsui #ifdef PCI_NETBSD_CONFIGURE
260ca8ce3aeSthorpej 	struct pciconf_resources *pcires = pciconf_resource_init();
261ca8ce3aeSthorpej 	pciconf_resource_add(pcires, PCICONF_RESOURCE_IO,
262ca8ce3aeSthorpej 	    PCI_IO_START, PCI_IO_SIZE);
263ca8ce3aeSthorpej 	pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM,
264ca8ce3aeSthorpej 	    PCI_MEM_START, PCI_MEM_SIZE);
265ca8ce3aeSthorpej 	pci_configure_bus(pc, pcires, 0, mips_cache_info.mci_dcache_align);
266ca8ce3aeSthorpej 	pciconf_resource_fini(pcires);
2670d0bf3b5Stsutsui #endif
268b34ad9c5Stsutsui 
2691258a246Ssoda 	out32(RD94_SYS_PCI_INTMASK, 0xf);
2701258a246Ssoda 
2711258a246Ssoda 	for (i = 0; i < 4; i++)
2721258a246Ssoda 		necpb_inttbl[i] = NULL;
2731258a246Ssoda 
2742a8a21a0Stsutsui 	(*platform->set_intr)(MIPS_INT_MASK_2, necpb_intr, ARC_INTPRI_PCIISA);
2751258a246Ssoda 
27649e5e093Ssoda 	pba.pba_iot = &sc->sc_ncp->nc_iot;
27749e5e093Ssoda 	pba.pba_memt = &sc->sc_ncp->nc_memt;
27849e5e093Ssoda 	pba.pba_dmat = &sc->sc_ncp->nc_dmat;
2797dd7f8baSfvdl 	pba.pba_dmat64 = NULL;
280b34ad9c5Stsutsui 	pba.pba_pc = pc;
281a6b2b839Sdyoung 	pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY;
2821258a246Ssoda 	pba.pba_bus = 0;
283204183c0Sthorpej 	pba.pba_bridgetag = NULL;
2841258a246Ssoda 
285c7fb772bSthorpej 	config_found(self, &pba, pcibusprint, CFARGS_NONE);
2861258a246Ssoda }
2871258a246Ssoda 
2880f31d9deStsutsui static void
necpb_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)289cbab9cadSchs necpb_attach_hook(device_t parent, device_t self,
2907fe2a5a0Stsutsui     struct pcibus_attach_args *pba)
2911258a246Ssoda {
2921258a246Ssoda }
2931258a246Ssoda 
2940f31d9deStsutsui static int
necpb_bus_maxdevs(pci_chipset_tag_t pc,int busno)2957fe2a5a0Stsutsui necpb_bus_maxdevs(pci_chipset_tag_t pc, int busno)
2961258a246Ssoda {
2977fe2a5a0Stsutsui 
2987fe2a5a0Stsutsui 	return 32;
2991258a246Ssoda }
3001258a246Ssoda 
3010f31d9deStsutsui static pcitag_t
necpb_make_tag(pci_chipset_tag_t pc,int bus,int device,int function)3027fe2a5a0Stsutsui necpb_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
3031258a246Ssoda {
3041258a246Ssoda 	pcitag_t tag;
3051258a246Ssoda 
3061258a246Ssoda 	if (bus >= 256 || device >= 32 || function >= 8)
3070f31d9deStsutsui 		panic("%s: bad request", __func__);
3081258a246Ssoda 
3091258a246Ssoda 	tag = 0x80000000 | (bus << 16) | (device << 11) | (function << 8);
3107fe2a5a0Stsutsui 	return tag;
3111258a246Ssoda }
3121258a246Ssoda 
3130f31d9deStsutsui static void
necpb_decompose_tag(pci_chipset_tag_t pc,pcitag_t tag,int * bp,int * dp,int * fp)3147fe2a5a0Stsutsui necpb_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp,
3157fe2a5a0Stsutsui    int *fp)
3161258a246Ssoda {
3177fe2a5a0Stsutsui 
3181258a246Ssoda 	if (bp != NULL)
3191258a246Ssoda 		*bp = (tag >> 16) & 0xff;
3201258a246Ssoda 	if (dp != NULL)
3211258a246Ssoda 		*dp = (tag >> 11) & 0x1f;
3221258a246Ssoda 	if (fp != NULL)
3231258a246Ssoda 		*fp = (tag >> 8) & 0x07;
3241258a246Ssoda }
3251258a246Ssoda 
3260f31d9deStsutsui static pcireg_t
necpb_conf_read(pci_chipset_tag_t pc,pcitag_t tag,int reg)3277fe2a5a0Stsutsui necpb_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
3281258a246Ssoda {
3291258a246Ssoda 	pcireg_t data;
3301258a246Ssoda 	int s;
3311258a246Ssoda 
332605f564fSmsaitoh 	if ((unsigned int)reg >= PCI_CONF_SIZE)
333605f564fSmsaitoh 		return (pcireg_t) -1;
334605f564fSmsaitoh 
3351258a246Ssoda 	s = splhigh();
3361258a246Ssoda 	out32(RD94_SYS_PCI_CONFADDR, tag | reg);
3371258a246Ssoda 	data = in32(RD94_SYS_PCI_CONFDATA);
3381258a246Ssoda 	out32(RD94_SYS_PCI_CONFADDR, 0);
3391258a246Ssoda 	splx(s);
3401258a246Ssoda 
3417fe2a5a0Stsutsui 	return data;
3421258a246Ssoda }
3431258a246Ssoda 
3440f31d9deStsutsui static void
necpb_conf_write(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t data)3457fe2a5a0Stsutsui necpb_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
3461258a246Ssoda {
3471258a246Ssoda 	int s;
3481258a246Ssoda 
349605f564fSmsaitoh 	if ((unsigned int)reg >= PCI_CONF_SIZE)
350605f564fSmsaitoh 		return;
351605f564fSmsaitoh 
3521258a246Ssoda 	s = splhigh();
3531258a246Ssoda 	out32(RD94_SYS_PCI_CONFADDR, tag | reg);
3541258a246Ssoda 	out32(RD94_SYS_PCI_CONFDATA, data);
3551258a246Ssoda 	out32(RD94_SYS_PCI_CONFADDR, 0);
3561258a246Ssoda 	splx(s);
3571258a246Ssoda }
3581258a246Ssoda 
3590f31d9deStsutsui static int
necpb_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ihp)360a184f1f4Sdyoung necpb_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
3611258a246Ssoda {
3627701dc57Sur 	pci_chipset_tag_t pc = pa->pa_pc;
3637701dc57Sur 	pcitag_t intrtag = pa->pa_intrtag;
3647701dc57Sur 	int pin = pa->pa_intrpin;
3651258a246Ssoda 	int bus, dev;
3661258a246Ssoda 
3671258a246Ssoda 	if (pin == 0) {
3681258a246Ssoda 		/* No IRQ used. */
3691258a246Ssoda 		*ihp = -1;
3707fe2a5a0Stsutsui 		return 1;
3711258a246Ssoda 	}
3721258a246Ssoda 
3731258a246Ssoda 	if (pin > 4) {
3741258a246Ssoda 		printf("necpb_intr_map: bad interrupt pin %d\n", pin);
3751258a246Ssoda 		*ihp = -1;
3767fe2a5a0Stsutsui 		return 1;
3771258a246Ssoda 	}
3781258a246Ssoda 
3791258a246Ssoda 	necpb_decompose_tag(pc, intrtag, &bus, &dev, NULL);
3801258a246Ssoda 	if (bus != 0) {
3810d0bf3b5Stsutsui 		printf("necpb_intr_map: unknown bus %d\n", bus);
3821258a246Ssoda 		*ihp = -1;
3837fe2a5a0Stsutsui 		return 1;
3841258a246Ssoda 	}
3851258a246Ssoda 
3861258a246Ssoda 	switch (dev) {
3871258a246Ssoda 	case 3:
388c5bd6bbaStsutsui 		*ihp = 3;
3891258a246Ssoda 		break;
3901258a246Ssoda 	case 4:
391c5bd6bbaStsutsui 		*ihp = 2;
3921258a246Ssoda 		break;
3931258a246Ssoda 	case 5:
394c5bd6bbaStsutsui 		*ihp = 1;
3951258a246Ssoda 		break;
3961258a246Ssoda 	default:
3971258a246Ssoda 		*ihp = -1;
3987fe2a5a0Stsutsui 		return 1;
3991258a246Ssoda 	}
4001258a246Ssoda 
4017fe2a5a0Stsutsui 	return 0;
4021258a246Ssoda }
4031258a246Ssoda 
4040f31d9deStsutsui static const char *
necpb_intr_string(pci_chipset_tag_t pc,pci_intr_handle_t ih,char * buf,size_t len)405e58a356cSchristos necpb_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih, char *buf,
406e58a356cSchristos     size_t len)
4071258a246Ssoda {
4081258a246Ssoda 	if (ih >= 4)
4090f31d9deStsutsui 		panic("%s: bogus handle %ld", __func__, ih);
410e58a356cSchristos 	snprintf(buf, len, "int %c", 'A' + (int)ih);
411e58a356cSchristos 	return buf;
4121258a246Ssoda }
4131258a246Ssoda 
4140f31d9deStsutsui static void *
necpb_intr_establish(pci_chipset_tag_t pc,pci_intr_handle_t ih,int level,int (* func)(void *),void * arg)4157fe2a5a0Stsutsui necpb_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
4167fe2a5a0Stsutsui     int (*func)(void *), void *arg)
4171258a246Ssoda {
4181258a246Ssoda 	struct necpb_intrhand *n, *p;
4197fe2a5a0Stsutsui 	uint32_t mask;
420e58a356cSchristos 	char buf[PCI_INTRSTR_LEN];
4211258a246Ssoda 
4221258a246Ssoda 	if (ih >= 4)
4230f31d9deStsutsui 		panic("%s: bogus handle", __func__);
4241258a246Ssoda 
4256f97a7c1Sthorpej 	n = kmem_alloc(sizeof(*n), KM_SLEEP);
4261258a246Ssoda 	n->ih_func = func;
4271258a246Ssoda 	n->ih_arg = arg;
4281258a246Ssoda 	n->ih_next = NULL;
4291258a246Ssoda 	n->ih_intn = ih;
430e58a356cSchristos 	strlcpy(n->ih_evname, necpb_intr_string(pc, ih, buf, sizeof(buf)),
431e58a356cSchristos 	    sizeof(n->ih_evname));
432c747a937Stsutsui 	evcnt_attach_dynamic(&n->ih_evcnt, EVCNT_TYPE_INTR, NULL, "necpb",
433c747a937Stsutsui 	    n->ih_evname);
4341258a246Ssoda 
4351258a246Ssoda 	if (necpb_inttbl[ih] == NULL) {
4361258a246Ssoda 		necpb_inttbl[ih] = n;
4371258a246Ssoda 		mask = in32(RD94_SYS_PCI_INTMASK);
4381258a246Ssoda 		mask |= 1 << ih;
4391258a246Ssoda 		out32(RD94_SYS_PCI_INTMASK, mask);
4401258a246Ssoda 	} else {
4411258a246Ssoda 		p = necpb_inttbl[ih];
4421258a246Ssoda 		while (p->ih_next != NULL)
4431258a246Ssoda 			p = p->ih_next;
4441258a246Ssoda 		p->ih_next = n;
4451258a246Ssoda 	}
4461258a246Ssoda 
4471258a246Ssoda 	return n;
4481258a246Ssoda }
4491258a246Ssoda 
4500f31d9deStsutsui static void
necpb_intr_disestablish(pci_chipset_tag_t pc,void * cookie)4517fe2a5a0Stsutsui necpb_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
4521258a246Ssoda {
4531258a246Ssoda 	struct necpb_intrhand *n, *p, *q;
4547fe2a5a0Stsutsui 	uint32_t mask;
4551258a246Ssoda 
4561258a246Ssoda 	n = cookie;
4571258a246Ssoda 
4581258a246Ssoda 	q = NULL;
4591258a246Ssoda 	p = necpb_inttbl[n->ih_intn];
4601258a246Ssoda 	while (p != n) {
4611258a246Ssoda 		if (p == NULL)
4620f31d9deStsutsui 			panic("%s: broken intr table", __func__);
4631258a246Ssoda 		q = p;
4641258a246Ssoda 		p = p->ih_next;
4651258a246Ssoda 	}
4661258a246Ssoda 
4671258a246Ssoda 	if (q == NULL) {
4681258a246Ssoda 		necpb_inttbl[n->ih_intn] = n->ih_next;
4691258a246Ssoda 		if (n->ih_next == NULL) {
4701258a246Ssoda 			mask = in32(RD94_SYS_PCI_INTMASK);
4711258a246Ssoda 			mask &= ~(1 << n->ih_intn);
4721258a246Ssoda 			out32(RD94_SYS_PCI_INTMASK, mask);
4731258a246Ssoda 		}
4741258a246Ssoda 	} else
4751258a246Ssoda 		q->ih_next = n->ih_next;
4761258a246Ssoda 
477c747a937Stsutsui 	evcnt_detach(&n->ih_evcnt);
478c747a937Stsutsui 
4796f97a7c1Sthorpej 	kmem_free(n, sizeof(*n));
4801258a246Ssoda }
4811258a246Ssoda 
4821258a246Ssoda /*
4831258a246Ssoda  *   Handle PCI/EISA interrupt.
4841258a246Ssoda  */
4850f31d9deStsutsui static uint32_t
necpb_intr(uint32_t mask,struct clockframe * cf)4867310abdeStsutsui necpb_intr(uint32_t mask, struct clockframe *cf)
4871258a246Ssoda {
4887fe2a5a0Stsutsui 	uint32_t vector, stat;
4891258a246Ssoda 	struct necpb_intrhand *p;
490a410f672Stsutsui 	int i, handled;
4911258a246Ssoda 
492a410f672Stsutsui 	handled = 0;
4931258a246Ssoda 	vector = in32(RD94_SYS_INTSTAT2) & 0xffff;
4941258a246Ssoda 
4951258a246Ssoda 	if (vector == 0x4000) {
4961258a246Ssoda 		stat = in32(RD94_SYS_PCI_INTSTAT);
4971258a246Ssoda 		stat &= in32(RD94_SYS_PCI_INTMASK);
498b34ad9c5Stsutsui 		for (i = 0; i < 4; i++) {
499b34ad9c5Stsutsui 			if (stat & (1 << i)) {
5001258a246Ssoda #if 0
501b34ad9c5Stsutsui 				printf("pint %d\n", i);
5021258a246Ssoda #endif
503b34ad9c5Stsutsui 				p = necpb_inttbl[i];
5041258a246Ssoda 				while (p != NULL) {
505a410f672Stsutsui 					if ((*p->ih_func)(p->ih_arg)) {
506c747a937Stsutsui 						p->ih_evcnt.ev_count++;
507a410f672Stsutsui 						handled |= 1;
508a410f672Stsutsui 					}
5091258a246Ssoda 					p = p->ih_next;
5101258a246Ssoda 				}
5111258a246Ssoda 			}
5121258a246Ssoda 		}
5131258a246Ssoda 	} else if (vector == 0x8000) {
5141258a246Ssoda 		printf("eisa_nmi\n");
5151258a246Ssoda 	} else {
5161258a246Ssoda 		printf("eint %d\n", vector & 0xff);
5171258a246Ssoda #if 0
518a410f672Stsutsui 		if (eisa_intr(vector & 0xff)) {
519a410f672Stsutsui 			handled |= 1;
520a410f672Stsutsui 		}
5211258a246Ssoda #endif
5221258a246Ssoda 	}
5231258a246Ssoda 
5244f59bf75Stsutsui 	return handled ? MIPS_INT_MASK_2 : 0;
5251258a246Ssoda }
5260d0bf3b5Stsutsui 
5270d0bf3b5Stsutsui #ifdef PCI_NETBSD_CONFIGURE
5280f31d9deStsutsui static void
necpb_conf_interrupt(pci_chipset_tag_t pc,int bus,int dev,int func,int swiz,int * iline)5290d0bf3b5Stsutsui necpb_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int func,
5300d0bf3b5Stsutsui     int swiz, int *iline)
5310d0bf3b5Stsutsui {
5320d0bf3b5Stsutsui 
5330d0bf3b5Stsutsui 	return;
5340d0bf3b5Stsutsui }
5350d0bf3b5Stsutsui 
5360f31d9deStsutsui static int
necpb_conf_hook(pci_chipset_tag_t pc,int bus,int dev,int func,pcireg_t id)5370d0bf3b5Stsutsui necpb_conf_hook(pci_chipset_tag_t pc, int bus, int dev, int func,
5380d0bf3b5Stsutsui     pcireg_t id)
5390d0bf3b5Stsutsui {
5400d0bf3b5Stsutsui 
5410d0bf3b5Stsutsui 	/* ignore bogus IDs */
5420d0bf3b5Stsutsui 	if (id == 0)
5430d0bf3b5Stsutsui 		return 0;
5440d0bf3b5Stsutsui 
5450d0bf3b5Stsutsui 	/* don't configure bridges */
5460d0bf3b5Stsutsui 	if (bus == 0 && (dev == 1 || dev == 2))
5470d0bf3b5Stsutsui 		return 0;
5480d0bf3b5Stsutsui 
5490d0bf3b5Stsutsui 	return PCI_CONF_DEFAULT;
5500d0bf3b5Stsutsui }
5510d0bf3b5Stsutsui #endif
552