1/*
2 * Copyright (c) 2013 Qualcomm Atheros, 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 WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "opt_ah.h"
18
19#include "ah.h"
20#include "ah_internal.h"
21
22#include "ar9300/ar9300.h"
23
24/* shorthands to compact tables for readability */
25#define    OFDM    IEEE80211_T_OFDM
26#define    CCK    IEEE80211_T_CCK
27#define    TURBO    IEEE80211_T_TURBO
28#define    XR    ATHEROS_T_XR
29#define HT      IEEE80211_T_HT
30
31#define AR9300_NUM_OFDM_RATES   8
32#define AR9300_NUM_HT_SS_RATES  8
33#define AR9300_NUM_HT_DS_RATES  8
34#define AR9300_NUM_HT_TS_RATES  8
35
36/* Array Gain defined for TxBF */
37#define AR9300_TXBF_2TX_ARRAY_GAIN  6  /* 2TX/SS 3 */
38#define AR9300_TXBF_3TX_ARRAY_GAIN  10 /* 3TX/SS or 3TX/DS 4.8 */
39#define AR9300_STBC_3TX_ARRAY_GAIN  10 /* 3TX/SS or 3TX/DS 4.8 */
40
41/* MCS RATE CODES - first and last */
42#define AR9300_MCS0_RATE_CODE   0x80
43#define AR9300_MCS23_RATE_CODE  0x97
44
45static inline void ar9300_init_rate_txpower_cck(struct ath_hal *ah,
46       const HAL_RATE_TABLE *rt, u_int8_t rates_array[], u_int8_t chainmask);
47static inline void ar9300_init_rate_txpower_ofdm(struct ath_hal* ah,
48       const HAL_RATE_TABLE *rt, u_int8_t rates_array[], int rt_offset,
49       u_int8_t chainmask);
50static inline void ar9300_init_rate_txpower_ht(struct ath_hal *ah,
51       const HAL_RATE_TABLE *rt, HAL_BOOL is40, u_int8_t rates_array[],
52       int rt_ss_offset, int rt_ds_offset,
53       int rt_ts_offset, u_int8_t chainmask);
54static inline void ar9300_init_rate_txpower_stbc(struct ath_hal *ah,
55       const HAL_RATE_TABLE *rt, HAL_BOOL is40,
56       int rt_ss_offset, int rt_ds_offset,
57       int rt_ts_offset, u_int8_t chainmask);
58#if 0
59static inline void ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah,
60       const HAL_RATE_TABLE *rt, HAL_BOOL is40,
61       int rt_ss_offset, int rt_ds_offset,
62       int rt_ts_offset, u_int8_t chainmask);
63#endif
64
65#define AR9300_11A_RT_OFDM_OFFSET    0
66HAL_RATE_TABLE ar9300_11a_table = {
67    8,  /* number of rates */
68    { 0 },
69    {
70/*                                                  short            ctrl */
71/*             valid                 rate_code Preamble    dot11Rate Rate */
72/*   6 Mb */ {  AH_TRUE, OFDM,    6000,     0x0b,    0x00, (0x80 | 12),   0 },
73/*   9 Mb */ {  AH_TRUE, OFDM,    9000,     0x0f,    0x00,          18,   0 },
74/*  12 Mb */ {  AH_TRUE, OFDM,   12000,     0x0a,    0x00, (0x80 | 24),   2 },
75/*  18 Mb */ {  AH_TRUE, OFDM,   18000,     0x0e,    0x00,          36,   2 },
76/*  24 Mb */ {  AH_TRUE, OFDM,   24000,     0x09,    0x00, (0x80 | 48),   4 },
77/*  36 Mb */ {  AH_TRUE, OFDM,   36000,     0x0d,    0x00,          72,   4 },
78/*  48 Mb */ {  AH_TRUE, OFDM,   48000,     0x08,    0x00,          96,   4 },
79/*  54 Mb */ {  AH_TRUE, OFDM,   54000,     0x0c,    0x00,         108,   4 },
80    },
81};
82
83HAL_RATE_TABLE ar9300_11a_half_table = {
84    8,  /* number of rates */
85    { 0 },
86    {
87/*                                                  short            ctrl */
88/*             valid                 rate_code Preamble    dot11Rate Rate */
89/*   6 Mb */ {  AH_TRUE, OFDM,    3000,     0x0b,    0x00, (0x80 |  6),   0 },
90/*   9 Mb */ {  AH_TRUE, OFDM,    4500,     0x0f,    0x00,           9,   0 },
91/*  12 Mb */ {  AH_TRUE, OFDM,    6000,     0x0a,    0x00, (0x80 | 12),   2 },
92/*  18 Mb */ {  AH_TRUE, OFDM,    9000,     0x0e,    0x00,          18,   2 },
93/*  24 Mb */ {  AH_TRUE, OFDM,   12000,     0x09,    0x00, (0x80 | 24),   4 },
94/*  36 Mb */ {  AH_TRUE, OFDM,   18000,     0x0d,    0x00,          36,   4 },
95/*  48 Mb */ {  AH_TRUE, OFDM,   24000,     0x08,    0x00,          48,   4 },
96/*  54 Mb */ {  AH_TRUE, OFDM,   27000,     0x0c,    0x00,          54,   4 },
97    },
98};
99
100HAL_RATE_TABLE ar9300_11a_quarter_table = {
101    8,  /* number of rates */
102    { 0 },
103    {
104/*                                                  short           ctrl */
105/*            valid                 rate_code Preamble    dot11Rate Rate */
106/*  6 Mb */ {  AH_TRUE, OFDM,    1500,     0x0b,    0x00, (0x80 |  3),   0 },
107/*  9 Mb */ {  AH_TRUE, OFDM,    2250,     0x0f,    0x00,          4 ,   0 },
108/* 12 Mb */ {  AH_TRUE, OFDM,    3000,     0x0a,    0x00, (0x80 |  6),   2 },
109/* 18 Mb */ {  AH_TRUE, OFDM,    4500,     0x0e,    0x00,           9,   2 },
110/* 24 Mb */ {  AH_TRUE, OFDM,    6000,     0x09,    0x00, (0x80 | 12),   4 },
111/* 36 Mb */ {  AH_TRUE, OFDM,    9000,     0x0d,    0x00,          18,   4 },
112/* 48 Mb */ {  AH_TRUE, OFDM,   12000,     0x08,    0x00,          24,   4 },
113/* 54 Mb */ {  AH_TRUE, OFDM,   13500,     0x0c,    0x00,          27,   4 },
114    },
115};
116
117HAL_RATE_TABLE ar9300_turbo_table = {
118    8,  /* number of rates */
119    { 0 },
120    {
121/*                                                 short            ctrl */
122/*             valid                rate_code Preamble    dot11Rate Rate */
123/*   6 Mb */ {  AH_TRUE, TURBO,   6000,    0x0b,    0x00, (0x80 | 12),   0 },
124/*   9 Mb */ {  AH_TRUE, TURBO,   9000,    0x0f,    0x00,          18,   0 },
125/*  12 Mb */ {  AH_TRUE, TURBO,  12000,    0x0a,    0x00, (0x80 | 24),   2 },
126/*  18 Mb */ {  AH_TRUE, TURBO,  18000,    0x0e,    0x00,          36,   2 },
127/*  24 Mb */ {  AH_TRUE, TURBO,  24000,    0x09,    0x00, (0x80 | 48),   4 },
128/*  36 Mb */ {  AH_TRUE, TURBO,  36000,    0x0d,    0x00,          72,   4 },
129/*  48 Mb */ {  AH_TRUE, TURBO,  48000,    0x08,    0x00,          96,   4 },
130/*  54 Mb */ {  AH_TRUE, TURBO,  54000,    0x0c,    0x00,         108,   4 },
131    },
132};
133
134HAL_RATE_TABLE ar9300_11b_table = {
135    4,  /* number of rates */
136    { 0 },
137    {
138/*                                                 short            ctrl */
139/*             valid                rate_code Preamble    dot11Rate Rate */
140/*   1 Mb */ {  AH_TRUE,  CCK,    1000,    0x1b,    0x00, (0x80 |  2),   0 },
141/*   2 Mb */ {  AH_TRUE,  CCK,    2000,    0x1a,    0x04, (0x80 |  4),   1 },
142/* 5.5 Mb */ {  AH_TRUE,  CCK,    5500,    0x19,    0x04, (0x80 | 11),   1 },
143/*  11 Mb */ {  AH_TRUE,  CCK,   11000,    0x18,    0x04, (0x80 | 22),   1 },
144    },
145};
146
147
148/* Venice TODO: round_up_rate() is broken when the rate table does not represent
149 * rates in increasing order  e.g.  5.5, 11, 6, 9.
150 * An average rate of 6 Mbps will currently map to 11 Mbps.
151 */
152#define AR9300_11G_RT_OFDM_OFFSET    4
153HAL_RATE_TABLE ar9300_11g_table = {
154    12,  /* number of rates */
155    { 0 },
156    {
157/*                                                 short            ctrl */
158/*             valid                rate_code Preamble    dot11Rate Rate */
159/*   1 Mb */ {  AH_TRUE, CCK,     1000,    0x1b,    0x00, (0x80 |  2),   0 },
160/*   2 Mb */ {  AH_TRUE, CCK,     2000,    0x1a,    0x04, (0x80 |  4),   1 },
161/* 5.5 Mb */ {  AH_TRUE, CCK,     5500,    0x19,    0x04, (0x80 | 11),   2 },
162/*  11 Mb */ {  AH_TRUE, CCK,    11000,    0x18,    0x04, (0x80 | 22),   3 },
163/* Hardware workaround - remove rates 6, 9 from rate ctrl */
164/*   6 Mb */ {  AH_TRUE, OFDM,    6000,    0x0b,    0x00,          12,   4 },
165/*   9 Mb */ {  AH_TRUE, OFDM,    9000,    0x0f,    0x00,          18,   4 },
166/*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00,          24,   6 },
167/*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   6 },
168/*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00,          48,   8 },
169/*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   8 },
170/*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   8 },
171/*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   8 },
172    },
173};
174
175#if 0
176HAL_RATE_TABLE ar9300_xr_table = {
177    13,        /* number of rates */
178    { 0 },
179    {
180/*                                                 short     ctrl */
181/*            valid          rate_code Preamble    dot11Rate Rate */
182/* 0.25 Mb */ {AH_TRUE,   XR,   250, 0x03,   0x00, (0x80 |  1),   0, 612, 612 },
183/*  0.5 Mb */ {AH_TRUE,   XR,   500, 0x07,   0x00, (0x80 |  1),   0, 457, 457 },
184/*    1 Mb */ {AH_TRUE,   XR,  1000, 0x02,   0x00, (0x80 |  2),   1, 228, 228 },
185/*    2 Mb */ {AH_TRUE,   XR,  2000, 0x06,   0x00, (0x80 |  4),   2, 160, 160 },
186/*    3 Mb */ {AH_TRUE,   XR,  3000, 0x01,   0x00, (0x80 |  6),   3, 140, 140 },
187/*    6 Mb */ {AH_TRUE, OFDM,  6000, 0x0b,   0x00, (0x80 | 12),   4, 60,  60  },
188/*    9 Mb */ {AH_TRUE, OFDM,  9000, 0x0f,   0x00,          18,   4, 60,  60  },
189/*   12 Mb */ {AH_TRUE, OFDM, 12000, 0x0a,   0x00, (0x80 | 24),   6, 48,  48  },
190/*   18 Mb */ {AH_TRUE, OFDM, 18000, 0x0e,   0x00,          36,   6, 48,  48  },
191/*   24 Mb */ {AH_TRUE, OFDM, 24000, 0x09,   0x00,          48,   8, 44,  44  },
192/*   36 Mb */ {AH_TRUE, OFDM, 36000, 0x0d,   0x00,          72,   8, 44,  44  },
193/*   48 Mb */ {AH_TRUE, OFDM, 48000, 0x08,   0x00,          96,   8, 44,  44  },
194/*   54 Mb */ {AH_TRUE, OFDM, 54000, 0x0c,   0x00,         108,   8, 44,  44  },
195    },
196};
197#endif
198
199#define AR9300_11NG_RT_OFDM_OFFSET       4
200#define AR9300_11NG_RT_HT_SS_OFFSET      12
201#define AR9300_11NG_RT_HT_DS_OFFSET      20
202#define AR9300_11NG_RT_HT_TS_OFFSET      28
203HAL_RATE_TABLE ar9300_11ng_table = {
204
205    36,  /* number of rates */
206    { 0 },
207    {
208/*                                                 short            ctrl */
209/*             valid                rate_code Preamble    dot11Rate Rate */
210/*   1 Mb */ {  AH_TRUE, CCK,     1000,    0x1b,    0x00, (0x80 |  2),   0 },
211/*   2 Mb */ {  AH_TRUE, CCK,     2000,    0x1a,    0x04, (0x80 |  4),   1 },
212/* 5.5 Mb */ {  AH_TRUE, CCK,     5500,    0x19,    0x04, (0x80 | 11),   2 },
213/*  11 Mb */ {  AH_TRUE, CCK,    11000,    0x18,    0x04, (0x80 | 22),   3 },
214/* Hardware workaround - remove rates 6, 9 from rate ctrl */
215/*   6 Mb */ {  AH_FALSE, OFDM,    6000,    0x0b,    0x00,          12,   4 },
216/*   9 Mb */ {  AH_FALSE, OFDM,    9000,    0x0f,    0x00,          18,   4 },
217/*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00,          24,   6 },
218/*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   6 },
219/*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00,          48,   8 },
220/*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   8 },
221/*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   8 },
222/*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   8 },
223/*--- HT SS rates ---*/
224/* 6.5 Mb */ {  AH_TRUE, HT,      6500,    0x80,    0x00,           0,   4 },
225/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x81,    0x00,           1,   6 },
226/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x82,    0x00,           2,   6 },
227/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x83,    0x00,           3,   8 },
228/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x84,    0x00,           4,   8 },
229/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x85,    0x00,           5,   8 },
230/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x86,    0x00,           6,   8 },
231/*  65 Mb */ {  AH_TRUE, HT,     65000,    0x87,    0x00,           7,   8 },
232/*--- HT DS rates ---*/
233/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x88,    0x00,           8,   4 },
234/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x89,    0x00,           9,   6 },
235/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x8a,    0x00,          10,   6 },
236/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x8b,    0x00,          11,   8 },
237/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x8c,    0x00,          12,   8 },
238/* 104 Mb */ {  AH_TRUE, HT,    104000,    0x8d,    0x00,          13,   8 },
239/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x8e,    0x00,          14,   8 },
240/* 130 Mb */ {  AH_TRUE, HT,    130000,    0x8f,    0x00,          15,   8 },
241/*--- HT TS rates ---*/
242/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x90,    0x00,          16,   4 },
243/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x91,    0x00,          17,   6 },
244/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x92,    0x00,          18,   6 },
245/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x93,    0x00,          19,   8 },
246/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x94,    0x00,          20,   8 },
247/* 156 Mb */ {  AH_TRUE, HT,    156000,    0x95,    0x00,          21,   8 },
248/*175.5Mb */ {  AH_TRUE, HT,    175500,    0x96,    0x00,          22,   8 },
249/* 195 Mb */ {  AH_TRUE, HT,    195000,    0x97,    0x00,          23,   8 },
250    },
251};
252
253#define AR9300_11NA_RT_OFDM_OFFSET       0
254#define AR9300_11NA_RT_HT_SS_OFFSET      8
255#define AR9300_11NA_RT_HT_DS_OFFSET      16
256#define AR9300_11NA_RT_HT_TS_OFFSET      24
257static HAL_RATE_TABLE ar9300_11na_table = {
258
259    32,  /* number of rates */
260    { 0 },
261    {
262/*                                                 short            ctrl */
263/*             valid                rate_code Preamble    dot11Rate Rate */
264/*   6 Mb */ {  AH_TRUE, OFDM,    6000,    0x0b,    0x00, (0x80 | 12),   0 },
265/*   9 Mb */ {  AH_TRUE, OFDM,    9000,    0x0f,    0x00,          18,   0 },
266/*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00, (0x80 | 24),   2 },
267/*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   2 },
268/*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00, (0x80 | 48),   4 },
269/*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   4 },
270/*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   4 },
271/*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   4 },
272/*--- HT SS rates ---*/
273/* 6.5 Mb */ {  AH_TRUE, HT,      6500,    0x80,    0x00,           0,   0 },
274/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x81,    0x00,           1,   2 },
275/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x82,    0x00,           2,   2 },
276/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x83,    0x00,           3,   4 },
277/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x84,    0x00,           4,   4 },
278/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x85,    0x00,           5,   4 },
279/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x86,    0x00,           6,   4 },
280/*  65 Mb */ {  AH_TRUE, HT,     65000,    0x87,    0x00,           7,   4 },
281/*--- HT DS rates ---*/
282/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x88,    0x00,           8,   0 },
283/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x89,    0x00,           9,   2 },
284/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x8a,    0x00,          10,   2 },
285/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x8b,    0x00,          11,   4 },
286/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x8c,    0x00,          12,   4 },
287/* 104 Mb */ {  AH_TRUE, HT,    104000,    0x8d,    0x00,          13,   4 },
288/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x8e,    0x00,          14,   4 },
289/* 130 Mb */ {  AH_TRUE, HT,    130000,    0x8f,    0x00,          15,   4 },
290/*--- HT TS rates ---*/
291/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x90,    0x00,          16,   0 },
292/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x91,    0x00,          17,   2 },
293/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x92,    0x00,          18,   2 },
294/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x93,    0x00,          19,   4 },
295/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x94,    0x00,          20,   4 },
296/* 156 Mb */ {  AH_TRUE, HT,    156000,    0x95,    0x00,          21,   4 },
297/*175.5Mb */ {  AH_TRUE, HT,    175500,    0x96,    0x00,          22,   4 },
298/* 195 Mb */ {  AH_TRUE, HT,    195000,    0x97,    0x00,          23,   4 },
299    },
300};
301
302#undef    OFDM
303#undef    CCK
304#undef    TURBO
305#undef    XR
306#undef    HT
307#undef    HT_HGI
308
309const HAL_RATE_TABLE *
310ar9300_get_rate_table(struct ath_hal *ah, u_int mode)
311{
312    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
313    HAL_CAPABILITIES *p_cap = &ahpriv->ah_caps;
314    HAL_RATE_TABLE *rt;
315
316    switch (mode) {
317    case HAL_MODE_11A:
318        rt = &ar9300_11a_table;
319        break;
320    case HAL_MODE_11A_HALF_RATE:
321        if (p_cap->halChanHalfRate) {
322            rt = &ar9300_11a_half_table;
323            break;
324        }
325        return AH_NULL;
326    case HAL_MODE_11A_QUARTER_RATE:
327        if (p_cap->halChanQuarterRate) {
328            rt = &ar9300_11a_quarter_table;
329            break;
330        }
331        return AH_NULL;
332    case HAL_MODE_11B:
333        rt = &ar9300_11b_table;
334        break;
335    case HAL_MODE_11G:
336        rt =  &ar9300_11g_table;
337        break;
338    case HAL_MODE_TURBO:
339    case HAL_MODE_108G:
340        rt =  &ar9300_turbo_table;
341        break;
342#if 0
343    case HAL_MODE_XR:
344        rt = &ar9300_xr_table;
345        break;
346#endif
347    case HAL_MODE_11NG_HT20:
348    case HAL_MODE_11NG_HT40PLUS:
349    case HAL_MODE_11NG_HT40MINUS:
350        rt = &ar9300_11ng_table;
351        break;
352    case HAL_MODE_11NA_HT20:
353    case HAL_MODE_11NA_HT40PLUS:
354    case HAL_MODE_11NA_HT40MINUS:
355        rt = &ar9300_11na_table;
356        break;
357    default:
358        HALDEBUG(ah, HAL_DEBUG_CHANNEL,
359            "%s: invalid mode 0x%x\n", __func__, mode);
360        return AH_NULL;
361    }
362    ath_hal_setupratetable(ah, rt);
363    return rt;
364}
365
366static HAL_BOOL
367ar9300_invalid_stbc_cfg(int tx_chains, u_int8_t rate_code)
368{
369    switch (tx_chains) {
370    case 0: /* Single Chain */
371        return AH_TRUE;
372
373    case 1: /* 2 Chains */
374        if ((rate_code < 0x80) || (rate_code > 0x87)) {
375            return AH_TRUE;
376        } else {
377            return AH_FALSE;
378        }
379
380    case 2: /* 3 Chains */
381        if ((rate_code < 0x80) || (rate_code > 0x87)) {
382            return AH_TRUE;
383        } else {
384            return AH_FALSE;
385        }
386
387    default:
388        HALASSERT(0);
389        break;
390    }
391
392    return AH_TRUE;
393}
394
395int16_t
396ar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index,
397                     u_int8_t chainmask, u_int8_t xmit_mode)
398{
399    struct ath_hal_9300 *ahp = AH9300(ah);
400    int num_chains = ar9300_get_ntxchains(chainmask);
401
402    switch (xmit_mode) {
403    case AR9300_DEF_MODE:
404        return ahp->txpower[rate_index][num_chains-1];
405
406
407    case AR9300_STBC_MODE:
408        return ahp->txpower_stbc[rate_index][num_chains-1];
409
410    default:
411        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
412             __func__, xmit_mode);
413        HALASSERT(0);
414        break;
415    }
416
417    return ahp->txpower[rate_index][num_chains-1];
418}
419
420extern void
421ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah,
422                      u_int8_t power_per_rate[])
423
424{
425    struct ath_hal_9300 *ahp = AH9300(ah);
426    int16_t twice_array_gain, cdd_power = 0;
427    int i;
428
429    /*
430     *  Adjust the upper limit for CDD factoring in the array gain .
431     *  The array gain is the same as TxBF, hence reuse the same defines.
432     */
433    switch (ahp->ah_tx_chainmask) {
434
435    case OSPREY_1_CHAINMASK:
436        cdd_power = ahp->upper_limit[0];
437        break;
438
439    case OSPREY_2LOHI_CHAINMASK:
440    case OSPREY_2LOMID_CHAINMASK:
441        twice_array_gain =
442           (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
443           -(AR9300_TXBF_2TX_ARRAY_GAIN) :
444           ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
445           (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
446        cdd_power = ahp->upper_limit[1] + twice_array_gain;
447
448        HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: 2 chain; cdd_power=%d", __func__, cdd_power);
449        /* Adjust OFDM legacy rates as well */
450        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
451            if (power_per_rate[i] > cdd_power) {
452                power_per_rate[i] = cdd_power;
453            }
454        }
455
456        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 20*/
457        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) {
458            if (power_per_rate[i] > cdd_power) {
459                power_per_rate[i] = cdd_power;
460            }
461        }
462
463        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 40*/
464        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) {
465            if (power_per_rate[i] > cdd_power) {
466                power_per_rate[i] = cdd_power;
467            }
468        }
469        break;
470
471    case OSPREY_3_CHAINMASK:
472        twice_array_gain =
473            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
474            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
475            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
476            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
477        cdd_power = ahp->upper_limit[2] + twice_array_gain;
478        HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: 3 chain; cdd_power=%d", __func__, cdd_power);
479        /* Adjust OFDM legacy rates as well */
480        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
481            if (power_per_rate[i] > cdd_power) {
482                power_per_rate[i] = cdd_power;
483            }
484        }
485        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */
486        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) {
487            if (power_per_rate[i] > cdd_power) {
488                power_per_rate[i] = cdd_power;
489            }
490        }
491
492        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */
493        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) {
494            if (power_per_rate[i] > cdd_power) {
495                power_per_rate[i] = cdd_power;
496            }
497        }
498
499        break;
500
501    default:
502        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
503                 __func__, ahp->ah_tx_chainmask);
504        break;
505    }
506
507    return;
508}
509
510extern void
511ar9300_init_rate_txpower(struct ath_hal *ah, u_int mode,
512                      const struct ieee80211_channel *chan,
513                      u_int8_t power_per_rate[], u_int8_t chainmask)
514{
515    const HAL_RATE_TABLE *rt;
516    HAL_BOOL is40 = IEEE80211_IS_CHAN_HT40(chan);
517
518    rt = ar9300_get_rate_table(ah, mode);
519    HALASSERT(rt != NULL);
520
521    switch (mode) {
522    case HAL_MODE_11A:
523        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
524                              AR9300_11A_RT_OFDM_OFFSET, chainmask);
525        break;
526    case HAL_MODE_11NA_HT20:
527    case HAL_MODE_11NA_HT40PLUS:
528    case HAL_MODE_11NA_HT40MINUS:
529        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
530                              AR9300_11NA_RT_OFDM_OFFSET, chainmask);
531        ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
532                            AR9300_11NA_RT_HT_SS_OFFSET,
533                            AR9300_11NA_RT_HT_DS_OFFSET,
534                            AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
535        ar9300_init_rate_txpower_stbc(ah, rt, is40,
536                            AR9300_11NA_RT_HT_SS_OFFSET,
537                            AR9300_11NA_RT_HT_DS_OFFSET,
538                            AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
539#if 0
540        /* For FCC the array gain has to be factored for CDD mode */
541        if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
542            ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
543                            AR9300_11NA_RT_HT_SS_OFFSET,
544                            AR9300_11NA_RT_HT_DS_OFFSET,
545                            AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
546        }
547#endif
548        break;
549    case HAL_MODE_11G:
550        ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
551        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
552                              AR9300_11G_RT_OFDM_OFFSET, chainmask);
553        break;
554    case HAL_MODE_11B:
555        ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
556        break;
557    case HAL_MODE_11NG_HT20:
558    case HAL_MODE_11NG_HT40PLUS:
559    case HAL_MODE_11NG_HT40MINUS:
560        ar9300_init_rate_txpower_cck(ah, rt, power_per_rate,  chainmask);
561        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
562                              AR9300_11NG_RT_OFDM_OFFSET, chainmask);
563        ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
564                            AR9300_11NG_RT_HT_SS_OFFSET,
565                            AR9300_11NG_RT_HT_DS_OFFSET,
566                            AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
567        ar9300_init_rate_txpower_stbc(ah, rt, is40,
568                            AR9300_11NG_RT_HT_SS_OFFSET,
569                            AR9300_11NG_RT_HT_DS_OFFSET,
570                            AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
571#if 0
572        /* For FCC the array gain needs to be factored for CDD mode */
573        if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
574            ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
575                            AR9300_11NG_RT_HT_SS_OFFSET,
576                            AR9300_11NG_RT_HT_DS_OFFSET,
577                            AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
578        }
579#endif
580        break;
581    default:
582        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
583             __func__, mode);
584        HALASSERT(0);
585        break;
586    }
587
588}
589
590static inline void
591ar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
592                         u_int8_t rates_array[], u_int8_t chainmask)
593{
594    struct ath_hal_9300 *ahp = AH9300(ah);
595    /*
596     * Pick the lower of the long-preamble txpower, and short-preamble tx power.
597     * Unfortunately, the rate table doesn't have separate entries for these!.
598     */
599    switch (chainmask) {
600    case OSPREY_1_CHAINMASK:
601        ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
602        ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
603        ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
604                                  rates_array[ALL_TARGET_LEGACY_5S]);
605        ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
606                                      rates_array[ALL_TARGET_LEGACY_11S]);
607        break;
608    case OSPREY_2LOHI_CHAINMASK:
609    case OSPREY_2LOMID_CHAINMASK:
610        ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
611        ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
612        ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
613                                  rates_array[ALL_TARGET_LEGACY_5S]);
614        ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
615                                  rates_array[ALL_TARGET_LEGACY_11S]);
616        break;
617    case OSPREY_3_CHAINMASK:
618        ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
619        ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
620        ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
621                                   rates_array[ALL_TARGET_LEGACY_5S]);
622        ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
623                                       rates_array[ALL_TARGET_LEGACY_11S]);
624        break;
625    default:
626        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
627                 __func__, chainmask);
628        break;
629    }
630}
631
632static inline void
633ar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
634                          u_int8_t rates_array[], int rt_offset,
635                          u_int8_t chainmask)
636{
637    struct ath_hal_9300 *ahp = AH9300(ah);
638    int16_t twice_array_gain, cdd_power = 0;
639    int i, j;
640    u_int8_t ofdm_rt_2_pwr_idx[8] =
641    {
642        ALL_TARGET_LEGACY_6_24,
643        ALL_TARGET_LEGACY_6_24,
644        ALL_TARGET_LEGACY_6_24,
645        ALL_TARGET_LEGACY_6_24,
646        ALL_TARGET_LEGACY_6_24,
647        ALL_TARGET_LEGACY_36,
648        ALL_TARGET_LEGACY_48,
649        ALL_TARGET_LEGACY_54,
650    };
651
652    /*
653     *  For FCC adjust the upper limit for CDD factoring in the array gain.
654     *  The array gain is the same as TxBF, hence reuse the same defines.
655     */
656    for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) {
657
658        /* Get the correct OFDM rate to Power table Index */
659        j = ofdm_rt_2_pwr_idx[i- rt_offset];
660
661        switch (chainmask) {
662        case OSPREY_1_CHAINMASK:
663            ahp->txpower[i][0] = rates_array[j];
664            break;
665        case OSPREY_2LOHI_CHAINMASK:
666        case OSPREY_2LOMID_CHAINMASK:
667            ahp->txpower[i][1] = rates_array[j];
668            if (is_reg_dmn_fcc(ahp->reg_dmn)){
669                twice_array_gain = (ahp->twice_antenna_gain >=
670                ahp->twice_antenna_reduction)?
671                -(AR9300_TXBF_2TX_ARRAY_GAIN) :
672                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
673               (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
674                cdd_power = ahp->upper_limit[1] + twice_array_gain;
675                if (ahp->txpower[i][1] > cdd_power){
676                    ahp->txpower[i][1] = cdd_power;
677                }
678            }
679            break;
680        case OSPREY_3_CHAINMASK:
681            ahp->txpower[i][2] = rates_array[j];
682            if (is_reg_dmn_fcc(ahp->reg_dmn)) {
683                twice_array_gain =
684                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
685                -(AR9300_TXBF_3TX_ARRAY_GAIN):
686                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
687                (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
688                cdd_power = ahp->upper_limit[2] + twice_array_gain;
689                if (ahp->txpower[i][2] > cdd_power){
690                    ahp->txpower[i][2] = cdd_power;
691                }
692            }
693            break;
694        default:
695            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
696                     __func__, chainmask);
697            break;
698        }
699    }
700}
701
702static  u_int8_t mcs_rate_2_pwr_idx_ht20[24] =
703    {
704        ALL_TARGET_HT20_0_8_16,
705        ALL_TARGET_HT20_1_3_9_11_17_19,
706        ALL_TARGET_HT20_1_3_9_11_17_19,
707        ALL_TARGET_HT20_1_3_9_11_17_19,
708        ALL_TARGET_HT20_4,
709        ALL_TARGET_HT20_5,
710        ALL_TARGET_HT20_6,
711        ALL_TARGET_HT20_7,
712        ALL_TARGET_HT20_0_8_16,
713        ALL_TARGET_HT20_1_3_9_11_17_19,
714        ALL_TARGET_HT20_1_3_9_11_17_19,
715        ALL_TARGET_HT20_1_3_9_11_17_19,
716        ALL_TARGET_HT20_12,
717        ALL_TARGET_HT20_13,
718        ALL_TARGET_HT20_14,
719        ALL_TARGET_HT20_15,
720        ALL_TARGET_HT20_0_8_16,
721        ALL_TARGET_HT20_1_3_9_11_17_19,
722        ALL_TARGET_HT20_1_3_9_11_17_19,
723        ALL_TARGET_HT20_1_3_9_11_17_19,
724        ALL_TARGET_HT20_20,
725        ALL_TARGET_HT20_21,
726        ALL_TARGET_HT20_22,
727        ALL_TARGET_HT20_23
728    };
729
730static   u_int8_t mcs_rate_2_pwr_idx_ht40[24] =
731    {
732        ALL_TARGET_HT40_0_8_16,
733        ALL_TARGET_HT40_1_3_9_11_17_19,
734        ALL_TARGET_HT40_1_3_9_11_17_19,
735        ALL_TARGET_HT40_1_3_9_11_17_19,
736        ALL_TARGET_HT40_4,
737        ALL_TARGET_HT40_5,
738        ALL_TARGET_HT40_6,
739        ALL_TARGET_HT40_7,
740        ALL_TARGET_HT40_0_8_16,
741        ALL_TARGET_HT40_1_3_9_11_17_19,
742        ALL_TARGET_HT40_1_3_9_11_17_19,
743        ALL_TARGET_HT40_1_3_9_11_17_19,
744        ALL_TARGET_HT40_12,
745        ALL_TARGET_HT40_13,
746        ALL_TARGET_HT40_14,
747        ALL_TARGET_HT40_15,
748        ALL_TARGET_HT40_0_8_16,
749        ALL_TARGET_HT40_1_3_9_11_17_19,
750        ALL_TARGET_HT40_1_3_9_11_17_19,
751        ALL_TARGET_HT40_1_3_9_11_17_19,
752        ALL_TARGET_HT40_20,
753        ALL_TARGET_HT40_21,
754        ALL_TARGET_HT40_22,
755        ALL_TARGET_HT40_23,
756    };
757
758static inline void
759ar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
760                        HAL_BOOL is40,
761                        u_int8_t rates_array[],
762                        int rt_ss_offset, int rt_ds_offset,
763                        int rt_ts_offset, u_int8_t chainmask)
764{
765
766    struct ath_hal_9300 *ahp = AH9300(ah);
767    int i, j;
768    u_int8_t mcs_index = 0;
769
770
771    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
772        /* Get the correct MCS rate to Power table Index */
773        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
774                          mcs_rate_2_pwr_idx_ht20[mcs_index];
775        switch (chainmask) {
776        case OSPREY_1_CHAINMASK:
777            ahp->txpower[i][0] = rates_array[j];
778            break;
779        case OSPREY_2LOHI_CHAINMASK:
780        case OSPREY_2LOMID_CHAINMASK:
781            ahp->txpower[i][1] = rates_array[j];
782            break;
783        case OSPREY_3_CHAINMASK:
784            ahp->txpower[i][2] = rates_array[j];
785            break;
786        default:
787            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
788                     __func__, chainmask);
789            break;
790        }
791        mcs_index++;
792    }
793
794    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
795        /* Get the correct MCS rate to Power table Index */
796        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
797                                       mcs_rate_2_pwr_idx_ht20[mcs_index];
798        switch (chainmask) {
799        case OSPREY_1_CHAINMASK:
800            ahp->txpower[i][0] = rates_array[j];
801            break;
802        case OSPREY_2LOHI_CHAINMASK:
803        case OSPREY_2LOMID_CHAINMASK:
804            ahp->txpower[i][1] = rates_array[j];
805            break;
806        case OSPREY_3_CHAINMASK:
807            ahp->txpower[i][2] = rates_array[j];
808            break;
809        default:
810            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
811                         __func__, chainmask);
812            break;
813        }
814        mcs_index++;
815    }
816
817    for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
818        /* Get the correct MCS rate to Power table Index */
819        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
820                                  mcs_rate_2_pwr_idx_ht20[mcs_index];
821        switch (chainmask) {
822        case OSPREY_1_CHAINMASK:
823            ahp->txpower[i][0] = rates_array[j];
824            break;
825        case OSPREY_2LOHI_CHAINMASK:
826        case OSPREY_2LOMID_CHAINMASK:
827            ahp->txpower[i][1] = rates_array[j];
828            break;
829        case OSPREY_3_CHAINMASK:
830            ahp->txpower[i][2] = rates_array[j];
831            break;
832        default:
833            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
834                 __func__, chainmask);
835            break;
836        }
837        mcs_index++;
838    }
839}
840
841static inline void
842ar9300_init_rate_txpower_stbc(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
843                        HAL_BOOL is40,
844                        int rt_ss_offset, int rt_ds_offset,
845                        int rt_ts_offset, u_int8_t chainmask)
846{
847
848    struct ath_hal_9300 *ahp = AH9300(ah);
849    int i;
850    int16_t twice_array_gain, stbc_power = 0;
851    u_int8_t mcs_index = 0;
852
853    /* Upper Limit with STBC */
854    switch (chainmask) {
855    case OSPREY_1_CHAINMASK:
856        stbc_power = ahp->upper_limit[0];
857        break;
858    case OSPREY_2LOHI_CHAINMASK:
859    case OSPREY_2LOMID_CHAINMASK:
860        stbc_power = ahp->upper_limit[1];
861        break;
862    case OSPREY_3_CHAINMASK:
863        stbc_power = ahp->upper_limit[2];
864        /* Ony FCC requires that we back off with 3 transmit chains */
865        if (is_reg_dmn_fcc(ahp->reg_dmn)) {
866            twice_array_gain =
867                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
868                -(AR9300_STBC_3TX_ARRAY_GAIN) :
869                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
870                (ahp->twice_antenna_gain + AR9300_STBC_3TX_ARRAY_GAIN)), 0));
871            stbc_power = ahp->upper_limit[2] + twice_array_gain;
872        }
873        break;
874
875    default:
876        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
877                 __func__, chainmask);
878        break;
879    }
880
881
882    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
883        switch (chainmask) {
884        case OSPREY_1_CHAINMASK:
885            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
886            break;
887        case OSPREY_2LOHI_CHAINMASK:
888        case OSPREY_2LOMID_CHAINMASK:
889            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
890            break;
891        case OSPREY_3_CHAINMASK:
892            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
893            /* 3 TX/1 stream  STBC gain adjustment */
894            if (ahp->txpower_stbc[i][2] > stbc_power){
895                ahp->txpower_stbc[i][2] = stbc_power;
896            }
897            break;
898        default:
899            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
900                     __func__, chainmask);
901            break;
902        }
903        mcs_index++;
904    }
905
906    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
907        switch (chainmask) {
908        case OSPREY_1_CHAINMASK:
909            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
910            break;
911        case OSPREY_2LOHI_CHAINMASK:
912        case OSPREY_2LOMID_CHAINMASK:
913            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
914            break;
915        case OSPREY_3_CHAINMASK:
916            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
917            /* 3 TX/2 stream  STBC gain adjustment */
918            if (ahp->txpower_stbc[i][2] > stbc_power){
919                ahp->txpower_stbc[i][2] = stbc_power;
920	    }
921            break;
922        default:
923            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
924                     __func__, chainmask);
925            break;
926        }
927        mcs_index++;
928    }
929
930    for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
931        switch (chainmask) {
932        case OSPREY_1_CHAINMASK:
933            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
934            break;
935        case OSPREY_2LOHI_CHAINMASK:
936        case OSPREY_2LOMID_CHAINMASK:
937            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
938            break;
939        case OSPREY_3_CHAINMASK:
940            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
941            break;
942        default:
943            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
944                     __func__, chainmask);
945            break;
946        }
947        mcs_index++;
948    }
949
950    return;
951}
952
953/*
954 * To see why this is disabled, look at ar9300_eeprom.c for FCC/OET 13TR1003.
955 */
956#if 0
957static inline void
958ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
959                        HAL_BOOL is40,
960                        int rt_ss_offset, int rt_ds_offset,
961                        int rt_ts_offset, u_int8_t chainmask)
962{
963
964    struct ath_hal_9300 *ahp = AH9300(ah);
965    int i;
966    int16_t twice_array_gain, cdd_power = 0;
967    u_int8_t mcs_index = 0;
968
969    /*
970     *  Adjust the upper limit for CDD factoring in the array gain .
971     *  The array gain is the same as TxBF, hence reuse the same defines.
972     */
973    switch (chainmask) {
974    case OSPREY_1_CHAINMASK:
975        cdd_power = ahp->upper_limit[0];
976        break;
977
978    case OSPREY_2LOHI_CHAINMASK:
979    case OSPREY_2LOMID_CHAINMASK:
980        twice_array_gain =
981            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
982            -(AR9300_TXBF_2TX_ARRAY_GAIN) :
983            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
984            (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
985        cdd_power = ahp->upper_limit[1] + twice_array_gain;
986        break;
987
988    case OSPREY_3_CHAINMASK:
989        twice_array_gain =
990            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
991            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
992            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
993            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
994        cdd_power = ahp->upper_limit[2] + twice_array_gain;
995        break;
996
997    default:
998        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
999                     __func__, chainmask);
1000        break;
1001    }
1002
1003
1004    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
1005        switch (chainmask) {
1006        case OSPREY_1_CHAINMASK:
1007            break;
1008
1009        case OSPREY_2LOHI_CHAINMASK:
1010        case OSPREY_2LOMID_CHAINMASK:
1011            /* 2 TX/1 stream  CDD gain adjustment */
1012            if (ahp->txpower[i][1] > cdd_power){
1013                ahp->txpower[i][1] = cdd_power;
1014            }
1015            break;
1016        case OSPREY_3_CHAINMASK:
1017            /* 3 TX/1 stream  CDD gain adjustment */
1018            if (ahp->txpower[i][2] > cdd_power){
1019                ahp->txpower[i][2] = cdd_power;
1020            }
1021            break;
1022        default:
1023            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
1024                     __func__, chainmask);
1025            break;
1026        }
1027        mcs_index++;
1028    }
1029
1030    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
1031        switch (chainmask) {
1032        case OSPREY_1_CHAINMASK:
1033        case OSPREY_2LOHI_CHAINMASK:
1034        case OSPREY_2LOMID_CHAINMASK:
1035            break;
1036        case OSPREY_3_CHAINMASK:
1037        /* 3 TX/2 stream  TxBF gain adjustment */
1038            if (ahp->txpower[i][2] > cdd_power){
1039                ahp->txpower[i][2] = cdd_power;
1040            }
1041            break;
1042        default:
1043            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
1044                 __func__, chainmask);
1045            break;
1046        }
1047        mcs_index++;
1048    }
1049
1050    return;
1051
1052}
1053#endif
1054
1055void ar9300_disp_tpc_tables(struct ath_hal *ah)
1056{
1057    struct ath_hal_9300 *ahp = AH9300(ah);
1058    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
1059    u_int mode = ath_hal_get_curmode(ah, chan);
1060    const HAL_RATE_TABLE *rt;
1061    int i, j;
1062
1063    /* Check whether TPC is enabled */
1064    if (!ah->ah_config.ath_hal_desc_tpc) {
1065        ath_hal_printf(ah, "\n TPC Register method in use\n");
1066        return;
1067    }
1068
1069    rt = ar9300_get_rate_table(ah, mode);
1070    HALASSERT(rt != NULL);
1071
1072    ath_hal_printf(ah, "\n===TARGET POWER TABLE===\n");
1073    for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1074        for (i = 0; i < rt->rateCount; i++) {
1075            int16_t txpower[AR9300_MAX_CHAINS];
1076            txpower[j] = ahp->txpower[i][j];
1077            ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
1078                       "Power (%d Chain) [%2d.%1d dBm]\n",
1079                       i, rt->info[i].rateCode, rt->info[i].rateKbps,
1080                       j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1081        }
1082    }
1083    ath_hal_printf(ah, "\n");
1084
1085    ath_hal_printf(ah, "\n\n===TARGET POWER TABLE with STBC===\n");
1086    for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1087        for (i = 0; i < rt->rateCount; i++) {
1088            int16_t txpower[AR9300_MAX_CHAINS];
1089            txpower[j] = ahp->txpower_stbc[i][j];
1090
1091            /* Do not display invalid configurations */
1092            if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1093                (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1094                ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1095                continue;
1096            }
1097
1098            ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
1099                       "Power (%d Chain) [%2d.%1d dBm]\n",
1100                       i, rt->info[i].rateCode , rt->info[i].rateKbps,
1101                       j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1102        }
1103    }
1104    ath_hal_printf(ah, "\n");
1105}
1106
1107/*
1108 * The followings are customer specific APIs for querying power limit.
1109 * Power limit is based on regulatory domain, chipset, and transmission rate.
1110 * Here we only consider EEPROM values, no array gain/CTL considered here.
1111 */
1112
1113struct rate_power_tbl {
1114    u_int8_t    rateIdx;        /* rate index in the rate table */
1115    u_int32_t   rateKbps;       /* transfer rate in kbs */
1116    u_int8_t    rateCode;      /* rate for h/w descriptors */
1117    u_int8_t    txbf:   1,      /* txbf eligible */
1118                stbc:   1,      /* stbc eligible */
1119                chain1: 1,      /* one-chain eligible */
1120                chain2: 1,      /* two-chain eligible */
1121                chain3: 1;      /* three-chain eligible */
1122    int16_t     txpower[AR9300_MAX_CHAINS];     /* txpower for different chainmasks */
1123    int16_t     txpower_stbc[AR9300_MAX_CHAINS];
1124};
1125
1126u_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah)
1127{
1128    struct ath_hal_9300 *ahp = AH9300(ah);
1129    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
1130    u_int mode = ath_hal_get_curmode(ah, chan);
1131    const HAL_RATE_TABLE *rt;
1132    u_int8_t *data;
1133    struct rate_power_tbl *table;
1134    int i, j;
1135
1136    /* Check whether TPC is enabled */
1137    if (! ah->ah_config.ath_hal_desc_tpc) {
1138        ath_hal_printf(ah, "\n TPC Register method in use\n");
1139        return NULL;
1140    }
1141
1142    rt = (const HAL_RATE_TABLE *)ar9300_get_rate_table(ah, mode);
1143    HALASSERT(rt != NULL);
1144
1145    data = (u_int8_t *)ath_hal_malloc(
1146                       1 + rt->rateCount * sizeof(struct rate_power_tbl));
1147    if (data == NULL)
1148        return NULL;
1149
1150    OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl));
1151    /* store the rate count at the beginning */
1152    *data = rt->rateCount;
1153    table = (struct rate_power_tbl *)&data[1];
1154
1155    for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1156        for (i = 0; i < rt->rateCount; i++) {
1157            table[i].rateIdx = i;
1158            table[i].rateCode = rt->info[i].rateCode;
1159            table[i].rateKbps = rt->info[i].rateKbps;
1160            switch (j) {
1161            case 0:
1162                table[i].chain1 = rt->info[i].rateCode <= 0x87 ? 1 : 0;
1163                break;
1164            case 1:
1165                table[i].chain2 = rt->info[i].rateCode <= 0x8f ? 1 : 0;
1166                break;
1167            case 2:
1168                table[i].chain3 = 1;
1169                break;
1170            default:
1171                break;
1172            }
1173            if ((j == 0 && table[i].chain1) ||
1174                (j == 1 && table[i].chain2) ||
1175                (j == 2 && table[i].chain3))
1176                table[i].txpower[j] = ahp->txpower[i][j];
1177        }
1178    }
1179
1180    for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1181        for (i = 0; i < rt->rateCount; i++) {
1182            /* Do not display invalid configurations */
1183            if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1184                (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1185                ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1186                continue;
1187            }
1188
1189            table[i].stbc = 1;
1190            table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j];
1191        }
1192    }
1193
1194    return data;
1195    /* the caller is responsible to free data */
1196}
1197
1198HAL_STATUS
1199ath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq,
1200                                        int8_t *max_rate_power, int8_t *min_rate_power)
1201{
1202    /*
1203     * Used for AR9300 series chip only
1204     */
1205    if (ah->ah_magic == AR9300_MAGIC) {
1206        u_int8_t target_rate_power_limit_val_t2[ar9300_rate_size];
1207        int i;
1208
1209        *max_rate_power = 0;
1210        *min_rate_power = AR9300_MAX_RATE_POWER;
1211
1212        ar9300_set_target_power_from_eeprom(ah, freq, target_rate_power_limit_val_t2);
1213
1214        for (i=0; i<ar9300_rate_size; i++) {
1215            if (target_rate_power_limit_val_t2[i] > *max_rate_power)
1216                *max_rate_power = target_rate_power_limit_val_t2[i];
1217            if (target_rate_power_limit_val_t2[i] < *min_rate_power)
1218                *min_rate_power = target_rate_power_limit_val_t2[i];
1219        }
1220    } else {
1221        *max_rate_power = 0;
1222        *min_rate_power = 0;
1223    }
1224
1225    return HAL_OK;
1226}
1227