Commit 84705fc1 authored by Maxim Kochetkov's avatar Maxim Kochetkov Committed by David S. Miller

net: dsa: felix: introduce support for Seville VSC9953 switch

This is another switch from Vitesse / Microsemi / Microchip, that has
10 ports (8 external, 2 internal) and is integrated into the Freescale /
NXP T1040 PowerPC SoC. It is very similar to Felix from NXP LS1028A,
except that this is a platform device and Felix is a PCI device, and it
doesn't support IEEE 1588 and TSN.

Like Felix, this driver configures its own PCS on the internal MDIO bus
using a phy_device abstraction for it (yes, it will be refactored to use
a raw mdio_device, like other phylink drivers do, but let's keep it like
that for now). But unlike Felix, the MDIO bus and the PCS are not from
the same vendor. The PCS is the same QorIQ/Layerscape PCS as found in
Felix/ENETC/DPAA*, but the internal MDIO bus that is used to access it
is actually an instantiation of drivers/net/phy/mdio-mscc-miim.c. But it
would be difficult to reuse that driver (it doesn't even use regmap, and
it's less than 200 lines of code), so we hand-roll here some internal
MDIO bus accessors within seville_vsc9953.c, which serves the purpose of
driving the PCS absolutely fine.

Also, same as Felix, the PCS doesn't support dynamic reconfiguration of
SerDes protocol, so we need to do pre-validation of PHY mode from device
tree and not let phylink change it.
Signed-off-by: default avatarMaxim Kochetkov <fido_max@inbox.ru>
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 375e1314
...@@ -10,7 +10,11 @@ config NET_DSA_MSCC_FELIX ...@@ -10,7 +10,11 @@ config NET_DSA_MSCC_FELIX
select NET_DSA_TAG_OCELOT select NET_DSA_TAG_OCELOT
select FSL_ENETC_MDIO select FSL_ENETC_MDIO
help help
This driver supports the VSC9959 network switch, which is a member of This driver supports network switches from the the Vitesse /
the Vitesse / Microsemi / Microchip Ocelot family of switching cores. Microsemi / Microchip Ocelot family of switching cores that are
It is embedded as a PCIe function of the NXP LS1028A ENETC integrated connected to their host CPU via Ethernet.
endpoint. The following switches are supported:
- VSC9959 (Felix): embedded as a PCIe function of the NXP LS1028A
ENETC integrated endpoint.
- VSC9953 (Seville): embedded as a platform device on the
NXP T1040 SoC.
...@@ -3,4 +3,5 @@ obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o ...@@ -3,4 +3,5 @@ obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o
mscc_felix-objs := \ mscc_felix-objs := \
felix.o \ felix.o \
felix_vsc9959.o felix_vsc9959.o \
seville_vsc9953.o
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <soc/mscc/ocelot_ana.h> #include <soc/mscc/ocelot_ana.h>
#include <soc/mscc/ocelot_ptp.h> #include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include <linux/platform_device.h>
#include <linux/packing.h> #include <linux/packing.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_net.h> #include <linux/of_net.h>
...@@ -820,13 +821,24 @@ const struct dsa_switch_ops felix_switch_ops = { ...@@ -820,13 +821,24 @@ const struct dsa_switch_ops felix_switch_ops = {
static int __init felix_init(void) static int __init felix_init(void)
{ {
return pci_register_driver(&felix_vsc9959_pci_driver); int err;
err = pci_register_driver(&felix_vsc9959_pci_driver);
if (err)
return err;
err = platform_driver_register(&seville_vsc9953_driver);
if (err)
return err;
return 0;
} }
module_init(felix_init); module_init(felix_init);
static void __exit felix_exit(void) static void __exit felix_exit(void)
{ {
pci_unregister_driver(&felix_vsc9959_pci_driver); pci_unregister_driver(&felix_vsc9959_pci_driver);
platform_driver_unregister(&seville_vsc9953_driver);
} }
module_exit(felix_exit); module_exit(felix_exit);
......
...@@ -51,6 +51,7 @@ struct felix_info { ...@@ -51,6 +51,7 @@ struct felix_info {
extern const struct dsa_switch_ops felix_switch_ops; extern const struct dsa_switch_ops felix_switch_ops;
extern struct pci_driver felix_vsc9959_pci_driver; extern struct pci_driver felix_vsc9959_pci_driver;
extern struct platform_driver seville_vsc9953_driver;
/* DSA glue / front-end for struct ocelot */ /* DSA glue / front-end for struct ocelot */
struct felix { struct felix {
...@@ -63,4 +64,15 @@ struct felix { ...@@ -63,4 +64,15 @@ struct felix {
resource_size_t imdio_base; resource_size_t imdio_base;
}; };
void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
struct phylink_link_state *state);
void vsc9959_pcs_config(struct ocelot *ocelot, int port,
unsigned int link_an_mode,
const struct phylink_link_state *state);
void vsc9959_pcs_link_up(struct ocelot *ocelot, int port,
unsigned int link_an_mode,
phy_interface_t interface,
int speed, int duplex);
void vsc9959_mdio_bus_free(struct ocelot *ocelot);
#endif #endif
...@@ -852,9 +852,9 @@ static void vsc9959_pcs_config_usxgmii(struct phy_device *pcs, ...@@ -852,9 +852,9 @@ static void vsc9959_pcs_config_usxgmii(struct phy_device *pcs,
USXGMII_ADVERTISE_FDX); USXGMII_ADVERTISE_FDX);
} }
static void vsc9959_pcs_config(struct ocelot *ocelot, int port, void vsc9959_pcs_config(struct ocelot *ocelot, int port,
unsigned int link_an_mode, unsigned int link_an_mode,
const struct phylink_link_state *state) const struct phylink_link_state *state)
{ {
struct felix *felix = ocelot_to_felix(ocelot); struct felix *felix = ocelot_to_felix(ocelot);
struct phy_device *pcs = felix->pcs[port]; struct phy_device *pcs = felix->pcs[port];
...@@ -965,10 +965,10 @@ static void vsc9959_pcs_link_up_2500basex(struct phy_device *pcs, ...@@ -965,10 +965,10 @@ static void vsc9959_pcs_link_up_2500basex(struct phy_device *pcs,
phy_clear_bits(pcs, MII_BMCR, BMCR_ANENABLE); phy_clear_bits(pcs, MII_BMCR, BMCR_ANENABLE);
} }
static void vsc9959_pcs_link_up(struct ocelot *ocelot, int port, void vsc9959_pcs_link_up(struct ocelot *ocelot, int port,
unsigned int link_an_mode, unsigned int link_an_mode,
phy_interface_t interface, phy_interface_t interface,
int speed, int duplex) int speed, int duplex)
{ {
struct felix *felix = ocelot_to_felix(ocelot); struct felix *felix = ocelot_to_felix(ocelot);
struct phy_device *pcs = felix->pcs[port]; struct phy_device *pcs = felix->pcs[port];
...@@ -1096,8 +1096,8 @@ static void vsc9959_pcs_link_state_usxgmii(struct phy_device *pcs, ...@@ -1096,8 +1096,8 @@ static void vsc9959_pcs_link_state_usxgmii(struct phy_device *pcs,
pcs->duplex = DUPLEX_HALF; pcs->duplex = DUPLEX_HALF;
} }
static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port, void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
struct phylink_link_state *state) struct phylink_link_state *state)
{ {
struct felix *felix = ocelot_to_felix(ocelot); struct felix *felix = ocelot_to_felix(ocelot);
struct phy_device *pcs = felix->pcs[port]; struct phy_device *pcs = felix->pcs[port];
...@@ -1286,7 +1286,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) ...@@ -1286,7 +1286,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
return 0; return 0;
} }
static void vsc9959_mdio_bus_free(struct ocelot *ocelot) void vsc9959_mdio_bus_free(struct ocelot *ocelot)
{ {
struct felix *felix = ocelot_to_felix(ocelot); struct felix *felix = ocelot_to_felix(ocelot);
int port; int port;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment