summaryrefslogtreecommitdiff
path: root/cmd/sbc_harness/hw/w5500.h
blob: cf285793678598c31644af0138e1487d6c2f48e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/* hw/w5500.h - libmisc/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 _HW_W5500_H_
#define _HW_W5500_H_

#include <libcr_ipc/sema.h>
#include <libcr_ipc/mutex.h>
#include <libmisc/net.h>

#include "hw/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 */
	struct spi                      *spidev;
	uint                             pin_intr;
	uint                             pin_reset;

	/* 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,
                 struct spi* spi, uint pin_intr, uint pin_reset,
                 struct net_eth_addr addr);

/**
 * TODO.
 */
void w5500_hard_reset(struct w5500 *self, struct net_eth_addr addr);

/**
 * TODO.
 */
void w5500_soft_reset(struct w5500 *self, struct net_eth_addr addr);

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_listen(struct w5500 *self, uint8_t socknum,
                                             uint16_t port);

#endif /* _HW_W5500_H_ */