Module Name:    src
Committed By:   macallan
Date:           Wed May 27 00:35:34 UTC 2009

Modified Files:
        src/sys/dev/sbus: p9100.c

Log Message:
finally commit a lot of stuff that's been sitting in my source tree for
several ages:
- convert to device_t
- add support for programming colour depth and such, use it to reset the
  console to something usable when we enter ddb or exit X etc.
- basic power management
TODO:
- convert to PMF
- get rid of rconsole code so we don't need to map the framebuffer
- power down the whole DAC when not in use


To generate a diff of this commit:
cvs rdiff -u -r1.43 -r1.44 src/sys/dev/sbus/p9100.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/sbus/p9100.c
diff -u src/sys/dev/sbus/p9100.c:1.43 src/sys/dev/sbus/p9100.c:1.44
--- src/sys/dev/sbus/p9100.c:1.43	Tue May 12 14:43:59 2009
+++ src/sys/dev/sbus/p9100.c	Wed May 27 00:35:34 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: p9100.c,v 1.43 2009/05/12 14:43:59 cegger Exp $ */
+/*	$NetBSD: p9100.c,v 1.44 2009/05/27 00:35:34 macallan Exp $ */
 
 /*-
  * Copyright (c) 1998, 2005, 2006 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: p9100.c,v 1.43 2009/05/12 14:43:59 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: p9100.c,v 1.44 2009/05/27 00:35:34 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -62,7 +62,7 @@
 
 #include <dev/sbus/sbusvar.h>
 
-/*#include <dev/wscons/wsdisplayvar.h>*/
+#include <dev/wscons/wsdisplayvar.h>
 #include <dev/wscons/wsconsio.h>
 #include <dev/wsfont/wsfont.h>
 #include <dev/rasops/rasops.h>
@@ -78,6 +78,12 @@
 #include <sparc/dev/tctrlvar.h>/*XXX*/
 #endif
 
