⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tulip.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);		outl(0x0000EF05, ioaddr + CSR13);		break;	case DC21040:		outl(0x00000000, ioaddr + CSR13);		outl(0x00000004, ioaddr + CSR13);		break;	case DC21140: default:		if (tp->mtable)			outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);		break;	case DC21142:		outl(0x82420200, ioaddr + CSR6);		outl(0x0001, ioaddr + CSR13);		outl(0x0003FFFF, ioaddr + CSR14);		outl(0x0008, ioaddr + CSR15);		outl(0x0001, ioaddr + CSR13);		outl(0x1301, ioaddr + CSR12); /* Start NWay. */		break;	case LC82C168:		if ( ! tp->mii_cnt) {			outl(0x00420000, ioaddr + CSR6);			outl(0x30, ioaddr + CSR12);			outl(0x0001F078, ioaddr + 0xB8);			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */		}		break;	case MX98713: case MX98715: case MX98725:		outl(0x00000000, ioaddr + CSR6);		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */		outl(0x00000001, ioaddr + CSR13);		break;	}	return dev;}/* Serial EEPROM section. *//* The main routine to parse the very complicated SROM structure.   Search www.digital.com for "21X4 SROM" to get details.   This code is very complex, and will require changes to support   additional cards, so I'll be verbose about what is going on.   *//* Known cards that have old-style EEPROMs. */static struct fixups {  char *name;  unsigned char addr0, addr1, addr2;  u16 newtable[32];				/* Max length below. */} eeprom_fixups[] = {  {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,						  0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},  {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,							   0x0000, 0x009E, /* 10baseT */							   0x0903, 0x006D, /* 100baseTx */ }},  {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,								 0x0107, 0x8021, /* 100baseFx */								 0x0108, 0x8021, /* 100baseFx-FD */								 0x0103, 0x006D, /* 100baseTx */ }},  {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,							   0x1001, 0x009E, /* 10base2, CSR12 0x10*/							   0x0000, 0x009E, /* 10baseT */							   0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},  {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,							0x1B01, 0x0000, /* 10base2,   CSR12 0x1B */							0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ 							0x0B00, 0x009E, /* 10baseT,   CSR12 0x0B */   }},  {0, 0, 0, 0, {}}};static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};#define EEPROM_SIZE 128#if defined(__i386__)#define get_u16(ptr) (*(u16 *)(ptr))#else#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))#endifstatic void parse_eeprom(struct device *dev){	/* The last media info list parsed, for multiport boards.  */	static struct mediatable *last_mediatable = NULL;	static unsigned char *last_ee_data = NULL;	static int controller_index = 0;	struct tulip_private *tp = (struct tulip_private *)dev->priv;	long ioaddr = dev->base_addr;	unsigned char *ee_data = tp->eeprom;	int i;	tp->mtable = 0;	for (i = 0; i < EEPROM_SIZE/2; i++)		((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);	/* Detect an old-style (SA only) EEPROM layout:	   memcmp(eedata, eedata+16, 8). */	for (i = 0; i < 8; i ++)		if (ee_data[i] != ee_data[16+i])			break;	if (i >= 8) {		if (ee_data[0] == 0xff) {			if (last_mediatable) {				controller_index++;				printk(KERN_INFO "%s:  Controller %d of multiport board.\n",					   dev->name, controller_index);				tp->mtable = last_mediatable;				ee_data = last_ee_data;				goto subsequent_board;			} else				printk(KERN_INFO "%s:  Missing EEPROM, this interface may "					   "not work correctly!\n",			   dev->name);			return;		}	  /* Do a fix-up based on the vendor half of the station address prefix. */	  for (i = 0; eeprom_fixups[i].name; i++) {		if (dev->dev_addr[0] == eeprom_fixups[i].addr0			&&  dev->dev_addr[1] == eeprom_fixups[i].addr1			&&  dev->dev_addr[2] == eeprom_fixups[i].addr2) {		  if (dev->dev_addr[2] == 0xE8  &&  ee_data[0x1a] == 0x55)			  i++;			/* An Accton EN1207, not an outlaw Maxtech. */		  memcpy(ee_data + 26, eeprom_fixups[i].newtable,				 sizeof(eeprom_fixups[i].newtable));		  printk(KERN_INFO "%s: Old format EEPROM on '%s' board.  Using"				 " substitute media control info.\n",				 dev->name, eeprom_fixups[i].name);		  break;		}	  }	  if (eeprom_fixups[i].name == NULL) { /* No fixup found. */		printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n",			   dev->name);		return;	  }	}	if (tulip_debug > 1) {	  printk(KERN_DEBUG "read_eeprom:");	  for (i = 0; i < 64; i++) {		printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ",			   read_eeprom(ioaddr, i));	  }	  printk("\n");	}		controller_index = 0;	if (ee_data[19] > 1) {		/* Multiport board. */		last_ee_data = ee_data;	}subsequent_board:	if (ee_data[27] == 0) {		/* No valid media table. */	} else if (tp->chip_id == DC21041) {		unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];		short media;		int count;		media = get_u16(p);		p += 2;		count = *p++;		printk(KERN_INFO "%s:21041 Media information at %d, default media "			   "%4.4x (%s).\n", dev->name, ee_data[27], media,			   media & 0x0800 ? "Autosense" : medianame[media & 15]);		for (i = 0; i < count; i++) {			unsigned char media_code = *p++;			u16 csrvals[3];			int idx;			for (idx = 0; idx < 3; idx++) {				csrvals[idx] = get_u16(p);				p += 2;			}			if (media_code & 0x40) {				printk(KERN_INFO "%s:  21041 media %2.2x (%s),"					   " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",					   dev->name, media_code & 15, medianame[media_code & 15],					   csrvals[0], csrvals[1], csrvals[2]);			} else				printk(KERN_INFO "%s:  21041 media #%d, %s.\n",					   dev->name, media_code & 15, medianame[media_code & 15]);		}	} else {		unsigned char *p = (void *)ee_data + ee_data[27];		unsigned char csr12dir = 0;		int count;		struct mediatable *mtable;		u16 media = get_u16(p);		p += 2;		if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)			csr12dir = *p++;		count = *p++;		mtable = (struct mediatable *)			kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),					GFP_KERNEL);		if (mtable == NULL)			return;				/* Horrible, impossible failure. */		last_mediatable = tp->mtable = mtable;		mtable->defaultmedia = media;		mtable->leafcount = count;		mtable->csr12dir = csr12dir;		mtable->has_nonmii = mtable->has_mii = 0;		printk(KERN_INFO "%s:  EEPROM default media type %s.\n", dev->name,			   media & 0x0800 ? "Autosense" : medianame[media & 15]);		for (i = 0; i < count; i++) {			struct medialeaf *leaf = &mtable->mleaf[i];						if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */				leaf->type = 0;				leaf->media = p[0] & 0x3f;				leaf->leafdata = p;				if ((p[2] & 0x61) == 0x01)	/* Bogus, but Znyx boards do it. */					mtable->has_mii = 1;				p += 4;			} else {				leaf->type = p[1];				if (p[1] & 1) {					mtable->has_mii = 1;					leaf->media = 11;				} else {					mtable->has_nonmii = 1;					leaf->media = p[2] & 0x0f;				}				leaf->leafdata = p + 2;				p += (p[0] & 0x3f) + 1;			}			if (tulip_debug > 1  &&  leaf->media == 11) {				unsigned char *bp = leaf->leafdata;				printk(KERN_INFO "%s:  MII interface PHY %d, setup/reset "					   "sequences %d/%d long, capabilities %2.2x %2.2x.\n",					   dev->name, bp[0], bp[1], bp[1 + bp[1]*2],					   bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);			}			printk(KERN_INFO "%s:  Index #%d - Media %s (#%d) described "				   "by a %s (%d) block.\n",				   dev->name, i, medianame[leaf->media], leaf->media,				   block_name[leaf->type], leaf->type);		}	}}/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*//*  EEPROM_Ctrl bits. */#define EE_SHIFT_CLK	0x02	/* EEPROM shift clock. */#define EE_CS			0x01	/* EEPROM chip select. */#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */#define EE_WRITE_0		0x01#define EE_WRITE_1		0x05#define EE_DATA_READ	0x08	/* EEPROM chip data out. */#define EE_ENB			(0x4800 | EE_CS)/* Delay between EEPROM clock transitions.   The 1.2 code is a "nasty" timing loop, but PC compatible machines are   *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro.  */#ifdef _LINUX_DELAY_H#define eeprom_delay(nanosec)	udelay((nanosec + 999)/1000)#else#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)#endif/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD	(5 << 6)#define EE_READ_CMD		(6 << 6)#define EE_ERASE_CMD	(7 << 6)static int read_eeprom(long ioaddr, int location){	int i;	unsigned short retval = 0;	long ee_addr = ioaddr + CSR9;	int read_cmd = location | EE_READ_CMD;		outl(EE_ENB & ~EE_CS, ee_addr);	outl(EE_ENB, ee_addr);		/* Shift the read command bits out. */	for (i = 10; i >= 0; i--) {		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;		outl(EE_ENB | dataval, ee_addr);		eeprom_delay(100);		outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);		eeprom_delay(150);		outl(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */		eeprom_delay(250);	}	outl(EE_ENB, ee_addr);		for (i = 16; i > 0; i--) {		outl(EE_ENB | EE_SHIFT_CLK, ee_addr);		eeprom_delay(100);		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);		outl(EE_ENB, ee_addr);		eeprom_delay(100);	}	/* Terminate the EEPROM access. */	outl(EE_ENB & ~EE_CS, ee_addr);	return retval;}/* MII transceiver control section.   Read and write the MII registers using software-generated serial   MDIO protocol.  See the MII specifications or DP83840A data sheet   for details. *//* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually   met by back-to-back PCI I/O cycles, but we insert a delay to avoid   "overclocking" issues or future 66Mhz PCI. */#define mdio_delay() inl(mdio_addr)/* Read and write the MII registers using software-generated serial   MDIO protocol.  It is just different enough from the EEPROM protocol   to not share code.  The maxium data clock rate is 2.5 Mhz. */#define MDIO_SHIFT_CLK	0x10000#define MDIO_DATA_WRITE0 0x00000#define MDIO_DATA_WRITE1 0x20000#define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */#define MDIO_ENB_IN		0x40000#define MDIO_DATA_READ	0x80000static int mdio_read(struct device *dev, int phy_id, int location){	struct tulip_private *tp = (struct tulip_private *)dev->priv;	int i;	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int retval = 0;	long mdio_addr = dev->base_addr + CSR9;	if (tp->chip_id == LC82C168) {		long ioaddr = dev->base_addr;		int i = 1000;		outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);		while (--i > 0)			if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))				return retval & 0xffff;		return 0xffff;	}	/* Establish sync by sending at least 32 logic ones. */ 	for (i = 32; i >= 0; i--) {		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);		mdio_delay();		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	/* Shift the read command bits out. */	for (i = 15; i >= 0; i--) {		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;		outl(MDIO_ENB | dataval, mdio_addr);		mdio_delay();		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		outl(MDIO_ENB_IN, mdio_addr);		mdio_delay();		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	return (retval>>1) & 0xffff;}static void mdio_write(struct device *dev, int phy_id, int location, int value){	struct tulip_private *tp = (struct tulip_private *)dev->priv;	int i;	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;	long mdio_addr = dev->base_addr + CSR9;	if (tp->chip_id == LC82C168) {		long ioaddr = dev->base_addr;		int i = 1000;		outl(cmd, ioaddr + 0xA0);		do			if ( ! (inl(ioaddr + 0xA0) & 0x80000000))				break;		while (--i > 0);		return;	}	/* Establish sync by sending 32 logic ones. */ 	for (i = 32; i >= 0; i--) {		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);		mdio_delay();		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;		outl(MDIO_ENB | dataval, mdio_addr);		mdio_delay();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -