Commit | Line | Data |
---|---|---|
c2e86691 TH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Microchip KSZ9477 switch driver main logic | |
4 | * | |
42fc6a4c | 5 | * Copyright (C) 2017-2019 Microchip Technology Inc. |
c2e86691 TH |
6 | */ |
7 | ||
c2e86691 TH |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> | |
7c6ff470 | 10 | #include <linux/iopoll.h> |
c2e86691 TH |
11 | #include <linux/platform_data/microchip-ksz.h> |
12 | #include <linux/phy.h> | |
c2e86691 TH |
13 | #include <linux/if_bridge.h> |
14 | #include <net/dsa.h> | |
15 | #include <net/switchdev.h> | |
16 | ||
17 | #include "ksz_priv.h" | |
84bd1908 | 18 | #include "ksz9477_reg.h" |
7c6ff470 | 19 | #include "ksz_common.h" |
c2e86691 | 20 | |
8c29bebb TH |
21 | /* Used with variable features to indicate capabilities. */ |
22 | #define GBIT_SUPPORT BIT(0) | |
23 | #define NEW_XMII BIT(1) | |
24 | #define IS_9893 BIT(2) | |
25 | ||
c2e86691 TH |
26 | static const struct { |
27 | int index; | |
28 | char string[ETH_GSTRING_LEN]; | |
29 | } ksz9477_mib_names[TOTAL_SWITCH_COUNTER_NUM] = { | |
30 | { 0x00, "rx_hi" }, | |
31 | { 0x01, "rx_undersize" }, | |
32 | { 0x02, "rx_fragments" }, | |
33 | { 0x03, "rx_oversize" }, | |
34 | { 0x04, "rx_jabbers" }, | |
35 | { 0x05, "rx_symbol_err" }, | |
36 | { 0x06, "rx_crc_err" }, | |
37 | { 0x07, "rx_align_err" }, | |
38 | { 0x08, "rx_mac_ctrl" }, | |
39 | { 0x09, "rx_pause" }, | |
40 | { 0x0A, "rx_bcast" }, | |
41 | { 0x0B, "rx_mcast" }, | |
42 | { 0x0C, "rx_ucast" }, | |
43 | { 0x0D, "rx_64_or_less" }, | |
44 | { 0x0E, "rx_65_127" }, | |
45 | { 0x0F, "rx_128_255" }, | |
46 | { 0x10, "rx_256_511" }, | |
47 | { 0x11, "rx_512_1023" }, | |
48 | { 0x12, "rx_1024_1522" }, | |
49 | { 0x13, "rx_1523_2000" }, | |
50 | { 0x14, "rx_2001" }, | |
51 | { 0x15, "tx_hi" }, | |
52 | { 0x16, "tx_late_col" }, | |
53 | { 0x17, "tx_pause" }, | |
54 | { 0x18, "tx_bcast" }, | |
55 | { 0x19, "tx_mcast" }, | |
56 | { 0x1A, "tx_ucast" }, | |
57 | { 0x1B, "tx_deferred" }, | |
58 | { 0x1C, "tx_total_col" }, | |
59 | { 0x1D, "tx_exc_col" }, | |
60 | { 0x1E, "tx_single_col" }, | |
61 | { 0x1F, "tx_mult_col" }, | |
62 | { 0x80, "rx_total" }, | |
63 | { 0x81, "tx_total" }, | |
64 | { 0x82, "rx_discards" }, | |
65 | { 0x83, "tx_discards" }, | |
66 | }; | |
67 | ||
bafea01f MV |
68 | static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) |
69 | { | |
d4bcd99c | 70 | regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); |
bafea01f MV |
71 | } |
72 | ||
73 | static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, | |
74 | bool set) | |
75 | { | |
d4bcd99c MV |
76 | regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), |
77 | bits, set ? bits : 0); | |
bafea01f MV |
78 | } |
79 | ||
c2e86691 TH |
80 | static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) |
81 | { | |
d4bcd99c | 82 | regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0); |
c2e86691 TH |
83 | } |
84 | ||
85 | static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, | |
86 | u32 bits, bool set) | |
87 | { | |
d4bcd99c MV |
88 | regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset), |
89 | bits, set ? bits : 0); | |
c2e86691 TH |
90 | } |
91 | ||
0f9c36e3 | 92 | static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) |
c2e86691 | 93 | { |
0f9c36e3 | 94 | unsigned int val; |
c2e86691 | 95 | |
0f9c36e3 MV |
96 | return regmap_read_poll_timeout(dev->regmap[0], REG_SW_VLAN_CTRL, |
97 | val, !(val & VLAN_START), 10, 1000); | |
c2e86691 TH |
98 | } |
99 | ||
100 | static int ksz9477_get_vlan_table(struct ksz_device *dev, u16 vid, | |
101 | u32 *vlan_table) | |
102 | { | |
103 | int ret; | |
104 | ||
105 | mutex_lock(&dev->vlan_mutex); | |
106 | ||
107 | ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); | |
108 | ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); | |
109 | ||
110 | /* wait to be cleared */ | |
0f9c36e3 MV |
111 | ret = ksz9477_wait_vlan_ctrl_ready(dev); |
112 | if (ret) { | |
c2e86691 TH |
113 | dev_dbg(dev->dev, "Failed to read vlan table\n"); |
114 | goto exit; | |
115 | } | |
116 | ||
117 | ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &vlan_table[0]); | |
118 | ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, &vlan_table[1]); | |
119 | ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, &vlan_table[2]); | |
120 | ||
121 | ksz_write8(dev, REG_SW_VLAN_CTRL, 0); | |
122 | ||
123 | exit: | |
124 | mutex_unlock(&dev->vlan_mutex); | |
125 | ||
126 | return ret; | |
127 | } | |
128 | ||
129 | static int ksz9477_set_vlan_table(struct ksz_device *dev, u16 vid, | |
130 | u32 *vlan_table) | |
131 | { | |
132 | int ret; | |
133 | ||
134 | mutex_lock(&dev->vlan_mutex); | |
135 | ||
136 | ksz_write32(dev, REG_SW_VLAN_ENTRY__4, vlan_table[0]); | |
137 | ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, vlan_table[1]); | |
138 | ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_table[2]); | |
139 | ||
140 | ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); | |
141 | ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); | |
142 | ||
143 | /* wait to be cleared */ | |
0f9c36e3 MV |
144 | ret = ksz9477_wait_vlan_ctrl_ready(dev); |
145 | if (ret) { | |
c2e86691 TH |
146 | dev_dbg(dev->dev, "Failed to write vlan table\n"); |
147 | goto exit; | |
148 | } | |
149 | ||
150 | ksz_write8(dev, REG_SW_VLAN_CTRL, 0); | |
151 | ||
152 | /* update vlan cache table */ | |
153 | dev->vlan_cache[vid].table[0] = vlan_table[0]; | |
154 | dev->vlan_cache[vid].table[1] = vlan_table[1]; | |
155 | dev->vlan_cache[vid].table[2] = vlan_table[2]; | |
156 | ||
157 | exit: | |
158 | mutex_unlock(&dev->vlan_mutex); | |
159 | ||
160 | return ret; | |
161 | } | |
162 | ||
163 | static void ksz9477_read_table(struct ksz_device *dev, u32 *table) | |
164 | { | |
165 | ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]); | |
166 | ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]); | |
167 | ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]); | |
168 | ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]); | |
169 | } | |
170 | ||
171 | static void ksz9477_write_table(struct ksz_device *dev, u32 *table) | |
172 | { | |
173 | ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]); | |
174 | ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]); | |
175 | ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]); | |
176 | ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]); | |
177 | } | |
178 | ||
179 | static int ksz9477_wait_alu_ready(struct ksz_device *dev, u32 waiton, | |
180 | int timeout) | |
181 | { | |
182 | u32 data; | |
183 | ||
184 | do { | |
185 | ksz_read32(dev, REG_SW_ALU_CTRL__4, &data); | |
186 | if (!(data & waiton)) | |
187 | break; | |
188 | usleep_range(1, 10); | |
189 | } while (timeout-- > 0); | |
190 | ||
191 | if (timeout <= 0) | |
192 | return -ETIMEDOUT; | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, | |
198 | int timeout) | |
199 | { | |
200 | u32 data; | |
201 | ||
202 | do { | |
203 | ksz_read32(dev, REG_SW_ALU_STAT_CTRL__4, &data); | |
204 | if (!(data & waiton)) | |
205 | break; | |
206 | usleep_range(1, 10); | |
207 | } while (timeout-- > 0); | |
208 | ||
209 | if (timeout <= 0) | |
210 | return -ETIMEDOUT; | |
211 | ||
212 | return 0; | |
213 | } | |
214 | ||
215 | static int ksz9477_reset_switch(struct ksz_device *dev) | |
216 | { | |
217 | u8 data8; | |
218 | u16 data16; | |
219 | u32 data32; | |
220 | ||
221 | /* reset switch */ | |
222 | ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true); | |
223 | ||
224 | /* turn off SPI DO Edge select */ | |
225 | ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); | |
226 | data8 &= ~SPI_AUTO_EDGE_DETECTION; | |
227 | ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); | |
228 | ||
229 | /* default configuration */ | |
230 | ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); | |
231 | data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING | | |
232 | SW_SRC_ADDR_FILTER | SW_FLUSH_STP_TABLE | SW_FLUSH_MSTP_TABLE; | |
233 | ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); | |
234 | ||
235 | /* disable interrupts */ | |
236 | ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); | |
237 | ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F); | |
238 | ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); | |
239 | ||
240 | /* set broadcast storm protection 10% rate */ | |
241 | ksz_read16(dev, REG_SW_MAC_CTRL_2, &data16); | |
242 | data16 &= ~BROADCAST_STORM_RATE; | |
243 | data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100; | |
244 | ksz_write16(dev, REG_SW_MAC_CTRL_2, data16); | |
245 | ||
79c8bd15 RH |
246 | if (dev->synclko_125) |
247 | ksz_write8(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1, | |
248 | SW_ENABLE_REFCLKO | SW_REFCLKO_IS_125MHZ); | |
249 | ||
c2e86691 TH |
250 | return 0; |
251 | } | |
252 | ||
7c6ff470 TH |
253 | static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, |
254 | u64 *cnt) | |
255 | { | |
7c6ff470 | 256 | struct ksz_port *p = &dev->ports[port]; |
1c1eb580 | 257 | unsigned int val; |
7c6ff470 TH |
258 | u32 data; |
259 | int ret; | |
260 | ||
261 | /* retain the flush/freeze bit */ | |
262 | data = p->freeze ? MIB_COUNTER_FLUSH_FREEZE : 0; | |
263 | data |= MIB_COUNTER_READ; | |
264 | data |= (addr << MIB_COUNTER_INDEX_S); | |
265 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); | |
266 | ||
1c1eb580 MV |
267 | ret = regmap_read_poll_timeout(dev->regmap[2], |
268 | PORT_CTRL_ADDR(port, REG_PORT_MIB_CTRL_STAT__4), | |
269 | val, !(val & MIB_COUNTER_READ), 10, 1000); | |
7c6ff470 | 270 | /* failed to read MIB. get out of loop */ |
1c1eb580 | 271 | if (ret) { |
7c6ff470 TH |
272 | dev_dbg(dev->dev, "Failed to get MIB\n"); |
273 | return; | |
274 | } | |
275 | ||
276 | /* count resets upon read */ | |
277 | ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data); | |
278 | *cnt += data; | |
279 | } | |
280 | ||
281 | static void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | |
282 | u64 *dropped, u64 *cnt) | |
283 | { | |
284 | addr = ksz9477_mib_names[addr].index; | |
285 | ksz9477_r_mib_cnt(dev, port, addr, cnt); | |
286 | } | |
287 | ||
288 | static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze) | |
289 | { | |
290 | u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0; | |
291 | struct ksz_port *p = &dev->ports[port]; | |
292 | ||
293 | /* enable/disable the port for flush/freeze function */ | |
294 | mutex_lock(&p->mib.cnt_mutex); | |
295 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, val); | |
296 | ||
297 | /* used by MIB counter reading code to know freeze is enabled */ | |
298 | p->freeze = freeze; | |
299 | mutex_unlock(&p->mib.cnt_mutex); | |
300 | } | |
301 | ||
302 | static void ksz9477_port_init_cnt(struct ksz_device *dev, int port) | |
303 | { | |
304 | struct ksz_port_mib *mib = &dev->ports[port].mib; | |
305 | ||
306 | /* flush all enabled port MIB counters */ | |
307 | mutex_lock(&mib->cnt_mutex); | |
308 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, | |
309 | MIB_COUNTER_FLUSH_FREEZE); | |
310 | ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH); | |
311 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0); | |
312 | mutex_unlock(&mib->cnt_mutex); | |
313 | ||
314 | mib->cnt_ptr = 0; | |
315 | memset(mib->counters, 0, dev->mib_cnt * sizeof(u64)); | |
316 | } | |
317 | ||
c2e86691 TH |
318 | static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds, |
319 | int port) | |
320 | { | |
8c29bebb TH |
321 | enum dsa_tag_protocol proto = DSA_TAG_PROTO_KSZ9477; |
322 | struct ksz_device *dev = ds->priv; | |
323 | ||
324 | if (dev->features & IS_9893) | |
325 | proto = DSA_TAG_PROTO_KSZ9893; | |
326 | return proto; | |
c2e86691 TH |
327 | } |
328 | ||
329 | static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg) | |
330 | { | |
331 | struct ksz_device *dev = ds->priv; | |
332 | u16 val = 0xffff; | |
333 | ||
334 | /* No real PHY after this. Simulate the PHY. | |
335 | * A fixed PHY can be setup in the device tree, but this function is | |
336 | * still called for that port during initialization. | |
337 | * For RGMII PHY there is no way to access it so the fixed PHY should | |
338 | * be used. For SGMII PHY the supporting code will be added later. | |
339 | */ | |
340 | if (addr >= dev->phy_port_cnt) { | |
341 | struct ksz_port *p = &dev->ports[addr]; | |
342 | ||
343 | switch (reg) { | |
344 | case MII_BMCR: | |
345 | val = 0x1140; | |
346 | break; | |
347 | case MII_BMSR: | |
348 | val = 0x796d; | |
349 | break; | |
350 | case MII_PHYSID1: | |
351 | val = 0x0022; | |
352 | break; | |
353 | case MII_PHYSID2: | |
354 | val = 0x1631; | |
355 | break; | |
356 | case MII_ADVERTISE: | |
357 | val = 0x05e1; | |
358 | break; | |
359 | case MII_LPA: | |
360 | val = 0xc5e1; | |
361 | break; | |
362 | case MII_CTRL1000: | |
363 | val = 0x0700; | |
364 | break; | |
365 | case MII_STAT1000: | |
366 | if (p->phydev.speed == SPEED_1000) | |
367 | val = 0x3800; | |
368 | else | |
369 | val = 0; | |
370 | break; | |
371 | } | |
372 | } else { | |
373 | ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); | |
374 | } | |
375 | ||
376 | return val; | |
377 | } | |
378 | ||
379 | static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg, | |
380 | u16 val) | |
381 | { | |
382 | struct ksz_device *dev = ds->priv; | |
383 | ||
384 | /* No real PHY after this. */ | |
385 | if (addr >= dev->phy_port_cnt) | |
386 | return 0; | |
8c29bebb TH |
387 | |
388 | /* No gigabit support. Do not write to this register. */ | |
389 | if (!(dev->features & GBIT_SUPPORT) && reg == MII_CTRL1000) | |
390 | return 0; | |
c2e86691 TH |
391 | ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); |
392 | ||
393 | return 0; | |
394 | } | |
395 | ||
396 | static void ksz9477_get_strings(struct dsa_switch *ds, int port, | |
397 | u32 stringset, uint8_t *buf) | |
398 | { | |
399 | int i; | |
400 | ||
401 | if (stringset != ETH_SS_STATS) | |
402 | return; | |
403 | ||
404 | for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) { | |
405 | memcpy(buf + i * ETH_GSTRING_LEN, ksz9477_mib_names[i].string, | |
406 | ETH_GSTRING_LEN); | |
407 | } | |
408 | } | |
409 | ||
c2e86691 TH |
410 | static void ksz9477_cfg_port_member(struct ksz_device *dev, int port, |
411 | u8 member) | |
412 | { | |
413 | ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member); | |
414 | dev->ports[port].member = member; | |
415 | } | |
416 | ||
417 | static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port, | |
418 | u8 state) | |
419 | { | |
420 | struct ksz_device *dev = ds->priv; | |
421 | struct ksz_port *p = &dev->ports[port]; | |
422 | u8 data; | |
423 | int member = -1; | |
cbd72b48 | 424 | int forward = dev->member; |
c2e86691 TH |
425 | |
426 | ksz_pread8(dev, port, P_STP_CTRL, &data); | |
427 | data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); | |
428 | ||
429 | switch (state) { | |
430 | case BR_STATE_DISABLED: | |
431 | data |= PORT_LEARN_DISABLE; | |
432 | if (port != dev->cpu_port) | |
433 | member = 0; | |
434 | break; | |
435 | case BR_STATE_LISTENING: | |
436 | data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); | |
437 | if (port != dev->cpu_port && | |
438 | p->stp_state == BR_STATE_DISABLED) | |
439 | member = dev->host_mask | p->vid_member; | |
440 | break; | |
441 | case BR_STATE_LEARNING: | |
442 | data |= PORT_RX_ENABLE; | |
443 | break; | |
444 | case BR_STATE_FORWARDING: | |
445 | data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); | |
446 | ||
447 | /* This function is also used internally. */ | |
448 | if (port == dev->cpu_port) | |
449 | break; | |
450 | ||
451 | member = dev->host_mask | p->vid_member; | |
7049f9b5 | 452 | mutex_lock(&dev->dev_mutex); |
c2e86691 TH |
453 | |
454 | /* Port is a member of a bridge. */ | |
455 | if (dev->br_member & (1 << port)) { | |
456 | dev->member |= (1 << port); | |
457 | member = dev->member; | |
458 | } | |
7049f9b5 | 459 | mutex_unlock(&dev->dev_mutex); |
c2e86691 TH |
460 | break; |
461 | case BR_STATE_BLOCKING: | |
462 | data |= PORT_LEARN_DISABLE; | |
463 | if (port != dev->cpu_port && | |
464 | p->stp_state == BR_STATE_DISABLED) | |
465 | member = dev->host_mask | p->vid_member; | |
466 | break; | |
467 | default: | |
468 | dev_err(ds->dev, "invalid STP state: %d\n", state); | |
469 | return; | |
470 | } | |
471 | ||
472 | ksz_pwrite8(dev, port, P_STP_CTRL, data); | |
473 | p->stp_state = state; | |
7049f9b5 | 474 | mutex_lock(&dev->dev_mutex); |
c2e86691 TH |
475 | if (data & PORT_RX_ENABLE) |
476 | dev->rx_ports |= (1 << port); | |
477 | else | |
478 | dev->rx_ports &= ~(1 << port); | |
479 | if (data & PORT_TX_ENABLE) | |
480 | dev->tx_ports |= (1 << port); | |
481 | else | |
482 | dev->tx_ports &= ~(1 << port); | |
483 | ||
484 | /* Port membership may share register with STP state. */ | |
485 | if (member >= 0 && member != p->member) | |
486 | ksz9477_cfg_port_member(dev, port, (u8)member); | |
487 | ||
488 | /* Check if forwarding needs to be updated. */ | |
489 | if (state != BR_STATE_FORWARDING) { | |
490 | if (dev->br_member & (1 << port)) | |
491 | dev->member &= ~(1 << port); | |
492 | } | |
493 | ||
494 | /* When topology has changed the function ksz_update_port_member | |
cbd72b48 | 495 | * should be called to modify port forwarding behavior. |
c2e86691 | 496 | */ |
cbd72b48 TH |
497 | if (forward != dev->member) |
498 | ksz_update_port_member(dev, port); | |
7049f9b5 | 499 | mutex_unlock(&dev->dev_mutex); |
c2e86691 TH |
500 | } |
501 | ||
502 | static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) | |
503 | { | |
504 | u8 data; | |
505 | ||
506 | ksz_read8(dev, REG_SW_LUE_CTRL_2, &data); | |
507 | data &= ~(SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S); | |
508 | data |= (SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S); | |
509 | ksz_write8(dev, REG_SW_LUE_CTRL_2, data); | |
510 | if (port < dev->mib_port_cnt) { | |
511 | /* flush individual port */ | |
512 | ksz_pread8(dev, port, P_STP_CTRL, &data); | |
513 | if (!(data & PORT_LEARN_DISABLE)) | |
514 | ksz_pwrite8(dev, port, P_STP_CTRL, | |
515 | data | PORT_LEARN_DISABLE); | |
516 | ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true); | |
517 | ksz_pwrite8(dev, port, P_STP_CTRL, data); | |
518 | } else { | |
519 | /* flush all */ | |
520 | ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_STP_TABLE, true); | |
521 | } | |
522 | } | |
523 | ||
524 | static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port, | |
525 | bool flag) | |
526 | { | |
527 | struct ksz_device *dev = ds->priv; | |
528 | ||
529 | if (flag) { | |
530 | ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, | |
531 | PORT_VLAN_LOOKUP_VID_0, true); | |
c2e86691 TH |
532 | ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, true); |
533 | } else { | |
534 | ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, false); | |
c2e86691 TH |
535 | ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, |
536 | PORT_VLAN_LOOKUP_VID_0, false); | |
537 | } | |
538 | ||
539 | return 0; | |
540 | } | |
541 | ||
542 | static void ksz9477_port_vlan_add(struct dsa_switch *ds, int port, | |
543 | const struct switchdev_obj_port_vlan *vlan) | |
544 | { | |
545 | struct ksz_device *dev = ds->priv; | |
546 | u32 vlan_table[3]; | |
547 | u16 vid; | |
548 | bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; | |
549 | ||
550 | for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { | |
551 | if (ksz9477_get_vlan_table(dev, vid, vlan_table)) { | |
552 | dev_dbg(dev->dev, "Failed to get vlan table\n"); | |
553 | return; | |
554 | } | |
555 | ||
556 | vlan_table[0] = VLAN_VALID | (vid & VLAN_FID_M); | |
557 | if (untagged) | |
558 | vlan_table[1] |= BIT(port); | |
559 | else | |
560 | vlan_table[1] &= ~BIT(port); | |
561 | vlan_table[1] &= ~(BIT(dev->cpu_port)); | |
562 | ||
563 | vlan_table[2] |= BIT(port) | BIT(dev->cpu_port); | |
564 | ||
565 | if (ksz9477_set_vlan_table(dev, vid, vlan_table)) { | |
566 | dev_dbg(dev->dev, "Failed to set vlan table\n"); | |
567 | return; | |
568 | } | |
569 | ||
570 | /* change PVID */ | |
571 | if (vlan->flags & BRIDGE_VLAN_INFO_PVID) | |
572 | ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vid); | |
573 | } | |
574 | } | |
575 | ||
576 | static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port, | |
577 | const struct switchdev_obj_port_vlan *vlan) | |
578 | { | |
579 | struct ksz_device *dev = ds->priv; | |
580 | bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; | |
581 | u32 vlan_table[3]; | |
582 | u16 vid; | |
583 | u16 pvid; | |
584 | ||
585 | ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid); | |
586 | pvid = pvid & 0xFFF; | |
587 | ||
588 | for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { | |
589 | if (ksz9477_get_vlan_table(dev, vid, vlan_table)) { | |
590 | dev_dbg(dev->dev, "Failed to get vlan table\n"); | |
591 | return -ETIMEDOUT; | |
592 | } | |
593 | ||
594 | vlan_table[2] &= ~BIT(port); | |
595 | ||
596 | if (pvid == vid) | |
597 | pvid = 1; | |
598 | ||
599 | if (untagged) | |
600 | vlan_table[1] &= ~BIT(port); | |
601 | ||
602 | if (ksz9477_set_vlan_table(dev, vid, vlan_table)) { | |
603 | dev_dbg(dev->dev, "Failed to set vlan table\n"); | |
604 | return -ETIMEDOUT; | |
605 | } | |
606 | } | |
607 | ||
608 | ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid); | |
609 | ||
610 | return 0; | |
611 | } | |
612 | ||
613 | static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port, | |
614 | const unsigned char *addr, u16 vid) | |
615 | { | |
616 | struct ksz_device *dev = ds->priv; | |
617 | u32 alu_table[4]; | |
618 | u32 data; | |
619 | int ret = 0; | |
620 | ||
621 | mutex_lock(&dev->alu_mutex); | |
622 | ||
623 | /* find any entry with mac & vid */ | |
624 | data = vid << ALU_FID_INDEX_S; | |
625 | data |= ((addr[0] << 8) | addr[1]); | |
626 | ksz_write32(dev, REG_SW_ALU_INDEX_0, data); | |
627 | ||
628 | data = ((addr[2] << 24) | (addr[3] << 16)); | |
629 | data |= ((addr[4] << 8) | addr[5]); | |
630 | ksz_write32(dev, REG_SW_ALU_INDEX_1, data); | |
631 | ||
632 | /* start read operation */ | |
633 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); | |
634 | ||
635 | /* wait to be finished */ | |
636 | ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); | |
637 | if (ret < 0) { | |
638 | dev_dbg(dev->dev, "Failed to read ALU\n"); | |
639 | goto exit; | |
640 | } | |
641 | ||
642 | /* read ALU entry */ | |
643 | ksz9477_read_table(dev, alu_table); | |
644 | ||
645 | /* update ALU entry */ | |
646 | alu_table[0] = ALU_V_STATIC_VALID; | |
647 | alu_table[1] |= BIT(port); | |
648 | if (vid) | |
649 | alu_table[1] |= ALU_V_USE_FID; | |
650 | alu_table[2] = (vid << ALU_V_FID_S); | |
651 | alu_table[2] |= ((addr[0] << 8) | addr[1]); | |
652 | alu_table[3] = ((addr[2] << 24) | (addr[3] << 16)); | |
653 | alu_table[3] |= ((addr[4] << 8) | addr[5]); | |
654 | ||
655 | ksz9477_write_table(dev, alu_table); | |
656 | ||
657 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); | |
658 | ||
659 | /* wait to be finished */ | |
660 | ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); | |
661 | if (ret < 0) | |
662 | dev_dbg(dev->dev, "Failed to write ALU\n"); | |
663 | ||
664 | exit: | |
665 | mutex_unlock(&dev->alu_mutex); | |
666 | ||
667 | return ret; | |
668 | } | |
669 | ||
670 | static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port, | |
671 | const unsigned char *addr, u16 vid) | |
672 | { | |
673 | struct ksz_device *dev = ds->priv; | |
674 | u32 alu_table[4]; | |
675 | u32 data; | |
676 | int ret = 0; | |
677 | ||
678 | mutex_lock(&dev->alu_mutex); | |
679 | ||
680 | /* read any entry with mac & vid */ | |
681 | data = vid << ALU_FID_INDEX_S; | |
682 | data |= ((addr[0] << 8) | addr[1]); | |
683 | ksz_write32(dev, REG_SW_ALU_INDEX_0, data); | |
684 | ||
685 | data = ((addr[2] << 24) | (addr[3] << 16)); | |
686 | data |= ((addr[4] << 8) | addr[5]); | |
687 | ksz_write32(dev, REG_SW_ALU_INDEX_1, data); | |
688 | ||
689 | /* start read operation */ | |
690 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); | |
691 | ||
692 | /* wait to be finished */ | |
693 | ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); | |
694 | if (ret < 0) { | |
695 | dev_dbg(dev->dev, "Failed to read ALU\n"); | |
696 | goto exit; | |
697 | } | |
698 | ||
699 | ksz_read32(dev, REG_SW_ALU_VAL_A, &alu_table[0]); | |
700 | if (alu_table[0] & ALU_V_STATIC_VALID) { | |
701 | ksz_read32(dev, REG_SW_ALU_VAL_B, &alu_table[1]); | |
702 | ksz_read32(dev, REG_SW_ALU_VAL_C, &alu_table[2]); | |
703 | ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]); | |
704 | ||
705 | /* clear forwarding port */ | |
706 | alu_table[2] &= ~BIT(port); | |
707 | ||
708 | /* if there is no port to forward, clear table */ | |
709 | if ((alu_table[2] & ALU_V_PORT_MAP) == 0) { | |
710 | alu_table[0] = 0; | |
711 | alu_table[1] = 0; | |
712 | alu_table[2] = 0; | |
713 | alu_table[3] = 0; | |
714 | } | |
715 | } else { | |
716 | alu_table[0] = 0; | |
717 | alu_table[1] = 0; | |
718 | alu_table[2] = 0; | |
719 | alu_table[3] = 0; | |
720 | } | |
721 | ||
722 | ksz9477_write_table(dev, alu_table); | |
723 | ||
724 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); | |
725 | ||
726 | /* wait to be finished */ | |
727 | ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); | |
728 | if (ret < 0) | |
729 | dev_dbg(dev->dev, "Failed to write ALU\n"); | |
730 | ||
731 | exit: | |
732 | mutex_unlock(&dev->alu_mutex); | |
733 | ||
734 | return ret; | |
735 | } | |
736 | ||
737 | static void ksz9477_convert_alu(struct alu_struct *alu, u32 *alu_table) | |
738 | { | |
739 | alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID); | |
740 | alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER); | |
741 | alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER); | |
742 | alu->prio_age = (alu_table[0] >> ALU_V_PRIO_AGE_CNT_S) & | |
743 | ALU_V_PRIO_AGE_CNT_M; | |
744 | alu->mstp = alu_table[0] & ALU_V_MSTP_M; | |
745 | ||
746 | alu->is_override = !!(alu_table[1] & ALU_V_OVERRIDE); | |
747 | alu->is_use_fid = !!(alu_table[1] & ALU_V_USE_FID); | |
748 | alu->port_forward = alu_table[1] & ALU_V_PORT_MAP; | |
749 | ||
750 | alu->fid = (alu_table[2] >> ALU_V_FID_S) & ALU_V_FID_M; | |
751 | ||
752 | alu->mac[0] = (alu_table[2] >> 8) & 0xFF; | |
753 | alu->mac[1] = alu_table[2] & 0xFF; | |
754 | alu->mac[2] = (alu_table[3] >> 24) & 0xFF; | |
755 | alu->mac[3] = (alu_table[3] >> 16) & 0xFF; | |
756 | alu->mac[4] = (alu_table[3] >> 8) & 0xFF; | |
757 | alu->mac[5] = alu_table[3] & 0xFF; | |
758 | } | |
759 | ||
760 | static int ksz9477_port_fdb_dump(struct dsa_switch *ds, int port, | |
761 | dsa_fdb_dump_cb_t *cb, void *data) | |
762 | { | |
763 | struct ksz_device *dev = ds->priv; | |
764 | int ret = 0; | |
765 | u32 ksz_data; | |
766 | u32 alu_table[4]; | |
767 | struct alu_struct alu; | |
768 | int timeout; | |
769 | ||
770 | mutex_lock(&dev->alu_mutex); | |
771 | ||
772 | /* start ALU search */ | |
773 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_START | ALU_SEARCH); | |
774 | ||
775 | do { | |
776 | timeout = 1000; | |
777 | do { | |
778 | ksz_read32(dev, REG_SW_ALU_CTRL__4, &ksz_data); | |
779 | if ((ksz_data & ALU_VALID) || !(ksz_data & ALU_START)) | |
780 | break; | |
781 | usleep_range(1, 10); | |
782 | } while (timeout-- > 0); | |
783 | ||
784 | if (!timeout) { | |
785 | dev_dbg(dev->dev, "Failed to search ALU\n"); | |
786 | ret = -ETIMEDOUT; | |
787 | goto exit; | |
788 | } | |
789 | ||
790 | /* read ALU table */ | |
791 | ksz9477_read_table(dev, alu_table); | |
792 | ||
793 | ksz9477_convert_alu(&alu, alu_table); | |
794 | ||
795 | if (alu.port_forward & BIT(port)) { | |
796 | ret = cb(alu.mac, alu.fid, alu.is_static, data); | |
797 | if (ret) | |
798 | goto exit; | |
799 | } | |
800 | } while (ksz_data & ALU_START); | |
801 | ||
802 | exit: | |
803 | ||
804 | /* stop ALU search */ | |
805 | ksz_write32(dev, REG_SW_ALU_CTRL__4, 0); | |
806 | ||
807 | mutex_unlock(&dev->alu_mutex); | |
808 | ||
809 | return ret; | |
810 | } | |
811 | ||
812 | static void ksz9477_port_mdb_add(struct dsa_switch *ds, int port, | |
813 | const struct switchdev_obj_port_mdb *mdb) | |
814 | { | |
815 | struct ksz_device *dev = ds->priv; | |
816 | u32 static_table[4]; | |
817 | u32 data; | |
818 | int index; | |
819 | u32 mac_hi, mac_lo; | |
820 | ||
821 | mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); | |
822 | mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); | |
823 | mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); | |
824 | ||
825 | mutex_lock(&dev->alu_mutex); | |
826 | ||
827 | for (index = 0; index < dev->num_statics; index++) { | |
828 | /* find empty slot first */ | |
829 | data = (index << ALU_STAT_INDEX_S) | | |
830 | ALU_STAT_READ | ALU_STAT_START; | |
831 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
832 | ||
833 | /* wait to be finished */ | |
834 | if (ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) { | |
835 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); | |
836 | goto exit; | |
837 | } | |
838 | ||
839 | /* read ALU static table */ | |
840 | ksz9477_read_table(dev, static_table); | |
841 | ||
842 | if (static_table[0] & ALU_V_STATIC_VALID) { | |
843 | /* check this has same vid & mac address */ | |
844 | if (((static_table[2] >> ALU_V_FID_S) == mdb->vid) && | |
845 | ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && | |
846 | static_table[3] == mac_lo) { | |
847 | /* found matching one */ | |
848 | break; | |
849 | } | |
850 | } else { | |
851 | /* found empty one */ | |
852 | break; | |
853 | } | |
854 | } | |
855 | ||
856 | /* no available entry */ | |
857 | if (index == dev->num_statics) | |
858 | goto exit; | |
859 | ||
860 | /* add entry */ | |
861 | static_table[0] = ALU_V_STATIC_VALID; | |
862 | static_table[1] |= BIT(port); | |
863 | if (mdb->vid) | |
864 | static_table[1] |= ALU_V_USE_FID; | |
865 | static_table[2] = (mdb->vid << ALU_V_FID_S); | |
866 | static_table[2] |= mac_hi; | |
867 | static_table[3] = mac_lo; | |
868 | ||
869 | ksz9477_write_table(dev, static_table); | |
870 | ||
871 | data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; | |
872 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
873 | ||
874 | /* wait to be finished */ | |
875 | if (ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) | |
876 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); | |
877 | ||
878 | exit: | |
879 | mutex_unlock(&dev->alu_mutex); | |
880 | } | |
881 | ||
882 | static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port, | |
883 | const struct switchdev_obj_port_mdb *mdb) | |
884 | { | |
885 | struct ksz_device *dev = ds->priv; | |
886 | u32 static_table[4]; | |
887 | u32 data; | |
888 | int index; | |
889 | int ret = 0; | |
890 | u32 mac_hi, mac_lo; | |
891 | ||
892 | mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); | |
893 | mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); | |
894 | mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); | |
895 | ||
896 | mutex_lock(&dev->alu_mutex); | |
897 | ||
898 | for (index = 0; index < dev->num_statics; index++) { | |
899 | /* find empty slot first */ | |
900 | data = (index << ALU_STAT_INDEX_S) | | |
901 | ALU_STAT_READ | ALU_STAT_START; | |
902 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
903 | ||
904 | /* wait to be finished */ | |
905 | ret = ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000); | |
906 | if (ret < 0) { | |
907 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); | |
908 | goto exit; | |
909 | } | |
910 | ||
911 | /* read ALU static table */ | |
912 | ksz9477_read_table(dev, static_table); | |
913 | ||
914 | if (static_table[0] & ALU_V_STATIC_VALID) { | |
915 | /* check this has same vid & mac address */ | |
916 | ||
917 | if (((static_table[2] >> ALU_V_FID_S) == mdb->vid) && | |
918 | ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && | |
919 | static_table[3] == mac_lo) { | |
920 | /* found matching one */ | |
921 | break; | |
922 | } | |
923 | } | |
924 | } | |
925 | ||
926 | /* no available entry */ | |
927 | if (index == dev->num_statics) | |
928 | goto exit; | |
929 | ||
930 | /* clear port */ | |
931 | static_table[1] &= ~BIT(port); | |
932 | ||
933 | if ((static_table[1] & ALU_V_PORT_MAP) == 0) { | |
934 | /* delete entry */ | |
935 | static_table[0] = 0; | |
936 | static_table[1] = 0; | |
937 | static_table[2] = 0; | |
938 | static_table[3] = 0; | |
939 | } | |
940 | ||
941 | ksz9477_write_table(dev, static_table); | |
942 | ||
943 | data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; | |
944 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
945 | ||
946 | /* wait to be finished */ | |
947 | ret = ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000); | |
948 | if (ret < 0) | |
949 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); | |
950 | ||
951 | exit: | |
952 | mutex_unlock(&dev->alu_mutex); | |
953 | ||
954 | return ret; | |
955 | } | |
956 | ||
957 | static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port, | |
958 | struct dsa_mall_mirror_tc_entry *mirror, | |
959 | bool ingress) | |
960 | { | |
961 | struct ksz_device *dev = ds->priv; | |
962 | ||
963 | if (ingress) | |
964 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); | |
965 | else | |
966 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true); | |
967 | ||
968 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false); | |
969 | ||
970 | /* configure mirror port */ | |
971 | ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, | |
972 | PORT_MIRROR_SNIFFER, true); | |
973 | ||
974 | ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); | |
975 | ||
976 | return 0; | |
977 | } | |
978 | ||
979 | static void ksz9477_port_mirror_del(struct dsa_switch *ds, int port, | |
980 | struct dsa_mall_mirror_tc_entry *mirror) | |
981 | { | |
982 | struct ksz_device *dev = ds->priv; | |
983 | u8 data; | |
984 | ||
985 | if (mirror->ingress) | |
986 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false); | |
987 | else | |
988 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false); | |
989 | ||
990 | ksz_pread8(dev, port, P_MIRROR_CTRL, &data); | |
991 | ||
992 | if (!(data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) | |
993 | ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, | |
994 | PORT_MIRROR_SNIFFER, false); | |
995 | } | |
996 | ||
42fc6a4c TH |
997 | static void ksz9477_phy_setup(struct ksz_device *dev, int port, |
998 | struct phy_device *phy) | |
999 | { | |
8c29bebb TH |
1000 | /* Only apply to port with PHY. */ |
1001 | if (port >= dev->phy_port_cnt) | |
1002 | return; | |
1003 | ||
1004 | /* The MAC actually cannot run in 1000 half-duplex mode. */ | |
1005 | phy_remove_link_mode(phy, | |
1006 | ETHTOOL_LINK_MODE_1000baseT_Half_BIT); | |
1007 | ||
1008 | /* PHY does not support gigabit. */ | |
1009 | if (!(dev->features & GBIT_SUPPORT)) | |
42fc6a4c | 1010 | phy_remove_link_mode(phy, |
8c29bebb TH |
1011 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT); |
1012 | } | |
1013 | ||
1014 | static bool ksz9477_get_gbit(struct ksz_device *dev, u8 data) | |
1015 | { | |
1016 | bool gbit; | |
1017 | ||
1018 | if (dev->features & NEW_XMII) | |
1019 | gbit = !(data & PORT_MII_NOT_1GBIT); | |
1020 | else | |
1021 | gbit = !!(data & PORT_MII_1000MBIT_S1); | |
1022 | return gbit; | |
1023 | } | |
1024 | ||
1025 | static void ksz9477_set_gbit(struct ksz_device *dev, bool gbit, u8 *data) | |
1026 | { | |
1027 | if (dev->features & NEW_XMII) { | |
1028 | if (gbit) | |
1029 | *data &= ~PORT_MII_NOT_1GBIT; | |
1030 | else | |
1031 | *data |= PORT_MII_NOT_1GBIT; | |
1032 | } else { | |
1033 | if (gbit) | |
1034 | *data |= PORT_MII_1000MBIT_S1; | |
1035 | else | |
1036 | *data &= ~PORT_MII_1000MBIT_S1; | |
1037 | } | |
1038 | } | |
1039 | ||
1040 | static int ksz9477_get_xmii(struct ksz_device *dev, u8 data) | |
1041 | { | |
1042 | int mode; | |
1043 | ||
1044 | if (dev->features & NEW_XMII) { | |
1045 | switch (data & PORT_MII_SEL_M) { | |
1046 | case PORT_MII_SEL: | |
1047 | mode = 0; | |
1048 | break; | |
1049 | case PORT_RMII_SEL: | |
1050 | mode = 1; | |
1051 | break; | |
1052 | case PORT_GMII_SEL: | |
1053 | mode = 2; | |
1054 | break; | |
1055 | default: | |
1056 | mode = 3; | |
1057 | } | |
1058 | } else { | |
1059 | switch (data & PORT_MII_SEL_M) { | |
1060 | case PORT_MII_SEL_S1: | |
1061 | mode = 0; | |
1062 | break; | |
1063 | case PORT_RMII_SEL_S1: | |
1064 | mode = 1; | |
1065 | break; | |
1066 | case PORT_GMII_SEL_S1: | |
1067 | mode = 2; | |
1068 | break; | |
1069 | default: | |
1070 | mode = 3; | |
1071 | } | |
1072 | } | |
1073 | return mode; | |
1074 | } | |
1075 | ||
1076 | static void ksz9477_set_xmii(struct ksz_device *dev, int mode, u8 *data) | |
1077 | { | |
1078 | u8 xmii; | |
1079 | ||
1080 | if (dev->features & NEW_XMII) { | |
1081 | switch (mode) { | |
1082 | case 0: | |
1083 | xmii = PORT_MII_SEL; | |
1084 | break; | |
1085 | case 1: | |
1086 | xmii = PORT_RMII_SEL; | |
1087 | break; | |
1088 | case 2: | |
1089 | xmii = PORT_GMII_SEL; | |
1090 | break; | |
1091 | default: | |
1092 | xmii = PORT_RGMII_SEL; | |
1093 | break; | |
1094 | } | |
1095 | } else { | |
1096 | switch (mode) { | |
1097 | case 0: | |
1098 | xmii = PORT_MII_SEL_S1; | |
1099 | break; | |
1100 | case 1: | |
1101 | xmii = PORT_RMII_SEL_S1; | |
1102 | break; | |
1103 | case 2: | |
1104 | xmii = PORT_GMII_SEL_S1; | |
1105 | break; | |
1106 | default: | |
1107 | xmii = PORT_RGMII_SEL_S1; | |
1108 | break; | |
1109 | } | |
1110 | } | |
1111 | *data &= ~PORT_MII_SEL_M; | |
1112 | *data |= xmii; | |
1113 | } | |
1114 | ||
1115 | static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port) | |
1116 | { | |
1117 | phy_interface_t interface; | |
1118 | bool gbit; | |
1119 | int mode; | |
1120 | u8 data8; | |
1121 | ||
1122 | if (port < dev->phy_port_cnt) | |
1123 | return PHY_INTERFACE_MODE_NA; | |
1124 | ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); | |
1125 | gbit = ksz9477_get_gbit(dev, data8); | |
1126 | mode = ksz9477_get_xmii(dev, data8); | |
1127 | switch (mode) { | |
1128 | case 2: | |
1129 | interface = PHY_INTERFACE_MODE_GMII; | |
1130 | if (gbit) | |
1131 | break; | |
0fd12842 | 1132 | /* fall through */ |
8c29bebb TH |
1133 | case 0: |
1134 | interface = PHY_INTERFACE_MODE_MII; | |
1135 | break; | |
1136 | case 1: | |
1137 | interface = PHY_INTERFACE_MODE_RMII; | |
1138 | break; | |
1139 | default: | |
1140 | interface = PHY_INTERFACE_MODE_RGMII; | |
1141 | if (data8 & PORT_RGMII_ID_EG_ENABLE) | |
1142 | interface = PHY_INTERFACE_MODE_RGMII_TXID; | |
1143 | if (data8 & PORT_RGMII_ID_IG_ENABLE) { | |
1144 | interface = PHY_INTERFACE_MODE_RGMII_RXID; | |
1145 | if (data8 & PORT_RGMII_ID_EG_ENABLE) | |
1146 | interface = PHY_INTERFACE_MODE_RGMII_ID; | |
1147 | } | |
1148 | break; | |
42fc6a4c | 1149 | } |
8c29bebb | 1150 | return interface; |
42fc6a4c TH |
1151 | } |
1152 | ||
1fc33199 RH |
1153 | static void ksz9477_port_mmd_write(struct ksz_device *dev, int port, |
1154 | u8 dev_addr, u16 reg_addr, u16 val) | |
1155 | { | |
1156 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP, | |
1157 | MMD_SETUP(PORT_MMD_OP_INDEX, dev_addr)); | |
1158 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, reg_addr); | |
1159 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP, | |
1160 | MMD_SETUP(PORT_MMD_OP_DATA_NO_INCR, dev_addr)); | |
1161 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, val); | |
1162 | } | |
1163 | ||
1164 | static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port) | |
1165 | { | |
1166 | /* Apply PHY settings to address errata listed in | |
1167 | * KSZ9477, KSZ9897, KSZ9896, KSZ9567, KSZ8565 | |
1168 | * Silicon Errata and Data Sheet Clarification documents: | |
1169 | * | |
1170 | * Register settings are needed to improve PHY receive performance | |
1171 | */ | |
1172 | ksz9477_port_mmd_write(dev, port, 0x01, 0x6f, 0xdd0b); | |
1173 | ksz9477_port_mmd_write(dev, port, 0x01, 0x8f, 0x6032); | |
1174 | ksz9477_port_mmd_write(dev, port, 0x01, 0x9d, 0x248c); | |
1175 | ksz9477_port_mmd_write(dev, port, 0x01, 0x75, 0x0060); | |
1176 | ksz9477_port_mmd_write(dev, port, 0x01, 0xd3, 0x7777); | |
1177 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x06, 0x3008); | |
1178 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x08, 0x2001); | |
1179 | ||
1180 | /* Transmit waveform amplitude can be improved | |
1181 | * (1000BASE-T, 100BASE-TX, 10BASE-Te) | |
1182 | */ | |
1183 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x04, 0x00d0); | |
1184 | ||
1185 | /* Energy Efficient Ethernet (EEE) feature select must | |
1186 | * be manually disabled (except on KSZ8565 which is 100Mbit) | |
1187 | */ | |
1188 | if (dev->features & GBIT_SUPPORT) | |
1189 | ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000); | |
1190 | ||
1191 | /* Register settings are required to meet data sheet | |
1192 | * supply current specifications | |
1193 | */ | |
1194 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x13, 0x6eff); | |
1195 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x14, 0xe6ff); | |
1196 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x15, 0x6eff); | |
1197 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x16, 0xe6ff); | |
1198 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x17, 0x00ff); | |
1199 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x18, 0x43ff); | |
1200 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x19, 0xc3ff); | |
1201 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1a, 0x6fff); | |
1202 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1b, 0x07ff); | |
1203 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1c, 0x0fff); | |
1204 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1d, 0xe7ff); | |
1205 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1e, 0xefff); | |
1206 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee); | |
1207 | } | |
1208 | ||
c2e86691 TH |
1209 | static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) |
1210 | { | |
1211 | u8 data8; | |
1212 | u8 member; | |
1213 | u16 data16; | |
1214 | struct ksz_port *p = &dev->ports[port]; | |
1215 | ||
1216 | /* enable tag tail for host port */ | |
1217 | if (cpu_port) | |
1218 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE, | |
1219 | true); | |
1220 | ||
1221 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false); | |
1222 | ||
1223 | /* set back pressure */ | |
1224 | ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true); | |
1225 | ||
1226 | /* enable broadcast storm limit */ | |
1227 | ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); | |
1228 | ||
1229 | /* disable DiffServ priority */ | |
1230 | ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, false); | |
1231 | ||
1232 | /* replace priority */ | |
1233 | ksz_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, PORT_USER_PRIO_CEILING, | |
1234 | false); | |
1235 | ksz9477_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4, | |
1236 | MTI_PVID_REPLACE, false); | |
1237 | ||
1238 | /* enable 802.1p priority */ | |
1239 | ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); | |
1240 | ||
1241 | if (port < dev->phy_port_cnt) { | |
1242 | /* do not force flow control */ | |
1243 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, | |
1244 | PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, | |
1245 | false); | |
1246 | ||
1fc33199 RH |
1247 | if (dev->phy_errata_9477) |
1248 | ksz9477_phy_errata_setup(dev, port); | |
c2e86691 TH |
1249 | } else { |
1250 | /* force flow control */ | |
1251 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, | |
1252 | PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, | |
1253 | true); | |
1254 | ||
1255 | /* configure MAC to 1G & RGMII mode */ | |
1256 | ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); | |
c2e86691 TH |
1257 | switch (dev->interface) { |
1258 | case PHY_INTERFACE_MODE_MII: | |
8c29bebb TH |
1259 | ksz9477_set_xmii(dev, 0, &data8); |
1260 | ksz9477_set_gbit(dev, false, &data8); | |
c2e86691 TH |
1261 | p->phydev.speed = SPEED_100; |
1262 | break; | |
1263 | case PHY_INTERFACE_MODE_RMII: | |
8c29bebb TH |
1264 | ksz9477_set_xmii(dev, 1, &data8); |
1265 | ksz9477_set_gbit(dev, false, &data8); | |
c2e86691 TH |
1266 | p->phydev.speed = SPEED_100; |
1267 | break; | |
1268 | case PHY_INTERFACE_MODE_GMII: | |
8c29bebb TH |
1269 | ksz9477_set_xmii(dev, 2, &data8); |
1270 | ksz9477_set_gbit(dev, true, &data8); | |
c2e86691 TH |
1271 | p->phydev.speed = SPEED_1000; |
1272 | break; | |
1273 | default: | |
8c29bebb TH |
1274 | ksz9477_set_xmii(dev, 3, &data8); |
1275 | ksz9477_set_gbit(dev, true, &data8); | |
c2e86691 TH |
1276 | data8 &= ~PORT_RGMII_ID_IG_ENABLE; |
1277 | data8 &= ~PORT_RGMII_ID_EG_ENABLE; | |
1278 | if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID || | |
1279 | dev->interface == PHY_INTERFACE_MODE_RGMII_RXID) | |
1280 | data8 |= PORT_RGMII_ID_IG_ENABLE; | |
1281 | if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID || | |
1282 | dev->interface == PHY_INTERFACE_MODE_RGMII_TXID) | |
1283 | data8 |= PORT_RGMII_ID_EG_ENABLE; | |
c2e86691 TH |
1284 | p->phydev.speed = SPEED_1000; |
1285 | break; | |
1286 | } | |
1287 | ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); | |
1288 | p->phydev.duplex = 1; | |
1289 | } | |
7049f9b5 | 1290 | mutex_lock(&dev->dev_mutex); |
c2e86691 TH |
1291 | if (cpu_port) { |
1292 | member = dev->port_mask; | |
1293 | dev->on_ports = dev->host_mask; | |
1294 | dev->live_ports = dev->host_mask; | |
1295 | } else { | |
1296 | member = dev->host_mask | p->vid_member; | |
1297 | dev->on_ports |= (1 << port); | |
1298 | ||
1299 | /* Link was detected before port is enabled. */ | |
1300 | if (p->phydev.link) | |
1301 | dev->live_ports |= (1 << port); | |
1302 | } | |
7049f9b5 | 1303 | mutex_unlock(&dev->dev_mutex); |
c2e86691 TH |
1304 | ksz9477_cfg_port_member(dev, port, member); |
1305 | ||
1306 | /* clear pending interrupts */ | |
1307 | if (port < dev->phy_port_cnt) | |
1308 | ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16); | |
1309 | } | |
1310 | ||
1311 | static void ksz9477_config_cpu_port(struct dsa_switch *ds) | |
1312 | { | |
1313 | struct ksz_device *dev = ds->priv; | |
1314 | struct ksz_port *p; | |
1315 | int i; | |
1316 | ||
1317 | ds->num_ports = dev->port_cnt; | |
1318 | ||
1319 | for (i = 0; i < dev->port_cnt; i++) { | |
1320 | if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) { | |
8c29bebb TH |
1321 | phy_interface_t interface; |
1322 | ||
c2e86691 TH |
1323 | dev->cpu_port = i; |
1324 | dev->host_mask = (1 << dev->cpu_port); | |
1325 | dev->port_mask |= dev->host_mask; | |
1326 | ||
8c29bebb TH |
1327 | /* Read from XMII register to determine host port |
1328 | * interface. If set specifically in device tree | |
1329 | * note the difference to help debugging. | |
1330 | */ | |
1331 | interface = ksz9477_get_interface(dev, i); | |
1332 | if (!dev->interface) | |
1333 | dev->interface = interface; | |
1334 | if (interface && interface != dev->interface) | |
1335 | dev_info(dev->dev, | |
1336 | "use %s instead of %s\n", | |
1337 | phy_modes(dev->interface), | |
1338 | phy_modes(interface)); | |
1339 | ||
c2e86691 TH |
1340 | /* enable cpu port */ |
1341 | ksz9477_port_setup(dev, i, true); | |
1342 | p = &dev->ports[dev->cpu_port]; | |
1343 | p->vid_member = dev->port_mask; | |
1344 | p->on = 1; | |
1345 | } | |
1346 | } | |
1347 | ||
1348 | dev->member = dev->host_mask; | |
1349 | ||
1350 | for (i = 0; i < dev->mib_port_cnt; i++) { | |
1351 | if (i == dev->cpu_port) | |
1352 | continue; | |
1353 | p = &dev->ports[i]; | |
1354 | ||
1355 | /* Initialize to non-zero so that ksz_cfg_port_member() will | |
1356 | * be called. | |
1357 | */ | |
1358 | p->vid_member = (1 << i); | |
1359 | p->member = dev->port_mask; | |
1360 | ksz9477_port_stp_state_set(ds, i, BR_STATE_DISABLED); | |
1361 | p->on = 1; | |
1362 | if (i < dev->phy_port_cnt) | |
1363 | p->phy = 1; | |
1364 | if (dev->chip_id == 0x00947700 && i == 6) { | |
1365 | p->sgmii = 1; | |
1366 | ||
1367 | /* SGMII PHY detection code is not implemented yet. */ | |
1368 | p->phy = 0; | |
1369 | } | |
1370 | } | |
1371 | } | |
1372 | ||
1373 | static int ksz9477_setup(struct dsa_switch *ds) | |
1374 | { | |
1375 | struct ksz_device *dev = ds->priv; | |
1376 | int ret = 0; | |
1377 | ||
1378 | dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), | |
1379 | dev->num_vlans, GFP_KERNEL); | |
1380 | if (!dev->vlan_cache) | |
1381 | return -ENOMEM; | |
1382 | ||
1383 | ret = ksz9477_reset_switch(dev); | |
1384 | if (ret) { | |
1385 | dev_err(ds->dev, "failed to reset switch\n"); | |
1386 | return ret; | |
1387 | } | |
1388 | ||
962ad710 TH |
1389 | /* Required for port partitioning. */ |
1390 | ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, | |
1391 | true); | |
1392 | ||
8c29bebb TH |
1393 | /* Do not work correctly with tail tagging. */ |
1394 | ksz_cfg(dev, REG_SW_MAC_CTRL_0, SW_CHECK_LENGTH, false); | |
1395 | ||
c2e86691 TH |
1396 | /* accept packet up to 2000bytes */ |
1397 | ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true); | |
1398 | ||
1399 | ksz9477_config_cpu_port(ds); | |
1400 | ||
1401 | ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true); | |
1402 | ||
1403 | /* queue based egress rate limit */ | |
1404 | ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true); | |
1405 | ||
7c6ff470 TH |
1406 | /* enable global MIB counter freeze function */ |
1407 | ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true); | |
1408 | ||
c2e86691 TH |
1409 | /* start switch */ |
1410 | ksz_cfg(dev, REG_SW_OPERATION, SW_START, true); | |
1411 | ||
7c6ff470 TH |
1412 | ksz_init_mib_timer(dev); |
1413 | ||
c2e86691 TH |
1414 | return 0; |
1415 | } | |
1416 | ||
1417 | static const struct dsa_switch_ops ksz9477_switch_ops = { | |
1418 | .get_tag_protocol = ksz9477_get_tag_protocol, | |
1419 | .setup = ksz9477_setup, | |
1420 | .phy_read = ksz9477_phy_read16, | |
1421 | .phy_write = ksz9477_phy_write16, | |
c30d894b | 1422 | .adjust_link = ksz_adjust_link, |
c2e86691 TH |
1423 | .port_enable = ksz_enable_port, |
1424 | .port_disable = ksz_disable_port, | |
1425 | .get_strings = ksz9477_get_strings, | |
1426 | .get_ethtool_stats = ksz_get_ethtool_stats, | |
1427 | .get_sset_count = ksz_sset_count, | |
1428 | .port_bridge_join = ksz_port_bridge_join, | |
1429 | .port_bridge_leave = ksz_port_bridge_leave, | |
1430 | .port_stp_state_set = ksz9477_port_stp_state_set, | |
1431 | .port_fast_age = ksz_port_fast_age, | |
1432 | .port_vlan_filtering = ksz9477_port_vlan_filtering, | |
1433 | .port_vlan_prepare = ksz_port_vlan_prepare, | |
1434 | .port_vlan_add = ksz9477_port_vlan_add, | |
1435 | .port_vlan_del = ksz9477_port_vlan_del, | |
1436 | .port_fdb_dump = ksz9477_port_fdb_dump, | |
1437 | .port_fdb_add = ksz9477_port_fdb_add, | |
1438 | .port_fdb_del = ksz9477_port_fdb_del, | |
1439 | .port_mdb_prepare = ksz_port_mdb_prepare, | |
1440 | .port_mdb_add = ksz9477_port_mdb_add, | |
1441 | .port_mdb_del = ksz9477_port_mdb_del, | |
1442 | .port_mirror_add = ksz9477_port_mirror_add, | |
1443 | .port_mirror_del = ksz9477_port_mirror_del, | |
1444 | }; | |
1445 | ||
1446 | static u32 ksz9477_get_port_addr(int port, int offset) | |
1447 | { | |
1448 | return PORT_CTRL_ADDR(port, offset); | |
1449 | } | |
1450 | ||
1451 | static int ksz9477_switch_detect(struct ksz_device *dev) | |
1452 | { | |
1453 | u8 data8; | |
8c29bebb TH |
1454 | u8 id_hi; |
1455 | u8 id_lo; | |
c2e86691 TH |
1456 | u32 id32; |
1457 | int ret; | |
1458 | ||
1459 | /* turn off SPI DO Edge select */ | |
1460 | ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); | |
1461 | if (ret) | |
1462 | return ret; | |
1463 | ||
1464 | data8 &= ~SPI_AUTO_EDGE_DETECTION; | |
1465 | ret = ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); | |
1466 | if (ret) | |
1467 | return ret; | |
1468 | ||
1469 | /* read chip id */ | |
1470 | ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32); | |
8c29bebb TH |
1471 | if (ret) |
1472 | return ret; | |
1473 | ret = ksz_read8(dev, REG_GLOBAL_OPTIONS, &data8); | |
c2e86691 TH |
1474 | if (ret) |
1475 | return ret; | |
1476 | ||
1477 | /* Number of ports can be reduced depending on chip. */ | |
1478 | dev->mib_port_cnt = TOTAL_PORT_NUM; | |
1479 | dev->phy_port_cnt = 5; | |
1480 | ||
8c29bebb TH |
1481 | /* Default capability is gigabit capable. */ |
1482 | dev->features = GBIT_SUPPORT; | |
1483 | ||
1484 | id_hi = (u8)(id32 >> 16); | |
1485 | id_lo = (u8)(id32 >> 8); | |
1486 | if ((id_lo & 0xf) == 3) { | |
1487 | /* Chip is from KSZ9893 design. */ | |
1488 | dev->features |= IS_9893; | |
1489 | ||
1490 | /* Chip does not support gigabit. */ | |
1491 | if (data8 & SW_QW_ABLE) | |
1492 | dev->features &= ~GBIT_SUPPORT; | |
1493 | dev->mib_port_cnt = 3; | |
1494 | dev->phy_port_cnt = 2; | |
1495 | } else { | |
1496 | /* Chip uses new XMII register definitions. */ | |
1497 | dev->features |= NEW_XMII; | |
1498 | ||
1499 | /* Chip does not support gigabit. */ | |
1500 | if (!(data8 & SW_GIGABIT_ABLE)) | |
1501 | dev->features &= ~GBIT_SUPPORT; | |
1502 | } | |
1503 | ||
1504 | /* Change chip id to known ones so it can be matched against them. */ | |
1505 | id32 = (id_hi << 16) | (id_lo << 8); | |
1506 | ||
c2e86691 TH |
1507 | dev->chip_id = id32; |
1508 | ||
1509 | return 0; | |
1510 | } | |
1511 | ||
1512 | struct ksz_chip_data { | |
1513 | u32 chip_id; | |
1514 | const char *dev_name; | |
1515 | int num_vlans; | |
1516 | int num_alus; | |
1517 | int num_statics; | |
1518 | int cpu_ports; | |
1519 | int port_cnt; | |
1fc33199 | 1520 | bool phy_errata_9477; |
c2e86691 TH |
1521 | }; |
1522 | ||
1523 | static const struct ksz_chip_data ksz9477_switch_chips[] = { | |
1524 | { | |
1525 | .chip_id = 0x00947700, | |
1526 | .dev_name = "KSZ9477", | |
1527 | .num_vlans = 4096, | |
1528 | .num_alus = 4096, | |
1529 | .num_statics = 16, | |
1530 | .cpu_ports = 0x7F, /* can be configured as cpu port */ | |
1531 | .port_cnt = 7, /* total physical port count */ | |
1fc33199 | 1532 | .phy_errata_9477 = true, |
c2e86691 TH |
1533 | }, |
1534 | { | |
1535 | .chip_id = 0x00989700, | |
1536 | .dev_name = "KSZ9897", | |
1537 | .num_vlans = 4096, | |
1538 | .num_alus = 4096, | |
1539 | .num_statics = 16, | |
1540 | .cpu_ports = 0x7F, /* can be configured as cpu port */ | |
1541 | .port_cnt = 7, /* total physical port count */ | |
1fc33199 | 1542 | .phy_errata_9477 = true, |
c2e86691 | 1543 | }, |
8c29bebb TH |
1544 | { |
1545 | .chip_id = 0x00989300, | |
1546 | .dev_name = "KSZ9893", | |
1547 | .num_vlans = 4096, | |
1548 | .num_alus = 4096, | |
1549 | .num_statics = 16, | |
1550 | .cpu_ports = 0x07, /* can be configured as cpu port */ | |
1551 | .port_cnt = 3, /* total port count */ | |
1552 | }, | |
c2e86691 TH |
1553 | }; |
1554 | ||
1555 | static int ksz9477_switch_init(struct ksz_device *dev) | |
1556 | { | |
1557 | int i; | |
1558 | ||
1559 | dev->ds->ops = &ksz9477_switch_ops; | |
1560 | ||
1561 | for (i = 0; i < ARRAY_SIZE(ksz9477_switch_chips); i++) { | |
1562 | const struct ksz_chip_data *chip = &ksz9477_switch_chips[i]; | |
1563 | ||
1564 | if (dev->chip_id == chip->chip_id) { | |
1565 | dev->name = chip->dev_name; | |
1566 | dev->num_vlans = chip->num_vlans; | |
1567 | dev->num_alus = chip->num_alus; | |
1568 | dev->num_statics = chip->num_statics; | |
1569 | dev->port_cnt = chip->port_cnt; | |
1570 | dev->cpu_ports = chip->cpu_ports; | |
1fc33199 | 1571 | dev->phy_errata_9477 = chip->phy_errata_9477; |
c2e86691 TH |
1572 | |
1573 | break; | |
1574 | } | |
1575 | } | |
1576 | ||
1577 | /* no switch found */ | |
1578 | if (!dev->port_cnt) | |
1579 | return -ENODEV; | |
1580 | ||
1581 | dev->port_mask = (1 << dev->port_cnt) - 1; | |
1582 | ||
1583 | dev->reg_mib_cnt = SWITCH_COUNTER_NUM; | |
1584 | dev->mib_cnt = TOTAL_SWITCH_COUNTER_NUM; | |
1585 | ||
1586 | i = dev->mib_port_cnt; | |
1587 | dev->ports = devm_kzalloc(dev->dev, sizeof(struct ksz_port) * i, | |
1588 | GFP_KERNEL); | |
1589 | if (!dev->ports) | |
1590 | return -ENOMEM; | |
1591 | for (i = 0; i < dev->mib_port_cnt; i++) { | |
7c6ff470 | 1592 | mutex_init(&dev->ports[i].mib.cnt_mutex); |
c2e86691 TH |
1593 | dev->ports[i].mib.counters = |
1594 | devm_kzalloc(dev->dev, | |
1595 | sizeof(u64) * | |
1596 | (TOTAL_SWITCH_COUNTER_NUM + 1), | |
1597 | GFP_KERNEL); | |
1598 | if (!dev->ports[i].mib.counters) | |
1599 | return -ENOMEM; | |
1600 | } | |
c2e86691 TH |
1601 | |
1602 | return 0; | |
1603 | } | |
1604 | ||
1605 | static void ksz9477_switch_exit(struct ksz_device *dev) | |
1606 | { | |
1607 | ksz9477_reset_switch(dev); | |
1608 | } | |
1609 | ||
1610 | static const struct ksz_dev_ops ksz9477_dev_ops = { | |
1611 | .get_port_addr = ksz9477_get_port_addr, | |
1612 | .cfg_port_member = ksz9477_cfg_port_member, | |
1613 | .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, | |
42fc6a4c | 1614 | .phy_setup = ksz9477_phy_setup, |
c2e86691 | 1615 | .port_setup = ksz9477_port_setup, |
7c6ff470 TH |
1616 | .r_mib_cnt = ksz9477_r_mib_cnt, |
1617 | .r_mib_pkt = ksz9477_r_mib_pkt, | |
1618 | .freeze_mib = ksz9477_freeze_mib, | |
1619 | .port_init_cnt = ksz9477_port_init_cnt, | |
c2e86691 TH |
1620 | .shutdown = ksz9477_reset_switch, |
1621 | .detect = ksz9477_switch_detect, | |
1622 | .init = ksz9477_switch_init, | |
1623 | .exit = ksz9477_switch_exit, | |
1624 | }; | |
1625 | ||
1626 | int ksz9477_switch_register(struct ksz_device *dev) | |
1627 | { | |
1628 | return ksz_switch_register(dev, &ksz9477_dev_ops); | |
1629 | } | |
1630 | EXPORT_SYMBOL(ksz9477_switch_register); | |
1631 | ||
1632 | MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>"); | |
1633 | MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch DSA Driver"); | |
1634 | MODULE_LICENSE("GPL"); |