Merge branch 'GEHC-Bx50-Switch-Support'

Sebastian Reichel says:

====================
GEHC Bx50 Switch Support

This adds support for the internal switch found in GE Healthcare
B450v3, B650v3 and B850v3. All devices use a GPIO bitbanged MDIO
bus to communicate with the switch and a PCIe based network card
for exchanging network data. The cpu network data link requires,
that the switch's internal phy interface is enabled, so support
for that is added by the first patch in this series.

The patch series is based on v4.15-rc8.

Changes since PATCHv4:
 * Introduce dsa_port_link_(un)register_of and mark the fixed
   variant static.
 * Update patch description to describe the phy<->phy connection
   from i210 to the Marvell switch
Changes since PATCHv3:
 * Enable the phy in dsa_port_setup() instead of abusing the
   fixed link setup function
Changes since PATCHv2:
 * Add phy nodes to switch in bx50.dtsi and reference them
   from switch ports
 * Enable cpu-port's phy based on 'phy-handle' instead of 'phy-mode'
Changes since PATCHv1:
 * Use 'marvell,mv88e6085' instead of introducing compatible
   string for mv88e6240.
 * Fix indention of DT nodes
 * Only enable 'cpu' phy, if explicitly set to "internal".
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-01-23 19:22:39 -05:00
commit c89b517da1
8 changed files with 332 additions and 37 deletions

View File

@ -112,3 +112,55 @@
line-name = "PCA9539-P07";
};
};
&pci_root {
/* Intel Corporation I210 Gigabit Network Connection */
switch_nic: ethernet@3,0 {
compatible = "pci8086,1533";
reg = <0x00010000 0 0 0 0>;
};
};
&switch_ports {
port@0 {
reg = <0>;
label = "enacq";
phy-handle = <&switchphy0>;
};
port@1 {
reg = <1>;
label = "eneport1";
phy-handle = <&switchphy1>;
};
port@2 {
reg = <2>;
label = "enix";
phy-handle = <&switchphy2>;
};
port@3 {
reg = <3>;
label = "enid";
phy-handle = <&switchphy3>;
};
port@4 {
reg = <4>;
label = "cpu";
ethernet = <&switch_nic>;
phy-handle = <&switchphy4>;
};
port@5 {
reg = <5>;
label = "enembc";
/* connected to Ethernet MAC of AT91RM9200 in MII mode */
fixed-link {
speed = <100>;
full-duplex;
};
};
};

View File

@ -111,3 +111,55 @@
fsl,tx-cal-45-dp-ohms = <55>;
fsl,tx-d-cal = <100>;
};
&pci_root {
/* Intel Corporation I210 Gigabit Network Connection */
switch_nic: ethernet@3,0 {
compatible = "pci8086,1533";
reg = <0x00010000 0 0 0 0>;
};
};
&switch_ports {
port@0 {
reg = <0>;
label = "enacq";
phy-handle = <&switchphy0>;
};
port@1 {
reg = <1>;
label = "eneport1";
phy-handle = <&switchphy1>;
};
port@2 {
reg = <2>;
label = "enix";
phy-handle = <&switchphy2>;
};
port@3 {
reg = <3>;
label = "enid";
phy-handle = <&switchphy3>;
};
port@4 {
reg = <4>;
label = "cpu";
ethernet = <&switch_nic>;
phy-handle = <&switchphy4>;
};
port@5 {
reg = <5>;
label = "enembc";
/* connected to Ethernet MAC of AT91RM9200 in MII mode */
fixed-link {
speed = <100>;
full-duplex;
};
};
};

View File

