diff options
| -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), | 
