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 PLL_SEC_CONFIG 0x18050004
17 #define PLL_ETH0_INT_CLOCK 0x18050010
18 #define PLL_ETH1_INT_CLOCK 0x18050014
19 #define PLL_ETH_EXT_CLOCK 0x18050018
21 #define ag71xx_pll_shift(_ag) (((_ag)->pdev->id) ? 19 : 17)
22 #define ag71xx_pll_offset(_ag) (((_ag)->pdev->id) ? PLL_ETH1_INT_CLOCK \
25 static void ag71xx_set_pll(struct ag71xx
*ag
, u32 pll_val
)
27 void __iomem
*pll_reg
= ioremap_nocache(ag71xx_pll_offset(ag
), 4);
28 void __iomem
*pll_cfg
= ioremap_nocache(PLL_SEC_CONFIG
, 4);
32 s
= ag71xx_pll_shift(ag
);
34 t
= __raw_readl(pll_cfg
);
37 __raw_writel(t
, pll_cfg
);
40 __raw_writel(pll_val
, pll_reg
);
43 __raw_writel(t
, pll_cfg
);
47 __raw_writel(t
, pll_cfg
);
49 DBG("%s: pll_reg %#x: %#x\n", ag
->dev
->name
,
50 (unsigned int)pll_reg
, __raw_readl(pll_reg
));
56 static unsigned char *ag71xx_speed_str(struct ag71xx
*ag
)
71 #define PLL_VAL_1000 0x00110000
72 #define PLL_VAL_100 0x00001099
73 #define PLL_VAL_10 0x00991099
75 #define PLL_VAL_1000 0x01111000
76 #define PLL_VAL_100 0x09991000
77 #define PLL_VAL_10 0x09991999
80 static void ag71xx_phy_link_update(struct ag71xx
*ag
)
89 netif_carrier_off(ag
->dev
);
90 if (netif_msg_link(ag
))
91 printk(KERN_INFO
"%s: link down\n", ag
->dev
->name
);
95 cfg2
= ag71xx_rr(ag
, AG71XX_REG_MAC_CFG2
);
96 cfg2
&= ~(MAC_CFG2_IF_1000
| MAC_CFG2_IF_10_100
| MAC_CFG2_FDX
);
97 cfg2
|= (ag
->duplex
) ? MAC_CFG2_FDX
: 0;
99 ifctl
= ag71xx_rr(ag
, AG71XX_REG_MAC_IFCTL
);
100 ifctl
&= ~(MAC_IFCTL_SPEED
);
102 fifo5
= ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG5
);
103 fifo5
&= ~FIFO_CFG5_BYTE_PER_CLK
;
107 mii_speed
= MII_CTRL_SPEED_1000
;
108 cfg2
|= MAC_CFG2_IF_1000
;
110 fifo5
|= FIFO_CFG5_BYTE_PER_CLK
;
113 mii_speed
= MII_CTRL_SPEED_100
;
114 cfg2
|= MAC_CFG2_IF_10_100
;
115 ifctl
|= MAC_IFCTL_SPEED
;
119 mii_speed
= MII_CTRL_SPEED_10
;
120 cfg2
|= MAC_CFG2_IF_10_100
;
128 ag71xx_wr(ag
, AG71XX_REG_FIFO_CFG3
, 0x008001ff);
129 ag71xx_set_pll(ag
, pll
);
130 ag71xx_mii_ctrl_set_speed(ag
, mii_speed
);
132 ag71xx_wr(ag
, AG71XX_REG_MAC_CFG2
, cfg2
);
133 ag71xx_wr(ag
, AG71XX_REG_FIFO_CFG5
, fifo5
);
134 ag71xx_wr(ag
, AG71XX_REG_MAC_IFCTL
, ifctl
);
136 netif_carrier_on(ag
->dev
);
137 if (netif_msg_link(ag
))
138 printk(KERN_INFO
"%s: link up (%sMbps/%s duplex)\n",
140 ag71xx_speed_str(ag
),
141 (DUPLEX_FULL
== ag
->duplex
) ? "Full" : "Half");
143 DBG("%s: fifo1=%#x, fifo2=%#x, fifo3=%#x, fifo4=%#x, fifo5=%#x\n",
145 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG1
),
146 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG2
),
147 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG3
),
148 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG4
),
149 ag71xx_rr(ag
, AG71XX_REG_FIFO_CFG5
));
151 DBG("%s: mac_cfg2=%#x, ifctl=%#x, mii_ctrl=%#x\n",
153 ag71xx_rr(ag
, AG71XX_REG_MAC_CFG2
),
154 ag71xx_rr(ag
, AG71XX_REG_MAC_IFCTL
),
155 ag71xx_mii_ctrl_rr(ag
));
158 static void ag71xx_phy_link_adjust(struct net_device
*dev
)
160 struct ag71xx
*ag
= netdev_priv(dev
);
161 struct phy_device
*phydev
= ag
->phy_dev
;
163 int status_change
= 0;
165 spin_lock_irqsave(&ag
->lock
, flags
);
168 if (ag
->duplex
!= phydev
->duplex
169 || ag
->speed
!= phydev
->speed
) {
174 if (phydev
->link
!= ag
->link
) {
181 ag
->link
= phydev
->link
;
182 ag
->duplex
= phydev
->duplex
;
183 ag
->speed
= phydev
->speed
;
186 ag71xx_phy_link_update(ag
);
188 spin_unlock_irqrestore(&ag
->lock
, flags
);
191 void ag71xx_phy_start(struct ag71xx
*ag
)
194 phy_start(ag
->phy_dev
);
196 ag
->duplex
= DUPLEX_FULL
;
197 ag
->speed
= SPEED_100
;
199 ag71xx_phy_link_update(ag
);
203 void ag71xx_phy_stop(struct ag71xx
*ag
)
206 phy_stop(ag
->phy_dev
);
211 ag71xx_phy_link_update(ag
);
215 int ag71xx_phy_connect(struct ag71xx
*ag
)
217 struct net_device
*dev
= ag
->dev
;
218 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
219 struct phy_device
*phydev
= NULL
;
224 /* TODO: use mutex of the mdio bus */
225 for (phy_addr
= 0; phy_addr
< PHY_MAX_ADDR
; phy_addr
++) {
226 if (!(pdata
->phy_mask
& (1 << phy_addr
)))
229 if (ag
->mii_bus
->phy_map
[phy_addr
] == NULL
)
232 DBG("%s: PHY found at %s, uid=%08x\n",
234 ag
->mii_bus
->phy_map
[phy_addr
]->dev
.bus_id
,
235 ag
->mii_bus
->phy_map
[phy_addr
]->phy_id
);
238 phydev
= ag
->mii_bus
->phy_map
[phy_addr
];
246 printk(KERN_ERR
"%s: no PHY found\n", dev
->name
);
249 ag
->phy_dev
= phy_connect(dev
, phydev
->dev
.bus_id
,
250 &ag71xx_phy_link_adjust
, 0, pdata
->phy_if_mode
);
252 if (IS_ERR(ag
->phy_dev
)) {
253 printk(KERN_ERR
"%s: could not connect to PHY at %s\n",
254 dev
->name
, phydev
->dev
.bus_id
);
255 return PTR_ERR(ag
->phy_dev
);
258 /* mask with MAC supported features */
259 phydev
->supported
&= (SUPPORTED_10baseT_Half
260 | SUPPORTED_10baseT_Full
261 | SUPPORTED_100baseT_Half
262 | SUPPORTED_100baseT_Full
267 phydev
->advertising
= phydev
->supported
;
269 printk(KERN_DEBUG
"%s: connected to PHY at %s "
270 "[uid=%08x, driver=%s]\n",
271 dev
->name
, phydev
->dev
.bus_id
,
272 phydev
->phy_id
, phydev
->drv
->name
);
280 printk(KERN_DEBUG
"%s: connected to multiple PHYs (%d)\n",
281 dev
->name
, phy_count
);
288 void ag71xx_phy_disconnect(struct ag71xx
*ag
)
291 phy_disconnect(ag
->phy_dev
);
This page took 0.052445 seconds and 5 git commands to generate.