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