In earlier case phy fixup are added in board file as this is no more the case so adding support for phy register fixup in Device Tree Signed-off-by: Mugunthan V N <mugunthanvnm@xxxxxx> --- .../devicetree/bindings/net/phy-fixup.txt | 26 ++++++ drivers/of/of_net.c | 92 ++++++++++++++++++++ include/linux/of_net.h | 6 ++ 3 files changed, 124 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/phy-fixup.txt diff --git a/Documentation/devicetree/bindings/net/phy-fixup.txt b/Documentation/devicetree/bindings/net/phy-fixup.txt new file mode 100644 index 0000000..460f76d --- /dev/null +++ b/Documentation/devicetree/bindings/net/phy-fixup.txt @@ -0,0 +1,26 @@ +Ethernet Phy fixup Device Tree Bindings +--------------------------------------- + +The following DT fields can be added to MDIO DT notes and can be used to +add phy fix up needed + +Required properties: +- phy-fixup-registers : Will contain a array of register fix nodes which has + the following node parameters +- phy-id : Specifies the phy id for which the fix belongs to +- phy-mask : Specifies the phy mask for which the fix belongs to +- fixup-registers : Specifies the fix up registers and values in array + of offset value pair +Optional properties: + +Examples: + +&davinci_mdio { + phy-fixup-registers = <&atheros_txclk_delay_fixup>; + + atheros_txclk_delay_fixup: atheros_txclk_delay_fixup { + phy-id = <0x4dd074>; + phy-mask = <0xfffffffe>; + fixup-registers = <0x1d 0x5 0x1e 0x100>; + }; +}; diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c index ffab033..50ad671 100644 --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -10,6 +10,7 @@ #include <linux/of_net.h> #include <linux/phy.h> #include <linux/export.h> +#include <linux/of_net.h> /** * It maps 'enum phy_interface_t' found in include/linux/phy.h @@ -92,3 +93,94 @@ const void *of_get_mac_address(struct device_node *np) return NULL; } EXPORT_SYMBOL(of_get_mac_address); + +static int __of_phy_fixup_cb(struct phy_device *phydev) +{ + struct device_node *node = phydev->bus->parent->of_node; + struct device_node *phy_fixup_node; + const __be32 *parp; + int lenp; + int i, j; + + parp = of_get_property(node, "phy-fixup-registers", &lenp); + if (parp == NULL) + return 0; + lenp /= sizeof(void *); + + for (i = 0; i < lenp; i++) { + u32 phy_id; + const __be32 *fixups; + int fixup_len; + + phy_fixup_node = of_find_node_by_phandle(be32_to_cpup(parp+i)); + if (of_property_read_u32(phy_fixup_node, "phy-id", &phy_id)) { + pr_err("Missing PHY id in Phy fixup\n"); + return -EINVAL; + } + if (phy_id != phydev->phy_id) + continue; + + fixups = of_get_property(phy_fixup_node, "fixup-registers", + &fixup_len); + if (fixups == NULL) { + pr_err("Missing fixup registers in Phy fixup\n"); + return -EINVAL; + } + fixup_len /= sizeof(void *); + for (j = 0; j < fixup_len; j += 2) { + u16 regnum = be32_to_cpup(fixups + j); + u16 val = be32_to_cpup(fixups + j + 1); + phy_write(phydev, regnum, val); + } + } + + return 0; +} + +int of_add_phy_fixup_register(struct device_node *node) +{ + struct device_node *phy_fixup_node; + const __be32 *parp; + int lenp; + int i; + + parp = of_get_property(node, "phy-fixup-registers", &lenp); + if (parp == NULL) + return 0; + lenp /= sizeof(void *); + + for (i = 0; i < lenp; i++) { + u32 phy_id; + u32 phy_mask; + const __be32 *fixups; + int fixup_len; + + phy_fixup_node = of_find_node_by_phandle(be32_to_cpup(parp+i)); + if (of_property_read_u32(phy_fixup_node, "phy-id", &phy_id)) { + pr_err("Missing PHY id in Phy fixup\n"); + continue; + } + + if (of_property_read_u32(phy_fixup_node, "phy-mask", + &phy_mask)) { + pr_err("Missing PHY mask in Phy fixup\n"); + continue; + } + + fixups = of_get_property(phy_fixup_node, "fixup-registers", + &fixup_len); + if (fixups == NULL) { + pr_err("Missing fixup registers in Phy fixup\n"); + continue; + } + fixup_len /= sizeof(void *); + if (fixup_len % 2) { + pr_err("Fixup registers length is invalid in Phy fixup\n"); + continue; + } + phy_register_fixup_for_uid(phy_id, phy_mask, __of_phy_fixup_cb); + } + + return 0; +} +EXPORT_SYMBOL_GPL(of_add_phy_fixup_register); diff --git a/include/linux/of_net.h b/include/linux/of_net.h index 61bf53b..c690e38 100644 --- a/include/linux/of_net.h +++ b/include/linux/of_net.h @@ -11,6 +11,7 @@ #include <linux/of.h> extern const int of_get_phy_mode(struct device_node *np); extern const void *of_get_mac_address(struct device_node *np); +extern int of_add_phy_fixup_register(struct device_node *node); #else static inline const int of_get_phy_mode(struct device_node *np) { @@ -21,6 +22,11 @@ static inline const void *of_get_mac_address(struct device_node *np) { return NULL; } + +static int of_add_phy_fixup_register(struct device_node *node) +{ + return -ENODEV; +} #endif #endif /* __LINUX_OF_NET_H */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html