11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a1292595SJuergen Beisert /*
3a1292595SJuergen Beisert * Copyright (C) 2017 Pengutronix, Juergen Borleis <kernel@pengutronix.de>
4a1292595SJuergen Beisert */
5a1292595SJuergen Beisert #include <linux/kernel.h>
6a1292595SJuergen Beisert #include <linux/module.h>
7a1292595SJuergen Beisert #include <linux/gpio/consumer.h>
8a1292595SJuergen Beisert #include <linux/regmap.h>
9*28a2c3e5SAnatolij Gustschin #include <linux/iopoll.h>
10a1292595SJuergen Beisert #include <linux/mutex.h>
11a1292595SJuergen Beisert #include <linux/mii.h>
12f44a9010SRob Herring #include <linux/of.h>
134d6a78b4SEgil Hjelmeland #include <linux/phy.h>
14d99a86aeSEgil Hjelmeland #include <linux/if_bridge.h>
15430065e2SMans Rullgard #include <linux/if_vlan.h>
160620427eSEgil Hjelmeland #include <linux/etherdevice.h>
17a1292595SJuergen Beisert
18a1292595SJuergen Beisert #include "lan9303.h"
19a1292595SJuergen Beisert
2056e23d91SJerry Ray /* For the LAN9303 and LAN9354, only port 0 is an XMII port. */
2156e23d91SJerry Ray #define IS_PORT_XMII(port) ((port) == 0)
2256e23d91SJerry Ray
23a368ca53SEgil Hjelmeland #define LAN9303_NUM_PORTS 3
24a368ca53SEgil Hjelmeland
25ab78acb1SEgil Hjelmeland /* 13.2 System Control and Status Registers
26ab78acb1SEgil Hjelmeland * Multiply register number by 4 to get address offset.
27ab78acb1SEgil Hjelmeland */
28a1292595SJuergen Beisert #define LAN9303_CHIP_REV 0x14
29a1292595SJuergen Beisert # define LAN9303_CHIP_ID 0x9303
3013248b97SJerry Ray # define LAN9352_CHIP_ID 0x9352
3113248b97SJerry Ray # define LAN9353_CHIP_ID 0x9353
3213248b97SJerry Ray # define LAN9354_CHIP_ID 0x9354
3313248b97SJerry Ray # define LAN9355_CHIP_ID 0x9355
34a1292595SJuergen Beisert #define LAN9303_IRQ_CFG 0x15
35a1292595SJuergen Beisert # define LAN9303_IRQ_CFG_IRQ_ENABLE BIT(8)
36a1292595SJuergen Beisert # define LAN9303_IRQ_CFG_IRQ_POL BIT(4)
37a1292595SJuergen Beisert # define LAN9303_IRQ_CFG_IRQ_TYPE BIT(0)
38a1292595SJuergen Beisert #define LAN9303_INT_STS 0x16
39a1292595SJuergen Beisert # define LAN9303_INT_STS_PHY_INT2 BIT(27)
40a1292595SJuergen Beisert # define LAN9303_INT_STS_PHY_INT1 BIT(26)
41a1292595SJuergen Beisert #define LAN9303_INT_EN 0x17
42a1292595SJuergen Beisert # define LAN9303_INT_EN_PHY_INT2_EN BIT(27)
43a1292595SJuergen Beisert # define LAN9303_INT_EN_PHY_INT1_EN BIT(26)
44732f374eSJerry Ray #define LAN9303_BYTE_ORDER 0x19
45a1292595SJuergen Beisert #define LAN9303_HW_CFG 0x1D
46a1292595SJuergen Beisert # define LAN9303_HW_CFG_READY BIT(27)
47a1292595SJuergen Beisert # define LAN9303_HW_CFG_AMDX_EN_PORT2 BIT(26)
48a1292595SJuergen Beisert # define LAN9303_HW_CFG_AMDX_EN_PORT1 BIT(25)
49a1292595SJuergen Beisert #define LAN9303_PMI_DATA 0x29
50a1292595SJuergen Beisert #define LAN9303_PMI_ACCESS 0x2A
51a1292595SJuergen Beisert # define LAN9303_PMI_ACCESS_PHY_ADDR(x) (((x) & 0x1f) << 11)
52a1292595SJuergen Beisert # define LAN9303_PMI_ACCESS_MIIRINDA(x) (((x) & 0x1f) << 6)
53a1292595SJuergen Beisert # define LAN9303_PMI_ACCESS_MII_BUSY BIT(0)
54a1292595SJuergen Beisert # define LAN9303_PMI_ACCESS_MII_WRITE BIT(1)
55a1292595SJuergen Beisert #define LAN9303_MANUAL_FC_1 0x68
56a1292595SJuergen Beisert #define LAN9303_MANUAL_FC_2 0x69
57a1292595SJuergen Beisert #define LAN9303_MANUAL_FC_0 0x6a
5887523986SJerry Ray # define LAN9303_BP_EN BIT(6)
5987523986SJerry Ray # define LAN9303_RX_FC_EN BIT(2)
6087523986SJerry Ray # define LAN9303_TX_FC_EN BIT(1)
61a1292595SJuergen Beisert #define LAN9303_SWITCH_CSR_DATA 0x6b
62a1292595SJuergen Beisert #define LAN9303_SWITCH_CSR_CMD 0x6c
63a1292595SJuergen Beisert #define LAN9303_SWITCH_CSR_CMD_BUSY BIT(31)
64a1292595SJuergen Beisert #define LAN9303_SWITCH_CSR_CMD_RW BIT(30)
65a1292595SJuergen Beisert #define LAN9303_SWITCH_CSR_CMD_LANES (BIT(19) | BIT(18) | BIT(17) | BIT(16))
66a1292595SJuergen Beisert #define LAN9303_VIRT_PHY_BASE 0x70
67a1292595SJuergen Beisert #define LAN9303_VIRT_SPECIAL_CTRL 0x77
684d6a78b4SEgil Hjelmeland #define LAN9303_VIRT_SPECIAL_TURBO BIT(10) /*Turbo MII Enable*/
69a1292595SJuergen Beisert
70ab78acb1SEgil Hjelmeland /*13.4 Switch Fabric Control and Status Registers
71ab78acb1SEgil Hjelmeland * Accessed indirectly via SWITCH_CSR_CMD, SWITCH_CSR_DATA.
72ab78acb1SEgil Hjelmeland */
73a1292595SJuergen Beisert #define LAN9303_SW_DEV_ID 0x0000
74a1292595SJuergen Beisert #define LAN9303_SW_RESET 0x0001
75a1292595SJuergen Beisert #define LAN9303_SW_RESET_RESET BIT(0)
76a1292595SJuergen Beisert #define LAN9303_SW_IMR 0x0004
77a1292595SJuergen Beisert #define LAN9303_SW_IPR 0x0005
78a1292595SJuergen Beisert #define LAN9303_MAC_VER_ID_0 0x0400
79a1292595SJuergen Beisert #define LAN9303_MAC_RX_CFG_0 0x0401
80a1292595SJuergen Beisert # define LAN9303_MAC_RX_CFG_X_REJECT_MAC_TYPES BIT(1)
81a1292595SJuergen Beisert # define LAN9303_MAC_RX_CFG_X_RX_ENABLE BIT(0)
82a1292595SJuergen Beisert #define LAN9303_MAC_RX_UNDSZE_CNT_0 0x0410
83a1292595SJuergen Beisert #define LAN9303_MAC_RX_64_CNT_0 0x0411
84a1292595SJuergen Beisert #define LAN9303_MAC_RX_127_CNT_0 0x0412
85a1292595SJuergen Beisert #define LAN9303_MAC_RX_255_CNT_0 0x413
86a1292595SJuergen Beisert #define LAN9303_MAC_RX_511_CNT_0 0x0414
87a1292595SJuergen Beisert #define LAN9303_MAC_RX_1023_CNT_0 0x0415
88a1292595SJuergen Beisert #define LAN9303_MAC_RX_MAX_CNT_0 0x0416
89a1292595SJuergen Beisert #define LAN9303_MAC_RX_OVRSZE_CNT_0 0x0417
90a1292595SJuergen Beisert #define LAN9303_MAC_RX_PKTOK_CNT_0 0x0418
91a1292595SJuergen Beisert #define LAN9303_MAC_RX_CRCERR_CNT_0 0x0419
92a1292595SJuergen Beisert #define LAN9303_MAC_RX_MULCST_CNT_0 0x041a
93a1292595SJuergen Beisert #define LAN9303_MAC_RX_BRDCST_CNT_0 0x041b
94a1292595SJuergen Beisert #define LAN9303_MAC_RX_PAUSE_CNT_0 0x041c
95a1292595SJuergen Beisert #define LAN9303_MAC_RX_FRAG_CNT_0 0x041d
96a1292595SJuergen Beisert #define LAN9303_MAC_RX_JABB_CNT_0 0x041e
97a1292595SJuergen Beisert #define LAN9303_MAC_RX_ALIGN_CNT_0 0x041f
98a1292595SJuergen Beisert #define LAN9303_MAC_RX_PKTLEN_CNT_0 0x0420
99a1292595SJuergen Beisert #define LAN9303_MAC_RX_GOODPKTLEN_CNT_0 0x0421
100a1292595SJuergen Beisert #define LAN9303_MAC_RX_SYMBL_CNT_0 0x0422
101a1292595SJuergen Beisert #define LAN9303_MAC_RX_CTLFRM_CNT_0 0x0423
102a1292595SJuergen Beisert
103a1292595SJuergen Beisert #define LAN9303_MAC_TX_CFG_0 0x0440
104a1292595SJuergen Beisert # define LAN9303_MAC_TX_CFG_X_TX_IFG_CONFIG_DEFAULT (21 << 2)
105a1292595SJuergen Beisert # define LAN9303_MAC_TX_CFG_X_TX_PAD_ENABLE BIT(1)
106a1292595SJuergen Beisert # define LAN9303_MAC_TX_CFG_X_TX_ENABLE BIT(0)
107a1292595SJuergen Beisert #define LAN9303_MAC_TX_DEFER_CNT_0 0x0451
108a1292595SJuergen Beisert #define LAN9303_MAC_TX_PAUSE_CNT_0 0x0452
109a1292595SJuergen Beisert #define LAN9303_MAC_TX_PKTOK_CNT_0 0x0453
110a1292595SJuergen Beisert #define LAN9303_MAC_TX_64_CNT_0 0x0454
111a1292595SJuergen Beisert #define LAN9303_MAC_TX_127_CNT_0 0x0455
112a1292595SJuergen Beisert #define LAN9303_MAC_TX_255_CNT_0 0x0456
113a1292595SJuergen Beisert #define LAN9303_MAC_TX_511_CNT_0 0x0457
114a1292595SJuergen Beisert #define LAN9303_MAC_TX_1023_CNT_0 0x0458
115a1292595SJuergen Beisert #define LAN9303_MAC_TX_MAX_CNT_0 0x0459
116a1292595SJuergen Beisert #define LAN9303_MAC_TX_UNDSZE_CNT_0 0x045a
117a1292595SJuergen Beisert #define LAN9303_MAC_TX_PKTLEN_CNT_0 0x045c
118a1292595SJuergen Beisert #define LAN9303_MAC_TX_BRDCST_CNT_0 0x045d
119a1292595SJuergen Beisert #define LAN9303_MAC_TX_MULCST_CNT_0 0x045e
120a1292595SJuergen Beisert #define LAN9303_MAC_TX_LATECOL_0 0x045f
121a1292595SJuergen Beisert #define LAN9303_MAC_TX_EXCOL_CNT_0 0x0460
122a1292595SJuergen Beisert #define LAN9303_MAC_TX_SNGLECOL_CNT_0 0x0461
123a1292595SJuergen Beisert #define LAN9303_MAC_TX_MULTICOL_CNT_0 0x0462
124a1292595SJuergen Beisert #define LAN9303_MAC_TX_TOTALCOL_CNT_0 0x0463
125a1292595SJuergen Beisert
126a1292595SJuergen Beisert #define LAN9303_MAC_VER_ID_1 0x0800
127a1292595SJuergen Beisert #define LAN9303_MAC_RX_CFG_1 0x0801
128a1292595SJuergen Beisert #define LAN9303_MAC_TX_CFG_1 0x0840
129a1292595SJuergen Beisert #define LAN9303_MAC_VER_ID_2 0x0c00
130a1292595SJuergen Beisert #define LAN9303_MAC_RX_CFG_2 0x0c01
131a1292595SJuergen Beisert #define LAN9303_MAC_TX_CFG_2 0x0c40
132a1292595SJuergen Beisert #define LAN9303_SWE_ALR_CMD 0x1800
133ab335349SEgil Hjelmeland # define LAN9303_ALR_CMD_MAKE_ENTRY BIT(2)
134ab335349SEgil Hjelmeland # define LAN9303_ALR_CMD_GET_FIRST BIT(1)
135ab335349SEgil Hjelmeland # define LAN9303_ALR_CMD_GET_NEXT BIT(0)
136ab335349SEgil Hjelmeland #define LAN9303_SWE_ALR_WR_DAT_0 0x1801
137ab335349SEgil Hjelmeland #define LAN9303_SWE_ALR_WR_DAT_1 0x1802
138ab335349SEgil Hjelmeland # define LAN9303_ALR_DAT1_VALID BIT(26)
139ab335349SEgil Hjelmeland # define LAN9303_ALR_DAT1_END_OF_TABL BIT(25)
140ab335349SEgil Hjelmeland # define LAN9303_ALR_DAT1_AGE_OVERRID BIT(25)
141ab335349SEgil Hjelmeland # define LAN9303_ALR_DAT1_STATIC BIT(24)
142ab335349SEgil Hjelmeland # define LAN9303_ALR_DAT1_PORT_BITOFFS 16
143ab335349SEgil Hjelmeland # define LAN9303_ALR_DAT1_PORT_MASK (7 << LAN9303_ALR_DAT1_PORT_BITOFFS)
144ab335349SEgil Hjelmeland #define LAN9303_SWE_ALR_RD_DAT_0 0x1805
145ab335349SEgil Hjelmeland #define LAN9303_SWE_ALR_RD_DAT_1 0x1806
146ab335349SEgil Hjelmeland #define LAN9303_SWE_ALR_CMD_STS 0x1808
147ab335349SEgil Hjelmeland # define ALR_STS_MAKE_PEND BIT(0)
148a1292595SJuergen Beisert #define LAN9303_SWE_VLAN_CMD 0x180b
149a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_CMD_RNW BIT(5)
150a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_CMD_PVIDNVLAN BIT(4)
151a1292595SJuergen Beisert #define LAN9303_SWE_VLAN_WR_DATA 0x180c
152a1292595SJuergen Beisert #define LAN9303_SWE_VLAN_RD_DATA 0x180e
153a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_MEMBER_PORT2 BIT(17)
154a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_UNTAG_PORT2 BIT(16)
155a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_MEMBER_PORT1 BIT(15)
156a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_UNTAG_PORT1 BIT(14)
157a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_MEMBER_PORT0 BIT(13)
158a1292595SJuergen Beisert # define LAN9303_SWE_VLAN_UNTAG_PORT0 BIT(12)
159a1292595SJuergen Beisert #define LAN9303_SWE_VLAN_CMD_STS 0x1810
160a1292595SJuergen Beisert #define LAN9303_SWE_GLB_INGRESS_CFG 0x1840
1612aee4307SEgil Hjelmeland # define LAN9303_SWE_GLB_INGR_IGMP_TRAP BIT(7)
1622aee4307SEgil Hjelmeland # define LAN9303_SWE_GLB_INGR_IGMP_PORT(p) BIT(10 + p)
163a1292595SJuergen Beisert #define LAN9303_SWE_PORT_STATE 0x1843
164a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_FORWARDING_PORT2 (0)
165a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_LEARNING_PORT2 BIT(5)
166a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_BLOCKING_PORT2 BIT(4)
167a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_FORWARDING_PORT1 (0)
168a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_LEARNING_PORT1 BIT(3)
169a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_BLOCKING_PORT1 BIT(2)
170a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 (0)
171a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_LEARNING_PORT0 BIT(1)
172a1292595SJuergen Beisert # define LAN9303_SWE_PORT_STATE_BLOCKING_PORT0 BIT(0)
173d99a86aeSEgil Hjelmeland # define LAN9303_SWE_PORT_STATE_DISABLED_PORT0 (3)
174a1292595SJuergen Beisert #define LAN9303_SWE_PORT_MIRROR 0x1846
175a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_SNIFF_ALL BIT(8)
176a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT2 BIT(7)
177a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT1 BIT(6)
178a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT0 BIT(5)
179a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT2 BIT(4)
180a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT1 BIT(3)
181a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT0 BIT(2)
182a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_ENABLE_RX_MIRRORING BIT(1)
183a1292595SJuergen Beisert # define LAN9303_SWE_PORT_MIRROR_ENABLE_TX_MIRRORING BIT(0)
184d99a86aeSEgil Hjelmeland # define LAN9303_SWE_PORT_MIRROR_DISABLED 0
185a1292595SJuergen Beisert #define LAN9303_SWE_INGRESS_PORT_TYPE 0x1847
186f7e3bfa1SEgil Hjelmeland #define LAN9303_SWE_INGRESS_PORT_TYPE_VLAN 3
187a1292595SJuergen Beisert #define LAN9303_BM_CFG 0x1c00
188a1292595SJuergen Beisert #define LAN9303_BM_EGRSS_PORT_TYPE 0x1c0c
189a1292595SJuergen Beisert # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT2 (BIT(17) | BIT(16))
190a1292595SJuergen Beisert # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT1 (BIT(9) | BIT(8))
191a1292595SJuergen Beisert # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT0 (BIT(1) | BIT(0))
192a1292595SJuergen Beisert
193451d3ca0SEgil Hjelmeland #define LAN9303_SWITCH_PORT_REG(port, reg0) (0x400 * (port) + (reg0))
194a1292595SJuergen Beisert
195a1292595SJuergen Beisert /* the built-in PHYs are of type LAN911X */
196a1292595SJuergen Beisert #define MII_LAN911X_SPECIAL_MODES 0x12
197a1292595SJuergen Beisert #define MII_LAN911X_SPECIAL_CONTROL_STATUS 0x1f
198a1292595SJuergen Beisert
199a1292595SJuergen Beisert static const struct regmap_range lan9303_valid_regs[] = {
200a1292595SJuergen Beisert regmap_reg_range(0x14, 0x17), /* misc, interrupt */
201a1292595SJuergen Beisert regmap_reg_range(0x19, 0x19), /* endian test */
202a1292595SJuergen Beisert regmap_reg_range(0x1d, 0x1d), /* hardware config */
203a1292595SJuergen Beisert regmap_reg_range(0x23, 0x24), /* general purpose timer */
204a1292595SJuergen Beisert regmap_reg_range(0x27, 0x27), /* counter */
205a1292595SJuergen Beisert regmap_reg_range(0x29, 0x2a), /* PMI index regs */
206a1292595SJuergen Beisert regmap_reg_range(0x68, 0x6a), /* flow control */
207a1292595SJuergen Beisert regmap_reg_range(0x6b, 0x6c), /* switch fabric indirect regs */
208a1292595SJuergen Beisert regmap_reg_range(0x6d, 0x6f), /* misc */
209a1292595SJuergen Beisert regmap_reg_range(0x70, 0x77), /* virtual phy */
210a1292595SJuergen Beisert regmap_reg_range(0x78, 0x7a), /* GPIO */
211a1292595SJuergen Beisert regmap_reg_range(0x7c, 0x7e), /* MAC & reset */
212a1292595SJuergen Beisert regmap_reg_range(0x80, 0xb7), /* switch fabric direct regs (wr only) */
213a1292595SJuergen Beisert };
214a1292595SJuergen Beisert
215a1292595SJuergen Beisert static const struct regmap_range lan9303_reserved_ranges[] = {
216a1292595SJuergen Beisert regmap_reg_range(0x00, 0x13),
217a1292595SJuergen Beisert regmap_reg_range(0x18, 0x18),
218a1292595SJuergen Beisert regmap_reg_range(0x1a, 0x1c),
219a1292595SJuergen Beisert regmap_reg_range(0x1e, 0x22),
220a1292595SJuergen Beisert regmap_reg_range(0x25, 0x26),
221a1292595SJuergen Beisert regmap_reg_range(0x28, 0x28),
222a1292595SJuergen Beisert regmap_reg_range(0x2b, 0x67),
223a1292595SJuergen Beisert regmap_reg_range(0x7b, 0x7b),
224a1292595SJuergen Beisert regmap_reg_range(0x7f, 0x7f),
225a1292595SJuergen Beisert regmap_reg_range(0xb8, 0xff),
226a1292595SJuergen Beisert };
227a1292595SJuergen Beisert
228a1292595SJuergen Beisert const struct regmap_access_table lan9303_register_set = {
229a1292595SJuergen Beisert .yes_ranges = lan9303_valid_regs,
230a1292595SJuergen Beisert .n_yes_ranges = ARRAY_SIZE(lan9303_valid_regs),
231a1292595SJuergen Beisert .no_ranges = lan9303_reserved_ranges,
232a1292595SJuergen Beisert .n_no_ranges = ARRAY_SIZE(lan9303_reserved_ranges),
233a1292595SJuergen Beisert };
234a1292595SJuergen Beisert EXPORT_SYMBOL(lan9303_register_set);
235a1292595SJuergen Beisert
23687523986SJerry Ray /* Flow Control registers indexed by port number */
23787523986SJerry Ray static unsigned int flow_ctl_reg[] = {
23887523986SJerry Ray LAN9303_MANUAL_FC_0,
23987523986SJerry Ray LAN9303_MANUAL_FC_1,
24087523986SJerry Ray LAN9303_MANUAL_FC_2
24187523986SJerry Ray };
24287523986SJerry Ray
lan9303_read(struct regmap * regmap,unsigned int offset,u32 * reg)243a1292595SJuergen Beisert static int lan9303_read(struct regmap *regmap, unsigned int offset, u32 *reg)
244a1292595SJuergen Beisert {
245a1292595SJuergen Beisert int ret, i;
246a1292595SJuergen Beisert
247a1292595SJuergen Beisert /* we can lose arbitration for the I2C case, because the device
248a1292595SJuergen Beisert * tries to detect and read an external EEPROM after reset and acts as
249a1292595SJuergen Beisert * a master on the shared I2C bus itself. This conflicts with our
250a1292595SJuergen Beisert * attempts to access the device as a slave at the same moment.
251a1292595SJuergen Beisert */
252a1292595SJuergen Beisert for (i = 0; i < 5; i++) {
253a1292595SJuergen Beisert ret = regmap_read(regmap, offset, reg);
254a1292595SJuergen Beisert if (!ret)
255a1292595SJuergen Beisert return 0;
256a1292595SJuergen Beisert if (ret != -EAGAIN)
257a1292595SJuergen Beisert break;
258a1292595SJuergen Beisert msleep(500);
259a1292595SJuergen Beisert }
260a1292595SJuergen Beisert
261a1292595SJuergen Beisert return -EIO;
262a1292595SJuergen Beisert }
263a1292595SJuergen Beisert
lan9303_read_wait(struct lan9303 * chip,int offset,u32 mask)2645c13e075SEgil Hjelmeland static int lan9303_read_wait(struct lan9303 *chip, int offset, u32 mask)
2655c13e075SEgil Hjelmeland {
2665c13e075SEgil Hjelmeland int i;
2675c13e075SEgil Hjelmeland
2685c13e075SEgil Hjelmeland for (i = 0; i < 25; i++) {
2695c13e075SEgil Hjelmeland u32 reg;
2705c13e075SEgil Hjelmeland int ret;
2715c13e075SEgil Hjelmeland
2725c13e075SEgil Hjelmeland ret = lan9303_read(chip->regmap, offset, ®);
2735c13e075SEgil Hjelmeland if (ret) {
2745c13e075SEgil Hjelmeland dev_err(chip->dev, "%s failed to read offset %d: %d\n",
2755c13e075SEgil Hjelmeland __func__, offset, ret);
2765c13e075SEgil Hjelmeland return ret;
2775c13e075SEgil Hjelmeland }
2785c13e075SEgil Hjelmeland if (!(reg & mask))
2795c13e075SEgil Hjelmeland return 0;
2805c13e075SEgil Hjelmeland usleep_range(1000, 2000);
2815c13e075SEgil Hjelmeland }
2825c13e075SEgil Hjelmeland
2835c13e075SEgil Hjelmeland return -ETIMEDOUT;
2845c13e075SEgil Hjelmeland }
2855c13e075SEgil Hjelmeland
lan9303_virt_phy_reg_read(struct lan9303 * chip,int regnum)286a1292595SJuergen Beisert static int lan9303_virt_phy_reg_read(struct lan9303 *chip, int regnum)
287a1292595SJuergen Beisert {
288a1292595SJuergen Beisert int ret;
289a1292595SJuergen Beisert u32 val;
290a1292595SJuergen Beisert
291a1292595SJuergen Beisert if (regnum > MII_EXPANSION)
292a1292595SJuergen Beisert return -EINVAL;
293a1292595SJuergen Beisert
294a1292595SJuergen Beisert ret = lan9303_read(chip->regmap, LAN9303_VIRT_PHY_BASE + regnum, &val);
295a1292595SJuergen Beisert if (ret)
296a1292595SJuergen Beisert return ret;
297a1292595SJuergen Beisert
298a1292595SJuergen Beisert return val & 0xffff;
299a1292595SJuergen Beisert }
300a1292595SJuergen Beisert
lan9303_virt_phy_reg_write(struct lan9303 * chip,int regnum,u16 val)301a1292595SJuergen Beisert static int lan9303_virt_phy_reg_write(struct lan9303 *chip, int regnum, u16 val)
302a1292595SJuergen Beisert {
303a1292595SJuergen Beisert if (regnum > MII_EXPANSION)
304a1292595SJuergen Beisert return -EINVAL;
305a1292595SJuergen Beisert
306a1292595SJuergen Beisert return regmap_write(chip->regmap, LAN9303_VIRT_PHY_BASE + regnum, val);
307a1292595SJuergen Beisert }
308a1292595SJuergen Beisert
lan9303_indirect_phy_wait_for_completion(struct lan9303 * chip)3099e866e5dSEgil Hjelmeland static int lan9303_indirect_phy_wait_for_completion(struct lan9303 *chip)
310a1292595SJuergen Beisert {
3115c13e075SEgil Hjelmeland return lan9303_read_wait(chip, LAN9303_PMI_ACCESS,
3125c13e075SEgil Hjelmeland LAN9303_PMI_ACCESS_MII_BUSY);
313a1292595SJuergen Beisert }
314a1292595SJuergen Beisert
lan9303_indirect_phy_read(struct lan9303 * chip,int addr,int regnum)3159e866e5dSEgil Hjelmeland static int lan9303_indirect_phy_read(struct lan9303 *chip, int addr, int regnum)
316a1292595SJuergen Beisert {
317a1292595SJuergen Beisert int ret;
318a1292595SJuergen Beisert u32 val;
319a1292595SJuergen Beisert
320a1292595SJuergen Beisert val = LAN9303_PMI_ACCESS_PHY_ADDR(addr);
321a1292595SJuergen Beisert val |= LAN9303_PMI_ACCESS_MIIRINDA(regnum);
322a1292595SJuergen Beisert
323a1292595SJuergen Beisert mutex_lock(&chip->indirect_mutex);
324a1292595SJuergen Beisert
3259e866e5dSEgil Hjelmeland ret = lan9303_indirect_phy_wait_for_completion(chip);
326a1292595SJuergen Beisert if (ret)
327a1292595SJuergen Beisert goto on_error;
328a1292595SJuergen Beisert
329a1292595SJuergen Beisert /* start the MII read cycle */
330a1292595SJuergen Beisert ret = regmap_write(chip->regmap, LAN9303_PMI_ACCESS, val);
331a1292595SJuergen Beisert if (ret)
332a1292595SJuergen Beisert goto on_error;
333a1292595SJuergen Beisert
3349e866e5dSEgil Hjelmeland ret = lan9303_indirect_phy_wait_for_completion(chip);
335a1292595SJuergen Beisert if (ret)
336a1292595SJuergen Beisert goto on_error;
337a1292595SJuergen Beisert
338a1292595SJuergen Beisert /* read the result of this operation */
339a1292595SJuergen Beisert ret = lan9303_read(chip->regmap, LAN9303_PMI_DATA, &val);
340a1292595SJuergen Beisert if (ret)
341a1292595SJuergen Beisert goto on_error;
342a1292595SJuergen Beisert
343a1292595SJuergen Beisert mutex_unlock(&chip->indirect_mutex);
344a1292595SJuergen Beisert
345a1292595SJuergen Beisert return val & 0xffff;
346a1292595SJuergen Beisert
347a1292595SJuergen Beisert on_error:
348a1292595SJuergen Beisert mutex_unlock(&chip->indirect_mutex);
349a1292595SJuergen Beisert return ret;
350a1292595SJuergen Beisert }
351a1292595SJuergen Beisert
lan9303_indirect_phy_write(struct lan9303 * chip,int addr,int regnum,u16 val)3529e866e5dSEgil Hjelmeland static int lan9303_indirect_phy_write(struct lan9303 *chip, int addr,
3539e866e5dSEgil Hjelmeland int regnum, u16 val)
354a1292595SJuergen Beisert {
355a1292595SJuergen Beisert int ret;
356a1292595SJuergen Beisert u32 reg;
357a1292595SJuergen Beisert
358a1292595SJuergen Beisert reg = LAN9303_PMI_ACCESS_PHY_ADDR(addr);
359a1292595SJuergen Beisert reg |= LAN9303_PMI_ACCESS_MIIRINDA(regnum);
360a1292595SJuergen Beisert reg |= LAN9303_PMI_ACCESS_MII_WRITE;
361a1292595SJuergen Beisert
362a1292595SJuergen Beisert mutex_lock(&chip->indirect_mutex);
363a1292595SJuergen Beisert
3649e866e5dSEgil Hjelmeland ret = lan9303_indirect_phy_wait_for_completion(chip);
365a1292595SJuergen Beisert if (ret)
366a1292595SJuergen Beisert goto on_error;
367a1292595SJuergen Beisert
368a1292595SJuergen Beisert /* write the data first... */
369a1292595SJuergen Beisert ret = regmap_write(chip->regmap, LAN9303_PMI_DATA, val);
370a1292595SJuergen Beisert if (ret)
371a1292595SJuergen Beisert goto on_error;
372a1292595SJuergen Beisert
373a1292595SJuergen Beisert /* ...then start the MII write cycle */
374a1292595SJuergen Beisert ret = regmap_write(chip->regmap, LAN9303_PMI_ACCESS, reg);
375a1292595SJuergen Beisert
376a1292595SJuergen Beisert on_error:
377a1292595SJuergen Beisert mutex_unlock(&chip->indirect_mutex);
378a1292595SJuergen Beisert return ret;
379a1292595SJuergen Beisert }
380a1292595SJuergen Beisert
3812c340898SEgil Hjelmeland const struct lan9303_phy_ops lan9303_indirect_phy_ops = {
3822c340898SEgil Hjelmeland .phy_read = lan9303_indirect_phy_read,
3832c340898SEgil Hjelmeland .phy_write = lan9303_indirect_phy_write,
3842c340898SEgil Hjelmeland };
3852c340898SEgil Hjelmeland EXPORT_SYMBOL_GPL(lan9303_indirect_phy_ops);
3862c340898SEgil Hjelmeland
lan9303_switch_wait_for_completion(struct lan9303 * chip)387a1292595SJuergen Beisert static int lan9303_switch_wait_for_completion(struct lan9303 *chip)
388a1292595SJuergen Beisert {
3895c13e075SEgil Hjelmeland return lan9303_read_wait(chip, LAN9303_SWITCH_CSR_CMD,
3905c13e075SEgil Hjelmeland LAN9303_SWITCH_CSR_CMD_BUSY);
391a1292595SJuergen Beisert }
392a1292595SJuergen Beisert
lan9303_write_switch_reg(struct lan9303 * chip,u16 regnum,u32 val)393a1292595SJuergen Beisert static int lan9303_write_switch_reg(struct lan9303 *chip, u16 regnum, u32 val)
394a1292595SJuergen Beisert {
395a1292595SJuergen Beisert u32 reg;
396a1292595SJuergen Beisert int ret;
397a1292595SJuergen Beisert
398a1292595SJuergen Beisert reg = regnum;
399a1292595SJuergen Beisert reg |= LAN9303_SWITCH_CSR_CMD_LANES;
400a1292595SJuergen Beisert reg |= LAN9303_SWITCH_CSR_CMD_BUSY;
401a1292595SJuergen Beisert
402a1292595SJuergen Beisert mutex_lock(&chip->indirect_mutex);
403a1292595SJuergen Beisert
404a1292595SJuergen Beisert ret = lan9303_switch_wait_for_completion(chip);
405a1292595SJuergen Beisert if (ret)
406a1292595SJuergen Beisert goto on_error;
407a1292595SJuergen Beisert
408a1292595SJuergen Beisert ret = regmap_write(chip->regmap, LAN9303_SWITCH_CSR_DATA, val);
409a1292595SJuergen Beisert if (ret) {
410a1292595SJuergen Beisert dev_err(chip->dev, "Failed to write csr data reg: %d\n", ret);
411a1292595SJuergen Beisert goto on_error;
412a1292595SJuergen Beisert }
413a1292595SJuergen Beisert
414a1292595SJuergen Beisert /* trigger write */
415a1292595SJuergen Beisert ret = regmap_write(chip->regmap, LAN9303_SWITCH_CSR_CMD, reg);
416a1292595SJuergen Beisert if (ret)
417a1292595SJuergen Beisert dev_err(chip->dev, "Failed to write csr command reg: %d\n",
418a1292595SJuergen Beisert ret);
419a1292595SJuergen Beisert
420a1292595SJuergen Beisert on_error:
421a1292595SJuergen Beisert mutex_unlock(&chip->indirect_mutex);
422a1292595SJuergen Beisert return ret;
423a1292595SJuergen Beisert }
424a1292595SJuergen Beisert
lan9303_read_switch_reg(struct lan9303 * chip,u16 regnum,u32 * val)425a1292595SJuergen Beisert static int lan9303_read_switch_reg(struct lan9303 *chip, u16 regnum, u32 *val)
426a1292595SJuergen Beisert {
427a1292595SJuergen Beisert u32 reg;
428a1292595SJuergen Beisert int ret;
429a1292595SJuergen Beisert
430a1292595SJuergen Beisert reg = regnum;
431a1292595SJuergen Beisert reg |= LAN9303_SWITCH_CSR_CMD_LANES;
432a1292595SJuergen Beisert reg |= LAN9303_SWITCH_CSR_CMD_RW;
433a1292595SJuergen Beisert reg |= LAN9303_SWITCH_CSR_CMD_BUSY;
434a1292595SJuergen Beisert
435a1292595SJuergen Beisert mutex_lock(&chip->indirect_mutex);
436a1292595SJuergen Beisert
437a1292595SJuergen Beisert ret = lan9303_switch_wait_for_completion(chip);
438a1292595SJuergen Beisert if (ret)
439a1292595SJuergen Beisert goto on_error;
440a1292595SJuergen Beisert
441a1292595SJuergen Beisert /* trigger read */
442a1292595SJuergen Beisert ret = regmap_write(chip->regmap, LAN9303_SWITCH_CSR_CMD, reg);
443a1292595SJuergen Beisert if (ret) {
444a1292595SJuergen Beisert dev_err(chip->dev, "Failed to write csr command reg: %d\n",
445a1292595SJuergen Beisert ret);
446a1292595SJuergen Beisert goto on_error;
447a1292595SJuergen Beisert }
448a1292595SJuergen Beisert
449a1292595SJuergen Beisert ret = lan9303_switch_wait_for_completion(chip);
450a1292595SJuergen Beisert if (ret)
451a1292595SJuergen Beisert goto on_error;
452a1292595SJuergen Beisert
453a1292595SJuergen Beisert ret = lan9303_read(chip->regmap, LAN9303_SWITCH_CSR_DATA, val);
454a1292595SJuergen Beisert if (ret)
455a1292595SJuergen Beisert dev_err(chip->dev, "Failed to read csr data reg: %d\n", ret);
456a1292595SJuergen Beisert on_error:
457a1292595SJuergen Beisert mutex_unlock(&chip->indirect_mutex);
458a1292595SJuergen Beisert return ret;
459a1292595SJuergen Beisert }
460a1292595SJuergen Beisert
lan9303_write_switch_reg_mask(struct lan9303 * chip,u16 regnum,u32 val,u32 mask)4612aee4307SEgil Hjelmeland static int lan9303_write_switch_reg_mask(struct lan9303 *chip, u16 regnum,
4622aee4307SEgil Hjelmeland u32 val, u32 mask)
4632aee4307SEgil Hjelmeland {
4642aee4307SEgil Hjelmeland int ret;
4652aee4307SEgil Hjelmeland u32 reg;
4662aee4307SEgil Hjelmeland
4672aee4307SEgil Hjelmeland ret = lan9303_read_switch_reg(chip, regnum, ®);
4682aee4307SEgil Hjelmeland if (ret)
4692aee4307SEgil Hjelmeland return ret;
4702aee4307SEgil Hjelmeland
4712aee4307SEgil Hjelmeland reg = (reg & ~mask) | val;
4722aee4307SEgil Hjelmeland
4732aee4307SEgil Hjelmeland return lan9303_write_switch_reg(chip, regnum, reg);
4742aee4307SEgil Hjelmeland }
4752aee4307SEgil Hjelmeland
lan9303_write_switch_port(struct lan9303 * chip,int port,u16 regnum,u32 val)476451d3ca0SEgil Hjelmeland static int lan9303_write_switch_port(struct lan9303 *chip, int port,
477451d3ca0SEgil Hjelmeland u16 regnum, u32 val)
478451d3ca0SEgil Hjelmeland {
479451d3ca0SEgil Hjelmeland return lan9303_write_switch_reg(
480451d3ca0SEgil Hjelmeland chip, LAN9303_SWITCH_PORT_REG(port, regnum), val);
481451d3ca0SEgil Hjelmeland }
482451d3ca0SEgil Hjelmeland
lan9303_read_switch_port(struct lan9303 * chip,int port,u16 regnum,u32 * val)4830a967b4aSEgil Hjelmeland static int lan9303_read_switch_port(struct lan9303 *chip, int port,
4840a967b4aSEgil Hjelmeland u16 regnum, u32 *val)
4850a967b4aSEgil Hjelmeland {
4860a967b4aSEgil Hjelmeland return lan9303_read_switch_reg(
4870a967b4aSEgil Hjelmeland chip, LAN9303_SWITCH_PORT_REG(port, regnum), val);
4880a967b4aSEgil Hjelmeland }
4890a967b4aSEgil Hjelmeland
lan9303_detect_phy_setup(struct lan9303 * chip)490a1292595SJuergen Beisert static int lan9303_detect_phy_setup(struct lan9303 *chip)
491a1292595SJuergen Beisert {
492a1292595SJuergen Beisert int reg;
493a1292595SJuergen Beisert
494b17c6b1fSEgil Hjelmeland /* Calculate chip->phy_addr_base:
495b17c6b1fSEgil Hjelmeland * Depending on the 'phy_addr_sel_strap' setting, the three phys are
496a1292595SJuergen Beisert * using IDs 0-1-2 or IDs 1-2-3. We cannot read back the
497a1292595SJuergen Beisert * 'phy_addr_sel_strap' setting directly, so we need a test, which
498a1292595SJuergen Beisert * configuration is active:
499a1292595SJuergen Beisert * Special reg 18 of phy 3 reads as 0x0000, if 'phy_addr_sel_strap' is 0
500a1292595SJuergen Beisert * and the IDs are 0-1-2, else it contains something different from
501a1292595SJuergen Beisert * 0x0000, which means 'phy_addr_sel_strap' is 1 and the IDs are 1-2-3.
502d329ac88SEgil Hjelmeland * 0xffff is returned on MDIO read with no response.
503a1292595SJuergen Beisert */
5042c340898SEgil Hjelmeland reg = chip->ops->phy_read(chip, 3, MII_LAN911X_SPECIAL_MODES);
505a1292595SJuergen Beisert if (reg < 0) {
506a1292595SJuergen Beisert dev_err(chip->dev, "Failed to detect phy config: %d\n", reg);
507a1292595SJuergen Beisert return reg;
508a1292595SJuergen Beisert }
509a1292595SJuergen Beisert
510589d1976SEgil Hjelmeland chip->phy_addr_base = reg != 0 && reg != 0xffff;
511a1292595SJuergen Beisert
512a1292595SJuergen Beisert dev_dbg(chip->dev, "Phy setup '%s' detected\n",
513b17c6b1fSEgil Hjelmeland chip->phy_addr_base ? "1-2-3" : "0-1-2");
514a1292595SJuergen Beisert
515a1292595SJuergen Beisert return 0;
516a1292595SJuergen Beisert }
517a1292595SJuergen Beisert
518ab335349SEgil Hjelmeland /* Map ALR-port bits to port bitmap, and back */
519ab335349SEgil Hjelmeland static const int alrport_2_portmap[] = {1, 2, 4, 0, 3, 5, 6, 7 };
520ab335349SEgil Hjelmeland static const int portmap_2_alrport[] = {3, 0, 1, 4, 2, 5, 6, 7 };
521ab335349SEgil Hjelmeland
5220620427eSEgil Hjelmeland /* Return pointer to first free ALR cache entry, return NULL if none */
5230620427eSEgil Hjelmeland static struct lan9303_alr_cache_entry *
lan9303_alr_cache_find_free(struct lan9303 * chip)5240620427eSEgil Hjelmeland lan9303_alr_cache_find_free(struct lan9303 *chip)
5250620427eSEgil Hjelmeland {
5260620427eSEgil Hjelmeland int i;
5270620427eSEgil Hjelmeland struct lan9303_alr_cache_entry *entr = chip->alr_cache;
5280620427eSEgil Hjelmeland
5290620427eSEgil Hjelmeland for (i = 0; i < LAN9303_NUM_ALR_RECORDS; i++, entr++)
5300620427eSEgil Hjelmeland if (entr->port_map == 0)
5310620427eSEgil Hjelmeland return entr;
5320620427eSEgil Hjelmeland
5330620427eSEgil Hjelmeland return NULL;
5340620427eSEgil Hjelmeland }
5350620427eSEgil Hjelmeland
5360620427eSEgil Hjelmeland /* Return pointer to ALR cache entry matching MAC address */
5370620427eSEgil Hjelmeland static struct lan9303_alr_cache_entry *
lan9303_alr_cache_find_mac(struct lan9303 * chip,const u8 * mac_addr)5380620427eSEgil Hjelmeland lan9303_alr_cache_find_mac(struct lan9303 *chip, const u8 *mac_addr)
5390620427eSEgil Hjelmeland {
5400620427eSEgil Hjelmeland int i;
5410620427eSEgil Hjelmeland struct lan9303_alr_cache_entry *entr = chip->alr_cache;
5420620427eSEgil Hjelmeland
5430620427eSEgil Hjelmeland BUILD_BUG_ON_MSG(sizeof(struct lan9303_alr_cache_entry) & 1,
5440620427eSEgil Hjelmeland "ether_addr_equal require u16 alignment");
5450620427eSEgil Hjelmeland
5460620427eSEgil Hjelmeland for (i = 0; i < LAN9303_NUM_ALR_RECORDS; i++, entr++)
5470620427eSEgil Hjelmeland if (ether_addr_equal(entr->mac_addr, mac_addr))
5480620427eSEgil Hjelmeland return entr;
5490620427eSEgil Hjelmeland
5500620427eSEgil Hjelmeland return NULL;
5510620427eSEgil Hjelmeland }
5520620427eSEgil Hjelmeland
lan9303_csr_reg_wait(struct lan9303 * chip,int regno,u32 mask)553595476cbSEgil Hjelmeland static int lan9303_csr_reg_wait(struct lan9303 *chip, int regno, u32 mask)
554ab335349SEgil Hjelmeland {
555ab335349SEgil Hjelmeland int i;
556ab335349SEgil Hjelmeland
557595476cbSEgil Hjelmeland for (i = 0; i < 25; i++) {
558ab335349SEgil Hjelmeland u32 reg;
559ab335349SEgil Hjelmeland
560ab335349SEgil Hjelmeland lan9303_read_switch_reg(chip, regno, ®);
561595476cbSEgil Hjelmeland if (!(reg & mask))
562ab335349SEgil Hjelmeland return 0;
563ab335349SEgil Hjelmeland usleep_range(1000, 2000);
564ab335349SEgil Hjelmeland }
565595476cbSEgil Hjelmeland
566ab335349SEgil Hjelmeland return -ETIMEDOUT;
567ab335349SEgil Hjelmeland }
568ab335349SEgil Hjelmeland
lan9303_alr_make_entry_raw(struct lan9303 * chip,u32 dat0,u32 dat1)569ab335349SEgil Hjelmeland static int lan9303_alr_make_entry_raw(struct lan9303 *chip, u32 dat0, u32 dat1)
570ab335349SEgil Hjelmeland {
571ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_WR_DAT_0, dat0);
572ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_WR_DAT_1, dat1);
573ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
574ab335349SEgil Hjelmeland LAN9303_ALR_CMD_MAKE_ENTRY);
575595476cbSEgil Hjelmeland lan9303_csr_reg_wait(chip, LAN9303_SWE_ALR_CMD_STS, ALR_STS_MAKE_PEND);
576ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
577ab335349SEgil Hjelmeland
578ab335349SEgil Hjelmeland return 0;
579ab335349SEgil Hjelmeland }
580ab335349SEgil Hjelmeland
581ada2fee1SVladimir Oltean typedef int alr_loop_cb_t(struct lan9303 *chip, u32 dat0, u32 dat1,
582ab335349SEgil Hjelmeland int portmap, void *ctx);
583ab335349SEgil Hjelmeland
lan9303_alr_loop(struct lan9303 * chip,alr_loop_cb_t * cb,void * ctx)584ada2fee1SVladimir Oltean static int lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
585ab335349SEgil Hjelmeland {
586ada2fee1SVladimir Oltean int ret = 0, i;
587ab335349SEgil Hjelmeland
5882e8d243eSEgil Hjelmeland mutex_lock(&chip->alr_mutex);
589ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
590ab335349SEgil Hjelmeland LAN9303_ALR_CMD_GET_FIRST);
591ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
592ab335349SEgil Hjelmeland
593ab335349SEgil Hjelmeland for (i = 1; i < LAN9303_NUM_ALR_RECORDS; i++) {
594ab335349SEgil Hjelmeland u32 dat0, dat1;
595ab335349SEgil Hjelmeland int alrport, portmap;
596ab335349SEgil Hjelmeland
597ab335349SEgil Hjelmeland lan9303_read_switch_reg(chip, LAN9303_SWE_ALR_RD_DAT_0, &dat0);
598ab335349SEgil Hjelmeland lan9303_read_switch_reg(chip, LAN9303_SWE_ALR_RD_DAT_1, &dat1);
599ab335349SEgil Hjelmeland if (dat1 & LAN9303_ALR_DAT1_END_OF_TABL)
600ab335349SEgil Hjelmeland break;
601ab335349SEgil Hjelmeland
602ab335349SEgil Hjelmeland alrport = (dat1 & LAN9303_ALR_DAT1_PORT_MASK) >>
603ab335349SEgil Hjelmeland LAN9303_ALR_DAT1_PORT_BITOFFS;
604ab335349SEgil Hjelmeland portmap = alrport_2_portmap[alrport];
605ab335349SEgil Hjelmeland
606ada2fee1SVladimir Oltean ret = cb(chip, dat0, dat1, portmap, ctx);
607ada2fee1SVladimir Oltean if (ret)
608ada2fee1SVladimir Oltean break;
609ab335349SEgil Hjelmeland
610ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
611ab335349SEgil Hjelmeland LAN9303_ALR_CMD_GET_NEXT);
612ab335349SEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
613ab335349SEgil Hjelmeland }
6142e8d243eSEgil Hjelmeland mutex_unlock(&chip->alr_mutex);
615ada2fee1SVladimir Oltean
616ada2fee1SVladimir Oltean return ret;
617ab335349SEgil Hjelmeland }
618ab335349SEgil Hjelmeland
alr_reg_to_mac(u32 dat0,u32 dat1,u8 mac[6])619ab335349SEgil Hjelmeland static void alr_reg_to_mac(u32 dat0, u32 dat1, u8 mac[6])
620ab335349SEgil Hjelmeland {
621ab335349SEgil Hjelmeland mac[0] = (dat0 >> 0) & 0xff;
622ab335349SEgil Hjelmeland mac[1] = (dat0 >> 8) & 0xff;
623ab335349SEgil Hjelmeland mac[2] = (dat0 >> 16) & 0xff;
624ab335349SEgil Hjelmeland mac[3] = (dat0 >> 24) & 0xff;
625ab335349SEgil Hjelmeland mac[4] = (dat1 >> 0) & 0xff;
626ab335349SEgil Hjelmeland mac[5] = (dat1 >> 8) & 0xff;
627ab335349SEgil Hjelmeland }
628ab335349SEgil Hjelmeland
629ab335349SEgil Hjelmeland struct del_port_learned_ctx {
630ab335349SEgil Hjelmeland int port;
631ab335349SEgil Hjelmeland };
632ab335349SEgil Hjelmeland
633ab335349SEgil Hjelmeland /* Clear learned (non-static) entry on given port */
alr_loop_cb_del_port_learned(struct lan9303 * chip,u32 dat0,u32 dat1,int portmap,void * ctx)634ada2fee1SVladimir Oltean static int alr_loop_cb_del_port_learned(struct lan9303 *chip, u32 dat0,
635ab335349SEgil Hjelmeland u32 dat1, int portmap, void *ctx)
636ab335349SEgil Hjelmeland {
637ab335349SEgil Hjelmeland struct del_port_learned_ctx *del_ctx = ctx;
638ab335349SEgil Hjelmeland int port = del_ctx->port;
639ab335349SEgil Hjelmeland
640ab335349SEgil Hjelmeland if (((BIT(port) & portmap) == 0) || (dat1 & LAN9303_ALR_DAT1_STATIC))
641ada2fee1SVladimir Oltean return 0;
642ab335349SEgil Hjelmeland
643ab335349SEgil Hjelmeland /* learned entries has only one port, we can just delete */
644ab335349SEgil Hjelmeland dat1 &= ~LAN9303_ALR_DAT1_VALID; /* delete entry */
645ab335349SEgil Hjelmeland lan9303_alr_make_entry_raw(chip, dat0, dat1);
646ada2fee1SVladimir Oltean
647ada2fee1SVladimir Oltean return 0;
648ab335349SEgil Hjelmeland }
649ab335349SEgil Hjelmeland
650ab335349SEgil Hjelmeland struct port_fdb_dump_ctx {
651ab335349SEgil Hjelmeland int port;
652ab335349SEgil Hjelmeland void *data;
653ab335349SEgil Hjelmeland dsa_fdb_dump_cb_t *cb;
654ab335349SEgil Hjelmeland };
655ab335349SEgil Hjelmeland
alr_loop_cb_fdb_port_dump(struct lan9303 * chip,u32 dat0,u32 dat1,int portmap,void * ctx)656ada2fee1SVladimir Oltean static int alr_loop_cb_fdb_port_dump(struct lan9303 *chip, u32 dat0,
657ab335349SEgil Hjelmeland u32 dat1, int portmap, void *ctx)
658ab335349SEgil Hjelmeland {
659ab335349SEgil Hjelmeland struct port_fdb_dump_ctx *dump_ctx = ctx;
660ab335349SEgil Hjelmeland u8 mac[ETH_ALEN];
661ab335349SEgil Hjelmeland bool is_static;
662ab335349SEgil Hjelmeland
663ab335349SEgil Hjelmeland if ((BIT(dump_ctx->port) & portmap) == 0)
664ada2fee1SVladimir Oltean return 0;
665ab335349SEgil Hjelmeland
666ab335349SEgil Hjelmeland alr_reg_to_mac(dat0, dat1, mac);
667ab335349SEgil Hjelmeland is_static = !!(dat1 & LAN9303_ALR_DAT1_STATIC);
668ada2fee1SVladimir Oltean return dump_ctx->cb(mac, 0, is_static, dump_ctx->data);
669ab335349SEgil Hjelmeland }
670ab335349SEgil Hjelmeland
6710620427eSEgil Hjelmeland /* Set a static ALR entry. Delete entry if port_map is zero */
lan9303_alr_set_entry(struct lan9303 * chip,const u8 * mac,u8 port_map,bool stp_override)6720620427eSEgil Hjelmeland static void lan9303_alr_set_entry(struct lan9303 *chip, const u8 *mac,
6730620427eSEgil Hjelmeland u8 port_map, bool stp_override)
6740620427eSEgil Hjelmeland {
6750620427eSEgil Hjelmeland u32 dat0, dat1, alr_port;
6760620427eSEgil Hjelmeland
6770620427eSEgil Hjelmeland dev_dbg(chip->dev, "%s(%pM, %d)\n", __func__, mac, port_map);
6780620427eSEgil Hjelmeland dat1 = LAN9303_ALR_DAT1_STATIC;
6790620427eSEgil Hjelmeland if (port_map)
6800620427eSEgil Hjelmeland dat1 |= LAN9303_ALR_DAT1_VALID;
6810620427eSEgil Hjelmeland /* otherwise no ports: delete entry */
6820620427eSEgil Hjelmeland if (stp_override)
6830620427eSEgil Hjelmeland dat1 |= LAN9303_ALR_DAT1_AGE_OVERRID;
6840620427eSEgil Hjelmeland
6850620427eSEgil Hjelmeland alr_port = portmap_2_alrport[port_map & 7];
6860620427eSEgil Hjelmeland dat1 &= ~LAN9303_ALR_DAT1_PORT_MASK;
6870620427eSEgil Hjelmeland dat1 |= alr_port << LAN9303_ALR_DAT1_PORT_BITOFFS;
6880620427eSEgil Hjelmeland
6890620427eSEgil Hjelmeland dat0 = 0;
6900620427eSEgil Hjelmeland dat0 |= (mac[0] << 0);
6910620427eSEgil Hjelmeland dat0 |= (mac[1] << 8);
6920620427eSEgil Hjelmeland dat0 |= (mac[2] << 16);
6930620427eSEgil Hjelmeland dat0 |= (mac[3] << 24);
6940620427eSEgil Hjelmeland
6950620427eSEgil Hjelmeland dat1 |= (mac[4] << 0);
6960620427eSEgil Hjelmeland dat1 |= (mac[5] << 8);
6970620427eSEgil Hjelmeland
6980620427eSEgil Hjelmeland lan9303_alr_make_entry_raw(chip, dat0, dat1);
6990620427eSEgil Hjelmeland }
7000620427eSEgil Hjelmeland
7010620427eSEgil Hjelmeland /* Add port to static ALR entry, create new static entry if needed */
lan9303_alr_add_port(struct lan9303 * chip,const u8 * mac,int port,bool stp_override)7020620427eSEgil Hjelmeland static int lan9303_alr_add_port(struct lan9303 *chip, const u8 *mac, int port,
7030620427eSEgil Hjelmeland bool stp_override)
7040620427eSEgil Hjelmeland {
7050620427eSEgil Hjelmeland struct lan9303_alr_cache_entry *entr;
7060620427eSEgil Hjelmeland
7072e8d243eSEgil Hjelmeland mutex_lock(&chip->alr_mutex);
7080620427eSEgil Hjelmeland entr = lan9303_alr_cache_find_mac(chip, mac);
7090620427eSEgil Hjelmeland if (!entr) { /*New entry */
7100620427eSEgil Hjelmeland entr = lan9303_alr_cache_find_free(chip);
7112e8d243eSEgil Hjelmeland if (!entr) {
7122e8d243eSEgil Hjelmeland mutex_unlock(&chip->alr_mutex);
7130620427eSEgil Hjelmeland return -ENOSPC;
7142e8d243eSEgil Hjelmeland }
7150620427eSEgil Hjelmeland ether_addr_copy(entr->mac_addr, mac);
7160620427eSEgil Hjelmeland }
7170620427eSEgil Hjelmeland entr->port_map |= BIT(port);
7180620427eSEgil Hjelmeland entr->stp_override = stp_override;
7190620427eSEgil Hjelmeland lan9303_alr_set_entry(chip, mac, entr->port_map, stp_override);
7202e8d243eSEgil Hjelmeland mutex_unlock(&chip->alr_mutex);
7210620427eSEgil Hjelmeland
7220620427eSEgil Hjelmeland return 0;
7230620427eSEgil Hjelmeland }
7240620427eSEgil Hjelmeland
7250620427eSEgil Hjelmeland /* Delete static port from ALR entry, delete entry if last port */
lan9303_alr_del_port(struct lan9303 * chip,const u8 * mac,int port)7260620427eSEgil Hjelmeland static int lan9303_alr_del_port(struct lan9303 *chip, const u8 *mac, int port)
7270620427eSEgil Hjelmeland {
7280620427eSEgil Hjelmeland struct lan9303_alr_cache_entry *entr;
7290620427eSEgil Hjelmeland
7302e8d243eSEgil Hjelmeland mutex_lock(&chip->alr_mutex);
7310620427eSEgil Hjelmeland entr = lan9303_alr_cache_find_mac(chip, mac);
7320620427eSEgil Hjelmeland if (!entr)
7332e8d243eSEgil Hjelmeland goto out; /* no static entry found */
7340620427eSEgil Hjelmeland
7350620427eSEgil Hjelmeland entr->port_map &= ~BIT(port);
7360620427eSEgil Hjelmeland if (entr->port_map == 0) /* zero means its free again */
73730482e4eSEgil Hjelmeland eth_zero_addr(entr->mac_addr);
7380620427eSEgil Hjelmeland lan9303_alr_set_entry(chip, mac, entr->port_map, entr->stp_override);
7390620427eSEgil Hjelmeland
7402e8d243eSEgil Hjelmeland out:
7412e8d243eSEgil Hjelmeland mutex_unlock(&chip->alr_mutex);
7420620427eSEgil Hjelmeland return 0;
7430620427eSEgil Hjelmeland }
7440620427eSEgil Hjelmeland
lan9303_disable_processing_port(struct lan9303 * chip,unsigned int port)7459c84258eSEgil Hjelmeland static int lan9303_disable_processing_port(struct lan9303 *chip,
746a1292595SJuergen Beisert unsigned int port)
747a1292595SJuergen Beisert {
748a1292595SJuergen Beisert int ret;
749a1292595SJuergen Beisert
750a1292595SJuergen Beisert /* disable RX, but keep register reset default values else */
751451d3ca0SEgil Hjelmeland ret = lan9303_write_switch_port(chip, port, LAN9303_MAC_RX_CFG_0,
752a1292595SJuergen Beisert LAN9303_MAC_RX_CFG_X_REJECT_MAC_TYPES);
753a1292595SJuergen Beisert if (ret)
754a1292595SJuergen Beisert return ret;
755a1292595SJuergen Beisert
756a1292595SJuergen Beisert /* disable TX, but keep register reset default values else */
757451d3ca0SEgil Hjelmeland return lan9303_write_switch_port(chip, port, LAN9303_MAC_TX_CFG_0,
758a1292595SJuergen Beisert LAN9303_MAC_TX_CFG_X_TX_IFG_CONFIG_DEFAULT |
759a1292595SJuergen Beisert LAN9303_MAC_TX_CFG_X_TX_PAD_ENABLE);
760a1292595SJuergen Beisert }
761a1292595SJuergen Beisert
lan9303_enable_processing_port(struct lan9303 * chip,unsigned int port)7629c84258eSEgil Hjelmeland static int lan9303_enable_processing_port(struct lan9303 *chip,
763a1292595SJuergen Beisert unsigned int port)
764a1292595SJuergen Beisert {
765a1292595SJuergen Beisert int ret;
766a1292595SJuergen Beisert
767a1292595SJuergen Beisert /* enable RX and keep register reset default values else */
768451d3ca0SEgil Hjelmeland ret = lan9303_write_switch_port(chip, port, LAN9303_MAC_RX_CFG_0,
769a1292595SJuergen Beisert LAN9303_MAC_RX_CFG_X_REJECT_MAC_TYPES |
770a1292595SJuergen Beisert LAN9303_MAC_RX_CFG_X_RX_ENABLE);
771a1292595SJuergen Beisert if (ret)
772a1292595SJuergen Beisert return ret;
773a1292595SJuergen Beisert
774a1292595SJuergen Beisert /* enable TX and keep register reset default values else */
775451d3ca0SEgil Hjelmeland return lan9303_write_switch_port(chip, port, LAN9303_MAC_TX_CFG_0,
776a1292595SJuergen Beisert LAN9303_MAC_TX_CFG_X_TX_IFG_CONFIG_DEFAULT |
777a1292595SJuergen Beisert LAN9303_MAC_TX_CFG_X_TX_PAD_ENABLE |
778a1292595SJuergen Beisert LAN9303_MAC_TX_CFG_X_TX_ENABLE);
779a1292595SJuergen Beisert }
780a1292595SJuergen Beisert
781f7e3bfa1SEgil Hjelmeland /* forward special tagged packets from port 0 to port 1 *or* port 2 */
lan9303_setup_tagging(struct lan9303 * chip)782f7e3bfa1SEgil Hjelmeland static int lan9303_setup_tagging(struct lan9303 *chip)
783f7e3bfa1SEgil Hjelmeland {
784f7e3bfa1SEgil Hjelmeland int ret;
785f7e3bfa1SEgil Hjelmeland u32 val;
786f7e3bfa1SEgil Hjelmeland /* enable defining the destination port via special VLAN tagging
787f7e3bfa1SEgil Hjelmeland * for port 0
788f7e3bfa1SEgil Hjelmeland */
789f7e3bfa1SEgil Hjelmeland ret = lan9303_write_switch_reg(chip, LAN9303_SWE_INGRESS_PORT_TYPE,
790f7e3bfa1SEgil Hjelmeland LAN9303_SWE_INGRESS_PORT_TYPE_VLAN);
791f7e3bfa1SEgil Hjelmeland if (ret)
792f7e3bfa1SEgil Hjelmeland return ret;
793f7e3bfa1SEgil Hjelmeland
794f7e3bfa1SEgil Hjelmeland /* tag incoming packets at port 1 and 2 on their way to port 0 to be
795f7e3bfa1SEgil Hjelmeland * able to discover their source port
796f7e3bfa1SEgil Hjelmeland */
797f7e3bfa1SEgil Hjelmeland val = LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT0;
798f7e3bfa1SEgil Hjelmeland return lan9303_write_switch_reg(chip, LAN9303_BM_EGRSS_PORT_TYPE, val);
799f7e3bfa1SEgil Hjelmeland }
800f7e3bfa1SEgil Hjelmeland
801a1292595SJuergen Beisert /* We want a special working switch:
802a1292595SJuergen Beisert * - do not forward packets between port 1 and 2
803a1292595SJuergen Beisert * - forward everything from port 1 to port 0
804a1292595SJuergen Beisert * - forward everything from port 2 to port 0
805a1292595SJuergen Beisert */
lan9303_separate_ports(struct lan9303 * chip)806a1292595SJuergen Beisert static int lan9303_separate_ports(struct lan9303 *chip)
807a1292595SJuergen Beisert {
808a1292595SJuergen Beisert int ret;
809a1292595SJuergen Beisert
810e9292f2cSEgil Hjelmeland lan9303_alr_del_port(chip, eth_stp_addr, 0);
811a1292595SJuergen Beisert ret = lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_MIRROR,
812a1292595SJuergen Beisert LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT0 |
813a1292595SJuergen Beisert LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT1 |
814a1292595SJuergen Beisert LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT2 |
815a1292595SJuergen Beisert LAN9303_SWE_PORT_MIRROR_ENABLE_RX_MIRRORING |
816a1292595SJuergen Beisert LAN9303_SWE_PORT_MIRROR_SNIFF_ALL);
817a1292595SJuergen Beisert if (ret)
818a1292595SJuergen Beisert return ret;
819a1292595SJuergen Beisert
820a1292595SJuergen Beisert /* prevent port 1 and 2 from forwarding packets by their own */
821a1292595SJuergen Beisert return lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE,
822a1292595SJuergen Beisert LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 |
823a1292595SJuergen Beisert LAN9303_SWE_PORT_STATE_BLOCKING_PORT1 |
824a1292595SJuergen Beisert LAN9303_SWE_PORT_STATE_BLOCKING_PORT2);
825a1292595SJuergen Beisert }
826a1292595SJuergen Beisert
lan9303_bridge_ports(struct lan9303 * chip)827d99a86aeSEgil Hjelmeland static void lan9303_bridge_ports(struct lan9303 *chip)
828d99a86aeSEgil Hjelmeland {
829d99a86aeSEgil Hjelmeland /* ports bridged: remove mirroring */
830d99a86aeSEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_MIRROR,
831d99a86aeSEgil Hjelmeland LAN9303_SWE_PORT_MIRROR_DISABLED);
832d99a86aeSEgil Hjelmeland
833d99a86aeSEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE,
834d99a86aeSEgil Hjelmeland chip->swe_port_state);
835e9292f2cSEgil Hjelmeland lan9303_alr_add_port(chip, eth_stp_addr, 0, true);
836d99a86aeSEgil Hjelmeland }
837d99a86aeSEgil Hjelmeland
lan9303_handle_reset(struct lan9303 * chip)838a57d476dSPhil Reid static void lan9303_handle_reset(struct lan9303 *chip)
839a1292595SJuergen Beisert {
840a1292595SJuergen Beisert if (!chip->reset_gpio)
841a57d476dSPhil Reid return;
842a1292595SJuergen Beisert
843*28a2c3e5SAnatolij Gustschin gpiod_set_value_cansleep(chip->reset_gpio, 1);
844*28a2c3e5SAnatolij Gustschin
845a1292595SJuergen Beisert if (chip->reset_duration != 0)
846a1292595SJuergen Beisert msleep(chip->reset_duration);
847a1292595SJuergen Beisert
848a1292595SJuergen Beisert /* release (deassert) reset and activate the device */
849a1292595SJuergen Beisert gpiod_set_value_cansleep(chip->reset_gpio, 0);
850a1292595SJuergen Beisert }
851a1292595SJuergen Beisert
852a1292595SJuergen Beisert /* stop processing packets for all ports */
lan9303_disable_processing(struct lan9303 * chip)853a1292595SJuergen Beisert static int lan9303_disable_processing(struct lan9303 *chip)
854a1292595SJuergen Beisert {
855b3d14a2bSEgil Hjelmeland int p;
856a1292595SJuergen Beisert
8573c91b0c1SEgil Hjelmeland for (p = 1; p < LAN9303_NUM_PORTS; p++) {
8589c84258eSEgil Hjelmeland int ret = lan9303_disable_processing_port(chip, p);
859b3d14a2bSEgil Hjelmeland
860a1292595SJuergen Beisert if (ret)
861a1292595SJuergen Beisert return ret;
862b3d14a2bSEgil Hjelmeland }
863b3d14a2bSEgil Hjelmeland
864b3d14a2bSEgil Hjelmeland return 0;
865a1292595SJuergen Beisert }
866a1292595SJuergen Beisert
lan9303_check_device(struct lan9303 * chip)867a1292595SJuergen Beisert static int lan9303_check_device(struct lan9303 *chip)
868a1292595SJuergen Beisert {
869a1292595SJuergen Beisert int ret;
870*28a2c3e5SAnatolij Gustschin int err;
871a1292595SJuergen Beisert u32 reg;
872a1292595SJuergen Beisert
873*28a2c3e5SAnatolij Gustschin /* In I2C-managed configurations this polling loop will clash with
874*28a2c3e5SAnatolij Gustschin * switch's reading of EEPROM right after reset and this behaviour is
875*28a2c3e5SAnatolij Gustschin * not configurable. While lan9303_read() already has quite long retry
876*28a2c3e5SAnatolij Gustschin * timeout, seems not all cases are being detected as arbitration error.
877*28a2c3e5SAnatolij Gustschin *
878*28a2c3e5SAnatolij Gustschin * According to datasheet, EEPROM loader has 30ms timeout (in case of
879*28a2c3e5SAnatolij Gustschin * missing EEPROM).
880*28a2c3e5SAnatolij Gustschin *
881*28a2c3e5SAnatolij Gustschin * Loading of the largest supported EEPROM is expected to take at least
882*28a2c3e5SAnatolij Gustschin * 5.9s.
883*28a2c3e5SAnatolij Gustschin */
884*28a2c3e5SAnatolij Gustschin err = read_poll_timeout(lan9303_read, ret,
885*28a2c3e5SAnatolij Gustschin !ret && reg & LAN9303_HW_CFG_READY,
886*28a2c3e5SAnatolij Gustschin 20000, 6000000, false,
887*28a2c3e5SAnatolij Gustschin chip->regmap, LAN9303_HW_CFG, ®);
888*28a2c3e5SAnatolij Gustschin if (ret) {
889*28a2c3e5SAnatolij Gustschin dev_err(chip->dev, "failed to read HW_CFG reg: %pe\n",
890*28a2c3e5SAnatolij Gustschin ERR_PTR(ret));
891*28a2c3e5SAnatolij Gustschin return ret;
892*28a2c3e5SAnatolij Gustschin }
893*28a2c3e5SAnatolij Gustschin if (err) {
894*28a2c3e5SAnatolij Gustschin dev_err(chip->dev, "HW_CFG not ready: 0x%08x\n", reg);
895*28a2c3e5SAnatolij Gustschin return err;
896*28a2c3e5SAnatolij Gustschin }
897*28a2c3e5SAnatolij Gustschin
898a1292595SJuergen Beisert ret = lan9303_read(chip->regmap, LAN9303_CHIP_REV, ®);
899a1292595SJuergen Beisert if (ret) {
900a1292595SJuergen Beisert dev_err(chip->dev, "failed to read chip revision register: %d\n",
901a1292595SJuergen Beisert ret);
902a1292595SJuergen Beisert return ret;
903a1292595SJuergen Beisert }
904a1292595SJuergen Beisert
90513248b97SJerry Ray if (((reg >> 16) != LAN9303_CHIP_ID) &&
90613248b97SJerry Ray ((reg >> 16) != LAN9354_CHIP_ID)) {
90713248b97SJerry Ray dev_err(chip->dev, "unexpected device found: LAN%4.4X\n",
908a1292595SJuergen Beisert reg >> 16);
909a31e795aSWei Yongjun return -ENODEV;
910a1292595SJuergen Beisert }
911a1292595SJuergen Beisert
912a1292595SJuergen Beisert /* The default state of the LAN9303 device is to forward packets between
913a1292595SJuergen Beisert * all ports (if not configured differently by an external EEPROM).
914a1292595SJuergen Beisert * The initial state of a DSA device must be forwarding packets only
915a1292595SJuergen Beisert * between the external and the internal ports and no forwarding
916a1292595SJuergen Beisert * between the external ports. In preparation we stop packet handling
917a1292595SJuergen Beisert * at all for now until the LAN9303 device is re-programmed accordingly.
918a1292595SJuergen Beisert */
919a1292595SJuergen Beisert ret = lan9303_disable_processing(chip);
920a1292595SJuergen Beisert if (ret)
921a1292595SJuergen Beisert dev_warn(chip->dev, "failed to disable switching %d\n", ret);
922a1292595SJuergen Beisert
92313248b97SJerry Ray dev_info(chip->dev, "Found LAN%4.4X rev. %u\n", (reg >> 16), reg & 0xffff);
924a1292595SJuergen Beisert
925a1292595SJuergen Beisert ret = lan9303_detect_phy_setup(chip);
926a1292595SJuergen Beisert if (ret) {
927a1292595SJuergen Beisert dev_err(chip->dev,
928a1292595SJuergen Beisert "failed to discover phy bootstrap setup: %d\n", ret);
929a1292595SJuergen Beisert return ret;
930a1292595SJuergen Beisert }
931a1292595SJuergen Beisert
932a1292595SJuergen Beisert return 0;
933a1292595SJuergen Beisert }
934a1292595SJuergen Beisert
935a1292595SJuergen Beisert /* ---------------------------- DSA -----------------------------------*/
936a1292595SJuergen Beisert
lan9303_get_tag_protocol(struct dsa_switch * ds,int port,enum dsa_tag_protocol mp)9375ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds,
9384d776482SFlorian Fainelli int port,
9394d776482SFlorian Fainelli enum dsa_tag_protocol mp)
940a1292595SJuergen Beisert {
941a1292595SJuergen Beisert return DSA_TAG_PROTO_LAN9303;
942a1292595SJuergen Beisert }
943a1292595SJuergen Beisert
lan9303_setup(struct dsa_switch * ds)944a1292595SJuergen Beisert static int lan9303_setup(struct dsa_switch *ds)
945a1292595SJuergen Beisert {
946a1292595SJuergen Beisert struct lan9303 *chip = ds->priv;
947a1292595SJuergen Beisert int ret;
9481bcb5df8SJerry Ray u32 reg;
949a1292595SJuergen Beisert
950a1292595SJuergen Beisert /* Make sure that port 0 is the cpu port */
951a1292595SJuergen Beisert if (!dsa_is_cpu_port(ds, 0)) {
952a1292595SJuergen Beisert dev_err(chip->dev, "port 0 is not the CPU port\n");
953a1292595SJuergen Beisert return -EINVAL;
954a1292595SJuergen Beisert }
955a1292595SJuergen Beisert
9561bcb5df8SJerry Ray /* Virtual Phy: Remove Turbo 200Mbit mode */
957601f574aSJerry Ray ret = lan9303_read(chip->regmap, LAN9303_VIRT_SPECIAL_CTRL, ®);
958601f574aSJerry Ray if (ret)
959601f574aSJerry Ray return (ret);
9601bcb5df8SJerry Ray
961de375aa8SJerry Ray /* Clear the TURBO Mode bit if it was set. */
962de375aa8SJerry Ray if (reg & LAN9303_VIRT_SPECIAL_TURBO) {
9631bcb5df8SJerry Ray reg &= ~LAN9303_VIRT_SPECIAL_TURBO;
9641bcb5df8SJerry Ray regmap_write(chip->regmap, LAN9303_VIRT_SPECIAL_CTRL, reg);
965de375aa8SJerry Ray }
9661bcb5df8SJerry Ray
967f7e3bfa1SEgil Hjelmeland ret = lan9303_setup_tagging(chip);
968f7e3bfa1SEgil Hjelmeland if (ret)
969f7e3bfa1SEgil Hjelmeland dev_err(chip->dev, "failed to setup port tagging %d\n", ret);
970f7e3bfa1SEgil Hjelmeland
971a1292595SJuergen Beisert ret = lan9303_separate_ports(chip);
972a1292595SJuergen Beisert if (ret)
973a1292595SJuergen Beisert dev_err(chip->dev, "failed to separate ports %d\n", ret);
974a1292595SJuergen Beisert
9759c84258eSEgil Hjelmeland ret = lan9303_enable_processing_port(chip, 0);
976a1292595SJuergen Beisert if (ret)
977a1292595SJuergen Beisert dev_err(chip->dev, "failed to re-enable switching %d\n", ret);
978a1292595SJuergen Beisert
9792aee4307SEgil Hjelmeland /* Trap IGMP to port 0 */
9802aee4307SEgil Hjelmeland ret = lan9303_write_switch_reg_mask(chip, LAN9303_SWE_GLB_INGRESS_CFG,
9812aee4307SEgil Hjelmeland LAN9303_SWE_GLB_INGR_IGMP_TRAP |
9822aee4307SEgil Hjelmeland LAN9303_SWE_GLB_INGR_IGMP_PORT(0),
9832aee4307SEgil Hjelmeland LAN9303_SWE_GLB_INGR_IGMP_PORT(1) |
9842aee4307SEgil Hjelmeland LAN9303_SWE_GLB_INGR_IGMP_PORT(2));
9852aee4307SEgil Hjelmeland if (ret)
9862aee4307SEgil Hjelmeland dev_err(chip->dev, "failed to setup IGMP trap %d\n", ret);
9872aee4307SEgil Hjelmeland
988a1292595SJuergen Beisert return 0;
989a1292595SJuergen Beisert }
990a1292595SJuergen Beisert
991a1292595SJuergen Beisert struct lan9303_mib_desc {
992a1292595SJuergen Beisert unsigned int offset; /* offset of first MAC */
993a1292595SJuergen Beisert const char *name;
994a1292595SJuergen Beisert };
995a1292595SJuergen Beisert
996a1292595SJuergen Beisert static const struct lan9303_mib_desc lan9303_mib[] = {
997a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_BRDCST_CNT_0, .name = "RxBroad", },
998a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_PAUSE_CNT_0, .name = "RxPause", },
999a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_MULCST_CNT_0, .name = "RxMulti", },
1000a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_PKTOK_CNT_0, .name = "RxOk", },
1001a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_CRCERR_CNT_0, .name = "RxCrcErr", },
1002a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_ALIGN_CNT_0, .name = "RxAlignErr", },
1003a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_JABB_CNT_0, .name = "RxJabber", },
1004a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_FRAG_CNT_0, .name = "RxFragment", },
1005a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_64_CNT_0, .name = "Rx64Byte", },
1006a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_127_CNT_0, .name = "Rx128Byte", },
1007a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_255_CNT_0, .name = "Rx256Byte", },
1008a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_511_CNT_0, .name = "Rx512Byte", },
1009a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_1023_CNT_0, .name = "Rx1024Byte", },
1010a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_MAX_CNT_0, .name = "RxMaxByte", },
1011a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_PKTLEN_CNT_0, .name = "RxByteCnt", },
1012a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_SYMBL_CNT_0, .name = "RxSymbolCnt", },
1013a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_CTLFRM_CNT_0, .name = "RxCfs", },
1014a1292595SJuergen Beisert { .offset = LAN9303_MAC_RX_OVRSZE_CNT_0, .name = "RxOverFlow", },
1015a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_UNDSZE_CNT_0, .name = "TxShort", },
1016a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_BRDCST_CNT_0, .name = "TxBroad", },
1017a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_PAUSE_CNT_0, .name = "TxPause", },
1018a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_MULCST_CNT_0, .name = "TxMulti", },
101939f59bcaSJerry Ray { .offset = LAN9303_MAC_RX_UNDSZE_CNT_0, .name = "RxShort", },
1020a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_64_CNT_0, .name = "Tx64Byte", },
1021a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_127_CNT_0, .name = "Tx128Byte", },
1022a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_255_CNT_0, .name = "Tx256Byte", },
1023a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_511_CNT_0, .name = "Tx512Byte", },
1024a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_1023_CNT_0, .name = "Tx1024Byte", },
1025a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_MAX_CNT_0, .name = "TxMaxByte", },
1026a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_PKTLEN_CNT_0, .name = "TxByteCnt", },
1027a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_PKTOK_CNT_0, .name = "TxOk", },
1028a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_TOTALCOL_CNT_0, .name = "TxCollision", },
1029a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_MULTICOL_CNT_0, .name = "TxMultiCol", },
1030a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_SNGLECOL_CNT_0, .name = "TxSingleCol", },
1031a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_EXCOL_CNT_0, .name = "TxExcCol", },
1032a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_DEFER_CNT_0, .name = "TxDefer", },
1033a1292595SJuergen Beisert { .offset = LAN9303_MAC_TX_LATECOL_0, .name = "TxLateCol", },
1034a1292595SJuergen Beisert };
1035a1292595SJuergen Beisert
lan9303_get_strings(struct dsa_switch * ds,int port,u32 stringset,uint8_t * data)103689f09048SFlorian Fainelli static void lan9303_get_strings(struct dsa_switch *ds, int port,
103789f09048SFlorian Fainelli u32 stringset, uint8_t *data)
1038a1292595SJuergen Beisert {
1039a1292595SJuergen Beisert unsigned int u;
1040a1292595SJuergen Beisert
104189f09048SFlorian Fainelli if (stringset != ETH_SS_STATS)
104289f09048SFlorian Fainelli return;
104389f09048SFlorian Fainelli
1044a1292595SJuergen Beisert for (u = 0; u < ARRAY_SIZE(lan9303_mib); u++) {
1045a1292595SJuergen Beisert strncpy(data + u * ETH_GSTRING_LEN, lan9303_mib[u].name,
1046a1292595SJuergen Beisert ETH_GSTRING_LEN);
1047a1292595SJuergen Beisert }
1048a1292595SJuergen Beisert }
1049a1292595SJuergen Beisert
lan9303_get_ethtool_stats(struct dsa_switch * ds,int port,uint64_t * data)1050a1292595SJuergen Beisert static void lan9303_get_ethtool_stats(struct dsa_switch *ds, int port,
1051a1292595SJuergen Beisert uint64_t *data)
1052a1292595SJuergen Beisert {
1053a1292595SJuergen Beisert struct lan9303 *chip = ds->priv;
10540a967b4aSEgil Hjelmeland unsigned int u;
1055a1292595SJuergen Beisert
1056a1292595SJuergen Beisert for (u = 0; u < ARRAY_SIZE(lan9303_mib); u++) {
10570a967b4aSEgil Hjelmeland u32 reg;
10580a967b4aSEgil Hjelmeland int ret;
10590a967b4aSEgil Hjelmeland
10600a967b4aSEgil Hjelmeland ret = lan9303_read_switch_port(
10610a967b4aSEgil Hjelmeland chip, port, lan9303_mib[u].offset, ®);
10620a967b4aSEgil Hjelmeland
10638964916dSJerry Ray if (ret) {
10640a967b4aSEgil Hjelmeland dev_warn(chip->dev, "Reading status port %d reg %u failed\n",
10650a967b4aSEgil Hjelmeland port, lan9303_mib[u].offset);
10668964916dSJerry Ray reg = 0;
10678964916dSJerry Ray }
1068a1292595SJuergen Beisert data[u] = reg;
1069a1292595SJuergen Beisert }
1070a1292595SJuergen Beisert }
1071a1292595SJuergen Beisert
lan9303_get_sset_count(struct dsa_switch * ds,int port,int sset)107289f09048SFlorian Fainelli static int lan9303_get_sset_count(struct dsa_switch *ds, int port, int sset)
1073a1292595SJuergen Beisert {
107489f09048SFlorian Fainelli if (sset != ETH_SS_STATS)
107589f09048SFlorian Fainelli return 0;
107689f09048SFlorian Fainelli
1077a1292595SJuergen Beisert return ARRAY_SIZE(lan9303_mib);
1078a1292595SJuergen Beisert }
1079a1292595SJuergen Beisert
lan9303_phy_read(struct dsa_switch * ds,int port,int regnum)1080cae91b5cSChristian Eggers static int lan9303_phy_read(struct dsa_switch *ds, int port, int regnum)
1081a1292595SJuergen Beisert {
1082a1292595SJuergen Beisert struct lan9303 *chip = ds->priv;
1083b17c6b1fSEgil Hjelmeland int phy_base = chip->phy_addr_base;
1084a1292595SJuergen Beisert
1085cae91b5cSChristian Eggers if (port == 0)
1086a1292595SJuergen Beisert return lan9303_virt_phy_reg_read(chip, regnum);
1087cae91b5cSChristian Eggers if (port > 2)
1088a1292595SJuergen Beisert return -ENODEV;
1089a1292595SJuergen Beisert
1090cae91b5cSChristian Eggers return chip->ops->phy_read(chip, phy_base + port, regnum);
1091a1292595SJuergen Beisert }
1092a1292595SJuergen Beisert
lan9303_phy_write(struct dsa_switch * ds,int port,int regnum,u16 val)1093cae91b5cSChristian Eggers static int lan9303_phy_write(struct dsa_switch *ds, int port, int regnum,
1094a1292595SJuergen Beisert u16 val)
1095a1292595SJuergen Beisert {
1096a1292595SJuergen Beisert struct lan9303 *chip = ds->priv;
1097b17c6b1fSEgil Hjelmeland int phy_base = chip->phy_addr_base;
1098a1292595SJuergen Beisert
1099cae91b5cSChristian Eggers if (port == 0)
1100a1292595SJuergen Beisert return lan9303_virt_phy_reg_write(chip, regnum, val);
1101cae91b5cSChristian Eggers if (port > 2)
1102a1292595SJuergen Beisert return -ENODEV;
1103a1292595SJuergen Beisert
1104cae91b5cSChristian Eggers return chip->ops->phy_write(chip, phy_base + port, regnum, val);
1105a1292595SJuergen Beisert }
1106a1292595SJuergen Beisert
lan9303_port_enable(struct dsa_switch * ds,int port,struct phy_device * phy)1107a1292595SJuergen Beisert static int lan9303_port_enable(struct dsa_switch *ds, int port,
1108a1292595SJuergen Beisert struct phy_device *phy)
1109a1292595SJuergen Beisert {
1110430065e2SMans Rullgard struct dsa_port *dp = dsa_to_port(ds, port);
1111a1292595SJuergen Beisert struct lan9303 *chip = ds->priv;
1112a1292595SJuergen Beisert
1113430065e2SMans Rullgard if (!dsa_port_is_user(dp))
111474be4babSVivien Didelot return 0;
111574be4babSVivien Didelot
11168f6a19c0SVladimir Oltean vlan_vid_add(dsa_port_to_master(dp), htons(ETH_P_8021Q), port);
1117430065e2SMans Rullgard
11189c84258eSEgil Hjelmeland return lan9303_enable_processing_port(chip, port);
1119a1292595SJuergen Beisert }
1120a1292595SJuergen Beisert
lan9303_port_disable(struct dsa_switch * ds,int port)112175104db0SAndrew Lunn static void lan9303_port_disable(struct dsa_switch *ds, int port)
1122a1292595SJuergen Beisert {
1123430065e2SMans Rullgard struct dsa_port *dp = dsa_to_port(ds, port);
1124a1292595SJuergen Beisert struct lan9303 *chip = ds->priv;
1125a1292595SJuergen Beisert
1126430065e2SMans Rullgard if (!dsa_port_is_user(dp))
112774be4babSVivien Didelot return;
112874be4babSVivien Didelot
11298f6a19c0SVladimir Oltean vlan_vid_del(dsa_port_to_master(dp), htons(ETH_P_8021Q), port);
1130430065e2SMans Rullgard
11319c84258eSEgil Hjelmeland lan9303_disable_processing_port(chip, port);
1132cae91b5cSChristian Eggers lan9303_phy_write(ds, port, MII_BMCR, BMCR_PDOWN);
1133a1292595SJuergen Beisert }
1134a1292595SJuergen Beisert
lan9303_port_bridge_join(struct dsa_switch * ds,int port,struct dsa_bridge bridge,bool * tx_fwd_offload,struct netlink_ext_ack * extack)1135d99a86aeSEgil Hjelmeland static int lan9303_port_bridge_join(struct dsa_switch *ds, int port,
1136b079922bSVladimir Oltean struct dsa_bridge bridge,
113706b9cce4SVladimir Oltean bool *tx_fwd_offload,
113806b9cce4SVladimir Oltean struct netlink_ext_ack *extack)
1139d99a86aeSEgil Hjelmeland {
1140d99a86aeSEgil Hjelmeland struct lan9303 *chip = ds->priv;
1141d99a86aeSEgil Hjelmeland
1142d99a86aeSEgil Hjelmeland dev_dbg(chip->dev, "%s(port %d)\n", __func__, port);
114341fb0cf1SVladimir Oltean if (dsa_port_bridge_same(dsa_to_port(ds, 1), dsa_to_port(ds, 2))) {
1144d99a86aeSEgil Hjelmeland lan9303_bridge_ports(chip);
1145d99a86aeSEgil Hjelmeland chip->is_bridged = true; /* unleash stp_state_set() */
1146d99a86aeSEgil Hjelmeland }
1147d99a86aeSEgil Hjelmeland
1148d99a86aeSEgil Hjelmeland return 0;
1149d99a86aeSEgil Hjelmeland }
1150d99a86aeSEgil Hjelmeland
lan9303_port_bridge_leave(struct dsa_switch * ds,int port,struct dsa_bridge bridge)1151d99a86aeSEgil Hjelmeland static void lan9303_port_bridge_leave(struct dsa_switch *ds, int port,
1152d3eed0e5SVladimir Oltean struct dsa_bridge bridge)
1153d99a86aeSEgil Hjelmeland {
1154d99a86aeSEgil Hjelmeland struct lan9303 *chip = ds->priv;
1155d99a86aeSEgil Hjelmeland
1156d99a86aeSEgil Hjelmeland dev_dbg(chip->dev, "%s(port %d)\n", __func__, port);
1157d99a86aeSEgil Hjelmeland if (chip->is_bridged) {
1158d99a86aeSEgil Hjelmeland lan9303_separate_ports(chip);
1159d99a86aeSEgil Hjelmeland chip->is_bridged = false;
1160d99a86aeSEgil Hjelmeland }
1161d99a86aeSEgil Hjelmeland }
1162d99a86aeSEgil Hjelmeland
lan9303_port_stp_state_set(struct dsa_switch * ds,int port,u8 state)1163d99a86aeSEgil Hjelmeland static void lan9303_port_stp_state_set(struct dsa_switch *ds, int port,
1164d99a86aeSEgil Hjelmeland u8 state)
1165d99a86aeSEgil Hjelmeland {
1166d99a86aeSEgil Hjelmeland int portmask, portstate;
1167d99a86aeSEgil Hjelmeland struct lan9303 *chip = ds->priv;
1168d99a86aeSEgil Hjelmeland
1169d99a86aeSEgil Hjelmeland dev_dbg(chip->dev, "%s(port %d, state %d)\n",
1170d99a86aeSEgil Hjelmeland __func__, port, state);
1171d99a86aeSEgil Hjelmeland
1172d99a86aeSEgil Hjelmeland switch (state) {
1173d99a86aeSEgil Hjelmeland case BR_STATE_DISABLED:
1174d99a86aeSEgil Hjelmeland portstate = LAN9303_SWE_PORT_STATE_DISABLED_PORT0;
1175d99a86aeSEgil Hjelmeland break;
1176d99a86aeSEgil Hjelmeland case BR_STATE_BLOCKING:
1177d99a86aeSEgil Hjelmeland case BR_STATE_LISTENING:
1178d99a86aeSEgil Hjelmeland portstate = LAN9303_SWE_PORT_STATE_BLOCKING_PORT0;
1179d99a86aeSEgil Hjelmeland break;
1180d99a86aeSEgil Hjelmeland case BR_STATE_LEARNING:
1181d99a86aeSEgil Hjelmeland portstate = LAN9303_SWE_PORT_STATE_LEARNING_PORT0;
1182d99a86aeSEgil Hjelmeland break;
1183d99a86aeSEgil Hjelmeland case BR_STATE_FORWARDING:
1184d99a86aeSEgil Hjelmeland portstate = LAN9303_SWE_PORT_STATE_FORWARDING_PORT0;
1185d99a86aeSEgil Hjelmeland break;
1186d99a86aeSEgil Hjelmeland default:
1187d99a86aeSEgil Hjelmeland portstate = LAN9303_SWE_PORT_STATE_DISABLED_PORT0;
1188d99a86aeSEgil Hjelmeland dev_err(chip->dev, "unknown stp state: port %d, state %d\n",
1189d99a86aeSEgil Hjelmeland port, state);
1190d99a86aeSEgil Hjelmeland }
1191d99a86aeSEgil Hjelmeland
1192d99a86aeSEgil Hjelmeland portmask = 0x3 << (port * 2);
1193d99a86aeSEgil Hjelmeland portstate <<= (port * 2);
1194d99a86aeSEgil Hjelmeland
1195d99a86aeSEgil Hjelmeland chip->swe_port_state = (chip->swe_port_state & ~portmask) | portstate;
1196d99a86aeSEgil Hjelmeland
1197d99a86aeSEgil Hjelmeland if (chip->is_bridged)
1198d99a86aeSEgil Hjelmeland lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE,
1199d99a86aeSEgil Hjelmeland chip->swe_port_state);
1200d99a86aeSEgil Hjelmeland /* else: touching SWE_PORT_STATE would break port separation */
1201d99a86aeSEgil Hjelmeland }
1202d99a86aeSEgil Hjelmeland
lan9303_port_fast_age(struct dsa_switch * ds,int port)1203ab335349SEgil Hjelmeland static void lan9303_port_fast_age(struct dsa_switch *ds, int port)
1204ab335349SEgil Hjelmeland {
1205ab335349SEgil Hjelmeland struct lan9303 *chip = ds->priv;
1206ab335349SEgil Hjelmeland struct del_port_learned_ctx del_ctx = {
1207ab335349SEgil Hjelmeland .port = port,
1208ab335349SEgil Hjelmeland };
1209ab335349SEgil Hjelmeland
1210ab335349SEgil Hjelmeland dev_dbg(chip->dev, "%s(%d)\n", __func__, port);
1211ab335349SEgil Hjelmeland lan9303_alr_loop(chip, alr_loop_cb_del_port_learned, &del_ctx);
1212ab335349SEgil Hjelmeland }
1213ab335349SEgil Hjelmeland
lan9303_port_fdb_add(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)12140620427eSEgil Hjelmeland static int lan9303_port_fdb_add(struct dsa_switch *ds, int port,
1215c2693363SVladimir Oltean const unsigned char *addr, u16 vid,
1216c2693363SVladimir Oltean struct dsa_db db)
12170620427eSEgil Hjelmeland {
12180620427eSEgil Hjelmeland struct lan9303 *chip = ds->priv;
12190620427eSEgil Hjelmeland
12200620427eSEgil Hjelmeland dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
12210620427eSEgil Hjelmeland
12220620427eSEgil Hjelmeland return lan9303_alr_add_port(chip, addr, port, false);
12230620427eSEgil Hjelmeland }
12240620427eSEgil Hjelmeland
lan9303_port_fdb_del(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)12250620427eSEgil Hjelmeland static int lan9303_port_fdb_del(struct dsa_switch *ds, int port,
1226c2693363SVladimir Oltean const unsigned char *addr, u16 vid,
1227c2693363SVladimir Oltean struct dsa_db db)
12280620427eSEgil Hjelmeland {
12290620427eSEgil Hjelmeland struct lan9303 *chip = ds->priv;
12300620427eSEgil Hjelmeland
12310620427eSEgil Hjelmeland dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
12320620427eSEgil Hjelmeland lan9303_alr_del_port(chip, addr, port);
12330620427eSEgil Hjelmeland
12340620427eSEgil Hjelmeland return 0;
12350620427eSEgil Hjelmeland }
12360620427eSEgil Hjelmeland
lan9303_port_fdb_dump(struct dsa_switch * ds,int port,dsa_fdb_dump_cb_t * cb,void * data)1237ab335349SEgil Hjelmeland static int lan9303_port_fdb_dump(struct dsa_switch *ds, int port,
1238ab335349SEgil Hjelmeland dsa_fdb_dump_cb_t *cb, void *data)
1239ab335349SEgil Hjelmeland {
1240ab335349SEgil Hjelmeland struct lan9303 *chip = ds->priv;
1241ab335349SEgil Hjelmeland struct port_fdb_dump_ctx dump_ctx = {
1242ab335349SEgil Hjelmeland .port = port,
1243ab335349SEgil Hjelmeland .data = data,
1244ab335349SEgil Hjelmeland .cb = cb,
1245ab335349SEgil Hjelmeland };
1246ab335349SEgil Hjelmeland
1247ab335349SEgil Hjelmeland dev_dbg(chip->dev, "%s(%d)\n", __func__, port);
1248ada2fee1SVladimir Oltean return lan9303_alr_loop(chip, alr_loop_cb_fdb_port_dump, &dump_ctx);
1249ab335349SEgil Hjelmeland }
1250ab335349SEgil Hjelmeland
lan9303_port_mdb_prepare(struct dsa_switch * ds,int port,const struct switchdev_obj_port_mdb * mdb)12510620427eSEgil Hjelmeland static int lan9303_port_mdb_prepare(struct dsa_switch *ds, int port,
12523709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb)
12530620427eSEgil Hjelmeland {
12540620427eSEgil Hjelmeland struct lan9303 *chip = ds->priv;
12550620427eSEgil Hjelmeland
12560620427eSEgil Hjelmeland dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, mdb->addr,
12570620427eSEgil Hjelmeland mdb->vid);
12580620427eSEgil Hjelmeland if (mdb->vid)
12590620427eSEgil Hjelmeland return -EOPNOTSUPP;
12600620427eSEgil Hjelmeland if (lan9303_alr_cache_find_mac(chip, mdb->addr))
12610620427eSEgil Hjelmeland return 0;
12620620427eSEgil Hjelmeland if (!lan9303_alr_cache_find_free(chip))
12630620427eSEgil Hjelmeland return -ENOSPC;
12640620427eSEgil Hjelmeland
12650620427eSEgil Hjelmeland return 0;
12660620427eSEgil Hjelmeland }
12670620427eSEgil Hjelmeland
lan9303_port_mdb_add(struct dsa_switch * ds,int port,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)1268a52b2da7SVladimir Oltean static int lan9303_port_mdb_add(struct dsa_switch *ds, int port,
1269c2693363SVladimir Oltean const struct switchdev_obj_port_mdb *mdb,
1270c2693363SVladimir Oltean struct dsa_db db)
12710620427eSEgil Hjelmeland {
12720620427eSEgil Hjelmeland struct lan9303 *chip = ds->priv;
1273a52b2da7SVladimir Oltean int err;
1274a52b2da7SVladimir Oltean
1275a52b2da7SVladimir Oltean err = lan9303_port_mdb_prepare(ds, port, mdb);
1276a52b2da7SVladimir Oltean if (err)
1277a52b2da7SVladimir Oltean return err;
12780620427eSEgil Hjelmeland
12790620427eSEgil Hjelmeland dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, mdb->addr,
12800620427eSEgil Hjelmeland mdb->vid);
1281a52b2da7SVladimir Oltean return lan9303_alr_add_port(chip, mdb->addr, port, false);
12820620427eSEgil Hjelmeland }
12830620427eSEgil Hjelmeland
lan9303_port_mdb_del(struct dsa_switch * ds,int port,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)12840620427eSEgil Hjelmeland static int lan9303_port_mdb_del(struct dsa_switch *ds, int port,
1285c2693363SVladimir Oltean const struct switchdev_obj_port_mdb *mdb,
1286c2693363SVladimir Oltean struct dsa_db db)
12870620427eSEgil Hjelmeland {
12880620427eSEgil Hjelmeland struct lan9303 *chip = ds->priv;
12890620427eSEgil Hjelmeland
12900620427eSEgil Hjelmeland dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, mdb->addr,
12910620427eSEgil Hjelmeland mdb->vid);
12920620427eSEgil Hjelmeland if (mdb->vid)
12930620427eSEgil Hjelmeland return -EOPNOTSUPP;
12940620427eSEgil Hjelmeland lan9303_alr_del_port(chip, mdb->addr, port);
12950620427eSEgil Hjelmeland
12960620427eSEgil Hjelmeland return 0;
12970620427eSEgil Hjelmeland }
12980620427eSEgil Hjelmeland
lan9303_phylink_get_caps(struct dsa_switch * ds,int port,struct phylink_config * config)1299332bc552SJerry Ray static void lan9303_phylink_get_caps(struct dsa_switch *ds, int port,
1300332bc552SJerry Ray struct phylink_config *config)
1301332bc552SJerry Ray {
1302332bc552SJerry Ray struct lan9303 *chip = ds->priv;
1303332bc552SJerry Ray
1304332bc552SJerry Ray dev_dbg(chip->dev, "%s(%d) entered.", __func__, port);
1305332bc552SJerry Ray
1306332bc552SJerry Ray config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE |
1307332bc552SJerry Ray MAC_SYM_PAUSE;
1308332bc552SJerry Ray
1309332bc552SJerry Ray if (port == 0) {
1310332bc552SJerry Ray __set_bit(PHY_INTERFACE_MODE_RMII,
1311332bc552SJerry Ray config->supported_interfaces);
1312332bc552SJerry Ray __set_bit(PHY_INTERFACE_MODE_MII,
1313332bc552SJerry Ray config->supported_interfaces);
1314332bc552SJerry Ray } else {
1315332bc552SJerry Ray __set_bit(PHY_INTERFACE_MODE_INTERNAL,
1316332bc552SJerry Ray config->supported_interfaces);
1317332bc552SJerry Ray /* Compatibility for phylib's default interface type when the
1318332bc552SJerry Ray * phy-mode property is absent
1319332bc552SJerry Ray */
1320332bc552SJerry Ray __set_bit(PHY_INTERFACE_MODE_GMII,
1321332bc552SJerry Ray config->supported_interfaces);
1322332bc552SJerry Ray }
1323332bc552SJerry Ray }
1324332bc552SJerry Ray
lan9303_phylink_mac_link_up(struct dsa_switch * ds,int port,unsigned int mode,phy_interface_t interface,struct phy_device * phydev,int speed,int duplex,bool tx_pause,bool rx_pause)1325332bc552SJerry Ray static void lan9303_phylink_mac_link_up(struct dsa_switch *ds, int port,
1326332bc552SJerry Ray unsigned int mode,
1327332bc552SJerry Ray phy_interface_t interface,
1328332bc552SJerry Ray struct phy_device *phydev, int speed,
1329332bc552SJerry Ray int duplex, bool tx_pause,
1330332bc552SJerry Ray bool rx_pause)
1331332bc552SJerry Ray {
133287523986SJerry Ray struct lan9303 *chip = ds->priv;
1333332bc552SJerry Ray u32 ctl;
133487523986SJerry Ray u32 reg;
1335332bc552SJerry Ray
1336332bc552SJerry Ray /* On this device, we are only interested in doing something here if
1337332bc552SJerry Ray * this is the xMII port. All other ports are 10/100 phys using MDIO
1338332bc552SJerry Ray * to control there link settings.
1339332bc552SJerry Ray */
1340332bc552SJerry Ray if (!IS_PORT_XMII(port))
1341332bc552SJerry Ray return;
1342332bc552SJerry Ray
134387523986SJerry Ray /* Disable auto-negotiation and force the speed/duplex settings. */
1344332bc552SJerry Ray ctl = lan9303_phy_read(ds, port, MII_BMCR);
134587523986SJerry Ray ctl &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
1346332bc552SJerry Ray if (speed == SPEED_100)
1347332bc552SJerry Ray ctl |= BMCR_SPEED100;
1348332bc552SJerry Ray if (duplex == DUPLEX_FULL)
1349332bc552SJerry Ray ctl |= BMCR_FULLDPLX;
1350332bc552SJerry Ray lan9303_phy_write(ds, port, MII_BMCR, ctl);
135187523986SJerry Ray
135287523986SJerry Ray /* Force the flow control settings. */
135387523986SJerry Ray lan9303_read(chip->regmap, flow_ctl_reg[port], ®);
135487523986SJerry Ray reg &= ~(LAN9303_BP_EN | LAN9303_RX_FC_EN | LAN9303_TX_FC_EN);
135587523986SJerry Ray if (rx_pause)
135687523986SJerry Ray reg |= (LAN9303_RX_FC_EN | LAN9303_BP_EN);
135787523986SJerry Ray if (tx_pause)
135887523986SJerry Ray reg |= LAN9303_TX_FC_EN;
135987523986SJerry Ray regmap_write(chip->regmap, flow_ctl_reg[port], reg);
1360332bc552SJerry Ray }
1361332bc552SJerry Ray
1362d78d6776SBhumika Goyal static const struct dsa_switch_ops lan9303_switch_ops = {
1363a1292595SJuergen Beisert .get_tag_protocol = lan9303_get_tag_protocol,
1364a1292595SJuergen Beisert .setup = lan9303_setup,
1365a1292595SJuergen Beisert .get_strings = lan9303_get_strings,
1366a1292595SJuergen Beisert .phy_read = lan9303_phy_read,
1367a1292595SJuergen Beisert .phy_write = lan9303_phy_write,
1368332bc552SJerry Ray .phylink_get_caps = lan9303_phylink_get_caps,
1369332bc552SJerry Ray .phylink_mac_link_up = lan9303_phylink_mac_link_up,
1370a1292595SJuergen Beisert .get_ethtool_stats = lan9303_get_ethtool_stats,
1371a1292595SJuergen Beisert .get_sset_count = lan9303_get_sset_count,
1372a1292595SJuergen Beisert .port_enable = lan9303_port_enable,
1373a1292595SJuergen Beisert .port_disable = lan9303_port_disable,
1374d99a86aeSEgil Hjelmeland .port_bridge_join = lan9303_port_bridge_join,
1375d99a86aeSEgil Hjelmeland .port_bridge_leave = lan9303_port_bridge_leave,
1376d99a86aeSEgil Hjelmeland .port_stp_state_set = lan9303_port_stp_state_set,
1377ab335349SEgil Hjelmeland .port_fast_age = lan9303_port_fast_age,
13780620427eSEgil Hjelmeland .port_fdb_add = lan9303_port_fdb_add,
13790620427eSEgil Hjelmeland .port_fdb_del = lan9303_port_fdb_del,
1380ab335349SEgil Hjelmeland .port_fdb_dump = lan9303_port_fdb_dump,
13810620427eSEgil Hjelmeland .port_mdb_add = lan9303_port_mdb_add,
13820620427eSEgil Hjelmeland .port_mdb_del = lan9303_port_mdb_del,
1383a1292595SJuergen Beisert };
1384a1292595SJuergen Beisert
lan9303_register_switch(struct lan9303 * chip)1385a1292595SJuergen Beisert static int lan9303_register_switch(struct lan9303 *chip)
1386a1292595SJuergen Beisert {
13877e99e347SVivien Didelot chip->ds = devm_kzalloc(chip->dev, sizeof(*chip->ds), GFP_KERNEL);
1388a1292595SJuergen Beisert if (!chip->ds)
1389a1292595SJuergen Beisert return -ENOMEM;
1390a1292595SJuergen Beisert
13917e99e347SVivien Didelot chip->ds->dev = chip->dev;
13927e99e347SVivien Didelot chip->ds->num_ports = LAN9303_NUM_PORTS;
1393a1292595SJuergen Beisert chip->ds->priv = chip;
1394a1292595SJuergen Beisert chip->ds->ops = &lan9303_switch_ops;
1395cae91b5cSChristian Eggers chip->ds->phys_mii_mask = GENMASK(LAN9303_NUM_PORTS - 1, 0);
1396a1292595SJuergen Beisert
139723c9ee49SVivien Didelot return dsa_register_switch(chip->ds);
1398a1292595SJuergen Beisert }
1399a1292595SJuergen Beisert
lan9303_probe_reset_gpio(struct lan9303 * chip,struct device_node * np)1400f1689132SPhil Reid static int lan9303_probe_reset_gpio(struct lan9303 *chip,
1401a1292595SJuergen Beisert struct device_node *np)
1402a1292595SJuergen Beisert {
1403a1292595SJuergen Beisert chip->reset_gpio = devm_gpiod_get_optional(chip->dev, "reset",
14046bb9681aSMans Rullgard GPIOD_OUT_HIGH);
1405f1689132SPhil Reid if (IS_ERR(chip->reset_gpio))
1406f1689132SPhil Reid return PTR_ERR(chip->reset_gpio);
1407a1292595SJuergen Beisert
1408f1689132SPhil Reid if (!chip->reset_gpio) {
1409a1292595SJuergen Beisert dev_dbg(chip->dev, "No reset GPIO defined\n");
1410f1689132SPhil Reid return 0;
1411a1292595SJuergen Beisert }
1412a1292595SJuergen Beisert
1413a1292595SJuergen Beisert chip->reset_duration = 200;
1414a1292595SJuergen Beisert
1415a1292595SJuergen Beisert if (np) {
1416a1292595SJuergen Beisert of_property_read_u32(np, "reset-duration",
1417a1292595SJuergen Beisert &chip->reset_duration);
1418a1292595SJuergen Beisert } else {
1419a1292595SJuergen Beisert dev_dbg(chip->dev, "reset duration defaults to 200 ms\n");
1420a1292595SJuergen Beisert }
1421a1292595SJuergen Beisert
1422a1292595SJuergen Beisert /* A sane reset duration should not be longer than 1s */
1423a1292595SJuergen Beisert if (chip->reset_duration > 1000)
1424a1292595SJuergen Beisert chip->reset_duration = 1000;
1425f1689132SPhil Reid
1426f1689132SPhil Reid return 0;
1427a1292595SJuergen Beisert }
1428a1292595SJuergen Beisert
lan9303_probe(struct lan9303 * chip,struct device_node * np)1429a1292595SJuergen Beisert int lan9303_probe(struct lan9303 *chip, struct device_node *np)
1430a1292595SJuergen Beisert {
1431a1292595SJuergen Beisert int ret;
1432732f374eSJerry Ray u32 reg;
1433a1292595SJuergen Beisert
1434a1292595SJuergen Beisert mutex_init(&chip->indirect_mutex);
14352e8d243eSEgil Hjelmeland mutex_init(&chip->alr_mutex);
1436a1292595SJuergen Beisert
1437f1689132SPhil Reid ret = lan9303_probe_reset_gpio(chip, np);
1438f1689132SPhil Reid if (ret)
1439f1689132SPhil Reid return ret;
1440a1292595SJuergen Beisert
1441a57d476dSPhil Reid lan9303_handle_reset(chip);
1442a1292595SJuergen Beisert
1443732f374eSJerry Ray /* First read to the device. This is a Dummy read to ensure MDIO */
1444732f374eSJerry Ray /* access is in 32-bit sync. */
1445732f374eSJerry Ray ret = lan9303_read(chip->regmap, LAN9303_BYTE_ORDER, ®);
1446732f374eSJerry Ray if (ret) {
1447732f374eSJerry Ray dev_err(chip->dev, "failed to access the device: %d\n",
1448732f374eSJerry Ray ret);
1449732f374eSJerry Ray if (!chip->reset_gpio) {
1450732f374eSJerry Ray dev_dbg(chip->dev,
1451732f374eSJerry Ray "hint: maybe failed due to missing reset GPIO\n");
1452732f374eSJerry Ray }
1453732f374eSJerry Ray return ret;
1454732f374eSJerry Ray }
1455732f374eSJerry Ray
1456a1292595SJuergen Beisert ret = lan9303_check_device(chip);
1457a1292595SJuergen Beisert if (ret)
1458a1292595SJuergen Beisert return ret;
1459a1292595SJuergen Beisert
1460a1292595SJuergen Beisert ret = lan9303_register_switch(chip);
1461a1292595SJuergen Beisert if (ret) {
1462a1292595SJuergen Beisert dev_dbg(chip->dev, "Failed to register switch: %d\n", ret);
1463a1292595SJuergen Beisert return ret;
1464a1292595SJuergen Beisert }
1465a1292595SJuergen Beisert
1466a1292595SJuergen Beisert return 0;
1467a1292595SJuergen Beisert }
1468a1292595SJuergen Beisert EXPORT_SYMBOL(lan9303_probe);
1469a1292595SJuergen Beisert
lan9303_remove(struct lan9303 * chip)1470a1292595SJuergen Beisert int lan9303_remove(struct lan9303 *chip)
1471a1292595SJuergen Beisert {
1472a1292595SJuergen Beisert int rc;
1473a1292595SJuergen Beisert
1474a1292595SJuergen Beisert rc = lan9303_disable_processing(chip);
1475a1292595SJuergen Beisert if (rc != 0)
1476a1292595SJuergen Beisert dev_warn(chip->dev, "shutting down failed\n");
1477a1292595SJuergen Beisert
1478a1292595SJuergen Beisert dsa_unregister_switch(chip->ds);
1479a1292595SJuergen Beisert
1480a1292595SJuergen Beisert /* assert reset to the whole device to prevent it from doing anything */
1481a1292595SJuergen Beisert gpiod_set_value_cansleep(chip->reset_gpio, 1);
1482a1292595SJuergen Beisert
1483a1292595SJuergen Beisert return 0;
1484a1292595SJuergen Beisert }
1485a1292595SJuergen Beisert EXPORT_SYMBOL(lan9303_remove);
1486a1292595SJuergen Beisert
lan9303_shutdown(struct lan9303 * chip)14870650bf52SVladimir Oltean void lan9303_shutdown(struct lan9303 *chip)
14880650bf52SVladimir Oltean {
14890650bf52SVladimir Oltean dsa_switch_shutdown(chip->ds);
14900650bf52SVladimir Oltean }
14910650bf52SVladimir Oltean EXPORT_SYMBOL(lan9303_shutdown);
14920650bf52SVladimir Oltean
1493a1292595SJuergen Beisert MODULE_AUTHOR("Juergen Borleis <kernel@pengutronix.de>");
1494a1292595SJuergen Beisert MODULE_DESCRIPTION("Core driver for SMSC/Microchip LAN9303 three port ethernet switch");
1495a1292595SJuergen Beisert MODULE_LICENSE("GPL v2");
1496