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 ð_data, ð_config, CONFIG_ETH_INIT_PRIORITY, ð_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