@ -212,3 +212,78 @@
};
};
};
&pci_root {
/* PLX Technology, Inc. PEX 8605 PCI Express 4-port Gen2 Switch */
bridge@1,0 {
compatible = "pci10b5,8605";
reg = <0x00010000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
bridge@2,1 {
compatible = "pci10b5,8605";
reg = <0x00020800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
/* Intel Corporation I210 Gigabit Network Connection */
ethernet@3,0 {
compatible = "pci8086,1533";
reg = <0x00030000 0 0 0 0>;
};
};
bridge@2,2 {
compatible = "pci10b5,8605";
reg = <0x00021000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
/* Intel Corporation I210 Gigabit Network Connection */
switch_nic: ethernet@4,0 {
compatible = "pci8086,1533";
reg = <0x00040000 0 0 0 0>;
};
};
};
};
&switch_ports {
port@0 {
reg = <0>;
label = "eneport1";
phy-handle = <&switchphy0>;
};
port@1 {
reg = <1>;
label = "eneport2";
phy-handle = <&switchphy1>;
};
port@2 {
reg = <2>;
label = "enix";
phy-handle = <&switchphy2>;
};
port@3 {
reg = <3>;
label = "enid";
phy-handle = <&switchphy3>;
};
port@4 {
reg = <4>;
label = "cpu";
ethernet = <&switch_nic>;
phy-handle = <&switchphy4>;
};
};

View File

@ -92,6 +92,56 @@
mux-int-port = <1>;
mux-ext-port = <4>;
};
aliases {
mdio-gpio0 = &mdio0;
};
mdio0: mdio-gpio {
compatible = "virtual,mdio-gpio";
gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>, /* mdc */
<&gpio2 7 GPIO_ACTIVE_HIGH>; /* mdio */
#address-cells = <1>;
#size-cells = <0>;
switch@0 {
compatible = "marvell,mv88e6085"; /* 88e6240*/
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
switch_ports: ports {
#address-cells = <1>;
#size-cells = <0>;
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
switchphy0: switchphy@0 {
reg = <0>;
};
switchphy1: switchphy@1 {
reg = <1>;
};
switchphy2: switchphy@2 {
reg = <2>;
};
switchphy3: switchphy@3 {
reg = <3>;
};
switchphy4: switchphy@4 {
reg = <4>;
};
};
};
};
};
&ecspi5 {
@ -326,3 +376,15 @@
tcxo-clock-frequency = <26000000>;
};
};
&pcie {
/* Synopsys, Inc. Device */
pci_root: root@0,0 {
compatible = "pci16c3,abcd";
reg = <0x00000000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
};
};

View File

@ -271,13 +271,12 @@ static int dsa_port_setup(struct dsa_port *dp)
break;
case DSA_PORT_TYPE_CPU:
case DSA_PORT_TYPE_DSA:
err = dsa_port_fixed_link_register_of(dp);
err = dsa_port_link_register_of(dp);
if (err) {
dev_err(ds->dev, "failed to register fixed link for port %d.%d\n",
dev_err(ds->dev, "failed to setup link for port %d.%d\n",
ds->index, dp->index);
return err;
}
break;
case DSA_PORT_TYPE_USER:
err = dsa_slave_create(dp);
@ -301,7 +300,7 @@ static void dsa_port_teardown(struct dsa_port *dp)
break;
case DSA_PORT_TYPE_CPU:
case DSA_PORT_TYPE_DSA:
dsa_port_fixed_link_unregister_of(dp);
dsa_port_link_unregister_of(dp);
break;
case DSA_PORT_TYPE_USER:
if (dp->slave) {

View File

@ -166,8 +166,8 @@ int dsa_port_vlan_add(struct dsa_port *dp,
struct switchdev_trans *trans);
int dsa_port_vlan_del(struct dsa_port *dp,
const struct switchdev_obj_port_vlan *vlan);
int dsa_port_fixed_link_register_of(struct dsa_port *dp);
void dsa_port_fixed_link_unregister_of(struct dsa_port *dp);
int dsa_port_link_register_of(struct dsa_port *dp);
void dsa_port_link_unregister_of(struct dsa_port *dp);
/* slave.c */
extern const struct dsa_device_ops notag_netdev_ops;

View File

@ -86,7 +86,7 @@ static int dsa_cpu_dsa_setups(struct dsa_switch *ds)
if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)))
continue;
ret = dsa_port_fixed_link_register_of(&ds->ports[port]);
ret = dsa_port_link_register_of(&ds->ports[port]);
if (ret)
return ret;
}
@ -275,7 +275,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
for (port = 0; port < ds->num_ports; port++) {
if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)))
continue;
dsa_port_fixed_link_unregister_of(&ds->ports[port]);
dsa_port_link_unregister_of(&ds->ports[port]);
}
if (ds->slave_mii_bus && ds->ops->phy_read)

