1 /*
2  * Copyright (c) 2019 Antmicro <www.antmicro.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT litex_eth0
8 
9 #define LOG_MODULE_NAME eth_liteeth
10 #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
11 
12 #include <logging/log.h>
13 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
14 
15 #include <kernel.h>
16 #include <device.h>
17 #include <soc.h>
18 #include <stdbool.h>
19 #include <net/ethernet.h>
20 #include <net/net_if.h>
21 #include <net/net_pkt.h>
22 
23 #include <sys/printk.h>
24 
25 #include "eth.h"
26 
27 /* flags */
28 #define LITEETH_EV_TX		0x1
29 #define LITEETH_EV_RX		0x1
30 
31 /* slots */
32 #define LITEETH_SLOT_BASE	DT_INST_REG_ADDR_BY_NAME(0, buffers)
33 #define LITEETH_SLOT_RX0	((LITEETH_SLOT_BASE) + 0x0000)
34 #define LITEETH_SLOT_RX1	((LITEETH_SLOT_BASE) + 0x0800)
35 #define LITEETH_SLOT_TX0	((LITEETH_SLOT_BASE) + 0x1000)
36 #define LITEETH_SLOT_TX1	((LITEETH_SLOT_BASE) + 0x1800)
37 
38 /* sram - rx */
39 #define LITEETH_RX_BASE		DT_INST_REG_ADDR_BY_NAME(0, control)
40 #define LITEETH_RX_SLOT		((LITEETH_RX_BASE) + 0x00)
41 #define LITEETH_RX_LENGTH	((LITEETH_RX_BASE) + 0x04)
42 #define LITEETH_RX_EV_PENDING	((LITEETH_RX_BASE) + 0x28)
43 #define LITEETH_RX_EV_ENABLE	((LITEETH_RX_BASE) + 0x2c)
44 
45 /* sram - tx */
46 #define LITEETH_TX_BASE		((DT_INST_REG_ADDR_BY_NAME(0, control)) + 0x30)
47 #define LITEETH_TX_START	((LITEETH_TX_BASE) + 0x00)
48 #define LITEETH_TX_READY	((LITEETH_TX_BASE) + 0x04)
49 #define LITEETH_TX_SLOT		((LITEETH_TX_BASE) + 0x0c)
50 #define LITEETH_TX_LENGTH	((LITEETH_TX_BASE) + 0x10)
51 #define LITEETH_TX_EV_PENDING	((LITEETH_TX_BASE) + 0x1c)
52 
53 /* irq */
54 #define LITEETH_IRQ		DT_INST_IRQN(0)
55 #define LITEETH_IRQ_PRIORITY	DT_INST_IRQ(0, priority)
56 
57 #define MAX_TX_FAILURE 100
58 
59 struct eth_liteeth_dev_data {
60 	struct net_if *iface;
61 	uint8_t mac_addr[6];
62 
63 	uint8_t txslot;
64 	uint8_t rxslot;
65 
66 	uint8_t *tx_buf[2];
67 	uint8_t *rx_buf[2];
68 };
69 
70 struct eth_liteeth_config {
71 	void (*config_func)(void);
72 };
73 
eth_initialize(const struct device * dev)74 static int eth_initialize(const struct device *dev)
75 {
76 	const struct eth_liteeth_config *config = dev->config;
77 
78 	config->config_func();
79 
80 	return 0;
81 }
82 
eth_tx(const struct device * dev,struct net_pkt * pkt)83 static int eth_tx(const struct device *dev, struct net_pkt *pkt)
84 {
85 	int key;
86 	uint16_t len;
87 	struct eth_liteeth_dev_data *context = dev->data;
88 
89 	key = irq_lock();
90 	int attempts = 0;
91 
92 	/* get data from packet and send it */
93 	len = net_pkt_get_len(pkt);
94 	net_pkt_read(pkt, context->tx_buf[context->txslot], len);
95 
96 	sys_write8(context->txslot, LITEETH_TX_SLOT);
97 	sys_write8(len >> 8, LITEETH_TX_LENGTH);
98 	sys_write8(len & 0xFF, LITEETH_TX_LENGTH + 4);
99 
100 	/* wait for the device to be ready to transmit */
101 	while (sys_read8(LITEETH_TX_READY) == 0) {
102 		if (attempts++ == MAX_TX_FAILURE) {
103 			goto error;
104 		}
105 		k_sleep(K_MSEC(1));
106 	}
107 
108 	/* start transmitting */
109 	sys_write8(1, LITEETH_TX_START);
110 
111 	/* change slot */
112 	context->txslot = (context->txslot + 1) % 2;
113 
114 	irq_unlock(key);
115 
116 	return 0;
117 error:
118 	irq_unlock(key);
119 	LOG_ERR("TX fifo failed");
120 	return -1;
121 }
122 
eth_rx(const struct device * port)123 static void eth_rx(const struct device *port)
124 {
125 	struct net_pkt *pkt;
126 	struct eth_liteeth_dev_data *context = port->data;
127 
128 	int r;
129 	unsigned int key;
130 	uint16_t len = 0;
131 
132 	key = irq_lock();
133 
134 	/* get frame's length */
135 	for (int i = 0; i < 4; i++) {
136 		len <<= 8;
137 		len |= sys_read8(LITEETH_RX_LENGTH + i * 0x4);
138 	}
139 
140 	/* which slot is the frame in */
141 	context->rxslot = sys_read8(LITEETH_RX_SLOT);
142 
143 	/* obtain rx buffer */
144 	pkt = net_pkt_rx_alloc_with_buffer(context->iface, len, AF_UNSPEC, 0,
145 					   K_NO_WAIT);
146 	if (pkt == NULL) {
147 		LOG_ERR("Failed to obtain RX buffer");
148 		goto out;
149 	}
150 
151 	/* copy data to buffer */
152 	if (net_pkt_write(pkt, (void *)context->rx_buf[context->rxslot], len) != 0) {
153 		LOG_ERR("Failed to append RX buffer to context buffer");
154 		net_pkt_unref(pkt);
155 		goto out;
156 	}
157 
158 	/* receive data */
159 	r = net_recv_data(context->iface, pkt);
160 	if (r < 0) {
161 		LOG_ERR("Failed to enqueue frame into RX queue: %d", r);
162 		net_pkt_unref(pkt);
163 	}
164 
165 out:
166 	irq_unlock(key);
167 }
168 
eth_irq_handler(const struct device * port)169 static void eth_irq_handler(const struct device *port)
170 {
171 	/* check sram reader events (tx) */
172 	if (sys_read8(LITEETH_TX_EV_PENDING) & LITEETH_EV_TX) {
173 		/* TX event is not enabled nor used by this driver; ack just
174 		 * in case if some rogue TX event appeared
175 		 */
176 		sys_write8(LITEETH_EV_TX, LITEETH_TX_EV_PENDING);
177 	}
178 
179 	/* check sram writer events (rx) */
180 	if (sys_read8(LITEETH_RX_EV_PENDING) & LITEETH_EV_RX) {
181 		eth_rx(port);
182 
183 		/* ack writer irq */
184 		sys_write8(LITEETH_EV_RX, LITEETH_RX_EV_PENDING);
185 	}
186 }
187 
188 #ifdef CONFIG_ETH_LITEETH_0
189 
190 static struct eth_liteeth_dev_data eth_data = {
191 	.mac_addr =  DT_INST_PROP(0, local_mac_address)
192 };
193 
194 static void eth_irq_config(void);
195 static const struct eth_liteeth_config eth_config = {
196 	.config_func = eth_irq_config,
197 };
198 
eth_iface_init(struct net_if * iface)199 static void eth_iface_init(struct net_if *iface)
200 {
201 	const struct device *port = net_if_get_device(iface);
202 	struct eth_liteeth_dev_data *context = port->data;
203 	static bool init_done;
204 
205 	/* initialize only once */
206 	if (init_done) {
207 		return;
208 	}
209 
210 	/* set interface */
211 	context->iface = iface;
212 
213 	/* initialize ethernet L2 */
214 	ethernet_init(iface);
215 
216 #if DT_INST_PROP(0, zephyr_random_mac_address)
217 	/* generate random MAC address */
218 	gen_random_mac(context->mac_addr, 0x10, 0xe2, 0xd5);
219 #endif
220 
221 	/* set MAC address */
222 	if (net_if_set_link_addr(iface, context->mac_addr, sizeof(context->mac_addr),
223 			     NET_LINK_ETHERNET) < 0) {
224 		LOG_ERR("setting mac failed");
225 		return;
226 	}
227 
228 	/* clear pending events */
229 	sys_write8(LITEETH_EV_TX, LITEETH_TX_EV_PENDING);
230 	sys_write8(LITEETH_EV_RX, LITEETH_RX_EV_PENDING);
231 
232 	/* setup tx slots */
233 	context->txslot = 0;
234 	context->tx_buf[0] = (uint8_t *)LITEETH_SLOT_TX0;
235 	context->tx_buf[1] = (uint8_t *)LITEETH_SLOT_TX1;
236 
237 	/* setup rx slots */
238 	context->rxslot = 0;
239 	context->rx_buf[0] = (uint8_t *)LITEETH_SLOT_RX0;
240 	context->rx_buf[1] = (uint8_t *)LITEETH_SLOT_RX1;
241 
242 	init_done = true;
243 }
244 
eth_caps(const struct device * dev)245 static enum ethernet_hw_caps eth_caps(const struct device *dev)
246 {
247 	ARG_UNUSED(dev);
248 	return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T |
249 	       ETHERNET_LINK_1000BASE_T;
250 }
251 
252 static const struct ethernet_api eth_api = {
253 	.iface_api.init = eth_iface_init,
254 	.get_capabilities = eth_caps,
255 	.send = eth_tx
256 };
257 
258 NET_DEVICE_DT_INST_DEFINE(0, eth_initialize, NULL,
259 		&eth_data, &eth_config, CONFIG_ETH_INIT_PRIORITY, &eth_api,
260 		ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), NET_ETH_MTU);
261 
eth_irq_config(void)262 static void eth_irq_config(void)
263 {
264 	IRQ_CONNECT(LITEETH_IRQ, LITEETH_IRQ_PRIORITY, eth_irq_handler,
265 		    DEVICE_DT_INST_GET(0), 0);
266 	irq_enable(LITEETH_IRQ);
267 	sys_write8(1, LITEETH_RX_EV_ENABLE);
268 }
269 
270 #endif /* CONFIG_ETH_LITEETH_0 */
271