For reference, here are the remaining changes to get RPi5 network running.
It fixes MACB on the RPi5 but breaks MACB on all other platforms. 2 major
changes found by Oleksii are made here: adjust for MACB behind an AXI
bridge and account for the PCIe inbound access translation.
RPi5 owners may apply it on top of the series and give it a try.
(deliberately no Signed-off-by:)
---
board/raspberrypi/rpi/rpi.c | 12 ++-
configs/rpi_arm64_defconfig | 1 +
drivers/net/Kconfig | 1 +
drivers/net/macb.c | 156 ++++++++++++++++++++++++++++--------
drivers/net/macb.h | 16 ++++
5 files changed, 151 insertions(+), 35 deletions(-)
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index a7fd471114a..f474f497866 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -565,10 +565,18 @@ int board_late_init(void)
err = dm_pci_find_device(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RPI_RP1_C0,
0, &dev);
- if (err)
+ if (err) {
printf("RPI: RP1 device not found\n");
- else
+ } else {
+ int mii_init_gpio = 32; /* HACK - derive from FDT! */
+
dm_scan_fdt_dev(dev);
+ err = gpio_request(mii_init_gpio, "MII init");
+ if (!err) {
+ gpio_direction_output(mii_init_gpio, 1);
+ gpio_free(mii_init_gpio);
+ }
+ }
return 0;
}
diff --git a/configs/rpi_arm64_defconfig b/configs/rpi_arm64_defconfig
index 67b5311d4a6..57afb87c99c 100644
--- a/configs/rpi_arm64_defconfig
+++ b/configs/rpi_arm64_defconfig
@@ -49,6 +49,7 @@ CONFIG_MMC_SDHCI_SDMA=y
CONFIG_MMC_SDHCI_BCM2835=y
CONFIG_MMC_SDHCI_BCMSTB=y
CONFIG_BCMGENET=y
+CONFIG_MACB=y
CONFIG_NVME_PCI=y
CONFIG_PCI_BRCMSTB=y
CONFIG_PINCTRL=y
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 666618681df..1056e554721 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -570,6 +570,7 @@ config MACB
bool "Cadence MACB/GEM Ethernet Interface"
depends on ARM || RISCV
select PHYLIB
+ select DM_GPIO
help
The Cadence MACB ethernet interface is found on many Atmel
AT91 and SAMA5 parts. This driver also supports the Cadence
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index bea1dfed892..cd6562add95 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -38,14 +38,14 @@
#include <linux/mii.h>
#include <asm/io.h>
#include <linux/dma-mapping.h>
-#include <linux/errno.h>
-
/* Without CLK, we rely on the arch definition */
#if !defined(CONFIG_CLK)
#include <asm/arch/clk.h>
#endif
+#include <linux/errno.h>
#include "macb.h"
+#include "phys2bus.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -104,6 +104,8 @@ struct macb_dma_desc_64 {
#define RXBUF_FRMLEN_MASK 0x00000fff
#define TXBUF_FRMLEN_MASK 0x000007ff
+#define msleep(x) udelay((x) * 1000)
+
struct macb_device {
void *regs;
@@ -143,6 +145,10 @@ struct macb_device {
unsigned long pclk_rate;
#endif
phy_interface_t phy_interface;
+
+ struct gpio_desc phy_reset_gpio;
+ int phy_reset_ms;
+ struct udevice *udev;
};
struct macb_usrio_cfg {
@@ -274,47 +280,70 @@ int macb_miiphy_write(struct mii_dev *bus, int phy_adr,
int devad, int reg,
arch_get_mdio_control(bus->name);
macb_mdio_write(macb, phy_adr, reg, value);
+ return 0;
+}
+static int macb_miiphy_reset(struct mii_dev *bus)
+{
+ struct udevice *dev = eth_get_dev_by_name(bus->name);
+ struct macb_device *macb = dev_get_priv(dev);
+
+ if (!dm_gpio_is_valid(&macb->phy_reset_gpio))
+ return 0;
+
+ dm_gpio_set_value(&macb->phy_reset_gpio, 1);
+ msleep(macb->phy_reset_ms);
+ dm_gpio_set_value(&macb->phy_reset_gpio, 0);
return 0;
}
#endif
#define RX 1
#define TX 0
+
+/*
+ * NOTE: To handle buffers - rx_ring and tx_ring addresses should be used
instead
+ * of rx_buffer_dma and tx_buffer_dma. That is because on the several boards
this
+ * controller could be connected via PCIe or similar instead of the direct
connection.
+ * For example in BCM2712 macb controller is connected to RP1 chip via PCIe.
+ * When macb is connected directly to the SOC the rx_ring and tx_ring are the
same
+ * as rx_buffer_dma and tx_buffer_dma.
+ */
+
static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx)
{
if (rx)
- invalidate_dcache_range(macb->rx_ring_dma,
- ALIGN(macb->rx_ring_dma + MACB_RX_DMA_DESC_SIZE,
- PKTALIGN));
+ invalidate_dcache_range((ulong)(macb->rx_ring),
ALIGN((ulong)(macb->rx_ring) +
+ MACB_RX_DMA_DESC_SIZE, PKTALIGN));
else
- invalidate_dcache_range(macb->tx_ring_dma,
- ALIGN(macb->tx_ring_dma + MACB_TX_DMA_DESC_SIZE,
- PKTALIGN));
+ invalidate_dcache_range((unsigned long)macb->tx_ring,
+ ALIGN((unsigned long)macb->tx_ring +
+ MACB_TX_DMA_DESC_SIZE, PKTALIGN));
}
static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx)
{
if (rx)
- flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma +
- ALIGN(MACB_RX_DMA_DESC_SIZE, PKTALIGN));
+ flush_dcache_range((ulong)(macb->rx_ring),
+ (ulong)(macb->rx_ring) +
ALIGN(MACB_RX_DMA_DESC_SIZE, PKTALIGN));
else
- flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma +
+ flush_dcache_range((unsigned long)macb->tx_ring,
+ (unsigned long)macb->tx_ring +
ALIGN(MACB_TX_DMA_DESC_SIZE, PKTALIGN));
}
static inline void macb_flush_rx_buffer(struct macb_device *macb)
{
- flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma +
- ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
- PKTALIGN));
+ flush_dcache_range((ulong)macb->rx_buffer,
+ (ulong)macb->rx_buffer +
+ ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
PKTALIGN));
}
static inline void macb_invalidate_rx_buffer(struct macb_device *macb)
{
- invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma +
- ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
- PKTALIGN));
+ invalidate_dcache_range((ulong)macb->rx_buffer,
+ (ulong)macb->rx_buffer +
+ ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
PKTALIGN));
}
#if defined(CONFIG_CMD_NET)
@@ -340,12 +369,12 @@ static void macb_set_addr(struct macb_device *macb,
struct macb_dma_desc *desc,
static int _macb_send(struct macb_device *macb, const char *name, void *packet,
int length)
{
- unsigned long paddr, ctrl;
+ unsigned long paddr, dmaaddr, ctrl;
unsigned int tx_head = macb->tx_head;
int i;
paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
-
+ dmaaddr = dev_phys_to_bus(macb->udev, paddr);
ctrl = length & TXBUF_FRMLEN_MASK;
ctrl |= MACB_BIT(TX_LAST);
if (tx_head == (MACB_TX_RING_SIZE - 1)) {
@@ -359,7 +388,7 @@ static int _macb_send(struct macb_device *macb, const char
*name, void *packet,
tx_head = tx_head * 2;
macb->tx_ring[tx_head].ctrl = ctrl;
- macb_set_addr(macb, &macb->tx_ring[tx_head], paddr);
+ macb_set_addr(macb, &macb->tx_ring[tx_head], dmaaddr);
barrier();
macb_flush_ring_desc(macb, TX);
@@ -667,6 +696,22 @@ int __weak macb_linkspd_cb(struct udevice *dev, unsigned
int speed)
return 0;
}
+static void gem_init_axi(struct macb_device *bp)
+{
+ u32 amp;
+
+ /* AXI pipeline setup - don't touch values unless specified in device
+ * tree. Some hardware could have reset values > 1.
+ */
+ amp = gem_readl(bp, AMP);
+
+ amp = GEM_BFINS(AW2B_FILL, 1 /*bp->use_aw2b_fill*/, amp);
+ amp = GEM_BFINS(AW2W_MAX_PIPE, 8, amp);
+ amp = GEM_BFINS(AR2R_MAX_PIPE, 8, amp);
+
+ gem_writel(bp, AMP, amp);
+}
+
static int macb_phy_init(struct udevice *dev, const char *name)
{
struct macb_device *macb = dev_get_priv(dev);
@@ -838,8 +883,8 @@ static int gmac_init_multi_queues(struct macb_device *macb)
macb->dummy_desc->ctrl = MACB_BIT(TX_USED);
macb->dummy_desc->addr = 0;
- flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma +
- ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN));
+ flush_dcache_range((ulong)macb->dummy_desc,
+ (ulong)macb->dummy_desc +
ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN));
paddr = macb->dummy_desc_dma;
for (i = 1; i < num_queues; i++) {
@@ -943,6 +988,14 @@ static int _macb_init(struct udevice *dev, const char
*name)
macb_writel(macb, TBQPH, upper_32_bits(macb->tx_ring_dma));
}
+ /*
+ * Call axi bus init only for BCM2712 board which has macb
+ * connected over PCIe.
+ */
+ if ((IS_ENABLED(CONFIG_BCM2712)) /* &&
+ (gd_board_type() == BCM2712_RPI_5_B_NEW) */ )
+ gem_init_axi(macb);
+
if (macb_is_gem(macb)) {
/* Initialize DMA properties */
gmac_configure_dma(macb);
@@ -1122,7 +1175,7 @@ static u32 macb_dbw(struct macb_device *macb)
}
}
-static void _macb_eth_initialize(struct macb_device *macb)
+static void _macb_eth_initialize(struct macb_device *macb, struct udevice *dev)
{
int id = 0; /* This is not used by functions we call */
u32 ncfgr;
@@ -1136,13 +1189,23 @@ static void _macb_eth_initialize(struct macb_device
*macb)
macb->rx_buffer = dma_alloc_coherent(macb->rx_buffer_size *
MACB_RX_RING_SIZE,
&macb->rx_buffer_dma);
+
+ macb->rx_buffer_dma = dev_phys_to_bus(dev, (ulong)macb->rx_buffer);
+
macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE,
&macb->rx_ring_dma);
- macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE,
- &macb->tx_ring_dma);
+
+ macb->rx_ring_dma = dev_phys_to_bus(dev, (ulong)macb->rx_ring);
+
+ macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE,
&macb->tx_ring_dma);
+
+ macb->tx_ring_dma = dev_phys_to_bus(dev, (ulong)macb->tx_ring);
+
macb->dummy_desc = dma_alloc_coherent(MACB_TX_DUMMY_DMA_DESC_SIZE,
&macb->dummy_desc_dma);
+ macb->dummy_desc_dma = dev_phys_to_bus(dev, (ulong)macb->dummy_desc);
+
/*
* Do some basic initialization so that we at least can talk
* to the PHY
@@ -1216,11 +1279,19 @@ static const struct eth_ops macb_eth_ops = {
static int macb_enable_clk(struct udevice *dev)
{
struct macb_device *macb = dev_get_priv(dev);
- struct clk clk;
- ulong clk_rate;
+ struct clk clk, hclk;
+ struct clk tsu_clk;
int ret;
- ret = clk_get_by_index(dev, 0, &clk);
+ ret = clk_get_by_name(dev, "pclk", &clk);
+ if (ret)
+ return -EINVAL;
+
+ ret = clk_get_by_name_optional(dev, "hclk", &hclk);
+ if (ret)
+ return -EINVAL;
+
+ ret = clk_get_by_name_optional(dev, "tsu_clk", &tsu_clk);
if (ret)
return -EINVAL;
@@ -1233,11 +1304,17 @@ static int macb_enable_clk(struct udevice *dev)
if (ret && ret != -ENOSYS)
return ret;
- clk_rate = clk_get_rate(&clk);
- if (!clk_rate)
- return -EINVAL;
+ ret = clk_enable(&hclk);
+ if (ret && ret != -ENOSYS)
+ return ret;
- macb->pclk_rate = clk_rate;
+ ret = clk_enable(&tsu_clk);
+ if (ret && ret != -ENOSYS)
+ return ret;
+
+ macb->pclk_rate = 0xbebc200;
+ if (!macb->pclk_rate)
+ return -EINVAL;
return 0;
}
@@ -1268,6 +1345,7 @@ static int macb_eth_probe(struct udevice *dev)
if (macb->phy_interface == PHY_INTERFACE_MODE_NA)
return -EINVAL;
+ macb->udev = dev;
/* Read phyaddr from DT */
if (!dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
&phandle_args))
@@ -1293,7 +1371,7 @@ static int macb_eth_probe(struct udevice *dev)
return ret;
#endif
- _macb_eth_initialize(macb);
+ _macb_eth_initialize(macb, dev);
#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
macb->bus = mdio_alloc();
@@ -1302,6 +1380,7 @@ static int macb_eth_probe(struct udevice *dev)
strlcpy(macb->bus->name, dev->name, MDIO_NAME_LEN);
macb->bus->read = macb_miiphy_read;
macb->bus->write = macb_miiphy_write;
+ macb->bus->reset = macb_miiphy_reset;
ret = mdio_register(macb->bus);
if (ret < 0)
@@ -1343,6 +1422,7 @@ static int macb_eth_of_to_plat(struct udevice *dev)
void *blob = (void *)gd->fdt_blob;
int node = dev_of_offset(dev);
int fl_node, speed_fdt;
+ int ret;
/* fetch 'fixed-link' property */
fl_node = fdt_subnode_offset(blob, node, "fixed-link");
@@ -1368,6 +1448,16 @@ static int macb_eth_of_to_plat(struct udevice *dev)
if (!pdata->iobase)
return -EINVAL;
+ /* optional PHY reset-related properties */
+ ret = gpio_request_by_name(dev, "phy-reset-gpios", 0,
&macb->phy_reset_gpio,
+ GPIOD_IS_OUT);
+ if (ret && ret != -ENOENT) {
+ printf("Failed to obtain phy-reset gpio\n");
+ return ret;
+ }
+
+ macb->phy_reset_ms = ofnode_read_s32_default(dev_ofnode(dev),
"phy-reset-duration", 10);
+
return macb_late_eth_of_to_plat(dev);
}
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 002d5bd31b2..258eb9a635b 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -69,6 +69,7 @@
#define GEM_USRIO 0x000c /* User IO */
#define GEM_DMACFG 0x0010 /* DMA Configuration */
#define GEM_JML 0x0048 /* Jumbo Max Length */
+#define GEM_AMP 0x0054 /* AXI Max Pipeline */
#define GEM_HRB 0x0080 /* Hash Bottom */
#define GEM_HRT 0x0084 /* Hash Top */
#define GEM_SA1B 0x0088 /* Specific1 Bottom */
@@ -763,6 +764,21 @@
#define GEM_RX_CSUM_IP_TCP 2
#define GEM_RX_CSUM_IP_UDP 3
+/* Bitfields in AMP */
+/* Maximum number of outstanding AXI read requests */
+#define GEM_AR2R_MAX_PIPE_OFFSET 0
+#define GEM_AR2R_MAX_PIPE_SIZE 8
+/* Maximum number of outstanding AXI write requests */
+#define GEM_AW2W_MAX_PIPE_OFFSET 8
+#define GEM_AW2W_MAX_PIPE_SIZE 8
+/* Select whether the max AW2W transactions operates between: */
+#define GEM_AW2B_FILL_OFFSET 16
+/* 0: the AW to W AXI channel */
+#define GEM_AW2B_FILL_AW2W 0
+/* 1: AW to B channel */
+#define GEM_AW2B_FILL_AW2B 1
+#define GEM_AW2B_FILL_SIZE 1
+
/* limit RX checksum offload to TCP and UDP packets */
#define GEM_RX_CSUM_CHECKED_MASK 2
#define gem_writel_queue_TBQP(port, value, queue_num) \
--
2.51.0