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 ARM PrimeCell Advanced Audio CODEC interf...
details: https://anonhg.NetBSD.org/src/rev/919b2bb74de7
branches: trunk
changeset: 824527:919b2bb74de7
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Thu Jun 08 10:02:39 2017 +0000
description:
Add driver for ARM PrimeCell Advanced Audio CODEC interface (PL041).
Don't expect this driver to work on real hardware, but QEMU emulates it.
diffstat:
sys/conf/files | 6 +-
sys/dev/ic/pl041.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++
sys/dev/ic/pl041var.h | 60 ++++++++
3 files changed, 423 insertions(+), 1 deletions(-)
diffs (truncated from 446 to 300 lines):
diff -r 240c342b0427 -r 919b2bb74de7 sys/conf/files
--- a/sys/conf/files Thu Jun 08 09:49:46 2017 +0000
+++ b/sys/conf/files Thu Jun 08 10:02:39 2017 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1173 2017/06/03 17:03:36 jmcneill Exp $
+# $NetBSD: files,v 1.1174 2017/06/08 10:02:39 jmcneill Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20150846
@@ -1315,6 +1315,10 @@
device dwcmmc: sdmmcbus
file dev/ic/dwc_mmc.c dwcmmc
+# ARM PrimeCell PL041 (AACI) Advanced Audio CODEC interface
+device aaci: audiobus, auconv, aurateconv, mulaw, ac97
+file dev/ic/pl041.c aaci
+
# ARM PrimeCell PL050 (KMI) PS2 keyboard/mouse interface
device plkmi: pckbport
file dev/ic/pl050.c plkmi
diff -r 240c342b0427 -r 919b2bb74de7 sys/dev/ic/pl041.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/ic/pl041.c Thu Jun 08 10:02:39 2017 +0000
@@ -0,0 +1,358 @@
+/* $NetBSD: pl041.c,v 1.1 2017/06/08 10:02:39 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2017 Jared 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: pl041.c,v 1.1 2017/06/08 10:02:39 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/bus.h>
+#include <sys/audioio.h>
+
+#include <dev/audio_if.h>
+#include <dev/auconv.h>
+
+#include <dev/ic/ac97var.h>
+#include <dev/ic/ac97reg.h>
+
+#include <dev/ic/pl041var.h>
+
+#define AACIRXCR 0x00
+#define AACITXCR 0x04
+#define AACITXCR_TXFEN __BIT(16)
+#define AACITXCR_TXCM __BIT(15)
+#define AACITXCR_TSIZE __BITS(14,13)
+#define AACITXCR_TSIZE_16 __SHIFTIN(0, AACITXCR_TSIZE)
+#define AACITXCR_TX(n) __BIT(n)
+#define AACITXCR_TXEN __BIT(0)
+#define AACISR 0x08
+#define AACISR_TXFF __BIT(5)
+#define AACISR_TXHE __BIT(3)
+#define AACIISR 0x0c
+#define AACIISR_URINTR __BIT(5)
+#define AACIISR_TXINTR __BIT(2)
+#define AACIIE 0x10
+#define AACIIE_TXUIE __BIT(5)
+#define AACIIE_TXIE __BIT(2)
+#define AACISL1RX 0x50
+#define AACISL1TX 0x54
+#define AACISL2RX 0x58
+#define AACISL2TX 0x5c
+#define AACISLFR 0x68
+#define AACISLISTAT 0x6c
+#define AACISLIEN 0x70
+#define AACIINTCLR 0x74
+#define AACIMAINCR 0x78
+#define AACIRESET 0x7c
+#define AACISYNC 0x80
+#define AACIALLINTS 0x84
+#define AACIMAINFR 0x88
+#define AACIDR 0x90
+
+#define AACI_FIFO_DEPTH 512
+#define AACI_BLOCK_ALIGN 4
+
+#define AACI_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define AACI_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#define AACI_WRITE_MULTI(sc, reg, val, cnt) \
+ bus_space_write_multi_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val), (cnt))
+
+static const struct audio_format aaci_format = {
+ .mode = AUMODE_PLAY,
+ .encoding = AUDIO_ENCODING_SLINEAR_LE,
+ .validbits = 16,
+ .precision = 16,
+ .channels = 2,
+ .channel_mask = AUFMT_STEREO,
+ .frequency_type = 0,
+ .frequency = { 48000, 48000 }
+};
+
+static void
+aaci_write_data(struct aaci_softc *sc)
+{
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
+ if (sc->sc_pint == NULL)
+ return;
+
+ while ((AACI_READ(sc, AACISR) & AACISR_TXHE) == 0) {
+ const int len = min(AACI_FIFO_DEPTH / 2, min(sc->sc_pblkresid,
+ (uintptr_t)sc->sc_pend - (uintptr_t)sc->sc_pcur));
+ KASSERT((len & 3) == 0);
+ AACI_WRITE_MULTI(sc, AACIDR, sc->sc_pcur, len);
+ sc->sc_pcur += (len >> 2);
+ if (sc->sc_pcur == sc->sc_pend)
+ sc->sc_pcur = sc->sc_pstart;
+ sc->sc_pblkresid -= len;
+ if (sc->sc_pblkresid == 0) {
+ sc->sc_pblkresid = sc->sc_pblksize;
+ sc->sc_pint(sc->sc_pintarg);
+ }
+ }
+}
+
+static int
+aaci_query_encoding(void *priv, struct audio_encoding *enc)
+{
+ struct aaci_softc * const sc = priv;
+
+ return auconv_query_encoding(sc->sc_encodings, enc);
+}
+
+static int
+aaci_set_params(void *priv, int setmode, int usermode,
+ audio_params_t *play, audio_params_t *rec,
+ stream_filter_list_t *pfil, stream_filter_list_t *rfil)
+{
+ int index;
+
+ if (play && (setmode & AUMODE_PLAY) != 0) {
+ index = auconv_set_converter(&aaci_format, 1, AUMODE_PLAY,
+ play, true, pfil);
+ if (index < 0)
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+aaci_getdev(void *priv, struct audio_device *audiodev)
+{
+ snprintf(audiodev->name, sizeof(audiodev->name), "ARM");
+ snprintf(audiodev->version, sizeof(audiodev->version),
+ "PrimeCell AACI");
+ snprintf(audiodev->config, sizeof(audiodev->config), "aaci");
+ return 0;
+}
+
+static int
+aaci_set_port(void *priv, mixer_ctrl_t *mc)
+{
+ struct aaci_softc * const sc = priv;
+
+ return sc->sc_ac97_codec->vtbl->mixer_set_port(sc->sc_ac97_codec, mc);
+}
+
+static int
+aaci_get_port(void *priv, mixer_ctrl_t *mc)
+{
+ struct aaci_softc * const sc = priv;
+
+ return sc->sc_ac97_codec->vtbl->mixer_get_port(sc->sc_ac97_codec, mc);
+}
+
+static int
+aaci_query_devinfo(void *priv, mixer_devinfo_t *di)
+{
+ struct aaci_softc * const sc = priv;
+
+ return sc->sc_ac97_codec->vtbl->query_devinfo(sc->sc_ac97_codec, di);
+}
+
+static int
+aaci_get_props(void *priv)
+{
+ return AUDIO_PROP_PLAYBACK;
+}
+
+static int
+aaci_trigger_output(void *priv, void *start, void *end, int blksize,
+ void (*intr)(void *), void *intrarg, const audio_params_t *params)
+{
+ struct aaci_softc * const sc = priv;
+
+ sc->sc_pcur = start;
+ sc->sc_pstart = start;
+ sc->sc_pend = end;
+ sc->sc_pblksize = blksize;
+ sc->sc_pblkresid = blksize;
+ sc->sc_pint = intr;
+ sc->sc_pintarg = intrarg;
+
+ AACI_WRITE(sc, AACIIE, AACIIE_TXIE | AACIIE_TXUIE);
+ AACI_WRITE(sc, AACITXCR, AACITXCR_TXFEN | AACITXCR_TXEN |
+ AACITXCR_TXCM | AACITXCR_TSIZE_16 |
+ AACITXCR_TX(3) | AACITXCR_TX(4));
+
+ return ENXIO;
+}
+
+static int
+aaci_trigger_input(void *priv, void *start, void *end, int blksize,
+ void (*intr)(void *), void *intrarg, const audio_params_t *params)
+{
+ return ENXIO;
+}
+
+static int
+aaci_halt_output(void *priv)
+{
+ struct aaci_softc * const sc = priv;
+
+ sc->sc_pint = NULL;
+
+ AACI_WRITE(sc, AACITXCR, 0);
+ AACI_WRITE(sc, AACIIE, 0);
+
+ return 0;
+}
+
+static int
+aaci_halt_input(void *priv)
+{
+ return ENXIO;
+}
+
+static int
+aaci_round_blocksize(void *priv, int bs, int mode, const audio_params_t *params)
+{
+ return roundup(bs, AACI_BLOCK_ALIGN);
+}
+
+static void
+aaci_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
+{
+ struct aaci_softc * const sc = priv;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
+static const struct audio_hw_if aaci_hw_if = {
+ .query_encoding = aaci_query_encoding,
+ .set_params = aaci_set_params,
+ .getdev = aaci_getdev,
+ .set_port = aaci_set_port,
+ .get_port = aaci_get_port,
+ .query_devinfo = aaci_query_devinfo,
+ .get_props = aaci_get_props,
+ .trigger_output = aaci_trigger_output,
+ .trigger_input = aaci_trigger_input,
+ .halt_output = aaci_halt_output,
+ .halt_input = aaci_halt_input,
+ .round_blocksize = aaci_round_blocksize,
+ .get_locks = aaci_get_locks,
+};
+
+static int
+aaci_ac97_attach(void *priv, struct ac97_codec_if *codec)
+{
+ struct aaci_softc * const sc = priv;
+
+ sc->sc_ac97_codec = codec;
+
+ return 0;
+}
Home |
Main Index |
Thread Index |
Old Index