aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/dsa/mv88e6060.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/mv88e6060.c')
-rw-r--r--drivers/net/dsa/mv88e6060.c114
1 files changed, 38 insertions, 76 deletions
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 9093577755f6..0527f485c3dc 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -15,9 +15,7 @@
15#include <linux/netdevice.h> 15#include <linux/netdevice.h>
16#include <linux/phy.h> 16#include <linux/phy.h>
17#include <net/dsa.h> 17#include <net/dsa.h>
18 18#include "mv88e6060.h"
19#define REG_PORT(p) (8 + (p))
20#define REG_GLOBAL 0x0f
21 19
22static int reg_read(struct dsa_switch *ds, int addr, int reg) 20static int reg_read(struct dsa_switch *ds, int addr, int reg)
23{ 21{
@@ -67,13 +65,14 @@ static char *mv88e6060_probe(struct device *host_dev, int sw_addr)
67 if (bus == NULL) 65 if (bus == NULL)
68 return NULL; 66 return NULL;
69 67
70 ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03); 68 ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID);
71 if (ret >= 0) { 69 if (ret >= 0) {
72 if (ret == 0x0600) 70 if (ret == PORT_SWITCH_ID_6060)
73 return "Marvell 88E6060 (A0)"; 71 return "Marvell 88E6060 (A0)";
74 if (ret == 0x0601 || ret == 0x0602) 72 if (ret == PORT_SWITCH_ID_6060_R1 ||
73 ret == PORT_SWITCH_ID_6060_R2)
75 return "Marvell 88E6060 (B0)"; 74 return "Marvell 88E6060 (B0)";
76 if ((ret & 0xfff0) == 0x0600) 75 if ((ret & PORT_SWITCH_ID_6060_MASK) == PORT_SWITCH_ID_6060)
77 return "Marvell 88E6060"; 76 return "Marvell 88E6060";
78 } 77 }
79 78
@@ -87,22 +86,26 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
87 unsigned long timeout; 86 unsigned long timeout;
88 87
89 /* Set all ports to the disabled state. */ 88 /* Set all ports to the disabled state. */
90 for (i = 0; i < 6; i++) { 89 for (i = 0; i < MV88E6060_PORTS; i++) {
91 ret = REG_READ(REG_PORT(i), 0x04); 90 ret = REG_READ(REG_PORT(i), PORT_CONTROL);
92 REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); 91 REG_WRITE(REG_PORT(i), PORT_CONTROL,
92 ret & ~PORT_CONTROL_STATE_MASK);
93 } 93 }
94 94
95 /* Wait for transmit queues to drain. */ 95 /* Wait for transmit queues to drain. */
96 usleep_range(2000, 4000); 96 usleep_range(2000, 4000);
97 97
98 /* Reset the switch. */ 98 /* Reset the switch. */
99 REG_WRITE(REG_GLOBAL, 0x0a, 0xa130); 99 REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
100 GLOBAL_ATU_CONTROL_SWRESET |
101 GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
102 GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
100 103
101 /* Wait up to one second for reset to complete. */ 104 /* Wait up to one second for reset to complete. */
102 timeout = jiffies + 1 * HZ; 105 timeout = jiffies + 1 * HZ;
103 while (time_before(jiffies, timeout)) { 106 while (time_before(jiffies, timeout)) {
104 ret = REG_READ(REG_GLOBAL, 0x00); 107 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
105 if ((ret & 0x8000) == 0x0000) 108 if (ret & GLOBAL_STATUS_INIT_READY)
106 break; 109 break;
107 110
108 usleep_range(1000, 2000); 111 usleep_range(1000, 2000);
@@ -119,13 +122,15 @@ static int mv88e6060_setup_global(struct dsa_switch *ds)
119 * set the maximum frame size to 1536 bytes, and mask all 122 * set the maximum frame size to 1536 bytes, and mask all
120 * interrupt sources. 123 * interrupt sources.
121 */ 124 */
122 REG_WRITE(REG_GLOBAL, 0x04, 0x0800); 125 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536);
123 126
124 /* Enable automatic address learning, set the address 127 /* Enable automatic address learning, set the address
125 * database size to 1024 entries, and set the default aging 128 * database size to 1024 entries, and set the default aging
126 * time to 5 minutes. 129 * time to 5 minutes.
127 */ 130 */
128 REG_WRITE(REG_GLOBAL, 0x0a, 0x2130); 131 REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
132 GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
133 GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
129 134
130 return 0; 135 return 0;
131} 136}
@@ -139,25 +144,30 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
139 * state to Forwarding. Additionally, if this is the CPU 144 * state to Forwarding. Additionally, if this is the CPU
140 * port, enable Ingress and Egress Trailer tagging mode. 145 * port, enable Ingress and Egress Trailer tagging mode.
141 */ 146 */
142 REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003); 147 REG_WRITE(addr, PORT_CONTROL,
148 dsa_is_cpu_port(ds, p) ?
149 PORT_CONTROL_TRAILER |
150 PORT_CONTROL_INGRESS_MODE |
151 PORT_CONTROL_STATE_FORWARDING :
152 PORT_CONTROL_STATE_FORWARDING);
143 153
144 /* Port based VLAN map: give each port its own address 154 /* Port based VLAN map: give each port its own address
145 * database, allow the CPU port to talk to each of the 'real' 155 * database, allow the CPU port to talk to each of the 'real'
146 * ports, and allow each of the 'real' ports to only talk to 156 * ports, and allow each of the 'real' ports to only talk to
147 * the CPU port. 157 * the CPU port.
148 */ 158 */
149 REG_WRITE(addr, 0x06, 159 REG_WRITE(addr, PORT_VLAN_MAP,
150 ((p & 0xf) << 12) | 160 ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
151 (dsa_is_cpu_port(ds, p) ? 161 (dsa_is_cpu_port(ds, p) ?
152 ds->phys_port_mask : 162 ds->phys_port_mask :
153 (1 << ds->dst->cpu_port))); 163 BIT(ds->dst->cpu_port)));
154 164
155 /* Port Association Vector: when learning source addresses 165 /* Port Association Vector: when learning source addresses
156 * of packets, add the address to the address database using 166 * of packets, add the address to the address database using
157 * a port bitmap that has only the bit for this port set and 167 * a port bitmap that has only the bit for this port set and
158 * the other bits clear. 168 * the other bits clear.
159 */ 169 */
160 REG_WRITE(addr, 0x0b, 1 << p); 170 REG_WRITE(addr, PORT_ASSOC_VECTOR, BIT(p));
161 171
162 return 0; 172 return 0;
163} 173}
@@ -177,7 +187,7 @@ static int mv88e6060_setup(struct dsa_switch *ds)
177 if (ret < 0) 187 if (ret < 0)
178 return ret; 188 return ret;
179 189
180 for (i = 0; i < 6; i++) { 190 for (i = 0; i < MV88E6060_PORTS; i++) {
181 ret = mv88e6060_setup_port(ds, i); 191 ret = mv88e6060_setup_port(ds, i);
182 if (ret < 0) 192 if (ret < 0)
183 return ret; 193 return ret;
@@ -188,16 +198,17 @@ static int mv88e6060_setup(struct dsa_switch *ds)
188 198
189static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr) 199static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr)
190{ 200{
191 REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]); 201 /* Use the same MAC Address as FD Pause frames for all ports */
192 REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]); 202 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 9) | addr[1]);
193 REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]); 203 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
204 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
194 205
195 return 0; 206 return 0;
196} 207}
197 208
198static int mv88e6060_port_to_phy_addr(int port) 209static int mv88e6060_port_to_phy_addr(int port)
199{ 210{
200 if (port >= 0 && port <= 5) 211 if (port >= 0 && port < MV88E6060_PORTS)
201 return port; 212 return port;
202 return -1; 213 return -1;
203} 214}
@@ -225,54 +236,6 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
225 return reg_write(ds, addr, regnum, val); 236 return reg_write(ds, addr, regnum, val);
226} 237}
227 238
228static void mv88e6060_poll_link(struct dsa_switch *ds)
229{
230 int i;
231
232 for (i = 0; i < DSA_MAX_PORTS; i++) {
233 struct net_device *dev;
234 int uninitialized_var(port_status);
235 int link;
236 int speed;
237 int duplex;
238 int fc;
239
240 dev = ds->ports[i];
241 if (dev == NULL)
242 continue;
243
244 link = 0;
245 if (dev->flags & IFF_UP) {
246 port_status = reg_read(ds, REG_PORT(i), 0x00);
247 if (port_status < 0)
248 continue;
249
250 link = !!(port_status & 0x1000);
251 }
252
253 if (!link) {
254 if (netif_carrier_ok(dev)) {
255 netdev_info(dev, "link down\n");
256 netif_carrier_off(dev);
257 }
258 continue;
259 }
260
261 speed = (port_status & 0x0100) ? 100 : 10;
262 duplex = (port_status & 0x0200) ? 1 : 0;
263 fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
264
265 if (!netif_carrier_ok(dev)) {
266 netdev_info(dev,
267 "link up, %d Mb/s, %s duplex, flow control %sabled\n",
268 speed,
269 duplex ? "full" : "half",
270 fc ? "en" : "dis");
271 netif_carrier_on(dev);
272 }
273 }
274}
275
276static struct dsa_switch_driver mv88e6060_switch_driver = { 239static struct dsa_switch_driver mv88e6060_switch_driver = {
277 .tag_protocol = DSA_TAG_PROTO_TRAILER, 240 .tag_protocol = DSA_TAG_PROTO_TRAILER,
278 .probe = mv88e6060_probe, 241 .probe = mv88e6060_probe,
@@ -280,7 +243,6 @@ static struct dsa_switch_driver mv88e6060_switch_driver = {
280 .set_addr = mv88e6060_set_addr, 243 .set_addr = mv88e6060_set_addr,
281 .phy_read = mv88e6060_phy_read, 244 .phy_read = mv88e6060_phy_read,
282 .phy_write = mv88e6060_phy_write, 245 .phy_write = mv88e6060_phy_write,
283 .poll_link = mv88e6060_poll_link,
284}; 246};
285 247
286static int __init mv88e6060_init(void) 248static int __init mv88e6060_init(void)