diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2012-08-29 10:37:45 +0000 |
---|---|---|
committer | Gabor Juhos <juhosg@openwrt.org> | 2012-08-29 10:37:45 +0000 |
commit | bc4763a399f91c564ea712466102d51b742ea3a8 (patch) | |
tree | 3b1bc51866095cfef7651de9a4d177ed391e12a5 | |
parent | 1617f226a906f82ce6516e3e5a1e0909d8aa8806 (diff) | |
download | upstream-bc4763a399f91c564ea712466102d51b742ea3a8.tar.gz upstream-bc4763a399f91c564ea712466102d51b742ea3a8.tar.bz2 upstream-bc4763a399f91c564ea712466102d51b742ea3a8.zip |
ramips: Power down phy on disabled switch ports
Power down phy on disabled switch ports.
Haven't measured this myself yet, but according to this
http://www.8devices.com/community/viewtopic.php?f=6&t=156
it can save about 300mW of power.
[juhosg: fix checkpatch warning]
Signed-off-by: Tobias Diedrich <ranma+openwrt@tdiedrich.de>
SVN-Revision: 33304
-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 1ecb1a6ee7..309efdeb78 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), |