1 /* $OpenBSD: agp_sis.c,v 1.18 2014/05/27 12:40:00 kettenis 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/device.h> 36 #include <sys/rwlock.h> 37 38 #include <dev/pci/pcivar.h> 39 #include <dev/pci/pcireg.h> 40 #include <dev/pci/pcidevs.h> 41 #include <dev/pci/vga_pcivar.h> 42 #include <dev/pci/agpvar.h> 43 #include <dev/pci/agpreg.h> 44 45 #include <machine/bus.h> 46 47 struct agp_sis_softc { 48 struct device dev; 49 struct agp_softc *agpdev; 50 struct agp_gatt *gatt; 51 pci_chipset_tag_t ssc_pc; 52 pcitag_t ssc_tag; 53 bus_addr_t ssc_apaddr; 54 bus_size_t ssc_apsize; 55 pcireg_t ssc_winctrl; /* saved over suspend/resume */ 56 }; 57 58 void agp_sis_attach(struct device *, struct device *, void *); 59 int agp_sis_activate(struct device *, int); 60 void agp_sis_save(struct agp_sis_softc *); 61 void agp_sis_restore(struct agp_sis_softc *); 62 int agp_sis_probe(struct device *, void *, void *); 63 bus_size_t agp_sis_get_aperture(void *); 64 int agp_sis_set_aperture(void *, bus_size_t); 65 void agp_sis_bind_page(void *, bus_addr_t, paddr_t, int); 66 void agp_sis_unbind_page(void *, bus_addr_t); 67 void agp_sis_flush_tlb(void *); 68 69 struct cfattach sisagp_ca = { 70 sizeof(struct agp_sis_softc), agp_sis_probe, agp_sis_attach, 71 NULL, agp_sis_activate 72 }; 73 74 struct cfdriver sisagp_cd = { 75 NULL, "sisagp", DV_DULL 76 }; 77 78 const struct agp_methods agp_sis_methods = { 79 agp_sis_bind_page, 80 agp_sis_unbind_page, 81 agp_sis_flush_tlb, 82 }; 83 84 int 85 agp_sis_probe(struct device *parent, void *match, void *aux) 86 { 87 struct agp_attach_args *aa = aux; 88 struct pci_attach_args *pa = aa->aa_pa; 89 90 /* Must be a pchb, don't attach to iommu-style agp devs */ 91 if (agpbus_probe(aa) == 1 && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS && 92 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_SIS_755 && 93 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_SIS_760) 94 return (1); 95 return (0); 96 } 97 98 99 void 100 agp_sis_attach(struct device *parent, struct device *self, void *aux) 101 { 102 struct agp_sis_softc *ssc = (struct agp_sis_softc *)self; 103 struct agp_attach_args *aa = aux; 104 struct pci_attach_args *pa = aa->aa_pa; 105 struct agp_gatt *gatt; 106 pcireg_t reg; 107 108 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE, 109 PCI_MAPREG_TYPE_MEM, &ssc->ssc_apaddr, NULL, NULL) != 0) { 110 printf(": can't get aperture info\n"); 111 return; 112 } 113 114 ssc->ssc_pc = pa->pa_pc; 115 ssc->ssc_tag = pa->pa_tag; 116 ssc->ssc_apsize = agp_sis_get_aperture(ssc); 117 118 for (;;) { 119 gatt = agp_alloc_gatt(pa->pa_dmat, ssc->ssc_apsize); 120 if (gatt != NULL) 121 break; 122 123 /* 124 * Probably failed to alloc congigious memory. Try reducing the 125 * aperture so that the gatt size reduces. 126 */ 127 ssc->ssc_apsize /= 2; 128 if (agp_sis_set_aperture(ssc, ssc->ssc_apsize)) { 129 printf("can't set aperture size\n"); 130 return; 131 } 132 } 133 ssc->gatt = gatt; 134 135 /* Install the gatt. */ 136 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_ATTBASE, 137 gatt->ag_physical); 138 139 /* Enable the aperture and auto-tlb-inval */ 140 reg = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL); 141 reg |= (0x05 << 24) | 3; 142 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL, reg); 143 144 ssc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_sis_methods, 145 ssc->ssc_apaddr, ssc->ssc_apsize, &ssc->dev); 146 return; 147 } 148 149 int 150 agp_sis_activate(struct device *arg, int act) 151 { 152 struct agp_sis_softc *ssc = (struct agp_sis_softc *)arg; 153 154 switch (act) { 155 case DVACT_SUSPEND: 156 agp_sis_save(ssc); 157 break; 158 case DVACT_RESUME: 159 agp_sis_restore(ssc); 160 break; 161 } 162 163 return (0); 164 } 165 166 void 167 agp_sis_save(struct agp_sis_softc *ssc) 168 { 169 ssc->ssc_winctrl = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, 170 AGP_SIS_WINCTRL); 171 } 172 173 void 174 agp_sis_restore(struct agp_sis_softc *ssc) 175 { 176 /* Install the gatt. */ 177 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_ATTBASE, 178 ssc->gatt->ag_physical); 179 180 /* 181 * Enable the aperture, reset the aperture size and enable and 182 * auto-tlb-inval. 183 */ 184 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL, 185 ssc->ssc_winctrl); 186 } 187 188 bus_size_t 189 agp_sis_get_aperture(void *sc) 190 { 191 struct agp_sis_softc *ssc = sc; 192 int gws; 193 194 /* 195 * The aperture size is equal to 4M<<gws. 196 */ 197 gws = (pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, 198 AGP_SIS_WINCTRL)&0x70) >> 4; 199 return ((4 * 1024 * 1024) << gws); 200 } 201 202 int 203 agp_sis_set_aperture(void *sc, bus_size_t aperture) 204 { 205 struct agp_sis_softc *ssc = sc; 206 int gws; 207 pcireg_t reg; 208 209 /* 210 * Check for a power of two and make sure its within the 211 * programmable range. 212 */ 213 if (aperture & (aperture - 1) 214 || aperture < 4*1024*1024 215 || aperture > 256*1024*1024) 216 return (EINVAL); 217 218 gws = ffs(aperture / 4*1024*1024) - 1; 219 220 reg = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL); 221 reg &= ~0x00000070; 222 reg |= gws << 4; 223 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_WINCTRL, reg); 224 225 return (0); 226 } 227 228 void 229 agp_sis_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags) 230 { 231 struct agp_sis_softc *ssc = sc; 232 233 ssc->gatt->ag_virtual[(offset - ssc->ssc_apaddr) >> AGP_PAGE_SHIFT] = 234 physical; 235 } 236 237 void 238 agp_sis_unbind_page(void *sc, bus_addr_t offset) 239 { 240 struct agp_sis_softc *ssc = sc; 241 242 ssc->gatt->ag_virtual[(offset - ssc->ssc_apaddr) >> AGP_PAGE_SHIFT] = 0; 243 } 244 245 void 246 agp_sis_flush_tlb(void *sc) 247 { 248 struct agp_sis_softc *ssc = sc; 249 pcireg_t reg; 250 251 reg = pci_conf_read(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_TLBFLUSH); 252 reg &= 0xffffff00; 253 reg |= 0x02; 254 pci_conf_write(ssc->ssc_pc, ssc->ssc_tag, AGP_SIS_TLBFLUSH, reg); 255 } 256