This source file includes following definitions.
- bcm_cygnus_afe_config
- bcm_cygnus_config_init
- bcm_cygnus_resume
- bcm_omega_config_init
- bcm_omega_resume
- bcm_omega_get_tunable
- bcm_omega_set_tunable
- bcm_omega_get_phy_stats
- bcm_omega_probe
1
2
3
4
5
6
7 #include "bcm-phy-lib.h"
8 #include <linux/brcmphy.h>
9 #include <linux/module.h>
10 #include <linux/netdevice.h>
11 #include <linux/phy.h>
12
13 struct bcm_omega_phy_priv {
14 u64 *stats;
15 };
16
17
18 #define MII_BCM_CYGNUS_AFE_VDAC_ICTRL_0 0x91E5
19
20 static int bcm_cygnus_afe_config(struct phy_device *phydev)
21 {
22 int rc;
23
24
25 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, 0x0c30);
26 if (rc < 0)
27 return rc;
28
29
30 rc = bcm_phy_write_misc(phydev, 0x39, 0x01, 0xA7C8);
31 if (rc < 0)
32 return rc;
33
34
35 rc = bcm_phy_write_misc(phydev, 0x3A, 0x00, 0x0803);
36 if (rc < 0)
37 return rc;
38
39
40 rc = bcm_phy_write_misc(phydev, 0x3A, 0x01, 0xA740);
41 if (rc < 0)
42 return rc;
43
44
45 rc = bcm_phy_write_misc(phydev, 0x3A, 0x03, 0x8400);
46 if (rc < 0)
47 return rc;
48
49
50 rc = bcm_phy_write_misc(phydev, 0x3B, 0x00, 0x0004);
51 if (rc < 0)
52 return rc;
53
54
55 rc = phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x02);
56 if (rc < 0)
57 return rc;
58
59
60 rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10);
61 if (rc < 0)
62 return rc;
63
64
65 rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10);
66 if (rc < 0)
67 return rc;
68
69
70 rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00);
71
72 return 0;
73 }
74
75 static int bcm_cygnus_config_init(struct phy_device *phydev)
76 {
77 int reg, rc;
78
79 reg = phy_read(phydev, MII_BCM54XX_ECR);
80 if (reg < 0)
81 return reg;
82
83
84 reg |= MII_BCM54XX_ECR_IM;
85 rc = phy_write(phydev, MII_BCM54XX_ECR, reg);
86 if (rc)
87 return rc;
88
89
90 reg = ~(MII_BCM54XX_INT_DUPLEX |
91 MII_BCM54XX_INT_SPEED |
92 MII_BCM54XX_INT_LINK);
93 rc = phy_write(phydev, MII_BCM54XX_IMR, reg);
94 if (rc)
95 return rc;
96
97
98 rc = bcm_cygnus_afe_config(phydev);
99 if (rc)
100 return rc;
101
102
103 rc = bcm_phy_set_eee(phydev, true);
104 if (rc)
105 return rc;
106
107
108 return bcm_phy_enable_apd(phydev, false);
109 }
110
111 static int bcm_cygnus_resume(struct phy_device *phydev)
112 {
113 int rc;
114
115 genphy_resume(phydev);
116
117
118
119
120 rc = bcm_cygnus_config_init(phydev);
121 if (rc)
122 return rc;
123
124
125 return genphy_config_aneg(phydev);
126 }
127
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
139
140
141
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
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
173 ret = bcm_omega_config_init(phydev);
174 if (ret)
175 return ret;
176
177
178
179
180
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
215
216
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
252 static struct phy_driver bcm_cygnus_phy_driver[] = {
253 {
254 .phy_id = PHY_ID_BCM_CYGNUS,
255 .phy_id_mask = 0xfffffff0,
256 .name = "Broadcom Cygnus PHY",
257
258 .config_init = bcm_cygnus_config_init,
259 .ack_interrupt = bcm_phy_ack_intr,
260 .config_intr = bcm_phy_config_intr,
261 .suspend = genphy_suspend,
262 .resume = bcm_cygnus_resume,
263 }, {
264 .phy_id = PHY_ID_BCM_OMEGA,
265 .phy_id_mask = 0xfffffff0,
266 .name = "Broadcom Omega Combo GPHY",
267
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 };
280
281 static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
282 { PHY_ID_BCM_CYGNUS, 0xfffffff0, },
283 { PHY_ID_BCM_OMEGA, 0xfffffff0, },
284 { }
285 };
286 MODULE_DEVICE_TABLE(mdio, bcm_cygnus_phy_tbl);
287
288 module_phy_driver(bcm_cygnus_phy_driver);
289
290 MODULE_DESCRIPTION("Broadcom Cygnus internal PHY driver");
291 MODULE_LICENSE("GPL v2");
292 MODULE_AUTHOR("Broadcom Corporation");