diff mbox series

[net-next,v9,5/6] net: stmmac: configure SerDes according to the interface mode

Message ID 20250227121522.1802832-6-yong.liang.choong@linux.intel.com (mailing list archive)
State Accepted
Commit a42f6b3f1cc164781af144a71684d50b2d7d36f2
Delegated to: Netdev Maintainers
Headers show
Series Enable SGMII and 2500BASEX interface mode switching for Intel platforms | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -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 success CCed 11 of 11 maintainers
netdev/build_clang success Errors and warnings before: 1 this patch: 1
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 No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 5 this patch: 5
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2025-02-28--03-00 (tests: 894)

Commit Message

Choong Yong Liang Feb. 27, 2025, 12:15 p.m. UTC
Intel platform will configure the SerDes through PMC API based on the
provided interface mode.

This patch adds several new functions below:-
- intel_tsn_lane_is_available(): This new function reads FIA lane
  ownership registers and common lane registers through IPC commands
  to know which lane the mGbE port is assigned to.
- intel_mac_finish(): To configure the SerDes based on the assigned
  lane and latest interface mode, it sends IPC command to the PMC through
  PMC driver/API. The PMC acts as a proxy for R/W on behalf of the driver.
- intel_set_reg_access(): Set the register access to the available TSN
  interface.

Signed-off-by: Choong Yong Liang <yong.liang.choong@linux.intel.com>
---
 drivers/net/ethernet/stmicro/stmmac/Kconfig   |   1 +
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 179 +++++++++++++++++-
 .../net/ethernet/stmicro/stmmac/dwmac-intel.h |  29 +++
 3 files changed, 204 insertions(+), 5 deletions(-)

Comments

Andy Shevchenko March 6, 2025, 7:15 a.m. UTC | #1
Thu, Feb 27, 2025 at 08:15:21PM +0800, Choong Yong Liang kirjoitti:
> Intel platform will configure the SerDes through PMC API based on the
> provided interface mode.

> This patch adds several new functions below:-
> - intel_tsn_lane_is_available(): This new function reads FIA lane
>   ownership registers and common lane registers through IPC commands
>   to know which lane the mGbE port is assigned to.
> - intel_mac_finish(): To configure the SerDes based on the assigned
>   lane and latest interface mode, it sends IPC command to the PMC through
>   PMC driver/API. The PMC acts as a proxy for R/W on behalf of the driver.
> - intel_set_reg_access(): Set the register access to the available TSN
>   interface.

...

> config DWMAC_INTEL

>  	default X86
>  	depends on X86 && STMMAC_ETH && PCI
>  	depends on COMMON_CLK
> +	depends on ACPI

Stray and unexplained change. Please, fix it. We don't need the dependencies
which are not realised in the compile time.
Choong Yong Liang March 6, 2025, 8:39 a.m. UTC | #2
On 6/3/2025 3:15 pm, Andy Shevchenko wrote:
> Thu, Feb 27, 2025 at 08:15:21PM +0800, Choong Yong Liang kirjoitti:
>> Intel platform will configure the SerDes through PMC API based on the
>> provided interface mode.
>> This patch adds several new functions below:-
>> - intel_tsn_lane_is_available(): This new function reads FIA lane
>>    ownership registers and common lane registers through IPC commands
>>    to know which lane the mGbE port is assigned to.
>> - intel_mac_finish(): To configure the SerDes based on the assigned
>>    lane and latest interface mode, it sends IPC command to the PMC through
>>    PMC driver/API. The PMC acts as a proxy for R/W on behalf of the driver.
>> - intel_set_reg_access(): Set the register access to the available TSN
>>    interface.
> ...
> 
>> config DWMAC_INTEL
>>   	default X86
>>   	depends on X86 && STMMAC_ETH && PCI
>>   	depends on COMMON_CLK
>> +	depends on ACPI
> Stray and unexplained change. Please, fix it. We don't need the dependencies
> which are not realised in the compile time.
> 
> -- With Best Regards, Andy Shevchenko

Hi Andy,

