1c01f2b83SNavdeep Parhar /**************************************************************************
24d846d26SWarner Losh SPDX-License-Identifier: BSD-2-Clause
3c01f2b83SNavdeep Parhar
4c01f2b83SNavdeep Parhar Copyright (c) 2009 Chelsio Inc.
5c01f2b83SNavdeep Parhar All rights reserved.
6c01f2b83SNavdeep Parhar
7c01f2b83SNavdeep Parhar Redistribution and use in source and binary forms, with or without
8c01f2b83SNavdeep Parhar modification, are permitted provided that the following conditions are met:
9c01f2b83SNavdeep Parhar
10c01f2b83SNavdeep Parhar 1. Redistributions of source code must retain the above copyright notice,
11c01f2b83SNavdeep Parhar this list of conditions and the following disclaimer.
12c01f2b83SNavdeep Parhar
13c01f2b83SNavdeep Parhar 2. Neither the name of the Chelsio Corporation nor the names of its
14c01f2b83SNavdeep Parhar contributors may be used to endorse or promote products derived from
15c01f2b83SNavdeep Parhar this software without specific prior written permission.
16c01f2b83SNavdeep Parhar
17c01f2b83SNavdeep Parhar THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18c01f2b83SNavdeep Parhar AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19c01f2b83SNavdeep Parhar IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20c01f2b83SNavdeep Parhar ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21c01f2b83SNavdeep Parhar LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22c01f2b83SNavdeep Parhar CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23c01f2b83SNavdeep Parhar SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24c01f2b83SNavdeep Parhar INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25c01f2b83SNavdeep Parhar CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26c01f2b83SNavdeep Parhar ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27c01f2b83SNavdeep Parhar POSSIBILITY OF SUCH DAMAGE.
28c01f2b83SNavdeep Parhar
29c01f2b83SNavdeep Parhar ***************************************************************************/
30c01f2b83SNavdeep Parhar
31c01f2b83SNavdeep Parhar #include <sys/cdefs.h>
32c01f2b83SNavdeep Parhar #include <cxgb_include.h>
33c01f2b83SNavdeep Parhar
34c01f2b83SNavdeep Parhar #undef msleep
35c01f2b83SNavdeep Parhar #define msleep t3_os_sleep
36c01f2b83SNavdeep Parhar
37c01f2b83SNavdeep Parhar enum {
38c01f2b83SNavdeep Parhar /* MDIO_DEV_PMA_PMD registers */
39c01f2b83SNavdeep Parhar AQ_LINK_STAT = 0xe800,
40c01f2b83SNavdeep Parhar
41c01f2b83SNavdeep Parhar /* MDIO_DEV_XGXS registers */
42c01f2b83SNavdeep Parhar AQ_XAUI_RX_CFG = 0xc400,
43c01f2b83SNavdeep Parhar AQ_XAUI_KX_CFG = 0xc440,
44c01f2b83SNavdeep Parhar AQ_XAUI_TX_CFG = 0xe400,
45c01f2b83SNavdeep Parhar
46c01f2b83SNavdeep Parhar /* MDIO_DEV_ANEG registers */
47c01f2b83SNavdeep Parhar AQ_100M_CTRL = 0x0010,
48c01f2b83SNavdeep Parhar AQ_10G_CTRL = 0x0020,
49c01f2b83SNavdeep Parhar AQ_1G_CTRL = 0xc400,
50c01f2b83SNavdeep Parhar AQ_ANEG_STAT = 0xc800,
51c01f2b83SNavdeep Parhar
52c01f2b83SNavdeep Parhar /* MDIO_DEV_VEND1 registers */
53c01f2b83SNavdeep Parhar AQ_FW_VERSION = 0x0020,
54c01f2b83SNavdeep Parhar AQ_THERMAL_THR = 0xc421,
55c01f2b83SNavdeep Parhar AQ_THERMAL1 = 0xc820,
56c01f2b83SNavdeep Parhar AQ_THERMAL2 = 0xc821,
57c01f2b83SNavdeep Parhar AQ_IFLAG_GLOBAL = 0xfc00,
58c01f2b83SNavdeep Parhar AQ_IMASK_GLOBAL = 0xff00,
59c01f2b83SNavdeep Parhar };
60c01f2b83SNavdeep Parhar
61c01f2b83SNavdeep Parhar #define AQBIT(x) (1 << (0x##x))
62c01f2b83SNavdeep Parhar #define ADV_1G_FULL AQBIT(f)
63c01f2b83SNavdeep Parhar #define ADV_1G_HALF AQBIT(e)
64c01f2b83SNavdeep Parhar #define ADV_10G_FULL AQBIT(c)
65c01f2b83SNavdeep Parhar
66c01f2b83SNavdeep Parhar #define AQ_WRITE_REGS(phy, regs) do { \
67c01f2b83SNavdeep Parhar int i; \
68c01f2b83SNavdeep Parhar for (i = 0; i < ARRAY_SIZE(regs); i++) { \
69c01f2b83SNavdeep Parhar (void) mdio_write(phy, regs[i].mmd, regs[i].reg, regs[i].val); \
70c01f2b83SNavdeep Parhar } \
71c01f2b83SNavdeep Parhar } while (0)
72c01f2b83SNavdeep Parhar #define AQ_READ_REGS(phy, regs) do { \
73c01f2b83SNavdeep Parhar unsigned i, v; \
74c01f2b83SNavdeep Parhar for (i = 0; i < ARRAY_SIZE(regs); i++) { \
75c01f2b83SNavdeep Parhar (void) mdio_read(phy, regs[i].mmd, regs[i].reg, &v); \
76c01f2b83SNavdeep Parhar } \
77c01f2b83SNavdeep Parhar } while (0)
78c01f2b83SNavdeep Parhar
79c01f2b83SNavdeep Parhar /*
809097ac9aSElyes HAOUAS * Return value is temperature in celsius, 0xffff for error or don't know.
81c01f2b83SNavdeep Parhar */
82c01f2b83SNavdeep Parhar static int
aq100x_temperature(struct cphy * phy)83c01f2b83SNavdeep Parhar aq100x_temperature(struct cphy *phy)
84c01f2b83SNavdeep Parhar {
85c01f2b83SNavdeep Parhar unsigned int v;
86c01f2b83SNavdeep Parhar
87c01f2b83SNavdeep Parhar if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL2, &v) ||
88c01f2b83SNavdeep Parhar v == 0xffff || (v & 1) != 1)
89c01f2b83SNavdeep Parhar return (0xffff);
90c01f2b83SNavdeep Parhar
91c01f2b83SNavdeep Parhar if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL1, &v))
92c01f2b83SNavdeep Parhar return (0xffff);
93c01f2b83SNavdeep Parhar
94c01f2b83SNavdeep Parhar return ((int)((signed char)(v >> 8)));
95c01f2b83SNavdeep Parhar }
96c01f2b83SNavdeep Parhar
97c01f2b83SNavdeep Parhar static int
aq100x_set_defaults(struct cphy * phy)98c01f2b83SNavdeep Parhar aq100x_set_defaults(struct cphy *phy)
99c01f2b83SNavdeep Parhar {
100c01f2b83SNavdeep Parhar return mdio_write(phy, MDIO_DEV_VEND1, AQ_THERMAL_THR, 0x6c00);
101c01f2b83SNavdeep Parhar }
102c01f2b83SNavdeep Parhar
103c01f2b83SNavdeep Parhar static int
aq100x_reset(struct cphy * phy,int wait)104c01f2b83SNavdeep Parhar aq100x_reset(struct cphy *phy, int wait)
105c01f2b83SNavdeep Parhar {
106c01f2b83SNavdeep Parhar int err;
107c01f2b83SNavdeep Parhar err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
108c01f2b83SNavdeep Parhar if (!err)
109c01f2b83SNavdeep Parhar err = aq100x_set_defaults(phy);
110c01f2b83SNavdeep Parhar return (err);
111c01f2b83SNavdeep Parhar }
112c01f2b83SNavdeep Parhar
113c01f2b83SNavdeep Parhar static int
aq100x_intr_enable(struct cphy * phy)114c01f2b83SNavdeep Parhar aq100x_intr_enable(struct cphy *phy)
115c01f2b83SNavdeep Parhar {
116c01f2b83SNavdeep Parhar struct {
117c01f2b83SNavdeep Parhar int mmd;
118c01f2b83SNavdeep Parhar int reg;
119c01f2b83SNavdeep Parhar int val;
120c01f2b83SNavdeep Parhar } imasks[] = {
121c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, 0xd400, AQBIT(e)},
122c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, 0xff01, AQBIT(2)},
123c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, AQBIT(0)}
124c01f2b83SNavdeep Parhar };
125c01f2b83SNavdeep Parhar
126c01f2b83SNavdeep Parhar AQ_WRITE_REGS(phy, imasks);
127c01f2b83SNavdeep Parhar
128c01f2b83SNavdeep Parhar return (0);
129c01f2b83SNavdeep Parhar }
130c01f2b83SNavdeep Parhar
131c01f2b83SNavdeep Parhar static int
aq100x_intr_disable(struct cphy * phy)132c01f2b83SNavdeep Parhar aq100x_intr_disable(struct cphy *phy)
133c01f2b83SNavdeep Parhar {
134c01f2b83SNavdeep Parhar struct {
135c01f2b83SNavdeep Parhar int mmd;
136c01f2b83SNavdeep Parhar int reg;
137c01f2b83SNavdeep Parhar int val;
138c01f2b83SNavdeep Parhar } imasks[] = {
139c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, 0xd400, 0},
140c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, 0xff01, 0},
141c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, 0}
142c01f2b83SNavdeep Parhar };
143c01f2b83SNavdeep Parhar
144c01f2b83SNavdeep Parhar AQ_WRITE_REGS(phy, imasks);
145c01f2b83SNavdeep Parhar
146c01f2b83SNavdeep Parhar return (0);
147c01f2b83SNavdeep Parhar }
148c01f2b83SNavdeep Parhar
149c01f2b83SNavdeep Parhar static int
aq100x_intr_clear(struct cphy * phy)150c01f2b83SNavdeep Parhar aq100x_intr_clear(struct cphy *phy)
151c01f2b83SNavdeep Parhar {
152c01f2b83SNavdeep Parhar struct {
153c01f2b83SNavdeep Parhar int mmd;
154c01f2b83SNavdeep Parhar int reg;
155c01f2b83SNavdeep Parhar } iclr[] = {
156c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, 0xcc00},
157c01f2b83SNavdeep Parhar {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL} /* needed? */
158c01f2b83SNavdeep Parhar };
159c01f2b83SNavdeep Parhar
160c01f2b83SNavdeep Parhar AQ_READ_REGS(phy, iclr);
161c01f2b83SNavdeep Parhar
162c01f2b83SNavdeep Parhar return (0);
163c01f2b83SNavdeep Parhar }
164c01f2b83SNavdeep Parhar
165c01f2b83SNavdeep Parhar static int
aq100x_vendor_intr(struct cphy * phy,int * rc)166c01f2b83SNavdeep Parhar aq100x_vendor_intr(struct cphy *phy, int *rc)
167c01f2b83SNavdeep Parhar {
168c01f2b83SNavdeep Parhar int err;
169c01f2b83SNavdeep Parhar unsigned int cause, v;
170c01f2b83SNavdeep Parhar
171c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_VEND1, 0xfc01, &cause);
172c01f2b83SNavdeep Parhar if (err)
173c01f2b83SNavdeep Parhar return (err);
174c01f2b83SNavdeep Parhar
175c01f2b83SNavdeep Parhar if (cause & AQBIT(2)) {
176c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_VEND1, 0xcc00, &v);
177c01f2b83SNavdeep Parhar if (err)
178c01f2b83SNavdeep Parhar return (err);
179c01f2b83SNavdeep Parhar
180c01f2b83SNavdeep Parhar if (v & AQBIT(e)) {
181c01f2b83SNavdeep Parhar CH_WARN(phy->adapter, "PHY%d: temperature is now %dC\n",
182c01f2b83SNavdeep Parhar phy->addr, aq100x_temperature(phy));
183c01f2b83SNavdeep Parhar
184c01f2b83SNavdeep Parhar t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN,
185c01f2b83SNavdeep Parhar phy->addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL, 0);
186c01f2b83SNavdeep Parhar
187c01f2b83SNavdeep Parhar *rc |= cphy_cause_alarm;
188c01f2b83SNavdeep Parhar }
189c01f2b83SNavdeep Parhar
190c01f2b83SNavdeep Parhar cause &= ~4;
191c01f2b83SNavdeep Parhar }
192c01f2b83SNavdeep Parhar
193c01f2b83SNavdeep Parhar if (cause)
194c01f2b83SNavdeep Parhar CH_WARN(phy->adapter, "PHY%d: unhandled vendor interrupt"
195c01f2b83SNavdeep Parhar " (0x%x)\n", phy->addr, cause);
196c01f2b83SNavdeep Parhar
197c01f2b83SNavdeep Parhar return (0);
198c01f2b83SNavdeep Parhar
199c01f2b83SNavdeep Parhar }
200c01f2b83SNavdeep Parhar
201c01f2b83SNavdeep Parhar static int
aq100x_intr_handler(struct cphy * phy)202c01f2b83SNavdeep Parhar aq100x_intr_handler(struct cphy *phy)
203c01f2b83SNavdeep Parhar {
204c01f2b83SNavdeep Parhar int err, rc = 0;
205c01f2b83SNavdeep Parhar unsigned int cause;
206c01f2b83SNavdeep Parhar
207c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_VEND1, AQ_IFLAG_GLOBAL, &cause);
208c01f2b83SNavdeep Parhar if (err)
209c01f2b83SNavdeep Parhar return (err);
210c01f2b83SNavdeep Parhar
211c01f2b83SNavdeep Parhar if (cause & AQBIT(0)) {
212c01f2b83SNavdeep Parhar err = aq100x_vendor_intr(phy, &rc);
213c01f2b83SNavdeep Parhar if (err)
214c01f2b83SNavdeep Parhar return (err);
215c01f2b83SNavdeep Parhar cause &= ~AQBIT(0);
216c01f2b83SNavdeep Parhar }
217c01f2b83SNavdeep Parhar
218c01f2b83SNavdeep Parhar if (cause)
219c01f2b83SNavdeep Parhar CH_WARN(phy->adapter, "PHY%d: unhandled interrupt (0x%x)\n",
220c01f2b83SNavdeep Parhar phy->addr, cause);
221c01f2b83SNavdeep Parhar
222c01f2b83SNavdeep Parhar return (rc);
223c01f2b83SNavdeep Parhar }
224c01f2b83SNavdeep Parhar
225c01f2b83SNavdeep Parhar static int
aq100x_power_down(struct cphy * phy,int off)226c01f2b83SNavdeep Parhar aq100x_power_down(struct cphy *phy, int off)
227c01f2b83SNavdeep Parhar {
228c01f2b83SNavdeep Parhar int err, wait = 500;
229c01f2b83SNavdeep Parhar unsigned int v;
230c01f2b83SNavdeep Parhar
231c01f2b83SNavdeep Parhar err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, BMCR_PDOWN,
232c01f2b83SNavdeep Parhar off ? BMCR_PDOWN : 0);
233c01f2b83SNavdeep Parhar if (err || off)
234e050eaa3SNavdeep Parhar return (err);
235c01f2b83SNavdeep Parhar
236c01f2b83SNavdeep Parhar msleep(300);
237c01f2b83SNavdeep Parhar do {
238c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
239c01f2b83SNavdeep Parhar if (err)
240c01f2b83SNavdeep Parhar return (err);
241c01f2b83SNavdeep Parhar v &= BMCR_RESET;
242c01f2b83SNavdeep Parhar if (v)
243c01f2b83SNavdeep Parhar msleep(10);
244c01f2b83SNavdeep Parhar } while (v && --wait);
245c01f2b83SNavdeep Parhar if (v) {
246c01f2b83SNavdeep Parhar CH_WARN(phy->adapter, "PHY%d: power-up timed out (0x%x).\n",
247c01f2b83SNavdeep Parhar phy->addr, v);
248c01f2b83SNavdeep Parhar return (ETIMEDOUT);
249c01f2b83SNavdeep Parhar }
250c01f2b83SNavdeep Parhar
251c01f2b83SNavdeep Parhar return (0);
252c01f2b83SNavdeep Parhar }
253c01f2b83SNavdeep Parhar
254c01f2b83SNavdeep Parhar static int
aq100x_autoneg_enable(struct cphy * phy)255c01f2b83SNavdeep Parhar aq100x_autoneg_enable(struct cphy *phy)
256c01f2b83SNavdeep Parhar {
257c01f2b83SNavdeep Parhar int err;
258c01f2b83SNavdeep Parhar
259c01f2b83SNavdeep Parhar err = aq100x_power_down(phy, 0);
260c01f2b83SNavdeep Parhar if (!err)
261c01f2b83SNavdeep Parhar err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
262c01f2b83SNavdeep Parhar BMCR_RESET, BMCR_ANENABLE | BMCR_ANRESTART);
263c01f2b83SNavdeep Parhar
264c01f2b83SNavdeep Parhar return (err);
265c01f2b83SNavdeep Parhar }
266c01f2b83SNavdeep Parhar
267c01f2b83SNavdeep Parhar static int
aq100x_autoneg_restart(struct cphy * phy)268c01f2b83SNavdeep Parhar aq100x_autoneg_restart(struct cphy *phy)
269c01f2b83SNavdeep Parhar {
270c01f2b83SNavdeep Parhar return aq100x_autoneg_enable(phy);
271c01f2b83SNavdeep Parhar }
272c01f2b83SNavdeep Parhar
273c01f2b83SNavdeep Parhar static int
aq100x_advertise(struct cphy * phy,unsigned int advertise_map)274c01f2b83SNavdeep Parhar aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
275c01f2b83SNavdeep Parhar {
276c01f2b83SNavdeep Parhar unsigned int adv;
277c01f2b83SNavdeep Parhar int err;
278c01f2b83SNavdeep Parhar
279c01f2b83SNavdeep Parhar /* 10G advertisement */
280c01f2b83SNavdeep Parhar adv = 0;
281c01f2b83SNavdeep Parhar if (advertise_map & ADVERTISED_10000baseT_Full)
282c01f2b83SNavdeep Parhar adv |= ADV_10G_FULL;
283c01f2b83SNavdeep Parhar err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_10G_CTRL,
284c01f2b83SNavdeep Parhar ADV_10G_FULL, adv);
285c01f2b83SNavdeep Parhar if (err)
286c01f2b83SNavdeep Parhar return (err);
287c01f2b83SNavdeep Parhar
288c01f2b83SNavdeep Parhar /* 1G advertisement */
289c01f2b83SNavdeep Parhar adv = 0;
290c01f2b83SNavdeep Parhar if (advertise_map & ADVERTISED_1000baseT_Full)
291c01f2b83SNavdeep Parhar adv |= ADV_1G_FULL;
292c01f2b83SNavdeep Parhar if (advertise_map & ADVERTISED_1000baseT_Half)
293c01f2b83SNavdeep Parhar adv |= ADV_1G_HALF;
294c01f2b83SNavdeep Parhar err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_1G_CTRL,
295c01f2b83SNavdeep Parhar ADV_1G_FULL | ADV_1G_HALF, adv);
296c01f2b83SNavdeep Parhar if (err)
297c01f2b83SNavdeep Parhar return (err);
298c01f2b83SNavdeep Parhar
299c01f2b83SNavdeep Parhar /* 100M, pause advertisement */
300c01f2b83SNavdeep Parhar adv = 0;
301c01f2b83SNavdeep Parhar if (advertise_map & ADVERTISED_100baseT_Half)
302c01f2b83SNavdeep Parhar adv |= ADVERTISE_100HALF;
303c01f2b83SNavdeep Parhar if (advertise_map & ADVERTISED_100baseT_Full)
304c01f2b83SNavdeep Parhar adv |= ADVERTISE_100FULL;
305c01f2b83SNavdeep Parhar if (advertise_map & ADVERTISED_Pause)
306c01f2b83SNavdeep Parhar adv |= ADVERTISE_PAUSE_CAP;
307c01f2b83SNavdeep Parhar if (advertise_map & ADVERTISED_Asym_Pause)
308c01f2b83SNavdeep Parhar adv |= ADVERTISE_PAUSE_ASYM;
309c01f2b83SNavdeep Parhar err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_100M_CTRL, 0xfe0, adv);
310c01f2b83SNavdeep Parhar
311c01f2b83SNavdeep Parhar return (err);
312c01f2b83SNavdeep Parhar }
313c01f2b83SNavdeep Parhar
314c01f2b83SNavdeep Parhar static int
aq100x_set_loopback(struct cphy * phy,int mmd,int dir,int enable)315c01f2b83SNavdeep Parhar aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
316c01f2b83SNavdeep Parhar {
317c01f2b83SNavdeep Parhar return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
318c01f2b83SNavdeep Parhar BMCR_LOOPBACK, enable ? BMCR_LOOPBACK : 0);
319c01f2b83SNavdeep Parhar }
320c01f2b83SNavdeep Parhar
321c01f2b83SNavdeep Parhar static int
aq100x_set_speed_duplex(struct cphy * phy,int speed,int duplex)322c01f2b83SNavdeep Parhar aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
323c01f2b83SNavdeep Parhar {
324c01f2b83SNavdeep Parhar int err, set;
325c01f2b83SNavdeep Parhar
326c01f2b83SNavdeep Parhar if (speed == SPEED_100)
327c01f2b83SNavdeep Parhar set = BMCR_SPEED100;
328c01f2b83SNavdeep Parhar else if (speed == SPEED_1000)
329c01f2b83SNavdeep Parhar set = BMCR_SPEED1000;
330c01f2b83SNavdeep Parhar else if (speed == SPEED_10000)
331c01f2b83SNavdeep Parhar set = BMCR_SPEED1000 | BMCR_SPEED100;
332c01f2b83SNavdeep Parhar else
333c01f2b83SNavdeep Parhar return (EINVAL);
334c01f2b83SNavdeep Parhar
335c01f2b83SNavdeep Parhar if (duplex != DUPLEX_FULL)
336c01f2b83SNavdeep Parhar return (EINVAL);
337c01f2b83SNavdeep Parhar
338c01f2b83SNavdeep Parhar err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
339c01f2b83SNavdeep Parhar BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART, 0);
340c01f2b83SNavdeep Parhar if (err)
341c01f2b83SNavdeep Parhar return (err);
342c01f2b83SNavdeep Parhar
343c01f2b83SNavdeep Parhar err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
344c01f2b83SNavdeep Parhar BMCR_SPEED1000 | BMCR_SPEED100, set);
345c01f2b83SNavdeep Parhar if (err)
346c01f2b83SNavdeep Parhar return (err);
347c01f2b83SNavdeep Parhar
348c01f2b83SNavdeep Parhar return (0);
349c01f2b83SNavdeep Parhar }
350c01f2b83SNavdeep Parhar
351c01f2b83SNavdeep Parhar static int
aq100x_get_link_status(struct cphy * phy,int * link_state,int * speed,int * duplex,int * fc)352a5eb009bSNavdeep Parhar aq100x_get_link_status(struct cphy *phy, int *link_state, int *speed, int *duplex,
353c01f2b83SNavdeep Parhar int *fc)
354c01f2b83SNavdeep Parhar {
355c01f2b83SNavdeep Parhar int err;
356c01f2b83SNavdeep Parhar unsigned int v, link = 0;
357c01f2b83SNavdeep Parhar
358c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_PMA_PMD, AQ_LINK_STAT, &v);
359c01f2b83SNavdeep Parhar if (err)
360c01f2b83SNavdeep Parhar return (err);
361c01f2b83SNavdeep Parhar if (v == 0xffff || !(v & 1))
362c01f2b83SNavdeep Parhar goto done;
363c01f2b83SNavdeep Parhar
364c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_ANEG, MII_BMCR, &v);
365c01f2b83SNavdeep Parhar if (err)
366c01f2b83SNavdeep Parhar return (err);
367c01f2b83SNavdeep Parhar if (v & 0x8000)
368c01f2b83SNavdeep Parhar goto done;
369c01f2b83SNavdeep Parhar if (v & BMCR_ANENABLE) {
370c01f2b83SNavdeep Parhar
371c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_ANEG, 1, &v);
372c01f2b83SNavdeep Parhar if (err)
373c01f2b83SNavdeep Parhar return (err);
374c01f2b83SNavdeep Parhar if ((v & 0x20) == 0)
375c01f2b83SNavdeep Parhar goto done;
376c01f2b83SNavdeep Parhar
377c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_ANEG, AQ_ANEG_STAT, &v);
378c01f2b83SNavdeep Parhar if (err)
379c01f2b83SNavdeep Parhar return (err);
380c01f2b83SNavdeep Parhar
381c01f2b83SNavdeep Parhar if (speed) {
382c01f2b83SNavdeep Parhar switch (v & 0x6) {
383c01f2b83SNavdeep Parhar case 0x6: *speed = SPEED_10000;
384c01f2b83SNavdeep Parhar break;
385c01f2b83SNavdeep Parhar case 0x4: *speed = SPEED_1000;
386c01f2b83SNavdeep Parhar break;
387c01f2b83SNavdeep Parhar case 0x2: *speed = SPEED_100;
388c01f2b83SNavdeep Parhar break;
389c01f2b83SNavdeep Parhar case 0x0: *speed = SPEED_10;
390c01f2b83SNavdeep Parhar break;
391c01f2b83SNavdeep Parhar }
392c01f2b83SNavdeep Parhar }
393c01f2b83SNavdeep Parhar
394c01f2b83SNavdeep Parhar if (duplex)
395c01f2b83SNavdeep Parhar *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
396c01f2b83SNavdeep Parhar
397c01f2b83SNavdeep Parhar if (fc) {
398c01f2b83SNavdeep Parhar unsigned int lpa, adv;
399c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_ANEG, 0x13, &lpa);
400c01f2b83SNavdeep Parhar if (!err)
401c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_ANEG,
402c01f2b83SNavdeep Parhar AQ_100M_CTRL, &adv);
403c01f2b83SNavdeep Parhar if (err)
404c01f2b83SNavdeep Parhar return err;
405c01f2b83SNavdeep Parhar
406c01f2b83SNavdeep Parhar if (lpa & adv & ADVERTISE_PAUSE_CAP)
407c01f2b83SNavdeep Parhar *fc = PAUSE_RX | PAUSE_TX;
408c01f2b83SNavdeep Parhar else if (lpa & ADVERTISE_PAUSE_CAP &&
409c01f2b83SNavdeep Parhar lpa & ADVERTISE_PAUSE_ASYM &&
410c01f2b83SNavdeep Parhar adv & ADVERTISE_PAUSE_ASYM)
411c01f2b83SNavdeep Parhar *fc = PAUSE_TX;
412c01f2b83SNavdeep Parhar else if (lpa & ADVERTISE_PAUSE_ASYM &&
413c01f2b83SNavdeep Parhar adv & ADVERTISE_PAUSE_CAP)
414c01f2b83SNavdeep Parhar *fc = PAUSE_RX;
415c01f2b83SNavdeep Parhar else
416c01f2b83SNavdeep Parhar *fc = 0;
417c01f2b83SNavdeep Parhar }
418c01f2b83SNavdeep Parhar
419c01f2b83SNavdeep Parhar } else {
420c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
421c01f2b83SNavdeep Parhar if (err)
422c01f2b83SNavdeep Parhar return (err);
423c01f2b83SNavdeep Parhar
424c01f2b83SNavdeep Parhar v &= BMCR_SPEED1000 | BMCR_SPEED100;
425c01f2b83SNavdeep Parhar if (speed) {
426c01f2b83SNavdeep Parhar if (v == (BMCR_SPEED1000 | BMCR_SPEED100))
427c01f2b83SNavdeep Parhar *speed = SPEED_10000;
428c01f2b83SNavdeep Parhar else if (v == BMCR_SPEED1000)
429c01f2b83SNavdeep Parhar *speed = SPEED_1000;
430c01f2b83SNavdeep Parhar else if (v == BMCR_SPEED100)
431c01f2b83SNavdeep Parhar *speed = SPEED_100;
432c01f2b83SNavdeep Parhar else
433c01f2b83SNavdeep Parhar *speed = SPEED_10;
434c01f2b83SNavdeep Parhar }
435c01f2b83SNavdeep Parhar
436c01f2b83SNavdeep Parhar if (duplex)
437c01f2b83SNavdeep Parhar *duplex = DUPLEX_FULL;
438c01f2b83SNavdeep Parhar }
439c01f2b83SNavdeep Parhar
440c01f2b83SNavdeep Parhar link = 1;
441c01f2b83SNavdeep Parhar done:
442a5eb009bSNavdeep Parhar if (link_state)
443a5eb009bSNavdeep Parhar *link_state = link ? PHY_LINK_UP : PHY_LINK_DOWN;
444c01f2b83SNavdeep Parhar return (0);
445c01f2b83SNavdeep Parhar }
446c01f2b83SNavdeep Parhar
447c01f2b83SNavdeep Parhar static struct cphy_ops aq100x_ops = {
448c01f2b83SNavdeep Parhar .reset = aq100x_reset,
449c01f2b83SNavdeep Parhar .intr_enable = aq100x_intr_enable,
450c01f2b83SNavdeep Parhar .intr_disable = aq100x_intr_disable,
451c01f2b83SNavdeep Parhar .intr_clear = aq100x_intr_clear,
452c01f2b83SNavdeep Parhar .intr_handler = aq100x_intr_handler,
453c01f2b83SNavdeep Parhar .autoneg_enable = aq100x_autoneg_enable,
454c01f2b83SNavdeep Parhar .autoneg_restart = aq100x_autoneg_restart,
455c01f2b83SNavdeep Parhar .advertise = aq100x_advertise,
456c01f2b83SNavdeep Parhar .set_loopback = aq100x_set_loopback,
457c01f2b83SNavdeep Parhar .set_speed_duplex = aq100x_set_speed_duplex,
458c01f2b83SNavdeep Parhar .get_link_status = aq100x_get_link_status,
459c01f2b83SNavdeep Parhar .power_down = aq100x_power_down,
460c01f2b83SNavdeep Parhar };
461c01f2b83SNavdeep Parhar
462c01f2b83SNavdeep Parhar int
t3_aq100x_phy_prep(pinfo_t * pinfo,int phy_addr,const struct mdio_ops * mdio_ops)463c01f2b83SNavdeep Parhar t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr,
464c01f2b83SNavdeep Parhar const struct mdio_ops *mdio_ops)
465c01f2b83SNavdeep Parhar {
466c01f2b83SNavdeep Parhar struct cphy *phy = &pinfo->phy;
467c01f2b83SNavdeep Parhar unsigned int v, v2, gpio, wait;
468c01f2b83SNavdeep Parhar int err;
469c01f2b83SNavdeep Parhar adapter_t *adapter = pinfo->adapter;
470c01f2b83SNavdeep Parhar
471c01f2b83SNavdeep Parhar cphy_init(&pinfo->phy, adapter, pinfo, phy_addr, &aq100x_ops, mdio_ops,
472c01f2b83SNavdeep Parhar SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
473c01f2b83SNavdeep Parhar SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI |
474c01f2b83SNavdeep Parhar SUPPORTED_MISC_IRQ, "1000/10GBASE-T");
475c01f2b83SNavdeep Parhar
476c01f2b83SNavdeep Parhar /*
477c01f2b83SNavdeep Parhar * Hard reset the PHY.
478c01f2b83SNavdeep Parhar */
479c01f2b83SNavdeep Parhar gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
480c01f2b83SNavdeep Parhar t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
481c01f2b83SNavdeep Parhar msleep(1);
482c01f2b83SNavdeep Parhar t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
483c01f2b83SNavdeep Parhar
484c01f2b83SNavdeep Parhar /*
485c01f2b83SNavdeep Parhar * Give it enough time to load the firmware and get ready for mdio.
486c01f2b83SNavdeep Parhar */
487c01f2b83SNavdeep Parhar msleep(1000);
488c01f2b83SNavdeep Parhar wait = 500; /* in 10ms increments */
489c01f2b83SNavdeep Parhar do {
490c01f2b83SNavdeep Parhar err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
491c01f2b83SNavdeep Parhar if (err || v == 0xffff) {
492c01f2b83SNavdeep Parhar
493c01f2b83SNavdeep Parhar /* Allow prep_adapter to succeed when ffff is read */
494c01f2b83SNavdeep Parhar
495c01f2b83SNavdeep Parhar CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
496c01f2b83SNavdeep Parhar phy_addr, err, v);
497c01f2b83SNavdeep Parhar goto done;
498c01f2b83SNavdeep Parhar }
499c01f2b83SNavdeep Parhar
500c01f2b83SNavdeep Parhar v &= BMCR_RESET;
501c01f2b83SNavdeep Parhar if (v)
502c01f2b83SNavdeep Parhar msleep(10);
503c01f2b83SNavdeep Parhar } while (v && --wait);
504c01f2b83SNavdeep Parhar if (v) {
505c01f2b83SNavdeep Parhar CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
506c01f2b83SNavdeep Parhar phy_addr, v);
507c01f2b83SNavdeep Parhar
508c01f2b83SNavdeep Parhar goto done; /* let prep_adapter succeed */
509c01f2b83SNavdeep Parhar }
510c01f2b83SNavdeep Parhar
511c01f2b83SNavdeep Parhar /* Firmware version check. */
512c01f2b83SNavdeep Parhar (void) mdio_read(phy, MDIO_DEV_VEND1, AQ_FW_VERSION, &v);
513c01f2b83SNavdeep Parhar if (v < 0x115)
514c01f2b83SNavdeep Parhar CH_WARN(adapter, "PHY%d: unknown firmware %d.%d\n", phy_addr,
515c01f2b83SNavdeep Parhar v >> 8, v & 0xff);
516c01f2b83SNavdeep Parhar
517c01f2b83SNavdeep Parhar /* The PHY should start in really-low-power mode. */
518c01f2b83SNavdeep Parhar (void) mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
519c01f2b83SNavdeep Parhar if ((v & BMCR_PDOWN) == 0)
520c01f2b83SNavdeep Parhar CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
521c01f2b83SNavdeep Parhar phy_addr);
522c01f2b83SNavdeep Parhar
523c01f2b83SNavdeep Parhar /*
524c01f2b83SNavdeep Parhar * Verify XAUI and 1000-X settings, but let prep succeed no matter what.
525c01f2b83SNavdeep Parhar */
526c01f2b83SNavdeep Parhar v = v2 = 0;
527c01f2b83SNavdeep Parhar (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_RX_CFG, &v);
528c01f2b83SNavdeep Parhar (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_TX_CFG, &v2);
529c01f2b83SNavdeep Parhar if (v != 0x1b || v2 != 0x1b)
530c01f2b83SNavdeep Parhar CH_WARN(adapter, "PHY%d: incorrect XAUI settings "
531c01f2b83SNavdeep Parhar "(0x%x, 0x%x).\n", phy_addr, v, v2);
532c01f2b83SNavdeep Parhar v = 0;
533c01f2b83SNavdeep Parhar (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_KX_CFG, &v);
534c01f2b83SNavdeep Parhar if ((v & 0xf) != 0xf)
535c01f2b83SNavdeep Parhar CH_WARN(adapter, "PHY%d: incorrect 1000-X settings "
536c01f2b83SNavdeep Parhar "(0x%x).\n", phy_addr, v);
537c01f2b83SNavdeep Parhar
538c01f2b83SNavdeep Parhar (void) aq100x_set_defaults(phy);
539c01f2b83SNavdeep Parhar done:
540c01f2b83SNavdeep Parhar return (err);
541c01f2b83SNavdeep Parhar }
542