Commit 443a2367 authored by Grygorii Strashko's avatar Grygorii Strashko Committed by David S. Miller

net: ti: icssg-prueth: am65x SR2.0 add 10M full duplex support

For AM65x SR2.0 it's required to enable IEP1 in raw 64bit mode which is
used by PRU FW to monitor the link and apply w/a for 10M link issue.
Note. No public errata available yet.

Without this w/a the PRU FW will stuck if link state changes under TX
traffic pressure.

Hence, add support for 10M full duplex for AM65x SR2.0:
 - add new IEP API to enable IEP, but without PTP support
 - add pdata quirk_10m_link_issue to enable 10M link issue w/a.
Signed-off-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: default avatarVignesh Raghavendra <vigneshr@ti.com>
Reviewed-by: default avatarRoger Quadros <rogerq@kernel.org>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Reviewed-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Signed-off-by: default avatarMD Danish Anwar <danishanwar@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 186734c1
...@@ -727,6 +727,32 @@ void icss_iep_put(struct icss_iep *iep) ...@@ -727,6 +727,32 @@ void icss_iep_put(struct icss_iep *iep)
} }
EXPORT_SYMBOL_GPL(icss_iep_put); EXPORT_SYMBOL_GPL(icss_iep_put);
void icss_iep_init_fw(struct icss_iep *iep)
{
/* start IEP for FW use in raw 64bit mode, no PTP support */
iep->clk_tick_time = iep->def_inc;
iep->cycle_time_ns = 0;
iep->ops = NULL;
iep->clockops_data = NULL;
icss_iep_set_default_inc(iep, iep->def_inc);
icss_iep_set_compensation_inc(iep, iep->def_inc);
icss_iep_set_compensation_count(iep, 0);
regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, iep->refclk_freq / 10); /* 100 ms pulse */
regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
if (iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT)
icss_iep_set_slow_compensation_count(iep, 0);
icss_iep_enable(iep);
icss_iep_settime(iep, 0);
}
EXPORT_SYMBOL_GPL(icss_iep_init_fw);
void icss_iep_exit_fw(struct icss_iep *iep)
{
icss_iep_disable(iep);
}
EXPORT_SYMBOL_GPL(icss_iep_exit_fw);
int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops, int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops,
void *clockops_data, u32 cycle_time_ns) void *clockops_data, u32 cycle_time_ns)
{ {
......
...@@ -35,5 +35,7 @@ int icss_iep_exit(struct icss_iep *iep); ...@@ -35,5 +35,7 @@ int icss_iep_exit(struct icss_iep *iep);
int icss_iep_get_count_low(struct icss_iep *iep); int icss_iep_get_count_low(struct icss_iep *iep);
int icss_iep_get_count_hi(struct icss_iep *iep); int icss_iep_get_count_hi(struct icss_iep *iep);
int icss_iep_get_ptp_clock_idx(struct icss_iep *iep); int icss_iep_get_ptp_clock_idx(struct icss_iep *iep);
void icss_iep_init_fw(struct icss_iep *iep);
void icss_iep_exit_fw(struct icss_iep *iep);
#endif /* __NET_TI_ICSS_IEP_H */ #endif /* __NET_TI_ICSS_IEP_H */
...@@ -210,6 +210,10 @@ void icssg_config_ipg(struct prueth_emac *emac) ...@@ -210,6 +210,10 @@ void icssg_config_ipg(struct prueth_emac *emac)
case SPEED_100: case SPEED_100:
icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M);
break; break;
case SPEED_10:
/* IPG for 10M is same as 100M */
icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M);
break;
default: default:
/* Other links speeds not supported */ /* Other links speeds not supported */
netdev_err(emac->ndev, "Unsupported link speed\n"); netdev_err(emac->ndev, "Unsupported link speed\n");
...@@ -440,6 +444,9 @@ void icssg_config_set_speed(struct prueth_emac *emac) ...@@ -440,6 +444,9 @@ void icssg_config_set_speed(struct prueth_emac *emac)
case SPEED_100: case SPEED_100:
fw_speed = FW_LINK_SPEED_100M; fw_speed = FW_LINK_SPEED_100M;
break; break;
case SPEED_10:
fw_speed = FW_LINK_SPEED_10M;
break;
default: default:
/* Other links speeds not supported */ /* Other links speeds not supported */
netdev_err(emac->ndev, "Unsupported link speed\n"); netdev_err(emac->ndev, "Unsupported link speed\n");
......
...@@ -1149,7 +1149,6 @@ static int emac_phy_connect(struct prueth_emac *emac) ...@@ -1149,7 +1149,6 @@ static int emac_phy_connect(struct prueth_emac *emac)
/* remove unsupported modes */ /* remove unsupported modes */
phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT); phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
...@@ -2090,13 +2089,29 @@ static int prueth_probe(struct platform_device *pdev) ...@@ -2090,13 +2089,29 @@ static int prueth_probe(struct platform_device *pdev)
goto free_pool; goto free_pool;
} }
prueth->iep1 = icss_iep_get_idx(np, 1);
if (IS_ERR(prueth->iep1)) {
ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n");
icss_iep_put(prueth->iep0);
prueth->iep0 = NULL;
prueth->iep1 = NULL;
goto free_pool;
}
if (prueth->pdata.quirk_10m_link_issue) {
/* Enable IEP1 for FW in 64bit mode as W/A for 10M FD link detect issue under TX
* traffic.
*/
icss_iep_init_fw(prueth->iep1);
}
/* setup netdev interfaces */ /* setup netdev interfaces */
if (eth0_node) { if (eth0_node) {
ret = prueth_netdev_init(prueth, eth0_node); ret = prueth_netdev_init(prueth, eth0_node);
if (ret) { if (ret) {
dev_err_probe(dev, ret, "netdev init %s failed\n", dev_err_probe(dev, ret, "netdev init %s failed\n",
eth0_node->name); eth0_node->name);
goto netdev_exit; goto exit_iep;
} }
prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; prueth->emac[PRUETH_MAC0]->iep = prueth->iep0;
} }
...@@ -2167,6 +2182,10 @@ static int prueth_probe(struct platform_device *pdev) ...@@ -2167,6 +2182,10 @@ static int prueth_probe(struct platform_device *pdev)
prueth_netdev_exit(prueth, eth_node); prueth_netdev_exit(prueth, eth_node);
} }
exit_iep:
if (prueth->pdata.quirk_10m_link_issue)
icss_iep_exit_fw(prueth->iep1);
free_pool: free_pool:
gen_pool_free(prueth->sram_pool, gen_pool_free(prueth->sram_pool,
(unsigned long)prueth->msmcram.va, msmc_ram_size); (unsigned long)prueth->msmcram.va, msmc_ram_size);
...@@ -2212,6 +2231,10 @@ static void prueth_remove(struct platform_device *pdev) ...@@ -2212,6 +2231,10 @@ static void prueth_remove(struct platform_device *pdev)
prueth_netdev_exit(prueth, eth_node); prueth_netdev_exit(prueth, eth_node);
} }
if (prueth->pdata.quirk_10m_link_issue)
icss_iep_exit_fw(prueth->iep1);
icss_iep_put(prueth->iep1);
icss_iep_put(prueth->iep0); icss_iep_put(prueth->iep0);
gen_pool_free(prueth->sram_pool, gen_pool_free(prueth->sram_pool,
......
...@@ -208,6 +208,7 @@ struct prueth_pdata { ...@@ -208,6 +208,7 @@ struct prueth_pdata {
* @icssg_hwcmdseq: seq counter or HWQ messages * @icssg_hwcmdseq: seq counter or HWQ messages
* @emacs_initialized: num of EMACs/ext ports that are up/running * @emacs_initialized: num of EMACs/ext ports that are up/running
* @iep0: pointer to IEP0 device * @iep0: pointer to IEP0 device
* @iep1: pointer to IEP1 device
*/ */
struct prueth { struct prueth {
struct device *dev; struct device *dev;
...@@ -231,6 +232,7 @@ struct prueth { ...@@ -231,6 +232,7 @@ struct prueth {
u8 icssg_hwcmdseq; u8 icssg_hwcmdseq;
int emacs_initialized; int emacs_initialized;
struct icss_iep *iep0; struct icss_iep *iep0;
struct icss_iep *iep1;
}; };
struct emac_tx_ts_response { struct emac_tx_ts_response {
......
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