Module Name: src
Committed By: tnn
Date: Sat Aug 3 14:42:24 UTC 2019
Modified Files:
src/sys/arch/arm/sunxi: sun6i_spi.c
Log Message:
sun6i_spi: bring over non-intrusive improvements from sun4i_spi
- simplify attach error handling
- calculate minfreq & maxfreq instead of hardcoding
- print configured value of SPI_SCLK
- add convenience macro for reading/writing SPI register
- clean up commented out debug printfs
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/sunxi/sun6i_spi.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/sunxi/sun6i_spi.c
diff -u src/sys/arch/arm/sunxi/sun6i_spi.c:1.2 src/sys/arch/arm/sunxi/sun6i_spi.c:1.3
--- src/sys/arch/arm/sunxi/sun6i_spi.c:1.2 Thu Feb 1 14:50:36 2018
+++ src/sys/arch/arm/sunxi/sun6i_spi.c Sat Aug 3 14:42:24 2019
@@ -1,6 +1,7 @@
-/* $NetBSD: sun6i_spi.c,v 1.2 2018/02/01 14:50:36 jakllsch Exp $ */
+/* $NetBSD: sun6i_spi.c,v 1.3 2019/08/03 14:42:24 tnn Exp $ */
/*
+ * Copyright (c) 2019 Tobias Nygren
* Copyright (c) 2018 Jonathan A. Kollasch
* All rights reserved.
*
@@ -27,12 +28,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sun6i_spi.c,v 1.2 2018/02/01 14:50:36 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sun6i_spi.c,v 1.3 2019/08/03 14:42:24 tnn Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
-#include <sys/mutex.h>
#include <sys/bus.h>
#include <sys/intr.h>
#include <sys/kernel.h>
@@ -64,6 +64,11 @@ struct sun6ispi_softc {
volatile bool sc_running;
};
+#define SPIREG_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define SPIREG_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+
static int sun6ispi_match(device_t, cfdata_t, void *);
static void sun6ispi_attach(device_t, device_t, void *);
@@ -97,52 +102,37 @@ sun6ispi_attach(device_t parent, device_
struct sun6ispi_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
struct spibus_attach_args sba;
+ const int phandle = faa->faa_phandle;
+ bus_addr_t addr;
+ bus_size_t size;
struct fdtbus_reset *rst;
struct clk *clk, *modclk;
uint32_t gcr, isr;
char intrstr[128];
- aprint_naive("\n");
- aprint_normal(": SPI\n");
-
sc->sc_dev = self;
sc->sc_iot = faa->faa_bst;
SIMPLEQ_INIT(&sc->sc_q);
- const int phandle = faa->faa_phandle;
- bus_addr_t addr;
- bus_size_t size;
-
- if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
- aprint_error_dev(sc->sc_dev, "missing 'reg' property\n");
+ if ((clk = fdtbus_clock_get_index(phandle, 0)) == NULL
+ || clk_enable(clk) != 0) {
+ aprint_error(": couldn't enable clock\n");
return;
}
- if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
- aprint_error_dev(sc->sc_dev, "unable to map device\n");
+ /* 200MHz max on H3,H5 */
+ if ((modclk = fdtbus_clock_get(phandle, "mod")) == NULL
+ || clk_set_rate(modclk, 200000000) != 0
+ || clk_enable(modclk) != 0) {
+ aprint_error(": couldn't enable module clock\n");
return;
}
+ sc->sc_modclkrate = clk_get_rate(modclk);
- if ((clk = fdtbus_clock_get_index(phandle, 0)) != NULL) {
- if (clk_enable(clk) != 0) {
- aprint_error_dev(sc->sc_dev, "couldn't enable clock\n");
- return;
- }
- device_printf(self, "%s ahb @ %uHz\n", __func__, clk_get_rate(clk));
- }
-
- if ((modclk = fdtbus_clock_get(phandle, "mod")) != NULL) {
- /* 200MHz max on H3,H5 */
- if (clk_set_rate(modclk, 200000000) != 0) {
- aprint_error_dev(sc->sc_dev, "couldn't configure module clock\n");
- return;
- }
- if (clk_enable(modclk) != 0) {
- aprint_error_dev(sc->sc_dev, "couldn't enable module clock\n");
- return;
- }
- sc->sc_modclkrate = clk_get_rate(modclk);
- device_printf(self, "%s %uHz\n", __func__, sc->sc_modclkrate);
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0
+ || bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
}
if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL)
@@ -151,8 +141,8 @@ sun6ispi_attach(device_t parent, device_
return;
}
- isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SPI_INT_STA);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_INT_STA, isr);
+ isr = SPIREG_READ(sc, SPI_INT_STA);
+ SPIREG_WRITE(sc, SPI_INT_STA, isr);
if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error(": failed to decode interrupt\n");
@@ -162,13 +152,17 @@ sun6ispi_attach(device_t parent, device_
sc->sc_intrh = fdtbus_intr_establish(phandle, 0, IPL_VM, 0,
sun6ispi_intr, sc);
if (sc->sc_intrh == NULL) {
- aprint_error_dev(sc->sc_dev, "unable to establish interrupt\n");
+ aprint_error(": unable to establish interrupt\n");
return;
}
+
+ aprint_naive("\n");
+ aprint_normal(": SPI\n");
+
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
gcr = SPI_GCR_SRST;
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_GCR, gcr);
+ SPIREG_WRITE(sc, SPI_GCR, gcr);
for (u_int i = 0; ; i++) {
if (i >= 1000000) {
aprint_error_dev(self, "reset timeout\n");
@@ -181,9 +175,9 @@ sun6ispi_attach(device_t parent, device_
DELAY(1);
}
gcr = SPI_GCR_TP_EN | SPI_GCR_MODE | SPI_GCR_EN;
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_GCR, gcr);
+ SPIREG_WRITE(sc, SPI_GCR, gcr);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_IER, SPI_IER_DEFAULT);
+ SPIREG_WRITE(sc, SPI_IER, SPI_IER_DEFAULT);
sc->sc_spi.sct_cookie = sc;
sc->sc_spi.sct_configure = sun6ispi_configure;
@@ -200,21 +194,18 @@ sun6ispi_configure(void *cookie, int sla
{
struct sun6ispi_softc * const sc = cookie;
uint32_t tcr, cctl;
+ uint32_t minfreq, maxfreq;
-#if 0
- device_printf(sc->sc_dev, "%s slave %d mode %d speed %d\n", __func__, slave, mode, speed);
-
- if (speed > 200000)
- speed = 200000;
-#endif
-
- tcr = SPI_TCR_SS_LEVEL | SPI_TCR_SPOL;
+ minfreq = sc->sc_modclkrate >> 16;
+ maxfreq = sc->sc_modclkrate >> 1;
- if (slave > 3)
+ if (speed <= 0 || speed < minfreq || speed > maxfreq)
return EINVAL;
- if (speed <= 0)
+ if (slave >= sc->sc_spi.sct_nslaves)
return EINVAL;
+
+ tcr = SPI_TCR_SS_LEVEL | SPI_TCR_SPOL;
switch (mode) {
case SPI_MODE_0:
@@ -235,10 +226,7 @@ sun6ispi_configure(void *cookie, int sla
sc->sc_TCR = tcr;
- if (speed < 3000 || speed > 200000000)
- return EINVAL;
-
- if (speed > sc->sc_modclkrate / 2 || speed < sc->sc_modclkrate / 512) {
+ if (speed < sc->sc_modclkrate / 512) {
for (cctl = 0; cctl <= __SHIFTOUT_MASK(SPI_CCTL_CDR1); cctl++) {
if ((sc->sc_modclkrate / (1<<cctl)) <= speed)
goto cdr1_found;
@@ -251,8 +239,14 @@ cdr1_found:
cctl = SPI_CCTL_DRS|__SHIFTIN(cctl, SPI_CCTL_CDR2);
}
- device_printf(sc->sc_dev, "%s CCTL 0x%08x\n", __func__, cctl);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_CCTL, cctl);
+ device_printf(sc->sc_dev, "tcr 0x%x, cctl 0x%x, CLK %uHz, SCLK %uHz\n",
+ tcr, cctl, sc->sc_modclkrate,
+ (cctl & SPI_CCTL_DRS)
+ ? (sc->sc_modclkrate / (u_int)(2 * (__SHIFTOUT(cctl, SPI_CCTL_CDR2) + 1)))
+ : (sc->sc_modclkrate >> (__SHIFTOUT(cctl, SPI_CCTL_CDR1) + 1))
+ );
+
+ SPIREG_WRITE(sc, SPI_CCTL, cctl);
return 0;
}
@@ -272,27 +266,14 @@ sun6ispi_transfer(void *cookie, struct s
return 0;
}
-static size_t
-chunks_total_count(struct spi_transfer * st)
-{
- struct spi_chunk *chunk = st->st_chunks;
- size_t len = 0;
-
- do {
- len += chunk->chunk_count;
- } while ((chunk = chunk->chunk_next) != NULL);
-
- return len;
-}
-
static void
sun6ispi_start(struct sun6ispi_softc * const sc)
{
struct spi_transfer *st;
uint32_t isr, tcr;
- size_t ctc;
+ struct spi_chunk *chunk;
+ size_t burstcount;
- //device_printf(sc->sc_dev, "%s\n", __func__);
while ((st = spi_transq_first(&sc->sc_q)) != NULL) {
spi_transq_dequeue(&sc->sc_q);
@@ -302,37 +283,31 @@ sun6ispi_start(struct sun6ispi_softc * c
sc->sc_rchunk = sc->sc_wchunk = st->st_chunks;
sc->sc_running = true;
- isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SPI_INT_STA);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_INT_STA, isr);
-
- //printf("%s fcr 0x%08x\n", __func__, bus_space_read_4(sc->sc_iot, sc->sc_ioh, SPI_FCR));
-
- ctc = chunks_total_count(st);
- //printf("%s total count %zu\n", __func__, ctc);
+ isr = SPIREG_READ(sc, SPI_INT_STA);
+ SPIREG_WRITE(sc, SPI_INT_STA, isr);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_BC, __SHIFTIN(ctc, SPI_BC_MBC));
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_TC, __SHIFTIN(ctc, SPI_TC_MWTC));
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_BCC, __SHIFTIN(ctc, SPI_BCC_STC));
+ burstcount = 0;
+ for (chunk = st->st_chunks; chunk; chunk = chunk->chunk_next) {
+ burstcount += chunk->chunk_count;
+ }
+ KASSERT(burstcount <= SPI_BC_MBC);
+ SPIREG_WRITE(sc, SPI_BC, __SHIFTIN(burstcount, SPI_BC_MBC));
+ SPIREG_WRITE(sc, SPI_TC, __SHIFTIN(burstcount, SPI_TC_MWTC));
+ SPIREG_WRITE(sc, SPI_BCC, __SHIFTIN(burstcount, SPI_BCC_STC));
KASSERT(st->st_slave <= 3);
tcr = sc->sc_TCR | __SHIFTIN(st->st_slave, SPI_TCR_SS_SEL);
- //device_printf(sc->sc_dev, "%s before TCR write\n", __func__);
- //bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_TCR, tcr);
-
sun6ispi_send(sc);
const uint32_t ier = SPI_IER_DEFAULT | SPI_IER_RF_RDY_INT_EN | SPI_IER_TX_ERQ_INT_EN;
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_IER, ier);
+ SPIREG_WRITE(sc, SPI_IER, ier);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_TCR, tcr|SPI_TCR_XCH);
- //device_printf(sc->sc_dev, "%s after TCR write\n", __func__);
+ SPIREG_WRITE(sc, SPI_TCR, tcr|SPI_TCR_XCH);
if (!cold)
return;
- //device_printf(sc->sc_dev, "%s cold\n", __func__);
-
int s = splbio();
for (;;) {
sun6ispi_intr(sc);
@@ -343,7 +318,6 @@ sun6ispi_start(struct sun6ispi_softc * c
}
sc->sc_running = false;
-// device_printf(sc->sc_dev, "%s finishes\n", __func__);
}
static void
@@ -353,13 +327,10 @@ sun6ispi_send(struct sun6ispi_softc * co
uint32_t fsr;
struct spi_chunk *chunk;
- //device_printf(sc->sc_dev, "%s\n", __func__);
-
while ((chunk = sc->sc_wchunk) != NULL) {
while (chunk->chunk_wresid) {
- fsr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SPI_FSR);
+ fsr = SPIREG_READ(sc, SPI_FSR);
if (__SHIFTOUT(fsr, SPI_FSR_TF_CNT) >= 64) {
- //printf("%s fsr 0x%08x\n", __func__, fsr);
return;
}
if (chunk->chunk_wptr) {
@@ -367,7 +338,6 @@ sun6ispi_send(struct sun6ispi_softc * co
} else {
fd = '\0';
}
- //printf("%s fd %02x\n", __func__, fd);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, SPI_TXD, fd);
chunk->chunk_wresid--;
}
@@ -382,17 +352,13 @@ sun6ispi_recv(struct sun6ispi_softc * co
uint32_t fsr;
struct spi_chunk *chunk;
- //device_printf(sc->sc_dev, "%s\n", __func__);
-
while ((chunk = sc->sc_rchunk) != NULL) {
while (chunk->chunk_rresid) {
- fsr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SPI_FSR);
+ fsr = SPIREG_READ(sc, SPI_FSR);
if (__SHIFTOUT(fsr, SPI_FSR_RF_CNT) == 0) {
- //printf("%s fsr 0x%08x\n", __func__, fsr);
return;
}
fd = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SPI_RXD);
- //printf("%s fd %02x\n", __func__, fd);
if (chunk->chunk_rptr) {
*chunk->chunk_rptr++ = fd;
}
@@ -409,9 +375,8 @@ sun6ispi_intr(void *cookie)
struct spi_transfer *st;
uint32_t isr;
- isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SPI_INT_STA);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_INT_STA, isr);
- //device_printf(sc->sc_dev, "%s ISR 0x%08x\n", __func__, isr);
+ isr = SPIREG_READ(sc, SPI_INT_STA);
+ SPIREG_WRITE(sc, SPI_INT_STA, isr);
if (ISSET(isr, SPI_ISR_RX_RDY)) {
sun6ispi_recv(sc);
@@ -419,7 +384,7 @@ sun6ispi_intr(void *cookie)
}
if (ISSET(isr, SPI_ISR_TC)) {
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, SPI_IER, SPI_IER_DEFAULT);
+ SPIREG_WRITE(sc, SPI_IER, SPI_IER_DEFAULT);
sc->sc_rchunk = sc->sc_wchunk = NULL;
st = sc->sc_transfer;