Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/rockchip Add driver for Rockchip I2S/PCM contro...
details: https://anonhg.NetBSD.org/src/rev/14ae5f1e2ac9
branches: trunk
changeset: 461111:14ae5f1e2ac9
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Sat Nov 16 13:24:03 2019 +0000
description:
Add driver for Rockchip I2S/PCM controller.
diffstat:
sys/arch/arm/rockchip/files.rockchip | 7 +-
sys/arch/arm/rockchip/rk_i2s.c | 638 +++++++++++++++++++++++++++++++++++
2 files changed, 644 insertions(+), 1 deletions(-)
diffs (truncated from 663 to 300 lines):
diff -r 387ad91d0b8b -r 14ae5f1e2ac9 sys/arch/arm/rockchip/files.rockchip
--- a/sys/arch/arm/rockchip/files.rockchip Sat Nov 16 13:23:13 2019 +0000
+++ b/sys/arch/arm/rockchip/files.rockchip Sat Nov 16 13:24:03 2019 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.rockchip,v 1.21 2019/11/09 23:30:14 jmcneill Exp $
+# $NetBSD: files.rockchip,v 1.22 2019/11/16 13:24:03 jmcneill Exp $
#
# Configuration info for Rockchip family SoCs
#
@@ -103,6 +103,11 @@
attach dwhdmi at fdt with rk_dwhdmi
file arch/arm/rockchip/rk_dwhdmi.c rk_dwhdmi
+# I2S/PCM controller
+device rki2s
+attach rki2s at fdt with rk_i2s
+file arch/arm/rockchip/rk_i2s.c rk_i2s
+
# SOC parameters
defflag opt_soc.h SOC_ROCKCHIP
defflag opt_soc.h SOC_RK3328: SOC_ROCKCHIP
diff -r 387ad91d0b8b -r 14ae5f1e2ac9 sys/arch/arm/rockchip/rk_i2s.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/rockchip/rk_i2s.c Sat Nov 16 13:24:03 2019 +0000
@@ -0,0 +1,638 @@
+/* $NetBSD: rk_i2s.c,v 1.1 2019/11/16 13:24:03 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2019 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: rk_i2s.c,v 1.1 2019/11/16 13:24:03 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+
+#include <sys/audioio.h>
+#include <dev/audio/audio_if.h>
+#include <dev/audio/linear.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/syscon.h>
+
+#define RK_I2S_FIFO_DEPTH 32
+#define RK_I2S_SAMPLE_RATE 48000
+
+#define I2S_TXCR 0x00
+#define TXCR_RCNT __BITS(22,17)
+#define TXCR_TCSR __BITS(16,15)
+#define TXCR_HWT __BIT(14)
+#define TXCR_SJM __BIT(12)
+#define TXCR_FBM __BIT(11)
+#define TXCR_IBM __BITS(10,9)
+#define TXCR_PBM __BITS(8,7)
+#define TXCR_TFS __BIT(5)
+#define TXCR_VDW __BITS(4,0)
+#define I2S_RXCR 0x04
+#define RXCR_RCSR __BITS(16,15)
+#define RXCR_HWT __BIT(14)
+#define RXCR_SJM __BIT(12)
+#define RXCR_FBM __BIT(11)
+#define RXCR_IBM __BITS(10,9)
+#define RXCR_PBM __BITS(8,7)
+#define RXCR_TFS __BIT(5)
+#define RXCR_VDW __BITS(4,0)
+#define I2S_CKR 0x08
+#define CKR_TRCM __BITS(29,28)
+#define CKR_MSS __BIT(27)
+#define CKR_CKP __BIT(26)
+#define CKR_RLP __BIT(25)
+#define CKR_TLP __BIT(24)
+#define CKR_MDIV __BITS(23,16)
+#define CKR_RSD __BITS(15,8)
+#define CKR_TSD __BITS(7,0)
+#define I2S_TXFIFOLR 0x0c
+#define TXFIFOLR_TFL(n) __BITS((n) * 6 + 5, (n) * 6)
+#define I2S_DMACR 0x10
+#define DMACR_RDE __BIT(24)
+#define DMACR_RDL __BITS(20,16)
+#define DMACR_TDE __BIT(8)
+#define DMACR_TDL __BITS(4,0)
+#define I2S_INTCR 0x14
+#define INTCR_RFT __BITS(24,20)
+#define INTCR_RXOIC __BIT(18)
+#define INTCR_RXOIE __BIT(17)
+#define INTCR_RXFIE __BIT(16)
+#define INTCR_TFT __BITS(8,4)
+#define INTCR_TXUIC __BIT(2)
+#define INTCR_TXUIE __BIT(1)
+#define INTCR_TXEIE __BIT(0)
+#define I2S_INTSR 0x18
+#define INTSR_RXOI __BIT(17)
+#define INTSR_RXFI __BIT(16)
+#define INTSR_TXUI __BIT(1)
+#define INTSR_TXEI __BIT(0)
+#define I2S_XFER 0x1c
+#define XFER_RXS __BIT(1)
+#define XFER_TXS __BIT(0)
+#define I2S_CLR 0x20
+#define CLR_RXC __BIT(1)
+#define CLR_TXC __BIT(0)
+#define I2S_TXDR 0x24
+#define I2S_RXDR 0x28
+#define I2S_RXFIFOLR 0x2c
+#define RXFIFOLR_RFL(n) __BITS((n) * 6 + 5, (n) * 6)
+
+struct rk_i2s_config {
+ bus_size_t oe_reg;
+ u_int oe_mask;
+ u_int oe_val;
+};
+
+static const struct rk_i2s_config rk3399_i2s_config = {
+ .oe_reg = 0x0e220,
+ .oe_mask = __BITS(13,11),
+ .oe_val = 0x7,
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3399-i2s", (uintptr_t)&rk3399_i2s_config },
+ { NULL }
+};
+
+struct rk_i2s_softc;
+
+struct rk_i2s_chan {
+ uint32_t *ch_start;
+ uint32_t *ch_end;
+ uint32_t *ch_cur;
+
+ int ch_blksize;
+ int ch_resid;
+
+ void (*ch_intr)(void *);
+ void *ch_intrarg;
+};
+
+struct rk_i2s_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ int sc_phandle;
+ struct clk *sc_clk;
+ struct syscon *sc_grf;
+ const struct rk_i2s_config *sc_conf;
+
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
+
+ struct audio_format sc_format;
+
+ struct rk_i2s_chan sc_pchan;
+ struct rk_i2s_chan sc_rchan;
+
+ u_int sc_active;
+
+ struct audio_dai_device sc_dai;
+};
+
+#define RD4(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define WR4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int
+rk_i2s_query_format(void *priv, audio_format_query_t *afp)
+{
+ struct rk_i2s_softc * const sc = priv;
+
+ return audio_query_format(&sc->sc_format, 1, afp);
+}
+
+static int
+rk_i2s_set_format(void *priv, int setmode,
+ const audio_params_t *play, const audio_params_t *rec,
+ audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
+{
+ struct rk_i2s_softc * const sc = priv;
+ uint32_t ckr, txcr, rxcr;
+
+ ckr = RD4(sc, I2S_CKR);
+ if ((ckr & CKR_MSS) == 0) {
+ const u_int mclk_rate = clk_get_rate(sc->sc_clk);
+ device_printf(sc->sc_dev, "%s: sysclk rate %u Hz\n", __func__, mclk_rate);
+ const u_int bclk_rate = 2 * 32 * RK_I2S_SAMPLE_RATE;
+ const u_int bclk_div = mclk_rate / bclk_rate;
+ const u_int lrck_div = bclk_rate / RK_I2S_SAMPLE_RATE;
+
+ ckr &= ~CKR_MDIV;
+ ckr |= __SHIFTIN(bclk_div - 1, CKR_MDIV);
+ ckr &= ~CKR_TSD;
+ ckr |= __SHIFTIN(lrck_div - 1, CKR_TSD);
+ ckr &= ~CKR_RSD;
+ ckr |= __SHIFTIN(lrck_div - 1, CKR_RSD);
+ }
+
+ ckr &= ~CKR_TRCM;
+ ckr |= __SHIFTIN(0, CKR_TRCM);
+ WR4(sc, I2S_CKR, ckr);
+
+ if (play && (setmode & AUMODE_PLAY) != 0) {
+ if (play->channels & 1)
+ return EINVAL;
+ txcr = RD4(sc, I2S_TXCR);
+ txcr &= ~TXCR_VDW;
+ txcr |= __SHIFTIN(play->validbits - 1, TXCR_VDW);
+ txcr &= ~TXCR_TCSR;
+ txcr |= __SHIFTIN(play->channels / 2 - 1, TXCR_TCSR);
+ WR4(sc, I2S_TXCR, txcr);
+ }
+
+ if (rec && (setmode & AUMODE_RECORD) != 0) {
+ if (rec->channels & 1)
+ return EINVAL;
+ rxcr = RD4(sc, I2S_RXCR);
+ rxcr &= ~RXCR_VDW;
+ rxcr |= __SHIFTIN(rec->validbits - 1, RXCR_VDW);
+ rxcr &= ~RXCR_RCSR;
+ rxcr |= __SHIFTIN(rec->channels / 2 - 1, RXCR_RCSR);
+ WR4(sc, I2S_RXCR, rxcr);
+ }
+
+ return 0;
+}
+
+static int
+rk_i2s_get_props(void *priv)
+{
+
+ return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
+ AUDIO_PROP_FULLDUPLEX;
+}
+
+static int
+rk_i2s_round_blocksize(void *priv, int bs, int mode,
+ const audio_params_t *params)
+{
+ bs &= ~3;
+ if (bs == 0)
+ bs = 4;
+ return bs;
+}
+
+static void *
+rk_i2s_allocm(void *priv, int dir, size_t size)
+{
+ return kmem_zalloc(size, KM_SLEEP);
+}
+
+static void
+rk_i2s_freem(void *priv, void *addr, size_t size)
+{
+ kmem_free(addr, size);
+}
+
+static int
+rk_i2s_trigger_output(void *priv, void *start, void *end, int blksize,
+ void (*intr)(void *), void *intrarg, const audio_params_t *params)
+{
+ struct rk_i2s_softc * const sc = priv;
+ struct rk_i2s_chan *ch = &sc->sc_pchan;
+ uint32_t val;
+
+ if (sc->sc_active == 0) {
+ val = RD4(sc, I2S_XFER);
+ val |= (XFER_TXS | XFER_RXS);
+ WR4(sc, I2S_XFER, val);
+ }
+
+ sc->sc_active |= XFER_TXS;
+
+ val = RD4(sc, I2S_INTCR);
+ val |= INTCR_TXEIE;
+ val &= ~INTCR_TFT;
Home |
Main Index |
Thread Index |
Old Index