diff options
Diffstat (limited to 'roms/SLOF/lib/libbcm')
| -rw-r--r-- | roms/SLOF/lib/libbcm/Makefile | 53 | ||||
| -rw-r--r-- | roms/SLOF/lib/libbcm/bcm.code | 57 | ||||
| -rw-r--r-- | roms/SLOF/lib/libbcm/bcm.in | 20 | ||||
| -rw-r--r-- | roms/SLOF/lib/libbcm/bcm57xx.c | 3461 | ||||
| -rw-r--r-- | roms/SLOF/lib/libbcm/bcm57xx.h | 323 | 
5 files changed, 3914 insertions, 0 deletions
diff --git a/roms/SLOF/lib/libbcm/Makefile b/roms/SLOF/lib/libbcm/Makefile new file mode 100644 index 00000000..1aead4c5 --- /dev/null +++ b/roms/SLOF/lib/libbcm/Makefile @@ -0,0 +1,53 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008, 2013 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# *     IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ +	   -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) + +#CFLAGS += -O2 -I. -I../common -I$(TOP)/clients/net-snk/include -I$(TOP)/lib/libc/include -fno-builtin -ffreestanding -msoft-float -Wall -nostdinc + +LDFLAGS = -nostdlib + +TARGET = ../libbcm.a + + +all: $(TARGET) Makefile.dep + +SRCS =  bcm57xx.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) +	$(AR) -rc $@ $(OBJS) +	$(RANLIB) $@ + +clean: +	$(RM) $(TARGET) $(OBJS) + +distclean: clean +	$(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: +	$(RM) Makefile.dep +	$(MAKE) Makefile.dep + +Makefile.dep: Makefile +	$(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/roms/SLOF/lib/libbcm/bcm.code b/roms/SLOF/lib/libbcm/bcm.code new file mode 100644 index 00000000..308ebbaa --- /dev/null +++ b/roms/SLOF/lib/libbcm/bcm.code @@ -0,0 +1,57 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libbcm Forth wrapper + */ + +#include <bcm57xx.h> + +// : bcm57xx-open  ( -- false | [ driver true ] ) +PRIM(BCM57XX_X2d_OPEN) +{ +	net_driver_t *net_driver = bcm57xx_open(); +	if (net_driver) { +		PUSH; +		TOS.u = (unsigned long)net_driver; PUSH; +		TOS.n = -1; +	} else { +		PUSH; +		TOS.n = 0; +	} +} +MIRP + +// : bcm57xx-close  ( driver -- ) +PRIM(BCM57XX_X2d_CLOSE) +{ +	net_driver_t *driver = TOS.a; POP; +	bcm57xx_close(driver); +} +MIRP + + +// : bcm57xx-read  ( addr len -- actual ) +PRIM(BCM57XX_X2d_READ) +{ +	int len = TOS.u; POP; +	TOS.n = bcm57xx_read(TOS.a, len); +} +MIRP + +// : bcm57xx-write  ( addr len -- actual ) +PRIM(BCM57XX_X2d_WRITE) +{ +	int len = TOS.u; POP; +	TOS.n = bcm57xx_write(TOS.a, len); +} +MIRP diff --git a/roms/SLOF/lib/libbcm/bcm.in b/roms/SLOF/lib/libbcm/bcm.in new file mode 100644 index 00000000..ee50a6e6 --- /dev/null +++ b/roms/SLOF/lib/libbcm/bcm.in @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libbcm bindings for Forth - definitions + */ + +cod(BCM57XX-OPEN) +cod(BCM57XX-CLOSE) +cod(BCM57XX-READ) +cod(BCM57XX-WRITE) diff --git a/roms/SLOF/lib/libbcm/bcm57xx.c b/roms/SLOF/lib/libbcm/bcm57xx.c new file mode 100644 index 00000000..2ecb517f --- /dev/null +++ b/roms/SLOF/lib/libbcm/bcm57xx.c @@ -0,0 +1,3461 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * + ****************************************************************************** + * reference: + * Broadcom 57xx + * Host Programmer Interface Specification for the + * NetXtreme Family of Highly-Integrated Media Access Controlers + */ +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <byteorder.h> +#include <helpers.h> +#include <netdriver.h> +#include "bcm57xx.h" + +/* + * local defines + ****************************************************************************** + */ + + +// #define BCM_VLAN_TAG    ( (uint32_t) 0x1 ) + +// number of tx/rx rings +// NOTE: 5714 only uses 1 rx/tx ring, but memory +// for the other rings is cleaned anyways for +// sanity & future use +#define BCM_MAX_TX_RING         16 +#define BCM_MAX_RXRET_RING      16 +#define BCM_MAX_RXPROD_RCB       3 + +// bd descriptions +#define BCM_RXPROD_RING_SIZE     512    // don't change +#define BCM_RXRET_RING_SIZE	 512    // don't change +#define BCM_TX_RING_SIZE         512    // don't change +#define BCM_BUF_SIZE            1536    // don't change +#define BCM_MTU_MAX_LEN         1522 +#define BCM_MAX_RX_BUF            64 +#define BCM_MAX_TX_BUF            16 + +// number of MAC addresses in NIC +#define BCM_NUM_MAC_ADDR	   4 +#define BCM_NUM_MAC5704_ADDR	  12 +// offset of mac address field(s) in bcm register space +#define MAC5704_ADDR_OFFS	( (uint16_t) 0x0530 ) + +// offset of NIC memory start address from base address +#define BCM_MEMORY_OFFS         ( (uint64_t) 0x8000 ) + +// offset of statistics block in NIC memory +#define BCM_STATISTIC_OFFS	( (uint64_t) 0x0300 ) +// size of statistic block in NIC memory +#define BCM_STATISTIC_SIZE	0x800 + +// offsets of NIC rx/tx rings in NIC memory +#define BCM_NIC_TX_OFFS		( (uint16_t) 0x4000 ) +#define BCM_NIC_RX_OFFS		( (uint16_t) 0x6000 ) +#define BCM_NIC_TX_SIZE		( (uint16_t) ( ( BCM_TX_RING_SIZE * BCM_RCB_SIZE_u16 ) / 4 ) ) + +// device mailboxes +#define BCM_FW_MBX          	( (uint16_t) 0x0b50 ) +#define BCM_FW_MBX_CMD      	( (uint16_t) 0x0b78 ) +#define BCM_FW_MBX_LEN      	( (uint16_t) 0x0b7c ) +#define BCM_FW_MBX_DATA     	( (uint16_t) 0x0b80 ) +#define BCM_NICDRV_STATE_MBX	( (uint16_t) 0x0c04 ) + +// device mailbox commands +#define BCM_NICDRV_ALIVE	( (uint32_t) 0x00000001 ) +#define BCM_NICDRV_PAUSE_FW	( (uint32_t) 0x00000002 ) + +// device values +#define BCM_MAGIC_NUMBER           	( (uint32_t) 0x4b657654 ) + +// device states +#define NIC_FWDRV_STATE_START      	( (uint32_t) 0x00000001 ) +#define NIC_FWDRV_STATE_START_DONE 	( (uint32_t) 0x80000001 ) +#define NIC_FWDRV_STATE_UNLOAD     	( (uint32_t) 0x00000002 ) +#define NIC_FWDRV_STATE_UNLOAD_DONE	( (uint32_t) 0x80000002 ) +#define NIC_FWDRV_STATE_SUSPEND    	( (uint32_t) 0x00000004 ) + +// timer prescaler value +#define BCM_TMR_PRESCALE        ( (uint32_t) 0x41 ) + +// offset of transmit rcb's in NIC memory +#define BCM_TX_RCB_OFFS         ( (uint16_t) 0x0100 ) +// offset of receive return rcb's in NIC memory +#define BCM_RXRET_RCB_OFFS      ( (uint16_t) 0x0200 ) + +// register offsets for ring indices +#define TX_PROD_IND             ( (uint16_t) 0x0304 ) +#define TX_CONS_IND             ( (uint16_t) 0x3cc0 ) +#define RXPROD_PROD_IND         ( (uint16_t) 0x026c ) +#define RXPROD_CONS_IND         ( (uint16_t) 0x3c54 ) +#define RXRET_PROD_IND          ( (uint16_t) 0x3c80 ) +#define RXRET_CONS_IND          ( (uint16_t) 0x0284 ) +// NIC producer index only needed for initialization +#define TX_NIC_PROD_IND         ( (uint16_t) 0x0384 ) + +/* + * predefined register values used during initialization + * may be adapted by user + */ +#define DMA_RW_CTRL_VAL_5714    ( (uint32_t) 0x76144000 ) +#define DMA_RW_CTRL_VAL         ( (uint32_t) 0x760F0000 ) +#define TX_MAC_LEN_VAL          ( (uint32_t) 0x00002620 ) + +#define RX_LST_PLC_CFG_VAL      ( (uint32_t) 0x00000109 ) +#define RX_LST_PLC_STAT_EN_VAL  ( (uint32_t) 0x007e000f ) +#define NVM_ADDR_MSK            ( (uint32_t) 0x000fffff ) + +// Number of Receive Rules /w or /wo SOL enabled +#define RX_RULE_CFG_VAL		( (uint32_t) 0x00000008 ) +#define NUM_RX_RULE		( (uint32_t) 16 ) +#define NUM_RX_RULE_ASF		( (uint32_t) ( NUM_RX_RULE - 4 ) ) + +// RCB register offsets +#define BCM_RXPROD_RCB_JUM      ( (uint16_t) 0x2440 ) +#define BCM_RXPROD_RCB_STD      ( (uint16_t) 0x2450 ) +#define BCM_RXPROD_RCB_MIN      ( (uint16_t) 0x2460 ) + +// macros needed for new addressing method +#define BCM_RCB_HOSTADDR_HI_u16( rcb )	( (uint16_t) rcb + 0x00 ) +#define BCM_RCB_HOSTADDR_LOW_u16( rcb ) ( (uint16_t) rcb + 0x04 ) +#define BCM_RCB_LENFLAG_u16( rcb )      ( (uint16_t) rcb + 0x08 ) +#define BCM_RCB_NICADDR_u16( rcb )      ( (uint16_t) rcb + 0x0c ) +#define BCM_RCB_SIZE_u16		( (uint16_t) 0x0010 ) + +// RCB flags +#define RCB_FLAG_RING_DISABLED  BIT32( 1 ) + +// BCM device ID masks +#define BCM_DEV_5714   ( (uint64_t) 0x1 ) +#define BCM_DEV_5704   ( (uint64_t) 0x2 ) +#define BCM_DEV_5703   ( (uint64_t) 0x4 ) +#define BCM_DEV_SERDES ( (uint64_t) 0x80000000 ) +#define BCM_DEV_COPPER ( (uint64_t) 0x40000000 ) + +#define IS_5714        ( ( bcm_device_u64 & BCM_DEV_5714 ) != 0 ) +#define IS_5704        ( ( bcm_device_u64 & BCM_DEV_5704 ) != 0 ) +#define IS_5703        ( ( bcm_device_u64 & BCM_DEV_5703 ) != 0 ) +#define IS_SERDES      ( ( bcm_device_u64 & BCM_DEV_SERDES ) != 0 ) +#define IS_COPPER_PHY  ( ( bcm_device_u64 & BCM_DEV_COPPER ) != 0 ) + +#define BUFFERED_FLASH_PAGE_POS		9 +#define BUFFERED_FLASH_BYTE_ADDR_MASK	((<<BUFFERED_FLASH_PAGE_POS) - 1) +#define BUFFERED_FLASH_PAGE_SIZE	264 +#define BUFFERED_FLASH_PHY_SIZE		512 +#define MANUFACTURING_INFO_SIZE		140 +#define CRC32_POLYNOMIAL		0xEDB88320 + +/* + * local types + ****************************************************************************** + */ +typedef struct { +	uint32_t m_dev_u32; +	uint64_t m_devmsk_u64; +}	bcm_dev_t; + +/* + * BCM common data structures + * BCM57xx Programmer's Guide: Section 5 + */ + +/* + * 64bit host address in a way the NIC is able to understand it + */ +typedef struct { +	uint32_t m_hi_u32; +	uint32_t m_lo_u32; +}	bcm_addr64_t; +/* + * ring control block + */ +typedef struct { +	bcm_addr64_t m_hostaddr_st; +	uint32_t        m_lenflags_u32;	// upper 16b: len, lower 16b: flags +	uint32_t        m_nicaddr_u32; +}	bcm_rcb_t; + +/* + * tx buffer descriptor + */ +typedef struct { +	bcm_addr64_t m_hostaddr_st; +	uint32_t        m_lenflags_u32;	// upper 16b: len, lower 16b: flags +	uint32_t        m_VLANtag_u32;	// lower 16b: vtag +}       bcm_txbd_t; + +/* + * rx buffer descriptor + */ +typedef struct { +	bcm_addr64_t m_hostaddr_st; +	uint32_t        m_idxlen_u32;	// upper 16b: idx, lower 16b: len +	uint32_t        m_typeflags_u32;	// upper 16b: type, lower 16b: flags +	uint32_t        m_chksum_u32;	// upper 16b: ip, lower 16b: tcp/udp +	uint32_t        m_errvlan_u32;	// upper 16b: err, lower 16b: vlan tag +	uint32_t        m_reserved_u32; +	uint32_t        m_opaque_u32; +}	bcm_rxbd_t; + +/* + * bcm status block + * NOTE: in fact the status block is not used and configured + * so that it is not updated by the NIC. Still it has to be + * set up so the NIC is satisfied + */ +typedef struct { +	uint32_t   m_st_word_u32; +	uint32_t   m_st_tag_u32; +	uint16_t   m_rxprod_cons_u16; +	uint16_t   m_unused_u16; +	uint32_t   m_unused_u32; +	uint16_t   m_tx_cons_u16; +	uint16_t   m_rxret_prod_u16; +}	bcm_status_t; + +/* + * local constants + ****************************************************************************** + */ +static const bcm_dev_t bcm_dev[] = { +	{ 0x166b, BCM_DEV_5714  		}, +	{ 0x1668, BCM_DEV_5714  		}, +	{ 0x1669, BCM_DEV_5714  		}, +	{ 0x166a, BCM_DEV_5714			}, +	{ 0x1648, BCM_DEV_5704  		}, +	{ 0x1649, BCM_DEV_5704 | BCM_DEV_SERDES }, +	{ 0x16a8, BCM_DEV_5704 | BCM_DEV_SERDES }, +	{ 0x16a7, BCM_DEV_5703 | BCM_DEV_SERDES }, +	{ 0x16c7, BCM_DEV_5703 | BCM_DEV_SERDES }, +	{ 0     , 0             		} +}; + +/* + * local variables + ****************************************************************************** + */ +static uint64_t       bcm_device_u64; +static uint32_t       bcm_rxret_ring_sz; +static uint64_t       bcm_baseaddr_u64; +static uint64_t       bcm_memaddr_u64; + +/* + * rings & their buffers + */ +// the rings made of buffer descriptors +static bcm_txbd_t  bcm_tx_ring[BCM_TX_RING_SIZE]; +static bcm_rxbd_t  bcm_rxprod_ring[BCM_RXPROD_RING_SIZE]; +static bcm_rxbd_t  bcm_rxret_ring[BCM_RXRET_RING_SIZE*2]; + +// the buffers used in the rings +static uint8_t       bcm_tx_buffer_pu08[BCM_MAX_TX_BUF][BCM_BUF_SIZE]; +static uint8_t       bcm_rx_buffer_pu08[BCM_MAX_RX_BUF][BCM_BUF_SIZE]; + +// tx ring index of first/last bd +static uint32_t       bcm_tx_start_u32; +static uint32_t       bcm_tx_stop_u32; +static uint32_t       bcm_tx_bufavail_u32; + +/* + * status block + */ +static bcm_status_t bcm_status; + +/* + * implementation + ****************************************************************************** + */ + + +/* + * global functions + ****************************************************************************** + */ + + +/* + * local helper functions + ****************************************************************************** + */ +#if 0 +static char * +memcpy( char *dest, const char *src, size_t n ) +{ +        char *ret = dest; +        while( n-- ) { +                *dest++ = *src++; +        } + +        return( ret ); +} +#endif + +static char * +memset_ci( char *dest, int c, size_t n ) +{ +        char *ret = dest; +         +        while( n-- ) { +                wr08( dest, c ); +		dest++; +        } + +        return( ret ); +} + +#if 0 +static char * +memset( char *dest, int c, size_t n ) +{ +        char *ret = dest; +        while( n-- ) { +                *dest++ = (char) c; +        } + +        return( ret ); +} +#endif + +static uint32_t +bcm_nvram_logical_to_physical_address(uint32_t address) +{ +	uint32_t page_no   = address / BUFFERED_FLASH_PAGE_SIZE; +	uint32_t page_addr = address % BUFFERED_FLASH_PAGE_SIZE; + +	return (page_no << BUFFERED_FLASH_PAGE_POS) + page_addr; +} + +/* + * read/write functions to access NIC registers & memory + * NOTE: all functions are executed with cache inhibitation (dead slow :-) ) + */ +static uint32_t +bcm_read_mem32( uint16_t f_offs_u16 ) +{       // caution: shall only be used after initialization! +	return rd32( bcm_memaddr_u64 + (uint64_t) f_offs_u16 ); +} + +/* not used so far +static uint16_t +bcm_read_mem16( uint16_t f_offs_u16 ) +{       // caution: shall only be used after initialization! +	return rd16( bcm_memaddr_u64 + (uint64_t) f_offs_u16 ); +}*/ +/* not used so far +static uint8_t +bcm_read_mem08( uint16_t f_offs_u16 ) +{       // caution: shall only be used after initialization! +	return rd08( bcm_memaddr_u64 + (uint64_t) f_offs_u16 ); +}*/ + +static uint32_t +bcm_read_reg32_indirect( uint16_t f_offs_u16 ) +{       // caution: shall only be used after initialization! +	SLOF_pci_config_write32(REG_BASE_ADDR_REG, f_offs_u16); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        REG_BASE_ADDR_REG, +	                                        f_offs_u16 );*/ +	return bswap_32(SLOF_pci_config_read32(REG_DATA_REG)); +	/*return (uint32_t) bswap_32( snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                                                4, +	                                                                bcm_pcicfg_bus, +	                                                                bcm_pcicfg_devfn, +	                                                                REG_DATA_REG ) ) ;*/ +} + +static uint32_t +bcm_read_reg32( uint16_t f_offs_u16 ) +{       // caution: shall only be used after initialization! +	if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400) +		return bcm_read_reg32_indirect( f_offs_u16 + 0x5600 ); +	return rd32( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +} + +static uint16_t +bcm_read_reg16( uint16_t f_offs_u16 ) +{       // caution: shall only be used after initialization! +	return rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +} +/* not used so far +static uint8_t +bcm_read_reg08( uint16_t f_offs_u16 ) +{       // caution: shall only be used after initialization! +	return rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +}*/ + +static void +bcm_write_mem32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{       // caution: shall only be used after initialization! +	SLOF_pci_config_write32(MEM_BASE_ADDR_REG, f_offs_u16); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        MEM_BASE_ADDR_REG, +	                                        f_offs_u16 );*/ +	SLOF_pci_config_write32(MEM_DATA_REG, bswap_32(f_val_u32)); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        MEM_DATA_REG, +	                                        bswap_32 ( f_val_u32 ) );*/ +} + +static void +bcm_write_mem32( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{       // caution: shall only be used after initialization! +	if(f_offs_u16 >= BCM_RXRET_RCB_OFFS && +           f_offs_u16 < BCM_RXRET_RCB_OFFS + (BCM_MAX_RXRET_RING*BCM_RCB_SIZE_u16)) +		bcm_write_mem32_indirect( f_offs_u16, f_val_u32 ); +	else if(f_offs_u16 >= BCM_TX_RCB_OFFS && +           f_offs_u16 < BCM_TX_RCB_OFFS + (BCM_MAX_TX_RING*BCM_RCB_SIZE_u16)) +		bcm_write_mem32_indirect( f_offs_u16, f_val_u32 ); +	else +		wr32( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u32 ); +} +/* not used so far +static void +bcm_write_mem16( uint16_t f_offs_u16, uint16_t f_val_u16 ) +{       // caution: shall only be used after initialization! +	wr16( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 ); +}*/ +/* not used so far +static void +bcm_write_mem08( uint16_t f_offs_u16, uint8_t f_val_u08 ) +{       // caution: shall only be used after initialization! +	wr08( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_write_reg32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{       // caution: shall only be used after initialization! +	SLOF_pci_config_write32(REG_BASE_ADDR_REG, f_offs_u16); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        REG_BASE_ADDR_REG, +	                                        f_offs_u16 );*/ +	SLOF_pci_config_write32(REG_DATA_REG, bswap_32(f_val_u32)); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        REG_DATA_REG, +	                                        bswap_32 ( f_val_u32 ) );*/ +} + +static void +bcm_write_reg32( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{       // caution: shall only be used after initialization! +	if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400) +		bcm_write_reg32_indirect( f_offs_u16 + 0x5600, f_val_u32 ); +	else +		wr32( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u32 ); +} + +static void +bcm_write_reg16( uint16_t f_offs_u16, uint16_t f_val_u16 ) +{       // caution: shall only be used after initialization! +	wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 ); +} +/* not used so far +static void +bcm_write_reg08( uint16_t f_offs_u16, uint8_t f_val_u08 ) +{       // caution: shall only be used after initialization! +        wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_setb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 ) +{ +	uint32_t v; + +	v  = bcm_read_reg32( f_offs_u16 ); +	v |= f_mask_u32; +	bcm_write_reg32( f_offs_u16, v ); +} +/* not used so far +static void +bcm_setb_reg16( uint16_t f_offs_u16, uint16_t f_mask_u16 ) +{ +	uint16_t v; +	v  = rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +        v |= f_mask_u16; +	wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ +/* not used so far +static void +bcm_setb_reg08( uint16_t f_offs_u16, uint8_t f_mask_u08 ) +{ +	uint8_t v; +	v  = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +        v |= f_mask_u08; +	wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clrb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 ) +{ +	uint32_t v; + +	v  = bcm_read_reg32( f_offs_u16 ); +	v &= ~f_mask_u32; +	bcm_write_reg32( f_offs_u16, v ); +} + +static void +bcm_clrb_reg16( uint16_t f_offs_u16, uint16_t f_mask_u16 ) +{ +	uint16_t v; + +	v  = bcm_read_reg16( f_offs_u16 ); +	v &= ~f_mask_u16; +	bcm_write_reg16( f_offs_u16, v ); +} +/* not used so far +static void +bcm_clrb_reg08( uint16_t f_offs_u16, uint8_t f_mask_u08 ) +{ +	uint8_t v; +	v  = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +        v &= ~f_mask_u32; +	wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clr_wait_bit32( uint16_t r, uint32_t b ) +{ +	uint32_t i; + +	bcm_clrb_reg32( r, b ); + +	i = 1000; +	while( --i ) { + +		if( ( bcm_read_reg32( r ) & b ) == 0 ) { +			break; +		} + +		SLOF_usleep( 10 ); +	} +#ifdef BCM_DEBUG +	if( ( bcm_read_reg32( r ) & b ) != 0 ) { +		printf( "bcm57xx: bcm_clear_wait_bit32 failed (0x%04X)!\n", r ); +	} +#endif +} + +/* + * (g)mii bus access + */ +#if 0 +// not used so far +static int32_t +bcm_mii_write16( uint32_t f_reg_u32, uint16_t f_value_u16 ) +{ +	static const uint32_t WR_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 26 ) ); +	int32_t              l_autopoll_i32 = 0; +	uint32_t              l_wrval_u32; +	uint32_t              i; + +	/* +	 * only 0x00-0x1f are valid registers +	 */ +	if( f_reg_u32 > (uint32_t) 0x1f ) { +		return -1; +	} + +	/* +	 * disable auto polling if enabled +	 */ +	if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { +		l_autopoll_i32 = (int32_t) !0; +		bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); +		SLOF_usleep( 40 ); +	} + +	/* +	 * construct & write mi com register value +	 */ +	l_wrval_u32 = ( WR_VAL | ( f_reg_u32 << 16 ) | (uint32_t) f_value_u16 ); +	bcm_write_reg32( MI_COM_R, l_wrval_u32 ); + +	/* +	 * wait for transaction to complete +	 */ +	i = 25; +	while( ( --i ) && +	       ( ( bcm_read_reg32( MI_COM_R ) & BIT32( 29 ) ) != 0 ) ) { +		SLOF_usleep( 10 ); +	} + +	/* +	 * re-enable auto polling if necessary +	 */ +	if( l_autopoll_i32 ) { +		bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) ); +	} + +	// return on error +	if( i == 0 ) { +		return -1; +	} + +	return 0; +} +#endif + +static int32_t +bcm_mii_read16( uint32_t f_reg_u32, uint16_t *f_value_pu16 ) +{ +	static const uint32_t RD_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 27 ) ); +	int32_t l_autopoll_i32 = 0; +	uint32_t l_rdval_u32; +	uint32_t i; +	uint16_t first_not_busy; + +	/* +	 * only 0x00-0x1f are valid registers +	 */ +	if( f_reg_u32 > (uint32_t) 0x1f ) { +		return -1; +	} + +	/* +	 * disable auto polling if enabled +	 */ +	if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { +		l_autopoll_i32 = ( int32_t ) !0; +		bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); +		SLOF_usleep( 40 ); +	} + +	/* +	 * construct & write mi com register value +	 */ +	l_rdval_u32 = ( RD_VAL | ( f_reg_u32 << 16 ) ); +	bcm_write_reg32( MI_COM_R, l_rdval_u32 ); + +	/* +	 * wait for transaction to complete +	 * ERRATA workaround: must read two "not busy" states to indicate transaction complete +	 */ +	i = 25; +	first_not_busy = 0; +	l_rdval_u32 = bcm_read_reg32( MI_COM_R ); +	while( ( --i ) && +	       ( (first_not_busy == 0) || ( ( l_rdval_u32 & BIT32( 29 ) ) != 0 ) ) ) { +                /* Is this the first clear BUSY state? */ +		if ( ( l_rdval_u32 & BIT32( 29 ) ) == 0 ) +			first_not_busy++; +		SLOF_usleep( 10 ); +		l_rdval_u32 = bcm_read_reg32( MI_COM_R ); +	} + +	/* +	 * re-enable autopolling if necessary +	 */ +	if( l_autopoll_i32 ) { +		bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) ); +	} + +	/* +	 * return on read transaction error +	 * (check read failed bit) +	 */ +	if( ( i == 0 ) || +	    ( ( l_rdval_u32 & BIT32( 28 ) ) != 0 ) ) { +		return -1; +	} + +	/* +	 * return read value +	 */ +	*f_value_pu16 = (uint16_t) ( l_rdval_u32 & (uint32_t) 0xffff ); + +	return 0; +} + +/* + * ht2000 dump (not complete) + */ +#if 0 +static void +bcm_dump( void ) +{ +	uint32_t i, j; + +	printf( "*** DUMP ***********************************************************************\n\n" ); + +	printf( "* PCI Configuration Registers:\n" ); +	for( i = 0, j = 0; i < 0x40; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Private PCI Configuration Registers:\n" ); +	for( i = 0x68, j = 0; i < 0x88; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* VPD Config:\n" ); +	printf( "%04X: %08X  \n", 0x94, bcm_read_reg32( 0x94 ) ); + +	printf( "\n* Dual MAC Control Registers:\n" ); +	for( i = 0xb8, j = 0; i < 0xd0; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Ethernet MAC Control Registers:\n" ); +	for( i = 0x400, j = 0; i < 0x590; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Send Data Initiator Control:\n" ); +	for( i = 0xc00, j = 0; i < 0xc10; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Send Data Completion Control:\n" ); +	printf( "%04X: %08X  ", 0x1000, bcm_read_reg32( 0x1000 ) ); +	printf( "%04X: %08X  \n", 0x1008, bcm_read_reg32( 0x1008 ) ); +	 +	printf( "\n* Send BD Ring Selector Control:\n" ); +	printf( "%04X: %08X  ", 0x1400, bcm_read_reg32( 0x1400 ) ); +	printf( "%04X: %08X  ", 0x1404, bcm_read_reg32( 0x1404 ) ); +	printf( "%04X: %08X  \n", 0x1408, bcm_read_reg32( 0x1408 ) ); + +	printf( "\n* Send BD Initiator Control:\n" ); +	printf( "%04X: %08X  ", 0x1800, bcm_read_reg32( 0x1800 ) ); +	printf( "%04X: %08X  \n", 0x1804, bcm_read_reg32( 0x1804 ) ); + +	printf( "\n* Send BD Completion Control:\n" ); +	printf( "%04X: %08X  ", 0x1c00, bcm_read_reg32( 0x1c00 ) ); + +	printf( "\n* Receive List Placement Control:\n" ); +	for( i = 0x2000, j = 0; i < 0x2020; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Receive Data & Receive BD Initiator Control:\n" ); +	printf( "%04X: %08X  ", 0x2400, bcm_read_reg32( 0x2400 ) ); +	printf( "%04X: %08X  \n", 0x2404, bcm_read_reg32( 0x2404 ) ); + +	printf( "\n* Jumbo Receive BD Ring RCB:\n" ); +	for( i = 0x2440, j = 0; i < 0x2450; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Standard Receive BD Ring RCB:\n" ); +	for( i = 0x2450, j = 0; i < 0x2460; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Mini Receive BD Ring RCB:\n" ); +	for( i = 0x2460, j = 0; i < 0x2470; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\nRDI Timer Mode Register:\n" ); +	printf( "%04X: %08X  \n", 0x24f0, bcm_read_reg32( 0x24f0 ) ); + +	printf( "\n* Receive BD Initiator Control:\n" ); +	for( i = 0x2c00, j = 0; i < 0x2c20; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} + +	printf( "\n* Receive BD Completion Control:\n" ); +	for( i = 0x3000, j = 0; i < 0x3014; i += 4 ) { + +		printf( "%04X: %08X  ", i, bcm_read_reg32( i ) ); + +		if( ( ++j & 0x3 ) == 0 ) { +			printf( "\n" ); +		} + +	} +} +#endif + + + +/* + * NVRAM access + */ + +static int +bcm_nvram_lock( void ) +{ +	int i; + +	/* +	 * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) +	 */ +//	bcm_setb_reg32( SW_ARB_R, BIT32( 0 ) ); +	bcm_setb_reg32( SW_ARB_R, BIT32( 1 ) ); + +	i = 2000; +	while( ( --i ) &&  +//	       ( bcm_read_reg32( SW_ARB_R ) & BIT32( 8 ) ) == 0 ) { +	       ( bcm_read_reg32( SW_ARB_R ) & BIT32( 9 ) ) == 0 ) { +		SLOF_msleep( 1 ); +	} + +	// return on error +	if( i == 0 ) { +#ifdef BCM_DEBUG +		printf("bcm57xx: failed to lock nvram"); +#endif +		return -1; +	} + +	return 0; +} + +static void +bcm_nvram_unlock( void ) +{ +	/* +	 * release NVRam lock (CLR0) +	 */ +//	bcm_setb_reg32( SW_ARB_R, BIT32( 4 ) ); +	bcm_setb_reg32( SW_ARB_R, BIT32( 5 ) ); +} + +static void +bcm_nvram_init( void ) +{ +	/* +	 * enable access to NVRAM registers +	 */ +	if(IS_5714) { +		bcm_setb_reg32( NVM_ACC_R, BIT32( 1 ) | BIT32( 0 ) ); +	} + +	/* +	 * disable bit-bang method 19& disable interface bypass +	 */ +	bcm_clrb_reg32( NVM_CFG1_R, BIT32( 31 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 14 ) | BIT32( 16 ) ); +	bcm_setb_reg32( NVM_CFG1_R, BIT32 ( 13 ) | BIT32 ( 17 )); + +	/* +	 * enable Auto SEEPROM Access +	 */ +	bcm_setb_reg32( MISC_LOCAL_CTRL_R, BIT32 ( 24 ) ); + +	/* +	 * NVRAM write enable +	 */ +	bcm_setb_reg32( MODE_CTRL_R, BIT32 ( 21 ) ); +} + +static int32_t +bcm_nvram_read( uint32_t f_addr_u32, uint32_t *f_val_pu32, uint32_t lock ) +{ +	uint32_t i; + +	/* +	 * parameter check +	 */ +	if( f_addr_u32 > NVM_ADDR_MSK ) { +		return -1; +	} + +	/* +	 * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) +	 */ +	if( lock && (bcm_nvram_lock() == -1) ) { +		return -1; +	} + +	/* +	 * setup address to read +	 */ +	bcm_write_reg32( NVM_ADDR_R, +		bcm_nvram_logical_to_physical_address(f_addr_u32) ); +//	bcm_write_reg32( NVM_ADDR_R, f_addr_u32 ); + +	/* +	 * get the command going +	 */ +	bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) | +	                            BIT32( 4 ) | BIT32( 3 ) ); + +	/* +	 * wait for command completion +	 */ +	i = 2000; +        while( ( --i ) && +               ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) { +		SLOF_msleep( 1 ); +	} + +	/* +	 * read back data if no error +	 */ +	if( i != 0 ) { +		/* +		 * read back data +		 */ +		*f_val_pu32 = bcm_read_reg32( NVM_READ_R ); +	} + +	if(lock) +		bcm_nvram_unlock(); + +	// error +	if( i == 0 ) { +#ifdef BCM_DEBUG +		printf("bcm57xx: reading from NVRAM failed\n"); +#endif +		return -1; +	} + +	// success +	return 0; +} + +static int32_t +bcm_nvram_write( uint32_t f_addr_u32, uint32_t f_value_u32, uint32_t lock ) +{ +	uint32_t i; + +	/* +	 * parameter check +	 */ +	if( f_addr_u32 > NVM_ADDR_MSK ) { +		return -1; +	} + +	/* +	 * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) +	 */ +	if( lock && (bcm_nvram_lock() == -1) ) { +			return -1; +	} + +	/* +	 * setup address to write +	 */ +	bcm_write_reg32( NVM_ADDR_R, bcm_nvram_logical_to_physical_address( f_addr_u32 ) ); + +	/* +	 * setup write data +	 */ +	bcm_write_reg32( NVM_WRITE_R, f_value_u32 ); + +	/* +	 * get the command going +	 */ +	bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) | +	                            BIT32( 5 ) | BIT32( 4 ) | BIT32( 3 ) ); + +	/* +	 * wait for command completion +	 */ +	i = 2000; +	while( ( --i ) && +	       ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) { +		SLOF_msleep( 1 ); +	} + +	/* +	 * release NVRam lock (CLR0) +	 */ +	if(lock) +		bcm_nvram_unlock(); + +	// error +	if( i == 0 ) { +#ifdef BCM_DEBUG +		printf("bcm57xx: writing to NVRAM failed\n"); +#endif +		return -1; +	} + +	// success +	return 0; +} + +/* + * PHY initialization + */ +static int32_t +bcm_mii_phy_init( void ) +{ +	static const uint32_t PHY_STAT_R   = (uint32_t) 0x01; +	static const uint32_t AUX_STAT_R   = (uint32_t) 0x19; +	static const uint32_t MODE_GMII    = BIT32( 3 ); +	static const uint32_t MODE_MII     = BIT32( 2 ); +	static const uint32_t NEG_POLARITY = BIT32( 10 ); +	static const uint32_t MII_MSK      = ( MODE_GMII | MODE_MII ); +	static const uint16_t GIGA_ETH     = ( BIT16( 10 ) | BIT16( 9 ) ); +	int32_t i; +	uint16_t v; + +	/* +	 * enable MDI communication +	 */ +	bcm_write_reg32( MDI_CTRL_R, (uint32_t) 0x0 ); + +	/* +	 * check link up +	 */ +	i = 2500; +	do { +		SLOF_msleep( 1 ); +		// register needs to be read twice! +		bcm_mii_read16( PHY_STAT_R, &v ); +		bcm_mii_read16( PHY_STAT_R, &v ); +	} while( ( --i ) && +		 ( ( v & BIT16( 2 ) ) == 0 ) ); + +	if( i == 0 ) { +#ifdef BCM_DEBUG	 +		printf( "bcm57xx: link is down\n" ); +#endif +		return -1; +	} + +#ifdef BCM_DEBUG	 +	printf( "bcm57xx: link is up\n" ); +#endif +	if( !IS_COPPER_PHY ) { +		return 0; +	} + +	/* +	 * setup GMII or MII interface +	 */ +	i = bcm_read_reg32( ETH_MAC_MODE_R ); +	/* +	 * read status register twice, since the first +	 * read fails once between here and the moon... +	 */ +	bcm_mii_read16( AUX_STAT_R, &v ); +	bcm_mii_read16( AUX_STAT_R, &v ); + +	if( ( v & GIGA_ETH ) == GIGA_ETH ) { +#ifdef BCM_DEBUG	 +	printf( "bcm57xx: running PHY in GMII mode (1000BaseT)\n" ); +#endif +		// GMII device +		if( ( i & MII_MSK ) != MODE_GMII ) { +			i &= ~MODE_MII; +			i |=  MODE_GMII; +		} + +	} else { +#ifdef BCM_DEBUG	 +	printf( "bcm57xx: running PHY in MII mode (10/100BaseT)\n" ); +#endif +		// MII device +		if( ( i & MII_MSK ) != MODE_MII ) { +			i &= ~MODE_GMII; +			i |=  MODE_MII; +		} + +	} + +	if( IS_5704 && !IS_SERDES ) { +#ifdef BCM_DEBUG	 +		printf( "bcm57xx: set the link ready signal for 5704C to negative polarity\n" ); +#endif +		i |= NEG_POLARITY; // set the link ready signal for 5704C to negative polarity +	} + +	bcm_write_reg32( ETH_MAC_MODE_R, i ); + +	return 0; +} + +static int32_t +bcm_tbi_phy_init( void ) +{ +	int32_t i; +#if 0 +	/* +	 * set TBI mode full duplex +	 */ +	bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 1 ) ); +	bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) ); + +	/* +	 * enable MDI communication +	 */ +	bcm_write_reg32( MDI_CTRL_R, (uint32_t) 0x0 ); + +	/* Disable link change interrupt.  */ +	bcm_write_reg32( ETH_MAC_EVT_EN_R, 0 ); + +	/* +	 * set link polarity +	 */ +	bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 10 ) ); + +	/* +	 * wait for sync/config changes +	 */ +	for( i = 0; i < 100; i++ ) { +		bcm_write_reg32( ETH_MAC_STAT_R, +				 BIT32( 3 ) | BIT32( 4 ) ); + +		SLOF_usleep( 20 ); + +		if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & +		    ( BIT32( 3 ) | BIT32( 4 ) ) ) == 0 ) { +			break; +		} + +	} +#endif +	/* +	 * wait for sync to come up +	 */ +	for( i = 0; i < 100; i++ ) { + +		if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) != 0 ) { +			break; +		} + +		SLOF_usleep( 20 );  +	} + +	if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0) { +#ifdef BCM_DEBUG	 +		printf( "bcm57xx: link is down\n" ); +#endif +		return -1; +	} +#if 0 +	/* +	 * clear all attentions +	 */ +	bcm_write_reg32( ETH_MAC_STAT_R, (uint32_t) ~0 ); +#endif + +#ifdef BCM_DEBUG	 +	printf( "bcm57xx: link is up\n" ); +#endif +	return 0; +} + +static int32_t +bcm_phy_init( void ) +{ +	static const uint16_t SRAM_HW_CFG = (uint16_t) 0x0b58; +	uint32_t l_val_u32; +	int32_t l_ret_i32 = 0; + +	/* +         * get HW configuration from SRAM +	 */ +	l_val_u32  = bcm_read_mem32( SRAM_HW_CFG ); +	l_val_u32 &= ( BIT32( 5 ) | BIT32( 4 ) ); + +	switch( l_val_u32 ) { +		case 0x10: { +			#ifdef BCM_DEBUG +			printf( "bcm57xx: copper PHY detected\n" ); +			#endif + +			bcm_device_u64 |= BCM_DEV_COPPER; +			l_ret_i32       = bcm_mii_phy_init(); +		} break; + +		case 0x20: { +			#ifdef BCM_DEBUG +			printf( "bcm57xx: fiber PHY detected\n" ); +			#endif + +			if( !IS_SERDES ) { +				#ifdef BCM_DEBUG +				printf( "bcm57xx: running PHY in gmii/mii mode\n" ); +				#endif +				l_ret_i32 = bcm_mii_phy_init(); +			} else { +				#ifdef BCM_DEBUG +				printf( "bcm57xx: running PHY in tbi mode\n" ); +				#endif +				l_ret_i32 = bcm_tbi_phy_init(); +			} + +		} break; + +		default: { +			#ifdef BCM_DEBUG +			printf( "bcm57xx: unknown PHY type detected, terminating\n" ); +			#endif +			l_ret_i32 = -1; +		} + +	} + +	return l_ret_i32; +} + +/* + * ring initialization + */ +static void +bcm_init_rxprod_ring( void ) +{ +	uint32_t      v; +	uint32_t      i; + +	/* +	 * clear out the whole rx prod ring for sanity +	 */ +	memset( (void *) &bcm_rxprod_ring, +		0, +		BCM_RXPROD_RING_SIZE * sizeof( bcm_rxbd_t ) ); +	mb(); + +	/* +	 * assign buffers & indices to the ring members +	 */ +	for( i = 0; i < BCM_MAX_RX_BUF; i++ ) { +		bcm_rxprod_ring[i].m_hostaddr_st.m_hi_u32 = +			(uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] >> 32 ); +		bcm_rxprod_ring[i].m_hostaddr_st.m_lo_u32 = +			(uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] & +			          (uint64_t) 0xffffffff ); +		bcm_rxprod_ring[i].m_idxlen_u32  = ( i << 16 ); +		bcm_rxprod_ring[i].m_idxlen_u32 += BCM_BUF_SIZE; +	} + +	/* +	 * clear rcb registers & disable rings +	 * NOTE: mini & jumbo rings are not supported, +	 * still rcb's are cleaned out for sanity +	 */ +	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_JUM ), 0 ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 ); +	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_JUM ), 0 ); + +	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_STD ), 0 ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 ); +	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_STD ), 0 ); + +	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_MIN ), 0 ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 ); +	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_MIN ), 0 ); + +	/* +	 * clear rx producer index of std producer ring +	 */ +	bcm_write_reg32( RXPROD_PROD_IND, 0 ); + +	/* +	 * setup rx standard rcb using recommended NIC addr (hard coded) +	 */ +	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), +			 (uint32_t) ( (uint64_t) &bcm_rxprod_ring >> 32 ) ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), +		         (uint32_t) ( (uint64_t) &bcm_rxprod_ring & (uint64_t) 0xffffffff ) ); +	bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), +			 (uint32_t) BCM_NIC_RX_OFFS ); + +	if( IS_5704 || IS_5703 ) { +		// 5704: length field = max buffer len +		v = (uint32_t) BCM_BUF_SIZE << 16; +	} else { +		// 5714: length field = number of ring entries +		v = (uint32_t) BCM_RXPROD_RING_SIZE << 16; +	} + +	v &= (uint32_t) ~RCB_FLAG_RING_DISABLED; +	bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), v ); +} + +static void +bcm_init_rxret_ring( void ) +{ +	uint32_t      i; +	uint16_t      v; + +	/* +	 * clear out the whole rx ret ring for sanity +	 */ +	memset( (void *) &bcm_rxret_ring, +		0, +		2 * BCM_RXRET_RING_SIZE * sizeof( bcm_rxbd_t ) ); +	mb(); + +	/* +	 * setup return ring size dependent on installed device +	 */ +	bcm_rxret_ring_sz = BCM_RXRET_RING_SIZE; +	if( IS_5704 || IS_5703 ) { +		bcm_rxret_ring_sz *= 2; +	} + +        /* +	 * clear rcb memory & disable rings +	 * NOTE: 5714 only supports one return ring, +	 * still all possible rcb's are cleaned out for sanity +	 */ +	v = BCM_RXRET_RCB_OFFS; +	for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) { +		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); +		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 ); + +		v += BCM_RCB_SIZE_u16; +        } + +	/* +	 * clear rx consumer index of return ring +	 */ +	bcm_write_reg32( RXRET_CONS_IND, 0 ); + +	/* +	 * setup rx ret rcb +	 * NOTE: NIC address not aplicable in return rings +	 */ +	bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXRET_RCB_OFFS ), +	                 (uint32_t) ( (uint64_t) &bcm_rxret_ring >> 32 ) ); +	bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXRET_RCB_OFFS ), +	                 (uint32_t) ( (uint64_t) &bcm_rxret_ring  & +				   (uint64_t) 0xffffffff ) ); +	bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_RXRET_RCB_OFFS ), 0 ); + +	i   = bcm_rxret_ring_sz; +	i <<= 16; +	i  &= (uint32_t) ~RCB_FLAG_RING_DISABLED; +	bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXRET_RCB_OFFS ), i ); +} + +static void +bcm_init_tx_ring( void ) +{ +	uint32_t      i; +	uint16_t	   v; + +	/* +	 * clear out the whole tx ring for sanity +	 */ +	memset( (void *) &bcm_tx_ring, +		0, +		BCM_TX_RING_SIZE * sizeof( bcm_txbd_t ) ); +	mb(); + +        /* +	 * assign buffers to the ring members & setup invariant flags +	 */ +        for( i = 0; i < BCM_MAX_TX_BUF; i++ ) { +		bcm_tx_ring[i].m_hostaddr_st.m_hi_u32 = +			(uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] >> 32 ); +		bcm_tx_ring[i].m_hostaddr_st.m_lo_u32 = +			(uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] & +			          (uint64_t) 0xffffffff ); +		// flags: indicate last packet & coal now +		// -last packet is always true (only one send packet supported) +		// -coal now needed to always get the consumed bd's (since +		//  only a few bd's are set up which permanently are recycled) +		bcm_tx_ring[i].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) ); +		bcm_tx_ring[i].m_VLANtag_u32  = (uint32_t) 0;	// not used +        } + +        /* +	 * clear rcb memory & disable rings +	 * NOTE: 5714 only supports one send ring, +	 * still all possible rcb's are cleaned out for sanity +	 */ +        v = BCM_TX_RCB_OFFS; +	for( i = 0; i < BCM_MAX_TX_RING; i++ ) { +		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); +		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 ); + +		v += BCM_RCB_SIZE_u16; +	} + +	/* +	 * clear host/nic producer indices +	 */ +	bcm_write_reg32( TX_NIC_PROD_IND, 0 ); +	bcm_write_reg32( TX_PROD_IND, 0 ); + +	/* +	 * setup tx rcb using recommended NIC addr (hard coded) +	 */ +	bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_TX_RCB_OFFS ), +			          (uint32_t) ( (uint64_t) &bcm_tx_ring >> 32 ) ); +	bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_TX_RCB_OFFS ), +			          (uint32_t) ( (uint64_t) &bcm_tx_ring & +				            (uint64_t) 0xffffffff ) ); +	bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_TX_RCB_OFFS ), +			          (uint32_t) BCM_NIC_TX_OFFS ); + +	if( IS_5704 || IS_5703 ) { +		// 5704: length field = max buffer len +		i = (uint32_t) BCM_BUF_SIZE << 16; +	} else { +		// 5714: length field = number of ring entries +		i = (uint32_t) BCM_TX_RING_SIZE << 16; +	} + +	i &= ( uint32_t ) ~RCB_FLAG_RING_DISABLED; +	bcm_write_mem32( BCM_RCB_LENFLAG_u16( BCM_TX_RCB_OFFS ), i ); + +	/* +	 * remember the next bd index to be used +	 * & number of available buffers +	 */ +	bcm_tx_stop_u32     = BCM_MAX_TX_BUF; +	bcm_tx_bufavail_u32 = BCM_MAX_TX_BUF; +} + +static int32_t +bcm_mac_init( uint8_t *f_mac_pu08 ) +{ +	static const uint16_t MEM_MAC_LO = (uint16_t) 0x0c18; +	static const uint16_t MEM_MAC_HI = (uint16_t) 0x0c14; + +	uint32_t              NVR_MAC_LO = (uint16_t) 0x80; +	uint32_t              NVR_MAC_HI = (uint16_t) 0x7c; + +	bcm_addr64_t       l_mac_st; +	uint32_t              i; +	uint32_t              v; + +	/* +	 * Use MAC address from device tree if possible +	 */ +	for( i = 0, v = 0; i < 6; i++ ) { +		v += (uint32_t) f_mac_pu08[i]; +	} + +	if( v != 0 ) { +		l_mac_st.m_hi_u32  = ( ( (uint32_t) f_mac_pu08[0]) <<  8 ); +		l_mac_st.m_hi_u32 |= ( ( (uint32_t) f_mac_pu08[1]) <<  0 ); +		l_mac_st.m_lo_u32  = ( ( (uint32_t) f_mac_pu08[2]) << 24 ); +		l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[3]) << 16 ); +		l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[4]) <<  8 ); +		l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[5]) <<  0 ); +	} else { +		/* +		 * try to read MAC address from MAC mailbox +		 */ +		l_mac_st.m_hi_u32 = bcm_read_mem32( MEM_MAC_HI ); + +		if( ( l_mac_st.m_hi_u32 >> 16 ) == (uint32_t) 0x484b ) { +			l_mac_st.m_hi_u32 &= (uint32_t) 0xffff; +			l_mac_st.m_lo_u32  = bcm_read_mem32( MEM_MAC_LO ); +		} else { +			int32_t l_err_i32; + +			/* +			 * otherwise retrieve MAC address from NVRam +			 */ +			if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) != 0 ) { +				// secondary MAC is in use, address in NVRAM changes +				NVR_MAC_LO += 0x50; +				NVR_MAC_HI += 0x50; +			} +		 +			l_err_i32  = bcm_nvram_read( NVR_MAC_LO, &l_mac_st.m_lo_u32, 1 ); +			l_err_i32 += bcm_nvram_read( NVR_MAC_HI, &l_mac_st.m_hi_u32, 1 ); + +			// return on read error +			if( l_err_i32 < 0 ) { +#ifdef BCM_DEBUG +				printf( "bcm57xx: failed to retrieve MAC address\n" ); +#endif +				return -1; +			} +		} +	} + +        /* +         * write the mac addr into the NIC's register area +         */ +	bcm_write_reg32( MAC_ADDR_OFFS_HI(0), l_mac_st.m_hi_u32 ); +	bcm_write_reg32( MAC_ADDR_OFFS_LO(0), l_mac_st.m_lo_u32 ); +	for( i = 1; i < BCM_NUM_MAC_ADDR; i++ ) { +		bcm_write_reg32( MAC_ADDR_OFFS_HI(i), 0 ); +		bcm_write_reg32( MAC_ADDR_OFFS_LO(i), 0 ); +	} +	 +	/* +	 * WY 26.01.07 +	 * not needed anymore, s.a. +	if( IS_5704 != 0 ) { + +		v = MAC5704_ADDR_OFFS; +		for( i = 0; i < BCM_NUM_MAC5704_ADDR; i++ ) { +			bcm_write_reg32( v, l_mac_st.m_hi_u32 ); +			v += sizeof( uint32_t ); +			bcm_write_reg32( v, l_mac_st.m_lo_u32 ); +			v += sizeof( uint32_t ); +		} + +	} +	*/ + +        /* +         * return MAC address as string +         */ +        f_mac_pu08[0] = (uint8_t) ( ( l_mac_st.m_hi_u32 >>  8 ) & (uint32_t) 0xff ); +        f_mac_pu08[1] = (uint8_t) ( ( l_mac_st.m_hi_u32       ) & (uint32_t) 0xff ); +        f_mac_pu08[2] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 24 ) & (uint32_t) 0xff ); +        f_mac_pu08[3] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 16 ) & (uint32_t) 0xff ); +        f_mac_pu08[4] = (uint8_t) ( ( l_mac_st.m_lo_u32 >>  8 ) & (uint32_t) 0xff ); +        f_mac_pu08[5] = (uint8_t) ( ( l_mac_st.m_lo_u32       ) & (uint32_t) 0xff ); + +#ifdef BCM_DEBUG +	do { +		int32_t i; +		printf( "bcm57xx: retrieved MAC address " ); + +		for( i = 0; i < 6; i++ ) { +			printf( "%02X", f_mac_pu08[i] ); + +			if( i != 5 ) { +				printf( ":" ); +			} + +		} + +		printf( "\n" ); +	} while( 0 ); +#endif  + +	return 0; +} + + +/* + ****************************************************************************** + * ASF Firmware + ****************************************************************************** + */ + + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_ASF_REGS +static void +bcm_asf_check_register( void ) +{ +	uint32_t i; + +	i = bcm_read_reg32( ASF_CTRL_R ); +	printf( "bcm57xx: ASF control          : %x\n", i ); + +	i = bcm_read_reg32( ASF_WATCHDOG_TIMER_R ); +	printf( "bcm57xx: ASF Watchdog Timer   : %x\n", i ); + +	i = bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ); +	printf( "bcm57xx: ASF Heartbeat Timer  : %x\n", i ); + +	i = bcm_read_reg32( ASF_POLL_TIMER_R ); +	printf( "bcm57xx: ASF Poll Timer       : %x\n", i ); + +	i = bcm_read_reg32( POLL_LEGACY_TIMER_R ); +	printf( "bcm57xx: Poll Legacy Timer    : %x\n", i ); + +	i = bcm_read_reg32( RETRANSMISSION_TIMER_R ); +	printf( "bcm57xx: Retransmission Timer : %x\n", i ); + +	i = bcm_read_reg32( TIME_STAMP_COUNTER_R ); +	printf( "bcm57xx: Time Stamp Counter   : %x\n", i ); + +	i = bcm_read_reg32( RX_CPU_MODE_R ); +	printf( "bcm57xx: RX RISC Mode         : %x\n", i ); + +	i = bcm_read_reg32( RX_CPU_STATE_R ); +	printf( "bcm57xx: RX RISC State        : %x\n", i ); + +	i = bcm_read_reg32( RX_CPU_PC_R ); +	printf( "bcm57xx: RX RISC Prg. Counter : %x\n", i ); +} +#endif +#endif + +static int +bcm_fw_halt( void ) +{ +	int i; + +	bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_PAUSE_FW ); +	bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) ); + +	/* Wait for RX cpu to ACK the event.  */ +	for (i = 0; i < 100; i++) { +		if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 )) +			break; +		SLOF_msleep(1); +	} +	if( i>= 100) +		return -1; +	return 0; +} + + +#ifdef BCM_SW_AUTONEG +static void +bcm_sw_autoneg( void ) { +	uint32_t i, j, k; +	uint32_t SerDesCfg; +	uint32_t SgDigControl; +	uint32_t SgDigStatus; +	uint32_t ExpectedSgDigControl; +	int   AutoNegJustInitiated = 0; + +	// step 1: init TX 1000BX Autoneg. Register to zero +	bcm_write_reg32(TX_1000BX_AUTONEG_R, 0); + +	// step 2&3: set TBI mode +	bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) ); +	SLOF_usleep(10); + +	// step 4: enable link attention +	bcm_setb_reg32( ETH_MAC_EVT_EN_R, BIT32( 12 ) ); + +	// step 5: preserve voltage regulator bits +	SerDesCfg = bcm_read_reg32(SERDES_CTRL_R) & ( BIT32( 20 ) | BIT32( 21 ) +	                                            | BIT32( 22 ) | BIT32( 23 ) ); + +	// step 6: preserve voltage regulator bits +	SgDigControl = bcm_read_reg32(HW_AUTONEG_CTRL_R); + +	// step 7: if device is NOT set-up for auto negotiation, then go to step 26 +	// goto bcm_setup_phy_step26; + +	// We want to use auto negotiation + +	// step 8: we don't want to use flow control +	ExpectedSgDigControl = 0x81388400; // no flow control + +	// step 9: compare SgDigControl with 0x81388400 +	if(SgDigControl == ExpectedSgDigControl) { +		goto bcm_setup_phy_step17; +	} +#ifdef BCM_DEBUG +	printf("bcm57xx: SgDigControl = %08X\n", SgDigControl); +#endif +	// step 10 +	bcm_write_reg32(SERDES_CTRL_R, SerDesCfg | 0xC011880); + +	// step 11: restart auto negotiation +	bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl | BIT32( 30 ) ); + +	// step 12: read back HW_AUTONEG_CTRL_R +	bcm_read_reg32(HW_AUTONEG_CTRL_R); + +	// step 13 +	SLOF_usleep( 5 ); + +	// step 14,15,16: same as step 11, but don't restart auto neg. +	bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl); +	AutoNegJustInitiated = 1; +	goto bcm_setup_phy_step30; + +	// step 17: +	bcm_setup_phy_step17: +	if( ( bcm_read_reg32(ETH_MAC_STAT_R) & ( BIT32( 1 ) | BIT32( 0 ) ) ) == 0 ) { +		goto bcm_setup_phy_step30; +	} + +	// step 18: Get HW Autoneg. Status +	SgDigStatus = bcm_read_reg32(HW_AUTONEG_STAT_R); + +	// step 19: +	if( ( SgDigStatus & BIT32(1) ) +	&&  ( bcm_read_reg32(ETH_MAC_STAT_R) & BIT32(0) ) ) { +		// resolve the current flow control? +		AutoNegJustInitiated = 0; +		goto bcm_setup_phy_step30; +	} + +	// step 20 +	if( SgDigStatus & BIT32(1) ) { +		goto bcm_setup_phy_step30; +	} +	if( AutoNegJustInitiated != 0) { +		AutoNegJustInitiated = 0; +		goto bcm_setup_phy_step29; +	} + +	// step 21, 22, 23, 24: fallback to 1000Mbps-FullDuplex forced mode +	if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) { +		// port 0 +		bcm_write_reg32( SERDES_CTRL_R, 0xC010880 ); +	} +	else {	// port 1 +		bcm_write_reg32( SERDES_CTRL_R, 0x4010880 ); +	} +	// set to 1000Mbps-FullDuplex +	bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400); +	// read back +	bcm_read_reg32(HW_AUTONEG_CTRL_R); +	SLOF_usleep( 40 ); + +	// step 25: a little bit reduces... +	goto bcm_setup_phy_step30; + +	// step 26: check if auto negotiation bit is NOT set +//	bcm_setup_phy_step26: +	if( ( SgDigControl & BIT32(31) )== 0 ) { +		printf("No autoneg.\n"); +		goto bcm_setup_phy_step29; +	} + +	// step 27: +	if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) { +		// port 0 +		bcm_write_reg32( SERDES_CTRL_R, 0xC010880 ); +	} +	else {	// port 1 +		bcm_write_reg32( SERDES_CTRL_R, 0x4010880 ); +	} + +	// step 28: disable auto neg. and force 1000FD mode +	bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400); + +	// step 29-31: omitted for 5704S +	bcm_setup_phy_step29: +	bcm_setup_phy_step30: + +	// step 32: clear link attentions +	i = bcm_read_reg32( ETH_MAC_STAT_R ) | BIT32( 3 ) | BIT32( 4 ); +	k = 100; +	do { +		bcm_write_reg32( ETH_MAC_STAT_R, i ); +		j = bcm_read_reg32( ETH_MAC_STAT_R ); +		if( ( j & BIT32( 3 ) ) != 0 ) +			i = i & ~(BIT32( 3 )); +		if( ( j & BIT32( 4 ) ) != 0 ) +			i = i & ~(BIT32( 4 )); +		--k; +	} while( i & k); + +	// step 33 +	if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0 ) { +		goto bcm_setup_phy_step35; +	} + +	// step 34 +	i = bcm_read_reg32( ETH_MAC_MODE_R ); +	i|= BIT32( 17 ); +	bcm_write_reg32( ETH_MAC_MODE_R, i ); + +	SLOF_usleep( 1 ); + +	i = bcm_read_reg32( ETH_MAC_STAT_R ); +	i&= ~BIT32( 17 ); +	bcm_write_reg32( ETH_MAC_STAT_R, i ); + +	// step 35 & 36: done +	bcm_setup_phy_step35: +#ifdef BCM_DEBUG +	printf("bcm57xx: SetupPhy\n"); +#endif +	return; +} +#endif + +static int +bcm_handle_events( void ) { +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_ASF_REGS +	// ASF REGISTER CHECK +	// ------------------ +	// check if watchdog timer expired +	if( bcm_read_reg32( ASF_WATCHDOG_TIMER_R ) == 0 ) { +		// Show ASF registers +		bcm_asf_check_register(); + +		// rearm watchdog timer +		bcm_write_reg32( ASF_WATCHDOG_TIMER_R, 5 ); +	} +#endif +#endif + +#ifdef BCM_SW_AUTONEG +	// AUTO NEGOTIATION +	// ---------------- + +	// Check event for Auto Negotiation +	if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & +	    ( BIT32( 12 ) | BIT32( 3 ) | BIT32( 0 ) ) ) != 0 ) { +		// link timer procedure +		bcm_sw_autoneg(); +	} +#endif + +	// ASF FW HEARTBEAT +	// ---------------- + +	// check if heartsbeat timer expired +	if( bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ) <= 2) { +		int i; + +		// Send heartbeat event +		bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_ALIVE ); +		bcm_write_mem32( BCM_FW_MBX_LEN, 4 ); +		bcm_write_mem32( BCM_FW_MBX_DATA, 5 ); +		bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) ); + +		// Wait for RX cpu to ACK the event. +		for (i = 100; i > 0; i--) { +			if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 )) +				break; +			SLOF_msleep(1); +		} +		if( i == 0) { +#ifdef BCM_DEBUG +			printf( "bcm57xx: RX cpu did not acknowledge heartbeat event\n" ); +#endif +			return -1; +		} + +		// rearm heartbeat timer +		bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 5 ); +	} +	return 0; +} + +/* + * interface + ****************************************************************************** + */ +   +/* + * bcm_receive + */ +static int +bcm_receive( char *f_buffer_pc, int f_len_i ) +{ +	uint32_t l_rxret_prod_u32  = bcm_read_reg32( RXRET_PROD_IND ); +	uint32_t l_rxret_cons_u32  = bcm_read_reg32( RXRET_CONS_IND ); +	uint32_t l_rxprod_prod_u32 = bcm_read_reg32( RXPROD_PROD_IND ); +	int   l_ret_i; +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_RCV_DATA +	int i, j; +#endif +#endif + +	/* +	 * NOTE: dummy read to ensure data has already been DMA'd is +	 *       done by the indice reads +	 */ + +	bcm_handle_events(); + +	/* +	 * if producer index == consumer index then nothing was received +	 */ +	if( l_rxret_prod_u32 == l_rxret_cons_u32 ) { +		return 0; +	} + +	/* +	 * discard erroneous packets +	 */ +	if( ( bcm_rxret_ring[l_rxret_cons_u32].m_typeflags_u32 & BIT32( 10 ) ) != 0 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: erroneous frame received\n" ); +		printf( "       : frame discarded\n" ); +#endif +		l_ret_i = 0; +	} else { +	        /* +	         * get packet length, throw away checksum (last 4 bytes) +	         */ +	        l_ret_i = (int) ( bcm_rxret_ring[l_rxret_cons_u32].m_idxlen_u32 & +	                          (uint32_t) 0xffff ) - (int) 4; + +		/* +		 * discard oversized packets +	         */ +		if( l_ret_i > f_len_i ) { +#ifdef BCM_DEBUG +			printf( "bcm57xx: receive packet length error:\n" ); +			printf( "       : incoming 0x%X bytes, available buffer 0x%X bytes\n", l_ret_i, f_len_i ); +			printf( "       : frame discarded\n" ); +#endif		 +			l_ret_i = 0; +		} + +        } + +        /* +         * copy & update data & indices +         */ +	if( l_ret_i != 0 ) { +		uint64_t l_cpyaddr_u64; + +		l_cpyaddr_u64  =  +		( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_hi_u32 << 32 ); +		l_cpyaddr_u64 +=  +		( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_lo_u32 ); + +// FIXME: +		if(l_cpyaddr_u64 == 0) { +#ifdef BCM_DEBUG +			printf("bcm57xx: NULL address\n"); +#endif +			return 0; +		} +//  +		memcpy( (void *) f_buffer_pc, +		        (void *) l_cpyaddr_u64, +		        (size_t) l_ret_i ); + +	} + +	/* +	 * replenish bd to producer ring +	 */ +	bcm_rxprod_ring[l_rxprod_prod_u32] = +	                                bcm_rxret_ring[l_rxret_cons_u32]; +        bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 =  +	                                ( l_rxprod_prod_u32 << 16 ); +	bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 += +	                                (uint32_t) BCM_BUF_SIZE; + +        /* +         * update producer ring's producer index +         */ +        l_rxprod_prod_u32 = ( l_rxprod_prod_u32 + 1 ) & ( BCM_RXPROD_RING_SIZE - 1 ); + +        /* +         * move to the next bd in return ring +         */ +        l_rxret_cons_u32 = ( l_rxret_cons_u32 + 1 ) & (  bcm_rxret_ring_sz - 1 ); + +	/* +	 * synchronize before new indices are send to NIC +	 */ +	mb(); + +        /* +         * write back new indices +         */ +        bcm_write_reg32( RXRET_CONS_IND,  l_rxret_cons_u32  ); +        bcm_write_reg32( RXPROD_PROD_IND, l_rxprod_prod_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_RCV +	if( l_ret_i != 0 ) { +		printf( "bcm57xx: received bytes: %d\n", l_ret_i ); +	} +#ifdef BCM_SHOW_RCV_DATA +	for( i = 0, j = 0; i < l_ret_i; i++ ) { +		printf( "%02X ", ( uint32_t ) f_buffer_pc[i] ); + +		if( ( ++j % 0x18 ) == 0 ) { +			printf( "\n" ); +		} +	} + +	if( ( i % 0x18 ) != 0 ) { +		printf( "\n" ); +	} +#endif +#endif +#endif + +        /* +         * return packet length +         */ +        return l_ret_i; +} + +static int +bcm_xmit( char *f_buffer_pc, int f_len_i ) +{ +	uint32_t l_tx_cons_u32 = bcm_read_reg32( TX_CONS_IND ); +	uint32_t l_tx_prod_u32 = bcm_read_reg32( TX_PROD_IND ); +	uint64_t l_cpyaddr_u64; + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_DATA +	int i, j; +#endif +#ifdef BCM_SHOW_IDX +	printf( "\n" ); +	printf( "bcm57xx: TX_PROD_IND    : 0x%03X\n", l_tx_prod_u32 ); +	printf( "bcm57xx: TX_CONS_IND    : 0x%03X\n", l_tx_cons_u32 ); +	printf( "bcm57xx: RXPROD_PROD_IND: 0x%03X\n", bcm_read_reg32( RXPROD_PROD_IND ) ); +	printf( "bcm57xx: RXPROD_CONS_IND: 0x%03X\n", bcm_read_reg32( RXPROD_CONS_IND ) ); +	printf( "bcm57xx: RXRET_PROD_IND : 0x%03X\n", bcm_read_reg32( RXRET_PROD_IND ) ); +	printf( "bcm57xx: RXRET_CONS_IND : 0x%03X\n", bcm_read_reg32( RXRET_CONS_IND ) ); +	printf( "bcm57xx: available txb  : 0x%03X\n", bcm_tx_bufavail_u32 ); +#endif +#ifdef BCM_SHOW_STATS +	printf( "bcm57xx: bcm_status.m_st_word_u32:    %08X\n",               bcm_status.m_st_word_u32 ); +	printf( "bcm57xx: bcm_status.m_st_tag_u32 :    %08X\n",               bcm_status.m_st_tag_u32 ); +	printf( "bcm57xx: bcm_status.m_rxprod_cons_u16:    %04X\n", ( uint32_t ) bcm_status.m_rxprod_cons_u16 ); +	printf( "bcm57xx: bcm_status.m_unused_u16:         %04X\n", ( uint32_t ) bcm_status.m_unused_u16 ); +	printf( "bcm57xx: bcm_status.m_unused_u32:     %08X\n",               bcm_status.m_unused_u32 ); +	printf( "bcm57xx: bcm_status.m_tx_cons_u16:        %04X\n", ( uint32_t ) bcm_status.m_tx_cons_u16 ); +	printf( "bcm57xx: bcm_status.m_rxret_prod_u16:     %04X\n", ( uint32_t ) bcm_status.m_rxret_prod_u16 ); +#endif +#endif + +	bcm_handle_events(); + +	/* +	 * make all consumed bd's available in the ring again +	 * this way only a few buffers are needed instead of +	 * having 512 buffers allocated +	 */ +	while( bcm_tx_start_u32 != l_tx_cons_u32 ) { +		bcm_tx_ring[bcm_tx_stop_u32] = bcm_tx_ring[bcm_tx_start_u32]; +		bcm_tx_stop_u32  = ( bcm_tx_stop_u32  + 1 ) & ( BCM_TX_RING_SIZE - 1 ); +		bcm_tx_start_u32 = ( bcm_tx_start_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); +		bcm_tx_bufavail_u32++; +	} + +	/* +	 * check for tx buffer availability +	 */ +	if( bcm_tx_bufavail_u32 == 0 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: no more transmit buffers available\n" ); +#endif +		return 0; +	} + +	/* +	 * setup next available bd in tx ring +	 */ +	bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32  = ( BIT32( 2 ) | BIT32( 7 ) /*| BIT32( 6 )*/ ); +	bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 += ( (uint32_t) f_len_i << 16 ); +//	bcm_tx_ring[l_tx_prod_u32].m_VLANtag_u32   = BCM_VLAN_TAG; + +	l_cpyaddr_u64  = ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_hi_u32 << 32 ); +	l_cpyaddr_u64 += ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_lo_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_STATS +	printf("bcm57xx: xmit: l_cpyaddr_u64: 0x%lx\n", l_cpyaddr_u64 ); +	printf("               f_buffer_pc  : 0x%lx\n", f_buffer_pc ); +	printf("               f_len_i      : %d\n", f_len_i ); +#endif +#endif +	memcpy( (void *) l_cpyaddr_u64, (void *) f_buffer_pc, (size_t) f_len_i ); + +	/* +	 * update tx producer index & available buffers +	 */ +	l_tx_prod_u32 = ( l_tx_prod_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); +	bcm_tx_bufavail_u32--; + +	/* +	 * synchronize before new index is send to NIC +	 */ +	mb(); + +	bcm_write_reg32( TX_PROD_IND, l_tx_prod_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT +	printf( "bcm57xx: sent bytes: %d\n", f_len_i ); +#ifdef BCM_SHOW_XMIT_DATA +	for( i = 0, j = 0; i < f_len_i; i++ ) { +		printf( "%02X ", ( uint32_t ) f_buffer_pc[i] ); + +		if( ( ++j % 0x18 ) == 0 ) { +			printf( "\n" ); +		} + +	} +	if( ( i % 0x18 ) != 0 ) { +		printf( "\n" ); +	} +#endif +#endif + +#ifdef BCM_SHOW_STATS +	// coalesce status block now +	bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 3 ) | BIT32( 1 ) ); +#endif + +#endif +	return f_len_i; +} + +static int +check_driver( uint16_t vendor_id, uint16_t device_id ) +{ +	uint64_t i; + +	/* +	 * checks whether the driver is handling this device +	 * by verifying vendor & device id +	 * vendor id 0x14e4 == Broadcom +	 */ +        if( vendor_id != 0x14e4 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: netdevice not supported, illegal vendor id\n" ); +#endif +		return -1; +	} + +	for( i = 0; bcm_dev[i].m_dev_u32 != 0; i++ ) { +		if( bcm_dev[i].m_dev_u32 == (uint32_t) device_id ) { +			// success +			break; +		} +	} + +	if(bcm_dev[i].m_dev_u32 == 0) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: netdevice not supported, illegal device ID\n" ); +#endif +		return -1; +	} + +	/* +	 * initialize static variables +	 */ +	bcm_device_u64 = bcm_dev[i].m_devmsk_u64; +	bcm_rxret_ring_sz = 0; +	bcm_baseaddr_u64  = 0; +	bcm_memaddr_u64   = 0; + +	bcm_tx_start_u32    = 0; +	bcm_tx_stop_u32     = 0; +	bcm_tx_bufavail_u32 = 0; + +	return 0; +} + +static void +bcm_wol_activate(void) +{ +#ifdef BCM_DEBUG +	uint16_t reg_pwr_cap; +#endif +	uint16_t reg_pwr_crtl; +	uint32_t wol_mode; + +	wol_mode = bcm_read_reg32( WOL_MODE_R ); +	bcm_write_reg32( WOL_MODE_R, wol_mode | BIT32(0) ); + +#ifdef BCM_DEBUG +	printf( "bcm57xx: WOL activating..." ); +#endif + +//	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_WOL ); +//	SLOF_msleep( 100 ); + +#ifdef BCM_DEBUG +	reg_pwr_cap = SLOF_pci_config_read16(0x4a); +	/*reg_pwr_cap = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                                     2, +	                                                     bcm_pcicfg_bus, +	                                                     bcm_pcicfg_devfn, +	                                                     0x4a );*/ +	printf( "bcm57xx: PM Capability Register: %04X\n", reg_pwr_cap ); +#endif +	/* get curretn power control register */ +	reg_pwr_crtl = SLOF_pci_config_read16(0x4c); +	/*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                                      2, +	                                                      bcm_pcicfg_bus, +	                                                      bcm_pcicfg_devfn, +	                                                      0x4c );*/ + +#ifdef BCM_DEBUG +	printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + +	/* switch to power state D0 */ +	reg_pwr_crtl |= 0x8000; +	reg_pwr_crtl &= ~(0x0003); +	SLOF_pci_config_write16(0x4c, reg_pwr_crtl); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        2, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        0x4c, +	                                        reg_pwr_crtl );*/ +	SLOF_msleep(10); + +/* +	bcm_write_mem32( BCM_NICDRV_WOL_MBX, BCM_WOL_MAGIC_NUMBER | +	                                     NIC_WOLDRV_STATE_SHUTDOWN | +	                                     NIC_WOLDRV_WOL | +	                                     NIC_WOLDRV_SET_MAGIC_PKT ); +*/ + +	/* switch to power state D3hot */ +/* +	reg_pwr_crtl |= 0x0103; +	SLOF_pci_config_write16(0x4c, reg_pwr_crtl); +	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        2, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        0x4c, +	                                        reg_pwr_crtl ); +	SLOF_msleep(10); +*/ + +#ifdef BCM_DEBUG +	reg_pwr_crtl = SLOF_pci_config_read16(0x4c); +	/*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                                      2, +	                                                      bcm_pcicfg_bus, +	                                                      bcm_pcicfg_devfn, +	                                                      0x4c );*/ + +	printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + +#ifdef BCM_DEBUG +	printf( "bcm57xx: WOL activated" ); +#endif +} + +static int +bcm_init( net_driver_t *driver ) +{ +	static const uint32_t  lc_Maxwait_u32 = (uint32_t) 1000; +	uint32_t               l_baseaddrL_u32; +	uint32_t               l_baseaddrH_u32; +	uint32_t               i; +	uint8_t                *mac_addr = driver->mac_addr; + +	if(driver->running != 0) { +		return 0; +	} +#ifdef BCM_DEBUG +	printf( "bcm57xx: detected device " ); +	if( IS_5703 ) { +		printf( "5703S\n" ); +	} else if( IS_5704 ) { +		printf( "5704" ); + +		if( IS_SERDES ) { +			printf( "S\n" ); +		} else { +			printf( "C\n" ); +		} + +	} else if( IS_5714 ) { +		printf( "5714\n" ); +	} +#endif +	/* +	 * setup register & memory base addresses of NIC +	 */ +	l_baseaddrL_u32 = (uint32_t) ~0xf & +			  (uint32_t) SLOF_pci_config_read32(PCI_BAR1_R); +	/*l_baseaddrL_u32 = ( (uint32_t) ~0xf & +	      (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                                     4, +	                                                     bcm_pcicfg_bus, +	                                                     bcm_pcicfg_devfn, +	                                                     PCI_BAR1_R ) );*/ + +	l_baseaddrH_u32 = (uint32_t) SLOF_pci_config_read32(PCI_BAR2_R); +	/*l_baseaddrH_u32 =  +	      (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                                     4, +	                                                     bcm_pcicfg_bus, +	                                                     bcm_pcicfg_devfn, +	                                                     PCI_BAR2_R );*/ +	bcm_baseaddr_u64   = (uint64_t) l_baseaddrH_u32; +	bcm_baseaddr_u64 <<= 32; +	bcm_baseaddr_u64  += (uint64_t) l_baseaddrL_u32; +	bcm_baseaddr_u64 = +		(uint64_t) SLOF_translate_my_address((void *)bcm_baseaddr_u64); +	/*snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));*/ +	bcm_memaddr_u64    = bcm_baseaddr_u64 + BCM_MEMORY_OFFS; + +#ifdef BCM_DEBUG +	printf( "bcm57xx: device's register base high address = 0x%08X\n", l_baseaddrH_u32 ); +	printf( "bcm57xx: device's register base low address  = 0x%08X\n", l_baseaddrL_u32 ); +	printf( "bcm57xx: device's register address           = 0x%llx\n", bcm_baseaddr_u64 ); +#endif + +	/* +	 * 57xx hardware initialization +	 * BCM57xx Programmer's Guide: Section 8, "Initialization" +	 * steps 1 through 101 +	 */ + +	// step 1: enable bus master & memory space in command reg +	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); +	SLOF_pci_config_write16(PCI_COM_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        2, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_COM_R, +	                                        ( int ) i );*/ +	// step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode +	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + +	SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_MISC_HCTRL_R, +	                                        ( int ) i );*/ + +	/* +	 * from now on access may be made through the local +	 * read/write functions +	 */ + +	// step 3: Save ahche line size register +	// omitted, because register is not used for 5704 + +	// step 4: acquire the nvram lock +	if( bcm_nvram_lock() != 0 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: locking NVRAM failed\n" ); +#endif +		return -1; +	} + +	// step 5: prepare the chip for writing TG3_MAGIC_NUMBER +	bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) ); +	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); +	SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_MISC_HCTRL_R, +	                                        ( int ) i );*/ +	bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) | +	                              BIT32( 17 ) | BIT32( 16 ) | +	                              BIT32( 14 ) | BIT32( 13 ) | +	                              BIT32(  5 ) | BIT32(  4 ) | +	                              BIT32(  2 ) | BIT32(  1 ) ); + +	// step 6: write TG3_MAGIC_NUMBER +	bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER ); + +	// step 7: reset core clocks + +	if( IS_5714 ) { +		bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) ); +	} else { +		bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) ); +	} +	// step 8 +	SLOF_msleep( 20 ); + +	// step 9: disable & mask interrupts & enable indirect addressing mode & +	//              enable pci byte/word swapping initialize the misc host control register +	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); +	SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_MISC_HCTRL_R, +	                                        ( int ) i );*/ + +	// step 10: set but master et cetera +	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); +	SLOF_pci_config_write16(PCI_COM_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        2, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_COM_R, +	                                        ( int ) i );*/ + +	// step 11: disable PCI-X relaxed ordering +	bcm_clrb_reg16( PCI_X_COM_R, BIT16( 1 ) ); + +	// step 12: enable the MAC memory arbiter +	bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) ); + +	// step 13: omitted, only for BCM5700 +	// step 14: s. step 10 +	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); +	SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_MISC_HCTRL_R, +	                                        ( int ) i );*/ +	// step 15: set byte swapping (incl. step 27/28/29/30) +	// included prohibition of tx/rx interrupts +	bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) | +	                              BIT32( 17 ) | BIT32( 16 ) | +	                              BIT32( 14 ) | BIT32( 13 ) | +			  	      BIT32(  5 ) | BIT32(  4 ) | +	                              BIT32(  2 ) | BIT32(  1 ) ); +	// step 16: omitted +	i = 1000; +	while( ( --i ) && +	       ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) { +#ifdef BCM_DEBUG +		printf( "." ); +#endif +		SLOF_msleep( 1 ); +	} + +	// return on error +	if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { +		printf( "bootcode not loaded: %x\n", bcm_read_mem32( BCM_FW_MBX ) ); +#ifdef BCM_DEBUG +		printf( "failed\n" ); +#endif +		return -1; +	} + + +	// if ASF Firmware enabled +	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); +	SLOF_msleep( 10 ); + +	// step 17: write ethernet mac mode register +	/* +	 * WY 07.02.07 +	 * omitted for correct SOL function +	 */ +	/* +	if( IS_SERDES ) { +		bcm_write_reg32( ETH_MAC_MODE_R, (uint32_t) 0xc ); +	} else { +		bcm_write_reg32( ETH_MAC_MODE_R, (uint32_t) 0x0 ); +	} +	*/ + +	// step 18/19: omitted +	// step 20: enable hw bugfix for 5704 +	if( IS_5704 || IS_5703 ) { +		bcm_setb_reg32( MSG_DATA_R, BIT32( 26 ) | +		                            BIT32( 28 ) | +		                            BIT32( 29 ) ); +	} + +	// step 21: omitted +	// step 22: omitted +	// step 23: 5704 clear statistics block +	if( IS_5703 || IS_5704 ) { +		memset_ci( (void *) ( bcm_memaddr_u64 + BCM_STATISTIC_OFFS ), +		           0, +		           BCM_STATISTIC_SIZE ); +	} + +	// step 24/25: omitted +	// step 26: set DMA Read/Write Control register +	// NOTE: recommended values from the spec are used here +	if( IS_5714 ) { +		bcm_write_reg32( DMA_RW_CTRL_R, DMA_RW_CTRL_VAL_5714 ); +	} else { +		uint32_t l_PCIState_u32 = bcm_read_reg32( PCI_STATE_R ); +		uint32_t l_DMAVal_u32   = DMA_RW_CTRL_VAL; + +		if( ( l_PCIState_u32 & BIT32( 2 ) ) != 0 ) {	// PCI +			l_DMAVal_u32 |= (uint32_t) 0x300000; +		} else {					// PCI-X +			l_DMAVal_u32 |= (uint32_t) 0x900000; + +			if( ( bcm_read_reg32( PCI_CLK_CTRL_R ) & (uint32_t) 0x1f ) +			    >= (uint32_t) 6 ) { +				l_DMAVal_u32 |= (uint32_t) 0x4000; +			} + +		} + +		bcm_write_reg32( DMA_RW_CTRL_R, l_DMAVal_u32 ); +	} + +	// step 27/28/29: s. step 14 + +	// step 30: Configure TCP/UDP pseudo header checksum offloading +	// already done in step 14: offloading disabled + +	// step 31: setup timer prescaler +	i  = bcm_read_reg32( MISC_CFG_R ); +	i &= (uint32_t) ~0xfe;   // clear bits 7-1 first +	i |= ( BCM_TMR_PRESCALE << 1 ); +	bcm_write_reg32( MISC_CFG_R, i ); + +	// step 32: 5703/4 configure Mbuf pool address/length +	// step 33: 5703/4 configure MAC DMA resource pool +	// step 34: configure MAC memory pool watermarks +	// step 35: 5703/4 configure DMA resource watermarks +	//          using recommended settings (hard coded) +	if( IS_5703 || IS_5704 ) { + +		if( IS_5703 ) { +			bcm_write_reg32( MBUF_POOL_ADDR_R, (uint32_t) 0x8000 ); +			bcm_write_reg32( MBUF_POOL_LEN_R,  (uint32_t) 0x18000 ); +		} else { +			bcm_write_reg32( MBUF_POOL_ADDR_R, (uint32_t) 0x10000 ); +			bcm_write_reg32( MBUF_POOL_LEN_R,  (uint32_t) 0x10000 ); +		} + +		bcm_write_reg32( DMA_DESC_POOL_ADDR_R,   (uint32_t) 0x2000 ); +		bcm_write_reg32( DMA_DESC_POOL_LEN_R,    (uint32_t) 0x2000 ); + +		bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R,  (uint32_t) 0x50 ); +		bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x20 ); +		bcm_write_reg32( MBUF_HIGH_WMARK_R,      (uint32_t) 0x60 ); + +		bcm_write_reg32( DMA_DESC_LOW_WM_R,      (uint32_t)  5 ); +		bcm_write_reg32( DMA_DESC_HIGH_WM_R,     (uint32_t) 10 ); +	} else { +		bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R,  (uint32_t) 0x00 ); +		bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x10 ); +		bcm_write_reg32( MBUF_HIGH_WMARK_R,      (uint32_t) 0x60 ); +	} + +	// step 35: omitted +	// step 36: Configure flow control behaviour +	//          using recommended settings (hard coded) +	bcm_write_reg32( LOW_WMARK_MAX_RXFRAM_R, (uint32_t) 0x02 ); + +	// step 37/38: enable buffer manager & wait for successful start +	bcm_setb_reg32( BUF_MAN_MODE_R, BIT32( 2 ) | BIT32( 1 ) ); + +	i = lc_Maxwait_u32; +	while( ( --i ) && +	       ( ( bcm_read_reg32( BUF_MAN_MODE_R ) & BIT32( 1 ) ) == 0 ) ) { +		SLOF_usleep( 10 ); +	} + +	// return on error +	if( i == 0 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: init step 38: enable buffer manager failed\n" ); +#endif +		return -1; +	} + +	// step 39: enable internal hardware queues +	bcm_write_reg32( FTQ_RES_R, (uint32_t) ~0 ); +	bcm_write_reg32( FTQ_RES_R, (uint32_t)  0 ); + +	// step 40/41/42: initialize rx producer ring +	bcm_init_rxprod_ring(); + +	// step 43: set rx producer ring replenish threshold +	// using recommended setting of maximum allocated BD's/8 +	bcm_write_reg32( STD_RXPR_REP_THR_R, (uint32_t) BCM_MAX_RX_BUF / 8 ); + +	// step 44/45/46: initialize send rings +	bcm_init_tx_ring(); +	bcm_init_rxret_ring(); + +	// steps 47-50 done in ring init functions +	// step 51: configure MAC unicast address +	bcm_nvram_init(); +	if( bcm_mac_init( (uint8_t *) mac_addr ) < 0 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: init step 51: configure MAC unicast address failed\n" ); +#endif +		return -1; +	} +	memcpy(driver->mac_addr, mac_addr, 6); + +	// step 52: configure backoff random seed for transmit +	// using recommended algorithm +	i  = (uint32_t) mac_addr[0] + (uint32_t) mac_addr[1] + +	     (uint32_t) mac_addr[2] + (uint32_t) mac_addr[3] + +	     (uint32_t) mac_addr[4] + (uint32_t) mac_addr[5]; +	i &= (uint32_t) 0x03ff;  +	bcm_write_reg32( ETH_TX_RND_BO_R, i ); + +	// step 53: configure message transfer unit MTU size +	bcm_write_reg32( RX_MTU_SIZE_R, (uint32_t) BCM_MTU_MAX_LEN ); + +	// step 54: configure IPG for transmit +	// using recommended value (through #define) +	bcm_write_reg32( TX_MAC_LEN_R, TX_MAC_LEN_VAL ); + +	// step 55: configure receive rules + +	// set RX rule default class +	bcm_write_reg32( RX_RULE_CFG_R, RX_RULE_CFG_VAL ); + +	// step 56: configure the number of receive lists +	bcm_write_reg32( RX_LST_PLACE_CFG_R, RX_LST_PLC_CFG_VAL ); +	bcm_write_reg32( RX_LST_PLACE_STAT_EN_R, RX_LST_PLC_STAT_EN_VAL ); + +/* +	// rule 1: accept frames for our MAC address +	bcm_write_reg32( RX_RULE_CTRL_R ( 0 ), +			 BIT32( 31 ) | 	// enable rule +			 BIT32( 30 ) | 	// and with next +			 BIT32( 26 ) | 	// split value register +			 BIT32(  8 ) );	// class 1 +	bcm_write_reg32( RX_RULE_VAL_R  ( 0 ), +			 (uint32_t) 0xffff0000 | +			 ( bcm_read_reg32( MAC_ADDR_OFFS_HI(0) ) & +			   (uint32_t) 0xffff ) ); + +	bcm_write_reg32( RX_RULE_CTRL_R ( 1 ), +			 BIT32( 31 ) | 	// enable rule +			 BIT32(  8 ) | 	// class 1 +			 BIT32(  1 ) );	// offset 2 +	bcm_write_reg32( RX_RULE_VAL_R  ( 1 ), +			 bcm_read_reg32( MAC_ADDR_OFFS_LO(0) ) ); + +	// rule 2: accept broadcast frames +	bcm_write_reg32( RX_RULE_CTRL_R ( 2 ), +			 BIT32( 31 ) | 	// enable rule +			 BIT32( 30 ) | 	// and with next +			 BIT32( 26 ) | 	// split value register +			 BIT32(  8 ) );	// class 1 +	bcm_write_reg32( RX_RULE_VAL_R  ( 2 ), +			 (uint32_t) ~0 ); + +	bcm_write_reg32( RX_RULE_CTRL_R ( 3 ), +			 BIT32( 31 ) | 	// enable rule +			 BIT32(  8 ) | 	// class 1 +			 BIT32(  1 ) );	// offset 2 +	bcm_write_reg32( RX_RULE_VAL_R  ( 3 ), +			 (uint32_t) ~0 ); +*/ +	for( i=0; i<NUM_RX_RULE_ASF; ++i) { +		bcm_write_reg32( RX_RULE_CTRL_R ( i ),  0 ); +		bcm_write_reg32( RX_RULE_VAL_R  ( i ),  0 ); +	} + +	// step 57-60: enable rx/tx statistics +	// omitted, no need for statistics (so far) + +	// step 61/62: disable host coalescing engine/wait 20ms +	bcm_write_reg32( HOST_COAL_MODE_R, (uint32_t) 0 ); + +	i = lc_Maxwait_u32 * 2; +	while( ( --i ) && +	       ( bcm_read_reg32( HOST_COAL_MODE_R ) != 0 ) ) { +		SLOF_usleep( 10 ); +	} + +	// return on error +	if( i == 0 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: init step 62: disable host coal. engine failed\n" ); +#endif +		return -1; +	} + +	// step 63-66: initialize coalescing engine +	// NOTE: status block is unused in this driver, +	//       therefore the coal. engine status block +	//       automatic update is disabled (by writing +	//       0 to every counter +	bcm_write_reg32( RX_COAL_TICKS_R, 0 ); +	bcm_write_reg32( TX_COAL_TICKS_R, 0 ); +	bcm_write_reg32( RX_COAL_MAX_BD_R, 0 ); +	bcm_write_reg32( TX_COAL_MAX_BD_R, 0 ); +	bcm_write_reg32( RX_COAL_TICKS_INT_R, 0 ); +	bcm_write_reg32( TX_COAL_TICKS_INT_R, 0 ); +	bcm_write_reg32( RX_COAL_MAX_BD_INT_R, 0 ); +	bcm_write_reg32( TX_COAL_MAX_BD_INT_R, 0 ); + +	// step 67: initialize host status block address +	// NOTE: status block is not needed in this driver, +	//       still it needs to be set up +	i = (uint32_t) ( (uint64_t) &bcm_status >> 32 ); +	bcm_write_reg32( STB_HOST_ADDR_HI_R, i ); +	i = (uint32_t) ( (uint64_t) &bcm_status & (uint64_t) 0xffffffff ); +	bcm_write_reg32( STB_HOST_ADDR_LO_R, i ); + +	// 5704/3 adaption +	if( IS_5703 || IS_5704 ) { +		// step 68: 5704, for now omitted +		// step 69: 5704 set the statistics coalescing tick counter +		bcm_write_reg32( STAT_TICK_CNT_R, 0 ); +		// step 70: 5704 configure statistics block address in NIC memory +		//          using recommended values (hard coded) +		bcm_write_reg32( STAT_NIC_ADDR_R, (uint32_t) 0x300 ); +		// step 71: 5704 configure status block address in NIC memory +		//          using recommended values (hard coded) +		bcm_write_reg32( STB_NIC_ADDR_R, (uint32_t) 0xb00 ); +	} + +	// step 72: enable host coalescing engine +	bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 12 ) | BIT32( 11 ) | BIT32( 1 ) ); + +	// step 73: enable rx bd completion functional block +	bcm_write_reg32( RX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + +	// step 74: enable rx list placement functional block +	bcm_write_reg32( RX_LST_PLACE_MODE_R, BIT32( 1 ) ); +	// 5704/3 adaption +	if( IS_5703 || IS_5704 ) { +		// step 75: 5704/3 enable receive list selector func block +		bcm_write_reg32( RX_LST_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); +	} + +	// step 76: enable DMA engines +	bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 23 ) | BIT32( 22 ) | BIT32( 21 ) ); +	/* +	 * WY 26.10.07 This is wrong for 5714, better leave it alone +	if( IS_5714 ) { +		bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 20 ) ); +	} +	*/ + +	// step 77: omitted, statistics are not used +	// step 78: Configure the General Misc Local Control register +	// NOTE:    as known so far nothing needs to be done here, +	//          default values should work fine +	//bcm_setb_reg32( MISC_LOCAL_CTRL_R, 0 ); + +	// step 79: clear interrupts in INT_MBX0_R low word +	bcm_write_reg32( INT_MBX0_R, 0 ); +	// 5704/3 adaption +	// step 80: 5704/3 enable DMA completion functional block +	if( IS_5703 || IS_5704 ) { +		bcm_write_reg32( DMA_COMPL_MODE_R, BIT32( 1 ) ); +	} + +	// step 81/82: configure write/read DMA mode registers +	//             disable MSI +	bcm_write_reg32( RD_DMA_MODE_R, BIT32( 10 ) | BIT32( 9 ) | BIT32( 8 ) | +	                                BIT32(  7 ) | BIT32( 6 ) | BIT32( 5 ) | +	                                BIT32(  4 ) | BIT32( 3 ) | BIT32( 2 ) | +	                                BIT32(  1 ) ); +	bcm_write_reg32( WR_DMA_MODE_R, BIT32( 9 ) | BIT32( 8 ) | BIT32( 7 ) | +	                                BIT32( 6 ) | BIT32( 5 ) | BIT32( 4 ) | +	                                BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) ); +	bcm_clrb_reg32( MSI_MODE_R,     BIT32( 1 ) ); +	SLOF_usleep( 100 ); + +	// step 83-91: enable all these functional blocks... +	bcm_write_reg32( RX_DAT_COMPL_MODE_R,   BIT32( 1 ) | BIT32( 2 ) ); + +	if( IS_5703 || IS_5704 ) { +		bcm_write_reg32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) ); +	} + +	bcm_write_reg32( TX_DAT_COMPL_MODE_R,   BIT32( 1 ) ); +	bcm_write_reg32( TX_BD_COMPL_MODE_R,    BIT32( 1 ) | BIT32( 2 ) ); +	bcm_write_reg32( RX_BD_INIT_MODE_R,     BIT32( 1 ) | BIT32( 2 ) ); +	bcm_write_reg32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) ); +	bcm_write_reg32( TX_DAT_INIT_MODE_R,    BIT32( 1 ) | BIT32( 3 ) ); +	bcm_write_reg32( TX_BD_INIT_MODE_R,     BIT32( 1 ) | BIT32( 2 ) ); +	bcm_write_reg32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + +	// step 92: omitted +	// step 93/94: Enable Tx/Rx MAC +	bcm_setb_reg32( TX_MAC_MODE_R, BIT32( 1 ) ); +//	bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) | BIT32( 2 ) );	// set BIT32( 8 ) for promiscious mode! +	bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) );	// set BIT32( 8 ) for promiscious mode! +	                                            	// set BIT32( 10) for VLAN + +	// step 95: disable auto polling: +	//          bcm_phy_init takes care of this +	// step 96: omitted +	// step 97: omitted, may change though, but is not important +	// step 98: activate link & enable MAC functional block +	// NOTE     autopolling is enabled so bit 0 needs not to be set +	//bcm_setb_reg32( MI_STATUS_R, BIT32( 0 ) ); + +	// step 99: setup PHY +	// return if link is down +	if( bcm_phy_init() < 0 ) { +#ifdef BCM_DEBUG +		printf( "bcm57xx: init step 99: PHY initialization failed\n" ); +#endif +		return -1; +	} + +	// step 100: setup multicast filters +	bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0 ); +	bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0 ); +	bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0 ); +	bcm_write_reg32( MAC_HASH3_R, (uint32_t) 0 ); +/* +	// accept all multicast frames +	bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0xffffffff ); +	bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0xffffffff ); +	bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0xffffffff ); +	bcm_write_reg32( MAC_HASH3_R, (uint32_t) 0xffffffff ); +*/ +	// step 101: omitted, no interrupts used + +	// make initial receive buffers available for NIC +	// this step has to be done here after RX DMA engine has started (step 94) +	bcm_write_reg32( RXPROD_PROD_IND, BCM_MAX_RX_BUF ); + +	// if ASF Firmware enabled +	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE ); +	SLOF_msleep( 10 ); + +	// enable heartbeat timer + +	bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 0x5 ); + +	driver->running = 1; +	// off we go.. +	return 0; +} + +static int +bcm_reset( void ) +{ +	uint32_t i; + +#ifdef BCM_DEBUG +	printf( "bcm57xx: resetting controller.." ); +#endif + +	bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER ); + +	if( IS_5714 ) { +		bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) ); +	} else { +		bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) ); +	} + +	SLOF_msleep( 20 ); + +	/* +	 * after reset local read/write functions cannot be used annymore +	 * until bus master & stuff is set up again +	 */ + +	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); +	SLOF_pci_config_write16(PCI_COM_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        2, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_COM_R, +	                                        ( int ) i );*/ + +	// step 9 & 13: disable & mask interrupts & enable indirect addressing mode & +	//              enable pci byte/word swapping initialize the misc host control register +	i = ( BIT32( 7 ) | BIT32( 5 ) | BIT32( 4 ) | +	      BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); +	SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_MISC_HCTRL_R, +	                                        ( int ) i );*/ + +	// step 16: poll for bootcode completion by waiting for the one's +	//          complement of the magic number previously written +	i = 1000; +	while( ( --i ) && +	       ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) { +#ifdef BCM_DEBUG +		printf( "." ); +#else +		SLOF_msleep( 1 ); +#endif +	} + +	// return on error +	if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { +#ifdef BCM_DEBUG +		printf( "failed\n" ); +#endif +		return -1; +	} + +#ifdef BCM_DEBUG +	printf( "done\n" ); +#endif +	return 0; +} + +static int +bcm_term( void ) +{ +	uint32_t i; +	uint16_t v; + +#ifdef BCM_DEBUG +	printf( "bcm57xx: driver shutdown.." ); +#endif + +	/* +	 * halt ASF firmware +	 */ +	bcm_fw_halt(); + +	/* +	 * unload ASF firmware +	 */ +	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD ); + +	/* +	 * disable RX producer rings +	 */ +	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_JUM ), 0 ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 ); +	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_JUM ), 0 ); + +	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_STD ), 0 ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 ); +	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_STD ), 0 ); + +	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_MIN ), 0 ); +	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 ); +	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_MIN ), 0 ); + +	/* +	 * disable RX return rings +	 */ +	v = BCM_RXRET_RCB_OFFS; +	for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) { +		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); +		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 ); + +		v += BCM_RCB_SIZE_u16; +        } + +	/* +	 * disable TX rings +	 */ +        v = BCM_TX_RCB_OFFS; +	for( i = 0; i < BCM_MAX_TX_RING; i++ ) { +		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 ); +		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); +		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 ); + +		v += BCM_RCB_SIZE_u16; +	} + +	/* +	 * remove receive rules +	 */ +	bcm_write_reg32( RX_RULE_CTRL_R (  0 ), 0 ); +	bcm_write_reg32( RX_RULE_VAL_R  (  0 ), 0 ); +	bcm_write_reg32( RX_RULE_CTRL_R (  1 ), 0 ); +	bcm_write_reg32( RX_RULE_VAL_R  (  1 ), 0 ); + +	/* +	 * shutdown sequence +	 * BCM57xx Programmer's Guide: Section 8, "Shutdown" +	 * the enable bit of every state machine of the 57xx +	 * has to be reset. +	 */ + +	/* +	 * receive path shutdown sequence +	 */ +	bcm_clr_wait_bit32( RX_MAC_MODE_R,         BIT32( 1 ) ); +	bcm_clr_wait_bit32( RX_LST_PLACE_MODE_R,   BIT32( 1 ) ); +	bcm_clr_wait_bit32( RX_BD_INIT_MODE_R,     BIT32( 1 ) ); +	bcm_clr_wait_bit32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) ); +	bcm_clr_wait_bit32( RX_DAT_COMPL_MODE_R,   BIT32( 1 ) ); +	bcm_clr_wait_bit32( RX_BD_COMPL_MODE_R,    BIT32( 1 ) ); + +	if( IS_5704 || IS_5703 ) { +		bcm_clr_wait_bit32( RX_LST_SEL_MODE_R, BIT32( 1 ) ); +	} + +	/* +	 * transmit path & memory shutdown sequence +	 */ +	bcm_clr_wait_bit32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) ); +	bcm_clr_wait_bit32( TX_BD_INIT_MODE_R,     BIT32( 1 ) ); +	bcm_clr_wait_bit32( TX_DAT_INIT_MODE_R,    BIT32( 1 ) ); +	bcm_clr_wait_bit32( RD_DMA_MODE_R,         BIT32( 1 ) ); +	bcm_clr_wait_bit32( TX_DAT_COMPL_MODE_R,   BIT32( 1 ) ); + +	if( IS_5704 ) { +		bcm_clr_wait_bit32( DMA_COMPL_MODE_R, BIT32( 1 ) ); +	} + +	bcm_clr_wait_bit32( TX_BD_COMPL_MODE_R,    BIT32( 1 ) ); +	bcm_clr_wait_bit32( ETH_MAC_MODE_R,        BIT32( 21 ) ); +	bcm_clr_wait_bit32( TX_MAC_MODE_R,         BIT32( 1 ) ); + +	bcm_clr_wait_bit32( HOST_COAL_MODE_R,      BIT32( 1 ) ); +	bcm_clr_wait_bit32( WR_DMA_MODE_R,         BIT32( 1 ) ); + +	if( IS_5704 || IS_5703 ) { +		bcm_clr_wait_bit32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) ); +	} + +	bcm_write_reg32( FTQ_RES_R, (uint32_t) ~0 ); +	bcm_write_reg32( FTQ_RES_R, (uint32_t)  0 ); + +	if( IS_5704 || IS_5703 ) { +		bcm_clr_wait_bit32( BUF_MAN_MODE_R, BIT32( 1 ) ); +		bcm_clr_wait_bit32( MEMARB_MODE_R,  BIT32( 1 ) ); +	} + +#ifdef BCM_DEBUG +	printf( "done.\n" ); +#endif +	/* +	 * controller reset +	 */ +	if( bcm_reset() != 0 ) { +		return -1; +	} + +	/* +	 * restart ASF firmware +	 */ +	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD ); +	SLOF_msleep( 10 ); +	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD_DONE ); +	SLOF_msleep( 100 ); +	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); +	SLOF_msleep( 10 ); +	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE ); + +	/* +	 * activate Wake-on-LAN +	 */ +	bcm_wol_activate(); + +	/* +	 * PCI shutdown +	 */ +	bcm_clrb_reg32( PCI_MISC_HCTRL_R, BIT32( 3 ) | BIT32( 2 ) ); + +	/* +	 * from now on local rw functions cannot be used anymore +	 */ + +//	bcm_clrb_reg32( PCI_COM_R, BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + +	SLOF_pci_config_write32(PCI_COM_R, BIT32(8) | BIT32(6)); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        2, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_COM_R, +	                                        BIT32(8) | BIT32(6) );*/ + +	// no more networking... +	return 0; +} + +static int +bcm_getmac(uint32_t addr, char mac[6]) +{ +	uint32_t t1, t2; +	uint64_t t3; + +	if (bcm_nvram_read(addr, &t1, 1) != 0) +		return -1; +	if (bcm_nvram_read(addr+4, &t2, 1) != 0) +		return -1; +	t3 = ((uint64_t)t1 << 32) + t2; + +	mac[0] = (t3 >> 40) & 0xFF; +	mac[1] = (t3 >> 32) & 0xFF; +	mac[2] = (t3 >> 24) & 0xFF; +	mac[3] = (t3 >> 16) & 0xFF; +	mac[4] = (t3 >>  8) & 0xFF; +	mac[5] = (t3 >>  0) & 0xFF; + +	return 0; +} + +static char* +print_itoa(char *text, uint32_t value) +{ +	if(value >= 10) +		text = print_itoa(text, value / 10); +	*text = '0' + (value % 10); +	++text; +	return text; +} + +static int +bcm_get_version(char *text) +{ +	uint32_t t1; + +	if (bcm_nvram_read(0x94, &t1, 1) != 0) +		return -1; + +	text = print_itoa(text, (t1 >> 8) & 0xFF); +	text[0] = '.'; +	text = print_itoa(&text[1], t1 & 0xFF); +	text[0] = '\n'; +	return 0; +} + +static uint32_t +util_gen_crc( char *pcDatabuf, uint32_t ulDatalen, uint32_t ulCrc_in) +{ +	unsigned char data; +	uint32_t idx, bit, crc = ulCrc_in; + +	for(idx = 0; idx < ulDatalen; idx++) { +		data = *pcDatabuf++; +		for(bit = 0; bit < 8; bit++, data >>= 1) { +			crc = (crc >> 1) ^ (((crc ^ data) & 1) ? +				CRC32_POLYNOMIAL : 0); +		} +	} +	return bswap_32(~crc); +} + +static int +bcm_setmac(char mac_addr1[6], char mac_addr2[6]) +{ +	uint64_t mac1 = 0, mac2 = 0; +	uint32_t manu[MANUFACTURING_INFO_SIZE/4]; +	int addr, i; +	uint32_t crc, val1, val2, val3, val4; + +#ifdef BCM_DEBUG +	printf("Flashing MAC 1: %02X:%02X:%02X:%02X:%02X:%02X\n", +		((unsigned int) mac_addr1[0]) & 0xFF, +		((unsigned int) mac_addr1[1]) & 0xFF, +		((unsigned int) mac_addr1[2]) & 0xFF, +		((unsigned int) mac_addr1[3]) & 0xFF, +		((unsigned int) mac_addr1[4]) & 0xFF, +		((unsigned int) mac_addr1[5]) & 0xFF); + +	printf("Flashing MAC 2: %02X:%02X:%02X:%02X:%02X:%02X\n", +		((unsigned int) mac_addr2[0]) & 0xFF, +		((unsigned int) mac_addr2[1]) & 0xFF, +		((unsigned int) mac_addr2[2]) & 0xFF, +		((unsigned int) mac_addr2[3]) & 0xFF, +		((unsigned int) mac_addr2[4]) & 0xFF, +		((unsigned int) mac_addr2[5]) & 0xFF); +#endif + +	mac1 |= ((uint64_t) mac_addr1[0]) & 0xFF; mac1 = mac1 << 8; +	mac1 |= ((uint64_t) mac_addr1[1]) & 0xFF; mac1 = mac1 << 8; +	mac1 |= ((uint64_t) mac_addr1[2]) & 0xFF; mac1 = mac1 << 8; +	mac1 |= ((uint64_t) mac_addr1[3]) & 0xFF; mac1 = mac1 << 8; +	mac1 |= ((uint64_t) mac_addr1[4]) & 0xFF; mac1 = mac1 << 8; +	mac1 |= ((uint64_t) mac_addr1[5]) & 0xFF; + +	mac2 |= ((uint64_t) mac_addr2[0]) & 0xFF; mac2 = mac2 << 8; +	mac2 |= ((uint64_t) mac_addr2[1]) & 0xFF; mac2 = mac2 << 8; +	mac2 |= ((uint64_t) mac_addr2[2]) & 0xFF; mac2 = mac2 << 8; +	mac2 |= ((uint64_t) mac_addr2[3]) & 0xFF; mac2 = mac2 << 8; +	mac2 |= ((uint64_t) mac_addr2[4]) & 0xFF; mac2 = mac2 << 8; +	mac2 |= ((uint64_t) mac_addr2[5]) & 0xFF; + +	/* Extract the manufacturing data, starts at 0x74 */ +	if(bcm_nvram_lock() == -1) { +		return -1; +	} + +	addr = 0x74; +	for (i = 0; i < (MANUFACTURING_INFO_SIZE/4); i++) { +		if (bcm_nvram_read(addr, &manu[i], 0) != 0) { +			printf("\nREAD FAILED\n"); +			bcm_nvram_unlock(); +			return -1; +		} +		addr+=4; +	} +	bcm_nvram_unlock(); + +	/* Store the new MAC address in the manufacturing data */ +	val1 = mac1 >> 32; +	val2 = mac1 & 0xFFFFFFFF; +	val3 = mac2 >> 32; +	val4 = mac2 & 0xFFFFFFFF; +	manu[(0x7C-0x74)/4] = val1; +	manu[(0x80-0x74)/4] = val2; +	manu[(0xCC-0x74)/4] = val3; +	manu[(0xD0-0x74)/4] = val4; + +	/* Calculate the new manufacturing datas CRC */ +	crc = util_gen_crc(((char *)manu), +		MANUFACTURING_INFO_SIZE - 4, 0xFFFFFFFF); + +	/* Now write the new MAC addresses and CRC */ +	if ((bcm_nvram_write(0x7C, val1, 1) != 0) || +	    (bcm_nvram_write(0x80, val2, 1) != 0) || +	    (bcm_nvram_write(0xCC, val3, 1) != 0) || +	    (bcm_nvram_write(0xD0, val4, 1) != 0) || +	    (bcm_nvram_write(0xFC, crc,  1) != 0) ) +	{ +		/* Disastor ! */ +#ifdef BCM_DEBUG +		printf("failed to write MAC address\n"); +#endif +		return -1; +	} + +	/* Success !!!! */ +	return 0; +} + +static int +bcm_ioctl( int request, void* data ) +{ +	uint32_t                l_baseaddrL_u32; +	uint32_t                l_baseaddrH_u32; +	uint32_t                i; +	int                  ret_val = 0; +	char                 mac_addr[6]; +	ioctl_net_data_t     *ioctl_data = (ioctl_net_data_t*) data; + +	if(request != SIOCETHTOOL) { +		return -1; +	} + +#ifdef BCM_DEBUG +	printf( "bcm57xx: detected device " ); +	if( IS_5703 ) { +		printf( "5703S" ); +	} else if( IS_5704 ) { +		printf( "5704" ); +		if( IS_SERDES ) { +			printf( "S\n" ); +		} else { +			printf( "C\n" ); +		} +	} else if( IS_5714 ) { +		printf( "5714\n" ); +	} +#endif +	/* +	 * setup register & memory base addresses of NIC +	 */ +	l_baseaddrL_u32 = (uint32_t) ~0xf & +			  SLOF_pci_config_read32(PCI_BAR1_R); +	/*l_baseaddrL_u32 = ( (uint32_t) ~0xf & +	(uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                               4, +	                                               bcm_pcicfg_bus, +	                                               bcm_pcicfg_devfn, +	                                               PCI_BAR1_R ) );*/ + +	l_baseaddrH_u32 = SLOF_pci_config_read32(PCI_BAR2_R); +	/*l_baseaddrH_u32 =  +	(uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, +	                                               4, +	                                               bcm_pcicfg_bus, +	                                               bcm_pcicfg_devfn, +	                                               PCI_BAR2_R );*/ + +	bcm_baseaddr_u64   = (uint64_t) l_baseaddrH_u32; +	bcm_baseaddr_u64 <<= 32; +	bcm_baseaddr_u64  += (uint64_t) l_baseaddrL_u32; +	bcm_baseaddr_u64 = +		(uint64_t)SLOF_translate_my_address((void *)bcm_baseaddr_u64); +	/*snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));*/ +	bcm_memaddr_u64    = bcm_baseaddr_u64 + BCM_MEMORY_OFFS; + +	/* +	 * 57xx hardware initialization +	 * BCM57xx Programmer's Guide: Section 8, "Initialization" +	 * steps 1 through 101 +	 */ + +	// step 1: enable bus master & memory space in command reg +	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); +	SLOF_pci_config_write16(PCI_COM_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        2, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_COM_R, +	                                        ( int ) i );*/ + +	// step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode +	i = ( BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); +	SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); +	/*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, +	                                        4, +	                                        bcm_pcicfg_bus, +	                                        bcm_pcicfg_devfn, +	                                        PCI_MISC_HCTRL_R, +	                                        ( int ) i );*/ + +	bcm_nvram_init(); + +	switch(ioctl_data->subcmd) { +	case ETHTOOL_GMAC: +		switch(ioctl_data->data.mac.idx) { +		case 0: +			ret_val = bcm_getmac(0x7C, ioctl_data->data.mac.address); +			break; +		case 1: +			ret_val = bcm_getmac(0xCC, ioctl_data->data.mac.address); +			break; +		default: +			ret_val = -1; +			break; +		} +		break; +	case ETHTOOL_SMAC: +		switch(ioctl_data->data.mac.idx) { +		case 0: +			ret_val = bcm_getmac(0xCC, mac_addr); +			if(ret_val == 0) +				ret_val = bcm_setmac(ioctl_data->data.mac.address, mac_addr); +			break; +		case 1: +			ret_val = bcm_getmac(0x7C, mac_addr); +			if(ret_val == 0) +				ret_val = bcm_setmac(mac_addr, ioctl_data->data.mac.address); +			break; +		default: +			ret_val = -1; +			break; +		} +		break; +	case ETHTOOL_VERSION: { +		char *text = ioctl_data->data.version.text; +		memcpy(text, "  BCM57xx Boot code level: ", 27); +		ret_val = bcm_get_version(&text[27]); +		break; +	} +	default: +		ret_val = -1; +		break; +	} +	 +	bcm_term(); +	return ret_val; +} + +net_driver_t *bcm57xx_open(void) +{ +	net_driver_t *driver; +	uint16_t vendor_id, device_id; + +	vendor_id = SLOF_pci_config_read16(0); +	device_id = SLOF_pci_config_read16(2); +	if (check_driver(vendor_id, device_id)) +		return NULL; + +	driver = SLOF_alloc_mem(sizeof(*driver)); +	if (!driver) { +		printf("Unable to allocate virtio-net driver\n"); +		return NULL; +	} +	memset(driver, 0, sizeof(*driver)); + +	if (bcm_init(driver)) +		goto FAIL; + +	return driver; + +FAIL:	SLOF_free_mem(driver, sizeof(*driver)); +	return NULL; + +	return 0; +} + +void bcm57xx_close(net_driver_t *driver) +{ +	if (driver->running == 0) +		return; + +	bcm_term(); +	driver->running = 0; +	SLOF_free_mem(driver, sizeof(*driver)); +} + +int bcm57xx_read(char *buf, int len) +{ +	if (buf) +		return bcm_receive(buf, len); +	return -1; +} + +int bcm57xx_write(char *buf, int len) +{ +	if (buf) +		return bcm_xmit(buf, len); +	return -1; +} diff --git a/roms/SLOF/lib/libbcm/bcm57xx.h b/roms/SLOF/lib/libbcm/bcm57xx.h new file mode 100644 index 00000000..efaba60c --- /dev/null +++ b/roms/SLOF/lib/libbcm/bcm57xx.h @@ -0,0 +1,323 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cache.h> +#include <netdriver.h> + +// Debug switches +//#define BCM_DEBUG	// main debug switch, w/o it the other ones don't work +//#define BCM_SHOW_RCV +//#define BCM_SHOW_RCV_DATA +//#define BCM_SHOW_XMIT +//#define BCM_SHOW_XMIT_DATA +//#define BCM_SHOW_XMIT_STATS +//#define BCM_SHOW_IDX +//#define BCM_SHOW_STATS +//#define BCM_SHOW_ASF_REGS + +// Switch to enable SW AUTO-NEG +// don't try, it's still incomplete +//#define BCM_SW_AUTONEG + +/* + * used register offsets + */ +// PCI command register +#define PCI_COM_R               ( (uint16_t) 0x0004 ) +// PCI Cache Line Size register +#define PCI_CACHELS_R           ( (uint16_t) 0x000c ) +// PCI bar1 register +#define PCI_BAR1_R              ( (uint16_t) 0x0010 ) +// PCI bar2 register +#define PCI_BAR2_R              ( (uint16_t) 0x0014 ) +// PCI bar1 register +#define PCI_SUBID_R             ( (uint16_t) 0x002e ) +// PCI-X Comand register +#define PCI_X_COM_R             ( (uint16_t) 0x0042 ) +// Message Data Register +#define MSG_DATA_R		( (uint16_t) 0x0064 ) +// PCI misc host contrl register +#define PCI_MISC_HCTRL_R        ( (uint16_t) 0x0068 ) +// DMA Read/Write Control register +#define DMA_RW_CTRL_R           ( (uint16_t) 0x006c ) +// PCI State register +#define PCI_STATE_R		( (uint16_t) 0x0070 ) +// PCI_Clock Control register +#define PCI_CLK_CTRL_R		( (uint16_t) 0x0074 ) +// Register Base Address Register +#define REG_BASE_ADDR_REG	( (uint16_t) 0x0078 ) +// Memory Window Base Address Register +#define MEM_BASE_ADDR_REG	( (uint16_t) 0x007c ) +// Register Data Register +#define REG_DATA_REG		( (uint16_t) 0x0080 ) +// Memory Window Data Register +#define MEM_DATA_REG		( (uint16_t) 0x0084 ) +// MAC Function register +#define MAC_FUNC_R		( (uint16_t) 0x00b8 ) +// Interrupt Mailbox 0 register +#define INT_MBX0_R              ( (uint16_t) 0x0204 ) +// Ethernet MAC Mode register +#define ETH_MAC_MODE_R          ( (uint16_t) 0x0400 ) +// Ethernet MAC Addresses registers +#define MAC_ADDR_OFFS_HI( idx )	( (uint16_t) ( (idx*2 + 0)*sizeof( uint32_t ) + 0x0410 ) ) +#define MAC_ADDR_OFFS_LO( idx )	( (uint16_t) ( (idx*2 + 1)*sizeof( uint32_t ) + 0x0410 ) ) +// Ethernet MAC Status register +#define ETH_MAC_STAT_R		( (uint16_t) 0x0404 ) +// Ethernet MAC Event Enable register +#define ETH_MAC_EVT_EN_R	( (uint16_t) 0x0408 ) +// Ethernet Transmit Random Backoff register +#define ETH_TX_RND_BO_R         ( (uint16_t) 0x0438 ) +// Receive MTU Size register +#define RX_MTU_SIZE_R           ( (uint16_t) 0x043c ) +// Transmit 1000BASE-X Auto Negotiation register +#define TX_1000BX_AUTONEG_R	( (uint16_t) 0x0444 ) +// Receive 1000BASE-X Auto Negotiation register +#define RX_1000BX_AUTONEG_R	( (uint16_t) 0x0448 ) +// MI Communication register +#define MI_COM_R                ( (uint16_t) 0x044c ) +// MI Status Register +#define MI_STATUS_R             ( (uint16_t) 0x0450 ) +// MI Mode register +#define MI_MODE_R		( (uint16_t) 0x0454 ) +// Transmit MAC Mode register +#define TX_MAC_MODE_R           ( (uint16_t) 0x045c ) +// Transmit MAC Length register +#define TX_MAC_LEN_R            ( (uint16_t) 0x0464 ) +// Receive MAC Mode register +#define RX_MAC_MODE_R           ( (uint16_t) 0x0468 ) +// MAC Hash 0 register* VPD Config: +#define MAC_HASH0_R		( (uint16_t) 0x0470 ) +// MAC Hash 1 register +#define MAC_HASH1_R		( (uint16_t) 0x0474 ) +// MAC Hash 2 register +#define MAC_HASH2_R		( (uint16_t) 0x0478 ) +// MAC Hash 3 register +#define MAC_HASH3_R		( (uint16_t) 0x047c ) +// Receive Rules Control register +#define RX_RULE_CTRL_R( idx )	( (uint16_t) ( idx*8 + 0x0480 ) ) +// Receive Rules Value register +#define RX_RULE_VAL_R( idx )	( (uint16_t) ( idx*8 + 0x0484 ) ) +// Receive Rules Configuration register +#define RX_RULE_CFG_R           ( (uint16_t) 0x0500 ) +// Low Watermark Max Receive Frames register +#define LOW_WMARK_MAX_RXFRAM_R  ( (uint16_t) 0x0504 ) +// SerDes Control Register +#define SERDES_CTRL_R           ( (uint16_t) 0x0590 ) +// Hardware Auto Negotiation Control Register +#define HW_AUTONEG_CTRL_R       ( (uint16_t) 0x05B0 ) +// Hardware Auto Negotiation Status Register +#define HW_AUTONEG_STAT_R       ( (uint16_t) 0x05B4 ) +// Send Data Initiator Mode register +#define TX_DAT_INIT_MODE_R      ( (uint16_t) 0x0c00 ) +// Send Data Completion Mode register +#define TX_DAT_COMPL_MODE_R     ( (uint16_t) 0x1000 ) +// Send BD Ring Selector Mode register +#define TX_BD_RING_SEL_MODE_R   ( (uint16_t) 0x1400 ) +// Send BD Initiator Mode register +#define TX_BD_INIT_MODE_R       ( (uint16_t) 0x1800 ) +// Send BD Completion Mode register +#define TX_BD_COMPL_MODE_R      ( (uint16_t) 0x1c00 ) +// Receive List Placement Mode register +#define RX_LST_PLACE_MODE_R     ( (uint16_t) 0x2000 ) +// Receive List Placement Configuration register +#define RX_LST_PLACE_CFG_R      ( (uint16_t) 0x2010 ) +// Receive List Placement Statistics Enable Mask register +#define RX_LST_PLACE_STAT_EN_R	( (uint16_t) 0x2018 ) +// Receive Data & Receive BD Initiator Mode register +#define RX_DAT_BD_INIT_MODE_R   ( (uint16_t) 0x2400 ) +// Receive Data Completion Mode register +#define RX_DAT_COMPL_MODE_R     ( (uint16_t) 0x2800 ) +// Receive BD Initiator Mode register +#define RX_BD_INIT_MODE_R       ( (uint16_t) 0x2c00 ) +// Standard Receive Producer Ring Replenish Threshold register +#define STD_RXPR_REP_THR_R      ( (uint16_t) 0x2c18 ) +// Receive BD Completion Mode register +#define RX_BD_COMPL_MODE_R      ( (uint16_t) 0x3000 ) +// Receive List Selector Mode register +#define RX_LST_SEL_MODE_R	( (uint16_t) 0x3400 ) +// MBUF Cluster Free Mode register +#define MBUF_CLSTR_FREE_MODE_R	( (uint16_t) 0x3800 ) +// Host Coalescing Mode register +#define HOST_COAL_MODE_R        ( (uint16_t) 0x3c00 ) +// Receive Coalescing Ticks register +#define RX_COAL_TICKS_R         ( (uint16_t) 0x3c08 ) +// Send Coalescing Ticks register +#define TX_COAL_TICKS_R         ( (uint16_t) 0x3c0c ) +// Receive Max Coalesced BD Count register +#define RX_COAL_MAX_BD_R        ( (uint16_t) 0x3c10 ) +// Send Max Coalesced BD Count register +#define TX_COAL_MAX_BD_R        ( (uint16_t) 0x3c14 ) +// Receive Coalescing Ticks During Int register +#define RX_COAL_TICKS_INT_R     ( (uint16_t) 0x3c18 ) +// Send Coalescing Ticks During Int register +#define TX_COAL_TICKS_INT_R     ( (uint16_t) 0x3c1c ) +// Receive Max Coalesced BD Count During Int register +#define RX_COAL_MAX_BD_INT_R    ( (uint16_t) 0x3c18 ) +// Send Max Coalesced BD Count During Int register +#define TX_COAL_MAX_BD_INT_R    ( (uint16_t) 0x3c1c ) +// Statistics Ticks Counter register +#define STAT_TICK_CNT_R		( (uint16_t) 0x3c28 ) +// Status Block Host Address Low register +#define STB_HOST_ADDR_HI_R      ( (uint16_t) 0x3c38 ) +// Status Block Host Address High register +#define STB_HOST_ADDR_LO_R	( (uint16_t) 0x3c3c ) +// Statistics Base Address register +#define STAT_NIC_ADDR_R		( (uint16_t) 0x3c40 ) +// Status Block Base Address register +#define STB_NIC_ADDR_R		( (uint16_t) 0x3c44 ) +// Memory Arbiter Mode register +#define MEMARB_MODE_R           ( (uint16_t) 0x4000 ) +// Buffer Manager Mode register +#define BUF_MAN_MODE_R          ( (uint16_t) 0x4400 ) +// MBuf Pool Address register +#define MBUF_POOL_ADDR_R	( (uint16_t) 0x4408 ) +// MBuf Pool Length register +#define MBUF_POOL_LEN_R		( (uint16_t) 0x440c ) +// Read DMA Mbuf Low Watermark register +#define DMA_RMBUF_LOW_WMARK_R   ( (uint16_t) 0x4410 ) +// MAC Rx Mbuf Low Watermark register +#define MAC_RXMBUF_LOW_WMARK_R  ( (uint16_t) 0x4414 ) +// Mbuf High Watermark register +#define MBUF_HIGH_WMARK_R       ( (uint16_t) 0x4418 ) +// DMA Descriptor Pool Address register +#define DMA_DESC_POOL_ADDR_R	( (uint16_t) 0x442c ) +// DMA Descriptor Pool Length register +#define DMA_DESC_POOL_LEN_R	( (uint16_t) 0x4430 ) +// DMA Descriptor Low Watermark register +#define DMA_DESC_LOW_WM_R	( (uint16_t) 0x4434 ) +// DMA Descriptor HIGH Watermark register +#define DMA_DESC_HIGH_WM_R	( (uint16_t) 0x4438 ) +// Read DMA Mode register +#define RD_DMA_MODE_R           ( (uint16_t) 0x4800 ) +// Write DMA Mode register +#define WR_DMA_MODE_R           ( (uint16_t) 0x4c00 ) +// FTQ Reset register +#define FTQ_RES_R               ( (uint16_t) 0x5c00 ) +// MSI Mode register +#define MSI_MODE_R		( (uint16_t) 0x6000 ) +// DMA completion Mode register +#define DMA_COMPL_MODE_R	( (uint16_t) 0x6400 ) +// Mode Control register +#define MODE_CTRL_R             ( (uint16_t) 0x6800 ) +// Misc Configuration register +#define MISC_CFG_R              ( (uint16_t) 0x6804 ) +// Misc Local Control register +#define MISC_LOCAL_CTRL_R       ( (uint16_t) 0x6808 ) +// RX-Risc Mode Register +#define RX_CPU_MODE_R    	( (uint16_t) 0x5000 ) +// RX-Risc State Register +#define RX_CPU_STATE_R    	( (uint16_t) 0x5004 ) +// RX-Risc Program Counter +#define RX_CPU_PC_R  		( (uint16_t) 0x501c ) +// RX-Risc Event Register +#define RX_CPU_EVENT_R    	( (uint16_t) 0x6810 ) +// MDI Control register +#define MDI_CTRL_R		( (uint16_t) 0x6844 ) +// WOL Mode register +#define WOL_MODE_R		( (uint16_t) 0x6880 ) +// WOL Config register +#define WOL_CFG_R		( (uint16_t) 0x6884 ) +// WOL Status register +#define WOL_STATUS_R		( (uint16_t) 0x6888 ) + +// ASF Control register +#define ASF_CTRL_R		( (uint16_t) 0x6c00 ) +// ASF Watchdog Timer register +#define ASF_WATCHDOG_TIMER_R	( (uint16_t) 0x6c0c ) +// ASF Heartbeat Timer register +#define ASF_HEARTBEAT_TIMER_R	( (uint16_t) 0x6c10 ) +// Poll ASF Timer register +#define ASF_POLL_TIMER_R	( (uint16_t) 0x6c14 ) +// Poll Legacy Timer register +#define POLL_LEGACY_TIMER_R	( (uint16_t) 0x6c18 ) +// Retransmission Timer register +#define RETRANSMISSION_TIMER_R	( (uint16_t) 0x6c1c ) +// Time Stamp Counter register +#define TIME_STAMP_COUNTER_R	( (uint16_t) 0x6c20 ) + +// NVM Command register +#define NVM_COM_R		( (uint16_t) 0x7000 ) +// NVM Write register +#define NVM_WRITE_R		( (uint16_t) 0x7008 ) +// NVM Address register +#define NVM_ADDR_R		( (uint16_t) 0x700c ) +// NVM Read registertg3_phy_copper_begin +#define NVM_READ_R		( (uint16_t) 0x7010 ) +// NVM Access register +#define NVM_ACC_R		( (uint16_t) 0x7024 ) +// NVM Config 1 register +#define NVM_CFG1_R		( (uint16_t) 0x7014 ) +// Software arbitration register +#define SW_ARB_R                ( (uint16_t) 0x7020 ) + +/* + * useful def's + */ +#define rd08(a) 	ci_read_8((uint8_t *)(a)) +#define rd16(a) 	ci_read_16((uint16_t *)(a)) +#define rd32(a) 	ci_read_32((uint32_t *)(a)) +#define wr08(a,v)	ci_write_8((uint8_t *)(a), (v)) +#define wr16(a,v)	ci_write_16((uint16_t *)(a), (v)) +#define wr32(a,v)	ci_write_32((uint32_t *)(a), (v)) + +#define BIT08( bit )     ( (uint8_t) 0x1 << (bit) ) +#define BIT16( bit )     ( (uint16_t) 0x1 << (bit) ) +#define BIT32( bit )     ( (uint32_t) 0x1 << (bit) ) + +/* + * type definition + */ + +/* + * Constants for different kinds of IOCTL requests + */ + +#define SIOCETHTOOL  0x1000 + +/* + * special structure and constants for IOCTL requests of type ETHTOOL + */ + +#define ETHTOOL_GMAC         0x03 +#define ETHTOOL_SMAC         0x04 +#define ETHTOOL_VERSION      0x05 + +typedef struct { +	int idx; +	char address[6]; +} ioctl_ethtool_mac_t; + +typedef struct { +	unsigned int length; +	char *text; +} ioctl_ethtool_version_t; + + +/* + * default structure and constants for IOCTL requests + */ + +#define IF_NAME_SIZE 0xFF + +typedef struct { +	char if_name[IF_NAME_SIZE]; +	int subcmd; +	union { +		ioctl_ethtool_mac_t mac; +		ioctl_ethtool_version_t version; +	} data; +} ioctl_net_data_t; + +extern net_driver_t *bcm57xx_open(void); +extern void bcm57xx_close(net_driver_t *driver); +extern int bcm57xx_read(char *buf, int len); +extern int bcm57xx_write(char *buf, int len);  | 