The dependency on ACPI is necessary because the intel_pmc_ipc.h header 
relies on ACPI functionality to interact with the Intel PMC.
Andy Shevchenko March 6, 2025, 9:05 a.m. UTC | #3
On Thu, Mar 6, 2025 at 10:39 AM Choong Yong Liang
<yong.liang.choong@linux.intel.com> wrote:
> On 6/3/2025 3:15 pm, Andy Shevchenko wrote:
> > Thu, Feb 27, 2025 at 08:15:21PM +0800, Choong Yong Liang kirjoitti:

...

> >> config DWMAC_INTEL
> >>      default X86
> >>      depends on X86 && STMMAC_ETH && PCI
> >>      depends on COMMON_CLK
> >> +    depends on ACPI
> > Stray and unexplained change. Please, fix it. We don't need the dependencies
> > which are not realised in the compile time.
>
> The dependency on ACPI is necessary because the intel_pmc_ipc.h header
> relies on ACPI functionality to interact with the Intel PMC.

So, that header has to be fixed as ACPI here is really unneeded
dependency for the cases when somebody (for whatever reasons) want to
build a kernel without ACPI support but with the driver enabled for
let's say PCI device.
Choong Yong Liang March 6, 2025, 12:56 p.m. UTC | #4
On 6/3/2025 5:05 pm, Andy Shevchenko wrote:
> On Thu, Mar 6, 2025 at 10:39 AM Choong Yong Liang
> <yong.liang.choong@linux.intel.com> wrote:
>> On 6/3/2025 3:15 pm, Andy Shevchenko wrote:
>>> Thu, Feb 27, 2025 at 08:15:21PM +0800, Choong Yong Liang kirjoitti:
> ...
> 
>>>> config DWMAC_INTEL
>>>>       default X86
>>>>       depends on X86 && STMMAC_ETH && PCI
>>>>       depends on COMMON_CLK
>>>> +    depends on ACPI
>>> Stray and unexplained change. Please, fix it. We don't need the dependencies
>>> which are not realised in the compile time.
>> The dependency on ACPI is necessary because the intel_pmc_ipc.h header
>> relies on ACPI functionality to interact with the Intel PMC.
> So, that header has to be fixed as ACPI here is really unneeded
> dependency for the cases when somebody (for whatever reasons) want to
> build a kernel without ACPI support but with the driver enabled for
> let's say PCI device.
> 
> 
> -- With Best Regards, Andy Shevchenko

Hi Andy,

Thank you for your feedback, Andy.
I appreciate your insights regarding the ACPI dependency.
The intel_pmc_ipc.h header is under the ownership of David E Box, who 
focuses on the platform code, while my focus is on the netdev.

Hi David,

if you could kindly look into making the ACPI dependency optional in the 
intel_pmc_ipc.h header, it would be greatly appreciated.
I am more than willing to provide any support necessary to ensure a smooth 
resolution.

This patch series has already been accepted, but we recognize the 
importance of addressing this issue in the next patch series for upstream.
Our goal is to ensure that the driver can be compiled and function 
correctly in both ACPI and non-ACPI environments.

Thank you both for your understanding and collaboration.
David E. Box March 6, 2025, 8:52 p.m. UTC | #5
On Thu, 2025-03-06 at 20:56 +0800, Choong Yong Liang wrote:
> 
> 
> On 6/3/2025 5:05 pm, Andy Shevchenko wrote:
> > On Thu, Mar 6, 2025 at 10:39 AM Choong Yong Liang
> > <yong.liang.choong@linux.intel.com> wrote:
> > > On 6/3/2025 3:15 pm, Andy Shevchenko wrote:
> > > > Thu, Feb 27, 2025 at 08:15:21PM +0800, Choong Yong Liang kirjoitti:
> > ...
> > 
> > > > > config DWMAC_INTEL
> > > > >       default X86
> > > > >       depends on X86 && STMMAC_ETH && PCI
> > > > >       depends on COMMON_CLK
> > > > > +    depends on ACPI
> > > > Stray and unexplained change. Please, fix it. We don't need the
> > > > dependencies
> > > > which are not realised in the compile time.
> > > The dependency on ACPI is necessary because the intel_pmc_ipc.h header
> > > relies on ACPI functionality to interact with the Intel PMC.
> > So, that header has to be fixed as ACPI here is really unneeded
> > dependency for the cases when somebody (for whatever reasons) want to
> > build a kernel without ACPI support but with the driver enabled for
> > let's say PCI device.
> > 
> > 
> > -- With Best Regards, Andy Shevchenko
> 
> Hi Andy,
> 
> Thank you for your feedback, Andy.
> I appreciate your insights regarding the ACPI dependency.
> The intel_pmc_ipc.h header is under the ownership of David E Box, who 
> focuses on the platform code, while my focus is on the netdev.
> 
> Hi David,
> 
> if you could kindly look into making the ACPI dependency optional in the 
> intel_pmc_ipc.h header, it would be greatly appreciated.
> I am more than willing to provide any support necessary to ensure a smooth 
> resolution.

