cxgb_ael1002.c revision 176472
1167514Skmacy/**************************************************************************
2167514Skmacy
3167514SkmacyCopyright (c) 2007, Chelsio Inc.
4167514SkmacyAll rights reserved.
5167514Skmacy
6167514SkmacyRedistribution and use in source and binary forms, with or without
7167514Skmacymodification, are permitted provided that the following conditions are met:
8167514Skmacy
9167514Skmacy 1. Redistributions of source code must retain the above copyright notice,
10167514Skmacy    this list of conditions and the following disclaimer.
11167514Skmacy
12170076Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13167514Skmacy    contributors may be used to endorse or promote products derived from
14167514Skmacy    this software without specific prior written permission.
15167514Skmacy
16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26167514SkmacyPOSSIBILITY OF SUCH DAMAGE.
27167514Skmacy
28167514Skmacy***************************************************************************/
29167514Skmacy
30167514Skmacy#include <sys/cdefs.h>
31167514Skmacy__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_ael1002.c 176472 2008-02-23 01:06:17Z kmacy $");
32167514Skmacy
33170076Skmacy#ifdef CONFIG_DEFINED
34170076Skmacy#include <cxgb_include.h>
35170076Skmacy#else
36170076Skmacy#include <dev/cxgb/cxgb_include.h>
37170076Skmacy#endif
38167514Skmacy
39176472Skmacy#undef msleep
40176472Skmacy#define msleep t3_os_sleep
41176472Skmacy
42167514Skmacyenum {
43167514Skmacy	AEL100X_TX_DISABLE  = 9,
44167514Skmacy	AEL100X_TX_CONFIG1  = 0xc002,
45167514Skmacy	AEL1002_PWR_DOWN_HI = 0xc011,
46167514Skmacy	AEL1002_PWR_DOWN_LO = 0xc012,
47167514Skmacy	AEL1002_XFI_EQL     = 0xc015,
48167514Skmacy	AEL1002_LB_EN       = 0xc017,
49167514Skmacy
50167514Skmacy	LASI_CTRL   = 0x9002,
51167514Skmacy	LASI_STAT   = 0x9005
52167514Skmacy};
53167514Skmacy
54167514Skmacystatic void ael100x_txon(struct cphy *phy)
55167514Skmacy{
56167514Skmacy	int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
57167514Skmacy
58176472Skmacy	msleep(100);
59167514Skmacy	t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
60176472Skmacy	msleep(30);
61167514Skmacy}
62167514Skmacy
63167514Skmacystatic int ael1002_power_down(struct cphy *phy, int enable)
64167514Skmacy{
65167514Skmacy	int err;
66167514Skmacy
67167514Skmacy	err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
68167514Skmacy	if (!err)
69167514Skmacy		err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
70167514Skmacy					  BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
71167514Skmacy	return err;
72167514Skmacy}
73167514Skmacy
74167514Skmacystatic int ael1002_reset(struct cphy *phy, int wait)
75167514Skmacy{
76167514Skmacy	int err;
77167514Skmacy
78167514Skmacy	if ((err = ael1002_power_down(phy, 0)) ||
79167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
80167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
81167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
82167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
83167514Skmacy	    (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
84167514Skmacy				       0, 1 << 5)))
85167514Skmacy		return err;
86167514Skmacy	return 0;
87167514Skmacy}
88167514Skmacy
89167514Skmacystatic int ael1002_intr_noop(struct cphy *phy)
90167514Skmacy{
91167514Skmacy	return 0;
92167514Skmacy}
93167514Skmacy
94167514Skmacystatic int ael100x_get_link_status(struct cphy *phy, int *link_ok,
95167514Skmacy				   int *speed, int *duplex, int *fc)
96167514Skmacy{
97167514Skmacy	if (link_ok) {
98167514Skmacy		unsigned int status;
99167514Skmacy		int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
100167514Skmacy
101167514Skmacy		/*
102167514Skmacy		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
103167514Skmacy		 * once more to get the current link state.
104167514Skmacy		 */
105167514Skmacy		if (!err && !(status & BMSR_LSTATUS))
106167514Skmacy			err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
107167514Skmacy					&status);
108167514Skmacy		if (err)
109167514Skmacy			return err;
110167514Skmacy		*link_ok = !!(status & BMSR_LSTATUS);
111167514Skmacy	}
112167514Skmacy	if (speed)
113167514Skmacy		*speed = SPEED_10000;
114167514Skmacy	if (duplex)
115167514Skmacy		*duplex = DUPLEX_FULL;
116167514Skmacy	return 0;
117167514Skmacy}
118167514Skmacy
119167514Skmacy#ifdef C99_NOT_SUPPORTED
120167514Skmacystatic struct cphy_ops ael1002_ops = {
121167514Skmacy	ael1002_reset,
122167514Skmacy	ael1002_intr_noop,
123167514Skmacy	ael1002_intr_noop,
124167514Skmacy	ael1002_intr_noop,
125167514Skmacy	ael1002_intr_noop,
126167514Skmacy	NULL,
127167514Skmacy	NULL,
128167514Skmacy	NULL,
129167514Skmacy	NULL,
130167514Skmacy	NULL,
131167514Skmacy	ael100x_get_link_status,
132167514Skmacy	ael1002_power_down,
133167514Skmacy};
134167514Skmacy#else
135167514Skmacystatic struct cphy_ops ael1002_ops = {
136167514Skmacy	.reset           = ael1002_reset,
137167514Skmacy	.intr_enable     = ael1002_intr_noop,
138167514Skmacy	.intr_disable    = ael1002_intr_noop,
139167514Skmacy	.intr_clear      = ael1002_intr_noop,
140167514Skmacy	.intr_handler    = ael1002_intr_noop,
141167514Skmacy	.get_link_status = ael100x_get_link_status,
142167514Skmacy	.power_down      = ael1002_power_down,
143167514Skmacy};
144167514Skmacy#endif
145167514Skmacy
146176472Skmacyint t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
147176472Skmacy			const struct mdio_ops *mdio_ops)
148167514Skmacy{
149176472Skmacy	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
150176472Skmacy		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
151176472Skmacy		  "10GBASE-XR");
152167514Skmacy	ael100x_txon(phy);
153176472Skmacy	return 0;
154167514Skmacy}
155167514Skmacy
156167514Skmacystatic int ael1006_reset(struct cphy *phy, int wait)
157167514Skmacy{
158167514Skmacy	return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
159167514Skmacy}
160167514Skmacy
161167514Skmacystatic int ael1006_intr_enable(struct cphy *phy)
162167514Skmacy{
163167514Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
164167514Skmacy}
165167514Skmacy
166167514Skmacystatic int ael1006_intr_disable(struct cphy *phy)
167167514Skmacy{
168167514Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
169167514Skmacy}
170167514Skmacy
171167514Skmacystatic int ael1006_intr_clear(struct cphy *phy)
172167514Skmacy{
173167514Skmacy	u32 val;
174167514Skmacy
175167514Skmacy	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
176167514Skmacy}
177167514Skmacy
178167514Skmacystatic int ael1006_intr_handler(struct cphy *phy)
179167514Skmacy{
180167514Skmacy	unsigned int status;
181167514Skmacy	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
182167514Skmacy
183167514Skmacy	if (err)
184167514Skmacy		return err;
185167514Skmacy	return (status & 1) ?  cphy_cause_link_change : 0;
186167514Skmacy}
187167514Skmacy
188167514Skmacystatic int ael1006_power_down(struct cphy *phy, int enable)
189167514Skmacy{
190167514Skmacy	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
191167514Skmacy				   BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
192167514Skmacy}
193167514Skmacy
194167514Skmacy#ifdef C99_NOT_SUPPORTED
195167514Skmacystatic struct cphy_ops ael1006_ops = {
196167514Skmacy	ael1006_reset,
197167514Skmacy	ael1006_intr_enable,
198167514Skmacy	ael1006_intr_disable,
199167514Skmacy	ael1006_intr_clear,
200167514Skmacy	ael1006_intr_handler,
201167514Skmacy	NULL,
202167514Skmacy	NULL,
203167514Skmacy	NULL,
204167514Skmacy	NULL,
205167514Skmacy	NULL,
206167514Skmacy	ael100x_get_link_status,
207167514Skmacy	ael1006_power_down,
208167514Skmacy};
209167514Skmacy#else
210167514Skmacystatic struct cphy_ops ael1006_ops = {
211167514Skmacy	.reset           = ael1006_reset,
212167514Skmacy	.intr_enable     = ael1006_intr_enable,
213167514Skmacy	.intr_disable    = ael1006_intr_disable,
214167514Skmacy	.intr_clear      = ael1006_intr_clear,
215167514Skmacy	.intr_handler    = ael1006_intr_handler,
216167514Skmacy	.get_link_status = ael100x_get_link_status,
217167514Skmacy	.power_down      = ael1006_power_down,
218167514Skmacy};
219167514Skmacy#endif
220167514Skmacy
221176472Skmacyint t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
222176472Skmacy			const struct mdio_ops *mdio_ops)
223167514Skmacy{
224176472Skmacy	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
225176472Skmacy		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
226176472Skmacy		  "10GBASE-SR");
227167514Skmacy	ael100x_txon(phy);
228176472Skmacy	return 0;
229167514Skmacy}
230167514Skmacy
231167514Skmacy#ifdef C99_NOT_SUPPORTED
232167514Skmacystatic struct cphy_ops qt2045_ops = {
233167514Skmacy	ael1006_reset,
234167514Skmacy	ael1006_intr_enable,
235167514Skmacy	ael1006_intr_disable,
236167514Skmacy	ael1006_intr_clear,
237167514Skmacy	ael1006_intr_handler,
238167514Skmacy	NULL,
239167514Skmacy	NULL,
240167514Skmacy	NULL,
241167514Skmacy	NULL,
242167514Skmacy	NULL,
243167514Skmacy	ael100x_get_link_status,
244167514Skmacy	ael1006_power_down,
245167514Skmacy};
246167514Skmacy#else
247167514Skmacystatic struct cphy_ops qt2045_ops = {
248167514Skmacy	.reset           = ael1006_reset,
249167514Skmacy	.intr_enable     = ael1006_intr_enable,
250167514Skmacy	.intr_disable    = ael1006_intr_disable,
251167514Skmacy	.intr_clear      = ael1006_intr_clear,
252167514Skmacy	.intr_handler    = ael1006_intr_handler,
253167514Skmacy	.get_link_status = ael100x_get_link_status,
254167514Skmacy	.power_down      = ael1006_power_down,
255167514Skmacy};
256167514Skmacy#endif
257167514Skmacy
258176472Skmacyint t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
259176472Skmacy		       const struct mdio_ops *mdio_ops)
260167514Skmacy{
261167514Skmacy	unsigned int stat;
262167514Skmacy
263176472Skmacy	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
264176472Skmacy		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
265176472Skmacy		  "10GBASE-CX4");
266167514Skmacy
267167514Skmacy	/*
268167514Skmacy	 * Some cards where the PHY is supposed to be at address 0 actually
269167514Skmacy	 * have it at 1.
270167514Skmacy	 */
271167514Skmacy	if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
272167514Skmacy	    stat == 0xffff)
273167514Skmacy		phy->addr = 1;
274176472Skmacy	return 0;
275167514Skmacy}
276167514Skmacy
277167514Skmacystatic int xaui_direct_reset(struct cphy *phy, int wait)
278167514Skmacy{
279167514Skmacy	return 0;
280167514Skmacy}
281167514Skmacy
282167514Skmacystatic int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
283167514Skmacy				       int *speed, int *duplex, int *fc)
284167514Skmacy{
285167514Skmacy	if (link_ok) {
286167514Skmacy		unsigned int status;
287167514Skmacy
288167514Skmacy		status = t3_read_reg(phy->adapter,
289170654Skmacy				     XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) |
290170654Skmacy			 t3_read_reg(phy->adapter,
291170654Skmacy				     XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) |
292170654Skmacy			 t3_read_reg(phy->adapter,
293170654Skmacy				     XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) |
294170654Skmacy			 t3_read_reg(phy->adapter,
295170654Skmacy				     XGM_REG(A_XGM_SERDES_STAT3, phy->addr));
296167514Skmacy		*link_ok = !(status & F_LOWSIG0);
297167514Skmacy	}
298167514Skmacy	if (speed)
299167514Skmacy		*speed = SPEED_10000;
300167514Skmacy	if (duplex)
301167514Skmacy		*duplex = DUPLEX_FULL;
302167514Skmacy	return 0;
303167514Skmacy}
304167514Skmacy
305167514Skmacystatic int xaui_direct_power_down(struct cphy *phy, int enable)
306167514Skmacy{
307167514Skmacy	return 0;
308167514Skmacy}
309167514Skmacy
310167514Skmacy#ifdef C99_NOT_SUPPORTED
311167514Skmacystatic struct cphy_ops xaui_direct_ops = {
312167514Skmacy	xaui_direct_reset,
313167514Skmacy	ael1002_intr_noop,
314167514Skmacy	ael1002_intr_noop,
315167514Skmacy	ael1002_intr_noop,
316167514Skmacy	ael1002_intr_noop,
317167514Skmacy	NULL,
318167514Skmacy	NULL,
319167514Skmacy	NULL,
320167514Skmacy	NULL,
321167514Skmacy	NULL,
322167514Skmacy	xaui_direct_get_link_status,
323167514Skmacy	xaui_direct_power_down,
324167514Skmacy};
325167514Skmacy#else
326167514Skmacystatic struct cphy_ops xaui_direct_ops = {
327167514Skmacy	.reset           = xaui_direct_reset,
328167514Skmacy	.intr_enable     = ael1002_intr_noop,
329167514Skmacy	.intr_disable    = ael1002_intr_noop,
330167514Skmacy	.intr_clear      = ael1002_intr_noop,
331167514Skmacy	.intr_handler    = ael1002_intr_noop,
332167514Skmacy	.get_link_status = xaui_direct_get_link_status,
333167514Skmacy	.power_down      = xaui_direct_power_down,
334167514Skmacy};
335167514Skmacy#endif
336167514Skmacy
337176472Skmacyint t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
338176472Skmacy			    const struct mdio_ops *mdio_ops)
339167514Skmacy{
340176472Skmacy	cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
341176472Skmacy		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
342176472Skmacy		  "10GBASE-CX4");
343176472Skmacy	return 0;
344167514Skmacy}
345