add all source code from linksys/broadcom which is free, to cvs for better maintainence inside

openwrt. this gives us the ability to better support different hardware models, without changing
any external tar-balls. only et.o and wl.o is missing and is fetched from my webserver.


git-svn-id: svn://svn.openwrt.org/openwrt/trunk@379 3c298f89-4303-0410-b956-a3cf2f4a3e73
master
Waldemar Brodkorb 2005-03-16 13:50:00 +00:00
parent 4b825ad6f0
commit 9e4c591f74
85 changed files with 18591 additions and 16 deletions

View File

@ -0,0 +1,23 @@
#
# Makefile for Broadcom BCM947XX boards
#
# Copyright 2004, 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$
#
O_TARGET := bcm947xx.o
export-objs := nvram_linux.o setup.o
obj-y := prom.o setup.o time.o sbmips.o sbpci.o pcibios.o perfcntr.o gpio.o
obj-y += sflash.o nvram.o nvram_linux.o
vpath %.c $(SRCBASE)/shared $(SRCBASE)/shared/nvram
include $(TOPDIR)/Rules.make

View File

@ -0,0 +1,100 @@
#
# Makefile for Broadcom BCM947XX boards
#
# Copyright 2001-2003, 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$
#
# Copyright 2004 Manuel Novoa III <mjn3@codepoet.org>
# Modified to support bzip'd kernels.
# Of course, it would be better to integrate bunzip capability into CFE.
#
# Link at 3 MB offset in RAM
#TEXT_START ?= 0x80300000
TEXT_START ?= 0x80001000
BZ_MEM_TOP := 0x81000000
BZ_TEXT_START := BZ_MEM_TOP-0x4000
BZ_STACK_TOP := BZ_TEXT_START-4
OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
SRCBASE := $(TOPDIR)/../..
VPATH := $(SRCBASE)/shared
ASFLAGS += -D__ASSEMBLY__ -I$(SRCBASE)/include -DLOADADDR=$(LOADADDR)
ASFLAGS += -DBZ_MEM_TOP=$(BZ_MEM_TOP)
ASFLAGS += -DBZ_TEXT_START=$(BZ_TEXT_START)
ASFLAGS += -DBZ_STACK_TOP=$(BZ_STACK_TOP)
CFLAGS += -I$(SRCBASE)/include -DLOADADDR=$(LOADADDR)
CFLAGS += -DBZ_MEM_TOP=$(BZ_MEM_TOP)
CFLAGS += -DBZ_TEXT_START=$(BZ_TEXT_START)
CFLAGS += -DBZ_STACK_TOP=$(BZ_STACK_TOP)
ifdef CONFIG_MCOUNT
CFLAGS := $(subst -pg,,$(CFLAGS))
endif
CFLAGS += -ffunction-sections $(call check_gcc, -fvtable-gc, )
SEDFLAGS := s/BZ_TEXT_START/$(BZ_TEXT_START)/;s/BZ_MEM_TOP/$(BZ_MEM_TOP)/;s/TEXT_START/$(TEXT_START)/
SYSTEM ?= $(TOPDIR)/vmlinux
OBJECTS := head.o data.o
all: bzImage vmlinuz
# Don't build dependencies, this may die if $(CC) isn't gcc
dep:
# Create a gzipped version named vmlinuz for compatibility
vmlinuz: piggy
gzip -c9 $< > $@
# Our bzImage is a gzip'd binary that decompresses and runs
# the appended bzip'd kernel.
bzImage: bzLoaderImage.gz piggz
cat bzLoaderImage.gz piggz > $@
bzLoaderImage.gz: bzLoaderImage
gzip -nc9 $< > $@
bzLoaderImage: bzLoader
$(OBJCOPY) $< $@
bzLoader: vmlinux.lds $(OBJECTS)
$(LD) -static --gc-sections -no-warn-mismatch -T vmlinux.lds -o $@ $(OBJECTS)
vmlinux.lds: vmlinux.lds.in Makefile
@sed "$(SEDFLAGS)" < $< > $@
piggz: piggy
bzip2 -c9 $< > $@
piggy: $(SYSTEM)
$(OBJCOPY) $< $@
data.o: data.lds data.image
$(LD) -no-warn-mismatch -T data.lds -r -o $@ -b binary data.image -b elf32-tradlittlemips
data.lds:
@echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > $@
data.image: decompress_bunzip2.image
$(OBJCOPY) $< $@
decompress_bunzip2.image: decompress_bunzip2.lds decompress_bunzip2.o
$(LD) -static --gc-sections -no-warn-mismatch -T decompress_bunzip2.lds -o $@ decompress_bunzip2.o
decompress_bunzip2.lds: decompress_bunzip2.lds.in Makefile
@sed "$(SEDFLAGS)" < $< > $@
mrproper: clean
clean:
rm -f vmlinux vmlinuz piggz piggy *.lds *.o \
bzLoader bzLoaderImage bzLoaderImage.gz bzImage \
data.lds data.image \
decompress_bunzip2.lds decompress_bunzip2.image

View File

@ -0,0 +1,20 @@
FIRST... See the dedication in the decompress_bunzip2.c file as it applies
here too. Donations to hospice in Toni's memory would be appreciated.
As far as the code goes... the bzImage is just a bzip'd kernel image with
a small gzip'd decompressor/loader stuck on front. CFE ungzip's the loader
app which then relocates the bunzip decompressor into higher memory and
bunzip's the compressed kernel directly from flash. Then the instruction
cache is flushed (to remove traces of the loader) and the kernel is executed.
Of course, a better approach would be to add bunzip decompression to CFE.
Notes...
1) Instruction cache size and linesize are hardcoded (see the #warning).
2) Currently assumes at least 16M or ram.
3) Thanks to Mike Baker mbm at alt dot org for bouncing ideas back
and forth as well as diagnosing the last (icache) bug.
Manuel Novoa III <mjn3@codepoet.org> May 30, 2004

View File

@ -0,0 +1 @@
SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}

View File

@ -0,0 +1,758 @@
/* vi: set sw=4 ts=4: */
/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
which also acknowledges contributions by Mike Burrows, David Wheeler,
Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
Robert Sedgewick, and Jon L. Bentley.
This code is licensed under the LGPLv2:
LGPL (http://www.gnu.org/copyleft/lgpl.html
*/
/*
Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org).
More efficient reading of huffman codes, a streamlined read_bunzip()
function, and various other tweaks. In (limited) tests, approximately
20% faster than bzcat on x86 and about 10% faster on arm.
Note that about 2/3 of the time is spent in read_unzip() reversing
the Burrows-Wheeler transformation. Much of that time is delay
resulting from cache misses.
I would ask that anyone benefiting from this work, especially those
using it in commercial products, consider making a donation to my local
non-profit hospice organization in the name of the woman I loved, who
passed away Feb. 12, 2003.
In memory of Toni W. Hagan
Hospice of Acadiana, Inc.
2600 Johnston St., Suite 200
Lafayette, LA 70503-3240
Phone (337) 232-1234 or 1-800-738-2226
Fax (337) 232-1297
http://www.hospiceacadiana.com/
Manuel
*/
/* May 21, 2004 Manuel Novoa III
* Modified to load a bzip'd kernel on the linksys wrt54g.
*
* May 30, 2004
* Further size reduction via inlining and disabling len check code.
*/
/**********************************************************************/
/* Note... the LED code is specific to the v2.0 (and GS?) unit. */
#undef ENABLE_LEDS
/* #define ENABLE_LEDS 1 */
/* Do we want to bother with checking the bzip'd data for errors? */
#undef ENABLE_BUNZIP_CHECKING
/* #define ENABLE_BUNZIP_CHECKING 1 */
/**********************************************************************/
/* #include <bcm4710.h> */
#define BCM4710_FLASH 0x1fc00000 /* Flash */
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
/* The following cache code was taken from the file bcm4710_cache.h
* which was necessarily GPL as it was used to build the linksys
* kernel for the wrt54g. */
#warning icache [l]size hardcoded
#define icache_size 8192
#define ic_lsize 16
#define Index_Invalidate_I 0x00
#define cache_unroll(base,op) \
__asm__ __volatile__( \
".set noreorder;\n" \
".set mips3;\n" \
"cache %1, (%0);\n" \
".set mips0;\n" \
".set reorder\n" \
: \
: "r" (base), \
"i" (op));
static __inline__ void blast_icache(void)
{
unsigned long start = KSEG0;
unsigned long end = (start + icache_size);
while(start < end) {
cache_unroll(start,Index_Invalidate_I);
start += ic_lsize;
}
}
/**********************************************************************/
#ifndef INT_MAX
#define INT_MAX (((1 << 30)-1)*2 + 1)
#endif
/**********************************************************************/
#ifdef ENABLE_BUNZIP_CHECKING
#define REBOOT do {} while (1)
#else
#define REBOOT ((void) 0)
#endif
/**********************************************************************/
#ifdef ENABLE_LEDS
#define LED_POWER_ON 0x02 /* OFF == flashing */
#define LED_DMZ_OFF 0x80
#define LED_WLAN_OFF 0x01
#define LED_CODE_0 (LED_POWER_ON | LED_DMZ_OFF | LED_WLAN_OFF)
#define LED_CODE_1 (LED_POWER_ON | LED_DMZ_OFF)
#define LED_CODE_2 (LED_POWER_ON | LED_WLAN_OFF)
#define LED_CODE_3 (LED_POWER_ON)
#define SET_LED_ERROR(X) \
do { \
*(volatile u8*)(KSEG1ADDR(0x18000064))=(X & ~LED_POWER_ON); \
*(volatile u8*)(KSEG1ADDR(0x18000068))=0; /* Disable changes */ \
REBOOT; \
} while (0)
#define SET_LED(X) *(volatile u8*)(KSEG1ADDR(0x18000064))=X;
typedef unsigned char u8;
#else
#define SET_LED_ERROR(X) REBOOT
#define SET_LED(X) ((void)0)
#endif
/**********************************************************************/
/* Constants for huffman coding */
#define MAX_GROUPS 6
#define GROUP_SIZE 50 /* 64 would have been more efficient */
#define MAX_HUFCODE_BITS 20 /* Longest huffman code allowed */
#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
#define SYMBOL_RUNA 0
#define SYMBOL_RUNB 1
/* Status return values */
#define RETVAL_OK 0
#define RETVAL_LAST_BLOCK (-1)
#define RETVAL_NOT_BZIP_DATA (-2)
#define RETVAL_UNEXPECTED_INPUT_EOF (-3)
#define RETVAL_UNEXPECTED_OUTPUT_EOF (-4)
#define RETVAL_DATA_ERROR (-5)
#define RETVAL_OUT_OF_MEMORY (-6)
#define RETVAL_OBSOLETE_INPUT (-7)
/* Other housekeeping constants */
#define IOBUF_SIZE 4096
/* This is what we know about each huffman coding group */
struct group_data {
/* We have an extra slot at the end of limit[] for a sentinal value. */
int limit[MAX_HUFCODE_BITS+1],base[MAX_HUFCODE_BITS],permute[MAX_SYMBOLS];
int minLen, maxLen;
};
/* Structure holding all the housekeeping data, including IO buffers and
memory that persists between calls to bunzip */
typedef struct {
/* State for interrupting output loop */
int writeCopies,writePos,writeRunCountdown,writeCount,writeCurrent;
/* I/O tracking data (file handles, buffers, positions, etc.) */
#if defined(ENABLE_BUNZIP_CHECKING)
int /*in_fd,out_fd,*/ inbufCount,inbufPos /*,outbufPos*/;
#else
int /*in_fd,out_fd,inbufCount,*/ inbufPos /*,outbufPos*/;
#endif
unsigned char *inbuf /*,*outbuf*/;
unsigned int inbufBitCount, inbufBits;
/* The CRC values stored in the block header and calculated from the data */
#ifdef ENABLE_BUNZIP_CHECKING
unsigned int crc32Table[256],headerCRC, totalCRC, writeCRC;
/* Intermediate buffer and its size (in bytes) */
unsigned int *dbuf, dbufSize;
#else
unsigned int *dbuf;
#endif
/* These things are a bit too big to go on the stack */
unsigned char selectors[32768]; /* nSelectors=15 bits */
struct group_data groups[MAX_GROUPS]; /* huffman coding tables */
} bunzip_data;
static int get_next_block(bunzip_data *bd);
/**********************************************************************/
/* Undo burrows-wheeler transform on intermediate buffer to produce output.
If start_bunzip was initialized with out_fd=-1, then up to len bytes of
data are written to outbuf. Return value is number of bytes written or
error (all errors are negative numbers). If out_fd!=-1, outbuf and len
are ignored, data is written to out_fd and return is RETVAL_OK or error.
*/
static __inline__ int read_bunzip(bunzip_data *bd, char *outbuf, int len)
{
const unsigned int *dbuf;
int pos,current,previous,gotcount;
#ifdef ENABLE_LEDS
int led_state = LED_CODE_2;
#endif
/* If last read was short due to end of file, return last block now */
if(bd->writeCount<0) return bd->writeCount;
gotcount = 0;
dbuf=bd->dbuf;
pos=bd->writePos;
current=bd->writeCurrent;
/* We will always have pending decoded data to write into the output
buffer unless this is the very first call (in which case we haven't
huffman-decoded a block into the intermediate buffer yet). */
if (bd->writeCopies) {
/* Inside the loop, writeCopies means extra copies (beyond 1) */
--bd->writeCopies;
/* Loop outputting bytes */
for(;;) {
#if 0 /* Might want to enable this if passing a limiting size. */
/* #ifdef ENABLE_BUNZIP_CHECKING */
/* If the output buffer is full, snapshot state and return */
if(gotcount >= len) {
bd->writePos=pos;
bd->writeCurrent=current;
bd->writeCopies++;
return len;
}
#endif
/* Write next byte into output buffer, updating CRC */
outbuf[gotcount++] = current;
#ifdef ENABLE_BUNZIP_CHECKING
bd->writeCRC=(((bd->writeCRC)<<8)
^bd->crc32Table[((bd->writeCRC)>>24)^current]);
#endif
/* Loop now if we're outputting multiple copies of this byte */
if (bd->writeCopies) {
--bd->writeCopies;
continue;
}
decode_next_byte:
if (!bd->writeCount--) break;
/* Follow sequence vector to undo Burrows-Wheeler transform */
previous=current;
pos=dbuf[pos];
current=pos&0xff;
pos>>=8;
/* After 3 consecutive copies of the same byte, the 4th is a repeat
count. We count down from 4 instead
* of counting up because testing for non-zero is faster */
if(--bd->writeRunCountdown) {
if(current!=previous) bd->writeRunCountdown=4;
} else {
/* We have a repeated run, this byte indicates the count */
bd->writeCopies=current;
current=previous;
bd->writeRunCountdown=5;
/* Sometimes there are just 3 bytes (run length 0) */
if(!bd->writeCopies) goto decode_next_byte;
/* Subtract the 1 copy we'd output anyway to get extras */
--bd->writeCopies;
}
}
#ifdef ENABLE_BUNZIP_CHECKING
/* Decompression of this block completed successfully */
bd->writeCRC=~bd->writeCRC;
bd->totalCRC=((bd->totalCRC<<1) | (bd->totalCRC>>31)) ^ bd->writeCRC;
/* If this block had a CRC error, force file level CRC error. */
if(bd->writeCRC!=bd->headerCRC) {
bd->totalCRC=bd->headerCRC+1;
return RETVAL_LAST_BLOCK;
}
#endif
}
#ifdef ENABLE_LEDS
if (led_state == LED_CODE_2) {
led_state = LED_CODE_1;
} else {
led_state = LED_CODE_2;
}
SET_LED(led_state);
#endif
/* Refill the intermediate buffer by huffman-decoding next block of input */
/* (previous is just a convenient unused temp variable here) */
previous=get_next_block(bd);
#ifdef ENABLE_BUNZIP_CHECKING
if(previous) {
bd->writeCount=previous;
return (previous!=RETVAL_LAST_BLOCK) ? previous : gotcount;
}
bd->writeCRC=0xffffffffUL;
#else
if (previous) return gotcount;
#endif
pos=bd->writePos;
current=bd->writeCurrent;
goto decode_next_byte;
}
/**********************************************************************/
/* WARNING!!! Must be the first function!!! */
void load_and_run(unsigned long ra)
{
int dbuf[900000]; /* Maximum requred */
bunzip_data bd;
unsigned int i;
#ifdef ENABLE_BUNZIP_CHECKING
unsigned int j, c;
int r;
#endif
char *p;
#ifdef ENABLE_LEDS
*(volatile u8*)(KSEG1ADDR(0x18000068))=0x83; /* Allow all bits to change */
SET_LED(LED_CODE_0);
#endif
/* memset(&bd,0,sizeof(bunzip_data)); */
p = (char *) &bd;
for (i = 0 ; i < sizeof(bunzip_data) ; i++) {
p[i] = 0;
}
/* Find start of flash and adjust for pmon partition. */
p = ((char *) KSEG1ADDR(BCM4710_FLASH)) + 0x10000;
SET_LED(LED_CODE_1);
/* Find the start of the bzip'd data. */
while ((p[0]!='B') || (p[1]!='Z') || (p[2]!='h') /*|| (p[3]!='9')*/) ++p;
SET_LED(LED_CODE_2);
/* Setup input buffer */
bd.inbuf=p+4; /* Skip the "BZh9" header. */
#ifdef ENABLE_BUNZIP_CHECKING
bd.inbufCount=INT_MAX;
/* Init the CRC32 table (big endian) */
for(i=0;i<256;i++) {
c=i<<24;
for(j=8;j;j--)
c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
bd.crc32Table[i]=c;
}
bd.dbufSize=900000;
#endif
bd.dbuf=dbuf;
/* Actually do the bunzip */
#ifdef ENABLE_BUNZIP_CHECKING
r = read_bunzip(&bd, ((char *) LOADADDR), INT_MAX);
if (r > 0) {
if (bd.headerCRC==bd.totalCRC) {
SET_LED(LED_CODE_3);
{
int code = LED_WLAN_OFF;
int i, j;
for (j=0 ; j < 4 ; j++) {
for (i=0; i<(1<<27) ; i++) {}
SET_LED(code);
code ^= LED_WLAN_OFF;
}
}
blast_icache();
/* Jump to load address */
((void (*)(void)) LOADADDR)();
} else {
SET_LED_ERROR(LED_CODE_3);
}
} else {
SET_LED_ERROR(LED_CODE_2);
}
#else
read_bunzip(&bd, ((char *) LOADADDR), INT_MAX);
blast_icache();
/* Jump to load address */
((void (*)(void)) LOADADDR)();
#endif
}
/**********************************************************************/
/* Return the next nnn bits of input. All reads from the compressed input
are done through this function. All reads are big endian */
static unsigned int get_bits(bunzip_data *bd, char bits_wanted)
{
unsigned int bits=0;
/* If we need to get more data from the byte buffer, do so. (Loop getting
one byte at a time to enforce endianness and avoid unaligned access.) */
while (bd->inbufBitCount<bits_wanted) {
/* If we need to read more data from file into byte buffer, do so */
#ifdef ENABLE_BUNZIP_CHECKING
if(bd->inbufPos==bd->inbufCount) {
SET_LED_ERROR(LED_CODE_0);
}
#endif
/* Avoid 32-bit overflow (dump bit buffer to top of output) */
if(bd->inbufBitCount>=24) {
bits=bd->inbufBits&((1<<bd->inbufBitCount)-1);
bits_wanted-=bd->inbufBitCount;
bits<<=bits_wanted;
bd->inbufBitCount=0;
}
/* Grab next 8 bits of input from buffer. */
bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++];
bd->inbufBitCount+=8;
}
/* Calculate result */
bd->inbufBitCount-=bits_wanted;
bits|=(bd->inbufBits>>bd->inbufBitCount)&((1<<bits_wanted)-1);
return bits;
}
/* Unpacks the next block and sets up for the inverse burrows-wheeler step. */
static int get_next_block(bunzip_data *bd)
{
struct group_data *hufGroup;
#ifdef ENABLE_BUNZIP_CHECKING
int dbufCount,nextSym,dbufSize,groupCount,*base,*limit,selector,
i,j,k,t,runPos,symCount,symTotal,nSelectors,byteCount[256];
#else
int dbufCount,nextSym,/*dbufSize,*/groupCount,*base,*limit,selector,
i,j,k,t,runPos,symCount,symTotal,nSelectors,byteCount[256];
#endif
unsigned char uc, symToByte[256], mtfSymbol[256], *selectors;
unsigned int *dbuf,origPtr;
dbuf=bd->dbuf;
#ifdef ENABLE_BUNZIP_CHECKING
dbufSize=bd->dbufSize;
#endif
selectors=bd->selectors;
/* Read in header signature and CRC, then validate signature.
(last block signature means CRC is for whole file, return now) */
i = get_bits(bd,24);
j = get_bits(bd,24);
#ifdef ENABLE_BUNZIP_CHECKING
bd->headerCRC=get_bits(bd,32);
if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK;
if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA;
/* We can add support for blockRandomised if anybody complains. There was
some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
it didn't actually work. */
if(get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT;
if((origPtr=get_bits(bd,24)) > dbufSize) return RETVAL_DATA_ERROR;
#else
get_bits(bd,32);
if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK;
get_bits(bd,1);
origPtr=get_bits(bd,24);
#endif
/* mapping table: if some byte values are never used (encoding things
like ascii text), the compression code removes the gaps to have fewer
symbols to deal with, and writes a sparse bitfield indicating which
values were present. We make a translation table to convert the symbols
back to the corresponding bytes. */
t=get_bits(bd, 16);
symTotal=0;
for (i=0;i<16;i++) {
if(t&(1<<(15-i))) {
k=get_bits(bd,16);
for(j=0;j<16;j++)
if(k&(1<<(15-j))) symToByte[symTotal++]=(16*i)+j;
}
}
/* How many different huffman coding groups does this block use? */
groupCount=get_bits(bd,3);
#ifdef ENABLE_BUNZIP_CHECKING
if (groupCount<2 || groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR;
#endif
/* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding
group. Read in the group selector list, which is stored as MTF encoded
bit runs. (MTF=Move To Front, as each value is used it's moved to the
start of the list.) */
#ifdef ENABLE_BUNZIP_CHECKING
if(!(nSelectors=get_bits(bd, 15))) return RETVAL_DATA_ERROR;
#else
nSelectors=get_bits(bd, 15);
#endif
for(i=0; i<groupCount; i++) mtfSymbol[i] = i;
for(i=0; i<nSelectors; i++) {
/* Get next value */
#ifdef ENABLE_BUNZIP_CHECKING
for(j=0;get_bits(bd,1);j++) if (j>=groupCount) return RETVAL_DATA_ERROR;
#else
for(j=0;get_bits(bd,1);j++) ;
#endif
/* Decode MTF to get the next selector */
uc = mtfSymbol[j];
for(;j;j--) mtfSymbol[j] = mtfSymbol[j-1];
mtfSymbol[0]=selectors[i]=uc;
}
/* Read the huffman coding tables for each group, which code for symTotal
literal symbols, plus two run symbols (RUNA, RUNB) */
symCount=symTotal+2;
for (j=0; j<groupCount; j++) {
unsigned char length[MAX_SYMBOLS],temp[MAX_HUFCODE_BITS+1];
int minLen, maxLen, pp;
/* Read huffman code lengths for each symbol. They're stored in
a way similar to mtf; record a starting value for the first symbol,
and an offset from the previous value for everys symbol after that.
(Subtracting 1 before the loop and then adding it back at the end is
an optimization that makes the test inside the loop simpler: symbol
length 0 becomes negative, so an unsigned inequality catches it.) */
t=get_bits(bd, 5)-1;
for (i = 0; i < symCount; i++) {
for(;;) {
#ifdef ENABLE_BUNZIP_CHECKING
if (((unsigned)t) > (MAX_HUFCODE_BITS-1))
return RETVAL_DATA_ERROR;
#endif
/* If first bit is 0, stop. Else second bit indicates whether
to increment or decrement the value. Optimization: grab 2
bits and unget the second if the first was 0. */
k = get_bits(bd,2);
if (k < 2) {
bd->inbufBitCount++;
break;
}
/* Add one if second bit 1, else subtract 1. Avoids if/else */
t+=(((k+1)&2)-1);
}
/* Correct for the initial -1, to get the final symbol length */
length[i]=t+1;
}
/* Find largest and smallest lengths in this group */
minLen=maxLen=length[0];
for(i = 1; i < symCount; i++) {
if(length[i] > maxLen) maxLen = length[i];
else if(length[i] < minLen) minLen = length[i];
}
/* Calculate permute[], base[], and limit[] tables from length[].
*
* permute[] is the lookup table for converting huffman coded symbols
* into decoded symbols. base[] is the amount to subtract from the
* value of a huffman symbol of a given length when using permute[].
*
* limit[] indicates the largest numerical value a symbol with a given
* number of bits can have. This is how the huffman codes can vary in
* length: each code with a value>limit[length] needs another bit.
*/
hufGroup=bd->groups+j;
hufGroup->minLen = minLen;
hufGroup->maxLen = maxLen;
/* Note that minLen can't be smaller than 1, so we adjust the base
and limit array pointers so we're not always wasting the first
entry. We do this again when using them (during symbol decoding).*/
base=hufGroup->base-1;
limit=hufGroup->limit-1;
/* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
pp=0;
for(i=minLen;i<=maxLen;i++) {
temp[i]=limit[i]=0;
for(t=0;t<symCount;t++)
if(length[t]==i) hufGroup->permute[pp++] = t;
}
/* Count symbols coded for at each bit length */
for (i=0;i<symCount;i++) temp[length[i]]++;
/* Calculate limit[] (the largest symbol-coding value at each bit
* length, which is (previous limit<<1)+symbols at this level), and
* base[] (number of symbols to ignore at each bit length, which is
* limit minus the cumulative count of symbols coded for already). */
pp=t=0;
for (i=minLen; i<maxLen; i++) {
pp+=temp[i];
/* We read the largest possible symbol size and then unget bits
after determining how many we need, and those extra bits could
be set to anything. (They're noise from future symbols.) At
each level we're really only interested in the first few bits,
so here we set all the trailing to-be-ignored bits to 1 so they
don't affect the value>limit[length] comparison. */
limit[i]= (pp << (maxLen - i)) - 1;
pp<<=1;
base[i+1]=pp-(t+=temp[i]);
}
limit[maxLen+1] = INT_MAX; /* Sentinal value for reading next sym. */
limit[maxLen]=pp+temp[maxLen]-1;
base[minLen]=0;
}
/* We've finished reading and digesting the block header. Now read this
block's huffman coded symbols from the file and undo the huffman coding
and run length encoding, saving the result into dbuf[dbufCount++]=uc */
/* Initialize symbol occurrence counters and symbol Move To Front table */
for(i=0;i<256;i++) {
byteCount[i] = 0;
mtfSymbol[i]=(unsigned char)i;
}
/* Loop through compressed symbols. */
runPos=dbufCount=symCount=selector=0;
for(;;) {
/* Determine which huffman coding group to use. */
if(!(symCount--)) {
symCount=GROUP_SIZE-1;
#ifdef ENABLE_BUNZIP_CHECKING
if(selector>=nSelectors) return RETVAL_DATA_ERROR;
#endif
hufGroup=bd->groups+selectors[selector++];
base=hufGroup->base-1;
limit=hufGroup->limit-1;
}
/* Read next huffman-coded symbol. */
/* Note: It is far cheaper to read maxLen bits and back up than it is
to read minLen bits and then an additional bit at a time, testing
as we go. Because there is a trailing last block (with file CRC),
there is no danger of the overread causing an unexpected EOF for a
valid compressed file. As a further optimization, we do the read
inline (falling back to a call to get_bits if the buffer runs
dry). The following (up to got_huff_bits:) is equivalent to
j=get_bits(bd,hufGroup->maxLen);
*/
while (bd->inbufBitCount<hufGroup->maxLen) {
#ifdef ENABLE_BUNZIP_CHECKING
if(bd->inbufPos==bd->inbufCount) {
j = get_bits(bd,hufGroup->maxLen);
goto got_huff_bits;
}
#endif
bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++];
bd->inbufBitCount+=8;
};
bd->inbufBitCount-=hufGroup->maxLen;
j = (bd->inbufBits>>bd->inbufBitCount)&((1<<hufGroup->maxLen)-1);
got_huff_bits:
/* Figure how how many bits are in next symbol and unget extras */
i=hufGroup->minLen;
while(j>limit[i]) ++i;
bd->inbufBitCount += (hufGroup->maxLen - i);
/* Huffman decode value to get nextSym (with bounds checking) */
#ifdef ENABLE_BUNZIP_CHECKING
if ((i > hufGroup->maxLen)
|| (((unsigned)(j=(j>>(hufGroup->maxLen-i))-base[i]))
>= MAX_SYMBOLS))
return RETVAL_DATA_ERROR;
#else
j=(j>>(hufGroup->maxLen-i))-base[i];
#endif
nextSym = hufGroup->permute[j];
/* We have now decoded the symbol, which indicates either a new literal
byte, or a repeated run of the most recent literal byte. First,
check if nextSym indicates a repeated run, and if so loop collecting
how many times to repeat the last literal. */
if (((unsigned)nextSym) <= SYMBOL_RUNB) { /* RUNA or RUNB */
/* If this is the start of a new run, zero out counter */
if(!runPos) {
runPos = 1;
t = 0;
}
/* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
each bit position, add 1 or 2 instead. For example,
1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
You can make any bit pattern that way using 1 less symbol than
the basic or 0/1 method (except all bits 0, which would use no
symbols, but a run of length 0 doesn't mean anything in this
context). Thus space is saved. */
t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
runPos <<= 1;
continue;
}
/* When we hit the first non-run symbol after a run, we now know
how many times to repeat the last literal, so append that many
copies to our buffer of decoded symbols (dbuf) now. (The last
literal used is the one at the head of the mtfSymbol array.) */
if(runPos) {
runPos=0;
#ifdef ENABLE_BUNZIP_CHECKING
if(dbufCount+t>=dbufSize) return RETVAL_DATA_ERROR;
#endif
uc = symToByte[mtfSymbol[0]];
byteCount[uc] += t;
while(t--) dbuf[dbufCount++]=uc;
}
/* Is this the terminating symbol? */
if(nextSym>symTotal) break;
/* At this point, nextSym indicates a new literal character. Subtract
one to get the position in the MTF array at which this literal is
currently to be found. (Note that the result can't be -1 or 0,
because 0 and 1 are RUNA and RUNB. But another instance of the
first symbol in the mtf array, position 0, would have been handled
as part of a run above. Therefore 1 unused mtf position minus
2 non-literal nextSym values equals -1.) */
#ifdef ENABLE_BUNZIP_CHECKING
if(dbufCount>=dbufSize) return RETVAL_DATA_ERROR;
#endif
i = nextSym - 1;
uc = mtfSymbol[i];
/* Adjust the MTF array. Since we typically expect to move only a
* small number of symbols, and are bound by 256 in any case, using
* memmove here would typically be bigger and slower due to function
* call overhead and other assorted setup costs. */
do {
mtfSymbol[i] = mtfSymbol[i-1];
} while (--i);
mtfSymbol[0] = uc;
uc=symToByte[uc];
/* We have our literal byte. Save it into dbuf. */
byteCount[uc]++;
dbuf[dbufCount++] = (unsigned int)uc;
}
/* At this point, we've read all the huffman-coded symbols (and repeated
runs) for this block from the input stream, and decoded them into the
intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
Now undo the Burrows-Wheeler transform on dbuf.
See http://dogma.net/markn/articles/bwt/bwt.htm
*/
/* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
j=0;
for(i=0;i<256;i++) {
k=j+byteCount[i];
byteCount[i] = j;
j=k;
}
/* Figure out what order dbuf would be in if we sorted it. */
for (i=0;i<dbufCount;i++) {
uc=(unsigned char)(dbuf[i] & 0xff);
dbuf[byteCount[uc]] |= (i << 8);
byteCount[uc]++;
}
/* Decode first byte by hand to initialize "previous" byte. Note that it
doesn't get output, and if the first three characters are identical
it doesn't qualify as a run (hence writeRunCountdown=5). */
if(dbufCount) {
#ifdef ENABLE_BUNZIP_CHECKING
if(origPtr>=dbufCount) return RETVAL_DATA_ERROR;
#endif
bd->writePos=dbuf[origPtr];
bd->writeCurrent=(unsigned char)(bd->writePos&0xff);
bd->writePos>>=8;
bd->writeRunCountdown=5;
}
bd->writeCount=dbufCount;
return RETVAL_OK;
}

View File

@ -0,0 +1,17 @@
OUTPUT_ARCH(mips)
ENTRY(load_and_run)
SECTIONS {
. = 0x81000000-0x4000;
.text : {
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

View File

@ -0,0 +1,17 @@
OUTPUT_ARCH(mips)
ENTRY(load_and_run)
SECTIONS {
. = BZ_TEXT_START;
.text : {
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

View File

@ -0,0 +1,26 @@
/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org) */
/* Licensed under the linux kernel's version of the GPL. */
#include <asm/asm.h>
#include <asm/regdef.h>
.text
LEAF(startup)
.set noreorder
li t1, BZ_TEXT_START
add a0, t1, 0
la a1, code_start
la a2, code_stop
$L1:
lw t0, 0(a1)
sw t0, 0(a0)
add a1, 4
add a0, 4
blt a1, a2, $L1
add sp, t1, -4
jal t1
.set reorder
END(startup)

View File

@ -0,0 +1,17 @@
OUTPUT_ARCH(mips)
ENTRY(startup)
SECTIONS {
. = 0x80001000;
.text : {
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

View File

@ -0,0 +1,17 @@
OUTPUT_ARCH(mips)
ENTRY(startup)
SECTIONS {
. = TEXT_START;
.text : {
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

View File

@ -0,0 +1,158 @@
/*
* GPIO char driver
*
* Copyright 2004, 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 <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <typedefs.h>
#include <bcmutils.h>
#include <sbutils.h>
#include <bcmdevs.h>
static void *gpio_sbh;
static int gpio_major;
static devfs_handle_t gpio_dir;
static struct {
char *name;
devfs_handle_t handle;
} gpio_file[] = {
{ "in", NULL },
{ "out", NULL },
{ "outen", NULL },
{ "control", NULL }
};
static int
gpio_open(struct inode *inode, struct file * file)
{
if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file))
return -ENODEV;
MOD_INC_USE_COUNT;
return 0;
}
static int
gpio_release(struct inode *inode, struct file * file)
{
MOD_DEC_USE_COUNT;
return 0;
}
static ssize_t
gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
u32 val;
switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
case 0:
val = sb_gpioin(gpio_sbh);
break;
case 1:
val = sb_gpioout(gpio_sbh, 0, 0);
break;
case 2:
val = sb_gpioouten(gpio_sbh, 0, 0);
break;
case 3:
val = sb_gpiocontrol(gpio_sbh, 0, 0);
break;
default:
return -ENODEV;
}
if (put_user(val, (u32 *) buf))
return -EFAULT;
return sizeof(val);
}
static ssize_t
gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
u32 val;
if (get_user(val, (u32 *) buf))
return -EFAULT;
switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
case 0:
return -EACCES;
case 1:
sb_gpioout(gpio_sbh, ~0, val);
break;
case 2:
sb_gpioouten(gpio_sbh, ~0, val);
break;
case 3:
sb_gpiocontrol(gpio_sbh, ~0, val);
break;
default:
return -ENODEV;
}
return sizeof(val);
}
static struct file_operations gpio_fops = {
owner: THIS_MODULE,
open: gpio_open,
release: gpio_release,
read: gpio_read,
write: gpio_write,
};
static int __init
gpio_init(void)
{
int i;
if (!(gpio_sbh = sb_kattach()))
return -ENODEV;
sb_gpiosetcore(gpio_sbh);
if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0)
return gpio_major;
gpio_dir = devfs_mk_dir(NULL, "gpio", NULL);
for (i = 0; i < ARRAYSIZE(gpio_file); i++) {
gpio_file[i].handle = devfs_register(gpio_dir,
gpio_file[i].name,
DEVFS_FL_DEFAULT, gpio_major, i,
S_IFCHR | S_IRUGO | S_IWUGO,
&gpio_fops, NULL);
}
return 0;
}
static void __exit
gpio_exit(void)
{
int i;
for (i = 0; i < ARRAYSIZE(gpio_file); i++)
devfs_unregister(gpio_file[i].handle);
devfs_unregister(gpio_dir);
devfs_unregister_chrdev(gpio_major, "gpio");
sb_detach(gpio_sbh);
}
module_init(gpio_init);
module_exit(gpio_exit);

View File

@ -0,0 +1,317 @@
/*
* NVRAM variable manipulation (common)
*
* Copyright 2004, 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 <osl.h>
#include <bcmendian.h>
#include <bcmnvram.h>
#include <bcmutils.h>
#include <sbsdram.h>
extern struct nvram_tuple * _nvram_realloc(struct nvram_tuple *t, const char *name, const char *value);
extern void _nvram_free(struct nvram_tuple *t);
extern int _nvram_read(void *buf);
char * _nvram_get(const char *name);
int _nvram_set(const char *name, const char *value);
int _nvram_unset(const char *name);
int _nvram_getall(char *buf, int count);
int _nvram_commit(struct nvram_header *header);
int _nvram_init(void);
void _nvram_exit(void);
static struct nvram_tuple * nvram_hash[257];
static struct nvram_tuple * nvram_dead;
/* Free all tuples. Should be locked. */
static void
nvram_free(void)
{
uint i;
struct nvram_tuple *t, *next;
/* Free hash table */
for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
for (t = nvram_hash[i]; t; t = next) {
next = t->next;
_nvram_free(t);
}
nvram_hash[i] = NULL;
}
/* Free dead table */
for (t = nvram_dead; t; t = next) {
next = t->next;
_nvram_free(t);
}
nvram_dead = NULL;
/* Indicate to per-port code that all tuples have been freed */
_nvram_free(NULL);
}
/* String hash */
static INLINE uint
hash(const char *s)
{
uint hash = 0;
while (*s)
hash = 31 * hash + *s++;
return hash;
}
/* (Re)initialize the hash table. Should be locked. */
static int
nvram_rehash(struct nvram_header *header)
{
char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
/* (Re)initialize hash table */
nvram_free();
/* Parse and set "name=value\0 ... \0\0" */
name = (char *) &header[1];
end = (char *) header + NVRAM_SPACE - 2;
end[0] = end[1] = '\0';
for (; *name; name = value + strlen(value) + 1) {
if (!(eq = strchr(name, '=')))
break;
*eq = '\0';
value = eq + 1;
_nvram_set(name, value);
*eq = '=';
}
/* Set special SDRAM parameters */
if (!_nvram_get("sdram_init")) {
sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
_nvram_set("sdram_init", buf);
}
if (!_nvram_get("sdram_config")) {
sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
_nvram_set("sdram_config", buf);
}
if (!_nvram_get("sdram_refresh")) {
sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
_nvram_set("sdram_refresh", buf);
}
if (!_nvram_get("sdram_ncdl")) {
sprintf(buf, "0x%08X", header->config_ncdl);
_nvram_set("sdram_ncdl", buf);
}
return 0;
}
/* Get the value of an NVRAM variable. Should be locked. */
char *
_nvram_get(const char *name)
{
uint i;
struct nvram_tuple *t;
char *value;
if (!name)
return NULL;
/* Hash the name */
i = hash(name) % ARRAYSIZE(nvram_hash);
/* Find the associated tuple in the hash table */
for (t = nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
value = t ? t->value : NULL;
return value;
}
/* Get the value of an NVRAM variable. Should be locked. */
int
_nvram_set(const char *name, const char *value)
{
uint i;
struct nvram_tuple *t, *u, **prev;
/* Hash the name */
i = hash(name) % ARRAYSIZE(nvram_hash);
/* Find the associated tuple in the hash table */
for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
/* (Re)allocate tuple */
if (!(u = _nvram_realloc(t, name, value)))
return -12; /* -ENOMEM */
/* Value reallocated */
if (t && t == u)
return 0;
/* Move old tuple to the dead table */
if (t) {
*prev = t->next;
t->next = nvram_dead;
nvram_dead = t;
}
/* Add new tuple to the hash table */
u->next = nvram_hash[i];
nvram_hash[i] = u;
return 0;
}
/* Unset the value of an NVRAM variable. Should be locked. */
int
_nvram_unset(const char *name)
{
uint i;
struct nvram_tuple *t, **prev;
if (!name)
return 0;
/* Hash the name */
i = hash(name) % ARRAYSIZE(nvram_hash);
/* Find the associated tuple in the hash table */
for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
/* Move it to the dead table */
if (t) {
*prev = t->next;
t->next = nvram_dead;
nvram_dead = t;
}
return 0;
}
/* Get all NVRAM variables. Should be locked. */
int
_nvram_getall(char *buf, int count)
{
uint i;
struct nvram_tuple *t;
int len = 0;
bzero(buf, count);
/* Write name=value\0 ... \0\0 */
for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
for (t = nvram_hash[i]; t; t = t->next) {
if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1))
len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1;
else
break;
}
}
return 0;
}
/* Regenerate NVRAM. Should be locked. */
int
_nvram_commit(struct nvram_header *header)
{
char *init, *config, *refresh, *ncdl;
char *ptr, *end;
int i;
struct nvram_tuple *t;
struct nvram_header tmp;
uint8 crc;
/* Regenerate header */
header->magic = NVRAM_MAGIC;
header->crc_ver_init = (NVRAM_VERSION << 8);
if (!(init = _nvram_get("sdram_init")) ||
!(config = _nvram_get("sdram_config")) ||
!(refresh = _nvram_get("sdram_refresh")) ||
!(ncdl = _nvram_get("sdram_ncdl"))) {
header->crc_ver_init |= SDRAM_INIT << 16;
header->config_refresh = SDRAM_CONFIG;
header->config_refresh |= SDRAM_REFRESH << 16;
header->config_ncdl = 0;
} else {
header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16;
header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff;
header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16;
header->config_ncdl = bcm_strtoul(ncdl, NULL, 0);
}
/* Clear data area */
ptr = (char *) header + sizeof(struct nvram_header);
bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
/* Leave space for a double NUL at the end */
end = (char *) header + NVRAM_SPACE - 2;
/* Write out all tuples */
for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
for (t = nvram_hash[i]; t; t = t->next) {
if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
break;
ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
}
}
/* End with a double NUL */
ptr += 2;
/* Set new length */
header->len = ROUNDUP(ptr - (char *) header, 4);
/* Little-endian CRC8 over the last 11 bytes of the header */
tmp.crc_ver_init = htol32(header->crc_ver_init);
tmp.config_refresh = htol32(header->config_refresh);
tmp.config_ncdl = htol32(header->config_ncdl);
crc = crc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
/* Continue CRC8 over data bytes */
crc = crc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
/* Set new CRC8 */
header->crc_ver_init |= crc;
/* Reinitialize hash table */
return nvram_rehash(header);
}
/* Initialize hash table. Should be locked. */
int
_nvram_init(void)
{
struct nvram_header *header;
int ret;
if (!(header = (struct nvram_header *) MALLOC(NVRAM_SPACE))) {
printf("nvram_init: out of memory\n");
return -12; /* -ENOMEM */
}
if ((ret = _nvram_read(header)) == 0 &&
header->magic == NVRAM_MAGIC)
nvram_rehash(header);
MFREE(header, NVRAM_SPACE);
return ret;
}
/* Free hash table. Should be locked. */
void
_nvram_exit(void)
{
nvram_free();
}

View File

@ -0,0 +1,638 @@
/*
* NVRAM variable manipulation (Linux kernel half)
*
* Copyright 2004, 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 <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/bootmem.h>
#include <linux/wrapper.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/mtd/mtd.h>
#include <asm/addrspace.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <typedefs.h>
#include <bcmendian.h>
#include <bcmnvram.h>
#include <bcmutils.h>
#include <sbconfig.h>
#include <sbchipc.h>
#include <sbutils.h>
#include <sbmips.h>
#include <sflash.h>
/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
#ifdef MODULE
#define early_nvram_get(name) nvram_get(name)
#else /* !MODULE */
/* Global SB handle */
extern void *bcm947xx_sbh;
extern spinlock_t bcm947xx_sbh_lock;
/* Convenience */
#define sbh bcm947xx_sbh
#define sbh_lock bcm947xx_sbh_lock
#define KB * 1024
#define MB * 1024 * 1024
/* Probe for NVRAM header */
static void __init
early_nvram_init(void)
{
struct nvram_header *header;
chipcregs_t *cc;
struct sflash *info = NULL;
int i;
uint32 base, off, lim;
if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
base = CC_FLASH_BASE;
switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
case PFLASH:
lim = CC_FLASH_MAX;
break;
case SFLASH_ST:
case SFLASH_AT:
if ((info = sflash_init(cc)) == NULL)
return;
lim = info->size;
break;
case FLASH_NONE:
default:
return;
}
} else {
/* extif assumed, Stop at 4 MB */
base = FLASH_BASE;
lim = FLASH_MAX;
}
off = FLASH_MIN;
while (off <= lim) {
/* Windowed flash access */
header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
if (header->magic == NVRAM_MAGIC) {
u32 *src = (u32 *) header;
u32 *dst = (u32 *) nvram_buf;
for (i = 0; i < sizeof(struct nvram_header); i += 4)
*dst++ = *src++;
for (; i < header->len && i < NVRAM_SPACE; i += 4)
*dst++ = ltoh32(*src++);
return;
}
/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
if (off == 1 KB)
break;
else if (off == 4 KB)
off = 1 KB;
else if (off == lim)
off = 4 KB;
else
off <<= 1;
}
}
/* Early (before mm or mtd) read-only access to NVRAM */
static char * __init
early_nvram_get(const char *name)
{
char *var, *value, *end, *eq;
if (!name)
return NULL;
if (!nvram_buf[0])
early_nvram_init();
/* Look for name=value and return value */
var = &nvram_buf[sizeof(struct nvram_header)];
end = nvram_buf + sizeof(nvram_buf) - 2;
end[0] = end[1] = '\0';
for (; *var; var = value + strlen(value) + 1) {
if (!(eq = strchr(var, '=')))
break;
value = eq + 1;
if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
return value;
}
return NULL;
}
#endif /* !MODULE */
extern char * _nvram_get(const char *name);
extern int _nvram_set(const char *name, const char *value);
extern int _nvram_unset(const char *name);
extern int _nvram_getall(char *buf, int count);
extern int _nvram_commit(struct nvram_header *header);
extern int _nvram_init(void);
extern void _nvram_exit(void);
/* Globals */
static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
static struct semaphore nvram_sem;
static unsigned long nvram_offset = 0;
static int nvram_major = -1;
static devfs_handle_t nvram_handle = NULL;
static struct mtd_info *nvram_mtd = NULL;
int
_nvram_read(char *buf)
{
struct nvram_header *header = (struct nvram_header *) buf;
size_t len;
if (!nvram_mtd ||
MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) ||
len != NVRAM_SPACE ||
header->magic != NVRAM_MAGIC) {
/* Maybe we can recover some data from early initialization */
memcpy(buf, nvram_buf, NVRAM_SPACE);
}
return 0;
}
struct nvram_tuple *
_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
{
if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
return NULL;
if (!t) {
if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
return NULL;
/* Copy name */
t->name = (char *) &t[1];
strcpy(t->name, name);
t->value = NULL;
}
/* Copy value */
if (!t->value || strcmp(t->value, value)) {
t->value = &nvram_buf[nvram_offset];
strcpy(t->value, value);
nvram_offset += strlen(value) + 1;
}
return t;
}
void
_nvram_free(struct nvram_tuple *t)
{
if (!t)
nvram_offset = 0;
else
kfree(t);
}
int
nvram_set(const char *name, const char *value)
{
unsigned long flags;
int ret;
struct nvram_header *header;
spin_lock_irqsave(&nvram_lock, flags);
if ((ret = _nvram_set(name, value))) {
/* Consolidate space and try again */
if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
if (_nvram_commit(header) == 0)
ret = _nvram_set(name, value);
kfree(header);
}
}
spin_unlock_irqrestore(&nvram_lock, flags);
return ret;
}
char *
real_nvram_get(const char *name)
{
unsigned long flags;
char *value;
spin_lock_irqsave(&nvram_lock, flags);
value = _nvram_get(name);
spin_unlock_irqrestore(&nvram_lock, flags);
return value;
}
char *
nvram_get(const char *name)
{
if (nvram_major >= 0)
return real_nvram_get(name);
else
return early_nvram_get(name);
}
int
nvram_unset(const char *name)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&nvram_lock, flags);
ret = _nvram_unset(name);
spin_unlock_irqrestore(&nvram_lock, flags);
return ret;
}
static void
erase_callback(struct erase_info *done)
{
wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
wake_up(wait_q);
}
int
nvram_commit(void)
{
char *buf;
size_t erasesize, len;
unsigned int i;
int ret;
struct nvram_header *header;
unsigned long flags;
u_int32_t offset;
DECLARE_WAITQUEUE(wait, current);
wait_queue_head_t wait_q;
struct erase_info erase;
printk("nvram_commit(): init\n");
if (!nvram_mtd) {
printk("nvram_commit: NVRAM not found\n");
return -ENODEV;
}
if (in_interrupt()) {
printk("nvram_commit: not committing in interrupt\n");
return -EINVAL;
}
/* Backup sector blocks to be erased */
erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize);
if (!(buf = kmalloc(erasesize, GFP_KERNEL))) {
printk("nvram_commit: out of memory\n");
return -ENOMEM;
}
down(&nvram_sem);
#if 0
offset = nvram_mtd->size - erasesize;
i = erasesize - NVRAM_SPACE;
ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
if (ret || len != i) {
printk("nvram_commit: read error\n");
ret = -EIO;
goto done;
#endif
if ((i = erasesize - NVRAM_SPACE) > 0) {
offset = nvram_mtd->size - erasesize;
len = 0;
ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
if (ret || len != i) {
printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
ret = -EIO;
goto done;
}
header = (struct nvram_header *)(buf + i);
} else {
offset = nvram_mtd->size - NVRAM_SPACE;
header = (struct nvram_header *)buf;
}
/* Regenerate NVRAM */
spin_lock_irqsave(&nvram_lock, flags);
ret = _nvram_commit(header);
spin_unlock_irqrestore(&nvram_lock, flags);
if (ret)
goto done;
/* Erase sector blocks */
init_waitqueue_head(&wait_q);
for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len; offset += nvram_mtd->erasesize) {
erase.mtd = nvram_mtd;
erase.addr = offset;
erase.len = nvram_mtd->erasesize;
erase.callback = erase_callback;
erase.priv = (u_long) &wait_q;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
/* Unlock sector blocks */
if (nvram_mtd->unlock)
nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
if ((ret = MTD_ERASE(nvram_mtd, &erase))) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&wait_q, &wait);
printk("nvram_commit: erase error\n");
goto done;
}
/* Wait for erase to finish */
schedule();
remove_wait_queue(&wait_q, &wait);
}
/* Write partition up to end of data area */
offset = nvram_mtd->size - erasesize;
i = erasesize - NVRAM_SPACE + header->len;
ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf);
if (ret || len != i) {
printk("nvram_commit: write error\n");
ret = -EIO;
goto done;
}
/*
* Reading a few bytes back here will put the device
* back to the correct mode on certain flashes */
offset = nvram_mtd->size - erasesize;
ret = MTD_READ(nvram_mtd, offset, 4, &len, buf);
done:
up(&nvram_sem);
kfree(buf);
printk("nvram_commit(): end\n");
return ret;
}
int
nvram_getall(char *buf, int count)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&nvram_lock, flags);
ret = _nvram_getall(buf, count);
spin_unlock_irqrestore(&nvram_lock, flags);
return ret;
}
EXPORT_SYMBOL(nvram_get);
EXPORT_SYMBOL(nvram_getall);
EXPORT_SYMBOL(nvram_set);
EXPORT_SYMBOL(nvram_unset);
EXPORT_SYMBOL(nvram_commit);
/* User mode interface below */
static ssize_t
dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
char tmp[100], *name = tmp, *value;
ssize_t ret;
unsigned long off;
if (count > sizeof(tmp)) {
if (!(name = kmalloc(count, GFP_KERNEL)))
return -ENOMEM;
}
if (copy_from_user(name, buf, count)) {
ret = -EFAULT;
goto done;
}
if (*name == '\0') {
/* Get all variables */
ret = nvram_getall(name, count);
if (ret == 0) {
if (copy_to_user(buf, name, count)) {
ret = -EFAULT;
goto done;
}
ret = count;
}
} else {
if (!(value = nvram_get(name))) {
ret = 0;
goto done;
}
/* Provide the offset into mmap() space */
off = (unsigned long) value - (unsigned long) nvram_buf;
if (put_user(off, (unsigned long *) buf)) {
ret = -EFAULT;
goto done;
}
ret = sizeof(unsigned long);
}
flush_cache_all();
done:
if (name != tmp)
kfree(name);
return ret;
}
static ssize_t
dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
char tmp[100], *name = tmp, *value;
ssize_t ret;
if (count > sizeof(tmp)) {
if (!(name = kmalloc(count, GFP_KERNEL)))
return -ENOMEM;
}
if (copy_from_user(name, buf, count)) {
ret = -EFAULT;
goto done;
}
value = name;
name = strsep(&value, "=");
if (value)
ret = nvram_set(name, value) ? : count;
else
ret = nvram_unset(name) ? : count;
done:
if (name != tmp)
kfree(name);
return ret;
}
static int
dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
if (cmd != NVRAM_MAGIC)
return -EINVAL;
return nvram_commit();
}
static int
dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
{
unsigned long offset = virt_to_phys(nvram_buf);
if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
return 0;
}
static int
dev_nvram_open(struct inode *inode, struct file * file)
{
MOD_INC_USE_COUNT;
return 0;
}
static int
dev_nvram_release(struct inode *inode, struct file * file)
{
MOD_DEC_USE_COUNT;
return 0;
}
static struct file_operations dev_nvram_fops = {
owner: THIS_MODULE,
open: dev_nvram_open,
release: dev_nvram_release,
read: dev_nvram_read,
write: dev_nvram_write,
ioctl: dev_nvram_ioctl,
mmap: dev_nvram_mmap,
};
static void
dev_nvram_exit(void)
{
int order = 0;
struct page *page, *end;
if (nvram_handle)
devfs_unregister(nvram_handle);
if (nvram_major >= 0)
devfs_unregister_chrdev(nvram_major, "nvram");
if (nvram_mtd)
put_mtd_device(nvram_mtd);
while ((PAGE_SIZE << order) < NVRAM_SPACE)
order++;
end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(nvram_buf); page <= end; page++)
mem_map_unreserve(page);
_nvram_exit();
}
static int __init
dev_nvram_init(void)
{
int order = 0, ret = 0;
struct page *page, *end;
unsigned int i;
/* Allocate and reserve memory to mmap() */
while ((PAGE_SIZE << order) < NVRAM_SPACE)
order++;
end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(nvram_buf); page <= end; page++)
mem_map_reserve(page);
#ifdef CONFIG_MTD
/* Find associated MTD device */
for (i = 0; i < MAX_MTD_DEVICES; i++) {
nvram_mtd = get_mtd_device(NULL, i);
if (nvram_mtd) {
if (!strcmp(nvram_mtd->name, "nvram") &&
nvram_mtd->size >= NVRAM_SPACE)
break;
put_mtd_device(nvram_mtd);
}
}
if (i >= MAX_MTD_DEVICES)
nvram_mtd = NULL;
#endif
/* Initialize hash table lock */
spin_lock_init(&nvram_lock);
/* Initialize commit semaphore */
init_MUTEX(&nvram_sem);
/* Register char device */
if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
ret = nvram_major;
goto err;
}
/* Initialize hash table */
_nvram_init();
/* Create /dev/nvram handle */
nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL);
/* Set the SDRAM NCDL value into NVRAM if not already done */
if (getintvar(NULL, "sdram_ncdl") == 0) {
unsigned int ncdl;
char buf[] = "0x00000000";
if ((ncdl = sb_memc_get_ncdl(sbh))) {
sprintf(buf, "0x%08x", ncdl);
nvram_set("sdram_ncdl", buf);
nvram_commit();
}
}
return 0;
err:
dev_nvram_exit();
return ret;
}
module_init(dev_nvram_init);
module_exit(dev_nvram_exit);

View File

@ -0,0 +1,352 @@
/*
* Low-Level PCI and SB support for BCM47xx (Linux support code)
*
* Copyright 2004, 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 <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/paccess.h>
#include <typedefs.h>
#include <bcmutils.h>
#include <sbconfig.h>
#include <sbpci.h>
#include <pcicfg.h>
#include <sbutils.h>
#include <bcmdevs.h>
#include <bcmnvram.h>
/* Global SB handle */
extern void *bcm947xx_sbh;
extern spinlock_t bcm947xx_sbh_lock;
/* Convenience */
#define sbh bcm947xx_sbh
#define sbh_lock bcm947xx_sbh_lock
static int
sbpci_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&sbh_lock, flags);
ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
spin_unlock_irqrestore(&sbh_lock, flags);
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static int
sbpci_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&sbh_lock, flags);
ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
spin_unlock_irqrestore(&sbh_lock, flags);
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static int
sbpci_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&sbh_lock, flags);
ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
spin_unlock_irqrestore(&sbh_lock, flags);
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static int
sbpci_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&sbh_lock, flags);
ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
spin_unlock_irqrestore(&sbh_lock, flags);
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static int
sbpci_write_config_word(struct pci_dev *dev, int where, u16 value)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&sbh_lock, flags);
ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
spin_unlock_irqrestore(&sbh_lock, flags);
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static int
sbpci_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&sbh_lock, flags);
ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
spin_unlock_irqrestore(&sbh_lock, flags);
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pcibios_ops = {
sbpci_read_config_byte,
sbpci_read_config_word,
sbpci_read_config_dword,
sbpci_write_config_byte,
sbpci_write_config_word,
sbpci_write_config_dword
};
void __init
pcibios_init(void)
{
ulong flags;
if (!(sbh = sb_kattach()))
panic("sb_kattach failed");
spin_lock_init(&sbh_lock);
spin_lock_irqsave(&sbh_lock, flags);
sbpci_init(sbh);
spin_unlock_irqrestore(&sbh_lock, flags);
set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000));
/* Scan the SB bus */
pci_scan_bus(0, &pcibios_ops, NULL);
}
char * __init
pcibios_setup(char *str)
{
if (!strncmp(str, "ban=", 4)) {
sbpci_ban(simple_strtoul(str + 4, NULL, 0));
return NULL;
}
return (str);
}
static u32 pci_iobase = 0x100;
static u32 pci_membase = SB_PCI_DMA;
void __init
pcibios_fixup_bus(struct pci_bus *b)
{
struct list_head *ln;
struct pci_dev *d;
struct resource *res;
int pos, size;
u32 *base;
u8 irq;
printk("PCI: Fixing up bus %d\n", b->number);
/* Fix up SB */
if (b->number == 0) {
for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
d = pci_dev_b(ln);
/* Fix up interrupt lines */
pci_read_config_byte(d, PCI_INTERRUPT_LINE, &irq);
d->irq = irq + 2;
pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
}
}
/* Fix up external PCI */
else {
for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
d = pci_dev_b(ln);
/* Fix up resource bases */
for (pos = 0; pos < 6; pos++) {
res = &d->resource[pos];
base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase;
if (res->end) {
size = res->end - res->start + 1;
if (*base & (size - 1))
*base = (*base + size) & ~(size - 1);
res->start = *base;
res->end = res->start + size - 1;
*base += size;
pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
}
/* Fix up PCI bridge BAR0 only */
if (b->number == 1 && PCI_SLOT(d->devfn) == 0)
break;
}
/* Fix up interrupt lines */
if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))
d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq;
pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
}
}
}
unsigned int
pcibios_assign_all_busses(void)
{
return 1;
}
void
pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
}
int
pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
int idx;
struct resource *r;
/* External PCI only */
if (dev->bus->number == 0)
return 0;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for(idx=0; idx<6; idx++) {
r = &dev->resource[idx];
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (dev->resource[PCI_ROM_RESOURCE].start)
cmd |= PCI_COMMAND_MEMORY;
if (cmd != old_cmd) {
printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
int
pcibios_enable_device(struct pci_dev *dev, int mask)
{
ulong flags;
uint coreidx;
/* External PCI device enable */
if (dev->bus->number != 0)
return pcibios_enable_resources(dev);
/* These cores come out of reset enabled */
if (dev->device == SB_MIPS ||
dev->device == SB_MIPS33 ||
dev->device == SB_EXTIF ||
dev->device == SB_CC)
return 0;
spin_lock_irqsave(&sbh_lock, flags);
coreidx = sb_coreidx(sbh);
if (!sb_setcoreidx(sbh, PCI_SLOT(dev->devfn)))
return PCIBIOS_DEVICE_NOT_FOUND;
/*
* The USB core requires a special bit to be set during core
* reset to enable host (OHCI) mode. Resetting the SB core in
* pcibios_enable_device() is a hack for compatibility with
* vanilla usb-ohci so that it does not have to know about
* SB. A driver that wants to use the USB core in device mode
* should know about SB and should reset the bit back to 0
* after calling pcibios_enable_device().
*/
if (sb_coreid(sbh) == SB_USB) {
sb_core_disable(sbh, sb_coreflags(sbh, 0, 0));
sb_core_reset(sbh, 1 << 29);
} else
sb_core_reset(sbh, 0);
sb_setcoreidx(sbh, coreidx);
spin_unlock_irqrestore(&sbh_lock, flags);
return 0;
}
void
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
unsigned long where, size;
u32 reg;
/* External PCI only */
if (dev->bus->number == 0)
return;
where = PCI_BASE_ADDRESS_0 + (resource * 4);
size = res->end - res->start;
pci_read_config_dword(dev, where, &reg);
reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
pci_write_config_dword(dev, where, reg);
}
static void __init
quirk_sbpci_bridge(struct pci_dev *dev)
{
if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0)
return;
printk("PCI: Fixing up bridge\n");
/* Enable PCI bridge bus mastering and memory space */
pci_set_master(dev);
pcibios_enable_resources(dev);
/* Enable PCI bridge BAR1 prefetch and burst */
pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3);
}
/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain crappy BIOSes forget to set it properly.
*/
unsigned int pcibios_max_latency = 255;
void pcibios_set_master(struct pci_dev *dev)
{
u8 lat;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
if (lat < 16)
lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
else if (lat > pcibios_max_latency)
lat = pcibios_max_latency;
else
return;
printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_sbpci_bridge },
{ 0 }
};

View File

@ -0,0 +1,67 @@
/*
* Broadcom BCM47xx Performance Counter /proc/cpuinfo support
*
* Copyright 2004, 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 <asm/mipsregs.h>
/*
* BCM4710 performance counter register select values
* No even-odd control-counter mapping, just counters
*/
#define PERF_DCACHE_HIT 0
#define PERF_DCACHE_MISS 1
#define PERF_ICACHE_HIT 2
#define PERF_ICACHE_MISS 3
#define PERF_ICOUNT 4
/*
* Move from Coprocessor 0 Register 25 Select n
* data <- CPR[0,25,n]
* GPR[1] <- data
*/
#define read_bcm4710_perf_cntr(n) \
({ int __res; \
__asm__ __volatile__( \
".set\tnoreorder\n\t" \
".set\tnoat\n\t" \
".word\t"STR(0x4001c800|(n))"\n\t" \
"move\t%0,$1\n\t" \
".set\tat\n\t" \
".set\treorder" \
:"=r" (__res)); \
__res;})
asmlinkage unsigned int read_perf_cntr(unsigned int counter)
{
switch (counter) {
case PERF_DCACHE_HIT: return read_bcm4710_perf_cntr(PERF_DCACHE_HIT);
case PERF_DCACHE_MISS: return read_bcm4710_perf_cntr(PERF_DCACHE_MISS);
case PERF_ICACHE_HIT: return read_bcm4710_perf_cntr(PERF_ICACHE_HIT);
case PERF_ICACHE_MISS: return read_bcm4710_perf_cntr(PERF_ICACHE_MISS);
case PERF_ICOUNT: return read_bcm4710_perf_cntr(PERF_ICOUNT);
}
return 0;
}
asmlinkage void write_perf_cntr(unsigned int counter, unsigned int val)
{
}
asmlinkage unsigned int read_perf_cntl(unsigned int counter)
{
return 0;
}
asmlinkage void write_perf_cntl(unsigned int counter, unsigned int val)
{
}

View File

@ -0,0 +1,41 @@
/*
* Early initialization code for BCM94710 boards
*
* Copyright 2004, 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 <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/bootinfo.h>
void __init
prom_init(int argc, const char **argv)
{
unsigned long mem;
mips_machgroup = MACH_GROUP_BRCM;
mips_machtype = MACH_BCM947XX;
/* Figure out memory size by finding aliases */
for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
*(unsigned long *)(prom_init))
break;
}
add_memory_region(0, mem, BOOT_MEM_RAM);
}
void __init
prom_free_prom_memory(void)
{
}

View File

@ -0,0 +1,951 @@
/*
* BCM47XX Sonics SiliconBackplane MIPS core routines
*
* Copyright 2004, 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 <osl.h>
#include <sbutils.h>
#include <bcmdevs.h>
#include <bcmnvram.h>
#include <bcmutils.h>
#include <hndmips.h>
#include <sbconfig.h>
#include <sbextif.h>
#include <sbchipc.h>
#include <sbmemc.h>
/*
* Memory segments (32bit kernel mode addresses)
*/
#undef KUSEG
#undef KSEG0
#undef KSEG1
#undef KSEG2
#undef KSEG3
#define KUSEG 0x00000000
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG2 0xc0000000
#define KSEG3 0xe0000000
/*
* Map an address to a certain kernel segment
*/
#undef KSEG0ADDR
#undef KSEG1ADDR
#undef KSEG2ADDR
#undef KSEG3ADDR
#define KSEG0ADDR(a) (((a) & 0x1fffffff) | KSEG0)
#define KSEG1ADDR(a) (((a) & 0x1fffffff) | KSEG1)
#define KSEG2ADDR(a) (((a) & 0x1fffffff) | KSEG2)
#define KSEG3ADDR(a) (((a) & 0x1fffffff) | KSEG3)
/*
* The following macros are especially useful for __asm__
* inline assembler.
*/
#ifndef __STR
#define __STR(x) #x
#endif
#ifndef STR
#define STR(x) __STR(x)
#endif
/* *********************************************************************
* CP0 Registers
********************************************************************* */
#define C0_INX 0 /* CP0: TLB Index */
#define C0_RAND 1 /* CP0: TLB Random */
#define C0_TLBLO0 2 /* CP0: TLB EntryLo0 */
#define C0_TLBLO C0_TLBLO0 /* CP0: TLB EntryLo0 */
#define C0_TLBLO1 3 /* CP0: TLB EntryLo1 */
#define C0_CTEXT 4 /* CP0: Context */
#define C0_PGMASK 5 /* CP0: TLB PageMask */
#define C0_WIRED 6 /* CP0: TLB Wired */
#define C0_BADVADDR 8 /* CP0: Bad Virtual Address */
#define C0_COUNT 9 /* CP0: Count */
#define C0_TLBHI 10 /* CP0: TLB EntryHi */
#define C0_COMPARE 11 /* CP0: Compare */
#define C0_SR 12 /* CP0: Processor Status */
#define C0_STATUS C0_SR /* CP0: Processor Status */
#define C0_CAUSE 13 /* CP0: Exception Cause */
#define C0_EPC 14 /* CP0: Exception PC */
#define C0_PRID 15 /* CP0: Processor Revision Indentifier */
#define C0_CONFIG 16 /* CP0: Config */
#define C0_LLADDR 17 /* CP0: LLAddr */
#define C0_WATCHLO 18 /* CP0: WatchpointLo */
#define C0_WATCHHI 19 /* CP0: WatchpointHi */
#define C0_XCTEXT 20 /* CP0: XContext */
#define C0_DIAGNOSTIC 22 /* CP0: Diagnostic */
#define C0_BROADCOM C0_DIAGNOSTIC /* CP0: Broadcom Register */
#define C0_ECC 26 /* CP0: ECC */
#define C0_CACHEERR 27 /* CP0: CacheErr */
#define C0_TAGLO 28 /* CP0: TagLo */
#define C0_TAGHI 29 /* CP0: TagHi */
#define C0_ERREPC 30 /* CP0: ErrorEPC */
/*
* Macros to access the system control coprocessor
*/
#define MFC0(source, sel) \
({ \
int __res; \
__asm__ __volatile__( \
".set\tnoreorder\n\t" \
".set\tnoat\n\t" \
".word\t"STR(0x40010000 | ((source)<<11) | (sel))"\n\t" \
"move\t%0,$1\n\t" \
".set\tat\n\t" \
".set\treorder" \
:"=r" (__res) \
: \
:"$1"); \
__res; \
})
#define MTC0(source, sel, value) \
do { \
__asm__ __volatile__( \
".set\tnoreorder\n\t" \
".set\tnoat\n\t" \
"move\t$1,%z0\n\t" \
".word\t"STR(0x40810000 | ((source)<<11) | (sel))"\n\t" \
".set\tat\n\t" \
".set\treorder" \
: \
:"Jr" (value) \
:"$1"); \
} while (0)
/*
* R4x00 interrupt enable / cause bits
*/
#undef IE_SW0
#undef IE_SW1
#undef IE_IRQ0
#undef IE_IRQ1
#undef IE_IRQ2
#undef IE_IRQ3
#undef IE_IRQ4
#undef IE_IRQ5
#define IE_SW0 (1<< 8)
#define IE_SW1 (1<< 9)
#define IE_IRQ0 (1<<10)
#define IE_IRQ1 (1<<11)
#define IE_IRQ2 (1<<12)
#define IE_IRQ3 (1<<13)
#define IE_IRQ4 (1<<14)
#define IE_IRQ5 (1<<15)
/*
* Bitfields in the R4xx0 cp0 status register
*/
#define ST0_IE 0x00000001
#define ST0_EXL 0x00000002
#define ST0_ERL 0x00000004
#define ST0_KSU 0x00000018
# define KSU_USER 0x00000010
# define KSU_SUPERVISOR 0x00000008
# define KSU_KERNEL 0x00000000
#define ST0_UX 0x00000020
#define ST0_SX 0x00000040
#define ST0_KX 0x00000080
#define ST0_DE 0x00010000
#define ST0_CE 0x00020000
/*
* Status register bits available in all MIPS CPUs.
*/
#define ST0_IM 0x0000ff00
#define ST0_CH 0x00040000
#define ST0_SR 0x00100000
#define ST0_TS 0x00200000
#define ST0_BEV 0x00400000
#define ST0_RE 0x02000000
#define ST0_FR 0x04000000
#define ST0_CU 0xf0000000
#define ST0_CU0 0x10000000
#define ST0_CU1 0x20000000
#define ST0_CU2 0x40000000
#define ST0_CU3 0x80000000
#define ST0_XX 0x80000000 /* MIPS IV naming */
/*
* Cache Operations
*/
#ifndef Fill_I
#define Fill_I 0x14
#endif
#define cache_unroll(base,op) \
__asm__ __volatile__(" \
.set noreorder; \
.set mips3; \
cache %1, (%0); \
.set mips0; \
.set reorder" \
: \
: "r" (base), \
"i" (op));
/*
* These are the UART port assignments, expressed as offsets from the base
* register. These assignments should hold for any serial port based on
* a 8250, 16450, or 16550(A).
*/
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_MSR 6 /* In: Modem Status Register */
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
/*
* Returns TRUE if an external UART exists at the given base
* register.
*/
static bool
serial_exists(uint8 *regs)
{
uint8 save_mcr, status1;
save_mcr = R_REG(&regs[UART_MCR]);
W_REG(&regs[UART_MCR], UART_MCR_LOOP | 0x0a);
status1 = R_REG(&regs[UART_MSR]) & 0xf0;
W_REG(&regs[UART_MCR], save_mcr);
return (status1 == 0x90);
}
/*
* Initializes UART access. The callback function will be called once
* per found UART.
*/
void
sb_serial_init(void *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift))
{
void *regs;
ulong base;
uint irq;
int i, n;
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(&sb->sbadmatch1)));
/* Determine IRQ */
irq = sb_irq(sbh);
/* Disable GPIO interrupt initially */
W_REG(&eir->gpiointpolarity, 0);
W_REG(&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(regs)) {
/* Set GPIO 1 to be the external UART IRQ */
W_REG(&eir->gpiointmask, 2);
if (add)
add(regs, irq, 13500000, 0);
}
}
/* Add internal UART if enabled */
if (R_REG(&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;
/* Determine core revision and capabilities */
rev = sb_corerev(sbh);
cap = R_REG(&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(&cc->clockcontrol_n),
R_REG(&cc->clockcontrol_m2));
div = 1;
} else if (rev >= 3) {
/* Internal backplane clock */
baud_base = sb_clock_rate(pll,
R_REG(&cc->clockcontrol_n),
R_REG(&cc->clockcontrol_sb));
div = 2; /* Minimum divisor */
W_REG(&cc->clkdiv, ((R_REG(&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(&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);
}
}
}
/* Returns the SB interrupt flag of the current core. */
uint32
sb_flag(void *sbh)
{
void *regs;
sbconfig_t *sb;
regs = sb_coreregs(sbh);
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
return (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
}
static const uint32 sbips_int_mask[] = {
0,
SBIPS_INT1_MASK,
SBIPS_INT2_MASK,
SBIPS_INT3_MASK,
SBIPS_INT4_MASK
};
static const uint32 sbips_int_shift[] = {
0,
0,
SBIPS_INT2_SHIFT,
SBIPS_INT3_SHIFT,
SBIPS_INT4_SHIFT
};
/*
* Returns the MIPS IRQ assignment of the current core. If unassigned,
* 0 is returned.
*/
uint
sb_irq(void *sbh)
{
uint idx;
void *regs;
sbconfig_t *sb;
uint32 flag, sbipsflag;
uint irq = 0;
flag = sb_flag(sbh);
idx = sb_coreidx(sbh);
if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
(regs = sb_setcore(sbh, SB_MIPS33, 0))) {
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
/* sbipsflag specifies which core is routed to interrupts 1 to 4 */
sbipsflag = R_REG(&sb->sbipsflag);
for (irq = 1; irq <= 4; irq++) {
if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
break;
}
if (irq == 5)
irq = 0;
}
sb_setcoreidx(sbh, idx);
return irq;
}
/* Clears the specified MIPS IRQ. */
static void
sb_clearirq(void *sbh, uint irq)
{
void *regs;
sbconfig_t *sb;
if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
!(regs = sb_setcore(sbh, SB_MIPS33, 0)))
ASSERT(regs);
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
if (irq == 0)
W_REG(&sb->sbintvec, 0);
else
OR_REG(&sb->sbipsflag, sbips_int_mask[irq]);
}
/*
* Assigns the specified MIPS IRQ to the specified core. Shared MIPS
* IRQ 0 may be assigned more than once.
*/
static void
sb_setirq(void *sbh, uint irq, uint coreid, uint coreunit)
{
void *regs;
sbconfig_t *sb;
uint32 flag;
regs = sb_setcore(sbh, coreid, coreunit);
ASSERT(regs);
flag = sb_flag(sbh);
if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
!(regs = sb_setcore(sbh, SB_MIPS33, 0)))
ASSERT(regs);
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
if (irq == 0)
OR_REG(&sb->sbintvec, 1 << flag);
else {
flag <<= sbips_int_shift[irq];
ASSERT(!(flag & ~sbips_int_mask[irq]));
flag |= R_REG(&sb->sbipsflag) & ~sbips_int_mask[irq];
W_REG(&sb->sbipsflag, flag);
}
}
/*
* Initializes clocks and interrupts. SB and NVRAM access must be
* initialized prior to calling.
*/
void
sb_mips_init(void *sbh)
{
ulong hz, ns, tmp;
extifregs_t *eir;
chipcregs_t *cc;
char *value;
uint irq;
/* Figure out current SB clock speed */
if ((hz = sb_clock(sbh)) == 0)
hz = 100000000;
ns = 1000000000 / hz;
/* Setup external interface timing */
if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
/* Initialize extif so we can get to the LEDs and external UART */
W_REG(&eir->prog_config, CF_EN);
/* Set timing for the flash */
tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
/* Set programmable interface timing for external uart */
tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
} else if ((cc = sb_setcore(sbh, SB_CC, 0))) {
/* Set timing for the flash */
tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
tmp |= CEIL(10, ns) << FW_W1_SHIFT; /* W1 = 10nS */
tmp |= CEIL(120, ns); /* W0 = 120nS */
W_REG(&cc->flash_waitcount, tmp);
W_REG(&cc->pcmcia_memwait, tmp);
}
/* Chip specific initialization */
switch (sb_chip(sbh)) {
case BCM4710_DEVICE_ID:
/* Clear interrupt map */
for (irq = 0; irq <= 4; irq++)
sb_clearirq(sbh, irq);
sb_setirq(sbh, 0, SB_CODEC, 0);
sb_setirq(sbh, 0, SB_EXTIF, 0);
sb_setirq(sbh, 2, SB_ENET, 1);
sb_setirq(sbh, 3, SB_ILINE20, 0);
sb_setirq(sbh, 4, SB_PCI, 0);
ASSERT(eir);
value = nvram_get("et0phyaddr");
if (value && !strcmp(value, "31")) {
/* Enable internal UART */
W_REG(&eir->corecontrol, CC_UE);
/* Give USB its own interrupt */
sb_setirq(sbh, 1, SB_USB, 0);
} else {
/* Disable internal UART */
W_REG(&eir->corecontrol, 0);
/* Give Ethernet its own interrupt */
sb_setirq(sbh, 1, SB_ENET, 0);
sb_setirq(sbh, 0, SB_USB, 0);
}
break;
case BCM4310_DEVICE_ID:
MTC0(C0_BROADCOM, 0, MFC0(C0_BROADCOM, 0) & ~(1 << 22));
break;
}
}
uint32
sb_mips_clock(void *sbh)
{
extifregs_t *eir;
chipcregs_t *cc;
uint32 n, m;
uint idx;
uint32 pll_type, rate = 0;
/* get index of the current core */
idx = sb_coreidx(sbh);
pll_type = PLL_TYPE1;
/* switch to extif or chipc core */
if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
n = R_REG(&eir->clockcontrol_n);
m = R_REG(&eir->clockcontrol_sb);
} else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
n = R_REG(&cc->clockcontrol_n);
if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4))
m = R_REG(&cc->clockcontrol_mips);
else if (pll_type == PLL_TYPE3) {
rate = 200000000;
goto out;
} else
m = R_REG(&cc->clockcontrol_sb);
} else
goto out;
/* calculate rate */
rate = sb_clock_rate(pll_type, n, m);
out:
/* switch back to previous core */
sb_setcoreidx(sbh, idx);
return rate;
}
static void
icache_probe(int *size, int *lsize)
{
uint32 config1;
uint sets, ways;
config1 = MFC0(C0_CONFIG, 1);
/* Instruction Cache Size = Associativity * Line Size * Sets Per Way */
if ((*lsize = ((config1 >> 19) & 7)))
*lsize = 2 << *lsize;
sets = 64 << ((config1 >> 22) & 7);
ways = 1 + ((config1 >> 16) & 7);
*size = *lsize * sets * ways;
}
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
static void
handler(void)
{
/* Step 11 */
__asm__ (
".set\tmips32\n\t"
"ssnop\n\t"
"ssnop\n\t"
/* Disable interrupts */
/* MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
"mfc0 $15, $12\n\t"
"and $15, $15, -31746\n\t"
"mtc0 $15, $12\n\t"
"eret\n\t"
"nop\n\t"
"nop\n\t"
".set\tmips0"
);
}
/* The following MUST come right after handler() */
static void
afterhandler(void)
{
}
/*
* Set the MIPS, backplane and PCI clocks as closely as possible.
*/
bool
sb_mips_setclock(void *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
{
extifregs_t *eir = NULL;
chipcregs_t *cc = NULL;
mipsregs_t *mipsr = NULL;
volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci;
uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, new_ratio;
uint32 pll_type, sync_mode;
uint idx, i;
typedef struct {
uint32 mipsclock;
uint16 n;
uint32 sb;
uint32 pci33;
uint32 pci25;
} n3m_table_t;
static n3m_table_t type1_table[] = {
{ 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 }, /* 96.000 32.000 24.000 */
{ 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 }, /* 100.000 33.333 25.000 */
{ 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 }, /* 104.000 31.200 24.960 */
{ 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 }, /* 108.000 32.400 24.923 */
{ 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 }, /* 112.000 32.000 24.889 */
{ 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 }, /* 115.200 32.000 24.000 */
{ 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 }, /* 120.000 30.000 24.000 */
{ 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 }, /* 124.800 31.200 24.960 */
{ 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 }, /* 128.000 32.000 24.000 */
{ 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 }, /* 132.000 33.000 24.750 */
{ 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 }, /* 136.000 32.640 24.727 */
{ 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 }, /* 140.000 30.000 24.706 */
{ 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 }, /* 144.000 30.857 24.686 */
{ 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 }, /* 150.857 33.000 24.000 */
{ 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 }, /* 152.000 32.571 24.000 */
{ 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 }, /* 156.000 31.200 24.960 */
{ 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 }, /* 160.000 32.000 24.000 */
{ 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 }, /* 163.200 32.640 24.727 */
{ 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 }, /* 168.000 32.000 24.889 */
{ 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 }, /* 176.000 33.000 24.000 */
};
typedef struct {
uint32 mipsclock;
uint32 sbclock;
uint16 n;
uint32 sb;
uint32 pci33;
uint32 m2;
uint32 m3;
uint32 ratio;
uint32 ratio_parm;
} n4m_table_t;
static n4m_table_t type2_table[] = {
{ 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
{ 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
{ 200000000, 100000000, 0x0303, 0x01000000, 0x01000600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
{ 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
{ 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
{ 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
{ 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
{ 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
{ 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
{ 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
{ 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
{ 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
{ 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
{ 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
{ 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
{ 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
{ 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 }
};
static n4m_table_t type4_table[] = {
{ 192000000, 96000000, 0x0702, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
{ 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
{ 216000000, 108000000, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
{ 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x11030305, 0x04000005, 0x94, 0x012a00a9 },
{ 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
{ 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 0x21, 0x0aaa0555 },
{ 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
{ 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
{ 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
{ 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
{ 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
{ 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 0x52, 0x02520129 }
};
uint icache_size, ic_lsize;
ulong start, end, dst;
bool ret = FALSE;
/* get index of the current core */
idx = sb_coreidx(sbh);
/* switch to extif or chipc core */
if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
pll_type = PLL_TYPE1;
clockcontrol_n = &eir->clockcontrol_n;
clockcontrol_sb = &eir->clockcontrol_sb;
clockcontrol_pci = &eir->clockcontrol_pci;
} else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
clockcontrol_n = &cc->clockcontrol_n;
clockcontrol_sb = &cc->clockcontrol_sb;
clockcontrol_pci = &cc->clockcontrol_pci;
} else
goto done;
/* Store the current clock register values */
orig_n = R_REG(clockcontrol_n);
orig_sb = R_REG(clockcontrol_sb);
orig_pci = R_REG(clockcontrol_pci);
if (pll_type == PLL_TYPE1) {
/* Keep the current PCI clock if not specified */
if (pciclock == 0) {
pciclock = sb_clock_rate(pll_type, R_REG(clockcontrol_n), R_REG(clockcontrol_pci));
pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
}
/* Search for the closest MIPS clock less than or equal to a preferred value */
for (i = 0; i < ARRAYSIZE(type1_table); i++) {
ASSERT(type1_table[i].mipsclock ==
sb_clock_rate(pll_type, type1_table[i].n, type1_table[i].sb));
if (type1_table[i].mipsclock > mipsclock)
break;
}
if (i == 0) {
ret = FALSE;
goto done;
} else {
ret = TRUE;
i--;
}
ASSERT(type1_table[i].mipsclock <= mipsclock);
/* No PLL change */
if ((orig_n == type1_table[i].n) &&
(orig_sb == type1_table[i].sb) &&
(orig_pci == type1_table[i].pci33))
goto done;
/* Set the PLL controls */
W_REG(clockcontrol_n, type1_table[i].n);
W_REG(clockcontrol_sb, type1_table[i].sb);
if (pciclock == 25000000)
W_REG(clockcontrol_pci, type1_table[i].pci25);
else
W_REG(clockcontrol_pci, type1_table[i].pci33);
/* Reset */
sb_watchdog(sbh, 1);
while (1);
} else if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4)) {
n4m_table_t *table = (pll_type == PLL_TYPE2) ? type2_table : type4_table;
uint tabsz = (pll_type == PLL_TYPE2) ? ARRAYSIZE(type2_table) : ARRAYSIZE(type4_table);
ASSERT(cc);
/* Store the current clock register values */
orig_m2 = R_REG(&cc->clockcontrol_m2);
orig_mips = R_REG(&cc->clockcontrol_mips);
orig_ratio_parm = 0;
/* Look up current ratio */
for (i = 0; i < tabsz; i++) {
if ((orig_n == table[i].n) &&
(orig_sb == table[i].sb) &&
(orig_pci == table[i].pci33) &&
(orig_m2 == table[i].m2) &&
(orig_mips == table[i].m3)) {
orig_ratio_parm = table[i].ratio_parm;
break;
}
}
/* Search for the closest MIPS clock greater or equal to a preferred value */
for (i = 0; i < tabsz; i++) {
ASSERT(table[i].mipsclock ==
sb_clock_rate(pll_type, table[i].n, table[i].m3));
if ((mipsclock <= table[i].mipsclock) &&
((sbclock == 0) || (sbclock <= table[i].sbclock)))
break;
}
if (i == tabsz) {
ret = FALSE;
goto done;
} else {
ret = TRUE;
}
/* No PLL change */
if ((orig_n == table[i].n) &&
(orig_sb == table[i].sb) &&
(orig_pci == table[i].pci33) &&
(orig_m2 == table[i].m2) &&
(orig_mips == table[i].m3))
goto done;
/* Set the PLL controls */
W_REG(clockcontrol_n, table[i].n);
W_REG(clockcontrol_sb, table[i].sb);
W_REG(clockcontrol_pci, table[i].pci33);
W_REG(&cc->clockcontrol_m2, table[i].m2);
W_REG(&cc->clockcontrol_mips, table[i].m3);
/* No ratio change */
if (orig_ratio_parm == table[i].ratio_parm)
goto end_fill;
new_ratio = table[i].ratio_parm;
icache_probe(&icache_size, &ic_lsize);
/* Preload the code into the cache */
start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
while (start < end) {
cache_unroll(start, Fill_I);
start += ic_lsize;
}
/* Copy the handler */
start = (ulong) &handler;
end = (ulong) &afterhandler;
dst = KSEG1ADDR(0x180);
for (i = 0; i < (end - start); i += 4)
*((ulong *)(dst + i)) = *((ulong *)(start + i));
/* Preload handler into the cache one line at a time */
for (i = 0; i < (end - start); i += 4)
cache_unroll(dst + i, Fill_I);
/* Clear BEV bit */
MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
/* Enable interrupts */
MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
/* Enable MIPS timer interrupt */
if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
!(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
ASSERT(mipsr);
W_REG(&mipsr->intmask, 1);
start_fill:
/* step 1, set clock ratios */
MTC0(C0_BROADCOM, 3, new_ratio);
MTC0(C0_BROADCOM, 1, 8);
/* step 2: program timer intr */
W_REG(&mipsr->timer, 100);
(void) R_REG(&mipsr->timer);
/* step 3, switch to async */
sync_mode = MFC0(C0_BROADCOM, 4);
MTC0(C0_BROADCOM, 4, 1 << 22);
/* step 4, set cfg active */
MTC0(C0_BROADCOM, 2, 0x9);
/* steps 5 & 6 */
__asm__ __volatile__ (
".set\tmips3\n\t"
"wait\n\t"
".set\tmips0"
);
/* step 7, clear cfg_active */
MTC0(C0_BROADCOM, 2, 0);
/* Additional Step: set back to orig sync mode */
MTC0(C0_BROADCOM, 4, sync_mode);
/* step 8, fake soft reset */
MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | 4);
end_fill:
/* step 9 set watchdog timer */
sb_watchdog(sbh, 20);
(void) R_REG(&cc->chipid);
/* step 11 */
__asm__ __volatile__ (
".set\tmips3\n\t"
"sync\n\t"
"wait\n\t"
".set\tmips0"
);
while (1);
}
done:
/* switch back to previous core */
sb_setcoreidx(sbh, idx);
return ret;
}
/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
uint32
sb_memc_get_ncdl(void *sbh)
{
sbmemcregs_t *memc;
uint32 ret = 0;
uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
uint idx, rev;
idx = sb_coreidx(sbh);
memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
if (memc == 0)
goto out;
rev = sb_corerev(sbh);
config = R_REG(&memc->config);
wr = R_REG(&memc->wrncdlcor);
rd = R_REG(&memc->rdncdlcor);
misc = R_REG(&memc->miscdlyctl);
dqsg = R_REG(&memc->dqsgatencdl);
rd &= MEMC_RDNCDLCOR_RD_MASK;
wr &= MEMC_WRNCDLCOR_WR_MASK;
dqsg &= MEMC_DQSGATENCDL_G_MASK;
if (config & MEMC_CONFIG_DDR) {
ret = (wr << 16) | (rd << 8) | dqsg;
} else {
if (rev > 0)
cd = rd;
else
cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
ret = (sm << 16) | (sd << 8) | cd;
}
out:
/* switch back to previous core */
sb_setcoreidx(sbh, idx);
return ret;
}

View File

@ -0,0 +1,563 @@
/*
* Low-Level PCI and SB support for BCM47xx
*
* Copyright 2004, 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 <pcicfg.h>
#include <bcmdevs.h>
#include <sbconfig.h>
#include <sbpci.h>
#include <osl.h>
#include <bcmendian.h>
#include <bcmutils.h>
#include <sbutils.h>
#include <bcmnvram.h>
#include <hndmips.h>
/* Can free sbpci_init() memory after boot */
#ifndef linux
#define __init
#endif
/* Emulated configuration space */
static pci_config_regs sb_config_regs[SB_MAXCORES];
/* Banned cores */
static uint16 pci_ban[32] = { 0 };
static uint pci_banned = 0;
/* CardBus mode */
static bool cardbus = FALSE;
/* Disable PCI host core */
static bool pci_disabled = FALSE;
/*
* Functions for accessing external PCI configuration space
*/
/* Assume one-hot slot wiring */
#define PCI_SLOT_MAX 16
static uint32
config_cmd(void *sbh, uint bus, uint dev, uint func, uint off)
{
uint coreidx;
sbpciregs_t *regs;
uint32 addr = 0;
/* CardBusMode supports only one device */
if (cardbus && dev > 1)
return 0;
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) {
/* Slide the PCI window to the appropriate slot */
W_REG(&regs->sbtopci1, SBTOPCI_CFG0 | ((1 << (dev + 16)) & SBTOPCI1_MASK));
addr = SB_PCI_CFG | ((1 << (dev + 16)) & ~SBTOPCI1_MASK) |
(func << 8) | (off & ~3);
}
}
/* Type 1 transaction */
else {
W_REG(&regs->sbtopci1, SBTOPCI_CFG1);
addr = SB_PCI_CFG | (bus << 16) | (dev << 11) | (func << 8) | (off & ~3);
}
sb_setcoreidx(sbh, coreidx);
return addr;
}
static int
extpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
{
uint32 addr, *reg = NULL, val;
int ret = 0;
if (pci_disabled ||
!(addr = config_cmd(sbh, bus, dev, func, off)) ||
!(reg = (uint32 *) REG_MAP(addr, len)) ||
BUSPROBE(val, reg))
val = 0xffffffff;
val >>= 8 * (off & 3);
if (len == 4)
*((uint32 *) buf) = val;
else if (len == 2)
*((uint16 *) buf) = (uint16) val;
else if (len == 1)
*((uint8 *) buf) = (uint8) val;
else
ret = -1;
if (reg)
REG_UNMAP(reg);
return ret;
}
static int
extpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
{
uint32 addr, *reg = NULL, val;
int ret = 0;
if (pci_disabled ||
!(addr = config_cmd(sbh, bus, dev, func, off)) ||
!(reg = (uint32 *) REG_MAP(addr, len)) ||
BUSPROBE(val, reg))
goto done;
if (len == 4)
val = *((uint32 *) buf);
else if (len == 2) {
val &= ~(0xffff << (8 * (off & 3)));
val |= *((uint16 *) buf) << (8 * (off & 3));
} else if (len == 1) {
val &= ~(0xff << (8 * (off & 3)));
val |= *((uint8 *) buf) << (8 * (off & 3));
} else
ret = -1;
W_REG(reg, val);
done:
if (reg)
REG_UNMAP(reg);
return ret;
}
/*
* Functions for accessing translated SB configuration space
*/
static int
sb_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
{
pci_config_regs *cfg;
if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
return -1;
cfg = &sb_config_regs[dev];
ASSERT(ISALIGNED(off, len));
ASSERT(ISALIGNED(buf, len));
if (len == 4)
*((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
else if (len == 2)
*((uint16 *) buf) = ltoh16(*((uint16 *)((ulong) cfg + off)));
else if (len == 1)
*((uint8 *) buf) = *((uint8 *)((ulong) cfg + off));
else
return -1;
return 0;
}
static int
sb_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
{
uint coreidx, n;
void *regs;
sbconfig_t *sb;
pci_config_regs *cfg;
if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
return -1;
cfg = &sb_config_regs[dev];
ASSERT(ISALIGNED(off, len));
ASSERT(ISALIGNED(buf, len));
/* Emulate BAR sizing */
if (off >= OFFSETOF(pci_config_regs, base[0]) && off <= OFFSETOF(pci_config_regs, base[3]) &&
len == 4 && *((uint32 *) buf) == ~0) {
coreidx = sb_coreidx(sbh);
if ((regs = sb_setcoreidx(sbh, dev))) {
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
/* Highest numbered address match register */
n = (R_REG(&sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
if (off == OFFSETOF(pci_config_regs, base[0]))
cfg->base[0] = ~(sb_size(R_REG(&sb->sbadmatch0)) - 1);
else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
cfg->base[1] = ~(sb_size(R_REG(&sb->sbadmatch1)) - 1);
else if (off == OFFSETOF(pci_config_regs, base[2]) && n >= 2)
cfg->base[2] = ~(sb_size(R_REG(&sb->sbadmatch2)) - 1);
else if (off == OFFSETOF(pci_config_regs, base[3]) && n >= 3)
cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);
}
sb_setcoreidx(sbh, coreidx);
return 0;
}
if (len == 4)
*((uint32 *)((ulong) cfg + off)) = htol32(*((uint32 *) buf));
else if (len == 2)
*((uint16 *)((ulong) cfg + off)) = htol16(*((uint16 *) buf));
else if (len == 1)
*((uint8 *)((ulong) cfg + off)) = *((uint8 *) buf);
else
return -1;
return 0;
}
int
sbpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
{
if (bus == 0)
return sb_read_config(sbh, bus, dev, func, off, buf, len);
else
return extpci_read_config(sbh, bus, dev, func, off, buf, len);
}
int
sbpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
{
if (bus == 0)
return sb_write_config(sbh, bus, dev, func, off, buf, len);
else
return extpci_write_config(sbh, bus, dev, func, off, buf, len);
}
void
sbpci_ban(uint16 core)
{
if (pci_banned < ARRAYSIZE(pci_ban))
pci_ban[pci_banned++] = core;
}
//#define CT4712_WR 1 /* Workaround for 4712 */
int __init
sbpci_init(void *sbh)
{
uint chip, chiprev, chippkg, coreidx, host, i;
uint32 boardflags;
sbpciregs_t *pci;
sbconfig_t *sb;
pci_config_regs *cfg;
void *regs;
char varname[8];
int CT4712_WR;
uint wlidx = 0;
uint16 vendor, core;
uint8 class, subclass, progif;
uint32 val;
uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
chip = sb_chip(sbh);
chiprev = sb_chiprev(sbh);
chippkg = sb_chippkg(sbh);
coreidx = sb_coreidx(sbh);
if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0)))
return -1;
sb_core_reset(sbh, 0);
/* In some board, */
if(nvram_match("boardtype", "bcm94710dev"))
CT4712_WR = 0;
else
CT4712_WR = 1;
boardflags = (uint32) getintvar(NULL, "boardflags");
if ((chip == BCM4310_DEVICE_ID) && (chiprev == 0))
pci_disabled = TRUE;
/*
* The 200-pin BCM4712 package does not bond out PCI. Even when
* PCI is bonded out, some boards may leave the pins
* floating.
*/
if (((chip == BCM4712_DEVICE_ID) && (chippkg == BCM4712SMALL_PKG_ID)) ||
(boardflags & BFL_NOPCI) || CT4712_WR)
pci_disabled = TRUE;
/*
* If the PCI core should not be touched (disabled, not bonded
* out, or pins floating), do not even attempt to access core
* registers. Otherwise, try to determine if it is in host
* mode.
*/
if (pci_disabled)
host = 0;
else
host = !BUSPROBE(val, &pci->control);
if (!host) {
/* Disable PCI interrupts in client mode */
sb = (sbconfig_t *)((ulong) pci + SBCONFIGOFF);
W_REG(&sb->sbintvec, 0);
/* Disable the PCI bridge in client mode */
sbpci_ban(SB_PCI);
printf("PCI: Disabled\n");
} else {
/* Reset the external PCI bus and enable the clock */
W_REG(&pci->control, 0x5); /* enable the tristate drivers */
W_REG(&pci->control, 0xd); /* enable the PCI clock */
OSL_DELAY(150); /* delay > 100 us */
W_REG(&pci->control, 0xf); /* deassert PCI reset */
W_REG(&pci->arbcontrol, PCI_INT_ARB); /* use internal arbiter */
OSL_DELAY(1); /* delay 1 us */
/* Enable CardBusMode */
cardbus = nvram_match("cardbus", "1");
if (cardbus) {
printf("PCI: Enabling CardBus\n");
/* GPIO 1 resets the CardBus device on bcm94710ap */
sb_gpioout(sbh, 1, 1);
sb_gpioouten(sbh, 1, 1);
W_REG(&pci->sprom[0], R_REG(&pci->sprom[0]) | 0x400);
}
/* 64 MB I/O access window */
W_REG(&pci->sbtopci0, SBTOPCI_IO);
/* 64 MB configuration access window */
W_REG(&pci->sbtopci1, SBTOPCI_CFG0);
/* 1 GB memory access window */
W_REG(&pci->sbtopci2, SBTOPCI_MEM | SB_PCI_DMA);
/* Enable PCI bridge BAR0 prefetch and burst */
val = 6;
sbpci_write_config(sbh, 1, 0, 0, PCI_CFG_CMD, &val, sizeof(val));
/* Enable PCI interrupts */
W_REG(&pci->intmask, PCI_INTA);
}
/* Scan the SB bus */
bzero(sb_config_regs, sizeof(sb_config_regs));
for (cfg = sb_config_regs; cfg < &sb_config_regs[SB_MAXCORES]; cfg++) {
cfg->vendor = 0xffff;
if (!(regs = sb_setcoreidx(sbh, cfg - sb_config_regs)))
continue;
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
/* Read ID register and parse vendor and core */
val = R_REG(&sb->sbidhigh);
vendor = (val & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT;
core = (val & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
progif = 0;
/* Check if this core is banned */
for (i = 0; i < pci_banned; i++)
if (core == pci_ban[i])
break;
if (i < pci_banned)
continue;
/* Known vendor translations */
switch (vendor) {
case SB_VEND_BCM:
vendor = VENDOR_BROADCOM;
break;
}
/* Determine class based on known core codes */
switch (core) {
case SB_ILINE20:
class = PCI_CLASS_NET;
subclass = PCI_NET_ETHER;
core = BCM47XX_ILINE_ID;
break;
case SB_ILINE100:
class = PCI_CLASS_NET;
subclass = PCI_NET_ETHER;
core = BCM4610_ILINE_ID;
break;
case SB_ENET:
class = PCI_CLASS_NET;
subclass = PCI_NET_ETHER;
core = BCM47XX_ENET_ID;
break;
case SB_SDRAM:
case SB_MEMC:
class = PCI_CLASS_MEMORY;
subclass = PCI_MEMORY_RAM;
break;
case SB_PCI:
class = PCI_CLASS_BRIDGE;
subclass = PCI_BRIDGE_PCI;
break;
case SB_MIPS:
case SB_MIPS33:
class = PCI_CLASS_CPU;
subclass = PCI_CPU_MIPS;
break;
case SB_CODEC:
class = PCI_CLASS_COMM;
subclass = PCI_COMM_MODEM;
core = BCM47XX_V90_ID;
break;
case SB_USB:
class = PCI_CLASS_SERIAL;
subclass = PCI_SERIAL_USB;
progif = 0x10; /* OHCI */
core = BCM47XX_USB_ID;
break;
case SB_USB11H:
class = PCI_CLASS_SERIAL;
subclass = PCI_SERIAL_USB;
progif = 0x10; /* OHCI */
core = BCM47XX_USBH_ID;
break;
case SB_USB11D:
class = PCI_CLASS_SERIAL;
subclass = PCI_SERIAL_USB;
core = BCM47XX_USBD_ID;
break;
case SB_IPSEC:
class = PCI_CLASS_CRYPT;
subclass = PCI_CRYPT_NETWORK;
core = BCM47XX_IPSEC_ID;
break;
case SB_EXTIF:
case SB_CC:
class = PCI_CLASS_MEMORY;
subclass = PCI_MEMORY_FLASH;
break;
case SB_D11:
class = PCI_CLASS_NET;
subclass = PCI_NET_OTHER;
/* Let an nvram variable override this */
sprintf(varname, "wl%did", wlidx);
wlidx++;
if ((core = getintvar(NULL, varname)) == 0) {
if (chip == BCM4712_DEVICE_ID) {
if (chippkg == BCM4712SMALL_PKG_ID)
core = BCM4306_D11G_ID;
else
core = BCM4306_D11DUAL_ID;
} else {
/* 4310 */
core = BCM4310_D11B_ID;
}
}
break;
default:
class = subclass = progif = 0xff;
break;
}
/* Supported translations */
cfg->vendor = htol16(vendor);
cfg->device = htol16(core);
cfg->rev_id = chiprev;
cfg->prog_if = progif;
cfg->sub_class = subclass;
cfg->base_class = class;
cfg->base[0] = htol32(sb_base(R_REG(&sb->sbadmatch0)));
cfg->base[1] = htol32(sb_base(R_REG(&sb->sbadmatch1)));
cfg->base[2] = htol32(sb_base(R_REG(&sb->sbadmatch2)));
cfg->base[3] = htol32(sb_base(R_REG(&sb->sbadmatch3)));
cfg->base[4] = 0;
cfg->base[5] = 0;
if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI)
cfg->header_type = PCI_HEADER_BRIDGE;
else
cfg->header_type = PCI_HEADER_NORMAL;
/* Save core interrupt flag */
cfg->int_pin = R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK;
/* Default to MIPS shared interrupt 0 */
cfg->int_line = 0;
/* MIPS sbipsflag maps core interrupt flags to interrupts 1 through 4 */
if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
(regs = sb_setcore(sbh, SB_MIPS33, 0))) {
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
val = R_REG(&sb->sbipsflag);
for (cfg->int_line = 1; cfg->int_line <= 4; cfg->int_line++) {
if (((val & sbips_int_mask[cfg->int_line]) >> sbips_int_shift[cfg->int_line]) == cfg->int_pin)
break;
}
if (cfg->int_line > 4)
cfg->int_line = 0;
}
/* Emulated core */
*((uint32 *) &cfg->sprom_control) = 0xffffffff;
}
sb_setcoreidx(sbh, coreidx);
return 0;
}
void
sbpci_check(void *sbh)
{
uint coreidx;
sbpciregs_t *pci;
uint32 sbtopci1;
uint32 buf[64], *ptr, i;
ulong pa;
volatile uint j;
coreidx = sb_coreidx(sbh);
pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
/* Clear the test array */
pa = (ulong) DMA_MAP(NULL, buf, sizeof(buf), DMA_RX, NULL);
ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
memset(ptr, 0, sizeof(buf));
/* Point PCI window 1 to memory */
sbtopci1 = R_REG(&pci->sbtopci1);
W_REG(&pci->sbtopci1, SBTOPCI_MEM | (pa & SBTOPCI1_MASK));
/* Fill the test array via PCI window 1 */
ptr = (uint32 *) REG_MAP(SB_PCI_CFG + (pa & ~SBTOPCI1_MASK), sizeof(buf));
for (i = 0; i < ARRAYSIZE(buf); i++) {
for (j = 0; j < 2; j++);
W_REG(&ptr[i], i);
}
REG_UNMAP(ptr);
/* Restore PCI window 1 */
W_REG(&pci->sbtopci1, sbtopci1);
/* Check the test array */
DMA_UNMAP(NULL, pa, sizeof(buf), DMA_RX, NULL);
ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
for (i = 0; i < ARRAYSIZE(buf); i++) {
if (ptr[i] != i)
break;
}
/* Change the clock if the test fails */
if (i < ARRAYSIZE(buf)) {
uint32 req, cur;
cur = sb_clock(sbh);
printf("PCI: Test failed at %d MHz\n", (cur + 500000) / 1000000);
for (req = 104000000; req < 176000000; req += 4000000) {
printf("PCI: Resetting to %d MHz\n", (req + 500000) / 1000000);
/* This will only reset if the clocks are valid and have changed */
sb_mips_setclock(sbh, req, 0, 0);
}
/* Should not reach here */
ASSERT(0);
}
sb_setcoreidx(sbh, coreidx);
}

View File

@ -0,0 +1,251 @@
/*
* Generic setup routines for Broadcom MIPS boards
*
* Copyright 2004, 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 <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/serialP.h>
#include <linux/ide.h>
#include <asm/bootinfo.h>
#include <asm/time.h>
#include <asm/reboot.h>
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#endif
#include <typedefs.h>
#include <bcmutils.h>
#include <bcmnvram.h>
#include <sbmips.h>
#include <sbutils.h>
#include <trxhdr.h>
extern void bcm947xx_time_init(void);
extern void bcm947xx_timer_setup(struct irqaction *irq);
#ifdef CONFIG_REMOTE_DEBUG
extern void set_debug_traps(void);
extern void rs_kgdb_hook(struct serial_state *);
extern void breakpoint(void);
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
extern struct ide_ops std_ide_ops;
#endif
/* Global SB handle */
void *bcm947xx_sbh = NULL;
spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED;
EXPORT_SYMBOL(bcm947xx_sbh);
EXPORT_SYMBOL(bcm947xx_sbh_lock);
/* Convenience */
#define sbh bcm947xx_sbh
#define sbh_lock bcm947xx_sbh_lock
/* Kernel command line */
char arcs_cmdline[CL_SIZE] __initdata = CONFIG_CMDLINE;
void
bcm947xx_machine_restart(char *command)
{
printk("Please stand by while rebooting the system...\n");
/* Set the watchdog timer to reset immediately */
__cli();
sb_watchdog(sbh, 1);
while (1);
}
void
bcm947xx_machine_halt(void)
{
printk("System halted\n");
/* Disable interrupts and watchdog and spin forever */
__cli();
sb_watchdog(sbh, 0);
while (1);
}
#ifdef CONFIG_SERIAL
static struct serial_struct rs = {
line: 0,
flags: ASYNC_BOOT_AUTOCONF,
io_type: SERIAL_IO_MEM,
};
static void __init
serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
{
rs.iomem_base = regs;
rs.irq = irq + 2;
rs.baud_base = baud_base / 16;
rs.iomem_reg_shift = reg_shift;
early_serial_setup(&rs);
rs.line++;
}
static void __init
serial_setup(void *sbh)
{
sb_serial_init(sbh, serial_add);
#ifdef CONFIG_REMOTE_DEBUG
/* Use the last port for kernel debugging */
if (rs.iomem_base)
rs_kgdb_hook(&rs);
#endif
}
#endif /* CONFIG_SERIAL */
void __init
brcm_setup(void)
{
char *value;
/* Get global SB handle */
sbh = sb_kattach();
/* Initialize clocks and interrupts */
sb_mips_init(sbh);
#ifdef CONFIG_SERIAL
/* Initialize UARTs */
serial_setup(sbh);
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
ide_ops = &std_ide_ops;
#endif
/* Override default command line arguments */
value = nvram_get("kernel_args");
if (value && strlen(value) && strncmp(value, "empty", 5))
strncpy(arcs_cmdline, value, sizeof(arcs_cmdline));
/* Generic setup */
_machine_restart = bcm947xx_machine_restart;
_machine_halt = bcm947xx_machine_halt;
_machine_power_off = bcm947xx_machine_halt;
board_time_init = bcm947xx_time_init;
board_timer_setup = bcm947xx_timer_setup;
}
const char *
get_system_type(void)
{
return "Broadcom BCM947XX";
}
void __init
bus_error_init(void)
{
}
#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition bcm947xx_parts[] = {
{ name: "pmon", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
{ name: "linux", offset: 0, size: 0, },
{ name: "rootfs", offset: 0, size: 0, },
{ name: "nvram", offset: 0, size: 0, },
{ name: "OpenWrt", offset: 0, size: 0, },
{ name: NULL, },
};
static int __init
find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
{
struct trx_header *trx;
unsigned char buf[512];
int off;
size_t len;
trx = (struct trx_header *) buf;
for (off = (256*1024); off < size; off += mtd->erasesize) {
memset(buf, 0xe5, sizeof(buf));
/*
* Read into buffer
*/
if (MTD_READ(mtd, off, sizeof(buf), &len, buf) ||
len != sizeof(buf))
continue;
/* found a TRX header */
if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
part->offset = le32_to_cpu(trx->offsets[1]);
part->size = le32_to_cpu(trx->len);
part->size -= part->offset;
part->offset += off;
goto done;
}
}
printk(KERN_NOTICE
"%s: Couldn't find root filesystem\n",
mtd->name);
return -1;
done:
return part->size;
}
struct mtd_partition * __init
init_mtd_partitions(struct mtd_info *mtd, size_t size)
{
/* boot loader */
bcm947xx_parts[0].offset=0;
bcm947xx_parts[0].size=256*1024;
/* nvram */
bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
bcm947xx_parts[3].size = size - bcm947xx_parts[3].offset;
/* Size linux (kernel and rootfs) */
bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
bcm947xx_parts[1].size = bcm947xx_parts[3].offset - bcm947xx_parts[1].offset;
/* Find and size rootfs */
if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
/* entirely jffs2 */
bcm947xx_parts[2].size = bcm947xx_parts[3].offset - bcm947xx_parts[2].offset;
bcm947xx_parts[4].name = NULL;
} else {
/* legacy setup */
/* calculate leftover flash, and assign it to the jffs2 partition */
bcm947xx_parts[4].offset = bcm947xx_parts[2].offset + bcm947xx_parts[2].size;
bcm947xx_parts[4].offset = ROUNDUP(bcm947xx_parts[4].offset, mtd->erasesize);
bcm947xx_parts[4].size = bcm947xx_parts[3].offset - bcm947xx_parts[4].offset;
}
return bcm947xx_parts;
}
EXPORT_SYMBOL(init_mtd_partitions);
#endif

View File

@ -0,0 +1,346 @@
/*
* Broadcom SiliconBackplane chipcommon serial flash interface
*
* Copyright 2004, 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 <bcmutils.h>
#include <osl.h>
#include <sbchipc.h>
#include <sflash.h>
/* Private global state */
static struct sflash sflash;
/* Issue a serial flash command */
static INLINE void
sflash_cmd(chipcregs_t *cc, uint opcode)
{
W_REG(&cc->flashcontrol, SFLASH_START | opcode);
while (R_REG(&cc->flashcontrol) & SFLASH_BUSY);
}
/* Initialize serial flash access */
struct sflash *
sflash_init(chipcregs_t *cc)
{
uint32 id, id2;
bzero(&sflash, sizeof(sflash));
sflash.type = R_REG(&cc->capabilities) & CAP_FLASH_MASK;
switch (sflash.type) {
case SFLASH_ST:
/* Probe for ST chips */
sflash_cmd(cc, SFLASH_ST_DP);
sflash_cmd(cc, SFLASH_ST_RES);
id = R_REG(&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 0xbf:
W_REG(&cc->flashaddress, 1);
sflash_cmd(cc, SFLASH_ST_RES);
id2 = R_REG(&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(cc, SFLASH_AT_STATUS);
id = R_REG(&cc->flashdata) & 0x3c;
switch (id) {
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;
}
/* Read len bytes starting at offset into buf. Returns number of bytes read. */
int
sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
{
int cnt;
uint32 *from, *to;
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;
from = (uint32 *)(CC_FLASH_BASE + offset);
to = (uint32 *)buf;
if (cnt < 4) {
bcopy(from, to, cnt);
return cnt;
}
while (cnt >= 4) {
*to++ = *from++;
cnt -= 4;
}
return (len - cnt);
}
/* Poll for command completion. Returns zero when complete. */
int
sflash_poll(chipcregs_t *cc, uint offset)
{
if (offset >= sflash.size)
return -22;
switch (sflash.type) {
case SFLASH_ST:
/* Check for ST Write In Progress bit */
sflash_cmd(cc, SFLASH_ST_RDSR);
return R_REG(&cc->flashdata) & SFLASH_ST_WIP;
case SFLASH_AT:
/* Check for Atmel Ready bit */
sflash_cmd(cc, SFLASH_AT_STATUS);
return !(R_REG(&cc->flashdata) & SFLASH_AT_READY);
}
return 0;
}
/* Write len bytes starting at offset into buf. Returns number of bytes
* written. Caller should poll for completion.
*/
int
sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
{
struct sflash *sfl;
int ret = 0;
uint32 page, byte, mask;
if (!len)
return 0;
if ((offset + len) > sflash.size)
return -22;
sfl = &sflash;
switch (sfl->type) {
case SFLASH_ST:
ret = 1;
/* Enable writes */
sflash_cmd(cc, SFLASH_ST_WREN);
W_REG(&cc->flashaddress, offset);
W_REG(&cc->flashdata, *buf);
/* Page program */
sflash_cmd(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(&cc->flashaddress, page);
sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
/* 250 us for AT45DB321B */
SPINWAIT(sflash_poll(cc, offset), 1000);
ASSERT(!sflash_poll(cc, offset));
}
/* Write into buffer 1 */
for (ret = 0; ret < len && byte < sfl->blocksize; ret++) {
W_REG(&cc->flashaddress, byte++);
W_REG(&cc->flashdata, *buf++);
sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
}
/* Write buffer 1 into main memory page */
W_REG(&cc->flashaddress, page);
sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
break;
}
return ret;
}
/* Erase a region. Returns number of bytes scheduled for erasure.
* Caller should poll for completion.
*/
int
sflash_erase(chipcregs_t *cc, uint offset)
{
struct sflash *sfl;
if (offset >= sflash.size)
return -22;
sfl = &sflash;
switch (sfl->type) {
case SFLASH_ST:
sflash_cmd(cc, SFLASH_ST_WREN);
W_REG(&cc->flashaddress, offset);
sflash_cmd(cc, SFLASH_ST_SE);
return sfl->blocksize;
case SFLASH_AT:
W_REG(&cc->flashaddress, offset << 1);
sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
return sfl->blocksize;
}
return 0;
}
/*
* writes the appropriate range of flash, a NULL buf simply erases
* the region of flash
*/
int
sflash_commit(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;
/* 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(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(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(cc, (uint) cur_offset)) < 0)
goto done;
while (sflash_poll(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(cc,
(uint) cur_offset,
(uint) cur_length,
(uchar *) cur_ptr)) < 0) {
ret = bytes;
goto done;
}
while (sflash_poll(cc, (uint) cur_offset));
cur_offset += bytes;
cur_length -= bytes;
cur_ptr += bytes;
}
offset += cur_retlen;
len -= cur_retlen;
buf += cur_retlen;
}
done:
if (block)
MFREE(block, blocksize);
return ret;
}

View File

@ -0,0 +1,117 @@
/*
* Copyright 2004, 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 <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/serial_reg.h>
#include <linux/interrupt.h>
#include <asm/addrspace.h>
#include <asm/io.h>
#include <asm/time.h>
#include <typedefs.h>
#include <bcmnvram.h>
#include <sbconfig.h>
#include <sbextif.h>
#include <sbutils.h>
#include <sbmips.h>
/* Global SB handle */
extern void *bcm947xx_sbh;
extern spinlock_t bcm947xx_sbh_lock;
/* Convenience */
#define sbh bcm947xx_sbh
#define sbh_lock bcm947xx_sbh_lock
extern int panic_timeout;
static int watchdog = 0;
static u8 *mcr = NULL;
void __init
bcm947xx_time_init(void)
{
unsigned int hz;
extifregs_t *eir;
/*
* Use deterministic values for initial counter interrupt
* so that calibrate delay avoids encountering a counter wrap.
*/
write_c0_count(0);
write_c0_compare(0xffff);
if (!(hz = sb_mips_clock(sbh)))
hz = 100000000;
printk("CPU: BCM%04x rev %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh),
(hz + 500000) / 1000000);
/* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
mips_hpt_frequency = hz / 2;
/* Set watchdog interval in ms */
watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0);
/* Please set the watchdog to 3 sec if it is less than 3 but not equal to 0 */
if (watchdog > 0) {
if (watchdog < 3000)
watchdog = 3000;
}
/* Set panic timeout in seconds */
panic_timeout = watchdog / 1000;
/* Setup blink */
if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
sbconfig_t *sb = (sbconfig_t *)((unsigned int) eir + SBCONFIGOFF);
unsigned long base = EXTIF_CFGIF_BASE(sb_base(readl(&sb->sbadmatch1)));
mcr = (u8 *) ioremap_nocache(base + UART_MCR, 1);
}
}
static void
bcm947xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/* Generic MIPS timer code */
timer_interrupt(irq, dev_id, regs);
/* Set the watchdog timer to reset after the specified number of ms */
if (watchdog > 0)
sb_watchdog(sbh, WATCHDOG_CLOCK / 1000 * watchdog);
#ifdef CONFIG_HWSIM
(*((int *)0xa0000f1c))++;
#else
/* Blink one of the LEDs in the external UART */
if (mcr && !(jiffies % (HZ/2)))
writeb(readb(mcr) ^ UART_MCR_OUT2, mcr);
#endif
}
static struct irqaction bcm947xx_timer_irqaction = {
bcm947xx_timer_interrupt,
SA_INTERRUPT,
0,
"timer",
NULL,
NULL
};
void __init
bcm947xx_timer_setup(struct irqaction *irq)
{
/* Enable the timer interrupt */
setup_irq(7, &bcm947xx_timer_irqaction);
}

View File

@ -0,0 +1,26 @@
#
# Makefile for generic Broadcom MIPS boards
#
# Copyright 2004, 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$
#
.S.s:
$(CPP) $(AFLAGS) $< -o $*.s
.S.o:
$(CC) $(AFLAGS) -c $< -o $*.o
O_TARGET := brcm.o
obj-y := int-handler.o irq.o
obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o
include $(TOPDIR)/Rules.make

View File

@ -0,0 +1,120 @@
/*
* Copyright 2004, 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.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
* This is the interface to the remote debugger stub.
*
*/
#include <linux/serialP.h>
#include <linux/serial_reg.h>
#include <asm/serial.h>
#include <asm/io.h>
static struct async_struct kdb_port_info = {0};
static __inline__ unsigned int serial_in(struct async_struct *info, int offset)
{
return readb((unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
}
static __inline__ void serial_out(struct async_struct *info, int offset,
int value)
{
writeb(value, (unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
}
void rs_kgdb_hook(struct serial_state *ser) {
int t;
kdb_port_info.state = ser;
kdb_port_info.magic = SERIAL_MAGIC;
kdb_port_info.port = ser->port;
kdb_port_info.flags = ser->flags;
kdb_port_info.iomem_base = ser->iomem_base;
kdb_port_info.iomem_reg_shift = ser->iomem_reg_shift;
kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS;
/*
* Clear all interrupts
*/
serial_in(&kdb_port_info, UART_LSR);
serial_in(&kdb_port_info, UART_RX);
serial_in(&kdb_port_info, UART_IIR);
serial_in(&kdb_port_info, UART_MSR);
/*
* Now, initialize the UART
*/
serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR);
/*
* and set the speed of the serial port
* (currently hardwired to 115200 8N1
*/
/* baud rate is fixed to 115200 (is this sufficient?)*/
t = kdb_port_info.state->baud_base / 115200;
/* set DLAB */
serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */
serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */
/* reset DLAB */
serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);
}
int putDebugChar(char c)
{
if (!kdb_port_info.state) { /* need to init device first */
return 0;
}
while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0)
;
serial_out(&kdb_port_info, UART_TX, c);
return 1;
}
char getDebugChar(void)
{
if (!kdb_port_info.state) { /* need to init device first */
return 0;
}
while (!(serial_in(&kdb_port_info, UART_LSR) & 1))
;
return(serial_in(&kdb_port_info, UART_RX));
}

View File

@ -0,0 +1,51 @@
/*
* Generic interrupt handler for Broadcom MIPS boards
*
* Copyright 2004, 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 <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Combined hardware interrupt (hw0)
* 3 Hardware
* 4 Hardware
* 5 Hardware
* 6 Hardware
* 7 R4k timer
*/
.text
.set noreorder
.set noat
.align 5
NESTED(brcmIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
.set noreorder
jal brcm_irq_dispatch
move a0, sp
j ret_from_irq
nop
END(brcmIRQ)

View File

@ -0,0 +1,130 @@
/*
* Generic interrupt control functions for Broadcom MIPS boards
*
* Copyright 2004, 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 <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/gdb-stub.h>
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
extern asmlinkage void brcmIRQ(void);
extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
void
brcm_irq_dispatch(struct pt_regs *regs)
{
u32 cause;
cause = read_c0_cause() &
read_c0_status() &
CAUSEF_IP;
#ifdef CONFIG_KERNPROF
change_c0_status(cause | 1, 1);
#else
clear_c0_status(cause);
#endif
if (cause & CAUSEF_IP7)
do_IRQ(7, regs);
if (cause & CAUSEF_IP2)
do_IRQ(2, regs);
if (cause & CAUSEF_IP3)
do_IRQ(3, regs);
if (cause & CAUSEF_IP4)
do_IRQ(4, regs);
if (cause & CAUSEF_IP5)
do_IRQ(5, regs);
if (cause & CAUSEF_IP6)
do_IRQ(6, regs);
}
static void
enable_brcm_irq(unsigned int irq)
{
if (irq < 8)
set_c0_status(1 << (irq + 8));
else
set_c0_status(IE_IRQ0);
}
static void
disable_brcm_irq(unsigned int irq)
{
if (irq < 8)
clear_c0_status(1 << (irq + 8));
else
clear_c0_status(IE_IRQ0);
}
static void
ack_brcm_irq(unsigned int irq)
{
/* Already done in brcm_irq_dispatch */
}
static unsigned int
startup_brcm_irq(unsigned int irq)
{
enable_brcm_irq(irq);
return 0; /* never anything pending */
}
static void
end_brcm_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_brcm_irq(irq);
}
static struct hw_interrupt_type brcm_irq_type = {
typename: "MIPS",
startup: startup_brcm_irq,
shutdown: disable_brcm_irq,
enable: enable_brcm_irq,
disable: disable_brcm_irq,
ack: ack_brcm_irq,
end: end_brcm_irq,
NULL
};
void __init
init_IRQ(void)
{
int i;
for (i = 0; i < NR_IRQS; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].handler = &brcm_irq_type;
}
set_except_vector(0, brcmIRQ);
change_c0_status(ST0_IM, ALLINTS);
#ifdef CONFIG_REMOTE_DEBUG
printk("Breaking into debugger...\n");
set_debug_traps();
breakpoint();
#endif
}

View File

@ -0,0 +1,855 @@
/*
* Common Flash Interface support:
* SST Standard Vendor Command Set (ID 0x0701)
*
* Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
*
* 2_by_8 routines added by Simon Munton
*
* This code is GPL
*
* $Id$
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
static int cfi_sststd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_sststd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_sststd_erase_onesize(struct mtd_info *, struct erase_info *);
static int cfi_sststd_erase_varsize(struct mtd_info *, struct erase_info *);
static void cfi_sststd_sync (struct mtd_info *);
static int cfi_sststd_suspend (struct mtd_info *);
static void cfi_sststd_resume (struct mtd_info *);
static void cfi_sststd_destroy(struct mtd_info *);
struct mtd_info *cfi_cmdset_0701(struct map_info *, int);
static struct mtd_info *cfi_sststd_setup (struct map_info *);
static struct mtd_chip_driver cfi_sststd_chipdrv = {
probe: NULL, /* Not usable directly */
destroy: cfi_sststd_destroy,
name: "cfi_cmdset_0701",
module: THIS_MODULE
};
struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
int ofs_factor = cfi->interleave * cfi->device_type;
int i;
__u8 major, minor;
__u32 base = cfi->chips[0].start;
if (cfi->cfi_mode==1){
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
major = cfi_read_query(map, base + (adr+3)*ofs_factor);
minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
printk(" SST Query Table v%c.%c at 0x%4.4X\n",
major, minor, adr);
cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL);
cfi->mfr = cfi_read_query(map, base);
cfi->id = cfi_read_query(map, base + ofs_factor);
cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
switch (cfi->device_type) {
case CFI_DEVICETYPE_X16:
cfi->addr_unlock1 = 0x5555;
cfi->addr_unlock2 = 0x2AAA;
break;
default:
printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0701 device type %d\n", cfi->device_type);
return NULL;
}
} /* CFI mode */
for (i=0; i< cfi->numchips; i++) {
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
}
map->fldrv = &cfi_sststd_chipdrv;
MOD_INC_USE_COUNT;
cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL);
return cfi_sststd_setup(map);
}
static struct mtd_info *cfi_sststd_setup(struct map_info *map)
{
struct cfi_private *cfi = map->fldrv_priv;
struct mtd_info *mtd;
unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
printk("number of %s chips: %d\n", (cfi->cfi_mode)?"JEDEC":"CFI",cfi->numchips);
if (!mtd) {
printk("Failed to allocate memory for MTD device\n");
kfree(cfi->cmdset_priv);
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;
/* Also select the correct geometry setup too */
mtd->size = devsize * cfi->numchips;
if (cfi->cfiq->NumEraseRegions == 1) {
/* No need to muck about with multiple erase sizes */
mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave;
} else {
unsigned long offset = 0;
int i,j;
mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
if (!mtd->eraseregions) {
printk("Failed to allocate memory for MTD erase region info\n");
kfree(cfi->cmdset_priv);
return NULL;
}
for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
unsigned long ernum, ersize;
ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
if (mtd->erasesize < ersize) {
mtd->erasesize = ersize;
}
for (j=0; j<cfi->numchips; j++) {
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
}
offset += (ersize * ernum);
}
// debug
for (i=0; i<mtd->numeraseregions;i++){
printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
i,mtd->eraseregions[i].offset,
mtd->eraseregions[i].erasesize,
mtd->eraseregions[i].numblocks);
}
}
switch (CFIDEV_BUSWIDTH)
{
case 1:
case 2:
case 4:
if (mtd->numeraseregions > 1)
mtd->erase = cfi_sststd_erase_varsize;
else
mtd->erase = cfi_sststd_erase_onesize;
mtd->read = cfi_sststd_read;
mtd->write = cfi_sststd_write;
break;
default:
printk("Unsupported buswidth\n");
kfree(mtd);
kfree(cfi->cmdset_priv);
return NULL;
break;
}
mtd->sync = cfi_sststd_sync;
mtd->suspend = cfi_sststd_suspend;
mtd->resume = cfi_sststd_resume;
mtd->flags = MTD_CAP_NORFLASH;
map->fldrv = &cfi_sststd_chipdrv;
mtd->name = map->name;
MOD_INC_USE_COUNT;
return mtd;
}
static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long timeo = jiffies + HZ;
retry:
cfi_spin_lock(chip->mutex);
if (chip->state != FL_READY){
printk("Waiting for chip to read, status = %d\n", chip->state);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
cfi_spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
timeo = jiffies + HZ;
goto retry;
}
adr += chip->start;
chip->state = FL_READY;
map->copy_from(map, buf, adr, len);
wake_up(&chip->wq);
cfi_spin_unlock(chip->mutex);
return 0;
}
static int cfi_sststd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
unsigned long ofs;
int chipnum;
int ret = 0;
/* ofs: offset within the first chip that the first read should start */
chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift);
*retlen = 0;
while (len) {
unsigned long thislen;
if (chipnum >= cfi->numchips)
break;
if ((len + ofs -1) >> cfi->chipshift)
thislen = (1<<cfi->chipshift) - ofs;
else
thislen = len;
ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
if (ret)
break;
*retlen += thislen;
len -= thislen;
buf += thislen;
ofs = 0;
chipnum++;
}
return ret;
}
static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
{
unsigned long timeo = jiffies + HZ;
unsigned int Last[4];
unsigned long Count = 0;
struct cfi_private *cfi = map->fldrv_priv;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
retry:
cfi_spin_lock(chip->mutex);
if (chip->state != FL_READY){
printk("Waiting for chip to write, status = %d\n", chip->state);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
cfi_spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
printk("Wake up to write:\n");
timeo = jiffies + HZ;
goto retry;
}
chip->state = FL_WRITING;
adr += chip->start;
ENABLE_VPP(map);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_write(map, datum, adr);
cfi_spin_unlock(chip->mutex);
cfi_udelay(chip->word_write_time);
cfi_spin_lock(chip->mutex);
Last[0] = cfi_read(map, adr);
// printk("Last[0] is %x\n", Last[0]);
Last[1] = cfi_read(map, adr);
// printk("Last[1] is %x\n", Last[1]);
Last[2] = cfi_read(map, adr);
// printk("Last[2] is %x\n", Last[2]);
for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){
cfi_spin_unlock(chip->mutex);
cfi_udelay(10);
cfi_spin_lock(chip->mutex);
Last[Count % 4] = cfi_read(map, adr);
// printk("Last[%d%%4] is %x\n", Count, Last[Count%4]);
}
if (Last[(Count - 1) % 4] != datum){
printk("Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum);
cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL);
DISABLE_VPP(map);
ret = -EIO;
}
DISABLE_VPP(map);
chip->state = FL_READY;
wake_up(&chip->wq);
cfi_spin_unlock(chip->mutex);
return ret;
}
static int cfi_sststd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
int ret = 0;
int chipnum;
unsigned long ofs, chipstart;
*retlen = 0;
if (!len)
return 0;
chipnum = to >> cfi->chipshift;
ofs = to - (chipnum << cfi->chipshift);
chipstart = cfi->chips[chipnum].start;
/* If it's not bus-aligned, do the first byte write */
if (ofs & (CFIDEV_BUSWIDTH-1)) {
unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
int i = ofs - bus_ofs;
int n = 0;
u_char tmp_buf[4];
__u32 datum;
map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
while (len && i < CFIDEV_BUSWIDTH)
tmp_buf[i++] = buf[n++], len--;
if (cfi_buswidth_is_2()) {
datum = *(__u16*)tmp_buf;
} else if (cfi_buswidth_is_4()) {
datum = *(__u32*)tmp_buf;
} else {
return -EINVAL; /* should never happen, but be safe */
}
ret = do_write_oneword(map, &cfi->chips[chipnum],
bus_ofs, datum, 0);
if (ret)
return ret;
ofs += n;
buf += n;
(*retlen) += n;
if (ofs >> cfi->chipshift) {
chipnum ++;
ofs = 0;
if (chipnum == cfi->numchips)
return 0;
}
}
/* We are now aligned, write as much as possible */
while(len >= CFIDEV_BUSWIDTH) {
__u32 datum;
if (cfi_buswidth_is_1()) {
datum = *(__u8*)buf;
} else if (cfi_buswidth_is_2()) {
datum = *(__u16*)buf;
} else if (cfi_buswidth_is_4()) {
datum = *(__u32*)buf;
} else {
return -EINVAL;
}
ret = do_write_oneword(map, &cfi->chips[chipnum],
ofs, datum, cfi->fast_prog);
if (ret) {
return ret;
}
ofs += CFIDEV_BUSWIDTH;
buf += CFIDEV_BUSWIDTH;
(*retlen) += CFIDEV_BUSWIDTH;
len -= CFIDEV_BUSWIDTH;
if (ofs >> cfi->chipshift) {
chipnum ++;
ofs = 0;
if (chipnum == cfi->numchips)
return 0;
chipstart = cfi->chips[chipnum].start;
}
}
if (len & (CFIDEV_BUSWIDTH-1)) {
int i = 0, n = 0;
u_char tmp_buf[4];
__u32 datum;
map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
while (len--)
tmp_buf[i++] = buf[n++];
if (cfi_buswidth_is_2()) {
datum = *(__u16*)tmp_buf;
} else if (cfi_buswidth_is_4()) {
datum = *(__u32*)tmp_buf;
} else {
return -EINVAL; /* should never happen, but be safe */
}
ret = do_write_oneword(map, &cfi->chips[chipnum],
ofs, datum, 0);
if (ret)
return ret;
(*retlen) += n;
}
return 0;
}
static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
{
unsigned int status;
unsigned long timeo = jiffies + HZ;
struct cfi_private *cfi = map->fldrv_priv;
unsigned int rdy_mask;
DECLARE_WAITQUEUE(wait, current);
retry:
cfi_spin_lock(chip->mutex);
if (chip->state != FL_READY){
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
cfi_spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
timeo = jiffies + HZ;
goto retry;
}
chip->state = FL_ERASING;
adr += chip->start;
ENABLE_VPP(map);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
cfi_write(map, CMD(0x30), adr);
timeo = jiffies + (HZ*20);
cfi_spin_unlock(chip->mutex);
schedule_timeout(HZ);
cfi_spin_lock(chip->mutex);
rdy_mask = CMD(0x80);
/* Once the state machine's known to be working I'll do that */
while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) {
static int z=0;
if (chip->state != FL_ERASING) {
/* Someone's suspended the erase. Sleep */
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
cfi_spin_unlock(chip->mutex);
printk("erase suspended. Sleeping\n");
schedule();
remove_wait_queue(&chip->wq, &wait);
timeo = jiffies + (HZ*2);
cfi_spin_lock(chip->mutex);
continue;
}
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
chip->state = FL_READY;
cfi_spin_unlock(chip->mutex);
printk("waiting for erase to complete timed out.");
DISABLE_VPP(map);
return -EIO;
}
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
z++;
if ( 0 && !(z % 100 ))
printk("chip not ready yet after erase. looping\n");
cfi_udelay(1);
cfi_spin_lock(chip->mutex);
continue;
}
/* Done and happy. */
DISABLE_VPP(map);
chip->state = FL_READY;
wake_up(&chip->wq);
cfi_spin_unlock(chip->mutex);
return 0;
}
static int cfi_sststd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
unsigned long adr, len;
int chipnum, ret = 0;
int i, first;
struct mtd_erase_region_info *regions = mtd->eraseregions;
if (instr->addr > mtd->size)
return -EINVAL;
if ((instr->len + instr->addr) > mtd->size)
return -EINVAL;
/* Check that both start and end of the requested erase are
* aligned with the erasesize at the appropriate addresses.
*/
i = 0;
/* Skip all erase regions which are ended before the start of
the requested erase. Actually, to save on the calculations,
we skip to the first erase region which starts after the
start of the requested erase, and then go back one.
*/
while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
i++;
i--;
/* OK, now i is pointing at the erase region in which this
erase request starts. Check the start of the requested
erase range is aligned with the erase size which is in
effect here.
*/
if (instr->addr & (regions[i].erasesize-1))
return -EINVAL;
/* Remember the erase region we start on */
first = i;
/* Next, check that the end of the requested erase is aligned
* with the erase region at that address.
*/
while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
i++;
/* As before, drop back one to point at the region in which
the address actually falls
*/
i--;
if ((instr->addr + instr->len) & (regions[i].erasesize-1))
return -EINVAL;
chipnum = instr->addr >> cfi->chipshift;
adr = instr->addr - (chipnum << cfi->chipshift);
len = instr->len;
i=first;
while(len) {
ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
if (ret)
return ret;
adr += regions[i].erasesize;
len -= regions[i].erasesize;
if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
i++;
if (adr >> cfi->chipshift) {
adr = 0;
chipnum++;
if (chipnum >= cfi->numchips)
break;
}
}
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
return 0;
}
static int cfi_sststd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
unsigned long adr, len;
int chipnum, ret = 0;
if (instr->addr & (mtd->erasesize - 1))
return -EINVAL;
if (instr->len & (mtd->erasesize -1))
return -EINVAL;
if ((instr->len + instr->addr) > mtd->size)
return -EINVAL;
chipnum = instr->addr >> cfi->chipshift;
adr = instr->addr - (chipnum << cfi->chipshift);
len = instr->len;
while(len) {
ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
if (ret)
return ret;
adr += mtd->erasesize;
len -= mtd->erasesize;
if (adr >> cfi->chipshift) {
adr = 0;
chipnum++;
if (chipnum >= cfi->numchips)
break;
}
}
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
return 0;
}
static void cfi_sststd_sync (struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
int i;
struct flchip *chip;
int ret = 0;
DECLARE_WAITQUEUE(wait, current);
for (i=0; !ret && i<cfi->numchips; i++) {
chip = &cfi->chips[i];
retry:
cfi_spin_lock(chip->mutex);
switch(chip->state) {
case FL_READY:
case FL_STATUS:
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
chip->oldstate = chip->state;
chip->state = FL_SYNCING;
/* No need to wake_up() on this state change -
* as the whole point is that nobody can do anything
* with the chip now anyway.
*/
case FL_SYNCING:
cfi_spin_unlock(chip->mutex);
break;
default:
/* Not an idle state */
add_wait_queue(&chip->wq, &wait);
cfi_spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
goto retry;
}
}
/* Unlock the chips again */
for (i--; i >=0; i--) {
chip = &cfi->chips[i];
cfi_spin_lock(chip->mutex);
if (chip->state == FL_SYNCING) {
chip->state = chip->oldstate;
wake_up(&chip->wq);
}
cfi_spin_unlock(chip->mutex);
}
}
static int cfi_sststd_suspend(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
int i;
struct flchip *chip;
int ret = 0;
//printk("suspend\n");
for (i=0; !ret && i<cfi->numchips; i++) {
chip = &cfi->chips[i];
cfi_spin_lock(chip->mutex);
switch(chip->state) {
case FL_READY:
case FL_STATUS:
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
chip->oldstate = chip->state;
chip->state = FL_PM_SUSPENDED;
/* No need to wake_up() on this state change -
* as the whole point is that nobody can do anything
* with the chip now anyway.
*/
case FL_PM_SUSPENDED:
break;
default:
ret = -EAGAIN;
break;
}
cfi_spin_unlock(chip->mutex);
}
/* Unlock the chips again */
if (ret) {
for (i--; i >=0; i--) {
chip = &cfi->chips[i];
cfi_spin_lock(chip->mutex);
if (chip->state == FL_PM_SUSPENDED) {
chip->state = chip->oldstate;
wake_up(&chip->wq);
}
cfi_spin_unlock(chip->mutex);
}
}
return ret;
}
static void cfi_sststd_resume(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
int i;
struct flchip *chip;
//printk("resume\n");
for (i=0; i<cfi->numchips; i++) {
chip = &cfi->chips[i];
cfi_spin_lock(chip->mutex);
if (chip->state == FL_PM_SUSPENDED) {
chip->state = FL_READY;
cfi_write(map, CMD(0xF0), chip->start);
wake_up(&chip->wq);
}
else
printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n");
cfi_spin_unlock(chip->mutex);
}
}
static void cfi_sststd_destroy(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
kfree(cfi->cmdset_priv);
kfree(cfi);
}
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define cfi_sststd_init init_module
#define cfi_sststd_exit cleanup_module
#endif
static char im_name[]="cfi_cmdset_0701";
mod_init_t cfi_sststd_init(void)
{
inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0701);
return 0;
}
mod_exit_t cfi_sststd_exit(void)
{
inter_module_unregister(im_name);
}
module_init(cfi_sststd_init);
module_exit(cfi_sststd_exit);

View File

@ -0,0 +1,283 @@
/*
* Broadcom SiliconBackplane chipcommon serial flash interface
*
* Copyright 2004, 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 <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/mtd/compatmac.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <typedefs.h>
#include <bcmdevs.h>
#include <bcmutils.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmnvram.h>
#include <sbconfig.h>
#include <sbchipc.h>
#include <sflash.h>
#ifdef CONFIG_MTD_PARTITIONS
extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
#endif
struct sflash_mtd {
chipcregs_t *cc;
struct semaphore lock;
struct mtd_info mtd;
struct mtd_erase_region_info region;
};
/* Private global state */
static struct sflash_mtd sflash;
static int
sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
{
int now = jiffies;
int ret = 0;
for (;;) {
if (!sflash_poll(sflash->cc, offset)) {
ret = 0;
break;
}
if (time_after(jiffies, now + timeout)) {
printk(KERN_ERR "sflash: timeout\n");
ret = -ETIMEDOUT;
break;
}
if (current->need_resched) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(timeout / 10);
} else
udelay(1);
}
return ret;
}
static int
sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
int bytes, ret = 0;
/* Check address range */
if (!len)
return 0;
if ((from + len) > mtd->size)
return -EINVAL;
down(&sflash->lock);
*retlen = 0;
while (len) {
if ((bytes = sflash_read(sflash->cc, (uint) from, len, buf)) < 0) {
ret = bytes;
break;
}
from += (loff_t) bytes;
len -= bytes;
buf += bytes;
*retlen += bytes;
}
up(&sflash->lock);
return ret;
}
static int
sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
{
struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
int bytes, ret = 0;
/* Check address range */
if (!len)
return 0;
if ((to + len) > mtd->size)
return -EINVAL;
down(&sflash->lock);
*retlen = 0;
while (len) {
if ((bytes = sflash_write(sflash->cc, (uint) to, len, buf)) < 0) {
ret = bytes;
break;
}
if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10)))
break;
to += (loff_t) bytes;
len -= bytes;
buf += bytes;
*retlen += bytes;
}
up(&sflash->lock);
return ret;
}
static int
sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
{
struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
int i, j, ret = 0;
unsigned int addr, len;
/* Check address range */
if (!erase->len)
return 0;
if ((erase->addr + erase->len) > mtd->size)
return -EINVAL;
addr = erase->addr;
len = erase->len;
down(&sflash->lock);
/* Ensure that requested region is aligned */
for (i = 0; i < mtd->numeraseregions; i++) {
for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
if (addr == mtd->eraseregions[i].offset + mtd->eraseregions[i].erasesize * j &&
len >= mtd->eraseregions[i].erasesize) {
if ((ret = sflash_erase(sflash->cc, addr)) < 0)
break;
if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ)))
break;
addr += mtd->eraseregions[i].erasesize;
len -= mtd->eraseregions[i].erasesize;
}
}
if (ret)
break;
}
up(&sflash->lock);
/* Set erase status */
if (ret)
erase->state = MTD_ERASE_FAILED;
else
erase->state = MTD_ERASE_DONE;
/* Call erase callback */
if (erase->callback)
erase->callback(erase);
return ret;
}
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define sflash_mtd_init init_module
#define sflash_mtd_exit cleanup_module
#endif
mod_init_t
sflash_mtd_init(void)
{
struct pci_dev *pdev;
int ret = 0;
struct sflash *info;
uint i;
#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *parts;
#endif
if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_CC, NULL))) {
printk(KERN_ERR "sflash: chipcommon not found\n");
return -ENODEV;
}
memset(&sflash, 0, sizeof(struct sflash_mtd));
init_MUTEX(&sflash.lock);
/* Map registers and flash base */
if (!(sflash.cc = ioremap_nocache(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0)))) {
printk(KERN_ERR "sflash: error mapping registers\n");
ret = -EIO;
goto fail;
}
/* Initialize serial flash access */
info = sflash_init(sflash.cc);
if (!info) {
printk(KERN_ERR "sflash: found no supported devices\n");
ret = -ENODEV;
goto fail;
}
/* Setup region info */
sflash.region.offset = 0;
sflash.region.erasesize = info->blocksize;
sflash.region.numblocks = info->numblocks;
if (sflash.region.erasesize > sflash.mtd.erasesize)
sflash.mtd.erasesize = sflash.region.erasesize;
sflash.mtd.size = info->size;
sflash.mtd.numeraseregions = 1;
/* Register with MTD */
sflash.mtd.name = "sflash";
sflash.mtd.type = MTD_NORFLASH;
sflash.mtd.flags = MTD_CAP_NORFLASH;
sflash.mtd.eraseregions = &sflash.region;
sflash.mtd.module = THIS_MODULE;
sflash.mtd.erase = sflash_mtd_erase;
sflash.mtd.read = sflash_mtd_read;
sflash.mtd.write = sflash_mtd_write;
sflash.mtd.priv = &sflash;
#ifdef CONFIG_MTD_PARTITIONS
parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size);
for (i = 0; parts[i].name; i++);
ret = add_mtd_partitions(&sflash.mtd, parts, i);
#else
ret = add_mtd_device(&sflash.mtd);
#endif
if (ret) {
printk(KERN_ERR "sflash: add_mtd failed\n");
goto fail;
}
return 0;
fail:
if (sflash.cc)
iounmap((void *) sflash.cc);
return ret;
}
mod_exit_t
sflash_mtd_exit(void)
{
#ifdef CONFIG_MTD_PARTITIONS
del_mtd_partitions(&sflash.mtd);
#else
del_mtd_device(&sflash.mtd);
#endif
iounmap((void *) sflash.cc);
}
module_init(sflash_mtd_init);
module_exit(sflash_mtd_exit);

View File

@ -0,0 +1,236 @@
/*
* Flash mapping for BCM947XX boards
*
* Copyright 2004, 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 <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
#include <typedefs.h>
#include <bcmnvram.h>
#include <bcmutils.h>
#include <sbconfig.h>
#include <sbchipc.h>
#include <sbutils.h>
#include <trxhdr.h>
/* Global SB handle */
extern void *bcm947xx_sbh;
extern spinlock_t bcm947xx_sbh_lock;
/* Convenience */
#define sbh bcm947xx_sbh
#define sbh_lock bcm947xx_sbh_lock
#ifdef CONFIG_MTD_PARTITIONS
extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
#endif
#define WINDOW_ADDR 0x1fc00000
#define WINDOW_SIZE 0x400000
#define BUSWIDTH 2
/* e.g., flash=2M or flash=4M */
static int flash = 0;
MODULE_PARM(flash, "i");
static int __init
bcm947xx_setup(char *str)
{
flash = memparse(str, &str);
return 1;
}
__setup("flash=", bcm947xx_setup);
static struct mtd_info *bcm947xx_mtd;
__u8 bcm947xx_map_read8(struct map_info *map, unsigned long ofs)
{
if (map->map_priv_2 == 1)
return __raw_readb(map->map_priv_1 + ofs);
u16 val = __raw_readw(map->map_priv_1 + (ofs & ~1));
if (ofs & 1)
return ((val >> 8) & 0xff);
else
return (val & 0xff);
}
__u16 bcm947xx_map_read16(struct map_info *map, unsigned long ofs)
{
return __raw_readw(map->map_priv_1 + ofs);
}
__u32 bcm947xx_map_read32(struct map_info *map, unsigned long ofs)
{
return __raw_readl(map->map_priv_1 + ofs);
}
void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
if (len==1) {
memcpy_fromio(to, map->map_priv_1 + from, len);
} else {
int i;
u16 *dest = (u16 *) to;
u16 *src = (u16 *) (map->map_priv_1 + from);
for (i = 0; i < (len / 2); i++) {
dest[i] = src[i];
}
if (len & 1)
*((u8 *)dest+len-1) = src[i] & 0xff;
}
}
void bcm947xx_map_write8(struct map_info *map, __u8 d, unsigned long adr)
{
__raw_writeb(d, map->map_priv_1 + adr);
mb();
}
void bcm947xx_map_write16(struct map_info *map, __u16 d, unsigned long adr)
{
__raw_writew(d, map->map_priv_1 + adr);
mb();
}
void bcm947xx_map_write32(struct map_info *map, __u32 d, unsigned long adr)
{
__raw_writel(d, map->map_priv_1 + adr);
mb();
}
void bcm947xx_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
memcpy_toio(map->map_priv_1 + to, from, len);
}
struct map_info bcm947xx_map = {
name: "Physically mapped flash",
size: WINDOW_SIZE,
buswidth: BUSWIDTH,
read8: bcm947xx_map_read8,
read16: bcm947xx_map_read16,
read32: bcm947xx_map_read32,
copy_from: bcm947xx_map_copy_from,
write8: bcm947xx_map_write8,
write16: bcm947xx_map_write16,
write32: bcm947xx_map_write32,
copy_to: bcm947xx_map_copy_to
};
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define init_bcm947xx_map init_module
#define cleanup_bcm947xx_map cleanup_module
#endif
mod_init_t init_bcm947xx_map(void)
{
ulong flags;
uint coreidx;
chipcregs_t *cc;
uint32 fltype;
uint window_addr = 0, window_size = 0;
size_t size;
int ret = 0;
#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *parts;
int i;
#endif
spin_lock_irqsave(&sbh_lock, flags);
coreidx = sb_coreidx(sbh);
/* Check strapping option if chipcommon exists */
if ((cc = sb_setcore(sbh, SB_CC, 0))) {
fltype = readl(&cc->capabilities) & CAP_FLASH_MASK;
if (fltype == PFLASH) {
bcm947xx_map.map_priv_2 = 1;
window_addr = 0x1c000000;
bcm947xx_map.size = window_size = 32 * 1024 * 1024;
if ((readl(&cc->flash_config) & CC_CFG_DS) == 0)
bcm947xx_map.buswidth = 1;
}
} else {
fltype = PFLASH;
bcm947xx_map.map_priv_2 = 0;
window_addr = WINDOW_ADDR;
window_size = WINDOW_SIZE;
}
sb_setcoreidx(sbh, coreidx);
spin_unlock_irqrestore(&sbh_lock, flags);
if (fltype != PFLASH) {
printk(KERN_ERR "pflash: found no supported devices\n");
ret = -ENODEV;
goto fail;
}
bcm947xx_map.map_priv_1 = (unsigned long) ioremap(window_addr, window_size);
if (!bcm947xx_map.map_priv_1) {
printk(KERN_ERR "pflash: ioremap failed\n");
ret = -EIO;
goto fail;
}
if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
printk(KERN_ERR "pflash: cfi_probe failed\n");
ret = -ENXIO;
goto fail;
}
bcm947xx_mtd->module = THIS_MODULE;
/* Allow size override for testing */
size = flash ? : bcm947xx_mtd->size;
printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr);
#ifdef CONFIG_MTD_PARTITIONS
parts = init_mtd_partitions(bcm947xx_mtd, size);
for (i = 0; parts[i].name; i++);
ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
if (ret) {
printk(KERN_ERR "pflash: add_mtd_partitions failed\n");
goto fail;
}
#endif
return 0;
fail:
if (bcm947xx_mtd)
map_destroy(bcm947xx_mtd);
if (bcm947xx_map.map_priv_1)
iounmap((void *) bcm947xx_map.map_priv_1);
bcm947xx_map.map_priv_1 = 0;
return ret;
}
mod_exit_t cleanup_bcm947xx_map(void)
{
#ifdef CONFIG_MTD_PARTITIONS
del_mtd_partitions(bcm947xx_mtd);
#endif
map_destroy(bcm947xx_mtd);
iounmap((void *) bcm947xx_map.map_priv_1);
bcm947xx_map.map_priv_1 = 0;
}
module_init(init_bcm947xx_map);
module_exit(cleanup_bcm947xx_map);

View File

@ -0,0 +1,9 @@
O_TARGET := diag.o
MAC_OBJS := diag_led.o
export-objs :=
obj-y := $(MAC_OBJS)
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make

View File

@ -0,0 +1,210 @@
// replacement diag module
// (c) 2004 openwrt
// mbm at alt dot org
//
// initial release 2004/03/28
//
// 2004/08/26 asus & buffalo support added
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sysctl.h>
#include <asm/io.h>
#include <typedefs.h>
#include <bcm4710.h>
#include <sbutils.h>
extern char * nvram_get(const char *name);
static void *sbh;
// v2.x - - - - -
#define DIAG_GPIO (1<<1)
#define DMZ_GPIO (1<<7)
static void set_gpio(uint32 mask, uint32 value) {
sb_gpiocontrol(sbh,mask,0);
sb_gpioouten(sbh,mask,mask);
sb_gpioout(sbh,mask,value);
}
static void v2_set_diag(u8 state) {
set_gpio(DIAG_GPIO,state);
}
static void v2_set_dmz(u8 state) {
set_gpio(DMZ_GPIO,state);
}
// v1.x - - - - -
#define LED_DIAG 0x13
#define LED_DMZ 0x12
static void v1_set_diag(u8 state) {
if (!state) {
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG)=0xFF;
} else {
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG);
}
}
static void v1_set_dmz(u8 state) {
if (!state) {
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ)=0xFF;
} else {
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ);
}
}
// - - - - -
static void ignore(u8 ignored) {};
// - - - - -
#define BIT_DMZ 0x01
#define BIT_DIAG 0x04
void (*set_diag)(u8 state);
void (*set_dmz)(u8 state);
static unsigned int diag = 0;
static void diag_change()
{
//printk(KERN_INFO "led -> %02x\n",diag);
set_diag(0xFF); // off
set_dmz(0xFF); // off
if(diag & BIT_DIAG)
set_diag(0x00); // on
if(diag & BIT_DMZ)
set_dmz(0x00); // on
}
static int proc_diag(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
int r;
r = proc_dointvec(table, write, filp, buffer, lenp);
if (write && !r) {
diag_change();
}
return r;
}
// - - - - -
static unsigned char reset_gpio = 0;
static unsigned char reset_polarity = 0;
static unsigned int reset = 0;
static int proc_reset(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
if (reset_gpio) {
sb_gpiocontrol(sbh,reset_gpio,reset_gpio);
sb_gpioouten(sbh,reset_gpio,0);
reset=!(sb_gpioin(sbh)&reset_gpio);
if (reset_polarity) reset=!reset;
} else {
reset=0;
}
return proc_dointvec(table, write, filp, buffer, lenp);
}
// - - - - -
static struct ctl_table_header *diag_sysctl_header;
static ctl_table sys_diag[] = {
{
ctl_name: 2000,
procname: "diag",
data: &diag,
maxlen: sizeof(diag),
mode: 0644,
proc_handler: proc_diag
},
{
ctl_name: 2001,
procname: "reset",
data: &reset,
maxlen: sizeof(reset),
mode: 0444,
proc_handler: proc_reset
},
{ 0 }
};
static int __init diag_init()
{
char *buf;
u32 board_type;
sbh = sb_kattach();
sb_gpiosetcore(sbh);
board_type = sb_boardtype(sbh);
printk(KERN_INFO "diag boardtype: %08x\n",board_type);
set_diag=ignore;
set_dmz=ignore;
if ((board_type & 0xf00) == 0x400) {
board_type=1;
buf=nvram_get("boardtype")?:"";
if (!strcmp(buf,"bcm94710dev")) {
buf=nvram_get("boardnum")?:"";
if (!strcmp(buf,"42")) {
// wrt54g v1.x
set_diag=v1_set_diag;
set_dmz=v1_set_dmz;
reset_gpio=(1<<6);
reset_polarity=0;
} else if (!strcmp(buf,"asusX")) {
//asus wl-500g
//no leds
reset_gpio=(1<<6);
reset_polarity=1;
}
} else if (!strcmp(buf,"bcm94710ap")) {
buf=nvram_get("boardnum")?:"";
if (!strcmp(buf,"42")) {
// buffalo
set_dmz=v2_set_dmz;
reset_gpio=(1<<4);
reset_polarity=1;
} else if (!strcmp(buf,"44")) {
//dell truemobile
set_dmz=v2_set_dmz;
reset_gpio=(1<<0);
reset_polarity=0;
}
}
} else {
board_type=2;
set_diag=v2_set_diag;
set_dmz=v2_set_dmz;
reset_gpio=(1<<6);
reset_polarity=0;
buf=nvram_get("boardnum")?:"";
if (!strcmp(buf,"44")) {
set_diag=ignore;
set_dmz=ignore;
reset_gpio=(1<<5);
reset_polarity=0;
}
}
printk(KERN_INFO "using v%d hardware\n",board_type);
diag_sysctl_header = register_sysctl_table(sys_diag, 0);
diag_change();
return 0;
}
static void __exit diag_exit()
{
unregister_sysctl_table(diag_sysctl_header);
}
module_init(diag_init);
module_exit(diag_exit);

View File

@ -0,0 +1,34 @@
#
# Makefile for the Broadcom et driver
#
# Copyright 2004, 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$
#
O_TARGET := et.o
ET_OBJS := et_linux.o etc.o
ifeq ($(CONFIG_ET_47XX),y)
ET_OBJS += etc47xx.o etc_robo.o etc_adm.o
EXTRA_CFLAGS += -DBCM47XX_CHOPS
endif
ifeq ($(CONFIG_ET_4413),y)
ET_OBJS += etc4413.o
EXTRA_CFLAGS += -DBCM4413_CHOPS
endif
export-objs :=
obj-y := $(ET_OBJS)
obj-m := $(O_TARGET)
EXTRA_CFLAGS += -DDMA
include $(TOPDIR)/Rules.make

View File

@ -0,0 +1,35 @@
#
# Broadcom Home Networking Division (HND) driver configuration
#
# Copyright 2004, 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.
#
mainmenu_option next_comment
comment 'Broadcom HND network devices'
tristate 'Broadcom HND network device support' CONFIG_HND $CONFIG_PCI
if [ "$CONFIG_HND" != "n" ]; then
dep_tristate ' Broadcom InsideLine HPNA support' CONFIG_IL $CONFIG_HND
if [ "$CONFIG_IL" != "n" ]; then
bool ' Broadcom BCM42xx support' CONFIG_IL_42XX
bool ' Broadcom BCM47xx support' CONFIG_IL_47XX
int ' LARQ buffer allocation (0 = tiny, 2 = huge)' CONFIG_LARQ_BUF 0
fi
dep_tristate ' Broadcom 10/100 Ethernet support' CONFIG_ET $CONFIG_HND
if [ "$CONFIG_ET" != "n" ]; then
bool ' Broadcom BCM4413 support' CONFIG_ET_4413
bool ' Broadcom BCM47xx support' CONFIG_ET_47XX
fi
dep_tristate ' Broadcom BCM43xx 802.11 Wireless support' CONFIG_WL $CONFIG_HND
if [ "$CONFIG_WL" != "n" ]; then
bool ' Access Point Mode Supported' CONFIG_WL_AP
bool ' STA Mode Supported' CONFIG_WL_STA
bool ' OID Interface Supported' CONFIG_WL_OID
fi
fi
endmenu

View File

@ -0,0 +1,30 @@
#
# Makefile for Broadcom Home Networking Division (HND) shared driver code
#
# Copyright 2004, 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$
#
O_TARGET := hnd.o
HND_OBJS := bcmutils.o hnddma.o linux_osl.o sbutils.o bcmsrom.o
ifneq ($(CONFIG_BCM947XX),y)
HND_OBJS += nvramstubs.o
endif
export-objs := shared_ksyms.o
obj-y := shared_ksyms.o $(HND_OBJS)
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
shared_ksyms.c: shared_ksyms.sh $(HND_OBJS)
sh -e $< $(HND_OBJS) > $@

View File

@ -0,0 +1,711 @@
/*
* Misc useful routines to access NIC SROM
*
* Copyright 2004, 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 <osl.h>
#include <bcmutils.h>
#include <bcmsrom.h>
#include <bcmdevs.h>
#include <bcmendian.h>
#include <sbpcmcia.h>
#include <pcicfg.h>
#include <sbutils.h>
#include <proto/ethernet.h> /* for sprom content groking */
#define VARS_MAX 4096 /* should be reduced */
static int initvars_srom_pci(void *curmap, char **vars, int *count);
static int initvars_cis_pcmcia(void *sbh, void *curmap, void *osh, char **vars, int *count);
static int sprom_cmd_pcmcia(void *osh, uint8 cmd);
static int sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data);
static int sprom_write_pcmcia(void *osh, uint16 addr, uint16 data);
static int sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc);
/*
* Initialize the vars from the right source for this platform.
* Return 0 on success, nonzero on error.
*/
int
srom_var_init(void *sbh, uint bus, void *curmap, void *osh, char **vars, int *count)
{
if (vars == NULL)
return (0);
switch (bus) {
case SB_BUS:
/* These two could be asserts ... */
*vars = NULL;
*count = 0;
return(0);
case PCI_BUS:
ASSERT(curmap); /* can not be NULL */
return(initvars_srom_pci(curmap, vars, count));
case PCMCIA_BUS:
return(initvars_cis_pcmcia(sbh, curmap, osh, vars, count));
default:
ASSERT(0);
}
return (-1);
}
/* support only 16-bit word read from srom */
int
srom_read(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
{
void *srom;
uint i, off, nw;
/* check input - 16-bit access only */
if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
return 1;
if (bus == PCI_BUS) {
if (!curmap)
return 1;
srom = (void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
if (sprom_read_pci(srom, byteoff, buf, nbytes, FALSE))
return 1;
} else if (bus == PCMCIA_BUS) {
off = byteoff / 2;
nw = nbytes / 2;
for (i = 0; i < nw; i++) {
if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i)))
return 1;
}
} else {
return 1;
}
return 0;
}
/* support only 16-bit word write into srom */
int
srom_write(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
{
uint16 *srom;
uint i, off, nw, crc_range;
uint16 image[SPROM_SIZE], *p;
uint8 crc;
volatile uint32 val32;
/* check input - 16-bit access only */
if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
return 1;
crc_range = ((bus == PCMCIA_BUS) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2;
/* if changes made inside crc cover range */
if (byteoff < crc_range) {
nw = (((byteoff + nbytes) > crc_range) ? byteoff + nbytes : crc_range) / 2;
/* read data including entire first 64 words from srom */
if (srom_read(bus, curmap, osh, 0, nw * 2, image))
return 1;
/* make changes */
bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
/* calculate crc */
htol16_buf(image, crc_range);
crc = ~crc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
ltoh16_buf(image, crc_range);
image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
p = image;
off = 0;
} else {
p = buf;
off = byteoff / 2;
nw = nbytes / 2;
}
if (bus == PCI_BUS) {
srom = (uint16*)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
/* enable writes to the SPROM */
val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
val32 |= SPROM_WRITEEN;
OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
bcm_mdelay(500);
/* write srom */
for (i = 0; i < nw; i++) {
W_REG(&srom[off + i], p[i]);
bcm_mdelay(20);
}
/* disable writes to the SPROM */
OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN);
} else if (bus == PCMCIA_BUS) {
/* enable writes to the SPROM */
if (sprom_cmd_pcmcia(osh, SROM_WEN))
return 1;
bcm_mdelay(500);
/* write srom */
for (i = 0; i < nw; i++) {
sprom_write_pcmcia(osh, (uint16)(off + i), p[i]);
bcm_mdelay(20);
}
/* disable writes to the SPROM */
if (sprom_cmd_pcmcia(osh, SROM_WDS))
return 1;
} else {
return 1;
}
bcm_mdelay(500);
return 0;
}
int
srom_parsecis(uint8 *cis, char **vars, int *count)
{
char eabuf[32];
char *vp, *base;
uint8 tup, tlen, sromrev = 1;
int i, j;
uint varsize;
bool ag_init = FALSE;
uint16 w;
ASSERT(vars);
ASSERT(count);
base = vp = MALLOC(VARS_MAX);
ASSERT(vp);
i = 0;
do {
tup = cis[i++];
tlen = cis[i++];
if ((i + tlen) >= CIS_SIZE)
break;
switch (tup) {
case CISTPL_MANFID:
vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]);
vp++;
vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]);
vp++;
break;
case CISTPL_FUNCE:
if (cis[i] == LAN_NID) {
ASSERT(cis[i + 1] == ETHER_ADDR_LEN);
bcm_ether_ntoa((uchar*)&cis[i + 2], eabuf);
vp += sprintf(vp, "il0macaddr=%s", eabuf);
vp++;
}
break;
case CISTPL_CFTABLE:
vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]);
vp++;
break;
case CISTPL_BRCM_HNBU:
switch (cis[i]) {
case HNBU_CHIPID:
vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) + cis[i + 1]);
vp++;
vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) + cis[i + 3]);
vp++;
if (tlen == 7) {
vp += sprintf(vp, "chiprev=%d", (cis[i + 6] << 8) + cis[i + 5]);
vp++;
}
break;
case HNBU_BOARDREV:
vp += sprintf(vp, "boardrev=%d", cis[i + 1]);
vp++;
break;
case HNBU_AA:
vp += sprintf(vp, "aa0=%d", cis[i + 1]);
vp++;
break;
case HNBU_AG:
vp += sprintf(vp, "ag0=%d", cis[i + 1]);
vp++;
ag_init = TRUE;
break;
case HNBU_CC:
vp += sprintf(vp, "cc=%d", cis[i + 1]);
vp++;
break;
case HNBU_PAPARMS:
vp += sprintf(vp, "pa0maxpwr=%d", cis[i + tlen - 1]);
vp++;
if (tlen == 9) {
/* New version */
for (j = 0; j < 3; j++) {
vp += sprintf(vp, "pa0b%d=%d", j,
(cis[i + (j * 2) + 2] << 8) + cis[i + (j * 2) + 1]);
vp++;
}
vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]);
vp++;
}
break;
case HNBU_OEM:
vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
cis[i + 1], cis[i + 2], cis[i + 3], cis[i + 4],
cis[i + 5], cis[i + 6], cis[i + 7], cis[i + 8]);
vp++;
break;
case HNBU_BOARDFLAGS:
w = (cis[i + 2] << 8) + cis[i + 1];
if (w == 0xffff) w = 0;
vp += sprintf(vp, "boardflags=%d", w);
vp++;
break;
case HNBU_LED:
if (cis[i + 1] != 0xff) {
vp += sprintf(vp, "wl0gpio0=%d", cis[i + 1]);
vp++;
}
if (cis[i + 2] != 0xff) {
vp += sprintf(vp, "wl0gpio1=%d", cis[i + 2]);
vp++;
}
if (cis[i + 3] != 0xff) {
vp += sprintf(vp, "wl0gpio2=%d", cis[i + 3]);
vp++;
}
if (cis[i + 4] != 0xff) {
vp += sprintf(vp, "wl0gpio3=%d", cis[i + 4]);
vp++;
}
break;
}
break;
}
i += tlen;
} while (tup != 0xff);
/* Set the srom version */
vp += sprintf(vp, "sromrev=%d", sromrev);
vp++;
/* For now just set boardflags2 to zero */
vp += sprintf(vp, "boardflags2=0");
vp++;
/* if there is no antenna gain field, set default */
if (ag_init == FALSE) {
vp += sprintf(vp, "ag0=%d", 0xff);
vp++;
}
/* final nullbyte terminator */
*vp++ = '\0';
varsize = (uint)vp - (uint)base;
ASSERT(varsize < VARS_MAX);
if (varsize == VARS_MAX) {
*vars = base;
} else {
vp = MALLOC(varsize);
ASSERT(vp);
bcopy(base, vp, varsize);
MFREE(base, VARS_MAX);
*vars = vp;
}
*count = varsize;
return (0);
}
/* set PCMCIA sprom command register */
static int
sprom_cmd_pcmcia(void *osh, uint8 cmd)
{
uint8 status;
uint wait_cnt = 1000;
/* write sprom command register */
OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1);
/* wait status */
while (wait_cnt--) {
OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1);
if (status & SROM_DONE)
return 0;
}
return 1;
}
/* read a word from the PCMCIA srom */
static int
sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data)
{
uint8 addr_l, addr_h, data_l, data_h;
addr_l = (uint8)((addr * 2) & 0xff);
addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
/* set address */
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
/* do read */
if (sprom_cmd_pcmcia(osh, SROM_READ))
return 1;
/* read data */
OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1);
OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1);
*data = (data_h << 8) | data_l;
return 0;
}
/* write a word to the PCMCIA srom */
static int
sprom_write_pcmcia(void *osh, uint16 addr, uint16 data)
{
uint8 addr_l, addr_h, data_l, data_h;
addr_l = (uint8)((addr * 2) & 0xff);
addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
data_l = (uint8)(data & 0xff);
data_h = (uint8)((data >> 8) & 0xff);
/* set address */
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
/* write data */
OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1);
OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1);
/* do write */
return sprom_cmd_pcmcia(osh, SROM_WRITE);
}
/*
* Read in and validate sprom.
* Return 0 on success, nonzero on error.
*/
static int
sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc)
{
int off, nw;
uint8 chk8;
int i;
off = byteoff / 2;
nw = ROUNDUP(nbytes, 2) / 2;
/* read the sprom */
for (i = 0; i < nw; i++)
buf[i] = R_REG(&sprom[off + i]);
if (check_crc) {
/* fixup the endianness so crc8 will pass */
htol16_buf(buf, nw * 2);
if ((chk8 = crc8((uchar*)buf, nbytes, CRC8_INIT_VALUE)) != CRC8_GOOD_VALUE)
return (1);
/* now correct the endianness of the byte array */
ltoh16_buf(buf, nw * 2);
}
return (0);
}
/*
* Initialize nonvolatile variable table from sprom.
* Return 0 on success, nonzero on error.
*/
static int
initvars_srom_pci(void *curmap, char **vars, int *count)
{
uint16 w, b[64];
uint8 sromrev;
struct ether_addr ea;
char eabuf[32];
uint32 bfl;
int c, woff, i;
char *vp, *base;
if (sprom_read_pci((void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, sizeof (b), TRUE))
return (-1);
/* top word of sprom contains version and crc8 */
sromrev = b[63] & 0xff;
if ((sromrev != 1) && (sromrev != 2)) {
return (-2);
}
ASSERT(vars);
ASSERT(count);
base = vp = MALLOC(VARS_MAX);
ASSERT(vp);
vp += sprintf(vp, "sromrev=%d", sromrev);
vp++;
if (sromrev >= 2) {
/* New section takes over the 4th hardware function space */
/* Word 29 is max power 11a high/low */
w = b[29];
vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff);
vp++;
vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff);
vp++;
/* Words 30-32 set the 11alow pa settings,
* 33-35 are the 11ahigh ones.
*/
for (i = 0; i < 3; i++) {
vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]);
vp++;
vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]);
vp++;
}
w = b[59];
if (w == 0)
vp += sprintf(vp, "ccode=");
else
vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
vp++;
}
/* parameter section of sprom starts at byte offset 72 */
woff = 72/2;
/* first 6 bytes are il0macaddr */
ea.octet[0] = (b[woff] >> 8) & 0xff;
ea.octet[1] = b[woff] & 0xff;
ea.octet[2] = (b[woff+1] >> 8) & 0xff;
ea.octet[3] = b[woff+1] & 0xff;
ea.octet[4] = (b[woff+2] >> 8) & 0xff;
ea.octet[5] = b[woff+2] & 0xff;
woff += ETHER_ADDR_LEN/2 ;
bcm_ether_ntoa((uchar*)&ea, eabuf);
vp += sprintf(vp, "il0macaddr=%s", eabuf);
vp++;
/* next 6 bytes are et0macaddr */
ea.octet[0] = (b[woff] >> 8) & 0xff;
ea.octet[1] = b[woff] & 0xff;
ea.octet[2] = (b[woff+1] >> 8) & 0xff;
ea.octet[3] = b[woff+1] & 0xff;
ea.octet[4] = (b[woff+2] >> 8) & 0xff;
ea.octet[5] = b[woff+2] & 0xff;
woff += ETHER_ADDR_LEN/2 ;
bcm_ether_ntoa((uchar*)&ea, eabuf);
vp += sprintf(vp, "et0macaddr=%s", eabuf);
vp++;
/* next 6 bytes are et1macaddr */
ea.octet[0] = (b[woff] >> 8) & 0xff;
ea.octet[1] = b[woff] & 0xff;
ea.octet[2] = (b[woff+1] >> 8) & 0xff;
ea.octet[3] = b[woff+1] & 0xff;
ea.octet[4] = (b[woff+2] >> 8) & 0xff;
ea.octet[5] = b[woff+2] & 0xff;
woff += ETHER_ADDR_LEN/2 ;
bcm_ether_ntoa((uchar*)&ea, eabuf);
vp += sprintf(vp, "et1macaddr=%s", eabuf);
vp++;
/*
* Enet phy settings one or two singles or a dual
* Bits 4-0 : MII address for enet0 (0x1f for not there)
* Bits 9-5 : MII address for enet1 (0x1f for not there)
* Bit 14 : Mdio for enet0
* Bit 15 : Mdio for enet1
*/
w = b[woff];
vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f));
vp++;
vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f));
vp++;
vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1));
vp++;
vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1));
vp++;
/* Word 46 has board rev, antennas 0/1 & Country code/control */
w = b[46];
vp += sprintf(vp, "boardrev=%d", w & 0xff);
vp++;
if (sromrev > 1)
vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf);
else
vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf);
vp++;
vp += sprintf(vp, "aa0=%d", (w >> 12) & 0x3);
vp++;
vp += sprintf(vp, "aa1=%d", (w >> 14) & 0x3);
vp++;
/* Words 47-49 set the (wl) pa settings */
woff = 47;
for (i = 0; i < 3; i++) {
vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]);
vp++;
vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]);
vp++;
}
/*
* Words 50-51 set the customer-configured wl led behavior.
* 8 bits/gpio pin. High bit: activehi=0, activelo=1;
* LED behavior values defined in wlioctl.h .
*/
w = b[50];
if ((w != 0) && (w != 0xffff)) {
/* gpio0 */
vp += sprintf(vp, "wl0gpio0=%d", (w & 0xff));
vp++;
/* gpio1 */
vp += sprintf(vp, "wl0gpio1=%d", (w >> 8) & 0xff);
vp++;
}
w = b[51];
if ((w != 0) && (w != 0xffff)) {
/* gpio2 */
vp += sprintf(vp, "wl0gpio2=%d", w & 0xff);
vp++;
/* gpio3 */
vp += sprintf(vp, "wl0gpio3=%d", (w >> 8) & 0xff);
vp++;
}
/* Word 52 is max power 0/1 */
w = b[52];
vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff);
vp++;
vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff);
vp++;
/* Word 56 is idle tssi target 0/1 */
w = b[56];
vp += sprintf(vp, "pa0itssit=%d", w & 0xff);
vp++;
vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff);
vp++;
/* Word 57 is boardflags, if not programmed make it zero */
bfl = (uint32)b[57];
if (bfl == 0xffff) bfl = 0;
if (sromrev > 1) {
/* Word 28 is boardflags2 */
bfl |= (uint32)b[28] << 16;
}
vp += sprintf(vp, "boardflags=%d", bfl);
vp++;
/* Word 58 is antenna gain 0/1 */
w = b[58];
vp += sprintf(vp, "ag0=%d", w & 0xff);
vp++;
vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
vp++;
if (sromrev == 1) {
/* set the oem string */
vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
((b[59] >> 8) & 0xff), (b[59] & 0xff),
((b[60] >> 8) & 0xff), (b[60] & 0xff),
((b[61] >> 8) & 0xff), (b[61] & 0xff),
((b[62] >> 8) & 0xff), (b[62] & 0xff));
vp++;
} else {
if (sromrev >= 1){
/* Word 60 OFDM tx power offset from CCK level */
/* OFDM Power Offset - opo */
w = b[60] & 0xff;
if (w == 0xff)
w = 16;
vp += sprintf(vp, "opo=%d", w);
vp++;
}
}
/* final nullbyte terminator */
*vp++ = '\0';
c = vp - base;
ASSERT(c <= VARS_MAX);
if (c == VARS_MAX) {
*vars = base;
} else {
vp = MALLOC(c);
ASSERT(vp);
bcopy(base, vp, c);
MFREE(base, VARS_MAX);
*vars = vp;
}
*count = c;
return (0);
}
/*
* Read the cis and call parsecis to initialize the vars.
* Return 0 on success, nonzero on error.
*/
static int
initvars_cis_pcmcia(void *sbh, void *curmap, void *osh, char **vars, int *count)
{
uint8 *cis = NULL;
int rc;
uint data_sz;
data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
if ((cis = MALLOC(data_sz)) == NULL)
return (-1);
if (sb_pcmciarev(sbh) == 1) {
if (srom_read(PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) {
MFREE(cis, data_sz);
return (-1);
}
/* fix up endianess for 16-bit data vs 8-bit parsing */
ltoh16_buf((uint16 *)cis, data_sz);
} else
OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz);
rc = srom_parsecis(cis, vars, count);
MFREE(cis, data_sz);
return (rc);
}

View File

@ -0,0 +1,803 @@
/*
* Misc useful OS-independent routines.
*
* Copyright 2004, 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 <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <bcmnvram.h>
unsigned char bcm_ctype[] = {
_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
_BCM_C,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C,_BCM_C, /* 8-15 */
_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
_BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
_BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
_BCM_P,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U, /* 64-71 */
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
_BCM_P,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L, /* 96-103 */
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 160-175 */
_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 176-191 */
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 192-207 */
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_L, /* 208-223 */
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 224-239 */
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L /* 240-255 */
};
uchar
bcm_toupper(uchar c)
{
if (bcm_islower(c))
c -= 'a'-'A';
return (c);
}
ulong
bcm_strtoul(char *cp, char **endp, uint base)
{
ulong result, value;
bool minus;
minus = FALSE;
while (bcm_isspace(*cp))
cp++;
if (cp[0] == '+')
cp++;
else if (cp[0] == '-') {
minus = TRUE;
cp++;
}
if (base == 0) {
if (cp[0] == '0') {
if ((cp[1] == 'x') || (cp[1] == 'X')) {
base = 16;
cp = &cp[2];
} else {
base = 8;
cp = &cp[1];
}
} else
base = 10;
} else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
cp = &cp[2];
}
result = 0;
while (bcm_isxdigit(*cp) &&
(value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
result = result*base + value;
cp++;
}
if (minus)
result = (ulong)(result * -1);
if (endp)
*endp = (char *)cp;
return (result);
}
uint
bcm_atoi(char *s)
{
uint n;
n = 0;
while (bcm_isdigit(*s))
n = (n * 10) + *s++ - '0';
return (n);
}
void
deadbeef(char *p, uint len)
{
static uchar meat[] = { 0xde, 0xad, 0xbe, 0xef };
while (len-- > 0) {
*p = meat[((uint)p) & 3];
p++;
}
}
/* pretty hex print a contiguous buffer */
void
prhex(char *msg, uchar *buf, uint nbytes)
{
char line[256];
char* p;
uint i;
if (msg && (msg[0] != '\0'))
printf("%s: ", msg);
p = line;
for (i = 0; i < nbytes; i++) {
if (i % 16 == 0) {
p += sprintf(p, "%04d: ", i); /* line prefix */
}
p += sprintf(p, "%02x ", buf[i]);
if (i % 16 == 15) {
printf("%s\n", line); /* flush line */
p = line;
}
}
/* flush last partial line */
if (p != line)
printf("%s\n", line);
}
/* pretty hex print a pkt buffer chain */
void
prpkt(char *msg, void *drv, void *p0)
{
void *p;
if (msg && (msg[0] != '\0'))
printf("%s: ", msg);
for (p = p0; p; p = PKTNEXT(drv, p))
prhex(NULL, PKTDATA(drv, p), PKTLEN(drv, p));
}
/* copy a pkt buffer chain into a buffer */
uint
pktcopy(void *drv, void *p, uint offset, int len, uchar *buf)
{
uint n, ret = 0;
if (len < 0)
len = 4096; /* "infinite" */
/* skip 'offset' bytes */
for (; p && offset; p = PKTNEXT(drv, p)) {
if (offset < (uint)PKTLEN(drv, p))
break;
offset -= PKTLEN(drv, p);
}
if (!p)
return 0;
/* copy the data */
for (; p && len; p = PKTNEXT(drv, p)) {
n = MIN((uint)PKTLEN(drv, p) - offset, (uint)len);
bcopy(PKTDATA(drv, p) + offset, buf, n);
buf += n;
len -= n;
ret += n;
offset = 0;
}
return ret;
}
/* return total length of buffer chain */
uint
pkttotlen(void *drv, void *p)
{
uint total;
total = 0;
for (; p; p = PKTNEXT(drv, p))
total += PKTLEN(drv, p);
return (total);
}
uchar*
bcm_ether_ntoa(char *ea, char *buf)
{
sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",
(uchar)ea[0]&0xff, (uchar)ea[1]&0xff, (uchar)ea[2]&0xff,
(uchar)ea[3]&0xff, (uchar)ea[4]&0xff, (uchar)ea[5]&0xff);
return (buf);
}
/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
int
bcm_ether_atoe(char *p, char *ea)
{
int i = 0;
for (;;) {
ea[i++] = (char) bcm_strtoul(p, &p, 16);
if (!*p++ || i == 6)
break;
}
return (i == 6);
}
/*
* Advance from the current 1-byte tag/1-byte length/variable-length value
* triple, to the next, returning a pointer to the next.
*/
bcm_tlv_t *
bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
{
int len;
/* validate current elt */
if (*buflen < 2) {
return NULL;
}
len = elt->len;
/* validate remaining buflen */
if (*buflen >= (2 + len + 2)) {
elt = (bcm_tlv_t*)(elt->data + len);
*buflen -= (2 + len);
} else {
elt = NULL;
}
return elt;
}
/*
* Traverse a string of 1-byte tag/1-byte length/variable-length value
* triples, returning a pointer to the substring whose first element
* matches tag. Stop parsing when we see an element whose ID is greater
* than the target key.
*/
bcm_tlv_t *
bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
{
bcm_tlv_t *elt;
int totlen;
elt = (bcm_tlv_t*)buf;
totlen = buflen;
/* find tagged parameter */
while (totlen >= 2) {
uint id = elt->id;
int len = elt->len;
/* Punt if we start seeing IDs > than target key */
if (id > key)
return(NULL);
/* validate remaining totlen */
if ((id == key) && (totlen >= (len + 2)))
return (elt);
elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
totlen -= (len + 2);
}
return NULL;
}
/*
* Traverse a string of 1-byte tag/1-byte length/variable-length value
* triples, returning a pointer to the substring whose first element
* matches tag
*/
bcm_tlv_t *
bcm_parse_tlvs(void *buf, int buflen, uint key)
{
bcm_tlv_t *elt;
int totlen;
elt = (bcm_tlv_t*)buf;
totlen = buflen;
/* find tagged parameter */
while (totlen >= 2) {
int len = elt->len;
/* validate remaining totlen */
if ((elt->id == key) && (totlen >= (len + 2)))
return (elt);
elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
totlen -= (len + 2);
}
return NULL;
}
void
pktq_init(struct pktq *q, uint maxlen, bool priority)
{
q->head = q->tail = NULL;
q->priority = priority;
q->maxlen = maxlen;
q->len = 0;
}
bool
pktenq(struct pktq *q, void *p, bool lifo)
{
void *next, *prev;
/* Queue is full */
if (q->len >= q->maxlen)
return FALSE;
/* Queueing chains not allowed */
ASSERT(PKTLINK(p) == NULL);
/* Queue is empty */
if (q->tail == NULL) {
ASSERT(q->head == NULL);
q->head = q->tail = p;
}
/* Insert at head or tail */
else if (q->priority == FALSE) {
/* Insert at head (LIFO) */
if (lifo) {
PKTSETLINK(p, q->head);
q->head = p;
}
/* Insert at tail (FIFO) */
else {
ASSERT(PKTLINK(q->tail) == NULL);
PKTSETLINK(q->tail, p);
PKTSETLINK(p, NULL);
q->tail = p;
}
}
/* Insert by priority */
else {
ASSERT(q->head);
ASSERT(q->tail);
/* Shortcut to insertion at tail */
if (PKTPRIO(p) < PKTPRIO(q->tail) ||
(!lifo && PKTPRIO(p) <= PKTPRIO(q->tail))) {
prev = q->tail;
next = NULL;
}
/* Insert at head or in the middle */
else {
prev = NULL;
next = q->head;
}
/* Walk the queue */
for (; next; prev = next, next = PKTLINK(next)) {
/* Priority queue invariant */
ASSERT(!prev || PKTPRIO(prev) >= PKTPRIO(next));
/* Insert at head of string of packets of same priority (LIFO) */
if (lifo) {
if (PKTPRIO(p) >= PKTPRIO(next))
break;
}
/* Insert at tail of string of packets of same priority (FIFO) */
else {
if (PKTPRIO(p) > PKTPRIO(next))
break;
}
}
/* Insert at tail */
if (next == NULL) {
ASSERT(PKTLINK(q->tail) == NULL);
PKTSETLINK(q->tail, p);
PKTSETLINK(p, NULL);
q->tail = p;
}
/* Insert in the middle */
else if (prev) {
PKTSETLINK(prev, p);
PKTSETLINK(p, next);
}
/* Insert at head */
else {
PKTSETLINK(p, q->head);
q->head = p;
}
}
/* List invariants after insertion */
ASSERT(q->head);
ASSERT(PKTLINK(q->tail) == NULL);
q->len++;
return TRUE;
}
void*
pktdeq(struct pktq *q)
{
void *p;
if ((p = q->head)) {
ASSERT(q->tail);
q->head = PKTLINK(p);
PKTSETLINK(p, NULL);
q->len--;
if (q->head == NULL)
q->tail = NULL;
}
else {
ASSERT(q->tail == NULL);
}
return (p);
}
/*******************************************************************************
* crc8
*
* Computes a crc8 over the input data using the polynomial:
*
* x^8 + x^7 +x^6 + x^4 + x^2 + 1
*
* The caller provides the initial value (either CRC8_INIT_VALUE
* or the previous returned value) to allow for processing of
* discontiguous blocks of data. When generating the CRC the
* caller is responsible for complementing the final return value
* and inserting it into the byte stream. When checking, a final
* return value of CRC8_GOOD_VALUE indicates a valid CRC.
*
* Reference: Dallas Semiconductor Application Note 27
* Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
* ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
* ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
*
******************************************************************************/
static uint8 crc8_table[256] = {
0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
};
/*
* Search the name=value vars for a specific one and return its value.
* Returns NULL if not found.
*/
char*
getvar(char *vars, char *name)
{
char *s;
int len;
len = strlen(name);
/* first look in vars[] */
for (s = vars; s && *s; ) {
if ((bcmp(s, name, len) == 0) && (s[len] == '='))
return (&s[len+1]);
while (*s++)
;
}
/* then query nvram */
return (nvram_get(name));
}
/*
* Search the vars for a specific one and return its value as
* an integer. Returns 0 if not found.
*/
int
getintvar(char *vars, char *name)
{
char *val;
if ((val = getvar(vars, name)) == NULL)
return (0);
return (bcm_strtoul(val, NULL, 0));
}
/* return pointer to location of substring 'needle' in 'haystack' */
char*
bcmstrstr(char *haystack, char *needle)
{
int len, nlen;
int i;
if ((haystack == NULL) || (needle == NULL))
return (haystack);
nlen = strlen(needle);
len = strlen(haystack) - nlen + 1;
for (i = 0; i < len; i++)
if (bcmp(needle, &haystack[i], nlen) == 0)
return (&haystack[i]);
return (NULL);
}
void
bcm_mdelay(uint ms)
{
uint i;
for (i = 0; i < ms; i++) {
OSL_DELAY(1000);
}
}
#define CRC_INNER_LOOP(n, c, x) \
(c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
uint8
crc8(
uint8 *pdata, /* pointer to array of data to process */
uint nbytes, /* number of input data bytes to process */
uint8 crc /* either CRC8_INIT_VALUE or previous return value */
)
{
/* hard code the crc loop instead of using CRC_INNER_LOOP macro
* to avoid the undefined and unnecessary (uint8 >> 8) operation. */
while (nbytes-- > 0)
crc = crc8_table[(crc ^ *pdata++) & 0xff];
return crc;
}
/*******************************************************************************
* crc16
*
* Computes a crc16 over the input data using the polynomial:
*
* x^16 + x^12 +x^5 + 1
*
* The caller provides the initial value (either CRC16_INIT_VALUE
* or the previous returned value) to allow for processing of
* discontiguous blocks of data. When generating the CRC the
* caller is responsible for complementing the final return value
* and inserting it into the byte stream. When checking, a final
* return value of CRC16_GOOD_VALUE indicates a valid CRC.
*
* Reference: Dallas Semiconductor Application Note 27
* Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
* ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
* ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
*
******************************************************************************/
static uint16 crc16_table[256] = {
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
};
uint16
crc16(
uint8 *pdata, /* pointer to array of data to process */
uint nbytes, /* number of input data bytes to process */
uint16 crc /* either CRC16_INIT_VALUE or previous return value */
)
{
while (nbytes-- > 0)
CRC_INNER_LOOP(16, crc, *pdata++);
return crc;
}
static uint32 crc32_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
uint32
crc32(
uint8 *pdata, /* pointer to array of data to process */
uint nbytes, /* number of input data bytes to process */
uint32 crc /* either CRC32_INIT_VALUE or previous return value */
)
{
uint8 *pend;
#ifdef __mips__
uint8 tmp[4];
ulong *tptr = (ulong *)tmp;
/* in case the beginning of the buffer isn't aligned */
pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
nbytes -= (pend - pdata);
while (pdata < pend)
CRC_INNER_LOOP(32, crc, *pdata++);
/* handle bulk of data as 32-bit words */
pend = pdata + (nbytes & 0xfffffffc);
while (pdata < pend) {
*tptr = *((ulong *)pdata)++;
CRC_INNER_LOOP(32, crc, tmp[0]);
CRC_INNER_LOOP(32, crc, tmp[1]);
CRC_INNER_LOOP(32, crc, tmp[2]);
CRC_INNER_LOOP(32, crc, tmp[3]);
}
/* 1-3 bytes at end of buffer */
pend = pdata + (nbytes & 0x03);
while (pdata < pend)
CRC_INNER_LOOP(32, crc, *pdata++);
#else
pend = pdata + nbytes;
while (pdata < pend)
CRC_INNER_LOOP(32, crc, *pdata++);
#endif
return crc;
}
#ifdef notdef
#define CLEN 1499
#define CBUFSIZ (CLEN+4)
#define CNBUFS 5
void testcrc32(void)
{
uint j,k,l;
uint8 *buf;
uint len[CNBUFS];
uint32 crcr;
uint32 crc32tv[CNBUFS] =
{0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
/* step through all possible alignments */
for (l=0;l<=4;l++) {
for (j=0; j<CNBUFS; j++) {
len[j] = CLEN;
for (k=0; k<len[j]; k++)
*(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
}
for (j=0; j<CNBUFS; j++) {
crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
ASSERT(crcr == crc32tv[j]);
}
}
MFREE(buf, CBUFSIZ*CNBUFS);
return;
}
#endif

View File

@ -0,0 +1,841 @@
/*
* Generic Broadcom Home Networking Division (HND) DMA module.
* This supports the following chips: BCM42xx, 44xx, 47xx .
*
* Copyright 2004, 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 <osl.h>
#include <bcmendian.h>
#include <bcmutils.h>
struct dma_info; /* forward declaration */
#define di_t struct dma_info
#include <hnddma.h>
/* debug/trace */
#define DMA_ERROR(args)
#define DMA_TRACE(args)
/* default dma message level(if input msg_level pointer is null in dma_attach()) */
static uint dma_msg_level = 0;
#define MAXNAMEL 8
#define MAXDD (DMAMAXRINGSZ / sizeof (dmadd_t))
/* dma engine software state */
typedef struct dma_info {
hnddma_t hnddma; /* exported structure */
uint *msg_level; /* message level pointer */
char name[MAXNAMEL]; /* callers name for diag msgs */
void *drv; /* driver handle */
void *dev; /* device handle */
dmaregs_t *regs; /* dma engine registers */
dmadd_t *txd; /* pointer to chip-specific tx descriptor ring */
uint txin; /* index of next descriptor to reclaim */
uint txout; /* index of next descriptor to post */
uint txavail; /* # free tx descriptors */
void *txp[MAXDD]; /* parallel array of pointers to packets */
ulong txdpa; /* physical address of descriptor ring */
uint txdalign; /* #bytes added to alloc'd mem to align txd */
dmadd_t *rxd; /* pointer to chip-specific rx descriptor ring */
uint rxin; /* index of next descriptor to reclaim */
uint rxout; /* index of next descriptor to post */
void *rxp[MAXDD]; /* parallel array of pointers to packets */
ulong rxdpa; /* physical address of descriptor ring */
uint rxdalign; /* #bytes added to alloc'd mem to align rxd */
/* tunables */
uint ntxd; /* # tx descriptors */
uint nrxd; /* # rx descriptors */
uint rxbufsize; /* rx buffer size in bytes */
uint nrxpost; /* # rx buffers to keep posted */
uint rxoffset; /* rxcontrol offset */
uint ddoffset; /* add to get dma address of descriptor ring */
uint dataoffset; /* add to get dma address of data buffer */
} dma_info_t;
/* descriptor bumping macros */
#define TXD(x) ((x) & (di->ntxd - 1))
#define RXD(x) ((x) & (di->nrxd - 1))
#define NEXTTXD(i) TXD(i + 1)
#define PREVTXD(i) TXD(i - 1)
#define NEXTRXD(i) RXD(i + 1)
#define NTXDACTIVE(h, t) TXD(t - h)
#define NRXDACTIVE(h, t) RXD(t - h)
/* macros to convert between byte offsets and indexes */
#define B2I(bytes) ((bytes) / sizeof (dmadd_t))
#define I2B(index) ((index) * sizeof (dmadd_t))
void*
dma_attach(void *drv, void *dev, char *name, dmaregs_t *regs, uint ntxd, uint nrxd,
uint rxbufsize, uint nrxpost, uint rxoffset, uint ddoffset, uint dataoffset, uint *msg_level)
{
dma_info_t *di;
void *va;
ASSERT(ntxd <= MAXDD);
ASSERT(nrxd <= MAXDD);
/* allocate private info structure */
if ((di = MALLOC(sizeof (dma_info_t))) == NULL)
return (NULL);
bzero((char*)di, sizeof (dma_info_t));
/* set message level */
di->msg_level = msg_level ? msg_level : &dma_msg_level;
DMA_TRACE(("%s: dma_attach: drv 0x%x dev 0x%x regs 0x%x ntxd %d nrxd %d rxbufsize %d nrxpost %d rxoffset %d ddoffset 0x%x dataoffset 0x%x\n", name, (uint)drv, (uint)dev, (uint)regs, ntxd, nrxd, rxbufsize, nrxpost, rxoffset, ddoffset, dataoffset));
/* make a private copy of our callers name */
strncpy(di->name, name, MAXNAMEL);
di->name[MAXNAMEL-1] = '\0';
di->drv = drv;
di->dev = dev;
di->regs = regs;
/* allocate transmit descriptor ring */
if (ntxd) {
if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->txdpa)) == NULL)
goto fail;
di->txd = (dmadd_t*) ROUNDUP(va, DMARINGALIGN);
di->txdalign = ((uint)di->txd - (uint)va);
di->txdpa = di->txdpa + di->txdalign;
ASSERT(ISALIGNED(di->txd, DMARINGALIGN));
}
/* allocate receive descriptor ring */
if (nrxd) {
if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->rxdpa)) == NULL)
goto fail;
di->rxd = (dmadd_t*) ROUNDUP(va, DMARINGALIGN);
di->rxdalign = ((uint)di->rxd - (uint)va);
di->rxdpa = di->rxdpa + di->rxdalign;
ASSERT(ISALIGNED(di->rxd, DMARINGALIGN));
}
/* save tunables */
di->ntxd = ntxd;
di->nrxd = nrxd;
di->rxbufsize = rxbufsize;
di->nrxpost = nrxpost;
di->rxoffset = rxoffset;
di->ddoffset = ddoffset;
di->dataoffset = dataoffset;
return ((void*)di);
fail:
dma_detach((void*)di);
return (NULL);
}
/* may be called with core in reset */
void
dma_detach(dma_info_t *di)
{
if (di == NULL)
return;
DMA_TRACE(("%s: dma_detach\n", di->name));
/* shouldn't be here if descriptors are unreclaimed */
ASSERT(di->txin == di->txout);
ASSERT(di->rxin == di->rxout);
/* free dma descriptor rings */
if (di->txd)
DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->txd - di->txdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->txdpa);
if (di->rxd)
DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->rxd - di->rxdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->rxdpa);
/* free our private info structure */
MFREE((void*)di, sizeof (dma_info_t));
}
void
dma_txreset(dma_info_t *di)
{
uint32 status;
DMA_TRACE(("%s: dma_txreset\n", di->name));
/* suspend tx DMA first */
W_REG(&di->regs->xmtcontrol, XC_SE);
SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED &&
status != XS_XS_IDLE &&
status != XS_XS_STOPPED,
10000);
W_REG(&di->regs->xmtcontrol, 0);
SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED,
10000);
if (status != XS_XS_DISABLED) {
DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di->name));
}
/* wait for the last transaction to complete */
OSL_DELAY(300);
}
void
dma_rxreset(dma_info_t *di)
{
uint32 status;
DMA_TRACE(("%s: dma_rxreset\n", di->name));
W_REG(&di->regs->rcvcontrol, 0);
SPINWAIT((status = (R_REG(&di->regs->rcvstatus) & RS_RS_MASK)) != RS_RS_DISABLED,
10000);
if (status != RS_RS_DISABLED) {
DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di->name));
}
}
void
dma_txinit(dma_info_t *di)
{
DMA_TRACE(("%s: dma_txinit\n", di->name));
di->txin = di->txout = 0;
di->txavail = di->ntxd - 1;
/* clear tx descriptor ring */
BZERO_SM((void*)di->txd, (di->ntxd * sizeof (dmadd_t)));
W_REG(&di->regs->xmtcontrol, XC_XE);
W_REG(&di->regs->xmtaddr, (di->txdpa + di->ddoffset));
}
bool
dma_txenabled(dma_info_t *di)
{
uint32 xc;
/* If the chip is dead, it is not enabled :-) */
xc = R_REG(&di->regs->xmtcontrol);
return ((xc != 0xffffffff) && (xc & XC_XE));
}
void
dma_txsuspend(dma_info_t *di)
{
DMA_TRACE(("%s: dma_txsuspend\n", di->name));
OR_REG(&di->regs->xmtcontrol, XC_SE);
}
void
dma_txresume(dma_info_t *di)
{
DMA_TRACE(("%s: dma_txresume\n", di->name));
AND_REG(&di->regs->xmtcontrol, ~XC_SE);
}
bool
dma_txsuspended(dma_info_t *di)
{
if (!(R_REG(&di->regs->xmtcontrol) & XC_SE))
return 0;
if ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) != XS_XS_IDLE)
return 0;
OSL_DELAY(2);
return ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) == XS_XS_IDLE);
}
bool
dma_txstopped(dma_info_t *di)
{
return ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) == XS_XS_STOPPED);
}
bool
dma_rxstopped(dma_info_t *di)
{
return ((R_REG(&di->regs->rcvstatus) & RS_RS_MASK) == RS_RS_STOPPED);
}
void
dma_fifoloopbackenable(dma_info_t *di)
{
DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
OR_REG(&di->regs->xmtcontrol, XC_LE);
}
void
dma_rxinit(dma_info_t *di)
{
DMA_TRACE(("%s: dma_rxinit\n", di->name));
di->rxin = di->rxout = 0;
/* clear rx descriptor ring */
BZERO_SM((void*)di->rxd, (di->nrxd * sizeof (dmadd_t)));
dma_rxenable(di);
W_REG(&di->regs->rcvaddr, (di->rxdpa + di->ddoffset));
}
void
dma_rxenable(dma_info_t *di)
{
DMA_TRACE(("%s: dma_rxenable\n", di->name));
W_REG(&di->regs->rcvcontrol, ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
}
bool
dma_rxenabled(dma_info_t *di)
{
uint32 rc;
rc = R_REG(&di->regs->rcvcontrol);
return ((rc != 0xffffffff) && (rc & RC_RE));
}
/*
* The BCM47XX family supports full 32bit dma engine buffer addressing so
* dma buffers can cross 4 Kbyte page boundaries.
*/
int
dma_txfast(dma_info_t *di, void *p0, uint32 coreflags)
{
void *p, *next;
uchar *data;
uint len;
uint txout;
uint32 ctrl;
uint32 pa;
DMA_TRACE(("%s: dma_txfast\n", di->name));
txout = di->txout;
ctrl = 0;
/*
* Walk the chain of packet buffers
* allocating and initializing transmit descriptor entries.
*/
for (p = p0; p; p = next) {
data = PKTDATA(di->drv, p);
len = PKTLEN(di->drv, p);
next = PKTNEXT(di->drv, p);
/* return nonzero if out of tx descriptors */
if (NEXTTXD(txout) == di->txin)
goto outoftxd;
if (len == 0)
continue;
/* get physical address of buffer start */
pa = (uint32) DMA_MAP(di->dev, data, len, DMA_TX, p);
/* build the descriptor control value */
ctrl = len & CTRL_BC_MASK;
ctrl |= coreflags;
if (p == p0)
ctrl |= CTRL_SOF;
if (next == NULL)
ctrl |= (CTRL_IOC | CTRL_EOF);
if (txout == (di->ntxd - 1))
ctrl |= CTRL_EOT;
/* init the tx descriptor */
W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));
ASSERT(di->txp[txout] == NULL);
txout = NEXTTXD(txout);
}
/* if last txd eof not set, fix it */
if (!(ctrl & CTRL_EOF))
W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));
/* save the packet */
di->txp[PREVTXD(txout)] = p0;
/* bump the tx descriptor index */
di->txout = txout;
/* kick the chip */
W_REG(&di->regs->xmtptr, I2B(txout));
/* tx flow control */
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
return (0);
outoftxd:
DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
PKTFREE(di->drv, p0, TRUE);
di->txavail = 0;
di->hnddma.txnobuf++;
return (-1);
}
#define PAGESZ 4096
#define PAGEBASE(x) ((uint)(x) & ~4095)
/*
* Just like above except go through the extra effort of splitting
* buffers that cross 4Kbyte boundaries into multiple tx descriptors.
*/
int
dma_tx(dma_info_t *di, void *p0, uint32 coreflags)
{
void *p, *next;
uchar *data;
uint plen, len;
uchar *page, *start, *end;
uint txout;
uint32 ctrl;
uint32 pa;
DMA_TRACE(("%s: dma_tx\n", di->name));
txout = di->txout;
ctrl = 0;
/*
* Walk the chain of packet buffers
* splitting those that cross 4 Kbyte boundaries
* allocating and initializing transmit descriptor entries.
*/
for (p = p0; p; p = next) {
data = PKTDATA(di->drv, p);
plen = PKTLEN(di->drv, p);
next = PKTNEXT(di->drv, p);
if (plen == 0)
continue;
for (page = (uchar*)PAGEBASE(data);
page <= (uchar*)PAGEBASE(data + plen - 1);
page += PAGESZ) {
/* return nonzero if out of tx descriptors */
if (NEXTTXD(txout) == di->txin)
goto outoftxd;
start = (page == (uchar*)PAGEBASE(data))? data: page;
end = (page == (uchar*)PAGEBASE(data + plen))?
(data + plen): (page + PAGESZ);
len = end - start;
/* build the descriptor control value */
ctrl = len & CTRL_BC_MASK;
ctrl |= coreflags;
if ((p == p0) && (start == data))
ctrl |= CTRL_SOF;
if ((next == NULL) && (end == (data + plen)))
ctrl |= (CTRL_IOC | CTRL_EOF);
if (txout == (di->ntxd - 1))
ctrl |= CTRL_EOT;
/* get physical address of buffer start */
pa = (uint32) DMA_MAP(di->dev, start, len, DMA_TX, p);
/* init the tx descriptor */
W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));
ASSERT(di->txp[txout] == NULL);
txout = NEXTTXD(txout);
}
}
/* if last txd eof not set, fix it */
if (!(ctrl & CTRL_EOF))
W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));
/* save the packet */
di->txp[PREVTXD(txout)] = p0;
/* bump the tx descriptor index */
di->txout = txout;
/* kick the chip */
W_REG(&di->regs->xmtptr, I2B(txout));
/* tx flow control */
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
return (0);
outoftxd:
DMA_ERROR(("%s: dma_tx: out of txds\n", di->name));
PKTFREE(di->drv, p0, TRUE);
di->txavail = 0;
di->hnddma.txnobuf++;
return (-1);
}
/* returns a pointer to the next frame received, or NULL if there are no more */
void*
dma_rx(dma_info_t *di)
{
void *p;
uint len;
int skiplen = 0;
while ((p = dma_getnextrxp(di, FALSE))) {
/* skip giant packets which span multiple rx descriptors */
if (skiplen > 0) {
skiplen -= di->rxbufsize;
if (skiplen < 0)
skiplen = 0;
PKTFREE(di->drv, p, FALSE);
continue;
}
len = ltoh16(*(uint16*)(PKTDATA(di->drv, p)));
DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
/* bad frame length check */
if (len > (di->rxbufsize - di->rxoffset)) {
DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len));
if (len > 0)
skiplen = len - (di->rxbufsize - di->rxoffset);
PKTFREE(di->drv, p, FALSE);
di->hnddma.rxgiants++;
continue;
}
/* set actual length */
PKTSETLEN(di->drv, p, (di->rxoffset + len));
break;
}
return (p);
}
/* post receive buffers */
void
dma_rxfill(dma_info_t *di)
{
void *p;
uint rxin, rxout;
uint ctrl;
uint n;
uint i;
uint32 pa;
uint rxbufsize;
/*
* Determine how many receive buffers we're lacking
* from the full complement, allocate, initialize,
* and post them, then update the chip rx lastdscr.
*/
rxin = di->rxin;
rxout = di->rxout;
rxbufsize = di->rxbufsize;
n = di->nrxpost - NRXDACTIVE(rxin, rxout);
DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
for (i = 0; i < n; i++) {
if ((p = PKTGET(di->drv, rxbufsize, FALSE)) == NULL) {
DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name));
di->hnddma.rxnobuf++;
break;
}
*(uint32*)(OSL_UNCACHED(PKTDATA(di->drv, p))) = 0;
pa = (uint32) DMA_MAP(di->dev, PKTDATA(di->drv, p), rxbufsize, DMA_RX, p);
ASSERT(ISALIGNED(pa, 4));
/* save the free packet pointer */
ASSERT(di->rxp[rxout] == NULL);
di->rxp[rxout] = p;
/* prep the descriptor control value */
ctrl = rxbufsize;
if (rxout == (di->nrxd - 1))
ctrl |= CTRL_EOT;
/* init the rx descriptor */
W_SM(&di->rxd[rxout].ctrl, BUS_SWAP32(ctrl));
W_SM(&di->rxd[rxout].addr, BUS_SWAP32(pa + di->dataoffset));
rxout = NEXTRXD(rxout);
}
di->rxout = rxout;
/* update the chip lastdscr pointer */
W_REG(&di->regs->rcvptr, I2B(rxout));
}
void
dma_txreclaim(dma_info_t *di, bool forceall)
{
void *p;
DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
while ((p = dma_getnexttxp(di, forceall)))
PKTFREE(di->drv, p, TRUE);
}
/*
* Reclaim next completed txd (txds if using chained buffers) and
* return associated packet.
* If 'force' is true, reclaim txd(s) and return associated packet
* regardless of the value of the hardware "curr" pointer.
*/
void*
dma_getnexttxp(dma_info_t *di, bool forceall)
{
uint start, end, i;
void *txp;
DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
txp = NULL;
start = di->txin;
if (forceall)
end = di->txout;
else
end = B2I(R_REG(&di->regs->xmtstatus) & XS_CD_MASK);
if ((start == 0) && (end > di->txout))
goto bogus;
for (i = start; i != end && !txp; i = NEXTTXD(i)) {
DMA_UNMAP(di->dev, (BUS_SWAP32(R_SM(&di->txd[i].addr)) - di->dataoffset),
(BUS_SWAP32(R_SM(&di->txd[i].ctrl)) & CTRL_BC_MASK), DMA_TX, di->txp[i]);
W_SM(&di->txd[i].addr, 0xdeadbeef);
txp = di->txp[i];
di->txp[i] = NULL;
}
di->txin = i;
/* tx flow control */
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
return (txp);
bogus:
/*
DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
start, end, di->txout, forceall));
*/
return (NULL);
}
/* like getnexttxp but no reclaim */
void*
dma_peeknexttxp(dma_info_t *di)
{
uint end, i;
end = B2I(R_REG(&di->regs->xmtstatus) & XS_CD_MASK);
for (i = di->txin; i != end; i = NEXTTXD(i))
if (di->txp[i])
return (di->txp[i]);
return (NULL);
}
void
dma_rxreclaim(dma_info_t *di)
{
void *p;
DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
while ((p = dma_getnextrxp(di, TRUE)))
PKTFREE(di->drv, p, FALSE);
}
void *
dma_getnextrxp(dma_info_t *di, bool forceall)
{
uint i;
void *rxp;
/* if forcing, dma engine must be disabled */
ASSERT(!forceall || !dma_rxenabled(di));
i = di->rxin;
/* return if no packets posted */
if (i == di->rxout)
return (NULL);
/* ignore curr if forceall */
if (!forceall && (i == B2I(R_REG(&di->regs->rcvstatus) & RS_CD_MASK)))
return (NULL);
/* get the packet pointer that corresponds to the rx descriptor */
rxp = di->rxp[i];
ASSERT(rxp);
di->rxp[i] = NULL;
/* clear this packet from the descriptor ring */
DMA_UNMAP(di->dev, (BUS_SWAP32(R_SM(&di->rxd[i].addr)) - di->dataoffset),
di->rxbufsize, DMA_RX, rxp);
W_SM(&di->rxd[i].addr, 0xdeadbeef);
di->rxin = NEXTRXD(i);
return (rxp);
}
char*
dma_dumptx(dma_info_t *di, char *buf)
{
buf += sprintf(buf, "txd 0x%lx txdpa 0x%lx txp 0x%lx txin %d txout %d txavail %d\n",
(ulong)di->txd, di->txdpa, (ulong)di->txp, di->txin, di->txout, di->txavail);
buf += sprintf(buf, "xmtcontrol 0x%x xmtaddr 0x%x xmtptr 0x%x xmtstatus 0x%x\n",
R_REG(&di->regs->xmtcontrol),
R_REG(&di->regs->xmtaddr),
R_REG(&di->regs->xmtptr),
R_REG(&di->regs->xmtstatus));
return (buf);
}
char*
dma_dumprx(dma_info_t *di, char *buf)
{
buf += sprintf(buf, "rxd 0x%lx rxdpa 0x%lx rxp 0x%lx rxin %d rxout %d\n",
(ulong)di->rxd, di->rxdpa, (ulong)di->rxp, di->rxin, di->rxout);
buf += sprintf(buf, "rcvcontrol 0x%x rcvaddr 0x%x rcvptr 0x%x rcvstatus 0x%x\n",
R_REG(&di->regs->rcvcontrol),
R_REG(&di->regs->rcvaddr),
R_REG(&di->regs->rcvptr),
R_REG(&di->regs->rcvstatus));
return (buf);
}
char*
dma_dump(dma_info_t *di, char *buf)
{
buf = dma_dumptx(di, buf);
buf = dma_dumprx(di, buf);
return (buf);
}
uint
dma_getvar(dma_info_t *di, char *name)
{
if (!strcmp(name, "&txavail"))
return ((uint) &di->txavail);
else {
ASSERT(0);
}
return (0);
}
void
dma_txblock(dma_info_t *di)
{
di->txavail = 0;
}
void
dma_txunblock(dma_info_t *di)
{
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
}
uint
dma_txactive(dma_info_t *di)
{
return (NTXDACTIVE(di->txin, di->txout));
}
/*
* Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
*/
void
dma_txrotate(di_t *di)
{
uint ad;
uint nactive;
uint rot;
uint old, new;
uint32 w;
uint first, last;
ASSERT(dma_txsuspended(di));
nactive = dma_txactive(di);
ad = B2I((R_REG(&di->regs->xmtstatus) & XS_AD_MASK) >> XS_AD_SHIFT);
rot = TXD(ad - di->txin);
ASSERT(rot < di->ntxd);
/* full-ring case is a lot harder - don't worry about this */
if (rot >= (di->ntxd - nactive)) {
DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name));
return;
}
first = di->txin;
last = PREVTXD(di->txout);
/* move entries starting at last and moving backwards to first */
for (old = last; old != PREVTXD(first); old = PREVTXD(old)) {
new = TXD(old + rot);
/*
* Move the tx dma descriptor.
* EOT is set only in the last entry in the ring.
*/
w = R_SM(&di->txd[old].ctrl) & ~CTRL_EOT;
if (new == (di->ntxd - 1))
w |= CTRL_EOT;
W_SM(&di->txd[new].ctrl, w);
W_SM(&di->txd[new].addr, R_SM(&di->txd[old].addr));
/* zap the old tx dma descriptor address field */
W_SM(&di->txd[old].addr, 0xdeadbeef);
/* move the corresponding txp[] entry */
ASSERT(di->txp[new] == NULL);
di->txp[new] = di->txp[old];
di->txp[old] = NULL;
}
/* update txin and txout */
di->txin = ad;
di->txout = TXD(di->txout + rot);
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
/* kick the chip */
W_REG(&di->regs->xmtptr, I2B(di->txout));
}

View File

@ -0,0 +1,465 @@
/*
* Linux OS Independent Layer
*
* Copyright 2004, 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$
*/
#define LINUX_OSL
#include <typedefs.h>
#include <bcmendian.h>
#include <linuxver.h>
#include <linux_osl.h>
#include <bcmutils.h>
#include <linux/delay.h>
#ifdef mips
#include <asm/paccess.h>
#endif
#include <pcicfg.h>
#define PCI_CFG_RETRY 10
void*
osl_pktget(void *drv, uint len, bool send)
{
struct sk_buff *skb;
if ((skb = dev_alloc_skb(len)) == NULL)
return (NULL);
skb_put(skb, len);
/* ensure the cookie field is cleared */
PKTSETCOOKIE(skb, NULL);
return ((void*) skb);
}
void
osl_pktfree(void *p)
{
struct sk_buff *skb, *nskb;
skb = (struct sk_buff*) p;
/* perversion: we use skb->next to chain multi-skb packets */
while (skb) {
nskb = skb->next;
skb->next = NULL;
if (skb->destructor) {
/* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists */
dev_kfree_skb_any(skb);
} else {
/* can free immediately (even in_irq()) if destructor does not exist */
dev_kfree_skb(skb);
}
skb = nskb;
}
}
uint32
osl_pci_read_config(void *loc, uint offset, uint size)
{
struct pci_dev *pdev;
uint val;
uint retry=PCI_CFG_RETRY;
/* only 4byte access supported */
ASSERT(size == 4);
pdev = (struct pci_dev*)loc;
do {
pci_read_config_dword(pdev, offset, &val);
if (val != 0xffffffff)
break;
} while (retry--);
return (val);
}
void
osl_pci_write_config(void *loc, uint offset, uint size, uint val)
{
struct pci_dev *pdev;
uint retry=PCI_CFG_RETRY;
/* only 4byte access supported */
ASSERT(size == 4);
pdev = (struct pci_dev*)loc;
do {
pci_write_config_dword(pdev, offset, val);
if (offset!=PCI_BAR0_WIN)
break;
if (osl_pci_read_config(loc,offset,size) == val)
break;
} while (retry--);
}
static void
osl_pcmcia_attr(void *osh, uint offset, char *buf, int size, bool write)
{
}
void
osl_pcmcia_read_attr(void *osh, uint offset, void *buf, int size)
{
osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
}
void
osl_pcmcia_write_attr(void *osh, uint offset, void *buf, int size)
{
osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
}
#if defined(BINOSL)
void
osl_assert(char *exp, char *file, int line)
{
char tempbuf[255];
sprintf(tempbuf, "assertion \"%s\" failed: file \"%s\", line %d\n", exp, file, line);
panic(tempbuf);
}
void*
osl_malloc(uint size)
{
return (kmalloc(size, GFP_ATOMIC));
}
void
osl_mfree(void *addr, uint size)
{
kfree(addr);
}
uint
osl_malloced(void)
{
#ifdef MODULE
return malloced;
#else
return 0;
#endif
}
#endif /* defined(BCMDBG) || defined(BINOSL) */
/*
* BINOSL selects the slightly slower function-call-based binary compatible osl.
*/
#ifdef BINOSL
int
osl_printf(const char *format, ...)
{
va_list args;
char buf[1024];
int len;
/* sprintf into a local buffer because there *is* no "vprintk()".. */
va_start(args, format);
len = vsprintf(buf, format, args);
va_end(args);
if (len > sizeof (buf)) {
printk("osl_printf: buffer overrun\n");
return (0);
}
return (printk(buf));
}
int
osl_sprintf(char *buf, const char *format, ...)
{
va_list args;
int rc;
va_start(args, format);
rc = vsprintf(buf, format, args);
va_end(args);
return (rc);
}
int
osl_strcmp(const char *s1, const char *s2)
{
return (strcmp(s1, s2));
}
int
osl_strncmp(const char *s1, const char *s2, uint n)
{
return (strncmp(s1, s2, n));
}
int
osl_strlen(char *s)
{
return (strlen(s));
}
char*
osl_strcpy(char *d, const char *s)
{
return (strcpy(d, s));
}
char*
osl_strncpy(char *d, const char *s, uint n)
{
return (strncpy(d, s, n));
}
void
bcopy(const void *src, void *dst, int len)
{
memcpy(dst, src, len);
}
int
bcmp(const void *b1, const void *b2, int len)
{
return (memcmp(b1, b2, len));
}
void
bzero(void *b, int len)
{
memset(b, '\0', len);
}
uint32
osl_readl(volatile uint32 *r)
{
return (readl(r));
}
uint16
osl_readw(volatile uint16 *r)
{
return (readw(r));
}
uint8
osl_readb(volatile uint8 *r)
{
return (readb(r));
}
void
osl_writel(uint32 v, volatile uint32 *r)
{
writel(v, r);
}
void
osl_writew(uint16 v, volatile uint16 *r)
{
writew(v, r);
}
void
osl_writeb(uint8 v, volatile uint8 *r)
{
writeb(v, r);
}
void *
osl_uncached(void *va)
{
#ifdef mips
return ((void*)KSEG1ADDR(va));
#else
return ((void*)va);
#endif
}
uint
osl_getcycles(void)
{
uint cycles;
#if defined(mips)
cycles = read_c0_count() * 2;
#elif defined(__i386__)
rdtscl(cycles);
#else
cycles = 0;
#endif
return cycles;
}
void *
osl_reg_map(uint32 pa, uint size)
{
return (ioremap_nocache((unsigned long)pa, (unsigned long)size));
}
void
osl_reg_unmap(void *va)
{
iounmap(va);
}
int
osl_busprobe(uint32 *val, uint32 addr)
{
#ifdef mips
return get_dbe(*val, (uint32*)addr);
#else
*val = readl(addr);
return 0;
#endif
}
void*
osl_dma_alloc_consistent(void *dev, uint size, ulong *pap)
{
return (pci_alloc_consistent((struct pci_dev*)dev, size, (dma_addr_t*)pap));
}
void
osl_dma_free_consistent(void *dev, void *va, uint size, ulong pa)
{
pci_free_consistent((struct pci_dev*)dev, size, va, (dma_addr_t)pa);
}
uint
osl_dma_map(void *dev, void *va, uint size, int direction)
{
int dir;
dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
return (pci_map_single(dev, va, size, dir));
}
void
osl_dma_unmap(void *dev, uint pa, uint size, int direction)
{
int dir;
dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
pci_unmap_single(dev, (uint32)pa, size, dir);
}
void
osl_delay(uint usec)
{
udelay(usec);
}
uchar*
osl_pktdata(void *drv, void *skb)
{
return (((struct sk_buff*)skb)->data);
}
uint
osl_pktlen(void *drv, void *skb)
{
return (((struct sk_buff*)skb)->len);
}
uint
osl_pktheadroom(void *drv, void *skb)
{
return (uint) skb_headroom((struct sk_buff *) skb);
}
uint
osl_pkttailroom(void *drv, void *skb)
{
return (uint) skb_tailroom((struct sk_buff *) skb);
}
void*
osl_pktnext(void *drv, void *skb)
{
return (((struct sk_buff*)skb)->next);
}
void
osl_pktsetnext(void *skb, void *x)
{
((struct sk_buff*)skb)->next = (struct sk_buff*)x;
}
void
osl_pktsetlen(void *drv, void *skb, uint len)
{
__skb_trim((struct sk_buff*)skb, len);
}
uchar*
osl_pktpush(void *drv, void *skb, int bytes)
{
return (skb_push((struct sk_buff*)skb, bytes));
}
uchar*
osl_pktpull(void *drv, void *skb, int bytes)
{
return (skb_pull((struct sk_buff*)skb, bytes));
}
void*
osl_pktdup(void *drv, void *skb)
{
return (skb_clone((struct sk_buff*)skb, GFP_ATOMIC));
}
void*
osl_pktcookie(void *skb)
{
return ((void*)((struct sk_buff*)skb)->csum);
}
void
osl_pktsetcookie(void *skb, void *x)
{
((struct sk_buff*)skb)->csum = (uint)x;
}
void*
osl_pktlink(void *skb)
{
return (((struct sk_buff*)skb)->prev);
}
void
osl_pktsetlink(void *skb, void *x)
{
((struct sk_buff*)skb)->prev = (struct sk_buff*)x;
}
uint
osl_pktprio(void *skb)
{
return (((struct sk_buff*)skb)->priority);
}
void
osl_pktsetprio(void *skb, uint x)
{
((struct sk_buff*)skb)->priority = x;
}
#endif /* BINOSL */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
#!/bin/sh
#
# Copyright 2004, 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$
#
cat <<EOF
#include <linux/config.h>
#include <linux/module.h>
EOF
for file in $* ; do
${NM} $file | sed -ne 's/[0-9A-Fa-f]* [DT] \([^ ]*\)/extern void \1; EXPORT_SYMBOL(\1);/p'
done

View File

@ -0,0 +1,59 @@
#
# Makefile for the Broadcom wl driver
#
# Copyright 2004, 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$
#
O_TARGET := wl.o
WL_OBJS := wl_linux.o wlc.o d11ucode.o wlc_phy.o wlc_rate.o wlc_led.o wlc_security.o rc4.o tkhash.o bcmwpa.o
INSUP_OBJS := aes.o aeskeywrap.o hmac.o md5.o passhash.o prf.o rijndael-alg-fst.o sha1.o
# Alternate ioctl interfaces
ifeq ($(CONFIG_NET_WIRELESS),y)
WL_OBJS += wlc_cmn_ioctl.o
endif
ifeq ($(CONFIG_WL_OID),y)
WL_OBJS += wl_oid.o
endif
ifeq ($(CONFIG_WL_STA),y)
WL_OBJS += $(INSUP_OBJS)
endif
# Prefix driver variants
WL_APOBJS := $(foreach obj,$(WL_OBJS),ap_$(obj))
WL_STAOBJS := $(foreach obj,$(WL_OBJS) wlc_sup.o,sta_$(obj))
WL_APSTAOBJS := $(foreach obj,$(WL_OBJS) wlc_sup.o,apsta_$(obj))
ifneq ($(CONFIG_WL_STA),y)
WL_APSTAOBJS += $(foreach obj,$(INSUP_OBJS), apsta_$(obj))
endif
# Either or both
ifeq ($(CONFIG_WL_AP),y)
AP := AP
endif
ifeq ($(CONFIG_WL_STA),y)
STA := STA
endif
# Build all variants as modules but link only one of them
export-objs :=
obj-y := $(WL_$(AP)$(STA)OBJS)
obj-m := $(O_TARGET)
variant-objs := $(WL_APOBJS) $(WL_STAOBJS) $(WL_APSTAOBJS)
EXTRA_CFLAGS += -DDMA
include $(TOPDIR)/Rules.make

View File

@ -0,0 +1,912 @@
/*
*
* bcm47xx pcmcia driver
*
* Copyright 2004, 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.
*
* Based on sa1100_generic.c from www.handhelds.org,
* and au1000_generic.c from oss.sgi.com.
*
* $Id$
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/bus_ops.h>
#include "cs_internal.h"
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <typedefs.h>
#include <bcm4710.h>
#include <sbextif.h>
#include "bcm4710pcmcia.h"
#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
#endif
MODULE_DESCRIPTION("Linux PCMCIA Card Services: bcm47xx Socket Controller");
/* This structure maintains housekeeping state for each socket, such
* as the last known values of the card detect pins, or the Card Services
* callback value associated with the socket:
*/
static struct bcm47xx_pcmcia_socket *pcmcia_socket;
static int socket_count;
/* Returned by the low-level PCMCIA interface: */
static struct pcmcia_low_level *pcmcia_low_level;
/* Event poll timer structure */
static struct timer_list poll_timer;
/* Prototypes for routines which are used internally: */
static int bcm47xx_pcmcia_driver_init(void);
static void bcm47xx_pcmcia_driver_shutdown(void);
static void bcm47xx_pcmcia_task_handler(void *data);
static void bcm47xx_pcmcia_poll_event(unsigned long data);
static void bcm47xx_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs);
static struct tq_struct bcm47xx_pcmcia_task;
#ifdef CONFIG_PROC_FS
static int bcm47xx_pcmcia_proc_status(char *buf, char **start,
off_t pos, int count, int *eof, void *data);
#endif
/* Prototypes for operations which are exported to the
* in-kernel PCMCIA core:
*/
static int bcm47xx_pcmcia_init(unsigned int sock);
static int bcm47xx_pcmcia_suspend(unsigned int sock);
static int bcm47xx_pcmcia_register_callback(unsigned int sock,
void (*handler)(void *, unsigned int), void *info);
static int bcm47xx_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap);
static int bcm47xx_pcmcia_get_status(unsigned int sock, u_int *value);
static int bcm47xx_pcmcia_get_socket(unsigned int sock, socket_state_t *state);
static int bcm47xx_pcmcia_set_socket(unsigned int sock, socket_state_t *state);
static int bcm47xx_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *io);
static int bcm47xx_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *io);
static int bcm47xx_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *mem);
static int bcm47xx_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *mem);
#ifdef CONFIG_PROC_FS
static void bcm47xx_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base);
#endif
static struct pccard_operations bcm47xx_pcmcia_operations = {
bcm47xx_pcmcia_init,
bcm47xx_pcmcia_suspend,
bcm47xx_pcmcia_register_callback,
bcm47xx_pcmcia_inquire_socket,
bcm47xx_pcmcia_get_status,
bcm47xx_pcmcia_get_socket,
bcm47xx_pcmcia_set_socket,
bcm47xx_pcmcia_get_io_map,
bcm47xx_pcmcia_set_io_map,
bcm47xx_pcmcia_get_mem_map,
bcm47xx_pcmcia_set_mem_map,
#ifdef CONFIG_PROC_FS
bcm47xx_pcmcia_proc_setup
#endif
};
/*
* bcm47xx_pcmcia_driver_init()
*
* This routine performs a basic sanity check to ensure that this
* kernel has been built with the appropriate board-specific low-level
* PCMCIA support, performs low-level PCMCIA initialization, registers
* this socket driver with Card Services, and then spawns the daemon
* thread which is the real workhorse of the socket driver.
*
* Please see linux/Documentation/arm/SA1100/PCMCIA for more information
* on the low-level kernel interface.
*
* Returns: 0 on success, -1 on error
*/
static int __init bcm47xx_pcmcia_driver_init(void)
{
servinfo_t info;
struct pcmcia_init pcmcia_init;
struct pcmcia_state state;
unsigned int i;
unsigned long tmp;
printk("\nBCM47XX PCMCIA (CS release %s)\n", CS_RELEASE);
CardServices(GetCardServicesInfo, &info);
if (info.Revision != CS_RELEASE_CODE) {
printk(KERN_ERR "Card Services release codes do not match\n");
return -1;
}
#ifdef CONFIG_BCM4710
pcmcia_low_level=&bcm4710_pcmcia_ops;
#else
#error Unsupported Broadcom BCM47XX board.
#endif
pcmcia_init.handler=bcm47xx_pcmcia_interrupt;
if ((socket_count = pcmcia_low_level->init(&pcmcia_init)) < 0) {
printk(KERN_ERR "Unable to initialize PCMCIA service.\n");
return -EIO;
} else {
printk("\t%d PCMCIA sockets initialized.\n", socket_count);
}
pcmcia_socket =
kmalloc(sizeof(struct bcm47xx_pcmcia_socket) * socket_count,
GFP_KERNEL);
memset(pcmcia_socket, 0,
sizeof(struct bcm47xx_pcmcia_socket) * socket_count);
if (!pcmcia_socket) {
printk(KERN_ERR "Card Services can't get memory \n");
return -1;
}
for (i = 0; i < socket_count; i++) {
if (pcmcia_low_level->socket_state(i, &state) < 0) {
printk(KERN_ERR "Unable to get PCMCIA status\n");
return -EIO;
}
pcmcia_socket[i].k_state = state;
pcmcia_socket[i].cs_state.csc_mask = SS_DETECT;
if (i == 0) {
pcmcia_socket[i].virt_io =
(unsigned long)ioremap_nocache(EXTIF_PCMCIA_IOBASE(BCM4710_EXTIF), 0x1000);
/* Substract ioport base which gets added by in/out */
pcmcia_socket[i].virt_io -= mips_io_port_base;
pcmcia_socket[i].phys_attr =
(unsigned long)EXTIF_PCMCIA_CFGBASE(BCM4710_EXTIF);
pcmcia_socket[i].phys_mem =
(unsigned long)EXTIF_PCMCIA_MEMBASE(BCM4710_EXTIF);
} else {
printk(KERN_ERR "bcm4710: socket 1 not supported\n");
return 1;
}
}
/* Only advertise as many sockets as we can detect: */
if (register_ss_entry(socket_count, &bcm47xx_pcmcia_operations) < 0) {
printk(KERN_ERR "Unable to register socket service routine\n");
return -ENXIO;
}
/* Start the event poll timer.
* It will reschedule by itself afterwards.
*/
bcm47xx_pcmcia_poll_event(0);
DEBUG(1, "bcm4710: initialization complete\n");
return 0;
}
module_init(bcm47xx_pcmcia_driver_init);
/*
* bcm47xx_pcmcia_driver_shutdown()
*
* Invokes the low-level kernel service to free IRQs associated with this
* socket controller and reset GPIO edge detection.
*/
static void __exit bcm47xx_pcmcia_driver_shutdown(void)
{
int i;
del_timer_sync(&poll_timer);
unregister_ss_entry(&bcm47xx_pcmcia_operations);
pcmcia_low_level->shutdown();
flush_scheduled_tasks();
for (i = 0; i < socket_count; i++) {
if (pcmcia_socket[i].virt_io)
iounmap((void *)pcmcia_socket[i].virt_io);
if (pcmcia_socket[i].phys_attr)
iounmap((void *)pcmcia_socket[i].phys_attr);
if (pcmcia_socket[i].phys_mem)
iounmap((void *)pcmcia_socket[i].phys_mem);
}
DEBUG(1, "bcm4710: shutdown complete\n");
}
module_exit(bcm47xx_pcmcia_driver_shutdown);
/*
* bcm47xx_pcmcia_init()
* We perform all of the interesting initialization tasks in
* bcm47xx_pcmcia_driver_init().
*
* Returns: 0
*/
static int bcm47xx_pcmcia_init(unsigned int sock)
{
DEBUG(1, "%s(): initializing socket %u\n", __FUNCTION__, sock);
return 0;
}
/*
* bcm47xx_pcmcia_suspend()
*
* We don't currently perform any actions on a suspend.
*
* Returns: 0
*/
static int bcm47xx_pcmcia_suspend(unsigned int sock)
{
DEBUG(1, "%s(): suspending socket %u\n", __FUNCTION__, sock);
return 0;
}
/*
* bcm47xx_pcmcia_events()
*
* Helper routine to generate a Card Services event mask based on
* state information obtained from the kernel low-level PCMCIA layer
* in a recent (and previous) sampling. Updates `prev_state'.
*
* Returns: an event mask for the given socket state.
*/
static inline unsigned
bcm47xx_pcmcia_events(struct pcmcia_state *state,
struct pcmcia_state *prev_state,
unsigned int mask, unsigned int flags)
{
unsigned int events=0;
if (state->bvd1 != prev_state->bvd1) {
DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
events |= mask & (flags & SS_IOCARD) ? SS_STSCHG : SS_BATDEAD;
}
if (state->bvd2 != prev_state->bvd2) {
DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
events |= mask & (flags & SS_IOCARD) ? 0 : SS_BATWARN;
}
if (state->detect != prev_state->detect) {
DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
events |= mask & SS_DETECT;
}
if (state->ready != prev_state->ready) {
DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
events |= mask & ((flags & SS_IOCARD) ? 0 : SS_READY);
}
if (events != 0) {
DEBUG(2, "events: %s%s%s%s%s\n",
(events & SS_DETECT) ? "DETECT " : "",
(events & SS_READY) ? "READY " : "",
(events & SS_BATDEAD) ? "BATDEAD " : "",
(events & SS_BATWARN) ? "BATWARN " : "",
(events & SS_STSCHG) ? "STSCHG " : "");
}
*prev_state=*state;
return events;
}
/*
* bcm47xx_pcmcia_task_handler()
*
* Processes serviceable socket events using the "eventd" thread context.
*
* Event processing (specifically, the invocation of the Card Services event
* callback) occurs in this thread rather than in the actual interrupt
* handler due to the use of scheduling operations in the PCMCIA core.
*/
static void bcm47xx_pcmcia_task_handler(void *data)
{
struct pcmcia_state state;
int i, events, irq_status;
DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
for (i = 0; i < socket_count; i++) {
if ((irq_status = pcmcia_low_level->socket_state(i, &state)) < 0)
printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
events = bcm47xx_pcmcia_events(&state,
&pcmcia_socket[i].k_state,
pcmcia_socket[i].cs_state.csc_mask,
pcmcia_socket[i].cs_state.flags);
if (pcmcia_socket[i].handler != NULL) {
pcmcia_socket[i].handler(pcmcia_socket[i].handler_info,
events);
}
}
}
static struct tq_struct bcm47xx_pcmcia_task = {
routine: bcm47xx_pcmcia_task_handler
};
/*
* bcm47xx_pcmcia_poll_event()
*
* Let's poll for events in addition to IRQs since IRQ only is unreliable...
*/
static void bcm47xx_pcmcia_poll_event(unsigned long dummy)
{
DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
poll_timer.function = bcm47xx_pcmcia_poll_event;
poll_timer.expires = jiffies + BCM47XX_PCMCIA_POLL_PERIOD;
add_timer(&poll_timer);
schedule_task(&bcm47xx_pcmcia_task);
}
/*
* bcm47xx_pcmcia_interrupt()
*
* Service routine for socket driver interrupts (requested by the
* low-level PCMCIA init() operation via bcm47xx_pcmcia_thread()).
*
* The actual interrupt-servicing work is performed by
* bcm47xx_pcmcia_task(), largely because the Card Services event-
* handling code performs scheduling operations which cannot be
* executed from within an interrupt context.
*/
static void
bcm47xx_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
{
DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
schedule_task(&bcm47xx_pcmcia_task);
}
/*
* bcm47xx_pcmcia_register_callback()
*
* Implements the register_callback() operation for the in-kernel
* PCMCIA service (formerly SS_RegisterCallback in Card Services). If
* the function pointer `handler' is not NULL, remember the callback
* location in the state for `sock', and increment the usage counter
* for the driver module. (The callback is invoked from the interrupt
* service routine, bcm47xx_pcmcia_interrupt(), to notify Card Services
* of interesting events.) Otherwise, clear the callback pointer in the
* socket state and decrement the module usage count.
*
* Returns: 0
*/
static int
bcm47xx_pcmcia_register_callback(unsigned int sock,
void (*handler)(void *, unsigned int), void *info)
{
if (handler == NULL) {
pcmcia_socket[sock].handler = NULL;
MOD_DEC_USE_COUNT;
} else {
MOD_INC_USE_COUNT;
pcmcia_socket[sock].handler = handler;
pcmcia_socket[sock].handler_info = info;
}
return 0;
}
/*
* bcm47xx_pcmcia_inquire_socket()
*
* Implements the inquire_socket() operation for the in-kernel PCMCIA
* service (formerly SS_InquireSocket in Card Services). Of note is
* the setting of the SS_CAP_PAGE_REGS bit in the `features' field of
* `cap' to "trick" Card Services into tolerating large "I/O memory"
* addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory
* resource database check. (Mapped memory is set up within the socket
* driver itself.)
*
* In conjunction with the STATIC_MAP capability is a new field,
* `io_offset', recommended by David Hinds. Rather than go through
* the SetIOMap interface (which is not quite suited for communicating
* window locations up from the socket driver), we just pass up
* an offset which is applied to client-requested base I/O addresses
* in alloc_io_space().
*
* Returns: 0 on success, -1 if no pin has been configured for `sock'
*/
static int
bcm47xx_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
{
struct pcmcia_irq_info irq_info;
if (sock >= socket_count) {
printk(KERN_ERR "bcm47xx: socket %u not configured\n", sock);
return -1;
}
/* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
* force_low argument to validate_mem() in rsrc_mgr.c -- since in
* general, the mapped * addresses of the PCMCIA memory regions
* will not be within 0xffff, setting force_low would be
* undesirable.
*
* SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
* resource database; we instead pass up physical address ranges
* and allow other parts of Card Services to deal with remapping.
*
* SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
* not 32-bit CardBus devices.
*/
cap->features = (SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
irq_info.sock = sock;
irq_info.irq = -1;
if (pcmcia_low_level->get_irq_info(&irq_info) < 0) {
printk(KERN_ERR "Error obtaining IRQ info socket %u\n", sock);
return -1;
}
cap->irq_mask = 0;
cap->map_size = PAGE_SIZE;
cap->pci_irq = irq_info.irq;
cap->io_offset = pcmcia_socket[sock].virt_io;
return 0;
}
/*
* bcm47xx_pcmcia_get_status()
*
* Implements the get_status() operation for the in-kernel PCMCIA
* service (formerly SS_GetStatus in Card Services). Essentially just
* fills in bits in `status' according to internal driver state or
* the value of the voltage detect chipselect register.
*
* As a debugging note, during card startup, the PCMCIA core issues
* three set_socket() commands in a row the first with RESET deasserted,
* the second with RESET asserted, and the last with RESET deasserted
* again. Following the third set_socket(), a get_status() command will
* be issued. The kernel is looking for the SS_READY flag (see
* setup_socket(), reset_socket(), and unreset_socket() in cs.c).
*
* Returns: 0
*/
static int
bcm47xx_pcmcia_get_status(unsigned int sock, unsigned int *status)
{
struct pcmcia_state state;
if ((pcmcia_low_level->socket_state(sock, &state)) < 0) {
printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
return -1;
}
pcmcia_socket[sock].k_state = state;
*status = state.detect ? SS_DETECT : 0;
*status |= state.ready ? SS_READY : 0;
/* The power status of individual sockets is not available
* explicitly from the hardware, so we just remember the state
* and regurgitate it upon request:
*/
*status |= pcmcia_socket[sock].cs_state.Vcc ? SS_POWERON : 0;
if (pcmcia_socket[sock].cs_state.flags & SS_IOCARD)
*status |= state.bvd1 ? SS_STSCHG : 0;
else {
if (state.bvd1 == 0)
*status |= SS_BATDEAD;
else if (state.bvd2 == 0)
*status |= SS_BATWARN;
}
*status |= state.vs_3v ? SS_3VCARD : 0;
*status |= state.vs_Xv ? SS_XVCARD : 0;
DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n",
(*status&SS_DETECT)?"DETECT ":"",
(*status&SS_READY)?"READY ":"",
(*status&SS_BATDEAD)?"BATDEAD ":"",
(*status&SS_BATWARN)?"BATWARN ":"",
(*status&SS_POWERON)?"POWERON ":"",
(*status&SS_STSCHG)?"STSCHG ":"",
(*status&SS_3VCARD)?"3VCARD ":"",
(*status&SS_XVCARD)?"XVCARD ":"");
return 0;
}
/*
* bcm47xx_pcmcia_get_socket()
*
* Implements the get_socket() operation for the in-kernel PCMCIA
* service (formerly SS_GetSocket in Card Services). Not a very
* exciting routine.
*
* Returns: 0
*/
static int
bcm47xx_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
{
DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
/* This information was given to us in an earlier call to set_socket(),
* so we're just regurgitating it here:
*/
*state = pcmcia_socket[sock].cs_state;
return 0;
}
/*
* bcm47xx_pcmcia_set_socket()
*
* Implements the set_socket() operation for the in-kernel PCMCIA
* service (formerly SS_SetSocket in Card Services). We more or
* less punt all of this work and let the kernel handle the details
* of power configuration, reset, &c. We also record the value of
* `state' in order to regurgitate it to the PCMCIA core later.
*
* Returns: 0
*/
static int
bcm47xx_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
{
struct pcmcia_configure configure;
DEBUG(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
"\tVcc %d Vpp %d irq %d\n",
(state->csc_mask == 0) ? "<NONE>" : "",
(state->csc_mask & SS_DETECT) ? "DETECT " : "",
(state->csc_mask & SS_READY) ? "READY " : "",
(state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
(state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
(state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
(state->flags == 0) ? "<NONE>" : "",
(state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
(state->flags & SS_IOCARD) ? "IOCARD " : "",
(state->flags & SS_RESET) ? "RESET " : "",
(state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
(state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
state->Vcc, state->Vpp, state->io_irq);
configure.sock = sock;
configure.vcc = state->Vcc;
configure.vpp = state->Vpp;
configure.output = (state->flags & SS_OUTPUT_ENA) ? 1 : 0;
configure.speaker = (state->flags & SS_SPKR_ENA) ? 1 : 0;
configure.reset = (state->flags & SS_RESET) ? 1 : 0;
if (pcmcia_low_level->configure_socket(&configure) < 0) {
printk(KERN_ERR "Unable to configure socket %u\n", sock);
return -1;
}
pcmcia_socket[sock].cs_state = *state;
return 0;
}
/*
* bcm47xx_pcmcia_get_io_map()
*
* Implements the get_io_map() operation for the in-kernel PCMCIA
* service (formerly SS_GetIOMap in Card Services). Just returns an
* I/O map descriptor which was assigned earlier by a set_io_map().
*
* Returns: 0 on success, -1 if the map index was out of range
*/
static int
bcm47xx_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
{
DEBUG(2, "bcm47xx_pcmcia_get_io_map: sock %d\n", sock);
if (map->map >= MAX_IO_WIN) {
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
*map = pcmcia_socket[sock].io_map[map->map];
return 0;
}
/*
* bcm47xx_pcmcia_set_io_map()
*
* Implements the set_io_map() operation for the in-kernel PCMCIA
* service (formerly SS_SetIOMap in Card Services). We configure
* the map speed as requested, but override the address ranges
* supplied by Card Services.
*
* Returns: 0 on success, -1 on error
*/
int
bcm47xx_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
{
unsigned int speed;
unsigned long start;
DEBUG(2, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n"
"\tflags: %s%s%s%s%s%s%s%s\n",
map->map, map->speed, map->start, map->stop,
(map->flags == 0) ? "<NONE>" : "",
(map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
(map->flags & MAP_16BIT) ? "16BIT " : "",
(map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
(map->flags & MAP_0WS) ? "0WS " : "",
(map->flags & MAP_WRPROT) ? "WRPROT " : "",
(map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
(map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
if (map->map >= MAX_IO_WIN) {
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
if (map->flags & MAP_ACTIVE) {
speed = (map->speed > 0) ? map->speed : BCM47XX_PCMCIA_IO_SPEED;
pcmcia_socket[sock].speed_io = speed;
}
start = map->start;
if (map->stop == 1) {
map->stop = PAGE_SIZE - 1;
}
map->start = pcmcia_socket[sock].virt_io;
map->stop = map->start + (map->stop - start);
pcmcia_socket[sock].io_map[map->map] = *map;
DEBUG(2, "set_io_map %d start %x stop %x\n",
map->map, map->start, map->stop);
return 0;
}
/*
* bcm47xx_pcmcia_get_mem_map()
*
* Implements the get_mem_map() operation for the in-kernel PCMCIA
* service (formerly SS_GetMemMap in Card Services). Just returns a
* memory map descriptor which was assigned earlier by a
* set_mem_map() request.
*
* Returns: 0 on success, -1 if the map index was out of range
*/
static int
bcm47xx_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
{
DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
if (map->map >= MAX_WIN) {
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
*map = pcmcia_socket[sock].mem_map[map->map];
return 0;
}
/*
* bcm47xx_pcmcia_set_mem_map()
*
* Implements the set_mem_map() operation for the in-kernel PCMCIA
* service (formerly SS_SetMemMap in Card Services). We configure
* the map speed as requested, but override the address ranges
* supplied by Card Services.
*
* Returns: 0 on success, -1 on error
*/
static int
bcm47xx_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
{
unsigned int speed;
unsigned long start;
u_long flags;
if (map->map >= MAX_WIN) {
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
DEBUG(2, "\tmap %u speed %u\n\tsys_start %#lx\n"
"\tsys_stop %#lx\n\tcard_start %#x\n"
"\tflags: %s%s%s%s%s%s%s%s\n",
map->map, map->speed, map->sys_start, map->sys_stop,
map->card_start, (map->flags == 0) ? "<NONE>" : "",
(map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
(map->flags & MAP_16BIT) ? "16BIT " : "",
(map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
(map->flags & MAP_0WS) ? "0WS " : "",
(map->flags & MAP_WRPROT) ? "WRPROT " : "",
(map->flags & MAP_ATTRIB) ? "ATTRIB " : "",
(map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "");
if (map->flags & MAP_ACTIVE) {
/* When clients issue RequestMap, the access speed is not always
* properly configured:
*/
speed = (map->speed > 0) ? map->speed : BCM47XX_PCMCIA_MEM_SPEED;
/* TBD */
if (map->flags & MAP_ATTRIB) {
pcmcia_socket[sock].speed_attr = speed;
} else {
pcmcia_socket[sock].speed_mem = speed;
}
}
save_flags(flags);
cli();
start = map->sys_start;
if (map->sys_stop == 0)
map->sys_stop = PAGE_SIZE - 1;
if (map->flags & MAP_ATTRIB) {
map->sys_start = pcmcia_socket[sock].phys_attr +
map->card_start;
} else {
map->sys_start = pcmcia_socket[sock].phys_mem +
map->card_start;
}
map->sys_stop = map->sys_start + (map->sys_stop - start);
pcmcia_socket[sock].mem_map[map->map] = *map;
restore_flags(flags);
DEBUG(2, "set_mem_map %d start %x stop %x card_start %x\n",
map->map, map->sys_start, map->sys_stop,
map->card_start);
return 0;
}
#if defined(CONFIG_PROC_FS)
/*
* bcm47xx_pcmcia_proc_setup()
*
* Implements the proc_setup() operation for the in-kernel PCMCIA
* service (formerly SS_ProcSetup in Card Services).
*
* Returns: 0 on success, -1 on error
*/
static void
bcm47xx_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
{
struct proc_dir_entry *entry;
if ((entry = create_proc_entry("status", 0, base)) == NULL) {
printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
return;
}
entry->read_proc = bcm47xx_pcmcia_proc_status;
entry->data = (void *)sock;
}
/*
* bcm47xx_pcmcia_proc_status()
*
* Implements the /proc/bus/pccard/??/status file.
*
* Returns: the number of characters added to the buffer
*/
static int
bcm47xx_pcmcia_proc_status(char *buf, char **start, off_t pos,
int count, int *eof, void *data)
{
char *p = buf;
unsigned int sock = (unsigned int)data;
p += sprintf(p, "k_flags : %s%s%s%s%s%s%s\n",
pcmcia_socket[sock].k_state.detect ? "detect " : "",
pcmcia_socket[sock].k_state.ready ? "ready " : "",
pcmcia_socket[sock].k_state.bvd1 ? "bvd1 " : "",
pcmcia_socket[sock].k_state.bvd2 ? "bvd2 " : "",
pcmcia_socket[sock].k_state.wrprot ? "wrprot " : "",
pcmcia_socket[sock].k_state.vs_3v ? "vs_3v " : "",
pcmcia_socket[sock].k_state.vs_Xv ? "vs_Xv " : "");
p += sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n",
pcmcia_socket[sock].k_state.detect ? "SS_DETECT " : "",
pcmcia_socket[sock].k_state.ready ? "SS_READY " : "",
pcmcia_socket[sock].cs_state.Vcc ? "SS_POWERON " : "",
pcmcia_socket[sock].cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "",
(pcmcia_socket[sock].cs_state.flags & SS_IOCARD &&
pcmcia_socket[sock].k_state.bvd1) ? "SS_STSCHG " : "",
((pcmcia_socket[sock].cs_state.flags & SS_IOCARD) == 0 &&
(pcmcia_socket[sock].k_state.bvd1 == 0)) ? "SS_BATDEAD " : "",
((pcmcia_socket[sock].cs_state.flags & SS_IOCARD) == 0 &&
(pcmcia_socket[sock].k_state.bvd2 == 0)) ? "SS_BATWARN " : "",
pcmcia_socket[sock].k_state.vs_3v ? "SS_3VCARD " : "",
pcmcia_socket[sock].k_state.vs_Xv ? "SS_XVCARD " : "");
p += sprintf(p, "mask : %s%s%s%s%s\n",
pcmcia_socket[sock].cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "",
pcmcia_socket[sock].cs_state.csc_mask & SS_READY ? "SS_READY " : "",
pcmcia_socket[sock].cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "",
pcmcia_socket[sock].cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "",
pcmcia_socket[sock].cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : "");
p += sprintf(p, "cs_flags : %s%s%s%s%s\n",
pcmcia_socket[sock].cs_state.flags & SS_PWR_AUTO ?
"SS_PWR_AUTO " : "",
pcmcia_socket[sock].cs_state.flags & SS_IOCARD ?
"SS_IOCARD " : "",
pcmcia_socket[sock].cs_state.flags & SS_RESET ?
"SS_RESET " : "",
pcmcia_socket[sock].cs_state.flags & SS_SPKR_ENA ?
"SS_SPKR_ENA " : "",
pcmcia_socket[sock].cs_state.flags & SS_OUTPUT_ENA ?
"SS_OUTPUT_ENA " : "");
p += sprintf(p, "Vcc : %d\n", pcmcia_socket[sock].cs_state.Vcc);
p += sprintf(p, "Vpp : %d\n", pcmcia_socket[sock].cs_state.Vpp);
p += sprintf(p, "irq : %d\n", pcmcia_socket[sock].cs_state.io_irq);
p += sprintf(p, "I/O : %u\n", pcmcia_socket[sock].speed_io);
p += sprintf(p, "attribute: %u\n", pcmcia_socket[sock].speed_attr);
p += sprintf(p, "common : %u\n", pcmcia_socket[sock].speed_mem);
return p-buf;
}
#endif /* defined(CONFIG_PROC_FS) */

View File

@ -0,0 +1,266 @@
/*
* BCM4710 specific pcmcia routines.
*
* Copyright 2004, 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 <linux/module.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/bus_ops.h>
#include "cs_internal.h"
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <typedefs.h>
#include <bcmdevs.h>
#include <bcm4710.h>
#include <sbconfig.h>
#include <sbextif.h>
#include "bcm4710pcmcia.h"
/* Use a static var for irq dev_id */
static int bcm47xx_pcmcia_dev_id;
/* Do we think we have a card or not? */
static int bcm47xx_pcmcia_present = 0;
static void bcm4710_pcmcia_reset(void)
{
extifregs_t *eir;
unsigned long s;
uint32 out0, out1, outen;
eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t));
save_and_cli(s);
/* Use gpio7 to reset the pcmcia slot */
outen = readl(&eir->gpio[0].outen);
outen |= BCM47XX_PCMCIA_RESET;
out0 = readl(&eir->gpio[0].out);
out0 &= ~(BCM47XX_PCMCIA_RESET);
out1 = out0 | BCM47XX_PCMCIA_RESET;
writel(out0, &eir->gpio[0].out);
writel(outen, &eir->gpio[0].outen);
mdelay(1);
writel(out1, &eir->gpio[0].out);
mdelay(1);
writel(out0, &eir->gpio[0].out);
restore_flags(s);
}
static int bcm4710_pcmcia_init(struct pcmcia_init *init)
{
struct pci_dev *pdev;
extifregs_t *eir;
uint32 outen, intp, intm, tmp;
uint16 *attrsp;
int rc = 0, i;
extern unsigned long bcm4710_cpu_cycle;
if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_EXTIF, NULL))) {
printk(KERN_ERR "bcm4710_pcmcia: extif not found\n");
return -ENODEV;
}
eir = (extifregs_t *) ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
/* Initialize the pcmcia i/f: 16bit no swap */
writel(CF_EM_PCMCIA | CF_DS | CF_EN, &eir->pcmcia_config);
#ifdef notYet
/* Set the timing for memory accesses */
tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */
tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */
tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */
tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */
writel(tmp, &eir->pcmcia_memwait); /* 0x01020a0c for a 100Mhz clock */
/* Set the timing for I/O accesses */
tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */
tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */
tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */
tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */
writel(tmp, &eir->pcmcia_iowait); /* 0x01020a0c for a 100Mhz clock */
/* Set the timing for attribute accesses */
tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */
tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */
tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */
tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */
writel(tmp, &eir->pcmcia_attrwait); /* 0x01020a0c for a 100Mhz clock */
#endif
/* Make sure gpio0 and gpio5 are inputs */
outen = readl(&eir->gpio[0].outen);
outen &= ~(BCM47XX_PCMCIA_WP | BCM47XX_PCMCIA_STSCHG | BCM47XX_PCMCIA_RESET);
writel(outen, &eir->gpio[0].outen);
/* Issue a reset to the pcmcia socket */
bcm4710_pcmcia_reset();
#ifdef DO_BCM47XX_PCMCIA_INTERRUPTS
/* Setup gpio5 to be the STSCHG interrupt */
intp = readl(&eir->gpiointpolarity);
writel(intp | BCM47XX_PCMCIA_STSCHG, &eir->gpiointpolarity); /* Active low */
intm = readl(&eir->gpiointmask);
writel(intm | BCM47XX_PCMCIA_STSCHG, &eir->gpiointmask); /* Enable it */
#endif
DEBUG(2, "bcm4710_pcmcia after reset:\n");
DEBUG(2, "\textstatus\t= 0x%08x:\n", readl(&eir->extstatus));
DEBUG(2, "\tpcmcia_config\t= 0x%08x:\n", readl(&eir->pcmcia_config));
DEBUG(2, "\tpcmcia_memwait\t= 0x%08x:\n", readl(&eir->pcmcia_memwait));
DEBUG(2, "\tpcmcia_attrwait\t= 0x%08x:\n", readl(&eir->pcmcia_attrwait));
DEBUG(2, "\tpcmcia_iowait\t= 0x%08x:\n", readl(&eir->pcmcia_iowait));
DEBUG(2, "\tgpioin\t\t= 0x%08x:\n", readl(&eir->gpioin));
DEBUG(2, "\tgpio_outen0\t= 0x%08x:\n", readl(&eir->gpio[0].outen));
DEBUG(2, "\tgpio_out0\t= 0x%08x:\n", readl(&eir->gpio[0].out));
DEBUG(2, "\tgpiointpolarity\t= 0x%08x:\n", readl(&eir->gpiointpolarity));
DEBUG(2, "\tgpiointmask\t= 0x%08x:\n", readl(&eir->gpiointmask));
#ifdef DO_BCM47XX_PCMCIA_INTERRUPTS
/* Request pcmcia interrupt */
rc = request_irq(BCM47XX_PCMCIA_IRQ, init->handler, SA_INTERRUPT,
"PCMCIA Interrupt", &bcm47xx_pcmcia_dev_id);
#endif
attrsp = (uint16 *)ioremap_nocache(EXTIF_PCMCIA_CFGBASE(BCM4710_EXTIF), 0x1000);
tmp = readw(&attrsp[0]);
DEBUG(2, "\tattr[0] = 0x%04x\n", tmp);
if ((tmp == 0x7fff) || (tmp == 0x7f00)) {
bcm47xx_pcmcia_present = 0;
} else {
bcm47xx_pcmcia_present = 1;
}
/* There's only one socket */
return 1;
}
static int bcm4710_pcmcia_shutdown(void)
{
extifregs_t *eir;
uint32 intm;
eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t));
/* Disable the pcmcia i/f */
writel(0, &eir->pcmcia_config);
/* Reset gpio's */
intm = readl(&eir->gpiointmask);
writel(intm & ~BCM47XX_PCMCIA_STSCHG, &eir->gpiointmask); /* Disable it */
free_irq(BCM47XX_PCMCIA_IRQ, &bcm47xx_pcmcia_dev_id);
return 0;
}
static int
bcm4710_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
{
extifregs_t *eir;
eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t));
if (sock != 0) {
printk(KERN_ERR "bcm4710 socket_state bad sock %d\n", sock);
return -1;
}
if (bcm47xx_pcmcia_present) {
state->detect = 1;
state->ready = 1;
state->bvd1 = 1;
state->bvd2 = 1;
state->wrprot = (readl(&eir->gpioin) & BCM47XX_PCMCIA_WP) == BCM47XX_PCMCIA_WP;
state->vs_3v = 0;
state->vs_Xv = 0;
} else {
state->detect = 0;
state->ready = 0;
}
return 1;
}
static int bcm4710_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
if (info->sock >= BCM47XX_PCMCIA_MAX_SOCK) return -1;
info->irq = BCM47XX_PCMCIA_IRQ;
return 0;
}
static int
bcm4710_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
if (configure->sock >= BCM47XX_PCMCIA_MAX_SOCK) return -1;
DEBUG(2, "Vcc %dV Vpp %dV output %d speaker %d reset %d\n", configure->vcc,
configure->vpp, configure->output, configure->speaker, configure->reset);
if ((configure->vcc != 50) || (configure->vpp != 50)) {
printk("%s: bad Vcc/Vpp (%d:%d)\n", __FUNCTION__, configure->vcc,
configure->vpp);
}
if (configure->reset) {
/* Issue a reset to the pcmcia socket */
DEBUG(1, "%s: Reseting socket\n", __FUNCTION__);
bcm4710_pcmcia_reset();
}
return 0;
}
struct pcmcia_low_level bcm4710_pcmcia_ops = {
bcm4710_pcmcia_init,
bcm4710_pcmcia_shutdown,
bcm4710_pcmcia_socket_state,
bcm4710_pcmcia_get_irq_info,
bcm4710_pcmcia_configure_socket
};

View File

@ -0,0 +1,118 @@
/*
*
* bcm47xx pcmcia driver
*
* Copyright 2004, 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.
*
* Based on sa1100.h and include/asm-arm/arch-sa1100/pcmica.h
* from www.handhelds.org,
* and au1000_generic.c from oss.sgi.com.
*
* $Id$
*/
#if !defined(_BCM4710PCMCIA_H)
#define _BCM4710PCMCIA_H
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
/* The 47xx can only support one socket */
#define BCM47XX_PCMCIA_MAX_SOCK 1
/* In the bcm947xx gpio's are used for some pcmcia functions */
#define BCM47XX_PCMCIA_WP 0x01 /* Bit 0 is WP input */
#define BCM47XX_PCMCIA_STSCHG 0x20 /* Bit 5 is STSCHG input/interrupt */
#define BCM47XX_PCMCIA_RESET 0x80 /* Bit 7 is RESET */
#define BCM47XX_PCMCIA_IRQ 2
/* The socket driver actually works nicely in interrupt-driven form,
* so the (relatively infrequent) polling is "just to be sure."
*/
#define BCM47XX_PCMCIA_POLL_PERIOD (2 * HZ)
#define BCM47XX_PCMCIA_IO_SPEED (255)
#define BCM47XX_PCMCIA_MEM_SPEED (300)
struct pcmcia_state {
unsigned detect: 1,
ready: 1,
bvd1: 1,
bvd2: 1,
wrprot: 1,
vs_3v: 1,
vs_Xv: 1;
};
struct pcmcia_configure {
unsigned sock: 8,
vcc: 8,
vpp: 8,
output: 1,
speaker: 1,
reset: 1;
};
struct pcmcia_irq_info {
unsigned int sock;
unsigned int irq;
};
/* This structure encapsulates per-socket state which we might need to
* use when responding to a Card Services query of some kind.
*/
struct bcm47xx_pcmcia_socket {
socket_state_t cs_state;
struct pcmcia_state k_state;
unsigned int irq;
void (*handler)(void *, unsigned int);
void *handler_info;
pccard_io_map io_map[MAX_IO_WIN];
pccard_mem_map mem_map[MAX_WIN];
ioaddr_t virt_io, phys_attr, phys_mem;
unsigned short speed_io, speed_attr, speed_mem;
};
struct pcmcia_init {
void (*handler)(int irq, void *dev, struct pt_regs *regs);
};
struct pcmcia_low_level {
int (*init)(struct pcmcia_init *);
int (*shutdown)(void);
int (*socket_state)(unsigned sock, struct pcmcia_state *);
int (*get_irq_info)(struct pcmcia_irq_info *);
int (*configure_socket)(const struct pcmcia_configure *);
};
extern struct pcmcia_low_level bcm47xx_pcmcia_ops;
/* I/O pins replacing memory pins
* (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75)
*
* These signals change meaning when going from memory-only to
* memory-or-I/O interface:
*/
#define iostschg bvd1
#define iospkr bvd2
/*
* Declaration for implementation specific low_level operations.
*/
extern struct pcmcia_low_level bcm4710_pcmcia_ops;
#endif /* !defined(_BCM4710PCMCIA_H) */

View File

@ -0,0 +1,91 @@
/*
* BCM4710 address space map and definitions
* Think twice before adding to this file, this is not the kitchen sink
* These definitions are not guaranteed for all 47xx chips, only the 4710
*
* Copyright 2004, 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$
*/
#ifndef _bcm4710_h_
#define _bcm4710_h_
/* Address map */
#define BCM4710_SDRAM 0x00000000 /* Physical SDRAM */
#define BCM4710_PCI_MEM 0x08000000 /* Host Mode PCI memory access space (64 MB) */
#define BCM4710_PCI_CFG 0x0c000000 /* Host Mode PCI configuration space (64 MB) */
#define BCM4710_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
#define BCM4710_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
#define BCM4710_ENUM 0x18000000 /* Beginning of core enumeration space */
/* Core register space */
#define BCM4710_REG_SDRAM 0x18000000 /* SDRAM core registers */
#define BCM4710_REG_ILINE20 0x18001000 /* InsideLine20 core registers */
#define BCM4710_REG_EMAC0 0x18002000 /* Ethernet MAC 0 core registers */
#define BCM4710_REG_CODEC 0x18003000 /* Codec core registers */
#define BCM4710_REG_USB 0x18004000 /* USB core registers */
#define BCM4710_REG_PCI 0x18005000 /* PCI core registers */
#define BCM4710_REG_MIPS 0x18006000 /* MIPS core registers */
#define BCM4710_REG_EXTIF 0x18007000 /* External Interface core registers */
#define BCM4710_REG_EMAC1 0x18008000 /* Ethernet MAC 1 core registers */
#define BCM4710_EXTIF 0x1f000000 /* External Interface base address */
#define BCM4710_PCMCIA_MEM 0x1f000000 /* External Interface PCMCIA memory access */
#define BCM4710_PCMCIA_IO 0x1f100000 /* PCMCIA I/O access */
#define BCM4710_PCMCIA_CONF 0x1f200000 /* PCMCIA configuration */
#define BCM4710_PROG 0x1f800000 /* Programable interface */
#define BCM4710_FLASH 0x1fc00000 /* Flash */
#define BCM4710_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
#define BCM4710_UART (BCM4710_REG_EXTIF + 0x00000300)
#define BCM4710_EUART (BCM4710_EXTIF + 0x00800000)
#define BCM4710_LED (BCM4710_EXTIF + 0x00900000)
#define SBFLAG_PCI 0
#define SBFLAG_ENET0 1
#define SBFLAG_ILINE20 2
#define SBFLAG_CODEC 3
#define SBFLAG_USB 4
#define SBFLAG_EXTIF 5
#define SBFLAG_ENET1 6
#ifdef CONFIG_HWSIM
#define BCM4710_TRACE(trval) do { *((int *)0xa0000f18) = (trval); } while (0)
#else
#define BCM4710_TRACE(trval)
#endif
/* BCM94702 CPCI -ExtIF used for LocalBus devs */
#define BCM94702_CPCI_RESET_ADDR BCM4710_EXTIF
#define BCM94702_CPCI_BOARDID_ADDR (BCM4710_EXTIF | 0x4000)
#define BCM94702_CPCI_DOC_ADDR (BCM4710_EXTIF | 0x6000)
#define BCM94702_DOC_ADDR BCM94702_CPCI_DOC_ADDR
#define BCM94702_CPCI_LED_ADDR (BCM4710_EXTIF | 0xc000)
#define BCM94702_CPCI_NVRAM_ADDR (BCM4710_EXTIF | 0xe000)
#define BCM94702_CPCI_NVRAM_SIZE 0x1ff0 /* 8K NVRAM : DS1743/STM48txx*/
#define BCM94702_CPCI_TOD_REG_BASE (BCM94702_CPCI_NVRAM_ADDR | 0x1ff0)
#define LED_REG(x) \
(*(volatile unsigned char *) (KSEG1ADDR(BCM94702_CPCI_LED_ADDR) + (x)))
/*
* Reset function implemented in PLD. Read or write should trigger hard reset
*/
#define SYS_HARD_RESET() \
{ for (;;) \
*( (volatile unsigned char *)\
KSEG1ADDR(BCM94702_CPCI_RESET_ADDR) ) = 0x80; \
}
#endif /* _bcm4710_h_ */

View File

@ -0,0 +1,251 @@
/*
* Broadcom device-specific manifest constants.
*
* Copyright 2004, 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$
*/
#ifndef _BCMDEVS_H
#define _BCMDEVS_H
/* Known PCI vendor Id's */
#define VENDOR_EPIGRAM 0xfeda
#define VENDOR_BROADCOM 0x14e4
#define VENDOR_3COM 0x10b7
#define VENDOR_NETGEAR 0x1385
#define VENDOR_DIAMOND 0x1092
#define VENDOR_DELL 0x1028
#define VENDOR_HP 0x0e11
#define VENDOR_APPLE 0x106b
/* PCI Device Id's */
#define BCM4210_DEVICE_ID 0x1072 /* never used */
#define BCM4211_DEVICE_ID 0x4211
#define BCM4230_DEVICE_ID 0x1086 /* never used */
#define BCM4231_DEVICE_ID 0x4231
#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */
#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */
#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */
#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */
#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */
#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */
#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */
#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */
#define BCM47XX_ILINE_ID 0x4711 /* 47xx iline20 */
#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */
#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */
#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */
#define BCM47XX_USB_ID 0x4715 /* 47xx usb */
#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */
#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */
#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */
#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */
#define BCM4610_DEVICE_ID 0x4610 /* 4610 primary function 0 */
#define BCM4610_ILINE_ID 0x4611 /* 4610 iline100 */
#define BCM4610_V90_ID 0x4612 /* 4610 v90 codec */
#define BCM4610_ENET_ID 0x4613 /* 4610 enet */
#define BCM4610_EXT_ID 0x4614 /* 4610 external i/f */
#define BCM4610_USB_ID 0x4615 /* 4610 usb */
#define BCM4402_DEVICE_ID 0x4402 /* 4402 primary function 0 */
#define BCM4402_ENET_ID 0x4402 /* 4402 enet */
#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */
#define BCM4301_DEVICE_ID 0x4301 /* 4301 primary function 0 */
#define BCM4301_D11B_ID 0x4301 /* 4301 802.11b */
#define BCM4307_DEVICE_ID 0x4307 /* 4307 primary function 0 */
#define BCM4307_V90_ID 0x4305 /* 4307 v90 codec */
#define BCM4307_ENET_ID 0x4306 /* 4307 enet */
#define BCM4307_D11B_ID 0x4307 /* 4307 802.11b */
#define BCM4306_DEVICE_ID 0x4306 /* 4306 chipcommon chipid */
#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */
#define BCM4306_D11G_ID2 0x4325
#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
#define BCM4306_UART_ID 0x4322 /* 4306 uart */
#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
#define BCM4309_PKG_ID 1 /* 4309 package id */
#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */
#define BCM4303_PKG_ID 2 /* 4303 package id */
#define BCM4310_DEVICE_ID 0x4310 /* 4310 chipcommon chipid */
#define BCM4310_D11B_ID 0x4311 /* 4310 802.11b */
#define BCM4310_UART_ID 0x4312 /* 4310 uart */
#define BCM4310_ENET_ID 0x4313 /* 4310 enet */
#define BCM4310_USB_ID 0x4315 /* 4310 usb */
#define BCM4704_DEVICE_ID 0x4704 /* 4704 chipcommon chipid */
#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */
#define BCM4317_DEVICE_ID 0x4317 /* 4317 chip common chipid */
#define BCM4712_DEVICE_ID 0x4712 /* 4712 chipcommon chipid */
#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */
#define SDIOH_FPGA_ID 0x4380 /* sdio host fpga */
#define BCM5365_DEVICE_ID 0x5365 /* 5365 chipcommon chipid */
/* PCMCIA vendor Id's */
#define VENDOR_BROADCOM_PCMCIA 0x02d0
/* SDIO vendor Id's */
#define VENDOR_BROADCOM_SDIO 0x00BF
/* boardflags */
#define BFL_BTCOEXIST 0x0001 /* This board implements Bluetooth coexistance */
#define BFL_PACTRL 0x0002 /* This board has gpio 9 controlling the PA */
#define BFL_AIRLINEMODE 0x0004 /* This board implements gpio13 radio disable indication */
#define BFL_ENETSPI 0x0010 /* This board has ephy roboswitch spi */
#define BFL_CCKHIPWR 0x0040 /* Can do high-power CCK transmission */
#define BFL_ENETADM 0x0080 /* This board has ADMtek switch */
#define BFL_ENETVLAN 0x0100 /* This board can do vlan */
#define BFL_AFTERBURNER 0x0200 /* This board supports Afterburner mode */
#define BFL_NOPCI 0x0400 /* This board leaves PCI floating */
#define BFL_FEM 0x0800 /* This board supports the Front End Module */
/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
#define BOARD_GPIO_HWRAD_B 0x010 /* bit 4 is HWRAD input on 4301 */
#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistance Input */
#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistance Out */
#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
/* Bus types */
#define SB_BUS 0 /* Silicon Backplane */
#define PCI_BUS 1 /* PCI target */
#define PCMCIA_BUS 2 /* PCMCIA target */
#define SDIO_BUS 3 /* SDIO target */
/* power control defines */
#define PLL_DELAY 150 /* 150us pll on delay */
#define FREF_DELAY 200 /* 200us fref change delay */
#define MIN_SLOW_CLK 32 /* 32us Slow clock period */
/* Reference Board Types */
#define BU4710_BOARD 0x0400
#define VSIM4710_BOARD 0x0401
#define QT4710_BOARD 0x0402
#define BU4610_BOARD 0x0403
#define VSIM4610_BOARD 0x0404
#define BU4307_BOARD 0x0405
#define BCM94301CB_BOARD 0x0406
#define BCM94301PC_BOARD 0x0406 /* Pcmcia 5v card */
#define BCM94301MP_BOARD 0x0407
#define BCM94307MP_BOARD 0x0408
#define BCMAP4307_BOARD 0x0409
#define BU4309_BOARD 0x040a
#define BCM94309CB_BOARD 0x040b
#define BCM94309MP_BOARD 0x040c
#define BCM4309AP_BOARD 0x040d
#define BCM94302MP_BOARD 0x040e
#define VSIM4310_BOARD 0x040f
#define BU4711_BOARD 0x0410
#define BCM94310U_BOARD 0x0411
#define BCM94310AP_BOARD 0x0412
#define BCM94310MP_BOARD 0x0414
#define BU4306_BOARD 0x0416
#define BCM94306CB_BOARD 0x0417
#define BCM94306MP_BOARD 0x0418
#define BCM94710D_BOARD 0x041a
#define BCM94710R1_BOARD 0x041b
#define BCM94710R4_BOARD 0x041c
#define BCM94710AP_BOARD 0x041d
#define BU2050_BOARD 0x041f
#define BCM94309G_BOARD 0x0421
#define BCM94301PC3_BOARD 0x0422 /* Pcmcia 3.3v card */
#define BU4704_BOARD 0x0423
#define BU4702_BOARD 0x0424
#define BCM94306PC_BOARD 0x0425 /* pcmcia 3.3v 4306 card */
#define BU4317_BOARD 0x0426
#define BCM94702MN_BOARD 0x0428
/* BCM4702 1U CompactPCI Board */
#define BCM94702CPCI_BOARD 0x0429
/* BCM4702 with BCM95380 VLAN Router */
#define BCM95380RR_BOARD 0x042a
/* cb4306 with SiGe PA */
#define BCM94306CBSG_BOARD 0x042b
/* mp4301 with 2050 radio */
#define BCM94301MPL_BOARD 0x042c
/* cb4306 with SiGe PA */
#define PCSG94306_BOARD 0x042d
/* bu4704 with sdram */
#define BU4704SD_BOARD 0x042e
/* Dual 11a/11g Router */
#define BCM94704AGR_BOARD 0x042f
/* 11a-only minipci */
#define BCM94308MP_BOARD 0x0430
/* BCM94317 boards */
#define BCM94317CB_BOARD 0x0440
#define BCM94317MP_BOARD 0x0441
#define BCM94317PCMCIA_BOARD 0x0442
#define BCM94317SDIO_BOARD 0x0443
#define BU4712_BOARD 0x0444
/* BCM4712 boards */
#define BCM94712AGR_BOARD 0x0445
#define BCM94712AP_BOARD 0x0446
/* BCM4702 boards */
#define CT4702AP_BOARD 0x0447
/* BRCM 4306 w/ Front End Modules */
#define BCM94306MPM 0x0450
#define BCM94306MPL 0x0453
#endif /* _BCMDEVS_H */

View File

@ -0,0 +1,127 @@
/*
* local version of endian.h - byte order defines
*
* Copyright 2004, 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$
*/
#ifndef _BCMENDIAN_H_
#define _BCMENDIAN_H_
#include <typedefs.h>
/* Byte swap a 16 bit value */
#define BCMSWAP16(val) \
((uint16)( \
(((uint16)(val) & (uint16)0x00ffU) << 8) | \
(((uint16)(val) & (uint16)0xff00U) >> 8) ))
/* Byte swap a 32 bit value */
#define BCMSWAP32(val) \
((uint32)( \
(((uint32)(val) & (uint32)0x000000ffUL) << 24) | \
(((uint32)(val) & (uint32)0x0000ff00UL) << 8) | \
(((uint32)(val) & (uint32)0x00ff0000UL) >> 8) | \
(((uint32)(val) & (uint32)0xff000000UL) >> 24) ))
static INLINE uint16
bcmswap16(uint16 val)
{
return BCMSWAP16(val);
}
static INLINE uint32
bcmswap32(uint32 val)
{
return BCMSWAP32(val);
}
/* buf - start of buffer of shorts to swap */
/* len - byte length of buffer */
static INLINE void
bcmswap16_buf(uint16 *buf, uint len)
{
len = len/2;
while(len--){
*buf = bcmswap16(*buf);
buf++;
}
}
#ifndef hton16
#ifndef IL_BIGENDIAN
#define HTON16(i) BCMSWAP16(i)
#define hton16(i) bcmswap16(i)
#define hton32(i) bcmswap32(i)
#define ntoh16(i) bcmswap16(i)
#define ntoh32(i) bcmswap32(i)
#define ltoh16(i) (i)
#define ltoh32(i) (i)
#define htol16(i) (i)
#define htol32(i) (i)
#else
#define HTON16(i) (i)
#define hton16(i) (i)
#define hton32(i) (i)
#define ntoh16(i) (i)
#define ntoh32(i) (i)
#define ltoh16(i) bcmswap16(i)
#define ltoh32(i) bcmswap32(i)
#define htol16(i) bcmswap16(i)
#define htol32(i) bcmswap32(i)
#endif
#endif
#ifndef IL_BIGENDIAN
#define ltoh16_buf(buf, i)
#define htol16_buf(buf, i)
#else
#define ltoh16_buf(buf, i) bcmswap16_buf((uint16*)buf, i)
#define htol16_buf(buf, i) bcmswap16_buf((uint16*)buf, i)
#endif
/*
* load 16-bit value from unaligned little endian byte array.
*/
static INLINE uint16
ltoh16_ua(uint8 *bytes)
{
return (bytes[1]<<8)+bytes[0];
}
/*
* load 32-bit value from unaligned little endian byte array.
*/
static INLINE uint32
ltoh32_ua(uint8 *bytes)
{
return (bytes[3]<<24)+(bytes[2]<<16)+(bytes[1]<<8)+bytes[0];
}
/*
* load 16-bit value from unaligned big(network) endian byte array.
*/
static INLINE uint16
ntoh16_ua(uint8 *bytes)
{
return (bytes[0]<<8)+bytes[1];
}
/*
* load 32-bit value from unaligned big(network) endian byte array.
*/
static INLINE uint32
ntoh32_ua(uint8 *bytes)
{
return (bytes[0]<<24)+(bytes[1]<<16)+(bytes[2]<<8)+bytes[3];
}
#endif /* _BCMENDIAN_H_ */

View File

@ -0,0 +1,229 @@
/*
* Hardware-specific definitions for
* Broadcom BCM47XX 10/100 Mbps Ethernet cores.
*
* Copyright 2004, 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$
*/
#ifndef _bcmenet_47xx_h_
#define _bcmenet_47xx_h_
#include <bcmdevs.h>
#include <hnddma.h>
#define BCMENET_NFILTERS 64 /* # ethernet address filter entries */
#define BCMENET_MCHASHBASE 0x200 /* multicast hash filter base address */
#define BCMENET_MCHASHSIZE 256 /* multicast hash filter size in bytes */
#define BCMENET_MAX_DMA 4096 /* chip has 12 bits of DMA addressing */
/* power management event wakeup pattern constants */
#define BCMENET_NPMP 4 /* chip supports 4 wakeup patterns */
#define BCMENET_PMPBASE 0x400 /* wakeup pattern base address */
#define BCMENET_PMPSIZE 0x80 /* 128bytes each pattern */
#define BCMENET_PMMBASE 0x600 /* wakeup mask base address */
#define BCMENET_PMMSIZE 0x10 /* 128bits each mask */
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif /* PAD */
/* sometimes you just need the enet mib definitions */
#include <bcmenetmib.h>
/*
* Host Interface Registers
*/
typedef volatile struct _bcmenettregs {
/* Device and Power Control */
uint32 devcontrol;
uint32 PAD[2];
uint32 biststatus;
uint32 wakeuplength;
uint32 PAD[3];
/* Interrupt Control */
uint32 intstatus;
uint32 intmask;
uint32 gptimer;
uint32 PAD[23];
/* Ethernet MAC Address Filtering Control */
uint32 PAD[2];
uint32 enetftaddr;
uint32 enetftdata;
uint32 PAD[2];
/* Ethernet MAC Control */
uint32 emactxmaxburstlen;
uint32 emacrxmaxburstlen;
uint32 emaccontrol;
uint32 emacflowcontrol;
uint32 PAD[20];
/* DMA Lazy Interrupt Control */
uint32 intrecvlazy;
uint32 PAD[63];
/* DMA engine */
dmaregs_t dmaregs;
dmafifo_t dmafifo;
uint32 PAD[116];
/* EMAC Registers */
uint32 rxconfig;
uint32 rxmaxlength;
uint32 txmaxlength;
uint32 PAD;
uint32 mdiocontrol;
uint32 mdiodata;
uint32 emacintmask;
uint32 emacintstatus;
uint32 camdatalo;
uint32 camdatahi;
uint32 camcontrol;
uint32 enetcontrol;
uint32 txcontrol;
uint32 txwatermark;
uint32 mibcontrol;
uint32 PAD[49];
/* EMAC MIB counters */
bcmenetmib_t mib;
uint32 PAD[585];
/* Sonics SiliconBackplane config registers */
sbconfig_t sbconfig;
} bcmenetregs_t;
/* device control */
#define DC_PM ((uint32)1 << 7) /* pattern filtering enable */
#define DC_IP ((uint32)1 << 10) /* internal ephy present (rev >= 1) */
#define DC_ER ((uint32)1 << 15) /* ephy reset */
#define DC_MP ((uint32)1 << 16) /* mii phy mode enable */
#define DC_CO ((uint32)1 << 17) /* mii phy mode: enable clocks */
#define DC_PA_MASK 0x7c0000 /* mii phy mode: mdc/mdio phy address */
#define DC_PA_SHIFT 18
/* wakeup length */
#define WL_P0_MASK 0x7f /* pattern 0 */
#define WL_D0 ((uint32)1 << 7)
#define WL_P1_MASK 0x7f00 /* pattern 1 */
#define WL_P1_SHIFT 8
#define WL_D1 ((uint32)1 << 15)
#define WL_P2_MASK 0x7f0000 /* pattern 2 */
#define WL_P2_SHIFT 16
#define WL_D2 ((uint32)1 << 23)
#define WL_P3_MASK 0x7f000000 /* pattern 3 */
#define WL_P3_SHIFT 24
#define WL_D3 ((uint32)1 << 31)
/* intstatus and intmask */
#define I_PME ((uint32)1 << 6) /* power management event */
#define I_TO ((uint32)1 << 7) /* general purpose timeout */
#define I_PC ((uint32)1 << 10) /* descriptor error */
#define I_PD ((uint32)1 << 11) /* data error */
#define I_DE ((uint32)1 << 12) /* descriptor protocol error */
#define I_RU ((uint32)1 << 13) /* receive descriptor underflow */
#define I_RO ((uint32)1 << 14) /* receive fifo overflow */
#define I_XU ((uint32)1 << 15) /* transmit fifo underflow */
#define I_RI ((uint32)1 << 16) /* receive interrupt */
#define I_XI ((uint32)1 << 24) /* transmit interrupt */
#define I_EM ((uint32)1 << 26) /* emac interrupt */
#define I_MW ((uint32)1 << 27) /* mii write */
#define I_MR ((uint32)1 << 28) /* mii read */
/* emaccontrol */
#define EMC_CG ((uint32)1 << 0) /* crc32 generation enable */
#define EMC_EP ((uint32)1 << 2) /* onchip ephy: powerdown (rev >= 1) */
#define EMC_ED ((uint32)1 << 3) /* onchip ephy: energy detected (rev >= 1) */
#define EMC_LC_MASK 0xe0 /* onchip ephy: led control (rev >= 1) */
#define EMC_LC_SHIFT 5
/* emacflowcontrol */
#define EMF_RFH_MASK 0xff /* rx fifo hi water mark */
#define EMF_PG ((uint32)1 << 15) /* enable pause frame generation */
/* interrupt receive lazy */
#define IRL_TO_MASK 0x00ffffff /* timeout */
#define IRL_FC_MASK 0xff000000 /* frame count */
#define IRL_FC_SHIFT 24 /* frame count */
/* emac receive config */
#define ERC_DB ((uint32)1 << 0) /* disable broadcast */
#define ERC_AM ((uint32)1 << 1) /* accept all multicast */
#define ERC_RDT ((uint32)1 << 2) /* receive disable while transmitting */
#define ERC_PE ((uint32)1 << 3) /* promiscuous enable */
#define ERC_LE ((uint32)1 << 4) /* loopback enable */
#define ERC_FE ((uint32)1 << 5) /* enable flow control */
#define ERC_UF ((uint32)1 << 6) /* accept unicast flow control frame */
#define ERC_RF ((uint32)1 << 7) /* reject filter */
/* emac mdio control */
#define MC_MF_MASK 0x7f /* mdc frequency */
#define MC_PE ((uint32)1 << 7) /* mii preamble enable */
/* emac mdio data */
#define MD_DATA_MASK 0xffff /* r/w data */
#define MD_TA_MASK 0x30000 /* turnaround value */
#define MD_TA_SHIFT 16
#define MD_TA_VALID (2 << MD_TA_SHIFT) /* valid ta */
#define MD_RA_MASK 0x7c0000 /* register address */
#define MD_RA_SHIFT 18
#define MD_PMD_MASK 0xf800000 /* physical media device */
#define MD_PMD_SHIFT 23
#define MD_OP_MASK 0x30000000 /* opcode */
#define MD_OP_SHIFT 28
#define MD_OP_WRITE (1 << MD_OP_SHIFT) /* write op */
#define MD_OP_READ (2 << MD_OP_SHIFT) /* read op */
#define MD_SB_MASK 0xc0000000 /* start bits */
#define MD_SB_SHIFT 30
#define MD_SB_START (0x1 << MD_SB_SHIFT) /* start of frame */
/* emac intstatus and intmask */
#define EI_MII ((uint32)1 << 0) /* mii mdio interrupt */
#define EI_MIB ((uint32)1 << 1) /* mib interrupt */
#define EI_FLOW ((uint32)1 << 2) /* flow control interrupt */
/* emac cam data high */
#define CD_V ((uint32)1 << 16) /* valid bit */
/* emac cam control */
#define CC_CE ((uint32)1 << 0) /* cam enable */
#define CC_MS ((uint32)1 << 1) /* mask select */
#define CC_RD ((uint32)1 << 2) /* read */
#define CC_WR ((uint32)1 << 3) /* write */
#define CC_INDEX_MASK 0x3f0000 /* index */
#define CC_INDEX_SHIFT 16
#define CC_CB ((uint32)1 << 31) /* cam busy */
/* emac ethernet control */
#define EC_EE ((uint32)1 << 0) /* emac enable */
#define EC_ED ((uint32)1 << 1) /* emac disable */
#define EC_ES ((uint32)1 << 2) /* emac soft reset */
#define EC_EP ((uint32)1 << 3) /* external phy select */
/* emac transmit control */
#define EXC_FD ((uint32)1 << 0) /* full duplex */
#define EXC_FM ((uint32)1 << 1) /* flowmode */
#define EXC_SB ((uint32)1 << 2) /* single backoff enable */
#define EXC_SS ((uint32)1 << 3) /* small slottime */
/* emac mib control */
#define EMC_RZ ((uint32)1 << 0) /* autoclear on read */
/* sometimes you just need the enet rxheader definitions */
#include <bcmenetrxh.h>
#endif /* _bcmenet_47xx_h_ */

View File

@ -0,0 +1,81 @@
/*
* Hardware-specific MIB definition for
* Broadcom Home Networking Division
* BCM44XX and BCM47XX 10/100 Mbps Ethernet cores.
*
* Copyright 2004, 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$
*/
#ifndef _bcmenetmib_h_
#define _bcmenetmib_h_
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif /* PAD */
/*
* EMAC MIB Registers
*/
typedef volatile struct {
uint32 tx_good_octets;
uint32 tx_good_pkts;
uint32 tx_octets;
uint32 tx_pkts;
uint32 tx_broadcast_pkts;
uint32 tx_multicast_pkts;
uint32 tx_len_64;
uint32 tx_len_65_to_127;
uint32 tx_len_128_to_255;
uint32 tx_len_256_to_511;
uint32 tx_len_512_to_1023;
uint32 tx_len_1024_to_max;
uint32 tx_jabber_pkts;
uint32 tx_oversize_pkts;
uint32 tx_fragment_pkts;
uint32 tx_underruns;
uint32 tx_total_cols;
uint32 tx_single_cols;
uint32 tx_multiple_cols;
uint32 tx_excessive_cols;
uint32 tx_late_cols;
uint32 tx_defered;
uint32 tx_carrier_lost;
uint32 tx_pause_pkts;
uint32 PAD[8];
uint32 rx_good_octets;
uint32 rx_good_pkts;
uint32 rx_octets;
uint32 rx_pkts;
uint32 rx_broadcast_pkts;
uint32 rx_multicast_pkts;
uint32 rx_len_64;
uint32 rx_len_65_to_127;
uint32 rx_len_128_to_255;
uint32 rx_len_256_to_511;
uint32 rx_len_512_to_1023;
uint32 rx_len_1024_to_max;
uint32 rx_jabber_pkts;
uint32 rx_oversize_pkts;
uint32 rx_fragment_pkts;
uint32 rx_missed_pkts;
uint32 rx_crc_align_errs;
uint32 rx_undersize;
uint32 rx_crc_errs;
uint32 rx_align_errs;
uint32 rx_symbol_errs;
uint32 rx_pause_pkts;
uint32 rx_nonpause_pkts;
} bcmenetmib_t;
#endif /* _bcmenetmib_h_ */

View File

@ -0,0 +1,43 @@
/*
* Hardware-specific Receive Data Header for the
* Broadcom Home Networking Division
* BCM44XX and BCM47XX 10/100 Mbps Ethernet cores.
*
* Copyright 2004, 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$
*/
#ifndef _bcmenetrxh_h_
#define _bcmenetrxh_h_
/*
* The Ethernet MAC core returns an 8-byte Receive Frame Data Header
* with every frame consisting of
* 16bits of frame length, followed by
* 16bits of EMAC rx descriptor info, followed by 32bits of undefined.
*/
typedef volatile struct {
uint16 len;
uint16 flags;
uint16 pad[12];
} bcmenetrxh_t;
#define RXHDR_LEN 28
#define RXF_L ((uint16)1 << 11) /* last buffer in a frame */
#define RXF_MISS ((uint16)1 << 7) /* received due to promisc mode */
#define RXF_BRDCAST ((uint16)1 << 6) /* dest is broadcast address */
#define RXF_MULT ((uint16)1 << 5) /* dest is multicast address */
#define RXF_LG ((uint16)1 << 4) /* frame length > rxmaxlength */
#define RXF_NO ((uint16)1 << 3) /* odd number of nibbles */
#define RXF_RXER ((uint16)1 << 2) /* receive symbol error */
#define RXF_CRC ((uint16)1 << 1) /* crc error */
#define RXF_OV ((uint16)1 << 0) /* fifo overflow */
#endif /* _bcmenetrxh_h_ */

View File

@ -0,0 +1,148 @@
/*
* NVRAM variable manipulation
*
* Copyright 2004, 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$
*/
#ifndef _bcmnvram_h_
#define _bcmnvram_h_
#ifndef _LANGUAGE_ASSEMBLY
#include <typedefs.h>
struct nvram_header {
uint32 magic;
uint32 len;
uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:27 init, mem. test 28, 29-31 reserved */
uint32 config_refresh; /* 0:15 config, 16:31 refresh */
uint32 config_ncdl; /* ncdl values for memc */
};
struct nvram_tuple {
char *name;
char *value;
struct nvram_tuple *next;
};
/*
* Initialize NVRAM access. May be unnecessary or undefined on certain
* platforms.
*/
extern int nvram_init(void *sbh);
/*
* Disable NVRAM access. May be unnecessary or undefined on certain
* platforms.
*/
extern void nvram_exit(void);
/*
* Get the value of an NVRAM variable. The pointer returned may be
* invalid after a set.
* @param name name of variable to get
* @return value of variable or NULL if undefined
*/
extern char * nvram_get(const char *name);
/*
* Get the value of an NVRAM variable.
* @param name name of variable to get
* @return value of variable or NUL if undefined
*/
#define nvram_safe_get(name) (nvram_get(name) ? : "")
#define nvram_safe_unset(name) ({ \
if(nvram_get(name)) \
nvram_unset(name); \
})
#define nvram_safe_set(name, value) ({ \
if(!nvram_get(name) || strcmp(nvram_get(name), value)) \
nvram_set(name, value); \
})
/*
* Match an NVRAM variable.
* @param name name of variable to match
* @param match value to compare against value of variable
* @return TRUE if variable is defined and its value is string equal
* to match or FALSE otherwise
*/
static INLINE int
nvram_match(char *name, char *match) {
const char *value = nvram_get(name);
return (value && !strcmp(value, match));
}
/*
* Inversely match an NVRAM variable.
* @param name name of variable to match
* @param match value to compare against value of variable
* @return TRUE if variable is defined and its value is not string
* equal to invmatch or FALSE otherwise
*/
static INLINE int
nvram_invmatch(char *name, char *invmatch) {
const char *value = nvram_get(name);
return (value && strcmp(value, invmatch));
}
/*
* Set the value of an NVRAM variable. The name and value strings are
* copied into private storage. Pointers to previously set values
* may become invalid. The new value may be immediately
* retrieved but will not be permanently stored until a commit.
* @param name name of variable to set
* @param value value of variable
* @return 0 on success and errno on failure
*/
extern int nvram_set(const char *name, const char *value);
/*
* Unset an NVRAM variable. Pointers to previously set values
* remain valid until a set.
* @param name name of variable to unset
* @return 0 on success and errno on failure
* NOTE: use nvram_commit to commit this change to flash.
*/
extern int nvram_unset(const char *name);
/*
* Commit NVRAM variables to permanent storage. All pointers to values
* may be invalid after a commit.
* NVRAM values are undefined after a commit.
* @return 0 on success and errno on failure
*/
extern int nvram_commit(void);
/*
* Get all NVRAM variables (format name=value\0 ... \0\0).
* @param buf buffer to store variables
* @param count size of buffer in bytes
* @return 0 on success and errno on failure
*/
extern int nvram_getall(char *buf, int count);
extern int file2nvram(char *filename, char *varname);
extern int nvram2file(char *varname, char *filename);
#endif /* _LANGUAGE_ASSEMBLY */
#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
#define NVRAM_VERSION 1
#define NVRAM_HEADER_SIZE 20
#define NVRAM_SPACE 0x8000
#define FLASH_BASE 0xbfc00000 /* Extif core */
#define FLASH_MIN 0x00100000 /* Minimum flash size */
#define FLASH_MAX 0x00400000 /* Maximum flash size with extif */
#endif /* _bcmnvram_h_ */

View File

@ -0,0 +1,24 @@
/*
* Misc useful routines to access NIC srom
*
* Copyright 2004, 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$
*/
#ifndef _bcmsrom_h_
#define _bcmsrom_h_
extern int srom_var_init(void *sbh, uint bus, void *curmap, void *osh, char **vars, int *count);
extern int srom_read(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf);
extern int srom_write(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf);
extern int srom_parsecis(uint8 *cis, char **vars, int *count);
#endif /* _bcmsrom_h_ */

View File

@ -0,0 +1,157 @@
/*
* Misc useful os-independent macros and functions.
*
* Copyright 2004, 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$
*/
#ifndef _bcmutils_h_
#define _bcmutils_h_
#ifndef MIN
#define MIN(a, b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define MAX(a, b) (((a)>(b))?(a):(b))
#endif
#define CEIL(x, y) (((x) + ((y)-1)) / (y))
#define ROUNDUP(x, y) ((((ulong)(x)+((y)-1))/(y))*(y))
#define ISALIGNED(a, x) (((uint)(a) & ((x)-1)) == 0)
#define ISPOWEROF2(x) ((((x)-1)&(x))==0)
#define OFFSETOF(type, member) ((uint) &((type *)0)->member)
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
/* bit map related macros */
#ifndef setbit
#define NBBY 8 /* 8 bits per byte */
#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
#endif
#define NBITS(type) (sizeof (type) * 8)
#define _BCM_U 0x01 /* upper */
#define _BCM_L 0x02 /* lower */
#define _BCM_D 0x04 /* digit */
#define _BCM_C 0x08 /* cntrl */
#define _BCM_P 0x10 /* punct */
#define _BCM_S 0x20 /* white space (space/lf/tab) */
#define _BCM_X 0x40 /* hex digit */
#define _BCM_SP 0x80 /* hard space (0x20) */
extern unsigned char bcm_ctype[];
#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
/*
* Spin at most 'us' microseconds while 'exp' is true.
* Caller should explicitly test 'exp' when this completes
* and take appropriate error action if 'exp' is still true.
*/
#define SPINWAIT(exp, us) { \
uint countdown = (us) + 9; \
while ((exp) && (countdown >= 10)) {\
OSL_DELAY(10); \
countdown -= 10; \
} \
}
/* generic osl packet queue */
struct pktq {
void *head; /* first packet to dequeue */
void *tail; /* last packet to dequeue */
uint len; /* number of queued packets */
uint maxlen; /* maximum number of queued packets */
bool priority; /* enqueue by packet priority */
};
#define DEFAULT_QLEN 128
#define pktq_len(q) ((q)->len)
#define pktq_avail(q) ((q)->maxlen - (q)->len)
#define pktq_head(q) ((q)->head)
#define pktq_full(q) ((q)->len >= (q)->maxlen)
/* crc defines */
#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */
#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */
#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */
#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */
/* tag_ID/length/value_buffer tuple */
typedef struct bcm_tlv {
uint8 id;
uint8 len;
uint8 data[1];
} bcm_tlv_t;
/* Check that bcm_tlv_t fits into the given buflen */
#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (buflen) >= 2 + (elt)->len)
/* buffer length for ethernet address from bcm_ether_ntoa() */
#define ETHER_ADDR_STR_LEN 18
/*
* load 32-bit value from unaligned byte array
*/
#ifdef IL_BIGENDIAN
#define load32_ua(a) ((((uint8 *)(a))[0] << 24) + (((uint8 *)(a))[1] << 16) + \
(((uint8 *)(a))[2] << 8) + ((uint8 *)(a))[3])
#else
#define load32_ua(a) ((((uint8 *)(a))[3] << 24) + (((uint8 *)(a))[2] << 16) + \
(((uint8 *)(a))[1] << 8) + ((uint8 *)(a))[0])
#endif
/* externs */
extern uint bcm_atoi(char *s);
extern uchar bcm_toupper(uchar c);
extern ulong bcm_strtoul(char *cp, char **endp, uint base);
extern void deadbeef(char *p, uint len);
extern void prhex(char *msg, uchar *buf, uint len);
extern void prpkt(char *msg, void *drv, void *p0);
extern uint pktcopy(void *drv, void *p, uint offset, int len, uchar *buf);
extern uint pkttotlen(void *drv, void *);
extern uchar *bcm_ether_ntoa(char *ea, char *buf);
extern int bcm_ether_atoe(char *p, char *ea);
extern void bcm_mdelay(uint ms);
extern char *getvar(char *vars, char *name);
extern int getintvar(char *vars, char *name);
extern char *bcmstrstr(char *haystack, char *needle);
extern uint8 crc8(uint8 *p, uint nbytes, uint8 crc);
extern uint16 crc16(uint8 *p, uint nbytes, uint16 crc);
extern uint32 crc32(uint8 *p, uint nbytes, uint32 crc);
extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen);
extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key);
extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key);
extern void pktq_init(struct pktq *q, uint maxlen, bool priority);
extern bool pktenq(struct pktq *q, void *p, bool lifo);
extern void *pktdeq(struct pktq *q);
#define bcmlog(fmt, a1, a2)
#define bcmdumplog(buf, size) *buf = '\0'
#define bcmdumplogent(buf, idx) -1
#endif /* _bcmutils_h_ */

View File

@ -0,0 +1,186 @@
/*
* Generic Broadcom Home Networking Division (HND) DMA engine definitions.
* This supports the following chips: BCM42xx, 44xx, 47xx .
*
* Copyright 2004, 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$
*/
#ifndef _hnddma_h_
#define _hnddma_h_
/*
* Each DMA processor consists of a transmit channel and a receive channel.
*/
typedef volatile struct {
/* transmit channel */
uint32 xmtcontrol; /* enable, et al */
uint32 xmtaddr; /* descriptor ring base address (4K aligned) */
uint32 xmtptr; /* last descriptor posted to chip */
uint32 xmtstatus; /* current active descriptor, et al */
/* receive channel */
uint32 rcvcontrol; /* enable, et al */
uint32 rcvaddr; /* descriptor ring base address (4K aligned) */
uint32 rcvptr; /* last descriptor posted to chip */
uint32 rcvstatus; /* current active descriptor, et al */
} dmaregs_t;
typedef volatile struct {
/* diag access */
uint32 fifoaddr; /* diag address */
uint32 fifodatalow; /* low 32bits of data */
uint32 fifodatahigh; /* high 32bits of data */
uint32 pad; /* reserved */
} dmafifo_t;
/* transmit channel control */
#define XC_XE ((uint32)1 << 0) /* transmit enable */
#define XC_SE ((uint32)1 << 1) /* transmit suspend request */
#define XC_LE ((uint32)1 << 2) /* loopback enable */
#define XC_FL ((uint32)1 << 4) /* flush request */
/* transmit descriptor table pointer */
#define XP_LD_MASK 0xfff /* last valid descriptor */
/* transmit channel status */
#define XS_CD_MASK 0x0fff /* current descriptor pointer */
#define XS_XS_MASK 0xf000 /* transmit state */
#define XS_XS_SHIFT 12
#define XS_XS_DISABLED 0x0000 /* disabled */
#define XS_XS_ACTIVE 0x1000 /* active */
#define XS_XS_IDLE 0x2000 /* idle wait */
#define XS_XS_STOPPED 0x3000 /* stopped */
#define XS_XS_SUSP 0x4000 /* suspend pending */
#define XS_XE_MASK 0xf0000 /* transmit errors */
#define XS_XE_SHIFT 16
#define XS_XE_NOERR 0x00000 /* no error */
#define XS_XE_DPE 0x10000 /* descriptor protocol error */
#define XS_XE_DFU 0x20000 /* data fifo underrun */
#define XS_XE_BEBR 0x30000 /* bus error on buffer read */
#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */
#define XS_AD_MASK 0xfff00000 /* active descriptor */
#define XS_AD_SHIFT 20
/* receive channel control */
#define RC_RE ((uint32)1 << 0) /* receive enable */
#define RC_RO_MASK 0xfe /* receive frame offset */
#define RC_RO_SHIFT 1
#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */
/* receive descriptor table pointer */
#define RP_LD_MASK 0xfff /* last valid descriptor */
/* receive channel status */
#define RS_CD_MASK 0x0fff /* current descriptor pointer */
#define RS_RS_MASK 0xf000 /* receive state */
#define RS_RS_SHIFT 12
#define RS_RS_DISABLED 0x0000 /* disabled */
#define RS_RS_ACTIVE 0x1000 /* active */
#define RS_RS_IDLE 0x2000 /* idle wait */
#define RS_RS_STOPPED 0x3000 /* reserved */
#define RS_RE_MASK 0xf0000 /* receive errors */
#define RS_RE_SHIFT 16
#define RS_RE_NOERR 0x00000 /* no error */
#define RS_RE_DPE 0x10000 /* descriptor protocol error */
#define RS_RE_DFO 0x20000 /* data fifo overflow */
#define RS_RE_BEBW 0x30000 /* bus error on buffer write */
#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */
#define RS_AD_MASK 0xfff00000 /* active descriptor */
#define RS_AD_SHIFT 20
/* fifoaddr */
#define FA_OFF_MASK 0xffff /* offset */
#define FA_SEL_MASK 0xf0000 /* select */
#define FA_SEL_SHIFT 16
#define FA_SEL_XDD 0x00000 /* transmit dma data */
#define FA_SEL_XDP 0x10000 /* transmit dma pointers */
#define FA_SEL_RDD 0x40000 /* receive dma data */
#define FA_SEL_RDP 0x50000 /* receive dma pointers */
#define FA_SEL_XFD 0x80000 /* transmit fifo data */
#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */
#define FA_SEL_RFD 0xc0000 /* receive fifo data */
#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */
/*
* DMA Descriptor
* Descriptors are only read by the hardware, never written back.
*/
typedef volatile struct {
uint32 ctrl; /* misc control bits & bufcount */
uint32 addr; /* data buffer address */
} dmadd_t;
/*
* Each descriptor ring must be 4096byte aligned
* and fit within a single 4096byte page.
*/
#define DMAMAXRINGSZ 4096
#define DMARINGALIGN 4096
/* control flags */
#define CTRL_BC_MASK 0x1fff /* buffer byte count */
#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */
#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */
#define CTRL_EOF ((uint32)1 << 30) /* end of frame */
#define CTRL_SOF ((uint32)1 << 31) /* start of frame */
/* control flags in the range [27:20] are core-specific and not defined here */
#define CTRL_CORE_MASK 0x0ff00000
/* export structure */
typedef volatile struct {
/* rx error counters */
uint rxgiants; /* rx giant frames */
uint rxnobuf; /* rx out of dma descriptors */
/* tx error counters */
uint txnobuf; /* tx out of dma descriptors */
} hnddma_t;
#ifndef di_t
#define di_t void
#endif
/* externs */
extern void *dma_attach(void *drv, void *dev, char *name, dmaregs_t *dmaregs,
uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset,
uint ddoffset, uint dataoffset, uint *msg_level);
extern void dma_detach(di_t *di);
extern void dma_txreset(di_t *di);
extern void dma_rxreset(di_t *di);
extern void dma_txinit(di_t *di);
extern bool dma_txenabled(di_t *di);
extern void dma_rxinit(di_t *di);
extern void dma_rxenable(di_t *di);
extern bool dma_rxenabled(di_t *di);
extern void dma_txsuspend(di_t *di);
extern void dma_txresume(di_t *di);
extern bool dma_txsuspended(di_t *di);
extern bool dma_txstopped(di_t *di);
extern bool dma_rxstopped(di_t *di);
extern int dma_txfast(di_t *di, void *p, uint32 coreflags);
extern int dma_tx(di_t *di, void *p, uint32 coreflags);
extern void dma_fifoloopbackenable(di_t *di);
extern void *dma_rx(di_t *di);
extern void dma_rxfill(di_t *di);
extern void dma_txreclaim(di_t *di, bool forceall);
extern void dma_rxreclaim(di_t *di);
extern char *dma_dump(di_t *di, char *buf);
extern char *dma_dumptx(di_t *di, char *buf);
extern char *dma_dumprx(di_t *di, char *buf);
extern uint dma_getvar(di_t *di, char *name);
extern void *dma_getnexttxp(di_t *di, bool forceall);
extern void *dma_peeknexttxp(di_t *di);
extern void *dma_getnextrxp(di_t *di, bool forceall);
extern void dma_txblock(di_t *di);
extern void dma_txunblock(di_t *di);
extern uint dma_txactive(di_t *di);
extern void dma_txrotate(di_t *di);
#endif /* _hnddma_h_ */

View File

@ -0,0 +1,16 @@
/*
* Alternate include file for HND sbmips.h since CFE also ships with
* a sbmips.h.
*
* Copyright 2004, 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 "sbmips.h"

View File

@ -0,0 +1,343 @@
/*
* Linux OS Independent Layer
*
* Copyright 2004, 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$
*/
#ifndef _linux_osl_h_
#define _linux_osl_h_
#include <typedefs.h>
/* use current 2.4.x calling conventions */
#include <linuxver.h>
/* assert and panic */
#define ASSERT(exp) do {} while (0)
/* PCMCIA attribute space access macros */
#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
struct pcmcia_dev {
dev_link_t link; /* PCMCIA device pointer */
dev_node_t node; /* PCMCIA node structure */
void *base; /* Mapped attribute memory window */
size_t size; /* Size of window */
void *drv; /* Driver data */
};
#endif
#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \
osl_pcmcia_read_attr((osh), (offset), (buf), (size))
#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \
osl_pcmcia_write_attr((osh), (offset), (buf), (size))
extern void osl_pcmcia_read_attr(void *osh, uint offset, void *buf, int size);
extern void osl_pcmcia_write_attr(void *osh, uint offset, void *buf, int size);
/* PCI configuration space access macros */
#define OSL_PCI_READ_CONFIG(loc, offset, size) \
osl_pci_read_config((loc), (offset), (size))
#define OSL_PCI_WRITE_CONFIG(loc, offset, size, val) \
osl_pci_write_config((loc), (offset), (size), (val))
extern uint32 osl_pci_read_config(void *loc, uint size, uint offset);
extern void osl_pci_write_config(void *loc, uint offset, uint size, uint val);
/* OSL initialization */
#define osl_init() do {} while (0)
/* host/bus architecture-specific byte swap */
#define BUS_SWAP32(v) (v)
/* general purpose memory allocation */
#if defined(BINOSL)
#if defined(BCMDBG_MEM)
#define MALLOC(size) osl_debug_malloc((size), __LINE__, __FILE__)
#define MFREE(addr, size) osl_debug_mfree((addr), (size))
#define MALLOCED() osl_malloced()
extern void* osl_debug_malloc(uint size, int line, char* file);
extern void osl_debug_mfree(void *addr, uint size);
extern void osl_debug_memdump(void);
#else
#define MALLOC(size) osl_malloc((size))
#define MFREE(addr, size) osl_mfree((addr), (size))
#define MALLOCED() osl_malloced()
#endif
extern void *osl_malloc(uint size);
extern void osl_mfree(void *addr, uint size);
extern uint osl_malloced(void);
#else
#define MALLOC(size) kmalloc((size), GFP_ATOMIC)
#define MFREE(addr, size) kfree((addr))
#define MALLOCED() (0)
#endif
/*
* BINOSL selects the slightly slower function-call-based binary compatible osl.
* Macros expand to calls to functions defined in linux_osl.c .
*/
#ifndef BINOSL
/* string library, kernel mode */
#define printf(fmt, args...) printk(fmt, ## args)
#include <linux/kernel.h>
#include <linux/string.h>
/* register access macros */
#define R_REG(r) ( \
sizeof(*(r)) == sizeof(uint8) ? readb((volatile uint8*)(r)) : \
sizeof(*(r)) == sizeof(uint16) ? readw((volatile uint16*)(r)) : \
readl((volatile uint32*)(r)) \
)
#define W_REG(r, v) do { \
switch (sizeof(*(r))) { \
case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \
case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \
case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
} \
} while (0)
#define AND_REG(r, v) W_REG((r), R_REG(r) & (v))
#define OR_REG(r, v) W_REG((r), R_REG(r) | (v))
/* bcopy, bcmp, and bzero */
#define bcopy(src, dst, len) memcpy((dst), (src), (len))
#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
#define bzero(b, len) memset((b), '\0', (len))
/* uncached virtual address */
#ifdef mips
#define OSL_UNCACHED(va) KSEG1ADDR((va))
#include <asm/addrspace.h>
#else
#define OSL_UNCACHED(va) (va)
#endif
/* get processor cycle count */
#if defined(mips)
#define OSL_GETCYCLES(x) ((x) = read_c0_count() * 2)
#elif defined(__i386__)
#define OSL_GETCYCLES(x) rdtscl((x))
#else
#define OSL_GETCYCLES(x) ((x) = 0)
#endif
/* dereference an address that may cause a bus exception */
#ifdef mips
#if defined(MODULE) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,17))
#define BUSPROBE(val, addr) panic("get_dbe() will not fixup a bus exception when compiled into a module")
#else
#define BUSPROBE(val, addr) get_dbe((val), (addr))
#include <asm/paccess.h>
#endif
#else
#define BUSPROBE(val, addr) ({ (val) = R_REG((addr)); 0; })
#endif
/* map/unmap physical to virtual I/O */
#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size))
#define REG_UNMAP(va) iounmap((void *)(va))
/* allocate/free shared (dma-able) consistent (uncached) memory */
#define DMA_ALLOC_CONSISTENT(dev, size, pap) \
pci_alloc_consistent((dev), (size), (dma_addr_t*)(pap))
#define DMA_FREE_CONSISTENT(dev, va, size, pa) \
pci_free_consistent((dev), (size), (va), (dma_addr_t)(pa))
/* map/unmap direction */
#define DMA_TX PCI_DMA_TODEVICE
#define DMA_RX PCI_DMA_FROMDEVICE
/* map/unmap shared (dma-able) memory */
#define DMA_MAP(dev, va, size, direction, p) \
pci_map_single((dev), (va), (size), (direction))
#define DMA_UNMAP(dev, pa, size, direction, p) \
pci_unmap_single((dev), (dma_addr_t)(pa), (size), (direction))
/* microsecond delay */
#define OSL_DELAY(usec) udelay(usec)
#include <linux/delay.h>
/* shared (dma-able) memory access macros */
#define R_SM(r) *(r)
#define W_SM(r, v) (*(r) = (v))
#define BZERO_SM(r, len) memset((r), '\0', (len))
/* packet primitives */
#define PKTGET(drv, len, send) osl_pktget((drv), (len), (send))
#define PKTFREE(drv, skb, send) osl_pktfree((skb))
#define PKTDATA(drv, skb) (((struct sk_buff*)(skb))->data)
#define PKTLEN(drv, skb) (((struct sk_buff*)(skb))->len)
#define PKTHEADROOM(drv, skb) (PKTDATA(drv,skb)-(((struct sk_buff*)(skb))->head))
#define PKTTAILROOM(drv, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail))
#define PKTNEXT(drv, skb) (((struct sk_buff*)(skb))->next)
#define PKTSETNEXT(skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x))
#define PKTSETLEN(drv, skb, len) __skb_trim((struct sk_buff*)(skb), (len))
#define PKTPUSH(drv, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes))
#define PKTPULL(drv, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes))
#define PKTDUP(drv, skb) skb_clone((struct sk_buff*)(skb), GFP_ATOMIC)
#define PKTCOOKIE(skb) ((void*)((struct sk_buff*)(skb))->csum)
#define PKTSETCOOKIE(skb, x) (((struct sk_buff*)(skb))->csum = (uint)(x))
#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev)
#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x))
#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority)
#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x))
extern void *osl_pktget(void *drv, uint len, bool send);
extern void osl_pktfree(void *skb);
#else /* BINOSL */
/* string library */
#ifndef LINUX_OSL
#undef printf
#define printf(fmt, args...) osl_printf((fmt), ## args)
#undef sprintf
#define sprintf(buf, fmt, args...) osl_sprintf((buf), (fmt), ## args)
#undef strcmp
#define strcmp(s1, s2) osl_strcmp((s1), (s2))
#undef strncmp
#define strncmp(s1, s2, n) osl_strncmp((s1), (s2), (n))
#undef strlen
#define strlen(s) osl_strlen((s))
#undef strcpy
#define strcpy(d, s) osl_strcpy((d), (s))
#undef strncpy
#define strncpy(d, s, n) osl_strncpy((d), (s), (n))
#endif
extern int osl_printf(const char *format, ...);
extern int osl_sprintf(char *buf, const char *format, ...);
extern int osl_strcmp(const char *s1, const char *s2);
extern int osl_strncmp(const char *s1, const char *s2, uint n);
extern int osl_strlen(char *s);
extern char* osl_strcpy(char *d, const char *s);
extern char* osl_strncpy(char *d, const char *s, uint n);
/* register access macros */
#define R_REG(r) ( \
sizeof(*(r)) == sizeof(uint8) ? osl_readb((volatile uint8*)(r)) : \
sizeof(*(r)) == sizeof(uint16) ? osl_readw((volatile uint16*)(r)) : \
osl_readl((volatile uint32*)(r)) \
)
#define W_REG(r, v) do { \
switch (sizeof(*(r))) { \
case sizeof(uint8): osl_writeb((uint8)(v), (volatile uint8*)(r)); break; \
case sizeof(uint16): osl_writew((uint16)(v), (volatile uint16*)(r)); break; \
case sizeof(uint32): osl_writel((uint32)(v), (volatile uint32*)(r)); break; \
} \
} while (0)
#define AND_REG(r, v) W_REG((r), R_REG(r) & (v))
#define OR_REG(r, v) W_REG((r), R_REG(r) | (v))
extern uint8 osl_readb(volatile uint8 *r);
extern uint16 osl_readw(volatile uint16 *r);
extern uint32 osl_readl(volatile uint32 *r);
extern void osl_writeb(uint8 v, volatile uint8 *r);
extern void osl_writew(uint16 v, volatile uint16 *r);
extern void osl_writel(uint32 v, volatile uint32 *r);
/* bcopy, bcmp, and bzero */
extern void bcopy(const void *src, void *dst, int len);
extern int bcmp(const void *b1, const void *b2, int len);
extern void bzero(void *b, int len);
/* uncached virtual address */
#define OSL_UNCACHED(va) osl_uncached((va))
extern void *osl_uncached(void *va);
/* get processor cycle count */
#define OSL_GETCYCLES(x) ((x) = osl_getcycles())
extern uint osl_getcycles(void);
/* dereference an address that may target abort */
#define BUSPROBE(val, addr) osl_busprobe(&(val), (addr))
extern int osl_busprobe(uint32 *val, uint32 addr);
/* map/unmap physical to virtual */
#define REG_MAP(pa, size) osl_reg_map((pa), (size))
#define REG_UNMAP(va) osl_reg_unmap((va))
extern void *osl_reg_map(uint32 pa, uint size);
extern void osl_reg_unmap(void *va);
/* allocate/free shared (dma-able) consistent (uncached) memory */
#define DMA_ALLOC_CONSISTENT(dev, size, pap) \
osl_dma_alloc_consistent((dev), (size), (pap))
#define DMA_FREE_CONSISTENT(dev, va, size, pa) \
osl_dma_free_consistent((dev), (void*)(va), (size), (pa))
extern void *osl_dma_alloc_consistent(void *dev, uint size, ulong *pap);
extern void osl_dma_free_consistent(void *dev, void *va, uint size, ulong pa);
/* map/unmap direction */
#define DMA_TX 1
#define DMA_RX 2
/* map/unmap shared (dma-able) memory */
#define DMA_MAP(dev, va, size, direction, p) \
osl_dma_map((dev), (va), (size), (direction))
#define DMA_UNMAP(dev, pa, size, direction, p) \
osl_dma_unmap((dev), (pa), (size), (direction))
extern uint osl_dma_map(void *dev, void *va, uint size, int direction);
extern void osl_dma_unmap(void *dev, uint pa, uint size, int direction);
/* microsecond delay */
#define OSL_DELAY(usec) osl_delay((usec))
extern void osl_delay(uint usec);
/* shared (dma-able) memory access macros */
#define R_SM(r) *(r)
#define W_SM(r, v) (*(r) = (v))
#define BZERO_SM(r, len) bzero((r), (len))
/* packet primitives */
#define PKTGET(drv, len, send) osl_pktget((drv), (len), (send))
#define PKTFREE(drv, skb, send) osl_pktfree((skb))
#define PKTDATA(drv, skb) osl_pktdata((drv), (skb))
#define PKTLEN(drv, skb) osl_pktlen((drv), (skb))
#define PKTHEADROOM(drv, skb) osl_pktheadroom((drv), (skb))
#define PKTTAILROOM(drv, skb) osl_pkttailroom((drv), (skb))
#define PKTNEXT(drv, skb) osl_pktnext((drv), (skb))
#define PKTSETNEXT(skb, x) osl_pktsetnext((skb), (x))
#define PKTSETLEN(drv, skb, len) osl_pktsetlen((drv), (skb), (len))
#define PKTPUSH(drv, skb, bytes) osl_pktpush((drv), (skb), (bytes))
#define PKTPULL(drv, skb, bytes) osl_pktpull((drv), (skb), (bytes))
#define PKTDUP(drv, skb) osl_pktdup((drv), (skb))
#define PKTCOOKIE(skb) osl_pktcookie((skb))
#define PKTSETCOOKIE(skb, x) osl_pktsetcookie((skb), (x))
#define PKTLINK(skb) osl_pktlink((skb))
#define PKTSETLINK(skb, x) osl_pktsetlink((skb), (x))
#define PKTPRIO(skb) osl_pktprio((skb))
#define PKTSETPRIO(skb, x) osl_pktsetprio((skb), (x))
extern void *osl_pktget(void *drv, uint len, bool send);
extern void osl_pktfree(void *skb);
extern uchar *osl_pktdata(void *drv, void *skb);
extern uint osl_pktlen(void *drv, void *skb);
extern uint osl_pktheadroom(void *drv, void *skb);
extern uint osl_pkttailroom(void *drv, void *skb);
extern void *osl_pktnext(void *drv, void *skb);
extern void osl_pktsetnext(void *skb, void *x);
extern void osl_pktsetlen(void *drv, void *skb, uint len);
extern uchar *osl_pktpush(void *drv, void *skb, int bytes);
extern uchar *osl_pktpull(void *drv, void *skb, int bytes);
extern void *osl_pktdup(void *drv, void *skb);
extern void *osl_pktcookie(void *skb);
extern void osl_pktsetcookie(void *skb, void *x);
extern void *osl_pktlink(void *skb);
extern void osl_pktsetlink(void *skb, void *x);
extern uint osl_pktprio(void *skb);
extern void osl_pktsetprio(void *skb, uint x);
#endif /* BINOSL */
#endif /* _linux_osl_h_ */

View File

@ -0,0 +1,392 @@
/*
* Linux-specific abstractions to gain some independence from linux kernel versions.
* Pave over some 2.2 versus 2.4 versus 2.6 kernel differences.
*
* Copyright 2004, 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$
*/
#ifndef _linuxver_h_
#define _linuxver_h_
#include <linux/config.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */
#ifdef __UNDEF_NO_VERSION__
#undef __NO_VERSION__
#else
#define __NO_VERSION__
#endif
#endif
#if defined(MODULE) && defined(MODVERSIONS)
#include <linux/modversions.h>
#endif
/* linux/malloc.h is deprecated, use linux/slab.h instead. */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9))
#include <linux/malloc.h>
#else
#include <linux/slab.h>
#endif
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <asm/io.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41))
#include <linux/workqueue.h>
#else
#include <linux/tqueue.h>
#define work_struct tq_struct
#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data))
#define schedule_work(_work) schedule_task((_work))
#define flush_scheduled_work() flush_scheduled_tasks()
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
/* Some distributions have their own 2.6.x compatibility layers */
#ifndef IRQ_NONE
typedef void irqreturn_t;
#define IRQ_NONE
#define IRQ_HANDLED
#define IRQ_RETVAL(x)
#endif
#endif
#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69))
/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which
* does this, but it's not in 2.4 so we do our own for now. */
static inline void
cs_error(client_handle_t handle, int func, int ret)
{
error_info_t err = { func, ret };
CardServices(ReportError, handle, &err);
}
#endif
#endif /* CONFIG_PCMCIA */
#ifndef __exit
#define __exit
#endif
#ifndef __devexit
#define __devexit
#endif
#ifndef __devinit
#define __devinit __init
#endif
#ifndef __devinitdata
#define __devinitdata
#endif
#ifndef __devexit_p
#define __devexit_p(x) x
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
#define pci_get_drvdata(dev) (dev)->sysdata
#define pci_set_drvdata(dev, value) (dev)->sysdata=(value)
/*
* New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration
*/
struct pci_device_id {
unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */
unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
unsigned long driver_data; /* Data private to the driver */
};
struct pci_driver {
struct list_head node;
char *name;
const struct pci_device_id *id_table; /* NULL if wants all devices */
int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
void (*suspend)(struct pci_dev *dev); /* Device suspended */
void (*resume)(struct pci_dev *dev); /* Device woken up */
};
#define MODULE_DEVICE_TABLE(type, name)
#define PCI_ANY_ID (~0)
/* compatpci.c */
#define pci_module_init pci_register_driver
extern int pci_register_driver(struct pci_driver *drv);
extern void pci_unregister_driver(struct pci_driver *drv);
#endif /* PCI registration */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18))
#ifdef MODULE
#define module_init(x) int init_module(void) { return x(); }
#define module_exit(x) void cleanup_module(void) { x(); }
#else
#define module_init(x) __initcall(x);
#define module_exit(x) __exitcall(x);
#endif
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48))
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13))
#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)])
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,44))
#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,23))
#define pci_enable_device(dev) do { } while (0)
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,14))
#define net_device device
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42))
/*
* DMA mapping
*
* See linux/Documentation/DMA-mapping.txt
*/
#ifndef PCI_DMA_TODEVICE
#define PCI_DMA_TODEVICE 1
#define PCI_DMA_FROMDEVICE 2
#endif
typedef u32 dma_addr_t;
/* Pure 2^n version of get_order */
static inline int get_order(unsigned long size)
{
int order;
size = (size-1) >> (PAGE_SHIFT-1);
order = -1;
do {
size >>= 1;
order++;
} while (size);
return order;
}
static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle)
{
void *ret;
int gfp = GFP_ATOMIC | GFP_DMA;
ret = (void *)__get_free_pages(gfp, get_order(size));
if (ret != NULL) {
memset(ret, 0, size);
*dma_handle = virt_to_bus(ret);
}
return ret;
}
static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
free_pages((unsigned long)vaddr, get_order(size));
}
#ifdef ILSIM
extern uint pci_map_single(void *dev, void *va, uint size, int direction);
extern void pci_unmap_single(void *dev, uint pa, uint size, int direction);
#else
#define pci_map_single(cookie, address, size, dir) virt_to_bus(address)
#define pci_unmap_single(cookie, address, size, dir)
#endif
#endif /* DMA mapping */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
#define dev_kfree_skb_any(a) dev_kfree_skb(a)
#define netif_down(dev) do { (dev)->start = 0; } while(0)
/* pcmcia-cs provides its own netdevice compatibility layer */
#ifndef _COMPAT_NETDEVICE_H
/*
* SoftNet
*
* For pre-softnet kernels we need to tell the upper layer not to
* re-enter start_xmit() while we are in there. However softnet
* guarantees not to enter while we are in there so there is no need
* to do the netif_stop_queue() dance unless the transmit queue really
* gets stuck. This should also improve performance according to tests
* done by Aman Singla.
*/
#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
#define netif_wake_queue(dev) do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while(0)
#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy)
static inline void netif_start_queue(struct net_device *dev)
{
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
}
#define netif_queue_stopped(dev) (dev)->tbusy
#define netif_running(dev) (dev)->start
#endif /* _COMPAT_NETDEVICE_H */
#define netif_device_attach(dev) netif_start_queue(dev)
#define netif_device_detach(dev) netif_stop_queue(dev)
/* 2.4.x renamed bottom halves to tasklets */
#define tasklet_struct tq_struct
static inline void tasklet_schedule(struct tasklet_struct *tasklet)
{
queue_task(tasklet, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
static inline void tasklet_init(struct tasklet_struct *tasklet,
void (*func)(unsigned long),
unsigned long data)
{
tasklet->next = NULL;
tasklet->sync = 0;
tasklet->routine = (void (*)(void *))func;
tasklet->data = (void *)data;
}
#define tasklet_kill(tasklet) {do{} while(0);}
/* 2.4.x introduced del_timer_sync() */
#define del_timer_sync(timer) del_timer(timer)
#else
#define netif_down(dev)
#endif /* SoftNet */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3))
/*
* Emit code to initialise a tq_struct's routine and data pointers
*/
#define PREPARE_TQUEUE(_tq, _routine, _data) \
do { \
(_tq)->routine = _routine; \
(_tq)->data = _data; \
} while (0)
/*
* Emit code to initialise all of a tq_struct
*/
#define INIT_TQUEUE(_tq, _routine, _data) \
do { \
INIT_LIST_HEAD(&(_tq)->list); \
(_tq)->sync = 0; \
PREPARE_TQUEUE((_tq), (_routine), (_data)); \
} while (0)
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6))
/* Power management related routines */
static inline int
pci_save_state(struct pci_dev *dev, u32 *buffer)
{
int i;
if (buffer) {
for (i = 0; i < 16; i++)
pci_read_config_dword(dev, i * 4,&buffer[i]);
}
return 0;
}
static inline int
pci_restore_state(struct pci_dev *dev, u32 *buffer)
{
int i;
if (buffer) {
for (i = 0; i < 16; i++)
pci_write_config_dword(dev,i * 4, buffer[i]);
}
/*
* otherwise, write the context information we know from bootup.
* This works around a problem where warm-booting from Windows
* combined with a D3(hot)->D0 transition causes PCI config
* header data to be forgotten.
*/
else {
for (i = 0; i < 6; i ++)
pci_write_config_dword(dev,
PCI_BASE_ADDRESS_0 + (i * 4),
pci_resource_start(dev, i));
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
return 0;
}
#endif /* PCI power management */
/* Old cp0 access macros deprecated in 2.4.19 */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
#define read_c0_count() read_32bit_cp0_register(CP0_COUNT)
#endif
/* Module refcount handled internally in 2.6.x */
#ifndef SET_MODULE_OWNER
#define SET_MODULE_OWNER(dev) do {} while (0)
#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
#else
#define OLD_MOD_INC_USE_COUNT do {} while (0)
#define OLD_MOD_DEC_USE_COUNT do {} while (0)
#endif
#ifndef SET_NETDEV_DEV
#define SET_NETDEV_DEV(net, pdev) do {} while (0)
#endif
#ifndef HAVE_FREE_NETDEV
#define free_netdev(dev) kfree(dev)
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
/* struct packet_type redefined in 2.6.x */
#define af_packet_priv data
#endif
#endif /* _linuxver_h_ */

View File

@ -0,0 +1,38 @@
/*
* OS Independent Layer
*
* Copyright 2004, 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$
*/
#ifndef _osl_h_
#define _osl_h_
#ifdef V2_HAL
#include <v2hal_osl.h>
#elif defined(linux)
#include <linux_osl.h>
#elif PMON
#include <pmon_osl.h>
#elif defined(NDIS)
#include <ndis_osl.h>
#elif defined(_CFE_)
#include <cfe_osl.h>
#elif defined(MACOS9)
#include <macos9_osl.h>
#elif defined(MACOSX)
#include <macosx_osl.h>
#else
#error "Unsupported OSL requested"
#endif
/* handy */
#define SET_REG(r, mask, val) W_REG((r), ((R_REG(r) & ~(mask)) | (val)))
#endif /* _osl_h_ */

View File

@ -0,0 +1,369 @@
/*
* pcicfg.h: PCI configuration constants and structures.
*
* Copyright 2004, 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$
*/
#ifndef _h_pci_
#define _h_pci_
/* The following inside ifndef's so we don't collide with NTDDK.H */
#ifndef PCI_MAX_BUS
#define PCI_MAX_BUS 0x100
#endif
#ifndef PCI_MAX_DEVICES
#define PCI_MAX_DEVICES 0x20
#endif
#ifndef PCI_MAX_FUNCTION
#define PCI_MAX_FUNCTION 0x8
#endif
#ifndef PCI_INVALID_VENDORID
#define PCI_INVALID_VENDORID 0xffff
#endif
#ifndef PCI_INVALID_DEVICEID
#define PCI_INVALID_DEVICEID 0xffff
#endif
/* Convert between bus-slot-function-register and config addresses */
#define PCICFG_BUS_SHIFT 16 /* Bus shift */
#define PCICFG_SLOT_SHIFT 11 /* Slot shift */
#define PCICFG_FUN_SHIFT 8 /* Function shift */
#define PCICFG_OFF_SHIFT 0 /* Bus shift */
#define PCICFG_BUS_MASK 0xff /* Bus mask */
#define PCICFG_SLOT_MASK 0x1f /* Slot mask */
#define PCICFG_FUN_MASK 7 /* Function mask */
#define PCICFG_OFF_MASK 0xff /* Bus mask */
#define PCI_CONFIG_ADDR(b, s, f, o) \
((((b) & PCICFG_BUS_MASK) << PCICFG_BUS_SHIFT) \
| (((s) & PCICFG_SLOT_MASK) << PCICFG_SLOT_SHIFT) \
| (((f) & PCICFG_FUN_MASK) << PCICFG_FUN_SHIFT) \
| (((o) & PCICFG_OFF_MASK) << PCICFG_OFF_SHIFT))
#define PCI_CONFIG_BUS(a) (((a) >> PCICFG_BUS_SHIFT) & PCICFG_BUS_MASK)
#define PCI_CONFIG_SLOT(a) (((a) >> PCICFG_SLOT_SHIFT) & PCICFG_SLOT_MASK)
#define PCI_CONFIG_FUN(a) (((a) >> PCICFG_FUN_SHIFT) & PCICFG_FUN_MASK)
#define PCI_CONFIG_OFF(a) (((a) >> PCICFG_OFF_SHIFT) & PCICFG_OFF_MASK)
/* The actual config space */
#define PCI_BAR_MAX 6
#define PCI_ROM_BAR 8
#define PCR_RSVDA_MAX 2
typedef struct _pci_config_regs {
unsigned short vendor;
unsigned short device;
unsigned short command;
unsigned short status;
unsigned char rev_id;
unsigned char prog_if;
unsigned char sub_class;
unsigned char base_class;
unsigned char cache_line_size;
unsigned char latency_timer;
unsigned char header_type;
unsigned char bist;
unsigned long base[PCI_BAR_MAX];
unsigned long cardbus_cis;
unsigned short subsys_vendor;
unsigned short subsys_id;
unsigned long baserom;
unsigned long rsvd_a[PCR_RSVDA_MAX];
unsigned char int_line;
unsigned char int_pin;
unsigned char min_gnt;
unsigned char max_lat;
unsigned char dev_dep[192];
} pci_config_regs;
#define SZPCR (sizeof (pci_config_regs))
#define MINSZPCR 64 /* offsetof (dev_dep[0] */
/* A structure for the config registers is nice, but in most
* systems the config space is not memory mapped, so we need
* filed offsetts. :-(
*/
#define PCI_CFG_VID 0
#define PCI_CFG_DID 2
#define PCI_CFG_CMD 4
#define PCI_CFG_STAT 6
#define PCI_CFG_REV 8
#define PCI_CFG_PROGIF 9
#define PCI_CFG_SUBCL 0xa
#define PCI_CFG_BASECL 0xb
#define PCI_CFG_CLSZ 0xc
#define PCI_CFG_LATTIM 0xd
#define PCI_CFG_HDR 0xe
#define PCI_CFG_BIST 0xf
#define PCI_CFG_BAR0 0x10
#define PCI_CFG_BAR1 0x14
#define PCI_CFG_BAR2 0x18
#define PCI_CFG_BAR3 0x1c
#define PCI_CFG_BAR4 0x20
#define PCI_CFG_BAR5 0x24
#define PCI_CFG_CIS 0x28
#define PCI_CFG_SVID 0x2c
#define PCI_CFG_SSID 0x2e
#define PCI_CFG_ROMBAR 0x30
#define PCI_CFG_INT 0x3c
#define PCI_CFG_PIN 0x3d
#define PCI_CFG_MINGNT 0x3e
#define PCI_CFG_MAXLAT 0x3f
/* Classes and subclasses */
typedef enum {
PCI_CLASS_OLD = 0,
PCI_CLASS_DASDI,
PCI_CLASS_NET,
PCI_CLASS_DISPLAY,
PCI_CLASS_MMEDIA,
PCI_CLASS_MEMORY,
PCI_CLASS_BRIDGE,
PCI_CLASS_COMM,
PCI_CLASS_BASE,
PCI_CLASS_INPUT,
PCI_CLASS_DOCK,
PCI_CLASS_CPU,
PCI_CLASS_SERIAL,
PCI_CLASS_INTELLIGENT = 0xe,
PCI_CLASS_SATELLITE,
PCI_CLASS_CRYPT,
PCI_CLASS_DSP,
PCI_CLASS_MAX
} pci_classes;
typedef enum {
PCI_DASDI_SCSI,
PCI_DASDI_IDE,
PCI_DASDI_FLOPPY,
PCI_DASDI_IPI,
PCI_DASDI_RAID,
PCI_DASDI_OTHER = 0x80
} pci_dasdi_subclasses;
typedef enum {
PCI_NET_ETHER,
PCI_NET_TOKEN,
PCI_NET_FDDI,
PCI_NET_ATM,
PCI_NET_OTHER = 0x80
} pci_net_subclasses;
typedef enum {
PCI_DISPLAY_VGA,
PCI_DISPLAY_XGA,
PCI_DISPLAY_3D,
PCI_DISPLAY_OTHER = 0x80
} pci_display_subclasses;
typedef enum {
PCI_MMEDIA_VIDEO,
PCI_MMEDIA_AUDIO,
PCI_MMEDIA_PHONE,
PCI_MEDIA_OTHER = 0x80
} pci_mmedia_subclasses;
typedef enum {
PCI_MEMORY_RAM,
PCI_MEMORY_FLASH,
PCI_MEMORY_OTHER = 0x80
} pci_memory_subclasses;
typedef enum {
PCI_BRIDGE_HOST,
PCI_BRIDGE_ISA,
PCI_BRIDGE_EISA,
PCI_BRIDGE_MC,
PCI_BRIDGE_PCI,
PCI_BRIDGE_PCMCIA,
PCI_BRIDGE_NUBUS,
PCI_BRIDGE_CARDBUS,
PCI_BRIDGE_RACEWAY,
PCI_BRIDGE_OTHER = 0x80
} pci_bridge_subclasses;
typedef enum {
PCI_COMM_UART,
PCI_COMM_PARALLEL,
PCI_COMM_MULTIUART,
PCI_COMM_MODEM,
PCI_COMM_OTHER = 0x80
} pci_comm_subclasses;
typedef enum {
PCI_BASE_PIC,
PCI_BASE_DMA,
PCI_BASE_TIMER,
PCI_BASE_RTC,
PCI_BASE_PCI_HOTPLUG,
PCI_BASE_OTHER = 0x80
} pci_base_subclasses;
typedef enum {
PCI_INPUT_KBD,
PCI_INPUT_PEN,
PCI_INPUT_MOUSE,
PCI_INPUT_SCANNER,
PCI_INPUT_GAMEPORT,
PCI_INPUT_OTHER = 0x80
} pci_input_subclasses;
typedef enum {
PCI_DOCK_GENERIC,
PCI_DOCK_OTHER = 0x80
} pci_dock_subclasses;
typedef enum {
PCI_CPU_386,
PCI_CPU_486,
PCI_CPU_PENTIUM,
PCI_CPU_ALPHA = 0x10,
PCI_CPU_POWERPC = 0x20,
PCI_CPU_MIPS = 0x30,
PCI_CPU_COPROC = 0x40,
PCI_CPU_OTHER = 0x80
} pci_cpu_subclasses;
typedef enum {
PCI_SERIAL_IEEE1394,
PCI_SERIAL_ACCESS,
PCI_SERIAL_SSA,
PCI_SERIAL_USB,
PCI_SERIAL_FIBER,
PCI_SERIAL_SMBUS,
PCI_SERIAL_OTHER = 0x80
} pci_serial_subclasses;
typedef enum {
PCI_INTELLIGENT_I2O,
} pci_intelligent_subclasses;
typedef enum {
PCI_SATELLITE_TV,
PCI_SATELLITE_AUDIO,
PCI_SATELLITE_VOICE,
PCI_SATELLITE_DATA,
PCI_SATELLITE_OTHER = 0x80
} pci_satellite_subclasses;
typedef enum {
PCI_CRYPT_NETWORK,
PCI_CRYPT_ENTERTAINMENT,
PCI_CRYPT_OTHER = 0x80
} pci_crypt_subclasses;
typedef enum {
PCI_DSP_DPIO,
PCI_DSP_OTHER = 0x80
} pci_dsp_subclasses;
/* Header types */
typedef enum {
PCI_HEADER_NORMAL,
PCI_HEADER_BRIDGE,
PCI_HEADER_CARDBUS
} pci_header_types;
/* Overlay for a PCI-to-PCI bridge */
#define PPB_RSVDA_MAX 2
#define PPB_RSVDD_MAX 8
typedef struct _ppb_config_regs {
unsigned short vendor;
unsigned short device;
unsigned short command;
unsigned short status;
unsigned char rev_id;
unsigned char prog_if;
unsigned char sub_class;
unsigned char base_class;
unsigned char cache_line_size;
unsigned char latency_timer;
unsigned char header_type;
unsigned char bist;
unsigned long rsvd_a[PPB_RSVDA_MAX];
unsigned char prim_bus;
unsigned char sec_bus;
unsigned char sub_bus;
unsigned char sec_lat;
unsigned char io_base;
unsigned char io_lim;
unsigned short sec_status;
unsigned short mem_base;
unsigned short mem_lim;
unsigned short pf_mem_base;
unsigned short pf_mem_lim;
unsigned long pf_mem_base_hi;
unsigned long pf_mem_lim_hi;
unsigned short io_base_hi;
unsigned short io_lim_hi;
unsigned short subsys_vendor;
unsigned short subsys_id;
unsigned long rsvd_b;
unsigned char rsvd_c;
unsigned char int_pin;
unsigned short bridge_ctrl;
unsigned char chip_ctrl;
unsigned char diag_ctrl;
unsigned short arb_ctrl;
unsigned long rsvd_d[PPB_RSVDD_MAX];
unsigned char dev_dep[192];
} ppb_config_regs;
/* Eveything below is BRCM HND proprietary */
#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */
#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */
#define PCI_SPROM_CONTROL 0x88 /* sprom property control */
#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */
#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */
#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */
#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */
#define PCI_BACKPLANE_ADDR 0xA0 /* address an arbitrary location on the system backplane */
#define PCI_BACKPLANE_DATA 0xA4 /* data at the location specified by above address register */
#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */
#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */
#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */
#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */
#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */
/* PCI_INT_STATUS */
#define PCI_SBIM_STATUS_SERR 0x4 /* backplane SBErr interrupt status */
/* PCI_INT_MASK */
#define PCI_SBIM_SHIFT 8 /* backplane core interrupt mask bits offset */
#define PCI_SBIM_MASK 0xff00 /* backplane core interrupt mask */
#define PCI_SBIM_MASK_SERR 0x4 /* backplane SBErr interrupt mask */
/* PCI_SPROM_CONTROL */
#define SPROM_BLANK 0x04 /* indicating a blank sprom */
#define SPROM_WRITEEN 0x10 /* sprom write enable */
#define SPROM_BOOTROM_WE 0x20 /* external bootrom write enable */
#define SPROM_SIZE 256 /* sprom size in 16-bit */
#define SPROM_CRC_RANGE 64 /* crc cover range in 16-bit */
/* PCI_CFG_CMD_STAT */
#define PCI_CFG_CMD_STAT_TA 0x08000000 /* target abort status */
#endif

View File

@ -0,0 +1,852 @@
/*
* Copyright 2004, 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.
*
* Fundamental types and constants relating to 802.11
*
* $Id$
*/
#ifndef _802_11_H_
#define _802_11_H_
#ifndef _TYPEDEFS_H_
#include <typedefs.h>
#endif
#ifndef _NET_ETHERNET_H_
#include <proto/ethernet.h>
#endif
/* enable structure packing */
#if !defined(__GNUC__)
#pragma pack(1)
#endif
/* some platforms require stronger medicine */
#if defined(__GNUC__)
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif
#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */
/* Generic 802.11 frame constants */
#define DOT11_A3_HDR_LEN 24
#define DOT11_A4_HDR_LEN 30
#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN
#define DOT11_FCS_LEN 4
#define DOT11_ICV_LEN 4
#define DOT11_ICV_AES_LEN 8
#define DOT11_QOS_LEN 2
#define DOT11_KEY_INDEX_SHIFT 6
#define DOT11_IV_LEN 4
#define DOT11_IV_TKIP_LEN 8
#define DOT11_IV_AES_OCB_LEN 4
#define DOT11_IV_AES_CCM_LEN 8
/* Includes MIC */
#define DOT11_MAX_MPDU_BODY_LEN 2304
/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */
#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \
DOT11_QOS_LEN + \
DOT11_IV_AES_CCM_LEN + \
DOT11_MAX_MPDU_BODY_LEN + \
DOT11_ICV_LEN + \
DOT11_FCS_LEN)
#define DOT11_MAX_SSID_LEN 32
/* dot11RTSThreshold */
#define DOT11_DEFAULT_RTS_LEN 2347
#define DOT11_MAX_RTS_LEN 2347
/* dot11FragmentationThreshold */
#define DOT11_MIN_FRAG_LEN 256
#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength of the attached PHY */
#define DOT11_DEFAULT_FRAG_LEN 2346
/* dot11BeaconPeriod */
#define DOT11_MIN_BEACON_PERIOD 1
#define DOT11_MAX_BEACON_PERIOD 0xFFFF
/* dot11DTIMPeriod */
#define DOT11_MIN_DTIM_PERIOD 1
#define DOT11_MAX_DTIM_PERIOD 0xFF
/* 802.2 LLC/SNAP header used by 802.11 per 802.1H */
#define DOT11_LLC_SNAP_HDR_LEN 8
#define DOT11_OUI_LEN 3
struct dot11_llc_snap_header {
uint8 dsap; /* always 0xAA */
uint8 ssap; /* always 0xAA */
uint8 ctl; /* always 0x03 */
uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00
Bridge-Tunnel: 0x00 0x00 0xF8 */
uint16 type; /* ethertype */
} PACKED;
/* RFC1042 header used by 802.11 per 802.1H */
#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN)
/* Generic 802.11 MAC header */
/*
* N.B.: This struct reflects the full 4 address 802.11 MAC header.
* The fields are defined such that the shorter 1, 2, and 3
* address headers just use the first k fields.
*/
struct dot11_header {
uint16 fc; /* frame control */
uint16 durid; /* duration/ID */
struct ether_addr a1; /* address 1 */
struct ether_addr a2; /* address 2 */
struct ether_addr a3; /* address 3 */
uint16 seq; /* sequence control */
struct ether_addr a4; /* address 4 */
} PACKED;
/* Control frames */
struct dot11_rts_frame {
uint16 fc; /* frame control */
uint16 durid; /* duration/ID */
struct ether_addr ra; /* receiver address */
struct ether_addr ta; /* transmitter address */
} PACKED;
#define DOT11_RTS_LEN 16
struct dot11_cts_frame {
uint16 fc; /* frame control */
uint16 durid; /* duration/ID */
struct ether_addr ra; /* receiver address */
} PACKED;
#define DOT11_CTS_LEN 10
struct dot11_ack_frame {
uint16 fc; /* frame control */
uint16 durid; /* duration/ID */
struct ether_addr ra; /* receiver address */
} PACKED;
#define DOT11_ACK_LEN 10
struct dot11_ps_poll_frame {
uint16 fc; /* frame control */
uint16 durid; /* AID */
struct ether_addr bssid; /* receiver address, STA in AP */
struct ether_addr ta; /* transmitter address */
} PACKED;
#define DOT11_PS_POLL_LEN 16
struct dot11_cf_end_frame {
uint16 fc; /* frame control */
uint16 durid; /* duration/ID */
struct ether_addr ra; /* receiver address */
struct ether_addr bssid; /* transmitter address, STA in AP */
} PACKED;
#define DOT11_CS_END_LEN 16
/* Management frame header */
struct dot11_management_header {
uint16 fc; /* frame control */
uint16 durid; /* duration/ID */
struct ether_addr da; /* receiver address */
struct ether_addr sa; /* transmitter address */
struct ether_addr bssid; /* BSS ID */
uint16 seq; /* sequence control */
} PACKED;
#define DOT11_MGMT_HDR_LEN 24
/* Management frame payloads */
struct dot11_bcn_prb {
uint32 timestamp[2];
uint16 beacon_interval;
uint16 capability;
} PACKED;
#define DOT11_BCN_PRB_LEN 12
struct dot11_auth {
uint16 alg; /* algorithm */
uint16 seq; /* sequence control */
uint16 status; /* status code */
} PACKED;
#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge info elt */
struct dot11_assoc_req {
uint16 capability; /* capability information */
uint16 listen; /* listen interval */
} PACKED;
struct dot11_assoc_resp {
uint16 capability; /* capability information */
uint16 status; /* status code */
uint16 aid; /* association ID */
} PACKED;
struct dot11_action_measure {
uint8 category;
uint8 action;
uint8 token;
uint8 data[1];
} PACKED;
#define DOT11_ACTION_MEASURE_LEN 3
/**************
802.11h related definitions.
**************/
typedef struct {
uint8 id;
uint8 len;
uint8 power;
} dot11_power_cnst_t;
typedef struct {
uint8 min;
uint8 max;
} dot11_power_cap_t;
typedef struct {
uint8 id;
uint8 len;
uint8 tx_pwr;
uint8 margin;
} dot11_tpc_rep_t;
#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */
typedef struct {
uint8 id;
uint8 len;
uint8 first_channel;
uint8 num_channels;
} dot11_supp_channels_t;
struct dot11_channel_switch {
uint8 id;
uint8 len;
uint8 mode;
uint8 channel;
uint8 count;
} PACKED;
typedef struct dot11_channel_switch dot11_channel_switch_t;
/* 802.11h Measurement Request/Report IEs */
/* Measurement Type field */
#define DOT11_MEASURE_TYPE_BASIC 0
#define DOT11_MEASURE_TYPE_CCA 1
#define DOT11_MEASURE_TYPE_RPI 2
/* Measurement Mode field */
/* Measurement Request Modes */
#define DOT11_MEASURE_MODE_ENABLE (1<<1)
#define DOT11_MEASURE_MODE_REQUEST (1<<2)
#define DOT11_MEASURE_MODE_REPORT (1<<3)
/* Measurement Report Modes */
#define DOT11_MEASURE_MODE_LATE (1<<0)
#define DOT11_MEASURE_MODE_INCAPABLE (1<<1)
#define DOT11_MEASURE_MODE_REFUSED (1<<2)
/* Basic Measurement Map bits */
#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0))
#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1))
#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2))
#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3))
#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4))
typedef struct {
uint8 id;
uint8 len;
uint8 token;
uint8 mode;
uint8 type;
uint8 channel;
uint8 start_time[8];
uint16 duration;
} dot11_meas_req_t;
#define DOT11_MNG_IE_MREQ_LEN 14
/* length of Measure Request IE data not including variable len */
#define DOT11_MNG_IE_MREQ_FIXED_LEN 3
struct dot11_meas_rep {
uint8 id;
uint8 len;
uint8 token;
uint8 mode;
uint8 type;
union
{
struct {
uint8 channel;
uint8 start_time[8];
uint16 duration;
uint8 map;
} PACKED basic;
uint8 data[1];
} PACKED rep;
} PACKED;
typedef struct dot11_meas_rep dot11_meas_rep_t;
/* length of Measure Report IE data not including variable len */
#define DOT11_MNG_IE_MREP_FIXED_LEN 3
struct dot11_meas_rep_basic {
uint8 channel;
uint8 start_time[8];
uint16 duration;
uint8 map;
} PACKED;
typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t;
#define DOT11_MEASURE_BASIC_REP_LEN 12
struct dot11_quiet {
uint8 id;
uint8 len;
uint8 count; /* TBTTs until beacon interval in quiet starts */
uint8 period; /* Beacon intervals between periodic quiet periods ? */
uint16 duration;/* Length of quiet period, in TU's */
uint16 offset; /* TU's offset from TBTT in Count field */
} PACKED;
typedef struct dot11_quiet dot11_quiet_t;
typedef struct {
uint8 channel;
uint8 map;
} chan_map_tuple_t;
typedef struct {
uint8 id;
uint8 len;
uint8 eaddr[ETHER_ADDR_LEN];
uint8 interval;
chan_map_tuple_t map[1];
} dot11_ibss_dfs_t;
/* WME Elements */
#define WME_OUI "\x00\x50\xf2"
#define WME_VER 1
#define WME_TYPE 2
#define WME_SUBTYPE_IE 0 /* Information Element */
#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */
#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */
/* WME Access Category Indices (ACIs) */
#define AC_BE 0 /* Best Effort */
#define AC_BK 1 /* Background */
#define AC_VI 2 /* Video */
#define AC_VO 3 /* Voice */
#define AC_MAX 4
/* WME Information Element (IE) */
struct wme_ie {
uint8 oui[3];
uint8 type;
uint8 subtype;
uint8 version;
uint8 acinfo;
} PACKED;
typedef struct wme_ie wme_ie_t;
#define WME_IE_LEN 7
struct wme_acparam {
uint8 ACI;
uint8 ECW;
uint16 TXOP; /* stored in network order (ls octet first) */
} PACKED;
typedef struct wme_acparam wme_acparam_t;
/* WME Parameter Element (PE) */
struct wme_params {
uint8 oui[3];
uint8 type;
uint8 subtype;
uint8 version;
uint8 acinfo;
uint8 rsvd;
wme_acparam_t acparam[4];
} PACKED;
typedef struct wme_params wme_params_t;
#define WME_PARAMS_IE_LEN 24
/* acinfo */
#define WME_COUNT_MASK 0x0f
/* ACI */
#define WME_AIFS_MASK 0x0f
#define WME_ACM_MASK 0x10
#define WME_ACI_MASK 0x60
#define WME_ACI_SHIFT 5
/* ECW */
#define WME_CWMIN_MASK 0x0f
#define WME_CWMAX_MASK 0xf0
#define WME_CWMAX_SHIFT 4
#define WME_TXOP_UNITS 32
/* WME Traffic Specification (TSPEC) element */
#define WME_SUBTYPE_TSPEC 2
#define WME_TSPEC_HDR_LEN 2
#define WME_TSPEC_BODY_OFF 2
struct wme_tspec {
uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */
uint8 type; /* WME_TYPE */
uint8 subtype; /* WME_SUBTYPE_TSPEC */
uint8 version; /* WME_VERSION */
uint16 ts_info; /* TS Info */
uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */
uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */
uint32 min_service_interval; /* Minimum Service Interval (us) */
uint32 max_service_interval; /* Maximum Service Interval (us) */
uint32 inactivity_interval; /* Inactivity Interval (us) */
uint32 service_start; /* Service Start Time (us) */
uint32 min_rate; /* Minimum Data Rate (bps) */
uint32 mean_rate; /* Mean Data Rate (bps) */
uint32 max_burst_size; /* Maximum Burst Size (bytes) */
uint32 min_phy_rate; /* Minimum PHY Rate (bps) */
uint32 peak_rate; /* Peak Data Rate (bps) */
uint32 delay_bound; /* Delay Bound (us) */
uint16 surplus_bandwidth; /* Surplus Bandwidth Allowance Factor */
uint16 medium_time; /* Medium Time (32 us/s periods) */
} PACKED;
typedef struct wme_tspec wme_tspec_t;
#define WME_TSPEC_LEN 56 /* not including 2-byte header */
/* ts_info */
/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */
#define TS_INFO_PRIO_SHIFT_HI 11
#define TS_INFO_PRIO_MASK_HI (0x7 << TS_INFO_PRIO_SHIFT_HI)
#define TS_INFO_PRIO_SHIFT_LO 1
#define TS_INFO_PRIO_MASK_LO (0x7 << TS_INFO_PRIO_SHIFT_LO)
#define TS_INFO_CONTENTION_SHIFT 7
#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT)
#define TS_INFO_DIRECTION_SHIFT 5
#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT)
#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT)
#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT)
#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT)
/* nom_msdu_size */
#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */
#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */
/* surplus_bandwidth */
/* Represented as 3 bits of integer, binary point, 13 bits fraction */
#define INTEGER_SHIFT 13
#define FRACTION_MASK 0x1FFF
/* Management Notification Frame */
struct dot11_management_notification {
uint8 category; /* DOT11_ACTION_NOTIFICATION */
uint8 action;
uint8 token;
uint8 status;
uint8 data[1]; /* Elements */
} PACKED;
#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */
/* WME Action Codes */
#define WME_SETUP_REQUEST 0
#define WME_SETUP_RESPONSE 1
#define WME_TEARDOWN 2
/* WME Setup Response Status Codes */
#define WME_ADMISSION_ACCEPTED 0
#define WME_INVALID_PARAMETERS 1
#define WME_ADMISSION_REFUSED 3
/* Macro to take a pointer to a beacon or probe response
* header and return the char* pointer to the SSID info element
*/
#define BCN_PRB_SSID(hdr) ((char*)(hdr) + DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_LEN)
/* Authentication frame payload constants */
#define DOT11_OPEN_SYSTEM 0
#define DOT11_SHARED_KEY 1
#define DOT11_CHALLENGE_LEN 128
/* Frame control macros */
#define FC_PVER_MASK 0x3
#define FC_PVER_SHIFT 0
#define FC_TYPE_MASK 0xC
#define FC_TYPE_SHIFT 2
#define FC_SUBTYPE_MASK 0xF0
#define FC_SUBTYPE_SHIFT 4
#define FC_TODS 0x100
#define FC_TODS_SHIFT 8
#define FC_FROMDS 0x200
#define FC_FROMDS_SHIFT 9
#define FC_MOREFRAG 0x400
#define FC_MOREFRAG_SHIFT 10
#define FC_RETRY 0x800
#define FC_RETRY_SHIFT 11
#define FC_PM 0x1000
#define FC_PM_SHIFT 12
#define FC_MOREDATA 0x2000
#define FC_MOREDATA_SHIFT 13
#define FC_WEP 0x4000
#define FC_WEP_SHIFT 14
#define FC_ORDER 0x8000
#define FC_ORDER_SHIFT 15
/* sequence control macros */
#define SEQNUM_SHIFT 4
#define FRAGNUM_MASK 0xF
/* Frame Control type/subtype defs */
/* FC Types */
#define FC_TYPE_MNG 0
#define FC_TYPE_CTL 1
#define FC_TYPE_DATA 2
/* Management Subtypes */
#define FC_SUBTYPE_ASSOC_REQ 0
#define FC_SUBTYPE_ASSOC_RESP 1
#define FC_SUBTYPE_REASSOC_REQ 2
#define FC_SUBTYPE_REASSOC_RESP 3
#define FC_SUBTYPE_PROBE_REQ 4
#define FC_SUBTYPE_PROBE_RESP 5
#define FC_SUBTYPE_BEACON 8
#define FC_SUBTYPE_ATIM 9
#define FC_SUBTYPE_DISASSOC 10
#define FC_SUBTYPE_AUTH 11
#define FC_SUBTYPE_DEAUTH 12
#define FC_SUBTYPE_ACTION 13
/* Control Subtypes */
#define FC_SUBTYPE_PS_POLL 10
#define FC_SUBTYPE_RTS 11
#define FC_SUBTYPE_CTS 12
#define FC_SUBTYPE_ACK 13
#define FC_SUBTYPE_CF_END 14
#define FC_SUBTYPE_CF_END_ACK 15
/* Data Subtypes */
#define FC_SUBTYPE_DATA 0
#define FC_SUBTYPE_DATA_CF_ACK 1
#define FC_SUBTYPE_DATA_CF_POLL 2
#define FC_SUBTYPE_DATA_CF_ACK_POLL 3
#define FC_SUBTYPE_NULL 4
#define FC_SUBTYPE_CF_ACK 5
#define FC_SUBTYPE_CF_POLL 6
#define FC_SUBTYPE_CF_ACK_POLL 7
#define FC_SUBTYPE_QOS_DATA 8
#define FC_SUBTYPE_QOS_NULL 12
/* type-subtype combos */
#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK)
#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT))
#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ)
#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP)
#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ)
#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP)
#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ)
#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP)
#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON)
#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC)
#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH)
#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH)
#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION)
#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL)
#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS)
#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS)
#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK)
#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END)
#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK)
#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA)
#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL)
#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK)
#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA)
#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL)
/* QoS Control Field */
/* 802.1D Tag */
#define QOS_PRIO_SHIFT 0
#define QOS_PRIO_MASK 0x0007
#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT)
/* Ack Policy (0 means Acknowledge) */
#define QOS_ACK_SHIFT 5
#define QOS_ACK_MASK 0x0060
#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT)
/* Management Frames */
/* Management Frame Constants */
/* Fixed fields */
#define DOT11_MNG_AUTH_ALGO_LEN 2
#define DOT11_MNG_AUTH_SEQ_LEN 2
#define DOT11_MNG_BEACON_INT_LEN 2
#define DOT11_MNG_CAP_LEN 2
#define DOT11_MNG_AP_ADDR_LEN 6
#define DOT11_MNG_LISTEN_INT_LEN 2
#define DOT11_MNG_REASON_LEN 2
#define DOT11_MNG_AID_LEN 2
#define DOT11_MNG_STATUS_LEN 2
#define DOT11_MNG_TIMESTAMP_LEN 8
/* DUR/ID field in assoc resp is 0xc000 | AID */
#define DOT11_AID_MASK 0x3fff
/* Reason Codes */
#define DOT11_RC_RESERVED 0
#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */
#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */
#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station is
leaving (or has left) IBSS or ESS */
#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */
#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle
all currently associated stations */
#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from
nonauthenticated station */
#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from
nonassociated station */
#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is
leaving (or has left) BSS */
#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is
not authenticated with responding station */
#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */
/* Status Codes */
#define DOT11_STATUS_SUCCESS 0 /* Successful */
#define DOT11_STATUS_FAILURE 1 /* Unspecified failure */
#define DOT11_STATUS_CAP_MISMATCH 10 /* Cannot support all requested capabilities
in the Capability Information field */
#define DOT11_STATUS_REASSOC_FAIL 11 /* Reassociation denied due to inability to
confirm that association exists */
#define DOT11_STATUS_ASSOC_FAIL 12 /* Association denied due to reason outside
the scope of this standard */
#define DOT11_STATUS_AUTH_MISMATCH 13 /* Responding station does not support the
specified authentication algorithm */
#define DOT11_STATUS_AUTH_SEQ 14 /* Received an Authentication frame with
authentication transaction sequence number
out of expected sequence */
#define DOT11_STATUS_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of challenge failure */
#define DOT11_STATUS_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout waiting
for next frame in sequence */
#define DOT11_STATUS_ASSOC_BUSY_FAIL 17 /* Association denied because AP is unable to
handle additional associated stations */
#define DOT11_STATUS_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting station
not supporting all of the data rates in the
BSSBasicRateSet parameter */
#define DOT11_STATUS_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting station
not supporting the Short Preamble option */
#define DOT11_STATUS_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting station
not supporting the PBCC Modulation option */
#define DOT11_STATUS_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting station
not supporting the Channel Agility option */
#define DOT11_STATUS_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum Management
capability is required. */
#define DOT11_STATUS_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info in the
Power Cap element is unacceptable. */
#define DOT11_STATUS_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info in the
Supported Channel element is unacceptable */
#define DOT11_STATUS_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting station
not supporting the Short Slot Time option */
#define DOT11_STATUS_ASSOC_ERPBCC_REQUIRED 26 /* Association denied due to requesting station
not supporting the ER-PBCC Modulation option */
#define DOT11_STATUS_ASSOC_DSSOFDM_REQUIRED 27 /* Association denied due to requesting station
not supporting the DSS-OFDM option */
/* Info Elts, length of INFORMATION portion of Info Elts */
#define DOT11_MNG_DS_PARAM_LEN 1
#define DOT11_MNG_IBSS_PARAM_LEN 2
/* TIM Info element has 3 bytes fixed info in INFORMATION field,
* followed by 1 to 251 bytes of Partial Virtual Bitmap */
#define DOT11_MNG_TIM_FIXED_LEN 3
#define DOT11_MNG_TIM_DTIM_COUNT 0
#define DOT11_MNG_TIM_DTIM_PERIOD 1
#define DOT11_MNG_TIM_BITMAP_CTL 2
#define DOT11_MNG_TIM_PVB 3
/* TLV defines */
#define TLV_TAG_OFF 0
#define TLV_LEN_OFF 1
#define TLV_HDR_LEN 2
#define TLV_BODY_OFF 2
/* Management Frame Information Element IDs */
#define DOT11_MNG_SSID_ID 0
#define DOT11_MNG_RATES_ID 1
#define DOT11_MNG_FH_PARMS_ID 2
#define DOT11_MNG_DS_PARMS_ID 3
#define DOT11_MNG_CF_PARMS_ID 4
#define DOT11_MNG_TIM_ID 5
#define DOT11_MNG_IBSS_PARMS_ID 6
#define DOT11_MNG_COUNTRY_ID 7
#define DOT11_MNG_HOPPING_PARMS_ID 8
#define DOT11_MNG_HOPPING_TABLE_ID 9
#define DOT11_MNG_REQUEST_ID 10
#define DOT11_MNG_CHALLENGE_ID 16
#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */
#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */
#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */
#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */
#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */
#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement*/
#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */
#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */
#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */
#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */
#define DOT11_MNG_ERP_ID 42
#define DOT11_MNG_NONERP_ID 47
#define DOT11_MNG_EXT_RATES_ID 50
#define DOT11_MNG_WPA_ID 221
#define DOT11_MNG_PROPR_ID 221
/* ERP info element bit values */
#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */
#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present in the BSS */
#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for ERP-OFDM frames */
#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, 1 == not allowed */
/* Capability Information Field */
#define DOT11_CAP_ESS 0x0001
#define DOT11_CAP_IBSS 0x0002
#define DOT11_CAP_POLLABLE 0x0004
#define DOT11_CAP_POLL_RQ 0x0008
#define DOT11_CAP_PRIVACY 0x0010
#define DOT11_CAP_SHORT 0x0020
#define DOT11_CAP_PBCC 0x0040
#define DOT11_CAP_AGILITY 0x0080
#define DOT11_CAP_SPECTRUM 0x0100
#define DOT11_CAP_SHORTSLOT 0x0400
#define DOT11_CAP_CCK_OFDM 0x2000
/* Action Frame Constants */
#define DOT11_ACTION_CAT_ERR_MASK 0x80
#define DOT11_ACTION_CAT_SPECT_MNG 0x00
#define DOT11_ACTION_NOTIFICATION 0x11 /* 17 */
#define DOT11_ACTION_ID_M_REQ 0
#define DOT11_ACTION_ID_M_REP 1
#define DOT11_ACTION_ID_TPC_REQ 2
#define DOT11_ACTION_ID_TPC_REP 3
#define DOT11_ACTION_ID_CHANNEL_SWITCH 4
/* MLME Enumerations */
#define DOT11_BSSTYPE_INFRASTRUCTURE 0
#define DOT11_BSSTYPE_INDEPENDENT 1
#define DOT11_BSSTYPE_ANY 2
#define DOT11_SCANTYPE_ACTIVE 0
#define DOT11_SCANTYPE_PASSIVE 1
/* 802.11 A PHY constants */
#define APHY_SLOT_TIME 9
#define APHY_SIFS_TIME 16
#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME))
#define APHY_PREAMBLE_TIME 16
#define APHY_SIGNAL_TIME 4
#define APHY_SYMBOL_TIME 4
#define APHY_SERVICE_NBITS 16
#define APHY_TAIL_NBITS 6
#define APHY_CWMIN 15
/* 802.11 B PHY constants */
#define BPHY_SLOT_TIME 20
#define BPHY_SIFS_TIME 10
#define BPHY_DIFS_TIME 50
#define BPHY_PLCP_TIME 192
#define BPHY_PLCP_SHORT_TIME 96
#define BPHY_CWMIN 31
/* 802.11 G constants */
#define DOT11_OFDM_SIGNAL_EXTENSION 6
#define PHY_CWMAX 1023
#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */
/* dot11Counters Table - 802.11 spec., Annex D */
typedef struct d11cnt {
uint32 txfrag; /* dot11TransmittedFragmentCount */
uint32 txmulti; /* dot11MulticastTransmittedFrameCount */
uint32 txfail; /* dot11FailedCount */
uint32 txretry; /* dot11RetryCount */
uint32 txretrie; /* dot11MultipleRetryCount */
uint32 rxdup; /* dot11FrameduplicateCount */
uint32 txrts; /* dot11RTSSuccessCount */
uint32 txnocts; /* dot11RTSFailureCount */
uint32 txnoack; /* dot11ACKFailureCount */
uint32 rxfrag; /* dot11ReceivedFragmentCount */
uint32 rxmulti; /* dot11MulticastReceivedFrameCount */
uint32 rxcrc; /* dot11FCSErrorCount */
uint32 txfrmsnt; /* dot11TransmittedFrameCount */
uint32 rxundec; /* dot11WEPUndecryptableCount */
} d11cnt_t;
/* BRCM OUI */
#define BRCM_OUI "\x00\x10\x18"
/* BRCM info element */
struct brcm_ie {
uchar id;
uchar len;
uchar oui[3];
uchar ver;
uchar assoc; /* # of assoc STAs */
uchar flags; /* misc flags */
} PACKED;
#define BRCM_IE_LEN 8
typedef struct brcm_ie brcm_ie_t;
#define BRCM_IE_VER 1
/* brcm_ie flags */
#define BRF_ABCAP 0x1 /* afterburner capable */
#define BRF_ABRQRD 0x2 /* afterburner requested */
/* WPA definitions */
#define WPA_VERSION 1
#define WPA_OUI "\x00\x50\xF2"
#define WPA_OUI_LEN 3
/* WPA authentication modes */
#define WPA_AUTH_NONE 0 /* None */
#define WPA_AUTH_UNSPECIFIED 1 /* Unspecified authentication over 802.1X: default for WPA */
#define WPA_AUTH_PSK 2 /* Pre-shared Key over 802.1X */
#define WPA_AUTH_DISABLED 255 /* Legacy (i.e., non-WPA) */
#define IS_WPA_AUTH(auth) ((auth) == WPA_AUTH_NONE || \
(auth) == WPA_AUTH_UNSPECIFIED || \
(auth) == WPA_AUTH_PSK)
/* Key related defines */
#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */
#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */
#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */
#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */
#define WEP1_KEY_SIZE 5 /* max size of any WEP key */
#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */
#define WEP128_KEY_SIZE 13 /* max size of any WEP key */
#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */
#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */
#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */
#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */
#define TKIP_KEY_SIZE 32 /* size of any TKIP key */
#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */
#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */
#define TKIP_MIC_SUP_RX 16 /* offset to Supplicant MIC RX key */
#define TKIP_MIC_SUP_TX 24 /* offset to Supplicant MIC TX key */
#define AES_KEY_SIZE 16 /* size of AES key */
#undef PACKED
#if !defined(__GNUC__)
#pragma pack()
#endif
#endif /* _802_11_H_ */

View File

@ -0,0 +1,164 @@
/*******************************************************************************
* $Id$
* Copyright 2004, 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.
* From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
******************************************************************************/
#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */
#define _NET_ETHERNET_H_
#ifndef _TYPEDEFS_H_
#include "typedefs.h"
#endif
#if defined(__GNUC__)
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif
/*
* The number of bytes in an ethernet (MAC) address.
*/
#define ETHER_ADDR_LEN 6
/*
* The number of bytes in the type field.
*/
#define ETHER_TYPE_LEN 2
/*
* The number of bytes in the trailing CRC field.
*/
#define ETHER_CRC_LEN 4
/*
* The length of the combined header.
*/
#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN)
/*
* The minimum packet length.
*/
#define ETHER_MIN_LEN 64
/*
* The minimum packet user data length.
*/
#define ETHER_MIN_DATA 46
/*
* The maximum packet length.
*/
#define ETHER_MAX_LEN 1518
/*
* The maximum packet user data length.
*/
#define ETHER_MAX_DATA 1500
/*
* Used to uniquely identify a 802.1q VLAN-tagged header.
*/
#define VLAN_TAG 0x8100
/*
* Located after dest & src address in ether header.
*/
#define VLAN_FIELDS_OFFSET (ETHER_ADDR_LEN * 2)
/*
* 4 bytes of vlan field info.
*/
#define VLAN_FIELDS_SIZE 4
/* location of bits in 16-bit vlan fields */
#define VLAN_PRI_SHIFT 13 /* user priority */
#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */
/* 3 bits of priority */
#define VLAN_PRI_MASK 7
/* 12 bits of vlan identfier (VID) */
#define VLAN_VID_MASK 0xFFF /* VLAN identifier (VID) field */
struct vlan_tags {
uint16 tag_type; /* 0x8100 for VLAN */
uint16 tag_control; /* prio | cfi | vid */
} PACKED ;
/* 802.1X ethertype */
#define ETHER_TYPE_IP 0x0800 /* IP */
#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */
#define ETHER_TYPE_802_1X 0x888e /* 802.1x */
#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4byte subtype follows ethertype */
#define ETHER_BRCM_CRAM 0x1 /* Broadcom subtype cram protocol */
/*
* A macro to validate a length with
*/
#define ETHER_IS_VALID_LEN(foo) \
((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN)
#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */
/*
* Structure of a 10Mb/s Ethernet header.
*/
struct ether_header {
uint8 ether_dhost[ETHER_ADDR_LEN];
uint8 ether_shost[ETHER_ADDR_LEN];
uint16 ether_type;
} PACKED ;
/*
* Structure of a 48-bit Ethernet address.
*/
struct ether_addr {
uint8 octet[ETHER_ADDR_LEN];
} PACKED ;
#endif
/*
* Takes a pointer, returns true if a 48-bit multicast address
* (including broadcast, since it is all ones)
*/
#define ETHER_ISMULTI(ea) (((uint8 *)(ea))[0] & 1)
/*
* Takes a pointer, returns true if a 48-bit broadcast (all ones)
*/
#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \
((uint8 *)(ea))[1] & \
((uint8 *)(ea))[2] & \
((uint8 *)(ea))[3] & \
((uint8 *)(ea))[4] & \
((uint8 *)(ea))[5]) == 0xff)
static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
/*
* Takes a pointer, returns true if a 48-bit null address (all zeros)
*/
#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \
((uint8 *)(ea))[1] | \
((uint8 *)(ea))[2] | \
((uint8 *)(ea))[3] | \
((uint8 *)(ea))[4] | \
((uint8 *)(ea))[5]) == 0)
/* Differentiated Services Codepoint - lower 6 bits of tos in iphdr */
#define DSCP_PRI_MASK 0x3F /* bits 0-6 */
#define DSCP_WME_PRI_MASK 0x38 /* bits 3-6 */
#define DSCP_WME_PRI_SHIFT 3
#undef PACKED
#endif /* _NET_ETHERNET_H_ */

View File

@ -0,0 +1,367 @@
/*
* SiliconBackplane Chipcommon core hardware definitions.
*
* The chipcommon core provides chip identification, SB control,
* jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer,
* gpio interface, extbus, and support for serial and parallel flashes.
*
* $Id$
* Copyright 2004, 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.
*
*/
#ifndef _SBCHIPC_H
#define _SBCHIPC_H
#ifndef _LANGUAGE_ASSEMBLY
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif /* PAD */
typedef volatile struct {
uint32 chipid; /* 0x0 */
uint32 capabilities;
uint32 corecontrol; /* corerev >= 1 */
uint32 bist;
/* OTP */
uint32 otpstatus; /* 0x10, corerev >= 10 */
uint32 otpcontrol;
uint32 otpprog;
uint32 PAD;
/* Interrupt control */
uint32 intstatus; /* 0x20 */
uint32 intmask;
uint32 PAD[2];
/* Jtag Master */
uint32 jtagcmd; /* 0x30, rev >= 10 */
uint32 jtagir;
uint32 jtagdr;
uint32 jtagctrl;
/* serial flash interface registers */
uint32 flashcontrol; /* 0x40 */
uint32 flashaddress;
uint32 flashdata;
uint32 PAD[1];
/* Silicon backplane configuration broadcast control */
uint32 broadcastaddress; /* 0x50 */
uint32 broadcastdata;
uint32 PAD[2];
/* gpio - cleared only by power-on-reset */
uint32 gpioin; /* 0x60 */
uint32 gpioout;
uint32 gpioouten;
uint32 gpiocontrol;
uint32 gpiointpolarity;
uint32 gpiointmask;
uint32 PAD[2];
/* Watchdog timer */
uint32 watchdog; /* 0x80 */
uint32 PAD[3];
/* clock control */
uint32 clockcontrol_n; /* 0x90 */
uint32 clockcontrol_sb; /* aka m0 */
uint32 clockcontrol_pci; /* aka m1 */
uint32 clockcontrol_m2; /* mii/uart/mipsref */
uint32 clockcontrol_mips; /* aka m3 */
uint32 clkdiv; /* corerev >= 3 */
uint32 PAD[2];
/* pll delay registers (corerev >= 4) */
uint32 pll_on_delay; /* 0xb0 */
uint32 fref_sel_delay;
uint32 slow_clk_ctl; /* 5 < corerev < 10 */
uint32 PAD[1];
/* Instaclock registers (corerev >= 10) */
uint32 system_clk_ctl; /* 0xc0 */
uint32 clkstatestretch;
uint32 PAD[14];
/* ExtBus control registers (corerev >= 3) */
uint32 pcmcia_config; /* 0x100 */
uint32 pcmcia_memwait;
uint32 pcmcia_attrwait;
uint32 pcmcia_iowait;
uint32 ide_config;
uint32 ide_memwait;
uint32 ide_attrwait;
uint32 ide_iowait;
uint32 prog_config;
uint32 prog_waitcount;
uint32 flash_config;
uint32 flash_waitcount;
uint32 PAD[116];
/* uarts */
uint8 uart0data; /* 0x300 */
uint8 uart0imr;
uint8 uart0fcr;
uint8 uart0lcr;
uint8 uart0mcr;
uint8 uart0lsr;
uint8 uart0msr;
uint8 uart0scratch;
uint8 PAD[248]; /* corerev >= 1 */
uint8 uart1data; /* 0x400 */
uint8 uart1imr;
uint8 uart1fcr;
uint8 uart1lcr;
uint8 uart1mcr;
uint8 uart1lsr;
uint8 uart1msr;
uint8 uart1scratch;
} chipcregs_t;
#endif /* _LANGUAGE_ASSEMBLY */
#define CC_CHIPID 0
#define CC_CAPABILITIES 4
#define CC_JTAGCMD 0x30
#define CC_JTAGIR 0x34
#define CC_JTAGDR 0x38
#define CC_JTAGCTRL 0x3c
#define CC_CLKDIV 0xa4
/* chipid */
#define CID_ID_MASK 0x0000ffff /* Chip Id mask */
#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */
#define CID_REV_SHIFT 16 /* Chip Revision shift */
#define CID_PKG_MASK 0x00f00000 /* Package Option mask */
#define CID_PKG_SHIFT 20 /* Package Option shift */
#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */
#define CID_CC_SHIFT 24
/* capabilities */
#define CAP_UARTS_MASK 0x00000003 /* Number of uarts */
#define CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */
#define CAP_UCLKSEL 0x00000018 /* UARTs clock select */
#define CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */
#define CAP_UARTGPIO 0x00000020 /* UARTs own Gpio's 15:12 */
#define CAP_EXTBUS 0x00000040 /* External bus present */
#define CAP_FLASH_MASK 0x00000700 /* Type of flash */
#define CAP_PLL_MASK 0x00038000 /* Type of PLL */
#define CAP_PWR_CTL 0x00040000 /* Power control */
#define CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */
#define CAP_JTAGP 0x00400000 /* JTAG Master Present */
#define CAP_ROM 0x00800000 /* Internal boot rom active */
/* PLL type */
#define PLL_NONE 0x00000000
#define PLL_TYPE1 0x00010000 /* 48Mhz base, 3 dividers */
#define PLL_TYPE2 0x00020000 /* 48Mhz, 4 dividers */
#define PLL_TYPE3 0x00030000 /* 25Mhz, 2 dividers */
#define PLL_TYPE4 0x00008000 /* 48Mhz, 4 dividers */
/* corecontrol */
#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */
#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
/* jtagcmd */
#define JCMD_START 0x80000000
#define JCMD_BUSY 0x80000000
#define JCMD_PAUSE 0x40000000
#define JCMD0_ACC_MASK 0x0000f000
#define JCMD0_ACC_IRDR 0x00000000
#define JCMD0_ACC_DR 0x00001000
#define JCMD0_ACC_IR 0x00002000
#define JCMD0_ACC_RESET 0x00003000
#define JCMD0_ACC_IRPDR 0x00004000
#define JCMD0_ACC_PDR 0x00005000
#define JCMD0_IRW_MASK 0x00000f00
#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */
#define JCMD_ACC_IRDR 0x00000000
#define JCMD_ACC_DR 0x00010000
#define JCMD_ACC_IR 0x00020000
#define JCMD_ACC_RESET 0x00030000
#define JCMD_ACC_IRPDR 0x00040000
#define JCMD_ACC_PDR 0x00050000
#define JCMD_IRW_MASK 0x00001f00
#define JCMD_IRW_SHIFT 8
#define JCMD_DRW_MASK 0x0000003f
/* jtagctrl */
#define JCTRL_FORCE_CLK 4 /* Force clock */
#define JCTRL_EXT_EN 2 /* Enable external targets */
#define JCTRL_EN 1 /* Enable Jtag master */
/* Fields in clkdiv */
#define CLKD_SFLASH 0x0f000000
#define CLKD_SFLASH_SHIFT 24
#define CLKD_OTP 0x000f0000
#define CLKD_OTP_SHIFT 16
#define CLKD_JTAG 0x00000f00
#define CLKD_JTAG_SHIFT 8
#define CLKD_UART 0x000000ff
/* intstatus/intmask */
#define CI_GPIO 0x00000001 /* gpio intr */
#define CI_EI 0x00000002 /* ro: ext intr pin (corerev >= 3) */
#define CI_WDREST 0x80000000 /* watchdog reset occurred */
/* slow_clk_ctl */
#define SCC_SS_MASK 0x00000007 /* slow clock source mask */
#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */
#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */
#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */
#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */
#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */
#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */
#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */
#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */
#define SCC_CD_MASK 0xffff0000 /* ClockDivider mask, SlowClk = 1/(4+divisor) * crystal/PCI clock */
#define SCC_CD_SHF 16 /* CLockDivider shift */
/* sys_clk_ctl */
#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */
#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */
#define SYCC_FP 0x00000004 /* ForcePLLOn */
#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */
#define SYCC_HR 0x00000010 /* Force HT */
#define SYCC_CD_MASK 0xffff0000 /* ClockDivider mask, SlowClk = 1/(4+divisor) * crystal/PCI clock */
#define SYCC_CD_SHF 16 /* CLockDivider shift */
/* clockcontrol_n */
#define CN_N1_MASK 0x3f /* n1 control */
#define CN_N2_MASK 0x3f00 /* n2 control */
#define CN_N2_SHIFT 8
/* clockcontrol_sb/pci/uart */
#define CC_M1_MASK 0x3f /* m1 control */
#define CC_M2_MASK 0x3f00 /* m2 control */
#define CC_M2_SHIFT 8
#define CC_M3_MASK 0x3f0000 /* m3 control */
#define CC_M3_SHIFT 16
#define CC_MC_MASK 0x1f000000 /* mux control */
#define CC_MC_SHIFT 24
/* N3M Clock control values for 125Mhz */
#define CC_125_N 0x0802 /* Default values for bcm4310 */
#define CC_125_M 0x04020009
#define CC_125_M25 0x11090009
#define CC_125_M33 0x11090005
/* N3M Clock control magic field values */
#define CC_F6_2 0x02 /* A factor of 2 in */
#define CC_F6_3 0x03 /* 6-bit fields like */
#define CC_F6_4 0x05 /* N1, M1 or M3 */
#define CC_F6_5 0x09
#define CC_F6_6 0x11
#define CC_F6_7 0x21
#define CC_F5_BIAS 5 /* 5-bit fields get this added */
#define CC_MC_BYPASS 0x08
#define CC_MC_M1 0x04
#define CC_MC_M1M2 0x02
#define CC_MC_M1M2M3 0x01
#define CC_MC_M1M3 0x11
/* Type 2 Clock control magic field values */
#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */
#define CC_T2M2_BIAS 3 /* m2 bias */
#define CC_T2MC_M1BYP 1
#define CC_T2MC_M2BYP 2
#define CC_T2MC_M3BYP 4
/* Common clock base */
#define CC_CLOCK_BASE 24000000 /* Half the clock freq */
/* Flash types in the chipcommon capabilities register */
#define FLASH_NONE 0x000 /* No flash */
#define SFLASH_ST 0x100 /* ST serial flash */
#define SFLASH_AT 0x200 /* Atmel serial flash */
#define PFLASH 0x700 /* Parallel flash */
/* Prefered flash window in chipcommon */
#define CC_FLASH_BASE 0xbc000000 /* Chips with chipcommon cores */
#define CC_FLASH_MAX 0x02000000 /* Maximum flash size with chipc */
/* Bits in the config registers */
#define CC_CFG_EN 0x0001 /* Enable */
#define CC_CFG_EM_MASK 0x000e /* Extif Mode */
#define CC_CFG_EM_ASYNC 0x0002 /* Async/Parallel flash */
#define CC_CFG_EM_SYNC 0x0004 /* Synchronous */
#define CC_CFG_EM_PCMCIA 0x0008 /* PCMCIA */
#define CC_CFG_EM_IDE 0x000a /* IDE */
#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
#define CC_CFG_CD_MASK 0x0060 /* Sync: Clock divisor */
#define CC_CFG_CE 0x0080 /* Sync: Clock enable */
#define CC_CFG_SB 0x0100 /* Sync: Size/Bytestrobe */
/* Start/busy bit in flashcontrol */
#define SFLASH_START 0x80000000
#define SFLASH_BUSY SFLASH_START
/* flashcontrol opcodes for ST flashes */
#define SFLASH_ST_WREN 0x0006 /* Write Enable */
#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */
#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */
#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */
#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */
#define SFLASH_ST_PP 0x0302 /* Page Program */
#define SFLASH_ST_SE 0x02d8 /* Sector Erase */
#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */
#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */
#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */
/* Status register bits for ST flashes */
#define SFLASH_ST_WIP 0x01 /* Write In Progress */
#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */
#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */
#define SFLASH_ST_BP_SHIFT 2
#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */
/* flashcontrol opcodes for Atmel flashes */
#define SFLASH_AT_READ 0x07e8
#define SFLASH_AT_PAGE_READ 0x07d2
#define SFLASH_AT_BUF1_READ
#define SFLASH_AT_BUF2_READ
#define SFLASH_AT_STATUS 0x01d7
#define SFLASH_AT_BUF1_WRITE 0x0384
#define SFLASH_AT_BUF2_WRITE 0x0387
#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283
#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286
#define SFLASH_AT_BUF1_PROGRAM 0x0288
#define SFLASH_AT_BUF2_PROGRAM 0x0289
#define SFLASH_AT_PAGE_ERASE 0x0281
#define SFLASH_AT_BLOCK_ERASE 0x0250
#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
#define SFLASH_AT_BUF1_LOAD 0x0253
#define SFLASH_AT_BUF2_LOAD 0x0255
#define SFLASH_AT_BUF1_COMPARE 0x0260
#define SFLASH_AT_BUF2_COMPARE 0x0261
#define SFLASH_AT_BUF1_REPROGRAM 0x0258
#define SFLASH_AT_BUF2_REPROGRAM 0x0259
/* Status register bits for Atmel flashes */
#define SFLASH_AT_READY 0x80
#define SFLASH_AT_MISMATCH 0x40
#define SFLASH_AT_ID_MASK 0x38
#define SFLASH_AT_ID_SHIFT 3
#endif /* _SBCHIPC_H */

View File

@ -0,0 +1,292 @@
/*
* Broadcom SiliconBackplane hardware register definitions.
*
* Copyright 2004, 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$
*/
#ifndef _SBCONFIG_H
#define _SBCONFIG_H
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif
/*
* SiliconBackplane Address Map.
* All regions may not exist on all chips.
*/
#define SB_SDRAM_BASE 0x00000000 /* Physical SDRAM */
#define SB_PCI_MEM 0x08000000 /* Host Mode PCI memory access space (64 MB) */
#define SB_PCI_CFG 0x0c000000 /* Host Mode PCI configuration space (64 MB) */
#define SB_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
#define SB_ENUM_BASE 0x18000000 /* Enumeration space base */
#define SB_ENUM_LIM 0x18010000 /* Enumeration space limit */
#define SB_EXTIF_BASE 0x1f000000 /* External Interface region base address */
#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
#define SB_EUART (SB_EXTIF_BASE + 0x00800000)
#define SB_LED (SB_EXTIF_BASE + 0x00900000)
/* enumeration space related defs */
#define SB_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */
#define SB_MAXCORES ((SB_ENUM_LIM - SB_ENUM_BASE)/SB_CORE_SIZE)
#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */
#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */
/* mips address */
#define SB_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
/*
* Sonics Configuration Space Registers.
*/
#define SBIPSFLAG 0x08
#define SBTPSFLAG 0x18
#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */
#define SBTMERRLOG 0x50 /* sonics >= 2.3 */
#define SBADMATCH3 0x60
#define SBADMATCH2 0x68
#define SBADMATCH1 0x70
#define SBIMSTATE 0x90
#define SBINTVEC 0x94
#define SBTMSTATELOW 0x98
#define SBTMSTATEHIGH 0x9c
#define SBBWA0 0xa0
#define SBIMCONFIGLOW 0xa8
#define SBIMCONFIGHIGH 0xac
#define SBADMATCH0 0xb0
#define SBTMCONFIGLOW 0xb8
#define SBTMCONFIGHIGH 0xbc
#define SBBCONFIG 0xc0
#define SBBSTATE 0xc8
#define SBACTCNFG 0xd8
#define SBFLAGST 0xe8
#define SBIDLOW 0xf8
#define SBIDHIGH 0xfc
#ifndef _LANGUAGE_ASSEMBLY
typedef volatile struct _sbconfig {
uint32 PAD[2];
uint32 sbipsflag; /* initiator port ocp slave flag */
uint32 PAD[3];
uint32 sbtpsflag; /* target port ocp slave flag */
uint32 PAD[11];
uint32 sbtmerrloga; /* (sonics >= 2.3) */
uint32 PAD;
uint32 sbtmerrlog; /* (sonics >= 2.3) */
uint32 PAD[3];
uint32 sbadmatch3; /* address match3 */
uint32 PAD;
uint32 sbadmatch2; /* address match2 */
uint32 PAD;
uint32 sbadmatch1; /* address match1 */
uint32 PAD[7];
uint32 sbimstate; /* initiator agent state */
uint32 sbintvec; /* interrupt mask */
uint32 sbtmstatelow; /* target state */
uint32 sbtmstatehigh; /* target state */
uint32 sbbwa0; /* bandwidth allocation table0 */
uint32 PAD;
uint32 sbimconfiglow; /* initiator configuration */
uint32 sbimconfighigh; /* initiator configuration */
uint32 sbadmatch0; /* address match0 */
uint32 PAD;
uint32 sbtmconfiglow; /* target configuration */
uint32 sbtmconfighigh; /* target configuration */
uint32 sbbconfig; /* broadcast configuration */
uint32 PAD;
uint32 sbbstate; /* broadcast state */
uint32 PAD[3];
uint32 sbactcnfg; /* activate configuration */
uint32 PAD[3];
uint32 sbflagst; /* current sbflags */
uint32 PAD[3];
uint32 sbidlow; /* identification */
uint32 sbidhigh; /* identification */
} sbconfig_t;
#endif /* _LANGUAGE_ASSEMBLY */
/* sbipsflag */
#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */
#define SBIPS_INT1_SHIFT 0
#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */
#define SBIPS_INT2_SHIFT 8
#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */
#define SBIPS_INT3_SHIFT 16
#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */
#define SBIPS_INT4_SHIFT 24
/* sbtpsflag */
#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */
#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */
/* sbtmerrlog */
#define SBTMEL_CM 0x00000007 /* command */
#define SBTMEL_CI 0x0000ff00 /* connection id */
#define SBTMEL_EC 0x0f000000 /* error code */
#define SBTMEL_ME 0x80000000 /* multiple error */
/* sbimstate */
#define SBIM_PC 0xf /* pipecount */
#define SBIM_AP_MASK 0x30 /* arbitration policy */
#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */
#define SBIM_AP_TS 0x10 /* use timesliaces only */
#define SBIM_AP_TK 0x20 /* use token only */
#define SBIM_AP_RSV 0x30 /* reserved */
#define SBIM_IBE 0x20000 /* inbanderror */
#define SBIM_TO 0x40000 /* timeout */
#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */
#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */
/* sbtmstatelow */
#define SBTML_RESET 0x1 /* reset */
#define SBTML_REJ 0x2 /* reject */
#define SBTML_CLK 0x10000 /* clock enable */
#define SBTML_FGC 0x20000 /* force gated clocks on */
#define SBTML_FL_MASK 0x3ffc0000 /* core-specific flags */
#define SBTML_PE 0x40000000 /* pme enable */
#define SBTML_BE 0x80000000 /* bist enable */
/* sbtmstatehigh */
#define SBTMH_SERR 0x1 /* serror */
#define SBTMH_INT 0x2 /* interrupt */
#define SBTMH_BUSY 0x4 /* busy */
#define SBTMH_TO 0x00000020 /* timeout (sonics >= 2.3) */
#define SBTMH_FL_MASK 0x1fff0000 /* core-specific flags */
#define SBTMH_GCR 0x20000000 /* gated clock request */
#define SBTMH_BISTF 0x40000000 /* bist failed */
#define SBTMH_BISTD 0x80000000 /* bist done */
/* sbbwa0 */
#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */
#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */
#define SBBWA_TAB1_SHIFT 16
/* sbimconfiglow */
#define SBIMCL_STO_MASK 0x7 /* service timeout */
#define SBIMCL_RTO_MASK 0x70 /* request timeout */
#define SBIMCL_RTO_SHIFT 4
#define SBIMCL_CID_MASK 0xff0000 /* connection id */
#define SBIMCL_CID_SHIFT 16
/* sbimconfighigh */
#define SBIMCH_IEM_MASK 0xc /* inband error mode */
#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */
#define SBIMCH_TEM_SHIFT 4
#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */
#define SBIMCH_BEM_SHIFT 6
/* sbadmatch0 */
#define SBAM_TYPE_MASK 0x3 /* address type */
#define SBAM_AD64 0x4 /* reserved */
#define SBAM_ADINT0_MASK 0xf8 /* type0 size */
#define SBAM_ADINT0_SHIFT 3
#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */
#define SBAM_ADINT1_SHIFT 3
#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */
#define SBAM_ADINT2_SHIFT 3
#define SBAM_ADEN 0x400 /* enable */
#define SBAM_ADNEG 0x800 /* negative decode */
#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */
#define SBAM_BASE0_SHIFT 8
#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */
#define SBAM_BASE1_SHIFT 12
#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */
#define SBAM_BASE2_SHIFT 16
/* sbtmconfiglow */
#define SBTMCL_CD_MASK 0xff /* clock divide */
#define SBTMCL_CO_MASK 0xf800 /* clock offset */
#define SBTMCL_CO_SHIFT 11
#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */
#define SBTMCL_IF_SHIFT 18
#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */
#define SBTMCL_IM_SHIFT 24
/* sbtmconfighigh */
#define SBTMCH_BM_MASK 0x3 /* busy mode */
#define SBTMCH_RM_MASK 0x3 /* retry mode */
#define SBTMCH_RM_SHIFT 2
#define SBTMCH_SM_MASK 0x30 /* stop mode */
#define SBTMCH_SM_SHIFT 4
#define SBTMCH_EM_MASK 0x300 /* sb error mode */
#define SBTMCH_EM_SHIFT 8
#define SBTMCH_IM_MASK 0xc00 /* int mode */
#define SBTMCH_IM_SHIFT 10
/* sbbconfig */
#define SBBC_LAT_MASK 0x3 /* sb latency */
#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */
#define SBBC_MAX0_SHIFT 16
#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */
#define SBBC_MAX1_SHIFT 20
/* sbbstate */
#define SBBS_SRD 0x1 /* st reg disable */
#define SBBS_HRD 0x2 /* hold reg disable */
/* sbidlow */
#define SBIDL_CS_MASK 0x3 /* config space */
#define SBIDL_AR_MASK 0x38 /* # address ranges supported */
#define SBIDL_AR_SHIFT 3
#define SBIDL_SYNCH 0x40 /* sync */
#define SBIDL_INIT 0x80 /* initiator */
#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */
#define SBIDL_MINLAT_SHIFT 8
#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */
#define SBIDL_MAXLAT_SHIFT 12
#define SBIDL_FIRST 0x10000 /* this initiator is first */
#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */
#define SBIDL_CW_SHIFT 18
#define SBIDL_TP_MASK 0xf00000 /* target ports */
#define SBIDL_TP_SHIFT 20
#define SBIDL_IP_MASK 0xf000000 /* initiator ports */
#define SBIDL_IP_SHIFT 24
#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */
#define SBIDL_RV_SHIFT 28
/* sbidhigh */
#define SBIDH_RC_MASK 0xf /* revision code*/
#define SBIDH_CC_MASK 0xfff0 /* core code */
#define SBIDH_CC_SHIFT 4
#define SBIDH_VC_MASK 0xffff0000 /* vendor code */
#define SBIDH_VC_SHIFT 16
#define SB_COMMIT 0xfd8 /* update buffered registers value */
/* vendor codes */
#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */
/* core codes */
#define SB_CC 0x800 /* chipcommon core */
#define SB_ILINE20 0x801 /* iline20 core */
#define SB_SDRAM 0x803 /* sdram core */
#define SB_PCI 0x804 /* pci core */
#define SB_MIPS 0x805 /* mips core */
#define SB_ENET 0x806 /* enet mac core */
#define SB_CODEC 0x807 /* v90 codec core */
#define SB_USB 0x808 /* usb 1.1 host/device core */
#define SB_ILINE100 0x80a /* iline100 core */
#define SB_IPSEC 0x80b /* ipsec core */
#define SB_PCMCIA 0x80d /* pcmcia core */
#define SB_MEMC 0x80f /* memc sdram core */
#define SB_EXTIF 0x811 /* external interface core */
#define SB_D11 0x812 /* 802.11 MAC core */
#define SB_MIPS33 0x816 /* mips3302 core */
#define SB_USB11H 0x817 /* usb 1.1 host core */
#define SB_USB11D 0x818 /* usb 1.1 device core */
#define SB_USB20H 0x819 /* usb 2.0 host core */
#define SB_USB20D 0x81A /* usb 2.0 device core */
#define SB_SDIOH 0x81B /* sdio host core */
#endif /* _SBCONFIG_H */

View File

@ -0,0 +1,242 @@
/*
* Hardware-specific External Interface I/O core definitions
* for the BCM47xx family of SiliconBackplane-based chips.
*
* The External Interface core supports a total of three external chip selects
* supporting external interfaces. One of the external chip selects is
* used for Flash, one is used for PCMCIA, and the other may be
* programmed to support either a synchronous interface or an
* asynchronous interface. The asynchronous interface can be used to
* support external devices such as UARTs and the BCM2019 Bluetooth
* baseband processor.
* The external interface core also contains 2 on-chip 16550 UARTs, clock
* frequency control, a watchdog interrupt timer, and a GPIO interface.
*
* Copyright 2004, 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$
*/
#ifndef _SBEXTIF_H
#define _SBEXTIF_H
/* external interface address space */
#define EXTIF_PCMCIA_MEMBASE(x) (x)
#define EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000)
#define EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000)
#define EXTIF_CFGIF_BASE(x) ((x) + 0x800000)
#define EXTIF_FLASH_BASE(x) ((x) + 0xc00000)
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif /* PAD */
/*
* The multiple instances of output and output enable registers
* are present to allow driver software for multiple cores to control
* gpio outputs without needing to share a single register pair.
*/
struct gpiouser {
uint32 out;
uint32 outen;
};
#define NGPIOUSER 5
typedef volatile struct {
uint32 corecontrol;
uint32 extstatus;
uint32 PAD[2];
/* pcmcia control registers */
uint32 pcmcia_config;
uint32 pcmcia_memwait;
uint32 pcmcia_attrwait;
uint32 pcmcia_iowait;
/* programmable interface control registers */
uint32 prog_config;
uint32 prog_waitcount;
/* flash control registers */
uint32 flash_config;
uint32 flash_waitcount;
uint32 PAD[4];
uint32 watchdog;
/* clock control */
uint32 clockcontrol_n;
uint32 clockcontrol_sb;
uint32 clockcontrol_pci;
uint32 clockcontrol_mii;
uint32 PAD[3];
/* gpio */
uint32 gpioin;
struct gpiouser gpio[NGPIOUSER];
uint32 PAD;
uint32 ejtagouten;
uint32 gpiointpolarity;
uint32 gpiointmask;
uint32 PAD[153];
uint8 uartdata;
uint8 PAD[3];
uint8 uartimer;
uint8 PAD[3];
uint8 uartfcr;
uint8 PAD[3];
uint8 uartlcr;
uint8 PAD[3];
uint8 uartmcr;
uint8 PAD[3];
uint8 uartlsr;
uint8 PAD[3];
uint8 uartmsr;
uint8 PAD[3];
uint8 uartscratch;
uint8 PAD[3];
} extifregs_t;
/* corecontrol */
#define CC_UE (1 << 0) /* uart enable */
/* extstatus */
#define ES_EM (1 << 0) /* endian mode (ro) */
#define ES_EI (1 << 1) /* external interrupt pin (ro) */
#define ES_GI (1 << 2) /* gpio interrupt pin (ro) */
/* gpio bit mask */
#define GPIO_BIT0 (1 << 0)
#define GPIO_BIT1 (1 << 1)
#define GPIO_BIT2 (1 << 2)
#define GPIO_BIT3 (1 << 3)
#define GPIO_BIT4 (1 << 4)
#define GPIO_BIT5 (1 << 5)
#define GPIO_BIT6 (1 << 6)
#define GPIO_BIT7 (1 << 7)
/* pcmcia/prog/flash_config */
#define CF_EN (1 << 0) /* enable */
#define CF_EM_MASK 0xe /* mode */
#define CF_EM_SHIFT 1
#define CF_EM_FLASH 0x0 /* flash/asynchronous mode */
#define CF_EM_SYNC 0x2 /* synchronous mode */
#define CF_EM_PCMCIA 0x4 /* pcmcia mode */
#define CF_DS (1 << 4) /* destsize: 0=8bit, 1=16bit */
#define CF_BS (1 << 5) /* byteswap */
#define CF_CD_MASK 0xc0 /* clock divider */
#define CF_CD_SHIFT 6
#define CF_CD_DIV2 0x0 /* backplane/2 */
#define CF_CD_DIV3 0x40 /* backplane/3 */
#define CF_CD_DIV4 0x80 /* backplane/4 */
#define CF_CE (1 << 8) /* clock enable */
#define CF_SB (1 << 9) /* size/bytestrobe (synch only) */
/* pcmcia_memwait */
#define PM_W0_MASK 0x3f /* waitcount0 */
#define PM_W1_MASK 0x1f00 /* waitcount1 */
#define PM_W1_SHIFT 8
#define PM_W2_MASK 0x1f0000 /* waitcount2 */
#define PM_W2_SHIFT 16
#define PM_W3_MASK 0x1f000000 /* waitcount3 */
#define PM_W3_SHIFT 24
/* pcmcia_attrwait */
#define PA_W0_MASK 0x3f /* waitcount0 */
#define PA_W1_MASK 0x1f00 /* waitcount1 */
#define PA_W1_SHIFT 8
#define PA_W2_MASK 0x1f0000 /* waitcount2 */
#define PA_W2_SHIFT 16
#define PA_W3_MASK 0x1f000000 /* waitcount3 */
#define PA_W3_SHIFT 24
/* pcmcia_iowait */
#define PI_W0_MASK 0x3f /* waitcount0 */
#define PI_W1_MASK 0x1f00 /* waitcount1 */
#define PI_W1_SHIFT 8
#define PI_W2_MASK 0x1f0000 /* waitcount2 */
#define PI_W2_SHIFT 16
#define PI_W3_MASK 0x1f000000 /* waitcount3 */
#define PI_W3_SHIFT 24
/* prog_waitcount */
#define PW_W0_MASK 0x0000001f /* waitcount0 */
#define PW_W1_MASK 0x00001f00 /* waitcount1 */
#define PW_W1_SHIFT 8
#define PW_W2_MASK 0x001f0000 /* waitcount2 */
#define PW_W2_SHIFT 16
#define PW_W3_MASK 0x1f000000 /* waitcount3 */
#define PW_W3_SHIFT 24
#define PW_W0 0x0000000c
#define PW_W1 0x00000a00
#define PW_W2 0x00020000
#define PW_W3 0x01000000
/* flash_waitcount */
#define FW_W0_MASK 0x1f /* waitcount0 */
#define FW_W1_MASK 0x1f00 /* waitcount1 */
#define FW_W1_SHIFT 8
#define FW_W2_MASK 0x1f0000 /* waitcount2 */
#define FW_W2_SHIFT 16
#define FW_W3_MASK 0x1f000000 /* waitcount3 */
#define FW_W3_SHIFT 24
/* watchdog */
#define WATCHDOG_CLOCK 48000000 /* Hz */
/* clockcontrol_n */
#define CN_N1_MASK 0x3f /* n1 control */
#define CN_N2_MASK 0x3f00 /* n2 control */
#define CN_N2_SHIFT 8
/* clockcontrol_sb/pci/mii */
#define CC_M1_MASK 0x3f /* m1 control */
#define CC_M2_MASK 0x3f00 /* m2 control */
#define CC_M2_SHIFT 8
#define CC_M3_MASK 0x3f0000 /* m3 control */
#define CC_M3_SHIFT 16
#define CC_MC_MASK 0x1f000000 /* mux control */
#define CC_MC_SHIFT 24
/* Clock control default values */
#define CC_DEF_N 0x0009 /* Default values for bcm4710 */
#define CC_DEF_100 0x04020011
#define CC_DEF_33 0x11030011
#define CC_DEF_25 0x11050011
/* Clock control values for 125Mhz */
#define CC_125_N 0x0802
#define CC_125_M 0x04020009
#define CC_125_M25 0x11090009
#define CC_125_M33 0x11090005
/* Clock control magic field values */
#define CC_F6_2 0x02 /* A factor of 2 in */
#define CC_F6_3 0x03 /* 6-bit fields like */
#define CC_F6_4 0x05 /* N1, M1 or M3 */
#define CC_F6_5 0x09
#define CC_F6_6 0x11
#define CC_F6_7 0x21
#define CC_F5_BIAS 5 /* 5-bit fields get this added */
#define CC_MC_BYPASS 0x08
#define CC_MC_M1 0x04
#define CC_MC_M1M2 0x02
#define CC_MC_M1M2M3 0x01
#define CC_MC_M1M3 0x11
#define CC_CLOCK_BASE 24000000 /* Half the clock freq. in the 4710 */
#endif /* _SBEXTIF_H */

View File

@ -0,0 +1,147 @@
/*
* BCM47XX Sonics SiliconBackplane DDR/SDRAM controller core hardware definitions.
*
* Copyright 2004, 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$
*/
#ifndef _SBMEMC_H
#define _SBMEMC_H
#ifdef _LANGUAGE_ASSEMBLY
#define MEMC_CONTROL 0x00
#define MEMC_CONFIG 0x04
#define MEMC_REFRESH 0x08
#define MEMC_BISTSTAT 0x0c
#define MEMC_MODEBUF 0x10
#define MEMC_BKCLS 0x14
#define MEMC_PRIORINV 0x18
#define MEMC_DRAMTIM 0x1c
#define MEMC_INTSTAT 0x20
#define MEMC_INTMASK 0x24
#define MEMC_INTINFO 0x28
#define MEMC_NCDLCTL 0x30
#define MEMC_RDNCDLCOR 0x34
#define MEMC_WRNCDLCOR 0x38
#define MEMC_MISCDLYCTL 0x3c
#define MEMC_DQSGATENCDL 0x40
#define MEMC_SPARE 0x44
#define MEMC_TPADDR 0x48
#define MEMC_TPDATA 0x4c
#define MEMC_BARRIER 0x50
#define MEMC_CORE 0x54
#else
/* Sonics side: MEMC core registers */
typedef volatile struct sbmemcregs {
uint32 control;
uint32 config;
uint32 refresh;
uint32 biststat;
uint32 modebuf;
uint32 bkcls;
uint32 priorinv;
uint32 dramtim;
uint32 intstat;
uint32 intmask;
uint32 intinfo;
uint32 reserved1;
uint32 ncdlctl;
uint32 rdncdlcor;
uint32 wrncdlcor;
uint32 miscdlyctl;
uint32 dqsgatencdl;
uint32 spare;
uint32 tpaddr;
uint32 tpdata;
uint32 barrier;
uint32 core;
} sbmemcregs_t;
#endif
/* MEMC Core Init values (OCP ID 0x80f) */
/* For sdr: */
#define MEMC_SD_CONFIG_INIT 0x00048000
#define MEMC_SD_DRAMTIM2_INIT 0x000754d8
#define MEMC_SD_DRAMTIM3_INIT 0x000754da
#define MEMC_SD_RDNCDLCOR_INIT 0x00000000
#define MEMC_SD_WRNCDLCOR_INIT 0x49351200
#define MEMC_SD1_WRNCDLCOR_INIT 0x14500200 /* For corerev 1 (4712) */
#define MEMC_SD_MISCDLYCTL_INIT 0x00061c1b
#define MEMC_SD1_MISCDLYCTL_INIT 0x00021416 /* For corerev 1 (4712) */
#define MEMC_SD_CONTROL_INIT0 0x00000002
#define MEMC_SD_CONTROL_INIT1 0x00000008
#define MEMC_SD_CONTROL_INIT2 0x00000004
#define MEMC_SD_CONTROL_INIT3 0x00000010
#define MEMC_SD_CONTROL_INIT4 0x00000001
#define MEMC_SD_MODEBUF_INIT 0x00000000
#define MEMC_SD_REFRESH_INIT 0x0000840f
/* This is for SDRM8X8X4 */
#define MEMC_SDR_INIT 0x0008
#define MEMC_SDR_MODE 0x32
#define MEMC_SDR_NCDL 0x00020032
#define MEMC_SDR1_NCDL 0x0002020f /* For corerev 1 (4712) */
/* For ddr: */
#define MEMC_CONFIG_INIT 0x00048000
#define MEMC_DRAMTIM2_INIT 0x000754d8
#define MEMC_DRAMTIM25_INIT 0x000754d9
#define MEMC_RDNCDLCOR_INIT 0x00000000
#define MEMC_WRNCDLCOR_INIT 0x49351200
#define MEMC_1_WRNCDLCOR_INIT 0x14500200
#define MEMC_DQSGATENCDL_INIT 0x00030000
#define MEMC_MISCDLYCTL_INIT 0x21061c1b
#define MEMC_1_MISCDLYCTL_INIT 0x21021400
#define MEMC_NCDLCTL_INIT 0x00002001
#define MEMC_CONTROL_INIT0 0x00000002
#define MEMC_CONTROL_INIT1 0x00000008
#define MEMC_MODEBUF_INIT0 0x00004000
#define MEMC_CONTROL_INIT2 0x00000010
#define MEMC_MODEBUF_INIT1 0x00000100
#define MEMC_CONTROL_INIT3 0x00000010
#define MEMC_CONTROL_INIT4 0x00000008
#define MEMC_REFRESH_INIT 0x0000840f
#define MEMC_CONTROL_INIT5 0x00000004
#define MEMC_MODEBUF_INIT2 0x00000000
#define MEMC_CONTROL_INIT6 0x00000010
#define MEMC_CONTROL_INIT7 0x00000001
/* This is for DDRM16X16X2 */
#define MEMC_DDR_INIT 0x0009
#define MEMC_DDR_MODE 0x62
#define MEMC_DDR_NCDL 0x0005050a
#define MEMC_DDR1_NCDL 0x00000a0a /* For corerev 1 (4712) */
/* mask for sdr/ddr calibration registers */
#define MEMC_RDNCDLCOR_RD_MASK 0x000000ff
#define MEMC_WRNCDLCOR_WR_MASK 0x000000ff
#define MEMC_DQSGATENCDL_G_MASK 0x000000ff
/* masks for miscdlyctl registers */
#define MEMC_MISC_SM_MASK 0x30000000
#define MEMC_MISC_SM_SHIFT 28
#define MEMC_MISC_SD_MASK 0x0f000000
#define MEMC_MISC_SD_SHIFT 24
/* hw threshhold for calculating wr/rd for sdr memc */
#define MEMC_CD_THRESHOLD 128
/* Low bit of init register says if memc is ddr or sdr */
#define MEMC_CONFIG_DDR 0x00000001
#endif /* _SBMEMC_H */

View File

@ -0,0 +1,56 @@
/*
* Broadcom SiliconBackplane MIPS definitions
*
* SB MIPS cores are custom MIPS32 processors with SiliconBackplane
* OCP interfaces. The CP0 processor ID is 0x00024000, where bits
* 23:16 mean Broadcom and bits 15:8 mean a MIPS core with an OCP
* interface. The core revision is stored in the SB ID register in SB
* configuration space.
*
* Copyright 2004, 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$
*/
#ifndef _SBMIPS_H
#define _SBMIPS_H
#ifndef _LANGUAGE_ASSEMBLY
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif /* PAD */
typedef volatile struct {
uint32 corecontrol;
uint32 PAD[2];
uint32 biststatus;
uint32 PAD[4];
uint32 intstatus;
uint32 intmask;
uint32 timer;
} mipsregs_t;
extern uint32 sb_flag(void *sbh);
extern uint sb_irq(void *sbh);
extern void sb_serial_init(void *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift));
extern void sb_mips_init(void *sbh);
extern uint32 sb_mips_clock(void *sbh);
extern bool sb_mips_setclock(void *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock);
extern uint32 sb_memc_get_ncdl(void *sbh);
#endif /* _LANGUAGE_ASSEMBLY */
#endif /* _SBMIPS_H */

View File

@ -0,0 +1,113 @@
/*
* BCM47XX Sonics SiliconBackplane PCI core hardware definitions.
*
* $Id$
* Copyright 2004, 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.
*/
#ifndef _SBPCI_H
#define _SBPCI_H
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif
/* Sonics side: PCI core and host control registers */
typedef struct sbpciregs {
uint32 control; /* PCI control */
uint32 PAD[3];
uint32 arbcontrol; /* PCI arbiter control */
uint32 PAD[3];
uint32 intstatus; /* Interrupt status */
uint32 intmask; /* Interrupt mask */
uint32 sbtopcimailbox; /* Sonics to PCI mailbox */
uint32 PAD[9];
uint32 bcastaddr; /* Sonics broadcast address */
uint32 bcastdata; /* Sonics broadcast data */
uint32 PAD[2];
uint32 gpioin; /* ro: gpio input (>=rev2) */
uint32 gpioout; /* rw: gpio output (>=rev2) */
uint32 gpioouten; /* rw: gpio output enable (>= rev2) */
uint32 gpiocontrol; /* rw: gpio control (>= rev2) */
uint32 PAD[36];
uint32 sbtopci0; /* Sonics to PCI translation 0 */
uint32 sbtopci1; /* Sonics to PCI translation 1 */
uint32 sbtopci2; /* Sonics to PCI translation 2 */
uint32 PAD[445];
uint16 sprom[36]; /* SPROM shadow Area */
uint32 PAD[46];
} sbpciregs_t;
/* PCI control */
#define PCI_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */
#define PCI_RST 0x02 /* Value driven out to pin */
#define PCI_CLK_OE 0x04 /* When set, drives clock as gated by PCI_CLK out to pin */
#define PCI_CLK 0x08 /* Gate for clock driven out to pin */
/* PCI arbiter control */
#define PCI_INT_ARB 0x01 /* When set, use an internal arbiter */
#define PCI_EXT_ARB 0x02 /* When set, use an external arbiter */
#define PCI_PARKID_MASK 0x06 /* Selects which agent is parked on an idle bus */
#define PCI_PARKID_SHIFT 1
#define PCI_PARKID_LAST 0 /* Last requestor */
#define PCI_PARKID_4710 1 /* 4710 */
#define PCI_PARKID_EXTREQ0 2 /* External requestor 0 */
#define PCI_PARKID_EXTREQ1 3 /* External requestor 1 */
/* Interrupt status/mask */
#define PCI_INTA 0x01 /* PCI INTA# is asserted */
#define PCI_INTB 0x02 /* PCI INTB# is asserted */
#define PCI_SERR 0x04 /* PCI SERR# has been asserted (write one to clear) */
#define PCI_PERR 0x08 /* PCI PERR# has been asserted (write one to clear) */
#define PCI_PME 0x10 /* PCI PME# is asserted */
/* (General) PCI/SB mailbox interrupts, two bits per pci function */
#define MAILBOX_F0_0 0x100 /* function 0, int 0 */
#define MAILBOX_F0_1 0x200 /* function 0, int 1 */
#define MAILBOX_F1_0 0x400 /* function 1, int 0 */
#define MAILBOX_F1_1 0x800 /* function 1, int 1 */
#define MAILBOX_F2_0 0x1000 /* function 2, int 0 */
#define MAILBOX_F2_1 0x2000 /* function 2, int 1 */
#define MAILBOX_F3_0 0x4000 /* function 3, int 0 */
#define MAILBOX_F3_1 0x8000 /* function 3, int 1 */
/* Sonics broadcast address */
#define BCAST_ADDR_MASK 0xff /* Broadcast register address */
/* Sonics to PCI translation types */
#define SBTOPCI0_MASK 0xfc000000
#define SBTOPCI1_MASK 0xfc000000
#define SBTOPCI2_MASK 0xc0000000
#define SBTOPCI_MEM 0
#define SBTOPCI_IO 1
#define SBTOPCI_CFG0 2
#define SBTOPCI_CFG1 3
#define SBTOPCI_PREF 0x4 /* prefetch enable */
#define SBTOPCI_BURST 0x8 /* burst enable */
/* PCI side: Reserved PCI configuration registers (see pcicfg.h) */
#define cap_list rsvd_a[0]
#define bar0_window dev_dep[0x80 - 0x40]
#define bar1_window dev_dep[0x84 - 0x40]
#define sprom_control dev_dep[0x88 - 0x40]
#ifndef _LANGUAGE_ASSEMBLY
extern int sbpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
extern int sbpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
extern void sbpci_ban(uint16 core);
extern int sbpci_init(void *sbh);
extern void sbpci_check(void *sbh);
#endif /* !_LANGUAGE_ASSEMBLY */
#endif /* _SBPCI_H */

View File

@ -0,0 +1,139 @@
/*
* BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
*
* $Id$
* Copyright 2004, 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.
*/
#ifndef _SBPCMCIA_H
#define _SBPCMCIA_H
/* All the addresses that are offsets in attribute space are divided
* by two to account for the fact that odd bytes are invalid in
* attribute space and our read/write routines make the space appear
* as if they didn't exist. Still we want to show the original numbers
* as documented in the hnd_pcmcia core manual.
*/
/* PCMCIA Function Configuration Registers */
#define PCMCIA_FCR (0x700 / 2)
#define FCR0_OFF 0
#define FCR1_OFF (0x40 / 2)
#define FCR2_OFF (0x80 / 2)
#define FCR3_OFF (0xc0 / 2)
#define PCMCIA_FCR0 (0x700 / 2)
#define PCMCIA_FCR1 (0x740 / 2)
#define PCMCIA_FCR2 (0x780 / 2)
#define PCMCIA_FCR3 (0x7c0 / 2)
/* Standard PCMCIA FCR registers */
#define PCMCIA_COR 0
#define COR_RST 0x80
#define COR_LEV 0x40
#define COR_IRQEN 0x04
#define COR_BLREN 0x01
#define COR_FUNEN 0x01
#define PCICIA_FCSR (2 / 2)
#define PCICIA_PRR (4 / 2)
#define PCICIA_SCR (6 / 2)
#define PCICIA_ESR (8 / 2)
#define PCM_MEMOFF 0x0000
#define F0_MEMOFF 0x1000
#define F1_MEMOFF 0x2000
#define F2_MEMOFF 0x3000
#define F3_MEMOFF 0x4000
/* Memory base in the function fcr's */
#define MEM_ADDR0 (0x728 / 2)
#define MEM_ADDR1 (0x72a / 2)
#define MEM_ADDR2 (0x72c / 2)
/* PCMCIA base plus Srom access in fcr0: */
#define PCMCIA_ADDR0 (0x072e / 2)
#define PCMCIA_ADDR1 (0x0730 / 2)
#define PCMCIA_ADDR2 (0x0732 / 2)
#define MEM_SEG (0x0734 / 2)
#define SROM_CS (0x0736 / 2)
#define SROM_DATAL (0x0738 / 2)
#define SROM_DATAH (0x073a / 2)
#define SROM_ADDRL (0x073c / 2)
#define SROM_ADDRH (0x073e / 2)
/* Values for srom_cs: */
#define SROM_IDLE 0
#define SROM_WRITE 1
#define SROM_READ 2
#define SROM_WEN 4
#define SROM_WDS 7
#define SROM_DONE 8
/* CIS stuff */
/* The CIS stops where the FCRs start */
#define CIS_SIZE PCMCIA_FCR
/* Standard tuples we know about */
#define CISTPL_MANFID 0x20 /* Manufacturer and device id */
#define CISTPL_FUNCE 0x22 /* Function extensions */
#define CISTPL_CFTABLE 0x1b /* Config table entry */
/* Function extensions for LANs */
#define LAN_TECH 1 /* Technology type */
#define LAN_SPEED 2 /* Raw bit rate */
#define LAN_MEDIA 3 /* Transmission media */
#define LAN_NID 4 /* Node identification (aka MAC addr) */
#define LAN_CONN 5 /* Connector standard */
/* CFTable */
#define CFTABLE_REGWIN_2K 0x08 /* 2k reg windows size */
#define CFTABLE_REGWIN_4K 0x10 /* 4k reg windows size */
#define CFTABLE_REGWIN_8K 0x20 /* 8k reg windows size */
/* Vendor unique tuples are 0x80-0x8f. Within Broadcom we'll
* take one for HNBU, and use "extensions" (a la FUNCE) within it.
*/
#define CISTPL_BRCM_HNBU 0x80
/* Subtypes of BRCM_HNBU: */
#define HNBU_CHIPID 0x01 /* Six bytes with PCI vendor &
* device id and chiprev
*/
#define HNBU_BOARDREV 0x02 /* Two bytes board revision */
#define HNBU_PAPARMS 0x03 /* Eleven bytes PA parameters */
#define HNBU_OEM 0x04 /* Eight bytes OEM data */
#define HNBU_CC 0x05 /* Default country code */
#define HNBU_AA 0x06 /* Antennas available */
#define HNBU_AG 0x07 /* Antenna gain */
#define HNBU_BOARDFLAGS 0x08 /* board flags */
#define HNBU_LED 0x09 /* LED set */
/* sbtmstatelow */
#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */
#define SBTML_INT_EN 0x20000 /* enable sb interrupt */
/* sbtmstatehigh */
#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */
#endif /* _SBPCMCIA_H */

View File

@ -0,0 +1,75 @@
/*
* BCM47XX Sonics SiliconBackplane SDRAM controller core hardware definitions.
*
* Copyright 2004, 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$
*/
#ifndef _SBSDRAM_H
#define _SBSDRAM_H
#ifndef _LANGUAGE_ASSEMBLY
/* Sonics side: SDRAM core registers */
typedef volatile struct sbsdramregs {
uint32 initcontrol; /* Generates external SDRAM initialization sequence */
uint32 config; /* Initializes external SDRAM mode register */
uint32 refresh; /* Controls external SDRAM refresh rate */
uint32 pad1;
uint32 pad2;
} sbsdramregs_t;
#endif
/* SDRAM initialization control (initcontrol) register bits */
#define SDRAM_CBR 0x0001 /* Writing 1 generates refresh cycle and toggles bit */
#define SDRAM_PRE 0x0002 /* Writing 1 generates precharge cycle and toggles bit */
#define SDRAM_MRS 0x0004 /* Writing 1 generates mode register select cycle and toggles bit */
#define SDRAM_EN 0x0008 /* When set, enables access to SDRAM */
#define SDRAM_16Mb 0x0000 /* Use 16 Megabit SDRAM */
#define SDRAM_64Mb 0x0010 /* Use 64 Megabit SDRAM */
#define SDRAM_128Mb 0x0020 /* Use 128 Megabit SDRAM */
#define SDRAM_RSVMb 0x0030 /* Use special SDRAM */
#define SDRAM_RST 0x0080 /* Writing 1 causes soft reset of controller */
#define SDRAM_SELFREF 0x0100 /* Writing 1 enables self refresh mode */
#define SDRAM_PWRDOWN 0x0200 /* Writing 1 causes controller to power down */
#define SDRAM_32BIT 0x0400 /* When set, indicates 32 bit SDRAM interface */
#define SDRAM_9BITCOL 0x0800 /* When set, indicates 9 bit column */
/* SDRAM configuration (config) register bits */
#define SDRAM_BURSTFULL 0x0000 /* Use full page bursts */
#define SDRAM_BURST8 0x0001 /* Use burst of 8 */
#define SDRAM_BURST4 0x0002 /* Use burst of 4 */
#define SDRAM_BURST2 0x0003 /* Use burst of 2 */
#define SDRAM_CAS3 0x0000 /* Use CAS latency of 3 */
#define SDRAM_CAS2 0x0004 /* Use CAS latency of 2 */
/* SDRAM refresh control (refresh) register bits */
#define SDRAM_REF(p) (((p)&0xff) | SDRAM_REF_EN) /* Refresh period */
#define SDRAM_REF_EN 0x8000 /* Writing 1 enables periodic refresh */
/* SDRAM Core default Init values (OCP ID 0x803) */
#define SDRAM_INIT MEM4MX16X2
#define SDRAM_CONFIG SDRAM_BURSTFULL
#define SDRAM_REFRESH SDRAM_REF(0x40)
#define MEM1MX16 0x009 /* 2 MB */
#define MEM1MX16X2 0x409 /* 4 MB */
#define MEM2MX8X2 0x809 /* 4 MB */
#define MEM2MX8X4 0xc09 /* 8 MB */
#define MEM2MX32 0x439 /* 8 MB */
#define MEM4MX16 0x019 /* 8 MB */
#define MEM4MX16X2 0x419 /* 16 MB */
#define MEM8MX8X2 0x819 /* 16 MB */
#define MEM8MX16 0x829 /* 16 MB */
#define MEM4MX32 0x429 /* 16 MB */
#define MEM8MX8X4 0xc19 /* 32 MB */
#define MEM8MX16X2 0xc29 /* 32 MB */
#endif /* _SBSDRAM_H */

View File

@ -0,0 +1,94 @@
/*
* Misc utility routines for accessing chip-specific features
* of Broadcom HNBU SiliconBackplane-based chips.
*
* Copyright 2004, 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$
*/
#ifndef _sbutils_h_
#define _sbutils_h_
/* Board styles (bustype) */
#define BOARDSTYLE_SOC 0 /* Silicon Backplane */
#define BOARDSTYLE_PCI 1 /* PCI/MiniPCI board */
#define BOARDSTYLE_PCMCIA 2 /* PCMCIA board */
#define BOARDSTYLE_CARDBUS 3 /* Cardbus board */
/*
* Many of the routines below take an 'sbh' handle as their first arg.
* Allocate this by calling sb_attach(). Free it by calling sb_detach().
* At any one time, the sbh is logically focused on one particular sb core
* (the "current core").
* Use sb_setcore() or sb_setcoreidx() to change the association to another core.
*/
/* exported externs */
extern void *sb_attach(uint pcidev, void *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz);
extern void *sb_kattach(void);
extern void sb_detach(void *sbh);
extern uint sb_chip(void *sbh);
extern uint sb_chiprev(void *sbh);
extern uint sb_chipcrev(void *sbh);
extern uint sb_chippkg(void *sbh);
extern uint sb_pcirev(void *sbh);
extern uint sb_pcmciarev(void *sbh);
extern uint sb_boardvendor(void *sbh);
extern uint sb_boardtype(void *sbh);
extern uint sb_boardstyle(void *sbh);
extern uint sb_bus(void *sbh);
extern uint sb_corelist(void *sbh, uint coreid[]);
extern uint sb_coreid(void *sbh);
extern uint sb_coreidx(void *sbh);
extern uint sb_coreunit(void *sbh);
extern uint sb_corevendor(void *sbh);
extern uint sb_corerev(void *sbh);
extern void *sb_coreregs(void *sbh);
extern uint32 sb_coreflags(void *sbh, uint32 mask, uint32 val);
extern uint32 sb_coreflagshi(void *sbh, uint32 mask, uint32 val);
extern bool sb_iscoreup(void *sbh);
extern void *sb_setcoreidx(void *sbh, uint coreidx);
extern void *sb_setcore(void *sbh, uint coreid, uint coreunit);
extern void sb_commit(void *sbh);
extern uint32 sb_base(uint32 admatch);
extern uint32 sb_size(uint32 admatch);
extern void sb_core_reset(void *sbh, uint32 bits);
extern void sb_core_tofixup(void *sbh);
extern void sb_core_disable(void *sbh, uint32 bits);
extern uint32 sb_clock_rate(uint32 pll_type, uint32 n, uint32 m);
extern uint32 sb_clock(void *sbh);
extern void sb_pci_setup(void *sbh, uint32 *dmaoffset, uint coremask);
extern void sb_pcmcia_init(void *sbh);
extern void sb_watchdog(void *sbh, uint ticks);
extern void *sb_gpiosetcore(void *sbh);
extern uint32 sb_gpiocontrol(void *sbh, uint32 mask, uint32 val);
extern uint32 sb_gpioouten(void *sbh, uint32 mask, uint32 val);
extern uint32 sb_gpioout(void *sbh, uint32 mask, uint32 val);
extern uint32 sb_gpioin(void *sbh);
extern uint32 sb_gpiointpolarity(void *sbh, uint32 mask, uint32 val);
extern uint32 sb_gpiointmask(void *sbh, uint32 mask, uint32 val);
extern bool sb_taclear(void *sbh);
extern void sb_pwrctl_init(void *sbh);
extern uint16 sb_pwrctl_fast_pwrup_delay(void *sbh);
extern bool sb_pwrctl_clk(void *sbh, uint mode);
extern int sb_pwrctl_xtal(void *sbh, uint what, bool on);
extern int sb_pwrctl_slowclk(void *sbh, bool set, uint *div);
extern void sb_register_intr_callback(void *sbh, void *intrsoff_fn, void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg);
/* pwrctl xtal what flags */
#define XTAL 0x1 /* primary crystal oscillator (2050) */
#define PLL 0x2 /* main chip pll */
/* pwrctl clk mode */
#define CLK_FAST 0 /* force fast (pll) clock */
#define CLK_SLOW 1 /* force slow clock */
#define CLK_DYNAMIC 2 /* enable dynamic power control */
#endif /* _sbutils_h_ */

View File

@ -0,0 +1,36 @@
/*
* Broadcom SiliconBackplane chipcommon serial flash interface
*
* Copyright 2004, 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$
*/
#ifndef _sflash_h_
#define _sflash_h_
#include <typedefs.h>
#include <sbchipc.h>
struct sflash {
uint blocksize; /* Block size */
uint numblocks; /* Number of blocks */
uint32 type; /* Type */
uint size; /* Total size in bytes */
};
/* Utility functions */
extern int sflash_poll(chipcregs_t *cc, uint offset);
extern int sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf);
extern int sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf);
extern int sflash_erase(chipcregs_t *cc, uint offset);
extern int sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf);
extern struct sflash * sflash_init(chipcregs_t *cc);
#endif /* _sflash_h_ */

View File

@ -0,0 +1,31 @@
/*
* TRX image file header format.
*
* Copyright 2004, 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>
#define TRX_MAGIC 0x30524448 /* "HDR0" */
#define TRX_VERSION 1
#define TRX_MAX_LEN 0x3A0000
#define TRX_NO_HEADER 1 /* Do not write TRX header */
struct trx_header {
uint32 magic; /* "HDR0" */
uint32 len; /* Length of file including header */
uint32 crc32; /* 32-bit CRC from flag_version to end of file */
uint32 flag_version; /* 0:15 flags, 16:31 version */
uint32 offsets[3]; /* Offsets of partitions from start of header */
};
/* Compatibility */
typedef struct trx_header TRXHDR, *PTRXHDR;

View File

@ -0,0 +1,293 @@
/*
* Copyright 2004, 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$
*/
#ifndef _TYPEDEFS_H_
#define _TYPEDEFS_H_
/* Define 'SITE_TYPEDEFS' in the compile to include a site specific
* typedef file "site_typedefs.h".
*
* If 'SITE_TYPEDEFS' is not defined, then the "Inferred Typedefs"
* section of this file makes inferences about the compile environment
* based on defined symbols and possibly compiler pragmas.
*
* Following these two sections is the "Default Typedefs"
* section. This section is only prcessed if 'USE_TYPEDEF_DEFAULTS' is
* defined. This section has a default set of typedefs and a few
* proprocessor symbols (TRUE, FALSE, NULL, ...).
*/
#ifdef SITE_TYPEDEFS
/*******************************************************************************
* Site Specific Typedefs
*******************************************************************************/
#include "site_typedefs.h"
#else
/*******************************************************************************
* Inferred Typedefs
*******************************************************************************/
/* Infer the compile environment based on preprocessor symbols and pramas.
* Override type definitions as needed, and include configuration dependent
* header files to define types.
*/
#ifdef __cplusplus
#define TYPEDEF_BOOL
#ifndef FALSE
#define FALSE false
#endif
#ifndef TRUE
#define TRUE true
#endif
#else /* ! __cplusplus */
/* for Windows build, define bool as a uchar instead of the default int */
#if defined(_WIN32)
#define TYPEDEF_BOOL
typedef unsigned char bool;
#endif /* _WIN32 */
#endif /* ! __cplusplus */
#ifdef _MSC_VER /* Microsoft C */
#define TYPEDEF_INT64
#define TYPEDEF_UINT64
typedef signed __int64 int64;
typedef unsigned __int64 uint64;
#endif
#if defined(MACOSX) && defined(KERNEL)
#define TYPEDEF_BOOL
#endif
#if defined(linux)
#define TYPEDEF_UINT
#define TYPEDEF_USHORT
#define TYPEDEF_ULONG
#endif
#if !defined(linux) && !defined(_WIN32) && !defined(PMON) && !defined(_CFE_)
#define TYPEDEF_UINT
#define TYPEDEF_USHORT
#endif
/* Do not support the (u)int64 types with strict ansi for GNU C */
#if defined(__GNUC__) && defined(__STRICT_ANSI__)
#define TYPEDEF_INT64
#define TYPEDEF_UINT64
#endif
/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode
* for singned or unsigned */
#if defined(__ICL)
#define TYPEDEF_INT64
#if defined(__STDC__)
#define TYPEDEF_UINT64
#endif
#endif /* __ICL */
#if !defined(_WIN32) && !defined(PMON) && !defined(_CFE_)
/* pick up ushort & uint from standard types.h */
#if defined(linux) && defined(__KERNEL__)
#include <linux/types.h> /* sys/types.h and linux/types.h are oil and water */
#else
#include <sys/types.h>
#endif
#endif /* !_WIN32 && !PMON && !_CFE_ */
#if defined(MACOSX) && defined(KERNEL)
#include <IOKit/IOTypes.h>
#endif
/* use the default typedefs in the next section of this file */
#define USE_TYPEDEF_DEFAULTS
#endif /* SITE_TYPEDEFS */
/*******************************************************************************
* Default Typedefs
*******************************************************************************/
#ifdef USE_TYPEDEF_DEFAULTS
#undef USE_TYPEDEF_DEFAULTS
#ifndef TYPEDEF_BOOL
typedef int bool;
#endif
/*----------------------- define uchar, ushort, uint, ulong ----------------*/
#ifndef TYPEDEF_UCHAR
typedef unsigned char uchar;
#endif
#ifndef TYPEDEF_USHORT
typedef unsigned short ushort;
#endif
#ifndef TYPEDEF_UINT
typedef unsigned int uint;
#endif
#ifndef TYPEDEF_ULONG
typedef unsigned long ulong;
#endif
/*----------------------- define [u]int8/16/32/64 --------------------------*/
#ifndef TYPEDEF_UINT8
typedef unsigned char uint8;
#endif
#ifndef TYPEDEF_UINT16
typedef unsigned short uint16;
#endif
#ifndef TYPEDEF_UINT32
typedef unsigned int uint32;
#endif
#ifndef TYPEDEF_UINT64
typedef unsigned long long uint64;
#endif
#ifndef TYPEDEF_INT8
typedef signed char int8;
#endif
#ifndef TYPEDEF_INT16
typedef signed short int16;
#endif
#ifndef TYPEDEF_INT32
typedef signed int int32;
#endif
#ifndef TYPEDEF_INT64
typedef signed long long int64;
#endif
/*----------------------- define float32/64, float_t -----------------------*/
#ifndef TYPEDEF_FLOAT32
typedef float float32;
#endif
#ifndef TYPEDEF_FLOAT64
typedef double float64;
#endif
/*
* abstracted floating point type allows for compile time selection of
* single or double precision arithmetic. Compiling with -DFLOAT32
* selects single precision; the default is double precision.
*/
#ifndef TYPEDEF_FLOAT_T
#if defined(FLOAT32)
typedef float32 float_t;
#else /* default to double precision floating point */
typedef float64 float_t;
#endif
#endif /* TYPEDEF_FLOAT_T */
/*----------------------- define macro values -----------------------------*/
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef OFF
#define OFF 0
#endif
#ifndef ON
#define ON 1
#endif
/*----------------------- define PTRSZ, INLINE ----------------------------*/
#ifndef PTRSZ
#define PTRSZ sizeof (char*)
#endif
#ifndef INLINE
#ifdef _MSC_VER
#define INLINE __inline
#elif __GNUC__
#define INLINE __inline__
#else
#define INLINE
#endif /* _MSC_VER */
#endif /* INLINE */
#undef TYPEDEF_BOOL
#undef TYPEDEF_UCHAR
#undef TYPEDEF_USHORT
#undef TYPEDEF_UINT
#undef TYPEDEF_ULONG
#undef TYPEDEF_UINT8
#undef TYPEDEF_UINT16
#undef TYPEDEF_UINT32
#undef TYPEDEF_UINT64
#undef TYPEDEF_INT8
#undef TYPEDEF_INT16
#undef TYPEDEF_INT32
#undef TYPEDEF_INT64
#undef TYPEDEF_FLOAT32
#undef TYPEDEF_FLOAT64
#undef TYPEDEF_FLOAT_T
#endif /* USE_TYPEDEF_DEFAULTS */
#endif /* _TYPEDEFS_H_ */

View File

@ -20,43 +20,47 @@ LINUX_KARCH:=$(shell echo $(ARCH) | sed -e 's/i[3-9]86/i386/' \
)
LINUX_SITE=http://www.kernel.org/pub/linux/kernel/v2.4
LINUX_BINARY_DRIVER_SITE=http://openwrt.openbsd-geek.de
LINUX_SOURCE=linux-$(LINUX_VERSION).tar.bz2
LINUX_KCONFIG=./linux.config
LINUX_PATCHES=./kernel-patches
LINUX_KERNEL_SOURCE=./kernel-source
LINUX_BINLOC=arch/$(LINUX_KARCH)/brcm-boards/bcm947xx/compressed/vmlinuz
# Used by pcmcia-cs and others
LINUX_SOURCE_DIR=$(LINUX_DIR)-$(LINUX_VERSION)
# kernel stuff extracted from linksys firmware GPL sourcetree
# WRT54GS_3_37_2_1109_US (shared,include,wl,et)
LINKSYS_KERNEL_SITE=http://openwrt.openbsd-geek.de
LINKSYS_KERNEL_TGZ=linksys-kernel.tar.gz
# binary driver extracted from linksys firmware GPL sourcetree WRT54GS_3_37_2_1109_US
LINUX_BINARY_WL_DRIVER=kernel-binary-wl.tar.gz
LINUX_BINARY_ET_DRIVER=kernel-binary-et.tar.gz
TARGET_MODULES_DIR=$(TARGET_DIR)/lib/modules/$(LINUX_VERSION)
$(DL_DIR)/$(LINKSYS_KERNEL_TGZ):
$(WGET) -P $(DL_DIR) $(LINKSYS_KERNEL_SITE)/$(LINKSYS_KERNEL_TGZ)
$(DL_DIR)/$(LINUX_BINARY_WL_DRIVER):
$(WGET) -P $(DL_DIR) $(LINUX_BINARY_DRIVER_SITE)/$(LINUX_BINARY_WL_DRIVER)
$(LINUX_DIR)/.unpacked: $(DL_DIR)/$(LINUX_SOURCE) $(DL_DIR)/$(LINKSYS_KERNEL_TGZ)
$(DL_DIR)/$(LINUX_BINARY_ET_DRIVER):
$(WGET) -P $(DL_DIR) $(LINUX_BINARY_DRIVER_SITE)/$(LINUX_BINARY_ET_DRIVER)
$(LINUX_DIR)/.unpacked: $(DL_DIR)/$(LINUX_SOURCE) $(DL_DIR)/$(LINUX_BINARY_WL_DRIVER) $(DL_DIR)/$(LINUX_BINARY_ET_DRIVER)
-mkdir -p $(BUILD_DIR)
bzcat $(DL_DIR)/$(LINUX_SOURCE) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) -
# extract linksys binary kernel stuff and include/shared files
zcat $(DL_DIR)/$(LINKSYS_KERNEL_TGZ) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) -
ln -sf $(LINUX_DIR)-$(LINUX_VERSION) $(LINUX_DIR)
# extract wlan and lan binary only driver
zcat $(DL_DIR)/$(LINUX_BINARY_WL_DRIVER) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) -
zcat $(DL_DIR)/$(LINUX_BINARY_ET_DRIVER) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) -
touch $(LINUX_DIR)/.unpacked
$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
$(PATCH) $(LINUX_DIR) $(LINUX_PATCHES)
# copy kernel source which is maintained in openwrt via cvs
cp -a $(LINUX_KERNEL_SOURCE)/* $(LINUX_DIR)
# copy binary drivers
cp -a $(BUILD_DIR)/wl/*.o $(LINUX_DIR)/drivers/net/wl
cp -a $(BUILD_DIR)/et/*.o $(LINUX_DIR)/drivers/net/et
touch $(LINUX_DIR)/.patched
$(LINUX_DIR)/.configured: $(LINUX_DIR)/.patched
-cp $(LINUX_KCONFIG) $(LINUX_DIR)/.config
#ifeq ($(BR2_TARGET_ROOTFS_SQUASHFS_LZMA),y)
# $(SED) "s,rootfstype=jffs2,rootfstype=squashfs," $(LINUX_DIR)/.config
#endif
#ifeq ($(BR2_TARGET_ROOTFS_SQUASHFS),y)
# $(SED) "s,rootfstype=jffs2,rootfstype=squashfs," $(LINUX_DIR)/.config
#endif
$(SED) "s,^CROSS_COMPILE.*,CROSS_COMPILE=$(KERNEL_CROSS),g;" \
$(LINUX_DIR)/Makefile \
$(LINUX_DIR)/arch/mips/Makefile
@ -106,5 +110,4 @@ linux-dirclean:
rm -rf $(LINUX_DIR)-$(LINUX_VERSION)
rm -rf $(LINUX_DIR)
rm -rf $(BUILD_DIR)/modules
rm -rf $(BUILD_DIR)/linksys-kernel