2 * Copyright (c) 2008-2009 Atheros Communications Inc.
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.
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.
19 static inline u16
ath9k_hw_fbin2freq(u8 fbin
, bool is2GHz
)
21 if (fbin
== AR5416_BCHAN_UNUSED
)
24 return (u16
) ((is2GHz
) ? (2300 + fbin
) : (4800 + 5 * fbin
));
27 void ath9k_hw_analog_shift_regwrite(struct ath_hw
*ah
, u32 reg
, u32 val
)
29 REG_WRITE(ah
, reg
, val
);
31 if (ah
->config
.analog_shiftreg
)
35 void ath9k_hw_analog_shift_rmw(struct ath_hw
*ah
, u32 reg
, u32 mask
,
40 regVal
= REG_READ(ah
, reg
) & ~mask
;
41 regVal
|= (val
<< shift
) & mask
;
43 REG_WRITE(ah
, reg
, regVal
);
45 if (ah
->config
.analog_shiftreg
)
49 int16_t ath9k_hw_interpolate(u16 target
, u16 srcLeft
, u16 srcRight
,
50 int16_t targetLeft
, int16_t targetRight
)
54 if (srcRight
== srcLeft
) {
57 rv
= (int16_t) (((target
- srcLeft
) * targetRight
+
58 (srcRight
- target
) * targetLeft
) /
59 (srcRight
- srcLeft
));
64 bool ath9k_hw_get_lower_upper_index(u8 target
, u8
*pList
, u16 listSize
,
65 u16
*indexL
, u16
*indexR
)
69 if (target
<= pList
[0]) {
70 *indexL
= *indexR
= 0;
73 if (target
>= pList
[listSize
- 1]) {
74 *indexL
= *indexR
= (u16
) (listSize
- 1);
78 for (i
= 0; i
< listSize
- 1; i
++) {
79 if (pList
[i
] == target
) {
80 *indexL
= *indexR
= i
;
83 if (target
< pList
[i
+ 1]) {
85 *indexR
= (u16
) (i
+ 1);
92 void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw
*ah
, u16
*eep_data
,
93 int eep_start_loc
, int size
)
99 for (addr
= 0; addr
< size
; addr
++) {
100 addrdata
[i
] = AR5416_EEPROM_OFFSET
+
101 ((addr
+ eep_start_loc
) << AR5416_EEPROM_S
);
104 REG_READ_MULTI(ah
, addrdata
, data
, i
);
106 for (j
= 0; j
< i
; j
++) {
115 REG_READ_MULTI(ah
, addrdata
, data
, i
);
117 for (j
= 0; j
< i
; j
++) {
124 bool ath9k_hw_nvram_read(struct ath_common
*common
, u32 off
, u16
*data
)
126 return common
->bus_ops
->eeprom_read(common
, off
, data
);
129 void ath9k_hw_fill_vpd_table(u8 pwrMin
, u8 pwrMax
, u8
*pPwrList
,
130 u8
*pVpdList
, u16 numIntercepts
,
135 u16 idxL
= 0, idxR
= 0;
137 for (i
= 0; i
<= (pwrMax
- pwrMin
) / 2; i
++) {
138 ath9k_hw_get_lower_upper_index(currPwr
, pPwrList
,
139 numIntercepts
, &(idxL
),
143 if (idxL
== numIntercepts
- 1)
144 idxL
= (u16
) (numIntercepts
- 2);
145 if (pPwrList
[idxL
] == pPwrList
[idxR
])
148 k
= (u16
)(((currPwr
- pPwrList
[idxL
]) * pVpdList
[idxR
] +
149 (pPwrList
[idxR
] - currPwr
) * pVpdList
[idxL
]) /
150 (pPwrList
[idxR
] - pPwrList
[idxL
]));
151 pRetVpdList
[i
] = (u8
) k
;
156 void ath9k_hw_get_legacy_target_powers(struct ath_hw
*ah
,
157 struct ath9k_channel
*chan
,
158 struct cal_target_power_leg
*powInfo
,
160 struct cal_target_power_leg
*pNewPower
,
161 u16 numRates
, bool isExtTarget
)
163 struct chan_centers centers
;
166 int matchIndex
= -1, lowIndex
= -1;
169 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
170 freq
= (isExtTarget
) ? centers
.ext_center
: centers
.ctl_center
;
172 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
,
173 IS_CHAN_2GHZ(chan
))) {
176 for (i
= 0; (i
< numChannels
) &&
177 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
178 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
179 IS_CHAN_2GHZ(chan
))) {
182 } else if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
183 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
184 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
185 IS_CHAN_2GHZ(chan
))) {
190 if ((matchIndex
== -1) && (lowIndex
== -1))
194 if (matchIndex
!= -1) {
195 *pNewPower
= powInfo
[matchIndex
];
197 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
199 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
202 for (i
= 0; i
< numRates
; i
++) {
203 pNewPower
->tPow2x
[i
] =
204 (u8
)ath9k_hw_interpolate(freq
, clo
, chi
,
205 powInfo
[lowIndex
].tPow2x
[i
],
206 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
211 void ath9k_hw_get_target_powers(struct ath_hw
*ah
,
212 struct ath9k_channel
*chan
,
213 struct cal_target_power_ht
*powInfo
,
215 struct cal_target_power_ht
*pNewPower
,
216 u16 numRates
, bool isHt40Target
)
218 struct chan_centers centers
;
221 int matchIndex
= -1, lowIndex
= -1;
224 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
225 freq
= isHt40Target
? centers
.synth_center
: centers
.ctl_center
;
227 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
, IS_CHAN_2GHZ(chan
))) {
230 for (i
= 0; (i
< numChannels
) &&
231 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
232 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
233 IS_CHAN_2GHZ(chan
))) {
237 if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
238 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
239 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
240 IS_CHAN_2GHZ(chan
))) {
245 if ((matchIndex
== -1) && (lowIndex
== -1))
249 if (matchIndex
!= -1) {
250 *pNewPower
= powInfo
[matchIndex
];
252 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
254 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
257 for (i
= 0; i
< numRates
; i
++) {
258 pNewPower
->tPow2x
[i
] = (u8
)ath9k_hw_interpolate(freq
,
260 powInfo
[lowIndex
].tPow2x
[i
],
261 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
266 u16
ath9k_hw_get_max_edge_power(u16 freq
, struct cal_ctl_edges
*pRdEdgesPower
,
267 bool is2GHz
, int num_band_edges
)
269 u16 twiceMaxEdgePower
= MAX_RATE_POWER
;
272 for (i
= 0; (i
< num_band_edges
) &&
273 (pRdEdgesPower
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
274 if (freq
== ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
, is2GHz
)) {
275 twiceMaxEdgePower
= CTL_EDGE_TPOWER(pRdEdgesPower
[i
].ctl
);
277 } else if ((i
> 0) &&
278 (freq
< ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
,
280 if (ath9k_hw_fbin2freq(pRdEdgesPower
[i
- 1].bChannel
,
282 CTL_EDGE_FLAGS(pRdEdgesPower
[i
- 1].ctl
)) {
284 CTL_EDGE_TPOWER(pRdEdgesPower
[i
- 1].ctl
);
290 return twiceMaxEdgePower
;
293 void ath9k_hw_update_regulatory_maxpower(struct ath_hw
*ah
)
295 struct ath_common
*common
= ath9k_hw_common(ah
);
296 struct ath_regulatory
*regulatory
= ath9k_hw_regulatory(ah
);
298 switch (ar5416_get_ntxchains(ah
->txchainmask
)) {
302 regulatory
->max_power_level
+= INCREASE_MAXPOW_BY_TWO_CHAIN
;
305 regulatory
->max_power_level
+= INCREASE_MAXPOW_BY_THREE_CHAIN
;
308 ath_dbg(common
, ATH_DBG_EEPROM
,
309 "Invalid chainmask configuration\n");
314 void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw
*ah
,
315 struct ath9k_channel
*chan
,
317 u8
*bChans
, u16 availPiers
,
319 u16
*pPdGainBoundaries
, u8
*pPDADCValues
,
324 u16 idxL
= 0, idxR
= 0, numPiers
;
325 static u8 vpdTableL
[AR5416_NUM_PD_GAINS
]
326 [AR5416_MAX_PWR_RANGE_IN_HALF_DB
];
327 static u8 vpdTableR
[AR5416_NUM_PD_GAINS
]
328 [AR5416_MAX_PWR_RANGE_IN_HALF_DB
];
329 static u8 vpdTableI
[AR5416_NUM_PD_GAINS
]
330 [AR5416_MAX_PWR_RANGE_IN_HALF_DB
];
332 u8
*pVpdL
, *pVpdR
, *pPwrL
, *pPwrR
;
333 u8 minPwrT4
[AR5416_NUM_PD_GAINS
];
334 u8 maxPwrT4
[AR5416_NUM_PD_GAINS
];
337 u16 sizeCurrVpdTable
, maxIndex
, tgtIndex
;
339 int16_t minDelta
= 0;
340 struct chan_centers centers
;
341 int pdgain_boundary_default
;
342 struct cal_data_per_freq
*data_def
= pRawDataSet
;
343 struct cal_data_per_freq_4k
*data_4k
= pRawDataSet
;
344 struct cal_data_per_freq_ar9287
*data_9287
= pRawDataSet
;
345 bool eeprom_4k
= AR_SREV_9285(ah
) || AR_SREV_9271(ah
);
348 if (AR_SREV_9287(ah
))
349 intercepts
= AR9287_PD_GAIN_ICEPTS
;
351 intercepts
= AR5416_PD_GAIN_ICEPTS
;
353 memset(&minPwrT4
, 0, AR5416_NUM_PD_GAINS
);
354 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
356 for (numPiers
= 0; numPiers
< availPiers
; numPiers
++) {
357 if (bChans
[numPiers
] == AR5416_BCHAN_UNUSED
)
361 match
= ath9k_hw_get_lower_upper_index((u8
)FREQ2FBIN(centers
.synth_center
,
363 bChans
, numPiers
, &idxL
, &idxR
);
366 if (AR_SREV_9287(ah
)) {
367 /* FIXME: array overrun? */
368 for (i
= 0; i
< numXpdGains
; i
++) {
369 minPwrT4
[i
] = data_9287
[idxL
].pwrPdg
[i
][0];
370 maxPwrT4
[i
] = data_9287
[idxL
].pwrPdg
[i
][4];
371 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
372 data_9287
[idxL
].pwrPdg
[i
],
373 data_9287
[idxL
].vpdPdg
[i
],
377 } else if (eeprom_4k
) {
378 for (i
= 0; i
< numXpdGains
; i
++) {
379 minPwrT4
[i
] = data_4k
[idxL
].pwrPdg
[i
][0];
380 maxPwrT4
[i
] = data_4k
[idxL
].pwrPdg
[i
][4];
381 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
382 data_4k
[idxL
].pwrPdg
[i
],
383 data_4k
[idxL
].vpdPdg
[i
],
388 for (i
= 0; i
< numXpdGains
; i
++) {
389 minPwrT4
[i
] = data_def
[idxL
].pwrPdg
[i
][0];
390 maxPwrT4
[i
] = data_def
[idxL
].pwrPdg
[i
][4];
391 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
392 data_def
[idxL
].pwrPdg
[i
],
393 data_def
[idxL
].vpdPdg
[i
],
399 for (i
= 0; i
< numXpdGains
; i
++) {
400 if (AR_SREV_9287(ah
)) {
401 pVpdL
= data_9287
[idxL
].vpdPdg
[i
];
402 pPwrL
= data_9287
[idxL
].pwrPdg
[i
];
403 pVpdR
= data_9287
[idxR
].vpdPdg
[i
];
404 pPwrR
= data_9287
[idxR
].pwrPdg
[i
];
405 } else if (eeprom_4k
) {
406 pVpdL
= data_4k
[idxL
].vpdPdg
[i
];
407 pPwrL
= data_4k
[idxL
].pwrPdg
[i
];
408 pVpdR
= data_4k
[idxR
].vpdPdg
[i
];
409 pPwrR
= data_4k
[idxR
].pwrPdg
[i
];
411 pVpdL
= data_def
[idxL
].vpdPdg
[i
];
412 pPwrL
= data_def
[idxL
].pwrPdg
[i
];
413 pVpdR
= data_def
[idxR
].vpdPdg
[i
];
414 pPwrR
= data_def
[idxR
].pwrPdg
[i
];
417 minPwrT4
[i
] = max(pPwrL
[0], pPwrR
[0]);
420 min(pPwrL
[intercepts
- 1],
421 pPwrR
[intercepts
- 1]);
424 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
428 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
433 for (j
= 0; j
<= (maxPwrT4
[i
] - minPwrT4
[i
]) / 2; j
++) {
435 (u8
)(ath9k_hw_interpolate((u16
)
440 bChans
[idxL
], bChans
[idxR
],
441 vpdTableL
[i
][j
], vpdTableR
[i
][j
]));
448 for (i
= 0; i
< numXpdGains
; i
++) {
449 if (i
== (numXpdGains
- 1))
450 pPdGainBoundaries
[i
] =
451 (u16
)(maxPwrT4
[i
] / 2);
453 pPdGainBoundaries
[i
] =
454 (u16
)((maxPwrT4
[i
] + minPwrT4
[i
+ 1]) / 4);
456 pPdGainBoundaries
[i
] =
457 min((u16
)MAX_RATE_POWER
, pPdGainBoundaries
[i
]);
459 if ((i
== 0) && !AR_SREV_5416_20_OR_LATER(ah
)) {
460 minDelta
= pPdGainBoundaries
[0] - 23;
461 pPdGainBoundaries
[0] = 23;
467 if (AR_SREV_9280_20_OR_LATER(ah
))
468 ss
= (int16_t)(0 - (minPwrT4
[i
] / 2));
472 ss
= (int16_t)((pPdGainBoundaries
[i
- 1] -
474 tPdGainOverlap
+ 1 + minDelta
);
476 vpdStep
= (int16_t)(vpdTableI
[i
][1] - vpdTableI
[i
][0]);
477 vpdStep
= (int16_t)((vpdStep
< 1) ? 1 : vpdStep
);
479 while ((ss
< 0) && (k
< (AR5416_NUM_PDADC_VALUES
- 1))) {
480 tmpVal
= (int16_t)(vpdTableI
[i
][0] + ss
* vpdStep
);
481 pPDADCValues
[k
++] = (u8
)((tmpVal
< 0) ? 0 : tmpVal
);
485 sizeCurrVpdTable
= (u8
) ((maxPwrT4
[i
] - minPwrT4
[i
]) / 2 + 1);
486 tgtIndex
= (u8
)(pPdGainBoundaries
[i
] + tPdGainOverlap
-
488 maxIndex
= (tgtIndex
< sizeCurrVpdTable
) ?
489 tgtIndex
: sizeCurrVpdTable
;
491 while ((ss
< maxIndex
) && (k
< (AR5416_NUM_PDADC_VALUES
- 1))) {
492 pPDADCValues
[k
++] = vpdTableI
[i
][ss
++];
495 vpdStep
= (int16_t)(vpdTableI
[i
][sizeCurrVpdTable
- 1] -
496 vpdTableI
[i
][sizeCurrVpdTable
- 2]);
497 vpdStep
= (int16_t)((vpdStep
< 1) ? 1 : vpdStep
);
499 if (tgtIndex
>= maxIndex
) {
500 while ((ss
<= tgtIndex
) &&
501 (k
< (AR5416_NUM_PDADC_VALUES
- 1))) {
502 tmpVal
= (int16_t)((vpdTableI
[i
][sizeCurrVpdTable
- 1] +
503 (ss
- maxIndex
+ 1) * vpdStep
));
504 pPDADCValues
[k
++] = (u8
)((tmpVal
> 255) ?
512 pdgain_boundary_default
= 58;
514 pdgain_boundary_default
= pPdGainBoundaries
[i
- 1];
516 while (i
< AR5416_PD_GAINS_IN_MASK
) {
517 pPdGainBoundaries
[i
] = pdgain_boundary_default
;
521 while (k
< AR5416_NUM_PDADC_VALUES
) {
522 pPDADCValues
[k
] = pPDADCValues
[k
- 1];
527 int ath9k_hw_eeprom_init(struct ath_hw
*ah
)
531 if (AR_SREV_9300_20_OR_LATER(ah
))
532 ah
->eep_ops
= &eep_ar9300_ops
;
533 else if (AR_SREV_9287(ah
)) {
534 ah
->eep_ops
= &eep_ar9287_ops
;
535 } else if (AR_SREV_9285(ah
) || AR_SREV_9271(ah
)) {
536 ah
->eep_ops
= &eep_4k_ops
;
538 ah
->eep_ops
= &eep_def_ops
;
541 if (!ah
->eep_ops
->fill_eeprom(ah
))
544 status
= ah
->eep_ops
->check_eeprom(ah
);