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/5463b10a206a
branches:  trunk
changeset: 846433:5463b10a206a
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 0fb1a18d0f18 -r 5463b10a206a 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 0fb1a18d0f18 -r 5463b10a206a 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