mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	Refresh uboot-lantiq patches. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> SVN-Revision: 40546
		
			
				
	
	
		
			547 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			547 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 7288414298b34dcda1216fee1fe38d05ea0027a2 Mon Sep 17 00:00:00 2001
 | |
| From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
 | |
| Date: Mon, 17 Dec 2012 23:32:39 +0100
 | |
| Subject: net: add driver for Lantiq XWAY ARX100 switch
 | |
| 
 | |
| Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
 | |
| 
 | |
| --- a/arch/mips/include/asm/arch-arx100/config.h
 | |
| +++ b/arch/mips/include/asm/arch-arx100/config.h
 | |
| @@ -10,17 +10,21 @@
 | |
|   * and drivers for this SoC:
 | |
|   *
 | |
|   * CONFIG_LTQ_SUPPORT_UART
 | |
| - * - support the Danube ASC/UART interface and console
 | |
| + * - support the ARX100 ASC/UART interface and console
 | |
|   *
 | |
|   * CONFIG_LTQ_SUPPORT_NOR_FLASH
 | |
|   * - support a parallel NOR flash via the CFI interface in flash bank 0
 | |
|   *
 | |
|   * CONFIG_LTQ_SUPPORT_ETHERNET
 | |
| - * - support the Danube ETOP and MAC interface
 | |
| + * - support the ARX100 ETOP and MAC interface
 | |
|   *
 | |
|   * CONFIG_LTQ_SUPPORT_SPI_FLASH
 | |
| - * - support the Danube SPI interface and serial flash drivers
 | |
| + * - support the ARX100 SPI interface and serial flash drivers
 | |
|   * - specific SPI flash drivers must be configured separately
 | |
| + *
 | |
| + * CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH
 | |
| + * - build a preloader that runs in the internal SRAM and loads
 | |
| + *   the U-Boot from SPI flash into RAM
 | |
|   */
 | |
|  
 | |
|  #ifndef __ARX100_CONFIG_H__
 | |
| --- /dev/null
 | |
| +++ b/arch/mips/include/asm/arch-arx100/switch.h
 | |
| @@ -0,0 +1,86 @@
 | |
| +/*
 | |
| + *   Copyright (C) 2012-2013 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
 | |
| + *
 | |
| + *   SPDX-License-Identifier:	GPL-2.0+
 | |
| + */
 | |
| +
 | |
| +#ifndef __ARX100_SWITCH_H__
 | |
| +#define __ARX100_SWITCH_H__
 | |
| +
 | |
| +struct ar9_switch_regs {
 | |
| +	__be32	ps;		/* Port status*/
 | |
| +	__be32	p0_ctl;		/* Port 0 control */
 | |
| +	__be32	p1_ctl;		/* Port 1 control */
 | |
| +	__be32	p2_ctl;		/* Port 2 control */
 | |
| +	__be32	p0_vlan;	/* Port 0 VLAN control */
 | |
| +	__be32	p1_vlan;	/* Port 1 VLAN control */
 | |
| +	__be32	p2_vlan;	/* Port 2 VLAN control */
 | |
| +	__be32	p0_inctl;	/* Port 0 ingress control */
 | |
| +	__be32	p1_inctl;	/* Port 1 ingress control */
 | |
| +	__be32	p2_inctl;	/* Port 2 ingress control */
 | |
| +	u32	rsvd0[16];
 | |
| +	__be32	sw_gctl0;	/* Switch global control 0 */
 | |
| +	__be32	sw_gctl1;	/* Switch global control 1 */
 | |
| +	__be32	arp;		/* ARP/RARP */
 | |
| +	__be32	strm_ctl;	/* Storm control */
 | |
| +	__be32	rgmii_ctl;	/* RGMII/GMII port control */
 | |
| +	u32	rsvd1[4];
 | |
| +	__be32	pmac_hd_ctl;	/* PMAC header control */
 | |
| +	u32	rsvd2[15];
 | |
| +	__be32	mdio_ctrl;	/* MDIO indirect access control */
 | |
| +	__be32	mdio_data;	/* MDIO indirect read data */
 | |
| +};
 | |
| +
 | |
| +#define BUILD_CHECK_AR9_REG(name, offset)	\
 | |
| +	BUILD_BUG_ON(offsetof(struct ar9_switch_regs, name) != (offset))
 | |
| +
 | |
