1 From 7288414298b34dcda1216fee1fe38d05ea0027a2 Mon Sep 17 00:00:00 2001
2 From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
3 Date: Mon, 17 Dec 2012 23:32:39 +0100
4 Subject: net: add driver for Lantiq XWAY ARX100 switch
6 Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
8 diff --git a/arch/mips/include/asm/arch-arx100/config.h b/arch/mips/include/asm/arch-arx100/config.h
9 index 1a6c9bc..8f955e8 100644
10 --- a/arch/mips/include/asm/arch-arx100/config.h
11 +++ b/arch/mips/include/asm/arch-arx100/config.h
13 * and drivers for this SoC:
15 * CONFIG_LTQ_SUPPORT_UART
16 - * - support the Danube ASC/UART interface and console
17 + * - support the ARX100 ASC/UART interface and console
19 * CONFIG_LTQ_SUPPORT_NOR_FLASH
20 * - support a parallel NOR flash via the CFI interface in flash bank 0
22 * CONFIG_LTQ_SUPPORT_ETHERNET
23 - * - support the Danube ETOP and MAC interface
24 + * - support the ARX100 ETOP and MAC interface
26 * CONFIG_LTQ_SUPPORT_SPI_FLASH
27 - * - support the Danube SPI interface and serial flash drivers
28 + * - support the ARX100 SPI interface and serial flash drivers
29 * - specific SPI flash drivers must be configured separately
31 + * CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH
32 + * - build a preloader that runs in the internal SRAM and loads
33 + * the U-Boot from SPI flash into RAM
36 #ifndef __ARX100_CONFIG_H__
37 diff --git a/arch/mips/include/asm/arch-arx100/switch.h b/arch/mips/include/asm/arch-arx100/switch.h
39 index 0000000..301056c
41 +++ b/arch/mips/include/asm/arch-arx100/switch.h
44 + * Copyright (C) 2012-2013 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
46 + * SPDX-License-Identifier: GPL-2.0+
49 +#ifndef __ARX100_SWITCH_H__
50 +#define __ARX100_SWITCH_H__
52 +struct ar9_switch_regs {
53 + __be32 ps; /* Port status*/
54 + __be32 p0_ctl; /* Port 0 control */
55 + __be32 p1_ctl; /* Port 1 control */
56 + __be32 p2_ctl; /* Port 2 control */
57 + __be32 p0_vlan; /* Port 0 VLAN control */
58 + __be32 p1_vlan; /* Port 1 VLAN control */
59 + __be32 p2_vlan; /* Port 2 VLAN control */
60 + __be32 p0_inctl; /* Port 0 ingress control */
61 + __be32 p1_inctl; /* Port 1 ingress control */
62 + __be32 p2_inctl; /* Port 2 ingress control */
64 + __be32 sw_gctl0; /* Switch global control 0 */
65 + __be32 sw_gctl1; /* Switch global control 1 */
66 + __be32 arp; /* ARP/RARP */
67 + __be32 strm_ctl; /* Storm control */
68 + __be32 rgmii_ctl; /* RGMII/GMII port control */
70 + __be32 pmac_hd_ctl; /* PMAC header control */
72 + __be32 mdio_ctrl; /* MDIO indirect access control */
73 + __be32 mdio_data; /* MDIO indirect read data */
76 +#define BUILD_CHECK_AR9_REG(name, offset) \
77 + BUILD_BUG_ON(offsetof(struct ar9_switch_regs, name) != (offset))
79 +static inline void build_check_ar9_registers(void)
81 + BUILD_CHECK_AR9_REG(sw_gctl0, 0x68);
82 + BUILD_CHECK_AR9_REG(rgmii_ctl, 0x78);
83 + BUILD_CHECK_AR9_REG(pmac_hd_ctl, 0x8c);
84 + BUILD_CHECK_AR9_REG(mdio_ctrl, 0xcc);
85 + BUILD_CHECK_AR9_REG(mdio_data, 0xd0);
88 +#define P0_CTL_FLP (1 << 18)
89 +#define P0_CTL_FLD (1 << 17)
91 +#define SW_GCTL0_SE (1 << 31)
93 +#define RGMII_CTL_P1_SHIFT 10
94 +#define RGMII_CTL_P1_MASK (0x3FF << RGMII_CTL_P1_SHIFT)
95 +#define RGMII_CTL_P0_MASK 0x3FF
96 +#define RGMII_CTL_P0IS_SHIFT 8
97 +#define RGMII_CTL_P0IS_RGMII (0x0 << RGMII_CTL_P0IS_SHIFT)
98 +#define RGMII_CTL_P0IS_MII (0x1 << RGMII_CTL_P0IS_SHIFT)
99 +#define RGMII_CTL_P0IS_REVMII (0x2 << RGMII_CTL_P0IS_SHIFT)
100 +#define RGMII_CTL_P0IS_RMII (0x3 << RGMII_CTL_P0IS_SHIFT)
101 +#define RGMII_CTL_P0RDLY_SHIFT 6
102 +#define RGMII_CTL_P0RDLY_0_0 (0x0 << RGMII_CTL_P0RDLY_SHIFT)
103 +#define RGMII_CTL_P0RDLY_1_5 (0x1 << RGMII_CTL_P0RDLY_SHIFT)
104 +#define RGMII_CTL_P0RDLY_1_75 (0x2 << RGMII_CTL_P0RDLY_SHIFT)
105 +#define RGMII_CTL_P0RDLY_2_0 (0x3 << RGMII_CTL_P0RDLY_SHIFT)
106 +#define RGMII_CTL_P0TDLY_SHIFT 4
107 +#define RGMII_CTL_P0TDLY_0_0 (0x0 << RGMII_CTL_P0TDLY_SHIFT)
108 +#define RGMII_CTL_P0TDLY_1_5 (0x1 << RGMII_CTL_P0TDLY_SHIFT)
109 +#define RGMII_CTL_P0TDLY_1_75 (0x2 << RGMII_CTL_P0TDLY_SHIFT)
110 +#define RGMII_CTL_P0TDLY_2_0 (0x3 << RGMII_CTL_P0TDLY_SHIFT)
111 +#define RGMII_CTL_P0SPD_SHIFT 2
112 +#define RGMII_CTL_P0SPD_10 (0x0 << RGMII_CTL_P0SPD_SHIFT)
113 +#define RGMII_CTL_P0SPD_100 (0x1 << RGMII_CTL_P0SPD_SHIFT)
114 +#define RGMII_CTL_P0SPD_1000 (0x2 << RGMII_CTL_P0SPD_SHIFT)
115 +#define RGMII_CTL_P0DUP_FULL (1 << 1)
116 +#define RGMII_CTL_P0FCE_EN (1 << 0)
118 +#define PMAC_HD_CTL_AC (1 << 18)
120 +#define MDIO_CTRL_WD_SHIFT 16
121 +#define MDIO_CTRL_MBUSY (1 << 15)
122 +#define MDIO_CTRL_OP_READ (1 << 11)
123 +#define MDIO_CTRL_OP_WRITE (1 << 10)
124 +#define MDIO_CTRL_PHYAD_SHIFT 5
125 +#define MDIO_CTRL_PHYAD_MASK (0x1f << MDIO_CTRL_PHYAD_SHIFT)
126 +#define MDIO_CTRL_REGAD_MASK 0x1f
128 +#endif /* __ARX100_SWITCH_H__ */
129 diff --git a/drivers/net/Makefile b/drivers/net/Makefile
130 index bbc2c92..926b8c2 100644
131 --- a/drivers/net/Makefile
132 +++ b/drivers/net/Makefile
133 @@ -38,6 +38,7 @@ COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
134 COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
135 COBJS-$(CONFIG_LAN91C96) += lan91c96.o
136 COBJS-$(CONFIG_LANTIQ_DANUBE_ETOP) += lantiq_danube_etop.o
137 +COBJS-$(CONFIG_LANTIQ_ARX100_SWITCH) += lantiq_arx100_switch.o
138 COBJS-$(CONFIG_LANTIQ_VRX200_SWITCH) += lantiq_vrx200_switch.o
139 COBJS-$(CONFIG_MACB) += macb.o
140 COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
141 diff --git a/drivers/net/lantiq_arx100_switch.c b/drivers/net/lantiq_arx100_switch.c
143 index 0000000..cc65249
145 +++ b/drivers/net/lantiq_arx100_switch.c
148 + * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
150 + * SPDX-License-Identifier: GPL-2.0+
158 +#include <linux/compiler.h>
159 +#include <asm/gpio.h>
160 +#include <asm/processor.h>
161 +#include <asm/lantiq/io.h>
162 +#include <asm/lantiq/eth.h>
163 +#include <asm/lantiq/pm.h>
164 +#include <asm/lantiq/reset.h>
165 +#include <asm/lantiq/dma.h>
166 +#include <asm/arch/soc.h>
167 +#include <asm/arch/switch.h>
169 +#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX
170 +#define LTQ_ETH_TX_BUFFER_CNT 8
171 +#define LTQ_ETH_RX_DATA_SIZE PKTSIZE_ALIGN
172 +#define LTQ_ETH_IP_ALIGN 2
174 +#define LTQ_MDIO_DRV_NAME "ltq-mdio"
175 +#define LTQ_ETH_DRV_NAME "ltq-eth"
177 +#define LTQ_ETHSW_MAX_GMAC 2
178 +#define LTQ_ETHSW_PMAC 2
180 +struct ltq_eth_priv {
181 + struct ltq_dma_device dma_dev;
182 + struct mii_dev *bus;
183 + struct eth_device *dev;
184 + struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC];
189 +static struct ar9_switch_regs *switch_regs =
190 + (struct ar9_switch_regs *) CKSEG1ADDR(LTQ_SWITCH_BASE);
192 +static int ltq_mdio_is_busy(void)
194 + u32 mdio_ctrl = ltq_readl(&switch_regs->mdio_ctrl);
196 + return mdio_ctrl & MDIO_CTRL_MBUSY;
199 +static void ltq_mdio_poll(void)
201 + while (ltq_mdio_is_busy())
207 +static int ltq_mdio_read(struct mii_dev *bus, int phyad, int devad,
213 + mdio_ctrl = MDIO_CTRL_MBUSY | MDIO_CTRL_OP_READ |
214 + ((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
215 + (regad & MDIO_CTRL_REGAD_MASK);
218 + ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
220 + retval = ltq_readl(&switch_regs->mdio_data);
221 + ltq_writel(&switch_regs->mdio_data, 0xFFFF);
223 + debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, retval);
228 +static int ltq_mdio_write(struct mii_dev *bus, int phyad, int devad,
229 + int regad, u16 val)
233 + debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, val);
235 + mdio_ctrl = (val << MDIO_CTRL_WD_SHIFT) | MDIO_CTRL_MBUSY |
236 + MDIO_CTRL_OP_WRITE |
237 + ((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
238 + (regad & MDIO_CTRL_REGAD_MASK);
241 + ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
246 +static void ltq_eth_gmac_update(struct phy_device *phydev, int num)
250 +static inline u8 *ltq_eth_rx_packet_align(int rx_num)
252 + u8 *packet = (u8 *) NetRxPackets[rx_num];
257 + return packet + LTQ_ETH_IP_ALIGN;
260 +static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
262 + struct ltq_eth_priv *priv = dev->priv;
263 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
264 + struct phy_device *phydev;
267 + for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
268 + phydev = priv->phymap[i];
272 + phy_startup(phydev);
273 + ltq_eth_gmac_update(phydev, i);
276 + for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
277 + ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
278 + LTQ_ETH_RX_DATA_SIZE);
280 + ltq_dma_enable(dma_dev);
288 +static void ltq_eth_halt(struct eth_device *dev)
290 + struct ltq_eth_priv *priv = dev->priv;
291 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
292 + struct phy_device *phydev;
295 + ltq_dma_reset(dma_dev);
297 + for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
298 + phydev = priv->phymap[i];
302 + phy_shutdown(phydev);
304 + ltq_eth_gmac_update(phydev, i);
308 +static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
310 + struct ltq_eth_priv *priv = dev->priv;
311 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
314 + err = ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
316 + puts("NET: timeout on waiting for TX descriptor\n");
320 + priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
325 +static int ltq_eth_recv(struct eth_device *dev)
327 + struct ltq_eth_priv *priv = dev->priv;
328 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
332 + if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
336 + printf("%s: rx_num %d\n", __func__, priv->rx_num);
339 + len = ltq_dma_rx_length(dma_dev, priv->rx_num);
340 + packet = ltq_eth_rx_packet_align(priv->rx_num);
343 + printf("%s: received: packet %p, len %u, rx_num %d\n",
344 + __func__, packet, len, priv->rx_num);
348 + NetReceive(packet, len);
350 + ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
351 + LTQ_ETH_RX_DATA_SIZE);
353 + priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
358 +static void ltq_eth_pmac_init(void)
360 + /* Add CRC to packets from DMA to PMAC */
361 + ltq_setbits(&switch_regs->pmac_hd_ctl, PMAC_HD_CTL_AC);
363 + /* Force link up */
364 + ltq_setbits(&switch_regs->p2_ctl, P0_CTL_FLP);
367 +static void ltq_eth_hw_init(const struct ltq_eth_port_config *port)
369 + /* Power up ethernet subsystems */
370 + ltq_pm_enable(LTQ_PM_ETH);
372 + /* Enable switch core */
373 + ltq_setbits(&switch_regs->sw_gctl0, SW_GCTL0_SE);
376 + gpio_set_altfunc(42, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
378 + gpio_set_altfunc(43, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
380 + ltq_eth_pmac_init();
383 +static void ltq_eth_port_config(struct ltq_eth_priv *priv,
384 + const struct ltq_eth_port_config *port)
386 + struct phy_device *phydev;
387 + struct switch_device *sw;
389 + unsigned int port_ctl, port_xmii = 0;
394 + rgmii_ctl = ltq_readl(&switch_regs->rgmii_ctl);
396 + if (port->num == 1)
397 + port_ctl = ltq_readl(&switch_regs->p1_ctl);
399 + port_ctl = ltq_readl(&switch_regs->p0_ctl);
401 + switch (port->phy_if) {
402 + case PHY_INTERFACE_MODE_RGMII:
403 + port_xmii = RGMII_CTL_P0IS_RGMII;
405 + switch (port->rgmii_tx_delay) {
407 + port_xmii |= RGMII_CTL_P0TDLY_1_5;
410 + port_xmii |= RGMII_CTL_P0TDLY_1_75;
413 + port_xmii |= RGMII_CTL_P0TDLY_2_0;
419 + switch (port->rgmii_rx_delay) {
421 + port_xmii |= RGMII_CTL_P0RDLY_1_5;
424 + port_xmii |= RGMII_CTL_P0RDLY_1_75;
427 + port_xmii |= RGMII_CTL_P0RDLY_2_0;
433 + if (!(port->flags & LTQ_ETH_PORT_PHY)) {
434 + port_xmii |= (RGMII_CTL_P0SPD_1000 |
435 + RGMII_CTL_P0DUP_FULL);
436 + port_ctl |= P0_CTL_FLP;
440 + case PHY_INTERFACE_MODE_MII:
441 + port_xmii = RGMII_CTL_P0IS_MII;
443 + if (!(port->flags & LTQ_ETH_PORT_PHY)) {
444 + port_xmii |= (RGMII_CTL_P0SPD_100 |
445 + RGMII_CTL_P0DUP_FULL);
446 + port_ctl |= P0_CTL_FLP;
454 + if (port->num == 1) {
455 + ltq_writel(&switch_regs->p1_ctl, port_ctl);
457 + rgmii_ctl &= ~RGMII_CTL_P1_MASK;
458 + rgmii_ctl |= (port_xmii << RGMII_CTL_P1_SHIFT);
460 + ltq_writel(&switch_regs->p0_ctl, port_ctl);
462 + rgmii_ctl &= ~RGMII_CTL_P0_MASK;
463 + rgmii_ctl |= port_xmii;
466 + ltq_writel(&switch_regs->rgmii_ctl, rgmii_ctl);
468 + /* Connect to external switch */
469 + if (port->flags & LTQ_ETH_PORT_SWITCH) {
470 + sw = switch_connect(priv->bus);
475 + /* Connect to internal/external PHYs */
476 + if (port->flags & LTQ_ETH_PORT_PHY) {
477 + phydev = phy_connect(priv->bus, port->phy_addr, priv->dev,
480 + phy_config(phydev);
482 + priv->phymap[port->num] = phydev;
486 +int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
488 + struct eth_device *dev;
489 + struct mii_dev *bus;
490 + struct ltq_eth_priv *priv;
491 + struct ltq_dma_device *dma_dev;
492 + const struct ltq_eth_port_config *port = &board_config->ports[0];
495 + build_check_ar9_registers();
498 + ltq_eth_hw_init(port);
500 + dev = calloc(1, sizeof(*dev));
504 + priv = calloc(1, sizeof(*priv));
508 + bus = mdio_alloc();
512 + sprintf(dev->name, LTQ_ETH_DRV_NAME);
514 + dev->init = ltq_eth_init;
515 + dev->halt = ltq_eth_halt;
516 + dev->recv = ltq_eth_recv;
517 + dev->send = ltq_eth_send;
519 + sprintf(bus->name, LTQ_MDIO_DRV_NAME);
520 + bus->read = ltq_mdio_read;
521 + bus->write = ltq_mdio_write;
524 + dma_dev = &priv->dma_dev;
526 + dma_dev->rx_chan.chan_no = 0;
527 + dma_dev->rx_chan.class = 0;
528 + dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
529 + dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
530 + dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
531 + dma_dev->tx_chan.chan_no = 1;
532 + dma_dev->tx_chan.class = 0;
533 + dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
534 + dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
535 + dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
540 + ret = ltq_dma_register(dma_dev);
544 + ret = mdio_register(bus);
548 + ret = eth_register(dev);
552 + for (i = 0; i < board_config->num_ports; i++)
553 + ltq_eth_port_config(priv, &board_config->ports[i]);