2 * Atheros AR71xx built-in ethernet mac driver
4 * Copyright (C) 2008-2009 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 static unsigned char *ag71xx_speed_str(struct ag71xx
*ag
)
30 #define AR71XX_PLL_VAL_1000 0x00110000
31 #define AR71XX_PLL_VAL_100 0x00001099
32 #define AR71XX_PLL_VAL_10 0x00991099
34 #define AR91XX_PLL_VAL_1000 0x1a000000
35 #define AR91XX_PLL_VAL_100 0x13000a44
36 #define AR91XX_PLL_VAL_10 0x00441099
38 static void ag71xx_phy_link_update(struct ag71xx
*ag
)
40 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
48 netif_carrier_off(ag
->dev
);
49 if (netif_msg_link(ag
))
50 printk(KERN_INFO
"%s: link down\n", ag
->dev
->name
);
54 cfg2
= ag71xx_rr(ag
, AG71XX_REG_MAC_CFG2
);
55 cfg2
&= ~(MAC_CFG2_IF_1000
| MAC_CFG2_IF_10_100
| MAC_CFG2_FDX
);
56 cfg2
|= (ag
->duplex
) ? MAC_CFG2_FDX
: 0;
58 ifctl
= ag71xx_rr(ag
, AG71XX_REG_MAC_IFCTL
);
59 ifctl
&= ~(MAC_IFCTL_SPEED
);
61 fifo5
= ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG5
);
62 fifo5
&= ~FIFO_CFG5_BM
;
66 mii_speed
= MII_CTRL_SPEED_1000
;
67 cfg2
|= MAC_CFG2_IF_1000
;
68 pll
= pdata
->is_ar91xx
? AR91XX_PLL_VAL_1000
69 : AR71XX_PLL_VAL_1000
;
70 fifo5
|= FIFO_CFG5_BM
;
73 mii_speed
= MII_CTRL_SPEED_100
;
74 cfg2
|= MAC_CFG2_IF_10_100
;
75 ifctl
|= MAC_IFCTL_SPEED
;
76 pll
= pdata
->is_ar91xx
? AR91XX_PLL_VAL_100
80 mii_speed
= MII_CTRL_SPEED_10
;
81 cfg2
|= MAC_CFG2_IF_10_100
;
82 pll
= pdata
->is_ar91xx
? AR91XX_PLL_VAL_10
90 ag71xx_wr(ag
, AG71XX_REG_FIFO_CFG3
,
91 pdata
->is_ar91xx
? 0x780fff : 0x008001ff);
93 ag71xx_mii_ctrl_set_speed(ag
, mii_speed
);
95 ag71xx_wr(ag
, AG71XX_REG_MAC_CFG2
, cfg2
);
96 ag71xx_wr(ag
, AG71XX_REG_FIFO_CFG5
, fifo5
);
97 ag71xx_wr(ag
, AG71XX_REG_MAC_IFCTL
, ifctl
);
99 netif_carrier_on(ag
->dev
);
100 if (netif_msg_link(ag
))
101 printk(KERN_INFO
"%s: link up (%sMbps/%s duplex)\n",
103 ag71xx_speed_str(ag
),
104 (DUPLEX_FULL
== ag
->duplex
) ? "Full" : "Half");
106 DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n",
108 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG0
),
109 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG1
),
110 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG2
));
112 DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n",
114 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG3
),
115 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG4
),
116 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG5
));
118 DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x, mii_ctrl=%#x\n",
120 ag71xx_rr(ag
, AG71XX_REG_MAC_CFG2
),
121 ag71xx_rr(ag
, AG71XX_REG_MAC_IFCTL
),
122 ag71xx_mii_ctrl_rr(ag
));
125 static void ag71xx_phy_link_adjust(struct net_device
*dev
)
127 struct ag71xx
*ag
= netdev_priv(dev
);
128 struct phy_device
*phydev
= ag
->phy_dev
;
130 int status_change
= 0;
132 spin_lock_irqsave(&ag
->lock
, flags
);
135 if (ag
->duplex
!= phydev
->duplex
136 || ag
->speed
!= phydev
->speed
) {
141 if (phydev
->link
!= ag
->link
)
144 ag
->link
= phydev
->link
;
145 ag
->duplex
= phydev
->duplex
;
146 ag
->speed
= phydev
->speed
;
149 ag71xx_phy_link_update(ag
);
151 spin_unlock_irqrestore(&ag
->lock
, flags
);
154 void ag71xx_phy_start(struct ag71xx
*ag
)
157 phy_start(ag
->phy_dev
);
159 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
161 ag
->duplex
= pdata
->duplex
;
162 ag
->speed
= pdata
->speed
;
164 ag71xx_phy_link_update(ag
);
168 void ag71xx_phy_stop(struct ag71xx
*ag
)
171 phy_stop(ag
->phy_dev
);
176 ag71xx_phy_link_update(ag
);
180 static int ag71xx_phy_connect_fixed(struct ag71xx
*ag
)
182 struct net_device
*dev
= ag
->dev
;
183 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
186 /* use fixed settings */
187 switch (pdata
->speed
) {
193 printk(KERN_ERR
"%s: invalid speed specified\n",
202 static int ag71xx_phy_connect_multi(struct ag71xx
*ag
)
204 struct net_device
*dev
= ag
->dev
;
205 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
206 struct phy_device
*phydev
= NULL
;
211 for (phy_addr
= 0; phy_addr
< PHY_MAX_ADDR
; phy_addr
++) {
212 if (!(pdata
->phy_mask
& (1 << phy_addr
)))
215 if (ag
->mii_bus
->phy_map
[phy_addr
] == NULL
)
218 DBG("%s: PHY found at %s, uid=%08x\n",
220 ag
->mii_bus
->phy_map
[phy_addr
]->dev
.bus_id
,
221 ag
->mii_bus
->phy_map
[phy_addr
]->phy_id
);
224 phydev
= ag
->mii_bus
->phy_map
[phy_addr
];
231 printk(KERN_ERR
"%s: no PHY found with phy_mask=%08x\n",
232 dev
->name
, pdata
->phy_mask
);
236 ag
->phy_dev
= phy_connect(dev
, phydev
->dev
.bus_id
,
237 &ag71xx_phy_link_adjust
, 0, pdata
->phy_if_mode
);
239 if (IS_ERR(ag
->phy_dev
)) {
240 printk(KERN_ERR
"%s: could not connect to PHY at %s\n",
241 dev
->name
, phydev
->dev
.bus_id
);
242 return PTR_ERR(ag
->phy_dev
);
245 /* mask with MAC supported features */
247 phydev
->supported
&= PHY_GBIT_FEATURES
;
249 phydev
->supported
&= PHY_BASIC_FEATURES
;
251 phydev
->advertising
= phydev
->supported
;
253 printk(KERN_DEBUG
"%s: connected to PHY at %s "
254 "[uid=%08x, driver=%s]\n",
255 dev
->name
, phydev
->dev
.bus_id
,
256 phydev
->phy_id
, phydev
->drv
->name
);
264 printk(KERN_DEBUG
"%s: connected to %d PHYs\n",
265 dev
->name
, phy_count
);
266 ret
= ag71xx_phy_connect_fixed(ag
);
273 int ag71xx_phy_connect(struct ag71xx
*ag
)
275 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
278 return ag71xx_phy_connect_multi(ag
);
280 return ag71xx_phy_connect_fixed(ag
);
283 void ag71xx_phy_disconnect(struct ag71xx
*ag
)
286 phy_disconnect(ag
->phy_dev
);
This page took 0.061645 seconds and 5 git commands to generate.