| From 6943ed031ee75f13a950e293f92db68ea2ec2786 Mon Sep 17 00:00:00 2001 |
| From: Claudiu Manoil <claudiu.manoil@nxp.com> |
| Date: Wed, 14 Aug 2019 14:34:47 +0300 |
| Subject: [PATCH] enetc: Initialize SerDes for SGMII and SXGMII protocols |
| |
| ENETC has ethernet MACs capable of SGMII and SXGMII but |
| in order to use these protocols some serdes configurations |
| need to be performed. |
| The serdes is configurable via an internal MDIO bus |
| connected to an internal PCS device, all reads/writes are |
| performed at address 0. |
| This patch basically removes the dependecy on a bootloader |
| regarding serdes initialization. |
| |
| Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com> |
| Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com> |
| --- |
| drivers/net/ethernet/freescale/enetc/enetc_hw.h | 17 +++++++ |
| drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 24 +++++++++ |
| drivers/net/ethernet/freescale/enetc/enetc_pf.c | 59 +++++++++++++++++++++++ |
| drivers/net/ethernet/freescale/enetc/enetc_pf.h | 2 + |
| 4 files changed, 102 insertions(+) |
| |
| --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h |
| +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h |
| @@ -223,6 +223,23 @@ enum enetc_bdr_type {TX, RX}; |
| #define ENETC_PM0_MAXFRM 0x8014 |
| #define ENETC_SET_TX_MTU(val) ((val) << 16) |
| #define ENETC_SET_MAXFRM(val) ((val) & 0xffff) |
| + |
| +#define ENETC_PM_IMDIO_BASE 0x8030 |
| +/* PCS registers */ |
| +#define ENETC_PCS_CR 0x0 |
| +#define ENETC_PCS_CR_RESET_AN 0x1200 |
| +#define ENETC_PCS_CR_DEF_VAL 0x0140 |
| +#define ENETC_PCS_CR_LANE_RESET 0x8000 |
| +#define ENETC_PCS_DEV_ABILITY 0x04 |
| +#define ENETC_PCS_DEV_ABILITY_SGMII 0x4001 |
| +#define ENETC_PCS_DEV_ABILITY_SXGMII 0x5001 |
| +#define ENETC_PCS_LINK_TIMER1 0x12 |
| +#define ENETC_PCS_LINK_TIMER1_VAL 0x06a0 |
| +#define ENETC_PCS_LINK_TIMER2 0x13 |
| +#define ENETC_PCS_LINK_TIMER2_VAL 0x0003 |
| +#define ENETC_PCS_IF_MODE 0x14 |
| +#define ENETC_PCS_IF_MODE_SGMII_AN 0x0003 |
| + |
| #define ENETC_PM0_IF_MODE 0x8300 |
| #define ENETC_PMO_IFM_RG BIT(2) |
| #define ENETC_PM0_IFM_RLP (BIT(5) | BIT(11)) |
| --- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c |
| +++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c |
| @@ -200,3 +200,27 @@ void enetc_mdio_remove(struct enetc_pf * |
| if (pf->mdio) |
| mdiobus_unregister(pf->mdio); |
| } |
| + |
| +int enetc_imdio_init(struct enetc_pf *pf) |
| +{ |
| + struct device *dev = &pf->si->pdev->dev; |
| + struct enetc_mdio_priv *mdio_priv; |
| + struct mii_bus *bus; |
| + |
| + bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); |
| + if (!bus) |
| + return -ENOMEM; |
| + |
| + bus->name = "FSL ENETC internal MDIO Bus"; |
| + bus->read = enetc_mdio_read; |
| + bus->write = enetc_mdio_write; |
| + bus->parent = dev; |
| + mdio_priv = bus->priv; |
| + mdio_priv->hw = &pf->si->hw; |
| + mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE; |
| + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); |
| + |
| + pf->imdio = bus; |
| + |
| + return 0; |
| +} |
| --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c |
| +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c |
| @@ -872,6 +872,61 @@ static void enetc_init_unused_port(struc |
| enetc_free_cbdr(dev, &si->cbd_ring); |
| } |
| |
| +static void enetc_configure_sgmii(struct mii_bus *imdio) |
| +{ |
| + /* Set to SGMII mode, use AN */ |
| + imdio->write(imdio, 0, ENETC_PCS_IF_MODE, |
| + ENETC_PCS_IF_MODE_SGMII_AN); |
| + |
| + /* Dev ability - SGMII */ |
| + imdio->write(imdio, 0, ENETC_PCS_DEV_ABILITY, |
| + ENETC_PCS_DEV_ABILITY_SGMII); |
| + |
| + /* Adjust link timer for SGMII */ |
| + imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER1, |
| + ENETC_PCS_LINK_TIMER1_VAL); |
| + imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER2, |
| + ENETC_PCS_LINK_TIMER2_VAL); |
| + |
| + /* restart PCS AN */ |
| + imdio->write(imdio, 0, ENETC_PCS_CR, |
| + ENETC_PCS_CR_RESET_AN | ENETC_PCS_CR_DEF_VAL); |
| +} |
| + |
| +static void enetc_configure_sxgmii(struct mii_bus *imdio) |
| +{ |
| + /* Dev ability - SXGMII */ |
| + imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | |
| + ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII); |
| + |
| + /* Restart PCS AN */ |
| + imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | |
| + ENETC_PCS_CR, |
| + ENETC_PCS_CR_LANE_RESET | ENETC_PCS_CR_RESET_AN); |
| +} |
| + |
| +static int enetc_configure_serdes(struct enetc_ndev_priv *priv) |
| +{ |
| + struct enetc_pf *pf = enetc_si_priv(priv->si); |
| + int err; |
| + |
| + if (priv->if_mode != PHY_INTERFACE_MODE_SGMII && |
| + priv->if_mode != PHY_INTERFACE_MODE_XGMII) |
| + return 0; |
| + |
| + err = enetc_imdio_init(pf); |
| + if (err) |
| + return err; |
| + |
| + if (priv->if_mode == PHY_INTERFACE_MODE_SGMII) |
| + enetc_configure_sgmii(pf->imdio); |
| + |
| + if (priv->if_mode == PHY_INTERFACE_MODE_XGMII) |
| + enetc_configure_sxgmii(pf->imdio); |
| + |
| + return 0; |
| +} |
| + |
| static int enetc_pf_probe(struct pci_dev *pdev, |
| const struct pci_device_id *ent) |
| { |
| @@ -956,6 +1011,10 @@ static int enetc_pf_probe(struct pci_dev |
| if (err) |
| dev_warn(&pdev->dev, "Fallback to PHY-less operation\n"); |
| |
| + err = enetc_configure_serdes(priv); |
| + if (err) |
| + dev_warn(&pdev->dev, "Attempted serdes config but failed\n"); |
| + |
| err = register_netdev(ndev); |
| if (err) |
| goto err_reg_netdev; |
| --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h |
| +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h |
| @@ -44,6 +44,7 @@ struct enetc_pf { |
| DECLARE_BITMAP(active_vlans, VLAN_N_VID); |
| |
| struct mii_bus *mdio; /* saved for cleanup */ |
| + struct mii_bus *imdio; |
| }; |
| |
| int enetc_msg_psi_init(struct enetc_pf *pf); |
| @@ -53,3 +54,4 @@ void enetc_msg_handle_rxmsg(struct enetc |
| /* MDIO */ |
| int enetc_mdio_probe(struct enetc_pf *pf); |
| void enetc_mdio_remove(struct enetc_pf *pf); |
| +int enetc_imdio_init(struct enetc_pf *pf); |