From 0223e595f4033e91e93403a7317bcc9e47676b8f Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Wed, 23 Aug 2017 15:54:21 -0500 Subject: Initial import of modified u-boot tree Original upstream URL: git://git.denx.de/u-boot.git Original upstream GIT hash: 62c175fbb8a0f9a926c88294ea9f7e88eb898f6c --- examples/api/.gitignore | 2 + examples/api/Makefile | 90 ++++++ examples/api/crt0.S | 71 +++++ examples/api/demo.c | 331 ++++++++++++++++++++++ examples/api/glue.c | 435 +++++++++++++++++++++++++++++ examples/api/glue.h | 85 ++++++ examples/api/libgenwrap.c | 98 +++++++ examples/standalone/.gitignore | 13 + examples/standalone/82559_eeprom.c | 357 +++++++++++++++++++++++ examples/standalone/Makefile | 118 ++++++++ examples/standalone/README.smc91111_eeprom | 246 ++++++++++++++++ examples/standalone/atmel_df_pow2.c | 210 ++++++++++++++ examples/standalone/eepro100_eeprom.c | 214 ++++++++++++++ examples/standalone/hello_world.c | 54 ++++ examples/standalone/interrupt.c | 81 ++++++ examples/standalone/mem_to_mem_idma2intr.c | 385 +++++++++++++++++++++++++ examples/standalone/mips.lds | 59 ++++ examples/standalone/mips64.lds | 59 ++++ examples/standalone/nds32.lds | 56 ++++ examples/standalone/ppc_longjmp.S | 79 ++++++ examples/standalone/ppc_setjmp.S | 83 ++++++ examples/standalone/sched.c | 369 ++++++++++++++++++++++++ examples/standalone/smc91111_eeprom.c | 388 +++++++++++++++++++++++++ examples/standalone/smc911x_eeprom.c | 378 +++++++++++++++++++++++++ examples/standalone/sparc.lds | 62 ++++ examples/standalone/stubs.c | 237 ++++++++++++++++ examples/standalone/test_burst.c | 319 +++++++++++++++++++++ examples/standalone/test_burst.h | 38 +++ examples/standalone/test_burst_lib.S | 170 +++++++++++ examples/standalone/timer.c | 349 +++++++++++++++++++++++ examples/standalone/x86-testapp.c | 100 +++++++ 31 files changed, 5536 insertions(+) create mode 100644 examples/api/.gitignore create mode 100644 examples/api/Makefile create mode 100644 examples/api/crt0.S create mode 100644 examples/api/demo.c create mode 100644 examples/api/glue.c create mode 100644 examples/api/glue.h create mode 100644 examples/api/libgenwrap.c create mode 100644 examples/standalone/.gitignore create mode 100644 examples/standalone/82559_eeprom.c create mode 100644 examples/standalone/Makefile create mode 100644 examples/standalone/README.smc91111_eeprom create mode 100644 examples/standalone/atmel_df_pow2.c create mode 100644 examples/standalone/eepro100_eeprom.c create mode 100644 examples/standalone/hello_world.c create mode 100644 examples/standalone/interrupt.c create mode 100644 examples/standalone/mem_to_mem_idma2intr.c create mode 100644 examples/standalone/mips.lds create mode 100644 examples/standalone/mips64.lds create mode 100644 examples/standalone/nds32.lds create mode 100644 examples/standalone/ppc_longjmp.S create mode 100644 examples/standalone/ppc_setjmp.S create mode 100644 examples/standalone/sched.c create mode 100644 examples/standalone/smc91111_eeprom.c create mode 100644 examples/standalone/smc911x_eeprom.c create mode 100644 examples/standalone/sparc.lds create mode 100644 examples/standalone/stubs.c create mode 100644 examples/standalone/test_burst.c create mode 100644 examples/standalone/test_burst.h create mode 100644 examples/standalone/test_burst_lib.S create mode 100644 examples/standalone/timer.c create mode 100644 examples/standalone/x86-testapp.c (limited to 'examples') diff --git a/examples/api/.gitignore b/examples/api/.gitignore new file mode 100644 index 0000000..d7b18dc --- /dev/null +++ b/examples/api/.gitignore @@ -0,0 +1,2 @@ +demo +demo.bin diff --git a/examples/api/Makefile b/examples/api/Makefile new file mode 100644 index 0000000..bad05af --- /dev/null +++ b/examples/api/Makefile @@ -0,0 +1,90 @@ +# +# (C) Copyright 2007 Semihalf +# +# 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 Foundatio; 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),powerpc) +LOAD_ADDR = 0x40000 +endif +ifeq ($(ARCH),arm) +LOAD_ADDR = 0x1000000 +endif + +include $(TOPDIR)/config.mk + +# Resulting ELF and binary exectuables will be named demo and demo.bin +OUTPUT-$(CONFIG_API) = $(obj)demo +OUTPUT = $(OUTPUT-y) + +# Source files located in the examples/api directory +SOBJ_FILES-$(CONFIG_API) += crt0.o +COBJ_FILES-$(CONFIG_API) += demo.o +COBJ_FILES-$(CONFIG_API) += glue.o +COBJ_FILES-$(CONFIG_API) += libgenwrap.o + +# Source files which exist outside the examples/api directory +EXT_COBJ_FILES-$(CONFIG_API) += lib/crc32.o +EXT_COBJ_FILES-$(CONFIG_API) += lib/ctype.o +EXT_COBJ_FILES-$(CONFIG_API) += lib/div64.o +EXT_COBJ_FILES-$(CONFIG_API) += lib/string.o +EXT_COBJ_FILES-$(CONFIG_API) += lib/time.o +EXT_COBJ_FILES-$(CONFIG_API) += lib/vsprintf.o +ifeq ($(ARCH),powerpc) +EXT_SOBJ_FILES-$(CONFIG_API) += arch/powerpc/lib/ppcstring.o +endif + +# Create a list of source files so their dependencies can be auto-generated +SRCS += $(addprefix $(SRCTREE)/,$(EXT_COBJ_FILES-y:.o=.c)) +SRCS += $(addprefix $(SRCTREE)/,$(EXT_SOBJ_FILES-y:.o=.S)) +SRCS += $(addprefix $(SRCTREE)/examples/api/,$(COBJ_FILES-y:.o=.c)) +SRCS += $(addprefix $(SRCTREE)/examples/api/,$(SOBJ_FILES-y:.o=.S)) + +# Create a list of object files to be compiled +OBJS += $(addprefix $(obj),$(SOBJ_FILES-y)) +OBJS += $(addprefix $(obj),$(COBJ_FILES-y)) +OBJS += $(addprefix $(obj),$(notdir $(EXT_COBJ_FILES-y))) +OBJS += $(addprefix $(obj),$(notdir $(EXT_SOBJ_FILES-y))) + +CPPFLAGS += -I.. + +all: $(obj).depend $(OUTPUT) + +######################################################################### + +$(OUTPUT): $(OBJS) + $(LD) -Ttext $(LOAD_ADDR) -o $@ $^ $(PLATFORM_LIBS) + $(OBJCOPY) -O binary $@ $(OUTPUT).bin 2>/dev/null + +# Rule to build generic library C files +$(obj)%.o: $(SRCTREE)/lib/%.c + $(CC) -g $(CFLAGS) -c -o $@ $< + +# Rule to build architecture-specific library assembly files +$(obj)%.o: $(SRCTREE)/arch/$(ARCH)/lib/%.S + $(CC) -g $(CFLAGS) -c -o $@ $< + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/examples/api/crt0.S b/examples/api/crt0.S new file mode 100644 index 0000000..6daf127 --- /dev/null +++ b/examples/api/crt0.S @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2007 Semihalf + * + * Written by: Rafal Jaworowski + * + * 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 + * + */ + +#if defined(CONFIG_PPC) + + .text + .globl _start +_start: + lis %r11, search_hint@ha + addi %r11, %r11, search_hint@l + stw %r1, 0(%r11) + b main + + + .globl syscall +syscall: + lis %r11, syscall_ptr@ha + addi %r11, %r11, syscall_ptr@l + lwz %r11, 0(%r11) + mtctr %r11 + bctr + +#elif defined(CONFIG_ARM) + + .text + .globl _start +_start: + ldr ip, =search_hint + str sp, [ip] + b main + + + .globl syscall +syscall: + ldr ip, =syscall_ptr + ldr pc, [ip] + +#else +#error No support for this arch! +#endif + + .globl syscall_ptr +syscall_ptr: + .align 4 + .long 0 + + .globl search_hint +search_hint: + .long 0 diff --git a/examples/api/demo.c b/examples/api/demo.c new file mode 100644 index 0000000..19d38f6 --- /dev/null +++ b/examples/api/demo.c @@ -0,0 +1,331 @@ +/* + * (C) Copyright 2007-2008 Semihalf + * + * Written by: Rafal Jaworowski + * + * 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 +#include +#include + +#include "glue.h" + +#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0) + +#define BUF_SZ 2048 +#define WAIT_SECS 5 + +void test_dump_buf(void *, int); +void test_dump_di(int); +void test_dump_si(struct sys_info *); +void test_dump_sig(struct api_signature *); + +static char buf[BUF_SZ]; + +int main(int argc, char * const argv[]) +{ + int rv = 0, h, i, j, devs_no; + struct api_signature *sig = NULL; + ulong start, now; + struct device_info *di; + lbasize_t rlen; + struct display_info disinfo; + + if (!api_search_sig(&sig)) + return -1; + + syscall_ptr = sig->syscall; + if (syscall_ptr == NULL) + return -2; + + if (sig->version > API_SIG_VERSION) + return -3; + + printf("API signature found @%x\n", (unsigned int)sig); + test_dump_sig(sig); + + printf("\n*** Consumer API test ***\n"); + printf("syscall ptr 0x%08x@%08x\n", (unsigned int)syscall_ptr, + (unsigned int)&syscall_ptr); + + /* console activities */ + ub_putc('B'); + + printf("*** Press any key to continue ***\n"); + printf("got char 0x%x\n", ub_getc()); + + /* system info */ + test_dump_si(ub_get_sys_info()); + + /* timing */ + printf("\n*** Timing - wait a couple of secs ***\n"); + start = ub_get_timer(0); + printf("\ntime: start %lu\n\n", start); + for (i = 0; i < WAIT_SECS; i++) + for (j = 0; j < 1000; j++) + ub_udelay(1000); /* wait 1 ms */ + + /* this is the number of milliseconds that passed from ub_get_timer(0) */ + now = ub_get_timer(start); + printf("\ntime: now %lu\n\n", now); + + /* enumerate devices */ + printf("\n*** Enumerate devices ***\n"); + devs_no = ub_dev_enum(); + + printf("Number of devices found: %d\n", devs_no); + if (devs_no == 0) + return -1; + + printf("\n*** Show devices ***\n"); + for (i = 0; i < devs_no; i++) { + test_dump_di(i); + printf("\n"); + } + + printf("\n*** Operations on devices ***\n"); + + /* test opening a device already opened */ + h = 0; + if ((rv = ub_dev_open(h)) != 0) { + errf("open device %d error %d\n", h, rv); + return -1; + } + if ((rv = ub_dev_open(h)) != 0) + errf("open device %d error %d\n", h, rv); + + ub_dev_close(h); + + /* test storage */ + printf("Trying storage devices...\n"); + for (i = 0; i < devs_no; i++) { + di = ub_dev_get(i); + + if (di->type & DEV_TYP_STOR) + break; + + } + if (i == devs_no) + printf("No storage devices available\n"); + else { + memset(buf, 0, BUF_SZ); + + if ((rv = ub_dev_open(i)) != 0) + errf("open device %d error %d\n", i, rv); + + else if ((rv = ub_dev_read(i, buf, 1, 0, &rlen)) != 0) + errf("could not read from device %d, error %d\n", i, rv); + else { + printf("Sector 0 dump (512B):\n"); + test_dump_buf(buf, 512); + } + + ub_dev_close(i); + } + + /* test networking */ + printf("Trying network devices...\n"); + for (i = 0; i < devs_no; i++) { + di = ub_dev_get(i); + + if (di->type == DEV_TYP_NET) + break; + + } + if (i == devs_no) + printf("No network devices available\n"); + else { + if ((rv = ub_dev_open(i)) != 0) + errf("open device %d error %d\n", i, rv); + else if ((rv = ub_dev_send(i, &buf, 2048)) != 0) + errf("could not send to device %d, error %d\n", i, rv); + + ub_dev_close(i); + } + + if (ub_dev_close(h) != 0) + errf("could not close device %d\n", h); + + printf("\n*** Env vars ***\n"); + + printf("ethact = %s\n", ub_env_get("ethact")); + printf("old fileaddr = %s\n", ub_env_get("fileaddr")); + ub_env_set("fileaddr", "deadbeef"); + printf("new fileaddr = %s\n", ub_env_get("fileaddr")); + + const char *env = NULL; + + while ((env = ub_env_enum(env)) != NULL) + printf("%s = %s\n", env, ub_env_get(env)); + + printf("\n*** Display ***\n"); + + if (ub_display_get_info(DISPLAY_TYPE_LCD, &disinfo)) { + printf("LCD info: failed\n"); + } else { + printf("LCD info:\n"); + printf(" pixel width: %d\n", disinfo.pixel_width); + printf(" pixel height: %d\n", disinfo.pixel_height); + printf(" screen rows: %d\n", disinfo.screen_rows); + printf(" screen cols: %d\n", disinfo.screen_cols); + } + if (ub_display_get_info(DISPLAY_TYPE_VIDEO, &disinfo)) { + printf("video info: failed\n"); + } else { + printf("video info:\n"); + printf(" pixel width: %d\n", disinfo.pixel_width); + printf(" pixel height: %d\n", disinfo.pixel_height); + printf(" screen rows: %d\n", disinfo.screen_rows); + printf(" screen cols: %d\n", disinfo.screen_cols); + } + + printf("*** Press any key to continue ***\n"); + printf("got char 0x%x\n", ub_getc()); + + /* + * This only clears messages on screen, not on serial port. It is + * equivalent to a no-op if no display is available. + */ + ub_display_clear(); + + /* reset */ + printf("\n*** Resetting board ***\n"); + ub_reset(); + printf("\nHmm, reset returned...?!\n"); + + return rv; +} + +void test_dump_sig(struct api_signature *sig) +{ + printf("signature:\n"); + printf(" version\t= %d\n", sig->version); + printf(" checksum\t= 0x%08x\n", sig->checksum); + printf(" sc entry\t= 0x%08x\n", (unsigned int)sig->syscall); +} + +void test_dump_si(struct sys_info *si) +{ + int i; + + printf("sys info:\n"); + printf(" clkbus\t= 0x%08x\n", (unsigned int)si->clk_bus); + printf(" clkcpu\t= 0x%08x\n", (unsigned int)si->clk_cpu); + printf(" bar\t\t= 0x%08x\n", (unsigned int)si->bar); + + printf("---\n"); + for (i = 0; i < si->mr_no; i++) { + if (si->mr[i].flags == 0) + break; + + printf(" start\t= 0x%08lx\n", si->mr[i].start); + printf(" size\t= 0x%08lx\n", si->mr[i].size); + + switch(si->mr[i].flags & 0x000F) { + case MR_ATTR_FLASH: + printf(" type FLASH\n"); + break; + case MR_ATTR_DRAM: + printf(" type DRAM\n"); + break; + case MR_ATTR_SRAM: + printf(" type SRAM\n"); + break; + default: + printf(" type UNKNOWN\n"); + } + printf("---\n"); + } +} + +static char *test_stor_typ(int type) +{ + if (type & DT_STOR_IDE) + return "IDE"; + + if (type & DT_STOR_MMC) + return "MMC"; + + if (type & DT_STOR_SATA) + return "SATA"; + + if (type & DT_STOR_SCSI) + return "SCSI"; + + if (type & DT_STOR_USB) + return "USB"; + + return "Unknown"; +} + +void test_dump_buf(void *buf, int len) +{ + int i; + int line_counter = 0; + int sep_flag = 0; + int addr = 0; + + printf("%07x:\t", addr); + + for (i = 0; i < len; i++) { + if (line_counter++ > 15) { + line_counter = 0; + sep_flag = 0; + addr += 16; + i--; + printf("\n%07x:\t", addr); + continue; + } + + if (sep_flag++ > 1) { + sep_flag = 1; + printf(" "); + } + + printf("%02x", *((char *)buf++)); + } + + printf("\n"); +} + +void test_dump_di(int handle) +{ + int i; + struct device_info *di = ub_dev_get(handle); + + printf("device info (%d):\n", handle); + printf(" cookie\t= 0x%08x\n", (uint32_t)di->cookie); + printf(" type\t\t= 0x%08x\n", di->type); + + if (di->type == DEV_TYP_NET) { + printf(" hwaddr\t= "); + for (i = 0; i < 6; i++) + printf("%02x ", di->di_net.hwaddr[i]); + + printf("\n"); + + } else if (di->type & DEV_TYP_STOR) { + printf(" type\t\t= %s\n", test_stor_typ(di->type)); + printf(" blk size\t\t= %d\n", (unsigned int)di->di_stor.block_size); + printf(" blk count\t\t= %d\n", (unsigned int)di->di_stor.block_count); + } +} diff --git a/examples/api/glue.c b/examples/api/glue.c new file mode 100644 index 0000000..d907e3f --- /dev/null +++ b/examples/api/glue.c @@ -0,0 +1,435 @@ +/* + * (C) Copyright 2007-2008 Semihalf, Rafal Jaworowski + * + * 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 +#include +#include + +#include "glue.h" + +static int valid_sig(struct api_signature *sig) +{ + uint32_t checksum; + struct api_signature s; + + if (sig == NULL) + return 0; + /* + * Clear the checksum field (in the local copy) so as to calculate the + * CRC with the same initial contents as at the time when the sig was + * produced + */ + s = *sig; + s.checksum = 0; + + checksum = crc32(0, (unsigned char *)&s, sizeof(struct api_signature)); + + if (checksum != sig->checksum) + return 0; + + return 1; +} + +/* + * Searches for the U-Boot API signature + * + * returns 1/0 depending on found/not found result + */ +int api_search_sig(struct api_signature **sig) +{ + unsigned char *sp; + uint32_t search_start = 0; + uint32_t search_end = 0; + + if (sig == NULL) + return 0; + + if (search_hint == 0) + search_hint = 255 * 1024 * 1024; + + search_start = search_hint & ~0x000fffff; + search_end = search_start + API_SEARCH_LEN - API_SIG_MAGLEN; + + sp = (unsigned char *)search_start; + while ((sp + API_SIG_MAGLEN) < (unsigned char *)search_end) { + if (!memcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) { + *sig = (struct api_signature *)sp; + if (valid_sig(*sig)) + return 1; + } + sp += API_SIG_MAGLEN; + } + + *sig = NULL; + return 0; +} + +/**************************************** + * + * console + * + ****************************************/ + +int ub_getc(void) +{ + int c; + + if (!syscall(API_GETC, NULL, (uint32_t)&c)) + return -1; + + return c; +} + +int ub_tstc(void) +{ + int t; + + if (!syscall(API_TSTC, NULL, (uint32_t)&t)) + return -1; + + return t; +} + +void ub_putc(char c) +{ + syscall(API_PUTC, NULL, (uint32_t)&c); +} + +void ub_puts(const char *s) +{ + syscall(API_PUTS, NULL, (uint32_t)s); +} + +/**************************************** + * + * system + * + ****************************************/ + +void ub_reset(void) +{ + syscall(API_RESET, NULL); +} + +static struct mem_region mr[UB_MAX_MR]; +static struct sys_info si; + +struct sys_info * ub_get_sys_info(void) +{ + int err = 0; + + memset(&si, 0, sizeof(struct sys_info)); + si.mr = mr; + si.mr_no = UB_MAX_MR; + memset(&mr, 0, sizeof(mr)); + + if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si)) + return NULL; + + return ((err) ? NULL : &si); +} + +/**************************************** + * + * timing + * + ****************************************/ + +void ub_udelay(unsigned long usec) +{ + syscall(API_UDELAY, NULL, &usec); +} + +unsigned long ub_get_timer(unsigned long base) +{ + unsigned long cur; + + if (!syscall(API_GET_TIMER, NULL, &cur, &base)) + return 0; + + return cur; +} + + +/**************************************************************************** + * + * devices + * + * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1 + * + ***************************************************************************/ + +static struct device_info devices[UB_MAX_DEV]; + +struct device_info * ub_dev_get(int i) +{ + return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]); +} + +/* + * Enumerates the devices: fills out device_info elements in the devices[] + * array. + * + * returns: number of devices found + */ +int ub_dev_enum(void) +{ + struct device_info *di; + int n = 0; + + memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV); + di = &devices[0]; + + if (!syscall(API_DEV_ENUM, NULL, di)) + return 0; + + while (di->cookie != NULL) { + + if (++n >= UB_MAX_DEV) + break; + + /* take another device_info */ + di++; + + /* pass on the previous cookie */ + di->cookie = devices[n - 1].cookie; + + if (!syscall(API_DEV_ENUM, NULL, di)) + return 0; + } + + return n; +} + +/* + * handle: 0-based id of the device + * + * returns: 0 when OK, err otherwise + */ +int ub_dev_open(int handle) +{ + struct device_info *di; + int err = 0; + + if (handle < 0 || handle >= UB_MAX_DEV) + return API_EINVAL; + + di = &devices[handle]; + + if (!syscall(API_DEV_OPEN, &err, di)) + return -1; + + return err; +} + +int ub_dev_close(int handle) +{ + struct device_info *di; + + if (handle < 0 || handle >= UB_MAX_DEV) + return API_EINVAL; + + di = &devices[handle]; + if (!syscall(API_DEV_CLOSE, NULL, di)) + return -1; + + return 0; +} + +/* + * + * Validates device for read/write, it has to: + * + * - have sane handle + * - be opened + * + * returns: 0/1 accordingly + */ +static int dev_valid(int handle) +{ + if (handle < 0 || handle >= UB_MAX_DEV) + return 0; + + if (devices[handle].state != DEV_STA_OPEN) + return 0; + + return 1; +} + +static int dev_stor_valid(int handle) +{ + if (!dev_valid(handle)) + return 0; + + if (!(devices[handle].type & DEV_TYP_STOR)) + return 0; + + return 1; +} + +int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start, + lbasize_t *rlen) +{ + struct device_info *di; + lbasize_t act_len; + int err = 0; + + if (!dev_stor_valid(handle)) + return API_ENODEV; + + di = &devices[handle]; + if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len)) + return API_ESYSC; + + if (!err && rlen) + *rlen = act_len; + + return err; +} + +static int dev_net_valid(int handle) +{ + if (!dev_valid(handle)) + return 0; + + if (devices[handle].type != DEV_TYP_NET) + return 0; + + return 1; +} + +int ub_dev_recv(int handle, void *buf, int len, int *rlen) +{ + struct device_info *di; + int err = 0, act_len; + + if (!dev_net_valid(handle)) + return API_ENODEV; + + di = &devices[handle]; + if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len)) + return API_ESYSC; + + if (!err && rlen) + *rlen = act_len; + + return (err); +} + +int ub_dev_send(int handle, void *buf, int len) +{ + struct device_info *di; + int err = 0; + + if (!dev_net_valid(handle)) + return API_ENODEV; + + di = &devices[handle]; + if (!syscall(API_DEV_WRITE, &err, di, buf, &len)) + return API_ESYSC; + + return err; +} + +/**************************************** + * + * env vars + * + ****************************************/ + +char * ub_env_get(const char *name) +{ + char *value; + + if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value)) + return NULL; + + return value; +} + +void ub_env_set(const char *name, char *value) +{ + syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value); +} + +static char env_name[256]; + +const char * ub_env_enum(const char *last) +{ + const char *env, *str; + int i; + + env = NULL; + + /* + * It's OK to pass only the name piece as last (and not the whole + * 'name=val' string), since the API_ENUM_ENV call uses envmatch() + * internally, which handles such case + */ + if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env)) + return NULL; + + if (!env) + /* no more env. variables to enumerate */ + return NULL; + + /* next enumerated env var */ + memset(env_name, 0, 256); + for (i = 0, str = env; *str != '=' && *str != '\0';) + env_name[i++] = *str++; + + env_name[i] = '\0'; + + return env_name; +} + +/**************************************** + * + * display + * + ****************************************/ + +int ub_display_get_info(int type, struct display_info *di) +{ + int err = 0; + + if (!syscall(API_DISPLAY_GET_INFO, &err, (uint32_t)type, (uint32_t)di)) + return API_ESYSC; + + return err; +} + +int ub_display_draw_bitmap(ulong bitmap, int x, int y) +{ + int err = 0; + + if (!syscall(API_DISPLAY_DRAW_BITMAP, &err, bitmap, x, y)) + return API_ESYSC; + + return err; +} + +void ub_display_clear(void) +{ + syscall(API_DISPLAY_CLEAR, NULL); +} diff --git a/examples/api/glue.h b/examples/api/glue.h new file mode 100644 index 0000000..e43f7d9 --- /dev/null +++ b/examples/api/glue.h @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2007 Semihalf + * + * Written by: Rafal Jaworowski + * + * 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 the header file for conveniency wrapper routines (API glue) + */ + +#ifndef _API_GLUE_H_ +#define _API_GLUE_H_ + +#define API_SEARCH_LEN (3 * 1024 * 1024) /* 3MB search range */ + +#define UB_MAX_MR 5 /* max mem regions number */ +#define UB_MAX_DEV 6 /* max devices number */ + +extern void *syscall_ptr; +extern uint32_t search_hint; + +int syscall(int, int *, ...); +int api_search_sig(struct api_signature **sig); + +/* + * The ub_ library calls are part of the application, not U-Boot code! They + * are front-end wrappers that are used by the consumer application: they + * prepare arguments for particular syscall and jump to the low level + * syscall() + */ + +/* console */ +int ub_getc(void); +int ub_tstc(void); +void ub_putc(char c); +void ub_puts(const char *s); + +/* system */ +void ub_reset(void); +struct sys_info * ub_get_sys_info(void); + +/* time */ +void ub_udelay(unsigned long); +unsigned long ub_get_timer(unsigned long); + +/* env vars */ +char * ub_env_get(const char *name); +void ub_env_set(const char *name, char *value); +const char * ub_env_enum(const char *last); + +/* devices */ +int ub_dev_enum(void); +int ub_dev_open(int handle); +int ub_dev_close(int handle); +int ub_dev_read(int handle, void *buf, lbasize_t len, + lbastart_t start, lbasize_t *rlen); +int ub_dev_send(int handle, void *buf, int len); +int ub_dev_recv(int handle, void *buf, int len, int *rlen); +struct device_info * ub_dev_get(int); + +/* display */ +int ub_display_get_info(int type, struct display_info *di); +int ub_display_draw_bitmap(ulong bitmap, int x, int y); +void ub_display_clear(void); + +#endif /* _API_GLUE_H_ */ diff --git a/examples/api/libgenwrap.c b/examples/api/libgenwrap.c new file mode 100644 index 0000000..873cf34 --- /dev/null +++ b/examples/api/libgenwrap.c @@ -0,0 +1,98 @@ +/* + * (C) Copyright 2007 Semihalf + * + * Written by: Rafal Jaworowski + * + * 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 is a set of wrappers/stubs that allow to use certain routines from + * U-Boot's lib in the standalone app. This way way we can re-use + * existing code e.g. operations on strings and similar. + * + */ + +#include +#include +#include + +#include "glue.h" + +/* + * printf() and vprintf() are stolen from u-boot/common/console.c + */ +int printf (const char *fmt, ...) +{ + va_list args; + uint i; + char printbuffer[256]; + + va_start (args, fmt); + + /* For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vsprintf (printbuffer, fmt, args); + va_end (args); + + /* Print the string */ + ub_puts (printbuffer); + return i; +} + +int vprintf (const char *fmt, va_list args) +{ + uint i; + char printbuffer[256]; + + /* For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vsprintf (printbuffer, fmt, args); + + /* Print the string */ + ub_puts (printbuffer); + return i; +} + +void putc (const char c) +{ + ub_putc(c); +} + +void __udelay(unsigned long usec) +{ + ub_udelay(usec); +} + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + ub_reset(); + return 0; +} + +void *malloc (size_t len) +{ + return NULL; +} + +void hang (void) +{ + while (1) ; +} diff --git a/examples/standalone/.gitignore b/examples/standalone/.gitignore new file mode 100644 index 0000000..4d9ce66 --- /dev/null +++ b/examples/standalone/.gitignore @@ -0,0 +1,13 @@ +/82559_eeprom +/atmel_df_pow2 +/eepro100_eeprom +/hello_world +/interrupt +/mem_to_mem_idma2intr +/sched +/smc91111_eeprom +/smc911x_eeprom +/test_burst +/timer +*.bin +*.srec diff --git a/examples/standalone/82559_eeprom.c b/examples/standalone/82559_eeprom.c new file mode 100644 index 0000000..8dd7079 --- /dev/null +++ b/examples/standalone/82559_eeprom.c @@ -0,0 +1,357 @@ + +/* + * Copyright 1998-2001 by Donald Becker. + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Contact the author for use under other terms. + * + * This program must be compiled with "-O"! + * See the bottom of this file for the suggested compile-command. + * + * The author may be reached as becker@scyld.com, or C/O + * Scyld Computing Corporation + * 410 Severn Ave., Suite 210 + * Annapolis MD 21403 + * + * Common-sense licensing statement: Using any portion of this program in + * your own program means that you must give credit to the original author + * and release the resulting code under the GPL. + */ + +#define _PPC_STRING_H_ /* avoid unnecessary str/mem functions */ + +#include +#include +#include + + +/* 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</dev/null + +$(BIN): +$(obj)%.bin: $(obj)% + $(OBJCOPY) -O binary $< $@ 2>/dev/null + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/examples/standalone/README.smc91111_eeprom b/examples/standalone/README.smc91111_eeprom new file mode 100644 index 0000000..28e7e69 --- /dev/null +++ b/examples/standalone/README.smc91111_eeprom @@ -0,0 +1,246 @@ +This is the readme for the Das U-Boot standalone program smc91111 + +The main purpose of this is to manage MAC addresses on platforms +which include the SMC91111 integrated 10/100 MAC Phy, with attached +EEPROMs. + + +Contents: +------------------------ +1. Ensuring U-boot's MAC address can be set in hardware +2. Running the smc91111_eeprom program +3. Setting MAC addresses +4. Other things you can do with this +5. Things to be done. + + +1. Ensuring U-boot's MAC address can be set in hardware +-------------------------------------------------------------------------- + +On the Internet - MAC addresses are very important. Short for Media +Access Control address, a hardware address that uniquely identifies +each node of a network. When things are not unique - bad things +can happen. This is why U-Boot makes it difficult to change MAC +addresses. + +To find out who has a MAC address, or to purchase MAC addresses, goto +the IEEE, at: +http://standards.ieee.org/regauth/oui/index.shtml + +To change your MAC address, there can not be a MAC address predefined in +U-Boot. To ensure that this does not occur, check your +include/configs/.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/.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 : + 1000: + 000010d8 : + +You can see that the entry point (or the address that should be +jumped to is 0x10d8). This is also the same as the entry point +of the elf file. + +Now we load it to the actual load location: + +BOOT> loadb 0x1000 + +## Ready for binary (kermit) download to 0x00001000 at 57600 bps... + +(Back at pinky.dsl-only.net) +---------------------------------------------------- +Kermit>send /tftpboot/eeprom.bin +Kermit>connect + +Connecting to /dev/ttyS0, speed 57600 + Escape character: Ctrl-\ (ASCII 28, FS): enabled +Type the escape character followed by C to get back, +or followed by ? to see other options. +---------------------------------------------------- +## Total Size = 0x00000d70 = 3440 Bytes +## Start Addr = 0x00001000 + +BOOT> go 0x10D8 + +## Starting application at 0x000010D8 ... + +SMC91111> + +3. Setting MAC addresses +-------------------------------------------------------------------------- + +The MAC address can be stored in four locations: + +-Boot environmental variable in Flash <- can not change, without + re-flashing U-boot. +U-Boot environental variable <- can not change, without + resetting board/U-Boot +LAN91C111 Registers <- volitle +LAN91C111 EEPROM <- Non Volitle + +If you have not activated the network, and do not have a hardcoded +or pre-assigned MAC address in U-boot, the environmental variables +should be blank, and allow you to set things one time. + +To set the EEPROM MAC address to 12:34:56:78:9A:BC + +SMC91111> W E 20 3412 + +Writing EEPROM register 20 with 3412 +SMC91111> W E 21 7856 + +Writing EEPROM register 21 with 7856 +SMC91111> W E 22 BC9A + +Writing EEPROM register 22 with bc9a +EEPROM contents copied to MAC +SMC91111> P + +Current MAC Address in SMSC91111 12:34:56:78:9a:bc +Current MAC Address in EEPROM 12:34:56:78:9a:bc + +(CNTRL-C to exit) +SMC91111> ## Application terminated, rc = 0x0 + +BOOT> reset +U-Boot 1.1.1 (gcc version: 3.3.3) +Release Version Beta released on Oct 10 2004 - 00:34:35 +Blackfin support by LG Soft India +For further information please check this link http://www.blackfin.uclinux.org +BOOT> ping 192.168.0.4 + +Using MAC Address 12:34:56:78:9A:BC +host 192.168.0.4 is alive + + +4. Other things that you can do +-------------------------------------------------------------------------- +After the stand alone application is running, there are a few options: + - P : Print the MAC + - D : Dump the LAN91C111 EEPROM contents + - M : Dump the LAN91C111 MAC contents + - C : Copies the MAC address from the EEPROM to the LAN91C111 + - W : Write a register in the EEPROM or in the MAC + +SMC91111> P + +Current MAC Address in SMSC91111 12:34:56:78:9a:bc +Current MAC Address in EEPROM 12:34:56:78:9a:bc + +SMC91111> D + +IOS2-0 000 001 002 003 004 005 006 007 +CONFIG 00:ffff 04:ffff 08:ffff 0c:ffff 10:ffff 14:ffff 18:ffff 1c:ffff +BASE 01:ffff 05:ffff 09:ffff 0d:ffff 11:ffff 15:ffff 19:ffff 1d:ffff + 02:ffff 06:ffff 0a:ffff 0e:0020 12:ffff 16:ffff 1a:ffff 1e:ffff + 03:ffff 07:ffff 0b:ffff 0f:ffff 13:ffff 17:ffff 1b:ffff 1f:ffff + +20:3412 21:7856 22:bc9a 23:ffff 24:ffff 25:ffff 26:ffff 27:ffff +28:ffff 29:ffff 2a:ffff 2b:ffff 2c:ffff 2d:ffff 2e:ffff 2f:ffff +30:ffff 31:ffff 32:ffff 33:ffff 34:ffff 35:ffff 36:ffff 37:ffff +38:ffff 39:ffff 3a:ffff 3b:ffff 3c:ffff 3d:ffff 3e:ffff 3f:ffff + +SMC91111> M + + Bank0 Bank1 Bank2 Bank3 +00 0000 a0b1 3332 0000 +02 0000 1801 8000 0000 +04 0000 3412 8080 0000 +06 0000 7856 003f 0000 +08 0404 bc9a 02df 3332 +0a 0000 ffff 02df 3391 +0c 0000 1214 0004 001f +0e 3300 3301 3302 3303 + +SMC91111> C + +EEPROM contents copied to MAC + +SMC91111> W E 2A ABCD + +Writing EEPROM register 2a with abcd + +SMC91111> W M 14 FF00 + +Writing MAC register bank 1, reg 04 with ff00 diff --git a/examples/standalone/atmel_df_pow2.c b/examples/standalone/atmel_df_pow2.c new file mode 100644 index 0000000..2e14aba --- /dev/null +++ b/examples/standalone/atmel_df_pow2.c @@ -0,0 +1,210 @@ +/* + * atmel_df_pow2.c - convert Atmel Dataflashes to Power of 2 mode + * + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the 2-clause BSD. + */ + +#include +#include +#include + +#define CMD_ID 0x9f +#define CMD_STAT 0xd7 +#define CMD_CFG 0x3d + +static int flash_cmd(struct spi_slave *slave, uchar cmd, uchar *buf, int len) +{ + buf[0] = cmd; + return spi_xfer(slave, 8 * len, buf, buf, SPI_XFER_BEGIN | SPI_XFER_END); +} + +static int flash_status(struct spi_slave *slave) +{ + uchar buf[2]; + if (flash_cmd(slave, CMD_STAT, buf, sizeof(buf))) + return -1; + return buf[1]; +} + +static int flash_set_pow2(struct spi_slave *slave) +{ + int ret; + uchar buf[4]; + + buf[1] = 0x2a; + buf[2] = 0x80; + buf[3] = 0xa6; + + ret = flash_cmd(slave, CMD_CFG, buf, sizeof(buf)); + if (ret) + return ret; + + /* wait Tp, or 6 msec */ + udelay(6000); + + ret = flash_status(slave); + if (ret == -1) + return 1; + + return ret & 0x1 ? 0 : 1; +} + +static int flash_check(struct spi_slave *slave) +{ + int ret; + uchar buf[4]; + + ret = flash_cmd(slave, CMD_ID, buf, sizeof(buf)); + if (ret) + return ret; + + if (buf[1] != 0x1F) { + printf("atmel flash not found (id[0] = %#x)\n", buf[1]); + return 1; + } + + if ((buf[2] >> 5) != 0x1) { + printf("AT45 flash not found (id[0] = %#x)\n", buf[2]); + return 2; + } + + return 0; +} + +static char *getline(void) +{ + static char buffer[100]; + char c; + size_t i; + + i = 0; + while (1) { + buffer[i] = '\0'; + + c = getc(); + + 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; + } + } +} + +int atmel_df_pow2(int argc, char * const 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; + } + + spi_init(); + + while (1) { + struct spi_slave *slave; + char *line, *p; + int bus, cs, status; + + puts("\nenter the [BUS:]CS of the SPI flash: "); + line = getline(); + + /* CTRL+C */ + if (!line) + return 0; + if (line[0] == '\0') + continue; + + bus = cs = simple_strtoul(line, &p, 10); + if (*p) { + if (*p == ':') { + ++p; + cs = simple_strtoul(p, &p, 10); + } + if (*p) { + puts("invalid format, please try again\n"); + continue; + } + } else + bus = 0; + + printf("\ngoing to work with dataflash at %i:%i\n", bus, cs); + + /* use a low speed -- it'll work with all devices, and + * speed here doesn't really matter. + */ + slave = spi_setup_slave(bus, cs, 1000, SPI_MODE_3); + if (!slave) { + puts("unable to setup slave\n"); + continue; + } + + if (spi_claim_bus(slave)) { + spi_free_slave(slave); + continue; + } + + if (flash_check(slave)) { + puts("no flash found\n"); + goto done; + } + + status = flash_status(slave); + if (status == -1) { + puts("unable to read status register\n"); + goto done; + } + if (status & 0x1) { + puts("flash is already in power-of-2 mode!\n"); + goto done; + } + + puts("are you sure you wish to set power-of-2 mode?\n"); + puts("this operation is permanent and irreversible\n"); + printf("enter YES to continue: "); + line = getline(); + if (!line || strcmp(line, "YES")) + goto done; + + if (flash_set_pow2(slave)) { + puts("setting pow2 mode failed\n"); + goto done; + } + + puts( + "Configuration should be updated now. You will have to\n" + "power cycle the part in order to finish the conversion.\n" + ); + + done: + spi_release_bus(slave); + spi_free_slave(slave); + } +} diff --git a/examples/standalone/eepro100_eeprom.c b/examples/standalone/eepro100_eeprom.c new file mode 100644 index 0000000..3c7f380 --- /dev/null +++ b/examples/standalone/eepro100_eeprom.c @@ -0,0 +1,214 @@ +/* + * 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 _PPC_STRING_H_ + +#include +#include + +static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr); + +int eepro100_eeprom(int argc, char * const 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)); +} + +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< +#include + +int hello_world (int argc, char * const 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] : ""); + } + + printf ("Hit any key to exit ... "); + while (!tstc()) + ; + /* consume input */ + (void) getc(); + + printf ("\n\n"); + return (0); +} diff --git a/examples/standalone/interrupt.c b/examples/standalone/interrupt.c new file mode 100644 index 0000000..a5b58a1 --- /dev/null +++ b/examples/standalone/interrupt.c @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2006 + * Detlev Zundel, DENX Software Engineering, dzu@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * This is a very simple standalone application demonstrating + * catching IRQs on the MPC52xx architecture. + * + * The interrupt to be intercepted can be specified as an argument + * to the application. Specifying nothing will intercept IRQ1 on the + * MPC5200 platform. On the CR825 carrier board from MicroSys this + * maps to the ABORT switch :) + * + * Note that the specified vector is only a logical number specified + * by the respective header file. + */ + +#include +#include +#include + +#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 * const argv[]) +{ + int c, irq = -1; + + app_startup (argv); + + if (argc > 1) + irq = simple_strtoul (argv[1], NULL, 0); + if ((irq < 0) || (irq > NR_IRQS)) + irq = DFL_IRQ; + + printf ("Installing handler for irq vector %d and doing busy wait\n", + irq); + printf ("Press 'q' to quit\n"); + + /* Install interrupt handler */ + install_hdlr (irq, irq_handler, NULL); + while ((c = getc ()) != 'q') { + printf ("Ok, ok, I am still alive!\n"); + } + + free_hdlr (irq); + printf ("\nInterrupt handler has been uninstalled\n"); + + return (0); +} + +/* + * Handler for interrupt + */ +static void irq_handler (void *arg) +{ + /* just for demonstration */ + printf ("+"); +} diff --git a/examples/standalone/mem_to_mem_idma2intr.c b/examples/standalone/mem_to_mem_idma2intr.c new file mode 100644 index 0000000..215dc22 --- /dev/null +++ b/examples/standalone/mem_to_mem_idma2intr.c @@ -0,0 +1,385 @@ +/* The dpalloc function used and implemented in this file was derieved + * from PPCBoot/U-Boot file "arch/powerpc/cpu/mpc8260/commproc.c". + */ + +/* Author: Arun Dharankar + * This example is meant to only demonstrate how the IDMA could be used. + */ + +/* + * This file is based on "arch/powerpc/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 +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define STANDALONE + +#ifndef STANDALONE /* Linked into/Part of PPCBoot */ +#include +#include +#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 * const argv[]) +#else +int do_idma (bd_t * bd, int argc, char * const 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 u16 *)&immap->im_dprambase16 + [PROFF_IDMA2_BASE / sizeof(u16)] = 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->arch.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->arch.dp_alloc_top) { + dpbase = savebase; + printf ("dpalloc: ran out of dual port ram!"); + return 0; + } + + retloc = dpbase; + dpbase += size; + + memset ((void *) &immr->im_dprambase[retloc], 0, size); + + return (retloc); +} diff --git a/examples/standalone/mips.lds b/examples/standalone/mips.lds new file mode 100644 index 0000000..5f766ed --- /dev/null +++ b/examples/standalone/mips.lds @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk Engineering, + * + * 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-tradlittlemips") +OUTPUT_ARCH(mips) +SECTIONS +{ + .text : + { + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { *(.data*) } + + . = .; + _gp = ALIGN(16) + 0x7ff0; + + .got : { + __got_start = .; + *(.got) + __got_end = .; + } + + .sdata : { *(.sdata*) } + + . = ALIGN(4); + __bss_start = .; + .sbss (NOLOAD) : { *(.sbss*) } + .bss (NOLOAD) : { *(.bss*) . = ALIGN(4); } + + _end = .; +} diff --git a/examples/standalone/mips64.lds b/examples/standalone/mips64.lds new file mode 100644 index 0000000..9b27ef4 --- /dev/null +++ b/examples/standalone/mips64.lds @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk Engineering, + * + * 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("elf64-tradbigmips", "elf64-tradbigmips", "elf64-tradlittlemips") +OUTPUT_ARCH(mips) +SECTIONS +{ + .text : + { + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { *(.data*) } + + . = .; + _gp = ALIGN(16) + 0x7ff0; + + .got : { + __got_start = .; + *(.got) + __got_end = .; + } + + .sdata : { *(.sdata*) } + + . = ALIGN(4); + __bss_start = .; + .sbss (NOLOAD) : { *(.sbss*) } + .bss (NOLOAD) : { *(.bss*) . = ALIGN(4); } + + _end = .; +} diff --git a/examples/standalone/nds32.lds b/examples/standalone/nds32.lds new file mode 100644 index 0000000..50b4c4b --- /dev/null +++ b/examples/standalone/nds32.lds @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Andes Technology Corporation + * Shawn Lin, Andes Technology Corporation + * Macpaul Lin, Andes Technology Corporation + * + * 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-nds32", "elf32-nds32", "elf32-nds32") +OUTPUT_ARCH(nds32) +ENTRY(_start) +SECTIONS +{ + . = ALIGN(4); + .text : + { + *(.text) + } + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + + .got : { + __got_start = .; + *(.got) + __got_end = .; + } + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + __bss_end = .; + + . = ALIGN(4); + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + + _end = .; +} diff --git a/examples/standalone/ppc_longjmp.S b/examples/standalone/ppc_longjmp.S new file mode 100644 index 0000000..5ca6f6f --- /dev/null +++ b/examples/standalone/ppc_longjmp.S @@ -0,0 +1,79 @@ +/* longjmp for PowerPC. + Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +# define JB_GPR1 0 /* Also known as the stack pointer */ +# define JB_GPR2 1 +# define JB_LR 2 /* The address we will return to */ +# define JB_GPRS 3 /* GPRs 14 through 31 are saved, 18 in total */ +# define JB_CR 21 /* Condition code registers. */ +# define JB_FPRS 22 /* FPRs 14 through 31 are saved, 18*2 words total */ +# define JB_SIZE (58*4) + +#define FP(x...) x +#define FP(x...) x + +.globl ppc_longjmp; + +ppc_longjmp: + lwz r1,(JB_GPR1*4)(r3) + lwz r2,(JB_GPR2*4)(r3) + lwz r0,(JB_LR*4)(r3) + lwz r14,((JB_GPRS+0)*4)(r3) +FP( lfd 14,((JB_FPRS+0*2)*4)(r3)) + lwz r15,((JB_GPRS+1)*4)(r3) +FP( lfd 15,((JB_FPRS+1*2)*4)(r3)) + lwz r16,((JB_GPRS+2)*4)(r3) +FP( lfd 16,((JB_FPRS+2*2)*4)(r3)) + lwz r17,((JB_GPRS+3)*4)(r3) +FP( lfd 17,((JB_FPRS+3*2)*4)(r3)) + lwz r18,((JB_GPRS+4)*4)(r3) +FP( lfd 18,((JB_FPRS+4*2)*4)(r3)) + lwz r19,((JB_GPRS+5)*4)(r3) +FP( lfd 19,((JB_FPRS+5*2)*4)(r3)) + lwz r20,((JB_GPRS+6)*4)(r3) +FP( lfd 20,((JB_FPRS+6*2)*4)(r3)) + mtlr r0 + lwz r21,((JB_GPRS+7)*4)(r3) +FP( lfd 21,((JB_FPRS+7*2)*4)(r3)) + lwz r22,((JB_GPRS+8)*4)(r3) +FP( lfd 22,((JB_FPRS+8*2)*4)(r3)) + lwz r0,(JB_CR*4)(r3) + lwz r23,((JB_GPRS+9)*4)(r3) +FP( lfd 23,((JB_FPRS+9*2)*4)(r3)) + lwz r24,((JB_GPRS+10)*4)(r3) +FP( lfd 24,((JB_FPRS+10*2)*4)(r3)) + lwz r25,((JB_GPRS+11)*4)(r3) +FP( lfd 25,((JB_FPRS+11*2)*4)(r3)) + mtcrf 0xFF,r0 + lwz r26,((JB_GPRS+12)*4)(r3) +FP( lfd 26,((JB_FPRS+12*2)*4)(r3)) + lwz r27,((JB_GPRS+13)*4)(r3) +FP( lfd 27,((JB_FPRS+13*2)*4)(r3)) + lwz r28,((JB_GPRS+14)*4)(r3) +FP( lfd 28,((JB_FPRS+14*2)*4)(r3)) + lwz r29,((JB_GPRS+15)*4)(r3) +FP( lfd 29,((JB_FPRS+15*2)*4)(r3)) + lwz r30,((JB_GPRS+16)*4)(r3) +FP( lfd 30,((JB_FPRS+16*2)*4)(r3)) + lwz r31,((JB_GPRS+17)*4)(r3) +FP( lfd 31,((JB_FPRS+17*2)*4)(r3)) + mr r3,r4 + blr diff --git a/examples/standalone/ppc_setjmp.S b/examples/standalone/ppc_setjmp.S new file mode 100644 index 0000000..421abfd --- /dev/null +++ b/examples/standalone/ppc_setjmp.S @@ -0,0 +1,83 @@ +/* setjmp for PowerPC. + Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +# define JB_GPR1 0 /* Also known as the stack pointer */ +# define JB_GPR2 1 +# define JB_LR 2 /* The address we will return to */ +# define JB_GPRS 3 /* GPRs 14 through 31 are saved, 18 in total */ +# define JB_CR 21 /* Condition code registers. */ +# define JB_FPRS 22 /* FPRs 14 through 31 are saved, 18*2 words total */ +# define JB_SIZE (58*4) + +#define FP(x...) x + +.globl setctxsp; +setctxsp: + mr r1, r3 + blr + +.globl ppc_setjmp; +ppc_setjmp: + stw r1,(JB_GPR1*4)(3) + mflr r0 + stw r2,(JB_GPR2*4)(3) + stw r14,((JB_GPRS+0)*4)(3) +FP( stfd 14,((JB_FPRS+0*2)*4)(3)) + stw r0,(JB_LR*4)(3) + stw r15,((JB_GPRS+1)*4)(3) +FP( stfd 15,((JB_FPRS+1*2)*4)(3)) + mfcr r0 + stw r16,((JB_GPRS+2)*4)(3) +FP( stfd 16,((JB_FPRS+2*2)*4)(3)) + stw r0,(JB_CR*4)(3) + stw r17,((JB_GPRS+3)*4)(3) +FP( stfd 17,((JB_FPRS+3*2)*4)(3)) + stw r18,((JB_GPRS+4)*4)(3) +FP( stfd 18,((JB_FPRS+4*2)*4)(3)) + stw r19,((JB_GPRS+5)*4)(3) +FP( stfd 19,((JB_FPRS+5*2)*4)(3)) + stw r20,((JB_GPRS+6)*4)(3) +FP( stfd 20,((JB_FPRS+6*2)*4)(3)) + stw r21,((JB_GPRS+7)*4)(3) +FP( stfd 21,((JB_FPRS+7*2)*4)(3)) + stw r22,((JB_GPRS+8)*4)(3) +FP( stfd 22,((JB_FPRS+8*2)*4)(3)) + stw r23,((JB_GPRS+9)*4)(3) +FP( stfd 23,((JB_FPRS+9*2)*4)(3)) + stw r24,((JB_GPRS+10)*4)(3) +FP( stfd 24,((JB_FPRS+10*2)*4)(3)) + stw r25,((JB_GPRS+11)*4)(3) +FP( stfd 25,((JB_FPRS+11*2)*4)(3)) + stw r26,((JB_GPRS+12)*4)(3) +FP( stfd 26,((JB_FPRS+12*2)*4)(3)) + stw r27,((JB_GPRS+13)*4)(3) +FP( stfd 27,((JB_FPRS+13*2)*4)(3)) + stw r28,((JB_GPRS+14)*4)(3) +FP( stfd 28,((JB_FPRS+14*2)*4)(3)) + stw r29,((JB_GPRS+15)*4)(3) +FP( stfd 29,((JB_FPRS+15*2)*4)(3)) + stw r30,((JB_GPRS+16)*4)(3) +FP( stfd 30,((JB_FPRS+16*2)*4)(3)) + stw r31,((JB_GPRS+17)*4)(3) +FP( stfd 31,((JB_FPRS+17*2)*4)(3)) + + li 3, 0 + blr diff --git a/examples/standalone/sched.c b/examples/standalone/sched.c new file mode 100644 index 0000000..b32766f --- /dev/null +++ b/examples/standalone/sched.c @@ -0,0 +1,369 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +/* + * Author: Arun Dharankar + * + * A very simple thread/schedular model: + * - only one master thread, and no parent child relation maintained + * - parent thread cannot be stopped or deleted + * - no permissions or credentials + * - no elaborate safety checks + * - cooperative multi threading + * - Simple round-robin scheduleing with no priorities + * - no metering/statistics collection + * + * Basic idea of implementing this is to allow more than one tests to + * execute "simultaneously". + * + * This may be modified such thread_yield may be called in syscalls, and + * timer interrupts. + */ + + +#define MAX_THREADS 8 + +#define CTX_SIZE 512 +#define STK_SIZE 8*1024 + +#define STATE_EMPTY 0 +#define STATE_RUNNABLE 1 +#define STATE_STOPPED 2 +#define STATE_TERMINATED 2 + +#define MASTER_THREAD 0 + +#define RC_FAILURE (-1) +#define RC_SUCCESS (0) + +typedef vu_char *jmp_ctx; +unsigned long setctxsp (vu_char *sp); +int ppc_setjmp(jmp_ctx env); +void ppc_longjmp(jmp_ctx env, int val); +#define setjmp ppc_setjmp +#define longjmp ppc_longjmp + +struct lthread { + int state; + int retval; + char stack[STK_SIZE]; + uchar context[CTX_SIZE]; + int (*func) (void *); + void *arg; +}; +static volatile struct lthread lthreads[MAX_THREADS]; +static volatile int current_tid = MASTER_THREAD; + + +static uchar dbg = 0; + +#define PDEBUG(fmt, args...) { \ + if(dbg != 0) { \ + printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);\ + printf(fmt, ##args); \ + printf("\n"); \ + } \ +} + +static int testthread (void *); +static void sched_init (void); +static int thread_create (int (*func) (void *), void *arg); +static int thread_start (int id); +static void thread_yield (void); +static int thread_delete (int id); +static int thread_join (int *ret); + +#if 0 /* not used yet */ +static int thread_stop (int id); +#endif /* not used yet */ + +/* An example of schedular test */ + +#define NUMTHREADS 7 +int sched (int ac, char *av[]) +{ + int i, j; + int tid[NUMTHREADS]; + int names[NUMTHREADS]; + + app_startup(av); + + sched_init (); + + for (i = 0; i < NUMTHREADS; i++) { + names[i] = i; + j = thread_create (testthread, (void *) &names[i]); + if (j == RC_FAILURE) + printf ("schedtest: Failed to create thread %d\n", i); + if (j > 0) { + printf ("schedtest: Created thread with id %d, name %d\n", + j, i); + tid[i] = j; + } + } + printf ("schedtest: Threads created\n"); + + printf ("sched_test: function=0x%08x\n", (unsigned)testthread); + for (i = 0; i < NUMTHREADS; i++) { + printf ("schedtest: Setting thread %d runnable\n", tid[i]); + thread_start (tid[i]); + thread_yield (); + } + printf ("schedtest: Started %d threads\n", NUMTHREADS); + + while (1) { + printf ("schedtest: Waiting for threads to complete\n"); + if (tstc () && getc () == 0x3) { + printf ("schedtest: Aborting threads...\n"); + for (i = 0; i < NUMTHREADS; i++) { + printf ("schedtest: Deleting thread %d\n", tid[i]); + thread_delete (tid[i]); + } + return RC_SUCCESS; + } + j = -1; + i = thread_join (&j); + if (i == RC_FAILURE) { + printf ("schedtest: No threads pending, " + "exiting schedular test\n"); + return RC_SUCCESS; + } + printf ("schedtest: thread is %d returned %d\n", i, j); + thread_yield (); + } + + return RC_SUCCESS; +} + +static int testthread (void *name) +{ + int i; + + printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n", + *(int *) name, (unsigned)&i); + + printf ("Thread %02d, i=%d\n", *(int *) name, i); + + for (i = 0; i < 0xffff * (*(int *) name + 1); i++) { + if (tstc () && getc () == 0x3) { + printf ("testthread: myname %d terminating.\n", + *(int *) name); + return *(int *) name + 1; + } + + if (i % 100 == 0) + thread_yield (); + } + + printf ("testthread: returning %d, i=0x%x\n", + *(int *) name + 1, i); + + return *(int *) name + 1; +} + + +static void sched_init (void) +{ + int i; + + for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) + lthreads[i].state = STATE_EMPTY; + + current_tid = MASTER_THREAD; + lthreads[current_tid].state = STATE_RUNNABLE; + PDEBUG ("sched_init: master context = 0x%08x", + (unsigned)lthreads[current_tid].context); + return; +} + +static void thread_yield (void) +{ + static int i; + + PDEBUG ("thread_yield: current tid=%d", current_tid); + +#define SWITCH(new) \ + if(lthreads[new].state == STATE_RUNNABLE) { \ + PDEBUG("thread_yield: %d match, ctx=0x%08x", \ + new, \ + (unsigned)lthreads[current_tid].context); \ + if(setjmp(lthreads[current_tid].context) == 0) { \ + current_tid = new; \ + PDEBUG("thread_yield: tid %d returns 0", \ + new); \ + longjmp(lthreads[new].context, 1); \ + } else { \ + PDEBUG("thread_yield: tid %d returns 1", \ + new); \ + return; \ + } \ + } + + for (i = current_tid + 1; i < MAX_THREADS; i++) { + SWITCH (i); + } + + if (current_tid != 0) { + for (i = 0; i <= current_tid; i++) { + SWITCH (i); + } + } + + PDEBUG ("thread_yield: returning from thread_yield"); + return; +} + +static int thread_create (int (*func) (void *), void *arg) +{ + int i; + + for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { + if (lthreads[i].state == STATE_EMPTY) { + lthreads[i].state = STATE_STOPPED; + lthreads[i].func = func; + lthreads[i].arg = arg; + PDEBUG ("thread_create: returns new tid %d", i); + return i; + } + } + + PDEBUG ("thread_create: returns failure"); + return RC_FAILURE; +} + +static int thread_delete (int id) +{ + if (id <= MASTER_THREAD || id > MAX_THREADS) + return RC_FAILURE; + + if (current_tid == id) + return RC_FAILURE; + + lthreads[id].state = STATE_EMPTY; + return RC_SUCCESS; +} + +static void thread_launcher (void) +{ + PDEBUG ("thread_launcher: invoking func=0x%08x", + (unsigned)lthreads[current_tid].func); + + lthreads[current_tid].retval = + lthreads[current_tid].func (lthreads[current_tid].arg); + + PDEBUG ("thread_launcher: tid %d terminated", current_tid); + + lthreads[current_tid].state = STATE_TERMINATED; + thread_yield (); + printf ("thread_launcher: should NEVER get here!\n"); + + return; +} + +static int thread_start (int id) +{ + PDEBUG ("thread_start: id=%d", id); + if (id <= MASTER_THREAD || id > MAX_THREADS) { + return RC_FAILURE; + } + + if (lthreads[id].state != STATE_STOPPED) + return RC_FAILURE; + + if (setjmp (lthreads[current_tid].context) == 0) { + lthreads[id].state = STATE_RUNNABLE; + current_tid = id; + PDEBUG ("thread_start: to be stack=0%08x", + (unsigned)lthreads[id].stack); + setctxsp ((vu_char *)<hreads[id].stack[STK_SIZE]); + thread_launcher (); + } + + PDEBUG ("thread_start: Thread id=%d started, parent returns", id); + + return RC_SUCCESS; +} + +#if 0 /* not used so far */ +static int thread_stop (int id) +{ + if (id <= MASTER_THREAD || id >= MAX_THREADS) + return RC_FAILURE; + + if (current_tid == id) + return RC_FAILURE; + + lthreads[id].state = STATE_STOPPED; + return RC_SUCCESS; +} +#endif /* not used so far */ + +static int thread_join (int *ret) +{ + int i, j = 0; + + PDEBUG ("thread_join: *ret = %d", *ret); + + if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) { + PDEBUG ("thread_join: invalid tid %d", *ret); + return RC_FAILURE; + } + + if (*ret == -1) { + PDEBUG ("Checking for tid = -1"); + while (1) { + /* PDEBUG("thread_join: start while-loopn"); */ + j = 0; + for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { + if (lthreads[i].state == STATE_TERMINATED) { + *ret = lthreads[i].retval; + lthreads[i].state = STATE_EMPTY; + /* PDEBUG("thread_join: returning retval %d of tid %d", + ret, i); */ + return RC_SUCCESS; + } + + if (lthreads[i].state != STATE_EMPTY) { + PDEBUG ("thread_join: %d used slots tid %d state=%d", + j, i, lthreads[i].state); + j++; + } + } + if (j == 0) { + PDEBUG ("thread_join: all slots empty!"); + return RC_FAILURE; + } + /* PDEBUG("thread_join: yielding"); */ + thread_yield (); + /* PDEBUG("thread_join: back from yield"); */ + } + } + + if (lthreads[*ret].state == STATE_TERMINATED) { + i = *ret; + *ret = lthreads[*ret].retval; + lthreads[*ret].state = STATE_EMPTY; + PDEBUG ("thread_join: returing %d for tid %d", *ret, i); + return RC_SUCCESS; + } + + PDEBUG ("thread_join: thread %d is not terminated!", *ret); + return RC_FAILURE; +} diff --git a/examples/standalone/smc91111_eeprom.c b/examples/standalone/smc91111_eeprom.c new file mode 100644 index 0000000..c98b0fc --- /dev/null +++ b/examples/standalone/smc91111_eeprom.c @@ -0,0 +1,388 @@ +/* + * (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 +#include +#include "../drivers/net/smc91111.h" + +#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 (struct eth_device *dev); +void dump_eeprom (struct eth_device *dev); +int write_eeprom_reg (struct eth_device *dev, int value, int reg); +void copy_from_eeprom (struct eth_device *dev); +void print_MAC (struct eth_device *dev); +int read_eeprom_reg (struct eth_device *dev, int reg); +void print_macaddr (struct eth_device *dev); + +int smc91111_eeprom (int argc, char * const argv[]) +{ + int c, i, j, done, line, reg, value, start, what; + char input[50]; + + struct eth_device dev; + dev.iobase = CONFIG_SMC91111_BASE; + + /* 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 (&dev, 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 (&dev, value, reg); + break; + case 2: + printf ("Writing MAC register bank %i, reg %02x with %04x\n", reg >> 4, reg & 0xE, value); + SMC_SELECT_BANK (&dev, reg >> 4); + SMC_outw (&dev, value, reg & 0xE); + break; + default: + printf ("Wrong\n"); + break; + } + break; + case ('D'): + dump_eeprom (&dev); + break; + case ('M'): + dump_reg (&dev); + break; + case ('C'): + copy_from_eeprom (&dev); + break; + case ('P'): + print_macaddr (&dev); + break; + default: + break; + } + + } + + return (0); +} + +void copy_from_eeprom (struct eth_device *dev) +{ + int i; + + SMC_SELECT_BANK (dev, 1); + SMC_outw (dev, (SMC_inw (dev, CTL_REG) & !CTL_EEPROM_SELECT) | + CTL_RELOAD, CTL_REG); + i = 100; + while ((SMC_inw (dev, 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 (struct eth_device *dev) +{ + int i, j, k, mac[6]; + + printf ("Current MAC Address in SMSC91111 "); + SMC_SELECT_BANK (dev, 1); + for (i = 0; i < 5; i++) { + printf ("%02x:", SMC_inb (dev, ADDR0_REG + i)); + } + + printf ("%02x\n", SMC_inb (dev, ADDR0_REG + 5)); + + i = 0; + for (j = 0x20; j < 0x23; j++) { + k = read_eeprom_reg (dev, 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 (struct eth_device *dev) +{ + 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 (dev, j + k)); + } + printf ("\n"); + } + + for (j = 0x20; j < 0x40; j++) { + if ((j & 0x07) == 0) + printf ("\n"); + printf ("%02x:%04x ", j, read_eeprom_reg (dev, j)); + } + printf ("\n"); + +} + +int read_eeprom_reg (struct eth_device *dev, int reg) +{ + int timeout; + + SMC_SELECT_BANK (dev, 2); + SMC_outw (dev, reg, PTR_REG); + + SMC_SELECT_BANK (dev, 1); + SMC_outw (dev, SMC_inw (dev, CTL_REG) | CTL_EEPROM_SELECT | + CTL_RELOAD, CTL_REG); + timeout = 100; + while ((SMC_inw (dev, CTL_REG) & CTL_RELOAD) && --timeout) + udelay (100); + if (timeout == 0) { + printf ("Timeout Reading EEPROM register %02x\n", reg); + return 0; + } + + return SMC_inw (dev, GP_REG); + +} + +int write_eeprom_reg (struct eth_device *dev, int value, int reg) +{ + int timeout; + + SMC_SELECT_BANK (dev, 2); + SMC_outw (dev, reg, PTR_REG); + + SMC_SELECT_BANK (dev, 1); + SMC_outw (dev, value, GP_REG); + SMC_outw (dev, SMC_inw (dev, CTL_REG) | CTL_EEPROM_SELECT | + CTL_STORE, CTL_REG); + timeout = 100; + while ((SMC_inw (dev, 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 (struct eth_device *dev) +{ + 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 (dev, j); + printf ("%04x ", SMC_inw (dev, i)); + } + printf ("\n"); + } +} diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c new file mode 100644 index 0000000..6c79c5f --- /dev/null +++ b/examples/standalone/smc911x_eeprom.c @@ -0,0 +1,378 @@ +/* + * smc911x_eeprom.c - EEPROM interface to SMC911x parts. + * Only tested on SMSC9118 though ... + * + * Copyright 2004-2009 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 +#include +#include +#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 \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(struct eth_device *dev) +{ + u8 i, j = 0; + for (i = 0x50; i < 0xB8; i += sizeof(u32)) + printf("%02x: 0x%08x %c", i, + smc911x_reg_read(dev, i), + (j++ % 2 ? '\n' : ' ')); +} + +/** + * do_eeprom_cmd - handle eeprom communication + */ +static int do_eeprom_cmd(struct eth_device *dev, int cmd, u8 reg) +{ + if (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) { + printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n", + smc911x_reg_read(dev, E2P_CMD)); + return -1; + } + + smc911x_reg_write(dev, E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg); + + while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) + if (smsc_ctrlc()) { + printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n", + smc911x_reg_read(dev, E2P_CMD)); + return -1; + } + + return 0; +} + +/** + * read_eeprom_reg - read specified register in EEPROM + */ +static u8 read_eeprom_reg(struct eth_device *dev, u8 reg) +{ + int ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ, reg); + return (ret ? : smc911x_reg_read(dev, E2P_DATA)); +} + +/** + * write_eeprom_reg - write specified value into specified register in EEPROM + */ +static int write_eeprom_reg(struct eth_device *dev, u8 value, u8 reg) +{ + int ret; + + /* enable erasing/writing */ + ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN, reg); + if (ret) + goto done; + + /* erase the eeprom reg */ + ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE, reg); + if (ret) + goto done; + + /* write the eeprom reg */ + smc911x_reg_write(dev, E2P_DATA, value); + ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE, reg); + if (ret) + goto done; + + /* disable erasing/writing */ + ret = do_eeprom_cmd(dev, 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 (isblank(buf[0])) + ++buf; + return buf; +} + +/** + * write_stuff - handle writing of MAC registers / eeprom + */ +static void write_stuff(struct eth_device *dev, 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(dev, value, reg); + } else { + printf("Writing MAC register %02x with %08x\n", reg, value); + smc911x_reg_write(dev, reg, value); + } +} + +/** + * copy_from_eeprom - copy MAC address in eeprom to address registers + */ +static void copy_from_eeprom(struct eth_device *dev) +{ + ulong addrl = + read_eeprom_reg(dev, 0x01) | + read_eeprom_reg(dev, 0x02) << 8 | + read_eeprom_reg(dev, 0x03) << 16 | + read_eeprom_reg(dev, 0x04) << 24; + ulong addrh = + read_eeprom_reg(dev, 0x05) | + read_eeprom_reg(dev, 0x06) << 8; + smc911x_set_mac_csr(dev, ADDRL, addrl); + smc911x_set_mac_csr(dev, ADDRH, addrh); + puts("EEPROM contents copied to MAC\n"); +} + +/** + * print_macaddr - print MAC address registers and MAC address in eeprom + */ +static void print_macaddr(struct eth_device *dev) +{ + puts("Current MAC Address in MAC: "); + ulong addrl = smc911x_get_mac_csr(dev, ADDRL); + ulong addrh = smc911x_get_mac_csr(dev, 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(dev, i)); + printf("%02x\n", read_eeprom_reg(dev, i)); +} + +/** + * dump_eeprom - dump the whole content of the EEPROM + */ +static void dump_eeprom(struct eth_device *dev) +{ + int i; + puts("EEPROM:\n"); + for (i = 0; i < 7; ++i) + printf("%02x: 0x%02x\n", i, read_eeprom_reg(dev, i)); +} + +/** + * smc911x_init - get the MAC/EEPROM up and ready for use + */ +static int smc911x_init(struct eth_device *dev) +{ + /* See if there is anything there */ + if (smc911x_detect_chip(dev)) + return 1; + + smc911x_reset(dev); + + /* Make sure we set EEDIO/EECLK to the EEPROM */ + if (smc911x_reg_read(dev, GPIO_CFG) & GPIO_CFG_EEPR_EN) { + while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) + if (smsc_ctrlc()) { + printf("init: timeout (E2P_CMD = 0x%08x)\n", + smc911x_reg_read(dev, E2P_CMD)); + return 1; + } + smc911x_reg_write(dev, GPIO_CFG, + smc911x_reg_read(dev, 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 * const argv[]) +{ + /* Avoid initializing on stack as gcc likes to call memset() */ + struct eth_device dev; + dev.iobase = CONFIG_SMC911X_BASE; + + /* 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(&dev)) + 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] && !isblank(line[1])) + goto unknown_cmd; + + /* Now parse the command */ + switch (line[0]) { + case 'W': write_stuff(&dev, line); break; + case 'D': dump_eeprom(&dev); break; + case 'M': dump_regs(&dev); break; + case 'C': copy_from_eeprom(&dev); break; + case 'P': print_macaddr(&dev); break; + unknown_cmd: + default: puts("ERROR: Unknown command!\n\n"); + case '?': + case 'H': usage(); break; + case 'Q': return 0; + } + } +} diff --git a/examples/standalone/sparc.lds b/examples/standalone/sparc.lds new file mode 100644 index 0000000..646b80f --- /dev/null +++ b/examples/standalone/sparc.lds @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2003, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc") +OUTPUT_ARCH(sparc) +ENTRY(_start) + +SECTIONS +{ + .text : + { + *(.text) + } + __text_end = .; + + . = ALIGN(4); + .rodata : + { + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + } + __rodata_end = .; + + . = ALIGN(4); + .data : + { + *(.data) + } + + . = ALIGN(4); + __data_end = .; + + __bss_start = .; + . = ALIGN(4); + .bss : + { + *(.bss) + } + . = ALIGN(4); + __bss_end = .; + _end = .; +} diff --git a/examples/standalone/stubs.c b/examples/standalone/stubs.c new file mode 100644 index 0000000..8fb1765 --- /dev/null +++ b/examples/standalone/stubs.c @@ -0,0 +1,237 @@ +#include +#include + +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +#if defined(CONFIG_X86) +/* + * 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_NIOS2) +/* + * gp 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, gp\n" \ +" ldw r8, 0(r8)\n" \ +" ldw r8, %1(r8)\n" \ +" jmp r8\n" \ + : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "gp"); +#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) +/* + * P3 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 = [P3 + %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" \ +" jmp %%g1\n" \ +" nop\n" \ + : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "g1" ); +#elif defined(CONFIG_NDS32) +/* + * r16 holds the pointer to the global_data. gp is call clobbered. + * not support reduced register (16 GPR). + */ +#define EXPORT_FUNC(x) \ + asm volatile ( \ +" .globl " #x "\n" \ +#x ":\n" \ +" lwi $r16, [$gp + (%0)]\n" \ +" lwi $r16, [$r16 + (%1)]\n" \ +" jr $r16\n" \ + : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "$r16"); +#elif defined(CONFIG_OPENRISC) +/* + * r10 holds the pointer to the global_data, r13 is a call-clobbered + * register + */ +#define EXPORT_FUNC(x) \ + asm volatile ( \ +" .globl " #x "\n" \ +#x ":\n" \ +" l.lwz r13, %0(r10)\n" \ +" l.lwz r13, %1(r13)\n" \ +" l.jr r13\n" \ +" l.nop\n" \ + : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r13"); +#else +/*" addi $sp, $sp, -24\n" \ +" br $r16\n" \*/ + +#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> +} + +#include + +void app_startup(char * const *argv) +{ + char *cp = __bss_start; + + /* Zero out BSS */ + while (cp < _end) + *cp++ = 0; + +#if defined(CONFIG_X86) + /* x86 does not have a dedicated register for passing global_data */ + global_data = (gd_t *)argv[-1]; + jt = global_data->jt; +#endif +} + +#undef EXPORT_FUNC diff --git a/examples/standalone/test_burst.c b/examples/standalone/test_burst.c new file mode 100644 index 0000000..2b101b7 --- /dev/null +++ b/examples/standalone/test_burst.c @@ -0,0 +1,319 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * The test exercises SDRAM accesses in burst mode + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#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 * const argv[]) +{ + unsigned long size = CACHE_LINE_SIZE; + unsigned int pass = 0; + int res = 0; + int i, j; + + if (argc == 3) { + char * d; + for (size = 0, d = argv[1]; *d >= '0' && *d <= '9'; d++) { + size *= 10; + size += *d - '0'; + } + if (size == 0 || *d) { + test_usage(); + return 1; + } + for (d = argv[2]; *d >= '0' && *d <= '9'; d++) { + pass *= 10; + pass += *d - '0'; + } + if (*d) { + test_usage(); + return 1; + } + } else if (argc > 3) { + test_usage(); + return 1; + } + + size += (CACHE_LINE_SIZE - 1); + size &= ~(CACHE_LINE_SIZE - 1); + + if (!test_mmu_is_on()) { + test_prepare(); + } + + test_desc(size); + + for (j = 0; !pass || j < pass; j++) { + for (i = 0; i < sizeof(test_pattern) / sizeof(test_pattern[0]); + i++) { + res = test_burst_start(size, test_pattern[i]); + if (res != 0) { + goto Done; + } + } + + printf ("Iteration #%d passed\n", j + 1); + + if (tstc() && 0x03 == getc()) + break; + } +Done: + return res; +} + +static void test_prepare (void) +{ + printf ("\n"); + + caches_init(); + disable_interrupts(); + mmu_init(); + + printf ("Interrupts are disabled\n"); + printf ("I-Cache is ON\n"); + printf ("D-Cache is ON\n"); + printf ("MMU is ON\n"); + + printf ("\n"); + + test_map_8M (TEST_PADDR, TEST_VADDR_NC, 0); + test_map_8M (TEST_PADDR, TEST_VADDR_C, 1); + + test_map_8M (TEST_FLASH_ADDR & 0xFF800000, TEST_FLASH_ADDR & 0xFF800000, 0); + + /* Configure GPIO ports */ + signal_init(); +} + +static int test_burst_start (unsigned long size, unsigned long pattern) +{ + volatile unsigned long * vaddr_c = (unsigned long *)TEST_VADDR_C; + volatile unsigned long * vaddr_nc = (unsigned long *)TEST_VADDR_NC; + int i, n; + int res = 1; + + printf ("Test pattern %08lx ...", pattern); + + n = size / 4; + + for (i = 0; i < n; i ++) { + vaddr_c [i] = pattern; + } + signal_start(); + flush_dcache_range((unsigned long)vaddr_c, (unsigned long)(vaddr_c + n) - 1); + + for (i = 0; i < n; i ++) { + register unsigned long tmp = vaddr_nc [i]; + if (tmp != pattern) { + test_error("2a", vaddr_nc + i, tmp, pattern); + goto Done; + } + } + + for (i = 0; i < n; i ++) { + register unsigned long tmp = vaddr_c [i]; + if (tmp != pattern) { + test_error("2b", vaddr_c + i, tmp, pattern); + goto Done; + } + } + + for (i = 0; i < n; i ++) { + vaddr_nc [i] = pattern; + } + + for (i = 0; i < n; i ++) { + register unsigned long tmp = vaddr_nc [i]; + if (tmp != pattern) { + test_error("3a", vaddr_nc + i, tmp, pattern); + goto Done; + } + } + + signal_start(); + for (i = 0; i < n; i ++) { + register unsigned long tmp = vaddr_c [i]; + if (tmp != pattern) { + test_error("3b", vaddr_c + i, tmp, pattern); + goto Done; + } + } + + res = 0; +Done: + printf(" %s\n", res == 0 ? "OK" : ""); + + return res; +} + +static void test_map_8M (unsigned long paddr, unsigned long vaddr, int cached) +{ + mtspr (MD_EPN, (vaddr & 0xFFFFFC00) | MI_EVALID); + mtspr (MD_TWC, MI_PS8MEG | MI_SVALID); + mtspr (MD_RPN, (paddr & 0xFFFFF000) | MI_BOOTINIT | (cached ? 0 : 2)); + mtspr (MD_AP, MI_Kp); +} + +static int test_mmu_is_on(void) +{ + unsigned long msr; + + asm volatile("mfmsr %0" : "=r" (msr) :); + + return msr & MSR_DR; +} + +static void test_desc(unsigned long size) +{ + printf( + "The following tests will be conducted:\n" + "1) Map %ld-byte region of physical RAM at 0x%08x\n" + " into two virtual regions:\n" + " one cached at 0x%08x and\n" + " the the other uncached at 0x%08x.\n", + size, TEST_PADDR, TEST_VADDR_NC, TEST_VADDR_C); + + puts( + "2) Fill the cached region with a pattern, and flush the cache\n" + "2a) Check the uncached region to match the pattern\n" + "2b) Check the cached region to match the pattern\n" + "3) Fill the uncached region with a pattern\n" + "3a) Check the cached region to match the pattern\n" + "3b) Check the uncached region to match the pattern\n" + "2b) Change the patterns and go to step 2\n" + "\n" + ); +} + +static void test_error( + char * step, volatile void * addr, unsigned long val, unsigned long pattern) +{ + volatile unsigned long * p = (void *)TEST_FLASH_ADDR; + + signal_error(); + + p[0] = (unsigned long)addr; + p[1] = val; + p[2] = pattern; + + printf ("\nError at step %s, addr %08lx: read %08lx, pattern %08lx", + step, (unsigned long)addr, val, pattern); +} + +static void signal_init(void) +{ +#if defined(GPIO1_INIT) + GPIO1_INIT; +#endif +#if defined(GPIO2_INIT) + GPIO2_INIT; +#endif +} + +static void signal_start(void) +{ +#if defined(GPIO1_INIT) + if (GPIO1_DAT & GPIO1_BIT) { + GPIO1_DAT &= ~GPIO1_BIT; + } else { + GPIO1_DAT |= GPIO1_BIT; + } +#endif +} + +static void signal_error(void) +{ +#if defined(GPIO2_INIT) + if (GPIO2_DAT & GPIO2_BIT) { + GPIO2_DAT &= ~GPIO2_BIT; + } else { + GPIO2_DAT |= GPIO2_BIT; + } +#endif +} + +static void test_usage(void) +{ + printf("Usage: go 0x40004 [size] [count]\n"); +} diff --git a/examples/standalone/test_burst.h b/examples/standalone/test_burst.h new file mode 100644 index 0000000..f85928c --- /dev/null +++ b/examples/standalone/test_burst.h @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEST_BURST_H +#define _TEST_BURST_H + +/* Cache line size */ +#define CACHE_LINE_SIZE 16 +/* Binary logarithm of the cache line size */ +#define LG_CACHE_LINE_SIZE 4 + +#ifndef __ASSEMBLY__ +extern void mmu_init(void); +extern void caches_init(void); +extern void flush_dcache_range(unsigned long start, unsigned long stop); +#endif + +#endif /* _TEST_BURST_H */ diff --git a/examples/standalone/test_burst_lib.S b/examples/standalone/test_burst_lib.S new file mode 100644 index 0000000..aef4e32 --- /dev/null +++ b/examples/standalone/test_burst_lib.S @@ -0,0 +1,170 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#include +#include +#include +#include +#include "test_burst.h" + + .text +/* + * void mmu_init(void); + * + * This function turns the MMU on + * + * Three 8 MByte regions are mapped 1:1, uncached + * - SDRAM lower 8 MByte + * - SDRAM higher 8 MByte + * - IMMR + */ + .global mmu_init +mmu_init: + tlbia /* Invalidate all TLB entries */ + li r8, 0 + mtspr MI_CTR, r8 /* Set instruction control to zero */ + lis r8, MD_RESETVAL@h + mtspr MD_CTR, r8 /* Set data TLB control */ + + /* Now map the lower 8 Meg into the TLBs. For this quick hack, + * we can load the instruction and data TLB registers with the + * same values. + */ + li r8, MI_EVALID /* Create EPN for address 0 */ + mtspr MI_EPN, r8 + mtspr MD_EPN, r8 + li r8, MI_PS8MEG /* Set 8M byte page */ + ori r8, r8, MI_SVALID /* Make it valid */ + mtspr MI_TWC, r8 + mtspr MD_TWC, r8 + li r8, MI_BOOTINIT|0x2 /* Create RPN for address 0 */ + mtspr MI_RPN, r8 /* Store TLB entry */ + mtspr MD_RPN, r8 + lis r8, MI_Kp@h /* Set the protection mode */ + mtspr MI_AP, r8 + mtspr MD_AP, r8 + + /* Now map the higher 8 Meg into the TLBs. For this quick hack, + * we can load the instruction and data TLB registers with the + * same values. + */ + lwz r9,20(r2) /* gd->ram_size */ + addis r9,r9,-0x80 + + mr r8, r9 /* Higher 8 Meg in SDRAM */ + ori r8, r8, MI_EVALID /* Mark page valid */ + mtspr MI_EPN, r8 + mtspr MD_EPN, r8 + li r8, MI_PS8MEG /* Set 8M byte page */ + ori r8, r8, MI_SVALID /* Make it valid */ + mtspr MI_TWC, r8 + mtspr MD_TWC, r8 + mr r8, r9 + ori r8, r8, MI_BOOTINIT|0x2 + mtspr MI_RPN, r8 /* Store TLB entry */ + mtspr MD_RPN, r8 + lis r8, MI_Kp@h /* Set the protection mode */ + mtspr MI_AP, r8 + mtspr MD_AP, r8 + + /* Map another 8 MByte at the IMMR to get the processor + * internal registers (among other things). + */ + mfspr r9, 638 /* Get current IMMR */ + andis. r9, r9, 0xff80 /* Get 8Mbyte boundary */ + + mr r8, r9 /* Create vaddr for TLB */ + ori r8, r8, MD_EVALID /* Mark it valid */ + mtspr MD_EPN, r8 + li r8, MD_PS8MEG /* Set 8M byte page */ + ori r8, r8, MD_SVALID /* Make it valid */ + mtspr MD_TWC, r8 + mr r8, r9 /* Create paddr for TLB */ + ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ + mtspr MD_RPN, r8 + + /* We now have the lower and higher 8 Meg mapped into TLB entries, + * and the caches ready to work. + */ + mfmsr r0 + ori r0,r0,MSR_DR|MSR_IR + mtspr SRR1,r0 + mflr r0 + mtspr SRR0,r0 + SYNC + rfi /* enables MMU */ + +/* + * void caches_init(void); + */ + .globl caches_init +caches_init: + sync + + mfspr r3, IC_CST /* Clear error bits */ + mfspr r3, DC_CST + + lis r3, IDC_UNALL@h /* Unlock all */ + mtspr IC_CST, r3 + mtspr DC_CST, r3 + + lis r3, IDC_INVALL@h /* Invalidate all */ + mtspr IC_CST, r3 + mtspr DC_CST, r3 + + lis r3, IDC_ENABLE@h /* Enable all */ + mtspr IC_CST, r3 + mtspr DC_CST, r3 + + blr + +/* + * void flush_dcache_range(unsigned long start, unsigned long stop); + */ + .global flush_dcache_range +flush_dcache_range: + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + +1: dcbf 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbf's to get to ram */ + blr + +/* + * void disable_interrupts(void); + */ + .global disable_interrupts +disable_interrupts: + mfmsr r0 + rlwinm r0,r0,0,17,15 + mtmsr r0 + blr diff --git a/examples/standalone/timer.c b/examples/standalone/timer.c new file mode 100644 index 0000000..8fd38b2 --- /dev/null +++ b/examples/standalone/timer.c @@ -0,0 +1,349 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +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 const char usage[] = "\n[q, b, e, ?] "; + +int timer (int argc, char * const 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); + + puts(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"); + } + puts(usage); + } + if (running) { + printf ("Stopping timer\n"); + *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); + free_hdlr (hwp->cpm_vec); + } + + return (0); +} + + +/* Set period in microseconds and start. + * Truncate to maximum period if more than this is requested - but warn about it. + */ + +void setPeriod (tid_8xx_cpmtimer_t *hwp, ulong interval) +{ + unsigned short prescaler; + unsigned long ticks; + + printf ("Set interval %ld us\n", interval); + + /* Warn if requesting longer period than possible */ + if (interval > CPMT_MAX_INTERVAL) { + printf ("Truncate interval %ld to maximum (%d)\n", + interval, CPMT_MAX_INTERVAL); + interval = CPMT_MAX_INTERVAL; + } + /* + * Check if we want to use clock divider: + * Since the reference counter can be incremented only in integer steps, + * we try to keep it as big as possible to allow the resulting period to be + * as precise as possible. + */ + /* prescaler, enable interrupt, restart after ref count is reached */ + prescaler = (ushort) ((CPMT_PRESCALER - 1) << 8) | + CPMT_MR_ORI | + CPMT_MR_FRR; + + ticks = ((ulong) CLOCKRATE * interval); + + if (ticks > CPMT_MAX_TICKS) { + ticks /= CPMT_CLOCK_DIV; + prescaler |= CPMT_MR_ICLK_CLKDIV; /* use system clock divided by 16 */ + } else { + prescaler |= CPMT_MR_ICLK_CLK; /* use system clock without divider */ + } + +#ifdef DEBUG + printf ("clock/%d, prescale factor %d, reference %ld, ticks %ld\n", + (ticks > CPMT_MAX_TICKS) ? CPMT_CLOCK_DIV : 1, + CPMT_PRESCALER, + (ticks / CPMT_PRESCALER), + ticks + ); +#endif + + /* set prescaler register */ + *hwp->tmrp = prescaler; + + /* clear timer counter */ + *hwp->tcnp = 0; + + /* set reference register */ + *hwp->trrp = (unsigned short) (ticks / CPMT_PRESCALER); + +#ifdef DEBUG + printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x," + " tcr=0x%x, tcn=0x%x, ter=0x%x\n", + *hwp->tgcrp, *hwp->tmrp, *hwp->trrp, + *hwp->tcrp, *hwp->tcnp, *hwp->terp + ); +#endif +} + +/* + * Handler for CPMVEC_TIMER1 interrupt + */ +static +void timer_handler (void *arg) +{ + tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)arg; + + /* printf ("** TER1=%04x ** ", *hwp->terp); */ + + /* just for demonstration */ + printf ("."); + + /* clear all possible events: Ref. and Cap. */ + *hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF); +} diff --git a/examples/standalone/x86-testapp.c b/examples/standalone/x86-testapp.c new file mode 100644 index 0000000..1e16ec7 --- /dev/null +++ b/examples/standalone/x86-testapp.c @@ -0,0 +1,100 @@ +#include +#include +#include + +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"); +#elif defined(__nds32__) +#define EXPORT_FUNC(x) \ +asm volatile ( \ +" .globl mon_" #x "\n" \ +"mon_" #x ":\n" \ +" lwi $r16, [$gp + (%0)]\n" \ +" lwi $r16, [$r16 + (%1)]\n" \ +" jr $r16\n" \ +: : "i"(offsetof(xxx_t, pfunc)), \ +"i"(XF_ ## x * sizeof(void *)) : "$r16"); + +#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"); +#elif defined(__nds32__) + register volatile xxx_t *pq asm("$r16"); +#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; +} -- cgit v1.1