agp_ali.c revision 173573
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 173573 2007-11-12 21:51:38Z jhb $");
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
42173573Sjhb#include <dev/agp/agppriv.h>
43173573Sjhb#include <dev/agp/agpreg.h>
44119288Simp#include <dev/pci/pcivar.h>
45119288Simp#include <dev/pci/pcireg.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)) {
68142646Scognet	case 0x167110b9:
69142646Scognet		return ("Ali M1671 host to AGP bridge");
7061452Sdfr	case 0x154110b9:
7161452Sdfr		return ("Ali M1541 host to AGP bridge");
72139431Sanholt	case 0x162110b9:
73139431Sanholt		return ("Ali M1621 host to AGP bridge");
7461452Sdfr	};
7561452Sdfr
7661452Sdfr	return NULL;
7761452Sdfr}
7861452Sdfr
7961452Sdfrstatic int
8061452Sdfragp_ali_probe(device_t dev)
8161452Sdfr{
8261452Sdfr	const char *desc;
8361452Sdfr
84127815Snjl	if (resource_disabled("agp", device_get_unit(dev)))
85127815Snjl		return (ENXIO);
8661452Sdfr	desc = agp_ali_match(dev);
8761452Sdfr	if (desc) {
8861452Sdfr		device_set_desc(dev, desc);
89142398Simp		return BUS_PROBE_DEFAULT;
9061452Sdfr	}
9161452Sdfr
9261452Sdfr	return ENXIO;
9361452Sdfr}
9461452Sdfr
9561452Sdfrstatic int
9661452Sdfragp_ali_attach(device_t dev)
9761452Sdfr{
9861452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
9961452Sdfr	struct agp_gatt *gatt;
10061452Sdfr	int error;
101134098Sanholt	u_int32_t attbase;
10261452Sdfr
10361452Sdfr	error = agp_generic_attach(dev);
10461452Sdfr	if (error)
10561452Sdfr		return error;
10661452Sdfr
10761452Sdfr	sc->initial_aperture = AGP_GET_APERTURE(dev);
108122513Sanholt	if (sc->initial_aperture == 0) {
109122513Sanholt		device_printf(dev, "bad initial aperture size, disabling\n");
110122513Sanholt		return ENXIO;
111122513Sanholt	}
11261452Sdfr
11361452Sdfr	for (;;) {
11461452Sdfr		gatt = agp_alloc_gatt(dev);
11561452Sdfr		if (gatt)
11661452Sdfr			break;
11761452Sdfr
11861452Sdfr		/*
11961452Sdfr		 * Probably contigmalloc failure. Try reducing the
12061452Sdfr		 * aperture so that the gatt size reduces.
12161452Sdfr		 */
12261452Sdfr		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
12361452Sdfr			agp_generic_detach(dev);
12461452Sdfr			return ENOMEM;
12561452Sdfr		}
12661452Sdfr	}
12761452Sdfr	sc->gatt = gatt;
12861452Sdfr
12961452Sdfr	/* Install the gatt. */
130134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
131134098Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, gatt->ag_physical |
132134099Sanholt	    (attbase & 0xfff), 4);
13361452Sdfr
13461452Sdfr	/* Enable the TLB. */
13561452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
13661452Sdfr
13761452Sdfr	return 0;
13861452Sdfr}
13961452Sdfr
14061452Sdfrstatic int
14161452Sdfragp_ali_detach(device_t dev)
14261452Sdfr{
14361452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
144134098Sanholt	u_int32_t attbase;
14561452Sdfr
146173203Sjhb	agp_free_cdev(dev);
14761452Sdfr
14861452Sdfr	/* Disable the TLB.. */
14961452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
15061452Sdfr
15161452Sdfr	/* Put the aperture back the way it started. */
15261452Sdfr	AGP_SET_APERTURE(dev, sc->initial_aperture);
153134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
154134099Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, attbase & 0xfff, 4);
15561452Sdfr
15661452Sdfr	agp_free_gatt(sc->gatt);
157173203Sjhb	agp_free_res(dev);
15861452Sdfr	return 0;
15961452Sdfr}
16061452Sdfr
16161452Sdfr#define M 1024*1024
16261452Sdfr
16361452Sdfrstatic u_int32_t agp_ali_table[] = {
16461452Sdfr	0,			/* 0 - invalid */
16561452Sdfr	1,			/* 1 - invalid */
16661452Sdfr	2,			/* 2 - invalid */
16761452Sdfr	4*M,			/* 3 - invalid */
16861452Sdfr	8*M,			/* 4 - invalid */
16961452Sdfr	0,			/* 5 - invalid */
17061452Sdfr	16*M,			/* 6 - invalid */
17161452Sdfr	32*M,			/* 7 - invalid */
17261452Sdfr	64*M,			/* 8 - invalid */
17361452Sdfr	128*M,			/* 9 - invalid */
17461452Sdfr	256*M,			/* 10 - invalid */
17561452Sdfr};
17661452Sdfr#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
17761452Sdfr
17861452Sdfrstatic u_int32_t
17961452Sdfragp_ali_get_aperture(device_t dev)
18061452Sdfr{
18161452Sdfr	/*
18261452Sdfr	 * The aperture size is derived from the low bits of attbase.
18361452Sdfr	 * I'm not sure this is correct..
18461452Sdfr	 */
185134099Sanholt	int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xf;
18661452Sdfr	if (i >= agp_ali_table_size)
18761452Sdfr		return 0;
18861452Sdfr	return agp_ali_table[i];
18961452Sdfr}
19061452Sdfr
19161452Sdfrstatic int
19261452Sdfragp_ali_set_aperture(device_t dev, u_int32_t aperture)
19361452Sdfr{
19461452Sdfr	int i;
195134098Sanholt	u_int32_t attbase;
19661452Sdfr
19761452Sdfr	for (i = 0; i < agp_ali_table_size; i++)
19861452Sdfr		if (agp_ali_table[i] == aperture)
19961452Sdfr			break;
20061452Sdfr	if (i == agp_ali_table_size)
20161452Sdfr		return EINVAL;
20261452Sdfr
203134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
204134099Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, (attbase & ~0xf) | i, 4);
20561452Sdfr	return 0;
20661452Sdfr}
20761452Sdfr
20861452Sdfrstatic int
20961452Sdfragp_ali_bind_page(device_t dev, int offset, vm_offset_t physical)
21061452Sdfr{
21161452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
21261452Sdfr
21361452Sdfr	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
21461452Sdfr		return EINVAL;
21561452Sdfr
21661452Sdfr	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
21761452Sdfr	return 0;
21861452Sdfr}
21961452Sdfr
22061452Sdfrstatic int
22161452Sdfragp_ali_unbind_page(device_t dev, int offset)
22261452Sdfr{
22361452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
22461452Sdfr
22561452Sdfr	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
22661452Sdfr		return EINVAL;
22761452Sdfr
22861452Sdfr	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
22961452Sdfr	return 0;
23061452Sdfr}
23161452Sdfr
23261452Sdfrstatic void
23361452Sdfragp_ali_flush_tlb(device_t dev)
23461452Sdfr{
23561452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
23661452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
23761452Sdfr}
23861452Sdfr
23961452Sdfrstatic device_method_t agp_ali_methods[] = {
24061452Sdfr	/* Device interface */
24161452Sdfr	DEVMETHOD(device_probe,		agp_ali_probe),
24261452Sdfr	DEVMETHOD(device_attach,	agp_ali_attach),
24361452Sdfr	DEVMETHOD(device_detach,	agp_ali_detach),
24461452Sdfr	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
24561452Sdfr	DEVMETHOD(device_suspend,	bus_generic_suspend),
24661452Sdfr	DEVMETHOD(device_resume,	bus_generic_resume),
24761452Sdfr
24861452Sdfr	/* AGP interface */
24961452Sdfr	DEVMETHOD(agp_get_aperture,	agp_ali_get_aperture),
25061452Sdfr	DEVMETHOD(agp_set_aperture,	agp_ali_set_aperture),
25161452Sdfr	DEVMETHOD(agp_bind_page,	agp_ali_bind_page),
25261452Sdfr	DEVMETHOD(agp_unbind_page,	agp_ali_unbind_page),
25361452Sdfr	DEVMETHOD(agp_flush_tlb,	agp_ali_flush_tlb),
25461452Sdfr	DEVMETHOD(agp_enable,		agp_generic_enable),
25561452Sdfr	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
25661452Sdfr	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
25761452Sdfr	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
25861452Sdfr	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
25961452Sdfr
26061452Sdfr	{ 0, 0 }
26161452Sdfr};
26261452Sdfr
26361452Sdfrstatic driver_t agp_ali_driver = {
26461452Sdfr	"agp",
26561452Sdfr	agp_ali_methods,
26661452Sdfr	sizeof(struct agp_ali_softc),
26761452Sdfr};
26861452Sdfr
26961452Sdfrstatic devclass_t agp_devclass;
27061452Sdfr
271153572SjhbDRIVER_MODULE(agp_ali, hostb, agp_ali_driver, agp_devclass, 0, 0);
272113506SmdoddMODULE_DEPEND(agp_ali, agp, 1, 1, 1);
273113506SmdoddMODULE_DEPEND(agp_ali, pci, 1, 1, 1);
274