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