]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
NET: Lantiq: Make etop ethernet work on ASE / AR9
authorJohn Crispin <blogic@openwrt.org>
Tue, 17 Jan 2012 13:26:14 +0000 (14:26 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 26 Apr 2012 23:26:26 +0000 (00:26 +0100)
Extend the driver to handle the different DMA channel layout for AR9 and
Amazon-SE SoCs. The patch also adds support for the integrated PHY found
on Amazon-SE and the gigabit switch found inside the AR9.

Signed-off-by: John Crispin <blogic@openwrt.org>
Acked-by: David S. Miller <davem@davemloft.net>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3262/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
arch/mips/lantiq/xway/devices.c
arch/mips/lantiq/xway/mach-easy50601.c
drivers/net/ethernet/lantiq_etop.c

index b4465a888e20eecab1558e01d3cf1eb9cb997b0a..2a8d5adcad305d5eb2c094bff03842d842b83873 100644 (file)
 
 #define MIPS_CPU_TIMER_IRQ             7
 
-#define LTQ_DMA_CH0_INT                (INT_NUM_IM2_IRL0)
-#define LTQ_DMA_CH1_INT                (INT_NUM_IM2_IRL0 + 1)
-#define LTQ_DMA_CH2_INT                (INT_NUM_IM2_IRL0 + 2)
-#define LTQ_DMA_CH3_INT                (INT_NUM_IM2_IRL0 + 3)
-#define LTQ_DMA_CH4_INT                (INT_NUM_IM2_IRL0 + 4)
-#define LTQ_DMA_CH5_INT                (INT_NUM_IM2_IRL0 + 5)
-#define LTQ_DMA_CH6_INT                (INT_NUM_IM2_IRL0 + 6)
-#define LTQ_DMA_CH7_INT                (INT_NUM_IM2_IRL0 + 7)
-#define LTQ_DMA_CH8_INT                (INT_NUM_IM2_IRL0 + 8)
-#define LTQ_DMA_CH9_INT                (INT_NUM_IM2_IRL0 + 9)
-#define LTQ_DMA_CH10_INT       (INT_NUM_IM2_IRL0 + 10)
-#define LTQ_DMA_CH11_INT       (INT_NUM_IM2_IRL0 + 11)
-#define LTQ_DMA_CH12_INT       (INT_NUM_IM2_IRL0 + 25)
-#define LTQ_DMA_CH13_INT       (INT_NUM_IM2_IRL0 + 26)
-#define LTQ_DMA_CH14_INT       (INT_NUM_IM2_IRL0 + 27)
-#define LTQ_DMA_CH15_INT       (INT_NUM_IM2_IRL0 + 28)
-#define LTQ_DMA_CH16_INT       (INT_NUM_IM2_IRL0 + 29)
-#define LTQ_DMA_CH17_INT       (INT_NUM_IM2_IRL0 + 30)
-#define LTQ_DMA_CH18_INT       (INT_NUM_IM2_IRL0 + 16)
-#define LTQ_DMA_CH19_INT       (INT_NUM_IM2_IRL0 + 21)
+#define LTQ_DMA_ETOP           ((ltq_is_ase()) ? \
+                               (INT_NUM_IM3_IRL0) : (INT_NUM_IM2_IRL0))
 
 #define LTQ_PPE_MBOX_INT       (INT_NUM_IM2_IRL0 + 24)
 
index 59a6b4dfd47c5c7085357376f354b556ffc4869d..9d0afebc567119029baa637b12ed39ef07808e0f 100644 (file)
@@ -82,6 +82,7 @@
 #define LTQ_PMU_SIZE           0x1000
 
 #define PMU_DMA                        0x0020
+#define PMU_EPHY               0x0080
 #define PMU_USB                        0x8041
 #define PMU_LED                        0x0800
 #define PMU_GPT                        0x1000
 #define LTQ_ETOP_BASE_ADDR     0x1E180000
 #define LTQ_ETOP_SIZE          0x40000
 
+/* GBIT - gigabit switch */
+#define LTQ_GBIT_BASE_ADDR     0x1E108000
+#define LTQ_GBIT_SIZE          0x200
+
 /* DMA */
 #define LTQ_DMA_BASE_ADDR      0x1E104100
 #define LTQ_DMA_SIZE           0x800
@@ -169,6 +174,11 @@ extern void ltq_pmu_enable(unsigned int module);
 extern void ltq_pmu_disable(unsigned int module);
 extern void ltq_cgu_enable(unsigned int clk);
 
