mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 08:21:14 +00:00
170 lines
5.3 KiB
Diff
170 lines
5.3 KiB
Diff
|
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
|
||
|
@@ -221,6 +221,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
|
||
|
@@ -807,6 +807,61 @@ static void enetc_of_put_phy(struct enet
|
||
|
of_node_put(priv->phy_node);
|
||
|
}
|
||
|
|
||
|
+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)
|
||
|
{
|
||
|
@@ -871,6 +926,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);
|