| +static inline void build_check_ar9_registers(void)
 | |
| +{
 | |
| +	BUILD_CHECK_AR9_REG(sw_gctl0, 0x68);
 | |
| +	BUILD_CHECK_AR9_REG(rgmii_ctl, 0x78);
 | |
| +	BUILD_CHECK_AR9_REG(pmac_hd_ctl, 0x8c);
 | |
| +	BUILD_CHECK_AR9_REG(mdio_ctrl, 0xcc);
 | |
| +	BUILD_CHECK_AR9_REG(mdio_data, 0xd0);
 | |
| +}
 | |
| +
 | |
| +#define P0_CTL_FLP		(1 << 18)
 | |
| +#define P0_CTL_FLD		(1 << 17)
 | |
| +
 | |
| +#define SW_GCTL0_SE		(1 << 31)
 | |
| +
 | |
| +#define RGMII_CTL_P1_SHIFT	10
 | |
| +#define RGMII_CTL_P1_MASK	(0x3FF << RGMII_CTL_P1_SHIFT)
 | |
| +#define RGMII_CTL_P0_MASK	0x3FF
 | |
| +#define RGMII_CTL_P0IS_SHIFT	8
 | |
| +#define RGMII_CTL_P0IS_RGMII	(0x0 << RGMII_CTL_P0IS_SHIFT)
 | |
| +#define RGMII_CTL_P0IS_MII	(0x1 << RGMII_CTL_P0IS_SHIFT)
 | |
| +#define RGMII_CTL_P0IS_REVMII	(0x2 << RGMII_CTL_P0IS_SHIFT)
 | |
| +#define RGMII_CTL_P0IS_RMII	(0x3 << RGMII_CTL_P0IS_SHIFT)
 | |
| +#define RGMII_CTL_P0RDLY_SHIFT	6
 | |
| +#define RGMII_CTL_P0RDLY_0_0	(0x0 << RGMII_CTL_P0RDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0RDLY_1_5	(0x1 << RGMII_CTL_P0RDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0RDLY_1_75	(0x2 << RGMII_CTL_P0RDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0RDLY_2_0	(0x3 << RGMII_CTL_P0RDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0TDLY_SHIFT	4
 | |
| +#define RGMII_CTL_P0TDLY_0_0	(0x0 << RGMII_CTL_P0TDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0TDLY_1_5	(0x1 << RGMII_CTL_P0TDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0TDLY_1_75	(0x2 << RGMII_CTL_P0TDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0TDLY_2_0	(0x3 << RGMII_CTL_P0TDLY_SHIFT)
 | |
| +#define RGMII_CTL_P0SPD_SHIFT	2
 | |
| +#define RGMII_CTL_P0SPD_10	(0x0 << RGMII_CTL_P0SPD_SHIFT)
 | |
| +#define RGMII_CTL_P0SPD_100	(0x1 << RGMII_CTL_P0SPD_SHIFT)
 | |
| +#define RGMII_CTL_P0SPD_1000	(0x2 << RGMII_CTL_P0SPD_SHIFT)
 | |
| +#define RGMII_CTL_P0DUP_FULL	(1 << 1)
 | |
| +#define RGMII_CTL_P0FCE_EN	(1 << 0)
 | |
| +
 | |
| +#define PMAC_HD_CTL_AC		(1 << 18)
 | |
| +
 | |
| +#define MDIO_CTRL_WD_SHIFT	16
 | |
| +#define MDIO_CTRL_MBUSY		(1 << 15)
 | |
| +#define MDIO_CTRL_OP_READ	(1 << 11)
 | |
| +#define MDIO_CTRL_OP_WRITE	(1 << 10)
 | |
| +#define MDIO_CTRL_PHYAD_SHIFT	5
 | |
| +#define MDIO_CTRL_PHYAD_MASK	(0x1f << MDIO_CTRL_PHYAD_SHIFT)
 | |
| +#define MDIO_CTRL_REGAD_MASK	0x1f
 | |
| +
 | |
| +#endif /* __ARX100_SWITCH_H__ */
 | |
| --- a/drivers/net/Makefile
 | |
| +++ b/drivers/net/Makefile
 | |
| @@ -38,6 +38,7 @@ COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks86
 | |
|  COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
 | |
|  COBJS-$(CONFIG_LAN91C96) += lan91c96.o
 | |
