xref: /illumos-gate/usr/src/uts/common/io/atge/atge_mii.c (revision 0eb090a7)
1 /*
2  * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/mii.h>
29 #include <sys/miiregs.h>
30 
31 #include "atge.h"
32 #include "atge_cmn_reg.h"
33 #include "atge_l1e_reg.h"
34 #include "atge_l1_reg.h"
35 
36 uint16_t
37 atge_mii_read(void *arg, uint8_t phy, uint8_t reg)
38 {
39 	atge_t	*atgep = arg;
40 	uint32_t v;
41 	int i;
42 
43 	mutex_enter(&atgep->atge_mii_lock);
44 
45 	OUTL(atgep, ATGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ |
46 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
47 
48 	for (i = PHY_TIMEOUT; i > 0; i--) {
49 		drv_usecwait(5);
50 		v = INL(atgep, ATGE_MDIO);
51 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
52 			break;
53 	}
54 
55 	mutex_exit(&atgep->atge_mii_lock);
56 
57 	if (i == 0) {
58 		atge_error(atgep->atge_dip, "PHY (%d) read timeout : %d",
59 		    phy, reg);
60 
61 		return (0xffff);
62 	}
63 
64 	/*
65 	 * Some fast ethernet chips may not be able to auto-nego with
66 	 * switches even though they have 1000T based PHY. Hence we mask
67 	 * 1000T based capabilities.
68 	 */
69 	if (atgep->atge_flags & ATGE_FLAG_FASTETHER) {
70 		if (reg == MII_STATUS)
71 			v &= ~MII_STATUS_EXTSTAT;
72 		else if (reg == MII_EXTSTATUS)
73 			v = 0;
74 	}
75 
76 	return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
77 }
78 
79 void
80 atge_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
81 {
82 	atge_t	*atgep = arg;
83 	uint32_t v;
84 	int i;
85 
86 	mutex_enter(&atgep->atge_mii_lock);
87 
88 	OUTL(atgep, ATGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE |
89 	    (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT |
90 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
91 
92 	for (i = PHY_TIMEOUT; i > 0; i--) {
93 		drv_usecwait(1);
94 		v = INL(atgep, ATGE_MDIO);
95 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
96 			break;
97 	}
98 
99 	mutex_exit(&atgep->atge_mii_lock);
100 
101 	if (i == 0) {
102 		atge_error(atgep->atge_dip, "PHY (%d) write timeout:reg %d,"
103 		    "  val :%d", phy, reg, val);
104 	}
105 }
106 
107 void
108 atge_l1e_mii_reset(void *arg)
109 {
110 	atge_t *atgep = arg;
111 	int phyaddr;
112 
113 	phyaddr = mii_get_addr(atgep->atge_mii);
114 
115 	OUTW(atgep, ATGE_GPHY_CTRL,
116 	    GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE | GPHY_CTRL_SEL_ANA_RESET |
117 	    GPHY_CTRL_PHY_PLL_ON);
118 	drv_usecwait(1000);
119 
120 	OUTW(atgep, ATGE_GPHY_CTRL,
121 	    GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE |
122 	    GPHY_CTRL_SEL_ANA_RESET | GPHY_CTRL_PHY_PLL_ON);
123 	drv_usecwait(1000);
124 
125 	/*
126 	 * Some fast ethernet chips may not be able to auto-nego with
127 	 * switches even though they have 1000T based PHY. Hence we need
128 	 * to write 0 to MII_MSCONTROL control register.
129 	 */
130 	if (atgep->atge_flags & ATGE_FLAG_FASTETHER)
131 		atge_mii_write(atgep, phyaddr, MII_MSCONTROL, 0x0);
132 
133 	/* Enable hibernation mode. */
134 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x0B);
135 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0xBC00);
136 
137 	/* Set Class A/B for all modes. */
138 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x00);
139 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x02EF);
140 
141 	/* Enable 10BT power saving. */
142 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x12);
143 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x4C04);
144 
145 	/* Adjust 1000T power. */
146 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x04);
147 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x8BBB);
148 
149 	/* 10BT center tap voltage. */
150 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x05);
151 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x2C46);
152 	drv_usecwait(1000);
153 }
154 
155 void
156 atge_l1_mii_reset(void *arg)
157 {
158 	atge_t *atgep = arg;
159 	int linkup, i;
160 	uint16_t reg, pn;
161 	int phyaddr;
162 
163 	phyaddr = mii_get_addr(atgep->atge_mii);
164 
165 	OUTL(atgep, ATGE_GPHY_CTRL, GPHY_CTRL_RST);
166 	drv_usecwait(1000);
167 
168 	OUTL(atgep, ATGE_GPHY_CTRL, GPHY_CTRL_CLR);
169 	drv_usecwait(1000);
170 
171 	atge_mii_write(atgep, phyaddr, MII_CONTROL, MII_CONTROL_RESET);
172 
173 	for (linkup = 0, pn = 0; pn < 4; pn++) {
174 		atge_mii_write(atgep, phyaddr, ATPHY_CDTC,
175 		    (pn << PHY_CDTC_POFF) | PHY_CDTC_ENB);
176 
177 		for (i = 200; i > 0; i--) {
178 			drv_usecwait(1000);
179 
180 			reg = atge_mii_read(atgep, phyaddr, ATPHY_CDTC);
181 
182 			if ((reg & PHY_CDTC_ENB) == 0)
183 				break;
184 		}
185 
186 		drv_usecwait(1000);
187 
188 		reg = atge_mii_read(atgep, phyaddr, ATPHY_CDTS);
189 
190 		if ((reg & PHY_CDTS_STAT_MASK) != PHY_CDTS_STAT_OPEN) {
191 			linkup++;
192 			break;
193 		}
194 	}
195 
196 	atge_mii_write(atgep, phyaddr, MII_CONTROL,
197 	    MII_CONTROL_RESET |  MII_CONTROL_ANE | MII_CONTROL_RSAN);
198 
199 	if (linkup == 0) {
200 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0);
201 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x124E);
202 
203 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 1);
204 		reg = atge_mii_read(atgep, phyaddr, ATPHY_DBG_DATA);
205 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, reg | 0x03);
206 
207 		drv_usecwait(1500 * 1000);
208 
209 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0);
210 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x024E);
211 	}
212 }
213