1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Texas Instruments ICSSG Ethernet Driver |
3 | * |
4 | * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ |
5 | * |
6 | */ |
7 | |
8 | #include <linux/etherdevice.h> |
9 | #include <linux/types.h> |
10 | #include <linux/regmap.h> |
11 | |
12 | #include "icssg_prueth.h" |
13 | |
14 | #define ICSSG_NUM_CLASSIFIERS 16 |
15 | #define ICSSG_NUM_FT1_SLOTS 8 |
16 | #define ICSSG_NUM_FT3_SLOTS 16 |
17 | |
18 | #define ICSSG_NUM_CLASSIFIERS_IN_USE 5 |
19 | |
20 | /* Filter 1 - FT1 */ |
21 | #define FT1_NUM_SLOTS 8 |
22 | #define FT1_SLOT_SIZE 0x10 /* bytes */ |
23 | |
24 | /* offsets from FT1 slot base i.e. slot 1 start */ |
25 | #define FT1_DA0 0x0 |
26 | #define FT1_DA1 0x4 |
27 | #define FT1_DA0_MASK 0x8 |
28 | #define FT1_DA1_MASK 0xc |
29 | |
30 | #define FT1_N_REG(slize, n, reg) \ |
31 | (offs[slice].ft1_slot_base + FT1_SLOT_SIZE * (n) + (reg)) |
32 | |
33 | #define FT1_LEN_MASK GENMASK(19, 16) |
34 | #define FT1_LEN_SHIFT 16 |
35 | #define FT1_LEN(len) (((len) << FT1_LEN_SHIFT) & FT1_LEN_MASK) |
36 | #define FT1_START_MASK GENMASK(14, 0) |
37 | #define FT1_START(start) ((start) & FT1_START_MASK) |
38 | #define FT1_MATCH_SLOT(n) (GENMASK(23, 16) & (BIT(n) << 16)) |
39 | |
40 | /* FT1 config type */ |
41 | enum ft1_cfg_type { |
42 | FT1_CFG_TYPE_DISABLED = 0, |
43 | FT1_CFG_TYPE_EQ, |
44 | FT1_CFG_TYPE_GT, |
45 | FT1_CFG_TYPE_LT, |
46 | }; |
47 | |
48 | #define FT1_CFG_SHIFT(n) (2 * (n)) |
49 | #define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) |
50 | |
51 | /* Filter 3 - FT3 */ |
52 | #define FT3_NUM_SLOTS 16 |
53 | #define FT3_SLOT_SIZE 0x20 /* bytes */ |
54 | |
55 | /* offsets from FT3 slot n's base */ |
56 | #define FT3_START 0 |
57 | #define FT3_START_AUTO 0x4 |
58 | #define FT3_START_OFFSET 0x8 |
59 | #define FT3_JUMP_OFFSET 0xc |
60 | #define FT3_LEN 0x10 |
61 | #define FT3_CFG 0x14 |
62 | #define FT3_T 0x18 |
63 | #define FT3_T_MASK 0x1c |
64 | |
65 | #define FT3_N_REG(slize, n, reg) \ |
66 | (offs[slice].ft3_slot_base + FT3_SLOT_SIZE * (n) + (reg)) |
67 | |
68 | /* offsets from rx_class n's base */ |
69 | #define RX_CLASS_AND_EN 0 |
70 | #define RX_CLASS_OR_EN 0x4 |
71 | #define RX_CLASS_NUM_SLOTS 16 |
72 | #define RX_CLASS_EN_SIZE 0x8 /* bytes */ |
73 | |
74 | #define RX_CLASS_N_REG(slice, n, reg) \ |
75 | (offs[slice].rx_class_base + RX_CLASS_EN_SIZE * (n) + (reg)) |
76 | |
77 | /* RX Class Gates */ |
78 | #define RX_CLASS_GATES_SIZE 0x4 /* bytes */ |
79 | |
80 | #define RX_CLASS_GATES_N_REG(slice, n) \ |
81 | (offs[slice].rx_class_gates_base + RX_CLASS_GATES_SIZE * (n)) |
82 | |
83 | #define RX_CLASS_GATES_ALLOW_MASK BIT(6) |
84 | #define RX_CLASS_GATES_RAW_MASK BIT(5) |
85 | #define RX_CLASS_GATES_PHASE_MASK BIT(4) |
86 | |
87 | /* RX Class traffic data matching bits */ |
88 | #define RX_CLASS_FT_UC BIT(31) |
89 | #define RX_CLASS_FT_MC BIT(30) |
90 | #define RX_CLASS_FT_BC BIT(29) |
91 | #define RX_CLASS_FT_FW BIT(28) |
92 | #define RX_CLASS_FT_RCV BIT(27) |
93 | #define RX_CLASS_FT_VLAN BIT(26) |
94 | #define RX_CLASS_FT_DA_P BIT(25) |
95 | #define RX_CLASS_FT_DA_I BIT(24) |
96 | #define RX_CLASS_FT_FT1_MATCH_MASK GENMASK(23, 16) |
97 | #define RX_CLASS_FT_FT1_MATCH_SHIFT 16 |
98 | #define RX_CLASS_FT_FT3_MATCH_MASK GENMASK(15, 0) |
99 | #define RX_CLASS_FT_FT3_MATCH_SHIFT 0 |
100 | |
101 | #define RX_CLASS_FT_FT1_MATCH(slot) \ |
102 | ((BIT(slot) << RX_CLASS_FT_FT1_MATCH_SHIFT) & \ |
103 | RX_CLASS_FT_FT1_MATCH_MASK) |
104 | |
105 | /* RX class type */ |
106 | enum rx_class_sel_type { |
107 | RX_CLASS_SEL_TYPE_OR = 0, |
108 | RX_CLASS_SEL_TYPE_AND = 1, |
109 | RX_CLASS_SEL_TYPE_OR_AND_AND = 2, |
110 | RX_CLASS_SEL_TYPE_OR_OR_AND = 3, |
111 | }; |
112 | |
113 | #define FT1_CFG_SHIFT(n) (2 * (n)) |
114 | #define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) |
115 | |
116 | #define RX_CLASS_SEL_SHIFT(n) (2 * (n)) |
117 | #define RX_CLASS_SEL_MASK(n) (0x3 << RX_CLASS_SEL_SHIFT((n))) |
118 | |
119 | #define ICSSG_CFG_OFFSET 0 |
120 | #define MAC_INTERFACE_0 0x18 |
121 | #define MAC_INTERFACE_1 0x1c |
122 | |
123 | #define ICSSG_CFG_RX_L2_G_EN BIT(2) |
124 | |
125 | /* These are register offsets per PRU */ |
126 | struct miig_rt_offsets { |
127 | u32 mac0; |
128 | u32 mac1; |
129 | u32 ft1_start_len; |
130 | u32 ft1_cfg; |
131 | u32 ft1_slot_base; |
132 | u32 ft3_slot_base; |
133 | u32 ft3_p_base; |
134 | u32 ft_rx_ptr; |
135 | u32 rx_class_base; |
136 | u32 rx_class_cfg1; |
137 | u32 rx_class_cfg2; |
138 | u32 rx_class_gates_base; |
139 | u32 rx_green; |
140 | u32 rx_rate_cfg_base; |
141 | u32 rx_rate_src_sel0; |
142 | u32 rx_rate_src_sel1; |
143 | u32 tx_rate_cfg_base; |
144 | u32 stat_base; |
145 | u32 tx_hsr_tag; |
146 | u32 tx_hsr_seq; |
147 | u32 tx_vlan_type; |
148 | u32 tx_vlan_ins; |
149 | }; |
150 | |
151 | /* These are the offset values for miig_rt_offsets registers */ |
152 | static const struct miig_rt_offsets offs[] = { |
153 | /* PRU0 */ |
154 | { |
155 | 0x8, |
156 | 0xc, |
157 | 0x80, |
158 | 0x84, |
159 | 0x88, |
160 | 0x108, |
161 | 0x308, |
162 | 0x408, |
163 | 0x40c, |
164 | 0x48c, |
165 | 0x490, |
166 | 0x494, |
167 | 0x4d4, |
168 | 0x4e4, |
169 | 0x504, |
170 | 0x508, |
171 | 0x50c, |
172 | 0x54c, |
173 | 0x63c, |
174 | 0x640, |
175 | 0x644, |
176 | 0x648, |
177 | }, |
178 | /* PRU1 */ |
179 | { |
180 | 0x10, |
181 | 0x14, |
182 | 0x64c, |
183 | 0x650, |
184 | 0x654, |
185 | 0x6d4, |
186 | 0x8d4, |
187 | 0x9d4, |
188 | 0x9d8, |
189 | 0xa58, |
190 | 0xa5c, |
191 | 0xa60, |
192 | 0xaa0, |
193 | 0xab0, |
194 | 0xad0, |
195 | 0xad4, |
196 | 0xad8, |
197 | 0xb18, |
198 | 0xc08, |
199 | 0xc0c, |
200 | 0xc10, |
201 | 0xc14, |
202 | }, |
203 | }; |
204 | |
205 | static void rx_class_ft1_set_start_len(struct regmap *miig_rt, int slice, |
206 | u16 start, u8 len) |
207 | { |
208 | u32 offset, val; |
209 | |
210 | offset = offs[slice].ft1_start_len; |
211 | val = FT1_LEN(len) | FT1_START(start); |
212 | regmap_write(map: miig_rt, reg: offset, val); |
213 | } |
214 | |
215 | static void rx_class_ft1_set_da(struct regmap *miig_rt, int slice, |
216 | int n, const u8 *addr) |
217 | { |
218 | u32 offset; |
219 | |
220 | offset = FT1_N_REG(slice, n, FT1_DA0); |
221 | regmap_write(map: miig_rt, reg: offset, val: (u32)(addr[0] | addr[1] << 8 | |
222 | addr[2] << 16 | addr[3] << 24)); |
223 | offset = FT1_N_REG(slice, n, FT1_DA1); |
224 | regmap_write(map: miig_rt, reg: offset, val: (u32)(addr[4] | addr[5] << 8)); |
225 | } |
226 | |
227 | static void rx_class_ft1_set_da_mask(struct regmap *miig_rt, int slice, |
228 | int n, const u8 *addr) |
229 | { |
230 | u32 offset; |
231 | |
232 | offset = FT1_N_REG(slice, n, FT1_DA0_MASK); |
233 | regmap_write(map: miig_rt, reg: offset, val: (u32)(addr[0] | addr[1] << 8 | |
234 | addr[2] << 16 | addr[3] << 24)); |
235 | offset = FT1_N_REG(slice, n, FT1_DA1_MASK); |
236 | regmap_write(map: miig_rt, reg: offset, val: (u32)(addr[4] | addr[5] << 8)); |
237 | } |
238 | |
239 | static void rx_class_ft1_cfg_set_type(struct regmap *miig_rt, int slice, int n, |
240 | enum ft1_cfg_type type) |
241 | { |
242 | u32 offset; |
243 | |
244 | offset = offs[slice].ft1_cfg; |
245 | regmap_update_bits(map: miig_rt, reg: offset, FT1_CFG_MASK(n), |
246 | val: type << FT1_CFG_SHIFT(n)); |
247 | } |
248 | |
249 | static void rx_class_sel_set_type(struct regmap *miig_rt, int slice, int n, |
250 | enum rx_class_sel_type type) |
251 | { |
252 | u32 offset; |
253 | |
254 | offset = offs[slice].rx_class_cfg1; |
255 | regmap_update_bits(map: miig_rt, reg: offset, RX_CLASS_SEL_MASK(n), |
256 | val: type << RX_CLASS_SEL_SHIFT(n)); |
257 | } |
258 | |
259 | static void rx_class_set_and(struct regmap *miig_rt, int slice, int n, |
260 | u32 data) |
261 | { |
262 | u32 offset; |
263 | |
264 | offset = RX_CLASS_N_REG(slice, n, RX_CLASS_AND_EN); |
265 | regmap_write(map: miig_rt, reg: offset, val: data); |
266 | } |
267 | |
268 | static void rx_class_set_or(struct regmap *miig_rt, int slice, int n, |
269 | u32 data) |
270 | { |
271 | u32 offset; |
272 | |
273 | offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN); |
274 | regmap_write(map: miig_rt, reg: offset, val: data); |
275 | } |
276 | |
277 | void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac) |
278 | { |
279 | regmap_write(map: miig_rt, MAC_INTERFACE_0, val: (u32)(mac[0] | mac[1] << 8 | |
280 | mac[2] << 16 | mac[3] << 24)); |
281 | regmap_write(map: miig_rt, MAC_INTERFACE_1, val: (u32)(mac[4] | mac[5] << 8)); |
282 | } |
283 | |
284 | void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac) |
285 | { |
286 | regmap_write(map: miig_rt, reg: offs[slice].mac0, val: (u32)(mac[0] | mac[1] << 8 | |
287 | mac[2] << 16 | mac[3] << 24)); |
288 | regmap_write(map: miig_rt, reg: offs[slice].mac1, val: (u32)(mac[4] | mac[5] << 8)); |
289 | } |
290 | |
291 | /* disable all RX traffic */ |
292 | void icssg_class_disable(struct regmap *miig_rt, int slice) |
293 | { |
294 | u32 data, offset; |
295 | int n; |
296 | |
297 | /* Enable RX_L2_G */ |
298 | regmap_update_bits(map: miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_RX_L2_G_EN, |
299 | ICSSG_CFG_RX_L2_G_EN); |
300 | |
301 | for (n = 0; n < ICSSG_NUM_CLASSIFIERS; n++) { |
302 | /* AND_EN = 0 */ |
303 | rx_class_set_and(miig_rt, slice, n, data: 0); |
304 | /* OR_EN = 0 */ |
305 | rx_class_set_or(miig_rt, slice, n, data: 0); |
306 | |
307 | /* set CFG1 to OR */ |
308 | rx_class_sel_set_type(miig_rt, slice, n, type: RX_CLASS_SEL_TYPE_OR); |
309 | |
310 | /* configure gate */ |
311 | offset = RX_CLASS_GATES_N_REG(slice, n); |
312 | regmap_read(map: miig_rt, reg: offset, val: &data); |
313 | /* clear class_raw so we go through filters */ |
314 | data &= ~RX_CLASS_GATES_RAW_MASK; |
315 | /* set allow and phase mask */ |
316 | data |= RX_CLASS_GATES_ALLOW_MASK | RX_CLASS_GATES_PHASE_MASK; |
317 | regmap_write(map: miig_rt, reg: offset, val: data); |
318 | } |
319 | |
320 | /* FT1 Disabled */ |
321 | for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) { |
322 | const u8 addr[] = { 0, 0, 0, 0, 0, 0, }; |
323 | |
324 | rx_class_ft1_cfg_set_type(miig_rt, slice, n, |
325 | type: FT1_CFG_TYPE_DISABLED); |
326 | rx_class_ft1_set_da(miig_rt, slice, n, addr); |
327 | rx_class_ft1_set_da_mask(miig_rt, slice, n, addr); |
328 | } |
329 | |
330 | /* clear CFG2 */ |
331 | regmap_write(map: miig_rt, reg: offs[slice].rx_class_cfg2, val: 0); |
332 | } |
333 | |
334 | void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti) |
335 | { |
336 | u32 data; |
337 | |
338 | /* defaults */ |
339 | icssg_class_disable(miig_rt, slice); |
340 | |
341 | /* Setup Classifier */ |
342 | /* match on Broadcast or MAC_PRU address */ |
343 | data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P; |
344 | |
345 | /* multicast */ |
346 | if (allmulti) |
347 | data |= RX_CLASS_FT_MC; |
348 | |
349 | rx_class_set_or(miig_rt, slice, n: 0, data); |
350 | |
351 | /* set CFG1 for OR_OR_AND for classifier */ |
352 | rx_class_sel_set_type(miig_rt, slice, n: 0, type: RX_CLASS_SEL_TYPE_OR_OR_AND); |
353 | |
354 | /* clear CFG2 */ |
355 | regmap_write(map: miig_rt, reg: offs[slice].rx_class_cfg2, val: 0); |
356 | } |
357 | |
358 | /* required for SAV check */ |
359 | void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr) |
360 | { |
361 | const u8 mask_addr[] = { 0, 0, 0, 0, 0, 0, }; |
362 | |
363 | rx_class_ft1_set_start_len(miig_rt, slice, start: 0, len: 6); |
364 | rx_class_ft1_set_da(miig_rt, slice, n: 0, addr: mac_addr); |
365 | rx_class_ft1_set_da_mask(miig_rt, slice, n: 0, addr: mask_addr); |
366 | rx_class_ft1_cfg_set_type(miig_rt, slice, n: 0, type: FT1_CFG_TYPE_EQ); |
367 | } |
368 | |