[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251112201937.1336854-3-prabhakar.mahadev-lad.rj@bp.renesas.com>
Date: Wed, 12 Nov 2025 20:19:37 +0000
From: Prabhakar <prabhakar.csengg@...il.com>
To: Clément Léger <clement.leger@...tlin.com>,
Andrew Lunn <andrew+netdev@...n.ch>,
"David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>,
Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Heiner Kallweit <hkallweit1@...il.com>,
Russell King <linux@...linux.org.uk>,
Geert Uytterhoeven <geert+renesas@...der.be>,
Magnus Damm <magnus.damm@...il.com>
Cc: linux-renesas-soc@...r.kernel.org,
netdev@...r.kernel.org,
devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org,
Prabhakar <prabhakar.csengg@...il.com>,
Biju Das <biju.das.jz@...renesas.com>,
Fabrizio Castro <fabrizio.castro.jz@...esas.com>,
Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
Subject: [PATCH net-next 2/2] net: pcs: rzn1-miic: Add support for PHY link active-level configuration
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
Add support to configure the PHY link signal active level per converter
using the DT property "renesas,miic-phylink-active-low".
Introduce the MIIC_PHYLINK register definition and extend the MIIC driver
with a new `phylink` structure to store the mask and value for PHY link
configuration. Implement `miic_configure_phylink()` to determine the bit
position and polarity for each port based on the SoC type, such as RZ/N1
or RZ/T2H/N2H.
The accumulated configuration is stored during Device Tree parsing and
applied later in `miic_probe()` after hardware initialization, since the
MIIC registers can only be modified safely once the hardware setup is
complete.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
---
drivers/net/pcs/pcs-rzn1-miic.c | 108 +++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 2 deletions(-)
diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c
index 885f17c32643..333467cf91a7 100644
--- a/drivers/net/pcs/pcs-rzn1-miic.c
+++ b/drivers/net/pcs/pcs-rzn1-miic.c
@@ -28,6 +28,8 @@
#define MIIC_MODCTRL 0x8
+#define MIIC_PHYLINK 0x14
+
#define MIIC_CONVCTRL(port) (0x100 + (port) * 4)
#define MIIC_CONVCTRL_CONV_SPEED GENMASK(1, 0)
@@ -177,6 +179,16 @@ static const char * const rzt2h_reset_ids[] = {
"crst",
};
+/**
+ * struct phylink - Phylink configuration
+ * @mask: Mask of phylink bits
+ * @val: Value of phylink bits
+ */
+struct phylink {
+ u32 mask;
+ u32 val;
+};
+
/**
* struct miic - MII converter structure
* @base: base address of the MII converter
@@ -184,6 +196,7 @@ static const char * const rzt2h_reset_ids[] = {
* @lock: Lock used for read-modify-write access
* @rsts: Reset controls for the MII converter
* @of_data: Pointer to OF data
+ * @phylink: Phylink configuration
*/
struct miic {
void __iomem *base;
@@ -191,6 +204,12 @@ struct miic {
spinlock_t lock;
struct reset_control_bulk_data rsts[MIIC_MAX_NUM_RSTS];
const struct miic_of_data *of_data;
+ struct phylink phylink;
+};
+
+enum miic_type {
+ MIIC_TYPE_RZN1,
+ MIIC_TYPE_RZT2H,
};
/**
@@ -210,6 +229,7 @@ struct miic {
* @init_unlock_lock_regs: Flag to indicate if registers need to be unlocked
* before access.
* @miic_write: Function pointer to write a value to a MIIC register
+ * @type: Type of MIIC
*/
struct miic_of_data {
struct modctrl_match *match_table;
@@ -226,6 +246,7 @@ struct miic_of_data {
u8 reset_count;
bool init_unlock_lock_regs;
void (*miic_write)(struct miic *miic, int offset, u32 value);
+ enum miic_type type;
};
/**
@@ -581,10 +602,82 @@ static int miic_match_dt_conf(struct miic *miic, s8 *dt_val, u32 *mode_cfg)
return -EINVAL;
}
+static void miic_configure_phylink(struct miic *miic, u32 conf,
+ u32 port, bool active_low)
+{
+ bool polarity_active_high;
+ u32 mask, val;
+ int shift;
+
+ /* determine shift and polarity for this conf */
+ if (miic->of_data->type == MIIC_TYPE_RZN1) {
+ switch (conf) {
+ /* switch ports => bits [3:0] (shift 0), active when low */
+ case MIIC_SWITCH_PORTA:
+ case MIIC_SWITCH_PORTB:
+ case MIIC_SWITCH_PORTC:
+ case MIIC_SWITCH_PORTD:
+ shift = 0;
+ polarity_active_high = false;
+ break;
+
+ /* EtherCAT ports => bits [7:4] (shift 4), active when high */
+ case MIIC_ETHERCAT_PORTA:
+ case MIIC_ETHERCAT_PORTB:
+ case MIIC_ETHERCAT_PORTC:
+ shift = 4;
+ polarity_active_high = true;
+ break;
+
+ /* Sercos ports => bits [11:8] (shift 8), active when high */
+ case MIIC_SERCOS_PORTA:
+ case MIIC_SERCOS_PORTB:
+ shift = 8;
+ polarity_active_high = true;
+ break;
+
+ default:
+ return;
+ }
+ } else {
+ switch (conf) {
+ /* ETHSW ports => bits [3:0] (shift 0), active when low */
+ case ETHSS_ETHSW_PORT0:
+ case ETHSS_ETHSW_PORT1:
+ case ETHSS_ETHSW_PORT2:
+ shift = 0;
+ polarity_active_high = false;
+ break;
+
+ /* ESC ports => bits [7:4] (shift 4), active when high */
+ case ETHSS_ESC_PORT0:
+ case ETHSS_ESC_PORT1:
+ case ETHSS_ESC_PORT2:
+ shift = 4;
+ polarity_active_high = true;
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ mask = BIT(port) << shift;
+
+ if (polarity_active_high)
+ val = (active_low ? 0 : BIT(port)) << shift;
+ else
+ val = (active_low ? BIT(port) : 0) << shift;
+
+ miic->phylink.mask |= mask;
+ miic->phylink.val = (miic->phylink.val & ~mask) | (val & mask);
+}
+
static int miic_parse_dt(struct miic *miic, u32 *mode_cfg)
{
struct device_node *np = miic->dev->of_node;
struct device_node *conv;
+ bool active_low;
int port, ret;
s8 *dt_val;
u32 conf;
@@ -605,8 +698,15 @@ static int miic_parse_dt(struct miic *miic, u32 *mode_cfg)
/* Adjust for 0 based index */
port += !miic->of_data->miic_port_start;
- if (of_property_read_u32(conv, "renesas,miic-input", &conf) == 0)
- dt_val[port] = conf;
+ if (of_property_read_u32(conv, "renesas,miic-input", &conf))
+ continue;
+
+ dt_val[port] = conf;
+
+ active_low = of_property_read_bool(conv, "renesas,miic-phylink-active-low");
+
+ miic_configure_phylink(miic, conf, port - !miic->of_data->miic_port_start,
+ active_low);
}
ret = miic_match_dt_conf(miic, dt_val, mode_cfg);
@@ -696,6 +796,8 @@ static int miic_probe(struct platform_device *pdev)
if (ret)
goto disable_runtime_pm;
+ miic_reg_rmw(miic, MIIC_PHYLINK, miic->phylink.mask, miic->phylink.val);
+
/* miic_create() relies on that fact that data are attached to the
* platform device to determine if the driver is ready so this needs to
* be the last thing to be done after everything is initialized
@@ -729,6 +831,7 @@ static struct miic_of_data rzn1_miic_of_data = {
.sw_mode_mask = GENMASK(4, 0),
.init_unlock_lock_regs = true,
.miic_write = miic_reg_writel_unlocked,
+ .type = MIIC_TYPE_RZN1,
};
static struct miic_of_data rzt2h_miic_of_data = {
@@ -745,6 +848,7 @@ static struct miic_of_data rzt2h_miic_of_data = {
.reset_ids = rzt2h_reset_ids,
.reset_count = ARRAY_SIZE(rzt2h_reset_ids),
.miic_write = miic_reg_writel_locked,
+ .type = MIIC_TYPE_RZT2H,
};
static const struct of_device_id miic_of_mtable[] = {
--
2.43.0
Powered by blists - more mailing lists