+#ifdef PNOZZ_DEBUG
+#define DPRINTF aprint_normal
+#else
+#define DPRINTF while (0) aprint_normal
+#endif
+
 struct pnozz_cursor {
 	short	pc_enable;		/* cursor is enabled */
 	struct	fbcurpos pc_pos;	/* position */
@@ -90,7 +96,7 @@
 
 /* per-display variables */
 struct p9100_softc {
-	struct device	sc_dev;		/* base device */
+	device_t	sc_dev;		/* base device */
 	struct sbusdev	sc_sd;		/* sbus device */
 	struct fbdevice	sc_fb;		/* frame buffer device */
 
@@ -100,10 +106,11 @@
 	bus_size_t	sc_ctl_psize;	/*   for device mmap() */
 	bus_space_handle_t sc_ctl_memh;	/*   bus space handle */
 
+#if 0
 	bus_addr_t	sc_cmd_paddr;	/* phys address description */
 	bus_size_t	sc_cmd_psize;	/*   for device mmap() */
 	bus_space_handle_t sc_cmd_memh;	/*   bus space handle */
-
+#endif
 	bus_addr_t	sc_fb_paddr;	/* phys address description */
 	bus_size_t	sc_fb_psize;	/*   for device mmap() */
 	bus_space_handle_t sc_fb_memh;	/*   bus space handle */
@@ -111,10 +118,12 @@
 	volatile uint32_t sc_junk;
 	uint32_t sc_mono_width;	/* for setup_mono */
 
-	uint32_t sc_width;
-	uint32_t sc_height;	/* panel width / height */
-	uint32_t sc_stride;
-	uint32_t sc_depth;
+	uint32_t	sc_width;
+	uint32_t	sc_height;	/* panel width / height */
+	uint32_t	sc_stride;
+	uint32_t	sc_depth;
+	int		sc_depthshift;	/* blitter works on bytes not pixels */
+	
 	union	bt_cmap sc_cmap;	/* Brooktree color map */
 
 	struct pnozz_cursor sc_cursor;
@@ -155,7 +164,7 @@
 static void	p9100unblank(device_t);
 static void	p9100_shutdown(void *);
 
-CFATTACH_DECL(pnozz, sizeof(struct p9100_softc),
+CFATTACH_DECL_NEW(pnozz, sizeof(struct p9100_softc),
     p9100_sbus_match, p9100_sbus_attach, NULL, NULL);
 
 extern struct cfdriver pnozz_cd;
@@ -189,6 +198,7 @@
 #endif
 
 static void 	p9100_init_engine(struct p9100_softc *);
+static int	p9100_set_depth(struct p9100_softc *, int);
 
 #if NWSDISPLAY > 0
 static void	p9100_sync(struct p9100_softc *);
@@ -229,7 +239,9 @@
 static void	p9100_setcursorcmap(struct p9100_softc *);
 static void	p9100_loadcursor(struct p9100_softc *);
 
+#if 0
 static int	p9100_intr(void *);
+#endif
 
 /* power management stuff */
 static void p9100_power_hook(int, void *);
@@ -264,7 +276,9 @@
 {
 	struct sbus_attach_args *sa = aux;
 
-	return (strcmp("p9100", sa->sa_name) == 0);
+	if (strcmp("p9100", sa->sa_name) == 0)
+		return 100;
+	return 0;
 }
 
 
@@ -278,7 +292,7 @@
 	struct sbus_attach_args *sa = args;
 	struct fbdevice *fb = &sc->sc_fb;
 	int isconsole;
-	int node;
+	int node = sa->sa_node;
 	int i, j;
 	uint8_t ver;
 
@@ -289,24 +303,67 @@
 #endif
 
 	sc->sc_last_offset = 0xffffffff;
+	sc->sc_dev = self;
+
+	/*
+	 * When the ROM has mapped in a p9100 display, the address
+	 * maps only the video RAM, so in any case we have to map the
+	 * registers ourselves.  We only need the video RAM if we are
+	 * going to print characters via rconsole.
+	 */
+
+	if (sa->sa_npromvaddrs != 0)
+		fb->fb_pixels = (void *)sa->sa_promvaddrs[0];
 
 	/* Remember cookies for p9100_mmap() */
 	sc->sc_bustag = sa->sa_bustag;
+
 	sc->sc_ctl_paddr = sbus_bus_addr(sa->sa_bustag,
 		sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base);
 	sc->sc_ctl_psize = 0x8000;/*(bus_size_t)sa->sa_reg[0].oa_size;*/
 
-	sc->sc_cmd_paddr = sbus_bus_addr(sa->sa_bustag,
-		sa->sa_reg[1].oa_space, sa->sa_reg[1].oa_base);
-	sc->sc_cmd_psize = (bus_size_t)sa->sa_reg[1].oa_size;
-
 	sc->sc_fb_paddr = sbus_bus_addr(sa->sa_bustag,
 		sa->sa_reg[2].oa_space, sa->sa_reg[2].oa_base);
 	sc->sc_fb_psize = (bus_size_t)sa->sa_reg[2].oa_size;
 
+	if (sbus_bus_map(sc->sc_bustag,
+	    sa->sa_reg[0].oa_space,
+	    sa->sa_reg[0].oa_base,
+	    /*
+	     * XXX for some reason the SBus resources don't cover
+	     * all registers, so we just map what we need
+	     */
+	    0x8000,
+	    0, &sc->sc_ctl_memh) != 0) {
+		printf("%s: cannot map control registers\n",
+		    self->dv_xname);
+		return;
+	}
+
+	if (fb->fb_pixels == NULL) {
+		if (sbus_bus_map(sc->sc_bustag,
+		    sa->sa_reg[2].oa_space,
+		    sa->sa_reg[2].oa_base,
+		    sc->sc_fb_psize,
+		    BUS_SPACE_MAP_LINEAR, &sc->sc_fb_memh) != 0) {
+			printf("%s: cannot map framebuffer\n",
+			    self->dv_xname);
+			return;
+		}
+		fb->fb_pixels = (char *)sc->sc_fb_memh;
+	} else {
+		sc->sc_fb_memh = (bus_space_handle_t) fb->fb_pixels;
+	}
+	sc->sc_width = prom_getpropint(node, "width", 800);
+	sc->sc_height = prom_getpropint(node, "height", 600);
+	sc->sc_depth = prom_getpropint(node, "depth", 8) >> 3;
+
+	sc->sc_stride = prom_getpropint(node, "linebytes",
+	    sc->sc_width * sc->sc_depth);
+
 	fb->fb_driver = &p9100fbdriver;
-	fb->fb_device = &sc->sc_dev;
-	fb->fb_flags = device_cfdata(&sc->sc_dev)->cf_flags & FB_USERMASK;
+	fb->fb_device = sc->sc_dev;
+	fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK;
 #ifdef PNOZZ_EMUL_CG3
 	fb->fb_type.fb_type = FBTYPE_SUN3COLOR;
 #else
@@ -316,13 +373,14 @@
 
 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
 
-	node = sa->sa_node;
 	isconsole = fb_is_console(node);
+#if 0
 	if (!isconsole) {
 		aprint_normal("\n");
 		aprint_error_dev(self, "fatal error: PROM didn't configure device\n");
 		return;
 	}
+#endif
 
 	/*
 	 * When the ROM has mapped in a p9100 display, the address
@@ -360,48 +418,62 @@
 		sc->sc_fb_memh = (bus_space_handle_t) fb->fb_pixels;
 	}
 
+#if 0
+	/*
+	 * we set our own depth and OBP won't hand us anything else than 8 bit
+	 * anyway
+	 */
 	i = p9100_ctl_read_4(sc, 0x0004);
 	switch ((i >> 26) & 7) {
-	    case 5: fb->fb_type.fb_depth = 32; break;
-	    case 7: fb->fb_type.fb_depth = 24; break;
-	    case 3: fb->fb_type.fb_depth = 16; break;
-	    case 2: fb->fb_type.fb_depth = 8; break;
+	    case 5: 
+	    	fb->fb_type.fb_depth = 32;
+		sc->sc_depth = 4;
+		sc->sc_depthshift = 2;
+		break;
+	    case 7: 
+	    	fb->fb_type.fb_depth = 24;
+		/* bitch and moan */
+		break;
+	    case 3:
+	    	fb->fb_type.fb_depth = 16;
+		sc->sc_depth = 2;
+		sc->sc_depthshift = 1;
+		break;
+	    case 2:
+	    	fb->fb_type.fb_depth = 8;
+		sc->sc_depth = 1;
+		sc->sc_depthshift = 0;
+		break;
 	    default: {
 		panic("pnozz: can't determine screen depth (0x%02x)", i);
 	    }
 	}
-	sc->sc_depth = (fb->fb_type.fb_depth >> 3);
-
-	/* XXX for some reason I get a kernel trap with this */
-	sc->sc_width = prom_getpropint(node, "width", 800);
-	sc->sc_height = prom_getpropint(node, "height", 600);
-
-	sc->sc_stride = prom_getpropint(node, "linebytes", sc->sc_width *
-	    (fb->fb_type.fb_depth >> 3));
+#else
+    	fb->fb_type.fb_depth = 8;
+	sc->sc_depth = 1;
+	sc->sc_depthshift = 0;
+#endif	
 
 	/* check the RAMDAC */
 	ver = p9100_ramdac_read_ctl(sc, DAC_VERSION);
 
 	p9100_init_engine(sc);
-
+	p9100_set_depth(sc, 8);
+	
 	fb_setsize_obp(fb, fb->fb_type.fb_depth, sc->sc_width, sc->sc_height,
 	    node);
 
-	sbus_establish(&sc->sc_sd, &sc->sc_dev);
+	sbus_establish(&sc->sc_sd, sc->sc_dev);
+#if 0
 	bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO,
 	    p9100_intr, sc);
-
-	fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes;
-	printf(": rev %d / %x, %dx%d, depth %d mem %x",
-	       (i & 7), ver, fb->fb_type.fb_width, fb->fb_type.fb_height,
-	       fb->fb_type.fb_depth, (unsigned int)sc->sc_fb_psize);
+#endif
 
 	fb->fb_type.fb_cmsize = prom_getpropint(node, "cmsize", 256);
 	if ((1 << fb->fb_type.fb_depth) != fb->fb_type.fb_cmsize)
 		printf(", %d entry colormap", fb->fb_type.fb_cmsize);
 
 	/* Initialize the default color map. */
-	/*bt_initcmap(&sc->sc_cmap, 256);*/
 	j = 0;
 	for (i = 0; i < 256; i++) {
 		sc->sc_cmap.cm_map[i][0] = rasops_cmap[j];
@@ -419,7 +491,7 @@
 
 	if (shutdownhook_establish(p9100_shutdown, sc) == NULL) {
 		panic("%s: could not establish shutdown hook",
-		      device_xname(&sc->sc_dev));
+		      device_xname(sc->sc_dev));
 	}
 
 	if (isconsole) {
@@ -461,6 +533,10 @@
 
 	config_found(self, &aa, wsemuldisplaydevprint);
 #endif
+	fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes;
+	printf(": rev %d / %x, %dx%d, depth %d mem %x",
+	       (i & 7), ver, fb->fb_type.fb_width, fb->fb_type.fb_height,
+	       fb->fb_type.fb_depth, (unsigned int)sc->sc_fb_psize);
 	/* cursor sprite handling */
 	p9100_init_cursor(sc);
 
@@ -470,7 +546,7 @@
 	/* register with power management */
 	sc->sc_video = 1;
 	sc->sc_powerstate = PWR_RESUME;
-	powerhook_establish(device_xname(&sc->sc_dev), p9100_power_hook, sc);
+	powerhook_establish(device_xname(sc->sc_dev), p9100_power_hook, sc);
 
 #if NTCTRL > 0
 	/* register callback for external monitor status change */
@@ -701,6 +777,7 @@
 	p9100_ctl_write_4(sc, PATTERN1, 0xffffffff);
 	p9100_ctl_write_4(sc, PATTERN2, 0xffffffff);
 	p9100_ctl_write_4(sc, PATTERN3, 0xffffffff);
+
 }
 
 /* we only need these in the wsdisplay case */
@@ -748,14 +825,16 @@
 	dst = ((xd & 0x3fff) << 16) | (yd & 0x3fff);
 	srcw = (((xs + wi - 1) & 0x3fff) << 16) | ((ys + he - 1) & 0x3fff);
 	dstw = (((xd + wi - 1) & 0x3fff) << 16) | ((yd + he - 1) & 0x3fff);
+
 	p9100_sync(sc);
+	
 	p9100_ctl_write_4(sc, RASTER_OP, rop);
 
-	p9100_ctl_write_4(sc, ABS_XY0, src);
+	p9100_ctl_write_4(sc, ABS_XY0, src << sc->sc_depthshift);
+	p9100_ctl_write_4(sc, ABS_XY1, srcw << sc->sc_depthshift);
+	p9100_ctl_write_4(sc, ABS_XY2, dst << sc->sc_depthshift);
+	p9100_ctl_write_4(sc, ABS_XY3, dstw << sc->sc_depthshift);
 
-	p9100_ctl_write_4(sc, ABS_XY1, srcw);
-	p9100_ctl_write_4(sc, ABS_XY2, dst);
-	p9100_ctl_write_4(sc, ABS_XY3, dstw);
 	sc->sc_junk = p9100_ctl_read_4(sc, COMMAND_BLIT);
 }
 
@@ -823,17 +902,15 @@
 		if (shift == 0) {
 			/* check how many bits are significant */
 			if (to_go > 31) {
-				bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh,
+				bus_space_write_4(sc->sc_bustag, 
+				    sc->sc_ctl_memh,
 				    (PIXEL_1 + (31 << 2)), latch);
-				/*p9100_ctl_write_4(sc, (PIXEL_1 +
-				    (31 << 2)), latch);*/
 				to_go -= 32;
 			} else
 			{
-				bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh,
+				bus_space_write_4(sc->sc_bustag, 
+				    sc->sc_ctl_memh,
 				    (PIXEL_1 + ((to_go - 1) << 2)), latch);
-				/*p9100_ctl_write_4(sc, (PIXEL_1 +
-				    ((to_go - 1) << 2)), latch);*/
 				to_go = 0;
 			}
 			latch = 0;
@@ -910,6 +987,8 @@
 			sc->vd.active = &p9100_console_screen;
 			SCREEN_VISIBLE(&p9100_console_screen);
 		}
+		p9100_init_engine(sc);
+		p9100_set_depth(sc, 8);
 		vcons_redraw_screen(&p9100_console_screen);
 	}
 }
@@ -967,7 +1046,6 @@
 p9100loadcmap(struct p9100_softc *sc, int start, int ncolors)
 {
 	int i;
-
 	sc->sc_last_offset = 0xffffffff;
 
 	p9100_ramdac_write(sc, DAC_CMAP_WRIDX, start);
@@ -1010,7 +1088,7 @@
 	}
 #endif
 
-	if (off >= sc->sc_fb_psize + sc->sc_ctl_psize + sc->sc_cmd_psize)
+	if (off >= sc->sc_fb_psize + sc->sc_ctl_psize/* + sc->sc_cmd_psize*/)
 		return (-1);
 
 	if (off < sc->sc_fb_psize) {
@@ -1020,6 +1098,7 @@
 			prot,
 			BUS_SPACE_MAP_LINEAR));
 	}
+
 	off -= sc->sc_fb_psize;
 	if (off < sc->sc_ctl_psize) {
 		return (bus_space_mmap(sc->sc_bustag,
@@ -1028,6 +1107,7 @@
 			prot,
 			BUS_SPACE_MAP_LINEAR));
 	}
+#if 0
 	off -= sc->sc_ctl_psize;
 
 	return (bus_space_mmap(sc->sc_bustag,
@@ -1035,6 +1115,8 @@
 		off,
 		prot,
 		BUS_SPACE_MAP_LINEAR));
+#endif
+	return EINVAL;
 }
 
 /* wscons stuff */
@@ -1057,8 +1139,10 @@
 		p9100_bitblt(sc, x, y, x, y, wi, he, ROP_SRC ^ 0xff);
 		ri->ri_flg &= ~RI_CURSOR;
 	}
+
 	ri->ri_crow = row;
 	ri->ri_ccol = col;
+
 	if (on)
 	{
 		x = ri->ri_ccol * wi + ri->ri_xorigin;
@@ -1092,10 +1176,12 @@
 
 	if (!CHAR_IN_FONT(c, ri->ri_font))
 		return;
+
 	bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff];
 	fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff];
 	x = ri->ri_xorigin + col * wi;
 	y = ri->ri_yorigin + row * he;
+
 	if (c == 0x20) {
 		p9100_rectfill(sc, x, y, wi, he, bg);
 	} else {
@@ -1109,7 +1195,6 @@
 			    data);
 			data += ri->ri_font->stride;
 		}
-		/*p9100_sync(sc);*/
 	}
 }
 
@@ -1164,6 +1249,7 @@
 					if (new_mode == WSDISPLAYIO_MODE_EMUL)
 					{
 						p9100_init_engine(sc);
+						p9100_set_depth(sc, 8);
 						p9100loadcmap(sc, 0, 256);
 						p9100_clearscreen(sc);
 						vcons_redraw_screen(ms);
@@ -1220,9 +1306,8 @@
 
 	ri->ri_bits = bus_space_vaddr(sc->sc_bustag, sc->sc_fb_memh);
 
-#ifdef DEBUG_P9100
-	printf("addr: %08lx\n",(ulong)ri->ri_bits);
-#endif
+	DPRINTF("addr: %08lx\n",(ulong)ri->ri_bits);
+
 	rasops_init(ri, sc->sc_height/8, sc->sc_width/8);
 	ri->ri_caps = WSSCREEN_WSCOLORS;
 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
@@ -1381,12 +1466,16 @@
 		fg = WS_DEFAULT_FG;
 		bg = WS_DEFAULT_BG;
 	}
+
+	*attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 | (flags & 0xff);
+
 	if (flags & WSATTR_REVERSE) {
 		*attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16 |
 		    (flags & 0xff) << 8;
 	} else
 		*attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 |
 		    (flags & 0xff) << 8;
+
 	return 0;
 }
 
@@ -1401,13 +1490,15 @@
 
 #endif /* NWSDISPLAY > 0 */
 
+#if 0
 static int
 p9100_intr(void *arg)
 {
-	/*p9100_softc *sc=arg;
-	printf(".");*/
+	/*p9100_softc *sc=arg;*/
+	DPRINTF(".");
 	return 1;
 }
+#endif
 
 static void
 p9100_init_cursor(struct p9100_softc *sc)
@@ -1535,7 +1626,7 @@
 			p9100_ramdac_write(sc, DAC_INDX_DATA, latch2);
 		}
 	}
-#ifdef DEBUG_CURSOR
+#ifdef PNOZZ_DEBUG_CURSOR
 	printf("image:\n");
 	for (i=0;i<0x80;i+=2)
 		printf("%08x %08x\n", image[i], image[i+1]);
@@ -1558,19 +1649,21 @@
 
 	s = splhigh();
 #endif
-#ifdef DEBUG
-	printf("%s: external VGA %s\n", device_xname(&sc->sc_dev),
+
+#ifdef PNOZZ_DEBUG
+	printf("%s: external VGA %s\n", device_xname(sc->sc_dev),
 	    status ? "on" : "off");
 #endif
+
 	sc->sc_last_offset = 0xffffffff;
 
 	if (status) {
-		p9100_ramdac_write_ctl(sc, DAC_POWER,
-		    p9100_ramdac_read_ctl(sc, DAC_POWER) &
+		p9100_ramdac_write_ctl(sc, DAC_POWER_MGT,
+		    p9100_ramdac_read_ctl(sc, DAC_POWER_MGT) &
 		    ~DAC_POWER_IPWR_DISABLE);
 	} else {
-		p9100_ramdac_write_ctl(sc, DAC_POWER,
-		    p9100_ramdac_read_ctl(sc, DAC_POWER) |
+		p9100_ramdac_write_ctl(sc, DAC_POWER_MGT,
+		    p9100_ramdac_read_ctl(sc, DAC_POWER_MGT) |
 		    DAC_POWER_IPWR_DISABLE);
 	}
 #ifdef PNOZZ_PARANOID
@@ -1578,3 +1671,175 @@
 #endif
 }
 #endif /* NTCTRL > 0 */
+
+static int
+upper_bit(uint32_t b)
+{
+        uint32_t mask=0x80000000;
+        int cnt = 31;
+        if (b == 0)  
+                return -1;
+        while ((mask != 0) && ((b & mask) == 0)) {
+                mask = mask >> 1;
+                cnt--;
+        }
+        return cnt;
+}
+
+static int
+p9100_set_depth(struct p9100_softc *sc, int depth)
+{
+	int new_sls;
+	uint32_t bits, scr, memctl, mem;
+	int s0, s1, s2, s3, ps, crtcline;
+	uint8_t pf, mc3, es;
+
+	switch (depth) {
+		case 8:
+			sc->sc_depthshift = 0;
+			ps = 2;
+			pf = 3;
+			mc3 = 0;
+			es = 0;	/* no swapping */
+			memctl = 3;
+			break;
+		case 16:
+			sc->sc_depthshift = 1;
+			ps = 3;
+			pf = 4;
+			mc3 = 0;
+			es = 2;	/* swap bytes in 16bit words */
+			memctl = 2;
+			break;
+		case 24:
+			/* boo */
+			printf("We don't DO 24bit pixels dammit!\n");
+			return 0;
+		case 32:
+			sc->sc_depthshift = 2;
+			ps = 5;
+			pf = 6;
+			mc3 = 0;
+			es = 6;	/* swap both half-words and bytes */
+			memctl = 1;	/* 0 */
+			break;
+		default:
+			aprint_error("%s: bogus colour depth (%d)\n",
+			    __func__, depth);
+			return FALSE;
+	}
+	/*
+	 * this could be done a lot shorter and faster but then nobody would 
+	 * understand what the hell we're doing here without getting a major 
+	 * headache. Scanline size is encoded as 4 shift values, 3 of them 3 bits 
+	 * wide, 16 << n for n>0, one 2 bits, 512 << n for n>0. n==0 means 0
+	 */
+	new_sls = sc->sc_width << sc->sc_depthshift;
+	sc->sc_stride = new_sls;
+	bits = new_sls;
+	s3 = upper_bit(bits);
+	if (s3 > 9) {
+		bits &= ~(1 << s3);
+		s3 -= 9;
+	} else
+		s3 = 0;
+	s2 = upper_bit(bits);
+	if (s2 > 0) {
+		bits &= ~(1 << s2);
+		s2 -= 4;
+	} else
+		s2 = 0;
+	s1 = upper_bit(bits);
+	if (s1 > 0) {
+	        bits &= ~(1 << s1);
+	        s1 -= 4;
+	} else
+		s1 = 0;
+	s0 = upper_bit(bits);
+	if (s0 > 0) {
+	        bits &= ~(1 << s0);
+	        s0 -= 4;
+	} else
+		s0 = 0;
+
+
+	DPRINTF("sls: %x sh: %d %d %d %d leftover: %x\n", new_sls, s0, s1,
+	    s2, s3, bits);
+
+	/* 
+	 * now let's put these values into the System Config Register. No need to 
+	 * read it here since we (hopefully) just saved the content 
+	 */
+	scr = p9100_ctl_read_4(sc, SYS_CONF);
+	scr = (s0 << SHIFT_0) | (s1 << SHIFT_1) | (s2 << SHIFT_2) | 
+	        (s3 << SHIFT_3) | (ps << PIXEL_SHIFT) | (es << SWAP_SHIFT);
+
+	DPRINTF("new scr: %x DAC %x %x\n", scr, pf, mc3);
+    
+	mem = p9100_ctl_read_4(sc, VID_MEM_CONFIG);
+
+	DPRINTF("old memctl: %08x\n", mem);
+
+	/* set shift and crtc clock */
+	mem &= ~(0x0000fc00);
+	mem |= (memctl << 10) | (memctl << 13);
+	p9100_ctl_write_4(sc, VID_MEM_CONFIG, mem);
+
+	DPRINTF("new memctl: %08x\n", mem);
+
+	/* whack the engine... */
+	p9100_ctl_write_4(sc, SYS_CONF, scr);
+    
+	/* ok, whack the DAC */
+	p9100_ramdac_write_ctl(sc, DAC_MISC_1, 0x11);
+	p9100_ramdac_write_ctl(sc, DAC_MISC_2, 0x45);
+	p9100_ramdac_write_ctl(sc, DAC_MISC_3, mc3);
+	/* 
+	 * despite the 3GX manual saying otherwise we don't need to mess with
+	 * any clock dividers here
+	 */
+	p9100_ramdac_write_ctl(sc, DAC_MISC_CLK, 1);
+	p9100_ramdac_write_ctl(sc, 3, 0);
+	p9100_ramdac_write_ctl(sc, 4, 0);
+
+	p9100_ramdac_write_ctl(sc, DAC_POWER_MGT, 0);
+	p9100_ramdac_write_ctl(sc, DAC_OPERATION, 0);
+	p9100_ramdac_write_ctl(sc, DAC_PALETTE_CTRL, 0);
+
+	p9100_ramdac_write_ctl(sc, DAC_PIXEL_FMT, pf);
+
+	/* TODO: distinguish between 15 and 16 bit */
+	p9100_ramdac_write_ctl(sc, DAC_8BIT_CTRL, 0);
+	/* direct colour, linear, 565 */
+	p9100_ramdac_write_ctl(sc, DAC_16BIT_CTRL, 0xc6);
+	/* direct colour */
+	p9100_ramdac_write_ctl(sc, DAC_32BIT_CTRL, 3);
+
+	/* From the 3GX manual. Needs magic number reduction */
+	p9100_ramdac_write_ctl(sc, 0x10, 2);
+	p9100_ramdac_write_ctl(sc, 0x11, 0);
+	p9100_ramdac_write_ctl(sc, 0x14, 5);
+	p9100_ramdac_write_ctl(sc, 0x08, 1);
+	p9100_ramdac_write_ctl(sc, 0x15, 5);
+	p9100_ramdac_write_ctl(sc, 0x16, 0x63);
+
+	/* whack the CRTC */
+	/* we always transfer 64bit in one go */
+	crtcline = sc->sc_stride >> 3;
+
+	DPRINTF("crtcline: %d\n", crtcline);
+
+	p9100_ctl_write_4(sc, VID_HTOTAL, (24 << sc->sc_depthshift) + crtcline);
+	p9100_ctl_write_4(sc, VID_HSRE, 8 << sc->sc_depthshift);
+	p9100_ctl_write_4(sc, VID_HBRE, 18 << sc->sc_depthshift);
+	p9100_ctl_write_4(sc, VID_HBFE, (18 << sc->sc_depthshift) + crtcline);
+
+#ifdef PNOZZ_DEBUG
+	{
+		uint32_t sscr;
+		sscr = p9100_ctl_read_4(sc, SYS_CONF);
+		printf("scr: %x\n", sscr);
+	}
+#endif
+	return TRUE;
+}

Reply via email to