Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ath/ath_hal/ar5212/ar2316.c
39566 views
1
/*-
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
5
* Copyright (c) 2002-2008 Atheros Communications, Inc.
6
*
7
* Permission to use, copy, modify, and/or distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*/
19
#include "opt_ah.h"
20
21
#include "ah.h"
22
#include "ah_internal.h"
23
24
#include "ar5212/ar5212.h"
25
#include "ar5212/ar5212reg.h"
26
#include "ar5212/ar5212phy.h"
27
28
#include "ah_eeprom_v3.h"
29
30
#define AH_5212_2316
31
#include "ar5212/ar5212.ini"
32
33
#define N(a) (sizeof(a)/sizeof(a[0]))
34
35
typedef RAW_DATA_STRUCT_2413 RAW_DATA_STRUCT_2316;
36
typedef RAW_DATA_PER_CHANNEL_2413 RAW_DATA_PER_CHANNEL_2316;
37
#define PWR_TABLE_SIZE_2316 PWR_TABLE_SIZE_2413
38
39
struct ar2316State {
40
RF_HAL_FUNCS base; /* public state, must be first */
41
uint16_t pcdacTable[PWR_TABLE_SIZE_2316];
42
43
uint32_t Bank1Data[N(ar5212Bank1_2316)];
44
uint32_t Bank2Data[N(ar5212Bank2_2316)];
45
uint32_t Bank3Data[N(ar5212Bank3_2316)];
46
uint32_t Bank6Data[N(ar5212Bank6_2316)];
47
uint32_t Bank7Data[N(ar5212Bank7_2316)];
48
49
/*
50
* Private state for reduced stack usage.
51
*/
52
/* filled out Vpd table for all pdGains (chanL) */
53
uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL]
54
[MAX_PWR_RANGE_IN_HALF_DB];
55
/* filled out Vpd table for all pdGains (chanR) */
56
uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL]
57
[MAX_PWR_RANGE_IN_HALF_DB];
58
/* filled out Vpd table for all pdGains (interpolated) */
59
uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL]
60
[MAX_PWR_RANGE_IN_HALF_DB];
61
};
62
#define AR2316(ah) ((struct ar2316State *) AH5212(ah)->ah_rfHal)
63
64
extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
65
uint32_t numBits, uint32_t firstBit, uint32_t column);
66
67
static void
68
ar2316WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
69
int regWrites)
70
{
71
struct ath_hal_5212 *ahp = AH5212(ah);
72
73
HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2316, modesIndex, regWrites);
74
HAL_INI_WRITE_ARRAY(ah, ar5212Common_2316, 1, regWrites);
75
HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2316, freqIndex, regWrites);
76
77
/* For AP51 */
78
if (!ahp->ah_cwCalRequire) {
79
OS_REG_WRITE(ah, 0xa358, (OS_REG_READ(ah, 0xa358) & ~0x2));
80
} else {
81
ahp->ah_cwCalRequire = AH_FALSE;
82
}
83
}
84
85
/*
86
* Take the MHz channel value and set the Channel value
87
*
88
* ASSUMES: Writes enabled to analog bus
89
*/
90
static HAL_BOOL
91
ar2316SetChannel(struct ath_hal *ah, struct ieee80211_channel *chan)
92
{
93
uint16_t freq = ath_hal_gethwchannel(ah, chan);
94
uint32_t channelSel = 0;
95
uint32_t bModeSynth = 0;
96
uint32_t aModeRefSel = 0;
97
uint32_t reg32 = 0;
98
99
OS_MARK(ah, AH_MARK_SETCHANNEL, freq);
100
101
if (freq < 4800) {
102
uint32_t txctl;
103
104
if (((freq - 2192) % 5) == 0) {
105
channelSel = ((freq - 672) * 2 - 3040)/10;
106
bModeSynth = 0;
107
} else if (((freq - 2224) % 5) == 0) {
108
channelSel = ((freq - 704) * 2 - 3040) / 10;
109
bModeSynth = 1;
110
} else {
111
HALDEBUG(ah, HAL_DEBUG_ANY,
112
"%s: invalid channel %u MHz\n",
113
__func__, freq);
114
return AH_FALSE;
115
}
116
117
channelSel = (channelSel << 2) & 0xff;
118
channelSel = ath_hal_reverseBits(channelSel, 8);
119
120
txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
121
if (freq == 2484) {
122
/* Enable channel spreading for channel 14 */
123
OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
124
txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
125
} else {
126
OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
127
txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
128
}
129
} else if ((freq % 20) == 0 && freq >= 5120) {
130
channelSel = ath_hal_reverseBits(
131
((freq - 4800) / 20 << 2), 8);
132
aModeRefSel = ath_hal_reverseBits(3, 2);
133
} else if ((freq % 10) == 0) {
134
channelSel = ath_hal_reverseBits(
135
((freq - 4800) / 10 << 1), 8);
136
aModeRefSel = ath_hal_reverseBits(2, 2);
137
} else if ((freq % 5) == 0) {
138
channelSel = ath_hal_reverseBits(
139
(freq - 4800) / 5, 8);
140
aModeRefSel = ath_hal_reverseBits(1, 2);
141
} else {
142
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
143
__func__, freq);
144
return AH_FALSE;
145
}
146
147
reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
148
(1 << 12) | 0x1;
149
OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
150
151
reg32 >>= 8;
152
OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
153
154
AH_PRIVATE(ah)->ah_curchan = chan;
155
return AH_TRUE;
156
}
157
158
/*
159
* Reads EEPROM header info from device structure and programs
160
* all rf registers
161
*
162
* REQUIRES: Access to the analog rf device
163
*/
164
static HAL_BOOL
165
ar2316SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan,
166
uint16_t modesIndex, uint16_t *rfXpdGain)
167
{
168
#define RF_BANK_SETUP(_priv, _ix, _col) do { \
169
int i; \
170
for (i = 0; i < N(ar5212Bank##_ix##_2316); i++) \
171
(_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2316[i][_col];\
172
} while (0)
173
struct ath_hal_5212 *ahp = AH5212(ah);
174
const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
175
uint16_t ob2GHz = 0, db2GHz = 0;
176
struct ar2316State *priv = AR2316(ah);
177
int regWrites = 0;
178
179
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n",
180
__func__, chan->ic_freq, chan->ic_flags, modesIndex);
181
182
HALASSERT(priv != AH_NULL);
183
184
/* Setup rf parameters */
185
if (IEEE80211_IS_CHAN_B(chan)) {
186
ob2GHz = ee->ee_obFor24;
187
db2GHz = ee->ee_dbFor24;
188
} else {
189
ob2GHz = ee->ee_obFor24g;
190
db2GHz = ee->ee_dbFor24g;
191
}
192
193
/* Bank 1 Write */
194
RF_BANK_SETUP(priv, 1, 1);
195
196
/* Bank 2 Write */
197
RF_BANK_SETUP(priv, 2, modesIndex);
198
199
/* Bank 3 Write */
200
RF_BANK_SETUP(priv, 3, modesIndex);
201
202
/* Bank 6 Write */
203
RF_BANK_SETUP(priv, 6, modesIndex);
204
205
ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 178, 0);
206
ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 175, 0);
207
208
/* Bank 7 Setup */
209
RF_BANK_SETUP(priv, 7, modesIndex);
210
211
/* Write Analog registers */
212
HAL_INI_WRITE_BANK(ah, ar5212Bank1_2316, priv->Bank1Data, regWrites);
213
HAL_INI_WRITE_BANK(ah, ar5212Bank2_2316, priv->Bank2Data, regWrites);
214
HAL_INI_WRITE_BANK(ah, ar5212Bank3_2316, priv->Bank3Data, regWrites);
215
HAL_INI_WRITE_BANK(ah, ar5212Bank6_2316, priv->Bank6Data, regWrites);
216
HAL_INI_WRITE_BANK(ah, ar5212Bank7_2316, priv->Bank7Data, regWrites);
217
218
/* Now that we have reprogrammed rfgain value, clear the flag. */
219
ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
220
221
return AH_TRUE;
222
#undef RF_BANK_SETUP
223
}
224
225
/*
226
* Return a reference to the requested RF Bank.
227
*/
228
static uint32_t *
229
ar2316GetRfBank(struct ath_hal *ah, int bank)
230
{
231
struct ar2316State *priv = AR2316(ah);
232
233
HALASSERT(priv != AH_NULL);
234
switch (bank) {
235
case 1: return priv->Bank1Data;
236
case 2: return priv->Bank2Data;
237
case 3: return priv->Bank3Data;
238
case 6: return priv->Bank6Data;
239
case 7: return priv->Bank7Data;
240
}
241
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
242
__func__, bank);
243
return AH_NULL;
244
}
245
246
/*
247
* Return indices surrounding the value in sorted integer lists.
248
*
249
* NB: the input list is assumed to be sorted in ascending order
250
*/
251
static void
252
GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize,
253
uint32_t *vlo, uint32_t *vhi)
254
{
255
int16_t target = v;
256
const int16_t *ep = lp+listSize;
257
const int16_t *tp;
258
259
/*
260
* Check first and last elements for out-of-bounds conditions.
261
*/
262
if (target < lp[0]) {
263
*vlo = *vhi = 0;
264
return;
265
}
266
if (target >= ep[-1]) {
267
*vlo = *vhi = listSize - 1;
268
return;
269
}
270
271
/* look for value being near or between 2 values in list */
272
for (tp = lp; tp < ep; tp++) {
273
/*
274
* If value is close to the current value of the list
275
* then target is not between values, it is one of the values
276
*/
277
if (*tp == target) {
278
*vlo = *vhi = tp - (const int16_t *) lp;
279
return;
280
}
281
/*
282
* Look for value being between current value and next value
283
* if so return these 2 values
284
*/
285
if (target < tp[1]) {
286
*vlo = tp - (const int16_t *) lp;
287
*vhi = *vlo + 1;
288
return;
289
}
290
}
291
}
292
293
/*
294
* Fill the Vpdlist for indices Pmax-Pmin
295
*/
296
static HAL_BOOL
297
ar2316FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax,
298
const int16_t *pwrList, const int16_t *VpdList,
299
uint16_t numIntercepts, uint16_t retVpdList[][64])
300
{
301
uint16_t ii, jj, kk;
302
int16_t currPwr = (int16_t)(2*Pmin);
303
/* since Pmin is pwr*2 and pwrList is 4*pwr */
304
uint32_t idxL, idxR;
305
306
ii = 0;
307
jj = 0;
308
309
if (numIntercepts < 2)
310
return AH_FALSE;
311
312
while (ii <= (uint16_t)(Pmax - Pmin)) {
313
GetLowerUpperIndex(currPwr, pwrList, numIntercepts,
314
&(idxL), &(idxR));
315
if (idxR < 1)
316
idxR = 1; /* extrapolate below */
317
if (idxL == (uint32_t)(numIntercepts - 1))
318
idxL = numIntercepts - 2; /* extrapolate above */
319
if (pwrList[idxL] == pwrList[idxR])
320
kk = VpdList[idxL];
321
else
322
kk = (uint16_t)
323
(((currPwr - pwrList[idxL])*VpdList[idxR]+
324
(pwrList[idxR] - currPwr)*VpdList[idxL])/
325
(pwrList[idxR] - pwrList[idxL]));
326
retVpdList[pdGainIdx][ii] = kk;
327
ii++;
328
currPwr += 2; /* half dB steps */
329
}
330
331
return AH_TRUE;
332
}
333
334
/*
335
* Returns interpolated or the scaled up interpolated value
336
*/
337
static int16_t
338
interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
339
int16_t targetLeft, int16_t targetRight)
340
{
341
int16_t rv;
342
343
if (srcRight != srcLeft) {
344
rv = ((target - srcLeft)*targetRight +
345
(srcRight - target)*targetLeft) / (srcRight - srcLeft);
346
} else {
347
rv = targetLeft;
348
}
349
return rv;
350
}
351
352
/*
353
* Uses the data points read from EEPROM to reconstruct the pdadc power table
354
* Called by ar2316SetPowerTable()
355
*/
356
static int
357
ar2316getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel,
358
const RAW_DATA_STRUCT_2316 *pRawDataset,
359
uint16_t pdGainOverlap_t2,
360
int16_t *pMinCalPower, uint16_t pPdGainBoundaries[],
361
uint16_t pPdGainValues[], uint16_t pPDADCValues[])
362
{
363
struct ar2316State *priv = AR2316(ah);
364
#define VpdTable_L priv->vpdTable_L
365
#define VpdTable_R priv->vpdTable_R
366
#define VpdTable_I priv->vpdTable_I
367
uint32_t ii, jj, kk;
368
int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */
369
uint32_t idxL, idxR;
370
uint32_t numPdGainsUsed = 0;
371
/*
372
* If desired to support -ve power levels in future, just
373
* change pwr_I_0 to signed 5-bits.
374
*/
375
int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
376
/* to accommodate -ve power levels later on. */
377
int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
378
/* to accommodate -ve power levels later on */
379
uint16_t numVpd = 0;
380
uint16_t Vpd_step;
381
int16_t tmpVal ;
382
uint32_t sizeCurrVpdTable, maxIndex, tgtIndex;
383
384
/* Get upper lower index */
385
GetLowerUpperIndex(channel, pRawDataset->pChannels,
386
pRawDataset->numChannels, &(idxL), &(idxR));
387
388
for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
389
jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
390
/* work backwards 'cause highest pdGain for lowest power */
391
numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd;
392
if (numVpd > 0) {
393
pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain;
394
Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0];
395
if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) {
396
Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0];
397
}
398
Pmin_t2[numPdGainsUsed] = (int16_t)
399
(Pmin_t2[numPdGainsUsed] / 2);
400
Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1];
401
if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1])
402
Pmax_t2[numPdGainsUsed] =
403
pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1];
404
Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2);
405
ar2316FillVpdTable(
406
numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
407
&(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]),
408
&(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L
409
);
410
ar2316FillVpdTable(
411
numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
412
&(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]),
413
&(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R
414
);
415
for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) {
416
VpdTable_I[numPdGainsUsed][kk] =
417
interpolate_signed(
418
channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR],
419
(int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]);
420
}
421
/* fill VpdTable_I for this pdGain */
422
numPdGainsUsed++;
423
}
424
/* if this pdGain is used */
425
}
426
427
*pMinCalPower = Pmin_t2[0];
428
kk = 0; /* index for the final table */
429
for (ii = 0; ii < numPdGainsUsed; ii++) {
430
if (ii == (numPdGainsUsed - 1))
431
pPdGainBoundaries[ii] = Pmax_t2[ii] +
432
PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB;
433
else
434
pPdGainBoundaries[ii] = (uint16_t)
435
((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 );
436
if (pPdGainBoundaries[ii] > 63) {
437
HALDEBUG(ah, HAL_DEBUG_ANY,
438
"%s: clamp pPdGainBoundaries[%d] %d\n",
439
__func__, ii, pPdGainBoundaries[ii]);/*XXX*/
440
pPdGainBoundaries[ii] = 63;
441
}
442
443
/* Find starting index for this pdGain */
444
if (ii == 0)
445
ss = 0; /* for the first pdGain, start from index 0 */
446
else
447
ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) -
448
pdGainOverlap_t2;
449
Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]);
450
Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
451
/*
452
*-ve ss indicates need to extrapolate data below for this pdGain
453
*/
454
while (ss < 0) {
455
tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step);
456
pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal);
457
ss++;
458
}
459
460
sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii];
461
tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii];
462
maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
463
464
while (ss < (int16_t)maxIndex)
465
pPDADCValues[kk++] = VpdTable_I[ii][ss++];
466
467
Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] -
468
VpdTable_I[ii][sizeCurrVpdTable-2]);
469
Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
470
/*
471
* for last gain, pdGainBoundary == Pmax_t2, so will
472
* have to extrapolate
473
*/
474
if (tgtIndex > maxIndex) { /* need to extrapolate above */
475
while(ss < (int16_t)tgtIndex) {
476
tmpVal = (uint16_t)
477
(VpdTable_I[ii][sizeCurrVpdTable-1] +
478
(ss-maxIndex)*Vpd_step);
479
pPDADCValues[kk++] = (tmpVal > 127) ?
480
127 : tmpVal;
481
ss++;
482
}
483
} /* extrapolated above */
484
} /* for all pdGainUsed */
485
486
while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) {
487
pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1];
488
ii++;
489
}
490
while (kk < 128) {
491
pPDADCValues[kk] = pPDADCValues[kk-1];
492
kk++;
493
}
494
495
return numPdGainsUsed;
496
#undef VpdTable_L
497
#undef VpdTable_R
498
#undef VpdTable_I
499
}
500
501
static HAL_BOOL
502
ar2316SetPowerTable(struct ath_hal *ah,
503
int16_t *minPower, int16_t *maxPower,
504
const struct ieee80211_channel *chan,
505
uint16_t *rfXpdGain)
506
{
507
struct ath_hal_5212 *ahp = AH5212(ah);
508
const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
509
const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
510
uint16_t pdGainOverlap_t2;
511
int16_t minCalPower2316_t2;
512
uint16_t *pdadcValues = ahp->ah_pcdacTable;
513
uint16_t gainBoundaries[4];
514
uint32_t reg32, regoffset;
515
int i, numPdGainsUsed;
516
#ifndef AH_USE_INIPDGAIN
517
uint32_t tpcrg1;
518
#endif
519
520
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
521
__func__, chan->ic_freq, chan->ic_flags);
522
523
if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
524
pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
525
else if (IEEE80211_IS_CHAN_B(chan))
526
pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
527
else {
528
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__);
529
return AH_FALSE;
530
}
531
532
pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5),
533
AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
534
535
numPdGainsUsed = ar2316getGainBoundariesAndPdadcsForPowers(ah,
536
chan->channel, pRawDataset, pdGainOverlap_t2,
537
&minCalPower2316_t2,gainBoundaries, rfXpdGain, pdadcValues);
538
HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
539
540
#ifdef AH_USE_INIPDGAIN
541
/*
542
* Use pd_gains curve from eeprom; Atheros always uses
543
* the default curve from the ini file but some vendors
544
* (e.g. Zcomax) want to override this curve and not
545
* honoring their settings results in tx power 5dBm low.
546
*/
547
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
548
(pRawDataset->pDataPerChannel[0].numPdGains - 1));
549
#else
550
tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
551
tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
552
| SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
553
switch (numPdGainsUsed) {
554
case 3:
555
tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3;
556
tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3);
557
/* fall thru... */
558
case 2:
559
tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2;
560
tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2);
561
/* fall thru... */
562
case 1:
563
tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1;
564
tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1);
565
break;
566
}
567
#ifdef AH_DEBUG
568
if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1))
569
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default "
570
"pd_gains (default 0x%x, calculated 0x%x)\n",
571
__func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
572
#endif
573
OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
574
#endif
575
576
/*
577
* Note the pdadc table may not start at 0 dBm power, could be
578
* negative or greater than 0. Need to offset the power
579
* values by the amount of minPower for griffin
580
*/
581
if (minCalPower2316_t2 != 0)
582
ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2316_t2);
583
else
584
ahp->ah_txPowerIndexOffset = 0;
585
586
/* Finally, write the power values into the baseband power table */
587
regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */
588
for (i = 0; i < 32; i++) {
589
reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) |
590
((pdadcValues[4*i + 1] & 0xFF) << 8) |
591
((pdadcValues[4*i + 2] & 0xFF) << 16) |
592
((pdadcValues[4*i + 3] & 0xFF) << 24) ;
593
OS_REG_WRITE(ah, regoffset, reg32);
594
regoffset += 4;
595
}
596
597
OS_REG_WRITE(ah, AR_PHY_TPCRG5,
598
SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
599
SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
600
SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
601
SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
602
SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
603
604
return AH_TRUE;
605
}
606
607
static int16_t
608
ar2316GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
609
{
610
uint32_t ii,jj;
611
uint16_t Pmin=0,numVpd;
612
613
for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
614
jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
615
/* work backwards 'cause highest pdGain for lowest power */
616
numVpd = data->pDataPerPDGain[jj].numVpd;
617
if (numVpd > 0) {
618
Pmin = data->pDataPerPDGain[jj].pwr_t4[0];
619
return(Pmin);
620
}
621
}
622
return(Pmin);
623
}
624
625
static int16_t
626
ar2316GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
627
{
628
uint32_t ii;
629
uint16_t Pmax=0,numVpd;
630
631
for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
632
/* work forwards cuase lowest pdGain for highest power */
633
numVpd = data->pDataPerPDGain[ii].numVpd;
634
if (numVpd > 0) {
635
Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1];
636
return(Pmax);
637
}
638
}
639
return(Pmax);
640
}
641
642
static HAL_BOOL
643
ar2316GetChannelMaxMinPower(struct ath_hal *ah,
644
const struct ieee80211_channel *chan,
645
int16_t *maxPow, int16_t *minPow)
646
{
647
uint16_t freq = chan->ic_freq; /* NB: never mapped */
648
const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
649
const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
650
const RAW_DATA_PER_CHANNEL_2316 *data=AH_NULL;
651
uint16_t numChannels;
652
int totalD,totalF, totalMin,last, i;
653
654
*maxPow = 0;
655
656
if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
657
pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
658
else if (IEEE80211_IS_CHAN_B(chan))
659
pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
660
else
661
return(AH_FALSE);
662
663
numChannels = pRawDataset->numChannels;
664
data = pRawDataset->pDataPerChannel;
665
666
/* Make sure the channel is in the range of the TP values
667
* (freq piers)
668
*/
669
if (numChannels < 1)
670
return(AH_FALSE);
671
672
if ((freq < data[0].channelValue) ||
673
(freq > data[numChannels-1].channelValue)) {
674
if (freq < data[0].channelValue) {
675
*maxPow = ar2316GetMaxPower(ah, &data[0]);
676
*minPow = ar2316GetMinPower(ah, &data[0]);
677
return(AH_TRUE);
678
} else {
679
*maxPow = ar2316GetMaxPower(ah, &data[numChannels - 1]);
680
*minPow = ar2316GetMinPower(ah, &data[numChannels - 1]);
681
return(AH_TRUE);
682
}
683
}
684
685
/* Linearly interpolate the power value now */
686
for (last=0,i=0; (i<numChannels) && (freq > data[i].channelValue);
687
last = i++);
688
totalD = data[i].channelValue - data[last].channelValue;
689
if (totalD > 0) {
690
totalF = ar2316GetMaxPower(ah, &data[i]) - ar2316GetMaxPower(ah, &data[last]);
691
*maxPow = (int8_t) ((totalF*(freq-data[last].channelValue) +
692
ar2316GetMaxPower(ah, &data[last])*totalD)/totalD);
693
totalMin = ar2316GetMinPower(ah, &data[i]) - ar2316GetMinPower(ah, &data[last]);
694
*minPow = (int8_t) ((totalMin*(freq-data[last].channelValue) +
695
ar2316GetMinPower(ah, &data[last])*totalD)/totalD);
696
return(AH_TRUE);
697
} else {
698
if (freq == data[i].channelValue) {
699
*maxPow = ar2316GetMaxPower(ah, &data[i]);
700
*minPow = ar2316GetMinPower(ah, &data[i]);
701
return(AH_TRUE);
702
} else
703
return(AH_FALSE);
704
}
705
}
706
707
/*
708
* Free memory for analog bank scratch buffers
709
*/
710
static void
711
ar2316RfDetach(struct ath_hal *ah)
712
{
713
struct ath_hal_5212 *ahp = AH5212(ah);
714
715
HALASSERT(ahp->ah_rfHal != AH_NULL);
716
ath_hal_free(ahp->ah_rfHal);
717
ahp->ah_rfHal = AH_NULL;
718
}
719
720
/*
721
* Allocate memory for private state.
722
* Scratch Buffer will be reinitialized every reset so no need to zero now
723
*/
724
static HAL_BOOL
725
ar2316RfAttach(struct ath_hal *ah, HAL_STATUS *status)
726
{
727
struct ath_hal_5212 *ahp = AH5212(ah);
728
struct ar2316State *priv;
729
730
HALASSERT(ah->ah_magic == AR5212_MAGIC);
731
732
HALASSERT(ahp->ah_rfHal == AH_NULL);
733
priv = ath_hal_malloc(sizeof(struct ar2316State));
734
if (priv == AH_NULL) {
735
HALDEBUG(ah, HAL_DEBUG_ANY,
736
"%s: cannot allocate private state\n", __func__);
737
*status = HAL_ENOMEM; /* XXX */
738
return AH_FALSE;
739
}
740
priv->base.rfDetach = ar2316RfDetach;
741
priv->base.writeRegs = ar2316WriteRegs;
742
priv->base.getRfBank = ar2316GetRfBank;
743
priv->base.setChannel = ar2316SetChannel;
744
priv->base.setRfRegs = ar2316SetRfRegs;
745
priv->base.setPowerTable = ar2316SetPowerTable;
746
priv->base.getChannelMaxMinPower = ar2316GetChannelMaxMinPower;
747
priv->base.getNfAdjust = ar5212GetNfAdjust;
748
749
ahp->ah_pcdacTable = priv->pcdacTable;
750
ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
751
ahp->ah_rfHal = &priv->base;
752
753
ahp->ah_cwCalRequire = AH_TRUE; /* force initial cal */
754
755
return AH_TRUE;
756
}
757
758
static HAL_BOOL
759
ar2316Probe(struct ath_hal *ah)
760
{
761
return IS_2316(ah);
762
}
763
AH_RF(RF2316, ar2316Probe, ar2316RfAttach);
764
765