net: dsa: Rename DSA probe function.
[cascardo/linux.git] / drivers / net / dsa / mv88e6352.c
1 /*
2  * net/dsa/mv88e6352.c - Marvell 88e6352 switch chip support
3  *
4  * Copyright (c) 2014 Guenter Roeck
5  *
6  * Derived from mv88e6123_61_65.c
7  * Copyright (c) 2008-2009 Marvell Semiconductor
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  */
14
15 #include <linux/delay.h>
16 #include <linux/jiffies.h>
17 #include <linux/list.h>
18 #include <linux/module.h>
19 #include <linux/netdevice.h>
20 #include <linux/platform_device.h>
21 #include <linux/phy.h>
22 #include <net/dsa.h>
23 #include "mv88e6xxx.h"
24
25 static const struct mv88e6xxx_switch_id mv88e6352_table[] = {
26         { PORT_SWITCH_ID_6172, "Marvell 88E6172" },
27         { PORT_SWITCH_ID_6176, "Marvell 88E6176" },
28         { PORT_SWITCH_ID_6240, "Marvell 88E6240" },
29         { PORT_SWITCH_ID_6320, "Marvell 88E6320" },
30         { PORT_SWITCH_ID_6320_A1, "Marvell 88E6320 (A1)" },
31         { PORT_SWITCH_ID_6320_A2, "Marvell 88e6320 (A2)" },
32         { PORT_SWITCH_ID_6321, "Marvell 88E6321" },
33         { PORT_SWITCH_ID_6321_A1, "Marvell 88E6321 (A1)" },
34         { PORT_SWITCH_ID_6321_A2, "Marvell 88e6321 (A2)" },
35         { PORT_SWITCH_ID_6352, "Marvell 88E6352" },
36         { PORT_SWITCH_ID_6352_A0, "Marvell 88E6352 (A0)" },
37         { PORT_SWITCH_ID_6352_A1, "Marvell 88E6352 (A1)" },
38 };
39
40 static char *mv88e6352_drv_probe(struct device *dsa_dev,
41                                  struct device *host_dev,
42                                  int sw_addr, void **priv)
43 {
44         return mv88e6xxx_drv_probe(dsa_dev, host_dev, sw_addr, priv,
45                                    mv88e6352_table,
46                                    ARRAY_SIZE(mv88e6352_table));
47 }
48
49 static int mv88e6352_setup_global(struct dsa_switch *ds)
50 {
51         u32 upstream_port = dsa_upstream_port(ds);
52         int ret;
53         u32 reg;
54
55         ret = mv88e6xxx_setup_global(ds);
56         if (ret)
57                 return ret;
58
59         /* Discard packets with excessive collisions,
60          * mask all interrupt sources, enable PPU (bit 14, undocumented).
61          */
62         REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
63                   GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_DISCARD_EXCESS);
64
65         /* Configure the upstream port, and configure the upstream
66          * port as the port to which ingress and egress monitor frames
67          * are to be sent.
68          */
69         reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
70                 upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
71                 upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
72         REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
73
74         /* Disable remote management for now, and set the switch's
75          * DSA device number.
76          */
77         REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
78
79         return 0;
80 }
81
82 static int mv88e6352_setup(struct dsa_switch *ds)
83 {
84         struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
85         int ret;
86
87         ps->ds = ds;
88
89         ret = mv88e6xxx_setup_common(ds);
90         if (ret < 0)
91                 return ret;
92
93         ps->num_ports = 7;
94
95         mutex_init(&ps->eeprom_mutex);
96
97         ret = mv88e6xxx_switch_reset(ds, true);
98         if (ret < 0)
99                 return ret;
100
101         ret = mv88e6352_setup_global(ds);
102         if (ret < 0)
103                 return ret;
104
105         return mv88e6xxx_setup_ports(ds);
106 }
107
108 static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
109 {
110         struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
111         int ret;
112
113         mutex_lock(&ps->eeprom_mutex);
114
115         ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
116                                   GLOBAL2_EEPROM_OP_READ |
117                                   (addr & GLOBAL2_EEPROM_OP_ADDR_MASK));
118         if (ret < 0)
119                 goto error;
120
121         ret = mv88e6xxx_eeprom_busy_wait(ds);
122         if (ret < 0)
123                 goto error;
124
125         ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_EEPROM_DATA);
126 error:
127         mutex_unlock(&ps->eeprom_mutex);
128         return ret;
129 }
130
131 static int mv88e6352_get_eeprom(struct dsa_switch *ds,
132                                 struct ethtool_eeprom *eeprom, u8 *data)
133 {
134         int offset;
135         int len;
136         int ret;
137
138         offset = eeprom->offset;
139         len = eeprom->len;
140         eeprom->len = 0;
141
142         eeprom->magic = 0xc3ec4951;
143
144         ret = mv88e6xxx_eeprom_load_wait(ds);
145         if (ret < 0)
146                 return ret;
147
148         if (offset & 1) {
149                 int word;
150
151                 word = mv88e6352_read_eeprom_word(ds, offset >> 1);
152                 if (word < 0)
153                         return word;
154
155                 *data++ = (word >> 8) & 0xff;
156
157                 offset++;
158                 len--;
159                 eeprom->len++;
160         }
161
162         while (len >= 2) {
163                 int word;
164
165                 word = mv88e6352_read_eeprom_word(ds, offset >> 1);
166                 if (word < 0)
167                         return word;
168
169                 *data++ = word & 0xff;
170                 *data++ = (word >> 8) & 0xff;
171
172                 offset += 2;
173                 len -= 2;
174                 eeprom->len += 2;
175         }
176
177         if (len) {
178                 int word;
179
180                 word = mv88e6352_read_eeprom_word(ds, offset >> 1);
181                 if (word < 0)
182                         return word;
183
184                 *data++ = word & 0xff;
185
186                 offset++;
187                 len--;
188                 eeprom->len++;
189         }
190
191         return 0;
192 }
193
194 static int mv88e6352_eeprom_is_readonly(struct dsa_switch *ds)
195 {
196         int ret;
197
198         ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP);
199         if (ret < 0)
200                 return ret;
201
202         if (!(ret & GLOBAL2_EEPROM_OP_WRITE_EN))
203                 return -EROFS;
204
205         return 0;
206 }
207
208 static int mv88e6352_write_eeprom_word(struct dsa_switch *ds, int addr,
209                                        u16 data)
210 {
211         struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
212         int ret;
213
214         mutex_lock(&ps->eeprom_mutex);
215
216         ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data);
217         if (ret < 0)
218                 goto error;
219
220         ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
221                                   GLOBAL2_EEPROM_OP_WRITE |
222                                   (addr & GLOBAL2_EEPROM_OP_ADDR_MASK));
223         if (ret < 0)
224                 goto error;
225
226         ret = mv88e6xxx_eeprom_busy_wait(ds);
227 error:
228         mutex_unlock(&ps->eeprom_mutex);
229         return ret;
230 }
231
232 static int mv88e6352_set_eeprom(struct dsa_switch *ds,
233                                 struct ethtool_eeprom *eeprom, u8 *data)
234 {
235         int offset;
236         int ret;
237         int len;
238
239         if (eeprom->magic != 0xc3ec4951)
240                 return -EINVAL;
241
242         ret = mv88e6352_eeprom_is_readonly(ds);
243         if (ret)
244                 return ret;
245
246         offset = eeprom->offset;
247         len = eeprom->len;
248         eeprom->len = 0;
249
250         ret = mv88e6xxx_eeprom_load_wait(ds);
251         if (ret < 0)
252                 return ret;
253
254         if (offset & 1) {
255                 int word;
256
257                 word = mv88e6352_read_eeprom_word(ds, offset >> 1);
258                 if (word < 0)
259                         return word;
260
261                 word = (*data++ << 8) | (word & 0xff);
262
263                 ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
264                 if (ret < 0)
265                         return ret;
266
267                 offset++;
268                 len--;
269                 eeprom->len++;
270         }
271
272         while (len >= 2) {
273                 int word;
274
275                 word = *data++;
276                 word |= *data++ << 8;
277
278                 ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
279                 if (ret < 0)
280                         return ret;
281
282                 offset += 2;
283                 len -= 2;
284                 eeprom->len += 2;
285         }
286
287         if (len) {
288                 int word;
289
290                 word = mv88e6352_read_eeprom_word(ds, offset >> 1);
291                 if (word < 0)
292                         return word;
293
294                 word = (word & 0xff00) | *data++;
295
296                 ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
297                 if (ret < 0)
298                         return ret;
299
300                 offset++;
301                 len--;
302                 eeprom->len++;
303         }
304
305         return 0;
306 }
307
308 struct dsa_switch_driver mv88e6352_switch_driver = {
309         .tag_protocol           = DSA_TAG_PROTO_EDSA,
310         .probe                  = mv88e6352_drv_probe,
311         .setup                  = mv88e6352_setup,
312         .set_addr               = mv88e6xxx_set_addr_indirect,
313         .phy_read               = mv88e6xxx_phy_read_indirect,
314         .phy_write              = mv88e6xxx_phy_write_indirect,
315         .get_strings            = mv88e6xxx_get_strings,
316         .get_ethtool_stats      = mv88e6xxx_get_ethtool_stats,
317         .get_sset_count         = mv88e6xxx_get_sset_count,
318         .adjust_link            = mv88e6xxx_adjust_link,
319         .set_eee                = mv88e6xxx_set_eee,
320         .get_eee                = mv88e6xxx_get_eee,
321 #ifdef CONFIG_NET_DSA_HWMON
322         .get_temp               = mv88e6xxx_get_temp,
323         .get_temp_limit         = mv88e6xxx_get_temp_limit,
324         .set_temp_limit         = mv88e6xxx_set_temp_limit,
325         .get_temp_alarm         = mv88e6xxx_get_temp_alarm,
326 #endif
327         .get_eeprom             = mv88e6352_get_eeprom,
328         .set_eeprom             = mv88e6352_set_eeprom,
329         .get_regs_len           = mv88e6xxx_get_regs_len,
330         .get_regs               = mv88e6xxx_get_regs,
331         .port_bridge_join       = mv88e6xxx_port_bridge_join,
332         .port_bridge_leave      = mv88e6xxx_port_bridge_leave,
333         .port_stp_state_set     = mv88e6xxx_port_stp_state_set,
334         .port_vlan_filtering    = mv88e6xxx_port_vlan_filtering,
335         .port_vlan_prepare      = mv88e6xxx_port_vlan_prepare,
336         .port_vlan_add          = mv88e6xxx_port_vlan_add,
337         .port_vlan_del          = mv88e6xxx_port_vlan_del,
338         .port_vlan_dump         = mv88e6xxx_port_vlan_dump,
339         .port_fdb_prepare       = mv88e6xxx_port_fdb_prepare,
340         .port_fdb_add           = mv88e6xxx_port_fdb_add,
341         .port_fdb_del           = mv88e6xxx_port_fdb_del,
342         .port_fdb_dump          = mv88e6xxx_port_fdb_dump,
343 };
344
345 MODULE_ALIAS("platform:mv88e6172");
346 MODULE_ALIAS("platform:mv88e6176");
347 MODULE_ALIAS("platform:mv88e6320");
348 MODULE_ALIAS("platform:mv88e6321");
349 MODULE_ALIAS("platform:mv88e6352");