ramips: ethernet: ralink: rewrite esw_rt3050 to support link states
authorAlexander Couzens <lynxis@fe80.eu>
Wed, 9 Jun 2021 21:46:35 +0000 (23:46 +0200)
committerAlexander Couzens <lynxis@fe80.eu>
Fri, 25 Jun 2021 10:30:20 +0000 (12:30 +0200)
Ensure the esw is initialized before the ethernet device is sending
packets. Further implement carrier detection similar to mt7620.
If any port has a link, the ethernet device will detect a carrier.

Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
target/linux/ramips/files/drivers/net/ethernet/ralink/esw_rt3050.c
target/linux/ramips/files/drivers/net/ethernet/ralink/esw_rt3050.h
target/linux/ramips/files/drivers/net/ethernet/ralink/soc_rt3050.c

index 4a7dbb2d03952a3c226a40bc9b0fe2d50472ebb2..75b6707be2b55d66932beac587a06fb05c3ea6d3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/reset.h>
 
 #include "mtk_eth_soc.h"
+#include "esw_rt3050.h"
 
 /* HW limitations for this switch:
  * - No large frame support (PKT_MAX_LEN at most 1536)
@@ -216,6 +217,7 @@ struct rt305x_esw {
        struct device           *dev;
        void __iomem            *base;
        int                     irq;
+       struct fe_priv          *priv;
 
        /* Protects against concurrent register r/w operations. */
        spinlock_t              reg_rw_lock;
@@ -736,19 +738,44 @@ static void esw_hw_init(struct rt305x_esw *esw)
        esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR);
 }
 
+
+int rt3050_esw_has_carrier(struct fe_priv *priv)
+{
+       struct rt305x_esw *esw = priv->soc->swpriv;
+       u32 link;
+       int i;
+       bool cpuport;
+
+       link = esw_r32(esw, RT305X_ESW_REG_POA);
+       link >>= RT305X_ESW_POA_LINK_SHIFT;
+       cpuport = link & BIT(RT305X_ESW_PORT6);
+       link &= RT305X_ESW_POA_LINK_MASK;
+       for (i = 0; i <= RT305X_ESW_PORT5; i++) {
+               if (priv->link[i] != (link & BIT(i)))
+                       dev_info(esw->dev, "port %d link %s\n", i, link & BIT(i) ? "up" : "down");
+               priv->link[i] = link & BIT(i);
+       }
+
+       return !!link && cpuport;
+}
+
 static irqreturn_t esw_interrupt(int irq, void *_esw)
 {
-       struct rt305x_esw *esw = (struct rt305x_esw *)_esw;
+       struct rt305x_esw *esw = (struct rt305x_esw *) _esw;
        u32 status;
+       int i;
 
        status = esw_r32(esw, RT305X_ESW_REG_ISR);
        if (status & RT305X_ESW_PORT_ST_CHG) {
-               u32 link = esw_r32(esw, RT305X_ESW_REG_POA);
-
-               link >>= RT305X_ESW_POA_LINK_SHIFT;
-               link &= RT305X_ESW_POA_LINK_MASK;
-               dev_info(esw->dev, "link changed 0x%02X\n", link);
+               if (!esw->priv)
+                       goto out;
+               if (rt3050_esw_has_carrier(esw->priv))
+                       netif_carrier_on(esw->priv->netdev);
+               else
+                       netif_carrier_off(esw->priv->netdev);
        }
+
+out:
        esw_w32(esw, status, RT305X_ESW_REG_ISR);
 
        return IRQ_HANDLED;
@@ -1376,9 +1403,7 @@ static int esw_probe(struct platform_device *pdev)
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct device_node *np = pdev->dev.of_node;
        const __be32 *port_map, *port_disable, *reg_init;
-       struct switch_dev *swdev;
        struct rt305x_esw *esw;
-       int ret;
 
        esw = devm_kzalloc(&pdev->dev, sizeof(*esw), GFP_KERNEL);
        if (!esw)
@@ -1417,6 +1442,67 @@ static int esw_probe(struct platform_device *pdev)
        if (IS_ERR(esw->rst_ephy))
                esw->rst_ephy = NULL;
 
+       spin_lock_init(&esw->reg_rw_lock);
+       platform_set_drvdata(pdev, esw);
+
+       return 0;
+}
+
+static int esw_remove(struct platform_device *pdev)
+{
+       struct rt305x_esw *esw = platform_get_drvdata(pdev);
+
+       if (esw) {
+               esw_w32(esw, ~0, RT305X_ESW_REG_IMR);
+               platform_set_drvdata(pdev, NULL);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id ralink_esw_match[] = {
+       { .compatible = "ralink,rt3050-esw" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ralink_esw_match);
+
+/* called by the ethernet driver to bound with the switch driver */
+int rt3050_esw_init(struct fe_priv *priv)
+{
+       struct device_node *np = priv->switch_np;
+       struct platform_device *pdev = of_find_device_by_node(np);
+       struct switch_dev *swdev;
+       struct rt305x_esw *esw;
+       const __be32 *rgmii;
+       int ret;
+
+       if (!pdev)
+               return -ENODEV;
+
+       if (!of_device_is_compatible(np, ralink_esw_match->compatible))
+               return -EINVAL;
+
+       esw = platform_get_drvdata(pdev);
+       if (!esw)
+               return -EPROBE_DEFER;
+
+       priv->soc->swpriv = esw;
+       esw->priv = priv;
+
+       esw_hw_init(esw);
+
+       rgmii = of_get_property(np, "ralink,rgmii", NULL);
+       if (rgmii && be32_to_cpu(*rgmii) == 1) {
+               /*
+                * External switch connected to RGMII interface.
+                * Unregister the switch device after initialization.
+                */
+               dev_err(&pdev->dev, "RGMII mode, not exporting switch device.\n");
+               unregister_switch(&esw->swdev);
+               platform_set_drvdata(pdev, NULL);
+               return -ENODEV;
+       }
+
        swdev = &esw->swdev;
        swdev->of_node = pdev->dev.of_node;
        swdev->name = "rt305x-esw";
@@ -1432,53 +1518,19 @@ static int esw_probe(struct platform_device *pdev)
                return ret;
        }
 
-       platform_set_drvdata(pdev, esw);
-
-       spin_lock_init(&esw->reg_rw_lock);
-
-       esw_hw_init(esw);
-
-       reg_init = of_get_property(np, "ralink,rgmii", NULL);
-       if (reg_init && be32_to_cpu(*reg_init) == 1) {
-               /* 
-                * External switch connected to RGMII interface. 
-                * Unregister the switch device after initialization. 
-                */
-               dev_err(&pdev->dev, "RGMII mode, not exporting switch device.\n");
-               unregister_switch(&esw->swdev);
-               platform_set_drvdata(pdev, NULL);
-               return -ENODEV;
-       }
-
        ret = devm_request_irq(&pdev->dev, esw->irq, esw_interrupt, 0, "esw",
-                              esw);
-
+                       esw);
        if (!ret) {
                esw_w32(esw, RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_ISR);
                esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR);
        }
 
-       return ret;
-}
-
-static int esw_remove(struct platform_device *pdev)
-{
-       struct rt305x_esw *esw = platform_get_drvdata(pdev);
-
-       if (esw) {
-               esw_w32(esw, ~0, RT305X_ESW_REG_IMR);
-               platform_set_drvdata(pdev, NULL);
-       }
+       dev_info(&pdev->dev, "mediatek esw at 0x%08lx, irq %d initialized\n",
+                  esw->base, esw->irq);
 
        return 0;
 }
 
