Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/agp/agp_ati.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2005 Eric Anholt
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*
28
* Based on reading the Linux 2.6.8.1 driver by Dave Jones.
29
*/
30
31
#include <sys/param.h>
32
#include <sys/systm.h>
33
#include <sys/malloc.h>
34
#include <sys/kernel.h>
35
#include <sys/module.h>
36
#include <sys/bus.h>
37
#include <sys/lock.h>
38
#include <sys/mutex.h>
39
#include <sys/proc.h>
40
41
#include <dev/agp/agppriv.h>
42
#include <dev/agp/agpreg.h>
43
#include <dev/pci/pcivar.h>
44
#include <dev/pci/pcireg.h>
45
46
#include <vm/vm.h>
47
#include <vm/vm_extern.h>
48
#include <vm/vm_kern.h>
49
#include <vm/vm_object.h>
50
#include <vm/pmap.h>
51
#include <machine/bus.h>
52
#include <machine/resource.h>
53
#include <sys/rman.h>
54
55
MALLOC_DECLARE(M_AGP);
56
57
#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off)
58
#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
59
60
struct agp_ati_softc {
61
struct agp_softc agp;
62
struct resource *regs; /* memory mapped control registers */
63
bus_space_tag_t bst; /* bus_space tag */
64
bus_space_handle_t bsh; /* bus_space handle */
65
u_int32_t initial_aperture; /* aperture size at startup */
66
char is_rs300;
67
68
/* The GATT */
69
u_int32_t ag_entries;
70
u_int32_t *ag_virtual; /* virtual address of gatt */
71
u_int32_t *ag_vdir; /* virtual address of page dir */
72
vm_offset_t ag_pdir; /* physical address of page dir */
73
};
74
75
static const char*
76
agp_ati_match(device_t dev)
77
{
78
if (pci_get_class(dev) != PCIC_BRIDGE ||
79
pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
80
return NULL;
81
82
if (agp_find_caps(dev) == 0)
83
return NULL;
84
85
switch (pci_get_devid(dev)) {
86
case 0xcab01002:
87
return ("ATI RS100 AGP bridge");
88
case 0xcab21002:
89
return ("ATI RS200 AGP bridge");
90
case 0xcbb21002:
91
return ("ATI RS200M AGP bridge");
92
case 0xcab31002:
93
return ("ATI RS250 AGP bridge");
94
case 0x58301002:
95
return ("ATI RS300_100 AGP bridge");
96
case 0x58311002:
97
return ("ATI RS300_133 AGP bridge");
98
case 0x58321002:
99
return ("ATI RS300_166 AGP bridge");
100
case 0x58331002:
101
return ("ATI RS300_200 AGP bridge");
102
}
103
104
return NULL;
105
}
106
107
static int
108
agp_ati_probe(device_t dev)
109
{
110
const char *desc;
111
112
desc = agp_ati_match(dev);
113
if (desc) {
114
device_set_desc(dev, desc);
115
return 0;
116
}
117
118
return ENXIO;
119
}
120
121
static int
122
agp_ati_alloc_gatt(device_t dev)
123
{
124
struct agp_ati_softc *sc = device_get_softc(dev);
125
u_int32_t apsize = AGP_GET_APERTURE(dev);
126
u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
127
u_int32_t apbase_offset;
128
int i;
129
130
/* Alloc the GATT -- pointers to pages of AGP memory */
131
sc->ag_entries = entries;
132
sc->ag_virtual = kmem_alloc_attr(entries * sizeof(uint32_t),
133
M_NOWAIT | M_ZERO, 0, ~0, VM_MEMATTR_WRITE_COMBINING);
134
if (sc->ag_virtual == NULL) {
135
if (bootverbose)
136
device_printf(dev, "GATT allocation failed\n");
137
return ENOMEM;
138
}
139
140
/* Alloc the page directory -- pointers to each page of the GATT */
141
sc->ag_vdir = kmem_alloc_attr(AGP_PAGE_SIZE, M_NOWAIT | M_ZERO,
142
0, ~0, VM_MEMATTR_WRITE_COMBINING);
143
if (sc->ag_vdir == NULL) {
144
if (bootverbose)
145
device_printf(dev, "pagedir allocation failed\n");
146
kmem_free(sc->ag_virtual, entries * sizeof(uint32_t));
147
return ENOMEM;
148
}
149
sc->ag_pdir = vtophys((vm_offset_t)sc->ag_vdir);
150
151
apbase_offset = pci_read_config(dev, AGP_APBASE, 4) >> 22;
152
/* Fill in the pagedir's pointers to GATT pages */
153
for (i = 0; i < sc->ag_entries / 1024; i++) {
154
vm_offset_t va;
155
vm_offset_t pa;
156
157
va = ((vm_offset_t)sc->ag_virtual) + i * AGP_PAGE_SIZE;
158
pa = vtophys(va);
159
sc->ag_vdir[apbase_offset + i] = pa | 1;
160
}
161
162
return 0;
163
}
164
165
static int
166
agp_ati_attach(device_t dev)
167
{
168
struct agp_ati_softc *sc = device_get_softc(dev);
169
int error, rid;
170
u_int32_t temp;
171
u_int32_t apsize_reg, agpmode_reg;
172
173
error = agp_generic_attach(dev);
174
if (error)
175
return error;
176
177
switch (pci_get_devid(dev)) {
178
case 0xcab01002: /* ATI RS100 AGP bridge */
179
case 0xcab21002: /* ATI RS200 AGP bridge */
180
case 0xcbb21002: /* ATI RS200M AGP bridge */
181
case 0xcab31002: /* ATI RS250 AGP bridge */
182
sc->is_rs300 = 0;
183
apsize_reg = ATI_RS100_APSIZE;
184
agpmode_reg = ATI_RS100_IG_AGPMODE;
185
break;
186
case 0x58301002: /* ATI RS300_100 AGP bridge */
187
case 0x58311002: /* ATI RS300_133 AGP bridge */
188
case 0x58321002: /* ATI RS300_166 AGP bridge */
189
case 0x58331002: /* ATI RS300_200 AGP bridge */
190
sc->is_rs300 = 1;
191
apsize_reg = ATI_RS300_APSIZE;
192
agpmode_reg = ATI_RS300_IG_AGPMODE;
193
break;
194
default:
195
/* Unknown chipset */
196
return EINVAL;
197
}
198
199
rid = ATI_GART_MMADDR;
200
sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
201
if (!sc->regs) {
202
agp_generic_detach(dev);
203
return ENOMEM;
204
}
205
206
sc->bst = rman_get_bustag(sc->regs);
207
sc->bsh = rman_get_bushandle(sc->regs);
208
209
sc->initial_aperture = AGP_GET_APERTURE(dev);
210
211
for (;;) {
212
if (agp_ati_alloc_gatt(dev) == 0)
213
break;
214
215
/*
216
* Probably contigmalloc failure. Try reducing the
217
* aperture so that the gatt size reduces.
218
*/
219
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
220
return ENOMEM;
221
}
222
223
temp = pci_read_config(dev, apsize_reg, 4);
224
pci_write_config(dev, apsize_reg, temp | 1, 4);
225
226
pci_write_config(dev, agpmode_reg, 0x20000, 4);
227
228
WRITE4(ATI_GART_FEATURE_ID, 0x00060000);
229
230
temp = pci_read_config(dev, 4, 4); /* XXX: Magic reg# */
231
pci_write_config(dev, 4, temp | (1 << 14), 4);
232
233
WRITE4(ATI_GART_BASE, sc->ag_pdir);
234
235
AGP_FLUSH_TLB(dev);
236
237
return 0;
238
}
239
240
static int
241
agp_ati_detach(device_t dev)
242
{
243
struct agp_ati_softc *sc = device_get_softc(dev);
244
u_int32_t apsize_reg, temp;
245
246
agp_free_cdev(dev);
247
248
if (sc->is_rs300)
249
apsize_reg = ATI_RS300_APSIZE;
250
else
251
apsize_reg = ATI_RS100_APSIZE;
252
253
/* Clear the GATT base */
254
WRITE4(ATI_GART_BASE, 0);
255
256
/* Put the aperture back the way it started. */
257
AGP_SET_APERTURE(dev, sc->initial_aperture);
258
259
temp = pci_read_config(dev, apsize_reg, 4);
260
pci_write_config(dev, apsize_reg, temp & ~1, 4);
261
262
kmem_free(sc->ag_vdir, AGP_PAGE_SIZE);
263
kmem_free(sc->ag_virtual, sc->ag_entries * sizeof(uint32_t));
264
265
bus_release_resource(dev, SYS_RES_MEMORY, ATI_GART_MMADDR, sc->regs);
266
agp_free_res(dev);
267
268
return 0;
269
}
270
271
static u_int32_t
272
agp_ati_get_aperture(device_t dev)
273
{
274
struct agp_ati_softc *sc = device_get_softc(dev);
275
int size_value;
276
277
if (sc->is_rs300)
278
size_value = pci_read_config(dev, ATI_RS300_APSIZE, 4);
279
else
280
size_value = pci_read_config(dev, ATI_RS100_APSIZE, 4);
281
282
size_value = (size_value & 0x0000000e) >> 1;
283
size_value = (32 * 1024 * 1024) << size_value;
284
285
return size_value;
286
}
287
288
static int
289
agp_ati_set_aperture(device_t dev, u_int32_t aperture)
290
{
291
struct agp_ati_softc *sc = device_get_softc(dev);
292
int size_value;
293
u_int32_t apsize_reg;
294
295
if (sc->is_rs300)
296
apsize_reg = ATI_RS300_APSIZE;
297
else
298
apsize_reg = ATI_RS100_APSIZE;
299
300
size_value = pci_read_config(dev, apsize_reg, 4);
301
302
size_value &= ~0x0000000e;
303
size_value |= (ffs(aperture / (32 * 1024 * 1024)) - 1) << 1;
304
305
pci_write_config(dev, apsize_reg, size_value, 4);
306
307
return 0;
308
}
309
310
static int
311
agp_ati_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
312
{
313
struct agp_ati_softc *sc = device_get_softc(dev);
314
315
if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT))
316
return EINVAL;
317
318
sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
319
320
return 0;
321
}
322
323
static int
324
agp_ati_unbind_page(device_t dev, vm_offset_t offset)
325
{
326
struct agp_ati_softc *sc = device_get_softc(dev);
327
328
if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT))
329
return EINVAL;
330
331
sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
332
return 0;
333
}
334
335
static void
336
agp_ati_flush_tlb(device_t dev)
337
{
338
struct agp_ati_softc *sc = device_get_softc(dev);
339
340
/* Set the cache invalidate bit and wait for the chipset to clear */
341
WRITE4(ATI_GART_CACHE_CNTRL, 1);
342
(void)READ4(ATI_GART_CACHE_CNTRL);
343
}
344
345
static device_method_t agp_ati_methods[] = {
346
/* Device interface */
347
DEVMETHOD(device_probe, agp_ati_probe),
348
DEVMETHOD(device_attach, agp_ati_attach),
349
DEVMETHOD(device_detach, agp_ati_detach),
350
DEVMETHOD(device_shutdown, bus_generic_shutdown),
351
DEVMETHOD(device_suspend, bus_generic_suspend),
352
DEVMETHOD(device_resume, bus_generic_resume),
353
354
/* AGP interface */
355
DEVMETHOD(agp_get_aperture, agp_ati_get_aperture),
356
DEVMETHOD(agp_set_aperture, agp_ati_set_aperture),
357
DEVMETHOD(agp_bind_page, agp_ati_bind_page),
358
DEVMETHOD(agp_unbind_page, agp_ati_unbind_page),
359
DEVMETHOD(agp_flush_tlb, agp_ati_flush_tlb),
360
DEVMETHOD(agp_enable, agp_generic_enable),
361
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
362
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
363
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
364
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
365
{ 0, 0 }
366
};
367
368
static driver_t agp_ati_driver = {
369
"agp",
370
agp_ati_methods,
371
sizeof(struct agp_ati_softc),
372
};
373
374
DRIVER_MODULE(agp_ati, hostb, agp_ati_driver, 0, 0);
375
MODULE_DEPEND(agp_ati, agp, 1, 1, 1);
376
MODULE_DEPEND(agp_ati, pci, 1, 1, 1);
377
378