xref: /illumos-gate/usr/src/uts/common/io/rtw/rtwphyio.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /*
6  * Copyright (c) 2004, 2005 David Young.  All rights reserved.
7  *
8  * Programmed for NetBSD by David Young.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of David Young may not be used to endorse or promote
19  *    products derived from this software without specific prior
20  *    written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL David
26  * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33  * OF SUCH DAMAGE.
34  */
35 /*
36  * Control input/output with the Philips SA2400 RF front-end and
37  * the baseband processor built into the Realtek RTL8180.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 
43 #include <sys/param.h>
44 #include <sys/types.h>
45 #include <sys/signal.h>
46 #include <sys/stream.h>
47 #include <sys/termio.h>
48 #include <sys/errno.h>
49 #include <sys/file.h>
50 #include <sys/cmn_err.h>
51 #include <sys/stropts.h>
52 #include <sys/strtty.h>
53 #include <sys/kbio.h>
54 #include <sys/cred.h>
55 #include <sys/stat.h>
56 #include <sys/consdev.h>
57 #include <sys/kmem.h>
58 #include <sys/modctl.h>
59 #include <sys/ddi.h>
60 #include <sys/sunddi.h>
61 #include <sys/pci.h>
62 #include <sys/errno.h>
63 #include <sys/gld.h>
64 #include <sys/dlpi.h>
65 #include <sys/ethernet.h>
66 #include <sys/list.h>
67 #include <sys/byteorder.h>
68 #include <sys/strsun.h>
69 #include <inet/common.h>
70 #include <inet/nd.h>
71 #include <inet/mi.h>
72 
73 
74 #include "rtwreg.h"
75 #include "max2820reg.h"
76 #include "sa2400reg.h"
77 #include "si4136reg.h"
78 #include "rtwvar.h"
79 #include "rtwphyio.h"
80 #include "rtwphy.h"
81 
82 static int rtw_macbangbits_timeout = 100;
83 
84 uint8_t
85 rtw_bbp_read(struct rtw_regs *regs, uint_t addr)
86 {
87 	RTW_WRITE(regs, RTW_BB,
88 	    LSHIFT(addr, RTW_BB_ADDR_MASK) | RTW_BB_RD_MASK | RTW_BB_WR_MASK);
89 	DELAY(10);
90 	RTW_WBR(regs, RTW_BB, RTW_BB);
91 	return (MASK_AND_RSHIFT(RTW_READ(regs, RTW_BB), RTW_BB_RD_MASK));
92 }
93 
94 int
95 rtw_bbp_write(struct rtw_regs *regs, uint_t addr, uint_t val)
96 {
97 #define	BBP_WRITE_ITERS	50
98 #define	BBP_WRITE_DELAY	1
99 	int i;
100 	uint32_t wrbbp, rdbbp;
101 
102 	RTW_DPRINTF(RTW_DEBUG_PHYIO,
103 	    "%s: bbp[%u] <- %u\n", __func__, addr, val);
104 
105 	wrbbp = LSHIFT(addr, RTW_BB_ADDR_MASK) | RTW_BB_WREN |
106 	    LSHIFT(val, RTW_BB_WR_MASK) | RTW_BB_RD_MASK,
107 	    rdbbp = LSHIFT(addr, RTW_BB_ADDR_MASK) |
108 	    RTW_BB_WR_MASK | RTW_BB_RD_MASK;
109 
110 	RTW_DPRINTF(RTW_DEBUG_PHYIO,
111 	    "%s: rdbbp = %08x, wrbbp = %08x\n", __func__, rdbbp, wrbbp);
112 
113 	for (i = BBP_WRITE_ITERS; --i >= 0; ) {
114 		RTW_RBW(regs, RTW_BB, RTW_BB);
115 		RTW_WRITE(regs, RTW_BB, wrbbp);
116 		RTW_SYNC(regs, RTW_BB, RTW_BB);
117 		RTW_WRITE(regs, RTW_BB, rdbbp);
118 		RTW_SYNC(regs, RTW_BB, RTW_BB);
119 		DELAY(BBP_WRITE_DELAY);	/* 1 microsecond */
120 		if (MASK_AND_RSHIFT(RTW_READ(regs, RTW_BB),
121 		    RTW_BB_RD_MASK) == val) {
122 			RTW_DPRINTF(RTW_DEBUG_PHYIO,
123 			    "%s: finished in %dus\n", __func__,
124 			    BBP_WRITE_DELAY * (BBP_WRITE_ITERS - i));
125 			return (0);
126 		}
127 		DELAY(BBP_WRITE_DELAY);	/* again */
128 	}
129 	cmn_err(CE_NOTE, "%s: timeout\n", __func__);
130 	return (-1);
131 }
132 
133 /*
134  * Help rtw_rf_hostwrite bang bits to RF over 3-wire interface.
135  */
136 static void
137 rtw_rf_hostbangbits(struct rtw_regs *regs, uint32_t bits, int lo_to_hi,
138     uint_t nbits)
139 {
140 	int i;
141 	uint32_t mask, reg;
142 
143 	RTW_DPRINTF(RTW_DEBUG_PHYIO,
144 	    "%s: %u bits, %08x, %s\n", __func__, nbits, bits,
145 	    (lo_to_hi) ? "lo to hi" : "hi to lo");
146 
147 	reg = RTW_PHYCFG_HST;
148 	RTW_WRITE(regs, RTW_PHYCFG, reg);
149 	RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
150 
151 	if (lo_to_hi)
152 		mask = 0x1;
153 	else
154 		mask = 1 << (nbits - 1);
155 
156 	for (i = 0; i < nbits; i++) {
157 		RTW_DPRINTF(RTW_DEBUG_PHYBITIO,
158 		    "%s: bits %08x mask %08x -> bit %08x\n",
159 		    __func__, bits, mask, bits & mask);
160 
161 		if ((bits & mask) != 0)
162 			reg |= RTW_PHYCFG_HST_DATA;
163 		else
164 			reg &= ~RTW_PHYCFG_HST_DATA;
165 
166 		reg |= RTW_PHYCFG_HST_CLK;
167 		RTW_WRITE(regs, RTW_PHYCFG, reg);
168 		RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
169 
170 		DELAY(2);	/* arbitrary delay */
171 
172 		reg &= ~RTW_PHYCFG_HST_CLK;
173 		RTW_WRITE(regs, RTW_PHYCFG, reg);
174 		RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
175 
176 		if (lo_to_hi)
177 			mask <<= 1;
178 		else
179 			mask >>= 1;
180 	}
181 
182 	reg |= RTW_PHYCFG_HST_EN;
183 	RTW_WRITE(regs, RTW_PHYCFG, reg);
184 	RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
185 }
186 
187 /*
188  * Help rtw_rf_macwrite: tell MAC to bang bits to RF over the 3-wire
189  * interface.
190  */
191 static int
192 rtw_rf_macbangbits(struct rtw_regs *regs, uint32_t reg)
193 {
194 	int i;
195 
196 	RTW_DPRINTF(RTW_DEBUG_PHY, "%s: %08x\n", __func__, reg);
197 
198 	RTW_WRITE(regs, RTW_PHYCFG, RTW_PHYCFG_MAC_POLL | reg);
199 
200 	RTW_WBR(regs, RTW_PHYCFG, RTW_PHYCFG);
201 
202 	for (i = rtw_macbangbits_timeout; --i >= 0; DELAY(1)) {
203 		if ((RTW_READ(regs, RTW_PHYCFG) & RTW_PHYCFG_MAC_POLL) == 0) {
204 			RTW_DPRINTF(RTW_DEBUG_PHY,
205 			    "%s: finished in %dus\n", __func__,
206 			    rtw_macbangbits_timeout - i);
207 			return (0);
208 		}
209 		RTW_RBR(regs, RTW_PHYCFG, RTW_PHYCFG);	/* paranoia? */
210 	}
211 
212 	cmn_err(CE_NOTE, "%s: RTW_PHYCFG_MAC_POLL still set.\n", __func__);
213 	return (-1);
214 }
215 
216 /*ARGSUSED*/
217 static uint32_t
218 rtw_grf5101_host_crypt(uint_t addr, uint32_t val)
219 {
220 	/* TBD */
221 	return (0);
222 }
223 
224 static uint32_t
225 rtw_grf5101_mac_crypt(uint_t addr, uint32_t val)
226 {
227 	uint32_t data_and_addr;
228 #define	EXTRACT_NIBBLE(d, which) (((d) >> (4 * (which))) & 0xf)
229 	static uint8_t caesar[16] =
230 	{
231 		0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
232 		0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
233 	};
234 
235 	data_and_addr =  caesar[EXTRACT_NIBBLE(val, 2)] |
236 	    (caesar[EXTRACT_NIBBLE(val, 1)] <<  4) |
237 	    (caesar[EXTRACT_NIBBLE(val, 0)] <<  8) |
238 	    (caesar[(addr >> 1) & 0xf] << 12) |
239 	    ((addr & 0x1) << 16) |
240 	    (caesar[EXTRACT_NIBBLE(val, 3)] << 24);
241 	return (LSHIFT(data_and_addr, RTW_PHYCFG_MAC_PHILIPS_ADDR_MASK |
242 	    RTW_PHYCFG_MAC_PHILIPS_DATA_MASK));
243 #undef EXTRACT_NIBBLE
244 }
245 
246 static const char *
247 rtw_rfchipid_string(enum rtw_rfchipid rfchipid)
248 {
249 	switch (rfchipid) {
250 	case RTW_RFCHIPID_MAXIM:
251 		return ("Maxim");
252 	case RTW_RFCHIPID_PHILIPS:
253 		return ("Philips");
254 	case RTW_RFCHIPID_GCT:
255 		return ("GCT");
256 	case RTW_RFCHIPID_RFMD:
257 		return ("RFMD");
258 	case RTW_RFCHIPID_INTERSIL:
259 		return ("Intersil");
260 	default:
261 		return ("unknown");
262 	}
263 }
264 
265 /*
266  * Bang bits over the 3-wire interface.
267  */
268 int
269 rtw_rf_hostwrite(struct rtw_regs *regs, enum rtw_rfchipid rfchipid,
270     uint_t addr, uint32_t val)
271 {
272 	uint_t nbits;
273 	int lo_to_hi;
274 	uint32_t bits;
275 
276 	RTW_DPRINTF(RTW_DEBUG_PHYIO, "%s: %s[%u] <- %08x\n", __func__,
277 	    rtw_rfchipid_string(rfchipid), addr, val);
278 
279 	switch (rfchipid) {
280 	case RTW_RFCHIPID_MAXIM:
281 		nbits = 16;
282 		lo_to_hi = 0;
283 		bits = LSHIFT(val, MAX2820_TWI_DATA_MASK) |
284 		    LSHIFT(addr, MAX2820_TWI_ADDR_MASK);
285 		break;
286 	case RTW_RFCHIPID_PHILIPS:
287 		bits = LSHIFT(val, SA2400_TWI_DATA_MASK) |
288 		    LSHIFT(addr, SA2400_TWI_ADDR_MASK) | SA2400_TWI_WREN;
289 		nbits = 32;
290 		lo_to_hi = 1;
291 		break;
292 	case RTW_RFCHIPID_GCT:
293 	case RTW_RFCHIPID_RFMD:
294 		if (rfchipid == RTW_RFCHIPID_GCT)
295 			bits = rtw_grf5101_host_crypt(addr, val);
296 		else {
297 			bits = LSHIFT(val, SI4126_TWI_DATA_MASK) |
298 			    LSHIFT(addr, SI4126_TWI_ADDR_MASK);
299 		}
300 		nbits = 22;
301 		lo_to_hi = 0;
302 		break;
303 	case RTW_RFCHIPID_INTERSIL:
304 	default:
305 		cmn_err(CE_WARN, "%s: unknown rfchipid %d\n",
306 		    __func__, rfchipid);
307 		return (-1);
308 	}
309 
310 	rtw_rf_hostbangbits(regs, bits, lo_to_hi, nbits);
311 
312 	return (0);
313 }
314 
315 static uint32_t
316 rtw_maxim_swizzle(uint_t addr, uint32_t val)
317 {
318 	uint32_t hidata, lodata;
319 
320 	lodata = MASK_AND_RSHIFT(val, RTW_MAXIM_LODATA_MASK);
321 	hidata = MASK_AND_RSHIFT(val, RTW_MAXIM_HIDATA_MASK);
322 	return (LSHIFT(lodata, RTW_PHYCFG_MAC_MAXIM_LODATA_MASK) |
323 	    LSHIFT(hidata, RTW_PHYCFG_MAC_MAXIM_HIDATA_MASK) |
324 	    LSHIFT(addr, RTW_PHYCFG_MAC_MAXIM_ADDR_MASK));
325 }
326 
327 /*
328  * Tell the MAC what to bang over the 3-wire interface.
329  */
330 int
331 rtw_rf_macwrite(struct rtw_regs *regs, enum rtw_rfchipid rfchipid,
332     uint_t addr, uint32_t val)
333 {
334 	uint32_t reg;
335 
336 	RTW_DPRINTF(RTW_DEBUG_PHYIO, "%s: %s[%u] <- %08x\n", __func__,
337 	    rtw_rfchipid_string(rfchipid), addr, val);
338 
339 	switch (rfchipid) {
340 	case RTW_RFCHIPID_GCT:
341 		reg = rtw_grf5101_mac_crypt(addr, val);
342 		break;
343 	case RTW_RFCHIPID_MAXIM:
344 		reg = rtw_maxim_swizzle(addr, val);
345 		break;
346 	default:
347 	case RTW_RFCHIPID_PHILIPS:
348 
349 		reg = LSHIFT(addr, RTW_PHYCFG_MAC_PHILIPS_ADDR_MASK) |
350 		    LSHIFT(val, RTW_PHYCFG_MAC_PHILIPS_DATA_MASK);
351 	}
352 
353 	switch (rfchipid) {
354 	case RTW_RFCHIPID_GCT:
355 	case RTW_RFCHIPID_MAXIM:
356 	case RTW_RFCHIPID_RFMD:
357 		reg |= RTW_PHYCFG_MAC_RFTYPE_RFMD;
358 		break;
359 	case RTW_RFCHIPID_INTERSIL:
360 		reg |= RTW_PHYCFG_MAC_RFTYPE_INTERSIL;
361 		break;
362 	case RTW_RFCHIPID_PHILIPS:
363 		reg |= RTW_PHYCFG_MAC_RFTYPE_PHILIPS;
364 		break;
365 	default:
366 		cmn_err(CE_WARN, "%s: unknown rfchipid %d\n",
367 		    __func__, rfchipid);
368 		return (-1);
369 	}
370 
371 	return (rtw_rf_macbangbits(regs, reg));
372 }
373