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