|  | /* | 
|  | * INCA-IP internal switch ethernet driver. | 
|  | * | 
|  | * (C) Copyright 2003-2004 | 
|  | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <common.h> | 
|  |  | 
|  | #if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \ | 
|  | && defined(CONFIG_INCA_IP_SWITCH) | 
|  |  | 
|  | #include <malloc.h> | 
|  | #include <net.h> | 
|  | #include <asm/inca-ip.h> | 
|  | #include <asm/addrspace.h> | 
|  |  | 
|  |  | 
|  | #define NUM_RX_DESC	PKTBUFSRX | 
|  | #define NUM_TX_DESC	3 | 
|  | #define TOUT_LOOP	1000000 | 
|  |  | 
|  |  | 
|  | #define DELAY	udelay(10000) | 
|  | /* Sometimes the store word instruction hangs while writing to one | 
|  | * of the Switch registers. Moving the instruction into a separate | 
|  | * function somehow makes the problem go away. | 
|  | */ | 
|  | static void SWORD(volatile u32 * reg, u32 value) | 
|  | { | 
|  | *reg = value; | 
|  | } | 
|  |  | 
|  | #define DMA_WRITE_REG(reg, value) *((volatile u32 *)reg) = (u32)value; | 
|  | #define DMA_READ_REG(reg, value)    value = (u32)*((volatile u32*)reg) | 
|  | #define SW_WRITE_REG(reg, value)   \ | 
|  | SWORD(reg, value);\ | 
|  | DELAY;\ | 
|  | SWORD(reg, value); | 
|  |  | 
|  | #define SW_READ_REG(reg, value)	   \ | 
|  | value = (u32)*((volatile u32*)reg);\ | 
|  | DELAY;\ | 
|  | value = (u32)*((volatile u32*)reg); | 
|  |  | 
|  | #define INCA_DMA_TX_POLLING_TIME	0x07 | 
|  | #define INCA_DMA_RX_POLLING_TIME	0x07 | 
|  |  | 
|  | #define INCA_DMA_TX_HOLD		0x80000000 | 
|  | #define INCA_DMA_TX_EOP			0x40000000 | 
|  | #define INCA_DMA_TX_SOP			0x20000000 | 
|  | #define INCA_DMA_TX_ICPT		0x10000000 | 
|  | #define INCA_DMA_TX_IEOP		0x08000000 | 
|  |  | 
|  | #define INCA_DMA_RX_C			0x80000000 | 
|  | #define INCA_DMA_RX_SOP			0x40000000 | 
|  | #define INCA_DMA_RX_EOP			0x20000000 | 
|  |  | 
|  | #define INCA_SWITCH_PHY_SPEED_10H	0x1 | 
|  | #define INCA_SWITCH_PHY_SPEED_10F	0x5 | 
|  | #define INCA_SWITCH_PHY_SPEED_100H	0x2 | 
|  | #define INCA_SWITCH_PHY_SPEED_100F	0x6 | 
|  |  | 
|  | /************************ Auto MDIX settings ************************/ | 
|  | #define INCA_IP_AUTO_MDIX_LAN_PORTS_DIR		INCA_IP_Ports_P1_DIR | 
|  | #define INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL	INCA_IP_Ports_P1_ALTSEL | 
|  | #define INCA_IP_AUTO_MDIX_LAN_PORTS_OUT		INCA_IP_Ports_P1_OUT | 
|  | #define INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX	16 | 
|  |  | 
|  | #define WAIT_SIGNAL_RETRIES			100 | 
|  | #define WAIT_LINK_RETRIES			100 | 
|  | #define LINK_RETRY_DELAY			2000  /* ms */ | 
|  | /********************************************************************/ | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | union { | 
|  | struct { | 
|  | volatile u32 HOLD		:1; | 
|  | volatile u32 ICpt		:1; | 
|  | volatile u32 IEop		:1; | 
|  | volatile u32 offset		:3; | 
|  | volatile u32 reserved0		:4; | 
|  | volatile u32 NFB		:22; | 
|  | }field; | 
|  |  | 
|  | volatile u32 word; | 
|  | }params; | 
|  |  | 
|  | volatile u32 nextRxDescPtr; | 
|  |  | 
|  | volatile u32 RxDataPtr; | 
|  |  | 
|  | union { | 
|  | struct { | 
|  | volatile u32 C			:1; | 
|  | volatile u32 Sop		:1; | 
|  | volatile u32 Eop		:1; | 
|  | volatile u32 reserved3		:12; | 
|  | volatile u32 NBT		:17; | 
|  | }field; | 
|  |  | 
|  | volatile u32 word; | 
|  | }status; | 
|  |  | 
|  | } inca_rx_descriptor_t; | 
|  |  | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | union { | 
|  | struct { | 
|  | volatile u32 HOLD		:1; | 
|  | volatile u32 Eop		:1; | 
|  | volatile u32 Sop		:1; | 
|  | volatile u32 ICpt		:1; | 
|  | volatile u32 IEop		:1; | 
|  | volatile u32 reserved0		:5; | 
|  | volatile u32 NBA		:22; | 
|  | }field; | 
|  |  | 
|  | volatile u32 word; | 
|  | }params; | 
|  |  | 
|  | volatile u32 nextTxDescPtr; | 
|  |  | 
|  | volatile u32 TxDataPtr; | 
|  |  | 
|  | volatile u32 C			:1; | 
|  | volatile u32 reserved3		:31; | 
|  |  | 
|  | } inca_tx_descriptor_t; | 
|  |  | 
|  |  | 
|  | static inca_rx_descriptor_t rx_ring[NUM_RX_DESC] __attribute__ ((aligned(16))); | 
|  | static inca_tx_descriptor_t tx_ring[NUM_TX_DESC] __attribute__ ((aligned(16))); | 
|  |  | 
|  | static int tx_new, rx_new, tx_hold, rx_hold; | 
|  | static int tx_old_hold = -1; | 
|  | static int initialized	= 0; | 
|  |  | 
|  |  | 
|  | static int inca_switch_init(struct eth_device *dev, bd_t * bis); | 
|  | static int inca_switch_send(struct eth_device *dev, volatile void *packet, int length); | 
|  | static int inca_switch_recv(struct eth_device *dev); | 
|  | static void inca_switch_halt(struct eth_device *dev); | 
|  | static void inca_init_switch_chip(void); | 
|  | static void inca_dma_init(void); | 
|  | static int inca_amdix(void); | 
|  |  | 
|  |  | 
|  | int inca_switch_initialize(bd_t * bis) | 
|  | { | 
|  | struct eth_device *dev; | 
|  |  | 
|  | #if 0 | 
|  | printf("Entered inca_switch_initialize()\n"); | 
|  | #endif | 
|  |  | 
|  | if (!(dev = (struct eth_device *) malloc (sizeof *dev))) { | 
|  | printf("Failed to allocate memory\n"); | 
|  | return 0; | 
|  | } | 
|  | memset(dev, 0, sizeof(*dev)); | 
|  |  | 
|  | inca_dma_init(); | 
|  |  | 
|  | inca_init_switch_chip(); | 
|  |  | 
|  | #if defined(CONFIG_INCA_IP_SWITCH_AMDIX) | 
|  | inca_amdix(); | 
|  | #endif | 
|  |  | 
|  | sprintf(dev->name, "INCA-IP Switch"); | 
|  | dev->init = inca_switch_init; | 
|  | dev->halt = inca_switch_halt; | 
|  | dev->send = inca_switch_send; | 
|  | dev->recv = inca_switch_recv; | 
|  |  | 
|  | eth_register(dev); | 
|  |  | 
|  | #if 0 | 
|  | printf("Leaving inca_switch_initialize()\n"); | 
|  | #endif | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int inca_switch_init(struct eth_device *dev, bd_t * bis) | 
|  | { | 
|  | int i; | 
|  | u32 v, regValue; | 
|  | u16 wTmp; | 
|  |  | 
|  | #if 0 | 
|  | printf("Entering inca_switch_init()\n"); | 
|  | #endif | 
|  |  | 
|  | /* Set MAC address. | 
|  | */ | 
|  | wTmp = (u16)dev->enetaddr[0]; | 
|  | regValue = (wTmp << 8) | dev->enetaddr[1]; | 
|  |  | 
|  | SW_WRITE_REG(INCA_IP_Switch_PMAC_SA1, regValue); | 
|  |  | 
|  | wTmp = (u16)dev->enetaddr[2]; | 
|  | regValue = (wTmp << 8) | dev->enetaddr[3]; | 
|  | regValue = regValue << 16; | 
|  | wTmp = (u16)dev->enetaddr[4]; | 
|  | regValue |= (wTmp<<8) | dev->enetaddr[5]; | 
|  |  | 
|  | SW_WRITE_REG(INCA_IP_Switch_PMAC_SA2, regValue); | 
|  |  | 
|  | /* Initialize the descriptor rings. | 
|  | */ | 
|  | for (i = 0; i < NUM_RX_DESC; i++) { | 
|  | inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]); | 
|  | memset(rx_desc, 0, sizeof(rx_ring[i])); | 
|  |  | 
|  | /* Set maximum size of receive buffer. | 
|  | */ | 
|  | rx_desc->params.field.NFB = PKTSIZE_ALIGN; | 
|  |  | 
|  | /* Set the offset of the receive buffer. Zero means | 
|  | * that the offset mechanism is not used. | 
|  | */ | 
|  | rx_desc->params.field.offset = 0; | 
|  |  | 
|  | /* Check if it is the last descriptor. | 
|  | */ | 
|  | if (i == (NUM_RX_DESC - 1)) { | 
|  | /* Let the last descriptor point to the first | 
|  | * one. | 
|  | */ | 
|  | rx_desc->nextRxDescPtr = KSEG1ADDR((u32)rx_ring); | 
|  | } else { | 
|  | /* Set the address of the next descriptor. | 
|  | */ | 
|  | rx_desc->nextRxDescPtr = (u32)KSEG1ADDR(&rx_ring[i+1]); | 
|  | } | 
|  |  | 
|  | rx_desc->RxDataPtr = (u32)KSEG1ADDR(NetRxPackets[i]); | 
|  | } | 
|  |  | 
|  | #if 0 | 
|  | printf("rx_ring = 0x%08X 0x%08X\n", (u32)rx_ring, (u32)&rx_ring[0]); | 
|  | printf("tx_ring = 0x%08X 0x%08X\n", (u32)tx_ring, (u32)&tx_ring[0]); | 
|  | #endif | 
|  |  | 
|  | for (i = 0; i < NUM_TX_DESC; i++) { | 
|  | inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[i]); | 
|  |  | 
|  | memset(tx_desc, 0, sizeof(tx_ring[i])); | 
|  |  | 
|  | tx_desc->params.word	   = 0; | 
|  | tx_desc->params.field.HOLD = 1; | 
|  | tx_desc->C		   = 1; | 
|  |  | 
|  | /* Check if it is the last descriptor. | 
|  | */ | 
|  | if (i == (NUM_TX_DESC - 1)) { | 
|  | /* Let the last descriptor point to the | 
|  | * first one. | 
|  | */ | 
|  | tx_desc->nextTxDescPtr = KSEG1ADDR((u32)tx_ring); | 
|  | } else { | 
|  | /* Set the address of the next descriptor. | 
|  | */ | 
|  | tx_desc->nextTxDescPtr = (u32)KSEG1ADDR(&tx_ring[i+1]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Initialize RxDMA. | 
|  | */ | 
|  | DMA_READ_REG(INCA_IP_DMA_DMA_RXISR, v); | 
|  | #if 0 | 
|  | printf("RX status = 0x%08X\n", v); | 
|  | #endif | 
|  |  | 
|  | /* Writing to the FRDA of CHANNEL. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring); | 
|  |  | 
|  | /* Writing to the COMMAND REG. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_INIT); | 
|  |  | 
|  | /* Initialize TxDMA. | 
|  | */ | 
|  | DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v); | 
|  | #if 0 | 
|  | printf("TX status = 0x%08X\n", v); | 
|  | #endif | 
|  |  | 
|  | /* Writing to the FRDA of CHANNEL. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXFRDA0, (u32)tx_ring); | 
|  |  | 
|  | tx_new = rx_new = 0; | 
|  |  | 
|  | tx_hold = NUM_TX_DESC - 1; | 
|  | rx_hold = NUM_RX_DESC - 1; | 
|  |  | 
|  | #if 0 | 
|  | rx_ring[rx_hold].params.field.HOLD = 1; | 
|  | #endif | 
|  | /* enable spanning tree forwarding, enable the CPU port */ | 
|  | /* ST_PT: | 
|  | *	CPS (CPU port status)	0x3 (forwarding) | 
|  | *	LPS (LAN port status)	0x3 (forwarding) | 
|  | *	PPS (PC port status)	0x3 (forwarding) | 
|  | */ | 
|  | SW_WRITE_REG(INCA_IP_Switch_ST_PT,0x3f); | 
|  |  | 
|  | #if 0 | 
|  | printf("Leaving inca_switch_init()\n"); | 
|  | #endif | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int inca_switch_send(struct eth_device *dev, volatile void *packet, int length) | 
|  | { | 
|  | int		       i; | 
|  | int		       res	= -1; | 
|  | u32		       command; | 
|  | u32		       regValue; | 
|  | inca_tx_descriptor_t * tx_desc	= KSEG1ADDR(&tx_ring[tx_new]); | 
|  |  | 
|  | #if 0 | 
|  | printf("Entered inca_switch_send()\n"); | 
|  | #endif | 
|  |  | 
|  | if (length <= 0) { | 
|  | printf ("%s: bad packet size: %d\n", dev->name, length); | 
|  | goto Done; | 
|  | } | 
|  |  | 
|  | for(i = 0; tx_desc->C == 0; i++) { | 
|  | if (i >= TOUT_LOOP) { | 
|  | printf("%s: tx error buffer not ready\n", dev->name); | 
|  | goto Done; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (tx_old_hold >= 0) { | 
|  | KSEG1ADDR(&tx_ring[tx_old_hold])->params.field.HOLD = 1; | 
|  | } | 
|  | tx_old_hold = tx_hold; | 
|  |  | 
|  | tx_desc->params.word = | 
|  | (INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD); | 
|  |  | 
|  | tx_desc->C = 0; | 
|  | tx_desc->TxDataPtr = (u32)packet; | 
|  | tx_desc->params.field.NBA = length; | 
|  |  | 
|  | KSEG1ADDR(&tx_ring[tx_hold])->params.field.HOLD = 0; | 
|  |  | 
|  | tx_hold = tx_new; | 
|  | tx_new	= (tx_new + 1) % NUM_TX_DESC; | 
|  |  | 
|  |  | 
|  | if (! initialized) { | 
|  | command = INCA_IP_DMA_DMA_TXCCR0_INIT; | 
|  | initialized = 1; | 
|  | } else { | 
|  | command = INCA_IP_DMA_DMA_TXCCR0_HR; | 
|  | } | 
|  |  | 
|  | DMA_READ_REG(INCA_IP_DMA_DMA_TXCCR0, regValue); | 
|  | regValue |= command; | 
|  | #if 0 | 
|  | printf("regValue = 0x%x\n", regValue); | 
|  | #endif | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue); | 
|  |  | 
|  | #if 1 | 
|  | for(i = 0; KSEG1ADDR(&tx_ring[tx_hold])->C == 0; i++) { | 
|  | if (i >= TOUT_LOOP) { | 
|  | printf("%s: tx buffer not ready\n", dev->name); | 
|  | goto Done; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | res = length; | 
|  | Done: | 
|  | #if 0 | 
|  | printf("Leaving inca_switch_send()\n"); | 
|  | #endif | 
|  | return res; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int inca_switch_recv(struct eth_device *dev) | 
|  | { | 
|  | int		       length  = 0; | 
|  | inca_rx_descriptor_t * rx_desc; | 
|  |  | 
|  | #if 0 | 
|  | printf("Entered inca_switch_recv()\n"); | 
|  | #endif | 
|  |  | 
|  | for (;;) { | 
|  | rx_desc = KSEG1ADDR(&rx_ring[rx_new]); | 
|  |  | 
|  | if (rx_desc->status.field.C == 0) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | #if 0 | 
|  | rx_ring[rx_new].params.field.HOLD = 1; | 
|  | #endif | 
|  |  | 
|  | if (! rx_desc->status.field.Eop) { | 
|  | printf("Partly received packet!!!\n"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | length = rx_desc->status.field.NBT; | 
|  | rx_desc->status.word &= | 
|  | ~(INCA_DMA_RX_EOP | INCA_DMA_RX_SOP | INCA_DMA_RX_C); | 
|  | #if 0 | 
|  | { | 
|  | int i; | 
|  | for (i=0;i<length - 4;i++) { | 
|  | if (i % 16 == 0) printf("\n%04x: ", i); | 
|  | printf("%02X ", NetRxPackets[rx_new][i]); | 
|  | } | 
|  | printf("\n"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (length) { | 
|  | #if 0 | 
|  | printf("Received %d bytes\n", length); | 
|  | #endif | 
|  | NetReceive((void*)KSEG1ADDR(NetRxPackets[rx_new]), length - 4); | 
|  | } else { | 
|  | #if 1 | 
|  | printf("Zero length!!!\n"); | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | KSEG1ADDR(&rx_ring[rx_hold])->params.field.HOLD = 0; | 
|  |  | 
|  | rx_hold = rx_new; | 
|  |  | 
|  | rx_new = (rx_new + 1) % NUM_RX_DESC; | 
|  | } | 
|  |  | 
|  | #if 0 | 
|  | printf("Leaving inca_switch_recv()\n"); | 
|  | #endif | 
|  |  | 
|  | return length; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void inca_switch_halt(struct eth_device *dev) | 
|  | { | 
|  | #if 0 | 
|  | printf("Entered inca_switch_halt()\n"); | 
|  | #endif | 
|  |  | 
|  | #if 1 | 
|  | initialized = 0; | 
|  | #endif | 
|  | #if 1 | 
|  | /* Disable forwarding to the CPU port. | 
|  | */ | 
|  | SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf); | 
|  |  | 
|  | /* Close RxDMA channel. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF); | 
|  |  | 
|  | /* Close TxDMA channel. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_TXCCR0_OFF); | 
|  |  | 
|  |  | 
|  | #endif | 
|  | #if 0 | 
|  | printf("Leaving inca_switch_halt()\n"); | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | static void inca_init_switch_chip(void) | 
|  | { | 
|  | u32 regValue; | 
|  |  | 
|  | /* To workaround a problem with collision counter | 
|  | * (see Errata sheet). | 
|  | */ | 
|  | SW_WRITE_REG(INCA_IP_Switch_PC_TX_CTL, 0x00000001); | 
|  | SW_WRITE_REG(INCA_IP_Switch_LAN_TX_CTL, 0x00000001); | 
|  |  | 
|  | #if 1 | 
|  | /* init MDIO configuration: | 
|  | *	MDS (Poll speed):	0x01 (4ms) | 
|  | *	PHY_LAN_ADDR:		0x06 | 
|  | *	PHY_PC_ADDR:		0x05 | 
|  | *	UEP (Use External PHY): 0x00 (Internal PHY is used) | 
|  | *	PS (Port Select):	0x00 (PT/UMM for LAN) | 
|  | *	PT (PHY Test):		0x00 (no test mode) | 
|  | *	UMM (Use MDIO Mode):	0x00 (state machine is disabled) | 
|  | */ | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50); | 
|  |  | 
|  | /* init PHY: | 
|  | *	SL (Auto Neg. Speed for LAN) | 
|  | *	SP (Auto Neg. Speed for PC) | 
|  | *	LL (Link Status for LAN) | 
|  | *	LP (Link Status for PC) | 
|  | *	DL (Duplex Status for LAN) | 
|  | *	DP (Duplex Status for PC) | 
|  | *	PL (Auto Neg. Pause Status for LAN) | 
|  | *	PP (Auto Neg. Pause Status for PC) | 
|  | */ | 
|  | SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff); | 
|  |  | 
|  | /* MDIO_ACC: | 
|  | *	RA (Request/Ack)  0x01 (Request) | 
|  | *	RW (Read/Write)	  0x01 (Write) | 
|  | *	PHY_ADDR	  0x05 (PC) | 
|  | *	REG_ADDR	  0x00 (PHY_BCR: basic control register) | 
|  | *	PHY_DATA	  0x8000 | 
|  | *		      Reset		      - software reset | 
|  | *		      LB (loop back)	      - normal | 
|  | *		      SS (speed select)	      - 10 Mbit/s | 
|  | *		      ANE (auto neg. enable)  - enable | 
|  | *		      PD (power down)	      - normal | 
|  | *		      ISO (isolate)	      - normal | 
|  | *		      RAN (restart auto neg.) - normal | 
|  | *		      DM (duplex mode)	      - half duplex | 
|  | *		      CT (collision test)     - enable | 
|  | */ | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0a09000); | 
|  |  | 
|  | /* MDIO_ACC: | 
|  | *	RA (Request/Ack)  0x01 (Request) | 
|  | *	RW (Read/Write)	  0x01 (Write) | 
|  | *	PHY_ADDR	  0x06 (LAN) | 
|  | *	REG_ADDR	  0x00 (PHY_BCR: basic control register) | 
|  | *	PHY_DATA	  0x8000 | 
|  | *		      Reset		      - software reset | 
|  | *		      LB (loop back)	      - normal | 
|  | *		      SS (speed select)	      - 10 Mbit/s | 
|  | *		      ANE (auto neg. enable)  - enable | 
|  | *		      PD (power down)	      - normal | 
|  | *		      ISO (isolate)	      - normal | 
|  | *		      RAN (restart auto neg.) - normal | 
|  | *		      DM (duplex mode)	      - half duplex | 
|  | *		      CT (collision test)     - enable | 
|  | */ | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0c09000); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | /* Make sure the CPU port is disabled for now. We | 
|  | * don't want packets to get stacked for us until | 
|  | * we enable DMA and are prepared to receive them. | 
|  | */ | 
|  | SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf); | 
|  |  | 
|  | SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue); | 
|  |  | 
|  | /* CRC GEN is enabled. | 
|  | */ | 
|  | regValue |= 0x00000200; | 
|  | SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue); | 
|  |  | 
|  | /* ADD TAG is disabled. | 
|  | */ | 
|  | SW_READ_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue); | 
|  | regValue &= ~0x00000002; | 
|  | SW_WRITE_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void inca_dma_init(void) | 
|  | { | 
|  | /* Switch off all DMA channels. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF); | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR1, INCA_IP_DMA_DMA_RXCCR1_OFF); | 
|  |  | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF); | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR1, INCA_IP_DMA_DMA_TXCCR1_OFF); | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR2, INCA_IP_DMA_DMA_TXCCR2_OFF); | 
|  |  | 
|  | /* Setup TX channel polling time. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME); | 
|  |  | 
|  | /* Setup RX channel polling time. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME); | 
|  |  | 
|  | /* ERRATA: write reset value into the DMA RX IMR register. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF); | 
|  |  | 
|  | /* Just in case: disable all transmit interrupts also. | 
|  | */ | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXIMR, 0xFFFFFFFF); | 
|  |  | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXISR, 0xFFFFFFFF); | 
|  | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXISR, 0xFFFFFFFF); | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_INCA_IP_SWITCH_AMDIX) | 
|  | static int inca_amdix(void) | 
|  | { | 
|  | u32 phyReg1 = 0; | 
|  | u32 phyReg4 = 0; | 
|  | u32 phyReg5 = 0; | 
|  | u32 phyReg6 = 0; | 
|  | u32 phyReg31 = 0; | 
|  | u32 regEphy = 0; | 
|  | int mdi_flag; | 
|  | int retries; | 
|  |  | 
|  | /* Setup GPIO pins. | 
|  | */ | 
|  | *INCA_IP_AUTO_MDIX_LAN_PORTS_DIR    |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | 
|  | *INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | 
|  |  | 
|  | #if 0 | 
|  | /* Wait for signal. | 
|  | */ | 
|  | retries = WAIT_SIGNAL_RETRIES; | 
|  | while (--retries) { | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | 
|  | (0x1 << 31) |	/* RA		*/ | 
|  | (0x0 << 30) |	/* Read		*/ | 
|  | (0x6 << 21) |	/* LAN		*/ | 
|  | (17  << 16));	/* PHY_MCSR	*/ | 
|  | do { | 
|  | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1); | 
|  | } while (phyReg1 & (1 << 31)); | 
|  |  | 
|  | if (phyReg1 & (1 << 1)) { | 
|  | /* Signal detected */ | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!retries) | 
|  | goto Fail; | 
|  | #endif | 
|  |  | 
|  | /* Set MDI mode. | 
|  | */ | 
|  | *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | 
|  | mdi_flag = 1; | 
|  |  | 
|  | /* Wait for link. | 
|  | */ | 
|  | retries = WAIT_LINK_RETRIES; | 
|  | while (--retries) { | 
|  | udelay(LINK_RETRY_DELAY * 1000); | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | 
|  | (0x1 << 31) |	/* RA		*/ | 
|  | (0x0 << 30) |	/* Read		*/ | 
|  | (0x6 << 21) |	/* LAN		*/ | 
|  | (1   << 16));	/* PHY_BSR	*/ | 
|  | do { | 
|  | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1); | 
|  | } while (phyReg1 & (1 << 31)); | 
|  |  | 
|  | if (phyReg1 & (1 << 2)) { | 
|  | /* Link is up */ | 
|  | break; | 
|  | } else if (mdi_flag) { | 
|  | /* Set MDIX mode */ | 
|  | *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | 
|  | mdi_flag = 0; | 
|  | } else { | 
|  | /* Set MDI mode */ | 
|  | *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | 
|  | mdi_flag = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!retries) { | 
|  | goto Fail; | 
|  | } else { | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | 
|  | (0x1 << 31) |	/* RA		*/ | 
|  | (0x0 << 30) |	/* Read		*/ | 
|  | (0x6 << 21) |	/* LAN		*/ | 
|  | (1   << 16));	/* PHY_BSR	*/ | 
|  | do { | 
|  | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1); | 
|  | } while (phyReg1 & (1 << 31)); | 
|  |  | 
|  | /* Auto-negotiation / Parallel detection complete | 
|  | */ | 
|  | if (phyReg1 & (1 << 5)) { | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | 
|  | (0x1 << 31) |	/* RA		*/ | 
|  | (0x0 << 30) |	/* Read		*/ | 
|  | (0x6 << 21) |	/* LAN		*/ | 
|  | (31  << 16));	/* PHY_SCSR	*/ | 
|  | do { | 
|  | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg31); | 
|  | } while (phyReg31 & (1 << 31)); | 
|  |  | 
|  | switch ((phyReg31 >> 2) & 0x7) { | 
|  | case INCA_SWITCH_PHY_SPEED_10H: | 
|  | /* 10Base-T Half-duplex */ | 
|  | regEphy = 0; | 
|  | break; | 
|  | case INCA_SWITCH_PHY_SPEED_10F: | 
|  | /* 10Base-T Full-duplex */ | 
|  | regEphy = INCA_IP_Switch_EPHY_DL; | 
|  | break; | 
|  | case INCA_SWITCH_PHY_SPEED_100H: | 
|  | /* 100Base-TX Half-duplex */ | 
|  | regEphy = INCA_IP_Switch_EPHY_SL; | 
|  | break; | 
|  | case INCA_SWITCH_PHY_SPEED_100F: | 
|  | /* 100Base-TX Full-duplex */ | 
|  | regEphy = INCA_IP_Switch_EPHY_SL | INCA_IP_Switch_EPHY_DL; | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* In case of Auto-negotiation, | 
|  | * update the negotiated PAUSE support status | 
|  | */ | 
|  | if (phyReg1 & (1 << 3)) { | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | 
|  | (0x1 << 31) |	/* RA		*/ | 
|  | (0x0 << 30) |	/* Read		*/ | 
|  | (0x6 << 21) |	/* LAN		*/ | 
|  | (6   << 16));	/* PHY_ANER	*/ | 
|  | do { | 
|  | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg6); | 
|  | } while (phyReg6 & (1 << 31)); | 
|  |  | 
|  | /* We are Autoneg-able. | 
|  | * Is Link partner also able to autoneg? | 
|  | */ | 
|  | if (phyReg6 & (1 << 0)) { | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | 
|  | (0x1 << 31) |	/* RA		*/ | 
|  | (0x0 << 30) |	/* Read		*/ | 
|  | (0x6 << 21) |	/* LAN		*/ | 
|  | (4   << 16));	/* PHY_ANAR	*/ | 
|  | do { | 
|  | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg4); | 
|  | } while (phyReg4 & (1 << 31)); | 
|  |  | 
|  | /* We advertise PAUSE capab. | 
|  | * Does link partner also advertise it? | 
|  | */ | 
|  | if (phyReg4 & (1 << 10)) { | 
|  | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | 
|  | (0x1 << 31) |	/* RA		*/ | 
|  | (0x0 << 30) |	/* Read		*/ | 
|  | (0x6 << 21) |	/* LAN		*/ | 
|  | (5   << 16));	/* PHY_ANLPAR	*/ | 
|  | do { | 
|  | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg5); | 
|  | } while (phyReg5 & (1 << 31)); | 
|  |  | 
|  | /* Link partner is PAUSE capab. | 
|  | */ | 
|  | if (phyReg5 & (1 << 10)) { | 
|  | regEphy |= INCA_IP_Switch_EPHY_PL; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | /* Link is up */ | 
|  | regEphy |= INCA_IP_Switch_EPHY_LL; | 
|  |  | 
|  | SW_WRITE_REG(INCA_IP_Switch_EPHY, regEphy); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | Fail: | 
|  | printf("No Link on LAN port\n"); | 
|  | return -1; | 
|  | } | 
|  | #endif /* CONFIG_INCA_IP_SWITCH_AMDIX */ | 
|  |  | 
|  | #endif |