From 33d027c5b8fb5265ea84ac41a7bfedd805c48b24 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Thu, 9 Apr 2020 14:09:48 +0800 Subject: ramips: move and rename out-of-tree mtk eth driver move the driver into shared 'files' directory and rename all symbols from mediatek/mtk to ralink. Signed-off-by: Chuanhong Guo --- .../files/drivers/net/ethernet/ralink/gsw_mt7620.c | 313 +++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 target/linux/ramips/files/drivers/net/ethernet/ralink/gsw_mt7620.c (limited to 'target/linux/ramips/files/drivers/net/ethernet/ralink/gsw_mt7620.c') diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/gsw_mt7620.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/gsw_mt7620.c new file mode 100644 index 0000000000..bd379e6c7d --- /dev/null +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/gsw_mt7620.c @@ -0,0 +1,313 @@ +/* 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 +#include +#include + +#include + +#include "mtk_eth_soc.h" +#include "gsw_mt7620.h" + +void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg) +{ + iowrite32(val, gsw->base + reg); +} + +u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg) +{ + return ioread32(gsw->base + reg); +} + +static irqreturn_t gsw_interrupt_mt7620(int irq, void *_priv) +{ + struct fe_priv *priv = (struct fe_priv *)_priv; + struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv; + u32 status; + int i, max = (gsw->port4 == PORT4_EPHY) ? (4) : (3); + + status = mtk_switch_r32(gsw, GSW_REG_ISR); + if (status & PORT_IRQ_ST_CHG) + for (i = 0; i <= max; i++) { + u32 status = mtk_switch_r32(gsw, GSW_REG_PORT_STATUS(i)); + int link = status & 0x1; + + if (link != priv->link[i]) + mt7620_print_link_state(priv, i, link, + (status >> 2) & 3, + (status & 0x2)); + + priv->link[i] = link; + } + mt7620_handle_carrier(priv); + mtk_switch_w32(gsw, status, GSW_REG_ISR); + + return IRQ_HANDLED; +} + +static int mt7620_mdio_mode(struct device_node *eth_node) +{ + struct device_node *phy_node, *mdiobus_node; + const __be32 *id; + int ret = 0; + + mdiobus_node = of_get_child_by_name(eth_node, "mdio-bus"); + + if (mdiobus_node) { + if (of_property_read_bool(mdiobus_node, "mediatek,mdio-mode")) + ret = 1; + + for_each_child_of_node(mdiobus_node, phy_node) { + id = of_get_property(phy_node, "reg", NULL); + if (id && (be32_to_cpu(*id) == 0x1f)) + ret = 1; + } + + of_node_put(mdiobus_node); + } + + return ret; +} + +static void mt7620_hw_init(struct mt7620_gsw *gsw, int mdio_mode) +{ + u32 i; + u32 val; + u32 is_BGA = (rt_sysc_r32(0x0c) >> 16) & 1; + + rt_sysc_w32(rt_sysc_r32(SYSC_REG_CFG1) | BIT(8), SYSC_REG_CFG1); + mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_CKGCR) & ~(0x3 << 4), GSW_REG_CKGCR); + + /* Enable MIB stats */ + mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_MIB_CNT_EN) | (1 << 1), GSW_REG_MIB_CNT_EN); + + if (mdio_mode) { + u32 val; + + /* turn off ephy and set phy base addr to 12 */ + mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_GPC1) | + (0x1f << 24) | (0xc << 16), + GSW_REG_GPC1); + + /* set MT7530 central align */ + val = mt7530_mdio_r32(gsw, 0x7830); + val &= ~BIT(0); + val |= BIT(1); + mt7530_mdio_w32(gsw, 0x7830, val); + + val = mt7530_mdio_r32(gsw, 0x7a40); + val &= ~BIT(30); + mt7530_mdio_w32(gsw, 0x7a40, val); + + mt7530_mdio_w32(gsw, 0x7a78, 0x855); + } else { + + if (gsw->ephy_base) { + /* set phy base addr to ephy_base */ + mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_GPC1) | + (gsw->ephy_base << 16), + GSW_REG_GPC1); + fe_reset(BIT(24)); /* Resets the Ethernet PHY block. */ + } + + /* global page 4 */ + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x4000); + + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0x7444); + if (is_BGA) + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 19, 0x0114); + else + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 19, 0x0117); + + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x10cf); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x6212); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0777); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 29, 0x4000); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 28, 0xc077); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0000); + + /* global page 3 */ + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x3000); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0x4838); + + /* global page 2 */ + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x2000); + if (is_BGA) { + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 21, 0x0515); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x0053); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 23, 0x00bf); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0aaf); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x0fad); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0fc1); + } else { + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 21, 0x0517); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x0fd2); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 23, 0x00bf); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0aab); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x00ae); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0fff); + } + /* global page 1 */ + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x1000); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0xe7f8); + + /* turn on all PHYs */ + for (i = 0; i <= 4; i++) { + val = _mt7620_mii_read(gsw, gsw->ephy_base + i, 0); + val &= ~BIT(11); + _mt7620_mii_write(gsw, gsw->ephy_base + i, 0, val); + } + } + + /* global page 0 */ + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x8000); + _mt7620_mii_write(gsw, gsw->ephy_base + 0, 30, 0xa000); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 30, 0xa000); + _mt7620_mii_write(gsw, gsw->ephy_base + 2, 30, 0xa000); + _mt7620_mii_write(gsw, gsw->ephy_base + 3, 30, 0xa000); + + _mt7620_mii_write(gsw, gsw->ephy_base + 0, 4, 0x05e1); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 4, 0x05e1); + _mt7620_mii_write(gsw, gsw->ephy_base + 2, 4, 0x05e1); + _mt7620_mii_write(gsw, gsw->ephy_base + 3, 4, 0x05e1); + + /* global page 2 */ + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0xa000); + _mt7620_mii_write(gsw, gsw->ephy_base + 0, 16, 0x1111); + _mt7620_mii_write(gsw, gsw->ephy_base + 1, 16, 0x1010); + _mt7620_mii_write(gsw, gsw->ephy_base + 2, 16, 0x1515); + _mt7620_mii_write(gsw, gsw->ephy_base + 3, 16, 0x0f0f); + + /* CPU Port6 Force Link 1G, FC ON */ + mtk_switch_w32(gsw, 0x5e33b, GSW_REG_PORT_PMCR(6)); + + /* Set Port 6 as CPU Port */ + mtk_switch_w32(gsw, 0x7f7f7fe0, 0x0010); + + /* setup port 4 */ + if (gsw->port4 == PORT4_EPHY) { + u32 val = rt_sysc_r32(SYSC_REG_CFG1); + + val |= 3 << 14; + rt_sysc_w32(val, SYSC_REG_CFG1); + _mt7620_mii_write(gsw, gsw->ephy_base + 4, 30, 0xa000); + _mt7620_mii_write(gsw, gsw->ephy_base + 4, 4, 0x05e1); + _mt7620_mii_write(gsw, gsw->ephy_base + 4, 16, 0x1313); + pr_info("gsw: setting port4 to ephy mode\n"); + } else if (!mdio_mode) { + u32 val = rt_sysc_r32(SYSC_REG_CFG1); + + val &= ~(3 << 14); + rt_sysc_w32(val, SYSC_REG_CFG1); + pr_info("gsw: setting port4 to gmac mode\n"); + } +} + +static const struct of_device_id mediatek_gsw_match[] = { + { .compatible = "mediatek,mt7620-gsw" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mediatek_gsw_match); + +int mtk_gsw_init(struct fe_priv *priv) +{ + struct device_node *np = priv->switch_np; + struct platform_device *pdev = of_find_device_by_node(np); + struct mt7620_gsw *gsw; + + if (!pdev) + return -ENODEV; + + if (!of_device_is_compatible(np, mediatek_gsw_match->compatible)) + return -EINVAL; + + gsw = platform_get_drvdata(pdev); + priv->soc->swpriv = gsw; + + mt7620_hw_init(gsw, mt7620_mdio_mode(priv->dev->of_node)); + + if (gsw->irq) { + request_irq(gsw->irq, gsw_interrupt_mt7620, 0, + "gsw", priv); + mtk_switch_w32(gsw, ~PORT_IRQ_ST_CHG, GSW_REG_IMR); + } + + return 0; +} + +static int mt7620_gsw_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + const char *port4 = NULL; + struct mt7620_gsw *gsw; + struct device_node *np = pdev->dev.of_node; + u16 val; + + gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL); + if (!gsw) + return -ENOMEM; + + gsw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gsw->base)) + return PTR_ERR(gsw->base); + + gsw->dev = &pdev->dev; + + of_property_read_string(np, "mediatek,port4", &port4); + if (port4 && !strcmp(port4, "ephy")) + gsw->port4 = PORT4_EPHY; + else if (port4 && !strcmp(port4, "gmac")) + gsw->port4 = PORT4_EXT; + else + gsw->port4 = PORT4_EPHY; + + if (of_property_read_u16(np, "mediatek,ephy-base-address", &val) == 0) + gsw->ephy_base = val; + else + gsw->ephy_base = 0; + + gsw->irq = platform_get_irq(pdev, 0); + + platform_set_drvdata(pdev, gsw); + + return 0; +} + +static int mt7620_gsw_remove(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver gsw_driver = { + .probe = mt7620_gsw_probe, + .remove = mt7620_gsw_remove, + .driver = { + .name = "mt7620-gsw", + .owner = THIS_MODULE, + .of_match_table = mediatek_gsw_match, + }, +}; + +module_platform_driver(gsw_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7620 SoC"); +MODULE_VERSION(MTK_FE_DRV_VERSION); -- cgit v1.2.3