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