Beispiel #1
0
/*
 * 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), &regs->intmask);
		cc_intmask |= ccintmask;
		W_REG(sb_osh(sbh), &regs->intmask, cc_intmask);
	}

	/* restore original coreidx */
	sb_setcoreidx(sbh, origidx);
	return done;
}
Beispiel #2
0
/* 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;
}
Beispiel #3
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;
}
Beispiel #4
0
/* 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;
}
Beispiel #5
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, &regs->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, &regs->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;
}
Beispiel #6
0
/* 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);
}
Beispiel #7
0
/* 
 * 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), &regs->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);
		}
	}
}
Beispiel #8
0
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);
}
Beispiel #9
0
/*
 * 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 *)&regs->pcicfg[func][off >> 2];
		*val = R_REG(osh, *addr);
		ret = TRUE;
	}
Beispiel #10
0
/*
 * 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);
	}
}
Beispiel #11
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);
}
Beispiel #12
0
/* 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;
}
Beispiel #13
0
/* 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;
}
Beispiel #14
0
/*
 * 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++;
		}
Beispiel #15
0
/*
 * 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;
}
Beispiel #16
0
/*
 * 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);
		}
	}
}
Beispiel #17
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;
}