summaryrefslogtreecommitdiff
path: root/libhw/rp2040_include
diff options
context:
space:
mode:
Diffstat (limited to 'libhw/rp2040_include')
-rw-r--r--libhw/rp2040_include/libhw/rp2040_hwspi.h63
-rw-r--r--libhw/rp2040_include/libhw/w5500.h102
2 files changed, 165 insertions, 0 deletions
diff --git a/libhw/rp2040_include/libhw/rp2040_hwspi.h b/libhw/rp2040_include/libhw/rp2040_hwspi.h
new file mode 100644
index 0000000..8e44e50
--- /dev/null
+++ b/libhw/rp2040_include/libhw/rp2040_hwspi.h
@@ -0,0 +1,63 @@
+/* libhw/rp2040_hwspi.h - `implements_spi` implementation for the RP2040's
+ * ARM Primecell SSP (PL022) (header file)
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBHW_RP2040_HWSPI_H_
+#define _LIBHW_RP2040_HWSPI_H_
+
+#include <pico/binary_info.h> /* for bi_* */
+
+#include <libhw/generic/spi.h>
+
+enum rp2040_hwspi_instance {
+ RP2040_HWSPI_0 = 0,
+ RP2040_HWSPI_1 = 1,
+};
+
+struct rp2040_hwspi {
+ implements_spi;
+
+ void /*spi_inst_t*/ *inst;
+ uint pin_cs;
+};
+
+/**
+ * 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
+ *
+ * There is no bit-order argument; the RP2040's hardware SPI always
+ * uses MSB-first bit order.
+ */
+#define rp2040_hwspi_init(self, name, \
+ inst_num, mode, baudrate_hz, \
+ pin_miso, pin_mosi, pin_clk, pin_cs) \
+ do { \
+ bi_decl(bi_4pins_with_names(pin_miso, name" SPI MISO", \
+ pin_mosi, name" SPI MOSI", \
+ pin_mosi, name" SPI CLK", \
+ pin_mosi, name" SPI CS")); \
+ _rp2040_hwspi_init(self, \
+ inst_num, mode, baudrate_hz, \
+ 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,
+ uint pin_miso,
+ uint pin_mosi,
+ uint pin_clk,
+ uint pin_cs);
+
+#endif /* _LIBHW_RP2040_HWSPI_H_ */
diff --git a/libhw/rp2040_include/libhw/w5500.h b/libhw/rp2040_include/libhw/w5500.h
new file mode 100644
index 0000000..6b5a690
--- /dev/null
+++ b/libhw/rp2040_include/libhw/w5500.h
@@ -0,0 +1,102 @@
+/* libhw/w5500.h - <libhw/generic/net.h> implementation for the WIZnet W5500 chip
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBHW_W5500_H_
+#define _LIBHW_W5500_H_
+
+#include <libcr_ipc/sema.h>
+#include <libcr_ipc/mutex.h>
+
+#include <libhw/generic/net.h>
+#include <libhw/generic/spi.h>
+
+struct _w5500_tcp_conn {
+ /* const-after-init */
+ implements_net_stream_conn;
+ /* mutable */
+ bool read_open;
+ bool write_open;
+};
+
+struct _w5500_tcp_listener {
+ /* const-after-init */
+ implements_net_stream_listener;
+ uint8_t socknum;
+ struct _w5500_tcp_conn active_conn;
+
+ /* mutable */
+ uint16_t port;
+ cr_mutex_t cmd_mu;
+ cr_sema_t listen_sema, read_sema;
+};
+
+struct w5500 {
+ /* const-after-init */
+ implements_spi *spidev;
+ uint pin_intr;
+ uint pin_reset;
+ struct net_eth_addr hwaddr;
+
+ /* mutable */
+ uint16_t next_local_port;
+ struct _w5500_tcp_listener listeners[8];
+ cr_sema_t intr;
+};
+
+/**
+ * Initialize a WIZnet W5500 Ethernet-and-TCP/IP-offload chip.
+ *
+ * The W5500 has 3 lines of communication with the MCU:
+ *
+ * - An SPI-based RPC protocol:
+ * + mode: mode 0 or mode 3
+ * + bit-order: MSB-first
+ * + clock frequency: 33.3MHz - 80MHz
+ * - An interrupt pin that it pulls low when an event happens (to let
+ * the MCU know that it should do an SPI RPC "get" to see what
+ * happened.)
+ * - A reset pin that the MCU can pull low to reset the W5500.
+ */
+#define w5500_init(self, name, spi, pin_intr, pin_reset, eth_addr) do { \
+ bi_decl(bi_2pins_with_names(pin_intr, name" interrupt", \
+ pin_reset, name" reset")); \
+ _w5500_init(self, spi, pin_intr, pin_reset, eth_addr); \
+ } while (0)
+void _w5500_init(struct w5500 *self,
+ implements_spi *spi, uint pin_intr, uint pin_reset,
+ struct net_eth_addr addr);
+
+/**
+ * TODO.
+ */
+void w5500_hard_reset(struct w5500 *self);
+
+/**
+ * TODO.
+ */
+void w5500_soft_reset(struct w5500 *self);
+
+struct w5500_netcfg {
+ struct net_ip4_addr gateway_addr;
+ struct net_ip4_addr subnet_mask;
+ struct net_ip4_addr addr;
+};
+
+/**
+ * TODO.
+ */
+void w5500_netcfg(struct w5500 *self, struct w5500_netcfg cfg);
+
+implements_net_stream_listener *w5500_tcp_listen(struct w5500 *self, uint8_t socknum,
+ uint16_t port);
+
+/**
+ * TODO.
+ */
+implements_net_packet_conn *w5500_udp_conn(struct w5500 *self, uint8_t socknum,
+ uint16_t port);
+
+#endif /* _LIBHW_W5500_H_ */