Commit f0a910dd authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 2e9589ff f7af8fe8
......@@ -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 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
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(&regs->mdio_stat, priv->is_little_endian);
mdio_stat &= ~MDIO_STAT_CLKDIV(0x1ff);
mdio_stat |= MDIO_STAT_CLKDIV(div);
xgmac_write32(mdio_stat, &regs->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(&regs->mdio_stat, priv->is_little_endian);
mdio_stat |= MDIO_STAT_PRE_DIS;
xgmac_write32(mdio_stat, &regs->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,31 +364,11 @@ 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;
return ret;
}
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);
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment