/****************************************************************************** Copyright (c) 2004, Infineon Technologies. All rights reserved. No Warranty Because the program is licensed free of charge, there is no warranty for the program, to the extent permitted by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the program "as is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the program is with you. should the program prove defective, you assume the cost of all necessary servicing, repair or correction. In no event unless required by applicable law or agreed to in writing will any copyright holder, or any other party who may modify and/or redistribute the program as permitted above, be liable to you for damages, including any general, special, incidental or consequential damages arising out of the use or inability to use the program (including but not limited to loss of data or data being rendered inaccurate or losses sustained by you or third parties or a failure of the program to operate with any other programs), even if such holder or other party has been advised of the possibility of such damages. ****************************************************************************** Module : admmod.c Date : 2004-09-01 Description : JoeLin Remarks: Revision: MarsLin, add to support VLAN *****************************************************************************/ //000001.joelin 2005/06/02 add"ADM6996_MDC_MDIO_MODE" define, // if define ADM6996_MDC_MDIO_MODE==> ADM6996LC and ADM6996I will be in MDIO/MDC(SMI)(16 bit) mode, // amazon should contrl ADM6996 by MDC/MDIO pin // if undef ADM6996_MDC_MDIO_MODE==> ADM6996 will be in EEProm(32 bit) mode, // amazon should contrl ADM6996 by GPIO15,16,17,18 pin /* 507281:linmars 2005/07/28 support MDIO/EEPROM config mode */ /* 509201:linmars remove driver testing codes */ #include #include #include #include #include #include #include #include #include #include //#include unsigned int ifx_sw_conf[ADM_SW_MAX_PORT_NUM+1] = \ {ADM_SW_PORT0_CONF, ADM_SW_PORT1_CONF, ADM_SW_PORT2_CONF, \ ADM_SW_PORT3_CONF, ADM_SW_PORT4_CONF, ADM_SW_PORT5_CONF}; unsigned int ifx_sw_bits[8] = \ {0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff}; unsigned int ifx_sw_vlan_port[6] = {0, 2, 4, 6, 7, 8}; //050613:fchang /* 507281:linmars start */ #ifdef CONFIG_SWITCH_ADM6996_MDIO #define ADM6996_MDC_MDIO_MODE 1 //000001.joelin #else #undef ADM6996_MDC_MDIO_MODE #endif /* 507281:linmars end */ #define adm6996i 0 #define adm6996lc 1 #define adm6996l 2 unsigned int adm6996_mode=adm6996i; /* initialize GPIO pins. output mode, low */ void ifx_gpio_init(void) { //GPIO16,17,18 direction:output //GPIO16,17,18 output 0 AMAZON_SW_REG(AMAZON_GPIO_P1_DIR) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC); AMAZON_SW_REG(AMAZON_GPIO_P1_OUT) =AMAZON_SW_REG(AMAZON_GPIO_P1_IN)& ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC); } /* read one bit from mdio port */ int ifx_sw_mdio_readbit(void) { //int val; //val = (AMAZON_SW_REG(GPIO_conf0_REG) & GPIO0_INPUT_MASK) >> 8; //return val; //GPIO16 return AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&1; } /* MDIO mode selection 1 -> output 0 -> input switch input/output mode of GPIO 0 */ void ifx_mdio_mode(int mode) { // AMAZON_SW_REG(GPIO_conf0_REG) = mode ? GPIO_ENABLEBITS : // ((GPIO_ENABLEBITS | MDIO_INPUT) & ~MDIO_OUTPUT_EN); mode?(AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)|=GPIO_MDIO): (AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)&=~GPIO_MDIO); /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_DIR); mode?(r|=GPIO_MDIO):(r&=~GPIO_MDIO); AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)=r;*/ } void ifx_mdc_hi(void) { //GPIO_SET_HI(GPIO_MDC); //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDC; /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT); r|=GPIO_MDC; AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/ AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDC; } void ifx_mdio_hi(void) { //GPIO_SET_HI(GPIO_MDIO); //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDIO; /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT); r|=GPIO_MDIO; AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/ AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDIO; } void ifx_mdcs_hi(void) { //GPIO_SET_HI(GPIO_MDCS); //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDCS; /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT); r|=GPIO_MDCS; AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/ AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDCS; } void ifx_mdc_lo(void) { //GPIO_SET_LOW(GPIO_MDC); //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDC; /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT); r&=~GPIO_MDC; AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/ AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDC); } void ifx_mdio_lo(void) { //GPIO_SET_LOW(GPIO_MDIO); //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDIO; /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT); r&=~GPIO_MDIO; AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/ AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDIO); } void ifx_mdcs_lo(void) { //GPIO_SET_LOW(GPIO_MDCS); //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDCS; /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT); r&=~GPIO_MDCS; AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/ AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDCS); } /* mdc pulse 0 -> 1 -> 0 */ static void ifx_sw_mdc_pulse(void) { ifx_mdc_lo(); udelay(ADM_SW_MDC_DOWN_DELAY); ifx_mdc_hi(); udelay(ADM_SW_MDC_UP_DELAY); ifx_mdc_lo(); } /* mdc toggle 1 -> 0 */ static void ifx_sw_mdc_toggle(void) { ifx_mdc_hi(); udelay(ADM_SW_MDC_UP_DELAY); ifx_mdc_lo(); udelay(ADM_SW_MDC_DOWN_DELAY); } /* enable eeprom write For ATC 93C66 type EEPROM; accessing ADM6996 internal EEPROM type registers */ static void ifx_sw_eeprom_write_enable(void) { unsigned int op; ifx_mdcs_lo(); ifx_mdc_lo(); ifx_mdio_hi(); udelay(ADM_SW_CS_DELAY); /* enable chip select */ ifx_mdcs_hi(); udelay(ADM_SW_CS_DELAY); /* start bit */ ifx_mdio_hi(); ifx_sw_mdc_pulse(); /* eeprom write enable */ op = ADM_SW_BIT_MASK_4; while (op) { if (op & ADM_SW_EEPROM_WRITE_ENABLE) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3); while (op) { ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* disable chip select */ ifx_mdcs_lo(); udelay(ADM_SW_CS_DELAY); ifx_sw_mdc_pulse(); } /* disable eeprom write */ static void ifx_sw_eeprom_write_disable(void) { unsigned int op; ifx_mdcs_lo(); ifx_mdc_lo(); ifx_mdio_hi(); udelay(ADM_SW_CS_DELAY); /* enable chip select */ ifx_mdcs_hi(); udelay(ADM_SW_CS_DELAY); /* start bit */ ifx_mdio_hi(); ifx_sw_mdc_pulse(); /* eeprom write disable */ op = ADM_SW_BIT_MASK_4; while (op) { if (op & ADM_SW_EEPROM_WRITE_DISABLE) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3); while (op) { ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* disable chip select */ ifx_mdcs_lo(); udelay(ADM_SW_CS_DELAY); ifx_sw_mdc_pulse(); } /* read registers from ADM6996 serial registers start at 0x200 (addr bit 9 = 1b) EEPROM registers -> 16bits; Serial registers -> 32bits */ #ifdef ADM6996_MDC_MDIO_MODE //smi mode//000001.joelin static int ifx_sw_read_adm6996i_smi(unsigned int addr, unsigned int *dat) { addr=(addr<<16)&0x3ff0000; AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) =(0xC0000000|addr); while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){}; *dat=((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x0FFFF); return 0; } #endif static int ifx_sw_read_adm6996i(unsigned int addr, unsigned int *dat) { unsigned int op; ifx_gpio_init(); ifx_mdcs_hi(); udelay(ADM_SW_CS_DELAY); ifx_mdcs_lo(); ifx_mdc_lo(); ifx_mdio_lo(); udelay(ADM_SW_CS_DELAY); /* preamble, 32 bit 1 */ ifx_mdio_hi(); op = ADM_SW_BIT_MASK_32; while (op) { ifx_sw_mdc_pulse(); op >>= 1; } /* command start (01b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_START) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* read command (10b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_READ) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* send address A9 ~ A0 */ op = ADM_SW_BIT_MASK_10; while (op) { if (op & addr) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* turnaround bits */ op = ADM_SW_BIT_MASK_2; ifx_mdio_hi(); while (op) { ifx_sw_mdc_pulse(); op >>= 1; } udelay(ADM_SW_MDC_DOWN_DELAY); /* set MDIO pin to input mode */ ifx_mdio_mode(ADM_SW_MDIO_INPUT); /* start read data */ *dat = 0; //adm6996i op = ADM_SW_BIT_MASK_32; op = ADM_SW_BIT_MASK_16;//adm6996i while (op) { *dat <<= 1; if (ifx_sw_mdio_readbit()) *dat |= 1; ifx_sw_mdc_toggle(); op >>= 1; } /* set MDIO to output mode */ ifx_mdio_mode(ADM_SW_MDIO_OUTPUT); /* dummy clock */ op = ADM_SW_BIT_MASK_4; ifx_mdio_lo(); while(op) { ifx_sw_mdc_pulse(); op >>= 1; } ifx_mdc_lo(); ifx_mdio_lo(); ifx_mdcs_hi(); /* EEPROM registers */ //adm6996i if (!(addr & 0x200)) //adm6996i { //adm6996i if (addr % 2) //adm6996i *dat >>= 16; //adm6996i else //adm6996i *dat &= 0xffff; //adm6996i } return 0; } //adm6996 static int ifx_sw_read_adm6996l(unsigned int addr, unsigned int *dat) { unsigned int op; ifx_gpio_init(); ifx_mdcs_hi(); udelay(ADM_SW_CS_DELAY); ifx_mdcs_lo(); ifx_mdc_lo(); ifx_mdio_lo(); udelay(ADM_SW_CS_DELAY); /* preamble, 32 bit 1 */ ifx_mdio_hi(); op = ADM_SW_BIT_MASK_32; while (op) { ifx_sw_mdc_pulse(); op >>= 1; } /* command start (01b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_START) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* read command (10b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_READ) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* send address A9 ~ A0 */ op = ADM_SW_BIT_MASK_10; while (op) { if (op & addr) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* turnaround bits */ op = ADM_SW_BIT_MASK_2; ifx_mdio_hi(); while (op) { ifx_sw_mdc_pulse(); op >>= 1; } udelay(ADM_SW_MDC_DOWN_DELAY); /* set MDIO pin to input mode */ ifx_mdio_mode(ADM_SW_MDIO_INPUT); /* start read data */ *dat = 0; op = ADM_SW_BIT_MASK_32; while (op) { *dat <<= 1; if (ifx_sw_mdio_readbit()) *dat |= 1; ifx_sw_mdc_toggle(); op >>= 1; } /* set MDIO to output mode */ ifx_mdio_mode(ADM_SW_MDIO_OUTPUT); /* dummy clock */ op = ADM_SW_BIT_MASK_4; ifx_mdio_lo(); while(op) { ifx_sw_mdc_pulse(); op >>= 1; } ifx_mdc_lo(); ifx_mdio_lo(); ifx_mdcs_hi(); /* EEPROM registers */ if (!(addr & 0x200)) { if (addr % 2) *dat >>= 16; else *dat &= 0xffff; } return 0; } static int ifx_sw_read(unsigned int addr, unsigned int *dat) { #ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin ifx_sw_read_adm6996i_smi(addr,dat); #else if (adm6996_mode==adm6996i) ifx_sw_read_adm6996i(addr,dat); else ifx_sw_read_adm6996l(addr,dat); #endif return 0; } /* write register to ADM6996 eeprom registers */ //for adm6996i -start #ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin static int ifx_sw_write_adm6996i_smi(unsigned int addr, unsigned int dat) { AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) = ((addr<<16)&0x3ff0000)|dat|0x80000000; while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){}; return 0; } #endif //ADM6996_MDC_MDIO_MODE //000001.joelin static int ifx_sw_write_adm6996i(unsigned int addr, unsigned int dat) { unsigned int op; ifx_gpio_init(); ifx_mdcs_hi(); udelay(ADM_SW_CS_DELAY); ifx_mdcs_lo(); ifx_mdc_lo(); ifx_mdio_lo(); udelay(ADM_SW_CS_DELAY); /* preamble, 32 bit 1 */ ifx_mdio_hi(); op = ADM_SW_BIT_MASK_32; while (op) { ifx_sw_mdc_pulse(); op >>= 1; } /* command start (01b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_START) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* write command (01b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_WRITE) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* send address A9 ~ A0 */ op = ADM_SW_BIT_MASK_10; while (op) { if (op & addr) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* turnaround bits */ op = ADM_SW_BIT_MASK_2; ifx_mdio_hi(); while (op) { ifx_sw_mdc_pulse(); op >>= 1; } udelay(ADM_SW_MDC_DOWN_DELAY); /* set MDIO pin to output mode */ ifx_mdio_mode(ADM_SW_MDIO_OUTPUT); /* start write data */ op = ADM_SW_BIT_MASK_16; while (op) { if (op & dat) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_toggle(); op >>= 1; } // /* set MDIO to output mode */ // ifx_mdio_mode(ADM_SW_MDIO_OUTPUT); /* dummy clock */ op = ADM_SW_BIT_MASK_4; ifx_mdio_lo(); while(op) { ifx_sw_mdc_pulse(); op >>= 1; } ifx_mdc_lo(); ifx_mdio_lo(); ifx_mdcs_hi(); /* EEPROM registers */ //adm6996i if (!(addr & 0x200)) //adm6996i { //adm6996i if (addr % 2) //adm6996i *dat >>= 16; //adm6996i else //adm6996i *dat &= 0xffff; //adm6996i } return 0; } //for adm6996i-end static int ifx_sw_write_adm6996l(unsigned int addr, unsigned int dat) { unsigned int op; ifx_gpio_init(); /* enable write */ ifx_sw_eeprom_write_enable(); /* chip select */ ifx_mdcs_hi(); udelay(ADM_SW_CS_DELAY); /* issue write command */ /* start bit */ ifx_mdio_hi(); ifx_sw_mdc_pulse(); /* EEPROM write command */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_EEPROM_WRITE) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_pulse(); op >>= 1; } /* send address A7 ~ A0 */ op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 1); while (op) { if (op & addr) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_toggle(); op >>= 1; } /* start write data */ op = ADM_SW_BIT_MASK_16; while (op) { if (op & dat) ifx_mdio_hi(); else ifx_mdio_lo(); ifx_sw_mdc_toggle(); op >>= 1; } /* disable cs & wait 1 clock */ ifx_mdcs_lo(); udelay(ADM_SW_CS_DELAY); ifx_sw_mdc_toggle(); ifx_sw_eeprom_write_disable(); return 0; } static int ifx_sw_write(unsigned int addr, unsigned int dat) { #ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin ifx_sw_write_adm6996i_smi(addr,dat); #else //000001.joelin if (adm6996_mode==adm6996i) ifx_sw_write_adm6996i(addr,dat); else ifx_sw_write_adm6996l(addr,dat); #endif //000001.joelin return 0; } /* do switch PHY reset */ int ifx_sw_reset(void) { /* reset PHY */ ifx_sw_write(ADM_SW_PHY_RESET, 0); return 0; } /* 509201:linmars start */ #if 0 /* check port status */ int ifx_check_port_status(int port) { unsigned int val; if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM)) { ifx_printf(("error on port number (%d)!!\n", port)); return -1; } ifx_sw_read(ifx_sw_conf[port], &val); if (ifx_sw_conf[port]%2) val >>= 16; /* only 16bits are effective */ val &= 0xFFFF; ifx_printf(("Port %d status (%.8x): \n", port, val)); if (val & ADM_SW_PORT_FLOWCTL) ifx_printf(("\t802.3x flow control supported!\n")); else ifx_printf(("\t802.3x flow control not supported!\n")); if (val & ADM_SW_PORT_AN) ifx_printf(("\tAuto negotiation ON!\n")); else ifx_printf(("\tAuto negotiation OFF!\n")); if (val & ADM_SW_PORT_100M) ifx_printf(("\tLink at 100M!\n")); else ifx_printf(("\tLink at 10M!\n")); if (val & ADM_SW_PORT_FULL) ifx_printf(("\tFull duplex!\n")); else ifx_printf(("\tHalf duplex!\n")); if (val & ADM_SW_PORT_DISABLE) ifx_printf(("\tPort disabled!\n")); else ifx_printf(("\tPort enabled!\n")); if (val & ADM_SW_PORT_TOS) ifx_printf(("\tTOS enabled!\n")); else ifx_printf(("\tTOS disabled!\n")); if (val & ADM_SW_PORT_PPRI) ifx_printf(("\tPort priority first!\n")); else ifx_printf(("\tVLAN or TOS priority first!\n")); if (val & ADM_SW_PORT_MDIX) ifx_printf(("\tAuto MDIX!\n")); else ifx_printf(("\tNo auto MDIX\n")); ifx_printf(("\tPVID: %d\n", \ ((val >> ADM_SW_PORT_PVID_SHIFT)&ifx_sw_bits[ADM_SW_PORT_PVID_BITS]))); return 0; } /* initialize a VLAN clear all VLAN bits */ int ifx_sw_vlan_init(int vlanid) { ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, 0); return 0; } /* add a port to certain vlan */ int ifx_sw_vlan_add(int port, int vlanid) { int reg = 0; if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) || (vlanid > ADM_SW_MAX_VLAN_NUM)) { ifx_printf(("Port number or VLAN number ERROR!!\n")); return -1; } ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, ®); reg |= (1 << ifx_sw_vlan_port[port]); ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg); return 0; } /* delete a given port from certain vlan */ int ifx_sw_vlan_del(int port, int vlanid) { unsigned int reg = 0; if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) || (vlanid > ADM_SW_MAX_VLAN_NUM)) { ifx_printf(("Port number or VLAN number ERROR!!\n")); return -1; } ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, ®); reg &= ~(1 << ifx_sw_vlan_port[port]); ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg); return 0; } /* default VLAN setting port 0~3 as untag port and PVID = 1 VLAN1: port 0~3 and port 5 (MII) */ static int ifx_sw_init(void) { ifx_printf(("Setting default ADM6996 registers... \n")); /* MAC clone, 802.1q based VLAN */ ifx_sw_write(ADM_SW_VLAN_MODE, 0xff30); /* auto MDIX, PVID=1, untag */ ifx_sw_write(ADM_SW_PORT0_CONF, 0x840f); ifx_sw_write(ADM_SW_PORT1_CONF, 0x840f); ifx_sw_write(ADM_SW_PORT2_CONF, 0x840f); ifx_sw_write(ADM_SW_PORT3_CONF, 0x840f); /* auto MDIX, PVID=2, untag */ ifx_sw_write(ADM_SW_PORT5_CONF, 0x880f); /* port 0~3 & 5 as VLAN1 */ ifx_sw_write(ADM_SW_VLAN0_CONF+1, 0x0155); return 0; } #endif /* 509201:linmars end */ int adm_open(struct inode *node, struct file *filp) { MOD_INC_USE_COUNT; return 0; } ssize_t adm_read(struct file *filep, char *buf, size_t count, loff_t *ppos) { return count; } ssize_t adm_write(struct file *filep, const char *buf, size_t count, loff_t *ppos) { return count; } /* close */ int adm_release(struct inode *inode, struct file *filp) { MOD_DEC_USE_COUNT; return 0; } /* IOCTL function */ int adm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long args) { PREGRW uREGRW; unsigned int rtval; unsigned int val; //6996i unsigned int control[6] ; //6996i unsigned int status[6] ; //6996i PMACENTRY mMACENTRY;//adm6996i PPROTOCOLFILTER uPROTOCOLFILTER ;///adm6996i if (_IOC_TYPE(cmd) != ADM_MAGIC) { printk("adm_ioctl: IOC_TYPE(%x) != ADM_MAGIC(%x)! \n", _IOC_TYPE(cmd), ADM_MAGIC); return (-EINVAL); } if(_IOC_NR(cmd) >= KEY_IOCTL_MAX_KEY) { printk(KERN_WARNING "adm_ioctl: IOC_NR(%x) invalid! \n", _IOC_NR(cmd)); return (-EINVAL); } switch (cmd) { case ADM_IOCTL_REGRW: { uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL); rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW)); if (rtval != 0) { printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n"); return (-EFAULT); } switch(uREGRW->mode) { case REG_READ: uREGRW->value = 0x12345678;//inl(uREGRW->addr); copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW)); break; case REG_WRITE: //outl(uREGRW->value, uREGRW->addr); break; default: printk("No such Register Read/Write function!! \n"); return (-EFAULT); } kfree(uREGRW); break; } case ADM_SW_IOCTL_REGRW: { unsigned int val = 0xff; uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL); rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW)); if (rtval != 0) { printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n"); return (-EFAULT); } switch(uREGRW->mode) { case REG_READ: ifx_sw_read(uREGRW->addr, &val); uREGRW->value = val; copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW)); break; case REG_WRITE: ifx_sw_write(uREGRW->addr, uREGRW->value); break; default: printk("No such Register Read/Write function!! \n"); return (-EFAULT); } kfree(uREGRW); break; } /* 509201:linmars start */ #if 0 case ADM_SW_IOCTL_PORTSTS: for (rtval = 0; rtval < ADM_SW_MAX_PORT_NUM+1; rtval++) ifx_check_port_status(rtval); break; case ADM_SW_IOCTL_INIT: ifx_sw_init(); break; #endif /* 509201:linmars end */ //adm6996i case ADM_SW_IOCTL_MACENTRY_ADD: case ADM_SW_IOCTL_MACENTRY_DEL: case ADM_SW_IOCTL_MACENTRY_GET_INIT: case ADM_SW_IOCTL_MACENTRY_GET_MORE: mMACENTRY = (PMACENTRY)kmalloc(sizeof(MACENTRY), GFP_KERNEL); rtval = copy_from_user(mMACENTRY, (PMACENTRY)args, sizeof(MACENTRY)); if (rtval != 0) { printk("ADM_SW_IOCTL_MACENTRY: copy from user FAILED!! \n"); return (-EFAULT); } control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0] ; control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2] ; control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4] ; control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4); if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control else control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) { //initial the pointer to the first address val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } control[5]=0x030;//initial the first address ifx_sw_write(0x11f,control[5]); val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } } //if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) control[5]=0x02c;//search by the mac address field val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } ifx_sw_write(0x11a,control[0]); ifx_sw_write(0x11b,control[1]); ifx_sw_write(0x11c,control[2]); ifx_sw_write(0x11d,control[3]); ifx_sw_write(0x11e,control[4]); ifx_sw_write(0x11f,control[5]); val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } val=((val&0x7000)>>12);//result ,status5[14:12] mMACENTRY->result=val; if (!val) { printk(" Command OK!! \n"); if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) { ifx_sw_read(0x120,&(status[0])); ifx_sw_read(0x121,&(status[1])); ifx_sw_read(0x122,&(status[2])); ifx_sw_read(0x123,&(status[3])); ifx_sw_read(0x124,&(status[4])); ifx_sw_read(0x125,&(status[5])); mMACENTRY->mac_addr[0]=(status[0]&0x00ff) ; mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8 ; mMACENTRY->mac_addr[2]=(status[1]&0x00ff) ; mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ; mMACENTRY->mac_addr[4]=(status[2]&0x00ff) ; mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ; mMACENTRY->fid=(status[3]&0xf); mMACENTRY->portmap=((status[3]>>4)&0x3f); if (status[5]&0x2) {//static info_ctrl //status5[1]???? mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff); mMACENTRY->info_type=1; } else {//not static age_timer mMACENTRY->ctrl.age_timer=(status[4]&0x00ff); mMACENTRY->info_type=0; } //status5[13]???? mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1] mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ??? mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2] }//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) } else if (val==0x001) printk(" All Entry Used!! \n"); else if (val==0x002) printk(" Entry Not Found!! \n"); else if (val==0x003) printk(" Try Next Entry!! \n"); else if (val==0x005) printk(" Command Error!! \n"); else printk(" UnKnown Error!! \n"); copy_to_user((PMACENTRY)args, mMACENTRY,sizeof(MACENTRY)); break; case ADM_SW_IOCTL_FILTER_ADD: case ADM_SW_IOCTL_FILTER_DEL: case ADM_SW_IOCTL_FILTER_GET: uPROTOCOLFILTER = (PPROTOCOLFILTER)kmalloc(sizeof(PROTOCOLFILTER), GFP_KERNEL); rtval = copy_from_user(uPROTOCOLFILTER, (PPROTOCOLFILTER)args, sizeof(PROTOCOLFILTER)); if (rtval != 0) { printk("ADM_SW_IOCTL_FILTER_ADD: copy from user FAILED!! \n"); return (-EFAULT); } if(cmd==ADM_SW_IOCTL_FILTER_DEL) { //delete filter uPROTOCOLFILTER->ip_p=00; //delet filter uPROTOCOLFILTER->action=00; //delete filter } //delete filter ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7 if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){ if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p } else { if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p } if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7 ifx_sw_read(0x95, &val); //protocol filter action if(cmd==ADM_SW_IOCTL_FILTER_GET) { uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action copy_to_user((PPROTOCOLFILTER)args, uPROTOCOLFILTER, sizeof(PROTOCOLFILTER)); } else { val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2)); // printk("%d----\n",val); ifx_sw_write(0x95, val); //write protocol filter action } break; //adm6996i /* others */ default: return -EFAULT; } /* end of switch */ return 0; } /* Santosh: handle IGMP protocol filter ADD/DEL/GET */ int adm_process_protocol_filter_request (unsigned int cmd, PPROTOCOLFILTER uPROTOCOLFILTER) { unsigned int val; //6996i if(cmd==ADM_SW_IOCTL_FILTER_DEL) { //delete filter uPROTOCOLFILTER->ip_p=00; //delet filter uPROTOCOLFILTER->action=00; //delete filter } //delete filter ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7 if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){ if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p } else { if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p } if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7 ifx_sw_read(0x95, &val); //protocol filter action if(cmd==ADM_SW_IOCTL_FILTER_GET) { uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action } else { val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2)); ifx_sw_write(0x95, val); //write protocol filter action } return 0; } /* Santosh: function for MAC ENTRY ADD/DEL/GET */ int adm_process_mac_table_request (unsigned int cmd, PMACENTRY mMACENTRY) { unsigned int rtval; unsigned int val; //6996i unsigned int control[6] ; //6996i unsigned int status[6] ; //6996i // printk ("adm_process_mac_table_request: enter\n"); control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0] ; control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2] ; control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4] ; control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4); if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control else control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) { //initial the pointer to the first address val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } control[5]=0x030;//initial the first address ifx_sw_write(0x11f,control[5]); val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } } //if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) control[5]=0x02c;//search by the mac address field val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } ifx_sw_write(0x11a,control[0]); ifx_sw_write(0x11b,control[1]); ifx_sw_write(0x11c,control[2]); ifx_sw_write(0x11d,control[3]); ifx_sw_write(0x11e,control[4]); ifx_sw_write(0x11f,control[5]); val=0x8000;//busy ,status5[15] while(val&0x8000){ //check busy ? ifx_sw_read(0x125, &val); } val=((val&0x7000)>>12);//result ,status5[14:12] mMACENTRY->result=val; if (!val) { printk(" Command OK!! \n"); if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) { ifx_sw_read(0x120,&(status[0])); ifx_sw_read(0x121,&(status[1])); ifx_sw_read(0x122,&(status[2])); ifx_sw_read(0x123,&(status[3])); ifx_sw_read(0x124,&(status[4])); ifx_sw_read(0x125,&(status[5])); mMACENTRY->mac_addr[0]=(status[0]&0x00ff) ; mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8 ; mMACENTRY->mac_addr[2]=(status[1]&0x00ff) ; mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ; mMACENTRY->mac_addr[4]=(status[2]&0x00ff) ; mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ; mMACENTRY->fid=(status[3]&0xf); mMACENTRY->portmap=((status[3]>>4)&0x3f); if (status[5]&0x2) {//static info_ctrl //status5[1]???? mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff); mMACENTRY->info_type=1; } else {//not static age_timer mMACENTRY->ctrl.age_timer=(status[4]&0x00ff); mMACENTRY->info_type=0; } //status5[13]???? mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1] mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ??? mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2] }//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) } else if (val==0x001) printk(" All Entry Used!! \n"); else if (val==0x002) printk(" Entry Not Found!! \n"); else if (val==0x003) printk(" Try Next Entry!! \n"); else if (val==0x005) printk(" Command Error!! \n"); else printk(" UnKnown Error!! \n"); // printk ("adm_process_mac_table_request: Exit\n"); return 0; } /* Santosh: End of function for MAC ENTRY ADD/DEL*/ struct file_operations adm_ops = { read: adm_read, write: adm_write, open: adm_open, release: adm_release, ioctl: adm_ioctl }; int adm_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; len += sprintf(buf+len, " ************ Registers ************ \n"); *eof = 1; return len; } int __init init_adm6996_module(void) { unsigned int val = 000; unsigned int val1 = 000; printk("Loading ADM6996 driver... \n"); /* if running on adm5120 */ /* set GPIO 0~2 as adm6996 control pins */ //outl(0x003f3f00, 0x12000028); /* enable switch port 5 (MII) as RMII mode (5120MAC <-> 6996MAC) */ //outl(0x18a, 0x12000030); /* group adm5120 port 1 ~ 5 as VLAN0, port 5 & 6(CPU) as VLAN1 */ //outl(0x417e, 0x12000040); /* end adm5120 fixup */ #ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin register_chrdev(69, "adm6996", &adm_ops); AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x27be; AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xfc; adm6996_mode=adm6996i; ifx_sw_read(0xa0, &val); ifx_sw_read(0xa1, &val1); val=((val1&0x0f)<<16)|val; printk ("\nADM6996 SMI Mode-"); printk ("Chip ID:%5x \n ", val); #else //000001.joelin AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x2c50; AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xff; AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL0) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC); AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL1) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC); AMAZON_SW_REG(AMAZON_GPIO_P1_OD) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC); ifx_gpio_init(); register_chrdev(69, "adm6996", &adm_ops); mdelay(100); /* create proc entries */ // create_proc_read_entry("admide", 0, NULL, admide_proc, NULL); //joelin adm6996i support start adm6996_mode=adm6996i; ifx_sw_read(0xa0, &val); adm6996_mode=adm6996l; ifx_sw_read(0x200, &val1); // printk ("\n %0x \n",val1); if ((val&0xfff0)==0x1020) { printk ("\n ADM6996I .. \n"); adm6996_mode=adm6996i; } else if ((val1&0xffffff00)==0x71000) {//71010 or 71020 printk ("\n ADM6996LC .. \n"); adm6996_mode=adm6996lc; } else { printk ("\n ADM6996L .. \n"); adm6996_mode=adm6996l; } #endif //ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin if ((adm6996_mode==adm6996lc)||(adm6996_mode==adm6996i)){ #if 0 /* removed by MarsLin */ ifx_sw_write(0x29,0xc000); ifx_sw_write(0x30,0x0985); #else ifx_sw_read(0xa0, &val); if (val == 0x1021) // for both 6996LC and 6996I, only AB version need the patch ifx_sw_write(0x29, 0x9000); ifx_sw_write(0x30,0x0985); #endif } //joelin adm6996i support end return 0; } void __exit cleanup_adm6996_module(void) { printk("Free ADM device driver... \n"); unregister_chrdev(69, "adm6996"); /* remove proc entries */ // remove_proc_entry("admide", NULL); } /* MarsLin, add start */ #if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE) #define SET_BIT(reg, mask) reg |= (mask) #define CLEAR_BIT(reg, mask) reg &= (~mask) static int ifx_hw_reset(void) { CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL0),0x2000); CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL1),0x2000); SET_BIT((*AMAZON_GPIO_P0_OD),0x2000); SET_BIT((*AMAZON_GPIO_P0_DIR), 0x2000); CLEAR_BIT((*AMAZON_GPIO_P0_OUT), 0x2000); mdelay(500); SET_BIT((*AMAZON_GPIO_P0_OUT), 0x2000); cleanup_adm6996_module(); return init_adm6996_module(); } int (*adm6996_hw_reset)(void) = ifx_hw_reset; EXPORT_SYMBOL(adm6996_hw_reset); EXPORT_SYMBOL(adm6996_mode); int (*adm6996_sw_read)(unsigned int addr, unsigned int *data) = ifx_sw_read; EXPORT_SYMBOL(adm6996_sw_read); int (*adm6996_sw_write)(unsigned int addr, unsigned int data) = ifx_sw_write; EXPORT_SYMBOL(adm6996_sw_write); #endif /* MarsLin, add end */ /* Santosh: for IGMP proxy/snooping, Begin */ EXPORT_SYMBOL (adm_process_mac_table_request); EXPORT_SYMBOL (adm_process_protocol_filter_request); /* Santosh: for IGMP proxy/snooping, End */ MODULE_DESCRIPTION("ADMtek 6996 Driver"); MODULE_AUTHOR("Joe Lin "); MODULE_LICENSE("GPL"); module_init(init_adm6996_module); module_exit(cleanup_adm6996_module);