/* Wait for CK_OUT_EN clear */ do {
val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG);
val &= SDCC_DLL_CONFIG_CK_OUT_EN; if (!val) break;
mdelay(1);
retry--;
} while (retry > 0); if (!retry)
dev_err(dev, "Clear CK_OUT_EN timedout\n");
/* Set CK_OUT_EN */
rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN,
SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG);
/* Wait for CK_OUT_EN set */
retry = 1000; do {
val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG);
val &= SDCC_DLL_CONFIG_CK_OUT_EN; if (val) break;
mdelay(1);
retry--;
} while (retry > 0); if (!retry)
dev_err(dev, "Set CK_OUT_EN timedout\n");
/* Set DDR_CAL_EN */
rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN,
SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2);
if (!ethqos->has_emac_ge_3) {
rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS,
0, SDCC_HC_REG_DLL_CONFIG2);
staticint ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed)
{ struct device *dev = ðqos->pdev->dev; int phase_shift; int loopback;
/* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */ if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID ||
ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID)
phase_shift = 0; else
phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN;
/* Determine if this platform wants loopback enabled after programming */ if (ethqos->rgmii_config_loopback_en)
loopback = RGMII_CONFIG_LOOPBACK_EN; else
loopback = 0;
staticint ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed)
{ struct device *dev = ðqos->pdev->dev; volatileunsignedint dll_lock; unsignedint i, retry = 1000;
/* Reset to POR values and enable clk */ for (i = 0; i < ethqos->num_por; i++)
rgmii_writel(ethqos, ethqos->por[i].value,
ethqos->por[i].offset);
ethqos_set_func_clk_en(ethqos);
/* Initialize the DLL first */
/* Set DLL_RST */
rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST,
SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG);
/* Set PDN */
rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN,
SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG);
if (speed != SPEED_100 && speed != SPEED_10) { /* Set DLL_EN */
rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN,
SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG);
/* Set CK_OUT_EN */
rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN,
SDCC_DLL_CONFIG_CK_OUT_EN,
SDCC_HC_REG_DLL_CONFIG);
/* Set USR_CTL bit 26 with mask of 3 bits */ if (!ethqos->has_emac_ge_3)
rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26),
SDCC_USR_CTL);
/* wait for DLL LOCK */ do {
mdelay(1);
dll_lock = rgmii_readl(ethqos, SDC4_STATUS); if (dll_lock & SDC4_STATUS_DLL_LOCK) break;
retry--;
} while (retry > 0); if (!retry)
dev_err(dev, "Timeout while waiting for DLL lock\n");
}
if (speed == SPEED_1000)
ethqos_dll_configure(ethqos);
ethqos_rgmii_macro_init(ethqos, speed);
return 0;
}
staticvoid ethqos_set_serdes_speed(struct qcom_ethqos *ethqos, int speed)
{ if (ethqos->serdes_speed != speed) {
phy_set_speed(ethqos->serdes_phy, speed);
ethqos->serdes_speed = speed;
}
}
/* On interface toggle MAC registers gets reset. * Configure MAC block for SGMII on ethernet phy link up
*/ staticint ethqos_configure_sgmii(struct qcom_ethqos *ethqos, int speed)
{ struct net_device *dev = platform_get_drvdata(ethqos->pdev); struct stmmac_priv *priv = netdev_priv(dev); int val;
val = readl(ethqos->mac_base + MAC_CTRL_REG);
switch (speed) { case SPEED_2500:
val &= ~ETHQOS_MAC_CTRL_PORT_SEL;
rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
RGMII_IO_MACRO_CONFIG2);
ethqos_set_serdes_speed(ethqos, SPEED_2500);
ethqos_pcs_set_inband(priv, false); break; case SPEED_1000:
val &= ~ETHQOS_MAC_CTRL_PORT_SEL;
rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
RGMII_IO_MACRO_CONFIG2);
ethqos_set_serdes_speed(ethqos, SPEED_1000);
ethqos_pcs_set_inband(priv, true); break; case SPEED_100:
val |= ETHQOS_MAC_CTRL_PORT_SEL | ETHQOS_MAC_CTRL_SPEED_MODE;
ethqos_set_serdes_speed(ethqos, SPEED_1000);
ethqos_pcs_set_inband(priv, true); break; case SPEED_10:
val |= ETHQOS_MAC_CTRL_PORT_SEL;
val &= ~ETHQOS_MAC_CTRL_SPEED_MODE;
rgmii_updatel(ethqos, RGMII_CONFIG_SGMII_CLK_DVDR,
FIELD_PREP(RGMII_CONFIG_SGMII_CLK_DVDR,
SGMII_10M_RX_CLK_DVDR),
RGMII_IO_MACRO_CONFIG);
ethqos_set_serdes_speed(ethqos, SPEED_1000);
ethqos_pcs_set_inband(priv, true); break;
}
staticint ethqos_clks_config(void *priv, bool enabled)
{ struct qcom_ethqos *ethqos = priv; int ret = 0;
if (enabled) {
ret = clk_prepare_enable(ethqos->link_clk); if (ret) {
dev_err(ðqos->pdev->dev, "link_clk enable failed\n"); return ret;
}
/* Enable functional clock to prevent DMA reset to timeout due * to lacking PHY clock after the hardware block has been power * cycled. The actual configuration will be adjusted once * ethqos_fix_mac_speed() is invoked.
*/
ethqos_set_func_clk_en(ethqos);
} else {
clk_disable_unprepare(ethqos->link_clk);
}
/* Max the PTP ref clock out to get the best resolution possible */
err = clk_set_rate(plat_dat->clk_ptp_ref, ULONG_MAX); if (err)
netdev_err(priv->dev, "Failed to max out clk_ptp_ref: %d\n", err);
plat_dat->clk_ptp_rate = clk_get_rate(plat_dat->clk_ptp_ref);
ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii"); if (IS_ERR(ethqos->link_clk)) return dev_err_probe(dev, PTR_ERR(ethqos->link_clk), "Failed to get link_clk\n");
ret = ethqos_clks_config(ethqos, true); if (ret) return ret;
ret = devm_add_action_or_reset(dev, ethqos_clks_disable, ethqos); if (ret) return ret;
ethqos->serdes_phy = devm_phy_optional_get(dev, "serdes"); if (IS_ERR(ethqos->serdes_phy)) return dev_err_probe(dev, PTR_ERR(ethqos->serdes_phy), "Failed to get serdes phy\n");
plat_dat->bsp_priv = ethqos;
plat_dat->fix_mac_speed = ethqos_fix_mac_speed;
plat_dat->dump_debug_regs = rgmii_dump;
plat_dat->ptp_clk_freq_config = ethqos_ptp_clk_freq_config;
plat_dat->has_gmac4 = 1; if (ethqos->has_emac_ge_3)
plat_dat->dwmac4_addrs = &data->dwmac4_addrs;
plat_dat->pmt = 1; if (of_property_read_bool(np, "snps,tso"))
plat_dat->flags |= STMMAC_FLAG_TSO_EN; if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
plat_dat->flags |= STMMAC_FLAG_RX_CLK_RUNS_IN_LPI; if (data->has_integrated_pcs)
plat_dat->flags |= STMMAC_FLAG_HAS_INTEGRATED_PCS; if (data->dma_addr_width)
plat_dat->host_dma_width = data->dma_addr_width;
if (ethqos->serdes_phy) {
plat_dat->serdes_powerup = qcom_ethqos_serdes_powerup;
plat_dat->serdes_powerdown = qcom_ethqos_serdes_powerdown;
}
/* Enable TSO on queue0 and enable TBS on rest of the queues */ for (i = 1; i < plat_dat->tx_queues_to_use; i++)
plat_dat->tx_queues_cfg[i].tbs_en = 1;
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.