Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/sparc64 Add EDID and video mode setting support to ...



details:   https://anonhg.NetBSD.org/src/rev/8d21a0d2ba98
branches:  trunk
changeset: 763980:8d21a0d2ba98
user:      jdc <jdc%NetBSD.org@localhost>
date:      Sat Apr 09 19:31:14 2011 +0000

description:
Add EDID and video mode setting support to FFB.

Add definitions for registers related to video modes, and to DDC.  Rename
other registers to be more descriptive.
Add i2c bus routines to read the EDID data via DDC.
Add routines to calculate, and to set, the video mode.

Note, that interlaced and stereo video modes are not supported.

Thanks to Michael Lorenz and Jared McNeill for advice and encouragement,
and to Martin Husemann for testing.

diffstat:

 sys/arch/sparc64/conf/files.sparc64 |    4 +-
 sys/arch/sparc64/dev/ffb.c          |  538 ++++++++++++++++++++++++++++++++++-
 sys/arch/sparc64/dev/ffbreg.h       |   81 ++++-
 sys/arch/sparc64/dev/ffbvar.h       |   16 +-
 4 files changed, 610 insertions(+), 29 deletions(-)

diffs (truncated from 859 to 300 lines):

diff -r d1b597da6bcc -r 8d21a0d2ba98 sys/arch/sparc64/conf/files.sparc64
--- a/sys/arch/sparc64/conf/files.sparc64       Sat Apr 09 18:22:31 2011 +0000
+++ b/sys/arch/sparc64/conf/files.sparc64       Sat Apr 09 19:31:14 2011 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.sparc64,v 1.129 2011/03/20 20:55:46 mrg Exp $
+#      $NetBSD: files.sparc64,v 1.130 2011/04/09 19:31:14 jdc Exp $
 
 # @(#)files.sparc64    8.1 (Berkeley) 7/19/93
 # sparc64-specific configuration info
@@ -168,7 +168,7 @@
 attach cgfourteen at sbus
 file   arch/sparc64/dev/cgfourteen.c   cgfourteen needs-flag
 
-device ffb: wsemuldisplaydev, rasops8, rasops32, fb, vcons
+device ffb: wsemuldisplaydev, rasops8, rasops32, fb, vcons, i2cbus, iic, i2c_bitbang, ddc_read_edid, edid, videomode
 file   arch/sparc64/dev/ffb.c                  ffb
 defflag opt_ffb.h FFB_DEBUG FFB_SYNC
 attach ffb at mainbus,upa with ffb_mainbus
diff -r d1b597da6bcc -r 8d21a0d2ba98 sys/arch/sparc64/dev/ffb.c
--- a/sys/arch/sparc64/dev/ffb.c        Sat Apr 09 18:22:31 2011 +0000
+++ b/sys/arch/sparc64/dev/ffb.c        Sat Apr 09 19:31:14 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ffb.c,v 1.38 2010/09/21 03:31:04 macallan Exp $        */
+/*     $NetBSD: ffb.c,v 1.39 2011/04/09 19:31:15 jdc Exp $     */
 /*     $OpenBSD: creator.c,v 1.20 2002/07/30 19:48:15 jason Exp $      */
 
 /*
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffb.c,v 1.38 2010/09/21 03:31:04 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffb.c,v 1.39 2011/04/09 19:31:15 jdc Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -57,6 +57,10 @@
 #include <dev/wsfont/wsfont.h>
 #include <dev/wscons/wsdisplay_vconsvar.h>
 
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/i2c_bitbang.h>
+#include <dev/i2c/ddcvar.h>
+
 #include <sparc64/dev/ffbreg.h>
 #include <sparc64/dev/ffbvar.h>
 
@@ -74,6 +78,19 @@
 #define SYNC
 #endif
 
+/* Debugging */
+#if !defined FFB_DEBUG
+#define FFB_DEBUG 0
+#endif
+#define DPRINTF(x)     if (ffb_debug) printf x
+/* Patchable */
+extern int ffb_debug;
+#if FFB_DEBUG > 0
+int ffb_debug = 1;
+#else
+int ffb_debug = 0;
+#endif
+
 extern struct cfdriver ffb_cd;
 
 struct wsscreen_descr ffb_stdscreen = {
@@ -136,18 +153,53 @@
        .mmap = ffb_mmap,
 };
 
