Commit 63caca1e authored by David S. Miller's avatar David S. Miller

Merge branch 'fec-next'

Joakim Zhang says:

====================
net: fec: add support for i.MX8MQ and i.MX8QM

This patch set adds supports for i.MX8MQ and i.MX8QM, both of them extend new features.

ChangeLogs:
V1->V2:
	* rebase on schema binding, and update dts compatible string.
	* use generic ethernet controller property for MAC internal RGMII clock delay
	  rx-internal-delay-ps and tx-internal-delay-ps
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 68f98848 987e1b96
...@@ -40,6 +40,24 @@ properties: ...@@ -40,6 +40,24 @@ properties:
- enum: - enum:
- fsl,imx7d-fec - fsl,imx7d-fec
- const: fsl,imx6sx-fec - const: fsl,imx6sx-fec
- items:
- const: fsl,imx8mq-fec
- const: fsl,imx6sx-fec
- items:
- enum:
- fsl,imx8mm-fec
- fsl,imx8mn-fec
- fsl,imx8mp-fec
- const: fsl,imx8mq-fec
- const: fsl,imx6sx-fec
- items:
- const: fsl,imx8qm-fec
- const: fsl,imx6sx-fec
- items:
- enum:
- fsl,imx8qxp-fec
- const: fsl,imx8qm-fec
- const: fsl,imx6sx-fec
reg: reg:
maxItems: 1 maxItems: 1
...@@ -78,6 +96,8 @@ properties: ...@@ -78,6 +96,8 @@ properties:
SOC internal PLL. SOC internal PLL.
The "enet_out"(option), output clock for external device, like supply clock The "enet_out"(option), output clock for external device, like supply clock
for PHY. The clock is required if PHY clock source from SOC. for PHY. The clock is required if PHY clock source from SOC.
The "enet_2x_txclk"(option), for RGMII sampling clock which fixed at 250Mhz.
The clock is required if SoC RGMII enable clock delay.
clock-names: clock-names:
minItems: 2 minItems: 2
...@@ -89,6 +109,7 @@ properties: ...@@ -89,6 +109,7 @@ properties:
- ptp - ptp
- enet_clk_ref - enet_clk_ref
- enet_out - enet_out
- enet_2x_txclk
phy-mode: true phy-mode: true
...@@ -100,6 +121,12 @@ properties: ...@@ -100,6 +121,12 @@ properties:
mac-address: true mac-address: true
tx-internal-delay-ps:
enum: [0, 2000]
rx-internal-delay-ps:
enum: [0, 2000]
phy-supply: phy-supply:
description: description:
Regulator that powers the Ethernet PHY. Regulator that powers the Ethernet PHY.
......
...@@ -920,7 +920,7 @@ sdma1: dma-controller@30bd0000 { ...@@ -920,7 +920,7 @@ sdma1: dma-controller@30bd0000 {
}; };
fec1: ethernet@30be0000 { fec1: ethernet@30be0000 {
compatible = "fsl,imx8mm-fec", "fsl,imx6sx-fec"; compatible = "fsl,imx8mm-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
reg = <0x30be0000 0x10000>; reg = <0x30be0000 0x10000>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
......
...@@ -923,7 +923,7 @@ sdma1: dma-controller@30bd0000 { ...@@ -923,7 +923,7 @@ sdma1: dma-controller@30bd0000 {
}; };
fec1: ethernet@30be0000 { fec1: ethernet@30be0000 {
compatible = "fsl,imx8mn-fec", "fsl,imx6sx-fec"; compatible = "fsl,imx8mn-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
reg = <0x30be0000 0x10000>; reg = <0x30be0000 0x10000>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
......
...@@ -17,9 +17,9 @@ &usdhc3 { ...@@ -17,9 +17,9 @@ &usdhc3 {
}; };
&fec1 { &fec1 {
compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec"; compatible = "fsl,imx8qxp-fec", "fsl,imx8qm-fec", "fsl,imx6sx-fec";
}; };
&fec2 { &fec2 {
compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec"; compatible = "fsl,imx8qxp-fec", "fsl,imx8qm-fec", "fsl,imx6sx-fec";
}; };
...@@ -77,6 +77,8 @@ ...@@ -77,6 +77,8 @@
#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */ #define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */
#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */ #define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */
#define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */ #define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */
#define FEC_LPI_SLEEP 0x1f4 /* Set IEEE802.3az LPI Sleep Ts time */
#define FEC_LPI_WAKE 0x1f8 /* Set IEEE802.3az LPI Wake Tw time */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */ #define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */ #define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
...@@ -379,6 +381,9 @@ struct bufdesc_ex { ...@@ -379,6 +381,9 @@ struct bufdesc_ex {
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF) #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF)
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF)) #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
#define FEC_ENET_TXC_DLY ((uint)0x00010000)
#define FEC_ENET_RXC_DLY ((uint)0x00020000)
/* ENET interrupt coalescing macro define */ /* ENET interrupt coalescing macro define */
#define FEC_ITR_CLK_SEL (0x1 << 30) #define FEC_ITR_CLK_SEL (0x1 << 30)
#define FEC_ITR_EN (0x1 << 31) #define FEC_ITR_EN (0x1 << 31)
...@@ -472,6 +477,19 @@ struct bufdesc_ex { ...@@ -472,6 +477,19 @@ struct bufdesc_ex {
*/ */
#define FEC_QUIRK_HAS_MULTI_QUEUES (1 << 19) #define FEC_QUIRK_HAS_MULTI_QUEUES (1 << 19)
/* i.MX8MQ ENET IP version add new feature to support IEEE 802.3az EEE
* standard. For the transmission, MAC supply two user registers to set
* Sleep (TS) and Wake (TW) time.
*/
#define FEC_QUIRK_HAS_EEE (1 << 20)
/* i.MX8QM ENET IP version add new feture to generate delayed TXC/RXC
* as an alternative option to make sure it works well with various PHYs.
* For the implementation of delayed clock, ENET takes synchronized 250MHz
* clocks to generate 2ns delay.
*/
#define FEC_QUIRK_DELAYED_CLKS_SUPPORT (1 << 21)
struct bufdesc_prop { struct bufdesc_prop {
int qid; int qid;
/* Address of Rx and Tx buffers */ /* Address of Rx and Tx buffers */
...@@ -528,6 +546,7 @@ struct fec_enet_private { ...@@ -528,6 +546,7 @@ struct fec_enet_private {
struct clk *clk_ref; struct clk *clk_ref;
struct clk *clk_enet_out; struct clk *clk_enet_out;
struct clk *clk_ptp; struct clk *clk_ptp;
struct clk *clk_2x_txclk;
bool ptp_clk_on; bool ptp_clk_on;
struct mutex ptp_clk_mutex; struct mutex ptp_clk_mutex;
...@@ -550,6 +569,8 @@ struct fec_enet_private { ...@@ -550,6 +569,8 @@ struct fec_enet_private {
uint phy_speed; uint phy_speed;
phy_interface_t phy_interface; phy_interface_t phy_interface;
struct device_node *phy_node; struct device_node *phy_node;
bool rgmii_txc_dly;
bool rgmii_rxc_dly;
int link; int link;
int full_duplex; int full_duplex;
int speed; int speed;
...@@ -589,6 +610,10 @@ struct fec_enet_private { ...@@ -589,6 +610,10 @@ struct fec_enet_private {
unsigned int tx_time_itr; unsigned int tx_time_itr;
unsigned int itr_clk_rate; unsigned int itr_clk_rate;
/* tx lpi eee mode */
struct ethtool_eee eee;
unsigned int clk_ref_rate;
u32 rx_copybreak; u32 rx_copybreak;
/* ptp clock period in ns*/ /* ptp clock period in ns*/
......
...@@ -135,6 +135,26 @@ static const struct fec_devinfo fec_imx6ul_info = { ...@@ -135,6 +135,26 @@ static const struct fec_devinfo fec_imx6ul_info = {
FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII, FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII,
}; };
static const struct fec_devinfo fec_imx8mq_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 |
FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
FEC_QUIRK_HAS_EEE,
};
static const struct fec_devinfo fec_imx8qm_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 |
FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
FEC_QUIRK_DELAYED_CLKS_SUPPORT,
};
static struct platform_device_id fec_devtype[] = { static struct platform_device_id fec_devtype[] = {
{ {
/* keep it for coldfire */ /* keep it for coldfire */
...@@ -161,6 +181,12 @@ static struct platform_device_id fec_devtype[] = { ...@@ -161,6 +181,12 @@ static struct platform_device_id fec_devtype[] = {
}, { }, {
.name = "imx6ul-fec", .name = "imx6ul-fec",
.driver_data = (kernel_ulong_t)&fec_imx6ul_info, .driver_data = (kernel_ulong_t)&fec_imx6ul_info,
}, {
.name = "imx8mq-fec",
.driver_data = (kernel_ulong_t)&fec_imx8mq_info,
}, {
.name = "imx8qm-fec",
.driver_data = (kernel_ulong_t)&fec_imx8qm_info,
}, { }, {
/* sentinel */ /* sentinel */
} }
...@@ -175,6 +201,8 @@ enum imx_fec_type { ...@@ -175,6 +201,8 @@ enum imx_fec_type {
MVF600_FEC, MVF600_FEC,
IMX6SX_FEC, IMX6SX_FEC,
IMX6UL_FEC, IMX6UL_FEC,
IMX8MQ_FEC,
IMX8QM_FEC,
}; };
static const struct of_device_id fec_dt_ids[] = { static const struct of_device_id fec_dt_ids[] = {
...@@ -185,6 +213,8 @@ static const struct of_device_id fec_dt_ids[] = { ...@@ -185,6 +213,8 @@ static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], }, { .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], }, { .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
{ .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], }, { .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], },
{ .compatible = "fsl,imx8mq-fec", .data = &fec_devtype[IMX8MQ_FEC], },
{ .compatible = "fsl,imx8qm-fec", .data = &fec_devtype[IMX8QM_FEC], },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, fec_dt_ids); MODULE_DEVICE_TABLE(of, fec_dt_ids);
...@@ -1107,6 +1137,13 @@ fec_restart(struct net_device *ndev) ...@@ -1107,6 +1137,13 @@ fec_restart(struct net_device *ndev)
if (fep->bufdesc_ex) if (fep->bufdesc_ex)
ecntl |= (1 << 4); ecntl |= (1 << 4);
if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
fep->rgmii_txc_dly)
ecntl |= FEC_ENET_TXC_DLY;
if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
fep->rgmii_rxc_dly)
ecntl |= FEC_ENET_RXC_DLY;
#ifndef CONFIG_M5272 #ifndef CONFIG_M5272
/* Enable the MIB statistic event counters */ /* Enable the MIB statistic event counters */
writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT); writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT);
...@@ -1970,6 +2007,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) ...@@ -1970,6 +2007,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
if (ret) if (ret)
goto failed_clk_ref; goto failed_clk_ref;
ret = clk_prepare_enable(fep->clk_2x_txclk);
if (ret)
goto failed_clk_2x_txclk;
fec_enet_phy_reset_after_clk_enable(ndev); fec_enet_phy_reset_after_clk_enable(ndev);
} else { } else {
clk_disable_unprepare(fep->clk_enet_out); clk_disable_unprepare(fep->clk_enet_out);
...@@ -1980,10 +2021,14 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) ...@@ -1980,10 +2021,14 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
mutex_unlock(&fep->ptp_clk_mutex); mutex_unlock(&fep->ptp_clk_mutex);
} }
clk_disable_unprepare(fep->clk_ref); clk_disable_unprepare(fep->clk_ref);
clk_disable_unprepare(fep->clk_2x_txclk);
} }
return 0; return 0;
failed_clk_2x_txclk:
if (fep->clk_ref)
clk_disable_unprepare(fep->clk_ref);
failed_clk_ref: failed_clk_ref:
if (fep->clk_ptp) { if (fep->clk_ptp) {
mutex_lock(&fep->ptp_clk_mutex); mutex_lock(&fep->ptp_clk_mutex);
...@@ -2692,6 +2737,92 @@ static int fec_enet_set_tunable(struct net_device *netdev, ...@@ -2692,6 +2737,92 @@ static int fec_enet_set_tunable(struct net_device *netdev,
return ret; return ret;
} }
/* LPI Sleep Ts count base on tx clk (clk_ref).
* The lpi sleep cnt value = X us / (cycle_ns).
*/
static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
{
struct fec_enet_private *fep = netdev_priv(ndev);
return us * (fep->clk_ref_rate / 1000) / 1000;
}
static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct ethtool_eee *p = &fep->eee;
unsigned int sleep_cycle, wake_cycle;
int ret = 0;
if (enable) {
ret = phy_init_eee(ndev->phydev, 0);
if (ret)
return ret;
sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
wake_cycle = sleep_cycle;
} else {
sleep_cycle = 0;
wake_cycle = 0;
}
p->tx_lpi_enabled = enable;
p->eee_enabled = enable;
p->eee_active = enable;
writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
return 0;
}
static int
fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct ethtool_eee *p = &fep->eee;
if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
return -EOPNOTSUPP;
if (!netif_running(ndev))
return -ENETDOWN;
edata->eee_enabled = p->eee_enabled;
edata->eee_active = p->eee_active;
edata->tx_lpi_timer = p->tx_lpi_timer;
edata->tx_lpi_enabled = p->tx_lpi_enabled;
return phy_ethtool_get_eee(ndev->phydev, edata);
}
static int
fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct ethtool_eee *p = &fep->eee;
int ret = 0;
if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
return -EOPNOTSUPP;
if (!netif_running(ndev))
return -ENETDOWN;
p->tx_lpi_timer = edata->tx_lpi_timer;
if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
!edata->tx_lpi_timer)
ret = fec_enet_eee_mode_set(ndev, false);
else
ret = fec_enet_eee_mode_set(ndev, true);
if (ret)
return ret;
return phy_ethtool_set_eee(ndev->phydev, edata);
}
static void static void
fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{ {
...@@ -2752,6 +2883,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = { ...@@ -2752,6 +2883,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.set_tunable = fec_enet_set_tunable, .set_tunable = fec_enet_set_tunable,
.get_wol = fec_enet_get_wol, .get_wol = fec_enet_get_wol,
.set_wol = fec_enet_set_wol, .set_wol = fec_enet_set_wol,
.get_eee = fec_enet_get_eee,
.set_eee = fec_enet_set_eee,
.get_link_ksettings = phy_ethtool_get_link_ksettings, .get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings,
.self_test = net_selftest, .self_test = net_selftest,
...@@ -3586,6 +3719,7 @@ fec_probe(struct platform_device *pdev) ...@@ -3586,6 +3719,7 @@ fec_probe(struct platform_device *pdev)
char irq_name[8]; char irq_name[8];
int irq_cnt; int irq_cnt;
struct fec_devinfo *dev_info; struct fec_devinfo *dev_info;
u32 rgmii_delay;
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs); fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
...@@ -3643,6 +3777,12 @@ fec_probe(struct platform_device *pdev) ...@@ -3643,6 +3777,12 @@ fec_probe(struct platform_device *pdev)
if (ret) if (ret)
goto failed_stop_mode; goto failed_stop_mode;
/* For rgmii internal delay, valid values are 0ps and 2000ps */
if (of_property_read_u32(np, "tx-internal-delay-ps", &rgmii_delay))
fep->rgmii_txc_dly = true;
if (of_property_read_u32(np, "rx-internal-delay-ps", &rgmii_delay))
fep->rgmii_rxc_dly = true;
phy_node = of_parse_phandle(np, "phy-handle", 0); phy_node = of_parse_phandle(np, "phy-handle", 0);
if (!phy_node && of_phy_is_fixed_link(np)) { if (!phy_node && of_phy_is_fixed_link(np)) {
ret = of_phy_register_fixed_link(np); ret = of_phy_register_fixed_link(np);
...@@ -3692,6 +3832,12 @@ fec_probe(struct platform_device *pdev) ...@@ -3692,6 +3832,12 @@ fec_probe(struct platform_device *pdev)
fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref"); fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
if (IS_ERR(fep->clk_ref)) if (IS_ERR(fep->clk_ref))
fep->clk_ref = NULL; fep->clk_ref = NULL;
fep->clk_ref_rate = clk_get_rate(fep->clk_ref);
/* clk_2x_txclk is optional, depends on board */
fep->clk_2x_txclk = devm_clk_get(&pdev->dev, "enet_2x_txclk");
if (IS_ERR(fep->clk_2x_txclk))
fep->clk_2x_txclk = NULL;
fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX; fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
......
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