ar71xx: add dynamic MDIO clock calculation

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33342 3c298f89-4303-0410-b956-a3cf2f4a3e73
master
Gabor Juhos 2012-09-09 14:05:17 +00:00
parent 2ef5213899
commit 773fa9a77f
2 changed files with 66 additions and 8 deletions

View File

@ -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 */

View File

@ -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);