2 * Copyright (c) 2000 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/pci/agp_amd.c,v 1.3.2.4 2002/04/25 23:41:36 cokane Exp $
27 * $DragonFly: src/sys/dev/agp/agp_amd.c,v 1.8 2006/10/25 22:55:52 dillon Exp $
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/kernel.h>
41 #include <bus/pci/pcivar.h>
42 #include <bus/pci/pcireg.h>
47 #include <vm/vm_object.h>
49 #include <machine/clock.h>
51 MALLOC_DECLARE(M_AGP
);
53 #define READ2(off) bus_space_read_2(sc->bst, sc->bsh, off)
54 #define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off)
55 #define WRITE2(off,v) bus_space_write_2(sc->bst, sc->bsh, off, v)
56 #define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
60 u_int32_t
*ag_virtual
; /* virtual address of gatt */
61 vm_offset_t ag_physical
;
62 u_int32_t
*ag_vdir
; /* virtual address of page dir */
63 vm_offset_t ag_pdir
; /* physical address of page dir */
66 struct agp_amd_softc
{
68 struct resource
*regs
; /* memory mapped control registers */
69 bus_space_tag_t bst
; /* bus_space tag */
70 bus_space_handle_t bsh
; /* bus_space handle */
71 u_int32_t initial_aperture
; /* aperture size at startup */
72 struct agp_amd_gatt
*gatt
;
75 static struct agp_amd_gatt
*
76 agp_amd_alloc_gatt(device_t dev
)
78 u_int32_t apsize
= AGP_GET_APERTURE(dev
);
79 u_int32_t entries
= apsize
>> AGP_PAGE_SHIFT
;
80 struct agp_amd_gatt
*gatt
;
81 int i
, npages
, pdir_offset
;
85 "allocating GATT for aperture of size %dM\n",
86 apsize
/ (1024*1024));
88 gatt
= kmalloc(sizeof(struct agp_amd_gatt
), M_AGP
, M_INTWAIT
);
91 * The AMD751 uses a page directory to map a non-contiguous
92 * gatt so we don't need to use contigmalloc.
93 * Malloc individual gatt pages and map them into the page
96 gatt
->ag_entries
= entries
;
97 gatt
->ag_virtual
= kmalloc(entries
* sizeof(u_int32_t
),
98 M_AGP
, M_INTWAIT
| M_ZERO
);
101 * Allocate the page directory.
103 gatt
->ag_vdir
= kmalloc(AGP_PAGE_SIZE
, M_AGP
, M_INTWAIT
| M_ZERO
);
104 gatt
->ag_pdir
= vtophys((vm_offset_t
) gatt
->ag_vdir
);
106 device_printf(dev
, "gatt -> ag_pdir %8x\n",
107 (vm_offset_t
)gatt
->ag_pdir
);
109 * Allocate the gatt pages
111 gatt
->ag_entries
= entries
;
113 device_printf(dev
, "allocating GATT for %d AGP page entries\n",
115 gatt
->ag_physical
= vtophys((vm_offset_t
) gatt
->ag_virtual
);
118 * Map the pages of the GATT into the page directory.
120 * The GATT page addresses are mapped into the directory offset by
121 * an amount dependent on the base address of the aperture. This
122 * is and offset into the page directory, not an offset added to
123 * the addresses of the gatt pages.
126 pdir_offset
= pci_read_config(dev
, AGP_AMD751_APBASE
, 4) >> 22;
128 npages
= ((entries
* sizeof(u_int32_t
) + AGP_PAGE_SIZE
- 1)
131 for (i
= 0; i
< npages
; i
++) {
135 va
= ((vm_offset_t
) gatt
->ag_virtual
) + i
* AGP_PAGE_SIZE
;
137 gatt
->ag_vdir
[i
+ pdir_offset
] = pa
| 1;
141 * Make sure the chipset can see everything.
149 agp_amd_free_gatt(struct agp_amd_gatt
*gatt
)
151 kfree(gatt
->ag_virtual
, M_AGP
);
152 kfree(gatt
->ag_vdir
, M_AGP
);
157 agp_amd_match(device_t dev
)
159 if (pci_get_class(dev
) != PCIC_BRIDGE
160 || pci_get_subclass(dev
) != PCIS_BRIDGE_HOST
)
163 if (agp_find_caps(dev
) == 0)
166 switch (pci_get_devid(dev
)) {
169 return ("AMD 751 host to AGP bridge");
172 return ("AMD 761 host to AGP bridge");
175 return ("AMD 762 host to AGP bridge");
183 agp_amd_probe(device_t dev
)
187 desc
= agp_amd_match(dev
);
190 device_set_desc(dev
, desc
);
198 agp_amd_attach(device_t dev
)
200 struct agp_amd_softc
*sc
= device_get_softc(dev
);
201 struct agp_amd_gatt
*gatt
;
204 error
= agp_generic_attach(dev
);
208 rid
= AGP_AMD751_REGISTERS
;
209 sc
->regs
= bus_alloc_resource(dev
, SYS_RES_MEMORY
, &rid
,
210 0, ~0, 1, RF_ACTIVE
);
212 agp_generic_detach(dev
);
216 sc
->bst
= rman_get_bustag(sc
->regs
);
217 sc
->bsh
= rman_get_bushandle(sc
->regs
);
219 sc
->initial_aperture
= AGP_GET_APERTURE(dev
);
220 if (sc
->initial_aperture
== 0) {
221 device_printf(dev
, "bad initial aperture size, disabling\n");
226 gatt
= agp_amd_alloc_gatt(dev
);
231 * Probably contigmalloc failure. Try reducing the
232 * aperture so that the gatt size reduces.
234 if (AGP_SET_APERTURE(dev
, AGP_GET_APERTURE(dev
) / 2))
239 /* Install the gatt. */
240 WRITE4(AGP_AMD751_ATTBASE
, gatt
->ag_pdir
);
242 /* Enable synchronisation between host and agp. */
243 pci_write_config(dev
,
245 AGP_AMD751_MODECTRL_SYNEN
, 1);
247 /* Set indexing mode for two-level and enable page dir cache */
248 pci_write_config(dev
,
249 AGP_AMD751_MODECTRL2
,
250 AGP_AMD751_MODECTRL2_GPDCE
, 1);
252 /* Enable the TLB and flush */
253 WRITE2(AGP_AMD751_STATUS
,
254 READ2(AGP_AMD751_STATUS
) | AGP_AMD751_STATUS_GCE
);
261 agp_amd_detach(device_t dev
)
263 struct agp_amd_softc
*sc
= device_get_softc(dev
);
266 error
= agp_generic_detach(dev
);
270 /* Disable the TLB.. */
271 WRITE2(AGP_AMD751_STATUS
,
272 READ2(AGP_AMD751_STATUS
) & ~AGP_AMD751_STATUS_GCE
);
274 /* Disable host-agp sync */
275 pci_write_config(dev
, AGP_AMD751_MODECTRL
, 0x00, 1);
277 /* Clear the GATT base */
278 WRITE4(AGP_AMD751_ATTBASE
, 0);
280 /* Put the aperture back the way it started. */
281 AGP_SET_APERTURE(dev
, sc
->initial_aperture
);
283 agp_amd_free_gatt(sc
->gatt
);
285 bus_release_resource(dev
, SYS_RES_MEMORY
,
286 AGP_AMD751_REGISTERS
, sc
->regs
);
292 agp_amd_get_aperture(device_t dev
)
297 * The aperture size is equal to 32M<<vas.
299 vas
= (pci_read_config(dev
, AGP_AMD751_APCTRL
, 1) & 0x06) >> 1;
300 return (32*1024*1024) << vas
;
304 agp_amd_set_aperture(device_t dev
, u_int32_t aperture
)
309 * Check for a power of two and make sure its within the
310 * programmable range.
312 if (aperture
& (aperture
- 1)
313 || aperture
< 32*1024*1024
314 || aperture
> 2U*1024*1024*1024)
317 vas
= ffs(aperture
/ 32*1024*1024) - 1;
320 * While the size register is bits 1-3 of APCTRL, bit 0 must be
321 * set for the size value to be 'valid'
323 pci_write_config(dev
, AGP_AMD751_APCTRL
,
324 (((pci_read_config(dev
, AGP_AMD751_APCTRL
, 1) & ~0x06)
325 | ((vas
<< 1) | 1))), 1);
331 agp_amd_bind_page(device_t dev
, int offset
, vm_offset_t physical
)
333 struct agp_amd_softc
*sc
= device_get_softc(dev
);
335 if (offset
< 0 || offset
>= (sc
->gatt
->ag_entries
<< AGP_PAGE_SHIFT
))
338 sc
->gatt
->ag_virtual
[offset
>> AGP_PAGE_SHIFT
] = physical
| 1;
340 /* invalidate the cache */
346 agp_amd_unbind_page(device_t dev
, int offset
)
348 struct agp_amd_softc
*sc
= device_get_softc(dev
);
350 if (offset
< 0 || offset
>= (sc
->gatt
->ag_entries
<< AGP_PAGE_SHIFT
))
353 sc
->gatt
->ag_virtual
[offset
>> AGP_PAGE_SHIFT
] = 0;
358 agp_amd_flush_tlb(device_t dev
)
360 struct agp_amd_softc
*sc
= device_get_softc(dev
);
362 /* Set the cache invalidate bit and wait for the chipset to clear */
363 WRITE4(AGP_AMD751_TLBCTRL
, 1);
366 } while (READ4(AGP_AMD751_TLBCTRL
));
369 static device_method_t agp_amd_methods
[] = {
370 /* Device interface */
371 DEVMETHOD(device_probe
, agp_amd_probe
),
372 DEVMETHOD(device_attach
, agp_amd_attach
),
373 DEVMETHOD(device_detach
, agp_amd_detach
),
374 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
375 DEVMETHOD(device_suspend
, bus_generic_suspend
),
376 DEVMETHOD(device_resume
, bus_generic_resume
),
379 DEVMETHOD(agp_get_aperture
, agp_amd_get_aperture
),
380 DEVMETHOD(agp_set_aperture
, agp_amd_set_aperture
),
381 DEVMETHOD(agp_bind_page
, agp_amd_bind_page
),
382 DEVMETHOD(agp_unbind_page
, agp_amd_unbind_page
),
383 DEVMETHOD(agp_flush_tlb
, agp_amd_flush_tlb
),
384 DEVMETHOD(agp_enable
, agp_generic_enable
),
385 DEVMETHOD(agp_alloc_memory
, agp_generic_alloc_memory
),
386 DEVMETHOD(agp_free_memory
, agp_generic_free_memory
),
387 DEVMETHOD(agp_bind_memory
, agp_generic_bind_memory
),
388 DEVMETHOD(agp_unbind_memory
, agp_generic_unbind_memory
),
393 static driver_t agp_amd_driver
= {
396 sizeof(struct agp_amd_softc
),
399 static devclass_t agp_devclass
;
401 DRIVER_MODULE(agp_amd
, pci
, agp_amd_driver
, agp_devclass
, 0, 0);
402 MODULE_DEPEND(agp_amd
, agp
, 1, 1, 1);
403 MODULE_DEPEND(agp_amd
, pci
, 1, 1, 1);