blob: 1088f3eca3564bf6758f19d15336a8f8f6c09b49 [file] [log] [blame]
Yang Xiwend9717112023-08-23 01:03:42 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Hisilicon Fast Ethernet MAC Driver
4 * Adapted from linux
5 *
6 * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
7 * Copyright (c) 2023 Yang Xiwen <forbidden405@outlook.com>
8 */
9
10#include <dm.h>
11#include <clk.h>
12#include <miiphy.h>
13#include <net.h>
14#include <reset.h>
15#include <wait_bit.h>
16#include <asm/io.h>
17#include <dm/device_compat.h>
18#include <linux/delay.h>
19#include <linux/kernel.h>
20
21/* MAC control register list */
22#define MAC_PORTSEL 0x0200
23#define MAC_PORTSEL_STAT_CPU BIT(0)
24#define MAC_PORTSEL_RMII BIT(1)
25#define MAC_PORTSET 0x0208
26#define MAC_PORTSET_DUPLEX_FULL BIT(0)
27#define MAC_PORTSET_LINKED BIT(1)
28#define MAC_PORTSET_SPEED_100M BIT(2)
29#define MAC_SET 0x0210
30#define MAX_FRAME_SIZE 1600
31#define MAX_FRAME_SIZE_MASK GENMASK(10, 0)
32#define BIT_PAUSE_EN BIT(18)
33#define RX_COALESCE_SET 0x0340
34#define RX_COALESCED_FRAME_OFFSET 24
35#define RX_COALESCED_FRAMES 8
36#define RX_COALESCED_TIMER 0x74
37#define QLEN_SET 0x0344
38#define RX_DEPTH_OFFSET 8
39#define MAX_HW_FIFO_DEPTH 64
40#define HW_TX_FIFO_DEPTH 1
41#define MAX_HW_RX_FIFO_DEPTH (MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH)
42#define HW_RX_FIFO_DEPTH min(PKTBUFSRX, MAX_HW_RX_FIFO_DEPTH)
43#define IQFRM_DES 0x0354
44#define RX_FRAME_LEN_MASK GENMASK(11, 0)
45#define RX_FRAME_IN_INDEX_MASK GENMASK(17, 12)
46#define IQ_ADDR 0x0358
47#define EQ_ADDR 0x0360
48#define EQFRM_LEN 0x0364
49#define ADDRQ_STAT 0x036C
50#define TX_CNT_INUSE_MASK GENMASK(5, 0)
51#define BIT_TX_READY BIT(24)
52#define BIT_RX_READY BIT(25)
53/* global control register list */
54#define GLB_HOSTMAC_L32 0x0000
55#define GLB_HOSTMAC_H16 0x0004
56#define GLB_SOFT_RESET 0x0008
57#define SOFT_RESET_ALL BIT(0)
58#define GLB_FWCTRL 0x0010
59#define FWCTRL_VLAN_ENABLE BIT(0)
60#define FWCTRL_FW2CPU_ENA BIT(5)
61#define FWCTRL_FWALL2CPU BIT(7)
62#define GLB_MACTCTRL 0x0014
63#define MACTCTRL_UNI2CPU BIT(1)
64#define MACTCTRL_MULTI2CPU BIT(3)
65#define MACTCTRL_BROAD2CPU BIT(5)
66#define MACTCTRL_MACT_ENA BIT(7)
67#define GLB_IRQ_STAT 0x0030
68#define GLB_IRQ_ENA 0x0034
69#define IRQ_ENA_PORT0_MASK GENMASK(7, 0)
70#define IRQ_ENA_PORT0 BIT(18)
71#define IRQ_ENA_ALL BIT(19)
72#define GLB_IRQ_RAW 0x0038
73#define IRQ_INT_RX_RDY BIT(0)
74#define IRQ_INT_TX_PER_PACKET BIT(1)
75#define IRQ_INT_TX_FIFO_EMPTY BIT(6)
76#define IRQ_INT_MULTI_RXRDY BIT(7)
77#define DEF_INT_MASK (IRQ_INT_MULTI_RXRDY | \
78 IRQ_INT_TX_PER_PACKET | \
79 IRQ_INT_TX_FIFO_EMPTY)
80#define GLB_MAC_L32_BASE 0x0100
81#define GLB_MAC_H16_BASE 0x0104
82#define MACFLT_HI16_MASK GENMASK(15, 0)
83#define BIT_MACFLT_ENA BIT(17)
84#define BIT_MACFLT_FW2CPU BIT(21)
85#define GLB_MAC_H16(reg) (GLB_MAC_H16_BASE + ((reg) * 0x8))
86#define GLB_MAC_L32(reg) (GLB_MAC_L32_BASE + ((reg) * 0x8))
87#define MAX_MAC_FILTER_NUM 8
88#define MAX_UNICAST_ADDRESSES 2
89#define MAX_MULTICAST_ADDRESSES (MAX_MAC_FILTER_NUM - \
90 MAX_UNICAST_ADDRESSES)
91/* software tx and rx queue number, should be power of 2 */
92#define TXQ_NUM 64
93#define RXQ_NUM 128
94
95#define PHY_RESET_DELAYS_PROPERTY "hisilicon,phy-reset-delays-us"
96#define MAC_RESET_DELAY_PROPERTY "hisilicon,mac-reset-delay-us"
97#define MAC_RESET_ASSERT_PERIOD 200000
98
99enum phy_reset_delays {
100 PRE_DELAY,
101 PULSE,
102 POST_DELAY,
103 DELAYS_NUM,
104};
105
106enum clk_type {
107 CLK_MAC,
108 CLK_BUS,
109 CLK_PHY,
110 CLK_NUM,
111};
112
113struct hisi_femac_priv {
114 void __iomem *port_base;
115 void __iomem *glb_base;
116 struct clk *clks[CLK_NUM];
117 struct reset_ctl *mac_rst;
118 struct reset_ctl *phy_rst;
119 u32 phy_reset_delays[DELAYS_NUM];
120 u32 mac_reset_delay;
121
122 struct phy_device *phy;
123
124 u32 link_status;
125};
126
127static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs)
128{
129 u32 val;
130
131 val = readl(priv->glb_base + GLB_IRQ_ENA);
132 writel(val | irqs, priv->glb_base + GLB_IRQ_ENA);
133}
134
135static void hisi_femac_irq_disable(struct hisi_femac_priv *priv, int irqs)
136{
137 u32 val;
138
139 val = readl(priv->glb_base + GLB_IRQ_ENA);
140 writel(val & (~irqs), priv->glb_base + GLB_IRQ_ENA);
141}
142
143static void hisi_femac_port_init(struct hisi_femac_priv *priv)
144{
145 u32 val;
146
147 /* MAC gets link status info and phy mode by software config */
148 val = MAC_PORTSEL_STAT_CPU;
149 if (priv->phy->interface == PHY_INTERFACE_MODE_RMII)
150 val |= MAC_PORTSEL_RMII;
151 writel(val, priv->port_base + MAC_PORTSEL);
152
153 /*clear all interrupt status */
154 writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
155 hisi_femac_irq_disable(priv, IRQ_ENA_PORT0_MASK | IRQ_ENA_PORT0);
156
157 val = readl(priv->glb_base + GLB_FWCTRL);
158 val &= ~(FWCTRL_VLAN_ENABLE | FWCTRL_FWALL2CPU);
159 val |= FWCTRL_FW2CPU_ENA;
160 writel(val, priv->glb_base + GLB_FWCTRL);
161
162 val = readl(priv->glb_base + GLB_MACTCTRL);
163 val |= (MACTCTRL_BROAD2CPU | MACTCTRL_MACT_ENA);
164 writel(val, priv->glb_base + GLB_MACTCTRL);
165
166 val = readl(priv->port_base + MAC_SET);
167 val &= ~MAX_FRAME_SIZE_MASK;
168 val |= MAX_FRAME_SIZE;
169 writel(val, priv->port_base + MAC_SET);
170
171 val = RX_COALESCED_TIMER |
172 (RX_COALESCED_FRAMES << RX_COALESCED_FRAME_OFFSET);
173 writel(val, priv->port_base + RX_COALESCE_SET);
174
175 val = (HW_RX_FIFO_DEPTH << RX_DEPTH_OFFSET) | HW_TX_FIFO_DEPTH;
176 writel(val, priv->port_base + QLEN_SET);
177}
178
179static void hisi_femac_rx_refill(struct hisi_femac_priv *priv)
180{
181 int i;
182 ulong addr;
183
184 for (i = 0; i < HW_RX_FIFO_DEPTH; i++) {
185 addr = (ulong)net_rx_packets[i];
186 writel(addr, priv->port_base + IQ_ADDR);
187 }
188}
189
190static void hisi_femac_adjust_link(struct udevice *dev)
191{
192 struct hisi_femac_priv *priv = dev_get_priv(dev);
193 struct phy_device *phy = priv->phy;
194 u32 status = 0;
195
196 if (phy->link)
197 status |= MAC_PORTSET_LINKED;
198 if (phy->duplex == DUPLEX_FULL)
199 status |= MAC_PORTSET_DUPLEX_FULL;
200 if (phy->speed == SPEED_100)
201 status |= MAC_PORTSET_SPEED_100M;
202
203 writel(status, priv->port_base + MAC_PORTSET);
204}
205
206static int hisi_femac_port_reset(struct hisi_femac_priv *priv)
207{
208 u32 val;
209
210 val = readl(priv->glb_base + GLB_SOFT_RESET);
211 val |= SOFT_RESET_ALL;
212 writel(val, priv->glb_base + GLB_SOFT_RESET);
213
214 udelay(800);
215
216 val &= ~SOFT_RESET_ALL;
217 writel(val, priv->glb_base + GLB_SOFT_RESET);
218
219 return 0;
220}
221
222static int hisi_femac_set_hw_mac_addr(struct udevice *dev)
223{
224 struct hisi_femac_priv *priv = dev_get_priv(dev);
225 struct eth_pdata *plat = dev_get_plat(dev);
226 unsigned char *mac = plat->enetaddr;
227 u32 reg;
228
229 reg = mac[1] | (mac[0] << 8);
230 writel(reg, priv->glb_base + GLB_HOSTMAC_H16);
231
232 reg = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24);
233 writel(reg, priv->glb_base + GLB_HOSTMAC_L32);
234
235 return 0;
236}
237
238static int hisi_femac_start(struct udevice *dev)
239{
240 int ret;
241 struct hisi_femac_priv *priv = dev_get_priv(dev);
242
243 hisi_femac_port_reset(priv);
244 hisi_femac_set_hw_mac_addr(dev);
245 hisi_femac_rx_refill(priv);
246
247 ret = phy_startup(priv->phy);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800248 if (ret) {
249 dev_err(dev, "Failed to startup phy: %d\n", ret);
250 return log_msg_ret("phy", ret);
251 }
Yang Xiwend9717112023-08-23 01:03:42 +0800252
253 if (!priv->phy->link) {
254 debug("%s: link down\n", __func__);
255 return -ENODEV;
256 }
257
258 hisi_femac_adjust_link(dev);
259
260 writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
261 hisi_femac_irq_enable(priv, IRQ_ENA_ALL | IRQ_ENA_PORT0 | DEF_INT_MASK);
262
263 return 0;
264}
265
266static int hisi_femac_send(struct udevice *dev, void *packet, int length)
267{
268 struct hisi_femac_priv *priv = dev_get_priv(dev);
269 ulong addr = (ulong)packet;
270 int ret;
271
272 // clear previous irq
273 writel(IRQ_INT_TX_PER_PACKET, priv->glb_base + GLB_IRQ_RAW);
274
275 // flush cache
276 flush_cache(addr, length + ETH_FCS_LEN);
277
278 // write packet address
279 writel(addr, priv->port_base + EQ_ADDR);
280
281 // write packet length (and send it)
282 writel(length + ETH_FCS_LEN, priv->port_base + EQFRM_LEN);
283
284 // wait until FIFO is empty
285 ret = wait_for_bit_le32(priv->glb_base + GLB_IRQ_RAW, IRQ_INT_TX_PER_PACKET, true, 50, false);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800286 if (ret == -ETIMEDOUT) {
287 dev_err(dev, "FIFO timeout\n");
288 return log_msg_ret("net", ret);
289 }
Yang Xiwend9717112023-08-23 01:03:42 +0800290
291 return 0;
292}
293
294static int hisi_femac_recv(struct udevice *dev, int flags, uchar **packetp)
295{
296 struct hisi_femac_priv *priv = dev_get_priv(dev);
297 int val, index, length;
298
299 val = readl(priv->glb_base + GLB_IRQ_RAW);
300 if (!(val & IRQ_INT_RX_RDY))
301 return -EAGAIN;
302
303 val = readl(priv->port_base + IQFRM_DES);
304 index = (val & RX_FRAME_IN_INDEX_MASK) >> 12;
305 length = val & RX_FRAME_LEN_MASK;
306
307 // invalidate cache
308 invalidate_dcache_range((ulong)net_rx_packets[index], (ulong)net_rx_packets[index] + length);
309 *packetp = net_rx_packets[index];
310
311 // Tell hardware we will process the packet
312 writel(IRQ_INT_RX_RDY, priv->glb_base + GLB_IRQ_RAW);
313
314 return length;
315}
316
317static int hisi_femac_free_pkt(struct udevice *dev, uchar *packet, int length)
318{
319 struct hisi_femac_priv *priv = dev_get_priv(dev);
320 ulong addr = (ulong)packet;
321
322 // Tell hardware the packet can be reused
323 writel(addr, priv->port_base + IQ_ADDR);
324
325 return 0;
326}
327
328static void hisi_femac_stop(struct udevice *dev)
329{
330 struct hisi_femac_priv *priv = dev_get_priv(dev);
331
332 // assert internal reset
333 writel(SOFT_RESET_ALL, priv->glb_base + GLB_SOFT_RESET);
334}
335
336int hisi_femac_of_to_plat(struct udevice *dev)
337{
338 int ret, i;
339 struct hisi_femac_priv *priv = dev_get_priv(dev);
340 static const char * const clk_strs[] = {
341 [CLK_MAC] = "mac",
342 [CLK_BUS] = "bus",
343 [CLK_PHY] = "phy",
344 };
345
346 priv->port_base = dev_remap_addr_name(dev, "port");
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800347 if (!priv->port_base) {
348 dev_err(dev, "Failed to remap port address space\n");
349 return log_msg_ret("net", -EINVAL);
350 }
Yang Xiwend9717112023-08-23 01:03:42 +0800351
352 priv->glb_base = dev_remap_addr_name(dev, "glb");
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800353 if (IS_ERR(priv->glb_base)) {
354 dev_err(dev, "Failed to remap global address space\n");
355 return log_msg_ret("net", -EINVAL);
356 }
Yang Xiwend9717112023-08-23 01:03:42 +0800357
358 for (i = 0; i < ARRAY_SIZE(clk_strs); i++) {
359 priv->clks[i] = devm_clk_get(dev, clk_strs[i]);
360 if (IS_ERR(priv->clks[i])) {
361 dev_err(dev, "Error getting clock %s\n", clk_strs[i]);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800362 return log_msg_ret("clk", PTR_ERR(priv->clks[i]));
Yang Xiwend9717112023-08-23 01:03:42 +0800363 }
364 }
365
366 priv->mac_rst = devm_reset_control_get(dev, "mac");
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800367 if (IS_ERR(priv->mac_rst)) {
368 dev_err(dev, "Failed to get MAC reset %ld\n", PTR_ERR(priv->mac_rst));
369 return log_msg_ret("rst", PTR_ERR(priv->mac_rst));
370 }
Yang Xiwend9717112023-08-23 01:03:42 +0800371
372 priv->phy_rst = devm_reset_control_get(dev, "phy");
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800373 if (IS_ERR(priv->phy_rst)) {
374 dev_err(dev, "Failed to get PHY reset %ld\n", PTR_ERR(priv->phy_rst));
375 return log_msg_ret("rst", PTR_ERR(priv->phy_rst));
376 }
Yang Xiwend9717112023-08-23 01:03:42 +0800377
378 ret = dev_read_u32_array(dev,
379 PHY_RESET_DELAYS_PROPERTY,
380 priv->phy_reset_delays,
381 DELAYS_NUM);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800382 if (ret < 0) {
383 dev_err(dev, "Failed to get PHY reset delays %d\n", ret);
384 return log_msg_ret("rst", ret);
385 }
Yang Xiwend9717112023-08-23 01:03:42 +0800386
387 priv->mac_reset_delay = dev_read_u32_default(dev,
388 MAC_RESET_DELAY_PROPERTY,
389 MAC_RESET_ASSERT_PERIOD);
390
391 return 0;
392}
393
394static int hisi_femac_phy_reset(struct hisi_femac_priv *priv)
395{
396 struct reset_ctl *rst = priv->phy_rst;
397 u32 *delays = priv->phy_reset_delays;
398 int ret;
399
400 // Disable MAC clk before phy reset
401 ret = clk_disable(priv->clks[CLK_MAC]);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800402 if (ret < 0) {
403 pr_err("%s: Failed to disable MAC clock %d\n", __func__, ret);
404 return log_msg_ret("clk", ret);
405 }
Yang Xiwend9717112023-08-23 01:03:42 +0800406 ret = clk_disable(priv->clks[CLK_BUS]);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800407 if (ret < 0) {
408 pr_err("%s: Failed to disable bus clock %d\n", __func__, ret);
409 return log_msg_ret("clk", ret);
410 }
Yang Xiwend9717112023-08-23 01:03:42 +0800411
412 udelay(delays[PRE_DELAY]);
413
414 ret = reset_assert(rst);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800415 if (ret < 0) {
416 pr_err("%s: Failed to assert reset %d\n", __func__, ret);
417 return log_msg_ret("rst", ret);
418 }
Yang Xiwend9717112023-08-23 01:03:42 +0800419
420 udelay(delays[PULSE]);
421
422 ret = reset_deassert(rst);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800423 if (ret < 0) {
424 pr_err("%s: Failed to deassert reset %d\n", __func__, ret);
425 return log_msg_ret("rst", ret);
426 }
Yang Xiwend9717112023-08-23 01:03:42 +0800427
428 udelay(delays[POST_DELAY]);
429
430 ret = clk_enable(priv->clks[CLK_MAC]);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800431 if (ret < 0) {
432 pr_err("%s: Failed to enable MAC clock %d\n", __func__, ret);
433 return log_msg_ret("clk", ret);
434 }
Yang Xiwend9717112023-08-23 01:03:42 +0800435 ret = clk_enable(priv->clks[CLK_BUS]);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800436 if (ret < 0) {
437 pr_err("%s: Failed to enable MAC bus clock %d\n", __func__, ret);
438 return log_msg_ret("clk", ret);
439 }
Yang Xiwend9717112023-08-23 01:03:42 +0800440
441 return 0;
442}
443
444int hisi_femac_probe(struct udevice *dev)
445{
446 struct hisi_femac_priv *priv = dev_get_priv(dev);
447 int ret, i;
448
449 // Enable clocks
450 for (i = 0; i < CLK_NUM; i++) {
451 ret = clk_prepare_enable(priv->clks[i]);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800452 if (ret < 0) {
453 dev_err(dev, "Failed to enable clk %d: %d\n", i, ret);
454 return log_msg_ret("clk", ret);
455 }
Yang Xiwend9717112023-08-23 01:03:42 +0800456 }
457
458 // Reset MAC
459 ret = reset_assert(priv->mac_rst);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800460 if (ret < 0) {
461 dev_err(dev, "Failed to assert MAC reset: %d\n", ret);
462 return log_msg_ret("net", ret);
463 }
Yang Xiwend9717112023-08-23 01:03:42 +0800464
465 udelay(priv->mac_reset_delay);
466
467 ret = reset_deassert(priv->mac_rst);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800468 if (ret < 0) {
469 dev_err(dev, "Failed to deassert MAC reset: %d\n", ret);
470 return log_msg_ret("net", ret);
471 }
Yang Xiwend9717112023-08-23 01:03:42 +0800472
473 // Reset PHY
474 ret = hisi_femac_phy_reset(priv);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800475 if (ret < 0) {
476 dev_err(dev, "Failed to reset PHY: %d\n", ret);
477 return log_msg_ret("net", ret);
478 }
Yang Xiwend9717112023-08-23 01:03:42 +0800479
480 // Connect to PHY
481 priv->phy = dm_eth_phy_connect(dev);
Yang Xiwenf56b07b2024-01-22 22:33:21 +0800482 if (!priv->phy) {
483 dev_err(dev, "Failed to connect to phy\n");
484 return log_msg_ret("phy", -EINVAL);
485 }
Yang Xiwend9717112023-08-23 01:03:42 +0800486
487 hisi_femac_port_init(priv);
488 return 0;
489}
490
491static const struct eth_ops hisi_femac_ops = {
492 .start = hisi_femac_start,
493 .send = hisi_femac_send,
494 .recv = hisi_femac_recv,
495 .free_pkt = hisi_femac_free_pkt,
496 .stop = hisi_femac_stop,
497 .write_hwaddr = hisi_femac_set_hw_mac_addr,
498};
499
500static const struct udevice_id hisi_femac_ids[] = {
501 {.compatible = "hisilicon,hisi-femac-v1",},
502 {.compatible = "hisilicon,hisi-femac-v2",},
503 {.compatible = "hisilicon,hi3516cv300-femac",},
504 {.compatible = "hisilicon,hi3798mv200-femac",},
505 {},
506};
507
508U_BOOT_DRIVER(hisi_femac_driver) = {
509 .name = "eth_hisi_femac",
510 .id = UCLASS_ETH,
511 .of_match = of_match_ptr(hisi_femac_ids),
512 .of_to_plat = hisi_femac_of_to_plat,
513 .ops = &hisi_femac_ops,
514 .probe = hisi_femac_probe,
515 .plat_auto = sizeof(struct eth_pdata),
516 .priv_auto = sizeof(struct hisi_femac_priv),
517};