/* * Interface to register chipc secondary isr */ bool BCMINITFN(sb_cc_register_isr) (sb_t * sbh, cc_isr_fn isr, uint32 ccintmask, void *cbdata) { bool done = FALSE; chipcregs_t *regs; uint origidx; uint i; /* Save the current core index */ origidx = sb_coreidx(sbh); regs = sb_setcore(sbh, SB_CC, 0); ASSERT(regs); for (i = 0; i < MAX_CC_INT_SOURCE; i++) { if (cc_isr_desc[i].isr == NULL) { cc_isr_desc[i].isr = isr; cc_isr_desc[i].cbdata = cbdata; cc_isr_desc[i].intmask = ccintmask; done = TRUE; break; } } if (done) { cc_intmask = R_REG(sb_osh(sbh), ®s->intmask); cc_intmask |= ccintmask; W_REG(sb_osh(sbh), ®s->intmask, cc_intmask); } /* restore original coreidx */ sb_setcoreidx(sbh, origidx); return done; }
/* Erase a region. Returns number of bytes scheduled for erasure. * Caller should poll for completion. */ int sflash_erase(sb_t *sbh, chipcregs_t *cc, uint offset) { struct sflash *sfl; osl_t *osh; ASSERT(sbh); osh = sb_osh(sbh); if (offset >= sflash.size) return -22; sfl = &sflash; switch (sfl->type) { case SFLASH_ST: sflash_cmd(osh, cc, SFLASH_ST_WREN); W_REG(osh, &cc->flashaddress, offset); sflash_cmd(osh, cc, SFLASH_ST_SE); return sfl->blocksize; case SFLASH_AT: W_REG(osh, &cc->flashaddress, offset << 1); sflash_cmd(osh, cc, SFLASH_AT_PAGE_ERASE); return sfl->blocksize; } return 0; }
/* * Initialize nonvolatile variable table from flash. * Return 0 on success, nonzero on error. */ static int initvars_flash_sb(void *sbh, char **vars, uint *count) { osl_t *osh = sb_osh(sbh); char devpath[SB_DEVPATH_BUFSZ]; char *vp, *base; int err; ASSERT(vars); ASSERT(count); if ((err = sb_devpath(sbh, devpath, sizeof(devpath)))) return err; base = vp = MALLOC(osh, VARS_MAX); ASSERT(vp); if (!vp) return BCME_NOMEM; if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath))) goto err; err = initvars_table(osh, base, vp, vars, count); err: MFREE(osh, base, VARS_MAX); return err; }
/* Poll for command completion. Returns zero when complete. */ int sflash_poll(sb_t *sbh, chipcregs_t *cc, uint offset) { osl_t *osh; ASSERT(sbh); osh = sb_osh(sbh); if (offset >= sflash.size) return -22; switch (sflash.type) { case SFLASH_ST: /* Check for ST Write In Progress bit */ sflash_cmd(osh, cc, SFLASH_ST_RDSR); return R_REG(osh, &cc->flashdata) & SFLASH_ST_WIP; case SFLASH_AT: /* Check for Atmel Ready bit */ sflash_cmd(osh, cc, SFLASH_AT_STATUS); return !(R_REG(osh, &cc->flashdata) & SFLASH_AT_READY); } return 0; }
static uint32 config_cmd(sb_t *sbh, uint bus, uint dev, uint func, uint off) { uint coreidx; sbpciregs_t *regs; uint32 addr = 0; osl_t *osh; /* CardBusMode supports only one device */ if (cardbus && dev > 1) return 0; osh = sb_osh(sbh); coreidx = sb_coreidx(sbh); regs = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0); /* Type 0 transaction */ if (bus == 1) { /* Skip unwired slots */ if (dev < PCI_SLOT_MAX) { uint32 win; /* Slide the PCI window to the appropriate slot */ win = (SBTOPCI_CFG0 | ((1 << (dev + PCI_SLOTAD_MAP)) & SBTOPCI1_MASK)); W_REG(osh, ®s->sbtopci1, win); addr = SB_PCI_CFG | ((1 << (dev + PCI_SLOTAD_MAP)) & ~SBTOPCI1_MASK) | (func << PCICFG_FUN_SHIFT) | (off & ~3); } } else { /* Type 1 transaction */ W_REG(osh, ®s->sbtopci1, SBTOPCI_CFG1); addr = SB_PCI_CFG | (bus << PCICFG_BUS_SHIFT) | (dev << PCICFG_SLOT_SHIFT) | (func << PCICFG_FUN_SHIFT) | (off & ~3); } sb_setcoreidx(sbh, coreidx); return addr; }
/* Read len bytes starting at offset into buf. Returns number of bytes read. */ int sflash_read(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, uchar *buf) { uint8 *from, *to; int cnt, i; osl_t *osh; ASSERT(sbh); if (!len) return 0; if ((offset + len) > sflash.size) return -22; if ((len >= 4) && (offset & 3)) cnt = 4 - (offset & 3); else if ((len >= 4) && ((uint32)buf & 3)) cnt = 4 - ((uint32)buf & 3); else cnt = len; osh = sb_osh(sbh); from = (uint8 *)KSEG1ADDR(SB_FLASH2 + offset); to = (uint8 *)buf; if (cnt < 4) { for (i = 0; i < cnt; i ++) { *to = R_REG(osh, from); from ++; to ++; } return cnt; } while (cnt >= 4) { *(uint32 *)to = R_REG(osh, (uint32 *)from); from += 4; to += 4; cnt -= 4; } return (len - cnt); }
/* * chipc primary interrupt handler */ void sb_cc_isr(sb_t * sbh, chipcregs_t * regs) { uint32 ccintstatus; uint32 intstatus; uint32 i; /* prior to rev 21 chipc interrupt means uart and gpio */ if (sbh->ccrev >= 21) ccintstatus = R_REG(sb_osh(sbh), ®s->intstatus) & cc_intmask; else ccintstatus = (CI_UART | CI_GPIO); for (i = 0; i < MAX_CC_INT_SOURCE; i++) { if ((cc_isr_desc[i].isr != NULL) && (intstatus = (cc_isr_desc[i].intmask & ccintstatus))) { (cc_isr_desc[i].isr) (cc_isr_desc[i].cbdata, intstatus); } } }
static void __init sb_extif_serial_init(sb_t * sbh, void *regs, sb_serial_init_fn add) { osl_t *osh = sb_osh(sbh); extifregs_t *eir = (extifregs_t *) regs; sbconfig_t *sb; ulong base; uint irq; int i, n; /* Determine external UART register base */ sb = (sbconfig_t *) ((ulong) eir + SBCONFIGOFF); base = EXTIF_CFGIF_BASE(sb_base(R_REG(osh, &sb->sbadmatch1))); /* Determine IRQ */ irq = sb_irq(sbh); /* Disable GPIO interrupt initially */ W_REG(osh, &eir->gpiointpolarity, 0); W_REG(osh, &eir->gpiointmask, 0); /* Search for external UARTs */ n = 2; for (i = 0; i < 2; i++) { regs = (void *)REG_MAP(base + (i * 8), 8); if (serial_exists(osh, regs)) { /* Set GPIO 1 to be the external UART IRQ */ W_REG(osh, &eir->gpiointmask, 2); /* XXXDetermine external UART clock */ if (add) add(regs, irq, 13500000, 0); } } /* Add internal UART if enabled */ if (R_REG(osh, &eir->corecontrol) & CC_UE) if (add) add((void *)&eir->uartdata, irq, sb_clock(sbh), 2); }
/* * Read host bridge PCI config registers from Silicon Backplane (>=rev8). * * It returns TRUE to indicate that access to the host bridge's pci config * from SB is ok, and values in 'addr' and 'val' are valid. * * It can only read registers at multiple of 4-bytes. Callers must pick up * needed bytes from 'val' based on 'off' value. Value in 'addr' reflects * the register address where value in 'val' is read. */ static bool sb_pcihb_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, uint32 **addr, uint32 *val) { sbpciregs_t *regs; osl_t *osh; uint coreidx; bool ret = FALSE; /* sanity check */ ASSERT(bus == 1); ASSERT(dev == pci_hbslot); ASSERT(func == 0); osh = sb_osh(sbh); /* read pci config when core rev >= 8 */ coreidx = sb_coreidx(sbh); regs = (sbpciregs_t *)sb_setcore(sbh, SB_PCI, 0); if (regs && sb_corerev(sbh) >= PCI_HBSBCFG_REV) { *addr = (uint32 *)®s->pcicfg[func][off >> 2]; *val = R_REG(osh, *addr); ret = TRUE; }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMINITFN(sb_serial_init) (sb_t * sbh, sb_serial_init_fn add) { osl_t *osh; void *regs; chipcregs_t *cc; uint32 rev, cap, pll, baud_base, div; uint irq; int i, n; osh = sb_osh(sbh); regs = sb_setcore(sbh, SB_EXTIF, 0); if (regs) { sb_extif_serial_init(sbh, regs, add); return; } cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); ASSERT(cc); /* Determine core revision and capabilities */ rev = sbh->ccrev; cap = sbh->cccaps; pll = cap & CC_CAP_PLL_MASK; /* Determine IRQ */ irq = sb_irq(sbh); if (pll == PLL_TYPE1) { /* PLL clock */ baud_base = sb_clock_rate(pll, R_REG(osh, &cc->clockcontrol_n), R_REG(osh, &cc->clockcontrol_m2)); div = 1; } else { /* 5354 chip common uart uses a constant clock * frequency of 25MHz */ if (sb_corerev(sbh) == 20) { /* Set the override bit so we don't divide it */ W_REG(osh, &cc->corecontrol, CC_UARTCLKO); baud_base = 25000000; } else if (rev >= 11 && rev != 15) { /* Fixed ALP clock */ baud_base = sb_alp_clock(sbh); div = 1; /* Turn off UART clock before switching clock source */ if (rev >= 21) AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); /* Set the override bit so we don't divide it */ OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); if (rev >= 21) OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); } else if (rev >= 3) { /* Internal backplane clock */ baud_base = sb_clock(sbh); div = 2; /* Minimum divisor */ W_REG(osh, &cc->clkdiv, ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); } else { /* Fixed internal backplane clock */ baud_base = 88000000; div = 48; } /* Clock source depends on strapping if UartClkOverride is unset */ if ((rev > 0) && ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) { if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) { /* Internal divided backplane clock */ baud_base /= div; } else { /* Assume external clock of 1.8432 MHz */ baud_base = 1843200; } } } /* Add internal UARTs */ n = cap & CC_CAP_UARTS_MASK; for (i = 0; i < n; i++) { /* Register offset changed after revision 0 */ if (rev) regs = (void *)((ulong) & cc->uart0data + (i * 256)); else regs = (void *)((ulong) & cc->uart0data + (i * 8)); if (add) add(regs, irq, baud_base, 0); } }
/* * Setup the gige core. * Resetting the core will lose all settings. */ void sb_gige_init(sb_t *sbh, uint32 unit, bool *rgmii) { volatile pci_config_regs *pci; sbgige_pcishim_t *ocp; sbconfig_t *sb; osl_t *osh; uint32 statelow; uint32 statehigh; uint32 base; uint32 idx; void *regs; /* Sanity checks */ ASSERT(sbh); ASSERT(rgmii); idx = sb_coreidx(sbh); /* point to the gige core registers */ regs = sb_setcore(sbh, SB_GIGETH, unit); ASSERT(regs); osh = sb_osh(sbh); pci = &((sbgige_t *)regs)->pcicfg; ocp = &((sbgige_t *)regs)->pcishim; sb = &((sbgige_t *)regs)->sbconfig; /* Enable the core clock and memory access */ if (!sb_iscoreup(sbh)) sb_core_reset(sbh, 0, 0); /* * Setup the 64K memory-mapped region base address through BAR0. * Leave the other BAR values alone. */ base = sb_base(R_REG(osh, &sb->sbadmatch1)); W_REG(osh, &pci->base[0], base); W_REG(osh, &pci->base[1], 0); /* * Enable the PCI memory access anyway. Any PCI config commands * issued before the core is enabled will go to the emulation * only and will not go to the real PCI config registers. */ OR_REG(osh, &pci->command, 2); /* * Enable the posted write flush scheme as follows: * * - Enable flush on any core register read * - Enable timeout on the flush * - Disable the interrupt mask when flushing * * This differs from the default setting only in that interrupts are * not masked. Since posted writes are not flushed on interrupt, the * driver must explicitly request a flush in its interrupt handling * by reading a core register. */ W_REG(osh, &ocp->FlushStatusControl, 0x68); /* * Determine whether the GbE is in GMII or RGMII mode. This is * indicated in bit 16 of the SBTMStateHigh register, which is * part of the core-specific flags field. * * For GMII, bypass the Rx/Tx DLLs, i.e. add no delay to RXC/GTXC * within the core. For RGMII, do not bypass the DLLs, resulting * in added delay for RXC/GTXC. The SBTMStateLow register contains * the controls for doing this in the core-specific flags field: * * bit 24 - Enable DLL controls * bit 20 - Bypass Rx DLL * bit 19 - Bypass Tx DLL */ statelow = R_REG(osh, &sb->sbtmstatelow); /* DLL controls */ statehigh = R_REG(osh, &sb->sbtmstatehigh); /* GMII/RGMII mode */ if ((statehigh & (1 << 16)) != 0) /* RGMII */ { statelow &= ~(1 << 20); /* no Rx bypass (delay) */ statelow &= ~(1 << 19); /* no Tx bypass (delay) */ *rgmii = TRUE; } else /* GMII */ { statelow |= (1 << 20); /* Rx bypass (no delay) */ statelow |= (1 << 19); /* Tx bypass (no delay) */ *rgmii = FALSE; } statelow |= (1 << 24); /* enable DLL controls */ W_REG(osh, &sb->sbtmstatelow, statelow); sb_setcoreidx(sbh, idx); }
/* Initialize serial flash access */ struct sflash * sflash_init(sb_t *sbh, chipcregs_t *cc) { uint32 id, id2; osl_t *osh; ASSERT(sbh); osh = sb_osh(sbh); bzero(&sflash, sizeof(sflash)); sflash.type = sbh->cccaps & CC_CAP_FLASH_MASK; switch (sflash.type) { case SFLASH_ST: /* Probe for ST chips */ sflash_cmd(osh, cc, SFLASH_ST_DP); sflash_cmd(osh, cc, SFLASH_ST_RES); id = R_REG(osh, &cc->flashdata); switch (id) { case 0x11: /* ST M25P20 2 Mbit Serial Flash */ sflash.blocksize = 64 * 1024; sflash.numblocks = 4; break; case 0x12: /* ST M25P40 4 Mbit Serial Flash */ sflash.blocksize = 64 * 1024; sflash.numblocks = 8; break; case 0x13: /* ST M25P80 8 Mbit Serial Flash */ sflash.blocksize = 64 * 1024; sflash.numblocks = 16; break; case 0x14: /* ST M25P16 16 Mbit Serial Flash */ sflash.blocksize = 64 * 1024; sflash.numblocks = 32; break; case 0x15: /* ST M25P32 32 Mbit Serial Flash */ sflash.blocksize = 64 * 1024; sflash.numblocks = 64; break; case 0x16: /* ST M25P64 64 Mbit Serial Flash */ sflash.blocksize = 64 * 1024; sflash.numblocks = 128; break; case 0xbf: W_REG(osh, &cc->flashaddress, 1); sflash_cmd(osh, cc, SFLASH_ST_RES); id2 = R_REG(osh, &cc->flashdata); if (id2 == 0x44) { /* SST M25VF80 4 Mbit Serial Flash */ sflash.blocksize = 64 * 1024; sflash.numblocks = 8; } break; } break; case SFLASH_AT: /* Probe for Atmel chips */ sflash_cmd(osh, cc, SFLASH_AT_STATUS); id = R_REG(osh, &cc->flashdata) & 0x3c; switch (id) { case 0xc: /* Atmel AT45DB011 1Mbit Serial Flash */ sflash.blocksize = 256; sflash.numblocks = 512; break; case 0x14: /* Atmel AT45DB021 2Mbit Serial Flash */ sflash.blocksize = 256; sflash.numblocks = 1024; break; case 0x1c: /* Atmel AT45DB041 4Mbit Serial Flash */ sflash.blocksize = 256; sflash.numblocks = 2048; break; case 0x24: /* Atmel AT45DB081 8Mbit Serial Flash */ sflash.blocksize = 256; sflash.numblocks = 4096; break; case 0x2c: /* Atmel AT45DB161 16Mbit Serial Flash */ sflash.blocksize = 512; sflash.numblocks = 4096; break; case 0x34: /* Atmel AT45DB321 32Mbit Serial Flash */ sflash.blocksize = 512; sflash.numblocks = 8192; break; case 0x3c: /* Atmel AT45DB642 64Mbit Serial Flash */ sflash.blocksize = 1024; sflash.numblocks = 8192; break; } break; } sflash.size = sflash.blocksize * sflash.numblocks; return sflash.size ? &sflash : NULL; }
/* Write len bytes starting at offset into buf. Returns number of bytes * written. Caller should poll for completion. */ int sflash_write(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar *buf) { struct sflash *sfl; int ret = 0; bool is4712b0; uint32 page, byte, mask; osl_t *osh; ASSERT(sbh); osh = sb_osh(sbh); if (!len) return 0; if ((offset + len) > sflash.size) return -22; sfl = &sflash; switch (sfl->type) { case SFLASH_ST: mask = R_REG(osh, &cc->chipid); is4712b0 = (((mask & CID_ID_MASK) == BCM4712_CHIP_ID) && ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT))); /* Enable writes */ sflash_cmd(osh, cc, SFLASH_ST_WREN); if (is4712b0) { mask = 1 << 14; W_REG(osh, &cc->flashaddress, offset); W_REG(osh, &cc->flashdata, *buf++); /* Set chip select */ OR_REG(osh, &cc->gpioout, mask); /* Issue a page program with the first byte */ sflash_cmd(osh, cc, SFLASH_ST_PP); ret = 1; offset++; len--; while (len > 0) { if ((offset & 255) == 0) { /* Page boundary, drop cs and return */ AND_REG(osh, &cc->gpioout, ~mask); if (!sflash_poll(sbh, cc, offset)) { /* Flash rejected command */ return -11; } return ret; } else { /* Write single byte */ sflash_cmd(osh, cc, *buf++); } ret++; offset++; len--; } /* All done, drop cs if needed */ if ((offset & 255) != 1) { /* Drop cs */ AND_REG(osh, &cc->gpioout, ~mask); if (!sflash_poll(sbh, cc, offset)) { /* Flash rejected command */ return -12; } } } else if (sbh->ccrev >= 20) { W_REG(NULL, &cc->flashaddress, offset); W_REG(NULL, &cc->flashdata, *buf++); /* Issue a page program with CSA bit set */ sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP); ret = 1; offset++; len--; while (len > 0) { if ((offset & 255) == 0) { /* Page boundary, poll droping cs and return */ W_REG(NULL, &cc->flashcontrol, 0); if (!sflash_poll(sbh, cc, offset)) { /* Flash rejected command */ return -11; } return ret; } else { /* Write single byte */ sflash_cmd(osh, cc, SFLASH_ST_CSA | *buf++); } ret++; offset++; len--; } /* All done, drop cs if needed */ if ((offset & 255) != 1) { /* Drop cs, poll */ W_REG(NULL, &cc->flashcontrol, 0); if (!sflash_poll(sbh, cc, offset)) { /* Flash rejected command */ return -12; } } } else { ret = 1; W_REG(osh, &cc->flashaddress, offset); W_REG(osh, &cc->flashdata, *buf); /* Page program */ sflash_cmd(osh, cc, SFLASH_ST_PP); } break; case SFLASH_AT: mask = sfl->blocksize - 1; page = (offset & ~mask) << 1; byte = offset & mask; /* Read main memory page into buffer 1 */ if (byte || (len < sfl->blocksize)) { W_REG(osh, &cc->flashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD); /* 250 us for AT45DB321B */ SPINWAIT(sflash_poll(sbh, cc, offset), 1000); ASSERT(!sflash_poll(sbh, cc, offset)); } /* Write into buffer 1 */ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) { W_REG(osh, &cc->flashaddress, byte++); W_REG(osh, &cc->flashdata, *buf++); sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE); } /* Write buffer 1 into main memory page */ W_REG(osh, &cc->flashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM); break; } return ret; }
/* * Initialize nonvolatile variable table from sprom. * Return 0 on success, nonzero on error. */ static int initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count) { uint16 w, *b; uint8 sromrev = 0; struct ether_addr ea; char eabuf[32]; uint32 w32; int woff, i; char *vp, *base; osl_t *osh = sb_osh(sbh); bool flash = FALSE; char name[SB_DEVPATH_BUFSZ+16], *value; char devpath[SB_DEVPATH_BUFSZ]; int err; /* * Apply CRC over SROM content regardless SROM is present or not, * and use variable <devpath>sromrev's existance in flash to decide * if we should return an error when CRC fails or read SROM variables * from flash. */ b = MALLOC(osh, SROM_MAX); ASSERT(b); if (!b) return -2; err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, 64, TRUE); if (b[SROM4_SIGN] == SROM4_SIGNATURE) { /* sromrev >= 4, read more */ err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, SROM4_WORDS, TRUE); sromrev = b[SROM4_WORDS - 1] & 0xff; } else if (err == 0) { /* srom is good and is rev < 4 */ /* top word of sprom contains version and crc8 */ sromrev = b[63] & 0xff; /* bcm4401 sroms misprogrammed */ if (sromrev == 0x10) sromrev = 1; } if (err) { #ifdef WLTEST BS_ERROR(("SROM Crc Error, so see if we could use a default\n")); w32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); if (w32 & SPROM_OTPIN_USE) { BS_ERROR(("srom crc failed with OTP, use default vars....\n")); vp = base = mfgsromvars; if (sb_chip(sbh) == BCM4311_CHIP_ID) { BS_ERROR(("setting the devid to be 4311\n")); vp += sprintf(vp, "devid=0x4311"); vp++; } bcopy(defaultsromvars, vp, MFGSROM_DEFVARSLEN); vp += MFGSROM_DEFVARSLEN; goto varsdone; } else { BS_ERROR(("srom crc failed with SPROM....\n")); #endif /* WLTEST */ if ((err = sb_devpath(sbh, devpath, sizeof(devpath)))) return err; sprintf(name, "%ssromrev", devpath); if (!(value = getvar(NULL, name))) return (-1); sromrev = (uint8)bcm_strtoul(value, NULL, 0); flash = TRUE; #ifdef WLTEST } #endif /* WLTEST */ } /* srom version check */ if (sromrev > 4) return (-2); ASSERT(vars); ASSERT(count); base = vp = MALLOC(osh, VARS_MAX); ASSERT(vp); if (!vp) return -2; /* read variables from flash */ if (flash) { if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath))) goto err; goto varsdone; } vp += sprintf(vp, "sromrev=%d", sromrev); vp++; if (sromrev >= 4) { uint path, pathbase; const uint pathbases[MAX_PATH] = {SROM4_PATH0, SROM4_PATH1, SROM4_PATH2, SROM4_PATH3}; vp += sprintf(vp, "boardrev=%d", b[SROM4_BREV]); vp++; vp += sprintf(vp, "boardflags=%d", (b[SROM4_BFL1] << 16) | b[SROM4_BFL0]); vp++; vp += sprintf(vp, "boardflags2=%d", (b[SROM4_BFL3] << 16) | b[SROM4_BFL2]); vp++; /* The macaddr */ ea.octet[0] = (b[SROM4_MACHI] >> 8) & 0xff; ea.octet[1] = b[SROM4_MACHI] & 0xff; ea.octet[2] = (b[SROM4_MACMID] >> 8) & 0xff; ea.octet[3] = b[SROM4_MACMID] & 0xff; ea.octet[4] = (b[SROM4_MACLO] >> 8) & 0xff; ea.octet[5] = b[SROM4_MACLO] & 0xff; bcm_ether_ntoa(&ea, eabuf); vp += sprintf(vp, "macaddr=%s", eabuf); vp++; w = b[SROM4_CCODE]; if (w == 0) vp += sprintf(vp, "ccode="); else vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff)); vp++; vp += sprintf(vp, "regrev=%d", b[SROM4_REGREV]); vp++; w = b[SROM4_LEDBH10]; if ((w != 0) && (w != 0xffff)) { /* ledbh0 */ vp += sprintf(vp, "ledbh0=%d", (w & 0xff)); vp++; /* ledbh1 */ vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff); vp++; }
/* * writes the appropriate range of flash, a NULL buf simply erases * the region of flash */ int sflash_commit(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar *buf) { struct sflash *sfl; uchar *block = NULL, *cur_ptr, *blk_ptr; uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder; uint blk_offset, blk_len, copied; int bytes, ret = 0; osl_t *osh; ASSERT(sbh); osh = sb_osh(sbh); /* Check address range */ if (len <= 0) return 0; sfl = &sflash; if ((offset + len) > sfl->size) return -1; blocksize = sfl->blocksize; mask = blocksize - 1; /* Allocate a block of mem */ if (!(block = MALLOC(osh, blocksize))) return -1; while (len) { /* Align offset */ cur_offset = offset & ~mask; cur_length = blocksize; cur_ptr = block; remainder = blocksize - (offset & mask); if (len < remainder) cur_retlen = len; else cur_retlen = remainder; /* buf == NULL means erase only */ if (buf) { /* Copy existing data into holding block if necessary */ if ((offset & mask) || (len < blocksize)) { blk_offset = cur_offset; blk_len = cur_length; blk_ptr = cur_ptr; /* Copy entire block */ while (blk_len) { copied = sflash_read(sbh, cc, blk_offset, blk_len, blk_ptr); blk_offset += copied; blk_len -= copied; blk_ptr += copied; } } /* Copy input data into holding block */ memcpy(cur_ptr + (offset & mask), buf, cur_retlen); } /* Erase block */ if ((ret = sflash_erase(sbh, cc, (uint) cur_offset)) < 0) goto done; while (sflash_poll(sbh, cc, (uint) cur_offset)); /* buf == NULL means erase only */ if (!buf) { offset += cur_retlen; len -= cur_retlen; continue; } /* Write holding block */ while (cur_length > 0) { if ((bytes = sflash_write(sbh, cc, (uint) cur_offset, (uint) cur_length, (uchar *) cur_ptr)) < 0) { ret = bytes; goto done; } while (sflash_poll(sbh, cc, (uint) cur_offset)); cur_offset += bytes; cur_length -= bytes; cur_ptr += bytes; } offset += cur_retlen; len -= cur_retlen; buf += cur_retlen; } ret = len; done: if (block) MFREE(osh, block, blocksize); return ret; }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMINITFN(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift)) { osl_t *osh; void *regs; ulong base; uint irq; int i, n; osh = sb_osh(sbh); if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) { extifregs_t *eir = (extifregs_t *) regs; sbconfig_t *sb; /* Determine external UART register base */ sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF); base = EXTIF_CFGIF_BASE(sb_base(R_REG(osh, &sb->sbadmatch1))); /* Determine IRQ */ irq = sb_irq(sbh); /* Disable GPIO interrupt initially */ W_REG(osh, &eir->gpiointpolarity, 0); W_REG(osh, &eir->gpiointmask, 0); /* Search for external UARTs */ n = 2; for (i = 0; i < 2; i++) { regs = (void *) REG_MAP(base + (i * 8), 8); if (serial_exists(osh, regs)) { /* Set GPIO 1 to be the external UART IRQ */ W_REG(osh, &eir->gpiointmask, 2); /* XXXDetermine external UART clock */ if (add) add(regs, irq, 13500000, 0); } } /* Add internal UART if enabled */ if (R_REG(osh, &eir->corecontrol) & CC_UE) if (add) add((void *) &eir->uartdata, irq, sb_clock(sbh), 2); } else if ((regs = sb_setcore(sbh, SB_CC, 0))) { chipcregs_t *cc = (chipcregs_t *) regs; uint32 rev, cap, pll, baud_base, div; /* Default value */ div = 48; /* Determine core revision and capabilities */ rev = sb_corerev(sbh); cap = R_REG(osh, &cc->capabilities); pll = cap & CAP_PLL_MASK; /* Determine IRQ */ irq = sb_irq(sbh); if (pll == PLL_TYPE1) { /* PLL clock */ baud_base = sb_clock_rate(pll, R_REG(osh, &cc->clockcontrol_n), R_REG(osh, &cc->clockcontrol_m2)); div = 1; } else { /* 5354 chip common uart uses a constant clock * frequency of 25MHz */ if (sb_corerev(sbh) == 20) { /* Set the override bit so we don't divide it */ W_REG(osh, &cc->corecontrol, CC_UARTCLKO); baud_base = 25000000; } else if (rev >= 11 && rev != 15) { /* Fixed ALP clock */ baud_base = sb_alp_clock(sbh); div = 1; /* Set the override bit so we don't divide it */ W_REG(osh, &cc->corecontrol, CC_UARTCLKO); } else if (rev >= 3) { /* Internal backplane clock */ baud_base = sb_clock(sbh); div = 2; /* Minimum divisor */ W_REG(osh, &cc->clkdiv, ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); } else { /* Fixed internal backplane clock */ baud_base = 88000000; div = 48; } /* Clock source depends on strapping if UartClkOverride is unset */ if ((rev > 0) && ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) { if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) { /* Internal divided backplane clock */ baud_base /= div; } else { /* Assume external clock of 1.8432 MHz */ baud_base = 1843200; } } } /* Add internal UARTs */ n = cap & CAP_UARTS_MASK; for (i = 0; i < n; i++) { /* Register offset changed after revision 0 */ if (rev) regs = (void *)((ulong) &cc->uart0data + (i * 256)); else regs = (void *)((ulong) &cc->uart0data + (i * 8)); if (add) add(regs, irq, baud_base, 0); } } }
/* Read the flash ID and set the globals */ int sysFlashInit(char *flash_str) { osl_t *osh; uint32 fltype = PFLASH; uint16 flash_vendid = 0; uint16 flash_devid = 0; int idx; struct sflash *sflash; /* * Check for serial flash. */ sbh = sb_kattach(SB_OSH); ASSERT(sbh); osh = sb_osh(sbh); flashutl_base = (uint8*)OSL_UNCACHED(SB_FLASH1); flashutl_wsz = sizeof(uint16); cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0); if (cc) { flashutl_base = (uint8*)OSL_UNCACHED(SB_FLASH2); flashutl_wsz = (R_REG(osh, &cc->flash_config) & CC_CFG_DS) ? sizeof(uint16) : sizeof(uint8); /* Select SFLASH ? */ fltype = R_REG(osh, &cc->capabilities) & CC_CAP_FLASH_MASK; if (fltype == SFLASH_ST || fltype == SFLASH_AT) { sflash = sflash_init(sbh, cc); flashutl_cmd = &sflash_cmd_t; flashutl_desc = &sflash_desc; flashutl_desc->size = sflash->size; if (flash_str) sprintf(flash_str, "SFLASH %d kB", sflash->size/1024); return (0); } } ASSERT(flashutl_wsz == sizeof(uint8) || flashutl_wsz == sizeof(uint16)); /* * Parallel flash support * Some flashes have different unlock addresses, try each it turn */ for (idx = 0; fltype == PFLASH && idx < ARRAYSIZE(flash_cmds); idx ++) { flashutl_cmd = &flash_cmds[idx]; if (flashutl_cmd->type == OLD) continue; if (flashutl_cmd->read_id) cmd(flashutl_cmd->read_id, CMD_ADDR); #ifdef MIPSEB flash_vendid = flash_readword(FLASH_ADDR(2)); flash_devid = flash_readword(FLASH_ADDR(0)); #else flash_vendid = flash_readword(FLASH_ADDR(0)); flash_devid = flash_readword(FLASH_ADDR(2)); #endif /* MIPSEB */ /* Funky AMD, uses 3 byte device ID so use first byte (4th addr) to * identify it is a 3-byte ID and use the next two bytes (5th & 6th addr) * to form a word for unique identification of format xxyy, where * xx = 5th addr and yy = 6th addr */ if ((flash_vendid == 1) && (flash_devid == 0x227e)) { /* Get real devid */ uint16 flash_devid_5th; #ifdef MIPSEB flash_devid_5th = flash_readword(FLASH_ADDR(0x1e)) << 8; flash_devid = (flash_readword(FLASH_ADDR(0x1c)) & 0xff) | flash_devid_5th; #else flash_devid_5th = flash_readword(FLASH_ADDR(0x1c)) << 8; flash_devid = (flash_readword(FLASH_ADDR(0x1e)) & 0xff) | flash_devid_5th; #endif /* MIPSEB */ } flashutl_desc = flashes; while (flashutl_desc->mfgid != 0 && !(flashutl_desc->mfgid == flash_vendid && flashutl_desc->devid == flash_devid)) { flashutl_desc++; } if (flashutl_desc->mfgid != 0) break; } if (flashutl_desc->mfgid == 0) { flashutl_desc = NULL; flashutl_cmd = NULL; } else { flashutl_cmd = flash_cmds; while (flashutl_cmd->type != 0 && flashutl_cmd->type != flashutl_desc->type) flashutl_cmd++; if (flashutl_cmd->type == 0) flashutl_cmd = NULL; } if (flashutl_cmd != NULL) { flash_reset(); } if (flashutl_desc == NULL) { if (flash_str) sprintf(flash_str, "UNKNOWN 0x%x 0x%x", flash_vendid, flash_devid); DPRINT(("Flash type UNKNOWN\n")); return 1; } if (flash_str) strcpy(flash_str, flashutl_desc->desc); DPRINT(("Flash type \"%s\"\n", flashutl_desc->desc)); return 0; }