summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaven Xu <[email protected]>2026-07-22 15:50:57 +0800
committerJerome Forissier <[email protected]>2026-08-04 10:00:32 +0200
commita1aaacc968ae995b7557a316907c2e2f073b1a17 (patch)
tree9df5befc5dce04cff70b92fceb153f5397042ce7
parent7946774a0feb40a4abc71e749e61071ffce56979 (diff)
net: rtl8169: add support for RTL8126A and RTL8127A
RTL8126A and RTL8127A share most of the register layouts and quirks with RTL8125 series, but require explicit desc type and CRC-drop setup during init. This patch adds PCI IDs and MAC versions. RTL8126A is 0x66 and RTL8127A is 0x6e. And RTL8127A requires Tx Desc V3 format and an additional RADM FIFO protection configuration according to vendor driver. Signed-off-by: Javen Xu <[email protected]>
-rw-r--r--drivers/net/rtl8169.c103
1 files changed, 94 insertions, 9 deletions
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index e203faed26b..0208ff2d435 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -49,6 +49,7 @@
#include <asm/cache.h>
#include <asm/io.h>
#include <pci.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/printk.h>
@@ -152,8 +153,24 @@ enum RTL8125_registers {
IntrMask_8125 = 0x38,
IntrStatus_8125 = 0x3C,
TxPoll_8125 = 0x90,
+ RX_DESC_MODE = 0xd8,
+ MACOCP = 0xb0,
+ RADMFIFO_PROTECT = 0x0402,
+ TX_DESC_MODE = 0xeb58,
};
+/* MAC OCP indirect access via the MACOCP register */
+#define RTL8125_OCP_WRITE 0x80000000
+#define RTL8125_OCP_ADDR_SHIFT 16
+#define RX_DESC_CRC_DROP BIT(0)
+#define RX_DESC_TYPE BIT(1)
+
+/* TX_DESC_MODE (MAC OCP 0xeb58): TX descriptor format select, bits [1:0] */
+#define TX_DESC_FMT_MASK GENMASK(1, 0)
+#define TX_DESC_FMT_STD BIT(0)
+#define TX_DESC_FMT_V3 BIT(1)
+#define RX_PAUSE_SLOT_ON BIT(11)
+
enum RTL8169_register_content {
/*InterruptStatusBits */
SYSErr = 0x8000,
@@ -271,6 +288,8 @@ static struct {
{"RTL-8168h/8111h", 0x54, 0xff7e1880,},
{"RTL-8125B", 0x64, 0xff7e1880,},
{"RTL-8125d", 0x6a, 0xff7e5880,},
+ {"RTL-8126A", 0x66, 0xff7e5880,},
+ {"RTL-8127A", 0x6e, 0xff7e5880,},
};
enum _DescStatusBit {
@@ -355,6 +374,8 @@ static const unsigned int rtl8169_rx_config =
static struct pci_device_id supported[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8125) },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8126) },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8127) },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161) },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) },
@@ -398,6 +419,33 @@ int mdio_read(int RegAddr)
return value;
}
+/* RTL8125/8126/8127 share the same register layout and quirks */
+static bool rtl_is_8125(struct pci_child_plat *pplat)
+{
+ return pplat->device == 0x8125 || pplat->device == 0x8126 ||
+ pplat->device == 0x8127;
+}
+
+static void rtl_mac_ocp_write(u16 reg_addr, u16 value)
+{
+ u32 data32;
+
+ data32 = (u32)(reg_addr / 2) << RTL8125_OCP_ADDR_SHIFT;
+ data32 += value;
+ data32 |= RTL8125_OCP_WRITE;
+ RTL_W32(MACOCP, data32);
+}
+
+static u16 rtl_mac_ocp_read(u16 reg_addr)
+{
+ u32 data32;
+
+ data32 = (u32)(reg_addr / 2) << RTL8125_OCP_ADDR_SHIFT;
+ RTL_W32(MACOCP, data32);
+
+ return (u16)RTL_R32(MACOCP);
+}
+
static int rtl8169_init_board(unsigned long dev_iobase, const char *name)
{
int i;
@@ -571,12 +619,15 @@ static int rtl_recv_common(struct udevice *dev, unsigned long dev_iobase,
return length;
} else {
- u32 IntrStatus = IntrStatus_8169;
+ u32 sts;
- if (pplat->device == 0x8125)
- IntrStatus = IntrStatus_8125;
- ushort sts = RTL_R8(IntrStatus);
- RTL_W8(IntrStatus, sts & ~(TxErr | RxErr | SYSErr));
+ if (rtl_is_8125(pplat)) {
+ sts = RTL_R32(IntrStatus_8125);
+ RTL_W32(IntrStatus_8125, sts & ~(TxErr | RxErr | SYSErr));
+ } else {
+ sts = RTL_R16(IntrStatus_8169);
+ RTL_W16(IntrStatus_8169, sts & ~(TxErr | RxErr | SYSErr));
+ }
udelay(100); /* wait */
}
tpc->cur_rx = cur_rx;
@@ -636,8 +687,8 @@ static int rtl_send_common(struct udevice *dev, unsigned long dev_iobase,
((len > ETH_ZLEN) ? len : ETH_ZLEN));
}
rtl_flush_tx_desc(&tpc->TxDescArray[entry]);
- if (pplat->device == 0x8125)
- RTL_W8(TxPoll_8125, 0x1); /* set polling bit */
+ if (rtl_is_8125(pplat))
+ RTL_W32(TxPoll_8125, 0x1); /* set polling bit */
else
RTL_W8(TxPoll_8169, 0x40); /* set polling bit */
@@ -697,6 +748,8 @@ static void rtl8169_set_rx_mode(void)
static void rtl8169_hw_start(struct udevice *dev)
{
+ u8 version = rtl_chip_info[tpc->chipset].version;
+ u16 tx_desc_mode;
u32 i;
#ifdef DEBUG_RTL8169
@@ -719,6 +772,36 @@ static void rtl8169_hw_start(struct udevice *dev)
RTL_W8(Cfg9346, Cfg9346_Unlock);
+ /*
+ * RTL8125D/8126A/8127A require explicit descriptor-type and CRC-drop setup.
+ * RTL8125B (0x64) is intentionally excluded to avoid regressing working hardware.
+ */
+ switch (version) {
+ case 0x6a:
+ case 0x66:
+ case 0x6e:
+ /* Reg 0xD8: Disable CRC drop and force legacy 16-byte RX desc */
+ RTL_W8(RX_DESC_MODE, RTL_R8(RX_DESC_MODE) & ~(RX_DESC_CRC_DROP | RX_DESC_TYPE));
+
+ /* RxConfig 0x44: enable RX pause slot (RTL8125B and later) */
+ RTL_W32(RxConfig, RTL_R32(RxConfig) | RX_PAUSE_SLOT_ON);
+
+ /* MAC OCP 0xEB58: TX descriptor format setup */
+ tx_desc_mode = rtl_mac_ocp_read(TX_DESC_MODE) & ~TX_DESC_FMT_MASK;
+
+ if (version == 0x6e) {
+ /* RTL8127A specific: Tx desc V3 and RADM FIFO protection */
+ rtl_mac_ocp_write(TX_DESC_MODE, tx_desc_mode | TX_DESC_FMT_V3);
+ RTL_W16(RADMFIFO_PROTECT, 0x2001);
+ } else {
+ /* RTL8125D / RTL8126A specific: standard Tx desc */
+ rtl_mac_ocp_write(TX_DESC_MODE, tx_desc_mode | TX_DESC_FMT_STD);
+ }
+ break;
+ default:
+ break;
+ }
+
/* RTL-8169sb/8110sb or previous version */
if (tpc->chipset <= 5)
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
@@ -860,8 +943,8 @@ static void rtl_halt_common(struct udevice *dev)
RTL_W8(ChipCmd, 0x00);
/* Disable interrupts by clearing the interrupt mask. */
- if (pplat->device == 0x8125)
- RTL_W16(IntrMask_8125, 0x0000);
+ if (rtl_is_8125(pplat))
+ RTL_W32(IntrMask_8125, 0x00000000);
else
RTL_W16(IntrMask_8169, 0x0000);
@@ -1052,6 +1135,8 @@ static int rtl8169_eth_probe(struct udevice *dev)
switch (pplat->device) {
case 0x8125:
+ case 0x8126:
+ case 0x8127:
case 0x8161:
case 0x8168:
region = 2;