Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/ic Add I2S audio input support.



details:   https://anonhg.NetBSD.org/src/rev/bbffdf73c944
branches:  trunk
changeset: 461108:bbffdf73c944
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Nov 16 12:50:08 2019 +0000

description:
Add I2S audio input support.

diffstat:

 sys/dev/ic/dw_hdmi.c |  200 +++++++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/ic/dw_hdmi.h |    6 +-
 2 files changed, 200 insertions(+), 6 deletions(-)

diffs (truncated from 318 to 300 lines):

diff -r 4b437c37ad7b -r bbffdf73c944 sys/dev/ic/dw_hdmi.c
--- a/sys/dev/ic/dw_hdmi.c      Sat Nov 16 12:47:47 2019 +0000
+++ b/sys/dev/ic/dw_hdmi.c      Sat Nov 16 12:50:08 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dw_hdmi.c,v 1.2 2019/11/09 23:27:50 jmcneill Exp $ */
+/* $NetBSD: dw_hdmi.c,v 1.3 2019/11/16 12:50:08 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2019 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dw_hdmi.c,v 1.2 2019/11/09 23:27:50 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dw_hdmi.c,v 1.3 2019/11/16 12:50:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -45,6 +45,8 @@
 #include <dev/videomode/videomode.h>
 #include <dev/videomode/edidvar.h>
 
+#include <dev/audio/audio_dai.h>
+
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
@@ -52,6 +54,8 @@
 
 #define        HDMI_DESIGN_ID          0x0000
 #define        HDMI_REVISION_ID        0x0001
+#define        HDMI_CONFIG0_ID         0x0004
+#define         HDMI_CONFIG0_ID_AUDI2S                 __BIT(4)
 #define        HDMI_CONFIG2_ID         0x0006
 
 #define        HDMI_IH_I2CM_STAT0      0x0105
@@ -131,6 +135,10 @@
 #define         HDMI_FC_CH1PREAM_DEFAULT               0x16
 #define        HDMI_FC_CH2PREAM        0x1016
 #define         HDMI_FC_CH2PREAM_DEFAULT               0x21
+#define        HDMI_FC_AUDCONF0        0x1025
+#define        HDMI_FC_AUDCONF1        0x1026
+#define        HDMI_FC_AUDCONF2        0x1027
+#define        HDMI_FC_AUDCONF3        0x1028
 
 #define        HDMI_PHY_CONF0          0x3000
 #define         HDMI_PHY_CONF0_PDZ                     __BIT(7)
@@ -149,6 +157,28 @@
 #define         HDMI_PHY_STAT0_HPD                     __BIT(1)
 #define         HDMI_PHY_STAT0_TX_PHY_LOCK             __BIT(0)
 
+#define        HDMI_AUD_CONF0          0x3100
+#define         HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST       __BIT(7)
+#define         HDMI_AUD_CONF0_I2S_SELECT              __BIT(5)
+#define         HDMI_AUD_CONF0_I2S_IN_EN               __BITS(3,0)
+#define        HDMI_AUD_CONF1          0x3101
+#define         HDMI_AUD_CONF1_I2S_WIDTH               __BITS(4,0)
+#define        HDMI_AUD_INT            0x3102
+#define        HDMI_AUD_CONF2          0x3103
+#define         HDMI_AUD_CONF2_INSERT_PCUV             __BIT(2)
+#define         HDMI_AUD_CONF2_NLPCM                   __BIT(1)
+#define         HDMI_AUD_CONF2_HBR                     __BIT(0)
+#define        HDMI_AUD_INT1           0x3104
+
+#define        HDMI_AUD_N1             0x3200
+#define        HDMI_AUD_N2             0x3201
+#define        HDMI_AUD_N3             0x3202
+#define        HDMI_AUD_CTS1           0x3203
+#define        HDMI_AUD_CTS2           0x3204
+#define        HDMI_AUD_CTS3           0x3205
+#define        HDMI_AUD_INPUTCLKFS     0x3206
+#define         HDMI_AUD_INPUTCLKFS_IFSFACTOR          __BITS(2,0)
+
 #define        HDMI_MC_CLKDIS          0x4001
 #define         HDMI_MC_CLKDIS_HDCPCLK_DISABLE         __BIT(6)
 #define         HDMI_MC_CLKDIS_CECCLK_DISABLE          __BIT(5)
@@ -210,6 +240,16 @@
 #define         HDMI_I2CM_SOFTRSTZ_I2C_SOFTRST         __BIT(0)
 #define        HDMI_I2CM_SEGPTR        0x7e0a
 
+enum dwhdmi_dai_mixer_ctrl {
+       DWHDMI_DAI_OUTPUT_CLASS,
+       DWHDMI_DAI_INPUT_CLASS,
+
+       DWHDMI_DAI_OUTPUT_MASTER_VOLUME,
+       DWHDMI_DAI_INPUT_DAC_VOLUME,
+
+       DWHDMI_DAI_MIXER_CTRL_LAST
+};
+
 static int
 dwhdmi_ddc_acquire_bus(void *priv, int flags)
 {
@@ -433,7 +473,6 @@
 static void
 dwhdmi_mc_init(struct dwhdmi_softc *sc)
 {
-       struct dwhdmi_connector *dwhdmi_connector = &sc->sc_connector;
        uint8_t val;
        u_int n, iter;
 
@@ -445,8 +484,6 @@
              HDMI_MC_CLKDIS_CECCLK_DISABLE |
              HDMI_MC_CLKDIS_CSCCLK_DISABLE |
              HDMI_MC_CLKDIS_PREPCLK_DISABLE;
-       if (!dwhdmi_connector->monitor_audio)
-               val |= HDMI_MC_CLKDIS_AUDCLK_DISABLE;
        dwhdmi_write(sc, HDMI_MC_CLKDIS, val);
 
        /* Soft reset TMDS */
