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