Commit | Line | Data |
---|---|---|
a2443fd1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
8e185d69 AP |
2 | /* |
3 | * Copyright (C) 2015 Broadcom Corporation | |
8e185d69 AP |
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 */ | |
79fb218d | 56 | rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10); |
8e185d69 AP |
57 | if (rc < 0) |
58 | return rc; | |
59 | ||
60 | /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ | |
79fb218d | 61 | rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10); |
8e185d69 AP |
62 | if (rc < 0) |
63 | return rc; | |
64 | ||
65 | /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ | |
79fb218d | 66 | rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00); |
8e185d69 AP |
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 */ | |
99cec8a4 | 99 | rc = bcm_phy_set_eee(phydev, true); |
8e185d69 AP |
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", | |
529ed127 | 129 | .features = PHY_GBIT_FEATURES, |
8e185d69 | 130 | .config_init = bcm_cygnus_config_init, |
8e185d69 AP |
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"); |