diff options
Diffstat (limited to 'examples/standalone')
23 files changed, 4357 insertions, 0 deletions
| diff --git a/examples/standalone/.gitignore b/examples/standalone/.gitignore new file mode 100644 index 000000000..0d1864cc2 --- /dev/null +++ b/examples/standalone/.gitignore @@ -0,0 +1,11 @@ +/82559_eeprom +/hello_world +/interrupt +/mem_to_mem_idma2intr +/test_burst +/timer +/sched +/smc91111_eeprom +/smc911x_eeprom +*.bin +*.srec diff --git a/examples/standalone/82559_eeprom.c b/examples/standalone/82559_eeprom.c new file mode 100644 index 000000000..5e2eee9e9 --- /dev/null +++ b/examples/standalone/82559_eeprom.c @@ -0,0 +1,357 @@ + +/* + * Copyright 1998-2001 by Donald Becker. + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Contact the author for use under other terms. + * + * This program must be compiled with "-O"! + * See the bottom of this file for the suggested compile-command. + * + * The author may be reached as becker@scyld.com, or C/O + *  Scyld Computing Corporation + *  410 Severn Ave., Suite 210 + *  Annapolis MD 21403 + * + * Common-sense licensing statement: Using any portion of this program in + * your own program means that you must give credit to the original author + * and release the resulting code under the GPL. + */ + +#define _PPC_STRING_H_		/* avoid unnecessary str/mem functions */ + +#include <common.h> +#include <exports.h> +#include <asm/io.h> + + +/* Default EEPROM for i82559 */ +static unsigned short default_eeprom[64] = { +	0x0100, 0x0302, 0x0504, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0x40c0, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + +static unsigned short eeprom[256]; + +static int eeprom_size = 64; +static int eeprom_addr_size = 6; + +static int debug = 0; + +static inline unsigned short swap16(unsigned short x) +{ +	return (((x & 0xff) << 8) | ((x & 0xff00) >> 8)); +} + + +void * memcpy(void * dest,const void *src,size_t count) +{ +	char *tmp = (char *) dest, *s = (char *) src; + +	while (count--) +		*tmp++ = *s++; + +	return dest; +} + + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD	(5) +#define EE_READ_CMD		(6) +#define EE_ERASE_CMD	(7) + +/* Serial EEPROM section. */ +#define EE_SHIFT_CLK	0x01	/* EEPROM shift clock. */ +#define EE_CS			0x02	/* EEPROM chip select. */ +#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */ +#define EE_DATA_READ	0x08	/* EEPROM chip data out. */ +#define EE_ENB			(0x4800 | EE_CS) +#define EE_WRITE_0		0x4802 +#define EE_WRITE_1		0x4806 +#define EE_OFFSET		14 + +/* Delay between EEPROM clock transitions. */ +#define eeprom_delay(ee_addr)	inw(ee_addr) + +/* Wait for the EEPROM to finish the previous operation. */ +static int eeprom_busy_poll(long ee_ioaddr) +{ +	int i; +	outw(EE_ENB, ee_ioaddr); +	for (i = 0; i < 10000; i++)			/* Typical 2000 ticks */ +		if (inw(ee_ioaddr) & EE_DATA_READ) +			break; +	return i; +} + +/* This executes a generic EEPROM command, typically a write or write enable. +   It returns the data output from the EEPROM, and thus may also be used for +   reads. */ +static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) +{ +	unsigned retval = 0; +	long ee_addr = ioaddr + EE_OFFSET; + +	if (debug > 1) +		printf(" EEPROM op 0x%x: ", cmd); + +	outw(EE_ENB | EE_SHIFT_CLK, ee_addr); + +	/* Shift the command bits out. */ +	do { +		short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; +		outw(dataval, ee_addr); +		eeprom_delay(ee_addr); +		if (debug > 2) +			printf("%X", inw(ee_addr) & 15); +		outw(dataval | EE_SHIFT_CLK, ee_addr); +		eeprom_delay(ee_addr); +		retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); +	} while (--cmd_len >= 0); +#if 0 +	outw(EE_ENB, ee_addr); +#endif +	/* Terminate the EEPROM access. */ +	outw(EE_ENB & ~EE_CS, ee_addr); +	if (debug > 1) +		printf(" EEPROM result is 0x%5.5x.\n", retval); +	return retval; +} + +static int read_eeprom(long ioaddr, int location, int addr_len) +{ +	return do_eeprom_cmd(ioaddr, ((EE_READ_CMD << addr_len) | location) +		<< 16 , 3 + addr_len + 16) & 0xffff; +} + +static void write_eeprom(long ioaddr, int index, int value, int addr_len) +{ +	long ee_ioaddr = ioaddr + EE_OFFSET; +	int i; + +	/* Poll for previous op finished. */ +	eeprom_busy_poll(ee_ioaddr);			/* Typical 0 ticks */ +	/* Enable programming modes. */ +	do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); +	/* Do the actual write. */ +	do_eeprom_cmd(ioaddr, +				  (((EE_WRITE_CMD<<addr_len) | index)<<16) | (value & 0xffff), +				  3 + addr_len + 16); +	/* Poll for write finished. */ +	i = eeprom_busy_poll(ee_ioaddr);			/* Typical 2000 ticks */ +	if (debug) +		printf(" Write finished after %d ticks.\n", i); +	/* Disable programming. This command is not instantaneous, so we check +	   for busy before the next op. */ +	do_eeprom_cmd(ioaddr, (0x40 << (addr_len-4)), 3 + addr_len); +	eeprom_busy_poll(ee_ioaddr); +} + +static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr) +{ +	unsigned short checksum = 0; +	int size_test; +	int i; + +	printf("Resetting i82559 EEPROM @ 0x%08lx ... ", ioaddr); + +	size_test = do_eeprom_cmd(ioaddr, (EE_READ_CMD << 8) << 16, 27); +	eeprom_addr_size = (size_test & 0xffe0000) == 0xffe0000 ? 8 : 6; +	eeprom_size = 1 << eeprom_addr_size; + +	memcpy(eeprom, default_eeprom, sizeof default_eeprom); + +	for (i = 0; i < 3; i++) +		eeprom[i] = (hwaddr[i*2+1]<<8) + hwaddr[i*2]; + +	/* Recalculate the checksum. */ +	for (i = 0; i < eeprom_size - 1; i++) +		checksum += eeprom[i]; +	eeprom[i] = 0xBABA - checksum; + +	for (i = 0; i < eeprom_size; i++) +		write_eeprom(ioaddr, i, eeprom[i], eeprom_addr_size); + +	for (i = 0; i < eeprom_size; i++) +		if (read_eeprom(ioaddr, i, eeprom_addr_size) != eeprom[i]) { +			printf("failed\n"); +			return 1; +		} + +	printf("done\n"); +	return 0; +} + +static unsigned int hatoi(char *p, char **errp) +{ +	unsigned int res = 0; + +	while (1) { +		switch (*p) { +		case 'a': +		case 'b': +		case 'c': +		case 'd': +		case 'e': +		case 'f': +			res |= (*p - 'a' + 10); +			break; +		case 'A': +		case 'B': +		case 'C': +		case 'D': +		case 'E': +		case 'F': +			res |= (*p - 'A' + 10); +			break; +		case '0': +		case '1': +		case '2': +		case '3': +		case '4': +		case '5': +		case '6': +		case '7': +		case '8': +		case '9': +			res |= (*p - '0'); +			break; +		default: +			if (errp) { +				*errp = p; +			} +		return res; +		} +		p++; +		if (*p == 0) { +			break; +		} +		res <<= 4; +	} + +	if (errp) { +		*errp = NULL; +	} + +	return res; +} + +static unsigned char *gethwaddr(char *in, unsigned char *out) +{ +	char tmp[3]; +	int i; +	char *err; + +	for (i=0;i<6;i++) { +		if (in[i*3+2] == 0 && i == 5) { +			out[i] = hatoi(&in[i*3], &err); +			if (err) { +				return NULL; +			} +		} else if (in[i*3+2] == ':' && i < 5) { +			tmp[0] = in[i*3]; +			tmp[1] = in[i*3+1]; +			tmp[2] = 0; +			out[i] = hatoi(tmp, &err); +			if (err) { +				return NULL; +			} +		} else { +			return NULL; +		} +	} + +	return out; +} + +static u32 +read_config_dword(int bus, int dev, int func, int reg) +{ +	u32 res; + +	outl(0x80000000|(bus&0xff)<<16|(dev&0x1f)<<11|(func&7)<<8|(reg&0xfc), +	     0xcf8); +	res = inl(0xcfc); +	outl(0, 0xcf8); +	return res; +} + +static u16 +read_config_word(int bus, int dev, int func, int reg) +{ +	u32 res; + +	outl(0x80000000|(bus&0xff)<<16|(dev&0x1f)<<11|(func&7)<<8|(reg&0xfc), +	     0xcf8); +	res = inw(0xcfc + (reg & 2)); +	outl(0, 0xcf8); +	return res; +} + +static void +write_config_word(int bus, int dev, int func, int reg, u16 data) +{ + +	outl(0x80000000|(bus&0xff)<<16|(dev&0x1f)<<11|(func&7)<<8|(reg&0xfc), +	     0xcf8); +	outw(data, 0xcfc + (reg & 2)); +	outl(0, 0xcf8); +} + + +int main (int argc, char *argv[]) +{ +	unsigned char *eth_addr; +	uchar buf[6]; +	int instance; + +	app_startup(argv); +	if (argc != 2) { +		printf ("call with base Ethernet address\n"); +		return 1; +	} + + +	eth_addr = gethwaddr(argv[1], buf); +	if (NULL == eth_addr) { +		printf ("Can not parse ethernet address\n"); +		return 1; +	} +	if (eth_addr[5] & 0x01) { +		printf("Base Ethernet address must be even\n"); +	} + + +	for (instance = 0; instance < 2; instance ++)  { +		unsigned int io_addr; +		unsigned char mac[6]; +		int bar1 = read_config_dword(0, 6+instance, 0, 0x14); +		if (! (bar1 & 1)) { +			printf("ETH%d is disabled %x\n", instance, bar1); +		} else { +			printf("ETH%d IO=0x%04x\n", instance, bar1 & ~3); +		} +		io_addr = (bar1 & (~3L)); + + +		write_config_word(0, 6+instance, 0, 4, +				  read_config_word(0, 6+instance, 0, 4) | 1); +		printf("ETH%d CMD %04x\n", instance, +			   read_config_word(0, 6+instance, 0, 4)); + +		memcpy(mac, eth_addr, 6); +		mac[5] += instance; + +		printf("got io=%04x, ha=%02x:%02x:%02x:%02x:%02x:%02x\n", +			   io_addr, mac[0], mac[1], mac[2], +			   mac[3], mac[4], mac[5]); +		reset_eeprom(io_addr, mac); +	} +	return 0; +} diff --git a/examples/standalone/Makefile b/examples/standalone/Makefile new file mode 100644 index 000000000..dbcfa920e --- /dev/null +++ b/examples/standalone/Makefile @@ -0,0 +1,198 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that 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 +# + +ifeq ($(ARCH),ppc) +LOAD_ADDR = 0x40000 +endif + +ifeq ($(ARCH),i386) +LOAD_ADDR = 0x40000 +endif + +ifeq ($(ARCH),arm) +ifeq ($(BOARD),omap2420h4) +LOAD_ADDR = 0x80300000 +else +ifeq ($(CPU),omap3) +LOAD_ADDR = 0x80300000 +else +LOAD_ADDR = 0xc100000 +endif +endif +endif + +ifeq ($(ARCH),mips) +LOAD_ADDR = 0x80200000 -T mips.lds +endif + +ifeq ($(ARCH),nios) +LOAD_ADDR = 0x00800000 -L $(gcclibdir)/m32 -T nios.lds +endif + +ifeq ($(ARCH),nios2) +LOAD_ADDR = 0x02000000 -L $(gcclibdir) -T nios2.lds +endif + +ifeq ($(ARCH),m68k) +LOAD_ADDR = 0x20000  -L $(clibdir) +endif + +ifeq ($(ARCH),microblaze) +LOAD_ADDR = 0x80F00000 +endif + +ifeq ($(ARCH),blackfin) +LOAD_ADDR = 0x1000 +endif + +ifeq ($(ARCH),avr32) +LOAD_ADDR = 0x00000000 +endif + +ifeq ($(ARCH),sh) +LOAD_ADDR = 0x8C000000 +ifeq ($(CPU),sh2) +BIG_ENDIAN=y +endif +endif + +ifeq ($(ARCH),sparc) +LOAD_ADDR = 0x00000000 -L $(gcclibdir) -T sparc.lds +endif + +include $(TOPDIR)/config.mk + +ELF	= hello_world +SREC	= hello_world.srec +BIN	= hello_world.bin + +ifeq ($(CPU),mpc8xx) +ELF	+= test_burst +SREC	+= test_burst.srec +BIN	+= test_burst.bin +endif + +ifeq ($(ARCH),i386) +ELF	+= 82559_eeprom +SREC	+= 82559_eeprom.srec +BIN	+= 82559_eeprom.bin +endif + +ifeq ($(ARCH),ppc) +ELF	+= sched +SREC	+= sched.srec +BIN	+= sched.bin +endif + +ifeq ($(ARCH),blackfin) +BFIN_BIN = smc91111_eeprom smc911x_eeprom +ELF	+= $(BFIN_BIN) +SREC	+= $(addsuffix .srec,$(BFIN_BIN)) +BIN	+= $(addsuffix .bin,$(BFIN_BIN)) +endif + +# The following example is pretty 8xx specific... +ifeq ($(CPU),mpc8xx) +ELF	+= timer +SREC	+= timer.srec +BIN	+= timer.bin +endif + +# The following example is 8260 specific... +ifeq ($(CPU),mpc8260) +ELF	+= mem_to_mem_idma2intr +SREC	+= mem_to_mem_idma2intr.srec +BIN	+= mem_to_mem_idma2intr.bin +endif + +# Demo for 52xx IRQs +ifeq ($(CPU),mpc5xxx) +ELF	+= interrupt +SREC	+= interrupt.srec +BIN	+= interrupt.bin +endif + +# Utility for resetting i82559 EEPROM +ifeq ($(BOARD),oxc) +ELF	+= eepro100_eeprom +SREC	+= eepro100_eeprom.srec +BIN	+= eepro100_eeprom.bin +endif + +ifeq ($(BIG_ENDIAN),y) +EX_LDFLAGS += -EB +endif + +COBJS	:= $(SREC:.srec=.o) + +LIB	= $(obj)libstubs.a +LIBAOBJS= +ifeq ($(ARCH),ppc) +LIBAOBJS+= $(ARCH)_longjmp.o $(ARCH)_setjmp.o +endif +ifeq ($(CPU),mpc8xx) +LIBAOBJS+= test_burst_lib.o +endif +LIBCOBJS= stubs.o + +LIBOBJS	= $(addprefix $(obj),$(LIBAOBJS) $(LIBCOBJS)) + +SRCS	:= $(COBJS:.o=.c) $(LIBCOBJS:.o=.c) $(if $(LIBAOBJS),$(LIBAOBJS:.o=.S)) +OBJS	:= $(addprefix $(obj),$(COBJS)) +ELF	:= $(addprefix $(obj),$(ELF)) +BIN	:= $(addprefix $(obj),$(BIN)) +SREC	:= $(addprefix $(obj),$(SREC)) + +gcclibdir := $(shell dirname `$(CC) -print-libgcc-file-name`) +clibdir := $(shell dirname `$(CC) $(CFLAGS) -print-file-name=libc.a`) + +CPPFLAGS += -I.. + +all:	$(obj).depend $(OBJS) $(LIB) $(SREC) $(BIN) $(ELF) + +######################################################################### +$(LIB):	$(obj).depend $(LIBOBJS) +		$(AR) $(ARFLAGS) $@ $(LIBOBJS) + +$(ELF): +$(obj)%:	$(obj)%.o $(LIB) +		$(LD) -g $(EX_LDFLAGS) -Ttext $(LOAD_ADDR) \ +			-o $@ -e $(SYM_PREFIX)$(notdir $(<:.o=)) $< $(LIB) \ +			-L$(gcclibdir) -lgcc + +$(SREC): +$(obj)%.srec:	$(obj)% +		$(OBJCOPY) -O srec $< $@ 2>/dev/null + +$(BIN): +$(obj)%.bin:	$(obj)% +		$(OBJCOPY) -O binary $< $@ 2>/dev/null + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/examples/standalone/README.smc91111_eeprom b/examples/standalone/README.smc91111_eeprom new file mode 100644 index 000000000..28e7e6978 --- /dev/null +++ b/examples/standalone/README.smc91111_eeprom @@ -0,0 +1,246 @@ +This is the readme for the Das U-Boot standalone program smc91111 + +The main purpose of this is to manage MAC addresses on platforms +which include the SMC91111 integrated 10/100 MAC Phy, with attached +EEPROMs. + + +Contents: +------------------------ +1. Ensuring U-boot's MAC address can be set in hardware +2. Running the smc91111_eeprom program +3. Setting MAC addresses +4. Other things you can do with this +5. Things to be done. + + +1. Ensuring U-boot's MAC address can be set in hardware +-------------------------------------------------------------------------- + +On the Internet - MAC addresses are very important. Short for Media +Access Control address, a hardware address that uniquely identifies +each node of a network. When things are not unique - bad things +can happen.  This is why U-Boot makes it difficult to change MAC +addresses. + +To find out who has a MAC address, or to purchase MAC addresses, goto +the IEEE, at: +http://standards.ieee.org/regauth/oui/index.shtml + +To change your MAC address, there can not be a MAC address predefined in +U-Boot. To ensure that this does not occur, check your +include/configs/<board_name>.h file, and check to see that the following +settings are _not_ or commented out there. + +#define HARDCODE_MAC			1 +#define CONFIG_ETHADDR			02:80:ad:20:31:b8 + +The purpose of HARDCODE_MAC is to hardcode the MAC address in software, +(not what we want), or to preset it to 02:80:ad:20:31:b8 (not what we +want either). + +You can check this in a running U-Boot, by doing a power cycle, then +before U-Boot tries to do any networking, running the 'printenv' command + +  BOOT> printenv + +  ethaddr=02:80:ad:20:31:b8 + +If you see the 'ethaddr' variable show up, like the above, you need to +recompile U-Boot, with the above settings commented out of the +include/configs/<board_name>.h file. + +2. Running the smc91111_eeprom program +--------------------------------------------------------------------- + +After Uboot is compiled, there should be three files of interest: +-rwxr-xr-x    1		8806 2004-10-11 14:00 smc91111_eeprom	    <- ELF +-rwxr-xr-x    1		3440 2004-10-11 14:00 smc91111_eeprom.bin   <- BIN +-rwxr-xr-x    1		9524 2004-10-11 14:00 smc91111_eeprom.srec  <- SREC + +if there is not, check the examples/Makefile, and ensure there is something +like for your architecture: + +   ifeq ($(ARCH),blackfin) +   SREC	  += smc91111_eeprom.srec +   BIN	  += smc91111_eeprom.bin smc91111_eeprom +   endif + +To load the files: there are two methods: a) serial or b) network. Since +it is not a good idea to start doing things on the network before the +MAC address is set, this example will do things over serial. + +a) Loading the elf file via the serial port +-------------------------------------------- +Loading the elf is very easy - just ensure that the location +you specify things to load as is not the load address specified +in the Makefile. + +BOOT> loadb 0x1000000 + +## Ready for binary (kermit) download to 0x01000000 at 57600 bps... + +(type CNTL-\ then C) +(Back at local machine) +---------------------------------------------------- +Kermit>send ~/u-boot_1.1.1/examples/smc91111_eeprom +Kermit>connect + +Connecting to /dev/ttyS0, speed 57600 + Escape character: Ctrl-\ (ASCII 28, FS): enabled +Type the escape character followed by C to get back, +or followed by ? to see other options. +---------------------------------------------------- +## Total Size	   = 0x00002266 = 8806 Bytes +## Start Addr	   = 0x01000000 + +BOOT> bootelf 0x1000000 + +Loading .text @ 0x00001000 (3440 bytes) +## Starting application at 0x000010d8 ... + +SMC91111> + +b) Loading the binary file via the serial port +----------------------------------------------- +For many toolchains, the entry point is not the load point. +The Load point is a hard coded address from the +examples/Makefile. The entry point can be found by doing something +like: + +  u-boot_1.1.1/examples> bfin-elf-objdump -d smc91111_eeprom |less + +  smc91111_eeprom:     file format elf32-bfin + +  Disassembly of section .text: + +  00001000 <smc91111_eeprom-0xd8>: +      1000: +  000010d8 <smc91111_eeprom>: + +You can see that the entry point (or the address that should be +jumped to is 0x10d8). This is also the same as the entry point +of the elf file. + +Now we load it to the actual load location: + +BOOT> loadb 0x1000 + +## Ready for binary (kermit) download to 0x00001000 at 57600 bps... + +(Back at pinky.dsl-only.net) +---------------------------------------------------- +Kermit>send /tftpboot/eeprom.bin +Kermit>connect + +Connecting to /dev/ttyS0, speed 57600 + Escape character: Ctrl-\ (ASCII 28, FS): enabled +Type the escape character followed by C to get back, +or followed by ? to see other options. +---------------------------------------------------- +## Total Size	   = 0x00000d70 = 3440 Bytes +## Start Addr	   = 0x00001000 + +BOOT> go 0x10D8 + +## Starting application at 0x000010D8 ... + +SMC91111> + +3. Setting MAC addresses +-------------------------------------------------------------------------- + +The MAC address can be stored in four locations: + +-Boot environmental variable in Flash <- can not change, without +					  re-flashing U-boot. +U-Boot environental variable	       <- can not change, without +					  resetting board/U-Boot +LAN91C111 Registers		       <- volitle +LAN91C111 EEPROM		       <- Non Volitle + +If you have not activated the network, and do not have a hardcoded +or pre-assigned MAC address in U-boot, the environmental variables +should be blank, and allow you to set things one time. + +To set the EEPROM MAC address to 12:34:56:78:9A:BC + +SMC91111> W E 20 3412 + +Writing EEPROM register 20 with 3412 +SMC91111> W E 21 7856 + +Writing EEPROM register 21 with 7856 +SMC91111> W E 22 BC9A + +Writing EEPROM register 22 with bc9a +EEPROM contents copied to MAC +SMC91111> P + +Current MAC Address in SMSC91111 12:34:56:78:9a:bc +Current MAC Address in EEPROM	 12:34:56:78:9a:bc + +(CNTRL-C to exit) +SMC91111> ## Application terminated, rc = 0x0 + +BOOT> reset +U-Boot 1.1.1 (gcc version: 3.3.3) +Release Version Beta released on Oct 10 2004 - 00:34:35 +Blackfin support by LG Soft India +For further information please check this link http://www.blackfin.uclinux.org +BOOT> ping 192.168.0.4 + +Using MAC Address 12:34:56:78:9A:BC +host 192.168.0.4 is alive + + +4. Other things that you can do +-------------------------------------------------------------------------- +After the stand alone application is running, there are a few options: + - P : Print the MAC + - D : Dump the LAN91C111 EEPROM contents + - M : Dump the LAN91C111 MAC contents + - C : Copies the MAC address from the EEPROM to the LAN91C111 + - W : Write a register in the EEPROM or in the MAC + +SMC91111> P + +Current MAC Address in SMSC91111 12:34:56:78:9a:bc +Current MAC Address in EEPROM	 12:34:56:78:9a:bc + +SMC91111> D + +IOS2-0	  000	  001	  002	  003	  004	  005	  006	  007 +CONFIG 00:ffff 04:ffff 08:ffff 0c:ffff 10:ffff 14:ffff 18:ffff 1c:ffff +BASE   01:ffff 05:ffff 09:ffff 0d:ffff 11:ffff 15:ffff 19:ffff 1d:ffff +       02:ffff 06:ffff 0a:ffff 0e:0020 12:ffff 16:ffff 1a:ffff 1e:ffff +       03:ffff 07:ffff 0b:ffff 0f:ffff 13:ffff 17:ffff 1b:ffff 1f:ffff + +20:3412 21:7856 22:bc9a 23:ffff 24:ffff 25:ffff 26:ffff 27:ffff +28:ffff 29:ffff 2a:ffff 2b:ffff 2c:ffff 2d:ffff 2e:ffff 2f:ffff +30:ffff 31:ffff 32:ffff 33:ffff 34:ffff 35:ffff 36:ffff 37:ffff +38:ffff 39:ffff 3a:ffff 3b:ffff 3c:ffff 3d:ffff 3e:ffff 3f:ffff + +SMC91111> M + +    Bank0 Bank1 Bank2 Bank3 +00  0000  a0b1	3332  0000 +02  0000  1801	8000  0000 +04  0000  3412	8080  0000 +06  0000  7856	003f  0000 +08  0404  bc9a	02df  3332 +0a  0000  ffff	02df  3391 +0c  0000  1214	0004  001f +0e  3300  3301	3302  3303 + +SMC91111> C + +EEPROM contents copied to MAC + +SMC91111> W E 2A ABCD + +Writing EEPROM register 2a with abcd + +SMC91111> W M 14 FF00 + +Writing MAC register bank 1, reg 04 with ff00 diff --git a/examples/standalone/eepro100_eeprom.c b/examples/standalone/eepro100_eeprom.c new file mode 100644 index 000000000..2b15d05ad --- /dev/null +++ b/examples/standalone/eepro100_eeprom.c @@ -0,0 +1,215 @@ +/* + * Copyright 1998-2001 by Donald Becker. + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Contact the author for use under other terms. + * + * This program must be compiled with "-O"! + * See the bottom of this file for the suggested compile-command. + * + * The author may be reached as becker@scyld.com, or C/O + *  Scyld Computing Corporation + *  410 Severn Ave., Suite 210 + *  Annapolis MD 21403 + * + * Common-sense licensing statement: Using any portion of this program in + * your own program means that you must give credit to the original author + * and release the resulting code under the GPL. + */ + +/* avoid unnecessary memcpy function */ +#define __HAVE_ARCH_MEMCPY +#define _PPC_STRING_H_ + +#include <common.h> +#include <exports.h> + +static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr); + +int eepro100_eeprom(int argc, char *argv[]) +{ +	int ret = 0; + +	unsigned char hwaddr1[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x05 }; +	unsigned char hwaddr2[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x06 }; + +	app_startup(argv); + +#if defined(CONFIG_OXC) +	ret |= reset_eeprom(0x80000000, hwaddr1); +	ret |= reset_eeprom(0x81000000, hwaddr2); +#endif + +	return ret; +} + +/* Default EEPROM for i82559 */ +static unsigned short default_eeprom[64] = { +	0x0100, 0x0302, 0x0504, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0x40c0, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + +static unsigned short eeprom[256]; + +static int eeprom_size = 64; +static int eeprom_addr_size = 6; + +static int debug = 0; + +static inline unsigned short swap16(unsigned short x) +{ +	return (((x & 0xff) << 8) | ((x & 0xff00) >> 8)); +} + +static inline void outw(short data, long addr) +{ +	*(volatile short *)(addr) = swap16(data); +} + +static inline short inw(long addr) +{ +	return swap16(*(volatile short *)(addr)); +} + +static inline void *memcpy(void *dst, const void *src, unsigned int len) +{ +	char *ret = dst; +	while (len-- > 0) { +		*ret++ = *((char *)src); +		src++; +	} +	return (void *)ret; +} + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD	(5) +#define EE_READ_CMD		(6) +#define EE_ERASE_CMD	(7) + +/* Serial EEPROM section. */ +#define EE_SHIFT_CLK	0x01	/* EEPROM shift clock. */ +#define EE_CS			0x02	/* EEPROM chip select. */ +#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */ +#define EE_DATA_READ	0x08	/* EEPROM chip data out. */ +#define EE_ENB			(0x4800 | EE_CS) +#define EE_WRITE_0		0x4802 +#define EE_WRITE_1		0x4806 +#define EE_OFFSET		14 + +/* Delay between EEPROM clock transitions. */ +#define eeprom_delay(ee_addr)	inw(ee_addr) + +/* Wait for the EEPROM to finish the previous operation. */ +static int eeprom_busy_poll(long ee_ioaddr) +{ +	int i; +	outw(EE_ENB, ee_ioaddr); +	for (i = 0; i < 10000; i++)			/* Typical 2000 ticks */ +		if (inw(ee_ioaddr) & EE_DATA_READ) +			break; +	return i; +} + +/* This executes a generic EEPROM command, typically a write or write enable. +   It returns the data output from the EEPROM, and thus may also be used for +   reads. */ +static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) +{ +	unsigned retval = 0; +	long ee_addr = ioaddr + EE_OFFSET; + +	if (debug > 1) +		printf(" EEPROM op 0x%x: ", cmd); + +	outw(EE_ENB | EE_SHIFT_CLK, ee_addr); + +	/* Shift the command bits out. */ +	do { +		short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; +		outw(dataval, ee_addr); +		eeprom_delay(ee_addr); +		if (debug > 2) +			printf("%X", inw(ee_addr) & 15); +		outw(dataval | EE_SHIFT_CLK, ee_addr); +		eeprom_delay(ee_addr); +		retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); +	} while (--cmd_len >= 0); +#if 0 +	outw(EE_ENB, ee_addr); +#endif +	/* Terminate the EEPROM access. */ +	outw(EE_ENB & ~EE_CS, ee_addr); +	if (debug > 1) +		printf(" EEPROM result is 0x%5.5x.\n", retval); +	return retval; +} + +static int read_eeprom(long ioaddr, int location, int addr_len) +{ +	return do_eeprom_cmd(ioaddr, ((EE_READ_CMD << addr_len) | location) +		<< 16 , 3 + addr_len + 16) & 0xffff; +} + +static void write_eeprom(long ioaddr, int index, int value, int addr_len) +{ +	long ee_ioaddr = ioaddr + EE_OFFSET; +	int i; + +	/* Poll for previous op finished. */ +	eeprom_busy_poll(ee_ioaddr);			/* Typical 0 ticks */ +	/* Enable programming modes. */ +	do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); +	/* Do the actual write. */ +	do_eeprom_cmd(ioaddr, +				  (((EE_WRITE_CMD<<addr_len) | index)<<16) | (value & 0xffff), +				  3 + addr_len + 16); +	/* Poll for write finished. */ +	i = eeprom_busy_poll(ee_ioaddr);			/* Typical 2000 ticks */ +	if (debug) +		printf(" Write finished after %d ticks.\n", i); +	/* Disable programming. This command is not instantaneous, so we check +	   for busy before the next op. */ +	do_eeprom_cmd(ioaddr, (0x40 << (addr_len-4)), 3 + addr_len); +	eeprom_busy_poll(ee_ioaddr); +} + +static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr) +{ +	unsigned short checksum = 0; +	int size_test; +	int i; + +	printf("Resetting i82559 EEPROM @ 0x%08lX ... ", ioaddr); + +	size_test = do_eeprom_cmd(ioaddr, (EE_READ_CMD << 8) << 16, 27); +	eeprom_addr_size = (size_test & 0xffe0000) == 0xffe0000 ? 8 : 6; +	eeprom_size = 1 << eeprom_addr_size; + +	memcpy(eeprom, default_eeprom, sizeof default_eeprom); + +	for (i = 0; i < 3; i++) +		eeprom[i] = (hwaddr[i*2+1]<<8) + hwaddr[i*2]; + +	/* Recalculate the checksum. */ +	for (i = 0; i < eeprom_size - 1; i++) +		checksum += eeprom[i]; +	eeprom[i] = 0xBABA - checksum; + +	for (i = 0; i < eeprom_size; i++) +		write_eeprom(ioaddr, i, eeprom[i], eeprom_addr_size); + +	for (i = 0; i < eeprom_size; i++) +		if (read_eeprom(ioaddr, i, eeprom_addr_size) != eeprom[i]) { +			printf("failed\n"); +			return 1; +		} + +	printf("done\n"); +	return 0; +} diff --git a/examples/standalone/hello_world.c b/examples/standalone/hello_world.c new file mode 100644 index 000000000..9317f6d8c --- /dev/null +++ b/examples/standalone/hello_world.c @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + +#include <common.h> +#include <exports.h> + +int hello_world (int argc, char *argv[]) +{ +	int i; + +	/* Print the ABI version */ +	app_startup(argv); +	printf ("Example expects ABI version %d\n", XF_VERSION); +	printf ("Actual U-Boot ABI version %d\n", (int)get_version()); + +	printf ("Hello World\n"); + +	printf ("argc = %d\n", argc); + +	for (i=0; i<=argc; ++i) { +		printf ("argv[%d] = \"%s\"\n", +			i, +			argv[i] ? argv[i] : "<NULL>"); +	} + +	printf ("Hit any key to exit ... "); +	while (!tstc()) +		; +	/* consume input */ +	(void) getc(); + +	printf ("\n\n"); +	return (0); +} diff --git a/examples/standalone/interrupt.c b/examples/standalone/interrupt.c new file mode 100644 index 000000000..f3061d1ec --- /dev/null +++ b/examples/standalone/interrupt.c @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2006 + * Detlev Zundel, DENX Software Engineering, dzu@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 a very simple standalone application demonstrating + * catching IRQs on the MPC52xx architecture. + * + * The interrupt to be intercepted can be specified as an argument + * to the application.  Specifying nothing will intercept IRQ1 on the + * MPC5200 platform.  On the CR825 carrier board from MicroSys this + * maps to the ABORT switch :) + * + * Note that the specified vector is only a logical number specified + * by the respective header file. + */ + +#include <common.h> +#include <exports.h> +#include <config.h> + +#if defined(CONFIG_MPC5xxx) +#define DFL_IRQ MPC5XXX_IRQ1 +#else +#define DFL_IRQ 0 +#endif + +static void irq_handler (void *arg); + +int interrupt (int argc, char *argv[]) +{ +	int c, irq = -1; + +	app_startup (argv); + +	if (argc > 1) +		irq = simple_strtoul (argv[1], NULL, 0); +	if ((irq < 0) || (irq > NR_IRQS)) +		irq = DFL_IRQ; + +	printf ("Installing handler for irq vector %d and doing busy wait\n", +		irq); +	printf ("Press 'q' to quit\n"); + +	/* Install interrupt handler */ +	install_hdlr (irq, irq_handler, NULL); +	while ((c = getc ()) != 'q') { +		printf ("Ok, ok, I am still alive!\n"); +	} + +	free_hdlr (irq); +	printf ("\nInterrupt handler has been uninstalled\n"); + +	return (0); +} + +/* + * Handler for interrupt + */ +static void irq_handler (void *arg) +{ +	/* just for demonstration */ +	printf ("+"); +} diff --git a/examples/standalone/mem_to_mem_idma2intr.c b/examples/standalone/mem_to_mem_idma2intr.c new file mode 100644 index 000000000..15779d0a1 --- /dev/null +++ b/examples/standalone/mem_to_mem_idma2intr.c @@ -0,0 +1,384 @@ +/* The dpalloc function used and implemented in this file was derieved + * from PPCBoot/U-Boot file "cpu/mpc8260/commproc.c". + */ + +/* Author: Arun Dharankar <ADharankar@ATTBI.Com> + * This example is meant to only demonstrate how the IDMA could be used. + */ + +/* + * This file is based on "arch/ppc/8260_io/commproc.c" - here is it's + * copyright notice: + * + * General Purpose functions for the global management of the + * 8260 Communication Processor Module. + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com) + *  2.3.99 Updates + * + * In addition to the individual control of the communication + * channels, there are a few functions that globally affect the + * communication processor. + * + * Buffer descriptors must be allocated from the dual ported memory + * space.  The allocator for that is here.  When the communication + * process is reset, we reclaim the memory available.  There is + * currently no deallocator for this memory. + */ + + +#include <common.h> +#include <exports.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define STANDALONE + +#ifndef STANDALONE			/* Linked into/Part of  PPCBoot */ +#include <command.h> +#include <watchdog.h> +#else					/* Standalone app of PPCBoot */ +#define WATCHDOG_RESET() {						\ +			*(ushort *)(CONFIG_SYS_IMMR + 0x1000E) = 0x556c;	\ +			*(ushort *)(CONFIG_SYS_IMMR + 0x1000E) = 0xaa39;	\ +		} +#endif	/* STANDALONE */ + +static int debug = 1; + +#define DEBUG(fmt, args...)	 {					\ +	if(debug != 0) {						\ +		printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);	\ +		printf(fmt, ##args);					\ +	}								\ +} + +#define CPM_CR_IDMA1_SBLOCK  (0x14) +#define CPM_CR_IDMA2_SBLOCK  (0x15) +#define CPM_CR_IDMA3_SBLOCK  (0x16) +#define CPM_CR_IDMA4_SBLOCK  (0x17) +#define CPM_CR_IDMA1_PAGE    (0x07) +#define CPM_CR_IDMA2_PAGE    (0x08) +#define CPM_CR_IDMA3_PAGE    (0x09) +#define CPM_CR_IDMA4_PAGE    (0x0a) +#define PROFF_IDMA1_BASE     ((uint)0x87fe) +#define PROFF_IDMA2_BASE     ((uint)0x88fe) +#define PROFF_IDMA3_BASE     ((uint)0x89fe) +#define PROFF_IDMA4_BASE     ((uint)0x8afe) + +#define CPM_CR_INIT_TRX     ((ushort)0x0000) +#define CPM_CR_FLG  ((ushort)0x0001) + +#define mk_cr_cmd(PG, SBC, MCN, OP) \ +    ((PG << 26) | (SBC << 21) | (MCN << 6) | OP) + + +#pragma pack(1) +typedef struct ibdbits { +	unsigned b_valid:1; +	unsigned b_resv1:1; +	unsigned b_wrap:1; +	unsigned b_interrupt:1; +	unsigned b_last:1; +	unsigned b_resv2:1; +	unsigned b_cm:1; +	unsigned b_resv3:2; +	unsigned b_sdn:1; +	unsigned b_ddn:1; +	unsigned b_dgbl:1; +	unsigned b_dbo:2; +	unsigned b_resv4:1; +	unsigned b_ddtb:1; +	unsigned b_resv5:2; +	unsigned b_sgbl:1; +	unsigned b_sbo:2; +	unsigned b_resv6:1; +	unsigned b_sdtb:1; +	unsigned b_resv7:9; +} ibdbits_t; + +#pragma pack(1) +typedef union ibdbitsu { +	ibdbits_t b; +	uint i; +} ibdbitsu_t; + +#pragma pack(1) +typedef struct idma_buf_desc { +	ibdbitsu_t ibd_bits;		/* Status and Control */ +	uint ibd_datlen;		/* Data length in buffer */ +	uint ibd_sbuf;			/* Source buffer addr in host mem */ +	uint ibd_dbuf;			/* Destination buffer addr in host mem */ +} ibd_t; + + +#pragma pack(1) +typedef struct dcmbits { +	unsigned b_fb:1; +	unsigned b_lp:1; +	unsigned b_resv1:3; +	unsigned b_tc2:1; +	unsigned b_resv2:1; +	unsigned b_wrap:3; +	unsigned b_sinc:1; +	unsigned b_dinc:1; +	unsigned b_erm:1; +	unsigned b_dt:1; +	unsigned b_sd:2; +} dcmbits_t; + +#pragma pack(1) +typedef union dcmbitsu { +	dcmbits_t b; +	ushort i; +} dcmbitsu_t; + +#pragma pack(1) +typedef struct pram_idma { +	ushort pi_ibase; +	dcmbitsu_t pi_dcmbits; +	ushort pi_ibdptr; +	ushort pi_dprbuf; +	ushort pi_bufinv;		/* internal to CPM */ +	ushort pi_ssmax; +	ushort pi_dprinptr;		/* internal to CPM */ +	ushort pi_sts; +	ushort pi_dproutptr;		/* internal to CPM */ +	ushort pi_seob; +	ushort pi_deob; +	ushort pi_dts; +	ushort pi_retadd; +	ushort pi_resv1;		/* internal to CPM */ +	uint pi_bdcnt; +	uint pi_sptr; +	uint pi_dptr; +	uint pi_istate; +} pram_idma_t; + + +volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; +volatile ibd_t *bdf; +volatile pram_idma_t *piptr; + +volatile int dmadone; +volatile int *dmadonep = &dmadone; +void dmadone_handler (void *); + +int idma_init (void); +void idma_start (int, int, int, uint, uint, int); +uint dpalloc (uint, uint); + + +uint dpinit_done = 0; + + +#ifdef STANDALONE +int ctrlc (void) +{ +	if (tstc()) { +		switch (getc ()) { +		case 0x03:		/* ^C - Control C */ +			return 1; +		default: +			break; +		} +	} +	return 0; +} +void * memset(void * s,int c,size_t count) +{ +	char *xs = (char *) s; +	while (count--) +		*xs++ = c; +	return s; +} +int memcmp(const void * cs,const void * ct,size_t count) +{ +	const unsigned char *su1, *su2; +	int res = 0; +	for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) +		if ((res = *su1 - *su2) != 0) +			break; +	return res; +} +#endif	/* STANDALONE */ + +#ifdef STANDALONE +int mem_to_mem_idma2intr (int argc, char *argv[]) +#else +int do_idma (bd_t * bd, int argc, char *argv[]) +#endif	/* STANDALONE */ +{ +	int i; + +	app_startup(argv); +	dpinit_done = 0; + +	idma_init (); + +	DEBUG ("Installing dma handler\n"); +	install_hdlr (7, dmadone_handler, (void *) bdf); + +	memset ((void *) 0x100000, 'a', 512); +	memset ((void *) 0x200000, 'b', 512); + +	for (i = 0; i < 32; i++) { +		printf ("Startin IDMA, iteration=%d\n", i); +		idma_start (1, 1, 512, 0x100000, 0x200000, 3); +	} + +	DEBUG ("Uninstalling dma handler\n"); +	free_hdlr (7); + +	return 0; +} + +void +idma_start (int sinc, int dinc, int sz, uint sbuf, uint dbuf, int ttype) +{ +	/* ttype is for M-M, M-P, P-M or P-P: not used for now */ + +	piptr->pi_istate = 0;	/* manual says: clear it before every START_IDMA */ +	piptr->pi_dcmbits.b.b_resv1 = 0; + +	if (sinc == 1) +		piptr->pi_dcmbits.b.b_sinc = 1; +	else +		piptr->pi_dcmbits.b.b_sinc = 0; + +	if (dinc == 1) +		piptr->pi_dcmbits.b.b_dinc = 1; +	else +		piptr->pi_dcmbits.b.b_dinc = 0; + +	piptr->pi_dcmbits.b.b_erm = 0; +	piptr->pi_dcmbits.b.b_sd = 0x00;	/* M-M */ + +	bdf->ibd_sbuf = sbuf; +	bdf->ibd_dbuf = dbuf; +	bdf->ibd_bits.b.b_cm = 0; +	bdf->ibd_bits.b.b_interrupt = 1; +	bdf->ibd_bits.b.b_wrap = 1; +	bdf->ibd_bits.b.b_last = 1; +	bdf->ibd_bits.b.b_sdn = 0; +	bdf->ibd_bits.b.b_ddn = 0; +	bdf->ibd_bits.b.b_dgbl = 0; +	bdf->ibd_bits.b.b_ddtb = 0; +	bdf->ibd_bits.b.b_sgbl = 0; +	bdf->ibd_bits.b.b_sdtb = 0; +	bdf->ibd_bits.b.b_dbo = 1; +	bdf->ibd_bits.b.b_sbo = 1; +	bdf->ibd_bits.b.b_valid = 1; +	bdf->ibd_datlen = 512; + +	*dmadonep = 0; + +	immap->im_sdma.sdma_idmr2 = (uchar) 0xf; + +	immap->im_cpm.cp_cpcr = mk_cr_cmd (CPM_CR_IDMA2_PAGE, +					   CPM_CR_IDMA2_SBLOCK, 0x0, +					   0x9) | 0x00010000; + +	while (*dmadonep != 1) { +		if (ctrlc ()) { +			DEBUG ("\nInterrupted waiting for DMA interrupt.\n"); +			goto done; +		} +		printf ("Waiting for DMA interrupt (dmadone=%d b_valid = %d)...\n", +			dmadone, bdf->ibd_bits.b.b_valid); +		udelay (1000000); +	} +	printf ("DMA complete notification received!\n"); + +  done: +	DEBUG ("memcmp(0x%08x, 0x%08x, 512) = %d\n", +		sbuf, dbuf, memcmp ((void *) sbuf, (void *) dbuf, 512)); + +	return; +} + +#define MAX_INT_BUFSZ	64 +#define DCM_WRAP	 0	/* MUST be consistant with MAX_INT_BUFSZ */ + +int idma_init (void) +{ +	uint memaddr; + +	immap->im_cpm.cp_rccr &= ~0x00F3FFFF; +	immap->im_cpm.cp_rccr |= 0x00A00A00; + +	memaddr = dpalloc (sizeof (pram_idma_t), 64); + +	*(volatile ushort *) &immap->im_dprambase[PROFF_IDMA2_BASE] = memaddr; +	piptr = (volatile pram_idma_t *) ((uint) (immap) + memaddr); + +	piptr->pi_resv1 = 0;		/* manual says: clear it */ +	piptr->pi_dcmbits.b.b_fb = 0; +	piptr->pi_dcmbits.b.b_lp = 1; +	piptr->pi_dcmbits.b.b_erm = 0; +	piptr->pi_dcmbits.b.b_dt = 0; + +	memaddr = (uint) dpalloc (sizeof (ibd_t), 64); +	piptr->pi_ibase = piptr->pi_ibdptr = (volatile short) memaddr; +	bdf = (volatile ibd_t *) ((uint) (immap) + memaddr); +	bdf->ibd_bits.b.b_valid = 0; + +	memaddr = (uint) dpalloc (64, 64); +	piptr->pi_dprbuf = (volatile ushort) memaddr; +	piptr->pi_dcmbits.b.b_wrap = 4; +	piptr->pi_ssmax = 32; + +	piptr->pi_sts = piptr->pi_ssmax; +	piptr->pi_dts = piptr->pi_ssmax; + +	return 1; +} + +void dmadone_handler (void *arg) +{ +	immap->im_sdma.sdma_idmr2 = (uchar) 0x0; + +	*dmadonep = 1; + +	return; +} + + +static uint dpbase = 0; + +uint dpalloc (uint size, uint align) +{ +	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; +	uint retloc; +	uint align_mask, off; +	uint savebase; + +	/* Pointer to initial global data area */ + +	if (dpinit_done == 0) { +		dpbase = gd->dp_alloc_base; +		dpinit_done = 1; +	} + +	align_mask = align - 1; +	savebase = dpbase; + +	if ((off = (dpbase & align_mask)) != 0) +		dpbase += (align - off); + +	if ((off = size & align_mask) != 0) +		size += align - off; + +	if ((dpbase + size) >= gd->dp_alloc_top) { +		dpbase = savebase; +		printf ("dpalloc: ran out of dual port ram!"); +		return 0; +	} + +	retloc = dpbase; +	dpbase += size; + +	memset ((void *) &immr->im_dprambase[retloc], 0, size); + +	return (retloc); +} diff --git a/examples/standalone/mips.lds b/examples/standalone/mips.lds new file mode 100644 index 000000000..717b201a7 --- /dev/null +++ b/examples/standalone/mips.lds @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk Engineering, <wd@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + +/* +OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips") +*/ +OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips") +OUTPUT_ARCH(mips) +SECTIONS +{ +	.text       : +	{ +	  *(.text) +	} + +	. = ALIGN(4); +	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + +	. = ALIGN(4); +	.data  : { *(.data) } + +	. = .; +	_gp = ALIGN(16) + 0x7ff0; + +	.got : { +	  __got_start = .; +	  *(.got) +	  __got_end = .; +	} + +	.sdata  : { *(.sdata) } + +	. = ALIGN(4); +	__bss_start = .; +	.sbss (NOLOAD) : { *(.sbss) } +	.bss (NOLOAD)  : { *(.bss) . = ALIGN(4); } + +	_end = .; +} diff --git a/examples/standalone/nios.lds b/examples/standalone/nios.lds new file mode 100644 index 000000000..4c1080b86 --- /dev/null +++ b/examples/standalone/nios.lds @@ -0,0 +1,61 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + + +OUTPUT_FORMAT("elf32-nios") +OUTPUT_ARCH(nios) +ENTRY(_start) + +SECTIONS +{ +	.text : +	{ +	  *(.text) +	} +	__text_end = .; + +	. = ALIGN(4); +	.rodata : +	{ +		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +	} +	__rodata_end = .; + +	. = ALIGN(4); +	.data : +	{ +		*(.data) +	} +	. = ALIGN(4); +	__data_end = .; + +	__bss_start = .; +	. = ALIGN(4); +	.bss (NOLOAD) : +	{ +		*(.bss) +	} +	. = ALIGN(4); +	__bss_end = .; +	_end = .; +} diff --git a/examples/standalone/nios2.lds b/examples/standalone/nios2.lds new file mode 100644 index 000000000..a3e5ea8e3 --- /dev/null +++ b/examples/standalone/nios2.lds @@ -0,0 +1,133 @@ +/* + * (C) Copyright 2004, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + + +OUTPUT_FORMAT("elf32-littlenios2") +OUTPUT_ARCH(nios2) +ENTRY(_start) + +SECTIONS +{ +	.text : +	{ +	  *(.text) +	  *(.text.*) +	  *(.gnu.linkonce.t*) +	  *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +	  *(.gnu.linkonce.r*) +	} +	. = ALIGN (4); +	_etext = .; +	PROVIDE (etext = .); + +	/* INIT DATA sections - "Small" data (see the gcc -G option) +	 * is always gp-relative. Here we make all init data sections +	 * adjacent to simplify the startup code -- and provide +	 * the global pointer for gp-relative access. +	 */ +	_data = .; +	.data : +	{ +	  *(.data) +	  *(.data.*) +	  *(.gnu.linkonce.d*) +	} + +	. = ALIGN(16); +	_gp = .;			/* Global pointer addr */ +	PROVIDE (gp = .); + +	.sdata : +	{ +	  *(.sdata) +	  *(.sdata.*) +	  *(.gnu.linkonce.s.*) +	} +	. = ALIGN(4); + +	_edata = .; +	PROVIDE (edata = .); + +	/* UNINIT DATA - Small uninitialized data is first so it's +	 * adjacent to sdata and can be referenced via gp. The normal +	 * bss follows. We keep it adjacent to simplify init code. +	 */ +	__bss_start = .; +	.sbss (NOLOAD) : +	{ +	  *(.sbss) +	  *(.sbss.*) +	  *(.gnu.linkonce.sb.*) +	  *(.scommon) +	} +	. = ALIGN(4); +	.bss (NOLOAD) : +	{ +	  *(.bss) +	  *(.bss.*) +	  *(.dynbss) +	  *(COMMON) +	  *(.scommon) +	} +	. = ALIGN(4); +	_end = .; +	PROVIDE (end = .); + +	/* CMD TABLE - uboot command sections +	 */ +	. = .; +	__uboot_cmd_start = .; +	.u_boot_cmd : +	{ +	  *(.u_boot_cmd) +	} +	. = ALIGN(4); +	__u_boot_cmd_end = .; + +	/* DEBUG -- symbol table, string table, etc. etc. +	 */ +	.stab 0 : { *(.stab) } +	.stabstr 0 : { *(.stabstr) } +	.stab.excl 0 : { *(.stab.excl) } +	.stab.exclstr 0 : { *(.stab.exclstr) } +	.stab.index 0 : { *(.stab.index) } +	.stab.indexstr 0 : { *(.stab.indexstr) } +	.comment 0 : { *(.comment) } +	.debug          0 : { *(.debug) } +	.line           0 : { *(.line) } +	.debug_srcinfo  0 : { *(.debug_srcinfo) } +	.debug_sfnames  0 : { *(.debug_sfnames) } +	.debug_aranges  0 : { *(.debug_aranges) } +	.debug_pubnames 0 : { *(.debug_pubnames) } +	.debug_info     0 : { *(.debug_info) } +	.debug_abbrev   0 : { *(.debug_abbrev) } +	.debug_line     0 : { *(.debug_line) } +	.debug_frame    0 : { *(.debug_frame) } +	.debug_str      0 : { *(.debug_str) } +	.debug_loc      0 : { *(.debug_loc) } +	.debug_macinfo  0 : { *(.debug_macinfo) } +	.debug_weaknames 0 : { *(.debug_weaknames) } +	.debug_funcnames 0 : { *(.debug_funcnames) } +	.debug_typenames 0 : { *(.debug_typenames) } +	.debug_varnames  0 : { *(.debug_varnames) } +} diff --git a/examples/standalone/ppc_longjmp.S b/examples/standalone/ppc_longjmp.S new file mode 100644 index 000000000..5ca6f6f3d --- /dev/null +++ b/examples/standalone/ppc_longjmp.S @@ -0,0 +1,79 @@ +/* longjmp for PowerPC. +   Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <ppc_asm.tmpl> + +# define JB_GPR1   0  /* Also known as the stack pointer */ +# define JB_GPR2   1 +# define JB_LR     2  /* The address we will return to */ +# define JB_GPRS   3  /* GPRs 14 through 31 are saved, 18 in total */ +# define JB_CR     21 /* Condition code registers. */ +# define JB_FPRS   22 /* FPRs 14 through 31 are saved, 18*2 words total */ +# define JB_SIZE   (58*4) + +#define FP(x...) x +#define FP(x...) x + +.globl      ppc_longjmp; + +ppc_longjmp: +	lwz r1,(JB_GPR1*4)(r3) +	lwz r2,(JB_GPR2*4)(r3) +	lwz r0,(JB_LR*4)(r3) +	lwz r14,((JB_GPRS+0)*4)(r3) +FP(	lfd 14,((JB_FPRS+0*2)*4)(r3)) +	lwz r15,((JB_GPRS+1)*4)(r3) +FP(	lfd 15,((JB_FPRS+1*2)*4)(r3)) +	lwz r16,((JB_GPRS+2)*4)(r3) +FP(	lfd 16,((JB_FPRS+2*2)*4)(r3)) +	lwz r17,((JB_GPRS+3)*4)(r3) +FP(	lfd 17,((JB_FPRS+3*2)*4)(r3)) +	lwz r18,((JB_GPRS+4)*4)(r3) +FP(	lfd 18,((JB_FPRS+4*2)*4)(r3)) +	lwz r19,((JB_GPRS+5)*4)(r3) +FP(	lfd 19,((JB_FPRS+5*2)*4)(r3)) +	lwz r20,((JB_GPRS+6)*4)(r3) +FP(	lfd 20,((JB_FPRS+6*2)*4)(r3)) +	mtlr r0 +	lwz r21,((JB_GPRS+7)*4)(r3) +FP(	lfd 21,((JB_FPRS+7*2)*4)(r3)) +	lwz r22,((JB_GPRS+8)*4)(r3) +FP(	lfd 22,((JB_FPRS+8*2)*4)(r3)) +	lwz r0,(JB_CR*4)(r3) +	lwz r23,((JB_GPRS+9)*4)(r3) +FP(	lfd 23,((JB_FPRS+9*2)*4)(r3)) +	lwz r24,((JB_GPRS+10)*4)(r3) +FP(	lfd 24,((JB_FPRS+10*2)*4)(r3)) +	lwz r25,((JB_GPRS+11)*4)(r3) +FP(	lfd 25,((JB_FPRS+11*2)*4)(r3)) +	mtcrf 0xFF,r0 +	lwz r26,((JB_GPRS+12)*4)(r3) +FP(	lfd 26,((JB_FPRS+12*2)*4)(r3)) +	lwz r27,((JB_GPRS+13)*4)(r3) +FP(	lfd 27,((JB_FPRS+13*2)*4)(r3)) +	lwz r28,((JB_GPRS+14)*4)(r3) +FP(	lfd 28,((JB_FPRS+14*2)*4)(r3)) +	lwz r29,((JB_GPRS+15)*4)(r3) +FP(	lfd 29,((JB_FPRS+15*2)*4)(r3)) +	lwz r30,((JB_GPRS+16)*4)(r3) +FP(	lfd 30,((JB_FPRS+16*2)*4)(r3)) +	lwz r31,((JB_GPRS+17)*4)(r3) +FP(	lfd 31,((JB_FPRS+17*2)*4)(r3)) +	mr r3,r4 +	blr diff --git a/examples/standalone/ppc_setjmp.S b/examples/standalone/ppc_setjmp.S new file mode 100644 index 000000000..421abfd6e --- /dev/null +++ b/examples/standalone/ppc_setjmp.S @@ -0,0 +1,83 @@ +/* setjmp for PowerPC. +   Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <ppc_asm.tmpl> + +# define JB_GPR1   0  /* Also known as the stack pointer */ +# define JB_GPR2   1 +# define JB_LR     2  /* The address we will return to */ +# define JB_GPRS   3  /* GPRs 14 through 31 are saved, 18 in total */ +# define JB_CR     21 /* Condition code registers. */ +# define JB_FPRS   22 /* FPRs 14 through 31 are saved, 18*2 words total */ +# define JB_SIZE   (58*4) + +#define FP(x...) x + +.globl      setctxsp; +setctxsp: +	mr  r1, r3 +	blr + +.globl      ppc_setjmp; +ppc_setjmp: +	stw  r1,(JB_GPR1*4)(3) +	mflr r0 +	stw  r2,(JB_GPR2*4)(3) +	stw  r14,((JB_GPRS+0)*4)(3) +FP(	stfd 14,((JB_FPRS+0*2)*4)(3)) +	stw  r0,(JB_LR*4)(3) +	stw  r15,((JB_GPRS+1)*4)(3) +FP(	stfd 15,((JB_FPRS+1*2)*4)(3)) +	mfcr r0 +	stw  r16,((JB_GPRS+2)*4)(3) +FP(	stfd 16,((JB_FPRS+2*2)*4)(3)) +	stw  r0,(JB_CR*4)(3) +	stw  r17,((JB_GPRS+3)*4)(3) +FP(	stfd 17,((JB_FPRS+3*2)*4)(3)) +	stw  r18,((JB_GPRS+4)*4)(3) +FP(	stfd 18,((JB_FPRS+4*2)*4)(3)) +	stw  r19,((JB_GPRS+5)*4)(3) +FP(	stfd 19,((JB_FPRS+5*2)*4)(3)) +	stw  r20,((JB_GPRS+6)*4)(3) +FP(	stfd 20,((JB_FPRS+6*2)*4)(3)) +	stw  r21,((JB_GPRS+7)*4)(3) +FP(	stfd 21,((JB_FPRS+7*2)*4)(3)) +	stw  r22,((JB_GPRS+8)*4)(3) +FP(	stfd 22,((JB_FPRS+8*2)*4)(3)) +	stw  r23,((JB_GPRS+9)*4)(3) +FP(	stfd 23,((JB_FPRS+9*2)*4)(3)) +	stw  r24,((JB_GPRS+10)*4)(3) +FP(	stfd 24,((JB_FPRS+10*2)*4)(3)) +	stw  r25,((JB_GPRS+11)*4)(3) +FP(	stfd 25,((JB_FPRS+11*2)*4)(3)) +	stw  r26,((JB_GPRS+12)*4)(3) +FP(	stfd 26,((JB_FPRS+12*2)*4)(3)) +	stw  r27,((JB_GPRS+13)*4)(3) +FP(	stfd 27,((JB_FPRS+13*2)*4)(3)) +	stw  r28,((JB_GPRS+14)*4)(3) +FP(	stfd 28,((JB_FPRS+14*2)*4)(3)) +	stw  r29,((JB_GPRS+15)*4)(3) +FP(	stfd 29,((JB_FPRS+15*2)*4)(3)) +	stw  r30,((JB_GPRS+16)*4)(3) +FP(	stfd 30,((JB_FPRS+16*2)*4)(3)) +	stw  r31,((JB_GPRS+17)*4)(3) +FP(	stfd 31,((JB_FPRS+17*2)*4)(3)) + +	li 3, 0 +	blr diff --git a/examples/standalone/sched.c b/examples/standalone/sched.c new file mode 100644 index 000000000..b32766fed --- /dev/null +++ b/examples/standalone/sched.c @@ -0,0 +1,369 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + +#include <common.h> +#include <exports.h> + +/* + * Author: Arun Dharankar <ADharankar@ATTBI.Com> + * + * A very simple thread/schedular model: + *   - only one master thread, and no parent child relation maintained + *   - parent thread cannot be stopped or deleted + *   - no permissions or credentials + *   - no elaborate safety checks + *   - cooperative multi threading + *   - Simple round-robin scheduleing with no priorities + *   - no metering/statistics collection + * + * Basic idea of implementing this is to allow more than one tests to + * execute "simultaneously". + * + * This may be modified such thread_yield may be called in syscalls, and + * timer interrupts. + */ + + +#define MAX_THREADS 8 + +#define CTX_SIZE 512 +#define STK_SIZE 8*1024 + +#define STATE_EMPTY 0 +#define STATE_RUNNABLE 1 +#define STATE_STOPPED 2 +#define STATE_TERMINATED 2 + +#define MASTER_THREAD 0 + +#define RC_FAILURE	(-1) +#define	RC_SUCCESS	(0) + +typedef	vu_char *jmp_ctx; +unsigned long setctxsp (vu_char *sp); +int ppc_setjmp(jmp_ctx env); +void ppc_longjmp(jmp_ctx env, int val); +#define setjmp	ppc_setjmp +#define longjmp	ppc_longjmp + +struct lthread { +	int state; +	int retval; +	char stack[STK_SIZE]; +	uchar context[CTX_SIZE]; +	int (*func) (void *); +	void *arg; +}; +static volatile struct lthread lthreads[MAX_THREADS]; +static volatile int current_tid = MASTER_THREAD; + + +static uchar dbg = 0; + +#define PDEBUG(fmt, args...)	 {					\ +	if(dbg != 0) {							\ +		printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);\ +		printf(fmt, ##args);				\ +		printf("\n");					\ +	}								\ +} + +static int testthread (void *); +static void sched_init (void); +static int thread_create (int (*func) (void *), void *arg); +static int thread_start (int id); +static void thread_yield (void); +static int thread_delete (int id); +static int thread_join (int *ret); + +#if 0							/* not used yet */ +static int thread_stop (int id); +#endif							/* not used yet */ + +/* An example of schedular test */ + +#define NUMTHREADS 7 +int sched (int ac, char *av[]) +{ +	int i, j; +	int tid[NUMTHREADS]; +	int names[NUMTHREADS]; + +	app_startup(av); + +	sched_init (); + +	for (i = 0; i < NUMTHREADS; i++) { +		names[i] = i; +		j = thread_create (testthread, (void *) &names[i]); +		if (j == RC_FAILURE) +			printf ("schedtest: Failed to create thread %d\n", i); +		if (j > 0) { +			printf ("schedtest: Created thread with id %d, name %d\n", +						j, i); +			tid[i] = j; +		} +	} +	printf ("schedtest: Threads created\n"); + +	printf ("sched_test: function=0x%08x\n", (unsigned)testthread); +	for (i = 0; i < NUMTHREADS; i++) { +		printf ("schedtest: Setting thread %d runnable\n", tid[i]); +		thread_start (tid[i]); +		thread_yield (); +	} +	printf ("schedtest: Started %d threads\n", NUMTHREADS); + +	while (1) { +		printf ("schedtest: Waiting for threads to complete\n"); +		if (tstc () && getc () == 0x3) { +			printf ("schedtest: Aborting threads...\n"); +			for (i = 0; i < NUMTHREADS; i++) { +				printf ("schedtest: Deleting thread %d\n", tid[i]); +				thread_delete (tid[i]); +			} +			return RC_SUCCESS; +		} +		j = -1; +		i = thread_join (&j); +		if (i == RC_FAILURE) { +			printf ("schedtest: No threads pending, " +						"exiting schedular test\n"); +			return RC_SUCCESS; +		} +		printf ("schedtest: thread is %d returned %d\n", i, j); +		thread_yield (); +	} + +	return RC_SUCCESS; +} + +static int testthread (void *name) +{ +	int i; + +	printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n", +		*(int *) name, (unsigned)&i); + +	printf ("Thread %02d, i=%d\n", *(int *) name, i); + +	for (i = 0; i < 0xffff * (*(int *) name + 1); i++) { +		if (tstc () && getc () == 0x3) { +			printf ("testthread: myname %d terminating.\n", +						*(int *) name); +			return *(int *) name + 1; +		} + +		if (i % 100 == 0) +			thread_yield (); +	} + +	printf ("testthread: returning %d, i=0x%x\n", +				*(int *) name + 1, i); + +	return *(int *) name + 1; +} + + +static void sched_init (void) +{ +	int i; + +	for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) +		lthreads[i].state = STATE_EMPTY; + +	current_tid = MASTER_THREAD; +	lthreads[current_tid].state = STATE_RUNNABLE; +	PDEBUG ("sched_init: master context = 0x%08x", +		(unsigned)lthreads[current_tid].context); +	return; +} + +static void thread_yield (void) +{ +	static int i; + +	PDEBUG ("thread_yield: current tid=%d", current_tid); + +#define SWITCH(new)							\ +	if(lthreads[new].state == STATE_RUNNABLE) {			\ +		PDEBUG("thread_yield: %d match, ctx=0x%08x",		\ +			new,						\ +			(unsigned)lthreads[current_tid].context);	\ +		if(setjmp(lthreads[current_tid].context) == 0) {	\ +			current_tid = new;				\ +			PDEBUG("thread_yield: tid %d returns 0",	\ +				new);					\ +			longjmp(lthreads[new].context, 1);		\ +		} else {						\ +			PDEBUG("thread_yield: tid %d returns 1",	\ +				new);					\ +			return;						\ +		}							\ +	} + +	for (i = current_tid + 1; i < MAX_THREADS; i++) { +		SWITCH (i); +	} + +	if (current_tid != 0) { +		for (i = 0; i <= current_tid; i++) { +			SWITCH (i); +		} +	} + +	PDEBUG ("thread_yield: returning from thread_yield"); +	return; +} + +static int thread_create (int (*func) (void *), void *arg) +{ +	int i; + +	for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { +		if (lthreads[i].state == STATE_EMPTY) { +			lthreads[i].state = STATE_STOPPED; +			lthreads[i].func = func; +			lthreads[i].arg = arg; +			PDEBUG ("thread_create: returns new tid %d", i); +			return i; +		} +	} + +	PDEBUG ("thread_create: returns failure"); +	return RC_FAILURE; +} + +static int thread_delete (int id) +{ +	if (id <= MASTER_THREAD || id > MAX_THREADS) +		return RC_FAILURE; + +	if (current_tid == id) +		return RC_FAILURE; + +	lthreads[id].state = STATE_EMPTY; +	return RC_SUCCESS; +} + +static void thread_launcher (void) +{ +	PDEBUG ("thread_launcher: invoking func=0x%08x", +		   (unsigned)lthreads[current_tid].func); + +	lthreads[current_tid].retval = +			lthreads[current_tid].func (lthreads[current_tid].arg); + +	PDEBUG ("thread_launcher: tid %d terminated", current_tid); + +	lthreads[current_tid].state = STATE_TERMINATED; +	thread_yield (); +	printf ("thread_launcher: should NEVER get here!\n"); + +	return; +} + +static int thread_start (int id) +{ +	PDEBUG ("thread_start: id=%d", id); +	if (id <= MASTER_THREAD || id > MAX_THREADS) { +		return RC_FAILURE; +	} + +	if (lthreads[id].state != STATE_STOPPED) +		return RC_FAILURE; + +	if (setjmp (lthreads[current_tid].context) == 0) { +		lthreads[id].state = STATE_RUNNABLE; +		current_tid = id; +		PDEBUG ("thread_start: to be stack=0%08x", +			(unsigned)lthreads[id].stack); +		setctxsp ((vu_char *)<hreads[id].stack[STK_SIZE]); +		thread_launcher (); +	} + +	PDEBUG ("thread_start: Thread id=%d started, parent returns", id); + +	return RC_SUCCESS; +} + +#if 0	/* not used so far */ +static int thread_stop (int id) +{ +	if (id <= MASTER_THREAD || id >= MAX_THREADS) +		return RC_FAILURE; + +	if (current_tid == id) +		return RC_FAILURE; + +	lthreads[id].state = STATE_STOPPED; +	return RC_SUCCESS; +} +#endif	/* not used so far */ + +static int thread_join (int *ret) +{ +	int i, j = 0; + +	PDEBUG ("thread_join: *ret = %d", *ret); + +	if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) { +		PDEBUG ("thread_join: invalid tid %d", *ret); +		return RC_FAILURE; +	} + +	if (*ret == -1) { +		PDEBUG ("Checking for tid = -1"); +		while (1) { +			/* PDEBUG("thread_join: start while-loopn"); */ +			j = 0; +			for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { +				if (lthreads[i].state == STATE_TERMINATED) { +					*ret = lthreads[i].retval; +					lthreads[i].state = STATE_EMPTY; +					/* PDEBUG("thread_join: returning retval %d of tid %d", +					   ret, i); */ +					return RC_SUCCESS; +				} + +				if (lthreads[i].state != STATE_EMPTY) { +					PDEBUG ("thread_join: %d used slots tid %d state=%d", +						   j, i, lthreads[i].state); +					j++; +				} +			} +			if (j == 0) { +				PDEBUG ("thread_join: all slots empty!"); +				return RC_FAILURE; +			} +			/*  PDEBUG("thread_join: yielding"); */ +			thread_yield (); +			/*  PDEBUG("thread_join: back from yield"); */ +		} +	} + +	if (lthreads[*ret].state == STATE_TERMINATED) { +		i = *ret; +		*ret = lthreads[*ret].retval; +		lthreads[*ret].state = STATE_EMPTY; +		PDEBUG ("thread_join: returing %d for tid %d", *ret, i); +		return RC_SUCCESS; +	} + +	PDEBUG ("thread_join: thread %d is not terminated!", *ret); +	return RC_FAILURE; +} diff --git a/examples/standalone/smc91111_eeprom.c b/examples/standalone/smc91111_eeprom.c new file mode 100644 index 000000000..39e530648 --- /dev/null +++ b/examples/standalone/smc91111_eeprom.c @@ -0,0 +1,395 @@ +/* + * (C) Copyright 2004 + * Robin Getz rgetz@blacfin.uclinux.org + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + * + * Heavily borrowed from the following peoples GPL'ed software: + *  - Wolfgang Denk, DENX Software Engineering, wd@denx.de + *       Das U-boot + *  - Ladislav Michl ladis@linux-mips.org + *       A rejected patch on the U-Boot mailing list + */ + +#include <common.h> +#include <exports.h> +#include "../drivers/net/smc91111.h" + +#ifdef CONFIG_DRIVER_SMC91111 + +#ifndef SMC91111_EEPROM_INIT +# define SMC91111_EEPROM_INIT() +#endif + +#define SMC_BASE_ADDRESS CONFIG_SMC91111_BASE +#define EEPROM		0x1 +#define MAC		0x2 +#define UNKNOWN		0x4 + +void dump_reg (void); +void dump_eeprom (void); +int write_eeprom_reg (int, int); +void copy_from_eeprom (void); +void print_MAC (void); +int read_eeprom_reg (int); +void print_macaddr (void); + +int smc91111_eeprom (int argc, char *argv[]) +{ +	int c, i, j, done, line, reg, value, start, what; +	char input[50]; + +	/* Print the ABI version */ +	app_startup (argv); +	if (XF_VERSION != (int) get_version ()) { +		printf ("Expects ABI version %d\n", XF_VERSION); +		printf ("Actual U-Boot ABI version %d\n", +			(int) get_version ()); +		printf ("Can't run\n\n"); +		return (0); +	} + +	SMC91111_EEPROM_INIT(); + +	if ((SMC_inw (BANK_SELECT) & 0xFF00) != 0x3300) { +		printf ("Can't find SMSC91111\n"); +		return (0); +	} + +	done = 0; +	what = UNKNOWN; +	printf ("\n"); +	while (!done) { +		/* print the prompt */ +		printf ("SMC91111> "); +		line = 0; +		i = 0; +		start = 1; +		while (!line) { +			/* Wait for a keystroke */ +			while (!tstc ()); + +			c = getc (); +			/* Make Uppercase */ +			if (c >= 'Z') +				c -= ('a' - 'A'); +			/* printf(" |%02x| ",c); */ + +			switch (c) { +			case '\r':	/* Enter                */ +			case '\n': +				input[i] = 0; +				puts ("\r\n"); +				line = 1; +				break; +			case '\0':	/* nul                  */ +				continue; + +			case 0x03:	/* ^C - break           */ +				input[0] = 0; +				i = 0; +				line = 1; +				done = 1; +				break; + +			case 0x5F: +			case 0x08:	/* ^H  - backspace      */ +			case 0x7F:	/* DEL - backspace      */ +				if (i > 0) { +					puts ("\b \b"); +					i--; +				} +				break; +			default: +				if (start) { +					if ((c == 'W') || (c == 'D') +					    || (c == 'M') || (c == 'C') +					    || (c == 'P')) { +						putc (c); +						input[i] = c; +						if (i <= 45) +							i++; +						start = 0; +					} +				} else { +					if ((c >= '0' && c <= '9') +					    || (c >= 'A' && c <= 'F') +					    || (c == 'E') || (c == 'M') +					    || (c == ' ')) { +						putc (c); +						input[i] = c; +						if (i <= 45) +							i++; +						break; +					} +				} +				break; +			} +		} + +		for (; i < 49; i++) +			input[i] = 0; + +		switch (input[0]) { +		case ('W'): +			/* Line should be w reg value */ +			i = 0; +			reg = 0; +			value = 0; +			/* Skip to the next space or end) */ +			while ((input[i] != ' ') && (input[i] != 0)) +				i++; + +			if (input[i] != 0) +				i++; + +			/* Are we writing to EEPROM or MAC */ +			switch (input[i]) { +			case ('E'): +				what = EEPROM; +				break; +			case ('M'): +				what = MAC; +				break; +			default: +				what = UNKNOWN; +				break; +			} + +			/* skip to the next space or end */ +			while ((input[i] != ' ') && (input[i] != 0)) +				i++; +			if (input[i] != 0) +				i++; + +			/* Find register to write into */ +			j = 0; +			while ((input[i] != ' ') && (input[i] != 0)) { +				j = input[i] - 0x30; +				if (j >= 0xA) { +					j -= 0x07; +				} +				reg = (reg * 0x10) + j; +				i++; +			} + +			while ((input[i] != ' ') && (input[i] != 0)) +				i++; + +			if (input[i] != 0) +				i++; +			else +				what = UNKNOWN; + +			/* Get the value to write */ +			j = 0; +			while ((input[i] != ' ') && (input[i] != 0)) { +				j = input[i] - 0x30; +				if (j >= 0xA) { +					j -= 0x07; +				} +				value = (value * 0x10) + j; +				i++; +			} + +			switch (what) { +			case 1: +				printf ("Writing EEPROM register %02x with %04x\n", reg, value); +				write_eeprom_reg (value, reg); +				break; +			case 2: +				printf ("Writing MAC register bank %i, reg %02x with %04x\n", reg >> 4, reg & 0xE, value); +				SMC_SELECT_BANK (reg >> 4); +				SMC_outw (value, reg & 0xE); +				break; +			default: +				printf ("Wrong\n"); +				break; +			} +			break; +		case ('D'): +			dump_eeprom (); +			break; +		case ('M'): +			dump_reg (); +			break; +		case ('C'): +			copy_from_eeprom (); +			break; +		case ('P'): +			print_macaddr (); +			break; +		default: +			break; +		} + +	} + +	return (0); +} + +void copy_from_eeprom (void) +{ +	int i; + +	SMC_SELECT_BANK (1); +	SMC_outw ((SMC_inw (CTL_REG) & !CTL_EEPROM_SELECT) | CTL_RELOAD, +		  CTL_REG); +	i = 100; +	while ((SMC_inw (CTL_REG) & CTL_RELOAD) && --i) +		udelay (100); +	if (i == 0) { +		printf ("Timeout Refreshing EEPROM registers\n"); +	} else { +		printf ("EEPROM contents copied to MAC\n"); +	} + +} + +void print_macaddr (void) +{ +	int i, j, k, mac[6]; + +	printf ("Current MAC Address in SMSC91111 "); +	SMC_SELECT_BANK (1); +	for (i = 0; i < 5; i++) { +		printf ("%02x:", SMC_inb (ADDR0_REG + i)); +	} + +	printf ("%02x\n", SMC_inb (ADDR0_REG + 5)); + +	i = 0; +	for (j = 0x20; j < 0x23; j++) { +		k = read_eeprom_reg (j); +		mac[i] = k & 0xFF; +		i++; +		mac[i] = k >> 8; +		i++; +	} + +	printf ("Current MAC Address in EEPROM    "); +	for (i = 0; i < 5; i++) +		printf ("%02x:", mac[i]); +	printf ("%02x\n", mac[5]); + +} +void dump_eeprom (void) +{ +	int j, k; + +	printf ("IOS2-0    "); +	for (j = 0; j < 8; j++) { +		printf ("%03x     ", j); +	} +	printf ("\n"); + +	for (k = 0; k < 4; k++) { +		if (k == 0) +			printf ("CONFIG "); +		if (k == 1) +			printf ("BASE   "); +		if ((k == 2) || (k == 3)) +			printf ("       "); +		for (j = 0; j < 0x20; j += 4) { +			printf ("%02x:%04x ", j + k, read_eeprom_reg (j + k)); +		} +		printf ("\n"); +	} + +	for (j = 0x20; j < 0x40; j++) { +		if ((j & 0x07) == 0) +			printf ("\n"); +		printf ("%02x:%04x ", j, read_eeprom_reg (j)); +	} +	printf ("\n"); + +} + +int read_eeprom_reg (int reg) +{ +	int timeout; + +	SMC_SELECT_BANK (2); +	SMC_outw (reg, PTR_REG); + +	SMC_SELECT_BANK (1); +	SMC_outw (SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_RELOAD, +		  CTL_REG); +	timeout = 100; +	while ((SMC_inw (CTL_REG) & CTL_RELOAD) && --timeout) +		udelay (100); +	if (timeout == 0) { +		printf ("Timeout Reading EEPROM register %02x\n", reg); +		return 0; +	} + +	return SMC_inw (GP_REG); + +} + +int write_eeprom_reg (int value, int reg) +{ +	int timeout; + +	SMC_SELECT_BANK (2); +	SMC_outw (reg, PTR_REG); + +	SMC_SELECT_BANK (1); +	SMC_outw (value, GP_REG); +	SMC_outw (SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_STORE, CTL_REG); +	timeout = 100; +	while ((SMC_inw (CTL_REG) & CTL_STORE) && --timeout) +		udelay (100); +	if (timeout == 0) { +		printf ("Timeout Writing EEPROM register %02x\n", reg); +		return 0; +	} + +	return 1; + +} + +void dump_reg (void) +{ +	int i, j; + +	printf ("    "); +	for (j = 0; j < 4; j++) { +		printf ("Bank%i ", j); +	} +	printf ("\n"); +	for (i = 0; i < 0xF; i += 2) { +		printf ("%02x  ", i); +		for (j = 0; j < 4; j++) { +			SMC_SELECT_BANK (j); +			printf ("%04x  ", SMC_inw (i)); +		} +		printf ("\n"); +	} +} + +#else + +int smc91111_eeprom (int argc, char *argv[]) +{ +	printf("Not supported for this board\n"); +	return 1; +} + +#endif diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c new file mode 100644 index 000000000..bf22f0a25 --- /dev/null +++ b/examples/standalone/smc911x_eeprom.c @@ -0,0 +1,383 @@ +/* + * smc911x_eeprom.c - EEPROM interface to SMC911x parts. + * Only tested on SMSC9118 though ... + * + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + * + * Based on smc91111_eeprom.c which: + * Heavily borrowed from the following peoples GPL'ed software: + *  - Wolfgang Denk, DENX Software Engineering, wd@denx.de + *       Das U-boot + *  - Ladislav Michl ladis@linux-mips.org + *       A rejected patch on the U-Boot mailing list + */ + +#include <common.h> +#include <exports.h> + +#ifdef CONFIG_DRIVER_SMC911X + +#include "../drivers/net/smc911x.h" + +/** + *	smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?) + */ +static int smsc_ctrlc(void) +{ +	return (tstc() && getc() == 0x03); +} + +/** + *	usage - dump usage information + */ +static void usage(void) +{ +	puts( +		"MAC/EEPROM Commands:\n" +		" P : Print the MAC addresses\n" +		" D : Dump the EEPROM contents\n" +		" M : Dump the MAC contents\n" +		" C : Copy the MAC address from the EEPROM to the MAC\n" +		" W : Write a register in the EEPROM or in the MAC\n" +		" Q : Quit\n" +		"\n" +		"Some commands take arguments:\n" +		" W <E|M> <register> <value>\n" +		"    E: EEPROM   M: MAC\n" +	); +} + +/** + *	dump_regs - dump the MAC registers + * + * Registers 0x00 - 0x50 are FIFOs.  The 0x50+ are the control registers + * and they're all 32bits long.  0xB8+ are reserved, so don't bother. + */ +static void dump_regs(void) +{ +	u8 i, j = 0; +	for (i = 0x50; i < 0xB8; i += sizeof(u32)) +		printf("%02x: 0x%08x %c", i, +			smc911x_reg_read(CONFIG_DRIVER_SMC911X_BASE + i), +			(j++ % 2 ? '\n' : ' ')); +} + +/** + *	do_eeprom_cmd - handle eeprom communication + */ +static int do_eeprom_cmd(int cmd, u8 reg) +{ +	if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) { +		printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n", +			smc911x_reg_read(E2P_CMD)); +		return -1; +	} + +	smc911x_reg_write(E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg); + +	while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) +		if (smsc_ctrlc()) { +			printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n", +				smc911x_reg_read(E2P_CMD)); +			return -1; +		} + +	return 0; +} + +/** + *	read_eeprom_reg - read specified register in EEPROM + */ +static u8 read_eeprom_reg(u8 reg) +{ +	int ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_READ, reg); +	return (ret ? : smc911x_reg_read(E2P_DATA)); +} + +/** + *	write_eeprom_reg - write specified value into specified register in EEPROM + */ +static int write_eeprom_reg(u8 value, u8 reg) +{ +	int ret; + +	/* enable erasing/writing */ +	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWEN, reg); +	if (ret) +		goto done; + +	/* erase the eeprom reg */ +	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_ERASE, reg); +	if (ret) +		goto done; + +	/* write the eeprom reg */ +	smc911x_reg_write(E2P_DATA, value); +	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_WRITE, reg); +	if (ret) +		goto done; + +	/* disable erasing/writing */ +	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWDS, reg); + + done: +	return ret; +} + +/** + *	skip_space - find first non-whitespace in given pointer + */ +static char *skip_space(char *buf) +{ +	while (buf[0] == ' ' || buf[0] == '\t') +		++buf; +	return buf; +} + +/** + *	write_stuff - handle writing of MAC registers / eeprom + */ +static void write_stuff(char *line) +{ +	char dest; +	char *endp; +	u8 reg; +	u32 value; + +	/* Skip over the "W " part of the command */ +	line = skip_space(line + 1); + +	/* Figure out destination */ +	switch (line[0]) { +	case 'E': +	case 'M': +		dest = line[0]; +		break; +	default: +	invalid_usage: +		printf("ERROR: Invalid write usage\n"); +		usage(); +		return; +	} + +	/* Get the register to write */ +	line = skip_space(line + 1); +	reg = simple_strtoul(line, &endp, 16); +	if (line == endp) +		goto invalid_usage; + +	/* Get the value to write */ +	line = skip_space(endp); +	value = simple_strtoul(line, &endp, 16); +	if (line == endp) +		goto invalid_usage; + +	/* Check for trailing cruft */ +	line = skip_space(endp); +	if (line[0]) +		goto invalid_usage; + +	/* Finally, execute the command */ +	if (dest == 'E') { +		printf("Writing EEPROM register %02x with %02x\n", reg, value); +		write_eeprom_reg(value, reg); +	} else { +		printf("Writing MAC register %02x with %08x\n", reg, value); +		smc911x_reg_write(CONFIG_DRIVER_SMC911X_BASE + reg, value); +	} +} + +/** + *	copy_from_eeprom - copy MAC address in eeprom to address registers + */ +static void copy_from_eeprom(void) +{ +	ulong addrl = +		read_eeprom_reg(0x01) | +		read_eeprom_reg(0x02) << 8 | +		read_eeprom_reg(0x03) << 16 | +		read_eeprom_reg(0x04) << 24; +	ulong addrh = +		read_eeprom_reg(0x05) | +		read_eeprom_reg(0x06) << 8; +	smc911x_set_mac_csr(ADDRL, addrl); +	smc911x_set_mac_csr(ADDRH, addrh); +	puts("EEPROM contents copied to MAC\n"); +} + +/** + *	print_macaddr - print MAC address registers and MAC address in eeprom + */ +static void print_macaddr(void) +{ +	puts("Current MAC Address in MAC:     "); +	ulong addrl = smc911x_get_mac_csr(ADDRL); +	ulong addrh = smc911x_get_mac_csr(ADDRH); +	printf("%02x:%02x:%02x:%02x:%02x:%02x\n", +		(u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16), +		(u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8)); + +	puts("Current MAC Address in EEPROM:  "); +	int i; +	for (i = 1; i < 6; ++i) +		printf("%02x:", read_eeprom_reg(i)); +	printf("%02x\n", read_eeprom_reg(i)); +} + +/** + *	dump_eeprom - dump the whole content of the EEPROM + */ +static void dump_eeprom(void) +{ +	int i; +	puts("EEPROM:\n"); +	for (i = 0; i < 7; ++i) +		printf("%02x: 0x%02x\n", i, read_eeprom_reg(i)); +} + +/** + *	smc911x_init - get the MAC/EEPROM up and ready for use + */ +static int smc911x_init(void) +{ +	/* See if there is anything there */ +	if (!smc911x_detect_chip()) +		return 1; + +	smc911x_reset(); + +	/* Make sure we set EEDIO/EECLK to the EEPROM */ +	if (smc911x_reg_read(GPIO_CFG) & GPIO_CFG_EEPR_EN) { +		while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) +			if (smsc_ctrlc()) { +				printf("init: timeout (E2P_CMD = 0x%08x)\n", +					smc911x_reg_read(E2P_CMD)); +				return 1; +			} +		smc911x_reg_write(GPIO_CFG, smc911x_reg_read(GPIO_CFG) & ~GPIO_CFG_EEPR_EN); +	} + +	return 0; +} + +/** + *	getline - consume a line of input and handle some escape sequences + */ +static char *getline(void) +{ +	static char buffer[100]; +	char c; +	size_t i; + +	i = 0; +	while (1) { +		buffer[i] = '\0'; +		while (!tstc()) +			continue; + +		c = getc(); +		/* Convert to uppercase */ +		if (c >= 'a' && c <= 'z') +			c -= ('a' - 'A'); + +		switch (c) { +		case '\r':	/* Enter/Return key */ +		case '\n': +			puts("\n"); +			return buffer; + +		case 0x03:	/* ^C - break */ +			return NULL; + +		case 0x5F: +		case 0x08:	/* ^H  - backspace */ +		case 0x7F:	/* DEL - backspace */ +			if (i) { +				puts("\b \b"); +				i--; +			} +			break; + +		default: +			/* Ignore control characters */ +			if (c < 0x20) +				break; +			/* Queue up all other characters */ +			buffer[i++] = c; +			printf("%c", c); +			break; +		} +	} +} + +/** + *	smc911x_eeprom - our application's main() function + */ +int smc911x_eeprom(int argc, char *argv[]) +{ +	/* Print the ABI version */ +	app_startup(argv); +	if (XF_VERSION != get_version()) { +		printf("Expects ABI version %d\n", XF_VERSION); +		printf("Actual U-Boot ABI version %lu\n", get_version()); +		printf("Can't run\n\n"); +		return 1; +	} + +	/* Initialize the MAC/EEPROM somewhat */ +	puts("\n"); +	if (smc911x_init()) +		return 1; + +	/* Dump helpful usage information */ +	puts("\n"); +	usage(); +	puts("\n"); + +	while (1) { +		char *line; + +		/* Send the prompt and wait for a line */ +		puts("eeprom> "); +		line = getline(); + +		/* Got a ctrl+c */ +		if (!line) +			return 0; + +		/* Eat leading space */ +		line = skip_space(line); + +		/* Empty line, try again */ +		if (!line[0]) +			continue; + +		/* Only accept 1 letter commands */ +		if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t') +			goto unknown_cmd; + +		/* Now parse the command */ +		switch (line[0]) { +		case 'W': write_stuff(line);  break; +		case 'D': dump_eeprom();      break; +		case 'M': dump_regs();        break; +		case 'C': copy_from_eeprom(); break; +		case 'P': print_macaddr();    break; +		unknown_cmd: +		default:  puts("ERROR: Unknown command!\n\n"); +		case '?': +		case 'H': usage();            break; +		case 'Q': return 0; +		} +	} +} + +#else +int smc911x_eeprom(int argc, char *argv[]) +{ +	puts("Not supported for this board\n"); +	return 1; +} +#endif diff --git a/examples/standalone/sparc.lds b/examples/standalone/sparc.lds new file mode 100644 index 000000000..9733daa86 --- /dev/null +++ b/examples/standalone/sparc.lds @@ -0,0 +1,61 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + + +OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc") +OUTPUT_ARCH(sparc) +ENTRY(_start) + +SECTIONS +{ +	.text : +	{ +	  *(.text) +	} +	__text_end = .; + +	. = ALIGN(4); +	.rodata : +	{ +		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +	} +	__rodata_end = .; + +	. = ALIGN(4); +	.data : +	{ +		*(.data) +	} +	. = ALIGN(4); +	__data_end = .; + +	__bss_start = .; +	. = ALIGN(4); +	.bss : +	{ +		*(.bss) +	} +	. = ALIGN(4); +	__bss_end = .; +	_end = .; +} diff --git a/examples/standalone/stubs.c b/examples/standalone/stubs.c new file mode 100644 index 000000000..a8cb95428 --- /dev/null +++ b/examples/standalone/stubs.c @@ -0,0 +1,225 @@ +#include <exports.h> + +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +#if defined(CONFIG_I386) +/* + * x86 does not have a dedicated register to store the pointer to + * the global_data. Thus the jump table address is stored in a + * global variable, but such approach does not allow for execution + * from flash memory. The global_data address is passed as argv[-1] + * to the application program. + */ +static void **jt; +gd_t *global_data; + +#define EXPORT_FUNC(x) \ +	asm volatile (			\ +"	.globl " #x "\n"		\ +#x ":\n"				\ +"	movl	%0, %%eax\n"		\ +"	movl	jt, %%ecx\n"		\ +"	jmp	*(%%ecx, %%eax)\n"	\ +	: : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx"); +#elif defined(CONFIG_PPC) +/* + * r2 holds the pointer to the global_data, r11 is a call-clobbered + * register + */ +#define EXPORT_FUNC(x) \ +	asm volatile (			\ +"	.globl " #x "\n"		\ +#x ":\n"				\ +"	lwz	%%r11, %0(%%r2)\n"	\ +"	lwz	%%r11, %1(%%r11)\n"	\ +"	mtctr	%%r11\n"		\ +"	bctr\n"				\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r11"); +#elif defined(CONFIG_ARM) +/* + * r8 holds the pointer to the global_data, ip is a call-clobbered + * register + */ +#define EXPORT_FUNC(x) \ +	asm volatile (			\ +"	.globl " #x "\n"		\ +#x ":\n"				\ +"	ldr	ip, [r8, %0]\n"		\ +"	ldr	pc, [ip, %1]\n"		\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "ip"); +#elif defined(CONFIG_MIPS) +/* + * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call- + * clobbered register that is also used to set gp ($26). Note that the + * jr instruction also executes the instruction immediately following + * it; however, GCC/mips generates an additional `nop' after each asm + * statement + */ +#define EXPORT_FUNC(x) \ +	asm volatile (			\ +"	.globl " #x "\n"		\ +#x ":\n"				\ +"	lw	$25, %0($26)\n"		\ +"	lw	$25, %1($25)\n"		\ +"	jr	$25\n"			\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "t9"); +#elif defined(CONFIG_NIOS) +/* + * %g7 holds the pointer to the global_data. %g0 is call clobbered. + */ +#define EXPORT_FUNC(x) \ +	asm volatile (			\ +"	.globl " #x "\n"		\ +#x ":\n"				\ +"	pfx	%%hi(%0)\n"		\ +"	movi	%%g0, %%lo(%0)\n"	\ +"	add	%%g0, %%g7\n"		\ +"	ld	%%g0, [%%g0]\n"		\ +"	pfx	%1\n"			\ +"	ld	%%g0, [%%g0]\n"		\ +"	jmp	%%g0\n"			\ +"	nop	\n"			\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x) : "r0"); +#elif defined(CONFIG_NIOS2) +/* + * r15 holds the pointer to the global_data, r8 is call-clobbered + */ +#define EXPORT_FUNC(x) \ +	asm volatile (			\ +"	.globl " #x "\n"		\ +#x ":\n"				\ +"	movhi	r8, %%hi(%0)\n"		\ +"	ori	r8, r0, %%lo(%0)\n"	\ +"	add	r8, r8, r15\n"		\ +"	ldw	r8, 0(r8)\n"		\ +"	ldw	r8, %1(r8)\n"		\ +"	jmp	r8\n"			\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r15"); +#elif defined(CONFIG_M68K) +/* + * d7 holds the pointer to the global_data, a0 is a call-clobbered + * register + */ +#define EXPORT_FUNC(x) \ +	asm volatile (			\ +"	.globl " #x "\n"		\ +#x ":\n"				\ +"	move.l	%%d7, %%a0\n"		\ +"	adda.l	%0, %%a0\n"		\ +"	move.l	(%%a0), %%a0\n"		\ +"	adda.l	%1, %%a0\n"		\ +"	move.l	(%%a0), %%a0\n"		\ +"	jmp	(%%a0)\n"			\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "a0"); +#elif defined(CONFIG_MICROBLAZE) +/* + * r31 holds the pointer to the global_data. r5 is a call-clobbered. + */ +#define EXPORT_FUNC(x)				\ +	asm volatile (				\ +"	.globl " #x "\n"			\ +#x ":\n"					\ +"	lwi	r5, r31, %0\n"			\ +"	lwi	r5, r5, %1\n"			\ +"	bra	r5\n"				\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r5"); +#elif defined(CONFIG_BLACKFIN) +/* + * P5 holds the pointer to the global_data, P0 is a call-clobbered + * register + */ +#define EXPORT_FUNC(x)			\ +	asm volatile (			\ +"	.globl _" #x "\n_"		\ +#x ":\n"				\ +"	P0 = [P5 + %0]\n"		\ +"	P0 = [P0 + %1]\n"		\ +"	JUMP (P0)\n"			\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "P0"); +#elif defined(CONFIG_AVR32) +/* + * r6 holds the pointer to the global_data. r8 is call clobbered. + */ +#define EXPORT_FUNC(x)					\ +	asm volatile(					\ +		"	.globl\t" #x "\n"		\ +		#x ":\n"				\ +		"	ld.w	r8, r6[%0]\n"		\ +		"	ld.w	pc, r8[%1]\n"		\ +		:					\ +		: "i"(offsetof(gd_t, jt)), "i"(XF_ ##x)	\ +		: "r8"); +#elif defined(CONFIG_SH) +/* + * r13 holds the pointer to the global_data. r1 is a call clobbered. + */ +#define EXPORT_FUNC(x)					\ +	asm volatile (					\ +		"	.align	2\n"			\ +		"	.globl " #x "\n"		\ +		#x ":\n"				\ +		"	mov	r13, r1\n"		\ +		"	add	%0, r1\n"		\ +		"	mov.l @r1, r2\n"	\ +		"	add	%1, r2\n"		\ +		"	mov.l @r2, r1\n"	\ +		"	jmp	@r1\n"			\ +		"	nop\n"				\ +		"	nop\n"				\ +		: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r1", "r2"); +#elif defined(CONFIG_SPARC) +/* + * g7 holds the pointer to the global_data. g1 is call clobbered. + */ +#define EXPORT_FUNC(x)					\ +	asm volatile(					\ +"	.globl\t" #x "\n"				\ +#x ":\n"						\ +"	set %0, %%g1\n"					\ +"	or %%g1, %%g7, %%g1\n"				\ +"	ld [%%g1], %%g1\n"				\ +"	ld [%%g1 + %1], %%g1\n"				\ +"	call %%g1\n"					\ +"	nop\n"						\ +	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x) : "g1" ); + +#else +#error stubs definition missing for this architecture +#endif + +/* This function is necessary to prevent the compiler from + * generating prologue/epilogue, preparing stack frame etc. + * The stub functions are special, they do not use the stack + * frame passed to them, but pass it intact to the actual + * implementation. On the other hand, asm() statements with + * arguments can be used only inside the functions (gcc limitation) + */ +#if GCC_VERSION < 3004 +static +#endif /* GCC_VERSION */ +void __attribute__((unused)) dummy(void) +{ +#include <_exports.h> +} + +extern unsigned long __bss_start, _end; + +void app_startup(char **argv) +{ +	unsigned char * cp = (unsigned char *) &__bss_start; + +	/* Zero out BSS */ +	while (cp < (unsigned char *)&_end) { +		*cp++ = 0; +	} + +#if defined(CONFIG_I386) +	/* x86 does not have a dedicated register for passing global_data */ +	global_data = (gd_t *)argv[-1]; +	jt = global_data->jt; +#endif +} + +#undef EXPORT_FUNC diff --git a/examples/standalone/test_burst.c b/examples/standalone/test_burst.c new file mode 100644 index 000000000..7109c098e --- /dev/null +++ b/examples/standalone/test_burst.c @@ -0,0 +1,319 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + * + * The test exercises SDRAM accesses in burst mode + */ + +#include <common.h> +#include <exports.h> + +#include <commproc.h> +#include <asm/mmu.h> +#include <asm/processor.h> + +#include <serial.h> +#include <watchdog.h> + +#include "test_burst.h" + +/* 8 MB test region of physical RAM */ +#define TEST_PADDR	0x00800000 +/* The uncached virtual region */ +#define TEST_VADDR_NC	0x00800000 +/* The cached virtual region */ +#define TEST_VADDR_C	0x01000000 +/* When an error is detected, the address where the error has been found, +   and also the current and the expected data will be written to +   the following flash address +*/ +#define TEST_FLASH_ADDR	0x40100000 + +/* Define GPIO ports to signal start of burst transfers and errors */ +#ifdef CONFIG_LWMON +/* Use PD.8 to signal start of burst transfers */ +#define GPIO1_DAT	(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat) +#define GPIO1_BIT	0x0080 +/* Configure PD.8 as general purpose output */ +#define GPIO1_INIT \ +	((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar &= ~GPIO1_BIT; \ +	((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir |=  GPIO1_BIT; +/* Use PD.9 to signal error */ +#define GPIO2_DAT	(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat) +#define GPIO2_BIT	0x0040 +/* Configure PD.9 as general purpose output */ +#define GPIO2_INIT \ +	((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar &= ~GPIO2_BIT; \ +	((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir |=  GPIO2_BIT; +#endif /* CONFIG_LWMON */ + + +static void test_prepare (void); +static int test_burst_start (unsigned long size, unsigned long pattern); +static void test_map_8M (unsigned long paddr, unsigned long vaddr, int cached); +static int test_mmu_is_on(void); +static void test_desc(unsigned long size); +static void test_error(char * step, volatile void * addr, unsigned long val, unsigned long pattern); +static void signal_init(void); +static void signal_start(void); +static void signal_error(void); +static void test_usage(void); + +static unsigned long test_pattern [] = { +	0x00000000, +	0xffffffff, +	0x55555555, +	0xaaaaaaaa, +}; + + +int test_burst (int argc, char *argv[]) +{ +	unsigned long size = CACHE_LINE_SIZE; +	unsigned int pass = 0; +	int res = 0; +	int i, j; + +	if (argc == 3) { +		char * d; +		for (size = 0, d = argv[1]; *d >= '0' && *d <= '9'; d++) { +			size *= 10; +			size += *d - '0'; +		} +		if (size == 0 || *d) { +			test_usage(); +			return 1; +		} +		for (d = argv[2]; *d >= '0' && *d <= '9'; d++) { +			pass *= 10; +			pass += *d - '0'; +		} +		if (*d) { +			test_usage(); +			return 1; +		} +	} else if (argc > 3) { +		test_usage(); +		return 1; +	} + +	size +=  (CACHE_LINE_SIZE - 1); +	size &= ~(CACHE_LINE_SIZE - 1); + +	if (!test_mmu_is_on()) { +		test_prepare(); +	} + +	test_desc(size); + +	for (j = 0; !pass || j < pass; j++) { +		for (i = 0; i < sizeof(test_pattern) / sizeof(test_pattern[0]); +		     i++) { +			res = test_burst_start(size, test_pattern[i]); +			if (res != 0) { +				goto Done; +			} +		} + +		printf ("Iteration #%d passed\n", j + 1); + +		if (tstc() && 0x03 == getc()) +			break; +	} +Done: +	return res; +} + +static void test_prepare (void) +{ +	printf ("\n"); + +	caches_init(); +	disable_interrupts(); +	mmu_init(); + +	printf ("Interrupts are disabled\n"); +	printf ("I-Cache is ON\n"); +	printf ("D-Cache is ON\n"); +	printf ("MMU is ON\n"); + +	printf ("\n"); + +	test_map_8M (TEST_PADDR, TEST_VADDR_NC, 0); +	test_map_8M (TEST_PADDR, TEST_VADDR_C,  1); + +	test_map_8M (TEST_FLASH_ADDR & 0xFF800000, TEST_FLASH_ADDR & 0xFF800000, 0); + +	/* Configure GPIO ports */ +	signal_init(); +} + +static int test_burst_start (unsigned long size, unsigned long pattern) +{ +	volatile unsigned long * vaddr_c = (unsigned long *)TEST_VADDR_C; +	volatile unsigned long * vaddr_nc = (unsigned long *)TEST_VADDR_NC; +	int i, n; +	int res = 1; + +	printf ("Test pattern %08lx ...", pattern); + +	n = size / 4; + +	for (i = 0; i < n; i ++) { +		vaddr_c [i] = pattern; +	} +	signal_start(); +	flush_dcache_range((unsigned long)vaddr_c, (unsigned long)(vaddr_c + n) - 1); + +	for (i = 0; i < n; i ++) { +		register unsigned long tmp = vaddr_nc [i]; +		if (tmp != pattern) { +			test_error("2a", vaddr_nc + i, tmp, pattern); +			goto Done; +		} +	} + +	for (i = 0; i < n; i ++) { +		register unsigned long tmp = vaddr_c [i]; +		if (tmp != pattern) { +			test_error("2b", vaddr_c + i, tmp, pattern); +			goto Done; +		} +	} + +	for (i = 0; i < n; i ++) { +		vaddr_nc [i] = pattern; +	} + +	for (i = 0; i < n; i ++) { +		register unsigned long tmp = vaddr_nc [i]; +		if (tmp != pattern) { +			test_error("3a", vaddr_nc + i, tmp, pattern); +			goto Done; +		} +	} + +	signal_start(); +	for (i = 0; i < n; i ++) { +		register unsigned long tmp = vaddr_c [i]; +		if (tmp != pattern) { +			test_error("3b", vaddr_c + i, tmp, pattern); +			goto Done; +		} +	} + +	res = 0; +Done: +	printf(" %s\n", res == 0 ? "OK" : ""); + +	return res; +} + +static void test_map_8M (unsigned long paddr, unsigned long vaddr, int cached) +{ +	mtspr (MD_EPN, (vaddr & 0xFFFFFC00) | MI_EVALID); +	mtspr (MD_TWC, MI_PS8MEG | MI_SVALID); +	mtspr (MD_RPN, (paddr & 0xFFFFF000) | MI_BOOTINIT | (cached ? 0 : 2)); +	mtspr (MD_AP, MI_Kp); +} + +static int test_mmu_is_on(void) +{ +	unsigned long msr; + +	asm volatile("mfmsr %0" : "=r" (msr) :); + +	return msr & MSR_DR; +} + +static void test_desc(unsigned long size) +{ +	printf( +	"The following tests will be conducted:\n" +	"1)  Map %ld-byte region of physical RAM at 0x%08x\n" +	"    into two virtual regions:\n" +	"    one cached at 0x%08x and\n" +	"    the the other uncached at 0x%08x.\n", +	size, TEST_PADDR, TEST_VADDR_NC, TEST_VADDR_C); + +	puts( +	"2)  Fill the cached region with a pattern, and flush the cache\n" +	"2a) Check the uncached region to match the pattern\n" +	"2b) Check the cached region to match the pattern\n" +	"3)  Fill the uncached region with a pattern\n" +	"3a) Check the cached region to match the pattern\n" +	"3b) Check the uncached region to match the pattern\n" +	"2b) Change the patterns and go to step 2\n" +	"\n" +	); +} + +static void test_error( +	char * step, volatile void * addr, unsigned long val, unsigned long pattern) +{ +	volatile unsigned long * p = (void *)TEST_FLASH_ADDR; + +	signal_error(); + +	p[0] = (unsigned long)addr; +	p[1] = val; +	p[2] = pattern; + +	printf ("\nError at step %s, addr %08lx: read %08lx, pattern %08lx", +		step, (unsigned long)addr, val, pattern); +} + +static void signal_init(void) +{ +#if defined(GPIO1_INIT) +	GPIO1_INIT; +#endif +#if defined(GPIO2_INIT) +	GPIO2_INIT; +#endif +} + +static void signal_start(void) +{ +#if defined(GPIO1_INIT) +	if (GPIO1_DAT & GPIO1_BIT) { +		GPIO1_DAT &= ~GPIO1_BIT; +	} else { +		GPIO1_DAT |= GPIO1_BIT; +	} +#endif +} + +static void signal_error(void) +{ +#if defined(GPIO2_INIT) +	if (GPIO2_DAT & GPIO2_BIT) { +		GPIO2_DAT &= ~GPIO2_BIT; +	} else { +		GPIO2_DAT |= GPIO2_BIT; +	} +#endif +} + +static void test_usage(void) +{ +	printf("Usage: go 0x40004 [size] [count]\n"); +} diff --git a/examples/standalone/test_burst.h b/examples/standalone/test_burst.h new file mode 100644 index 000000000..f85928c21 --- /dev/null +++ b/examples/standalone/test_burst.h @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + +#ifndef _TEST_BURST_H +#define _TEST_BURST_H + +/* Cache line size */ +#define CACHE_LINE_SIZE		16 +/* Binary logarithm of the cache line size */ +#define LG_CACHE_LINE_SIZE	4 + +#ifndef __ASSEMBLY__ +extern void mmu_init(void); +extern void caches_init(void); +extern void flush_dcache_range(unsigned long start, unsigned long stop); +#endif + +#endif /* _TEST_BURST_H */ diff --git a/examples/standalone/test_burst_lib.S b/examples/standalone/test_burst_lib.S new file mode 100644 index 000000000..aef4e3242 --- /dev/null +++ b/examples/standalone/test_burst_lib.S @@ -0,0 +1,170 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + +#include <config.h> + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> +#include <asm/cache.h> +#include <asm/mmu.h> +#include "test_burst.h" + +	.text +/* + *	void mmu_init(void); + * + *	This function turns the MMU on + * + *	Three 8 MByte regions are mapped 1:1, uncached + *	- SDRAM lower 8 MByte + *	- SDRAM higher 8 MByte + *	- IMMR + */ +	.global mmu_init +mmu_init: +	tlbia			/* Invalidate all TLB entries */ +	li	r8, 0 +	mtspr	MI_CTR, r8	/* Set instruction control to zero */ +	lis	r8, MD_RESETVAL@h +	mtspr	MD_CTR, r8	/* Set data TLB control */ + +	/* Now map the lower 8 Meg into the TLBs.  For this quick hack, +	 * we can load the instruction and data TLB registers with the +	 * same values. +	 */ +	li	r8, MI_EVALID		/* Create EPN for address 0 */ +	mtspr	MI_EPN, r8 +	mtspr	MD_EPN, r8 +	li	r8, MI_PS8MEG		/* Set 8M byte page */ +	ori	r8, r8, MI_SVALID	/* Make it valid */ +	mtspr	MI_TWC, r8 +	mtspr	MD_TWC, r8 +	li	r8, MI_BOOTINIT|0x2	/* Create RPN for address 0 */ +	mtspr	MI_RPN, r8		/* Store TLB entry */ +	mtspr	MD_RPN, r8 +	lis	r8, MI_Kp@h		/* Set the protection mode */ +	mtspr	MI_AP, r8 +	mtspr	MD_AP, r8 + +	/* Now map the higher 8 Meg into the TLBs.  For this quick hack, +	 * we can load the instruction and data TLB registers with the +	 * same values. +	 */ +	lwz	r9,20(r2)		/* gd->ram_size */ +	addis	r9,r9,-0x80 + +	mr	r8, r9			/* Higher 8 Meg in SDRAM */ +	ori	r8, r8, MI_EVALID	/* Mark page valid */ +	mtspr	MI_EPN, r8 +	mtspr	MD_EPN, r8 +	li	r8, MI_PS8MEG		/* Set 8M byte page */ +	ori	r8, r8, MI_SVALID	/* Make it valid */ +	mtspr	MI_TWC, r8 +	mtspr	MD_TWC, r8 +	mr	r8, r9 +	ori	r8, r8, MI_BOOTINIT|0x2 +	mtspr	MI_RPN, r8		/* Store TLB entry */ +	mtspr	MD_RPN, r8 +	lis	r8, MI_Kp@h		/* Set the protection mode */ +	mtspr	MI_AP, r8 +	mtspr	MD_AP, r8 + +	/* Map another 8 MByte at the IMMR to get the processor +	 * internal registers (among other things). +	 */ +	mfspr	r9, 638			/* Get current IMMR */ +	andis.	r9, r9, 0xff80		/* Get 8Mbyte boundary */ + +	mr	r8, r9			/* Create vaddr for TLB */ +	ori	r8, r8, MD_EVALID	/* Mark it valid */ +	mtspr	MD_EPN, r8 +	li	r8, MD_PS8MEG		/* Set 8M byte page */ +	ori	r8, r8, MD_SVALID	/* Make it valid */ +	mtspr	MD_TWC, r8 +	mr	r8, r9			/* Create paddr for TLB */ +	ori	r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ +	mtspr	MD_RPN, r8 + +	/* We now have the lower and higher 8 Meg mapped into TLB entries, +	 * and the caches ready to work. +	 */ +	mfmsr	r0 +	ori	r0,r0,MSR_DR|MSR_IR +	mtspr	SRR1,r0 +	mflr	r0 +	mtspr	SRR0,r0 +	SYNC +	rfi	/* enables MMU */ + +/* + *	void caches_init(void); + */ +	.globl	caches_init +caches_init: +	sync + +	mfspr	r3, IC_CST		/* Clear error bits */ +	mfspr	r3, DC_CST + +	lis	r3, IDC_UNALL@h		/* Unlock all */ +	mtspr	IC_CST, r3 +	mtspr	DC_CST, r3 + +	lis	r3, IDC_INVALL@h	/* Invalidate all */ +	mtspr	IC_CST, r3 +	mtspr	DC_CST, r3 + +	lis	r3, IDC_ENABLE@h	/* Enable all */ +	mtspr	IC_CST, r3 +	mtspr	DC_CST, r3 + +	blr + +/* + *	void flush_dcache_range(unsigned long start, unsigned long stop); + */ +	.global flush_dcache_range +flush_dcache_range: +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5 +	subf	r4,r3,r4 +	add	r4,r4,r5 +	srwi.	r4,r4,LG_CACHE_LINE_SIZE +	beqlr +	mtctr	r4 + +1:	dcbf	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbf's to get to ram */ +	blr + +/* + *	void disable_interrupts(void); + */ +	.global disable_interrupts +disable_interrupts: +	mfmsr	r0 +	rlwinm	r0,r0,0,17,15 +	mtmsr	r0 +	blr diff --git a/examples/standalone/timer.c b/examples/standalone/timer.c new file mode 100644 index 000000000..6628b21de --- /dev/null +++ b/examples/standalone/timer.c @@ -0,0 +1,349 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 + */ + +#include <common.h> +#include <commproc.h> +#include <mpc8xx_irq.h> +#include <exports.h> + +DECLARE_GLOBAL_DATA_PTR; + +#undef	DEBUG + +#define	TIMER_PERIOD	1000000		/* 1 second clock */ + +static void timer_handler (void *arg); + + +/* Access functions for the Machine State Register */ +static __inline__ unsigned long get_msr(void) +{ +    unsigned long msr; + +    asm volatile("mfmsr %0" : "=r" (msr) :); +    return msr; +} + +static __inline__ void set_msr(unsigned long msr) +{ +    asm volatile("mtmsr %0" : : "r" (msr)); +} + +/* + * Definitions to access the CPM Timer registers + * See 8xx_immap.h for Internal Memory Map layout, + * and commproc.h for CPM Interrupt vectors (aka "IRQ"s) + */ + +typedef struct tid_8xx_cpmtimer_s { +  int		 cpm_vec;	/* CPM Interrupt Vector for this timer	*/ +  ushort	*tgcrp;		/* Pointer to Timer Global Config Reg.	*/ +  ushort	*tmrp;		/* Pointer to Timer Mode Register	*/ +  ushort	*trrp;		/* Pointer to Timer Reference Register	*/ +  ushort	*tcrp;		/* Pointer to Timer Capture Register	*/ +  ushort	*tcnp;		/* Pointer to Timer Counter Register	*/ +  ushort	*terp;		/* Pointer to Timer Event Register	*/ +} tid_8xx_cpmtimer_t; + +#ifndef CLOCKRATE +#  define CLOCKRATE 64 +#endif + +#define	CPMT_CLOCK_DIV		16 +#define	CPMT_MAX_PRESCALER	256 +#define CPMT_MAX_REFERENCE	65535	/* max. unsigned short */ + +#define	CPMT_MAX_TICKS		(CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER) +#define	CPMT_MAX_TICKS_WITH_DIV	(CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER * CPMT_CLOCK_DIV) +#define	CPMT_MAX_INTERVAL	(CPMT_MAX_TICKS_WITH_DIV / CLOCKRATE) + +/* For now: always use max. prescaler value */ +#define	CPMT_PRESCALER		(CPMT_MAX_PRESCALER) + +/* CPM Timer Event Register Bits */ +#define	CPMT_EVENT_CAP		0x0001	/* Capture Event		*/ +#define	CPMT_EVENT_REF		0x0002	/* Reference Counter Event	*/ + +/* CPM Timer Global Config Register */ +#define	CPMT_GCR_RST		0x0001	/* Reset  Timer			*/ +#define	CPMT_GCR_STP		0x0002	/* Stop   Timer			*/ +#define	CPMT_GCR_FRZ		0x0004	/* Freeze Timer			*/ +#define	CPMT_GCR_GM_CAS		0x0008	/* Gate Mode / Cascade Timers	*/ +#define	CPMT_GCR_MASK		(CPMT_GCR_RST|CPMT_GCR_STP|CPMT_GCR_FRZ|CPMT_GCR_GM_CAS) + +/* CPM Timer Mode register */ +#define	CPMT_MR_GE		0x0001	/* Gate Enable			*/ +#define	CPMT_MR_ICLK_CASC	0x0000	/* Clock internally cascaded	*/ +#define	CPMT_MR_ICLK_CLK	0x0002	/* Clock = system clock		*/ +#define	CPMT_MR_ICLK_CLKDIV	0x0004	/* Clock = system clock / 16	*/ +#define	CPMT_MR_ICLK_TIN	0x0006	/* Clock = TINx signal		*/ +#define	CPMT_MR_FRR		0x0008	/* Free Run / Restart		*/ +#define	CPMT_MR_ORI		0x0010	/* Out. Reference Interrupt En.	*/ +#define	CPMT_MR_OM		0x0020	/* Output Mode			*/ +#define	CPMT_MR_CE_DIS		0x0000	/* Capture/Interrupt disabled	*/ +#define	CPMT_MR_CE_RISE		0x0040	/* Capt./Interr. on rising  TIN	*/ +#define CPMT_MR_CE_FALL		0x0080	/* Capt./Interr. on falling TIN	*/ +#define	CPMT_MR_CE_ANY		0x00C0	/* Capt./Interr. on any TIN edge*/ + + +/* + * which CPM timer to use - index starts at 0 (= timer 1) + */ +#define	TID_TIMER_ID	0	/* use CPM timer 1		*/ + +void setPeriod (tid_8xx_cpmtimer_t *hwp, ulong interval); + +static char *usage = "\n[q, b, e, ?] "; + +int timer (int argc, char *argv[]) +{ +	cpmtimer8xx_t *cpmtimerp;	/* Pointer to the CPM Timer structure   */ +	tid_8xx_cpmtimer_t hw; +	tid_8xx_cpmtimer_t *hwp = &hw; +	int c; +	int running; + +	app_startup(argv); + +	/* Pointer to CPM Timer structure */ +	cpmtimerp = &((immap_t *) gd->bd->bi_immr_base)->im_cpmtimer; + +	printf ("TIMERS=0x%x\n", (unsigned) cpmtimerp); + +	/* Initialize pointers depending on which timer we use */ +	switch (TID_TIMER_ID) { +	case 0: +		hwp->tmrp = &(cpmtimerp->cpmt_tmr1); +		hwp->trrp = &(cpmtimerp->cpmt_trr1); +		hwp->tcrp = &(cpmtimerp->cpmt_tcr1); +		hwp->tcnp = &(cpmtimerp->cpmt_tcn1); +		hwp->terp = &(cpmtimerp->cpmt_ter1); +		hwp->cpm_vec = CPMVEC_TIMER1; +		break; +	case 1: +		hwp->tmrp = &(cpmtimerp->cpmt_tmr2); +		hwp->trrp = &(cpmtimerp->cpmt_trr2); +		hwp->tcrp = &(cpmtimerp->cpmt_tcr2); +		hwp->tcnp = &(cpmtimerp->cpmt_tcn2); +		hwp->terp = &(cpmtimerp->cpmt_ter2); +		hwp->cpm_vec = CPMVEC_TIMER2; +		break; +	case 2: +		hwp->tmrp = &(cpmtimerp->cpmt_tmr3); +		hwp->trrp = &(cpmtimerp->cpmt_trr3); +		hwp->tcrp = &(cpmtimerp->cpmt_tcr3); +		hwp->tcnp = &(cpmtimerp->cpmt_tcn3); +		hwp->terp = &(cpmtimerp->cpmt_ter3); +		hwp->cpm_vec = CPMVEC_TIMER3; +		break; +	case 3: +		hwp->tmrp = &(cpmtimerp->cpmt_tmr4); +		hwp->trrp = &(cpmtimerp->cpmt_trr4); +		hwp->tcrp = &(cpmtimerp->cpmt_tcr4); +		hwp->tcnp = &(cpmtimerp->cpmt_tcn4); +		hwp->terp = &(cpmtimerp->cpmt_ter4); +		hwp->cpm_vec = CPMVEC_TIMER4; +		break; +	} + +	hwp->tgcrp = &cpmtimerp->cpmt_tgcr; + +	printf ("Using timer %d\n" +			"tgcr @ 0x%x, tmr @ 0x%x, trr @ 0x%x," +			" tcr @ 0x%x, tcn @ 0x%x, ter @ 0x%x\n", +			TID_TIMER_ID + 1, +			(unsigned) hwp->tgcrp, +			(unsigned) hwp->tmrp, +			(unsigned) hwp->trrp, +			(unsigned) hwp->tcrp, +			(unsigned) hwp->tcnp, +			(unsigned) hwp->terp +			); + +	/* reset timer    */ +	*hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); + +	/* clear all events */ +	*hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF); + +	printf (usage); +	running = 0; +	while ((c = getc()) != 'q') { +	    if (c == 'b') { + +		setPeriod (hwp, TIMER_PERIOD);	/* Set period and start ticking */ + +		/* Install interrupt handler (enable timer in CIMR) */ +		install_hdlr (hwp->cpm_vec, timer_handler, hwp); + +		printf ("Enabling timer\n"); + +		/* enable timer */ +		*hwp->tgcrp |= (CPMT_GCR_RST << TID_TIMER_ID); +		running = 1; + +#ifdef	DEBUG +		printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x," +			" tcr=0x%x, tcn=0x%x, ter=0x%x\n", +				*hwp->tgcrp, *hwp->tmrp, *hwp->trrp, +				*hwp->tcrp,  *hwp->tcnp, *hwp->terp +				); +#endif +	    } else if (c == 'e') { + +		printf ("Stopping timer\n"); + +		*hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); +		running = 0; + +#ifdef	DEBUG +		printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x," +			" tcr=0x%x, tcn=0x%x, ter=0x%x\n", +				*hwp->tgcrp, *hwp->tmrp, *hwp->trrp, +				*hwp->tcrp,  *hwp->tcnp, *hwp->terp +			); +#endif +		/* Uninstall interrupt handler */ +		free_hdlr (hwp->cpm_vec); + +	    } else if (c == '?') { +#ifdef	DEBUG +		cpic8xx_t *cpm_icp = &((immap_t *) gd->bd->bi_immr_base)->im_cpic; +		sysconf8xx_t *siup = &((immap_t *) gd->bd->bi_immr_base)->im_siu_conf; +#endif + +		printf ("\ntgcr=0x%x, tmr=0x%x, trr=0x%x," +			" tcr=0x%x, tcn=0x%x, ter=0x%x\n", +				*hwp->tgcrp, *hwp->tmrp, *hwp->trrp, +				*hwp->tcrp,  *hwp->tcnp, *hwp->terp +			); +#ifdef	DEBUG +		printf ("SIUMCR=0x%08lx, SYPCR=0x%08lx," +			" SIMASK=0x%08lx, SIPEND=0x%08lx\n", +				siup->sc_siumcr, +				siup->sc_sypcr, +				siup->sc_simask, +				siup->sc_sipend +			); + +		printf ("CIMR=0x%08lx, CICR=0x%08lx, CIPR=0x%08lx\n", +			cpm_icp->cpic_cimr, +			cpm_icp->cpic_cicr, +			cpm_icp->cpic_cipr +			); +#endif +	    } else { +		printf ("\nEnter: q - quit, b - start timer, e - stop timer, ? - get status\n"); +	    } +	    printf (usage); +	} +	if (running) { +		printf ("Stopping timer\n"); +		*hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); +		free_hdlr (hwp->cpm_vec); +	} + +	return (0); +} + + +/* Set period in microseconds and start. + * Truncate to maximum period if more than this is requested - but warn about it. + */ + +void setPeriod (tid_8xx_cpmtimer_t *hwp, ulong interval) +{ +	unsigned short prescaler; +	unsigned long ticks; + +	printf ("Set interval %ld us\n", interval); + +	/* Warn if requesting longer period than possible */ +	if (interval > CPMT_MAX_INTERVAL) { +		printf ("Truncate interval %ld to maximum (%d)\n", +				interval, CPMT_MAX_INTERVAL); +		interval = CPMT_MAX_INTERVAL; +	} +	/* +	 * Check if we want to use clock divider: +	 * Since the reference counter can be incremented only in integer steps, +	 * we try to keep it as big as possible to allow the resulting period to be +	 * as precise as possible. +	 */ +	/* prescaler, enable interrupt, restart after ref count is reached */ +	prescaler = (ushort) ((CPMT_PRESCALER - 1) << 8) | +			CPMT_MR_ORI | +			CPMT_MR_FRR; + +	ticks = ((ulong) CLOCKRATE * interval); + +	if (ticks > CPMT_MAX_TICKS) { +		ticks /= CPMT_CLOCK_DIV; +		prescaler |= CPMT_MR_ICLK_CLKDIV;	/* use system clock divided by 16 */ +	} else { +		prescaler |= CPMT_MR_ICLK_CLK;	/* use system clock without divider */ +	} + +#ifdef	DEBUG +	printf ("clock/%d, prescale factor %d, reference %ld, ticks %ld\n", +			(ticks > CPMT_MAX_TICKS) ? CPMT_CLOCK_DIV : 1, +			CPMT_PRESCALER, +			(ticks / CPMT_PRESCALER), +			ticks +			); +#endif + +	/* set prescaler register */ +	*hwp->tmrp = prescaler; + +	/* clear timer counter */ +	*hwp->tcnp = 0; + +	/* set reference register */ +	*hwp->trrp = (unsigned short) (ticks / CPMT_PRESCALER); + +#ifdef	DEBUG +	printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x," +		" tcr=0x%x, tcn=0x%x, ter=0x%x\n", +			*hwp->tgcrp, *hwp->tmrp, *hwp->trrp, +			*hwp->tcrp,  *hwp->tcnp, *hwp->terp +		); +#endif +} + +/* + * Handler for CPMVEC_TIMER1 interrupt + */ +static +void timer_handler (void *arg) +{ +	tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)arg; + +	/* printf ("** TER1=%04x ** ", *hwp->terp); */ + +	/* just for demonstration */ +	printf ("."); + +	/* clear all possible events: Ref. and Cap. */ +	*hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF); +} diff --git a/examples/standalone/x86-testapp.c b/examples/standalone/x86-testapp.c new file mode 100644 index 000000000..e8603d9ba --- /dev/null +++ b/examples/standalone/x86-testapp.c @@ -0,0 +1,87 @@ +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +void *func[8], **pfunc; + +typedef struct xxx xxx_t; +struct xxx { +	int dummy; +	void **pfunc; +} q; + +#define XF_strcpy 3 +#define XF_printf 4 + +#define LABEL(x)					\ +asm volatile (						\ + +#if defined(__i386__) +#define EXPORT_FUNC(x)					\ +asm volatile (						\ +"	.globl mon_" #x "\n"				\ +"mon_" #x ":\n"						\ +"	movl	%0, %%eax\n"				\ +"	movl	pfunc, %%ecx\n"				\ +"	jmp	*(%%ecx,%%eax)\n"			\ +	: : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx"); +#elif defined(__powerpc__) +#define EXPORT_FUNC(x)					\ +asm volatile (						\ +"	.globl mon_" #x "\n"				\ +"mon_" #x ":\n"						\ +"	lwz	%%r11, %0(%%r2)\n"			\ +"	lwz	%%r11, %1(%%r11)\n"			\ +"	mtctr	%%r11\n"				\ +"	bctr\n"					\ +	: : "i"(offsetof(xxx_t, pfunc)), "i"(XF_ ## x * sizeof(void *)) : "r11", "r2"); +#elif defined(__arm__) +#define EXPORT_FUNC(x)					\ +asm volatile (						\ +"	.globl mon_" #x "\n"				\ +"mon_" #x ":\n"						\ +"	ldr	ip, [r8, %0]\n"				\ +"	ldr	pc, [ip, %1]\n"				\ +	: : "i"(offsetof(xxx_t, pfunc)), "i"(XF_ ## x * sizeof(void *)) : "ip"); +#elif defined(__mips__) +#define EXPORT_FUNC(x)					\ +asm volatile (						\ +"	.globl mon_" #x "\n"				\ +"mon_" #x ":\n"						\ +"	lw	$25, %0($26)\n"				\ +"	lw	$25, %1($25)\n"				\ +"	jr	$25\n"					\ +	: : "i"(offsetof(xxx_t, pfunc)), "i"(XF_ ## x * sizeof(void *)) : "t9"); +#else +#error [No stub code for this arch] +#endif + +void dummy(void) +{ +EXPORT_FUNC(printf) +EXPORT_FUNC(strcpy) +} + +int main(void) +{ +#if defined(__i386__) +	xxx_t *pq; +#elif defined(__powerpc__) +	register volatile xxx_t *pq asm("r2"); +#elif defined(__arm__) +	register volatile xxx_t *pq asm("r8"); +#elif defined(__mips__) +	register volatile xxx_t *pq asm("k0"); +#endif +	char buf[32]; + +	func[XF_strcpy] = strcpy; +	func[XF_printf] = printf; +	pq = &q; +	pq->pfunc = pfunc = func; + +	mon_strcpy(buf, "test"); +	mon_printf("hi %s %d z\n", buf, 444); + +	return 0; +} |