ath79: ag71xx: add support for optional mdio reset
[openwrt/staging/wigyori.git] / target / linux / ath79 / files / drivers / net / ethernet / atheros / ag71xx / ag71xx_gmac.c
1 /*
2 * Atheros AR71xx built-in ethernet mac driver
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
7 */
8
9 #include <linux/sizes.h>
10 #include <linux/of_address.h>
11 #include "ag71xx.h"
12
13 static void ag71xx_of_set(struct device_node *np, const char *prop,
14 u32 *reg, u32 shift, u32 mask)
15 {
16 u32 val;
17
18 if (of_property_read_u32(np, prop, &val))
19 return;
20
21 *reg &= ~(mask << shift);
22 *reg |= ((val & mask) << shift);
23 }
24
25 static void ag71xx_of_bit(struct device_node *np, const char *prop,
26 u32 *reg, u32 mask)
27 {
28 u32 val;
29
30 if (of_property_read_u32(np, prop, &val))
31 return;
32
33 if (val)
34 *reg |= mask;
35 else
36 *reg &= ~mask;
37 }
38
39 static void ag71xx_setup_gmac_933x(struct device_node *np, void __iomem *base)
40 {
41 u32 val = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);
42
43 ag71xx_of_bit(np, "switch-phy-swap", &val, AR933X_ETH_CFG_SW_PHY_SWAP);
44 ag71xx_of_bit(np, "switch-phy-addr-swap", &val,
45 AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);
46
47 __raw_writel(val, base + AR933X_GMAC_REG_ETH_CFG);
48 }
49
50 static void ag71xx_setup_gmac_934x(struct device_node *np, void __iomem *base)
51 {
52 u32 val = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
53
54 ag71xx_of_bit(np, "rgmii-gmac0", &val, AR934X_ETH_CFG_RGMII_GMAC0);
55 ag71xx_of_bit(np, "mii-gmac0", &val, AR934X_ETH_CFG_MII_GMAC0);
56 ag71xx_of_bit(np, "gmii-gmac0", &val, AR934X_ETH_CFG_GMII_GMAC0);
57 ag71xx_of_bit(np, "switch-phy-swap", &val, AR934X_ETH_CFG_SW_PHY_SWAP);
58 ag71xx_of_bit(np, "switch-only-mode", &val,
59 AR934X_ETH_CFG_SW_ONLY_MODE);
60 ag71xx_of_set(np, "rxdv-delay", &val,
61 AR934X_ETH_CFG_RDV_DELAY_SHIFT, 0x3);
62 ag71xx_of_set(np, "rxd-delay", &val,
63 AR934X_ETH_CFG_RXD_DELAY_SHIFT, 0x3);
64 ag71xx_of_set(np, "txd-delay", &val,
65 AR934X_ETH_CFG_TXD_DELAY_SHIFT, 0x3);
66 ag71xx_of_set(np, "txen-delay", &val,
67 AR934X_ETH_CFG_TXE_DELAY_SHIFT, 0x3);
68
69 __raw_writel(val, base + AR934X_GMAC_REG_ETH_CFG);
70 }
71
72 static void ag71xx_setup_gmac_955x(struct device_node *np, void __iomem *base)
73 {
74 u32 val = __raw_readl(base + QCA955X_GMAC_REG_ETH_CFG);
75
76 ag71xx_of_bit(np, "rgmii-enabled", &val, QCA955X_ETH_CFG_RGMII_EN);
77 ag71xx_of_bit(np, "ge0-sgmii", &val, QCA955X_ETH_CFG_GE0_SGMII);
78 ag71xx_of_set(np, "txen-delay", &val, QCA955X_ETH_CFG_TXE_DELAY_SHIFT, 0x3);
79 ag71xx_of_set(np, "txd-delay", &val, QCA955X_ETH_CFG_TXD_DELAY_SHIFT, 0x3);
80 ag71xx_of_set(np, "rxdv-delay", &val, QCA955X_ETH_CFG_RDV_DELAY_SHIFT, 0x3);
81 ag71xx_of_set(np, "rxd-delay", &val, QCA955X_ETH_CFG_RXD_DELAY_SHIFT, 0x3);
82
83 __raw_writel(val, base + QCA955X_GMAC_REG_ETH_CFG);
84 }
85
86 static void ag71xx_setup_gmac_956x(struct device_node *np, void __iomem *base)
87 {
88 u32 val = __raw_readl(base + QCA956X_GMAC_REG_ETH_CFG);
89
90 ag71xx_of_bit(np, "switch-phy-swap", &val, QCA956X_ETH_CFG_SW_PHY_SWAP);
91 ag71xx_of_bit(np, "switch-phy-addr-swap", &val,
92 QCA956X_ETH_CFG_SW_PHY_ADDR_SWAP);
93
94 __raw_writel(val, base + QCA956X_GMAC_REG_ETH_CFG);
95 }
96
97 int ag71xx_setup_gmac(struct device_node *np)
98 {
99 struct device_node *np_dev;
100 void __iomem *base;
101 int err = 0;
102
103 np = of_get_child_by_name(np, "gmac-config");
104 if (!np)
105 return 0;
106
107 np_dev = of_parse_phandle(np, "device", 0);
108 if (!np_dev)
109 goto out;
110
111 base = of_iomap(np_dev, 0);
112 if (!base) {
113 pr_err("%pOF: can't map GMAC registers\n", np_dev);
114 err = -ENOMEM;
115 goto err_iomap;
116 }
117
118 if (of_device_is_compatible(np_dev, "qca,ar9330-gmac"))
119 ag71xx_setup_gmac_933x(np, base);
120 else if (of_device_is_compatible(np_dev, "qca,ar9340-gmac"))
121 ag71xx_setup_gmac_934x(np, base);
122 else if (of_device_is_compatible(np_dev, "qca,qca9550-gmac"))
123 ag71xx_setup_gmac_955x(np, base);
124 else if (of_device_is_compatible(np_dev, "qca,qca9560-gmac"))
125 ag71xx_setup_gmac_956x(np, base);
126
127 iounmap(base);
128
129 err_iomap:
130 of_node_put(np_dev);
131 out:
132 of_node_put(np);
133 return err;
134 }