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 rk_spi: Rockchip SPI driver



details:   https://anonhg.NetBSD.org/src/rev/3af6ed9f6035
branches:  trunk
changeset: 964510:3af6ed9f6035
user:      tnn <tnn%NetBSD.org@localhost>
date:      Mon Aug 05 15:22:59 2019 +0000

description:
rk_spi: Rockchip SPI driver

Match only on RK3399 for now, but should work on RK3328 as well with
the proper CRU support. If you can, please test and enable for RK3328.

diffstat:

 sys/arch/arm/rockchip/files.rockchip |    7 +-
 sys/arch/arm/rockchip/rk_spi.c       |  517 +++++++++++++++++++++++++++++++++++
 2 files changed, 523 insertions(+), 1 deletions(-)

diffs (truncated from 542 to 300 lines):

diff -r f893c2ca1a5d -r 3af6ed9f6035 sys/arch/arm/rockchip/files.rockchip
--- a/sys/arch/arm/rockchip/files.rockchip      Mon Aug 05 15:06:47 2019 +0000
+++ b/sys/arch/arm/rockchip/files.rockchip      Mon Aug 05 15:22:59 2019 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.rockchip,v 1.19 2019/05/01 10:41:33 jmcneill Exp $
+#      $NetBSD: files.rockchip,v 1.20 2019/08/05 15:22:59 tnn Exp $
 #
 # Configuration info for Rockchip family SoCs
 #
@@ -42,6 +42,11 @@
 attach rkiic at fdt with rk_i2c
 file   arch/arm/rockchip/rk_i2c.c              rk_i2c
 
+# SPI
+device rkspi: spibus
+attach rkspi at fdt with rk_spi
+file   arch/arm/rockchip/rk_spi.c              rk_spi
+
 # USB PHY
 device rkusb { }
 attach rkusb at fdt with rk_usb
