From abd74f86b459f4ac684de4a0f1bf6552d14b105a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 13 May 2012 15:10:40 +0000 Subject: amazon: update amazon target to kernel 3.3 This is just compile tested, my device is currently not working. SVN-Revision: 31706 --- target/linux/amazon/files/drivers/net/admmod.c | 1494 -------------------- target/linux/amazon/files/drivers/net/amazon_sw.c | 899 ------------ .../amazon/files/drivers/net/ethernet/admmod.c | 1493 +++++++++++++++++++ .../amazon/files/drivers/net/ethernet/amazon_sw.c | 899 ++++++++++++ 4 files changed, 2392 insertions(+), 2393 deletions(-) delete mode 100644 target/linux/amazon/files/drivers/net/admmod.c delete mode 100644 target/linux/amazon/files/drivers/net/amazon_sw.c create mode 100644 target/linux/amazon/files/drivers/net/ethernet/admmod.c create mode 100644 target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c (limited to 'target/linux/amazon/files/drivers/net') diff --git a/target/linux/amazon/files/drivers/net/admmod.c b/target/linux/amazon/files/drivers/net/admmod.c deleted file mode 100644 index 473a1f6..0000000 --- a/target/linux/amazon/files/drivers/net/admmod.c +++ /dev/null @@ -1,1494 +0,0 @@ -/****************************************************************************** - 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 -//#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 */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) -static long adm_ioctl(struct file *filp, unsigned int cmd, unsigned long args) -#else -static int adm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long args) -#endif -{ - 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, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) - unlocked_ioctl: adm_ioctl -#else - ioctl: adm_ioctl -#endif -}; - -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); - diff --git a/target/linux/amazon/files/drivers/net/amazon_sw.c b/target/linux/amazon/files/drivers/net/amazon_sw.c deleted file mode 100644 index 54a7062..0000000 --- a/target/linux/amazon/files/drivers/net/amazon_sw.c +++ /dev/null @@ -1,899 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - */ -//----------------------------------------------------------------------- -/* - * Description: - * Driver for Infineon Amazon 3 port switch - */ -//----------------------------------------------------------------------- -/* Author: Wu Qi Ming[Qi-Ming.Wu@infineon.com] - * Created: 7-April-2004 - */ -//----------------------------------------------------------------------- -/* History - * Changed on: Jun 28, 2004 - * Changed by: peng.liu@infineon.com - * Reason: add hardware flow control (HFC) (CONFIG_NET_HW_FLOWCONTROL) - * - * Changed on: Apr 6, 2005 - * Changed by: mars.lin@infineon.com - * Reason : supoort port identification - */ - - -// copyright 2004-2005 infineon.com - -// copyright 2007 john crispin -// copyright 2007 felix fietkau -// copyright 2009 hauke mehrtens - - -// TODO -// port vlan code from bcrm target... the tawainese code was scrapped due to crappyness -// check all the mmi reg settings and possibly document them better -// verify the ethtool code -// remove the while(1) stuff -// further clean up and rework ... but it works for now -// check the mode[]=bridge stuff -// verify that the ethaddr can be set from u-boot - - -#ifndef __KERNEL__ -#define __KERNEL__ -#endif - - -#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined(MODVERSIONS) && !defined(__GENKSYMS__) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// how many mii ports are there ? -#define AMAZON_SW_INT_NO 2 - -#define ETHERNET_PACKET_DMA_BUFFER_SIZE 1536 - -/***************************************** Module Parameters *************************************/ -char mode[] = "bridge"; -module_param_array(mode, charp, NULL, 0); - -static int timeout = 1 * HZ; -module_param(timeout, int, 0); - -int switch_init(struct net_device *dev); -void switch_tx_timeout(struct net_device *dev); - -static struct net_device *switch_devs[2]; - -int add_mac_table_entry(u64 entry_value) -{ - int i; - u32 data1, data2; - - AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = ~7; - - for (i = 0; i < 32; i++) { - AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | i; - while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; - data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1); - data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2); - if ((data1 & (0x00700000)) != 0x00700000) - continue; - AMAZON_SW_REG32(AMAZON_SW_DATA1) = (u32) (entry_value >> 32); - AMAZON_SW_REG32(AMAZON_SW_DATA2) = (u32) entry_value & 0xffffffff; - AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | i; - while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; - break; - } - AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) |= 7; - if (i >= 32) - return -1; - return OK; -} - -u64 read_mac_table_entry(int index) -{ - u32 data1, data2; - u64 value; - AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | index; - while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; - data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1) & 0xffffff; - data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2); - value = (u64) data1 << 32 | (u64) data2; - return value; -} - -int write_mac_table_entry(int index, u64 value) -{ - u32 data1, data2; - data1 = (u32) (value >> 32); - data2 = (u32) value & 0xffffffff; - AMAZON_SW_REG32(AMAZON_SW_DATA1) = data1; - AMAZON_SW_REG32(AMAZON_SW_DATA2) = data2; - AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | index; - while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; - return OK; -} - -u32 get_mdio_reg(int phy_addr, int reg_num) -{ - u32 value; - AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (3 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16); - while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {}; - value = AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & 0xffff; - return value; -} - -int set_mdio_reg(int phy_addr, int reg_num, u32 value) -{ - AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (2 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16) | (value & 0xffff); - while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {}; - return OK; -} - -int auto_negotiate(int phy_addr) -{ - u32 value = 0; - value = get_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG); - set_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG, (value | RESTART_AUTO_NEGOTIATION | AUTO_NEGOTIATION_ENABLE | PHY_RESET)); - return OK; -} - -/* - In this version of switch driver, we split the dma channels for the switch. - 2 for port0 and 2 for port1. So that we can do internal bridging if necessary. - In switch mode, packets coming in from port0 or port1 is able to do Destination - address lookup. Packets coming from port0 with destination address of port1 should - not go to pmac again. The switch hardware should be able to do the switch in the hard - ware level. Packets coming from the pmac should not do the DA look up in that the - desination is already known for the kernel. It only needs to go to the correct NIC to - find its way out. - */ -int amazon_sw_chip_init(void) -{ - u32 tmp1; - int i = 0; - - /* Aging tick select: 5mins */ - tmp1 = 0xa0; - if (strcmp(mode, "bridge") == 0) { - // bridge mode, set militarised mode to 1, no learning! - tmp1 |= 0xC00; - } else { - // enable learning for P0 and P1, - tmp1 |= 3; - } - - /* unknown broadcast/multicast/unicast to all ports */ - AMAZON_SW_REG32(AMAZON_SW_UN_DEST) = 0x1ff; - - AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = tmp1; - - /* OCS:1 set OCS bit, split the two NIC in rx direction EDL:1 (enable DA lookup) */ -#if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE) - AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x700; -#else - AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x401; -#endif - - /* EPC: 1 split the two NIC in tx direction CRC is generated */ - AMAZON_SW_REG32(AMAZON_SW_P2_CTL) = 0x6; - - // for bi-directional - AMAZON_SW_REG32(AMAZON_SW_P0_WM) = 0x14141412; - AMAZON_SW_REG32(AMAZON_SW_P1_WM) = 0x14141412; - AMAZON_SW_REG32(AMAZON_SW_P2_WM) = 0x28282826; - AMAZON_SW_REG32(AMAZON_SW_GBL_WM) = 0x0; - - AMAZON_SW_REG32(AMAZON_CGU_PLL0SR) = (AMAZON_SW_REG32(AMAZON_CGU_PLL0SR)) | 0x58000000; - // clock for PHY - AMAZON_SW_REG32(AMAZON_CGU_IFCCR) = (AMAZON_SW_REG32(AMAZON_CGU_IFCCR)) | 0x80000004; - // enable power for PHY - AMAZON_SW_REG32(AMAZON_PMU_PWDCR) = (AMAZON_SW_REG32(AMAZON_PMU_PWDCR)) | AMAZON_PMU_PWDCR_EPHY; - // set reverse MII, enable MDIO statemachine - AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG) = 0x800027bf; - while (1) - if (((AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG)) & 0x80000000) == 0) - break; - AMAZON_SW_REG32(AMAZON_SW_EPHY) = 0xff; - - // auto negotiation - AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = 0x83e08000; - auto_negotiate(0x1f); - - /* enable all ports */ - AMAZON_SW_REG32(AMAZON_SW_PS_CTL) = 0x7; - for (i = 0; i < 32; i++) - write_mac_table_entry(i, 1 << 50); - return 0; -} - -static unsigned char my_ethaddr[MAX_ADDR_LEN]; -/* need to get the ether addr from u-boot */ -static int __init ethaddr_setup(char *line) -{ - char *ep; - int i; - - memset(my_ethaddr, 0, MAX_ADDR_LEN); - for (i = 0; i < 6; i++) { - my_ethaddr[i] = line ? simple_strtoul(line, &ep, 16) : 0; - if (line) - line = (*ep) ? ep + 1 : ep; - } - printk(KERN_INFO "amazon_mii0: mac address %2x-%2x-%2x-%2x-%2x-%2x \n", my_ethaddr[0], my_ethaddr[1], my_ethaddr[2], my_ethaddr[3], my_ethaddr[4], my_ethaddr[5]); - return 0; -} - -__setup("ethaddr=", ethaddr_setup); - -static void open_rx_dma(struct net_device *dev) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - int i; - - for (i = 0; i < dma_dev->num_rx_chan; i++) - dma_dev->rx_chan[i].control = 1; - dma_device_update_rx(dma_dev); -} - -#ifdef CONFIG_NET_HW_FLOWCONTROL -static void close_rx_dma(struct net_device *dev) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - int i; - - for (i = 0; i < dma_dev->num_rx_chan; i++) - dma_dev->rx_chan[i].control = 0; - dma_device_update_rx(dma_dev); -} - -void amazon_xon(struct net_device *dev) -{ - unsigned long flag; - local_irq_save(flag); - open_rx_dma(dev); - local_irq_restore(flag); -} -#endif - -int switch_open(struct net_device *dev) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - if (!strcmp(dev->name, "eth1")) { - priv->mdio_phy_addr = PHY0_ADDR; - } - open_rx_dma(dev); - -#ifdef CONFIG_NET_HW_FLOWCONTROL - if ((priv->fc_bit = netdev_register_fc(dev, amazon_xon)) == 0) { - printk(KERN_WARNING "amazon_mii0: Hardware Flow Control register fails\n"); - } -#endif - - netif_start_queue(dev); - return OK; -} - -int switch_release(struct net_device *dev) -{ - int i; - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - - for (i = 0; i < dma_dev->num_tx_chan; i++) - dma_dev->tx_chan[i].control = 0; - for (i = 0; i < dma_dev->num_rx_chan; i++) - dma_dev->rx_chan[i].control = 0; - - dma_device_update(dma_dev); - -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (priv->fc_bit) { - netdev_unregister_fc(priv->fc_bit); - } -#endif - netif_stop_queue(dev); - - return OK; -} - - -void switch_rx(struct net_device *dev, int len, struct sk_buff *skb) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - int mit_sel = 0; -#endif - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - -#ifdef CONFIG_NET_HW_FLOWCONTROL - mit_sel = netif_rx(skb); - switch (mit_sel) { - case NET_RX_SUCCESS: - case NET_RX_CN_LOW: - case NET_RX_CN_MOD: - break; - case NET_RX_CN_HIGH: - break; - case NET_RX_DROP: - if ((priv->fc_bit) - && (!test_and_set_bit(priv->fc_bit, &netdev_fc_xoff))) { - close_rx_dma(dev); - } - break; - } -#else - netif_rx(skb); -#endif - priv->stats.rx_packets++; - priv->stats.rx_bytes += len; - return; -} - -int asmlinkage switch_hw_tx(char *buf, int len, struct net_device *dev) -{ - struct switch_priv *priv = netdev_priv(dev); - struct dma_device_info *dma_dev = priv->dma_device; - - dma_dev->current_tx_chan = 0; - return dma_device_write(dma_dev, buf, len, priv->skb); -} - -int asmlinkage switch_tx(struct sk_buff *skb, struct net_device *dev) -{ - int len; - char *data; - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - data = skb->data; - priv->skb = skb; - dev->trans_start = jiffies; - - if (switch_hw_tx(data, len, dev) != len) { - dev_kfree_skb_any(skb); - return OK; - } - - priv->stats.tx_packets++; - priv->stats.tx_bytes += len; - return OK; -} - -void switch_tx_timeout(struct net_device *dev) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - priv->stats.tx_errors++; - netif_wake_queue(dev); - return; -} - -void negotiate(struct net_device *dev) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - unsigned short data = get_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG); - - data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD); - - switch (priv->current_speed_selection) { - case 10: - if (priv->current_duplex == full) - data |= MDIO_ADVERT_10_FD; - else if (priv->current_duplex == half) - data |= MDIO_ADVERT_10_HD; - else - data |= MDIO_ADVERT_10_HD | MDIO_ADVERT_10_FD; - break; - - case 100: - if (priv->current_duplex == full) - data |= MDIO_ADVERT_100_FD; - else if (priv->current_duplex == half) - data |= MDIO_ADVERT_100_HD; - else - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD; - break; - - case 0: /* Auto */ - if (priv->current_duplex == full) - data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD; - else if (priv->current_duplex == half) - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD; - else - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; - break; - - default: /* assume autoneg speed and duplex */ - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; - } - - set_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG, data); - - /* Renegotiate with link partner */ - - data = get_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG); - data |= MDIO_BC_NEGOTIATE; - - set_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG, data); - -} - - -void set_duplex(struct net_device *dev, enum duplex new_duplex) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - if (new_duplex != priv->current_duplex) { - priv->current_duplex = new_duplex; - negotiate(dev); - } -} - -void set_speed(struct net_device *dev, unsigned long speed) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - priv->current_speed_selection = speed; - negotiate(dev); -} - -static int switch_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - struct ethtool_cmd ecmd; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd))) - return -EFAULT; - - switch (ecmd.cmd) { - case ETHTOOL_GSET: - memset((void *) &ecmd, 0, sizeof(ecmd)); - ecmd.supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; - ecmd.port = PORT_TP; - ecmd.transceiver = XCVR_EXTERNAL; - ecmd.phy_address = priv->mdio_phy_addr; - - ecmd.speed = priv->current_speed; - - ecmd.duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; - - ecmd.advertising = ADVERTISED_TP; - if (priv->current_duplex == autoneg && priv->current_speed_selection == 0) - ecmd.advertising |= ADVERTISED_Autoneg; - else { - ecmd.advertising |= ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; - if (priv->current_speed_selection == 10) - ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full); - else if (priv->current_speed_selection == 100) - ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full); - if (priv->current_duplex == half) - ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full); - else if (priv->current_duplex == full) - ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half); - } - ecmd.autoneg = AUTONEG_ENABLE; - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd))) - return -EFAULT; - break; - - case ETHTOOL_SSET: - if (!capable(CAP_NET_ADMIN)) { - return -EPERM; - } - if (ecmd.autoneg == AUTONEG_ENABLE) { - set_duplex(dev, autoneg); - set_speed(dev, 0); - } else { - set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full); - set_speed(dev, ecmd.speed == SPEED_10 ? 10 : 100); - } - break; - - case ETHTOOL_GDRVINFO: - { - struct ethtool_drvinfo info; - memset((void *) &info, 0, sizeof(info)); - strncpy(info.driver, "AMAZONE", sizeof(info.driver) - 1); - strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1); - strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1); - info.regdump_len = 0; - info.eedump_len = 0; - info.testinfo_len = 0; - if (copy_to_user(ifr->ifr_data, &info, sizeof(info))) - return -EFAULT; - } - break; - case ETHTOOL_NWAY_RST: - if (priv->current_duplex == autoneg && priv->current_speed_selection == 0) - negotiate(dev); - break; - default: - return -EOPNOTSUPP; - break; - } - return 0; -} - - - -int mac_table_tools_ioctl(struct net_device *dev, struct mac_table_req *req) -{ - int cmd; - int i; - cmd = req->cmd; - switch (cmd) { - case RESET_MAC_TABLE: - for (i = 0; i < 32; i++) { - write_mac_table_entry(i, 0); - } - break; - case READ_MAC_ENTRY: - req->entry_value = read_mac_table_entry(req->index); - break; - case WRITE_MAC_ENTRY: - write_mac_table_entry(req->index, req->entry_value); - break; - case ADD_MAC_ENTRY: - add_mac_table_entry(req->entry_value); - break; - default: - return -EINVAL; - } - - return 0; -} - - -/* - the ioctl for the switch driver is developed in the conventional way - the control type falls into some basic categories, among them, the - SIOCETHTOOL is the traditional eth interface. VLAN_TOOLS and - MAC_TABLE_TOOLS are designed specifically for amazon chip. User - should be aware of the data structures used in these interfaces. -*/ -int switch_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct data_req *switch_data_req = (struct data_req *) ifr->ifr_data; - struct mac_table_req *switch_mac_table_req; - switch (cmd) { - case SIOCETHTOOL: - switch_ethtool_ioctl(dev, ifr); - break; - case SIOCGMIIPHY: /* Get PHY address */ - break; - case SIOCGMIIREG: /* Read MII register */ - break; - case SIOCSMIIREG: /* Write MII register */ - break; - case SET_ETH_SPEED_10: /* 10 Mbps */ - break; - case SET_ETH_SPEED_100: /* 100 Mbps */ - break; - case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ - break; - case SET_ETH_DUPLEX_HALF: /* Half duplex. */ - break; - case SET_ETH_DUPLEX_FULL: /* Full duplex. */ - break; - case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex */ - break; - case SET_ETH_REG: - AMAZON_SW_REG32(switch_data_req->index) = switch_data_req->value; - break; - case MAC_TABLE_TOOLS: - switch_mac_table_req = (struct mac_table_req *) ifr->ifr_data; - mac_table_tools_ioctl(dev, switch_mac_table_req); - break; - default: - return -EINVAL; - } - - return 0; -} - -struct net_device_stats *switch_stats(struct net_device *dev) -{ - struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); - return &priv->stats; -} - -int switch_change_mtu(struct net_device *dev, int new_mtu) -{ - if (new_mtu >= 1516) - new_mtu = 1516; - dev->mtu = new_mtu; - return 0; -} - -int switch_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev) -{ - u8 *buf = NULL; - int len = 0; - struct sk_buff *skb = NULL; - - len = dma_device_read(dma_dev, &buf, (void **) &skb); - - if (len >= 0x600) { - printk(KERN_WARNING "amazon_mii0: packet too large %d\n", len); - goto switch_hw_receive_err_exit; - } - - /* remove CRC */ - len -= 4; - if (skb == NULL) { - printk(KERN_WARNING "amazon_mii0: cannot restore pointer\n"); - goto switch_hw_receive_err_exit; - } - if (len > (skb->end - skb->tail)) { - printk(KERN_WARNING "amazon_mii0: BUG, len:%d end:%p tail:%p\n", (len + 4), skb->end, skb->tail); - goto switch_hw_receive_err_exit; - } - skb_put(skb, len); - skb->dev = dev; - switch_rx(dev, len, skb); - return OK; - - switch_hw_receive_err_exit: - if (skb) - dev_kfree_skb_any(skb); - return -EIO; -} - -int dma_intr_handler(struct dma_device_info *dma_dev, int status) -{ - struct net_device *dev; - - dev = dma_dev->priv; - switch (status) { - case RCV_INT: - switch_hw_receive(dev, dma_dev); - break; - case TX_BUF_FULL_INT: - netif_stop_queue(dev); - break; - case TRANSMIT_CPT_INT: - netif_wake_queue(dev); - break; - } - return OK; -} - -/* reserve 2 bytes in front of data pointer*/ -u8 *dma_buffer_alloc(int len, int *byte_offset, void **opt) -{ - u8 *buffer = NULL; - struct sk_buff *skb = NULL; - skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); - if (skb == NULL) { - return NULL; - } - buffer = (u8 *) (skb->data); - skb_reserve(skb, 2); - *(int *) opt = (int) skb; - *byte_offset = 2; - return buffer; -} - -int dma_buffer_free(u8 * dataptr, void *opt) -{ - struct sk_buff *skb = NULL; - if (opt == NULL) { - kfree(dataptr); - } else { - skb = (struct sk_buff *) opt; - dev_kfree_skb_any(skb); - } - return OK; -} - -int init_dma_device(_dma_device_info * dma_dev, struct net_device *dev) -{ - int i; - int num_tx_chan, num_rx_chan; - if (strcmp(dma_dev->device_name, "switch1") == 0) { - num_tx_chan = 1; - num_rx_chan = 2; - } else { - num_tx_chan = 1; - num_rx_chan = 2; - } - dma_dev->priv = dev; - - dma_dev->weight = 1; - dma_dev->num_tx_chan = num_tx_chan; - dma_dev->num_rx_chan = num_rx_chan; - dma_dev->ack = 1; - dma_dev->tx_burst_len = 4; - dma_dev->rx_burst_len = 4; - for (i = 0; i < dma_dev->num_tx_chan; i++) { - dma_dev->tx_chan[i].weight = QOS_DEFAULT_WGT; - dma_dev->tx_chan[i].desc_num = 10; - dma_dev->tx_chan[i].packet_size = 0; - dma_dev->tx_chan[i].control = 0; - } - for (i = 0; i < num_rx_chan; i++) { - dma_dev->rx_chan[i].weight = QOS_DEFAULT_WGT; - dma_dev->rx_chan[i].desc_num = 10; - dma_dev->rx_chan[i].packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE; - dma_dev->rx_chan[i].control = 0; - } - dma_dev->intr_handler = dma_intr_handler; - dma_dev->buffer_alloc = dma_buffer_alloc; - dma_dev->buffer_free = dma_buffer_free; - return 0; -} - -int switch_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - return OK; -} - -static const struct net_device_ops amazon_mii_ops = { - .ndo_init = switch_init, - .ndo_open = switch_open, - .ndo_stop = switch_release, - .ndo_start_xmit = switch_tx, - .ndo_do_ioctl = switch_ioctl, - .ndo_get_stats = switch_stats, - .ndo_change_mtu = switch_change_mtu, - .ndo_set_mac_address = switch_set_mac_address, - .ndo_tx_timeout = switch_tx_timeout, -}; - -int switch_init(struct net_device *dev) -{ - u64 retval = 0; - int i; - int result; - struct switch_priv *priv; - ether_setup(dev); /* assign some of the fields */ - printk(KERN_INFO "amazon_mii0: %s up using ", dev->name); - dev->watchdog_timeo = timeout; - - priv = netdev_priv(dev); - priv->dma_device = (struct dma_device_info *) kmalloc(sizeof(struct dma_device_info), GFP_KERNEL); - if (priv->num == 0) { - sprintf(priv->dma_device->device_name, "switch1"); - } else if (priv->num == 1) { - sprintf(priv->dma_device->device_name, "switch2"); - } - printk("\"%s\"\n", priv->dma_device->device_name); - init_dma_device(priv->dma_device, dev); - result = dma_device_register(priv->dma_device); - - /* read the mac address from the mac table and put them into the mac table. */ - for (i = 0; i < 6; i++) { - retval += my_ethaddr[i]; - } - /* ethaddr not set in u-boot ? */ - if (retval == 0) { - dev->dev_addr[0] = 0x00; - dev->dev_addr[1] = 0x20; - dev->dev_addr[2] = 0xda; - dev->dev_addr[3] = 0x86; - dev->dev_addr[4] = 0x23; - dev->dev_addr[5] = 0x74 + (unsigned char) priv->num; - } else { - for (i = 0; i < 6; i++) { - dev->dev_addr[i] = my_ethaddr[i]; - } - dev->dev_addr[5] += +(unsigned char) priv->num; - } - return OK; -} - -static int amazon_mii_probe(struct platform_device *dev) -{ - int i = 0, result, device_present = 0; - struct switch_priv *priv; - - for (i = 0; i < AMAZON_SW_INT_NO; i++) { - switch_devs[i] = alloc_etherdev(sizeof(struct switch_priv)); - switch_devs[i]->netdev_ops = &amazon_mii_ops; - strcpy(switch_devs[i]->name, "eth%d"); - priv = (struct switch_priv *) netdev_priv(switch_devs[i]); - priv->num = i; - if ((result = register_netdev(switch_devs[i]))) - printk(KERN_WARNING "amazon_mii0: error %i registering device \"%s\"\n", result, switch_devs[i]->name); - else - device_present++; - } - amazon_sw_chip_init(); - return device_present ? 0 : -ENODEV; -} - -static int amazon_mii_remove(struct platform_device *dev) -{ - int i; - struct switch_priv *priv; - for (i = 0; i < AMAZON_SW_INT_NO; i++) { - priv = netdev_priv(switch_devs[i]); - if (priv->dma_device) { - dma_device_unregister(priv->dma_device); - kfree(priv->dma_device); - } - kfree(netdev_priv(switch_devs[i])); - unregister_netdev(switch_devs[i]); - } - return 0; -} - -static struct platform_driver amazon_mii_driver = { - .probe = amazon_mii_probe, - .remove = amazon_mii_remove, - .driver = { - .name = "amazon_mii0", - .owner = THIS_MODULE, - }, -}; - -static int __init amazon_mii_init(void) -{ - int ret = platform_driver_register(&amazon_mii_driver); - if (ret) - printk(KERN_WARNING "amazon_mii0: Error registering platfom driver!\n"); - return ret; -} - -static void __exit amazon_mii_cleanup(void) -{ - platform_driver_unregister(&amazon_mii_driver); -} - -module_init(amazon_mii_init); -module_exit(amazon_mii_cleanup); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Wu Qi Ming"); -MODULE_DESCRIPTION("ethernet driver for AMAZON boards"); - diff --git a/target/linux/amazon/files/drivers/net/ethernet/admmod.c b/target/linux/amazon/files/drivers/net/ethernet/admmod.c new file mode 100644 index 0000000..a11ee1d --- /dev/null +++ b/target/linux/amazon/files/drivers/net/ethernet/admmod.c @@ -0,0 +1,1493 @@ +/****************************************************************************** + 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 +//#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 */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) +static long adm_ioctl(struct file *filp, unsigned int cmd, unsigned long args) +#else +static int adm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long args) +#endif +{ + 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 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, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) + unlocked_ioctl: adm_ioctl +#else + ioctl: adm_ioctl +#endif +}; + +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); + diff --git a/target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c b/target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c new file mode 100644 index 0000000..d18b439 --- /dev/null +++ b/target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c @@ -0,0 +1,899 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ +//----------------------------------------------------------------------- +/* + * Description: + * Driver for Infineon Amazon 3 port switch + */ +//----------------------------------------------------------------------- +/* Author: Wu Qi Ming[Qi-Ming.Wu@infineon.com] + * Created: 7-April-2004 + */ +//----------------------------------------------------------------------- +/* History + * Changed on: Jun 28, 2004 + * Changed by: peng.liu@infineon.com + * Reason: add hardware flow control (HFC) (CONFIG_NET_HW_FLOWCONTROL) + * + * Changed on: Apr 6, 2005 + * Changed by: mars.lin@infineon.com + * Reason : supoort port identification + */ + + +// copyright 2004-2005 infineon.com + +// copyright 2007 john crispin +// copyright 2007 felix fietkau +// copyright 2009 hauke mehrtens + + +// TODO +// port vlan code from bcrm target... the tawainese code was scrapped due to crappyness +// check all the mmi reg settings and possibly document them better +// verify the ethtool code +// remove the while(1) stuff +// further clean up and rework ... but it works for now +// check the mode[]=bridge stuff +// verify that the ethaddr can be set from u-boot + + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif + +#if defined(MODVERSIONS) && !defined(__GENKSYMS__) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// how many mii ports are there ? +#define AMAZON_SW_INT_NO 2 + +#define ETHERNET_PACKET_DMA_BUFFER_SIZE 1536 + +/***************************************** Module Parameters *************************************/ +static char mode[] = "bridge"; +module_param_array(mode, charp, NULL, 0); + +static int timeout = 1 * HZ; +module_param(timeout, int, 0); + +int switch_init(struct net_device *dev); +void switch_tx_timeout(struct net_device *dev); + +static struct net_device *switch_devs[2]; + +int add_mac_table_entry(u64 entry_value) +{ + int i; + u32 data1, data2; + + AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = ~7; + + for (i = 0; i < 32; i++) { + AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | i; + while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; + data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1); + data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2); + if ((data1 & (0x00700000)) != 0x00700000) + continue; + AMAZON_SW_REG32(AMAZON_SW_DATA1) = (u32) (entry_value >> 32); + AMAZON_SW_REG32(AMAZON_SW_DATA2) = (u32) entry_value & 0xffffffff; + AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | i; + while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; + break; + } + AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) |= 7; + if (i >= 32) + return -1; + return OK; +} + +u64 read_mac_table_entry(int index) +{ + u32 data1, data2; + u64 value; + AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | index; + while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; + data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1) & 0xffffff; + data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2); + value = (u64) data1 << 32 | (u64) data2; + return value; +} + +int write_mac_table_entry(int index, u64 value) +{ + u32 data1, data2; + data1 = (u32) (value >> 32); + data2 = (u32) value & 0xffffffff; + AMAZON_SW_REG32(AMAZON_SW_DATA1) = data1; + AMAZON_SW_REG32(AMAZON_SW_DATA2) = data2; + AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | index; + while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {}; + return OK; +} + +u32 get_mdio_reg(int phy_addr, int reg_num) +{ + u32 value; + AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (3 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16); + while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {}; + value = AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & 0xffff; + return value; +} + +int set_mdio_reg(int phy_addr, int reg_num, u32 value) +{ + AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (2 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16) | (value & 0xffff); + while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {}; + return OK; +} + +int auto_negotiate(int phy_addr) +{ + u32 value = 0; + value = get_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG); + set_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG, (value | RESTART_AUTO_NEGOTIATION | AUTO_NEGOTIATION_ENABLE | PHY_RESET)); + return OK; +} + +/* + In this version of switch driver, we split the dma channels for the switch. + 2 for port0 and 2 for port1. So that we can do internal bridging if necessary. + In switch mode, packets coming in from port0 or port1 is able to do Destination + address lookup. Packets coming from port0 with destination address of port1 should + not go to pmac again. The switch hardware should be able to do the switch in the hard + ware level. Packets coming from the pmac should not do the DA look up in that the + desination is already known for the kernel. It only needs to go to the correct NIC to + find its way out. + */ +int amazon_sw_chip_init(void) +{ + u32 tmp1; + int i = 0; + + /* Aging tick select: 5mins */ + tmp1 = 0xa0; + if (strcmp(mode, "bridge") == 0) { + // bridge mode, set militarised mode to 1, no learning! + tmp1 |= 0xC00; + } else { + // enable learning for P0 and P1, + tmp1 |= 3; + } + + /* unknown broadcast/multicast/unicast to all ports */ + AMAZON_SW_REG32(AMAZON_SW_UN_DEST) = 0x1ff; + + AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = tmp1; + + /* OCS:1 set OCS bit, split the two NIC in rx direction EDL:1 (enable DA lookup) */ +#if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE) + AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x700; +#else + AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x401; +#endif + + /* EPC: 1 split the two NIC in tx direction CRC is generated */ + AMAZON_SW_REG32(AMAZON_SW_P2_CTL) = 0x6; + + // for bi-directional + AMAZON_SW_REG32(AMAZON_SW_P0_WM) = 0x14141412; + AMAZON_SW_REG32(AMAZON_SW_P1_WM) = 0x14141412; + AMAZON_SW_REG32(AMAZON_SW_P2_WM) = 0x28282826; + AMAZON_SW_REG32(AMAZON_SW_GBL_WM) = 0x0; + + AMAZON_SW_REG32(AMAZON_CGU_PLL0SR) = (AMAZON_SW_REG32(AMAZON_CGU_PLL0SR)) | 0x58000000; + // clock for PHY + AMAZON_SW_REG32(AMAZON_CGU_IFCCR) = (AMAZON_SW_REG32(AMAZON_CGU_IFCCR)) | 0x80000004; + // enable power for PHY + AMAZON_SW_REG32(AMAZON_PMU_PWDCR) = (AMAZON_SW_REG32(AMAZON_PMU_PWDCR)) | AMAZON_PMU_PWDCR_EPHY; + // set reverse MII, enable MDIO statemachine + AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG) = 0x800027bf; + while (1) + if (((AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG)) & 0x80000000) == 0) + break; + AMAZON_SW_REG32(AMAZON_SW_EPHY) = 0xff; + + // auto negotiation + AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = 0x83e08000; + auto_negotiate(0x1f); + + /* enable all ports */ + AMAZON_SW_REG32(AMAZON_SW_PS_CTL) = 0x7; + for (i = 0; i < 32; i++) + write_mac_table_entry(i, 1 << 50); + return 0; +} + +static unsigned char my_ethaddr[MAX_ADDR_LEN]; +/* need to get the ether addr from u-boot */ +static int __init ethaddr_setup(char *line) +{ + char *ep; + int i; + + memset(my_ethaddr, 0, MAX_ADDR_LEN); + for (i = 0; i < 6; i++) { + my_ethaddr[i] = line ? simple_strtoul(line, &ep, 16) : 0; + if (line) + line = (*ep) ? ep + 1 : ep; + } + printk(KERN_INFO "amazon_mii0: mac address %2x-%2x-%2x-%2x-%2x-%2x \n", my_ethaddr[0], my_ethaddr[1], my_ethaddr[2], my_ethaddr[3], my_ethaddr[4], my_ethaddr[5]); + return 0; +} + +__setup("ethaddr=", ethaddr_setup); + +static void open_rx_dma(struct net_device *dev) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + struct dma_device_info *dma_dev = priv->dma_device; + int i; + + for (i = 0; i < dma_dev->num_rx_chan; i++) + dma_dev->rx_chan[i].control = 1; + dma_device_update_rx(dma_dev); +} + +#ifdef CONFIG_NET_HW_FLOWCONTROL +static void close_rx_dma(struct net_device *dev) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + struct dma_device_info *dma_dev = priv->dma_device; + int i; + + for (i = 0; i < dma_dev->num_rx_chan; i++) + dma_dev->rx_chan[i].control = 0; + dma_device_update_rx(dma_dev); +} + +void amazon_xon(struct net_device *dev) +{ + unsigned long flag; + local_irq_save(flag); + open_rx_dma(dev); + local_irq_restore(flag); +} +#endif + +int switch_open(struct net_device *dev) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + if (!strcmp(dev->name, "eth1")) { + priv->mdio_phy_addr = PHY0_ADDR; + } + open_rx_dma(dev); + +#ifdef CONFIG_NET_HW_FLOWCONTROL + if ((priv->fc_bit = netdev_register_fc(dev, amazon_xon)) == 0) { + printk(KERN_WARNING "amazon_mii0: Hardware Flow Control register fails\n"); + } +#endif + + netif_start_queue(dev); + return OK; +} + +int switch_release(struct net_device *dev) +{ + int i; + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + struct dma_device_info *dma_dev = priv->dma_device; + + for (i = 0; i < dma_dev->num_tx_chan; i++) + dma_dev->tx_chan[i].control = 0; + for (i = 0; i < dma_dev->num_rx_chan; i++) + dma_dev->rx_chan[i].control = 0; + + dma_device_update(dma_dev); + +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (priv->fc_bit) { + netdev_unregister_fc(priv->fc_bit); + } +#endif + netif_stop_queue(dev); + + return OK; +} + + +void switch_rx(struct net_device *dev, int len, struct sk_buff *skb) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); +#ifdef CONFIG_NET_HW_FLOWCONTROL + int mit_sel = 0; +#endif + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + +#ifdef CONFIG_NET_HW_FLOWCONTROL + mit_sel = netif_rx(skb); + switch (mit_sel) { + case NET_RX_SUCCESS: + case NET_RX_CN_LOW: + case NET_RX_CN_MOD: + break; + case NET_RX_CN_HIGH: + break; + case NET_RX_DROP: + if ((priv->fc_bit) + && (!test_and_set_bit(priv->fc_bit, &netdev_fc_xoff))) { + close_rx_dma(dev); + } + break; + } +#else + netif_rx(skb); +#endif + priv->stats.rx_packets++; + priv->stats.rx_bytes += len; + return; +} + +int asmlinkage switch_hw_tx(char *buf, int len, struct net_device *dev) +{ + struct switch_priv *priv = netdev_priv(dev); + struct dma_device_info *dma_dev = priv->dma_device; + + dma_dev->current_tx_chan = 0; + return dma_device_write(dma_dev, buf, len, priv->skb); +} + +int asmlinkage switch_tx(struct sk_buff *skb, struct net_device *dev) +{ + int len; + char *data; + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + data = skb->data; + priv->skb = skb; + dev->trans_start = jiffies; + + if (switch_hw_tx(data, len, dev) != len) { + dev_kfree_skb_any(skb); + return OK; + } + + priv->stats.tx_packets++; + priv->stats.tx_bytes += len; + return OK; +} + +void switch_tx_timeout(struct net_device *dev) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + priv->stats.tx_errors++; + netif_wake_queue(dev); + return; +} + +void negotiate(struct net_device *dev) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + unsigned short data = get_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG); + + data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD); + + switch (priv->current_speed_selection) { + case 10: + if (priv->current_duplex == full) + data |= MDIO_ADVERT_10_FD; + else if (priv->current_duplex == half) + data |= MDIO_ADVERT_10_HD; + else + data |= MDIO_ADVERT_10_HD | MDIO_ADVERT_10_FD; + break; + + case 100: + if (priv->current_duplex == full) + data |= MDIO_ADVERT_100_FD; + else if (priv->current_duplex == half) + data |= MDIO_ADVERT_100_HD; + else + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD; + break; + + case 0: /* Auto */ + if (priv->current_duplex == full) + data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD; + else if (priv->current_duplex == half) + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD; + else + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; + break; + + default: /* assume autoneg speed and duplex */ + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; + } + + set_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG, data); + + /* Renegotiate with link partner */ + + data = get_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG); + data |= MDIO_BC_NEGOTIATE; + + set_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG, data); + +} + + +void set_duplex(struct net_device *dev, enum duplex new_duplex) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + if (new_duplex != priv->current_duplex) { + priv->current_duplex = new_duplex; + negotiate(dev); + } +} + +void set_speed(struct net_device *dev, unsigned long speed) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + priv->current_speed_selection = speed; + negotiate(dev); +} + +static int switch_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + struct ethtool_cmd ecmd; + + if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd))) + return -EFAULT; + + switch (ecmd.cmd) { + case ETHTOOL_GSET: + memset((void *) &ecmd, 0, sizeof(ecmd)); + ecmd.supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; + ecmd.port = PORT_TP; + ecmd.transceiver = XCVR_EXTERNAL; + ecmd.phy_address = priv->mdio_phy_addr; + + ecmd.speed = priv->current_speed; + + ecmd.duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; + + ecmd.advertising = ADVERTISED_TP; + if (priv->current_duplex == autoneg && priv->current_speed_selection == 0) + ecmd.advertising |= ADVERTISED_Autoneg; + else { + ecmd.advertising |= ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; + if (priv->current_speed_selection == 10) + ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full); + else if (priv->current_speed_selection == 100) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full); + if (priv->current_duplex == half) + ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full); + else if (priv->current_duplex == full) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half); + } + ecmd.autoneg = AUTONEG_ENABLE; + if (copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd))) + return -EFAULT; + break; + + case ETHTOOL_SSET: + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + if (ecmd.autoneg == AUTONEG_ENABLE) { + set_duplex(dev, autoneg); + set_speed(dev, 0); + } else { + set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full); + set_speed(dev, ecmd.speed == SPEED_10 ? 10 : 100); + } + break; + + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info; + memset((void *) &info, 0, sizeof(info)); + strncpy(info.driver, "AMAZONE", sizeof(info.driver) - 1); + strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1); + strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1); + info.regdump_len = 0; + info.eedump_len = 0; + info.testinfo_len = 0; + if (copy_to_user(ifr->ifr_data, &info, sizeof(info))) + return -EFAULT; + } + break; + case ETHTOOL_NWAY_RST: + if (priv->current_duplex == autoneg && priv->current_speed_selection == 0) + negotiate(dev); + break; + default: + return -EOPNOTSUPP; + break; + } + return 0; +} + + + +int mac_table_tools_ioctl(struct net_device *dev, struct mac_table_req *req) +{ + int cmd; + int i; + cmd = req->cmd; + switch (cmd) { + case RESET_MAC_TABLE: + for (i = 0; i < 32; i++) { + write_mac_table_entry(i, 0); + } + break; + case READ_MAC_ENTRY: + req->entry_value = read_mac_table_entry(req->index); + break; + case WRITE_MAC_ENTRY: + write_mac_table_entry(req->index, req->entry_value); + break; + case ADD_MAC_ENTRY: + add_mac_table_entry(req->entry_value); + break; + default: + return -EINVAL; + } + + return 0; +} + + +/* + the ioctl for the switch driver is developed in the conventional way + the control type falls into some basic categories, among them, the + SIOCETHTOOL is the traditional eth interface. VLAN_TOOLS and + MAC_TABLE_TOOLS are designed specifically for amazon chip. User + should be aware of the data structures used in these interfaces. +*/ +int switch_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct data_req *switch_data_req = (struct data_req *) ifr->ifr_data; + struct mac_table_req *switch_mac_table_req; + switch (cmd) { + case SIOCETHTOOL: + switch_ethtool_ioctl(dev, ifr); + break; + case SIOCGMIIPHY: /* Get PHY address */ + break; + case SIOCGMIIREG: /* Read MII register */ + break; + case SIOCSMIIREG: /* Write MII register */ + break; + case SET_ETH_SPEED_10: /* 10 Mbps */ + break; + case SET_ETH_SPEED_100: /* 100 Mbps */ + break; + case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ + break; + case SET_ETH_DUPLEX_HALF: /* Half duplex. */ + break; + case SET_ETH_DUPLEX_FULL: /* Full duplex. */ + break; + case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex */ + break; + case SET_ETH_REG: + AMAZON_SW_REG32(switch_data_req->index) = switch_data_req->value; + break; + case MAC_TABLE_TOOLS: + switch_mac_table_req = (struct mac_table_req *) ifr->ifr_data; + mac_table_tools_ioctl(dev, switch_mac_table_req); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct net_device_stats *switch_stats(struct net_device *dev) +{ + struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev); + return &priv->stats; +} + +int switch_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu >= 1516) + new_mtu = 1516; + dev->mtu = new_mtu; + return 0; +} + +int switch_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev) +{ + u8 *buf = NULL; + int len = 0; + struct sk_buff *skb = NULL; + + len = dma_device_read(dma_dev, &buf, (void **) &skb); + + if (len >= 0x600) { + printk(KERN_WARNING "amazon_mii0: packet too large %d\n", len); + goto switch_hw_receive_err_exit; + } + + /* remove CRC */ + len -= 4; + if (skb == NULL) { + printk(KERN_WARNING "amazon_mii0: cannot restore pointer\n"); + goto switch_hw_receive_err_exit; + } + if (len > (skb->end - skb->tail)) { + printk(KERN_WARNING "amazon_mii0: BUG, len:%d end:%p tail:%p\n", (len + 4), skb->end, skb->tail); + goto switch_hw_receive_err_exit; + } + skb_put(skb, len); + skb->dev = dev; + switch_rx(dev, len, skb); + return OK; + + switch_hw_receive_err_exit: + if (skb) + dev_kfree_skb_any(skb); + return -EIO; +} + +int dma_intr_handler(struct dma_device_info *dma_dev, int status) +{ + struct net_device *dev; + + dev = dma_dev->priv; + switch (status) { + case RCV_INT: + switch_hw_receive(dev, dma_dev); + break; + case TX_BUF_FULL_INT: + netif_stop_queue(dev); + break; + case TRANSMIT_CPT_INT: + netif_wake_queue(dev); + break; + } + return OK; +} + +/* reserve 2 bytes in front of data pointer*/ +u8 *dma_buffer_alloc(int len, int *byte_offset, void **opt) +{ + u8 *buffer = NULL; + struct sk_buff *skb = NULL; + skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); + if (skb == NULL) { + return NULL; + } + buffer = (u8 *) (skb->data); + skb_reserve(skb, 2); + *(int *) opt = (int) skb; + *byte_offset = 2; + return buffer; +} + +int dma_buffer_free(u8 * dataptr, void *opt) +{ + struct sk_buff *skb = NULL; + if (opt == NULL) { + kfree(dataptr); + } else { + skb = (struct sk_buff *) opt; + dev_kfree_skb_any(skb); + } + return OK; +} + +int init_dma_device(_dma_device_info * dma_dev, struct net_device *dev) +{ + int i; + int num_tx_chan, num_rx_chan; + if (strcmp(dma_dev->device_name, "switch1") == 0) { + num_tx_chan = 1; + num_rx_chan = 2; + } else { + num_tx_chan = 1; + num_rx_chan = 2; + } + dma_dev->priv = dev; + + dma_dev->weight = 1; + dma_dev->num_tx_chan = num_tx_chan; + dma_dev->num_rx_chan = num_rx_chan; + dma_dev->ack = 1; + dma_dev->tx_burst_len = 4; + dma_dev->rx_burst_len = 4; + for (i = 0; i < dma_dev->num_tx_chan; i++) { + dma_dev->tx_chan[i].weight = QOS_DEFAULT_WGT; + dma_dev->tx_chan[i].desc_num = 10; + dma_dev->tx_chan[i].packet_size = 0; + dma_dev->tx_chan[i].control = 0; + } + for (i = 0; i < num_rx_chan; i++) { + dma_dev->rx_chan[i].weight = QOS_DEFAULT_WGT; + dma_dev->rx_chan[i].desc_num = 10; + dma_dev->rx_chan[i].packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE; + dma_dev->rx_chan[i].control = 0; + } + dma_dev->intr_handler = dma_intr_handler; + dma_dev->buffer_alloc = dma_buffer_alloc; + dma_dev->buffer_free = dma_buffer_free; + return 0; +} + +int switch_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + return OK; +} + +static const struct net_device_ops amazon_mii_ops = { + .ndo_init = switch_init, + .ndo_open = switch_open, + .ndo_stop = switch_release, + .ndo_start_xmit = switch_tx, + .ndo_do_ioctl = switch_ioctl, + .ndo_get_stats = switch_stats, + .ndo_change_mtu = switch_change_mtu, + .ndo_set_mac_address = switch_set_mac_address, + .ndo_tx_timeout = switch_tx_timeout, +}; + +int switch_init(struct net_device *dev) +{ + u64 retval = 0; + int i; + int result; + struct switch_priv *priv; + ether_setup(dev); /* assign some of the fields */ + printk(KERN_INFO "amazon_mii0: %s up using ", dev->name); + dev->watchdog_timeo = timeout; + + priv = netdev_priv(dev); + priv->dma_device = (struct dma_device_info *) kmalloc(sizeof(struct dma_device_info), GFP_KERNEL); + if (priv->num == 0) { + sprintf(priv->dma_device->device_name, "switch1"); + } else if (priv->num == 1) { + sprintf(priv->dma_device->device_name, "switch2"); + } + printk("\"%s\"\n", priv->dma_device->device_name); + init_dma_device(priv->dma_device, dev); + result = dma_device_register(priv->dma_device); + + /* read the mac address from the mac table and put them into the mac table. */ + for (i = 0; i < 6; i++) { + retval += my_ethaddr[i]; + } + /* ethaddr not set in u-boot ? */ + if (retval == 0) { + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x20; + dev->dev_addr[2] = 0xda; + dev->dev_addr[3] = 0x86; + dev->dev_addr[4] = 0x23; + dev->dev_addr[5] = 0x74 + (unsigned char) priv->num; + } else { + for (i = 0; i < 6; i++) { + dev->dev_addr[i] = my_ethaddr[i]; + } + dev->dev_addr[5] += +(unsigned char) priv->num; + } + return OK; +} + +static int amazon_mii_probe(struct platform_device *dev) +{ + int i = 0, result, device_present = 0; + struct switch_priv *priv; + + for (i = 0; i < AMAZON_SW_INT_NO; i++) { + switch_devs[i] = alloc_etherdev(sizeof(struct switch_priv)); + switch_devs[i]->netdev_ops = &amazon_mii_ops; + strcpy(switch_devs[i]->name, "eth%d"); + priv = (struct switch_priv *) netdev_priv(switch_devs[i]); + priv->num = i; + if ((result = register_netdev(switch_devs[i]))) + printk(KERN_WARNING "amazon_mii0: error %i registering device \"%s\"\n", result, switch_devs[i]->name); + else + device_present++; + } + amazon_sw_chip_init(); + return device_present ? 0 : -ENODEV; +} + +static int amazon_mii_remove(struct platform_device *dev) +{ + int i; + struct switch_priv *priv; + for (i = 0; i < AMAZON_SW_INT_NO; i++) { + priv = netdev_priv(switch_devs[i]); + if (priv->dma_device) { + dma_device_unregister(priv->dma_device); + kfree(priv->dma_device); + } + kfree(netdev_priv(switch_devs[i])); + unregister_netdev(switch_devs[i]); + } + return 0; +} + +static struct platform_driver amazon_mii_driver = { + .probe = amazon_mii_probe, + .remove = amazon_mii_remove, + .driver = { + .name = "amazon_mii0", + .owner = THIS_MODULE, + }, +}; + +static int __init amazon_mii_init(void) +{ + int ret = platform_driver_register(&amazon_mii_driver); + if (ret) + printk(KERN_WARNING "amazon_mii0: Error registering platfom driver!\n"); + return ret; +} + +static void __exit amazon_mii_cleanup(void) +{ + platform_driver_unregister(&amazon_mii_driver); +} + +module_init(amazon_mii_init); +module_exit(amazon_mii_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wu Qi Ming"); +MODULE_DESCRIPTION("ethernet driver for AMAZON boards"); + -- cgit v1.1