diff mbox series

[net,v2,1/2] net: phy: nxp-c45-tja11xx: add TJA112X PHY configuration errata

Message ID 20250304160619.181046-2-andrei.botila@oss.nxp.com (mailing list archive)
State Accepted
Commit a07364b394697d2e0baffeb517f41385259aa484
Delegated to: Netdev Maintainers
Headers show
Series net: phy: nxp-c45-tja11xx: add errata for TJA112XA/B | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers fail 1 blamed authors not CCed: radu-nicolae.pirea@oss.nxp.com; 2 maintainers not CCed: radu-nicolae.pirea@oss.nxp.com sd@queasysnail.net
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Andrei Botila March 4, 2025, 4:06 p.m. UTC
The most recent sillicon versions of TJA1120 and TJA1121 can achieve
full silicon performance by putting the PHY in managed mode.

It is necessary to apply these PHY writes before link gets established.
Application of this fix is required after restart of device and wakeup
from sleep.

Cc: stable@vger.kernel.org
Fixes: f1fe5dff2b8a ("net: phy: nxp-c45-tja11xx: add TJA1120 support")
Signed-off-by: Andrei Botila <andrei.botila@oss.nxp.com>
---
 drivers/net/phy/nxp-c45-tja11xx.c | 52 +++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

Comments

Paolo Abeni March 6, 2025, 9:43 a.m. UTC | #1
On 3/4/25 5:06 PM, Andrei Botila wrote:
> diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
> index 34231b5b9175..709d6c9f7cba 100644
> --- a/drivers/net/phy/nxp-c45-tja11xx.c
> +++ b/drivers/net/phy/nxp-c45-tja11xx.c
> @@ -22,6 +22,11 @@
>  #define PHY_ID_TJA_1103			0x001BB010
>  #define PHY_ID_TJA_1120			0x001BB031
>  
> +#define VEND1_DEVICE_ID3		0x0004
> +#define TJA1120_DEV_ID3_SILICON_VERSION	GENMASK(15, 12)
> +#define TJA1120_DEV_ID3_SAMPLE_TYPE	GENMASK(11, 8)
> +#define DEVICE_ID3_SAMPLE_TYPE_R	0x9
> +
>  #define VEND1_DEVICE_CONTROL		0x0040
>  #define DEVICE_CONTROL_RESET		BIT(15)
>  #define DEVICE_CONTROL_CONFIG_GLOBAL_EN	BIT(14)
> @@ -1593,6 +1598,50 @@ static int nxp_c45_set_phy_mode(struct phy_device *phydev)
>  	return 0;
>  }
>  
> +/* Errata: ES_TJA1120 and ES_TJA1121 Rev. 1.0 — 28 November 2024 Section 3.1 */
> +static void nxp_c45_tja1120_errata(struct phy_device *phydev)
> +{
> +	int silicon_version, sample_type;
> +	bool macsec_ability;
> +	int phy_abilities;
> +	int ret = 0;
> +
> +	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_ID3);
> +	if (ret < 0)
> +		return;
> +
> +	sample_type = FIELD_GET(TJA1120_DEV_ID3_SAMPLE_TYPE, ret);
> +	if (sample_type != DEVICE_ID3_SAMPLE_TYPE_R)
> +		return;
> +
> +	silicon_version = FIELD_GET(TJA1120_DEV_ID3_SILICON_VERSION, ret);
> +
> +	phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1,
> +				     VEND1_PORT_ABILITIES);
> +	macsec_ability = !!(phy_abilities & MACSEC_ABILITY);
> +	if ((!macsec_ability && silicon_version == 2) ||
> +	    (macsec_ability && silicon_version == 1)) {
> +		/* TJA1120/TJA1121 PHY configuration errata workaround.
> +		 * Apply PHY writes sequence before link up.
> +		 */
> +		if (!macsec_ability) {
> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x4b95);
> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0xf3cd);
> +		} else {
> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x89c7);
> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0893);
> +		}
> +
> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0476, 0x58a0);
> +
> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x8921, 0xa3a);
> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x89F1, 0x16c1);
> +
> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x0);
> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0);

