diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2018-09-11 17:23:33 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2018-09-11 17:23:33 +0200 |
commit | 149d33a6cd94debad2e9692b5bd8d6a059cd1354 (patch) | |
tree | ea1b484a6ace1d7e2df9620a3d209c83e08557c2 /drivers | |
parent | f97ae392215b34fd836ee44a377c619e568038a4 (diff) | |
parent | df333632e18463e64b35fba1df65b155fc82d781 (diff) | |
download | barebox-149d33a6cd94debad2e9692b5bd8d6a059cd1354.tar.gz barebox-149d33a6cd94debad2e9692b5bd8d6a059cd1354.tar.xz |
Merge branch 'for-next/net'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/phy/Kconfig | 5 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/davicom.c | 140 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 96 |
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; } |