diff options
Diffstat (limited to 'drivers/eepro100.c')
| -rw-r--r-- | drivers/eepro100.c | 297 | 
1 files changed, 210 insertions, 87 deletions
| diff --git a/drivers/eepro100.c b/drivers/eepro100.c index 906159ee3..04c17f69f 100644 --- a/drivers/eepro100.c +++ b/drivers/eepro100.c @@ -26,6 +26,7 @@  #include <net.h>  #include <asm/io.h>  #include <pci.h> +#include <miiphy.h>  #undef DEBUG @@ -34,67 +35,67 @@  	/* Ethernet chip registers.  	 */ -#define SCBStatus       	0	/* Rx/Command Unit Status *Word* */ -#define SCBIntAckByte   	1	/* Rx/Command Unit STAT/ACK byte */ -#define SCBCmd          	2	/* Rx/Command Unit Command *Word* */ -#define SCBIntrCtlByte  	3	/* Rx/Command Unit Intr.Control Byte */ -#define SCBPointer      	4	/* General purpose pointer. */ -#define SCBPort         	8	/* Misc. commands and operands. */ -#define SCBflash        	12	/* Flash memory control. */ -#define SCBeeprom       	14	/* EEPROM memory control. */ -#define SCBCtrlMDI      	16	/* MDI interface control. */ -#define SCBEarlyRx      	20	/* Early receive byte count. */ -#define SCBGenControl   	28	/* 82559 General Control Register */ -#define SCBGenStatus    	29	/* 82559 General Status register */ +#define SCBStatus		0	/* Rx/Command Unit Status *Word* */ +#define SCBIntAckByte		1	/* Rx/Command Unit STAT/ACK byte */ +#define SCBCmd			2	/* Rx/Command Unit Command *Word* */ +#define SCBIntrCtlByte		3	/* Rx/Command Unit Intr.Control Byte */ +#define SCBPointer		4	/* General purpose pointer. */ +#define SCBPort			8	/* Misc. commands and operands. */ +#define SCBflash		12	/* Flash memory control. */ +#define SCBeeprom		14	/* EEPROM memory control. */ +#define SCBCtrlMDI		16	/* MDI interface control. */ +#define SCBEarlyRx		20	/* Early receive byte count. */ +#define SCBGenControl		28	/* 82559 General Control Register */ +#define SCBGenStatus		29	/* 82559 General Status register */  	/* 82559 SCB status word defnitions  	 */ -#define SCB_STATUS_CX   	0x8000	/* CU finished command (transmit) */ -#define SCB_STATUS_FR   	0x4000	/* frame received */ -#define SCB_STATUS_CNA  	0x2000	/* CU left active state */ -#define SCB_STATUS_RNR  	0x1000	/* receiver left ready state */ -#define SCB_STATUS_MDI  	0x0800	/* MDI read/write cycle done */ -#define SCB_STATUS_SWI  	0x0400	/* software generated interrupt */ -#define SCB_STATUS_FCP  	0x0100	/* flow control pause interrupt */ +#define SCB_STATUS_CX		0x8000	/* CU finished command (transmit) */ +#define SCB_STATUS_FR		0x4000	/* frame received */ +#define SCB_STATUS_CNA		0x2000	/* CU left active state */ +#define SCB_STATUS_RNR		0x1000	/* receiver left ready state */ +#define SCB_STATUS_MDI		0x0800	/* MDI read/write cycle done */ +#define SCB_STATUS_SWI		0x0400	/* software generated interrupt */ +#define SCB_STATUS_FCP		0x0100	/* flow control pause interrupt */ -#define SCB_INTACK_MASK 	0xFD00	/* all the above */ +#define SCB_INTACK_MASK		0xFD00	/* all the above */ -#define SCB_INTACK_TX 		(SCB_STATUS_CX | SCB_STATUS_CNA) -#define SCB_INTACK_RX 		(SCB_STATUS_FR | SCB_STATUS_RNR) +#define SCB_INTACK_TX		(SCB_STATUS_CX | SCB_STATUS_CNA) +#define SCB_INTACK_RX		(SCB_STATUS_FR | SCB_STATUS_RNR)  	/* System control block commands  	 */  /* CU Commands */ -#define CU_NOP          	0x0000 -#define	CU_START        	0x0010 -#define	CU_RESUME       	0x0020 -#define	CU_STATSADDR    	0x0040	/* Load Dump Statistics ctrs addr */ -#define	CU_SHOWSTATS    	0x0050	/* Dump statistics counters. */ -#define	CU_ADDR_LOAD    	0x0060	/* Base address to add to CU commands */ -#define	CU_DUMPSTATS    	0x0070	/* Dump then reset stats counters. */ +#define CU_NOP			0x0000 +#define CU_START		0x0010 +#define CU_RESUME		0x0020 +#define CU_STATSADDR		0x0040	/* Load Dump Statistics ctrs addr */ +#define CU_SHOWSTATS		0x0050	/* Dump statistics counters. */ +#define CU_ADDR_LOAD		0x0060	/* Base address to add to CU commands */ +#define CU_DUMPSTATS		0x0070	/* Dump then reset stats counters. */  /* RUC Commands */ -#define RUC_NOP         	0x0000 -#define	RUC_START       	0x0001 -#define	RUC_RESUME      	0x0002 -#define RUC_ABORT       	0x0004 -#define	RUC_ADDR_LOAD   	0x0006	/* (seems not to clear on acceptance) */ -#define RUC_RESUMENR    	0x0007 +#define RUC_NOP			0x0000 +#define RUC_START		0x0001 +#define RUC_RESUME		0x0002 +#define RUC_ABORT		0x0004 +#define RUC_ADDR_LOAD		0x0006	/* (seems not to clear on acceptance) */ +#define RUC_RESUMENR		0x0007 -#define CU_CMD_MASK     	0x00f0 -#define RU_CMD_MASK     	0x0007 +#define CU_CMD_MASK		0x00f0 +#define RU_CMD_MASK		0x0007 -#define SCB_M	        	0x0100	/* 0 = enable interrupt, 1 = disable */ -#define SCB_SWI         	0x0200	/* 1 - cause device to interrupt */ +#define SCB_M			0x0100	/* 0 = enable interrupt, 1 = disable */ +#define SCB_SWI			0x0200	/* 1 - cause device to interrupt */ -#define CU_STATUS_MASK  	0x00C0 -#define RU_STATUS_MASK  	0x003C +#define CU_STATUS_MASK		0x00C0 +#define RU_STATUS_MASK		0x003C -#define RU_STATUS_IDLE  	(0<<2) -#define RU_STATUS_SUS   	(1<<2) -#define RU_STATUS_NORES 	(2<<2) -#define RU_STATUS_READY 	(4<<2) -#define RU_STATUS_NO_RBDS_SUS   ((1<<2)|(8<<2)) +#define RU_STATUS_IDLE		(0<<2) +#define RU_STATUS_SUS		(1<<2) +#define RU_STATUS_NORES		(2<<2) +#define RU_STATUS_READY		(4<<2) +#define RU_STATUS_NO_RBDS_SUS	((1<<2)|(8<<2))  #define RU_STATUS_NO_RBDS_NORES ((2<<2)|(8<<2))  #define RU_STATUS_NO_RBDS_READY ((4<<2)|(8<<2)) @@ -138,27 +139,27 @@ struct RxFD {  };  #define RFD_STATUS_C		0x8000	/* completion of received frame */ -#define RFD_STATUS_OK   	0x2000	/* frame received with no errors */ +#define RFD_STATUS_OK		0x2000	/* frame received with no errors */ -#define RFD_CONTROL_EL   	0x8000	/* 1=last RFD in RFA */ -#define RFD_CONTROL_S    	0x4000	/* 1=suspend RU after receiving frame */ -#define RFD_CONTROL_H    	0x0010	/* 1=RFD is a header RFD */ -#define RFD_CONTROL_SF   	0x0008	/* 0=simplified, 1=flexible mode */ +#define RFD_CONTROL_EL		0x8000	/* 1=last RFD in RFA */ +#define RFD_CONTROL_S		0x4000	/* 1=suspend RU after receiving frame */ +#define RFD_CONTROL_H		0x0010	/* 1=RFD is a header RFD */ +#define RFD_CONTROL_SF		0x0008	/* 0=simplified, 1=flexible mode */ -#define RFD_COUNT_MASK     	0x3fff -#define RFD_COUNT_F        	0x4000 -#define RFD_COUNT_EOF      	0x8000 +#define RFD_COUNT_MASK		0x3fff +#define RFD_COUNT_F		0x4000 +#define RFD_COUNT_EOF		0x8000 -#define RFD_RX_CRC          	0x0800	/* crc error */ -#define RFD_RX_ALIGNMENT    	0x0400	/* alignment error */ -#define RFD_RX_RESOURCE     	0x0200	/* out of space, no resources */ -#define RFD_RX_DMA_OVER     	0x0100	/* DMA overrun */ -#define RFD_RX_SHORT        	0x0080	/* short frame error */ -#define RFD_RX_LENGTH       	0x0020 -#define RFD_RX_ERROR        	0x0010	/* receive error */ -#define RFD_RX_NO_ADR_MATCH 	0x0004	/* no address match */ -#define RFD_RX_IA_MATCH     	0x0002	/* individual address does not match */ -#define RFD_RX_TCO          	0x0001	/* TCO indication */ +#define RFD_RX_CRC		0x0800	/* crc error */ +#define RFD_RX_ALIGNMENT	0x0400	/* alignment error */ +#define RFD_RX_RESOURCE		0x0200	/* out of space, no resources */ +#define RFD_RX_DMA_OVER		0x0100	/* DMA overrun */ +#define RFD_RX_SHORT		0x0080	/* short frame error */ +#define RFD_RX_LENGTH		0x0020 +#define RFD_RX_ERROR		0x0010	/* receive error */ +#define RFD_RX_NO_ADR_MATCH	0x0004	/* no address match */ +#define RFD_RX_IA_MATCH		0x0002	/* individual address does not match */ +#define RFD_RX_TCO		0x0001	/* TCO indication */  	/* Transmit frame descriptors  	 */ @@ -176,45 +177,45 @@ struct TxFD {				/* Transmit frame descriptor set. */  };  #define TxCB_CMD_TRANSMIT	0x0004	/* transmit command */ -#define TxCB_CMD_SF         	0x0008	/* 0=simplified, 1=flexible mode */ -#define TxCB_CMD_NC         	0x0010	/* 0=CRC insert by controller */ -#define TxCB_CMD_I          	0x2000	/* generate interrupt on completion */ -#define TxCB_CMD_S          	0x4000	/* suspend on completion */ -#define TxCB_CMD_EL         	0x8000	/* last command block in CBL */ +#define TxCB_CMD_SF		0x0008	/* 0=simplified, 1=flexible mode */ +#define TxCB_CMD_NC		0x0010	/* 0=CRC insert by controller */ +#define TxCB_CMD_I		0x2000	/* generate interrupt on completion */ +#define TxCB_CMD_S		0x4000	/* suspend on completion */ +#define TxCB_CMD_EL		0x8000	/* last command block in CBL */ -#define TxCB_COUNT_MASK     	0x3fff -#define TxCB_COUNT_EOF      	0x8000 +#define TxCB_COUNT_MASK		0x3fff +#define TxCB_COUNT_EOF		0x8000  	/* The Speedo3 Rx and Tx frame/buffer descriptors.  	 */  struct descriptor {			/* A generic descriptor. */  	volatile u16 status;  	volatile u16 command; -	volatile u32 link;		/* struct descriptor *  */ +	volatile u32 link;		/* struct descriptor *	*/  	unsigned char params[0];  }; -#define CFG_CMD_EL         	0x8000 -#define CFG_CMD_SUSPEND    	0x4000 -#define CFG_CMD_INT        	0x2000 -#define CFG_CMD_IAS        	0x0001	/* individual address setup */ -#define CFG_CMD_CONFIGURE  	0x0002	/* configure */ +#define CFG_CMD_EL		0x8000 +#define CFG_CMD_SUSPEND		0x4000 +#define CFG_CMD_INT		0x2000 +#define CFG_CMD_IAS		0x0001	/* individual address setup */ +#define CFG_CMD_CONFIGURE	0x0002	/* configure */ -#define CFG_STATUS_C       	0x8000 -#define CFG_STATUS_OK      	0x2000 +#define CFG_STATUS_C		0x8000 +#define CFG_STATUS_OK		0x2000  	/* Misc.  	 */ -#define NUM_RX_DESC 		PKTBUFSRX -#define NUM_TX_DESC 		1	/* Number of TX descriptors   */ +#define NUM_RX_DESC		PKTBUFSRX +#define NUM_TX_DESC		1	/* Number of TX descriptors   */  #define TOUT_LOOP		1000000  #define ETH_ALEN		6 -static struct RxFD rx_ring[NUM_RX_DESC];	/* RX descriptor ring         */ -static struct TxFD tx_ring[NUM_TX_DESC];	/* TX descriptor ring         */ +static struct RxFD rx_ring[NUM_RX_DESC];	/* RX descriptor ring	      */ +static struct TxFD tx_ring[NUM_TX_DESC];	/* TX descriptor ring	      */  static int rx_next;			/* RX descriptor ring pointer */  static int tx_next;			/* TX descriptor ring pointer */  static int tx_threshold; @@ -271,8 +272,124 @@ static inline void OUTL (struct eth_device *dev, int command, u_long addr)  	*(volatile u32 *) ((addr + dev->iobase)) = cpu_to_le32 (command);  } -	/* Wait for the chip get the command. -	 */ +#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +static inline int INL (struct eth_device *dev, u_long addr) +{ +	return le32_to_cpu (*(volatile u32 *) (addr + dev->iobase)); +} + +static int get_phyreg (struct eth_device *dev, unsigned char addr, +		unsigned char reg, unsigned short *value) +{ +	int cmd; +	int timeout = 50; + +	/* read requested data */ +	cmd = (2 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16); +	OUTL (dev, cmd, SCBCtrlMDI); + +	do { +		udelay(1000); +		cmd = INL (dev, SCBCtrlMDI); +	} while (!(cmd & (1 << 28)) && (--timeout)); + +	if (timeout == 0) +		return -1; + +	*value = (unsigned short) (cmd & 0xffff); + +	return 0; +} + +static int set_phyreg (struct eth_device *dev, unsigned char addr, +		unsigned char reg, unsigned short value) +{ +	int cmd; +	int timeout = 50; + +	/* write requested data */ +	cmd = (1 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16); +	OUTL (dev, cmd | value, SCBCtrlMDI); + +	while (!(INL (dev, SCBCtrlMDI) & (1 << 28)) && (--timeout)) +		udelay(1000); + +	if (timeout == 0) +		return -1; + +	return 0; +} + +/* Check if given phyaddr is valid, i.e. there is a PHY connected. + * Do this by checking model value field from ID2 register. + */ +static struct eth_device* verify_phyaddr (char *devname, unsigned char addr) +{ +	struct eth_device *dev; +	unsigned short value; +	unsigned char model; + +	dev = eth_get_dev_by_name(devname); +	if (dev == NULL) { +		printf("%s: no such device\n", devname); +		return NULL; +	} + +	/* read id2 register */ +	if (get_phyreg(dev, addr, PHY_PHYIDR2, &value) != 0) { +		printf("%s: mii read timeout!\n", devname); +		return NULL; +	} + +	/* get model */ +	model = (unsigned char)((value >> 4) & 0x003f); + +	if (model == 0) { +		printf("%s: no PHY at address %d\n", devname, addr); +		return NULL; +	} + +	return dev; +} + +static int eepro100_miiphy_read (char *devname, unsigned char addr, +		unsigned char reg, unsigned short *value) +{ +	struct eth_device *dev; + +	dev = verify_phyaddr(devname, addr); +	if (dev == NULL) +		return -1; + +	if (get_phyreg(dev, addr, reg, value) != 0) { +		printf("%s: mii read timeout!\n", devname); +		return -1; +	} + +	return 0; +} + +static int eepro100_miiphy_write (char *devname, unsigned char addr, +		unsigned char reg, unsigned short value) +{ +	struct eth_device *dev; + +	dev = verify_phyaddr(devname, addr); +	if (dev == NULL) +		return -1; + +	if (set_phyreg(dev, addr, reg, value) != 0) { +		printf("%s: mii write timeout!\n", devname); +		return -1; +	} + +	return 0; +} + +#endif /* defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) */ + +/* Wait for the chip get the command. +*/  static int wait_for_eepro100 (struct eth_device *dev)  {  	int i; @@ -345,6 +462,12 @@ int eepro100_initialize (bd_t * bis)  		eth_register (dev); +#if defined (CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +		/* register mii command access routines */ +		miiphy_register(dev->name, +				eepro100_miiphy_read, eepro100_miiphy_write); +#endif +  		card_number++;  		/* Set the latency timer for value. @@ -723,12 +846,12 @@ int eepro100_write_eeprom (struct eth_device* dev, int location, int addr_len, u      OUTW(dev, EE_ENB | dataval, SCBeeprom);      udelay(1); -    datalong = datalong << 1; /* Adjust significant data bit*/ +    datalong = datalong << 1;	/* Adjust significant data bit*/      }      /* Finish up command  (toggle CS) */      OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom); -    udelay(1);                /* delay for more than 250 ns */ +    udelay(1);			/* delay for more than 250 ns */      OUTW(dev, EE_ENB, SCBeeprom);      /* Wait for programming ready (D0 = 1) */ |