xref: /linux/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c (revision 06103dccbbd29408255a409f6f98f7f02387dc93)
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