1250003Sadrian/*
2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc.
3250003Sadrian *
4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any
5250003Sadrian * purpose with or without fee is hereby granted, provided that the above
6250003Sadrian * copyright notice and this permission notice appear in all copies.
7250003Sadrian *
8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14250003Sadrian * PERFORMANCE OF THIS SOFTWARE.
15250003Sadrian */
16250003Sadrian
17250003Sadrian#include "opt_ah.h"
18250003Sadrian
19250003Sadrian#include "ah.h"
20250003Sadrian#include "ah_internal.h"
21250003Sadrian
22250003Sadrian#include "ar9300/ar9300.h"
23250003Sadrian
24250003Sadrian/* shorthands to compact tables for readability */
25250003Sadrian#define    OFDM    IEEE80211_T_OFDM
26250003Sadrian#define    CCK    IEEE80211_T_CCK
27250003Sadrian#define    TURBO    IEEE80211_T_TURBO
28250003Sadrian#define    XR    ATHEROS_T_XR
29250003Sadrian#define HT      IEEE80211_T_HT
30250003Sadrian
31250003Sadrian#define AR9300_NUM_OFDM_RATES   8
32250003Sadrian#define AR9300_NUM_HT_SS_RATES  8
33250003Sadrian#define AR9300_NUM_HT_DS_RATES  8
34250003Sadrian#define AR9300_NUM_HT_TS_RATES  8
35250003Sadrian
36250003Sadrian/* Array Gain defined for TxBF */
37250003Sadrian#define AR9300_TXBF_2TX_ARRAY_GAIN  6  /* 2TX/SS 3 */
38250003Sadrian#define AR9300_TXBF_3TX_ARRAY_GAIN  10 /* 3TX/SS or 3TX/DS 4.8 */
39250003Sadrian#define AR9300_STBC_3TX_ARRAY_GAIN  10 /* 3TX/SS or 3TX/DS 4.8 */
40250003Sadrian
41250003Sadrian/* MCS RATE CODES - first and last */
42250003Sadrian#define AR9300_MCS0_RATE_CODE   0x80
43250003Sadrian#define AR9300_MCS23_RATE_CODE  0x97
44250003Sadrian
45250003Sadrianstatic inline void ar9300_init_rate_txpower_cck(struct ath_hal *ah,
46250003Sadrian       const HAL_RATE_TABLE *rt, u_int8_t rates_array[], u_int8_t chainmask);
47250003Sadrianstatic inline void ar9300_init_rate_txpower_ofdm(struct ath_hal* ah,
48250003Sadrian       const HAL_RATE_TABLE *rt, u_int8_t rates_array[], int rt_offset,
49250003Sadrian       u_int8_t chainmask);
50250003Sadrianstatic inline void ar9300_init_rate_txpower_ht(struct ath_hal *ah,
51250003Sadrian       const HAL_RATE_TABLE *rt, HAL_BOOL is40, u_int8_t rates_array[],
52250003Sadrian       int rt_ss_offset, int rt_ds_offset,
53250003Sadrian       int rt_ts_offset, u_int8_t chainmask);
54250003Sadrianstatic inline void ar9300_init_rate_txpower_stbc(struct ath_hal *ah,
55250003Sadrian       const HAL_RATE_TABLE *rt, HAL_BOOL is40,
56250003Sadrian       int rt_ss_offset, int rt_ds_offset,
57250003Sadrian       int rt_ts_offset, u_int8_t chainmask);
58250003Sadrianstatic inline void ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah,
59250003Sadrian       const HAL_RATE_TABLE *rt, HAL_BOOL is40,
60250003Sadrian       int rt_ss_offset, int rt_ds_offset,
61250003Sadrian       int rt_ts_offset, u_int8_t chainmask);
62250003Sadrian
63250003Sadrian#define AR9300_11A_RT_OFDM_OFFSET    0
64250003SadrianHAL_RATE_TABLE ar9300_11a_table = {
65250003Sadrian    8,  /* number of rates */
66250003Sadrian    { 0 },
67250003Sadrian    {
68250003Sadrian/*                                                  short            ctrl */
69250003Sadrian/*             valid                 rate_code Preamble    dot11Rate Rate */
70250003Sadrian/*   6 Mb */ {  AH_TRUE, OFDM,    6000,     0x0b,    0x00, (0x80 | 12),   0 },
71250003Sadrian/*   9 Mb */ {  AH_TRUE, OFDM,    9000,     0x0f,    0x00,          18,   0 },
72250003Sadrian/*  12 Mb */ {  AH_TRUE, OFDM,   12000,     0x0a,    0x00, (0x80 | 24),   2 },
73250003Sadrian/*  18 Mb */ {  AH_TRUE, OFDM,   18000,     0x0e,    0x00,          36,   2 },
74250003Sadrian/*  24 Mb */ {  AH_TRUE, OFDM,   24000,     0x09,    0x00, (0x80 | 48),   4 },
75250003Sadrian/*  36 Mb */ {  AH_TRUE, OFDM,   36000,     0x0d,    0x00,          72,   4 },
76250003Sadrian/*  48 Mb */ {  AH_TRUE, OFDM,   48000,     0x08,    0x00,          96,   4 },
77250003Sadrian/*  54 Mb */ {  AH_TRUE, OFDM,   54000,     0x0c,    0x00,         108,   4 },
78250003Sadrian    },
79250003Sadrian};
80250003Sadrian
81250003SadrianHAL_RATE_TABLE ar9300_11a_half_table = {
82250003Sadrian    8,  /* number of rates */
83250003Sadrian    { 0 },
84250003Sadrian    {
85250003Sadrian/*                                                  short            ctrl */
86250003Sadrian/*             valid                 rate_code Preamble    dot11Rate Rate */
87250003Sadrian/*   6 Mb */ {  AH_TRUE, OFDM,    3000,     0x0b,    0x00, (0x80 |  6),   0 },
88250003Sadrian/*   9 Mb */ {  AH_TRUE, OFDM,    4500,     0x0f,    0x00,           9,   0 },
89250003Sadrian/*  12 Mb */ {  AH_TRUE, OFDM,    6000,     0x0a,    0x00, (0x80 | 12),   2 },
90250003Sadrian/*  18 Mb */ {  AH_TRUE, OFDM,    9000,     0x0e,    0x00,          18,   2 },
91250003Sadrian/*  24 Mb */ {  AH_TRUE, OFDM,   12000,     0x09,    0x00, (0x80 | 24),   4 },
92250003Sadrian/*  36 Mb */ {  AH_TRUE, OFDM,   18000,     0x0d,    0x00,          36,   4 },
93250003Sadrian/*  48 Mb */ {  AH_TRUE, OFDM,   24000,     0x08,    0x00,          48,   4 },
94250003Sadrian/*  54 Mb */ {  AH_TRUE, OFDM,   27000,     0x0c,    0x00,          54,   4 },
95250003Sadrian    },
96250003Sadrian};
97250003Sadrian
98250003SadrianHAL_RATE_TABLE ar9300_11a_quarter_table = {
99250003Sadrian    8,  /* number of rates */
100250003Sadrian    { 0 },
101250003Sadrian    {
102250003Sadrian/*                                                  short           ctrl */
103250003Sadrian/*            valid                 rate_code Preamble    dot11Rate Rate */
104250003Sadrian/*  6 Mb */ {  AH_TRUE, OFDM,    1500,     0x0b,    0x00, (0x80 |  3),   0 },
105250003Sadrian/*  9 Mb */ {  AH_TRUE, OFDM,    2250,     0x0f,    0x00,          4 ,   0 },
106250003Sadrian/* 12 Mb */ {  AH_TRUE, OFDM,    3000,     0x0a,    0x00, (0x80 |  6),   2 },
107250003Sadrian/* 18 Mb */ {  AH_TRUE, OFDM,    4500,     0x0e,    0x00,           9,   2 },
108250003Sadrian/* 24 Mb */ {  AH_TRUE, OFDM,    6000,     0x09,    0x00, (0x80 | 12),   4 },
109250003Sadrian/* 36 Mb */ {  AH_TRUE, OFDM,    9000,     0x0d,    0x00,          18,   4 },
110250003Sadrian/* 48 Mb */ {  AH_TRUE, OFDM,   12000,     0x08,    0x00,          24,   4 },
111250003Sadrian/* 54 Mb */ {  AH_TRUE, OFDM,   13500,     0x0c,    0x00,          27,   4 },
112250003Sadrian    },
113250003Sadrian};
114250003Sadrian
115250003SadrianHAL_RATE_TABLE ar9300_turbo_table = {
116250003Sadrian    8,  /* number of rates */
117250003Sadrian    { 0 },
118250003Sadrian    {
119250003Sadrian/*                                                 short            ctrl */
120250003Sadrian/*             valid                rate_code Preamble    dot11Rate Rate */
121250003Sadrian/*   6 Mb */ {  AH_TRUE, TURBO,   6000,    0x0b,    0x00, (0x80 | 12),   0 },
122250003Sadrian/*   9 Mb */ {  AH_TRUE, TURBO,   9000,    0x0f,    0x00,          18,   0 },
123250003Sadrian/*  12 Mb */ {  AH_TRUE, TURBO,  12000,    0x0a,    0x00, (0x80 | 24),   2 },
124250003Sadrian/*  18 Mb */ {  AH_TRUE, TURBO,  18000,    0x0e,    0x00,          36,   2 },
125250003Sadrian/*  24 Mb */ {  AH_TRUE, TURBO,  24000,    0x09,    0x00, (0x80 | 48),   4 },
126250003Sadrian/*  36 Mb */ {  AH_TRUE, TURBO,  36000,    0x0d,    0x00,          72,   4 },
127250003Sadrian/*  48 Mb */ {  AH_TRUE, TURBO,  48000,    0x08,    0x00,          96,   4 },
128250003Sadrian/*  54 Mb */ {  AH_TRUE, TURBO,  54000,    0x0c,    0x00,         108,   4 },
129250003Sadrian    },
130250003Sadrian};
131250003Sadrian
132250003SadrianHAL_RATE_TABLE ar9300_11b_table = {
133250003Sadrian    4,  /* number of rates */
134250003Sadrian    { 0 },
135250003Sadrian    {
136250003Sadrian/*                                                 short            ctrl */
137250003Sadrian/*             valid                rate_code Preamble    dot11Rate Rate */
138250003Sadrian/*   1 Mb */ {  AH_TRUE,  CCK,    1000,    0x1b,    0x00, (0x80 |  2),   0 },
139250003Sadrian/*   2 Mb */ {  AH_TRUE,  CCK,    2000,    0x1a,    0x04, (0x80 |  4),   1 },
140250003Sadrian/* 5.5 Mb */ {  AH_TRUE,  CCK,    5500,    0x19,    0x04, (0x80 | 11),   1 },
141250003Sadrian/*  11 Mb */ {  AH_TRUE,  CCK,   11000,    0x18,    0x04, (0x80 | 22),   1 },
142250003Sadrian    },
143250003Sadrian};
144250003Sadrian
145250003Sadrian
146250003Sadrian/* Venice TODO: round_up_rate() is broken when the rate table does not represent
147250003Sadrian * rates in increasing order  e.g.  5.5, 11, 6, 9.
148250003Sadrian * An average rate of 6 Mbps will currently map to 11 Mbps.
149250003Sadrian */
150250003Sadrian#define AR9300_11G_RT_OFDM_OFFSET    4
151250003SadrianHAL_RATE_TABLE ar9300_11g_table = {
152250003Sadrian    12,  /* number of rates */
153250003Sadrian    { 0 },
154250003Sadrian    {
155250003Sadrian/*                                                 short            ctrl */
156250003Sadrian/*             valid                rate_code Preamble    dot11Rate Rate */
157250003Sadrian/*   1 Mb */ {  AH_TRUE, CCK,     1000,    0x1b,    0x00, (0x80 |  2),   0 },
158250003Sadrian/*   2 Mb */ {  AH_TRUE, CCK,     2000,    0x1a,    0x04, (0x80 |  4),   1 },
159250003Sadrian/* 5.5 Mb */ {  AH_TRUE, CCK,     5500,    0x19,    0x04, (0x80 | 11),   2 },
160250003Sadrian/*  11 Mb */ {  AH_TRUE, CCK,    11000,    0x18,    0x04, (0x80 | 22),   3 },
161250003Sadrian/* Hardware workaround - remove rates 6, 9 from rate ctrl */
162250008Sadrian/*   6 Mb */ {  AH_TRUE, OFDM,    6000,    0x0b,    0x00,          12,   4 },
163250008Sadrian/*   9 Mb */ {  AH_TRUE, OFDM,    9000,    0x0f,    0x00,          18,   4 },
164250003Sadrian/*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00,          24,   6 },
165250003Sadrian/*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   6 },
166250003Sadrian/*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00,          48,   8 },
167250003Sadrian/*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   8 },
168250003Sadrian/*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   8 },
169250003Sadrian/*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   8 },
170250003Sadrian    },
171250003Sadrian};
172250003Sadrian
173250008Sadrian#if 0
174250003SadrianHAL_RATE_TABLE ar9300_xr_table = {
175250003Sadrian    13,        /* number of rates */
176250003Sadrian    { 0 },
177250003Sadrian    {
178250003Sadrian/*                                                 short     ctrl */
179250003Sadrian/*            valid          rate_code Preamble    dot11Rate Rate */
180250003Sadrian/* 0.25 Mb */ {AH_TRUE,   XR,   250, 0x03,   0x00, (0x80 |  1),   0, 612, 612 },
181250003Sadrian/*  0.5 Mb */ {AH_TRUE,   XR,   500, 0x07,   0x00, (0x80 |  1),   0, 457, 457 },
182250003Sadrian/*    1 Mb */ {AH_TRUE,   XR,  1000, 0x02,   0x00, (0x80 |  2),   1, 228, 228 },
183250003Sadrian/*    2 Mb */ {AH_TRUE,   XR,  2000, 0x06,   0x00, (0x80 |  4),   2, 160, 160 },
184250003Sadrian/*    3 Mb */ {AH_TRUE,   XR,  3000, 0x01,   0x00, (0x80 |  6),   3, 140, 140 },
185250003Sadrian/*    6 Mb */ {AH_TRUE, OFDM,  6000, 0x0b,   0x00, (0x80 | 12),   4, 60,  60  },
186250003Sadrian/*    9 Mb */ {AH_TRUE, OFDM,  9000, 0x0f,   0x00,          18,   4, 60,  60  },
187250003Sadrian/*   12 Mb */ {AH_TRUE, OFDM, 12000, 0x0a,   0x00, (0x80 | 24),   6, 48,  48  },
188250003Sadrian/*   18 Mb */ {AH_TRUE, OFDM, 18000, 0x0e,   0x00,          36,   6, 48,  48  },
189250003Sadrian/*   24 Mb */ {AH_TRUE, OFDM, 24000, 0x09,   0x00,          48,   8, 44,  44  },
190250003Sadrian/*   36 Mb */ {AH_TRUE, OFDM, 36000, 0x0d,   0x00,          72,   8, 44,  44  },
191250003Sadrian/*   48 Mb */ {AH_TRUE, OFDM, 48000, 0x08,   0x00,          96,   8, 44,  44  },
192250003Sadrian/*   54 Mb */ {AH_TRUE, OFDM, 54000, 0x0c,   0x00,         108,   8, 44,  44  },
193250003Sadrian    },
194250003Sadrian};
195250008Sadrian#endif
196250003Sadrian
197250003Sadrian#define AR9300_11NG_RT_OFDM_OFFSET       4
198250003Sadrian#define AR9300_11NG_RT_HT_SS_OFFSET      12
199250003Sadrian#define AR9300_11NG_RT_HT_DS_OFFSET      20
200250003Sadrian#define AR9300_11NG_RT_HT_TS_OFFSET      28
201250003SadrianHAL_RATE_TABLE ar9300_11ng_table = {
202250003Sadrian
203250003Sadrian    36,  /* number of rates */
204250003Sadrian    { 0 },
205250003Sadrian    {
206250003Sadrian/*                                                 short            ctrl */
207250003Sadrian/*             valid                rate_code Preamble    dot11Rate Rate */
208250003Sadrian/*   1 Mb */ {  AH_TRUE, CCK,     1000,    0x1b,    0x00, (0x80 |  2),   0 },
209250003Sadrian/*   2 Mb */ {  AH_TRUE, CCK,     2000,    0x1a,    0x04, (0x80 |  4),   1 },
210250003Sadrian/* 5.5 Mb */ {  AH_TRUE, CCK,     5500,    0x19,    0x04, (0x80 | 11),   2 },
211250003Sadrian/*  11 Mb */ {  AH_TRUE, CCK,    11000,    0x18,    0x04, (0x80 | 22),   3 },
212250003Sadrian/* Hardware workaround - remove rates 6, 9 from rate ctrl */
213250008Sadrian/*   6 Mb */ {  AH_FALSE, OFDM,    6000,    0x0b,    0x00,          12,   4 },
214250008Sadrian/*   9 Mb */ {  AH_FALSE, OFDM,    9000,    0x0f,    0x00,          18,   4 },
215250003Sadrian/*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00,          24,   6 },
216250003Sadrian/*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   6 },
217250003Sadrian/*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00,          48,   8 },
218250003Sadrian/*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   8 },
219250003Sadrian/*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   8 },
220250003Sadrian/*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   8 },
221250003Sadrian/*--- HT SS rates ---*/
222250003Sadrian/* 6.5 Mb */ {  AH_TRUE, HT,      6500,    0x80,    0x00,           0,   4 },
223250003Sadrian/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x81,    0x00,           1,   6 },
224250003Sadrian/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x82,    0x00,           2,   6 },
225250003Sadrian/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x83,    0x00,           3,   8 },
226250003Sadrian/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x84,    0x00,           4,   8 },
227250003Sadrian/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x85,    0x00,           5,   8 },
228250003Sadrian/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x86,    0x00,           6,   8 },
229250003Sadrian/*  65 Mb */ {  AH_TRUE, HT,     65000,    0x87,    0x00,           7,   8 },
230250003Sadrian/*--- HT DS rates ---*/
231250003Sadrian/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x88,    0x00,           8,   4 },
232250003Sadrian/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x89,    0x00,           9,   6 },
233250003Sadrian/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x8a,    0x00,          10,   6 },
234250003Sadrian/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x8b,    0x00,          11,   8 },
235250003Sadrian/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x8c,    0x00,          12,   8 },
236250003Sadrian/* 104 Mb */ {  AH_TRUE, HT,    104000,    0x8d,    0x00,          13,   8 },
237250003Sadrian/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x8e,    0x00,          14,   8 },
238250003Sadrian/* 130 Mb */ {  AH_TRUE, HT,    130000,    0x8f,    0x00,          15,   8 },
239250003Sadrian/*--- HT TS rates ---*/
240250003Sadrian/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x90,    0x00,          16,   4 },
241250003Sadrian/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x91,    0x00,          17,   6 },
242250003Sadrian/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x92,    0x00,          18,   6 },
243250003Sadrian/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x93,    0x00,          19,   8 },
244250003Sadrian/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x94,    0x00,          20,   8 },
245250003Sadrian/* 156 Mb */ {  AH_TRUE, HT,    156000,    0x95,    0x00,          21,   8 },
246250003Sadrian/*175.5Mb */ {  AH_TRUE, HT,    175500,    0x96,    0x00,          22,   8 },
247250003Sadrian/* 195 Mb */ {  AH_TRUE, HT,    195000,    0x97,    0x00,          23,   8 },
248250003Sadrian    },
249250003Sadrian};
250250003Sadrian
251250003Sadrian#define AR9300_11NA_RT_OFDM_OFFSET       0
252250003Sadrian#define AR9300_11NA_RT_HT_SS_OFFSET      8
253250003Sadrian#define AR9300_11NA_RT_HT_DS_OFFSET      16
254250003Sadrian#define AR9300_11NA_RT_HT_TS_OFFSET      24
255250003Sadrianstatic HAL_RATE_TABLE ar9300_11na_table = {
256250003Sadrian
257250003Sadrian    32,  /* number of rates */
258250003Sadrian    { 0 },
259250003Sadrian    {
260250003Sadrian/*                                                 short            ctrl */
261250003Sadrian/*             valid                rate_code Preamble    dot11Rate Rate */
262250003Sadrian/*   6 Mb */ {  AH_TRUE, OFDM,    6000,    0x0b,    0x00, (0x80 | 12),   0 },
263250003Sadrian/*   9 Mb */ {  AH_TRUE, OFDM,    9000,    0x0f,    0x00,          18,   0 },
264250003Sadrian/*  12 Mb */ {  AH_TRUE, OFDM,   12000,    0x0a,    0x00, (0x80 | 24),   2 },
265250003Sadrian/*  18 Mb */ {  AH_TRUE, OFDM,   18000,    0x0e,    0x00,          36,   2 },
266250003Sadrian/*  24 Mb */ {  AH_TRUE, OFDM,   24000,    0x09,    0x00, (0x80 | 48),   4 },
267250003Sadrian/*  36 Mb */ {  AH_TRUE, OFDM,   36000,    0x0d,    0x00,          72,   4 },
268250003Sadrian/*  48 Mb */ {  AH_TRUE, OFDM,   48000,    0x08,    0x00,          96,   4 },
269250003Sadrian/*  54 Mb */ {  AH_TRUE, OFDM,   54000,    0x0c,    0x00,         108,   4 },
270250003Sadrian/*--- HT SS rates ---*/
271250003Sadrian/* 6.5 Mb */ {  AH_TRUE, HT,      6500,    0x80,    0x00,           0,   0 },
272250003Sadrian/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x81,    0x00,           1,   2 },
273250003Sadrian/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x82,    0x00,           2,   2 },
274250003Sadrian/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x83,    0x00,           3,   4 },
275250003Sadrian/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x84,    0x00,           4,   4 },
276250003Sadrian/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x85,    0x00,           5,   4 },
277250003Sadrian/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x86,    0x00,           6,   4 },
278250003Sadrian/*  65 Mb */ {  AH_TRUE, HT,     65000,    0x87,    0x00,           7,   4 },
279250003Sadrian/*--- HT DS rates ---*/
280250003Sadrian/*  13 Mb */ {  AH_TRUE, HT,     13000,    0x88,    0x00,           8,   0 },
281250003Sadrian/*  26 Mb */ {  AH_TRUE, HT,     26000,    0x89,    0x00,           9,   2 },
282250003Sadrian/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x8a,    0x00,          10,   2 },
283250003Sadrian/*  52 Mb */ {  AH_TRUE, HT,     52000,    0x8b,    0x00,          11,   4 },
284250003Sadrian/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x8c,    0x00,          12,   4 },
285250003Sadrian/* 104 Mb */ {  AH_TRUE, HT,    104000,    0x8d,    0x00,          13,   4 },
286250003Sadrian/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x8e,    0x00,          14,   4 },
287250003Sadrian/* 130 Mb */ {  AH_TRUE, HT,    130000,    0x8f,    0x00,          15,   4 },
288250003Sadrian/*--- HT TS rates ---*/
289250003Sadrian/*19.5 Mb */ {  AH_TRUE, HT,     19500,    0x90,    0x00,          16,   0 },
290250003Sadrian/*  39 Mb */ {  AH_TRUE, HT,     39000,    0x91,    0x00,          17,   2 },
291250003Sadrian/*58.5 Mb */ {  AH_TRUE, HT,     58500,    0x92,    0x00,          18,   2 },
292250003Sadrian/*  78 Mb */ {  AH_TRUE, HT,     78000,    0x93,    0x00,          19,   4 },
293250003Sadrian/* 117 Mb */ {  AH_TRUE, HT,    117000,    0x94,    0x00,          20,   4 },
294250003Sadrian/* 156 Mb */ {  AH_TRUE, HT,    156000,    0x95,    0x00,          21,   4 },
295250003Sadrian/*175.5Mb */ {  AH_TRUE, HT,    175500,    0x96,    0x00,          22,   4 },
296250003Sadrian/* 195 Mb */ {  AH_TRUE, HT,    195000,    0x97,    0x00,          23,   4 },
297250003Sadrian    },
298250003Sadrian};
299250003Sadrian
300250003Sadrian#undef    OFDM
301250003Sadrian#undef    CCK
302250003Sadrian#undef    TURBO
303250003Sadrian#undef    XR
304250003Sadrian#undef    HT
305250003Sadrian#undef    HT_HGI
306250003Sadrian
307250003Sadrianconst HAL_RATE_TABLE *
308250003Sadrianar9300_get_rate_table(struct ath_hal *ah, u_int mode)
309250003Sadrian{
310250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
311250003Sadrian    HAL_CAPABILITIES *p_cap = &ahpriv->ah_caps;
312250003Sadrian    HAL_RATE_TABLE *rt;
313250003Sadrian
314250003Sadrian    switch (mode) {
315250003Sadrian    case HAL_MODE_11A:
316250003Sadrian        rt = &ar9300_11a_table;
317250003Sadrian        break;
318250003Sadrian    case HAL_MODE_11A_HALF_RATE:
319250008Sadrian        if (p_cap->halChanHalfRate) {
320250003Sadrian            rt = &ar9300_11a_half_table;
321250003Sadrian            break;
322250003Sadrian        }
323250003Sadrian        return AH_NULL;
324250003Sadrian    case HAL_MODE_11A_QUARTER_RATE:
325250008Sadrian        if (p_cap->halChanQuarterRate) {
326250003Sadrian            rt = &ar9300_11a_quarter_table;
327250003Sadrian            break;
328250003Sadrian        }
329250003Sadrian        return AH_NULL;
330250003Sadrian    case HAL_MODE_11B:
331250003Sadrian        rt = &ar9300_11b_table;
332250003Sadrian        break;
333250003Sadrian    case HAL_MODE_11G:
334250003Sadrian        rt =  &ar9300_11g_table;
335250003Sadrian        break;
336250003Sadrian    case HAL_MODE_TURBO:
337250003Sadrian    case HAL_MODE_108G:
338250003Sadrian        rt =  &ar9300_turbo_table;
339250003Sadrian        break;
340250008Sadrian#if 0
341250003Sadrian    case HAL_MODE_XR:
342250003Sadrian        rt = &ar9300_xr_table;
343250003Sadrian        break;
344250008Sadrian#endif
345250003Sadrian    case HAL_MODE_11NG_HT20:
346250003Sadrian    case HAL_MODE_11NG_HT40PLUS:
347250003Sadrian    case HAL_MODE_11NG_HT40MINUS:
348250003Sadrian        rt = &ar9300_11ng_table;
349250003Sadrian        break;
350250003Sadrian    case HAL_MODE_11NA_HT20:
351250003Sadrian    case HAL_MODE_11NA_HT40PLUS:
352250003Sadrian    case HAL_MODE_11NA_HT40MINUS:
353250003Sadrian        rt = &ar9300_11na_table;
354250003Sadrian        break;
355250003Sadrian    default:
356250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CHANNEL,
357250003Sadrian            "%s: invalid mode 0x%x\n", __func__, mode);
358250003Sadrian        return AH_NULL;
359250003Sadrian    }
360250003Sadrian    ath_hal_setupratetable(ah, rt);
361250003Sadrian    return rt;
362250003Sadrian}
363250003Sadrian
364250003Sadrianstatic HAL_BOOL
365250003Sadrianar9300_invalid_stbc_cfg(int tx_chains, u_int8_t rate_code)
366250003Sadrian{
367250003Sadrian    switch (tx_chains) {
368250003Sadrian    case 0: /* Single Chain */
369250003Sadrian        return AH_TRUE;
370250003Sadrian
371250003Sadrian    case 1: /* 2 Chains */
372250003Sadrian        if ((rate_code < 0x80) || (rate_code > 0x87)) {
373250003Sadrian            return AH_TRUE;
374250003Sadrian        } else {
375250003Sadrian            return AH_FALSE;
376250003Sadrian        }
377250003Sadrian
378250003Sadrian    case 2: /* 3 Chains */
379250003Sadrian        if ((rate_code < 0x80) || (rate_code > 0x87)) {
380250003Sadrian            return AH_TRUE;
381250003Sadrian        } else {
382250003Sadrian            return AH_FALSE;
383250003Sadrian        }
384250003Sadrian
385250003Sadrian    default:
386250003Sadrian        HALASSERT(0);
387250003Sadrian        break;
388250003Sadrian    }
389250003Sadrian
390250003Sadrian    return AH_TRUE;
391250003Sadrian}
392250003Sadrian
393250003Sadrianint16_t
394250003Sadrianar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index,
395250003Sadrian                     u_int8_t chainmask, u_int8_t xmit_mode)
396250003Sadrian{
397250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
398250003Sadrian    int num_chains = ar9300_get_ntxchains(chainmask);
399250003Sadrian
400250003Sadrian    switch (xmit_mode) {
401250003Sadrian    case AR9300_DEF_MODE:
402250003Sadrian        return ahp->txpower[rate_index][num_chains-1];
403250003Sadrian
404250003Sadrian
405250003Sadrian    case AR9300_STBC_MODE:
406250003Sadrian        return ahp->txpower_stbc[rate_index][num_chains-1];
407250003Sadrian
408250003Sadrian    default:
409250003Sadrian        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
410250003Sadrian             __func__, xmit_mode);
411250003Sadrian        HALASSERT(0);
412250003Sadrian        break;
413250003Sadrian    }
414250003Sadrian
415250003Sadrian    return ahp->txpower[rate_index][num_chains-1];
416250003Sadrian}
417250003Sadrian
418250003Sadrianextern void
419250003Sadrianar9300_adjust_reg_txpower_cdd(struct ath_hal *ah,
420250003Sadrian                      u_int8_t power_per_rate[])
421250003Sadrian
422250003Sadrian{
423250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
424250003Sadrian    int16_t twice_array_gain, cdd_power = 0;
425250003Sadrian    int i;
426250003Sadrian
427250003Sadrian    /*
428250003Sadrian     *  Adjust the upper limit for CDD factoring in the array gain .
429250003Sadrian     *  The array gain is the same as TxBF, hence reuse the same defines.
430250003Sadrian     */
431250003Sadrian    switch (ahp->ah_tx_chainmask) {
432250003Sadrian
433250003Sadrian    case OSPREY_1_CHAINMASK:
434250003Sadrian        cdd_power = ahp->upper_limit[0];
435250003Sadrian        break;
436250003Sadrian
437250003Sadrian    case OSPREY_2LOHI_CHAINMASK:
438250003Sadrian    case OSPREY_2LOMID_CHAINMASK:
439250003Sadrian        twice_array_gain =
440250003Sadrian           (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
441250003Sadrian           -(AR9300_TXBF_2TX_ARRAY_GAIN) :
442250003Sadrian           ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
443250003Sadrian           (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
444250003Sadrian        cdd_power = ahp->upper_limit[1] + twice_array_gain;
445250003Sadrian        /* Adjust OFDM legacy rates as well */
446250003Sadrian        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
447250003Sadrian            if (power_per_rate[i] > cdd_power) {
448250003Sadrian                power_per_rate[i] = cdd_power;
449250003Sadrian            }
450250003Sadrian        }
451250003Sadrian
452250003Sadrian        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 20*/
453250003Sadrian        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) {
454250003Sadrian            if (power_per_rate[i] > cdd_power) {
455250003Sadrian                power_per_rate[i] = cdd_power;
456250003Sadrian            }
457250003Sadrian        }
458250003Sadrian
459250003Sadrian        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 40*/
460250003Sadrian        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) {
461250003Sadrian            if (power_per_rate[i] > cdd_power) {
462250003Sadrian                power_per_rate[i] = cdd_power;
463250003Sadrian            }
464250003Sadrian        }
465250003Sadrian        break;
466250003Sadrian
467250003Sadrian    case OSPREY_3_CHAINMASK:
468250003Sadrian        twice_array_gain =
469250003Sadrian            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
470250003Sadrian            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
471250003Sadrian            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
472250003Sadrian            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
473250003Sadrian        cdd_power = ahp->upper_limit[2] + twice_array_gain;
474250003Sadrian        /* Adjust OFDM legacy rates as well */
475250003Sadrian        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
476250003Sadrian            if (power_per_rate[i] > cdd_power) {
477250003Sadrian                power_per_rate[i] = cdd_power;
478250003Sadrian            }
479250003Sadrian        }
480250003Sadrian        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */
481250003Sadrian        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) {
482250003Sadrian            if (power_per_rate[i] > cdd_power) {
483250003Sadrian                power_per_rate[i] = cdd_power;
484250003Sadrian            }
485250003Sadrian        }
486250003Sadrian
487250003Sadrian        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */
488250003Sadrian        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) {
489250003Sadrian            if (power_per_rate[i] > cdd_power) {
490250003Sadrian                power_per_rate[i] = cdd_power;
491250003Sadrian            }
492250003Sadrian        }
493250003Sadrian
494250003Sadrian        break;
495250003Sadrian
496250003Sadrian    default:
497250003Sadrian        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
498250003Sadrian                 __func__, ahp->ah_tx_chainmask);
499250003Sadrian        break;
500250003Sadrian    }
501250003Sadrian
502250003Sadrian    return;
503250003Sadrian}
504250003Sadrian
505250003Sadrianextern void
506250003Sadrianar9300_init_rate_txpower(struct ath_hal *ah, u_int mode,
507250008Sadrian                      const struct ieee80211_channel *chan,
508250003Sadrian                      u_int8_t power_per_rate[], u_int8_t chainmask)
509250003Sadrian{
510250003Sadrian    const HAL_RATE_TABLE *rt;
511250008Sadrian    HAL_BOOL is40 = IEEE80211_IS_CHAN_HT40(chan);
512250003Sadrian
513250003Sadrian    rt = ar9300_get_rate_table(ah, mode);
514250003Sadrian    HALASSERT(rt != NULL);
515250003Sadrian
516250003Sadrian    switch (mode) {
517250003Sadrian    case HAL_MODE_11A:
518250003Sadrian        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
519250003Sadrian                              AR9300_11A_RT_OFDM_OFFSET, chainmask);
520250003Sadrian        break;
521250003Sadrian    case HAL_MODE_11NA_HT20:
522250003Sadrian    case HAL_MODE_11NA_HT40PLUS:
523250003Sadrian    case HAL_MODE_11NA_HT40MINUS:
524250003Sadrian        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
525250003Sadrian                              AR9300_11NA_RT_OFDM_OFFSET, chainmask);
526250003Sadrian        ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
527250003Sadrian                            AR9300_11NA_RT_HT_SS_OFFSET,
528250003Sadrian                            AR9300_11NA_RT_HT_DS_OFFSET,
529250003Sadrian                            AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
530250003Sadrian        ar9300_init_rate_txpower_stbc(ah, rt, is40,
531250003Sadrian                            AR9300_11NA_RT_HT_SS_OFFSET,
532250003Sadrian                            AR9300_11NA_RT_HT_DS_OFFSET,
533250003Sadrian                            AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
534250003Sadrian        /* For FCC the array gain has to be factored for CDD mode */
535250008Sadrian        if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
536250003Sadrian            ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
537250003Sadrian                            AR9300_11NA_RT_HT_SS_OFFSET,
538250003Sadrian                            AR9300_11NA_RT_HT_DS_OFFSET,
539250003Sadrian                            AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
540250003Sadrian        }
541250003Sadrian        break;
542250003Sadrian    case HAL_MODE_11G:
543250003Sadrian        ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
544250003Sadrian        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
545250003Sadrian                              AR9300_11G_RT_OFDM_OFFSET, chainmask);
546250003Sadrian        break;
547250003Sadrian    case HAL_MODE_11B:
548250003Sadrian        ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
549250003Sadrian        break;
550250003Sadrian    case HAL_MODE_11NG_HT20:
551250003Sadrian    case HAL_MODE_11NG_HT40PLUS:
552250003Sadrian    case HAL_MODE_11NG_HT40MINUS:
553250003Sadrian        ar9300_init_rate_txpower_cck(ah, rt, power_per_rate,  chainmask);
554250003Sadrian        ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
555250003Sadrian                              AR9300_11NG_RT_OFDM_OFFSET, chainmask);
556250003Sadrian        ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
557250003Sadrian                            AR9300_11NG_RT_HT_SS_OFFSET,
558250003Sadrian                            AR9300_11NG_RT_HT_DS_OFFSET,
559250003Sadrian                            AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
560250003Sadrian        ar9300_init_rate_txpower_stbc(ah, rt, is40,
561250003Sadrian                            AR9300_11NG_RT_HT_SS_OFFSET,
562250003Sadrian                            AR9300_11NG_RT_HT_DS_OFFSET,
563250003Sadrian                            AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
564250003Sadrian        /* For FCC the array gain needs to be factored for CDD mode */
565250008Sadrian        if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
566250003Sadrian            ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
567250003Sadrian                            AR9300_11NG_RT_HT_SS_OFFSET,
568250003Sadrian                            AR9300_11NG_RT_HT_DS_OFFSET,
569250003Sadrian                            AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
570250003Sadrian        }
571250003Sadrian        break;
572250003Sadrian    default:
573250003Sadrian        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
574250003Sadrian             __func__, mode);
575250003Sadrian        HALASSERT(0);
576250003Sadrian        break;
577250003Sadrian    }
578250003Sadrian
579250003Sadrian}
580250003Sadrian
581250003Sadrianstatic inline void
582250003Sadrianar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
583250003Sadrian                         u_int8_t rates_array[], u_int8_t chainmask)
584250003Sadrian{
585250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
586250003Sadrian    /*
587250003Sadrian     * Pick the lower of the long-preamble txpower, and short-preamble tx power.
588250003Sadrian     * Unfortunately, the rate table doesn't have separate entries for these!.
589250003Sadrian     */
590250003Sadrian    switch (chainmask) {
591250003Sadrian    case OSPREY_1_CHAINMASK:
592250003Sadrian        ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
593250003Sadrian        ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
594250003Sadrian        ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
595250003Sadrian                                  rates_array[ALL_TARGET_LEGACY_5S]);
596250003Sadrian        ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
597250003Sadrian                                      rates_array[ALL_TARGET_LEGACY_11S]);
598250003Sadrian        break;
599250003Sadrian    case OSPREY_2LOHI_CHAINMASK:
600250003Sadrian    case OSPREY_2LOMID_CHAINMASK:
601250003Sadrian        ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
602250003Sadrian        ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
603250003Sadrian        ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
604250003Sadrian                                  rates_array[ALL_TARGET_LEGACY_5S]);
605250003Sadrian        ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
606250003Sadrian                                  rates_array[ALL_TARGET_LEGACY_11S]);
607250003Sadrian        break;
608250003Sadrian    case OSPREY_3_CHAINMASK:
609250003Sadrian        ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
610250003Sadrian        ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
611250003Sadrian        ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
612250003Sadrian                                   rates_array[ALL_TARGET_LEGACY_5S]);
613250003Sadrian        ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
614250003Sadrian                                       rates_array[ALL_TARGET_LEGACY_11S]);
615250003Sadrian        break;
616250003Sadrian    default:
617250003Sadrian        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
618250003Sadrian                 __func__, chainmask);
619250003Sadrian        break;
620250003Sadrian    }
621250003Sadrian}
622250003Sadrian
623250003Sadrianstatic inline void
624250003Sadrianar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
625250003Sadrian                          u_int8_t rates_array[], int rt_offset,
626250003Sadrian                          u_int8_t chainmask)
627250003Sadrian{
628250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
629250003Sadrian    int16_t twice_array_gain, cdd_power = 0;
630250003Sadrian    int i, j;
631250003Sadrian    u_int8_t ofdm_rt_2_pwr_idx[8] =
632250003Sadrian    {
633250003Sadrian        ALL_TARGET_LEGACY_6_24,
634250003Sadrian        ALL_TARGET_LEGACY_6_24,
635250003Sadrian        ALL_TARGET_LEGACY_6_24,
636250003Sadrian        ALL_TARGET_LEGACY_6_24,
637250003Sadrian        ALL_TARGET_LEGACY_6_24,
638250003Sadrian        ALL_TARGET_LEGACY_36,
639250003Sadrian        ALL_TARGET_LEGACY_48,
640250003Sadrian        ALL_TARGET_LEGACY_54,
641250003Sadrian    };
642250003Sadrian
643250003Sadrian    /*
644250003Sadrian     *  For FCC adjust the upper limit for CDD factoring in the array gain.
645250003Sadrian     *  The array gain is the same as TxBF, hence reuse the same defines.
646250003Sadrian     */
647250003Sadrian    for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) {
648250003Sadrian
649250003Sadrian        /* Get the correct OFDM rate to Power table Index */
650250003Sadrian        j = ofdm_rt_2_pwr_idx[i- rt_offset];
651250003Sadrian
652250003Sadrian        switch (chainmask) {
653250003Sadrian        case OSPREY_1_CHAINMASK:
654250003Sadrian            ahp->txpower[i][0] = rates_array[j];
655250003Sadrian            break;
656250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
657250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
658250003Sadrian            ahp->txpower[i][1] = rates_array[j];
659250003Sadrian            if (is_reg_dmn_fcc(ahp->reg_dmn)){
660250003Sadrian                twice_array_gain = (ahp->twice_antenna_gain >=
661250003Sadrian                ahp->twice_antenna_reduction)?
662250003Sadrian                -(AR9300_TXBF_2TX_ARRAY_GAIN) :
663250003Sadrian                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
664250003Sadrian               (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
665250003Sadrian                cdd_power = ahp->upper_limit[1] + twice_array_gain;
666250003Sadrian                if (ahp->txpower[i][1] > cdd_power){
667250003Sadrian                    ahp->txpower[i][1] = cdd_power;
668250003Sadrian                }
669250003Sadrian            }
670250003Sadrian            break;
671250003Sadrian        case OSPREY_3_CHAINMASK:
672250003Sadrian            ahp->txpower[i][2] = rates_array[j];
673250003Sadrian            if (is_reg_dmn_fcc(ahp->reg_dmn)) {
674250003Sadrian                twice_array_gain =
675250003Sadrian                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
676250003Sadrian                -(AR9300_TXBF_3TX_ARRAY_GAIN):
677250003Sadrian                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
678250003Sadrian                (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
679250003Sadrian                cdd_power = ahp->upper_limit[2] + twice_array_gain;
680250003Sadrian                if (ahp->txpower[i][2] > cdd_power){
681250003Sadrian                    ahp->txpower[i][2] = cdd_power;
682250003Sadrian                }
683250003Sadrian            }
684250003Sadrian            break;
685250003Sadrian        default:
686250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
687250003Sadrian                     __func__, chainmask);
688250003Sadrian            break;
689250003Sadrian        }
690250003Sadrian    }
691250003Sadrian}
692250003Sadrian
693250003Sadrianstatic  u_int8_t mcs_rate_2_pwr_idx_ht20[24] =
694250003Sadrian    {
695250003Sadrian        ALL_TARGET_HT20_0_8_16,
696250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
697250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
698250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
699250003Sadrian        ALL_TARGET_HT20_4,
700250003Sadrian        ALL_TARGET_HT20_5,
701250003Sadrian        ALL_TARGET_HT20_6,
702250003Sadrian        ALL_TARGET_HT20_7,
703250003Sadrian        ALL_TARGET_HT20_0_8_16,
704250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
705250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
706250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
707250003Sadrian        ALL_TARGET_HT20_12,
708250003Sadrian        ALL_TARGET_HT20_13,
709250003Sadrian        ALL_TARGET_HT20_14,
710250003Sadrian        ALL_TARGET_HT20_15,
711250003Sadrian        ALL_TARGET_HT20_0_8_16,
712250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
713250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
714250003Sadrian        ALL_TARGET_HT20_1_3_9_11_17_19,
715250003Sadrian        ALL_TARGET_HT20_20,
716250003Sadrian        ALL_TARGET_HT20_21,
717250003Sadrian        ALL_TARGET_HT20_22,
718250003Sadrian        ALL_TARGET_HT20_23
719250003Sadrian    };
720250003Sadrian
721250003Sadrianstatic   u_int8_t mcs_rate_2_pwr_idx_ht40[24] =
722250003Sadrian    {
723250003Sadrian        ALL_TARGET_HT40_0_8_16,
724250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
725250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
726250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
727250003Sadrian        ALL_TARGET_HT40_4,
728250003Sadrian        ALL_TARGET_HT40_5,
729250003Sadrian        ALL_TARGET_HT40_6,
730250003Sadrian        ALL_TARGET_HT40_7,
731250003Sadrian        ALL_TARGET_HT40_0_8_16,
732250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
733250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
734250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
735250003Sadrian        ALL_TARGET_HT40_12,
736250003Sadrian        ALL_TARGET_HT40_13,
737250003Sadrian        ALL_TARGET_HT40_14,
738250003Sadrian        ALL_TARGET_HT40_15,
739250003Sadrian        ALL_TARGET_HT40_0_8_16,
740250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
741250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
742250003Sadrian        ALL_TARGET_HT40_1_3_9_11_17_19,
743250003Sadrian        ALL_TARGET_HT40_20,
744250003Sadrian        ALL_TARGET_HT40_21,
745250003Sadrian        ALL_TARGET_HT40_22,
746250003Sadrian        ALL_TARGET_HT40_23,
747250003Sadrian    };
748250003Sadrian
749250003Sadrianstatic inline void
750250003Sadrianar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
751250003Sadrian                        HAL_BOOL is40,
752250003Sadrian                        u_int8_t rates_array[],
753250003Sadrian                        int rt_ss_offset, int rt_ds_offset,
754250003Sadrian                        int rt_ts_offset, u_int8_t chainmask)
755250003Sadrian{
756250003Sadrian
757250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
758250003Sadrian    int i, j;
759250003Sadrian    u_int8_t mcs_index = 0;
760250003Sadrian
761250003Sadrian
762250003Sadrian    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
763250003Sadrian        /* Get the correct MCS rate to Power table Index */
764250003Sadrian        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
765250003Sadrian                          mcs_rate_2_pwr_idx_ht20[mcs_index];
766250003Sadrian        switch (chainmask) {
767250003Sadrian        case OSPREY_1_CHAINMASK:
768250003Sadrian            ahp->txpower[i][0] = rates_array[j];
769250003Sadrian            break;
770250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
771250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
772250003Sadrian            ahp->txpower[i][1] = rates_array[j];
773250003Sadrian            break;
774250003Sadrian        case OSPREY_3_CHAINMASK:
775250003Sadrian            ahp->txpower[i][2] = rates_array[j];
776250003Sadrian            break;
777250003Sadrian        default:
778250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
779250003Sadrian                     __func__, chainmask);
780250003Sadrian            break;
781250003Sadrian        }
782250003Sadrian        mcs_index++;
783250003Sadrian    }
784250003Sadrian
785250003Sadrian    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
786250003Sadrian        /* Get the correct MCS rate to Power table Index */
787250003Sadrian        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
788250003Sadrian                                       mcs_rate_2_pwr_idx_ht20[mcs_index];
789250003Sadrian        switch (chainmask) {
790250003Sadrian        case OSPREY_1_CHAINMASK:
791250003Sadrian            ahp->txpower[i][0] = rates_array[j];
792250003Sadrian            break;
793250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
794250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
795250003Sadrian            ahp->txpower[i][1] = rates_array[j];
796250003Sadrian            break;
797250003Sadrian        case OSPREY_3_CHAINMASK:
798250003Sadrian            ahp->txpower[i][2] = rates_array[j];
799250003Sadrian            break;
800250003Sadrian        default:
801250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
802250003Sadrian                         __func__, chainmask);
803250003Sadrian            break;
804250003Sadrian        }
805250003Sadrian        mcs_index++;
806250003Sadrian    }
807250003Sadrian
808250003Sadrian    for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
809250003Sadrian        /* Get the correct MCS rate to Power table Index */
810250003Sadrian        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
811250003Sadrian                                  mcs_rate_2_pwr_idx_ht20[mcs_index];
812250003Sadrian        switch (chainmask) {
813250003Sadrian        case OSPREY_1_CHAINMASK:
814250003Sadrian            ahp->txpower[i][0] = rates_array[j];
815250003Sadrian            break;
816250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
817250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
818250003Sadrian            ahp->txpower[i][1] = rates_array[j];
819250003Sadrian            break;
820250003Sadrian        case OSPREY_3_CHAINMASK:
821250003Sadrian            ahp->txpower[i][2] = rates_array[j];
822250003Sadrian            break;
823250003Sadrian        default:
824250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
825250003Sadrian                 __func__, chainmask);
826250003Sadrian            break;
827250003Sadrian        }
828250003Sadrian        mcs_index++;
829250003Sadrian    }
830250003Sadrian}
831250003Sadrian
832250003Sadrianstatic inline void
833250003Sadrianar9300_init_rate_txpower_stbc(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
834250003Sadrian                        HAL_BOOL is40,
835250003Sadrian                        int rt_ss_offset, int rt_ds_offset,
836250003Sadrian                        int rt_ts_offset, u_int8_t chainmask)
837250003Sadrian{
838250003Sadrian
839250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
840250003Sadrian    int i;
841250003Sadrian    int16_t twice_array_gain, stbc_power = 0;
842250003Sadrian    u_int8_t mcs_index = 0;
843250003Sadrian
844250003Sadrian    /* Upper Limit with STBC */
845250003Sadrian    switch (chainmask) {
846250003Sadrian    case OSPREY_1_CHAINMASK:
847250003Sadrian        stbc_power = ahp->upper_limit[0];
848250003Sadrian        break;
849250003Sadrian    case OSPREY_2LOHI_CHAINMASK:
850250003Sadrian    case OSPREY_2LOMID_CHAINMASK:
851250003Sadrian        stbc_power = ahp->upper_limit[1];
852250003Sadrian        break;
853250003Sadrian    case OSPREY_3_CHAINMASK:
854250003Sadrian        stbc_power = ahp->upper_limit[2];
855250003Sadrian        /* Ony FCC requires that we back off with 3 transmit chains */
856250003Sadrian        if (is_reg_dmn_fcc(ahp->reg_dmn)) {
857250003Sadrian            twice_array_gain =
858250003Sadrian                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
859250003Sadrian                -(AR9300_STBC_3TX_ARRAY_GAIN) :
860250003Sadrian                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
861250003Sadrian                (ahp->twice_antenna_gain + AR9300_STBC_3TX_ARRAY_GAIN)), 0));
862250003Sadrian            stbc_power = ahp->upper_limit[2] + twice_array_gain;
863250003Sadrian        }
864250003Sadrian        break;
865250003Sadrian
866250003Sadrian    default:
867250003Sadrian        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
868250003Sadrian                 __func__, chainmask);
869250003Sadrian        break;
870250003Sadrian    }
871250003Sadrian
872250003Sadrian
873250003Sadrian    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
874250003Sadrian        switch (chainmask) {
875250003Sadrian        case OSPREY_1_CHAINMASK:
876250003Sadrian            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
877250003Sadrian            break;
878250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
879250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
880250003Sadrian            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
881250003Sadrian            break;
882250003Sadrian        case OSPREY_3_CHAINMASK:
883250003Sadrian            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
884250003Sadrian            /* 3 TX/1 stream  STBC gain adjustment */
885250003Sadrian            if (ahp->txpower_stbc[i][2] > stbc_power){
886250003Sadrian                ahp->txpower_stbc[i][2] = stbc_power;
887250003Sadrian            }
888250003Sadrian            break;
889250003Sadrian        default:
890250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
891250003Sadrian                     __func__, chainmask);
892250003Sadrian            break;
893250003Sadrian        }
894250003Sadrian        mcs_index++;
895250003Sadrian    }
896250003Sadrian
897250003Sadrian    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
898250003Sadrian        switch (chainmask) {
899250003Sadrian        case OSPREY_1_CHAINMASK:
900250003Sadrian            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
901250003Sadrian            break;
902250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
903250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
904250003Sadrian            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
905250003Sadrian            break;
906250003Sadrian        case OSPREY_3_CHAINMASK:
907250003Sadrian            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
908250003Sadrian            /* 3 TX/2 stream  STBC gain adjustment */
909250003Sadrian            if (ahp->txpower_stbc[i][2] > stbc_power){
910250003Sadrian                ahp->txpower_stbc[i][2] = stbc_power;
911250003Sadrian	    }
912250003Sadrian            break;
913250003Sadrian        default:
914250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
915250003Sadrian                     __func__, chainmask);
916250003Sadrian            break;
917250003Sadrian        }
918250003Sadrian        mcs_index++;
919250003Sadrian    }
920250003Sadrian
921250003Sadrian    for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
922250003Sadrian        switch (chainmask) {
923250003Sadrian        case OSPREY_1_CHAINMASK:
924250003Sadrian            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
925250003Sadrian            break;
926250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
927250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
928250003Sadrian            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
929250003Sadrian            break;
930250003Sadrian        case OSPREY_3_CHAINMASK:
931250003Sadrian            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
932250003Sadrian            break;
933250003Sadrian        default:
934250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
935250003Sadrian                     __func__, chainmask);
936250003Sadrian            break;
937250003Sadrian        }
938250003Sadrian        mcs_index++;
939250003Sadrian    }
940250003Sadrian
941250003Sadrian    return;
942250003Sadrian}
943250003Sadrian
944250003Sadrianstatic inline void
945250003Sadrianar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
946250003Sadrian                        HAL_BOOL is40,
947250003Sadrian                        int rt_ss_offset, int rt_ds_offset,
948250003Sadrian                        int rt_ts_offset, u_int8_t chainmask)
949250003Sadrian{
950250003Sadrian
951250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
952250003Sadrian    int i;
953250003Sadrian    int16_t twice_array_gain, cdd_power = 0;
954250003Sadrian    u_int8_t mcs_index = 0;
955250003Sadrian
956250003Sadrian    /*
957250003Sadrian     *  Adjust the upper limit for CDD factoring in the array gain .
958250003Sadrian     *  The array gain is the same as TxBF, hence reuse the same defines.
959250003Sadrian     */
960250003Sadrian    switch (chainmask) {
961250003Sadrian    case OSPREY_1_CHAINMASK:
962250003Sadrian        cdd_power = ahp->upper_limit[0];
963250003Sadrian        break;
964250003Sadrian
965250003Sadrian    case OSPREY_2LOHI_CHAINMASK:
966250003Sadrian    case OSPREY_2LOMID_CHAINMASK:
967250003Sadrian        twice_array_gain =
968250003Sadrian            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
969250003Sadrian            -(AR9300_TXBF_2TX_ARRAY_GAIN) :
970250003Sadrian            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
971250003Sadrian            (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
972250003Sadrian        cdd_power = ahp->upper_limit[1] + twice_array_gain;
973250003Sadrian        break;
974250003Sadrian
975250003Sadrian    case OSPREY_3_CHAINMASK:
976250003Sadrian        twice_array_gain =
977250003Sadrian            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
978250003Sadrian            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
979250003Sadrian            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
980250003Sadrian            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
981250003Sadrian        cdd_power = ahp->upper_limit[2] + twice_array_gain;
982250003Sadrian        break;
983250003Sadrian
984250003Sadrian    default:
985250003Sadrian        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
986250003Sadrian                     __func__, chainmask);
987250003Sadrian        break;
988250003Sadrian    }
989250003Sadrian
990250003Sadrian
991250003Sadrian    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
992250003Sadrian        switch (chainmask) {
993250003Sadrian        case OSPREY_1_CHAINMASK:
994250003Sadrian            break;
995250003Sadrian
996250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
997250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
998250003Sadrian            /* 2 TX/1 stream  CDD gain adjustment */
999250003Sadrian            if (ahp->txpower[i][1] > cdd_power){
1000250003Sadrian                ahp->txpower[i][1] = cdd_power;
1001250003Sadrian            }
1002250003Sadrian            break;
1003250003Sadrian        case OSPREY_3_CHAINMASK:
1004250003Sadrian            /* 3 TX/1 stream  CDD gain adjustment */
1005250003Sadrian            if (ahp->txpower[i][2] > cdd_power){
1006250003Sadrian                ahp->txpower[i][2] = cdd_power;
1007250003Sadrian            }
1008250003Sadrian            break;
1009250003Sadrian        default:
1010250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
1011250003Sadrian                     __func__, chainmask);
1012250003Sadrian            break;
1013250003Sadrian        }
1014250003Sadrian        mcs_index++;
1015250003Sadrian    }
1016250003Sadrian
1017250003Sadrian    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
1018250003Sadrian        switch (chainmask) {
1019250003Sadrian        case OSPREY_1_CHAINMASK:
1020250003Sadrian        case OSPREY_2LOHI_CHAINMASK:
1021250003Sadrian        case OSPREY_2LOMID_CHAINMASK:
1022250003Sadrian            break;
1023250003Sadrian        case OSPREY_3_CHAINMASK:
1024250003Sadrian        /* 3 TX/2 stream  TxBF gain adjustment */
1025250003Sadrian            if (ahp->txpower[i][2] > cdd_power){
1026250003Sadrian                ahp->txpower[i][2] = cdd_power;
1027250003Sadrian            }
1028250003Sadrian            break;
1029250003Sadrian        default:
1030250003Sadrian            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
1031250003Sadrian                 __func__, chainmask);
1032250003Sadrian            break;
1033250003Sadrian        }
1034250003Sadrian        mcs_index++;
1035250003Sadrian    }
1036250003Sadrian
1037250003Sadrian    return;
1038250003Sadrian
1039250003Sadrian}
1040250003Sadrian
1041250003Sadrianvoid ar9300_disp_tpc_tables(struct ath_hal *ah)
1042250003Sadrian{
1043250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
1044250008Sadrian    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
1045250003Sadrian    u_int mode = ath_hal_get_curmode(ah, chan);
1046250003Sadrian    const HAL_RATE_TABLE *rt;
1047250003Sadrian    int i, j;
1048250003Sadrian
1049250003Sadrian    /* Check whether TPC is enabled */
1050250008Sadrian    if (!ah->ah_config.ath_hal_desc_tpc) {
1051250003Sadrian        ath_hal_printf(ah, "\n TPC Register method in use\n");
1052250003Sadrian        return;
1053250003Sadrian    }
1054250003Sadrian
1055250003Sadrian    rt = ar9300_get_rate_table(ah, mode);
1056250003Sadrian    HALASSERT(rt != NULL);
1057250003Sadrian
1058250003Sadrian    ath_hal_printf(ah, "\n===TARGET POWER TABLE===\n");
1059250003Sadrian    for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1060250003Sadrian        for (i = 0; i < rt->rateCount; i++) {
1061250003Sadrian            int16_t txpower[AR9300_MAX_CHAINS];
1062250003Sadrian            txpower[j] = ahp->txpower[i][j];
1063250003Sadrian            ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
1064250003Sadrian                       "Power (%d Chain) [%2d.%1d dBm]\n",
1065250008Sadrian                       i, rt->info[i].rateCode, rt->info[i].rateKbps,
1066250003Sadrian                       j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1067250003Sadrian        }
1068250003Sadrian    }
1069250003Sadrian    ath_hal_printf(ah, "\n");
1070250003Sadrian
1071250003Sadrian    ath_hal_printf(ah, "\n\n===TARGET POWER TABLE with STBC===\n");
1072250003Sadrian    for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1073250003Sadrian        for (i = 0; i < rt->rateCount; i++) {
1074250003Sadrian            int16_t txpower[AR9300_MAX_CHAINS];
1075250003Sadrian            txpower[j] = ahp->txpower_stbc[i][j];
1076250003Sadrian
1077250003Sadrian            /* Do not display invalid configurations */
1078250008Sadrian            if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1079250008Sadrian                (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1080250008Sadrian                ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1081250003Sadrian                continue;
1082250003Sadrian            }
1083250003Sadrian
1084250003Sadrian            ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
1085250003Sadrian                       "Power (%d Chain) [%2d.%1d dBm]\n",
1086250008Sadrian                       i, rt->info[i].rateCode , rt->info[i].rateKbps,
1087250003Sadrian                       j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1088250003Sadrian        }
1089250003Sadrian    }
1090250003Sadrian    ath_hal_printf(ah, "\n");
1091250003Sadrian}
1092250003Sadrian
1093250003Sadrian/*
1094250003Sadrian * The followings are customer specific APIs for querying power limit.
1095250003Sadrian * Power limit is based on regulatory domain, chipset, and transmission rate.
1096250003Sadrian * Here we only consider EEPROM values, no array gain/CTL considered here.
1097250003Sadrian */
1098250003Sadrian
1099250003Sadrianstruct rate_power_tbl {
1100250003Sadrian    u_int8_t    rateIdx;        /* rate index in the rate table */
1101250003Sadrian    u_int32_t   rateKbps;       /* transfer rate in kbs */
1102250003Sadrian    u_int8_t    rateCode;      /* rate for h/w descriptors */
1103250003Sadrian    u_int8_t    txbf:   1,      /* txbf eligible */
1104250003Sadrian                stbc:   1,      /* stbc eligible */
1105250003Sadrian                chain1: 1,      /* one-chain eligible */
1106250003Sadrian                chain2: 1,      /* two-chain eligible */
1107250003Sadrian                chain3: 1;      /* three-chain eligible */
1108250003Sadrian    int16_t     txpower[AR9300_MAX_CHAINS];     /* txpower for different chainmasks */
1109250003Sadrian    int16_t     txpower_stbc[AR9300_MAX_CHAINS];
1110250003Sadrian};
1111250003Sadrian
1112250003Sadrianu_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah)
1113250003Sadrian{
1114250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
1115250008Sadrian    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
1116250003Sadrian    u_int mode = ath_hal_get_curmode(ah, chan);
1117250003Sadrian    const HAL_RATE_TABLE *rt;
1118250003Sadrian    u_int8_t *data;
1119250003Sadrian    struct rate_power_tbl *table;
1120250003Sadrian    int i, j;
1121250003Sadrian
1122250003Sadrian    /* Check whether TPC is enabled */
1123250008Sadrian    if (! ah->ah_config.ath_hal_desc_tpc) {
1124250003Sadrian        ath_hal_printf(ah, "\n TPC Register method in use\n");
1125250003Sadrian        return NULL;
1126250003Sadrian    }
1127250003Sadrian
1128250008Sadrian    rt = (const HAL_RATE_TABLE *)ar9300_get_rate_table(ah, mode);
1129250003Sadrian    HALASSERT(rt != NULL);
1130250003Sadrian
1131250008Sadrian    data = (u_int8_t *)ath_hal_malloc(
1132250003Sadrian                       1 + rt->rateCount * sizeof(struct rate_power_tbl));
1133250003Sadrian    if (data == NULL)
1134250003Sadrian        return NULL;
1135250003Sadrian
1136250003Sadrian    OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl));
1137250003Sadrian    /* store the rate count at the beginning */
1138250003Sadrian    *data = rt->rateCount;
1139250003Sadrian    table = (struct rate_power_tbl *)&data[1];
1140250003Sadrian
1141250003Sadrian    for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1142250003Sadrian        for (i = 0; i < rt->rateCount; i++) {
1143250003Sadrian            table[i].rateIdx = i;
1144250008Sadrian            table[i].rateCode = rt->info[i].rateCode;
1145250003Sadrian            table[i].rateKbps = rt->info[i].rateKbps;
1146250003Sadrian            switch (j) {
1147250003Sadrian            case 0:
1148250008Sadrian                table[i].chain1 = rt->info[i].rateCode <= 0x87 ? 1 : 0;
1149250003Sadrian                break;
1150250003Sadrian            case 1:
1151250008Sadrian                table[i].chain2 = rt->info[i].rateCode <= 0x8f ? 1 : 0;
1152250003Sadrian                break;
1153250003Sadrian            case 2:
1154250003Sadrian                table[i].chain3 = 1;
1155250003Sadrian                break;
1156250003Sadrian            default:
1157250003Sadrian                break;
1158250003Sadrian            }
1159250003Sadrian            if ((j == 0 && table[i].chain1) ||
1160250003Sadrian                (j == 1 && table[i].chain2) ||
1161250003Sadrian                (j == 2 && table[i].chain3))
1162250003Sadrian                table[i].txpower[j] = ahp->txpower[i][j];
1163250003Sadrian        }
1164250003Sadrian    }
1165250003Sadrian
1166250003Sadrian    for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1167250003Sadrian        for (i = 0; i < rt->rateCount; i++) {
1168250003Sadrian            /* Do not display invalid configurations */
1169250008Sadrian            if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1170250008Sadrian                (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1171250008Sadrian                ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1172250003Sadrian                continue;
1173250003Sadrian            }
1174250003Sadrian
1175250003Sadrian            table[i].stbc = 1;
1176250003Sadrian            table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j];
1177250003Sadrian        }
1178250003Sadrian    }
1179250003Sadrian
1180250003Sadrian    return data;
1181250003Sadrian    /* the caller is responsible to free data */
1182250003Sadrian}
1183250003Sadrian
1184250003SadrianHAL_STATUS
1185250003Sadrianath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq,
1186250003Sadrian                                        int8_t *max_rate_power, int8_t *min_rate_power)
1187250003Sadrian{
1188250003Sadrian    /*
1189250003Sadrian     * Used for AR9300 series chip only
1190250003Sadrian     */
1191250008Sadrian    if (ah->ah_magic == AR9300_MAGIC) {
1192250003Sadrian        u_int8_t target_rate_power_limit_val_t2[ar9300_rate_size];
1193250003Sadrian        int i;
1194250003Sadrian
1195250003Sadrian        *max_rate_power = 0;
1196250003Sadrian        *min_rate_power = AR9300_MAX_RATE_POWER;
1197250003Sadrian
1198250003Sadrian        ar9300_set_target_power_from_eeprom(ah, freq, target_rate_power_limit_val_t2);
1199250003Sadrian
1200250003Sadrian        for (i=0; i<ar9300_rate_size; i++) {
1201250003Sadrian            if (target_rate_power_limit_val_t2[i] > *max_rate_power)
1202250003Sadrian                *max_rate_power = target_rate_power_limit_val_t2[i];
1203250003Sadrian            if (target_rate_power_limit_val_t2[i] < *min_rate_power)
1204250003Sadrian                *min_rate_power = target_rate_power_limit_val_t2[i];
1205250003Sadrian        }
1206250003Sadrian    } else {
1207250003Sadrian        *max_rate_power = 0;
1208250003Sadrian        *min_rate_power = 0;
1209250003Sadrian    }
1210250003Sadrian
1211250003Sadrian    return HAL_OK;
1212250003Sadrian}
1213