-static const struct of_device_id ralink_esw_match[] = {
-       { .compatible = "ralink,rt3050-esw" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ralink_esw_match);
-
 static struct platform_driver esw_driver = {
        .probe = esw_probe,
        .remove = esw_remove,
index bbc8fbd52a40fb3532939730166d06ecf9598a14..c9650209cfe124e63a082f0d317b94329b69f957 100644 (file)
@@ -26,4 +26,7 @@ static inline int __init mtk_switch_init(void) { return 0; }
 static inline void mtk_switch_exit(void) { }
 
 #endif
+
+int rt3050_esw_init(struct fe_priv *priv);
+int rt3050_esw_has_carrier(struct fe_priv *priv);
 #endif
index f98d7ec3da68f223b4e34f7a92562f919412f34a..435f007477883e83d22a8334290da6d2a413baf3 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/mach-ralink/ralink_regs.h>
 
 #include "mtk_eth_soc.h"
+#include "esw_rt3050.h"
 #include "mdio_rt2880.h"
 
 static const u16 rt5350_reg_table[FE_REG_COUNT] = {
@@ -115,6 +116,7 @@ static void rt5350_tx_dma(struct fe_tx_dma *txd)
 static struct fe_soc_data rt3050_data = {
        .init_data = rt305x_init_data,
        .fwd_config = rt3050_fwd_config,
+       .switch_init = rt3050_esw_init,
        .pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
        .checksum_bit = RX_DMA_L4VALID,
        .rx_int = FE_RX_DONE_INT,
@@ -127,6 +129,7 @@ static struct fe_soc_data rt5350_data = {
        .reg_table = rt5350_reg_table,
        .set_mac = rt5350_set_mac,
        .fwd_config = rt5350_fwd_config,
+       .switch_init = rt3050_esw_init,
        .tx_dma = rt5350_tx_dma,
        .pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
        .checksum_bit = RX_DMA_L4VALID,