aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-10-08 07:46:03 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-08 07:46:03 -0400
commit494f8eb9b616590c78bb1974aed835a842f012b6 (patch)
treecd3753e0b39d3072dc87e55a53d5f37b2dd39477
parent91d2f14bc38336177c2d65e0c2cbf6447133cee1 (diff)
parent9200c27a1cc7ac719e4c43411e5a170144ba0ac5 (diff)
Merge branch 'broadcom-iproc'
Arun Parameswaran says: ==================== Add support for Broadcom's iProc MDIO and Cygnus Ethernet PHY This patchset adds support for the iProc MDIO interface and the Broadcom Cygnus SoC's internal Ethernet PHY. The internal Ethernet PHY(s) in the Cygnus SoC's are accessed via the MDIO interface found in most of the iProc based chips. The patch also consolidates the common API's used by the Broadcom phys to a common library. Existing Broadcom phy drivers have been modified to use the common library API's. This patch series is based on Linux v4.3-rc1 and is avaliable in: https://github.com/Broadcom/cygnus-linux/tree/cygnus-net-phy-mdio-v3 The Ethernet driver for the iProc family will be submitted soon, as will the device tree configurations for the different iProc family SoCs. Changes from v2: - Modified drivers/net/phy/Kconfig to modify the BCM_CYGNUS_PHY driver to 'depends on MDIO_BCM_IPROC' instead of 'select'. - Added github branch to the cover letter Changes from v1: - Updated device tree documentation for the iProc MDIO driver based on Florian's feedback. - Moved the core register defines from the Cygnus PHY driver to 'include/linux/brcmphy.h' based on Florian's feedback. - Created a new patch/commit to modify the bcm7xxx phy driver to use the new core register defines. - Modified the Kconfig entry for the Broadcom PHY library to 'tristate' instead of 'bool' ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/brcm,iproc-mdio.txt23
-rw-r--r--drivers/net/phy/Kconfig28
-rw-r--r--drivers/net/phy/Makefile3
-rw-r--r--drivers/net/phy/bcm-cygnus.c158
-rw-r--r--drivers/net/phy/bcm-phy-lib.c208
-rw-r--r--drivers/net/phy/bcm-phy-lib.h37
-rw-r--r--drivers/net/phy/bcm63xx.c38
-rw-r--r--drivers/net/phy/bcm7xxx.c136
-rw-r--r--drivers/net/phy/broadcom.c149
-rw-r--r--drivers/net/phy/mdio-bcm-iproc.c213
-rw-r--r--include/linux/brcmphy.h29
11 files changed, 760 insertions, 262 deletions
diff --git a/Documentation/devicetree/bindings/net/brcm,iproc-mdio.txt b/Documentation/devicetree/bindings/net/brcm,iproc-mdio.txt
new file mode 100644
index 000000000000..8ba9ed11d716
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,iproc-mdio.txt
@@ -0,0 +1,23 @@
1* Broadcom iProc MDIO bus controller
2
3Required properties:
4- compatible: should be "brcm,iproc-mdio"
5- reg: address and length of the register set for the MDIO interface
6- #size-cells: must be 1
7- #address-cells: must be 0
8
9Child nodes of this MDIO bus controller node are standard Ethernet PHY device
10nodes as described in Documentation/devicetree/bindings/net/phy.txt
11
12Example:
13
14mdio@18002000 {
15 compatible = "brcm,iproc-mdio";
16 reg = <0x18002000 0x8>;
17 #size-cells = <1>;
18 #address-cells = <0>;
19
20 enet-gphy@0 {
21 reg = <0>;
22 };
23};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index c5ad98ace5d0..9d097ae54fb2 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -69,20 +69,39 @@ config SMSC_PHY
69 ---help--- 69 ---help---
70 Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs 70 Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
71 71
72config BCM_NET_PHYLIB
73 tristate
74
72config BROADCOM_PHY 75config BROADCOM_PHY
73 tristate "Drivers for Broadcom PHYs" 76 tristate "Drivers for Broadcom PHYs"
77 select BCM_NET_PHYLIB
74 ---help--- 78 ---help---
75 Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, 79 Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
76 BCM5481 and BCM5482 PHYs. 80 BCM5481 and BCM5482 PHYs.
77 81
82config BCM_CYGNUS_PHY
83 tristate "Drivers for Broadcom Cygnus SoC internal PHY"
84 depends on ARCH_BCM_CYGNUS || COMPILE_TEST
85 depends on MDIO_BCM_IPROC
86 select BCM_NET_PHYLIB
87 ---help---
88 This PHY driver is for the 1G internal PHYs of the Broadcom
89 Cygnus Family SoC.
90
91 Currently supports internal PHY's used in the BCM11300,
92 BCM11320, BCM11350, BCM11360, BCM58300, BCM58302,
93 BCM58303 & BCM58305 Broadcom Cygnus SoCs.
94
78config BCM63XX_PHY 95config BCM63XX_PHY
79 tristate "Drivers for Broadcom 63xx SOCs internal PHY" 96 tristate "Drivers for Broadcom 63xx SOCs internal PHY"
80 depends on BCM63XX 97 depends on BCM63XX
98 select BCM_NET_PHYLIB
81 ---help--- 99 ---help---
82 Currently supports the 6348 and 6358 PHYs. 100 Currently supports the 6348 and 6358 PHYs.
83 101
84config BCM7XXX_PHY 102config BCM7XXX_PHY
85 tristate "Drivers for Broadcom 7xxx SOCs internal PHYs" 103 tristate "Drivers for Broadcom 7xxx SOCs internal PHYs"
104 select BCM_NET_PHYLIB
86 ---help--- 105 ---help---
87 Currently supports the BCM7366, BCM7439, BCM7445, and 106 Currently supports the BCM7366, BCM7439, BCM7445, and
88 40nm and 65nm generation of BCM7xxx Set Top Box SoCs. 107 40nm and 65nm generation of BCM7xxx Set Top Box SoCs.
@@ -225,6 +244,15 @@ config MDIO_BCM_UNIMAC
225 This hardware can be found in the Broadcom GENET Ethernet MAC 244 This hardware can be found in the Broadcom GENET Ethernet MAC
226 controllers as well as some Broadcom Ethernet switches such as the 245 controllers as well as some Broadcom Ethernet switches such as the
227 Starfighter 2 switches. 246 Starfighter 2 switches.
247
248config MDIO_BCM_IPROC
249 tristate "Broadcom iProc MDIO bus controller"
250 depends on ARCH_BCM_IPROC || COMPILE_TEST
251 depends on HAS_IOMEM && OF_MDIO
252 help
253 This module provides a driver for the MDIO busses found in the
254 Broadcom iProc SoC's.
255
228endif # PHYLIB 256endif # PHYLIB
229 257
230config MICREL_KS8995MA 258config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 87f079c4b2c7..7655d47ad8d8 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,10 +12,12 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o
12obj-$(CONFIG_SMSC_PHY) += smsc.o 12obj-$(CONFIG_SMSC_PHY) += smsc.o
13obj-$(CONFIG_TERANETICS_PHY) += teranetics.o 13obj-$(CONFIG_TERANETICS_PHY) += teranetics.o
14obj-$(CONFIG_VITESSE_PHY) += vitesse.o 14obj-$(CONFIG_VITESSE_PHY) += vitesse.o
15obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o
15obj-$(CONFIG_BROADCOM_PHY) += broadcom.o 16obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
16obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o 17obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
17obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o 18obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
18obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o 19obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
20obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o
19obj-$(CONFIG_ICPLUS_PHY) += icplus.o 21obj-$(CONFIG_ICPLUS_PHY) += icplus.o
20obj-$(CONFIG_REALTEK_PHY) += realtek.o 22obj-$(CONFIG_REALTEK_PHY) += realtek.o
21obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o 23obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
@@ -38,3 +40,4 @@ obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
38obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o 40obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
39obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o 41obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
40obj-$(CONFIG_MICROCHIP_PHY) += microchip.o 42obj-$(CONFIG_MICROCHIP_PHY) += microchip.o
43obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c
new file mode 100644
index 000000000000..49bbc6826883
--- /dev/null
+++ b/drivers/net/phy/bcm-cygnus.c
@@ -0,0 +1,158 @@
1/*
2 * 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.
12 */
13
14/* Broadcom Cygnus SoC internal transceivers support. */
15#include "bcm-phy-lib.h"
16#include <linux/brcmphy.h>
17#include <linux/module.h>
18#include <linux/netdevice.h>
19#include <linux/phy.h>
20
21/* Broadcom Cygnus Phy specific registers */
22#define MII_BCM_CYGNUS_AFE_VDAC_ICTRL_0 0x91E5 /* VDAL Control register */
23
24static int bcm_cygnus_afe_config(struct phy_device *phydev)
25{
26 int rc;
27
28 /* ensure smdspclk is enabled */
29 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, 0x0c30);
30 if (rc < 0)
31 return rc;
32
33 /* AFE_VDAC_ICTRL_0 bit 7:4 Iq=1100 for 1g 10bt, normal modes */
34 rc = bcm_phy_write_misc(phydev, 0x39, 0x01, 0xA7C8);
35 if (rc < 0)
36 return rc;
37
38 /* AFE_HPF_TRIM_OTHERS bit11=1, short cascode enable for all modes*/
39 rc = bcm_phy_write_misc(phydev, 0x3A, 0x00, 0x0803);
40 if (rc < 0)
41 return rc;
42
43 /* AFE_TX_CONFIG_1 bit 7:4 Iq=1100 for test modes */
44 rc = bcm_phy_write_misc(phydev, 0x3A, 0x01, 0xA740);
45 if (rc < 0)
46 return rc;
47
48 /* AFE TEMPSEN_OTHERS rcal_HT, rcal_LT 10000 */
49 rc = bcm_phy_write_misc(phydev, 0x3A, 0x03, 0x8400);
50 if (rc < 0)
51 return rc;
52
53 /* AFE_FUTURE_RSV bit 2:0 rccal <2:0>=100 */
54 rc = bcm_phy_write_misc(phydev, 0x3B, 0x00, 0x0004);
55 if (rc < 0)
56 return rc;
57
58 /* Adjust bias current trim to overcome digital offSet */
59 rc = phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x02);
60 if (rc < 0)
61 return rc;
62
63 /* make rcal=100, since rdb default is 000 */
64 rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10);
65 if (rc < 0)
66 return rc;
67
68 /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */
69 rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10);
70 if (rc < 0)
71 return rc;
72
73 /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */
74 rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00);
75
76 return 0;
77}
78
79static int bcm_cygnus_config_init(struct phy_device *phydev)
80{
81 int reg, rc;
82
83 reg = phy_read(phydev, MII_BCM54XX_ECR);
84 if (reg < 0)
85 return reg;
86
87 /* Mask interrupts globally. */
88 reg |= MII_BCM54XX_ECR_IM;
89 rc = phy_write(phydev, MII_BCM54XX_ECR, reg);
90 if (rc)
91 return rc;
92
93 /* Unmask events of interest */
94 reg = ~(MII_BCM54XX_INT_DUPLEX |
95 MII_BCM54XX_INT_SPEED |
96 MII_BCM54XX_INT_LINK);
97 rc = phy_write(phydev, MII_BCM54XX_IMR, reg);
98 if (rc)
99 return rc;
100
101 /* Apply AFE settings for the PHY */
102 rc = bcm_cygnus_afe_config(phydev);
103 if (rc)
104 return rc;
105
106 /* Advertise EEE */
107 rc = bcm_phy_enable_eee(phydev);
108 if (rc)
109 return rc;
110
111 /* Enable APD */
112 return bcm_phy_enable_apd(phydev, false);
113}
114
115static int bcm_cygnus_resume(struct phy_device *phydev)
116{
117 int rc;
118
119 genphy_resume(phydev);
120
121 /* Re-initialize the PHY to apply AFE work-arounds and
122 * configurations when coming out of suspend.
123 */
124 rc = bcm_cygnus_config_init(phydev);
125 if (rc)
126 return rc;
127
128 /* restart auto negotiation with the new settings */
129 return genphy_config_aneg(phydev);
130}
131
132static struct phy_driver bcm_cygnus_phy_driver[] = {
133{
134 .phy_id = PHY_ID_BCM_CYGNUS,
135 .phy_id_mask = 0xfffffff0,
136 .name = "Broadcom Cygnus PHY",
137 .features = PHY_GBIT_FEATURES |
138 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
139 .config_init = bcm_cygnus_config_init,
140 .config_aneg = genphy_config_aneg,
141 .read_status = genphy_read_status,
142 .ack_interrupt = bcm_phy_ack_intr,
143 .config_intr = bcm_phy_config_intr,
144 .suspend = genphy_suspend,
145 .resume = bcm_cygnus_resume,
146} };
147
148static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
149 { PHY_ID_BCM_CYGNUS, 0xfffffff0, },
150 { }
151};
152MODULE_DEVICE_TABLE(mdio, bcm_cygnus_phy_tbl);
153
154module_phy_driver(bcm_cygnus_phy_driver);
155
156MODULE_DESCRIPTION("Broadcom Cygnus internal PHY driver");
157MODULE_LICENSE("GPL v2");
158MODULE_AUTHOR("Broadcom Corporation");
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
new file mode 100644
index 000000000000..dd79ea6ba023
--- /dev/null
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -0,0 +1,208 @@
1/*
2 * 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.
12 */
13
14#include "bcm-phy-lib.h"
15#include <linux/brcmphy.h>
16#include <linux/export.h>
17#include <linux/mdio.h>
18#include <linux/phy.h>
19
20#define MII_BCM_CHANNEL_WIDTH 0x2000
21#define BCM_CL45VEN_EEE_ADV 0x3c
22
23int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
24{
25 int rc;
26
27 rc = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
28 if (rc < 0)
29 return rc;
30
31 return phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
32}
33EXPORT_SYMBOL_GPL(bcm_phy_write_exp);
34
35int bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
36{
37 int val;
38
39 val = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
40 if (val < 0)
41 return val;
42
43 val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
44
45 /* Restore default value. It's O.K. if this write fails. */
46 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
47
48 return val;
49}
50EXPORT_SYMBOL_GPL(bcm_phy_read_exp);
51
52int bcm_phy_write_misc(struct phy_device *phydev,
53 u16 reg, u16 chl, u16 val)
54{
55 int rc;
56 int tmp;
57
58 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
59 MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
60 if (rc < 0)
61 return rc;
62
63 tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
64 tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
65 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
66 if (rc < 0)
67 return rc;
68
69 tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
70 rc = bcm_phy_write_exp(phydev, tmp, val);
71
72 return rc;
73}
74EXPORT_SYMBOL_GPL(bcm_phy_write_misc);
75
76int bcm_phy_read_misc(struct phy_device *phydev,
77 u16 reg, u16 chl)
78{
79 int rc;
80 int tmp;
81
82 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
83 MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
84 if (rc < 0)
85 return rc;
86
87 tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
88 tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
89 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
90 if (rc < 0)
91 return rc;
92
93 tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
94 rc = bcm_phy_read_exp(phydev, tmp);
95
96 return rc;
97}
98EXPORT_SYMBOL_GPL(bcm_phy_read_misc);
99
100int bcm_phy_ack_intr(struct phy_device *phydev)
101{
102 int reg;
103
104 /* Clear pending interrupts. */
105 reg = phy_read(phydev, MII_BCM54XX_ISR);
106 if (reg < 0)
107 return reg;
108
109 return 0;
110}
111EXPORT_SYMBOL_GPL(bcm_phy_ack_intr);
112
113int bcm_phy_config_intr(struct phy_device *phydev)
114{
115 int reg;
116
117 reg = phy_read(phydev, MII_BCM54XX_ECR);
118 if (reg < 0)
119 return reg;
120
121 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
122 reg &= ~MII_BCM54XX_ECR_IM;
123 else
124 reg |= MII_BCM54XX_ECR_IM;
125
126 return phy_write(phydev, MII_BCM54XX_ECR, reg);
127}
128EXPORT_SYMBOL_GPL(bcm_phy_config_intr);
129
130int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow)
131{
132 phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
133 return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
134}
135EXPORT_SYMBOL_GPL(bcm_phy_read_shadow);
136
137int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
138 u16 val)
139{
140 return phy_write(phydev, MII_BCM54XX_SHD,
141 MII_BCM54XX_SHD_WRITE |
142 MII_BCM54XX_SHD_VAL(shadow) |
143 MII_BCM54XX_SHD_DATA(val));
144}
145EXPORT_SYMBOL_GPL(bcm_phy_write_shadow);
146
147int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down)
148{
149 int val;
150
151 if (dll_pwr_down) {
152 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
153 if (val < 0)
154 return val;
155
156 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
157 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
158 }
159
160 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
161 if (val < 0)
162 return val;
163
164 /* Clear APD bits */
165 val &= BCM_APD_CLR_MASK;
166
167 if (phydev->autoneg == AUTONEG_ENABLE)
168 val |= BCM54XX_SHD_APD_EN;
169 else
170 val |= BCM_NO_ANEG_APD_EN;
171
172 /* Enable energy detect single link pulse for easy wakeup */
173 val |= BCM_APD_SINGLELP_EN;
174
175 /* Enable Auto Power-Down (APD) for the PHY */
176 return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
177}
178EXPORT_SYMBOL_GPL(bcm_phy_enable_apd);
179
180int bcm_phy_enable_eee(struct phy_device *phydev)
181{
182 int val;
183
184 /* Enable EEE at PHY level */
185 val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
186 MDIO_MMD_AN, phydev->addr);
187 if (val < 0)
188 return val;
189
190 val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
191
192 phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
193 MDIO_MMD_AN, phydev->addr, (u32)val);
194
195 /* Advertise EEE */
196 val = phy_read_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
197 MDIO_MMD_AN, phydev->addr);
198 if (val < 0)
199 return val;
200
201 val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
202
203 phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
204 MDIO_MMD_AN, phydev->addr, (u32)val);
205
206 return 0;
207}
208EXPORT_SYMBOL_GPL(bcm_phy_enable_eee);
diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h
new file mode 100644
index 000000000000..b2091c88b44d
--- /dev/null
+++ b/drivers/net/phy/bcm-phy-lib.h
@@ -0,0 +1,37 @@
1/*
2 * 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.
12 */
13
14#ifndef _LINUX_BCM_PHY_LIB_H
15#define _LINUX_BCM_PHY_LIB_H
16
17#include <linux/phy.h>
18
19int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
20int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
21
22int bcm_phy_write_misc(struct phy_device *phydev,
23 u16 reg, u16 chl, u16 value);
24int bcm_phy_read_misc(struct phy_device *phydev,
25 u16 reg, u16 chl);
26
27int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
28 u16 val);
29int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow);
30
31int bcm_phy_ack_intr(struct phy_device *phydev);
32int bcm_phy_config_intr(struct phy_device *phydev);
33
34int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
35
36int bcm_phy_enable_eee(struct phy_device *phydev);
37#endif /* _LINUX_BCM_PHY_LIB_H */
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index 830ec31f952f..86b28052bf06 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -6,6 +6,7 @@
6 * as published by the Free Software Foundation; either version 6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version. 7 * 2 of the License, or (at your option) any later version.
8 */ 8 */
9#include "bcm-phy-lib.h"
9#include <linux/module.h> 10#include <linux/module.h>
10#include <linux/phy.h> 11#include <linux/phy.h>
11 12
@@ -42,35 +43,6 @@ static int bcm63xx_config_init(struct phy_device *phydev)
42 return phy_write(phydev, MII_BCM63XX_IR, reg); 43 return phy_write(phydev, MII_BCM63XX_IR, reg);
43} 44}
44 45
45static int bcm63xx_ack_interrupt(struct phy_device *phydev)
46{
47 int reg;
48
49 /* Clear pending interrupts. */
50 reg = phy_read(phydev, MII_BCM63XX_IR);
51 if (reg < 0)
52 return reg;
53
54 return 0;
55}
56
57static int bcm63xx_config_intr(struct phy_device *phydev)
58{
59 int reg, err;
60
61 reg = phy_read(phydev, MII_BCM63XX_IR);
62 if (reg < 0)
63 return reg;
64
65 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
66 reg &= ~MII_BCM63XX_IR_GMASK;
67 else
68 reg |= MII_BCM63XX_IR_GMASK;
69
70 err = phy_write(phydev, MII_BCM63XX_IR, reg);
71 return err;
72}
73
74static struct phy_driver bcm63xx_driver[] = { 46static struct phy_driver bcm63xx_driver[] = {
75{ 47{
76 .phy_id = 0x00406000, 48 .phy_id = 0x00406000,
@@ -82,8 +54,8 @@ static struct phy_driver bcm63xx_driver[] = {
82 .config_init = bcm63xx_config_init, 54 .config_init = bcm63xx_config_init,
83 .config_aneg = genphy_config_aneg, 55 .config_aneg = genphy_config_aneg,
84 .read_status = genphy_read_status, 56 .read_status = genphy_read_status,
85 .ack_interrupt = bcm63xx_ack_interrupt, 57 .ack_interrupt = bcm_phy_ack_intr,
86 .config_intr = bcm63xx_config_intr, 58 .config_intr = bcm_phy_config_intr,
87 .driver = { .owner = THIS_MODULE }, 59 .driver = { .owner = THIS_MODULE },
88}, { 60}, {
89 /* same phy as above, with just a different OUI */ 61 /* same phy as above, with just a different OUI */
@@ -95,8 +67,8 @@ static struct phy_driver bcm63xx_driver[] = {
95 .config_init = bcm63xx_config_init, 67 .config_init = bcm63xx_config_init,
96 .config_aneg = genphy_config_aneg, 68 .config_aneg = genphy_config_aneg,
97 .read_status = genphy_read_status, 69 .read_status = genphy_read_status,
98 .ack_interrupt = bcm63xx_ack_interrupt, 70 .ack_interrupt = bcm_phy_ack_intr,
99 .config_intr = bcm63xx_config_intr, 71 .config_intr = bcm_phy_config_intr,
100 .driver = { .owner = THIS_MODULE }, 72 .driver = { .owner = THIS_MODULE },
101} }; 73} };
102 74
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 6b701b3ded74..03d4809a9126 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -12,12 +12,12 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/phy.h> 13#include <linux/phy.h>
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include "bcm-phy-lib.h"
15#include <linux/bitops.h> 16#include <linux/bitops.h>
16#include <linux/brcmphy.h> 17#include <linux/brcmphy.h>
17#include <linux/mdio.h> 18#include <linux/mdio.h>
18 19
19/* Broadcom BCM7xxx internal PHY registers */ 20/* Broadcom BCM7xxx internal PHY registers */
20#define MII_BCM7XXX_CHANNEL_WIDTH 0x2000
21 21
22/* 40nm only register definitions */ 22/* 40nm only register definitions */
23#define MII_BCM7XXX_100TX_AUX_CTL 0x10 23#define MII_BCM7XXX_100TX_AUX_CTL 0x10
@@ -25,7 +25,6 @@
25#define MII_BCM7XXX_100TX_DISC 0x14 25#define MII_BCM7XXX_100TX_DISC 0x14
26#define MII_BCM7XXX_AUX_MODE 0x1d 26#define MII_BCM7XXX_AUX_MODE 0x1d
27#define MII_BCM7XX_64CLK_MDIO BIT(12) 27#define MII_BCM7XX_64CLK_MDIO BIT(12)
28#define MII_BCM7XXX_CORE_BASE1E 0x1e
29#define MII_BCM7XXX_TEST 0x1f 28#define MII_BCM7XXX_TEST 0x1f
30#define MII_BCM7XXX_SHD_MODE_2 BIT(2) 29#define MII_BCM7XXX_SHD_MODE_2 BIT(2)
31 30
@@ -46,39 +45,13 @@
46#define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3) 45#define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3)
47#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) 46#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0)
48 47
49#define CORE_EXPB0 0xb0
50
51static void phy_write_exp(struct phy_device *phydev,
52 u16 reg, u16 value)
53{
54 phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg);
55 phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
56}
57
58static void phy_write_misc(struct phy_device *phydev,
59 u16 reg, u16 chl, u16 value)
60{
61 int tmp;
62
63 phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
64
65 tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
66 tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
67 phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
68
69 tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
70 phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
71
72 phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
73}
74
75static void r_rc_cal_reset(struct phy_device *phydev) 48static void r_rc_cal_reset(struct phy_device *phydev)
76{ 49{
77 /* Reset R_CAL/RC_CAL Engine */ 50 /* Reset R_CAL/RC_CAL Engine */
78 phy_write_exp(phydev, 0x00b0, 0x0010); 51 bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
79 52
80 /* Disable Reset R_AL/RC_CAL Engine */ 53 /* Disable Reset R_AL/RC_CAL Engine */
81 phy_write_exp(phydev, 0x00b0, 0x0000); 54 bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
82} 55}
83 56
84static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) 57static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
@@ -86,38 +59,38 @@ static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
86 /* Increase VCO range to prevent unlocking problem of PLL at low 59 /* Increase VCO range to prevent unlocking problem of PLL at low
87 * temp 60 * temp
88 */ 61 */
89 phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); 62 bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
90 63
91 /* Change Ki to 011 */ 64 /* Change Ki to 011 */
92 phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); 65 bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
93 66
94 /* Disable loading of TVCO buffer to bandgap, set bandgap trim 67 /* Disable loading of TVCO buffer to bandgap, set bandgap trim
95 * to 111 68 * to 111
96 */ 69 */
97 phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); 70 bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
98 71
99 /* Adjust bias current trim by -3 */ 72 /* Adjust bias current trim by -3 */
100 phy_write_misc(phydev, DSP_TAP10, 0x690b); 73 bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
101 74
102 /* Switch to CORE_BASE1E */ 75 /* Switch to CORE_BASE1E */
103 phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd); 76 phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd);
104 77
105 r_rc_cal_reset(phydev); 78 r_rc_cal_reset(phydev);
106 79
107 /* write AFE_RXCONFIG_0 */ 80 /* write AFE_RXCONFIG_0 */
108 phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); 81 bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
109 82
110 /* write AFE_RXCONFIG_1 */ 83 /* write AFE_RXCONFIG_1 */
111 phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); 84 bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
112 85
113 /* write AFE_RX_LP_COUNTER */ 86 /* write AFE_RX_LP_COUNTER */
114 phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 87 bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
115 88
116 /* write AFE_HPF_TRIM_OTHERS */ 89 /* write AFE_HPF_TRIM_OTHERS */
117 phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); 90 bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
118 91
119 /* write AFTE_TX_CONFIG */ 92 /* write AFTE_TX_CONFIG */
120 phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); 93 bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
121 94
122 return 0; 95 return 0;
123} 96}
@@ -125,36 +98,36 @@ static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
125static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) 98static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
126{ 99{
127 /* AFE_RXCONFIG_0 */ 100 /* AFE_RXCONFIG_0 */
128 phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15); 101 bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
129 102
130 /* AFE_RXCONFIG_1 */ 103 /* AFE_RXCONFIG_1 */
131 phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f); 104 bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
132 105
133 /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */ 106 /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
134 phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003); 107 bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
135 108
136 /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */ 109 /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
137 phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 110 bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
138 111
139 /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */ 112 /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
140 phy_write_misc(phydev, AFE_TX_CONFIG, 0x431); 113 bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
141 114
142 /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */ 115 /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
143 phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da); 116 bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
144 117
145 /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */ 118 /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
146 phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020); 119 bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
147 120
148 /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal 121 /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
149 * offset for HT=0 code 122 * offset for HT=0 code
150 */ 123 */
151 phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3); 124 bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
152 125
153 /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */ 126 /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
154 phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010); 127 phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
155 128
156 /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */ 129 /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
157 phy_write_misc(phydev, DSP_TAP10, 0x011b); 130 bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
158 131
159 /* Reset R_CAL/RC_CAL engine */ 132 /* Reset R_CAL/RC_CAL engine */
160 r_rc_cal_reset(phydev); 133 r_rc_cal_reset(phydev);
@@ -165,24 +138,24 @@ static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
165static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev) 138static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
166{ 139{
167 /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */ 140 /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
168 phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f); 141 bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
169 142
170 /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */ 143 /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
171 phy_write_misc(phydev, AFE_TX_CONFIG, 0x431); 144 bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
172 145
173 /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */ 146 /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
174 phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da); 147 bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
175 148
176 /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal 149 /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
177 * offset for HT=0 code 150 * offset for HT=0 code
178 */ 151 */
179 phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3); 152 bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
180 153
181 /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */ 154 /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
182 phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010); 155 phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
183 156
184 /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */ 157 /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
185 phy_write_misc(phydev, DSP_TAP10, 0x011b); 158 bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
186 159
187 /* Reset R_CAL/RC_CAL engine */ 160 /* Reset R_CAL/RC_CAL engine */
188 r_rc_cal_reset(phydev); 161 r_rc_cal_reset(phydev);
@@ -190,53 +163,6 @@ static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
190 return 0; 163 return 0;
191} 164}
192 165
193static int bcm7xxx_apd_enable(struct phy_device *phydev)
194{
195 int val;
196
197 /* Enable powering down of the DLL during auto-power down */
198 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
199 if (val < 0)
200 return val;
201
202 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
203 bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
204
205 /* Enable auto-power down */
206 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
207 if (val < 0)
208 return val;
209
210 val |= BCM54XX_SHD_APD_EN;
211 return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
212}
213
214static int bcm7xxx_eee_enable(struct phy_device *phydev)
215{
216 int val;
217
218 val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
219 MDIO_MMD_AN, phydev->addr);
220 if (val < 0)
221 return val;
222
223 /* Enable general EEE feature at the PHY level */
224 val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
225
226 phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
227 MDIO_MMD_AN, phydev->addr, val);
228
229 /* Advertise supported modes */
230 val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
231 MDIO_MMD_AN, phydev->addr);
232
233 val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
234 phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
235 MDIO_MMD_AN, phydev->addr, val);
236
237 return 0;
238}
239
240static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 166static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
241{ 167{
242 u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags); 168 u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
@@ -273,11 +199,11 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
273 if (ret) 199 if (ret)
274 return ret; 200 return ret;
275 201
276 ret = bcm7xxx_eee_enable(phydev); 202 ret = bcm_phy_enable_eee(phydev);
277 if (ret) 203 if (ret)
278 return ret; 204 return ret;
279 205
280 return bcm7xxx_apd_enable(phydev); 206 return bcm_phy_enable_apd(phydev, true);
281} 207}
282 208
283static int bcm7xxx_28nm_resume(struct phy_device *phydev) 209static int bcm7xxx_28nm_resume(struct phy_device *phydev)
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 9c71295f2fef..07a6119121c3 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -14,6 +14,7 @@
14 * 2 of the License, or (at your option) any later version. 14 * 2 of the License, or (at your option) any later version.
15 */ 15 */
16 16
17#include "bcm-phy-lib.h"
17#include <linux/module.h> 18#include <linux/module.h>
18#include <linux/phy.h> 19#include <linux/phy.h>
19#include <linux/brcmphy.h> 20#include <linux/brcmphy.h>
@@ -29,39 +30,6 @@ MODULE_DESCRIPTION("Broadcom PHY driver");
29MODULE_AUTHOR("Maciej W. Rozycki"); 30MODULE_AUTHOR("Maciej W. Rozycki");
30MODULE_LICENSE("GPL"); 31MODULE_LICENSE("GPL");
31 32
32/* Indirect register access functions for the Expansion Registers */
33static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
34{
35 int val;
36
37 val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
38 if (val < 0)
39 return val;
40
41 val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
42
43 /* Restore default value. It's O.K. if this write fails. */
44 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
45
46 return val;
47}
48
49static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
50{
51 int ret;
52
53 ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
54 if (ret < 0)
55 return ret;
56
57 ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
58
59 /* Restore default value. It's O.K. if this write fails. */
60 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
61
62 return ret;
63}
64
65static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) 33static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
66{ 34{
67 return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); 35 return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
@@ -72,28 +40,28 @@ static int bcm50610_a0_workaround(struct phy_device *phydev)
72{ 40{
73 int err; 41 int err;
74 42
75 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, 43 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
76 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | 44 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
77 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); 45 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
78 if (err < 0) 46 if (err < 0)
79 return err; 47 return err;
80 48
81 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, 49 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
82 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); 50 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
83 if (err < 0) 51 if (err < 0)
84 return err; 52 return err;
85 53
86 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, 54 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
87 MII_BCM54XX_EXP_EXP75_VDACCTRL); 55 MII_BCM54XX_EXP_EXP75_VDACCTRL);
88 if (err < 0) 56 if (err < 0)
89 return err; 57 return err;
90 58
91 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, 59 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
92 MII_BCM54XX_EXP_EXP96_MYST); 60 MII_BCM54XX_EXP_EXP96_MYST);
93 if (err < 0) 61 if (err < 0)
94 return err; 62 return err;
95 63
96 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, 64 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
97 MII_BCM54XX_EXP_EXP97_MYST); 65 MII_BCM54XX_EXP_EXP97_MYST);
98 66
99 return err; 67 return err;
@@ -114,7 +82,7 @@ static int bcm54xx_phydsp_config(struct phy_device *phydev)
114 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 82 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
115 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) { 83 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
116 /* Clear bit 9 to fix a phy interop issue. */ 84 /* Clear bit 9 to fix a phy interop issue. */
117 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08, 85 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
118 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ); 86 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
119 if (err < 0) 87 if (err < 0)
120 goto error; 88 goto error;
@@ -129,12 +97,12 @@ static int bcm54xx_phydsp_config(struct phy_device *phydev)
129 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { 97 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
130 int val; 98 int val;
131 99
132 val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75); 100 val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
133 if (val < 0) 101 if (val < 0)
134 goto error; 102 goto error;
135 103
136 val |= MII_BCM54XX_EXP_EXP75_CM_OSC; 104 val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
137 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val); 105 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
138 } 106 }
139 107
140error: 108error:
@@ -159,7 +127,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
159 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M) 127 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
160 return; 128 return;
161 129
162 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3); 130 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
163 if (val < 0) 131 if (val < 0)
164 return; 132 return;
165 133
@@ -190,9 +158,9 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
190 val |= BCM54XX_SHD_SCR3_TRDDAPD; 158 val |= BCM54XX_SHD_SCR3_TRDDAPD;
191 159
192 if (orig != val) 160 if (orig != val)
193 bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val); 161 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
194 162
195 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD); 163 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
196 if (val < 0) 164 if (val < 0)
197 return; 165 return;
198 166
@@ -204,7 +172,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
204 val &= ~BCM54XX_SHD_APD_EN; 172 val &= ~BCM54XX_SHD_APD_EN;
205 173
206 if (orig != val) 174 if (orig != val)
207 bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val); 175 bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
208} 176}
209 177
210static int bcm54xx_config_init(struct phy_device *phydev) 178static int bcm54xx_config_init(struct phy_device *phydev)
@@ -232,7 +200,7 @@ static int bcm54xx_config_init(struct phy_device *phydev)
232 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 200 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
233 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 201 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
234 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) 202 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
235 bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0); 203 bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
236 204
237 if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || 205 if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
238 (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || 206 (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
@@ -254,8 +222,8 @@ static int bcm5482_config_init(struct phy_device *phydev)
254 /* 222 /*
255 * Enable secondary SerDes and its use as an LED source 223 * Enable secondary SerDes and its use as an LED source
256 */ 224 */
257 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD); 225 reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
258 bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD, 226 bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
259 reg | 227 reg |
260 BCM5482_SHD_SSD_LEDM | 228 BCM5482_SHD_SSD_LEDM |
261 BCM5482_SHD_SSD_EN); 229 BCM5482_SHD_SSD_EN);
@@ -264,10 +232,10 @@ static int bcm5482_config_init(struct phy_device *phydev)
264 * Enable SGMII slave mode and auto-detection 232 * Enable SGMII slave mode and auto-detection
265 */ 233 */
266 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; 234 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
267 err = bcm54xx_exp_read(phydev, reg); 235 err = bcm_phy_read_exp(phydev, reg);
268 if (err < 0) 236 if (err < 0)
269 return err; 237 return err;
270 err = bcm54xx_exp_write(phydev, reg, err | 238 err = bcm_phy_write_exp(phydev, reg, err |
271 BCM5482_SSD_SGMII_SLAVE_EN | 239 BCM5482_SSD_SGMII_SLAVE_EN |
272 BCM5482_SSD_SGMII_SLAVE_AD); 240 BCM5482_SSD_SGMII_SLAVE_AD);
273 if (err < 0) 241 if (err < 0)
@@ -277,10 +245,10 @@ static int bcm5482_config_init(struct phy_device *phydev)
277 * Disable secondary SerDes powerdown 245 * Disable secondary SerDes powerdown
278 */ 246 */
279 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; 247 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
280 err = bcm54xx_exp_read(phydev, reg); 248 err = bcm_phy_read_exp(phydev, reg);
281 if (err < 0) 249 if (err < 0)
282 return err; 250 return err;
283 err = bcm54xx_exp_write(phydev, reg, 251 err = bcm_phy_write_exp(phydev, reg,
284 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); 252 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
285 if (err < 0) 253 if (err < 0)
286 return err; 254 return err;
@@ -288,15 +256,15 @@ static int bcm5482_config_init(struct phy_device *phydev)
288 /* 256 /*
289 * Select 1000BASE-X register set (primary SerDes) 257 * Select 1000BASE-X register set (primary SerDes)
290 */ 258 */
291 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE); 259 reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
292 bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE, 260 bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
293 reg | BCM5482_SHD_MODE_1000BX); 261 reg | BCM5482_SHD_MODE_1000BX);
294 262
295 /* 263 /*
296 * LED1=ACTIVITYLED, LED3=LINKSPD[2] 264 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
297 * (Use LED1 as secondary SerDes ACTIVITY LED) 265 * (Use LED1 as secondary SerDes ACTIVITY LED)
298 */ 266 */
299 bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1, 267 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
300 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | 268 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
301 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); 269 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
302 270
@@ -334,35 +302,6 @@ static int bcm5482_read_status(struct phy_device *phydev)
334 return err; 302 return err;
335} 303}
336 304
337static int bcm54xx_ack_interrupt(struct phy_device *phydev)
338{
339 int reg;
340
341 /* Clear pending interrupts. */
342 reg = phy_read(phydev, MII_BCM54XX_ISR);
343 if (reg < 0)
344 return reg;
345
346 return 0;
347}
348
349static int bcm54xx_config_intr(struct phy_device *phydev)
350{
351 int reg, err;
352
353 reg = phy_read(phydev, MII_BCM54XX_ECR);
354 if (reg < 0)
355 return reg;
356
357 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
358 reg &= ~MII_BCM54XX_ECR_IM;
359 else
360 reg |= MII_BCM54XX_ECR_IM;
361
362 err = phy_write(phydev, MII_BCM54XX_ECR, reg);
363 return err;
364}
365
366static int bcm5481_config_aneg(struct phy_device *phydev) 305static int bcm5481_config_aneg(struct phy_device *phydev)
367{ 306{
368 int ret; 307 int ret;
@@ -519,8 +458,8 @@ static struct phy_driver broadcom_drivers[] = {
519 .config_init = bcm54xx_config_init, 458 .config_init = bcm54xx_config_init,
520 .config_aneg = genphy_config_aneg, 459 .config_aneg = genphy_config_aneg,
521 .read_status = genphy_read_status, 460 .read_status = genphy_read_status,
522 .ack_interrupt = bcm54xx_ack_interrupt, 461 .ack_interrupt = bcm_phy_ack_intr,
523 .config_intr = bcm54xx_config_intr, 462 .config_intr = bcm_phy_config_intr,
524 .driver = { .owner = THIS_MODULE }, 463 .driver = { .owner = THIS_MODULE },
525}, { 464}, {
526 .phy_id = PHY_ID_BCM5421, 465 .phy_id = PHY_ID_BCM5421,
@@ -532,8 +471,8 @@ static struct phy_driver broadcom_drivers[] = {
532 .config_init = bcm54xx_config_init, 471 .config_init = bcm54xx_config_init,
533 .config_aneg = genphy_config_aneg, 472 .config_aneg = genphy_config_aneg,
534 .read_status = genphy_read_status, 473 .read_status = genphy_read_status,
535 .ack_interrupt = bcm54xx_ack_interrupt, 474 .ack_interrupt = bcm_phy_ack_intr,
536 .config_intr = bcm54xx_config_intr, 475 .config_intr = bcm_phy_config_intr,
537 .driver = { .owner = THIS_MODULE }, 476 .driver = { .owner = THIS_MODULE },
538}, { 477}, {
539 .phy_id = PHY_ID_BCM5461, 478 .phy_id = PHY_ID_BCM5461,
@@ -545,8 +484,8 @@ static struct phy_driver broadcom_drivers[] = {
545 .config_init = bcm54xx_config_init, 484 .config_init = bcm54xx_config_init,
546 .config_aneg = genphy_config_aneg, 485 .config_aneg = genphy_config_aneg,
547 .read_status = genphy_read_status, 486 .read_status = genphy_read_status,
548 .ack_interrupt = bcm54xx_ack_interrupt, 487 .ack_interrupt = bcm_phy_ack_intr,
549 .config_intr = bcm54xx_config_intr, 488 .config_intr = bcm_phy_config_intr,
550 .driver = { .owner = THIS_MODULE }, 489 .driver = { .owner = THIS_MODULE },
551}, { 490}, {
552 .phy_id = PHY_ID_BCM54616S, 491 .phy_id = PHY_ID_BCM54616S,
@@ -558,8 +497,8 @@ static struct phy_driver broadcom_drivers[] = {
558 .config_init = bcm54xx_config_init, 497 .config_init = bcm54xx_config_init,
559 .config_aneg = genphy_config_aneg, 498 .config_aneg = genphy_config_aneg,
560 .read_status = genphy_read_status, 499 .read_status = genphy_read_status,
561 .ack_interrupt = bcm54xx_ack_interrupt, 500 .ack_interrupt = bcm_phy_ack_intr,
562 .config_intr = bcm54xx_config_intr, 501 .config_intr = bcm_phy_config_intr,
563 .driver = { .owner = THIS_MODULE }, 502 .driver = { .owner = THIS_MODULE },
564}, { 503}, {
565 .phy_id = PHY_ID_BCM5464, 504 .phy_id = PHY_ID_BCM5464,
@@ -571,8 +510,8 @@ static struct phy_driver broadcom_drivers[] = {
571 .config_init = bcm54xx_config_init, 510 .config_init = bcm54xx_config_init,
572 .config_aneg = genphy_config_aneg, 511 .config_aneg = genphy_config_aneg,
573 .read_status = genphy_read_status, 512 .read_status = genphy_read_status,
574 .ack_interrupt = bcm54xx_ack_interrupt, 513 .ack_interrupt = bcm_phy_ack_intr,
575 .config_intr = bcm54xx_config_intr, 514 .config_intr = bcm_phy_config_intr,
576 .driver = { .owner = THIS_MODULE }, 515 .driver = { .owner = THIS_MODULE },
577}, { 516}, {
578 .phy_id = PHY_ID_BCM5481, 517 .phy_id = PHY_ID_BCM5481,
@@ -584,8 +523,8 @@ static struct phy_driver broadcom_drivers[] = {
584 .config_init = bcm54xx_config_init, 523 .config_init = bcm54xx_config_init,
585 .config_aneg = bcm5481_config_aneg, 524 .config_aneg = bcm5481_config_aneg,
586 .read_status = genphy_read_status, 525 .read_status = genphy_read_status,
587 .ack_interrupt = bcm54xx_ack_interrupt, 526 .ack_interrupt = bcm_phy_ack_intr,
588 .config_intr = bcm54xx_config_intr, 527 .config_intr = bcm_phy_config_intr,
589 .driver = { .owner = THIS_MODULE }, 528 .driver = { .owner = THIS_MODULE },
590}, { 529}, {
591 .phy_id = PHY_ID_BCM5482, 530 .phy_id = PHY_ID_BCM5482,
@@ -597,8 +536,8 @@ static struct phy_driver broadcom_drivers[] = {
597 .config_init = bcm5482_config_init, 536 .config_init = bcm5482_config_init,
598 .config_aneg = genphy_config_aneg, 537 .config_aneg = genphy_config_aneg,
599 .read_status = bcm5482_read_status, 538 .read_status = bcm5482_read_status,
600 .ack_interrupt = bcm54xx_ack_interrupt, 539 .ack_interrupt = bcm_phy_ack_intr,
601 .config_intr = bcm54xx_config_intr, 540 .config_intr = bcm_phy_config_intr,
602 .driver = { .owner = THIS_MODULE }, 541 .driver = { .owner = THIS_MODULE },
603}, { 542}, {
604 .phy_id = PHY_ID_BCM50610, 543 .phy_id = PHY_ID_BCM50610,
@@ -610,8 +549,8 @@ static struct phy_driver broadcom_drivers[] = {
610 .config_init = bcm54xx_config_init, 549 .config_init = bcm54xx_config_init,
611 .config_aneg = genphy_config_aneg, 550 .config_aneg = genphy_config_aneg,
612 .read_status = genphy_read_status, 551 .read_status = genphy_read_status,
613 .ack_interrupt = bcm54xx_ack_interrupt, 552 .ack_interrupt = bcm_phy_ack_intr,
614 .config_intr = bcm54xx_config_intr, 553 .config_intr = bcm_phy_config_intr,
615 .driver = { .owner = THIS_MODULE }, 554 .driver = { .owner = THIS_MODULE },
616}, { 555}, {
617 .phy_id = PHY_ID_BCM50610M, 556 .phy_id = PHY_ID_BCM50610M,
@@ -623,8 +562,8 @@ static struct phy_driver broadcom_drivers[] = {
623 .config_init = bcm54xx_config_init, 562 .config_init = bcm54xx_config_init,
624 .config_aneg = genphy_config_aneg, 563 .config_aneg = genphy_config_aneg,
625 .read_status = genphy_read_status, 564 .read_status = genphy_read_status,
626 .ack_interrupt = bcm54xx_ack_interrupt, 565 .ack_interrupt = bcm_phy_ack_intr,
627 .config_intr = bcm54xx_config_intr, 566 .config_intr = bcm_phy_config_intr,
628 .driver = { .owner = THIS_MODULE }, 567 .driver = { .owner = THIS_MODULE },
629}, { 568}, {
630 .phy_id = PHY_ID_BCM57780, 569 .phy_id = PHY_ID_BCM57780,
@@ -636,8 +575,8 @@ static struct phy_driver broadcom_drivers[] = {
636 .config_init = bcm54xx_config_init, 575 .config_init = bcm54xx_config_init,
637 .config_aneg = genphy_config_aneg, 576 .config_aneg = genphy_config_aneg,
638 .read_status = genphy_read_status, 577 .read_status = genphy_read_status,
639 .ack_interrupt = bcm54xx_ack_interrupt, 578 .ack_interrupt = bcm_phy_ack_intr,
640 .config_intr = bcm54xx_config_intr, 579 .config_intr = bcm_phy_config_intr,
641 .driver = { .owner = THIS_MODULE }, 580 .driver = { .owner = THIS_MODULE },
642}, { 581}, {
643 .phy_id = PHY_ID_BCMAC131, 582 .phy_id = PHY_ID_BCMAC131,
diff --git a/drivers/net/phy/mdio-bcm-iproc.c b/drivers/net/phy/mdio-bcm-iproc.c
new file mode 100644
index 000000000000..c0b4e65267af
--- /dev/null
+++ b/drivers/net/phy/mdio-bcm-iproc.c
@@ -0,0 +1,213 @@
1/*
2 * 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.
12 */
13
14#include <linux/delay.h>
15#include <linux/io.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/of_platform.h>
20#include <linux/of_mdio.h>
21#include <linux/phy.h>
22#include <linux/platform_device.h>
23#include <linux/sched.h>
24
25#define IPROC_GPHY_MDCDIV 0x1a
26
27#define MII_CTRL_OFFSET 0x000
28
29#define MII_CTRL_DIV_SHIFT 0
30#define MII_CTRL_PRE_SHIFT 7
31#define MII_CTRL_BUSY_SHIFT 8
32
33#define MII_DATA_OFFSET 0x004
34#define MII_DATA_MASK 0xffff
35#define MII_DATA_TA_SHIFT 16
36#define MII_DATA_TA_VAL 2
37#define MII_DATA_RA_SHIFT 18
38#define MII_DATA_PA_SHIFT 23
39#define MII_DATA_OP_SHIFT 28
40#define MII_DATA_OP_WRITE 1
41#define MII_DATA_OP_READ 2
42#define MII_DATA_SB_SHIFT 30
43
44struct iproc_mdio_priv {
45 struct mii_bus *mii_bus;
46 void __iomem *base;
47};
48
49static inline int iproc_mdio_wait_for_idle(void __iomem *base)
50{
51 u32 val;
52 unsigned int timeout = 1000; /* loop for 1s */
53
54 do {
55 val = readl(base + MII_CTRL_OFFSET);
56 if ((val & BIT(MII_CTRL_BUSY_SHIFT)) == 0)
57 return 0;
58
59 usleep_range(1000, 2000);
60 } while (timeout--);
61
62 return -ETIMEDOUT;
63}
64
65static inline void iproc_mdio_config_clk(void __iomem *base)
66{
67 u32 val;
68
69 val = (IPROC_GPHY_MDCDIV << MII_CTRL_DIV_SHIFT) |
70 BIT(MII_CTRL_PRE_SHIFT);
71 writel(val, base + MII_CTRL_OFFSET);
72}
73
74static int iproc_mdio_read(struct mii_bus *bus, int phy_id, int reg)
75{
76 struct iproc_mdio_priv *priv = bus->priv;
77 u32 cmd;
78 int rc;
79
80 rc = iproc_mdio_wait_for_idle(priv->base);
81 if (rc)
82 return rc;
83
84 iproc_mdio_config_clk(priv->base);
85
86 /* Prepare the read operation */
87 cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
88 (reg << MII_DATA_RA_SHIFT) |
89 (phy_id << MII_DATA_PA_SHIFT) |
90 BIT(MII_DATA_SB_SHIFT) |
91 (MII_DATA_OP_READ << MII_DATA_OP_SHIFT);
92
93 writel(cmd, priv->base + MII_DATA_OFFSET);
94
95 rc = iproc_mdio_wait_for_idle(priv->base);
96 if (rc)
97 return rc;
98
99 cmd = readl(priv->base + MII_DATA_OFFSET) & MII_DATA_MASK;
100
101 return cmd;
102}
103
104static int iproc_mdio_write(struct mii_bus *bus, int phy_id,
105 int reg, u16 val)
106{
107 struct iproc_mdio_priv *priv = bus->priv;
108 u32 cmd;
109 int rc;
110
111 rc = iproc_mdio_wait_for_idle(priv->base);
112 if (rc)
113 return rc;
114
115 iproc_mdio_config_clk(priv->base);
116
117 /* Prepare the write operation */
118 cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
119 (reg << MII_DATA_RA_SHIFT) |
120 (phy_id << MII_DATA_PA_SHIFT) |
121 BIT(MII_DATA_SB_SHIFT) |
122 (MII_DATA_OP_WRITE << MII_DATA_OP_SHIFT) |
123 ((u32)(val) & MII_DATA_MASK);
124
125 writel(cmd, priv->base + MII_DATA_OFFSET);
126
127 rc = iproc_mdio_wait_for_idle(priv->base);
128 if (rc)
129 return rc;
130
131 return 0;
132}
133
134static int iproc_mdio_probe(struct platform_device *pdev)
135{
136 struct iproc_mdio_priv *priv;
137 struct mii_bus *bus;
138 struct resource *res;
139 int rc;
140
141 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
142 if (!priv)
143 return -ENOMEM;
144
145 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
146 priv->base = devm_ioremap_resource(&pdev->dev, res);
147 if (IS_ERR(priv->base)) {
148 dev_err(&pdev->dev, "failed to ioremap register\n");
149 return PTR_ERR(priv->base);
150 }
151
152 priv->mii_bus = mdiobus_alloc();
153 if (!priv->mii_bus) {
154 dev_err(&pdev->dev, "MDIO bus alloc failed\n");
155 return -ENOMEM;
156 }
157
158 bus = priv->mii_bus;
159 bus->priv = priv;
160 bus->name = "iProc MDIO bus";
161 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
162 bus->parent = &pdev->dev;
163 bus->read = iproc_mdio_read;
164 bus->write = iproc_mdio_write;
165
166 rc = of_mdiobus_register(bus, pdev->dev.of_node);
167 if (rc) {
168 dev_err(&pdev->dev, "MDIO bus registration failed\n");
169 goto err_iproc_mdio;
170 }
171
172 platform_set_drvdata(pdev, priv);
173
174 dev_info(&pdev->dev, "Broadcom iProc MDIO bus at 0x%p\n", priv->base);
175
176 return 0;
177
178err_iproc_mdio:
179 mdiobus_free(bus);
180 return rc;
181}
182
183static int iproc_mdio_remove(struct platform_device *pdev)
184{
185 struct iproc_mdio_priv *priv = platform_get_drvdata(pdev);
186
187 mdiobus_unregister(priv->mii_bus);
188 mdiobus_free(priv->mii_bus);
189
190 return 0;
191}
192
193static const struct of_device_id iproc_mdio_of_match[] = {
194 { .compatible = "brcm,iproc-mdio", },
195 { /* sentinel */ },
196};
197MODULE_DEVICE_TABLE(of, iproc_mdio_of_match);
198
199static struct platform_driver iproc_mdio_driver = {
200 .driver = {
201 .name = "iproc-mdio",
202 .of_match_table = iproc_mdio_of_match,
203 },
204 .probe = iproc_mdio_probe,
205 .remove = iproc_mdio_remove,
206};
207
208module_platform_driver(iproc_mdio_driver);
209
210MODULE_AUTHOR("Broadcom Corporation");
211MODULE_DESCRIPTION("Broadcom iProc MDIO bus controller");
212MODULE_LICENSE("GPL v2");
213MODULE_ALIAS("platform:iproc-mdio");
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 697ca7795bd9..59f4a7304419 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -30,6 +30,8 @@
30#define PHY_ID_BCM7439_2 0xae025080 30#define PHY_ID_BCM7439_2 0xae025080
31#define PHY_ID_BCM7445 0x600d8510 31#define PHY_ID_BCM7445 0x600d8510
32 32
33#define PHY_ID_BCM_CYGNUS 0xae025200
34
33#define PHY_BCM_OUI_MASK 0xfffffc00 35#define PHY_BCM_OUI_MASK 0xfffffc00
34#define PHY_BCM_OUI_1 0x00206000 36#define PHY_BCM_OUI_1 0x00206000
35#define PHY_BCM_OUI_2 0x0143bc00 37#define PHY_BCM_OUI_2 0x0143bc00
@@ -138,7 +140,10 @@
138 140
139/* 01010: Auto Power-Down */ 141/* 01010: Auto Power-Down */
140#define BCM54XX_SHD_APD 0x0a 142#define BCM54XX_SHD_APD 0x0a
143#define BCM_APD_CLR_MASK 0xFE9F /* clear bits 5, 6 & 8 */
141#define BCM54XX_SHD_APD_EN 0x0020 144#define BCM54XX_SHD_APD_EN 0x0020
145#define BCM_NO_ANEG_APD_EN 0x0060 /* bits 5 & 6 */
146#define BCM_APD_SINGLELP_EN 0x0100 /* Bit 8 */
142 147
143#define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ 148#define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */
144 /* LED3 / ~LINKSPD[2] selector */ 149 /* LED3 / ~LINKSPD[2] selector */
@@ -209,27 +214,13 @@
209#define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */ 214#define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */
210#define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */ 215#define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */
211 216
212/*
213 * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
214 * 0x1c shadow registers.
215 */
216static inline int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
217{
218 phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
219 return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
220}
221
222static inline int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow,
223 u16 val)
224{
225 return phy_write(phydev, MII_BCM54XX_SHD,
226 MII_BCM54XX_SHD_WRITE |
227 MII_BCM54XX_SHD_VAL(shadow) |
228 MII_BCM54XX_SHD_DATA(val));
229}
230
231#define BRCM_CL45VEN_EEE_CONTROL 0x803d 217#define BRCM_CL45VEN_EEE_CONTROL 0x803d
232#define LPI_FEATURE_EN 0x8000 218#define LPI_FEATURE_EN 0x8000
233#define LPI_FEATURE_EN_DIG1000X 0x4000 219#define LPI_FEATURE_EN_DIG1000X 0x4000
234 220
221/* Core register definitions*/
222#define MII_BRCM_CORE_BASE1E 0x1E
223#define MII_BRCM_CORE_EXPB0 0xB0
224#define MII_BRCM_CORE_EXPB1 0xB1
225
235#endif /* _LINUX_BRCMPHY_H */ 226#endif /* _LINUX_BRCMPHY_H */