mirror of https://github.com/hak5/openwrt.git
1494 lines
40 KiB
C
1494 lines
40 KiB
C
/******************************************************************************
|
|
Copyright (c) 2004, Infineon Technologies. All rights reserved.
|
|
|
|
No Warranty
|
|
Because the program is licensed free of charge, there is no warranty for
|
|
the program, to the extent permitted by applicable law. Except when
|
|
otherwise stated in writing the copyright holders and/or other parties
|
|
provide the program "as is" without warranty of any kind, either
|
|
expressed or implied, including, but not limited to, the implied
|
|
warranties of merchantability and fitness for a particular purpose. The
|
|
entire risk as to the quality and performance of the program is with
|
|
you. should the program prove defective, you assume the cost of all
|
|
necessary servicing, repair or correction.
|
|
|
|
In no event unless required by applicable law or agreed to in writing
|
|
will any copyright holder, or any other party who may modify and/or
|
|
redistribute the program as permitted above, be liable to you for
|
|
damages, including any general, special, incidental or consequential
|
|
damages arising out of the use or inability to use the program
|
|
(including but not limited to loss of data or data being rendered
|
|
inaccurate or losses sustained by you or third parties or a failure of
|
|
the program to operate with any other programs), even if such holder or
|
|
other party has been advised of the possibility of such damages.
|
|
******************************************************************************
|
|
Module : admmod.c
|
|
Date : 2004-09-01
|
|
Description : JoeLin
|
|
Remarks:
|
|
|
|
Revision:
|
|
MarsLin, add to support VLAN
|
|
|
|
*****************************************************************************/
|
|
//000001.joelin 2005/06/02 add"ADM6996_MDC_MDIO_MODE" define,
|
|
// if define ADM6996_MDC_MDIO_MODE==> ADM6996LC and ADM6996I will be in MDIO/MDC(SMI)(16 bit) mode,
|
|
// amazon should contrl ADM6996 by MDC/MDIO pin
|
|
// if undef ADM6996_MDC_MDIO_MODE==> ADM6996 will be in EEProm(32 bit) mode,
|
|
// amazon should contrl ADM6996 by GPIO15,16,17,18 pin
|
|
/* 507281:linmars 2005/07/28 support MDIO/EEPROM config mode */
|
|
/* 509201:linmars remove driver testing codes */
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/module.h>
|
|
#include <linux/string.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/delay.h>
|
|
#include <asm/uaccess.h>
|
|
#include <linux/init.h>
|
|
#include <linux/ioctl.h>
|
|
#include <asm/atomic.h>
|
|
#include <asm-mips/amazon/amazon.h>
|
|
#include <asm-mips/amazon/adm6996.h>
|
|
//#include <linux/amazon/adm6996.h>
|
|
|
|
|
|
unsigned int ifx_sw_conf[ADM_SW_MAX_PORT_NUM+1] = \
|
|
{ADM_SW_PORT0_CONF, ADM_SW_PORT1_CONF, ADM_SW_PORT2_CONF, \
|
|
ADM_SW_PORT3_CONF, ADM_SW_PORT4_CONF, ADM_SW_PORT5_CONF};
|
|
unsigned int ifx_sw_bits[8] = \
|
|
{0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
|
|
unsigned int ifx_sw_vlan_port[6] = {0, 2, 4, 6, 7, 8};
|
|
//050613:fchang
|
|
/* 507281:linmars start */
|
|
#ifdef CONFIG_SWITCH_ADM6996_MDIO
|
|
#define ADM6996_MDC_MDIO_MODE 1 //000001.joelin
|
|
#else
|
|
#undef ADM6996_MDC_MDIO_MODE
|
|
#endif
|
|
/* 507281:linmars end */
|
|
#define adm6996i 0
|
|
#define adm6996lc 1
|
|
#define adm6996l 2
|
|
unsigned int adm6996_mode=adm6996i;
|
|
/*
|
|
initialize GPIO pins.
|
|
output mode, low
|
|
*/
|
|
void ifx_gpio_init(void)
|
|
{
|
|
//GPIO16,17,18 direction:output
|
|
//GPIO16,17,18 output 0
|
|
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_DIR) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT) =AMAZON_SW_REG(AMAZON_GPIO_P1_IN)& ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
|
|
|
|
}
|
|
|
|
/* read one bit from mdio port */
|
|
int ifx_sw_mdio_readbit(void)
|
|
{
|
|
//int val;
|
|
|
|
//val = (AMAZON_SW_REG(GPIO_conf0_REG) & GPIO0_INPUT_MASK) >> 8;
|
|
//return val;
|
|
//GPIO16
|
|
return AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&1;
|
|
}
|
|
|
|
/*
|
|
MDIO mode selection
|
|
1 -> output
|
|
0 -> input
|
|
|
|
switch input/output mode of GPIO 0
|
|
*/
|
|
void ifx_mdio_mode(int mode)
|
|
{
|
|
// AMAZON_SW_REG(GPIO_conf0_REG) = mode ? GPIO_ENABLEBITS :
|
|
// ((GPIO_ENABLEBITS | MDIO_INPUT) & ~MDIO_OUTPUT_EN);
|
|
mode?(AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)|=GPIO_MDIO):
|
|
(AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)&=~GPIO_MDIO);
|
|
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_DIR);
|
|
mode?(r|=GPIO_MDIO):(r&=~GPIO_MDIO);
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)=r;*/
|
|
}
|
|
|
|
void ifx_mdc_hi(void)
|
|
{
|
|
//GPIO_SET_HI(GPIO_MDC);
|
|
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDC;
|
|
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
|
|
r|=GPIO_MDC;
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
|
|
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDC;
|
|
}
|
|
|
|
void ifx_mdio_hi(void)
|
|
{
|
|
//GPIO_SET_HI(GPIO_MDIO);
|
|
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDIO;
|
|
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
|
|
r|=GPIO_MDIO;
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
|
|
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDIO;
|
|
}
|
|
|
|
void ifx_mdcs_hi(void)
|
|
{
|
|
//GPIO_SET_HI(GPIO_MDCS);
|
|
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDCS;
|
|
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
|
|
r|=GPIO_MDCS;
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
|
|
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDCS;
|
|
}
|
|
|
|
void ifx_mdc_lo(void)
|
|
{
|
|
//GPIO_SET_LOW(GPIO_MDC);
|
|
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDC;
|
|
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
|
|
r&=~GPIO_MDC;
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
|
|
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDC);
|
|
}
|
|
|
|
void ifx_mdio_lo(void)
|
|
{
|
|
//GPIO_SET_LOW(GPIO_MDIO);
|
|
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDIO;
|
|
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
|
|
r&=~GPIO_MDIO;
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
|
|
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDIO);
|
|
}
|
|
|
|
void ifx_mdcs_lo(void)
|
|
{
|
|
//GPIO_SET_LOW(GPIO_MDCS);
|
|
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDCS;
|
|
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
|
|
r&=~GPIO_MDCS;
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
|
|
|
|
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDCS);
|
|
}
|
|
|
|
/*
|
|
mdc pulse
|
|
0 -> 1 -> 0
|
|
*/
|
|
static void ifx_sw_mdc_pulse(void)
|
|
{
|
|
ifx_mdc_lo();
|
|
udelay(ADM_SW_MDC_DOWN_DELAY);
|
|
ifx_mdc_hi();
|
|
udelay(ADM_SW_MDC_UP_DELAY);
|
|
ifx_mdc_lo();
|
|
}
|
|
|
|
/*
|
|
mdc toggle
|
|
1 -> 0
|
|
*/
|
|
static void ifx_sw_mdc_toggle(void)
|
|
{
|
|
ifx_mdc_hi();
|
|
udelay(ADM_SW_MDC_UP_DELAY);
|
|
ifx_mdc_lo();
|
|
udelay(ADM_SW_MDC_DOWN_DELAY);
|
|
}
|
|
|
|
/*
|
|
enable eeprom write
|
|
For ATC 93C66 type EEPROM; accessing ADM6996 internal EEPROM type registers
|
|
*/
|
|
static void ifx_sw_eeprom_write_enable(void)
|
|
{
|
|
unsigned int op;
|
|
|
|
ifx_mdcs_lo();
|
|
ifx_mdc_lo();
|
|
ifx_mdio_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
/* enable chip select */
|
|
ifx_mdcs_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
/* start bit */
|
|
ifx_mdio_hi();
|
|
ifx_sw_mdc_pulse();
|
|
|
|
/* eeprom write enable */
|
|
op = ADM_SW_BIT_MASK_4;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_EEPROM_WRITE_ENABLE)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
|
|
while (op)
|
|
{
|
|
ifx_mdio_lo();
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
/* disable chip select */
|
|
ifx_mdcs_lo();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
ifx_sw_mdc_pulse();
|
|
}
|
|
|
|
/*
|
|
disable eeprom write
|
|
*/
|
|
static void ifx_sw_eeprom_write_disable(void)
|
|
{
|
|
unsigned int op;
|
|
|
|
ifx_mdcs_lo();
|
|
ifx_mdc_lo();
|
|
ifx_mdio_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
/* enable chip select */
|
|
ifx_mdcs_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
/* start bit */
|
|
ifx_mdio_hi();
|
|
ifx_sw_mdc_pulse();
|
|
/* eeprom write disable */
|
|
op = ADM_SW_BIT_MASK_4;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_EEPROM_WRITE_DISABLE)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
|
|
while (op)
|
|
{
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
/* disable chip select */
|
|
ifx_mdcs_lo();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
ifx_sw_mdc_pulse();
|
|
}
|
|
|
|
/*
|
|
read registers from ADM6996
|
|
serial registers start at 0x200 (addr bit 9 = 1b)
|
|
EEPROM registers -> 16bits; Serial registers -> 32bits
|
|
*/
|
|
#ifdef ADM6996_MDC_MDIO_MODE //smi mode//000001.joelin
|
|
static int ifx_sw_read_adm6996i_smi(unsigned int addr, unsigned int *dat)
|
|
{
|
|
addr=(addr<<16)&0x3ff0000;
|
|
AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) =(0xC0000000|addr);
|
|
while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
|
|
*dat=((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x0FFFF);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int ifx_sw_read_adm6996i(unsigned int addr, unsigned int *dat)
|
|
{
|
|
unsigned int op;
|
|
|
|
ifx_gpio_init();
|
|
|
|
ifx_mdcs_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
ifx_mdcs_lo();
|
|
ifx_mdc_lo();
|
|
ifx_mdio_lo();
|
|
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
/* preamble, 32 bit 1 */
|
|
ifx_mdio_hi();
|
|
op = ADM_SW_BIT_MASK_32;
|
|
while (op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* command start (01b) */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_SMI_START)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* read command (10b) */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_SMI_READ)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* send address A9 ~ A0 */
|
|
op = ADM_SW_BIT_MASK_10;
|
|
while (op)
|
|
{
|
|
if (op & addr)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* turnaround bits */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
ifx_mdio_hi();
|
|
while (op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
udelay(ADM_SW_MDC_DOWN_DELAY);
|
|
|
|
/* set MDIO pin to input mode */
|
|
ifx_mdio_mode(ADM_SW_MDIO_INPUT);
|
|
|
|
/* start read data */
|
|
*dat = 0;
|
|
//adm6996i op = ADM_SW_BIT_MASK_32;
|
|
op = ADM_SW_BIT_MASK_16;//adm6996i
|
|
while (op)
|
|
{
|
|
*dat <<= 1;
|
|
if (ifx_sw_mdio_readbit()) *dat |= 1;
|
|
ifx_sw_mdc_toggle();
|
|
|
|
op >>= 1;
|
|
}
|
|
|
|
/* set MDIO to output mode */
|
|
ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
|
|
|
|
/* dummy clock */
|
|
op = ADM_SW_BIT_MASK_4;
|
|
ifx_mdio_lo();
|
|
while(op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
ifx_mdc_lo();
|
|
ifx_mdio_lo();
|
|
ifx_mdcs_hi();
|
|
|
|
/* EEPROM registers */
|
|
//adm6996i if (!(addr & 0x200))
|
|
//adm6996i {
|
|
//adm6996i if (addr % 2)
|
|
//adm6996i *dat >>= 16;
|
|
//adm6996i else
|
|
//adm6996i *dat &= 0xffff;
|
|
//adm6996i }
|
|
|
|
return 0;
|
|
}
|
|
//adm6996
|
|
static int ifx_sw_read_adm6996l(unsigned int addr, unsigned int *dat)
|
|
{
|
|
unsigned int op;
|
|
|
|
ifx_gpio_init();
|
|
|
|
ifx_mdcs_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
ifx_mdcs_lo();
|
|
ifx_mdc_lo();
|
|
ifx_mdio_lo();
|
|
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
/* preamble, 32 bit 1 */
|
|
ifx_mdio_hi();
|
|
op = ADM_SW_BIT_MASK_32;
|
|
while (op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* command start (01b) */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_SMI_START)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* read command (10b) */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_SMI_READ)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* send address A9 ~ A0 */
|
|
op = ADM_SW_BIT_MASK_10;
|
|
while (op)
|
|
{
|
|
if (op & addr)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* turnaround bits */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
ifx_mdio_hi();
|
|
while (op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
udelay(ADM_SW_MDC_DOWN_DELAY);
|
|
|
|
/* set MDIO pin to input mode */
|
|
ifx_mdio_mode(ADM_SW_MDIO_INPUT);
|
|
|
|
/* start read data */
|
|
*dat = 0;
|
|
op = ADM_SW_BIT_MASK_32;
|
|
while (op)
|
|
{
|
|
*dat <<= 1;
|
|
if (ifx_sw_mdio_readbit()) *dat |= 1;
|
|
ifx_sw_mdc_toggle();
|
|
|
|
op >>= 1;
|
|
}
|
|
|
|
/* set MDIO to output mode */
|
|
ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
|
|
|
|
/* dummy clock */
|
|
op = ADM_SW_BIT_MASK_4;
|
|
ifx_mdio_lo();
|
|
while(op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
ifx_mdc_lo();
|
|
ifx_mdio_lo();
|
|
ifx_mdcs_hi();
|
|
|
|
/* EEPROM registers */
|
|
if (!(addr & 0x200))
|
|
{
|
|
if (addr % 2)
|
|
*dat >>= 16;
|
|
else
|
|
*dat &= 0xffff;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifx_sw_read(unsigned int addr, unsigned int *dat)
|
|
{
|
|
#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
|
|
ifx_sw_read_adm6996i_smi(addr,dat);
|
|
#else
|
|
if (adm6996_mode==adm6996i) ifx_sw_read_adm6996i(addr,dat);
|
|
else ifx_sw_read_adm6996l(addr,dat);
|
|
#endif
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
write register to ADM6996 eeprom registers
|
|
*/
|
|
//for adm6996i -start
|
|
#ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
|
|
static int ifx_sw_write_adm6996i_smi(unsigned int addr, unsigned int dat)
|
|
{
|
|
|
|
AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) = ((addr<<16)&0x3ff0000)|dat|0x80000000;
|
|
while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
|
|
|
|
return 0;
|
|
|
|
}
|
|
#endif //ADM6996_MDC_MDIO_MODE //000001.joelin
|
|
|
|
static int ifx_sw_write_adm6996i(unsigned int addr, unsigned int dat)
|
|
{
|
|
unsigned int op;
|
|
|
|
ifx_gpio_init();
|
|
|
|
ifx_mdcs_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
ifx_mdcs_lo();
|
|
ifx_mdc_lo();
|
|
ifx_mdio_lo();
|
|
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
/* preamble, 32 bit 1 */
|
|
ifx_mdio_hi();
|
|
op = ADM_SW_BIT_MASK_32;
|
|
while (op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* command start (01b) */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_SMI_START)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* write command (01b) */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_SMI_WRITE)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* send address A9 ~ A0 */
|
|
op = ADM_SW_BIT_MASK_10;
|
|
while (op)
|
|
{
|
|
if (op & addr)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* turnaround bits */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
ifx_mdio_hi();
|
|
while (op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
udelay(ADM_SW_MDC_DOWN_DELAY);
|
|
|
|
/* set MDIO pin to output mode */
|
|
ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
|
|
|
|
|
|
/* start write data */
|
|
op = ADM_SW_BIT_MASK_16;
|
|
while (op)
|
|
{
|
|
if (op & dat)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_toggle();
|
|
op >>= 1;
|
|
}
|
|
|
|
// /* set MDIO to output mode */
|
|
// ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
|
|
|
|
/* dummy clock */
|
|
op = ADM_SW_BIT_MASK_4;
|
|
ifx_mdio_lo();
|
|
while(op)
|
|
{
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
ifx_mdc_lo();
|
|
ifx_mdio_lo();
|
|
ifx_mdcs_hi();
|
|
|
|
/* EEPROM registers */
|
|
//adm6996i if (!(addr & 0x200))
|
|
//adm6996i {
|
|
//adm6996i if (addr % 2)
|
|
//adm6996i *dat >>= 16;
|
|
//adm6996i else
|
|
//adm6996i *dat &= 0xffff;
|
|
//adm6996i }
|
|
|
|
return 0;
|
|
}
|
|
//for adm6996i-end
|
|
static int ifx_sw_write_adm6996l(unsigned int addr, unsigned int dat)
|
|
{
|
|
unsigned int op;
|
|
|
|
ifx_gpio_init();
|
|
|
|
/* enable write */
|
|
ifx_sw_eeprom_write_enable();
|
|
|
|
/* chip select */
|
|
ifx_mdcs_hi();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
|
|
/* issue write command */
|
|
/* start bit */
|
|
ifx_mdio_hi();
|
|
ifx_sw_mdc_pulse();
|
|
|
|
/* EEPROM write command */
|
|
op = ADM_SW_BIT_MASK_2;
|
|
while (op)
|
|
{
|
|
if (op & ADM_SW_EEPROM_WRITE)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_pulse();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* send address A7 ~ A0 */
|
|
op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 1);
|
|
|
|
while (op)
|
|
{
|
|
if (op & addr)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_toggle();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* start write data */
|
|
op = ADM_SW_BIT_MASK_16;
|
|
while (op)
|
|
{
|
|
if (op & dat)
|
|
ifx_mdio_hi();
|
|
else
|
|
ifx_mdio_lo();
|
|
|
|
ifx_sw_mdc_toggle();
|
|
op >>= 1;
|
|
}
|
|
|
|
/* disable cs & wait 1 clock */
|
|
ifx_mdcs_lo();
|
|
udelay(ADM_SW_CS_DELAY);
|
|
ifx_sw_mdc_toggle();
|
|
|
|
ifx_sw_eeprom_write_disable();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifx_sw_write(unsigned int addr, unsigned int dat)
|
|
{
|
|
#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
|
|
ifx_sw_write_adm6996i_smi(addr,dat);
|
|
#else //000001.joelin
|
|
if (adm6996_mode==adm6996i) ifx_sw_write_adm6996i(addr,dat);
|
|
else ifx_sw_write_adm6996l(addr,dat);
|
|
#endif //000001.joelin
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
do switch PHY reset
|
|
*/
|
|
int ifx_sw_reset(void)
|
|
{
|
|
/* reset PHY */
|
|
ifx_sw_write(ADM_SW_PHY_RESET, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* 509201:linmars start */
|
|
#if 0
|
|
/*
|
|
check port status
|
|
*/
|
|
int ifx_check_port_status(int port)
|
|
{
|
|
unsigned int val;
|
|
|
|
if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM))
|
|
{
|
|
ifx_printf(("error on port number (%d)!!\n", port));
|
|
return -1;
|
|
}
|
|
|
|
ifx_sw_read(ifx_sw_conf[port], &val);
|
|
if (ifx_sw_conf[port]%2) val >>= 16;
|
|
/* only 16bits are effective */
|
|
val &= 0xFFFF;
|
|
|
|
ifx_printf(("Port %d status (%.8x): \n", port, val));
|
|
|
|
if (val & ADM_SW_PORT_FLOWCTL)
|
|
ifx_printf(("\t802.3x flow control supported!\n"));
|
|
else
|
|
ifx_printf(("\t802.3x flow control not supported!\n"));
|
|
|
|
if (val & ADM_SW_PORT_AN)
|
|
ifx_printf(("\tAuto negotiation ON!\n"));
|
|
else
|
|
ifx_printf(("\tAuto negotiation OFF!\n"));
|
|
|
|
if (val & ADM_SW_PORT_100M)
|
|
ifx_printf(("\tLink at 100M!\n"));
|
|
else
|
|
ifx_printf(("\tLink at 10M!\n"));
|
|
|
|
if (val & ADM_SW_PORT_FULL)
|
|
ifx_printf(("\tFull duplex!\n"));
|
|
else
|
|
ifx_printf(("\tHalf duplex!\n"));
|
|
|
|
if (val & ADM_SW_PORT_DISABLE)
|
|
ifx_printf(("\tPort disabled!\n"));
|
|
else
|
|
ifx_printf(("\tPort enabled!\n"));
|
|
|
|
if (val & ADM_SW_PORT_TOS)
|
|
ifx_printf(("\tTOS enabled!\n"));
|
|
else
|
|
ifx_printf(("\tTOS disabled!\n"));
|
|
|
|
if (val & ADM_SW_PORT_PPRI)
|
|
ifx_printf(("\tPort priority first!\n"));
|
|
else
|
|
ifx_printf(("\tVLAN or TOS priority first!\n"));
|
|
|
|
if (val & ADM_SW_PORT_MDIX)
|
|
ifx_printf(("\tAuto MDIX!\n"));
|
|
else
|
|
ifx_printf(("\tNo auto MDIX\n"));
|
|
|
|
ifx_printf(("\tPVID: %d\n", \
|
|
((val >> ADM_SW_PORT_PVID_SHIFT)&ifx_sw_bits[ADM_SW_PORT_PVID_BITS])));
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
initialize a VLAN
|
|
clear all VLAN bits
|
|
*/
|
|
int ifx_sw_vlan_init(int vlanid)
|
|
{
|
|
ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
add a port to certain vlan
|
|
*/
|
|
int ifx_sw_vlan_add(int port, int vlanid)
|
|
{
|
|
int reg = 0;
|
|
|
|
if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) ||
|
|
(vlanid > ADM_SW_MAX_VLAN_NUM))
|
|
{
|
|
ifx_printf(("Port number or VLAN number ERROR!!\n"));
|
|
return -1;
|
|
}
|
|
ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, ®);
|
|
reg |= (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 <joe.lin@infineon.com>");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_init(init_adm6996_module);
|
|
module_exit(cleanup_adm6996_module);
|
|
|