blob: 15a94f6ce9a105064761c08c77b7f3ae264d38d3 [file] [log] [blame]
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
4 *
5 * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7 */
8
9#include <common.h>
10#include <clk.h>
11#include <dm.h>
12#include <dma.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070014#include <malloc.h>
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +010015#include <miiphy.h>
16#include <net.h>
17#include <phy.h>
18#include <reset.h>
19#include <wait_bit.h>
20#include <asm/io.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060021#include <linux/printk.h>
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +010022
23#define ETH_RX_DESC PKTBUFSRX
24#define ETH_MAX_MTU_SIZE 1518
25#define ETH_TIMEOUT 100
26#define ETH_TX_WATERMARK 32
27
28/* ETH Receiver Configuration register */
29#define ETH_RXCFG_REG 0x00
30#define ETH_RXCFG_ENFLOW_SHIFT 5
31#define ETH_RXCFG_ENFLOW_MASK (1 << ETH_RXCFG_ENFLOW_SHIFT)
32
33/* ETH Receive Maximum Length register */
34#define ETH_RXMAXLEN_REG 0x04
35#define ETH_RXMAXLEN_SHIFT 0
36#define ETH_RXMAXLEN_MASK (0x7ff << ETH_RXMAXLEN_SHIFT)
37
38/* ETH Transmit Maximum Length register */
39#define ETH_TXMAXLEN_REG 0x08
40#define ETH_TXMAXLEN_SHIFT 0
41#define ETH_TXMAXLEN_MASK (0x7ff << ETH_TXMAXLEN_SHIFT)
42
43/* MII Status/Control register */
44#define MII_SC_REG 0x10
45#define MII_SC_MDCFREQDIV_SHIFT 0
46#define MII_SC_MDCFREQDIV_MASK (0x7f << MII_SC_MDCFREQDIV_SHIFT)
47#define MII_SC_PREAMBLE_EN_SHIFT 7
48#define MII_SC_PREAMBLE_EN_MASK (1 << MII_SC_PREAMBLE_EN_SHIFT)
49
50/* MII Data register */
51#define MII_DAT_REG 0x14
52#define MII_DAT_DATA_SHIFT 0
53#define MII_DAT_DATA_MASK (0xffff << MII_DAT_DATA_SHIFT)
54#define MII_DAT_TA_SHIFT 16
55#define MII_DAT_TA_MASK (0x3 << MII_DAT_TA_SHIFT)
56#define MII_DAT_REG_SHIFT 18
57#define MII_DAT_REG_MASK (0x1f << MII_DAT_REG_SHIFT)
58#define MII_DAT_PHY_SHIFT 23
59#define MII_DAT_PHY_MASK (0x1f << MII_DAT_PHY_SHIFT)
60#define MII_DAT_OP_SHIFT 28
61#define MII_DAT_OP_WRITE (0x5 << MII_DAT_OP_SHIFT)
62#define MII_DAT_OP_READ (0x6 << MII_DAT_OP_SHIFT)
63
64/* ETH Interrupts Mask register */
65#define ETH_IRMASK_REG 0x18
66
67/* ETH Interrupts register */
68#define ETH_IR_REG 0x1c
69#define ETH_IR_MII_SHIFT 0
70#define ETH_IR_MII_MASK (1 << ETH_IR_MII_SHIFT)
71
72/* ETH Control register */
73#define ETH_CTL_REG 0x2c
74#define ETH_CTL_ENABLE_SHIFT 0
75#define ETH_CTL_ENABLE_MASK (1 << ETH_CTL_ENABLE_SHIFT)
76#define ETH_CTL_DISABLE_SHIFT 1
77#define ETH_CTL_DISABLE_MASK (1 << ETH_CTL_DISABLE_SHIFT)
78#define ETH_CTL_RESET_SHIFT 2
79#define ETH_CTL_RESET_MASK (1 << ETH_CTL_RESET_SHIFT)
80#define ETH_CTL_EPHY_SHIFT 3
81#define ETH_CTL_EPHY_MASK (1 << ETH_CTL_EPHY_SHIFT)
82
83/* ETH Transmit Control register */
84#define ETH_TXCTL_REG 0x30
85#define ETH_TXCTL_FD_SHIFT 0
86#define ETH_TXCTL_FD_MASK (1 << ETH_TXCTL_FD_SHIFT)
87
88/* ETH Transmit Watermask register */
89#define ETH_TXWMARK_REG 0x34
90#define ETH_TXWMARK_WM_SHIFT 0
91#define ETH_TXWMARK_WM_MASK (0x3f << ETH_TXWMARK_WM_SHIFT)
92
93/* MIB Control register */
94#define MIB_CTL_REG 0x38
95#define MIB_CTL_RDCLEAR_SHIFT 0
96#define MIB_CTL_RDCLEAR_MASK (1 << MIB_CTL_RDCLEAR_SHIFT)
97
98/* ETH Perfect Match registers */
99#define ETH_PM_CNT 4
100#define ETH_PML_REG(x) (0x58 + (x) * 0x8)
101#define ETH_PMH_REG(x) (0x5c + (x) * 0x8)
102#define ETH_PMH_VALID_SHIFT 16
103#define ETH_PMH_VALID_MASK (1 << ETH_PMH_VALID_SHIFT)
104
105/* MIB Counters registers */
106#define MIB_REG_CNT 55
107#define MIB_REG(x) (0x200 + (x) * 4)
108
109/* ETH data */
110struct bcm6348_eth_priv {
111 void __iomem *base;
112 /* DMA */
113 struct dma rx_dma;
114 struct dma tx_dma;
115 /* PHY */
116 int phy_id;
117 struct phy_device *phy_dev;
118};
119
120static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
121{
122 /* disable emac */
123 clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
124 ETH_CTL_DISABLE_MASK);
125
126 /* wait until emac is disabled */
127 if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
128 ETH_CTL_DISABLE_MASK, false,
129 ETH_TIMEOUT, false))
130 pr_err("%s: error disabling emac\n", __func__);
131}
132
133static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
134{
135 setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
136}
137
138static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
139{
140 /* reset emac */
141 writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
142 wmb();
143
144 /* wait until emac is reset */
145 if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
146 ETH_CTL_RESET_MASK, false,
147 ETH_TIMEOUT, false))
148 pr_err("%s: error resetting emac\n", __func__);
149}
150
151static int bcm6348_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
152{
153 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
154
155 return dma_prepare_rcv_buf(&priv->rx_dma, packet, len);
156}
157
158static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
159{
160 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
161
162 return dma_receive(&priv->rx_dma, (void**)packetp, NULL);
163}
164
165static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
166{
167 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
168
169 return dma_send(&priv->tx_dma, packet, length, NULL);
170}
171
172static int bcm6348_eth_adjust_link(struct udevice *dev,
173 struct phy_device *phydev)
174{
175 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
176
177 /* mac duplex parameters */
178 if (phydev->duplex)
179 setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
180 else
181 clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
182
183 /* rx flow control (pause frame handling) */
184 if (phydev->pause)
185 setbits_be32(priv->base + ETH_RXCFG_REG,
186 ETH_RXCFG_ENFLOW_MASK);
187 else
188 clrbits_be32(priv->base + ETH_RXCFG_REG,
189 ETH_RXCFG_ENFLOW_MASK);
190
191 return 0;
192}
193
194static int bcm6348_eth_start(struct udevice *dev)
195{
196 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
197 int ret, i;
198
199 /* prepare rx dma buffers */
200 for (i = 0; i < ETH_RX_DESC; i++) {
201 ret = dma_prepare_rcv_buf(&priv->rx_dma, net_rx_packets[i],
202 PKTSIZE_ALIGN);
203 if (ret < 0)
204 break;
205 }
206
207 /* enable dma rx channel */
208 dma_enable(&priv->rx_dma);
209
210 /* enable dma tx channel */
211 dma_enable(&priv->tx_dma);
212
213 ret = phy_startup(priv->phy_dev);
214 if (ret) {
215 pr_err("%s: could not initialize phy\n", __func__);
216 return ret;
217 }
218
219 if (!priv->phy_dev->link) {
220 pr_err("%s: no phy link\n", __func__);
221 return -EIO;
222 }
223
224 bcm6348_eth_adjust_link(dev, priv->phy_dev);
225
226 /* zero mib counters */
227 for (i = 0; i < MIB_REG_CNT; i++)
228 writel_be(0, MIB_REG(i));
229
230 /* enable rx flow control */
231 setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
232
233 /* set max rx/tx length */
234 writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
235 ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
236 writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
237 ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
238
239 /* set correct transmit fifo watermark */
240 writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
241 ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
242
243 /* enable emac */
244 bcm6348_eth_mac_enable(priv);
245
246 /* clear interrupts */
247 writel_be(0, priv->base + ETH_IRMASK_REG);
248
249 return 0;
250}
251
252static void bcm6348_eth_stop(struct udevice *dev)
253{
254 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
255
256 /* disable dma rx channel */
257 dma_disable(&priv->rx_dma);
258
259 /* disable dma tx channel */
260 dma_disable(&priv->tx_dma);
261
262 /* disable emac */
263 bcm6348_eth_mac_disable(priv);
264}
265
266static int bcm6348_eth_write_hwaddr(struct udevice *dev)
267{
Simon Glassfa20e932020-12-03 16:55:20 -0700268 struct eth_pdata *pdata = dev_get_plat(dev);
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +0100269 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
270 bool running = false;
271
272 /* check if emac is running */
273 if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
274 running = true;
275
276 /* disable emac */
277 if (running)
278 bcm6348_eth_mac_disable(priv);
279
280 /* set mac address */
281 writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
282 (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
283 priv->base + ETH_PML_REG(0));
284 writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
285 ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
286
287 /* enable emac */
288 if (running)
289 bcm6348_eth_mac_enable(priv);
290
291 return 0;
292}
293
294static const struct eth_ops bcm6348_eth_ops = {
295 .free_pkt = bcm6348_eth_free_pkt,
296 .recv = bcm6348_eth_recv,
297 .send = bcm6348_eth_send,
298 .start = bcm6348_eth_start,
299 .stop = bcm6348_eth_stop,
300 .write_hwaddr = bcm6348_eth_write_hwaddr,
301};
302
303static const struct udevice_id bcm6348_eth_ids[] = {
304 { .compatible = "brcm,bcm6348-enet", },
305 { /* sentinel */ }
306};
307
308static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
309{
310 /* make sure mii interrupt status is cleared */
311 writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
312
313 /* issue mii op */
314 writel_be(data, base + MII_DAT_REG);
315
316 /* wait until emac is disabled */
317 return wait_for_bit_be32(base + ETH_IR_REG,
318 ETH_IR_MII_MASK, true,
319 ETH_TIMEOUT, false);
320}
321
322static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
323 int reg)
324{
325 void __iomem *base = bus->priv;
326 uint32_t val;
327
328 val = MII_DAT_OP_READ;
329 val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
330 val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
331 val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
332
333 if (bcm6348_mdio_op(base, val)) {
334 pr_err("%s: timeout\n", __func__);
335 return -EINVAL;
336 }
337
338 val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
339 val >>= MII_DAT_DATA_SHIFT;
340
341 return val;
342}
343
344static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
345 int reg, u16 value)
346{
347 void __iomem *base = bus->priv;
348 uint32_t val;
349
350 val = MII_DAT_OP_WRITE;
351 val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
352 val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
353 val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
354 val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
355
356 if (bcm6348_mdio_op(base, val)) {
357 pr_err("%s: timeout\n", __func__);
358 return -EINVAL;
359 }
360
361 return 0;
362}
363
364static int bcm6348_mdio_init(const char *name, void __iomem *base)
365{
366 struct mii_dev *bus;
367
368 bus = mdio_alloc();
369 if (!bus) {
370 pr_err("%s: failed to allocate MDIO bus\n", __func__);
371 return -ENOMEM;
372 }
373
374 bus->read = bcm6348_mdio_read;
375 bus->write = bcm6348_mdio_write;
376 bus->priv = base;
377 snprintf(bus->name, sizeof(bus->name), "%s", name);
378
379 return mdio_register(bus);
380}
381
382static int bcm6348_phy_init(struct udevice *dev)
383{
Simon Glassfa20e932020-12-03 16:55:20 -0700384 struct eth_pdata *pdata = dev_get_plat(dev);
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +0100385 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
386 struct mii_dev *bus;
387
388 /* get mii bus */
389 bus = miiphy_get_dev_by_name(dev->name);
390
391 /* phy connect */
392 priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
393 pdata->phy_interface);
394 if (!priv->phy_dev) {
395 pr_err("%s: no phy device\n", __func__);
396 return -ENODEV;
397 }
398
399 priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
400 SUPPORTED_10baseT_Full |
401 SUPPORTED_100baseT_Half |
402 SUPPORTED_100baseT_Full |
403 SUPPORTED_Autoneg |
404 SUPPORTED_Pause |
405 SUPPORTED_MII);
406 priv->phy_dev->advertising = priv->phy_dev->supported;
407
408 /* phy config */
409 phy_config(priv->phy_dev);
410
411 return 0;
412}
413
414static int bcm6348_eth_probe(struct udevice *dev)
415{
Simon Glassfa20e932020-12-03 16:55:20 -0700416 struct eth_pdata *pdata = dev_get_plat(dev);
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +0100417 struct bcm6348_eth_priv *priv = dev_get_priv(dev);
418 struct ofnode_phandle_args phy;
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +0100419 int ret, i;
420
421 /* get base address */
422 priv->base = dev_remap_addr(dev);
423 if (!priv->base)
424 return -EINVAL;
425 pdata->iobase = (phys_addr_t) priv->base;
426
427 /* get phy mode */
Marek Behúnbc194772022-04-07 00:33:01 +0200428 pdata->phy_interface = dev_read_phy_mode(dev);
Marek Behún48631e42022-04-07 00:33:03 +0200429 if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +0100430 return -ENODEV;
431
432 /* get phy */
433 if (dev_read_phandle_with_args(dev, "phy", NULL, 0, 0, &phy))
434 return -ENOENT;
435 priv->phy_id = ofnode_read_u32_default(phy.node, "reg", -1);
436
437 /* get dma channels */
438 ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
439 if (ret)
440 return -EINVAL;
441
442 ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
443 if (ret)
444 return -EINVAL;
445
446 /* try to enable clocks */
447 for (i = 0; ; i++) {
448 struct clk clk;
449 int ret;
450
451 ret = clk_get_by_index(dev, i, &clk);
452 if (ret < 0)
453 break;
454
455 ret = clk_enable(&clk);
456 if (ret < 0) {
457 pr_err("%s: error enabling clock %d\n", __func__, i);
458 return ret;
459 }
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +0100460 }
461
462 /* try to perform resets */
463 for (i = 0; ; i++) {
464 struct reset_ctl reset;
465 int ret;
466
467 ret = reset_get_by_index(dev, i, &reset);
468 if (ret < 0)
469 break;
470
471 ret = reset_deassert(&reset);
472 if (ret < 0) {
473 pr_err("%s: error deasserting reset %d\n", __func__, i);
474 return ret;
475 }
476
477 ret = reset_free(&reset);
478 if (ret < 0) {
479 pr_err("%s: error freeing reset %d\n", __func__, i);
480 return ret;
481 }
482 }
483
484 /* disable emac */
485 bcm6348_eth_mac_disable(priv);
486
487 /* reset emac */
488 bcm6348_eth_mac_reset(priv);
489
490 /* select correct mii interface */
491 if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
492 clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
493 else
494 setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
495
496 /* turn on mdc clock */
497 writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
498 MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
499
500 /* set mib counters to not clear when read */
501 clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
502
503 /* initialize perfect match registers */
504 for (i = 0; i < ETH_PM_CNT; i++) {
505 writel_be(0, priv->base + ETH_PML_REG(i));
506 writel_be(0, priv->base + ETH_PMH_REG(i));
507 }
508
509 /* init mii bus */
510 ret = bcm6348_mdio_init(dev->name, priv->base);
511 if (ret)
512 return ret;
513
514 /* init phy */
515 ret = bcm6348_phy_init(dev);
516 if (ret)
517 return ret;
518
519 return 0;
520}
521
522U_BOOT_DRIVER(bcm6348_eth) = {
523 .name = "bcm6348_eth",
524 .id = UCLASS_ETH,
525 .of_match = bcm6348_eth_ids,
526 .ops = &bcm6348_eth_ops,
Simon Glass71fa5b42020-12-03 16:55:18 -0700527 .plat_auto = sizeof(struct eth_pdata),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700528 .priv_auto = sizeof(struct bcm6348_eth_priv),
Álvaro Fernández Rojas204fd5e2018-12-01 19:00:24 +0100529 .probe = bcm6348_eth_probe,
530};