diff options
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/ath79/dts/ar9330.dtsi | 1 | ||||
-rw-r--r-- | target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c | 88 |
2 files changed, 63 insertions, 26 deletions
diff --git a/target/linux/ath79/dts/ar9330.dtsi b/target/linux/ath79/dts/ar9330.dtsi index 4649262b28..a902712e3c 100644 --- a/target/linux/ath79/dts/ar9330.dtsi +++ b/target/linux/ath79/dts/ar9330.dtsi @@ -166,6 +166,7 @@ &mdio1 { status = "okay"; + compatible = "qca,ar9330-mdio"; resets = <&rst 23>; reset-names = "mdio"; diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c index baaa33e10b..0bfc1546cd 100644 --- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c +++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c @@ -84,14 +84,62 @@ static int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, u16 val return 0; } -static int ar934x_mdio_clock_div(unsigned int rate) +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 device_node *np, u32 *div) { - if (rate == 100 * 1000 * 1000) - return 6; /* 100 MHz clock divided by 20 => 5 MHz */ - else if (rate == 25 * 1000 * 1000) - return 0; /* 25 MHz clock divided by 4 => 6.25 MHz */ - else - return 3; /* 40 MHz clock divided by 8 => 5 MHz */ + struct clk *ref_clk = of_clk_get(np, 0); + unsigned long ref_clock; + u32 mdio_clock; + const u32 *table; + int ndivs, i; + + if (IS_ERR(ref_clk)) + return -EINVAL; + + ref_clock = clk_get_rate(ref_clk); + clk_put(ref_clk); + + if(of_property_read_u32(np, "qca,mdio-max-frequency", &mdio_clock)) { + if (of_property_read_bool(np, "builtin-switch")) + mdio_clock = 5000000; + else + mdio_clock = 2000000; + } + + if (of_device_is_compatible(np, "qca,ar9330-mdio") || + of_device_is_compatible(np, "qca,ar9340-mdio")) { + table = ar933x_mdio_div_table; + ndivs = ARRAY_SIZE(ar933x_mdio_div_table); + } else if (of_device_is_compatible(np, "qca,ar7240-mdio")) { + 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; + } + } + + return -ENOENT; } static int ag71xx_mdio_reset(struct mii_bus *bus) @@ -103,26 +151,13 @@ static int ag71xx_mdio_reset(struct mii_bus *bus) builtin_switch = of_property_read_bool(np, "builtin-switch"); - if (of_device_is_compatible(np, "qca,ar7240-mdio")) - t = MII_CFG_CLK_DIV_6; - else if (of_device_is_compatible(np, "qca,ar9340-mdio")) - t = MII_CFG_CLK_DIV_58; - else if (builtin_switch) - t = MII_CFG_CLK_DIV_10; - else - t = MII_CFG_CLK_DIV_28; - - if (builtin_switch && of_device_is_compatible(np, "qca,ar9340-mdio")) { - struct clk *ref_clk = of_clk_get(np, 0); - int clock_rate; - - if (WARN_ON_ONCE(!ref_clk)) - clock_rate = 40 * 1000 * 1000; + if (ag71xx_mdio_get_divider(np, &t)) { + if (of_device_is_compatible(np, "qca,ar9340-mdio")) + t = MII_CFG_CLK_DIV_58; + else if (builtin_switch) + t = MII_CFG_CLK_DIV_10; else - clock_rate = clk_get_rate(ref_clk); - - t = ar934x_mdio_clock_div(clock_rate); - clk_put(ref_clk); + t = MII_CFG_CLK_DIV_28; } regmap_write(am->mii_regmap, AG71XX_REG_MII_CFG, t | MII_CFG_RESET); @@ -200,6 +235,7 @@ static int ag71xx_mdio_remove(struct platform_device *pdev) static const struct of_device_id ag71xx_mdio_match[] = { { .compatible = "qca,ar7240-mdio" }, + { .compatible = "qca,ar9330-mdio" }, { .compatible = "qca,ar9340-mdio" }, { .compatible = "qca,ath79-mdio" }, {} |