mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
net: stmmac: configure SerDes according to the interface mode
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> Link: https://patch.msgid.link/20250227121522.1802832-6-yong.liang.choong@linux.intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
e654cfc718
commit
a42f6b3f1c
3 changed files with 204 additions and 5 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Add table
Reference in a new issue