+/* I2C glue */
+static int ffb_i2c_acquire_bus(void *, int);
+static void ffb_i2c_release_bus(void *, int);
+static int ffb_i2c_send_start(void *, int);
+static int ffb_i2c_send_stop(void *, int);
+static int ffb_i2c_initiate_xfer(void *, i2c_addr_t, int);
+static int ffb_i2c_read_byte(void *, uint8_t *, int);
+static int ffb_i2c_write_byte(void *, uint8_t, int);
+
+/* I2C bitbang glue */
+static void ffb_i2cbb_set_bits(void *, uint32_t);
+static void ffb_i2cbb_set_dir(void *, uint32_t);
+static uint32_t ffb_i2cbb_read(void *);
+
+static const struct i2c_bitbang_ops ffb_i2cbb_ops = {
+       ffb_i2cbb_set_bits,
+       ffb_i2cbb_set_dir,
+       ffb_i2cbb_read,
+       {
+               FFB_DAC_CFG_MPDATA_SDA,
+               FFB_DAC_CFG_MPDATA_SCL,
+               0,
+               0
+       }
+};
+
+void ffb_attach_i2c(struct ffb_softc *);
+
+/* Video mode setting */
+int ffb_tgc_disable(struct ffb_softc *);
+void ffb_get_pclk(int, uint32_t *, int *);
+int ffb_set_vmode(struct ffb_softc *, struct videomode *, int, int *, int *);
+
+
 void
 ffb_attach(struct ffb_softc *sc)
 {
        struct wsemuldisplaydev_attach_args waa;
        struct rasops_info *ri;
        long defattr;
-       const char *model;
+       const char *model, *out_dev;
        int btype;
        uint32_t dac;
        int maxrow, maxcol;
        u_int blank = WSDISPLAYIO_VIDEO_ON;
        char buf[6+1];
+       int i, try_edid;
 
        printf(":");
                
@@ -157,8 +209,10 @@
                        printf(" Creator3D");
                else
                        printf(" Creator");
-       } else
+       } else {
                printf(" Elite3D");
+               btype = 0;
+       }
 
        model = prom_getpropstring(sc->sc_node, "model");
        if (model == NULL || strlen(model) == 0)
@@ -166,6 +220,7 @@
 
        sc->sc_depth = 24;
        sc->sc_linebytes = 8192;
+       /* We might alter these during EDID mode setting */
        sc->sc_height = prom_getpropint(sc->sc_node, "height", 0);
        sc->sc_width = prom_getpropint(sc->sc_node, "width", 0);
        
@@ -180,10 +235,8 @@
                ? strtoul(buf, NULL, 10)
                : 34;
 
-       ffb_ras_init(sc);
-
        /* collect DAC version, as Elite3D cursor enable bit is reversed */
-       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GVERS);
+       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_DEVID);
        dac = DAC_READ(sc, FFB_DAC_VALUE);
        sc->sc_dacrev = (dac >> 28) & 0xf;
 
@@ -204,6 +257,63 @@
                printf("%s: found old DAC, enabling redraw on unblank\n", 
                    device_xname(&sc->sc_dv));
 
