Merge branch 'xgmac_mdio-preamble-suppression-and-custom-MDC-frequerncies'
Tobias Waldekranz says: ==================== net/fsl: xgmac_mdio: Preamble suppression and custom MDC frequencies The first patch removes the docs for a binding that has never been supported by the driver as far as I can see. This is a bit of a mystery to me, maybe Freescale/NXP had/has support for it in an internal version? We then start working on the xgmac_mdio driver, converting the driver to exclusively use managed resources, thereby simplifying the error paths. Suggested by Andrew. Preamble suppression is then added, followed by MDC frequency customization. Neither code will change any bits if the corresponding dt properties are not specified, so as to not trample on any setup done by the bootloader, which boards might have relied on up to now. Finally, we document the new bindings. Tested on a T1023 based board. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
f0a910dd04
|
@ -388,14 +388,24 @@ PROPERTIES
|
|||
Value type: <prop-encoded-array>
|
||||
Definition: A standard property.
|
||||
|
||||
- bus-frequency
|
||||
- clocks
|
||||
Usage: optional
|
||||
Value type: <phandle>
|
||||
Definition: A reference to the input clock of the controller
|
||||
from which the MDC frequency is derived.
|
||||
|
||||
- clock-frequency
|
||||
Usage: optional
|
||||
Value type: <u32>
|
||||
Definition: Specifies the external MDIO bus clock speed to
|
||||
be used, if different from the standard 2.5 MHz.
|
||||
This may be due to the standard speed being unsupported (e.g.
|
||||
due to a hardware problem), or to advertise that all relevant
|
||||
components in the system support a faster speed.
|
||||
Definition: Specifies the external MDC frequency, in Hertz, to
|
||||
be used. Requires that the input clock is specified in the
|
||||
"clocks" property. See also: mdio.yaml.
|
||||
|
||||
- suppress-preamble
|
||||
Usage: optional
|
||||
Value type: <boolean>
|
||||
Definition: Disable generation of preamble bits. See also:
|
||||
mdio.yaml.
|
||||
|
||||
- interrupts
|
||||
Usage: required for external MDIO
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/acpi_mdio.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mdio.h>
|
||||
|
@ -36,9 +37,10 @@ struct tgec_mdio_controller {
|
|||
} __packed;
|
||||
|
||||
#define MDIO_STAT_ENC BIT(6)
|
||||
#define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8)
|
||||
#define MDIO_STAT_CLKDIV(x) (((x) & 0x1ff) << 7)
|
||||
#define MDIO_STAT_BSY BIT(0)
|
||||
#define MDIO_STAT_RD_ER BIT(1)
|
||||
#define MDIO_STAT_PRE_DIS BIT(5)
|
||||
#define MDIO_CTL_DEV_ADDR(x) (x & 0x1f)
|
||||
#define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5)
|
||||
#define MDIO_CTL_PRE_DIS BIT(10)
|
||||
|
@ -50,6 +52,8 @@ struct tgec_mdio_controller {
|
|||
|
||||
struct mdio_fsl_priv {
|
||||
struct tgec_mdio_controller __iomem *mdio_base;
|
||||
struct clk *enet_clk;
|
||||
u32 mdc_freq;
|
||||
bool is_little_endian;
|
||||
bool has_a009885;
|
||||
bool has_a011043;
|
||||
|
@ -254,6 +258,50 @@ irq_restore:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int xgmac_mdio_set_mdc_freq(struct mii_bus *bus)
|
||||
{
|
||||
struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;
|
||||
struct tgec_mdio_controller __iomem *regs = priv->mdio_base;
|
||||
struct device *dev = bus->parent;
|
||||
u32 mdio_stat, div;
|
||||
|
||||
if (device_property_read_u32(dev, "clock-frequency", &priv->mdc_freq))
|
||||
return 0;
|
||||
|
||||
priv->enet_clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->enet_clk)) {
|
||||
dev_err(dev, "Input clock unknown, not changing MDC frequency");
|
||||
return PTR_ERR(priv->enet_clk);
|
||||
}
|
||||
|
||||
div = ((clk_get_rate(priv->enet_clk) / priv->mdc_freq) - 1) / 2;
|
||||
if (div < 5 || div > 0x1ff) {
|
||||
dev_err(dev, "Requested MDC frequecy is out of range, ignoring");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mdio_stat = xgmac_read32(®s->mdio_stat, priv->is_little_endian);
|
||||
mdio_stat &= ~MDIO_STAT_CLKDIV(0x1ff);
|
||||
mdio_stat |= MDIO_STAT_CLKDIV(div);
|
||||
xgmac_write32(mdio_stat, ®s->mdio_stat, priv->is_little_endian);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xgmac_mdio_set_suppress_preamble(struct mii_bus *bus)
|
||||
{
|
||||
struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;
|
||||
struct tgec_mdio_controller __iomem *regs = priv->mdio_base;
|
||||
struct device *dev = bus->parent;
|
||||
u32 mdio_stat;
|
||||
|
||||
if (!device_property_read_bool(dev, "suppress-preamble"))
|
||||
return;
|
||||
|
||||
mdio_stat = xgmac_read32(®s->mdio_stat, priv->is_little_endian);
|
||||
mdio_stat |= MDIO_STAT_PRE_DIS;
|
||||
xgmac_write32(mdio_stat, ®s->mdio_stat, priv->is_little_endian);
|
||||
}
|
||||
|
||||
static int xgmac_mdio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct fwnode_handle *fwnode;
|
||||
|
@ -273,7 +321,7 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
bus = mdiobus_alloc_size(sizeof(struct mdio_fsl_priv));
|
||||
bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(struct mdio_fsl_priv));
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -284,13 +332,11 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
|
|||
bus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res->start);
|
||||
|
||||
/* Set the PHY base address */
|
||||
priv = bus->priv;
|
||||
priv->mdio_base = ioremap(res->start, resource_size(res));
|
||||
if (!priv->mdio_base) {
|
||||
ret = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
priv->mdio_base = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (IS_ERR(priv->mdio_base))
|
||||
return PTR_ERR(priv->mdio_base);
|
||||
|
||||
/* For both ACPI and DT cases, endianness of MDIO controller
|
||||
* needs to be specified using "little-endian" property.
|
||||
|
@ -303,6 +349,12 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
|
|||
priv->has_a011043 = device_property_read_bool(&pdev->dev,
|
||||
"fsl,erratum-a011043");
|
||||
|
||||
xgmac_mdio_set_suppress_preamble(bus);
|
||||
|
||||
ret = xgmac_mdio_set_mdc_freq(bus);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fwnode = pdev->dev.fwnode;
|
||||
if (is_of_node(fwnode))
|
||||
ret = of_mdiobus_register(bus, to_of_node(fwnode));
|
||||
|
@ -312,30 +364,10 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
|
|||
ret = -EINVAL;
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "cannot register MDIO bus\n");
|
||||
goto err_registration;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, bus);
|
||||
|
||||
return 0;
|
||||
|
||||
err_registration:
|
||||
iounmap(priv->mdio_base);
|
||||
|
||||
err_ioremap:
|
||||
mdiobus_free(bus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xgmac_mdio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mii_bus *bus = platform_get_drvdata(pdev);
|
||||
struct mdio_fsl_priv *priv = bus->priv;
|
||||
|
||||
mdiobus_unregister(bus);
|
||||
iounmap(priv->mdio_base);
|
||||
mdiobus_free(bus);
|
||||
platform_set_drvdata(pdev, bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -364,7 +396,6 @@ static struct platform_driver xgmac_mdio_driver = {
|
|||
.acpi_match_table = xgmac_acpi_match,
|
||||
},
|
||||
.probe = xgmac_mdio_probe,
|
||||
.remove = xgmac_mdio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(xgmac_mdio_driver);
|
||||
|
|
Загрузка…
Ссылка в новой задаче