#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */
#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */
-/* Fields in otpprog in rev >= 21 and HND OTP */
+/* Fields in otpprog in rev >= 21 */
#define OTPP_COL_MASK 0x000000ff
#define OTPP_COL_SHIFT 0
#define OTPP_ROW_MASK 0x0000ff00
#define OTPP_VALUE_MASK 0x20000000
#define OTPP_VALUE_SHIFT 29
#define OTPP_START_BUSY 0x80000000
-#define OTPP_READ 0x40000000 /* HND OTP */
+#define OTPP_READ 0x40000000
/* Opcodes for OTPP_OC field */
#define OTPPOC_READ 0
#define OTPPOC_ROW_LOCK 8
#define OTPPOC_PRESCN_TEST 9
-/*
- * There are two different OTP controllers so far:
- * 1. new IPX OTP controller: chipc 21, >=23
- * 2. older HND OTP controller: chipc 12, 17, 22
- *
- * Define BCMHNDOTP to include support for the HND OTP controller.
- * Define BCMIPXOTP to include support for the IPX OTP controller.
- *
- * NOTE 1: More than one may be defined
- * NOTE 2: If none are defined, the default is to include them all.
- */
-
-#if !defined(BCMHNDOTP) && !defined(BCMIPXOTP)
-#define BCMHNDOTP 1
-#define BCMIPXOTP 1
-#endif
-
-#define OTPTYPE_HND(ccrev) ((ccrev) < 21 || (ccrev) == 22)
#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
#define OTPP_TRIES 10000000 /* # of tries for OTPP */
-#ifdef BCMIPXOTP
#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
-#endif
/* OTP common function type */
typedef int (*otp_status_t) (void *oh);
otp_fn_t *fn; /* OTP functions */
struct si_pub *sih; /* Saved sb handle */
-#ifdef BCMIPXOTP
/* IPX OTP section */
u16 wsize; /* Size of otp in words */
u16 rows; /* Geometry */
u16 fbase; /* fuse subregion offset */
u16 flim; /* fuse subregion boundary */
int otpgu_base; /* offset to General Use Region */
-#endif /* BCMIPXOTP */
-
-#ifdef BCMHNDOTP
- /* HND OTP section */
- uint size; /* Size of otp in bytes */
- uint hwprot; /* Hardware protection bits */
- uint signvalid; /* Signature valid bits */
- int boundary; /* hw/sw boundary */
-#endif /* BCMHNDOTP */
} otpinfo_t;
static otpinfo_t otpinfo;
*
*/
-#ifdef BCMIPXOTP
-
#define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
/* OTP layout */
(otp_status_t) ipxotp_status
};
-#endif /* BCMIPXOTP */
-
-/*
- * HND OTP Code
- *
- * Exported functions:
- * hndotp_status()
- * hndotp_size()
- * hndotp_init()
- * hndotp_read_bit()
- * hndotp_read_region()
- * hndotp_nvread()
- *
- */
-
-#ifdef BCMHNDOTP
-
-/* Fields in otpstatus */
-#define OTPS_PROGFAIL 0x80000000
-#define OTPS_PROTECT 0x00000007
-#define OTPS_HW_PROTECT 0x00000001
-#define OTPS_SW_PROTECT 0x00000002
-#define OTPS_CID_PROTECT 0x00000004
-#define OTPS_RCEV_MSK 0x00003f00
-#define OTPS_RCEV_SHIFT 8
-
-/* Fields in the otpcontrol register */
-#define OTPC_RECWAIT 0xff000000
-#define OTPC_PROGWAIT 0x00ffff00
-#define OTPC_PRW_SHIFT 8
-#define OTPC_MAXFAIL 0x00000038
-#define OTPC_VSEL 0x00000006
-#define OTPC_SELVL 0x00000001
-
-/* OTP regions (Word offsets from otp size) */
-#define OTP_SWLIM_OFF (-4)
-#define OTP_CIDBASE_OFF 0
-#define OTP_CIDLIM_OFF 4
-
-/* Predefined OTP words (Word offset from otp size) */
-#define OTP_BOUNDARY_OFF (-4)
-#define OTP_HWSIGN_OFF (-3)
-#define OTP_SWSIGN_OFF (-2)
-#define OTP_CIDSIGN_OFF (-1)
-#define OTP_CID_OFF 0
-#define OTP_PKG_OFF 1
-#define OTP_FID_OFF 2
-#define OTP_RSV_OFF 3
-#define OTP_LIM_OFF 4
-#define OTP_RD_OFF 4 /* Redundancy row starts here */
-#define OTP_RC0_OFF 28 /* Redundancy control word 1 */
-#define OTP_RC1_OFF 32 /* Redundancy control word 2 */
-#define OTP_RC_LIM_OFF 36 /* Redundancy control word end */
-
-#define OTP_HW_REGION OTPS_HW_PROTECT
-#define OTP_SW_REGION OTPS_SW_PROTECT
-#define OTP_CID_REGION OTPS_CID_PROTECT
-
-#if OTP_HW_REGION != OTP_HW_RGN
-#error "incompatible OTP_HW_RGN"
-#endif
-#if OTP_SW_REGION != OTP_SW_RGN
-#error "incompatible OTP_SW_RGN"
-#endif
-#if OTP_CID_REGION != OTP_CI_RGN
-#error "incompatible OTP_CI_RGN"
-#endif
-
-/* Redundancy entry definitions */
-#define OTP_RCE_ROW_SZ 6
-#define OTP_RCE_SIGN_MASK 0x7fff
-#define OTP_RCE_ROW_MASK 0x3f
-#define OTP_RCE_BITS 21
-#define OTP_RCE_SIGN_SZ 15
-#define OTP_RCE_BIT0 1
-
-#define OTP_WPR 4
-#define OTP_SIGNATURE 0x578a
-#define OTP_MAGIC 0x4e56
-
-static int hndotp_status(void *oh)
-{
- otpinfo_t *oi = (otpinfo_t *) oh;
- return (int)(oi->hwprot | oi->signvalid);
-}
-
-static int hndotp_size(void *oh)
-{
- otpinfo_t *oi = (otpinfo_t *) oh;
- return (int)(oi->size);
-}
-
-static u16 hndotp_otpr(void *oh, chipcregs_t *cc, uint wn)
-{
- volatile u16 *ptr;
-
- ptr = (volatile u16 *)((volatile char *)cc + CC_SROM_OTP);
- return R_REG(&ptr[wn]);
-}
-
-static u16 hndotp_otproff(void *oh, chipcregs_t *cc, int woff)
-{
- otpinfo_t *oi = (otpinfo_t *) oh;
- volatile u16 *ptr;
-
- ptr = (volatile u16 *)((volatile char *)cc + CC_SROM_OTP);
-
- return R_REG(&ptr[(oi->size / 2) + woff]);
-}
-
-static u16 hndotp_read_bit(void *oh, chipcregs_t *cc, uint idx)
-{
- uint k, row, col;
- u32 otpp, st;
-
- row = idx / 65;
- col = idx % 65;
-
- otpp = OTPP_START_BUSY | OTPP_READ |
- ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) | (col & OTPP_COL_MASK);
-
- W_REG(&cc->otpprog, otpp);
- st = R_REG(&cc->otpprog);
- for (k = 0;
- ((st & OTPP_START_BUSY) == OTPP_START_BUSY) && (k < OTPP_TRIES);
- k++)
- st = R_REG(&cc->otpprog);
-
- if (k >= OTPP_TRIES) {
- return 0xffff;
- }
- if (st & OTPP_READERR) {
- return 0xffff;
- }
- st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
- return (u16) st;
-}
-
-static void *hndotp_init(struct si_pub *sih)
-{
- uint idx;
- chipcregs_t *cc;
- otpinfo_t *oi;
- u32 cap = 0, clkdiv, otpdiv = 0;
- void *ret = NULL;
-
- oi = &otpinfo;
-
- idx = ai_coreidx(sih);
-
- /* Check for otp */
- cc = ai_setcoreidx(sih, SI_CC_IDX);
- if (cc != NULL) {
- cap = R_REG(&cc->capabilities);
- if ((cap & CC_CAP_OTPSIZE) == 0) {
- /* Nothing there */
- goto out;
- }
-
- if (!((oi->ccrev == 12) || (oi->ccrev == 17)
- || (oi->ccrev == 22)))
- return NULL;
-
- /* Read the OTP byte size. chipcommon rev >= 18 has RCE so the size is
- * 8 row (64 bytes) smaller
- */
- oi->size =
- 1 << (((cap & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT)
- + CC_CAP_OTPSIZE_BASE);
- if (oi->ccrev >= 18)
- oi->size -= ((OTP_RC0_OFF - OTP_BOUNDARY_OFF) * 2);
-
- oi->hwprot = (int)(R_REG(&cc->otpstatus) & OTPS_PROTECT);
- oi->boundary = -1;
-
- /* Check the region signature */
- if (hndotp_otproff(oi, cc, OTP_HWSIGN_OFF) == OTP_SIGNATURE) {
- oi->signvalid |= OTP_HW_REGION;
- oi->boundary = hndotp_otproff(oi, cc, OTP_BOUNDARY_OFF);
- }
-
- if (hndotp_otproff(oi, cc, OTP_SWSIGN_OFF) == OTP_SIGNATURE)
- oi->signvalid |= OTP_SW_REGION;
-
- if (hndotp_otproff(oi, cc, OTP_CIDSIGN_OFF) == OTP_SIGNATURE)
- oi->signvalid |= OTP_CID_REGION;
-
- /* Set OTP clkdiv for stability */
- if (oi->ccrev == 22)
- otpdiv = 12;
-
- if (otpdiv) {
- clkdiv = R_REG(&cc->clkdiv);
- clkdiv =
- (clkdiv & ~CLKD_OTP) | (otpdiv << CLKD_OTP_SHIFT);
- W_REG(&cc->clkdiv, clkdiv);
- }
- udelay(10);
-
- ret = (void *)oi;
- }
-
- out: /* All done */
- ai_setcoreidx(sih, idx);
-
- return ret;
-}
-
-static int hndotp_read_region(void *oh, int region, u16 *data, uint *wlen)
-{
- otpinfo_t *oi = (otpinfo_t *) oh;
- u32 idx, st;
- chipcregs_t *cc;
- int i;
-
-
- if (region != OTP_HW_REGION) {
- /*
- * Only support HW region
- * (no active chips use HND OTP SW region)
- * */
- return -ENOTSUPP;
- }
-
- /* Region empty? */
- st = oi->hwprot | oi->signvalid;
- if ((st & region) == 0)
- return -ENODATA;
-
- *wlen =
- ((int)*wlen < oi->boundary / 2) ? *wlen : (uint) oi->boundary / 2;
-
- idx = ai_coreidx(oi->sih);
- cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
-
- for (i = 0; i < (int)*wlen; i++)
- data[i] = hndotp_otpr(oh, cc, i);
-
- ai_setcoreidx(oi->sih, idx);
-
- return 0;
-}
-
-static int hndotp_nvread(void *oh, char *data, uint *len)
-{
- int rc = 0;
- otpinfo_t *oi = (otpinfo_t *) oh;
- u32 base, bound, lim = 0, st;
- int i, chunk, gchunks, tsz = 0;
- u32 idx;
- chipcregs_t *cc;
- uint offset;
- u16 *rawotp = NULL;
-
- /* save the orig core */
- idx = ai_coreidx(oi->sih);
- cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
-
- st = hndotp_status(oh);
- if (!(st & (OTP_HW_REGION | OTP_SW_REGION))) {
- rc = -1;
- goto out;
- }
-
- /* Read the whole otp so we can easily manipulate it */
- lim = hndotp_size(oh);
- rawotp = kmalloc(lim, GFP_ATOMIC);
- if (rawotp == NULL) {
- rc = -2;
- goto out;
- }
- for (i = 0; i < (int)(lim / 2); i++)
- rawotp[i] = hndotp_otpr(oh, cc, i);
-
- if ((st & OTP_HW_REGION) == 0) {
- /* This could be a programming failure in the first
- * chunk followed by one or more good chunks
- */
- for (i = 0; i < (int)(lim / 2); i++)
- if (rawotp[i] == OTP_MAGIC)
- break;
-
- if (i < (int)(lim / 2)) {
- base = i;
- bound = (i * 2) + rawotp[i + 1];
- } else {
- rc = -3;
- goto out;
- }
- } else {
- bound = rawotp[(lim / 2) + OTP_BOUNDARY_OFF];
-
- /* There are two cases: 1) The whole otp is used as nvram
- * and 2) There is a hardware header followed by nvram.
- */
- if (rawotp[0] == OTP_MAGIC) {
- base = 0;
- } else
- base = bound;
- }
-
- /* Find and copy the data */
-
- chunk = 0;
- gchunks = 0;
- i = base / 2;
- offset = 0;
- while ((i < (int)(lim / 2)) && (rawotp[i] == OTP_MAGIC)) {
- int dsz, rsz = rawotp[i + 1];
-
- if (((i * 2) + rsz) >= (int)lim) {
- /* Bad length, try to find another chunk anyway */
- rsz = 6;
- }
- if (crc_ccitt(CRC16_INIT_VALUE, (u8 *) &rawotp[i], rsz) ==
- CRC16_GOOD_VALUE) {
- /* Good crc, copy the vars */
- gchunks++;
- dsz = rsz - 6;
- tsz += dsz;
- if (offset + dsz >= *len) {
- goto out;
- }
- memcpy(&data[offset], &rawotp[i + 2], dsz);
- offset += dsz;
- /* Remove extra null characters at the end */
- while (offset > 1 &&
- data[offset - 1] == 0 && data[offset - 2] == 0)
- offset--;
- i += rsz / 2;
- } else {
- /* bad length or crc didn't check, try to find the next set */
- if (rawotp[i + (rsz / 2)] == OTP_MAGIC) {
- /* Assume length is good */
- i += rsz / 2;
- } else {
- while (++i < (int)(lim / 2))
- if (rawotp[i] == OTP_MAGIC)
- break;
- }
- }
- chunk++;
- }
-
- *len = offset;
-
- out:
- kfree(rawotp);
- ai_setcoreidx(oi->sih, idx);
-
- return rc;
-}
-
-static otp_fn_t otp_fn = {
- (otp_size_t) hndotp_size,
- (otp_read_bit_t) hndotp_read_bit,
-
- (otp_init_t) hndotp_init,
- (otp_read_region_t) hndotp_read_region,
- (otp_nvread_t) hndotp_nvread,
-
- (otp_status_t) hndotp_status
-};
-
-#endif /* BCMHNDOTP */
-
/*
- * Common Code: Compiled for IPX / HND / AUTO
* otp_status()
* otp_size()
* otp_read_bit()
oi->ccrev = sih->ccrev;
-#ifdef BCMIPXOTP
if (OTPTYPE_IPX(oi->ccrev))
oi->fn = &ipxotp_fn;
-#endif
-
-#ifdef BCMHNDOTP
- if (OTPTYPE_HND(oi->ccrev))
- oi->fn = &otp_fn;
-#endif
if (oi->fn == NULL) {
return NULL;