1185377Ssam/*
2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc.
4185377Ssam *
5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any
6185377Ssam * purpose with or without fee is hereby granted, provided that the above
7185377Ssam * copyright notice and this permission notice appear in all copies.
8185377Ssam *
9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16185377Ssam *
17186015Ssam * $FreeBSD$
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam#include "ah_devid.h"
24185377Ssam
25185377Ssam#include "ar5312/ar5312.h"
26185377Ssam#include "ar5312/ar5312reg.h"
27185377Ssam#include "ar5312/ar5312phy.h"
28185377Ssam
29185377Ssam/* Add static register initialization vectors */
30185377Ssam#define AH_5212_COMMON
31185377Ssam#include "ar5212/ar5212.ini"
32185377Ssam
33185377Ssamstatic  HAL_BOOL ar5312GetMacAddr(struct ath_hal *ah);
34185377Ssam
35185377Ssamstatic void
36185377Ssamar5312AniSetup(struct ath_hal *ah)
37185377Ssam{
38185377Ssam	static const struct ar5212AniParams aniparams = {
39185377Ssam		.maxNoiseImmunityLevel	= 4,	/* levels 0..4 */
40185377Ssam		.totalSizeDesired	= { -41, -41, -48, -48, -48 },
41185377Ssam		.coarseHigh		= { -18, -18, -16, -14, -12 },
42185377Ssam		.coarseLow		= { -56, -56, -60, -60, -60 },
43185377Ssam		.firpwr			= { -72, -72, -75, -78, -80 },
44185377Ssam		.maxSpurImmunityLevel	= 2,
45185377Ssam		.cycPwrThr1		= { 2, 4, 6 },
46185377Ssam		.maxFirstepLevel	= 2,	/* levels 0..2 */
47185377Ssam		.firstep		= { 0, 4, 8 },
48185377Ssam		.ofdmTrigHigh		= 500,
49185377Ssam		.ofdmTrigLow		= 200,
50185377Ssam		.cckTrigHigh		= 200,
51185377Ssam		.cckTrigLow		= 100,
52185377Ssam		.rssiThrHigh		= 40,
53185377Ssam		.rssiThrLow		= 7,
54185377Ssam		.period			= 100,
55185377Ssam	};
56185377Ssam	ar5212AniAttach(ah, &aniparams, &aniparams, AH_TRUE);
57185377Ssam}
58185377Ssam
59185377Ssam/*
60185406Ssam * Attach for an AR5312 part.
61185377Ssam */
62185406Ssamstatic struct ath_hal *
63185377Ssamar5312Attach(uint16_t devid, HAL_SOFTC sc,
64217624Sadrian	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
65217624Sadrian	HAL_STATUS *status)
66185377Ssam{
67185377Ssam	struct ath_hal_5212 *ahp = AH_NULL;
68185377Ssam	struct ath_hal *ah;
69185406Ssam	struct ath_hal_rf *rf;
70185377Ssam	uint32_t val;
71185377Ssam	uint16_t eeval;
72185377Ssam	HAL_STATUS ecode;
73185377Ssam
74225883Sadrian	HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
75185377Ssam		 __func__, sc, st, (void*) sh);
76185377Ssam
77185377Ssam	/* NB: memory is returned zero'd */
78185377Ssam	ahp = ath_hal_malloc(sizeof (struct ath_hal_5212));
79185377Ssam	if (ahp == AH_NULL) {
80225883Sadrian		HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
81185377Ssam		    "%s: cannot allocate memory for state block\n", __func__);
82185377Ssam		*status = HAL_ENOMEM;
83185377Ssam		return AH_NULL;
84185377Ssam	}
85185377Ssam	ar5212InitState(ahp, devid, sc, st, sh, status);
86185377Ssam	ah = &ahp->ah_priv.h;
87185377Ssam
88185377Ssam	/* override 5212 methods for our needs */
89185377Ssam	ah->ah_reset			= ar5312Reset;
90185377Ssam	ah->ah_phyDisable		= ar5312PhyDisable;
91185377Ssam	ah->ah_setLedState		= ar5312SetLedState;
92185377Ssam	ah->ah_detectCardPresent	= ar5312DetectCardPresent;
93185377Ssam	ah->ah_setPowerMode		= ar5312SetPowerMode;
94185377Ssam	ah->ah_getPowerMode		= ar5312GetPowerMode;
95185377Ssam	ah->ah_isInterruptPending	= ar5312IsInterruptPending;
96185377Ssam
97185377Ssam	ahp->ah_priv.ah_eepromRead	= ar5312EepromRead;
98185377Ssam#ifdef AH_SUPPORT_WRITE_EEPROM
99185377Ssam	ahp->ah_priv.ah_eepromWrite	= ar5312EepromWrite;
100185377Ssam#endif
101185377Ssam#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317)
102185377Ssam	if (IS_5315(ah)) {
103185377Ssam		ahp->ah_priv.ah_gpioCfgOutput	= ar5315GpioCfgOutput;
104185377Ssam		ahp->ah_priv.ah_gpioCfgInput	= ar5315GpioCfgInput;
105185377Ssam		ahp->ah_priv.ah_gpioGet		= ar5315GpioGet;
106185377Ssam		ahp->ah_priv.ah_gpioSet		= ar5315GpioSet;
107185377Ssam		ahp->ah_priv.ah_gpioSetIntr	= ar5315GpioSetIntr;
108185377Ssam	} else
109185377Ssam#endif
110185377Ssam	{
111185377Ssam		ahp->ah_priv.ah_gpioCfgOutput	= ar5312GpioCfgOutput;
112185377Ssam		ahp->ah_priv.ah_gpioCfgInput	= ar5312GpioCfgInput;
113185377Ssam		ahp->ah_priv.ah_gpioGet		= ar5312GpioGet;
114185377Ssam		ahp->ah_priv.ah_gpioSet		= ar5312GpioSet;
115185377Ssam		ahp->ah_priv.ah_gpioSetIntr	= ar5312GpioSetIntr;
116185377Ssam	}
117185377Ssam
118185377Ssam	ah->ah_gpioCfgInput		= ahp->ah_priv.ah_gpioCfgInput;
119185377Ssam	ah->ah_gpioCfgOutput		= ahp->ah_priv.ah_gpioCfgOutput;
120185377Ssam	ah->ah_gpioGet			= ahp->ah_priv.ah_gpioGet;
121185377Ssam	ah->ah_gpioSet			= ahp->ah_priv.ah_gpioSet;
122185377Ssam	ah->ah_gpioSetIntr		= ahp->ah_priv.ah_gpioSetIntr;
123185377Ssam
124185377Ssam	/* setup common ini data; rf backends handle remainder */
125185377Ssam	HAL_INI_INIT(&ahp->ah_ini_modes, ar5212Modes, 6);
126186098Ssam	HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 2);
127185377Ssam
128185377Ssam	if (!ar5312ChipReset(ah, AH_NULL)) {	/* reset chip */
129185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
130185377Ssam		ecode = HAL_EIO;
131185377Ssam		goto bad;
132185377Ssam	}
133185377Ssam
134185377Ssam#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317)
135185377Ssam	if ((devid == AR5212_AR2315_REV6) ||
136185377Ssam	    (devid == AR5212_AR2315_REV7) ||
137185377Ssam	    (devid == AR5212_AR2317_REV1) ||
138185377Ssam	    (devid == AR5212_AR2317_REV2) ) {
139185377Ssam		val = ((OS_REG_READ(ah, (AR5315_RSTIMER_BASE -((uint32_t) sh)) + AR5315_WREV)) >> AR5315_WREV_S)
140185377Ssam			& AR5315_WREV_ID;
141185377Ssam		AH_PRIVATE(ah)->ah_macVersion = val >> AR5315_WREV_ID_S;
142185377Ssam		AH_PRIVATE(ah)->ah_macRev = val & AR5315_WREV_REVISION;
143185377Ssam		HALDEBUG(ah, HAL_DEBUG_ATTACH,
144185377Ssam		    "%s: Mac Chip Rev 0x%02x.%x\n" , __func__,
145185377Ssam		    AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev);
146185377Ssam	} else
147185377Ssam#endif
148185377Ssam	{
149185377Ssam		val = OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + 0x0020);
150185377Ssam		val = OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + 0x0080);
151185377Ssam		/* Read Revisions from Chips */
152185377Ssam		val = ((OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + AR5312_WREV)) >> AR5312_WREV_S) & AR5312_WREV_ID;
153185377Ssam		AH_PRIVATE(ah)->ah_macVersion = val >> AR5312_WREV_ID_S;
154185377Ssam		AH_PRIVATE(ah)->ah_macRev = val & AR5312_WREV_REVISION;
155185377Ssam	}
156185377Ssam	/* XXX - THIS IS WRONG. NEEDS TO BE FIXED */
157185377Ssam	if (((AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_VENICE &&
158185377Ssam              AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_VENICE) ||
159185377Ssam             AH_PRIVATE(ah)->ah_macRev < AR_SREV_D2PLUS) &&
160185377Ssam              AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_COBRA) {
161185377Ssam#ifdef AH_DEBUG
162185377Ssam		ath_hal_printf(ah, "%s: Mac Chip Rev 0x%02x.%x is not supported by "
163185377Ssam                         "this driver\n", __func__,
164185377Ssam                         AH_PRIVATE(ah)->ah_macVersion,
165185377Ssam                         AH_PRIVATE(ah)->ah_macRev);
166185377Ssam#endif
167185377Ssam		ecode = HAL_ENOTSUPP;
168185377Ssam		goto bad;
169185377Ssam	}
170185377Ssam
171185377Ssam	AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID);
172185377Ssam
173185377Ssam	if (!ar5212ChipTest(ah)) {
174185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n",
175185377Ssam		    __func__);
176185377Ssam		ecode = HAL_ESELFTEST;
177185377Ssam		goto bad;
178185377Ssam	}
179185377Ssam
180185377Ssam	/*
181185377Ssam	 * Set correct Baseband to analog shift
182185377Ssam	 * setting to access analog chips.
183185377Ssam	 */
184185377Ssam	OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
185185377Ssam
186185377Ssam	/* Read Radio Chip Rev Extract */
187185377Ssam	AH_PRIVATE(ah)->ah_analog5GhzRev = ar5212GetRadioRev(ah);
188185406Ssam
189185406Ssam	rf = ath_hal_rfprobe(ah, &ecode);
190185406Ssam	if (rf == AH_NULL)
191185377Ssam		goto bad;
192185380Ssam	if (IS_RAD5112(ah) && !IS_RADX112_REV2(ah)) {
193185377Ssam#ifdef AH_DEBUG
194185377Ssam		ath_hal_printf(ah, "%s: 5112 Rev 1 is not supported by this "
195185377Ssam                         "driver (analog5GhzRev 0x%x)\n", __func__,
196185377Ssam                         AH_PRIVATE(ah)->ah_analog5GhzRev);
197185377Ssam#endif
198185377Ssam		ecode = HAL_ENOTSUPP;
199185377Ssam		goto bad;
200185377Ssam	}
201185377Ssam
202185377Ssam	ecode = ath_hal_legacyEepromAttach(ah);
203185377Ssam	if (ecode != HAL_OK) {
204185377Ssam		goto bad;
205185377Ssam	}
206185377Ssam
207185377Ssam	/*
208185377Ssam	 * If Bmode and AR5212, verify 2.4 analog exists
209185377Ssam	 */
210185377Ssam	if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE) &&
211185377Ssam	    (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) == AR_RAD5111_SREV_MAJOR) {
212185377Ssam		/*
213185377Ssam		 * Set correct Baseband to analog shift
214185377Ssam		 * setting to access analog chips.
215185377Ssam		 */
216185377Ssam		OS_REG_WRITE(ah, AR_PHY(0), 0x00004007);
217185377Ssam		OS_DELAY(2000);
218185377Ssam		AH_PRIVATE(ah)->ah_analog2GhzRev = ar5212GetRadioRev(ah);
219185377Ssam
220185377Ssam		/* Set baseband for 5GHz chip */
221185377Ssam		OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
222185377Ssam		OS_DELAY(2000);
223185377Ssam		if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != AR_RAD2111_SREV_MAJOR) {
224185377Ssam#ifdef AH_DEBUG
225185377Ssam			ath_hal_printf(ah, "%s: 2G Radio Chip Rev 0x%02X is not "
226185377Ssam				"supported by this driver\n", __func__,
227185377Ssam				AH_PRIVATE(ah)->ah_analog2GhzRev);
228185377Ssam#endif
229185377Ssam			ecode = HAL_ENOTSUPP;
230185377Ssam			goto bad;
231185377Ssam		}
232185377Ssam	}
233185377Ssam
234185377Ssam	ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval);
235185377Ssam	if (ecode != HAL_OK) {
236185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
237185377Ssam		    "%s: cannot read regulatory domain from EEPROM\n",
238185377Ssam		    __func__);
239185377Ssam		goto bad;
240185377Ssam        }
241185377Ssam	AH_PRIVATE(ah)->ah_currentRD = eeval;
242185377Ssam	/* XXX record serial number */
243185377Ssam
244185377Ssam	/* XXX other capabilities */
245185377Ssam	/*
246185377Ssam	 * Got everything we need now to setup the capabilities.
247185377Ssam	 */
248185377Ssam	if (!ar5212FillCapabilityInfo(ah)) {
249185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
250185377Ssam		    "%s: failed ar5212FillCapabilityInfo\n", __func__);
251185377Ssam		ecode = HAL_EEREAD;
252185377Ssam		goto bad;
253185377Ssam	}
254185377Ssam
255185406Ssam	if (!rf->attach(ah, &ecode)) {
256185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n",
257185377Ssam		    __func__, ecode);
258185377Ssam		goto bad;
259185377Ssam	}
260185377Ssam	/* arrange a direct call instead of thunking */
261185377Ssam	AH_PRIVATE(ah)->ah_getNfAdjust = ahp->ah_rfHal->getNfAdjust;
262185377Ssam
263185377Ssam	/* Initialize gain ladder thermal calibration structure */
264185377Ssam	ar5212InitializeGainValues(ah);
265185377Ssam
266185377Ssam        /* BSP specific call for MAC address of this WMAC device */
267185377Ssam        if (!ar5312GetMacAddr(ah)) {
268185377Ssam                ecode = HAL_EEBADMAC;
269185377Ssam                goto bad;
270185377Ssam        }
271185377Ssam
272185377Ssam	ar5312AniSetup(ah);
273185377Ssam	ar5212InitNfCalHistBuffer(ah);
274185377Ssam
275185377Ssam	/* XXX EAR stuff goes here */
276185377Ssam	return ah;
277185377Ssam
278185377Ssambad:
279185377Ssam	if (ahp)
280185377Ssam		ar5212Detach((struct ath_hal *) ahp);
281185377Ssam	if (status)
282185377Ssam		*status = ecode;
283185377Ssam	return AH_NULL;
284185377Ssam}
285185377Ssam
286185377Ssamstatic HAL_BOOL
287185377Ssamar5312GetMacAddr(struct ath_hal *ah)
288185377Ssam{
289185377Ssam	const struct ar531x_boarddata *board = AR5312_BOARDCONFIG(ah);
290185377Ssam        int wlanNum = AR5312_UNIT(ah);
291185377Ssam        const uint8_t *macAddr;
292185377Ssam
293185377Ssam	switch (wlanNum) {
294185377Ssam	case 0:
295185377Ssam		macAddr = board->wlan0Mac;
296185377Ssam		break;
297185377Ssam	case 1:
298185377Ssam		macAddr = board->wlan1Mac;
299185377Ssam		break;
300185377Ssam	default:
301185377Ssam#ifdef AH_DEBUG
302185377Ssam		ath_hal_printf(ah, "Invalid WLAN wmac index (%d)\n",
303185377Ssam			       wlanNum);
304185377Ssam#endif
305185377Ssam		return AH_FALSE;
306185377Ssam	}
307185377Ssam	OS_MEMCPY(AH5212(ah)->ah_macaddr, macAddr, 6);
308185377Ssam	return AH_TRUE;
309185377Ssam}
310185406Ssam
311185406Ssamstatic const char*
312185406Ssamar5312Probe(uint16_t vendorid, uint16_t devid)
313185406Ssam{
314185406Ssam	if (vendorid == ATHEROS_VENDOR_ID) {
315185406Ssam		switch (devid) {
316185406Ssam		case AR5212_AR5312_REV2:
317185406Ssam		case AR5212_AR5312_REV7:
318185406Ssam			return "Atheros 5312 WiSoC";
319185406Ssam		case AR5212_AR2313_REV8:
320185406Ssam			return "Atheros 2313 WiSoC";
321185406Ssam		case AR5212_AR2315_REV6:
322185406Ssam		case AR5212_AR2315_REV7:
323185406Ssam			return "Atheros 2315 WiSoC";
324185406Ssam		case AR5212_AR2317_REV1:
325188549Ssam		case AR5212_AR2317_REV2:
326185406Ssam			return "Atheros 2317 WiSoC";
327185406Ssam		case AR5212_AR2413:
328185406Ssam			return "Atheros 2413";
329185406Ssam		case AR5212_AR2417:
330185406Ssam			return "Atheros 2417";
331185406Ssam		}
332185406Ssam	}
333185406Ssam	return AH_NULL;
334185406Ssam}
335185418SsamAH_CHIP(AR5312, ar5312Probe, ar5312Attach);
336