| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: voodoofb.c,v 1.32 2012/01/17 21:31:46 macallan Exp $ */ | | 1 | /* $NetBSD: voodoofb.c,v 1.33 2012/01/18 08:04:18 macallan Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2005, 2006 Michael Lorenz | | 4 | * Copyright (c) 2005, 2006 Michael Lorenz |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -22,27 +22,27 @@ | | | @@ -22,27 +22,27 @@ |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | /* | | 28 | /* |
29 | * A console driver for 3Dfx Voodoo3 graphics boards | | 29 | * A console driver for 3Dfx Voodoo3 graphics boards |
30 | * Thanks to Andreas Drewke (andreas_dr@gmx.de) for his Voodoo3 driver for BeOS | | 30 | * Thanks to Andreas Drewke (andreas_dr@gmx.de) for his Voodoo3 driver for BeOS |
31 | * which I used as reference / documentation | | 31 | * which I used as reference / documentation |
32 | */ | | 32 | */ |
33 | | | 33 | |
34 | #include <sys/cdefs.h> | | 34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: voodoofb.c,v 1.32 2012/01/17 21:31:46 macallan Exp $"); | | 35 | __KERNEL_RCSID(0, "$NetBSD: voodoofb.c,v 1.33 2012/01/18 08:04:18 macallan Exp $"); |
36 | | | 36 | |
37 | #include <sys/param.h> | | 37 | #include <sys/param.h> |
38 | #include <sys/systm.h> | | 38 | #include <sys/systm.h> |
39 | #include <sys/kernel.h> | | 39 | #include <sys/kernel.h> |
40 | #include <sys/device.h> | | 40 | #include <sys/device.h> |
41 | #include <sys/malloc.h> | | 41 | #include <sys/malloc.h> |
42 | #include <sys/callout.h> | | 42 | #include <sys/callout.h> |
43 | #include <sys/kauth.h> | | 43 | #include <sys/kauth.h> |
44 | | | 44 | |
45 | #include <dev/pci/pcivar.h> | | 45 | #include <dev/pci/pcivar.h> |
46 | #include <dev/pci/pcireg.h> | | 46 | #include <dev/pci/pcireg.h> |
47 | #include <dev/pci/pcidevs.h> | | 47 | #include <dev/pci/pcidevs.h> |
48 | #include <dev/pci/pciio.h> | | 48 | #include <dev/pci/pciio.h> |
| @@ -966,28 +966,29 @@ voodoofb_ioctl(void *v, void *vs, u_long | | | @@ -966,28 +966,29 @@ voodoofb_ioctl(void *v, void *vs, u_long |
966 | if (new_mode == WSDISPLAYIO_MODE_EMUL) { | | 966 | if (new_mode == WSDISPLAYIO_MODE_EMUL) { |
967 | voodoofb_drm_map(sc); | | 967 | voodoofb_drm_map(sc); |
968 | int i; | | 968 | int i; |
969 | | | 969 | |
970 | /* restore the palette */ | | 970 | /* restore the palette */ |
971 | for (i = 0; i < 256; i++) { | | 971 | for (i = 0; i < 256; i++) { |
972 | voodoofb_putpalreg(sc, | | 972 | voodoofb_putpalreg(sc, |
973 | i, | | 973 | i, |
974 | sc->sc_cmap_red[i], | | 974 | sc->sc_cmap_red[i], |
975 | sc->sc_cmap_green[i], | | 975 | sc->sc_cmap_green[i], |
976 | sc->sc_cmap_blue[i]); | | 976 | sc->sc_cmap_blue[i]); |
977 | } | | 977 | } |
978 | vcons_redraw_screen(ms); | | 978 | vcons_redraw_screen(ms); |
979 | } else | | 979 | } else { |
980 | voodoofb_drm_unmap(sc); | | 980 | voodoofb_drm_unmap(sc); |
| | | 981 | } |
981 | } | | 982 | } |
982 | } | | 983 | } |
983 | return 0; | | 984 | return 0; |
984 | } | | 985 | } |
985 | return EPASSTHROUGH; | | 986 | return EPASSTHROUGH; |
986 | } | | 987 | } |
987 | | | 988 | |
988 | static paddr_t | | 989 | static paddr_t |
989 | voodoofb_mmap(void *v, void *vs, off_t offset, int prot) | | 990 | voodoofb_mmap(void *v, void *vs, off_t offset, int prot) |
990 | { | | 991 | { |
991 | struct vcons_data *vd = v; | | 992 | struct vcons_data *vd = v; |
992 | struct voodoofb_softc *sc = vd->cookie; | | 993 | struct voodoofb_softc *sc = vd->cookie; |
993 | paddr_t pa; | | 994 | paddr_t pa; |
| @@ -1175,31 +1176,41 @@ voodoofb_setup_monitor(struct voodoofb_s | | | @@ -1175,31 +1176,41 @@ voodoofb_setup_monitor(struct voodoofb_s |
1175 | horizontal_sync_start = (vm->hsync_start >> 3) - 1; | | 1176 | horizontal_sync_start = (vm->hsync_start >> 3) - 1; |
1176 | horizontal_sync_end = (vm->hsync_end >> 3) - 1; | | 1177 | horizontal_sync_end = (vm->hsync_end >> 3) - 1; |
1177 | horizontal_total = (vm->htotal >> 3) - 1; | | 1178 | horizontal_total = (vm->htotal >> 3) - 1; |
1178 | horizontal_blanking_start = horizontal_display_end; | | 1179 | horizontal_blanking_start = horizontal_display_end; |
1179 | horizontal_blanking_end = horizontal_total; | | 1180 | horizontal_blanking_end = horizontal_total; |
1180 | | | 1181 | |
1181 | vertical_display_enable_end = vm->vdisplay - 1; | | 1182 | vertical_display_enable_end = vm->vdisplay - 1; |
1182 | vertical_sync_start = vm->vsync_start; // - 1; | | 1183 | vertical_sync_start = vm->vsync_start; // - 1; |
1183 | vertical_sync_end = vm->vsync_end; // - 1; | | 1184 | vertical_sync_end = vm->vsync_end; // - 1; |
1184 | vertical_total = vm->vtotal - 2; | | 1185 | vertical_total = vm->vtotal - 2; |
1185 | vertical_blanking_start = vertical_display_enable_end; | | 1186 | vertical_blanking_start = vertical_display_enable_end; |
1186 | vertical_blanking_end = vertical_total; | | 1187 | vertical_blanking_end = vertical_total; |
1187 | | | 1188 | |
| | | 1189 | #if 0 |
1188 | misc = 0x0f | | | 1190 | misc = 0x0f | |
1189 | (vm->hdisplay < 400 ? 0xa0 : | | 1191 | (vm->hdisplay < 400 ? 0xa0 : |
1190 | vm->hdisplay < 480 ? 0x60 : | | 1192 | vm->hdisplay < 480 ? 0x60 : |
1191 | vm->hdisplay < 768 ? 0xe0 : 0x20); | | 1193 | vm->hdisplay < 768 ? 0xe0 : 0x20); |
1192 | | | 1194 | #else |
| | | 1195 | misc = 0x2f; |
| | | 1196 | if (vm->flags & VID_NHSYNC) |
| | | 1197 | misc |= HSYNC_NEG; |
| | | 1198 | if (vm->flags & VID_NVSYNC) |
| | | 1199 | misc |= VSYNC_NEG; |
| | | 1200 | #ifdef VOODOOFB_DEBUG |
| | | 1201 | printf("misc: %02x\n", misc); |
| | | 1202 | #endif |
| | | 1203 | #endif |
1193 | mode->vr_seq[0] = 3; | | 1204 | mode->vr_seq[0] = 3; |
1194 | mode->vr_seq[1] = 1; | | 1205 | mode->vr_seq[1] = 1; |
1195 | mode->vr_seq[2] = 8; | | 1206 | mode->vr_seq[2] = 8; |
1196 | mode->vr_seq[3] = 0; | | 1207 | mode->vr_seq[3] = 0; |
1197 | mode->vr_seq[4] = 6; | | 1208 | mode->vr_seq[4] = 6; |
1198 | | | 1209 | |
1199 | /* crtc regs start */ | | 1210 | /* crtc regs start */ |
1200 | mode->vr_crtc[0] = horizontal_total - 4; | | 1211 | mode->vr_crtc[0] = horizontal_total - 4; |
1201 | mode->vr_crtc[1] = horizontal_display_end; | | 1212 | mode->vr_crtc[1] = horizontal_display_end; |
1202 | mode->vr_crtc[2] = horizontal_blanking_start; | | 1213 | mode->vr_crtc[2] = horizontal_blanking_start; |
1203 | mode->vr_crtc[3] = 0x80 | (horizontal_blanking_end & 0x1f); | | 1214 | mode->vr_crtc[3] = 0x80 | (horizontal_blanking_end & 0x1f); |
1204 | mode->vr_crtc[4] = horizontal_sync_start; | | 1215 | mode->vr_crtc[4] = horizontal_sync_start; |
1205 | | | 1216 | |
| @@ -1237,27 +1248,27 @@ voodoofb_setup_monitor(struct voodoofb_s | | | @@ -1237,27 +1248,27 @@ voodoofb_setup_monitor(struct voodoofb_s |
1237 | mode->vr_crtc[24] = 255; | | 1248 | mode->vr_crtc[24] = 255; |
1238 | | | 1249 | |
1239 | /* overflow registers */ | | 1250 | /* overflow registers */ |
1240 | mode->vr_crtc[CRTC_HDISP_EXT] = | | 1251 | mode->vr_crtc[CRTC_HDISP_EXT] = |
1241 | (horizontal_total&0x100) >> 8 | | | 1252 | (horizontal_total&0x100) >> 8 | |
1242 | (horizontal_display_end & 0x100) >> 6 | | | 1253 | (horizontal_display_end & 0x100) >> 6 | |
1243 | (horizontal_blanking_start & 0x100) >> 4 | | | 1254 | (horizontal_blanking_start & 0x100) >> 4 | |
1244 | (horizontal_blanking_end & 0x40) >> 1 | | | 1255 | (horizontal_blanking_end & 0x40) >> 1 | |
1245 | (horizontal_sync_start & 0x100) >> 2 | | | 1256 | (horizontal_sync_start & 0x100) >> 2 | |
1246 | (horizontal_sync_end & 0x20) << 2; | | 1257 | (horizontal_sync_end & 0x20) << 2; |
1247 | | | 1258 | |
1248 | mode->vr_crtc[CRTC_VDISP_EXT] = | | 1259 | mode->vr_crtc[CRTC_VDISP_EXT] = |
1249 | (vertical_total & 0x400) >> 10 | | | 1260 | (vertical_total & 0x400) >> 10 | |
1250 | (vertical_display_enable_end & 0x400) >> 8 | | | 1261 | (vertical_display_enable_end & 0x400) >> 8 | /* the manual is contradictory here */ |
1251 | (vertical_blanking_start & 0x400) >> 6 | | | 1262 | (vertical_blanking_start & 0x400) >> 6 | |
1252 | (vertical_blanking_end & 0x400) >> 4; | | 1263 | (vertical_blanking_end & 0x400) >> 4; |
1253 | | | 1264 | |
1254 | /* attr regs start */ | | 1265 | /* attr regs start */ |
1255 | mode->vr_attr[0] = 0; | | 1266 | mode->vr_attr[0] = 0; |
1256 | mode->vr_attr[1] = 0; | | 1267 | mode->vr_attr[1] = 0; |
1257 | mode->vr_attr[2] = 0; | | 1268 | mode->vr_attr[2] = 0; |
1258 | mode->vr_attr[3] = 0; | | 1269 | mode->vr_attr[3] = 0; |
1259 | mode->vr_attr[4] = 0; | | 1270 | mode->vr_attr[4] = 0; |
1260 | mode->vr_attr[5] = 0; | | 1271 | mode->vr_attr[5] = 0; |
1261 | mode->vr_attr[6] = 0; | | 1272 | mode->vr_attr[6] = 0; |
1262 | mode->vr_attr[7] = 0; | | 1273 | mode->vr_attr[7] = 0; |
1263 | mode->vr_attr[8] = 0; | | 1274 | mode->vr_attr[8] = 0; |
| @@ -1428,26 +1439,36 @@ voodoofb_init(struct voodoofb_softc *sc) | | | @@ -1428,26 +1439,36 @@ voodoofb_init(struct voodoofb_softc *sc) |
1428 | voodoo3_make_room(sc, 8); | | 1439 | voodoo3_make_room(sc, 8); |
1429 | voodoo3_write32(sc, SRCBASE, 0); | | 1440 | voodoo3_write32(sc, SRCBASE, 0); |
1430 | voodoo3_write32(sc, DSTBASE, 0); | | 1441 | voodoo3_write32(sc, DSTBASE, 0); |
1431 | voodoo3_write32(sc, COMMANDEXTRA_2D, 0); | | 1442 | voodoo3_write32(sc, COMMANDEXTRA_2D, 0); |
1432 | voodoo3_write32(sc, CLIP0MIN, 0); | | 1443 | voodoo3_write32(sc, CLIP0MIN, 0); |
1433 | voodoo3_write32(sc, CLIP0MAX, 0x1fff1fff); | | 1444 | voodoo3_write32(sc, CLIP0MAX, 0x1fff1fff); |
1434 | voodoo3_write32(sc, CLIP1MIN, 0); | | 1445 | voodoo3_write32(sc, CLIP1MIN, 0); |
1435 | voodoo3_write32(sc, CLIP1MAX, 0x1fff1fff); | | 1446 | voodoo3_write32(sc, CLIP1MAX, 0x1fff1fff); |
1436 | voodoo3_write32(sc, SRCXY, 0); | | 1447 | voodoo3_write32(sc, SRCXY, 0); |
1437 | | | 1448 | |
1438 | voodoofb_wait_idle(sc); | | 1449 | voodoofb_wait_idle(sc); |
1439 | } | | 1450 | } |
1440 | | | 1451 | |
| | | 1452 | #define MAX_CLOCK 250000 /* all Voodoo3 should support that */ |
| | | 1453 | #define MAX_HRES 1700 /* |
| | | 1454 | * XXX in theory we can go higher but I |
| | | 1455 | * couldn't get anything above 1680 x 1200 |
| | | 1456 | * to work, so until I find out why it's |
| | | 1457 | * disabled so people won't end up with a |
| | | 1458 | * blank screen |
| | | 1459 | */ |
| | | 1460 | #define MODE_IS_VALID(m) (((m)->dot_clock <= MAX_CLOCK) && \ |
| | | 1461 | ((m)->hdisplay < MAX_HRES)) |
1441 | static void | | 1462 | static void |
1442 | voodoofb_setup_i2c(struct voodoofb_softc *sc) | | 1463 | voodoofb_setup_i2c(struct voodoofb_softc *sc) |
1443 | { | | 1464 | { |
1444 | int i; | | 1465 | int i; |
1445 | | | 1466 | |
1446 | /* Fill in the i2c tag */ | | 1467 | /* Fill in the i2c tag */ |
1447 | sc->sc_i2c.ic_cookie = sc; | | 1468 | sc->sc_i2c.ic_cookie = sc; |
1448 | sc->sc_i2c.ic_acquire_bus = voodoofb_i2c_acquire_bus; | | 1469 | sc->sc_i2c.ic_acquire_bus = voodoofb_i2c_acquire_bus; |
1449 | sc->sc_i2c.ic_release_bus = voodoofb_i2c_release_bus; | | 1470 | sc->sc_i2c.ic_release_bus = voodoofb_i2c_release_bus; |
1450 | sc->sc_i2c.ic_send_start = voodoofb_i2c_send_start; | | 1471 | sc->sc_i2c.ic_send_start = voodoofb_i2c_send_start; |
1451 | sc->sc_i2c.ic_send_stop = voodoofb_i2c_send_stop; | | 1472 | sc->sc_i2c.ic_send_stop = voodoofb_i2c_send_stop; |
1452 | sc->sc_i2c.ic_initiate_xfer = voodoofb_i2c_initiate_xfer; | | 1473 | sc->sc_i2c.ic_initiate_xfer = voodoofb_i2c_initiate_xfer; |
1453 | sc->sc_i2c.ic_read_byte = voodoofb_i2c_read_byte; | | 1474 | sc->sc_i2c.ic_read_byte = voodoofb_i2c_read_byte; |
| @@ -1472,40 +1493,53 @@ voodoofb_setup_i2c(struct voodoofb_softc | | | @@ -1472,40 +1493,53 @@ voodoofb_setup_i2c(struct voodoofb_softc |
1472 | if (i < 3) { | | 1493 | if (i < 3) { |
1473 | if (edid_parse(sc->sc_edid_data, &sc->sc_edid_info) != -1) { | | 1494 | if (edid_parse(sc->sc_edid_data, &sc->sc_edid_info) != -1) { |
1474 | #ifdef VOODOOFB_DEBUG | | 1495 | #ifdef VOODOOFB_DEBUG |
1475 | edid_print(&sc->sc_edid_info); | | 1496 | edid_print(&sc->sc_edid_info); |
1476 | #endif | | 1497 | #endif |
1477 | /* | | 1498 | /* |
1478 | * Now pick a mode. | | 1499 | * Now pick a mode. |
1479 | * How do we know our max. pixel clock? | | 1500 | * How do we know our max. pixel clock? |
1480 | * All Voodoo3 should support at least 250MHz. | | 1501 | * All Voodoo3 should support at least 250MHz. |
1481 | * All Voodoo3 I've seen so far have at least 8MB | | 1502 | * All Voodoo3 I've seen so far have at least 8MB |
1482 | * which we're not going to exhaust either in 8bit. | | 1503 | * which we're not going to exhaust either in 8bit. |
1483 | */ | | 1504 | */ |
1484 | if ((sc->sc_edid_info.edid_preferred_mode != NULL)) { | | 1505 | if ((sc->sc_edid_info.edid_preferred_mode != NULL)) { |
1485 | sc->sc_videomode = | | 1506 | struct videomode *m = |
1486 | sc->sc_edid_info.edid_preferred_mode; | | 1507 | sc->sc_edid_info.edid_preferred_mode; |
1487 | } else { | | 1508 | if (MODE_IS_VALID(m)) { |
| | | 1509 | sc->sc_videomode = m; |
| | | 1510 | } else { |
| | | 1511 | aprint_error_dev(sc->sc_dev, |
| | | 1512 | "unable to use preferred mode\n"); |
| | | 1513 | } |
| | | 1514 | } |
| | | 1515 | /* |
| | | 1516 | * if we can't use the preferred mode go look for the |
| | | 1517 | * best one we can support |
| | | 1518 | */ |
| | | 1519 | if (sc->sc_videomode == NULL) { |
1488 | int n; | | 1520 | int n; |
1489 | struct videomode *m = sc->sc_edid_info.edid_modes; | | 1521 | struct videomode *m = |
| | | 1522 | sc->sc_edid_info.edid_modes; |
1490 | | | 1523 | |
1491 | sort_modes(sc->sc_edid_info.edid_modes, | | 1524 | sort_modes(sc->sc_edid_info.edid_modes, |
1492 | &sc->sc_edid_info.edid_preferred_mode, | | 1525 | &sc->sc_edid_info.edid_preferred_mode, |
1493 | sc->sc_edid_info.edid_nmodes); | | 1526 | sc->sc_edid_info.edid_nmodes); |
1494 | while ((sc->sc_videomode == NULL) && | | 1527 | while ((sc->sc_videomode == NULL) && |
1495 | (n < sc->sc_edid_info.edid_nmodes)) { | | 1528 | (n < sc->sc_edid_info.edid_nmodes)) { |
1496 | if (m[n].dot_clock <= 250000) { | | 1529 | if (MODE_IS_VALID(&m[n])) { |
1497 | sc->sc_videomode = &m[n]; | | 1530 | sc->sc_videomode = &m[n]; |
1498 | } | | 1531 | } |
| | | 1532 | n++; |
1499 | } | | 1533 | } |
1500 | } | | 1534 | } |
1501 | } | | 1535 | } |
1502 | } | | 1536 | } |
1503 | } | | 1537 | } |
1504 | | | 1538 | |
1505 | /* I2C bitbanging */ | | 1539 | /* I2C bitbanging */ |
1506 | static void voodoofb_i2cbb_set_bits(void *cookie, uint32_t bits) | | 1540 | static void voodoofb_i2cbb_set_bits(void *cookie, uint32_t bits) |
1507 | { | | 1541 | { |
1508 | struct voodoofb_softc *sc = cookie; | | 1542 | struct voodoofb_softc *sc = cookie; |
1509 | uint32_t out; | | 1543 | uint32_t out; |
1510 | | | 1544 | |
1511 | out = bits >> 2; /* bitmasks match the IN bits */ | | 1545 | out = bits >> 2; /* bitmasks match the IN bits */ |