1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2015 Broadcom Corporation
6 /* Broadcom Cygnus SoC internal transceivers support. */
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>
13 struct bcm_omega_phy_priv
{
17 /* Broadcom Cygnus Phy specific registers */
18 #define MII_BCM_CYGNUS_AFE_VDAC_ICTRL_0 0x91E5 /* VDAL Control register */
20 static int bcm_cygnus_afe_config(struct phy_device
*phydev
)
24 /* ensure smdspclk is enabled */
25 rc
= phy_write(phydev
, MII_BCM54XX_AUX_CTL
, 0x0c30);
29 /* AFE_VDAC_ICTRL_0 bit 7:4 Iq=1100 for 1g 10bt, normal modes */
30 rc
= bcm_phy_write_misc(phydev
, 0x39, 0x01, 0xA7C8);
34 /* AFE_HPF_TRIM_OTHERS bit11=1, short cascode enable for all modes*/
35 rc
= bcm_phy_write_misc(phydev
, 0x3A, 0x00, 0x0803);
39 /* AFE_TX_CONFIG_1 bit 7:4 Iq=1100 for test modes */
40 rc
= bcm_phy_write_misc(phydev
, 0x3A, 0x01, 0xA740);
44 /* AFE TEMPSEN_OTHERS rcal_HT, rcal_LT 10000 */
45 rc
= bcm_phy_write_misc(phydev
, 0x3A, 0x03, 0x8400);
49 /* AFE_FUTURE_RSV bit 2:0 rccal <2:0>=100 */
50 rc
= bcm_phy_write_misc(phydev
, 0x3B, 0x00, 0x0004);
54 /* Adjust bias current trim to overcome digital offSet */
55 rc
= phy_write(phydev
, MII_BRCM_CORE_BASE1E
, 0x02);
59 /* make rcal=100, since rdb default is 000 */
60 rc
= bcm_phy_write_exp_sel(phydev
, MII_BRCM_CORE_EXPB1
, 0x10);
64 /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */
65 rc
= bcm_phy_write_exp_sel(phydev
, MII_BRCM_CORE_EXPB0
, 0x10);
69 /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */
70 rc
= bcm_phy_write_exp_sel(phydev
, MII_BRCM_CORE_EXPB0
, 0x00);
75 static int bcm_cygnus_config_init(struct phy_device
*phydev
)
79 reg
= phy_read(phydev
, MII_BCM54XX_ECR
);
83 /* Mask interrupts globally. */
84 reg
|= MII_BCM54XX_ECR_IM
;
85 rc
= phy_write(phydev
, MII_BCM54XX_ECR
, reg
);
89 /* Unmask events of interest */
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
);
97 /* Apply AFE settings for the PHY */
98 rc
= bcm_cygnus_afe_config(phydev
);
103 rc
= bcm_phy_set_eee(phydev
, true);
108 return bcm_phy_enable_apd(phydev
, false);
111 static int bcm_cygnus_resume(struct phy_device
*phydev
)
115 genphy_resume(phydev
);
117 /* Re-initialize the PHY to apply AFE work-arounds and
118 * configurations when coming out of suspend.
120 rc
= bcm_cygnus_config_init(phydev
);
124 /* restart auto negotiation with the new settings */
125 return genphy_config_aneg(phydev
);
128 static int bcm_omega_config_init(struct phy_device
*phydev
)
133 rev
= phydev
->phy_id
& ~phydev
->drv
->phy_id_mask
;
135 pr_info_once("%s: %s PHY revision: 0x%02x\n",
136 phydev_name(phydev
), phydev
->drv
->name
, rev
);
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
143 phy_read(phydev
, MII_BMSR
);
147 ret
= bcm_phy_28nm_a0b0_afe_config_init(phydev
);
156 ret
= bcm_phy_downshift_get(phydev
, &count
);
160 /* Only enable EEE if Wirespeed/downshift is disabled */
161 ret
= bcm_phy_set_eee(phydev
, count
== DOWNSHIFT_DEV_DISABLE
);
165 return bcm_phy_enable_apd(phydev
, true);
168 static int bcm_omega_resume(struct phy_device
*phydev
)
172 /* Re-apply workarounds coming out suspend/resume */
173 ret
= bcm_omega_config_init(phydev
);
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.
182 return genphy_config_aneg(phydev
);
185 static int bcm_omega_get_tunable(struct phy_device
*phydev
,
186 struct ethtool_tunable
*tuna
, void *data
)
189 case ETHTOOL_PHY_DOWNSHIFT
:
190 return bcm_phy_downshift_get(phydev
, (u8
*)data
);
196 static int bcm_omega_set_tunable(struct phy_device
*phydev
,
197 struct ethtool_tunable
*tuna
,
200 u8 count
= *(u8
*)data
;
204 case ETHTOOL_PHY_DOWNSHIFT
:
205 ret
= bcm_phy_downshift_set(phydev
, count
);
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.
218 ret
= bcm_phy_set_eee(phydev
, count
== DOWNSHIFT_DEV_DISABLE
);
222 return genphy_restart_aneg(phydev
);
225 static void bcm_omega_get_phy_stats(struct phy_device
*phydev
,
226 struct ethtool_stats
*stats
, u64
*data
)
228 struct bcm_omega_phy_priv
*priv
= phydev
->priv
;
230 bcm_phy_get_stats(phydev
, priv
->stats
, stats
, data
);
233 static int bcm_omega_probe(struct phy_device
*phydev
)
235 struct bcm_omega_phy_priv
*priv
;
237 priv
= devm_kzalloc(&phydev
->mdio
.dev
, sizeof(*priv
), GFP_KERNEL
);
243 priv
->stats
= devm_kcalloc(&phydev
->mdio
.dev
,
244 bcm_phy_get_sset_count(phydev
), sizeof(u64
),
252 static struct phy_driver bcm_cygnus_phy_driver
[] = {
254 .phy_id
= PHY_ID_BCM_CYGNUS
,
255 .phy_id_mask
= 0xfffffff0,
256 .name
= "Broadcom Cygnus PHY",
257 /* PHY_GBIT_FEATURES */
258 .config_init
= bcm_cygnus_config_init
,
259 .config_intr
= bcm_phy_config_intr
,
260 .handle_interrupt
= bcm_phy_handle_interrupt
,
261 .suspend
= genphy_suspend
,
262 .resume
= bcm_cygnus_resume
,
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
,
281 static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl
[] = {
282 { PHY_ID_BCM_CYGNUS
, 0xfffffff0, },
283 { PHY_ID_BCM_OMEGA
, 0xfffffff0, },
286 MODULE_DEVICE_TABLE(mdio
, bcm_cygnus_phy_tbl
);
288 module_phy_driver(bcm_cygnus_phy_driver
);
290 MODULE_DESCRIPTION("Broadcom Cygnus internal PHY driver");
291 MODULE_LICENSE("GPL v2");
292 MODULE_AUTHOR("Broadcom Corporation");