ralink: reduce access to uncached tx/rx dma ring buffer
[openwrt/svn-archive/archive.git] / target / linux / ramips / files / drivers / net / ethernet / ralink / mdio_rt2880.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; version 2 of the License
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
14 *
15 * Copyright (C) 2009-2013 John Crispin <blogic@openwrt.org>
16 */
17
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/types.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/init.h>
23 #include <linux/skbuff.h>
24 #include <linux/etherdevice.h>
25 #include <linux/ethtool.h>
26 #include <linux/platform_device.h>
27 #include <linux/phy.h>
28 #include <linux/of_device.h>
29 #include <linux/clk.h>
30 #include <linux/of_net.h>
31 #include <linux/of_mdio.h>
32
33 #include "ralink_soc_eth.h"
34 #include "mdio_rt2880.h"
35 #include "mdio.h"
36
37 #define FE_MDIO_RETRY 1000
38
39 static unsigned char *rt2880_speed_str(struct fe_priv *priv)
40 {
41 switch (priv->phy->speed[0]) {
42 case SPEED_1000:
43 return "1000";
44 case SPEED_100:
45 return "100";
46 case SPEED_10:
47 return "10";
48 }
49
50 return "?";
51 }
52
53 void rt2880_mdio_link_adjust(struct fe_priv *priv, int port)
54 {
55 u32 mdio_cfg;
56
57 if (!priv->link[0]) {
58 netif_carrier_off(priv->netdev);
59 netdev_info(priv->netdev, "link down\n");
60 return;
61 }
62
63 mdio_cfg = FE_MDIO_CFG_TX_CLK_SKEW_200 |
64 FE_MDIO_CFG_RX_CLK_SKEW_200 |
65 FE_MDIO_CFG_GP1_FRC_EN;
66
67 if (priv->phy->duplex[0] == DUPLEX_FULL)
68 mdio_cfg |= FE_MDIO_CFG_GP1_DUPLEX;
69
70 if (priv->phy->tx_fc[0])
71 mdio_cfg |= FE_MDIO_CFG_GP1_FC_TX;
72
73 if (priv->phy->rx_fc[0])
74 mdio_cfg |= FE_MDIO_CFG_GP1_FC_RX;
75
76 switch (priv->phy->speed[0]) {
77 case SPEED_10:
78 mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_10;
79 break;
80 case SPEED_100:
81 mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_100;
82 break;
83 case SPEED_1000:
84 mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_1000;
85 break;
86 default:
87 BUG();
88 }
89
90 fe_w32(mdio_cfg, FE_MDIO_CFG);
91
92 netif_carrier_on(priv->netdev);
93 netdev_info(priv->netdev, "link up (%sMbps/%s duplex)\n",
94 rt2880_speed_str(priv),
95 (DUPLEX_FULL == priv->phy->duplex[0]) ? "Full" : "Half");
96 }
97
98 static int rt2880_mdio_wait_ready(struct fe_priv *priv)
99 {
100 int retries;
101
102 retries = FE_MDIO_RETRY;
103 while (1) {
104 u32 t;
105
106 t = fe_r32(FE_MDIO_ACCESS);
107 if ((t & (0x1 << 31)) == 0)
108 return 0;
109
110 if (retries-- == 0)
111 break;
112
113 udelay(1);
114 }
115
116 dev_err(priv->device, "MDIO operation timed out\n");
117 return -ETIMEDOUT;
118 }
119
120 int rt2880_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
121 {
122 struct fe_priv *priv = bus->priv;
123 int err;
124 u32 t;
125
126 err = rt2880_mdio_wait_ready(priv);
127 if (err)
128 return 0xffff;
129
130 t = (phy_addr << 24) | (phy_reg << 16);
131 fe_w32(t, FE_MDIO_ACCESS);
132 t |= (1 << 31);
133 fe_w32(t, FE_MDIO_ACCESS);
134
135 err = rt2880_mdio_wait_ready(priv);
136 if (err)
137 return 0xffff;
138
139 pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__,
140 phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff);
141
142 return fe_r32(FE_MDIO_ACCESS) & 0xffff;
143 }
144
145 int rt2880_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val)
146 {
147 struct fe_priv *priv = bus->priv;
148 int err;
149 u32 t;
150
151 pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__,
152 phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff);
153
154 err = rt2880_mdio_wait_ready(priv);
155 if (err)
156 return err;
157
158 t = (1 << 30) | (phy_addr << 24) | (phy_reg << 16) | val;
159 fe_w32(t, FE_MDIO_ACCESS);
160 t |= (1 << 31);
161 fe_w32(t, FE_MDIO_ACCESS);
162
163 return rt2880_mdio_wait_ready(priv);
164 }
165
166 void rt2880_port_init(struct fe_priv *priv, struct device_node *np)
167 {
168 const __be32 *id = of_get_property(np, "reg", NULL);
169 const __be32 *link;
170 int size;
171 int phy_mode;
172
173 if (!id || (be32_to_cpu(*id) != 0)) {
174 pr_err("%s: invalid port id\n", np->name);
175 return;
176 }
177
178 priv->phy->phy_fixed[0] = of_get_property(np, "ralink,fixed-link", &size);
179 if (priv->phy->phy_fixed[0] && (size != (4 * sizeof(*priv->phy->phy_fixed[0])))) {
180 pr_err("%s: invalid fixed link property\n", np->name);
181 priv->phy->phy_fixed[0] = NULL;
182 return;
183 }
184
185 phy_mode = of_get_phy_mode(np);
186 switch (phy_mode) {
187 case PHY_INTERFACE_MODE_RGMII:
188 break;
189 case PHY_INTERFACE_MODE_MII:
190 break;
191 case PHY_INTERFACE_MODE_RMII:
192 break;
193 default:
194 if (!priv->phy->phy_fixed[0])
195 dev_err(priv->device, "port %d - invalid phy mode\n", priv->phy->speed[0]);
196 break;
197 }
198
199 priv->phy->phy_node[0] = of_parse_phandle(np, "phy-handle", 0);
200 if (!priv->phy->phy_node[0] && !priv->phy->phy_fixed[0])
201 return;
202
203 if (priv->phy->phy_fixed[0]) {
204 link = priv->phy->phy_fixed[0];
205 priv->phy->speed[0] = be32_to_cpup(link++);
206 priv->phy->duplex[0] = be32_to_cpup(link++);
207 priv->phy->tx_fc[0] = be32_to_cpup(link++);
208 priv->phy->rx_fc[0] = be32_to_cpup(link++);
209
210 priv->link[0] = 1;
211 switch (priv->phy->speed[0]) {
212 case SPEED_10:
213 break;
214 case SPEED_100:
215 break;
216 case SPEED_1000:
217 break;
218 default:
219 dev_err(priv->device, "invalid link speed: %d\n", priv->phy->speed[0]);
220 priv->phy->phy_fixed[0] = 0;
221 return;
222 }
223 dev_info(priv->device, "using fixed link parameters\n");
224 rt2880_mdio_link_adjust(priv, 0);
225 return;
226 }
227 if (priv->phy->phy_node[0] && priv->mii_bus->phy_map[0]) {
228 fe_connect_phy_node(priv, priv->phy->phy_node[0]);
229 }
230
231 return;
232 }