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