rpcd: iwinfo plugin fixes
[openwrt/svn-archive/archive.git] / package / boot / uboot-lantiq / patches / 0016-net-add-driver-for-Lantiq-XWAY-ARX100-switch.patch
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
5
6 Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
7
8 --- a/arch/mips/include/asm/arch-arx100/config.h
9 +++ b/arch/mips/include/asm/arch-arx100/config.h
10 @@ -10,17 +10,21 @@
11 * and drivers for this SoC:
12 *
13 * CONFIG_LTQ_SUPPORT_UART
14 - * - support the Danube ASC/UART interface and console
15 + * - support the ARX100 ASC/UART interface and console
16 *
17 * CONFIG_LTQ_SUPPORT_NOR_FLASH
18 * - support a parallel NOR flash via the CFI interface in flash bank 0
19 *
20 * CONFIG_LTQ_SUPPORT_ETHERNET
21 - * - support the Danube ETOP and MAC interface
22 + * - support the ARX100 ETOP and MAC interface
23 *
24 * CONFIG_LTQ_SUPPORT_SPI_FLASH
25 - * - support the Danube SPI interface and serial flash drivers
26 + * - support the ARX100 SPI interface and serial flash drivers
27 * - specific SPI flash drivers must be configured separately
28 + *
29 + * CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH
30 + * - build a preloader that runs in the internal SRAM and loads
31 + * the U-Boot from SPI flash into RAM
32 */
33
34 #ifndef __ARX100_CONFIG_H__
35 --- /dev/null
36 +++ b/arch/mips/include/asm/arch-arx100/switch.h
37 @@ -0,0 +1,86 @@
38 +/*
39 + * Copyright (C) 2012-2013 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
40 + *
41 + * SPDX-License-Identifier: GPL-2.0+
42 + */
43 +
44 +#ifndef __ARX100_SWITCH_H__
45 +#define __ARX100_SWITCH_H__
46 +
47 +struct ar9_switch_regs {
48 + __be32 ps; /* Port status*/
49 + __be32 p0_ctl; /* Port 0 control */
50 + __be32 p1_ctl; /* Port 1 control */
51 + __be32 p2_ctl; /* Port 2 control */
52 + __be32 p0_vlan; /* Port 0 VLAN control */
53 + __be32 p1_vlan; /* Port 1 VLAN control */
54 + __be32 p2_vlan; /* Port 2 VLAN control */
55 + __be32 p0_inctl; /* Port 0 ingress control */
56 + __be32 p1_inctl; /* Port 1 ingress control */
57 + __be32 p2_inctl; /* Port 2 ingress control */
58 + u32 rsvd0[16];
59 + __be32 sw_gctl0; /* Switch global control 0 */
60 + __be32 sw_gctl1; /* Switch global control 1 */
61 + __be32 arp; /* ARP/RARP */
62 + __be32 strm_ctl; /* Storm control */
63 + __be32 rgmii_ctl; /* RGMII/GMII port control */
64 + u32 rsvd1[4];
65 + __be32 pmac_hd_ctl; /* PMAC header control */
66 + u32 rsvd2[15];
67 + __be32 mdio_ctrl; /* MDIO indirect access control */
68 + __be32 mdio_data; /* MDIO indirect read data */
69 +};
70 +
71 +#define BUILD_CHECK_AR9_REG(name, offset) \
72 + BUILD_BUG_ON(offsetof(struct ar9_switch_regs, name) != (offset))
73 +
74 +static inline void build_check_ar9_registers(void)
75 +{
76 + BUILD_CHECK_AR9_REG(sw_gctl0, 0x68);
77 + BUILD_CHECK_AR9_REG(rgmii_ctl, 0x78);
78 + BUILD_CHECK_AR9_REG(pmac_hd_ctl, 0x8c);
79 + BUILD_CHECK_AR9_REG(mdio_ctrl, 0xcc);
80 + BUILD_CHECK_AR9_REG(mdio_data, 0xd0);
81 +}
82 +
83 +#define P0_CTL_FLP (1 << 18)
84 +#define P0_CTL_FLD (1 << 17)
85 +
86 +#define SW_GCTL0_SE (1 << 31)
87 +
88 +#define RGMII_CTL_P1_SHIFT 10
89 +#define RGMII_CTL_P1_MASK (0x3FF << RGMII_CTL_P1_SHIFT)
90 +#define RGMII_CTL_P0_MASK 0x3FF
91 +#define RGMII_CTL_P0IS_SHIFT 8
92 +#define RGMII_CTL_P0IS_RGMII (0x0 << RGMII_CTL_P0IS_SHIFT)
93 +#define RGMII_CTL_P0IS_MII (0x1 << RGMII_CTL_P0IS_SHIFT)
94 +#define RGMII_CTL_P0IS_REVMII (0x2 << RGMII_CTL_P0IS_SHIFT)
95 +#define RGMII_CTL_P0IS_RMII (0x3 << RGMII_CTL_P0IS_SHIFT)
96 +#define RGMII_CTL_P0RDLY_SHIFT 6
97 +#define RGMII_CTL_P0RDLY_0_0 (0x0 << RGMII_CTL_P0RDLY_SHIFT)
98 +#define RGMII_CTL_P0RDLY_1_5 (0x1 << RGMII_CTL_P0RDLY_SHIFT)
99 +#define RGMII_CTL_P0RDLY_1_75 (0x2 << RGMII_CTL_P0RDLY_SHIFT)
100 +#define RGMII_CTL_P0RDLY_2_0 (0x3 << RGMII_CTL_P0RDLY_SHIFT)
101 +#define RGMII_CTL_P0TDLY_SHIFT 4
102 +#define RGMII_CTL_P0TDLY_0_0 (0x0 << RGMII_CTL_P0TDLY_SHIFT)
103 +#define RGMII_CTL_P0TDLY_1_5 (0x1 << RGMII_CTL_P0TDLY_SHIFT)
104 +#define RGMII_CTL_P0TDLY_1_75 (0x2 << RGMII_CTL_P0TDLY_SHIFT)
105 +#define RGMII_CTL_P0TDLY_2_0 (0x3 << RGMII_CTL_P0TDLY_SHIFT)
106 +#define RGMII_CTL_P0SPD_SHIFT 2
107 +#define RGMII_CTL_P0SPD_10 (0x0 << RGMII_CTL_P0SPD_SHIFT)
108 +#define RGMII_CTL_P0SPD_100 (0x1 << RGMII_CTL_P0SPD_SHIFT)
109 +#define RGMII_CTL_P0SPD_1000 (0x2 << RGMII_CTL_P0SPD_SHIFT)
110 +#define RGMII_CTL_P0DUP_FULL (1 << 1)
111 +#define RGMII_CTL_P0FCE_EN (1 << 0)
112 +
113 +#define PMAC_HD_CTL_AC (1 << 18)
114 +
115 +#define MDIO_CTRL_WD_SHIFT 16
116 +#define MDIO_CTRL_MBUSY (1 << 15)
117 +#define MDIO_CTRL_OP_READ (1 << 11)
118 +#define MDIO_CTRL_OP_WRITE (1 << 10)
119 +#define MDIO_CTRL_PHYAD_SHIFT 5
120 +#define MDIO_CTRL_PHYAD_MASK (0x1f << MDIO_CTRL_PHYAD_SHIFT)
121 +#define MDIO_CTRL_REGAD_MASK 0x1f
122 +
123 +#endif /* __ARX100_SWITCH_H__ */
124 --- a/drivers/net/Makefile
125 +++ b/drivers/net/Makefile
126 @@ -38,6 +38,7 @@ COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks86
127 COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
128 COBJS-$(CONFIG_LAN91C96) += lan91c96.o
129 COBJS-$(CONFIG_LANTIQ_DANUBE_ETOP) += lantiq_danube_etop.o
130 +COBJS-$(CONFIG_LANTIQ_ARX100_SWITCH) += lantiq_arx100_switch.o
131 COBJS-$(CONFIG_LANTIQ_VRX200_SWITCH) += lantiq_vrx200_switch.o
132 COBJS-$(CONFIG_MACB) += macb.o
133 COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
134 --- /dev/null
135 +++ b/drivers/net/lantiq_arx100_switch.c
136 @@ -0,0 +1,410 @@
137 +/*
138 + * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
139 + *
140 + * SPDX-License-Identifier: GPL-2.0+
141 + */
142 +#define DEBUG
143 +#include <common.h>
144 +#include <malloc.h>
145 +#include <netdev.h>
146 +#include <miiphy.h>
147 +#include <switch.h>
148 +#include <linux/compiler.h>
149 +#include <asm/gpio.h>
150 +#include <asm/processor.h>
151 +#include <asm/lantiq/io.h>
152 +#include <asm/lantiq/eth.h>
153 +#include <asm/lantiq/pm.h>
154 +#include <asm/lantiq/reset.h>
155 +#include <asm/lantiq/dma.h>
156 +#include <asm/arch/soc.h>
157 +#include <asm/arch/switch.h>
158 +
159 +#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX
160 +#define LTQ_ETH_TX_BUFFER_CNT 8
161 +#define LTQ_ETH_RX_DATA_SIZE PKTSIZE_ALIGN
162 +#define LTQ_ETH_IP_ALIGN 2
163 +
164 +#define LTQ_MDIO_DRV_NAME "ltq-mdio"
165 +#define LTQ_ETH_DRV_NAME "ltq-eth"
166 +
167 +#define LTQ_ETHSW_MAX_GMAC 2
168 +#define LTQ_ETHSW_PMAC 2
169 +
170 +struct ltq_eth_priv {
171 + struct ltq_dma_device dma_dev;
172 + struct mii_dev *bus;
173 + struct eth_device *dev;
174 + struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC];
175 + int rx_num;
176 + int tx_num;
177 +};
178 +
179 +static struct ar9_switch_regs *switch_regs =
180 + (struct ar9_switch_regs *) CKSEG1ADDR(LTQ_SWITCH_BASE);
181 +
182 +static int ltq_mdio_is_busy(void)
183 +{
184 + u32 mdio_ctrl = ltq_readl(&switch_regs->mdio_ctrl);
185 +
186 + return mdio_ctrl & MDIO_CTRL_MBUSY;
187 +}
188 +
189 +static void ltq_mdio_poll(void)
190 +{
191 + while (ltq_mdio_is_busy())
192 + cpu_relax();
193 +
194 + __udelay(1000);
195 +}
196 +
197 +static int ltq_mdio_read(struct mii_dev *bus, int phyad, int devad,
198 + int regad)
199 +{
200 + u32 mdio_ctrl;
201 + int retval;
202 +
203 + mdio_ctrl = MDIO_CTRL_MBUSY | MDIO_CTRL_OP_READ |
204 + ((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
205 + (regad & MDIO_CTRL_REGAD_MASK);
206 +
207 + ltq_mdio_poll();
208 + ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
209 + ltq_mdio_poll();
210 + retval = ltq_readl(&switch_regs->mdio_data);
211 + ltq_writel(&switch_regs->mdio_data, 0xFFFF);
212 +
213 + debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, retval);
214 +
215 + return retval;
216 +}
217 +
218 +static int ltq_mdio_write(struct mii_dev *bus, int phyad, int devad,
219 + int regad, u16 val)
220 +{
221 + u32 mdio_ctrl;
222 +
223 + debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, val);
224 +
225 + mdio_ctrl = (val << MDIO_CTRL_WD_SHIFT) | MDIO_CTRL_MBUSY |
226 + MDIO_CTRL_OP_WRITE |
227 + ((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
228 + (regad & MDIO_CTRL_REGAD_MASK);
229 +
230 + ltq_mdio_poll();
231 + ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
232 +
233 + return 0;
234 +}
235 +
236 +static void ltq_eth_gmac_update(struct phy_device *phydev, int num)
237 +{
238 +}
239 +
240 +static inline u8 *ltq_eth_rx_packet_align(int rx_num)
241 +{
242 + u8 *packet = (u8 *) NetRxPackets[rx_num];
243 +
244 + /*
245 + * IP header needs
246 + */
247 + return packet + LTQ_ETH_IP_ALIGN;
248 +}
249 +
250 +static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
251 +{
252 + struct ltq_eth_priv *priv = dev->priv;
253 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
254 + struct phy_device *phydev;
255 + int i;
256 +
257 + for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
258 + phydev = priv->phymap[i];
259 + if (!phydev)
260 + continue;
261 +
262 + phy_startup(phydev);
263 + ltq_eth_gmac_update(phydev, i);
264 + }
265 +
266 + for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
267 + ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
268 + LTQ_ETH_RX_DATA_SIZE);
269 +
270 + ltq_dma_enable(dma_dev);
271 +
272 + priv->rx_num = 0;
273 + priv->tx_num = 0;
274 +
275 + return 0;
276 +}
277 +
278 +static void ltq_eth_halt(struct eth_device *dev)
279 +{
280 + struct ltq_eth_priv *priv = dev->priv;
281 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
282 + struct phy_device *phydev;
283 + int i;
284 +
285 + ltq_dma_reset(dma_dev);
286 +
287 + for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
288 + phydev = priv->phymap[i];
289 + if (!phydev)
290 + continue;
291 +
292 + phy_shutdown(phydev);
293 + phydev->link = 0;
294 + ltq_eth_gmac_update(phydev, i);
295 + }
296 +}
297 +
298 +static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
299 +{
300 + struct ltq_eth_priv *priv = dev->priv;
301 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
302 + int err;
303 +
304 + err = ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
305 + if (err) {
306 + puts("NET: timeout on waiting for TX descriptor\n");
307 + return -1;
308 + }
309 +
310 + priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
311 +
312 + return err;
313 +}
314 +
315 +static int ltq_eth_recv(struct eth_device *dev)
316 +{
317 + struct ltq_eth_priv *priv = dev->priv;
318 + struct ltq_dma_device *dma_dev = &priv->dma_dev;
319 + u8 *packet;
320 + int len;
321 +
322 + if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
323 + return 0;
324 +
325 +#if 0
326 + printf("%s: rx_num %d\n", __func__, priv->rx_num);
327 +#endif
328 +
329 + len = ltq_dma_rx_length(dma_dev, priv->rx_num);
330 + packet = ltq_eth_rx_packet_align(priv->rx_num);
331 +
332 +#if 0
333 + printf("%s: received: packet %p, len %u, rx_num %d\n",
334 + __func__, packet, len, priv->rx_num);
335 +#endif
336 +
337 + if (len)
338 + NetReceive(packet, len);
339 +
340 + ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
341 + LTQ_ETH_RX_DATA_SIZE);
342 +
343 + priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
344 +
345 + return 0;
346 +}
347 +
348 +static void ltq_eth_pmac_init(void)
349 +{
350 + /* Add CRC to packets from DMA to PMAC */
351 + ltq_setbits(&switch_regs->pmac_hd_ctl, PMAC_HD_CTL_AC);
352 +
353 + /* Force link up */
354 + ltq_setbits(&switch_regs->p2_ctl, P0_CTL_FLP);
355 +}
356 +
357 +static void ltq_eth_hw_init(const struct ltq_eth_port_config *port)
358 +{
359 + /* Power up ethernet subsystems */
360 + ltq_pm_enable(LTQ_PM_ETH);
361 +
362 + /* Enable switch core */
363 + ltq_setbits(&switch_regs->sw_gctl0, SW_GCTL0_SE);
364 +
365 + /* MII/MDIO */
366 + gpio_set_altfunc(42, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
367 + /* MII/MDC */
368 + gpio_set_altfunc(43, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
369 +
370 + ltq_eth_pmac_init();
371 +}
372 +
373 +static void ltq_eth_port_config(struct ltq_eth_priv *priv,
374 + const struct ltq_eth_port_config *port)
375 +{
376 + struct phy_device *phydev;
377 + struct switch_device *sw;
378 + u32 rgmii_ctl;
379 + unsigned int port_ctl, port_xmii = 0;
380 +
381 + if (port->num > 1)
382 + return;
383 +
384 + rgmii_ctl = ltq_readl(&switch_regs->rgmii_ctl);
385 +
386 + if (port->num == 1)
387 + port_ctl = ltq_readl(&switch_regs->p1_ctl);
388 + else
389 + port_ctl = ltq_readl(&switch_regs->p0_ctl);
390 +
391 + switch (port->phy_if) {
392 + case PHY_INTERFACE_MODE_RGMII:
393 + port_xmii = RGMII_CTL_P0IS_RGMII;
394 +
395 + switch (port->rgmii_tx_delay) {
396 + case 1:
397 + port_xmii |= RGMII_CTL_P0TDLY_1_5;
398 + break;
399 + case 2:
400 + port_xmii |= RGMII_CTL_P0TDLY_1_75;
401 + break;
402 + case 3:
403 + port_xmii |= RGMII_CTL_P0TDLY_2_0;
404 + break;
405 + default:
406 + break;
407 + }
408 +
409 + switch (port->rgmii_rx_delay) {
410 + case 1:
411 + port_xmii |= RGMII_CTL_P0RDLY_1_5;
412 + break;
413 + case 2:
414 + port_xmii |= RGMII_CTL_P0RDLY_1_75;
415 + break;
416 + case 3:
417 + port_xmii |= RGMII_CTL_P0RDLY_2_0;
418 + break;
419 + default:
420 + break;
421 + }
422 +
423 + if (!(port->flags & LTQ_ETH_PORT_PHY)) {
424 + port_xmii |= (RGMII_CTL_P0SPD_1000 |
425 + RGMII_CTL_P0DUP_FULL);
426 + port_ctl |= P0_CTL_FLP;
427 + }
428 +
429 + break;
430 + case PHY_INTERFACE_MODE_MII:
431 + port_xmii = RGMII_CTL_P0IS_MII;
432 +
433 + if (!(port->flags & LTQ_ETH_PORT_PHY)) {
434 + port_xmii |= (RGMII_CTL_P0SPD_100 |
435 + RGMII_CTL_P0DUP_FULL);
436 + port_ctl |= P0_CTL_FLP;
437 + }
438 +
439 + break;
440 + default:
441 + break;
442 + }
443 +
444 + if (port->num == 1) {
445 + ltq_writel(&switch_regs->p1_ctl, port_ctl);
446 +
447 + rgmii_ctl &= ~RGMII_CTL_P1_MASK;
448 + rgmii_ctl |= (port_xmii << RGMII_CTL_P1_SHIFT);
449 + } else {
450 + ltq_writel(&switch_regs->p0_ctl, port_ctl);
451 +
452 + rgmii_ctl &= ~RGMII_CTL_P0_MASK;
453 + rgmii_ctl |= port_xmii;
454 + }
455 +
456 + ltq_writel(&switch_regs->rgmii_ctl, rgmii_ctl);
457 +
458 + /* Connect to external switch */
459 + if (port->flags & LTQ_ETH_PORT_SWITCH) {
460 + sw = switch_connect(priv->bus);
461 + if (sw)
462 + switch_setup(sw);
463 + }
464 +
465 + /* Connect to internal/external PHYs */
466 + if (port->flags & LTQ_ETH_PORT_PHY) {
467 + phydev = phy_connect(priv->bus, port->phy_addr, priv->dev,
468 + port->phy_if);
469 + if (phydev)
470 + phy_config(phydev);
471 +
472 + priv->phymap[port->num] = phydev;
473 + }
474 +}
475 +
476 +int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
477 +{
478 + struct eth_device *dev;
479 + struct mii_dev *bus;
480 + struct ltq_eth_priv *priv;
481 + struct ltq_dma_device *dma_dev;
482 + const struct ltq_eth_port_config *port = &board_config->ports[0];
483 + int i, ret;
484 +
485 + build_check_ar9_registers();
486 +
487 + ltq_dma_init();
488 + ltq_eth_hw_init(port);
489 +
490 + dev = calloc(1, sizeof(*dev));
491 + if (!dev)
492 + return -1;
493 +
494 + priv = calloc(1, sizeof(*priv));
495 + if (!priv)
496 + return -1;
497 +
498 + bus = mdio_alloc();
499 + if (!bus)
500 + return -1;
501 +
502 + sprintf(dev->name, LTQ_ETH_DRV_NAME);
503 + dev->priv = priv;
504 + dev->init = ltq_eth_init;
505 + dev->halt = ltq_eth_halt;
506 + dev->recv = ltq_eth_recv;
507 + dev->send = ltq_eth_send;
508 +
509 + sprintf(bus->name, LTQ_MDIO_DRV_NAME);
510 + bus->read = ltq_mdio_read;
511 + bus->write = ltq_mdio_write;
512 + bus->priv = priv;
513 +
514 + dma_dev = &priv->dma_dev;
515 + dma_dev->port = 0;
516 + dma_dev->rx_chan.chan_no = 0;
517 + dma_dev->rx_chan.class = 0;
518 + dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
519 + dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
520 + dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
521 + dma_dev->tx_chan.chan_no = 1;
522 + dma_dev->tx_chan.class = 0;
523 + dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
524 + dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
525 + dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
526 +
527 + priv->bus = bus;
528 + priv->dev = dev;
529 +
530 + ret = ltq_dma_register(dma_dev);
531 + if (ret)
532 + return ret;
533 +
534 + ret = mdio_register(bus);
535 + if (ret)
536 + return ret;
537 +
538 + ret = eth_register(dev);
539 + if (ret)
540 + return ret;
541 +
542 + for (i = 0; i < board_config->num_ports; i++)
543 + ltq_eth_port_config(priv, &board_config->ports[i]);
544 +
545 + return 0;
546 +}