Skip to content

Commit 38f790a

Browse files
vDorstdavem330
authored andcommitted
net: dsa: mt7530: Add support for port 5
Adding support for port 5. Port 5 can muxed/interface to: - internal 5th GMAC of the switch; can be used as 2nd CPU port or as extra port with an external phy for a 6th ethernet port. - internal PHY of port 0 or 4; Used in most applications so that port 0 or 4 is the WAN port and interfaces with the 2nd GMAC of the SOC. Signed-off-by: René van Dorst <[email protected]> Tested-by: Frank Wunderlich <[email protected]> Acked-by: Russell King <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4f358cb commit 38f790a

File tree

2 files changed

+168
-6
lines changed

2 files changed

+168
-6
lines changed

drivers/net/dsa/mt7530.c

Lines changed: 139 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,77 @@ mt7530_get_sset_count(struct dsa_switch *ds, int port, int sset)
633633
return ARRAY_SIZE(mt7530_mib);
634634
}
635635

636+
static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
637+
{
638+
struct mt7530_priv *priv = ds->priv;
639+
u8 tx_delay = 0;
640+
int val;
641+
642+
mutex_lock(&priv->reg_mutex);
643+
644+
val = mt7530_read(priv, MT7530_MHWTRAP);
645+
646+
val |= MHWTRAP_MANUAL | MHWTRAP_P5_MAC_SEL | MHWTRAP_P5_DIS;
647+
val &= ~MHWTRAP_P5_RGMII_MODE & ~MHWTRAP_PHY0_SEL;
648+
649+
switch (priv->p5_intf_sel) {
650+
case P5_INTF_SEL_PHY_P0:
651+
/* MT7530_P5_MODE_GPHY_P0: 2nd GMAC -> P5 -> P0 */
652+
val |= MHWTRAP_PHY0_SEL;
653+
/* fall through */
654+
case P5_INTF_SEL_PHY_P4:
655+
/* MT7530_P5_MODE_GPHY_P4: 2nd GMAC -> P5 -> P4 */
656+
val &= ~MHWTRAP_P5_MAC_SEL & ~MHWTRAP_P5_DIS;
657+
658+
/* Setup the MAC by default for the cpu port */
659+
mt7530_write(priv, MT7530_PMCR_P(5), 0x56300);
660+
break;
661+
case P5_INTF_SEL_GMAC5:
662+
/* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */
663+
val &= ~MHWTRAP_P5_DIS;
664+
break;
665+
case P5_DISABLED:
666+
interface = PHY_INTERFACE_MODE_NA;
667+
break;
668+
default:
669+
dev_err(ds->dev, "Unsupported p5_intf_sel %d\n",
670+
priv->p5_intf_sel);
671+
goto unlock_exit;
672+
}
673+
674+
/* Setup RGMII settings */
675+
if (phy_interface_mode_is_rgmii(interface)) {
676+
val |= MHWTRAP_P5_RGMII_MODE;
677+
678+
/* P5 RGMII RX Clock Control: delay setting for 1000M */
679+
mt7530_write(priv, MT7530_P5RGMIIRXCR, CSR_RGMII_EDGE_ALIGN);
680+
681+
/* Don't set delay in DSA mode */
682+
if (!dsa_is_dsa_port(priv->ds, 5) &&
683+
(interface == PHY_INTERFACE_MODE_RGMII_TXID ||
684+
interface == PHY_INTERFACE_MODE_RGMII_ID))
685+
tx_delay = 4; /* n * 0.5 ns */
686+
687+
/* P5 RGMII TX Clock Control: delay x */
688+
mt7530_write(priv, MT7530_P5RGMIITXCR,
689+
CSR_RGMII_TXC_CFG(0x10 + tx_delay));
690+
691+
/* reduce P5 RGMII Tx driving, 8mA */
692+
mt7530_write(priv, MT7530_IO_DRV_CR,
693+
P5_IO_CLK_DRV(1) | P5_IO_DATA_DRV(1));
694+
}
695+
696+
mt7530_write(priv, MT7530_MHWTRAP, val);
697+
698+
dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n",
699+
val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface));
700+
701+
priv->p5_interface = interface;
702+
703+
unlock_exit:
704+
mutex_unlock(&priv->reg_mutex);
705+
}
706+
636707
static int
637708
mt7530_cpu_port_enable(struct mt7530_priv *priv,
638709
int port)
@@ -1169,7 +1240,10 @@ static int
11691240
mt7530_setup(struct dsa_switch *ds)
11701241
{
11711242
struct mt7530_priv *priv = ds->priv;
1243+
struct device_node *phy_node;
1244+
struct device_node *mac_np;
11721245
struct mt7530_dummy_poll p;
1246+
phy_interface_t interface;
11731247
struct device_node *dn;
11741248
u32 id, val;
11751249
int ret, i;
@@ -1260,6 +1334,40 @@ mt7530_setup(struct dsa_switch *ds)
12601334
mt7530_port_disable(ds, i);
12611335
}
12621336

1337+
/* Setup port 5 */
1338+
priv->p5_intf_sel = P5_DISABLED;
1339+
interface = PHY_INTERFACE_MODE_NA;
1340+
1341+
if (!dsa_is_unused_port(ds, 5)) {
1342+
priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
1343+
interface = of_get_phy_mode(ds->ports[5].dn);
1344+
} else {
1345+
/* Scan the ethernet nodes. look for GMAC1, lookup used phy */
1346+
for_each_child_of_node(dn, mac_np) {
1347+
if (!of_device_is_compatible(mac_np,
1348+
"mediatek,eth-mac"))
1349+
continue;
1350+
1351+
ret = of_property_read_u32(mac_np, "reg", &id);
1352+
if (ret < 0 || id != 1)
1353+
continue;
1354+
1355+
phy_node = of_parse_phandle(mac_np, "phy-handle", 0);
1356+
if (phy_node->parent == priv->dev->of_node->parent) {
1357+
interface = of_get_phy_mode(mac_np);
1358+
id = of_mdio_parse_addr(ds->dev, phy_node);
1359+
if (id == 0)
1360+
priv->p5_intf_sel = P5_INTF_SEL_PHY_P0;
1361+
if (id == 4)
1362+
priv->p5_intf_sel = P5_INTF_SEL_PHY_P4;
1363+
}
1364+
of_node_put(phy_node);
1365+
break;
1366+
}
1367+
}
1368+
1369+
mt7530_setup_port5(ds, interface);
1370+
12631371
/* Flush the FDB table */
12641372
ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
12651373
if (ret < 0)
@@ -1284,7 +1392,16 @@ static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,
12841392
if (state->interface != PHY_INTERFACE_MODE_GMII)
12851393
return;
12861394
break;
1287-
/* case 5: Port 5 is not supported! */
1395+
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
1396+
if (priv->p5_interface == state->interface)
1397+
break;
1398+
if (!phy_interface_mode_is_rgmii(state->interface) &&
1399+
state->interface != PHY_INTERFACE_MODE_MII &&
1400+
state->interface != PHY_INTERFACE_MODE_GMII)
1401+
return;
1402+
1403+
mt7530_setup_port5(ds, state->interface);
1404+
break;
12881405
case 6: /* 1st cpu port */
12891406
if (priv->p6_interface == state->interface)
12901407
break;
@@ -1324,6 +1441,10 @@ static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,
13241441
mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
13251442
PMCR_BACKPR_EN | PMCR_FORCE_MODE | PMCR_FORCE_LNK;
13261443

