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