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/e1118a6d6666
branches: trunk
changeset: 996362:e1118a6d6666
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 f21188d13ba9 -r e1118a6d6666 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 f21188d13ba9 -r e1118a6d6666 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