openwrt/target/linux/layerscape/patches-5.4/701-net-0229-enetc-Initialize-SerDes-for-SGMII-and-SXGMII-protoco.patch
Yangbo Lu cddd459140 layerscape: add patches-5.4
Add patches for linux-5.4. The patches are from NXP LSDK-20.04 release
which was tagged LSDK-20.04-V5.4.
https://source.codeaurora.org/external/qoriq/qoriq-components/linux/

For boards LS1021A-IOT, and Traverse-LS1043 which are not involved in
LSDK, port the dts patches from 4.14.

The patches are sorted into the following categories:
  301-arch-xxxx
  302-dts-xxxx
  303-core-xxxx
  701-net-xxxx
  801-audio-xxxx
  802-can-xxxx
  803-clock-xxxx
  804-crypto-xxxx
  805-display-xxxx
  806-dma-xxxx
  807-gpio-xxxx
  808-i2c-xxxx
  809-jailhouse-xxxx
  810-keys-xxxx
  811-kvm-xxxx
  812-pcie-xxxx
  813-pm-xxxx
  814-qe-xxxx
  815-sata-xxxx
  816-sdhc-xxxx
  817-spi-xxxx
  818-thermal-xxxx
  819-uart-xxxx
  820-usb-xxxx
  821-vfio-xxxx

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
2020-05-07 12:53:06 +02:00

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);