hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
kernel/drivers/net/phy/bcm-cygnus.c
....@@ -1,14 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
23 * Copyright (C) 2015 Broadcom Corporation
3
- *
4
- * This program is free software; you can redistribute it and/or
5
- * modify it under the terms of the GNU General Public License as
6
- * published by the Free Software Foundation version 2.
7
- *
8
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9
- * kind, whether express or implied; without even the implied warranty
10
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
- * GNU General Public License for more details.
124 */
135
146 /* Broadcom Cygnus SoC internal transceivers support. */
....@@ -17,6 +9,10 @@
179 #include <linux/module.h>
1810 #include <linux/netdevice.h>
1911 #include <linux/phy.h>
12
+
13
+struct bcm_omega_phy_priv {
14
+ u64 *stats;
15
+};
2016
2117 /* Broadcom Cygnus Phy specific registers */
2218 #define MII_BCM_CYGNUS_AFE_VDAC_ICTRL_0 0x91E5 /* VDAL Control register */
....@@ -129,21 +125,162 @@
129125 return genphy_config_aneg(phydev);
130126 }
131127
128
+static int bcm_omega_config_init(struct phy_device *phydev)
129
+{
130
+ u8 count, rev;
131
+ int ret = 0;
132
+
133
+ rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
134
+
135
+ pr_info_once("%s: %s PHY revision: 0x%02x\n",
136
+ phydev_name(phydev), phydev->drv->name, rev);
137
+
138
+ /* Dummy read to a register to workaround an issue upon reset where the
139
+ * internal inverter may not allow the first MDIO transaction to pass
140
+ * the MDIO management controller and make us return 0xffff for such
141
+ * reads.
142
+ */
143
+ phy_read(phydev, MII_BMSR);
144
+
145
+ switch (rev) {
146
+ case 0x00:
147
+ ret = bcm_phy_28nm_a0b0_afe_config_init(phydev);
148
+ break;
149
+ default:
150
+ break;
151
+ }
152
+
153
+ if (ret)
154
+ return ret;
155
+
156
+ ret = bcm_phy_downshift_get(phydev, &count);
157
+ if (ret)
158
+ return ret;
159
+
160
+ /* Only enable EEE if Wirespeed/downshift is disabled */
161
+ ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
162
+ if (ret)
163
+ return ret;
164
+
165
+ return bcm_phy_enable_apd(phydev, true);
166
+}
167
+
168
+static int bcm_omega_resume(struct phy_device *phydev)
169
+{
170
+ int ret;
171
+
172
+ /* Re-apply workarounds coming out suspend/resume */
173
+ ret = bcm_omega_config_init(phydev);
174
+ if (ret)
175
+ return ret;
176
+
177
+ /* 28nm Gigabit PHYs come out of reset without any half-duplex
178
+ * or "hub" compliant advertised mode, fix that. This does not
179
+ * cause any problems with the PHY library since genphy_config_aneg()
180
+ * gracefully handles auto-negotiated and forced modes.
181
+ */
182
+ return genphy_config_aneg(phydev);
183
+}
184
+
185
+static int bcm_omega_get_tunable(struct phy_device *phydev,
186
+ struct ethtool_tunable *tuna, void *data)
187
+{
188
+ switch (tuna->id) {
189
+ case ETHTOOL_PHY_DOWNSHIFT:
190
+ return bcm_phy_downshift_get(phydev, (u8 *)data);
191
+ default:
192
+ return -EOPNOTSUPP;
193
+ }
194
+}
195
+
196
+static int bcm_omega_set_tunable(struct phy_device *phydev,
197
+ struct ethtool_tunable *tuna,
198
+ const void *data)
199
+{
200
+ u8 count = *(u8 *)data;
201
+ int ret;
202
+
203
+ switch (tuna->id) {
204
+ case ETHTOOL_PHY_DOWNSHIFT:
205
+ ret = bcm_phy_downshift_set(phydev, count);
206
+ break;
207
+ default:
208
+ return -EOPNOTSUPP;
209
+ }
210
+
211
+ if (ret)
212
+ return ret;
213
+
214
+ /* Disable EEE advertisement since this prevents the PHY
215
+ * from successfully linking up, trigger auto-negotiation restart
216
+ * to let the MAC decide what to do.
217
+ */
218
+ ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
219
+ if (ret)
220
+ return ret;
221
+
222
+ return genphy_restart_aneg(phydev);
223
+}
224
+
225
+static void bcm_omega_get_phy_stats(struct phy_device *phydev,
226
+ struct ethtool_stats *stats, u64 *data)
227
+{
228
+ struct bcm_omega_phy_priv *priv = phydev->priv;
229
+
230
+ bcm_phy_get_stats(phydev, priv->stats, stats, data);
231
+}
232
+
233
+static int bcm_omega_probe(struct phy_device *phydev)
234
+{
235
+ struct bcm_omega_phy_priv *priv;
236
+
237
+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
238
+ if (!priv)
239
+ return -ENOMEM;
240
+
241
+ phydev->priv = priv;
242
+
243
+ priv->stats = devm_kcalloc(&phydev->mdio.dev,
244
+ bcm_phy_get_sset_count(phydev), sizeof(u64),
245
+ GFP_KERNEL);
246
+ if (!priv->stats)
247
+ return -ENOMEM;
248
+
249
+ return 0;
250
+}
251
+
132252 static struct phy_driver bcm_cygnus_phy_driver[] = {
133253 {
134254 .phy_id = PHY_ID_BCM_CYGNUS,
135255 .phy_id_mask = 0xfffffff0,
136256 .name = "Broadcom Cygnus PHY",
137
- .features = PHY_GBIT_FEATURES,
257
+ /* PHY_GBIT_FEATURES */
138258 .config_init = bcm_cygnus_config_init,
139259 .ack_interrupt = bcm_phy_ack_intr,
140260 .config_intr = bcm_phy_config_intr,
141261 .suspend = genphy_suspend,
142262 .resume = bcm_cygnus_resume,
143
-} };
263
+}, {
264
+ .phy_id = PHY_ID_BCM_OMEGA,
265
+ .phy_id_mask = 0xfffffff0,
266
+ .name = "Broadcom Omega Combo GPHY",
267
+ /* PHY_GBIT_FEATURES */
268
+ .flags = PHY_IS_INTERNAL,
269
+ .config_init = bcm_omega_config_init,
270
+ .suspend = genphy_suspend,
271
+ .resume = bcm_omega_resume,
272
+ .get_tunable = bcm_omega_get_tunable,
273
+ .set_tunable = bcm_omega_set_tunable,
274
+ .get_sset_count = bcm_phy_get_sset_count,
275
+ .get_strings = bcm_phy_get_strings,
276
+ .get_stats = bcm_omega_get_phy_stats,
277
+ .probe = bcm_omega_probe,
278
+}
279
+};
144280
145281 static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
146282 { PHY_ID_BCM_CYGNUS, 0xfffffff0, },
283
+ { PHY_ID_BCM_OMEGA, 0xfffffff0, },
147284 { }
148285 };
149286 MODULE_DEVICE_TABLE(mdio, bcm_cygnus_phy_tbl);