ef78b50148f6349ea2e57ef814dca793f1b02e19
[openwrt/staging/neocturne.git] /
1 From 6943ed031ee75f13a950e293f92db68ea2ec2786 Mon Sep 17 00:00:00 2001
2 From: Claudiu Manoil <claudiu.manoil@nxp.com>
3 Date: Wed, 14 Aug 2019 14:34:47 +0300
4 Subject: [PATCH] enetc: Initialize SerDes for SGMII and SXGMII protocols
5
6 ENETC has ethernet MACs capable of SGMII and SXGMII but
7 in order to use these protocols some serdes configurations
8 need to be performed.
9 The serdes is configurable via an internal MDIO bus
10 connected to an internal PCS device, all reads/writes are
11 performed at address 0.
12 This patch basically removes the dependecy on a bootloader
13 regarding serdes initialization.
14
15 Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
16 Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
17 ---
18 drivers/net/ethernet/freescale/enetc/enetc_hw.h | 17 +++++++
19 drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 24 +++++++++
20 drivers/net/ethernet/freescale/enetc/enetc_pf.c | 59 +++++++++++++++++++++++
21 drivers/net/ethernet/freescale/enetc/enetc_pf.h | 2 +
22 4 files changed, 102 insertions(+)
23
24 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
25 +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
26 @@ -221,6 +221,23 @@ enum enetc_bdr_type {TX, RX};
27 #define ENETC_PM0_MAXFRM 0x8014
28 #define ENETC_SET_TX_MTU(val) ((val) << 16)
29 #define ENETC_SET_MAXFRM(val) ((val) & 0xffff)
30 +
31 +#define ENETC_PM_IMDIO_BASE 0x8030
32 +/* PCS registers */
33 +#define ENETC_PCS_CR 0x0
34 +#define ENETC_PCS_CR_RESET_AN 0x1200
35 +#define ENETC_PCS_CR_DEF_VAL 0x0140
36 +#define ENETC_PCS_CR_LANE_RESET 0x8000
37 +#define ENETC_PCS_DEV_ABILITY 0x04
38 +#define ENETC_PCS_DEV_ABILITY_SGMII 0x4001
39 +#define ENETC_PCS_DEV_ABILITY_SXGMII 0x5001
40 +#define ENETC_PCS_LINK_TIMER1 0x12
41 +#define ENETC_PCS_LINK_TIMER1_VAL 0x06a0
42 +#define ENETC_PCS_LINK_TIMER2 0x13
43 +#define ENETC_PCS_LINK_TIMER2_VAL 0x0003
44 +#define ENETC_PCS_IF_MODE 0x14
45 +#define ENETC_PCS_IF_MODE_SGMII_AN 0x0003
46 +
47 #define ENETC_PM0_IF_MODE 0x8300
48 #define ENETC_PMO_IFM_RG BIT(2)
49 #define ENETC_PM0_IFM_RLP (BIT(5) | BIT(11))
50 --- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
51 +++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
52 @@ -200,3 +200,27 @@ void enetc_mdio_remove(struct enetc_pf *
53 if (pf->mdio)
54 mdiobus_unregister(pf->mdio);
55 }
56 +
57 +int enetc_imdio_init(struct enetc_pf *pf)
58 +{
59 + struct device *dev = &pf->si->pdev->dev;
60 + struct enetc_mdio_priv *mdio_priv;
61 + struct mii_bus *bus;
62 +
63 + bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
64 + if (!bus)
65 + return -ENOMEM;
66 +
67 + bus->name = "FSL ENETC internal MDIO Bus";
68 + bus->read = enetc_mdio_read;
69 + bus->write = enetc_mdio_write;
70 + bus->parent = dev;
71 + mdio_priv = bus->priv;
72 + mdio_priv->hw = &pf->si->hw;
73 + mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
74 + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
75 +
76 + pf->imdio = bus;
77 +
78 + return 0;
79 +}
80 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
81 +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
82 @@ -807,6 +807,61 @@ static void enetc_of_put_phy(struct enet
83 of_node_put(priv->phy_node);
84 }
85
86 +static void enetc_configure_sgmii(struct mii_bus *imdio)
87 +{
88 + /* Set to SGMII mode, use AN */
89 + imdio->write(imdio, 0, ENETC_PCS_IF_MODE,
90 + ENETC_PCS_IF_MODE_SGMII_AN);
91 +
92 + /* Dev ability - SGMII */
93 + imdio->write(imdio, 0, ENETC_PCS_DEV_ABILITY,
94 + ENETC_PCS_DEV_ABILITY_SGMII);
95 +
96 + /* Adjust link timer for SGMII */
97 + imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER1,
98 + ENETC_PCS_LINK_TIMER1_VAL);
99 + imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER2,
100 + ENETC_PCS_LINK_TIMER2_VAL);
101 +
102 + /* restart PCS AN */
103 + imdio->write(imdio, 0, ENETC_PCS_CR,
104 + ENETC_PCS_CR_RESET_AN | ENETC_PCS_CR_DEF_VAL);
105 +}
106 +
107 +static void enetc_configure_sxgmii(struct mii_bus *imdio)
108 +{
109 + /* Dev ability - SXGMII */
110 + imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) |
111 + ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII);
112 +
113 + /* Restart PCS AN */
114 + imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) |
115 + ENETC_PCS_CR,
116 + ENETC_PCS_CR_LANE_RESET | ENETC_PCS_CR_RESET_AN);
117 +}
118 +
119 +static int enetc_configure_serdes(struct enetc_ndev_priv *priv)
120 +{
121 + struct enetc_pf *pf = enetc_si_priv(priv->si);
122 + int err;
123 +
124 + if (priv->if_mode != PHY_INTERFACE_MODE_SGMII &&
125 + priv->if_mode != PHY_INTERFACE_MODE_XGMII)
126 + return 0;
127 +
128 + err = enetc_imdio_init(pf);
129 + if (err)
130 + return err;
131 +
132 + if (priv->if_mode == PHY_INTERFACE_MODE_SGMII)
133 + enetc_configure_sgmii(pf->imdio);
134 +
135 + if (priv->if_mode == PHY_INTERFACE_MODE_XGMII)
136 + enetc_configure_sxgmii(pf->imdio);
137 +
138 + return 0;
139 +}
140 +
141 static int enetc_pf_probe(struct pci_dev *pdev,
142 const struct pci_device_id *ent)
143 {
144 @@ -871,6 +926,10 @@ static int enetc_pf_probe(struct pci_dev
145 if (err)
146 dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
147
148 + err = enetc_configure_serdes(priv);
149 + if (err)
150 + dev_warn(&pdev->dev, "Attempted serdes config but failed\n");
151 +
152 err = register_netdev(ndev);
153 if (err)
154 goto err_reg_netdev;
155 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
156 +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
157 @@ -44,6 +44,7 @@ struct enetc_pf {
158 DECLARE_BITMAP(active_vlans, VLAN_N_VID);
159
160 struct mii_bus *mdio; /* saved for cleanup */
161 + struct mii_bus *imdio;
162 };
163
164 int enetc_msg_psi_init(struct enetc_pf *pf);
165 @@ -53,3 +54,4 @@ void enetc_msg_handle_rxmsg(struct enetc
166 /* MDIO */
167 int enetc_mdio_probe(struct enetc_pf *pf);
168 void enetc_mdio_remove(struct enetc_pf *pf);
169 +int enetc_imdio_init(struct enetc_pf *pf);