1444+
/* Are we connected to external phy */
1445+
if (port == 5 && dsa_is_user_port(ds, 5))
1446+
mcr_new |= PMCR_EXT_PHY;
1447+
13271448
switch (state->speed) {
13281449
case SPEED_1000:
13291450
mcr_new |= PMCR_FORCE_SPEED_1000;
@@ -1379,7 +1500,13 @@ static void mt7530_phylink_validate(struct dsa_switch *ds, int port,
13791500
state->interface != PHY_INTERFACE_MODE_GMII)
13801501
goto unsupported;
13811502
break;
1382-
/* case 5: Port 5 not supported! */
1503+
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
1504+
if (state->interface != PHY_INTERFACE_MODE_NA &&
1505+
!phy_interface_mode_is_rgmii(state->interface) &&
1506+
state->interface != PHY_INTERFACE_MODE_MII &&
1507+
state->interface != PHY_INTERFACE_MODE_GMII)
1508+
goto unsupported;
1509+
break;
13831510
case 6: /* 1st cpu port */
13841511
if (state->interface != PHY_INTERFACE_MODE_NA &&
13851512
state->interface != PHY_INTERFACE_MODE_RGMII &&
@@ -1396,15 +1523,21 @@ static void mt7530_phylink_validate(struct dsa_switch *ds, int port,
13961523
phylink_set_port_modes(mask);
13971524
phylink_set(mask, Autoneg);
13981525

1399-
if (state->interface != PHY_INTERFACE_MODE_TRGMII) {
1526+
if (state->interface == PHY_INTERFACE_MODE_TRGMII) {
1527+
phylink_set(mask, 1000baseT_Full);
1528+
} else {
14001529
phylink_set(mask, 10baseT_Half);
14011530
phylink_set(mask, 10baseT_Full);
14021531
phylink_set(mask, 100baseT_Half);
14031532
phylink_set(mask, 100baseT_Full);
1404-
phylink_set(mask, 1000baseT_Half);
1405-
}
14061533

1407-
phylink_set(mask, 1000baseT_Full);
1534+
if (state->interface != PHY_INTERFACE_MODE_MII) {
1535+
phylink_set(mask, 1000baseT_Half);
1536+
phylink_set(mask, 1000baseT_Full);
1537+
if (port == 5)
1538+
phylink_set(mask, 1000baseX_Full);
1539+
}
1540+
}
14081541

14091542
phylink_set(mask, Pause);
14101543
phylink_set(mask, Asym_Pause);

drivers/net/dsa/mt7530.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ enum mt7530_vlan_port_attr {
186186
/* Register for port MAC control register */
187187
#define MT7530_PMCR_P(x) (0x3000 + ((x) * 0x100))
188188
#define PMCR_IFG_XMIT(x) (((x) & 0x3) << 18)
189+
#define PMCR_EXT_PHY BIT(17)
189190
#define PMCR_MAC_MODE BIT(16)
190191
#define PMCR_FORCE_MODE BIT(15)
191192
#define PMCR_TX_EN BIT(14)
@@ -245,6 +246,7 @@ enum mt7530_vlan_port_attr {
245246

246247
/* Register for hw trap modification */
247248
#define MT7530_MHWTRAP 0x7804
249+
#define MHWTRAP_PHY0_SEL BIT(20)
248250
#define MHWTRAP_MANUAL BIT(16)
249251
#define MHWTRAP_P5_MAC_SEL BIT(13)
250252
#define MHWTRAP_P6_DIS BIT(8)
@@ -402,6 +404,30 @@ struct mt7530_port {
402404
u16 pvid;
403405
};
404406

407+
/* Port 5 interface select definitions */
408+
enum p5_interface_select {
409+
P5_DISABLED = 0,
410+
P5_INTF_SEL_PHY_P0,
411+
P5_INTF_SEL_PHY_P4,
412+
P5_INTF_SEL_GMAC5,
413+
};
414+
415+
static const char *p5_intf_modes(unsigned int p5_interface)
416+
{
417+
switch (p5_interface) {
418+
case P5_DISABLED:
419+
return "DISABLED";
420+
case P5_INTF_SEL_PHY_P0:
421+
return "PHY P0";
422+
case P5_INTF_SEL_PHY_P4:
423+
return "PHY P4";
424+
case P5_INTF_SEL_GMAC5:
425+
return "GMAC5";
426+
default:
427+
return "unknown";
428+
}
429+
}
430+
405431
/* struct mt7530_priv - This is the main data structure for holding the state
406432
* of the driver
407433
* @dev: The device pointer
@@ -418,6 +444,7 @@ struct mt7530_port {
418444
* @reg_mutex: The lock for protecting among process accessing
419445
* registers
420446
* @p6_interface Holding the current port 6 interface
447+
* @p5_intf_sel: Holding the current port 5 interface select
421448
*/
422449
struct mt7530_priv {
423450
struct device *dev;
@@ -431,6 +458,8 @@ struct mt7530_priv {
431458
unsigned int id;
432459
bool mcm;
433460
phy_interface_t p6_interface;
461+
phy_interface_t p5_interface;
462+
unsigned int p5_intf_sel;
434463

435464
struct mt7530_port ports[MT7530_NUM_PORTS];
436465
/* protect among processes for registers access*/

0 commit comments

Comments
 (0)