surprise :p
[openwrt/staging/wigyori.git] / target / linux / ar71xx / files / drivers / net / ag71xx / ag71xx_mii.c
1 /*
2 * Atheros AR71xx built-in ethernet mac driver
3 *
4 * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
6 *
7 * Based on Atheros' AG7100 driver
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published
11 * by the Free Software Foundation.
12 */
13
14 #include "ag71xx.h"
15
16 #define AG71XX_MII_RETRY 1000
17 #define AG71XX_MII_DELAY 5
18
19 static inline void ag71xx_mii_ctrl_wr(struct ag71xx *ag, u32 value)
20 {
21 __raw_writel(value, ag->mii_ctrl);
22 }
23
24 static inline u32 ag71xx_mii_ctrl_rr(struct ag71xx *ag)
25 {
26 return __raw_readl(ag->mii_ctrl);
27 }
28
29 void ag71xx_mii_ctrl_set_if(struct ag71xx *ag, unsigned int mii_if)
30 {
31 u32 t;
32
33 t = ag71xx_mii_ctrl_rr(ag);
34 t &= ~(0x3);
35 t |= (mii_if & 0x3);
36 ag71xx_mii_ctrl_wr(ag, t);
37 }
38
39 void ag71xx_mii_ctrl_set_speed(struct ag71xx *ag, unsigned int speed)
40 {
41 u32 t;
42
43 t = ag71xx_mii_ctrl_rr(ag);
44 t &= ~(0x3 << 4);
45 t |= (speed & 0x3) << 4;
46 ag71xx_mii_ctrl_wr(ag, t);
47 }
48
49 static int ag71xx_mii_read(struct ag71xx *ag, int addr, int reg)
50 {
51 int ret;
52 int i;
53
54 ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
55 ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
56 ((addr & 0xff) << MII_ADDR_S) | (reg & 0xff));
57 ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_READ);
58
59 i = AG71XX_MII_RETRY;
60 while (ag71xx_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
61 if (i-- == 0) {
62 printk(KERN_ERR "%s: mii_read timed out\n",
63 ag->dev->name);
64 ret = 0xffff;
65 goto out;
66 }
67 udelay(AG71XX_MII_DELAY);
68 }
69
70 ret = ag71xx_rr(ag, AG71XX_REG_MII_STATUS) & 0xffff;
71 ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
72
73 DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
74
75 out:
76 return ret;
77 }
78
79 static void ag71xx_mii_write(struct ag71xx *ag, int addr, int reg, u16 val)
80 {
81 int i;
82
83 DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
84
85 ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
86 ((addr & 0xff) << MII_ADDR_S) | (reg & 0xff));
87 ag71xx_wr(ag, AG71XX_REG_MII_CTRL, val);
88
89 i = AG71XX_MII_RETRY;
90 while (ag71xx_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
91 if (i-- == 0) {
92 printk(KERN_ERR "%s: mii_write timed out\n",
93 ag->dev->name);
94 break;
95 }
96 udelay(AG71XX_MII_DELAY);
97 }
98 }
99
100 int ag71xx_mii_peek(struct ag71xx *ag)
101 {
102 int cnt;
103 int i;
104
105 cnt = 0;
106 for (i = 0; i < PHY_MAX_ADDR; i++) {
107 u16 bmsr, id1, id2, bmcr, advert, lpa;
108
109 bmsr = ag71xx_mii_read(ag, i, MII_BMSR);
110 bmcr = ag71xx_mii_read(ag, i, MII_BMCR);
111 id1 = ag71xx_mii_read(ag, i, MII_PHYSID1);
112 id2 = ag71xx_mii_read(ag, i, MII_PHYSID2);
113 advert = ag71xx_mii_read(ag, i, MII_ADVERTISE);
114 lpa = ag71xx_mii_read(ag, i, MII_LPA);
115 DBG("%s: phy%02d bmsr=%04x, bmcr=%04x, "
116 "id=%04x.%04x, advertise=%04x, lpa=%04x\n",
117 ag->dev->name, i,
118 bmsr, bmcr, id1, id2, advert, lpa);
119
120 if ((bmsr | bmcr | id1 | id2 | advert | lpa) != 0)
121 cnt++;
122 }
123
124 return cnt;
125 }
126
127 #define PLL_SEC_CONFIG 0x18050004
128 #define PLL_ETH0_INT_CLOCK 0x18050010
129 #define PLL_ETH1_INT_CLOCK 0x18050014
130 #define PLL_ETH_EXT_CLOCK 0x18050018
131
132 #define ag7100_pll_shift(_ag) (((_ag)->pdev->id) ? 19 : 17)
133 #define ag7100_pll_offset(_ag) (((_ag)->pdev->id) ? PLL_ETH1_INT_CLOCK \
134 : PLL_ETH0_INT_CLOCK)
135
136 static void ag71xx_set_pll(struct ag71xx *ag, u32 pll_val)
137 {
138 void __iomem *pll_reg = ioremap_nocache(ag7100_pll_offset(ag), 4);
139 void __iomem *pll_cfg = ioremap_nocache(PLL_SEC_CONFIG, 4);
140 u32 s;
141 u32 t;
142
143 s = ag7100_pll_shift(ag);
144
145 t = __raw_readl(pll_cfg);
146 t &= ~(3 << s);
147 t |= (2 << s);
148 __raw_writel(t, pll_cfg);
149 udelay(100);
150
151 __raw_writel(pll_val, pll_reg);
152
153 t |= (3 << s);
154 __raw_writel(t, pll_cfg);
155 udelay(100);
156
157 t &= ~(3 << s);
158 __raw_writel(t, pll_cfg);
159 udelay(100);
160 DBG("%s: pll_reg %#x: %#x\n", ag->dev->name,
161 (unsigned int)pll_reg, __raw_readl(pll_reg));
162
163 iounmap(pll_cfg);
164 iounmap(pll_reg);
165 }
166
167 static unsigned char *ag71xx_speed_str(struct ag71xx *ag)
168 {
169 switch (ag->speed) {
170 case SPEED_1000:
171 return "1000";
172 case SPEED_100:
173 return "100";
174 case SPEED_10:
175 return "10";
176 }
177
178 return "?";
179 }
180
181 #if 1
182 #define PLL_VAL_1000 0x00110000
183 #define PLL_VAL_100 0x00001099
184 #define PLL_VAL_10 0x00991099
185 #else
186 #define PLL_VAL_1000 0x01111000
187 #define PLL_VAL_100 0x09991000
188 #define PLL_VAL_10 0x09991999
189 #endif
190
191 void ag71xx_link_update(struct ag71xx *ag)
192 {
193 u32 cfg2;
194 u32 ifctl;
195 u32 pll;
196 u32 fifo5;
197 u32 mii_speed;
198
199 if (!ag->link) {
200 netif_carrier_off(ag->dev);
201 printk(KERN_INFO "%s: link down\n", ag->dev->name);
202 return;
203 }
204
205 cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
206 cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
207 cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0;
208
209 ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
210 ifctl &= ~(MAC_IFCTL_SPEED);
211
212 fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
213 fifo5 &= ~FIFO_CFG5_BYTE_PER_CLK;
214
215 switch (ag->speed) {
216 case SPEED_1000:
217 mii_speed = MII_CTRL_SPEED_1000;
218 cfg2 |= MAC_CFG2_IF_1000;
219 pll = PLL_VAL_1000;
220 fifo5 |= FIFO_CFG5_BYTE_PER_CLK;
221 break;
222 case SPEED_100:
223 mii_speed = MII_CTRL_SPEED_100;
224 cfg2 |= MAC_CFG2_IF_10_100;
225 ifctl |= MAC_IFCTL_SPEED;
226 pll = PLL_VAL_100;
227 break;
228 case SPEED_10:
229 mii_speed = MII_CTRL_SPEED_10;
230 cfg2 |= MAC_CFG2_IF_10_100;
231 pll = PLL_VAL_10;
232 break;
233 default:
234 BUG();
235 return;
236 }
237
238 ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff);
239 ag71xx_set_pll(ag, pll);
240 ag71xx_mii_ctrl_set_speed(ag, mii_speed);
241
242 ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
243 ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
244 ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
245
246 netif_carrier_on(ag->dev);
247 printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n",
248 ag->dev->name,
249 ag71xx_speed_str(ag),
250 (DUPLEX_FULL == ag->duplex) ? "Full" : "Half");
251
252 DBG("%s: fifo1=%#x, fifo2=%#x, fifo3=%#x, fifo4=%#x, fifo5=%#x\n",
253 ag->dev->name,
254 ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
255 ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2),
256 ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
257 ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
258 ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
259
260 DBG("%s: mac_cfg2=%#x, ifctl=%#x, mii_ctrl=%#x\n",
261 ag->dev->name,
262 ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
263 ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
264 ag71xx_mii_ctrl_rr(ag));
265 }
266
267 static void ag71xx_link_adjust(struct net_device *dev)
268 {
269 struct ag71xx *ag = netdev_priv(dev);
270 struct phy_device *phydev = ag->phy_dev;
271 unsigned long flags;
272 int status_change = 0;
273
274 spin_lock_irqsave(&ag->lock, flags);
275
276 if (phydev->link) {
277 if (ag->duplex != phydev->duplex
278 || ag->speed != phydev->speed) {
279 status_change = 1;
280 }
281 }
282
283 if (phydev->link != ag->link) {
284 if (phydev->link)
285 netif_schedule(dev);
286
287 status_change = 1;
288 }
289
290 ag->link = phydev->link;
291 ag->duplex = phydev->duplex;
292 ag->speed = phydev->speed;
293
294 if (status_change)
295 ag71xx_link_update(ag);
296
297 spin_unlock_irqrestore(&ag->lock, flags);
298 }
299
300 static int ag71xx_mdio_read(struct mii_bus *bus, int addr, int reg)
301 {
302 struct ag71xx *ag = bus->priv;
303
304 return ag71xx_mii_read(ag, addr, reg);
305 }
306
307 static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
308 {
309 struct ag71xx *ag = bus->priv;
310
311 ag71xx_mii_write(ag, addr, reg, val);
312 return 0;
313 }
314
315 static int ag71xx_mdio_reset(struct mii_bus *bus)
316 {
317 /* TODO */
318 return 0;
319 }
320
321 static int ag71xx_mdio_probe(struct ag71xx *ag)
322 {
323 struct net_device *dev = ag->dev;
324 struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
325 struct phy_device *phydev = NULL;
326 int phy_count = 0;
327 int phy_addr;
328
329 for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
330 if (!(pdata->phy_mask & (1 << phy_addr)))
331 continue;
332
333 if (ag->mii_bus.phy_map[phy_addr] == NULL)
334 continue;
335
336 DBG("%s: PHY found at %s, uid=%08x\n",
337 dev->name,
338 ag->mii_bus.phy_map[phy_addr]->dev.bus_id,
339 ag->mii_bus.phy_map[phy_addr]->phy_id);
340
341 if (phydev == NULL)
342 phydev = ag->mii_bus.phy_map[phy_addr];
343
344 phy_count++;
345 }
346
347 switch (phy_count) {
348 case 0:
349 printk(KERN_ERR "%s: no PHY found\n", dev->name);
350 return -ENODEV;
351 case 1:
352 ag->phy_dev = phy_connect(dev, phydev->dev.bus_id,
353 &ag71xx_link_adjust, 0, pdata->phy_if_mode);
354
355 if (IS_ERR(ag->phy_dev)) {
356 printk(KERN_ERR "%s: could not connect to PHY at %s\n",
357 dev->name, phydev->dev.bus_id);
358 return PTR_ERR(ag->phy_dev);
359 }
360
361 /* mask with MAC supported features */
362 phydev->supported &= (SUPPORTED_10baseT_Half
363 | SUPPORTED_10baseT_Full
364 | SUPPORTED_100baseT_Half
365 | SUPPORTED_100baseT_Full
366 | SUPPORTED_Autoneg
367 | SUPPORTED_MII
368 | SUPPORTED_TP);
369
370 phydev->advertising = phydev->supported;
371
372 printk(KERN_DEBUG "%s: connected to PHY at %s "
373 "[uid=%08x, driver=%s]\n",
374 dev->name, phydev->dev.bus_id,
375 phydev->phy_id, phydev->drv->name);
376
377 ag->link = 0;
378 ag->speed = 0;
379 ag->duplex = -1;
380 break;
381 default:
382 ag->phy_dev = NULL;
383 printk(KERN_DEBUG "%s: connected to multiple PHYs (%d)\n",
384 dev->name, phy_count);
385 break;
386 }
387
388 return 0;
389 }
390
391 int ag71xx_mdio_init(struct ag71xx *ag, int id)
392 {
393 int err;
394 int i;
395
396 ag->mii_bus.name = "ag71xx_mii";
397 ag->mii_bus.read = ag71xx_mdio_read;
398 ag->mii_bus.write = ag71xx_mdio_write;
399 ag->mii_bus.reset = ag71xx_mdio_reset;
400 ag->mii_bus.id = id;
401 ag->mii_bus.priv = ag;
402 ag->mii_bus.dev = &ag->dev->dev;
403
404 ag->mii_bus.irq = kmalloc(sizeof(*ag->mii_bus.irq) * PHY_MAX_ADDR,
405 GFP_KERNEL);
406 if (!ag->mii_bus.irq) {
407 err = -ENOMEM;
408 goto err_out;
409 }
410
411 for (i = 0; i < PHY_MAX_ADDR; i++)
412 ag->mii_bus.irq[i] = PHY_POLL;
413
414 err = mdiobus_register(&ag->mii_bus);
415 if (err)
416 goto err_free_irqs;
417
418 err = ag71xx_mdio_probe(ag);
419 if (err)
420 goto err_unregister_bus;
421
422 return 0;
423
424 err_unregister_bus:
425 mdiobus_unregister(&ag->mii_bus);
426 err_free_irqs:
427 kfree(ag->mii_bus.irq);
428 err_out:
429 return err;
430 }
431
432 void ag71xx_mdio_cleanup(struct ag71xx *ag)
433 {
434 mdiobus_unregister(&ag->mii_bus);
435 kfree(ag->mii_bus.irq);
436 }