Commit 3d7316ac authored by Colin Foster's avatar Colin Foster Committed by Jakub Kicinski
Browse files

net: dsa: ocelot: add external ocelot switch control



Add control of an external VSC7512 chip.

Currently the four copper phy ports are fully functional. Communication to
external phys is also functional, but the SGMII / QSGMII interfaces are
currently non-functional.

Signed-off-by: default avatarColin Foster <colin.foster@in-advantage.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Reviewed-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # regression
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 11fc80cb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15155,6 +15155,7 @@ M: Colin Foster <colin.foster@in-advantage.com>
S:	Supported
F:	Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml
F:	drivers/mfd/ocelot*
F:	drivers/net/dsa/ocelot/ocelot_ext.c
F:	include/linux/mfd/ocelot.h
OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER
+20 −0
Original line number Diff line number Diff line
@@ -8,6 +8,26 @@ config NET_DSA_MSCC_FELIX_DSA_LIB
	  Its name comes from the first hardware chip to make use of it
	  (VSC9959), code named Felix.

config NET_DSA_MSCC_OCELOT_EXT
	tristate "Ocelot External Ethernet switch support"
	depends on NET_DSA && SPI
	depends on NET_VENDOR_MICROSEMI
	select MDIO_MSCC_MIIM
	select MFD_OCELOT_CORE
	select MSCC_OCELOT_SWITCH_LIB
	select NET_DSA_MSCC_FELIX_DSA_LIB
	select NET_DSA_TAG_OCELOT_8021Q
	select NET_DSA_TAG_OCELOT
	help
	  This driver supports the VSC7511, VSC7512, VSC7513 and VSC7514 chips
	  when controlled through SPI.

	  The Ocelot switch family is a set of multi-port networking chips. All
	  of these chips have the ability to be controlled externally through
	  SPI or PCIe interfaces.

	  Say "Y" here to enable external control to these chips.

config NET_DSA_MSCC_FELIX
	tristate "Ocelot / Felix Ethernet switch support"
	depends on NET_DSA && PCI
+2 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_NET_DSA_MSCC_FELIX_DSA_LIB) += mscc_felix_dsa_lib.o
obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o
obj-$(CONFIG_NET_DSA_MSCC_OCELOT_EXT) += mscc_ocelot_ext.o
obj-$(CONFIG_NET_DSA_MSCC_SEVILLE) += mscc_seville.o

mscc_felix_dsa_lib-objs := felix.o
mscc_felix-objs := felix_vsc9959.o
mscc_ocelot_ext-objs := ocelot_ext.o
mscc_seville-objs := seville_vsc9953.o
+163 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
 * Copyright 2021-2022 Innovative Advantage Inc.
 */

#include <linux/mfd/ocelot.h>
#include <linux/phylink.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <soc/mscc/ocelot.h>
#include <soc/mscc/vsc7514_regs.h>
#include "felix.h"

#define VSC7514_NUM_PORTS		11

#define OCELOT_PORT_MODE_SERDES		(OCELOT_PORT_MODE_SGMII | \
					 OCELOT_PORT_MODE_QSGMII)

static const u32 vsc7512_port_modes[VSC7514_NUM_PORTS] = {
	OCELOT_PORT_MODE_INTERNAL,
	OCELOT_PORT_MODE_INTERNAL,
	OCELOT_PORT_MODE_INTERNAL,
	OCELOT_PORT_MODE_INTERNAL,
	OCELOT_PORT_MODE_NONE,
	OCELOT_PORT_MODE_NONE,
	OCELOT_PORT_MODE_NONE,
	OCELOT_PORT_MODE_NONE,
	OCELOT_PORT_MODE_NONE,
	OCELOT_PORT_MODE_NONE,
	OCELOT_PORT_MODE_NONE,
};

static const struct ocelot_ops ocelot_ext_ops = {
	.reset		= ocelot_reset,
	.wm_enc		= ocelot_wm_enc,
	.wm_dec		= ocelot_wm_dec,
	.wm_stat	= ocelot_wm_stat,
	.port_to_netdev	= felix_port_to_netdev,
	.netdev_to_port	= felix_netdev_to_port,
};

static const char * const vsc7512_resource_names[TARGET_MAX] = {
	[SYS] = "sys",
	[REW] = "rew",
	[S0] = "s0",
	[S1] = "s1",
	[S2] = "s2",
	[QS] = "qs",
	[QSYS] = "qsys",
	[ANA] = "ana",
};

static const struct felix_info vsc7512_info = {
	.resource_names			= vsc7512_resource_names,
	.regfields			= vsc7514_regfields,
	.map				= vsc7514_regmap,
	.ops				= &ocelot_ext_ops,
	.vcap				= vsc7514_vcap_props,
	.num_mact_rows			= 1024,
	.num_ports			= VSC7514_NUM_PORTS,
	.num_tx_queues			= OCELOT_NUM_TC,
	.port_modes			= vsc7512_port_modes,
};

static int ocelot_ext_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct dsa_switch *ds;
	struct ocelot *ocelot;
	struct felix *felix;
	int err;

	felix = kzalloc(sizeof(*felix), GFP_KERNEL);
	if (!felix)
		return -ENOMEM;

	dev_set_drvdata(dev, felix);

	ocelot = &felix->ocelot;
	ocelot->dev = dev;

	ocelot->num_flooding_pgids = 1;

	felix->info = &vsc7512_info;

	ds = kzalloc(sizeof(*ds), GFP_KERNEL);
	if (!ds) {
		err = -ENOMEM;
		dev_err_probe(dev, err, "Failed to allocate DSA switch\n");
		goto err_free_felix;
	}

	ds->dev = dev;
	ds->num_ports = felix->info->num_ports;
	ds->num_tx_queues = felix->info->num_tx_queues;

	ds->ops = &felix_switch_ops;
	ds->priv = ocelot;
	felix->ds = ds;
	felix->tag_proto = DSA_TAG_PROTO_OCELOT;

	err = dsa_register_switch(ds);
	if (err) {
		dev_err_probe(dev, err, "Failed to register DSA switch\n");
		goto err_free_ds;
	}

	return 0;

err_free_ds:
	kfree(ds);
err_free_felix:
	kfree(felix);
	return err;
}

static int ocelot_ext_remove(struct platform_device *pdev)
{
	struct felix *felix = dev_get_drvdata(&pdev->dev);

	if (!felix)
		return 0;

	dsa_unregister_switch(felix->ds);

	kfree(felix->ds);
	kfree(felix);

	return 0;
}

static void ocelot_ext_shutdown(struct platform_device *pdev)
{
	struct felix *felix = dev_get_drvdata(&pdev->dev);

	if (!felix)
		return;

	dsa_switch_shutdown(felix->ds);

	dev_set_drvdata(&pdev->dev, NULL);
}

static const struct of_device_id ocelot_ext_switch_of_match[] = {
	{ .compatible = "mscc,vsc7512-switch" },
	{ },
};
MODULE_DEVICE_TABLE(of, ocelot_ext_switch_of_match);

static struct platform_driver ocelot_ext_switch_driver = {
	.driver = {
		.name = "ocelot-switch",
		.of_match_table = of_match_ptr(ocelot_ext_switch_of_match),
	},
	.probe = ocelot_ext_probe,
	.remove = ocelot_ext_remove,
	.shutdown = ocelot_ext_shutdown,
};
module_platform_driver(ocelot_ext_switch_driver);

MODULE_DESCRIPTION("External Ocelot Switch driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(MFD_OCELOT);