1 /* $OpenBSD: agp_ali.c,v 1.10 2009/05/10 16:57:44 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/proc.h> 38 #include <sys/conf.h> 39 #include <sys/device.h> 40 #include <sys/lock.h> 41 #include <sys/agpio.h> 42 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcireg.h> 45 #include <dev/pci/pcidevs.h> 46 #include <dev/pci/vga_pcivar.h> 47 #include <dev/pci/agpvar.h> 48 #include <dev/pci/agpreg.h> 49 50 #include <machine/bus.h> 51 52 struct agp_ali_softc { 53 struct device dev; 54 struct agp_softc *agpdev; 55 struct agp_gatt *gatt; 56 pci_chipset_tag_t asc_pc; 57 pcitag_t asc_tag; 58 bus_addr_t asc_apaddr; 59 bus_size_t asc_apsize; 60 }; 61 62 void agp_ali_attach(struct device *, struct device *, void *); 63 int agp_ali_probe(struct device *, void *, void *); 64 bus_size_t agp_ali_get_aperture(void *); 65 int agp_ali_set_aperture(void *sc, bus_size_t); 66 void agp_ali_bind_page(void *, bus_addr_t, paddr_t, int); 67 void agp_ali_unbind_page(void *, bus_addr_t); 68 void agp_ali_flush_tlb(void *); 69 70 struct cfattach aliagp_ca = { 71 sizeof(struct agp_ali_softc), agp_ali_probe, agp_ali_attach 72 }; 73 74 struct cfdriver aliagp_cd = { 75 NULL, "aliagp", DV_DULL 76 }; 77 78 const struct agp_methods agp_ali_methods = { 79 agp_ali_bind_page, 80 agp_ali_unbind_page, 81 agp_ali_flush_tlb, 82 }; 83 84 int 85 agp_ali_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_ALI && 92 PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_ALI_M1689) 93 return (1); 94 return (0); 95 } 96 97 void 98 agp_ali_attach(struct device *parent, struct device *self, void *aux) 99 { 100 struct agp_ali_softc *asc = (struct agp_ali_softc *)self; 101 struct agp_gatt *gatt; 102 struct agp_attach_args *aa = aux; 103 struct pci_attach_args *pa = aa->aa_pa; 104 pcireg_t reg; 105 106 asc->asc_tag = pa->pa_tag; 107 asc->asc_pc = pa->pa_pc; 108 asc->asc_apsize = agp_ali_get_aperture(asc); 109 110 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE, 111 PCI_MAPREG_TYPE_MEM, &asc->asc_apaddr, NULL, NULL) != 0) { 112 printf(": can't get aperture info\n"); 113 return; 114 } 115 116 for (;;) { 117 gatt = agp_alloc_gatt(pa->pa_dmat, asc->asc_apsize); 118 if (gatt != NULL) 119 break; 120 /* 121 * almost certainly error allocating contigious dma memory 122 * so reduce aperture so that the gatt size reduces. 123 */ 124 asc->asc_apsize /= 2; 125 if (agp_ali_set_aperture(asc, asc->asc_apsize)) { 126 printf("failed to set aperture\n"); 127 return; 128 } 129 } 130 asc->gatt = gatt; 131 132 /* Install the gatt. */ 133 reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE); 134 reg = (reg & 0xff) | gatt->ag_physical; 135 pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE, reg); 136 137 /* Enable the TLB. */ 138 reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL); 139 reg = (reg & ~0xff) | 0x10; 140 pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg); 141 142 asc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_ali_methods, 143 asc->asc_apaddr, asc->asc_apsize, &asc->dev); 144 return; 145 } 146 147 #if 0 148 int 149 agp_ali_detach(struct agp_softc *sc) 150 { 151 int error; 152 pcireg_t reg; 153 struct agp_ali_softc *asc = sc->sc_chipc; 154 155 error = agp_generic_detach(sc); 156 if (error) 157 return (error); 158 159 /* Disable the TLB.. */ 160 reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL); 161 reg &= ~0xff; 162 reg |= 0x90; 163 pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL, reg); 164 165 /* Put the aperture back the way it started. */ 166 AGP_SET_APERTURE(sc, asc->initial_aperture); 167 reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE); 168 reg &= 0xff; 169 pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE, reg); 170 171 agp_free_gatt(sc, asc->gatt); 172 return (0); 173 } 174 #endif 175 176 #define M 1024*1024 177 178 static const u_int32_t agp_ali_table[] = { 179 0, /* 0 - invalid */ 180 1, /* 1 - invalid */ 181 2, /* 2 - invalid */ 182 4*M, /* 3 - invalid */ 183 8*M, /* 4 - invalid */ 184 0, /* 5 - invalid */ 185 16*M, /* 6 - invalid */ 186 32*M, /* 7 - invalid */ 187 64*M, /* 8 - invalid */ 188 128*M, /* 9 - invalid */ 189 256*M, /* 10 - invalid */ 190 }; 191 #define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0])) 192 193 bus_size_t 194 agp_ali_get_aperture(void *sc) 195 { 196 struct agp_ali_softc *asc = sc; 197 int i; 198 199 /* 200 * The aperture size is derived from the low bits of attbase. 201 * I'm not sure this is correct.. 202 */ 203 i = (int)pci_conf_read(asc->asc_pc, asc->asc_tag, 204 AGP_ALI_ATTBASE) & 0xff; 205 if (i >= agp_ali_table_size) 206 return (0); 207 return (agp_ali_table[i]); 208 } 209 210 int 211 agp_ali_set_aperture(void *sc, bus_size_t aperture) 212 { 213 struct agp_ali_softc *asc = sc; 214 int i; 215 pcireg_t reg; 216 217 for (i = 0; i < agp_ali_table_size; i++) 218 if (agp_ali_table[i] == aperture) 219 break; 220 if (i == agp_ali_table_size) 221 return (EINVAL); 222 223 reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE); 224 reg &= ~0xff; 225 reg |= i; 226 pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE, reg); 227 return (0); 228 } 229 230 void 231 agp_ali_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags) 232 { 233 struct agp_ali_softc *asc = sc; 234 235 asc->gatt->ag_virtual[(offset - asc->asc_apaddr) >> AGP_PAGE_SHIFT] = 236 physical; 237 } 238 239 void 240 agp_ali_unbind_page(void *sc, bus_size_t offset) 241 { 242 struct agp_ali_softc *asc = sc; 243 244 asc->gatt->ag_virtual[(offset - asc->asc_apaddr) >> AGP_PAGE_SHIFT] = 0; 245 } 246 247 void 248 agp_ali_flush_tlb(void *sc) 249 { 250 struct agp_ali_softc *asc = sc; 251 pcireg_t reg; 252 253 reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL); 254 reg &= ~0xff; 255 reg |= 0x90; 256 pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg); 257 reg &= ~0xff; 258 reg |= 0x10; 259 pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg); 260 } 261 262