xref: /freebsd/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_phy.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
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 
45 static 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);
47 static 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);
50 static 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);
54 static 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 static inline void ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah,
59        const HAL_RATE_TABLE *rt, HAL_BOOL is40,
60        int rt_ss_offset, int rt_ds_offset,
61        int rt_ts_offset, u_int8_t chainmask);
62 
63 #define AR9300_11A_RT_OFDM_OFFSET    0
64 HAL_RATE_TABLE ar9300_11a_table = {
65     8,  /* number of rates */
66     { 0 },
67     {
68 /*                                                  short            ctrl */
69 /*             valid                 rate_code Preamble    dot11Rate Rate */
70 /*   6 Mb */ {  AH_TRUE, OFDM,    6000,     0x0b,    0x00, (0x80 | 12),   0 },
71 /*   9 Mb */ {  AH_TRUE, OFDM,    9000,     0x0f,    0x00,          18,   0 },
72 /*  12 Mb */ {  AH_TRUE, OFDM,   12000,     0x0a,    0x00, (0x80 | 24),   2 },
73 /*  18 Mb */ {  AH_TRUE, OFDM,   18000,     0x0e,    0x00,          36,   2 },
74 /*  24 Mb */ {  AH_TRUE, OFDM,   24000,     0x09,    0x00, (0x80 | 48),   4 },
75 /*  36 Mb */ {  AH_TRUE, OFDM,   36000,     0x0d,    0x00,          72,   4 },
76 /*  48 Mb */ {  AH_TRUE, OFDM,   48000,     0x08,    0x00,          96,   4 },
77 /*  54 Mb */ {  AH_TRUE, OFDM,   54000,     0x0c,    0x00,         108,   4 },
78     },
79 };
80 
81 HAL_RATE_TABLE ar9300_11a_half_table = {
82     8,  /* number of rates */
83     { 0 },
84     {
85 /*                                                  short            ctrl */
86 /*             valid                 rate_code Preamble    dot11Rate Rate */
87 /*   6 Mb */ {  AH_TRUE, OFDM,    3000,     0x0b,    0x00, (0x80 |  6),   0 },
88 /*   9 Mb */ {  AH_TRUE, OFDM,    4500,     0x0f,    0x00,           9,   0 },
89 /*  12 Mb */ {  AH_TRUE, OFDM,    6000,     0x0a,    0x00, (0x80 | 12),   2 },
90 /*  18 Mb */ {  AH_TRUE, OFDM,    9000,     0x0e,    0x00,          18,   2 },
91 /*  24 Mb */ {  AH_TRUE, OFDM,   12000,     0x09,    0x00, (0x80 | 24),   4 },
92 /*  36 Mb */ {  AH_TRUE, OFDM,   18000,     0x0d,    0x00,          36,   4 },
93 /*  48 Mb */ {  AH_TRUE, OFDM,   24000,     0x08,    0x00,          48,   4 },
94 /*  54 Mb */ {  AH_TRUE, OFDM,   27000,     0x0c,    0x00,          54,   4 },
95     },
96 };
97 
98 HAL_RATE_TABLE ar9300_11a_quarter_table = {
99     8,  /* number of rates */
100     { 0 },
101     {
102 /*                                                  short           ctrl */
103 /*            valid                 rate_code Preamble    dot11Rate Rate */
104 /*  6 Mb */ {  AH_TRUE, OFDM,    1500,     0x0b,    0x00, (0x80 |  3),   0 },
105 /*  9 Mb */ {  AH_TRUE, OFDM,    2250,     0x0f,    0x00,          4 ,   0 },
106 /* 12 Mb */ {  AH_TRUE, OFDM,    3000,     0x0a,    0x00, (0x80 |  6),   2 },
107 /* 18 Mb */ {  AH_TRUE, OFDM,    4500,     0x0e,    0x00,           9,   2 },
108 /* 24 Mb */ {  AH_TRUE, OFDM,    6000,     0x09,    0x00, (0x80 | 12),   4 },
109 /* 36 Mb */ {  AH_TRUE, OFDM,    9000,     0x0d,    0x00,          18,   4 },
110 /* 48 Mb */ {  AH_TRUE, OFDM,   12000,     0x08,    0x00,          24,   4 },
111 /* 54 Mb */ {  AH_TRUE, OFDM,   13500,     0x0c,    0x00,          27,   4 },
112     },
113 };
114 
115 HAL_RATE_TABLE ar9300_turbo_table = {
116     8,  /* number of rates */
117     { 0 },
118     {
119 /*                                                 short            ctrl */
120 /*             valid                rate_code Preamble    dot11Rate Rate */
121 /*   6 Mb */ {  AH_TRUE, TURBO,   6000,    0x0b,    0x00, (0x80 | 12),   0 },
122 /*   9 Mb */ {  AH_TRUE, TURBO,   9000,    0x0f,    0x00,          18,   0 },
123 /*  12 Mb */ {  AH_TRUE, TURBO,  12000,    0x0a,    0x00, (0x80 | 24),   2 },
124 /*  18 Mb */ {  AH_TRUE, TURBO,  18000,    0x0e,    0x00,          36,   2 },
125 /*  24 Mb */ {  AH_TRUE, TURBO,  24000,    0x09,    0x00, (0x80 | 48),   4 },
126 /*  36 Mb */ {  AH_TRUE, TURBO,  36000,    0x0d,    0x00,          72,   4 },
127 /*  48 Mb */ {  AH_TRUE, TURBO,  48000,    0x08,    0x00,          96,   4 },
128 /*  54 Mb */ {  AH_TRUE, TURBO,  54000,    0x0c,    0x00,         108,   4 },
129     },
130 };
131 
132 HAL_RATE_TABLE ar9300_11b_table = {
133     4,  /* number of rates */
134     { 0 },
135     {
136 /*                                                 short            ctrl */
137 /*             valid                rate_code Preamble    dot11Rate Rate */
138 /*   1 Mb */ {  AH_TRUE,  CCK,    1000,    0x1b,    0x00, (0x80 |  2),   0 },
139 /*   2 Mb */ {  AH_TRUE,  CCK,    2000,    0x1a,    0x04, (0x80 |  4),   1 },
140 /* 5.5 Mb */ {  AH_TRUE,  CCK,    5500,    0x19,    0x04, (0x80 | 11),   1 },
141 /*  11 Mb */ {  AH_TRUE,  CCK,   11000,    0x18,    0x04, (0x80 | 22),   1 },
142     },
143 };
144 
145 
146 /* Venice TODO: round_up_rate() is broken when the rate table does not represent
147  * rates in increasing order  e.g.  5.5, 11, 6, 9.
148  * An average rate of 6 Mbps will currently map to 11 Mbps.
149  */
150 #define AR9300_11G_RT_OFDM_OFFSET    4
151 HAL_RATE_TABLE ar9300_11g_table = {
152     12,  /* number of rates */
153     { 0 },
154     {
155 /*                                                 short            ctrl */
156 /*             valid                rate_code Preamble    dot11Rate Rate */
157 /*   1 Mb */ {  AH_TRUE, CCK,     1000,    0x1b,    0x00, (0x80 |  2),   0 },
158 /*   2 Mb */ {  AH_TRUE, CCK,     2000,    0x1a,    0x04, (0x80 |  4),   1 },
159 /* 5.5 Mb */ {  AH_TRUE, CCK,     5500,    0x19,    0x04, (0x80 | 11),   2 },
160 /*  11 Mb */ {  AH_TRUE, CCK,    11000,    0x18,    0x04, (0x80 | 22),   3 },
161 /* Hardware workaround - remove rates 6, 9 from rate ctrl */
162 /*   6 Mb */ {  AH_TRUE, OFDM,    6000,    0x0b,    0x00,          12,   4 },
163 /*   9 Mb */ {  AH_TRUE, OFDM,    9000,    0x0f,    0x00,          18,   4 },
164 /*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00,          24,   6 },
165 /*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   6 },
166 /*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00,          48,   8 },
167 /*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   8 },
168 /*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   8 },
169 /*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   8 },
170     },
171 };
172 
173 #if 0
174 HAL_RATE_TABLE ar9300_xr_table = {
175     13,        /* number of rates */
176     { 0 },
177     {
178 /*                                                 short     ctrl */
179 /*            valid          rate_code Preamble    dot11Rate Rate */
180 /* 0.25 Mb */ {AH_TRUE,   XR,   250, 0x03,   0x00, (0x80 |  1),   0, 612, 612 },
181 /*  0.5 Mb */ {AH_TRUE,   XR,   500, 0x07,   0x00, (0x80 |  1),   0, 457, 457 },
182 /*    1 Mb */ {AH_TRUE,   XR,  1000, 0x02,   0x00, (0x80 |  2),   1, 228, 228 },
183 /*    2 Mb */ {AH_TRUE,   XR,  2000, 0x06,   0x00, (0x80 |  4),   2, 160, 160 },
184 /*    3 Mb */ {AH_TRUE,   XR,  3000, 0x01,   0x00, (0x80 |  6),   3, 140, 140 },
185 /*    6 Mb */ {AH_TRUE, OFDM,  6000, 0x0b,   0x00, (0x80 | 12),   4, 60,  60  },
186 /*    9 Mb */ {AH_TRUE, OFDM,  9000, 0x0f,   0x00,          18,   4, 60,  60  },
187 /*   12 Mb */ {AH_TRUE, OFDM, 12000, 0x0a,   0x00, (0x80 | 24),   6, 48,  48  },
188 /*   18 Mb */ {AH_TRUE, OFDM, 18000, 0x0e,   0x00,          36,   6, 48,  48  },
189 /*   24 Mb */ {AH_TRUE, OFDM, 24000, 0x09,   0x00,          48,   8, 44,  44  },
190 /*   36 Mb */ {AH_TRUE, OFDM, 36000, 0x0d,   0x00,          72,   8, 44,  44  },
191 /*   48 Mb */ {AH_TRUE, OFDM, 48000, 0x08,   0x00,          96,   8, 44,  44  },
192 /*   54 Mb */ {AH_TRUE, OFDM, 54000, 0x0c,   0x00,         108,   8, 44,  44  },
193     },
194 };
195 #endif
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
201 HAL_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
255 static 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 
307 const HAL_RATE_TABLE *
308 ar9300_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->halChanHalfRate) {
320             rt = &ar9300_11a_half_table;
321             break;
322         }
323         return AH_NULL;
324     case HAL_MODE_11A_QUARTER_RATE:
325         if (p_cap->halChanQuarterRate) {
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 #if 0
341     case HAL_MODE_XR:
342         rt = &ar9300_xr_table;
343         break;
344 #endif
345     case HAL_MODE_11NG_HT20:
346     case HAL_MODE_11NG_HT40PLUS:
347     case HAL_MODE_11NG_HT40MINUS:
348         rt = &ar9300_11ng_table;
349         break;
350     case HAL_MODE_11NA_HT20:
351     case HAL_MODE_11NA_HT40PLUS:
352     case HAL_MODE_11NA_HT40MINUS:
353         rt = &ar9300_11na_table;
354         break;
355     default:
356         HALDEBUG(ah, HAL_DEBUG_CHANNEL,
357             "%s: invalid mode 0x%x\n", __func__, mode);
358         return AH_NULL;
359     }
360     ath_hal_setupratetable(ah, rt);
361     return rt;
362 }
363 
364 static HAL_BOOL
365 ar9300_invalid_stbc_cfg(int tx_chains, u_int8_t rate_code)
366 {
367     switch (tx_chains) {
368     case 0: /* Single Chain */
369         return AH_TRUE;
370 
371     case 1: /* 2 Chains */
372         if ((rate_code < 0x80) || (rate_code > 0x87)) {
373             return AH_TRUE;
374         } else {
375             return AH_FALSE;
376         }
377 
378     case 2: /* 3 Chains */
379         if ((rate_code < 0x80) || (rate_code > 0x87)) {
380             return AH_TRUE;
381         } else {
382             return AH_FALSE;
383         }
384 
385     default:
386         HALASSERT(0);
387         break;
388     }
389 
390     return AH_TRUE;
391 }
392 
393 int16_t
394 ar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index,
395                      u_int8_t chainmask, u_int8_t xmit_mode)
396 {
397     struct ath_hal_9300 *ahp = AH9300(ah);
398     int num_chains = ar9300_get_ntxchains(chainmask);
399 
400     switch (xmit_mode) {
401     case AR9300_DEF_MODE:
402         return ahp->txpower[rate_index][num_chains-1];
403 
404 
405     case AR9300_STBC_MODE:
406         return ahp->txpower_stbc[rate_index][num_chains-1];
407 
408     default:
409         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
410              __func__, xmit_mode);
411         HALASSERT(0);
412         break;
413     }
414 
415     return ahp->txpower[rate_index][num_chains-1];
416 }
417 
418 extern void
419 ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah,
420                       u_int8_t power_per_rate[])
421 
422 {
423     struct ath_hal_9300 *ahp = AH9300(ah);
424     int16_t twice_array_gain, cdd_power = 0;
425     int i;
426 
427     /*
428      *  Adjust the upper limit for CDD factoring in the array gain .
429      *  The array gain is the same as TxBF, hence reuse the same defines.
430      */
431     switch (ahp->ah_tx_chainmask) {
432 
433     case OSPREY_1_CHAINMASK:
434         cdd_power = ahp->upper_limit[0];
435         break;
436 
437     case OSPREY_2LOHI_CHAINMASK:
438     case OSPREY_2LOMID_CHAINMASK:
439         twice_array_gain =
440            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
441            -(AR9300_TXBF_2TX_ARRAY_GAIN) :
442            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
443            (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
444         cdd_power = ahp->upper_limit[1] + twice_array_gain;
445         /* Adjust OFDM legacy rates as well */
446         for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
447             if (power_per_rate[i] > cdd_power) {
448                 power_per_rate[i] = cdd_power;
449             }
450         }
451 
452         /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 20*/
453         for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) {
454             if (power_per_rate[i] > cdd_power) {
455                 power_per_rate[i] = cdd_power;
456             }
457         }
458 
459         /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 40*/
460         for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) {
461             if (power_per_rate[i] > cdd_power) {
462                 power_per_rate[i] = cdd_power;
463             }
464         }
465         break;
466 
467     case OSPREY_3_CHAINMASK:
468         twice_array_gain =
469             (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
470             -(AR9300_TXBF_3TX_ARRAY_GAIN) :
471             ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
472             (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
473         cdd_power = ahp->upper_limit[2] + twice_array_gain;
474         /* Adjust OFDM legacy rates as well */
475         for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
476             if (power_per_rate[i] > cdd_power) {
477                 power_per_rate[i] = cdd_power;
478             }
479         }
480         /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */
481         for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) {
482             if (power_per_rate[i] > cdd_power) {
483                 power_per_rate[i] = cdd_power;
484             }
485         }
486 
487         /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */
488         for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) {
489             if (power_per_rate[i] > cdd_power) {
490                 power_per_rate[i] = cdd_power;
491             }
492         }
493 
494         break;
495 
496     default:
497         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
498                  __func__, ahp->ah_tx_chainmask);
499         break;
500     }
501 
502     return;
503 }
504 
505 extern void
506 ar9300_init_rate_txpower(struct ath_hal *ah, u_int mode,
507                       const struct ieee80211_channel *chan,
508                       u_int8_t power_per_rate[], u_int8_t chainmask)
509 {
510     const HAL_RATE_TABLE *rt;
511     HAL_BOOL is40 = IEEE80211_IS_CHAN_HT40(chan);
512 
513     rt = ar9300_get_rate_table(ah, mode);
514     HALASSERT(rt != NULL);
515 
516     switch (mode) {
517     case HAL_MODE_11A:
518         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
519                               AR9300_11A_RT_OFDM_OFFSET, chainmask);
520         break;
521     case HAL_MODE_11NA_HT20:
522     case HAL_MODE_11NA_HT40PLUS:
523     case HAL_MODE_11NA_HT40MINUS:
524         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
525                               AR9300_11NA_RT_OFDM_OFFSET, chainmask);
526         ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
527                             AR9300_11NA_RT_HT_SS_OFFSET,
528                             AR9300_11NA_RT_HT_DS_OFFSET,
529                             AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
530         ar9300_init_rate_txpower_stbc(ah, rt, is40,
531                             AR9300_11NA_RT_HT_SS_OFFSET,
532                             AR9300_11NA_RT_HT_DS_OFFSET,
533                             AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
534         /* For FCC the array gain has to be factored for CDD mode */
535         if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
536             ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
537                             AR9300_11NA_RT_HT_SS_OFFSET,
538                             AR9300_11NA_RT_HT_DS_OFFSET,
539                             AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
540         }
541         break;
542     case HAL_MODE_11G:
543         ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
544         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
545                               AR9300_11G_RT_OFDM_OFFSET, chainmask);
546         break;
547     case HAL_MODE_11B:
548         ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
549         break;
550     case HAL_MODE_11NG_HT20:
551     case HAL_MODE_11NG_HT40PLUS:
552     case HAL_MODE_11NG_HT40MINUS:
553         ar9300_init_rate_txpower_cck(ah, rt, power_per_rate,  chainmask);
554         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
555                               AR9300_11NG_RT_OFDM_OFFSET, chainmask);
556         ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
557                             AR9300_11NG_RT_HT_SS_OFFSET,
558                             AR9300_11NG_RT_HT_DS_OFFSET,
559                             AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
560         ar9300_init_rate_txpower_stbc(ah, rt, is40,
561                             AR9300_11NG_RT_HT_SS_OFFSET,
562                             AR9300_11NG_RT_HT_DS_OFFSET,
563                             AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
564         /* For FCC the array gain needs to be factored for CDD mode */
565         if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
566             ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
567                             AR9300_11NG_RT_HT_SS_OFFSET,
568                             AR9300_11NG_RT_HT_DS_OFFSET,
569                             AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
570         }
571         break;
572     default:
573         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
574              __func__, mode);
575         HALASSERT(0);
576         break;
577     }
578 
579 }
580 
581 static inline void
582 ar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
583                          u_int8_t rates_array[], u_int8_t chainmask)
584 {
585     struct ath_hal_9300 *ahp = AH9300(ah);
586     /*
587      * Pick the lower of the long-preamble txpower, and short-preamble tx power.
588      * Unfortunately, the rate table doesn't have separate entries for these!.
589      */
590     switch (chainmask) {
591     case OSPREY_1_CHAINMASK:
592         ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
593         ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
594         ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
595                                   rates_array[ALL_TARGET_LEGACY_5S]);
596         ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
597                                       rates_array[ALL_TARGET_LEGACY_11S]);
598         break;
599     case OSPREY_2LOHI_CHAINMASK:
600     case OSPREY_2LOMID_CHAINMASK:
601         ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
602         ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
603         ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
604                                   rates_array[ALL_TARGET_LEGACY_5S]);
605         ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
606                                   rates_array[ALL_TARGET_LEGACY_11S]);
607         break;
608     case OSPREY_3_CHAINMASK:
609         ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
610         ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
611         ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
612                                    rates_array[ALL_TARGET_LEGACY_5S]);
613         ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
614                                        rates_array[ALL_TARGET_LEGACY_11S]);
615         break;
616     default:
617         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
618                  __func__, chainmask);
619         break;
620     }
621 }
622 
623 static inline void
624 ar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
625                           u_int8_t rates_array[], int rt_offset,
626                           u_int8_t chainmask)
627 {
628     struct ath_hal_9300 *ahp = AH9300(ah);
629     int16_t twice_array_gain, cdd_power = 0;
630     int i, j;
631     u_int8_t ofdm_rt_2_pwr_idx[8] =
632     {
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_6_24,
638         ALL_TARGET_LEGACY_36,
639         ALL_TARGET_LEGACY_48,
640         ALL_TARGET_LEGACY_54,
641     };
642 
643     /*
644      *  For FCC adjust the upper limit for CDD factoring in the array gain.
645      *  The array gain is the same as TxBF, hence reuse the same defines.
646      */
647     for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) {
648 
649         /* Get the correct OFDM rate to Power table Index */
650         j = ofdm_rt_2_pwr_idx[i- rt_offset];
651 
652         switch (chainmask) {
653         case OSPREY_1_CHAINMASK:
654             ahp->txpower[i][0] = rates_array[j];
655             break;
656         case OSPREY_2LOHI_CHAINMASK:
657         case OSPREY_2LOMID_CHAINMASK:
658             ahp->txpower[i][1] = rates_array[j];
659             if (is_reg_dmn_fcc(ahp->reg_dmn)){
660                 twice_array_gain = (ahp->twice_antenna_gain >=
661                 ahp->twice_antenna_reduction)?
662                 -(AR9300_TXBF_2TX_ARRAY_GAIN) :
663                 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
664                (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
665                 cdd_power = ahp->upper_limit[1] + twice_array_gain;
666                 if (ahp->txpower[i][1] > cdd_power){
667                     ahp->txpower[i][1] = cdd_power;
668                 }
669             }
670             break;
671         case OSPREY_3_CHAINMASK:
672             ahp->txpower[i][2] = rates_array[j];
673             if (is_reg_dmn_fcc(ahp->reg_dmn)) {
674                 twice_array_gain =
675                 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
676                 -(AR9300_TXBF_3TX_ARRAY_GAIN):
677                 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
678                 (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
679                 cdd_power = ahp->upper_limit[2] + twice_array_gain;
680                 if (ahp->txpower[i][2] > cdd_power){
681                     ahp->txpower[i][2] = cdd_power;
682                 }
683             }
684             break;
685         default:
686             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
687                      __func__, chainmask);
688             break;
689         }
690     }
691 }
692 
693 static  u_int8_t mcs_rate_2_pwr_idx_ht20[24] =
694     {
695         ALL_TARGET_HT20_0_8_16,
696         ALL_TARGET_HT20_1_3_9_11_17_19,
697         ALL_TARGET_HT20_1_3_9_11_17_19,
698         ALL_TARGET_HT20_1_3_9_11_17_19,
699         ALL_TARGET_HT20_4,
700         ALL_TARGET_HT20_5,
701         ALL_TARGET_HT20_6,
702         ALL_TARGET_HT20_7,
703         ALL_TARGET_HT20_0_8_16,
704         ALL_TARGET_HT20_1_3_9_11_17_19,
705         ALL_TARGET_HT20_1_3_9_11_17_19,
706         ALL_TARGET_HT20_1_3_9_11_17_19,
707         ALL_TARGET_HT20_12,
708         ALL_TARGET_HT20_13,
709         ALL_TARGET_HT20_14,
710         ALL_TARGET_HT20_15,
711         ALL_TARGET_HT20_0_8_16,
712         ALL_TARGET_HT20_1_3_9_11_17_19,
713         ALL_TARGET_HT20_1_3_9_11_17_19,
714         ALL_TARGET_HT20_1_3_9_11_17_19,
715         ALL_TARGET_HT20_20,
716         ALL_TARGET_HT20_21,
717         ALL_TARGET_HT20_22,
718         ALL_TARGET_HT20_23
719     };
720 
721 static   u_int8_t mcs_rate_2_pwr_idx_ht40[24] =
722     {
723         ALL_TARGET_HT40_0_8_16,
724         ALL_TARGET_HT40_1_3_9_11_17_19,
725         ALL_TARGET_HT40_1_3_9_11_17_19,
726         ALL_TARGET_HT40_1_3_9_11_17_19,
727         ALL_TARGET_HT40_4,
728         ALL_TARGET_HT40_5,
729         ALL_TARGET_HT40_6,
730         ALL_TARGET_HT40_7,
731         ALL_TARGET_HT40_0_8_16,
732         ALL_TARGET_HT40_1_3_9_11_17_19,
733         ALL_TARGET_HT40_1_3_9_11_17_19,
734         ALL_TARGET_HT40_1_3_9_11_17_19,
735         ALL_TARGET_HT40_12,
736         ALL_TARGET_HT40_13,
737         ALL_TARGET_HT40_14,
738         ALL_TARGET_HT40_15,
739         ALL_TARGET_HT40_0_8_16,
740         ALL_TARGET_HT40_1_3_9_11_17_19,
741         ALL_TARGET_HT40_1_3_9_11_17_19,
742         ALL_TARGET_HT40_1_3_9_11_17_19,
743         ALL_TARGET_HT40_20,
744         ALL_TARGET_HT40_21,
745         ALL_TARGET_HT40_22,
746         ALL_TARGET_HT40_23,
747     };
748 
749 static inline void
750 ar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
751                         HAL_BOOL is40,
752                         u_int8_t rates_array[],
753                         int rt_ss_offset, int rt_ds_offset,
754                         int rt_ts_offset, u_int8_t chainmask)
755 {
756 
757     struct ath_hal_9300 *ahp = AH9300(ah);
758     int i, j;
759     u_int8_t mcs_index = 0;
760 
761 
762     for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
763         /* Get the correct MCS rate to Power table Index */
764         j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
765                           mcs_rate_2_pwr_idx_ht20[mcs_index];
766         switch (chainmask) {
767         case OSPREY_1_CHAINMASK:
768             ahp->txpower[i][0] = rates_array[j];
769             break;
770         case OSPREY_2LOHI_CHAINMASK:
771         case OSPREY_2LOMID_CHAINMASK:
772             ahp->txpower[i][1] = rates_array[j];
773             break;
774         case OSPREY_3_CHAINMASK:
775             ahp->txpower[i][2] = rates_array[j];
776             break;
777         default:
778             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
779                      __func__, chainmask);
780             break;
781         }
782         mcs_index++;
783     }
784 
785     for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
786         /* Get the correct MCS rate to Power table Index */
787         j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
788                                        mcs_rate_2_pwr_idx_ht20[mcs_index];
789         switch (chainmask) {
790         case OSPREY_1_CHAINMASK:
791             ahp->txpower[i][0] = rates_array[j];
792             break;
793         case OSPREY_2LOHI_CHAINMASK:
794         case OSPREY_2LOMID_CHAINMASK:
795             ahp->txpower[i][1] = rates_array[j];
796             break;
797         case OSPREY_3_CHAINMASK:
798             ahp->txpower[i][2] = rates_array[j];
799             break;
800         default:
801             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
802                          __func__, chainmask);
803             break;
804         }
805         mcs_index++;
806     }
807 
808     for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
809         /* Get the correct MCS rate to Power table Index */
810         j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
811                                   mcs_rate_2_pwr_idx_ht20[mcs_index];
812         switch (chainmask) {
813         case OSPREY_1_CHAINMASK:
814             ahp->txpower[i][0] = rates_array[j];
815             break;
816         case OSPREY_2LOHI_CHAINMASK:
817         case OSPREY_2LOMID_CHAINMASK:
818             ahp->txpower[i][1] = rates_array[j];
819             break;
820         case OSPREY_3_CHAINMASK:
821             ahp->txpower[i][2] = rates_array[j];
822             break;
823         default:
824             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
825                  __func__, chainmask);
826             break;
827         }
828         mcs_index++;
829     }
830 }
831 
832 static inline void
833 ar9300_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 
944 static inline void
945 ar9300_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 
1041 void ar9300_disp_tpc_tables(struct ath_hal *ah)
1042 {
1043     struct ath_hal_9300 *ahp = AH9300(ah);
1044     const struct ieee80211_channel *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->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].rateCode, rt->info[i].rateKbps,
1066                        j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1067         }
1068     }
1069     ath_hal_printf(ah, "\n");
1070 
1071     ath_hal_printf(ah, "\n\n===TARGET POWER TABLE with STBC===\n");
1072     for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1073         for (i = 0; i < rt->rateCount; i++) {
1074             int16_t txpower[AR9300_MAX_CHAINS];
1075             txpower[j] = ahp->txpower_stbc[i][j];
1076 
1077             /* Do not display invalid configurations */
1078             if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1079                 (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1080                 ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1081                 continue;
1082             }
1083 
1084             ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
1085                        "Power (%d Chain) [%2d.%1d dBm]\n",
1086                        i, rt->info[i].rateCode , rt->info[i].rateKbps,
1087                        j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1088         }
1089     }
1090     ath_hal_printf(ah, "\n");
1091 }
1092 
1093 /*
1094  * The followings are customer specific APIs for querying power limit.
1095  * Power limit is based on regulatory domain, chipset, and transmission rate.
1096  * Here we only consider EEPROM values, no array gain/CTL considered here.
1097  */
1098 
1099 struct rate_power_tbl {
1100     u_int8_t    rateIdx;        /* rate index in the rate table */
1101     u_int32_t   rateKbps;       /* transfer rate in kbs */
1102     u_int8_t    rateCode;      /* rate for h/w descriptors */
1103     u_int8_t    txbf:   1,      /* txbf eligible */
1104                 stbc:   1,      /* stbc eligible */
1105                 chain1: 1,      /* one-chain eligible */
1106                 chain2: 1,      /* two-chain eligible */
1107                 chain3: 1;      /* three-chain eligible */
1108     int16_t     txpower[AR9300_MAX_CHAINS];     /* txpower for different chainmasks */
1109     int16_t     txpower_stbc[AR9300_MAX_CHAINS];
1110 };
1111 
1112 u_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah)
1113 {
1114     struct ath_hal_9300 *ahp = AH9300(ah);
1115     const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
1116     u_int mode = ath_hal_get_curmode(ah, chan);
1117     const HAL_RATE_TABLE *rt;
1118     u_int8_t *data;
1119     struct rate_power_tbl *table;
1120     int i, j;
1121 
1122     /* Check whether TPC is enabled */
1123     if (! ah->ah_config.ath_hal_desc_tpc) {
1124         ath_hal_printf(ah, "\n TPC Register method in use\n");
1125         return NULL;
1126     }
1127 
1128     rt = (const HAL_RATE_TABLE *)ar9300_get_rate_table(ah, mode);
1129     HALASSERT(rt != NULL);
1130 
1131     data = (u_int8_t *)ath_hal_malloc(
1132                        1 + rt->rateCount * sizeof(struct rate_power_tbl));
1133     if (data == NULL)
1134         return NULL;
1135 
1136     OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl));
1137     /* store the rate count at the beginning */
1138     *data = rt->rateCount;
1139     table = (struct rate_power_tbl *)&data[1];
1140 
1141     for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1142         for (i = 0; i < rt->rateCount; i++) {
1143             table[i].rateIdx = i;
1144             table[i].rateCode = rt->info[i].rateCode;
1145             table[i].rateKbps = rt->info[i].rateKbps;
1146             switch (j) {
1147             case 0:
1148                 table[i].chain1 = rt->info[i].rateCode <= 0x87 ? 1 : 0;
1149                 break;
1150             case 1:
1151                 table[i].chain2 = rt->info[i].rateCode <= 0x8f ? 1 : 0;
1152                 break;
1153             case 2:
1154                 table[i].chain3 = 1;
1155                 break;
1156             default:
1157                 break;
1158             }
1159             if ((j == 0 && table[i].chain1) ||
1160                 (j == 1 && table[i].chain2) ||
1161                 (j == 2 && table[i].chain3))
1162                 table[i].txpower[j] = ahp->txpower[i][j];
1163         }
1164     }
1165 
1166     for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1167         for (i = 0; i < rt->rateCount; i++) {
1168             /* Do not display invalid configurations */
1169             if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1170                 (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1171                 ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1172                 continue;
1173             }
1174 
1175             table[i].stbc = 1;
1176             table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j];
1177         }
1178     }
1179 
1180     return data;
1181     /* the caller is responsible to free data */
1182 }
1183 
1184 HAL_STATUS
1185 ath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq,
1186                                         int8_t *max_rate_power, int8_t *min_rate_power)
1187 {
1188     /*
1189      * Used for AR9300 series chip only
1190      */
1191     if (ah->ah_magic == AR9300_MAGIC) {
1192         u_int8_t target_rate_power_limit_val_t2[ar9300_rate_size];
1193         int i;
1194 
1195         *max_rate_power = 0;
1196         *min_rate_power = AR9300_MAX_RATE_POWER;
1197 
1198         ar9300_set_target_power_from_eeprom(ah, freq, target_rate_power_limit_val_t2);
1199 
1200         for (i=0; i<ar9300_rate_size; i++) {
1201             if (target_rate_power_limit_val_t2[i] > *max_rate_power)
1202                 *max_rate_power = target_rate_power_limit_val_t2[i];
1203             if (target_rate_power_limit_val_t2[i] < *min_rate_power)
1204                 *min_rate_power = target_rate_power_limit_val_t2[i];
1205         }
1206     } else {
1207         *max_rate_power = 0;
1208         *min_rate_power = 0;
1209     }
1210 
1211     return HAL_OK;
1212 }
1213