22
22
#include <linux/of_irq.h>
23
23
#include <linux/of_address.h>
24
24
#include <linux/of_net.h>
25
+ #include <linux/of_mdio.h>
25
26
#include <net/dsa.h>
26
27
#include <linux/ethtool.h>
27
28
#include <linux/if_bridge.h>
@@ -836,6 +837,66 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
836
837
return 0 ;
837
838
}
838
839
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
+
839
900
static irqreturn_t bcm_sf2_switch_0_isr (int irq , void * dev_id )
840
901
{
841
902
struct bcm_sf2_priv * priv = dev_id ;
@@ -932,6 +993,72 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,
932
993
}
933
994
}
934
995
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
+
935
1062
static int bcm_sf2_sw_setup (struct dsa_switch * ds )
936
1063
{
937
1064
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)
972
1099
goto out_unmap ;
973
1100
}
974
1101
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
+
975
1108
/* Disable all interrupts and request them */
976
1109
bcm_sf2_intr_disable (priv );
977
1110
@@ -1017,23 +1150,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
1017
1150
bcm_sf2_port_disable (ds , port , NULL );
1018
1151
}
1019
1152
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
-
1037
1153
rev = reg_readl (priv , REG_SWITCH_REVISION );
1038
1154
priv -> hw_params .top_rev = (rev >> SWITCH_TOP_REV_SHIFT ) &
1039
1155
SWITCH_TOP_REV_MASK ;
@@ -1058,6 +1174,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
1058
1174
iounmap (* base );
1059
1175
base ++ ;
1060
1176
}
1177
+ bcm_sf2_mdio_unregister (priv );
1061
1178
return ret ;
1062
1179
}
1063
1180
@@ -1078,68 +1195,6 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
1078
1195
return priv -> hw_params .gphy_rev ;
1079
1196
}
1080
1197
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
-
1143
1198
static void bcm_sf2_sw_adjust_link (struct dsa_switch * ds , int port ,
1144
1199
struct phy_device * phydev )
1145
1200
{
@@ -1376,8 +1431,6 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
1376
1431
.setup = bcm_sf2_sw_setup ,
1377
1432
.set_addr = bcm_sf2_sw_set_addr ,
1378
1433
.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 ,
1381
1434
.get_strings = bcm_sf2_sw_get_strings ,
1382
1435
.get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats ,
1383
1436
.get_sset_count = bcm_sf2_sw_get_sset_count ,
0 commit comments