📄 dmfe.c
字号:
/*
Process op-mode
AUTO mode : PHY controller in Auto-negotiation Mode
Force mode: PHY controller in force mode with HUB
N-way force capability with SWITCH
*/
static void dmfe_process_mode(struct dmfe_board_info *db)
{
u16 phy_reg;
/* Full Duplex Mode Check */
if (db->op_mode & 0x4)
db->cr6_data |= CR6_FDM; /* Set Full Duplex Bit */
else
db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */
/* Transciver Selection */
if (db->op_mode & 0x10) /* 1M HomePNA */
db->cr6_data|=0x40000; /* External MII select */
else
db->cr6_data&=~0x40000; /* Internal 10/100 transciver */
update_cr6(db->cr6_data, db->ioaddr);
/* 10/100M phyxcer force mode need */
if ( !(db->media_mode & 0x18)) /* Skip for AUTO mode or HomePNA */
{ /* Forece Mode */
phy_reg=phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
if ( !(phy_reg & 0x1) )
{
/* parter without N-Way capability */
phy_reg=0x0;
switch(db->op_mode)
{
case DMFE_10MHF: phy_reg=0x0; break;
case DMFE_10MFD: phy_reg=0x100; break;
case DMFE_100MHF: phy_reg=0x2000; break;
case DMFE_100MFD: phy_reg=0x2100; break;
}
phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
if ( db->chip_type && (db->chip_id==PCI_DM9102_ID) )
mdelay(20);
phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
}
}
}
/*
Write a word to Phy register
*/
static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
{
u16 i;
u32 ioaddr;
if (chip_id == PCI_DM9132_ID)
{
ioaddr=iobase+0x80+offset*4;
outw(phy_data, ioaddr);
}
else
{
/* DM9102/DM9102A Chip */
ioaddr=iobase+DCR9;
/* Send 33 synchronization clock to Phy controller */
for (i=0; i<35; i++)
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send start command(01) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_0);
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send write command(01) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_0);
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send Phy addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(ioaddr, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
/* Send register addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(ioaddr, offset&i ? PHY_DATA_1: PHY_DATA_0);
/* written trasnition */
phy_write_1bit(ioaddr, PHY_DATA_1);
phy_write_1bit(ioaddr, PHY_DATA_0);
/* Write a word data to PHY controller */
for (i=0x8000; i>0; i>>=1)
phy_write_1bit(ioaddr, phy_data&i ? PHY_DATA_1: PHY_DATA_0);
}
}
/*
Read a word data from phy register
*/
static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id)
{
int i;
u16 phy_data;
u32 ioaddr;
if (chip_id == PCI_DM9132_ID)
{
/* DM9132 Chip */
ioaddr=iobase+0x80+offset*4;
phy_data=inw(ioaddr);
}
else
{
/* DM9102/DM9102A Chip */
ioaddr=iobase+DCR9;
/* Send 33 synchronization clock to Phy controller */
for (i=0; i<35; i++)
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send start command(01) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_0);
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send read command(10) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_1);
phy_write_1bit(ioaddr, PHY_DATA_0);
/* Send Phy addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(ioaddr, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
/* Send register addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(ioaddr, offset&i ? PHY_DATA_1: PHY_DATA_0);
/* Skip transition state */
phy_read_1bit(ioaddr);
/* read 16bit data */
for (phy_data=0, i=0; i<16; i++)
{
phy_data<<=1;
phy_data|=phy_read_1bit(ioaddr);
}
}
return phy_data;
}
/*
Write one bit data to Phy Controller
*/
static void phy_write_1bit(u32 ioaddr, u32 phy_data)
{
outl(phy_data, ioaddr); /* MII Clock Low */
DELAY_1US;
outl(phy_data|MDCLKH, ioaddr); /* MII Clock High */
DELAY_1US;
outl(phy_data, ioaddr); /* MII Clock Low */
DELAY_1US;
}
/*
Read one bit phy data from PHY controller
*/
static u16 phy_read_1bit(u32 ioaddr)
{
u16 phy_data;
outl(0x50000, ioaddr);
DELAY_1US;
phy_data=(inl(ioaddr)>>19) & 0x1;
outl(0x40000, ioaddr);
DELAY_1US;
return phy_data;
}
/*
Calculate the CRC valude of the Rx packet
flag = 1 : return the reverse CRC (for the received packet CRC)
0 : return the normal CRC (for Hash Table index)
*/
unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
{
unsigned long Crc = 0xffffffff;
while (Len--) {
Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
}
if (flag)
return ~Crc;
else
return Crc;
}
/*
Parser SROM and media mode
*/
static void dmfe_parse_srom(struct dmfe_board_info * db)
{
char * srom=db->srom;
int dmfe_mode, tmp_reg;
DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
/* Init CR15 */
db->cr15_data=CR15_DEFAULT;
/* Check SROM Version */
if ( ((int)srom[18] & 0xff) == SROM_V41_CODE)
{ /* SROM V4.01 */
/* Get NIC support media mode */
db->NIC_capability=*(u16 *)(&srom[34]);
db->PHY_reg4=0;
for (tmp_reg=1; tmp_reg<0x10; tmp_reg<<=1)
{
switch( db->NIC_capability & tmp_reg )
{
case 0x1: db->PHY_reg4|=0x0020; break;
case 0x2: db->PHY_reg4|=0x0040; break;
case 0x4: db->PHY_reg4|=0x0080; break;
case 0x8: db->PHY_reg4|=0x0100; break;
}
}
/* Media Mode Force or not check */
dmfe_mode=*((int *)&srom[34]) & *((int *)&srom[36]);
switch(dmfe_mode)
{
case 0x1: dmfe_media_mode=DMFE_10MHF; break; /* Select 10MHF */
case 0x4: dmfe_media_mode=DMFE_100MHF; break; /* Select 100MHF */
case 0x2: dmfe_media_mode=DMFE_10MFD; break; /* Select 10MFD */
case 0x8: dmfe_media_mode=DMFE_100MFD; break; /* Select 100MFD */
case 0x100:
case 0x200: dmfe_media_mode=DMFE_1M_HPNA; break; /* Select HomePNA */
}
/* Special Function setting */
/* VLAN function */
if ( (SF_mode & 0x1) || (srom[43] & 0x80) ) db->cr15_data|=0x40;
/* Flow Control */
if ( (SF_mode & 0x2) || (srom[40] & 0x1) ) db->cr15_data|=0x400;
/* TX pause packet */
if ( (SF_mode & 0x4) || (srom[40] & 0xe) ) db->cr15_data|=0x9800;
}
/* Parse HPNA parameter */
db->HPNA_command=1;
/* Accept remote command or not */
if (HPNA_rx_cmd==0)
db->HPNA_command |= 0x8000;
/* Issue remote command & operation mode */
if (HPNA_tx_cmd==1)
switch(HPNA_mode) /* Issue Remote Command */
{
case 0: db->HPNA_command |= 0x0904; break;
case 1: db->HPNA_command |= 0x0a00; break;
case 2: db->HPNA_command |= 0x0506; break;
case 3: db->HPNA_command |= 0x0602; break;
}
else
switch(HPNA_mode) /* Don't Issue */
{
case 0: db->HPNA_command |= 0x0004; break;
case 1: db->HPNA_command |= 0x0000; break;
case 2: db->HPNA_command |= 0x0006; break;
case 3: db->HPNA_command |= 0x0002; break;
}
/* Check DM9801 or DM9802 present or not */
db->HPNA_present=0;
update_cr6(db->cr6_data|0x40000, db->ioaddr);
tmp_reg=phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
if ( (tmp_reg&0xfff0) == 0xb900 )
{
/* DM9801 or DM9802 present */
db->HPNA_timer=8; /* Check remote device status after 8 second */
if (phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id)==0x4404)
{/* DM9801 HomeRun */
db->HPNA_present=1;
dmfe_program_DM9801(db, tmp_reg);
}
else
{/* DM9802 LongRun */
db->HPNA_present=2;
dmfe_program_DM9802(db);
}
}
}
/* Description:
Init HomeRun DM9801
*/
static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
{
uint reg17, reg25;
if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
switch(HPNA_rev) {
case 0xb900: /* DM9801 E3 */
db->HPNA_command |= 0x1000;
reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
break;
case 0xb901: /* DM9801 E4 */
reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
break;
case 0xb902: /* DM9801 E5 */
case 0xb903: /* DM9801 E6 */
default:
db->HPNA_command |= 0x1000;
reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
break;
}
phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
}
/* Description:
Init HomeRun DM9802
*/
static void dmfe_program_DM9802(struct dmfe_board_info * db)
{
uint phy_reg;
if (!HPNA_NoiseFloor) HPNA_NoiseFloor=DM9802_NOISE_FLOOR;
phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
phy_reg=phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
phy_reg= ( phy_reg & 0xff00) + HPNA_NoiseFloor;
phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
}
/* Description:
Check remote HPNA power and speed status. If not correct,
issue command again.
*/
static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
{
uint phy_reg;
/* Got remote device status */
phy_reg=phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
switch(phy_reg)
{
case 0x00: phy_reg=0x0a00;break; /* LP/LS */
case 0x20: phy_reg=0x0900;break; /* LP/HS */
case 0x40: phy_reg=0x0600;break; /* HP/LS */
case 0x60: phy_reg=0x0500;break; /* HP/HS */
}
/* Check remote device status match our setting ot not */
if ( phy_reg != (db->HPNA_command & 0x0f00) )
{
phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
db->HPNA_timer=8;
}
else
db->HPNA_timer=600; /* Match, every 10 minutes, check */
}
#ifdef MODULE
#if LINUX_VERSION_CODE > 0x20118
MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
MODULE_LICENSE("GPL");
MODULE_PARM(debug, "i");
MODULE_PARM(mode, "i");
MODULE_PARM(cr6set, "i");
MODULE_PARM(chkmode, "i");
MODULE_PARM(HPNA_mode, "i");
MODULE_PARM(HPNA_rx_cmd, "i");
MODULE_PARM(HPNA_tx_cmd, "i");
MODULE_PARM(HPNA_NoiseFloor, "i");
MODULE_PARM(SF_mode, "i");
#endif
/* Description:
when user used insmod to add module, system invoked init_module()
to initilize and register.
*/
int init_module(void)
{
DMFE_DBUG(0, "init_module() ", debug);
if (debug) dmfe_debug=debug; /* set debug flag */
if (cr6set) dmfe_cr6_user_set=cr6set;
switch(mode)
{
case DMFE_10MHF:
case DMFE_100MHF:
case DMFE_10MFD:
case DMFE_100MFD:
case DMFE_1M_HPNA:
dmfe_media_mode=mode;
break;
default:dmfe_media_mode=DMFE_AUTO;
break;
}
if (HPNA_mode>4) HPNA_mode=0; /* Default: LP/HS */
if (HPNA_rx_cmd>1) HPNA_rx_cmd=0; /* Default: Ignored remote command */
if (HPNA_tx_cmd>1) HPNA_tx_cmd=0; /* Default: Don't issue remote command */
if (HPNA_NoiseFloor > 15)
HPNA_NoiseFloor = 0;
return dmfe_probe(0); /* search board and register */
}
/* Description:
when user used rmmod to delete mod
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -