0016-net-add-driver-for-Lantiq-XWAY-ARX100-switch.patch 14 KB

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