2222#include <linux/of_irq.h>
2323#include <linux/of_address.h>
2424#include <linux/of_net.h>
25+ #include <linux/of_mdio.h>
2526#include <net/dsa.h>
2627#include <linux/ethtool.h>
2728#include <linux/if_bridge.h>
@@ -836,6 +837,66 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
836837 return 0 ;
837838}
838839
840+ static int bcm_sf2_sw_indir_rw (struct bcm_sf2_priv * priv , int op , int addr ,
841+ int regnum , u16 val )
842+ {
843+ int ret = 0 ;
844+ u32 reg ;
845+
846+ reg = reg_readl (priv , REG_SWITCH_CNTRL );
847+ reg |= MDIO_MASTER_SEL ;
848+ reg_writel (priv , reg , REG_SWITCH_CNTRL );
849+
850+ /* Page << 8 | offset */
851+ reg = 0x70 ;
852+ reg <<= 2 ;
853+ core_writel (priv , addr , reg );
854+
855+ /* Page << 8 | offset */
856+ reg = 0x80 << 8 | regnum << 1 ;
857+ reg <<= 2 ;
858+
859+ if (op )
860+ ret = core_readl (priv , reg );
861+ else
862+ core_writel (priv , val , reg );
863+
864+ reg = reg_readl (priv , REG_SWITCH_CNTRL );
865+ reg &= ~MDIO_MASTER_SEL ;
866+ reg_writel (priv , reg , REG_SWITCH_CNTRL );
867+
868+ return ret & 0xffff ;
869+ }
870+
871+ static int bcm_sf2_sw_mdio_read (struct mii_bus * bus , int addr , int regnum )
872+ {
873+ struct bcm_sf2_priv * priv = bus -> priv ;
874+
875+ /* Intercept reads from Broadcom pseudo-PHY address, else, send
876+ * them to our master MDIO bus controller
877+ */
878+ if (addr == BRCM_PSEUDO_PHY_ADDR && priv -> indir_phy_mask & BIT (addr ))
879+ return bcm_sf2_sw_indir_rw (priv , 1 , addr , regnum , 0 );
880+ else
881+ return mdiobus_read (priv -> master_mii_bus , addr , regnum );
882+ }
883+
884+ static int bcm_sf2_sw_mdio_write (struct mii_bus * bus , int addr , int regnum ,
885+ u16 val )
886+ {
887+ struct bcm_sf2_priv * priv = bus -> priv ;
888+
889+ /* Intercept writes to the Broadcom pseudo-PHY address, else,
890+ * send them to our master MDIO bus controller
891+ */
892+ if (addr == BRCM_PSEUDO_PHY_ADDR && priv -> indir_phy_mask & BIT (addr ))
893+ bcm_sf2_sw_indir_rw (priv , 0 , addr , regnum , val );
894+ else
895+ mdiobus_write (priv -> master_mii_bus , addr , regnum , val );
896+
897+ return 0 ;
898+ }
899+
839900static irqreturn_t bcm_sf2_switch_0_isr (int irq , void * dev_id )
840901{
841902 struct bcm_sf2_priv * priv = dev_id ;
@@ -932,6 +993,72 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,
932993 }
933994}
934995
996+ static int bcm_sf2_mdio_register (struct dsa_switch * ds )
997+ {
998+ struct bcm_sf2_priv * priv = ds_to_priv (ds );
999+ struct device_node * dn ;
1000+ static int index ;
1001+ int err ;
1002+
1003+ /* Find our integrated MDIO bus node */
1004+ dn = of_find_compatible_node (NULL , NULL , "brcm,unimac-mdio" );
1005+ priv -> master_mii_bus = of_mdio_find_bus (dn );
1006+ if (!priv -> master_mii_bus )
1007+ return - EPROBE_DEFER ;
1008+
1009+ get_device (& priv -> master_mii_bus -> dev );
1010+ priv -> master_mii_dn = dn ;
1011+
1012+ priv -> slave_mii_bus = devm_mdiobus_alloc (ds -> dev );
1013+ if (!priv -> slave_mii_bus )
1014+ return - ENOMEM ;
1015+
1016+ priv -> slave_mii_bus -> priv = priv ;
1017+ priv -> slave_mii_bus -> name = "sf2 slave mii" ;
1018+ priv -> slave_mii_bus -> read = bcm_sf2_sw_mdio_read ;
1019+ priv -> slave_mii_bus -> write = bcm_sf2_sw_mdio_write ;
1020+ snprintf (priv -> slave_mii_bus -> id , MII_BUS_ID_SIZE , "sf2-%d" ,
1021+ index ++ );
1022+ priv -> slave_mii_bus -> dev .of_node = dn ;
1023+
1024+ /* Include the pseudo-PHY address to divert reads towards our
1025+ * workaround. This is only required for 7445D0, since 7445E0
1026+ * disconnects the internal switch pseudo-PHY such that we can use the
1027+ * regular SWITCH_MDIO master controller instead.
1028+ *
1029+ * Here we flag the pseudo PHY as needing special treatment and would
1030+ * otherwise make all other PHY read/writes go to the master MDIO bus
1031+ * controller that comes with this switch backed by the "mdio-unimac"
1032+ * driver.
1033+ */
1034+ if (of_machine_is_compatible ("brcm,bcm7445d0" ))
1035+ priv -> indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR );
1036+ else
1037+ priv -> indir_phy_mask = 0 ;
1038+
1039+ ds -> phys_mii_mask = priv -> indir_phy_mask ;
1040+ ds -> slave_mii_bus = priv -> slave_mii_bus ;
1041+ priv -> slave_mii_bus -> parent = ds -> dev -> parent ;
1042+ priv -> slave_mii_bus -> phy_mask = ~priv -> indir_phy_mask ;
1043+
1044+ if (dn )
1045+ err = of_mdiobus_register (priv -> slave_mii_bus , dn );
1046+ else
1047+ err = mdiobus_register (priv -> slave_mii_bus );
1048+
1049+ if (err )
1050+ of_node_put (dn );
1051+
1052+ return err ;
1053+ }
1054+
1055+ static void bcm_sf2_mdio_unregister (struct bcm_sf2_priv * priv )
1056+ {
1057+ mdiobus_unregister (priv -> slave_mii_bus );
1058+ if (priv -> master_mii_dn )
1059+ of_node_put (priv -> master_mii_dn );
1060+ }
1061+
9351062static int bcm_sf2_sw_setup (struct dsa_switch * ds )
9361063{
9371064 const char * reg_names [BCM_SF2_REGS_NUM ] = BCM_SF2_REGS_NAME ;
@@ -972,6 +1099,12 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
9721099 goto out_unmap ;
9731100 }
9741101
1102+ ret = bcm_sf2_mdio_register (ds );
1103+ if (ret ) {
1104+ pr_err ("failed to register MDIO bus\n" );
1105+ goto out_unmap ;
1106+ }
1107+
9751108 /* Disable all interrupts and request them */
9761109 bcm_sf2_intr_disable (priv );
9771110
@@ -1017,23 +1150,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
10171150 bcm_sf2_port_disable (ds , port , NULL );
10181151 }
10191152
1020- /* Include the pseudo-PHY address and the broadcast PHY address to
1021- * divert reads towards our workaround. This is only required for
1022- * 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such
1023- * that we can use the regular SWITCH_MDIO master controller instead.
1024- *
1025- * By default, DSA initializes ds->phys_mii_mask to
1026- * ds->enabled_port_mask to have a 1:1 mapping between Port address
1027- * and PHY address in order to utilize the slave_mii_bus instance to
1028- * read from Port PHYs. This is not what we want here, so we
1029- * initialize phys_mii_mask 0 to always utilize the "master" MDIO
1030- * bus backed by the "mdio-unimac" driver.
1031- */
1032- if (of_machine_is_compatible ("brcm,bcm7445d0" ))
1033- ds -> phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR ) | (1 << 0 ));
1034- else
1035- ds -> phys_mii_mask = 0 ;
1036-
10371153 rev = reg_readl (priv , REG_SWITCH_REVISION );
10381154 priv -> hw_params .top_rev = (rev >> SWITCH_TOP_REV_SHIFT ) &
10391155 SWITCH_TOP_REV_MASK ;
@@ -1058,6 +1174,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
10581174 iounmap (* base );
10591175 base ++ ;
10601176 }
1177+ bcm_sf2_mdio_unregister (priv );
10611178 return ret ;
10621179}
10631180
@@ -1078,68 +1195,6 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
10781195 return priv -> hw_params .gphy_rev ;
10791196}
10801197
1081- static int bcm_sf2_sw_indir_rw (struct dsa_switch * ds , int op , int addr ,
1082- int regnum , u16 val )
1083- {
1084- struct bcm_sf2_priv * priv = ds_to_priv (ds );
1085- int ret = 0 ;
1086- u32 reg ;
1087-
1088- reg = reg_readl (priv , REG_SWITCH_CNTRL );
1089- reg |= MDIO_MASTER_SEL ;
1090- reg_writel (priv , reg , REG_SWITCH_CNTRL );
1091-
1092- /* Page << 8 | offset */
1093- reg = 0x70 ;
1094- reg <<= 2 ;
1095- core_writel (priv , addr , reg );
1096-
1097- /* Page << 8 | offset */
1098- reg = 0x80 << 8 | regnum << 1 ;
1099- reg <<= 2 ;
1100-
1101- if (op )
1102- ret = core_readl (priv , reg );
1103- else
1104- core_writel (priv , val , reg );
1105-
1106- reg = reg_readl (priv , REG_SWITCH_CNTRL );
1107- reg &= ~MDIO_MASTER_SEL ;
1108- reg_writel (priv , reg , REG_SWITCH_CNTRL );
1109-
1110- return ret & 0xffff ;
1111- }
1112-
1113- static int bcm_sf2_sw_phy_read (struct dsa_switch * ds , int addr , int regnum )
1114- {
1115- /* Intercept reads from the MDIO broadcast address or Broadcom
1116- * pseudo-PHY address
1117- */
1118- switch (addr ) {
1119- case 0 :
1120- case BRCM_PSEUDO_PHY_ADDR :
1121- return bcm_sf2_sw_indir_rw (ds , 1 , addr , regnum , 0 );
1122- default :
1123- return 0xffff ;
1124- }
1125- }
1126-
1127- static int bcm_sf2_sw_phy_write (struct dsa_switch * ds , int addr , int regnum ,
1128- u16 val )
1129- {
1130- /* Intercept writes to the MDIO broadcast address or Broadcom
1131- * pseudo-PHY address
1132- */
1133- switch (addr ) {
1134- case 0 :
1135- case BRCM_PSEUDO_PHY_ADDR :
1136- bcm_sf2_sw_indir_rw (ds , 0 , addr , regnum , val );
1137- break ;
1138- }
1139-
1140- return 0 ;
1141- }
1142-
11431198static void bcm_sf2_sw_adjust_link (struct dsa_switch * ds , int port ,
11441199 struct phy_device * phydev )
11451200{
@@ -1376,8 +1431,6 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
13761431 .setup = bcm_sf2_sw_setup ,
13771432 .set_addr = bcm_sf2_sw_set_addr ,
13781433 .get_phy_flags = bcm_sf2_sw_get_phy_flags ,
1379- .phy_read = bcm_sf2_sw_phy_read ,
1380- .phy_write = bcm_sf2_sw_phy_write ,
13811434 .get_strings = bcm_sf2_sw_get_strings ,
13821435 .get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats ,
13831436 .get_sset_count = bcm_sf2_sw_get_sset_count ,
0 commit comments