carl9170 firmware: import 1.7.0
[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, 2010 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 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
33 static void set_channel_start(void)
34 {
35         /* Manipulate CCA threshold to stop transmission */
36         set(AR9170_PHY_REG_CCA_THRESHOLD, 0x300);
37         /* Enable Virtual CCA */
38         orl(AR9170_MAC_REG_QOS_PRIORITY_VIRTUAL_CCA,
39             AR9170_MAC_VIRTUAL_CCA_ALL);
40 }
41
42 static void set_channel_end(void)
43 {
44         /* Manipulate CCA threshold to resume transmission */
45         set(AR9170_PHY_REG_CCA_THRESHOLD, 0x0);
46         /* Disable Virtual CCA */
47         andl(AR9170_MAC_REG_QOS_PRIORITY_VIRTUAL_CCA,
48              ~AR9170_MAC_VIRTUAL_CCA_ALL);
49 }
50
51 void rf_notify_set_channel(void)
52 {
53         set_channel_start();
54 }
55
56 /*
57  * Update delta slope coeff man and exp
58  */
59 static void hw_turn_off_dyn(const uint32_t delta_slope_coeff_exp,
60                             const uint32_t delta_slope_coeff_man,
61                             const uint32_t delta_slope_coeff_exp_shgi,
62                             const uint32_t delta_slope_coeff_man_shgi)
63 {
64         uint32_t tmp;
65
66         tmp = get_async(AR9170_PHY_REG_TIMING3) & 0x00001fff;
67         tmp |= (delta_slope_coeff_man << AR9170_PHY_TIMING3_DSC_MAN_S) &
68                 AR9170_PHY_TIMING3_DSC_MAN;
69         tmp |= (delta_slope_coeff_exp << AR9170_PHY_TIMING3_DSC_EXP_S) &
70                 AR9170_PHY_TIMING3_DSC_EXP;
71
72         set(AR9170_PHY_REG_TIMING3, tmp);
73
74         tmp = (delta_slope_coeff_man_shgi << AR9170_PHY_HALFGI_DSC_MAN_S) &
75                 AR9170_PHY_HALFGI_DSC_MAN;
76
77         tmp |= (delta_slope_coeff_exp_shgi << AR9170_PHY_HALFGI_DSC_EXP_S) &
78                 AR9170_PHY_HALFGI_DSC_EXP;
79
80         set(AR9170_PHY_REG_HALFGI, tmp);
81 }
82
83 static void program_ADDAC(void)
84 {
85         /* ??? Select Internal ADDAC ??? (is external radio) */
86         set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_EXTERNAL_RADIO);
87
88         delay(10);
89
90         set(0x1c589c, 0x00000000);      /*# 7-0 */
91         set(0x1c589c, 0x00000000);      /*# 15-8 */
92         set(0x1c589c, 0x00000000);      /*# 23-16 */
93         set(0x1c589c, 0x00000000);      /*# 31- */
94
95         set(0x1c589c, 0x00000000);      /*# 39- */
96         set(0x1c589c, 0x00000000);      /*# 47- */
97         set(0x1c589c, 0x00000000);      /*# 55- [48]:doubles the xtalosc bias current */
98         set(0x1c589c, 0x00000000);      /*# 63- */
99
100         set(0x1c589c, 0x00000000);      /*# 71- */
101         set(0x1c589c, 0x00000000);      /*# 79- */
102         set(0x1c589c, 0x00000000);      /*# 87- */
103         set(0x1c589c, 0x00000000);      /*# 95- */
104
105         set(0x1c589c, 0x00000000);      /*# 103- */
106         set(0x1c589c, 0x00000000);      /*# 111- */
107         set(0x1c589c, 0x00000000);      /*# 119- */
108         set(0x1c589c, 0x00000000);      /*# 127- */
109
110         set(0x1c589c, 0x00000000);      /*# 135- */
111         set(0x1c589c, 0x00000000);      /*# 143- */
112         set(0x1c589c, 0x00000000);      /*# 151- */
113         set(0x1c589c, 0x00000030);      /*# 159- #[158:156]=xlnabufmode */
114
115         set(0x1c589c, 0x00000004);      /*# 167-  [162]:disable clkp_driver to flow */
116         set(0x1c589c, 0x00000000);      /*# 175- */
117         set(0x1c589c, 0x00000000);      /*# 183-176 */
118         set(0x1c589c, 0x00000000);      /*# 191-184 */
119
120         set(0x1c589c, 0x00000000);      /*# 199- */
121         set(0x1c589c, 0x00000000);      /*# 207- */
122         set(0x1c589c, 0x00000000);      /*# 215- */
123         set(0x1c589c, 0x00000000);      /*# 223- */
124
125         set(0x1c589c, 0x00000000);      /*# 231- */
126         set(0x1c58c4, 0x00000000);      /*# 233-232 */
127
128         delay(10);
129
130         /* Select External Flow ???? (is internal addac??) */
131         set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_INTERNAL_ADDAC);
132 }
133
134 static uint32_t AGC_calibration(uint32_t loop)
135 {
136         uint32_t wrdata;
137         uint32_t ret;
138
139 #define AGC_CAL_NF      (AR9170_PHY_AGC_CONTROL_CAL | AR9170_PHY_AGC_CONTROL_NF);
140
141         wrdata = get_async(AR9170_PHY_REG_AGC_CONTROL) | AGC_CAL_NF;
142         set(AR9170_PHY_REG_AGC_CONTROL, wrdata);
143
144         ret = get_async(AR9170_PHY_REG_AGC_CONTROL) & AGC_CAL_NF;
145
146         /* sitesurvey : 100 ms / current connected 200 ms */
147         while (loop && ret != 0x0) {
148                 ret = get_async(AR9170_PHY_REG_AGC_CONTROL) & AGC_CAL_NF;
149
150                 if (ret == 0)
151                         break;
152
153                 udelay(100);
154                 loop--;
155         }
156
157         /* return the AGC/Noise calibration state to the driver */
158         return ret;
159 }
160
161 #define EIGHTY_FLAG (CARL9170FW_PHY_HT_ENABLE | CARL9170FW_PHY_HT_DYN2040)
162
163 static uint32_t rf_init(const uint32_t delta_slope_coeff_exp,
164                         const uint32_t delta_slope_coeff_man,
165                         const uint32_t delta_slope_coeff_exp_shgi,
166                         const uint32_t delta_slope_coeff_man_shgi,
167                         const uint32_t finiteLoopCount,
168                         const bool initialize)
169 {
170         uint32_t ret;
171
172         hw_turn_off_dyn(delta_slope_coeff_exp,
173                         delta_slope_coeff_man,
174                         delta_slope_coeff_exp_shgi,
175                         delta_slope_coeff_man_shgi);
176
177         if (initialize) {
178                 /* Real Chip */
179                 program_ADDAC();
180
181                 /* inverse chain 0 <-> chain 2 */
182                 set(AR9170_PHY_REG_ANALOG_SWAP, AR9170_PHY_ANALOG_SWAP_AB);
183
184                 /* swap chain 0 and chain 2 */
185                 set(AR9170_PHY_REG_ANALOG_SWAP, AR9170_PHY_ANALOG_SWAP_AB |
186                                                 AR9170_PHY_ANALOG_SWAP_ALT_CHAIN);
187
188                 /* configure mask */
189                 set(AR9170_PHY_REG_RX_CHAINMASK, 0x5);  /* chain 0 + chain 2 */
190                 set(AR9170_PHY_REG_CAL_CHAINMASK, 0x5); /* chain 0 + chain 2 */
191
192                 /* Activate BB */
193                 set(AR9170_PHY_REG_ACTIVE, AR9170_PHY_ACTIVE_EN);
194                 delay(10);
195         }
196
197         ret = AGC_calibration(finiteLoopCount);
198
199         set_channel_end();
200         return ret;
201 }
202
203 void rf_cmd(const struct carl9170_cmd *cmd, struct carl9170_rsp *resp)
204 {
205         uint32_t ret;
206
207         fw.phy.ht_settings = cmd->rf_init.ht_settings;
208         fw.phy.frequency = cmd->rf_init.freq;
209
210         if ((fw.phy.ht_settings & EIGHTY_FLAG) == EIGHTY_FLAG)
211                 clock_set(true, AHB_80_88MHZ);
212         else
213                 clock_set(true, AHB_40_44MHZ);
214
215         ret = rf_init(le32_to_cpu(cmd->rf_init.delta_slope_coeff_exp),
216                       le32_to_cpu(cmd->rf_init.delta_slope_coeff_man),
217                       le32_to_cpu(cmd->rf_init.delta_slope_coeff_exp_shgi),
218                       le32_to_cpu(cmd->rf_init.delta_slope_coeff_man_shgi),
219                       le32_to_cpu(cmd->rf_init.finiteLoopCount),
220                       cmd->hdr.cmd == CARL9170_CMD_RF_INIT);
221
222         resp->hdr.len = sizeof(struct carl9170_rf_init_result);
223         resp->rf_init_res.ret = cpu_to_le32(ret);
224
225         resp->rf_init_res.regs[0] = get(AR9170_PHY_REG_CCA);
226         resp->rf_init_res.regs[3] = get(AR9170_PHY_REG_EXT_CCA);
227
228         resp->rf_init_res.regs[1] = get(AR9170_PHY_REG_CH1_CCA);
229         resp->rf_init_res.regs[4] = get(AR9170_PHY_REG_CH1_EXT_CCA);
230
231         resp->rf_init_res.regs[2] = get(AR9170_PHY_REG_CH2_CCA);
232         resp->rf_init_res.regs[5] = get(AR9170_PHY_REG_CH2_EXT_CCA);
233 }
234
235 #ifdef CONFIG_CARL9170FW_PSM
236 void rf_psm(void)
237 {
238         u32 bank3;
239
240         /*
241          * FIXME: Does not work on 5GHz band!
242          */
243
244         if (fw.phy.psm.state == CARL9170_PSM_SOFTWARE) {
245                 /* not enabled by the driver */
246                 return;
247         }
248
249         if (fw.phy.psm.state & CARL9170_PSM_SLEEP) {
250                 fw.phy.psm.state &= ~CARL9170_PSM_SLEEP;
251
252                 /* disable all agc gain and offset updates to a2 */
253                 set(AR9170_PHY_REG_TEST2, 0x8000000);
254
255                 /* power down ADDAC */
256                 set(AR9170_PHY_REG_ADC_CTL,
257                     AR9170_PHY_ADC_CTL_OFF_PWDDAC |
258                     AR9170_PHY_ADC_CTL_OFF_PWDADC |
259                     0xa0000000);
260
261                 /* Synthesizer off + RX off */
262                 bank3 = 0x00400018;
263
264                 clock_set(true, AHB_20_22MHZ);
265         } else {
266                 /* advance to the next PSM step */
267                 fw.phy.psm.state--;
268
269                 if (fw.phy.psm.state == CARL9170_PSM_WAKE) {
270                         /* wake up ADDAC */
271                         set(AR9170_PHY_REG_ADC_CTL,
272                             AR9170_PHY_ADC_CTL_OFF_PWDDAC |
273                             AR9170_PHY_ADC_CTL_OFF_PWDADC);
274
275                         /* enable all agc gain and offset updates to a2 */
276                         set(AR9170_PHY_REG_TEST2, 0x0);
277
278                         /* Synthesizer on + RX on */
279                         bank3 = 0x01420098;
280
281                         if ((fw.phy.ht_settings & EIGHTY_FLAG) == EIGHTY_FLAG)
282                                 clock_set(true, AHB_80_88MHZ);
283                         else
284                                 clock_set(true, AHB_40_44MHZ);
285                 } else {
286                         return ;
287                 }
288         }
289
290         if (fw.phy.frequency < 30000000)
291                 bank3 |= 0x00800000;
292
293         set(0x1c58f0, bank3);
294 }
295 #endif /* CONFIG_CARL9170FW_PSM */
296
297 #endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */