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