carl9170 firmware: report device tallies
[carl9170fw.git] / carlfw / src / rf.c
1 /*
2  * carl9170 firmware - used by the ar9170 wireless device
3  *
4  * PHY and RF functions
5  *
6  * Copyright (c) 2000-2005 ZyDAS Technology Corporation
7  * Copyright (c) 2007-2009 Atheros Communications, Inc.
8  * Copyright    2009    Johannes Berg <johannes@sipsolutions.net>
9  * Copyright 2009-2011  Christian Lamparter <chunkeey@googlemail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "carl9170.h"
27 #include "timer.h"
28 #include "printf.h"
29 #include "rf.h"
30 #include "shared/phy.h"
31
32 void tally_update(void)
33 {
34         unsigned int time;
35
36 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
37         unsigned int main_not_free, ext_not_free;
38
39         main_not_free = get(AR9170_MAC_REG_CHANNEL_BUSY);
40         ext_not_free = get(AR9170_MAC_REG_EXT_BUSY);
41         time = get_clock_counter();
42
43         if (fw.phy.state == CARL9170_PHY_ON) {
44                 unsigned int us_delta = (time - fw.tally_clock) / max(fw.ticks_per_usec, 40u);
45
46                 fw.tally.active += us_delta;
47                 fw.tally.main_free += main_not_free;
48                 fw.tally.ext_free += ext_not_free;
49         }
50 #else
51         time = get_clock_counter();
52
53 #endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */
54
55         fw.tally_clock = time;
56 }
57
58 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
59 static void set_channel_end(void)
60 {
61         /* Manipulate CCA threshold to resume transmission */
62         set(AR9170_PHY_REG_CCA_THRESHOLD, 0x0);
63         /* Disable Virtual CCA */
64         andl(AR9170_MAC_REG_QOS_PRIORITY_VIRTUAL_CCA,
65              ~AR9170_MAC_VIRTUAL_CCA_ALL);
66
67         /* clear statistics */
68         tally_update();
69
70         fw.phy.state = CARL9170_PHY_ON;
71 }
72
73 void rf_notify_set_channel(void)
74 {
75         tally_update();
76
77         /* Manipulate CCA threshold to stop transmission */
78         set(AR9170_PHY_REG_CCA_THRESHOLD, 0x300);
79         /* Enable Virtual CCA */
80         orl(AR9170_MAC_REG_QOS_PRIORITY_VIRTUAL_CCA,
81             AR9170_MAC_VIRTUAL_CCA_ALL);
82
83         /* reset CCA stats */
84         fw.tally.active = 0;
85         fw.tally.main_free = 0;
86         fw.tally.ext_free = 0;
87         fw.phy.state = CARL9170_PHY_OFF;
88 }
89
90 /*
91  * Update delta slope coeff man and exp
92  */
93 static void hw_turn_off_dyn(const uint32_t delta_slope_coeff_exp,
94                             const uint32_t delta_slope_coeff_man,
95                             const uint32_t delta_slope_coeff_exp_shgi,
96                             const uint32_t delta_slope_coeff_man_shgi)
97 {
98         uint32_t tmp;
99
100         tmp = get_async(AR9170_PHY_REG_TIMING3) & 0x00001fff;
101         tmp |= (delta_slope_coeff_man << AR9170_PHY_TIMING3_DSC_MAN_S) &
102                 AR9170_PHY_TIMING3_DSC_MAN;
103         tmp |= (delta_slope_coeff_exp << AR9170_PHY_TIMING3_DSC_EXP_S) &
104                 AR9170_PHY_TIMING3_DSC_EXP;
105
106         set(AR9170_PHY_REG_TIMING3, tmp);
107
108         tmp = (delta_slope_coeff_man_shgi << AR9170_PHY_HALFGI_DSC_MAN_S) &
109                 AR9170_PHY_HALFGI_DSC_MAN;
110
111         tmp |= (delta_slope_coeff_exp_shgi << AR9170_PHY_HALFGI_DSC_EXP_S) &
112                 AR9170_PHY_HALFGI_DSC_EXP;
113
114         set(AR9170_PHY_REG_HALFGI, tmp);
115 }
116
117 static void program_ADDAC(void)
118 {
119         /* ??? Select Internal ADDAC ??? (is external radio) */
120         set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_EXTERNAL_RADIO);
121
122         delay(10);
123
124         set(0x1c589c, 0x00000000);      /*# 7-0 */
125         set(0x1c589c, 0x00000000);      /*# 15-8 */
126         set(0x1c589c, 0x00000000);      /*# 23-16 */
127         set(0x1c589c, 0x00000000);      /*# 31- */
128
129         set(0x1c589c, 0x00000000);      /*# 39- */
130         set(0x1c589c, 0x00000000);      /*# 47- */
131         set(0x1c589c, 0x00000000);      /*# 55- [48]:doubles the xtalosc bias current */
132         set(0x1c589c, 0x00000000);      /*# 63- */
133
134         set(0x1c589c, 0x00000000);      /*# 71- */
135         set(0x1c589c, 0x00000000);      /*# 79- */
136         set(0x1c589c, 0x00000000);      /*# 87- */
137         set(0x1c589c, 0x00000000);      /*# 95- */
138
139         set(0x1c589c, 0x00000000);      /*# 103- */
140         set(0x1c589c, 0x00000000);      /*# 111- */
141         set(0x1c589c, 0x00000000);      /*# 119- */
142         set(0x1c589c, 0x00000000);      /*# 127- */
143
144         set(0x1c589c, 0x00000000);      /*# 135- */
145         set(0x1c589c, 0x00000000);      /*# 143- */
146         set(0x1c589c, 0x00000000);      /*# 151- */
147         set(0x1c589c, 0x00000030);      /*# 159- #[158:156]=xlnabufmode */
148
149         set(0x1c589c, 0x00000004);      /*# 167-  [162]:disable clkp_driver to flow */
150         set(0x1c589c, 0x00000000);      /*# 175- */
151         set(0x1c589c, 0x00000000);      /*# 183-176 */
152         set(0x1c589c, 0x00000000);      /*# 191-184 */
153
154         set(0x1c589c, 0x00000000);      /*# 199- */
155         set(0x1c589c, 0x00000000);      /*# 207- */
156         set(0x1c589c, 0x00000000);      /*# 215- */
157         set(0x1c589c, 0x00000000);      /*# 223- */
158
159         set(0x1c589c, 0x00000000);      /*# 231- */
160         set(0x1c58c4, 0x00000000);      /*# 233-232 */
161
162         delay(10);
163
164         /* Select External Flow ???? (is internal addac??) */
165         set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_INTERNAL_ADDAC);
166 }
167
168 static uint32_t AGC_calibration(uint32_t loop)
169 {
170         uint32_t wrdata;
171         uint32_t ret;
172
173 #define AGC_CAL_NF      (AR9170_PHY_AGC_CONTROL_CAL | AR9170_PHY_AGC_CONTROL_NF)
174
175         wrdata = get_async(AR9170_PHY_REG_AGC_CONTROL) | AGC_CAL_NF;
176         set(AR9170_PHY_REG_AGC_CONTROL, wrdata);
177
178         ret = get_async(AR9170_PHY_REG_AGC_CONTROL) & AGC_CAL_NF;
179
180         /* sitesurvey : 100 ms / current connected 200 ms */
181         while ((ret != 0) && loop--) {
182                 udelay(100);
183
184                 ret = get_async(AR9170_PHY_REG_AGC_CONTROL) & AGC_CAL_NF;
185         }
186
187         /* return the AGC/Noise calibration state to the driver */
188         return ret;
189 }
190
191 #define EIGHTY_FLAG (CARL9170FW_PHY_HT_ENABLE | CARL9170FW_PHY_HT_DYN2040)
192
193 static uint32_t rf_init(const uint32_t delta_slope_coeff_exp,
194                         const uint32_t delta_slope_coeff_man,
195                         const uint32_t delta_slope_coeff_exp_shgi,
196                         const uint32_t delta_slope_coeff_man_shgi,
197                         const uint32_t finiteLoopCount,
198                         const bool initialize)
199 {
200         uint32_t ret;
201
202         hw_turn_off_dyn(delta_slope_coeff_exp,
203                         delta_slope_coeff_man,
204                         delta_slope_coeff_exp_shgi,
205                         delta_slope_coeff_man_shgi);
206
207         if (initialize) {
208                 /* Real Chip */
209                 program_ADDAC();
210
211                 /* inverse chain 0 <-> chain 2 */
212                 set(AR9170_PHY_REG_ANALOG_SWAP, AR9170_PHY_ANALOG_SWAP_AB);
213
214                 /* swap chain 0 and chain 2 */
215                 set(AR9170_PHY_REG_ANALOG_SWAP, AR9170_PHY_ANALOG_SWAP_AB |
216                                                 AR9170_PHY_ANALOG_SWAP_ALT_CHAIN);
217
218                 /* Activate BB */
219                 set(AR9170_PHY_REG_ACTIVE, AR9170_PHY_ACTIVE_EN);
220                 delay(10);
221         }
222
223         ret = AGC_calibration(finiteLoopCount);
224
225         set_channel_end();
226         return ret;
227 }
228
229 void rf_cmd(const struct carl9170_cmd *cmd, struct carl9170_rsp *resp)
230 {
231         uint32_t ret;
232
233         fw.phy.ht_settings = cmd->rf_init.ht_settings;
234         fw.phy.frequency = cmd->rf_init.freq;
235
236         /*
237          * Is the clock controlled by the PHY?
238          */
239         if ((fw.phy.ht_settings & EIGHTY_FLAG) == EIGHTY_FLAG)
240                 clock_set(AHB_80_88MHZ, true);
241         else
242                 clock_set(AHB_40_44MHZ, true);
243
244         ret = rf_init(le32_to_cpu(cmd->rf_init.delta_slope_coeff_exp),
245                       le32_to_cpu(cmd->rf_init.delta_slope_coeff_man),
246                       le32_to_cpu(cmd->rf_init.delta_slope_coeff_exp_shgi),
247                       le32_to_cpu(cmd->rf_init.delta_slope_coeff_man_shgi),
248                       le32_to_cpu(cmd->rf_init.finiteLoopCount),
249                       cmd->hdr.cmd == CARL9170_CMD_RF_INIT);
250
251         resp->hdr.len = sizeof(struct carl9170_rf_init_result);
252         resp->rf_init_res.ret = cpu_to_le32(ret);
253 }
254
255 void rf_psm(void)
256 {
257         u32 bank3;
258
259         if (fw.phy.psm.state == CARL9170_PSM_SOFTWARE) {
260                 /* not enabled by the driver */
261                 return;
262         }
263
264         if (fw.phy.psm.state & CARL9170_PSM_SLEEP) {
265                 fw.phy.psm.state &= ~CARL9170_PSM_SLEEP;
266
267                 /* disable all agc gain and offset updates to a2 */
268                 set(AR9170_PHY_REG_TEST2, 0x8000000);
269
270                 /* power down ADDAC */
271                 set(AR9170_PHY_REG_ADC_CTL,
272                     AR9170_PHY_ADC_CTL_OFF_PWDDAC |
273                     AR9170_PHY_ADC_CTL_OFF_PWDADC |
274                     0xa0000000);
275
276                 /* Synthesizer off + RX off */
277                 bank3 = 0x00400018;
278
279                 tally_update();
280                 fw.phy.state = CARL9170_PHY_OFF;
281         } else {
282                 /* advance to the next PSM step */
283                 fw.phy.psm.state--;
284
285                 if (fw.phy.psm.state == CARL9170_PSM_WAKE) {
286                         /* wake up ADDAC */
287                         set(AR9170_PHY_REG_ADC_CTL,
288                             AR9170_PHY_ADC_CTL_OFF_PWDDAC |
289                             AR9170_PHY_ADC_CTL_OFF_PWDADC);
290
291                         /* enable all agc gain and offset updates to a2 */
292                         set(AR9170_PHY_REG_TEST2, 0x0);
293
294                         /* Synthesizer on + RX on */
295                         bank3 = 0x01420098;
296
297                         tally_update();
298                         fw.phy.state = CARL9170_PHY_ON;
299                 } else {
300                         return ;
301                 }
302         }
303
304         if (fw.phy.frequency < 3000000)
305                 bank3 |= 0x00800000;
306
307         set(0x1c58f0, bank3);
308 }
309
310 #endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */