Module Name: src
Committed By: macallan
Date: Tue Jan 20 12:13:04 UTC 2015
Modified Files:
src/sys/arch/sgimips/dev: crmfb.c crmfbreg.h
Log Message:
- remove scratch area, it's been unused since we're drawing characters by
hardware
- don't sync the rendering engine unless we have to, watch FIFO levels
instead
- support anti-aliased fonts and let the drawing engine do all the work
To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.39 src/sys/arch/sgimips/dev/crmfb.c
cvs rdiff -u -r1.15 -r1.16 src/sys/arch/sgimips/dev/crmfbreg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/sgimips/dev/crmfb.c
diff -u src/sys/arch/sgimips/dev/crmfb.c:1.38 src/sys/arch/sgimips/dev/crmfb.c:1.39
--- src/sys/arch/sgimips/dev/crmfb.c:1.38 Tue Sep 2 15:44:44 2014
+++ src/sys/arch/sgimips/dev/crmfb.c Tue Jan 20 12:13:04 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: crmfb.c,v 1.38 2014/09/02 15:44:44 macallan Exp $ */
+/* $NetBSD: crmfb.c,v 1.39 2015/01/20 12:13:04 macallan Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <[email protected]>
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.38 2014/09/02 15:44:44 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.39 2015/01/20 12:13:04 macallan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -154,7 +154,10 @@ struct crmfb_softc {
int sc_mte_x_shift;
uint32_t sc_mte_mode;
uint32_t sc_de_mode;
- uint8_t *sc_scratch;
+ uint32_t sc_src_mode;
+ uint32_t sc_dst_mode;
+ int sc_needs_sync;
+ uint8_t *sc_lptr;
paddr_t sc_linear;
uint32_t sc_vtflags;
int sc_wsmode, sc_video_on;
@@ -198,6 +201,7 @@ static void crmfb_copyrows(void *, int,
static void crmfb_eraserows(void *, int, int, long);
static void crmfb_cursor(void *, int, int, int);
static void crmfb_putchar(void *, int, int, u_int, long);
+static void crmfb_putchar_aa(void *, int, int, u_int, long);
/* I2C glue */
static int crmfb_i2c_acquire_bus(void *, int);
@@ -336,8 +340,8 @@ crmfb_attach(device_t parent, device_t s
if (rv)
panic("crmfb_attach: can't load DMA map");
- /* allocate an extra 64Kb for a linear buffer */
- sc->sc_dma.size = 0x10000 * (16 * sc->sc_tiles_x + 1);
+ /* allocate an extra 128Kb for a linear buffer */
+ sc->sc_dma.size = 0x10000 * (16 * sc->sc_tiles_x + 2);
rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma.size, 65536, 0,
sc->sc_dma.segs,
sizeof(sc->sc_dma.segs) / sizeof(sc->sc_dma.segs[0]),
@@ -365,8 +369,8 @@ crmfb_attach(device_t parent, device_t s
}
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmai.map, 0, sc->sc_dmai.size,
BUS_DMASYNC_PREWRITE);
- sc->sc_scratch = (char *)KERNADDR(sc->sc_dma) + (0xf0000 * sc->sc_tiles_x);
sc->sc_linear = (paddr_t)DMAADDR(sc->sc_dma) + 0x100000 * sc->sc_tiles_x;
+ sc->sc_lptr = (char *)KERNADDR(sc->sc_dma) + (0x100000 * sc->sc_tiles_x);
aprint_normal_dev(sc->sc_dev, "allocated %d byte fb @ %p (%p)\n",
sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma));
@@ -580,8 +584,8 @@ crmfb_mmap(void *v, void *vs, off_t offs
/* now the actual engine registers */
if ((offset >= 0x15002000) && (offset < 0x15005000))
return bus_space_mmap(sc->sc_iot, offset, 0, prot, 0);
- /* and now the scratch area */
- if ((offset >= 0x15010000) && (offset < 0x15020000))
+ /* and now the linear area */
+ if ((offset >= 0x15010000) && (offset < 0x15030000))
return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs,
sc->sc_dma.nsegs,
offset + (0x100000 * sc->sc_tiles_x) - 0x15010000,
@@ -599,7 +603,7 @@ crmfb_init_screen(void *c, struct vcons_
sc = (struct crmfb_softc *)c;
ri = &scr->scr_ri;
- ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
+ ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_ENABLE_ALPHA;
ri->ri_depth = sc->sc_console_depth;
ri->ri_width = sc->sc_width;
ri->ri_height = sc->sc_height;
@@ -639,8 +643,11 @@ crmfb_init_screen(void *c, struct vcons_
ri->ri_ops.eraserows = crmfb_eraserows;
ri->ri_ops.copycols = crmfb_copycols;
ri->ri_ops.erasecols = crmfb_erasecols;
- ri->ri_ops.putchar = crmfb_putchar;
-
+ if (FONT_IS_ALPHA(ri->ri_font)) {
+ ri->ri_ops.putchar = crmfb_putchar_aa;
+ } else {
+ ri->ri_ops.putchar = crmfb_putchar;
+ }
return;
}
@@ -831,6 +838,61 @@ crmfb_read_reg(struct crmfb_softc *sc, i
return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
}
+static inline void
+crmfb_wait_idle(struct crmfb_softc *sc)
+{
+ int i = 0;
+
+ do {
+ i++;
+ } while (((bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS) &
+ CRIME_DE_IDLE) == 0) && (i < 100000000));
+ if (i >= 100000000)
+ aprint_error("crmfb_wait_idle() timed out\n");
+ sc->sc_needs_sync = 0;
+}
+
+/* writes to CRIME_DE_MODE_* only take effect when the engine is idle */
+
+static inline void
+crmfb_src_mode(struct crmfb_softc *sc, uint32_t mode)
+{
+ if (mode == sc->sc_src_mode)
+ return;
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, mode);
+ sc->sc_needs_sync = 1;
+ sc->sc_src_mode = mode;
+}
+
+static inline void
+crmfb_dst_mode(struct crmfb_softc *sc, uint32_t mode)
+{
+ if (mode == sc->sc_dst_mode)
+ return;
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_DST, mode);
+ sc->sc_needs_sync = 1;
+ sc->sc_dst_mode = mode;
+}
+
+static inline void
+crmfb_make_room(struct crmfb_softc *sc, int num)
+{
+ int i = 0, slots;
+ uint32_t status;
+
+ if (sc->sc_needs_sync != 0) {
+ crmfb_wait_idle(sc);
+ return;
+ }
+
+ do {
+ i++;
+ status = bus_space_read_4(sc->sc_iot, sc->sc_reh,
+ CRIME_DE_STATUS);
+ slots = 60 - CRIME_PIPE_LEVEL(status);
+ } while (slots <= num);
+}
+
static int
crmfb_wait_dma_idle(struct crmfb_softc *sc)
{
@@ -1022,12 +1084,11 @@ crmfb_setup_video(struct crmfb_softc *sc
}
tlbptr += 32;
}
- sc->sc_scratch = (char *)KERNADDR(sc->sc_dma) + (0xf0000 * tx);
- /* now put the last 64kB into the 1st linear TLB */
+ /* now put the last 128kB into the 1st linear TLB */
page = (sc->sc_linear >> 12) | 0x80000000;
tlbptr = 0;
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 16; i++) {
reg = ((uint64_t)page << 32) | (page + 1);
bus_space_write_8(sc->sc_iot, sc->sc_reh,
CRIME_RE_LINEAR_A + tlbptr, reg);
@@ -1081,10 +1142,13 @@ crmfb_setup_video(struct crmfb_softc *sc
panic("%s: unsuported colour depth %d\n", __func__,
depth);
}
- bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_DST,
- sc->sc_de_mode);
- bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC,
- sc->sc_de_mode);
+ sc->sc_needs_sync = 0;
+ sc->sc_src_mode = 0xffffffff;
+ sc->sc_dst_mode = 0xffffffff;
+
+ crmfb_src_mode(sc, sc->sc_de_mode);
+ crmfb_dst_mode(sc, sc->sc_de_mode);
+
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_X, 1);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_Y, 1);
@@ -1104,6 +1168,7 @@ crmfb_set_mte_direction(struct crmfb_sof
if (dir == sc->sc_mte_direction)
return;
+ crmfb_make_room(sc, 2);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, dir);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, dir);
sc->sc_mte_direction = dir;
@@ -1112,7 +1177,9 @@ crmfb_set_mte_direction(struct crmfb_sof
static void
crmfb_setup_palette(struct crmfb_softc *sc)
{
- int i;
+ int i, j, x;
+ uint32_t col;
+ struct rasops_info *ri = &crmfb_console_screen.scr_ri;
for (i = 0; i < 256; i++) {
crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2],
@@ -1121,19 +1188,41 @@ crmfb_setup_palette(struct crmfb_softc *
sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1];
sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0];
}
-}
-static inline void
-crmfb_wait_idle(struct crmfb_softc *sc)
-{
- int i = 0;
+ if (FONT_IS_ALPHA(ri->ri_font)) {
+ sc->sc_de_mode =
+ (sc->sc_de_mode & ~DE_MODE_TYPE_MASK) | DE_MODE_TYPE_RGB;
+ }
- do {
- i++;
- } while (((bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS) &
- CRIME_DE_IDLE) == 0) && (i < 100000000));
- if (i >= 100000000)
- aprint_error("crmfb_wait_idle() timed out\n");
+ /* draw 16 character cells in 32bit RGBA for alpha blending */
+ crmfb_make_room(sc, 3);
+ crmfb_dst_mode(sc,
+ DE_MODE_TLB_A |
+ DE_MODE_BUFDEPTH_32 |
+ DE_MODE_TYPE_RGBA |
+ DE_MODE_PIXDEPTH_32);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
+ DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
+ DE_PRIM_RECTANGLE | DE_PRIM_TB);
+ j = 0;
+ x = 0;
+ for (i = 0; i < 16; i++) {
+ crmfb_make_room(sc, 2);
+ col = (rasops_cmap[j] << 24) |
+ (rasops_cmap[j + 1] << 16) |
+ (rasops_cmap[j + 2] << 8);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, col);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
+ (x << 16) | ((sc->sc_height - 500) & 0xffff));
+ bus_space_write_4(sc->sc_iot, sc->sc_reh,
+ CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
+ ((x + ri->ri_font->fontwidth - 1) << 16) |
+ ((sc->sc_height + ri->ri_font->fontheight - 1) & 0xffff));
+ j += 3;
+ x += ri->ri_font->fontwidth;
+ }
+ crmfb_dst_mode(sc, sc->sc_de_mode);
}
static void
@@ -1144,8 +1233,8 @@ crmfb_fill_rect(struct crmfb_softc *sc,
rxa = x << sc->sc_mte_x_shift;
rxe = ((x + width) << sc->sc_mte_x_shift) - 1;
- crmfb_wait_idle(sc);
crmfb_set_mte_direction(sc, 1);
+ crmfb_make_room(sc, 4);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
sc->sc_mte_mode | 0);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_BG, colour);
@@ -1162,9 +1251,9 @@ crmfb_bitblt(struct crmfb_softc *sc, int
{
uint32_t prim = DE_PRIM_RECTANGLE;
int rxa, rya, rxe, rye, rxs, rys;
- crmfb_wait_idle(sc);
- bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC,
- sc->sc_de_mode);
+ crmfb_make_room(sc, 2);
+ crmfb_src_mode(sc, sc->sc_de_mode);
+ crmfb_make_room(sc, 6);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | DE_DRAWMODE_ROP |
DE_DRAWMODE_XFER_EN);
@@ -1212,7 +1301,7 @@ crmfb_scroll(struct crmfb_softc *sc, int
rxe = ((xs + wi) << sc->sc_mte_x_shift) - 1;
rxde = ((xd + wi) << sc->sc_mte_x_shift) - 1;
- crmfb_wait_idle(sc);
+ crmfb_make_room(sc, 1);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
sc->sc_mte_mode | MTE_MODE_COPY);
@@ -1232,6 +1321,7 @@ crmfb_scroll(struct crmfb_softc *sc, int
ryde = yd + he - 1;
crmfb_set_mte_direction(sc, 1);
}
+ crmfb_make_room(sc, 4);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC0,
(rxa << 16) | rya);
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC1,
@@ -1367,7 +1457,7 @@ crmfb_putchar(void *cookie, int row, int
if (c == 0x20) {
crmfb_fill_rect(sc, x, y, wi, he, bg);
} else {
- crmfb_wait_idle(sc);
+ crmfb_make_room(sc, 6);
/* setup */
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK |
@@ -1382,14 +1472,13 @@ crmfb_putchar(void *cookie, int row, int
bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STIPPLE_MODE,
0x001f0000);
/* now let's feed the engine */
+ crmfb_make_room(sc, 30);
if (font->stride == 1) {
/* shovel in 8 bit quantities */
fd8 = fd;
for (i = 0; i < he; i++) {
- /*
- * the pipeline should be long enough to
- * draw any character without having to wait
- */
+ if (i & 8)
+ crmfb_make_room(sc, 30);
bus_space_write_4(sc->sc_iot, sc->sc_reh,
CRIME_DE_STIPPLE_PAT, *fd8 << 24);
bus_space_write_4(sc->sc_iot, sc->sc_reh,
@@ -1404,10 +1493,8 @@ crmfb_putchar(void *cookie, int row, int
/* shovel in 16 bit quantities */
fd16 = fd;
for (i = 0; i < he; i++) {
- /*
- * the pipeline should be long enough to
- * draw any character without having to wait
- */
+ if (i & 8)
+ crmfb_make_room(sc, 30);
bus_space_write_4(sc->sc_iot, sc->sc_reh,
CRIME_DE_STIPPLE_PAT, *fd16 << 16);
bus_space_write_4(sc->sc_iot, sc->sc_reh,
@@ -1423,6 +1510,97 @@ crmfb_putchar(void *cookie, int row, int
}
static void
+crmfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct vcons_screen *scr = ri->ri_hw;
+ struct crmfb_softc *sc = scr->scr_cookie;
+ struct wsdisplay_font *font = PICK_FONT(ri, c);
+ uint32_t bg, fg;
+ int x, y, wi, he, uc, xx;
+ void *fd;
+
+ wi = font->fontwidth;
+ he = font->fontheight;
+
+ x = ri->ri_xorigin + col * wi;
+ y = ri->ri_yorigin + row * he;
+
+ bg = ri->ri_devcmap[(attr >> 16) & 0xff];
+ fg = (attr >> 24);
+ uc = c - font->firstchar;
+ fd = (uint8_t *)font->data + uc * ri->ri_fontscale;
+
+ /* fill the cell with the background colour */
+ crmfb_fill_rect(sc, x, y, wi, he, bg);
+
+ /* if all we draw is a space we're done */
+ if (c == 0x20)
+ return;
+
+ /* copy the glyph into the linear buffer */
+ memcpy(sc->sc_lptr, fd, ri->ri_fontscale);
+ wbflush();
+
+ /* now blit it on top of the requested fg colour cell */
+ xx = fg * wi;
+ crmfb_make_room(sc, 2);
+ crmfb_src_mode(sc,
+ DE_MODE_LIN_A |
+ DE_MODE_BUFDEPTH_8 |
+ DE_MODE_TYPE_CI |
+ DE_MODE_PIXDEPTH_8);
+ crmfb_dst_mode(sc,
+ DE_MODE_TLB_A |
+ DE_MODE_BUFDEPTH_32 |
+ DE_MODE_TYPE_CI |
+ DE_MODE_PIXDEPTH_8);
+
+ crmfb_make_room(sc, 6);
+ /* only write into the alpha channel */
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
+ DE_DRAWMODE_PLANEMASK | 0x08 |
+ DE_DRAWMODE_XFER_EN);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
+ DE_PRIM_RECTANGLE | DE_PRIM_TB);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STRD_SRC, 1);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
+ (xx << 16) | (sc->sc_height & 0xffff));
+ bus_space_write_4(sc->sc_iot, sc->sc_reh,
+ CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
+ ((xx + wi - 1) << 16) | ((sc->sc_height + he - 1) & 0xffff));
+
+ /* now draw the actual character */
+ crmfb_make_room(sc, 2);
+ crmfb_src_mode(sc,
+ DE_MODE_TLB_A |
+ DE_MODE_BUFDEPTH_32 |
+ DE_MODE_TYPE_RGBA |
+ DE_MODE_PIXDEPTH_32);
+ crmfb_dst_mode(sc, sc->sc_de_mode);
+
+ crmfb_make_room(sc, 6);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
+ DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK |
+ DE_DRAWMODE_ALPHA_BLEND |
+ DE_DRAWMODE_XFER_EN);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ALPHA_FUNC,
+ DE_ALPHA_ADD |
+ (DE_ALPHA_OP_SRC_ALPHA << DE_ALPHA_OP_SRC_SHIFT) |
+ (DE_ALPHA_OP_1_MINUS_SRC_ALPHA << DE_ALPHA_OP_DST_SHIFT));
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
+ DE_PRIM_RECTANGLE | DE_PRIM_TB);
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC,
+ (xx << 16) | (sc->sc_height & 0xffff));
+ bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
+ (x << 16) | (y & 0xffff));
+ bus_space_write_4(sc->sc_iot, sc->sc_reh,
+ CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
+ ((x + wi - 1) << 16) | ((y + he - 1) & 0xffff));
+}
+
+static void
crmfb_setup_ddc(struct crmfb_softc *sc)
{
int i;
@@ -1679,4 +1857,3 @@ crmfb_set_mode(struct crmfb_softc *sc, c
return TRUE;
}
-
Index: src/sys/arch/sgimips/dev/crmfbreg.h
diff -u src/sys/arch/sgimips/dev/crmfbreg.h:1.15 src/sys/arch/sgimips/dev/crmfbreg.h:1.16
--- src/sys/arch/sgimips/dev/crmfbreg.h:1.15 Tue May 17 22:26:33 2011
+++ src/sys/arch/sgimips/dev/crmfbreg.h Tue Jan 20 12:13:04 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: crmfbreg.h,v 1.15 2011/05/17 22:26:33 macallan Exp $ */
+/* $NetBSD: crmfbreg.h,v 1.16 2015/01/20 12:13:04 macallan Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <[email protected]>
@@ -68,6 +68,7 @@
#define CRMFB_DOTCLOCK_N_MASK 0x00003f00
#define CRMFB_DOTCLOCK_P_MASK 0x0000c000
#define CRMFB_DOTCLOCK_CLKRUN_SHIFT 20
+#define CRMFB_DOTCLOCK_BYPASS 0x00100000 /* turn the clock off */
#define CRMFB_DOTCLOCK_OUT_OF_RANGE 0x00400000
#define CRMFB_DOTCLOCK_OUT_OF_LOCK 0x00800000
#define CRMFB_DOTCLOCK_TDWNI 0x01000000 /* ? */
@@ -328,6 +329,7 @@
#define DE_MODE_TYPE_RGBA 0x00000020
#define DE_MODE_TYPE_ABGR 0x00000030
#define DE_MODE_TYPE_YCRCB 0x000000f0
+#define DE_MODE_TYPE_MASK 0x000000f0
#define DE_MODE_PIXDEPTH_8 0x00000000
#define DE_MODE_PIXDEPTH_16 0x00000004
#define DE_MODE_PIXDEPTH_32 0x00000008
@@ -427,7 +429,12 @@
#define CRIME_DE_BUF_START 0x0000003f
#define CRIME_DE_LEVEL_SHIFT 18
-#define CRIME_DE_LEVEL_MAX 0x7f
+/*
+ * XXX
+ * The manual claims that the pipeline is 128 deep, in reality it seems to be
+ * 64, at least on my O2. Might be 128 deep on O2+
+ */
+#define CRIME_DE_LEVEL_MAX 0x3f
#define CRIME_PIPE_LEVEL(x) ((x & CRIME_DE_LEVEL_MASK) >> \
CRIME_DE_LEVEL_SHIFT)