aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-eeprom.c
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-05-22 14:01:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-22 14:06:04 -0400
commit0848e297c2107dbc12a91a1709c879c73bd188d8 (patch)
treeeb98eab2c1e4701ac84daf68461c80c03d9016b3 /drivers/net/wireless/iwlwifi/iwl-eeprom.c
parent8a566afea0639fc387add782bc799009512a911b (diff)
iwlwifi: support NVM access (EEPROM/OTP)
Two type of NVM available for devices 1000, 6000 and after, adding support to read OTP lower blocks if OTP is used instead of EEPROM. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-eeprom.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c147
1 files changed, 129 insertions, 18 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index b400bd510fc5..9cc063b8b2d6 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}
153EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); 153EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
154 154
155static 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,35 @@ const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
198} 224}
199EXPORT_SYMBOL(iwlcore_eeprom_query_addr); 225EXPORT_SYMBOL(iwlcore_eeprom_query_addr);
200 226
227static 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 ret = iwl_grab_nic_access(priv);
244 if (!ret) {
245 iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
246 APMG_PS_CTRL_VAL_RESET_REQ);
247 udelay(5);
248 iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
249 APMG_PS_CTRL_VAL_RESET_REQ);
250 iwl_release_nic_access(priv);
251 }
252 }
253 return ret;
254}
255
201/** 256/**
202 * iwl_eeprom_init - read EEPROM contents 257 * iwl_eeprom_init - read EEPROM contents
203 * 258 *
@@ -209,11 +264,18 @@ int iwl_eeprom_init(struct iwl_priv *priv)
209{ 264{
210 u16 *e; 265 u16 *e;
211 u32 gp = iwl_read32(priv, CSR_EEPROM_GP); 266 u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
212 int sz = priv->cfg->eeprom_size; 267 int sz;
213 int ret; 268 int ret;
214 u16 addr; 269 u16 addr;
270 u32 otpgp;
271
272 priv->nvm_device_type = iwlcore_get_nvm_type(priv);
215 273
216 /* allocate eeprom */ 274 /* allocate eeprom */
275 if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
276 priv->cfg->eeprom_size =
277 OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
278 sz = priv->cfg->eeprom_size;
217 priv->eeprom = kzalloc(sz, GFP_KERNEL); 279 priv->eeprom = kzalloc(sz, GFP_KERNEL);
218 if (!priv->eeprom) { 280 if (!priv->eeprom) {
219 ret = -ENOMEM; 281 ret = -ENOMEM;
@@ -235,30 +297,77 @@ int iwl_eeprom_init(struct iwl_priv *priv)
235 ret = -ENOENT; 297 ret = -ENOENT;
236 goto err; 298 goto err;
237 } 299 }
238 300 if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
239 /* eeprom is an array of 16bit values */ 301 ret = iwl_init_otp_access(priv);
240 for (addr = 0; addr < sz; addr += sizeof(u16)) { 302 if (ret) {
241 u32 r; 303 IWL_ERR(priv, "Failed to initialize OTP access.\n");
242 304 ret = -ENOENT;
243 _iwl_write32(priv, CSR_EEPROM_REG, 305 goto err;
244 CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); 306 }
245 307 _iwl_write32(priv, CSR_EEPROM_GP,
246 ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, 308 iwl_read32(priv, CSR_EEPROM_GP) &
247 CSR_EEPROM_REG_READ_VALID_MSK, 309 ~CSR_EEPROM_GP_IF_OWNER_MSK);
248 IWL_EEPROM_ACCESS_TIMEOUT); 310 /* clear */
249 if (ret < 0) { 311 _iwl_write32(priv, CSR_OTP_GP_REG,
250 IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); 312 iwl_read32(priv, CSR_OTP_GP_REG) |
251 goto done; 313 CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
314 CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
315
316 for (addr = 0; addr < sz; addr += sizeof(u16)) {
317 u32 r;
318
319 _iwl_write32(priv, CSR_EEPROM_REG,
320 CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
321
322 ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
323 CSR_EEPROM_REG_READ_VALID_MSK,
324 IWL_EEPROM_ACCESS_TIMEOUT);
325 if (ret < 0) {
326 IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
327 goto done;
328 }
329 r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
330 /* check for ECC errors: */
331 otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
332 if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
333 /* stop in this case */
334 IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
335 goto done;
336 }
337 if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
338 /* continue in this case */
339 _iwl_write32(priv, CSR_OTP_GP_REG,
340 iwl_read32(priv, CSR_OTP_GP_REG) |
341 CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
342 IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
343 }
344 e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
345 }
346 } else {
347 /* eeprom is an array of 16bit values */
348 for (addr = 0; addr < sz; addr += sizeof(u16)) {
349 u32 r;
350
351 _iwl_write32(priv, CSR_EEPROM_REG,
352 CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
353
354 ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
355 CSR_EEPROM_REG_READ_VALID_MSK,
356 IWL_EEPROM_ACCESS_TIMEOUT);
357 if (ret < 0) {
358 IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
359 goto done;
360 }
361 r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
362 e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
252 } 363 }
253 r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
254 e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
255 } 364 }
256 ret = 0; 365 ret = 0;
257done: 366done:
258 priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); 367 priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
259err: 368err:
260 if (ret) 369 if (ret)
261 kfree(priv->eeprom); 370 iwl_eeprom_free(priv);
262alloc_err: 371alloc_err:
263 return ret; 372 return ret;
264} 373}
@@ -301,6 +410,8 @@ EXPORT_SYMBOL(iwl_eeprom_query_addr);
301 410
302u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) 411u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
303{ 412{
413 if (!priv->eeprom)
414 return 0;
304 return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); 415 return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
305} 416}
306EXPORT_SYMBOL(iwl_eeprom_query16); 417EXPORT_SYMBOL(iwl_eeprom_query16);