From: Christian Marangi <[email protected]>

Add support for Ethernet controller present in Airoha AN7583. This
follow the same implementation of Airoha AN7581 with the only difference
of having a different reset number and a different logic to reach the
SCU node.

Generalize the driver for these 2 part to account for these minor
difference.

The switch init part also required some care as the Switch Internal PHY
enable BMCR_PDOWN by default and tweak to GEPHY_CONN_CFG is also needed.

Signed-off-by: Christian Marangi <[email protected]>
---
 drivers/net/airoha_eth.c | 94 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c
index e5d39b95cc5..d552b9e9de9 100644
--- a/drivers/net/airoha_eth.c
+++ b/drivers/net/airoha_eth.c
@@ -24,6 +24,7 @@
 #include <linux/ethtool.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/mii.h>
 #include <linux/time.h>
 #include <asm/arch/scu-regmap.h>
 
@@ -34,6 +35,11 @@
 #define AIROHA_MAX_NUM_RSTS            3
 #define AIROHA_MAX_NUM_XSI_RSTS                4
 
+#define AIROHA_MAX_NUM_SWITCH_PORT     4
+#define AIROHA_MAX_PBUS_TRY            10
+#define AIROHA_PBUS_SLEEP              100
+#define AIROHA_PBUS_C22_MASK           0x800000
+
 #define AIROHA_MAX_PACKET_SIZE         2048
 #define AIROHA_NUM_TX_RING             1
 #define AIROHA_NUM_RX_RING             1
@@ -86,6 +92,19 @@
 #define   SWITCH_PHY_PRE_EN            BIT(15)
 #define   SWITCH_PHY_END_ADDR          GENMASK(12, 8)
 #define   SWITCH_PHY_ST_ADDR           GENMASK(4, 0)
+#define SWITCH_GEPHY_CONN_CFG          0x7c14
+#define   SWITCH_DPHY_CKIN_SEL         BIT(31)
+#define   SWITCH_PHY_CORE_REG_CLK_SEL  BIT(30)
+#define   SWITCH_ETHER_AFE_PWD         GENMASK(28, 24)
+#define SWITCH_PBUS_PHY_IAC            0x7c20
+#define   SWITCH_PBUS_PHY_START                BIT(31)
+#define   SWITCH_PBUS_PHY_CMD          BIT(30)
+#define   SWITCH_PBUS_PHY_CMD_READ     FIELD_PREP(SWITCH_PBUS_PHY_CMD, 0x0)
+#define   SWITCH_PBUS_PHY_CMD_WRITE    FIELD_PREP(SWITCH_PBUS_PHY_CMD, 0x1)
+#define   SWITCH_PBUS_PHY_PORTADDR     GENMASK(28, 24)
+#define   SWITCH_PBUS_PHY_REGADDR      GENMASK(23, 0)
+#define SWITCH_PBUS_PHY_IAWD           0x7c24
+#define SWITCH_PBUS_PHY_IARD           0x7c28
 
 /* FE */
 #define PSE_BASE                       0x0100
@@ -365,6 +384,12 @@ static const char * const en7581_xsi_rsts_names[] = {
        "xfp-mac",
 };
 
+static const char * const an7583_xsi_rsts_names[] = {
+       "hsi0-mac",
+       "hsi1-mac",
+       "xfp-mac",
+};
+
 static u32 airoha_rr(void __iomem *base, u32 offset)
 {
        return readl(base + offset);
@@ -405,8 +430,12 @@ static u32 airoha_rmw(void __iomem *base, u32 offset, u32 
mask, u32 val)
 #define airoha_qdma_clear(qdma, offset, val)                   \
        airoha_rmw((qdma)->regs, (offset), (val), 0)
 
+#define airoha_switch_rr(eth, offset)                          \
+       airoha_rr((eth)->switch_regs, (offset))
 #define airoha_switch_wr(eth, offset, val)                     \
        airoha_wr((eth)->switch_regs, (offset), (val))
+#define airoha_switch_rmw(eth, offset, mask, val)              \
+       airoha_rmw((eth)->switch_regs, (offset), (mask), (val))
 
 static inline dma_addr_t dma_map_unaligned(void *vaddr, size_t len,
                                           enum dma_data_direction dir)
@@ -438,6 +467,8 @@ static int airoha_get_fe_port(struct airoha_gdm_port *port)
        case 0x7523:
                /* FIXME: GDM1 is the only supported port */
                return FE_PSE_PORT_GDM1;
+       case 0x7583:
+               return port->id == 3 ? FE_PSE_PORT_GDM3 : port->id;
        case 0x7581:
        default:
                return port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
@@ -809,6 +840,59 @@ static int airoha_switch_init(struct udevice *dev, struct 
airoha_eth *eth)
                         FIELD_PREP(SWITCH_PHY_END_ADDR, 0xc) |
                         FIELD_PREP(SWITCH_PHY_ST_ADDR, 0x8));
 
