Source-Changes-HG archive

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

[src/trunk]: src/sys Add driver for Designware HDMI TX controller.



details:   https://anonhg.NetBSD.org/src/rev/f5d53ee1896f
branches:  trunk
changeset: 447978:f5d53ee1896f
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Wed Jan 30 01:19:49 2019 +0000

description:
Add driver for Designware HDMI TX controller.

diffstat:

 sys/conf/files       |    6 +-
 sys/dev/ic/dw_hdmi.c |  660 +++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ic/dw_hdmi.h |   77 +++++
 3 files changed, 742 insertions(+), 1 deletions(-)

diffs (truncated from 765 to 300 lines):

diff -r a88364331254 -r f5d53ee1896f sys/conf/files
--- a/sys/conf/files    Wed Jan 30 01:11:08 2019 +0000
+++ b/sys/conf/files    Wed Jan 30 01:19:49 2019 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files,v 1.1227 2019/01/28 01:00:23 pgoyette Exp $
+#      $NetBSD: files,v 1.1228 2019/01/30 01:19:49 jmcneill Exp $
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
 
 version        20171118
@@ -1480,6 +1480,10 @@
 device ipmi: sysmon_envsys, sysmon_wdog
 attach ipmi at ipmibus
 
+# Designware HDMI TX
+device dwhdmi: edid, videomode, drmkms, drmkms_i2c
+file   dev/ic/dw_hdmi.c                dwhdmi
+
 #
 # File systems
 #
