159191Skris/* $NetBSD: pci_gio.c,v 1.20 2023/12/20 15:29:07 thorpej Exp $ */ 259191Skris 359191Skris/* 459191Skris * Copyright (c) 2006 Stephen M. Rumble 5109998Smarkm * All rights reserved. 6109998Smarkm * 7109998Smarkm * Redistribution and use in source and binary forms, with or without 8109998Smarkm * modification, are permitted provided that the following conditions 9109998Smarkm * are met: 10109998Smarkm * 1. Redistributions of source code must retain the above copyright 11109998Smarkm * notice, this list of conditions and the following disclaimer. 12109998Smarkm * 2. The name of the author may not be used to endorse or promote products 13109998Smarkm * derived from this software without specific prior written permission. 14109998Smarkm * 15109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16109998Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17109998Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18109998Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19109998Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2059191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2159191Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2259191Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2359191Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2459191Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25160814Ssimon */ 26109998Smarkm 27109998Smarkm#include <sys/cdefs.h> 28109998Smarkm__KERNEL_RCSID(0, "$NetBSD: pci_gio.c,v 1.20 2023/12/20 15:29:07 thorpej Exp $"); 29109998Smarkm 30109998Smarkm/* 31109998Smarkm * Glue for PCI devices that are connected to the GIO bus by various little 32109998Smarkm * GIO<->PCI ASICs. 33109998Smarkm * 34109998Smarkm * We presently support the following boards: 35109998Smarkm * o Phobos G100/G130/G160 (if_tlp, lxtphy) 36109998Smarkm * o Set Engineering GFE (if_tl, nsphy) 37109998Smarkm */ 38109998Smarkm 39109998Smarkm#include "opt_pci.h" 40109998Smarkm#include "pci.h" 41109998Smarkm 42109998Smarkm#include <sys/param.h> 43109998Smarkm#include <sys/systm.h> 44109998Smarkm#include <sys/device.h> 45109998Smarkm 46109998Smarkm#include <sys/bus.h> 47109998Smarkm#include <machine/machtype.h> 4868651Skris 4959191Skris#include <sgimips/gio/giovar.h> 5068651Skris#include <sgimips/gio/gioreg.h> 5159191Skris#include <sgimips/gio/giodevs.h> 5259191Skris 5368651Skris#include <sgimips/dev/imcvar.h> 5459191Skris 5559191Skris#include <mips/cache.h> 5659191Skris 5759191Skris#include <dev/pci/pcivar.h> 5868651Skris#include <dev/pci/pcireg.h> 5959191Skris#include <dev/pci/pcidevs.h> 6059191Skris#include <dev/pci/pciconf.h> 6159191Skris 6259191Skrisint giopci_debug = 0; 63109998Smarkm#define DPRINTF(_x) if (giopci_debug) printf _x 6468651Skris 6568651Skrisstruct giopci_softc { 6668651Skris struct sgimips_pci_chipset sc_pc; 6759191Skris int sc_slot; 6859191Skris int sc_gprid; 6959191Skris uint32_t sc_pci_len; 7059191Skris bus_space_tag_t sc_iot; 7159191Skris bus_space_handle_t sc_ioh; 7259191Skris}; 7359191Skris 7459191Skrisstatic int giopci_match(device_t, cfdata_t, void *); 7568651Skrisstatic void giopci_attach(device_t, device_t, void *); 7668651Skrisstatic int giopci_bus_maxdevs(pci_chipset_tag_t, int); 7768651Skrisstatic pcireg_t giopci_conf_read(pci_chipset_tag_t, pcitag_t, int); 7868651Skrisstatic void giopci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); 7959191Skrisstatic int giopci_conf_hook(pci_chipset_tag_t, int, int, int, pcireg_t); 8059191Skrisstatic int giopci_intr_map(const struct pci_attach_args *, 8159191Skris pci_intr_handle_t *); 8259191Skrisstatic const char * 8368651Skris giopci_intr_string(pci_chipset_tag_t, pci_intr_handle_t, 8459191Skris char *, size_t); 8568651Skrisstatic void *giopci_intr_establish(int, int, int (*)(void *), void *); 8668651Skrisstatic void giopci_intr_disestablish(void *); 8759191Skris 8868651Skris#define PHOBOS_PCI_OFFSET 0x00100000 8968651Skris#define PHOBOS_PCI_LENGTH 128 /* ~arbitrary */ 9059191Skris#define PHOBOS_TULIP_START 0x00101000 9159191Skris#define PHOBOS_TULIP_END 0x001fffff 9259191Skris 9359191Skris#define SETENG_MAGIC_OFFSET 0x00020000 9459191Skris#define SETENG_MAGIC_VALUE 0x00001000 9559191Skris#define SETENG_PCI_OFFSET 0x00080000 9659191Skris#define SETENG_PCI_LENGTH 128 /* ~arbitrary */ 9759191Skris#define SETENG_TLAN_START 0x00100000 9859191Skris#define SETENG_TLAN_END 0x001fffff 99109998Smarkm 10059191SkrisCFATTACH_DECL_NEW(giopci, sizeof(struct giopci_softc), 101109998Smarkm giopci_match, giopci_attach, NULL, NULL); 102109998Smarkm 103109998Smarkmstatic void pcimem_bus_mem_init(bus_space_tag_t, void *); 104109998Smarkmstatic struct mips_bus_space pcimem_mbst; 105109998Smarkmbus_space_tag_t gio_pci_memt = NULL; 106109998Smarkm 107109998Smarkmstatic int 108109998Smarkmgiopci_match(device_t parent, cfdata_t match, void *aux) 109109998Smarkm{ 110109998Smarkm struct gio_attach_args *ga = aux; 111109998Smarkm int gprid; 112109998Smarkm 11359191Skris /* 11459191Skris * I think that these cards are all GIO32-bis or GIO64. Thus 11559191Skris * they work in either Indigo2/Challenge M or 11659191Skris * Indy/Challenge S/Indigo R4k, according to form factor. However, 11759191Skris * there are some exceptions (e.g. my Indigo R4k won't power 11859191Skris * on with the Set Engineering card installed). 119109998Smarkm */ 12059191Skris if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22) 121109998Smarkm return (0); 122109998Smarkm 123109998Smarkm gprid = GIO_PRODUCT_PRODUCTID(ga->ga_product); 124109998Smarkm if (gprid == PHOBOS_G100 || gprid == PHOBOS_G130 || 125109998Smarkm gprid == PHOBOS_G160 || gprid == SETENG_GFE) 126109998Smarkm return (1); 127109998Smarkm 12859191Skris return (0); 129109998Smarkm} 130109998Smarkm 131109998Smarkmstatic void 132109998Smarkmgiopci_attach(device_t parent, device_t self, void *aux) 133109998Smarkm{ 13459191Skris struct giopci_softc *sc = device_private(self); 135109998Smarkm pci_chipset_tag_t pc = &sc->sc_pc; 136109998Smarkm struct gio_attach_args *ga = aux; 137109998Smarkm uint32_t pci_off, pci_len, arb; 138109998Smarkm struct pcibus_attach_args pba; 139109998Smarkm u_long m_start, m_end; 140109998Smarkm#ifdef PCI_NETBSD_CONFIGURE 14159191Skris extern int pci_conf_debug; 142109998Smarkm 143109998Smarkm pci_conf_debug = giopci_debug; 144109998Smarkm#endif 145109998Smarkm 146109998Smarkm sc->sc_iot = ga->ga_iot; 14759191Skris sc->sc_slot = ga->ga_slot; 148109998Smarkm sc->sc_gprid = GIO_PRODUCT_PRODUCTID(ga->ga_product); 149109998Smarkm 150109998Smarkm pcimem_bus_mem_init(&pcimem_mbst, NULL); 151109998Smarkm gio_pci_memt = &pcimem_mbst; 15259191Skris 153109998Smarkm if (mach_type == MACH_SGI_IP22 && 154109998Smarkm mach_subtype == MACH_SGI_IP22_FULLHOUSE) 155109998Smarkm arb = GIO_ARB_RT | GIO_ARB_MST | GIO_ARB_PIPE; 156109998Smarkm else 157109998Smarkm arb = GIO_ARB_RT | GIO_ARB_MST; 158109998Smarkm 159109998Smarkm if (gio_arb_config(ga->ga_slot, arb)) { 160109998Smarkm printf(": failed to configure GIO bus arbiter\n"); 161109998Smarkm return; 162109998Smarkm } 16359191Skris 16459191Skris#if (NIMC > 0) 16559191Skris imc_disable_sysad_parity(); 16659191Skris#endif 16759191Skris 16859191Skris switch (sc->sc_gprid) { 16959191Skris case PHOBOS_G100: 17059191Skris case PHOBOS_G130: 17159191Skris case PHOBOS_G160: 172109998Smarkm pci_off = PHOBOS_PCI_OFFSET; 173109998Smarkm pci_len = PHOBOS_PCI_LENGTH; 174109998Smarkm m_start = MIPS_KSEG1_TO_PHYS(ga->ga_addr + PHOBOS_TULIP_START); 175109998Smarkm m_end = MIPS_KSEG1_TO_PHYS(ga->ga_addr + PHOBOS_TULIP_END); 176109998Smarkm break; 177109998Smarkm 178109998Smarkm case SETENG_GFE: 17959191Skris /* 18059191Skris * NB: The SetEng board does not allow the ThunderLAN's DMA 18159191Skris * engine to properly transfer segments that span page 18268651Skris * boundaries. See sgimips/autoconf.c where we catch a 18368651Skris * tl(4) device attachment and create an appropriate 18468651Skris * proplib entry to enable the workaround. 18559191Skris */ 18668651Skris pci_off = SETENG_PCI_OFFSET; 18768651Skris pci_len = SETENG_PCI_LENGTH; 18868651Skris m_start = MIPS_KSEG1_TO_PHYS(ga->ga_addr + SETENG_TLAN_START); 18968651Skris m_end = MIPS_KSEG1_TO_PHYS(ga->ga_addr + SETENG_TLAN_END); 19059191Skris bus_space_write_4(ga->ga_iot, ga->ga_ioh, 19159191Skris SETENG_MAGIC_OFFSET, SETENG_MAGIC_VALUE); 19259191Skris break; 19359191Skris 19459191Skris default: 19559191Skris panic("giopci_attach: unsupported GIO product id 0x%02x", 19659191Skris sc->sc_gprid); 19759191Skris } 19859191Skris 19959191Skris if (bus_space_subregion(ga->ga_iot, ga->ga_ioh, pci_off, pci_len, 20059191Skris &sc->sc_ioh)) { 20159191Skris printf("%s: unable to map PCI registers\n", device_xname(self)); 20259191Skris return; 20359191Skris } 20459191Skris sc->sc_pci_len = pci_len; 20559191Skris 20659191Skris pc->pc_bus_maxdevs = giopci_bus_maxdevs; 20759191Skris pc->pc_conf_read = giopci_conf_read; 20859191Skris pc->pc_conf_write = giopci_conf_write; 20959191Skris pc->pc_conf_hook = giopci_conf_hook; 21068651Skris pc->pc_intr_map = giopci_intr_map; 21168651Skris pc->pc_intr_string = giopci_intr_string; 21268651Skris pc->intr_establish = giopci_intr_establish; 21368651Skris pc->intr_disestablish = giopci_intr_disestablish; 21468651Skris pc->iot = ga->ga_iot; 21559191Skris pc->ioh = ga->ga_ioh; 21659191Skris pc->cookie = sc; 21759191Skris 21859191Skris printf(": %s\n", gio_product_string(sc->sc_gprid)); 21959191Skris 22059191Skris#ifdef PCI_NETBSD_CONFIGURE 22159191Skris struct pciconf_resources *pcires = pciconf_resource_init(); 22259191Skris 22359191Skris pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM, 22459191Skris m_start, (m_end - m_start) + 1); 22559191Skris 22659191Skris pci_configure_bus(pc, pcires, 0, 22759191Skris mips_cache_info.mci_dcache_align); 22859191Skris 22959191Skris pciconf_resource_fini(pcires); 23059191Skris#endif 23168651Skris 23259191Skris memset(&pba, 0, sizeof(pba)); 23368651Skris pba.pba_memt = gio_pci_memt; 23468651Skris pba.pba_dmat = ga->ga_dmat; 23568651Skris pba.pba_pc = pc; 23668651Skris pba.pba_flags = PCI_FLAGS_MEM_OKAY; 23759191Skris /* NB: do not set PCI_FLAGS_{MRL,MRM,MWI}_OKAY -- true ?! */ 23859191Skris 239160814Ssimon config_found(self, &pba, pcibusprint, CFARGS_NONE); 240160814Ssimon} 24159191Skris 242109998Smarkmstatic int 243109998Smarkmgiopci_bus_maxdevs(pci_chipset_tag_t pc, int busno) 24459191Skris{ 245109998Smarkm 246109998Smarkm return (busno == 0); 24759191Skris} 24868651Skris 24959191Skrisstatic pcireg_t 25059191Skrisgiopci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 25159191Skris{ 25259191Skris struct giopci_softc *sc = pc->cookie; 25359191Skris int bus, dev, func; 25459191Skris pcireg_t data; 25559191Skris 25659191Skris if ((unsigned int)reg >= PCI_CONF_SIZE) 25759191Skris return (pcireg_t) -1; 25859191Skris 25959191Skris pci_decompose_tag(pc, tag, &bus, &dev, &func); 26059191Skris if (bus != 0 || dev != 0 || func != 0) 261109998Smarkm return (0); 262109998Smarkm 26359191Skris /* XXX - should just use bus_space_peek */ 26459191Skris if (reg >= sc->sc_pci_len) { 26559191Skris DPRINTF(("giopci_conf_read: reg 0x%x out of bounds\n", reg)); 26659191Skris return (0); 26759191Skris } 26859191Skris 26959191Skris DPRINTF(("giopci_conf_read: reg 0x%x = 0x", reg)); 27059191Skris data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); 27159191Skris DPRINTF(("%08x\n", data)); 27259191Skris 27359191Skris return (data); 27468651Skris} 27568651Skris 27668651Skrisstatic void 27768651Skrisgiopci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 27868651Skris{ 27968651Skris struct giopci_softc *sc = pc->cookie; 28068651Skris int bus, dev, func; 28168651Skris 28268651Skris if ((unsigned int)reg >= PCI_CONF_SIZE) 28368651Skris return; 28468651Skris 28568651Skris pci_decompose_tag(pc, tag, &bus, &dev, &func); 28668651Skris if (bus != 0 || dev != 0 || func != 0) 28768651Skris return; 28868651Skris 28968651Skris /* XXX - should just use bus_space_poke */ 29068651Skris if (reg >= sc->sc_pci_len) { 29168651Skris DPRINTF(("giopci_conf_write: reg 0x%x out of bounds " 29268651Skris "(val = 0x%08x)\n", reg, data)); 29368651Skris return; 29468651Skris } 29568651Skris 29668651Skris DPRINTF(("giopci_conf_write: reg 0x%x = 0x%08x\n", reg, data)); 29768651Skris bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, data); 29868651Skris} 29968651Skris 30068651Skrisstatic int 30168651Skrisgiopci_conf_hook(pci_chipset_tag_t pc, int bus, int device, int function, 30268651Skris pcireg_t id) 30368651Skris{ 30468651Skris 30568651Skris /* All devices use memory accesses only. */ 30668651Skris return (PCI_CONF_MAP_MEM | PCI_CONF_ENABLE_MEM | PCI_CONF_ENABLE_BM); 30768651Skris} 30868651Skris 30968651Skrisstatic int 31068651Skrisgiopci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 31168651Skris{ 31268651Skris struct giopci_softc *sc = pa->pa_pc->cookie; 31368651Skris 31468651Skris *ihp = sc->sc_slot; 31568651Skris 31668651Skris return (0); 31768651Skris} 31868651Skris 31968651Skrisstatic const char * 32068651Skrisgiopci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih, char * buf, 32168651Skris size_t len) 32268651Skris{ 32368651Skris snprintf(buf, len, "slot %s", (ih == GIO_SLOT_EXP0) ? "EXP0" : 32468651Skris (ih == GIO_SLOT_EXP1) ? "EXP1" : "GFX"); 32568651Skris return buf; 32668651Skris} 32768651Skris 32868651Skrisstatic void * 32968651Skrisgiopci_intr_establish(int slot, int level, int (*func)(void *), void *arg) 33068651Skris{ 33168651Skris 33268651Skris return (gio_intr_establish(slot, level, func, arg)); 33368651Skris} 33468651Skris 33568651Skrisstatic void 33668651Skrisgiopci_intr_disestablish(void *cookie) 33768651Skris{ 33868651Skris 33968651Skris panic("giopci_intr_disestablish: impossible."); 34068651Skris} 34168651Skris 34268651Skris#define CHIP pcimem 34359191Skris#define CHIP_MEM /* defined */ 34459191Skris#define CHIP_WRONG_ENDIAN 34559191Skris 34659191Skris#define CHIP_W1_BUS_START(v) 0x00000000UL 34759191Skris#define CHIP_W1_BUS_END(v) 0xffffffffUL 34859191Skris#define CHIP_W1_SYS_START(v) 0x00000000UL 34959191Skris#define CHIP_W1_SYS_END(v) 0xffffffffUL 35059191Skris 35159191Skris#include <mips/mips/bus_space_alignstride_chipdep.c> 35259191Skris