+       /* AN7583 require tweak to GEPHY_CONN_CFG and clear PHY BMCR_PDOWN */
+       if (!strcmp(data->switch_compatible, "airoha,an7583-switch")) {
+               int i;
+
+               airoha_switch_rmw(eth, SWITCH_GEPHY_CONN_CFG,
+                                 SWITCH_DPHY_CKIN_SEL |
+                                 SWITCH_PHY_CORE_REG_CLK_SEL |
+                                 SWITCH_ETHER_AFE_PWD,
+                                 SWITCH_DPHY_CKIN_SEL |
+                                 SWITCH_PHY_CORE_REG_CLK_SEL |
+                                 FIELD_PREP(SWITCH_ETHER_AFE_PWD, 0));
+
+               /* Disable BMCR_PDOWN for every PHY */
+               for (i = 0; i < AIROHA_MAX_NUM_SWITCH_PORT; i++) {
+                       int try;
+                       u32 val;
+
+                       airoha_switch_wr(eth, SWITCH_PBUS_PHY_IAC,
+                                        SWITCH_PBUS_PHY_START |
+                                        SWITCH_PBUS_PHY_CMD_READ |
+                                        FIELD_PREP(SWITCH_PBUS_PHY_PORTADDR, 
i) |
+                                        FIELD_PREP(SWITCH_PBUS_PHY_REGADDR,
+                                                   AIROHA_PBUS_C22_MASK | 
MII_BMCR));
+
+                       for (try = 0; try < AIROHA_MAX_PBUS_TRY; try++) {
+                               val = airoha_switch_rr(eth, 
SWITCH_PBUS_PHY_IAC);
+                               if (!(val & SWITCH_PBUS_PHY_START))
+                                       break;
+
+                               udelay(AIROHA_PBUS_SLEEP);
+                       }
+
+                       val = airoha_switch_rr(eth, SWITCH_PBUS_PHY_IARD);
+                       val &= ~BMCR_PDOWN;
+
+                       airoha_switch_wr(eth, SWITCH_PBUS_PHY_IAWD, val);
+                       airoha_switch_wr(eth, SWITCH_PBUS_PHY_IAC,
+                                        SWITCH_PBUS_PHY_START |
+                                        SWITCH_PBUS_PHY_CMD_WRITE |
+                                        FIELD_PREP(SWITCH_PBUS_PHY_PORTADDR, 
i) |
+                                        FIELD_PREP(SWITCH_PBUS_PHY_REGADDR,
+                                                   AIROHA_PBUS_C22_MASK | 
MII_BMCR));
+
+                       for (try = 0; try < AIROHA_MAX_PBUS_TRY; try++) {
+                               val = airoha_switch_rr(eth, 
SWITCH_PBUS_PHY_IAC);
+                               if (!(val & SWITCH_PBUS_PHY_START))
+                                       break;
+
+                               udelay(AIROHA_PBUS_SLEEP);
+                       }
+               }
+       }
+
        return 0;
 }
 
@@ -1269,6 +1353,13 @@ static const struct airoha_eth_soc_data en7581_data = {
        .switch_compatible = "airoha,en7581-switch",
 };
 
+static const struct airoha_eth_soc_data an7583_data = {
+       .version = 0x7583,
+       .xsi_rsts_names = an7583_xsi_rsts_names,
+       .num_xsi_rsts = ARRAY_SIZE(an7583_xsi_rsts_names),
+       .switch_compatible = "airoha,an7583-switch",
+};
+
 static const struct udevice_id airoha_eth_ids[] = {
        { .compatible = "airoha,en7523-eth",
          .data = (ulong)&en7523_data,
@@ -1276,6 +1367,9 @@ static const struct udevice_id airoha_eth_ids[] = {
        { .compatible = "airoha,en7581-eth",
          .data = (ulong)&en7581_data,
        },
+       { .compatible = "airoha,an7583-eth",
+         .data = (ulong)&an7583_data,
+       },
        { }
 };
 
-- 
2.53.0

Reply via email to