1*cad38435Smrg /* $NetBSD: rk_spi.c,v 1.7 2021/05/15 08:46:00 mrg Exp $ */
29a2a6739Stnn
39a2a6739Stnn /*
49a2a6739Stnn * Copyright (c) 2019 The NetBSD Foundation, Inc.
59a2a6739Stnn * All rights reserved.
69a2a6739Stnn *
79a2a6739Stnn * This code is derived from software contributed to The NetBSD Foundation
89a2a6739Stnn * by Tobias Nygren.
99a2a6739Stnn *
109a2a6739Stnn * Redistribution and use in source and binary forms, with or without
119a2a6739Stnn * modification, are permitted provided that the following conditions
129a2a6739Stnn * are met:
139a2a6739Stnn * 1. Redistributions of source code must retain the above copyright
149a2a6739Stnn * notice, this list of conditions and the following disclaimer.
159a2a6739Stnn * 2. Redistributions in binary form must reproduce the above copyright
169a2a6739Stnn * notice, this list of conditions and the following disclaimer in the
179a2a6739Stnn * documentation and/or other materials provided with the distribution.
189a2a6739Stnn *
199a2a6739Stnn * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209a2a6739Stnn * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219a2a6739Stnn * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229a2a6739Stnn * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239a2a6739Stnn * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249a2a6739Stnn * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259a2a6739Stnn * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269a2a6739Stnn * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279a2a6739Stnn * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289a2a6739Stnn * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299a2a6739Stnn * POSSIBILITY OF SUCH DAMAGE.
309a2a6739Stnn */
319a2a6739Stnn
329a2a6739Stnn #include <sys/cdefs.h>
33*cad38435Smrg __KERNEL_RCSID(0, "$NetBSD: rk_spi.c,v 1.7 2021/05/15 08:46:00 mrg Exp $");
349a2a6739Stnn
359a2a6739Stnn #include <sys/param.h>
369a2a6739Stnn #include <sys/device.h>
379a2a6739Stnn #include <sys/systm.h>
389a2a6739Stnn #include <sys/bus.h>
399a2a6739Stnn #include <sys/intr.h>
409a2a6739Stnn #include <sys/kernel.h>
419a2a6739Stnn #include <sys/bitops.h>
429a2a6739Stnn #include <dev/spi/spivar.h>
439a2a6739Stnn #include <dev/fdt/fdtvar.h>
449a2a6739Stnn #include <arm/fdt/arm_fdtvar.h>
459a2a6739Stnn
469a2a6739Stnn #define SPI_CTRLR0 0x00
479a2a6739Stnn #define SPI_CTRLR0_MTM __BIT(21)
489a2a6739Stnn #define SPI_CTRLR0_OPM __BIT(20)
499a2a6739Stnn #define SPI_CTRLR0_XFM __BITS(19, 18)
509a2a6739Stnn #define SPI_CTRLR0_FRF __BITS(17, 16)
519a2a6739Stnn #define SPI_CTRLR0_RSD __BITS(15, 14)
529a2a6739Stnn #define SPI_CTRLR0_BHT __BIT(13)
539a2a6739Stnn #define SPI_CTRLR0_FBM __BIT(12)
549a2a6739Stnn #define SPI_CTRLR0_EM __BIT(11)
559a2a6739Stnn #define SPI_CTRLR0_RW __BIT(10)
569a2a6739Stnn #define SPI_CTRLR0_CSM __BITS(9, 8)
579a2a6739Stnn #define SPI_CTRLR0_SCPOL __BIT(7)
589a2a6739Stnn #define SPI_CTRLR0_SCPH __BIT(6)
599a2a6739Stnn #define SPI_CTRLR0_CFS __BITS(5, 2)
609a2a6739Stnn #define SPI_CTRLR0_DFS __BITS(1, 0)
619a2a6739Stnn #define SPI_CTRLR0_DFS_4BIT 0x0
629a2a6739Stnn #define SPI_CTRLR0_DFS_8BIT 0x1
639a2a6739Stnn #define SPI_CTRLR0_DFS_16BIT 0x2
649a2a6739Stnn
659a2a6739Stnn #define SPI_CTRLR1 0x04
669a2a6739Stnn #define SPI_CTRLR1_NDM __BITS(15, 0)
679a2a6739Stnn
689a2a6739Stnn #define SPI_ENR 0x08
699a2a6739Stnn #define SPI_ENR_ENR __BIT(0)
709a2a6739Stnn
719a2a6739Stnn #define SPI_SER 0x0c
729a2a6739Stnn #define SPI_SER_SER1 __BIT(1)
739a2a6739Stnn #define SPI_SER_SER0 __BIT(0)
749a2a6739Stnn
759a2a6739Stnn #define SPI_BAUDR 0x10
769a2a6739Stnn #define SPI_BAUDR_BAUDR __BITS(15, 0)
779a2a6739Stnn
789a2a6739Stnn #define SPI_TXFTLR 0x14
799a2a6739Stnn #define SPI_TXFTLR_TXFLTR __BITS(4, 0)
809a2a6739Stnn
819a2a6739Stnn #define SPI_RXFTLR 0x18
829a2a6739Stnn #define SPI_RXFLTR_RXFLTR __BITS(4, 0)
839a2a6739Stnn
849a2a6739Stnn #define SPI_TXFLR 0x1c
859a2a6739Stnn #define SPI_TXFLR_TXFLR __BITS(5, 0)
869a2a6739Stnn
879a2a6739Stnn #define SPI_RXFLR 0x20
889a2a6739Stnn #define SPI_RXFLR_RXFLR __BITS(5, 0)
899a2a6739Stnn
909a2a6739Stnn #define SPI_SR 0x24
919a2a6739Stnn #define SPI_SR_RFF __BIT(4)
929a2a6739Stnn #define SPI_SR_RFE __BIT(3)
939a2a6739Stnn #define SPI_SR_TFE __BIT(2)
949a2a6739Stnn #define SPI_SR_TFF __BIT(1)
959a2a6739Stnn #define SPI_SR_BSF __BIT(0)
969a2a6739Stnn
979a2a6739Stnn #define SPI_IPR 0x28
989a2a6739Stnn #define SPI_IPR_IPR __BIT(0)
999a2a6739Stnn
1009a2a6739Stnn #define SPI_IMR 0x2c
1019a2a6739Stnn #define SPI_IMR_RFFIM __BIT(4)
1029a2a6739Stnn #define SPI_IMR_RFOIM __BIT(3)
1039a2a6739Stnn #define SPI_IMR_RFUIM __BIT(2)
1049a2a6739Stnn #define SPI_IMR_TFOIM __BIT(1)
1059a2a6739Stnn #define SPI_IMR_TFEIM __BIT(0)
1069a2a6739Stnn
1079a2a6739Stnn #define SPI_ISR 0x30
1089a2a6739Stnn #define SPI_ISR_RFFIS __BIT(4)
1099a2a6739Stnn #define SPI_ISR_RFOIS __BIT(3)
1109a2a6739Stnn #define SPI_ISR_RFUIS __BIT(2)
1119a2a6739Stnn #define SPI_ISR_TFOIS __BIT(1)
1129a2a6739Stnn #define SPI_ISR_TFEIS __BIT(0)
1139a2a6739Stnn
1149a2a6739Stnn #define SPI_RISR 0x34
1159a2a6739Stnn #define SPI_RISR_RFFRIS __BIT(4)
1169a2a6739Stnn #define SPI_RISR_RFORIS __BIT(3)
1179a2a6739Stnn #define SPI_RISR_RFURIS __BIT(2)
1189a2a6739Stnn #define SPI_RISR_TFORIS __BIT(1)
1199a2a6739Stnn #define SPI_RISR_TFERIS __BIT(0)
1209a2a6739Stnn
1219a2a6739Stnn #define SPI_ICR 0x38
1229a2a6739Stnn #define SPI_ICR_CTFOI __BIT(3)
1239a2a6739Stnn #define SPI_ICR_CRFOI __BIT(2)
1249a2a6739Stnn #define SPI_ICR_CRFUI __BIT(1)
1259a2a6739Stnn #define SPI_ICR_CCI __BIT(0)
1269a2a6739Stnn #define SPI_ICR_ALL __BITS(3, 0)
1279a2a6739Stnn
1289a2a6739Stnn #define SPI_DMACR 0x3c
1299a2a6739Stnn #define SPI_DMACR_TDE __BIT(1)
1309a2a6739Stnn #define SPI_DMACR_RDE __BIT(0)
1319a2a6739Stnn
1329a2a6739Stnn #define SPI_DMATDLR 0x40
1339a2a6739Stnn #define SPI_DMATDLR_TDL __BITS(4, 0)
1349a2a6739Stnn
1359a2a6739Stnn #define SPI_DMARDLR 0x44
1369a2a6739Stnn #define SPI_DMARDLR_RDL __BITS(4, 0)
1379a2a6739Stnn
1389a2a6739Stnn #define SPI_TXDR 0x400
1399a2a6739Stnn #define SPI_TXDR_TXDR __BITS(15, 0)
1409a2a6739Stnn
1419a2a6739Stnn #define SPI_RXDR 0x800
1429a2a6739Stnn #define SPI_RXDR_RXDR __BITS(15, 0)
1439a2a6739Stnn
1449a2a6739Stnn #define SPI_FIFOLEN 32
1459a2a6739Stnn
1466e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
1476e54367aSthorpej { .compat = "rockchip,rk3066-spi" },
1486e54367aSthorpej { .compat = "rockchip,rk3328-spi" },
1496e54367aSthorpej { .compat = "rockchip,rk3399-spi" },
1506e54367aSthorpej DEVICE_COMPAT_EOL
1519a2a6739Stnn };
1529a2a6739Stnn
1539a2a6739Stnn struct rk_spi_softc {
1549a2a6739Stnn device_t sc_dev;
1559a2a6739Stnn bus_space_tag_t sc_bst;
1569a2a6739Stnn bus_space_handle_t sc_bsh;
1579a2a6739Stnn void *sc_ih;
1589a2a6739Stnn u_int sc_spi_freq;
1599a2a6739Stnn struct spi_controller sc_spi;
1609a2a6739Stnn SIMPLEQ_HEAD(,spi_transfer) sc_q;
1619a2a6739Stnn struct spi_transfer *sc_transfer;
1629a2a6739Stnn struct spi_chunk *sc_rchunk, *sc_wchunk;
1639a2a6739Stnn volatile bool sc_running;
1649a2a6739Stnn };
1659a2a6739Stnn
1669a2a6739Stnn #define SPIREG_READ(sc, reg) \
1679a2a6739Stnn bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
1689a2a6739Stnn #define SPIREG_WRITE(sc, reg, val) \
1699a2a6739Stnn bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
1709a2a6739Stnn
1715715c05aStnn static struct spi_controller *rk_spi_get_controller(device_t);
1729a2a6739Stnn static int rk_spi_match(device_t, cfdata_t, void *);
1739a2a6739Stnn static void rk_spi_attach(device_t, device_t, void *);
1749a2a6739Stnn
1759a2a6739Stnn static int rk_spi_configure(void *, int, int, int);
1769a2a6739Stnn static int rk_spi_transfer(void *, struct spi_transfer *);
1779a2a6739Stnn
1789a2a6739Stnn static void rk_spi_txfifo_fill(struct rk_spi_softc * const, size_t);
1799a2a6739Stnn static void rk_spi_rxfifo_drain(struct rk_spi_softc * const, size_t);
1809a2a6739Stnn static void rk_spi_rxtx(struct rk_spi_softc * const);
1819a2a6739Stnn static void rk_spi_set_interrupt_mask(struct rk_spi_softc * const);
1829a2a6739Stnn static void rk_spi_start(struct rk_spi_softc * const);
1839a2a6739Stnn static int rk_spi_intr(void *);
1849a2a6739Stnn
1859a2a6739Stnn CFATTACH_DECL_NEW(rk_spi, sizeof(struct rk_spi_softc),
1869a2a6739Stnn rk_spi_match, rk_spi_attach, NULL, NULL);
1879a2a6739Stnn
1885715c05aStnn static const struct fdtbus_spi_controller_func rk_spi_funcs = {
1895715c05aStnn .get_controller = rk_spi_get_controller
1905715c05aStnn };
1915715c05aStnn
1925715c05aStnn static struct spi_controller *
rk_spi_get_controller(device_t dev)1935715c05aStnn rk_spi_get_controller(device_t dev)
1945715c05aStnn {
1955715c05aStnn struct rk_spi_softc * const sc = device_private(dev);
1965715c05aStnn
1975715c05aStnn return &sc->sc_spi;
1985715c05aStnn }
1995715c05aStnn
2009a2a6739Stnn static int
rk_spi_match(device_t parent,cfdata_t cf,void * aux)2019a2a6739Stnn rk_spi_match(device_t parent, cfdata_t cf, void *aux)
2029a2a6739Stnn {
2039a2a6739Stnn struct fdt_attach_args * const faa = aux;
2049a2a6739Stnn
2056e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
2069a2a6739Stnn }
2079a2a6739Stnn
2089a2a6739Stnn static void
rk_spi_attach(device_t parent,device_t self,void * aux)2099a2a6739Stnn rk_spi_attach(device_t parent, device_t self, void *aux)
2109a2a6739Stnn {
2119a2a6739Stnn struct rk_spi_softc * const sc = device_private(self);
2129a2a6739Stnn struct fdt_attach_args * const faa = aux;
2139a2a6739Stnn const int phandle = faa->faa_phandle;
2149a2a6739Stnn bus_addr_t addr;
2159a2a6739Stnn bus_size_t size;
2169a2a6739Stnn struct clk *sclk, *pclk;
2179a2a6739Stnn char intrstr[128];
2189a2a6739Stnn
2199a2a6739Stnn sc->sc_dev = self;
2209a2a6739Stnn sc->sc_bst = faa->faa_bst;
2219a2a6739Stnn SIMPLEQ_INIT(&sc->sc_q);
2229a2a6739Stnn
2239a2a6739Stnn if ((sclk = fdtbus_clock_get(phandle, "spiclk")) == NULL
2249a2a6739Stnn || clk_enable(sclk) != 0) {
2259a2a6739Stnn aprint_error(": couldn't enable sclk\n");
2269a2a6739Stnn return;
2279a2a6739Stnn }
2289a2a6739Stnn
2299a2a6739Stnn if ((pclk = fdtbus_clock_get(phandle, "apb_pclk")) == NULL
2309a2a6739Stnn || clk_enable(pclk) != 0) {
2319a2a6739Stnn aprint_error(": couldn't enable pclk\n");
2329a2a6739Stnn return;
2339a2a6739Stnn }
2349a2a6739Stnn
2359a2a6739Stnn sc->sc_spi_freq = clk_get_rate(sclk);
2369a2a6739Stnn
2379a2a6739Stnn if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0
2389a2a6739Stnn || bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
2399a2a6739Stnn aprint_error(": couldn't map registers\n");
2409a2a6739Stnn return;
2419a2a6739Stnn }
2429a2a6739Stnn
2439a2a6739Stnn SPIREG_WRITE(sc, SPI_ENR, 0);
2449a2a6739Stnn SPIREG_WRITE(sc, SPI_IMR, 0);
2459a2a6739Stnn
2469a2a6739Stnn if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
2479a2a6739Stnn aprint_error(": failed to decode interrupt\n");
2489a2a6739Stnn return;
2499a2a6739Stnn }
2509a2a6739Stnn
25164e248edSryo sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 0,
25264e248edSryo rk_spi_intr, sc, device_xname(self));
2539a2a6739Stnn if (sc->sc_ih == NULL) {
2549a2a6739Stnn aprint_error(": unable to establish interrupt\n");
2559a2a6739Stnn return;
2569a2a6739Stnn }
2579a2a6739Stnn
2589a2a6739Stnn aprint_naive("\n");
2599a2a6739Stnn aprint_normal(": SPI\n");
2609a2a6739Stnn aprint_normal_dev(self, "interrupting on %s\n", intrstr);
2619a2a6739Stnn
2629a2a6739Stnn sc->sc_spi.sct_cookie = sc;
2639a2a6739Stnn sc->sc_spi.sct_configure = rk_spi_configure;
2649a2a6739Stnn sc->sc_spi.sct_transfer = rk_spi_transfer;
2659a2a6739Stnn sc->sc_spi.sct_nslaves = 2;
2669a2a6739Stnn
2675715c05aStnn fdtbus_register_spi_controller(self, phandle, &rk_spi_funcs);
2685715c05aStnn (void) fdtbus_attach_spibus(self, phandle, spibus_print);
2699a2a6739Stnn }
2709a2a6739Stnn
2719a2a6739Stnn static int
rk_spi_configure(void * cookie,int slave,int mode,int speed)2729a2a6739Stnn rk_spi_configure(void *cookie, int slave, int mode, int speed)
2739a2a6739Stnn {
2749a2a6739Stnn struct rk_spi_softc * const sc = cookie;
2759a2a6739Stnn uint32_t ctrlr0;
2769a2a6739Stnn uint16_t divider;
2779a2a6739Stnn
2789a2a6739Stnn divider = (sc->sc_spi_freq / speed) & ~1;
2793108ff76Stnn if (divider < 2) {
2803108ff76Stnn aprint_error_dev(sc->sc_dev,
2813108ff76Stnn "spi_clk %u is too low for speed %u, using speed %u\n",
2823108ff76Stnn sc->sc_spi_freq, speed, sc->sc_spi_freq / 2);
2833108ff76Stnn divider = 2;
2843108ff76Stnn }
2859a2a6739Stnn
2869a2a6739Stnn if (slave >= sc->sc_spi.sct_nslaves)
2879a2a6739Stnn return EINVAL;
2889a2a6739Stnn
2899a2a6739Stnn ctrlr0 = SPI_CTRLR0_BHT | __SHIFTIN(SPI_CTRLR0_DFS_8BIT, SPI_CTRLR0_DFS);
2909a2a6739Stnn
2919a2a6739Stnn switch (mode) {
2929a2a6739Stnn case SPI_MODE_0:
2939a2a6739Stnn ctrlr0 |= 0;
2949a2a6739Stnn break;
2959a2a6739Stnn case SPI_MODE_1:
2969a2a6739Stnn ctrlr0 |= SPI_CTRLR0_SCPH;
2979a2a6739Stnn break;
2989a2a6739Stnn case SPI_MODE_2:
2999a2a6739Stnn ctrlr0 |= SPI_CTRLR0_SCPOL;
3009a2a6739Stnn break;
3019a2a6739Stnn case SPI_MODE_3:
3029a2a6739Stnn ctrlr0 |= SPI_CTRLR0_SCPH | SPI_CTRLR0_SCPOL;
3039a2a6739Stnn break;
3049a2a6739Stnn default:
3059a2a6739Stnn return EINVAL;
3069a2a6739Stnn }
3079a2a6739Stnn
3089a2a6739Stnn SPIREG_WRITE(sc, SPI_ENR, 0);
3099a2a6739Stnn SPIREG_WRITE(sc, SPI_SER, 0);
3109a2a6739Stnn SPIREG_WRITE(sc, SPI_CTRLR0, ctrlr0);
3119a2a6739Stnn SPIREG_WRITE(sc, SPI_BAUDR, divider);
3129a2a6739Stnn
3139a2a6739Stnn SPIREG_WRITE(sc, SPI_DMACR, 0);
3149a2a6739Stnn SPIREG_WRITE(sc, SPI_DMATDLR, 0);
3159a2a6739Stnn SPIREG_WRITE(sc, SPI_DMARDLR, 0);
3169a2a6739Stnn
3179a2a6739Stnn SPIREG_WRITE(sc, SPI_IPR, 0);
3189a2a6739Stnn SPIREG_WRITE(sc, SPI_IMR, 0);
3199a2a6739Stnn SPIREG_WRITE(sc, SPI_ICR, SPI_ICR_ALL);
3209a2a6739Stnn
3219a2a6739Stnn SPIREG_WRITE(sc, SPI_ENR, 1);
3229a2a6739Stnn
3239a2a6739Stnn return 0;
3249a2a6739Stnn }
3259a2a6739Stnn
3269a2a6739Stnn static int
rk_spi_transfer(void * cookie,struct spi_transfer * st)3279a2a6739Stnn rk_spi_transfer(void *cookie, struct spi_transfer *st)
3289a2a6739Stnn {
3299a2a6739Stnn struct rk_spi_softc * const sc = cookie;
3309a2a6739Stnn int s;
3319a2a6739Stnn
3329a2a6739Stnn s = splbio();
3339a2a6739Stnn spi_transq_enqueue(&sc->sc_q, st);
3349a2a6739Stnn if (sc->sc_running == false) {
3359a2a6739Stnn rk_spi_start(sc);
3369a2a6739Stnn }
3379a2a6739Stnn splx(s);
3389a2a6739Stnn
3399a2a6739Stnn return 0;
3409a2a6739Stnn }
3419a2a6739Stnn
3429a2a6739Stnn static void
rk_spi_txfifo_fill(struct rk_spi_softc * const sc,size_t maxlen)3439a2a6739Stnn rk_spi_txfifo_fill(struct rk_spi_softc * const sc, size_t maxlen)
3449a2a6739Stnn {
3459a2a6739Stnn struct spi_chunk *chunk = sc->sc_wchunk;
3469a2a6739Stnn size_t len;
3479a2a6739Stnn uint8_t b;
3489a2a6739Stnn
3499a2a6739Stnn if (chunk == NULL)
3509a2a6739Stnn return;
3519a2a6739Stnn
3529a2a6739Stnn len = MIN(maxlen, chunk->chunk_wresid);
3539a2a6739Stnn chunk->chunk_wresid -= len;
3549a2a6739Stnn while (len--) {
3559a2a6739Stnn if (chunk->chunk_wptr) {
3569a2a6739Stnn b = *chunk->chunk_wptr++;
3579a2a6739Stnn } else {
3589a2a6739Stnn b = 0;
3599a2a6739Stnn }
3609a2a6739Stnn bus_space_write_1(sc->sc_bst, sc->sc_bsh, SPI_TXDR, b);
3619a2a6739Stnn }
3629a2a6739Stnn if (sc->sc_wchunk->chunk_wresid == 0) {
3639a2a6739Stnn sc->sc_wchunk = sc->sc_wchunk->chunk_next;
3649a2a6739Stnn }
3659a2a6739Stnn }
3669a2a6739Stnn
3679a2a6739Stnn static void
rk_spi_rxfifo_drain(struct rk_spi_softc * const sc,size_t maxlen)3689a2a6739Stnn rk_spi_rxfifo_drain(struct rk_spi_softc * const sc, size_t maxlen)
3699a2a6739Stnn {
3709a2a6739Stnn struct spi_chunk *chunk = sc->sc_rchunk;
3719a2a6739Stnn size_t len;
3729a2a6739Stnn uint8_t b;
3739a2a6739Stnn
3749a2a6739Stnn if (chunk == NULL)
3759a2a6739Stnn return;
3769a2a6739Stnn
3779a2a6739Stnn len = MIN(maxlen, chunk->chunk_rresid);
3789a2a6739Stnn chunk->chunk_rresid -= len;
3799a2a6739Stnn
3809a2a6739Stnn while (len--) {
3819a2a6739Stnn b = bus_space_read_1(sc->sc_bst, sc->sc_bsh, SPI_RXDR);
3829a2a6739Stnn if (chunk->chunk_rptr) {
3839a2a6739Stnn *chunk->chunk_rptr++ = b;
3849a2a6739Stnn }
3859a2a6739Stnn }
3869a2a6739Stnn if (sc->sc_rchunk->chunk_rresid == 0) {
3879a2a6739Stnn sc->sc_rchunk = sc->sc_rchunk->chunk_next;
3889a2a6739Stnn }
3899a2a6739Stnn }
3909a2a6739Stnn
3919a2a6739Stnn static void
rk_spi_rxtx(struct rk_spi_softc * const sc)3929a2a6739Stnn rk_spi_rxtx(struct rk_spi_softc * const sc)
3939a2a6739Stnn {
3949a2a6739Stnn bool again;
3959a2a6739Stnn uint32_t reg;
3969a2a6739Stnn size_t avail;
3979a2a6739Stnn
3989a2a6739Stnn /* Service both FIFOs until no more progress can be made. */
3999a2a6739Stnn again = true;
4009a2a6739Stnn while (again) {
4019a2a6739Stnn again = false;
4029a2a6739Stnn reg = SPIREG_READ(sc, SPI_RXFLR);
4039a2a6739Stnn avail = __SHIFTOUT(reg, SPI_RXFLR_RXFLR);
4049a2a6739Stnn if (avail > 0) {
4059a2a6739Stnn KASSERT(sc->sc_rchunk != NULL);
4069a2a6739Stnn rk_spi_rxfifo_drain(sc, avail);
4079a2a6739Stnn again = true;
4089a2a6739Stnn }
4099a2a6739Stnn reg = SPIREG_READ(sc, SPI_TXFLR);
4109a2a6739Stnn avail = SPI_FIFOLEN - __SHIFTOUT(reg, SPI_TXFLR_TXFLR);
4119a2a6739Stnn if (avail > 0 && sc->sc_wchunk != NULL) {
4129a2a6739Stnn rk_spi_txfifo_fill(sc, avail);
4139a2a6739Stnn again = true;
4149a2a6739Stnn }
4159a2a6739Stnn }
4169a2a6739Stnn }
4179a2a6739Stnn
4189a2a6739Stnn static void
rk_spi_set_interrupt_mask(struct rk_spi_softc * const sc)4199a2a6739Stnn rk_spi_set_interrupt_mask(struct rk_spi_softc * const sc)
4209a2a6739Stnn {
4219a2a6739Stnn uint32_t imr = SPI_IMR_RFOIM | SPI_IMR_RFUIM | SPI_IMR_TFOIM;
4229a2a6739Stnn int len;
4239a2a6739Stnn
4249a2a6739Stnn /*
4259a2a6739Stnn * Delay rx interrupts until the FIFO has the # of bytes we'd
4269a2a6739Stnn * ideally like to receive, or FIFO is half full.
4279a2a6739Stnn */
4289a2a6739Stnn len = sc->sc_rchunk != NULL
4299a2a6739Stnn ? MIN(sc->sc_rchunk->chunk_rresid, SPI_FIFOLEN / 2) : 0;
4309a2a6739Stnn if (len > 0) {
4319a2a6739Stnn SPIREG_WRITE(sc, SPI_RXFTLR, len - 1);
4329a2a6739Stnn imr |= SPI_IMR_RFFIM;
4339a2a6739Stnn }
4349a2a6739Stnn
4359a2a6739Stnn /*
4369a2a6739Stnn * Delay tx interrupts until the FIFO can accept the # of bytes we'd
4379a2a6739Stnn * ideally like to transmit, or the FIFO is half empty.
4389a2a6739Stnn */
4399a2a6739Stnn len = sc->sc_wchunk != NULL
4409a2a6739Stnn ? MIN(sc->sc_wchunk->chunk_wresid, SPI_FIFOLEN / 2) : 0;
4419a2a6739Stnn if (len > 0) {
4429a2a6739Stnn SPIREG_WRITE(sc, SPI_TXFTLR, SPI_FIFOLEN - len);
4439a2a6739Stnn imr |= SPI_IMR_TFEIM;
4449a2a6739Stnn }
4459a2a6739Stnn
4469a2a6739Stnn /* If xfer is done, then interrupt as soon as the tx fifo is empty. */
4479a2a6739Stnn if (!ISSET(imr, (SPI_IMR_RFFIM | SPI_IMR_TFEIM))) {
4489a2a6739Stnn SPIREG_WRITE(sc, SPI_TXFTLR, 0);
4499a2a6739Stnn imr |= SPI_IMR_TFEIM;
4509a2a6739Stnn }
4519a2a6739Stnn
4529a2a6739Stnn SPIREG_WRITE(sc, SPI_IMR, imr);
4539a2a6739Stnn }
4549a2a6739Stnn
4559a2a6739Stnn static void
rk_spi_start(struct rk_spi_softc * const sc)4569a2a6739Stnn rk_spi_start(struct rk_spi_softc * const sc)
4579a2a6739Stnn {
4589a2a6739Stnn struct spi_transfer *st;
4599a2a6739Stnn
4609a2a6739Stnn while ((st = spi_transq_first(&sc->sc_q)) != NULL) {
4619a2a6739Stnn spi_transq_dequeue(&sc->sc_q);
4629a2a6739Stnn KASSERT(sc->sc_transfer == NULL);
4639a2a6739Stnn sc->sc_transfer = st;
4649a2a6739Stnn sc->sc_rchunk = sc->sc_wchunk = st->st_chunks;
4659a2a6739Stnn sc->sc_running = true;
4669a2a6739Stnn
4679a2a6739Stnn KASSERT(st->st_slave < sc->sc_spi.sct_nslaves);
4689a2a6739Stnn SPIREG_WRITE(sc, SPI_SER, 1 << st->st_slave);
4699a2a6739Stnn
4709a2a6739Stnn rk_spi_rxtx(sc);
4719a2a6739Stnn rk_spi_set_interrupt_mask(sc);
4729a2a6739Stnn
4739a2a6739Stnn if (!cold)
4749a2a6739Stnn return;
4759a2a6739Stnn
4769a2a6739Stnn for (;;) {
4779a2a6739Stnn (void) rk_spi_intr(sc);
4789a2a6739Stnn if (ISSET(st->st_flags, SPI_F_DONE))
4799a2a6739Stnn break;
4809a2a6739Stnn }
4819a2a6739Stnn }
4829a2a6739Stnn sc->sc_running = false;
4839a2a6739Stnn }
4849a2a6739Stnn
4859a2a6739Stnn static int
rk_spi_intr(void * cookie)4869a2a6739Stnn rk_spi_intr(void *cookie)
4879a2a6739Stnn {
4889a2a6739Stnn struct rk_spi_softc * const sc = cookie;
4899a2a6739Stnn struct spi_transfer *st;
4909a2a6739Stnn uint32_t isr;
4919a2a6739Stnn uint32_t sr;
4929a2a6739Stnn uint32_t icr = SPI_ICR_CCI;
4939a2a6739Stnn
4949a2a6739Stnn isr = SPIREG_READ(sc, SPI_ISR);
4959a2a6739Stnn if (!isr)
4969a2a6739Stnn return 0;
4979a2a6739Stnn
4989a2a6739Stnn if (ISSET(isr, SPI_ISR_RFOIS)) {
4999a2a6739Stnn device_printf(sc->sc_dev, "RXFIFO overflow\n");
5009a2a6739Stnn icr |= SPI_ICR_CRFOI;
5019a2a6739Stnn }
5029a2a6739Stnn if (ISSET(isr, SPI_ISR_RFUIS)) {
5039a2a6739Stnn device_printf(sc->sc_dev, "RXFIFO underflow\n");
5049a2a6739Stnn icr |= SPI_ICR_CRFUI;
5059a2a6739Stnn }
5069a2a6739Stnn if (ISSET(isr, SPI_ISR_TFOIS)) {
5079a2a6739Stnn device_printf(sc->sc_dev, "TXFIFO overflow\n");
5089a2a6739Stnn icr |= SPI_ICR_CTFOI;
5099a2a6739Stnn }
5109a2a6739Stnn
5119a2a6739Stnn rk_spi_rxtx(sc);
5129a2a6739Stnn
5139a2a6739Stnn if (sc->sc_rchunk == NULL && sc->sc_wchunk == NULL) {
5149a2a6739Stnn do {
5159a2a6739Stnn sr = SPIREG_READ(sc, SPI_SR);
5169a2a6739Stnn } while (ISSET(sr, SPI_SR_BSF));
5179a2a6739Stnn SPIREG_WRITE(sc, SPI_IMR, 0);
5189a2a6739Stnn SPIREG_WRITE(sc, SPI_SER, 0);
5199a2a6739Stnn st = sc->sc_transfer;
5209a2a6739Stnn sc->sc_transfer = NULL;
5219a2a6739Stnn KASSERT(st != NULL);
5229a2a6739Stnn spi_done(st, 0);
5239a2a6739Stnn sc->sc_running = false;
5249a2a6739Stnn } else {
5259a2a6739Stnn rk_spi_set_interrupt_mask(sc);
5269a2a6739Stnn }
5279a2a6739Stnn
5289a2a6739Stnn SPIREG_WRITE(sc, SPI_ICR, icr);
5299a2a6739Stnn
5309a2a6739Stnn return 1;
5319a2a6739Stnn }
532