Skip to content

Commit 975d183

Browse files
mwalledavem330
authored andcommitted
net: enetc: Initialize SerDes for SGMII and USXGMII protocols
ENETC has ethernet MACs capable of SGMII, 2500BaseX and USXGMII. But in order to use these protocols some SerDes configurations need to be performed. The SerDes is configurable via an internal PCS PHY which is connected to an internal MDIO bus at address 0. This patch basically removes the dependency on bootloader regarding SerDes initialization. Signed-off-by: Michael Walle <[email protected]> Reviewed-by: Claudiu Manoil <[email protected]> Tested-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 16659b8 commit 975d183

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

drivers/net/ethernet/freescale/enetc/enetc_hw.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ enum enetc_bdr_type {TX, RX};
224224
#define ENETC_PM0_MAXFRM 0x8014
225225
#define ENETC_SET_TX_MTU(val) ((val) << 16)
226226
#define ENETC_SET_MAXFRM(val) ((val) & 0xffff)
227+
228+
#define ENETC_PM_IMDIO_BASE 0x8030
229+
227230
#define ENETC_PM0_IF_MODE 0x8300
228231
#define ENETC_PMO_IFM_RG BIT(2)
229232
#define ENETC_PM0_IFM_RLP (BIT(5) | BIT(11))

drivers/net/ethernet/freescale/enetc/enetc_pf.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
22
/* Copyright 2017-2019 NXP */
33

4+
#include <linux/mdio.h>
45
#include <linux/module.h>
56
#include <linux/fsl/enetc_mdio.h>
67
#include <linux/of_mdio.h>
@@ -833,6 +834,135 @@ static void enetc_of_put_phy(struct enetc_ndev_priv *priv)
833834
of_node_put(priv->phy_node);
834835
}
835836

