Module Name: src Committed By: snj Date: Tue Nov 18 18:19:10 UTC 2014
Modified Files: src/sys/arch/arm/allwinner [netbsd-7]: awin_hdmi.c awin_hdmiaudio.c awin_var.h src/sys/arch/evbarm/awin [netbsd-7]: awin_machdep.c src/sys/dev/i2c [netbsd-7]: ddc.c ddcvar.h src/sys/dev/videomode [netbsd-7]: edid.c edidreg.h edidvar.h Log Message: Pull up following revision(s) (requested by jmcneill in ticket #244): sys/arch/arm/allwinner/awin_hdmi.c: revision 1.13-1.15 sys/arch/arm/allwinner/awin_hdmiaudio.c: revision 1.4 sys/arch/arm/allwinner/awin_var.h: revision 1.25 sys/arch/evbarm/awin/awin_machdep.c: revision 1.29 sys/dev/i2c/ddc.c: revision 1.4 sys/dev/i2c/ddcvar.h: revision 1.2 sys/dev/videomode/edid.c: revision 1.13 sys/dev/videomode/edidreg.h: revision 1.4 sys/dev/videomode/edidvar.h: revision 1.3 Parse the extension block count field, and make it available in struct edid_info -- add ddc_read_edid_block, which is the same as ddc_read_edid but takes an additional block number argument -- Add support for DVI displays. Detect HDMI vs DVI mode by looking for a CEA-861-D extension block in the EDID, and then searching this block for an HDMI vendor-specific data block (HDMI VSDB). -- Allow for overriding DVI/HDMI detection with a kernel boot arg. Set hdmi.forcemode=dvi or hdmi.forcemode=hdmi to disable auto-detection. -- report hotplug status for AUDIO_GETDEV fields, only allow playback if a capable display is connected -- clear repeater sel bits before setting -- would cause an issue if we ever switched away from a pixel doubling mode To generate a diff of this commit: cvs rdiff -u -r1.4.2.4 -r1.4.2.5 src/sys/arch/arm/allwinner/awin_hdmi.c cvs rdiff -u -r1.3.2.2 -r1.3.2.3 src/sys/arch/arm/allwinner/awin_hdmiaudio.c cvs rdiff -u -r1.10.2.4 -r1.10.2.5 src/sys/arch/arm/allwinner/awin_var.h cvs rdiff -u -r1.8.2.7 -r1.8.2.8 src/sys/arch/evbarm/awin/awin_machdep.c cvs rdiff -u -r1.3 -r1.3.62.1 src/sys/dev/i2c/ddc.c cvs rdiff -u -r1.1 -r1.1.138.1 src/sys/dev/i2c/ddcvar.h cvs rdiff -u -r1.12 -r1.12.12.1 src/sys/dev/videomode/edid.c cvs rdiff -u -r1.3 -r1.3.30.1 src/sys/dev/videomode/edidreg.h cvs rdiff -u -r1.2 -r1.2.138.1 src/sys/dev/videomode/edidvar.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/arm/allwinner/awin_hdmi.c diff -u src/sys/arch/arm/allwinner/awin_hdmi.c:1.4.2.4 src/sys/arch/arm/allwinner/awin_hdmi.c:1.4.2.5 --- src/sys/arch/arm/allwinner/awin_hdmi.c:1.4.2.4 Fri Nov 14 13:37:39 2014 +++ src/sys/arch/arm/allwinner/awin_hdmi.c Tue Nov 18 18:19:09 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: awin_hdmi.c,v 1.4.2.4 2014/11/14 13:37:39 martin Exp $ */ +/* $NetBSD: awin_hdmi.c,v 1.4.2.5 2014/11/18 18:19:09 snj Exp $ */ /*- * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> @@ -32,7 +32,7 @@ #define AWIN_HDMI_PLL 3 /* PLL7 or PLL3 */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.4.2.4 2014/11/14 13:37:39 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.4.2.5 2014/11/18 18:19:09 snj Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -64,6 +64,14 @@ struct awin_hdmi_softc { kmutex_t sc_ic_lock; bool sc_connected; + char sc_display_vendor[16]; + char sc_display_product[16]; + + u_int sc_display_mode; + u_int sc_current_display_mode; +#define DISPLAY_MODE_AUTO 0 +#define DISPLAY_MODE_HDMI 1 +#define DISPLAY_MODE_DVI 2 uint32_t sc_ver; unsigned int sc_i2c_blklen; @@ -85,17 +93,19 @@ static int awin_hdmi_i2c_acquire_bus(voi static void awin_hdmi_i2c_release_bus(void *, int); static int awin_hdmi_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int); -static int awin_hdmi_i2c_xfer(void *, i2c_addr_t, uint8_t, +static int awin_hdmi_i2c_xfer(void *, i2c_addr_t, uint8_t, uint8_t, size_t, int, int); static int awin_hdmi_i2c_reset(struct awin_hdmi_softc *, int); static void awin_hdmi_enable(struct awin_hdmi_softc *); static void awin_hdmi_read_edid(struct awin_hdmi_softc *); +static u_int awin_hdmi_get_display_mode(struct awin_hdmi_softc *, + const struct edid_info *); static void awin_hdmi_video_enable(struct awin_hdmi_softc *, bool); static void awin_hdmi_set_videomode(struct awin_hdmi_softc *, - const struct videomode *); + const struct videomode *, u_int); static void awin_hdmi_set_audiomode(struct awin_hdmi_softc *, - const struct videomode *); + const struct videomode *, u_int); static void awin_hdmi_hpd(struct awin_hdmi_softc *); static void awin_hdmi_thread(void *); #if 0 @@ -127,6 +137,7 @@ awin_hdmi_attach(device_t parent, device struct awin_hdmi_softc *sc = device_private(self); struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; + prop_dictionary_t cfg = device_properties(self); uint32_t ver, clk; sc->sc_dev = self; @@ -172,6 +183,15 @@ awin_hdmi_attach(device_t parent, device sc->sc_ver = ver; sc->sc_i2c_blklen = 16; + const char *display_mode = NULL; + prop_dictionary_get_cstring_nocopy(cfg, "display-mode", &display_mode); + if (display_mode) { + if (strcasecmp(display_mode, "hdmi") == 0) + sc->sc_display_mode = DISPLAY_MODE_HDMI; + else if (strcasecmp(display_mode, "dvi") == 0) + sc->sc_display_mode = DISPLAY_MODE_DVI; + } + #if 0 sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL, awin_hdmi_intr, sc); @@ -237,6 +257,7 @@ awin_hdmi_i2c_exec(void *priv, i2c_op_t { struct awin_hdmi_softc *sc = priv; uint8_t *pbuf; + uint8_t block; int resid; off_t off; int err; @@ -251,14 +272,15 @@ awin_hdmi_i2c_exec(void *priv, i2c_op_t if (err) goto done; - off = *(const uint8_t *)cmdbuf; + block = *(const uint8_t *)cmdbuf; + off = (block & 1) ? 128 : 0; pbuf = buf; resid = len; while (resid > 0) { size_t blklen = min(resid, sc->sc_i2c_blklen); - err = awin_hdmi_i2c_xfer(sc, addr, off, blklen, + err = awin_hdmi_i2c_xfer(sc, addr, block >> 1, off, blklen, AWIN_HDMI_DDC_COMMAND_ACCESS_CMD_EOREAD, flags); if (err) goto done; @@ -288,7 +310,7 @@ done: } static int -awin_hdmi_i2c_xfer_1_3(void *priv, i2c_addr_t addr, uint8_t reg, +awin_hdmi_i2c_xfer_1_3(void *priv, i2c_addr_t addr, uint8_t block, uint8_t reg, size_t len, int type, int flags) { struct awin_hdmi_softc *sc = priv; @@ -299,7 +321,8 @@ awin_hdmi_i2c_xfer_1_3(void *priv, i2c_a val &= ~AWIN_HDMI_DDC_CTRL_FIFO_DIR; HDMI_WRITE(sc, AWIN_HDMI_DDC_CTRL_REG, val); - val = __SHIFTIN(0x60, AWIN_HDMI_DDC_SLAVE_ADDR_1); + val |= __SHIFTIN(block, AWIN_HDMI_DDC_SLAVE_ADDR_0); + val |= __SHIFTIN(0x60, AWIN_HDMI_DDC_SLAVE_ADDR_1); val |= __SHIFTIN(reg, AWIN_HDMI_DDC_SLAVE_ADDR_2); val |= __SHIFTIN(addr, AWIN_HDMI_DDC_SLAVE_ADDR_3); HDMI_WRITE(sc, AWIN_HDMI_DDC_SLAVE_ADDR_REG, val); @@ -336,7 +359,7 @@ awin_hdmi_i2c_xfer_1_3(void *priv, i2c_a } static int -awin_hdmi_i2c_xfer_1_4(void *priv, i2c_addr_t addr, uint8_t reg, +awin_hdmi_i2c_xfer_1_4(void *priv, i2c_addr_t addr, uint8_t block, uint8_t reg, size_t len, int type, int flags) { struct awin_hdmi_softc *sc = priv; @@ -347,7 +370,7 @@ awin_hdmi_i2c_xfer_1_4(void *priv, i2c_a val |= AWIN_A31_HDMI_DDC_FIFO_CTRL_RST; HDMI_WRITE(sc, AWIN_A31_HDMI_DDC_FIFO_CTRL_REG, val); - val = __SHIFTIN(0, AWIN_A31_HDMI_DDC_SLAVE_ADDR_SEG_PTR); + val = __SHIFTIN(block, AWIN_A31_HDMI_DDC_SLAVE_ADDR_SEG_PTR); val |= __SHIFTIN(0x60, AWIN_A31_HDMI_DDC_SLAVE_ADDR_DDC_CMD); val |= __SHIFTIN(reg, AWIN_A31_HDMI_DDC_SLAVE_ADDR_OFF_ADR); val |= __SHIFTIN(addr, AWIN_A31_HDMI_DDC_SLAVE_ADDR_DEV_ADR); @@ -378,16 +401,18 @@ awin_hdmi_i2c_xfer_1_4(void *priv, i2c_a } static int -awin_hdmi_i2c_xfer(void *priv, i2c_addr_t addr, uint8_t reg, +awin_hdmi_i2c_xfer(void *priv, i2c_addr_t addr, uint8_t block, uint8_t reg, size_t len, int type, int flags) { struct awin_hdmi_softc *sc = priv; int rv; if (HDMI_1_3_P(sc)) { - rv = awin_hdmi_i2c_xfer_1_3(priv, addr, reg, len, type, flags); + rv = awin_hdmi_i2c_xfer_1_3(priv, addr, block, reg, len, + type, flags); } else { - rv = awin_hdmi_i2c_xfer_1_4(priv, addr, reg, len, type, flags); + rv = awin_hdmi_i2c_xfer_1_4(priv, addr, block, reg, len, + type, flags); } return rv; @@ -468,12 +493,13 @@ awin_hdmi_read_edid(struct awin_hdmi_sof char edid[128]; struct edid_info ei; int retry = 4; + u_int display_mode; memset(edid, 0, sizeof(edid)); memset(&ei, 0, sizeof(ei)); while (--retry > 0) { - if (ddc_read_edid(&sc->sc_ic, edid, sizeof(edid)) == 0) + if (!ddc_read_edid_block(&sc->sc_ic, edid, sizeof(edid), 0)) break; } if (retry == 0) { @@ -489,6 +515,22 @@ awin_hdmi_read_edid(struct awin_hdmi_sof #endif } + if (sc->sc_display_mode == DISPLAY_MODE_AUTO) + display_mode = awin_hdmi_get_display_mode(sc, &ei); + else + display_mode = sc->sc_display_mode; + + const char *forced = sc->sc_display_mode == DISPLAY_MODE_AUTO ? + "auto-detected" : "forced"; + device_printf(sc->sc_dev, "%s mode (%s)\n", + display_mode == DISPLAY_MODE_HDMI ? "HDMI" : "DVI", forced); + + strlcpy(sc->sc_display_vendor, ei.edid_vendorname, + sizeof(sc->sc_display_vendor)); + strlcpy(sc->sc_display_product, ei.edid_productname, + sizeof(sc->sc_display_product)); + sc->sc_current_display_mode = display_mode; + mode = ei.edid_preferred_mode; if (mode == NULL) mode = pick_mode_by_ref(640, 480, 60); @@ -500,8 +542,8 @@ awin_hdmi_read_edid(struct awin_hdmi_sof awin_debe_set_videomode(mode); awin_tcon_set_videomode(mode); - awin_hdmi_set_videomode(sc, mode); - awin_hdmi_set_audiomode(sc, mode); + awin_hdmi_set_videomode(sc, mode, display_mode); + awin_hdmi_set_audiomode(sc, mode, display_mode); awin_debe_enable(true); delay(20000); awin_tcon_enable(true); @@ -510,6 +552,90 @@ awin_hdmi_read_edid(struct awin_hdmi_sof } } +static u_int +awin_hdmi_get_display_mode(struct awin_hdmi_softc *sc, + const struct edid_info *ei) +{ + char edid[128]; + bool found_hdmi = false; + unsigned int n, p; + + /* + * Scan through extension blocks, looking for a CEA-861-D v3 + * block. If an HDMI Vendor-Specific Data Block (HDMI VSDB) is + * found in that, assume HDMI mode. + */ + for (n = 1; n <= MIN(ei->edid_ext_block_count, 4); n++) { + if (ddc_read_edid_block(&sc->sc_ic, edid, sizeof(edid), n)) { +#ifdef AWIN_HDMI_DEBUG + device_printf(sc->sc_dev, + "Failed to read EDID block %d\n", n); +#endif + break; + } + +#ifdef AWIN_HDMI_DEBUG + device_printf(sc->sc_dev, "EDID block #%d:\n", n); +#endif + + const uint8_t tag = edid[0]; + const uint8_t rev = edid[1]; + const uint8_t off = edid[2]; + +#ifdef AWIN_HDMI_DEBUG + device_printf(sc->sc_dev, " Tag %d, Revision %d, Offset %d\n", + tag, rev, off); + device_printf(sc->sc_dev, " Flags: 0x%02x\n", edid[3]); +#endif + + /* We are looking for a CEA-861-D tag (02h) with revision 3 */ + if (tag != 0x02 || rev != 3) + continue; + /* + * CEA data block collection starts at byte 4, so the + * DTD blocks must start after it. + */ + if (off <= 4) + continue; + + /* Parse the CEA data blocks */ + for (p = 4; p < off;) { + const uint8_t btag = (edid[p] >> 5) & 0x7; + const uint8_t blen = edid[p] & 0x1f; + +#ifdef AWIN_HDMI_DEBUG + device_printf(sc->sc_dev, " CEA data block @ %d\n", p); + device_printf(sc->sc_dev, " Tag %d, Length %d\n", + btag, blen); +#endif + + /* Make sure the length is sane */ + if (p + blen + 1 > off) + break; + /* Looking for a VSDB tag */ + if (btag != 3) + goto next_block; + /* HDMI VSDB is at least 5 bytes long */ + if (blen < 5) + goto next_block; + +#ifdef AWIN_HDMI_DEBUG + device_printf(sc->sc_dev, " ID: %02x%02x%02x\n", + edid[p + 1], edid[p + 2], edid[p + 3]); +#endif + + /* HDMI 24-bit IEEE registration ID is 0x000C03 */ + if (memcmp(&edid[p + 1], "\x03\x0c\x00", 3) == 0) + found_hdmi = true; + +next_block: + p += (1 + blen); + } + } + + return found_hdmi ? DISPLAY_MODE_HDMI : DISPLAY_MODE_DVI; +} + static void awin_hdmi_video_enable(struct awin_hdmi_softc *sc, bool enable) { @@ -538,7 +664,7 @@ awin_hdmi_video_enable(struct awin_hdmi_ static void awin_hdmi_set_videomode(struct awin_hdmi_softc *sc, - const struct videomode *mode) + const struct videomode *mode, u_int display_mode) { uint32_t val; const u_int dblscan_p = !!(mode->flags & VID_DBLSCAN); @@ -603,13 +729,20 @@ awin_hdmi_set_videomode(struct awin_hdmi #endif val = HDMI_READ(sc, AWIN_HDMI_VID_CTRL_REG); - val |= __SHIFTIN(AWIN_HDMI_VID_CTRL_HDMI_MODE_HDMI, - AWIN_HDMI_VID_CTRL_HDMI_MODE); - val &= ~AWIN_HDMI_VID_CTRL_OUTPUT_FMT; + val &= ~AWIN_HDMI_VID_CTRL_HDMI_MODE; + if (display_mode == DISPLAY_MODE_DVI) { + val |= __SHIFTIN(AWIN_HDMI_VID_CTRL_HDMI_MODE_DVI, + AWIN_HDMI_VID_CTRL_HDMI_MODE); + } else { + val |= __SHIFTIN(AWIN_HDMI_VID_CTRL_HDMI_MODE_HDMI, + AWIN_HDMI_VID_CTRL_HDMI_MODE); + } + val &= ~AWIN_HDMI_VID_CTRL_REPEATER_SEL; if (dblscan_p) { val |= __SHIFTIN(AWIN_HDMI_VID_CTRL_REPEATER_SEL_2X, AWIN_HDMI_VID_CTRL_REPEATER_SEL); } + val &= ~AWIN_HDMI_VID_CTRL_OUTPUT_FMT; if (interlace_p) { val |= __SHIFTIN(AWIN_HDMI_VID_CTRL_OUTPUT_FMT_INTERLACE, AWIN_HDMI_VID_CTRL_OUTPUT_FMT); @@ -658,7 +791,7 @@ awin_hdmi_set_videomode(struct awin_hdmi static void awin_hdmi_set_audiomode(struct awin_hdmi_softc *sc, - const struct videomode *mode) + const struct videomode *mode, u_int display_mode) { uint32_t cts, n, val; @@ -675,6 +808,11 @@ awin_hdmi_set_audiomode(struct awin_hdmi val = HDMI_READ(sc, AWIN_HDMI_AUD_CTRL_REG); } while (val & AWIN_HDMI_AUD_CTRL_RST); + /* No audio support in DVI mode */ + if (display_mode != DISPLAY_MODE_HDMI) { + return; + } + /* DMA & FIFO control */ val = HDMI_READ(sc, AWIN_HDMI_ADMA_CTRL_REG); if (awin_chip_id() == AWIN_CHIP_ID_A31) { @@ -740,7 +878,6 @@ awin_hdmi_hpd(struct awin_hdmi_softc *sc if (sc->sc_connected == con) return; - sc->sc_connected = con; if (con) { device_printf(sc->sc_dev, "display connected\n"); awin_hdmi_read_edid(sc); @@ -748,6 +885,8 @@ awin_hdmi_hpd(struct awin_hdmi_softc *sc device_printf(sc->sc_dev, "display disconnected\n"); awin_tcon_set_videomode(NULL); } + + sc->sc_connected = con; } static void @@ -780,6 +919,32 @@ awin_hdmi_intr(void *priv) } #endif +void +awin_hdmi_get_info(struct awin_hdmi_info *info) +{ + struct awin_hdmi_softc *sc; + device_t dev; + + memset(info, 0, sizeof(*info)); + + dev = device_find_by_driver_unit("awinhdmi", 0); + if (dev == NULL) { + info->display_connected = false; + return; + } + sc = device_private(dev); + + info->display_connected = sc->sc_connected; + if (info->display_connected) { + strlcpy(info->display_vendor, sc->sc_display_vendor, + sizeof(info->display_vendor)); + strlcpy(info->display_product, sc->sc_display_product, + sizeof(info->display_product)); + info->display_hdmimode = + sc->sc_current_display_mode == DISPLAY_MODE_HDMI; + } +} + #if defined(DDB) void awin_hdmi_dump_regs(void) Index: src/sys/arch/arm/allwinner/awin_hdmiaudio.c diff -u src/sys/arch/arm/allwinner/awin_hdmiaudio.c:1.3.2.2 src/sys/arch/arm/allwinner/awin_hdmiaudio.c:1.3.2.3 --- src/sys/arch/arm/allwinner/awin_hdmiaudio.c:1.3.2.2 Fri Nov 14 13:37:39 2014 +++ src/sys/arch/arm/allwinner/awin_hdmiaudio.c Tue Nov 18 18:19:09 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: awin_hdmiaudio.c,v 1.3.2.2 2014/11/14 13:37:39 martin Exp $ */ +/* $NetBSD: awin_hdmiaudio.c,v 1.3.2.3 2014/11/18 18:19:09 snj Exp $ */ /*- * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: awin_hdmiaudio.c,v 1.3.2.2 2014/11/14 13:37:39 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: awin_hdmiaudio.c,v 1.3.2.3 2014/11/18 18:19:09 snj Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -538,14 +538,35 @@ static int awin_hdmiaudio_getdev(void *priv, struct audio_device *audiodev) { struct awin_hdmiaudio_softc *sc = priv; + struct awin_hdmi_info info; + const char *vendor = NULL, *product = NULL; const int vmaj = __SHIFTOUT(sc->sc_ver, AWIN_HDMI_VERSION_ID_H); const int vmin = __SHIFTOUT(sc->sc_ver, AWIN_HDMI_VERSION_ID_L); - snprintf(audiodev->name, sizeof(audiodev->name), "Allwinner"); - snprintf(audiodev->version, sizeof(audiodev->version), + awin_hdmi_get_info(&info); + + if (info.display_connected && info.display_hdmimode) { + if (strlen(info.display_vendor) > 0 && + strlen(info.display_product) > 0) { + vendor = info.display_vendor; + product = info.display_product; + } else { + vendor = "HDMI"; + product = ""; + } + } else if (info.display_connected) { + vendor = "DVI"; + product = "(unsupported)"; + } else { + vendor = "HDMI"; + product = "(disconnected)"; + } + + strlcpy(audiodev->name, vendor, sizeof(audiodev->name)); + strlcpy(audiodev->version, product, sizeof(audiodev->version)); + snprintf(audiodev->config, sizeof(audiodev->config), "HDMI %d.%d", vmaj, vmin); - snprintf(audiodev->config, sizeof(audiodev->config), "awin_hdmiaudio"); return 0; } @@ -574,11 +595,16 @@ awin_hdmiaudio_trigger_output(void *priv { struct awin_hdmiaudio_softc *sc = priv; struct awin_hdmiaudio_dma *dma; + struct awin_hdmi_info info; bus_addr_t pstart; bus_size_t psize; uint32_t dmacfg; int error; + awin_hdmi_get_info(&info); + if (info.display_connected == false || info.display_hdmimode == false) + return ENXIO; + pstart = 0; psize = (uintptr_t)end - (uintptr_t)start; Index: src/sys/arch/arm/allwinner/awin_var.h diff -u src/sys/arch/arm/allwinner/awin_var.h:1.10.2.4 src/sys/arch/arm/allwinner/awin_var.h:1.10.2.5 --- src/sys/arch/arm/allwinner/awin_var.h:1.10.2.4 Sat Nov 15 11:31:40 2014 +++ src/sys/arch/arm/allwinner/awin_var.h Tue Nov 18 18:19:09 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: awin_var.h,v 1.10.2.4 2014/11/15 11:31:40 martin Exp $ */ +/* $NetBSD: awin_var.h,v 1.10.2.5 2014/11/18 18:19:09 snj Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * All rights reserved. @@ -132,6 +132,15 @@ void awin_tcon_enable(bool); void awin_debe_set_videomode(const struct videomode *); void awin_debe_enable(bool); int awin_debe_ioctl(device_t, u_long, void *); + +struct awin_hdmi_info { + bool display_connected; + char display_vendor[16]; + char display_product[16]; + bool display_hdmimode; +}; +void awin_hdmi_get_info(struct awin_hdmi_info *); + void awin_fb_set_videomode(device_t, u_int, u_int); void awin_fb_ddb_trap_callback(int); Index: src/sys/arch/evbarm/awin/awin_machdep.c diff -u src/sys/arch/evbarm/awin/awin_machdep.c:1.8.2.7 src/sys/arch/evbarm/awin/awin_machdep.c:1.8.2.8 --- src/sys/arch/evbarm/awin/awin_machdep.c:1.8.2.7 Fri Nov 14 22:23:28 2014 +++ src/sys/arch/evbarm/awin/awin_machdep.c Tue Nov 18 18:19:09 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: awin_machdep.c,v 1.8.2.7 2014/11/14 22:23:28 martin Exp $ */ +/* $NetBSD: awin_machdep.c,v 1.8.2.8 2014/11/18 18:19:09 snj Exp $ */ /* * Machine dependent functions for kernel setup for TI OSK5912 board. @@ -125,7 +125,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: awin_machdep.c,v 1.8.2.7 2014/11/14 22:23:28 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: awin_machdep.c,v 1.8.2.8 2014/11/18 18:19:09 snj Exp $"); #include "opt_machdep.h" #include "opt_ddb.h" @@ -769,6 +769,20 @@ awin_device_register(device_t self, void } } + if (device_is_a(self, "awinhdmi")) { + char *display_mode; + if (get_bootconf_option(boot_args, "hdmi.forcemode", + BOOTOPT_TYPE_STRING, &display_mode)) { + if (strcasecmp(display_mode, "hdmi") == 0) { + prop_dictionary_set_cstring(dict, + "display-mode", "hdmi"); + } else if (strcasecmp(display_mode, "dvi") == 0) { + prop_dictionary_set_cstring(dict, + "display-mode", "dvi"); + } + } + } + #if NGENFB > 0 if (device_is_a(self, "genfb")) { #ifdef DDB Index: src/sys/dev/i2c/ddc.c diff -u src/sys/dev/i2c/ddc.c:1.3 src/sys/dev/i2c/ddc.c:1.3.62.1 --- src/sys/dev/i2c/ddc.c:1.3 Sun May 4 15:26:29 2008 +++ src/sys/dev/i2c/ddc.c Tue Nov 18 18:19:10 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ddc.c,v 1.3 2008/05/04 15:26:29 xtraeme Exp $ */ +/* $NetBSD: ddc.c,v 1.3.62.1 2014/11/18 18:19:10 snj Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ddc.c,v 1.3 2008/05/04 15:26:29 xtraeme Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ddc.c,v 1.3.62.1 2014/11/18 18:19:10 snj Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -91,12 +91,18 @@ ddc_attach(device_t parent, device_t sel int ddc_read_edid(i2c_tag_t tag, uint8_t *dest, size_t len) { + return ddc_read_edid_block(tag, dest, len, DDC_EDID_START); +} + +int +ddc_read_edid_block(i2c_tag_t tag, uint8_t *dest, size_t len, uint8_t block) +{ uint8_t wbuf[2]; if (iic_acquire_bus(tag, I2C_F_POLL) != 0) return -1; - wbuf[0] = DDC_EDID_START; /* start address */ + wbuf[0] = block; /* start address */ if (iic_exec(tag, I2C_OP_READ_WITH_STOP, DDC_ADDR, wbuf, 1, dest, len, I2C_F_POLL)) { Index: src/sys/dev/i2c/ddcvar.h diff -u src/sys/dev/i2c/ddcvar.h:1.1 src/sys/dev/i2c/ddcvar.h:1.1.138.1 --- src/sys/dev/i2c/ddcvar.h:1.1 Tue Apr 25 21:18:16 2006 +++ src/sys/dev/i2c/ddcvar.h Tue Nov 18 18:19:10 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ddcvar.h,v 1.1 2006/04/25 21:18:16 gdamore Exp $ */ +/* $NetBSD: ddcvar.h,v 1.1.138.1 2014/11/18 18:19:10 snj Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -40,5 +40,6 @@ * autoconfiguration framework. */ int ddc_read_edid(i2c_tag_t, u_int8_t *, size_t); +int ddc_read_edid_block(i2c_tag_t, u_int8_t *, size_t, uint8_t); #endif /* _DEV_I2C_DDCVAR_H_ */ Index: src/sys/dev/videomode/edid.c diff -u src/sys/dev/videomode/edid.c:1.12 src/sys/dev/videomode/edid.c:1.12.12.1 --- src/sys/dev/videomode/edid.c:1.12 Fri Feb 8 16:35:10 2013 +++ src/sys/dev/videomode/edid.c Tue Nov 18 18:19:10 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: edid.c,v 1.12 2013/02/08 16:35:10 skrll Exp $ */ +/* $NetBSD: edid.c,v 1.12.12.1 2014/11/18 18:19:10 snj Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: edid.c,v 1.12 2013/02/08 16:35:10 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: edid.c,v 1.12.12.1 2014/11/18 18:19:10 snj Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -286,6 +286,8 @@ edid_print(struct edid_info *edid) DIVIDE(DIVIDE(edid->edid_preferred_mode->dot_clock * 1000, edid->edid_preferred_mode->htotal), edid->edid_preferred_mode->vtotal)); + + printf("Number of extension blocks: %d\n", edid->edid_ext_block_count); } static const struct videomode * @@ -569,6 +571,8 @@ edid_parse(uint8_t *data, struct edid_in edid->edid_chroma.ec_whitex = EDID_CHROMA_WHITEX(data); edid->edid_chroma.ec_whitey = EDID_CHROMA_WHITEY(data); + edid->edid_ext_block_count = EDID_EXT_BLOCK_COUNT(data); + /* lookup established modes */ edid->edid_nmodes = 0; edid->edid_preferred_mode = NULL; Index: src/sys/dev/videomode/edidreg.h diff -u src/sys/dev/videomode/edidreg.h:1.3 src/sys/dev/videomode/edidreg.h:1.3.30.1 --- src/sys/dev/videomode/edidreg.h:1.3 Wed Mar 30 18:49:56 2011 +++ src/sys/dev/videomode/edidreg.h Tue Nov 18 18:19:10 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: edidreg.h,v 1.3 2011/03/30 18:49:56 jdc Exp $ */ +/* $NetBSD: edidreg.h,v 1.3.30.1 2014/11/18 18:19:10 snj Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -250,4 +250,6 @@ #define EDID_DESC_STD_TIMING_START 5 #define EDID_DESC_STD_TIMING_COUNT 6 +#define EDID_EXT_BLOCK_COUNT(ptr) ((ptr)[126]) + #endif /* _DEV_VIDEOMODE_EDIDREG_H */ Index: src/sys/dev/videomode/edidvar.h diff -u src/sys/dev/videomode/edidvar.h:1.2 src/sys/dev/videomode/edidvar.h:1.2.138.1 --- src/sys/dev/videomode/edidvar.h:1.2 Thu May 11 19:05:41 2006 +++ src/sys/dev/videomode/edidvar.h Tue Nov 18 18:19:10 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: edidvar.h,v 1.2 2006/05/11 19:05:41 gdamore Exp $ */ +/* $NetBSD: edidvar.h,v 1.2.138.1 2014/11/18 18:19:10 snj Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -75,6 +75,7 @@ struct edid_info { uint8_t edid_max_vsize; /* in cm */ uint8_t edid_gamma; uint8_t edid_features; + uint8_t edid_ext_block_count; int edid_have_range; struct edid_range edid_range;