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