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: releng/10.2/sys/dev/agp/agp_ali.c 244926 2013-01-01 18:16:49Z antoine $");
29116192Sobrien
3061452Sdfr#include <sys/param.h>
3161452Sdfr#include <sys/systm.h>
3261452Sdfr#include <sys/malloc.h>
3361452Sdfr#include <sys/kernel.h>
34129878Sphk#include <sys/module.h>
3561452Sdfr#include <sys/bus.h>
3661452Sdfr#include <sys/lock.h>
3776827Salfred#include <sys/mutex.h>
3879339Sjhb#include <sys/proc.h>
3961452Sdfr
40173573Sjhb#include <dev/agp/agppriv.h>
41173573Sjhb#include <dev/agp/agpreg.h>
42119288Simp#include <dev/pci/pcivar.h>
43119288Simp#include <dev/pci/pcireg.h>
4461452Sdfr
4561452Sdfr#include <vm/vm.h>
4661452Sdfr#include <vm/vm_object.h>
4761452Sdfr#include <vm/pmap.h>
4861452Sdfr
4961452Sdfrstruct agp_ali_softc {
5061452Sdfr	struct agp_softc agp;
5161452Sdfr	u_int32_t	initial_aperture; /* aperture size at startup */
5261452Sdfr	struct agp_gatt *gatt;
5361452Sdfr};
5461452Sdfr
5561452Sdfrstatic const char*
5661452Sdfragp_ali_match(device_t dev)
5761452Sdfr{
5861452Sdfr	if (pci_get_class(dev) != PCIC_BRIDGE
5961452Sdfr	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
6061452Sdfr		return NULL;
6161452Sdfr
6261452Sdfr	if (agp_find_caps(dev) == 0)
6361452Sdfr		return NULL;
6461452Sdfr
6561452Sdfr	switch (pci_get_devid(dev)) {
66142646Scognet	case 0x167110b9:
67142646Scognet		return ("Ali M1671 host to AGP bridge");
6861452Sdfr	case 0x154110b9:
6961452Sdfr		return ("Ali M1541 host to AGP bridge");
70139431Sanholt	case 0x162110b9:
71139431Sanholt		return ("Ali M1621 host to AGP bridge");
72244926Santoine	}
7361452Sdfr
7461452Sdfr	return NULL;
7561452Sdfr}
7661452Sdfr
7761452Sdfrstatic int
7861452Sdfragp_ali_probe(device_t dev)
7961452Sdfr{
8061452Sdfr	const char *desc;
8161452Sdfr
82241885Seadler	if (resource_disabled("agp", device_get_unit(dev)))
83241885Seadler		return (ENXIO);
8461452Sdfr	desc = agp_ali_match(dev);
8561452Sdfr	if (desc) {
8661452Sdfr		device_set_desc(dev, desc);
87142398Simp		return BUS_PROBE_DEFAULT;
8861452Sdfr	}
8961452Sdfr
9061452Sdfr	return ENXIO;
9161452Sdfr}
9261452Sdfr
9361452Sdfrstatic int
9461452Sdfragp_ali_attach(device_t dev)
9561452Sdfr{
9661452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
9761452Sdfr	struct agp_gatt *gatt;
9861452Sdfr	int error;
99134098Sanholt	u_int32_t attbase;
10061452Sdfr
10161452Sdfr	error = agp_generic_attach(dev);
10261452Sdfr	if (error)
10361452Sdfr		return error;
10461452Sdfr
10561452Sdfr	sc->initial_aperture = AGP_GET_APERTURE(dev);
106122513Sanholt	if (sc->initial_aperture == 0) {
107122513Sanholt		device_printf(dev, "bad initial aperture size, disabling\n");
108122513Sanholt		return ENXIO;
109122513Sanholt	}
11061452Sdfr
11161452Sdfr	for (;;) {
11261452Sdfr		gatt = agp_alloc_gatt(dev);
11361452Sdfr		if (gatt)
11461452Sdfr			break;
11561452Sdfr
11661452Sdfr		/*
11761452Sdfr		 * Probably contigmalloc failure. Try reducing the
11861452Sdfr		 * aperture so that the gatt size reduces.
11961452Sdfr		 */
12061452Sdfr		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
12161452Sdfr			agp_generic_detach(dev);
12261452Sdfr			return ENOMEM;
12361452Sdfr		}
12461452Sdfr	}
12561452Sdfr	sc->gatt = gatt;
12661452Sdfr
12761452Sdfr	/* Install the gatt. */
128134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
129134098Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, gatt->ag_physical |
130134099Sanholt	    (attbase & 0xfff), 4);
13161452Sdfr
13261452Sdfr	/* Enable the TLB. */
13361452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
13461452Sdfr
13561452Sdfr	return 0;
13661452Sdfr}
13761452Sdfr
13861452Sdfrstatic int
13961452Sdfragp_ali_detach(device_t dev)
14061452Sdfr{
14161452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
142134098Sanholt	u_int32_t attbase;
14361452Sdfr
144173203Sjhb	agp_free_cdev(dev);
14561452Sdfr
14661452Sdfr	/* Disable the TLB.. */
14761452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
14861452Sdfr
14961452Sdfr	/* Put the aperture back the way it started. */
15061452Sdfr	AGP_SET_APERTURE(dev, sc->initial_aperture);
151134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
152134099Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, attbase & 0xfff, 4);
15361452Sdfr
15461452Sdfr	agp_free_gatt(sc->gatt);
155173203Sjhb	agp_free_res(dev);
15661452Sdfr	return 0;
15761452Sdfr}
15861452Sdfr
15961452Sdfr#define M 1024*1024
16061452Sdfr
16161452Sdfrstatic u_int32_t agp_ali_table[] = {
16261452Sdfr	0,			/* 0 - invalid */
16361452Sdfr	1,			/* 1 - invalid */
16461452Sdfr	2,			/* 2 - invalid */
16561452Sdfr	4*M,			/* 3 - invalid */
16661452Sdfr	8*M,			/* 4 - invalid */
16761452Sdfr	0,			/* 5 - invalid */
16861452Sdfr	16*M,			/* 6 - invalid */
16961452Sdfr	32*M,			/* 7 - invalid */
17061452Sdfr	64*M,			/* 8 - invalid */
17161452Sdfr	128*M,			/* 9 - invalid */
17261452Sdfr	256*M,			/* 10 - invalid */
17361452Sdfr};
17461452Sdfr#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
17561452Sdfr
17661452Sdfrstatic u_int32_t
17761452Sdfragp_ali_get_aperture(device_t dev)
17861452Sdfr{
17961452Sdfr	/*
18061452Sdfr	 * The aperture size is derived from the low bits of attbase.
18161452Sdfr	 * I'm not sure this is correct..
18261452Sdfr	 */
183134099Sanholt	int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xf;
18461452Sdfr	if (i >= agp_ali_table_size)
18561452Sdfr		return 0;
18661452Sdfr	return agp_ali_table[i];
18761452Sdfr}
18861452Sdfr
18961452Sdfrstatic int
19061452Sdfragp_ali_set_aperture(device_t dev, u_int32_t aperture)
19161452Sdfr{
19261452Sdfr	int i;
193134098Sanholt	u_int32_t attbase;
19461452Sdfr
19561452Sdfr	for (i = 0; i < agp_ali_table_size; i++)
19661452Sdfr		if (agp_ali_table[i] == aperture)
19761452Sdfr			break;
19861452Sdfr	if (i == agp_ali_table_size)
19961452Sdfr		return EINVAL;
20061452Sdfr
201134098Sanholt	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
202134099Sanholt	pci_write_config(dev, AGP_ALI_ATTBASE, (attbase & ~0xf) | i, 4);
20361452Sdfr	return 0;
20461452Sdfr}
20561452Sdfr
20661452Sdfrstatic int
207194017Savgagp_ali_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
20861452Sdfr{
20961452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
21061452Sdfr
211194017Savg	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
21261452Sdfr		return EINVAL;
21361452Sdfr
21461452Sdfr	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
21561452Sdfr	return 0;
21661452Sdfr}
21761452Sdfr
21861452Sdfrstatic int
219194017Savgagp_ali_unbind_page(device_t dev, vm_offset_t offset)
22061452Sdfr{
22161452Sdfr	struct agp_ali_softc *sc = device_get_softc(dev);
22261452Sdfr
223194017Savg	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
22461452Sdfr		return EINVAL;
22561452Sdfr
22661452Sdfr	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
22761452Sdfr	return 0;
22861452Sdfr}
22961452Sdfr
23061452Sdfrstatic void
23161452Sdfragp_ali_flush_tlb(device_t dev)
23261452Sdfr{
23361452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
23461452Sdfr	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
23561452Sdfr}
23661452Sdfr
23761452Sdfrstatic device_method_t agp_ali_methods[] = {
23861452Sdfr	/* Device interface */
23961452Sdfr	DEVMETHOD(device_probe,		agp_ali_probe),
24061452Sdfr	DEVMETHOD(device_attach,	agp_ali_attach),
24161452Sdfr	DEVMETHOD(device_detach,	agp_ali_detach),
24261452Sdfr	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
24361452Sdfr	DEVMETHOD(device_suspend,	bus_generic_suspend),
24461452Sdfr	DEVMETHOD(device_resume,	bus_generic_resume),
24561452Sdfr
24661452Sdfr	/* AGP interface */
24761452Sdfr	DEVMETHOD(agp_get_aperture,	agp_ali_get_aperture),
24861452Sdfr	DEVMETHOD(agp_set_aperture,	agp_ali_set_aperture),
24961452Sdfr	DEVMETHOD(agp_bind_page,	agp_ali_bind_page),
25061452Sdfr	DEVMETHOD(agp_unbind_page,	agp_ali_unbind_page),
25161452Sdfr	DEVMETHOD(agp_flush_tlb,	agp_ali_flush_tlb),
25261452Sdfr	DEVMETHOD(agp_enable,		agp_generic_enable),
25361452Sdfr	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
25461452Sdfr	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
25561452Sdfr	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
25661452Sdfr	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
25761452Sdfr
25861452Sdfr	{ 0, 0 }
25961452Sdfr};
26061452Sdfr
26161452Sdfrstatic driver_t agp_ali_driver = {
26261452Sdfr	"agp",
26361452Sdfr	agp_ali_methods,
26461452Sdfr	sizeof(struct agp_ali_softc),
26561452Sdfr};
26661452Sdfr
26761452Sdfrstatic devclass_t agp_devclass;
26861452Sdfr
269153572SjhbDRIVER_MODULE(agp_ali, hostb, agp_ali_driver, agp_devclass, 0, 0);
270113506SmdoddMODULE_DEPEND(agp_ali, agp, 1, 1, 1);
271113506SmdoddMODULE_DEPEND(agp_ali, pci, 1, 1, 1);
272