xref: /illumos-gate/usr/src/uts/common/io/chxge/com/my3126.c (revision 4fa33403)
1d39a76e7Sxw /*
2d39a76e7Sxw  * CDDL HEADER START
3d39a76e7Sxw  *
4d39a76e7Sxw  * The contents of this file are subject to the terms of the
5d39a76e7Sxw  * Common Development and Distribution License (the "License").
6d39a76e7Sxw  * You may not use this file except in compliance with the License.
7d39a76e7Sxw  *
8d39a76e7Sxw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d39a76e7Sxw  * or http://www.opensolaris.org/os/licensing.
10d39a76e7Sxw  * See the License for the specific language governing permissions
11d39a76e7Sxw  * and limitations under the License.
12d39a76e7Sxw  *
13d39a76e7Sxw  * When distributing Covered Code, include this CDDL HEADER in each
14d39a76e7Sxw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d39a76e7Sxw  * If applicable, add the following below this CDDL HEADER, with the
16d39a76e7Sxw  * fields enclosed by brackets "[]" replaced with your own identifying
17d39a76e7Sxw  * information: Portions Copyright [yyyy] [name of copyright owner]
18d39a76e7Sxw  *
19d39a76e7Sxw  * CDDL HEADER END
20d39a76e7Sxw  */
21d39a76e7Sxw 
22d39a76e7Sxw /*
23d39a76e7Sxw  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
24d39a76e7Sxw  */
25d39a76e7Sxw 
26d39a76e7Sxw #include "cphy.h"
27d39a76e7Sxw #include "elmer0.h"
28d39a76e7Sxw #include "suni1x10gexp_regs.h"
29d39a76e7Sxw 
30d39a76e7Sxw /* Port Reset */
31d39a76e7Sxw /* ARGSUSED */
my3126_reset(struct cphy * cphy,int wait)32d39a76e7Sxw static int my3126_reset(struct cphy *cphy, int wait)
33d39a76e7Sxw {
34d39a76e7Sxw 	/*
35d39a76e7Sxw 	 * This can be done through registers.  It is not required since
36d39a76e7Sxw 	 * a full chip reset is used.
37d39a76e7Sxw 	 */
38d39a76e7Sxw 	return (0);
39d39a76e7Sxw }
40d39a76e7Sxw 
41d39a76e7Sxw /* ARGSUSED */
my3126_interrupt_enable(struct cphy * cphy)42d39a76e7Sxw static int my3126_interrupt_enable(struct cphy *cphy)
43d39a76e7Sxw {
44d39a76e7Sxw 	/* T1 Elmer does not support link/act LED. */
45d39a76e7Sxw 	if (!is_T2(cphy->adapter))
46d39a76e7Sxw 		return (0);
47d39a76e7Sxw 	ch_start_cyclic(&cphy->phy_update_cyclic, 30);
48d39a76e7Sxw 	(void) t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo);
49d39a76e7Sxw 	return (0);
50d39a76e7Sxw }
51d39a76e7Sxw 
52d39a76e7Sxw /* ARGSUSED */
my3126_interrupt_disable(struct cphy * cphy)53d39a76e7Sxw static int my3126_interrupt_disable(struct cphy *cphy)
54d39a76e7Sxw {
55d39a76e7Sxw 	/* T1 Elmer does not support link/act LED. */
56d39a76e7Sxw 	if (is_T2(cphy->adapter))
57d39a76e7Sxw 		ch_stop_cyclic(&cphy->phy_update_cyclic);
58d39a76e7Sxw 	return (0);
59d39a76e7Sxw }
60d39a76e7Sxw 
61d39a76e7Sxw /* ARGSUSED */
my3126_interrupt_clear(struct cphy * cphy)62d39a76e7Sxw static int my3126_interrupt_clear(struct cphy *cphy)
63d39a76e7Sxw {
64d39a76e7Sxw 	return (0);
65d39a76e7Sxw }
66d39a76e7Sxw 
67*4fa33403SToomas Soome #define	OFFSET(REG_ADDR)    (REG_ADDR << 2)
68d39a76e7Sxw 
69*4fa33403SToomas Soome static int
my3126_interrupt_handler(struct cphy * cphy)70*4fa33403SToomas Soome my3126_interrupt_handler(struct cphy *cphy)
71d39a76e7Sxw {
72d39a76e7Sxw 	u32 val;
73d39a76e7Sxw 	u16 val16;
74d39a76e7Sxw 	u16 status;
75d39a76e7Sxw 	u32 act_count;
76d39a76e7Sxw 	adapter_t *adapter;
77d39a76e7Sxw 
78d39a76e7Sxw 	/* T1 Elmer does not support link/act LED. */
79d39a76e7Sxw 	if (!is_T2(cphy->adapter))
80d39a76e7Sxw 		return (cphy_cause_link_change);
81d39a76e7Sxw 
82d39a76e7Sxw 	adapter = cphy->adapter;
83d39a76e7Sxw 	if (cphy->count == 50) {
84d39a76e7Sxw 		(void) mdio_read(cphy, 0x1, 0x1, &val);
85d39a76e7Sxw 		val16 = (u16) val;
86d39a76e7Sxw 		status = cphy->bmsr ^ val16;
87*4fa33403SToomas Soome 
88d39a76e7Sxw 		if (status & BMSR_LSTATUS) {
89d39a76e7Sxw 			link_changed(adapter, 0);
90d39a76e7Sxw 		}
91d39a76e7Sxw 		cphy->bmsr = val16;
92d39a76e7Sxw 
93*4fa33403SToomas Soome 		/*
94*4fa33403SToomas Soome 		 * We have only enabled link change interrupts so it
95*4fa33403SToomas Soome 		 * must be that.
96d39a76e7Sxw 		 */
97d39a76e7Sxw 		cphy->count = 0;
98d39a76e7Sxw 	}
99d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_CONTROL),
100*4fa33403SToomas Soome 	    SUNI1x10GEXP_BITMSK_MSTAT_SNAP);
101d39a76e7Sxw 	(void) t1_tpi_read(adapter,
102*4fa33403SToomas Soome 	    OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW), &act_count);
103d39a76e7Sxw 	(void) t1_tpi_read(adapter,
104*4fa33403SToomas Soome 	    OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW), &val);
105d39a76e7Sxw 	act_count += val;
106d39a76e7Sxw 	val = cphy->elmer_gpo;
107d39a76e7Sxw 	if ((val & (1 << 8)) ||
108*4fa33403SToomas Soome 	    (cphy->act_count == act_count) || (cphy->act_on)) {
109d39a76e7Sxw 		val |= (1 << 9);
110d39a76e7Sxw 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
111d39a76e7Sxw 		cphy->act_on = 0;
112d39a76e7Sxw 	} else {
113d39a76e7Sxw 		val &= ~(1 << 9);
114*4fa33403SToomas Soome 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
115d39a76e7Sxw 		cphy->act_on = 1;
116d39a76e7Sxw 	}
117d39a76e7Sxw 	cphy->elmer_gpo = val;
118d39a76e7Sxw 	cphy->act_count = act_count;
119d39a76e7Sxw 	cphy->count++;
120d39a76e7Sxw 
121d39a76e7Sxw 	return (cphy_cause_link_change);
122d39a76e7Sxw }
123d39a76e7Sxw 
124d39a76e7Sxw /* ARGSUSED */
my3126_set_loopback(struct cphy * cphy,int on)125d39a76e7Sxw static int my3126_set_loopback(struct cphy *cphy, int on)
126d39a76e7Sxw {
127d39a76e7Sxw 	return (0);
128d39a76e7Sxw }
129d39a76e7Sxw 
130d39a76e7Sxw /* To check the activity LED */
my3126_get_link_status(struct cphy * cphy,int * link_ok,int * speed,int * duplex,int * fc)131d39a76e7Sxw static int my3126_get_link_status(struct cphy *cphy,
132d39a76e7Sxw 			int *link_ok, int *speed, int *duplex, int *fc)
133d39a76e7Sxw {
134d39a76e7Sxw 	u32 val;
135d39a76e7Sxw 	u16 val16;
136d39a76e7Sxw 	adapter_t *adapter;
137d39a76e7Sxw 
138d39a76e7Sxw 	/* T1 Elmer does not support link/act LED. */
139d39a76e7Sxw 	if (!is_T2(cphy->adapter))
140d39a76e7Sxw 		return (0);
141d39a76e7Sxw 
142d39a76e7Sxw 	adapter = cphy->adapter;
143d39a76e7Sxw 	(void) mdio_read(cphy, 0x1, 0x1, &val);
144d39a76e7Sxw 	val16 = (u16) val;
145d39a76e7Sxw 	val = cphy->elmer_gpo;
146d39a76e7Sxw 	*link_ok = (val16 & BMSR_LSTATUS);
147d39a76e7Sxw 	if (*link_ok) {
148*4fa33403SToomas Soome 		/* Light the LED. */
149*4fa33403SToomas Soome 		val &= ~(1 << 8);
150d39a76e7Sxw 	} else {
151*4fa33403SToomas Soome 		/* Turn off the LED. */
152*4fa33403SToomas Soome 		val |= (1 << 8);
153d39a76e7Sxw 	}
154d39a76e7Sxw 	(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
155d39a76e7Sxw 	cphy->elmer_gpo = val;
156d39a76e7Sxw 	*speed = SPEED_10000;
157d39a76e7Sxw 	*duplex = DUPLEX_FULL;
158d39a76e7Sxw 	/* need to add flow control */
159d39a76e7Sxw 	if (fc)
160d39a76e7Sxw 		*fc = PAUSE_RX | PAUSE_TX;
161d39a76e7Sxw 
162d39a76e7Sxw 	return (0);
163d39a76e7Sxw }
164d39a76e7Sxw 
my3126_destroy(struct cphy * cphy)165d39a76e7Sxw static void my3126_destroy(struct cphy *cphy)
166d39a76e7Sxw {
167*4fa33403SToomas Soome 	t1_os_free(cphy, sizeof (*cphy));
168d39a76e7Sxw }
169d39a76e7Sxw 
170d39a76e7Sxw #ifdef C99_NOT_SUPPORTED
171d39a76e7Sxw static struct cphy_ops my3126_ops = {
172d39a76e7Sxw 	my3126_destroy,
173d39a76e7Sxw 	my3126_reset,
174d39a76e7Sxw 	my3126_interrupt_enable,
175d39a76e7Sxw 	my3126_interrupt_disable,
176d39a76e7Sxw 	my3126_interrupt_clear,
177d39a76e7Sxw 	my3126_interrupt_handler,
178d39a76e7Sxw 	NULL,
179d39a76e7Sxw 	NULL,
180d39a76e7Sxw 	NULL,
181d39a76e7Sxw 	NULL,
182d39a76e7Sxw 	my3126_set_loopback,
183d39a76e7Sxw 	NULL,
184d39a76e7Sxw 	my3126_get_link_status,
185d39a76e7Sxw };
186d39a76e7Sxw #else
187d39a76e7Sxw static struct cphy_ops my3126_ops = {
188*4fa33403SToomas Soome 	.destroy		= my3126_destroy,
189*4fa33403SToomas Soome 	.reset			= my3126_reset,
190*4fa33403SToomas Soome 	.interrupt_enable	= my3126_interrupt_enable,
191*4fa33403SToomas Soome 	.interrupt_disable	= my3126_interrupt_disable,
192*4fa33403SToomas Soome 	.interrupt_clear	= my3126_interrupt_clear,
193*4fa33403SToomas Soome 	.interrupt_handler	= my3126_interrupt_handler,
194*4fa33403SToomas Soome 	.get_link_status	= my3126_get_link_status,
195*4fa33403SToomas Soome 	.set_loopback		= my3126_set_loopback,
196d39a76e7Sxw };
197d39a76e7Sxw #endif
198d39a76e7Sxw 
199*4fa33403SToomas Soome static void
my3126_cyclic_cb(void * ptr)200*4fa33403SToomas Soome my3126_cyclic_cb(void *ptr)
201*4fa33403SToomas Soome {
202*4fa33403SToomas Soome 	(void) my3126_interrupt_handler(ptr);
203*4fa33403SToomas Soome }
204*4fa33403SToomas Soome 
my3126_phy_create(adapter_t * adapter,int phy_addr,struct mdio_ops * mdio_ops)205d39a76e7Sxw static struct cphy *my3126_phy_create(adapter_t *adapter, int phy_addr,
206*4fa33403SToomas Soome     struct mdio_ops *mdio_ops)
207d39a76e7Sxw {
208*4fa33403SToomas Soome 	struct cphy *cphy = t1_os_malloc_wait_zero(sizeof (*cphy));
209d39a76e7Sxw 
210d39a76e7Sxw 	if (cphy)
211d39a76e7Sxw 		cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops);
212d39a76e7Sxw 
213d39a76e7Sxw 	if (is_T2(adapter)) {
214*4fa33403SToomas Soome 		ch_init_cyclic(adapter, &cphy->phy_update_cyclic,
215*4fa33403SToomas Soome 		    my3126_cyclic_cb, cphy);
216d39a76e7Sxw 		cphy->bmsr = 0;
217d39a76e7Sxw 	}
218d39a76e7Sxw 
219d39a76e7Sxw 	return (cphy);
220d39a76e7Sxw }
221d39a76e7Sxw 
222d39a76e7Sxw /* Chip Reset */
my3126_phy_reset(adapter_t * adapter)223*4fa33403SToomas Soome static int my3126_phy_reset(adapter_t *adapter)
224d39a76e7Sxw {
225d39a76e7Sxw 	u32 val;
226d39a76e7Sxw 
227d39a76e7Sxw 	(void) t1_tpi_read(adapter, A_ELMER0_GPO, &val);
228d39a76e7Sxw 	val &= ~4;
229d39a76e7Sxw 	(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
230d39a76e7Sxw 	DELAY_MS(100);
231d39a76e7Sxw 
232d39a76e7Sxw 	(void) t1_tpi_write(adapter, A_ELMER0_GPO, val | 4);
233d39a76e7Sxw 	DELAY_MS(1000);
234d39a76e7Sxw 
235d39a76e7Sxw 	/* Now lets enable the Laser. Delay 100us */
236d39a76e7Sxw 	(void) t1_tpi_read(adapter, A_ELMER0_GPO, &val);
237d39a76e7Sxw 	val |= 0x8000;
238d39a76e7Sxw 	(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
239d39a76e7Sxw 	DELAY_US(100);
240d39a76e7Sxw 	return (0);
241d39a76e7Sxw }
242d39a76e7Sxw 
243d39a76e7Sxw struct gphy t1_my3126_ops = {
244d39a76e7Sxw 	my3126_phy_create,
245d39a76e7Sxw 	my3126_phy_reset
246d39a76e7Sxw };
247