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