xref: /freebsd/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_phy.c (revision 6851341a3328ce3c36a52f24086f1b8bed1dde82)
176bd547bSAdrian Chadd /*
276bd547bSAdrian Chadd  * Copyright (c) 2013 Qualcomm Atheros, Inc.
376bd547bSAdrian Chadd  *
476bd547bSAdrian Chadd  * Permission to use, copy, modify, and/or distribute this software for any
576bd547bSAdrian Chadd  * purpose with or without fee is hereby granted, provided that the above
676bd547bSAdrian Chadd  * copyright notice and this permission notice appear in all copies.
776bd547bSAdrian Chadd  *
876bd547bSAdrian Chadd  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
976bd547bSAdrian Chadd  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1076bd547bSAdrian Chadd  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1176bd547bSAdrian Chadd  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1276bd547bSAdrian Chadd  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1376bd547bSAdrian Chadd  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1476bd547bSAdrian Chadd  * PERFORMANCE OF THIS SOFTWARE.
1576bd547bSAdrian Chadd  */
1676bd547bSAdrian Chadd 
1776bd547bSAdrian Chadd #include "opt_ah.h"
1876bd547bSAdrian Chadd 
1976bd547bSAdrian Chadd #include "ah.h"
2076bd547bSAdrian Chadd #include "ah_internal.h"
2176bd547bSAdrian Chadd 
2276bd547bSAdrian Chadd #include "ar9300/ar9300.h"
2376bd547bSAdrian Chadd 
2476bd547bSAdrian Chadd /* shorthands to compact tables for readability */
2576bd547bSAdrian Chadd #define    OFDM    IEEE80211_T_OFDM
2676bd547bSAdrian Chadd #define    CCK    IEEE80211_T_CCK
2776bd547bSAdrian Chadd #define    TURBO    IEEE80211_T_TURBO
2876bd547bSAdrian Chadd #define    XR    ATHEROS_T_XR
2976bd547bSAdrian Chadd #define HT      IEEE80211_T_HT
3076bd547bSAdrian Chadd 
3176bd547bSAdrian Chadd #define AR9300_NUM_OFDM_RATES   8
3276bd547bSAdrian Chadd #define AR9300_NUM_HT_SS_RATES  8
3376bd547bSAdrian Chadd #define AR9300_NUM_HT_DS_RATES  8
3476bd547bSAdrian Chadd #define AR9300_NUM_HT_TS_RATES  8
3576bd547bSAdrian Chadd 
3676bd547bSAdrian Chadd /* Array Gain defined for TxBF */
3776bd547bSAdrian Chadd #define AR9300_TXBF_2TX_ARRAY_GAIN  6  /* 2TX/SS 3 */
3876bd547bSAdrian Chadd #define AR9300_TXBF_3TX_ARRAY_GAIN  10 /* 3TX/SS or 3TX/DS 4.8 */
3976bd547bSAdrian Chadd #define AR9300_STBC_3TX_ARRAY_GAIN  10 /* 3TX/SS or 3TX/DS 4.8 */
4076bd547bSAdrian Chadd 
4176bd547bSAdrian Chadd /* MCS RATE CODES - first and last */
4276bd547bSAdrian Chadd #define AR9300_MCS0_RATE_CODE   0x80
4376bd547bSAdrian Chadd #define AR9300_MCS23_RATE_CODE  0x97
4476bd547bSAdrian Chadd 
4576bd547bSAdrian Chadd static inline void ar9300_init_rate_txpower_cck(struct ath_hal *ah,
4676bd547bSAdrian Chadd        const HAL_RATE_TABLE *rt, u_int8_t rates_array[], u_int8_t chainmask);
4776bd547bSAdrian Chadd static inline void ar9300_init_rate_txpower_ofdm(struct ath_hal* ah,
4876bd547bSAdrian Chadd        const HAL_RATE_TABLE *rt, u_int8_t rates_array[], int rt_offset,
4976bd547bSAdrian Chadd        u_int8_t chainmask);
5076bd547bSAdrian Chadd static inline void ar9300_init_rate_txpower_ht(struct ath_hal *ah,
5176bd547bSAdrian Chadd        const HAL_RATE_TABLE *rt, HAL_BOOL is40, u_int8_t rates_array[],
5276bd547bSAdrian Chadd        int rt_ss_offset, int rt_ds_offset,
5376bd547bSAdrian Chadd        int rt_ts_offset, u_int8_t chainmask);
5476bd547bSAdrian Chadd static inline void ar9300_init_rate_txpower_stbc(struct ath_hal *ah,
5576bd547bSAdrian Chadd        const HAL_RATE_TABLE *rt, HAL_BOOL is40,
5676bd547bSAdrian Chadd        int rt_ss_offset, int rt_ds_offset,
5776bd547bSAdrian Chadd        int rt_ts_offset, u_int8_t chainmask);
58*6851341aSAdrian Chadd #if 0
5976bd547bSAdrian Chadd static inline void ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah,
6076bd547bSAdrian Chadd        const HAL_RATE_TABLE *rt, HAL_BOOL is40,
6176bd547bSAdrian Chadd        int rt_ss_offset, int rt_ds_offset,
6276bd547bSAdrian Chadd        int rt_ts_offset, u_int8_t chainmask);
63*6851341aSAdrian Chadd #endif
6476bd547bSAdrian Chadd 
6576bd547bSAdrian Chadd #define AR9300_11A_RT_OFDM_OFFSET    0
6676bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_11a_table = {
6776bd547bSAdrian Chadd     8,  /* number of rates */
6876bd547bSAdrian Chadd     { 0 },
6976bd547bSAdrian Chadd     {
7076bd547bSAdrian Chadd /*                                                  short            ctrl */
7176bd547bSAdrian Chadd /*             valid                 rate_code Preamble    dot11Rate Rate */
7276bd547bSAdrian Chadd /*   6 Mb */ {  AH_TRUE, OFDM,    6000,     0x0b,    0x00, (0x80 | 12),   0 },
7376bd547bSAdrian Chadd /*   9 Mb */ {  AH_TRUE, OFDM,    9000,     0x0f,    0x00,          18,   0 },
7476bd547bSAdrian Chadd /*  12 Mb */ {  AH_TRUE, OFDM,   12000,     0x0a,    0x00, (0x80 | 24),   2 },
7576bd547bSAdrian Chadd /*  18 Mb */ {  AH_TRUE, OFDM,   18000,     0x0e,    0x00,          36,   2 },
7676bd547bSAdrian Chadd /*  24 Mb */ {  AH_TRUE, OFDM,   24000,     0x09,    0x00, (0x80 | 48),   4 },
7776bd547bSAdrian Chadd /*  36 Mb */ {  AH_TRUE, OFDM,   36000,     0x0d,    0x00,          72,   4 },
7876bd547bSAdrian Chadd /*  48 Mb */ {  AH_TRUE, OFDM,   48000,     0x08,    0x00,          96,   4 },
7976bd547bSAdrian Chadd /*  54 Mb */ {  AH_TRUE, OFDM,   54000,     0x0c,    0x00,         108,   4 },
8076bd547bSAdrian Chadd     },
8176bd547bSAdrian Chadd };
8276bd547bSAdrian Chadd 
8376bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_11a_half_table = {
8476bd547bSAdrian Chadd     8,  /* number of rates */
8576bd547bSAdrian Chadd     { 0 },
8676bd547bSAdrian Chadd     {
8776bd547bSAdrian Chadd /*                                                  short            ctrl */
8876bd547bSAdrian Chadd /*             valid                 rate_code Preamble    dot11Rate Rate */
8976bd547bSAdrian Chadd /*   6 Mb */ {  AH_TRUE, OFDM,    3000,     0x0b,    0x00, (0x80 |  6),   0 },
9076bd547bSAdrian Chadd /*   9 Mb */ {  AH_TRUE, OFDM,    4500,     0x0f,    0x00,           9,   0 },
9176bd547bSAdrian Chadd /*  12 Mb */ {  AH_TRUE, OFDM,    6000,     0x0a,    0x00, (0x80 | 12),   2 },
9276bd547bSAdrian Chadd /*  18 Mb */ {  AH_TRUE, OFDM,    9000,     0x0e,    0x00,          18,   2 },
9376bd547bSAdrian Chadd /*  24 Mb */ {  AH_TRUE, OFDM,   12000,     0x09,    0x00, (0x80 | 24),   4 },
9476bd547bSAdrian Chadd /*  36 Mb */ {  AH_TRUE, OFDM,   18000,     0x0d,    0x00,          36,   4 },
9576bd547bSAdrian Chadd /*  48 Mb */ {  AH_TRUE, OFDM,   24000,     0x08,    0x00,          48,   4 },
9676bd547bSAdrian Chadd /*  54 Mb */ {  AH_TRUE, OFDM,   27000,     0x0c,    0x00,          54,   4 },
9776bd547bSAdrian Chadd     },
9876bd547bSAdrian Chadd };
9976bd547bSAdrian Chadd 
10076bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_11a_quarter_table = {
10176bd547bSAdrian Chadd     8,  /* number of rates */
10276bd547bSAdrian Chadd     { 0 },
10376bd547bSAdrian Chadd     {
10476bd547bSAdrian Chadd /*                                                  short           ctrl */
10576bd547bSAdrian Chadd /*            valid                 rate_code Preamble    dot11Rate Rate */
10676bd547bSAdrian Chadd /*  6 Mb */ {  AH_TRUE, OFDM,    1500,     0x0b,    0x00, (0x80 |  3),   0 },
10776bd547bSAdrian Chadd /*  9 Mb */ {  AH_TRUE, OFDM,    2250,     0x0f,    0x00,          4 ,   0 },
10876bd547bSAdrian Chadd /* 12 Mb */ {  AH_TRUE, OFDM,    3000,     0x0a,    0x00, (0x80 |  6),   2 },
10976bd547bSAdrian Chadd /* 18 Mb */ {  AH_TRUE, OFDM,    4500,     0x0e,    0x00,           9,   2 },
11076bd547bSAdrian Chadd /* 24 Mb */ {  AH_TRUE, OFDM,    6000,     0x09,    0x00, (0x80 | 12),   4 },
11176bd547bSAdrian Chadd /* 36 Mb */ {  AH_TRUE, OFDM,    9000,     0x0d,    0x00,          18,   4 },
11276bd547bSAdrian Chadd /* 48 Mb */ {  AH_TRUE, OFDM,   12000,     0x08,    0x00,          24,   4 },
11376bd547bSAdrian Chadd /* 54 Mb */ {  AH_TRUE, OFDM,   13500,     0x0c,    0x00,          27,   4 },
11476bd547bSAdrian Chadd     },
11576bd547bSAdrian Chadd };
11676bd547bSAdrian Chadd 
11776bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_turbo_table = {
11876bd547bSAdrian Chadd     8,  /* number of rates */
11976bd547bSAdrian Chadd     { 0 },
12076bd547bSAdrian Chadd     {
12176bd547bSAdrian Chadd /*                                                 short            ctrl */
12276bd547bSAdrian Chadd /*             valid                rate_code Preamble    dot11Rate Rate */
12376bd547bSAdrian Chadd /*   6 Mb */ {  AH_TRUE, TURBO,   6000,    0x0b,    0x00, (0x80 | 12),   0 },
12476bd547bSAdrian Chadd /*   9 Mb */ {  AH_TRUE, TURBO,   9000,    0x0f,    0x00,          18,   0 },
12576bd547bSAdrian Chadd /*  12 Mb */ {  AH_TRUE, TURBO,  12000,    0x0a,    0x00, (0x80 | 24),   2 },
12676bd547bSAdrian Chadd /*  18 Mb */ {  AH_TRUE, TURBO,  18000,    0x0e,    0x00,          36,   2 },
12776bd547bSAdrian Chadd /*  24 Mb */ {  AH_TRUE, TURBO,  24000,    0x09,    0x00, (0x80 | 48),   4 },
12876bd547bSAdrian Chadd /*  36 Mb */ {  AH_TRUE, TURBO,  36000,    0x0d,    0x00,          72,   4 },
12976bd547bSAdrian Chadd /*  48 Mb */ {  AH_TRUE, TURBO,  48000,    0x08,    0x00,          96,   4 },
13076bd547bSAdrian Chadd /*  54 Mb */ {  AH_TRUE, TURBO,  54000,    0x0c,    0x00,         108,   4 },
13176bd547bSAdrian Chadd     },
13276bd547bSAdrian Chadd };
13376bd547bSAdrian Chadd 
13476bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_11b_table = {
13576bd547bSAdrian Chadd     4,  /* number of rates */
13676bd547bSAdrian Chadd     { 0 },
13776bd547bSAdrian Chadd     {
13876bd547bSAdrian Chadd /*                                                 short            ctrl */
13976bd547bSAdrian Chadd /*             valid                rate_code Preamble    dot11Rate Rate */
14076bd547bSAdrian Chadd /*   1 Mb */ {  AH_TRUE,  CCK,    1000,    0x1b,    0x00, (0x80 |  2),   0 },
14176bd547bSAdrian Chadd /*   2 Mb */ {  AH_TRUE,  CCK,    2000,    0x1a,    0x04, (0x80 |  4),   1 },
14276bd547bSAdrian Chadd /* 5.5 Mb */ {  AH_TRUE,  CCK,    5500,    0x19,    0x04, (0x80 | 11),   1 },
14376bd547bSAdrian Chadd /*  11 Mb */ {  AH_TRUE,  CCK,   11000,    0x18,    0x04, (0x80 | 22),   1 },
14476bd547bSAdrian Chadd     },
14576bd547bSAdrian Chadd };
14676bd547bSAdrian Chadd 
14776bd547bSAdrian Chadd 
14876bd547bSAdrian Chadd /* Venice TODO: round_up_rate() is broken when the rate table does not represent
14976bd547bSAdrian Chadd  * rates in increasing order  e.g.  5.5, 11, 6, 9.
15076bd547bSAdrian Chadd  * An average rate of 6 Mbps will currently map to 11 Mbps.
15176bd547bSAdrian Chadd  */
15276bd547bSAdrian Chadd #define AR9300_11G_RT_OFDM_OFFSET    4
15376bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_11g_table = {
15476bd547bSAdrian Chadd     12,  /* number of rates */
15576bd547bSAdrian Chadd     { 0 },
15676bd547bSAdrian Chadd     {
15776bd547bSAdrian Chadd /*                                                 short            ctrl */
15876bd547bSAdrian Chadd /*             valid                rate_code Preamble    dot11Rate Rate */
15976bd547bSAdrian Chadd /*   1 Mb */ {  AH_TRUE, CCK,     1000,    0x1b,    0x00, (0x80 |  2),   0 },
16076bd547bSAdrian Chadd /*   2 Mb */ {  AH_TRUE, CCK,     2000,    0x1a,    0x04, (0x80 |  4),   1 },
16176bd547bSAdrian Chadd /* 5.5 Mb */ {  AH_TRUE, CCK,     5500,    0x19,    0x04, (0x80 | 11),   2 },
16276bd547bSAdrian Chadd /*  11 Mb */ {  AH_TRUE, CCK,    11000,    0x18,    0x04, (0x80 | 22),   3 },
16376bd547bSAdrian Chadd /* Hardware workaround - remove rates 6, 9 from rate ctrl */
164e113789bSAdrian Chadd /*   6 Mb */ {  AH_TRUE, OFDM,    6000,    0x0b,    0x00,          12,   4 },
165e113789bSAdrian Chadd /*   9 Mb */ {  AH_TRUE, OFDM,    9000,    0x0f,    0x00,          18,   4 },
16676bd547bSAdrian Chadd /*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00,          24,   6 },
16776bd547bSAdrian Chadd /*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   6 },
16876bd547bSAdrian Chadd /*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00,          48,   8 },
16976bd547bSAdrian Chadd /*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   8 },
17076bd547bSAdrian Chadd /*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   8 },
17176bd547bSAdrian Chadd /*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   8 },
17276bd547bSAdrian Chadd     },
17376bd547bSAdrian Chadd };
17476bd547bSAdrian Chadd 
175e113789bSAdrian Chadd #if 0
17676bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_xr_table = {
17776bd547bSAdrian Chadd     13,        /* number of rates */
17876bd547bSAdrian Chadd     { 0 },
17976bd547bSAdrian Chadd     {
18076bd547bSAdrian Chadd /*                                                 short     ctrl */
18176bd547bSAdrian Chadd /*            valid          rate_code Preamble    dot11Rate Rate */
18276bd547bSAdrian Chadd /* 0.25 Mb */ {AH_TRUE,   XR,   250, 0x03,   0x00, (0x80 |  1),   0, 612, 612 },
18376bd547bSAdrian Chadd /*  0.5 Mb */ {AH_TRUE,   XR,   500, 0x07,   0x00, (0x80 |  1),   0, 457, 457 },
18476bd547bSAdrian Chadd /*    1 Mb */ {AH_TRUE,   XR,  1000, 0x02,   0x00, (0x80 |  2),   1, 228, 228 },
18576bd547bSAdrian Chadd /*    2 Mb */ {AH_TRUE,   XR,  2000, 0x06,   0x00, (0x80 |  4),   2, 160, 160 },
18676bd547bSAdrian Chadd /*    3 Mb */ {AH_TRUE,   XR,  3000, 0x01,   0x00, (0x80 |  6),   3, 140, 140 },
18776bd547bSAdrian Chadd /*    6 Mb */ {AH_TRUE, OFDM,  6000, 0x0b,   0x00, (0x80 | 12),   4, 60,  60  },
18876bd547bSAdrian Chadd /*    9 Mb */ {AH_TRUE, OFDM,  9000, 0x0f,   0x00,          18,   4, 60,  60  },
18976bd547bSAdrian Chadd /*   12 Mb */ {AH_TRUE, OFDM, 12000, 0x0a,   0x00, (0x80 | 24),   6, 48,  48  },
19076bd547bSAdrian Chadd /*   18 Mb */ {AH_TRUE, OFDM, 18000, 0x0e,   0x00,          36,   6, 48,  48  },
19176bd547bSAdrian Chadd /*   24 Mb */ {AH_TRUE, OFDM, 24000, 0x09,   0x00,          48,   8, 44,  44  },
19276bd547bSAdrian Chadd /*   36 Mb */ {AH_TRUE, OFDM, 36000, 0x0d,   0x00,          72,   8, 44,  44  },
19376bd547bSAdrian Chadd /*   48 Mb */ {AH_TRUE, OFDM, 48000, 0x08,   0x00,          96,   8, 44,  44  },
19476bd547bSAdrian Chadd /*   54 Mb */ {AH_TRUE, OFDM, 54000, 0x0c,   0x00,         108,   8, 44,  44  },
19576bd547bSAdrian Chadd     },
19676bd547bSAdrian Chadd };
197e113789bSAdrian Chadd #endif
19876bd547bSAdrian Chadd 
19976bd547bSAdrian Chadd #define AR9300_11NG_RT_OFDM_OFFSET       4
20076bd547bSAdrian Chadd #define AR9300_11NG_RT_HT_SS_OFFSET      12
20176bd547bSAdrian Chadd #define AR9300_11NG_RT_HT_DS_OFFSET      20
20276bd547bSAdrian Chadd #define AR9300_11NG_RT_HT_TS_OFFSET      28
20376bd547bSAdrian Chadd HAL_RATE_TABLE ar9300_11ng_table = {
20476bd547bSAdrian Chadd 
20576bd547bSAdrian Chadd     36,  /* number of rates */
20676bd547bSAdrian Chadd     { 0 },
20776bd547bSAdrian Chadd     {
20876bd547bSAdrian Chadd /*                                                 short            ctrl */
20976bd547bSAdrian Chadd /*             valid                rate_code Preamble    dot11Rate Rate */
21076bd547bSAdrian Chadd /*   1 Mb */ {  AH_TRUE, CCK,     1000,    0x1b,    0x00, (0x80 |  2),   0 },
21176bd547bSAdrian Chadd /*   2 Mb */ {  AH_TRUE, CCK,     2000,    0x1a,    0x04, (0x80 |  4),   1 },
21276bd547bSAdrian Chadd /* 5.5 Mb */ {  AH_TRUE, CCK,     5500,    0x19,    0x04, (0x80 | 11),   2 },
21376bd547bSAdrian Chadd /*  11 Mb */ {  AH_TRUE, CCK,    11000,    0x18,    0x04, (0x80 | 22),   3 },
21476bd547bSAdrian Chadd /* Hardware workaround - remove rates 6, 9 from rate ctrl */
21576bd547bSAdrian Chadd /*   6 Mb */ {  AH_FALSE, OFDM,    6000,    0x0b,    0x00,          12,   4 },
21676bd547bSAdrian Chadd /*   9 Mb */ {  AH_FALSE, OFDM,    9000,    0x0f,    0x00,          18,   4 },
21776bd547bSAdrian Chadd /*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00,          24,   6 },
21876bd547bSAdrian Chadd /*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   6 },
21976bd547bSAdrian Chadd /*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00,          48,   8 },
22076bd547bSAdrian Chadd /*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   8 },
22176bd547bSAdrian Chadd /*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   8 },
22276bd547bSAdrian Chadd /*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   8 },
22376bd547bSAdrian Chadd /*--- HT SS rates ---*/
22476bd547bSAdrian Chadd /* 6.5 Mb */ {  AH_TRUE, HT,      6500,    0x80,    0x00,           0,   4 },
22576bd547bSAdrian Chadd /*  13 Mb */ {  AH_TRUE, HT,     13000,    0x81,    0x00,           1,   6 },
22676bd547bSAdrian Chadd /*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x82,    0x00,           2,   6 },
22776bd547bSAdrian Chadd /*  26 Mb */ {  AH_TRUE, HT,     26000,    0x83,    0x00,           3,   8 },
22876bd547bSAdrian Chadd /*  39 Mb */ {  AH_TRUE, HT,     39000,    0x84,    0x00,           4,   8 },
22976bd547bSAdrian Chadd /*  52 Mb */ {  AH_TRUE, HT,     52000,    0x85,    0x00,           5,   8 },
23076bd547bSAdrian Chadd /*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x86,    0x00,           6,   8 },
23176bd547bSAdrian Chadd /*  65 Mb */ {  AH_TRUE, HT,     65000,    0x87,    0x00,           7,   8 },
23276bd547bSAdrian Chadd /*--- HT DS rates ---*/
23376bd547bSAdrian Chadd /*  13 Mb */ {  AH_TRUE, HT,     13000,    0x88,    0x00,           8,   4 },
23476bd547bSAdrian Chadd /*  26 Mb */ {  AH_TRUE, HT,     26000,    0x89,    0x00,           9,   6 },
23576bd547bSAdrian Chadd /*  39 Mb */ {  AH_TRUE, HT,     39000,    0x8a,    0x00,          10,   6 },
23676bd547bSAdrian Chadd /*  52 Mb */ {  AH_TRUE, HT,     52000,    0x8b,    0x00,          11,   8 },
23776bd547bSAdrian Chadd /*  78 Mb */ {  AH_TRUE, HT,     78000,    0x8c,    0x00,          12,   8 },
23876bd547bSAdrian Chadd /* 104 Mb */ {  AH_TRUE, HT,    104000,    0x8d,    0x00,          13,   8 },
23976bd547bSAdrian Chadd /* 117 Mb */ {  AH_TRUE, HT,    117000,    0x8e,    0x00,          14,   8 },
24076bd547bSAdrian Chadd /* 130 Mb */ {  AH_TRUE, HT,    130000,    0x8f,    0x00,          15,   8 },
24176bd547bSAdrian Chadd /*--- HT TS rates ---*/
24276bd547bSAdrian Chadd /*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x90,    0x00,          16,   4 },
24376bd547bSAdrian Chadd /*  39 Mb */ {  AH_TRUE, HT,     39000,    0x91,    0x00,          17,   6 },
24476bd547bSAdrian Chadd /*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x92,    0x00,          18,   6 },
24576bd547bSAdrian Chadd /*  78 Mb */ {  AH_TRUE, HT,     78000,    0x93,    0x00,          19,   8 },
24676bd547bSAdrian Chadd /* 117 Mb */ {  AH_TRUE, HT,    117000,    0x94,    0x00,          20,   8 },
24776bd547bSAdrian Chadd /* 156 Mb */ {  AH_TRUE, HT,    156000,    0x95,    0x00,          21,   8 },
24876bd547bSAdrian Chadd /*175.5Mb */ {  AH_TRUE, HT,    175500,    0x96,    0x00,          22,   8 },
24976bd547bSAdrian Chadd /* 195 Mb */ {  AH_TRUE, HT,    195000,    0x97,    0x00,          23,   8 },
25076bd547bSAdrian Chadd     },
25176bd547bSAdrian Chadd };
25276bd547bSAdrian Chadd 
25376bd547bSAdrian Chadd #define AR9300_11NA_RT_OFDM_OFFSET       0
25476bd547bSAdrian Chadd #define AR9300_11NA_RT_HT_SS_OFFSET      8
25576bd547bSAdrian Chadd #define AR9300_11NA_RT_HT_DS_OFFSET      16
25676bd547bSAdrian Chadd #define AR9300_11NA_RT_HT_TS_OFFSET      24
25776bd547bSAdrian Chadd static HAL_RATE_TABLE ar9300_11na_table = {
25876bd547bSAdrian Chadd 
25976bd547bSAdrian Chadd     32,  /* number of rates */
26076bd547bSAdrian Chadd     { 0 },
26176bd547bSAdrian Chadd     {
26276bd547bSAdrian Chadd /*                                                 short            ctrl */
26376bd547bSAdrian Chadd /*             valid                rate_code Preamble    dot11Rate Rate */
26476bd547bSAdrian Chadd /*   6 Mb */ {  AH_TRUE, OFDM,    6000,    0x0b,    0x00, (0x80 | 12),   0 },
26576bd547bSAdrian Chadd /*   9 Mb */ {  AH_TRUE, OFDM,    9000,    0x0f,    0x00,          18,   0 },
26676bd547bSAdrian Chadd /*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00, (0x80 | 24),   2 },
26776bd547bSAdrian Chadd /*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   2 },
26876bd547bSAdrian Chadd /*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00, (0x80 | 48),   4 },
26976bd547bSAdrian Chadd /*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   4 },
27076bd547bSAdrian Chadd /*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   4 },
27176bd547bSAdrian Chadd /*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   4 },
27276bd547bSAdrian Chadd /*--- HT SS rates ---*/
27376bd547bSAdrian Chadd /* 6.5 Mb */ {  AH_TRUE, HT,      6500,    0x80,    0x00,           0,   0 },
27476bd547bSAdrian Chadd /*  13 Mb */ {  AH_TRUE, HT,     13000,    0x81,    0x00,           1,   2 },
27576bd547bSAdrian Chadd /*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x82,    0x00,           2,   2 },
27676bd547bSAdrian Chadd /*  26 Mb */ {  AH_TRUE, HT,     26000,    0x83,    0x00,           3,   4 },
27776bd547bSAdrian Chadd /*  39 Mb */ {  AH_TRUE, HT,     39000,    0x84,    0x00,           4,   4 },
27876bd547bSAdrian Chadd /*  52 Mb */ {  AH_TRUE, HT,     52000,    0x85,    0x00,           5,   4 },
27976bd547bSAdrian Chadd /*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x86,    0x00,           6,   4 },
28076bd547bSAdrian Chadd /*  65 Mb */ {  AH_TRUE, HT,     65000,    0x87,    0x00,           7,   4 },
28176bd547bSAdrian Chadd /*--- HT DS rates ---*/
28276bd547bSAdrian Chadd /*  13 Mb */ {  AH_TRUE, HT,     13000,    0x88,    0x00,           8,   0 },
28376bd547bSAdrian Chadd /*  26 Mb */ {  AH_TRUE, HT,     26000,    0x89,    0x00,           9,   2 },
28476bd547bSAdrian Chadd /*  39 Mb */ {  AH_TRUE, HT,     39000,    0x8a,    0x00,          10,   2 },
28576bd547bSAdrian Chadd /*  52 Mb */ {  AH_TRUE, HT,     52000,    0x8b,    0x00,          11,   4 },
28676bd547bSAdrian Chadd /*  78 Mb */ {  AH_TRUE, HT,     78000,    0x8c,    0x00,          12,   4 },
28776bd547bSAdrian Chadd /* 104 Mb */ {  AH_TRUE, HT,    104000,    0x8d,    0x00,          13,   4 },
28876bd547bSAdrian Chadd /* 117 Mb */ {  AH_TRUE, HT,    117000,    0x8e,    0x00,          14,   4 },
28976bd547bSAdrian Chadd /* 130 Mb */ {  AH_TRUE, HT,    130000,    0x8f,    0x00,          15,   4 },
29076bd547bSAdrian Chadd /*--- HT TS rates ---*/
29176bd547bSAdrian Chadd /*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x90,    0x00,          16,   0 },
29276bd547bSAdrian Chadd /*  39 Mb */ {  AH_TRUE, HT,     39000,    0x91,    0x00,          17,   2 },
29376bd547bSAdrian Chadd /*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x92,    0x00,          18,   2 },
29476bd547bSAdrian Chadd /*  78 Mb */ {  AH_TRUE, HT,     78000,    0x93,    0x00,          19,   4 },
29576bd547bSAdrian Chadd /* 117 Mb */ {  AH_TRUE, HT,    117000,    0x94,    0x00,          20,   4 },
29676bd547bSAdrian Chadd /* 156 Mb */ {  AH_TRUE, HT,    156000,    0x95,    0x00,          21,   4 },
29776bd547bSAdrian Chadd /*175.5Mb */ {  AH_TRUE, HT,    175500,    0x96,    0x00,          22,   4 },
29876bd547bSAdrian Chadd /* 195 Mb */ {  AH_TRUE, HT,    195000,    0x97,    0x00,          23,   4 },
29976bd547bSAdrian Chadd     },
30076bd547bSAdrian Chadd };
30176bd547bSAdrian Chadd 
30276bd547bSAdrian Chadd #undef    OFDM
30376bd547bSAdrian Chadd #undef    CCK
30476bd547bSAdrian Chadd #undef    TURBO
30576bd547bSAdrian Chadd #undef    XR
30676bd547bSAdrian Chadd #undef    HT
30776bd547bSAdrian Chadd #undef    HT_HGI
30876bd547bSAdrian Chadd 
30976bd547bSAdrian Chadd const HAL_RATE_TABLE *
ar9300_get_rate_table(struct ath_hal * ah,u_int mode)31076bd547bSAdrian Chadd ar9300_get_rate_table(struct ath_hal *ah, u_int mode)
31176bd547bSAdrian Chadd {
31276bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
31376bd547bSAdrian Chadd     HAL_CAPABILITIES *p_cap = &ahpriv->ah_caps;
31476bd547bSAdrian Chadd     HAL_RATE_TABLE *rt;
31576bd547bSAdrian Chadd 
31676bd547bSAdrian Chadd     switch (mode) {
31776bd547bSAdrian Chadd     case HAL_MODE_11A:
31876bd547bSAdrian Chadd         rt = &ar9300_11a_table;
31976bd547bSAdrian Chadd         break;
32076bd547bSAdrian Chadd     case HAL_MODE_11A_HALF_RATE:
321e113789bSAdrian Chadd         if (p_cap->halChanHalfRate) {
32276bd547bSAdrian Chadd             rt = &ar9300_11a_half_table;
32376bd547bSAdrian Chadd             break;
32476bd547bSAdrian Chadd         }
32576bd547bSAdrian Chadd         return AH_NULL;
32676bd547bSAdrian Chadd     case HAL_MODE_11A_QUARTER_RATE:
327e113789bSAdrian Chadd         if (p_cap->halChanQuarterRate) {
32876bd547bSAdrian Chadd             rt = &ar9300_11a_quarter_table;
32976bd547bSAdrian Chadd             break;
33076bd547bSAdrian Chadd         }
33176bd547bSAdrian Chadd         return AH_NULL;
33276bd547bSAdrian Chadd     case HAL_MODE_11B:
33376bd547bSAdrian Chadd         rt = &ar9300_11b_table;
33476bd547bSAdrian Chadd         break;
33576bd547bSAdrian Chadd     case HAL_MODE_11G:
33676bd547bSAdrian Chadd         rt =  &ar9300_11g_table;
33776bd547bSAdrian Chadd         break;
33876bd547bSAdrian Chadd     case HAL_MODE_TURBO:
33976bd547bSAdrian Chadd     case HAL_MODE_108G:
34076bd547bSAdrian Chadd         rt =  &ar9300_turbo_table;
34176bd547bSAdrian Chadd         break;
342e113789bSAdrian Chadd #if 0
34376bd547bSAdrian Chadd     case HAL_MODE_XR:
34476bd547bSAdrian Chadd         rt = &ar9300_xr_table;
34576bd547bSAdrian Chadd         break;
346e113789bSAdrian Chadd #endif
34776bd547bSAdrian Chadd     case HAL_MODE_11NG_HT20:
34876bd547bSAdrian Chadd     case HAL_MODE_11NG_HT40PLUS:
34976bd547bSAdrian Chadd     case HAL_MODE_11NG_HT40MINUS:
35076bd547bSAdrian Chadd         rt = &ar9300_11ng_table;
35176bd547bSAdrian Chadd         break;
35276bd547bSAdrian Chadd     case HAL_MODE_11NA_HT20:
35376bd547bSAdrian Chadd     case HAL_MODE_11NA_HT40PLUS:
35476bd547bSAdrian Chadd     case HAL_MODE_11NA_HT40MINUS:
35576bd547bSAdrian Chadd         rt = &ar9300_11na_table;
35676bd547bSAdrian Chadd         break;
35776bd547bSAdrian Chadd     default:
35876bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CHANNEL,
35976bd547bSAdrian Chadd             "%s: invalid mode 0x%x\n", __func__, mode);
36076bd547bSAdrian Chadd         return AH_NULL;
36176bd547bSAdrian Chadd     }
36276bd547bSAdrian Chadd     ath_hal_setupratetable(ah, rt);
36376bd547bSAdrian Chadd     return rt;
36476bd547bSAdrian Chadd }
36576bd547bSAdrian Chadd 
36676bd547bSAdrian Chadd static HAL_BOOL
ar9300_invalid_stbc_cfg(int tx_chains,u_int8_t rate_code)36776bd547bSAdrian Chadd ar9300_invalid_stbc_cfg(int tx_chains, u_int8_t rate_code)
36876bd547bSAdrian Chadd {
36976bd547bSAdrian Chadd     switch (tx_chains) {
37076bd547bSAdrian Chadd     case 0: /* Single Chain */
37176bd547bSAdrian Chadd         return AH_TRUE;
37276bd547bSAdrian Chadd 
37376bd547bSAdrian Chadd     case 1: /* 2 Chains */
37476bd547bSAdrian Chadd         if ((rate_code < 0x80) || (rate_code > 0x87)) {
37576bd547bSAdrian Chadd             return AH_TRUE;
37676bd547bSAdrian Chadd         } else {
37776bd547bSAdrian Chadd             return AH_FALSE;
37876bd547bSAdrian Chadd         }
37976bd547bSAdrian Chadd 
38076bd547bSAdrian Chadd     case 2: /* 3 Chains */
38176bd547bSAdrian Chadd         if ((rate_code < 0x80) || (rate_code > 0x87)) {
38276bd547bSAdrian Chadd             return AH_TRUE;
38376bd547bSAdrian Chadd         } else {
38476bd547bSAdrian Chadd             return AH_FALSE;
38576bd547bSAdrian Chadd         }
38676bd547bSAdrian Chadd 
38776bd547bSAdrian Chadd     default:
38876bd547bSAdrian Chadd         HALASSERT(0);
38976bd547bSAdrian Chadd         break;
39076bd547bSAdrian Chadd     }
39176bd547bSAdrian Chadd 
39276bd547bSAdrian Chadd     return AH_TRUE;
39376bd547bSAdrian Chadd }
39476bd547bSAdrian Chadd 
39576bd547bSAdrian Chadd 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)39676bd547bSAdrian Chadd ar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index,
39776bd547bSAdrian Chadd                      u_int8_t chainmask, u_int8_t xmit_mode)
39876bd547bSAdrian Chadd {
39976bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
40076bd547bSAdrian Chadd     int num_chains = ar9300_get_ntxchains(chainmask);
40176bd547bSAdrian Chadd 
40276bd547bSAdrian Chadd     switch (xmit_mode) {
40376bd547bSAdrian Chadd     case AR9300_DEF_MODE:
40476bd547bSAdrian Chadd         return ahp->txpower[rate_index][num_chains-1];
40576bd547bSAdrian Chadd 
40676bd547bSAdrian Chadd 
40776bd547bSAdrian Chadd     case AR9300_STBC_MODE:
40876bd547bSAdrian Chadd         return ahp->txpower_stbc[rate_index][num_chains-1];
40976bd547bSAdrian Chadd 
41076bd547bSAdrian Chadd     default:
41176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
41276bd547bSAdrian Chadd              __func__, xmit_mode);
41376bd547bSAdrian Chadd         HALASSERT(0);
41476bd547bSAdrian Chadd         break;
41576bd547bSAdrian Chadd     }
41676bd547bSAdrian Chadd 
41776bd547bSAdrian Chadd     return ahp->txpower[rate_index][num_chains-1];
41876bd547bSAdrian Chadd }
41976bd547bSAdrian Chadd 
42076bd547bSAdrian Chadd extern void
ar9300_adjust_reg_txpower_cdd(struct ath_hal * ah,u_int8_t power_per_rate[])42176bd547bSAdrian Chadd ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah,
42276bd547bSAdrian Chadd                       u_int8_t power_per_rate[])
42376bd547bSAdrian Chadd 
42476bd547bSAdrian Chadd {
42576bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
42676bd547bSAdrian Chadd     int16_t twice_array_gain, cdd_power = 0;
42776bd547bSAdrian Chadd     int i;
42876bd547bSAdrian Chadd 
42976bd547bSAdrian Chadd     /*
43076bd547bSAdrian Chadd      *  Adjust the upper limit for CDD factoring in the array gain .
43176bd547bSAdrian Chadd      *  The array gain is the same as TxBF, hence reuse the same defines.
43276bd547bSAdrian Chadd      */
43376bd547bSAdrian Chadd     switch (ahp->ah_tx_chainmask) {
43476bd547bSAdrian Chadd 
43576bd547bSAdrian Chadd     case OSPREY_1_CHAINMASK:
43676bd547bSAdrian Chadd         cdd_power = ahp->upper_limit[0];
43776bd547bSAdrian Chadd         break;
43876bd547bSAdrian Chadd 
43976bd547bSAdrian Chadd     case OSPREY_2LOHI_CHAINMASK:
44076bd547bSAdrian Chadd     case OSPREY_2LOMID_CHAINMASK:
44176bd547bSAdrian Chadd         twice_array_gain =
44276bd547bSAdrian Chadd            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
44376bd547bSAdrian Chadd            -(AR9300_TXBF_2TX_ARRAY_GAIN) :
44476bd547bSAdrian Chadd            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
44576bd547bSAdrian Chadd            (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
44676bd547bSAdrian Chadd         cdd_power = ahp->upper_limit[1] + twice_array_gain;
447*6851341aSAdrian Chadd 
448*6851341aSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: 2 chain; cdd_power=%d", __func__, cdd_power);
44976bd547bSAdrian Chadd         /* Adjust OFDM legacy rates as well */
45076bd547bSAdrian Chadd         for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
45176bd547bSAdrian Chadd             if (power_per_rate[i] > cdd_power) {
45276bd547bSAdrian Chadd                 power_per_rate[i] = cdd_power;
45376bd547bSAdrian Chadd             }
45476bd547bSAdrian Chadd         }
45576bd547bSAdrian Chadd 
45676bd547bSAdrian Chadd         /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 20*/
45776bd547bSAdrian Chadd         for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) {
45876bd547bSAdrian Chadd             if (power_per_rate[i] > cdd_power) {
45976bd547bSAdrian Chadd                 power_per_rate[i] = cdd_power;
46076bd547bSAdrian Chadd             }
46176bd547bSAdrian Chadd         }
46276bd547bSAdrian Chadd 
46376bd547bSAdrian Chadd         /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 40*/
46476bd547bSAdrian Chadd         for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) {
46576bd547bSAdrian Chadd             if (power_per_rate[i] > cdd_power) {
46676bd547bSAdrian Chadd                 power_per_rate[i] = cdd_power;
46776bd547bSAdrian Chadd             }
46876bd547bSAdrian Chadd         }
46976bd547bSAdrian Chadd         break;
47076bd547bSAdrian Chadd 
47176bd547bSAdrian Chadd     case OSPREY_3_CHAINMASK:
47276bd547bSAdrian Chadd         twice_array_gain =
47376bd547bSAdrian Chadd             (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
47476bd547bSAdrian Chadd             -(AR9300_TXBF_3TX_ARRAY_GAIN) :
47576bd547bSAdrian Chadd             ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
47676bd547bSAdrian Chadd             (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
47776bd547bSAdrian Chadd         cdd_power = ahp->upper_limit[2] + twice_array_gain;
478*6851341aSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: 3 chain; cdd_power=%d", __func__, cdd_power);
47976bd547bSAdrian Chadd         /* Adjust OFDM legacy rates as well */
48076bd547bSAdrian Chadd         for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
48176bd547bSAdrian Chadd             if (power_per_rate[i] > cdd_power) {
48276bd547bSAdrian Chadd                 power_per_rate[i] = cdd_power;
48376bd547bSAdrian Chadd             }
48476bd547bSAdrian Chadd         }
48576bd547bSAdrian Chadd         /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */
48676bd547bSAdrian Chadd         for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) {
48776bd547bSAdrian Chadd             if (power_per_rate[i] > cdd_power) {
48876bd547bSAdrian Chadd                 power_per_rate[i] = cdd_power;
48976bd547bSAdrian Chadd             }
49076bd547bSAdrian Chadd         }
49176bd547bSAdrian Chadd 
49276bd547bSAdrian Chadd         /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */
49376bd547bSAdrian Chadd         for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) {
49476bd547bSAdrian Chadd             if (power_per_rate[i] > cdd_power) {
49576bd547bSAdrian Chadd                 power_per_rate[i] = cdd_power;
49676bd547bSAdrian Chadd             }
49776bd547bSAdrian Chadd         }
49876bd547bSAdrian Chadd 
49976bd547bSAdrian Chadd         break;
50076bd547bSAdrian Chadd 
50176bd547bSAdrian Chadd     default:
50276bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
50376bd547bSAdrian Chadd                  __func__, ahp->ah_tx_chainmask);
50476bd547bSAdrian Chadd         break;
50576bd547bSAdrian Chadd     }
50676bd547bSAdrian Chadd 
50776bd547bSAdrian Chadd     return;
50876bd547bSAdrian Chadd }
50976bd547bSAdrian Chadd 
51076bd547bSAdrian Chadd 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)51176bd547bSAdrian Chadd ar9300_init_rate_txpower(struct ath_hal *ah, u_int mode,
512e113789bSAdrian Chadd                       const struct ieee80211_channel *chan,
51376bd547bSAdrian Chadd                       u_int8_t power_per_rate[], u_int8_t chainmask)
51476bd547bSAdrian Chadd {
51576bd547bSAdrian Chadd     const HAL_RATE_TABLE *rt;
516e113789bSAdrian Chadd     HAL_BOOL is40 = IEEE80211_IS_CHAN_HT40(chan);
51776bd547bSAdrian Chadd 
51876bd547bSAdrian Chadd     rt = ar9300_get_rate_table(ah, mode);
51976bd547bSAdrian Chadd     HALASSERT(rt != NULL);
52076bd547bSAdrian Chadd 
52176bd547bSAdrian Chadd     switch (mode) {
52276bd547bSAdrian Chadd     case HAL_MODE_11A:
52376bd547bSAdrian Chadd         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
52476bd547bSAdrian Chadd                               AR9300_11A_RT_OFDM_OFFSET, chainmask);
52576bd547bSAdrian Chadd         break;
52676bd547bSAdrian Chadd     case HAL_MODE_11NA_HT20:
52776bd547bSAdrian Chadd     case HAL_MODE_11NA_HT40PLUS:
52876bd547bSAdrian Chadd     case HAL_MODE_11NA_HT40MINUS:
52976bd547bSAdrian Chadd         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
53076bd547bSAdrian Chadd                               AR9300_11NA_RT_OFDM_OFFSET, chainmask);
53176bd547bSAdrian Chadd         ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
53276bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_SS_OFFSET,
53376bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_DS_OFFSET,
53476bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
53576bd547bSAdrian Chadd         ar9300_init_rate_txpower_stbc(ah, rt, is40,
53676bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_SS_OFFSET,
53776bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_DS_OFFSET,
53876bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
539*6851341aSAdrian Chadd #if 0
54076bd547bSAdrian Chadd         /* For FCC the array gain has to be factored for CDD mode */
541e113789bSAdrian Chadd         if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
54276bd547bSAdrian Chadd             ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
54376bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_SS_OFFSET,
54476bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_DS_OFFSET,
54576bd547bSAdrian Chadd                             AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
54676bd547bSAdrian Chadd         }
547*6851341aSAdrian Chadd #endif
54876bd547bSAdrian Chadd         break;
54976bd547bSAdrian Chadd     case HAL_MODE_11G:
55076bd547bSAdrian Chadd         ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
55176bd547bSAdrian Chadd         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
55276bd547bSAdrian Chadd                               AR9300_11G_RT_OFDM_OFFSET, chainmask);
55376bd547bSAdrian Chadd         break;
55476bd547bSAdrian Chadd     case HAL_MODE_11B:
55576bd547bSAdrian Chadd         ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
55676bd547bSAdrian Chadd         break;
55776bd547bSAdrian Chadd     case HAL_MODE_11NG_HT20:
55876bd547bSAdrian Chadd     case HAL_MODE_11NG_HT40PLUS:
55976bd547bSAdrian Chadd     case HAL_MODE_11NG_HT40MINUS:
56076bd547bSAdrian Chadd         ar9300_init_rate_txpower_cck(ah, rt, power_per_rate,  chainmask);
56176bd547bSAdrian Chadd         ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
56276bd547bSAdrian Chadd                               AR9300_11NG_RT_OFDM_OFFSET, chainmask);
56376bd547bSAdrian Chadd         ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
56476bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_SS_OFFSET,
56576bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_DS_OFFSET,
56676bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
56776bd547bSAdrian Chadd         ar9300_init_rate_txpower_stbc(ah, rt, is40,
56876bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_SS_OFFSET,
56976bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_DS_OFFSET,
57076bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
571*6851341aSAdrian Chadd #if 0
57276bd547bSAdrian Chadd         /* For FCC the array gain needs to be factored for CDD mode */
573e113789bSAdrian Chadd         if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
57476bd547bSAdrian Chadd             ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
57576bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_SS_OFFSET,
57676bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_DS_OFFSET,
57776bd547bSAdrian Chadd                             AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
57876bd547bSAdrian Chadd         }
579*6851341aSAdrian Chadd #endif
58076bd547bSAdrian Chadd         break;
58176bd547bSAdrian Chadd     default:
58276bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
58376bd547bSAdrian Chadd              __func__, mode);
58476bd547bSAdrian Chadd         HALASSERT(0);
58576bd547bSAdrian Chadd         break;
58676bd547bSAdrian Chadd     }
58776bd547bSAdrian Chadd 
58876bd547bSAdrian Chadd }
58976bd547bSAdrian Chadd 
59076bd547bSAdrian Chadd 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)59176bd547bSAdrian Chadd ar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
59276bd547bSAdrian Chadd                          u_int8_t rates_array[], u_int8_t chainmask)
59376bd547bSAdrian Chadd {
59476bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
59576bd547bSAdrian Chadd     /*
59676bd547bSAdrian Chadd      * Pick the lower of the long-preamble txpower, and short-preamble tx power.
59776bd547bSAdrian Chadd      * Unfortunately, the rate table doesn't have separate entries for these!.
59876bd547bSAdrian Chadd      */
59976bd547bSAdrian Chadd     switch (chainmask) {
60076bd547bSAdrian Chadd     case OSPREY_1_CHAINMASK:
60176bd547bSAdrian Chadd         ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
60276bd547bSAdrian Chadd         ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
60376bd547bSAdrian Chadd         ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
60476bd547bSAdrian Chadd                                   rates_array[ALL_TARGET_LEGACY_5S]);
60576bd547bSAdrian Chadd         ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
60676bd547bSAdrian Chadd                                       rates_array[ALL_TARGET_LEGACY_11S]);
60776bd547bSAdrian Chadd         break;
60876bd547bSAdrian Chadd     case OSPREY_2LOHI_CHAINMASK:
60976bd547bSAdrian Chadd     case OSPREY_2LOMID_CHAINMASK:
61076bd547bSAdrian Chadd         ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
61176bd547bSAdrian Chadd         ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
61276bd547bSAdrian Chadd         ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
61376bd547bSAdrian Chadd                                   rates_array[ALL_TARGET_LEGACY_5S]);
61476bd547bSAdrian Chadd         ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
61576bd547bSAdrian Chadd                                   rates_array[ALL_TARGET_LEGACY_11S]);
61676bd547bSAdrian Chadd         break;
61776bd547bSAdrian Chadd     case OSPREY_3_CHAINMASK:
61876bd547bSAdrian Chadd         ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
61976bd547bSAdrian Chadd         ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
62076bd547bSAdrian Chadd         ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
62176bd547bSAdrian Chadd                                    rates_array[ALL_TARGET_LEGACY_5S]);
62276bd547bSAdrian Chadd         ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
62376bd547bSAdrian Chadd                                        rates_array[ALL_TARGET_LEGACY_11S]);
62476bd547bSAdrian Chadd         break;
62576bd547bSAdrian Chadd     default:
62676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
62776bd547bSAdrian Chadd                  __func__, chainmask);
62876bd547bSAdrian Chadd         break;
62976bd547bSAdrian Chadd     }
63076bd547bSAdrian Chadd }
63176bd547bSAdrian Chadd 
63276bd547bSAdrian Chadd 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)63376bd547bSAdrian Chadd ar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
63476bd547bSAdrian Chadd                           u_int8_t rates_array[], int rt_offset,
63576bd547bSAdrian Chadd                           u_int8_t chainmask)
63676bd547bSAdrian Chadd {
63776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
63876bd547bSAdrian Chadd     int16_t twice_array_gain, cdd_power = 0;
63976bd547bSAdrian Chadd     int i, j;
64076bd547bSAdrian Chadd     u_int8_t ofdm_rt_2_pwr_idx[8] =
64176bd547bSAdrian Chadd     {
64276bd547bSAdrian Chadd         ALL_TARGET_LEGACY_6_24,
64376bd547bSAdrian Chadd         ALL_TARGET_LEGACY_6_24,
64476bd547bSAdrian Chadd         ALL_TARGET_LEGACY_6_24,
64576bd547bSAdrian Chadd         ALL_TARGET_LEGACY_6_24,
64676bd547bSAdrian Chadd         ALL_TARGET_LEGACY_6_24,
64776bd547bSAdrian Chadd         ALL_TARGET_LEGACY_36,
64876bd547bSAdrian Chadd         ALL_TARGET_LEGACY_48,
64976bd547bSAdrian Chadd         ALL_TARGET_LEGACY_54,
65076bd547bSAdrian Chadd     };
65176bd547bSAdrian Chadd 
65276bd547bSAdrian Chadd     /*
65376bd547bSAdrian Chadd      *  For FCC adjust the upper limit for CDD factoring in the array gain.
65476bd547bSAdrian Chadd      *  The array gain is the same as TxBF, hence reuse the same defines.
65576bd547bSAdrian Chadd      */
65676bd547bSAdrian Chadd     for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) {
65776bd547bSAdrian Chadd 
65876bd547bSAdrian Chadd         /* Get the correct OFDM rate to Power table Index */
65976bd547bSAdrian Chadd         j = ofdm_rt_2_pwr_idx[i- rt_offset];
66076bd547bSAdrian Chadd 
66176bd547bSAdrian Chadd         switch (chainmask) {
66276bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
66376bd547bSAdrian Chadd             ahp->txpower[i][0] = rates_array[j];
66476bd547bSAdrian Chadd             break;
66576bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
66676bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
66776bd547bSAdrian Chadd             ahp->txpower[i][1] = rates_array[j];
66876bd547bSAdrian Chadd             if (is_reg_dmn_fcc(ahp->reg_dmn)){
66976bd547bSAdrian Chadd                 twice_array_gain = (ahp->twice_antenna_gain >=
67076bd547bSAdrian Chadd                 ahp->twice_antenna_reduction)?
67176bd547bSAdrian Chadd                 -(AR9300_TXBF_2TX_ARRAY_GAIN) :
67276bd547bSAdrian Chadd                 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
67376bd547bSAdrian Chadd                (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
67476bd547bSAdrian Chadd                 cdd_power = ahp->upper_limit[1] + twice_array_gain;
67576bd547bSAdrian Chadd                 if (ahp->txpower[i][1] > cdd_power){
67676bd547bSAdrian Chadd                     ahp->txpower[i][1] = cdd_power;
67776bd547bSAdrian Chadd                 }
67876bd547bSAdrian Chadd             }
67976bd547bSAdrian Chadd             break;
68076bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
68176bd547bSAdrian Chadd             ahp->txpower[i][2] = rates_array[j];
68276bd547bSAdrian Chadd             if (is_reg_dmn_fcc(ahp->reg_dmn)) {
68376bd547bSAdrian Chadd                 twice_array_gain =
68476bd547bSAdrian Chadd                 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
68576bd547bSAdrian Chadd                 -(AR9300_TXBF_3TX_ARRAY_GAIN):
68676bd547bSAdrian Chadd                 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
68776bd547bSAdrian Chadd                 (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
68876bd547bSAdrian Chadd                 cdd_power = ahp->upper_limit[2] + twice_array_gain;
68976bd547bSAdrian Chadd                 if (ahp->txpower[i][2] > cdd_power){
69076bd547bSAdrian Chadd                     ahp->txpower[i][2] = cdd_power;
69176bd547bSAdrian Chadd                 }
69276bd547bSAdrian Chadd             }
69376bd547bSAdrian Chadd             break;
69476bd547bSAdrian Chadd         default:
69576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
69676bd547bSAdrian Chadd                      __func__, chainmask);
69776bd547bSAdrian Chadd             break;
69876bd547bSAdrian Chadd         }
69976bd547bSAdrian Chadd     }
70076bd547bSAdrian Chadd }
70176bd547bSAdrian Chadd 
70276bd547bSAdrian Chadd static  u_int8_t mcs_rate_2_pwr_idx_ht20[24] =
70376bd547bSAdrian Chadd     {
70476bd547bSAdrian Chadd         ALL_TARGET_HT20_0_8_16,
70576bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
70676bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
70776bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
70876bd547bSAdrian Chadd         ALL_TARGET_HT20_4,
70976bd547bSAdrian Chadd         ALL_TARGET_HT20_5,
71076bd547bSAdrian Chadd         ALL_TARGET_HT20_6,
71176bd547bSAdrian Chadd         ALL_TARGET_HT20_7,
71276bd547bSAdrian Chadd         ALL_TARGET_HT20_0_8_16,
71376bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
71476bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
71576bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
71676bd547bSAdrian Chadd         ALL_TARGET_HT20_12,
71776bd547bSAdrian Chadd         ALL_TARGET_HT20_13,
71876bd547bSAdrian Chadd         ALL_TARGET_HT20_14,
71976bd547bSAdrian Chadd         ALL_TARGET_HT20_15,
72076bd547bSAdrian Chadd         ALL_TARGET_HT20_0_8_16,
72176bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
72276bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
72376bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
72476bd547bSAdrian Chadd         ALL_TARGET_HT20_20,
72576bd547bSAdrian Chadd         ALL_TARGET_HT20_21,
72676bd547bSAdrian Chadd         ALL_TARGET_HT20_22,
72776bd547bSAdrian Chadd         ALL_TARGET_HT20_23
72876bd547bSAdrian Chadd     };
72976bd547bSAdrian Chadd 
73076bd547bSAdrian Chadd static   u_int8_t mcs_rate_2_pwr_idx_ht40[24] =
73176bd547bSAdrian Chadd     {
73276bd547bSAdrian Chadd         ALL_TARGET_HT40_0_8_16,
73376bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
73476bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
73576bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
73676bd547bSAdrian Chadd         ALL_TARGET_HT40_4,
73776bd547bSAdrian Chadd         ALL_TARGET_HT40_5,
73876bd547bSAdrian Chadd         ALL_TARGET_HT40_6,
73976bd547bSAdrian Chadd         ALL_TARGET_HT40_7,
74076bd547bSAdrian Chadd         ALL_TARGET_HT40_0_8_16,
74176bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
74276bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
74376bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
74476bd547bSAdrian Chadd         ALL_TARGET_HT40_12,
74576bd547bSAdrian Chadd         ALL_TARGET_HT40_13,
74676bd547bSAdrian Chadd         ALL_TARGET_HT40_14,
74776bd547bSAdrian Chadd         ALL_TARGET_HT40_15,
74876bd547bSAdrian Chadd         ALL_TARGET_HT40_0_8_16,
74976bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
75076bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
75176bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
75276bd547bSAdrian Chadd         ALL_TARGET_HT40_20,
75376bd547bSAdrian Chadd         ALL_TARGET_HT40_21,
75476bd547bSAdrian Chadd         ALL_TARGET_HT40_22,
75576bd547bSAdrian Chadd         ALL_TARGET_HT40_23,
75676bd547bSAdrian Chadd     };
75776bd547bSAdrian Chadd 
75876bd547bSAdrian Chadd 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)75976bd547bSAdrian Chadd ar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
76076bd547bSAdrian Chadd                         HAL_BOOL is40,
76176bd547bSAdrian Chadd                         u_int8_t rates_array[],
76276bd547bSAdrian Chadd                         int rt_ss_offset, int rt_ds_offset,
76376bd547bSAdrian Chadd                         int rt_ts_offset, u_int8_t chainmask)
76476bd547bSAdrian Chadd {
76576bd547bSAdrian Chadd 
76676bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
76776bd547bSAdrian Chadd     int i, j;
76876bd547bSAdrian Chadd     u_int8_t mcs_index = 0;
76976bd547bSAdrian Chadd 
77076bd547bSAdrian Chadd 
77176bd547bSAdrian Chadd     for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
77276bd547bSAdrian Chadd         /* Get the correct MCS rate to Power table Index */
77376bd547bSAdrian Chadd         j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
77476bd547bSAdrian Chadd                           mcs_rate_2_pwr_idx_ht20[mcs_index];
77576bd547bSAdrian Chadd         switch (chainmask) {
77676bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
77776bd547bSAdrian Chadd             ahp->txpower[i][0] = rates_array[j];
77876bd547bSAdrian Chadd             break;
77976bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
78076bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
78176bd547bSAdrian Chadd             ahp->txpower[i][1] = rates_array[j];
78276bd547bSAdrian Chadd             break;
78376bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
78476bd547bSAdrian Chadd             ahp->txpower[i][2] = rates_array[j];
78576bd547bSAdrian Chadd             break;
78676bd547bSAdrian Chadd         default:
78776bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
78876bd547bSAdrian Chadd                      __func__, chainmask);
78976bd547bSAdrian Chadd             break;
79076bd547bSAdrian Chadd         }
79176bd547bSAdrian Chadd         mcs_index++;
79276bd547bSAdrian Chadd     }
79376bd547bSAdrian Chadd 
79476bd547bSAdrian Chadd     for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
79576bd547bSAdrian Chadd         /* Get the correct MCS rate to Power table Index */
79676bd547bSAdrian Chadd         j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
79776bd547bSAdrian Chadd                                        mcs_rate_2_pwr_idx_ht20[mcs_index];
79876bd547bSAdrian Chadd         switch (chainmask) {
79976bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
80076bd547bSAdrian Chadd             ahp->txpower[i][0] = rates_array[j];
80176bd547bSAdrian Chadd             break;
80276bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
80376bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
80476bd547bSAdrian Chadd             ahp->txpower[i][1] = rates_array[j];
80576bd547bSAdrian Chadd             break;
80676bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
80776bd547bSAdrian Chadd             ahp->txpower[i][2] = rates_array[j];
80876bd547bSAdrian Chadd             break;
80976bd547bSAdrian Chadd         default:
81076bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
81176bd547bSAdrian Chadd                          __func__, chainmask);
81276bd547bSAdrian Chadd             break;
81376bd547bSAdrian Chadd         }
81476bd547bSAdrian Chadd         mcs_index++;
81576bd547bSAdrian Chadd     }
81676bd547bSAdrian Chadd 
81776bd547bSAdrian Chadd     for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
81876bd547bSAdrian Chadd         /* Get the correct MCS rate to Power table Index */
81976bd547bSAdrian Chadd         j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
82076bd547bSAdrian Chadd                                   mcs_rate_2_pwr_idx_ht20[mcs_index];
82176bd547bSAdrian Chadd         switch (chainmask) {
82276bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
82376bd547bSAdrian Chadd             ahp->txpower[i][0] = rates_array[j];
82476bd547bSAdrian Chadd             break;
82576bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
82676bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
82776bd547bSAdrian Chadd             ahp->txpower[i][1] = rates_array[j];
82876bd547bSAdrian Chadd             break;
82976bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
83076bd547bSAdrian Chadd             ahp->txpower[i][2] = rates_array[j];
83176bd547bSAdrian Chadd             break;
83276bd547bSAdrian Chadd         default:
83376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
83476bd547bSAdrian Chadd                  __func__, chainmask);
83576bd547bSAdrian Chadd             break;
83676bd547bSAdrian Chadd         }
83776bd547bSAdrian Chadd         mcs_index++;
83876bd547bSAdrian Chadd     }
83976bd547bSAdrian Chadd }
84076bd547bSAdrian Chadd 
84176bd547bSAdrian Chadd 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)84276bd547bSAdrian Chadd ar9300_init_rate_txpower_stbc(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
84376bd547bSAdrian Chadd                         HAL_BOOL is40,
84476bd547bSAdrian Chadd                         int rt_ss_offset, int rt_ds_offset,
84576bd547bSAdrian Chadd                         int rt_ts_offset, u_int8_t chainmask)
84676bd547bSAdrian Chadd {
84776bd547bSAdrian Chadd 
84876bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
84976bd547bSAdrian Chadd     int i;
85076bd547bSAdrian Chadd     int16_t twice_array_gain, stbc_power = 0;
85176bd547bSAdrian Chadd     u_int8_t mcs_index = 0;
85276bd547bSAdrian Chadd 
85376bd547bSAdrian Chadd     /* Upper Limit with STBC */
85476bd547bSAdrian Chadd     switch (chainmask) {
85576bd547bSAdrian Chadd     case OSPREY_1_CHAINMASK:
85676bd547bSAdrian Chadd         stbc_power = ahp->upper_limit[0];
85776bd547bSAdrian Chadd         break;
85876bd547bSAdrian Chadd     case OSPREY_2LOHI_CHAINMASK:
85976bd547bSAdrian Chadd     case OSPREY_2LOMID_CHAINMASK:
86076bd547bSAdrian Chadd         stbc_power = ahp->upper_limit[1];
86176bd547bSAdrian Chadd         break;
86276bd547bSAdrian Chadd     case OSPREY_3_CHAINMASK:
86376bd547bSAdrian Chadd         stbc_power = ahp->upper_limit[2];
86476bd547bSAdrian Chadd         /* Ony FCC requires that we back off with 3 transmit chains */
86576bd547bSAdrian Chadd         if (is_reg_dmn_fcc(ahp->reg_dmn)) {
86676bd547bSAdrian Chadd             twice_array_gain =
86776bd547bSAdrian Chadd                 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
86876bd547bSAdrian Chadd                 -(AR9300_STBC_3TX_ARRAY_GAIN) :
86976bd547bSAdrian Chadd                 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
87076bd547bSAdrian Chadd                 (ahp->twice_antenna_gain + AR9300_STBC_3TX_ARRAY_GAIN)), 0));
87176bd547bSAdrian Chadd             stbc_power = ahp->upper_limit[2] + twice_array_gain;
87276bd547bSAdrian Chadd         }
87376bd547bSAdrian Chadd         break;
87476bd547bSAdrian Chadd 
87576bd547bSAdrian Chadd     default:
87676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
87776bd547bSAdrian Chadd                  __func__, chainmask);
87876bd547bSAdrian Chadd         break;
87976bd547bSAdrian Chadd     }
88076bd547bSAdrian Chadd 
88176bd547bSAdrian Chadd 
88276bd547bSAdrian Chadd     for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
88376bd547bSAdrian Chadd         switch (chainmask) {
88476bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
88576bd547bSAdrian Chadd             ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
88676bd547bSAdrian Chadd             break;
88776bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
88876bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
88976bd547bSAdrian Chadd             ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
89076bd547bSAdrian Chadd             break;
89176bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
89276bd547bSAdrian Chadd             ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
89376bd547bSAdrian Chadd             /* 3 TX/1 stream  STBC gain adjustment */
89476bd547bSAdrian Chadd             if (ahp->txpower_stbc[i][2] > stbc_power){
89576bd547bSAdrian Chadd                 ahp->txpower_stbc[i][2] = stbc_power;
89676bd547bSAdrian Chadd             }
89776bd547bSAdrian Chadd             break;
89876bd547bSAdrian Chadd         default:
89976bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
90076bd547bSAdrian Chadd                      __func__, chainmask);
90176bd547bSAdrian Chadd             break;
90276bd547bSAdrian Chadd         }
90376bd547bSAdrian Chadd         mcs_index++;
90476bd547bSAdrian Chadd     }
90576bd547bSAdrian Chadd 
90676bd547bSAdrian Chadd     for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
90776bd547bSAdrian Chadd         switch (chainmask) {
90876bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
90976bd547bSAdrian Chadd             ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
91076bd547bSAdrian Chadd             break;
91176bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
91276bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
91376bd547bSAdrian Chadd             ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
91476bd547bSAdrian Chadd             break;
91576bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
91676bd547bSAdrian Chadd             ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
91776bd547bSAdrian Chadd             /* 3 TX/2 stream  STBC gain adjustment */
91876bd547bSAdrian Chadd             if (ahp->txpower_stbc[i][2] > stbc_power){
91976bd547bSAdrian Chadd                 ahp->txpower_stbc[i][2] = stbc_power;
92076bd547bSAdrian Chadd 	    }
92176bd547bSAdrian Chadd             break;
92276bd547bSAdrian Chadd         default:
92376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
92476bd547bSAdrian Chadd                      __func__, chainmask);
92576bd547bSAdrian Chadd             break;
92676bd547bSAdrian Chadd         }
92776bd547bSAdrian Chadd         mcs_index++;
92876bd547bSAdrian Chadd     }
92976bd547bSAdrian Chadd 
93076bd547bSAdrian Chadd     for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
93176bd547bSAdrian Chadd         switch (chainmask) {
93276bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
93376bd547bSAdrian Chadd             ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
93476bd547bSAdrian Chadd             break;
93576bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
93676bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
93776bd547bSAdrian Chadd             ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
93876bd547bSAdrian Chadd             break;
93976bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
94076bd547bSAdrian Chadd             ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
94176bd547bSAdrian Chadd             break;
94276bd547bSAdrian Chadd         default:
94376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
94476bd547bSAdrian Chadd                      __func__, chainmask);
94576bd547bSAdrian Chadd             break;
94676bd547bSAdrian Chadd         }
94776bd547bSAdrian Chadd         mcs_index++;
94876bd547bSAdrian Chadd     }
94976bd547bSAdrian Chadd 
95076bd547bSAdrian Chadd     return;
95176bd547bSAdrian Chadd }
95276bd547bSAdrian Chadd 
953*6851341aSAdrian Chadd /*
954*6851341aSAdrian Chadd  * To see why this is disabled, look at ar9300_eeprom.c for FCC/OET 13TR1003.
955*6851341aSAdrian Chadd  */
956*6851341aSAdrian Chadd #if 0
95776bd547bSAdrian Chadd static inline void
95876bd547bSAdrian Chadd ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
95976bd547bSAdrian Chadd                         HAL_BOOL is40,
96076bd547bSAdrian Chadd                         int rt_ss_offset, int rt_ds_offset,
96176bd547bSAdrian Chadd                         int rt_ts_offset, u_int8_t chainmask)
96276bd547bSAdrian Chadd {
96376bd547bSAdrian Chadd 
96476bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
96576bd547bSAdrian Chadd     int i;
96676bd547bSAdrian Chadd     int16_t twice_array_gain, cdd_power = 0;
96776bd547bSAdrian Chadd     u_int8_t mcs_index = 0;
96876bd547bSAdrian Chadd 
96976bd547bSAdrian Chadd     /*
97076bd547bSAdrian Chadd      *  Adjust the upper limit for CDD factoring in the array gain .
97176bd547bSAdrian Chadd      *  The array gain is the same as TxBF, hence reuse the same defines.
97276bd547bSAdrian Chadd      */
97376bd547bSAdrian Chadd     switch (chainmask) {
97476bd547bSAdrian Chadd     case OSPREY_1_CHAINMASK:
97576bd547bSAdrian Chadd         cdd_power = ahp->upper_limit[0];
97676bd547bSAdrian Chadd         break;
97776bd547bSAdrian Chadd 
97876bd547bSAdrian Chadd     case OSPREY_2LOHI_CHAINMASK:
97976bd547bSAdrian Chadd     case OSPREY_2LOMID_CHAINMASK:
98076bd547bSAdrian Chadd         twice_array_gain =
98176bd547bSAdrian Chadd             (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
98276bd547bSAdrian Chadd             -(AR9300_TXBF_2TX_ARRAY_GAIN) :
98376bd547bSAdrian Chadd             ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
98476bd547bSAdrian Chadd             (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
98576bd547bSAdrian Chadd         cdd_power = ahp->upper_limit[1] + twice_array_gain;
98676bd547bSAdrian Chadd         break;
98776bd547bSAdrian Chadd 
98876bd547bSAdrian Chadd     case OSPREY_3_CHAINMASK:
98976bd547bSAdrian Chadd         twice_array_gain =
99076bd547bSAdrian Chadd             (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
99176bd547bSAdrian Chadd             -(AR9300_TXBF_3TX_ARRAY_GAIN) :
99276bd547bSAdrian Chadd             ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
99376bd547bSAdrian Chadd             (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
99476bd547bSAdrian Chadd         cdd_power = ahp->upper_limit[2] + twice_array_gain;
99576bd547bSAdrian Chadd         break;
99676bd547bSAdrian Chadd 
99776bd547bSAdrian Chadd     default:
99876bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
99976bd547bSAdrian Chadd                      __func__, chainmask);
100076bd547bSAdrian Chadd         break;
100176bd547bSAdrian Chadd     }
100276bd547bSAdrian Chadd 
100376bd547bSAdrian Chadd 
100476bd547bSAdrian Chadd     for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
100576bd547bSAdrian Chadd         switch (chainmask) {
100676bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
100776bd547bSAdrian Chadd             break;
100876bd547bSAdrian Chadd 
100976bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
101076bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
101176bd547bSAdrian Chadd             /* 2 TX/1 stream  CDD gain adjustment */
101276bd547bSAdrian Chadd             if (ahp->txpower[i][1] > cdd_power){
101376bd547bSAdrian Chadd                 ahp->txpower[i][1] = cdd_power;
101476bd547bSAdrian Chadd             }
101576bd547bSAdrian Chadd             break;
101676bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
101776bd547bSAdrian Chadd             /* 3 TX/1 stream  CDD gain adjustment */
101876bd547bSAdrian Chadd             if (ahp->txpower[i][2] > cdd_power){
101976bd547bSAdrian Chadd                 ahp->txpower[i][2] = cdd_power;
102076bd547bSAdrian Chadd             }
102176bd547bSAdrian Chadd             break;
102276bd547bSAdrian Chadd         default:
102376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
102476bd547bSAdrian Chadd                      __func__, chainmask);
102576bd547bSAdrian Chadd             break;
102676bd547bSAdrian Chadd         }
102776bd547bSAdrian Chadd         mcs_index++;
102876bd547bSAdrian Chadd     }
102976bd547bSAdrian Chadd 
103076bd547bSAdrian Chadd     for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
103176bd547bSAdrian Chadd         switch (chainmask) {
103276bd547bSAdrian Chadd         case OSPREY_1_CHAINMASK:
103376bd547bSAdrian Chadd         case OSPREY_2LOHI_CHAINMASK:
103476bd547bSAdrian Chadd         case OSPREY_2LOMID_CHAINMASK:
103576bd547bSAdrian Chadd             break;
103676bd547bSAdrian Chadd         case OSPREY_3_CHAINMASK:
103776bd547bSAdrian Chadd         /* 3 TX/2 stream  TxBF gain adjustment */
103876bd547bSAdrian Chadd             if (ahp->txpower[i][2] > cdd_power){
103976bd547bSAdrian Chadd                 ahp->txpower[i][2] = cdd_power;
104076bd547bSAdrian Chadd             }
104176bd547bSAdrian Chadd             break;
104276bd547bSAdrian Chadd         default:
104376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
104476bd547bSAdrian Chadd                  __func__, chainmask);
104576bd547bSAdrian Chadd             break;
104676bd547bSAdrian Chadd         }
104776bd547bSAdrian Chadd         mcs_index++;
104876bd547bSAdrian Chadd     }
104976bd547bSAdrian Chadd 
105076bd547bSAdrian Chadd     return;
105176bd547bSAdrian Chadd 
105276bd547bSAdrian Chadd }
1053*6851341aSAdrian Chadd #endif
105476bd547bSAdrian Chadd 
ar9300_disp_tpc_tables(struct ath_hal * ah)105576bd547bSAdrian Chadd void ar9300_disp_tpc_tables(struct ath_hal *ah)
105676bd547bSAdrian Chadd {
105776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
1058e113789bSAdrian Chadd     const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
105976bd547bSAdrian Chadd     u_int mode = ath_hal_get_curmode(ah, chan);
106076bd547bSAdrian Chadd     const HAL_RATE_TABLE *rt;
106176bd547bSAdrian Chadd     int i, j;
106276bd547bSAdrian Chadd 
106376bd547bSAdrian Chadd     /* Check whether TPC is enabled */
1064e113789bSAdrian Chadd     if (!ah->ah_config.ath_hal_desc_tpc) {
106576bd547bSAdrian Chadd         ath_hal_printf(ah, "\n TPC Register method in use\n");
106676bd547bSAdrian Chadd         return;
106776bd547bSAdrian Chadd     }
106876bd547bSAdrian Chadd 
106976bd547bSAdrian Chadd     rt = ar9300_get_rate_table(ah, mode);
107076bd547bSAdrian Chadd     HALASSERT(rt != NULL);
107176bd547bSAdrian Chadd 
107276bd547bSAdrian Chadd     ath_hal_printf(ah, "\n===TARGET POWER TABLE===\n");
107376bd547bSAdrian Chadd     for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
107476bd547bSAdrian Chadd         for (i = 0; i < rt->rateCount; i++) {
107576bd547bSAdrian Chadd             int16_t txpower[AR9300_MAX_CHAINS];
107676bd547bSAdrian Chadd             txpower[j] = ahp->txpower[i][j];
107776bd547bSAdrian Chadd             ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
107876bd547bSAdrian Chadd                        "Power (%d Chain) [%2d.%1d dBm]\n",
1079e113789bSAdrian Chadd                        i, rt->info[i].rateCode, rt->info[i].rateKbps,
108076bd547bSAdrian Chadd                        j + 1, txpower[j] / 2, txpower[j]%2 * 5);
108176bd547bSAdrian Chadd         }
108276bd547bSAdrian Chadd     }
108376bd547bSAdrian Chadd     ath_hal_printf(ah, "\n");
108476bd547bSAdrian Chadd 
108576bd547bSAdrian Chadd     ath_hal_printf(ah, "\n\n===TARGET POWER TABLE with STBC===\n");
108676bd547bSAdrian Chadd     for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
108776bd547bSAdrian Chadd         for (i = 0; i < rt->rateCount; i++) {
108876bd547bSAdrian Chadd             int16_t txpower[AR9300_MAX_CHAINS];
108976bd547bSAdrian Chadd             txpower[j] = ahp->txpower_stbc[i][j];
109076bd547bSAdrian Chadd 
109176bd547bSAdrian Chadd             /* Do not display invalid configurations */
1092e113789bSAdrian Chadd             if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1093e113789bSAdrian Chadd                 (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1094e113789bSAdrian Chadd                 ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
109576bd547bSAdrian Chadd                 continue;
109676bd547bSAdrian Chadd             }
109776bd547bSAdrian Chadd 
109876bd547bSAdrian Chadd             ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
109976bd547bSAdrian Chadd                        "Power (%d Chain) [%2d.%1d dBm]\n",
1100e113789bSAdrian Chadd                        i, rt->info[i].rateCode , rt->info[i].rateKbps,
110176bd547bSAdrian Chadd                        j + 1, txpower[j] / 2, txpower[j]%2 * 5);
110276bd547bSAdrian Chadd         }
110376bd547bSAdrian Chadd     }
110476bd547bSAdrian Chadd     ath_hal_printf(ah, "\n");
110576bd547bSAdrian Chadd }
110676bd547bSAdrian Chadd 
110776bd547bSAdrian Chadd /*
110876bd547bSAdrian Chadd  * The followings are customer specific APIs for querying power limit.
110976bd547bSAdrian Chadd  * Power limit is based on regulatory domain, chipset, and transmission rate.
111076bd547bSAdrian Chadd  * Here we only consider EEPROM values, no array gain/CTL considered here.
111176bd547bSAdrian Chadd  */
111276bd547bSAdrian Chadd 
111376bd547bSAdrian Chadd struct rate_power_tbl {
111476bd547bSAdrian Chadd     u_int8_t    rateIdx;        /* rate index in the rate table */
111576bd547bSAdrian Chadd     u_int32_t   rateKbps;       /* transfer rate in kbs */
111676bd547bSAdrian Chadd     u_int8_t    rateCode;      /* rate for h/w descriptors */
111776bd547bSAdrian Chadd     u_int8_t    txbf:   1,      /* txbf eligible */
111876bd547bSAdrian Chadd                 stbc:   1,      /* stbc eligible */
111976bd547bSAdrian Chadd                 chain1: 1,      /* one-chain eligible */
112076bd547bSAdrian Chadd                 chain2: 1,      /* two-chain eligible */
112176bd547bSAdrian Chadd                 chain3: 1;      /* three-chain eligible */
112276bd547bSAdrian Chadd     int16_t     txpower[AR9300_MAX_CHAINS];     /* txpower for different chainmasks */
112376bd547bSAdrian Chadd     int16_t     txpower_stbc[AR9300_MAX_CHAINS];
112476bd547bSAdrian Chadd };
112576bd547bSAdrian Chadd 
ar9300_get_tpc_tables(struct ath_hal * ah)112676bd547bSAdrian Chadd u_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah)
112776bd547bSAdrian Chadd {
112876bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
1129e113789bSAdrian Chadd     const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
113076bd547bSAdrian Chadd     u_int mode = ath_hal_get_curmode(ah, chan);
113176bd547bSAdrian Chadd     const HAL_RATE_TABLE *rt;
113276bd547bSAdrian Chadd     u_int8_t *data;
113376bd547bSAdrian Chadd     struct rate_power_tbl *table;
113476bd547bSAdrian Chadd     int i, j;
113576bd547bSAdrian Chadd 
113676bd547bSAdrian Chadd     /* Check whether TPC is enabled */
1137e113789bSAdrian Chadd     if (! ah->ah_config.ath_hal_desc_tpc) {
113876bd547bSAdrian Chadd         ath_hal_printf(ah, "\n TPC Register method in use\n");
113976bd547bSAdrian Chadd         return NULL;
114076bd547bSAdrian Chadd     }
114176bd547bSAdrian Chadd 
1142e113789bSAdrian Chadd     rt = (const HAL_RATE_TABLE *)ar9300_get_rate_table(ah, mode);
114376bd547bSAdrian Chadd     HALASSERT(rt != NULL);
114476bd547bSAdrian Chadd 
1145e113789bSAdrian Chadd     data = (u_int8_t *)ath_hal_malloc(
114676bd547bSAdrian Chadd                        1 + rt->rateCount * sizeof(struct rate_power_tbl));
114776bd547bSAdrian Chadd     if (data == NULL)
114876bd547bSAdrian Chadd         return NULL;
114976bd547bSAdrian Chadd 
115076bd547bSAdrian Chadd     OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl));
115176bd547bSAdrian Chadd     /* store the rate count at the beginning */
115276bd547bSAdrian Chadd     *data = rt->rateCount;
115376bd547bSAdrian Chadd     table = (struct rate_power_tbl *)&data[1];
115476bd547bSAdrian Chadd 
115576bd547bSAdrian Chadd     for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
115676bd547bSAdrian Chadd         for (i = 0; i < rt->rateCount; i++) {
115776bd547bSAdrian Chadd             table[i].rateIdx = i;
1158e113789bSAdrian Chadd             table[i].rateCode = rt->info[i].rateCode;
115976bd547bSAdrian Chadd             table[i].rateKbps = rt->info[i].rateKbps;
116076bd547bSAdrian Chadd             switch (j) {
116176bd547bSAdrian Chadd             case 0:
1162e113789bSAdrian Chadd                 table[i].chain1 = rt->info[i].rateCode <= 0x87 ? 1 : 0;
116376bd547bSAdrian Chadd                 break;
116476bd547bSAdrian Chadd             case 1:
1165e113789bSAdrian Chadd                 table[i].chain2 = rt->info[i].rateCode <= 0x8f ? 1 : 0;
116676bd547bSAdrian Chadd                 break;
116776bd547bSAdrian Chadd             case 2:
116876bd547bSAdrian Chadd                 table[i].chain3 = 1;
116976bd547bSAdrian Chadd                 break;
117076bd547bSAdrian Chadd             default:
117176bd547bSAdrian Chadd                 break;
117276bd547bSAdrian Chadd             }
117376bd547bSAdrian Chadd             if ((j == 0 && table[i].chain1) ||
117476bd547bSAdrian Chadd                 (j == 1 && table[i].chain2) ||
117576bd547bSAdrian Chadd                 (j == 2 && table[i].chain3))
117676bd547bSAdrian Chadd                 table[i].txpower[j] = ahp->txpower[i][j];
117776bd547bSAdrian Chadd         }
117876bd547bSAdrian Chadd     }
117976bd547bSAdrian Chadd 
118076bd547bSAdrian Chadd     for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
118176bd547bSAdrian Chadd         for (i = 0; i < rt->rateCount; i++) {
118276bd547bSAdrian Chadd             /* Do not display invalid configurations */
1183e113789bSAdrian Chadd             if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1184e113789bSAdrian Chadd                 (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1185e113789bSAdrian Chadd                 ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
118676bd547bSAdrian Chadd                 continue;
118776bd547bSAdrian Chadd             }
118876bd547bSAdrian Chadd 
118976bd547bSAdrian Chadd             table[i].stbc = 1;
119076bd547bSAdrian Chadd             table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j];
119176bd547bSAdrian Chadd         }
119276bd547bSAdrian Chadd     }
119376bd547bSAdrian Chadd 
119476bd547bSAdrian Chadd     return data;
119576bd547bSAdrian Chadd     /* the caller is responsible to free data */
119676bd547bSAdrian Chadd }
119776bd547bSAdrian Chadd 
119876bd547bSAdrian Chadd 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)119976bd547bSAdrian Chadd ath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq,
120076bd547bSAdrian Chadd                                         int8_t *max_rate_power, int8_t *min_rate_power)
120176bd547bSAdrian Chadd {
120276bd547bSAdrian Chadd     /*
120376bd547bSAdrian Chadd      * Used for AR9300 series chip only
120476bd547bSAdrian Chadd      */
1205e113789bSAdrian Chadd     if (ah->ah_magic == AR9300_MAGIC) {
120676bd547bSAdrian Chadd         u_int8_t target_rate_power_limit_val_t2[ar9300_rate_size];
120776bd547bSAdrian Chadd         int i;
120876bd547bSAdrian Chadd 
120976bd547bSAdrian Chadd         *max_rate_power = 0;
121076bd547bSAdrian Chadd         *min_rate_power = AR9300_MAX_RATE_POWER;
121176bd547bSAdrian Chadd 
121276bd547bSAdrian Chadd         ar9300_set_target_power_from_eeprom(ah, freq, target_rate_power_limit_val_t2);
121376bd547bSAdrian Chadd 
121476bd547bSAdrian Chadd         for (i=0; i<ar9300_rate_size; i++) {
121576bd547bSAdrian Chadd             if (target_rate_power_limit_val_t2[i] > *max_rate_power)
121676bd547bSAdrian Chadd                 *max_rate_power = target_rate_power_limit_val_t2[i];
121776bd547bSAdrian Chadd             if (target_rate_power_limit_val_t2[i] < *min_rate_power)
121876bd547bSAdrian Chadd                 *min_rate_power = target_rate_power_limit_val_t2[i];
121976bd547bSAdrian Chadd         }
122076bd547bSAdrian Chadd     } else {
122176bd547bSAdrian Chadd         *max_rate_power = 0;
122276bd547bSAdrian Chadd         *min_rate_power = 0;
122376bd547bSAdrian Chadd     }
122476bd547bSAdrian Chadd 
122576bd547bSAdrian Chadd     return HAL_OK;
122676bd547bSAdrian Chadd }
1227