0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/device.h>
0011 #include <linux/netdevice.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/of.h>
0015 #include <linux/of_net.h>
0016 #include <linux/of_mdio.h>
0017 #include <net/switchdev.h>
0018 #include <linux/etherdevice.h>
0019 #include <linux/io.h>
0020 #include <linux/printk.h>
0021 #include <linux/iopoll.h>
0022 #include <linux/mfd/syscon.h>
0023 #include <linux/regmap.h>
0024 #include <linux/types.h>
0025 #include <linux/reset.h>
0026
0027 #include "sparx5_main_regs.h"
0028 #include "sparx5_main.h"
0029 #include "sparx5_port.h"
0030
0031 #define QLIM_WM(fraction) \
0032 ((SPX5_BUFFER_MEMORY / SPX5_BUFFER_CELL_SZ - 100) * (fraction) / 100)
0033 #define IO_RANGES 3
0034
0035 struct initial_port_config {
0036 u32 portno;
0037 struct device_node *node;
0038 struct sparx5_port_config conf;
0039 struct phy *serdes;
0040 };
0041
0042 struct sparx5_ram_config {
0043 void __iomem *init_reg;
0044 u32 init_val;
0045 };
0046
0047 struct sparx5_main_io_resource {
0048 enum sparx5_target id;
0049 phys_addr_t offset;
0050 int range;
0051 };
0052
0053 static const struct sparx5_main_io_resource sparx5_main_iomap[] = {
0054 { TARGET_CPU, 0, 0 },
0055 { TARGET_FDMA, 0x80000, 0 },
0056 { TARGET_PCEP, 0x400000, 0 },
0057 { TARGET_DEV2G5, 0x10004000, 1 },
0058 { TARGET_DEV5G, 0x10008000, 1 },
0059 { TARGET_PCS5G_BR, 0x1000c000, 1 },
0060 { TARGET_DEV2G5 + 1, 0x10010000, 1 },
0061 { TARGET_DEV5G + 1, 0x10014000, 1 },
0062 { TARGET_PCS5G_BR + 1, 0x10018000, 1 },
0063 { TARGET_DEV2G5 + 2, 0x1001c000, 1 },
0064 { TARGET_DEV5G + 2, 0x10020000, 1 },
0065 { TARGET_PCS5G_BR + 2, 0x10024000, 1 },
0066 { TARGET_DEV2G5 + 6, 0x10028000, 1 },
0067 { TARGET_DEV5G + 6, 0x1002c000, 1 },
0068 { TARGET_PCS5G_BR + 6, 0x10030000, 1 },
0069 { TARGET_DEV2G5 + 7, 0x10034000, 1 },
0070 { TARGET_DEV5G + 7, 0x10038000, 1 },
0071 { TARGET_PCS5G_BR + 7, 0x1003c000, 1 },
0072 { TARGET_DEV2G5 + 8, 0x10040000, 1 },
0073 { TARGET_DEV5G + 8, 0x10044000, 1 },
0074 { TARGET_PCS5G_BR + 8, 0x10048000, 1 },
0075 { TARGET_DEV2G5 + 9, 0x1004c000, 1 },
0076 { TARGET_DEV5G + 9, 0x10050000, 1 },
0077 { TARGET_PCS5G_BR + 9, 0x10054000, 1 },
0078 { TARGET_DEV2G5 + 10, 0x10058000, 1 },
0079 { TARGET_DEV5G + 10, 0x1005c000, 1 },
0080 { TARGET_PCS5G_BR + 10, 0x10060000, 1 },
0081 { TARGET_DEV2G5 + 11, 0x10064000, 1 },
0082 { TARGET_DEV5G + 11, 0x10068000, 1 },
0083 { TARGET_PCS5G_BR + 11, 0x1006c000, 1 },
0084 { TARGET_DEV2G5 + 12, 0x10070000, 1 },
0085 { TARGET_DEV10G, 0x10074000, 1 },
0086 { TARGET_PCS10G_BR, 0x10078000, 1 },
0087 { TARGET_DEV2G5 + 14, 0x1007c000, 1 },
0088 { TARGET_DEV10G + 2, 0x10080000, 1 },
0089 { TARGET_PCS10G_BR + 2, 0x10084000, 1 },
0090 { TARGET_DEV2G5 + 15, 0x10088000, 1 },
0091 { TARGET_DEV10G + 3, 0x1008c000, 1 },
0092 { TARGET_PCS10G_BR + 3, 0x10090000, 1 },
0093 { TARGET_DEV2G5 + 16, 0x10094000, 1 },
0094 { TARGET_DEV2G5 + 17, 0x10098000, 1 },
0095 { TARGET_DEV2G5 + 18, 0x1009c000, 1 },
0096 { TARGET_DEV2G5 + 19, 0x100a0000, 1 },
0097 { TARGET_DEV2G5 + 20, 0x100a4000, 1 },
0098 { TARGET_DEV2G5 + 21, 0x100a8000, 1 },
0099 { TARGET_DEV2G5 + 22, 0x100ac000, 1 },
0100 { TARGET_DEV2G5 + 23, 0x100b0000, 1 },
0101 { TARGET_DEV2G5 + 32, 0x100b4000, 1 },
0102 { TARGET_DEV2G5 + 33, 0x100b8000, 1 },
0103 { TARGET_DEV2G5 + 34, 0x100bc000, 1 },
0104 { TARGET_DEV2G5 + 35, 0x100c0000, 1 },
0105 { TARGET_DEV2G5 + 36, 0x100c4000, 1 },
0106 { TARGET_DEV2G5 + 37, 0x100c8000, 1 },
0107 { TARGET_DEV2G5 + 38, 0x100cc000, 1 },
0108 { TARGET_DEV2G5 + 39, 0x100d0000, 1 },
0109 { TARGET_DEV2G5 + 40, 0x100d4000, 1 },
0110 { TARGET_DEV2G5 + 41, 0x100d8000, 1 },
0111 { TARGET_DEV2G5 + 42, 0x100dc000, 1 },
0112 { TARGET_DEV2G5 + 43, 0x100e0000, 1 },
0113 { TARGET_DEV2G5 + 44, 0x100e4000, 1 },
0114 { TARGET_DEV2G5 + 45, 0x100e8000, 1 },
0115 { TARGET_DEV2G5 + 46, 0x100ec000, 1 },
0116 { TARGET_DEV2G5 + 47, 0x100f0000, 1 },
0117 { TARGET_DEV2G5 + 57, 0x100f4000, 1 },
0118 { TARGET_DEV25G + 1, 0x100f8000, 1 },
0119 { TARGET_PCS25G_BR + 1, 0x100fc000, 1 },
0120 { TARGET_DEV2G5 + 59, 0x10104000, 1 },
0121 { TARGET_DEV25G + 3, 0x10108000, 1 },
0122 { TARGET_PCS25G_BR + 3, 0x1010c000, 1 },
0123 { TARGET_DEV2G5 + 60, 0x10114000, 1 },
0124 { TARGET_DEV25G + 4, 0x10118000, 1 },
0125 { TARGET_PCS25G_BR + 4, 0x1011c000, 1 },
0126 { TARGET_DEV2G5 + 64, 0x10124000, 1 },
0127 { TARGET_DEV5G + 12, 0x10128000, 1 },
0128 { TARGET_PCS5G_BR + 12, 0x1012c000, 1 },
0129 { TARGET_PORT_CONF, 0x10130000, 1 },
0130 { TARGET_DEV2G5 + 3, 0x10404000, 1 },
0131 { TARGET_DEV5G + 3, 0x10408000, 1 },
0132 { TARGET_PCS5G_BR + 3, 0x1040c000, 1 },
0133 { TARGET_DEV2G5 + 4, 0x10410000, 1 },
0134 { TARGET_DEV5G + 4, 0x10414000, 1 },
0135 { TARGET_PCS5G_BR + 4, 0x10418000, 1 },
0136 { TARGET_DEV2G5 + 5, 0x1041c000, 1 },
0137 { TARGET_DEV5G + 5, 0x10420000, 1 },
0138 { TARGET_PCS5G_BR + 5, 0x10424000, 1 },
0139 { TARGET_DEV2G5 + 13, 0x10428000, 1 },
0140 { TARGET_DEV10G + 1, 0x1042c000, 1 },
0141 { TARGET_PCS10G_BR + 1, 0x10430000, 1 },
0142 { TARGET_DEV2G5 + 24, 0x10434000, 1 },
0143 { TARGET_DEV2G5 + 25, 0x10438000, 1 },
0144 { TARGET_DEV2G5 + 26, 0x1043c000, 1 },
0145 { TARGET_DEV2G5 + 27, 0x10440000, 1 },
0146 { TARGET_DEV2G5 + 28, 0x10444000, 1 },
0147 { TARGET_DEV2G5 + 29, 0x10448000, 1 },
0148 { TARGET_DEV2G5 + 30, 0x1044c000, 1 },
0149 { TARGET_DEV2G5 + 31, 0x10450000, 1 },
0150 { TARGET_DEV2G5 + 48, 0x10454000, 1 },
0151 { TARGET_DEV10G + 4, 0x10458000, 1 },
0152 { TARGET_PCS10G_BR + 4, 0x1045c000, 1 },
0153 { TARGET_DEV2G5 + 49, 0x10460000, 1 },
0154 { TARGET_DEV10G + 5, 0x10464000, 1 },
0155 { TARGET_PCS10G_BR + 5, 0x10468000, 1 },
0156 { TARGET_DEV2G5 + 50, 0x1046c000, 1 },
0157 { TARGET_DEV10G + 6, 0x10470000, 1 },
0158 { TARGET_PCS10G_BR + 6, 0x10474000, 1 },
0159 { TARGET_DEV2G5 + 51, 0x10478000, 1 },
0160 { TARGET_DEV10G + 7, 0x1047c000, 1 },
0161 { TARGET_PCS10G_BR + 7, 0x10480000, 1 },
0162 { TARGET_DEV2G5 + 52, 0x10484000, 1 },
0163 { TARGET_DEV10G + 8, 0x10488000, 1 },
0164 { TARGET_PCS10G_BR + 8, 0x1048c000, 1 },
0165 { TARGET_DEV2G5 + 53, 0x10490000, 1 },
0166 { TARGET_DEV10G + 9, 0x10494000, 1 },
0167 { TARGET_PCS10G_BR + 9, 0x10498000, 1 },
0168 { TARGET_DEV2G5 + 54, 0x1049c000, 1 },
0169 { TARGET_DEV10G + 10, 0x104a0000, 1 },
0170 { TARGET_PCS10G_BR + 10, 0x104a4000, 1 },
0171 { TARGET_DEV2G5 + 55, 0x104a8000, 1 },
0172 { TARGET_DEV10G + 11, 0x104ac000, 1 },
0173 { TARGET_PCS10G_BR + 11, 0x104b0000, 1 },
0174 { TARGET_DEV2G5 + 56, 0x104b4000, 1 },
0175 { TARGET_DEV25G, 0x104b8000, 1 },
0176 { TARGET_PCS25G_BR, 0x104bc000, 1 },
0177 { TARGET_DEV2G5 + 58, 0x104c4000, 1 },
0178 { TARGET_DEV25G + 2, 0x104c8000, 1 },
0179 { TARGET_PCS25G_BR + 2, 0x104cc000, 1 },
0180 { TARGET_DEV2G5 + 61, 0x104d4000, 1 },
0181 { TARGET_DEV25G + 5, 0x104d8000, 1 },
0182 { TARGET_PCS25G_BR + 5, 0x104dc000, 1 },
0183 { TARGET_DEV2G5 + 62, 0x104e4000, 1 },
0184 { TARGET_DEV25G + 6, 0x104e8000, 1 },
0185 { TARGET_PCS25G_BR + 6, 0x104ec000, 1 },
0186 { TARGET_DEV2G5 + 63, 0x104f4000, 1 },
0187 { TARGET_DEV25G + 7, 0x104f8000, 1 },
0188 { TARGET_PCS25G_BR + 7, 0x104fc000, 1 },
0189 { TARGET_DSM, 0x10504000, 1 },
0190 { TARGET_ASM, 0x10600000, 1 },
0191 { TARGET_GCB, 0x11010000, 2 },
0192 { TARGET_QS, 0x11030000, 2 },
0193 { TARGET_PTP, 0x11040000, 2 },
0194 { TARGET_ANA_ACL, 0x11050000, 2 },
0195 { TARGET_LRN, 0x11060000, 2 },
0196 { TARGET_VCAP_SUPER, 0x11080000, 2 },
0197 { TARGET_QSYS, 0x110a0000, 2 },
0198 { TARGET_QFWD, 0x110b0000, 2 },
0199 { TARGET_XQS, 0x110c0000, 2 },
0200 { TARGET_CLKGEN, 0x11100000, 2 },
0201 { TARGET_ANA_AC_POL, 0x11200000, 2 },
0202 { TARGET_QRES, 0x11280000, 2 },
0203 { TARGET_EACL, 0x112c0000, 2 },
0204 { TARGET_ANA_CL, 0x11400000, 2 },
0205 { TARGET_ANA_L3, 0x11480000, 2 },
0206 { TARGET_HSCH, 0x11580000, 2 },
0207 { TARGET_REW, 0x11600000, 2 },
0208 { TARGET_ANA_L2, 0x11800000, 2 },
0209 { TARGET_ANA_AC, 0x11900000, 2 },
0210 { TARGET_VOP, 0x11a00000, 2 },
0211 };
0212
0213 static int sparx5_create_targets(struct sparx5 *sparx5)
0214 {
0215 struct resource *iores[IO_RANGES];
0216 void __iomem *iomem[IO_RANGES];
0217 void __iomem *begin[IO_RANGES];
0218 int range_id[IO_RANGES];
0219 int idx, jdx;
0220
0221 for (idx = 0, jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) {
0222 const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx];
0223
0224 if (idx == iomap->range) {
0225 range_id[idx] = jdx;
0226 idx++;
0227 }
0228 }
0229 for (idx = 0; idx < IO_RANGES; idx++) {
0230 iores[idx] = platform_get_resource(sparx5->pdev, IORESOURCE_MEM,
0231 idx);
0232 if (!iores[idx]) {
0233 dev_err(sparx5->dev, "Invalid resource\n");
0234 return -EINVAL;
0235 }
0236 iomem[idx] = devm_ioremap(sparx5->dev,
0237 iores[idx]->start,
0238 resource_size(iores[idx]));
0239 if (!iomem[idx]) {
0240 dev_err(sparx5->dev, "Unable to get switch registers: %s\n",
0241 iores[idx]->name);
0242 return -ENOMEM;
0243 }
0244 begin[idx] = iomem[idx] - sparx5_main_iomap[range_id[idx]].offset;
0245 }
0246 for (jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) {
0247 const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx];
0248
0249 sparx5->regs[iomap->id] = begin[iomap->range] + iomap->offset;
0250 }
0251 return 0;
0252 }
0253
0254 static int sparx5_create_port(struct sparx5 *sparx5,
0255 struct initial_port_config *config)
0256 {
0257 struct sparx5_port *spx5_port;
0258 struct net_device *ndev;
0259 struct phylink *phylink;
0260 int err;
0261
0262 ndev = sparx5_create_netdev(sparx5, config->portno);
0263 if (IS_ERR(ndev)) {
0264 dev_err(sparx5->dev, "Could not create net device: %02u\n",
0265 config->portno);
0266 return PTR_ERR(ndev);
0267 }
0268 spx5_port = netdev_priv(ndev);
0269 spx5_port->of_node = config->node;
0270 spx5_port->serdes = config->serdes;
0271 spx5_port->pvid = NULL_VID;
0272 spx5_port->signd_internal = true;
0273 spx5_port->signd_active_high = true;
0274 spx5_port->signd_enable = true;
0275 spx5_port->max_vlan_tags = SPX5_PORT_MAX_TAGS_NONE;
0276 spx5_port->vlan_type = SPX5_VLAN_PORT_TYPE_UNAWARE;
0277 spx5_port->custom_etype = 0x8880;
0278 spx5_port->phylink_pcs.poll = true;
0279 spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops;
0280 sparx5->ports[config->portno] = spx5_port;
0281
0282 err = sparx5_port_init(sparx5, spx5_port, &config->conf);
0283 if (err) {
0284 dev_err(sparx5->dev, "port init failed\n");
0285 return err;
0286 }
0287 spx5_port->conf = config->conf;
0288
0289
0290 sparx5_vlan_port_setup(sparx5, spx5_port->portno);
0291
0292
0293 spx5_port->phylink_config.dev = &spx5_port->ndev->dev;
0294 spx5_port->phylink_config.type = PHYLINK_NETDEV;
0295 spx5_port->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
0296 MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD |
0297 MAC_2500FD | MAC_5000FD | MAC_10000FD | MAC_25000FD;
0298
0299 __set_bit(PHY_INTERFACE_MODE_SGMII,
0300 spx5_port->phylink_config.supported_interfaces);
0301 __set_bit(PHY_INTERFACE_MODE_QSGMII,
0302 spx5_port->phylink_config.supported_interfaces);
0303 __set_bit(PHY_INTERFACE_MODE_1000BASEX,
0304 spx5_port->phylink_config.supported_interfaces);
0305 __set_bit(PHY_INTERFACE_MODE_2500BASEX,
0306 spx5_port->phylink_config.supported_interfaces);
0307
0308 if (spx5_port->conf.bandwidth == SPEED_5000 ||
0309 spx5_port->conf.bandwidth == SPEED_10000 ||
0310 spx5_port->conf.bandwidth == SPEED_25000)
0311 __set_bit(PHY_INTERFACE_MODE_5GBASER,
0312 spx5_port->phylink_config.supported_interfaces);
0313
0314 if (spx5_port->conf.bandwidth == SPEED_10000 ||
0315 spx5_port->conf.bandwidth == SPEED_25000)
0316 __set_bit(PHY_INTERFACE_MODE_10GBASER,
0317 spx5_port->phylink_config.supported_interfaces);
0318
0319 if (spx5_port->conf.bandwidth == SPEED_25000)
0320 __set_bit(PHY_INTERFACE_MODE_25GBASER,
0321 spx5_port->phylink_config.supported_interfaces);
0322
0323 phylink = phylink_create(&spx5_port->phylink_config,
0324 of_fwnode_handle(config->node),
0325 config->conf.phy_mode,
0326 &sparx5_phylink_mac_ops);
0327 if (IS_ERR(phylink))
0328 return PTR_ERR(phylink);
0329
0330 spx5_port->phylink = phylink;
0331
0332 return 0;
0333 }
0334
0335 static int sparx5_init_ram(struct sparx5 *s5)
0336 {
0337 const struct sparx5_ram_config spx5_ram_cfg[] = {
0338 {spx5_reg_get(s5, ANA_AC_STAT_RESET), ANA_AC_STAT_RESET_RESET},
0339 {spx5_reg_get(s5, ASM_STAT_CFG), ASM_STAT_CFG_STAT_CNT_CLR_SHOT},
0340 {spx5_reg_get(s5, QSYS_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
0341 {spx5_reg_get(s5, REW_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
0342 {spx5_reg_get(s5, VOP_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
0343 {spx5_reg_get(s5, ANA_AC_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
0344 {spx5_reg_get(s5, ASM_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
0345 {spx5_reg_get(s5, EACL_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
0346 {spx5_reg_get(s5, VCAP_SUPER_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
0347 {spx5_reg_get(s5, DSM_RAM_INIT), QSYS_RAM_INIT_RAM_INIT}
0348 };
0349 const struct sparx5_ram_config *cfg;
0350 u32 value, pending, jdx, idx;
0351
0352 for (jdx = 0; jdx < 10; jdx++) {
0353 pending = ARRAY_SIZE(spx5_ram_cfg);
0354 for (idx = 0; idx < ARRAY_SIZE(spx5_ram_cfg); idx++) {
0355 cfg = &spx5_ram_cfg[idx];
0356 if (jdx == 0) {
0357 writel(cfg->init_val, cfg->init_reg);
0358 } else {
0359 value = readl(cfg->init_reg);
0360 if ((value & cfg->init_val) != cfg->init_val)
0361 pending--;
0362 }
0363 }
0364 if (!pending)
0365 break;
0366 usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
0367 }
0368
0369 if (pending > 0) {
0370
0371
0372
0373 dev_err(s5->dev, "Memory initialization error\n");
0374 return -EINVAL;
0375 }
0376 return 0;
0377 }
0378
0379 static int sparx5_init_switchcore(struct sparx5 *sparx5)
0380 {
0381 u32 value;
0382 int err = 0;
0383
0384 spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(1),
0385 EACL_POL_EACL_CFG_EACL_FORCE_INIT,
0386 sparx5,
0387 EACL_POL_EACL_CFG);
0388
0389 spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(0),
0390 EACL_POL_EACL_CFG_EACL_FORCE_INIT,
0391 sparx5,
0392 EACL_POL_EACL_CFG);
0393
0394
0395 value = spx5_rd(sparx5, HSCH_RESET_CFG);
0396 if (!(value & HSCH_RESET_CFG_CORE_ENA)) {
0397 err = sparx5_init_ram(sparx5);
0398 if (err)
0399 return err;
0400 }
0401
0402
0403 spx5_wr(ANA_AC_STAT_RESET_RESET_SET(1), sparx5, ANA_AC_STAT_RESET);
0404 spx5_wr(ASM_STAT_CFG_STAT_CNT_CLR_SHOT_SET(1), sparx5, ASM_STAT_CFG);
0405
0406
0407 spx5_wr(HSCH_RESET_CFG_CORE_ENA_SET(1), sparx5, HSCH_RESET_CFG);
0408
0409 return 0;
0410 }
0411
0412 static int sparx5_init_coreclock(struct sparx5 *sparx5)
0413 {
0414 enum sparx5_core_clockfreq freq = sparx5->coreclock;
0415 u32 clk_div, clk_period, pol_upd_int, idx;
0416
0417
0418
0419
0420
0421 switch (sparx5->target_ct) {
0422 case SPX5_TARGET_CT_7546:
0423 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
0424 freq = SPX5_CORE_CLOCK_250MHZ;
0425 else if (sparx5->coreclock != SPX5_CORE_CLOCK_250MHZ)
0426 freq = 0;
0427 break;
0428 case SPX5_TARGET_CT_7549:
0429 case SPX5_TARGET_CT_7552:
0430 case SPX5_TARGET_CT_7556:
0431 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
0432 freq = SPX5_CORE_CLOCK_500MHZ;
0433 else if (sparx5->coreclock != SPX5_CORE_CLOCK_500MHZ)
0434 freq = 0;
0435 break;
0436 case SPX5_TARGET_CT_7558:
0437 case SPX5_TARGET_CT_7558TSN:
0438 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
0439 freq = SPX5_CORE_CLOCK_625MHZ;
0440 else if (sparx5->coreclock != SPX5_CORE_CLOCK_625MHZ)
0441 freq = 0;
0442 break;
0443 case SPX5_TARGET_CT_7546TSN:
0444 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
0445 freq = SPX5_CORE_CLOCK_625MHZ;
0446 break;
0447 case SPX5_TARGET_CT_7549TSN:
0448 case SPX5_TARGET_CT_7552TSN:
0449 case SPX5_TARGET_CT_7556TSN:
0450 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
0451 freq = SPX5_CORE_CLOCK_625MHZ;
0452 else if (sparx5->coreclock == SPX5_CORE_CLOCK_250MHZ)
0453 freq = 0;
0454 break;
0455 default:
0456 dev_err(sparx5->dev, "Target (%#04x) not supported\n",
0457 sparx5->target_ct);
0458 return -ENODEV;
0459 }
0460
0461 switch (freq) {
0462 case SPX5_CORE_CLOCK_250MHZ:
0463 clk_div = 10;
0464 pol_upd_int = 312;
0465 break;
0466 case SPX5_CORE_CLOCK_500MHZ:
0467 clk_div = 5;
0468 pol_upd_int = 624;
0469 break;
0470 case SPX5_CORE_CLOCK_625MHZ:
0471 clk_div = 4;
0472 pol_upd_int = 780;
0473 break;
0474 default:
0475 dev_err(sparx5->dev, "%d coreclock not supported on (%#04x)\n",
0476 sparx5->coreclock, sparx5->target_ct);
0477 return -EINVAL;
0478 }
0479
0480
0481 sparx5->coreclock = freq;
0482
0483
0484 spx5_rmw(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_SET(clk_div) |
0485 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV_SET(0) |
0486 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR_SET(0) |
0487 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL_SET(0) |
0488 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA_SET(0) |
0489 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_SET(1),
0490 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV |
0491 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV |
0492 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR |
0493 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL |
0494 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA |
0495 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA,
0496 sparx5,
0497 CLKGEN_LCPLL1_CORE_CLK_CFG);
0498
0499 clk_period = sparx5_clk_period(freq);
0500
0501 spx5_rmw(HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS_SET(clk_period / 100),
0502 HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS,
0503 sparx5,
0504 HSCH_SYS_CLK_PER);
0505
0506 spx5_rmw(ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100),
0507 ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS,
0508 sparx5,
0509 ANA_AC_POL_BDLB_DLB_CTRL);
0510
0511 spx5_rmw(ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100),
0512 ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS,
0513 sparx5,
0514 ANA_AC_POL_SLB_DLB_CTRL);
0515
0516 spx5_rmw(LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS_SET(clk_period / 100),
0517 LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS,
0518 sparx5,
0519 LRN_AUTOAGE_CFG_1);
0520
0521 for (idx = 0; idx < 3; idx++)
0522 spx5_rmw(GCB_SIO_CLOCK_SYS_CLK_PERIOD_SET(clk_period / 100),
0523 GCB_SIO_CLOCK_SYS_CLK_PERIOD,
0524 sparx5,
0525 GCB_SIO_CLOCK(idx));
0526
0527 spx5_rmw(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_SET
0528 ((256 * 1000) / clk_period),
0529 HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY,
0530 sparx5,
0531 HSCH_TAS_STATEMACHINE_CFG);
0532
0533 spx5_rmw(ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT_SET(pol_upd_int),
0534 ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT,
0535 sparx5,
0536 ANA_AC_POL_POL_UPD_INT_CFG);
0537
0538 return 0;
0539 }
0540
0541 static int sparx5_qlim_set(struct sparx5 *sparx5)
0542 {
0543 u32 res, dp, prio;
0544
0545 for (res = 0; res < 2; res++) {
0546 for (prio = 0; prio < 8; prio++)
0547 spx5_wr(0xFFF, sparx5,
0548 QRES_RES_CFG(prio + 630 + res * 1024));
0549
0550 for (dp = 0; dp < 4; dp++)
0551 spx5_wr(0xFFF, sparx5,
0552 QRES_RES_CFG(dp + 638 + res * 1024));
0553 }
0554
0555
0556 spx5_wr(QLIM_WM(80), sparx5, XQS_QLIMIT_SHR_QLIM_CFG(0));
0557 spx5_wr(QLIM_WM(90), sparx5, XQS_QLIMIT_SHR_CTOP_CFG(0));
0558 spx5_wr(QLIM_WM(95), sparx5, XQS_QLIMIT_SHR_ATOP_CFG(0));
0559 spx5_wr(QLIM_WM(100), sparx5, XQS_QLIMIT_SHR_TOP_CFG(0));
0560
0561 return 0;
0562 }
0563
0564
0565
0566
0567 static void sparx5_board_init(struct sparx5 *sparx5)
0568 {
0569 int idx;
0570
0571 if (!sparx5->sd_sgpio_remapping)
0572 return;
0573
0574
0575 spx5_rmw(GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL,
0576 GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL,
0577 sparx5,
0578 GCB_HW_SGPIO_SD_CFG);
0579
0580
0581 for (idx = 0; idx < SPX5_PORTS; idx++)
0582 if (sparx5->ports[idx])
0583 if (sparx5->ports[idx]->conf.sd_sgpio != ~0)
0584 spx5_wr(sparx5->ports[idx]->conf.sd_sgpio,
0585 sparx5,
0586 GCB_HW_SGPIO_TO_SD_MAP_CFG(idx));
0587 }
0588
0589 static int sparx5_start(struct sparx5 *sparx5)
0590 {
0591 u8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
0592 char queue_name[32];
0593 u32 idx;
0594 int err;
0595
0596
0597 for (idx = 0; idx < 3; idx++) {
0598 spx5_wr(idx, sparx5, ANA_AC_OWN_UPSID(idx));
0599 spx5_wr(idx, sparx5, ANA_CL_OWN_UPSID(idx));
0600 spx5_wr(idx, sparx5, ANA_L2_OWN_UPSID(idx));
0601 spx5_wr(idx, sparx5, REW_OWN_UPSID(idx));
0602 }
0603
0604
0605 for (idx = SPX5_PORTS; idx < SPX5_PORTS_ALL; idx++)
0606 spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(1),
0607 QFWD_SWITCH_PORT_MODE_PORT_ENA,
0608 sparx5,
0609 QFWD_SWITCH_PORT_MODE(idx));
0610
0611
0612 sparx5_update_fwd(sparx5);
0613
0614
0615 spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
0616 sparx5, ANA_AC_PGID_MISC_CFG(PGID_CPU));
0617 spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
0618 sparx5, ANA_AC_PGID_MISC_CFG(PGID_BCAST));
0619
0620
0621 for (idx = SPX5_PORT_CPU_0; idx <= SPX5_PORT_CPU_1; idx++)
0622 spx5_rmw(ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA_SET(1),
0623 ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA,
0624 sparx5, ANA_CL_FILTER_CTRL(idx));
0625
0626
0627 sparx5_mact_init(sparx5);
0628
0629
0630 sparx5_pgid_init(sparx5);
0631
0632
0633 sparx5_vlan_init(sparx5);
0634
0635
0636 sparx5_mact_learn(sparx5, PGID_CPU, broadcast, NULL_VID);
0637
0638
0639 sparx5_qlim_set(sparx5);
0640
0641 err = sparx5_config_auto_calendar(sparx5);
0642 if (err)
0643 return err;
0644
0645 err = sparx5_config_dsm_calendar(sparx5);
0646 if (err)
0647 return err;
0648
0649
0650 err = sparx_stats_init(sparx5);
0651 if (err)
0652 return err;
0653
0654
0655 mutex_init(&sparx5->mact_lock);
0656 INIT_LIST_HEAD(&sparx5->mact_entries);
0657 snprintf(queue_name, sizeof(queue_name), "%s-mact",
0658 dev_name(sparx5->dev));
0659 sparx5->mact_queue = create_singlethread_workqueue(queue_name);
0660 INIT_DELAYED_WORK(&sparx5->mact_work, sparx5_mact_pull_work);
0661 queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work,
0662 SPX5_MACT_PULL_DELAY);
0663
0664 err = sparx5_register_netdevs(sparx5);
0665 if (err)
0666 return err;
0667
0668 sparx5_board_init(sparx5);
0669 err = sparx5_register_notifier_blocks(sparx5);
0670
0671
0672 err = -ENXIO;
0673 if (sparx5->fdma_irq >= 0) {
0674 if (GCB_CHIP_ID_REV_ID_GET(sparx5->chip_id) > 0)
0675 err = devm_request_threaded_irq(sparx5->dev,
0676 sparx5->fdma_irq,
0677 NULL,
0678 sparx5_fdma_handler,
0679 IRQF_ONESHOT,
0680 "sparx5-fdma", sparx5);
0681 if (!err)
0682 err = sparx5_fdma_start(sparx5);
0683 if (err)
0684 sparx5->fdma_irq = -ENXIO;
0685 } else {
0686 sparx5->fdma_irq = -ENXIO;
0687 }
0688 if (err && sparx5->xtr_irq >= 0) {
0689 err = devm_request_irq(sparx5->dev, sparx5->xtr_irq,
0690 sparx5_xtr_handler, IRQF_SHARED,
0691 "sparx5-xtr", sparx5);
0692 if (!err)
0693 err = sparx5_manual_injection_mode(sparx5);
0694 if (err)
0695 sparx5->xtr_irq = -ENXIO;
0696 } else {
0697 sparx5->xtr_irq = -ENXIO;
0698 }
0699
0700 if (sparx5->ptp_irq >= 0) {
0701 err = devm_request_threaded_irq(sparx5->dev, sparx5->ptp_irq,
0702 NULL, sparx5_ptp_irq_handler,
0703 IRQF_ONESHOT, "sparx5-ptp",
0704 sparx5);
0705 if (err)
0706 sparx5->ptp_irq = -ENXIO;
0707
0708 sparx5->ptp = 1;
0709 }
0710
0711 return err;
0712 }
0713
0714 static void sparx5_cleanup_ports(struct sparx5 *sparx5)
0715 {
0716 sparx5_unregister_netdevs(sparx5);
0717 sparx5_destroy_netdevs(sparx5);
0718 }
0719
0720 static int mchp_sparx5_probe(struct platform_device *pdev)
0721 {
0722 struct initial_port_config *configs, *config;
0723 struct device_node *np = pdev->dev.of_node;
0724 struct device_node *ports, *portnp;
0725 struct reset_control *reset;
0726 struct sparx5 *sparx5;
0727 int idx = 0, err = 0;
0728
0729 if (!np && !pdev->dev.platform_data)
0730 return -ENODEV;
0731
0732 sparx5 = devm_kzalloc(&pdev->dev, sizeof(*sparx5), GFP_KERNEL);
0733 if (!sparx5)
0734 return -ENOMEM;
0735
0736 platform_set_drvdata(pdev, sparx5);
0737 sparx5->pdev = pdev;
0738 sparx5->dev = &pdev->dev;
0739
0740
0741 reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch");
0742 if (IS_ERR(reset))
0743 return dev_err_probe(&pdev->dev, PTR_ERR(reset),
0744 "Failed to get switch reset controller.\n");
0745 reset_control_reset(reset);
0746
0747
0748 sparx5->coreclock = SPX5_CORE_CLOCK_DEFAULT;
0749
0750 ports = of_get_child_by_name(np, "ethernet-ports");
0751 if (!ports) {
0752 dev_err(sparx5->dev, "no ethernet-ports child node found\n");
0753 return -ENODEV;
0754 }
0755 sparx5->port_count = of_get_child_count(ports);
0756
0757 configs = kcalloc(sparx5->port_count,
0758 sizeof(struct initial_port_config), GFP_KERNEL);
0759 if (!configs) {
0760 err = -ENOMEM;
0761 goto cleanup_pnode;
0762 }
0763
0764 for_each_available_child_of_node(ports, portnp) {
0765 struct sparx5_port_config *conf;
0766 struct phy *serdes;
0767 u32 portno;
0768
0769 err = of_property_read_u32(portnp, "reg", &portno);
0770 if (err) {
0771 dev_err(sparx5->dev, "port reg property error\n");
0772 continue;
0773 }
0774 config = &configs[idx];
0775 conf = &config->conf;
0776 conf->speed = SPEED_UNKNOWN;
0777 conf->bandwidth = SPEED_UNKNOWN;
0778 err = of_get_phy_mode(portnp, &conf->phy_mode);
0779 if (err) {
0780 dev_err(sparx5->dev, "port %u: missing phy-mode\n",
0781 portno);
0782 continue;
0783 }
0784 err = of_property_read_u32(portnp, "microchip,bandwidth",
0785 &conf->bandwidth);
0786 if (err) {
0787 dev_err(sparx5->dev, "port %u: missing bandwidth\n",
0788 portno);
0789 continue;
0790 }
0791 err = of_property_read_u32(portnp, "microchip,sd-sgpio", &conf->sd_sgpio);
0792 if (err)
0793 conf->sd_sgpio = ~0;
0794 else
0795 sparx5->sd_sgpio_remapping = true;
0796 serdes = devm_of_phy_get(sparx5->dev, portnp, NULL);
0797 if (IS_ERR(serdes)) {
0798 err = dev_err_probe(sparx5->dev, PTR_ERR(serdes),
0799 "port %u: missing serdes\n",
0800 portno);
0801 of_node_put(portnp);
0802 goto cleanup_config;
0803 }
0804 config->portno = portno;
0805 config->node = portnp;
0806 config->serdes = serdes;
0807
0808 conf->media = PHY_MEDIA_DAC;
0809 conf->serdes_reset = true;
0810 conf->portmode = conf->phy_mode;
0811 conf->power_down = true;
0812 idx++;
0813 }
0814
0815 err = sparx5_create_targets(sparx5);
0816 if (err)
0817 goto cleanup_config;
0818
0819 if (!of_get_mac_address(np, sparx5->base_mac)) {
0820 dev_info(sparx5->dev, "MAC addr was not set, use random MAC\n");
0821 eth_random_addr(sparx5->base_mac);
0822 sparx5->base_mac[5] = 0;
0823 }
0824
0825 sparx5->fdma_irq = platform_get_irq_byname(sparx5->pdev, "fdma");
0826 sparx5->xtr_irq = platform_get_irq_byname(sparx5->pdev, "xtr");
0827 sparx5->ptp_irq = platform_get_irq_byname(sparx5->pdev, "ptp");
0828
0829
0830 sparx5->chip_id = spx5_rd(sparx5, GCB_CHIP_ID);
0831
0832 sparx5->target_ct = (enum spx5_target_chiptype)
0833 GCB_CHIP_ID_PART_ID_GET(sparx5->chip_id);
0834
0835
0836 err = sparx5_init_switchcore(sparx5);
0837 if (err) {
0838 dev_err(sparx5->dev, "Switchcore initialization error\n");
0839 goto cleanup_config;
0840 }
0841
0842
0843 err = sparx5_init_coreclock(sparx5);
0844 if (err) {
0845 dev_err(sparx5->dev, "LC-PLL initialization error\n");
0846 goto cleanup_config;
0847 }
0848
0849 for (idx = 0; idx < sparx5->port_count; ++idx) {
0850 config = &configs[idx];
0851 if (!config->node)
0852 continue;
0853
0854 err = sparx5_create_port(sparx5, config);
0855 if (err) {
0856 dev_err(sparx5->dev, "port create error\n");
0857 goto cleanup_ports;
0858 }
0859 }
0860
0861 err = sparx5_start(sparx5);
0862 if (err) {
0863 dev_err(sparx5->dev, "Start failed\n");
0864 goto cleanup_ports;
0865 }
0866
0867 err = sparx5_ptp_init(sparx5);
0868 if (err) {
0869 dev_err(sparx5->dev, "PTP failed\n");
0870 goto cleanup_ports;
0871 }
0872 goto cleanup_config;
0873
0874 cleanup_ports:
0875 sparx5_cleanup_ports(sparx5);
0876 cleanup_config:
0877 kfree(configs);
0878 cleanup_pnode:
0879 of_node_put(ports);
0880 return err;
0881 }
0882
0883 static int mchp_sparx5_remove(struct platform_device *pdev)
0884 {
0885 struct sparx5 *sparx5 = platform_get_drvdata(pdev);
0886
0887 if (sparx5->xtr_irq) {
0888 disable_irq(sparx5->xtr_irq);
0889 sparx5->xtr_irq = -ENXIO;
0890 }
0891 if (sparx5->fdma_irq) {
0892 disable_irq(sparx5->fdma_irq);
0893 sparx5->fdma_irq = -ENXIO;
0894 }
0895 sparx5_ptp_deinit(sparx5);
0896 sparx5_fdma_stop(sparx5);
0897 sparx5_cleanup_ports(sparx5);
0898
0899 sparx5_unregister_notifier_blocks(sparx5);
0900
0901 return 0;
0902 }
0903
0904 static const struct of_device_id mchp_sparx5_match[] = {
0905 { .compatible = "microchip,sparx5-switch" },
0906 { }
0907 };
0908 MODULE_DEVICE_TABLE(of, mchp_sparx5_match);
0909
0910 static struct platform_driver mchp_sparx5_driver = {
0911 .probe = mchp_sparx5_probe,
0912 .remove = mchp_sparx5_remove,
0913 .driver = {
0914 .name = "sparx5-switch",
0915 .of_match_table = mchp_sparx5_match,
0916 },
0917 };
0918
0919 module_platform_driver(mchp_sparx5_driver);
0920
0921 MODULE_DESCRIPTION("Microchip Sparx5 switch driver");
0922 MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>");
0923 MODULE_LICENSE("Dual MIT/GPL");