[PATCH 3/3] net: RTL-8125B -- write mac to MAC0_BKP
In the case of RTL-8125B, Linux reads the mac address from register MAC0_BKP instead of MAC0, so let u-boot write the mac address there. Note: writing to MAC0 is still needed too, because this register is used by the hardware for mac filtering (the board will not receive packets if MAC0 is not set). Tested on a FriendlyElec Nanopi R5C board. Signed-off-by: Etienne Dublé --- drivers/net/rtl8169.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index b30d51731f..7c4d658c6b 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -153,6 +153,7 @@ enum RTL8125_registers { IntrMask_8125 = 0x38, IntrStatus_8125 = 0x3C, TxPoll_8125 = 0x90, + MAC0_BKP = 0x19e0, }; enum RTL8169_register_content { @@ -881,6 +882,7 @@ void rtl8169_eth_stop(struct udevice *dev) static int rtl8169_write_hwaddr(struct udevice *dev) { struct eth_pdata *plat = dev_get_plat(dev); + struct pci_child_plat *pplat = dev_get_parent_plat(dev); unsigned int i; RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -888,6 +890,19 @@ static int rtl8169_write_hwaddr(struct udevice *dev) for (i = 0; i < MAC_ADDR_LEN; i++) RTL_W8(MAC0 + i, plat->enetaddr[i]); + /* +* In the case of RTL8125, linux is reading the mac +* address from register MAC0_BKP instead of MAC0, +* so let's copy it there. +* Note: we still need to write the mac to MAC0 too +* (cf. the loop above) because the hardware uses MAC0 +* for mac filtering. +*/ + if (pplat->device == 0x8125) { + for (i = 0; i < MAC_ADDR_LEN; i++) + RTL_W8(MAC0_BKP + i, plat->enetaddr[i]); + } + RTL_W8(Cfg9346, Cfg9346_Lock); return 0; -- 2.34.1
[PATCH 2/3] rockchip: fix wrong PCI range address in rk3568 dtsi
One of the PCI ranges was wrong in this device tree. When testing with a FriendlyElec Nanopi R5C board, the 2nd ethernet interface (labelled "wan") was not working in u-boot because of that. With the correct value (found in FriendlyElec's downstream u-boot repository), this 2nd ethernet interface now works. Signed-off-by: Etienne Dublé --- dts/upstream/src/arm64/rockchip/rk3568.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/upstream/src/arm64/rockchip/rk3568.dtsi b/dts/upstream/src/arm64/rockchip/rk3568.dtsi index f1be76a54c..06aac034ca 100644 --- a/dts/upstream/src/arm64/rockchip/rk3568.dtsi +++ b/dts/upstream/src/arm64/rockchip/rk3568.dtsi @@ -150,7 +150,7 @@ <0x0 0xf000 0x0 0x0010>; ranges = <0x0100 0x0 0xf010 0x0 0xf010 0x0 0x0010>, <0x0200 0x0 0xf020 0x0 0xf020 0x0 0x01e0>, -<0x0300 0x0 0x4000 0x3 0x8000 0x0 0x4000>; +<0x0300 0x0 0x8000 0x3 0x8000 0x0 0x4000>; reg-names = "dbi", "apb", "config"; resets = < SRST_PCIE30X2_POWERUP>; reset-names = "pipe"; -- 2.34.1
[PATCH 1/3] net: give a different name to rtl8169 interfaces
This commit implements the .bind member function, and gives a different name to interfaces: "RTL8169#0", "RTL8169#1", etc. This was tested on a FriendlyElec Nanopi R5C board, which has two RTL-8125B interfaces managed by this driver. Since they were given the same name, it was previously not possible to select the 2nd one using ethact or ethprime environment variables. Signed-off-by: Etienne Dublé --- drivers/net/rtl8169.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 93e83661ce..b30d51731f 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -1091,6 +1091,16 @@ static int rtl8169_eth_probe(struct udevice *dev) return 0; } +static int rtl8169_eth_bind(struct udevice *dev) +{ + static int card_number; + char name[16]; + + sprintf(name, "RTL8169#%u", card_number++); + + return device_set_name(dev, name); +} + static const struct eth_ops rtl8169_eth_ops = { .start = rtl8169_eth_start, .send = rtl8169_eth_send, @@ -1108,6 +1118,7 @@ U_BOOT_DRIVER(eth_rtl8169) = { .name = "eth_rtl8169", .id = UCLASS_ETH, .of_match = rtl8169_eth_ids, + .bind = rtl8169_eth_bind, .probe = rtl8169_eth_probe, .ops= _eth_ops, .priv_auto = sizeof(struct rtl8169_private), -- 2.34.1
[PATCH 0/3] Improve networking support on FriendlyElec Nanopi R5C
This board has two RTL-8125B interfaces (drivers/net/rtl8169.c). The secondary interface (labelled "wan") was not working because of a wrong PCI address in file rk3568.dtsi. Moreover, users could not instruct u-boot to use this secondary interface (i.e., using ethprime), because both interfaces had the same name. Lastly, the mac address generated by u-boot was not properly passed to the Linux kernel, in the case of RTL-8125B. This series probably improves support of other similar boards too (e.g., Nanopi R5S). Etienne Dublé (3): net: give a different name to rtl8169 interfaces rockchip: fix wrong PCI range address in rk3568 dtsi net: RTL-8125B -- write mac to MAC0_BKP drivers/net/rtl8169.c | 26 + dts/upstream/src/arm64/rockchip/rk3568.dtsi | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) -- 2.34.1
[PATCH v3] watchdog: Add a watchdog driver for Raspberry Pi boards
This driver supports the bcm2835 watchdog found on Raspberry Pi boards. It is derived from the Linux driver and was tested on two Raspberry Pi board versions (B+ and 3B+). Signed-off-by: Etienne Dublé --- Changes for v2: - fixed whitespaces in email - moved a static variable to the priv struct Changes for v3: - used the max timeout value the hardware supports - turned the warning to a one-line message drivers/watchdog/Kconfig | 9 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/bcm2835_wdt.c | 132 + 3 files changed, 142 insertions(+) create mode 100644 drivers/watchdog/bcm2835_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f1b1cf63ca..06c0d630c8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -30,6 +30,7 @@ config WATCHDOG_TIMEOUT_MSECS default 128000 if ARCH_MX7 || ARCH_VF610 default 3 if ARCH_SOCFPGA default 16000 if ARCH_SUNXI + default 15000 if ARCH_BCM283X default 6 help Watchdog timeout in msec @@ -326,6 +327,14 @@ config WDT_SUNXI help Enable support for the watchdog timer in Allwinner sunxi SoCs. +config WDT_BCM2835 + bool "Broadcom 2835 watchdog timer support" + depends on WDT && ARCH_BCM283X + default y + help + Enable support for the watchdog timer in Broadcom 283X SoCs such + as Raspberry Pi boards. + config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 446d961d7d..f99915960c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_WDT_APPLE) += apple_wdt.o obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o obj-$(CONFIG_WDT_AST2600) += ast2600_wdt.o +obj-$(CONFIG_WDT_BCM2835) += bcm2835_wdt.o obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c new file mode 100644 index 00..3c1ead3dda --- /dev/null +++ b/drivers/watchdog/bcm2835_wdt.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Lubomir Rintel + * Copyright (C) 2023 Etienne Dublé (CNRS) + * + * This code is mostly derived from the linux driver. + */ + +#include +#include +#include +#include + +#define PM_RSTC0x1c +#define PM_WDOG0x24 + +#define PM_PASSWORD0x5a00 + +/* The hardware supports a maximum timeout value of 0xf ticks + * (just below 16 seconds). + */ +#define PM_WDOG_MAX_TICKS 0x000f +#define PM_RSTC_WRCFG_CLR 0xffcf +#define PM_RSTC_WRCFG_FULL_RESET 0x0020 +#define PM_RSTC_RESET 0x0102 + +#define MS_TO_WDOG_TICKS(x) (((x) << 16) / 1000) + +struct bcm2835_wdt_priv { + void __iomem *base; + u64 timeout_ticks; +}; + +static int bcm2835_wdt_start_ticks(struct udevice *dev, + u64 timeout_ticks, ulong flags) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + void __iomem *base = priv->base; + u32 cur; + + writel(PM_PASSWORD | timeout_ticks, base + PM_WDOG); + cur = readl(base + PM_RSTC); + writel(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET, + base + PM_RSTC); + + return 0; +} + +static int bcm2835_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + + priv->timeout_ticks = MS_TO_WDOG_TICKS(timeout_ms); + + if (priv->timeout_ticks > PM_WDOG_MAX_TICKS) { + printf("bcm2835_wdt: the timeout value is too high, using ~16s instead.\n"); + priv->timeout_ticks = PM_WDOG_MAX_TICKS; + } + + return bcm2835_wdt_start_ticks(dev, priv->timeout_ticks, flags); +} + +static int bcm2835_wdt_reset(struct udevice *dev) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + + /* restart the timer with the value of priv->timeout_ticks +* saved from the last bcm2835_wdt_start() call. +*/ + return bcm2835_wdt_start_ticks(dev, priv->timeout_ticks, 0); +} + +static int bcm2835_wdt_stop(struct udevice *dev) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + void __iomem *base = priv->base; + + writel(PM_PASSWORD | PM_RSTC_RESET, base + PM_RSTC); + + return 0; +} + +static int bcm2835_wdt_expire_now(struct udevice *dev, ulong flags) +{ + int ret; + + /* use a timeout of 10 ticks (~150us) */ + ret = bcm2835_wdt_start_ticks(dev, 10, flags); + if (ret) + return ret; + +
[PATCH v2] watchdog: Add a watchdog driver for Raspberry Pi boards
This driver supports the bcm2835 watchdog found on Raspberry Pi boards. It is derived from the Linux driver and was tested on two Raspberry Pi board versions (B+ and 3B+). Signed-off-by: Etienne Dublé --- Changes for v2: - fixed whitespaces in email - moved a static variable to the priv struct drivers/watchdog/Kconfig | 9 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/bcm2835_wdt.c | 140 + 3 files changed, 150 insertions(+) create mode 100644 drivers/watchdog/bcm2835_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f1b1cf63ca..06c0d630c8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -30,6 +30,7 @@ config WATCHDOG_TIMEOUT_MSECS default 128000 if ARCH_MX7 || ARCH_VF610 default 3 if ARCH_SOCFPGA default 16000 if ARCH_SUNXI + default 15000 if ARCH_BCM283X default 6 help Watchdog timeout in msec @@ -326,6 +327,14 @@ config WDT_SUNXI help Enable support for the watchdog timer in Allwinner sunxi SoCs. +config WDT_BCM2835 + bool "Broadcom 2835 watchdog timer support" + depends on WDT && ARCH_BCM283X + default y + help + Enable support for the watchdog timer in Broadcom 283X SoCs such + as Raspberry Pi boards. + config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 446d961d7d..f99915960c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_WDT_APPLE) += apple_wdt.o obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o obj-$(CONFIG_WDT_AST2600) += ast2600_wdt.o +obj-$(CONFIG_WDT_BCM2835) += bcm2835_wdt.o obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c new file mode 100644 index 00..00f7806cd5 --- /dev/null +++ b/drivers/watchdog/bcm2835_wdt.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Lubomir Rintel + * Copyright (C) 2023 Etienne Dublé (CNRS) + * + * This code is mostly derived from the linux driver. + */ + +#include +#include +#include +#include + +#define PM_RSTC0x1c +#define PM_WDOG0x24 + +#define PM_PASSWORD0x5a00 + +/* The hardware supports a maximum timeout value of 0xf ticks + * (just below 16 seconds). + * U-boot users specify the timeout as a number of milliseconds + * by using variable CONFIG_WATCHDOG_TIMEOUT_MSECS. + * The maximum value should be 15999 ms in our case. + * However, u-boot internally converts this config value to seconds, + * thus specifying 15999 actually means 15000 ms (0xf ticks). + */ +#define PM_WDOG_MAX_TICKS 0x000f +#define PM_RSTC_WRCFG_CLR 0xffcf +#define PM_RSTC_WRCFG_FULL_RESET 0x0020 +#define PM_RSTC_RESET 0x0102 + +#define MS_TO_WDOG_TICKS(x) (((x) << 16) / 1000) + +struct bcm2835_wdt_priv { + void __iomem *base; + u64 timeout_ticks; +}; + +static int bcm2835_wdt_start_ticks(struct udevice *dev, + u64 timeout_ticks, ulong flags) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + void __iomem *base = priv->base; + u32 cur; + + writel(PM_PASSWORD | timeout_ticks, base + PM_WDOG); + cur = readl(base + PM_RSTC); + writel(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | + PM_RSTC_WRCFG_FULL_RESET, base + PM_RSTC); + + return 0; +} + +static int bcm2835_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + + priv->timeout_ticks = MS_TO_WDOG_TICKS(timeout_ms); + + if (priv->timeout_ticks > PM_WDOG_MAX_TICKS) { + printf("WARNING: bcm2835_wdt cannot handle large timeout values.\n"); + printf(" Setting the max value of 15000 ms instead.\n"); + printf(" Set CONFIG_WATCHDOG_TIMEOUT_MSECS=15000 at most " + "to avoid this warning.\n"); + priv->timeout_ticks = PM_WDOG_MAX_TICKS; + } + + return bcm2835_wdt_start_ticks(dev, priv->timeout_ticks, flags); +} + +static int bcm2835_wdt_reset(struct udevice *dev) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + + /* restart the timer with the value of priv->timeout_ticks +* saved from the last bcm2835_wdt_start() call. +*/ + return bcm2835_wdt_start_ticks(dev, priv->timeout_ticks, 0); +} + +static int bcm2835_wdt_stop(struct udevice *dev) +{ + struct
[PATCH] bcmgenet: fix DMA buffer management
From: Etienne Dublé This commit fixes a serious issue occuring when several network commands are run on a raspberry pi 4 board: for instance a "dhcp" command and then one or several "tftp" commands. In this case, packet recv callbacks were called several times on the same packets, and send function was failing most of the time. note: if the boot procedure is made of a single network command, the issue is not visible. The issue is related to management of the packet ring buffers (producer / consumer) and DMA. Each time a packet is received, the ethernet device stores it in the buffer and increments an index called RDMA_PROD_INDEX. Each time the driver outputs a received packet, it increments another index called RDMA_CONS_INDEX. Between each pair of network commands, as part of the driver 'start' function, previous code tried to reset both RDMA_CONS_INDEX and RDMA_PROD_INDEX to 0. But RDMA_PROD_INDEX cannot be written from driver side, thus its value was actually not updated, and only RDMA_CONS_INDEX was reset to 0. This was resulting in a major synchronization issue between the driver and the device. Most visible bahavior was that the driver seemed to receive again the packets from the previous commands (e.g. DHCP response packets "received" again when performing the first TFTP command). This fix consists in setting RDMA_CONS_INDEX to the same value as RDMA_PROD_INDEX, when resetting the driver. The same kind of fix was needed on the TX side, and a few variables had to be reset accordingly (c_index, tx_index, rx_index). --- drivers/net/bcmgenet.c | 15 +++ 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/bcmgenet.c b/drivers/net/bcmgenet.c index 11b6148ab6..a4facfd63f 100644 --- a/drivers/net/bcmgenet.c +++ b/drivers/net/bcmgenet.c @@ -378,8 +378,6 @@ static void rx_descs_init(struct bcmgenet_eth_priv *priv) u32 len_stat, i; void *desc_base = priv->rx_desc_base; - priv->c_index = 0; - len_stat = (RX_BUF_LENGTH << DMA_BUFLENGTH_SHIFT) | DMA_OWN; for (i = 0; i < RX_DESCS; i++) { @@ -403,8 +401,10 @@ static void rx_ring_init(struct bcmgenet_eth_priv *priv) writel(RX_DESCS * DMA_DESC_SIZE / 4 - 1, priv->mac_reg + RDMA_RING_REG_BASE + DMA_END_ADDR); - writel(0x0, priv->mac_reg + RDMA_PROD_INDEX); - writel(0x0, priv->mac_reg + RDMA_CONS_INDEX); + /* cannot init RDMA_PROD_INDEX to 0, so align RDMA_CONS_INDEX on it instead */ + priv->c_index = readl(priv->mac_reg + RDMA_PROD_INDEX); + writel(priv->c_index, priv->mac_reg + RDMA_CONS_INDEX); + priv->rx_index = priv->c_index; writel((RX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH, priv->mac_reg + RDMA_RING_REG_BASE + DMA_RING_BUF_SIZE); writel(DMA_FC_THRESH_VALUE, priv->mac_reg + RDMA_XON_XOFF_THRESH); @@ -421,8 +421,9 @@ static void tx_ring_init(struct bcmgenet_eth_priv *priv) writel(0x0, priv->mac_reg + TDMA_WRITE_PTR); writel(TX_DESCS * DMA_DESC_SIZE / 4 - 1, priv->mac_reg + TDMA_RING_REG_BASE + DMA_END_ADDR); - writel(0x0, priv->mac_reg + TDMA_PROD_INDEX); - writel(0x0, priv->mac_reg + TDMA_CONS_INDEX); + /* cannot init TDMA_CONS_INDEX to 0, so align TDMA_PROD_INDEX on it instead */ + priv->tx_index = readl(priv->mac_reg + TDMA_CONS_INDEX); + writel(priv->tx_index, priv->mac_reg + TDMA_PROD_INDEX); writel(0x1, priv->mac_reg + TDMA_RING_REG_BASE + DMA_MBUF_DONE_THRESH); writel(0x0, priv->mac_reg + TDMA_FLOW_PERIOD); writel((TX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH, @@ -469,8 +470,6 @@ static int bcmgenet_gmac_eth_start(struct udevice *dev) priv->tx_desc_base = priv->mac_reg + GENET_TX_OFF; priv->rx_desc_base = priv->mac_reg + GENET_RX_OFF; - priv->tx_index = 0x0; - priv->rx_index = 0x0; bcmgenet_umac_reset(priv); -- 2.17.1