Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/arm/allwinner add HDMI audio driver



details:   https://anonhg.NetBSD.org/src/rev/bbd460c22a86
branches:  trunk
changeset: 333624:bbd460c22a86
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Tue Nov 11 17:00:59 2014 +0000

description:
add HDMI audio driver

diffstat:

 sys/arch/arm/allwinner/awin_hdmi.c      |   86 +++-
 sys/arch/arm/allwinner/awin_hdmiaudio.c |  647 ++++++++++++++++++++++++++++++++
 sys/arch/arm/allwinner/awin_io.c        |    4 +-
 sys/arch/arm/allwinner/awin_reg.h       |   41 ++
 sys/arch/arm/allwinner/files.awin       |    9 +-
 5 files changed, 777 insertions(+), 10 deletions(-)

diffs (truncated from 889 to 300 lines):

diff -r 874e03f43461 -r bbd460c22a86 sys/arch/arm/allwinner/awin_hdmi.c
--- a/sys/arch/arm/allwinner/awin_hdmi.c        Tue Nov 11 15:12:51 2014 +0000
+++ b/sys/arch/arm/allwinner/awin_hdmi.c        Tue Nov 11 17:00:59 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_hdmi.c,v 1.6 2014/11/10 18:18:09 jmcneill Exp $ */
+/* $NetBSD: awin_hdmi.c,v 1.7 2014/11/11 17:00:59 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -33,7 +33,7 @@
 #define AWIN_HDMI_PLL  3       /* PLL7 or PLL3 */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.6 2014/11/10 18:18:09 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.7 2014/11/11 17:00:59 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -102,6 +102,7 @@
 #if 0
 static int     awin_hdmi_intr(void *);
 #endif
+
 #if defined(DDB)
 void           awin_hdmi_dump_regs(void);
 #endif
@@ -533,7 +534,8 @@
 }
 
 static void
-awin_hdmi_set_videomode(struct awin_hdmi_softc *sc, const struct videomode *mode)
+awin_hdmi_set_videomode(struct awin_hdmi_softc *sc,
+    const struct videomode *mode)
 {
        uint32_t val;
        const u_int dblscan_p = !!(mode->flags & VID_DBLSCAN);
@@ -598,6 +600,8 @@
 #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);
        if (dblscan_p) {
                val |= __SHIFTIN(AWIN_HDMI_VID_CTRL_REPEATER_SEL_2X,
                                 AWIN_HDMI_VID_CTRL_REPEATER_SEL);
@@ -651,13 +655,81 @@
        val |= __SHIFTIN(AWIN_HDMI_VID_TIMING_4_TX_CLOCK_NORMAL,
                         AWIN_HDMI_VID_TIMING_4_TX_CLOCK);
        HDMI_WRITE(sc, AWIN_HDMI_VID_TIMING_4_REG, val);
+
+       /* Packet control */
+       HDMI_WRITE(sc, AWIN_HDMI_PKT_CTRL0_REG, 0x00005321);
+       HDMI_WRITE(sc, AWIN_HDMI_PKT_CTRL1_REG, 0x0000000f);
 }
 
 static void
-awin_hdmi_set_audiomode(struct awin_hdmi_softc *sc, const struct videomode *mode)
+awin_hdmi_set_audiomode(struct awin_hdmi_softc *sc,
+    const struct videomode *mode)
 {
-       /* TODO */
-       HDMI_WRITE(sc, AWIN_HDMI_AUD_CTRL_REG, 0);
+       uint32_t cts, n, val;
+
+       /*
+        * Before changing audio parameters, disable and reset the
+        * audio module. Wait for the soft reset bit to clear before
+        * configuring the audio parameters.
+        */
+       val = HDMI_READ(sc, AWIN_HDMI_AUD_CTRL_REG);
+       val &= ~AWIN_HDMI_AUD_CTRL_EN;
+       val |= AWIN_HDMI_AUD_CTRL_RST;
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_CTRL_REG, val);
+       do {
+               val = HDMI_READ(sc, AWIN_HDMI_AUD_CTRL_REG);
+       } while (val & AWIN_HDMI_AUD_CTRL_RST);
+
+       /* DMA & FIFO control */
+       val = HDMI_READ(sc, AWIN_HDMI_ADMA_CTRL_REG);
+       val |= AWIN_HDMI_ADMA_CTRL_SRC_DMA_MODE;        /* NDMA */
+       val &= ~AWIN_HDMI_ADMA_CTRL_SRC_DMA_SAMPLE_RATE;
+       val &= ~AWIN_HDMI_ADMA_CTRL_SRC_SAMPLE_LAYOUT;
+       val &= ~AWIN_HDMI_ADMA_CTRL_SRC_WORD_LEN;
+       val &= ~AWIN_HDMI_ADMA_CTRL_DATA_SEL;
+       HDMI_WRITE(sc, AWIN_HDMI_ADMA_CTRL_REG, val);
+
+       /* Audio format control */
+       val = HDMI_READ(sc, AWIN_HDMI_AUD_FMT_REG);
+       val &= ~AWIN_HDMI_AUD_FMT_SRC_SEL;
+       val &= ~AWIN_HDMI_AUD_FMT_SEL;
+       val &= ~AWIN_HDMI_AUD_FMT_DSD_FMT;
+       val &= ~AWIN_HDMI_AUD_FMT_LAYOUT;
+       val &= ~AWIN_HDMI_AUD_FMT_SRC_CH_CFG;
+       val |= __SHIFTIN(1, AWIN_HDMI_AUD_FMT_SRC_CH_CFG);
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_FMT_REG, val);
+
+       /* PCM control (channel map) */
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_PCM_CTRL_REG, 0x76543210);
+
+       /* Clock setup */
+       n = 6144;       /* 48 kHz */
+       cts = ((mode->dot_clock * 10) * (n / 128)) / 480;
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_CTS_REG, cts);
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_N_REG, n);
+
+       /* Audio PCM channel status 0 */
+       val = __SHIFTIN(AWIN_HDMI_AUD_CH_STATUS0_FS_FREQ_48,
+                       AWIN_HDMI_AUD_CH_STATUS0_FS_FREQ);
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_CH_STATUS0_REG, val);
+
+       /* Audio PCM channel status 1 */
+       val = HDMI_READ(sc, AWIN_HDMI_AUD_CH_STATUS1_REG);
+       val &= ~AWIN_HDMI_AUD_CH_STATUS1_CGMS_A;
+       val &= ~AWIN_HDMI_AUD_CH_STATUS1_ORIGINAL_FS;
+       val &= ~AWIN_HDMI_AUD_CH_STATUS1_WORD_LEN;
+       val |= __SHIFTIN(5, AWIN_HDMI_AUD_CH_STATUS1_WORD_LEN);
+       val |= AWIN_HDMI_AUD_CH_STATUS1_WORD_LEN_MAX;
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_CH_STATUS1_REG, val);
+
+       /* Re-enable */
+       val = HDMI_READ(sc, AWIN_HDMI_AUD_CTRL_REG);
+       val |= AWIN_HDMI_AUD_CTRL_EN;
+       HDMI_WRITE(sc, AWIN_HDMI_AUD_CTRL_REG, val);
+
+#if defined(DDB)
+       awin_hdmi_dump_regs();
+#endif
 }
 
 static void