+static inline int ltq_is_ase(void)
+{
+       return (ltq_get_soc_type() == SOC_TYPE_AMAZON_SE);
+}
+
 static inline int ltq_is_ar9(void)
 {
        return (ltq_get_soc_type() == SOC_TYPE_AR9);
index f97e565a23f03384194240fef2fb4146c347aa59..eab4644d09ac79c246910df57673ab3b3113055f 100644 (file)
@@ -74,18 +74,23 @@ void __init ltq_register_ase_asc(void)
 }
 
 /* ethernet */
-static struct resource ltq_etop_resources =
-       MEM_RES("etop", LTQ_ETOP_BASE_ADDR, LTQ_ETOP_SIZE);
+static struct resource ltq_etop_resources[] = {
+       MEM_RES("etop", LTQ_ETOP_BASE_ADDR, LTQ_ETOP_SIZE),
+       MEM_RES("gbit", LTQ_GBIT_BASE_ADDR, LTQ_GBIT_SIZE),
+};
 
 static struct platform_device ltq_etop = {
        .name           = "ltq_etop",
-       .resource       = &ltq_etop_resources,
+       .resource       = ltq_etop_resources,
        .num_resources  = 1,
 };
 
 void __init
 ltq_register_etop(struct ltq_eth_data *eth)
 {
+       /* only register the gphy on socs that have one */
+       if (ltq_is_ar9() | ltq_is_vr9())
+               ltq_etop.num_resources = 2;
        if (eth) {
                ltq_etop.dev.platform_data = eth;
                platform_device_register(&ltq_etop);
index d5aaf637ab1918f9b41a78783c36a7c842a750d7..16d65e04a7844c9d4ac6591038409fe20d311f95 100644 (file)
@@ -46,9 +46,14 @@ static struct physmap_flash_data easy50601_flash_data = {
        .parts          = easy50601_partitions,
 };
 
+static struct ltq_eth_data ltq_eth_data = {
+       .mii_mode = -1, /* use EPHY */
+};
+
 static void __init easy50601_init(void)
 {
        ltq_register_nor(&easy50601_flash_data);
+       ltq_register_etop(&ltq_eth_data);
 }
 
 MIPS_MACHINE(LTQ_MACH_EASY50601,
index 5dc9cbd5151417737c1779df53f102045da92595..874e70a74d88bc236a82e9bc9821f64c47aecb42 100644 (file)
 #define ETOP_MII_REVERSE       0xe
 #define ETOP_PLEN_UNDER                0x40
 #define ETOP_CGEN              0x800
-
-/* use 2 static channels for TX/RX */
+#define ETOP_CFG_MII0          0x01
+
+#define LTQ_GBIT_MDIO_CTL      0xCC
+#define LTQ_GBIT_MDIO_DATA     0xd0
+#define LTQ_GBIT_GCTL0         0x68
+#define LTQ_GBIT_PMAC_HD_CTL   0x8c
+#define LTQ_GBIT_P0_CTL                0x4
+#define LTQ_GBIT_PMAC_RX_IPG   0xa8
+
+#define PMAC_HD_CTL_AS         (1 << 19)
+#define PMAC_HD_CTL_RXSH       (1 << 22)
+
+/* Switch Enable (0=disable, 1=enable) */
+#define GCTL0_SE               0x80000000
+/* Disable MDIO auto polling (0=disable, 1=enable) */
+#define PX_CTL_DMDIO           0x00400000
+
+/* register information for the gbit's MDIO bus */
+#define MDIO_XR9_REQUEST       0x00008000
+#define MDIO_XR9_READ          0x00000800
+#define MDIO_XR9_WRITE         0x00000400
+#define MDIO_XR9_REG_MASK      0x1f
+#define MDIO_XR9_ADDR_MASK     0x1f
+#define MDIO_XR9_RD_MASK       0xffff
+#define MDIO_XR9_REG_OFFSET    0
+#define MDIO_XR9_ADDR_OFFSET   5
+#define MDIO_XR9_WR_OFFSET     16
+
+/* the newer xway socks have a embedded 3/7 port gbit multiplexer */
+#define ltq_has_gbit()         (ltq_is_ar9() || ltq_is_vr9())
+
+/* use 2 static channels for TX/RX
+   depending on the SoC we need to use different DMA channels for ethernet */
 #define LTQ_ETOP_TX_CHANNEL    1
-#define LTQ_ETOP_RX_CHANNEL    6
+#define LTQ_ETOP_RX_CHANNEL    ((ltq_is_ase()) ? (5) : \
+                               ((ltq_has_gbit()) ? (0) : (6)))
+
 #define IS_TX(x)               (x == LTQ_ETOP_TX_CHANNEL)
 #define IS_RX(x)               (x == LTQ_ETOP_RX_CHANNEL)
 
 #define ltq_etop_w32_mask(x, y, z)     \
                ltq_w32_mask(x, y, ltq_etop_membase + (z))
 
+#define ltq_gbit_r32(x)                ltq_r32(ltq_gbit_membase + (x))
+#define ltq_gbit_w32(x, y)     ltq_w32(x, ltq_gbit_membase + (y))
+#define ltq_gbit_w32_mask(x, y, z)     \
+               ltq_w32_mask(x, y, ltq_gbit_membase + (z))
+
 #define DRV_VERSION    "1.0"
 
 static void __iomem *ltq_etop_membase;
+static void __iomem *ltq_gbit_membase;
 
 struct ltq_etop_chan {
        int idx;
@@ -111,6 +150,9 @@ struct ltq_etop_priv {
        spinlock_t lock;
 };
 
+static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr,
+                               int phy_reg, u16 phy_data);
+
 static int
 ltq_etop_alloc_skb(struct ltq_etop_chan *ch)
 {
@@ -212,7 +254,7 @@ static irqreturn_t
 ltq_etop_dma_irq(int irq, void *_priv)
 {
        struct ltq_etop_priv *priv = _priv;
-       int ch = irq - LTQ_DMA_CH0_INT;
+       int ch = irq - LTQ_DMA_ETOP;
 
        napi_schedule(&priv->ch[ch].napi);
        return IRQ_HANDLED;
@@ -245,15 +287,43 @@ ltq_etop_hw_exit(struct net_device *dev)
                        ltq_etop_free_channel(dev, &priv->ch[i]);
 }
 
+static void
+ltq_etop_gbit_init(void)
+{
+       ltq_pmu_enable(PMU_SWITCH);
+
+       ltq_gpio_request(42, 2, 1, "MDIO");
+       ltq_gpio_request(43, 2, 1, "MDC");
+
+       ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0);
+       /** Disable MDIO auto polling mode */
+       ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL);
+       /* set 1522 packet size */
+       ltq_gbit_w32_mask(0x300, 0, LTQ_GBIT_GCTL0);
+       /* disable pmac & dmac headers */
+       ltq_gbit_w32_mask(PMAC_HD_CTL_AS | PMAC_HD_CTL_RXSH, 0,
+               LTQ_GBIT_PMAC_HD_CTL);
+       /* Due to traffic halt when burst length 8,
+               replace default IPG value with 0x3B */
+       ltq_gbit_w32(0x3B, LTQ_GBIT_PMAC_RX_IPG);
+}
+
 static int
 ltq_etop_hw_init(struct net_device *dev)
 {
        struct ltq_etop_priv *priv = netdev_priv(dev);
+       unsigned int mii_mode = priv->pldata->mii_mode;
        int i;
 
        ltq_pmu_enable(PMU_PPE);
 
-       switch (priv->pldata->mii_mode) {
+       if (ltq_has_gbit()) {
+               ltq_etop_gbit_init();
+               /* force the etops link to the gbit to MII */
+               mii_mode = PHY_INTERFACE_MODE_MII;
+       }
+
+       switch (mii_mode) {
        case PHY_INTERFACE_MODE_RMII:
                ltq_etop_w32_mask(ETOP_MII_MASK,
                        ETOP_MII_REVERSE, LTQ_ETOP_CFG);
@@ -265,6 +335,18 @@ ltq_etop_hw_init(struct net_device *dev)
                break;
 
        default:
+               if (ltq_is_ase()) {
+                       ltq_pmu_enable(PMU_EPHY);
+                       /* disable external MII */
+                       ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG);
+                       /* enable clock for internal PHY */
+                       ltq_cgu_enable(CGU_EPHY);
+                       /* we need to write this magic to the internal phy to
+                          make it work */
+                       ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020);
+                       pr_info("Selected EPHY mode\n");
+                       break;
+               }
                netdev_err(dev, "unknown mii mode %d\n",
                        priv->pldata->mii_mode);
                return -ENOTSUPP;
@@ -276,7 +358,7 @@ ltq_etop_hw_init(struct net_device *dev)
        ltq_dma_init_port(DMA_PORT_ETOP);
 
        for (i = 0; i < MAX_DMA_CHAN; i++) {
-               int irq = LTQ_DMA_CH0_INT + i;
+               int irq = LTQ_DMA_ETOP + i;
                struct ltq_etop_chan *ch = &priv->ch[i];
 
                ch->idx = ch->dma.nr = i;
@@ -339,6 +421,39 @@ static const struct ethtool_ops ltq_etop_ethtool_ops = {
        .nway_reset = ltq_etop_nway_reset,
 };
 
+static int
+ltq_etop_mdio_wr_xr9(struct mii_bus *bus, int phy_addr,
+               int phy_reg, u16 phy_data)
+{
+       u32 val = MDIO_XR9_REQUEST | MDIO_XR9_WRITE |
+               (phy_data << MDIO_XR9_WR_OFFSET) |
+               ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) |
+               ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET);
+
+       while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+               ;
+       ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL);
+       while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+               ;
+       return 0;
+}
+
+static int
+ltq_etop_mdio_rd_xr9(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+       u32 val = MDIO_XR9_REQUEST | MDIO_XR9_READ |
+               ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) |
+               ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET);
+
+       while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+               ;
+       ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL);
+       while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+               ;
+       val = ltq_gbit_r32(LTQ_GBIT_MDIO_DATA) & MDIO_XR9_RD_MASK;
+       return val;
+}
+
 static int
 ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data)
 {
@@ -380,14 +495,11 @@ ltq_etop_mdio_probe(struct net_device *dev)
 {
        struct ltq_etop_priv *priv = netdev_priv(dev);
        struct phy_device *phydev = NULL;
-       int phy_addr;
 
-       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-               if (priv->mii_bus->phy_map[phy_addr]) {
-                       phydev = priv->mii_bus->phy_map[phy_addr];
-                       break;
-               }
-       }
+       if (ltq_is_ase())
+               phydev = priv->mii_bus->phy_map[8];
+       else
+               phydev = priv->mii_bus->phy_map[0];
 
        if (!phydev) {
                netdev_err(dev, "no PHY found\n");
@@ -409,6 +521,9 @@ ltq_etop_mdio_probe(struct net_device *dev)
                              | SUPPORTED_Autoneg
                              | SUPPORTED_MII
                              | SUPPORTED_TP);
+       if (ltq_has_gbit())
+               phydev->supported &= SUPPORTED_1000baseT_Half
+                                       | SUPPORTED_1000baseT_Full;
 
        phydev->advertising = phydev->supported;
        priv->phydev = phydev;
@@ -434,8 +549,13 @@ ltq_etop_mdio_init(struct net_device *dev)
        }
 
        priv->mii_bus->priv = dev;
-       priv->mii_bus->read = ltq_etop_mdio_rd;
-       priv->mii_bus->write = ltq_etop_mdio_wr;
+       if (ltq_has_gbit()) {
+               priv->mii_bus->read = ltq_etop_mdio_rd_xr9;
+               priv->mii_bus->write = ltq_etop_mdio_wr_xr9;
+       } else {
+               priv->mii_bus->read = ltq_etop_mdio_rd;
+               priv->mii_bus->write = ltq_etop_mdio_wr;
+       }
        priv->mii_bus->name = "ltq_mii";
        snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                priv->pdev->name, priv->pdev->id);
@@ -526,9 +646,9 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
        struct ltq_etop_priv *priv = netdev_priv(dev);
        struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1];
        struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
-       int len;
        unsigned long flags;
        u32 byte_offset;
+       int len;
 
        len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
 
@@ -709,7 +829,7 @@ ltq_etop_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
        struct ltq_etop_priv *priv;
-       struct resource *res;
+       struct resource *res, *gbit_res;
        int err;
        int i;
 
@@ -737,6 +857,23 @@ ltq_etop_probe(struct platform_device *pdev)
                goto err_out;
        }
 
+       if (ltq_has_gbit()) {
+               gbit_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               if (!gbit_res) {
+                       dev_err(&pdev->dev, "failed to get gbit resource\n");
+                       err = -ENOENT;
+                       goto err_out;
+               }
+               ltq_gbit_membase = devm_ioremap_nocache(&pdev->dev,
+                       gbit_res->start, resource_size(gbit_res));
+               if (!ltq_gbit_membase) {
+                       dev_err(&pdev->dev, "failed to remap gigabit switch %d\n",
+                               pdev->id);
+                       err = -ENOMEM;
+                       goto err_out;
+               }
+       }
+
        dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
        if (!dev) {
                err = -ENOMEM;