summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-09-11 17:23:33 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2018-09-11 17:23:33 +0200
commit149d33a6cd94debad2e9692b5bd8d6a059cd1354 (patch)
treeea1b484a6ace1d7e2df9620a3d209c83e08557c2 /drivers/net
parentf97ae392215b34fd836ee44a377c619e568038a4 (diff)
parentdf333632e18463e64b35fba1df65b155fc82d781 (diff)
downloadbarebox-149d33a6cd94debad2e9692b5bd8d6a059cd1354.tar.gz
barebox-149d33a6cd94debad2e9692b5bd8d6a059cd1354.tar.xz
Merge branch 'for-next/net'
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/davicom.c140
-rw-r--r--drivers/net/phy/mdio_bus.c96
4 files changed, 241 insertions, 1 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index cda752b659..79fb917ee7 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -18,6 +18,11 @@ config AT803X_PHY
---help---
Currently supports the AT8030, AT8031 and AT8035 PHYs.
+config DAVICOM_PHY
+ bool "Driver for Davicom PHYs"
+ ---help---
+ Currently supports dm9161e and dm9131
+
config LXT_PHY
bool "Driver for the Intel LXT PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 30b20f8ee6..4424054d91 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -1,6 +1,7 @@
obj-y += phy.o mdio_bus.o
obj-$(CONFIG_AR8327N_PHY) += ar8327.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
+obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
new file mode 100644
index 0000000000..8a784b1e54
--- /dev/null
+++ b/drivers/net/phy/davicom.c
@@ -0,0 +1,140 @@
+/*
+ * drivers/net/phy/davicom.c
+ *
+ * Driver for Davicom PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#define MII_DM9161_SCR 0x10
+#define MII_DM9161_SCR_INIT 0x0610
+#define MII_DM9161_SCR_RMII 0x0100
+
+/* DM9161 Interrupt Register */
+#define MII_DM9161_INTR 0x15
+#define MII_DM9161_INTR_PEND 0x8000
+#define MII_DM9161_INTR_DPLX_MASK 0x0800
+#define MII_DM9161_INTR_SPD_MASK 0x0400
+#define MII_DM9161_INTR_LINK_MASK 0x0200
+#define MII_DM9161_INTR_MASK 0x0100
+#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
+#define MII_DM9161_INTR_SPD_CHANGE 0x0008
+#define MII_DM9161_INTR_LINK_CHANGE 0x0004
+#define MII_DM9161_INTR_INIT 0x0000
+#define MII_DM9161_INTR_STOP \
+(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
+ | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+
+/* DM9161 10BT Configuration/Status */
+#define MII_DM9161_10BTCSR 0x12
+#define MII_DM9161_10BTCSR_INIT 0x7800
+
+MODULE_DESCRIPTION("Davicom PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+
+static int dm9161_config_aneg(struct phy_device *phydev)
+{
+ int err;
+
+ /* Isolate the PHY */
+ err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
+
+ if (err < 0)
+ return err;
+
+ /* Configure the new settings */
+ err = genphy_config_aneg(phydev);
+
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int dm9161_config_init(struct phy_device *phydev)
+{
+ int err, temp;
+
+ /* Isolate the PHY */
+ err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
+
+ if (err < 0)
+ return err;
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ temp = MII_DM9161_SCR_INIT;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ temp = MII_DM9161_SCR_INIT | MII_DM9161_SCR_RMII;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Do not bypass the scrambler/descrambler */
+ err = phy_write(phydev, MII_DM9161_SCR, temp);
+ if (err < 0)
+ return err;
+
+ /* Clear 10BTCSR to default */
+ err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT);
+
+ if (err < 0)
+ return err;
+
+ /* Reconnect the PHY, and enable Autonegotiation */
+ return phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
+}
+
+static struct phy_driver dm91xx_driver[] = {
+{
+ .phy_id = 0x0181b880,
+ .drv.name = "Davicom DM9161E",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config_init = dm9161_config_init,
+ .config_aneg = dm9161_config_aneg,
+}, {
+ .phy_id = 0x0181b8b0,
+ .drv.name = "Davicom DM9161B/C",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config_init = dm9161_config_init,
+ .config_aneg = dm9161_config_aneg,
+}, {
+ .phy_id = 0x0181b8a0,
+ .drv.name = "Davicom DM9161A",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config_init = dm9161_config_init,
+ .config_aneg = dm9161_config_aneg,
+}, {
+ .phy_id = 0x00181b80,
+ .drv.name = "Davicom DM9131",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_BASIC_FEATURES,
+} };
+
+static int dm9161_init(void)
+{
+ return phy_drivers_register(dm91xx_driver,
+ ARRAY_SIZE(dm91xx_driver));
+}
+fs_initcall(dm9161_init);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 5d4218f7c0..02e47f6a14 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -17,14 +17,19 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <common.h>
+#include <of_gpio.h>
#include <driver.h>
#include <init.h>
+#include <gpio.h>
#include <clock.h>
#include <net.h>
#include <errno.h>
#include <linux/phy.h>
#include <linux/err.h>
+#define DEFAULT_GPIO_RESET_ASSERT 1000 /* us */
+#define DEFAULT_GPIO_RESET_DEASSERT 1000 /* us */
+
LIST_HEAD(mii_bus_list);
int mdiobus_detect(struct device_d *dev)
@@ -82,6 +87,82 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
return 0;
}
+/*
+ * Node is considered a PHY node if:
+ * o Compatible string of "ethernet-phy-idX.X"
+ * o Compatible string of "ethernet-phy-ieee802.3-c45"
+ * o Compatible string of "ethernet-phy-ieee802.3-c22"
+ * o No compatibility string
+ *
+ * A device which is not a phy is expected to have a compatible string
+ * indicating what sort of device it is.
+ */
+static bool of_mdiobus_child_is_phy(struct device_node *np)
+{
+ struct property *prop;
+ const char *cp;
+
+ of_property_for_each_string(np, "compatible", prop, cp) {
+ if (!strncmp(cp, "ethernet-phy-id", strlen("ethernet-phy-id")))
+ return true;
+ }
+
+ if (of_device_is_compatible(np, "ethernet-phy-ieee802.3-c45"))
+ return true;
+
+ if (of_device_is_compatible(np, "ethernet-phy-ieee802.3-c22"))
+ return true;
+
+ if (!of_find_property(np, "compatible", NULL))
+ return true;
+
+ return false;
+}
+
+/*
+ * Reset the PHY, based on DT info
+ *
+ * If np is a phy node, and the phy node contains a reset-gpios property
+ * then reset the phy.
+ */
+static void of_mdiobus_reset_phy(struct mii_bus *bus, struct device_node *np)
+{
+ enum of_gpio_flags of_flags;
+ u32 reset_deassert_delay;
+ u32 reset_assert_delay;
+ unsigned long flags;
+ int gpio;
+ int ret;
+
+ gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &of_flags);
+ if (!gpio_is_valid(gpio))
+ return;
+
+ flags = GPIOF_OUT_INIT_INACTIVE;
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ ret = gpio_request_one(gpio, flags, np->name);
+ if (ret) {
+ dev_err(&bus->dev, "failed to request reset gpio for: %s\n",
+ np->name);
+ return;
+ }
+
+ reset_assert_delay = DEFAULT_GPIO_RESET_ASSERT;
+ of_property_read_u32(np, "reset-assert-us", &reset_assert_delay);
+
+ reset_deassert_delay = DEFAULT_GPIO_RESET_DEASSERT;
+ of_property_read_u32(np, "reset-deassert-us", &reset_deassert_delay);
+
+ /* reset the PHY */
+ dev_dbg(&bus->dev, "reset PHY with GPIO: %d\n", gpio);
+ gpio_set_active(gpio, 1);
+ udelay(reset_assert_delay);
+ gpio_set_active(gpio, 0);
+ udelay(reset_deassert_delay);
+}
+
/**
* of_mdiobus_register - Register mii_bus and create PHYs from the device tree
* @mdio: pointer to mii_bus structure
@@ -111,6 +192,10 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
continue;
}
+ if (!of_mdiobus_child_is_phy(child))
+ continue;
+
+ of_mdiobus_reset_phy(mdio, child);
of_mdiobus_register_phy(mdio, child, addr);
}
@@ -154,8 +239,17 @@ int mdiobus_register(struct mii_bus *bus)
pr_info("%s: probed\n", dev_name(&bus->dev));
- if (bus->dev.device_node)
+ if (bus->dev.device_node) {
+ /* Register PHY's as child node to mdio node */
of_mdiobus_register(bus, bus->dev.device_node);
+ }
+ else if (bus->parent->device_node) {
+ /*
+ * Register PHY's as child node to the ethernet node,
+ * if there was no mdio node
+ */
+ of_mdiobus_register(bus, bus->parent->device_node);
+ }
return 0;
}