Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/sgimips/dev add mode setting support
details: https://anonhg.NetBSD.org/src/rev/3c88e899bb45
branches: trunk
changeset: 763915:3c88e899bb45
user: macallan <macallan%NetBSD.org@localhost>
date: Thu Apr 07 01:20:31 2011 +0000
description:
add mode setting support
If we find a monitor via DDC we switch to its preferred mode if it reports one,
otherwise stick with whatever the firmware set up.
diffstat:
sys/arch/sgimips/dev/crmfb.c | 211 ++++++++++++++++++++++++++++++++++-----
sys/arch/sgimips/dev/crmfbreg.h | 12 +-
2 files changed, 189 insertions(+), 34 deletions(-)
diffs (truncated from 383 to 300 lines):
diff -r 7e5015fa37a9 -r 3c88e899bb45 sys/arch/sgimips/dev/crmfb.c
--- a/sys/arch/sgimips/dev/crmfb.c Thu Apr 07 01:07:31 2011 +0000
+++ b/sys/arch/sgimips/dev/crmfb.c Thu Apr 07 01:20:31 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: crmfb.c,v 1.31 2011/04/04 22:50:36 macallan Exp $ */
+/* $NetBSD: crmfb.c,v 1.32 2011/04/07 01:20:31 macallan Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.31 2011/04/04 22:50:36 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.32 2011/04/07 01:20:31 macallan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -62,7 +62,13 @@
#include <arch/sgimips/dev/crmfbreg.h>
-/*#define CRMFB_DEBUG*/
+#include "opt_crmfb.h"
+
+#ifdef CRMFB_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF while (0) printf
+#endif
struct wsscreen_descr crmfb_defaultscreen = {
"default",
@@ -147,6 +153,7 @@
uint8_t *sc_scratch;
paddr_t sc_linear;
int sc_wsmode;
+ struct edid_info sc_edid_info;
/* cursor stuff */
int sc_cur_x;
@@ -213,6 +220,10 @@
};
static void crmfb_setup_ddc(struct crmfb_softc *);
+/* mode setting stuff */
+static uint32_t calc_pll(int); /* frequency in kHz */
+static int crmfb_set_mode(struct crmfb_softc *, const struct videomode *);
+
CFATTACH_DECL_NEW(crmfb, sizeof(struct crmfb_softc),
crmfb_match, crmfb_attach, NULL, NULL);
@@ -254,8 +265,6 @@
if (rv)
panic("crmfb_attach: can't map rendering engine");
- //crmfb_setup_ddc(sc);
-
/* determine mode configured by firmware */
d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_HCMAP);
sc->sc_width = (d >> CRMFB_VT_HCMAP_ON_SHIFT) & 0xfff;
@@ -280,6 +289,12 @@
aprint_normal_dev(sc->sc_dev, "initial resolution %dx%d\n",
sc->sc_width, sc->sc_height);
+ crmfb_setup_ddc(sc);
+ if ((sc->sc_edid_info.edid_preferred_mode != NULL)) {
+ if (crmfb_set_mode(sc, sc->sc_edid_info.edid_preferred_mode))
+ aprint_normal_dev(sc->sc_dev, "using %dx%d\n",
+ sc->sc_width, sc->sc_height);
+ }
/*
* first determine how many tiles we need
* in 32bit each tile is 128x128 pixels
@@ -381,7 +396,6 @@
sc->sc_hot_x = 0;
sc->sc_hot_y = 0;
- crmfb_setup_ddc(sc);
return;
}
@@ -798,7 +812,7 @@
{
uint64_t reg;
uint32_t d, h, mode, page;
- int i, bail, tile_width, tlbptr, lptr, j, tx, shift;
+ int i, bail, tile_width, tlbptr, lptr, j, tx, shift, overhang;
const char *wantsync;
uint16_t v;
@@ -811,7 +825,7 @@
d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
DELAY(50000);
- crmfb_write_reg(sc, CRMFB_DID_CONTROL, 0);
+ crmfb_write_reg(sc, CRMFB_DID_CONTROL, d);
DELAY(50000);
if (!crmfb_wait_dma_idle(sc))
@@ -875,8 +889,16 @@
d = ((int)(sc->sc_width / tile_width)) <<
CRMFB_FRM_TILESIZE_WIDTH_SHIFT;
- if ((sc->sc_width & (tile_width - 1)) != 0)
- d |= sc->sc_tiles_y;
+ overhang = sc->sc_width % tile_width;
+ if (overhang != 0) {
+ uint32_t val;
+ DPRINTF("tile width: %d\n", tile_width);
+ DPRINTF("overhang: %d\n", overhang);
+ val = (overhang * (depth >> 3)) >> 5;
+ DPRINTF("reg: %08x\n", val);
+ d |= (val & 0x1f);
+ DPRINTF("d: %08x\n", d);
+ }
switch (depth) {
case 8:
@@ -903,17 +925,17 @@
crmfb_write_reg(sc, CRMFB_OVR_WIDTH_TILE, 0);
crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, 0);
- /* enable drawing again */
- d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
- d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
- crmfb_write_reg(sc, CRMFB_DOTCLOCK, d);
- crmfb_write_reg(sc, CRMFB_VT_XY, 0);
-
/* turn on DMA for the framebuffer */
d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
+ /* enable drawing again */
+ crmfb_write_reg(sc, CRMFB_VT_XY, 0);
+ d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
+ d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
+ crmfb_write_reg(sc, CRMFB_DOTCLOCK, d);
+
/* turn off sync-on-green */
wantsync = arcbios_GetEnvironmentVariable("SyncOnGreen");
@@ -932,9 +954,7 @@
tx = ((sc->sc_width + (tile_width - 1)) & ~(tile_width - 1)) /
tile_width;
-#ifdef CRMFB_DEBUG
- printf("tx: %d\n", tx);
-#endif
+ DPRINTF("tx: %d\n", tx);
for (i = 0; i < 16; i++) {
reg = 0;
@@ -948,9 +968,7 @@
bus_space_write_8(sc->sc_iot, sc->sc_reh,
CRIME_RE_TLB_A + tlbptr + lptr,
reg);
-#ifdef CRMFB_DEBUG
- printf("%04x: %016llx\n", tlbptr + lptr, reg);
-#endif
+ DPRINTF("%04x: %016llx\n", tlbptr + lptr, reg);
reg = 0;
lptr += 8;
}
@@ -959,9 +977,7 @@
if (shift != 64) {
bus_space_write_8(sc->sc_iot, sc->sc_reh,
CRIME_RE_TLB_A + tlbptr + lptr, reg);
-#ifdef CRMFB_DEBUG
- printf("%04x: %016llx\n", tlbptr + lptr, reg);
-#endif
+ DPRINTF("%04x: %016llx\n", tlbptr + lptr, reg);
}
tlbptr += 32;
}
@@ -1358,7 +1374,6 @@
{
int i;
char edid_data[128];
- struct edid_info ei;
memset(edid_data, 0, 128);
sc->sc_i2c.ic_cookie = sc;
@@ -1377,8 +1392,8 @@
aprint_debug_dev(sc->sc_dev,
"had to try %d times to get EDID data\n", i);
if (i < 11) {
- edid_parse(edid_data, &ei);
- edid_print(&ei);
+ edid_parse(edid_data, &sc->sc_edid_info);
+ edid_print(&sc->sc_edid_info);
}
}
@@ -1457,3 +1472,143 @@
return i2c_bitbang_write_byte(cookie, val, flags, &crmfb_i2cbb_ops);
}
+
+/* mode setting stuff */
+static uint32_t
+calc_pll(int f_out)
+{
+ uint32_t ret;
+ int f_in = 20000; /* 20MHz in */
+ int M, N, P;
+ int error, div, best = 9999999;
+ int ff1, ff2;
+ int MM = 0, NN = 0, PP = 0, ff = 0;
+
+ /* f_out = M * f_in / (N * (1 << P) */
+
+ for (P = 0; P < 4; P++) {
+ for (N = 64; N > 0; N--) {
+ div = N * (1 << P);
+ M = f_out * div / f_in;
+ if ((M < 257) && (M > 100)) {
+ ff1 = M * f_in / div;
+ ff2 = (M + 1) * f_in / div;
+ error = abs(ff1 - f_out);
+ if (error < best) {
+ MM = M;
+ NN = N;
+ PP = P;
+ ff = ff1;
+ best = error;
+ }
+ error = abs(ff2 - f_out);
+ if ((error < best) && ( M < 256)){
+ MM = M + 1;
+ NN = N;
+ PP = P;
+ ff = ff2;
+ best = error;
+ }
+ }
+ }
+ }
+ DPRINTF("%d: M %d N %d P %d -> %d\n", f_out, MM, NN, PP, ff);
+ /* now shove the parameters into the register's format */
+ ret = (MM - 1) | ((NN - 1) << 8) | (P << 14);
+ return ret;
+}
+
+static int
+crmfb_set_mode(struct crmfb_softc *sc, const struct videomode *mode)
+{
+ uint32_t d, dc;
+ int tmp, diff;
+
+ if ((mode->hdisplay % 32) != 0) {
+ aprint_error_dev(sc->sc_dev, "hdisplay (%d) is not a multiple of 32\n", mode->hdisplay);
+ return FALSE;
+ }
+ if (mode->dot_clock > 140000) {
+ aprint_error_dev(sc->sc_dev, "requested dot clock is too high ( %d MHz )\n", mode->dot_clock / 1000);
+ return FALSE;
+ }
+
+ /* disable DMA */
+ d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL);
+ d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT);
+ crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d);
+ DELAY(50000);
+ d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
+ d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
+ crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
+ DELAY(50000);
+ crmfb_write_reg(sc, CRMFB_DID_CONTROL, d);
+ DELAY(50000);
+
+ if (!crmfb_wait_dma_idle(sc))
+ aprint_error("crmfb: crmfb_wait_dma_idle timed out\n");
+
+ /* ok, now we're good to go */
+ dc = calc_pll(mode->dot_clock);
+
+ crmfb_write_reg(sc, CRMFB_VT_XY, 1 << CRMFB_VT_XY_FREEZE_SHIFT);
+ delay(1000);
+
+ /* set the dot clock pll but don't start it yet */
+ crmfb_write_reg(sc, CRMFB_DOTCLOCK, dc);
+ delay(10000);
+
+ /* pixel counter */
+ d = mode->htotal | (mode->vtotal << 12);
+ crmfb_write_reg(sc, CRMFB_VT_XYMAX, d);
+
+ /* video timings */
+ d = mode->vsync_end | (mode->vsync_start << 12);
+ crmfb_write_reg(sc, CRMFB_VT_VSYNC, d);
+
+ d = mode->hsync_end | (mode->hsync_start << 12);
+ crmfb_write_reg(sc, CRMFB_VT_HSYNC, d);
+
+ d = mode->vtotal | (mode->vdisplay << 12);
+ crmfb_write_reg(sc, CRMFB_VT_VBLANK, d);
+
+ d = (mode->htotal - 5) | ((mode->hdisplay - 5) << 12);
Home |
Main Index |
Thread Index |
Old Index