Please add macro with meaningful names for all the magic numbers used
above, thanks!

Paolo
Andrei Botila March 6, 2025, 12:03 p.m. UTC | #2
On 3/6/2025 11:43 AM, Paolo Abeni wrote:
> On 3/4/25 5:06 PM, Andrei Botila wrote:
>> diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
>> index 34231b5b9175..709d6c9f7cba 100644
>> --- a/drivers/net/phy/nxp-c45-tja11xx.c
>> +++ b/drivers/net/phy/nxp-c45-tja11xx.c
>> @@ -22,6 +22,11 @@
>>  #define PHY_ID_TJA_1103			0x001BB010
>>  #define PHY_ID_TJA_1120			0x001BB031
>>  
>> +#define VEND1_DEVICE_ID3		0x0004
>> +#define TJA1120_DEV_ID3_SILICON_VERSION	GENMASK(15, 12)
>> +#define TJA1120_DEV_ID3_SAMPLE_TYPE	GENMASK(11, 8)
>> +#define DEVICE_ID3_SAMPLE_TYPE_R	0x9
>> +
>>  #define VEND1_DEVICE_CONTROL		0x0040
>>  #define DEVICE_CONTROL_RESET		BIT(15)
>>  #define DEVICE_CONTROL_CONFIG_GLOBAL_EN	BIT(14)
>> @@ -1593,6 +1598,50 @@ static int nxp_c45_set_phy_mode(struct phy_device *phydev)
>>  	return 0;
>>  }
>>  
>> +/* Errata: ES_TJA1120 and ES_TJA1121 Rev. 1.0 — 28 November 2024 Section 3.1 */
>> +static void nxp_c45_tja1120_errata(struct phy_device *phydev)
>> +{
>> +	int silicon_version, sample_type;
>> +	bool macsec_ability;
>> +	int phy_abilities;
>> +	int ret = 0;
>> +
>> +	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_ID3);
>> +	if (ret < 0)
>> +		return;
>> +
>> +	sample_type = FIELD_GET(TJA1120_DEV_ID3_SAMPLE_TYPE, ret);
>> +	if (sample_type != DEVICE_ID3_SAMPLE_TYPE_R)
>> +		return;
>> +
>> +	silicon_version = FIELD_GET(TJA1120_DEV_ID3_SILICON_VERSION, ret);
>> +
>> +	phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1,
>> +				     VEND1_PORT_ABILITIES);
>> +	macsec_ability = !!(phy_abilities & MACSEC_ABILITY);
>> +	if ((!macsec_ability && silicon_version == 2) ||
>> +	    (macsec_ability && silicon_version == 1)) {
>> +		/* TJA1120/TJA1121 PHY configuration errata workaround.
>> +		 * Apply PHY writes sequence before link up.
>> +		 */
>> +		if (!macsec_ability) {
>> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x4b95);
>> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0xf3cd);
>> +		} else {
>> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x89c7);
>> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0893);
>> +		}
>> +
>> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0476, 0x58a0);
>> +
>> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x8921, 0xa3a);
>> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x89F1, 0x16c1);
>> +
>> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x0);
>> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0);
> 
> Please add macro with meaningful names for all the magic numbers used
> above, thanks!
> 
> Paolo
> 

Hello, these registers are not documented in the datasheet or errata sheet.
The access sequence comes 1-to-1 from the errata so I couldn't use macros.

Regards, Andrei B.
Andrew Lunn March 6, 2025, 3:35 p.m. UTC | #3
> >> +/* Errata: ES_TJA1120 and ES_TJA1121 Rev. 1.0 — 28 November 2024 Section 3.1 */
> >> +static void nxp_c45_tja1120_errata(struct phy_device *phydev)
> >> +{
> >> +	int silicon_version, sample_type;
> >> +	bool macsec_ability;
> >> +	int phy_abilities;
> >> +	int ret = 0;
> >> +
> >> +	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_ID3);
> >> +	if (ret < 0)
> >> +		return;
> >> +
> >> +	sample_type = FIELD_GET(TJA1120_DEV_ID3_SAMPLE_TYPE, ret);
> >> +	if (sample_type != DEVICE_ID3_SAMPLE_TYPE_R)
> >> +		return;
> >> +
> >> +	silicon_version = FIELD_GET(TJA1120_DEV_ID3_SILICON_VERSION, ret);
> >> +
> >> +	phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1,
> >> +				     VEND1_PORT_ABILITIES);
> >> +	macsec_ability = !!(phy_abilities & MACSEC_ABILITY);
> >> +	if ((!macsec_ability && silicon_version == 2) ||
> >> +	    (macsec_ability && silicon_version == 1)) {
> >> +		/* TJA1120/TJA1121 PHY configuration errata workaround.
> >> +		 * Apply PHY writes sequence before link up.
> >> +		 */
> >> +		if (!macsec_ability) {
> >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x4b95);
> >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0xf3cd);
> >> +		} else {
> >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x89c7);
> >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0893);
> >> +		}
> >> +
> >> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0476, 0x58a0);
> >> +
> >> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x8921, 0xa3a);
> >> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x89F1, 0x16c1);
> >> +
> >> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x0);
> >> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0);
> > 
> > Please add macro with meaningful names for all the magic numbers used
> > above, thanks!
> > 
> > Paolo
> > 
> 
> Hello, these registers are not documented in the datasheet or errata sheet.
> The access sequence comes 1-to-1 from the errata so I couldn't use macros.

Yes, we sometimes just have to accept the drivers are doing magic we
have no idea about because the vendor does not want to tell is. All
the registers in MDIO_MMD_VEND1 are clearly vendor specific. The
MDIO_MMD_PMAPMD registers are also in the range reserved for
vendors. So i think we just have to accept it.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew
Simon Horman March 7, 2025, 1:24 p.m. UTC | #4
On Thu, Mar 06, 2025 at 04:35:12PM +0100, Andrew Lunn wrote:
> > >> +/* Errata: ES_TJA1120 and ES_TJA1121 Rev. 1.0 — 28 November 2024 Section 3.1 */
> > >> +static void nxp_c45_tja1120_errata(struct phy_device *phydev)
> > >> +{
> > >> +	int silicon_version, sample_type;
> > >> +	bool macsec_ability;
> > >> +	int phy_abilities;
> > >> +	int ret = 0;
> > >> +
> > >> +	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_ID3);
> > >> +	if (ret < 0)
> > >> +		return;
> > >> +
> > >> +	sample_type = FIELD_GET(TJA1120_DEV_ID3_SAMPLE_TYPE, ret);
> > >> +	if (sample_type != DEVICE_ID3_SAMPLE_TYPE_R)
> > >> +		return;
> > >> +
> > >> +	silicon_version = FIELD_GET(TJA1120_DEV_ID3_SILICON_VERSION, ret);
> > >> +
> > >> +	phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1,
> > >> +				     VEND1_PORT_ABILITIES);
> > >> +	macsec_ability = !!(phy_abilities & MACSEC_ABILITY);
> > >> +	if ((!macsec_ability && silicon_version == 2) ||
> > >> +	    (macsec_ability && silicon_version == 1)) {
> > >> +		/* TJA1120/TJA1121 PHY configuration errata workaround.
> > >> +		 * Apply PHY writes sequence before link up.
> > >> +		 */
> > >> +		if (!macsec_ability) {
> > >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x4b95);
> > >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0xf3cd);
> > >> +		} else {
> > >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x89c7);
> > >> +			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0893);
> > >> +		}
> > >> +
> > >> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0476, 0x58a0);
> > >> +
> > >> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x8921, 0xa3a);
> > >> +		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x89F1, 0x16c1);
> > >> +
> > >> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x0);
> > >> +		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0);
> > > 
> > > Please add macro with meaningful names for all the magic numbers used
> > > above, thanks!
> > > 
> > > Paolo
> > > 
> > 
> > Hello, these registers are not documented in the datasheet or errata sheet.
> > The access sequence comes 1-to-1 from the errata so I couldn't use macros.
> 
> Yes, we sometimes just have to accept the drivers are doing magic we
> have no idea about because the vendor does not want to tell is. All
> the registers in MDIO_MMD_VEND1 are clearly vendor specific. The
> MDIO_MMD_PMAPMD registers are also in the range reserved for
> vendors. So i think we just have to accept it.

+1

It can happen that vendors regard such information as IP that they do
not wish to disclose. Not saying that is the case here. Just saying
it is one reason that we sometimes have to accept such things.
So I think what you say above is completely reasonable.

> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> 
>     Andrew
>
diff mbox series

Patch

diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index 34231b5b9175..709d6c9f7cba 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -22,6 +22,11 @@ 
 #define PHY_ID_TJA_1103			0x001BB010
 #define PHY_ID_TJA_1120			0x001BB031
 
+#define VEND1_DEVICE_ID3		0x0004
+#define TJA1120_DEV_ID3_SILICON_VERSION	GENMASK(15, 12)
+#define TJA1120_DEV_ID3_SAMPLE_TYPE	GENMASK(11, 8)
+#define DEVICE_ID3_SAMPLE_TYPE_R	0x9
+
 #define VEND1_DEVICE_CONTROL		0x0040
 #define DEVICE_CONTROL_RESET		BIT(15)
 #define DEVICE_CONTROL_CONFIG_GLOBAL_EN	BIT(14)
@@ -1593,6 +1598,50 @@  static int nxp_c45_set_phy_mode(struct phy_device *phydev)
 	return 0;
 }
 
+/* Errata: ES_TJA1120 and ES_TJA1121 Rev. 1.0 — 28 November 2024 Section 3.1 */
+static void nxp_c45_tja1120_errata(struct phy_device *phydev)
+{
+	int silicon_version, sample_type;
+	bool macsec_ability;
+	int phy_abilities;
+	int ret = 0;
+
+	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_ID3);
+	if (ret < 0)
+		return;
+
+	sample_type = FIELD_GET(TJA1120_DEV_ID3_SAMPLE_TYPE, ret);
+	if (sample_type != DEVICE_ID3_SAMPLE_TYPE_R)
+		return;
+
+	silicon_version = FIELD_GET(TJA1120_DEV_ID3_SILICON_VERSION, ret);
+
+	phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+				     VEND1_PORT_ABILITIES);
+	macsec_ability = !!(phy_abilities & MACSEC_ABILITY);
+	if ((!macsec_ability && silicon_version == 2) ||
+	    (macsec_ability && silicon_version == 1)) {
+		/* TJA1120/TJA1121 PHY configuration errata workaround.
+		 * Apply PHY writes sequence before link up.
+		 */
+		if (!macsec_ability) {
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x4b95);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0xf3cd);
+		} else {
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x89c7);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0893);
+		}
+
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0476, 0x58a0);
+
+		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x8921, 0xa3a);
+		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x89F1, 0x16c1);
+
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 0x0);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 0x0);
+	}
+}
+
 static int nxp_c45_config_init(struct phy_device *phydev)
 {
 	int ret;
@@ -1609,6 +1658,9 @@  static int nxp_c45_config_init(struct phy_device *phydev)
 	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 1);
 	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 2);
 
+	if (phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, GENMASK(31, 4)))
+		nxp_c45_tja1120_errata(phydev);
+
 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG,
 			 PHY_CONFIG_AUTO);