/* 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 * entry is invalid
*/
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, * otherwise don't care.
*/ 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);
}
/* MIB counter doesn't provide a FramesTransmittedOK but instead * provide stats for Unicast, Broadcast and Multicast frames separately. * To simulate a global frame counter, read Unicast and addition Multicast * and Broadcast later
*/
mt7530_read_port_stats(priv, port, MT7530_PORT_MIB_TX_UNICAST, 1,
&mac_stats->FramesTransmittedOK);
/* MIB counter doesn't provide a FramesTransmittedOK but instead * provide stats for Unicast, Broadcast and Multicast frames separately. * To simulate a global frame counter, read Unicast and addition Multicast * and Broadcast later
*/
mt7530_read_port_stats(priv, port, MT7530_PORT_MIB_RX_UNICAST, 1,
&storage->rx_packets);
mt7530_read_port_stats(priv, port, MT7530_PORT_MIB_RX_MULTICAST, 1,
&storage->multicast);
storage->rx_packets += storage->multicast;
mt7530_read_port_stats(priv, port, MT7530_PORT_MIB_RX_BROADCAST, 1,
&data);
storage->rx_packets += data;
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;
/* In Clause 5 of IEEE Std 802-2014, two sublayers of the data link layer (DLL) * of the Open Systems Interconnection basic reference model (OSI/RM) are * described; the medium access control (MAC) and logical link control (LLC) * sublayers. The MAC sublayer is the one facing the physical layer. * * In 8.2 of IEEE Std 802.1Q-2022, the Bridge architecture is described. A * Bridge component comprises a MAC Relay Entity for interconnecting the Ports * of the Bridge, at least two Ports, and higher layer entities with at least a * Spanning Tree Protocol Entity included. * * Each Bridge Port also functions as an end station and shall provide the MAC * Service to an LLC Entity. Each instance of the MAC Service is provided to a * distinct LLC Entity that supports protocol identification, multiplexing, and * demultiplexing, for protocol data unit (PDU) transmission and reception by * one or more higher layer entities. * * It is described in 8.13.9 of IEEE Std 802.1Q-2022 that in a Bridge, the LLC * Entity associated with each Bridge Port is modeled as being directly * connected to the attached Local Area Network (LAN). * * On the switch with CPU port architecture, CPU port functions as Management * Port, and the Management Port functionality is provided by software which * functions as an end station. Software is connected to an IEEE 802 LAN that is * wholly contained within the system that incorporates the Bridge. Software * provides access to the LLC Entity associated with each Bridge Port by the * value of the source port field on the special tag on the frame received by * software. * * We call frames that carry control information to determine the active * topology and current extent of each Virtual Local Area Network (VLAN), i.e., * spanning tree or Shortest Path Bridging (SPB) and Multiple VLAN Registration * Protocol Data Units (MVRPDUs), and frames from other link constrained * protocols, such as Extensible Authentication Protocol over LAN (EAPOL) and * Link Layer Discovery Protocol (LLDP), link-local frames. They are not * forwarded by a Bridge. Permanently configured entries in the filtering * database (FDB) ensure that such frames are discarded by the Forwarding * Process. In 8.6.3 of IEEE Std 802.1Q-2022, this is described in detail: * * Each of the reserved MAC addresses specified in Table 8-1 * (01-80-C2-00-00-[00,01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F]) shall be * permanently configured in the FDB in C-VLAN components and ERs. * * Each of the reserved MAC addresses specified in Table 8-2 * (01-80-C2-00-00-[01,02,03,04,05,06,07,08,09,0A,0E]) shall be permanently * configured in the FDB in S-VLAN components. * * Each of the reserved MAC addresses specified in Table 8-3 * (01-80-C2-00-00-[01,02,04,0E]) shall be permanently configured in the FDB in * TPMR components. * * The FDB entries for reserved MAC addresses shall specify filtering for all * Bridge Ports and all VIDs. Management shall not provide the capability to * modify or remove entries for reserved MAC addresses. * * The addresses in Table 8-1, Table 8-2, and Table 8-3 determine the scope of * propagation of PDUs within a Bridged Network, as follows: * * The Nearest Bridge group address (01-80-C2-00-00-0E) is an address that no * conformant Two-Port MAC Relay (TPMR) component, Service VLAN (S-VLAN) * component, Customer VLAN (C-VLAN) component, or MAC Bridge can forward. * PDUs transmitted using this destination address, or any other addresses * that appear in Table 8-1, Table 8-2, and Table 8-3 * (01-80-C2-00-00-[00,01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F]), can * therefore travel no further than those stations that can be reached via a * single individual LAN from the originating station. * * The Nearest non-TPMR Bridge group address (01-80-C2-00-00-03), is an * address that no conformant S-VLAN component, C-VLAN component, or MAC * Bridge can forward; however, this address is relayed by a TPMR component. * PDUs using this destination address, or any of the other addresses that * appear in both Table 8-1 and Table 8-2 but not in Table 8-3 * (01-80-C2-00-00-[00,03,05,06,07,08,09,0A,0B,0C,0D,0F]), will be relayed by * any TPMRs but will propagate no further than the nearest S-VLAN component, * C-VLAN component, or MAC Bridge. * * The Nearest Customer Bridge group address (01-80-C2-00-00-00) is an address * that no conformant C-VLAN component, MAC Bridge can forward; however, it is * relayed by TPMR components and S-VLAN components. PDUs using this * destination address, or any of the other addresses that appear in Table 8-1 * but not in either Table 8-2 or Table 8-3 (01-80-C2-00-00-[00,0B,0C,0D,0F]), * will be relayed by TPMR components and S-VLAN components but will propagate * no further than the nearest C-VLAN component or MAC Bridge. * * Because the LLC Entity associated with each Bridge Port is provided via CPU * port, we must not filter these frames but forward them to CPU port. * * In a Bridge, the transmission Port is majorly decided by ingress and egress * rules, FDB, and spanning tree Port State functions of the Forwarding Process. * For link-local frames, only CPU port should be designated as destination port * in the FDB, and the other functions of the Forwarding Process must not * interfere with the decision of the transmission Port. We call this process * trapping frames to CPU port. * * Therefore, on the switch with CPU port architecture, link-local frames must * be trapped to CPU port, and certain link-local frames received by a Port of a * Bridge comprising a TPMR component or an S-VLAN component must be excluded * from it. * * A Bridge of the switch with CPU port architecture cannot comprise a Two-Port * MAC Relay (TPMR) component as a TPMR component supports only a subset of the * functionality of a MAC Bridge. A Bridge comprising two Ports (Management Port * doesn't count) of this architecture will either function as a standard MAC * Bridge or a standard VLAN Bridge. * * Therefore, a Bridge of this architecture can only comprise S-VLAN components, * C-VLAN components, or MAC Bridge components. Since there's no TPMR component, * we don't need to relay PDUs using the destination addresses specified on the * Nearest non-TPMR section, and the proportion of the Nearest Customer Bridge * section where they must be relayed by TPMR components. * * One option to trap link-local frames to CPU port is to add static FDB entries * with CPU port designated as destination port. However, because that * Independent VLAN Learning (IVL) is being used on every VID, each entry only * applies to a single VLAN Identifier (VID). For a Bridge comprising a MAC * Bridge component or a C-VLAN component, there would have to be 16 times 4096 * entries. This switch intellectual property can only hold a maximum of 2048 * entries. Using this option, there also isn't a mechanism to prevent * link-local frames from being discarded when the spanning tree Port State of * the reception Port is discarding. * * The remaining option is to utilise the BPC, RGAC1, RGAC2, RGAC3, and RGAC4 * registers. Whilst this applies to every VID, it doesn't contain all of the * reserved MAC addresses without affecting the remaining Standard Group MAC * Addresses. The REV_UN frame tag utilised using the RGAC4 register covers the * remaining 01-80-C2-00-00-[04,05,06,07,08,09,0A,0B,0C,0D,0F] destination * addresses. It also includes the 01-80-C2-00-00-22 to 01-80-C2-00-00-FF * destination addresses which may be relayed by MAC Bridges or VLAN Bridges. * The latter option provides better but not complete conformance. * * This switch intellectual property also does not provide a mechanism to trap * link-local frames with specific destination addresses to CPU port by Bridge, * to conform to the filtering rules for the distinct Bridge components. * * Therefore, regardless of the type of the Bridge component, link-local frames * with these destination addresses will be trapped to CPU port: * * 01-80-C2-00-00-[00,01,02,03,0E] * * In a Bridge comprising a MAC Bridge component or a C-VLAN component: * * Link-local frames with these destination addresses won't be trapped to CPU * port which won't conform to IEEE Std 802.1Q-2022: * * 01-80-C2-00-00-[04,05,06,07,08,09,0A,0B,0C,0D,0F] * * In a Bridge comprising an S-VLAN component: * * Link-local frames with these destination addresses will be trapped to CPU * port which won't conform to IEEE Std 802.1Q-2022: * * 01-80-C2-00-00-00 * * Link-local frames with these destination addresses won't be trapped to CPU * port which won't conform to IEEE Std 802.1Q-2022: * * 01-80-C2-00-00-[04,05,06,07,08,09,0A] * * To trap link-local frames to CPU port as conformant as this switch * intellectual property can allow, link-local frames are made to be regarded as * Bridge Protocol Data Units (BPDUs). This is because this switch intellectual * property only lets the frames regarded as BPDUs bypass the spanning tree Port * State function of the Forwarding Process. * * The only remaining interference is the ingress rules. When the reception Port * has no PVID assigned on software, VLAN-untagged frames won't be allowed in. * There doesn't seem to be a mechanism on the switch intellectual property to * have link-local frames bypass this function of the Forwarding Process.
*/ staticvoid
mt753x_trap_frames(struct mt7530_priv *priv)
{ /* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress them * VLAN-untagged.
*/
mt7530_rmw(priv, MT753X_BPC,
PAE_BPDU_FR | PAE_EG_TAG_MASK | PAE_PORT_FW_MASK |
BPDU_EG_TAG_MASK | BPDU_PORT_FW_MASK,
PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
PAE_PORT_FW(TO_CPU_FW_CPU_ONLY) |
BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
TO_CPU_FW_CPU_ONLY);
/* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and egress * them VLAN-untagged.
*/
mt7530_rmw(priv, MT753X_RGAC1,
R02_BPDU_FR | R02_EG_TAG_MASK | R02_PORT_FW_MASK |
R01_BPDU_FR | R01_EG_TAG_MASK | R01_PORT_FW_MASK,
R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
R02_PORT_FW(TO_CPU_FW_CPU_ONLY) | R01_BPDU_FR |
R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
TO_CPU_FW_CPU_ONLY);
/* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and egress * them VLAN-untagged.
*/
mt7530_rmw(priv, MT753X_RGAC2,
R0E_BPDU_FR | R0E_EG_TAG_MASK | R0E_PORT_FW_MASK |
R03_BPDU_FR | R03_EG_TAG_MASK | R03_PORT_FW_MASK,
R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
R0E_PORT_FW(TO_CPU_FW_CPU_ONLY) | R03_BPDU_FR |
R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
TO_CPU_FW_CPU_ONLY);
}
/* 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 * the MT7988 SoC. Trapped frames will be forwarded to the CPU port that * is affine to the inbound user port.
*/ 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 * the switch.
*/
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 * restore the port matrix if the port is the member of a certain * 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 * enablement for the port.
*/
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 * largest MTU of the user ports. Because the switch only has a global * RX length register, only allowing CPU port here is enough.
*/ if (!dsa_is_cpu_port(ds, port)) return 0;
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);
return 0;
}
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 * ports in the same bridge. If the port is disabled, port * matrix is kept and not being setup until the port becomes * 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 * (leaving the bridge), only the CPU port will remain in the port matrix * of this port.
*/
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);
return 0;
}
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't set standalone ports to fallback mode.
*/ 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 * the CPU port get out of VLAN filtering mode.
*/ 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 * table lookup.
*/ 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 * VID from incoming packets before fetching entry within the * VLAN table.
*/
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 * allow VLAN classification, but keep the EG_TAG attribute as * "consistent" (i.o.w. don't change its value) for packets * received by the switch from the CPU, so that tagged packets * are forwarded to user ports as tagged, and untagged as * 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 * back to the default as is at initial boot which is a VLAN-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 * set up with vlan_filtering not being set, Otherwise, the * port and the corresponding CPU port is required the setup * for becoming a VLAN-aware port.
*/
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 * VLAN and joining the port as one of the port members.
*/
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 * port inside the VLAN. * CPU port is always taken as a tagged port for serving more than one * VLANs across and also being applied with egress type stack mode for * that VLAN tags would be appended after hardware special tag used as * DSA tag.
*/ 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));
}
/* Validate the entry with independent learning, keep the original * ingress tag attribute.
*/
val = IVL_MAC | EG_CON | PORT_MEM(MT7530_ALL_MEMBERS) | FID(FID_BRIDGED) |
VLAN_VALID;
mt7530_write(priv, MT7530_VAWD1, 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 * is being removed from the VLAN.
*/ 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);
#ifdef CONFIG_GPIOLIB staticinline u32
mt7530_gpio_to_bit(unsignedint offset)
{ /* Map GPIO offset to register bit * [ 2: 0] port 0 LED 0..2 as GPIO 0..2 * [ 6: 4] port 1 LED 0..2 as GPIO 3..5 * [10: 8] port 2 LED 0..2 as GPIO 6..8 * [14:12] port 3 LED 0..2 as GPIO 9..11 * [18:16] port 4 LED 0..2 as GPIO 12..14
*/ return BIT(offset + offset / 3);
}
if (!of_property_read_bool(np, "interrupt-controller")) {
dev_info(dev, "no interrupt support\n"); return 0;
}
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 * controller also is the container for two GMACs nodes representing * as two netdev instances.
*/
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, * their conduits should share the same parent OF node
*/ 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 * different type of hardware
*/ 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 * MDIO bus the switch is on.
*/
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 * on all ports until they're enabled later.
*/
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. * Set priv->p5_mode to the appropriate value if PHY muxing is * 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 * on all ports until they're enabled later.
*/
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 * different type of hardware
*/ 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. * MT7531BE has got only one SGMII unit which is for port 6.
*/
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. Set the GPIO 11-12 pins to function as MDC and MDIO * to expose the MDIO bus of the switch.
*/
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_device has not yet been created provided for * phy_[read,write]_mmd_indirect is called, we provide our own * mt7531_ind_mmd_phy_[read,write] to complete this function.
*/
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. */ case 0 ... 4:
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces); break;
/* Port 5 supports rgmii with delays, mii, and gmii. */ case 5:
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. */ case 6:
__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. */ case 0 ... 4:
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces); break;
/* Port 5 supports rgmii with delays on MT7531BE, sgmii/802.3z on * MT7531AE.
*/ case 5: if (!priv->p5_sgmii) {
phy_interface_set_rgmii(config->supported_interfaces); break;
}
fallthrough;
/* Port 6 supports sgmii/802.3z. */ case 6:
__set_bit(PHY_INTERFACE_MODE_SGMII,
config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_1000BASEX,
config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_2500BASEX,
config->supported_interfaces);
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. */ case 0 ... 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. */ case 0 ... 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 * system to enter LPI mode immediately rather than waiting for * the LPI threshold.
*/ 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 * LPI threshold are unspecified.
*/
config->lpi_timer_default = FIELD_GET(LPI_THRESH_MASK, eeecr);
/* Set the CPU port to trap frames to for MT7530. Trapped frames will be * forwarded to the numerically smallest CPU port whose conduit * interface is up.
*/ 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. * We will need it for some of the clock and regulator setup.
*/
priv->info = of_device_get_match_data(dev); if (!priv->info) return -EINVAL;
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.