diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2012-09-09 14:05:17 +0000 |
---|---|---|
committer | Gabor Juhos <juhosg@openwrt.org> | 2012-09-09 14:05:17 +0000 |
commit | 759205777494fbf0b20eb9e133f4debb9e0d06ff (patch) | |
tree | a9c6625d14551d14abc607f304a90ca4a22d6aa6 /target/linux/ar71xx/files/drivers | |
parent | f3ecbea0526496d57d4f82b7521573e967074b8d (diff) | |
download | upstream-759205777494fbf0b20eb9e133f4debb9e0d06ff.tar.gz upstream-759205777494fbf0b20eb9e133f4debb9e0d06ff.tar.bz2 upstream-759205777494fbf0b20eb9e133f4debb9e0d06ff.zip |
ar71xx: add dynamic MDIO clock calculation
SVN-Revision: 33342
Diffstat (limited to 'target/linux/ar71xx/files/drivers')
-rw-r--r-- | target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c | 72 |
1 files changed, 64 insertions, 8 deletions
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 eaaf121485..e123505c7a 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); |