Commit | Line | Data |
---|---|---|
888cdb89 CL |
1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* | |
3 | * Copyright (C) 2022 Schneider Electric | |
4 | * | |
5 | * Clément Léger <clement.leger@bootlin.com> | |
6 | */ | |
7 | ||
8 | #include <linux/clk.h> | |
9 | #include <linux/debugfs.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/of.h> | |
13 | #include <linux/of_mdio.h> | |
14 | #include <linux/platform_device.h> | |
15 | #include <linux/pcs-rzn1-miic.h> | |
16 | #include <net/dsa.h> | |
17 | ||
18 | #define A5PSW_REVISION 0x0 | |
19 | #define A5PSW_PORT_OFFSET(port) (0x400 * (port)) | |
20 | ||
21 | #define A5PSW_PORT_ENA 0x8 | |
ebe9bc50 | 22 | #define A5PSW_PORT_ENA_TX(port) BIT(port) |
888cdb89 CL |
23 | #define A5PSW_PORT_ENA_RX_SHIFT 16 |
24 | #define A5PSW_PORT_ENA_TX_RX(port) (BIT((port) + A5PSW_PORT_ENA_RX_SHIFT) | \ | |
25 | BIT(port)) | |
26 | #define A5PSW_UCAST_DEF_MASK 0xC | |
27 | ||
28 | #define A5PSW_VLAN_VERIFY 0x10 | |
29 | #define A5PSW_VLAN_VERI_SHIFT 0 | |
30 | #define A5PSW_VLAN_DISC_SHIFT 16 | |
31 | ||
32 | #define A5PSW_BCAST_DEF_MASK 0x14 | |
33 | #define A5PSW_MCAST_DEF_MASK 0x18 | |
34 | ||
35 | #define A5PSW_INPUT_LEARN 0x1C | |
36 | #define A5PSW_INPUT_LEARN_DIS(p) BIT((p) + 16) | |
37 | #define A5PSW_INPUT_LEARN_BLOCK(p) BIT(p) | |
38 | ||
39 | #define A5PSW_MGMT_CFG 0x20 | |
9e4b45f2 | 40 | #define A5PSW_MGMT_CFG_ENABLE BIT(6) |
888cdb89 CL |
41 | |
42 | #define A5PSW_MODE_CFG 0x24 | |
43 | #define A5PSW_MODE_STATS_RESET BIT(31) | |
44 | ||
45 | #define A5PSW_VLAN_IN_MODE 0x28 | |
46 | #define A5PSW_VLAN_IN_MODE_PORT_SHIFT(port) ((port) * 2) | |
47 | #define A5PSW_VLAN_IN_MODE_PORT(port) (GENMASK(1, 0) << \ | |
48 | A5PSW_VLAN_IN_MODE_PORT_SHIFT(port)) | |
49 | #define A5PSW_VLAN_IN_MODE_SINGLE_PASSTHROUGH 0x0 | |
50 | #define A5PSW_VLAN_IN_MODE_SINGLE_REPLACE 0x1 | |
51 | #define A5PSW_VLAN_IN_MODE_TAG_ALWAYS 0x2 | |
52 | ||
53 | #define A5PSW_VLAN_OUT_MODE 0x2C | |
7b3f77c4 CL |
54 | #define A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port) ((port) * 2) |
55 | #define A5PSW_VLAN_OUT_MODE_PORT(port) (GENMASK(1, 0) << \ | |
56 | A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port)) | |
888cdb89 CL |
57 | #define A5PSW_VLAN_OUT_MODE_DIS 0x0 |
58 | #define A5PSW_VLAN_OUT_MODE_STRIP 0x1 | |
59 | #define A5PSW_VLAN_OUT_MODE_TAG_THROUGH 0x2 | |
60 | #define A5PSW_VLAN_OUT_MODE_TRANSPARENT 0x3 | |
61 | ||
62 | #define A5PSW_VLAN_IN_MODE_ENA 0x30 | |
63 | #define A5PSW_VLAN_TAG_ID 0x34 | |
64 | ||
7b3f77c4 | 65 | #define A5PSW_SYSTEM_TAGINFO(port) (0x200 + 4 * (port)) |
888cdb89 CL |
66 | |
67 | #define A5PSW_AUTH_PORT(port) (0x240 + 4 * (port)) | |
68 | #define A5PSW_AUTH_PORT_AUTHORIZED BIT(0) | |
69 | ||
70 | #define A5PSW_VLAN_RES(entry) (0x280 + 4 * (entry)) | |
71 | #define A5PSW_VLAN_RES_WR_PORTMASK BIT(30) | |
72 | #define A5PSW_VLAN_RES_WR_TAGMASK BIT(29) | |
73 | #define A5PSW_VLAN_RES_RD_TAGMASK BIT(28) | |
7b3f77c4 | 74 | #define A5PSW_VLAN_RES_VLANID GENMASK(16, 5) |
888cdb89 CL |
75 | #define A5PSW_VLAN_RES_PORTMASK GENMASK(4, 0) |
76 | ||
77 | #define A5PSW_RXMATCH_CONFIG(port) (0x3e80 + 4 * (port)) | |
78 | #define A5PSW_RXMATCH_CONFIG_PATTERN(p) BIT(p) | |
79 | ||
80 | #define A5PSW_PATTERN_CTRL(p) (0x3eb0 + 4 * (p)) | |
81 | #define A5PSW_PATTERN_CTRL_MGMTFWD BIT(1) | |
82 | ||
83 | #define A5PSW_LK_CTRL 0x400 | |
84 | #define A5PSW_LK_ADDR_CTRL_BLOCKING BIT(0) | |
85 | #define A5PSW_LK_ADDR_CTRL_LEARNING BIT(1) | |
86 | #define A5PSW_LK_ADDR_CTRL_AGEING BIT(2) | |
87 | #define A5PSW_LK_ADDR_CTRL_ALLOW_MIGR BIT(3) | |
88 | #define A5PSW_LK_ADDR_CTRL_CLEAR_TABLE BIT(6) | |
89 | ||
90 | #define A5PSW_LK_ADDR_CTRL 0x408 | |
91 | #define A5PSW_LK_ADDR_CTRL_BUSY BIT(31) | |
92 | #define A5PSW_LK_ADDR_CTRL_DELETE_PORT BIT(30) | |
93 | #define A5PSW_LK_ADDR_CTRL_CLEAR BIT(29) | |
94 | #define A5PSW_LK_ADDR_CTRL_LOOKUP BIT(28) | |
95 | #define A5PSW_LK_ADDR_CTRL_WAIT BIT(27) | |
96 | #define A5PSW_LK_ADDR_CTRL_READ BIT(26) | |
97 | #define A5PSW_LK_ADDR_CTRL_WRITE BIT(25) | |
98 | #define A5PSW_LK_ADDR_CTRL_ADDRESS GENMASK(12, 0) | |
99 | ||
100 | #define A5PSW_LK_DATA_LO 0x40C | |
101 | #define A5PSW_LK_DATA_HI 0x410 | |
102 | #define A5PSW_LK_DATA_HI_VALID BIT(16) | |
103 | #define A5PSW_LK_DATA_HI_PORT BIT(16) | |
104 | ||
105 | #define A5PSW_LK_LEARNCOUNT 0x418 | |
106 | #define A5PSW_LK_LEARNCOUNT_COUNT GENMASK(13, 0) | |
107 | #define A5PSW_LK_LEARNCOUNT_MODE GENMASK(31, 30) | |
108 | #define A5PSW_LK_LEARNCOUNT_MODE_SET 0x0 | |
109 | #define A5PSW_LK_LEARNCOUNT_MODE_INC 0x1 | |
110 | #define A5PSW_LK_LEARNCOUNT_MODE_DEC 0x2 | |
111 | ||
112 | #define A5PSW_MGMT_TAG_CFG 0x480 | |
113 | #define A5PSW_MGMT_TAG_CFG_TAGFIELD GENMASK(31, 16) | |
114 | #define A5PSW_MGMT_TAG_CFG_ALL_FRAMES BIT(1) | |
115 | #define A5PSW_MGMT_TAG_CFG_ENABLE BIT(0) | |
116 | ||
117 | #define A5PSW_LK_AGETIME 0x41C | |
118 | #define A5PSW_LK_AGETIME_MASK GENMASK(23, 0) | |
119 | ||
120 | #define A5PSW_MDIO_CFG_STATUS 0x700 | |
121 | #define A5PSW_MDIO_CFG_STATUS_CLKDIV GENMASK(15, 7) | |
122 | #define A5PSW_MDIO_CFG_STATUS_READERR BIT(1) | |
123 | #define A5PSW_MDIO_CFG_STATUS_BUSY BIT(0) | |
124 | ||
125 | #define A5PSW_MDIO_COMMAND 0x704 | |
126 | /* Register is named TRAININIT in datasheet and should be set when reading */ | |
127 | #define A5PSW_MDIO_COMMAND_READ BIT(15) | |
128 | #define A5PSW_MDIO_COMMAND_PHY_ADDR GENMASK(9, 5) | |
129 | #define A5PSW_MDIO_COMMAND_REG_ADDR GENMASK(4, 0) | |
130 | ||
131 | #define A5PSW_MDIO_DATA 0x708 | |
132 | #define A5PSW_MDIO_DATA_MASK GENMASK(15, 0) | |
133 | ||
134 | #define A5PSW_CMD_CFG(port) (0x808 + A5PSW_PORT_OFFSET(port)) | |
135 | #define A5PSW_CMD_CFG_CNTL_FRM_ENA BIT(23) | |
136 | #define A5PSW_CMD_CFG_SW_RESET BIT(13) | |
137 | #define A5PSW_CMD_CFG_TX_CRC_APPEND BIT(11) | |
138 | #define A5PSW_CMD_CFG_HD_ENA BIT(10) | |
139 | #define A5PSW_CMD_CFG_PAUSE_IGNORE BIT(8) | |
140 | #define A5PSW_CMD_CFG_CRC_FWD BIT(6) | |
141 | #define A5PSW_CMD_CFG_ETH_SPEED BIT(3) | |
142 | #define A5PSW_CMD_CFG_RX_ENA BIT(1) | |
143 | #define A5PSW_CMD_CFG_TX_ENA BIT(0) | |
144 | ||
145 | #define A5PSW_FRM_LENGTH(port) (0x814 + A5PSW_PORT_OFFSET(port)) | |
146 | #define A5PSW_FRM_LENGTH_MASK GENMASK(13, 0) | |
147 | ||
148 | #define A5PSW_STATUS(port) (0x840 + A5PSW_PORT_OFFSET(port)) | |
149 | ||
150 | #define A5PSW_STATS_HIWORD 0x900 | |
151 | ||
c7243fd4 CL |
152 | /* Stats */ |
153 | #define A5PSW_aFramesTransmittedOK 0x868 | |
154 | #define A5PSW_aFramesReceivedOK 0x86C | |
155 | #define A5PSW_aFrameCheckSequenceErrors 0x870 | |
156 | #define A5PSW_aAlignmentErrors 0x874 | |
157 | #define A5PSW_aOctetsTransmittedOK 0x878 | |
158 | #define A5PSW_aOctetsReceivedOK 0x87C | |
159 | #define A5PSW_aTxPAUSEMACCtrlFrames 0x880 | |
160 | #define A5PSW_aRxPAUSEMACCtrlFrames 0x884 | |
161 | /* If */ | |
162 | #define A5PSW_ifInErrors 0x888 | |
163 | #define A5PSW_ifOutErrors 0x88C | |
164 | #define A5PSW_ifInUcastPkts 0x890 | |
165 | #define A5PSW_ifInMulticastPkts 0x894 | |
166 | #define A5PSW_ifInBroadcastPkts 0x898 | |
167 | #define A5PSW_ifOutDiscards 0x89C | |
168 | #define A5PSW_ifOutUcastPkts 0x8A0 | |
169 | #define A5PSW_ifOutMulticastPkts 0x8A4 | |
170 | #define A5PSW_ifOutBroadcastPkts 0x8A8 | |
171 | /* Ether */ | |
172 | #define A5PSW_etherStatsDropEvents 0x8AC | |
173 | #define A5PSW_etherStatsOctets 0x8B0 | |
174 | #define A5PSW_etherStatsPkts 0x8B4 | |
175 | #define A5PSW_etherStatsUndersizePkts 0x8B8 | |
176 | #define A5PSW_etherStatsOversizePkts 0x8BC | |
177 | #define A5PSW_etherStatsPkts64Octets 0x8C0 | |
178 | #define A5PSW_etherStatsPkts65to127Octets 0x8C4 | |
179 | #define A5PSW_etherStatsPkts128to255Octets 0x8C8 | |
180 | #define A5PSW_etherStatsPkts256to511Octets 0x8CC | |
181 | #define A5PSW_etherStatsPkts512to1023Octets 0x8D0 | |
182 | #define A5PSW_etherStatsPkts1024to1518Octets 0x8D4 | |
183 | #define A5PSW_etherStatsPkts1519toXOctets 0x8D8 | |
184 | #define A5PSW_etherStatsJabbers 0x8DC | |
185 | #define A5PSW_etherStatsFragments 0x8E0 | |
186 | ||
187 | #define A5PSW_VLANReceived 0x8E8 | |
188 | #define A5PSW_VLANTransmitted 0x8EC | |
189 | ||
190 | #define A5PSW_aDeferred 0x910 | |
191 | #define A5PSW_aMultipleCollisions 0x914 | |
192 | #define A5PSW_aSingleCollisions 0x918 | |
193 | #define A5PSW_aLateCollisions 0x91C | |
194 | #define A5PSW_aExcessiveCollisions 0x920 | |
195 | #define A5PSW_aCarrierSenseErrors 0x924 | |
196 | ||
888cdb89 CL |
197 | #define A5PSW_VLAN_TAG(prio, id) (((prio) << 12) | (id)) |
198 | #define A5PSW_PORTS_NUM 5 | |
199 | #define A5PSW_CPU_PORT (A5PSW_PORTS_NUM - 1) | |
200 | #define A5PSW_MDIO_DEF_FREQ 2500000 | |
201 | #define A5PSW_MDIO_TIMEOUT 100 | |
202 | #define A5PSW_JUMBO_LEN (10 * SZ_1K) | |
203 | #define A5PSW_MDIO_CLK_DIV_MIN 5 | |
204 | #define A5PSW_TAG_LEN 8 | |
205 | #define A5PSW_VLAN_COUNT 32 | |
206 | ||
207 | /* Ensure enough space for 2 VLAN tags */ | |
208 | #define A5PSW_EXTRA_MTU_LEN (A5PSW_TAG_LEN + 8) | |
209 | #define A5PSW_MAX_MTU (A5PSW_JUMBO_LEN - A5PSW_EXTRA_MTU_LEN) | |
210 | ||
211 | #define A5PSW_PATTERN_MGMTFWD 0 | |
212 | ||
213 | #define A5PSW_LK_BUSY_USEC_POLL 10 | |
214 | #define A5PSW_CTRL_TIMEOUT 1000 | |
215 | #define A5PSW_TABLE_ENTRIES 8192 | |
216 | ||
5edf246c CL |
217 | struct fdb_entry { |
218 | u8 mac[ETH_ALEN]; | |
219 | u16 valid:1; | |
220 | u16 is_static:1; | |
221 | u16 prio:3; | |
222 | u16 port_mask:5; | |
223 | u16 reserved:6; | |
224 | } __packed; | |
225 | ||
226 | union lk_data { | |
227 | struct { | |
228 | u32 lo; | |
229 | u32 hi; | |
230 | }; | |
231 | struct fdb_entry entry; | |
232 | }; | |
233 | ||
888cdb89 CL |
234 | /** |
235 | * struct a5psw - switch struct | |
236 | * @base: Base address of the switch | |
237 | * @hclk: hclk_switch clock | |
238 | * @clk: clk_switch clock | |
239 | * @dev: Device associated to the switch | |
240 | * @mii_bus: MDIO bus struct | |
241 | * @mdio_freq: MDIO bus frequency requested | |
242 | * @pcs: Array of PCS connected to the switch ports (not for the CPU) | |
243 | * @ds: DSA switch struct | |
c7243fd4 | 244 | * @stats_lock: lock to access statistics (shared HI counter) |
888cdb89 CL |
245 | * @lk_lock: Lock for the lookup table |
246 | * @reg_lock: Lock for register read-modify-write operation | |
247 | * @bridged_ports: Mask of ports that are bridged and should be flooded | |
248 | * @br_dev: Bridge net device | |
249 | */ | |
250 | struct a5psw { | |
251 | void __iomem *base; | |
252 | struct clk *hclk; | |
253 | struct clk *clk; | |
254 | struct device *dev; | |
255 | struct mii_bus *mii_bus; | |
256 | struct phylink_pcs *pcs[A5PSW_PORTS_NUM - 1]; | |
257 | struct dsa_switch ds; | |
258 | struct mutex lk_lock; | |
259 | spinlock_t reg_lock; | |
260 | u32 bridged_ports; | |
261 | struct net_device *br_dev; | |
262 | }; |