blob: 725e954d8475284a0f2b6332d3627c638dd6d01a [file] [log] [blame]
Johannes Bergb1e1adf2013-01-24 14:14:22 +01001/******************************************************************************
2 *
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * GPL LICENSE SUMMARY
7 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +02008 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
Johannes Bergb1e1adf2013-01-24 14:14:22 +01009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
22 * USA
23 *
24 * The full GNU General Public License is included in this distribution
Emmanuel Grumbach410dc5a2013-02-18 09:22:28 +020025 * in the file called COPYING.
Johannes Bergb1e1adf2013-01-24 14:14:22 +010026 *
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30 *
31 * BSD LICENSE
32 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +020033 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
Johannes Bergb1e1adf2013-01-24 14:14:22 +010034 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 *
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
45 * distribution.
46 * * Neither the name Intel Corporation nor the names of its
47 * contributors may be used to endorse or promote products derived
48 * from this software without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 *****************************************************************************/
62#include <linux/types.h>
63#include <linux/slab.h>
64#include <linux/export.h>
Johannes Berg48e29342013-03-01 00:13:33 +010065#include "iwl-drv.h"
Johannes Bergb1e1adf2013-01-24 14:14:22 +010066#include "iwl-modparams.h"
67#include "iwl-nvm-parse.h"
68
69/* NVM offsets (in words) definitions */
70enum wkp_nvm_offsets {
71 /* NVM HW-Section offset (in words) definitions */
72 HW_ADDR = 0x15,
73
74/* NVM SW-Section offset (in words) definitions */
75 NVM_SW_SECTION = 0x1C0,
76 NVM_VERSION = 0,
77 RADIO_CFG = 1,
78 SKU = 2,
79 N_HW_ADDRS = 3,
80 NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
81
82/* NVM calibration section offset (in words) definitions */
83 NVM_CALIB_SECTION = 0x2B8,
84 XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
85};
86
87/* SKU Capabilities (actual values from NVM definition) */
88enum nvm_sku_bits {
89 NVM_SKU_CAP_BAND_24GHZ = BIT(0),
90 NVM_SKU_CAP_BAND_52GHZ = BIT(1),
91 NVM_SKU_CAP_11N_ENABLE = BIT(2),
Johannes Bergbfc824b2013-05-06 16:06:51 +020092 NVM_SKU_CAP_11AC_ENABLE = BIT(3),
Johannes Bergb1e1adf2013-01-24 14:14:22 +010093};
94
95/* radio config bits (actual values from NVM definition) */
96#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */
97#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
98#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
99#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
100#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
101#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
102
103/*
104 * These are the channel numbers in the order that they are stored in the NVM
105 */
106static const u8 iwl_nvm_channels[] = {
107 /* 2.4 GHz */
108 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
109 /* 5 GHz */
110 36, 40, 44 , 48, 52, 56, 60, 64,
111 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
112 149, 153, 157, 161, 165
113};
114
115#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
116#define NUM_2GHZ_CHANNELS 14
117#define FIRST_2GHZ_HT_MINUS 5
118#define LAST_2GHZ_HT_PLUS 9
119#define LAST_5GHZ_HT 161
120
Matti Gottlieb88f2fd72013-07-09 15:25:46 +0300121#define DEFAULT_MAX_TX_POWER 16
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100122
123/* rate data (static) */
124static struct ieee80211_rate iwl_cfg80211_rates[] = {
125 { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
126 { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
127 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
128 { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
129 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
130 { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
131 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
132 { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
133 { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
134 { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
135 { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
136 { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
137 { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
138 { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
139 { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
140};
141#define RATES_24_OFFS 0
142#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates)
143#define RATES_52_OFFS 4
144#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS)
145
146/**
147 * enum iwl_nvm_channel_flags - channel flags in NVM
148 * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo
149 * @NVM_CHANNEL_IBSS: usable as an IBSS channel
150 * @NVM_CHANNEL_ACTIVE: active scanning allowed
151 * @NVM_CHANNEL_RADAR: radar detection required
152 * @NVM_CHANNEL_DFS: dynamic freq selection candidate
153 * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
154 * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200155 * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
156 * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100157 */
158enum iwl_nvm_channel_flags {
159 NVM_CHANNEL_VALID = BIT(0),
160 NVM_CHANNEL_IBSS = BIT(1),
161 NVM_CHANNEL_ACTIVE = BIT(3),
162 NVM_CHANNEL_RADAR = BIT(4),
163 NVM_CHANNEL_DFS = BIT(7),
164 NVM_CHANNEL_WIDE = BIT(8),
165 NVM_CHANNEL_40MHZ = BIT(9),
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200166 NVM_CHANNEL_80MHZ = BIT(10),
167 NVM_CHANNEL_160MHZ = BIT(11),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100168};
169
170#define CHECK_AND_PRINT_I(x) \
171 ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
172
173static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
174 struct iwl_nvm_data *data,
175 const __le16 * const nvm_ch_flags)
176{
177 int ch_idx;
178 int n_channels = 0;
179 struct ieee80211_channel *channel;
180 u16 ch_flags;
181 bool is_5ghz;
182
183 for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
184 ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200185
186 if (ch_idx >= NUM_2GHZ_CHANNELS &&
187 !data->sku_cap_band_52GHz_enable)
188 ch_flags &= ~NVM_CHANNEL_VALID;
189
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100190 if (!(ch_flags & NVM_CHANNEL_VALID)) {
191 IWL_DEBUG_EEPROM(dev,
192 "Ch. %d Flags %x [%sGHz] - No traffic\n",
193 iwl_nvm_channels[ch_idx],
194 ch_flags,
195 (ch_idx >= NUM_2GHZ_CHANNELS) ?
196 "5.2" : "2.4");
197 continue;
198 }
199
200 channel = &data->channels[n_channels];
201 n_channels++;
202
203 channel->hw_value = iwl_nvm_channels[ch_idx];
204 channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
205 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
206 channel->center_freq =
207 ieee80211_channel_to_frequency(
208 channel->hw_value, channel->band);
209
210 /* TODO: Need to be dependent to the NVM */
211 channel->flags = IEEE80211_CHAN_NO_HT40;
212 if (ch_idx < NUM_2GHZ_CHANNELS &&
213 (ch_flags & NVM_CHANNEL_40MHZ)) {
214 if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
215 channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
216 if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
217 channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
218 } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
219 (ch_flags & NVM_CHANNEL_40MHZ)) {
220 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
221 channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
222 else
223 channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
224 }
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200225 if (!(ch_flags & NVM_CHANNEL_80MHZ))
226 channel->flags |= IEEE80211_CHAN_NO_80MHZ;
227 if (!(ch_flags & NVM_CHANNEL_160MHZ))
228 channel->flags |= IEEE80211_CHAN_NO_160MHZ;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100229
230 if (!(ch_flags & NVM_CHANNEL_IBSS))
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200231 channel->flags |= IEEE80211_CHAN_NO_IR;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100232
233 if (!(ch_flags & NVM_CHANNEL_ACTIVE))
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200234 channel->flags |= IEEE80211_CHAN_NO_IR;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100235
236 if (ch_flags & NVM_CHANNEL_RADAR)
237 channel->flags |= IEEE80211_CHAN_RADAR;
238
239 /* Initialize regulatory-based run-time data */
240
Matti Gottlieb88f2fd72013-07-09 15:25:46 +0300241 /*
242 * Default value - highest tx power value. max_power
243 * is not used in mvm, and is used for backwards compatibility
244 */
245 channel->max_power = DEFAULT_MAX_TX_POWER;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100246 is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
247 IWL_DEBUG_EEPROM(dev,
248 "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
249 channel->hw_value,
250 is_5ghz ? "5.2" : "2.4",
251 CHECK_AND_PRINT_I(VALID),
252 CHECK_AND_PRINT_I(IBSS),
253 CHECK_AND_PRINT_I(ACTIVE),
254 CHECK_AND_PRINT_I(RADAR),
255 CHECK_AND_PRINT_I(WIDE),
256 CHECK_AND_PRINT_I(DFS),
257 ch_flags,
258 channel->max_power,
259 ((ch_flags & NVM_CHANNEL_IBSS) &&
260 !(ch_flags & NVM_CHANNEL_RADAR))
261 ? "" : "not ");
262 }
263
264 return n_channels;
265}
266
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200267static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
268 struct iwl_nvm_data *data,
269 struct ieee80211_sta_vht_cap *vht_cap)
270{
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200271 int num_ants = num_of_ant(data->valid_rx_ant);
Eyal Shapira48e6de62013-11-03 10:04:08 +0200272
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200273 vht_cap->vht_supported = true;
274
275 vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
276 IEEE80211_VHT_CAP_RXSTBC_1 |
277 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
Eyal Shapirae36b7662014-01-06 20:16:48 +0200278 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200279 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
280
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200281 if (num_ants > 1)
282 vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
283
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200284 if (iwlwifi_mod_params.amsdu_size_8K)
285 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
286
287 vht_cap->vht_mcs.rx_mcs_map =
288 cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
289 IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
290 IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
291 IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
292 IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
293 IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
294 IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
295 IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
296
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200297 if (num_ants == 1 ||
Eyal Shapiraa7b8b2c2013-11-07 19:38:04 +0200298 cfg->rx_with_siso_diversity) {
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200299 vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
300 IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
301 /* this works because NOT_SUPPORTED == 3 */
302 vht_cap->vht_mcs.rx_mcs_map |=
303 cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
304 }
305
306 vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
307}
308
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100309static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
Johannes Bergbfc824b2013-05-06 16:06:51 +0200310 struct iwl_nvm_data *data, const __le16 *nvm_sw,
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300311 bool enable_vht, u8 tx_chains, u8 rx_chains)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100312{
313 int n_channels = iwl_init_channel_map(dev, cfg, data,
314 &nvm_sw[NVM_CHANNELS]);
315 int n_used = 0;
316 struct ieee80211_supported_band *sband;
317
318 sband = &data->bands[IEEE80211_BAND_2GHZ];
319 sband->band = IEEE80211_BAND_2GHZ;
320 sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
321 sband->n_bitrates = N_RATES_24;
322 n_used += iwl_init_sband_channels(data, sband, n_channels,
323 IEEE80211_BAND_2GHZ);
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300324 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ,
325 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100326
327 sband = &data->bands[IEEE80211_BAND_5GHZ];
328 sband->band = IEEE80211_BAND_5GHZ;
329 sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
330 sband->n_bitrates = N_RATES_52;
331 n_used += iwl_init_sband_channels(data, sband, n_channels,
332 IEEE80211_BAND_5GHZ);
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300333 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
334 tx_chains, rx_chains);
Johannes Bergbfc824b2013-05-06 16:06:51 +0200335 if (enable_vht)
336 iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100337
338 if (n_channels != n_used)
339 IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
340 n_used, n_channels);
341}
342
343struct iwl_nvm_data *
344iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
345 const __le16 *nvm_hw, const __le16 *nvm_sw,
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300346 const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100347{
348 struct iwl_nvm_data *data;
349 u8 hw_addr[ETH_ALEN];
350 u16 radio_cfg, sku;
351
352 data = kzalloc(sizeof(*data) +
353 sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
354 GFP_KERNEL);
355 if (!data)
356 return NULL;
357
358 data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
359
360 radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
361 data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
362 data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
363 data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
364 data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
365 data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
366 data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
367
368 sku = le16_to_cpup(nvm_sw + SKU);
369 data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
370 data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
371 data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
372 if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
373 data->sku_cap_11n_enable = false;
374
375 /* check overrides (some devices have wrong NVM) */
376 if (cfg->valid_tx_ant)
377 data->valid_tx_ant = cfg->valid_tx_ant;
378 if (cfg->valid_rx_ant)
379 data->valid_rx_ant = cfg->valid_rx_ant;
380
381 if (!data->valid_tx_ant || !data->valid_rx_ant) {
382 IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
383 data->valid_tx_ant, data->valid_rx_ant);
384 kfree(data);
385 return NULL;
386 }
387
388 data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
389
390 data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
391 data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
392
393 /* The byte order is little endian 16 bit, meaning 214365 */
394 memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
395 data->hw_addr[0] = hw_addr[1];
396 data->hw_addr[1] = hw_addr[0];
397 data->hw_addr[2] = hw_addr[3];
398 data->hw_addr[3] = hw_addr[2];
399 data->hw_addr[4] = hw_addr[5];
400 data->hw_addr[5] = hw_addr[4];
401
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300402 iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE,
403 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100404
405 data->calib_version = 255; /* TODO:
406 this value will prevent some checks from
407 failing, we need to check if this
408 field is still needed, and if it does,
409 where is it in the NVM*/
410
411 return data;
412}
Johannes Berg48e29342013-03-01 00:13:33 +0100413IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);