View File

@ -273,7 +273,56 @@ int dsa_port_vlan_del(struct dsa_port *dp,
return 0;
}
int dsa_port_fixed_link_register_of(struct dsa_port *dp)
static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
{
struct device_node *port_dn = dp->dn;
struct device_node *phy_dn;
struct dsa_switch *ds = dp->ds;
struct phy_device *phydev;
int port = dp->index;
int err = 0;
phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
if (!phy_dn)
return 0;
phydev = of_phy_find_device(phy_dn);
if (!phydev) {
err = -EPROBE_DEFER;
goto err_put_of;
}
if (enable) {
err = genphy_config_init(phydev);
if (err < 0)
goto err_put_dev;
err = genphy_resume(phydev);
if (err < 0)
goto err_put_dev;
err = genphy_read_status(phydev);
if (err < 0)
goto err_put_dev;
} else {
err = genphy_suspend(phydev);
if (err < 0)
goto err_put_dev;
}
if (ds->ops->adjust_link)
ds->ops->adjust_link(ds, port, phydev);
dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev));
err_put_dev:
put_device(&phydev->mdio.dev);
err_put_of:
of_node_put(phy_dn);
return err;
}
static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
{
struct device_node *dn = dp->dn;
struct dsa_switch *ds = dp->ds;
@ -282,38 +331,44 @@ int dsa_port_fixed_link_register_of(struct dsa_port *dp)
int mode;
int err;
if (of_phy_is_fixed_link(dn)) {
err = of_phy_register_fixed_link(dn);
if (err) {
dev_err(ds->dev,
"failed to register the fixed PHY of port %d\n",
port);
return err;
}
phydev = of_phy_find_device(dn);
mode = of_get_phy_mode(dn);
if (mode < 0)
mode = PHY_INTERFACE_MODE_NA;
phydev->interface = mode;
genphy_config_init(phydev);
genphy_read_status(phydev);
if (ds->ops->adjust_link)
ds->ops->adjust_link(ds, port, phydev);
put_device(&phydev->mdio.dev);
err = of_phy_register_fixed_link(dn);
if (err) {
dev_err(ds->dev,
"failed to register the fixed PHY of port %d\n",
port);
return err;
}
phydev = of_phy_find_device(dn);
mode = of_get_phy_mode(dn);
if (mode < 0)
mode = PHY_INTERFACE_MODE_NA;
phydev->interface = mode;
genphy_config_init(phydev);
genphy_read_status(phydev);
if (ds->ops->adjust_link)
ds->ops->adjust_link(ds, port, phydev);
put_device(&phydev->mdio.dev);
return 0;
}
void dsa_port_fixed_link_unregister_of(struct dsa_port *dp)
int dsa_port_link_register_of(struct dsa_port *dp)
{
struct device_node *dn = dp->dn;
if (of_phy_is_fixed_link(dn))
of_phy_deregister_fixed_link(dn);
if (of_phy_is_fixed_link(dp->dn))
return dsa_port_fixed_link_register_of(dp);
else
return dsa_port_setup_phy_of(dp, true);
}
void dsa_port_link_unregister_of(struct dsa_port *dp)
{
if (of_phy_is_fixed_link(dp->dn))
of_phy_deregister_fixed_link(dp->dn);
else
dsa_port_setup_phy_of(dp, false);
}