Module Name: src
Committed By: macallan
Date: Thu Sep 13 02:09:00 UTC 2012
Modified Files:
src/sys/dev/pci: pm2fb.c
Log Message:
add mode setting support
While there, don't pretend to support the Permedia2 non-V - I don't have the
hardware and it has never been tested in the first place. The only hardware
this has been tested on is a TechSource Raptor GFX 8P / Sun PGX32 which
happens to be a Permedia2V with Sun firmware.
To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 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.17 src/sys/dev/pci/pm2fb.c:1.18
--- src/sys/dev/pci/pm2fb.c:1.17 Wed Sep 12 12:07:04 2012
+++ src/sys/dev/pci/pm2fb.c Thu Sep 13 02:09:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: pm2fb.c,v 1.17 2012/09/12 12:07:04 macallan Exp $ */
+/* $NetBSD: pm2fb.c,v 1.18 2012/09/13 02:09:00 macallan Exp $ */
/*
* Copyright (c) 2009 Michael Lorenz
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pm2fb.c,v 1.17 2012/09/12 12:07:04 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pm2fb.c,v 1.18 2012/09/13 02:09:00 macallan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -104,7 +104,7 @@ struct pm2fb_softc {
struct i2c_controller sc_i2c;
uint8_t sc_edid_data[128];
struct edid_info sc_ei;
- struct videomode *sc_videomode;
+ const struct videomode *sc_videomode;
glyphcache sc_gc;
};
@@ -180,12 +180,49 @@ 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 void pm2fb_set_mode(struct pm2fb_softc *, const struct videomode *);
+
+/* this table is from xf86-video-glint */
+#define PARTPROD(a,b,c) (((a)<<6) | ((b)<<3) | (c))
+int partprodPermedia[] = {
+ -1,
+ PARTPROD(0,0,1), PARTPROD(0,1,1), PARTPROD(1,1,1), PARTPROD(1,1,2),
+ PARTPROD(1,2,2), PARTPROD(2,2,2), PARTPROD(1,2,3), PARTPROD(2,2,3),
+ PARTPROD(1,3,3), PARTPROD(2,3,3), PARTPROD(1,2,4), PARTPROD(3,3,3),
+ PARTPROD(1,3,4), PARTPROD(2,3,4), -1, PARTPROD(3,3,4),
+ PARTPROD(1,4,4), PARTPROD(2,4,4), -1, PARTPROD(3,4,4),
+ -1, PARTPROD(2,3,5), -1, PARTPROD(4,4,4),
+ PARTPROD(1,4,5), PARTPROD(2,4,5), PARTPROD(3,4,5), -1,
+ -1, -1, -1, PARTPROD(4,4,5),
+ PARTPROD(1,5,5), PARTPROD(2,5,5), -1, PARTPROD(3,5,5),
+ -1, -1, -1, PARTPROD(4,5,5),
+ -1, -1, -1, PARTPROD(3,4,6),
+ -1, -1, -1, PARTPROD(5,5,5),
+ PARTPROD(1,5,6), PARTPROD(2,5,6), -1, PARTPROD(3,5,6),
+ -1, -1, -1, PARTPROD(4,5,6),
+ -1, -1, -1, -1,
+ -1, -1, -1, PARTPROD(5,5,6),
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ 0};
static inline void
pm2fb_wait(struct pm2fb_softc *sc, int slots)
@@ -225,10 +262,10 @@ pm2fb_match(device_t parent, cfdata_t ma
return 0;
/*
- * only card tested on so far is a TechSource Raptor GFX 8P
+ * only card tested on so far is a TechSource Raptor GFX 8P /
* Sun PGX32, which happens to be a Permedia 2v
*/
- if ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_PERMEDIA2) ||
+ if (/*(PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_PERMEDIA2) ||*/
(PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_PERMEDIA2V))
return 100;
return (0);
@@ -257,28 +294,31 @@ pm2fb_attach(device_t parent, device_t s
PCI_PRODUCT_3DLABS_PERMEDIA2);
pci_aprint_devinfo(pa, NULL);
- /* fill in parameters from properties */
+ /*
+ * fill in parameters from properties
+ * if we can't get a usable mode via DDC2 we'll use this to pick one,
+ * which is why we fill them in with some conservative values that
+ * hopefully work as a last resort
+ */
dict = device_properties(self);
if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) {
aprint_error("%s: no width property\n", device_xname(self));
- return;
+ sc->sc_width = 1024;
}
if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) {
aprint_error("%s: no height property\n", device_xname(self));
- return;
+ sc->sc_height = 768;
}
if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
aprint_error("%s: no depth property\n", device_xname(self));
- return;
+ sc->sc_depth = 8;
}
+
/*
* 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);
@@ -317,12 +357,7 @@ pm2fb_attach(device_t parent, device_t s
vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
&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);
@@ -353,11 +388,11 @@ pm2fb_attach(device_t parent, device_t s
sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
/* XXX use actual memory size instead of assuming 8MB */
glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
- (0x800000 / sc->sc_stride) - sc->sc_height - 5,
- sc->sc_width,
- ri->ri_font->fontwidth,
- ri->ri_font->fontheight,
- defattr);
+ (sc->sc_fbsize / sc->sc_stride) - sc->sc_height - 5,
+ sc->sc_width,
+ ri->ri_font->fontwidth,
+ ri->ri_font->fontheight,
+ defattr);
wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
defattr);
vcons_replay_msgbuf(&sc->sc_console_screen);
@@ -365,11 +400,11 @@ pm2fb_attach(device_t parent, device_t s
if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
/* do some minimal setup to avoid weirdnesses later */
glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
- (0x800000 / sc->sc_stride) - sc->sc_height - 5,
- sc->sc_width,
- ri->ri_font->fontwidth,
- ri->ri_font->fontheight,
- defattr);
+ (sc->sc_fbsize / sc->sc_stride) - sc->sc_height - 5,
+ sc->sc_width,
+ ri->ri_font->fontwidth,
+ ri->ri_font->fontheight,
+ defattr);
vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
&defattr);
}
@@ -653,7 +688,6 @@ pm2fb_putpalreg(struct pm2fb_softc *sc,
return 0;
}
-#if 0
static uint8_t
pm2fb_read_dac(struct pm2fb_softc *sc, int reg)
{
@@ -675,6 +709,7 @@ pm2fb_read_dac(struct pm2fb_softc *sc, i
static void
pm2fb_write_dac(struct pm2fb_softc *sc, int reg, uint8_t data)
{
+ pm2fb_wait(sc, 3);
if (sc->sc_is_pm2) {
bus_space_write_1(sc->sc_memt, sc->sc_regh,
PM2_DAC_PAL_WRITE_IDX, reg);
@@ -689,7 +724,6 @@ pm2fb_write_dac(struct pm2fb_softc *sc,
PM2V_DAC_INDEX_DATA, data);
}
}
-#endif
static void
pm2fb_init(struct pm2fb_softc *sc)
@@ -730,9 +764,13 @@ pm2fb_init(struct pm2fb_softc *sc)
bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STIPPLE_MODE, 0);
bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ROP_MODE, 0);
bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_WINDOW_ORIGIN, 0);
+#if 0
sc->sc_pprod = bus_space_read_4(sc->sc_memt, sc->sc_regh,
PM2_FB_READMODE) &
(PM2FB_PP0_MASK | PM2FB_PP1_MASK | PM2FB_PP2_MASK);
+#endif
+ sc->sc_pprod = partprodPermedia[sc->sc_stride >> 5];
+
bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_FB_READMODE,
sc->sc_pprod);
bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEXMAP_FORMAT,
@@ -1039,7 +1077,6 @@ pm2fb_putchar_aa(void *cookie, int row,
/*
* TODO:
* - use packed mode here as well, instead of writing each pixel separately
- * - support 32bit colour
* - see if we can trick the chip into doing the alpha blending for us
*/
x = x >> 2;
@@ -1204,7 +1241,16 @@ pm2fb_eraserows(void *cookie, int row, i
}
}
-#define MODE_IS_VALID(m) (((m)->hdisplay < 2048) && ((m)->dot_clock < 230000))
+/*
+ * Permedia2 requires a stride that's a multiple of 32 pixels.
+ * For now reject modes with odd widths, although at some point we may want
+ * to just pick the next bigger stride and waste a few kB of video memory
+ */
+
+#define MODE_IS_VALID(m) (((m)->hdisplay < 2048) && \
+ ((m)->dot_clock < 230000) && \
+ (((m)->hdisplay & 32) == 0))
+
static void
pm2_setup_i2c(struct pm2fb_softc *sc)
{
@@ -1236,7 +1282,6 @@ pm2_setup_i2c(struct pm2fb_softc *sc)
i = 0;
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
@@ -1248,7 +1293,7 @@ pm2_setup_i2c(struct pm2fb_softc *sc)
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);
@@ -1286,17 +1331,14 @@ pm2_setup_i2c(struct pm2fb_softc *sc)
}
}
}
+ if (sc->sc_videomode == NULL) {
+ /* no EDID data? */
+ sc->sc_videomode = pick_mode_by_ref(sc->sc_width,
+ sc->sc_height, 60);
+ }
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);
+ pm2fb_set_mode(sc, sc->sc_videomode);
}
-#endif
}
/* I2C bitbanging */
@@ -1372,25 +1414,22 @@ 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;
+ uint8_t temp;
/*
- * this should work on both PM2 and PM2V
+ * this should work on PM2V, PM2 needs something slightly different
*/
- 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;
+ for (m = 1; m < 128; m++) {
+ for (n = 2 * m + 1; n < 256; n++) {
+ fi = RefClk * n / m;
+ for (p = 0; p < 2; p++) {
+ out_freq = fi >> (p + 1);
diff = abs(out_freq - freq);
if (diff < bdiff) {
bdiff = diff;
@@ -1402,8 +1441,77 @@ pm2fb_set_pll(struct pm2fb_softc *sc, in
}
}
}
- printf("best: %d kHz ( %d off ), %d %d %d\n", bfreq, bdiff, bm, bn, bp);
+ DPRINTF("best: %d kHz ( %d off ), %d %d %d\n", bfreq, bdiff, bm, bn, bp);
+ temp = pm2fb_read_dac(sc, PM2V_DAC_CLOCK_CONTROL) & 0xfc;
+ pm2fb_write_dac(sc, PM2V_DAC_CONTROL, 0);
+ pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_M, bm);
+ pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_N, bn);
+ pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_P, bp);
+ pm2fb_write_dac(sc, PM2V_DAC_CLOCK_CONTROL, temp | 3);
return 0;
}
-#endif
-
+
+/*
+ * most of the following was adapted from the xf86-video-glint driver's
+ * pm2v_dac.c
+ */
+static void
+pm2fb_set_mode(struct pm2fb_softc *sc, const struct videomode *mode)
+{
+ int t1, t2, t3, t4;
+ uint32_t vclk;
+ uint8_t sync = 0;
+
+ t1 = mode->hsync_start - mode->hdisplay;
+ t2 = mode->vsync_start - mode->vdisplay;
+ t3 = mode->hsync_end - mode->hsync_start;
+ t4 = mode->vsync_end - mode->vsync_start;
+
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HTOTAL,
+ ((mode->htotal) >> 3) - 1);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_END,
+ (t1 + t3) >> 3);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_START,
+ (t1 >> 3) - 1);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HBLANK_END,
+ (mode->htotal - mode->hdisplay) >> 3);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HGATE_END,
+ (mode->htotal - mode->hdisplay) >> 3);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_STRIDE,
+ (mode->hdisplay) >> 3);
+
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VTOTAL,
+ mode->vtotal - 1);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_END,
+ t2 + t4);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_START,
+ t2);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VBLANK_END,
+ mode->vtotal - mode->vdisplay);
+
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VIDEO_CONTROL,
+ PM2_VC_VIDEO_ENABLE | PM2_VC_RAMDAC_64BIT |
+ PM2_VC_HSYNC_ACT_HIGH | PM2_VC_VSYNC_ACT_HIGH);
+
+ vclk = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL,
+ vclk & 0xfffffffc);
+
+ pm2fb_set_pll(sc, mode->dot_clock / 2);
+ pm2fb_write_dac(sc, PM2V_DAC_MISC_CONTROL, PM2V_DAC_8BIT);
+
+ if (mode->flags & VID_PHSYNC)
+ sync |= PM2V_DAC_HSYNC_INV;
+ if (mode->flags & VID_PVSYNC)
+ sync |= PM2V_DAC_VSYNC_INV;
+ pm2fb_write_dac(sc, PM2V_DAC_SYNC_CONTROL, sync);
+
+ pm2fb_write_dac(sc, PM2V_DAC_COLOR_FORMAT, PM2V_DAC_PALETTE);
+ pm2fb_write_dac(sc, PM2V_DAC_PIXEL_SIZE, PM2V_PS_8BIT);
+ sc->sc_width = mode->hdisplay;
+ sc->sc_height = mode->vdisplay;
+ sc->sc_depth = 8;
+ sc->sc_stride = sc->sc_width;
+ aprint_normal_dev(sc->sc_dev, "using %d x %d in 8 bit\n",
+ sc->sc_width, sc->sc_height);
+}