diff options
Diffstat (limited to 'target/linux/ramips/files')
-rw-r--r-- | target/linux/ramips/files/drivers/net/ethernet/ramips/ramips_esw.c | 72 |
1 files changed, 67 insertions, 5 deletions
diff --git a/target/linux/ramips/files/drivers/net/ethernet/ramips/ramips_esw.c b/target/linux/ramips/files/drivers/net/ethernet/ramips/ramips_esw.c index 1ecb1a6ee..309efdeb7 100644 --- a/target/linux/ramips/files/drivers/net/ethernet/ramips/ramips_esw.c +++ b/target/linux/ramips/files/drivers/net/ethernet/ramips/ramips_esw.c @@ -1,5 +1,6 @@ #include <linux/ioport.h> #include <linux/switch.h> +#include <linux/mii.h> #include <rt305x_regs.h> #include <rt305x_esw_platform.h> @@ -326,6 +327,57 @@ rt305x_esw_set_vmsc(struct rt305x_esw *esw, unsigned vlan, unsigned msc) (msc & RT305X_ESW_VMSC_MSC_M) << s); } +static unsigned +rt305x_esw_get_port_disable(struct rt305x_esw *esw) +{ + unsigned reg; + reg = rt305x_esw_rr(esw, RT305X_ESW_REG_POC0); + return (reg >> RT305X_ESW_POC0_DIS_PORT_S) & + RT305X_ESW_POC0_DIS_PORT_M; +} + +static void +rt305x_esw_set_port_disable(struct rt305x_esw *esw, unsigned disable_mask) +{ + unsigned old_mask; + unsigned enable_mask; + unsigned changed; + int i; + + old_mask = rt305x_esw_get_port_disable(esw); + changed = old_mask ^ disable_mask; + enable_mask = old_mask & disable_mask; + + /* enable before writing to MII */ + rt305x_esw_rmw(esw, RT305X_ESW_REG_POC0, + (RT305X_ESW_POC0_DIS_PORT_M << + RT305X_ESW_POC0_DIS_PORT_S), + enable_mask << RT305X_ESW_POC0_DIS_PORT_S); + + for (i = 0; i < RT305X_ESW_NUM_LEDS; i++) { + if (!(changed & (1 << i))) + continue; + if (disable_mask & (1 << i)) { + /* disable */ + rt305x_mii_write(esw, i, MII_BMCR, + BMCR_PDOWN); + } else { + /* enable */ + rt305x_mii_write(esw, i, MII_BMCR, + BMCR_FULLDPLX | + BMCR_ANENABLE | + BMCR_ANRESTART | + BMCR_SPEED100); + } + } + + /* disable after writing to MII */ + rt305x_esw_rmw(esw, RT305X_ESW_REG_POC0, + (RT305X_ESW_POC0_DIS_PORT_M << + RT305X_ESW_POC0_DIS_PORT_S), + disable_mask << RT305X_ESW_POC0_DIS_PORT_S); +} + static int rt305x_esw_apply_config(struct switch_dev *dev); @@ -333,6 +385,7 @@ static void rt305x_esw_hw_init(struct rt305x_esw *esw) { int i; + u8 port_disable = 0; u8 port_map = RT305X_ESW_PMAP_LLLLLL; /* vodoo from original driver */ @@ -384,10 +437,21 @@ rt305x_esw_hw_init(struct rt305x_esw *esw) rt305x_esw_wr(esw, 0x00000005, RT305X_ESW_REG_P3LED); rt305x_esw_wr(esw, 0x00000005, RT305X_ESW_REG_P4LED); + /* Copy disabled port configuration from bootloader setup */ + port_disable = rt305x_esw_get_port_disable(esw); + for (i = 0; i < 6; i++) + esw->ports[i].disable = (port_disable & (1 << i)) != 0; + rt305x_mii_write(esw, 0, 31, 0x8000); for (i = 0; i < 5; i++) { - /* TX10 waveform coefficient */ - rt305x_mii_write(esw, i, 0, 0x3100); + if (esw->ports[i].disable) { + rt305x_mii_write(esw, i, MII_BMCR, BMCR_PDOWN); + } else { + rt305x_mii_write(esw, i, MII_BMCR, + BMCR_FULLDPLX | + BMCR_ANENABLE | + BMCR_SPEED100); + } /* TX10 waveform coefficient */ rt305x_mii_write(esw, i, 26, 0x1601); /* TX100/TX10 AD/DA current bias */ @@ -482,9 +546,7 @@ rt305x_esw_apply_config(struct switch_dev *dev) RT305X_ESW_REG_P0LED + 4*i); } - rt305x_esw_rmw(esw, RT305X_ESW_REG_POC0, - RT305X_ESW_POC0_DIS_PORT_M << RT305X_ESW_POC0_DIS_PORT_S, - disable << RT305X_ESW_POC0_DIS_PORT_S); + rt305x_esw_set_port_disable(esw, disable); rt305x_esw_rmw(esw, RT305X_ESW_REG_SGC2, (RT305X_ESW_SGC2_DOUBLE_TAG_M << RT305X_ESW_SGC2_DOUBLE_TAG_S), |