Move examples/ to examples/standalone

The current files in examples are all standalone application examples,
so put them in their own subdirectory for organizational purposes

Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
This commit is contained in:
Peter Tyser
2009-07-10 11:03:19 -05:00
committed by Wolfgang Denk
parent b220c64d86
commit 1bc1538613
24 changed files with 10 additions and 6 deletions

11
examples/standalone/.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
/82559_eeprom
/hello_world
/interrupt
/mem_to_mem_idma2intr
/test_burst
/timer
/sched
/smc91111_eeprom
/smc911x_eeprom
*.bin
*.srec

View File

@@ -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;
}

View File

@@ -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
#########################################################################

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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 ("+");
}

View File

@@ -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);
}

View File

@@ -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 = .;
}

View File

@@ -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 = .;
}

View File

@@ -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) }
}

View File

@@ -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

View File

@@ -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

369
examples/standalone/sched.c Normal file
View File

@@ -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 *)&lthreads[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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 = .;
}

225
examples/standalone/stubs.c Normal file
View File

@@ -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

View File

@@ -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");
}

View File

@@ -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 */

View File

@@ -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

349
examples/standalone/timer.c Normal file
View File

@@ -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);
}

View File

@@ -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;
}