summaryrefslogtreecommitdiff
path: root/libhw/rp2040_include
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-04 00:18:23 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-04 00:18:23 -0700
commit47cee5df1e5e63a8d0a5f1b634ac6d4e1ff00af7 (patch)
treed72daabeedecbc397cdce739639f8cf2cb947685 /libhw/rp2040_include
parent355d7a495b0ca1a622d600427a8c737f3207a803 (diff)
parent3f49a57b99e7fe5aafa73e70ed146d98b1ae174c (diff)
Merge branch 'lukeshu/dma'
Diffstat (limited to 'libhw/rp2040_include')
-rw-r--r--libhw/rp2040_include/libhw/rp2040_hwspi.h75
1 files changed, 57 insertions, 18 deletions
diff --git a/libhw/rp2040_include/libhw/rp2040_hwspi.h b/libhw/rp2040_include/libhw/rp2040_hwspi.h
index 76e0709..eb54cdc 100644
--- a/libhw/rp2040_include/libhw/rp2040_hwspi.h
+++ b/libhw/rp2040_include/libhw/rp2040_hwspi.h
@@ -9,6 +9,7 @@
#include <pico/binary_info.h> /* for bi_* */
+#include <libcr_ipc/sema.h>
#include <libmisc/private.h>
#include <libhw/generic/spi.h>
@@ -20,9 +21,19 @@ 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 dma_tx_data;
+ uint dma_tx_ctrl;
+ uint dma_rx_data;
+ uint dma_rx_ctrl;
- uint pin_cs;
+ /* mutable */
+ uint64_t dead_until_ns;
+ cr_sema_t sema;
END_PRIVATE(LIBHW_RP2040_HWSPI_H)
};
LO_IMPLEMENTATION_H(io_duplex_readwriter, struct rp2040_hwspi, rp2040_hwspi)
@@ -31,14 +42,18 @@ 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
+ * @param dma{1-4} : uint : DMA channel; any unused channel
*
* There is no bit-order argument; the RP2040's hardware SPI always
* uses MSB-first bit order.
@@ -48,16 +63,32 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi)
* the CPU. This is because the PL022 has a maximum of 16-bit frames,
* but we need to be able to do *at least* 32-bit frames (and ideally,
* much larger). By managing it ourselves, we can just keep CS pulled
- * low extra-long, making the frame extra-long. However, this means
- * that we can't SPI so fast that the CPU can't do things in time;
- * experimentally much faster than 60MHz seems to be when I start
- * getting mangled messages. We wouldn't have this speed limit with a
- * PIO-based SPI driver, because it could toggle CLK and CS in
- * lock-step with receiving data from the FIFO.
+ * low extra-long, making the frame extra-long.
+ *
+ * Restrictions on baudrate:
+ *
+ * - The PL022 requires that the baudrate is an even-number fraction
+ * of clk_peri.
+ * + This implies that the maximum baudrate is clk_peri/2.
+ * + Pico-SDK' default clk_peri is 125MHz, max is 200MHz.
+ * - The CS-from-GPIO hack above means that that we can't go so fast
+ * that the CPU can't do things in time.
+ * + Experimentally:
+ * | clk_sys=125MHz | baud=31.25MHz | works OK |
+ * | clk_sys=160MHz | baud=40 MHz | works OK |
+ * | clk_sys=170MHz | baud=42.5 MHz | works OK |
+ * | clk_sys=180MHz | baud=45 MHz | mangled in funny ways? |
+ * | clk_sys=200MHz | baud=50 MHz | messages get shifted right a bit |
+ * | clk_sys=125MHz | baud=62.5 MHz | messages get shifted right a bit |
+ *
+ * Both of these restrictions aught to be avoidable by using a
+ * PIO-based SPI driver instead of this PLL02-based driver.
*/
#define rp2040_hwspi_init(self, name, \
inst_num, mode, baudrate_hz, \
- pin_miso, pin_mosi, pin_clk, pin_cs) \
+ min_delay_ns, bogus_data, \
+ pin_miso, pin_mosi, pin_clk, pin_cs, \
+ dma1, dma2, dma3, dma4) \
do { \
bi_decl(bi_4pins_with_names(pin_miso, name" SPI MISO", \
pin_mosi, name" SPI MOSI", \
@@ -65,15 +96,23 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi)
pin_mosi, name" SPI CS")); \
_rp2040_hwspi_init(self, \
inst_num, mode, baudrate_hz, \
- pin_miso, pin_mosi, pin_clk, pin_cs); \
+ min_delay_ns, bogus_data, \
+ pin_miso, pin_mosi, pin_clk, pin_cs, \
+ dma1, dma2, dma3, dma4); \
} 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,
- uint pin_cs);
+ uint pin_cs,
+ uint dma1,
+ uint dma2,
+ uint dma3,
+ uint dma4);
#endif /* _LIBHW_RP2040_HWSPI_H_ */