1 /* $OpenBSD: agp_sis.c,v 1.15 2010/08/07 18:09:09 oga Exp $ */ 2 /* $NetBSD: agp_sis.c,v 1.2 2001/09/15 00:25:00 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 2000 Doug Rabson 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: src/sys/pci/agp_sis.c,v 1.3 2001/07/05 21:28:47 jhb Exp $ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/malloc.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/conf.h> 38 #include <sys/device.h> 39 #include <sys/agpio.h> 40 41 #include <dev/pci/pcivar.h> 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcidevs.h> 44 #include <dev/pci/vga_pcivar.h> 45 #include <dev/pci/agpvar.h> 46 #include <dev/pci/agpreg.h> 47 48 #include <machine/bus.h> 49 50 struct agp_sis_softc { 51 struct device dev; 52 struct agp_softc *agpdev; 53 struct agp_gatt *gatt; 54 pci_chipset_tag_t ssc_pc; 55 pcitag_t ssc_tag; 56 bus_addr_t ssc_apaddr; 57 bus_size_t ssc_apsize; 58 pcireg_t ssc_winctrl; /* saved over suspend/resume */ 59 }; 60 61 void agp_sis_attach(struct device *, struct device *, void *); 62 int agp_sis_activate(struct device *, int); 63 void agp_sis_save(struct agp_sis_softc *); 64 void agp_sis_restore(struct agp_sis_softc *); 65 int agp_sis_probe(struct device *, void *, void *); 66 bus_size_t agp_sis_get_aperture(void *); 67 int agp_sis_set_aperture(void *, bus_size_t); 68 void agp_sis_bind_page(void *, bus_addr_t, paddr_t, int); 69 void agp_sis_unbind_page(void *, bus_addr_t); 70 void agp_sis_flush_tlb(void *); 71 72 struct cfattach sisagp_ca = { 73 sizeof(struct agp_sis_softc), agp_sis_probe, agp_sis_attach, 74 NULL, agp_sis_activate 75 }; 76 77 struct cfdriver sisagp_cd = { 78 NULL, "sisagp", DV_DULL 79 }; 80 81 const struct agp_methods agp_sis_methods = { 82 agp_sis_bind_page, 83 agp_sis_unbind_page, 84 agp_sis_flush_tlb, 85 }; 86 87 int 88 agp_sis_probe(struct device *parent, void *match, void *aux) 89 { 90 struct agp_attach_args *aa = aux; 91 struct pci_attach_args *pa = aa->aa_pa; 92 93 /* Must be a pchb, don't attach to iommu-style agp devs */ 94 if (agpbus_probe(aa) == 1 && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS && 95 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_SIS_755 && 96 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_SIS_760) 97 return (1); 98 return (0); 99 } 100 101 102 void 103 agp_sis_attach(struct device *parent, struct device *self, void *aux) 104 { 105 struct agp_sis_softc *ssc = (struct agp_sis_softc *)self; 106 struct agp_attach_args *aa = aux; 107 struct pci_attach_args *pa = aa->aa_pa; 108 struct agp_gatt *gatt; 109 pcireg_t reg; 110 111 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE, 112 PCI_MAPREG_TYPE_MEM, &ssc->ssc_apaddr, NULL, NULL) != 0) { 113 printf(": can't get aperture info\n"); 114 return; 115 } 116 117 ssc->ssc_pc = pa->pa_pc; 118 ssc->ssc_tag = pa->pa_tag; 119 ssc->ssc_apsize = agp_sis_get_aperture(ssc); 120 121 for (;;) { 122 gatt = agp_alloc_gatt(pa->pa_dmat, ssc->ssc_apsize); 123 if (gatt != NULL) 124 break; 125 126 /* 127 * Probably failed to alloc congigious memory. Try reducing the 128 * aperture so that the gatt size reduces. 129 */ 130 ssc->ssc_apsize /= 2; 131 if (agp_sis_set_aperture(ssc, ssc->ssc_apsize)) { 132 printf("can't set aperture size\n"); 133 return; 134 } 135 } 136 ssc->gatt = gatt; 137 138 /* Install the gatt. */ 139 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_ATTBASE, 140 gatt->ag_physical); 141 142 /* Enable the aperture and auto-tlb-inval */ 143 reg = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL); 144 reg |= (0x05 << 24) | 3; 145 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL, reg); 146 147 ssc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_sis_methods, 148 ssc->ssc_apaddr, ssc->ssc_apsize, &ssc->dev); 149 return; 150 } 151 152 #if 0 153 int 154 agp_sis_detach(struct agp_softc *sc) 155 { 156 struct agp_sis_softc *ssc = sc->sc_chipc; 157 pcireg_t reg; 158 int error; 159 160 error = agp_generic_detach(sc); 161 if (error) 162 return (error); 163 164 reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL); 165 reg &= ~3; 166 reg &= 0x00ffffff; 167 pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL, reg); 168 169 /* Put the aperture back the way it started. */ 170 AGP_SET_APERTURE(sc, ssc->initial_aperture); 171 172 agp_free_gatt(sc, ssc->gatt); 173 return (0); 174 } 175 #endif 176 177 int 178 agp_sis_activate(struct device *arg, int act) 179 { 180 struct agp_sis_softc *ssc = (struct agp_sis_softc *)arg; 181 182 switch (act) { 183 case DVACT_SUSPEND: 184 agp_sis_save(ssc); 185 break; 186 case DVACT_RESUME: 187 agp_sis_restore(ssc); 188 break; 189 } 190 191 return (0); 192 } 193 194 void 195 agp_sis_save(struct agp_sis_softc *ssc) 196 { 197 ssc->ssc_winctrl = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, 198 AGP_SIS_WINCTRL); 199 } 200 201 void 202 agp_sis_restore(struct agp_sis_softc *ssc) 203 { 204 /* Install the gatt. */ 205 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_ATTBASE, 206 ssc->gatt->ag_physical); 207 208 /* 209 * Enable the aperture, reset the aperture size and enable and 210 * auto-tlb-inval. 211 */ 212 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL, 213 ssc->ssc_winctrl); 214 } 215 216 bus_size_t 217 agp_sis_get_aperture(void *sc) 218 { 219 struct agp_sis_softc *ssc = sc; 220 int gws; 221 222 /* 223 * The aperture size is equal to 4M<<gws. 224 */ 225 gws = (pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, 226 AGP_SIS_WINCTRL)&0x70) >> 4; 227 return ((4 * 1024 * 1024) << gws); 228 } 229 230 int 231 agp_sis_set_aperture(void *sc, bus_size_t aperture) 232 { 233 struct agp_sis_softc *ssc = sc; 234 int gws; 235 pcireg_t reg; 236 237 /* 238 * Check for a power of two and make sure its within the 239 * programmable range. 240 */ 241 if (aperture & (aperture - 1) 242 || aperture < 4*1024*1024 243 || aperture > 256*1024*1024) 244 return (EINVAL); 245 246 gws = ffs(aperture / 4*1024*1024) - 1; 247 248 reg = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL); 249 reg &= ~0x00000070; 250 reg |= gws << 4; 251 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL, reg); 252 253 return (0); 254 } 255 256 void 257 agp_sis_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags) 258 { 259 struct agp_sis_softc *ssc = sc; 260 261 ssc->gatt->ag_virtual[(offset - ssc->ssc_apaddr) >> AGP_PAGE_SHIFT] = 262 physical; 263 } 264 265 void 266 agp_sis_unbind_page(void *sc, bus_addr_t offset) 267 { 268 struct agp_sis_softc *ssc = sc; 269 270 ssc->gatt->ag_virtual[(offset - ssc->ssc_apaddr) >> AGP_PAGE_SHIFT] = 0; 271 } 272 273 void 274 agp_sis_flush_tlb(void *sc) 275 { 276 struct agp_sis_softc *ssc = sc; 277 pcireg_t reg; 278 279 reg = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_TLBFLUSH); 280 reg &= 0xffffff00; 281 reg |= 0x02; 282 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_TLBFLUSH, reg); 283 } 284