xref: /openbmc/linux/drivers/net/phy/bcm-cygnus.c (revision 3213486f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2015 Broadcom Corporation
4  */
5 
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>
12 
13 /* Broadcom Cygnus Phy specific registers */
14 #define MII_BCM_CYGNUS_AFE_VDAC_ICTRL_0  0x91E5 /* VDAL Control register */
15 
16 static int bcm_cygnus_afe_config(struct phy_device *phydev)
17 {
18 	int rc;
19 
20 	/* ensure smdspclk is enabled */
21 	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, 0x0c30);
22 	if (rc < 0)
23 		return rc;
24 
25 	/* AFE_VDAC_ICTRL_0 bit 7:4 Iq=1100 for 1g 10bt, normal modes */
26 	rc = bcm_phy_write_misc(phydev, 0x39, 0x01, 0xA7C8);
27 	if (rc < 0)
28 		return rc;
29 
30 	/* AFE_HPF_TRIM_OTHERS bit11=1, short cascode enable for all modes*/
31 	rc = bcm_phy_write_misc(phydev, 0x3A, 0x00, 0x0803);
32 	if (rc < 0)
33 		return rc;
34 
35 	/* AFE_TX_CONFIG_1 bit 7:4 Iq=1100 for test modes */
36 	rc = bcm_phy_write_misc(phydev, 0x3A, 0x01, 0xA740);
37 	if (rc < 0)
38 		return rc;
39 
40 	/* AFE TEMPSEN_OTHERS rcal_HT, rcal_LT 10000 */
41 	rc = bcm_phy_write_misc(phydev, 0x3A, 0x03, 0x8400);
42 	if (rc < 0)
43 		return rc;
44 
45 	/* AFE_FUTURE_RSV bit 2:0 rccal <2:0>=100 */
46 	rc = bcm_phy_write_misc(phydev, 0x3B, 0x00, 0x0004);
47 	if (rc < 0)
48 		return rc;
49 
50 	/* Adjust bias current trim to overcome digital offSet */
51 	rc = phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x02);
52 	if (rc < 0)
53 		return rc;
54 
55 	/* make rcal=100, since rdb default is 000 */
56 	rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10);
57 	if (rc < 0)
58 		return rc;
59 
60 	/* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */
61 	rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10);
62 	if (rc < 0)
63 		return rc;
64 
65 	/* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */
66 	rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00);
67 
68 	return 0;
69 }
70 
71 static int bcm_cygnus_config_init(struct phy_device *phydev)
72 {
73 	int reg, rc;
74 
75 	reg = phy_read(phydev, MII_BCM54XX_ECR);
76 	if (reg < 0)
77 		return reg;
78 
79 	/* Mask interrupts globally. */
80 	reg |= MII_BCM54XX_ECR_IM;
81 	rc = phy_write(phydev, MII_BCM54XX_ECR, reg);
82 	if (rc)
83 		return rc;
84 
85 	/* Unmask events of interest */
86 	reg = ~(MII_BCM54XX_INT_DUPLEX |
87 		MII_BCM54XX_INT_SPEED |
88 		MII_BCM54XX_INT_LINK);
89 	rc = phy_write(phydev, MII_BCM54XX_IMR, reg);
90 	if (rc)
91 		return rc;
92 
93 	/* Apply AFE settings for the PHY */
94 	rc = bcm_cygnus_afe_config(phydev);
95 	if (rc)
96 		return rc;
97 
98 	/* Advertise EEE */
99 	rc = bcm_phy_set_eee(phydev, true);
100 	if (rc)
101 		return rc;
102 
103 	/* Enable APD */
104 	return bcm_phy_enable_apd(phydev, false);
105 }
106 
107 static int bcm_cygnus_resume(struct phy_device *phydev)
108 {
109 	int rc;
110 
111 	genphy_resume(phydev);
112 
113 	/* Re-initialize the PHY to apply AFE work-arounds and
114 	 * configurations when coming out of suspend.
115 	 */
116 	rc = bcm_cygnus_config_init(phydev);
117 	if (rc)
118 		return rc;
119 
120 	/* restart auto negotiation with the new settings */
121 	return genphy_config_aneg(phydev);
122 }
123 
124 static struct phy_driver bcm_cygnus_phy_driver[] = {
125 {
126 	.phy_id        = PHY_ID_BCM_CYGNUS,
127 	.phy_id_mask   = 0xfffffff0,
128 	.name          = "Broadcom Cygnus PHY",
129 	.features      = PHY_GBIT_FEATURES,
130 	.config_init   = bcm_cygnus_config_init,
131 	.ack_interrupt = bcm_phy_ack_intr,
132 	.config_intr   = bcm_phy_config_intr,
133 	.suspend       = genphy_suspend,
134 	.resume        = bcm_cygnus_resume,
135 } };
136 
137 static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
138 	{ PHY_ID_BCM_CYGNUS, 0xfffffff0, },
139 	{ }
140 };
141 MODULE_DEVICE_TABLE(mdio, bcm_cygnus_phy_tbl);
142 
143 module_phy_driver(bcm_cygnus_phy_driver);
144 
145 MODULE_DESCRIPTION("Broadcom Cygnus internal PHY driver");
146 MODULE_LICENSE("GPL v2");
147 MODULE_AUTHOR("Broadcom Corporation");
148