1221163Sadrian/*
2221163Sadrian * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
3221163Sadrian * Copyright (c) 2008 Sam Leffler, Errno Consulting
4221163Sadrian * Copyright (c) 2008 Atheros Communications, Inc.
5221163Sadrian *
6221163Sadrian * Permission to use, copy, modify, and/or distribute this software for any
7221163Sadrian * purpose with or without fee is hereby granted, provided that the above
8221163Sadrian * copyright notice and this permission notice appear in all copies.
9221163Sadrian *
10221163Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11221163Sadrian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12221163Sadrian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13221163Sadrian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14221163Sadrian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15221163Sadrian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16221163Sadrian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17221163Sadrian *
18221163Sadrian * $FreeBSD$
19221163Sadrian */
20221163Sadrian#include "opt_ah.h"
21221163Sadrian
22221163Sadrian#include "ah.h"
23221163Sadrian#include "ah_internal.h"
24221163Sadrian#include "ah_devid.h"
25221163Sadrian
26221163Sadrian#include "ar5416/ar5416.h"
27221163Sadrian#include "ar5416/ar5416reg.h"
28221163Sadrian#include "ar5416/ar5416phy.h"
29221163Sadrian
30221163Sadrian#include "ar9001/ar9130reg.h"
31221163Sadrian#include "ar9001/ar9130_phy.h"
32221163Sadrian#include "ar9001/ar9130_eeprom.h"
33221163Sadrian
34221163Sadrian#include "ar9001/ar9130.ini"
35221163Sadrian
36221163Sadrianstatic const HAL_PERCAL_DATA ar9130_iq_cal = {		/* multi sample */
37221163Sadrian	.calName = "IQ", .calType = IQ_MISMATCH_CAL,
38221163Sadrian	.calNumSamples	= MAX_CAL_SAMPLES,
39221163Sadrian	.calCountMax	= PER_MIN_LOG_COUNT,
40221163Sadrian	.calCollect	= ar5416IQCalCollect,
41221163Sadrian	.calPostProc	= ar5416IQCalibration
42221163Sadrian};
43221163Sadrianstatic const HAL_PERCAL_DATA ar9130_adc_gain_cal = {	/* multi sample */
44221163Sadrian	.calName = "ADC Gain", .calType = ADC_GAIN_CAL,
45221163Sadrian	.calNumSamples	= MAX_CAL_SAMPLES,
46221163Sadrian	.calCountMax	= PER_MIN_LOG_COUNT,
47221163Sadrian	.calCollect	= ar5416AdcGainCalCollect,
48221163Sadrian	.calPostProc	= ar5416AdcGainCalibration
49221163Sadrian};
50221163Sadrianstatic const HAL_PERCAL_DATA ar9130_adc_dc_cal = {	/* multi sample */
51221163Sadrian	.calName = "ADC DC", .calType = ADC_DC_CAL,
52221163Sadrian	.calNumSamples	= MAX_CAL_SAMPLES,
53221163Sadrian	.calCountMax	= PER_MIN_LOG_COUNT,
54221163Sadrian	.calCollect	= ar5416AdcDcCalCollect,
55221163Sadrian	.calPostProc	= ar5416AdcDcCalibration
56221163Sadrian};
57221163Sadrianstatic const HAL_PERCAL_DATA ar9130_adc_init_dc_cal = {
58221163Sadrian	.calName = "ADC Init DC", .calType = ADC_DC_INIT_CAL,
59221163Sadrian	.calNumSamples	= MIN_CAL_SAMPLES,
60221163Sadrian	.calCountMax	= INIT_LOG_COUNT,
61221163Sadrian	.calCollect	= ar5416AdcDcCalCollect,
62221163Sadrian	.calPostProc	= ar5416AdcDcCalibration
63221163Sadrian};
64221163Sadrian
65221163Sadrianstatic HAL_BOOL ar9130FillCapabilityInfo(struct ath_hal *ah);
66221163Sadrian
67221163Sadrian/*
68221163Sadrian * Attach for an AR9130 part.
69221163Sadrian */
70221163Sadrianstatic struct ath_hal *
71221163Sadrianar9130Attach(uint16_t devid, HAL_SOFTC sc,
72221163Sadrian	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status)
73221163Sadrian{
74221163Sadrian	struct ath_hal_5416 *ahp5416;
75221163Sadrian	struct ath_hal_5212 *ahp;
76221163Sadrian	struct ath_hal *ah;
77221163Sadrian	uint32_t val;
78221163Sadrian	HAL_STATUS ecode;
79221163Sadrian	HAL_BOOL rfStatus;
80221163Sadrian
81225883Sadrian	HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
82221163Sadrian	    __func__, sc, (void*) st, (void*) sh);
83221163Sadrian
84221163Sadrian	/* NB: memory is returned zero'd */
85221163Sadrian	ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416));
86221163Sadrian	if (ahp5416 == AH_NULL) {
87225883Sadrian		HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
88221163Sadrian		    "%s: cannot allocate memory for state block\n", __func__);
89221163Sadrian		*status = HAL_ENOMEM;
90221163Sadrian		return AH_NULL;
91221163Sadrian	}
92221163Sadrian	ar5416InitState(ahp5416, devid, sc, st, sh, status);
93221163Sadrian	ahp = &ahp5416->ah_5212;
94221163Sadrian	ah = &ahp->ah_priv.h;
95221163Sadrian
96221163Sadrian	/* XXX override with 9100 specific state */
97221163Sadrian	AH5416(ah)->ah_initPLL = ar9130InitPLL;
98221163Sadrian	/* XXX should force chainmasks to 0x7, as per ath9k calibration bugs */
99221163Sadrian
100221163Sadrian	/* override 5416 methods for our needs */
101221163Sadrian
102221163Sadrian	AH5416(ah)->ah_cal.iqCalData.calData = &ar9130_iq_cal;
103221163Sadrian	AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9130_adc_gain_cal;
104221163Sadrian	AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9130_adc_dc_cal;
105221163Sadrian	AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9130_adc_init_dc_cal;
106221163Sadrian	AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
107221163Sadrian
108221163Sadrian	/*
109221163Sadrian	 * This was hard-set because the initial ath9k port of this
110221163Sadrian	 * code kept their runtime conditional register #defines.
111221163Sadrian	 * AR_SREV and the RTC registers have shifted for Howl;
112221163Sadrian	 * they detected this and changed the values at runtime.
113221163Sadrian	 * The current port doesn't yet do this; it may do at a
114221163Sadrian	 * later stage, so this is set early so any routines which
115221163Sadrian	 * manipulate the registers have ah_macVersion set to base
116221163Sadrian	 * the above decision upon.
117221163Sadrian	 */
118221163Sadrian	AH_PRIVATE((ah))->ah_macVersion = AR_XSREV_VERSION_HOWL;
119221163Sadrian
120221163Sadrian	/*
121221163Sadrian	 * Use the "local" EEPROM data given to us by the higher layers.
122230147Sadrian	 * This is a private copy out of system flash.
123230147Sadrian	 * By this stage the SoC SPI flash may have disabled the memory-
124230147Sadrian	 * mapping and rely purely on port-based SPI IO.
125221163Sadrian	 */
126230147Sadrian	AH_PRIVATE((ah))->ah_eepromRead = ath_hal_EepromDataRead;
127221163Sadrian	AH_PRIVATE((ah))->ah_eepromWrite = NULL;
128221163Sadrian	ah->ah_eepromdata = eepromdata;
129221163Sadrian
130221163Sadrian	if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) {
131221163Sadrian		/* reset chip */
132221163Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n",
133221163Sadrian		    __func__);
134221163Sadrian		ecode = HAL_EIO;
135221163Sadrian		goto bad;
136221163Sadrian	}
137221163Sadrian
138221163Sadrian	if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
139221163Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n",
140221163Sadrian		    __func__);
141221163Sadrian		ecode = HAL_EIO;
142221163Sadrian		goto bad;
143221163Sadrian	}
144221163Sadrian	/* Read Revisions from Chips before taking out of reset */
145221163Sadrian	val = OS_REG_READ(ah, AR_SREV_CHIP_HOWL) & AR_SREV_CHIP_HOWL_ID;
146221163Sadrian
147221163Sadrian	/* XXX are these values even valid for the mac/radio revision? -adrian */
148221163Sadrian	HALDEBUG(ah, HAL_DEBUG_ATTACH,
149221163Sadrian	    "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n",
150221163Sadrian	    __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION),
151221163Sadrian	    MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION));
152221163Sadrian	AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION);
153221163Sadrian	AH_PRIVATE(ah)->ah_ispcie = 0;
154221163Sadrian
155221163Sadrian	/* setup common ini data; rf backends handle remainder */
156221163Sadrian	HAL_INI_INIT(&ahp->ah_ini_modes, ar5416Modes_9100, 6);
157221163Sadrian	HAL_INI_INIT(&ahp->ah_ini_common, ar5416Common_9100, 2);
158221163Sadrian
159221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar5416BB_RfGain_9100, 3);
160221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar5416Bank0_9100, 2);
161221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar5416Bank1_9100, 2);
162221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar5416Bank2_9100, 2);
163221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar5416Bank3_9100, 3);
164221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar5416Bank6TPC_9100, 3);
165221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar5416Bank7_9100, 2);
166221163Sadrian	HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar5416Addac_9100, 2);
167221163Sadrian
168221163Sadrian	ecode = ath_hal_v14EepromAttach(ah);
169221163Sadrian	if (ecode != HAL_OK)
170221163Sadrian		goto bad;
171221163Sadrian
172221163Sadrian	if (!ar5416ChipReset(ah, AH_NULL)) {	/* reset chip */
173221163Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
174221163Sadrian		ecode = HAL_EIO;
175221163Sadrian		goto bad;
176221163Sadrian	}
177221163Sadrian
178221163Sadrian	AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID);
179221163Sadrian
180221163Sadrian	if (!ar5212ChipTest(ah)) {
181221163Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n",
182221163Sadrian		    __func__);
183221163Sadrian		ecode = HAL_ESELFTEST;
184221163Sadrian		goto bad;
185221163Sadrian	}
186221163Sadrian
187221163Sadrian	/*
188221163Sadrian	 * Set correct Baseband to analog shift
189221163Sadrian	 * setting to access analog chips.
190221163Sadrian	 */
191221163Sadrian	OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
192221163Sadrian
193221163Sadrian	/* Read Radio Chip Rev Extract */
194221163Sadrian	AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah);
195221163Sadrian	switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
196221163Sadrian        case AR_RAD2133_SREV_MAJOR:	/* Sowl: 2G/3x3 */
197221163Sadrian	case AR_RAD5133_SREV_MAJOR:	/* Sowl: 2+5G/3x3 */
198221163Sadrian		break;
199221163Sadrian	default:
200221163Sadrian		if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) {
201221163Sadrian			AH_PRIVATE(ah)->ah_analog5GhzRev =
202221163Sadrian				AR_RAD5133_SREV_MAJOR;
203221163Sadrian			break;
204221163Sadrian		}
205221163Sadrian#ifdef AH_DEBUG
206221163Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY,
207221163Sadrian		    "%s: 5G Radio Chip Rev 0x%02X is not supported by "
208221163Sadrian		    "this driver\n", __func__,
209221163Sadrian		    AH_PRIVATE(ah)->ah_analog5GhzRev);
210221163Sadrian		ecode = HAL_ENOTSUPP;
211221163Sadrian		goto bad;
212221163Sadrian#endif
213221163Sadrian	}
214221163Sadrian	rfStatus = ar2133RfAttach(ah, &ecode);
215221163Sadrian	if (!rfStatus) {
216221163Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n",
217221163Sadrian		    __func__, ecode);
218221163Sadrian		goto bad;
219221163Sadrian	}
220221163Sadrian
221221163Sadrian	/*
222221163Sadrian	 * Got everything we need now to setup the capabilities.
223221163Sadrian	 */
224221163Sadrian	if (!ar9130FillCapabilityInfo(ah)) {
225221163Sadrian		ecode = HAL_EEREAD;
226221163Sadrian		goto bad;
227221163Sadrian	}
228221163Sadrian
229221163Sadrian	ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr);
230221163Sadrian	if (ecode != HAL_OK) {
231221163Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY,
232221163Sadrian		    "%s: error getting mac address from EEPROM\n", __func__);
233221163Sadrian		goto bad;
234221163Sadrian        }
235221163Sadrian	/* XXX How about the serial number ? */
236221163Sadrian	/* Read Reg Domain */
237221163Sadrian	AH_PRIVATE(ah)->ah_currentRD =
238221163Sadrian	    ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL);
239221596Sadrian	AH_PRIVATE(ah)->ah_currentRDext =
240221596Sadrian	    ath_hal_eepromGet(ah, AR_EEP_REGDMN_1, AH_NULL);
241221163Sadrian
242221596Sadrian
243221163Sadrian	/*
244221163Sadrian	 * ah_miscMode is populated by ar5416FillCapabilityInfo()
245221163Sadrian	 * starting from griffin. Set here to make sure that
246221163Sadrian	 * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is
247221163Sadrian	 * placed into hardware.
248221163Sadrian	 */
249221163Sadrian	if (ahp->ah_miscMode != 0)
250221163Sadrian		OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
251221163Sadrian
252221163Sadrian	/* XXX no ANI for AR9130 */
253221163Sadrian	AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ;
254221163Sadrian	AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ;
255221163Sadrian	AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ;
256221163Sadrian	AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ;
257221163Sadrian	AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ;
258221163Sadrian	AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ;
259221163Sadrian
260221163Sadrian	ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist);
261221163Sadrian
262221163Sadrian	HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__);
263221163Sadrian
264221163Sadrian	return ah;
265221163Sadrianbad:
266221163Sadrian	if (ahp)
267221163Sadrian		ar5416Detach((struct ath_hal *) ahp);
268221163Sadrian	if (status)
269221163Sadrian		*status = ecode;
270221163Sadrian	return AH_NULL;
271221163Sadrian}
272221163Sadrian
273221163Sadrian/*
274221163Sadrian * Fill all software cached or static hardware state information.
275221163Sadrian * Return failure if capabilities are to come from EEPROM and
276221163Sadrian * cannot be read.
277221163Sadrian */
278221163Sadrianstatic HAL_BOOL
279221163Sadrianar9130FillCapabilityInfo(struct ath_hal *ah)
280221163Sadrian{
281221163Sadrian	HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
282221163Sadrian
283221163Sadrian	HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: begin\n", __func__);
284221163Sadrian	if (!ar5416FillCapabilityInfo(ah))
285221163Sadrian		return AH_FALSE;
286221163Sadrian	HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: fill'ed; now setting\n", __func__);
287221163Sadrian	pCap->halCSTSupport = AH_TRUE;
288221163Sadrian	pCap->halRifsRxSupport = AH_TRUE;
289221163Sadrian	pCap->halRifsTxSupport = AH_TRUE;
290221163Sadrian	pCap->halRtsAggrLimit = 64*1024;	/* 802.11n max */
291221163Sadrian	pCap->halExtChanDfsSupport = AH_TRUE;
292222584Sadrian	pCap->halUseCombinedRadarRssi = AH_TRUE;
293221163Sadrian	pCap->halAutoSleepSupport = AH_FALSE;	/* XXX? */
294221603Sadrian	/*
295221603Sadrian	 * MBSSID aggregation is broken in Howl v1.1, v1.2, v1.3
296221603Sadrian	 * and works fine in v1.4.
297221603Sadrian	 * XXX todo, enable it for v1.4.
298221603Sadrian	 */
299221603Sadrian	pCap->halMbssidAggrSupport = AH_FALSE;
300221603Sadrian	pCap->hal4AddrAggrSupport = AH_TRUE;
301226488Sadrian	/* BB Read WAR */
302226488Sadrian	pCap->halHasBBReadWar = AH_TRUE;
303221603Sadrian
304242412Sadrian	/*
305242412Sadrian	 * Implement the PLL/config changes needed for half/quarter
306242412Sadrian	 * rates before re-enabling them here.
307242412Sadrian	 */
308242412Sadrian	pCap->halChanHalfRate = AH_FALSE;
309242412Sadrian	pCap->halChanQuarterRate = AH_FALSE;
310242412Sadrian
311221163Sadrian	return AH_TRUE;
312221163Sadrian}
313221163Sadrian
314221163Sadrianstatic const char*
315221163Sadrianar9130Probe(uint16_t vendorid, uint16_t devid)
316221163Sadrian{
317221163Sadrian        if (vendorid == ATHEROS_VENDOR_ID && devid == AR5416_AR9130_DEVID)
318221163Sadrian                return "Atheros 9130";
319221163Sadrian	return AH_NULL;
320221163Sadrian}
321221163SadrianAH_CHIP(AR9130, ar9130Probe, ar9130Attach);
322