837+
static int enetc_imdio_init(struct enetc_pf *pf, bool is_c45)
838+
{
839+
struct device *dev = &pf->si->pdev->dev;
840+
struct enetc_mdio_priv *mdio_priv;
841+
struct phy_device *pcs;
842+
struct mii_bus *bus;
843+
int err;
844+
845+
bus = mdiobus_alloc_size(sizeof(*mdio_priv));
846+
if (!bus)
847+
return -ENOMEM;
848+
849+
bus->name = "Freescale ENETC internal MDIO Bus";
850+
bus->read = enetc_mdio_read;
851+
bus->write = enetc_mdio_write;
852+
bus->parent = dev;
853+
bus->phy_mask = ~0;
854+
mdio_priv = bus->priv;
855+
mdio_priv->hw = &pf->si->hw;
856+
mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
857+
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
858+
859+
err = mdiobus_register(bus);
860+
if (err) {
861+
dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
862+
goto free_mdio_bus;
863+
}
864+
865+
pcs = get_phy_device(bus, 0, is_c45);
866+
if (IS_ERR(pcs)) {
867+
err = PTR_ERR(pcs);
868+
dev_err(dev, "cannot get internal PCS PHY (%d)\n", err);
869+
goto unregister_mdiobus;
870+
}
871+
872+
pf->imdio = bus;
873+
pf->pcs = pcs;
874+
875+
return 0;
876+
877+
unregister_mdiobus:
878+
mdiobus_unregister(bus);
879+
free_mdio_bus:
880+
mdiobus_free(bus);
881+
return err;
882+
}
883+
884+
static void enetc_imdio_remove(struct enetc_pf *pf)
885+
{
886+
if (pf->pcs)
887+
put_device(&pf->pcs->mdio.dev);
888+
if (pf->imdio) {
889+
mdiobus_unregister(pf->imdio);
890+
mdiobus_free(pf->imdio);
891+
}
892+
}
893+
894+
static void enetc_configure_sgmii(struct phy_device *pcs)
895+
{
896+
/* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
897+
* for the MAC PCS in order to acknowledge the AN.
898+
*/
899+
phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | ADVERTISE_LPACK);
900+
901+
phy_write(pcs, ENETC_PCS_IF_MODE,
902+
ENETC_PCS_IF_MODE_SGMII_EN |
903+
ENETC_PCS_IF_MODE_USE_SGMII_AN);
904+
905+
/* Adjust link timer for SGMII */
906+
phy_write(pcs, ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
907+
phy_write(pcs, ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
908+
909+
phy_write(pcs, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE);
910+
}
911+
912+
static void enetc_configure_2500basex(struct phy_device *pcs)
913+
{
914+
phy_write(pcs, ENETC_PCS_IF_MODE,
915+
ENETC_PCS_IF_MODE_SGMII_EN |
916+
ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500));
917+
918+
phy_write(pcs, MII_BMCR, BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_RESET);
919+
}
920+
921+
static void enetc_configure_usxgmii(struct phy_device *pcs)
922+
{
923+
/* Configure device ability for the USXGMII Replicator */
924+
phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
925+
ADVERTISE_SGMII | ADVERTISE_LPACK |
926+
MDIO_USXGMII_FULL_DUPLEX);
927+
928+
/* Restart PCS AN */
929+
phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_BMCR,
930+
BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART);
931+
}
932+
933+
static int enetc_configure_serdes(struct enetc_ndev_priv *priv)
934+
{
935+
bool is_c45 = priv->if_mode == PHY_INTERFACE_MODE_USXGMII;
936+
struct enetc_pf *pf = enetc_si_priv(priv->si);
937+
int err;
938+
939+
if (priv->if_mode != PHY_INTERFACE_MODE_SGMII &&
940+
priv->if_mode != PHY_INTERFACE_MODE_2500BASEX &&
941+
priv->if_mode != PHY_INTERFACE_MODE_USXGMII)
942+
return 0;
943+
944+
err = enetc_imdio_init(pf, is_c45);
945+
if (err)
946+
return err;
947+
948+
switch (priv->if_mode) {
949+
case PHY_INTERFACE_MODE_SGMII:
950+
enetc_configure_sgmii(pf->pcs);
951+
break;
952+
case PHY_INTERFACE_MODE_2500BASEX:
953+
enetc_configure_2500basex(pf->pcs);
954+
break;
955+
case PHY_INTERFACE_MODE_USXGMII:
956+
enetc_configure_usxgmii(pf->pcs);
957+
break;
958+
default:
959+
dev_err(&pf->si->pdev->dev, "Unsupported link mode %s\n",
960+
phy_modes(priv->if_mode));
961+
}
962+
963+
return 0;
964+
}
965+
836966
static int enetc_pf_probe(struct pci_dev *pdev,
837967
const struct pci_device_id *ent)
838968
{
@@ -897,6 +1027,10 @@ static int enetc_pf_probe(struct pci_dev *pdev,
8971027
if (err)
8981028
dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
8991029

1030+
err = enetc_configure_serdes(priv);
1031+
if (err)
1032+
dev_warn(&pdev->dev, "Attempted SerDes config but failed\n");
1033+
9001034
err = register_netdev(ndev);
9011035
if (err)
9021036
goto err_reg_netdev;
@@ -932,6 +1066,7 @@ static void enetc_pf_remove(struct pci_dev *pdev)
9321066
priv = netdev_priv(si->ndev);
9331067
unregister_netdev(si->ndev);
9341068

1069+
enetc_imdio_remove(pf);
9351070
enetc_mdio_remove(pf);
9361071
enetc_of_put_phy(priv);
9371072

drivers/net/ethernet/freescale/enetc/enetc_pf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ struct enetc_pf {
4444
DECLARE_BITMAP(active_vlans, VLAN_N_VID);
4545

4646
struct mii_bus *mdio; /* saved for cleanup */
47+
struct mii_bus *imdio;
48+
struct phy_device *pcs;
4749
};
4850

4951
int enetc_msg_psi_init(struct enetc_pf *pf);

0 commit comments

Comments
 (0)