2 * Copyright (c) 2008-2011 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.
18 #include <linux/ath9k_platform.h>
20 void ath9k_hw_analog_shift_regwrite(struct ath_hw
*ah
, u32 reg
, u32 val
)
22 REG_WRITE(ah
, reg
, val
);
24 if (ah
->config
.analog_shiftreg
)
28 void ath9k_hw_analog_shift_rmw(struct ath_hw
*ah
, u32 reg
, u32 mask
,
31 REG_RMW(ah
, reg
, ((val
<< shift
) & mask
), mask
);
33 if (ah
->config
.analog_shiftreg
)
37 int16_t ath9k_hw_interpolate(u16 target
, u16 srcLeft
, u16 srcRight
,
38 int16_t targetLeft
, int16_t targetRight
)
42 if (srcRight
== srcLeft
) {
45 rv
= (int16_t) (((target
- srcLeft
) * targetRight
+
46 (srcRight
- target
) * targetLeft
) /
47 (srcRight
- srcLeft
));
52 bool ath9k_hw_get_lower_upper_index(u8 target
, u8
*pList
, u16 listSize
,
53 u16
*indexL
, u16
*indexR
)
57 if (target
<= pList
[0]) {
58 *indexL
= *indexR
= 0;
61 if (target
>= pList
[listSize
- 1]) {
62 *indexL
= *indexR
= (u16
) (listSize
- 1);
66 for (i
= 0; i
< listSize
- 1; i
++) {
67 if (pList
[i
] == target
) {
68 *indexL
= *indexR
= i
;
71 if (target
< pList
[i
+ 1]) {
73 *indexR
= (u16
) (i
+ 1);
80 void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw
*ah
, u16
*eep_data
,
81 int eep_start_loc
, int size
)
87 for (addr
= 0; addr
< size
; addr
++) {
88 addrdata
[i
] = AR5416_EEPROM_OFFSET
+
89 ((addr
+ eep_start_loc
) << AR5416_EEPROM_S
);
92 REG_READ_MULTI(ah
, addrdata
, data
, i
);
94 for (j
= 0; j
< i
; j
++) {
103 REG_READ_MULTI(ah
, addrdata
, data
, i
);
105 for (j
= 0; j
< i
; j
++) {
112 static bool ath9k_hw_nvram_read_array(u16
*blob
, size_t blob_size
,
113 off_t offset
, u16
*data
)
115 if (offset
>= blob_size
)
118 *data
= blob
[offset
];
122 static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data
*pdata
,
123 off_t offset
, u16
*data
)
125 return ath9k_hw_nvram_read_array(pdata
->eeprom_data
,
126 ARRAY_SIZE(pdata
->eeprom_data
),
130 static bool ath9k_hw_nvram_read_firmware(const struct firmware
*eeprom_blob
,
131 off_t offset
, u16
*data
)
133 return ath9k_hw_nvram_read_array((u16
*) eeprom_blob
->data
,
134 eeprom_blob
->size
/ sizeof(u16
),
138 bool ath9k_hw_nvram_read(struct ath_hw
*ah
, u32 off
, u16
*data
)
140 struct ath_common
*common
= ath9k_hw_common(ah
);
141 struct ath9k_platform_data
*pdata
= ah
->dev
->platform_data
;
145 ret
= ath9k_hw_nvram_read_firmware(ah
->eeprom_blob
, off
, data
);
146 else if (pdata
&& !pdata
->use_eeprom
)
147 ret
= ath9k_hw_nvram_read_pdata(pdata
, off
, data
);
149 ret
= common
->bus_ops
->eeprom_read(common
, off
, data
);
152 ath_dbg(common
, EEPROM
,
153 "unable to read eeprom region at offset %u\n", off
);
158 int ath9k_hw_nvram_swap_data(struct ath_hw
*ah
, bool *swap_needed
, int size
)
163 bool needs_byteswap
= false;
164 struct ath_common
*common
= ath9k_hw_common(ah
);
166 if (!ath9k_hw_nvram_read(ah
, AR5416_EEPROM_MAGIC_OFFSET
, &magic
)) {
167 ath_err(common
, "Reading Magic # failed\n");
171 if (swab16(magic
) == AR5416_EEPROM_MAGIC
) {
172 needs_byteswap
= true;
173 ath_dbg(common
, EEPROM
,
174 "EEPROM needs byte-swapping to correct endianness.\n");
175 } else if (magic
!= AR5416_EEPROM_MAGIC
) {
176 if (ath9k_hw_use_flash(ah
)) {
177 ath_dbg(common
, EEPROM
,
178 "Ignoring invalid EEPROM magic (0x%04x).\n",
182 "Invalid EEPROM magic (0x%04x).\n", magic
);
187 if (needs_byteswap
) {
188 if (ah
->ah_flags
& AH_NO_EEP_SWAP
) {
190 "Ignoring endianness difference in EEPROM magic bytes.\n");
192 eepdata
= (u16
*)(&ah
->eeprom
);
194 for (i
= 0; i
< size
; i
++)
195 eepdata
[i
] = swab16(eepdata
[i
]);
199 if (ah
->eep_ops
->get_eepmisc(ah
) & AR5416_EEPMISC_BIG_ENDIAN
) {
201 ath_dbg(common
, EEPROM
,
202 "Big Endian EEPROM detected according to EEPMISC register.\n");
204 *swap_needed
= false;
210 bool ath9k_hw_nvram_validate_checksum(struct ath_hw
*ah
, int size
)
213 u16
*eepdata
= (u16
*)(&ah
->eeprom
);
214 struct ath_common
*common
= ath9k_hw_common(ah
);
216 for (i
= 0; i
< size
; i
++)
220 ath_err(common
, "Bad EEPROM checksum 0x%x\n", sum
);
227 bool ath9k_hw_nvram_check_version(struct ath_hw
*ah
, int version
, int minrev
)
229 struct ath_common
*common
= ath9k_hw_common(ah
);
231 if (ah
->eep_ops
->get_eeprom_ver(ah
) != version
||
232 ah
->eep_ops
->get_eeprom_rev(ah
) < minrev
) {
233 ath_err(common
, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
234 ah
->eep_ops
->get_eeprom_ver(ah
),
235 ah
->eep_ops
->get_eeprom_rev(ah
));
242 void ath9k_hw_fill_vpd_table(u8 pwrMin
, u8 pwrMax
, u8
*pPwrList
,
243 u8
*pVpdList
, u16 numIntercepts
,
248 u16 idxL
= 0, idxR
= 0;
250 for (i
= 0; i
<= (pwrMax
- pwrMin
) / 2; i
++) {
251 ath9k_hw_get_lower_upper_index(currPwr
, pPwrList
,
252 numIntercepts
, &(idxL
),
256 if (idxL
== numIntercepts
- 1)
257 idxL
= (u16
) (numIntercepts
- 2);
258 if (pPwrList
[idxL
] == pPwrList
[idxR
])
261 k
= (u16
)(((currPwr
- pPwrList
[idxL
]) * pVpdList
[idxR
] +
262 (pPwrList
[idxR
] - currPwr
) * pVpdList
[idxL
]) /
263 (pPwrList
[idxR
] - pPwrList
[idxL
]));
264 pRetVpdList
[i
] = (u8
) k
;
269 void ath9k_hw_get_legacy_target_powers(struct ath_hw
*ah
,
270 struct ath9k_channel
*chan
,
271 struct cal_target_power_leg
*powInfo
,
273 struct cal_target_power_leg
*pNewPower
,
274 u16 numRates
, bool isExtTarget
)
276 struct chan_centers centers
;
279 int matchIndex
= -1, lowIndex
= -1;
282 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
283 freq
= (isExtTarget
) ? centers
.ext_center
: centers
.ctl_center
;
285 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
,
286 IS_CHAN_2GHZ(chan
))) {
289 for (i
= 0; (i
< numChannels
) &&
290 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
291 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
292 IS_CHAN_2GHZ(chan
))) {
295 } else if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
296 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
297 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
298 IS_CHAN_2GHZ(chan
))) {
303 if ((matchIndex
== -1) && (lowIndex
== -1))
307 if (matchIndex
!= -1) {
308 *pNewPower
= powInfo
[matchIndex
];
310 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
312 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
315 for (i
= 0; i
< numRates
; i
++) {
316 pNewPower
->tPow2x
[i
] =
317 (u8
)ath9k_hw_interpolate(freq
, clo
, chi
,
318 powInfo
[lowIndex
].tPow2x
[i
],
319 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
324 void ath9k_hw_get_target_powers(struct ath_hw
*ah
,
325 struct ath9k_channel
*chan
,
326 struct cal_target_power_ht
*powInfo
,
328 struct cal_target_power_ht
*pNewPower
,
329 u16 numRates
, bool isHt40Target
)
331 struct chan_centers centers
;
334 int matchIndex
= -1, lowIndex
= -1;
337 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
338 freq
= isHt40Target
? centers
.synth_center
: centers
.ctl_center
;
340 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
, IS_CHAN_2GHZ(chan
))) {
343 for (i
= 0; (i
< numChannels
) &&
344 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
345 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
346 IS_CHAN_2GHZ(chan
))) {
350 if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
351 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
352 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
353 IS_CHAN_2GHZ(chan
))) {
358 if ((matchIndex
== -1) && (lowIndex
== -1))
362 if (matchIndex
!= -1) {
363 *pNewPower
= powInfo
[matchIndex
];
365 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
367 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
370 for (i
= 0; i
< numRates
; i
++) {
371 pNewPower
->tPow2x
[i
] = (u8
)ath9k_hw_interpolate(freq
,
373 powInfo
[lowIndex
].tPow2x
[i
],
374 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
379 u16
ath9k_hw_get_max_edge_power(u16 freq
, struct cal_ctl_edges
*pRdEdgesPower
,
380 bool is2GHz
, int num_band_edges
)
382 u16 twiceMaxEdgePower
= MAX_RATE_POWER
;
385 for (i
= 0; (i
< num_band_edges
) &&
386 (pRdEdgesPower
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
387 if (freq
== ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
, is2GHz
)) {
388 twiceMaxEdgePower
= CTL_EDGE_TPOWER(pRdEdgesPower
[i
].ctl
);
390 } else if ((i
> 0) &&
391 (freq
< ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
,
393 if (ath9k_hw_fbin2freq(pRdEdgesPower
[i
- 1].bChannel
,
395 CTL_EDGE_FLAGS(pRdEdgesPower
[i
- 1].ctl
)) {
397 CTL_EDGE_TPOWER(pRdEdgesPower
[i
- 1].ctl
);
403 return twiceMaxEdgePower
;
406 u16
ath9k_hw_get_scaled_power(struct ath_hw
*ah
, u16 power_limit
,
407 u8 antenna_reduction
)
409 u16 reduction
= antenna_reduction
;
412 * Reduce scaled Power by number of chains active
413 * to get the per chain tx power level.
415 switch (ar5416_get_ntxchains(ah
->txchainmask
)) {
419 reduction
+= POWER_CORRECTION_FOR_TWO_CHAIN
;
422 reduction
+= POWER_CORRECTION_FOR_THREE_CHAIN
;
426 if (power_limit
> reduction
)
427 power_limit
-= reduction
;
431 return min_t(u16
, power_limit
, MAX_RATE_POWER
);
434 void ath9k_hw_update_regulatory_maxpower(struct ath_hw
*ah
)
436 struct ath_common
*common
= ath9k_hw_common(ah
);
437 struct ath_regulatory
*regulatory
= ath9k_hw_regulatory(ah
);
439 switch (ar5416_get_ntxchains(ah
->txchainmask
)) {
443 regulatory
->max_power_level
+= POWER_CORRECTION_FOR_TWO_CHAIN
;
446 regulatory
->max_power_level
+= POWER_CORRECTION_FOR_THREE_CHAIN
;
449 ath_dbg(common
, EEPROM
, "Invalid chainmask configuration\n");
454 void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw
*ah
,
455 struct ath9k_channel
*chan
,
457 u8
*bChans
, u16 availPiers
,
459 u16
*pPdGainBoundaries
, u8
*pPDADCValues
,
464 u16 idxL
= 0, idxR
= 0, numPiers
;
465 static u8 vpdTableL
[AR5416_NUM_PD_GAINS
]
466 [AR5416_MAX_PWR_RANGE_IN_HALF_DB
];
467 static u8 vpdTableR
[AR5416_NUM_PD_GAINS
]
468 [AR5416_MAX_PWR_RANGE_IN_HALF_DB
];
469 static u8 vpdTableI
[AR5416_NUM_PD_GAINS
]
470 [AR5416_MAX_PWR_RANGE_IN_HALF_DB
];
472 u8
*pVpdL
, *pVpdR
, *pPwrL
, *pPwrR
;
473 u8 minPwrT4
[AR5416_NUM_PD_GAINS
];
474 u8 maxPwrT4
[AR5416_NUM_PD_GAINS
];
477 u16 sizeCurrVpdTable
, maxIndex
, tgtIndex
;
479 int16_t minDelta
= 0;
480 struct chan_centers centers
;
481 int pdgain_boundary_default
;
482 struct cal_data_per_freq
*data_def
= pRawDataSet
;
483 struct cal_data_per_freq_4k
*data_4k
= pRawDataSet
;
484 struct cal_data_per_freq_ar9287
*data_9287
= pRawDataSet
;
485 bool eeprom_4k
= AR_SREV_9285(ah
) || AR_SREV_9271(ah
);
488 if (AR_SREV_9287(ah
))
489 intercepts
= AR9287_PD_GAIN_ICEPTS
;
491 intercepts
= AR5416_PD_GAIN_ICEPTS
;
493 memset(&minPwrT4
, 0, AR5416_NUM_PD_GAINS
);
494 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
496 for (numPiers
= 0; numPiers
< availPiers
; numPiers
++) {
497 if (bChans
[numPiers
] == AR5416_BCHAN_UNUSED
)
501 match
= ath9k_hw_get_lower_upper_index((u8
)FREQ2FBIN(centers
.synth_center
,
503 bChans
, numPiers
, &idxL
, &idxR
);
506 if (AR_SREV_9287(ah
)) {
507 for (i
= 0; i
< numXpdGains
; i
++) {
508 minPwrT4
[i
] = data_9287
[idxL
].pwrPdg
[i
][0];
509 maxPwrT4
[i
] = data_9287
[idxL
].pwrPdg
[i
][intercepts
- 1];
510 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
511 data_9287
[idxL
].pwrPdg
[i
],
512 data_9287
[idxL
].vpdPdg
[i
],
516 } else if (eeprom_4k
) {
517 for (i
= 0; i
< numXpdGains
; i
++) {
518 minPwrT4
[i
] = data_4k
[idxL
].pwrPdg
[i
][0];
519 maxPwrT4
[i
] = data_4k
[idxL
].pwrPdg
[i
][intercepts
- 1];
520 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
521 data_4k
[idxL
].pwrPdg
[i
],
522 data_4k
[idxL
].vpdPdg
[i
],
527 for (i
= 0; i
< numXpdGains
; i
++) {
528 minPwrT4
[i
] = data_def
[idxL
].pwrPdg
[i
][0];
529 maxPwrT4
[i
] = data_def
[idxL
].pwrPdg
[i
][intercepts
- 1];
530 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
531 data_def
[idxL
].pwrPdg
[i
],
532 data_def
[idxL
].vpdPdg
[i
],
538 for (i
= 0; i
< numXpdGains
; i
++) {
539 if (AR_SREV_9287(ah
)) {
540 pVpdL
= data_9287
[idxL
].vpdPdg
[i
];
541 pPwrL
= data_9287
[idxL
].pwrPdg
[i
];
542 pVpdR
= data_9287
[idxR
].vpdPdg
[i
];
543 pPwrR
= data_9287
[idxR
].pwrPdg
[i
];
544 } else if (eeprom_4k
) {
545 pVpdL
= data_4k
[idxL
].vpdPdg
[i
];
546 pPwrL
= data_4k
[idxL
].pwrPdg
[i
];
547 pVpdR
= data_4k
[idxR
].vpdPdg
[i
];
548 pPwrR
= data_4k
[idxR
].pwrPdg
[i
];
550 pVpdL
= data_def
[idxL
].vpdPdg
[i
];
551 pPwrL
= data_def
[idxL
].pwrPdg
[i
];
552 pVpdR
= data_def
[idxR
].vpdPdg
[i
];
553 pPwrR
= data_def
[idxR
].pwrPdg
[i
];
556 minPwrT4
[i
] = max(pPwrL
[0], pPwrR
[0]);
559 min(pPwrL
[intercepts
- 1],
560 pPwrR
[intercepts
- 1]);
563 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
567 ath9k_hw_fill_vpd_table(minPwrT4
[i
], maxPwrT4
[i
],
572 for (j
= 0; j
<= (maxPwrT4
[i
] - minPwrT4
[i
]) / 2; j
++) {
574 (u8
)(ath9k_hw_interpolate((u16
)
579 bChans
[idxL
], bChans
[idxR
],
580 vpdTableL
[i
][j
], vpdTableR
[i
][j
]));
587 for (i
= 0; i
< numXpdGains
; i
++) {
588 if (i
== (numXpdGains
- 1))
589 pPdGainBoundaries
[i
] =
590 (u16
)(maxPwrT4
[i
] / 2);
592 pPdGainBoundaries
[i
] =
593 (u16
)((maxPwrT4
[i
] + minPwrT4
[i
+ 1]) / 4);
595 pPdGainBoundaries
[i
] =
596 min((u16
)MAX_RATE_POWER
, pPdGainBoundaries
[i
]);
601 if (AR_SREV_9280_20_OR_LATER(ah
))
602 ss
= (int16_t)(0 - (minPwrT4
[i
] / 2));
606 ss
= (int16_t)((pPdGainBoundaries
[i
- 1] -
608 tPdGainOverlap
+ 1 + minDelta
);
610 vpdStep
= (int16_t)(vpdTableI
[i
][1] - vpdTableI
[i
][0]);
611 vpdStep
= (int16_t)((vpdStep
< 1) ? 1 : vpdStep
);
613 while ((ss
< 0) && (k
< (AR5416_NUM_PDADC_VALUES
- 1))) {
614 tmpVal
= (int16_t)(vpdTableI
[i
][0] + ss
* vpdStep
);
615 pPDADCValues
[k
++] = (u8
)((tmpVal
< 0) ? 0 : tmpVal
);
619 sizeCurrVpdTable
= (u8
) ((maxPwrT4
[i
] - minPwrT4
[i
]) / 2 + 1);
620 tgtIndex
= (u8
)(pPdGainBoundaries
[i
] + tPdGainOverlap
-
622 maxIndex
= (tgtIndex
< sizeCurrVpdTable
) ?
623 tgtIndex
: sizeCurrVpdTable
;
625 while ((ss
< maxIndex
) && (k
< (AR5416_NUM_PDADC_VALUES
- 1))) {
626 pPDADCValues
[k
++] = vpdTableI
[i
][ss
++];
629 vpdStep
= (int16_t)(vpdTableI
[i
][sizeCurrVpdTable
- 1] -
630 vpdTableI
[i
][sizeCurrVpdTable
- 2]);
631 vpdStep
= (int16_t)((vpdStep
< 1) ? 1 : vpdStep
);
633 if (tgtIndex
>= maxIndex
) {
634 while ((ss
<= tgtIndex
) &&
635 (k
< (AR5416_NUM_PDADC_VALUES
- 1))) {
636 tmpVal
= (int16_t)((vpdTableI
[i
][sizeCurrVpdTable
- 1] +
637 (ss
- maxIndex
+ 1) * vpdStep
));
638 pPDADCValues
[k
++] = (u8
)((tmpVal
> 255) ?
646 pdgain_boundary_default
= 58;
648 pdgain_boundary_default
= pPdGainBoundaries
[i
- 1];
650 while (i
< AR5416_PD_GAINS_IN_MASK
) {
651 pPdGainBoundaries
[i
] = pdgain_boundary_default
;
655 while (k
< AR5416_NUM_PDADC_VALUES
) {
656 pPDADCValues
[k
] = pPDADCValues
[k
- 1];
661 int ath9k_hw_eeprom_init(struct ath_hw
*ah
)
665 if (AR_SREV_9300_20_OR_LATER(ah
))
666 ah
->eep_ops
= &eep_ar9300_ops
;
667 else if (AR_SREV_9287(ah
)) {
668 ah
->eep_ops
= &eep_ar9287_ops
;
669 } else if (AR_SREV_9285(ah
) || AR_SREV_9271(ah
)) {
670 ah
->eep_ops
= &eep_4k_ops
;
672 ah
->eep_ops
= &eep_def_ops
;
675 if (!ah
->eep_ops
->fill_eeprom(ah
))
678 status
= ah
->eep_ops
->check_eeprom(ah
);