@@ -698,7 +770,7 @@
        uint32_t intsts;
 
        intsts = HDMI_READ(sc, AWIN_HDMI_INT_STATUS_REG);
-       if (!intsts)
+       if (!(intsts & 0x73))
                return 0;
 
        HDMI_WRITE(sc, AWIN_HDMI_INT_STATUS_REG, intsts);
diff -r 874e03f43461 -r bbd460c22a86 sys/arch/arm/allwinner/awin_hdmiaudio.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/allwinner/awin_hdmiaudio.c   Tue Nov 11 17:00:59 2014 +0000
@@ -0,0 +1,647 @@
+/* $NetBSD: awin_hdmiaudio.c,v 1.1 2014/11/11 17:00:59 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2014 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: awin_hdmiaudio.c,v 1.1 2014/11/11 17:00:59 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#include <dev/auconv.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+
+struct awin_hdmiaudio_dma {
+       LIST_ENTRY(awin_hdmiaudio_dma)  dma_list;
+       bus_dmamap_t            dma_map;
+       void                    *dma_addr;
+       size_t                  dma_size;
+       bus_dma_segment_t       dma_segs[1];
+       int                     dma_nsegs;
+};
+
+struct awin_hdmiaudio_softc {
+       device_t                sc_dev;
+       device_t                sc_audiodev;
+
+       bus_space_tag_t         sc_bst;
+       bus_space_handle_t      sc_bsh;
+       bus_dma_tag_t           sc_dmat;
+
+       uint32_t                sc_ver;
+
+       LIST_HEAD(, awin_hdmiaudio_dma) sc_dmalist;
+
+       uint8_t                 sc_drqtype_hdmiaudio;
+       uint8_t                 sc_drqtype_sdram;
+
+       kmutex_t                sc_lock;
+       kmutex_t                sc_intr_lock;
+
+       struct audio_format     sc_format;
+       struct audio_encoding_set *sc_encodings;
+
+       audio_params_t          sc_pparam;
+       struct awin_dma_channel *sc_pdma;
+       void                    (*sc_pint)(void *);
+       void                    *sc_pintarg;
+       bus_addr_t              sc_pstart;
+       bus_addr_t              sc_pend;
+       bus_addr_t              sc_pcur;
+       int                     sc_pblksize;
+};
+
+static int     awin_hdmiaudio_match(device_t, cfdata_t, void *);
+static void    awin_hdmiaudio_attach(device_t, device_t, void *);
+static int     awin_hdmiaudio_rescan(device_t, const char *, const int *);
+static void    awin_hdmiaudio_childdet(device_t, device_t);
+
+static int     awin_hdmiaudio_allocdma(struct awin_hdmiaudio_softc *, size_t,
+                                       size_t, struct awin_hdmiaudio_dma *);
+static void    awin_hdmiaudio_freedma(struct awin_hdmiaudio_softc *,
+                                      struct awin_hdmiaudio_dma *);
+
+static void    awin_hdmiaudio_pint(void *);
+static int     awin_hdmiaudio_play(struct awin_hdmiaudio_softc *);
+
+#if defined(DDB)
+void           awin_hdmiaudio_dump_regs(void);
+#endif
+
+static int     awin_hdmiaudio_open(void *, int);
+static void    awin_hdmiaudio_close(void *);
+static int     awin_hdmiaudio_drain(void *);
+static int     awin_hdmiaudio_query_encoding(void *, struct audio_encoding *);
+static int     awin_hdmiaudio_set_params(void *, int, int,
+                                         audio_params_t *, audio_params_t *,
+                                         stream_filter_list_t *,
+                                         stream_filter_list_t *);
+static int     awin_hdmiaudio_halt_output(void *);
+static int     awin_hdmiaudio_halt_input(void *);
+static int     awin_hdmiaudio_set_port(void *, mixer_ctrl_t *);
+static int     awin_hdmiaudio_get_port(void *, mixer_ctrl_t *);
+static int     awin_hdmiaudio_query_devinfo(void *, mixer_devinfo_t *);
+static void *  awin_hdmiaudio_allocm(void *, int, size_t);
+static void    awin_hdmiaudio_freem(void *, void *, size_t);
+static paddr_t awin_hdmiaudio_mappage(void *, void *, off_t, int);
+static int     awin_hdmiaudio_getdev(void *, struct audio_device *);
+static int     awin_hdmiaudio_get_props(void *);
+static int     awin_hdmiaudio_round_blocksize(void *, int, int,
+                                              const audio_params_t *);
+static size_t  awin_hdmiaudio_round_buffersize(void *, int, size_t);
+static int     awin_hdmiaudio_trigger_output(void *, void *, void *, int,
+                                             void (*)(void *), void *,
+                                             const audio_params_t *);
+static int     awin_hdmiaudio_trigger_input(void *, void *, void *, int,
+                                            void (*)(void *), void *,
+                                            const audio_params_t *);
+static void    awin_hdmiaudio_get_locks(void *, kmutex_t **, kmutex_t **);
+
+static const struct audio_hw_if awin_hdmiaudio_hw_if = {
+       .open = awin_hdmiaudio_open,
+       .close = awin_hdmiaudio_close,
+       .drain = awin_hdmiaudio_drain,
+       .query_encoding = awin_hdmiaudio_query_encoding,
+       .set_params = awin_hdmiaudio_set_params,
+       .halt_output = awin_hdmiaudio_halt_output,
+       .halt_input = awin_hdmiaudio_halt_input,
+       .allocm = awin_hdmiaudio_allocm,
+       .freem = awin_hdmiaudio_freem,
+       .mappage = awin_hdmiaudio_mappage,
+       .getdev = awin_hdmiaudio_getdev,
+       .set_port = awin_hdmiaudio_set_port,
+       .get_port = awin_hdmiaudio_get_port,
+       .query_devinfo = awin_hdmiaudio_query_devinfo,
+       .get_props = awin_hdmiaudio_get_props,
+       .round_blocksize = awin_hdmiaudio_round_blocksize,
+       .round_buffersize = awin_hdmiaudio_round_buffersize,
+       .trigger_output = awin_hdmiaudio_trigger_output,
+       .trigger_input = awin_hdmiaudio_trigger_input,
+       .get_locks = awin_hdmiaudio_get_locks,
+};
+
+enum {
+       HDMIAUDIO_OUTPUT_CLASS,
+       HDMIAUDIO_INPUT_CLASS,



Home | Main Index | Thread Index | Old Index