1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip lan969x Switch driver
3 *
4 * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
5 */
6
7 #include "lan969x.h"
8
9 #define LAN969X_SDLB_GRP_CNT 5
10 #define LAN969X_HSCH_LEAK_GRP_CNT 4
11
12 static const struct sparx5_main_io_resource lan969x_main_iomap[] = {
13 { TARGET_CPU, 0xc0000, 0 }, /* 0xe00c0000 */
14 { TARGET_FDMA, 0xc0400, 0 }, /* 0xe00c0400 */
15 { TARGET_GCB, 0x2010000, 1 }, /* 0xe2010000 */
16 { TARGET_QS, 0x2030000, 1 }, /* 0xe2030000 */
17 { TARGET_PTP, 0x2040000, 1 }, /* 0xe2040000 */
18 { TARGET_ANA_ACL, 0x2050000, 1 }, /* 0xe2050000 */
19 { TARGET_LRN, 0x2060000, 1 }, /* 0xe2060000 */
20 { TARGET_VCAP_SUPER, 0x2080000, 1 }, /* 0xe2080000 */
21 { TARGET_QSYS, 0x20a0000, 1 }, /* 0xe20a0000 */
22 { TARGET_QFWD, 0x20b0000, 1 }, /* 0xe20b0000 */
23 { TARGET_XQS, 0x20c0000, 1 }, /* 0xe20c0000 */
24 { TARGET_VCAP_ES2, 0x20d0000, 1 }, /* 0xe20d0000 */
25 { TARGET_VCAP_ES0, 0x20e0000, 1 }, /* 0xe20e0000 */
26 { TARGET_ANA_AC_POL, 0x2200000, 1 }, /* 0xe2200000 */
27 { TARGET_QRES, 0x2280000, 1 }, /* 0xe2280000 */
28 { TARGET_EACL, 0x22c0000, 1 }, /* 0xe22c0000 */
29 { TARGET_ANA_CL, 0x2400000, 1 }, /* 0xe2400000 */
30 { TARGET_ANA_L3, 0x2480000, 1 }, /* 0xe2480000 */
31 { TARGET_ANA_AC_SDLB, 0x2500000, 1 }, /* 0xe2500000 */
32 { TARGET_HSCH, 0x2580000, 1 }, /* 0xe2580000 */
33 { TARGET_REW, 0x2600000, 1 }, /* 0xe2600000 */
34 { TARGET_ANA_L2, 0x2800000, 1 }, /* 0xe2800000 */
35 { TARGET_ANA_AC, 0x2900000, 1 }, /* 0xe2900000 */
36 { TARGET_VOP, 0x2a00000, 1 }, /* 0xe2a00000 */
37 { TARGET_DEV2G5, 0x3004000, 1 }, /* 0xe3004000 */
38 { TARGET_DEV10G, 0x3008000, 1 }, /* 0xe3008000 */
39 { TARGET_PCS10G_BR, 0x300c000, 1 }, /* 0xe300c000 */
40 { TARGET_DEV2G5 + 1, 0x3010000, 1 }, /* 0xe3010000 */
41 { TARGET_DEV2G5 + 2, 0x3014000, 1 }, /* 0xe3014000 */
42 { TARGET_DEV2G5 + 3, 0x3018000, 1 }, /* 0xe3018000 */
43 { TARGET_DEV2G5 + 4, 0x301c000, 1 }, /* 0xe301c000 */
44 { TARGET_DEV10G + 1, 0x3020000, 1 }, /* 0xe3020000 */
45 { TARGET_PCS10G_BR + 1, 0x3024000, 1 }, /* 0xe3024000 */
46 { TARGET_DEV2G5 + 5, 0x3028000, 1 }, /* 0xe3028000 */
47 { TARGET_DEV2G5 + 6, 0x302c000, 1 }, /* 0xe302c000 */
48 { TARGET_DEV2G5 + 7, 0x3030000, 1 }, /* 0xe3030000 */
49 { TARGET_DEV2G5 + 8, 0x3034000, 1 }, /* 0xe3034000 */
50 { TARGET_DEV10G + 2, 0x3038000, 1 }, /* 0xe3038000 */
51 { TARGET_PCS10G_BR + 2, 0x303c000, 1 }, /* 0xe303c000 */
52 { TARGET_DEV2G5 + 9, 0x3040000, 1 }, /* 0xe3040000 */
53 { TARGET_DEV5G, 0x3044000, 1 }, /* 0xe3044000 */
54 { TARGET_PCS5G_BR, 0x3048000, 1 }, /* 0xe3048000 */
55 { TARGET_DEV2G5 + 10, 0x304c000, 1 }, /* 0xe304c000 */
56 { TARGET_DEV2G5 + 11, 0x3050000, 1 }, /* 0xe3050000 */
57 { TARGET_DEV2G5 + 12, 0x3054000, 1 }, /* 0xe3054000 */
58 { TARGET_DEV10G + 3, 0x3058000, 1 }, /* 0xe3058000 */
59 { TARGET_PCS10G_BR + 3, 0x305c000, 1 }, /* 0xe305c000 */
60 { TARGET_DEV2G5 + 13, 0x3060000, 1 }, /* 0xe3060000 */
61 { TARGET_DEV5G + 1, 0x3064000, 1 }, /* 0xe3064000 */
62 { TARGET_PCS5G_BR + 1, 0x3068000, 1 }, /* 0xe3068000 */
63 { TARGET_DEV2G5 + 14, 0x306c000, 1 }, /* 0xe306c000 */
64 { TARGET_DEV2G5 + 15, 0x3070000, 1 }, /* 0xe3070000 */
65 { TARGET_DEV2G5 + 16, 0x3074000, 1 }, /* 0xe3074000 */
66 { TARGET_DEV10G + 4, 0x3078000, 1 }, /* 0xe3078000 */
67 { TARGET_PCS10G_BR + 4, 0x307c000, 1 }, /* 0xe307c000 */
68 { TARGET_DEV2G5 + 17, 0x3080000, 1 }, /* 0xe3080000 */
69 { TARGET_DEV5G + 2, 0x3084000, 1 }, /* 0xe3084000 */
70 { TARGET_PCS5G_BR + 2, 0x3088000, 1 }, /* 0xe3088000 */
71 { TARGET_DEV2G5 + 18, 0x308c000, 1 }, /* 0xe308c000 */
72 { TARGET_DEV2G5 + 19, 0x3090000, 1 }, /* 0xe3090000 */
73 { TARGET_DEV2G5 + 20, 0x3094000, 1 }, /* 0xe3094000 */
74 { TARGET_DEV10G + 5, 0x3098000, 1 }, /* 0xe3098000 */
75 { TARGET_PCS10G_BR + 5, 0x309c000, 1 }, /* 0xe309c000 */
76 { TARGET_DEV2G5 + 21, 0x30a0000, 1 }, /* 0xe30a0000 */
77 { TARGET_DEV5G + 3, 0x30a4000, 1 }, /* 0xe30a4000 */
78 { TARGET_PCS5G_BR + 3, 0x30a8000, 1 }, /* 0xe30a8000 */
79 { TARGET_DEV2G5 + 22, 0x30ac000, 1 }, /* 0xe30ac000 */
80 { TARGET_DEV2G5 + 23, 0x30b0000, 1 }, /* 0xe30b0000 */
81 { TARGET_DEV2G5 + 24, 0x30b4000, 1 }, /* 0xe30b4000 */
82 { TARGET_DEV10G + 6, 0x30b8000, 1 }, /* 0xe30b8000 */
83 { TARGET_PCS10G_BR + 6, 0x30bc000, 1 }, /* 0xe30bc000 */
84 { TARGET_DEV2G5 + 25, 0x30c0000, 1 }, /* 0xe30c0000 */
85 { TARGET_DEV10G + 7, 0x30c4000, 1 }, /* 0xe30c4000 */
86 { TARGET_PCS10G_BR + 7, 0x30c8000, 1 }, /* 0xe30c8000 */
87 { TARGET_DEV2G5 + 26, 0x30cc000, 1 }, /* 0xe30cc000 */
88 { TARGET_DEV10G + 8, 0x30d0000, 1 }, /* 0xe30d0000 */
89 { TARGET_PCS10G_BR + 8, 0x30d4000, 1 }, /* 0xe30d4000 */
90 { TARGET_DEV2G5 + 27, 0x30d8000, 1 }, /* 0xe30d8000 */
91 { TARGET_DEV10G + 9, 0x30dc000, 1 }, /* 0xe30dc000 */
92 { TARGET_PCS10G_BR + 9, 0x30e0000, 1 }, /* 0xe30e0000 */
93 { TARGET_DEVRGMII, 0x30e4000, 1 }, /* 0xe30e4000 */
94 { TARGET_DEVRGMII + 1, 0x30e8000, 1 }, /* 0xe30e8000 */
95 { TARGET_DSM, 0x30ec000, 1 }, /* 0xe30ec000 */
96 { TARGET_PORT_CONF, 0x30f0000, 1 }, /* 0xe30f0000 */
97 { TARGET_ASM, 0x3200000, 1 }, /* 0xe3200000 */
98 { TARGET_HSIO_WRAP, 0x3408000, 1 }, /* 0xe3408000 */
99 };
100
101 static struct sparx5_sdlb_group lan969x_sdlb_groups[LAN969X_SDLB_GRP_CNT] = {
102 { 1000000000, 8192 / 2, 64 }, /* 1 G */
103 { 500000000, 8192 / 2, 64 }, /* 500 M */
104 { 100000000, 8192 / 4, 64 }, /* 100 M */
105 { 50000000, 8192 / 4, 64 }, /* 50 M */
106 { 5000000, 8192 / 8, 64 }, /* 10 M */
107 };
108
109 static u32 lan969x_hsch_max_group_rate[LAN969X_HSCH_LEAK_GRP_CNT] = {
110 655355, 1048568, 6553550, 10485680
111 };
112
lan969x_get_sdlb_group(int idx)113 static struct sparx5_sdlb_group *lan969x_get_sdlb_group(int idx)
114 {
115 return &lan969x_sdlb_groups[idx];
116 }
117
lan969x_get_hsch_max_group_rate(int grp)118 static u32 lan969x_get_hsch_max_group_rate(int grp)
119 {
120 return lan969x_hsch_max_group_rate[grp];
121 }
122
lan969x_get_dev_mode_bit(struct sparx5 * sparx5,int port)123 static u32 lan969x_get_dev_mode_bit(struct sparx5 *sparx5, int port)
124 {
125 if (lan969x_port_is_2g5(port) || lan969x_port_is_5g(port))
126 return port;
127
128 /* 10G */
129 switch (port) {
130 case 0:
131 return 12;
132 case 4:
133 return 13;
134 case 8:
135 return 14;
136 case 12:
137 return 0;
138 default:
139 return port;
140 }
141 }
142
lan969x_port_dev_mapping(struct sparx5 * sparx5,int port)143 static u32 lan969x_port_dev_mapping(struct sparx5 *sparx5, int port)
144 {
145 if (lan969x_port_is_5g(port)) {
146 switch (port) {
147 case 9:
148 return 0;
149 case 13:
150 return 1;
151 case 17:
152 return 2;
153 case 21:
154 return 3;
155 }
156 }
157
158 if (lan969x_port_is_10g(port)) {
159 switch (port) {
160 case 0:
161 return 0;
162 case 4:
163 return 1;
164 case 8:
165 return 2;
166 case 12:
167 return 3;
168 case 16:
169 return 4;
170 case 20:
171 return 5;
172 case 24:
173 return 6;
174 case 25:
175 return 7;
176 case 26:
177 return 8;
178 case 27:
179 return 9;
180 }
181 }
182
183 /* 2g5 port */
184 return port;
185 }
186
lan969x_port_mux_set(struct sparx5 * sparx5,struct sparx5_port * port,struct sparx5_port_config * conf)187 static int lan969x_port_mux_set(struct sparx5 *sparx5, struct sparx5_port *port,
188 struct sparx5_port_config *conf)
189 {
190 u32 portno = port->portno;
191 u32 inst;
192
193 if (port->conf.portmode == conf->portmode)
194 return 0; /* Nothing to do */
195
196 switch (conf->portmode) {
197 case PHY_INTERFACE_MODE_QSGMII: /* QSGMII: 4x2G5 devices. Mode Q' */
198 inst = (portno - portno % 4) / 4;
199 spx5_rmw(BIT(inst), BIT(inst), sparx5, PORT_CONF_QSGMII_ENA);
200 break;
201 default:
202 break;
203 }
204 return 0;
205 }
206
lan969x_ptp_irq_handler(int irq,void * args)207 static irqreturn_t lan969x_ptp_irq_handler(int irq, void *args)
208 {
209 int budget = SPARX5_MAX_PTP_ID;
210 struct sparx5 *sparx5 = args;
211
212 while (budget--) {
213 struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
214 struct skb_shared_hwtstamps shhwtstamps;
215 struct sparx5_port *port;
216 struct timespec64 ts;
217 unsigned long flags;
218 u32 val, id, txport;
219 u32 delay;
220
221 val = spx5_rd(sparx5, PTP_TWOSTEP_CTRL);
222
223 /* Check if a timestamp can be retrieved */
224 if (!(val & PTP_TWOSTEP_CTRL_PTP_VLD))
225 break;
226
227 WARN_ON(val & PTP_TWOSTEP_CTRL_PTP_OVFL);
228
229 if (!(val & PTP_TWOSTEP_CTRL_STAMP_TX))
230 continue;
231
232 /* Retrieve the ts Tx port */
233 txport = PTP_TWOSTEP_CTRL_STAMP_PORT_GET(val);
234
235 /* Retrieve its associated skb */
236 port = sparx5->ports[txport];
237
238 /* Retrieve the delay */
239 delay = spx5_rd(sparx5, PTP_TWOSTEP_STAMP_NSEC);
240 delay = PTP_TWOSTEP_STAMP_NSEC_NS_GET(delay);
241
242 /* Get next timestamp from fifo, which needs to be the
243 * rx timestamp which represents the id of the frame
244 */
245 spx5_rmw(PTP_TWOSTEP_CTRL_PTP_NXT_SET(1),
246 PTP_TWOSTEP_CTRL_PTP_NXT,
247 sparx5, PTP_TWOSTEP_CTRL);
248
249 val = spx5_rd(sparx5, PTP_TWOSTEP_CTRL);
250
251 /* Check if a timestamp can be retrieved */
252 if (!(val & PTP_TWOSTEP_CTRL_PTP_VLD))
253 break;
254
255 /* Read RX timestamping to get the ID */
256 id = spx5_rd(sparx5, PTP_TWOSTEP_STAMP_NSEC);
257 id <<= 8;
258 id |= spx5_rd(sparx5, PTP_TWOSTEP_STAMP_SUBNS);
259
260 spin_lock_irqsave(&port->tx_skbs.lock, flags);
261 skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
262 if (SPARX5_SKB_CB(skb)->ts_id != id)
263 continue;
264
265 __skb_unlink(skb, &port->tx_skbs);
266 skb_match = skb;
267 break;
268 }
269 spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
270
271 /* Next ts */
272 spx5_rmw(PTP_TWOSTEP_CTRL_PTP_NXT_SET(1),
273 PTP_TWOSTEP_CTRL_PTP_NXT,
274 sparx5, PTP_TWOSTEP_CTRL);
275
276 if (WARN_ON(!skb_match))
277 continue;
278
279 spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags);
280 sparx5->ptp_skbs--;
281 spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
282
283 /* Get the h/w timestamp */
284 sparx5_get_hwtimestamp(sparx5, &ts, delay);
285
286 /* Set the timestamp in the skb */
287 shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
288 skb_tstamp_tx(skb_match, &shhwtstamps);
289
290 dev_kfree_skb_any(skb_match);
291 }
292
293 return IRQ_HANDLED;
294 }
295
296 static const struct sparx5_regs lan969x_regs = {
297 .tsize = lan969x_tsize,
298 .gaddr = lan969x_gaddr,
299 .gcnt = lan969x_gcnt,
300 .gsize = lan969x_gsize,
301 .raddr = lan969x_raddr,
302 .rcnt = lan969x_rcnt,
303 .fpos = lan969x_fpos,
304 .fsize = lan969x_fsize,
305 };
306
307 static const struct sparx5_consts lan969x_consts = {
308 .n_ports = 30,
309 .n_ports_all = 35,
310 .n_hsch_l1_elems = 32,
311 .n_hsch_queues = 4,
312 .n_lb_groups = 5,
313 .n_pgids = 1054, /* (1024 + n_ports) */
314 .n_sio_clks = 1,
315 .n_own_upsids = 1,
316 .n_auto_cals = 4,
317 .n_filters = 256,
318 .n_gates = 256,
319 .n_sdlbs = 496,
320 .n_dsm_cal_taxis = 5,
321 .buf_size = 1572864,
322 .qres_max_prio_idx = 315,
323 .qres_max_colour_idx = 323,
324 .tod_pin = 4,
325 .vcaps = lan969x_vcaps,
326 .vcap_stats = &lan969x_vcap_stats,
327 .vcaps_cfg = lan969x_vcap_inst_cfg,
328 };
329
330 static const struct sparx5_ops lan969x_ops = {
331 .is_port_2g5 = &lan969x_port_is_2g5,
332 .is_port_5g = &lan969x_port_is_5g,
333 .is_port_10g = &lan969x_port_is_10g,
334 .is_port_25g = &lan969x_port_is_25g,
335 .is_port_rgmii = &lan969x_port_is_rgmii,
336 .get_port_dev_index = &lan969x_port_dev_mapping,
337 .get_port_dev_bit = &lan969x_get_dev_mode_bit,
338 .get_hsch_max_group_rate = &lan969x_get_hsch_max_group_rate,
339 .get_sdlb_group = &lan969x_get_sdlb_group,
340 .set_port_mux = &lan969x_port_mux_set,
341 .ptp_irq_handler = &lan969x_ptp_irq_handler,
342 .dsm_calendar_calc = &lan969x_dsm_calendar_calc,
343 .port_config_rgmii = &lan969x_port_config_rgmii,
344 .fdma_init = &lan969x_fdma_init,
345 .fdma_deinit = &lan969x_fdma_deinit,
346 .fdma_poll = &lan969x_fdma_napi_poll,
347 .fdma_xmit = &lan969x_fdma_xmit,
348 };
349
350 const struct sparx5_match_data lan969x_desc = {
351 .iomap = lan969x_main_iomap,
352 .iomap_size = ARRAY_SIZE(lan969x_main_iomap),
353 .ioranges = 2,
354 .regs = &lan969x_regs,
355 .consts = &lan969x_consts,
356 .ops = &lan969x_ops,
357 };
358