1 1.25 chs /* $NetBSD: igsfb_pci.c,v 1.25 2019/11/10 21:16:36 chs Exp $ */ 2 1.1 uwe 3 1.1 uwe /* 4 1.7 uwe * Copyright (c) 2002, 2003 Valeriy E. Ushakov 5 1.1 uwe * All rights reserved. 6 1.1 uwe * 7 1.1 uwe * Redistribution and use in source and binary forms, with or without 8 1.1 uwe * modification, are permitted provided that the following conditions 9 1.1 uwe * are met: 10 1.1 uwe * 1. Redistributions of source code must retain the above copyright 11 1.1 uwe * notice, this list of conditions and the following disclaimer. 12 1.1 uwe * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 uwe * notice, this list of conditions and the following disclaimer in the 14 1.1 uwe * documentation and/or other materials provided with the distribution. 15 1.1 uwe * 3. The name of the author may not be used to endorse or promote products 16 1.1 uwe * derived from this software without specific prior written permission 17 1.1 uwe * 18 1.1 uwe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 uwe * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 uwe * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 uwe * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 uwe * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 uwe * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 uwe * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 uwe * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 uwe * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 uwe * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 uwe */ 29 1.1 uwe 30 1.1 uwe /* 31 1.3 uwe * Integraphics Systems IGA 168x and CyberPro series. 32 1.1 uwe */ 33 1.1 uwe #include <sys/cdefs.h> 34 1.25 chs __KERNEL_RCSID(0, "$NetBSD: igsfb_pci.c,v 1.25 2019/11/10 21:16:36 chs Exp $"); 35 1.1 uwe 36 1.1 uwe #include <sys/param.h> 37 1.1 uwe #include <sys/systm.h> 38 1.1 uwe #include <sys/kernel.h> 39 1.1 uwe #include <sys/device.h> 40 1.1 uwe #include <sys/malloc.h> 41 1.1 uwe #include <sys/buf.h> 42 1.1 uwe 43 1.4 uwe #ifdef __sparc__ /* XXX: this doesn't belong here */ 44 1.1 uwe #include <machine/autoconf.h> 45 1.4 uwe #endif 46 1.17 ad #include <sys/bus.h> 47 1.17 ad #include <sys/intr.h> 48 1.1 uwe 49 1.1 uwe #include <dev/pci/pcivar.h> 50 1.1 uwe #include <dev/pci/pcireg.h> 51 1.1 uwe #include <dev/pci/pcidevs.h> 52 1.1 uwe 53 1.7 uwe #include <dev/wscons/wsdisplayvar.h> 54 1.1 uwe #include <dev/wscons/wsconsio.h> 55 1.7 uwe #include <dev/rasops/rasops.h> 56 1.10 macallan #include <dev/wscons/wsdisplay_vconsvar.h> 57 1.7 uwe 58 1.1 uwe #include <dev/ic/igsfbreg.h> 59 1.1 uwe #include <dev/ic/igsfbvar.h> 60 1.7 uwe #include <dev/pci/igsfb_pcivar.h> 61 1.7 uwe 62 1.7 uwe 63 1.7 uwe static int igsfb_pci_match_by_id(pcireg_t); 64 1.7 uwe static int igsfb_pci_map_regs(struct igsfb_devconfig *, 65 1.7 uwe bus_space_tag_t, bus_space_tag_t, 66 1.7 uwe pci_chipset_tag_t, 67 1.7 uwe pcitag_t, pci_product_id_t); 68 1.7 uwe static int igsfb_pci_is_console(pci_chipset_tag_t, pcitag_t); 69 1.7 uwe 70 1.7 uwe static int igsfb_pci_console = 0; 71 1.7 uwe static pcitag_t igsfb_pci_constag; 72 1.7 uwe 73 1.1 uwe 74 1.1 uwe 75 1.19 cegger static int igsfb_pci_match(device_t, cfdata_t, void *); 76 1.19 cegger static void igsfb_pci_attach(device_t, device_t, void *); 77 1.1 uwe 78 1.22 martin CFATTACH_DECL_NEW(igsfb_pci, sizeof(struct igsfb_softc), 79 1.6 thorpej igsfb_pci_match, igsfb_pci_attach, NULL, NULL); 80 1.1 uwe 81 1.7 uwe 82 1.1 uwe static int 83 1.12 uwe igsfb_pci_match_by_id(pcireg_t id) 84 1.1 uwe { 85 1.1 uwe 86 1.7 uwe if (PCI_VENDOR(id) != PCI_VENDOR_INTEGRAPHICS) 87 1.13 uwe return 0; 88 1.7 uwe 89 1.7 uwe switch (PCI_PRODUCT(id)) { 90 1.7 uwe case PCI_PRODUCT_INTEGRAPHICS_IGA1682: /* FALLTHROUGH */ 91 1.7 uwe case PCI_PRODUCT_INTEGRAPHICS_CYBERPRO2000: /* FALLTHROUGH */ 92 1.7 uwe case PCI_PRODUCT_INTEGRAPHICS_CYBERPRO2010: 93 1.13 uwe return 1; 94 1.7 uwe default: 95 1.13 uwe return 0; 96 1.7 uwe } 97 1.7 uwe } 98 1.1 uwe 99 1.7 uwe 100 1.7 uwe int 101 1.12 uwe igsfb_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, 102 1.12 uwe pci_chipset_tag_t pc, 103 1.12 uwe int bus, int device, int function) 104 1.7 uwe { 105 1.7 uwe struct igsfb_devconfig *dc; 106 1.7 uwe pcitag_t tag; 107 1.7 uwe pcireg_t id; 108 1.7 uwe int ret; 109 1.7 uwe 110 1.7 uwe tag = pci_make_tag(pc, bus, device, function); 111 1.7 uwe id = pci_conf_read(pc, tag, PCI_ID_REG); 112 1.7 uwe 113 1.7 uwe if (igsfb_pci_match_by_id(id) == 0) 114 1.13 uwe return 1; 115 1.1 uwe 116 1.7 uwe dc = &igsfb_console_dc; 117 1.7 uwe if (igsfb_pci_map_regs(dc, iot, memt, pc, tag, PCI_PRODUCT(id)) != 0) 118 1.13 uwe return 1; 119 1.4 uwe 120 1.7 uwe ret = igsfb_enable(dc->dc_iot, dc->dc_iobase, dc->dc_ioflags); 121 1.7 uwe if (ret) 122 1.13 uwe return ret; 123 1.7 uwe 124 1.7 uwe ret = igsfb_cnattach_subr(dc); 125 1.7 uwe if (ret) 126 1.13 uwe return ret; 127 1.7 uwe 128 1.7 uwe igsfb_pci_console = 1; 129 1.7 uwe igsfb_pci_constag = tag; 130 1.7 uwe 131 1.13 uwe return 0; 132 1.1 uwe } 133 1.1 uwe 134 1.1 uwe 135 1.7 uwe static int 136 1.12 uwe igsfb_pci_is_console(pci_chipset_tag_t pc, pcitag_t tag) 137 1.7 uwe { 138 1.7 uwe 139 1.16 cube return igsfb_pci_console && 140 1.16 cube !memcmp(&tag, &igsfb_pci_constag, sizeof tag); 141 1.7 uwe } 142 1.7 uwe 143 1.7 uwe 144 1.7 uwe static int 145 1.19 cegger igsfb_pci_match(device_t parent, cfdata_t match, void *aux) 146 1.7 uwe { 147 1.7 uwe struct pci_attach_args *pa = aux; 148 1.7 uwe 149 1.13 uwe return igsfb_pci_match_by_id(pa->pa_id); 150 1.7 uwe } 151 1.7 uwe 152 1.7 uwe 153 1.1 uwe static void 154 1.19 cegger igsfb_pci_attach(device_t parent, device_t self, void *aux) 155 1.1 uwe { 156 1.20 cegger struct igsfb_softc *sc = device_private(self); 157 1.1 uwe struct pci_attach_args *pa = aux; 158 1.1 uwe int isconsole; 159 1.11 uwe 160 1.21 mrg sc->sc_dev = self; 161 1.21 mrg 162 1.23 drochner pci_aprint_devinfo(pa, NULL); 163 1.11 uwe 164 1.7 uwe #if defined(__sparc__) && !defined(KRUPS_FORCE_SERIAL_CONSOLE) 165 1.7 uwe /* XXX: this doesn't belong here */ 166 1.7 uwe if (PCITAG_NODE(pa->pa_tag) == prom_instance_to_package(prom_stdout())) 167 1.7 uwe { 168 1.7 uwe int b, d, f; 169 1.7 uwe 170 1.7 uwe pci_decompose_tag(pa->pa_pc, pa->pa_tag, &b, &d, &f); 171 1.7 uwe igsfb_pci_cnattach(pa->pa_iot, pa->pa_memt, pa->pa_pc, b,d,f); 172 1.7 uwe } 173 1.7 uwe #endif 174 1.7 uwe 175 1.7 uwe isconsole = 0; 176 1.7 uwe if (igsfb_pci_is_console(pa->pa_pc, pa->pa_tag)) { 177 1.7 uwe sc->sc_dc = &igsfb_console_dc; 178 1.7 uwe isconsole = 1; 179 1.7 uwe } else { 180 1.7 uwe sc->sc_dc = malloc(sizeof(struct igsfb_devconfig), 181 1.25 chs M_DEVBUF, M_WAITOK | M_ZERO); 182 1.7 uwe if (igsfb_pci_map_regs(sc->sc_dc, 183 1.7 uwe pa->pa_iot, pa->pa_memt, pa->pa_pc, 184 1.7 uwe pa->pa_tag, PCI_PRODUCT(pa->pa_id)) != 0) 185 1.7 uwe { 186 1.24 msaitoh aprint_error("unable to map device registers\n"); 187 1.7 uwe free(sc->sc_dc, M_DEVBUF); 188 1.7 uwe sc->sc_dc = NULL; 189 1.7 uwe return; 190 1.7 uwe } 191 1.7 uwe 192 1.7 uwe igsfb_enable(sc->sc_dc->dc_iot, sc->sc_dc->dc_iobase, 193 1.7 uwe sc->sc_dc->dc_ioflags); 194 1.7 uwe } 195 1.7 uwe 196 1.7 uwe igsfb_attach_subr(sc, isconsole); 197 1.7 uwe } 198 1.7 uwe 199 1.7 uwe 200 1.7 uwe /* 201 1.7 uwe * Init memory and i/o bus space tags. Map device registers. 202 1.7 uwe * Use memory space mapped i/o space access for i/o registers 203 1.7 uwe * for CyberPro cards. 204 1.7 uwe */ 205 1.7 uwe static int 206 1.12 uwe igsfb_pci_map_regs(struct igsfb_devconfig *dc, 207 1.12 uwe bus_space_tag_t iot, bus_space_tag_t memt, 208 1.12 uwe pci_chipset_tag_t pc, pcitag_t tag, 209 1.12 uwe pci_product_id_t id) 210 1.7 uwe { 211 1.7 uwe 212 1.7 uwe dc->dc_id = id; 213 1.1 uwe 214 1.1 uwe /* 215 1.3 uwe * Configure memory space first since for CyberPro we use 216 1.3 uwe * memory-mapped i/o access. Note that we are NOT mapping any 217 1.4 uwe * of it yet. (XXX: search for memory BAR?) 218 1.1 uwe */ 219 1.1 uwe #define IGS_MEM_MAPREG (PCI_MAPREG_START + 0) 220 1.1 uwe 221 1.7 uwe dc->dc_memt = memt; 222 1.7 uwe if (pci_mapreg_info(pc, tag, 223 1.1 uwe IGS_MEM_MAPREG, PCI_MAPREG_TYPE_MEM, 224 1.7 uwe &dc->dc_memaddr, &dc->dc_memsz, &dc->dc_memflags) != 0) 225 1.1 uwe { 226 1.1 uwe printf("unable to configure memory space\n"); 227 1.13 uwe return 1; 228 1.1 uwe } 229 1.1 uwe 230 1.1 uwe /* 231 1.7 uwe * Configure I/O space. On CyberPro use MMIO. IGS 168x doesn't 232 1.7 uwe * have a BAR for its i/o space, so we have to hardcode it. 233 1.1 uwe */ 234 1.7 uwe if (id >= PCI_PRODUCT_INTEGRAPHICS_CYBERPRO2000) { 235 1.7 uwe dc->dc_iot = dc->dc_memt; 236 1.7 uwe dc->dc_iobase = dc->dc_memaddr | IGS_MEM_MMIO_SELECT; 237 1.7 uwe dc->dc_ioflags = dc->dc_memflags; 238 1.1 uwe } else { 239 1.7 uwe dc->dc_iot = iot; 240 1.7 uwe dc->dc_iobase = 0; 241 1.7 uwe dc->dc_ioflags = 0; 242 1.1 uwe } 243 1.1 uwe 244 1.3 uwe /* 245 1.3 uwe * Map I/O registers. This is done in bus glue, not in common 246 1.3 uwe * code because on e.g. ISA bus we'd need to access registers 247 1.3 uwe * to obtain/program linear memory location. 248 1.3 uwe */ 249 1.7 uwe if (bus_space_map(dc->dc_iot, 250 1.7 uwe dc->dc_iobase + IGS_REG_BASE, IGS_REG_SIZE, 251 1.7 uwe dc->dc_ioflags, 252 1.7 uwe &dc->dc_ioh) != 0) 253 1.1 uwe { 254 1.3 uwe printf("unable to map I/O registers\n"); 255 1.13 uwe return 1; 256 1.1 uwe } 257 1.1 uwe 258 1.13 uwe return 0; 259 1.1 uwe } 260