@@ -467,6 +504,59 @@
        dwhdmi_write(sc, HDMI_MC_CLKDIS, 0xff);
 }
 
+static void
+dwhdmi_audio_init(struct dwhdmi_softc *sc)
+{
+       uint8_t val;
+       u_int n;
+
+       /* The following values are for 48 kHz */
+       switch (sc->sc_curmode.clock) {
+       case 25170:
+               n = 6864;
+               break;
+       case 74170:
+               n = 11648;
+               break;
+       case 148350:
+               n = 5824;
+               break;
+       default:
+               n = 6144;
+               break;
+       }
+
+       /* Use automatic CTS generation */
+       dwhdmi_write(sc, HDMI_AUD_CTS1, 0);
+       dwhdmi_write(sc, HDMI_AUD_CTS2, 0);
+       dwhdmi_write(sc, HDMI_AUD_CTS3, 0);
+
+       /* Set N factor for audio clock regeneration */
+       dwhdmi_write(sc, HDMI_AUD_N1, n & 0xff);
+       dwhdmi_write(sc, HDMI_AUD_N2, (n >> 8) & 0xff);
+       dwhdmi_write(sc, HDMI_AUD_N3, (n >> 16) & 0xff);
+
+       val = dwhdmi_read(sc, HDMI_AUD_CONF0);
+       val |= HDMI_AUD_CONF0_I2S_SELECT;               /* XXX i2s mode */
+       val &= ~HDMI_AUD_CONF0_I2S_IN_EN;
+       val |= __SHIFTIN(1, HDMI_AUD_CONF0_I2S_IN_EN);  /* XXX 2ch */
+       dwhdmi_write(sc, HDMI_AUD_CONF0, val);
+       
+       val = __SHIFTIN(16, HDMI_AUD_CONF1_I2S_WIDTH);
+       dwhdmi_write(sc, HDMI_AUD_CONF1, val);
+
+       dwhdmi_write(sc, HDMI_AUD_INPUTCLKFS, 4);       /* XXX 64 FS */
+
+       dwhdmi_write(sc, HDMI_FC_AUDCONF0, 1 << 4);     /* XXX 2ch */
+       dwhdmi_write(sc, HDMI_FC_AUDCONF1, 0);
+       dwhdmi_write(sc, HDMI_FC_AUDCONF2, 0);
+       dwhdmi_write(sc, HDMI_FC_AUDCONF3, 0);
+
+       val = dwhdmi_read(sc, HDMI_MC_CLKDIS);
+       val &= ~HDMI_MC_CLKDIS_PREPCLK_DISABLE;
+       dwhdmi_write(sc, HDMI_MC_CLKDIS, val);
+}
+
 static enum drm_connector_status
 dwhdmi_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -594,6 +684,9 @@
 
        dwhdmi_tx_init(sc);
        dwhdmi_mc_init(sc);
+
+       if (sc->sc_connector.monitor_audio)
+               dwhdmi_audio_init(sc);
 }
 
 static void
@@ -646,6 +739,94 @@
        .mode_fixup = dwhdmi_bridge_mode_fixup,
 };
 
