1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Microchip LAN937X switch driver main logic |
3 | * Copyright (C) 2019-2022 Microchip Technology Inc. |
4 | */ |
5 | #include <linux/kernel.h> |
6 | #include <linux/module.h> |
7 | #include <linux/iopoll.h> |
8 | #include <linux/phy.h> |
9 | #include <linux/of_net.h> |
10 | #include <linux/if_bridge.h> |
11 | #include <linux/if_vlan.h> |
12 | #include <linux/math.h> |
13 | #include <net/dsa.h> |
14 | #include <net/switchdev.h> |
15 | |
16 | #include "lan937x_reg.h" |
17 | #include "ksz_common.h" |
18 | #include "ksz9477.h" |
19 | #include "lan937x.h" |
20 | |
21 | static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) |
22 | { |
23 | return regmap_update_bits(map: ksz_regmap_8(dev), reg: addr, mask: bits, val: set ? bits : 0); |
24 | } |
25 | |
26 | static int lan937x_port_cfg(struct ksz_device *dev, int port, int offset, |
27 | u8 bits, bool set) |
28 | { |
29 | return regmap_update_bits(map: ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset), |
30 | mask: bits, val: set ? bits : 0); |
31 | } |
32 | |
33 | static int lan937x_enable_spi_indirect_access(struct ksz_device *dev) |
34 | { |
35 | u16 data16; |
36 | int ret; |
37 | |
38 | /* Enable Phy access through SPI */ |
39 | ret = lan937x_cfg(dev, REG_GLOBAL_CTRL_0, SW_PHY_REG_BLOCK, set: false); |
40 | if (ret < 0) |
41 | return ret; |
42 | |
43 | ret = ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, val: &data16); |
44 | if (ret < 0) |
45 | return ret; |
46 | |
47 | /* Allow SPI access */ |
48 | data16 |= VPHY_SPI_INDIRECT_ENABLE; |
49 | |
50 | return ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, value: data16); |
51 | } |
52 | |
53 | static int lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg) |
54 | { |
55 | u16 addr_base = REG_PORT_T1_PHY_CTRL_BASE; |
56 | u16 temp; |
57 | |
58 | /* get register address based on the logical port */ |
59 | temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2))); |
60 | |
61 | return ksz_write16(dev, REG_VPHY_IND_ADDR__2, value: temp); |
62 | } |
63 | |
64 | static int lan937x_internal_phy_write(struct ksz_device *dev, int addr, int reg, |
65 | u16 val) |
66 | { |
67 | unsigned int value; |
68 | int ret; |
69 | |
70 | /* Check for internal phy port */ |
71 | if (!dev->info->internal_phy[addr]) |
72 | return -EOPNOTSUPP; |
73 | |
74 | ret = lan937x_vphy_ind_addr_wr(dev, addr, reg); |
75 | if (ret < 0) |
76 | return ret; |
77 | |
78 | /* Write the data to be written to the VPHY reg */ |
79 | ret = ksz_write16(dev, REG_VPHY_IND_DATA__2, value: val); |
80 | if (ret < 0) |
81 | return ret; |
82 | |
83 | /* Write the Write En and Busy bit */ |
84 | ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2, |
85 | value: (VPHY_IND_WRITE | VPHY_IND_BUSY)); |
86 | if (ret < 0) |
87 | return ret; |
88 | |
89 | ret = regmap_read_poll_timeout(ksz_regmap_16(dev), REG_VPHY_IND_CTRL__2, |
90 | value, !(value & VPHY_IND_BUSY), 10, |
91 | 1000); |
92 | if (ret < 0) { |
93 | dev_err(dev->dev, "Failed to write phy register\n" ); |
94 | return ret; |
95 | } |
96 | |
97 | return 0; |
98 | } |
99 | |
100 | static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, |
101 | u16 *val) |
102 | { |
103 | unsigned int value; |
104 | int ret; |
105 | |
106 | /* Check for internal phy port, return 0xffff for non-existent phy */ |
107 | if (!dev->info->internal_phy[addr]) |
108 | return 0xffff; |
109 | |
110 | ret = lan937x_vphy_ind_addr_wr(dev, addr, reg); |
111 | if (ret < 0) |
112 | return ret; |
113 | |
114 | /* Write Read and Busy bit to start the transaction */ |
115 | ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2, VPHY_IND_BUSY); |
116 | if (ret < 0) |
117 | return ret; |
118 | |
119 | ret = regmap_read_poll_timeout(ksz_regmap_16(dev), REG_VPHY_IND_CTRL__2, |
120 | value, !(value & VPHY_IND_BUSY), 10, |
121 | 1000); |
122 | if (ret < 0) { |
123 | dev_err(dev->dev, "Failed to read phy register\n" ); |
124 | return ret; |
125 | } |
126 | |
127 | /* Read the VPHY register which has the PHY data */ |
128 | return ksz_read16(dev, REG_VPHY_IND_DATA__2, val); |
129 | } |
130 | |
131 | int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) |
132 | { |
133 | return lan937x_internal_phy_read(dev, addr, reg, val: data); |
134 | } |
135 | |
136 | int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) |
137 | { |
138 | return lan937x_internal_phy_write(dev, addr, reg, val); |
139 | } |
140 | |
141 | int lan937x_reset_switch(struct ksz_device *dev) |
142 | { |
143 | u32 data32; |
144 | int ret; |
145 | |
146 | /* reset switch */ |
147 | ret = lan937x_cfg(dev, REG_SW_OPERATION, SW_RESET, set: true); |
148 | if (ret < 0) |
149 | return ret; |
150 | |
151 | /* Enable Auto Aging */ |
152 | ret = lan937x_cfg(dev, REG_SW_LUE_CTRL_1, SW_LINK_AUTO_AGING, set: true); |
153 | if (ret < 0) |
154 | return ret; |
155 | |
156 | /* disable interrupts */ |
157 | ret = ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); |
158 | if (ret < 0) |
159 | return ret; |
160 | |
161 | ret = ksz_write32(dev, REG_SW_INT_STATUS__4, POR_READY_INT); |
162 | if (ret < 0) |
163 | return ret; |
164 | |
165 | ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, value: 0xFF); |
166 | if (ret < 0) |
167 | return ret; |
168 | |
169 | return ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, val: &data32); |
170 | } |
171 | |
172 | void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) |
173 | { |
174 | const u32 *masks = dev->info->masks; |
175 | const u16 *regs = dev->info->regs; |
176 | struct dsa_switch *ds = dev->ds; |
177 | u8 member; |
178 | |
179 | /* enable tag tail for host port */ |
180 | if (cpu_port) |
181 | lan937x_port_cfg(dev, port, REG_PORT_CTRL_0, |
182 | PORT_TAIL_TAG_ENABLE, set: true); |
183 | |
184 | /* Enable the Port Queue split */ |
185 | ksz9477_port_queue_split(dev, port); |
186 | |
187 | /* set back pressure for half duplex */ |
188 | lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, |
189 | set: true); |
190 | |
191 | /* enable 802.1p priority */ |
192 | lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, set: true); |
193 | |
194 | if (!dev->info->internal_phy[port]) |
195 | lan937x_port_cfg(dev, port, offset: regs[P_XMII_CTRL_0], |
196 | bits: masks[P_MII_TX_FLOW_CTRL] | |
197 | masks[P_MII_RX_FLOW_CTRL], |
198 | set: true); |
199 | |
200 | if (cpu_port) |
201 | member = dsa_user_ports(ds); |
202 | else |
203 | member = BIT(dsa_upstream_port(ds, port)); |
204 | |
205 | dev->dev_ops->cfg_port_member(dev, port, member); |
206 | } |
207 | |
208 | void lan937x_config_cpu_port(struct dsa_switch *ds) |
209 | { |
210 | struct ksz_device *dev = ds->priv; |
211 | struct dsa_port *dp; |
212 | |
213 | dsa_switch_for_each_cpu_port(dp, ds) { |
214 | if (dev->info->cpu_ports & (1 << dp->index)) { |
215 | dev->cpu_port = dp->index; |
216 | |
217 | /* enable cpu port */ |
218 | lan937x_port_setup(dev, port: dp->index, cpu_port: true); |
219 | } |
220 | } |
221 | |
222 | dsa_switch_for_each_user_port(dp, ds) { |
223 | ksz_port_stp_state_set(ds, port: dp->index, BR_STATE_DISABLED); |
224 | } |
225 | } |
226 | |
227 | int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu) |
228 | { |
229 | struct dsa_switch *ds = dev->ds; |
230 | int ret; |
231 | |
232 | new_mtu += VLAN_ETH_HLEN + ETH_FCS_LEN; |
233 | |
234 | if (dsa_is_cpu_port(ds, p: port)) |
235 | new_mtu += LAN937X_TAG_LEN; |
236 | |
237 | if (new_mtu >= FR_MIN_SIZE) |
238 | ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, |
239 | PORT_JUMBO_PACKET, set: true); |
240 | else |
241 | ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, |
242 | PORT_JUMBO_PACKET, set: false); |
243 | if (ret < 0) { |
244 | dev_err(ds->dev, "failed to enable jumbo\n" ); |
245 | return ret; |
246 | } |
247 | |
248 | /* Write the frame size in PORT_MAX_FR_SIZE register */ |
249 | ret = ksz_pwrite16(dev, port, PORT_MAX_FR_SIZE, data: new_mtu); |
250 | if (ret) { |
251 | dev_err(ds->dev, "failed to update mtu for port %d\n" , port); |
252 | return ret; |
253 | } |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | int lan937x_set_ageing_time(struct ksz_device *dev, unsigned int msecs) |
259 | { |
260 | u32 secs = msecs / 1000; |
261 | u32 value; |
262 | int ret; |
263 | |
264 | value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs); |
265 | |
266 | ret = ksz_write8(dev, REG_SW_AGE_PERIOD__1, value); |
267 | if (ret < 0) |
268 | return ret; |
269 | |
270 | value = FIELD_GET(SW_AGE_PERIOD_19_8_M, secs); |
271 | |
272 | return ksz_write16(dev, REG_SW_AGE_PERIOD__2, value); |
273 | } |
274 | |
275 | static void lan937x_set_tune_adj(struct ksz_device *dev, int port, |
276 | u16 reg, u8 val) |
277 | { |
278 | u16 data16; |
279 | |
280 | ksz_pread16(dev, port, offset: reg, data: &data16); |
281 | |
282 | /* Update tune Adjust */ |
283 | data16 |= FIELD_PREP(PORT_TUNE_ADJ, val); |
284 | ksz_pwrite16(dev, port, offset: reg, data: data16); |
285 | |
286 | /* write DLL reset to take effect */ |
287 | data16 |= PORT_DLL_RESET; |
288 | ksz_pwrite16(dev, port, offset: reg, data: data16); |
289 | } |
290 | |
291 | static void lan937x_set_rgmii_tx_delay(struct ksz_device *dev, int port) |
292 | { |
293 | u8 val; |
294 | |
295 | /* Apply different codes based on the ports as per characterization |
296 | * results |
297 | */ |
298 | val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS : |
299 | RGMII_2_TX_DELAY_2NS; |
300 | |
301 | lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_5, val); |
302 | } |
303 | |
304 | static void lan937x_set_rgmii_rx_delay(struct ksz_device *dev, int port) |
305 | { |
306 | u8 val; |
307 | |
308 | val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_RX_DELAY_2NS : |
309 | RGMII_2_RX_DELAY_2NS; |
310 | |
311 | lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_4, val); |
312 | } |
313 | |
314 | void lan937x_phylink_get_caps(struct ksz_device *dev, int port, |
315 | struct phylink_config *config) |
316 | { |
317 | config->mac_capabilities = MAC_100FD; |
318 | |
319 | if (dev->info->supports_rgmii[port]) { |
320 | /* MII/RMII/RGMII ports */ |
321 | config->mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE | |
322 | MAC_100HD | MAC_10 | MAC_1000FD; |
323 | } |
324 | } |
325 | |
326 | void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port) |
327 | { |
328 | struct ksz_port *p = &dev->ports[port]; |
329 | |
330 | if (p->rgmii_tx_val) { |
331 | lan937x_set_rgmii_tx_delay(dev, port); |
332 | dev_info(dev->dev, "Applied rgmii tx delay for the port %d\n" , |
333 | port); |
334 | } |
335 | |
336 | if (p->rgmii_rx_val) { |
337 | lan937x_set_rgmii_rx_delay(dev, port); |
338 | dev_info(dev->dev, "Applied rgmii rx delay for the port %d\n" , |
339 | port); |
340 | } |
341 | } |
342 | |
343 | int lan937x_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val) |
344 | { |
345 | return ksz_pwrite32(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, data: val); |
346 | } |
347 | |
348 | int lan937x_switch_init(struct ksz_device *dev) |
349 | { |
350 | dev->port_mask = (1 << dev->info->port_cnt) - 1; |
351 | |
352 | return 0; |
353 | } |
354 | |
355 | int lan937x_setup(struct dsa_switch *ds) |
356 | { |
357 | struct ksz_device *dev = ds->priv; |
358 | int ret; |
359 | |
360 | /* enable Indirect Access from SPI to the VPHY registers */ |
361 | ret = lan937x_enable_spi_indirect_access(dev); |
362 | if (ret < 0) { |
363 | dev_err(dev->dev, "failed to enable spi indirect access" ); |
364 | return ret; |
365 | } |
366 | |
367 | /* The VLAN aware is a global setting. Mixed vlan |
368 | * filterings are not supported. |
369 | */ |
370 | ds->vlan_filtering_is_global = true; |
371 | |
372 | /* Enable aggressive back off for half duplex & UNH mode */ |
373 | lan937x_cfg(dev, REG_SW_MAC_CTRL_0, |
374 | bits: (SW_PAUSE_UNH_MODE | SW_NEW_BACKOFF | SW_AGGR_BACKOFF), |
375 | set: true); |
376 | |
377 | /* If NO_EXC_COLLISION_DROP bit is set, the switch will not drop |
378 | * packets when 16 or more collisions occur |
379 | */ |
380 | lan937x_cfg(dev, REG_SW_MAC_CTRL_1, NO_EXC_COLLISION_DROP, set: true); |
381 | |
382 | /* enable global MIB counter freeze function */ |
383 | lan937x_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, set: true); |
384 | |
385 | /* disable CLK125 & CLK25, 1: disable, 0: enable */ |
386 | lan937x_cfg(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1, |
387 | bits: (SW_CLK125_ENB | SW_CLK25_ENB), set: true); |
388 | |
389 | return 0; |
390 | } |
391 | |
392 | void lan937x_teardown(struct dsa_switch *ds) |
393 | { |
394 | |
395 | } |
396 | |
397 | void lan937x_switch_exit(struct ksz_device *dev) |
398 | { |
399 | lan937x_reset_switch(dev); |
400 | } |
401 | |
402 | MODULE_AUTHOR("Arun Ramadoss <arun.ramadoss@microchip.com>" ); |
403 | MODULE_DESCRIPTION("Microchip LAN937x Series Switch DSA Driver" ); |
404 | MODULE_LICENSE("GPL" ); |
405 | |