Choong you only need put the function under a #if CONFIG_ACPI block and provide
an alternative that returns an error when the code is not build. Like this,

#if CONFIG_ACPI
static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
*rbuf)
{
   ...
}
#else
static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
*rbuf) { return -ENODEV; }
#endif

David

> 
> This patch series has already been accepted, but we recognize the 
> importance of addressing this issue in the next patch series for upstream.
> Our goal is to ensure that the driver can be compiled and function 
> correctly in both ACPI and non-ACPI environments.
> 
> Thank you both for your understanding and collaboration.
Choong Yong Liang March 7, 2025, 5:28 a.m. UTC | #6
On 7/3/2025 4:52 am, David E. Box wrote:
> On Thu, 2025-03-06 at 20:56 +0800, Choong Yong Liang wrote:
>>
>>
>> On 6/3/2025 5:05 pm, Andy Shevchenko wrote:
>>> On Thu, Mar 6, 2025 at 10:39 AM Choong Yong Liang
>>> <yong.liang.choong@linux.intel.com> wrote:
>>>> On 6/3/2025 3:15 pm, Andy Shevchenko wrote:
>>>>> Thu, Feb 27, 2025 at 08:15:21PM +0800, Choong Yong Liang kirjoitti:
>>> ...
>>>
>>>>>> config DWMAC_INTEL
>>>>>>        default X86
>>>>>>        depends on X86 && STMMAC_ETH && PCI
>>>>>>        depends on COMMON_CLK
>>>>>> +    depends on ACPI
>>>>> Stray and unexplained change. Please, fix it. We don't need the
>>>>> dependencies
>>>>> which are not realised in the compile time.
>>>> The dependency on ACPI is necessary because the intel_pmc_ipc.h header
>>>> relies on ACPI functionality to interact with the Intel PMC.
>>> So, that header has to be fixed as ACPI here is really unneeded
>>> dependency for the cases when somebody (for whatever reasons) want to
>>> build a kernel without ACPI support but with the driver enabled for
>>> let's say PCI device.
>>>
>>>
>>> -- With Best Regards, Andy Shevchenko
>>
>> Hi Andy,
>>
>> Thank you for your feedback, Andy.
>> I appreciate your insights regarding the ACPI dependency.
>> The intel_pmc_ipc.h header is under the ownership of David E Box, who
>> focuses on the platform code, while my focus is on the netdev.
>>
>> Hi David,
>>
>> if you could kindly look into making the ACPI dependency optional in the
>> intel_pmc_ipc.h header, it would be greatly appreciated.
>> I am more than willing to provide any support necessary to ensure a smooth
>> resolution.
> 
> Choong you only need put the function under a #if CONFIG_ACPI block and provide
> an alternative that returns an error when the code is not build. Like this,
> 
> #if CONFIG_ACPI
> static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
> *rbuf)
> {
>     ...
> }
> #else
> static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
> *rbuf) { return -ENODEV; }
> #endif
> 
> David
> 
>>
>> This patch series has already been accepted, but we recognize the
>> importance of addressing this issue in the next patch series for upstream.
>> Our goal is to ensure that the driver can be compiled and function
>> correctly in both ACPI and non-ACPI environments.
>>
>> Thank you both for your understanding and collaboration.
> 
> 
Hi Andy and David,

Thank you for the feedback.

The current ACPI dependency for the config DWMAC_INTEL is necessary, but I 
agree on making it optional.

Implementing the suggestion from David using the "#if CONFIG_ACPI" approach 
would address your concern about users who need to build a kernel without 
ACPI support.

If you are okay with this approach, then I will submit the solution for 
upstream.
Andy Shevchenko March 7, 2025, 6:06 p.m. UTC | #7
On Fri, Mar 7, 2025 at 7:28 AM Choong Yong Liang
<yong.liang.choong@linux.intel.com> wrote:
> On 7/3/2025 4:52 am, David E. Box wrote:
> > On Thu, 2025-03-06 at 20:56 +0800, Choong Yong Liang wrote:
> >> On 6/3/2025 5:05 pm, Andy Shevchenko wrote:
> >>> On Thu, Mar 6, 2025 at 10:39 AM Choong Yong Liang
> >>> <yong.liang.choong@linux.intel.com> wrote:
> >>>> On 6/3/2025 3:15 pm, Andy Shevchenko wrote:
> >>>>> Thu, Feb 27, 2025 at 08:15:21PM +0800, Choong Yong Liang kirjoitti:

...

> >>>>>> config DWMAC_INTEL
> >>>>>>        default X86
> >>>>>>        depends on X86 && STMMAC_ETH && PCI
> >>>>>>        depends on COMMON_CLK
> >>>>>> +    depends on ACPI
> >>>>> Stray and unexplained change. Please, fix it. We don't need the
> >>>>> dependencies
> >>>>> which are not realised in the compile time.
> >>>> The dependency on ACPI is necessary because the intel_pmc_ipc.h header
> >>>> relies on ACPI functionality to interact with the Intel PMC.
> >>> So, that header has to be fixed as ACPI here is really unneeded
> >>> dependency for the cases when somebody (for whatever reasons) want to
> >>> build a kernel without ACPI support but with the driver enabled for
> >>> let's say PCI device.

> >> Thank you for your feedback, Andy.
> >> I appreciate your insights regarding the ACPI dependency.
> >> The intel_pmc_ipc.h header is under the ownership of David E Box, who
> >> focuses on the platform code, while my focus is on the netdev.
> >>
> >> if you could kindly look into making the ACPI dependency optional in the
> >> intel_pmc_ipc.h header, it would be greatly appreciated.
> >> I am more than willing to provide any support necessary to ensure a smooth
> >> resolution.
> >
> > Choong you only need put the function under a #if CONFIG_ACPI block and provide
> > an alternative that returns an error when the code is not build. Like this,
> >
> > #if CONFIG_ACPI
> > static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
> > *rbuf)
> > {
> >     ...
> > }
> > #else
> > static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
> > *rbuf) { return -ENODEV; }
> > #endif
> >
> >> This patch series has already been accepted, but we recognize the
> >> importance of addressing this issue in the next patch series for upstream.
> >> Our goal is to ensure that the driver can be compiled and function
> >> correctly in both ACPI and non-ACPI environments.
> >>
> >> Thank you both for your understanding and collaboration.

> The current ACPI dependency for the config DWMAC_INTEL is necessary,

I can argue on this. The driver worked without problems on the cases I
explained, so the dependency introduced very recently and only for a
subset of the cases. What you probably wanted to say is that "the
dependency is needed to avoid compilation errors in CONFIG_ACPI=n
cases since the used API doesn't (yet) provide the necessary stubs".
With that being assumed I agree.

> but I
> agree on making it optional.
>
> Implementing the suggestion from David using the "#if CONFIG_ACPI" approach
> would address your concern about users who need to build a kernel without
> ACPI support.
>
> If you are okay with this approach, then I will submit the solution for
> upstream.

Yes, please do it as the ACPI dependency brings a few hundreds of
kilobytes into the kernel with a lot of possible unneeded stuff.
diff mbox series

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 4cc85a36a1ab..c5f94a67b3f2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -307,6 +307,7 @@  config DWMAC_INTEL
 	default X86
 	depends on X86 && STMMAC_ETH && PCI
 	depends on COMMON_CLK
+	depends on ACPI
 	help
 	  This selects the Intel platform specific bus support for the
 	  stmmac driver. This driver is used for Intel Quark/EHL/TGL.
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index 48acba5eb178..f73a48f98581 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -5,15 +5,30 @@ 
 #include <linux/clk-provider.h>
 #include <linux/pci.h>
 #include <linux/dmi.h>
+#include <linux/platform_data/x86/intel_pmc_ipc.h>
 #include "dwmac-intel.h"
 #include "dwmac4.h"
 #include "stmmac.h"
 #include "stmmac_ptp.h"
 
+struct pmc_serdes_regs {
+	u8 index;
+	u32 val;
+};
+
+struct pmc_serdes_reg_info {
+	const struct pmc_serdes_regs *regs;
+	u8 num_regs;
+};
+
 struct intel_priv_data {
 	int mdio_adhoc_addr;	/* mdio address for serdes & etc */
 	unsigned long crossts_adj;
 	bool is_pse;
+	const int *tsn_lane_regs;
+	int max_tsn_lane_regs;
+	struct pmc_serdes_reg_info pid_1g;
+	struct pmc_serdes_reg_info pid_2p5g;
 };
 
 /* This struct is used to associate PCI Function of MAC controller on a board,
@@ -35,6 +50,44 @@  struct stmmac_pci_info {
 	int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
 };
 
+static const struct pmc_serdes_regs pid_modphy3_1g_regs[] = {
+	{ PID_MODPHY3_B_MODPHY_PCR_LCPLL_DWORD0,	B_MODPHY_PCR_LCPLL_DWORD0_1G },
+	{ PID_MODPHY3_N_MODPHY_PCR_LCPLL_DWORD2,	N_MODPHY_PCR_LCPLL_DWORD2_1G },
+	{ PID_MODPHY3_N_MODPHY_PCR_LCPLL_DWORD7,	N_MODPHY_PCR_LCPLL_DWORD7_1G },
+	{ PID_MODPHY3_N_MODPHY_PCR_LPPLL_DWORD10,	N_MODPHY_PCR_LPPLL_DWORD10_1G },
+	{ PID_MODPHY3_N_MODPHY_PCR_CMN_ANA_DWORD30,	N_MODPHY_PCR_CMN_ANA_DWORD30_1G },
+	{}
+};
+
+static const struct pmc_serdes_regs pid_modphy3_2p5g_regs[] = {
+	{ PID_MODPHY3_B_MODPHY_PCR_LCPLL_DWORD0,	B_MODPHY_PCR_LCPLL_DWORD0_2P5G },
+	{ PID_MODPHY3_N_MODPHY_PCR_LCPLL_DWORD2,	N_MODPHY_PCR_LCPLL_DWORD2_2P5G },
+	{ PID_MODPHY3_N_MODPHY_PCR_LCPLL_DWORD7,	N_MODPHY_PCR_LCPLL_DWORD7_2P5G },
+	{ PID_MODPHY3_N_MODPHY_PCR_LPPLL_DWORD10,	N_MODPHY_PCR_LPPLL_DWORD10_2P5G },
+	{ PID_MODPHY3_N_MODPHY_PCR_CMN_ANA_DWORD30,	N_MODPHY_PCR_CMN_ANA_DWORD30_2P5G },
+	{}
+};
+
+static const struct pmc_serdes_regs pid_modphy1_1g_regs[] = {
+	{ PID_MODPHY1_B_MODPHY_PCR_LCPLL_DWORD0,	B_MODPHY_PCR_LCPLL_DWORD0_1G },
+	{ PID_MODPHY1_N_MODPHY_PCR_LCPLL_DWORD2,	N_MODPHY_PCR_LCPLL_DWORD2_1G },
+	{ PID_MODPHY1_N_MODPHY_PCR_LCPLL_DWORD7,	N_MODPHY_PCR_LCPLL_DWORD7_1G },
+	{ PID_MODPHY1_N_MODPHY_PCR_LPPLL_DWORD10,	N_MODPHY_PCR_LPPLL_DWORD10_1G },
+	{ PID_MODPHY1_N_MODPHY_PCR_CMN_ANA_DWORD30,	N_MODPHY_PCR_CMN_ANA_DWORD30_1G },
+	{}
+};
+
+static const struct pmc_serdes_regs pid_modphy1_2p5g_regs[] = {
+	{ PID_MODPHY1_B_MODPHY_PCR_LCPLL_DWORD0,	B_MODPHY_PCR_LCPLL_DWORD0_2P5G },
+	{ PID_MODPHY1_N_MODPHY_PCR_LCPLL_DWORD2,	N_MODPHY_PCR_LCPLL_DWORD2_2P5G },
+	{ PID_MODPHY1_N_MODPHY_PCR_LCPLL_DWORD7,	N_MODPHY_PCR_LCPLL_DWORD7_2P5G },
+	{ PID_MODPHY1_N_MODPHY_PCR_LPPLL_DWORD10,	N_MODPHY_PCR_LPPLL_DWORD10_2P5G },
+	{ PID_MODPHY1_N_MODPHY_PCR_CMN_ANA_DWORD30,	N_MODPHY_PCR_CMN_ANA_DWORD30_2P5G },
+	{}
+};
+
+static const int ehl_tsn_lane_regs[] = {7, 8, 9, 10, 11};
+
 static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
 				    const struct dmi_system_id *dmi_list)
 {
@@ -93,7 +146,7 @@  static int intel_serdes_powerup(struct net_device *ndev, void *priv_data)
 	data &= ~SERDES_RATE_MASK;
 	data &= ~SERDES_PCLK_MASK;
 
-	if (priv->plat->max_speed == 2500)
+	if (priv->plat->phy_interface == PHY_INTERFACE_MODE_2500BASEX)
 		data |= SERDES_RATE_PCIE_GEN2 << SERDES_RATE_PCIE_SHIFT |
 			SERDES_PCLK_37p5MHZ << SERDES_PCLK_SHIFT;
 	else
@@ -415,6 +468,95 @@  static void intel_mgbe_pse_crossts_adj(struct intel_priv_data *intel_priv,
 	}
 }
 
+static int intel_tsn_lane_is_available(struct net_device *ndev,
+				       struct intel_priv_data *intel_priv)
+{
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	struct pmc_ipc_cmd tmp = {};
+	struct pmc_ipc_rbuf rbuf = {};
+	int ret = 0, i, j;
+	const int max_fia_regs = 5;
+
+	tmp.cmd = IPC_SOC_REGISTER_ACCESS;
+	tmp.sub_cmd = IPC_SOC_SUB_CMD_READ;
+
+	for (i = 0; i < max_fia_regs; i++) {
+		tmp.wbuf[0] = R_PCH_FIA_15_PCR_LOS1_REG_BASE + i;
+
+		ret = intel_pmc_ipc(&tmp, &rbuf);
+		if (ret < 0) {
+			netdev_info(priv->dev, "Failed to read from PMC.\n");
+			return ret;
+		}
+
+		for (j = 0; j <= intel_priv->max_tsn_lane_regs; j++)
+			if ((rbuf.buf[0] >>
+				(4 * (intel_priv->tsn_lane_regs[j] % 8)) &
+					B_PCH_FIA_PCR_L0O) == 0xB)
+				return ret;
+	}
+
+	return ret;
+}
+
+static int intel_set_reg_access(const struct pmc_serdes_regs *regs, int max_regs)
+{
+	int ret = 0, i;
+
+	for (i = 0; i < max_regs; i++) {
+		struct pmc_ipc_cmd tmp = {};
+		struct pmc_ipc_rbuf rbuf = {};
+
+		tmp.cmd = IPC_SOC_REGISTER_ACCESS;
+		tmp.sub_cmd = IPC_SOC_SUB_CMD_WRITE;
+		tmp.wbuf[0] = (u32)regs[i].index;
+		tmp.wbuf[1] = regs[i].val;
+
+		ret = intel_pmc_ipc(&tmp, &rbuf);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int intel_mac_finish(struct net_device *ndev,
+			    void *intel_data,
+			    unsigned int mode,
+			    phy_interface_t interface)
+{
+	struct intel_priv_data *intel_priv = intel_data;
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	const struct pmc_serdes_regs *regs;
+	int max_regs = 0;
+	int ret = 0;
+
+	ret = intel_tsn_lane_is_available(ndev, intel_priv);
+	if (ret < 0) {
+		netdev_info(priv->dev, "No TSN lane available to set the registers.\n");
+		return ret;
+	}
+
+	if (interface == PHY_INTERFACE_MODE_2500BASEX) {
+		regs = intel_priv->pid_2p5g.regs;
+		max_regs = intel_priv->pid_2p5g.num_regs;
+	} else {
+		regs = intel_priv->pid_1g.regs;
+		max_regs = intel_priv->pid_1g.num_regs;
+	}
+
+	ret = intel_set_reg_access(regs, max_regs);
+	if (ret < 0)
+		return ret;
+
+	priv->plat->phy_interface = interface;
+
+	intel_serdes_powerdown(ndev, intel_priv);
+	intel_serdes_powerup(ndev, intel_priv);
+
+	return ret;
+}
+
 static void common_default_data(struct plat_stmmacenet_data *plat)
 {
 	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
@@ -624,6 +766,8 @@  static int intel_mgbe_common_data(struct pci_dev *pdev,
 static int ehl_common_data(struct pci_dev *pdev,
 			   struct plat_stmmacenet_data *plat)
 {
+	struct intel_priv_data *intel_priv = plat->bsp_priv;
+
 	plat->rx_queues_to_use = 8;
 	plat->tx_queues_to_use = 8;
 	plat->flags |= STMMAC_FLAG_USE_PHY_WOL;
@@ -639,20 +783,29 @@  static int ehl_common_data(struct pci_dev *pdev,
 	plat->safety_feat_cfg->prtyen = 0;
 	plat->safety_feat_cfg->tmouten = 0;
 
+	intel_priv->tsn_lane_regs = ehl_tsn_lane_regs;
+	intel_priv->max_tsn_lane_regs = ARRAY_SIZE(ehl_tsn_lane_regs);
+
 	return intel_mgbe_common_data(pdev, plat);
 }
 
 static int ehl_sgmii_data(struct pci_dev *pdev,
 			  struct plat_stmmacenet_data *plat)
 {
+	struct intel_priv_data *intel_priv = plat->bsp_priv;
+
 	plat->bus_id = 1;
 	plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
-	plat->speed_mode_2500 = intel_speed_mode_2500;
 	plat->serdes_powerup = intel_serdes_powerup;
 	plat->serdes_powerdown = intel_serdes_powerdown;
-
+	plat->mac_finish = intel_mac_finish;
 	plat->clk_ptp_rate = 204800000;
 
+	intel_priv->pid_1g.regs = pid_modphy3_1g_regs;
+	intel_priv->pid_1g.num_regs = ARRAY_SIZE(pid_modphy3_1g_regs);
+	intel_priv->pid_2p5g.regs = pid_modphy3_2p5g_regs;
+	intel_priv->pid_2p5g.num_regs = ARRAY_SIZE(pid_modphy3_2p5g_regs);
+
 	return ehl_common_data(pdev, plat);
 }
 
@@ -705,10 +858,18 @@  static struct stmmac_pci_info ehl_pse0_rgmii1g_info = {
 static int ehl_pse0_sgmii1g_data(struct pci_dev *pdev,
 				 struct plat_stmmacenet_data *plat)
 {
+	struct intel_priv_data *intel_priv = plat->bsp_priv;
+
 	plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
-	plat->speed_mode_2500 = intel_speed_mode_2500;
 	plat->serdes_powerup = intel_serdes_powerup;
 	plat->serdes_powerdown = intel_serdes_powerdown;
+	plat->mac_finish = intel_mac_finish;
+
+	intel_priv->pid_1g.regs = pid_modphy1_1g_regs;
+	intel_priv->pid_1g.num_regs = ARRAY_SIZE(pid_modphy1_1g_regs);
+	intel_priv->pid_2p5g.regs = pid_modphy1_2p5g_regs;
+	intel_priv->pid_2p5g.num_regs = ARRAY_SIZE(pid_modphy1_2p5g_regs);
+
 	return ehl_pse0_common_data(pdev, plat);
 }
 
@@ -746,10 +907,18 @@  static struct stmmac_pci_info ehl_pse1_rgmii1g_info = {
 static int ehl_pse1_sgmii1g_data(struct pci_dev *pdev,
 				 struct plat_stmmacenet_data *plat)
 {
+	struct intel_priv_data *intel_priv = plat->bsp_priv;
+
 	plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
-	plat->speed_mode_2500 = intel_speed_mode_2500;
 	plat->serdes_powerup = intel_serdes_powerup;
 	plat->serdes_powerdown = intel_serdes_powerdown;
+	plat->mac_finish = intel_mac_finish;
+
+	intel_priv->pid_1g.regs = pid_modphy1_1g_regs;
+	intel_priv->pid_1g.num_regs = ARRAY_SIZE(pid_modphy1_1g_regs);
+	intel_priv->pid_2p5g.regs = pid_modphy1_2p5g_regs;
+	intel_priv->pid_2p5g.num_regs = ARRAY_SIZE(pid_modphy1_2p5g_regs);
+
 	return ehl_pse1_common_data(pdev, plat);
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
index 0a37987478c1..a12f8e65f89f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
@@ -50,4 +50,33 @@ 
 #define PCH_PTP_CLK_FREQ_19_2MHZ	(GMAC_GPO0)
 #define PCH_PTP_CLK_FREQ_200MHZ		(0)
 
+/* Modphy Register index */
+#define R_PCH_FIA_15_PCR_LOS1_REG_BASE			8
+#define R_PCH_FIA_15_PCR_LOS2_REG_BASE			9
+#define R_PCH_FIA_15_PCR_LOS3_REG_BASE			10
+#define R_PCH_FIA_15_PCR_LOS4_REG_BASE			11
+#define R_PCH_FIA_15_PCR_LOS5_REG_BASE			12
+#define B_PCH_FIA_PCR_L0O				GENMASK(3, 0)
+#define PID_MODPHY1_B_MODPHY_PCR_LCPLL_DWORD0		13
+#define PID_MODPHY1_N_MODPHY_PCR_LCPLL_DWORD2		14
+#define PID_MODPHY1_N_MODPHY_PCR_LCPLL_DWORD7		15
+#define PID_MODPHY1_N_MODPHY_PCR_LPPLL_DWORD10		16
+#define PID_MODPHY1_N_MODPHY_PCR_CMN_ANA_DWORD30	17
+#define PID_MODPHY3_B_MODPHY_PCR_LCPLL_DWORD0		18
+#define PID_MODPHY3_N_MODPHY_PCR_LCPLL_DWORD2		19
+#define PID_MODPHY3_N_MODPHY_PCR_LCPLL_DWORD7		20
+#define PID_MODPHY3_N_MODPHY_PCR_LPPLL_DWORD10		21
+#define PID_MODPHY3_N_MODPHY_PCR_CMN_ANA_DWORD30	22
+
+#define B_MODPHY_PCR_LCPLL_DWORD0_1G		0x46AAAA41
+#define N_MODPHY_PCR_LCPLL_DWORD2_1G		0x00000139
+#define N_MODPHY_PCR_LCPLL_DWORD7_1G		0x002A0003
+#define N_MODPHY_PCR_LPPLL_DWORD10_1G		0x00170008
+#define N_MODPHY_PCR_CMN_ANA_DWORD30_1G		0x0000D4AC
+#define B_MODPHY_PCR_LCPLL_DWORD0_2P5G		0x58555551
+#define N_MODPHY_PCR_LCPLL_DWORD2_2P5G		0x0000012D
+#define N_MODPHY_PCR_LCPLL_DWORD7_2P5G		0x001F0003
+#define N_MODPHY_PCR_LPPLL_DWORD10_2P5G		0x00170008
+#define N_MODPHY_PCR_CMN_ANA_DWORD30_2P5G	0x8200ACAC
+
 #endif /* __DWMAC_INTEL_H__ */