From: Mieczyslaw Nalewaj <namiltd@yahoo.com>
To: linusw@kernel.org, alsi@bang-olufsen.dk, andrew@lunn.ch,
olteanv@gmail.com, kuba@kernel.org, davem@davemloft.net,
edumazet@google.com, pabeni@redhat.com, linux@armlinux.org.uk,
luizluca@gmail.com, maxime.chevallier@bootlin.com,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH net-next 7/8] net: dsa: realtek: rtl8365mb: add family D SDS13 PCS support
Date: Wed, 7 Oct 2026 22:41:38 +0200 [thread overview]
Message-ID: <562b5fda-e1ec-40f0-834f-2bcebe2894b7@yahoo.com> (raw)
In-Reply-To: <84fc7483-b22d-45ea-a3b8-3285dc357265@yahoo.com>
Extend the existing RTL8367S SGMII/HSGMII PCS implementation in this
driver for family D switches, whose CPU SerDes is reached through the
indexed SDS13 window and whose SDS_MISC fields differ from family C.
The register sequence and tuning tables are derived from the GPL-licensed
Realtek RTL8367D port API distributed in the Mercusys MR80X GPL release.
Keep the existing family C path unchanged and select the new behavior from
the driver's chip-family metadata, making the implementation reusable by
other family D boards.
Co-developed-by: Fabiano Tassotti <fabianotassotti@gmail.com>
Signed-off-by: Fabiano Tassotti <fabianotassotti@gmail.com>
Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
---
drivers/net/dsa/realtek/rtl8365mb_main.c | 181 ++++++++++++++++++-----
1 file changed, 145 insertions(+), 36 deletions(-)
diff --git a/drivers/net/dsa/realtek/rtl8365mb_main.c b/drivers/net/dsa/realtek/rtl8365mb_main.c
index c638c20..aad26ba 100644
--- a/drivers/net/dsa/realtek/rtl8365mb_main.c
+++ b/drivers/net/dsa/realtek/rtl8365mb_main.c
@@ -286,6 +286,7 @@
#define RTL8365MB_SDS_INDACS_CMD_BUSY_MASK BIT(8)
#define RTL8365MB_SDS_INDACS_CMD_RUN_MASK BIT(7)
#define RTL8365MB_SDS_INDACS_CMD_WR_MASK BIT(6)
+#define RTL8365MB_SDS_INDACS_CMD_INDEX_MASK GENMASK(5, 0)
#define RTL8365MB_SDS_INDACS_ADR_REG 0x6601
#define RTL8365MB_SDS_INDACS_DATA_REG 0x6602
@@ -334,7 +335,22 @@
#define RTL8365MB_SDS_OPTION_ARM_KEY 0x0249
#define RTL8365MB_SDS_OPTION_REG 0x13C1
+/* Family D uses the SDS13 indirect window for its MAC6 SerDes. */
+#define RTL8365MB_D_SDS_EXT0_INDEX 13
+#define RTL8365MB_D_FIBER_CFG2_REG 0x13E8
+#define RTL8365MB_D_FIBER_CFG2_RX_DISABLE_MASK GENMASK(7, 6)
+#define RTL8365MB_D_FIBER_CFG2_RX_DISABLE_SDS0 BIT(6)
+#define RTL8365MB_D_SDS_MISC_PA33PC_EN BIT(11)
+#define RTL8365MB_D_SDS_MISC_PA12PC_EN BIT(10)
+#define RTL8365MB_D_SDS_MISC_MAC6_SEL_SDS0 BIT(9)
#define RTL8365MB_D_SDS_MISC_MODE_FIELD_MASK GENMASK(4, 0)
+#define RTL8365MB_D_SDS_MISC_MODE_SGMII 0x02
+#define RTL8365MB_D_SDS_MISC_MODE_HSGMII 0x12
+#define RTL8365MB_D_SDS_MISC_CFG_MASK \
+ (RTL8365MB_D_SDS_MISC_PA33PC_EN | \
+ RTL8365MB_D_SDS_MISC_PA12PC_EN | \
+ RTL8365MB_D_SDS_MISC_MAC6_SEL_SDS0 | \
+ RTL8365MB_D_SDS_MISC_MODE_FIELD_MASK)
/* Shared "disable" encoding for both SDS_MISC's and SDS1_MISC0's
* 5-bit mode fields.
*/
@@ -709,6 +725,21 @@ static const struct rtl8365mb_jam_tbl_entry rtl8365mb_sds_jam_hsgmii[] = {
{ 0x0424, 0xD810 }, { 0x0001, 0x0F80 }, { 0x002E, 0x83F2 },
};
+/* Family D tuning tables from the Realtek vendor port API. */
+static const struct rtl8365mb_jam_tbl_entry rtl8365mb_d_sds_jam_sgmii[] = {
+ { 0x0427, 0x4E0C }, { 0x0428, 0xAA00 }, { 0x0425, 0x5189 },
+ { 0x0424, 0x8414 }, { 0x0423, 0x1020 }, { 0x0410, 0x0002 },
+ { 0x0484, 0x011B }, { 0x0421, 0x8E13 }, { 0x0422, 0x1140 },
+ { 0x0004, 0x074F },
+};
+
+static const struct rtl8365mb_jam_tbl_entry rtl8365mb_d_sds_jam_hsgmii[] = {
+ { 0x0427, 0x4E0C }, { 0x0428, 0xAA00 }, { 0x0425, 0x5189 },
+ { 0x0424, 0x8414 }, { 0x0423, 0x1020 }, { 0x0410, 0x0002 },
+ { 0x0504, 0x051B }, { 0x0421, 0x8E13 }, { 0x0422, 0x1140 },
+ { 0x0004, 0x074F },
+};
+
enum rtl8365mb_phy_interface_mode {
RTL8365MB_PHY_INTERFACE_MODE_INVAL = 0,
RTL8365MB_PHY_INTERFACE_MODE_INTERNAL = BIT(0),
@@ -1322,7 +1353,8 @@ static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port,
return 0;
}
-static int rtl8365mb_sds_write(struct realtek_priv *priv, u16 addr, u16 data)
+static int rtl8365mb_sds_write(struct realtek_priv *priv, u8 index,
+ u16 addr, u16 data)
{
int ret;
@@ -1340,10 +1372,13 @@ static int rtl8365mb_sds_write(struct realtek_priv *priv, u16 addr, u16 data)
*/
return regmap_write(priv->map, RTL8365MB_SDS_INDACS_CMD_REG,
RTL8365MB_SDS_INDACS_CMD_RUN_MASK |
- RTL8365MB_SDS_INDACS_CMD_WR_MASK);
+ RTL8365MB_SDS_INDACS_CMD_WR_MASK |
+ FIELD_PREP(RTL8365MB_SDS_INDACS_CMD_INDEX_MASK,
+ index));
}
-static int rtl8365mb_sds_read(struct realtek_priv *priv, u16 addr, u16 *data)
+static int rtl8365mb_sds_read(struct realtek_priv *priv, u8 index,
+ u16 addr, u16 *data)
{
u32 val;
int ret;
@@ -1353,7 +1388,9 @@ static int rtl8365mb_sds_read(struct realtek_priv *priv, u16 addr, u16 *data)
return ret;
ret = regmap_write(priv->map, RTL8365MB_SDS_INDACS_CMD_REG,
- RTL8365MB_SDS_INDACS_CMD_RUN_MASK);
+ RTL8365MB_SDS_INDACS_CMD_RUN_MASK |
+ FIELD_PREP(RTL8365MB_SDS_INDACS_CMD_INDEX_MASK,
+ index));
if (ret)
return ret;
@@ -1393,6 +1430,14 @@ static int rtl8365mb_sds_probe_option(struct realtek_priv *priv)
int ret;
int i;
+ /* Family D has a fixed SDS13 programming model and does not use the
+ * family C option register to select its tuning table.
+ */
+ if (rtl8365mb_get_family(priv) == RTL8365MB_FAMILY_D) {
+ mb->sds_supported = true;
+ return 0;
+ }
+
/* Nothing to probe if no external interface is wired to the SerDes */
for (i = 0; i < RTL8365MB_MAX_NUM_EXTINTS; i++) {
extint = &mb->chip_info->extints[i];
@@ -1471,28 +1516,47 @@ static int rtl8365mb_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
const unsigned long *advertising,
bool permit_pause_to_mac)
{
- const struct rtl8365mb_jam_tbl_entry *sds_jam;
const int id = RTL8365MB_SDS_EXT_INTERFACE_ID;
+ const struct rtl8365mb_jam_tbl_entry *sds_jam;
struct rtl8365mb *mb = pcs_to_rtl8365mb(pcs);
- struct realtek_priv *priv;
+ struct realtek_priv *priv = mb->priv;
size_t sds_jam_size;
- u32 mode;
+ u32 misc_mask;
+ u32 misc_val;
+ u32 sds_mode;
+ u8 sds_index;
+ bool is_d;
u16 val;
int ret;
int i;
- priv = mb->priv;
+ is_d = rtl8365mb_get_family(priv) == RTL8365MB_FAMILY_D;
+ /* Select the appropriate tuning table and SDS mode */
if (interface == PHY_INTERFACE_MODE_2500BASEX) {
- sds_jam = rtl8365mb_sds_jam_hsgmii;
- sds_jam_size = ARRAY_SIZE(rtl8365mb_sds_jam_hsgmii);
- mode = RTL8365MB_EXT_PORT_MODE_HSGMII;
+ if (is_d) {
+ sds_jam = rtl8365mb_d_sds_jam_hsgmii;
+ sds_jam_size = ARRAY_SIZE(rtl8365mb_d_sds_jam_hsgmii);
+ sds_mode = RTL8365MB_D_SDS_MISC_MODE_HSGMII;
+ } else {
+ sds_jam = rtl8365mb_sds_jam_hsgmii;
+ sds_jam_size = ARRAY_SIZE(rtl8365mb_sds_jam_hsgmii);
+ sds_mode = RTL8365MB_EXT_PORT_MODE_HSGMII;
+ }
} else {
- sds_jam = rtl8365mb_sds_jam_sgmii;
- sds_jam_size = ARRAY_SIZE(rtl8365mb_sds_jam_sgmii);
- mode = RTL8365MB_EXT_PORT_MODE_SGMII;
+ if (is_d) {
+ sds_jam = rtl8365mb_d_sds_jam_sgmii;
+ sds_jam_size = ARRAY_SIZE(rtl8365mb_d_sds_jam_sgmii);
+ sds_mode = RTL8365MB_D_SDS_MISC_MODE_SGMII;
+ } else {
+ sds_jam = rtl8365mb_sds_jam_sgmii;
+ sds_jam_size = ARRAY_SIZE(rtl8365mb_sds_jam_sgmii);
+ sds_mode = RTL8365MB_EXT_PORT_MODE_SGMII;
+ }
}
+ sds_index = is_d ? RTL8365MB_D_SDS_EXT0_INDEX : 0;
+
/* Hold the embedded DW8051 microcontroller in reset and keep it
* disabled. The vendor driver loads firmware into it to manage the
* SerDes link, but the firmware only duplicates work that phylink
@@ -1521,34 +1585,53 @@ static int rtl8365mb_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
/* Tune the SerDes with vendor-prescribed parameters */
for (i = 0; i < sds_jam_size; i++) {
- ret = rtl8365mb_sds_write(priv, sds_jam[i].reg,
- sds_jam[i].val);
+ ret = rtl8365mb_sds_write(priv, sds_index,
+ sds_jam[i].reg, sds_jam[i].val);
+ if (ret)
+ return ret;
+ }
+
+ /* Family-specific post-tuning configuration */
+ if (is_d) {
+ ret = regmap_update_bits(priv->map, RTL8365MB_D_FIBER_CFG2_REG,
+ RTL8365MB_D_FIBER_CFG2_RX_DISABLE_MASK,
+ RTL8365MB_D_FIBER_CFG2_RX_DISABLE_SDS0);
if (ret)
return ret;
+
+ misc_mask = RTL8365MB_D_SDS_MISC_CFG_MASK;
+ misc_val = RTL8365MB_D_SDS_MISC_PA33PC_EN |
+ RTL8365MB_D_SDS_MISC_PA12PC_EN |
+ RTL8365MB_D_SDS_MISC_MAC6_SEL_SDS0 | sds_mode;
+ } else {
+ /* Mux the SerDes to MAC8 in the requested mode */
+ misc_mask = RTL8365MB_SDS_MISC_MAC8_SEL_SGMII_MASK |
+ RTL8365MB_SDS_MISC_MAC8_SEL_HSGMII_MASK;
+ misc_val = (sds_mode == RTL8365MB_EXT_PORT_MODE_SGMII) ?
+ RTL8365MB_SDS_MISC_MAC8_SEL_SGMII_MASK :
+ RTL8365MB_SDS_MISC_MAC8_SEL_HSGMII_MASK;
}
- /* Mux the SerDes to MAC8 in the requested mode */
ret = regmap_update_bits(priv->map, RTL8365MB_SDS_MISC_REG,
- RTL8365MB_SDS_MISC_MAC8_SEL_SGMII_MASK |
- RTL8365MB_SDS_MISC_MAC8_SEL_HSGMII_MASK,
- mode == RTL8365MB_EXT_PORT_MODE_SGMII ?
- RTL8365MB_SDS_MISC_MAC8_SEL_SGMII_MASK :
- RTL8365MB_SDS_MISC_MAC8_SEL_HSGMII_MASK);
+ misc_mask, misc_val);
if (ret)
return ret;
- val = mode << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(id);
- ret = regmap_update_bits(priv->map,
- RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(id),
- RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(id),
- val);
- if (ret)
- return ret;
+ if (!is_d) {
+ val = sds_mode << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(id);
+ ret = regmap_update_bits(priv->map,
+ RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(id),
+ RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(id),
+ val);
+ if (ret)
+ return ret;
+ }
/* Take the SerDes out of reset. The vendor driver does this only
* after the SerDes mux and the interface mode are configured.
*/
- ret = rtl8365mb_sds_write(priv, RTL8365MB_SDS_REG_RESET,
+ ret = rtl8365mb_sds_write(priv, sds_index,
+ RTL8365MB_SDS_REG_RESET,
RTL8365MB_SDS_RESET_DEASSERT);
if (ret)
return ret;
@@ -1558,12 +1641,14 @@ static int rtl8365mb_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
* This flushes the FIFOs and ensures a clean state for the link,
* preventing silent drops and CRC errors.
*/
- ret = rtl8365mb_sds_write(priv, RTL8365MB_SDS_REG_BMCR,
+ ret = rtl8365mb_sds_write(priv, sds_index,
+ RTL8365MB_SDS_REG_BMCR,
RTL8365MB_SDS_BMCR_DPRST_PHASE1);
if (ret)
return ret;
- ret = rtl8365mb_sds_write(priv, RTL8365MB_SDS_REG_BMCR,
+ ret = rtl8365mb_sds_write(priv, sds_index,
+ RTL8365MB_SDS_REG_BMCR,
RTL8365MB_SDS_BMCR_DPRST_PHASE2);
if (ret)
return ret;
@@ -1571,14 +1656,16 @@ static int rtl8365mb_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
/* Keep SGMII in-band autonegotiation disabled: the link parameters are
* forced from rtl8365mb_pcs_link_up() instead.
*/
- ret = rtl8365mb_sds_read(priv, RTL8365MB_SDS_REG_NWAY, &val);
+ ret = rtl8365mb_sds_read(priv, sds_index,
+ RTL8365MB_SDS_REG_NWAY, &val);
if (ret)
return ret;
val &= ~RTL8365MB_SDS_NWAY_EN_MASK;
val |= RTL8365MB_SDS_NWAY_RESTART_MASK;
- return rtl8365mb_sds_write(priv, RTL8365MB_SDS_REG_NWAY, val);
+ return rtl8365mb_sds_write(priv, sds_index,
+ RTL8365MB_SDS_REG_NWAY, val);
}
static bool rtl8365mb_interface_is_serdes(phy_interface_t interface)
@@ -1603,10 +1690,14 @@ static void rtl8365mb_pcs_get_state(struct phylink_pcs *pcs,
{
struct rtl8365mb *mb = pcs_to_rtl8365mb(pcs);
struct realtek_priv *priv = mb->priv;
+ u8 sds_index = 0;
u16 status;
+ bool is_d;
u32 val;
int ret;
+ is_d = rtl8365mb_get_family(priv) == RTL8365MB_FAMILY_D;
+
/* In-band autonegotiation is not implemented, so the link parameters are
* forced from rtl8365mb_pcs_link_up(). The real link state must still be
* read from the SerDes itself: the embedded DW8051 microcontroller that
@@ -1614,7 +1705,11 @@ static void rtl8365mb_pcs_get_state(struct phylink_pcs *pcs,
* rtl8365mb_pcs_config()), so the link status register can be read
* directly through the SDS_INDACS window without racing the auto-poll.
*/
- ret = rtl8365mb_sds_read(priv, RTL8365MB_SDS_REG_LINK_STATUS, &status);
+ if (is_d)
+ sds_index = RTL8365MB_D_SDS_EXT0_INDEX;
+
+ ret = rtl8365mb_sds_read(priv, sds_index,
+ RTL8365MB_SDS_REG_LINK_STATUS, &status);
if (ret) {
state->link = false;
return;
@@ -1625,6 +1720,13 @@ static void rtl8365mb_pcs_get_state(struct phylink_pcs *pcs,
if (!state->link)
return;
+ if (is_d) {
+ state->duplex = DUPLEX_FULL;
+ state->speed = state->interface == PHY_INTERFACE_MODE_2500BASEX ?
+ SPEED_2500 : SPEED_1000;
+ return;
+ }
+
/* The speed and duplex are forced; read them back from the values
* programmed into the SerDes MISC register.
*/
@@ -1666,6 +1768,12 @@ static void rtl8365mb_pcs_link_up(struct phylink_pcs *pcs,
u32 r_speed;
int ret;
+ /* Family D forces the external MAC ability from mac_link_up(); its
+ * SDS_MISC fields do not share the family C link-force layout.
+ */
+ if (rtl8365mb_get_family(priv) == RTL8365MB_FAMILY_D)
+ return;
+
/* The speed field has no value for 2.5 Gbps: the rate is determined by
* the HSGMII SerDes configuration, and the vendor driver programs the
* 1 Gbps value here.
@@ -1991,7 +2099,8 @@ static void rtl8365mb_phylink_mac_link_up(struct phylink_config *config,
* rtl8365mb_pcs_link_up() because pcs_link_up() carries no
* pause information.
*/
- if (rtl8365mb_interface_is_serdes(interface)) {
+ if (rtl8365mb_interface_is_serdes(interface) &&
+ rtl8365mb_get_family(priv) != RTL8365MB_FAMILY_D) {
u32 val = 0;
if (tx_pause)
--
2.53.0
next prev parent reply other threads:[~2026-10-07 20:52 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <84fc7483-b22d-45ea-a3b8-3285dc357265.ref@yahoo.com>
2026-10-07 20:34 ` [PATCH net-next 0/8] net: dsa: realtek: rtl8365mb: add support for RTL8367S-VB Mieczyslaw Nalewaj
2026-10-07 20:36 ` [PATCH net-next 1/8] net: dsa: realtek: rtl8365mb: detect RTL8367S-VB Mieczyslaw Nalewaj
2026-10-07 20:37 ` [PATCH net-next 2/8] net: dsa: realtek: rtl8365mb: set speed for family D Mieczyslaw Nalewaj
2026-10-07 20:38 ` [PATCH net-next 3/8] net: dsa: realtek: rtl8365mb: get pvid " Mieczyslaw Nalewaj
2026-10-07 20:39 ` [PATCH net-next 4/8] net: dsa: realtek: rtl8365mb: set RGMII mode " Mieczyslaw Nalewaj
2026-10-08 1:22 ` Andrew Lunn
2026-10-08 14:09 ` Mieczyslaw Nalewaj
2026-10-08 15:07 ` Mieczyslaw Nalewaj
2026-10-07 20:39 ` [PATCH net-next 5/8] net: dsa: realtek: rtl8365mb: set and get vlan 4k " Mieczyslaw Nalewaj
2026-10-07 20:40 ` [PATCH net-next 6/8] net: dsa: realtek: rtl8365mb: set/clear pvid " Mieczyslaw Nalewaj
2026-10-07 20:41 ` Mieczyslaw Nalewaj [this message]
2026-10-07 20:42 ` [PATCH net-next 8/8] net: dsa: realtek: rtl8365mb: re-latch the family D SerDes Mieczyslaw Nalewaj
2026-10-08 10:10 ` kernel test robot
2026-10-10 19:27 ` Mieczyslaw Nalewaj
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=562b5fda-e1ec-40f0-834f-2bcebe2894b7@yahoo.com \
--to=namiltd@yahoo.com \
--cc=alsi@bang-olufsen.dk \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linusw@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=luizluca@gmail.com \
--cc=maxime.chevallier@bootlin.com \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.