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 113 static struct sparx5_sdlb_group *lan969x_get_sdlb_group(int idx) 114 { 115 return &lan969x_sdlb_groups[idx]; 116 } 117 118 static u32 lan969x_get_hsch_max_group_rate(int grp) 119 { 120 return lan969x_hsch_max_group_rate[grp]; 121 } 122 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 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 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 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 }; 345 346 const struct sparx5_match_data lan969x_desc = { 347 .iomap = lan969x_main_iomap, 348 .iomap_size = ARRAY_SIZE(lan969x_main_iomap), 349 .ioranges = 2, 350 .regs = &lan969x_regs, 351 .consts = &lan969x_consts, 352 .ops = &lan969x_ops, 353 }; 354