65940d2017b2abd39b2e2dd1914e23bc2bf1c789
2 * Atheros AR71xx built-in ethernet mac driver
4 * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
7 * Based on Atheros' AG7100 driver
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.
16 #define AG71XX_MII_RETRY 1000
17 #define AG71XX_MII_DELAY 5
19 static inline void ag71xx_mii_ctrl_wr(struct ag71xx
*ag
, u32 value
)
21 __raw_writel(value
, ag
->mii_ctrl
);
24 static inline u32
ag71xx_mii_ctrl_rr(struct ag71xx
*ag
)
26 return __raw_readl(ag
->mii_ctrl
);
29 void ag71xx_mii_ctrl_set_if(struct ag71xx
*ag
, unsigned int mii_if
)
33 t
= ag71xx_mii_ctrl_rr(ag
);
36 ag71xx_mii_ctrl_wr(ag
, t
);
39 void ag71xx_mii_ctrl_set_speed(struct ag71xx
*ag
, unsigned int speed
)
43 t
= ag71xx_mii_ctrl_rr(ag
);
45 t
|= (speed
& 0x3) << 4;
46 ag71xx_mii_ctrl_wr(ag
, t
);
49 static int ag71xx_mii_read(struct ag71xx
*ag
, int addr
, int reg
)
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
);
60 while (ag71xx_rr(ag
, AG71XX_REG_MII_IND
) & MII_IND_BUSY
) {
62 printk(KERN_ERR
"%s: mii_read timed out\n",
67 udelay(AG71XX_MII_DELAY
);
70 ret
= ag71xx_rr(ag
, AG71XX_REG_MII_STATUS
) & 0xffff;
71 ag71xx_wr(ag
, AG71XX_REG_MII_CMD
, MII_CMD_WRITE
);
73 DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr
, reg
, ret
);
79 static void ag71xx_mii_write(struct ag71xx
*ag
, int addr
, int reg
, u16 val
)
83 DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr
, reg
, val
);
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
);
90 while (ag71xx_rr(ag
, AG71XX_REG_MII_IND
) & MII_IND_BUSY
) {
92 printk(KERN_ERR
"%s: mii_write timed out\n",
96 udelay(AG71XX_MII_DELAY
);
100 int ag71xx_mii_peek(struct ag71xx
*ag
)
106 for (i
= 0; i
< PHY_MAX_ADDR
; i
++) {
107 u16 bmsr
, id1
, id2
, bmcr
, advert
, lpa
;
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",
118 bmsr
, bmcr
, id1
, id2
, advert
, lpa
);
120 if ((bmsr
| bmcr
| id1
| id2
| advert
| lpa
) != 0)
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
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)
136 static void ag71xx_set_pll(struct ag71xx
*ag
, u32 pll_val
)
138 void __iomem
*pll_reg
= ioremap_nocache(ag7100_pll_offset(ag
), 4);
139 void __iomem
*pll_cfg
= ioremap_nocache(PLL_SEC_CONFIG
, 4);
143 s
= ag7100_pll_shift(ag
);
145 t
= __raw_readl(pll_cfg
);
148 __raw_writel(t
, pll_cfg
);
151 __raw_writel(pll_val
, pll_reg
);
154 __raw_writel(t
, pll_cfg
);
158 __raw_writel(t
, pll_cfg
);
160 DBG("%s: pll_reg %#x: %#x\n", ag
->dev
->name
,
161 (unsigned int)pll_reg
, __raw_readl(pll_reg
));
167 static unsigned char *ag71xx_speed_str(struct ag71xx
*ag
)
182 #define PLL_VAL_1000 0x00110000
183 #define PLL_VAL_100 0x00001099
184 #define PLL_VAL_10 0x00991099
186 #define PLL_VAL_1000 0x01111000
187 #define PLL_VAL_100 0x09991000
188 #define PLL_VAL_10 0x09991999
191 void ag71xx_link_update(struct ag71xx
*ag
)
200 netif_carrier_off(ag
->dev
);
201 printk(KERN_INFO
"%s: link down\n", ag
->dev
->name
);
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;
209 ifctl
= ag71xx_rr(ag
, AG71XX_REG_MAC_IFCTL
);
210 ifctl
&= ~(MAC_IFCTL_SPEED
);
212 fifo5
= ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG5
);
213 fifo5
&= ~FIFO_CFG5_BYTE_PER_CLK
;
217 mii_speed
= MII_CTRL_SPEED_1000
;
218 cfg2
|= MAC_CFG2_IF_1000
;
220 fifo5
|= FIFO_CFG5_BYTE_PER_CLK
;
223 mii_speed
= MII_CTRL_SPEED_100
;
224 cfg2
|= MAC_CFG2_IF_10_100
;
225 ifctl
|= MAC_IFCTL_SPEED
;
229 mii_speed
= MII_CTRL_SPEED_10
;
230 cfg2
|= MAC_CFG2_IF_10_100
;
238 ag71xx_wr(ag
, AG71XX_REG_FIFO_CFG3
, 0x008001ff);
239 ag71xx_set_pll(ag
, pll
);
240 ag71xx_mii_ctrl_set_speed(ag
, mii_speed
);
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
);
246 netif_carrier_on(ag
->dev
);
247 printk(KERN_INFO
"%s: link up (%sMbps/%s duplex)\n",
249 ag71xx_speed_str(ag
),
250 (DUPLEX_FULL
== ag
->duplex
) ? "Full" : "Half");
252 DBG("%s: fifo1=%#x, fifo2=%#x, fifo3=%#x, fifo4=%#x, fifo5=%#x\n",
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
));
260 DBG("%s: mac_cfg2=%#x, ifctl=%#x, mii_ctrl=%#x\n",
262 ag71xx_rr(ag
, AG71XX_REG_MAC_CFG2
),
263 ag71xx_rr(ag
, AG71XX_REG_MAC_IFCTL
),
264 ag71xx_mii_ctrl_rr(ag
));
267 static void ag71xx_link_adjust(struct net_device
*dev
)
269 struct ag71xx
*ag
= netdev_priv(dev
);
270 struct phy_device
*phydev
= ag
->phy_dev
;
272 int status_change
= 0;
274 spin_lock_irqsave(&ag
->lock
, flags
);
277 if (ag
->duplex
!= phydev
->duplex
278 || ag
->speed
!= phydev
->speed
) {
283 if (phydev
->link
!= ag
->link
) {
290 ag
->link
= phydev
->link
;
291 ag
->duplex
= phydev
->duplex
;
292 ag
->speed
= phydev
->speed
;
295 ag71xx_link_update(ag
);
297 spin_unlock_irqrestore(&ag
->lock
, flags
);
300 static int ag71xx_mdio_read(struct mii_bus
*bus
, int addr
, int reg
)
302 struct ag71xx
*ag
= bus
->priv
;
304 return ag71xx_mii_read(ag
, addr
, reg
);
307 static int ag71xx_mdio_write(struct mii_bus
*bus
, int addr
, int reg
, u16 val
)
309 struct ag71xx
*ag
= bus
->priv
;
311 ag71xx_mii_write(ag
, addr
, reg
, val
);
315 static int ag71xx_mdio_reset(struct mii_bus
*bus
)
321 static int ag71xx_mdio_probe(struct ag71xx
*ag
)
323 struct net_device
*dev
= ag
->dev
;
324 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
325 struct phy_device
*phydev
= NULL
;
329 for (phy_addr
= 0; phy_addr
< PHY_MAX_ADDR
; phy_addr
++) {
330 if (!(pdata
->phy_mask
& (1 << phy_addr
)))
333 if (ag
->mii_bus
.phy_map
[phy_addr
] == NULL
)
336 DBG("%s: PHY found at %s, uid=%08x\n",
338 ag
->mii_bus
.phy_map
[phy_addr
]->dev
.bus_id
,
339 ag
->mii_bus
.phy_map
[phy_addr
]->phy_id
);
342 phydev
= ag
->mii_bus
.phy_map
[phy_addr
];
349 printk(KERN_ERR
"%s: no PHY found\n", dev
->name
);
352 ag
->phy_dev
= phy_connect(dev
, phydev
->dev
.bus_id
,
353 &ag71xx_link_adjust
, 0, pdata
->phy_if_mode
);
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
);
361 /* mask with MAC supported features */
362 phydev
->supported
&= (SUPPORTED_10baseT_Half
363 | SUPPORTED_10baseT_Full
364 | SUPPORTED_100baseT_Half
365 | SUPPORTED_100baseT_Full
370 phydev
->advertising
= phydev
->supported
;
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
);
383 printk(KERN_DEBUG
"%s: connected to multiple PHYs (%d)\n",
384 dev
->name
, phy_count
);
391 int ag71xx_mdio_init(struct ag71xx
*ag
, int id
)
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
;
401 ag
->mii_bus
.priv
= ag
;
402 ag
->mii_bus
.dev
= &ag
->dev
->dev
;
404 ag
->mii_bus
.irq
= kmalloc(sizeof(*ag
->mii_bus
.irq
) * PHY_MAX_ADDR
,
406 if (!ag
->mii_bus
.irq
) {
411 for (i
= 0; i
< PHY_MAX_ADDR
; i
++)
412 ag
->mii_bus
.irq
[i
] = PHY_POLL
;
414 err
= mdiobus_register(&ag
->mii_bus
);
418 err
= ag71xx_mdio_probe(ag
);
420 goto err_unregister_bus
;
425 mdiobus_unregister(&ag
->mii_bus
);
427 kfree(ag
->mii_bus
.irq
);
432 void ag71xx_mdio_cleanup(struct ag71xx
*ag
)
434 mdiobus_unregister(&ag
->mii_bus
);
435 kfree(ag
->mii_bus
.irq
);
This page took 0.057217 seconds and 3 git commands to generate.