summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/sbc_harness/main.c2
-rw-r--r--libhw/rp2040_hwspi.c15
-rw-r--r--libhw/rp2040_include/libhw/rp2040_hwspi.h30
3 files changed, 36 insertions, 11 deletions
diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c
index 6fa76bd..a3351fc 100644
--- a/cmd/sbc_harness/main.c
+++ b/cmd/sbc_harness/main.c
@@ -169,6 +169,8 @@ COROUTINE init_cr(void *) {
rp2040_hwspi_init(&globals.dev_spi, "W5500", RP2040_HWSPI_0,
SPI_MODE_0, /* the W5500 supports mode 0 or mode 3 */
31250000, /* min(w5500, hwspi); w5500=80MHz; hwspi=31.25MHz, see rp2040_hwspi.h for a comment about why this is so low */
+ 30, /* W5500 datasheet says min(T_CS = SCSn High Time) = 30ns */
+ 0, /* bogus write write data when doing a read */
16, /* PIN_MISO */
19, /* PIN_MOSI */
18, /* PIN_CLK */
diff --git a/libhw/rp2040_hwspi.c b/libhw/rp2040_hwspi.c
index ac46451..8dd49d6 100644
--- a/libhw/rp2040_hwspi.c
+++ b/libhw/rp2040_hwspi.c
@@ -18,6 +18,8 @@
#define IMPLEMENTATION_FOR_LIBHW_RP2040_HWSPI_H YES
#include <libhw/rp2040_hwspi.h>
+#include <libhw/generic/alarmclock.h>
+
#include "config.h"
#ifndef CONFIG_RP2040_SPI_DEBUG
@@ -39,6 +41,8 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self,
enum rp2040_hwspi_instance inst_num,
enum spi_mode mode,
uint baudrate_hz,
+ uint64_t min_delay_ns,
+ uint8_t bogus_data,
uint pin_miso,
uint pin_mosi,
uint pin_clk,
@@ -100,9 +104,12 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self,
gpio_set_dir(pin_cs, GPIO_OUT);
gpio_put(pin_cs, 1);
- /* Return. */
+ /* Initialize self. */
self->inst = inst;
+ self->min_delay_ns = min_delay_ns;
+ self->bogus_data = bogus_data;
self->pin_cs = pin_cs;
+ self->dead_until_ns = 0;
}
static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct duplex_iovec *iov, int iovcnt) {
@@ -113,6 +120,9 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl
assert(iov);
assert(iovcnt);
+ uint64_t now = LO_CALL(bootclock, get_time_ns);
+ if (now < self->dead_until_ns)
+ sleep_until_ns(self->dead_until_ns);
gpio_put(self->pin_cs, 0);
/* TODO: Replace blocking reads+writes with DMA. */
for (int i = 0; i < iovcnt; i++) {
@@ -121,9 +131,10 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl
else if (iov[i].iov_write_src)
spi_write_blocking(inst, iov[i].iov_write_src, iov[i].iov_len);
else if (iov[i].iov_read_dst)
- spi_read_blocking(inst, 0, iov[i].iov_read_dst, iov[i].iov_len);
+ spi_read_blocking(inst, self->bogus_data, iov[i].iov_read_dst, iov[i].iov_len);
else
assert_notreached("duplex_iovec is neither read nor write");
}
gpio_put(self->pin_cs, 1);
+ self->dead_until_ns = LO_CALL(bootclock, get_time_ns) + self->min_delay_ns;
}
diff --git a/libhw/rp2040_include/libhw/rp2040_hwspi.h b/libhw/rp2040_include/libhw/rp2040_hwspi.h
index a1d85d4..fef1dbd 100644
--- a/libhw/rp2040_include/libhw/rp2040_hwspi.h
+++ b/libhw/rp2040_include/libhw/rp2040_hwspi.h
@@ -20,9 +20,14 @@ enum rp2040_hwspi_instance {
struct rp2040_hwspi {
BEGIN_PRIVATE(LIBHW_RP2040_HWSPI_H)
+ /* const */
LM_IF(IS_IMPLEMENTATION_FOR(LIBHW_RP2040_HWSPI_H))(spi_inst_t)(void) *inst;
+ uint64_t min_delay_ns;
+ uint8_t bogus_data;
+ uint pin_cs;
- uint pin_cs;
+ /* mutable */
+ uint64_t dead_until_ns;
END_PRIVATE(LIBHW_RP2040_HWSPI_H)
};
LO_IMPLEMENTATION_H(io_duplex_readwriter, struct rp2040_hwspi, rp2040_hwspi)
@@ -31,14 +36,17 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi)
/**
* Initialize an instance of `struct rp2040_hwspi`.
*
- * @param self : struct rp2040_hwspi : the structure to initialize
- * @param name : char * : a name for the SPI port; to include in the bininfo
- * @param inst_num : enum rp2040_hwspi_instance : the PL220 instance number; RP2040_HWSPI_{0,1}
- * @param mode : enum spi_mode : the SPI mode; SPI_MODE_{0..3}
- * @param pin_miso : uint : pin number; 0, 4, 16, or 20 for _HWSPI_0; 8, 12, 24, or 28 for _HWSPI_1
- * @param pin_mosi : uint : pin number; 3, 7, 19, or 23 for _HWSPI_0; 11, 15, or 27 for _HWSPI_1
- * @param pin_clk : uint : pin number; 2, 6, 18, or 22 for _HWSPI_0; 10, 14, or 26 for _HWSPI_1
- * @param pin_cs : uint : pin number; any unused GPIO pin
+ * @param self : struct rp2040_hwspi : the structure to initialize
+ * @param name : char * : a name for the SPI port; to include in the bininfo
+ * @param inst_num : enum rp2040_hwspi_instance : the PL220 instance number; RP2040_HWSPI_{0,1}
+ * @param mode : enum spi_mode : the SPI mode; SPI_MODE_{0..3}
+ * @param baudrate_hz : uint : baudrate in Hz
+ * @param min_delay_ns: uint64_t : minimum time for pin_cs to be high between messages
+ * @param bogus_data : uint8_t : bogus data to write when .iov_write_src is NULL
+ * @param pin_miso : uint : pin number; 0, 4, 16, or 20 for _HWSPI_0; 8, 12, 24, or 28 for _HWSPI_1
+ * @param pin_mosi : uint : pin number; 3, 7, 19, or 23 for _HWSPI_0; 11, 15, or 27 for _HWSPI_1
+ * @param pin_clk : uint : pin number; 2, 6, 18, or 22 for _HWSPI_0; 10, 14, or 26 for _HWSPI_1
+ * @param pin_cs : uint : pin number; any unused GPIO pin
*
* There is no bit-order argument; the RP2040's hardware SPI always
* uses MSB-first bit order.
@@ -67,6 +75,7 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi)
*/
#define rp2040_hwspi_init(self, name, \
inst_num, mode, baudrate_hz, \
+ min_delay_ns, bogus_data, \
pin_miso, pin_mosi, pin_clk, pin_cs) \
do { \
bi_decl(bi_4pins_with_names(pin_miso, name" SPI MISO", \
@@ -75,12 +84,15 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi)
pin_mosi, name" SPI CS")); \
_rp2040_hwspi_init(self, \
inst_num, mode, baudrate_hz, \
+ min_delay_ns, bogus_data, \
pin_miso, pin_mosi, pin_clk, pin_cs); \
} while(0)
void _rp2040_hwspi_init(struct rp2040_hwspi *self,
enum rp2040_hwspi_instance inst_num,
enum spi_mode mode,
uint baudrate_hz,
+ uint64_t min_delay_ns,
+ uint8_t bogus_data,
uint pin_miso,
uint pin_mosi,
uint pin_clk,