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