/****************************************************************************** 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: *****************************************************************************/ #include #include #include #include #include #include #include #include #include "adm6996.h" #include #include #include #define adm_printf printk static unsigned int adm_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}; static unsigned int adm_bits[8] = {0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff}; static unsigned int adm_vlan_port[6] = {0, 2, 4, 6, 7, 8}; #define admi 0 #define admlc 1 #define adml 2 /*--- #define ADM6996i ---*/ #ifdef ADM6996i static unsigned int adm_mode=admi; #endif /*------------------------------------------------------------------------------------------*\ * Register cache \*------------------------------------------------------------------------------------------*/ #define NUMBER_OF_SERIAL_REGISTERS (0x3c + 1) #define MAX_SERIAL_REGISTER_AGE 200 struct adm_struct adm_serial_register; static unsigned int *serial_register = (unsigned int *) &adm_serial_register; static unsigned long serial_register_timestamp[NUMBER_OF_SERIAL_REGISTERS]; static int adm_serial_registers[] = { REG_ADM_ID, REG_ADM_STATUS0, REG_ADM_STATUS1, REG_ADM_CABLEBROKENSTATUS, REG_ADM_RXPKTCNT0, REG_ADM_RXPKTCNT1, REG_ADM_RXPKTCNT2, REG_ADM_RXPKTCNT3, REG_ADM_RXPKTCNT4, REG_ADM_RXPKTCNT5, REG_ADM_RXPKTBYTECNT0, REG_ADM_RXPKTBYTECNT1, REG_ADM_RXPKTBYTECNT2, REG_ADM_RXPKTBYTECNT3, REG_ADM_RXPKTBYTECNT4, REG_ADM_RXPKTBYTECNT5, REG_ADM_TXPKTCNT0, REG_ADM_TXPKTCNT1, REG_ADM_TXPKTCNT2, REG_ADM_TXPKTCNT3, REG_ADM_TXPKTCNT4, REG_ADM_TXPKTCNT5, REG_ADM_TXPKTBYTECNT0, REG_ADM_TXPKTBYTECNT1, REG_ADM_TXPKTBYTECNT2, REG_ADM_TXPKTBYTECNT3, REG_ADM_TXPKTBYTECNT4, REG_ADM_TXPKTBYTECNT5, REG_ADM_COLLISIONCNT0, REG_ADM_COLLISIONCNT1, REG_ADM_COLLISIONCNT2, REG_ADM_COLLISIONCNT3, REG_ADM_COLLISIONCNT4, REG_ADM_COLLISIONCNT5, REG_ADM_ERRCNT0, REG_ADM_ERRCNT1, REG_ADM_ERRCNT2, REG_ADM_ERRCNT3, REG_ADM_ERRCNT4, REG_ADM_ERRCNT5, REG_ADM_OVERFLOWFLAG0, REG_ADM_OVERFLOWFLAG1, REG_ADM_OVERFLOWFLAG2, -1 }; /*------------------------------------------------------------------------------------------*\ * GPIO- Config AR7 \*------------------------------------------------------------------------------------------*/ #define EECK (1 << 27) /*--- EECLK -> MII_DCLK ---*/ #define EDO_EDI (1 << 26) /*--- EDO/EDI -> MII_DIO ---*/ #define EECS (1 << 4 ) /*--- EECS -> UARTB_TD/IICCKL/FSER_CLK ---*/ struct _hw_gpio *hw_gpio = (struct _hw_gpio *) AVALANCHE_GPIO_BASE; /*------------------------------------------------------------------------------------------*\ * initialize GPIO pins. output mode, low \*------------------------------------------------------------------------------------------*/ void adm_gpio_init(void) { /*--- set pins GPIO, OUTPUT, LOW ---*/ hw_gpio->Enable.Register |= (EECK + EDO_EDI + EECS); hw_gpio->Direction.Register &= ~(EECK + EDO_EDI + EECS); hw_gpio->OutputData.Register &= ~(EECK + EDO_EDI + EECS); } /*------------------------------------------------------------------------------------------*\ * read one bit from mdio port \*------------------------------------------------------------------------------------------*/ int adm_mdio_readbit(void) { return hw_gpio->InputData.Bits.mii_dio; } /*------------------------------------------------------------------------------------------*\ MDIO mode selection 0 -> output 1 -> input switch input/output mode of GPIO 0 \*------------------------------------------------------------------------------------------*/ void adm_mdio_mode(int mode) { hw_gpio->Direction.Bits.mii_dio = mode; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void adm_mdc_hi(void) { hw_gpio->OutputData.Bits.mii_dclk = 1; } void adm_mdio_hi(void) { hw_gpio->OutputData.Bits.mii_dio = 1; } void adm_mdcs_hi(void) { hw_gpio->OutputData.Bits.fser_clk = 1; } void adm_mdc_lo(void) { hw_gpio->OutputData.Bits.mii_dclk = 0; } void adm_mdio_lo(void) { hw_gpio->OutputData.Bits.mii_dio = 0; } void adm_mdcs_lo(void) { hw_gpio->OutputData.Bits.fser_clk = 0; } /*------------------------------------------------------------------------------------------*\ * mdc pulse * 0 -> 1 -> 0 \*------------------------------------------------------------------------------------------*/ static void adm_mdc_pulse(void) { adm_mdc_lo(); udelay(ADM_SW_MDC_DOWN_DELAY); adm_mdc_hi(); udelay(ADM_SW_MDC_UP_DELAY); adm_mdc_lo(); } /*------------------------------------------------------------------------------------------*\ * mdc toggle * 1 -> 0 \*------------------------------------------------------------------------------------------*/ static void adm_mdc_toggle(void) { adm_mdc_hi(); udelay(ADM_SW_MDC_UP_DELAY); adm_mdc_lo(); udelay(ADM_SW_MDC_DOWN_DELAY); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ /*--- #define adm_write_bits_pulsed(value, bits) { \ ---*/ /*--- unsigned int op = 1 << ((bits) - 1); \ ---*/ /*--- while (op) { \ ---*/ /*--- if (op & (value)) \ ---*/ /*--- adm_mdio_hi(); \ ---*/ /*--- else \ ---*/ /*--- adm_mdio_lo(); \ ---*/ /*--- adm_mdc_pulse(); \ ---*/ /*--- op >>= 1; \ ---*/ /*--- } \ ---*/ /*--- } ---*/ /*------------------------------------------------------------------------------------------*\ * enable eeprom write * For ATC 93C66 type EEPROM; accessing ADM6996 internal EEPROM type registers \*------------------------------------------------------------------------------------------*/ static void adm_eeprom_write_enable(void) { unsigned int op; adm_mdcs_lo(); adm_mdc_lo(); adm_mdio_hi(); udelay(ADM_SW_CS_DELAY); /* enable chip select */ adm_mdcs_hi(); udelay(ADM_SW_CS_DELAY); /* start bit */ adm_mdio_hi(); adm_mdc_pulse(); /* eeprom write enable */ /*--- adm_write_bits_pulsed(ADM_SW_EEPROM_WRITE_ENABLE, 4); ---*/ op = ADM_SW_BIT_MASK_4; while (op) { if (op & ADM_SW_EEPROM_WRITE_ENABLE) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3); while (op) { adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* disable chip select */ adm_mdcs_lo(); udelay(ADM_SW_CS_DELAY); adm_mdc_pulse(); } /*------------------------------------------------------------------------------------------*\ * disable eeprom write \*------------------------------------------------------------------------------------------*/ static void adm_eeprom_write_disable(void) { unsigned int op; adm_mdcs_lo(); adm_mdc_lo(); adm_mdio_hi(); udelay(ADM_SW_CS_DELAY); /* enable chip select */ adm_mdcs_hi(); udelay(ADM_SW_CS_DELAY); /* start bit */ adm_mdio_hi(); adm_mdc_pulse(); /* eeprom write disable */ /*--- adm_write_bits_pulsed(ADM_SW_EEPROM_WRITE_DISABLE, 4); ---*/ op = ADM_SW_BIT_MASK_4; while (op) { if (op & ADM_SW_EEPROM_WRITE_DISABLE) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3); while (op) { adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* disable chip select */ adm_mdcs_lo(); udelay(ADM_SW_CS_DELAY); adm_mdc_pulse(); } /*------------------------------------------------------------------------------------------*\ read registers from ADM6996 serial registers start at 0x200 (addr bit 9 = 1b) EEPROM registers -> 16bits; Serial registers -> 32bits \*------------------------------------------------------------------------------------------*/ #ifdef ADM6996i static unsigned int adm_read_admi(unsigned int addr) { unsigned int op, dat; adm_gpio_init(); adm_mdcs_hi(); udelay(ADM_SW_CS_DELAY); adm_mdcs_lo(); adm_mdc_lo(); adm_mdio_lo(); udelay(ADM_SW_CS_DELAY); /* preamble, 32 bit 1 */ adm_mdio_hi(); op = ADM_SW_BIT_MASK_32; while (op) { adm_mdc_pulse(); op >>= 1; } /* command start (01b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_START) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* read command (10b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_READ) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* send address A9 ~ A0 */ op = ADM_SW_BIT_MASK_10; while (op) { if (op & addr) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* set MDIO pin to input mode */ adm_mdio_mode(ADM_SW_MDIO_INPUT); /* turnaround bits */ op = ADM_SW_BIT_MASK_2; adm_mdio_hi(); while (op) { adm_mdc_pulse(); op >>= 1; } udelay(ADM_SW_MDC_DOWN_DELAY); /* start read data */ dat = 0; //admi op = ADM_SW_BIT_MASK_32; op = ADM_SW_BIT_MASK_16;//admi while (op) { dat <<= 1; if (adm_mdio_readbit()) dat |= 1; adm_mdc_toggle(); op >>= 1; } /* set MDIO to output mode */ adm_mdio_mode(ADM_SW_MDIO_OUTPUT); /* dummy clock */ op = ADM_SW_BIT_MASK_4; adm_mdio_lo(); while(op) { adm_mdc_pulse(); op >>= 1; } adm_mdc_lo(); adm_mdio_lo(); adm_mdcs_hi(); /* EEPROM registers */ //admi if (!(addr & 0x200)) //admi { //admi if (addr % 2) //admi dat >>= 16; //admi else //admi dat &= 0xffff; //admi } return dat; } #endif /*--- #ifdef ADM6996i ---*/ /*------------------------------------------------------------------------------------------*\ --- adm --- read registers from ADM6996 serial registers start at 0x200 (addr bit 9 = 1b) EEPROM registers -> 16bits; Serial registers -> 32bits \*------------------------------------------------------------------------------------------*/ static unsigned int adm_read_adml(unsigned int addr) { unsigned int op, dat; adm_gpio_init(); adm_mdcs_hi(); udelay(ADM_SW_CS_DELAY); adm_mdcs_lo(); adm_mdc_lo(); adm_mdio_lo(); udelay(ADM_SW_CS_DELAY); /* preamble, 32 bit 1 */ adm_mdio_hi(); op = ADM_SW_BIT_MASK_32; while (op) { adm_mdc_pulse(); op >>= 1; } /* command start (01b) */ /*--- adm_write_bits_pulsed(ADM_SW_SMI_START, 2); ---*/ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_START) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* read command (10b) */ /*--- adm_write_bits_pulsed(ADM_SW_SMI_READ, 2); ---*/ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_READ) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* send address A9 ~ A0 */ /*--- adm_write_bits_pulsed(addr, 10); ---*/ op = ADM_SW_BIT_MASK_10; while (op) { if (op & addr) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* set MDIO pin to input mode */ adm_mdio_mode(ADM_SW_MDIO_INPUT); /* turnaround bits */ op = ADM_SW_BIT_MASK_2; adm_mdio_hi(); while (op) { adm_mdc_pulse(); op >>= 1; } udelay(ADM_SW_MDC_DOWN_DELAY); /* start read data */ dat = 0; op = ADM_SW_BIT_MASK_32; while (op) { dat <<= 1; if (adm_mdio_readbit()) dat |= 1; adm_mdc_toggle(); op >>= 1; } /* set MDIO to output mode */ adm_mdio_mode(ADM_SW_MDIO_OUTPUT); /* dummy clock */ op = ADM_SW_BIT_MASK_4; adm_mdio_lo(); while(op) { adm_mdc_pulse(); op >>= 1; } adm_mdc_lo(); adm_mdio_lo(); adm_mdcs_hi(); /* EEPROM registers */ if (!(addr & 0x200)) { if (addr % 2) dat >>= 16; else dat &= 0xffff; } return dat; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int adm_read(unsigned int addr) { unsigned int address = addr & 0x7F; if((addr & 0x200)) { /* Serielles Register lesen */ if( (serial_register_timestamp[address] + MAX_SERIAL_REGISTER_AGE < jiffies) || (serial_register_timestamp[address] > jiffies)) { /* Register-Cache ungueltig */ # ifdef ADM6996i if (adm_mode == admi) serial_register[address] = adm_read_admi(addr); else # endif /*--- #ifdef ADM6996i ---*/ serial_register[address] = adm_read_adml(addr); serial_register_timestamp[address] = jiffies; } return serial_register[address]; } else { # ifdef ADM6996i if (adm_mode==admi) return adm_read_admi(addr); else # endif return adm_read_adml(addr); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void adm_update_cache(void) { unsigned int i = 0; for(i = 0; adm_serial_registers[i] != -1; i++) { ADM_GET_SERIAL_REG(adm_serial_registers[i]); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void adm_invalidate_register_cache(unsigned int addr) { serial_register_timestamp[addr & 0x7F] += MAX_SERIAL_REGISTER_AGE + 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #ifdef ADM6996i static int adm_write_admi(unsigned int addr, unsigned int dat) { unsigned int op; adm_gpio_init(); adm_mdcs_hi(); udelay(ADM_SW_CS_DELAY); adm_mdcs_lo(); adm_mdc_lo(); adm_mdio_lo(); udelay(ADM_SW_CS_DELAY); /* preamble, 32 bit 1 */ adm_mdio_hi(); op = ADM_SW_BIT_MASK_32; while (op) { adm_mdc_pulse(); op >>= 1; } /* command start (01b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_START) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* write command (01b) */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_SMI_WRITE) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* send address A9 ~ A0 */ op = ADM_SW_BIT_MASK_10; while (op) { if (op & addr) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* set MDIO pin to output mode */ adm_mdio_mode(ADM_SW_MDIO_OUTPUT); /* turnaround bits */ op = ADM_SW_BIT_MASK_2; adm_mdio_hi(); while (op) { adm_mdc_pulse(); op >>= 1; } udelay(ADM_SW_MDC_DOWN_DELAY); /* start write data */ op = ADM_SW_BIT_MASK_16; while (op) { if (op & dat) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_toggle(); op >>= 1; } // /* set MDIO to output mode */ // adm_mdio_mode(ADM_SW_MDIO_OUTPUT); /* dummy clock */ op = ADM_SW_BIT_MASK_4; adm_mdio_lo(); while(op) { adm_mdc_pulse(); op >>= 1; } adm_mdc_lo(); adm_mdio_lo(); adm_mdcs_hi(); /* EEPROM registers */ //admi if (!(addr & 0x200)) //admi { //admi if (addr % 2) //admi *dat >>= 16; //admi else //admi *dat &= 0xffff; //admi } return 0; } #endif /*--- #ifdef ADM6996i ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int adm_write_adml(unsigned int addr, unsigned int dat) { unsigned int op; adm_gpio_init(); /* enable write */ adm_eeprom_write_enable(); /* chip select */ adm_mdcs_hi(); udelay(ADM_SW_CS_DELAY); /* issue write command */ /* start bit */ adm_mdio_hi(); adm_mdc_pulse(); /* EEPROM write command */ op = ADM_SW_BIT_MASK_2; while (op) { if (op & ADM_SW_EEPROM_WRITE) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_pulse(); op >>= 1; } /* send address A7 ~ A0 */ op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 1); while (op) { if (op & addr) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_toggle(); op >>= 1; } /* start write data */ op = ADM_SW_BIT_MASK_16; while (op) { if (op & dat) adm_mdio_hi(); else adm_mdio_lo(); adm_mdc_toggle(); op >>= 1; } /* disable cs & wait 1 clock */ adm_mdcs_lo(); udelay(ADM_SW_CS_DELAY); adm_mdc_toggle(); adm_eeprom_write_disable(); return 0; } /*------------------------------------------------------------------------------------------*\ * write register to ADM6996 eeprom registers \*------------------------------------------------------------------------------------------*/ int adm_write(unsigned int addr, unsigned int dat) { #ifdef ADM6996i if (adm_mode==admi) adm_write_admi(addr, dat); else #endif adm_write_adml(addr, dat); return 0; } /* do switch PHY reset */ int adm_reset(void) { /* reset PHY */ adm_write(ADM_SW_PHY_RESET, 0); return 0; } /* check port status */ int adm_check_port_status(int port) { unsigned int val; if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM)) { adm_printf("error on port number (%d)!!\n", port); return -1; } val = adm_read(adm_conf[port]); if (adm_conf[port]%2) val >>= 16; /* only 16bits are effective */ val &= 0xFFFF; adm_printf("Port %d status (%.8x): \n", port, val); if (val & ADM_SW_PORT_FLOWCTL) adm_printf("\t802.3x flow control supported!\n"); else adm_printf("\t802.3x flow control not supported!\n"); if (val & ADM_SW_PORT_AN) adm_printf("\tAuto negotiation ON!\n"); else adm_printf("\tAuto negotiation OFF!\n"); if (val & ADM_SW_PORT_100M) adm_printf("\tLink at 100M!\n"); else adm_printf("\tLink at 10M!\n"); if (val & ADM_SW_PORT_FULL) adm_printf("\tFull duplex!\n"); else adm_printf("\tHalf duplex!\n"); if (val & ADM_SW_PORT_DISABLE) adm_printf("\tPort disabled!\n"); else adm_printf("\tPort enabled!\n"); if (val & ADM_SW_PORT_TOS) adm_printf("\tTOS enabled!\n"); else adm_printf("\tTOS disabled!\n"); if (val & ADM_SW_PORT_PPRI) adm_printf("\tPort priority first!\n"); else adm_printf("\tVLAN or TOS priority first!\n"); if (val & ADM_SW_PORT_MDIX) adm_printf("\tAuto MDIX!\n"); else adm_printf("\tNo auto MDIX\n"); adm_printf("\tPVID: %d\n", \ ((val >> ADM_SW_PORT_PVID_SHIFT)&adm_bits[ADM_SW_PORT_PVID_BITS])); return 0; } /*------------------------------------------------------------------------------------------*\ * initialize a VLAN * clear all VLAN bits \*------------------------------------------------------------------------------------------*/ int adm_vlan_init(int vlanid) { adm_write(ADM_SW_VLAN0_CONF + vlanid, 0); return 0; } /*------------------------------------------------------------------------------------------*\ * add a port to certain vlan \*------------------------------------------------------------------------------------------*/ int adm_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)) { adm_printf("Port number or VLAN number ERROR!!\n"); return -1; } reg = adm_read(ADM_SW_VLAN0_CONF + vlanid); reg |= (1 << adm_vlan_port[port]); adm_write(ADM_SW_VLAN0_CONF + vlanid, reg); return 0; } /*------------------------------------------------------------------------------------------*\ * delete a given port from certain vlan \*------------------------------------------------------------------------------------------*/ int adm_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)) { adm_printf("Port number or VLAN number ERROR!!\n"); return -1; } reg = adm_read(ADM_SW_VLAN0_CONF + vlanid); reg &= ~(1 << adm_vlan_port[port]); adm_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) \*------------------------------------------------------------------------------------------*/ void adm_init(void) { unsigned int i; for(i = 0; i < NUMBER_OF_SERIAL_REGISTERS; i++) { serial_register[i] = 0; serial_register_timestamp[i] = 0; } } /*------------------------------------------------------------------------------------------*\ * Reset the VLAN settings of the switch * \*------------------------------------------------------------------------------------------*/ void adm_vlan_fbox_reset(void) { unsigned int RegData, group; /* VLAN abschalten */ ADM_PUT_EEPROM_REG(ADM_SW_VLAN_MODE, 0xff00); for(group = 0; group < 16; group++) ADM_PUT_EEPROM_REG(ADM_SW_VLAN0_CONF + group, 0xFFFF); /* Alle aktiven Portsder VLAN-Gruppe 0 zuordnen, kein Tagging aktiv */ RegData = ADM_SW_PORT_FLOWCTL | ADM_SW_PORT_AN | ADM_SW_PORT_100M | ADM_SW_PORT_FULL | ADM_SW_PORT_MDIX | (0 << ADM_SW_PORT_PVID_SHIFT); ADM_PUT_EEPROM_REG(ADM_SW_PORT5_CONF, RegData); ADM_PUT_EEPROM_REG(ADM_SW_PORT0_CONF, RegData); ADM_PUT_EEPROM_REG(ADM_SW_PORT1_CONF, RegData); ADM_PUT_EEPROM_REG(ADM_SW_PORT2_CONF, RegData); ADM_PUT_EEPROM_REG(ADM_SW_PORT3_CONF, RegData); /* Port 4 ist nicht verbunden, also abschalten */ RegData = ADM_SW_PORT_FLOWCTL | ADM_SW_PORT_AN | ADM_SW_PORT_100M | ADM_SW_PORT_FULL | ADM_SW_PORT_MDIX | (0 << ADM_SW_PORT_PVID_SHIFT) | ADM_SW_PORT_DISABLE; ADM_PUT_EEPROM_REG(ADM_SW_PORT4_CONF, RegData); } /*------------------------------------------------------------------------------------------*\ * Configure VLAN on the switch * * * * Argument: config - Configuration structure * * * * Return: 0 - everything okay, negative value otherwise * \*------------------------------------------------------------------------------------------*/ int adm_vlan_fbox_config(struct avm_switch_struct *config) { unsigned int RegData, vlan_mapping, group, port; /* VLAN reseten */ adm_vlan_fbox_reset(); if(config->groups == 0) /* Reset VLAN only */ return 0; /* MAC clone, 802.1q based VLAN */ ADM_PUT_EEPROM_REG(ADM_SW_VLAN_MODE, 0xff30); /* Keep tags for outgoing packets from internal port */ RegData = ADM_SW_PORT_FLOWCTL | ADM_SW_PORT_AN | ADM_SW_PORT_100M | ADM_SW_PORT_FULL | ADM_SW_PORT_MDIX | ADM_SW_PORT_TAG; ADM_PUT_EEPROM_REG(ADM_SW_PORT5_CONF, RegData); for(group = 0; group < config->groups; group++) { vlan_mapping = 0x7f << 9; for(port = 0; port < 5; port++) { if(config->vlan[group].source_mask & (1 << port)) { RegData = ADM_SW_PORT_FLOWCTL | ADM_SW_PORT_AN | ADM_SW_PORT_100M | ADM_SW_PORT_FULL | ADM_SW_PORT_MDIX | (config->vlan[group].id << ADM_SW_PORT_PVID_SHIFT); switch(port) { case 0: /* Keep tags for outgoing packets from internal port */ RegData |= ADM_SW_PORT_TAG; ADM_PUT_EEPROM_REG(ADM_SW_PORT5_CONF, RegData); break; case 1: ADM_PUT_EEPROM_REG(ADM_SW_PORT0_CONF, RegData); break; case 2: ADM_PUT_EEPROM_REG(ADM_SW_PORT1_CONF, RegData); break; case 3: ADM_PUT_EEPROM_REG(ADM_SW_PORT2_CONF, RegData); break; case 4: ADM_PUT_EEPROM_REG(ADM_SW_PORT3_CONF, RegData); break; } } if(config->vlan[group].target_mask & (1 << port)) { switch(port) { case 0: vlan_mapping |= 1 << 8; break; /* Internal port */ case 1: vlan_mapping |= 1 << 0; break; /* External port 1 */ case 2: vlan_mapping |= 1 << 2; break; /* External port 1 */ case 3: vlan_mapping |= 1 << 4; break; /* External port 1 */ case 4: vlan_mapping |= 1 << 6; break; /* External port 1 */ default: # if !defined(CONFIG_NO_PRINTK) printk(KERN_ERR "CPMAC ADM: Illegal port?\n"); # endif /*--- #if !defined(CONFIG_NO_PRINTK) ---*/ break; } } } ADM_PUT_EEPROM_REG(ADM_SW_VLAN0_CONF + config->vlan[group].id, vlan_mapping); } return 0; }