diff options
author | Roman Yeryomin <roman@advem.lv> | 2018-01-17 00:07:58 +0200 |
---|---|---|
committer | John Crispin <john@phrozen.org> | 2018-02-15 10:46:39 +0100 |
commit | f4e5880d0f3496a3151fe24d87ca2d08d3403a83 (patch) | |
tree | b2a3f276e4786d7eed8d928cd8984975334556cf /target/linux/ramips/files-4.14/drivers/net/ethernet/mtk/mdio_rt2880.c | |
parent | a3b9cbafc33a94606368226020e7b69ff85f1115 (diff) | |
download | upstream-f4e5880d0f3496a3151fe24d87ca2d08d3403a83.tar.gz upstream-f4e5880d0f3496a3151fe24d87ca2d08d3403a83.tar.bz2 upstream-f4e5880d0f3496a3151fe24d87ca2d08d3403a83.zip |
ramips: preliminary support for 4.14
- removed upstreamed patches
- 0901-spansion_nand_id_fix.patch is disabled, not clear if it's needed
Signed-off-by: Roman Yeryomin <roman@advem.lv>
Signed-off-by: John Crispin <john@phrozen.org>
Diffstat (limited to 'target/linux/ramips/files-4.14/drivers/net/ethernet/mtk/mdio_rt2880.c')
-rw-r--r-- | target/linux/ramips/files-4.14/drivers/net/ethernet/mtk/mdio_rt2880.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/target/linux/ramips/files-4.14/drivers/net/ethernet/mtk/mdio_rt2880.c b/target/linux/ramips/files-4.14/drivers/net/ethernet/mtk/mdio_rt2880.c new file mode 100644 index 0000000000..e72f8c72b1 --- /dev/null +++ b/target/linux/ramips/files-4.14/drivers/net/ethernet/mtk/mdio_rt2880.c @@ -0,0 +1,222 @@ +/* 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; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2009-2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name> + * Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/of_net.h> +#include <linux/of_mdio.h> + +#include "mtk_eth_soc.h" +#include "mdio_rt2880.h" +#include "mdio.h" + +#define FE_MDIO_RETRY 1000 + +static unsigned char *rt2880_speed_str(struct fe_priv *priv) +{ + switch (priv->phy->speed[0]) { + case SPEED_1000: + return "1000"; + case SPEED_100: + return "100"; + case SPEED_10: + return "10"; + } + + return "?"; +} + +void rt2880_mdio_link_adjust(struct fe_priv *priv, int port) +{ + u32 mdio_cfg; + + if (!priv->link[0]) { + netif_carrier_off(priv->netdev); + netdev_info(priv->netdev, "link down\n"); + return; + } + + mdio_cfg = FE_MDIO_CFG_TX_CLK_SKEW_200 | + FE_MDIO_CFG_RX_CLK_SKEW_200 | + FE_MDIO_CFG_GP1_FRC_EN; + + if (priv->phy->duplex[0] == DUPLEX_FULL) + mdio_cfg |= FE_MDIO_CFG_GP1_DUPLEX; + + if (priv->phy->tx_fc[0]) + mdio_cfg |= FE_MDIO_CFG_GP1_FC_TX; + + if (priv->phy->rx_fc[0]) + mdio_cfg |= FE_MDIO_CFG_GP1_FC_RX; + + switch (priv->phy->speed[0]) { + case SPEED_10: + mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_10; + break; + case SPEED_100: + mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_100; + break; + case SPEED_1000: + mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_1000; + break; + default: + BUG(); + } + + fe_w32(mdio_cfg, FE_MDIO_CFG); + + netif_carrier_on(priv->netdev); + netdev_info(priv->netdev, "link up (%sMbps/%s duplex)\n", + rt2880_speed_str(priv), + (priv->phy->duplex[0] == DUPLEX_FULL) ? "Full" : "Half"); +} + +static int rt2880_mdio_wait_ready(struct fe_priv *priv) +{ + int retries; + + retries = FE_MDIO_RETRY; + while (1) { + u32 t; + + t = fe_r32(FE_MDIO_ACCESS); + if ((t & BIT(31)) == 0) + return 0; + + if (retries-- == 0) + break; + + udelay(1); + } + + dev_err(priv->device, "MDIO operation timed out\n"); + return -ETIMEDOUT; +} + +int rt2880_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) +{ + struct fe_priv *priv = bus->priv; + int err; + u32 t; + + err = rt2880_mdio_wait_ready(priv); + if (err) + return 0xffff; + + t = (phy_addr << 24) | (phy_reg << 16); + fe_w32(t, FE_MDIO_ACCESS); + t |= BIT(31); + fe_w32(t, FE_MDIO_ACCESS); + + err = rt2880_mdio_wait_ready(priv); + if (err) + return 0xffff; + + pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, + phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff); + + return fe_r32(FE_MDIO_ACCESS) & 0xffff; +} + +int rt2880_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) +{ + struct fe_priv *priv = bus->priv; + int err; + u32 t; + + pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, + phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff); + + err = rt2880_mdio_wait_ready(priv); + if (err) + return err; + + t = (1 << 30) | (phy_addr << 24) | (phy_reg << 16) | val; + fe_w32(t, FE_MDIO_ACCESS); + t |= BIT(31); + fe_w32(t, FE_MDIO_ACCESS); + + return rt2880_mdio_wait_ready(priv); +} + +void rt2880_port_init(struct fe_priv *priv, struct device_node *np) +{ + const __be32 *id = of_get_property(np, "reg", NULL); + const __be32 *link; + int size; + int phy_mode; + + if (!id || (be32_to_cpu(*id) != 0)) { + pr_err("%s: invalid port id\n", np->name); + return; + } + + priv->phy->phy_fixed[0] = of_get_property(np, + "mediatek,fixed-link", &size); + if (priv->phy->phy_fixed[0] && + (size != (4 * sizeof(*priv->phy->phy_fixed[0])))) { + pr_err("%s: invalid fixed link property\n", np->name); + priv->phy->phy_fixed[0] = NULL; + return; + } + + phy_mode = of_get_phy_mode(np); + switch (phy_mode) { + case PHY_INTERFACE_MODE_RGMII: + break; + case PHY_INTERFACE_MODE_MII: + break; + case PHY_INTERFACE_MODE_RMII: + break; + default: + if (!priv->phy->phy_fixed[0]) + dev_err(priv->device, "port %d - invalid phy mode\n", + priv->phy->speed[0]); + break; + } + + priv->phy->phy_node[0] = of_parse_phandle(np, "phy-handle", 0); + if (!priv->phy->phy_node[0] && !priv->phy->phy_fixed[0]) + return; + + if (priv->phy->phy_fixed[0]) { + link = priv->phy->phy_fixed[0]; + priv->phy->speed[0] = be32_to_cpup(link++); + priv->phy->duplex[0] = be32_to_cpup(link++); + priv->phy->tx_fc[0] = be32_to_cpup(link++); + priv->phy->rx_fc[0] = be32_to_cpup(link++); + + priv->link[0] = 1; + switch (priv->phy->speed[0]) { + case SPEED_10: + break; + case SPEED_100: + break; + case SPEED_1000: + break; + default: + dev_err(priv->device, "invalid link speed: %d\n", + priv->phy->speed[0]); + priv->phy->phy_fixed[0] = 0; + return; + } + dev_info(priv->device, "using fixed link parameters\n"); + rt2880_mdio_link_adjust(priv, 0); + return; + } + + if (priv->phy->phy_node[0] && mdiobus_get_phy(priv->mii_bus, 0)) + fe_connect_phy_node(priv, priv->phy->phy_node[0]); +} |