Module Name: src Committed By: macallan Date: Wed Sep 5 01:48:39 UTC 2012
Modified Files: src/sys/dev/pci: pm2fb.c Log Message: some preparations for mode setting support and such: - DDC2 support, so far only used for WSDISPLAYIO_GET_EDID - fix 8 bit support, use packed mode for some extra speed - pm2 and pm2v have different DACs, deal with it where appropriate To generate a diff of this commit: cvs rdiff -u -r1.14 -r1.15 src/sys/dev/pci/pm2fb.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/pm2fb.c diff -u src/sys/dev/pci/pm2fb.c:1.14 src/sys/dev/pci/pm2fb.c:1.15 --- src/sys/dev/pci/pm2fb.c:1.14 Wed May 23 18:39:30 2012 +++ src/sys/dev/pci/pm2fb.c Wed Sep 5 01:48:39 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: pm2fb.c,v 1.14 2012/05/23 18:39:30 macallan Exp $ */ +/* $NetBSD: pm2fb.c,v 1.15 2012/09/05 01:48:39 macallan Exp $ */ /* * Copyright (c) 2009 Michael Lorenz @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pm2fb.c,v 1.14 2012/05/23 18:39:30 macallan Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pm2fb.c,v 1.15 2012/09/05 01:48:39 macallan Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -40,6 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: pm2fb.c,v 1. #include <sys/malloc.h> #include <sys/lwp.h> #include <sys/kauth.h> +#include <sys/atomic.h> #include <dev/videomode/videomode.h> @@ -97,9 +98,12 @@ struct pm2fb_softc { u_char sc_cmap_blue[256]; /* engine stuff */ uint32_t sc_pprod; + int sc_is_pm2; /* i2c stuff */ struct i2c_controller sc_i2c; uint8_t sc_edid_data[128]; + struct edid_info sc_ei; + struct videomode *sc_videomode; }; static int pm2fb_match(device_t, cfdata_t, void *); @@ -174,6 +178,13 @@ static const struct i2c_bitbang_ops pm2f } }; +#if 0 +/* mode setting stuff */ +static int pm2fb_set_pll(struct pm2fb_softc *, int); +static uint8_t pm2fb_read_dac(struct pm2fb_softc *, int); +static void pm2fb_write_dac(struct pm2fb_softc *, int, uint8_t); +#endif + static inline void pm2fb_wait(struct pm2fb_softc *sc, int slots) { @@ -236,7 +247,7 @@ pm2fb_attach(device_t parent, device_t s sc->sc_memt = pa->pa_memt; sc->sc_iot = pa->pa_iot; sc->sc_dev = self; - + sc->sc_is_pm2 = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_PERMEDIA2); pci_aprint_devinfo(pa, NULL); /* fill in parameters from properties */ @@ -257,6 +268,10 @@ pm2fb_attach(device_t parent, device_t s * don't look at the linebytes property - The Raptor firmware lies * about it. Get it from width * depth >> 3 instead. */ + +#if 0 + sc->sc_depth = 8; +#endif sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3); prop_dictionary_get_bool(dict, "is_console", &is_console); @@ -296,6 +311,11 @@ pm2fb_attach(device_t parent, device_t s &pm2fb_accessops); sc->vd.init_screen = pm2fb_init_screen; +#if 0 + pm2fb_write_dac(sc, PM2V_DAC_PIXEL_SIZE, PM2V_PS_8BIT); + pm2fb_write_dac(sc, PM2V_DAC_COLOR_FORMAT, PM2V_DAC_PALETTE); +#endif + /* init engine here */ pm2fb_init(sc); @@ -328,8 +348,7 @@ pm2fb_attach(device_t parent, device_t s } else { if (sc->sc_console_screen.scr_ri.ri_rows == 0) { /* do some minimal setup to avoid weirdnesses later */ - vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, - &defattr); + vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr); } } @@ -575,6 +594,44 @@ pm2fb_putpalreg(struct pm2fb_softc *sc, return 0; } +#if 0 +static uint8_t +pm2fb_read_dac(struct pm2fb_softc *sc, int reg) +{ + if (sc->sc_is_pm2) { + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2_DAC_PAL_WRITE_IDX, reg); + return bus_space_read_1(sc->sc_memt, sc->sc_regh, + PM2_DAC_INDEX_DATA); + } else { + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2V_DAC_INDEX_LOW, reg & 0xff); + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff); + return bus_space_read_1(sc->sc_memt, sc->sc_regh, + PM2V_DAC_INDEX_DATA); + } +} + +static void +pm2fb_write_dac(struct pm2fb_softc *sc, int reg, uint8_t data) +{ + if (sc->sc_is_pm2) { + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2_DAC_PAL_WRITE_IDX, reg); + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2_DAC_INDEX_DATA, data); + } else { + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2V_DAC_INDEX_LOW, reg & 0xff); + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff); + bus_space_write_1(sc->sc_memt, sc->sc_regh, + PM2V_DAC_INDEX_DATA, data); + } +} +#endif + static void pm2fb_init(struct pm2fb_softc *sc) { @@ -621,7 +678,7 @@ pm2fb_init(struct pm2fb_softc *sc) sc->sc_pprod); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEXMAP_FORMAT, sc->sc_pprod); - pm2fb_wait(sc, 8); + pm2fb_wait(sc, 9); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DY, 1 << 16); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DXDOM, 0); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTXDOM, 0); @@ -631,7 +688,22 @@ pm2fb_init(struct pm2fb_softc *sc) bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MINYX, 0); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MAXYX, 0x0fff0fff); + switch(sc->sc_depth) { + case 8: + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_PIXEL_SIZE, PM2PS_8BIT); + break; + case 16: + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_PIXEL_SIZE, PM2PS_16BIT); + break; + case 32: + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_PIXEL_SIZE, PM2PS_32BIT); + break; + } pm2fb_flush_engine(sc); + DPRINTF("pixel size: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_RE_PIXEL_SIZE)); } static void @@ -659,6 +731,7 @@ pm2fb_bitblt(struct pm2fb_softc *sc, int int wi, int he, int rop) { uint32_t dir = 0; + int rxs, rxd, rwi; if (yd <= ys) { dir |= PM2RE_INC_Y; @@ -666,24 +739,60 @@ pm2fb_bitblt(struct pm2fb_softc *sc, int if (xd <= xs) { dir |= PM2RE_INC_X; } - pm2fb_wait(sc, 7); + pm2fb_wait(sc, 8); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0); - if (rop == 3) { - bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG, - PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN | PM2RECFG_ROP_EN | - PM2RECFG_PACKED | (rop << 6)); + if (sc->sc_depth == 8) { + /* + * use packed mode for some extra speed + * this copies 32bit quantities even in 8 bit mode, so we need + * to adjust for cases where the lower two bits in source and + * destination X don't align, and/or where the width isn't a + * multiple of 4 + */ + if (rop == 3) { + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_CONFIG, + PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN | + PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6)); + } else { + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_CONFIG, + PM2RECFG_READ_SRC | PM2RECFG_READ_DST | + PM2RECFG_WRITE_EN | PM2RECFG_PACKED | + PM2RECFG_ROP_EN | (rop << 6)); + } + rxs = xs >> 2; + rxd = xd >> 2; + rwi = wi >> 2; + /* adjust for non-aligned x */ + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_PACKEDDATA_LIMIT, + (xd << 16) | (xd + wi) | (((xd - xs) & 3) << 29)); } else { - bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG, - PM2RECFG_READ_SRC | PM2RECFG_READ_DST | PM2RECFG_WRITE_EN | - PM2RECFG_PACKED | PM2RECFG_ROP_EN | (rop << 6)); - } + /* we're in 16 or 32bit mode */ + if (rop == 3) { + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_CONFIG, + PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN | + PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6)); + } else { + bus_space_write_4(sc->sc_memt, sc->sc_regh, + PM2_RE_CONFIG, + PM2RECFG_READ_SRC | PM2RECFG_READ_DST | + PM2RECFG_WRITE_EN | PM2RECFG_PACKED | + PM2RECFG_ROP_EN | (rop << 6)); + } + rxs = xs; + rxd = xd; + rwi = wi; + } bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_START, - (yd << 16) | xd); + (yd << 16) | rxd); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_SIZE, - (he << 16) | wi); + (he << 16) | rwi); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SOURCE_DELTA, - (((ys - yd) & 0xfff) << 16) | ((xs - xd) & 0xfff)); + (((ys - yd) & 0xfff) << 16) | ((rxs - rxd) & 0xfff)); bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RENDER, PM2RE_RECTANGLE | dir); } @@ -890,13 +999,14 @@ pm2fb_eraserows(void *cookie, int row, i } } +#define MODE_IS_VALID(m) (((m)->hdisplay < 2048) && ((m)->dot_clock < 230000)) static void pm2_setup_i2c(struct pm2fb_softc *sc) { + int i; #ifdef PM2FB_DEBUG - struct edid_info ei; + int j; #endif - int i; /* Fill in the i2c tag */ sc->sc_i2c.ic_cookie = sc; @@ -912,7 +1022,6 @@ pm2_setup_i2c(struct pm2fb_softc *sc) DPRINTF("data: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA)); - /* make sure we're in i2c mode */ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA, 0); /* zero out the EDID buffer */ @@ -920,11 +1029,67 @@ pm2_setup_i2c(struct pm2fb_softc *sc) /* Some monitors don't respond first time */ i = 0; - while (sc->sc_edid_data[1] == 0 && i++ < 3) + while (sc->sc_edid_data[1] == 0 && i < 10) { ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128); + printf("\n"); + i++; + } #ifdef PM2FB_DEBUG - if (edid_parse(&sc->sc_edid_data[0], &ei) != -1) { - edid_print(&ei); + printf("i = %d\n", i); + for (i = 0; i < 128; i += 16) { + printf("%02x:", i); + for (j = 0; j < 16; j++) + printf(" %02x", sc->sc_edid_data[i + j]); + printf("\n"); + } +#endif +#if 0 + if (edid_parse(&sc->sc_edid_data[0], &sc->sc_ei) != -1) { +#ifdef PM2FB_DEBUG + edid_print(&sc->sc_ei); +#endif + + /* + * Now pick a mode. + */ + if ((sc->sc_ei.edid_preferred_mode != NULL)) { + struct videomode *m = sc->sc_ei.edid_preferred_mode; + if (MODE_IS_VALID(m)) { + sc->sc_videomode = m; + } else { + aprint_error_dev(sc->sc_dev, + "unable to use preferred mode\n"); + } + } + /* + * if we can't use the preferred mode go look for the + * best one we can support + */ + if (sc->sc_videomode == NULL) { + int n; + struct videomode *m = sc->sc_ei.edid_modes; + + sort_modes(sc->sc_ei.edid_modes, + &sc->sc_ei.edid_preferred_mode, + sc->sc_ei.edid_nmodes); + while ((sc->sc_videomode == NULL) && + (n < sc->sc_ei.edid_nmodes)) { + if (MODE_IS_VALID(&m[n])) { + sc->sc_videomode = &m[n]; + } + n++; + } + } + } + if (sc->sc_videomode != NULL) { + pm2fb_set_pll(sc, sc->sc_videomode->dot_clock); + if (sc->sc_is_pm2) { + printf("DAC: %02x\n", + pm2fb_read_dac(sc, PM2_DAC_COLOR_MODE)); + } else + printf("DAC: %02x\n", + pm2fb_read_dac(sc, PM2V_DAC_COLOR_FORMAT)); + if (0) pm2fb_write_dac(sc, PM2_DAC_COLOR_MODE, CM_PALETTE); } #endif } @@ -938,6 +1103,7 @@ static void pm2fb_i2cbb_set_bits(void *c out = bits << 2; /* bitmasks match the IN bits */ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA, out); + delay(100); } static void pm2fb_i2cbb_set_dir(void *cookie, uint32_t dir) @@ -951,7 +1117,6 @@ static uint32_t pm2fb_i2cbb_read(void *c uint32_t bits; bits = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA); - return bits; } @@ -1001,3 +1166,39 @@ pm2fb_i2c_write_byte(void *cookie, uint8 { return (i2c_bitbang_write_byte(cookie, val, flags, &pm2fb_i2cbb_ops)); } + +#if 0 + +#define RefClk 14318 /* all frequencies are in kHz */ +static int +pm2fb_set_pll(struct pm2fb_softc *sc, int freq) +{ + int m, n, p, diff, out_freq, bm, bn, bp, bdiff = 1000000, bfreq; + int fi; + + /* + * this should work on both PM2 and PM2V + */ + for (m = 0; m < 256; m++) { + for (n = 2; n < 14; n++) { + fi = RefClk * m / n; + if ((fi < 110000) || (fi > 250000)) + continue; + for (p = 0; p < 4; p++) { + out_freq = fi >> p; + diff = abs(out_freq - freq); + if (diff < bdiff) { + bdiff = diff; + bfreq = out_freq; + bm = m; + bn = n; + bp = p; + } + } + } + } + printf("best: %d kHz ( %d off ), %d %d %d\n", bfreq, bdiff, bm, bn, bp); + return 0; +} +#endif +