+       /* Check if a console resolution "<device>:r<res>" is set. */
+       if (sc->sc_console) {
+               out_dev = prom_getpropstring(sc->sc_node, "output_device");
+               if (out_dev != NULL && strlen(out_dev) != 0 &&
+                   strstr(out_dev, ":r") != NULL)
+                       try_edid = 0;
+               else
+                       try_edid = 1;
+       } else
+               try_edid = 1;
+
+       ffb_attach_i2c(sc);
+
+       /* Need to set asynchronous blank during DDC write/read */
+       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL);
+       dac = DAC_READ(sc, FFB_DAC_VALUE);
+       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL);
+       DAC_WRITE(sc, FFB_DAC_VALUE, dac | FFB_DAC_USR_CTRL_BLANK);
+
+       /* Some monitors don't respond first time */
+       i = 0;
+       while (sc->sc_edid_data[1] == 0 && i++ < 3)
+               ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, EDID_DATA_LEN);
+
+       /* Remove asynchronous blank */
+       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL);
+       DAC_WRITE(sc, FFB_DAC_VALUE, dac);
+
+       if (edid_parse(&sc->sc_edid_data[0], &sc->sc_edid_info) != -1) {
+               sort_modes(sc->sc_edid_info.edid_modes,
+                   &sc->sc_edid_info.edid_preferred_mode,
+                   sc->sc_edid_info.edid_nmodes);
+               DPRINTF(("%s: EDID data:\n  ", device_xname(&sc->sc_dv)));
+               for (i = 0; i < EDID_DATA_LEN; i++) {
+                       if (i && !(i % 32))
+                               DPRINTF(("\n "));
+                       if (i && !(i % 4))
+                               DPRINTF((" "));
+                       DPRINTF(("%02x", sc->sc_edid_data[i]));
+               }
+               DPRINTF(("\n"));
+               if (ffb_debug)
+                       edid_print(&sc->sc_edid_info);
+
+               if (try_edid)
+                       for (i = 0; i < sc->sc_edid_info.edid_nmodes; i++) {
+                               if (ffb_set_vmode(sc,
+                                   &(sc->sc_edid_info.edid_modes[i]), btype,
+                                   &(sc->sc_width), &(sc->sc_height)))
+                                       break;
+                       }
+       } else {
+               DPRINTF(("%s: No EDID data.\n", device_xname(&sc->sc_dv)));
+       }
+               
+       ffb_ras_init(sc);
+
        ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank);
 
        sc->sc_accel = ((device_cfdata(&sc->sc_dv)->cf_flags &
@@ -261,6 +371,27 @@
        config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint);
 }
 
+void
+ffb_attach_i2c(struct ffb_softc *sc)
+{
+       struct i2cbus_attach_args iba;
+
+       /* Fill in the i2c tag */
+       sc->sc_i2c.ic_cookie = sc;
+       sc->sc_i2c.ic_acquire_bus = ffb_i2c_acquire_bus;
+       sc->sc_i2c.ic_release_bus = ffb_i2c_release_bus;
+       sc->sc_i2c.ic_send_start = ffb_i2c_send_start;
+       sc->sc_i2c.ic_send_stop = ffb_i2c_send_stop;
+       sc->sc_i2c.ic_initiate_xfer = ffb_i2c_initiate_xfer;
+       sc->sc_i2c.ic_read_byte = ffb_i2c_read_byte;
+       sc->sc_i2c.ic_write_byte = ffb_i2c_write_byte;
+       sc->sc_i2c.ic_exec = NULL;
+
+       /* Attach I2C bus */
+       bzero(&iba, sizeof(iba));
+       iba.iba_tag = &sc->sc_i2c;
+}
+
 int
 ffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, struct lwp *l)
 {
@@ -268,13 +399,11 @@
        struct ffb_softc *sc = vd->cookie;
        struct wsdisplay_fbinfo *wdf;
        struct vcons_screen *ms = vd->active;
-       
-#ifdef FFB_DEBUG
-       printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
+
+       DPRINTF(("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
               device_xname(&sc->sc_dv),
               (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "",
-              (char)IOCGROUP(cmd), cmd & 0xff);
-#endif
+              (char)IOCGROUP(cmd), cmd & 0xff));
 
        switch (cmd) {
        case FBIOGTYPE:
@@ -362,7 +491,7 @@
                return EIO; /* not supported yet */
        default:
                return EPASSTHROUGH;
-        }
+       }
 
        return (0);
 }
@@ -374,7 +503,7 @@
        struct vcons_screen *ms = sc->vd.active;
        u_int val;
        
-       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
+       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC);
        val = DAC_READ(sc, FFB_DAC_VALUE);
 
        switch (cmd) {
@@ -394,7 +523,7 @@
                return(EINVAL);
        }
 
-       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
+       DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC);
        DAC_WRITE(sc, FFB_DAC_VALUE, val);
        
        if ((val & 1) && sc->sc_needredraw) {
@@ -477,13 +606,23 @@
 void
 ffb_ras_init(struct ffb_softc *sc)
 {
+       uint32_t fbc;
+
+       if (sc->sc_width > 1280) {
+       DPRINTF(("ffb_ras_init: high resolution.\n"));
+               fbc = FFB_FBC_WB_B | FFB_FBC_WM_COMBINED | FFB_FBC_WE_FORCEON |
+                   FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF | FFB_FBC_XE_ON;



Home | Main Index | Thread Index | Old Index