xref: /openbsd-src/sys/arch/loongson/dev/bonito.c (revision 85caa4b9a5f41b995dcf54ce01413cd20e8f7dcd)
1*85caa4b9Scheloha /*	$OpenBSD: bonito.c,v 1.36 2022/08/22 00:35:07 cheloha Exp $	*/
22bf3c060Smiod /*	$NetBSD: bonito_mainbus.c,v 1.11 2008/04/28 20:23:10 martin Exp $	*/
32bf3c060Smiod /*	$NetBSD: bonito_pci.c,v 1.5 2008/04/28 20:23:28 martin Exp $	*/
42bf3c060Smiod 
52bf3c060Smiod /*
651b07be5Smiod  * Copyright (c) 2009, 2010 Miodrag Vallat.
72bf3c060Smiod  *
82bf3c060Smiod  * Permission to use, copy, modify, and distribute this software for any
92bf3c060Smiod  * purpose with or without fee is hereby granted, provided that the above
102bf3c060Smiod  * copyright notice and this permission notice appear in all copies.
112bf3c060Smiod  *
122bf3c060Smiod  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
132bf3c060Smiod  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
142bf3c060Smiod  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
152bf3c060Smiod  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
162bf3c060Smiod  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
172bf3c060Smiod  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
182bf3c060Smiod  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
192bf3c060Smiod  */
202bf3c060Smiod /*-
212bf3c060Smiod  * Copyright (c) 2001 The NetBSD Foundation, Inc.
222bf3c060Smiod  * All rights reserved.
232bf3c060Smiod  *
242bf3c060Smiod  * This code is derived from software contributed to The NetBSD Foundation
252bf3c060Smiod  * by Jason R. Thorpe.
262bf3c060Smiod  *
272bf3c060Smiod  * Redistribution and use in source and binary forms, with or without
282bf3c060Smiod  * modification, are permitted provided that the following conditions
292bf3c060Smiod  * are met:
302bf3c060Smiod  * 1. Redistributions of source code must retain the above copyright
312bf3c060Smiod  *    notice, this list of conditions and the following disclaimer.
322bf3c060Smiod  * 2. Redistributions in binary form must reproduce the above copyright
332bf3c060Smiod  *    notice, this list of conditions and the following disclaimer in the
342bf3c060Smiod  *    documentation and/or other materials provided with the distribution.
352bf3c060Smiod  *
362bf3c060Smiod  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
372bf3c060Smiod  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
382bf3c060Smiod  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
392bf3c060Smiod  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
402bf3c060Smiod  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
412bf3c060Smiod  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
422bf3c060Smiod  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
432bf3c060Smiod  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
442bf3c060Smiod  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
452bf3c060Smiod  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
462bf3c060Smiod  * POSSIBILITY OF SUCH DAMAGE.
472bf3c060Smiod  */
482bf3c060Smiod 
492bf3c060Smiod /*
502bf3c060Smiod  * PCI configuration space support for the Loongson PCI and memory controller
512bf3c060Smiod  * chip, which is derived from the Algorithmics BONITO chip.
522bf3c060Smiod  */
532bf3c060Smiod 
542bf3c060Smiod #include <sys/param.h>
552bf3c060Smiod #include <sys/systm.h>
562bf3c060Smiod #include <sys/device.h>
57747dc728Smiod #include <sys/extent.h>
58747dc728Smiod #include <sys/malloc.h>
592bf3c060Smiod 
602bf3c060Smiod #include <machine/autoconf.h>
612bf3c060Smiod #include <machine/bus.h>
62c40b02a1Smiod #include <machine/cpu.h>
637b6ae6a5Smiod #include <mips64/mips_cpu.h>
642bf3c060Smiod #include <machine/intr.h>
652bf3c060Smiod 
662bf3c060Smiod #include <dev/pci/pcidevs.h>
672bf3c060Smiod #include <dev/pci/pcireg.h>
682bf3c060Smiod #include <dev/pci/pcivar.h>
692bf3c060Smiod #include <dev/pci/ppbreg.h>
702bf3c060Smiod 
712bf3c060Smiod #include <loongson/dev/bonitoreg.h>
722bf3c060Smiod #include <loongson/dev/bonitovar.h>
73e1844cd9Smiod #include <loongson/dev/bonito_irq.h>
742bf3c060Smiod 
75d57a735dSmiod #include <uvm/uvm_extern.h>
76d57a735dSmiod 
7751b07be5Smiod #if 0
7851b07be5Smiod #define	BONITO_DEBUG
7951b07be5Smiod #endif
8051b07be5Smiod 
812bf3c060Smiod int	bonito_match(struct device *, void *, void *);
822bf3c060Smiod void	bonito_attach(struct device *, struct device *, void *);
832bf3c060Smiod 
842bf3c060Smiod const struct cfattach bonito_ca = {
85c06fda6dSderaadt 	sizeof(struct bonito_softc), bonito_match, bonito_attach
862bf3c060Smiod };
872bf3c060Smiod 
882bf3c060Smiod struct cfdriver bonito_cd = {
892bf3c060Smiod 	NULL, "bonito", DV_DULL
902bf3c060Smiod };
912bf3c060Smiod 
92c40b02a1Smiod #define	wbflush()	mips_sync()
932bf3c060Smiod 
942bf3c060Smiod bus_addr_t	bonito_pa_to_device(paddr_t);
952bf3c060Smiod paddr_t		bonito_device_to_pa(bus_addr_t);
962bf3c060Smiod 
972bf3c060Smiod void	 bonito_intr_makemasks(void);
98b43ebd13Smpi uint32_t bonito_intr_2e(uint32_t, struct trapframe *);
99b43ebd13Smpi uint32_t bonito_intr_2f(uint32_t, struct trapframe *);
100b43ebd13Smpi void	 bonito_intr_dispatch(uint64_t, int, struct trapframe *);
1012bf3c060Smiod 
1022bf3c060Smiod void	 bonito_attach_hook(struct device *, struct device *,
1032bf3c060Smiod 	    struct pcibus_attach_args *);
1042bf3c060Smiod int	 bonito_bus_maxdevs(void *, int);
1052bf3c060Smiod pcitag_t bonito_make_tag(void *, int, int, int);
1062bf3c060Smiod void	 bonito_decompose_tag(void *, pcitag_t, int *, int *, int *);
107b1926db3Smiod int	 bonito_conf_size(void *, pcitag_t);
1082bf3c060Smiod pcireg_t bonito_conf_read(void *, pcitag_t, int);
109b870770aSmiod pcireg_t bonito_conf_read_internal(const struct bonito_config *, pcitag_t, int);
1102bf3c060Smiod void	 bonito_conf_write(void *, pcitag_t, int, pcireg_t);
1112bf3c060Smiod int	 bonito_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
1122bf3c060Smiod const char *
1132bf3c060Smiod 	 bonito_pci_intr_string(void *, pci_intr_handle_t);
1142bf3c060Smiod void	*bonito_pci_intr_establish(void *, pci_intr_handle_t, int,
1152bf3c060Smiod 	    int (*)(void *), void *, char *);
1162bf3c060Smiod void	 bonito_pci_intr_disestablish(void *, void *);
1172bf3c060Smiod 
118b870770aSmiod int	 bonito_conf_addr(const struct bonito_config *, pcitag_t, int,
119b870770aSmiod 	    u_int32_t *, u_int32_t *);
1202bf3c060Smiod 
121e1844cd9Smiod void	 bonito_splx(int);
122e1844cd9Smiod 
1232bf3c060Smiod /*
124e1844cd9Smiod  * Bonito interrupt handling declarations.
125e1844cd9Smiod  * See <loongson/dev/bonito_irq.h> for details.
1262bf3c060Smiod  */
1272bf3c060Smiod struct intrhand *bonito_intrhand[BONITO_NINTS];
1282bf3c060Smiod uint64_t bonito_intem;
1292bf3c060Smiod uint64_t bonito_imask[NIPLS];
1302bf3c060Smiod 
1312bf3c060Smiod struct machine_bus_dma_tag bonito_bus_dma_tag = {
1322bf3c060Smiod 	._dmamap_create = _dmamap_create,
1332bf3c060Smiod 	._dmamap_destroy = _dmamap_destroy,
1342bf3c060Smiod 	._dmamap_load = _dmamap_load,
1352bf3c060Smiod 	._dmamap_load_mbuf = _dmamap_load_mbuf,
1362bf3c060Smiod 	._dmamap_load_uio = _dmamap_load_uio,
1372bf3c060Smiod 	._dmamap_load_raw = _dmamap_load_raw,
1382bf3c060Smiod 	._dmamap_load_buffer = _dmamap_load_buffer,
1392bf3c060Smiod 	._dmamap_unload = _dmamap_unload,
1402bf3c060Smiod 	._dmamap_sync = _dmamap_sync,
1412bf3c060Smiod 
1422bf3c060Smiod 	._dmamem_alloc = _dmamem_alloc,
1432bf3c060Smiod 	._dmamem_free = _dmamem_free,
1442bf3c060Smiod 	._dmamem_map = _dmamem_map,
1452bf3c060Smiod 	._dmamem_unmap = _dmamem_unmap,
1462bf3c060Smiod 	._dmamem_mmap = _dmamem_mmap,
1472bf3c060Smiod 
1482bf3c060Smiod 	._pa_to_device = bonito_pa_to_device,
1492bf3c060Smiod 	._device_to_pa = bonito_device_to_pa
1502bf3c060Smiod };
1512bf3c060Smiod 
15251b07be5Smiod int     bonito_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
15351b07be5Smiod 	    bus_space_handle_t *);
154ec2663a6Smiod int     bonito_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
155ec2663a6Smiod 	    bus_space_handle_t *);
15651b07be5Smiod 
1572bf3c060Smiod struct mips_bus_space bonito_pci_io_space_tag = {
1582bf3c060Smiod 	.bus_base = PHYS_TO_XKPHYS(BONITO_PCIIO_BASE, CCA_NC),
1592bf3c060Smiod 	._space_read_1 = generic_space_read_1,
1602bf3c060Smiod 	._space_write_1 = generic_space_write_1,
1612bf3c060Smiod 	._space_read_2 = generic_space_read_2,
1622bf3c060Smiod 	._space_write_2 = generic_space_write_2,
1632bf3c060Smiod 	._space_read_4 = generic_space_read_4,
1642bf3c060Smiod 	._space_write_4 = generic_space_write_4,
1652bf3c060Smiod 	._space_read_8 = generic_space_read_8,
1662bf3c060Smiod 	._space_write_8 = generic_space_write_8,
1672bf3c060Smiod 	._space_read_raw_2 = generic_space_read_raw_2,
1682bf3c060Smiod 	._space_write_raw_2 = generic_space_write_raw_2,
1692bf3c060Smiod 	._space_read_raw_4 = generic_space_read_raw_4,
1702bf3c060Smiod 	._space_write_raw_4 = generic_space_write_raw_4,
1712bf3c060Smiod 	._space_read_raw_8 = generic_space_read_raw_8,
1722bf3c060Smiod 	._space_write_raw_8 = generic_space_write_raw_8,
17351b07be5Smiod 	._space_map = bonito_io_map,
1742bf3c060Smiod 	._space_unmap = generic_space_unmap,
1752bf3c060Smiod 	._space_subregion = generic_space_region,
17602ce23a6Smiod 	._space_vaddr = generic_space_vaddr,
17702ce23a6Smiod 	._space_mmap = generic_space_mmap
1782bf3c060Smiod };
1792bf3c060Smiod 
1802bf3c060Smiod struct mips_bus_space bonito_pci_mem_space_tag = {
181ec2663a6Smiod 	.bus_base = PHYS_TO_XKPHYS(0, CCA_NC),
1822bf3c060Smiod 	._space_read_1 = generic_space_read_1,
1832bf3c060Smiod 	._space_write_1 = generic_space_write_1,
1842bf3c060Smiod 	._space_read_2 = generic_space_read_2,
1852bf3c060Smiod 	._space_write_2 = generic_space_write_2,
1862bf3c060Smiod 	._space_read_4 = generic_space_read_4,
1872bf3c060Smiod 	._space_write_4 = generic_space_write_4,
1882bf3c060Smiod 	._space_read_8 = generic_space_read_8,
1892bf3c060Smiod 	._space_write_8 = generic_space_write_8,
1902bf3c060Smiod 	._space_read_raw_2 = generic_space_read_raw_2,
1912bf3c060Smiod 	._space_write_raw_2 = generic_space_write_raw_2,
1922bf3c060Smiod 	._space_read_raw_4 = generic_space_read_raw_4,
1932bf3c060Smiod 	._space_write_raw_4 = generic_space_write_raw_4,
1942bf3c060Smiod 	._space_read_raw_8 = generic_space_read_raw_8,
1952bf3c060Smiod 	._space_write_raw_8 = generic_space_write_raw_8,
196ec2663a6Smiod 	._space_map = bonito_mem_map,
1972bf3c060Smiod 	._space_unmap = generic_space_unmap,
1982bf3c060Smiod 	._space_subregion = generic_space_region,
19902ce23a6Smiod 	._space_vaddr = generic_space_vaddr,
20002ce23a6Smiod 	._space_mmap = generic_space_mmap
2012bf3c060Smiod };
2022bf3c060Smiod 
2032bf3c060Smiod int
bonito_match(struct device * parent,void * vcf,void * aux)2042bf3c060Smiod bonito_match(struct device *parent, void *vcf, void *aux)
2052bf3c060Smiod {
2062bf3c060Smiod 	struct mainbus_attach_args *maa = aux;
2072bf3c060Smiod 
20802ce23a6Smiod 	if (loongson_ver >= 0x3a)
20902ce23a6Smiod 		return (0);
21002ce23a6Smiod 
2112bf3c060Smiod 	if (strcmp(maa->maa_name, bonito_cd.cd_name) == 0)
2122bf3c060Smiod 		return (1);
2132bf3c060Smiod 
2142bf3c060Smiod 	return (0);
2152bf3c060Smiod }
2162bf3c060Smiod 
2172bf3c060Smiod void
bonito_attach(struct device * parent,struct device * self,void * aux)2182bf3c060Smiod bonito_attach(struct device *parent, struct device *self, void *aux)
2192bf3c060Smiod {
2202bf3c060Smiod 	struct bonito_softc *sc = (struct bonito_softc *)self;
2212bf3c060Smiod 	struct pcibus_attach_args pba;
2222bf3c060Smiod 	pci_chipset_tag_t pc = &sc->sc_pc;
2232bf3c060Smiod 	const struct bonito_config *bc;
224ac27cb78Smiod 	uint32_t reg;
2252bf3c060Smiod 
226e1844cd9Smiod 	/*
227e1844cd9Smiod 	 * Loongson 2F processors do not use a real Bonito64 chip but
228e1844cd9Smiod 	 * their own derivative, which is no longer 100% compatible.
229e1844cd9Smiod 	 * We need to make sure we never try to access an unimplemented
230e1844cd9Smiod 	 * register...
231e1844cd9Smiod 	 */
2324e0b48a5Smiod 	if (loongson_ver >= 0x2f)
23351b07be5Smiod 		sc->sc_compatible = 0;
234e1844cd9Smiod 	else
23551b07be5Smiod 		sc->sc_compatible = 1;
236e1844cd9Smiod 
237e1844cd9Smiod 	reg = PCI_REVISION(REGVAL(BONITO_PCI_REG(PCI_CLASS_REG)));
23851b07be5Smiod 	if (sc->sc_compatible) {
239e1844cd9Smiod 		printf(": BONITO Memory and PCI controller, %s rev %d.%d\n",
240e1844cd9Smiod 		    BONITO_REV_FPGA(reg) ? "FPGA" : "ASIC",
241e1844cd9Smiod 		    BONITO_REV_MAJOR(reg), BONITO_REV_MINOR(reg));
242e1844cd9Smiod 	} else {
243e1844cd9Smiod 		printf(": memory and PCI-X controller, rev %d\n",
244ac27cb78Smiod 		    PCI_REVISION(REGVAL(BONITO_PCI_REG(PCI_CLASS_REG))));
245e1844cd9Smiod 	}
2462bf3c060Smiod 
24751b07be5Smiod 	bc = sys_platform->bonito_config;
2482bf3c060Smiod 	sc->sc_bonito = bc;
2492bf3c060Smiod 	SLIST_INIT(&sc->sc_hook);
2502bf3c060Smiod 
25151b07be5Smiod #ifdef BONITO_DEBUG
25251b07be5Smiod 	if (!sc->sc_compatible)
25351b07be5Smiod 		printf("ISR4C: %08x\n", REGVAL(BONITO_PCI_REG(0x4c)));
25451b07be5Smiod 	printf("PCIMAP: %08x\n", REGVAL(BONITO_PCIMAP));
25551b07be5Smiod 	printf("MEMWIN: %08x.%08x - %08x.%08x\n",
25651b07be5Smiod 	    REGVAL(BONITO_MEM_WIN_BASE_H), REGVAL(BONITO_MEM_WIN_BASE_L),
25751b07be5Smiod 	    REGVAL(BONITO_MEM_WIN_MASK_H), REGVAL(BONITO_MEM_WIN_MASK_L));
25851b07be5Smiod 	if (!sc->sc_compatible) {
25951b07be5Smiod 		printf("HITSEL0: %08x.%08x\n",
26051b07be5Smiod 		    REGVAL(LOONGSON_PCI_HIT0_SEL_H),
26151b07be5Smiod 		    REGVAL(LOONGSON_PCI_HIT0_SEL_L));
26251b07be5Smiod 		printf("HITSEL1: %08x.%08x\n",
26351b07be5Smiod 		    REGVAL(LOONGSON_PCI_HIT1_SEL_H),
26451b07be5Smiod 		    REGVAL(LOONGSON_PCI_HIT1_SEL_L));
26551b07be5Smiod 		printf("HITSEL2: %08x.%08x\n",
26651b07be5Smiod 		    REGVAL(LOONGSON_PCI_HIT2_SEL_H),
26751b07be5Smiod 		    REGVAL(LOONGSON_PCI_HIT2_SEL_L));
26851b07be5Smiod 	}
26951b07be5Smiod 	printf("PCI BAR 0:%08x 1:%08x 2:%08x 3:%08x 4:%08x 5:%08x\n",
27051b07be5Smiod 	    REGVAL(BONITO_PCI_REG(PCI_MAPREG_START + 0 * 4)),
27151b07be5Smiod 	    REGVAL(BONITO_PCI_REG(PCI_MAPREG_START + 1 * 4)),
27251b07be5Smiod 	    REGVAL(BONITO_PCI_REG(PCI_MAPREG_START + 2 * 4)),
27351b07be5Smiod 	    REGVAL(BONITO_PCI_REG(PCI_MAPREG_START + 3 * 4)),
27451b07be5Smiod 	    REGVAL(BONITO_PCI_REG(PCI_MAPREG_START + 4 * 4)),
27551b07be5Smiod 	    REGVAL(BONITO_PCI_REG(PCI_MAPREG_START + 5 * 4)));
27651b07be5Smiod #endif
27751b07be5Smiod 
2782bf3c060Smiod 	/*
27936fd90dcSjsg 	 * Setup proper arbitration.
280ac27cb78Smiod 	 */
281ac27cb78Smiod 
28251b07be5Smiod 	if (!sc->sc_compatible) {
283ac27cb78Smiod 		/*
2846246b192Smiod 		 * According to Linux, changing the value of this register
2856246b192Smiod 		 * ``avoids deadlock of PCI reading/writing lock operation''.
2866246b192Smiod 		 *
2876246b192Smiod 		 * Unfortunately, documentation for the Implementation
2886246b192Smiod 		 * Specific Registers (ISR40 to ISR5C) is only found in the
2896246b192Smiod 		 * chinese version of the Loongson 2F documentation.
2906246b192Smiod 		 *
2916246b192Smiod 		 * The particular bit we set here is ``mas_read_defer''.
292ac27cb78Smiod 		 */
29351b07be5Smiod 		/* c2000001 -> d2000001 */
29451b07be5Smiod 		REGVAL(BONITO_PCI_REG(0x4c)) |= 0x10000000;
295ac27cb78Smiod 
296ac27cb78Smiod 		/* all pci devices may need to hold the bus */
297ac27cb78Smiod 		reg = REGVAL(LOONGSON_PXARB_CFG);
298ac27cb78Smiod 		reg &= ~LOONGSON_PXARB_RUDE_DEV_MSK;
299ac27cb78Smiod 		reg |= 0xfe << LOONGSON_PXARB_RUDE_DEV_SHFT;
300ac27cb78Smiod 		REGVAL(LOONGSON_PXARB_CFG) = reg;
301ac27cb78Smiod 		(void)REGVAL(LOONGSON_PXARB_CFG);
302e1844cd9Smiod 	}
303ac27cb78Smiod 
304ac27cb78Smiod 	/*
3052bf3c060Smiod 	 * Setup interrupt handling.
3062bf3c060Smiod 	 */
3072bf3c060Smiod 
3082bf3c060Smiod 	REGVAL(BONITO_GPIOIE) = bc->bc_gpioIE;
3092bf3c060Smiod 	REGVAL(BONITO_INTEDGE) = bc->bc_intEdge;
31051b07be5Smiod 	if (sc->sc_compatible)
311e1844cd9Smiod 		REGVAL(BONITO_INTSTEER) = bc->bc_intSteer;
3122bf3c060Smiod 	REGVAL(BONITO_INTPOL) = bc->bc_intPol;
313e1844cd9Smiod 
314ac27cb78Smiod 	REGVAL(BONITO_INTENCLR) = 0xffffffff;
3152bf3c060Smiod 	(void)REGVAL(BONITO_INTENCLR);
31626da9fefSmiod 
317d57a735dSmiod 	if (sc->sc_compatible) {
318d57a735dSmiod 		bonito_intem |= BONITO_INTRMASK_MASTERERR;
319747dc728Smiod 	}
320747dc728Smiod 
3214e0b48a5Smiod 	if (loongson_ver >= 0x2f)
322d57a735dSmiod 		set_intr(INTPRI_BONITO, CR_INT_4, bonito_intr_2f);
323d57a735dSmiod 	else
324d57a735dSmiod 		set_intr(INTPRI_BONITO, CR_INT_0, bonito_intr_2e);
325d57a735dSmiod 	register_splx_handler(bonito_splx);
326d57a735dSmiod 
327747dc728Smiod 	/*
3282bf3c060Smiod 	 * Attach PCI bus.
3292bf3c060Smiod 	 */
3302bf3c060Smiod 
3312bf3c060Smiod 	pc->pc_conf_v = sc;
3322bf3c060Smiod 	pc->pc_attach_hook = bonito_attach_hook;
3332bf3c060Smiod 	pc->pc_bus_maxdevs = bonito_bus_maxdevs;
3342bf3c060Smiod 	pc->pc_make_tag = bonito_make_tag;
3352bf3c060Smiod 	pc->pc_decompose_tag = bonito_decompose_tag;
336b1926db3Smiod 	pc->pc_conf_size = bonito_conf_size;
3372bf3c060Smiod 	pc->pc_conf_read = bonito_conf_read;
3382bf3c060Smiod 	pc->pc_conf_write = bonito_conf_write;
3392bf3c060Smiod 
3402bf3c060Smiod 	pc->pc_intr_v = sc;
3412bf3c060Smiod 	pc->pc_intr_map = bonito_pci_intr_map;
3422bf3c060Smiod 	pc->pc_intr_string = bonito_pci_intr_string;
3432bf3c060Smiod 	pc->pc_intr_establish = bonito_pci_intr_establish;
3442bf3c060Smiod 	pc->pc_intr_disestablish = bonito_pci_intr_disestablish;
3452bf3c060Smiod 
3462bf3c060Smiod 	bzero(&pba, sizeof pba);
3472bf3c060Smiod 	pba.pba_busname = "pci";
3482bf3c060Smiod 	pba.pba_iot = &bonito_pci_io_space_tag;
3492bf3c060Smiod 	pba.pba_memt = &bonito_pci_mem_space_tag;
3502bf3c060Smiod 	pba.pba_dmat = &bonito_bus_dma_tag;
3512bf3c060Smiod 	pba.pba_pc = pc;
3522bf3c060Smiod 	pba.pba_domain = pci_ndomains++;
3532bf3c060Smiod 	pba.pba_bus = 0;
35451b07be5Smiod #ifdef notyet
35551b07be5Smiod 	pba.pba_ioex = bonito_get_resource_extent(pc, 1);
35651b07be5Smiod 	pba.pba_memex = bonito_get_resource_extent(pc, 0);
35751b07be5Smiod #endif
3582bf3c060Smiod 
3592bf3c060Smiod 	config_found(&sc->sc_dev, &pba, bonito_print);
3602bf3c060Smiod }
3612bf3c060Smiod 
3622bf3c060Smiod bus_addr_t
bonito_pa_to_device(paddr_t pa)3632bf3c060Smiod bonito_pa_to_device(paddr_t pa)
3642bf3c060Smiod {
365df5d8a75Smiod 	return pa ^ loongson_dma_base;
3662bf3c060Smiod }
3672bf3c060Smiod 
3682bf3c060Smiod paddr_t
bonito_device_to_pa(bus_addr_t addr)3692bf3c060Smiod bonito_device_to_pa(bus_addr_t addr)
3702bf3c060Smiod {
371df5d8a75Smiod 	return addr ^ loongson_dma_base;
3722bf3c060Smiod }
3732bf3c060Smiod 
3742bf3c060Smiod int
bonito_print(void * aux,const char * pnp)3752bf3c060Smiod bonito_print(void *aux, const char *pnp)
3762bf3c060Smiod {
3772bf3c060Smiod 	struct pcibus_attach_args *pba = aux;
3782bf3c060Smiod 
3792bf3c060Smiod 	if (pnp)
3802bf3c060Smiod 		printf("%s at %s", pba->pba_busname, pnp);
3812bf3c060Smiod 	printf(" bus %d", pba->pba_bus);
3822bf3c060Smiod 
3832bf3c060Smiod 	return UNCONF;
3842bf3c060Smiod }
3852bf3c060Smiod 
3862bf3c060Smiod /*
3872bf3c060Smiod  * Bonito interrupt handling
3882bf3c060Smiod  */
3892bf3c060Smiod 
3902bf3c060Smiod void *
bonito_intr_establish(int irq,int type,int level,int (* handler)(void *),void * arg,const char * name)3912bf3c060Smiod bonito_intr_establish(int irq, int type, int level, int (*handler)(void *),
3922bf3c060Smiod     void *arg, const char *name)
3932bf3c060Smiod {
3942bf3c060Smiod 	struct intrhand **p, *q, *ih;
3952bf3c060Smiod 	int s;
3962bf3c060Smiod 
3972bf3c060Smiod #ifdef DIAGNOSTIC
3982bf3c060Smiod 	if (irq >= BONITO_NINTS || irq == BONITO_ISA_IRQ(2) || irq < 0)
3992bf3c060Smiod 		panic("bonito_intr_establish: illegal irq %d", irq);
4002bf3c060Smiod #endif
4012bf3c060Smiod 
4028aa1a2d2Svisa 	level &= ~IPL_MPSAFE;
4038aa1a2d2Svisa 
4042bf3c060Smiod 	ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT);
4052bf3c060Smiod 	if (ih == NULL)
4062bf3c060Smiod 		return NULL;
4072bf3c060Smiod 
4082bf3c060Smiod 	ih->ih_next = NULL;
4092bf3c060Smiod 	ih->ih_fun = handler;
4102bf3c060Smiod 	ih->ih_arg = arg;
4112bf3c060Smiod 	ih->ih_level = level;
4122bf3c060Smiod 	ih->ih_irq = irq;
4134667bebbSmatthew 	evcount_attach(&ih->ih_count, name, &ih->ih_irq);
4142bf3c060Smiod 
4152bf3c060Smiod 	s = splhigh();
4162bf3c060Smiod 
4172bf3c060Smiod 	/*
4182bf3c060Smiod 	 * Figure out where to put the handler.
4192bf3c060Smiod 	 * This is O(N^2), but we want to preserve the order, and N is
4202bf3c060Smiod 	 * generally small.
4212bf3c060Smiod 	 */
4222bf3c060Smiod 	for (p = &bonito_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
4232bf3c060Smiod 		;
4242bf3c060Smiod 	*p = ih;
4252bf3c060Smiod 
4262bf3c060Smiod 	bonito_intem |= 1UL << irq;
4272bf3c060Smiod 	bonito_intr_makemasks();
4282bf3c060Smiod 
4292bf3c060Smiod 	splx(s);	/* causes hw mask update */
4302bf3c060Smiod 
4312bf3c060Smiod 	return (ih);
4322bf3c060Smiod }
4332bf3c060Smiod 
4342bf3c060Smiod void
bonito_intr_disestablish(void * vih)435d57a735dSmiod bonito_intr_disestablish(void *vih)
4362bf3c060Smiod {
437d57a735dSmiod 	struct intrhand *ih = (struct intrhand *)vih;
438d57a735dSmiod 	struct intrhand **p, *q;
439d57a735dSmiod 	int irq = ih->ih_irq;
440d57a735dSmiod 	int s;
441d57a735dSmiod 
442d57a735dSmiod #ifdef DIAGNOSTIC
443d57a735dSmiod 	if (irq >= BONITO_NINTS || irq == BONITO_ISA_IRQ(2) || irq < 0)
444d57a735dSmiod 		panic("bonito_intr_disestablish: illegal irq %d", irq);
445d57a735dSmiod #endif
446d57a735dSmiod 
447d57a735dSmiod 	s = splhigh();
448d57a735dSmiod 
449d57a735dSmiod 	evcount_detach(&ih->ih_count);
450d57a735dSmiod 
451d57a735dSmiod 	for (p = &bonito_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
452d57a735dSmiod 		if (q == ih)
453d57a735dSmiod 			break;
454d57a735dSmiod #ifdef DIAGNOSTIC
455d57a735dSmiod 	if (q == NULL)
456d57a735dSmiod 		panic("bonito_intr_disestablish: never registered");
457d57a735dSmiod #endif
458d57a735dSmiod 	*p = ih->ih_next;
459d57a735dSmiod 
460d57a735dSmiod 	if (ih->ih_next == NULL && p == &bonito_intrhand[irq]) {
461d57a735dSmiod 		bonito_intem &= ~(1UL << irq);
462d57a735dSmiod 		bonito_intr_makemasks();
463d57a735dSmiod 		/*
464d57a735dSmiod 		 * No need to clear a bit in INTEN through INTCLR,
465d57a735dSmiod 		 * splhigh() took care of disabling everything and
466d57a735dSmiod 		 * splx() will not reenable this source after the
467d57a735dSmiod 		 * mask update.
468d57a735dSmiod 		 */
469d57a735dSmiod 	}
470d57a735dSmiod 
471d57a735dSmiod 	splx(s);
472d57a735dSmiod 
47341c0f940Sderaadt 	free(ih, M_DEVBUF, sizeof *ih);
4742bf3c060Smiod }
4752bf3c060Smiod 
476e1844cd9Smiod /*
47751b07be5Smiod  * Update interrupt masks. This is for designs without legacy PIC.
478e1844cd9Smiod  */
479e1844cd9Smiod 
4802bf3c060Smiod void
bonito_splx(int newipl)4812bf3c060Smiod bonito_splx(int newipl)
4822bf3c060Smiod {
4832bf3c060Smiod 	struct cpu_info *ci = curcpu();
4842bf3c060Smiod 
4852bf3c060Smiod 	/* Update masks to new ipl. Order highly important! */
4862bf3c060Smiod 	ci->ci_ipl = newipl;
4872bf3c060Smiod 	bonito_setintrmask(newipl);
488*85caa4b9Scheloha 
489*85caa4b9Scheloha 	/* Trigger deferred clock interrupt if it is now unmasked. */
490*85caa4b9Scheloha 	if (ci->ci_clock_deferred && newipl < IPL_CLOCK)
491*85caa4b9Scheloha 		md_triggerclock();
492*85caa4b9Scheloha 
4932bf3c060Smiod 	/* If we still have softints pending trigger processing. */
4942bf3c060Smiod 	if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
4952bf3c060Smiod 		setsoftintr0();
4962bf3c060Smiod }
4972bf3c060Smiod 
498e1844cd9Smiod void
bonito_setintrmask(int level)499e1844cd9Smiod bonito_setintrmask(int level)
500e1844cd9Smiod {
501e1844cd9Smiod 	uint64_t active;
502e1844cd9Smiod 	uint32_t clear, set;
503a6ba7b46Smiod 	register_t sr;
504e1844cd9Smiod 
505e1844cd9Smiod 	active = bonito_intem & ~bonito_imask[level];
506d57a735dSmiod 	/* be sure to mask high bits, there may be other interrupt sources */
507d57a735dSmiod 	clear = BONITO_DIRECT_MASK(bonito_imask[level]);
508d57a735dSmiod 	set = BONITO_DIRECT_MASK(active);
509e1844cd9Smiod 
510e1844cd9Smiod 	sr = disableintr();
511e1844cd9Smiod 
512d57a735dSmiod 	if (clear != 0) {
513e1844cd9Smiod 		REGVAL(BONITO_INTENCLR) = clear;
514d57a735dSmiod 		(void)REGVAL(BONITO_INTENCLR);
515d57a735dSmiod 	}
516d57a735dSmiod 	if (set != 0) {
517e1844cd9Smiod 		REGVAL(BONITO_INTENSET) = set;
518e1844cd9Smiod 		(void)REGVAL(BONITO_INTENSET);
519d57a735dSmiod 	}
520e1844cd9Smiod 
521e1844cd9Smiod 	setsr(sr);
522e1844cd9Smiod }
523e1844cd9Smiod 
5242bf3c060Smiod /*
5252bf3c060Smiod  * Recompute interrupt masks.
5262bf3c060Smiod  */
5272bf3c060Smiod void
bonito_intr_makemasks()5282bf3c060Smiod bonito_intr_makemasks()
5292bf3c060Smiod {
5302bf3c060Smiod 	int irq, level;
5312bf3c060Smiod 	struct intrhand *q;
5322bf3c060Smiod 	uint intrlevel[BONITO_NINTS];
5332bf3c060Smiod 
5342bf3c060Smiod 	/* First, figure out which levels each IRQ uses. */
5352bf3c060Smiod 	for (irq = 0; irq < BONITO_NINTS; irq++) {
5362bf3c060Smiod 		uint levels = 0;
5372bf3c060Smiod 		for (q = bonito_intrhand[irq]; q != NULL; q = q->ih_next)
5382bf3c060Smiod 			levels |= 1 << q->ih_level;
5392bf3c060Smiod 		intrlevel[irq] = levels;
5402bf3c060Smiod 	}
5412bf3c060Smiod 
5422bf3c060Smiod 	/*
5432bf3c060Smiod 	 * Then figure out which IRQs use each level.
5442bf3c060Smiod 	 * Note that we make sure never to overwrite imask[IPL_HIGH], in
5452bf3c060Smiod 	 * case an interrupt occurs during intr_disestablish() and causes
5462bf3c060Smiod 	 * an unfortunate splx() while we are here recomputing the masks.
5472bf3c060Smiod 	 */
5482bf3c060Smiod 	for (level = IPL_NONE; level < IPL_HIGH; level++) {
5492bf3c060Smiod 		uint64_t irqs = 0;
5502bf3c060Smiod 		for (irq = 0; irq < BONITO_NINTS; irq++)
5512bf3c060Smiod 			if (intrlevel[irq] & (1 << level))
5522bf3c060Smiod 				irqs |= 1UL << irq;
5532bf3c060Smiod 		bonito_imask[level] = irqs;
5542bf3c060Smiod 	}
5552bf3c060Smiod 
5562bf3c060Smiod 	/*
5572bf3c060Smiod 	 * There are tty, network and disk drivers that use free() at interrupt
5582bf3c060Smiod 	 * time, so vm > (tty | net | bio).
5592bf3c060Smiod 	 *
5602bf3c060Smiod 	 * Enforce a hierarchy that gives slow devices a better chance at not
5612bf3c060Smiod 	 * dropping data.
5622bf3c060Smiod 	 */
5632bf3c060Smiod 	bonito_imask[IPL_NET] |= bonito_imask[IPL_BIO];
5642bf3c060Smiod 	bonito_imask[IPL_TTY] |= bonito_imask[IPL_NET];
5652bf3c060Smiod 	bonito_imask[IPL_VM] |= bonito_imask[IPL_TTY];
5662bf3c060Smiod 	bonito_imask[IPL_CLOCK] |= bonito_imask[IPL_VM];
5672bf3c060Smiod 
5682bf3c060Smiod 	/*
5692bf3c060Smiod 	 * These are pseudo-levels.
5702bf3c060Smiod 	 */
5712bf3c060Smiod 	bonito_imask[IPL_NONE] = 0;
5722bf3c060Smiod 	bonito_imask[IPL_HIGH] = -1UL;
5732bf3c060Smiod }
5742bf3c060Smiod 
5752bf3c060Smiod /*
57651b07be5Smiod  * Process native interrupts
5772bf3c060Smiod  */
5782bf3c060Smiod 
5792bf3c060Smiod uint32_t
bonito_intr_2e(uint32_t hwpend,struct trapframe * frame)580b43ebd13Smpi bonito_intr_2e(uint32_t hwpend, struct trapframe *frame)
5812bf3c060Smiod {
5822bf3c060Smiod 	uint64_t imr, isr, mask;
583d57a735dSmiod 
584d57a735dSmiod 	isr = REGVAL(BONITO_INTISR);
585d57a735dSmiod 
586d57a735dSmiod 	/*
587d57a735dSmiod 	 * According to Linux code, Bonito64 - at least on Loongson
588d57a735dSmiod 	 * systems - triggers an interrupt during DMA, which is to be
589d57a735dSmiod 	 * ignored. Smells like a chip errata to me.
590d57a735dSmiod 	 */
591d57a735dSmiod 	while (ISSET(isr, BONITO_INTRMASK_MASTERERR)) {
592d57a735dSmiod 		delay(1);
593d57a735dSmiod 		isr = REGVAL(BONITO_INTISR);
594d57a735dSmiod 	}
595d57a735dSmiod 
596d57a735dSmiod 	isr &= BONITO_INTRMASK_GPIN;
597d57a735dSmiod 	imr = REGVAL(BONITO_INTEN);
598d57a735dSmiod 	isr &= imr;
599d57a735dSmiod #ifdef DEBUG
600d57a735dSmiod 	printf("pci interrupt: imr %04x isr %04x\n", imr, isr);
601d57a735dSmiod #endif
602d57a735dSmiod 	if (isr == 0)
603d57a735dSmiod 		return 0;	/* not for us */
604d57a735dSmiod 
605d57a735dSmiod 	/*
606d57a735dSmiod 	 * Mask all pending interrupts.
607d57a735dSmiod 	 */
608d57a735dSmiod 	REGVAL(BONITO_INTENCLR) = isr;
609d57a735dSmiod 	(void)REGVAL(BONITO_INTENCLR);
610d57a735dSmiod 
611d57a735dSmiod 	/*
612d57a735dSmiod 	 * If interrupts are spl-masked, mask them and wait for splx()
613d57a735dSmiod 	 * to reenable them when necessary.
614d57a735dSmiod 	 */
615d57a735dSmiod 	if ((mask = isr & bonito_imask[frame->ipl]) != 0) {
616d57a735dSmiod 		isr &= ~mask;
617d57a735dSmiod 		imr &= ~mask;
618d57a735dSmiod 	}
619d57a735dSmiod 
620d57a735dSmiod 	/*
621d57a735dSmiod 	 * Now process allowed interrupts.
622d57a735dSmiod 	 */
623d57a735dSmiod 	if (isr != 0) {
624d57a735dSmiod 		bonito_intr_dispatch(isr, 30, frame);
625d57a735dSmiod 
626d57a735dSmiod 		/*
627d57a735dSmiod 		 * Reenable interrupts which have been serviced.
628d57a735dSmiod 		 */
629d57a735dSmiod 		REGVAL(BONITO_INTENSET) = imr;
630d57a735dSmiod 		(void)REGVAL(BONITO_INTENSET);
631d57a735dSmiod 	}
632d57a735dSmiod 
633d57a735dSmiod 	return hwpend;
634d57a735dSmiod }
635d57a735dSmiod 
636d57a735dSmiod uint32_t
bonito_intr_2f(uint32_t hwpend,struct trapframe * frame)637b43ebd13Smpi bonito_intr_2f(uint32_t hwpend, struct trapframe *frame)
638d57a735dSmiod {
639d57a735dSmiod 	uint64_t imr, isr, mask;
6402bf3c060Smiod 
641e1844cd9Smiod 	isr = REGVAL(BONITO_INTISR) & LOONGSON_INTRMASK_LVL4;
6422bf3c060Smiod 	imr = REGVAL(BONITO_INTEN);
6432bf3c060Smiod 	isr &= imr;
6442bf3c060Smiod #ifdef DEBUG
6452bf3c060Smiod 	printf("pci interrupt: imr %04x isr %04x\n", imr, isr);
6462bf3c060Smiod #endif
647ac27cb78Smiod 	if (isr == 0)
648ac27cb78Smiod 		return 0;	/* not for us */
649ac27cb78Smiod 
6502bf3c060Smiod 	/*
6512bf3c060Smiod 	 * Mask all pending interrupts.
6522bf3c060Smiod 	 */
6532bf3c060Smiod 	REGVAL(BONITO_INTENCLR) = isr;
6542bf3c060Smiod 	(void)REGVAL(BONITO_INTENCLR);
6552bf3c060Smiod 
6562bf3c060Smiod 	/*
6572bf3c060Smiod 	 * If interrupts are spl-masked, mask them and wait for splx()
6582bf3c060Smiod 	 * to reenable them when necessary.
6592bf3c060Smiod 	 */
6602bf3c060Smiod 	if ((mask = isr & bonito_imask[frame->ipl]) != 0) {
6612bf3c060Smiod 		isr &= ~mask;
6622bf3c060Smiod 		imr &= ~mask;
6632bf3c060Smiod 	}
6642bf3c060Smiod 
6652bf3c060Smiod 	/*
6662bf3c060Smiod 	 * Now process allowed interrupts.
6672bf3c060Smiod 	 */
6682bf3c060Smiod 	if (isr != 0) {
669d57a735dSmiod 		bonito_intr_dispatch(isr,
670d57a735dSmiod 		    LOONGSON_INTR_DRAM_PARERR /* skip non-pci interrupts */,
671d57a735dSmiod 		    frame);
6722bf3c060Smiod 
6732bf3c060Smiod 		/*
6742bf3c060Smiod 		 * Reenable interrupts which have been serviced.
6752bf3c060Smiod 		 */
6762bf3c060Smiod 		REGVAL(BONITO_INTENSET) = imr;
6772bf3c060Smiod 		(void)REGVAL(BONITO_INTENSET);
6782bf3c060Smiod 	}
6792bf3c060Smiod 
6802bf3c060Smiod 	return hwpend;
6812bf3c060Smiod }
6822bf3c060Smiod 
683d57a735dSmiod void
bonito_intr_dispatch(uint64_t isr,int startbit,struct trapframe * frame)684b43ebd13Smpi bonito_intr_dispatch(uint64_t isr, int startbit, struct trapframe *frame)
685d57a735dSmiod {
686d57a735dSmiod 	int lvl, bitno;
687d57a735dSmiod 	uint64_t tmpisr, mask;
688d57a735dSmiod 	struct intrhand *ih;
689d57a735dSmiod 	int rc;
690d57a735dSmiod 
691d57a735dSmiod 	/* Service higher level interrupts first */
692d57a735dSmiod 	for (lvl = IPL_HIGH - 1; lvl != IPL_NONE; lvl--) {
693d57a735dSmiod 		tmpisr = isr & (bonito_imask[lvl] ^ bonito_imask[lvl - 1]);
694d57a735dSmiod 		if (tmpisr == 0)
695d57a735dSmiod 			continue;
696d57a735dSmiod 		for (bitno = startbit, mask = 1UL << bitno; mask != 0;
697d57a735dSmiod 		    bitno--, mask >>= 1) {
698d57a735dSmiod 			if ((tmpisr & mask) == 0)
699d57a735dSmiod 				continue;
700d57a735dSmiod 
701d57a735dSmiod 			rc = 0;
702d57a735dSmiod 			for (ih = bonito_intrhand[bitno]; ih != NULL;
703d57a735dSmiod 			    ih = ih->ih_next) {
704d57a735dSmiod 				splraise(ih->ih_level);
705d57a735dSmiod 				if ((*ih->ih_fun)(ih->ih_arg) != 0) {
706d57a735dSmiod 					rc = 1;
707d57a735dSmiod 					ih->ih_count.ec_count++;
708d57a735dSmiod 				}
709d57a735dSmiod 				curcpu()->ci_ipl = frame->ipl;
710d57a735dSmiod 			}
711d57a735dSmiod 			if (rc == 0) {
712d57a735dSmiod 				printf("spurious interrupt %d\n", bitno);
713d57a735dSmiod #ifdef DEBUG
714d57a735dSmiod 				printf("ISR %08x IMR %08x ipl %d mask %08x\n",
715d57a735dSmiod 				    REGVAL(BONITO_INTISR), REGVAL(BONITO_INTEN),
716d57a735dSmiod 				    frame->ipl, bonito_imask[frame->ipl]);
717d57a735dSmiod #ifdef DDB
718e97088d6Smpi 				db_enter();
719d57a735dSmiod #endif
720d57a735dSmiod #endif
721d57a735dSmiod 			}
722d57a735dSmiod 
723d57a735dSmiod 			if ((isr ^= mask) == 0)
724d57a735dSmiod 				return;
725d57a735dSmiod 			if ((tmpisr ^= mask) == 0)
726d57a735dSmiod 				break;
727d57a735dSmiod 		}
728d57a735dSmiod 	}
729d57a735dSmiod }
730d57a735dSmiod 
7312bf3c060Smiod /*
7322bf3c060Smiod  * various PCI helpers
7332bf3c060Smiod  */
7342bf3c060Smiod 
7352bf3c060Smiod void
bonito_attach_hook(struct device * parent,struct device * self,struct pcibus_attach_args * pba)7362bf3c060Smiod bonito_attach_hook(struct device *parent, struct device *self,
7372bf3c060Smiod     struct pcibus_attach_args *pba)
7382bf3c060Smiod {
7392bf3c060Smiod 	pci_chipset_tag_t pc = pba->pba_pc;
74025dee1c4Smiod 	struct bonito_softc *sc = pc->pc_conf_v;
74125dee1c4Smiod 	const struct bonito_config *bc = sc->sc_bonito;
7422bf3c060Smiod 
7432bf3c060Smiod 	if (pba->pba_bus != 0)
7442bf3c060Smiod 		return;
7452bf3c060Smiod 
74625dee1c4Smiod 	(*bc->bc_attach_hook)(pc);
7472bf3c060Smiod }
7482bf3c060Smiod 
7492bf3c060Smiod /*
7502bf3c060Smiod  * PCI configuration space access routines
7512bf3c060Smiod  */
7522bf3c060Smiod 
7532bf3c060Smiod int
bonito_bus_maxdevs(void * v,int busno)7542bf3c060Smiod bonito_bus_maxdevs(void *v, int busno)
7552bf3c060Smiod {
7562bf3c060Smiod 	struct bonito_softc *sc = v;
7572bf3c060Smiod 	const struct bonito_config *bc = sc->sc_bonito;
7582bf3c060Smiod 
7592bf3c060Smiod 	return busno == 0 ? 32 - bc->bc_adbase : 32;
7602bf3c060Smiod }
7612bf3c060Smiod 
7622bf3c060Smiod pcitag_t
bonito_make_tag(void * unused,int b,int d,int f)763b870770aSmiod bonito_make_tag(void *unused, int b, int d, int f)
7642bf3c060Smiod {
7652bf3c060Smiod 	return (b << 16) | (d << 11) | (f << 8);
7662bf3c060Smiod }
7672bf3c060Smiod 
7682bf3c060Smiod void
bonito_decompose_tag(void * unused,pcitag_t tag,int * bp,int * dp,int * fp)769b870770aSmiod bonito_decompose_tag(void *unused, pcitag_t tag, int *bp, int *dp, int *fp)
7702bf3c060Smiod {
7712bf3c060Smiod 	if (bp != NULL)
7722bf3c060Smiod 		*bp = (tag >> 16) & 0xff;
7732bf3c060Smiod 	if (dp != NULL)
7742bf3c060Smiod 		*dp = (tag >> 11) & 0x1f;
7752bf3c060Smiod 	if (fp != NULL)
7762bf3c060Smiod 		*fp = (tag >> 8) & 0x7;
7772bf3c060Smiod }
7782bf3c060Smiod 
7792bf3c060Smiod int
bonito_conf_addr(const struct bonito_config * bc,pcitag_t tag,int offset,u_int32_t * cfgoff,u_int32_t * pcimap_cfg)780b870770aSmiod bonito_conf_addr(const struct bonito_config *bc, pcitag_t tag, int offset,
7812bf3c060Smiod     u_int32_t *cfgoff, u_int32_t *pcimap_cfg)
7822bf3c060Smiod {
7832bf3c060Smiod 	int b, d, f;
7842bf3c060Smiod 
785b870770aSmiod 	bonito_decompose_tag(NULL, tag, &b, &d, &f);
7862bf3c060Smiod 
7872bf3c060Smiod 	if (b == 0) {
788b870770aSmiod 		d += bc->bc_adbase;
7892bf3c060Smiod 		if (d > 31)
7902bf3c060Smiod 			return 1;
7912bf3c060Smiod 		*cfgoff = (1 << d) | (f << 8) | offset;
7922bf3c060Smiod 		*pcimap_cfg = 0;
7932bf3c060Smiod 	} else {
7942bf3c060Smiod 		*cfgoff = tag | offset;
7952bf3c060Smiod 		*pcimap_cfg = BONITO_PCIMAPCFG_TYPE1;
7962bf3c060Smiod 	}
7972bf3c060Smiod 
7982bf3c060Smiod 	return 0;
7992bf3c060Smiod }
8002bf3c060Smiod 
8012bf3c060Smiod /* PCI Configuration Space access hook structure */
8022bf3c060Smiod struct bonito_cfg_hook {
8032bf3c060Smiod 	SLIST_ENTRY(bonito_cfg_hook) next;
8042bf3c060Smiod 	int	(*read)(void *, pci_chipset_tag_t, pcitag_t, int, pcireg_t *);
8052bf3c060Smiod 	int	(*write)(void *, pci_chipset_tag_t, pcitag_t, int, pcireg_t);
8062bf3c060Smiod 	void	*cookie;
8072bf3c060Smiod };
8082bf3c060Smiod 
8092bf3c060Smiod int
bonito_pci_hook(pci_chipset_tag_t pc,void * cookie,int (* r)(void *,pci_chipset_tag_t,pcitag_t,int,pcireg_t *),int (* w)(void *,pci_chipset_tag_t,pcitag_t,int,pcireg_t))8102bf3c060Smiod bonito_pci_hook(pci_chipset_tag_t pc, void *cookie,
8112bf3c060Smiod     int (*r)(void *, pci_chipset_tag_t, pcitag_t, int, pcireg_t *),
8122bf3c060Smiod     int (*w)(void *, pci_chipset_tag_t, pcitag_t, int, pcireg_t))
8132bf3c060Smiod {
8142bf3c060Smiod 	struct bonito_softc *sc = pc->pc_conf_v;
8152bf3c060Smiod 	struct bonito_cfg_hook *bch;
8162bf3c060Smiod 
8172bf3c060Smiod 	bch = malloc(sizeof *bch, M_DEVBUF, M_NOWAIT);
8182bf3c060Smiod 	if (bch == NULL)
8192bf3c060Smiod 		return ENOMEM;
8202bf3c060Smiod 
8212bf3c060Smiod 	bch->read = r;
8222bf3c060Smiod 	bch->write = w;
8232bf3c060Smiod 	bch->cookie = cookie;
8242bf3c060Smiod 	SLIST_INSERT_HEAD(&sc->sc_hook, bch, next);
8252bf3c060Smiod 	return 0;
8262bf3c060Smiod }
8272bf3c060Smiod 
828b1926db3Smiod int
bonito_conf_size(void * v,pcitag_t tag)829b1926db3Smiod bonito_conf_size(void *v, pcitag_t tag)
830b1926db3Smiod {
831b1926db3Smiod 	return PCI_CONFIG_SPACE_SIZE;
832b1926db3Smiod }
833b1926db3Smiod 
8342bf3c060Smiod pcireg_t
bonito_conf_read(void * v,pcitag_t tag,int offset)8352bf3c060Smiod bonito_conf_read(void *v, pcitag_t tag, int offset)
8362bf3c060Smiod {
8372bf3c060Smiod 	struct bonito_softc *sc = v;
8382bf3c060Smiod 	struct bonito_cfg_hook *hook;
839b870770aSmiod 	pcireg_t data;
8402bf3c060Smiod 
8412bf3c060Smiod 	SLIST_FOREACH(hook, &sc->sc_hook, next) {
8422bf3c060Smiod 		if (hook->read != NULL &&
8432bf3c060Smiod 		    (*hook->read)(hook->cookie, &sc->sc_pc, tag, offset,
8442bf3c060Smiod 		      &data) != 0)
8452bf3c060Smiod 			return data;
8462bf3c060Smiod 	}
8472bf3c060Smiod 
848b870770aSmiod 	return bonito_conf_read_internal(sc->sc_bonito, tag, offset);
849b870770aSmiod }
850b870770aSmiod 
851b870770aSmiod pcireg_t
bonito_conf_read_internal(const struct bonito_config * bc,pcitag_t tag,int offset)852b870770aSmiod bonito_conf_read_internal(const struct bonito_config *bc, pcitag_t tag,
853b870770aSmiod     int offset)
854b870770aSmiod {
855b870770aSmiod 	pcireg_t data;
856b870770aSmiod 	u_int32_t cfgoff, pcimap_cfg;
857a6ba7b46Smiod 	register_t sr;
858b870770aSmiod 	uint64_t imr;
859b870770aSmiod 
860b870770aSmiod 	if (bonito_conf_addr(bc, tag, offset, &cfgoff, &pcimap_cfg))
8612bf3c060Smiod 		return (pcireg_t)-1;
8622bf3c060Smiod 
86326da9fefSmiod 	sr = disableintr();
86426da9fefSmiod 	imr = REGVAL(BONITO_INTEN);
865ac27cb78Smiod 	REGVAL(BONITO_INTENCLR) = 0xffffffff;
86626da9fefSmiod 	(void)REGVAL(BONITO_INTENCLR);
8672bf3c060Smiod 
8682bf3c060Smiod 	/* clear aborts */
869ac27cb78Smiod 	REGVAL(BONITO_PCI_REG(PCI_COMMAND_STATUS_REG)) |=
8702bf3c060Smiod 	    PCI_STATUS_MASTER_ABORT | PCI_STATUS_MASTER_TARGET_ABORT;
8712bf3c060Smiod 
8722bf3c060Smiod 	/* high 16 bits of address go into PciMapCfg register */
8732bf3c060Smiod 	REGVAL(BONITO_PCIMAP_CFG) = (cfgoff >> 16) | pcimap_cfg;
87426da9fefSmiod 	(void)REGVAL(BONITO_PCIMAP_CFG);
8752bf3c060Smiod 	wbflush();
8762bf3c060Smiod 
8772bf3c060Smiod 	/* low 16 bits of address are offset into config space */
8782bf3c060Smiod 	data = REGVAL(BONITO_PCICFG_BASE + (cfgoff & 0xfffc));
8792bf3c060Smiod 
8802bf3c060Smiod 	/* check for error */
881ac27cb78Smiod 	if (REGVAL(BONITO_PCI_REG(PCI_COMMAND_STATUS_REG)) &
8822bf3c060Smiod 	    (PCI_STATUS_MASTER_ABORT | PCI_STATUS_MASTER_TARGET_ABORT)) {
883ac27cb78Smiod 		REGVAL(BONITO_PCI_REG(PCI_COMMAND_STATUS_REG)) |=
8842bf3c060Smiod 		    PCI_STATUS_MASTER_ABORT | PCI_STATUS_MASTER_TARGET_ABORT;
8852bf3c060Smiod 		data = (pcireg_t) -1;
8862bf3c060Smiod 	}
8872bf3c060Smiod 
88826da9fefSmiod 	REGVAL(BONITO_INTENSET) = imr;
88926da9fefSmiod 	(void)REGVAL(BONITO_INTENSET);
89026da9fefSmiod 	setsr(sr);
8912bf3c060Smiod 
8922bf3c060Smiod 	return data;
8932bf3c060Smiod }
8942bf3c060Smiod 
8952bf3c060Smiod void
bonito_conf_write(void * v,pcitag_t tag,int offset,pcireg_t data)8962bf3c060Smiod bonito_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data)
8972bf3c060Smiod {
8982bf3c060Smiod 	struct bonito_softc *sc = v;
89926da9fefSmiod 	u_int32_t cfgoff, pcimap_cfg;
9002bf3c060Smiod 	struct bonito_cfg_hook *hook;
901a6ba7b46Smiod 	register_t sr;
90226da9fefSmiod 	uint64_t imr;
9032bf3c060Smiod 
9042bf3c060Smiod 	SLIST_FOREACH(hook, &sc->sc_hook, next) {
9052bf3c060Smiod 		if (hook->write != NULL &&
9062bf3c060Smiod 		    (*hook->write)(hook->cookie, &sc->sc_pc, tag, offset,
9072bf3c060Smiod 		      data) != 0)
9082bf3c060Smiod 			return;
9092bf3c060Smiod 	}
9102bf3c060Smiod 
911b870770aSmiod 	if (bonito_conf_addr(sc->sc_bonito, tag, offset, &cfgoff, &pcimap_cfg))
9122bf3c060Smiod 		panic("bonito_conf_write");
9132bf3c060Smiod 
91426da9fefSmiod 	sr = disableintr();
91526da9fefSmiod 	imr = REGVAL(BONITO_INTEN);
916ac27cb78Smiod 	REGVAL(BONITO_INTENCLR) = 0xffffffff;
91726da9fefSmiod 	(void)REGVAL(BONITO_INTENCLR);
9182bf3c060Smiod 
9192bf3c060Smiod 	/* clear aborts */
920ac27cb78Smiod 	REGVAL(BONITO_PCI_REG(PCI_COMMAND_STATUS_REG)) |=
9212bf3c060Smiod 	    PCI_STATUS_MASTER_ABORT | PCI_STATUS_MASTER_TARGET_ABORT;
9222bf3c060Smiod 
9232bf3c060Smiod 	/* high 16 bits of address go into PciMapCfg register */
9242bf3c060Smiod 	REGVAL(BONITO_PCIMAP_CFG) = (cfgoff >> 16) | pcimap_cfg;
92526da9fefSmiod 	(void)REGVAL(BONITO_PCIMAP_CFG);
9262bf3c060Smiod 	wbflush();
9272bf3c060Smiod 
9282bf3c060Smiod 	/* low 16 bits of address are offset into config space */
9292bf3c060Smiod 	REGVAL(BONITO_PCICFG_BASE + (cfgoff & 0xfffc)) = data;
9302bf3c060Smiod 
93126da9fefSmiod 	REGVAL(BONITO_INTENSET) = imr;
93226da9fefSmiod 	(void)REGVAL(BONITO_INTENSET);
93326da9fefSmiod 	setsr(sr);
9342bf3c060Smiod }
9352bf3c060Smiod 
9362bf3c060Smiod /*
9372bf3c060Smiod  * PCI Interrupt handling
9382bf3c060Smiod  */
9392bf3c060Smiod 
9402bf3c060Smiod int
bonito_pci_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)9412bf3c060Smiod bonito_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
9422bf3c060Smiod {
943e1844cd9Smiod 	struct bonito_softc *sc = pa->pa_pc->pc_intr_v;
944e1844cd9Smiod 	const struct bonito_config *bc = sc->sc_bonito;
945e1844cd9Smiod 	int bus, dev, fn, pin;
9462bf3c060Smiod 
947d57a735dSmiod 	*ihp = (pci_intr_handle_t)-1;
9482bf3c060Smiod 
9492bf3c060Smiod 	if (pa->pa_intrpin == 0)	/* no interrupt needed */
9502bf3c060Smiod 		return 1;
9512bf3c060Smiod 
9522bf3c060Smiod #ifdef DIAGNOSTIC
9532bf3c060Smiod 	if (pa->pa_intrpin > 4) {
9542bf3c060Smiod 		printf("%s: bad interrupt pin %d\n", __func__, pa->pa_intrpin);
9552bf3c060Smiod 		return 1;
9562bf3c060Smiod 	}
9572bf3c060Smiod #endif
9582bf3c060Smiod 
959e1844cd9Smiod 	pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &fn);
9602bf3c060Smiod 	if (pa->pa_bridgetag) {
9612bf3c060Smiod 		pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev);
9622bf3c060Smiod 		*ihp = pa->pa_bridgeih[pin - 1];
9632bf3c060Smiod 	} else {
964e1844cd9Smiod 		if (bus == 0)
965e1844cd9Smiod 			*ihp = (*bc->bc_intr_map)(dev, fn, pa->pa_intrpin);
9662bf3c060Smiod 
967d57a735dSmiod 		if (*ihp == (pci_intr_handle_t)-1)
9682bf3c060Smiod 			return 1;
9692bf3c060Smiod 	}
9702bf3c060Smiod 
9712bf3c060Smiod 	return 0;
9722bf3c060Smiod }
9732bf3c060Smiod 
9742bf3c060Smiod const char *
bonito_pci_intr_string(void * cookie,pci_intr_handle_t ih)9752bf3c060Smiod bonito_pci_intr_string(void *cookie, pci_intr_handle_t ih)
9762bf3c060Smiod {
9772bf3c060Smiod 	static char irqstr[1 + 12];
9782bf3c060Smiod 
9792bf3c060Smiod 	if (BONITO_IRQ_IS_ISA(ih))
980b7eb4a84Sjsing 		snprintf(irqstr, sizeof irqstr, "isa irq %lu",
981d57a735dSmiod 		    BONITO_IRQ_TO_ISA(ih));
9822bf3c060Smiod 	else
983b7eb4a84Sjsing 		snprintf(irqstr, sizeof irqstr, "irq %lu", ih);
9842bf3c060Smiod 	return irqstr;
9852bf3c060Smiod }
9862bf3c060Smiod 
9872bf3c060Smiod void *
bonito_pci_intr_establish(void * cookie,pci_intr_handle_t ih,int level,int (* cb)(void *),void * cbarg,char * name)9882bf3c060Smiod bonito_pci_intr_establish(void *cookie, pci_intr_handle_t ih, int level,
9892bf3c060Smiod     int (*cb)(void *), void *cbarg, char *name)
9902bf3c060Smiod {
9912bf3c060Smiod 	return bonito_intr_establish(ih, IST_LEVEL, level, cb, cbarg, name);
9922bf3c060Smiod }
9932bf3c060Smiod 
9942bf3c060Smiod void
bonito_pci_intr_disestablish(void * cookie,void * ihp)9952bf3c060Smiod bonito_pci_intr_disestablish(void *cookie, void *ihp)
9962bf3c060Smiod {
9972bf3c060Smiod 	bonito_intr_disestablish(ihp);
9982bf3c060Smiod }
9992bf3c060Smiod 
1000ac27cb78Smiod /*
1001d57a735dSmiod  * bus_space mapping routines.
1002ac27cb78Smiod  */
1003ac27cb78Smiod 
100451b07be5Smiod /*
100551b07be5Smiod  * Legacy I/O access protection.
100651b07be5Smiod  * Since MI ISA code does not expect bus access to cause any failure when
100751b07be5Smiod  * accessing missing hardware, but only receive bogus data in return, we
100851b07be5Smiod  * force bus_space_map() to fail if there is no hardware there.
100951b07be5Smiod  */
101051b07be5Smiod 
101151b07be5Smiod int
bonito_io_map(bus_space_tag_t t,bus_addr_t offs,bus_size_t size,int flags,bus_space_handle_t * bshp)101251b07be5Smiod bonito_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
101351b07be5Smiod     bus_space_handle_t *bshp)
101451b07be5Smiod {
101551b07be5Smiod 	const struct legacy_io_range *r;
1016f81b2663Smiod 	bus_addr_t rend;
101751b07be5Smiod 
101851b07be5Smiod 	if (offs < BONITO_PCIIO_LEGACY) {
1019f81b2663Smiod 		if ((r = sys_platform->legacy_io_ranges) == NULL)
1020f81b2663Smiod 			return ENXIO;
1021f81b2663Smiod 
1022f81b2663Smiod 		rend = offs + size - 1;
1023f81b2663Smiod 		for (; r->start != 0; r++)
1024f81b2663Smiod 			if (offs >= r->start && rend <= r->end)
102551b07be5Smiod 				break;
102651b07be5Smiod 
1027d57a735dSmiod 		if (r->end == 0)
102851b07be5Smiod 			return ENXIO;
102951b07be5Smiod 	}
103051b07be5Smiod 
103151b07be5Smiod 	*bshp = t->bus_base + offs;
103251b07be5Smiod 	return 0;
103351b07be5Smiod }
103451b07be5Smiod 
103551b07be5Smiod /*
1036ec2663a6Smiod  * PCI memory access.
1037ec2663a6Smiod  * Things are a bit complicated here, as we can either use one of the 64MB
1038ec2663a6Smiod  * windows in PCILO space (making sure ranges spanning multiple windows will
1039ec2663a6Smiod  * turn contiguous), or a direct access within the PCIHI space.
1040ec2663a6Smiod  * Note that, on 2F systems, only the PCIHI range for which CPU->PCI accesses
1041ec2663a6Smiod  * are enabled in the crossbar is usable.
1042ec2663a6Smiod  */
1043ec2663a6Smiod 
1044ec2663a6Smiod int
bonito_mem_map(bus_space_tag_t t,bus_addr_t offs,bus_size_t size,int flags,bus_space_handle_t * bshp)1045ec2663a6Smiod bonito_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
1046ec2663a6Smiod     bus_space_handle_t *bshp)
1047ec2663a6Smiod {
1048ec2663a6Smiod 	uint32_t pcimap;
1049ec2663a6Smiod 	bus_addr_t pcilo_w[3];
1050ec2663a6Smiod 	bus_addr_t ws, we, w;
1051ec2663a6Smiod 	bus_addr_t end = offs + size - 1;
1052d57a735dSmiod 	int pcilo_window;
1053ec2663a6Smiod 
105450e1ba7cSmiod 	pcimap = REGVAL(BONITO_PCIMAP);
105550e1ba7cSmiod 
1056ec2663a6Smiod 	/*
1057877e1885Smiod 	 * Try a PCIHI mapping first.
1058877e1885Smiod 	 */
1059877e1885Smiod 
10604e0b48a5Smiod 	if (loongson_ver >= 0x2f) {
1061877e1885Smiod 		if (offs >= LS2F_PCIHI_BASE && end <= LS2F_PCIHI_TOP) {
1062877e1885Smiod 			*bshp = t->bus_base + offs;
1063877e1885Smiod 			return 0;
1064877e1885Smiod 		}
1065877e1885Smiod 	} else {
1066d57a735dSmiod 		/*
1067d57a735dSmiod 		 * Only try HI space if we do not have memory setup there.
1068d57a735dSmiod 		 */
1069d57a735dSmiod 		if (physmem <= atop(BONITO_PCILO_BASE)) {
1070877e1885Smiod 			/* PCI1.5 */
1071d57a735dSmiod 			if (offs >= BONITO_PCIHI_BASE &&
1072d57a735dSmiod 			    end <= BONITO_PCIHI_TOP) {
1073877e1885Smiod 				*bshp = t->bus_base + offs;
1074877e1885Smiod 				return 0;
1075877e1885Smiod 			}
1076877e1885Smiod 
1077877e1885Smiod 			/* PCI2 */
1078877e1885Smiod 			w = pcimap & BONITO_PCIMAP_PCIMAP_2 ? 0x80000000UL : 0;
1079877e1885Smiod 			if (offs >= w && end < (w + 0x80000000UL)) {
1080877e1885Smiod 				*bshp = t->bus_base + 0x80000000UL + (offs - w);
1081877e1885Smiod 				return 0;
1082877e1885Smiod 			}
1083877e1885Smiod 		}
1084d57a735dSmiod 	}
1085877e1885Smiod 
1086877e1885Smiod 	/*
1087877e1885Smiod 	 * No luck, try a PCILO mapping.
1088877e1885Smiod 	 */
1089877e1885Smiod 
1090877e1885Smiod 	/*
1091ec2663a6Smiod 	 * Decode PCIMAP, and figure out what PCILO mappings are
1092ec2663a6Smiod 	 * possible.
1093ec2663a6Smiod 	 */
1094ec2663a6Smiod 
1095ec2663a6Smiod 	pcilo_w[0] = (pcimap & BONITO_PCIMAP_PCIMAP_LO0) >>
1096ec2663a6Smiod 	    BONITO_PCIMAP_PCIMAP_LO0_SHIFT;
1097ec2663a6Smiod 	pcilo_w[1] = (pcimap & BONITO_PCIMAP_PCIMAP_LO1) >>
1098ec2663a6Smiod 	    BONITO_PCIMAP_PCIMAP_LO1_SHIFT;
1099ec2663a6Smiod 	pcilo_w[2] = (pcimap & BONITO_PCIMAP_PCIMAP_LO2) >>
1100ec2663a6Smiod 	    BONITO_PCIMAP_PCIMAP_LO2_SHIFT;
1101ec2663a6Smiod 
1102ec2663a6Smiod 	/*
1103ec2663a6Smiod 	 * Check if the 64MB areas we want to span are all available as
1104ec2663a6Smiod 	 * contiguous PCILO mappings.
1105ec2663a6Smiod 	 */
1106ec2663a6Smiod 
1107ec2663a6Smiod 	ws = offs >> 26;
1108ec2663a6Smiod 	we = end >> 26;
1109ec2663a6Smiod 
1110ec2663a6Smiod 	pcilo_window = -1;
1111ec2663a6Smiod 	if (ws == pcilo_w[0])
1112ec2663a6Smiod 		pcilo_window = 0;
1113ec2663a6Smiod 	else if (ws == pcilo_w[1])
1114ec2663a6Smiod 		pcilo_window = 1;
1115ec2663a6Smiod 	else if (ws == pcilo_w[2])
1116ec2663a6Smiod 		pcilo_window = 2;
1117ec2663a6Smiod 
1118ec2663a6Smiod 	if (pcilo_window >= 0) {
1119ec2663a6Smiod 		/* contiguous area test */
1120ec2663a6Smiod 		for (w = ws + 1; w <= we; w++) {
1121ec2663a6Smiod 			if (pcilo_window + (w - ws) > 2 ||
1122ec2663a6Smiod 			    w != pcilo_w[pcilo_window + (w - ws)]) {
1123ec2663a6Smiod 				pcilo_window = -1;
1124ec2663a6Smiod 				break;
1125ec2663a6Smiod 			}
1126ec2663a6Smiod 		}
1127ec2663a6Smiod 	}
1128ec2663a6Smiod 
1129ec2663a6Smiod 	if (pcilo_window >= 0) {
1130ec2663a6Smiod 		*bshp = t->bus_base + BONITO_PCILO_BASE +
1131ec2663a6Smiod 		    BONITO_PCIMAP_WINBASE(pcilo_window) +
1132ec2663a6Smiod 		    BONITO_PCIMAP_WINOFFSET(offs);
1133ec2663a6Smiod 		return 0;
1134ec2663a6Smiod 	}
1135ec2663a6Smiod 
1136ec2663a6Smiod 	return EINVAL;
1137ec2663a6Smiod }
1138ec2663a6Smiod 
1139ec2663a6Smiod /*
114051b07be5Smiod  * PCI resource handling
114151b07be5Smiod  */
114251b07be5Smiod 
114351b07be5Smiod struct extent *
bonito_get_resource_extent(pci_chipset_tag_t pc,int io)114451b07be5Smiod bonito_get_resource_extent(pci_chipset_tag_t pc, int io)
114551b07be5Smiod {
114651b07be5Smiod 	struct bonito_softc *sc = pc->pc_conf_v;
114751b07be5Smiod 	struct extent *ex;
114851b07be5Smiod 	char *exname;
114951b07be5Smiod 	size_t exnamesz;
115051b07be5Smiod 	uint32_t reg;
115151b07be5Smiod 	int errors;
115251b07be5Smiod 
115351b07be5Smiod 	exnamesz = 1 + 16 + 4;
115451b07be5Smiod 	exname = (char *)malloc(exnamesz, M_DEVBUF, M_NOWAIT);
115551b07be5Smiod 	if (exname == NULL)
115651b07be5Smiod 		return NULL;
115751b07be5Smiod 	snprintf(exname, exnamesz, "%s%s", sc->sc_dev.dv_xname,
115851b07be5Smiod 	    io ? "_io" : "_mem");
115951b07be5Smiod 
116051b07be5Smiod 	ex = extent_create(exname, 0, 0xffffffff, M_DEVBUF, NULL, 0,
116151b07be5Smiod 	    EX_NOWAIT | EX_FILLED);
116251b07be5Smiod 	if (ex == NULL)
116351b07be5Smiod 		goto out;
116451b07be5Smiod 
116551b07be5Smiod 	errors = 0;
116651b07be5Smiod 	if (io) {
116751b07be5Smiod 		/*
116851b07be5Smiod 		 * Reserve the low 16KB of I/O space to the legacy hardware,
116951b07be5Smiod 		 * if any.
117051b07be5Smiod 		 */
117151b07be5Smiod 		if (extent_free(ex, BONITO_PCIIO_LEGACY, BONITO_PCIIO_SIZE,
117251b07be5Smiod 		    EX_NOWAIT) != 0)
117351b07be5Smiod 			errors++;
117451b07be5Smiod 	} else {
117551b07be5Smiod 		reg = REGVAL(BONITO_PCIMAP);
117651b07be5Smiod 		if (extent_free(ex,
117751b07be5Smiod 		    BONITO_PCIMAP_WINBASE((reg & BONITO_PCIMAP_PCIMAP_LO0) >>
117851b07be5Smiod 		      BONITO_PCIMAP_PCIMAP_LO0_SHIFT),
117951b07be5Smiod 		    BONITO_PCIMAP_WINSIZE, EX_NOWAIT) != 0)
118051b07be5Smiod 			errors++;
118151b07be5Smiod 		if (extent_free(ex,
118251b07be5Smiod 		    BONITO_PCIMAP_WINBASE((reg & BONITO_PCIMAP_PCIMAP_LO1) >>
118351b07be5Smiod 		      BONITO_PCIMAP_PCIMAP_LO1_SHIFT),
118451b07be5Smiod 		    BONITO_PCIMAP_WINSIZE, EX_NOWAIT) != 0)
118551b07be5Smiod 			errors++;
118651b07be5Smiod 		if (extent_free(ex,
118751b07be5Smiod 		    BONITO_PCIMAP_WINBASE((reg & BONITO_PCIMAP_PCIMAP_LO2) >>
118851b07be5Smiod 		      BONITO_PCIMAP_PCIMAP_LO2_SHIFT),
118951b07be5Smiod 		    BONITO_PCIMAP_WINSIZE, EX_NOWAIT) != 0)
119051b07be5Smiod 			errors++;
119151b07be5Smiod 
119251b07be5Smiod 		if (sc->sc_compatible) {
119351b07be5Smiod 			/* XXX make PCIMAP_HI available if PCIMAP_2 set */
119451b07be5Smiod 		}
119551b07be5Smiod 	}
119651b07be5Smiod 
119751b07be5Smiod 	if (errors != 0) {
119851b07be5Smiod 		extent_destroy(ex);
119951b07be5Smiod 		ex = NULL;
120051b07be5Smiod 	}
120151b07be5Smiod 
120251b07be5Smiod #ifdef BONITO_DEBUG
120351b07be5Smiod 	extent_print(ex);
120451b07be5Smiod #endif
120551b07be5Smiod 
120651b07be5Smiod out:
120741c0f940Sderaadt 	free(exname, M_DEVBUF, exnamesz);
120851b07be5Smiod 
120951b07be5Smiod 	return ex;
121051b07be5Smiod }
121151b07be5Smiod 
121251b07be5Smiod /*
1213b870770aSmiod  * Functions used during early system configuration (before bonito attaches).
1214b870770aSmiod  */
1215b870770aSmiod 
121603052511Smiod pcitag_t bonito_make_tag_early(int, int, int);
121703052511Smiod pcireg_t bonito_conf_read_early(pcitag_t, int);
121803052511Smiod 
1219b870770aSmiod pcitag_t
bonito_make_tag_early(int b,int d,int f)122003052511Smiod bonito_make_tag_early(int b, int d, int f)
1221b870770aSmiod {
1222b870770aSmiod 	return bonito_make_tag(NULL, b, d, f);
1223b870770aSmiod }
1224b870770aSmiod 
1225b870770aSmiod pcireg_t
bonito_conf_read_early(pcitag_t tag,int reg)122603052511Smiod bonito_conf_read_early(pcitag_t tag, int reg)
1227b870770aSmiod {
122851b07be5Smiod 	return bonito_conf_read_internal(sys_platform->bonito_config, tag, reg);
1229b870770aSmiod }
123003052511Smiod 
123103052511Smiod void
bonito_early_setup()123203052511Smiod bonito_early_setup()
123303052511Smiod {
123403052511Smiod 	pci_make_tag_early = bonito_make_tag_early;
123503052511Smiod 	pci_conf_read_early = bonito_conf_read_early;
123603052511Smiod 
123703052511Smiod 	early_mem_t = &bonito_pci_mem_space_tag;
123803052511Smiod 	early_io_t = &bonito_pci_io_space_tag;
123903052511Smiod }
1240