diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-eeprom.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-eeprom.c | 153 |
1 files changed, 130 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 75517d05df08..7d7554a2f341 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -152,6 +152,32 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) | |||
152 | } | 152 | } |
153 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); | 153 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); |
154 | 154 | ||
155 | static int iwlcore_get_nvm_type(struct iwl_priv *priv) | ||
156 | { | ||
157 | u32 otpgp; | ||
158 | int nvm_type; | ||
159 | |||
160 | /* OTP only valid for CP/PP and after */ | ||
161 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | ||
162 | case CSR_HW_REV_TYPE_3945: | ||
163 | case CSR_HW_REV_TYPE_4965: | ||
164 | case CSR_HW_REV_TYPE_5300: | ||
165 | case CSR_HW_REV_TYPE_5350: | ||
166 | case CSR_HW_REV_TYPE_5100: | ||
167 | case CSR_HW_REV_TYPE_5150: | ||
168 | nvm_type = NVM_DEVICE_TYPE_EEPROM; | ||
169 | break; | ||
170 | default: | ||
171 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | ||
172 | if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) | ||
173 | nvm_type = NVM_DEVICE_TYPE_OTP; | ||
174 | else | ||
175 | nvm_type = NVM_DEVICE_TYPE_EEPROM; | ||
176 | break; | ||
177 | } | ||
178 | return nvm_type; | ||
179 | } | ||
180 | |||
155 | /* | 181 | /* |
156 | * The device's EEPROM semaphore prevents conflicts between driver and uCode | 182 | * The device's EEPROM semaphore prevents conflicts between driver and uCode |
157 | * when accessing the EEPROM; each access is a series of pulses to/from the | 183 | * when accessing the EEPROM; each access is a series of pulses to/from the |
@@ -198,6 +224,31 @@ const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) | |||
198 | } | 224 | } |
199 | EXPORT_SYMBOL(iwlcore_eeprom_query_addr); | 225 | EXPORT_SYMBOL(iwlcore_eeprom_query_addr); |
200 | 226 | ||
227 | static int iwl_init_otp_access(struct iwl_priv *priv) | ||
228 | { | ||
229 | int ret; | ||
230 | |||
231 | /* Enable 40MHz radio clock */ | ||
232 | _iwl_write32(priv, CSR_GP_CNTRL, | ||
233 | _iwl_read32(priv, CSR_GP_CNTRL) | | ||
234 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | ||
235 | |||
236 | /* wait for clock to be ready */ | ||
237 | ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, | ||
238 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | ||
239 | 25000); | ||
240 | if (ret < 0) | ||
241 | IWL_ERR(priv, "Time out access OTP\n"); | ||
242 | else { | ||
243 | iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, | ||
244 | APMG_PS_CTRL_VAL_RESET_REQ); | ||
245 | udelay(5); | ||
246 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, | ||
247 | APMG_PS_CTRL_VAL_RESET_REQ); | ||
248 | } | ||
249 | return ret; | ||
250 | } | ||
251 | |||
201 | /** | 252 | /** |
202 | * iwl_eeprom_init - read EEPROM contents | 253 | * iwl_eeprom_init - read EEPROM contents |
203 | * | 254 | * |
@@ -209,11 +260,18 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
209 | { | 260 | { |
210 | u16 *e; | 261 | u16 *e; |
211 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); | 262 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); |
212 | int sz = priv->cfg->eeprom_size; | 263 | int sz; |
213 | int ret; | 264 | int ret; |
214 | u16 addr; | 265 | u16 addr; |
266 | u32 otpgp; | ||
267 | |||
268 | priv->nvm_device_type = iwlcore_get_nvm_type(priv); | ||
215 | 269 | ||
216 | /* allocate eeprom */ | 270 | /* allocate eeprom */ |
271 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) | ||
272 | priv->cfg->eeprom_size = | ||
273 | OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; | ||
274 | sz = priv->cfg->eeprom_size; | ||
217 | priv->eeprom = kzalloc(sz, GFP_KERNEL); | 275 | priv->eeprom = kzalloc(sz, GFP_KERNEL); |
218 | if (!priv->eeprom) { | 276 | if (!priv->eeprom) { |
219 | ret = -ENOMEM; | 277 | ret = -ENOMEM; |
@@ -235,30 +293,77 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
235 | ret = -ENOENT; | 293 | ret = -ENOENT; |
236 | goto err; | 294 | goto err; |
237 | } | 295 | } |
238 | 296 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { | |
239 | /* eeprom is an array of 16bit values */ | 297 | ret = iwl_init_otp_access(priv); |
240 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | 298 | if (ret) { |
241 | u32 r; | 299 | IWL_ERR(priv, "Failed to initialize OTP access.\n"); |
242 | 300 | ret = -ENOENT; | |
243 | _iwl_write32(priv, CSR_EEPROM_REG, | 301 | goto err; |
244 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | 302 | } |
245 | 303 | _iwl_write32(priv, CSR_EEPROM_GP, | |
246 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | 304 | iwl_read32(priv, CSR_EEPROM_GP) & |
247 | CSR_EEPROM_REG_READ_VALID_MSK, | 305 | ~CSR_EEPROM_GP_IF_OWNER_MSK); |
248 | IWL_EEPROM_ACCESS_TIMEOUT); | 306 | /* clear */ |
249 | if (ret < 0) { | 307 | _iwl_write32(priv, CSR_OTP_GP_REG, |
250 | IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); | 308 | iwl_read32(priv, CSR_OTP_GP_REG) | |
251 | goto done; | 309 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | |
310 | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); | ||
311 | |||
312 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | ||
313 | u32 r; | ||
314 | |||
315 | _iwl_write32(priv, CSR_EEPROM_REG, | ||
316 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | ||
317 | |||
318 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | ||
319 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
320 | IWL_EEPROM_ACCESS_TIMEOUT); | ||
321 | if (ret < 0) { | ||
322 | IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); | ||
323 | goto done; | ||
324 | } | ||
325 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | ||
326 | /* check for ECC errors: */ | ||
327 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | ||
328 | if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { | ||
329 | /* stop in this case */ | ||
330 | IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); | ||
331 | goto done; | ||
332 | } | ||
333 | if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { | ||
334 | /* continue in this case */ | ||
335 | _iwl_write32(priv, CSR_OTP_GP_REG, | ||
336 | iwl_read32(priv, CSR_OTP_GP_REG) | | ||
337 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); | ||
338 | IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); | ||
339 | } | ||
340 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
341 | } | ||
342 | } else { | ||
343 | /* eeprom is an array of 16bit values */ | ||
344 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | ||
345 | u32 r; | ||
346 | |||
347 | _iwl_write32(priv, CSR_EEPROM_REG, | ||
348 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | ||
349 | |||
350 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | ||
351 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
352 | IWL_EEPROM_ACCESS_TIMEOUT); | ||
353 | if (ret < 0) { | ||
354 | IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); | ||
355 | goto done; | ||
356 | } | ||
357 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | ||
358 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
252 | } | 359 | } |
253 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | ||
254 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
255 | } | 360 | } |
256 | ret = 0; | 361 | ret = 0; |
257 | done: | 362 | done: |
258 | priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); | 363 | priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); |
259 | err: | 364 | err: |
260 | if (ret) | 365 | if (ret) |
261 | kfree(priv->eeprom); | 366 | iwl_eeprom_free(priv); |
262 | alloc_err: | 367 | alloc_err: |
263 | return ret; | 368 | return ret; |
264 | } | 369 | } |
@@ -285,7 +390,7 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) | |||
285 | 390 | ||
286 | return 0; | 391 | return 0; |
287 | err: | 392 | err: |
288 | IWL_ERR(priv, "Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", | 393 | IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", |
289 | eeprom_ver, priv->cfg->eeprom_ver, | 394 | eeprom_ver, priv->cfg->eeprom_ver, |
290 | calib_ver, priv->cfg->eeprom_calib_ver); | 395 | calib_ver, priv->cfg->eeprom_calib_ver); |
291 | return -EINVAL; | 396 | return -EINVAL; |
@@ -301,6 +406,8 @@ EXPORT_SYMBOL(iwl_eeprom_query_addr); | |||
301 | 406 | ||
302 | u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) | 407 | u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) |
303 | { | 408 | { |
409 | if (!priv->eeprom) | ||
410 | return 0; | ||
304 | return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); | 411 | return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); |
305 | } | 412 | } |
306 | EXPORT_SYMBOL(iwl_eeprom_query16); | 413 | EXPORT_SYMBOL(iwl_eeprom_query16); |
@@ -481,8 +588,8 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
481 | /* First write that fat is not enabled, and then enable | 588 | /* First write that fat is not enabled, and then enable |
482 | * one by one */ | 589 | * one by one */ |
483 | ch_info->fat_extension_channel = | 590 | ch_info->fat_extension_channel = |
484 | (IEEE80211_CHAN_NO_FAT_ABOVE | | 591 | (IEEE80211_CHAN_NO_HT40PLUS | |
485 | IEEE80211_CHAN_NO_FAT_BELOW); | 592 | IEEE80211_CHAN_NO_HT40MINUS); |
486 | 593 | ||
487 | if (!(is_channel_valid(ch_info))) { | 594 | if (!(is_channel_valid(ch_info))) { |
488 | IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " | 595 | IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " |
@@ -561,7 +668,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
561 | fat_extension_chan = 0; | 668 | fat_extension_chan = 0; |
562 | else | 669 | else |
563 | fat_extension_chan = | 670 | fat_extension_chan = |
564 | IEEE80211_CHAN_NO_FAT_BELOW; | 671 | IEEE80211_CHAN_NO_HT40MINUS; |
565 | 672 | ||
566 | /* Set up driver's info for lower half */ | 673 | /* Set up driver's info for lower half */ |
567 | iwl_set_fat_chan_info(priv, ieeeband, | 674 | iwl_set_fat_chan_info(priv, ieeeband, |
@@ -573,7 +680,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
573 | iwl_set_fat_chan_info(priv, ieeeband, | 680 | iwl_set_fat_chan_info(priv, ieeeband, |
574 | (eeprom_ch_index[ch] + 4), | 681 | (eeprom_ch_index[ch] + 4), |
575 | &(eeprom_ch_info[ch]), | 682 | &(eeprom_ch_info[ch]), |
576 | IEEE80211_CHAN_NO_FAT_ABOVE); | 683 | IEEE80211_CHAN_NO_HT40PLUS); |
577 | } | 684 | } |
578 | } | 685 | } |
579 | 686 | ||