diff options
| author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-09-09 14:05:17 +0000 | 
|---|---|---|
| committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-09-09 14:05:17 +0000 | 
| commit | c4b6e540e4557e10b9f0823caa00cd3e86261902 (patch) | |
| tree | 11ff13b2aec0a27b113048423f63bc8d9f9fc4f6 | |
| parent | 38ca354cccec484bd62b89c5958c729a04215460 (diff) | |
ar71xx: add dynamic MDIO clock calculation
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33342 3c298f89-4303-0410-b956-a3cf2f4a3e73
| -rw-r--r-- | target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h | 2 | ||||
| -rw-r--r-- | target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c | 72 | 
2 files changed, 66 insertions, 8 deletions
| diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h index e2f6f9b11..656a6ef86 100644 --- a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h +++ b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h @@ -53,6 +53,8 @@ struct ag71xx_mdio_platform_data {  	u8		is_ar7240:1;  	u8		is_ar9330:1;  	u8		is_ar934x:1; +	unsigned long	mdio_clock; +	unsigned long	ref_clock;  };  #endif /* __ASM_MACH_ATH79_PLATFORM_H */ diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c index eaaf12148..e123505c7 100644 --- a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c +++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c @@ -105,19 +105,75 @@ void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val)  	ag71xx_mdio_wait_busy(am);  } +static const u32 ar71xx_mdio_div_table[] = { +	4, 4, 6, 8, 10, 14, 20, 28, +}; + +static const u32 ar7240_mdio_div_table[] = { +	2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96, +}; + +static const u32 ar933x_mdio_div_table[] = { +	4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98, +}; + +static int ag71xx_mdio_get_divider(struct ag71xx_mdio *am, u32 *div) +{ +	unsigned long ref_clock, mdio_clock; +	const u32 *table; +	int ndivs; +	int i; + +	ref_clock = am->pdata->ref_clock; +	mdio_clock = am->pdata->mdio_clock; + +	if (!ref_clock || !mdio_clock) +		return -EINVAL; + +	if (am->pdata->is_ar9330 || am->pdata->is_ar934x) { +		table = ar933x_mdio_div_table; +		ndivs = ARRAY_SIZE(ar933x_mdio_div_table); +	} else if (am->pdata->is_ar7240) { +		table = ar7240_mdio_div_table; +		ndivs = ARRAY_SIZE(ar7240_mdio_div_table); +	} else { +		table = ar71xx_mdio_div_table; +		ndivs = ARRAY_SIZE(ar71xx_mdio_div_table); +	} + +	for (i = 0; i < ndivs; i++) { +		unsigned long t; + +		t = ref_clock / table[i]; +		if (t <= mdio_clock) { +			*div = i; +			return 0; +		} +	} + +	dev_err(&am->mii_bus->dev, "no divider found for %lu/%lu\n", +		ref_clock, mdio_clock); +	return -ENOENT; +} +  static int ag71xx_mdio_reset(struct mii_bus *bus)  {  	struct ag71xx_mdio *am = bus->priv;  	u32 t; +	int err; -	if (am->pdata->is_ar7240) -		t = MII_CFG_CLK_DIV_6; -	else if (am->pdata->builtin_switch && !am->pdata->is_ar934x) -		t = MII_CFG_CLK_DIV_10; -	else if (!am->pdata->builtin_switch && am->pdata->is_ar934x) -		t = MII_CFG_CLK_DIV_58; -	else -		t = MII_CFG_CLK_DIV_28; +	err = ag71xx_mdio_get_divider(am, &t); +	if (err) { +		/* fallback */ +		if (am->pdata->is_ar7240) +			t = MII_CFG_CLK_DIV_6; +		else if (am->pdata->builtin_switch && !am->pdata->is_ar934x) +			t = MII_CFG_CLK_DIV_10; +		else if (!am->pdata->builtin_switch && am->pdata->is_ar934x) +			t = MII_CFG_CLK_DIV_58; +		else +			t = MII_CFG_CLK_DIV_28; +	}  	ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);  	udelay(100); | 
