xref: /freebsd/sys/dev/cxgb/common/cxgb_ael1002.c (revision b6d90eb7)
1b6d90eb7SKip Macy /**************************************************************************
2b6d90eb7SKip Macy 
3b6d90eb7SKip Macy Copyright (c) 2007, Chelsio Inc.
4b6d90eb7SKip Macy All rights reserved.
5b6d90eb7SKip Macy 
6b6d90eb7SKip Macy Redistribution and use in source and binary forms, with or without
7b6d90eb7SKip Macy modification, are permitted provided that the following conditions are met:
8b6d90eb7SKip Macy 
9b6d90eb7SKip Macy  1. Redistributions of source code must retain the above copyright notice,
10b6d90eb7SKip Macy     this list of conditions and the following disclaimer.
11b6d90eb7SKip Macy 
12b6d90eb7SKip Macy  2. Redistributions in binary form must reproduce the above copyright
13b6d90eb7SKip Macy     notice, this list of conditions and the following disclaimer in the
14b6d90eb7SKip Macy     documentation and/or other materials provided with the distribution.
15b6d90eb7SKip Macy 
16b6d90eb7SKip Macy  3. Neither the name of the Chelsio Corporation nor the names of its
17b6d90eb7SKip Macy     contributors may be used to endorse or promote products derived from
18b6d90eb7SKip Macy     this software without specific prior written permission.
19b6d90eb7SKip Macy 
20b6d90eb7SKip Macy THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21b6d90eb7SKip Macy AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22b6d90eb7SKip Macy IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23b6d90eb7SKip Macy ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24b6d90eb7SKip Macy LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25b6d90eb7SKip Macy CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26b6d90eb7SKip Macy SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27b6d90eb7SKip Macy INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28b6d90eb7SKip Macy CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29b6d90eb7SKip Macy ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30b6d90eb7SKip Macy POSSIBILITY OF SUCH DAMAGE.
31b6d90eb7SKip Macy 
32b6d90eb7SKip Macy ***************************************************************************/
33b6d90eb7SKip Macy 
34b6d90eb7SKip Macy #include <sys/cdefs.h>
35b6d90eb7SKip Macy __FBSDID("$FreeBSD$");
36b6d90eb7SKip Macy 
37b6d90eb7SKip Macy #include <dev/cxgb/common/cxgb_common.h>
38b6d90eb7SKip Macy #include <dev/cxgb/common/cxgb_regs.h>
39b6d90eb7SKip Macy 
40b6d90eb7SKip Macy enum {
41b6d90eb7SKip Macy 	AEL100X_TX_DISABLE  = 9,
42b6d90eb7SKip Macy 	AEL100X_TX_CONFIG1  = 0xc002,
43b6d90eb7SKip Macy 	AEL1002_PWR_DOWN_HI = 0xc011,
44b6d90eb7SKip Macy 	AEL1002_PWR_DOWN_LO = 0xc012,
45b6d90eb7SKip Macy 	AEL1002_XFI_EQL     = 0xc015,
46b6d90eb7SKip Macy 	AEL1002_LB_EN       = 0xc017,
47b6d90eb7SKip Macy 
48b6d90eb7SKip Macy 	LASI_CTRL   = 0x9002,
49b6d90eb7SKip Macy 	LASI_STAT   = 0x9005
50b6d90eb7SKip Macy };
51b6d90eb7SKip Macy 
52b6d90eb7SKip Macy static void ael100x_txon(struct cphy *phy)
53b6d90eb7SKip Macy {
54b6d90eb7SKip Macy 	int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
55b6d90eb7SKip Macy 
56b6d90eb7SKip Macy 	t3_os_sleep(100);
57b6d90eb7SKip Macy 	t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
58b6d90eb7SKip Macy 	t3_os_sleep(30);
59b6d90eb7SKip Macy }
60b6d90eb7SKip Macy 
61b6d90eb7SKip Macy static int ael1002_power_down(struct cphy *phy, int enable)
62b6d90eb7SKip Macy {
63b6d90eb7SKip Macy 	int err;
64b6d90eb7SKip Macy 
65b6d90eb7SKip Macy 	err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
66b6d90eb7SKip Macy 	if (!err)
67b6d90eb7SKip Macy 		err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
68b6d90eb7SKip Macy 					  BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
69b6d90eb7SKip Macy 	return err;
70b6d90eb7SKip Macy }
71b6d90eb7SKip Macy 
72b6d90eb7SKip Macy static int ael1002_reset(struct cphy *phy, int wait)
73b6d90eb7SKip Macy {
74b6d90eb7SKip Macy 	int err;
75b6d90eb7SKip Macy 
76b6d90eb7SKip Macy 	if ((err = ael1002_power_down(phy, 0)) ||
77b6d90eb7SKip Macy 	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
78b6d90eb7SKip Macy 	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
79b6d90eb7SKip Macy 	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
80b6d90eb7SKip Macy 	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
81b6d90eb7SKip Macy 	    (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
82b6d90eb7SKip Macy 				       0, 1 << 5)))
83b6d90eb7SKip Macy 		return err;
84b6d90eb7SKip Macy 	return 0;
85b6d90eb7SKip Macy }
86b6d90eb7SKip Macy 
87b6d90eb7SKip Macy static int ael1002_intr_noop(struct cphy *phy)
88b6d90eb7SKip Macy {
89b6d90eb7SKip Macy 	return 0;
90b6d90eb7SKip Macy }
91b6d90eb7SKip Macy 
92b6d90eb7SKip Macy static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
93b6d90eb7SKip Macy 				   int *speed, int *duplex, int *fc)
94b6d90eb7SKip Macy {
95b6d90eb7SKip Macy 	if (link_ok) {
96b6d90eb7SKip Macy 		unsigned int status;
97b6d90eb7SKip Macy 		int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
98b6d90eb7SKip Macy 
99b6d90eb7SKip Macy 		/*
100b6d90eb7SKip Macy 		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
101b6d90eb7SKip Macy 		 * once more to get the current link state.
102b6d90eb7SKip Macy 		 */
103b6d90eb7SKip Macy 		if (!err && !(status & BMSR_LSTATUS))
104b6d90eb7SKip Macy 			err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
105b6d90eb7SKip Macy 					&status);
106b6d90eb7SKip Macy 		if (err)
107b6d90eb7SKip Macy 			return err;
108b6d90eb7SKip Macy 		*link_ok = !!(status & BMSR_LSTATUS);
109b6d90eb7SKip Macy 	}
110b6d90eb7SKip Macy 	if (speed)
111b6d90eb7SKip Macy 		*speed = SPEED_10000;
112b6d90eb7SKip Macy 	if (duplex)
113b6d90eb7SKip Macy 		*duplex = DUPLEX_FULL;
114b6d90eb7SKip Macy 	return 0;
115b6d90eb7SKip Macy }
116b6d90eb7SKip Macy 
117b6d90eb7SKip Macy #ifdef C99_NOT_SUPPORTED
118b6d90eb7SKip Macy static struct cphy_ops ael1002_ops = {
119b6d90eb7SKip Macy 	NULL,
120b6d90eb7SKip Macy 	ael1002_reset,
121b6d90eb7SKip Macy 	ael1002_intr_noop,
122b6d90eb7SKip Macy 	ael1002_intr_noop,
123b6d90eb7SKip Macy 	ael1002_intr_noop,
124b6d90eb7SKip Macy 	ael1002_intr_noop,
125b6d90eb7SKip Macy 	NULL,
126b6d90eb7SKip Macy 	NULL,
127b6d90eb7SKip Macy 	NULL,
128b6d90eb7SKip Macy 	NULL,
129b6d90eb7SKip Macy 	NULL,
130b6d90eb7SKip Macy 	ael100x_get_link_status,
131b6d90eb7SKip Macy 	ael1002_power_down,
132b6d90eb7SKip Macy };
133b6d90eb7SKip Macy #else
134b6d90eb7SKip Macy static struct cphy_ops ael1002_ops = {
135b6d90eb7SKip Macy 	.reset           = ael1002_reset,
136b6d90eb7SKip Macy 	.intr_enable     = ael1002_intr_noop,
137b6d90eb7SKip Macy 	.intr_disable    = ael1002_intr_noop,
138b6d90eb7SKip Macy 	.intr_clear      = ael1002_intr_noop,
139b6d90eb7SKip Macy 	.intr_handler    = ael1002_intr_noop,
140b6d90eb7SKip Macy 	.get_link_status = ael100x_get_link_status,
141b6d90eb7SKip Macy 	.power_down      = ael1002_power_down,
142b6d90eb7SKip Macy };
143b6d90eb7SKip Macy #endif
144b6d90eb7SKip Macy 
145b6d90eb7SKip Macy void t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
146b6d90eb7SKip Macy 			 const struct mdio_ops *mdio_ops)
147b6d90eb7SKip Macy {
148b6d90eb7SKip Macy 	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
149b6d90eb7SKip Macy 	ael100x_txon(phy);
150b6d90eb7SKip Macy }
151b6d90eb7SKip Macy 
152b6d90eb7SKip Macy static int ael1006_reset(struct cphy *phy, int wait)
153b6d90eb7SKip Macy {
154b6d90eb7SKip Macy 	return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
155b6d90eb7SKip Macy }
156b6d90eb7SKip Macy 
157b6d90eb7SKip Macy static int ael1006_intr_enable(struct cphy *phy)
158b6d90eb7SKip Macy {
159b6d90eb7SKip Macy 	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
160b6d90eb7SKip Macy }
161b6d90eb7SKip Macy 
162b6d90eb7SKip Macy static int ael1006_intr_disable(struct cphy *phy)
163b6d90eb7SKip Macy {
164b6d90eb7SKip Macy 	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
165b6d90eb7SKip Macy }
166b6d90eb7SKip Macy 
167b6d90eb7SKip Macy static int ael1006_intr_clear(struct cphy *phy)
168b6d90eb7SKip Macy {
169b6d90eb7SKip Macy 	u32 val;
170b6d90eb7SKip Macy 
171b6d90eb7SKip Macy 	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
172b6d90eb7SKip Macy }
173b6d90eb7SKip Macy 
174b6d90eb7SKip Macy static int ael1006_intr_handler(struct cphy *phy)
175b6d90eb7SKip Macy {
176b6d90eb7SKip Macy 	unsigned int status;
177b6d90eb7SKip Macy 	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
178b6d90eb7SKip Macy 
179b6d90eb7SKip Macy 	if (err)
180b6d90eb7SKip Macy 		return err;
181b6d90eb7SKip Macy 	return (status & 1) ?  cphy_cause_link_change : 0;
182b6d90eb7SKip Macy }
183b6d90eb7SKip Macy 
184b6d90eb7SKip Macy static int ael1006_power_down(struct cphy *phy, int enable)
185b6d90eb7SKip Macy {
186b6d90eb7SKip Macy 	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
187b6d90eb7SKip Macy 				   BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
188b6d90eb7SKip Macy }
189b6d90eb7SKip Macy 
190b6d90eb7SKip Macy #ifdef C99_NOT_SUPPORTED
191b6d90eb7SKip Macy static struct cphy_ops ael1006_ops = {
192b6d90eb7SKip Macy 	NULL,
193b6d90eb7SKip Macy 	ael1006_reset,
194b6d90eb7SKip Macy 	ael1006_intr_enable,
195b6d90eb7SKip Macy 	ael1006_intr_disable,
196b6d90eb7SKip Macy 	ael1006_intr_clear,
197b6d90eb7SKip Macy 	ael1006_intr_handler,
198b6d90eb7SKip Macy 	NULL,
199b6d90eb7SKip Macy 	NULL,
200b6d90eb7SKip Macy 	NULL,
201b6d90eb7SKip Macy 	NULL,
202b6d90eb7SKip Macy 	NULL,
203b6d90eb7SKip Macy 	ael100x_get_link_status,
204b6d90eb7SKip Macy 	ael1006_power_down,
205b6d90eb7SKip Macy };
206b6d90eb7SKip Macy #else
207b6d90eb7SKip Macy static struct cphy_ops ael1006_ops = {
208b6d90eb7SKip Macy 	.reset           = ael1006_reset,
209b6d90eb7SKip Macy 	.intr_enable     = ael1006_intr_enable,
210b6d90eb7SKip Macy 	.intr_disable    = ael1006_intr_disable,
211b6d90eb7SKip Macy 	.intr_clear      = ael1006_intr_clear,
212b6d90eb7SKip Macy 	.intr_handler    = ael1006_intr_handler,
213b6d90eb7SKip Macy 	.get_link_status = ael100x_get_link_status,
214b6d90eb7SKip Macy 	.power_down      = ael1006_power_down,
215b6d90eb7SKip Macy };
216b6d90eb7SKip Macy #endif
217b6d90eb7SKip Macy 
218b6d90eb7SKip Macy void t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
219b6d90eb7SKip Macy 			 const struct mdio_ops *mdio_ops)
220b6d90eb7SKip Macy {
221b6d90eb7SKip Macy 	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
222b6d90eb7SKip Macy 	ael100x_txon(phy);
223b6d90eb7SKip Macy }
224b6d90eb7SKip Macy 
225b6d90eb7SKip Macy #ifdef C99_NOT_SUPPORTED
226b6d90eb7SKip Macy static struct cphy_ops qt2045_ops = {
227b6d90eb7SKip Macy 	NULL,
228b6d90eb7SKip Macy 	ael1006_reset,
229b6d90eb7SKip Macy 	ael1006_intr_enable,
230b6d90eb7SKip Macy 	ael1006_intr_disable,
231b6d90eb7SKip Macy 	ael1006_intr_clear,
232b6d90eb7SKip Macy 	ael1006_intr_handler,
233b6d90eb7SKip Macy 	NULL,
234b6d90eb7SKip Macy 	NULL,
235b6d90eb7SKip Macy 	NULL,
236b6d90eb7SKip Macy 	NULL,
237b6d90eb7SKip Macy 	NULL,
238b6d90eb7SKip Macy 	ael100x_get_link_status,
239b6d90eb7SKip Macy 	ael1006_power_down,
240b6d90eb7SKip Macy };
241b6d90eb7SKip Macy #else
242b6d90eb7SKip Macy static struct cphy_ops qt2045_ops = {
243b6d90eb7SKip Macy 	.reset           = ael1006_reset,
244b6d90eb7SKip Macy 	.intr_enable     = ael1006_intr_enable,
245b6d90eb7SKip Macy 	.intr_disable    = ael1006_intr_disable,
246b6d90eb7SKip Macy 	.intr_clear      = ael1006_intr_clear,
247b6d90eb7SKip Macy 	.intr_handler    = ael1006_intr_handler,
248b6d90eb7SKip Macy 	.get_link_status = ael100x_get_link_status,
249b6d90eb7SKip Macy 	.power_down      = ael1006_power_down,
250b6d90eb7SKip Macy };
251b6d90eb7SKip Macy #endif
252b6d90eb7SKip Macy 
253b6d90eb7SKip Macy void t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
254b6d90eb7SKip Macy 			const struct mdio_ops *mdio_ops)
255b6d90eb7SKip Macy {
256b6d90eb7SKip Macy 	unsigned int stat;
257b6d90eb7SKip Macy 
258b6d90eb7SKip Macy 	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
259b6d90eb7SKip Macy 
260b6d90eb7SKip Macy 	/*
261b6d90eb7SKip Macy 	 * Some cards where the PHY is supposed to be at address 0 actually
262b6d90eb7SKip Macy 	 * have it at 1.
263b6d90eb7SKip Macy 	 */
264b6d90eb7SKip Macy 	if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
265b6d90eb7SKip Macy 	    stat == 0xffff)
266b6d90eb7SKip Macy 		phy->addr = 1;
267b6d90eb7SKip Macy }
268b6d90eb7SKip Macy 
269b6d90eb7SKip Macy static int xaui_direct_reset(struct cphy *phy, int wait)
270b6d90eb7SKip Macy {
271b6d90eb7SKip Macy 	return 0;
272b6d90eb7SKip Macy }
273b6d90eb7SKip Macy 
274b6d90eb7SKip Macy static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
275b6d90eb7SKip Macy 				       int *speed, int *duplex, int *fc)
276b6d90eb7SKip Macy {
277b6d90eb7SKip Macy 	if (link_ok) {
278b6d90eb7SKip Macy 		unsigned int status;
279b6d90eb7SKip Macy 
280b6d90eb7SKip Macy 		status = t3_read_reg(phy->adapter,
281b6d90eb7SKip Macy 				     XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
282b6d90eb7SKip Macy 		*link_ok = !(status & F_LOWSIG0);
283b6d90eb7SKip Macy 	}
284b6d90eb7SKip Macy 	if (speed)
285b6d90eb7SKip Macy 		*speed = SPEED_10000;
286b6d90eb7SKip Macy 	if (duplex)
287b6d90eb7SKip Macy 		*duplex = DUPLEX_FULL;
288b6d90eb7SKip Macy 	return 0;
289b6d90eb7SKip Macy }
290b6d90eb7SKip Macy 
291b6d90eb7SKip Macy static int xaui_direct_power_down(struct cphy *phy, int enable)
292b6d90eb7SKip Macy {
293b6d90eb7SKip Macy 	return 0;
294b6d90eb7SKip Macy }
295b6d90eb7SKip Macy 
296b6d90eb7SKip Macy #ifdef C99_NOT_SUPPORTED
297b6d90eb7SKip Macy static struct cphy_ops xaui_direct_ops = {
298b6d90eb7SKip Macy 	NULL,
299b6d90eb7SKip Macy 	xaui_direct_reset,
300b6d90eb7SKip Macy 	ael1002_intr_noop,
301b6d90eb7SKip Macy 	ael1002_intr_noop,
302b6d90eb7SKip Macy 	ael1002_intr_noop,
303b6d90eb7SKip Macy 	ael1002_intr_noop,
304b6d90eb7SKip Macy 	NULL,
305b6d90eb7SKip Macy 	NULL,
306b6d90eb7SKip Macy 	NULL,
307b6d90eb7SKip Macy 	NULL,
308b6d90eb7SKip Macy 	NULL,
309b6d90eb7SKip Macy 	xaui_direct_get_link_status,
310b6d90eb7SKip Macy 	xaui_direct_power_down,
311b6d90eb7SKip Macy };
312b6d90eb7SKip Macy #else
313b6d90eb7SKip Macy static struct cphy_ops xaui_direct_ops = {
314b6d90eb7SKip Macy 	.reset           = xaui_direct_reset,
315b6d90eb7SKip Macy 	.intr_enable     = ael1002_intr_noop,
316b6d90eb7SKip Macy 	.intr_disable    = ael1002_intr_noop,
317b6d90eb7SKip Macy 	.intr_clear      = ael1002_intr_noop,
318b6d90eb7SKip Macy 	.intr_handler    = ael1002_intr_noop,
319b6d90eb7SKip Macy 	.get_link_status = xaui_direct_get_link_status,
320b6d90eb7SKip Macy 	.power_down      = xaui_direct_power_down,
321b6d90eb7SKip Macy };
322b6d90eb7SKip Macy #endif
323b6d90eb7SKip Macy 
324b6d90eb7SKip Macy void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
325b6d90eb7SKip Macy 			     const struct mdio_ops *mdio_ops)
326b6d90eb7SKip Macy {
327b6d90eb7SKip Macy 	cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
328b6d90eb7SKip Macy }
329