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: Colin Foster <colin.foster@in-advantage.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # regression Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
11fc80cbb2
commit
3d7316ac81
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,8 +1,10 @@
|
||||
# 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
drivers/net/dsa/ocelot/ocelot_ext.c
Normal file
163
drivers/net/dsa/ocelot/ocelot_ext.c
Normal file
@ -0,0 +1,163 @@
|
||||
// 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);
|
Loading…
Reference in New Issue
Block a user