diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
| -rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 153 | 
1 files changed, 123 insertions, 30 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 23c5fef2f1ad..dc6f8763a5d4 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -62,6 +62,8 @@  #include <linux/if_vlan.h>  #include <linux/pinctrl/consumer.h>  #include <linux/prefetch.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h>  #include <soc/imx/cpuidle.h>  #include <asm/cacheflush.h> @@ -84,6 +86,56 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);  #define FEC_ENET_OPD_V	0xFFF0  #define FEC_MDIO_PM_TIMEOUT  100 /* ms */ +struct fec_devinfo { +	u32 quirks; +	u8 stop_gpr_reg; +	u8 stop_gpr_bit; +}; + +static const struct fec_devinfo fec_imx25_info = { +	.quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR | +		  FEC_QUIRK_HAS_FRREG, +}; + +static const struct fec_devinfo fec_imx27_info = { +	.quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG, +}; + +static const struct fec_devinfo fec_imx28_info = { +	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | +		  FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC | +		  FEC_QUIRK_HAS_FRREG, +}; + +static const struct fec_devinfo fec_imx6q_info = { +	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | +		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | +		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 | +		  FEC_QUIRK_HAS_RACC, +	.stop_gpr_reg = 0x34, +	.stop_gpr_bit = 27, +}; + +static const struct fec_devinfo fec_mvf600_info = { +	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC, +}; + +static const struct fec_devinfo fec_imx6x_info = { +	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | +		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | +		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | +		  FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | +		  FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE, +}; + +static const struct fec_devinfo fec_imx6ul_info = { +	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | +		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | +		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 | +		  FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | +		  FEC_QUIRK_HAS_COALESCE, +}; +  static struct platform_device_id fec_devtype[] = {  	{  		/* keep it for coldfire */ @@ -91,39 +143,25 @@ static struct platform_device_id fec_devtype[] = {  		.driver_data = 0,  	}, {  		.name = "imx25-fec", -		.driver_data = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR | -			       FEC_QUIRK_HAS_FRREG, +		.driver_data = (kernel_ulong_t)&fec_imx25_info,  	}, {  		.name = "imx27-fec", -		.driver_data = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG, +		.driver_data = (kernel_ulong_t)&fec_imx27_info,  	}, {  		.name = "imx28-fec", -		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | -				FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC | -				FEC_QUIRK_HAS_FRREG, +		.driver_data = (kernel_ulong_t)&fec_imx28_info,  	}, {  		.name = "imx6q-fec", -		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | -				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | -				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 | -				FEC_QUIRK_HAS_RACC, +		.driver_data = (kernel_ulong_t)&fec_imx6q_info,  	}, {  		.name = "mvf600-fec", -		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC, +		.driver_data = (kernel_ulong_t)&fec_mvf600_info,  	}, {  		.name = "imx6sx-fec", -		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | -				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | -				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | -				FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | -				FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE, +		.driver_data = (kernel_ulong_t)&fec_imx6x_info,  	}, {  		.name = "imx6ul-fec", -		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | -				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | -				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 | -				FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | -				FEC_QUIRK_HAS_COALESCE, +		.driver_data = (kernel_ulong_t)&fec_imx6ul_info,  	}, {  		/* sentinel */  	} @@ -1092,11 +1130,28 @@ fec_restart(struct net_device *ndev)  } +static void fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled) +{ +	struct fec_platform_data *pdata = fep->pdev->dev.platform_data; +	struct fec_stop_mode_gpr *stop_gpr = &fep->stop_gpr; + +	if (stop_gpr->gpr) { +		if (enabled) +			regmap_update_bits(stop_gpr->gpr, stop_gpr->reg, +					   BIT(stop_gpr->bit), +					   BIT(stop_gpr->bit)); +		else +			regmap_update_bits(stop_gpr->gpr, stop_gpr->reg, +					   BIT(stop_gpr->bit), 0); +	} else if (pdata && pdata->sleep_mode_enable) { +		pdata->sleep_mode_enable(enabled); +	} +} +  static void  fec_stop(struct net_device *ndev)  {  	struct fec_enet_private *fep = netdev_priv(ndev); -	struct fec_platform_data *pdata = fep->pdev->dev.platform_data;  	u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);  	u32 val; @@ -1125,9 +1180,7 @@ fec_stop(struct net_device *ndev)  		val = readl(fep->hwp + FEC_ECNTRL);  		val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);  		writel(val, fep->hwp + FEC_ECNTRL); - -		if (pdata && pdata->sleep_mode_enable) -			pdata->sleep_mode_enable(true); +		fec_enet_stop_mode(fep, true);  	}  	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); @@ -2128,7 +2181,6 @@ static void fec_enet_get_drvinfo(struct net_device *ndev,  	strlcpy(info->driver, fep->pdev->dev.driver->name,  		sizeof(info->driver)); -	strlcpy(info->version, "Revision: 1.0", sizeof(info->version));  	strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info));  } @@ -2642,6 +2694,8 @@ fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)  }  static const struct ethtool_ops fec_enet_ethtool_ops = { +	.supported_coalesce_params = ETHTOOL_COALESCE_USECS | +				     ETHTOOL_COALESCE_MAX_FRAMES,  	.get_drvinfo		= fec_enet_get_drvinfo,  	.get_regs_len		= fec_enet_get_regs_len,  	.get_regs		= fec_enet_get_regs, @@ -3397,6 +3451,37 @@ static int fec_enet_get_irq_cnt(struct platform_device *pdev)  	return irq_cnt;  } +static int fec_enet_init_stop_mode(struct fec_enet_private *fep, +				   struct fec_devinfo *dev_info, +				   struct device_node *np) +{ +	struct device_node *gpr_np; +	int ret = 0; + +	if (!dev_info) +		return 0; + +	gpr_np = of_parse_phandle(np, "gpr", 0); +	if (!gpr_np) +		return 0; + +	fep->stop_gpr.gpr = syscon_node_to_regmap(gpr_np); +	if (IS_ERR(fep->stop_gpr.gpr)) { +		dev_err(&fep->pdev->dev, "could not find gpr regmap\n"); +		ret = PTR_ERR(fep->stop_gpr.gpr); +		fep->stop_gpr.gpr = NULL; +		goto out; +	} + +	fep->stop_gpr.reg = dev_info->stop_gpr_reg; +	fep->stop_gpr.bit = dev_info->stop_gpr_bit; + +out: +	of_node_put(gpr_np); + +	return ret; +} +  static int  fec_probe(struct platform_device *pdev)  { @@ -3412,6 +3497,7 @@ fec_probe(struct platform_device *pdev)  	int num_rx_qs;  	char irq_name[8];  	int irq_cnt; +	struct fec_devinfo *dev_info;  	fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs); @@ -3429,7 +3515,9 @@ fec_probe(struct platform_device *pdev)  	of_id = of_match_device(fec_dt_ids, &pdev->dev);  	if (of_id)  		pdev->id_entry = of_id->data; -	fep->quirks = pdev->id_entry->driver_data; +	dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data; +	if (dev_info) +		fep->quirks = dev_info->quirks;  	fep->netdev = ndev;  	fep->num_rx_queues = num_rx_qs; @@ -3463,6 +3551,10 @@ fec_probe(struct platform_device *pdev)  	if (of_get_property(np, "fsl,magic-packet", NULL))  		fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET; +	ret = fec_enet_init_stop_mode(fep, dev_info, np); +	if (ret) +		goto failed_stop_mode; +  	phy_node = of_parse_phandle(np, "phy-handle", 0);  	if (!phy_node && of_phy_is_fixed_link(np)) {  		ret = of_phy_register_fixed_link(np); @@ -3631,6 +3723,7 @@ failed_clk:  	if (of_phy_is_fixed_link(np))  		of_phy_deregister_fixed_link(np);  	of_node_put(phy_node); +failed_stop_mode:  failed_phy:  	dev_id--;  failed_ioremap: @@ -3708,7 +3801,6 @@ static int __maybe_unused fec_resume(struct device *dev)  {  	struct net_device *ndev = dev_get_drvdata(dev);  	struct fec_enet_private *fep = netdev_priv(ndev); -	struct fec_platform_data *pdata = fep->pdev->dev.platform_data;  	int ret;  	int val; @@ -3726,8 +3818,8 @@ static int __maybe_unused fec_resume(struct device *dev)  			goto failed_clk;  		}  		if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) { -			if (pdata && pdata->sleep_mode_enable) -				pdata->sleep_mode_enable(false); +			fec_enet_stop_mode(fep, false); +  			val = readl(fep->hwp + FEC_ECNTRL);  			val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);  			writel(val, fep->hwp + FEC_ECNTRL); @@ -3793,6 +3885,7 @@ static struct platform_driver fec_driver = {  		.name	= DRIVER_NAME,  		.pm	= &fec_pm_ops,  		.of_match_table = fec_dt_ids, +		.suppress_bind_attrs = true,  	},  	.id_table = fec_devtype,  	.probe	= fec_probe,  |