diff options
Diffstat (limited to 'drivers/net/dsa/mt7530.c')
| -rw-r--r-- | drivers/net/dsa/mt7530.c | 821 | 
1 files changed, 336 insertions, 485 deletions
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index a508402c4ecb..9bc54e1348cb 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -142,31 +142,42 @@ err:  }  static void -core_write(struct mt7530_priv *priv, u32 reg, u32 val) +mt7530_mutex_lock(struct mt7530_priv *priv)  { -	struct mii_bus *bus = priv->bus; +	if (priv->bus) +		mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); +} -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +static void +mt7530_mutex_unlock(struct mt7530_priv *priv) +{ +	if (priv->bus) +		mutex_unlock(&priv->bus->mdio_lock); +} + +static void +core_write(struct mt7530_priv *priv, u32 reg, u32 val) +{ +	mt7530_mutex_lock(priv);  	core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  }  static void  core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)  { -	struct mii_bus *bus = priv->bus;  	u32 val; -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2);  	val &= ~mask;  	val |= set;  	core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  }  static void @@ -184,66 +195,42 @@ core_clear(struct mt7530_priv *priv, u32 reg, u32 val)  static int  mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)  { -	struct mii_bus *bus = priv->bus; -	u16 page, r, lo, hi;  	int ret; -	page = (reg >> 6) & 0x3ff; -	r  = (reg >> 2) & 0xf; -	lo = val & 0xffff; -	hi = val >> 16; +	ret = regmap_write(priv->regmap, reg, val); -	/* MT7530 uses 31 as the pseudo port */ -	ret = bus->write(bus, 0x1f, 0x1f, page);  	if (ret < 0) -		goto err; - -	ret = bus->write(bus, 0x1f, r,  lo); -	if (ret < 0) -		goto err; - -	ret = bus->write(bus, 0x1f, 0x10, hi); -err: -	if (ret < 0) -		dev_err(&bus->dev, +		dev_err(priv->dev,  			"failed to write mt7530 register\n"); +  	return ret;  }  static u32  mt7530_mii_read(struct mt7530_priv *priv, u32 reg)  { -	struct mii_bus *bus = priv->bus; -	u16 page, r, lo, hi;  	int ret; +	u32 val; -	page = (reg >> 6) & 0x3ff; -	r = (reg >> 2) & 0xf; - -	/* MT7530 uses 31 as the pseudo port */ -	ret = bus->write(bus, 0x1f, 0x1f, page); -	if (ret < 0) { -		dev_err(&bus->dev, +	ret = regmap_read(priv->regmap, reg, &val); +	if (ret) { +		WARN_ON_ONCE(1); +		dev_err(priv->dev,  			"failed to read mt7530 register\n"); -		return ret; +		return 0;  	} -	lo = bus->read(bus, 0x1f, r); -	hi = bus->read(bus, 0x1f, 0x10); - -	return (hi << 16) | (lo & 0xffff); +	return val;  }  static void  mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)  { -	struct mii_bus *bus = priv->bus; - -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	mt7530_mii_write(priv, reg, val); -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  }  static u32 @@ -255,14 +242,13 @@ _mt7530_unlocked_read(struct mt7530_dummy_poll *p)  static u32  _mt7530_read(struct mt7530_dummy_poll *p)  { -	struct mii_bus		*bus = p->priv->bus;  	u32 val; -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(p->priv);  	val = mt7530_mii_read(p->priv, p->reg); -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(p->priv);  	return val;  } @@ -280,23 +266,17 @@ static void  mt7530_rmw(struct mt7530_priv *priv, u32 reg,  	   u32 mask, u32 set)  { -	struct mii_bus *bus = priv->bus; -	u32 val; +	mt7530_mutex_lock(priv); -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	regmap_update_bits(priv->regmap, reg, mask, set); -	val = mt7530_mii_read(priv, reg); -	val &= ~mask; -	val |= set; -	mt7530_mii_write(priv, reg, val); - -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  }  static void  mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val)  { -	mt7530_rmw(priv, reg, 0, val); +	mt7530_rmw(priv, reg, val, val);  }  static void @@ -396,6 +376,9 @@ mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,  /* Set up switch core clock for MT7530 */  static void mt7530_pll_setup(struct mt7530_priv *priv)  { +	/* Disable core clock */ +	core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); +  	/* Disable PLL */  	core_write(priv, CORE_GSWPLL_GRP1, 0); @@ -409,14 +392,19 @@ static void mt7530_pll_setup(struct mt7530_priv *priv)  		   RG_GSWPLL_EN_PRE |  		   RG_GSWPLL_POSDIV_200M(2) |  		   RG_GSWPLL_FBKDIV_200M(32)); + +	udelay(20); + +	/* Enable core clock */ +	core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);  } -/* Setup TX circuit including relevant PAD and driving */ +/* Setup port 6 interface mode and TRGMII TX circuit */  static int  mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)  {  	struct mt7530_priv *priv = ds->priv; -	u32 ncpo1, ssc_delta, trgint, i, xtal; +	u32 ncpo1, ssc_delta, trgint, xtal;  	xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK; @@ -430,15 +418,17 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)  	switch (interface) {  	case PHY_INTERFACE_MODE_RGMII:  		trgint = 0; -		/* PLL frequency: 125MHz */ -		ncpo1 = 0x0c80;  		break;  	case PHY_INTERFACE_MODE_TRGMII:  		trgint = 1; +		if (xtal == HWTRAP_XTAL_25MHZ) +			ssc_delta = 0x57; +		else +			ssc_delta = 0x87;  		if (priv->id == ID_MT7621) { -			/* PLL frequency: 150MHz: 1.2GBit */ +			/* PLL frequency: 125MHz: 1.0GBit */  			if (xtal == HWTRAP_XTAL_40MHZ) -				ncpo1 = 0x0780; +				ncpo1 = 0x0640;  			if (xtal == HWTRAP_XTAL_25MHZ)  				ncpo1 = 0x0a00;  		} else { /* PLL frequency: 250MHz: 2.0Gbit */ @@ -454,46 +444,32 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)  		return -EINVAL;  	} -	if (xtal == HWTRAP_XTAL_25MHZ) -		ssc_delta = 0x57; -	else -		ssc_delta = 0x87; -  	mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,  		   P6_INTF_MODE(trgint)); -	/* Lower Tx Driving for TRGMII path */ -	for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) -		mt7530_write(priv, MT7530_TRGMII_TD_ODT(i), -			     TD_DM_DRVP(8) | TD_DM_DRVN(8)); +	if (trgint) { +		/* Disable the MT7530 TRGMII clocks */ +		core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); + +		/* Setup the MT7530 TRGMII Tx Clock */ +		core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1)); +		core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0)); +		core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); +		core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta)); +		core_write(priv, CORE_PLL_GROUP4, +			   RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN | +			   RG_SYSPLL_BIAS_LPF_EN); +		core_write(priv, CORE_PLL_GROUP2, +			   RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | +			   RG_SYSPLL_POSDIV(1)); +		core_write(priv, CORE_PLL_GROUP7, +			   RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) | +			   RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); + +		/* Enable the MT7530 TRGMII clocks */ +		core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); +	} -	/* Disable MT7530 core and TRGMII Tx clocks */ -	core_clear(priv, CORE_TRGMII_GSW_CLK_CG, -		   REG_GSWCK_EN | REG_TRGMIICK_EN); - -	/* Setup the MT7530 TRGMII Tx Clock */ -	core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1)); -	core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0)); -	core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); -	core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta)); -	core_write(priv, CORE_PLL_GROUP4, -		   RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN | -		   RG_SYSPLL_BIAS_LPF_EN); -	core_write(priv, CORE_PLL_GROUP2, -		   RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | -		   RG_SYSPLL_POSDIV(1)); -	core_write(priv, CORE_PLL_GROUP7, -		   RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) | -		   RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); - -	/* Enable MT7530 core and TRGMII Tx clocks */ -	core_set(priv, CORE_TRGMII_GSW_CLK_CG, -		 REG_GSWCK_EN | REG_TRGMIICK_EN); - -	if (!trgint) -		for (i = 0 ; i < NUM_TRGMII_CTRL; i++) -			mt7530_rmw(priv, MT7530_TRGMII_RD(i), -				   RD_TAP_MASK, RD_TAP(16));  	return 0;  } @@ -638,14 +614,13 @@ static int  mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,  			int regnum)  { -	struct mii_bus *bus = priv->bus;  	struct mt7530_dummy_poll p;  	u32 reg, val;  	int ret;  	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,  				 !(val & MT7531_PHY_ACS_ST), 20, 100000); @@ -678,7 +653,7 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,  	ret = val & MT7531_MDIO_RW_DATA_MASK;  out: -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  	return ret;  } @@ -687,14 +662,13 @@ static int  mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,  			 int regnum, u16 data)  { -	struct mii_bus *bus = priv->bus;  	struct mt7530_dummy_poll p;  	u32 val, reg;  	int ret;  	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,  				 !(val & MT7531_PHY_ACS_ST), 20, 100000); @@ -726,7 +700,7 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,  	}  out: -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  	return ret;  } @@ -734,14 +708,13 @@ out:  static int  mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)  { -	struct mii_bus *bus = priv->bus;  	struct mt7530_dummy_poll p;  	int ret;  	u32 val;  	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,  				 !(val & MT7531_PHY_ACS_ST), 20, 100000); @@ -764,7 +737,7 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)  	ret = val & MT7531_MDIO_RW_DATA_MASK;  out: -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  	return ret;  } @@ -773,14 +746,13 @@ static int  mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,  			 u16 data)  { -	struct mii_bus *bus = priv->bus;  	struct mt7530_dummy_poll p;  	int ret;  	u32 reg;  	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,  				 !(reg & MT7531_PHY_ACS_ST), 20, 100000); @@ -802,7 +774,7 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,  	}  out: -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  	return ret;  } @@ -924,6 +896,24 @@ mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)  	return 0;  } +static const char *p5_intf_modes(unsigned int p5_interface) +{ +	switch (p5_interface) { +	case P5_DISABLED: +		return "DISABLED"; +	case P5_INTF_SEL_PHY_P0: +		return "PHY P0"; +	case P5_INTF_SEL_PHY_P4: +		return "PHY P4"; +	case P5_INTF_SEL_GMAC5: +		return "GMAC5"; +	case P5_INTF_SEL_GMAC5_SGMII: +		return "GMAC5_SGMII"; +	default: +		return "unknown"; +	} +} +  static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)  {  	struct mt7530_priv *priv = ds->priv; @@ -1012,9 +1002,9 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)  	mt7530_write(priv, MT7530_PVC_P(port),  		     PORT_SPEC_TAG); -	/* Disable flooding by default */ -	mt7530_rmw(priv, MT7530_MFC, BC_FFP_MASK | UNM_FFP_MASK | UNU_FFP_MASK, -		   BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | UNU_FFP(BIT(port))); +	/* Enable flooding on the CPU port */ +	mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | +		   UNU_FFP(BIT(port)));  	/* Set CPU port number */  	if (priv->id == ID_MT7621) @@ -1083,7 +1073,6 @@ static int  mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)  {  	struct mt7530_priv *priv = ds->priv; -	struct mii_bus *bus = priv->bus;  	int length;  	u32 val; @@ -1094,7 +1083,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)  	if (!dsa_is_cpu_port(ds, port))  		return 0; -	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	val = mt7530_mii_read(priv, MT7530_GMACCR);  	val &= ~MAX_RX_PKT_LEN_MASK; @@ -1115,7 +1104,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)  	mt7530_mii_write(priv, MT7530_GMACCR, val); -	mutex_unlock(&bus->mdio_lock); +	mt7530_mutex_unlock(priv);  	return 0;  } @@ -1916,10 +1905,10 @@ mt7530_irq_thread_fn(int irq, void *dev_id)  	u32 val;  	int p; -	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  	val = mt7530_mii_read(priv, MT7530_SYS_INT_STS);  	mt7530_mii_write(priv, MT7530_SYS_INT_STS, val); -	mutex_unlock(&priv->bus->mdio_lock); +	mt7530_mutex_unlock(priv);  	for (p = 0; p < MT7530_NUM_PHYS; p++) {  		if (BIT(p) & val) { @@ -1955,7 +1944,7 @@ mt7530_irq_bus_lock(struct irq_data *d)  {  	struct mt7530_priv *priv = irq_data_get_irq_chip_data(d); -	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); +	mt7530_mutex_lock(priv);  }  static void @@ -1964,7 +1953,7 @@ mt7530_irq_bus_sync_unlock(struct irq_data *d)  	struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);  	mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable); -	mutex_unlock(&priv->bus->mdio_lock); +	mt7530_mutex_unlock(priv);  }  static struct irq_chip mt7530_irq_chip = { @@ -1993,6 +1982,47 @@ static const struct irq_domain_ops mt7530_irq_domain_ops = {  };  static void +mt7988_irq_mask(struct irq_data *d) +{ +	struct mt7530_priv *priv = irq_data_get_irq_chip_data(d); + +	priv->irq_enable &= ~BIT(d->hwirq); +	mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable); +} + +static void +mt7988_irq_unmask(struct irq_data *d) +{ +	struct mt7530_priv *priv = irq_data_get_irq_chip_data(d); + +	priv->irq_enable |= BIT(d->hwirq); +	mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable); +} + +static struct irq_chip mt7988_irq_chip = { +	.name = KBUILD_MODNAME, +	.irq_mask = mt7988_irq_mask, +	.irq_unmask = mt7988_irq_unmask, +}; + +static int +mt7988_irq_map(struct irq_domain *domain, unsigned int irq, +	       irq_hw_number_t hwirq) +{ +	irq_set_chip_data(irq, domain->host_data); +	irq_set_chip_and_handler(irq, &mt7988_irq_chip, handle_simple_irq); +	irq_set_nested_thread(irq, true); +	irq_set_noprobe(irq); + +	return 0; +} + +static const struct irq_domain_ops mt7988_irq_domain_ops = { +	.map = mt7988_irq_map, +	.xlate = irq_domain_xlate_onecell, +}; + +static void  mt7530_setup_mdio_irq(struct mt7530_priv *priv)  {  	struct dsa_switch *ds = priv->ds; @@ -2026,8 +2056,15 @@ mt7530_setup_irq(struct mt7530_priv *priv)  		return priv->irq ? : -EINVAL;  	} -	priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS, -						 &mt7530_irq_domain_ops, priv); +	if (priv->id == ID_MT7988) +		priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS, +							 &mt7988_irq_domain_ops, +							 priv); +	else +		priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS, +							 &mt7530_irq_domain_ops, +							 priv); +  	if (!priv->irq_domain) {  		dev_err(dev, "failed to create IRQ domain\n");  		return -ENOMEM; @@ -2201,7 +2238,16 @@ mt7530_setup(struct dsa_switch *ds)  	mt7530_pll_setup(priv); -	/* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ +	/* Lower Tx driving for TRGMII path */ +	for (i = 0; i < NUM_TRGMII_CTRL; i++) +		mt7530_write(priv, MT7530_TRGMII_TD_ODT(i), +			     TD_DM_DRVP(8) | TD_DM_DRVN(8)); + +	for (i = 0; i < NUM_TRGMII_CTRL; i++) +		mt7530_rmw(priv, MT7530_TRGMII_RD(i), +			   RD_TAP_MASK, RD_TAP(16)); + +	/* Enable port 6 */  	val = mt7530_read(priv, MT7530_MHWTRAP);  	val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;  	val |= MHWTRAP_MANUAL; @@ -2303,11 +2349,68 @@ mt7530_setup(struct dsa_switch *ds)  }  static int +mt7531_setup_common(struct dsa_switch *ds) +{ +	struct mt7530_priv *priv = ds->priv; +	struct dsa_port *cpu_dp; +	int ret, i; + +	/* BPDU to CPU port */ +	dsa_switch_for_each_cpu_port(cpu_dp, ds) { +		mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, +			   BIT(cpu_dp->index)); +		break; +	} +	mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, +		   MT753X_BPDU_CPU_ONLY); + +	/* Enable and reset MIB counters */ +	mt7530_mib_reset(ds); + +	/* Disable flooding on all ports */ +	mt7530_clear(priv, MT7530_MFC, BC_FFP_MASK | UNM_FFP_MASK | +		     UNU_FFP_MASK); + +	for (i = 0; i < MT7530_NUM_PORTS; i++) { +		/* Disable forwarding by default on all ports */ +		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, +			   PCR_MATRIX_CLR); + +		/* Disable learning by default on all ports */ +		mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); + +		mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR); + +		if (dsa_is_cpu_port(ds, i)) { +			ret = mt753x_cpu_port_enable(ds, i); +			if (ret) +				return ret; +		} else { +			mt7530_port_disable(ds, i); + +			/* Set default PVID to 0 on all user ports */ +			mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK, +				   G0_PORT_VID_DEF); +		} + +		/* Enable consistent egress tag */ +		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK, +			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); +	} + +	/* Flush the FDB table */ +	ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int  mt7531_setup(struct dsa_switch *ds)  {  	struct mt7530_priv *priv = ds->priv;  	struct mt7530_dummy_poll p; -	struct dsa_port *cpu_dp;  	u32 val, id;  	int ret, i; @@ -2385,44 +2488,7 @@ mt7531_setup(struct dsa_switch *ds)  	mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,  				 CORE_PLL_GROUP4, val); -	/* BPDU to CPU port */ -	dsa_switch_for_each_cpu_port(cpu_dp, ds) { -		mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, -			   BIT(cpu_dp->index)); -		break; -	} -	mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, -		   MT753X_BPDU_CPU_ONLY); - -	/* Enable and reset MIB counters */ -	mt7530_mib_reset(ds); - -	for (i = 0; i < MT7530_NUM_PORTS; i++) { -		/* Disable forwarding by default on all ports */ -		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, -			   PCR_MATRIX_CLR); - -		/* Disable learning by default on all ports */ -		mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); - -		mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR); - -		if (dsa_is_cpu_port(ds, i)) { -			ret = mt753x_cpu_port_enable(ds, i); -			if (ret) -				return ret; -		} else { -			mt7530_port_disable(ds, i); - -			/* Set default PVID to 0 on all user ports */ -			mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK, -				   G0_PORT_VID_DEF); -		} - -		/* Enable consistent egress tag */ -		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK, -			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); -	} +	mt7531_setup_common(ds);  	/* Setup VLAN ID 0 for VLAN-unaware bridges */  	ret = mt7530_setup_vlan0(priv); @@ -2432,11 +2498,6 @@ mt7531_setup(struct dsa_switch *ds)  	ds->assisted_learning_on_cpu_port = true;  	ds->mtu_enforcement_ingress = true; -	/* Flush the FDB table */ -	ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); -	if (ret < 0) -		return ret; -  	return 0;  } @@ -2502,6 +2563,25 @@ static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port,  	}  } +static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, +				     struct phylink_config *config) +{ +	phy_interface_zero(config->supported_interfaces); + +	switch (port) { +	case 0 ... 4: /* Internal phy */ +		__set_bit(PHY_INTERFACE_MODE_INTERNAL, +			  config->supported_interfaces); +		break; + +	case 6: +		__set_bit(PHY_INTERFACE_MODE_INTERNAL, +			  config->supported_interfaces); +		config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | +					   MAC_10000FD; +	} +} +  static int  mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)  { @@ -2572,126 +2652,20 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,  	return 0;  } -static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, -			       phy_interface_t interface, int speed, int duplex) -{ -	struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; -	int port = pcs_to_mt753x_pcs(pcs)->port; -	unsigned int val; - -	/* For adjusting speed and duplex of SGMII force mode. */ -	if (interface != PHY_INTERFACE_MODE_SGMII || -	    phylink_autoneg_inband(mode)) -		return; - -	/* SGMII force mode setting */ -	val = mt7530_read(priv, MT7531_SGMII_MODE(port)); -	val &= ~MT7531_SGMII_IF_MODE_MASK; - -	switch (speed) { -	case SPEED_10: -		val |= MT7531_SGMII_FORCE_SPEED_10; -		break; -	case SPEED_100: -		val |= MT7531_SGMII_FORCE_SPEED_100; -		break; -	case SPEED_1000: -		val |= MT7531_SGMII_FORCE_SPEED_1000; -		break; -	} - -	/* MT7531 SGMII 1G force mode can only work in full duplex mode, -	 * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. -	 * -	 * The speed check is unnecessary as the MAC capabilities apply -	 * this restriction. --rmk -	 */ -	if ((speed == SPEED_10 || speed == SPEED_100) && -	    duplex != DUPLEX_FULL) -		val |= MT7531_SGMII_FORCE_HALF_DUPLEX; - -	mt7530_write(priv, MT7531_SGMII_MODE(port), val); -} -  static bool mt753x_is_mac_port(u32 port)  {  	return (port == 5 || port == 6);  } -static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port, -					 phy_interface_t interface) -{ -	u32 val; - -	if (!mt753x_is_mac_port(port)) -		return -EINVAL; - -	mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), -		   MT7531_SGMII_PHYA_PWD); - -	val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port)); -	val &= ~MT7531_RG_TPHY_SPEED_MASK; -	/* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B -	 * encoding. -	 */ -	val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ? -		MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G; -	mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val); - -	mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); - -	/* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex -	 * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. -	 */ -	mt7530_rmw(priv, MT7531_SGMII_MODE(port), -		   MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS, -		   MT7531_SGMII_FORCE_SPEED_1000); - -	mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); - -	return 0; -} - -static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port, -				      phy_interface_t interface) -{ -	if (!mt753x_is_mac_port(port)) -		return -EINVAL; - -	mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), -		   MT7531_SGMII_PHYA_PWD); - -	mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), -		   MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G); - -	mt7530_set(priv, MT7531_SGMII_MODE(port), -		   MT7531_SGMII_REMOTE_FAULT_DIS | -		   MT7531_SGMII_SPEED_DUPLEX_AN); - -	mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port), -		   MT7531_SGMII_TX_CONFIG_MASK, 1); - -	mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); - -	mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART); - -	mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); - -	return 0; -} - -static void mt7531_pcs_an_restart(struct phylink_pcs *pcs) +static int +mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode, +		  phy_interface_t interface)  { -	struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; -	int port = pcs_to_mt753x_pcs(pcs)->port; -	u32 val; +	if (dsa_is_cpu_port(ds, port) && +	    interface == PHY_INTERFACE_MODE_INTERNAL) +		return 0; -	/* Only restart AN when AN is enabled */ -	val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); -	if (val & MT7531_SGMII_AN_ENABLE) { -		val |= MT7531_SGMII_AN_RESTART; -		mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val); -	} +	return -EINVAL;  }  static int @@ -2716,11 +2690,11 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  		phydev = dp->slave->phydev;  		return mt7531_rgmii_setup(priv, port, interface, phydev);  	case PHY_INTERFACE_MODE_SGMII: -		return mt7531_sgmii_setup_mode_an(priv, port, interface);  	case PHY_INTERFACE_MODE_NA:  	case PHY_INTERFACE_MODE_1000BASEX:  	case PHY_INTERFACE_MODE_2500BASEX: -		return mt7531_sgmii_setup_mode_force(priv, port, interface); +		/* handled in SGMII PCS driver */ +		return 0;  	default:  		return -EINVAL;  	} @@ -2745,11 +2719,11 @@ mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,  	switch (interface) {  	case PHY_INTERFACE_MODE_TRGMII: +		return &priv->pcs[port].pcs;  	case PHY_INTERFACE_MODE_SGMII:  	case PHY_INTERFACE_MODE_1000BASEX:  	case PHY_INTERFACE_MODE_2500BASEX: -		return &priv->pcs[port].pcs; - +		return priv->ports[port].sgmii_pcs;  	default:  		return NULL;  	} @@ -2764,7 +2738,8 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  	switch (port) {  	case 0 ... 4: /* Internal phy */ -		if (state->interface != PHY_INTERFACE_MODE_GMII) +		if (state->interface != PHY_INTERFACE_MODE_GMII && +		    state->interface != PHY_INTERFACE_MODE_INTERNAL)  			goto unsupported;  		break;  	case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ @@ -2842,7 +2817,8 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,  	/* MT753x MAC works in 1G full duplex mode for all up-clocked  	 * variants.  	 */ -	if (interface == PHY_INTERFACE_MODE_TRGMII || +	if (interface == PHY_INTERFACE_MODE_INTERNAL || +	    interface == PHY_INTERFACE_MODE_TRGMII ||  	    (phy_interface_mode_is_8023z(interface))) {  		speed = SPEED_1000;  		duplex = DUPLEX_FULL; @@ -2922,6 +2898,21 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port)  	return 0;  } +static int +mt7988_cpu_port_config(struct dsa_switch *ds, int port) +{ +	struct mt7530_priv *priv = ds->priv; + +	mt7530_write(priv, MT7530_PMCR_P(port), +		     PMCR_CPU_PORT_SETTING(priv->id)); + +	mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, +				   PHY_INTERFACE_MODE_INTERNAL, NULL, +				   SPEED_10000, DUPLEX_FULL, true, true); + +	return 0; +} +  static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,  				    struct phylink_config *config)  { @@ -2987,86 +2978,6 @@ static void mt7530_pcs_get_state(struct phylink_pcs *pcs,  		state->pause |= MLO_PAUSE_TX;  } -static int -mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, -			      struct phylink_link_state *state) -{ -	u32 status, val; -	u16 config_reg; - -	status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); -	state->link = !!(status & MT7531_SGMII_LINK_STATUS); -	state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE); -	if (state->interface == PHY_INTERFACE_MODE_SGMII && -	    (status & MT7531_SGMII_AN_ENABLE)) { -		val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); -		config_reg = val >> 16; - -		switch (config_reg & LPA_SGMII_SPD_MASK) { -		case LPA_SGMII_1000: -			state->speed = SPEED_1000; -			break; -		case LPA_SGMII_100: -			state->speed = SPEED_100; -			break; -		case LPA_SGMII_10: -			state->speed = SPEED_10; -			break; -		default: -			dev_err(priv->dev, "invalid sgmii PHY speed\n"); -			state->link = false; -			return -EINVAL; -		} - -		if (config_reg & LPA_SGMII_FULL_DUPLEX) -			state->duplex = DUPLEX_FULL; -		else -			state->duplex = DUPLEX_HALF; -	} - -	return 0; -} - -static void -mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, -				  struct phylink_link_state *state) -{ -	unsigned int val; - -	val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); -	state->link = !!(val & MT7531_SGMII_LINK_STATUS); -	if (!state->link) -		return; - -	state->an_complete = state->link; - -	if (state->interface == PHY_INTERFACE_MODE_2500BASEX) -		state->speed = SPEED_2500; -	else -		state->speed = SPEED_1000; - -	state->duplex = DUPLEX_FULL; -	state->pause = MLO_PAUSE_NONE; -} - -static void mt7531_pcs_get_state(struct phylink_pcs *pcs, -				 struct phylink_link_state *state) -{ -	struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; -	int port = pcs_to_mt753x_pcs(pcs)->port; - -	if (state->interface == PHY_INTERFACE_MODE_SGMII) { -		mt7531_sgmii_pcs_get_state_an(priv, port, state); -		return; -	} else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || -		   (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { -		mt7531_sgmii_pcs_get_state_inband(priv, port, state); -		return; -	} - -	state->link = false; -} -  static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,  			     phy_interface_t interface,  			     const unsigned long *advertising, @@ -3086,14 +2997,6 @@ static const struct phylink_pcs_ops mt7530_pcs_ops = {  	.pcs_an_restart = mt7530_pcs_an_restart,  }; -static const struct phylink_pcs_ops mt7531_pcs_ops = { -	.pcs_validate = mt753x_pcs_validate, -	.pcs_get_state = mt7531_pcs_get_state, -	.pcs_config = mt753x_pcs_config, -	.pcs_an_restart = mt7531_pcs_an_restart, -	.pcs_link_up = mt7531_pcs_link_up, -}; -  static int  mt753x_setup(struct dsa_switch *ds)  { @@ -3105,8 +3008,6 @@ mt753x_setup(struct dsa_switch *ds)  		priv->pcs[i].pcs.ops = priv->info->pcs_ops;  		priv->pcs[i].priv = priv;  		priv->pcs[i].port = i; -		if (mt753x_is_mac_port(i)) -			priv->pcs[i].pcs.poll = 1;  	}  	ret = priv->info->sw_setup(ds); @@ -3121,6 +3022,12 @@ mt753x_setup(struct dsa_switch *ds)  	if (ret && priv->irq)  		mt7530_free_irq_common(priv); +	if (priv->create_sgmii) { +		ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv)); +		if (ret && priv->irq) +			mt7530_free_irq(priv); +	} +  	return ret;  } @@ -3154,7 +3061,28 @@ static int mt753x_set_mac_eee(struct dsa_switch *ds, int port,  	return 0;  } -static const struct dsa_switch_ops mt7530_switch_ops = { +static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface) +{ +	return 0; +} + +static int mt7988_setup(struct dsa_switch *ds) +{ +	struct mt7530_priv *priv = ds->priv; + +	/* Reset the switch */ +	reset_control_assert(priv->rstc); +	usleep_range(20, 50); +	reset_control_deassert(priv->rstc); +	usleep_range(20, 50); + +	/* Reset the switch PHYs */ +	mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST); + +	return mt7531_setup_common(ds); +} + +const struct dsa_switch_ops mt7530_switch_ops = {  	.get_tag_protocol	= mtk_get_tag_protocol,  	.setup			= mt753x_setup,  	.get_strings		= mt7530_get_strings, @@ -3188,8 +3116,9 @@ static const struct dsa_switch_ops mt7530_switch_ops = {  	.get_mac_eee		= mt753x_get_mac_eee,  	.set_mac_eee		= mt753x_set_mac_eee,  }; +EXPORT_SYMBOL_GPL(mt7530_switch_ops); -static const struct mt753x_info mt753x_table[] = { +const struct mt753x_info mt753x_table[] = {  	[ID_MT7621] = {  		.id = ID_MT7621,  		.pcs_ops = &mt7530_pcs_ops, @@ -3216,7 +3145,7 @@ static const struct mt753x_info mt753x_table[] = {  	},  	[ID_MT7531] = {  		.id = ID_MT7531, -		.pcs_ops = &mt7531_pcs_ops, +		.pcs_ops = &mt7530_pcs_ops,  		.sw_setup = mt7531_setup,  		.phy_read_c22 = mt7531_ind_c22_phy_read,  		.phy_write_c22 = mt7531_ind_c22_phy_write, @@ -3227,53 +3156,38 @@ static const struct mt753x_info mt753x_table[] = {  		.mac_port_get_caps = mt7531_mac_port_get_caps,  		.mac_port_config = mt7531_mac_config,  	}, +	[ID_MT7988] = { +		.id = ID_MT7988, +		.pcs_ops = &mt7530_pcs_ops, +		.sw_setup = mt7988_setup, +		.phy_read_c22 = mt7531_ind_c22_phy_read, +		.phy_write_c22 = mt7531_ind_c22_phy_write, +		.phy_read_c45 = mt7531_ind_c45_phy_read, +		.phy_write_c45 = mt7531_ind_c45_phy_write, +		.pad_setup = mt7988_pad_setup, +		.cpu_port_config = mt7988_cpu_port_config, +		.mac_port_get_caps = mt7988_mac_port_get_caps, +		.mac_port_config = mt7988_mac_config, +	},  }; +EXPORT_SYMBOL_GPL(mt753x_table); -static const struct of_device_id mt7530_of_match[] = { -	{ .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], }, -	{ .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], }, -	{ .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], }, -	{ /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, mt7530_of_match); - -static int -mt7530_probe(struct mdio_device *mdiodev) +int +mt7530_probe_common(struct mt7530_priv *priv)  { -	struct mt7530_priv *priv; -	struct device_node *dn; - -	dn = mdiodev->dev.of_node; - -	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -	if (!priv) -		return -ENOMEM; +	struct device *dev = priv->dev; -	priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); +	priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);  	if (!priv->ds)  		return -ENOMEM; -	priv->ds->dev = &mdiodev->dev; +	priv->ds->dev = dev;  	priv->ds->num_ports = MT7530_NUM_PORTS; -	/* Use medatek,mcm property to distinguish hardware type that would -	 * casues a little bit differences on power-on sequence. -	 */ -	priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); -	if (priv->mcm) { -		dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); - -		priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); -		if (IS_ERR(priv->rstc)) { -			dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); -			return PTR_ERR(priv->rstc); -		} -	} -  	/* Get the hardware identifier from the devicetree node.  	 * We will need it for some of the clock and regulator setup.  	 */ -	priv->info = of_device_get_match_data(&mdiodev->dev); +	priv->info = of_device_get_match_data(dev);  	if (!priv->info)  		return -EINVAL; @@ -3287,90 +3201,27 @@ mt7530_probe(struct mdio_device *mdiodev)  		return -EINVAL;  	priv->id = priv->info->id; - -	if (priv->id == ID_MT7530) { -		priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); -		if (IS_ERR(priv->core_pwr)) -			return PTR_ERR(priv->core_pwr); - -		priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); -		if (IS_ERR(priv->io_pwr)) -			return PTR_ERR(priv->io_pwr); -	} - -	/* Not MCM that indicates switch works as the remote standalone -	 * integrated circuit so the GPIO pin would be used to complete -	 * the reset, otherwise memory-mapped register accessing used -	 * through syscon provides in the case of MCM. -	 */ -	if (!priv->mcm) { -		priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", -						      GPIOD_OUT_LOW); -		if (IS_ERR(priv->reset)) { -			dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); -			return PTR_ERR(priv->reset); -		} -	} - -	priv->bus = mdiodev->bus; -	priv->dev = &mdiodev->dev; +	priv->dev = dev;  	priv->ds->priv = priv;  	priv->ds->ops = &mt7530_switch_ops;  	mutex_init(&priv->reg_mutex); -	dev_set_drvdata(&mdiodev->dev, priv); +	dev_set_drvdata(dev, priv); -	return dsa_register_switch(priv->ds); +	return 0;  } +EXPORT_SYMBOL_GPL(mt7530_probe_common); -static void -mt7530_remove(struct mdio_device *mdiodev) +void +mt7530_remove_common(struct mt7530_priv *priv)  { -	struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); -	int ret = 0; - -	if (!priv) -		return; - -	ret = regulator_disable(priv->core_pwr); -	if (ret < 0) -		dev_err(priv->dev, -			"Failed to disable core power: %d\n", ret); - -	ret = regulator_disable(priv->io_pwr); -	if (ret < 0) -		dev_err(priv->dev, "Failed to disable io pwr: %d\n", -			ret); -  	if (priv->irq)  		mt7530_free_irq(priv);  	dsa_unregister_switch(priv->ds); -	mutex_destroy(&priv->reg_mutex); -} - -static void mt7530_shutdown(struct mdio_device *mdiodev) -{ -	struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); - -	if (!priv) -		return; -	dsa_switch_shutdown(priv->ds); - -	dev_set_drvdata(&mdiodev->dev, NULL); +	mutex_destroy(&priv->reg_mutex);  } - -static struct mdio_driver mt7530_mdio_driver = { -	.probe  = mt7530_probe, -	.remove = mt7530_remove, -	.shutdown = mt7530_shutdown, -	.mdiodrv.driver = { -		.name = "mt7530", -		.of_match_table = mt7530_of_match, -	}, -}; - -mdio_module_driver(mt7530_mdio_driver); +EXPORT_SYMBOL_GPL(mt7530_remove_common);  MODULE_AUTHOR("Sean Wang <[email protected]>");  MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");  |