xref: /onnv-gate/usr/src/uts/common/io/rtw/rtwphyio.c (revision 10448:fe6b44e693c2)
14689Sql147931 /*
2*10448SMikore.Li@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
34689Sql147931  * Use is subject to license terms.
44689Sql147931  */
54689Sql147931 /*
64689Sql147931  * Copyright (c) 2004, 2005 David Young.  All rights reserved.
74689Sql147931  *
84689Sql147931  * Programmed for NetBSD by David Young.
94689Sql147931  *
104689Sql147931  * Redistribution and use in source and binary forms, with or without
114689Sql147931  * modification, are permitted provided that the following conditions
124689Sql147931  * are met:
134689Sql147931  * 1. Redistributions of source code must retain the above copyright
144689Sql147931  *    notice, this list of conditions and the following disclaimer.
154689Sql147931  * 2. Redistributions in binary form must reproduce the above copyright
164689Sql147931  *    notice, this list of conditions and the following disclaimer in the
174689Sql147931  *    documentation and/or other materials provided with the distribution.
184689Sql147931  * 3. The name of David Young may not be used to endorse or promote
194689Sql147931  *    products derived from this software without specific prior
204689Sql147931  *    written permission.
214689Sql147931  *
224689Sql147931  * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
234689Sql147931  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
244689Sql147931  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
254689Sql147931  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL David
264689Sql147931  * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
274689Sql147931  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
284689Sql147931  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
294689Sql147931  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
304689Sql147931  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
314689Sql147931  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
324689Sql147931  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
334689Sql147931  * OF SUCH DAMAGE.
344689Sql147931  */
354689Sql147931 /*
364689Sql147931  * Control input/output with the Philips SA2400 RF front-end and
374689Sql147931  * the baseband processor built into the Realtek RTL8180.
384689Sql147931  */
394689Sql147931 #include <sys/types.h>
40*10448SMikore.Li@Sun.COM #include <sys/sysmacros.h>
414689Sql147931 #include "rtwreg.h"
424689Sql147931 #include "max2820reg.h"
434689Sql147931 #include "sa2400reg.h"
444689Sql147931 #include "si4136reg.h"
454689Sql147931 #include "rtwvar.h"
464689Sql147931 #include "rtwphyio.h"
474689Sql147931 #include "rtwphy.h"
484689Sql147931 
494689Sql147931 static int rtw_macbangbits_timeout = 100;
504689Sql147931 
514689Sql147931 uint8_t
rtw_bbp_read(struct rtw_regs * regs,uint_t addr)524689Sql147931 rtw_bbp_read(struct rtw_regs *regs, uint_t addr)
534689Sql147931 {
544689Sql147931 	RTW_WRITE(regs, RTW_BB,
554689Sql147931 	    LSHIFT(addr, RTW_BB_ADDR_MASK) | RTW_BB_RD_MASK | RTW_BB_WR_MASK);
564689Sql147931 	DELAY(10);
574689Sql147931 	RTW_WBR(regs, RTW_BB, RTW_BB);
584689Sql147931 	return (MASK_AND_RSHIFT(RTW_READ(regs, RTW_BB), RTW_BB_RD_MASK));
594689Sql147931 }
604689Sql147931 
614689Sql147931 int
rtw_bbp_write(struct rtw_regs * regs,uint_t addr,uint_t val)624689Sql147931 rtw_bbp_write(struct rtw_regs *regs, uint_t addr, uint_t val)
634689Sql147931 {
644689Sql147931 #define	BBP_WRITE_ITERS	50
654689Sql147931 #define	BBP_WRITE_DELAY	1
664689Sql147931 	int i;
674689Sql147931 	uint32_t wrbbp, rdbbp;
684689Sql147931 
694689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHYIO,
704689Sql147931 	    "%s: bbp[%u] <- %u\n", __func__, addr, val);
714689Sql147931 
724689Sql147931 	wrbbp = LSHIFT(addr, RTW_BB_ADDR_MASK) | RTW_BB_WREN |
734689Sql147931 	    LSHIFT(val, RTW_BB_WR_MASK) | RTW_BB_RD_MASK,
744689Sql147931 	    rdbbp = LSHIFT(addr, RTW_BB_ADDR_MASK) |
754689Sql147931 	    RTW_BB_WR_MASK | RTW_BB_RD_MASK;
764689Sql147931 
774689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHYIO,
784689Sql147931 	    "%s: rdbbp = %08x, wrbbp = %08x\n", __func__, rdbbp, wrbbp);
794689Sql147931 
804689Sql147931 	for (i = BBP_WRITE_ITERS; --i >= 0; ) {
814689Sql147931 		RTW_RBW(regs, RTW_BB, RTW_BB);
824689Sql147931 		RTW_WRITE(regs, RTW_BB, wrbbp);
834689Sql147931 		RTW_SYNC(regs, RTW_BB, RTW_BB);
844689Sql147931 		RTW_WRITE(regs, RTW_BB, rdbbp);
854689Sql147931 		RTW_SYNC(regs, RTW_BB, RTW_BB);
864689Sql147931 		DELAY(BBP_WRITE_DELAY);	/* 1 microsecond */
874689Sql147931 		if (MASK_AND_RSHIFT(RTW_READ(regs, RTW_BB),
884689Sql147931 		    RTW_BB_RD_MASK) == val) {
894689Sql147931 			RTW_DPRINTF(RTW_DEBUG_PHYIO,
904689Sql147931 			    "%s: finished in %dus\n", __func__,
914689Sql147931 			    BBP_WRITE_DELAY * (BBP_WRITE_ITERS - i));
924689Sql147931 			return (0);
934689Sql147931 		}
944689Sql147931 		DELAY(BBP_WRITE_DELAY);	/* again */
954689Sql147931 	}
964689Sql147931 	cmn_err(CE_NOTE, "%s: timeout\n", __func__);
974689Sql147931 	return (-1);
984689Sql147931 }
994689Sql147931 
1004689Sql147931 /*
1014689Sql147931  * Help rtw_rf_hostwrite bang bits to RF over 3-wire interface.
1024689Sql147931  */
1034689Sql147931 static void
rtw_rf_hostbangbits(struct rtw_regs * regs,uint32_t bits,int lo_to_hi,uint_t nbits)1044689Sql147931 rtw_rf_hostbangbits(struct rtw_regs *regs, uint32_t bits, int lo_to_hi,
1054689Sql147931     uint_t nbits)
1064689Sql147931 {
1074689Sql147931 	int i;
1084689Sql147931 	uint32_t mask, reg;
1094689Sql147931 
1104689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHYIO,
1114689Sql147931 	    "%s: %u bits, %08x, %s\n", __func__, nbits, bits,
1124689Sql147931 	    (lo_to_hi) ? "lo to hi" : "hi to lo");
1134689Sql147931 
1144689Sql147931 	reg = RTW_PHYCFG_HST;
1154689Sql147931 	RTW_WRITE(regs, RTW_PHYCFG, reg);
1164689Sql147931 	RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
1174689Sql147931 
1184689Sql147931 	if (lo_to_hi)
1194689Sql147931 		mask = 0x1;
1204689Sql147931 	else
1214689Sql147931 		mask = 1 << (nbits - 1);
1224689Sql147931 
1234689Sql147931 	for (i = 0; i < nbits; i++) {
1244689Sql147931 		RTW_DPRINTF(RTW_DEBUG_PHYBITIO,
1254689Sql147931 		    "%s: bits %08x mask %08x -> bit %08x\n",
1264689Sql147931 		    __func__, bits, mask, bits & mask);
1274689Sql147931 
1284689Sql147931 		if ((bits & mask) != 0)
1294689Sql147931 			reg |= RTW_PHYCFG_HST_DATA;
1304689Sql147931 		else
1314689Sql147931 			reg &= ~RTW_PHYCFG_HST_DATA;
1324689Sql147931 
1334689Sql147931 		reg |= RTW_PHYCFG_HST_CLK;
1344689Sql147931 		RTW_WRITE(regs, RTW_PHYCFG, reg);
1354689Sql147931 		RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
1364689Sql147931 
1374689Sql147931 		DELAY(2);	/* arbitrary delay */
1384689Sql147931 
1394689Sql147931 		reg &= ~RTW_PHYCFG_HST_CLK;
1404689Sql147931 		RTW_WRITE(regs, RTW_PHYCFG, reg);
1414689Sql147931 		RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
1424689Sql147931 
1434689Sql147931 		if (lo_to_hi)
1444689Sql147931 			mask <<= 1;
1454689Sql147931 		else
1464689Sql147931 			mask >>= 1;
1474689Sql147931 	}
1484689Sql147931 
1494689Sql147931 	reg |= RTW_PHYCFG_HST_EN;
1504689Sql147931 	RTW_WRITE(regs, RTW_PHYCFG, reg);
1514689Sql147931 	RTW_SYNC(regs, RTW_PHYCFG, RTW_PHYCFG);
1524689Sql147931 }
1534689Sql147931 
1544689Sql147931 /*
1554689Sql147931  * Help rtw_rf_macwrite: tell MAC to bang bits to RF over the 3-wire
1564689Sql147931  * interface.
1574689Sql147931  */
1584689Sql147931 static int
rtw_rf_macbangbits(struct rtw_regs * regs,uint32_t reg)1594689Sql147931 rtw_rf_macbangbits(struct rtw_regs *regs, uint32_t reg)
1604689Sql147931 {
1614689Sql147931 	int i;
1624689Sql147931 
1634689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHY, "%s: %08x\n", __func__, reg);
1644689Sql147931 
1654689Sql147931 	RTW_WRITE(regs, RTW_PHYCFG, RTW_PHYCFG_MAC_POLL | reg);
1664689Sql147931 
1674689Sql147931 	RTW_WBR(regs, RTW_PHYCFG, RTW_PHYCFG);
1684689Sql147931 
1694689Sql147931 	for (i = rtw_macbangbits_timeout; --i >= 0; DELAY(1)) {
1704689Sql147931 		if ((RTW_READ(regs, RTW_PHYCFG) & RTW_PHYCFG_MAC_POLL) == 0) {
1714689Sql147931 			RTW_DPRINTF(RTW_DEBUG_PHY,
1724689Sql147931 			    "%s: finished in %dus\n", __func__,
1734689Sql147931 			    rtw_macbangbits_timeout - i);
1744689Sql147931 			return (0);
1754689Sql147931 		}
1764689Sql147931 		RTW_RBR(regs, RTW_PHYCFG, RTW_PHYCFG);	/* paranoia? */
1774689Sql147931 	}
1784689Sql147931 
1794689Sql147931 	cmn_err(CE_NOTE, "%s: RTW_PHYCFG_MAC_POLL still set.\n", __func__);
1804689Sql147931 	return (-1);
1814689Sql147931 }
1824689Sql147931 
1834689Sql147931 /*ARGSUSED*/
1844689Sql147931 static uint32_t
rtw_grf5101_host_crypt(uint_t addr,uint32_t val)1854689Sql147931 rtw_grf5101_host_crypt(uint_t addr, uint32_t val)
1864689Sql147931 {
1874689Sql147931 	/* TBD */
1884689Sql147931 	return (0);
1894689Sql147931 }
1904689Sql147931 
1914689Sql147931 static uint32_t
rtw_grf5101_mac_crypt(uint_t addr,uint32_t val)1924689Sql147931 rtw_grf5101_mac_crypt(uint_t addr, uint32_t val)
1934689Sql147931 {
1944689Sql147931 	uint32_t data_and_addr;
1954689Sql147931 #define	EXTRACT_NIBBLE(d, which) (((d) >> (4 * (which))) & 0xf)
1964689Sql147931 	static uint8_t caesar[16] =
1974689Sql147931 	{
1984689Sql147931 		0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
1994689Sql147931 		0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
2004689Sql147931 	};
2014689Sql147931 
2024689Sql147931 	data_and_addr =  caesar[EXTRACT_NIBBLE(val, 2)] |
2034689Sql147931 	    (caesar[EXTRACT_NIBBLE(val, 1)] <<  4) |
2044689Sql147931 	    (caesar[EXTRACT_NIBBLE(val, 0)] <<  8) |
2054689Sql147931 	    (caesar[(addr >> 1) & 0xf] << 12) |
2064689Sql147931 	    ((addr & 0x1) << 16) |
2074689Sql147931 	    (caesar[EXTRACT_NIBBLE(val, 3)] << 24);
2084689Sql147931 	return (LSHIFT(data_and_addr, RTW_PHYCFG_MAC_PHILIPS_ADDR_MASK |
2094689Sql147931 	    RTW_PHYCFG_MAC_PHILIPS_DATA_MASK));
2104689Sql147931 #undef EXTRACT_NIBBLE
2114689Sql147931 }
2124689Sql147931 
2134689Sql147931 static const char *
rtw_rfchipid_string(enum rtw_rfchipid rfchipid)2144689Sql147931 rtw_rfchipid_string(enum rtw_rfchipid rfchipid)
2154689Sql147931 {
2164689Sql147931 	switch (rfchipid) {
2174689Sql147931 	case RTW_RFCHIPID_MAXIM:
2184689Sql147931 		return ("Maxim");
2194689Sql147931 	case RTW_RFCHIPID_PHILIPS:
2204689Sql147931 		return ("Philips");
2214689Sql147931 	case RTW_RFCHIPID_GCT:
2224689Sql147931 		return ("GCT");
2234689Sql147931 	case RTW_RFCHIPID_RFMD:
2244689Sql147931 		return ("RFMD");
2254689Sql147931 	case RTW_RFCHIPID_INTERSIL:
2264689Sql147931 		return ("Intersil");
2274689Sql147931 	default:
2284689Sql147931 		return ("unknown");
2294689Sql147931 	}
2304689Sql147931 }
2314689Sql147931 
2324689Sql147931 /*
2334689Sql147931  * Bang bits over the 3-wire interface.
2344689Sql147931  */
2354689Sql147931 int
rtw_rf_hostwrite(struct rtw_regs * regs,enum rtw_rfchipid rfchipid,uint_t addr,uint32_t val)2364689Sql147931 rtw_rf_hostwrite(struct rtw_regs *regs, enum rtw_rfchipid rfchipid,
2374689Sql147931     uint_t addr, uint32_t val)
2384689Sql147931 {
2394689Sql147931 	uint_t nbits;
2404689Sql147931 	int lo_to_hi;
2414689Sql147931 	uint32_t bits;
2424689Sql147931 
2434689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHYIO, "%s: %s[%u] <- %08x\n", __func__,
2444689Sql147931 	    rtw_rfchipid_string(rfchipid), addr, val);
2454689Sql147931 
2464689Sql147931 	switch (rfchipid) {
2474689Sql147931 	case RTW_RFCHIPID_MAXIM:
2484689Sql147931 		nbits = 16;
2494689Sql147931 		lo_to_hi = 0;
2504689Sql147931 		bits = LSHIFT(val, MAX2820_TWI_DATA_MASK) |
2514689Sql147931 		    LSHIFT(addr, MAX2820_TWI_ADDR_MASK);
2524689Sql147931 		break;
2534689Sql147931 	case RTW_RFCHIPID_PHILIPS:
2544689Sql147931 		bits = LSHIFT(val, SA2400_TWI_DATA_MASK) |
2554689Sql147931 		    LSHIFT(addr, SA2400_TWI_ADDR_MASK) | SA2400_TWI_WREN;
2564689Sql147931 		nbits = 32;
2574689Sql147931 		lo_to_hi = 1;
2584689Sql147931 		break;
2594689Sql147931 	case RTW_RFCHIPID_GCT:
2604689Sql147931 	case RTW_RFCHIPID_RFMD:
2614689Sql147931 		if (rfchipid == RTW_RFCHIPID_GCT)
2624689Sql147931 			bits = rtw_grf5101_host_crypt(addr, val);
2634689Sql147931 		else {
2644689Sql147931 			bits = LSHIFT(val, SI4126_TWI_DATA_MASK) |
2654689Sql147931 			    LSHIFT(addr, SI4126_TWI_ADDR_MASK);
2664689Sql147931 		}
2674689Sql147931 		nbits = 22;
2684689Sql147931 		lo_to_hi = 0;
2694689Sql147931 		break;
2704689Sql147931 	case RTW_RFCHIPID_INTERSIL:
2714689Sql147931 	default:
2724689Sql147931 		cmn_err(CE_WARN, "%s: unknown rfchipid %d\n",
2734689Sql147931 		    __func__, rfchipid);
2744689Sql147931 		return (-1);
2754689Sql147931 	}
2764689Sql147931 
2774689Sql147931 	rtw_rf_hostbangbits(regs, bits, lo_to_hi, nbits);
2784689Sql147931 
2794689Sql147931 	return (0);
2804689Sql147931 }
2814689Sql147931 
2824689Sql147931 static uint32_t
rtw_maxim_swizzle(uint_t addr,uint32_t val)2834689Sql147931 rtw_maxim_swizzle(uint_t addr, uint32_t val)
2844689Sql147931 {
2854689Sql147931 	uint32_t hidata, lodata;
2864689Sql147931 
2874689Sql147931 	lodata = MASK_AND_RSHIFT(val, RTW_MAXIM_LODATA_MASK);
2884689Sql147931 	hidata = MASK_AND_RSHIFT(val, RTW_MAXIM_HIDATA_MASK);
2894689Sql147931 	return (LSHIFT(lodata, RTW_PHYCFG_MAC_MAXIM_LODATA_MASK) |
2904689Sql147931 	    LSHIFT(hidata, RTW_PHYCFG_MAC_MAXIM_HIDATA_MASK) |
2914689Sql147931 	    LSHIFT(addr, RTW_PHYCFG_MAC_MAXIM_ADDR_MASK));
2924689Sql147931 }
2934689Sql147931 
2944689Sql147931 /*
2954689Sql147931  * Tell the MAC what to bang over the 3-wire interface.
2964689Sql147931  */
2974689Sql147931 int
rtw_rf_macwrite(struct rtw_regs * regs,enum rtw_rfchipid rfchipid,uint_t addr,uint32_t val)2984689Sql147931 rtw_rf_macwrite(struct rtw_regs *regs, enum rtw_rfchipid rfchipid,
2994689Sql147931     uint_t addr, uint32_t val)
3004689Sql147931 {
3014689Sql147931 	uint32_t reg;
3024689Sql147931 
3034689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHYIO, "%s: %s[%u] <- %08x\n", __func__,
3044689Sql147931 	    rtw_rfchipid_string(rfchipid), addr, val);
3054689Sql147931 
3064689Sql147931 	switch (rfchipid) {
3074689Sql147931 	case RTW_RFCHIPID_GCT:
3084689Sql147931 		reg = rtw_grf5101_mac_crypt(addr, val);
3094689Sql147931 		break;
3104689Sql147931 	case RTW_RFCHIPID_MAXIM:
3114689Sql147931 		reg = rtw_maxim_swizzle(addr, val);
3124689Sql147931 		break;
3134689Sql147931 	default:
3144689Sql147931 	case RTW_RFCHIPID_PHILIPS:
3154689Sql147931 
3164689Sql147931 		reg = LSHIFT(addr, RTW_PHYCFG_MAC_PHILIPS_ADDR_MASK) |
3174689Sql147931 		    LSHIFT(val, RTW_PHYCFG_MAC_PHILIPS_DATA_MASK);
3184689Sql147931 	}
3194689Sql147931 
3204689Sql147931 	switch (rfchipid) {
3214689Sql147931 	case RTW_RFCHIPID_GCT:
3224689Sql147931 	case RTW_RFCHIPID_MAXIM:
3234689Sql147931 	case RTW_RFCHIPID_RFMD:
3244689Sql147931 		reg |= RTW_PHYCFG_MAC_RFTYPE_RFMD;
3254689Sql147931 		break;
3264689Sql147931 	case RTW_RFCHIPID_INTERSIL:
3274689Sql147931 		reg |= RTW_PHYCFG_MAC_RFTYPE_INTERSIL;
3284689Sql147931 		break;
3294689Sql147931 	case RTW_RFCHIPID_PHILIPS:
3304689Sql147931 		reg |= RTW_PHYCFG_MAC_RFTYPE_PHILIPS;
3314689Sql147931 		break;
3324689Sql147931 	default:
3334689Sql147931 		cmn_err(CE_WARN, "%s: unknown rfchipid %d\n",
3344689Sql147931 		    __func__, rfchipid);
3354689Sql147931 		return (-1);
3364689Sql147931 	}
3374689Sql147931 
3384689Sql147931 	return (rtw_rf_macbangbits(regs, reg));
3394689Sql147931 }
340