mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
Merge branch 'phy-polarity-inversion-via-generic-device-tree-properties'
Vladimir Oltean says:
====================
PHY polarity inversion via generic device tree properties
Using the "rx-polarity" and "tx-polarity" device tree properties
introduced in linux-phy and merged into net-next in
commit 96a2d53f24 ("Merge tag 'phy_common_properties' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy")
we convert here two existing networking use cases - the EN8811H Ethernet
PHY and the Mediatek LynxI PCS.
Original cover letter:
Polarity inversion (described in patch 4/10) is a feature with at least
4 potential new users waiting for a generic description:
- Horatiu Vultur with the lan966x SerDes
- Daniel Golle with the MaxLinear GSW1xx switches
- Bjørn Mork with the AN8811HB Ethernet PHY
- Me with a custom SJA1105 board, switch which uses the DesignWare XPCS
I became interested in exploring the problem space because I was averse
to the idea of adding vendor-specific device tree properties to describe
a common need.
This set contains an implementation of a generic feature that should
cater to all known needs that were identified during my documentation
phase.
Apart from what is converted here, we also have the following, which I
did not touch:
- "st,px_rx_pol_inv" - its binding is a .txt file and I don't have time
for such a large detour to convert it to dtschema.
- "st,pcie-tx-pol-inv" and "st,sata-tx-pol-inv" - these are defined in a
.txt schema but are not implemented in any driver. My verdict would be
"delete the properties" but again, I would prefer not introducing such
dependency to this series.
====================
Link: https://patch.msgid.link/20260119091220.1493761-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
331cf8fc18
|
|
@ -16,6 +16,7 @@ description:
|
|||
|
||||
allOf:
|
||||
- $ref: ethernet-phy.yaml#
|
||||
- $ref: /schemas/phy/phy-common-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
@ -30,12 +31,18 @@ properties:
|
|||
description:
|
||||
Reverse rx polarity of the SERDES. This is the receiving
|
||||
side of the lines from the MAC towards the EN881H.
|
||||
This property is deprecated, for details please refer to
|
||||
Documentation/devicetree/bindings/phy/phy-common-props.yaml
|
||||
deprecated: true
|
||||
|
||||
airoha,pnswap-tx:
|
||||
type: boolean
|
||||
description:
|
||||
Reverse tx polarity of SERDES. This is the transmitting
|
||||
side of the lines from EN8811H towards the MAC.
|
||||
This property is deprecated, for details please refer to
|
||||
Documentation/devicetree/bindings/phy/phy-common-props.yaml
|
||||
deprecated: true
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
|
@ -44,6 +51,8 @@ unevaluatedProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
|
@ -51,6 +60,6 @@ examples:
|
|||
ethernet-phy@1 {
|
||||
compatible = "ethernet-phy-id03a2.a411";
|
||||
reg = <1>;
|
||||
airoha,pnswap-rx;
|
||||
rx-polarity = <PHY_POL_INVERT>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,12 +39,17 @@ properties:
|
|||
const: 1
|
||||
|
||||
mediatek,pnswap:
|
||||
description: Invert polarity of the SGMII data lanes
|
||||
description:
|
||||
Invert polarity of the SGMII data lanes.
|
||||
This property is deprecated, for details please refer to
|
||||
Documentation/devicetree/bindings/phy/phy-common-props.yaml.
|
||||
type: boolean
|
||||
deprecated: true
|
||||
|
||||
pcs:
|
||||
type: object
|
||||
description: MediaTek LynxI HSGMII PCS
|
||||
$ref: /schemas/phy/phy-common-props.yaml#
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt7988-sgmii
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@ mt7531_create_sgmii(struct mt7530_priv *priv)
|
|||
ret = PTR_ERR(regmap);
|
||||
break;
|
||||
}
|
||||
pcs = mtk_pcs_lynxi_create(priv->dev, regmap,
|
||||
MT7531_PHYA_CTRL_SIGNAL3, 0);
|
||||
pcs = mtk_pcs_lynxi_create(priv->dev, NULL, regmap,
|
||||
MT7531_PHYA_CTRL_SIGNAL3);
|
||||
if (!pcs) {
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -4994,7 +4994,6 @@ static int mtk_sgmii_init(struct mtk_eth *eth)
|
|||
{
|
||||
struct device_node *np;
|
||||
struct regmap *regmap;
|
||||
u32 flags;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MTK_MAX_DEVS; i++) {
|
||||
|
|
@ -5003,18 +5002,16 @@ static int mtk_sgmii_init(struct mtk_eth *eth)
|
|||
break;
|
||||
|
||||
regmap = syscon_node_to_regmap(np);
|
||||
flags = 0;
|
||||
if (of_property_read_bool(np, "mediatek,pnswap"))
|
||||
flags |= MTK_SGMII_FLAG_PN_SWAP;
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
if (IS_ERR(regmap)) {
|
||||
of_node_put(np);
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev, regmap,
|
||||
eth->soc->ana_rgc3,
|
||||
flags);
|
||||
eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev,
|
||||
of_fwnode_handle(np),
|
||||
regmap,
|
||||
eth->soc->ana_rgc3);
|
||||
of_node_put(np);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ config PCS_LYNX
|
|||
|
||||
config PCS_MTK_LYNXI
|
||||
tristate
|
||||
select PHY_COMMON_PROPS
|
||||
select REGMAP
|
||||
help
|
||||
This module provides helpers to phylink for managing the LynxI PCS
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/mdio.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pcs/pcs-mtk-lynxi.h>
|
||||
#include <linux/phy/phy-common-props.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
|
@ -62,8 +63,9 @@
|
|||
|
||||
/* Register to QPHY wrapper control */
|
||||
#define SGMSYS_QPHY_WRAP_CTRL 0xec
|
||||
#define SGMII_PN_SWAP_MASK GENMASK(1, 0)
|
||||
#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1))
|
||||
#define SGMII_PN_SWAP_RX BIT(1)
|
||||
#define SGMII_PN_SWAP_TX BIT(0)
|
||||
|
||||
|
||||
/* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated
|
||||
* data
|
||||
|
|
@ -81,6 +83,7 @@ struct mtk_pcs_lynxi {
|
|||
phy_interface_t interface;
|
||||
struct phylink_pcs pcs;
|
||||
u32 flags;
|
||||
struct fwnode_handle *fwnode;
|
||||
};
|
||||
|
||||
static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
|
||||
|
|
@ -120,6 +123,42 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
|
|||
FIELD_GET(SGMII_LPA, adv));
|
||||
}
|
||||
|
||||
static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct fwnode_handle *fwnode = mpcs->fwnode, *pcs_fwnode;
|
||||
unsigned int pol, default_pol = PHY_POL_NORMAL;
|
||||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
|
||||
default_pol = PHY_POL_INVERT;
|
||||
|
||||
pcs_fwnode = fwnode_get_named_child_node(fwnode, "pcs");
|
||||
|
||||
ret = phy_get_rx_polarity(pcs_fwnode, phy_modes(interface),
|
||||
BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
|
||||
default_pol, &pol);
|
||||
if (ret) {
|
||||
fwnode_handle_put(pcs_fwnode);
|
||||
return ret;
|
||||
}
|
||||
if (pol == PHY_POL_INVERT)
|
||||
val |= SGMII_PN_SWAP_RX;
|
||||
|
||||
ret = phy_get_tx_polarity(pcs_fwnode, phy_modes(interface),
|
||||
BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
|
||||
default_pol, &pol);
|
||||
fwnode_handle_put(pcs_fwnode);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (pol == PHY_POL_INVERT)
|
||||
val |= SGMII_PN_SWAP_TX;
|
||||
|
||||
return regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
|
||||
SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX, val);
|
||||
}
|
||||
|
||||
static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
|
|
@ -129,6 +168,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
|
|||
bool mode_changed = false, changed;
|
||||
unsigned int rgc3, sgm_mode, bmcr;
|
||||
int advertise, link_timer;
|
||||
int ret;
|
||||
|
||||
advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
|
||||
advertising);
|
||||
|
|
@ -168,10 +208,9 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
|
|||
regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
|
||||
SGMII_SW_RESET);
|
||||
|
||||
if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP)
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
|
||||
SGMII_PN_SWAP_MASK,
|
||||
SGMII_PN_SWAP_TX_RX);
|
||||
ret = mtk_pcs_config_polarity(mpcs, interface);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_2500BASEX)
|
||||
rgc3 = SGMII_PHY_SPEED_3_125G;
|
||||
|
|
@ -268,8 +307,8 @@ static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
|
|||
};
|
||||
|
||||
struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
|
||||
struct regmap *regmap, u32 ana_rgc3,
|
||||
u32 flags)
|
||||
struct fwnode_handle *fwnode,
|
||||
struct regmap *regmap, u32 ana_rgc3)
|
||||
{
|
||||
struct mtk_pcs_lynxi *mpcs;
|
||||
u32 id, ver;
|
||||
|
|
@ -303,10 +342,10 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
|
|||
|
||||
mpcs->ana_rgc3 = ana_rgc3;
|
||||
mpcs->regmap = regmap;
|
||||
mpcs->flags = flags;
|
||||
mpcs->pcs.ops = &mtk_pcs_lynxi_ops;
|
||||
mpcs->pcs.poll = true;
|
||||
mpcs->interface = PHY_INTERFACE_MODE_NA;
|
||||
mpcs->fwnode = fwnode_handle_get(fwnode);
|
||||
|
||||
__set_bit(PHY_INTERFACE_MODE_SGMII, mpcs->pcs.supported_interfaces);
|
||||
__set_bit(PHY_INTERFACE_MODE_1000BASEX, mpcs->pcs.supported_interfaces);
|
||||
|
|
@ -318,10 +357,14 @@ EXPORT_SYMBOL(mtk_pcs_lynxi_create);
|
|||
|
||||
void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct mtk_pcs_lynxi *mpcs;
|
||||
|
||||
if (!pcs)
|
||||
return;
|
||||
|
||||
kfree(pcs_to_mtk_pcs_lynxi(pcs));
|
||||
mpcs = pcs_to_mtk_pcs_lynxi(pcs);
|
||||
fwnode_handle_put(mpcs->fwnode);
|
||||
kfree(mpcs);
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ config AS21XXX_PHY
|
|||
|
||||
config AIR_EN8811H_PHY
|
||||
tristate "Airoha EN8811H 2.5 Gigabit PHY"
|
||||
select PHY_COMMON_PROPS
|
||||
help
|
||||
Currently supports the Airoha EN8811H PHY.
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy/phy-common-props.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/wordpart.h>
|
||||
|
|
@ -966,11 +967,45 @@ static int en8811h_probe(struct phy_device *phydev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int en8811h_config_serdes_polarity(struct phy_device *phydev)
|
||||
{
|
||||
struct device *dev = &phydev->mdio.dev;
|
||||
unsigned int pol, default_pol;
|
||||
u32 pbus_value = 0;
|
||||
int ret;
|
||||
|
||||
default_pol = PHY_POL_NORMAL;
|
||||
if (device_property_read_bool(dev, "airoha,pnswap-rx"))
|
||||
default_pol = PHY_POL_INVERT;
|
||||
|
||||
ret = phy_get_rx_polarity(dev_fwnode(dev), phy_modes(phydev->interface),
|
||||
BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
|
||||
default_pol, &pol);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (pol == PHY_POL_INVERT)
|
||||
pbus_value |= EN8811H_POLARITY_RX_REVERSE;
|
||||
|
||||
default_pol = PHY_POL_NORMAL;
|
||||
if (device_property_read_bool(dev, "airoha,pnswap-tx"))
|
||||
default_pol = PHY_POL_INVERT;
|
||||
|
||||
ret = phy_get_tx_polarity(dev_fwnode(dev), phy_modes(phydev->interface),
|
||||
BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
|
||||
default_pol, &pol);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (pol == PHY_POL_NORMAL)
|
||||
pbus_value |= EN8811H_POLARITY_TX_NORMAL;
|
||||
|
||||
return air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
|
||||
EN8811H_POLARITY_RX_REVERSE |
|
||||
EN8811H_POLARITY_TX_NORMAL, pbus_value);
|
||||
}
|
||||
|
||||
static int en8811h_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
struct device *dev = &phydev->mdio.dev;
|
||||
u32 pbus_value;
|
||||
int ret;
|
||||
|
||||
/* If restart happened in .probe(), no need to restart now */
|
||||
|
|
@ -1003,19 +1038,7 @@ static int en8811h_config_init(struct phy_device *phydev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Serdes polarity */
|
||||
pbus_value = 0;
|
||||
if (device_property_read_bool(dev, "airoha,pnswap-rx"))
|
||||
pbus_value |= EN8811H_POLARITY_RX_REVERSE;
|
||||
else
|
||||
pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
|
||||
if (device_property_read_bool(dev, "airoha,pnswap-tx"))
|
||||
pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
|
||||
else
|
||||
pbus_value |= EN8811H_POLARITY_TX_NORMAL;
|
||||
ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
|
||||
EN8811H_POLARITY_RX_REVERSE |
|
||||
EN8811H_POLARITY_TX_NORMAL, pbus_value);
|
||||
ret = en8811h_config_serdes_polarity(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
#include <linux/phylink.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MTK_SGMII_FLAG_PN_SWAP BIT(0)
|
||||
struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
u32 ana_rgc3, u32 flags);
|
||||
struct fwnode_handle *fwnode,
|
||||
struct regmap *regmap, u32 ana_rgc3);
|
||||
void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user