+static int
+dwhdmi_dai_set_format(audio_dai_tag_t dai, u_int format)
+{
+       return 0;
+}
+
+static int
+dwhdmi_dai_add_device(audio_dai_tag_t dai, audio_dai_tag_t aux)
+{
+       /* Not supported */
+       return 0;
+}
+
+static int
+dwhdmi_dai_set_port(void *priv, mixer_ctrl_t *mc)
+{
+       switch (mc->dev) {
+       case DWHDMI_DAI_OUTPUT_MASTER_VOLUME:
+       case DWHDMI_DAI_INPUT_DAC_VOLUME:
+               return 0;
+       default:
+               return ENXIO;
+       }
+}
+
+static int
+dwhdmi_dai_get_port(void *priv, mixer_ctrl_t *mc)
+{
+       switch (mc->dev) {
+       case DWHDMI_DAI_OUTPUT_MASTER_VOLUME:
+       case DWHDMI_DAI_INPUT_DAC_VOLUME:
+               mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 255;
+               mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 255;
+               return 0;
+       default:
+               return ENXIO;
+       }
+}
+
+static int
+dwhdmi_dai_query_devinfo(void *priv, mixer_devinfo_t *di)
+{
+       switch (di->index) {
+       case DWHDMI_DAI_OUTPUT_CLASS:
+               di->mixer_class = di->index;
+               strcpy(di->label.name, AudioCoutputs);
+               di->type = AUDIO_MIXER_CLASS;
+               di->next = di->prev = AUDIO_MIXER_LAST;
+               return 0;
+
+       case DWHDMI_DAI_INPUT_CLASS:
+               di->mixer_class = di->index;
+               strcpy(di->label.name, AudioCinputs);
+               di->type = AUDIO_MIXER_CLASS;
+               di->next = di->prev = AUDIO_MIXER_LAST;
+               return 0;
+
+       case DWHDMI_DAI_OUTPUT_MASTER_VOLUME:
+               di->mixer_class = DWHDMI_DAI_OUTPUT_CLASS;
+               strcpy(di->label.name, AudioNmaster);
+               di->un.v.delta = 1;
+               di->un.v.num_channels = 2;
+               strcpy(di->un.v.units.name, AudioNvolume);
+               di->type = AUDIO_MIXER_VALUE;
+               di->next = di->prev = AUDIO_MIXER_LAST;
+               return 0;
+
+       case DWHDMI_DAI_INPUT_DAC_VOLUME:
+               di->mixer_class = DWHDMI_DAI_INPUT_CLASS;
+               strcpy(di->label.name, AudioNdac);
+               di->un.v.delta = 1;
+               di->un.v.num_channels = 2;
+               strcpy(di->un.v.units.name, AudioNvolume);
+               di->type = AUDIO_MIXER_VALUE;
+               di->next = di->prev = AUDIO_MIXER_LAST;
+               return 0;
+
+       default:
+               return ENXIO;
+       }
+}
+
+static const struct audio_hw_if dwhdmi_dai_hw_if = {
+       .set_port = dwhdmi_dai_set_port,
+       .get_port = dwhdmi_dai_get_port,
+       .query_devinfo = dwhdmi_dai_query_devinfo,
+};
+
 int
 dwhdmi_attach(struct dwhdmi_softc *sc)
 {
@@ -690,6 +871,15 @@
                dwhdmi_write(sc, HDMI_PHY_CONF0, val);
        }
 
+       /*
+        * Initialize audio DAI
+        */
+       sc->sc_dai.dai_set_format = dwhdmi_dai_set_format;
+       sc->sc_dai.dai_add_device = dwhdmi_dai_add_device;
+       sc->sc_dai.dai_hw_if = &dwhdmi_dai_hw_if;
+       sc->sc_dai.dai_dev = sc->sc_dev;
+       sc->sc_dai.dai_priv = sc;
+
        return 0;
 }
 
diff -r 4b437c37ad7b -r bbffdf73c944 sys/dev/ic/dw_hdmi.h
--- a/sys/dev/ic/dw_hdmi.h      Sat Nov 16 12:47:47 2019 +0000
+++ b/sys/dev/ic/dw_hdmi.h      Sat Nov 16 12:50:08 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dw_hdmi.h,v 1.2 2019/11/09 23:27:50 jmcneill Exp $ */
+/* $NetBSD: dw_hdmi.h,v 1.3 2019/11/16 12:50:08 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2019 Jared D. McNeill <jmcneill%invisible.ca@localhost>



Home | Main Index | Thread Index | Old Index