cxgb_ael1002.c revision 170076
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 170076 2007-05-28 22:57:27Z kmacy $");
32167514Skmacy
33170076Skmacy#ifdef CONFIG_DEFINED
34170076Skmacy#include <cxgb_include.h>
35170076Skmacy#else
36170076Skmacy#include <dev/cxgb/cxgb_include.h>
37170076Skmacy#endif
38167514Skmacy
39167514Skmacyenum {
40167514Skmacy	AEL100X_TX_DISABLE  = 9,
41167514Skmacy	AEL100X_TX_CONFIG1  = 0xc002,
42167514Skmacy	AEL1002_PWR_DOWN_HI = 0xc011,
43167514Skmacy	AEL1002_PWR_DOWN_LO = 0xc012,
44167514Skmacy	AEL1002_XFI_EQL     = 0xc015,
45167514Skmacy	AEL1002_LB_EN       = 0xc017,
46167514Skmacy
47167514Skmacy	LASI_CTRL   = 0x9002,
48167514Skmacy	LASI_STAT   = 0x9005
49167514Skmacy};
50167514Skmacy
51167514Skmacystatic void ael100x_txon(struct cphy *phy)
52167514Skmacy{
53167514Skmacy	int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
54167514Skmacy
55167514Skmacy	t3_os_sleep(100);
56167514Skmacy	t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
57167514Skmacy	t3_os_sleep(30);
58167514Skmacy}
59167514Skmacy
60167514Skmacystatic int ael1002_power_down(struct cphy *phy, int enable)
61167514Skmacy{
62167514Skmacy	int err;
63167514Skmacy
64167514Skmacy	err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
65167514Skmacy	if (!err)
66167514Skmacy		err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
67167514Skmacy					  BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
68167514Skmacy	return err;
69167514Skmacy}
70167514Skmacy
71167514Skmacystatic int ael1002_reset(struct cphy *phy, int wait)
72167514Skmacy{
73167514Skmacy	int err;
74167514Skmacy
75167514Skmacy	if ((err = ael1002_power_down(phy, 0)) ||
76167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
77167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
78167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
79167514Skmacy	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
80167514Skmacy	    (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
81167514Skmacy				       0, 1 << 5)))
82167514Skmacy		return err;
83167514Skmacy	return 0;
84167514Skmacy}
85167514Skmacy
86167514Skmacystatic int ael1002_intr_noop(struct cphy *phy)
87167514Skmacy{
88167514Skmacy	return 0;
89167514Skmacy}
90167514Skmacy
91167514Skmacystatic int ael100x_get_link_status(struct cphy *phy, int *link_ok,
92167514Skmacy				   int *speed, int *duplex, int *fc)
93167514Skmacy{
94167514Skmacy	if (link_ok) {
95167514Skmacy		unsigned int status;
96167514Skmacy		int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
97167514Skmacy
98167514Skmacy		/*
99167514Skmacy		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
100167514Skmacy		 * once more to get the current link state.
101167514Skmacy		 */
102167514Skmacy		if (!err && !(status & BMSR_LSTATUS))
103167514Skmacy			err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
104167514Skmacy					&status);
105167514Skmacy		if (err)
106167514Skmacy			return err;
107167514Skmacy		*link_ok = !!(status & BMSR_LSTATUS);
108167514Skmacy	}
109167514Skmacy	if (speed)
110167514Skmacy		*speed = SPEED_10000;
111167514Skmacy	if (duplex)
112167514Skmacy		*duplex = DUPLEX_FULL;
113167514Skmacy	return 0;
114167514Skmacy}
115167514Skmacy
116167514Skmacy#ifdef C99_NOT_SUPPORTED
117167514Skmacystatic struct cphy_ops ael1002_ops = {
118167514Skmacy	NULL,
119167514Skmacy	ael1002_reset,
120167514Skmacy	ael1002_intr_noop,
121167514Skmacy	ael1002_intr_noop,
122167514Skmacy	ael1002_intr_noop,
123167514Skmacy	ael1002_intr_noop,
124167514Skmacy	NULL,
125167514Skmacy	NULL,
126167514Skmacy	NULL,
127167514Skmacy	NULL,
128167514Skmacy	NULL,
129167514Skmacy	ael100x_get_link_status,
130167514Skmacy	ael1002_power_down,
131167514Skmacy};
132167514Skmacy#else
133167514Skmacystatic struct cphy_ops ael1002_ops = {
134167514Skmacy	.reset           = ael1002_reset,
135167514Skmacy	.intr_enable     = ael1002_intr_noop,
136167514Skmacy	.intr_disable    = ael1002_intr_noop,
137167514Skmacy	.intr_clear      = ael1002_intr_noop,
138167514Skmacy	.intr_handler    = ael1002_intr_noop,
139167514Skmacy	.get_link_status = ael100x_get_link_status,
140167514Skmacy	.power_down      = ael1002_power_down,
141167514Skmacy};
142167514Skmacy#endif
143167514Skmacy
144167514Skmacyvoid t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
145167514Skmacy			 const struct mdio_ops *mdio_ops)
146167514Skmacy{
147167514Skmacy	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
148167514Skmacy	ael100x_txon(phy);
149167514Skmacy}
150167514Skmacy
151167514Skmacystatic int ael1006_reset(struct cphy *phy, int wait)
152167514Skmacy{
153167514Skmacy	return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
154167514Skmacy}
155167514Skmacy
156167514Skmacystatic int ael1006_intr_enable(struct cphy *phy)
157167514Skmacy{
158167514Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
159167514Skmacy}
160167514Skmacy
161167514Skmacystatic int ael1006_intr_disable(struct cphy *phy)
162167514Skmacy{
163167514Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
164167514Skmacy}
165167514Skmacy
166167514Skmacystatic int ael1006_intr_clear(struct cphy *phy)
167167514Skmacy{
168167514Skmacy	u32 val;
169167514Skmacy
170167514Skmacy	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
171167514Skmacy}
172167514Skmacy
173167514Skmacystatic int ael1006_intr_handler(struct cphy *phy)
174167514Skmacy{
175167514Skmacy	unsigned int status;
176167514Skmacy	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
177167514Skmacy
178167514Skmacy	if (err)
179167514Skmacy		return err;
180167514Skmacy	return (status & 1) ?  cphy_cause_link_change : 0;
181167514Skmacy}
182167514Skmacy
183167514Skmacystatic int ael1006_power_down(struct cphy *phy, int enable)
184167514Skmacy{
185167514Skmacy	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
186167514Skmacy				   BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
187167514Skmacy}
188167514Skmacy
189167514Skmacy#ifdef C99_NOT_SUPPORTED
190167514Skmacystatic struct cphy_ops ael1006_ops = {
191167514Skmacy	NULL,
192167514Skmacy	ael1006_reset,
193167514Skmacy	ael1006_intr_enable,
194167514Skmacy	ael1006_intr_disable,
195167514Skmacy	ael1006_intr_clear,
196167514Skmacy	ael1006_intr_handler,
197167514Skmacy	NULL,
198167514Skmacy	NULL,
199167514Skmacy	NULL,
200167514Skmacy	NULL,
201167514Skmacy	NULL,
202167514Skmacy	ael100x_get_link_status,
203167514Skmacy	ael1006_power_down,
204167514Skmacy};
205167514Skmacy#else
206167514Skmacystatic struct cphy_ops ael1006_ops = {
207167514Skmacy	.reset           = ael1006_reset,
208167514Skmacy	.intr_enable     = ael1006_intr_enable,
209167514Skmacy	.intr_disable    = ael1006_intr_disable,
210167514Skmacy	.intr_clear      = ael1006_intr_clear,
211167514Skmacy	.intr_handler    = ael1006_intr_handler,
212167514Skmacy	.get_link_status = ael100x_get_link_status,
213167514Skmacy	.power_down      = ael1006_power_down,
214167514Skmacy};
215167514Skmacy#endif
216167514Skmacy
217167514Skmacyvoid t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
218167514Skmacy			 const struct mdio_ops *mdio_ops)
219167514Skmacy{
220167514Skmacy	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
221167514Skmacy	ael100x_txon(phy);
222167514Skmacy}
223167514Skmacy
224167514Skmacy#ifdef C99_NOT_SUPPORTED
225167514Skmacystatic struct cphy_ops qt2045_ops = {
226167514Skmacy	NULL,
227167514Skmacy	ael1006_reset,
228167514Skmacy	ael1006_intr_enable,
229167514Skmacy	ael1006_intr_disable,
230167514Skmacy	ael1006_intr_clear,
231167514Skmacy	ael1006_intr_handler,
232167514Skmacy	NULL,
233167514Skmacy	NULL,
234167514Skmacy	NULL,
235167514Skmacy	NULL,
236167514Skmacy	NULL,
237167514Skmacy	ael100x_get_link_status,
238167514Skmacy	ael1006_power_down,
239167514Skmacy};
240167514Skmacy#else
241167514Skmacystatic struct cphy_ops qt2045_ops = {
242167514Skmacy	.reset           = ael1006_reset,
243167514Skmacy	.intr_enable     = ael1006_intr_enable,
244167514Skmacy	.intr_disable    = ael1006_intr_disable,
245167514Skmacy	.intr_clear      = ael1006_intr_clear,
246167514Skmacy	.intr_handler    = ael1006_intr_handler,
247167514Skmacy	.get_link_status = ael100x_get_link_status,
248167514Skmacy	.power_down      = ael1006_power_down,
249167514Skmacy};
250167514Skmacy#endif
251167514Skmacy
252167514Skmacyvoid t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
253167514Skmacy			const struct mdio_ops *mdio_ops)
254167514Skmacy{
255167514Skmacy	unsigned int stat;
256167514Skmacy
257167514Skmacy	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
258167514Skmacy
259167514Skmacy	/*
260167514Skmacy	 * Some cards where the PHY is supposed to be at address 0 actually
261167514Skmacy	 * have it at 1.
262167514Skmacy	 */
263167514Skmacy	if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
264167514Skmacy	    stat == 0xffff)
265167514Skmacy		phy->addr = 1;
266167514Skmacy}
267167514Skmacy
268167514Skmacystatic int xaui_direct_reset(struct cphy *phy, int wait)
269167514Skmacy{
270167514Skmacy	return 0;
271167514Skmacy}
272167514Skmacy
273167514Skmacystatic int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
274167514Skmacy				       int *speed, int *duplex, int *fc)
275167514Skmacy{
276167514Skmacy	if (link_ok) {
277167514Skmacy		unsigned int status;
278167514Skmacy
279167514Skmacy		status = t3_read_reg(phy->adapter,
280167514Skmacy				     XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
281167514Skmacy		*link_ok = !(status & F_LOWSIG0);
282167514Skmacy	}
283167514Skmacy	if (speed)
284167514Skmacy		*speed = SPEED_10000;
285167514Skmacy	if (duplex)
286167514Skmacy		*duplex = DUPLEX_FULL;
287167514Skmacy	return 0;
288167514Skmacy}
289167514Skmacy
290167514Skmacystatic int xaui_direct_power_down(struct cphy *phy, int enable)
291167514Skmacy{
292167514Skmacy	return 0;
293167514Skmacy}
294167514Skmacy
295167514Skmacy#ifdef C99_NOT_SUPPORTED
296167514Skmacystatic struct cphy_ops xaui_direct_ops = {
297167514Skmacy	NULL,
298167514Skmacy	xaui_direct_reset,
299167514Skmacy	ael1002_intr_noop,
300167514Skmacy	ael1002_intr_noop,
301167514Skmacy	ael1002_intr_noop,
302167514Skmacy	ael1002_intr_noop,
303167514Skmacy	NULL,
304167514Skmacy	NULL,
305167514Skmacy	NULL,
306167514Skmacy	NULL,
307167514Skmacy	NULL,
308167514Skmacy	xaui_direct_get_link_status,
309167514Skmacy	xaui_direct_power_down,
310167514Skmacy};
311167514Skmacy#else
312167514Skmacystatic struct cphy_ops xaui_direct_ops = {
313167514Skmacy	.reset           = xaui_direct_reset,
314167514Skmacy	.intr_enable     = ael1002_intr_noop,
315167514Skmacy	.intr_disable    = ael1002_intr_noop,
316167514Skmacy	.intr_clear      = ael1002_intr_noop,
317167514Skmacy	.intr_handler    = ael1002_intr_noop,
318167514Skmacy	.get_link_status = xaui_direct_get_link_status,
319167514Skmacy	.power_down      = xaui_direct_power_down,
320167514Skmacy};
321167514Skmacy#endif
322167514Skmacy
323167514Skmacyvoid t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
324167514Skmacy			     const struct mdio_ops *mdio_ops)
325167514Skmacy{
326167514Skmacy	cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
327167514Skmacy}
328