agp_ali.c revision 139431
161452Sdfr/*-
261452Sdfr * Copyright (c) 2000 Doug Rabson
361452Sdfr * All rights reserved.
461452Sdfr *
561452Sdfr * Redistribution and use in source and binary forms, with or without
661452Sdfr * modification, are permitted provided that the following conditions
761452Sdfr * are met:
861452Sdfr * 1. Redistributions of source code must retain the above copyright
961452Sdfr *    notice, this list of conditions and the following disclaimer.
1061452Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1161452Sdfr *    notice, this list of conditions and the following disclaimer in the
1261452Sdfr *    documentation and/or other materials provided with the distribution.
1361452Sdfr *
1461452Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1561452Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1661452Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1761452Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1861452Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1961452Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2061452Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2161452Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2261452Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2361452Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2461452Sdfr * SUCH DAMAGE.
2561452Sdfr */
2661452Sdfr
27116192Sobrien#include <sys/cdefs.h>
28116192Sobrien__FBSDID("$FreeBSD: head/sys/dev/agp/agp_ali.c 139431 2004-12-30 07:18:58Z anholt $");
29116192Sobrien
3061452Sdfr#include "opt_bus.h"
3161452Sdfr
3261452Sdfr#include <sys/param.h>
3361452Sdfr#include <sys/systm.h>
3461452Sdfr#include <sys/malloc.h>
3561452Sdfr#include <sys/kernel.h>
36129878Sphk#include <sys/module.h>
3761452Sdfr#include <sys/bus.h>
3861452Sdfr#include <sys/lock.h>
3976827Salfred#include <sys/mutex.h>
4079339Sjhb#include <sys/proc.h>
4161452Sdfr
42119288Simp#include <dev/pci/pcivar.h>
43119288Simp#include <dev/pci/pcireg.h>
4461452Sdfr#include <pci/agppriv.h>
4561452Sdfr#include <pci/agpreg.h>
4661452Sdfr
4761452Sdfr#include <vm/vm.h>
4861452Sdfr#include <vm/vm_object.h>
4961452Sdfr#include <vm/pmap.h>
5061452Sdfr
5161452Sdfrstruct agp_ali_softc {
5261452Sdfr	struct agp_softc agp;
5361452Sdfr	u_int32_t	initial_aperture; /* aperture size at startup */
5461452Sdfr	struct agp_gatt *gatt;
5561452Sdfr};
5661452Sdfr
5761452Sdfrstatic const char*
5861452Sdfragp_ali_match(device_t dev)
5961452Sdfr{
6061452Sdfr	if (pci_get_class(dev) != PCIC_BRIDGE
6161452Sdfr	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
6261452Sdfr		return NULL;
6361452Sdfr
6461452Sdfr	if (agp_find_caps(dev) == 0)
6561452Sdfr		return NULL;
6661452Sdfr
6761452Sdfr	switch (pci_get_devid(dev)) {
6861452Sdfr	case 0x154110b9:
6961452Sdfr		return ("Ali M1541 host to AGP bridge");
70139431Sanholt	case 0x162110b9:
71139431Sanholt		return ("Ali M1621 host to AGP bridge");
7261452Sdfr	};
7361452Sdfr
7461452Sdfr	return NULL;
7561452Sdfr}
7661452Sdfr
7761452Sdfrstatic int
7861452Sdfragp_ali_probe(device_t dev)
7961452Sdfr{
8061452Sdfr	const char *desc;
8161452Sdfr
82127815Snjl	if (resource_disabled("agp", device_get_unit(dev)))
83127815Snjl		return (ENXIO);
8461452Sdfr	desc = agp_ali_match(dev);
8561452Sdfr	if (desc) {
8661452Sdfr		device_verbose(dev);
8761452Sdfr		device_set_desc(dev, desc);
8861452Sdfr		return 0;
8961452Sdfr	}
9061452Sdfr
9161452Sdfr	return ENXIO;
9261452Sdfr}
9361452Sdfr
9461452Sdfrstatic int
9561452Sdfragp_ali_attach(device_t dev)
9661452Sdfr{
9761452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
9861452Sdfr	struct agp_gatt *gatt;
9961452Sdfr	int error;
100134098Sanholt	u_int32_t attbase;
10161452Sdfr
10261452Sdfr	error = agp_generic_attach(dev);
10361452Sdfr	if (error)
10461452Sdfr		return error;
10561452Sdfr
10661452Sdfr	sc->initial_aperture = AGP_GET_APERTURE(dev);
107122513Sanholt	if (sc->initial_aperture == 0) {
108122513Sanholt		device_printf(dev, "bad initial aperture size, disabling\n");
109122513Sanholt		return ENXIO;
110122513Sanholt	}
11161452Sdfr
11261452Sdfr	for (;;) {
11361452Sdfr		gatt = agp_alloc_gatt(dev);
11461452Sdfr		if (gatt)
11561452Sdfr			break;
11661452Sdfr
11761452Sdfr		/*
11861452Sdfr		 * Probably contigmalloc failure. Try reducing the
11961452Sdfr		 * aperture so that the gatt size reduces.
12061452Sdfr		 */
12161452Sdfr		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
12261452Sdfr			agp_generic_detach(dev);
12361452Sdfr			return ENOMEM;
12461452Sdfr		}
12561452Sdfr	}
12661452Sdfr	sc->gatt = gatt;
12761452Sdfr
12861452Sdfr	/* Install the gatt. */
129134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
130134098Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, gatt->ag_physical |
131134099Sanholt	    (attbase & 0xfff), 4);
13261452Sdfr
13361452Sdfr	/* Enable the TLB. */
13461452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
13561452Sdfr
13661452Sdfr	return 0;
13761452Sdfr}
13861452Sdfr
13961452Sdfrstatic int
14061452Sdfragp_ali_detach(device_t dev)
14161452Sdfr{
14261452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
14361452Sdfr	int error;
144134098Sanholt	u_int32_t attbase;
14561452Sdfr
14661452Sdfr	error = agp_generic_detach(dev);
14761452Sdfr	if (error)
14861452Sdfr		return error;
14961452Sdfr
15061452Sdfr	/* Disable the TLB.. */
15161452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
15261452Sdfr
15361452Sdfr	/* Put the aperture back the way it started. */
15461452Sdfr	AGP_SET_APERTURE(dev, sc->initial_aperture);
155134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
156134099Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, attbase & 0xfff, 4);
15761452Sdfr
15861452Sdfr	agp_free_gatt(sc->gatt);
15961452Sdfr	return 0;
16061452Sdfr}
16161452Sdfr
16261452Sdfr#define M 1024*1024
16361452Sdfr
16461452Sdfrstatic u_int32_t agp_ali_table[] = {
16561452Sdfr	0,			/* 0 - invalid */
16661452Sdfr	1,			/* 1 - invalid */
16761452Sdfr	2,			/* 2 - invalid */
16861452Sdfr	4*M,			/* 3 - invalid */
16961452Sdfr	8*M,			/* 4 - invalid */
17061452Sdfr	0,			/* 5 - invalid */
17161452Sdfr	16*M,			/* 6 - invalid */
17261452Sdfr	32*M,			/* 7 - invalid */
17361452Sdfr	64*M,			/* 8 - invalid */
17461452Sdfr	128*M,			/* 9 - invalid */
17561452Sdfr	256*M,			/* 10 - invalid */
17661452Sdfr};
17761452Sdfr#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
17861452Sdfr
17961452Sdfrstatic u_int32_t
18061452Sdfragp_ali_get_aperture(device_t dev)
18161452Sdfr{
18261452Sdfr	/*
18361452Sdfr	 * The aperture size is derived from the low bits of attbase.
18461452Sdfr	 * I'm not sure this is correct..
18561452Sdfr	 */
186134099Sanholt	int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xf;
18761452Sdfr	if (i >= agp_ali_table_size)
18861452Sdfr		return 0;
18961452Sdfr	return agp_ali_table[i];
19061452Sdfr}
19161452Sdfr
19261452Sdfrstatic int
19361452Sdfragp_ali_set_aperture(device_t dev, u_int32_t aperture)
19461452Sdfr{
19561452Sdfr	int i;
196134098Sanholt	u_int32_t attbase;
19761452Sdfr
19861452Sdfr	for (i = 0; i < agp_ali_table_size; i++)
19961452Sdfr		if (agp_ali_table[i] == aperture)
20061452Sdfr			break;
20161452Sdfr	if (i == agp_ali_table_size)
20261452Sdfr		return EINVAL;
20361452Sdfr
204134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
205134099Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, (attbase & ~0xf) | i, 4);
20661452Sdfr	return 0;
20761452Sdfr}
20861452Sdfr
20961452Sdfrstatic int
21061452Sdfragp_ali_bind_page(device_t dev, int offset, vm_offset_t physical)
21161452Sdfr{
21261452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
21361452Sdfr
21461452Sdfr	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
21561452Sdfr		return EINVAL;
21661452Sdfr
21761452Sdfr	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
21861452Sdfr	return 0;
21961452Sdfr}
22061452Sdfr
22161452Sdfrstatic int
22261452Sdfragp_ali_unbind_page(device_t dev, int offset)
22361452Sdfr{
22461452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
22561452Sdfr
22661452Sdfr	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
22761452Sdfr		return EINVAL;
22861452Sdfr
22961452Sdfr	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
23061452Sdfr	return 0;
23161452Sdfr}
23261452Sdfr
23361452Sdfrstatic void
23461452Sdfragp_ali_flush_tlb(device_t dev)
23561452Sdfr{
23661452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
23761452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
23861452Sdfr}
23961452Sdfr
24061452Sdfrstatic device_method_t agp_ali_methods[] = {
24161452Sdfr	/* Device interface */
24261452Sdfr	DEVMETHOD(device_probe,		agp_ali_probe),
24361452Sdfr	DEVMETHOD(device_attach,	agp_ali_attach),
24461452Sdfr	DEVMETHOD(device_detach,	agp_ali_detach),
24561452Sdfr	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
24661452Sdfr	DEVMETHOD(device_suspend,	bus_generic_suspend),
24761452Sdfr	DEVMETHOD(device_resume,	bus_generic_resume),
24861452Sdfr
24961452Sdfr	/* AGP interface */
25061452Sdfr	DEVMETHOD(agp_get_aperture,	agp_ali_get_aperture),
25161452Sdfr	DEVMETHOD(agp_set_aperture,	agp_ali_set_aperture),
25261452Sdfr	DEVMETHOD(agp_bind_page,	agp_ali_bind_page),
25361452Sdfr	DEVMETHOD(agp_unbind_page,	agp_ali_unbind_page),
25461452Sdfr	DEVMETHOD(agp_flush_tlb,	agp_ali_flush_tlb),
25561452Sdfr	DEVMETHOD(agp_enable,		agp_generic_enable),
25661452Sdfr	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
25761452Sdfr	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
25861452Sdfr	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
25961452Sdfr	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
26061452Sdfr
26161452Sdfr	{ 0, 0 }
26261452Sdfr};
26361452Sdfr
26461452Sdfrstatic driver_t agp_ali_driver = {
26561452Sdfr	"agp",
26661452Sdfr	agp_ali_methods,
26761452Sdfr	sizeof(struct agp_ali_softc),
26861452Sdfr};
26961452Sdfr
27061452Sdfrstatic devclass_t agp_devclass;
27161452Sdfr
27261452SdfrDRIVER_MODULE(agp_ali, pci, agp_ali_driver, agp_devclass, 0, 0);
273113506SmdoddMODULE_DEPEND(agp_ali, agp, 1, 1, 1);
274113506SmdoddMODULE_DEPEND(agp_ali, pci, 1, 1, 1);
275