// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright (c) 2015, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2020 Sartura Ltd. */
/* If we don't have a clock for AHB use the fixed value */
ahb_rate = IPQ_MDIO_CLK_RATE; if (priv->mdio_clk)
ahb_rate = clk_get_rate(priv->mdio_clk);
/* MDC rate is ahb_rate/(MDIO_MODE_DIV + 1) * While supported, internal documentation doesn't * assure correct functionality of the MDIO bus * with divider of 1, 2 or 4.
*/ for (div = 8; div <= 256; div *= 2) { /* The requested rate is supported by the div */ if (priv->mdc_rate == DIV_ROUND_UP(ahb_rate, div)) {
val = readl(priv->membase + MDIO_MODE_REG);
val &= ~MDIO_MODE_DIV_MASK;
val |= MDIO_MODE_DIV(div);
writel(val, priv->membase + MDIO_MODE_REG);
return 0;
}
}
/* The requested rate is not supported */ return -EINVAL;
}
/* To indicate CMN_PLL that ethernet_ldo has been ready if platform resource 1 * is specified in the device tree.
*/ if (priv->eth_ldo_rdy) {
val = readl(priv->eth_ldo_rdy);
val |= BIT(0);
writel(val, priv->eth_ldo_rdy);
fsleep(IPQ_PHY_SET_DELAY_US);
}
/* Configure MDIO clock source frequency if clock is specified in the device tree */
ret = clk_set_rate(priv->mdio_clk, IPQ_MDIO_CLK_RATE); if (ret) return ret;
ret = clk_prepare_enable(priv->mdio_clk); if (ret) return ret;
/* MDC rate defined in DT, we don't have to decide a default value */ if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&priv->mdc_rate)) return;
/* If we don't have a clock for AHB use the fixed value */
ahb_rate = IPQ_MDIO_CLK_RATE; if (priv->mdio_clk)
ahb_rate = clk_get_rate(priv->mdio_clk);
/* Check what is the current div set */
val = readl(priv->membase + MDIO_MODE_REG);
div = FIELD_GET(MDIO_MODE_DIV_MASK, val);
/* div is not set to the default value of /256 * Probably someone changed that (bootloader, other drivers) * Keep this and don't overwrite it.
*/ if (div != MDIO_MODE_DIV_256) {
priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div + 1); return;
}
/* If div is /256 assume nobody have set this value and * try to find one MDC rate that is close the 802.3 spec of * 2.5MHz
*/ for (div = 256; div >= 8; div /= 2) { /* Stop as soon as we found a divider that * reached the closest value to 2.5MHz
*/ if (DIV_ROUND_UP(ahb_rate, div) > 2500000) break;
bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); if (!bus) return -ENOMEM;
priv = bus->priv;
priv->membase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->membase)) return PTR_ERR(priv->membase);
priv->mdio_clk = devm_clk_get_optional(&pdev->dev, "gcc_mdio_ahb_clk"); if (IS_ERR(priv->mdio_clk)) return PTR_ERR(priv->mdio_clk);
ipq4019_mdio_select_mdc_rate(pdev, priv);
ret = ipq4019_mdio_set_div(priv); if (ret) return ret;
/* The platform resource is provided on the chipset IPQ5018 */ /* This resource is optional */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) {
priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->eth_ldo_rdy)) return PTR_ERR(priv->eth_ldo_rdy);
}
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.