|  COBJS-$(CONFIG_LANTIQ_DANUBE_ETOP) += lantiq_danube_etop.o
 | |
| +COBJS-$(CONFIG_LANTIQ_ARX100_SWITCH) += lantiq_arx100_switch.o
 | |
|  COBJS-$(CONFIG_LANTIQ_VRX200_SWITCH) += lantiq_vrx200_switch.o
 | |
|  COBJS-$(CONFIG_MACB) += macb.o
 | |
|  COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
 | |
| --- /dev/null
 | |
| +++ b/drivers/net/lantiq_arx100_switch.c
 | |
| @@ -0,0 +1,410 @@
 | |
| +/*
 | |
| + * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
 | |
| + *
 | |
| + * SPDX-License-Identifier:	GPL-2.0+
 | |
| + */
 | |
| +#define DEBUG
 | |
| +#include <common.h>
 | |
| +#include <malloc.h>
 | |
| +#include <netdev.h>
 | |
| +#include <miiphy.h>
 | |
| +#include <switch.h>
 | |
| +#include <linux/compiler.h>
 | |
| +#include <asm/gpio.h>
 | |
| +#include <asm/processor.h>
 | |
| +#include <asm/lantiq/io.h>
 | |
| +#include <asm/lantiq/eth.h>
 | |
| +#include <asm/lantiq/pm.h>
 | |
| +#include <asm/lantiq/reset.h>
 | |
| +#include <asm/lantiq/dma.h>
 | |
| +#include <asm/arch/soc.h>
 | |
| +#include <asm/arch/switch.h>
 | |
| +
 | |
| +#define LTQ_ETH_RX_BUFFER_CNT		PKTBUFSRX
 | |
| +#define LTQ_ETH_TX_BUFFER_CNT		8
 | |
| +#define LTQ_ETH_RX_DATA_SIZE		PKTSIZE_ALIGN
 | |
| +#define LTQ_ETH_IP_ALIGN		2
 | |
| +
 | |
| +#define LTQ_MDIO_DRV_NAME		"ltq-mdio"
 | |
| +#define LTQ_ETH_DRV_NAME		"ltq-eth"
 | |
| +
 | |
| +#define LTQ_ETHSW_MAX_GMAC		2
 | |
| +#define LTQ_ETHSW_PMAC			2
 | |
| +
 | |
| +struct ltq_eth_priv {
 | |
| +	struct ltq_dma_device dma_dev;
 | |
| +	struct mii_dev *bus;
 | |
| +	struct eth_device *dev;
 | |
| +	struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC];
 | |
| +	int rx_num;
 | |
| +	int tx_num;
 | |
| +};
 | |
| +
 | |
| +static struct ar9_switch_regs *switch_regs =
 | |
| +	(struct ar9_switch_regs *) CKSEG1ADDR(LTQ_SWITCH_BASE);
 | |
| +
 | |
| +static int ltq_mdio_is_busy(void)
 | |
| +{
 | |
| +	u32 mdio_ctrl = ltq_readl(&switch_regs->mdio_ctrl);
 | |
| +
 | |
| +	return mdio_ctrl & MDIO_CTRL_MBUSY;
 | |
| +}
 | |
| +
 | |
| +static void ltq_mdio_poll(void)
 | |
| +{
 | |
| +	while (ltq_mdio_is_busy())
 | |
| +		cpu_relax();
 | |
| +
 | |
| +	__udelay(1000);
 | |
| +}
 | |
| +
 | |
| +static int ltq_mdio_read(struct mii_dev *bus, int phyad, int devad,
 | |
| +					int regad)
 | |
| +{
 | |
| +	u32 mdio_ctrl;
 | |
| +	int retval;
 | |
| +
 | |
| +	mdio_ctrl = MDIO_CTRL_MBUSY | MDIO_CTRL_OP_READ |
 | |
| +		((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
 | |
| +		(regad & MDIO_CTRL_REGAD_MASK);
 | |
| +
 | |
| +	ltq_mdio_poll();
 | |
| +	ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
 | |
| +	ltq_mdio_poll();
 | |
| +	retval = ltq_readl(&switch_regs->mdio_data);
 | |
| +	ltq_writel(&switch_regs->mdio_data, 0xFFFF);
 | |
| +
 | |
| +	debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, retval);
 | |
| +
 | |
| +	return retval;
 | |
| +}
 | |
| +
 | |
| +static int ltq_mdio_write(struct mii_dev *bus, int phyad, int devad,
 | |
| +					int regad, u16 val)
 | |
| +{
 | |
| +	u32 mdio_ctrl;
 | |
| +
 | |
| +	debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, val);
 | |
| +
 | |
| +	mdio_ctrl = (val << MDIO_CTRL_WD_SHIFT) | MDIO_CTRL_MBUSY |
 | |
| +		MDIO_CTRL_OP_WRITE |
 | |
| +		((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
 | |
| +		(regad & MDIO_CTRL_REGAD_MASK);
 | |
| +
 | |
| +	ltq_mdio_poll();
 | |
| +	ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void ltq_eth_gmac_update(struct phy_device *phydev, int num)
 | |
| +{
 | |
| +}
 | |
| +
 | |
| +static inline u8 *ltq_eth_rx_packet_align(int rx_num)
 | |
| +{
 | |
| +	u8 *packet = (u8 *) NetRxPackets[rx_num];
 | |
| +
 | |
| +	/*
 | |
| +	 * IP header needs
 | |
| +	 */
 | |
| +	return packet + LTQ_ETH_IP_ALIGN;
 | |
| +}
 | |
| +
 | |
| +static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
 | |
| +{
 | |
| +	struct ltq_eth_priv *priv = dev->priv;
 | |
| +	struct ltq_dma_device *dma_dev = &priv->dma_dev;
 | |
| +	struct phy_device *phydev;
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
 | |
| +		phydev = priv->phymap[i];
 | |
| +		if (!phydev)
 | |
| +			continue;
 | |
| +
 | |
| +		phy_startup(phydev);
 | |
| +		ltq_eth_gmac_update(phydev, i);
 | |
| +	}
 | |
| +
 | |
| +	for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
 | |
| +		ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
 | |
| +			LTQ_ETH_RX_DATA_SIZE);
 | |
| +
 | |
| +	ltq_dma_enable(dma_dev);
 | |
| +
 | |
| +	priv->rx_num = 0;
 | |
| +	priv->tx_num = 0;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void ltq_eth_halt(struct eth_device *dev)
 | |
| +{
 | |
| +	struct ltq_eth_priv *priv = dev->priv;
 | |
| +	struct ltq_dma_device *dma_dev = &priv->dma_dev;
 | |
| +	struct phy_device *phydev;
 | |
| +	int i;
 | |
| +
 | |
| +	ltq_dma_reset(dma_dev);
 | |
| +
 | |
| +	for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
 | |
| +		phydev = priv->phymap[i];
 | |
| +		if (!phydev)
 | |
| +			continue;
 | |
| +
 | |
| +		phy_shutdown(phydev);
 | |
| +		phydev->link = 0;
 | |
| +		ltq_eth_gmac_update(phydev, i);
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
 | |
| +{
 | |
| +	struct ltq_eth_priv *priv = dev->priv;
 | |
| +	struct ltq_dma_device *dma_dev = &priv->dma_dev;
 | |
| +	int err;
 | |
| +
 | |
| +	err = ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
 | |
| +	if (err) {
 | |
| +		puts("NET: timeout on waiting for TX descriptor\n");
 | |
| +		return -1;
 | |
| +	}
 | |
| +
 | |
| +	priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
 | |
| +
 | |
| +	return err;
 | |
| +}
 | |
| +
 | |
| +static int ltq_eth_recv(struct eth_device *dev)
 | |
| +{
 | |
| +	struct ltq_eth_priv *priv = dev->priv;
 | |
| +	struct ltq_dma_device *dma_dev = &priv->dma_dev;
 | |
| +	u8 *packet;
 | |
| +	int len;
 | |
| +
 | |
| +	if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
 | |
| +		return 0;
 | |
| +
 | |
| +#if 0
 | |
| +	printf("%s: rx_num %d\n", __func__, priv->rx_num);
 | |
| +#endif
 | |
| +
 | |
| +	len = ltq_dma_rx_length(dma_dev, priv->rx_num);
 | |
| +	packet = ltq_eth_rx_packet_align(priv->rx_num);
 | |
| +
 | |
| +#if 0
 | |
| +	printf("%s: received: packet %p, len %u, rx_num %d\n",
 | |
| +		__func__, packet, len, priv->rx_num);
 | |
| +#endif
 | |
| +
 | |
| +	if (len)
 | |
| +		NetReceive(packet, len);
 | |
| +
 | |
| +	ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
 | |
| +		LTQ_ETH_RX_DATA_SIZE);
 | |
| +
 | |
| +	priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void ltq_eth_pmac_init(void)
 | |
| +{
 | |
| +	/* Add CRC to packets from DMA to PMAC */
 | |
| +	ltq_setbits(&switch_regs->pmac_hd_ctl, PMAC_HD_CTL_AC);
 | |
| +
 | |
| +	/* Force link up */
 | |
| +	ltq_setbits(&switch_regs->p2_ctl, P0_CTL_FLP);
 | |
| +}
 | |
| +
 | |
| +static void ltq_eth_hw_init(const struct ltq_eth_port_config *port)
 | |
| +{
 | |
| +	/* Power up ethernet subsystems */
 | |
| +	ltq_pm_enable(LTQ_PM_ETH);
 | |
| +
 | |
| +	/* Enable switch core */
 | |
| +	ltq_setbits(&switch_regs->sw_gctl0, SW_GCTL0_SE);
 | |
| +
 | |
| +	/* MII/MDIO */
 | |
| +	gpio_set_altfunc(42, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
 | |
| +	/* MII/MDC */
 | |
| +	gpio_set_altfunc(43, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
 | |
| +
 | |
| +	ltq_eth_pmac_init();
 | |
| +}
 | |
| +
 | |
| +static void ltq_eth_port_config(struct ltq_eth_priv *priv,
 | |
| +				const struct ltq_eth_port_config *port)
 | |
| +{
 | |
| +	struct phy_device *phydev;
 | |
| +	struct switch_device *sw;
 | |
| +	u32 rgmii_ctl;
 | |
| +	unsigned int port_ctl, port_xmii = 0;
 | |
| +
 | |
| +	if (port->num > 1)
 | |
| +		return;
 | |
| +
 | |
| +	rgmii_ctl = ltq_readl(&switch_regs->rgmii_ctl);
 | |
| +
 | |
| +	if (port->num == 1)
 | |
| +		port_ctl = ltq_readl(&switch_regs->p1_ctl);
 | |
| +	else
 | |
| +		port_ctl = ltq_readl(&switch_regs->p0_ctl);
 | |
| +
 | |
| +	switch (port->phy_if) {
 | |
| +	case PHY_INTERFACE_MODE_RGMII:
 | |
| +		port_xmii = RGMII_CTL_P0IS_RGMII;
 | |
| +
 | |
| +		switch (port->rgmii_tx_delay) {
 | |
| +		case 1:
 | |
| +			port_xmii |= RGMII_CTL_P0TDLY_1_5;
 | |
| +			break;
 | |
| +		case 2:
 | |
| +			port_xmii |= RGMII_CTL_P0TDLY_1_75;
 | |
| +			break;
 | |
| +		case 3:
 | |
| +			port_xmii |= RGMII_CTL_P0TDLY_2_0;
 | |
| +			break;
 | |
| +		default:
 | |
| +			break;
 | |
| +		}
 | |
| +
 | |
| +		switch (port->rgmii_rx_delay) {
 | |
| +		case 1:
 | |
| +			port_xmii |= RGMII_CTL_P0RDLY_1_5;
 | |
| +			break;
 | |
| +		case 2:
 | |
| +			port_xmii |= RGMII_CTL_P0RDLY_1_75;
 | |
| +			break;
 | |
| +		case 3:
 | |
| +			port_xmii |= RGMII_CTL_P0RDLY_2_0;
 | |
| +			break;
 | |
| +		default:
 | |
| +			break;
 | |
| +		}
 | |
| +
 | |
| +		if (!(port->flags & LTQ_ETH_PORT_PHY)) {
 | |
| +			port_xmii |= (RGMII_CTL_P0SPD_1000 |
 | |
| +					RGMII_CTL_P0DUP_FULL);
 | |
| +			port_ctl |= P0_CTL_FLP;
 | |
| +		}
 | |
| +
 | |
| +		break;
 | |
| +	case PHY_INTERFACE_MODE_MII:
 | |
| +		port_xmii = RGMII_CTL_P0IS_MII;
 | |
| +
 | |
| +		if (!(port->flags & LTQ_ETH_PORT_PHY)) {
 | |
| +			port_xmii |= (RGMII_CTL_P0SPD_100 |
 | |
| +					RGMII_CTL_P0DUP_FULL);
 | |
| +			port_ctl |= P0_CTL_FLP;
 | |
| +		}
 | |
| +
 | |
| +		break;
 | |
| +	default:
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
| +	if (port->num == 1) {
 | |
| +		ltq_writel(&switch_regs->p1_ctl, port_ctl);
 | |
| +
 | |
| +		rgmii_ctl &= ~RGMII_CTL_P1_MASK;
 | |
| +		rgmii_ctl |= (port_xmii << RGMII_CTL_P1_SHIFT);
 | |
| +	} else {
 | |
| +		ltq_writel(&switch_regs->p0_ctl, port_ctl);
 | |
| +
 | |
| +		rgmii_ctl &= ~RGMII_CTL_P0_MASK;
 | |
| +		rgmii_ctl |= port_xmii;
 | |
| +	}
 | |
| +
 | |
| +	ltq_writel(&switch_regs->rgmii_ctl, rgmii_ctl);
 | |
| +
 | |
| +	/* Connect to external switch */
 | |
| +	if (port->flags & LTQ_ETH_PORT_SWITCH) {
 | |
| +		sw = switch_connect(priv->bus);
 | |
| +		if (sw)
 | |
| +			switch_setup(sw);
 | |
| +	}
 | |
| +
 | |
| +	/* Connect to internal/external PHYs */
 | |
| +	if (port->flags & LTQ_ETH_PORT_PHY) {
 | |
| +		phydev = phy_connect(priv->bus, port->phy_addr, priv->dev,
 | |
| +					port->phy_if);
 | |
| +		if (phydev)
 | |
| +			phy_config(phydev);
 | |
| +
 | |
| +		priv->phymap[port->num] = phydev;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
 | |
| +{
 | |
| +	struct eth_device *dev;
 | |
| +	struct mii_dev *bus;
 | |
| +	struct ltq_eth_priv *priv;
 | |
| +	struct ltq_dma_device *dma_dev;
 | |
| +	const struct ltq_eth_port_config *port = &board_config->ports[0];
 | |
| +	int i, ret;
 | |
| +
 | |
| +	build_check_ar9_registers();
 | |
| +
 | |
| +	ltq_dma_init();
 | |
| +	ltq_eth_hw_init(port);
 | |
| +
 | |
| +	dev = calloc(1, sizeof(*dev));
 | |
| +	if (!dev)
 | |
| +		return -1;
 | |
| +
 | |
| +	priv = calloc(1, sizeof(*priv));
 | |
| +	if (!priv)
 | |
| +		return -1;
 | |
| +
 | |
| +	bus = mdio_alloc();
 | |
| +	if (!bus)
 | |
| +		return -1;
 | |
| +
 | |
| +	sprintf(dev->name, LTQ_ETH_DRV_NAME);
 | |
| +	dev->priv = priv;
 | |
| +	dev->init = ltq_eth_init;
 | |
| +	dev->halt = ltq_eth_halt;
 | |
| +	dev->recv = ltq_eth_recv;
 | |
| +	dev->send = ltq_eth_send;
 | |
| +
 | |
| +	sprintf(bus->name, LTQ_MDIO_DRV_NAME);
 | |
| +	bus->read = ltq_mdio_read;
 | |
| +	bus->write = ltq_mdio_write;
 | |
| +	bus->priv = priv;
 | |
| +
 | |
| +	dma_dev = &priv->dma_dev;
 | |
| +	dma_dev->port = 0;
 | |
| +	dma_dev->rx_chan.chan_no = 0;
 | |
| +	dma_dev->rx_chan.class = 0;
 | |
| +	dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
 | |
| +	dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
 | |
| +	dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
 | |
| +	dma_dev->tx_chan.chan_no = 1;
 | |
| +	dma_dev->tx_chan.class = 0;
 | |
| +	dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
 | |
| +	dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
 | |
| +	dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
 | |
| +
 | |
| +	priv->bus = bus;
 | |
| +	priv->dev = dev;
 | |
| +
 | |
| +	ret = ltq_dma_register(dma_dev);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	ret = mdio_register(bus);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	ret = eth_register(dev);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	for (i = 0; i < board_config->num_ports; i++)
 | |
| +		ltq_eth_port_config(priv, &board_config->ports[i]);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 |