[PATCH 3/3] net: RTL-8125B -- write mac to MAC0_BKP

2024-06-24 Thread ETIENNE DUBLE
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

2024-06-24 Thread ETIENNE DUBLE
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

2024-06-24 Thread ETIENNE DUBLE
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

2024-06-24 Thread ETIENNE DUBLE
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

2023-01-25 Thread ETIENNE DUBLE
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

2023-01-24 Thread ETIENNE DUBLE
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

2020-07-09 Thread etienne . duble
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