Make sure a serial port exists by determining whether it is possible to drain
[dragonfly.git] / sys / dev / agp / agp_i810.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 2000 Doug Rabson
3 * Copyright (c) 2000 Ruslan Ermilov
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: src/sys/pci/agp_i810.c,v 1.1.2.5 2002/09/15 08:45:41 anholt Exp $
be566ddd 28 * $DragonFly: src/sys/dev/agp/agp_i810.c,v 1.7 2004/05/13 14:33:14 joerg Exp $
984263bc
MD
29 */
30
31/*
32 * Fixes for 830/845G support: David Dawes <dawes@xfree86.org>
33 */
34
35#include "opt_bus.h"
36#include "opt_pci.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/kernel.h>
42#include <sys/bus.h>
43#include <sys/lock.h>
44
1f2de5d4
MD
45#include <bus/pci/pcivar.h>
46#include <bus/pci/pcireg.h>
47#include "agppriv.h"
48#include "agpreg.h"
984263bc
MD
49
50#include <vm/vm.h>
51#include <vm/vm_object.h>
52#include <vm/vm_page.h>
53#include <vm/vm_pageout.h>
54#include <vm/pmap.h>
55
56#include <machine/bus.h>
57#include <machine/resource.h>
58#include <sys/rman.h>
59
60MALLOC_DECLARE(M_AGP);
61
62#define READ1(off) bus_space_read_1(sc->bst, sc->bsh, off)
63#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off)
64#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
65
66#define CHIP_I810 0 /* i810/i815 */
67#define CHIP_I830 1 /* i830/i845 */
68
69struct agp_i810_softc {
70 struct agp_softc agp;
71 u_int32_t initial_aperture; /* aperture size at startup */
72 struct agp_gatt *gatt;
73 int chiptype; /* i810-like or i830 */
74 u_int32_t dcache_size; /* i810 only */
75 u_int32_t stolen; /* number of i830/845 gtt entries for stolen memory */
76 device_t bdev; /* bridge device */
77 struct resource *regs; /* memory mapped GC registers */
78 bus_space_tag_t bst; /* bus_space tag */
79 bus_space_handle_t bsh; /* bus_space handle */
80};
81
82static const char*
83agp_i810_match(device_t dev)
84{
85 if (pci_get_class(dev) != PCIC_DISPLAY
86 || pci_get_subclass(dev) != PCIS_DISPLAY_VGA)
87 return NULL;
88
89 switch (pci_get_devid(dev)) {
90 case 0x71218086:
91 return ("Intel 82810 (i810 GMCH) SVGA controller");
92
93 case 0x71238086:
94 return ("Intel 82810-DC100 (i810-DC100 GMCH) SVGA controller");
95
96 case 0x71258086:
97 return ("Intel 82810E (i810E GMCH) SVGA controller");
98
99 case 0x11328086:
100 return ("Intel 82815 (i815 GMCH) SVGA controller");
101
102 case 0x35778086:
103 return ("Intel 82830 (i830M GMCH) SVGA controller");
104
105 case 0x25628086:
106 return ("Intel 82845 (i845 GMCH) SVGA controller");
be566ddd
JS
107
108 case 0x25728086:
109 return ("Intel 82865 (i865 GMCH) SVGA controller");
984263bc
MD
110 };
111
112 return NULL;
113}
114
115/*
116 * Find bridge device.
117 */
118static device_t
119agp_i810_find_bridge(device_t dev)
120{
121 device_t *children, child;
122 int nchildren, i;
123 u_int32_t devid;
124
125 /*
126 * Calculate bridge device's ID.
127 */
128 devid = pci_get_devid(dev);
129 switch (devid) {
130 case 0x71218086:
131 case 0x71238086:
132 case 0x71258086:
133 devid -= 0x10000;
134 break;
135
136 case 0x11328086:
137 case 0x35778086:
138 case 0x25628086:
be566ddd 139 case 0x25728086:
984263bc
MD
140 devid -= 0x20000;
141 break;
142 };
143 if (device_get_children(device_get_parent(dev), &children, &nchildren))
144 return 0;
145
146 for (i = 0; i < nchildren; i++) {
147 child = children[i];
148
149 if (pci_get_devid(child) == devid) {
150 free(children, M_TEMP);
151 return child;
152 }
153 }
154 free(children, M_TEMP);
155 return 0;
156}
157
158static int
159agp_i810_probe(device_t dev)
160{
161 const char *desc;
162
163 desc = agp_i810_match(dev);
164 if (desc) {
165 device_t bdev;
166 u_int8_t smram;
167 int devid = pci_get_devid(dev);
168
169 bdev = agp_i810_find_bridge(dev);
170 if (!bdev) {
171 if (bootverbose)
172 printf("I810: can't find bridge device\n");
173 return ENXIO;
174 }
175
176 /*
177 * checking whether internal graphics device has been activated.
178 */
179 if ( (devid != 0x35778086 ) &&
be566ddd
JS
180 (devid != 0x25628086 ) &&
181 (devid != 0x25728086 ) ) {
984263bc
MD
182 smram = pci_read_config(bdev, AGP_I810_SMRAM, 1);
183 if ((smram & AGP_I810_SMRAM_GMS)
184 == AGP_I810_SMRAM_GMS_DISABLED) {
185 if (bootverbose)
186 printf("I810: disabled, not probing\n");
187 return ENXIO;
188 }
189 } else { /* I830MG */
190 unsigned int gcc1;
191 gcc1 = pci_read_config(bdev, AGP_I830_GCC1, 1);
192 if ((gcc1 & AGP_I830_GCC1_DEV2) == AGP_I830_GCC1_DEV2_DISABLED) {
193 if (bootverbose)
194 printf("I830: disabled, not probing\n");
195 return ENXIO;
196 }
197 }
198
199 device_verbose(dev);
200 device_set_desc(dev, desc);
201 return 0;
202 }
203
204 return ENXIO;
205}
206
207static int
208agp_i810_attach(device_t dev)
209{
210 struct agp_i810_softc *sc = device_get_softc(dev);
211 struct agp_gatt *gatt;
212 int error, rid;
213
214 sc->bdev = agp_i810_find_bridge(dev);
215 if (!sc->bdev)
216 return ENOENT;
217
218 error = agp_generic_attach(dev);
219 if (error)
220 return error;
221
222 switch (pci_get_devid(dev)) {
223 case 0x71218086:
224 case 0x71238086:
225 case 0x71258086:
226 case 0x11328086:
227 sc->chiptype = CHIP_I810;
228 break;
229 case 0x35778086:
230 case 0x25628086:
be566ddd 231 case 0x25728086:
984263bc
MD
232 sc->chiptype = CHIP_I830;
233 break;
234 };
235
236 /* Same for i810 and i830 */
237 rid = AGP_I810_MMADR;
238 sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
239 0, ~0, 1, RF_ACTIVE);
240 if (!sc->regs) {
241 agp_generic_detach(dev);
242 return ENOMEM;
243 }
244 sc->bst = rman_get_bustag(sc->regs);
245 sc->bsh = rman_get_bushandle(sc->regs);
246
247 sc->initial_aperture = AGP_GET_APERTURE(dev);
f7841f3c
MD
248 if (sc->initial_aperture == 0) {
249 device_printf(dev, "bad initial aperture size, disabling\n");
250 return ENXIO;
251 }
984263bc 252
97fe41b7 253 gatt = malloc( sizeof(struct agp_gatt), M_AGP, M_INTWAIT);
984263bc
MD
254 sc->gatt = gatt;
255
256 gatt->ag_entries = AGP_GET_APERTURE(dev) >> AGP_PAGE_SHIFT;
257
258 if ( sc->chiptype == CHIP_I810 ) {
259 /* Some i810s have on-chip memory called dcache */
260 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED)
261 sc->dcache_size = 4 * 1024 * 1024;
262 else
263 sc->dcache_size = 0;
264
265 /* According to the specs the gatt on the i810 must be 64k */
266 gatt->ag_virtual = contigmalloc( 64 * 1024, M_AGP, 0,
267 0, ~0, PAGE_SIZE, 0);
268 if (!gatt->ag_virtual) {
269 if (bootverbose)
270 device_printf(dev, "contiguous allocation failed\n");
271 free(gatt, M_AGP);
272 agp_generic_detach(dev);
273 return ENOMEM;
274 }
275 bzero(gatt->ag_virtual, gatt->ag_entries * sizeof(u_int32_t));
276
277 gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
278 agp_flush_cache();
279 /* Install the GATT. */
280 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1);
281 } else {
282 /* The i830 automatically initializes the 128k gatt on boot. */
283 unsigned int gcc1, pgtblctl;
284
285 gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 1);
286 switch (gcc1 & AGP_I830_GCC1_GMS) {
287 case AGP_I830_GCC1_GMS_STOLEN_512:
288 sc->stolen = (512 - 132) * 1024 / 4096;
289 break;
290 case AGP_I830_GCC1_GMS_STOLEN_1024:
291 sc->stolen = (1024 - 132) * 1024 / 4096;
292 break;
293 case AGP_I830_GCC1_GMS_STOLEN_8192:
294 sc->stolen = (8192 - 132) * 1024 / 4096;
295 break;
296 default:
297 sc->stolen = 0;
298 device_printf(dev, "unknown memory configuration, disabling\n");
299 agp_generic_detach(dev);
300 return EINVAL;
301 }
302 if (sc->stolen > 0)
303 device_printf(dev, "detected %dk stolen memory\n", sc->stolen * 4);
304 device_printf(dev, "aperture size is %dM\n", sc->initial_aperture / 1024 / 1024);
305
306 /* GATT address is already in there, make sure it's enabled */
307 pgtblctl = READ4(AGP_I810_PGTBL_CTL);
308#if 0
309 device_printf(dev, "PGTBL_CTL is 0x%08x\n", pgtblctl);
310#endif
311 pgtblctl |= 1;
312 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl);
313
314 gatt->ag_physical = pgtblctl & ~1;
315 }
316
317 /*
318 * Make sure the chipset can see everything.
319 */
320 agp_flush_cache();
321
322 return 0;
323}
324
325static int
326agp_i810_detach(device_t dev)
327{
328 struct agp_i810_softc *sc = device_get_softc(dev);
329 int error;
330
331 error = agp_generic_detach(dev);
332 if (error)
333 return error;
334
335 /* Clear the GATT base. */
336 if ( sc->chiptype == CHIP_I810 ) {
337 WRITE4(AGP_I810_PGTBL_CTL, 0);
338 } else {
339 unsigned int pgtblctl;
340 pgtblctl = READ4(AGP_I810_PGTBL_CTL);
341 pgtblctl &= ~1;
342 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl);
343 }
344
345 /* Put the aperture back the way it started. */
346 AGP_SET_APERTURE(dev, sc->initial_aperture);
347
348 if ( sc->chiptype == CHIP_I810 ) {
349 contigfree(sc->gatt->ag_virtual, 64 * 1024, M_AGP);
350 }
351 free(sc->gatt, M_AGP);
352
353 bus_release_resource(dev, SYS_RES_MEMORY,
354 AGP_I810_MMADR, sc->regs);
355
356 return 0;
357}
358
359static u_int32_t
360agp_i810_get_aperture(device_t dev)
361{
362 struct agp_i810_softc *sc = device_get_softc(dev);
363
364 if ( sc->chiptype == CHIP_I810 ) {
365 u_int16_t miscc;
366 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
367 if ((miscc & AGP_I810_MISCC_WINSIZE) == AGP_I810_MISCC_WINSIZE_32)
368 return 32 * 1024 * 1024;
369 else
370 return 64 * 1024 * 1024;
371 } else { /* I830 */
372 unsigned int gcc1;
373
374 gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 2);
375 if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64)
376 return 64 * 1024 * 1024;
377 else
378 return 128 * 1024 * 1024;
379 }
380}
381
382static int
383agp_i810_set_aperture(device_t dev, u_int32_t aperture)
384{
385 struct agp_i810_softc *sc = device_get_softc(dev);
386 u_int16_t miscc;
387
388 if ( sc->chiptype == CHIP_I810 ) {
389 /*
390 * Double check for sanity.
391 */
392 if (aperture != 32 * 1024 * 1024 && aperture != 64 * 1024 * 1024) {
393 device_printf(dev, "bad aperture size %d\n", aperture);
394 return EINVAL;
395 }
396
397 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
398 miscc &= ~AGP_I810_MISCC_WINSIZE;
399 if (aperture == 32 * 1024 * 1024)
400 miscc |= AGP_I810_MISCC_WINSIZE_32;
401 else
402 miscc |= AGP_I810_MISCC_WINSIZE_64;
403
404 pci_write_config(sc->bdev, AGP_I810_MISCC, miscc, 2);
405 } else { /* I830 */
406 unsigned int gcc1;
407
408 if (aperture != 64 * 1024 * 1024 && aperture != 128 * 1024 * 1024) {
409 device_printf(dev, "bad aperture size %d\n", aperture);
410 return EINVAL;
411 }
412 gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 2);
413 gcc1 &= ~AGP_I830_GCC1_GMASIZE;
414 if (aperture == 64 * 1024 * 1024)
415 gcc1 |= AGP_I830_GCC1_GMASIZE_64;
416 else
417 gcc1 |= AGP_I830_GCC1_GMASIZE_128;
418
419 pci_write_config(sc->bdev, AGP_I830_GCC1, gcc1, 2);
420 }
421
422 return 0;
423}
424
425static int
426agp_i810_bind_page(device_t dev, int offset, vm_offset_t physical)
427{
428 struct agp_i810_softc *sc = device_get_softc(dev);
429
430 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) {
431 device_printf(dev, "failed: offset is 0x%08x, shift is %d, entries is %d\n", offset, AGP_PAGE_SHIFT, sc->gatt->ag_entries);
432 return EINVAL;
433 }
434
435 if ( sc->chiptype == CHIP_I830 ) {
436 if ( (offset >> AGP_PAGE_SHIFT) < sc->stolen ) {
437 device_printf(dev, "trying to bind into stolen memory");
438 return EINVAL;
439 }
440 }
441
442 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, physical | 1);
443 return 0;
444}
445
446static int
447agp_i810_unbind_page(device_t dev, int offset)
448{
449 struct agp_i810_softc *sc = device_get_softc(dev);
450
451 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
452 return EINVAL;
453
454 if ( sc->chiptype == CHIP_I830 ) {
455 if ( (offset >> AGP_PAGE_SHIFT) < sc->stolen ) {
456 device_printf(dev, "trying to unbind from stolen memory");
457 return EINVAL;
458 }
459 }
460
461 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 0);
462 return 0;
463}
464
465/*
466 * Writing via memory mapped registers already flushes all TLBs.
467 */
468static void
469agp_i810_flush_tlb(device_t dev)
470{
471}
472
473static int
474agp_i810_enable(device_t dev, u_int32_t mode)
475{
476
477 return 0;
478}
479
480static struct agp_memory *
481agp_i810_alloc_memory(device_t dev, int type, vm_size_t size)
482{
483 struct agp_i810_softc *sc = device_get_softc(dev);
484 struct agp_memory *mem;
485
486 if ((size & (AGP_PAGE_SIZE - 1)) != 0)
487 return 0;
488
489 if (sc->agp.as_allocated + size > sc->agp.as_maxmem)
490 return 0;
491
492 if (type == 1) {
493 /*
494 * Mapping local DRAM into GATT.
495 */
496 if ( sc->chiptype == CHIP_I830 )
497 return 0;
498 if (size != sc->dcache_size)
499 return 0;
500 } else if (type == 2) {
501 /*
502 * Bogus mapping of a single page for the hardware cursor.
503 */
504 if (size != AGP_PAGE_SIZE)
505 return 0;
506 }
507
97fe41b7 508 mem = malloc(sizeof *mem, M_AGP, M_INTWAIT);
984263bc
MD
509 mem->am_id = sc->agp.as_nextid++;
510 mem->am_size = size;
511 mem->am_type = type;
512 if (type != 1)
513 mem->am_obj = vm_object_allocate(OBJT_DEFAULT,
514 atop(round_page(size)));
515 else
516 mem->am_obj = 0;
517
518 if (type == 2) {
519 /*
520 * Allocate and wire down the page now so that we can
521 * get its physical address.
522 */
523 vm_page_t m;
dc1fd4b3
MD
524 m = vm_page_grab(mem->am_obj, 0,
525 VM_ALLOC_NORMAL|VM_ALLOC_ZERO|VM_ALLOC_RETRY);
984263bc
MD
526 if ((m->flags & PG_ZERO) == 0)
527 vm_page_zero_fill(m);
528 vm_page_wire(m);
529 mem->am_physical = VM_PAGE_TO_PHYS(m);
530 vm_page_wakeup(m);
531 } else {
532 mem->am_physical = 0;
533 }
534
535 mem->am_offset = 0;
536 mem->am_is_bound = 0;
537 TAILQ_INSERT_TAIL(&sc->agp.as_memory, mem, am_link);
538 sc->agp.as_allocated += size;
539
540 return mem;
541}
542
543static int
544agp_i810_free_memory(device_t dev, struct agp_memory *mem)
545{
546 struct agp_i810_softc *sc = device_get_softc(dev);
547
548 if (mem->am_is_bound)
549 return EBUSY;
550
551 if (mem->am_type == 2) {
552 /*
553 * Unwire the page which we wired in alloc_memory.
554 */
555 vm_page_t m = vm_page_lookup(mem->am_obj, 0);
556 vm_page_unwire(m, 0);
557 }
558
559 sc->agp.as_allocated -= mem->am_size;
560 TAILQ_REMOVE(&sc->agp.as_memory, mem, am_link);
561 if (mem->am_obj)
562 vm_object_deallocate(mem->am_obj);
563 free(mem, M_AGP);
564 return 0;
565}
566
567static int
568agp_i810_bind_memory(device_t dev, struct agp_memory *mem,
569 vm_offset_t offset)
570{
571 struct agp_i810_softc *sc = device_get_softc(dev);
572 vm_offset_t i;
573
574 if (mem->am_type != 1)
575 return agp_generic_bind_memory(dev, mem, offset);
576
577 if ( sc->chiptype == CHIP_I830 )
578 return EINVAL;
579
580 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) {
581 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4,
582 i | 3);
583 }
584
585 return 0;
586}
587
588static int
589agp_i810_unbind_memory(device_t dev, struct agp_memory *mem)
590{
591 struct agp_i810_softc *sc = device_get_softc(dev);
592 vm_offset_t i;
593
594 if (mem->am_type != 1)
595 return agp_generic_unbind_memory(dev, mem);
596
597 if ( sc->chiptype == CHIP_I830 )
598 return EINVAL;
599
600 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
601 WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0);
602
603 return 0;
604}
605
606static device_method_t agp_i810_methods[] = {
607 /* Device interface */
608 DEVMETHOD(device_probe, agp_i810_probe),
609 DEVMETHOD(device_attach, agp_i810_attach),
610 DEVMETHOD(device_detach, agp_i810_detach),
611 DEVMETHOD(device_shutdown, bus_generic_shutdown),
612 DEVMETHOD(device_suspend, bus_generic_suspend),
613 DEVMETHOD(device_resume, bus_generic_resume),
614
615 /* AGP interface */
616 DEVMETHOD(agp_get_aperture, agp_i810_get_aperture),
617 DEVMETHOD(agp_set_aperture, agp_i810_set_aperture),
618 DEVMETHOD(agp_bind_page, agp_i810_bind_page),
619 DEVMETHOD(agp_unbind_page, agp_i810_unbind_page),
620 DEVMETHOD(agp_flush_tlb, agp_i810_flush_tlb),
621 DEVMETHOD(agp_enable, agp_i810_enable),
622 DEVMETHOD(agp_alloc_memory, agp_i810_alloc_memory),
623 DEVMETHOD(agp_free_memory, agp_i810_free_memory),
624 DEVMETHOD(agp_bind_memory, agp_i810_bind_memory),
625 DEVMETHOD(agp_unbind_memory, agp_i810_unbind_memory),
626
627 { 0, 0 }
628};
629
630static driver_t agp_i810_driver = {
631 "agp",
632 agp_i810_methods,
633 sizeof(struct agp_i810_softc),
634};
635
636static devclass_t agp_devclass;
637
638DRIVER_MODULE(agp_i810, pci, agp_i810_driver, agp_devclass, 0, 0);
f7841f3c
MD
639MODULE_DEPEND(agp_i810, agp, 1, 1, 1);
640MODULE_DEPEND(agp_i810, pci, 1, 1, 1);