xref: /openbmc/linux/drivers/net/wireless/ath/ath9k/eeprom.c (revision baa7eb025ab14f3cba2e35c0a8648f9c9f01d24f)
1 /*
2  * Copyright (c) 2008-2009 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 
19 static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
20 {
21 	if (fbin == AR5416_BCHAN_UNUSED)
22 		return fbin;
23 
24 	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
25 }
26 
27 void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
28 {
29         REG_WRITE(ah, reg, val);
30 
31         if (ah->config.analog_shiftreg)
32 		udelay(100);
33 }
34 
35 void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
36 			       u32 shift, u32 val)
37 {
38 	u32 regVal;
39 
40 	regVal = REG_READ(ah, reg) & ~mask;
41 	regVal |= (val << shift) & mask;
42 
43 	REG_WRITE(ah, reg, regVal);
44 
45 	if (ah->config.analog_shiftreg)
46 		udelay(100);
47 }
48 
49 int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
50 			     int16_t targetLeft, int16_t targetRight)
51 {
52 	int16_t rv;
53 
54 	if (srcRight == srcLeft) {
55 		rv = targetLeft;
56 	} else {
57 		rv = (int16_t) (((target - srcLeft) * targetRight +
58 				 (srcRight - target) * targetLeft) /
59 				(srcRight - srcLeft));
60 	}
61 	return rv;
62 }
63 
64 bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
65 				    u16 *indexL, u16 *indexR)
66 {
67 	u16 i;
68 
69 	if (target <= pList[0]) {
70 		*indexL = *indexR = 0;
71 		return true;
72 	}
73 	if (target >= pList[listSize - 1]) {
74 		*indexL = *indexR = (u16) (listSize - 1);
75 		return true;
76 	}
77 
78 	for (i = 0; i < listSize - 1; i++) {
79 		if (pList[i] == target) {
80 			*indexL = *indexR = i;
81 			return true;
82 		}
83 		if (target < pList[i + 1]) {
84 			*indexL = i;
85 			*indexR = (u16) (i + 1);
86 			return false;
87 		}
88 	}
89 	return false;
90 }
91 
92 bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
93 {
94 	return common->bus_ops->eeprom_read(common, off, data);
95 }
96 
97 void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
98 			     u8 *pVpdList, u16 numIntercepts,
99 			     u8 *pRetVpdList)
100 {
101 	u16 i, k;
102 	u8 currPwr = pwrMin;
103 	u16 idxL = 0, idxR = 0;
104 
105 	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
106 		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
107 					       numIntercepts, &(idxL),
108 					       &(idxR));
109 		if (idxR < 1)
110 			idxR = 1;
111 		if (idxL == numIntercepts - 1)
112 			idxL = (u16) (numIntercepts - 2);
113 		if (pPwrList[idxL] == pPwrList[idxR])
114 			k = pVpdList[idxL];
115 		else
116 			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
117 				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
118 				  (pPwrList[idxR] - pPwrList[idxL]));
119 		pRetVpdList[i] = (u8) k;
120 		currPwr += 2;
121 	}
122 }
123 
124 void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
125 				       struct ath9k_channel *chan,
126 				       struct cal_target_power_leg *powInfo,
127 				       u16 numChannels,
128 				       struct cal_target_power_leg *pNewPower,
129 				       u16 numRates, bool isExtTarget)
130 {
131 	struct chan_centers centers;
132 	u16 clo, chi;
133 	int i;
134 	int matchIndex = -1, lowIndex = -1;
135 	u16 freq;
136 
137 	ath9k_hw_get_channel_centers(ah, chan, &centers);
138 	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
139 
140 	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
141 				       IS_CHAN_2GHZ(chan))) {
142 		matchIndex = 0;
143 	} else {
144 		for (i = 0; (i < numChannels) &&
145 			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
146 			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
147 						       IS_CHAN_2GHZ(chan))) {
148 				matchIndex = i;
149 				break;
150 			} else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
151 						IS_CHAN_2GHZ(chan)) && i > 0 &&
152 				   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
153 						IS_CHAN_2GHZ(chan))) {
154 				lowIndex = i - 1;
155 				break;
156 			}
157 		}
158 		if ((matchIndex == -1) && (lowIndex == -1))
159 			matchIndex = i - 1;
160 	}
161 
162 	if (matchIndex != -1) {
163 		*pNewPower = powInfo[matchIndex];
164 	} else {
165 		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
166 					 IS_CHAN_2GHZ(chan));
167 		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
168 					 IS_CHAN_2GHZ(chan));
169 
170 		for (i = 0; i < numRates; i++) {
171 			pNewPower->tPow2x[i] =
172 				(u8)ath9k_hw_interpolate(freq, clo, chi,
173 						powInfo[lowIndex].tPow2x[i],
174 						powInfo[lowIndex + 1].tPow2x[i]);
175 		}
176 	}
177 }
178 
179 void ath9k_hw_get_target_powers(struct ath_hw *ah,
180 				struct ath9k_channel *chan,
181 				struct cal_target_power_ht *powInfo,
182 				u16 numChannels,
183 				struct cal_target_power_ht *pNewPower,
184 				u16 numRates, bool isHt40Target)
185 {
186 	struct chan_centers centers;
187 	u16 clo, chi;
188 	int i;
189 	int matchIndex = -1, lowIndex = -1;
190 	u16 freq;
191 
192 	ath9k_hw_get_channel_centers(ah, chan, &centers);
193 	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
194 
195 	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
196 		matchIndex = 0;
197 	} else {
198 		for (i = 0; (i < numChannels) &&
199 			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
200 			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
201 						       IS_CHAN_2GHZ(chan))) {
202 				matchIndex = i;
203 				break;
204 			} else
205 				if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
206 						IS_CHAN_2GHZ(chan)) && i > 0 &&
207 				    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
208 						IS_CHAN_2GHZ(chan))) {
209 					lowIndex = i - 1;
210 					break;
211 				}
212 		}
213 		if ((matchIndex == -1) && (lowIndex == -1))
214 			matchIndex = i - 1;
215 	}
216 
217 	if (matchIndex != -1) {
218 		*pNewPower = powInfo[matchIndex];
219 	} else {
220 		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
221 					 IS_CHAN_2GHZ(chan));
222 		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
223 					 IS_CHAN_2GHZ(chan));
224 
225 		for (i = 0; i < numRates; i++) {
226 			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
227 						clo, chi,
228 						powInfo[lowIndex].tPow2x[i],
229 						powInfo[lowIndex + 1].tPow2x[i]);
230 		}
231 	}
232 }
233 
234 u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
235 				bool is2GHz, int num_band_edges)
236 {
237 	u16 twiceMaxEdgePower = MAX_RATE_POWER;
238 	int i;
239 
240 	for (i = 0; (i < num_band_edges) &&
241 		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
242 		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
243 			twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
244 			break;
245 		} else if ((i > 0) &&
246 			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
247 						      is2GHz))) {
248 			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
249 					       is2GHz) < freq &&
250 			    CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
251 				twiceMaxEdgePower =
252 					CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
253 			}
254 			break;
255 		}
256 	}
257 
258 	return twiceMaxEdgePower;
259 }
260 
261 void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
262 {
263 	struct ath_common *common = ath9k_hw_common(ah);
264 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
265 
266 	switch (ar5416_get_ntxchains(ah->txchainmask)) {
267 	case 1:
268 		break;
269 	case 2:
270 		regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
271 		break;
272 	case 3:
273 		regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
274 		break;
275 	default:
276 		ath_dbg(common, ATH_DBG_EEPROM,
277 			"Invalid chainmask configuration\n");
278 		break;
279 	}
280 }
281 
282 void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
283 				struct ath9k_channel *chan,
284 				void *pRawDataSet,
285 				u8 *bChans, u16 availPiers,
286 				u16 tPdGainOverlap,
287 				u16 *pPdGainBoundaries, u8 *pPDADCValues,
288 				u16 numXpdGains)
289 {
290 	int i, j, k;
291 	int16_t ss;
292 	u16 idxL = 0, idxR = 0, numPiers;
293 	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
294 		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
295 	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
296 		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
297 	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
298 		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
299 
300 	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
301 	u8 minPwrT4[AR5416_NUM_PD_GAINS];
302 	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
303 	int16_t vpdStep;
304 	int16_t tmpVal;
305 	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
306 	bool match;
307 	int16_t minDelta = 0;
308 	struct chan_centers centers;
309 	int pdgain_boundary_default;
310 	struct cal_data_per_freq *data_def = pRawDataSet;
311 	struct cal_data_per_freq_4k *data_4k = pRawDataSet;
312 	struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
313 	bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
314 	int intercepts;
315 
316 	if (AR_SREV_9287(ah))
317 		intercepts = AR9287_PD_GAIN_ICEPTS;
318 	else
319 		intercepts = AR5416_PD_GAIN_ICEPTS;
320 
321 	memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
322 	ath9k_hw_get_channel_centers(ah, chan, &centers);
323 
324 	for (numPiers = 0; numPiers < availPiers; numPiers++) {
325 		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
326 			break;
327 	}
328 
329 	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
330 							     IS_CHAN_2GHZ(chan)),
331 					       bChans, numPiers, &idxL, &idxR);
332 
333 	if (match) {
334 		if (AR_SREV_9287(ah)) {
335 			/* FIXME: array overrun? */
336 			for (i = 0; i < numXpdGains; i++) {
337 				minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
338 				maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
339 				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
340 						data_9287[idxL].pwrPdg[i],
341 						data_9287[idxL].vpdPdg[i],
342 						intercepts,
343 						vpdTableI[i]);
344 			}
345 		} else if (eeprom_4k) {
346 			for (i = 0; i < numXpdGains; i++) {
347 				minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
348 				maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
349 				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
350 						data_4k[idxL].pwrPdg[i],
351 						data_4k[idxL].vpdPdg[i],
352 						intercepts,
353 						vpdTableI[i]);
354 			}
355 		} else {
356 			for (i = 0; i < numXpdGains; i++) {
357 				minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
358 				maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
359 				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
360 						data_def[idxL].pwrPdg[i],
361 						data_def[idxL].vpdPdg[i],
362 						intercepts,
363 						vpdTableI[i]);
364 			}
365 		}
366 	} else {
367 		for (i = 0; i < numXpdGains; i++) {
368 			if (AR_SREV_9287(ah)) {
369 				pVpdL = data_9287[idxL].vpdPdg[i];
370 				pPwrL = data_9287[idxL].pwrPdg[i];
371 				pVpdR = data_9287[idxR].vpdPdg[i];
372 				pPwrR = data_9287[idxR].pwrPdg[i];
373 			} else if (eeprom_4k) {
374 				pVpdL = data_4k[idxL].vpdPdg[i];
375 				pPwrL = data_4k[idxL].pwrPdg[i];
376 				pVpdR = data_4k[idxR].vpdPdg[i];
377 				pPwrR = data_4k[idxR].pwrPdg[i];
378 			} else {
379 				pVpdL = data_def[idxL].vpdPdg[i];
380 				pPwrL = data_def[idxL].pwrPdg[i];
381 				pVpdR = data_def[idxR].vpdPdg[i];
382 				pPwrR = data_def[idxR].pwrPdg[i];
383 			}
384 
385 			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
386 
387 			maxPwrT4[i] =
388 				min(pPwrL[intercepts - 1],
389 				    pPwrR[intercepts - 1]);
390 
391 
392 			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
393 						pPwrL, pVpdL,
394 						intercepts,
395 						vpdTableL[i]);
396 			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
397 						pPwrR, pVpdR,
398 						intercepts,
399 						vpdTableR[i]);
400 
401 			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
402 				vpdTableI[i][j] =
403 					(u8)(ath9k_hw_interpolate((u16)
404 					     FREQ2FBIN(centers.
405 						       synth_center,
406 						       IS_CHAN_2GHZ
407 						       (chan)),
408 					     bChans[idxL], bChans[idxR],
409 					     vpdTableL[i][j], vpdTableR[i][j]));
410 			}
411 		}
412 	}
413 
414 	k = 0;
415 
416 	for (i = 0; i < numXpdGains; i++) {
417 		if (i == (numXpdGains - 1))
418 			pPdGainBoundaries[i] =
419 				(u16)(maxPwrT4[i] / 2);
420 		else
421 			pPdGainBoundaries[i] =
422 				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
423 
424 		pPdGainBoundaries[i] =
425 			min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
426 
427 		if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
428 			minDelta = pPdGainBoundaries[0] - 23;
429 			pPdGainBoundaries[0] = 23;
430 		} else {
431 			minDelta = 0;
432 		}
433 
434 		if (i == 0) {
435 			if (AR_SREV_9280_20_OR_LATER(ah))
436 				ss = (int16_t)(0 - (minPwrT4[i] / 2));
437 			else
438 				ss = 0;
439 		} else {
440 			ss = (int16_t)((pPdGainBoundaries[i - 1] -
441 					(minPwrT4[i] / 2)) -
442 				       tPdGainOverlap + 1 + minDelta);
443 		}
444 		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
445 		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
446 
447 		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
448 			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
449 			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
450 			ss++;
451 		}
452 
453 		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
454 		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
455 				(minPwrT4[i] / 2));
456 		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
457 			tgtIndex : sizeCurrVpdTable;
458 
459 		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
460 			pPDADCValues[k++] = vpdTableI[i][ss++];
461 		}
462 
463 		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
464 				    vpdTableI[i][sizeCurrVpdTable - 2]);
465 		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
466 
467 		if (tgtIndex >= maxIndex) {
468 			while ((ss <= tgtIndex) &&
469 			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
470 				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
471 						    (ss - maxIndex + 1) * vpdStep));
472 				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
473 							 255 : tmpVal);
474 				ss++;
475 			}
476 		}
477 	}
478 
479 	if (eeprom_4k)
480 		pdgain_boundary_default = 58;
481 	else
482 		pdgain_boundary_default = pPdGainBoundaries[i - 1];
483 
484 	while (i < AR5416_PD_GAINS_IN_MASK) {
485 		pPdGainBoundaries[i] = pdgain_boundary_default;
486 		i++;
487 	}
488 
489 	while (k < AR5416_NUM_PDADC_VALUES) {
490 		pPDADCValues[k] = pPDADCValues[k - 1];
491 		k++;
492 	}
493 }
494 
495 int ath9k_hw_eeprom_init(struct ath_hw *ah)
496 {
497 	int status;
498 
499 	if (AR_SREV_9300_20_OR_LATER(ah))
500 		ah->eep_ops = &eep_ar9300_ops;
501 	else if (AR_SREV_9287(ah)) {
502 		ah->eep_ops = &eep_ar9287_ops;
503 	} else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
504 		ah->eep_ops = &eep_4k_ops;
505 	} else {
506 		ah->eep_ops = &eep_def_ops;
507 	}
508 
509 	if (!ah->eep_ops->fill_eeprom(ah))
510 		return -EIO;
511 
512 	status = ah->eep_ops->check_eeprom(ah);
513 
514 	return status;
515 }
516