Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-7]: src/sys Pull up following revision(s) (requested by jmcneill ...
details: https://anonhg.NetBSD.org/src/rev/63cb02f74a8d
branches: netbsd-7
changeset: 798599:63cb02f74a8d
user: snj <snj%NetBSD.org@localhost>
date: Tue Nov 18 18:19:09 2014 +0000
description:
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
diffstat:
sys/arch/arm/allwinner/awin_hdmi.c | 211 ++++++++++++++++++++++++++++---
sys/arch/arm/allwinner/awin_hdmiaudio.c | 36 ++++-
sys/arch/arm/allwinner/awin_var.h | 11 +-
sys/arch/evbarm/awin/awin_machdep.c | 18 ++-
sys/dev/i2c/ddc.c | 12 +-
sys/dev/i2c/ddcvar.h | 3 +-
sys/dev/videomode/edid.c | 8 +-
sys/dev/videomode/edidreg.h | 4 +-
sys/dev/videomode/edidvar.h | 3 +-
9 files changed, 267 insertions(+), 39 deletions(-)
diffs (truncated from 670 to 300 lines):
diff -r ff80ed8d6392 -r 63cb02f74a8d sys/arch/arm/allwinner/awin_hdmi.c
--- a/sys/arch/arm/allwinner/awin_hdmi.c Tue Nov 18 18:03:10 2014 +0000
+++ b/sys/arch/arm/allwinner/awin_hdmi.c Tue Nov 18 18:19:09 2014 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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 @@
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 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 @@
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 @@
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 @@
{
struct awin_hdmi_softc *sc = priv;
uint8_t *pbuf;
+ uint8_t block;
int resid;
off_t off;
int err;
@@ -251,14 +272,15 @@
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 @@
}
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 @@
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 @@
}
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 @@
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 @@
}
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 @@
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 @@
#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_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 @@
}
}
+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;
Home |
Main Index |
Thread Index |
Old Index