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>
This commit is contained in:
parent
4ac887cfda
commit
10d8493cd9
2 changed files with 115 additions and 21 deletions
|
@ -300,37 +300,128 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
|
|||
SSB_SROM8_FEM_ANTSWLUT_SHIFT);
|
||||
}
|
||||
|
||||
static bool bcma_is_sprom_available(struct bcma_bus *bus)
|
||||
/*
|
||||
* Indicates the presence of external SPROM.
|
||||
*/
|
||||
static bool bcma_sprom_ext_available(struct bcma_bus *bus)
|
||||
{
|
||||
u32 sromctrl;
|
||||
u32 chip_status;
|
||||
u32 srom_control;
|
||||
u32 present_mask;
|
||||
|
||||
if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
|
||||
return false;
|
||||
if (bus->drv_cc.core->id.rev >= 31) {
|
||||
if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
|
||||
return false;
|
||||
|
||||
if (bus->drv_cc.core->id.rev >= 32) {
|
||||
sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL);
|
||||
return sromctrl & BCMA_CC_SROM_CONTROL_PRESENT;
|
||||
srom_control = bcma_read32(bus->drv_cc.core,
|
||||
BCMA_CC_SROM_CONTROL);
|
||||
return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
|
||||
}
|
||||
return true;
|
||||
|
||||
/* older chipcommon revisions use chip status register */
|
||||
chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4313:
|
||||
present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
|
||||
break;
|
||||
|
||||
case 0x4331:
|
||||
present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
return chip_status & present_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Indicates that on-chip OTP memory is present and enabled.
|
||||
*/
|
||||
static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
|
||||
{
|
||||
u32 chip_status;
|
||||
u32 otpsize = 0;
|
||||
bool present;
|
||||
|
||||
chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4313:
|
||||
present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
|
||||
break;
|
||||
|
||||
case 0x4331:
|
||||
present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
|
||||
break;
|
||||
|
||||
case 43224:
|
||||
case 43225:
|
||||
/* for these chips OTP is always available */
|
||||
present = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
present = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (present) {
|
||||
otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
|
||||
otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
|
||||
}
|
||||
|
||||
return otpsize != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify OTP is filled and determine the byte
|
||||
* offset where SPROM data is located.
|
||||
*
|
||||
* On error, returns 0; byte offset otherwise.
|
||||
*/
|
||||
static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
|
||||
{
|
||||
struct bcma_device *cc = bus->drv_cc.core;
|
||||
u32 offset;
|
||||
|
||||
/* verify OTP status */
|
||||
if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
|
||||
return 0;
|
||||
|
||||
/* obtain bit offset from otplayout register */
|
||||
offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
|
||||
return BCMA_CC_SPROM + (offset >> 3);
|
||||
}
|
||||
|
||||
int bcma_sprom_get(struct bcma_bus *bus)
|
||||
{
|
||||
u16 offset;
|
||||
u16 offset = BCMA_CC_SPROM;
|
||||
u16 *sprom;
|
||||
int err = 0;
|
||||
|
||||
if (!bus->drv_cc.core)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!bcma_is_sprom_available(bus)) {
|
||||
if (!bcma_sprom_ext_available(bus)) {
|
||||
/*
|
||||
* Maybe there is no SPROM on the device?
|
||||
* Now we ask the arch code if there is some sprom
|
||||
* available for this device in some other storage.
|
||||
* External SPROM takes precedence so check
|
||||
* on-chip OTP only when no external SPROM
|
||||
* is present.
|
||||
*/
|
||||
err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
|
||||
return err;
|
||||
if (bcma_sprom_onchip_available(bus)) {
|
||||
/* determine offset */
|
||||
offset = bcma_sprom_onchip_offset(bus);
|
||||
}
|
||||
if (!offset) {
|
||||
/*
|
||||
* Maybe there is no SPROM on the device?
|
||||
* Now we ask the arch code if there is some sprom
|
||||
* available for this device in some other storage.
|
||||
*/
|
||||
err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
|
||||
|
@ -341,11 +432,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
|
|||
if (bus->chipinfo.id == 0x4331)
|
||||
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
|
||||
|
||||
/* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
|
||||
* According to brcm80211 this applies to cards with PCIe rev >= 6
|
||||
* TODO: understand this condition and use it */
|
||||
offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
|
||||
BCMA_CC_SPROM_PCIE6;
|
||||
pr_debug("SPROM offset 0x%x\n", offset);
|
||||
bcma_sprom_read(bus, offset, sprom);
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
#define BCMA_CC_OTPS_HW_PROTECT 0x00000001
|
||||
#define BCMA_CC_OTPS_SW_PROTECT 0x00000002
|
||||
#define BCMA_CC_OTPS_CID_PROTECT 0x00000004
|
||||
#define BCMA_CC_OTPS_GU_PROG_IND 0x00000F00 /* General Use programmed indication */
|
||||
#define BCMA_CC_OTPS_GU_PROG_IND_SHIFT 8
|
||||
#define BCMA_CC_OTPS_GU_PROG_HW 0x00000100 /* HW region programmed */
|
||||
#define BCMA_CC_OTPC 0x0014 /* OTP control */
|
||||
#define BCMA_CC_OTPC_RECWAIT 0xFF000000
|
||||
#define BCMA_CC_OTPC_PROGWAIT 0x00FFFF00
|
||||
|
@ -72,6 +75,8 @@
|
|||
#define BCMA_CC_OTPP_READ 0x40000000
|
||||
#define BCMA_CC_OTPP_START 0x80000000
|
||||
#define BCMA_CC_OTPP_BUSY 0x80000000
|
||||
#define BCMA_CC_OTPL 0x001C /* OTP layout */
|
||||
#define BCMA_CC_OTPL_GURGN_OFFSET 0x00000FFF /* offset of general use region */
|
||||
#define BCMA_CC_IRQSTAT 0x0020
|
||||
#define BCMA_CC_IRQMASK 0x0024
|
||||
#define BCMA_CC_IRQ_GPIO 0x00000001 /* gpio intr */
|
||||
|
@ -79,6 +84,10 @@
|
|||
#define BCMA_CC_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */
|
||||
#define BCMA_CC_CHIPCTL 0x0028 /* Rev >= 11 only */
|
||||
#define BCMA_CC_CHIPSTAT 0x002C /* Rev >= 11 only */
|
||||
#define BCMA_CC_CHIPST_4313_SPROM_PRESENT 1
|
||||
#define BCMA_CC_CHIPST_4313_OTP_PRESENT 2
|
||||
#define BCMA_CC_CHIPST_4331_SPROM_PRESENT 2
|
||||
#define BCMA_CC_CHIPST_4331_OTP_PRESENT 4
|
||||
#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
|
||||
#define BCMA_CC_JCMD_START 0x80000000
|
||||
#define BCMA_CC_JCMD_BUSY 0x80000000
|
||||
|
@ -256,7 +265,6 @@
|
|||
#define BCMA_CC_PLLCTL_ADDR 0x0660
|
||||
#define BCMA_CC_PLLCTL_DATA 0x0664
|
||||
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
|
||||
#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
|
||||
|
||||
/* Divider allocation in 4716/47162/5356 */
|
||||
#define BCMA_CC_PMU5_MAINPLL_CPU 1
|
||||
|
|
Loading…
Reference in a new issue