⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sbutils.c

📁 wi-fi sources for asus wl138g v2 pci card
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * * Copyright 2005-2006, Broadcom Corporation * All Rights Reserved. *  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * $Id$ */#include <typedefs.h>#include <bcmdefs.h>#include <osl.h>#include <sbutils.h>#include <bcmutils.h>#include <bcmdevs.h>#include <sbconfig.h>#include <sbchipc.h>#include <sbpci.h>#include <sbpcie.h>#include <pcicfg.h>#include <bcmsrom.h>/* debug/trace */#define	SB_ERROR(args)typedef uint32 (*sb_intrsoff_t)(void *intr_arg);typedef void (*sb_intrsrestore_t)(void *intr_arg, uint32 arg);typedef bool (*sb_intrsenabled_t)(void *intr_arg);/* misc sb info needed by some of the routines */typedef struct sb_info {	struct sb_pub  	sb;		/* back plane public state (must be first field) */	void	*osh;			/* osl os handle */	void	*sdh;			/* bcmsdh handle */	void	*curmap;		/* current regs va */	void	*regs[SB_MAXCORES];	/* other regs va */	uint	curidx;			/* current core index */	uint	dev_coreid;		/* the core provides driver functions */	bool	memseg;			/* flag to toggle MEM_SEG register */	uint	gpioidx;		/* gpio control core index */	uint	gpioid;			/* gpio control coretype */	uint	numcores;		/* # discovered cores */	uint	coreid[SB_MAXCORES];	/* id of each core */	void	*intr_arg;		/* interrupt callback function arg */	sb_intrsoff_t		intrsoff_fn;		/* turns chip interrupts off */	sb_intrsrestore_t	intrsrestore_fn;	/* restore chip interrupts */	sb_intrsenabled_t	intrsenabled_fn;	/* check if interrupts are enabled */} sb_info_t;/* local prototypes */static sb_info_t * sb_doattach(sb_info_t *si, uint devid, osl_t *osh, void *regs,	uint bustype, void *sdh, char **vars, uint *varsz);static void sb_scan(sb_info_t *si);static uint sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val);static uint _sb_coreidx(sb_info_t *si);static uint sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit);static bool sb_ispcie(sb_info_t *si);static bool sb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen);static int sb_pci_fixcfg(sb_info_t *si);/* routines to access mdio slave device registers */static int sb_pcie_mdiowrite(sb_info_t *si,  uint physmedia, uint readdr, uint val);static void sb_war30841(sb_info_t *si);/* delay needed between the mdio control/ mdiodata register data access */#define PR28829_DELAY() OSL_DELAY(10)/* global variable to indicate reservation/release of gpio's */static uint32 sb_gpioreservation = 0;#define	SB_INFO(sbh)	(sb_info_t*)sbh#define	SET_SBREG(si, r, mask, val)	\		W_SBREG((si), (r), ((R_SBREG((si), (r)) & ~(mask)) | (val)))#define	GOODCOREADDR(x)	(((x) >= SB_ENUM_BASE) && ((x) <= SB_ENUM_LIM) && \		ISALIGNED((x), SB_CORE_SIZE))#define	GOODREGS(regs)	((regs) && ISALIGNED((uintptr)(regs), SB_CORE_SIZE))#define	REGS2SB(va)	(sbconfig_t*) ((int8*)(va) + SBCONFIGOFF)#define	GOODIDX(idx)	(((uint)idx) < SB_MAXCORES)#define	BADIDX		(SB_MAXCORES+1)#define	NOREV		-1		/* Invalid rev */#define PCI(si)		((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCI))#define PCIE(si)	((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCIE))/* sonicsrev */#define	SONICS_2_2	(SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)#define	SONICS_2_3	(SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)#define	R_SBREG(si, sbr)	sb_read_sbreg((si), (sbr))#define	W_SBREG(si, sbr, v)	sb_write_sbreg((si), (sbr), (v))#define	AND_SBREG(si, sbr, v)	W_SBREG((si), (sbr), (R_SBREG((si), (sbr)) & (v)))#define	OR_SBREG(si, sbr, v)	W_SBREG((si), (sbr), (R_SBREG((si), (sbr)) | (v)))/* * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/ * after core switching to avoid invalid register accesss inside ISR. */#define INTR_OFF(si, intr_val) \	if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) {	\		intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); }#define INTR_RESTORE(si, intr_val) \	if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) {	\		(*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); }/* dynamic clock control defines */#define	LPOMINFREQ		25000		/* low power oscillator min */#define	LPOMAXFREQ		43000		/* low power oscillator max */#define	XTALMINFREQ		19800000	/* 20 MHz - 1% */#define	XTALMAXFREQ		20200000	/* 20 MHz + 1% */#define	PCIMINFREQ		25000000	/* 25 MHz */#define	PCIMAXFREQ		34000000	/* 33 MHz + fudge */#define	ILP_DIV_5MHZ		0		/* ILP = 5 MHz */#define	ILP_DIV_1MHZ		4		/* ILP = 1 MHz */#define MIN_DUMPBUFLEN  	32		/* debug *//* different register spaces to access thr'u pcie indirect access */#define PCIE_CONFIGREGS 	1		/* Access to config space */#define PCIE_PCIEREGS 		2		/* Access to pcie registers *//* GPIO Based LED powersave defines */#define DEFAULT_GPIO_ONTIME	10		/* Default: 10% on */#define DEFAULT_GPIO_OFFTIME	90		/* Default: 10% on */#define DEFAULT_GPIOTIMERVAL  ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)static uint32sb_read_sbreg(sb_info_t *si, volatile uint32 *sbr){	return (R_REG(sbr));}static voidsb_write_sbreg(sb_info_t *si, volatile uint32 *sbr, uint32 v){	W_REG(sbr, v);}/* * Allocate a sb handle. * devid - pci device id (used to determine chip#) * osh - opaque OS handle * regs - virtual address of initial core registers * bustype - pci/pcmcia/sb/sdio/etc * vars - pointer to a pointer area for "environment" variables * varsz - pointer to int to return the size of the vars */sb_t *BCMINITFN(sb_attach)(uint devid, osl_t *osh, void *regs,	uint bustype, void *sdh, char **vars, int *varsz){	sb_info_t *si;	/* alloc sb_info_t */	if ((si = MALLOC(osh, sizeof (sb_info_t))) == NULL) {		SB_ERROR(("sb_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));		return (NULL);	}	if (sb_doattach(si, devid, osh, regs, bustype, sdh, vars, (uint*)varsz) == NULL) {		MFREE(osh, si, sizeof(sb_info_t));		return (NULL);	}	return (sb_t *)si;}static sb_info_t  *BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs,                       uint bustype, void *sdh, char **vars, uint *varsz){	uint origidx;	chipcregs_t *cc;	sbconfig_t *sb;	uint32 w;	ASSERT(GOODREGS(regs));	bzero((uchar*)si, sizeof(sb_info_t));	si->sb.buscoreidx = si->gpioidx = BADIDX;	si->osh = osh;	si->curmap = regs;	si->sdh = sdh;	/* check to see if we are a sb core mimic'ing a pci core */	if (bustype == PCI_BUS) {		if (OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof (uint32)) == 0xffffffff) {			SB_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SB "			          "devid:0x%x\n", __FUNCTION__, devid));			bustype = SB_BUS;		}	}	si->sb.bustype = bustype;	if (si->sb.bustype != BUSTYPE(si->sb.bustype)) {		SB_ERROR(("sb_doattach: bus type %d does not match configured bus type %d\n",		          si->sb.bustype, BUSTYPE(si->sb.bustype)));		return NULL;	}	/* kludge to enable the clock on the 4306 which lacks a slowclock */	if (BUSTYPE(si->sb.bustype) == PCI_BUS)		sb_clkctl_xtal(&si->sb, XTAL|PLL, ON);	if (BUSTYPE(si->sb.bustype) == PCI_BUS) {		w = OSL_PCI_READ_CONFIG(osh, PCI_BAR0_WIN, sizeof(uint32));		if (!GOODCOREADDR(w))			OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32), SB_ENUM_BASE);	}	/* initialize current core index value */	si->curidx = _sb_coreidx(si);	if (si->curidx == BADIDX) {		SB_ERROR(("sb_doattach: bad core index\n"));		return NULL;	}	/* get sonics backplane revision */	sb = REGS2SB(si->curmap);	si->sb.sonicsrev = (R_SBREG(si, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT;	/* keep and reuse the initial register mapping */	origidx = si->curidx;	if (BUSTYPE(si->sb.bustype) == SB_BUS)		si->regs[origidx] = regs;	/* is core-0 a chipcommon core? */	si->numcores = 1;	cc = (chipcregs_t*) sb_setcoreidx(&si->sb, 0);	if (sb_coreid(&si->sb) != SB_CC)		cc = NULL;	/* determine chip id and rev */	if (cc) {		/* chip common core found! */		si->sb.chip = R_REG(&cc->chipid) & CID_ID_MASK;		si->sb.chiprev = (R_REG(&cc->chipid) & CID_REV_MASK) >> CID_REV_SHIFT;		si->sb.chippkg = (R_REG(&cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT;	} else		return NULL;	/* get chipcommon rev */	si->sb.ccrev = cc ? (int)sb_corerev(&si->sb) : NOREV;	/* determine numcores */	if (cc && ((si->sb.ccrev == 4) || (si->sb.ccrev >= 6)))		si->numcores = (R_REG(&cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT;	/* return to original core */	sb_setcoreidx(&si->sb, origidx);	/* sanity checks */	ASSERT(si->sb.chip);	/* scan for cores */	sb_scan(si);	/* fixup necessary chip/core configurations */	if (BUSTYPE(si->sb.bustype) == PCI_BUS) {		if (sb_pci_fixcfg(si)) {			SB_ERROR(("sb_doattach: sb_pci_fixcfg failed\n"));			return NULL;		}	}	/* srom_var_init() depends on sb_scan() info */	if (srom_var_init(si, si->sb.bustype, si->curmap, osh, vars, varsz)) {		SB_ERROR(("sb_doattach: srom_var_init failed: bad srom\n"));		return (NULL);	}	if (cc == NULL) {		/*		 * The chip revision number is hardwired into all		 * of the pci function config rev fields and is		 * independent from the individual core revision numbers.		 * For example, the "A0" silicon of each chip is chip rev 0.		 */		if (BUSTYPE(si->sb.bustype) == PCI_BUS) {			w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_REV, sizeof(uint32));			si->sb.chiprev = w & 0xff;		} else			si->sb.chiprev = 0;	}	/* gpio control core is required */	if (!GOODIDX(si->gpioidx)) {		SB_ERROR(("sb_doattach: gpio control core not found\n"));		return NULL;	}	/* get boardtype and boardrev */	switch (BUSTYPE(si->sb.bustype)) {	case PCI_BUS:		/* do a pci config read to get subsystem id and subvendor id */		w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_SVID, sizeof(uint32));		si->sb.boardvendor = w & 0xffff;		si->sb.boardtype = (w >> 16) & 0xffff;		break;	}	if (si->sb.boardtype == 0) {		SB_ERROR(("sb_doattach: unknown board type\n"));		ASSERT(si->sb.boardtype);	}	/* setup the GPIO based LED powersave register */	if (si->sb.ccrev >= 16) {		if ((vars == NULL) || ((w = getintvar(*vars, "gpiotimerval")) == 0))			w = DEFAULT_GPIOTIMERVAL;		sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), ~0, w);	}	if ((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev <= 1)) {		/* set proper clk setup delays before forcing HT */		sb_clkctl_init((void *)si);		sb_corereg((void*)si, SB_CC_IDX, OFFSETOF(chipcregs_t, system_clk_ctl),		           SYCC_HR, SYCC_HR);	}	return (si);}uintsb_coreid(sb_t *sbh){	sb_info_t *si;	sbconfig_t *sb;	si = SB_INFO(sbh);	sb = REGS2SB(si->curmap);	return ((R_SBREG(si, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);}uintsb_coreidx(sb_t *sbh){	sb_info_t *si;	si = SB_INFO(sbh);	return (si->curidx);}/* return current index of core */static uint_sb_coreidx(sb_info_t *si){	uint32 sbaddr = 0;	ASSERT(si);	switch (BUSTYPE(si->sb.bustype)) {	case PCI_BUS:		sbaddr = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32));		break;	default:		ASSERT(0);	}	if (!GOODCOREADDR(sbaddr))		return BADIDX;	return ((sbaddr - SB_ENUM_BASE) / SB_CORE_SIZE);}uintsb_corevendor(sb_t *sbh){	sb_info_t *si;	sbconfig_t *sb;	si = SB_INFO(sbh);	sb = REGS2SB(si->curmap);	return ((R_SBREG(si, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);}uintsb_corerev(sb_t *sbh){	sb_info_t *si;	sbconfig_t *sb;	uint sbidh;	si = SB_INFO(sbh);	sb = REGS2SB(si->curmap);	sbidh = R_SBREG(si, &sb->sbidhigh);	return (SBCOREREV(sbidh));}void *sb_osh(sb_t *sbh){	sb_info_t *si;	si = SB_INFO(sbh);	return si->osh;}#define	SBTML_ALLOW	(SBTML_PE | SBTML_FGC | SBTML_FL_MASK)/* set/clear sbtmstatelow core-specific flags */uint32sb_coreflags(sb_t *sbh, uint32 mask, uint32 val){	sb_info_t *si;	sbconfig_t *sb;	uint32 w;	si = SB_INFO(sbh);	sb = REGS2SB(si->curmap);	ASSERT((val & ~mask) == 0);	ASSERT((mask & ~SBTML_ALLOW) == 0);	/* mask and set */	if (mask || val) {		w = (R_SBREG(si, &sb->sbtmstatelow) & ~mask) | val;		W_SBREG(si, &sb->sbtmstatelow, w);	}	/* return the new value */	return (R_SBREG(si, &sb->sbtmstatelow) & SBTML_ALLOW);}/* set/clear sbtmstatehigh core-specific flags */uint32sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val){	sb_info_t *si;	sbconfig_t *sb;	uint32 w;	si = SB_INFO(sbh);	sb = REGS2SB(si->curmap);	ASSERT((val & ~mask) == 0);	ASSERT((mask & ~SBTMH_FL_MASK) == 0);	/* mask and set */	if (mask || val) {		w = (R_SBREG(si, &sb->sbtmstatehigh) & ~mask) | val;		W_SBREG(si, &sb->sbtmstatehigh, w);	}	/* return the new value */	return (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_FL_MASK);}/* Run bist on current core. Caller needs to take care of core-specific bist hazards */intsb_corebist(sb_t *sbh){	uint32 sblo;	sb_info_t *si;	sbconfig_t *sb;	int result = 0;	si = SB_INFO(sbh);	sb = REGS2SB(si->curmap);	sblo = R_SBREG(si, &sb->sbtmstatelow);	W_SBREG(si, &sb->sbtmstatelow, (sblo | SBTML_FGC | SBTML_BE));	SPINWAIT(((R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BISTD) == 0), 100000);	if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BISTF)		result = BCME_ERROR;	W_SBREG(si, &sb->sbtmstatelow, sblo);	return result;}boolsb_iscoreup(sb_t *sbh){	sb_info_t *si;	sbconfig_t *sb;	si = SB_INFO(sbh);	sb = REGS2SB(si->curmap);	return ((R_SBREG(si, &sb->sbtmstatelow) &	         (SBTML_RESET | SBTML_REJ_MASK | SBTML_CLK)) == SBTML_CLK);}/* * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, * switch back to the original core, and return the new value. * * When using the silicon backplane, no fidleing with interrupts or core switches are needed. * * Also, when using pci/pcie, we can optimize away the core switching for pci registers * and (on newer pci cores) chipcommon registers. */static uintsb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val){	uint origidx = 0;	uint32 *r = NULL;	uint w;	uint intr_val = 0;	bool fast = FALSE;	ASSERT(GOODIDX(coreidx));	ASSERT(regoff < SB_CORE_SIZE);	ASSERT((val & ~mask) == 0);	if (!fast) {		INTR_OFF(si, intr_val);		/* save current core index */		origidx = sb_coreidx(&si->sb);		/* switch core */		r = (uint32*) ((uchar*) sb_setcoreidx(&si->sb, coreidx) + regoff);	}	ASSERT(r);	/* mask and set */	if (mask || val) {		if (regoff >= SBCONFIGOFF) {			w = (R_SBREG(si, r) & ~mask) | val;			W_SBREG(si, r, w);		} else {			w = (R_REG(r) & ~mask) | val;			W_REG(r, w);		}	}	/* readback */	if (regoff >= SBCONFIGOFF)		w = R_SBREG(si, r);	else		w = R_REG(r);	if (!fast) {		/* restore core index */		if (origidx != coreidx)			sb_setcoreidx(&si->sb, origidx);		INTR_RESTORE(si, intr_val);	}	return (w);}#define DWORD_ALIGN(x)  (x & ~(0x03))#define BYTE_POS(x) (x & 0x3)#define WORD_POS(x) (x & 0x1)#define BYTE_SHIFT(x)  (8 * BYTE_POS(x))#define WORD_SHIFT(x)  (16 * WORD_POS(x))#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)#define read_pci_cfg_byte(a) \	(BYTE_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xff)#define read_pci_cfg_write(a) \	(WORD_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xffff)/* return TRUE if requested capability exists in the PCI config space */static boolsb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen){	uint8 cap_id;	uint8 cap_ptr;	uint32 	bufsize;	uint8 byte_val;	if (BUSTYPE(si->sb.bustype) != PCI_BUS)		return FALSE;	/* check for Header type 0 */	byte_val = read_pci_cfg_byte(PCI_CFG_HDR);	if ((byte_val & 0x7f) != PCI_HEADER_NORMAL)		return FALSE;	/* check if the capability pointer field exists */	byte_val = read_pci_cfg_byte(PCI_CFG_STAT);	if (!(byte_val & PCI_CAPPTR_PRESENT))		return FALSE;	cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);	/* check if the capability pointer is 0x00 */	if (cap_ptr == 0x00)		return FALSE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -