1 /* $NetBSD: bandit.c,v 1.25 2005/12/11 12:18:06 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Tsubai Masanari. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: bandit.c,v 1.25 2005/12/11 12:18:06 christos Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/device.h> 34 #include <sys/systm.h> 35 36 #include <dev/pci/pcivar.h> 37 #include <dev/ofw/openfirm.h> 38 #include <dev/ofw/ofw_pci.h> 39 40 #include <machine/autoconf.h> 41 42 struct bandit_softc { 43 struct device sc_dev; 44 struct pci_bridge sc_pc; 45 }; 46 47 void bandit_attach __P((struct device *, struct device *, void *)); 48 int bandit_match __P((struct device *, struct cfdata *, void *)); 49 50 pcireg_t bandit_conf_read __P((pci_chipset_tag_t, pcitag_t, int)); 51 void bandit_conf_write __P((pci_chipset_tag_t, pcitag_t, int, pcireg_t)); 52 53 static void bandit_init __P((struct bandit_softc *)); 54 55 CFATTACH_DECL(bandit, sizeof(struct bandit_softc), 56 bandit_match, bandit_attach, NULL, NULL); 57 58 int 59 bandit_match(parent, cf, aux) 60 struct device *parent; 61 struct cfdata *cf; 62 void *aux; 63 { 64 struct confargs *ca = aux; 65 66 if (strcmp(ca->ca_name, "bandit") == 0 || 67 strcmp(ca->ca_name, "chaos") == 0) 68 return 1; 69 70 return 0; 71 } 72 73 void 74 bandit_attach(parent, self, aux) 75 struct device *parent, *self; 76 void *aux; 77 { 78 struct bandit_softc *sc = (void *)self; 79 pci_chipset_tag_t pc = &sc->sc_pc; 80 struct confargs *ca = aux; 81 struct pcibus_attach_args pba; 82 int len, node = ca->ca_node; 83 u_int32_t reg[2], busrange[2]; 84 struct ranges { 85 u_int32_t pci_hi, pci_mid, pci_lo; 86 u_int32_t host; 87 u_int32_t size_hi, size_lo; 88 } ranges[6], *rp = ranges; 89 90 printf("\n"); 91 92 /* Bandit address */ 93 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8) 94 return; 95 96 /* PCI bus number */ 97 if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8) 98 return; 99 100 pc->node = node; 101 pc->addr = mapiodev(reg[0] + 0x800000, 4); 102 pc->data = mapiodev(reg[0] + 0xc00000, 8); 103 pc->bus = busrange[0]; 104 pc->conf_read = bandit_conf_read; 105 pc->conf_write = bandit_conf_write; 106 pc->memt = (bus_space_tag_t)0; 107 108 /* find i/o tag */ 109 len = OF_getprop(node, "ranges", ranges, sizeof(ranges)); 110 if (len == -1) 111 return; 112 while (len >= sizeof(ranges[0])) { 113 if ((rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 114 OFW_PCI_PHYS_HI_SPACE_IO) 115 pc->iot = (bus_space_tag_t)rp->host; 116 len -= sizeof(ranges[0]); 117 rp++; 118 } 119 120 bandit_init(sc); 121 122 memset(&pba, 0, sizeof(pba)); 123 pba.pba_memt = pc->memt; 124 pba.pba_iot = pc->iot; 125 pba.pba_dmat = &pci_bus_dma_tag; 126 pba.pba_dmat64 = NULL; 127 pba.pba_bus = pc->bus; 128 pba.pba_bridgetag = NULL; 129 pba.pba_pc = pc; 130 pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED; 131 132 config_found_ia(self, "pcibus", &pba, pcibusprint); 133 } 134 135 pcireg_t 136 bandit_conf_read(pc, tag, reg) 137 pci_chipset_tag_t pc; 138 pcitag_t tag; 139 int reg; 140 { 141 pcireg_t data; 142 int bus, dev, func, s; 143 u_int32_t x; 144 145 pci_decompose_tag(pc, tag, &bus, &dev, &func); 146 147 /* 148 * bandit's minimum device number of the first bus is 11. 149 * So we behave as if there is no device when dev < 11. 150 */ 151 if (func > 7) 152 panic("pci_conf_read: func > 7"); 153 154 if (bus == pc->bus) { 155 if (dev < 11) 156 return 0xffffffff; 157 x = (1 << dev) | (func << 8) | reg; 158 } else 159 x = tag | reg | 1; 160 161 s = splhigh(); 162 163 out32rb(pc->addr, x); 164 DELAY(10); 165 data = 0xffffffff; 166 if (!badaddr(pc->data, 4)) 167 data = in32rb(pc->data); 168 DELAY(10); 169 out32rb(pc->addr, 0); 170 DELAY(10); 171 172 splx(s); 173 174 return data; 175 } 176 177 void 178 bandit_conf_write(pc, tag, reg, data) 179 pci_chipset_tag_t pc; 180 pcitag_t tag; 181 int reg; 182 pcireg_t data; 183 { 184 int bus, dev, func, s; 185 u_int32_t x; 186 187 pci_decompose_tag(pc, tag, &bus, &dev, &func); 188 189 if (func > 7) 190 panic("pci_conf_write: func > 7"); 191 192 if (bus == pc->bus) { 193 if (dev < 11) 194 panic("pci_conf_write: dev < 11"); 195 x = (1 << dev) | (func << 8) | reg; 196 } else 197 x = tag | reg | 1; 198 199 s = splhigh(); 200 201 out32rb(pc->addr, x); 202 DELAY(10); 203 out32rb(pc->data, data); 204 DELAY(10); 205 out32rb(pc->addr, 0); 206 DELAY(10); 207 208 splx(s); 209 } 210 211 #define PCI_BANDIT 11 212 213 #define PCI_REG_MODE_SELECT 0x50 214 215 #define PCI_MODE_IO_COHERENT 0x040 /* I/O coherent */ 216 217 void 218 bandit_init(sc) 219 struct bandit_softc *sc; 220 { 221 pci_chipset_tag_t pc = &sc->sc_pc; 222 pcitag_t tag; 223 u_int mode; 224 225 tag = pci_make_tag(pc, pc->bus, PCI_BANDIT, 0); 226 if ((pci_conf_read(pc, tag, PCI_ID_REG) & 0xffff) == 0xffff) 227 return; 228 229 mode = pci_conf_read(pc, tag, PCI_REG_MODE_SELECT); 230 231 if ((mode & PCI_MODE_IO_COHERENT) == 0) { 232 mode |= PCI_MODE_IO_COHERENT; 233 pci_conf_write(pc, tag, PCI_REG_MODE_SELECT, mode); 234 } 235 } 236