summaryrefslogtreecommitdiff
path: root/target/linux/amazon/files/drivers/net/admmod.c
diff options
context:
space:
mode:
authorhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>2009-06-20 18:44:24 +0000
committerhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>2009-06-20 18:44:24 +0000
commit1932ef3fc46a90b00beec60bb9b746c87dce30b4 (patch)
treeba6451470376957571ec07746399f74e50977189 /target/linux/amazon/files/drivers/net/admmod.c
parenta4655acf980b230e72a85212d3ddb8b48c0ef9be (diff)
[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
Diffstat (limited to 'target/linux/amazon/files/drivers/net/admmod.c')
-rw-r--r--target/linux/amazon/files/drivers/net/admmod.c1484
1 files changed, 1484 insertions, 0 deletions
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 <linux/module.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <asm/atomic.h>
+#include <asm-mips/amazon/amazon.h>
+#include <asm-mips/amazon/adm6996.h>
+//#include <linux/amazon/adm6996.h>
+
+
+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);
+ 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);
+ 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 <joe.lin@infineon.com>");
+MODULE_LICENSE("GPL");
+
+module_init(init_adm6996_module);
+module_exit(cleanup_adm6996_module);
+