From 1932ef3fc46a90b00beec60bb9b746c87dce30b4 Mon Sep 17 00:00:00 2001 From: hauke Date: Sat, 20 Jun 2009 18:44:24 +0000 Subject: [amazon] Add ADM6996 switch driver This fixes #5314 Thanks to Michael Richter git-svn-id: svn://svn.openwrt.org/openwrt/trunk@16523 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- target/linux/amazon/files/drivers/net/admmod.c | 1484 ++++++++++++++++++++++++ 1 file changed, 1484 insertions(+) create mode 100644 target/linux/amazon/files/drivers/net/admmod.c (limited to 'target/linux/amazon/files/drivers/net/admmod.c') diff --git a/target/linux/amazon/files/drivers/net/admmod.c b/target/linux/amazon/files/drivers/net/admmod.c new file mode 100644 index 0000000000..70ba1496a1 --- /dev/null +++ b/target/linux/amazon/files/drivers/net/admmod.c @@ -0,0 +1,1484 @@ +/****************************************************************************** + 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) +{ + 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) +{ + 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); + -- cgit v1.2.3