summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm63xx/patches-2.6.27/010-add_integrated_ethernet_phy_support.patch
blob: 0ccafc1c0072f85d5702aed02dbe7a760e99345f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
From 7eefcb968019804e024c8243e28afb1eebd674a2 Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Sun, 21 Sep 2008 02:20:53 +0200
Subject: [PATCH] [MIPS] BCM63XX: Add integrated ethernet PHY support for phylib.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
---
 drivers/net/phy/Kconfig   |    6 ++
 drivers/net/phy/Makefile  |    1 +
 drivers/net/phy/bcm63xx.c |  132 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/phy/bcm63xx.c

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d55932a..a5d2c2d 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -56,6 +56,12 @@ config BROADCOM_PHY
 	  Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
 	  and BCM5482 PHYs.
 
+config BCM63XX_PHY
+	tristate "Drivers for Broadcom 63xx SOCs internal PHY"
+	depends on BCM63XX
+	---help---
+	  Currently supports the 6348 and 6358 PHYs.
+
 config ICPLUS_PHY
 	tristate "Drivers for ICPlus PHYs"
 	---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index eee329f..0d43f58 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
 obj-$(CONFIG_SMSC_PHY)		+= smsc.o
 obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
 obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
+obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
 obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
 obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
 obj-$(CONFIG_FIXED_PHY)		+= fixed.o
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
new file mode 100644
index 0000000..4fed95e
--- /dev/null
+++ b/drivers/net/phy/bcm63xx.c
@@ -0,0 +1,132 @@
+/*
+ *	Driver for Broadcom 63xx SOCs integrated PHYs
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define MII_BCM63XX_IR		0x1a	/* interrupt register */
+#define MII_BCM63XX_IR_EN	0x4000	/* global interrupt enable */
+#define MII_BCM63XX_IR_DUPLEX	0x0800	/* duplex changed */
+#define MII_BCM63XX_IR_SPEED	0x0400	/* speed changed */
+#define MII_BCM63XX_IR_LINK	0x0200	/* link changed */
+#define MII_BCM63XX_IR_GMASK	0x0100	/* global interrupt mask */
+
+MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_LICENSE("GPL");
+
+static int bcm63xx_config_init(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM63XX_IR);
+	if (reg < 0)
+		return reg;
+
+	/* Mask interrupts globally.  */
+	reg |= MII_BCM63XX_IR_GMASK;
+	err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	if (err < 0)
+		return err;
+
+	/* Unmask events we are interested in  */
+	reg = ~(MII_BCM63XX_IR_DUPLEX |
+		MII_BCM63XX_IR_SPEED |
+		MII_BCM63XX_IR_LINK) |
+		MII_BCM63XX_IR_EN;
+	err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int bcm63xx_ack_interrupt(struct phy_device *phydev)
+{
+	int reg;
+
+	/* Clear pending interrupts.  */
+	reg = phy_read(phydev, MII_BCM63XX_IR);
+	if (reg < 0)
+		return reg;
+
+	return 0;
+}
+
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM63XX_IR);
+	if (reg < 0)
+		return reg;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		reg &= ~MII_BCM63XX_IR_GMASK;
+	else
+		reg |= MII_BCM63XX_IR_GMASK;
+
+	err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	return err;
+}
+
+static struct phy_driver bcm63xx_1_driver = {
+	.phy_id		= 0x00406000,
+	.phy_id_mask	= 0xfffffc00,
+	.name		= "Broadcom BCM63XX (1)",
+	/* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= bcm63xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm63xx_ack_interrupt,
+	.config_intr	= bcm63xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+/* same phy as above, with just a different OUI */
+static struct phy_driver bcm63xx_2_driver = {
+	.phy_id		= 0x002bdc00,
+	.phy_id_mask	= 0xfffffc00,
+	.name		= "Broadcom BCM63XX (2)",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= bcm63xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm63xx_ack_interrupt,
+	.config_intr	= bcm63xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static int __init bcm63xx_phy_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&bcm63xx_1_driver);
+	if (ret)
+		goto out_63xx_1;
+	ret = phy_driver_register(&bcm63xx_2_driver);
+	if (ret)
+		goto out_63xx_2;
+	return ret;
+
+out_63xx_2:
+	phy_driver_unregister(&bcm63xx_1_driver);
+out_63xx_1:
+	return ret;
+}
+
+static void __exit bcm63xx_phy_exit(void)
+{
+	phy_driver_unregister(&bcm63xx_1_driver);
+	phy_driver_unregister(&bcm63xx_2_driver);
+}
+
+module_init(bcm63xx_phy_init);
+module_exit(bcm63xx_phy_exit);
-- 
1.5.4.3