blob: 747e576950f4f5989beba1b8d9a2c0dd785ec2d1 [file] [log] [blame]
Johannes Berge9676692012-04-10 14:10:28 -07001/******************************************************************************
2 *
3 * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * Intel Linux Wireless <ilw@linux.intel.com>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27/*
28 * DVM device-specific data & functions
29 */
Johannes Berge9676692012-04-10 14:10:28 -070030#include "iwl-io.h"
31#include "iwl-prph.h"
Johannes Berg26a7ca92012-05-21 11:55:54 +020032#include "iwl-eeprom-parse.h"
Johannes Berge9676692012-04-10 14:10:28 -070033
Johannes Berg1023fdc2012-05-15 12:16:34 +020034#include "agn.h"
35#include "dev.h"
36#include "commands.h"
37
Johannes Berg26a7ca92012-05-21 11:55:54 +020038
39#define EEPROM_RF_CONFIG_TYPE_MAX 0x3
40
41static void iwl_rf_config(struct iwl_priv *priv)
42{
43 u16 radio_cfg = priv->eeprom_data->radio_cfg;
44
45 /* write radio config values to register */
46 if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) {
47 u32 reg_val =
48 EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <<
49 CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE |
50 EEPROM_RF_CFG_STEP_MSK(radio_cfg) <<
51 CSR_HW_IF_CONFIG_REG_POS_PHY_STEP |
52 EEPROM_RF_CFG_DASH_MSK(radio_cfg) <<
53 CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
54
55 iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
56 CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
57 CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
58 CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val);
59
60 IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
61 EEPROM_RF_CFG_TYPE_MSK(radio_cfg),
62 EEPROM_RF_CFG_STEP_MSK(radio_cfg),
63 EEPROM_RF_CFG_DASH_MSK(radio_cfg));
64 } else {
65 WARN_ON(1);
66 }
67
68 /* set CSR_HW_CONFIG_REG for uCode use */
69 iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
70 CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
71 CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
72}
73
Johannes Berge9676692012-04-10 14:10:28 -070074/*
75 * 1000 series
76 * ===========
77 */
78
79/*
80 * For 1000, use advance thermal throttling critical temperature threshold,
81 * but legacy thermal management implementation for now.
82 * This is for the reason of 1000 uCode using advance thermal throttling API
83 * but not implement ct_kill_exit based on ct_kill exit temperature
84 * so the thermal throttling will still based on legacy thermal throttling
85 * management.
86 * The code here need to be modified once 1000 uCode has the advanced thermal
87 * throttling algorithm in place
88 */
89static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
90{
91 /* want Celsius */
92 priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
93 priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
94}
95
96/* NIC configuration for 1000 series */
97static void iwl1000_nic_config(struct iwl_priv *priv)
98{
99 /* set CSR_HW_CONFIG_REG for uCode use */
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700100 iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700101 CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
102 CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
103
104 /* Setting digital SVR for 1000 card to 1.32V */
105 /* locking is acquired in iwl_set_bits_mask_prph() function */
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700106 iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700107 APMG_SVR_DIGITAL_VOLTAGE_1_32,
108 ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
109}
110
Meenakshi Venkataramane381b212012-03-13 15:18:07 -0700111/**
112 * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
113 * @priv -- pointer to iwl_priv data structure
114 * @tsf_bits -- number of bits need to shift for masking)
115 */
116static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
117 u16 tsf_bits)
118{
119 return (1 << tsf_bits) - 1;
120}
121
122/**
123 * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
124 * @priv -- pointer to iwl_priv data structure
125 * @tsf_bits -- number of bits need to shift for masking)
126 */
127static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
128 u16 tsf_bits)
129{
130 return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
131}
132
133/*
134 * extended beacon time format
135 * time in usec will be changed into a 32-bit value in extended:internal format
136 * the extended part is the beacon counts
137 * the internal part is the time in usec within one beacon interval
138 */
139static u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec,
140 u32 beacon_interval)
141{
142 u32 quot;
143 u32 rem;
144 u32 interval = beacon_interval * TIME_UNIT;
145
146 if (!interval || !usec)
147 return 0;
148
149 quot = (usec / interval) &
150 (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >>
151 IWLAGN_EXT_BEACON_TIME_POS);
152 rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
153 IWLAGN_EXT_BEACON_TIME_POS);
154
155 return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
156}
157
158/* base is usually what we get from ucode with each received frame,
159 * the same as HW timer counter counting down
160 */
161static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
162 u32 addon, u32 beacon_interval)
163{
164 u32 base_low = base & iwl_beacon_time_mask_low(priv,
165 IWLAGN_EXT_BEACON_TIME_POS);
166 u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
167 IWLAGN_EXT_BEACON_TIME_POS);
168 u32 interval = beacon_interval * TIME_UNIT;
169 u32 res = (base & iwl_beacon_time_mask_high(priv,
170 IWLAGN_EXT_BEACON_TIME_POS)) +
171 (addon & iwl_beacon_time_mask_high(priv,
172 IWLAGN_EXT_BEACON_TIME_POS));
173
174 if (base_low > addon_low)
175 res += base_low - addon_low;
176 else if (base_low < addon_low) {
177 res += interval + base_low - addon_low;
178 res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
179 } else
180 res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
181
182 return cpu_to_le32(res);
183}
184
Johannes Berge9676692012-04-10 14:10:28 -0700185static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
186 .min_nrg_cck = 95,
187 .auto_corr_min_ofdm = 90,
188 .auto_corr_min_ofdm_mrc = 170,
189 .auto_corr_min_ofdm_x1 = 120,
190 .auto_corr_min_ofdm_mrc_x1 = 240,
191
192 .auto_corr_max_ofdm = 120,
193 .auto_corr_max_ofdm_mrc = 210,
194 .auto_corr_max_ofdm_x1 = 155,
195 .auto_corr_max_ofdm_mrc_x1 = 290,
196
197 .auto_corr_min_cck = 125,
198 .auto_corr_max_cck = 200,
199 .auto_corr_min_cck_mrc = 170,
200 .auto_corr_max_cck_mrc = 400,
201 .nrg_th_cck = 95,
202 .nrg_th_ofdm = 95,
203
204 .barker_corr_th_min = 190,
205 .barker_corr_th_min_mrc = 390,
206 .nrg_th_cca = 62,
207};
208
209static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
210{
Johannes Berge9676692012-04-10 14:10:28 -0700211 iwl1000_set_ct_threshold(priv);
212
213 /* Set initial sensitivity parameters */
214 priv->hw_params.sens = &iwl1000_sensitivity;
215}
216
217struct iwl_lib_ops iwl1000_lib = {
218 .set_hw_params = iwl1000_hw_set_hw_params,
219 .nic_config = iwl1000_nic_config,
Johannes Berge9676692012-04-10 14:10:28 -0700220 .temperature = iwlagn_temperature,
221};
222
223
224/*
225 * 2000 series
226 * ===========
227 */
228
229static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
230{
231 /* want Celsius */
232 priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
233 priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
234}
235
236/* NIC configuration for 2000 series */
237static void iwl2000_nic_config(struct iwl_priv *priv)
238{
239 iwl_rf_config(priv);
240
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700241 iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700242 CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
243}
244
245static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
246 .min_nrg_cck = 97,
247 .auto_corr_min_ofdm = 80,
248 .auto_corr_min_ofdm_mrc = 128,
249 .auto_corr_min_ofdm_x1 = 105,
250 .auto_corr_min_ofdm_mrc_x1 = 192,
251
252 .auto_corr_max_ofdm = 145,
253 .auto_corr_max_ofdm_mrc = 232,
254 .auto_corr_max_ofdm_x1 = 110,
255 .auto_corr_max_ofdm_mrc_x1 = 232,
256
257 .auto_corr_min_cck = 125,
258 .auto_corr_max_cck = 175,
259 .auto_corr_min_cck_mrc = 160,
260 .auto_corr_max_cck_mrc = 310,
261 .nrg_th_cck = 97,
262 .nrg_th_ofdm = 100,
263
264 .barker_corr_th_min = 190,
265 .barker_corr_th_min_mrc = 390,
266 .nrg_th_cca = 62,
267};
268
269static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
270{
Johannes Berge9676692012-04-10 14:10:28 -0700271 iwl2000_set_ct_threshold(priv);
272
273 /* Set initial sensitivity parameters */
274 priv->hw_params.sens = &iwl2000_sensitivity;
275}
276
277struct iwl_lib_ops iwl2000_lib = {
278 .set_hw_params = iwl2000_hw_set_hw_params,
279 .nic_config = iwl2000_nic_config,
Johannes Berge9676692012-04-10 14:10:28 -0700280 .temperature = iwlagn_temperature,
281};
282
283struct iwl_lib_ops iwl2030_lib = {
284 .set_hw_params = iwl2000_hw_set_hw_params,
285 .nic_config = iwl2000_nic_config,
Johannes Berge9676692012-04-10 14:10:28 -0700286 .temperature = iwlagn_temperature,
287};
288
289/*
290 * 5000 series
291 * ===========
292 */
293
294/* NIC configuration for 5000 series */
295static void iwl5000_nic_config(struct iwl_priv *priv)
296{
297 iwl_rf_config(priv);
298
299 /* W/A : NIC is stuck in a reset state after Early PCIe power off
300 * (PCIe power is lost before PERST# is asserted),
301 * causing ME FW to lose ownership and not being able to obtain it back.
302 */
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700303 iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700304 APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
305 ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
306}
307
308static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
309 .min_nrg_cck = 100,
310 .auto_corr_min_ofdm = 90,
311 .auto_corr_min_ofdm_mrc = 170,
312 .auto_corr_min_ofdm_x1 = 105,
313 .auto_corr_min_ofdm_mrc_x1 = 220,
314
315 .auto_corr_max_ofdm = 120,
316 .auto_corr_max_ofdm_mrc = 210,
317 .auto_corr_max_ofdm_x1 = 120,
318 .auto_corr_max_ofdm_mrc_x1 = 240,
319
320 .auto_corr_min_cck = 125,
321 .auto_corr_max_cck = 200,
322 .auto_corr_min_cck_mrc = 200,
323 .auto_corr_max_cck_mrc = 400,
324 .nrg_th_cck = 100,
325 .nrg_th_ofdm = 100,
326
327 .barker_corr_th_min = 190,
328 .barker_corr_th_min_mrc = 390,
329 .nrg_th_cca = 62,
330};
331
332static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
333 .min_nrg_cck = 95,
334 .auto_corr_min_ofdm = 90,
335 .auto_corr_min_ofdm_mrc = 170,
336 .auto_corr_min_ofdm_x1 = 105,
337 .auto_corr_min_ofdm_mrc_x1 = 220,
338
339 .auto_corr_max_ofdm = 120,
340 .auto_corr_max_ofdm_mrc = 210,
341 /* max = min for performance bug in 5150 DSP */
342 .auto_corr_max_ofdm_x1 = 105,
343 .auto_corr_max_ofdm_mrc_x1 = 220,
344
345 .auto_corr_min_cck = 125,
346 .auto_corr_max_cck = 200,
347 .auto_corr_min_cck_mrc = 170,
348 .auto_corr_max_cck_mrc = 400,
349 .nrg_th_cck = 95,
350 .nrg_th_ofdm = 95,
351
352 .barker_corr_th_min = 190,
353 .barker_corr_th_min_mrc = 390,
354 .nrg_th_cca = 62,
355};
356
357#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5)
358
359static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
360{
361 u16 temperature, voltage;
Johannes Berge9676692012-04-10 14:10:28 -0700362
Johannes Berg26a7ca92012-05-21 11:55:54 +0200363 temperature = le16_to_cpu(priv->eeprom_data->kelvin_temperature);
364 voltage = le16_to_cpu(priv->eeprom_data->kelvin_voltage);
Johannes Berge9676692012-04-10 14:10:28 -0700365
366 /* offset = temp - volt / coeff */
367 return (s32)(temperature -
368 voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
369}
370
371static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
372{
373 const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
374 s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
375 iwl_temp_calib_to_offset(priv);
376
377 priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
378}
379
380static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
381{
382 /* want Celsius */
383 priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
384}
385
386static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
387{
Johannes Berge9676692012-04-10 14:10:28 -0700388 iwl5000_set_ct_threshold(priv);
389
390 /* Set initial sensitivity parameters */
391 priv->hw_params.sens = &iwl5000_sensitivity;
392}
393
394static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
395{
Johannes Berge9676692012-04-10 14:10:28 -0700396 iwl5150_set_ct_threshold(priv);
397
398 /* Set initial sensitivity parameters */
399 priv->hw_params.sens = &iwl5150_sensitivity;
400}
401
402static void iwl5150_temperature(struct iwl_priv *priv)
403{
404 u32 vt = 0;
405 s32 offset = iwl_temp_calib_to_offset(priv);
406
407 vt = le32_to_cpu(priv->statistics.common.temperature);
408 vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
409 /* now vt hold the temperature in Kelvin */
410 priv->temperature = KELVIN_TO_CELSIUS(vt);
411 iwl_tt_handler(priv);
412}
413
414static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
415 struct ieee80211_channel_switch *ch_switch)
416{
417 /*
418 * MULTI-FIXME
419 * See iwlagn_mac_channel_switch.
420 */
421 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
422 struct iwl5000_channel_switch_cmd cmd;
Johannes Berge9676692012-04-10 14:10:28 -0700423 u32 switch_time_in_usec, ucode_switch_time;
424 u16 ch;
425 u32 tsf_low;
426 u8 switch_count;
427 u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
428 struct ieee80211_vif *vif = ctx->vif;
429 struct iwl_host_cmd hcmd = {
430 .id = REPLY_CHANNEL_SWITCH,
431 .len = { sizeof(cmd), },
432 .flags = CMD_SYNC,
433 .data = { &cmd, },
434 };
435
436 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
437 ch = ch_switch->channel->hw_value;
438 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
439 ctx->active.channel, ch);
440 cmd.channel = cpu_to_le16(ch);
441 cmd.rxon_flags = ctx->staging.flags;
442 cmd.rxon_filter_flags = ctx->staging.filter_flags;
443 switch_count = ch_switch->count;
444 tsf_low = ch_switch->timestamp & 0x0ffffffff;
445 /*
446 * calculate the ucode channel switch time
447 * adding TSF as one of the factor for when to switch
448 */
449 if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
450 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
451 beacon_interval)) {
452 switch_count -= (priv->ucode_beacon_time -
453 tsf_low) / beacon_interval;
454 } else
455 switch_count = 0;
456 }
457 if (switch_count <= 1)
458 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
459 else {
460 switch_time_in_usec =
461 vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
462 ucode_switch_time = iwl_usecs_to_beacons(priv,
463 switch_time_in_usec,
464 beacon_interval);
465 cmd.switch_time = iwl_add_beacon_time(priv,
466 priv->ucode_beacon_time,
467 ucode_switch_time,
468 beacon_interval);
469 }
470 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
471 cmd.switch_time);
Johannes Bergcc668802012-05-16 16:37:57 +0200472 cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
Johannes Berge9676692012-04-10 14:10:28 -0700473
474 return iwl_dvm_send_cmd(priv, &hcmd);
475}
476
477struct iwl_lib_ops iwl5000_lib = {
478 .set_hw_params = iwl5000_hw_set_hw_params,
479 .set_channel_switch = iwl5000_hw_channel_switch,
480 .nic_config = iwl5000_nic_config,
Johannes Berge9676692012-04-10 14:10:28 -0700481 .temperature = iwlagn_temperature,
482};
483
484struct iwl_lib_ops iwl5150_lib = {
485 .set_hw_params = iwl5150_hw_set_hw_params,
486 .set_channel_switch = iwl5000_hw_channel_switch,
487 .nic_config = iwl5000_nic_config,
Johannes Berge9676692012-04-10 14:10:28 -0700488 .temperature = iwl5150_temperature,
489};
490
491
492
493/*
494 * 6000 series
495 * ===========
496 */
497
498static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
499{
500 /* want Celsius */
501 priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
502 priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
503}
504
505/* NIC configuration for 6000 series */
506static void iwl6000_nic_config(struct iwl_priv *priv)
507{
508 iwl_rf_config(priv);
509
Emmanuel Grumbach21522682012-03-22 17:51:44 +0200510 switch (priv->cfg->device_family) {
Johannes Berge9676692012-04-10 14:10:28 -0700511 case IWL_DEVICE_FAMILY_6005:
512 case IWL_DEVICE_FAMILY_6030:
513 case IWL_DEVICE_FAMILY_6000:
514 break;
515 case IWL_DEVICE_FAMILY_6000i:
516 /* 2x2 IPA phy type */
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700517 iwl_write32(priv->trans, CSR_GP_DRIVER_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700518 CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
519 break;
520 case IWL_DEVICE_FAMILY_6050:
521 /* Indicate calibration version to uCode. */
Johannes Berg26a7ca92012-05-21 11:55:54 +0200522 if (priv->eeprom_data->calib_version >= 6)
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700523 iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700524 CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
525 break;
526 case IWL_DEVICE_FAMILY_6150:
527 /* Indicate calibration version to uCode. */
Johannes Berg26a7ca92012-05-21 11:55:54 +0200528 if (priv->eeprom_data->calib_version >= 6)
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700529 iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700530 CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
Emmanuel Grumbach68e8dfd2012-04-18 07:28:17 -0700531 iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
Johannes Berge9676692012-04-10 14:10:28 -0700532 CSR_GP_DRIVER_REG_BIT_6050_1x2);
533 break;
534 default:
535 WARN_ON(1);
536 }
537}
538
539static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
540 .min_nrg_cck = 110,
541 .auto_corr_min_ofdm = 80,
542 .auto_corr_min_ofdm_mrc = 128,
543 .auto_corr_min_ofdm_x1 = 105,
544 .auto_corr_min_ofdm_mrc_x1 = 192,
545
546 .auto_corr_max_ofdm = 145,
547 .auto_corr_max_ofdm_mrc = 232,
548 .auto_corr_max_ofdm_x1 = 110,
549 .auto_corr_max_ofdm_mrc_x1 = 232,
550
551 .auto_corr_min_cck = 125,
552 .auto_corr_max_cck = 175,
553 .auto_corr_min_cck_mrc = 160,
554 .auto_corr_max_cck_mrc = 310,
555 .nrg_th_cck = 110,
556 .nrg_th_ofdm = 110,
557
558 .barker_corr_th_min = 190,
559 .barker_corr_th_min_mrc = 336,
560 .nrg_th_cca = 62,
561};
562
563static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
564{
Johannes Berge9676692012-04-10 14:10:28 -0700565 iwl6000_set_ct_threshold(priv);
566
567 /* Set initial sensitivity parameters */
568 priv->hw_params.sens = &iwl6000_sensitivity;
569
570}
571
572static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
573 struct ieee80211_channel_switch *ch_switch)
574{
575 /*
576 * MULTI-FIXME
577 * See iwlagn_mac_channel_switch.
578 */
579 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
580 struct iwl6000_channel_switch_cmd cmd;
Johannes Berge9676692012-04-10 14:10:28 -0700581 u32 switch_time_in_usec, ucode_switch_time;
582 u16 ch;
583 u32 tsf_low;
584 u8 switch_count;
585 u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
586 struct ieee80211_vif *vif = ctx->vif;
587 struct iwl_host_cmd hcmd = {
588 .id = REPLY_CHANNEL_SWITCH,
589 .len = { sizeof(cmd), },
590 .flags = CMD_SYNC,
591 .data = { &cmd, },
592 };
593
594 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
595 ch = ch_switch->channel->hw_value;
596 IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
597 ctx->active.channel, ch);
598 cmd.channel = cpu_to_le16(ch);
599 cmd.rxon_flags = ctx->staging.flags;
600 cmd.rxon_filter_flags = ctx->staging.filter_flags;
601 switch_count = ch_switch->count;
602 tsf_low = ch_switch->timestamp & 0x0ffffffff;
603 /*
604 * calculate the ucode channel switch time
605 * adding TSF as one of the factor for when to switch
606 */
607 if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
608 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
609 beacon_interval)) {
610 switch_count -= (priv->ucode_beacon_time -
611 tsf_low) / beacon_interval;
612 } else
613 switch_count = 0;
614 }
615 if (switch_count <= 1)
616 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
617 else {
618 switch_time_in_usec =
619 vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
620 ucode_switch_time = iwl_usecs_to_beacons(priv,
621 switch_time_in_usec,
622 beacon_interval);
623 cmd.switch_time = iwl_add_beacon_time(priv,
624 priv->ucode_beacon_time,
625 ucode_switch_time,
626 beacon_interval);
627 }
628 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
629 cmd.switch_time);
Johannes Bergcc668802012-05-16 16:37:57 +0200630 cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
Johannes Berge9676692012-04-10 14:10:28 -0700631
632 return iwl_dvm_send_cmd(priv, &hcmd);
633}
634
635struct iwl_lib_ops iwl6000_lib = {
636 .set_hw_params = iwl6000_hw_set_hw_params,
637 .set_channel_switch = iwl6000_hw_channel_switch,
638 .nic_config = iwl6000_nic_config,
Johannes Berge9676692012-04-10 14:10:28 -0700639 .temperature = iwlagn_temperature,
640};
641
642struct iwl_lib_ops iwl6030_lib = {
643 .set_hw_params = iwl6000_hw_set_hw_params,
644 .set_channel_switch = iwl6000_hw_channel_switch,
645 .nic_config = iwl6000_nic_config,
Johannes Berge9676692012-04-10 14:10:28 -0700646 .temperature = iwlagn_temperature,
647};