/* Write the desired MMD Devad */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_CTRL, MDIO_MMD_VEND2); if (ret < 0) goto err;
/* Write the desired MMD register address */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_DATA, reg); if (ret < 0) goto err;
/* Select the Function : DATA with no post increment */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR); if (ret < 0) goto err;
/* Write the data into MMD's selected register */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_DATA, val);
err: if (ret < 0)
dev_err(&bus->dev, "failed to write mmd register\n");
/* Write the desired MMD Devad */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_CTRL, MDIO_MMD_VEND2); if (ret < 0) goto err;
/* Write the desired MMD register address */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_DATA, reg); if (ret < 0) goto err;
/* Select the Function : DATA with no post increment */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR); if (ret < 0) goto err;
/* Read the content of the MMD's selected register */
val = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_DATA);
val &= ~mask;
val |= set; /* Write the data into MMD's selected register */
ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_DATA, val);
err: if (ret < 0)
dev_err(&bus->dev, "failed to write mmd register\n");
/* Additional sanity for read command if the specified *entryisinvalid
*/
val = mt7530_read(priv, MT7530_ATC); if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID)) return -EINVAL;
/* If port 6 is available as a CPU port, always prefer that as the default, *otherwisedon'tcare.
*/ staticstruct dsa_port *
mt753x_preferred_default_local_cpu_port(struct dsa_switch *ds)
{ struct dsa_port *cpu_dp = dsa_to_port(ds, 6);
/* Step 1 : Disable MT7531 COREPLL */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val &= ~EN_COREPLL;
mt7530_write(priv, MT7531_PLLGP_EN, val);
/* Step 2: switch to XTAL output */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= SW_CLKSW;
mt7530_write(priv, MT7531_PLLGP_EN, val);
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_EN;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
/* Step 3: disable PLLGP and enable program PLLGP */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= SW_PLLGP;
mt7530_write(priv, MT7531_PLLGP_EN, val);
/* Step 4: program COREPLL output frequency to 500MHz */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_POSDIV_M;
val |= 2 << RG_COREPLL_POSDIV_S;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
usleep_range(25, 35);
switch (xtal) { case MT7531_XTAL_FSEL_25MHZ:
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
mt7530_write(priv, MT7531_PLLGP_CR0, val); break; case MT7531_XTAL_FSEL_40MHZ:
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
mt7530_write(priv, MT7531_PLLGP_CR0, val); break;
}
/* Set feedback divide ratio update signal to high */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val |= RG_COREPLL_SDM_PCW_CHG;
mt7530_write(priv, MT7531_PLLGP_CR0, val); /* Wait for at least 16 XTAL clocks */
usleep_range(10, 20);
/* Step 5: set feedback divide ratio update signal to low */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_CHG;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
/* Enable 325M clock for SGMII */
mt7530_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
/* Enable 250SSC clock for RGMII */
mt7530_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
/* Step 6: Enable MT7531 PLL */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val |= RG_COREPLL_EN;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= EN_COREPLL;
mt7530_write(priv, MT7531_PLLGP_EN, val);
usleep_range(25, 35);
}
val &= ~MT7530_P5_PHY0_SEL & ~MT7530_P5_MAC_SEL & ~MT7530_P5_RGMII_MODE;
switch (priv->p5_mode) { /* MUX_PHY_P0: P0 -> P5 -> SoC MAC */ case MUX_PHY_P0:
val |= MT7530_P5_PHY0_SEL;
fallthrough;
/* MUX_PHY_P4: P4 -> P5 -> SoC MAC */ case MUX_PHY_P4: /* Setup the MAC by default for the cpu port */
mt7530_write(priv, MT753X_PMCR_P(5), 0x56300); break;
/* GMAC5: P5 -> SoC MAC or external PHY */ default:
val |= MT7530_P5_MAC_SEL; break;
}
/* Setup RGMII settings */ if (phy_interface_mode_is_rgmii(interface)) {
val |= MT7530_P5_RGMII_MODE;
/* Enable Mediatek header mode on the cpu port */
mt7530_write(priv, MT7530_PVC_P(port),
PORT_SPEC_TAG);
/* Enable flooding on the CPU port */
mt7530_set(priv, MT753X_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
UNU_FFP(BIT(port)));
/* Add the CPU port to the CPU port bitmap for MT7531 and the switch on *theMT7988SoC.TrappedframeswillbeforwardedtotheCPUportthat *isaffinetotheinbounduserport.
*/ if (priv->id == ID_MT7531 || priv->id == ID_MT7988 ||
priv->id == ID_EN7581 || priv->id == ID_AN7583)
mt7530_set(priv, MT7531_CFC, MT7531_CPU_PMAP(BIT(port)));
/* CPU port gets connected to all user ports of *theswitch.
*/
mt7530_write(priv, MT7530_PCR_P(port),
PCR_MATRIX(dsa_user_ports(priv->ds)));
/* Set to fallback mode for independent VLAN learning */
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
MT7530_PORT_FALLBACK_MODE);
}
/* Allow the user port gets connected to the cpu port and also *restoretheportmatrixiftheportisthememberofacertain *bridge.
*/ if (dsa_port_is_user(dp)) { struct dsa_port *cpu_dp = dp->cpu_dp;
/* Clear up all port matrix which could be restored in the next *enablementfortheport.
*/
priv->ports[port].enable = false;
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
PCR_MATRIX_CLR);
mutex_unlock(&priv->reg_mutex);
if (priv->id != ID_MT7530 && priv->id != ID_MT7621) return;
/* Do not set MT7530_P5_DIS when port 5 is being used for PHY muxing. */ if (port == 5 && priv->p5_mode == GMAC5)
mt7530_set(priv, MT753X_MTRAP, MT7530_P5_DIS); elseif (port == 6)
mt7530_set(priv, MT753X_MTRAP, MT7530_P6_DIS);
}
staticint
mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{ struct mt7530_priv *priv = ds->priv; int length;
u32 val;
/* When a new MTU is set, DSA always set the CPU port's MTU to the *largestMTUoftheuserports.Becausetheswitchonlyhasaglobal *RXlengthregister,onlyallowingCPUporthereisenough.
*/ if (!dsa_is_cpu_port(ds, port)) return0;
mt7530_mutex_lock(priv);
val = mt7530_mii_read(priv, MT7530_GMACCR);
val &= ~MAX_RX_PKT_LEN_MASK;
/* RX length also includes Ethernet header, MTK tag, and FCS length */
length = new_mtu + ETH_HLEN + MTK_HDR_LEN + ETH_FCS_LEN; if (length <= 1522) {
val |= MAX_RX_PKT_LEN_1522;
} elseif (length <= 1536) {
val |= MAX_RX_PKT_LEN_1536;
} elseif (length <= 1552) {
val |= MAX_RX_PKT_LEN_1552;
} else {
val &= ~MAX_RX_JUMBO_MASK;
val |= MAX_RX_JUMBO(DIV_ROUND_UP(length, 1024));
val |= MAX_RX_PKT_LEN_JUMBO;
}
mt7530_mii_write(priv, MT7530_GMACCR, val);
mt7530_mutex_unlock(priv);
return0;
}
staticint
mt7530_port_max_mtu(struct dsa_switch *ds, int port)
{ return MT7530_MAX_MTU;
}
/* Add/remove this port to/from the port matrix of the other *portsinthesamebridge.Iftheportisdisabled,port *matrixiskeptandnotbeingsetupuntiltheportbecomes *enabled.
*/ if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev)) continue;
if (other_p->enable)
mt7530_rmw(priv, MT7530_PCR_P(other_port),
PCR_MATRIX_MASK, other_p->pm);
}
/* Add/remove the all other ports to this port matrix. For !join *(leavingthebridge),onlytheCPUportwillremainintheportmatrix *ofthisport.
*/
p->pm = PCR_MATRIX(port_bitmap); if (priv->ports[port].enable)
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, p->pm);
}
/* Set to fallback mode for independent VLAN learning */
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
MT7530_PORT_FALLBACK_MODE);
mutex_unlock(&priv->reg_mutex);
return0;
}
staticvoid
mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
{ struct mt7530_priv *priv = ds->priv; bool all_user_ports_removed = true; int i;
/* This is called after .port_bridge_leave when leaving a VLAN-aware *bridge.Don'tsetstandaloneportstofallbackmode.
*/ if (dsa_port_bridge_dev_get(dsa_to_port(ds, port)))
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
MT7530_PORT_FALLBACK_MODE);
/* Set PVID to 0 */
mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
G0_PORT_VID_DEF);
for (i = 0; i < priv->ds->num_ports; i++) { if (dsa_is_user_port(ds, i) &&
dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) {
all_user_ports_removed = false; break;
}
}
/* CPU port also does the same thing until all user ports belonging to *theCPUportgetoutofVLANfilteringmode.
*/ if (all_user_ports_removed) { struct dsa_port *dp = dsa_to_port(ds, port); struct dsa_port *cpu_dp = dp->cpu_dp;
/* Trapped into security mode allows packet forwarding through VLAN *tablelookup.
*/ if (dsa_is_user_port(ds, port)) {
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
MT7530_PORT_SECURITY_MODE);
mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
G0_PORT_VID(priv->ports[port].pvid));
/* Only accept tagged frames if PVID is not set */ if (!priv->ports[port].pvid)
mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
MT7530_VLAN_ACC_TAGGED);
/* Set the port as a user port which is to be able to recognize *VIDfromincomingpacketsbeforefetchingentrywithinthe *VLANtable.
*/
mt7530_rmw(priv, MT7530_PVC_P(port),
VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
VLAN_ATTR(MT7530_VLAN_USER) |
PVC_EG_TAG(MT7530_VLAN_EG_DISABLED));
} else { /* Also set CPU ports to the "user" VLAN port attribute, to *allowVLANclassification,butkeeptheEG_TAGattributeas *"consistent"(i.o.w.don'tchangeitsvalue)forpackets *receivedbytheswitchfromtheCPU,sothattaggedpackets *areforwardedtouserportsastagged,anduntaggedas *untagged.
*/
mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
VLAN_ATTR(MT7530_VLAN_USER));
}
}
/* When a port is removed from the bridge, the port would be set up *backtothedefaultasisatinitialbootwhichisaVLAN-unaware *port.
*/
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
MT7530_PORT_MATRIX_MODE);
if (vlan_filtering) { /* The port is being kept as VLAN-unaware port when bridge is *setupwithvlan_filteringnotbeingset,Otherwise,the *portandthecorrespondingCPUportisrequiredthesetup *forbecomingaVLAN-awareport.
*/
mt7530_port_set_vlan_aware(ds, port);
mt7530_port_set_vlan_aware(ds, cpu_dp->index);
} else {
mt7530_port_set_vlan_unaware(ds, port);
}
/* Validate the entry with independent learning, create egress tag per *VLANandjoiningtheportasoneoftheportmembers.
*/
val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | FID(FID_BRIDGED) |
VLAN_VALID;
mt7530_write(priv, MT7530_VAWD1, val);
/* Decide whether adding tag or not for those outgoing packets from the *portinsidetheVLAN. *CPUportisalwaystakenasataggedportforservingmorethanone *VLANsacrossandalsobeingappliedwithegresstypestackmodefor *thatVLANtagswouldbeappendedafterhardwarespecialtagusedas *DSAtag.
*/ if (dsa_port_is_cpu(dp))
val = MT7530_VLAN_EGRESS_STACK; elseif (entry->untagged)
val = MT7530_VLAN_EGRESS_UNTAG; else
val = MT7530_VLAN_EGRESS_TAG;
mt7530_rmw(priv, MT7530_VAWD2,
ETAG_CTRL_P_MASK(entry->port),
ETAG_CTRL_P(entry->port, val));
}
/* Accept all frames if PVID is set */
mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
MT7530_VLAN_ACC_ALL);
/* Only configure PVID if VLAN filtering is enabled */ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
mt7530_rmw(priv, MT7530_PPBV1_P(port),
G0_PORT_VID_MASK,
G0_PORT_VID(vlan->vid));
} elseif (vlan->vid && priv->ports[port].pvid == vlan->vid) { /* This VLAN is overwritten without PVID, so unset it */
priv->ports[port].pvid = G0_PORT_VID_DEF;
/* Only accept tagged frames if the port is VLAN-aware */ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
MT7530_VLAN_ACC_TAGGED);
/* PVID is being restored to the default whenever the PVID port *isbeingremovedfromtheVLAN.
*/ if (priv->ports[port].pvid == vlan->vid) {
priv->ports[port].pvid = G0_PORT_VID_DEF;
/* Only accept tagged frames if the port is VLAN-aware */ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
MT7530_VLAN_ACC_TAGGED);
/* Check for existent entry */ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) return -EEXIST;
val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
/* MT7530 only supports one monitor port */
monitor_port = MT753X_MIRROR_PORT_GET(priv->id, val); if (val & MT753X_MIRROR_EN(priv->id) &&
monitor_port != mirror->to_local_port) return -EEXIST;
val |= MT753X_MIRROR_EN(priv->id);
val &= ~MT753X_MIRROR_PORT_MASK(priv->id);
val |= MT753X_MIRROR_PORT_SET(priv->id, mirror->to_local_port);
mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
val = mt7530_read(priv, MT7530_PCR_P(port)); if (ingress) {
val |= PORT_RX_MIR;
priv->mirror_rx |= BIT(port);
} else {
val |= PORT_TX_MIR;
priv->mirror_tx |= BIT(port);
}
mt7530_write(priv, MT7530_PCR_P(port), val);
if (!of_property_read_bool(np, "interrupt-controller")) {
dev_info(dev, "no interrupt support\n"); return0;
}
irq = of_irq_get(np, 0); if (irq <= 0) {
dev_err(dev, "failed to get parent IRQ: %d\n", irq); return irq ? : -EINVAL;
}
/* This register must be set for MT7530 to properly fire interrupts */ if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
ret = devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
priv->regmap, irq,
IRQF_ONESHOT, 0, &mt7530_regmap_irq_chip,
&irq_data); if (ret) return ret;
/* The parent node of conduit netdev which holds the common system *controlleralsoisthecontainerfortwoGMACsnodesrepresenting *astwonetdevinstances.
*/
dsa_switch_for_each_cpu_port(cpu_dp, ds) {
dn = cpu_dp->conduit->dev.of_node->parent; /* It doesn't matter which CPU port is found first, *theirconduitsshouldsharethesameparentOFnode
*/ break;
}
if (!dn) {
dev_err(ds->dev, "parent OF node of DSA conduit not found"); return -EINVAL;
}
if (priv->id == ID_MT7530) {
regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
ret = regulator_enable(priv->core_pwr); if (ret < 0) {
dev_err(priv->dev, "Failed to enable core power: %d\n", ret); return ret;
}
regulator_set_voltage(priv->io_pwr, 3300000, 3300000);
ret = regulator_enable(priv->io_pwr); if (ret < 0) {
dev_err(priv->dev, "Failed to enable io pwr: %d\n",
ret); return ret;
}
}
/* Reset whole chip through gpio pin or memory-mapped registers for *differenttypeofhardware
*/ if (priv->mcm) {
reset_control_assert(priv->rstc);
usleep_range(5000, 5100);
reset_control_deassert(priv->rstc);
} else {
gpiod_set_value_cansleep(priv->reset, 0);
usleep_range(5000, 5100);
gpiod_set_value_cansleep(priv->reset, 1);
}
/* Waiting for MT7530 got to stable */
INIT_MT7530_DUMMY_POLL(&p, priv, MT753X_TRAP);
ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0, 20, 1000000); if (ret < 0) {
dev_err(priv->dev, "reset timeout\n"); return ret;
}
id = mt7530_read(priv, MT7530_CREV);
id >>= CHIP_NAME_SHIFT; if (id != MT7530_ID) {
dev_err(priv->dev, "chip %x can't be supported\n", id); return -ENODEV;
}
if ((val & MT7530_XTAL_MASK) == MT7530_XTAL_20MHZ) {
dev_err(priv->dev, "MT7530 with a 20MHz XTAL is not supported!\n"); return -EINVAL;
}
/* Reset the switch through internal reset */
mt7530_write(priv, MT7530_SYS_CTRL,
SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
SYS_CTRL_REG_RST);
/* Lower Tx driving for TRGMII path */ for (i = 0; i < NUM_TRGMII_CTRL; i++)
mt7530_write(priv, MT7530_TRGMII_TD_ODT(i),
TD_DM_DRVP(8) | TD_DM_DRVN(8));
for (i = 0; i < NUM_TRGMII_CTRL; i++)
mt7530_rmw(priv, MT7530_TRGMII_RD(i),
RD_TAP_MASK, RD_TAP(16));
/* Allow modifying the trap and directly access PHY registers via the *MDIObustheswitchison.
*/
mt7530_rmw(priv, MT753X_MTRAP, MT7530_CHG_TRAP |
MT7530_PHY_INDIRECT_ACCESS, MT7530_CHG_TRAP);
if ((val & MT7530_XTAL_MASK) == MT7530_XTAL_40MHZ)
mt7530_pll_setup(priv);
mt753x_trap_frames(priv);
/* Enable and reset MIB counters */
mt7530_mib_reset(ds);
for (i = 0; i < priv->ds->num_ports; i++) { /* Clear link settings and enable force mode to force link down *onallportsuntilthey'reenabledlater.
*/
mt7530_rmw(priv, MT753X_PMCR_P(i),
PMCR_LINK_SETTINGS_MASK |
MT753X_FORCE_MODE(priv->id),
MT753X_FORCE_MODE(priv->id));
/* Disable forwarding by default on all ports */
mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
PCR_MATRIX_CLR);
/* Disable learning by default on all ports */
mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
/* Set default PVID to 0 on all user ports */
mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK,
G0_PORT_VID_DEF);
} /* Enable consistent egress tag */
mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
}
/* Allow mirroring frames received on the local port (monitor port). */
mt7530_set(priv, MT753X_AGC, LOCAL_EN);
/* Setup VLAN ID 0 for VLAN-unaware bridges */
ret = mt7530_setup_vlan0(priv); if (ret) return ret;
/* Check for PHY muxing on port 5 */ if (dsa_is_unused_port(ds, 5)) { /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY. *Setpriv->p5_modetotheappropriatevalueifPHYmuxingis *detected.
*/
for_each_child_of_node(dn, mac_np) { if (!of_device_is_compatible(mac_np, "mediatek,eth-mac")) continue;
ret = of_property_read_u32(mac_np, "reg", &id); if (ret < 0 || id != 1) continue;
phy_node = of_parse_phandle(mac_np, "phy-handle", 0); if (!phy_node) continue;
if (phy_node->parent == priv->dev->of_node->parent ||
phy_node->parent->parent == priv->dev->of_node) {
ret = of_get_phy_mode(mac_np, &interface); if (ret && ret != -ENODEV) {
of_node_put(mac_np);
of_node_put(phy_node); return ret;
}
id = of_mdio_parse_addr(ds->dev, phy_node); if (id == 0)
priv->p5_mode = MUX_PHY_P0; if (id == 4)
priv->p5_mode = MUX_PHY_P4;
}
of_node_put(mac_np);
of_node_put(phy_node); break;
}
/* Enable and reset MIB counters */
mt7530_mib_reset(ds);
/* Disable flooding on all ports */
mt7530_clear(priv, MT753X_MFC, BC_FFP_MASK | UNM_FFP_MASK |
UNU_FFP_MASK);
for (i = 0; i < priv->ds->num_ports; i++) { /* Clear link settings and enable force mode to force link down *onallportsuntilthey'reenabledlater.
*/
mt7530_rmw(priv, MT753X_PMCR_P(i),
PMCR_LINK_SETTINGS_MASK |
MT753X_FORCE_MODE(priv->id),
MT753X_FORCE_MODE(priv->id));
/* Disable forwarding by default on all ports */
mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
PCR_MATRIX_CLR);
/* Disable learning by default on all ports */
mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
/* Reset whole chip through gpio pin or memory-mapped registers for *differenttypeofhardware
*/ if (priv->mcm) {
reset_control_assert(priv->rstc);
usleep_range(5000, 5100);
reset_control_deassert(priv->rstc);
} else {
gpiod_set_value_cansleep(priv->reset, 0);
usleep_range(5000, 5100);
gpiod_set_value_cansleep(priv->reset, 1);
}
/* Waiting for MT7530 got to stable */
INIT_MT7530_DUMMY_POLL(&p, priv, MT753X_TRAP);
ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0, 20, 1000000); if (ret < 0) {
dev_err(priv->dev, "reset timeout\n"); return ret;
}
id = mt7530_read(priv, MT7531_CREV);
id >>= CHIP_NAME_SHIFT;
if (id != MT7531_ID) {
dev_err(priv->dev, "chip %x can't be supported\n", id); return -ENODEV;
}
/* MT7531AE has got two SGMII units. One for port 5, one for port 6. *MT7531BEhasgotonlyoneSGMIIunitwhichisforport6.
*/
val = mt7530_read(priv, MT7531_TOP_SIG_SR);
priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
/* Force link down on all ports before internal reset */ for (i = 0; i < priv->ds->num_ports; i++)
mt7530_write(priv, MT753X_PMCR_P(i), MT7531_FORCE_MODE_LNK);
/* Reset the switch through internal reset */
mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
if (!priv->p5_sgmii) {
mt7531_pll_setup(priv);
} else { /* Unlike MT7531BE, the GPIO 6-12 pins are not used for RGMII on *MT7531AE.SettheGPIO11-12pinstofunctionasMDCandMDIO *toexposetheMDIObusoftheswitch.
*/
mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
MT7531_EXT_P_MDC_11);
mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
MT7531_EXT_P_MDIO_12);
}
/* Enable Energy-Efficient Ethernet (EEE) and PHY core PLL, since *phy_devicehasnotyetbeencreatedprovidedfor *phy_[read,write]_mmd_indirectiscalled,weprovideourown *mt7531_ind_mmd_phy_[read,write]tocompletethisfunction.
*/
val = mt7531_ind_c45_phy_read(priv,
MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MDIO_MMD_VEND2, CORE_PLL_GROUP4);
val |= MT7531_RG_SYSPLL_DMY2 | MT7531_PHY_PLL_BYPASS_MODE;
val &= ~MT7531_PHY_PLL_OFF;
mt7531_ind_c45_phy_write(priv,
MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MDIO_MMD_VEND2, CORE_PLL_GROUP4, val);
/* Disable EEE advertisement on the switch PHYs. */ for (i = MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr);
i < MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr) + MT7530_NUM_PHYS;
i++) {
mt7531_ind_c45_phy_write(priv, i, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
}
ret = mt7531_setup_common(ds); if (ret) return ret;
switch (port) { /* Ports which are connected to switch PHYs. There is no MII pinout. */ case0 ... 4:
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces); break;
/* Port 5 supports rgmii with delays, mii, and gmii. */ case5:
phy_interface_set_rgmii(config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_MII,
config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces); break;
/* Port 6 supports rgmii and trgmii. */ case6:
__set_bit(PHY_INTERFACE_MODE_RGMII,
config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_TRGMII,
config->supported_interfaces); break;
}
}
switch (port) { /* Ports which are connected to switch PHYs. There is no MII pinout. */ case0 ... 4:
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces); break;
/* Port 5 supports rgmii with delays on MT7531BE, sgmii/802.3z on *MT7531AE.
*/ case5: if (!priv->p5_sgmii) {
phy_interface_set_rgmii(config->supported_interfaces); break;
}
fallthrough;
staticvoid mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config)
{ switch (port) { /* Ports which are connected to switch PHYs. There is no MII pinout. */ case0 ... 3:
__set_bit(PHY_INTERFACE_MODE_INTERNAL,
config->supported_interfaces);
staticvoid en7581_mac_port_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config)
{ switch (port) { /* Ports which are connected to switch PHYs. There is no MII pinout. */ case0 ... 4:
__set_bit(PHY_INTERFACE_MODE_INTERNAL,
config->supported_interfaces);
val = mt7530_read(priv, MT7531_CLKGEN_CTRL);
val |= GP_CLK_EN;
val &= ~GP_MODE_MASK;
val |= GP_MODE(MT7531_GP_MODE_RGMII);
val &= ~CLK_SKEW_IN_MASK;
val |= CLK_SKEW_IN(MT7531_CLK_SKEW_NO_CHG);
val &= ~CLK_SKEW_OUT_MASK;
val |= CLK_SKEW_OUT(MT7531_CLK_SKEW_NO_CHG);
val |= TXCLK_NO_REVERSE | RXCLK_NO_DELAY;
/* Do not adjust rgmii delay when vendor phy driver presents. */ if (!phydev || phy_driver_is_genphy(phydev)) {
val &= ~(TXCLK_NO_REVERSE | RXCLK_NO_DELAY); switch (interface) { case PHY_INTERFACE_MODE_RGMII:
val |= TXCLK_NO_REVERSE;
val |= RXCLK_NO_DELAY; break; case PHY_INTERFACE_MODE_RGMII_RXID:
val |= TXCLK_NO_REVERSE; break; case PHY_INTERFACE_MODE_RGMII_TXID:
val |= RXCLK_NO_DELAY; break; case PHY_INTERFACE_MODE_RGMII_ID: break; default: break;
}
}
switch (interface) { case PHY_INTERFACE_MODE_TRGMII: return &priv->pcs[dp->index].pcs; case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: return priv->ports[dp->index].sgmii_pcs; default: return NULL;
}
}
/* If the timer is zero, then set LPI_MODE_EN, which allows the *systemtoenterLPImodeimmediatelyratherthanwaitingfor *theLPIthreshold.
*/ if (!timer)
val = LPI_MODE_EN; elseif (FIELD_FIT(LPI_THRESH_MASK, timer))
val = FIELD_PREP(LPI_THRESH_MASK, timer); else
val = LPI_THRESH_MASK;
eeecr = mt7530_read(priv, MT753X_PMEEECR_P(port)); /* tx_lpi_timer should be in microseconds. The time units for *LPIthresholdareunspecified.
*/
config->lpi_timer_default = FIELD_GET(LPI_THRESH_MASK, eeecr);
/* Set the CPU port to trap frames to for MT7530. Trapped frames will be *forwardedtothenumericallysmallestCPUportwhoseconduit *interfaceisup.
*/ if (priv->id != ID_MT7530 && priv->id != ID_MT7621) return;
mask = BIT(cpu_dp->index);
if (operational)
priv->active_cpu_ports |= mask; else
priv->active_cpu_ports &= ~mask;
if (priv->active_cpu_ports) {
val = MT7530_CPU_EN |
MT7530_CPU_PORT(__ffs(priv->active_cpu_ports));
}
/* Get the hardware identifier from the devicetree node. *Wewillneeditforsomeoftheclockandregulatorsetup.
*/
priv->info = of_device_get_match_data(dev); if (!priv->info) return -EINVAL;
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.149Bemerkung:
(vorverarbeitet am 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.