diff -r f893c2ca1a5d -r 3af6ed9f6035 sys/arch/arm/rockchip/rk_spi.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/rockchip/rk_spi.c    Mon Aug 05 15:22:59 2019 +0000
@@ -0,0 +1,517 @@
+/*     $NetBSD: rk_spi.c,v 1.1 2019/08/05 15:22:59 tnn Exp $   */
+
+/*
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tobias Nygren.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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_spi.c,v 1.1 2019/08/05 15:22:59 tnn Exp $");
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/intr.h>
+#include <sys/kernel.h>
+#include <sys/bitops.h>
+#include <dev/spi/spivar.h>
+#include <dev/fdt/fdtvar.h>
+#include <arm/fdt/arm_fdtvar.h>
+
+#define SPI_CTRLR0             0x00
+#define SPI_CTRLR0_MTM         __BIT(21)
+#define SPI_CTRLR0_OPM         __BIT(20)
+#define SPI_CTRLR0_XFM         __BITS(19, 18)
+#define SPI_CTRLR0_FRF         __BITS(17, 16)
+#define SPI_CTRLR0_RSD         __BITS(15, 14)
+#define SPI_CTRLR0_BHT         __BIT(13)
+#define SPI_CTRLR0_FBM         __BIT(12)
+#define SPI_CTRLR0_EM          __BIT(11)
+#define SPI_CTRLR0_RW          __BIT(10)
+#define SPI_CTRLR0_CSM         __BITS(9, 8)
+#define SPI_CTRLR0_SCPOL       __BIT(7)
+#define SPI_CTRLR0_SCPH                __BIT(6)
+#define SPI_CTRLR0_CFS         __BITS(5, 2)
+#define SPI_CTRLR0_DFS         __BITS(1, 0)
+#define SPI_CTRLR0_DFS_4BIT    0x0
+#define SPI_CTRLR0_DFS_8BIT    0x1
+#define SPI_CTRLR0_DFS_16BIT   0x2
+
+#define SPI_CTRLR1             0x04
+#define SPI_CTRLR1_NDM         __BITS(15, 0)
+
+#define SPI_ENR                        0x08
+#define SPI_ENR_ENR            __BIT(0)
+
+#define SPI_SER                        0x0c
+#define SPI_SER_SER1           __BIT(1)
+#define SPI_SER_SER0           __BIT(0)
+
+#define SPI_BAUDR              0x10
+#define SPI_BAUDR_BAUDR                __BITS(15, 0)
+
+#define SPI_TXFTLR             0x14
+#define SPI_TXFTLR_TXFLTR      __BITS(4, 0)
+
+#define SPI_RXFTLR             0x18
+#define SPI_RXFLTR_RXFLTR      __BITS(4, 0)
+
+#define SPI_TXFLR              0x1c
+#define SPI_TXFLR_TXFLR                __BITS(5, 0)
+
+#define SPI_RXFLR              0x20
+#define SPI_RXFLR_RXFLR                __BITS(5, 0)
+
+#define SPI_SR                 0x24
+#define SPI_SR_RFF             __BIT(4)
+#define SPI_SR_RFE             __BIT(3)
+#define SPI_SR_TFE             __BIT(2)
+#define SPI_SR_TFF             __BIT(1)
+#define SPI_SR_BSF             __BIT(0)
+
+#define SPI_IPR                        0x28
+#define SPI_IPR_IPR            __BIT(0)
+
+#define SPI_IMR                        0x2c
+#define SPI_IMR_RFFIM          __BIT(4)
+#define SPI_IMR_RFOIM          __BIT(3)
+#define SPI_IMR_RFUIM          __BIT(2)
+#define SPI_IMR_TFOIM          __BIT(1)
+#define SPI_IMR_TFEIM          __BIT(0)
+
+#define SPI_ISR                        0x30
+#define SPI_ISR_RFFIS          __BIT(4)
+#define SPI_ISR_RFOIS          __BIT(3)
+#define SPI_ISR_RFUIS          __BIT(2)
+#define SPI_ISR_TFOIS          __BIT(1)
+#define SPI_ISR_TFEIS          __BIT(0)
+
+#define SPI_RISR               0x34
+#define SPI_RISR_RFFRIS                __BIT(4)
+#define SPI_RISR_RFORIS                __BIT(3)
+#define SPI_RISR_RFURIS                __BIT(2)
+#define SPI_RISR_TFORIS                __BIT(1)
+#define SPI_RISR_TFERIS                __BIT(0)
+
+#define SPI_ICR                        0x38
+#define SPI_ICR_CTFOI          __BIT(3)
+#define SPI_ICR_CRFOI          __BIT(2)
+#define SPI_ICR_CRFUI          __BIT(1)
+#define SPI_ICR_CCI            __BIT(0)
+#define SPI_ICR_ALL            __BITS(3, 0)
+
+#define SPI_DMACR              0x3c
+#define SPI_DMACR_TDE          __BIT(1)
+#define SPI_DMACR_RDE          __BIT(0)
+
+#define SPI_DMATDLR            0x40
+#define SPI_DMATDLR_TDL                __BITS(4, 0)
+
+#define SPI_DMARDLR            0x44
+#define SPI_DMARDLR_RDL                __BITS(4, 0)
+
+#define SPI_TXDR               0x400
+#define SPI_TXDR_TXDR          __BITS(15, 0)
+
+#define SPI_RXDR               0x800
+#define SPI_RXDR_RXDR          __BITS(15, 0)
+
+#define SPI_FIFOLEN            32
+
+static const char * const compatible[] = {
+#if 0 /* should work on RK3328 but untested */
+       "rockchip,rk3066-spi",
+       "rockchip,rk3328-spi",
+#endif         
+       "rockchip,rk3399-spi",
+       NULL
+};
+
+struct rk_spi_softc {
+       device_t                sc_dev;
+       bus_space_tag_t         sc_bst;
+       bus_space_handle_t      sc_bsh;
+       void                    *sc_ih;
+       u_int                   sc_spi_freq;
+       struct spi_controller   sc_spi;
+       SIMPLEQ_HEAD(,spi_transfer) sc_q;
+       struct spi_transfer     *sc_transfer;
+       struct spi_chunk        *sc_rchunk, *sc_wchunk;
+       volatile bool           sc_running;
+};
+
+#define SPIREG_READ(sc, reg) \
+    bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define SPIREG_WRITE(sc, reg, val) \
+    bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int rk_spi_match(device_t, cfdata_t, void *);
+static void rk_spi_attach(device_t, device_t, void *);
+
+static int rk_spi_configure(void *, int, int, int);
+static int rk_spi_transfer(void *, struct spi_transfer *);
+
+static void rk_spi_txfifo_fill(struct rk_spi_softc * const, size_t);
+static void rk_spi_rxfifo_drain(struct rk_spi_softc * const, size_t);
+static void rk_spi_rxtx(struct rk_spi_softc * const);
+static void rk_spi_set_interrupt_mask(struct rk_spi_softc * const);
+static void rk_spi_start(struct rk_spi_softc * const);
+static int rk_spi_intr(void *);
+
+CFATTACH_DECL_NEW(rk_spi, sizeof(struct rk_spi_softc),
+    rk_spi_match, rk_spi_attach, NULL, NULL);
+
+static int
+rk_spi_match(device_t parent, cfdata_t cf, void *aux)
+{
+       struct fdt_attach_args * const faa = aux;
+
+       return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+rk_spi_attach(device_t parent, device_t self, void *aux)
+{
+       struct rk_spi_softc * const sc = device_private(self);
+       struct fdt_attach_args * const faa = aux;
+       const int phandle = faa->faa_phandle;
+       bus_addr_t addr;
+       bus_size_t size;
+       struct clk *sclk, *pclk;
+       char intrstr[128];
+       struct spibus_attach_args sba;
+       
+       sc->sc_dev = self;
+       sc->sc_bst = faa->faa_bst;
+       SIMPLEQ_INIT(&sc->sc_q);
+
+       if ((sclk = fdtbus_clock_get(phandle, "spiclk")) == NULL
+           || clk_enable(sclk) != 0) {
+               aprint_error(": couldn't enable sclk\n");
+               return;
+       }
+
+       if ((pclk = fdtbus_clock_get(phandle, "apb_pclk")) == NULL
+           || clk_enable(pclk) != 0) {
+               aprint_error(": couldn't enable pclk\n");
+               return;
+       }
+
+       sc->sc_spi_freq = clk_get_rate(sclk);
+
+       if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0
+           || bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+               aprint_error(": couldn't map registers\n");
+               return;
+       }
+
+       SPIREG_WRITE(sc, SPI_ENR, 0);
+       SPIREG_WRITE(sc, SPI_IMR, 0);
+
+       if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+               aprint_error(": failed to decode interrupt\n");
+               return;
+       }
+
+       sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM, 0, rk_spi_intr, sc);
+       if (sc->sc_ih == NULL) {
+               aprint_error(": unable to establish interrupt\n");
+               return;
+       }
+
+       aprint_naive("\n");
+       aprint_normal(": SPI\n");
+       aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+
+       sc->sc_spi.sct_cookie = sc;
+       sc->sc_spi.sct_configure = rk_spi_configure;
+       sc->sc_spi.sct_transfer = rk_spi_transfer;
+       sc->sc_spi.sct_nslaves = 2;
+
+       sba.sba_controller = &sc->sc_spi;
+
+       (void) config_found_ia(self, "spibus", &sba, spibus_print);
+}
+
+static int
+rk_spi_configure(void *cookie, int slave, int mode, int speed)
+{
+       struct rk_spi_softc * const sc = cookie;
+       uint32_t ctrlr0;
+       uint16_t divider;
+
+       divider = (sc->sc_spi_freq / speed) & ~1;
+       if (divider < 2)
+               return EINVAL;
+
+       if (slave >= sc->sc_spi.sct_nslaves)
+               return EINVAL;
+
+       ctrlr0 = SPI_CTRLR0_BHT | __SHIFTIN(SPI_CTRLR0_DFS_8BIT, SPI_CTRLR0_DFS);



Home | Main Index | Thread Index | Old Index