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
+				

Reply via email to