/**************************************************************************** Copyright 2009 Infineon Technologies AG Am Campeon 1-12; 81726 Munich, Germany For licensing information, see the file 'LICENSE' in the root folder of this software module. ***************************************************************************** \file ifxmips_vr9_gphy.c \remarks implement GPHY driver on VR9 platform *****************************************************************************/ #include #include /* printk() */ #include #include /* size_t */ #include /* struct device, and other headers */ #include #include #include #include /* eth_type_trans */ #include #include #include #include #include #include #include #include #include #include #include /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #define GPHY_FW_DIRECT_MAP //#include "ifxmips_eth.h" #if defined(CONFIG_VR9) #include "switch_api/ifxmips_sw_reg.h" #include "switch_api/ifxmips_gphy_sw.h" #include "switch_api/gphy_fw_ge.h" #if !defined(GPHY_FW_DIRECT_MAP) #include "switch_api/gphy_fw_fe.h" #endif /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ #endif /*CONFIG_VR9*/ #if defined(CONFIG_GE_MODE) #define IFX_GPHY_DEFAULT_FW 1 #define IFX_GPHY_MODE "GE Mode" #endif /*CONFIG_GE_MODE*/ #define IFX_DRV_MODULE_NAME "ifxmips_vr9_gphy" #define IFX_DRV_MODULE_VERSION "0.6" #define IFX_GPHY_INITCLK "25MHz" #define PROC_DATA_LENGTH 12 #define MAX_PHYS NUM_ETH_INF #define RGMII_MODE 0 static char version[] __devinitdata = IFX_DRV_MODULE_NAME ": V" IFX_DRV_MODULE_VERSION ""; static char ver[] __devinitdata = ":v" IFX_DRV_MODULE_VERSION ""; static char GPHY_CLK[] __devinitdata = IFX_GPHY_INITCLK; #if !defined(GPHY_FW_DIRECT_MAP) static char gphy_fw_dma[GPHY_FW_LEN_D]; #endif /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ struct proc_data_t { char name[PROC_DATA_LENGTH + 1]; char gphyNum[PROC_DATA_LENGTH + 1]; char value[PROC_DATA_LENGTH + 1]; }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct proc_data_t ifx_phy_mdio_data[] = { [0] = { .name = "phy0_mdio", .value = "0x11", .gphyNum = "0" }, [1] = { .name = "phy1_mdio", .value = "0x13", .gphyNum = "1" }, [2] = { .name = "phy2_mdio", .value = "0x00", .gphyNum = "2" }, [3] = { .name = "phy3_mdio", .value = "0x01", .gphyNum = "3" } }; #if !defined(GPHY_FW_DIRECT_MAP) struct proc_data_t ifx_phy_mode[] = { [0] = { .name = "mode", .value = "GE", .gphyNum = "0" }, [1] = { .name = "mode", .value = "GE", .gphyNum = "1" }, [2] = { .name = "mode", .value = "GE", .gphyNum = "2" }, [3] = { .name = "mode", .value = "GE", .gphyNum = "3" } }; #endif /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ struct proc_data_t ifx_phy_reset_data[] = { [0] = { .name = "reset", .value = "0", .gphyNum = "0" }, [1] = { .name = "reset", .value = "0", .gphyNum = "1" }, [2] = { .name = "reset", .value = "0", .gphyNum = "2" }, [3] = { .name = "reset", .value = "0", .gphyNum = "3" } }; struct proc_data_t ifx_phy_power_data[] = { [0] = { .name = "power", .value = "1", .gphyNum = "0" }, [1] = { .name = "power", .value = "1", .gphyNum = "1" }, [2] = { .name = "power", .value = "1", .gphyNum = "2" }, [3] = { .name = "power", .value = "1", .gphyNum = "3" }, }; static struct proc_dir_entry* ifx_gphy_dir=NULL; #if !defined(GPHY_FW_DIRECT_MAP) static struct proc_dir_entry* ifx_gphy_mode[MAX_PHYS]; #endif /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ static struct proc_dir_entry* ifx_gphy_mdio[MAX_PHYS]; static struct proc_dir_entry* ifx_gphy_reset[MAX_PHYS]; static struct proc_dir_entry* ifx_gphy_power[MAX_PHYS]; #ifdef CONFIG_GPHY_TRAFFIC_LED_SW_IMPLEMENTATION enum gphy_id_type { GPHY_ID_0 = 0, GPHY_ID_1 = 1, GPHY_ID_2 = 2, GPHY_ID_3 = 3, GPHY_ID_4 = 4, GPHY_ID_5 = 5, }; #define NUM_OF_PORTS 6 #define WAIT_TIMEOUT 10 #define SWITCH_LED_CON_REG 0x1B void gphy_data_led_on (int); void gphy_data_led_off (int); /* Thread Related */ /* -------- */ struct task_struct *gphy_led_thread_id; struct task_struct *gphy_rmon_poll_thread_id; static int gphy_led_thread (void *arg); static int gphy_rmon_poll_thread (void *arg); /* Signal Related */ /* -------- */ wait_queue_head_t gphy_led_thread_wait; int gphy_led_need_to_flash[NUM_OF_PORTS] = {0,0,0,0,0,0}; int gphy_led_status_on[NUM_OF_PORTS] = {0,0,0,0,0,0}; /* RMON Counters related */ #define VR9_SWIP_BASE_ADDR (0xBE108000) #define VR9_SWIP_TOP_BASE_ADDR (VR9_SWIP_BASE_ADDR + (0x0C40 * 4)) #define ETHSW_BM_RAM_VAL_3_REG ( VR9_SWIP_BASE_ADDR + (0x40 * 4) ) #define ETHSW_BM_RAM_VAL_2_REG ( VR9_SWIP_BASE_ADDR + (0x41 * 4) ) #define ETHSW_BM_RAM_VAL_1_REG ( VR9_SWIP_BASE_ADDR + (0x42 * 4) ) #define ETHSW_BM_RAM_VAL_0_REG ( VR9_SWIP_BASE_ADDR + (0x43 * 4) ) #define ETHSW_BM_RAM_ADDR_REG ( VR9_SWIP_BASE_ADDR + (0x44 * 4) ) #define ETHSW_BM_RAM_CTRL_REG ( VR9_SWIP_BASE_ADDR + (0x45 * 4) ) #endif /** Driver version info */ static inline int gphy_drv_ver(char *buf) { return sprintf(buf, "IFX GPHY driver %s, version %s \n", IFX_GPHY_MODE, version); } /** Driver version info for procfs */ static inline int gphy_ver(char *buf) { return sprintf(buf, "IFX GPHY driver, version %s Firmware: %x\n", ver, vr9_read_mdio(0x11, 0x1e)); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int gphy_proc_reset_gphy_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data, int phy) __attribute__ ((cold)); static int gphy_proc_reset_gphy2_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) __attribute__ ((cold)); static int gphy_proc_reset_gphy3_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) __attribute__ ((cold)); static int gphy_proc_reset_gphy1_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) __attribute__ ((cold)); static int gphy_proc_reset_gphy0_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) __attribute__ ((cold)); static int gphy_proc_reset_gphy_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data, int phy) __attribute__ ((cold)); static int gphy_proc_reset_read(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) __attribute__ ((cold)); static int gphy_proc_power_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) __attribute__ ((cold)); static int gphy_proc_power_read(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) __attribute__ ((cold)); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int gphy_proc_reset_gphy0_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) { return gphy_proc_reset_gphy_write(file, buf, count, data, 0); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int gphy_proc_reset_gphy1_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) { return gphy_proc_reset_gphy_write(file, buf, count, data, 1); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int gphy_proc_reset_gphy2_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) { return gphy_proc_reset_gphy_write(file, buf, count, data, 2); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int gphy_proc_reset_gphy3_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) { return gphy_proc_reset_gphy_write(file, buf, count, data, 3); } typedef int (*gphy_proc_reset_gphy_write_t)(struct file *, const IFX_char_t *, unsigned long , void *); gphy_proc_reset_gphy_write_t gphy_proc_reset_gphy_write_func[] = { gphy_proc_reset_gphy0_write, gphy_proc_reset_gphy1_write, gphy_proc_reset_gphy2_write, gphy_proc_reset_gphy3_write }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int gphy_proc_reset_gphy_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data, int phy) { int buffer_size = 0; struct proc_data_t *reset_data = (struct proc_data_t *)data; buffer_size = count; if (buffer_size > PROC_DATA_LENGTH) buffer_size = PROC_DATA_LENGTH; if (copy_from_user(reset_data->value, buf, buffer_size)) { return IFX_ERROR; } reset_data->value[buffer_size] = '\0'; if (reset_data->value[0] == '1') { /* RESET GPHY */ vr9_gphy_reset(1 << phy); /* Wait 2ms */ ifxmips_mdelay(200); /* RESET GPHY */ vr9_gphy_reset_released(1 << phy); /* take note on PMU register */ /* HW init of the GPHY */ vr9_phy_hw_init(); } reset_data->value[0] = 0; return buffer_size; } /*------------------------------------------------------------------------------------------*\ * Displays the MODE select status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_reset_read(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) { int len = 0; struct proc_data_t *reset_data = (struct proc_data_t *)data; len += sprintf(buf + len," %s\n", reset_data->value ); /* No sanity check cos length is smaller than one page */ *eof = 1; return len; } /*------------------------------------------------------------------------------------------*\ * Turn the POWER of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_power_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) { int len = 0; unsigned int phy, reg = 0x0; unsigned short pdata; struct proc_data_t *pwr_data = (struct proc_data_t *)data; if (count > PROC_DATA_LENGTH) len = PROC_DATA_LENGTH; else len = count; if (copy_from_user(pwr_data->value, buf, len)); return IFX_ERROR; if (pwr_data->value[0] == '0') pdata = 1; else pdata = 0; if (pwr_data->gphyNum[0] == '0') phy = 0x11; else phy = 0x13; data = (void *)vr9_read_mdio(phy, reg); /* POWER DOWN */ pdata |= (1 << 11); vr9_write_mdio(phy, reg, pdata); pwr_data->value[len] = '\0'; return len; } /*------------------------------------------------------------------------------------------*\ * Displays the POWER status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_power_read(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) { int len = 0; struct proc_data_t *pwr_data = (struct proc_data_t *)data; len = sprintf(buf," %s\n", pwr_data->value ); /* No sanity check cos length is smaller than one page */ *eof = 1; return len; } /*------------------------------------------------------------------------------------------*\ * Displays the PHY address status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_mdio_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) { int len = 0; return len; } /*------------------------------------------------------------------------------------------*\ * Displays the PHY address status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_mdio_read(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) { int len = 0; struct proc_data_t *mdio_data = (struct proc_data_t *)data; len = sprintf(buf," %s\n", mdio_data->value ); /* No sanity check cos length is smaller than one page */ *eof = 1; return len; } /*------------------------------------------------------------------------------------------*\ * Displays the PHY address status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ #if !defined(GPHY_FW_DIRECT_MAP) static int gphy_proc_mode_write(struct file *file, const IFX_char_t *buf, unsigned long count, void *data) { int len = 0; struct proc_data_t *mdio_data = (struct proc_data_t *)data; if (count > PROC_DATA_LENGTH) len = PROC_DATA_LENGTH; else len = count; if (copy_from_user(mdio_data->value, buf, len)); return IFX_ERROR; if (mdio_data->value[0] == 'G') { if (mdio_data->gphyNum[0] == '0') /* Load GPHY0 firmware module */ SW_WRITE_REG32( virt_to_phys(gphy_ge_fw_data), GFS_ADD0); else /* Load GPHY1 firmware module */ SW_WRITE_REG32( virt_to_phys(gphy_ge_fw_data), GFS_ADD1); } else { if (mdio_data->gphyNum[0] == '0') /* Load GPHY0 firmware module */ SW_WRITE_REG32( virt_to_phys(gphy_fe_fw_data), GFS_ADD0); else /* Load GPHY1 firmware module */ SW_WRITE_REG32( virt_to_phys(gphy_fe_fw_data), GFS_ADD1); } mdio_data->value[len] = '\0'; return len; } #endif /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ /*------------------------------------------------------------------------------------------*\ * Displays the MODE select status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ #if !defined(GPHY_FW_DIRECT_MAP) static int gphy_proc_mode_read(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) { int len = 0; #if 0 if (IFX_GPHY_DEFAULT_FW == 1) len += sprintf(buf + len, "MODE:GE\n"); else len += sprintf(buf + len, "MODE:SE\n"); /* No sanity check cos length is smaller than one page */ #else struct proc_data_t *mode_data = (struct proc_data_t *)data; len = sprintf(buf," %s\n", mode_data->value ); /* No sanity check cos length is smaller than one page */ #endif *eof = 1; return len; } #endif /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ /*------------------------------------------------------------------------------------------*\ * Displays the led status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_led(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) { int len = 0; int value = 0; /* No sanity check cos length is smaller than one page */ len += sprintf(buf + len, "LED:%d\n", value); *eof = 1; return len; } /*------------------------------------------------------------------------------------------*\ * Displays the clock status of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_clk(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) { int len = 0; /* No sanity check cos length is smaller than one page */ len += sprintf(buf + len, "%s\n", GPHY_CLK); *eof = 1; return len; } /*------------------------------------------------------------------------------------------*\ * Displays the version of GPHY module via proc file \*------------------------------------------------------------------------------------------*/ static int gphy_proc_version(IFX_char_t *buf, IFX_char_t **start, off_t offset, int count, int *eof, void *data) { int len = 0; /* No sanity check cos length is smaller than one page */ len += gphy_ver(buf + len); *eof = 1; return len; } /*------------------------------------------------------------------------------------------*\ * create proc for debug info, \used ifx_eth_module_init \*------------------------------------------------------------------------------------------*/ static int gphy_proc_create(void) { unsigned int phy; /* procfs */ ifx_gphy_dir = proc_mkdir ("driver/ifx_gphy", NULL); if (ifx_gphy_dir == NULL) { printk(KERN_ERR "%s: Create proc directory (/driver/ifx_gphy) failed!!!\n", __func__); return IFX_ERROR; } create_proc_read_entry("version", 0, ifx_gphy_dir, gphy_proc_version, NULL); create_proc_read_entry("clk", 0, ifx_gphy_dir, gphy_proc_clk, NULL); create_proc_read_entry("led", 0, ifx_gphy_dir, gphy_proc_led, NULL); /*--------------------------------------------------------------------------------------*\ * External Phy 0 (Port 3 an der Leiste) \*--------------------------------------------------------------------------------------*/ for(phy = 0 ; phy < MAX_PHYS ; phy++) { static char Buffer[128]; sprintf(Buffer, "driver/ifx_gphy/gphy%d", phy); ifx_gphy_dir = proc_mkdir (Buffer, NULL); if (ifx_gphy_dir == NULL) { printk(KERN_ERR "%s: Create proc directory (%s) failed!!!\n", __FUNCTION__, Buffer); return IFX_ERROR; } /*-------- MODE -----------*/ #if !defined(GPHY_FW_DIRECT_MAP) ifx_gphy_mode[phy] = create_proc_entry("mode", 0, ifx_gphy_dir); if (ifx_gphy_mode[phy] == NULL) { printk(KERN_ERR "%s: Create proc directory (mode) failed!!!\n", __func__); return IFX_ERROR; } ifx_gphy_mode[phy]->data = &ifx_phy_mode[phy]; ifx_gphy_mode[phy]->read_proc = gphy_proc_mode_read; ifx_gphy_mode[phy]->write_proc = gphy_proc_mode_write; #endif /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ /*-------- MDIO -----------*/ ifx_gphy_mdio[phy] = create_proc_entry("phy0_mdio", 0, ifx_gphy_dir); if (ifx_gphy_mdio[phy] == NULL) { printk(KERN_ERR "%s: Create proc directory (phy0_mdio) failed!!!\n", __func__); return IFX_ERROR; } ifx_gphy_mdio[phy]->data = &ifx_phy_mdio_data[phy]; ifx_gphy_mdio[phy]->read_proc = gphy_proc_mdio_read; ifx_gphy_mdio[phy]->write_proc = gphy_proc_mdio_write; /*-------- RESET -----------*/ ifx_gphy_reset[phy] = create_proc_entry("reset", 0, ifx_gphy_dir); if (ifx_gphy_reset[phy] == NULL) { printk(KERN_ERR "%s: Create proc directory (reset) failed!!!\n", __func__); return IFX_ERROR; } ifx_gphy_reset[phy]->data = &ifx_phy_reset_data[phy]; ifx_gphy_reset[phy]->read_proc = gphy_proc_reset_read; ifx_gphy_reset[phy]->write_proc = gphy_proc_reset_gphy_write_func[phy]; ifx_gphy_power[phy] = create_proc_entry("power", 0, ifx_gphy_dir); if (ifx_gphy_power[phy] == NULL) { printk(KERN_ERR "%s: Create proc directory (reset) failed!!!\n", __func__); return IFX_ERROR; } ifx_gphy_power[phy]->data = &ifx_phy_power_data[phy]; ifx_gphy_power[phy]->read_proc = gphy_proc_power_read; ifx_gphy_power[phy]->write_proc = gphy_proc_power_write; } return IFX_SUCCESS; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ /** remove of the proc entries, \used ifx_eth_module_exit */ static void gphy_proc_delete(void) { #if 0 remove_proc_entry("version", gphy_drv_ver); remove_proc_entry("clk", gphy_drv_ver); remove_proc_entry("led", gphy_drv_ver); remove_proc_entry("mode", gphy_drv_ver); remove_proc_entry("phy0_mdio", gphy_drv_ver); remove_proc_entry("phy1_mdio", gphy_drv_ver); remove_proc_entry("gphy1_reset", gphy_drv_ver); remove_proc_entry("gphy1_power", gphy_drv_ver); remove_proc_entry("driver/ifx_gphy/gphy0", NULL); remove_proc_entry("driver/ifx_gphy/gphy1", NULL); remove_proc_entry("driver/ifx_gphy", NULL); #endif } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int vr9_gphy_firmware_load(void) { #if !defined(GPHY_FW_DIRECT_MAP) int i; unsigned int value, value2; char *ptr; value = (u32)gphy_fw_dma; value2 = (value & 0xFFFF); value2 = 65536 - value2; memset(gphy_fw_dma, 0, sizeof(gphy_fw_dma)); ptr = gphy_fw_dma; /** just backup when want to cleanup the module */ ptr += value2; for(i = 0 ; i < 65536 ; i++) { if (IFX_GPHY_DEFAULT_FW == 0) *(ptr+i) = gphy_fe_fw_data[i]; else *(ptr+i) = gphy_ge_fw_data[i]; } value = (u32)gphy_fw_dma; value = value & 0xFFFF0000; value = value + 0x10000; value = value & 0xFFFFFF; printk("GPHY FIRMWARE LOAD SUCCESSFULLY AT ADDR : %x (GFS_ADD0 = %#x, GFS_ADD1 = %#x )\n",value, GFS_ADD0, GFS_ADD1); if (IFX_GPHY_DEFAULT_FW == 1 || IFX_GPHY_DEFAULT_FW == 0) { /* Load GPHY0 firmware module */ SW_WRITE_REG32( value, GFS_ADD0); /* Load GPHY1 firmware module */ SW_WRITE_REG32( value, GFS_ADD1); } #else /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ { unsigned int value = virt_to_phys( &gphy_ge_fw_data[0] ); SW_WRITE_REG32(value, GFS_ADD0); SW_WRITE_REG32(value, GFS_ADD1); printk("GPHY FIRMWARE LOAD SUCCESSFULLY AT ADDR : %x (GFS_ADD0 = %#x, GFS_ADD1 = %#x )\n",value, GFS_ADD0, GFS_ADD1); } #endif /*--- #else ---*/ /*--- #if !defined(GPHY_FW_DIRECT_MAP) ---*/ return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void setup_external_phy( int port, int mode){ unsigned int cfg_reg, phy_reg, mac_ctrl_0; printk("[%s] port=%d, mode=%d\n", __FUNCTION__, port, mode); if (port < 0 || port > 1 ) { printk("%s[%d]: Err!!! (invalid port number: %d)\n",__func__,__LINE__,port); return ; } cfg_reg = SW_READ_REG32(MII_CFG_0_REG + (port * 8)); cfg_reg |= MII_CFG_RES; /* reset the port */ SW_WRITE_REG32( cfg_reg, (MII_CFG_0_REG+(port*8)) ); udelay(100); switch (port) { case 0: cfg_reg = SW_READ_REG32(MII_CFG_0_REG); phy_reg = SW_READ_REG32(PHY_ADDR_0); mac_ctrl_0 = SW_READ_REG32(MAC_0_CTRL_0); mac_ctrl_0 &= ~(MAC_CTRL_0_FCON_MASK | MAC_CTRL_0_FDUP_MASK | MAC_CTRL_0_GMII_MASK); phy_reg &= ~(PHY_ADDR_LINKST_MASK | PHY_ADDR_SPEED_MASK | PHY_ADDR_FDUP_MASK); cfg_reg &= ~(MII_CFG_MIIRATE_MASK | MII_CFG_MIIMODE_MASK ); if (mode == RGMII_MODE ) { cfg_reg |= ( MII_CFG_MIIMODE_RGMII | MII_CFG_MIIRATE_125MHZ | MII_CFG_EN); mac_ctrl_0 |= MAC_CTRL_0_GMII_RGMII; phy_reg |= PHY_ADDR_SPEED_1000; } else { printk("%s[%d]: Err!!! (Unknow interface mode)\n",__func__,__LINE__); } mac_ctrl_0 |= (MAC_CTRL_0_FDUP_EN | MAC_CTRL_0_FCON_RXTX ); phy_reg |= PHY_ADDR_LINKST_UP; SW_WRITE_REG32( cfg_reg, MII_CFG_0_REG ); SW_WRITE_REG32( mac_ctrl_0, MAC_0_CTRL_0 ); SW_WRITE_REG32( phy_reg, PHY_ADDR_0 ); break; case 1: cfg_reg = SW_READ_REG32(MII_CFG_1_REG); phy_reg = SW_READ_REG32(PHY_ADDR_1); mac_ctrl_0 = SW_READ_REG32(MAC_1_CTRL_0); mac_ctrl_0 &= ~(MAC_CTRL_0_FCON_MASK | MAC_CTRL_0_FDUP_MASK | MAC_CTRL_0_GMII_MASK); phy_reg &= ~(PHY_ADDR_LINKST_MASK | PHY_ADDR_SPEED_MASK | PHY_ADDR_FDUP_MASK); cfg_reg &= ~(MII_CFG_MIIRATE_MASK | MII_CFG_MIIMODE_MASK ); if (mode == RGMII_MODE ) { cfg_reg |= ( MII_CFG_MIIMODE_RGMII | MII_CFG_MIIRATE_125MHZ | MII_CFG_EN); mac_ctrl_0 |= MAC_CTRL_0_GMII_RGMII; phy_reg |= PHY_ADDR_SPEED_1000; } else { printk("%s[%d]: Err!!! (Unknow interface mode)\n",__func__,__LINE__); } mac_ctrl_0 |= (MAC_CTRL_0_FDUP_EN | MAC_CTRL_0_FCON_RXTX ); phy_reg |= PHY_ADDR_LINKST_UP; SW_WRITE_REG32( cfg_reg, MII_CFG_1_REG ); SW_WRITE_REG32( mac_ctrl_0, MAC_1_CTRL_0 ); SW_WRITE_REG32( phy_reg, PHY_ADDR_1 ); break; } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void setup_external_phys (void) { setup_external_phy( 0, RGMII_MODE ); setup_external_phy( 1, RGMII_MODE ); } /*------------------------------------------------------------------------------------------*\ * Initilization GPHY module \*------------------------------------------------------------------------------------------*/ int ifx_phy_module_init (void) { int internal_gphy_numbers; char ver_str[128] = {0}; #ifdef CONFIG_GPHY_TRAFFIC_LED_SW_IMPLEMENTATION u32 led_conf; #endif /*--- #ifdef CONFIG_GPHY_TRAFFIC_LED_SW_IMPLEMENTATION ---*/ internal_gphy_numbers = 0x01 | 0x02; printk("[%s]\n ", __FUNCTION__); /*--- setup_external_phys(); ---*/ #if defined(CONFIG_VR9) /* RESET GPHY */ if(vr9_gphy_reset(internal_gphy_numbers) == 1) printk(KERN_ERR "GPHY driver init RESET FAILED !!\n"); /* Load GPHY firmware */ vr9_gphy_firmware_load(); /* Wait 2s */ ifxmips_mdelay(200); /* RESET GPHY */ if(vr9_gphy_reset_released(internal_gphy_numbers) == 1) printk(KERN_ERR "GPHY driver init RELEASE FAILED !!\n"); /* take note on PMU register */ /* HW init of the GPHY */ vr9_phy_hw_init(); #ifdef CONFIG_GPHY_TRAFFIC_LED_SW_IMPLEMENTATION /* Taking the control of LED from the switch */ led_conf = vr9_read_mdio(GPHY_ID_1, SWITCH_LED_CON_REG); led_conf = (led_conf & 0xfdff); vr9_write_mdio(GPHY_ID_1, SWITCH_LED_CON_REG, led_conf); led_conf = vr9_read_mdio(GPHY_ID_5, SWITCH_LED_CON_REG); led_conf = (led_conf & 0xfdff); vr9_write_mdio(GPHY_ID_5, SWITCH_LED_CON_REG, led_conf); /* Create the RMON monitoring and LED flashing threads */ gphy_led_thread_id = kthread_create(gphy_led_thread, IFX_NULL, "gphy_led_thread"); gphy_rmon_poll_thread_id = kthread_create(gphy_rmon_poll_thread, IFX_NULL, "gphy_rmon_poll_thread"); if (!IS_ERR(gphy_led_thread_id)) { printk ("GPHY LED poll thread created..\n"); wake_up_process(gphy_led_thread_id); } if (!IS_ERR(gphy_rmon_poll_thread_id)) { printk ("GPHY RMON poll thread created..\n"); wake_up_process(gphy_rmon_poll_thread_id); } init_waitqueue_head(&gphy_led_thread_wait); #endif #endif /* CONFIG_VR9*/ /* Create proc entry */ gphy_proc_create(); /* Print the driver version info */ gphy_drv_ver(ver_str); printk(KERN_INFO "%s", ver_str); return 0; } void ifx_phy_module_exit (void) { #if 0 int i; /*Unregister with DMA core driver */ dma_setup_uninit(); /* unregister the network devices */ for (i=0; i< NUM_ETH_INF ; i++) { unregister_netdev(ifx_eth_dev[i]); free_netdev(ifx_eth_dev[i]); } #endif gphy_proc_delete(); } #ifdef CONFIG_GPHY_TRAFFIC_LED_SW_IMPLEMENTATION /* This thread polls on the RMON TX and RX counters and signals the LED thread to flash the LED */ /* The LED thread is signalled only if the counters are different from previous and currently the LED is not ON and currently NOT flashing */ static int gphy_rmon_poll_thread (void *arg) { int port; int port_rx[NUM_OF_PORTS]; int port_rx_prev[NUM_OF_PORTS] = {0,0,0,0,0,0}; int port_tx[NUM_OF_PORTS]; int port_tx_prev[NUM_OF_PORTS] = {0,0,0,0,0,0}; printk (KERN_INFO "start %p ..\n", current); allow_signal(SIGKILL); while(!kthread_should_stop ()) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) break; /* Check the RMON counter */ //printk (KERN_INFO "Checking the RMON counter..!!\n"); for (port=0; port < NUM_OF_PORTS; port++) { if ((port == GPHY_ID_0) || (port == GPHY_ID_2) || (port == GPHY_ID_3) || (port == GPHY_ID_4)) continue; port_rx[port] = get_rmon_counter_rx_frame(port); port_tx[port] = get_rmon_counter_tx_frame(port); if ((port_rx[port] != port_rx_prev[port]) || (port_tx[port] != port_tx_prev[port])) { //printk (KERN_INFO "Some packet received on port %d ..!!\n", port); /* Signal the LED thread to blink it */ //if (gphy_led_status_on == 0 && gphy_led_need_to_flash == 0) if ((gphy_led_status_on[port] == 0) && gphy_led_need_to_flash[port] == 0) { gphy_led_need_to_flash[port] = 1; wake_up_interruptible (&gphy_led_thread_wait); port_rx_prev[port] = port_rx[port]; port_tx_prev[port] = port_tx[port]; } } } //printk (KERN_INFO "sleeping !!\n"); //schedule_timeout (LED_TIMOUT * HZ); msleep(100); } } /* This threads waits for the signals from the RMON thread and flashes the LED */ static int gphy_led_thread (void *arg) { int port; printk (KERN_INFO "start %p ..\n", current); allow_signal(SIGKILL); for (port=0; port