Commit 46b777ad authored by Raju Lakkaraju's avatar Raju Lakkaraju Committed by Jakub Kicinski

net: lan743x: Add support to SGMII 1G and 2.5G

Add SGMII access read and write functions
Add support to SGMII 1G and 2.5G for PCI11010/PCI11414 chips
Signed-off-by: default avatarRaju Lakkaraju <Raju.Lakkaraju@microchip.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 6b3768ac
......@@ -155,7 +155,7 @@ static int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset,
return 0;
}
static int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter,
int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter,
u16 timeout)
{
u16 timeout_cnt = 0;
......@@ -192,7 +192,7 @@ static int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter,
return 0;
}
static void lan743x_hs_syslock_release(struct lan743x_adapter *adapter)
void lan743x_hs_syslock_release(struct lan743x_adapter *adapter)
{
u32 val;
......
......@@ -22,20 +22,36 @@
#define MMD_ACCESS_WRITE 1
#define MMD_ACCESS_READ 2
#define MMD_ACCESS_READ_INC 3
#define PCS_POWER_STATE_DOWN 0x6
#define PCS_POWER_STATE_UP 0x4
static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
{
u32 chip_rev;
u32 cfg_load;
u32 hw_cfg;
u32 strap;
int ret;
/* Timeout = 100 (i.e. 1 sec (10 msce * 100)) */
ret = lan743x_hs_syslock_acquire(adapter, 100);
if (ret < 0) {
netif_err(adapter, drv, adapter->netdev,
"Sys Lock acquire failed ret:%d\n", ret);
return;
}
cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG);
lan743x_hs_syslock_release(adapter);
hw_cfg = lan743x_csr_read(adapter, HW_CFG);
if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ ||
hw_cfg & HW_CFG_RST_PROTECT_) {
strap = lan743x_csr_read(adapter, STRAP_READ);
if (strap & STRAP_READ_USE_SGMII_EN_) {
if (strap & STRAP_READ_SGMII_EN_)
adapter->is_sgmii_en = true;
else
adapter->is_sgmii_en = false;
netif_dbg(adapter, drv, adapter->netdev,
"STRAP_READ: 0x%08X\n", strap);
} else {
chip_rev = lan743x_csr_read(adapter, FPGA_REV);
if (chip_rev) {
......@@ -43,12 +59,12 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
adapter->is_sgmii_en = true;
else
adapter->is_sgmii_en = false;
netif_dbg(adapter, drv, adapter->netdev,
"FPGA_REV: 0x%08X\n", chip_rev);
} else {
adapter->is_sgmii_en = false;
}
}
netif_dbg(adapter, drv, adapter->netdev,
"SGMII I/F %sable\n", adapter->is_sgmii_en ? "En" : "Dis");
}
static bool is_pci11x1x_chip(struct lan743x_adapter *adapter)
......@@ -909,6 +925,318 @@ static int lan743x_mdiobus_c45_write(struct mii_bus *bus,
return ret;
}
static int lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter *adapter)
{
u32 data;
int ret;
ret = readx_poll_timeout(LAN743X_CSR_READ_OP, SGMII_ACC, data,
!(data & SGMII_ACC_SGMII_BZY_), 100, 1000000);
if (ret < 0)
netif_err(adapter, drv, adapter->netdev,
"%s: error %d sgmii wait timeout\n", __func__, ret);
return ret;
}
static int lan743x_sgmii_read(struct lan743x_adapter *adapter, u8 mmd, u16 addr)
{
u32 mmd_access;
int ret;
u32 val;
if (mmd > 31) {
netif_err(adapter, probe, adapter->netdev,
"%s mmd should <= 31\n", __func__);
return -EINVAL;
}
mutex_lock(&adapter->sgmii_rw_lock);
/* Load Register Address */
mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
mmd_access |= (addr | SGMII_ACC_SGMII_BZY_);
lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
ret = lan743x_sgmii_wait_till_not_busy(adapter);
if (ret < 0)
goto sgmii_unlock;
val = lan743x_csr_read(adapter, SGMII_DATA);
ret = (int)(val & SGMII_DATA_MASK_);
sgmii_unlock:
mutex_unlock(&adapter->sgmii_rw_lock);
return ret;
}
static int lan743x_sgmii_write(struct lan743x_adapter *adapter,
u8 mmd, u16 addr, u16 val)
{
u32 mmd_access;
int ret;
if (mmd > 31) {
netif_err(adapter, probe, adapter->netdev,
"%s mmd should <= 31\n", __func__);
return -EINVAL;
}
mutex_lock(&adapter->sgmii_rw_lock);
/* Load Register Data */
lan743x_csr_write(adapter, SGMII_DATA, (u32)(val & SGMII_DATA_MASK_));
/* Load Register Address */
mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
mmd_access |= (addr | SGMII_ACC_SGMII_BZY_ | SGMII_ACC_SGMII_WR_);
lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
ret = lan743x_sgmii_wait_till_not_busy(adapter);
mutex_unlock(&adapter->sgmii_rw_lock);
return ret;
}
static int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter,
u16 baud)
{
int mpllctrl0;
int mpllctrl1;
int miscctrl1;
int ret;
mpllctrl0 = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
VR_MII_GEN2_4_MPLL_CTRL0);
if (mpllctrl0 < 0)
return mpllctrl0;
mpllctrl0 &= ~VR_MII_MPLL_CTRL0_USE_REFCLK_PAD_;
if (baud == VR_MII_BAUD_RATE_1P25GBPS) {
mpllctrl1 = VR_MII_MPLL_MULTIPLIER_100;
/* mpll_baud_clk/4 */
miscctrl1 = 0xA;
} else {
mpllctrl1 = VR_MII_MPLL_MULTIPLIER_125;
/* mpll_baud_clk/2 */
miscctrl1 = 0x5;
}
ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
VR_MII_GEN2_4_MPLL_CTRL0, mpllctrl0);
if (ret < 0)
return ret;
ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
VR_MII_GEN2_4_MPLL_CTRL1, mpllctrl1);
if (ret < 0)
return ret;
return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
VR_MII_GEN2_4_MISC_CTRL1, miscctrl1);
}
static int lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter *adapter,
bool enable)
{
if (enable)
return lan743x_sgmii_mpll_set(adapter,
VR_MII_BAUD_RATE_3P125GBPS);
else
return lan743x_sgmii_mpll_set(adapter,
VR_MII_BAUD_RATE_1P25GBPS);
}
static int lan743x_is_sgmii_2_5G_mode(struct lan743x_adapter *adapter,
bool *status)
{
int ret;
ret = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
VR_MII_GEN2_4_MPLL_CTRL1);
if (ret < 0)
return ret;
if (ret == VR_MII_MPLL_MULTIPLIER_125 ||
ret == VR_MII_MPLL_MULTIPLIER_50)
*status = true;
else
*status = false;
return 0;
}
static int lan743x_sgmii_aneg_update(struct lan743x_adapter *adapter)
{
enum lan743x_sgmii_lsd lsd = adapter->sgmii_lsd;
int mii_ctrl;
int dgt_ctrl;
int an_ctrl;
int ret;
if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE)
/* Switch to 2.5 Gbps */
ret = lan743x_sgmii_2_5G_mode_set(adapter, true);
else
/* Switch to 10/100/1000 Mbps clock */
ret = lan743x_sgmii_2_5G_mode_set(adapter, false);
if (ret < 0)
return ret;
/* Enable SGMII Auto NEG */
mii_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
if (mii_ctrl < 0)
return mii_ctrl;
an_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, VR_MII_AN_CTRL);
if (an_ctrl < 0)
return an_ctrl;
dgt_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
VR_MII_DIG_CTRL1);
if (dgt_ctrl < 0)
return dgt_ctrl;
if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE) {
mii_ctrl &= ~(BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100);
mii_ctrl |= BMCR_SPEED1000;
dgt_ctrl |= VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
dgt_ctrl &= ~VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
/* In order for Auto-Negotiation to operate properly at
* 2.5 Gbps the 1.6ms link timer values must be adjusted
* The VR_MII_LINK_TIMER_CTRL Register must be set to
* 16'h7A1 and The CL37_TMR_OVR_RIDE bit of the
* VR_MII_DIG_CTRL1 Register set to 1
*/
ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
VR_MII_LINK_TIMER_CTRL, 0x7A1);
if (ret < 0)
return ret;
} else {
mii_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART);
an_ctrl &= ~VR_MII_AN_CTRL_SGMII_LINK_STS_;
dgt_ctrl &= ~VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
dgt_ctrl |= VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
}
ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR,
mii_ctrl);
if (ret < 0)
return ret;
ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
VR_MII_DIG_CTRL1, dgt_ctrl);
if (ret < 0)
return ret;
return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
VR_MII_AN_CTRL, an_ctrl);
}
static int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state)
{
u8 wait_cnt = 0;
u32 dig_sts;
do {
dig_sts = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
VR_MII_DIG_STS);
if (((dig_sts & VR_MII_DIG_STS_PSEQ_STATE_MASK_) >>
VR_MII_DIG_STS_PSEQ_STATE_POS_) == state)
break;
usleep_range(1000, 2000);
} while (wait_cnt++ < 10);
if (wait_cnt >= 10)
return -ETIMEDOUT;
return 0;
}
static int lan743x_sgmii_config(struct lan743x_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct phy_device *phydev = netdev->phydev;
enum lan743x_sgmii_lsd lsd = POWER_DOWN;
int mii_ctl;
bool status;
int ret;
switch (phydev->speed) {
case SPEED_2500:
if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER)
lsd = LINK_2500_MASTER;
else
lsd = LINK_2500_SLAVE;
break;
case SPEED_1000:
if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER)
lsd = LINK_1000_MASTER;
else
lsd = LINK_1000_SLAVE;
break;
case SPEED_100:
if (phydev->duplex)
lsd = LINK_100FD;
else
lsd = LINK_100HD;
break;
case SPEED_10:
if (phydev->duplex)
lsd = LINK_10FD;
else
lsd = LINK_10HD;
break;
default:
netif_err(adapter, drv, adapter->netdev,
"Invalid speed %d\n", phydev->speed);
return -EINVAL;
}
adapter->sgmii_lsd = lsd;
ret = lan743x_sgmii_aneg_update(adapter);
if (ret < 0) {
netif_err(adapter, drv, adapter->netdev,
"error %d SGMII cfg failed\n", ret);
return ret;
}
ret = lan743x_is_sgmii_2_5G_mode(adapter, &status);
if (ret < 0) {
netif_err(adapter, drv, adapter->netdev,
"erro %d SGMII get mode failed\n", ret);
return ret;
}
if (status)
netif_dbg(adapter, drv, adapter->netdev,
"SGMII 2.5G mode enable\n");
else
netif_dbg(adapter, drv, adapter->netdev,
"SGMII 1G mode enable\n");
/* SGMII/1000/2500BASE-X PCS power down */
mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
if (ret < 0)
return ret;
mii_ctl |= BMCR_PDOWN;
ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
if (ret < 0)
return ret;
ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_DOWN);
if (ret < 0)
return ret;
/* SGMII/1000/2500BASE-X PCS power up */
mii_ctl &= ~BMCR_PDOWN;
ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
if (ret < 0)
return ret;
ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP);
if (ret < 0)
return ret;
return 0;
}
static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
u8 *addr)
{
......@@ -1124,6 +1452,10 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
data |= MAC_CR_CFG_H_;
data &= ~MAC_CR_CFG_L_;
break;
case SPEED_2500:
data |= MAC_CR_CFG_H_;
data |= MAC_CR_CFG_L_;
break;
}
lan743x_csr_write(adapter, MAC_CR, data);
......@@ -1135,6 +1467,10 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
lan743x_phy_update_flowcontrol(adapter, local_advertisement,
remote_advertisement);
lan743x_ptp_update_latency(adapter, phydev->speed);
if (phydev->interface == PHY_INTERFACE_MODE_SGMII ||
phydev->interface == PHY_INTERFACE_MODE_1000BASEX ||
phydev->interface == PHY_INTERFACE_MODE_2500BASEX)
lan743x_sgmii_config(adapter);
}
}
......@@ -2875,6 +3211,7 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
pci11x1x_strap_get_status(adapter);
spin_lock_init(&adapter->eth_syslock_spinlock);
mutex_init(&adapter->sgmii_rw_lock);
} else {
adapter->max_tx_channels = LAN743X_MAX_TX_CHANNELS;
adapter->used_tx_channels = LAN743X_USED_TX_CHANNELS;
......
......@@ -97,6 +97,11 @@
#define CONFIG_REG_ADDR_BASE (0x0000)
#define ETH_EEPROM_REG_ADDR_BASE (0x0E00)
#define ETH_OTP_REG_ADDR_BASE (0x1000)
#define GEN_SYS_CONFIG_LOAD_STARTED_REG (0x0078)
#define ETH_SYS_CONFIG_LOAD_STARTED_REG (ETH_SYS_REG_ADDR_BASE + \
CONFIG_REG_ADDR_BASE + \
GEN_SYS_CONFIG_LOAD_STARTED_REG)
#define GEN_SYS_LOAD_STARTED_REG_ETH_ BIT(4)
#define SYS_LOCK_REG (0x00A0)
#define SYS_LOCK_REG_MAIN_LOCK_ BIT(7)
#define SYS_LOCK_REG_GEN_PERI_LOCK_ BIT(5)
......@@ -288,11 +293,82 @@
#define MAC_WUCSR2 (0x600)
#define SGMII_ACC (0x720)
#define SGMII_ACC_SGMII_BZY_ BIT(31)
#define SGMII_ACC_SGMII_WR_ BIT(30)
#define SGMII_ACC_SGMII_MMD_SHIFT_ (16)
#define SGMII_ACC_SGMII_MMD_MASK_ GENMASK(20, 16)
#define SGMII_ACC_SGMII_MMD_VSR_ BIT(15)
#define SGMII_ACC_SGMII_ADDR_SHIFT_ (0)
#define SGMII_ACC_SGMII_ADDR_MASK_ GENMASK(15, 0)
#define SGMII_DATA (0x724)
#define SGMII_DATA_SHIFT_ (0)
#define SGMII_DATA_MASK_ GENMASK(15, 0)
#define SGMII_CTL (0x728)
#define SGMII_CTL_SGMII_ENABLE_ BIT(31)
#define SGMII_CTL_LINK_STATUS_SOURCE_ BIT(8)
#define SGMII_CTL_SGMII_POWER_DN_ BIT(1)
/* Vendor Specific SGMII MMD details */
#define SR_VSMMD_PCS_ID1 0x0004
#define SR_VSMMD_PCS_ID2 0x0005
#define SR_VSMMD_STS 0x0008
#define SR_VSMMD_CTRL 0x0009
#define VR_MII_DIG_CTRL1 0x8000
#define VR_MII_DIG_CTRL1_VR_RST_ BIT(15)
#define VR_MII_DIG_CTRL1_R2TLBE_ BIT(14)
#define VR_MII_DIG_CTRL1_EN_VSMMD1_ BIT(13)
#define VR_MII_DIG_CTRL1_CS_EN_ BIT(10)
#define VR_MII_DIG_CTRL1_MAC_AUTO_SW_ BIT(9)
#define VR_MII_DIG_CTRL1_INIT_ BIT(8)
#define VR_MII_DIG_CTRL1_DTXLANED_0_ BIT(4)
#define VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_ BIT(3)
#define VR_MII_DIG_CTRL1_EN_2_5G_MODE_ BIT(2)
#define VR_MII_DIG_CTRL1_BYP_PWRUP_ BIT(1)
#define VR_MII_DIG_CTRL1_PHY_MODE_CTRL_ BIT(0)
#define VR_MII_AN_CTRL 0x8001
#define VR_MII_AN_CTRL_MII_CTRL_ BIT(8)
#define VR_MII_AN_CTRL_SGMII_LINK_STS_ BIT(4)
#define VR_MII_AN_CTRL_TX_CONFIG_ BIT(3)
#define VR_MII_AN_CTRL_1000BASE_X_ (0)
#define VR_MII_AN_CTRL_SGMII_MODE_ (2)
#define VR_MII_AN_CTRL_QSGMII_MODE_ (3)
#define VR_MII_AN_CTRL_PCS_MODE_SHIFT_ (1)
#define VR_MII_AN_CTRL_PCS_MODE_MASK_ GENMASK(2, 1)
#define VR_MII_AN_CTRL_MII_AN_INTR_EN_ BIT(0)
#define VR_MII_AN_INTR_STS 0x8002
#define VR_MII_AN_INTR_STS_LINK_UP_ BIT(4)
#define VR_MII_AN_INTR_STS_SPEED_MASK_ GENMASK(3, 2)
#define VR_MII_AN_INTR_STS_1000_MBPS_ BIT(3)
#define VR_MII_AN_INTR_STS_100_MBPS_ BIT(2)
#define VR_MII_AN_INTR_STS_10_MBPS_ (0)
#define VR_MII_AN_INTR_STS_FDX_ BIT(1)
#define VR_MII_AN_INTR_STS_CL37_ANCMPLT_INTR_ BIT(0)
#define VR_MII_LINK_TIMER_CTRL 0x800A
#define VR_MII_DIG_STS 0x8010
#define VR_MII_DIG_STS_PSEQ_STATE_MASK_ GENMASK(4, 2)
#define VR_MII_DIG_STS_PSEQ_STATE_POS_ (2)
#define VR_MII_GEN2_4_MPLL_CTRL0 0x8078
#define VR_MII_MPLL_CTRL0_REF_CLK_DIV2_ BIT(12)
#define VR_MII_MPLL_CTRL0_USE_REFCLK_PAD_ BIT(4)
#define VR_MII_GEN2_4_MPLL_CTRL1 0x8079
#define VR_MII_MPLL_CTRL1_MPLL_MULTIPLIER_ GENMASK(6, 0)
#define VR_MII_BAUD_RATE_3P125GBPS (3125)
#define VR_MII_BAUD_RATE_1P25GBPS (1250)
#define VR_MII_MPLL_MULTIPLIER_125 (125)
#define VR_MII_MPLL_MULTIPLIER_100 (100)
#define VR_MII_MPLL_MULTIPLIER_50 (50)
#define VR_MII_MPLL_MULTIPLIER_40 (40)
#define VR_MII_GEN2_4_MISC_CTRL1 0x809A
#define VR_MII_CTRL1_RX_RATE_0_MASK_ GENMASK(3, 2)
#define VR_MII_CTRL1_RX_RATE_0_SHIFT_ (2)
#define VR_MII_CTRL1_TX_RATE_0_MASK_ GENMASK(1, 0)
#define VR_MII_MPLL_BAUD_CLK (0)
#define VR_MII_MPLL_BAUD_CLK_DIV_2 (1)
#define VR_MII_MPLL_BAUD_CLK_DIV_4 (2)
#define INT_STS (0x780)
#define INT_BIT_DMA_RX_(channel) BIT(24 + (channel))
#define INT_BIT_ALL_RX_ (0x0F000000)
......@@ -914,6 +990,21 @@ struct lan743x_rx {
struct sk_buff *skb_head, *skb_tail;
};
/* SGMII Link Speed Duplex status */
enum lan743x_sgmii_lsd {
POWER_DOWN = 0,
LINK_DOWN,
ANEG_BUSY,
LINK_10HD,
LINK_10FD,
LINK_100HD,
LINK_100FD,
LINK_1000_MASTER,
LINK_1000_SLAVE,
LINK_2500_MASTER,
LINK_2500_SLAVE
};
struct lan743x_adapter {
struct net_device *netdev;
struct mii_bus *mdiobus;
......@@ -940,6 +1031,9 @@ struct lan743x_adapter {
spinlock_t eth_syslock_spinlock;
bool eth_syslock_en;
u32 eth_syslock_acquire_cnt;
struct mutex sgmii_rw_lock;
/* SGMII Link Speed & Duplex status */
enum lan743x_sgmii_lsd sgmii_lsd;
u8 max_tx_channels;
u8 used_tx_channels;
u8 max_vector_count;
......@@ -1059,5 +1153,7 @@ struct lan743x_rx_buffer_info {
u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset);
void lan743x_csr_write(struct lan743x_adapter *adapter, int offset, u32 data);
int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter, u16 timeout);
void lan743x_hs_syslock_release(struct lan743x_adapter *adapter);
#endif /* _LAN743X_H */
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