Commit 8e8fc62d authored by David S. Miller's avatar David S. Miller

Merge branch 'txgbe-link-modes'

Jiawen Wu says:

====================
support more link mode for TXGBE

There are three new interface mode support for Wangxun 10Gb NICs:
1000BASE-X, SGMII and XAUI.

Specific configurations are added to XPCS. And external PHY attaching
is added for copper NICs.

v2 -> v3:
- add device identifier read
- restrict pcs soft reset
- add firmware version warning

v1 -> v2:
- use the string "txgbe_pcs_mdio_bus" directly
- use dev_err() instead of pr_err()
- add device quirk flag
- add more macro definitions to explain PMA registers
- move txgbe_enable_sec_tx_path() to mac_finish()
- implement phylink for copper NICs
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1355fe13 ad63f7aa
...@@ -22925,6 +22925,7 @@ S: Maintained ...@@ -22925,6 +22925,7 @@ S: Maintained
W: https://www.net-swift.com W: https://www.net-swift.com
F: Documentation/networking/device_drivers/ethernet/wangxun/* F: Documentation/networking/device_drivers/ethernet/wangxun/*
F: drivers/net/ethernet/wangxun/ F: drivers/net/ethernet/wangxun/
F: drivers/net/pcs/pcs-xpcs-wx.c
WATCHDOG DEVICE DRIVERS WATCHDOG DEVICE DRIVERS
M: Wim Van Sebroeck <wim@linux-watchdog.org> M: Wim Van Sebroeck <wim@linux-watchdog.org>
......
...@@ -41,6 +41,7 @@ config TXGBE ...@@ -41,6 +41,7 @@ config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support" tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI depends on PCI
depends on COMMON_CLK depends on COMMON_CLK
select MARVELL_10G_PHY
select REGMAP select REGMAP
select I2C select I2C
select I2C_DESIGNWARE_PLATFORM select I2C_DESIGNWARE_PLATFORM
......
...@@ -205,6 +205,8 @@ ...@@ -205,6 +205,8 @@
#define WX_TSC_CTL 0x1D000 #define WX_TSC_CTL 0x1D000
#define WX_TSC_CTL_TX_DIS BIT(1) #define WX_TSC_CTL_TX_DIS BIT(1)
#define WX_TSC_CTL_TSEC_DIS BIT(0) #define WX_TSC_CTL_TSEC_DIS BIT(0)
#define WX_TSC_ST 0x1D004
#define WX_TSC_ST_SECTX_RDY BIT(0)
#define WX_TSC_BUF_AE 0x1D00C #define WX_TSC_BUF_AE 0x1D00C
#define WX_TSC_BUF_AE_THR GENMASK(9, 0) #define WX_TSC_BUF_AE_THR GENMASK(9, 0)
...@@ -231,6 +233,24 @@ ...@@ -231,6 +233,24 @@
#define WX_MAC_WDG_TIMEOUT 0x1100C #define WX_MAC_WDG_TIMEOUT 0x1100C
#define WX_MAC_RX_FLOW_CTRL 0x11090 #define WX_MAC_RX_FLOW_CTRL 0x11090
#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */ #define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */
/* MDIO Registers */
#define WX_MSCA 0x11200
#define WX_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
#define WX_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
#define WX_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
#define WX_MSCC 0x11204
#define WX_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
enum WX_MSCA_CMD_value {
WX_MSCA_CMD_RSV = 0,
WX_MSCA_CMD_WRITE,
WX_MSCA_CMD_POST_READ,
WX_MSCA_CMD_READ,
};
#define WX_MSCC_SADDR BIT(18)
#define WX_MSCC_BUSY BIT(22)
#define WX_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
#define WX_MMC_CONTROL 0x11800 #define WX_MMC_CONTROL 0x11800
#define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */ #define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */
...@@ -580,6 +600,13 @@ enum wx_mac_type { ...@@ -580,6 +600,13 @@ enum wx_mac_type {
wx_mac_em wx_mac_em
}; };
enum sp_media_type {
sp_media_unknown = 0,
sp_media_fiber,
sp_media_copper,
sp_media_backplane
};
enum em_mac_type { enum em_mac_type {
em_mac_type_unknown = 0, em_mac_type_unknown = 0,
em_mac_type_mdi, em_mac_type_mdi,
...@@ -827,6 +854,7 @@ struct wx { ...@@ -827,6 +854,7 @@ struct wx {
struct wx_bus_info bus; struct wx_bus_info bus;
struct wx_mac_info mac; struct wx_mac_info mac;
enum em_mac_type mac_type; enum em_mac_type mac_type;
enum sp_media_type media_type;
struct wx_eeprom_info eeprom; struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl; struct wx_addr_filter_info addr_ctrl;
struct wx_mac_addr *mac_table; struct wx_mac_addr *mac_table;
......
...@@ -37,24 +37,24 @@ static int ngbe_phy_read_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regn ...@@ -37,24 +37,24 @@ static int ngbe_phy_read_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF); wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */ /* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) | command = WX_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) | WX_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(device_type); WX_MSCA_DA(device_type);
wr32(wx, NGBE_MSCA, command); wr32(wx, WX_MSCA, command);
command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) | command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
NGBE_MSCC_BUSY | WX_MSCC_BUSY |
NGBE_MDIO_CLK(6); WX_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command); wr32(wx, WX_MSCC, command);
/* wait to complete */ /* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC); 100000, false, wx, WX_MSCC);
if (ret) { if (ret) {
wx_err(wx, "Mdio read c22 command did not complete.\n"); wx_err(wx, "Mdio read c22 command did not complete.\n");
return ret; return ret;
} }
return (u16)rd32(wx, NGBE_MSCC); return (u16)rd32(wx, WX_MSCC);
} }
static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regnum, u16 value) static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
...@@ -65,19 +65,19 @@ static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int reg ...@@ -65,19 +65,19 @@ static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int reg
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF); wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */ /* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) | command = WX_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) | WX_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(device_type); WX_MSCA_DA(device_type);
wr32(wx, NGBE_MSCA, command); wr32(wx, WX_MSCA, command);
command = value | command = value |
NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
NGBE_MSCC_BUSY | WX_MSCC_BUSY |
NGBE_MDIO_CLK(6); WX_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command); wr32(wx, WX_MSCC, command);
/* wait to complete */ /* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC); 100000, false, wx, WX_MSCC);
if (ret) if (ret)
wx_err(wx, "Mdio write c22 command did not complete.\n"); wx_err(wx, "Mdio write c22 command did not complete.\n");
...@@ -92,24 +92,24 @@ static int ngbe_phy_read_reg_mdi_c45(struct mii_bus *bus, int phy_addr, int devn ...@@ -92,24 +92,24 @@ static int ngbe_phy_read_reg_mdi_c45(struct mii_bus *bus, int phy_addr, int devn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0); wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */ /* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) | command = WX_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) | WX_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(devnum); WX_MSCA_DA(devnum);
wr32(wx, NGBE_MSCA, command); wr32(wx, WX_MSCA, command);
command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) | command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
NGBE_MSCC_BUSY | WX_MSCC_BUSY |
NGBE_MDIO_CLK(6); WX_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command); wr32(wx, WX_MSCC, command);
/* wait to complete */ /* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC); 100000, false, wx, WX_MSCC);
if (ret) { if (ret) {
wx_err(wx, "Mdio read c45 command did not complete.\n"); wx_err(wx, "Mdio read c45 command did not complete.\n");
return ret; return ret;
} }
return (u16)rd32(wx, NGBE_MSCC); return (u16)rd32(wx, WX_MSCC);
} }
static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr, static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
...@@ -121,19 +121,19 @@ static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr, ...@@ -121,19 +121,19 @@ static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0); wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */ /* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) | command = WX_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) | WX_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(devnum); WX_MSCA_DA(devnum);
wr32(wx, NGBE_MSCA, command); wr32(wx, WX_MSCA, command);
command = value | command = value |
NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
NGBE_MSCC_BUSY | WX_MSCC_BUSY |
NGBE_MDIO_CLK(6); WX_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command); wr32(wx, WX_MSCC, command);
/* wait to complete */ /* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC); 100000, false, wx, WX_MSCC);
if (ret) if (ret)
wx_err(wx, "Mdio write c45 command did not complete.\n"); wx_err(wx, "Mdio write c45 command did not complete.\n");
......
...@@ -59,25 +59,6 @@ ...@@ -59,25 +59,6 @@
#define NGBE_EEPROM_VERSION_L 0x1D #define NGBE_EEPROM_VERSION_L 0x1D
#define NGBE_EEPROM_VERSION_H 0x1E #define NGBE_EEPROM_VERSION_H 0x1E
/* mdio access */
#define NGBE_MSCA 0x11200
#define NGBE_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
#define NGBE_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
#define NGBE_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
#define NGBE_MSCC 0x11204
#define NGBE_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
enum NGBE_MSCA_CMD_value {
NGBE_MSCA_CMD_RSV = 0,
NGBE_MSCA_CMD_WRITE,
NGBE_MSCA_CMD_POST_READ,
NGBE_MSCA_CMD_READ,
};
#define NGBE_MSCC_SADDR BIT(18)
#define NGBE_MSCC_BUSY BIT(22)
#define NGBE_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
/* Media-dependent registers. */ /* Media-dependent registers. */
#define NGBE_MDIO_CLAUSE_SELECT 0x11220 #define NGBE_MDIO_CLAUSE_SELECT 0x11220
......
...@@ -13,6 +13,34 @@ ...@@ -13,6 +13,34 @@
#include "txgbe_type.h" #include "txgbe_type.h"
#include "txgbe_hw.h" #include "txgbe_hw.h"
/**
* txgbe_disable_sec_tx_path - Stops the transmit data path
* @wx: pointer to hardware structure
*
* Stops the transmit data path and waits for the HW to internally empty
* the tx security block
**/
int txgbe_disable_sec_tx_path(struct wx *wx)
{
int val;
wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, WX_TSC_CTL_TX_DIS);
return read_poll_timeout(rd32, val, val & WX_TSC_ST_SECTX_RDY,
1000, 20000, false, wx, WX_TSC_ST);
}
/**
* txgbe_enable_sec_tx_path - Enables the transmit data path
* @wx: pointer to hardware structure
*
* Enables the transmit data path.
**/
void txgbe_enable_sec_tx_path(struct wx *wx)
{
wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, 0);
WX_WRITE_FLUSH(wx);
}
/** /**
* txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds * txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds
* @wx: pointer to hardware structure * @wx: pointer to hardware structure
...@@ -257,17 +285,20 @@ static void txgbe_reset_misc(struct wx *wx) ...@@ -257,17 +285,20 @@ static void txgbe_reset_misc(struct wx *wx)
int txgbe_reset_hw(struct wx *wx) int txgbe_reset_hw(struct wx *wx)
{ {
int status; int status;
u32 val;
/* Call adapter stop to disable tx/rx and clear interrupts */ /* Call adapter stop to disable tx/rx and clear interrupts */
status = wx_stop_adapter(wx); status = wx_stop_adapter(wx);
if (status != 0) if (status != 0)
return status; return status;
val = WX_MIS_RST_LAN_RST(wx->bus.func); if (wx->media_type != sp_media_copper) {
wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST)); u32 val;
WX_WRITE_FLUSH(wx);
usleep_range(10, 100); val = WX_MIS_RST_LAN_RST(wx->bus.func);
wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
WX_WRITE_FLUSH(wx);
usleep_range(10, 100);
}
status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func)); status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func));
if (status != 0) if (status != 0)
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#ifndef _TXGBE_HW_H_ #ifndef _TXGBE_HW_H_
#define _TXGBE_HW_H_ #define _TXGBE_HW_H_
int txgbe_disable_sec_tx_path(struct wx *wx);
void txgbe_enable_sec_tx_path(struct wx *wx);
int txgbe_read_pba_string(struct wx *wx, u8 *pba_num, u32 pba_num_size); int txgbe_read_pba_string(struct wx *wx, u8 *pba_num, u32 pba_num_size);
int txgbe_validate_eeprom_checksum(struct wx *wx, u16 *checksum_val); int txgbe_validate_eeprom_checksum(struct wx *wx, u16 *checksum_val);
int txgbe_reset_hw(struct wx *wx); int txgbe_reset_hw(struct wx *wx);
......
...@@ -300,6 +300,49 @@ static void txgbe_down(struct wx *wx) ...@@ -300,6 +300,49 @@ static void txgbe_down(struct wx *wx)
wx_clean_all_rx_rings(wx); wx_clean_all_rx_rings(wx);
} }
/**
* txgbe_init_type_code - Initialize the shared code
* @wx: pointer to hardware structure
**/
static void txgbe_init_type_code(struct wx *wx)
{
u8 device_type = wx->subsystem_device_id & 0xF0;
switch (wx->device_id) {
case TXGBE_DEV_ID_SP1000:
case TXGBE_DEV_ID_WX1820:
wx->mac.type = wx_mac_sp;
break;
default:
wx->mac.type = wx_mac_unknown;
break;
}
switch (device_type) {
case TXGBE_ID_SFP:
wx->media_type = sp_media_fiber;
break;
case TXGBE_ID_XAUI:
case TXGBE_ID_SGMII:
wx->media_type = sp_media_copper;
break;
case TXGBE_ID_KR_KX_KX4:
case TXGBE_ID_MAC_XAUI:
case TXGBE_ID_MAC_SGMII:
wx->media_type = sp_media_backplane;
break;
case TXGBE_ID_SFI_XAUI:
if (wx->bus.func == 0)
wx->media_type = sp_media_fiber;
else
wx->media_type = sp_media_copper;
break;
default:
wx->media_type = sp_media_unknown;
break;
}
}
/** /**
* txgbe_sw_init - Initialize general software structures (struct wx) * txgbe_sw_init - Initialize general software structures (struct wx)
* @wx: board private structure to initialize * @wx: board private structure to initialize
...@@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx) ...@@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx)
return err; return err;
} }
switch (wx->device_id) { txgbe_init_type_code(wx);
case TXGBE_DEV_ID_SP1000:
case TXGBE_DEV_ID_WX1820:
wx->mac.type = wx_mac_sp;
break;
default:
wx->mac.type = wx_mac_unknown;
break;
}
/* Set common capability flags and settings */ /* Set common capability flags and settings */
wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS; wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;
...@@ -663,6 +698,9 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -663,6 +698,9 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id); "0x%08x", etrack_id);
} }
if (etrack_id < 0x20010)
dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL); txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
if (!txgbe) { if (!txgbe) {
err = -ENOMEM; err = -ENOMEM;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "../libwx/wx_hw.h" #include "../libwx/wx_hw.h"
#include "txgbe_type.h" #include "txgbe_type.h"
#include "txgbe_phy.h" #include "txgbe_phy.h"
#include "txgbe_hw.h"
static int txgbe_swnodes_register(struct txgbe *txgbe) static int txgbe_swnodes_register(struct txgbe *txgbe)
{ {
...@@ -160,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi ...@@ -160,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
{ {
struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev)); struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
return &txgbe->xpcs->pcs; if (interface == PHY_INTERFACE_MODE_10GBASER)
return &txgbe->xpcs->pcs;
return NULL;
} }
static void txgbe_mac_config(struct phylink_config *config, unsigned int mode, static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
...@@ -210,8 +214,32 @@ static void txgbe_mac_link_up(struct phylink_config *config, ...@@ -210,8 +214,32 @@ static void txgbe_mac_link_up(struct phylink_config *config,
wr32(wx, WX_MAC_WDG_TIMEOUT, wdg); wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
} }
static int txgbe_mac_prepare(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
struct wx *wx = netdev_priv(to_net_dev(config->dev));
wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
return txgbe_disable_sec_tx_path(wx);
}
static int txgbe_mac_finish(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
struct wx *wx = netdev_priv(to_net_dev(config->dev));
txgbe_enable_sec_tx_path(wx);
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
return 0;
}
static const struct phylink_mac_ops txgbe_mac_ops = { static const struct phylink_mac_ops txgbe_mac_ops = {
.mac_select_pcs = txgbe_phylink_mac_select, .mac_select_pcs = txgbe_phylink_mac_select,
.mac_prepare = txgbe_mac_prepare,
.mac_finish = txgbe_mac_finish,
.mac_config = txgbe_mac_config, .mac_config = txgbe_mac_config,
.mac_link_down = txgbe_mac_link_down, .mac_link_down = txgbe_mac_link_down,
.mac_link_up = txgbe_mac_link_up, .mac_link_up = txgbe_mac_link_up,
...@@ -219,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = { ...@@ -219,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = {
static int txgbe_phylink_init(struct txgbe *txgbe) static int txgbe_phylink_init(struct txgbe *txgbe)
{ {
struct fwnode_handle *fwnode = NULL;
struct phylink_config *config; struct phylink_config *config;
struct fwnode_handle *fwnode;
struct wx *wx = txgbe->wx; struct wx *wx = txgbe->wx;
phy_interface_t phy_mode; phy_interface_t phy_mode;
struct phylink *phylink; struct phylink *phylink;
...@@ -231,14 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe) ...@@ -231,14 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
config->dev = &wx->netdev->dev; config->dev = &wx->netdev->dev;
config->type = PHYLINK_NETDEV; config->type = PHYLINK_NETDEV;
config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE; config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
phy_mode = PHY_INTERFACE_MODE_10GBASER; MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]); if (wx->media_type == sp_media_copper) {
phy_mode = PHY_INTERFACE_MODE_XAUI;
__set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
} else {
phy_mode = PHY_INTERFACE_MODE_10GBASER;
fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
}
phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops); phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
if (IS_ERR(phylink)) if (IS_ERR(phylink))
return PTR_ERR(phylink); return PTR_ERR(phylink);
if (wx->phydev) {
int ret;
ret = phylink_connect_phy(phylink, wx->phydev);
if (ret) {
phylink_destroy(phylink);
return ret;
}
}
txgbe->phylink = phylink; txgbe->phylink = phylink;
return 0; return 0;
...@@ -431,7 +479,8 @@ static void txgbe_irq_handler(struct irq_desc *desc) ...@@ -431,7 +479,8 @@ static void txgbe_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);
if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN)) { if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
TXGBE_PX_MISC_ETH_AN)) {
u32 reg = rd32(wx, TXGBE_CFG_PORT_ST); u32 reg = rd32(wx, TXGBE_CFG_PORT_ST);
phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
...@@ -598,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe) ...@@ -598,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe)
return 0; return 0;
} }
static int txgbe_phy_read(struct mii_bus *bus, int phy_addr,
int devnum, int regnum)
{
struct wx *wx = bus->priv;
u32 val, command;
int ret;
/* setup and write the address cycle command */
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(devnum);
wr32(wx, WX_MSCA, command);
command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY;
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c45 command did not complete.\n");
return ret;
}
return (u16)rd32(wx, WX_MSCC);
}
static int txgbe_phy_write(struct mii_bus *bus, int phy_addr,
int devnum, int regnum, u16 value)
{
struct wx *wx = bus->priv;
int ret, command;
u16 val;
/* setup and write the address cycle command */
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(devnum);
wr32(wx, WX_MSCA, command);
command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY;
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c45 command did not complete.\n");
return ret;
}
static int txgbe_ext_phy_init(struct txgbe *txgbe)
{
struct phy_device *phydev;
struct mii_bus *mii_bus;
struct pci_dev *pdev;
struct wx *wx;
int ret = 0;
wx = txgbe->wx;
pdev = wx->pdev;
mii_bus = devm_mdiobus_alloc(&pdev->dev);
if (!mii_bus)
return -ENOMEM;
mii_bus->name = "txgbe_mii_bus";
mii_bus->read_c45 = &txgbe_phy_read;
mii_bus->write_c45 = &txgbe_phy_write;
mii_bus->parent = &pdev->dev;
mii_bus->phy_mask = GENMASK(31, 1);
mii_bus->priv = wx;
snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x",
(pdev->bus->number << 8) | pdev->devfn);
ret = devm_mdiobus_register(&pdev->dev, mii_bus);
if (ret) {
wx_err(wx, "failed to register MDIO bus: %d\n", ret);
return ret;
}
phydev = phy_find_first(mii_bus);
if (!phydev) {
wx_err(wx, "no PHY found\n");
return -ENODEV;
}
phy_attached_info(phydev);
wx->link = 0;
wx->speed = 0;
wx->duplex = 0;
wx->phydev = phydev;
ret = txgbe_phylink_init(txgbe);
if (ret) {
wx_err(wx, "failed to init phylink: %d\n", ret);
return ret;
}
return 0;
}
int txgbe_init_phy(struct txgbe *txgbe) int txgbe_init_phy(struct txgbe *txgbe)
{ {
int ret; int ret;
if (txgbe->wx->media_type == sp_media_copper)
return txgbe_ext_phy_init(txgbe);
ret = txgbe_swnodes_register(txgbe); ret = txgbe_swnodes_register(txgbe);
if (ret) { if (ret) {
wx_err(txgbe->wx, "failed to register software nodes\n"); wx_err(txgbe->wx, "failed to register software nodes\n");
...@@ -663,6 +819,12 @@ int txgbe_init_phy(struct txgbe *txgbe) ...@@ -663,6 +819,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
void txgbe_remove_phy(struct txgbe *txgbe) void txgbe_remove_phy(struct txgbe *txgbe)
{ {
if (txgbe->wx->media_type == sp_media_copper) {
phylink_disconnect_phy(txgbe->phylink);
phylink_destroy(txgbe->phylink);
return;
}
platform_device_unregister(txgbe->sfp_dev); platform_device_unregister(txgbe->sfp_dev);
platform_device_unregister(txgbe->i2c_dev); platform_device_unregister(txgbe->i2c_dev);
clkdev_drop(txgbe->clock); clkdev_drop(txgbe->clock);
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Makefile for Linux PCS drivers # Makefile for Linux PCS drivers
pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-wx.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
#include <linux/pcs/pcs-xpcs.h>
#include <linux/mdio.h>
#include "pcs-xpcs.h"
/* VR_XS_PMA_MMD */
#define TXGBE_PMA_MMD 0x8020
#define TXGBE_TX_GENCTL1 0x11
#define TXGBE_TX_GENCTL1_VBOOST_LVL GENMASK(10, 8)
#define TXGBE_TX_GENCTL1_VBOOST_EN0 BIT(4)
#define TXGBE_TX_GEN_CTL2 0x12
#define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
#define TXGBE_TX_RATE_CTL 0x14
#define TXGBE_TX_RATE_CTL_TX0_RATE(v) FIELD_PREP(GENMASK(2, 0), v)
#define TXGBE_RX_GEN_CTL2 0x32
#define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
#define TXGBE_RX_GEN_CTL3 0x33
#define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0 GENMASK(2, 0)
#define TXGBE_RX_RATE_CTL 0x34
#define TXGBE_RX_RATE_CTL_RX0_RATE(v) FIELD_PREP(GENMASK(1, 0), v)
#define TXGBE_RX_EQ_ATTN_CTL 0x37
#define TXGBE_RX_EQ_ATTN_LVL0 GENMASK(2, 0)
#define TXGBE_RX_EQ_CTL0 0x38
#define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v) FIELD_PREP(GENMASK(15, 12), v)
#define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v) FIELD_PREP(GENMASK(11, 8), v)
#define TXGBE_RX_EQ_CTL0_CTLE_POLE(v) FIELD_PREP(GENMASK(7, 5), v)
#define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v) FIELD_PREP(GENMASK(4, 0), v)
#define TXGBE_RX_EQ_CTL4 0x3C
#define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0 BIT(4)
#define TXGBE_RX_EQ_CTL4_CONT_ADAPT0 BIT(0)
#define TXGBE_AFE_DFE_ENABLE 0x3D
#define TXGBE_DFE_EN_0 BIT(4)
#define TXGBE_AFE_EN_0 BIT(0)
#define TXGBE_DFE_TAP_CTL0 0x3E
#define TXGBE_MPLLA_CTL0 0x51
#define TXGBE_MPLLA_CTL2 0x53
#define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN BIT(10)
#define TXGBE_MPLLA_CTL2_DIV10_CLK_EN BIT(9)
#define TXGBE_MPLLA_CTL3 0x57
#define TXGBE_MISC_CTL0 0x70
#define TXGBE_MISC_CTL0_PLL BIT(15)
#define TXGBE_MISC_CTL0_CR_PARA_SEL BIT(14)
#define TXGBE_MISC_CTL0_RX_VREF(v) FIELD_PREP(GENMASK(12, 8), v)
#define TXGBE_VCO_CAL_LD0 0x72
#define TXGBE_VCO_CAL_REF0 0x76
static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg)
{
return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg);
}
static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)
{
return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val);
}
static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)
{
int val;
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21);
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0);
val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549);
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29);
txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0);
txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0);
txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3));
txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3));
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN |
TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) |
TXGBE_RX_EQ_CTL0_CTLE_BOOST(5));
val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
val &= ~TXGBE_RX_EQ_ATTN_LVL0;
txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE);
val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE);
val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0);
txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val);
val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4);
val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0;
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val);
}
static void txgbe_pma_config_1g(struct dw_xpcs *xpcs)
{
int val;
val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0;
txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) |
TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6));
val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
val &= ~TXGBE_RX_EQ_ATTN_LVL0;
txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0);
val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3);
val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0);
txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20);
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46);
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540);
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A);
txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0);
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0);
txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3));
txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3));
txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1));
txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1));
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
}
static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs)
{
int val, ret;
/* Wait xpcs power-up good */
ret = read_poll_timeout(xpcs_read_vpcs, val,
(val & DW_PSEQ_ST) == DW_PSEQ_ST_GOOD,
10000, 1000000, false,
xpcs, DW_VR_XS_PCS_DIG_STS);
if (ret < 0)
dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n");
return ret;
}
static int txgbe_pma_init_done(struct dw_xpcs *xpcs)
{
int val, ret;
xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1);
/* wait pma initialization done */
ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST),
100000, 10000000, false,
xpcs, DW_VR_XS_PCS_DIG_CTRL1);
if (ret < 0)
dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n");
return ret;
}
static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)
{
int ret;
/* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */
ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);
ret &= MDIO_PCS_CTRL2_TYPE;
if ((ret == MDIO_PCS_CTRL2_10GBR &&
xpcs->interface != PHY_INTERFACE_MODE_10GBASER) ||
xpcs->interface == PHY_INTERFACE_MODE_SGMII)
return true;
return false;
}
int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
{
int val, ret;
switch (interface) {
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
break;
default:
return 0;
}
if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs))
return 0;
xpcs->interface = interface;
ret = txgbe_pcs_poll_power_up(xpcs);
if (ret < 0)
return ret;
if (interface == PHY_INTERFACE_MODE_10GBASER) {
xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR);
val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1);
val |= MDIO_CTRL1_SPEED10G;
xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val);
txgbe_pma_config_10gbaser(xpcs);
} else {
xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX);
xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0);
xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0);
txgbe_pma_config_1g(xpcs);
}
return txgbe_pma_init_done(xpcs);
}
...@@ -228,16 +228,39 @@ static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg, ...@@ -228,16 +228,39 @@ static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
return xpcs_write(xpcs, dev, DW_VENDOR | reg, val); return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
} }
static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg) int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
{ {
return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg); return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
} }
static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val) int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
{ {
return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val); return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
} }
static int xpcs_dev_flag(struct dw_xpcs *xpcs)
{
int ret, oui;
ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID1);
if (ret < 0)
return ret;
oui = ret;
ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
if (ret < 0)
return ret;
ret = (ret >> 10) & 0x3F;
oui |= ret << 16;
if (oui == DW_OUI_WX)
xpcs->dev_flag = DW_DEV_TXGBE;
return 0;
}
static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev) static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
{ {
/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
...@@ -660,7 +683,10 @@ EXPORT_SYMBOL_GPL(xpcs_config_eee); ...@@ -660,7 +683,10 @@ EXPORT_SYMBOL_GPL(xpcs_config_eee);
static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
unsigned int neg_mode) unsigned int neg_mode)
{ {
int ret, mdio_ctrl; int ret, mdio_ctrl, tx_conf;
if (xpcs->dev_flag == DW_DEV_TXGBE)
xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
/* For AN for C37 SGMII mode, the settings are :- /* For AN for C37 SGMII mode, the settings are :-
* 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case * 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
...@@ -697,9 +723,15 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, ...@@ -697,9 +723,15 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
ret |= (DW_VR_MII_PCS_MODE_C37_SGMII << ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT & DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
DW_VR_MII_PCS_MODE_MASK); DW_VR_MII_PCS_MODE_MASK);
ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII << if (xpcs->dev_flag == DW_DEV_TXGBE) {
DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT & ret |= DW_VR_MII_AN_CTRL_8BIT;
DW_VR_MII_TX_CONFIG_MASK); /* Hardware requires it to be PHY side SGMII */
tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII;
} else {
tx_conf = DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII;
}
ret |= tx_conf << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
DW_VR_MII_TX_CONFIG_MASK;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret); ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -713,6 +745,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, ...@@ -713,6 +745,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
else else
ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
if (xpcs->dev_flag == DW_DEV_TXGBE)
ret |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret); ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -732,6 +767,9 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, ...@@ -732,6 +767,9 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
int ret, mdio_ctrl, adv; int ret, mdio_ctrl, adv;
bool changed = 0; bool changed = 0;
if (xpcs->dev_flag == DW_DEV_TXGBE)
xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
/* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
* be disabled first:- * be disabled first:-
* 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
...@@ -753,6 +791,8 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, ...@@ -753,6 +791,8 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
return ret; return ret;
ret &= ~DW_VR_MII_PCS_MODE_MASK; ret &= ~DW_VR_MII_PCS_MODE_MASK;
if (!xpcs->pcs.poll)
ret |= DW_VR_MII_AN_INTR_EN;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret); ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -818,6 +858,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, ...@@ -818,6 +858,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
if (!compat) if (!compat)
return -ENODEV; return -ENODEV;
if (xpcs->dev_flag == DW_DEV_TXGBE) {
ret = txgbe_xpcs_switch_mode(xpcs, interface);
if (ret)
return ret;
}
switch (compat->an_mode) { switch (compat->an_mode) {
case DW_10GBASER: case DW_10GBASER:
break; break;
...@@ -977,6 +1023,33 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, ...@@ -977,6 +1023,33 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
state->duplex = DUPLEX_FULL; state->duplex = DUPLEX_FULL;
else else
state->duplex = DUPLEX_HALF; state->duplex = DUPLEX_HALF;
} else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
int speed, duplex;
state->link = true;
speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
if (speed < 0)
return speed;
speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
if (speed == SGMII_SPEED_SS6)
state->speed = SPEED_1000;
else if (speed == SGMII_SPEED_SS13)
state->speed = SPEED_100;
else if (speed == 0)
state->speed = SPEED_10;
duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
if (duplex < 0)
return duplex;
if (duplex & DW_FULL_DUPLEX)
state->duplex = DUPLEX_FULL;
else if (duplex & DW_HALF_DUPLEX)
state->duplex = DUPLEX_HALF;
xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
} }
return 0; return 0;
...@@ -1000,6 +1073,17 @@ static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs, ...@@ -1000,6 +1073,17 @@ static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
if (bmsr < 0) if (bmsr < 0)
return bmsr; return bmsr;
/* Clear AN complete interrupt */
if (!xpcs->pcs.poll) {
int an_intr;
an_intr = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
if (an_intr & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
an_intr &= ~DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, an_intr);
}
}
phylink_mii_c22_pcs_decode_state(state, bmsr, lpa); phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
} }
...@@ -1284,16 +1368,20 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, ...@@ -1284,16 +1368,20 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
goto out; goto out;
} }
ret = xpcs_dev_flag(xpcs);
if (ret)
goto out;
xpcs->pcs.ops = &xpcs_phylink_ops; xpcs->pcs.ops = &xpcs_phylink_ops;
xpcs->pcs.neg_mode = true; xpcs->pcs.neg_mode = true;
if (compat->an_mode == DW_10GBASER)
return xpcs;
xpcs->pcs.poll = true; if (xpcs->dev_flag != DW_DEV_TXGBE) {
xpcs->pcs.poll = true;
ret = xpcs_soft_reset(xpcs, compat); ret = xpcs_soft_reset(xpcs, compat);
if (ret) if (ret)
goto out; goto out;
}
return xpcs; return xpcs;
} }
......
...@@ -15,8 +15,14 @@ ...@@ -15,8 +15,14 @@
/* VR_XS_PCS */ /* VR_XS_PCS */
#define DW_USXGMII_RST BIT(10) #define DW_USXGMII_RST BIT(10)
#define DW_USXGMII_EN BIT(9) #define DW_USXGMII_EN BIT(9)
#define DW_VR_XS_PCS_DIG_CTRL1 0x0000
#define DW_VR_RST BIT(15)
#define DW_EN_VSMMD1 BIT(13)
#define DW_CL37_BP BIT(12)
#define DW_VR_XS_PCS_DIG_STS 0x0010 #define DW_VR_XS_PCS_DIG_STS 0x0010
#define DW_RXFIFO_ERR GENMASK(6, 5) #define DW_RXFIFO_ERR GENMASK(6, 5)
#define DW_PSEQ_ST GENMASK(4, 2)
#define DW_PSEQ_ST_GOOD FIELD_PREP(GENMASK(4, 2), 0x4)
/* SR_MII */ /* SR_MII */
#define DW_USXGMII_FULL BIT(8) #define DW_USXGMII_FULL BIT(8)
...@@ -61,12 +67,14 @@ ...@@ -61,12 +67,14 @@
/* VR_MII_DIG_CTRL1 */ /* VR_MII_DIG_CTRL1 */
#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9) #define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
#define DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL BIT(0)
/* VR_MII_DIG_CTRL2 */ /* VR_MII_DIG_CTRL2 */
#define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4) #define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4)
#define DW_VR_MII_DIG_CTRL2_RX_POL_INV BIT(0) #define DW_VR_MII_DIG_CTRL2_RX_POL_INV BIT(0)
/* VR_MII_AN_CTRL */ /* VR_MII_AN_CTRL */
#define DW_VR_MII_AN_CTRL_8BIT BIT(8)
#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3 #define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
#define DW_VR_MII_TX_CONFIG_MASK BIT(3) #define DW_VR_MII_TX_CONFIG_MASK BIT(3)
#define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1 #define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1
...@@ -75,8 +83,10 @@ ...@@ -75,8 +83,10 @@
#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1) #define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
#define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0 #define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0
#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2 #define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
#define DW_VR_MII_AN_INTR_EN BIT(0)
/* VR_MII_AN_INTR_STS */ /* VR_MII_AN_INTR_STS */
#define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR BIT(0)
#define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1) #define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1)
#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2 #define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2
#define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2) #define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2)
...@@ -90,6 +100,10 @@ ...@@ -90,6 +100,10 @@
#define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */ #define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */
#define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */ #define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */
/* SR MII MMD AN Advertisement defines */
#define DW_HALF_DUPLEX BIT(6)
#define DW_FULL_DUPLEX BIT(5)
/* VR MII EEE Control 0 defines */ /* VR MII EEE Control 0 defines */
#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */ #define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */ #define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
...@@ -106,6 +120,9 @@ ...@@ -106,6 +120,9 @@
int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg); int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg);
int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val); int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg);
int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val);
int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs);
int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
...@@ -20,12 +20,20 @@ ...@@ -20,12 +20,20 @@
#define DW_AN_C37_1000BASEX 4 #define DW_AN_C37_1000BASEX 4
#define DW_10GBASER 5 #define DW_10GBASER 5
/* device vendor OUI */
#define DW_OUI_WX 0x0018fc80
/* dev_flag */
#define DW_DEV_TXGBE BIT(0)
struct xpcs_id; struct xpcs_id;
struct dw_xpcs { struct dw_xpcs {
struct mdio_device *mdiodev; struct mdio_device *mdiodev;
const struct xpcs_id *id; const struct xpcs_id *id;
struct phylink_pcs pcs; struct phylink_pcs pcs;
phy_interface_t interface;
int dev_flag;
}; };
int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface); int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment