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