aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2012-03-06 09:50:48 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-03-06 15:16:18 -0500
commit10d8493cd9efd38b1947b7a74276dbdc8311aa1a (patch)
tree69caa6570a2582667783dd03c8ce5c204881f398
parent4ac887cfdad909f16ee1886fe4fa19b452fc7fd3 (diff)
bcma: add support for on-chip OTP memory used for SPROM storage
Wireless Broadcom chips can have either their SPROM data stored on either external SPROM or on-chip OTP memory. Both are accessed through the same register space. This patch adds support for the on-chip OTP memory. Tested with: BCM43224 OTP and SPROM BCM4331 SPROM BCM4313 OTP This patch is in response to linux-wireless thread [1]. [1] http://article.gmane.org/gmane.linux.kernel.wireless.general/85426 Tested-by: Saul St. John <saul.stjohn@gmail.com> Tested-by: Rafal Milecki <zajec5@gmail.com> Tested-by: Hauke Mehrtens <hauke@hauke-m.de> Cc: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/bcma/sprom.c126
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h10
2 files changed, 115 insertions, 21 deletions
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index fba8066857d2..cdcf75c0954f 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -300,37 +300,128 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
300 SSB_SROM8_FEM_ANTSWLUT_SHIFT); 300 SSB_SROM8_FEM_ANTSWLUT_SHIFT);
301} 301}
302 302
303static bool bcma_is_sprom_available(struct bcma_bus *bus) 303/*
304 * Indicates the presence of external SPROM.
305 */
306static bool bcma_sprom_ext_available(struct bcma_bus *bus)
304{ 307{
305 u32 sromctrl; 308 u32 chip_status;
309 u32 srom_control;
310 u32 present_mask;
306 311
307 if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM)) 312 if (bus->drv_cc.core->id.rev >= 31) {
308 return false; 313 if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
314 return false;
309 315
310 if (bus->drv_cc.core->id.rev >= 32) { 316 srom_control = bcma_read32(bus->drv_cc.core,
311 sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL); 317 BCMA_CC_SROM_CONTROL);
312 return sromctrl & BCMA_CC_SROM_CONTROL_PRESENT; 318 return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
313 } 319 }
314 return true; 320
321 /* older chipcommon revisions use chip status register */
322 chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
323 switch (bus->chipinfo.id) {
324 case 0x4313:
325 present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
326 break;
327
328 case 0x4331:
329 present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
330 break;
331
332 default:
333 return true;
334 }
335
336 return chip_status & present_mask;
337}
338
339/*
340 * Indicates that on-chip OTP memory is present and enabled.
341 */
342static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
343{
344 u32 chip_status;
345 u32 otpsize = 0;
346 bool present;
347
348 chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
349 switch (bus->chipinfo.id) {
350 case 0x4313:
351 present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
352 break;
353
354 case 0x4331:
355 present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
356 break;
357
358 case 43224:
359 case 43225:
360 /* for these chips OTP is always available */
361 present = true;
362 break;
363
364 default:
365 present = false;
366 break;
367 }
368
369 if (present) {
370 otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
371 otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
372 }
373
374 return otpsize != 0;
375}
376
377/*
378 * Verify OTP is filled and determine the byte
379 * offset where SPROM data is located.
380 *
381 * On error, returns 0; byte offset otherwise.
382 */
383static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
384{
385 struct bcma_device *cc = bus->drv_cc.core;
386 u32 offset;
387
388 /* verify OTP status */
389 if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
390 return 0;
391
392 /* obtain bit offset from otplayout register */
393 offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
394 return BCMA_CC_SPROM + (offset >> 3);
315} 395}
316 396
317int bcma_sprom_get(struct bcma_bus *bus) 397int bcma_sprom_get(struct bcma_bus *bus)
318{ 398{
319 u16 offset; 399 u16 offset = BCMA_CC_SPROM;
320 u16 *sprom; 400 u16 *sprom;
321 int err = 0; 401 int err = 0;
322 402
323 if (!bus->drv_cc.core) 403 if (!bus->drv_cc.core)
324 return -EOPNOTSUPP; 404 return -EOPNOTSUPP;
325 405
326 if (!bcma_is_sprom_available(bus)) { 406 if (!bcma_sprom_ext_available(bus)) {
327 /* 407 /*
328 * Maybe there is no SPROM on the device? 408 * External SPROM takes precedence so check
329 * Now we ask the arch code if there is some sprom 409 * on-chip OTP only when no external SPROM
330 * available for this device in some other storage. 410 * is present.
331 */ 411 */
332 err = bcma_fill_sprom_with_fallback(bus, &bus->sprom); 412 if (bcma_sprom_onchip_available(bus)) {
333 return err; 413 /* determine offset */
414 offset = bcma_sprom_onchip_offset(bus);
415 }
416 if (!offset) {
417 /*
418 * Maybe there is no SPROM on the device?
419 * Now we ask the arch code if there is some sprom
420 * available for this device in some other storage.
421 */
422 err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
423 return err;
424 }
334 } 425 }
335 426
336 sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), 427 sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
@@ -341,11 +432,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
341 if (bus->chipinfo.id == 0x4331) 432 if (bus->chipinfo.id == 0x4331)
342 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); 433 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
343 434
344 /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
345 * According to brcm80211 this applies to cards with PCIe rev >= 6
346 * TODO: understand this condition and use it */
347 offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
348 BCMA_CC_SPROM_PCIE6;
349 pr_debug("SPROM offset 0x%x\n", offset); 435 pr_debug("SPROM offset 0x%x\n", offset);
350 bcma_sprom_read(bus, offset, sprom); 436 bcma_sprom_read(bus, offset, sprom);
351 437
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index e72938b10714..8bbfe31fbac8 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -56,6 +56,9 @@
56#define BCMA_CC_OTPS_HW_PROTECT 0x00000001 56#define BCMA_CC_OTPS_HW_PROTECT 0x00000001
57#define BCMA_CC_OTPS_SW_PROTECT 0x00000002 57#define BCMA_CC_OTPS_SW_PROTECT 0x00000002
58#define BCMA_CC_OTPS_CID_PROTECT 0x00000004 58#define BCMA_CC_OTPS_CID_PROTECT 0x00000004
59#define BCMA_CC_OTPS_GU_PROG_IND 0x00000F00 /* General Use programmed indication */
60#define BCMA_CC_OTPS_GU_PROG_IND_SHIFT 8
61#define BCMA_CC_OTPS_GU_PROG_HW 0x00000100 /* HW region programmed */
59#define BCMA_CC_OTPC 0x0014 /* OTP control */ 62#define BCMA_CC_OTPC 0x0014 /* OTP control */
60#define BCMA_CC_OTPC_RECWAIT 0xFF000000 63#define BCMA_CC_OTPC_RECWAIT 0xFF000000
61#define BCMA_CC_OTPC_PROGWAIT 0x00FFFF00 64#define BCMA_CC_OTPC_PROGWAIT 0x00FFFF00
@@ -72,6 +75,8 @@
72#define BCMA_CC_OTPP_READ 0x40000000 75#define BCMA_CC_OTPP_READ 0x40000000
73#define BCMA_CC_OTPP_START 0x80000000 76#define BCMA_CC_OTPP_START 0x80000000
74#define BCMA_CC_OTPP_BUSY 0x80000000 77#define BCMA_CC_OTPP_BUSY 0x80000000
78#define BCMA_CC_OTPL 0x001C /* OTP layout */
79#define BCMA_CC_OTPL_GURGN_OFFSET 0x00000FFF /* offset of general use region */
75#define BCMA_CC_IRQSTAT 0x0020 80#define BCMA_CC_IRQSTAT 0x0020
76#define BCMA_CC_IRQMASK 0x0024 81#define BCMA_CC_IRQMASK 0x0024
77#define BCMA_CC_IRQ_GPIO 0x00000001 /* gpio intr */ 82#define BCMA_CC_IRQ_GPIO 0x00000001 /* gpio intr */
@@ -79,6 +84,10 @@
79#define BCMA_CC_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */ 84#define BCMA_CC_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */
80#define BCMA_CC_CHIPCTL 0x0028 /* Rev >= 11 only */ 85#define BCMA_CC_CHIPCTL 0x0028 /* Rev >= 11 only */
81#define BCMA_CC_CHIPSTAT 0x002C /* Rev >= 11 only */ 86#define BCMA_CC_CHIPSTAT 0x002C /* Rev >= 11 only */
87#define BCMA_CC_CHIPST_4313_SPROM_PRESENT 1
88#define BCMA_CC_CHIPST_4313_OTP_PRESENT 2
89#define BCMA_CC_CHIPST_4331_SPROM_PRESENT 2
90#define BCMA_CC_CHIPST_4331_OTP_PRESENT 4
82#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */ 91#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
83#define BCMA_CC_JCMD_START 0x80000000 92#define BCMA_CC_JCMD_START 0x80000000
84#define BCMA_CC_JCMD_BUSY 0x80000000 93#define BCMA_CC_JCMD_BUSY 0x80000000
@@ -256,7 +265,6 @@
256#define BCMA_CC_PLLCTL_ADDR 0x0660 265#define BCMA_CC_PLLCTL_ADDR 0x0660
257#define BCMA_CC_PLLCTL_DATA 0x0664 266#define BCMA_CC_PLLCTL_DATA 0x0664
258#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */ 267#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
259#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
260 268
261/* Divider allocation in 4716/47162/5356 */ 269/* Divider allocation in 4716/47162/5356 */
262#define BCMA_CC_PMU5_MAINPLL_CPU 1 270#define BCMA_CC_PMU5_MAINPLL_CPU 1