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