From 9c2422709075196022fcbc2d0f5f83e01d02b951 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 13 Feb 2017 12:38:27 +0100 Subject: ramips: add v4.9 support NAND support is missing Signed-off-by: John Crispin --- .../drivers/net/ethernet/mtk/mdio_mt7620.c | 168 +++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 target/linux/ramips/files-4.9/drivers/net/ethernet/mtk/mdio_mt7620.c (limited to 'target/linux/ramips/files-4.9/drivers/net/ethernet/mtk/mdio_mt7620.c') diff --git a/target/linux/ramips/files-4.9/drivers/net/ethernet/mtk/mdio_mt7620.c b/target/linux/ramips/files-4.9/drivers/net/ethernet/mtk/mdio_mt7620.c new file mode 100644 index 0000000000..9efe7896a5 --- /dev/null +++ b/target/linux/ramips/files-4.9/drivers/net/ethernet/mtk/mdio_mt7620.c @@ -0,0 +1,168 @@ +/* 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 + * Copyright (C) 2009-2015 Felix Fietkau + * Copyright (C) 2013-2015 Michael Lee + */ + +#include +#include +#include + +#include "mtk_eth_soc.h" +#include "gsw_mt7620.h" +#include "mdio.h" + +static int mt7620_mii_busy_wait(struct mt7620_gsw *gsw) +{ + unsigned long t_start = jiffies; + + while (1) { + if (!(mtk_switch_r32(gsw, MT7620A_GSW_REG_PIAC) & GSW_MDIO_ACCESS)) + return 0; + if (time_after(jiffies, t_start + GSW_REG_PHY_TIMEOUT)) + break; + } + + dev_err(gsw->dev, "mdio: MDIO timeout\n"); + return -1; +} + +u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr, + u32 phy_register, u32 write_data) +{ + if (mt7620_mii_busy_wait(gsw)) + return -1; + + write_data &= 0xffff; + + mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_WRITE | + (phy_register << GSW_MDIO_REG_SHIFT) | + (phy_addr << GSW_MDIO_ADDR_SHIFT) | write_data, + MT7620A_GSW_REG_PIAC); + + if (mt7620_mii_busy_wait(gsw)) + return -1; + + return 0; +} + +u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg) +{ + u32 d; + + if (mt7620_mii_busy_wait(gsw)) + return 0xffff; + + mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_READ | + (phy_reg << GSW_MDIO_REG_SHIFT) | + (phy_addr << GSW_MDIO_ADDR_SHIFT), + MT7620A_GSW_REG_PIAC); + + if (mt7620_mii_busy_wait(gsw)) + return 0xffff; + + d = mtk_switch_r32(gsw, MT7620A_GSW_REG_PIAC) & 0xffff; + + return d; +} + +int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) +{ + struct fe_priv *priv = bus->priv; + struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv; + + return _mt7620_mii_write(gsw, phy_addr, phy_reg, val); +} + +int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) +{ + struct fe_priv *priv = bus->priv; + struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv; + + return _mt7620_mii_read(gsw, phy_addr, phy_reg); +} + +void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val) +{ + _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff); + _mt7620_mii_write(gsw, 0x1f, (reg >> 2) & 0xf, val & 0xffff); + _mt7620_mii_write(gsw, 0x1f, 0x10, val >> 16); +} + +u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg) +{ + u16 high, low; + + _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff); + low = _mt7620_mii_read(gsw, 0x1f, (reg >> 2) & 0xf); + high = _mt7620_mii_read(gsw, 0x1f, 0x10); + + return (high << 16) | (low & 0xffff); +} + +static unsigned char *fe_speed_str(int speed) +{ + switch (speed) { + case 2: + case SPEED_1000: + return "1000"; + case 1: + case SPEED_100: + return "100"; + case 0: + case SPEED_10: + return "10"; + } + + return "? "; +} + +int mt7620_has_carrier(struct fe_priv *priv) +{ + struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv; + int i; + + for (i = 0; i < GSW_PORT6; i++) + if (mtk_switch_r32(gsw, GSW_REG_PORT_STATUS(i)) & 0x1) + return 1; + return 0; +} + + +void mt7620_handle_carrier(struct fe_priv *priv) +{ + if (!priv->phy) + return; + + if (mt7620_has_carrier(priv)) + netif_carrier_on(priv->netdev); + else + netif_carrier_off(priv->netdev); +} + +void mt7620_print_link_state(struct fe_priv *priv, int port, int link, + int speed, int duplex) +{ + if (link) + netdev_info(priv->netdev, "port %d link up (%sMbps/%s duplex)\n", + port, fe_speed_str(speed), + (duplex) ? "Full" : "Half"); + else + netdev_info(priv->netdev, "port %d link down\n", port); +} + +void mt7620_mdio_link_adjust(struct fe_priv *priv, int port) +{ + mt7620_print_link_state(priv, port, priv->link[port], + priv->phy->speed[port], + (priv->phy->duplex[port] == DUPLEX_FULL)); + mt7620_handle_carrier(priv); +} -- cgit v1.2.3