Lines Matching +full:sparx5 +full:- +full:sgpio
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
6 * The Sparx5 Chip Register Model can be browsed at this location:
7 * https://github.com/microchip-ung/sparx-5_reginfo
32 ((SPX5_BUFFER_MEMORY / SPX5_BUFFER_CELL_SZ - 100) * (fraction) / 100)
212 static int sparx5_create_targets(struct sparx5 *sparx5) in sparx5_create_targets() argument
223 if (idx == iomap->range) { in sparx5_create_targets()
229 iores[idx] = platform_get_resource(sparx5->pdev, IORESOURCE_MEM, in sparx5_create_targets()
232 dev_err(sparx5->dev, "Invalid resource\n"); in sparx5_create_targets()
233 return -EINVAL; in sparx5_create_targets()
235 iomem[idx] = devm_ioremap(sparx5->dev, in sparx5_create_targets()
236 iores[idx]->start, in sparx5_create_targets()
237 iores[idx]->end - iores[idx]->start in sparx5_create_targets()
240 dev_err(sparx5->dev, "Unable to get switch registers: %s\n", in sparx5_create_targets()
241 iores[idx]->name); in sparx5_create_targets()
242 return -ENOMEM; in sparx5_create_targets()
244 begin[idx] = iomem[idx] - sparx5_main_iomap[range_id[idx]].offset; in sparx5_create_targets()
249 sparx5->regs[iomap->id] = begin[iomap->range] + iomap->offset; in sparx5_create_targets()
254 static int sparx5_create_port(struct sparx5 *sparx5, in sparx5_create_port() argument
262 ndev = sparx5_create_netdev(sparx5, config->portno); in sparx5_create_port()
264 dev_err(sparx5->dev, "Could not create net device: %02u\n", in sparx5_create_port()
265 config->portno); in sparx5_create_port()
269 spx5_port->of_node = config->node; in sparx5_create_port()
270 spx5_port->serdes = config->serdes; in sparx5_create_port()
271 spx5_port->pvid = NULL_VID; in sparx5_create_port()
272 spx5_port->signd_internal = true; in sparx5_create_port()
273 spx5_port->signd_active_high = true; in sparx5_create_port()
274 spx5_port->signd_enable = true; in sparx5_create_port()
275 spx5_port->max_vlan_tags = SPX5_PORT_MAX_TAGS_NONE; in sparx5_create_port()
276 spx5_port->vlan_type = SPX5_VLAN_PORT_TYPE_UNAWARE; in sparx5_create_port()
277 spx5_port->custom_etype = 0x8880; /* Vitesse */ in sparx5_create_port()
278 spx5_port->phylink_pcs.poll = true; in sparx5_create_port()
279 spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops; in sparx5_create_port()
280 sparx5->ports[config->portno] = spx5_port; in sparx5_create_port()
282 err = sparx5_port_init(sparx5, spx5_port, &config->conf); in sparx5_create_port()
284 dev_err(sparx5->dev, "port init failed\n"); in sparx5_create_port()
287 spx5_port->conf = config->conf; in sparx5_create_port()
290 sparx5_vlan_port_setup(sparx5, spx5_port->portno); in sparx5_create_port()
293 spx5_port->phylink_config.dev = &spx5_port->ndev->dev; in sparx5_create_port()
294 spx5_port->phylink_config.type = PHYLINK_NETDEV; in sparx5_create_port()
295 spx5_port->phylink_config.pcs_poll = true; in sparx5_create_port()
297 phylink = phylink_create(&spx5_port->phylink_config, in sparx5_create_port()
298 of_fwnode_handle(config->node), in sparx5_create_port()
299 config->conf.phy_mode, in sparx5_create_port()
304 spx5_port->phylink = phylink; in sparx5_create_port()
305 phylink_set_pcs(phylink, &spx5_port->phylink_pcs); in sparx5_create_port()
310 static int sparx5_init_ram(struct sparx5 *s5) in sparx5_init_ram()
332 writel(cfg->init_val, cfg->init_reg); in sparx5_init_ram()
334 value = readl(cfg->init_reg); in sparx5_init_ram()
335 if ((value & cfg->init_val) != cfg->init_val) in sparx5_init_ram()
336 pending--; in sparx5_init_ram()
348 dev_err(s5->dev, "Memory initialization error\n"); in sparx5_init_ram()
349 return -EINVAL; in sparx5_init_ram()
354 static int sparx5_init_switchcore(struct sparx5 *sparx5) in sparx5_init_switchcore() argument
361 sparx5, in sparx5_init_switchcore()
366 sparx5, in sparx5_init_switchcore()
370 value = spx5_rd(sparx5, HSCH_RESET_CFG); in sparx5_init_switchcore()
372 err = sparx5_init_ram(sparx5); in sparx5_init_switchcore()
378 spx5_wr(ANA_AC_STAT_RESET_RESET_SET(1), sparx5, ANA_AC_STAT_RESET); in sparx5_init_switchcore()
379 spx5_wr(ASM_STAT_CFG_STAT_CNT_CLR_SHOT_SET(1), sparx5, ASM_STAT_CFG); in sparx5_init_switchcore()
381 /* Enable switch-core and queue system */ in sparx5_init_switchcore()
382 spx5_wr(HSCH_RESET_CFG_CORE_ENA_SET(1), sparx5, HSCH_RESET_CFG); in sparx5_init_switchcore()
387 static int sparx5_init_coreclock(struct sparx5 *sparx5) in sparx5_init_coreclock() argument
389 enum sparx5_core_clockfreq freq = sparx5->coreclock; in sparx5_init_coreclock()
396 switch (sparx5->target_ct) { in sparx5_init_coreclock()
398 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) in sparx5_init_coreclock()
400 else if (sparx5->coreclock != SPX5_CORE_CLOCK_250MHZ) in sparx5_init_coreclock()
406 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) in sparx5_init_coreclock()
408 else if (sparx5->coreclock != SPX5_CORE_CLOCK_500MHZ) in sparx5_init_coreclock()
413 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) in sparx5_init_coreclock()
415 else if (sparx5->coreclock != SPX5_CORE_CLOCK_625MHZ) in sparx5_init_coreclock()
419 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) in sparx5_init_coreclock()
425 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) in sparx5_init_coreclock()
427 else if (sparx5->coreclock == SPX5_CORE_CLOCK_250MHZ) in sparx5_init_coreclock()
431 dev_err(sparx5->dev, "Target (%#04x) not supported\n", in sparx5_init_coreclock()
432 sparx5->target_ct); in sparx5_init_coreclock()
433 return -ENODEV; in sparx5_init_coreclock()
450 dev_err(sparx5->dev, "%d coreclock not supported on (%#04x)\n", in sparx5_init_coreclock()
451 sparx5->coreclock, sparx5->target_ct); in sparx5_init_coreclock()
452 return -EINVAL; in sparx5_init_coreclock()
456 sparx5->coreclock = freq; in sparx5_init_coreclock()
471 sparx5, in sparx5_init_coreclock()
478 sparx5, in sparx5_init_coreclock()
483 sparx5, in sparx5_init_coreclock()
488 sparx5, in sparx5_init_coreclock()
493 sparx5, in sparx5_init_coreclock()
499 sparx5, in sparx5_init_coreclock()
505 sparx5, in sparx5_init_coreclock()
510 sparx5, in sparx5_init_coreclock()
516 static int sparx5_qlim_set(struct sparx5 *sparx5) in sparx5_qlim_set() argument
522 spx5_wr(0xFFF, sparx5, in sparx5_qlim_set()
526 spx5_wr(0xFFF, sparx5, in sparx5_qlim_set()
531 spx5_wr(QLIM_WM(80), sparx5, XQS_QLIMIT_SHR_QLIM_CFG(0)); in sparx5_qlim_set()
532 spx5_wr(QLIM_WM(90), sparx5, XQS_QLIMIT_SHR_CTOP_CFG(0)); in sparx5_qlim_set()
533 spx5_wr(QLIM_WM(95), sparx5, XQS_QLIMIT_SHR_ATOP_CFG(0)); in sparx5_qlim_set()
534 spx5_wr(QLIM_WM(100), sparx5, XQS_QLIMIT_SHR_TOP_CFG(0)); in sparx5_qlim_set()
539 /* Some boards needs to map the SGPIO for signal detect explicitly to the
542 static void sparx5_board_init(struct sparx5 *sparx5) in sparx5_board_init() argument
546 if (!sparx5->sd_sgpio_remapping) in sparx5_board_init()
549 /* Enable SGPIO Signal Detect remapping */ in sparx5_board_init()
552 sparx5, in sparx5_board_init()
555 /* Refer to LOS SGPIO */ in sparx5_board_init()
557 if (sparx5->ports[idx]) in sparx5_board_init()
558 if (sparx5->ports[idx]->conf.sd_sgpio != ~0) in sparx5_board_init()
559 spx5_wr(sparx5->ports[idx]->conf.sd_sgpio, in sparx5_board_init()
560 sparx5, in sparx5_board_init()
564 static int sparx5_start(struct sparx5 *sparx5) in sparx5_start() argument
573 spx5_wr(idx, sparx5, ANA_AC_OWN_UPSID(idx)); in sparx5_start()
574 spx5_wr(idx, sparx5, ANA_CL_OWN_UPSID(idx)); in sparx5_start()
575 spx5_wr(idx, sparx5, ANA_L2_OWN_UPSID(idx)); in sparx5_start()
576 spx5_wr(idx, sparx5, REW_OWN_UPSID(idx)); in sparx5_start()
583 sparx5, in sparx5_start()
587 sparx5_update_fwd(sparx5); in sparx5_start()
591 sparx5, ANA_AC_PGID_MISC_CFG(PGID_CPU)); in sparx5_start()
593 sparx5, ANA_AC_PGID_MISC_CFG(PGID_BCAST)); in sparx5_start()
599 sparx5, ANA_CL_FILTER_CTRL(idx)); in sparx5_start()
602 sparx5_mact_init(sparx5); in sparx5_start()
605 sparx5_vlan_init(sparx5); in sparx5_start()
608 sparx5_mact_learn(sparx5, PGID_CPU, broadcast, NULL_VID); in sparx5_start()
611 sparx5_qlim_set(sparx5); in sparx5_start()
613 err = sparx5_config_auto_calendar(sparx5); in sparx5_start()
617 err = sparx5_config_dsm_calendar(sparx5); in sparx5_start()
622 err = sparx_stats_init(sparx5); in sparx5_start()
627 mutex_init(&sparx5->mact_lock); in sparx5_start()
628 INIT_LIST_HEAD(&sparx5->mact_entries); in sparx5_start()
629 snprintf(queue_name, sizeof(queue_name), "%s-mact", in sparx5_start()
630 dev_name(sparx5->dev)); in sparx5_start()
631 sparx5->mact_queue = create_singlethread_workqueue(queue_name); in sparx5_start()
632 INIT_DELAYED_WORK(&sparx5->mact_work, sparx5_mact_pull_work); in sparx5_start()
633 queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work, in sparx5_start()
636 err = sparx5_register_netdevs(sparx5); in sparx5_start()
640 sparx5_board_init(sparx5); in sparx5_start()
641 err = sparx5_register_notifier_blocks(sparx5); in sparx5_start()
644 err = -ENXIO; in sparx5_start()
645 if (sparx5->fdma_irq >= 0) { in sparx5_start()
646 if (GCB_CHIP_ID_REV_ID_GET(sparx5->chip_id) > 0) in sparx5_start()
647 err = devm_request_threaded_irq(sparx5->dev, in sparx5_start()
648 sparx5->fdma_irq, in sparx5_start()
652 "sparx5-fdma", sparx5); in sparx5_start()
654 err = sparx5_fdma_start(sparx5); in sparx5_start()
656 sparx5->fdma_irq = -ENXIO; in sparx5_start()
658 sparx5->fdma_irq = -ENXIO; in sparx5_start()
660 if (err && sparx5->xtr_irq >= 0) { in sparx5_start()
661 err = devm_request_irq(sparx5->dev, sparx5->xtr_irq, in sparx5_start()
663 "sparx5-xtr", sparx5); in sparx5_start()
665 err = sparx5_manual_injection_mode(sparx5); in sparx5_start()
667 sparx5->xtr_irq = -ENXIO; in sparx5_start()
669 sparx5->xtr_irq = -ENXIO; in sparx5_start()
674 static void sparx5_cleanup_ports(struct sparx5 *sparx5) in sparx5_cleanup_ports() argument
676 sparx5_unregister_netdevs(sparx5); in sparx5_cleanup_ports()
677 sparx5_destroy_netdevs(sparx5); in sparx5_cleanup_ports()
683 struct device_node *np = pdev->dev.of_node; in mchp_sparx5_probe()
686 struct sparx5 *sparx5; in mchp_sparx5_probe() local
689 if (!np && !pdev->dev.platform_data) in mchp_sparx5_probe()
690 return -ENODEV; in mchp_sparx5_probe()
692 sparx5 = devm_kzalloc(&pdev->dev, sizeof(*sparx5), GFP_KERNEL); in mchp_sparx5_probe()
693 if (!sparx5) in mchp_sparx5_probe()
694 return -ENOMEM; in mchp_sparx5_probe()
696 platform_set_drvdata(pdev, sparx5); in mchp_sparx5_probe()
697 sparx5->pdev = pdev; in mchp_sparx5_probe()
698 sparx5->dev = &pdev->dev; in mchp_sparx5_probe()
701 reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch"); in mchp_sparx5_probe()
703 return dev_err_probe(&pdev->dev, PTR_ERR(reset), in mchp_sparx5_probe()
708 sparx5->coreclock = SPX5_CORE_CLOCK_DEFAULT; in mchp_sparx5_probe()
710 ports = of_get_child_by_name(np, "ethernet-ports"); in mchp_sparx5_probe()
712 dev_err(sparx5->dev, "no ethernet-ports child node found\n"); in mchp_sparx5_probe()
713 return -ENODEV; in mchp_sparx5_probe()
715 sparx5->port_count = of_get_child_count(ports); in mchp_sparx5_probe()
717 configs = kcalloc(sparx5->port_count, in mchp_sparx5_probe()
720 err = -ENOMEM; in mchp_sparx5_probe()
731 dev_err(sparx5->dev, "port reg property error\n"); in mchp_sparx5_probe()
735 conf = &config->conf; in mchp_sparx5_probe()
736 conf->speed = SPEED_UNKNOWN; in mchp_sparx5_probe()
737 conf->bandwidth = SPEED_UNKNOWN; in mchp_sparx5_probe()
738 err = of_get_phy_mode(portnp, &conf->phy_mode); in mchp_sparx5_probe()
740 dev_err(sparx5->dev, "port %u: missing phy-mode\n", in mchp_sparx5_probe()
745 &conf->bandwidth); in mchp_sparx5_probe()
747 dev_err(sparx5->dev, "port %u: missing bandwidth\n", in mchp_sparx5_probe()
751 err = of_property_read_u32(portnp, "microchip,sd-sgpio", &conf->sd_sgpio); in mchp_sparx5_probe()
753 conf->sd_sgpio = ~0; in mchp_sparx5_probe()
755 sparx5->sd_sgpio_remapping = true; in mchp_sparx5_probe()
756 serdes = devm_of_phy_get(sparx5->dev, portnp, NULL); in mchp_sparx5_probe()
758 err = dev_err_probe(sparx5->dev, PTR_ERR(serdes), in mchp_sparx5_probe()
764 config->portno = portno; in mchp_sparx5_probe()
765 config->node = portnp; in mchp_sparx5_probe()
766 config->serdes = serdes; in mchp_sparx5_probe()
768 conf->media = PHY_MEDIA_DAC; in mchp_sparx5_probe()
769 conf->serdes_reset = true; in mchp_sparx5_probe()
770 conf->portmode = conf->phy_mode; in mchp_sparx5_probe()
771 conf->power_down = true; in mchp_sparx5_probe()
775 err = sparx5_create_targets(sparx5); in mchp_sparx5_probe()
779 if (!of_get_mac_address(np, sparx5->base_mac)) { in mchp_sparx5_probe()
780 dev_info(sparx5->dev, "MAC addr was not set, use random MAC\n"); in mchp_sparx5_probe()
781 eth_random_addr(sparx5->base_mac); in mchp_sparx5_probe()
782 sparx5->base_mac[5] = 0; in mchp_sparx5_probe()
785 sparx5->fdma_irq = platform_get_irq_byname(sparx5->pdev, "fdma"); in mchp_sparx5_probe()
786 sparx5->xtr_irq = platform_get_irq_byname(sparx5->pdev, "xtr"); in mchp_sparx5_probe()
789 sparx5->chip_id = spx5_rd(sparx5, GCB_CHIP_ID); in mchp_sparx5_probe()
791 sparx5->target_ct = (enum spx5_target_chiptype) in mchp_sparx5_probe()
792 GCB_CHIP_ID_PART_ID_GET(sparx5->chip_id); in mchp_sparx5_probe()
795 err = sparx5_init_switchcore(sparx5); in mchp_sparx5_probe()
797 dev_err(sparx5->dev, "Switchcore initialization error\n"); in mchp_sparx5_probe()
801 /* Initialize the LC-PLL (core clock) and set affected registers */ in mchp_sparx5_probe()
802 err = sparx5_init_coreclock(sparx5); in mchp_sparx5_probe()
804 dev_err(sparx5->dev, "LC-PLL initialization error\n"); in mchp_sparx5_probe()
808 for (idx = 0; idx < sparx5->port_count; ++idx) { in mchp_sparx5_probe()
810 if (!config->node) in mchp_sparx5_probe()
813 err = sparx5_create_port(sparx5, config); in mchp_sparx5_probe()
815 dev_err(sparx5->dev, "port create error\n"); in mchp_sparx5_probe()
820 err = sparx5_start(sparx5); in mchp_sparx5_probe()
822 dev_err(sparx5->dev, "Start failed\n"); in mchp_sparx5_probe()
828 sparx5_cleanup_ports(sparx5); in mchp_sparx5_probe()
838 struct sparx5 *sparx5 = platform_get_drvdata(pdev); in mchp_sparx5_remove() local
840 if (sparx5->xtr_irq) { in mchp_sparx5_remove()
841 disable_irq(sparx5->xtr_irq); in mchp_sparx5_remove()
842 sparx5->xtr_irq = -ENXIO; in mchp_sparx5_remove()
844 if (sparx5->fdma_irq) { in mchp_sparx5_remove()
845 disable_irq(sparx5->fdma_irq); in mchp_sparx5_remove()
846 sparx5->fdma_irq = -ENXIO; in mchp_sparx5_remove()
848 sparx5_fdma_stop(sparx5); in mchp_sparx5_remove()
849 sparx5_cleanup_ports(sparx5); in mchp_sparx5_remove()
851 sparx5_unregister_notifier_blocks(sparx5); in mchp_sparx5_remove()
857 { .compatible = "microchip,sparx5-switch" },
866 .name = "sparx5-switch",
873 MODULE_DESCRIPTION("Microchip Sparx5 switch driver");