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