/* Unlock access to the PHYs, needed for SPI and side MDIO access */
ret = lan937x_cfg(dev, REG_GLOBAL_CTRL_0, SW_PHY_REG_BLOCK, false); if (ret < 0) goto print_error;
if (side_mdio) /* Allow access to internal PHYs over MDIO bus */
data16 = VPHY_MDIO_INTERNAL_ENABLE; else /* Enable SPI indirect access to address clock domain crossing *issue
*/
data16 = VPHY_SPI_INDIRECT_ENABLE;
ret = ksz_rmw16(dev, REG_VPHY_SPECIAL_CTRL__2,
VPHY_SPI_INDIRECT_ENABLE | VPHY_MDIO_INTERNAL_ENABLE,
data16);
print_error: if (ret < 0)
dev_err(dev->dev, "failed to preinit the MDIO bus\n");
return ret;
}
staticint lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg)
{
u16 addr_base = REG_PORT_T1_PHY_CTRL_BASE;
u16 temp;
if (is_lan937x_tx_phy(dev, addr))
addr_base = REG_PORT_TX_PHY_CTRL_BASE;
/* get register address based on the logical port */
temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2)));
int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu)
{ struct dsa_switch *ds = dev->ds; int ret;
new_mtu += VLAN_ETH_HLEN + ETH_FCS_LEN;
if (dsa_is_cpu_port(ds, port))
new_mtu += LAN937X_TAG_LEN;
if (new_mtu >= FR_MIN_SIZE)
ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0,
PORT_JUMBO_PACKET, true); else
ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0,
PORT_JUMBO_PACKET, false); if (ret < 0) {
dev_err(ds->dev, "failed to enable jumbo\n"); return ret;
}
/* Write the frame size in PORT_MAX_FR_SIZE register */
ret = ksz_pwrite16(dev, port, PORT_MAX_FR_SIZE, new_mtu); if (ret) {
dev_err(ds->dev, "failed to update mtu for port %d\n", port); return ret;
}
/* The aging timer comprises a 3-bit multiplier and a 20-bit second *value.Eitherofthemcannotbezero.Themaximumtimeristhen *7*1048575=7340025seconds.Asthisvalueistoolargefor *practicaluseitcanbeinterpretedasmicroseconds,makingthe *maximumtimer7340secondswithfinercontrol.Thisallowsfor *maximum122minutescomparedto29minutesinKSZ9477switch.
*/ if (msecs % 1000)
in_msec = true; else
secs /= 1000; if (!secs)
secs = 1;
/* Return error if too large. */ elseif (secs > 7 * MAX_TIMER_VAL) return -EINVAL;
/* Configure how to interpret the number value. */
ret = ksz_rmw8(dev, REG_SW_LUE_CTRL_2, SW_AGE_CNT_IN_MICROSEC,
in_msec ? SW_AGE_CNT_IN_MICROSEC : 0); if (ret < 0) return ret;
ret = ksz_read8(dev, REG_SW_LUE_CTRL_0, &value8); if (ret < 0) return ret;
/* Check whether there is need to update the multiplier. */
mult = FIELD_GET(SW_AGE_CNT_M, value8);
max_val = MAX_TIMER_VAL; if (mult > 0) { /* Try to use the same multiplier already in the register as *thehardwaredefaultusesmultiplier4and75secondsfor *300seconds.
*/
max_val = DIV_ROUND_UP(secs, mult); if (max_val > MAX_TIMER_VAL || max_val * mult != secs)
max_val = MAX_TIMER_VAL;
}
data = DIV_ROUND_UP(secs, max_val); if (mult != data) {
value8 &= ~SW_AGE_CNT_M;
value8 |= FIELD_PREP(SW_AGE_CNT_M, data);
ret = ksz_write8(dev, REG_SW_LUE_CTRL_0, value8); if (ret < 0) return ret;
}
secs = DIV_ROUND_UP(secs, data);
value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs);
ret = ksz_write8(dev, REG_SW_AGE_PERIOD__1, value); if (ret < 0) return ret;
/* write DLL reset to take effect */
data16 |= PORT_DLL_RESET;
ksz_pwrite16(dev, port, reg, data16);
}
staticvoid lan937x_set_rgmii_tx_delay(struct ksz_device *dev, int port)
{
u8 val;
/* Apply different codes based on the ports as per characterization *results
*/
val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS :
RGMII_2_TX_DELAY_2NS;
int lan937x_setup(struct dsa_switch *ds)
{ struct ksz_device *dev = ds->priv; int ret;
/* The VLAN aware is a global setting. Mixed vlan *filteringsarenotsupported.
*/
ds->vlan_filtering_is_global = true;
/* Enable aggressive back off for half duplex & UNH mode */
ret = lan937x_cfg(dev, REG_SW_MAC_CTRL_0, (SW_PAUSE_UNH_MODE |
SW_NEW_BACKOFF |
SW_AGGR_BACKOFF), true); if (ret < 0) return ret;
/* If NO_EXC_COLLISION_DROP bit is set, the switch will not drop *packetswhen16ormorecollisionsoccur
*/
ret = lan937x_cfg(dev, REG_SW_MAC_CTRL_1, NO_EXC_COLLISION_DROP, true); if (ret < 0) return ret;
/* enable global MIB counter freeze function */
ret = lan937x_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true); if (ret < 0) return ret;
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.