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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
63caca1e3e
@ -40,6 +40,24 @@ properties:
|
||||
- enum:
|
||||
- fsl,imx7d-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:
|
||||
maxItems: 1
|
||||
@ -78,6 +96,8 @@ properties:
|
||||
SOC internal PLL.
|
||||
The "enet_out"(option), output clock for external device, like supply clock
|
||||
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:
|
||||
minItems: 2
|
||||
@ -89,6 +109,7 @@ properties:
|
||||
- ptp
|
||||
- enet_clk_ref
|
||||
- enet_out
|
||||
- enet_2x_txclk
|
||||
|
||||
phy-mode: true
|
||||
|
||||
@ -100,6 +121,12 @@ properties:
|
||||
|
||||
mac-address: true
|
||||
|
||||
tx-internal-delay-ps:
|
||||
enum: [0, 2000]
|
||||
|
||||
rx-internal-delay-ps:
|
||||
enum: [0, 2000]
|
||||
|
||||
phy-supply:
|
||||
description:
|
||||
Regulator that powers the Ethernet PHY.
|
||||
|
@ -920,7 +920,7 @@
|
||||
};
|
||||
|
||||
fec1: ethernet@30be0000 {
|
||||
compatible = "fsl,imx8mm-fec", "fsl,imx6sx-fec";
|
||||
compatible = "fsl,imx8mm-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
|
||||
reg = <0x30be0000 0x10000>;
|
||||
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
@ -923,7 +923,7 @@
|
||||
};
|
||||
|
||||
fec1: ethernet@30be0000 {
|
||||
compatible = "fsl,imx8mn-fec", "fsl,imx6sx-fec";
|
||||
compatible = "fsl,imx8mn-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
|
||||
reg = <0x30be0000 0x10000>;
|
||||
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
@ -17,9 +17,9 @@
|
||||
};
|
||||
|
||||
&fec1 {
|
||||
compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec";
|
||||
compatible = "fsl,imx8qxp-fec", "fsl,imx8qm-fec", "fsl,imx6sx-fec";
|
||||
};
|
||||
|
||||
&fec2 {
|
||||
compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec";
|
||||
compatible = "fsl,imx8qxp-fec", "fsl,imx8qm-fec", "fsl,imx6sx-fec";
|
||||
};
|
||||
|
@ -77,6 +77,8 @@
|
||||
#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_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_ENR 0x308 /* MIIGSK Enable reg */
|
||||
|
||||
@ -379,6 +381,9 @@ struct bufdesc_ex {
|
||||
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | 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 */
|
||||
#define FEC_ITR_CLK_SEL (0x1 << 30)
|
||||
#define FEC_ITR_EN (0x1 << 31)
|
||||
@ -472,6 +477,19 @@ struct bufdesc_ex {
|
||||
*/
|
||||
#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 {
|
||||
int qid;
|
||||
/* Address of Rx and Tx buffers */
|
||||
@ -528,6 +546,7 @@ struct fec_enet_private {
|
||||
struct clk *clk_ref;
|
||||
struct clk *clk_enet_out;
|
||||
struct clk *clk_ptp;
|
||||
struct clk *clk_2x_txclk;
|
||||
|
||||
bool ptp_clk_on;
|
||||
struct mutex ptp_clk_mutex;
|
||||
@ -550,6 +569,8 @@ struct fec_enet_private {
|
||||
uint phy_speed;
|
||||
phy_interface_t phy_interface;
|
||||
struct device_node *phy_node;
|
||||
bool rgmii_txc_dly;
|
||||
bool rgmii_rxc_dly;
|
||||
int link;
|
||||
int full_duplex;
|
||||
int speed;
|
||||
@ -589,6 +610,10 @@ struct fec_enet_private {
|
||||
unsigned int tx_time_itr;
|
||||
unsigned int itr_clk_rate;
|
||||
|
||||
/* tx lpi eee mode */
|
||||
struct ethtool_eee eee;
|
||||
unsigned int clk_ref_rate;
|
||||
|
||||
u32 rx_copybreak;
|
||||
|
||||
/* ptp clock period in ns*/
|
||||
|
@ -135,6 +135,26 @@ static const struct fec_devinfo fec_imx6ul_info = {
|
||||
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[] = {
|
||||
{
|
||||
/* keep it for coldfire */
|
||||
@ -161,6 +181,12 @@ static struct platform_device_id fec_devtype[] = {
|
||||
}, {
|
||||
.name = "imx6ul-fec",
|
||||
.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 */
|
||||
}
|
||||
@ -175,6 +201,8 @@ enum imx_fec_type {
|
||||
MVF600_FEC,
|
||||
IMX6SX_FEC,
|
||||
IMX6UL_FEC,
|
||||
IMX8MQ_FEC,
|
||||
IMX8QM_FEC,
|
||||
};
|
||||
|
||||
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,imx6sx-fec", .data = &fec_devtype[IMX6SX_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 */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fec_dt_ids);
|
||||
@ -1107,6 +1137,13 @@ fec_restart(struct net_device *ndev)
|
||||
if (fep->bufdesc_ex)
|
||||
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
|
||||
/* Enable the MIB statistic event counters */
|
||||
writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT);
|
||||
@ -1970,6 +2007,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
|
||||
if (ret)
|
||||
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);
|
||||
} else {
|
||||
clk_disable_unprepare(fep->clk_enet_out);
|
||||
@ -1980,10 +2021,14 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
|
||||
mutex_unlock(&fep->ptp_clk_mutex);
|
||||
}
|
||||
clk_disable_unprepare(fep->clk_ref);
|
||||
clk_disable_unprepare(fep->clk_2x_txclk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed_clk_2x_txclk:
|
||||
if (fep->clk_ref)
|
||||
clk_disable_unprepare(fep->clk_ref);
|
||||
failed_clk_ref:
|
||||
if (fep->clk_ptp) {
|
||||
mutex_lock(&fep->ptp_clk_mutex);
|
||||
@ -2692,6 +2737,92 @@ static int fec_enet_set_tunable(struct net_device *netdev,
|
||||
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
|
||||
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 = {
|
||||
.set_tunable = fec_enet_set_tunable,
|
||||
.get_wol = fec_enet_get_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,
|
||||
.set_link_ksettings = phy_ethtool_set_link_ksettings,
|
||||
.self_test = net_selftest,
|
||||
@ -3586,6 +3719,7 @@ fec_probe(struct platform_device *pdev)
|
||||
char irq_name[8];
|
||||
int irq_cnt;
|
||||
struct fec_devinfo *dev_info;
|
||||
u32 rgmii_delay;
|
||||
|
||||
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
|
||||
|
||||
@ -3643,6 +3777,12 @@ fec_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
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);
|
||||
if (!phy_node && of_phy_is_fixed_link(np)) {
|
||||
ret = of_phy_register_fixed_link(np);
|
||||
@ -3692,6 +3832,12 @@ fec_probe(struct platform_device *pdev)
|
||||
fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
|
||||
if (IS_ERR(fep->clk_ref))
|
||||
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->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
|
||||
|
Loading…
Reference in New Issue
Block a user