xref: /linux/drivers/net/dsa/ocelot/ocelot_ext.c (revision ef1a99c65edb504c509a5c4aa865830867df6e7b)
13d7316acSColin Foster // SPDX-License-Identifier: (GPL-2.0 OR MIT)
23d7316acSColin Foster /*
33d7316acSColin Foster  * Copyright 2021-2022 Innovative Advantage Inc.
43d7316acSColin Foster  */
53d7316acSColin Foster 
63d7316acSColin Foster #include <linux/mfd/ocelot.h>
73d7316acSColin Foster #include <linux/phylink.h>
83d7316acSColin Foster #include <linux/platform_device.h>
93d7316acSColin Foster #include <linux/regmap.h>
103d7316acSColin Foster #include <soc/mscc/ocelot.h>
113d7316acSColin Foster #include <soc/mscc/vsc7514_regs.h>
123d7316acSColin Foster #include "felix.h"
133d7316acSColin Foster 
143d7316acSColin Foster #define VSC7514_NUM_PORTS		11
153d7316acSColin Foster 
163d7316acSColin Foster #define OCELOT_PORT_MODE_SERDES		(OCELOT_PORT_MODE_SGMII | \
173d7316acSColin Foster 					 OCELOT_PORT_MODE_QSGMII)
183d7316acSColin Foster 
193d7316acSColin Foster static const u32 vsc7512_port_modes[VSC7514_NUM_PORTS] = {
203d7316acSColin Foster 	OCELOT_PORT_MODE_INTERNAL,
213d7316acSColin Foster 	OCELOT_PORT_MODE_INTERNAL,
223d7316acSColin Foster 	OCELOT_PORT_MODE_INTERNAL,
233d7316acSColin Foster 	OCELOT_PORT_MODE_INTERNAL,
243d7316acSColin Foster 	OCELOT_PORT_MODE_NONE,
253d7316acSColin Foster 	OCELOT_PORT_MODE_NONE,
263d7316acSColin Foster 	OCELOT_PORT_MODE_NONE,
273d7316acSColin Foster 	OCELOT_PORT_MODE_NONE,
283d7316acSColin Foster 	OCELOT_PORT_MODE_NONE,
293d7316acSColin Foster 	OCELOT_PORT_MODE_NONE,
303d7316acSColin Foster 	OCELOT_PORT_MODE_NONE,
313d7316acSColin Foster };
323d7316acSColin Foster 
333d7316acSColin Foster static const struct ocelot_ops ocelot_ext_ops = {
343d7316acSColin Foster 	.reset		= ocelot_reset,
353d7316acSColin Foster 	.wm_enc		= ocelot_wm_enc,
363d7316acSColin Foster 	.wm_dec		= ocelot_wm_dec,
373d7316acSColin Foster 	.wm_stat	= ocelot_wm_stat,
383d7316acSColin Foster 	.port_to_netdev	= felix_port_to_netdev,
393d7316acSColin Foster 	.netdev_to_port	= felix_netdev_to_port,
403d7316acSColin Foster };
413d7316acSColin Foster 
423d7316acSColin Foster static const char * const vsc7512_resource_names[TARGET_MAX] = {
433d7316acSColin Foster 	[SYS] = "sys",
443d7316acSColin Foster 	[REW] = "rew",
453d7316acSColin Foster 	[S0] = "s0",
463d7316acSColin Foster 	[S1] = "s1",
473d7316acSColin Foster 	[S2] = "s2",
483d7316acSColin Foster 	[QS] = "qs",
493d7316acSColin Foster 	[QSYS] = "qsys",
503d7316acSColin Foster 	[ANA] = "ana",
513d7316acSColin Foster };
523d7316acSColin Foster 
533d7316acSColin Foster static const struct felix_info vsc7512_info = {
543d7316acSColin Foster 	.resource_names			= vsc7512_resource_names,
553d7316acSColin Foster 	.regfields			= vsc7514_regfields,
563d7316acSColin Foster 	.map				= vsc7514_regmap,
573d7316acSColin Foster 	.ops				= &ocelot_ext_ops,
583d7316acSColin Foster 	.vcap				= vsc7514_vcap_props,
593d7316acSColin Foster 	.num_mact_rows			= 1024,
603d7316acSColin Foster 	.num_ports			= VSC7514_NUM_PORTS,
613d7316acSColin Foster 	.num_tx_queues			= OCELOT_NUM_TC,
623d7316acSColin Foster 	.port_modes			= vsc7512_port_modes,
633d7316acSColin Foster };
643d7316acSColin Foster 
653d7316acSColin Foster static int ocelot_ext_probe(struct platform_device *pdev)
663d7316acSColin Foster {
673d7316acSColin Foster 	struct device *dev = &pdev->dev;
683d7316acSColin Foster 	struct dsa_switch *ds;
693d7316acSColin Foster 	struct ocelot *ocelot;
703d7316acSColin Foster 	struct felix *felix;
713d7316acSColin Foster 	int err;
723d7316acSColin Foster 
733d7316acSColin Foster 	felix = kzalloc(sizeof(*felix), GFP_KERNEL);
743d7316acSColin Foster 	if (!felix)
753d7316acSColin Foster 		return -ENOMEM;
763d7316acSColin Foster 
773d7316acSColin Foster 	dev_set_drvdata(dev, felix);
783d7316acSColin Foster 
793d7316acSColin Foster 	ocelot = &felix->ocelot;
803d7316acSColin Foster 	ocelot->dev = dev;
813d7316acSColin Foster 
823d7316acSColin Foster 	ocelot->num_flooding_pgids = 1;
833d7316acSColin Foster 
843d7316acSColin Foster 	felix->info = &vsc7512_info;
853d7316acSColin Foster 
863d7316acSColin Foster 	ds = kzalloc(sizeof(*ds), GFP_KERNEL);
873d7316acSColin Foster 	if (!ds) {
883d7316acSColin Foster 		err = -ENOMEM;
893d7316acSColin Foster 		dev_err_probe(dev, err, "Failed to allocate DSA switch\n");
903d7316acSColin Foster 		goto err_free_felix;
913d7316acSColin Foster 	}
923d7316acSColin Foster 
933d7316acSColin Foster 	ds->dev = dev;
943d7316acSColin Foster 	ds->num_ports = felix->info->num_ports;
953d7316acSColin Foster 	ds->num_tx_queues = felix->info->num_tx_queues;
963d7316acSColin Foster 
973d7316acSColin Foster 	ds->ops = &felix_switch_ops;
983d7316acSColin Foster 	ds->priv = ocelot;
993d7316acSColin Foster 	felix->ds = ds;
1003d7316acSColin Foster 	felix->tag_proto = DSA_TAG_PROTO_OCELOT;
1013d7316acSColin Foster 
1023d7316acSColin Foster 	err = dsa_register_switch(ds);
1033d7316acSColin Foster 	if (err) {
1043d7316acSColin Foster 		dev_err_probe(dev, err, "Failed to register DSA switch\n");
1053d7316acSColin Foster 		goto err_free_ds;
1063d7316acSColin Foster 	}
1073d7316acSColin Foster 
1083d7316acSColin Foster 	return 0;
1093d7316acSColin Foster 
1103d7316acSColin Foster err_free_ds:
1113d7316acSColin Foster 	kfree(ds);
1123d7316acSColin Foster err_free_felix:
1133d7316acSColin Foster 	kfree(felix);
1143d7316acSColin Foster 	return err;
1153d7316acSColin Foster }
1163d7316acSColin Foster 
1173d7316acSColin Foster static int ocelot_ext_remove(struct platform_device *pdev)
1183d7316acSColin Foster {
1193d7316acSColin Foster 	struct felix *felix = dev_get_drvdata(&pdev->dev);
1203d7316acSColin Foster 
1213d7316acSColin Foster 	if (!felix)
1223d7316acSColin Foster 		return 0;
1233d7316acSColin Foster 
1243d7316acSColin Foster 	dsa_unregister_switch(felix->ds);
1253d7316acSColin Foster 
1263d7316acSColin Foster 	kfree(felix->ds);
1273d7316acSColin Foster 	kfree(felix);
1283d7316acSColin Foster 
1293d7316acSColin Foster 	return 0;
1303d7316acSColin Foster }
1313d7316acSColin Foster 
1323d7316acSColin Foster static void ocelot_ext_shutdown(struct platform_device *pdev)
1333d7316acSColin Foster {
1343d7316acSColin Foster 	struct felix *felix = dev_get_drvdata(&pdev->dev);
1353d7316acSColin Foster 
1363d7316acSColin Foster 	if (!felix)
1373d7316acSColin Foster 		return;
1383d7316acSColin Foster 
1393d7316acSColin Foster 	dsa_switch_shutdown(felix->ds);
1403d7316acSColin Foster 
1413d7316acSColin Foster 	dev_set_drvdata(&pdev->dev, NULL);
1423d7316acSColin Foster }
1433d7316acSColin Foster 
1443d7316acSColin Foster static const struct of_device_id ocelot_ext_switch_of_match[] = {
1453d7316acSColin Foster 	{ .compatible = "mscc,vsc7512-switch" },
1463d7316acSColin Foster 	{ },
1473d7316acSColin Foster };
1483d7316acSColin Foster MODULE_DEVICE_TABLE(of, ocelot_ext_switch_of_match);
1493d7316acSColin Foster 
1503d7316acSColin Foster static struct platform_driver ocelot_ext_switch_driver = {
1513d7316acSColin Foster 	.driver = {
152*ef1a99c6SVladimir Oltean 		.name = "ocelot-ext-switch",
1533d7316acSColin Foster 		.of_match_table = of_match_ptr(ocelot_ext_switch_of_match),
1543d7316acSColin Foster 	},
1553d7316acSColin Foster 	.probe = ocelot_ext_probe,
1563d7316acSColin Foster 	.remove = ocelot_ext_remove,
1573d7316acSColin Foster 	.shutdown = ocelot_ext_shutdown,
1583d7316acSColin Foster };
1593d7316acSColin Foster module_platform_driver(ocelot_ext_switch_driver);
1603d7316acSColin Foster 
1613d7316acSColin Foster MODULE_DESCRIPTION("External Ocelot Switch driver");
1623d7316acSColin Foster MODULE_LICENSE("GPL");
1633d7316acSColin Foster MODULE_IMPORT_NS(MFD_OCELOT);
164