1/*
2 * Copyright (c) 2008-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "hw.h"
18
19void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
20{
21        REG_WRITE(ah, reg, val);
22
23        if (ah->config.analog_shiftreg)
24		udelay(100);
25}
26
27void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
28			       u32 shift, u32 val)
29{
30	REG_RMW(ah, reg, ((val << shift) & mask), mask);
31
32	if (ah->config.analog_shiftreg)
33		udelay(100);
34}
35
36int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
37			     int16_t targetLeft, int16_t targetRight)
38{
39	int16_t rv;
40
41	if (srcRight == srcLeft) {
42		rv = targetLeft;
43	} else {
44		rv = (int16_t) (((target - srcLeft) * targetRight +
45				 (srcRight - target) * targetLeft) /
46				(srcRight - srcLeft));
47	}
48	return rv;
49}
50
51bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
52				    u16 *indexL, u16 *indexR)
53{
54	u16 i;
55
56	if (target <= pList[0]) {
57		*indexL = *indexR = 0;
58		return true;
59	}
60	if (target >= pList[listSize - 1]) {
61		*indexL = *indexR = (u16) (listSize - 1);
62		return true;
63	}
64
65	for (i = 0; i < listSize - 1; i++) {
66		if (pList[i] == target) {
67			*indexL = *indexR = i;
68			return true;
69		}
70		if (target < pList[i + 1]) {
71			*indexL = i;
72			*indexR = (u16) (i + 1);
73			return false;
74		}
75	}
76	return false;
77}
78
79void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
80				  int eep_start_loc, int size)
81{
82	int i = 0, j, addr;
83	u32 addrdata[8];
84	u32 data[8];
85
86	for (addr = 0; addr < size; addr++) {
87		addrdata[i] = AR5416_EEPROM_OFFSET +
88			((addr + eep_start_loc) << AR5416_EEPROM_S);
89		i++;
90		if (i == 8) {
91			REG_READ_MULTI(ah, addrdata, data, i);
92
93			for (j = 0; j < i; j++) {
94				*eep_data = data[j];
95				eep_data++;
96			}
97			i = 0;
98		}
99	}
100
101	if (i != 0) {
102		REG_READ_MULTI(ah, addrdata, data, i);
103
104		for (j = 0; j < i; j++) {
105			*eep_data = data[j];
106			eep_data++;
107		}
108	}
109}
110
111static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off,
112				     u16 *data)
113{
114	u16 *blob_data;
115
116	if (off * sizeof(u16) > ah->eeprom_blob->size)
117		return false;
118
119	blob_data = (u16 *)ah->eeprom_blob->data;
120	*data =  blob_data[off];
121	return true;
122}
123
124bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
125{
126	struct ath_common *common = ath9k_hw_common(ah);
127	bool ret;
128
129	if (ah->eeprom_blob)
130		ret = ath9k_hw_nvram_read_blob(ah, off, data);
131	else
132		ret = common->bus_ops->eeprom_read(common, off, data);
133
134	if (!ret)
135		ath_dbg(common, EEPROM,
136			"unable to read eeprom region at offset %u\n", off);
137
138	return ret;
139}
140
141void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
142			     u8 *pVpdList, u16 numIntercepts,
143			     u8 *pRetVpdList)
144{
145	u16 i, k;
146	u8 currPwr = pwrMin;
147	u16 idxL = 0, idxR = 0;
148
149	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
150		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
151					       numIntercepts, &(idxL),
152					       &(idxR));
153		if (idxR < 1)
154			idxR = 1;
155		if (idxL == numIntercepts - 1)
156			idxL = (u16) (numIntercepts - 2);
157		if (pPwrList[idxL] == pPwrList[idxR])
158			k = pVpdList[idxL];
159		else
160			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
161				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
162				  (pPwrList[idxR] - pPwrList[idxL]));
163		pRetVpdList[i] = (u8) k;
164		currPwr += 2;
165	}
166}
167
168void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
169				       struct ath9k_channel *chan,
170				       struct cal_target_power_leg *powInfo,
171				       u16 numChannels,
172				       struct cal_target_power_leg *pNewPower,
173				       u16 numRates, bool isExtTarget)
174{
175	struct chan_centers centers;
176	u16 clo, chi;
177	int i;
178	int matchIndex = -1, lowIndex = -1;
179	u16 freq;
180
181	ath9k_hw_get_channel_centers(ah, chan, &centers);
182	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
183
184	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
185				       IS_CHAN_2GHZ(chan))) {
186		matchIndex = 0;
187	} else {
188		for (i = 0; (i < numChannels) &&
189			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
190			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
191						       IS_CHAN_2GHZ(chan))) {
192				matchIndex = i;
193				break;
194			} else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
195						IS_CHAN_2GHZ(chan)) && i > 0 &&
196				   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
197						IS_CHAN_2GHZ(chan))) {
198				lowIndex = i - 1;
199				break;
200			}
201		}
202		if ((matchIndex == -1) && (lowIndex == -1))
203			matchIndex = i - 1;
204	}
205
206	if (matchIndex != -1) {
207		*pNewPower = powInfo[matchIndex];
208	} else {
209		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
210					 IS_CHAN_2GHZ(chan));
211		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
212					 IS_CHAN_2GHZ(chan));
213
214		for (i = 0; i < numRates; i++) {
215			pNewPower->tPow2x[i] =
216				(u8)ath9k_hw_interpolate(freq, clo, chi,
217						powInfo[lowIndex].tPow2x[i],
218						powInfo[lowIndex + 1].tPow2x[i]);
219		}
220	}
221}
222
223void ath9k_hw_get_target_powers(struct ath_hw *ah,
224				struct ath9k_channel *chan,
225				struct cal_target_power_ht *powInfo,
226				u16 numChannels,
227				struct cal_target_power_ht *pNewPower,
228				u16 numRates, bool isHt40Target)
229{
230	struct chan_centers centers;
231	u16 clo, chi;
232	int i;
233	int matchIndex = -1, lowIndex = -1;
234	u16 freq;
235
236	ath9k_hw_get_channel_centers(ah, chan, &centers);
237	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
238
239	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
240		matchIndex = 0;
241	} else {
242		for (i = 0; (i < numChannels) &&
243			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
244			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
245						       IS_CHAN_2GHZ(chan))) {
246				matchIndex = i;
247				break;
248			} else
249				if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
250						IS_CHAN_2GHZ(chan)) && i > 0 &&
251				    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
252						IS_CHAN_2GHZ(chan))) {
253					lowIndex = i - 1;
254					break;
255				}
256		}
257		if ((matchIndex == -1) && (lowIndex == -1))
258			matchIndex = i - 1;
259	}
260
261	if (matchIndex != -1) {
262		*pNewPower = powInfo[matchIndex];
263	} else {
264		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
265					 IS_CHAN_2GHZ(chan));
266		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
267					 IS_CHAN_2GHZ(chan));
268
269		for (i = 0; i < numRates; i++) {
270			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
271						clo, chi,
272						powInfo[lowIndex].tPow2x[i],
273						powInfo[lowIndex + 1].tPow2x[i]);
274		}
275	}
276}
277
278u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
279				bool is2GHz, int num_band_edges)
280{
281	u16 twiceMaxEdgePower = MAX_RATE_POWER;
282	int i;
283
284	for (i = 0; (i < num_band_edges) &&
285		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
286		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
287			twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
288			break;
289		} else if ((i > 0) &&
290			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
291						      is2GHz))) {
292			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
293					       is2GHz) < freq &&
294			    CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
295				twiceMaxEdgePower =
296					CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
297			}
298			break;
299		}
300	}
301
302	return twiceMaxEdgePower;
303}
304
305u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
306			      u8 antenna_reduction)
307{
308	u16 reduction = antenna_reduction;
309
310	/*
311	 * Reduce scaled Power by number of chains active
312	 * to get the per chain tx power level.
313	 */
314	switch (ar5416_get_ntxchains(ah->txchainmask)) {
315	case 1:
316		break;
317	case 2:
318		reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
319		break;
320	case 3:
321		reduction += POWER_CORRECTION_FOR_THREE_CHAIN;
322		break;
323	}
324
325	if (power_limit > reduction)
326		power_limit -= reduction;
327	else
328		power_limit = 0;
329
330	return power_limit;
331}
332
333void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
334{
335	struct ath_common *common = ath9k_hw_common(ah);
336	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
337
338	switch (ar5416_get_ntxchains(ah->txchainmask)) {
339	case 1:
340		break;
341	case 2:
342		regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN;
343		break;
344	case 3:
345		regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN;
346		break;
347	default:
348		ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
349		break;
350	}
351}
352
353void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
354				struct ath9k_channel *chan,
355				void *pRawDataSet,
356				u8 *bChans, u16 availPiers,
357				u16 tPdGainOverlap,
358				u16 *pPdGainBoundaries, u8 *pPDADCValues,
359				u16 numXpdGains)
360{
361	int i, j, k;
362	int16_t ss;
363	u16 idxL = 0, idxR = 0, numPiers;
364	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
365		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
366	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
367		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
368	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
369		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
370
371	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
372	u8 minPwrT4[AR5416_NUM_PD_GAINS];
373	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
374	int16_t vpdStep;
375	int16_t tmpVal;
376	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
377	bool match;
378	int16_t minDelta = 0;
379	struct chan_centers centers;
380	int pdgain_boundary_default;
381	struct cal_data_per_freq *data_def = pRawDataSet;
382	struct cal_data_per_freq_4k *data_4k = pRawDataSet;
383	struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
384	bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
385	int intercepts;
386
387	if (AR_SREV_9287(ah))
388		intercepts = AR9287_PD_GAIN_ICEPTS;
389	else
390		intercepts = AR5416_PD_GAIN_ICEPTS;
391
392	memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
393	ath9k_hw_get_channel_centers(ah, chan, &centers);
394
395	for (numPiers = 0; numPiers < availPiers; numPiers++) {
396		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
397			break;
398	}
399
400	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
401							     IS_CHAN_2GHZ(chan)),
402					       bChans, numPiers, &idxL, &idxR);
403
404	if (match) {
405		if (AR_SREV_9287(ah)) {
406			/* FIXME: array overrun? */
407			for (i = 0; i < numXpdGains; i++) {
408				minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
409				maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
410				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
411						data_9287[idxL].pwrPdg[i],
412						data_9287[idxL].vpdPdg[i],
413						intercepts,
414						vpdTableI[i]);
415			}
416		} else if (eeprom_4k) {
417			for (i = 0; i < numXpdGains; i++) {
418				minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
419				maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
420				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
421						data_4k[idxL].pwrPdg[i],
422						data_4k[idxL].vpdPdg[i],
423						intercepts,
424						vpdTableI[i]);
425			}
426		} else {
427			for (i = 0; i < numXpdGains; i++) {
428				minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
429				maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
430				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
431						data_def[idxL].pwrPdg[i],
432						data_def[idxL].vpdPdg[i],
433						intercepts,
434						vpdTableI[i]);
435			}
436		}
437	} else {
438		for (i = 0; i < numXpdGains; i++) {
439			if (AR_SREV_9287(ah)) {
440				pVpdL = data_9287[idxL].vpdPdg[i];
441				pPwrL = data_9287[idxL].pwrPdg[i];
442				pVpdR = data_9287[idxR].vpdPdg[i];
443				pPwrR = data_9287[idxR].pwrPdg[i];
444			} else if (eeprom_4k) {
445				pVpdL = data_4k[idxL].vpdPdg[i];
446				pPwrL = data_4k[idxL].pwrPdg[i];
447				pVpdR = data_4k[idxR].vpdPdg[i];
448				pPwrR = data_4k[idxR].pwrPdg[i];
449			} else {
450				pVpdL = data_def[idxL].vpdPdg[i];
451				pPwrL = data_def[idxL].pwrPdg[i];
452				pVpdR = data_def[idxR].vpdPdg[i];
453				pPwrR = data_def[idxR].pwrPdg[i];
454			}
455
456			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
457
458			maxPwrT4[i] =
459				min(pPwrL[intercepts - 1],
460				    pPwrR[intercepts - 1]);
461
462
463			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
464						pPwrL, pVpdL,
465						intercepts,
466						vpdTableL[i]);
467			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
468						pPwrR, pVpdR,
469						intercepts,
470						vpdTableR[i]);
471
472			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
473				vpdTableI[i][j] =
474					(u8)(ath9k_hw_interpolate((u16)
475					     FREQ2FBIN(centers.
476						       synth_center,
477						       IS_CHAN_2GHZ
478						       (chan)),
479					     bChans[idxL], bChans[idxR],
480					     vpdTableL[i][j], vpdTableR[i][j]));
481			}
482		}
483	}
484
485	k = 0;
486
487	for (i = 0; i < numXpdGains; i++) {
488		if (i == (numXpdGains - 1))
489			pPdGainBoundaries[i] =
490				(u16)(maxPwrT4[i] / 2);
491		else
492			pPdGainBoundaries[i] =
493				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
494
495		pPdGainBoundaries[i] =
496			min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
497
498		minDelta = 0;
499
500		if (i == 0) {
501			if (AR_SREV_9280_20_OR_LATER(ah))
502				ss = (int16_t)(0 - (minPwrT4[i] / 2));
503			else
504				ss = 0;
505		} else {
506			ss = (int16_t)((pPdGainBoundaries[i - 1] -
507					(minPwrT4[i] / 2)) -
508				       tPdGainOverlap + 1 + minDelta);
509		}
510		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
511		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
512
513		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
514			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
515			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
516			ss++;
517		}
518
519		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
520		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
521				(minPwrT4[i] / 2));
522		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
523			tgtIndex : sizeCurrVpdTable;
524
525		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
526			pPDADCValues[k++] = vpdTableI[i][ss++];
527		}
528
529		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
530				    vpdTableI[i][sizeCurrVpdTable - 2]);
531		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
532
533		if (tgtIndex >= maxIndex) {
534			while ((ss <= tgtIndex) &&
535			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
536				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
537						    (ss - maxIndex + 1) * vpdStep));
538				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
539							 255 : tmpVal);
540				ss++;
541			}
542		}
543	}
544
545	if (eeprom_4k)
546		pdgain_boundary_default = 58;
547	else
548		pdgain_boundary_default = pPdGainBoundaries[i - 1];
549
550	while (i < AR5416_PD_GAINS_IN_MASK) {
551		pPdGainBoundaries[i] = pdgain_boundary_default;
552		i++;
553	}
554
555	while (k < AR5416_NUM_PDADC_VALUES) {
556		pPDADCValues[k] = pPDADCValues[k - 1];
557		k++;
558	}
559}
560
561int ath9k_hw_eeprom_init(struct ath_hw *ah)
562{
563	int status;
564
565	if (AR_SREV_9300_20_OR_LATER(ah))
566		ah->eep_ops = &eep_ar9300_ops;
567	else if (AR_SREV_9287(ah)) {
568		ah->eep_ops = &eep_ar9287_ops;
569	} else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
570		ah->eep_ops = &eep_4k_ops;
571	} else {
572		ah->eep_ops = &eep_def_ops;
573	}
574
575	if (!ah->eep_ops->fill_eeprom(ah))
576		return -EIO;
577
578	status = ah->eep_ops->check_eeprom(ah);
579
580	return status;
581}
582