diff -r a88364331254 -r f5d53ee1896f sys/dev/ic/dw_hdmi.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/ic/dw_hdmi.c      Wed Jan 30 01:19:49 2019 +0000
@@ -0,0 +1,660 @@
+/* $NetBSD: dw_hdmi.c,v 1.1 2019/01/30 01:19:49 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2019 Jared D. McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: dw_hdmi.c,v 1.1 2019/01/30 01:19:49 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+
+#include <dev/ic/dw_hdmi.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/ddcvar.h>
+#include <dev/i2c/ddcreg.h>
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+
+#define        HDMI_IH_I2CM_STAT0      0x0105
+#define         HDMI_IH_I2CM_STAT0_DONE                __BIT(1)
+#define         HDMI_IH_I2CM_STAT0_ERROR               __BIT(0)
+#define        HDMI_IH_MUTE            0x01ff
+#define         HDMI_IH_MUTE_WAKEUP_INTERRUPT          __BIT(1)
+#define         HDMI_IH_MUTE_ALL_INTERRUPT             __BIT(0)
+
+#define        HDMI_TX_INVID0          0x0200
+#define         HDMI_TX_INVID0_VIDEO_MAPPING           __BITS(4,0)
+#define          HDMI_TX_INVID0_VIDEO_MAPPING_DEFAULT  1
+#define        HDMI_TX_INSTUFFING      0x0201
+#define         HDMI_TX_INSTUFFING_BCBDATA_STUFFING    __BIT(2)
+#define         HDMI_TX_INSTUFFING_RCRDATA_STUFFING    __BIT(1)
+#define         HDMI_TX_INSTUFFING_GYDATA_STUFFING     __BIT(0)
+#define        HDMI_TX_GYDATA0         0x0202
+#define        HDMI_TX_GYDATA1         0x0203
+#define        HDMI_TX_RCRDATA0        0x0204
+#define        HDMI_TX_RCRDATA1        0x0205
+#define        HDMI_TX_BCBDATA0        0x0206
+#define        HDMI_TX_BCBDATA1        0x0207
+
+#define        HDMI_VP_STATUS          0x0800
+#define        HDMI_VP_PR_CD           0x0801
+#define         HDMI_VP_PR_CD_COLOR_DEPTH              __BITS(7,4)
+#define          HDMI_VP_PR_CD_COLOR_DEPTH_24          0
+#define         HDMI_VP_PR_CD_DESIRED_PR_FACTOR        __BITS(3,0)
+#define          HDMI_VP_PR_CD_DESIRED_PR_FACTOR_NONE  0
+#define        HDMI_VP_STUFF           0x0802
+#define         HDMI_VP_STUFF_IDEFAULT_PHASE           __BIT(5)
+#define         HDMI_VP_STUFF_YCC422_STUFFING          __BIT(2)
+#define         HDMI_VP_STUFF_PP_STUFFING              __BIT(1)
+#define         HDMI_VP_STUFF_PR_STUFFING              __BIT(0)
+#define        HDMI_VP_REMAP           0x0803
+#define         HDMI_VP_REMAP_YCC422_SIZE              __BITS(1,0)
+#define          HDMI_VP_REMAP_YCC422_SIZE_16          0
+#define        HDMI_VP_CONF            0x0804
+#define         HDMI_VP_CONF_BYPASS_EN                 __BIT(6)
+#define         HDMI_VP_CONF_BYPASS_SELECT             __BIT(2)
+#define         HDMI_VP_CONF_OUTPUT_SELECT             __BITS(1,0)
+#define          HDMI_VP_CONF_OUTPUT_SELECT_BYPASS     2
+#define        HDMI_VP_STAT            0x0805
+#define        HDMI_VP_INT             0x0806
+#define        HDMI_VP_MASK            0x0807
+#define        HDMI_VP_POL             0x0808
+
+#define        HDMI_FC_INVIDCONF       0x1000
+#define         HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY    __BIT(6)
+#define         HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY    __BIT(5)
+#define         HDMI_FC_INVIDCONF_DE_IN_POLARITY       __BIT(4)
+#define         HDMI_FC_INVIDCONF_DVI_MODE             __BIT(3)
+#define         HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC     __BIT(1)
+#define         HDMI_FC_INVIDCONF_IN_I_P               __BIT(0)
+#define        HDMI_FC_INHACTIV0       0x1001
+#define        HDMI_FC_INHACTIV1       0x1002
+#define        HDMI_FC_INHBLANK0       0x1003
+#define        HDMI_FC_INHBLANK1       0x1004
+#define        HDMI_FC_INVACTIV0       0x1005
+#define        HDMI_FC_INVACTIV1       0x1006
+#define        HDMI_FC_INVBLANK        0x1007
+#define        HDMI_FC_HSYNCINDELAY0   0x1008
+#define        HDMI_FC_HSYNCINDELAY1   0x1009
+#define        HDMI_FC_HSYNCINWIDTH0   0x100a
+#define        HDMI_FC_HSYNCINWIDTH1   0x100b
+#define        HDMI_FC_VSYNCINDELAY    0x100c
+#define        HDMI_FC_VSYNCINWIDTH    0x100d
+#define        HDMI_FC_CTRLDUR         0x1011
+#define         HDMI_FC_CTRLDUR_DEFAULT                12
+#define        HDMI_FC_EXCTRLDUR       0x1012
+#define         HDMI_FC_EXCTRLDUR_DEFAULT              32
+#define        HDMI_FC_EXCTRLSPAC      0x1013
+#define         HDMI_FC_EXCTRLSPAC_DEFAULT             1
+#define        HDMI_FC_CH0PREAM        0x1014
+#define         HDMI_FC_CH0PREAM_DEFAULT               0x0b
+#define        HDMI_FC_CH1PREAM        0x1015
+#define         HDMI_FC_CH1PREAM_DEFAULT               0x16
+#define        HDMI_FC_CH2PREAM        0x1016
+#define         HDMI_FC_CH2PREAM_DEFAULT               0x21
+
+#define        HDMI_MC_CLKDIS          0x4001
+#define         HDMI_MC_CLKDIS_HDCPCLK_DISABLE         __BIT(6)
+#define         HDMI_MC_CLKDIS_CECCLK_DISABLE          __BIT(5)
+#define         HDMI_MC_CLKDIS_CSCCLK_DISABLE          __BIT(4)
+#define         HDMI_MC_CLKDIS_AUDCLK_DISABLE          __BIT(3)
+#define         HDMI_MC_CLKDIS_PREPCLK_DISABLE         __BIT(2)
+#define         HDMI_MC_CLKDIS_TMDSCLK_DISABLE         __BIT(1)
+#define         HDMI_MC_CLKDIS_PIXELCLK_DISABLE        __BIT(0)
+#define        HDMI_MC_SWRSTZREQ       0x4002
+#define         HDMI_MC_SWRSTZREQ_CECSWRST_REQ         __BIT(6)
+#define         HDMI_MC_SWRSTZREQ_PREPSWRST_REQ        __BIT(2)
+#define         HDMI_MC_SWRSTZREQ_TMDSSWRST_REQ        __BIT(1)
+#define         HDMI_MC_SWRSTZREQ_PIXELSWRST_REQ       __BIT(0)
+#define        HDMI_MC_FLOWCTRL        0x4004
+#define        HDMI_MC_PHYRSTZ         0x4005
+#define        HDMI_MC_LOCKONCLOCK     0x4006
+#define        HDMI_MC_HEACPHY_RST     0x4007
+
+#define        HDMI_I2CM_SLAVE         0x7e00
+#define        HDMI_I2CM_ADDRESS       0x7e01
+#define        HDMI_I2CM_DATAO         0x7e02
+#define        HDMI_I2CM_DATAI         0x7e03
+#define        HDMI_I2CM_OPERATION     0x7e04
+#define         HDMI_I2CM_OPERATION_WR                 __BIT(4)
+#define         HDMI_I2CM_OPERATION_RD_EXT             __BIT(1)
+#define         HDMI_I2CM_OPERATION_RD                 __BIT(0)
+#define        HDMI_I2CM_INT           0x7e05
+#define         HDMI_I2CM_INT_DONE_POL                 __BIT(3)
+#define         HDMI_I2CM_INT_DONE_MASK                __BIT(2)
+#define         HDMI_I2CM_INT_DONE_INTERRUPT           __BIT(1)
+#define         HDMI_I2CM_INT_DONE_STATUS              __BIT(0)
+#define         HDMI_I2CM_INT_DEFAULT                  \
+       (HDMI_I2CM_INT_DONE_POL|                \
+        HDMI_I2CM_INT_DONE_INTERRUPT|          \
+        HDMI_I2CM_INT_DONE_STATUS)
+#define        HDMI_I2CM_CTLINT        0x7e06
+#define         HDMI_I2CM_CTLINT_NACK_POL              __BIT(7)
+#define         HDMI_I2CM_CTLINT_NACK_MASK             __BIT(6)
+#define         HDMI_I2CM_CTLINT_NACK_INTERRUPT        __BIT(5)
+#define         HDMI_I2CM_CTLINT_NACK_STATUS           __BIT(4)
+#define         HDMI_I2CM_CTLINT_ARB_POL               __BIT(3)
+#define         HDMI_I2CM_CTLINT_ARB_MASK              __BIT(2)
+#define         HDMI_I2CM_CTLINT_ARB_INTERRUPT         __BIT(1)
+#define         HDMI_I2CM_CTLINT_ARB_STATUS            __BIT(0)
+#define         HDMI_I2CM_CTLINT_DEFAULT               \
+       (HDMI_I2CM_CTLINT_NACK_POL|             \
+        HDMI_I2CM_CTLINT_NACK_INTERRUPT|       \
+        HDMI_I2CM_CTLINT_NACK_STATUS|          \
+        HDMI_I2CM_CTLINT_ARB_POL|              \
+        HDMI_I2CM_CTLINT_ARB_INTERRUPT|        \
+        HDMI_I2CM_CTLINT_ARB_STATUS)
+#define        HDMI_I2CM_DIV           0x7e07
+#define         HDMI_I2CM_DIV_FAST_STD_MODE            __BIT(3)
+#define        HDMI_I2CM_SEGADDR       0x7e08
+#define         HDMI_I2CM_SEGADDR_SEGADDR              __BITS(6,0)
+#define        HDMI_I2CM_SOFTRSTZ      0x7e09
+#define         HDMI_I2CM_SOFTRSTZ_I2C_SOFTRST         __BIT(0)
+#define        HDMI_I2CM_SEGPTR        0x7e0a
+
+static int
+dwhdmi_ddc_acquire_bus(void *priv, int flags)
+{
+       struct dwhdmi_softc * const sc = priv;
+
+       mutex_enter(&sc->sc_ic_lock);
+
+       return 0;
+}
+
+static void
+dwhdmi_ddc_release_bus(void *priv, int flags)
+{
+       struct dwhdmi_softc * const sc = priv;
+
+       mutex_exit(&sc->sc_ic_lock);
+}
+
+static int
+dwhdmi_ddc_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
+    const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
+{
+       struct dwhdmi_softc * const sc = priv;
+       uint8_t block, operation, val;
+       uint8_t *pbuf = buf;
+       int off, n, retry;
+
+       KASSERT(mutex_owned(&sc->sc_ic_lock));
+
+       if (addr != DDC_ADDR || op != I2C_OP_READ_WITH_STOP || cmdlen == 0 || buf == NULL) {
+               printf("dwhdmi_ddc_exec: bad args addr=%#x op=%#x cmdlen=%d buf=%p\n",
+                   addr, op, (int)cmdlen, buf);
+               return ENXIO;
+       }
+       if (len > 256) {
+               printf("dwhdmi_ddc_exec: bad len %d\n", (int)len);
+               return ERANGE;
+       }
+
+       dwhdmi_write(sc, HDMI_I2CM_SOFTRSTZ, 0);
+       dwhdmi_write(sc, HDMI_IH_I2CM_STAT0, dwhdmi_read(sc, HDMI_IH_I2CM_STAT0));
+       dwhdmi_write(sc, HDMI_I2CM_DIV, 0);
+       dwhdmi_write(sc, HDMI_I2CM_SLAVE, DDC_ADDR);
+       dwhdmi_write(sc, HDMI_I2CM_SEGADDR, DDC_SEGMENT_ADDR);
+
+       block = *(const uint8_t *)cmdbuf;
+       operation = block ? HDMI_I2CM_OPERATION_RD_EXT : HDMI_I2CM_OPERATION_RD;
+       off = (block & 1) ? 128 : 0;
+
+       for (n = 0; n < len; n++) {
+               dwhdmi_write(sc, HDMI_I2CM_ADDRESS, n + off);
+               dwhdmi_write(sc, HDMI_I2CM_OPERATION, operation);
+               for (retry = 10000; retry > 0; retry--) {
+                       val = dwhdmi_read(sc, HDMI_IH_I2CM_STAT0);
+                       if (val & HDMI_IH_I2CM_STAT0_ERROR) {
+                               return EIO;
+                       }
+                       if (val & HDMI_IH_I2CM_STAT0_DONE) {
+                               dwhdmi_write(sc, HDMI_IH_I2CM_STAT0, val);
+                               break;
+                       }
+                       delay(1);
+               }
+               if (retry == 0) {
+                       printf("dwhdmi_ddc_exec: timeout waiting for xfer, stat0=%#x\n", dwhdmi_read(sc, HDMI_IH_I2CM_STAT0));
+                       return ETIMEDOUT;
+               }
+
+               pbuf[n] = dwhdmi_read(sc, HDMI_I2CM_DATAI);
+       }
+
+       return 0;
+}
+
+uint8_t
+dwhdmi_read(struct dwhdmi_softc *sc, bus_size_t reg)
+{
+       uint8_t val;
+
+       switch (sc->sc_reg_width) {
+       case 1:
+               val = bus_space_read_1(sc->sc_bst, sc->sc_bsh, reg);
+               break;
+       case 4:
+               val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg * 4) & 0xff;
+               break;
+       default:



Home | Main Index | Thread Index | Old Index