diff options
Diffstat (limited to 'arch/nios')
33 files changed, 3403 insertions, 0 deletions
diff --git a/arch/nios/config.mk b/arch/nios/config.mk new file mode 100644 index 0000000..e1b9f07 --- /dev/null +++ b/arch/nios/config.mk @@ -0,0 +1,29 @@ +# +# (C) Copyright 2003 +# Psyent Corporation <www.psyent.com> +# Scott McNutt <smcnutt@psyent.com> +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +CROSS_COMPILE ?= nios-elf- + +STANDALONE_LOAD_ADDR = 0x00800000 -L $(gcclibdir)/m32 + +PLATFORM_CPPFLAGS += -m32 -DCONFIG_NIOS -D__NIOS__ -ffixed-g7 -gstabs diff --git a/arch/nios/cpu/Makefile b/arch/nios/cpu/Makefile new file mode 100644 index 0000000..ad17456 --- /dev/null +++ b/arch/nios/cpu/Makefile @@ -0,0 +1,48 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o +SOBJS = traps.o +COBJS = cpu.o interrupts.o serial.o asmi.o spi.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/nios/cpu/asmi.c b/arch/nios/cpu/asmi.c new file mode 100644 index 0000000..33553b7 --- /dev/null +++ b/arch/nios/cpu/asmi.c @@ -0,0 +1,695 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#if defined(CONFIG_NIOS_ASMI) +#include <command.h> +#include <nios-io.h> + +#if !defined(CONFIG_SYS_NIOS_ASMIBASE) +#error "*** CONFIG_SYS_NIOS_ASMIBASE not defined ***" +#endif + +/*-----------------------------------------------------------------------*/ +#define SHORT_HELP\ + "asmi - read/write Cyclone ASMI configuration device.\n" + +#define LONG_HELP\ + "\n"\ + "asmi erase start [end]\n"\ + " - erase sector start or sectors start through end.\n"\ + "asmi info\n"\ + " - display ASMI device information.\n"\ + "asmi protect on | off\n"\ + " - turn device protection on or off.\n"\ + "asmi read addr offset count\n"\ + " - read count bytes from offset to addr.\n"\ + "asmi write addr offset count\n"\ + " - write count bytes to offset from addr.\n"\ + "asmi verify addr offset count\n"\ + " - verify count bytes at offset from addr." + + +/*-----------------------------------------------------------------------*/ +/* Operation codes for serial configuration devices + */ +#define ASMI_WRITE_ENA 0x06 /* Write enable */ +#define ASMI_WRITE_DIS 0x04 /* Write disable */ +#define ASMI_READ_STAT 0x05 /* Read status */ +#define ASMI_READ_BYTES 0x03 /* Read bytes */ +#define ASMI_READ_ID 0xab /* Read silicon id */ +#define ASMI_WRITE_STAT 0x01 /* Write status */ +#define ASMI_WRITE_BYTES 0x02 /* Write bytes */ +#define ASMI_ERASE_BULK 0xc7 /* Erase entire device */ +#define ASMI_ERASE_SECT 0xd8 /* Erase sector */ + +/* Device status register bits + */ +#define ASMI_STATUS_WIP (1<<0) /* Write in progress */ +#define ASMI_STATUS_WEL (1<<1) /* Write enable latch */ + +static nios_asmi_t *asmi = (nios_asmi_t *)CONFIG_SYS_NIOS_ASMIBASE; + +/*********************************************************************** + * Device access + ***********************************************************************/ +static void asmi_cs (int assert) +{ + if (assert) { + asmi->control |= NIOS_ASMI_SSO; + } else { + /* Let all bits shift out */ + while ((asmi->status & NIOS_ASMI_TMT) == 0) + ; + asmi->control &= ~NIOS_ASMI_SSO; + } +} + +static void asmi_tx (unsigned char c) +{ + while ((asmi->status & NIOS_ASMI_TRDY) == 0) + ; + asmi->txdata = c; +} + +static int asmi_rx (void) +{ + while ((asmi->status & NIOS_ASMI_RRDY) == 0) + ; + return (asmi->rxdata); +} + +static unsigned char bitrev[] = { + 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, + 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f +}; + +static unsigned char asmi_bitrev( unsigned char c ) +{ + unsigned char val; + + val = bitrev[c>>4]; + val |= bitrev[c & 0x0f]<<4; + return (val); +} + +static void asmi_rcv (unsigned char *dst, int len) +{ + while (len--) { + asmi_tx (0); + *dst++ = asmi_rx (); + } +} + +static void asmi_rrcv (unsigned char *dst, int len) +{ + while (len--) { + asmi_tx (0); + *dst++ = asmi_bitrev (asmi_rx ()); + } +} + +static void asmi_snd (unsigned char *src, int len) +{ + while (len--) { + asmi_tx (*src++); + asmi_rx (); + } +} + +static void asmi_rsnd (unsigned char *src, int len) +{ + while (len--) { + asmi_tx (asmi_bitrev (*src++)); + asmi_rx (); + } +} + +static void asmi_wr_enable (void) +{ + asmi_cs (1); + asmi_tx (ASMI_WRITE_ENA); + asmi_rx (); + asmi_cs (0); +} + +static unsigned char asmi_status_rd (void) +{ + unsigned char status; + + asmi_cs (1); + asmi_tx (ASMI_READ_STAT); + asmi_rx (); + asmi_tx (0); + status = asmi_rx (); + asmi_cs (0); + return (status); +} + +static void asmi_status_wr (unsigned char status) +{ + asmi_wr_enable (); + asmi_cs (1); + asmi_tx (ASMI_WRITE_STAT); + asmi_rx (); + asmi_tx (status); + asmi_rx (); + asmi_cs (0); + return; +} + +/*********************************************************************** + * Device information + ***********************************************************************/ +typedef struct asmi_devinfo_t { + const char *name; /* Device name */ + unsigned char id; /* Device silicon id */ + unsigned char size; /* Total size log2(bytes)*/ + unsigned char num_sects; /* Number of sectors */ + unsigned char sz_sect; /* Sector size log2(bytes) */ + unsigned char sz_page; /* Page size log2(bytes) */ + unsigned char prot_mask; /* Protection mask */ +}asmi_devinfo_t; + +static struct asmi_devinfo_t devinfo[] = { + { "EPCS1 ", 0x10, 17, 4, 15, 8, 0x0c }, + { "EPCS4 ", 0x12, 19, 8, 16, 8, 0x1c }, + { 0, 0, 0, 0, 0, 0 } +}; + +static asmi_devinfo_t *asmi_dev_find (void) +{ + unsigned char buf[4]; + unsigned char id; + int i; + struct asmi_devinfo_t *dev = NULL; + + /* Read silicon id requires 3 "dummy bytes" before it's put + * on the wire. + */ + buf[0] = ASMI_READ_ID; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + asmi_cs (1); + asmi_snd (buf,4); + asmi_rcv (buf,1); + asmi_cs (0); + id = buf[0]; + + /* Find the info struct */ + i = 0; + while (devinfo[i].name) { + if (id == devinfo[i].id) { + dev = &devinfo[i]; + break; + } + i++; + } + + return (dev); +} + +/*********************************************************************** + * Misc Utilities + ***********************************************************************/ +static unsigned asmi_cfgsz (void) +{ + unsigned sz = 0; + unsigned char buf[128]; + unsigned char *p; + + /* Read in the first 128 bytes of the device */ + buf[0] = ASMI_READ_BYTES; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + asmi_cs (1); + asmi_snd (buf,4); + asmi_rrcv (buf, sizeof(buf)); + asmi_cs (0); + + /* Search for the starting 0x6a which is followed by the + * 4-byte 'register' and 4-byte bit-count. + */ + p = buf; + while (p < buf + sizeof(buf)-8) { + if ( *p == 0x6a ) { + /* Point to bit count and extract */ + p += 5; + sz = *p++; + sz |= *p++ << 8; + sz |= *p++ << 16; + sz |= *p++ << 24; + /* Convert to byte count */ + sz += 7; + sz >>= 3; + } else if (*p == 0xff) { + /* 0xff is ok ... just skip */ + p++; + continue; + } else { + /* Not 0xff or 0x6a ... something's not + * right ... report 'unknown' (sz=0). + */ + break; + } + } + return (sz); +} + +static int asmi_erase (unsigned start, unsigned end) +{ + unsigned off, sectsz; + unsigned char buf[4]; + struct asmi_devinfo_t *dev = asmi_dev_find (); + + if (!dev || (start>end)) + return (-1); + + /* Erase the requested sectors. An address is required + * that lies within the requested sector -- we'll just + * use the first address in the sector. + */ + printf ("asmi erasing sector %d ", start); + if (start != end) + printf ("to %d ", end); + sectsz = (1 << dev->sz_sect); + while (start <= end) { + off = start * sectsz; + start++; + + buf[0] = ASMI_ERASE_SECT; + buf[1] = off >> 16; + buf[2] = off >> 8; + buf[3] = off; + + asmi_wr_enable (); + asmi_cs (1); + asmi_snd (buf,4); + asmi_cs (0); + + printf ("."); /* Some user feedback */ + + /* Wait for erase to complete */ + while (asmi_status_rd() & ASMI_STATUS_WIP) + ; + } + printf (" done.\n"); + return (0); +} + +static int asmi_read (ulong addr, ulong off, ulong cnt) +{ + unsigned char buf[4]; + + buf[0] = ASMI_READ_BYTES; + buf[1] = off >> 16; + buf[2] = off >> 8; + buf[3] = off; + + asmi_cs (1); + asmi_snd (buf,4); + asmi_rrcv ((unsigned char *)addr, cnt); + asmi_cs (0); + + return (0); +} + +static +int asmi_write (ulong addr, ulong off, ulong cnt) +{ + ulong wrcnt; + unsigned pgsz; + unsigned char buf[4]; + struct asmi_devinfo_t *dev = asmi_dev_find (); + + if (!dev) + return (-1); + + pgsz = (1<<dev->sz_page); + while (cnt) { + if (off % pgsz) + wrcnt = pgsz - (off % pgsz); + else + wrcnt = pgsz; + wrcnt = (wrcnt > cnt) ? cnt : wrcnt; + + buf[0] = ASMI_WRITE_BYTES; + buf[1] = off >> 16; + buf[2] = off >> 8; + buf[3] = off; + + asmi_wr_enable (); + asmi_cs (1); + asmi_snd (buf,4); + asmi_rsnd ((unsigned char *)addr, wrcnt); + asmi_cs (0); + + /* Wait for write to complete */ + while (asmi_status_rd() & ASMI_STATUS_WIP) + ; + + cnt -= wrcnt; + off += wrcnt; + addr += wrcnt; + } + + return (0); +} + +static +int asmi_verify (ulong addr, ulong off, ulong cnt, ulong *err) +{ + ulong rdcnt; + unsigned char buf[256]; + unsigned char *start,*end; + int i; + + start = end = (unsigned char *)addr; + while (cnt) { + rdcnt = (cnt>sizeof(buf)) ? sizeof(buf) : cnt; + asmi_read ((ulong)buf, off, rdcnt); + for (i=0; i<rdcnt; i++) { + if (*end != buf[i]) { + *err = end - start; + return(-1); + } + end++; + } + cnt -= rdcnt; + off += rdcnt; + } + return (0); +} + +static int asmi_sect_erased (int sect, unsigned *offset, + struct asmi_devinfo_t *dev) +{ + unsigned char buf[128]; + unsigned off, end; + unsigned sectsz; + int i; + + sectsz = (1 << dev->sz_sect); + off = sectsz * sect; + end = off + sectsz; + + while (off < end) { + asmi_read ((ulong)buf, off, sizeof(buf)); + for (i=0; i < sizeof(buf); i++) { + if (buf[i] != 0xff) { + *offset = off + i; + return (0); + } + } + off += sizeof(buf); + } + return (1); +} + + +/*********************************************************************** + * Commands + ***********************************************************************/ +static +void do_asmi_info (struct asmi_devinfo_t *dev, int argc, char *argv[]) +{ + int i; + unsigned char stat; + unsigned tmp; + int erased; + + /* Basic device info */ + printf ("%s: %d kbytes (%d sectors x %d kbytes," + " %d bytes/page)\n", + dev->name, 1 << (dev->size-10), + dev->num_sects, 1 << (dev->sz_sect-10), + 1 << dev->sz_page ); + + /* Status -- for now protection is all-or-nothing */ + stat = asmi_status_rd(); + printf ("status: 0x%02x (WIP:%d, WEL:%d, PROT:%s)\n", + stat, + (stat & ASMI_STATUS_WIP) ? 1 : 0, + (stat & ASMI_STATUS_WEL) ? 1 : 0, + (stat & dev->prot_mask) ? "on" : "off" ); + + /* Configuration */ + tmp = asmi_cfgsz (); + if (tmp) { + printf ("config: 0x%06x (%d) bytes\n", tmp, tmp ); + } else { + printf ("config: unknown\n" ); + } + + /* Sector info */ + for (i=0; i<dev->num_sects; i++) { + erased = asmi_sect_erased (i, &tmp, dev); + printf (" %d: %06x ", + i, i*(1<<dev->sz_sect) ); + if (erased) + printf ("erased\n"); + else + printf ("data @ 0x%06x\n", tmp); + } + + return; +} + +static +void do_asmi_erase (struct asmi_devinfo_t *dev, int argc, char *argv[]) +{ + unsigned start,end; + + if ((argc < 3) || (argc > 4)) { + printf ("USAGE: asmi erase sect [end]\n"); + return; + } + if ((asmi_status_rd() & dev->prot_mask) != 0) { + printf ( "asmi: device protected.\n"); + return; + } + + start = simple_strtoul (argv[2], NULL, 10); + if (argc > 3) + end = simple_strtoul (argv[3], NULL, 10); + else + end = start; + if ((start >= dev->num_sects) || (start > end)) { + printf ("asmi: invalid sector range: [%d:%d]\n", + start, end ); + return; + } + + asmi_erase (start, end); + + return; +} + +static +void do_asmi_protect (struct asmi_devinfo_t *dev, int argc, char *argv[]) +{ + unsigned char stat; + + /* For now protection is all-or-nothing to keep things + * simple. The protection bits don't map in a linear + * fashion ... and we would rather protect the bottom + * of the device since it contains the config data and + * leave the top unprotected for app use. But unfortunately + * protection works from top-to-bottom so it does + * really help very much from a software app point-of-view. + */ + if (argc < 3) { + printf ("USAGE: asmi protect on | off\n"); + return; + } + if (!dev) + return; + + /* Protection on/off is just a matter of setting/clearing + * all protection bits in the status register. + */ + stat = asmi_status_rd (); + if (strcmp ("on", argv[2]) == 0) { + stat |= dev->prot_mask; + } else if (strcmp ("off", argv[2]) == 0 ) { + stat &= ~dev->prot_mask; + } else { + printf ("asmi: unknown protection: %s\n", argv[2]); + return; + } + asmi_status_wr (stat); + return; +} + +static +void do_asmi_read (struct asmi_devinfo_t *dev, int argc, char *argv[]) +{ + ulong addr,off,cnt; + ulong sz; + + if (argc < 5) { + printf ("USAGE: asmi read addr offset count\n"); + return; + } + + sz = 1 << dev->size; + addr = simple_strtoul (argv[2], NULL, 16); + off = simple_strtoul (argv[3], NULL, 16); + cnt = simple_strtoul (argv[4], NULL, 16); + if (off > sz) { + printf ("offset is greater than device size" + "... aborting.\n"); + return; + } + if ((off + cnt) > sz) { + printf ("request exceeds device size" + "... truncating.\n"); + cnt = sz - off; + } + printf ("asmi: read %08lx <- %06lx (0x%lx bytes)\n", + addr, off, cnt); + asmi_read (addr, off, cnt); + + return; +} + +static +void do_asmi_write (struct asmi_devinfo_t *dev, int argc, char *argv[]) +{ + ulong addr,off,cnt; + ulong sz; + ulong err; + + if (argc < 5) { + printf ("USAGE: asmi write addr offset count\n"); + return; + } + if ((asmi_status_rd() & dev->prot_mask) != 0) { + printf ( "asmi: device protected.\n"); + return; + } + + sz = 1 << dev->size; + addr = simple_strtoul (argv[2], NULL, 16); + off = simple_strtoul (argv[3], NULL, 16); + cnt = simple_strtoul (argv[4], NULL, 16); + if (off > sz) { + printf ("offset is greater than device size" + "... aborting.\n"); + return; + } + if ((off + cnt) > sz) { + printf ("request exceeds device size" + "... truncating.\n"); + cnt = sz - off; + } + printf ("asmi: write %08lx -> %06lx (0x%lx bytes)\n", + addr, off, cnt); + asmi_write (addr, off, cnt); + if (asmi_verify (addr, off, cnt, &err) != 0) + printf ("asmi: write error at offset %06lx\n", err); + + return; +} + +static +void do_asmi_verify (struct asmi_devinfo_t *dev, int argc, char *argv[]) +{ + ulong addr,off,cnt; + ulong sz; + ulong err; + + if (argc < 5) { + printf ("USAGE: asmi verify addr offset count\n"); + return; + } + + sz = 1 << dev->size; + addr = simple_strtoul (argv[2], NULL, 16); + off = simple_strtoul (argv[3], NULL, 16); + cnt = simple_strtoul (argv[4], NULL, 16); + if (off > sz) { + printf ("offset is greater than device size" + "... aborting.\n"); + return; + } + if ((off + cnt) > sz) { + printf ("request exceeds device size" + "... truncating.\n"); + cnt = sz - off; + } + printf ("asmi: verify %08lx -> %06lx (0x%lx bytes)\n", + addr, off, cnt); + if (asmi_verify (addr, off, cnt, &err) != 0) + printf ("asmi: verify error at offset %06lx\n", err); + + return; +} + +/*-----------------------------------------------------------------------*/ +int do_asmi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int len; + struct asmi_devinfo_t *dev = asmi_dev_find (); + + if (argc < 2) { + printf ("Usage:%s", LONG_HELP); + return (0); + } + + if (!dev) { + printf ("asmi: device not found.\n"); + return (0); + } + + len = strlen (argv[1]); + if (strncmp ("info", argv[1], len) == 0) { + do_asmi_info ( dev, argc, argv); + } else if (strncmp ("erase", argv[1], len) == 0) { + do_asmi_erase (dev, argc, argv); + } else if (strncmp ("protect", argv[1], len) == 0) { + do_asmi_protect (dev, argc, argv); + } else if (strncmp ("read", argv[1], len) == 0) { + do_asmi_read (dev, argc, argv); + } else if (strncmp ("write", argv[1], len) == 0) { + do_asmi_write (dev, argc, argv); + } else if (strncmp ("verify", argv[1], len) == 0) { + do_asmi_verify (dev, argc, argv); + } else { + printf ("asmi: unknown operation: %s\n", argv[1]); + } + + return (0); +} + +/*-----------------------------------------------------------------------*/ + + +U_BOOT_CMD( asmi, 5, 0, do_asmi, SHORT_HELP, LONG_HELP ); + +#endif /* CONFIG_NIOS_ASMI */ diff --git a/arch/nios/cpu/config.mk b/arch/nios/cpu/config.mk new file mode 100644 index 0000000..f228d72 --- /dev/null +++ b/arch/nios/cpu/config.mk @@ -0,0 +1,24 @@ +# +# (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 +# + +PLATFORM_RELFLAGS += diff --git a/arch/nios/cpu/cpu.c b/arch/nios/cpu/cpu.c new file mode 100644 index 0000000..5519e82 --- /dev/null +++ b/arch/nios/cpu/cpu.c @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <nios.h> + + +int checkcpu (void) +{ + unsigned val; + unsigned rev_major; + unsigned rev_minor; + short nregs, hi_limit, lo_limit; + + /* Get cpu version info */ + val = rdctl (CTL_CPU_ID); + puts ("CPU: "); + printf ("%s", (val & 0x00008000) ? "Nios-16 " : "Nios-32 "); + rev_major = (val>>12) & 0x07; + rev_minor = (val>>4) & 0x0ff; + printf ("Rev. %d.%d (0x%04x)", rev_major, rev_minor, + val & 0xffff); + if (rev_major == 0x08) + printf (" [OpenCore (R) Plus]"); + printf ("\n"); + + /* Check register file */ + val = rdctl (CTL_WVALID); + lo_limit = val & 0x01f; + hi_limit = (val>>5) & 0x1f; + nregs = (hi_limit + 2) * 16; + printf ("Reg file size: %d LO_LIMIT/HI_LIMIT: %d/%d\n", + nregs, lo_limit, hi_limit); + + return (0); +} + + +int do_reset (void) +{ + /* trap 0 does the trick ... at least with the OCI debug + * present -- haven't tested without it yet (stm). + */ + disable_interrupts (); + ipri (1); + asm volatile ("trap 0\n"); + + /* No return ;-) */ + + return(0); +} + + +#if defined(CONFIG_WATCHDOG) +void watchdog_reset (void) +{ +} +#endif /* CONFIG_WATCHDOG */ diff --git a/arch/nios/cpu/interrupts.c b/arch/nios/cpu/interrupts.c new file mode 100644 index 0000000..55a5718 --- /dev/null +++ b/arch/nios/cpu/interrupts.c @@ -0,0 +1,196 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <nios.h> +#include <nios-io.h> +#include <asm/ptrace.h> +#include <common.h> +#include <command.h> +#include <watchdog.h> +#ifdef CONFIG_STATUS_LED +#include <status_led.h> +#endif + +/****************************************************************************/ + +struct irq_action { + interrupt_handler_t *handler; + void *arg; + int count; +}; + +static struct irq_action irq_vecs[64]; + +/*************************************************************************/ +volatile ulong timestamp = 0; + +void reset_timer (void) +{ + timestamp = 0; +} + +ulong get_timer (ulong base) +{ + WATCHDOG_RESET (); + return (timestamp - base); +} + +void set_timer (ulong t) +{ + timestamp = t; +} + + +/* The board must handle this interrupt if a timer is not + * provided. + */ +#if defined(CONFIG_SYS_NIOS_TMRBASE) +void timer_interrupt (struct pt_regs *regs) +{ + /* Interrupt is cleared by writing anything to the + * status register. + */ + nios_timer_t *tmr = (nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE; + tmr->status = 0; + timestamp += CONFIG_SYS_NIOS_TMRMS; +#ifdef CONFIG_STATUS_LED + status_led_tick(timestamp); +#endif +} +#endif + +/*************************************************************************/ +int disable_interrupts (void) +{ + int val = 0; + + /* Writing anything to CLR_IE disables interrupts */ + val = rdctl (CTL_STATUS); + wrctl (CTL_CLR_IE, 0); + return (val & STATUS_IE); +} + +void enable_interrupts( void ) +{ + /* Writing anything SET_IE enables interrupts */ + wrctl (CTL_SET_IE, 0); +} + +void external_interrupt (struct pt_regs *regs) +{ + unsigned vec; + + vec = (regs->status & STATUS_IPRI) >> 9; /* ipri */ + + irq_vecs[vec].count++; + if (irq_vecs[vec].handler != NULL) { + (*irq_vecs[vec].handler)(irq_vecs[vec].arg); + } else { + /* A sad side-effect of masking a bogus interrupt is + * that lower priority interrupts will also be disabled. + * This is probably not what we want ... so hang insted. + */ + printf ("Unhandled interrupt: 0x%x\n", vec); + disable_interrupts (); + hang (); + } +} + +/*************************************************************************/ +int interrupt_init (void) +{ + int vec; + +#if defined(CONFIG_SYS_NIOS_TMRBASE) + nios_timer_t *tmr = (nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE; + + tmr->control &= ~NIOS_TIMER_ITO; + tmr->control |= NIOS_TIMER_STOP; +#if defined(CONFIG_SYS_NIOS_TMRCNT) + tmr->periodl = CONFIG_SYS_NIOS_TMRCNT & 0xffff; + tmr->periodh = (CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff; +#endif +#endif + + for (vec=0; vec<64; vec++ ) { + irq_vecs[vec].handler = NULL; + irq_vecs[vec].arg = NULL; + irq_vecs[vec].count = 0; + } + + /* Need timus interruptus -- start the lopri timer */ +#if defined(CONFIG_SYS_NIOS_TMRBASE) + tmr->control |= ( NIOS_TIMER_ITO | + NIOS_TIMER_CONT | + NIOS_TIMER_START ); + ipri (CONFIG_SYS_NIOS_TMRIRQ + 1); +#endif + enable_interrupts (); + return (0); +} + +void irq_install_handler (int vec, interrupt_handler_t *handler, void *arg) +{ + struct irq_action *irqa = irq_vecs; + int i = vec; + int flag; + + if (irqa[i].handler != NULL) { + printf ("Interrupt vector %d: handler 0x%x " + "replacing 0x%x\n", + vec, (uint)handler, (uint)irqa[i].handler); + } + + flag = disable_interrupts (); + irqa[i].handler = handler; + irqa[i].arg = arg; + if (flag ) + enable_interrupts (); +} + +/*************************************************************************/ +#if defined(CONFIG_CMD_IRQ) +int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int vec; + + printf ("\nInterrupt-Information:\n"); + printf ("Nr Routine Arg Count\n"); + + for (vec=0; vec<64; vec++) { + if (irq_vecs[vec].handler != NULL) { + printf ("%02d %08lx %08lx %d\n", + vec, + (ulong)irq_vecs[vec].handler<<1, + (ulong)irq_vecs[vec].arg, + irq_vecs[vec].count); + } + } + + return (0); +} +#endif diff --git a/arch/nios/cpu/serial.c b/arch/nios/cpu/serial.c new file mode 100644 index 0000000..44aa600 --- /dev/null +++ b/arch/nios/cpu/serial.c @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <watchdog.h> +#include <nios-io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/*------------------------------------------------------------------ + * JTAG acts as the serial port + *-----------------------------------------------------------------*/ +#if defined(CONFIG_CONSOLE_JTAG) + +static nios_jtag_t *jtag = (nios_jtag_t *)CONFIG_SYS_NIOS_CONSOLE; + +void serial_setbrg( void ){ return; } +int serial_init( void ) { return(0);} + +void serial_putc (char c) +{ + while ((jtag->txcntl & NIOS_JTAG_TRDY) != 0) + WATCHDOG_RESET (); + jtag->txcntl = NIOS_JTAG_TRDY | (unsigned char)c; +} + +void serial_puts (const char *s) +{ + while (*s != 0) + serial_putc (*s++); +} + +int serial_tstc (void) +{ + return (jtag->rxcntl & NIOS_JTAG_RRDY); +} + +int serial_getc (void) +{ + int c; + while (serial_tstc() == 0) + WATCHDOG_RESET (); + c = jtag->rxcntl & 0x0ff; + jtag->rxcntl = 0; + return (c); +} + +/*------------------------------------------------------------------ + * UART the serial port + *-----------------------------------------------------------------*/ +#else + +static nios_uart_t *uart = (nios_uart_t *)CONFIG_SYS_NIOS_CONSOLE; + +#if defined(CONFIG_SYS_NIOS_FIXEDBAUD) + +/* Everything's already setup for fixed-baud PTF + * assignment + */ +void serial_setbrg (void){ return; } +int serial_init (void) { return (0);} + +#else + +void serial_setbrg (void) +{ + unsigned div; + + div = (CONFIG_SYS_CLK_FREQ/gd->baudrate)-1; + uart->divisor = div; + return; +} + +int serial_init (void) +{ + serial_setbrg (); + return (0); +} + +#endif /* CONFIG_SYS_NIOS_FIXEDBAUD */ + + +/*----------------------------------------------------------------------- + * UART CONSOLE + *---------------------------------------------------------------------*/ +void serial_putc (char c) +{ + if (c == '\n') + serial_putc ('\r'); + while ((uart->status & NIOS_UART_TRDY) == 0) + WATCHDOG_RESET (); + uart->txdata = (unsigned char)c; +} + +void serial_puts (const char *s) +{ + while (*s != 0) { + serial_putc (*s++); + } +} + +int serial_tstc (void) +{ + return (uart->status & NIOS_UART_RRDY); +} + +int serial_getc (void) +{ + while (serial_tstc () == 0) + WATCHDOG_RESET (); + return( uart->rxdata & 0x00ff ); +} + +#endif /* CONFIG_JTAG_CONSOLE */ diff --git a/arch/nios/cpu/spi.c b/arch/nios/cpu/spi.c new file mode 100644 index 0000000..89f9797 --- /dev/null +++ b/arch/nios/cpu/spi.c @@ -0,0 +1,195 @@ +/* + * (C) Copyright 2004, Li-Pro.Net <www.li-pro.net> + * Stephan Linz <linz@li-pro.net> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/ctype.h> + +#if defined(CONFIG_NIOS_SPI) +#include <nios-io.h> +#include <spi.h> + +#if !defined(CONFIG_SYS_NIOS_SPIBASE) +#error "*** CONFIG_SYS_NIOS_SPIBASE not defined ***" +#endif + +#if !defined(CONFIG_SYS_NIOS_SPIBITS) +#error "*** CONFIG_SYS_NIOS_SPIBITS not defined ***" +#endif + +#if (CONFIG_SYS_NIOS_SPIBITS != 8) && (CONFIG_SYS_NIOS_SPIBITS != 16) +#error "*** CONFIG_SYS_NIOS_SPIBITS should be either 8 or 16 ***" +#endif + +static nios_spi_t *spi = (nios_spi_t *)CONFIG_SYS_NIOS_SPIBASE; + +/* Warning: + * You cannot enable DEBUG for early system initalization, i. e. when + * this driver is used to read environment parameters like "baudrate" + * from EEPROM which are used to initialize the serial port which is + * needed to print the debug messages... + */ +#undef DEBUG + +#ifdef DEBUG + +#define DPRINT(a) printf a; +/* ----------------------------------------------- + * Helper functions to peek into tx and rx buffers + * ----------------------------------------------- */ +static const char * const hex_digit = "0123456789ABCDEF"; + +static char quickhex (int i) +{ + return hex_digit[i]; +} + +static void memdump (const void *pv, int num) +{ + int i; + const unsigned char *pc = (const unsigned char *) pv; + + for (i = 0; i < num; i++) + printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f)); + printf ("\t"); + for (i = 0; i < num; i++) + printf ("%c", isprint (pc[i]) ? pc[i] : '.'); + printf ("\n"); +} +#else /* !DEBUG */ + +#define DPRINT(a) +#define memdump(p,n) + +#endif /* DEBUG */ + + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct spi_slave *slave; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + slave = malloc(sizeof(struct spi_slave)); + if (!slave) + return NULL; + + slave->bus = bus; + slave->cs = cs; + + /* TODO: Add support for different modes and speeds */ + + return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + +/* + * SPI transfer: + * + * See include/spi.h and http://www.altera.com/literature/ds/ds_nios_spi.pdf + * for more informations. + */ +int spi_xfer(struct spi_slave *slave, int bitlen, const void *dout, + void *din, unsigned long flags) +{ + const u8 *txd = dout; + u8 *rxd = din; + int j; + + DPRINT(("spi_xfer: slave %u:%u dout %08X din %08X bitlen %d\n", + slave->bus, slave->cs, *(uint *)dout, *(uint *)din, bitlen)); + + memdump(dout, (bitlen + 7) / 8); + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + if (!(flags & SPI_XFER_END) || bitlen > CONFIG_SYS_NIOS_SPIBITS) { + /* leave chip select active */ + spi->control |= NIOS_SPI_SSO; + } + + for ( j = 0; /* count each byte in */ + j < ((bitlen + 7) / 8); /* dout[] and din[] */ + +#if (CONFIG_SYS_NIOS_SPIBITS == 8) + j++) { + + while ((spi->status & NIOS_SPI_TRDY) == 0) + ; + spi->txdata = (unsigned)(txd[j]); + + while ((spi->status & NIOS_SPI_RRDY) == 0) + ; + rxd[j] = (unsigned char)(spi->rxdata & 0xff); + +#elif (CONFIG_SYS_NIOS_SPIBITS == 16) + j++, j++) { + + while ((spi->status & NIOS_SPI_TRDY) == 0) + ; + if ((j+1) < ((bitlen + 7) / 8)) + spi->txdata = (unsigned)((txd[j] << 8) | txd[j+1]); + else + spi->txdata = (unsigned)(txd[j] << 8); + + while ((spi->status & NIOS_SPI_RRDY) == 0) + ; + rxd[j] = (unsigned char)((spi->rxdata >> 8) & 0xff); + if ((j+1) < ((bitlen + 7) / 8)) + rxd[j+1] = (unsigned char)(spi->rxdata & 0xff); + +#else +#error "*** unsupported value of CONFIG_SYS_NIOS_SPIBITS ***" +#endif + + } + + if (bitlen > CONFIG_SYS_NIOS_SPIBITS && (flags & SPI_XFER_END)) { + spi->control &= ~NIOS_SPI_SSO; + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + memdump(din, (bitlen + 7) / 8); + + return 0; +} + +#endif /* CONFIG_NIOS_SPI */ diff --git a/arch/nios/cpu/start.S b/arch/nios/cpu/start.S new file mode 100644 index 0000000..3578a04 --- /dev/null +++ b/arch/nios/cpu/start.S @@ -0,0 +1,238 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <config.h> +#include <timestamp.h> +#include <version.h> + +#if !defined(CONFIG_IDENT_STRING) +#define CONFIG_IDENT_STRING "" +#endif + +#define STATUS_INIT 0x8600 /* IE=1, IPRI=2 */ + +/************************************************************************* + * RESTART + ************************************************************************/ + + .text + .global _start + +_start: + bsr 0f + nop + .long _start + + /* GERMS -- The "standard-32" configuration GERMS monitor looks + * for the string "Nios" at flash_base + 0xc (actually it only + * tests for 'N', 'i'). You can leave support for this in place + * as it's only a few words. + */ + . = _start + 0x000c + .string "Nios" + + .align 4 +0: + /* + * Early setup -- set cwp = HI_LIMIT, IPRI = 2, IE = 1 to + * enable underflow exceptions. Disable cache. + * NOTE: %o7 has return addr -- save in %g7 use later. + */ + mov %g7, %o7 + + pfx 2 /* WVALID */ + rdctl %g0 + lsri %g0, 1 + pfx %hi(STATUS_INIT) + or %g0, %lo(STATUS_INIT) + wrctl %g0 /* update status */ + nop + + /* + * STACK + */ + pfx %hi(CONFIG_SYS_INIT_SP) + movi %sp, %lo(CONFIG_SYS_INIT_SP) + pfx %xhi(CONFIG_SYS_INIT_SP) + movhi %sp, %xlo(CONFIG_SYS_INIT_SP) + mov %fp, %sp + + pfx %hi(4*16) + subi %sp, %lo(4*16) /* Space for reg window mgmt */ + + /* + * RELOCATE -- %g7 has return addr from bsr at _start. + */ + pfx %hi(__u_boot_cmd_end) + movi %g5, %lo(__u_boot_cmd_end) + pfx %xhi(__u_boot_cmd_end) + movhi %g5, %xlo(__u_boot_cmd_end) /* %g5 <- end address */ + + lsli %g7, 1 /* mem = retaddr << 1 */ + mov %g6, %g7 + subi %g6, 4 /* %g6 <- src addr */ + ld %g7, [%g7] /* %g7 <- dst addr */ + + /* No need to move text sections if we're already located + * at the proper address. + */ + cmp %g7, %g6 + ifs cc_z + br reloc + nop /* delay slot */ + +1: cmp %g7, %g5 + skps cc_nz + br 2f + nop /* delay slot */ + + ld %g0, [%g6] + addi %g6, 4 /* src++ */ + st [%g7], %g0 + addi %g7, 4 /* dst++ */ + br 1b + nop /* delay slot */ +2: + + /* + * Jump to relocation address + */ + pfx %hi(reloc@h) + movi %g0, %lo(reloc@h) + pfx %xhi(reloc@h) + movhi %g0, %xlo(reloc@h) + jmp %g0 + nop /* delay slot */ +reloc: + + /* + * CLEAR BSS + */ + pfx %hi(__bss_end) + movi %g5, %lo(__bss_end) + pfx %xhi(__bss_end) + movhi %g5, %xlo(__bss_end) /* %g5 <- end address */ + pfx %hi(__bss_start) + movi %g7, %lo(__bss_start) + pfx %xhi(__bss_start) + movhi %g7, %xlo(__bss_start) /* %g7 <- end address */ + + movi %g0, 0 +3: cmp %g7, %g5 + skps cc_nz + br 4f + nop /* delay slot */ + + st [%g7], %g0 + addi %g7, 4 /* (delay slot) dst++ */ + br 3b + nop /* delay slot */ +4: + + /* + * INIT VECTOR TABLE + */ + pfx %hi(CONFIG_SYS_VECT_BASE) + movi %g0, %lo(CONFIG_SYS_VECT_BASE) + pfx %xhi(CONFIG_SYS_VECT_BASE) + movhi %g0, %xlo(CONFIG_SYS_VECT_BASE) /* dst */ + mov %l0, %g0 + + pfx %hi(_vectors) + movi %g1, %lo(_vectors) + pfx %xhi(_vectors) + movhi %g1, %xlo(_vectors) /* src */ + bgen %g2, 6 /* cnt = 64 */ + + ldp %g3, [%l0, 3] /* bkpt vector */ + ldp %g4, [%l0, 4] /* single step vector */ + +5: ld %g7, [%g1] + addi %g1, 4 /* src++ */ + st [%g0], %g7 + addi %g0, 4 /* dst++ */ + + subi %g2, 1 /* cnt-- */ + ifrnz %g2 + br 5b + nop /* delay slot */ + +#if defined(CONFIG_ROM_STUBS) + /* Restore the breakpoint and single step exception + * vectors to their original values. + */ + stp [%l0,3], %g3 /* breakpoint */ + stp [%l0,4], %g4 /* single step */ +#endif + + /* For debug startup convenience ... software breakpoints + * set prior to this point may not succeed ;-) + */ + .global __start +__start: + + /* + * Call board_init -- never returns + */ + pfx %hi(board_init@h) + movi %g1, %lo(board_init@h) + pfx %xhi(board_init@h) + movhi %g1, %xlo(board_init@h) + call %g1 + nop /* Delaly slot */ + /* NEVER RETURNS */ + +/* + * dly_clks -- Nios doesn't have a time/clk reference for simple + * delay loops, so we do our best by counting instruction cycles. + * A control register that counts system clock cycles would be + * a handy feature -- hint for Altera ;-) + */ + .globl dly_clks + /* Each loop is 4 instructions as delay slot is always + * executed. Each instruction is approximately 4 clocks + * (according to some lame info from Altera). So ... + * ... each loop is about 16 clocks. + */ + +dly_clks: + lsri %o0, 4 /* cnt/16 */ + +8: skprnz %o0 + br 9f + subi %o0, 1 /* cnt--, Delay slot */ + br 8b + nop + +9: lret + nop /* Delay slot */ + + + .data + .globl version_string + +version_string: + .ascii U_BOOT_VERSION + .ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")" + .ascii CONFIG_IDENT_STRING, "\0" diff --git a/arch/nios/cpu/traps.S b/arch/nios/cpu/traps.S new file mode 100644 index 0000000..bc4d3f6 --- /dev/null +++ b/arch/nios/cpu/traps.S @@ -0,0 +1,582 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> + +/************************************************************************* + * Register window underflow + * + * The register window underflow exception occurs whenever the lowest + * valid register window is in use (CWP=LO_LIMIT) and a save instruction + * is issued. The save moves CWP below LO_LIMIT, %sp is set as normal, + * then the exception is generated prior to executing the instruction + * after the save. + ************************************************************************/ + .text + .global _cwp_lolimit + .align 4 + +_cwp_lolimit: + + /* Sixteen words are always allocated by the compiler in every + * procedure's stack frame, always starting at %sp, for saving + * 'in' and 'local' registers on a window overflow. + * + * Save the 'global' and 'in' regs on stack. They are restored + * at cwp = HI_LIMIT. The 'local' regs aren't in-use at this point. + */ + sts [%sp,0], %g0 /* Save 'global' regs*/ + sts [%sp,1], %g1 + sts [%sp,2], %g2 + sts [%sp,3], %g3 + sts [%sp,4], %g4 + sts [%sp,5], %g5 + sts [%sp,6], %g6 + sts [%sp,7], %g7 + + sts [%sp,8], %i0 /* Save 'in' regs */ + sts [%sp,9], %i1 + sts [%sp,10], %i2 + sts [%sp,11], %i3 + sts [%sp,12], %i4 + sts [%sp,13], %i5 + sts [%sp,14], %i6 + sts [%sp,15], %i7 + + /* Save current %sp and return address in a global so they are + * available at cwp = HI_LIMIT ... where the 'global'/'in' regs + * are restored. NOTE: %sp changes with cwp. + */ + mov %g7, %o7 + mov %g6, %sp + + /* Get LO_LIMIT/HI_LIMIT to know where to start & stop. Note: in + * the underflow exception, cwp is __NOT__ guaranteed to be zero. + * If the OCI debug module is enabled the reset value for LO_LIMIT + * is 2, not 1 -- so cwp can be 1 or 0. + */ + pfx 2 /* WVALID */ + rdctl %g1 + mov %g2, %g1 + pfx 0 + and %g1, 0x1f /* g1 <- LO_LIMIT */ + lsri %g2, 5 + pfx 0 + and %g2,0x1f /* g2 <- HI_LIMIT */ + + /* Set istatus so cwp = HI_LIMIT after tret + */ + movi %g5, 0x1f + lsli %g5, 4 + not %g5 /* mask to clr cwp */ + pfx 1 /* istatus */ + rdctl %g0 + and %g0, %g5 /* clear cwp field */ + + mov %g4, %g2 + lsli %g4, 4 + or %g0, %g4 /* cwp = HI_LIMIT */ + pfx 1 + wrctl %g0 /* update istatus */ + + /* Now move up the register file, saving as we go. When loop + * is first entered, %g1 is at LO_LIMIT. + */ +0: + restore /* cwp++ */ + sts [%sp,0], %l0 /* Save "local" regs*/ + sts [%sp,1], %l1 + sts [%sp,2], %l2 + sts [%sp,3], %l3 + sts [%sp,4], %l4 + sts [%sp,5], %l5 + sts [%sp,6], %l6 + sts [%sp,7], %l7 + + sts [%sp,8], %i0 /* Save 'in' regs */ + sts [%sp,9], %i1 + sts [%sp,10], %i2 + sts [%sp,11], %i3 + sts [%sp,12], %i4 + sts [%sp,13], %i5 + sts [%sp,14], %i6 + sts [%sp,15], %i7 + + cmp %g1, %g2 /* cwp == HI_LIMIT ? */ + skps cc_ne /* if so, we're done */ + br 1f + nop /* delay slot */ + + inc %g1 /* g1 <- cwp++ */ + br 0b + nop /* delay slot */ + + /* At this point cwp = HI_LIMIT, so the global/in regs that were + * in place when the underflow occurred must be restored using + * the original stack pointer (saved in g6). + */ +1: + mov %o7, %g7 /* restore return addr */ + mov %sp, %g6 /* Restore original sp */ + + lds %g0, [%sp,0] /* Restore 'global' regs*/ + lds %g1, [%sp,1] + lds %g2, [%sp,2] + lds %g3, [%sp,3] + lds %g4, [%sp,4] + lds %g5, [%sp,5] + lds %g6, [%sp,6] + lds %g7, [%sp,7] + + lds %i0, [%sp,8] /* Restore 'in' regs*/ + lds %i1, [%sp,9] + lds %i2, [%sp,10] + lds %i3, [%sp,11] + lds %i4, [%sp,12] + lds %i5, [%sp,13] + lds %i6, [%sp,14] + lds %i7, [%sp,15] + + tret %o7 /* All done */ + +/************************************************************************* + * Register window overflow + * + * The register window overflow exception occurs whenever the highest + * valid register window is in use (cwp = HI_LIMIT) and a restore + * instruction is issued. Control is transferred to the overflow handler + * before the instruction following restore is executed. + * + * When a register window overflow exception is taken, the exception + * handler sees cwp at HI_LIMIT. + ************************************************************************/ + .text + .global _cwp_hilimit + .align 4 + +_cwp_hilimit: + + /* Save 'global'/'in' regs on the stack -- will restore when cwp + * is at LO_LIMIT. Locals don't need saving as they are going away. + */ + sts [%sp,0], %g0 /* Save "global" regs*/ + sts [%sp,1], %g1 + sts [%sp,2], %g2 + sts [%sp,3], %g3 + sts [%sp,4], %g4 + sts [%sp,5], %g5 + sts [%sp,6], %g6 + sts [%sp,7], %g7 + + sts [%sp,8], %i0 /* Save 'in' regs */ + sts [%sp,9], %i1 + sts [%sp,10], %i2 + sts [%sp,11], %i3 + sts [%sp,12], %i4 + sts [%sp,13], %i5 + sts [%sp,14], %i6 + sts [%sp,15], %i7 + + /* The current %sp must be available in global to restore regs + * saved on stack. Need return addr as well ;-) + */ + mov %g7, %o7 + mov %g6, %sp + + /* Get HI_LIMIT & LO_LIMIT + */ + pfx 2 /* WVALID */ + rdctl %g1 + mov %g2, %g1 + pfx 0 + and %g1, 0x1f /* g1 <- LO_LIMIT */ + lsri %g2, 5 + pfx 0 + and %g2,0x1f /* g2 <- HI_LIMIT */ + + /* Set istatus so cwp = LO_LIMIT after tret + */ + movi %g5, 0x1f + lsli %g5, 4 + not %g5 /* mask to clr cwp */ + pfx 1 /* istatus */ + rdctl %g0 + and %g0, %g5 /* clear cwp field */ + + mov %g4, %g1 /* g4 <- LO_LIMIT */ + lsli %g4, 4 + or %g0, %g4 /* cwp = LO_LIMIT */ + pfx 1 + wrctl %g0 /* update istatus */ + + /* Move to cwp = LO_LIMIT-1 and restore 'in' regs. + */ + subi %g4,(1 << 4) /* g4 <- LO_LIMIT - 1 */ + rdctl %g0 + and %g0, %g5 /* clear cwp field */ + or %g0, %g4 /* cwp = LO_LIMIT - 1 */ + wrctl %g0 /* update status */ + nop + + mov %sp, %g6 /* Restore sp */ + lds %i0, [%sp,8] /* Restore 'in' regs */ + lds %i1, [%sp,9] + lds %i2, [%sp,10] + lds %i3, [%sp,11] + lds %i4, [%sp,12] + lds %i5, [%sp,13] + lds %i6, [%sp,14] /* sp in next window */ + lds %i7, [%sp,15] + + /* Starting at LO_LIMIT-1, move up the register file, restoring + * along the way. + */ +0: + restore /* cwp++ */ + lds %l0, [%sp,0] /* Restore 'local' regs*/ + lds %l1, [%sp,1] + lds %l2, [%sp,2] + lds %l3, [%sp,3] + lds %l4, [%sp,4] + lds %l5, [%sp,5] + lds %l6, [%sp,6] + lds %l7, [%sp,7] + + lds %i0, [%sp,8] /* Restore 'in' regs */ + lds %i1, [%sp,9] + lds %i2, [%sp,10] + lds %i3, [%sp,11] + lds %i4, [%sp,12] + lds %i5, [%sp,13] + lds %i6, [%sp,14] /* sp in next window */ + lds %i7, [%sp,15] + + cmp %g1, %g2 /* cwp == HI_LIMIT ? */ + skps cc_ne /* if so, we're done */ + br 1f + nop /* delay slot */ + + inc %g1 /* cwp++ */ + br 0b + nop /* delay slot */ + + /* All windows have been updated at this point, but the globals + * still need to be restored. Go to cwp = LO_LIMIT-1 to get + * some registers to use. + */ +1: + rdctl %g0 + and %g0, %g5 /* clear cwp field */ + or %g0, %g4 /* cwp = LO_LIMIT - 1 */ + wrctl %g0 /* update status */ + nop + + /* Now there are some registers available to use in restoring + * the globals. + */ + mov %sp, %g6 + mov %o7, %g7 + + lds %g0, [%sp,0] /* Restore "global" regs*/ + lds %g1, [%sp,1] + lds %g2, [%sp,2] + lds %g3, [%sp,3] + lds %g4, [%sp,4] + lds %g5, [%sp,5] + lds %g6, [%sp,6] + lds %g7, [%sp,7] + + /* The tret moves istatus -> status. istatus was already set for + * cwp = LO_LIMIT. + */ + + tret %o7 /* done */ + +/************************************************************************* + * Default exception handler + * + * The default handler passes control to external_interrupt(). So trap + * or hardware interrupt hanlders can be installed using the familiar + * irq_install_handler(). + * + * Here, the stack is fixed-up and cwp is incremented prior to calling + * external_interrupt(). This lets the underflow and overflow handlers + * operate normally during the exception. + ************************************************************************/ + .text + .global _def_xhandler + .align 4 + +_def_xhandler: + + /* Allocate some stack space: 16 words at %sp to accomodate + * a reg window underflow, 8 words to save interrupted task's + * 'out' regs (which are now the 'in' regs), 8 words to preserve + * the 'global' regs and 3 words to save the return address, + * status and istatus. istatus must be saved in the event an + * underflow occurs in a dispatched handler. status is saved so + * a handler can access it on stack. + */ + pfx %hi((16+16+3) * 4) + subi %fp, %lo((16+16+3) * 4) + mov %sp, %fp + + /* Save the 'global' regs and the interrupted task's 'out' regs + * (our 'in' regs) along with the return addr, status & istatus. + * First 16 words are for underflow exception. + */ + rdctl %l0 /* status */ + pfx 1 /* istatus */ + rdctl %l1 + + sts [%sp,16+0], %g0 /* Save 'global' regs*/ + sts [%sp,16+1], %g1 + sts [%sp,16+2], %g2 + sts [%sp,16+3], %g3 + sts [%sp,16+4], %g4 + sts [%sp,16+5], %g5 + sts [%sp,16+6], %g6 + sts [%sp,16+7], %g7 + + sts [%sp,16+8], %i0 /* Save 'in' regs */ + sts [%sp,16+9], %i1 + sts [%sp,16+10], %i2 + sts [%sp,16+11], %i3 + sts [%sp,16+12], %i4 + sts [%sp,16+13], %i5 + sts [%sp,16+14], %i6 + sts [%sp,16+15], %i7 + + sts [%sp,16+16], %l0 /* status */ + sts [%sp,16+17], %l1 /* istatus */ + sts [%sp,16+18], %o7 /* return addr */ + + /* Move to cwp+1 ... this guarantees cwp is at or above LO_LIMIT. + * Need to set IPRI=3 and IE=1 to enable underflow exceptions. + * NOTE: only the 'out' regs have been saved ... can't touch + * the 'in' or 'local' here. + */ + restore /* cwp++ */ + rdctl %o0 /* o0 <- status */ + + pfx %hi(0x7e00) + movi %o1, %lo(0x7e00) + not %o1 + and %o0, %o1 /* clear IPRI */ + + pfx %hi(0x8600) + movi %o1, %lo(0x8600) + or %o0, %o1 /* IPRI=3, IE=1 */ + + wrctl %o0 /* o0 -> status */ + nop + + /* It's ok to call a C routine now since cwp >= LO_LIMIT, + * interrupt task's registers are/will be preserved, and + * underflow exceptions can be handled. + */ + pfx %hi(external_interrupt@h) + movi %o1, %lo(external_interrupt@h) + pfx %xhi(external_interrupt@h) + movhi %o1, %xlo(external_interrupt@h) + bgen %o0, 4+2 /* 16 * 4 */ + add %o0, %sp /* Ptr to regs */ + call %o1 + nop + + /* Move back to the exception register window, restore the 'out' + * registers, then return from exception. + */ + rdctl %o0 /* o0 <- status */ + subi %o0, 16 + wrctl %o0 /* cwp-- */ + nop + + mov %sp, %fp + lds %g0, [%sp,16+0] /* Restore 'global' regs*/ + lds %g1, [%sp,16+1] + lds %g2, [%sp,16+2] + lds %g3, [%sp,16+3] + lds %g4, [%sp,16+4] + lds %g5, [%sp,16+5] + lds %g6, [%sp,16+6] + lds %g7, [%sp,16+7] + + lds %i0, [%sp,16+8] /* Restore 'in' regs*/ + lds %i1, [%sp,16+9] + lds %i2, [%sp,16+10] + lds %i3, [%sp,16+11] + lds %i4, [%sp,16+12] + lds %i5, [%sp,16+13] + lds %i6, [%sp,16+14] + lds %i7, [%sp,16+15] + + lds %l0, [%sp,16+16] /* status */ + lds %l1, [%sp,16+17] /* istatus */ + lds %o7, [%sp,16+18] /* return addr */ + + pfx 1 + wrctl %l1 /* restore istatus */ + + pfx %hi((16+16+3) * 4) + addi %sp, %lo((16+16+3) * 4) + mov %fp, %sp + + tret %o7 /* Done */ + + +/************************************************************************* + * Timebase Timer Interrupt -- This has identical structure to above, + * but calls timer_interrupt(). Doing it this way keeps things similar + * to other architectures (e.g. ppc). + ************************************************************************/ + .text + .global _timebase_int + .align 4 + +_timebase_int: + + /* Allocate stack space. + */ + pfx %hi((16+16+3) * 4) + subi %fp, %lo((16+16+3) * 4) + mov %sp, %fp + + /* Save the 'global' regs & 'out' regs (our 'in' regs) + */ + rdctl %l0 /* status */ + pfx 1 /* istatus */ + rdctl %l1 + + sts [%sp,16+0], %g0 /* Save 'global' regs*/ + sts [%sp,16+1], %g1 + sts [%sp,16+2], %g2 + sts [%sp,16+3], %g3 + sts [%sp,16+4], %g4 + sts [%sp,16+5], %g5 + sts [%sp,16+6], %g6 + sts [%sp,16+7], %g7 + + sts [%sp,16+8], %i0 /* Save 'in' regs */ + sts [%sp,16+9], %i1 + sts [%sp,16+10], %i2 + sts [%sp,16+11], %i3 + sts [%sp,16+12], %i4 + sts [%sp,16+13], %i5 + sts [%sp,16+14], %i6 + sts [%sp,16+15], %i7 + + sts [%sp,16+16], %l0 /* status */ + sts [%sp,16+17], %l1 /* istatus */ + sts [%sp,16+18], %o7 /* return addr */ + + /* Move to cwp+1. + */ + restore /* cwp++ */ + rdctl %o0 /* o0 <- status */ + + pfx %hi(0x7e00) + movi %o1, %lo(0x7e00) + not %o1 + and %o0, %o1 /* clear IPRI */ + + pfx %hi(0x8600) + movi %o1, %lo(0x8600) + or %o0, %o1 /* IPRI=3, IE=1 */ + + wrctl %o0 /* o0 -> status */ + nop + + /* Call timer_interrupt() + */ + pfx %hi(timer_interrupt@h) + movi %o1, %lo(timer_interrupt@h) + pfx %xhi(timer_interrupt@h) + movhi %o1, %xlo(timer_interrupt@h) + bgen %o0, 4+2 /* 16 * 4 */ + add %o0, %sp /* Ptr to regs */ + call %o1 + nop + + /* Move back to the exception register window, restore the 'out' + * registers, then return from exception. + */ + rdctl %o0 /* o0 <- status */ + subi %o0, 16 + wrctl %o0 /* cwp-- */ + nop + + mov %sp, %fp + lds %g0, [%sp,16+0] /* Restore 'global' regs*/ + lds %g1, [%sp,16+1] + lds %g2, [%sp,16+2] + lds %g3, [%sp,16+3] + lds %g4, [%sp,16+4] + lds %g5, [%sp,16+5] + lds %g6, [%sp,16+6] + lds %g7, [%sp,16+7] + + lds %i0, [%sp,16+8] /* Restore 'in' regs*/ + lds %i1, [%sp,16+9] + lds %i2, [%sp,16+10] + lds %i3, [%sp,16+11] + lds %i4, [%sp,16+12] + lds %i5, [%sp,16+13] + lds %i6, [%sp,16+14] + lds %i7, [%sp,16+15] + + lds %l0, [%sp,16+16] /* status */ + lds %l1, [%sp,16+17] /* istatus */ + lds %o7, [%sp,16+18] /* return addr */ + + pfx 1 + wrctl %l1 /* restore istatus */ + + pfx %hi((16+16+3) * 4) + addi %sp, %lo((16+16+3) * 4) + mov %fp, %sp + + tret %o7 /* Done */ + +/************************************************************************* + * GDB stubs + ************************************************************************/ + .text + .global _brkpt_hw_int, _brkpt_sw_int + .align 4 + +_brkpt_hw_int: + movi %l1, 9 + pfx 3 + wrctl %l1 + pfx 4 + wrctl %l1 + +_brkpt_sw_int: + movi %l1, 9 + pfx 3 + wrctl %l1 + pfx 4 + wrctl %l1 + + tret %o7 diff --git a/arch/nios/include/asm/bitops.h b/arch/nios/include/asm/bitops.h new file mode 100644 index 0000000..0be74f4 --- /dev/null +++ b/arch/nios/include/asm/bitops.h @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _ASM_NIOS_BITOPS_H_ +#define _ASM_NIOS_BITOPS_H_ + + +extern void set_bit(int nr, volatile void * a); +extern void clear_bit(int nr, volatile void * a); +extern int test_and_clear_bit(int nr, volatile void * a); +extern void change_bit(unsigned long nr, volatile void *addr); +extern int test_and_set_bit(int nr, volatile void * a); +extern int test_and_change_bit(int nr, volatile void * addr); +extern int test_bit(int nr, volatile void * a); +extern int ffs(int i); +#define PLATFORM_FFS + +#endif /* _ASM_NIOS_BITOPS_H */ diff --git a/arch/nios/include/asm/byteorder.h b/arch/nios/include/asm/byteorder.h new file mode 100644 index 0000000..dc71021 --- /dev/null +++ b/arch/nios/include/asm/byteorder.h @@ -0,0 +1,30 @@ +/* +* (C) Copyright 2003, Psyent Corporation <www.psyent.com> +* Scott McNutt <smcnutt@psyent.com> +* +* See file CREDITS for list of people who contributed to this +* project. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, +* MA 02111-1307 USA +*/ + +#ifndef __ASM_NIOS_BYTEORDER_H +#define __ASM_NIOS_BYTEORDER_H + +#include <asm/types.h> +#include <linux/byteorder/little_endian.h> + +#endif diff --git a/arch/nios/include/asm/cache.h b/arch/nios/include/asm/cache.h new file mode 100644 index 0000000..3cdb703 --- /dev/null +++ b/arch/nios/include/asm/cache.h @@ -0,0 +1 @@ +/*FIXME: Implement this! */ diff --git a/arch/nios/include/asm/config.h b/arch/nios/include/asm/config.h new file mode 100644 index 0000000..2efe898 --- /dev/null +++ b/arch/nios/include/asm/config.h @@ -0,0 +1,27 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * 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 _ASM_CONFIG_H_ +#define _ASM_CONFIG_H_ + +/* Relocation to SDRAM works on all NIOS boards */ +#define CONFIG_RELOC_FIXUP_WORKS + +#endif diff --git a/arch/nios/include/asm/global_data.h b/arch/nios/include/asm/global_data.h new file mode 100644 index 0000000..fa54ee4 --- /dev/null +++ b/arch/nios/include/asm/global_data.h @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_NIOS_GLOBALDATA_H +#define __ASM_NIOS_GLOBALDATA_H + +typedef struct global_data { + bd_t *bd; + unsigned long flags; + unsigned long baudrate; + unsigned long cpu_clk; /* CPU clock in Hz! */ + unsigned long have_console; /* serial_init() was called */ + phys_size_t ram_size; /* RAM size */ + unsigned long env_addr; /* Address of Environment struct */ + unsigned long env_valid; /* Checksum of Environment valid */ +#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER) + unsigned long post_log_word; /* Record POST activities */ + unsigned long post_init_f_time; /* When post_init_f started */ +#endif + void **jt; /* Standalone app jump table */ +} gd_t; + +/* flags */ +#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ +#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */ +#define GD_FLG_SILENT 0x00004 /* Silent mode */ +#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */ +#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */ +#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */ +#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ + +#define DECLARE_GLOBAL_DATA_PTR register gd_t *gd asm ("%g7") + +#endif /* __ASM_NIOS_GLOBALDATA_H */ diff --git a/arch/nios/include/asm/io.h b/arch/nios/include/asm/io.h new file mode 100644 index 0000000..899682c --- /dev/null +++ b/arch/nios/include/asm/io.h @@ -0,0 +1,141 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_NIOS_IO_H_ +#define __ASM_NIOS_IO_H_ + +#define __raw_writeb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __raw_writew(v,a) (*(volatile unsigned short *)(a) = (v)) +#define __raw_writel(v,a) (*(volatile unsigned int *)(a) = (v)) + +#define __raw_readb(a) (*(volatile unsigned char *)(a)) +#define __raw_readw(a) (*(volatile unsigned short *)(a)) +#define __raw_readl(a) (*(volatile unsigned int *)(a)) + +#define readb(addr)\ + ({unsigned char val;\ + asm volatile( " pfxio 0 \n"\ + " ld %0, [%1] \n"\ + " ext8d %0, %1 \n"\ + :"=r"(val) : "r" (addr)); val;}) + +#define readw(addr)\ + ({unsigned short val;\ + asm volatile( " pfxio 0 \n"\ + " ld %0, [%1] \n"\ + " ext16d %0, %1 \n"\ + :"=r"(val) : "r" (addr)); val;}) + +#define readl(addr)\ + ({unsigned long val;\ + asm volatile( " pfxio 0 \n"\ + " ld %0, [%1] \n"\ + :"=r"(val) : "r" (addr)); val;}) + +#define writeb(addr,val)\ + asm volatile ( " fill8 %%r0, %1 \n"\ + " st8d [%0], %%r0 \n"\ + : : "r" (addr), "r" (val) : "r0") + +#define writew(addr,val)\ + asm volatile ( " fill16 %%r0, %1 \n"\ + " st16d [%0], %%r0 \n"\ + : : "r" (addr), "r" (val) : "r0") + +#define writel(addr,val)\ + asm volatile ( " st [%0], %1 \n"\ + : : "r" (addr), "r" (val)) + +#define inb(addr) readb(addr) +#define inw(addr) readw(addr) +#define inl(addr) readl(addr) +#define outb(val,addr) writeb(addr,val) +#define outw(val,addr) writew(addr,val) +#define outl(val,addr) writel(addr,val) + +static inline void insb (unsigned long port, void *dst, unsigned long count) +{ + unsigned char *p = dst; + while (count--) *p++ = inb (port); +} +static inline void insw (unsigned long port, void *dst, unsigned long count) +{ + unsigned short *p = dst; + while (count--) *p++ = inw (port); +} +static inline void insl (unsigned long port, void *dst, unsigned long count) +{ + unsigned long *p = dst; + while (count--) *p++ = inl (port); +} + +static inline void outsb (unsigned long port, const void *src, unsigned long count) +{ + const unsigned char *p = src; + while (count--) outb (*p++, port); +} + +static inline void outsw (unsigned long port, const void *src, unsigned long count) +{ + const unsigned short *p = src; + while (count--) outw (*p++, port); +} +static inline void outsl (unsigned long port, const void *src, unsigned long count) +{ + const unsigned long *p = src; + while (count--) outl (*p++, port); +} + +static inline void sync(void) +{ +} + +/* + * Given a physical address and a length, return a virtual address + * that can be used to access the memory range with the caching + * properties specified by "flags". + */ +#define MAP_NOCACHE (0) +#define MAP_WRCOMBINE (0) +#define MAP_WRBACK (0) +#define MAP_WRTHROUGH (0) + +static inline void * +map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) +{ + return (void *)paddr; +} + +/* + * Take down a mapping set up by map_physmem(). + */ +static inline void unmap_physmem(void *vaddr, unsigned long flags) +{ + +} + +static inline phys_addr_t virt_to_phys(void * vaddr) +{ + return (phys_addr_t)(vaddr); +} + +#endif /* __ASM_NIOS_IO_H_ */ diff --git a/arch/nios/include/asm/posix_types.h b/arch/nios/include/asm/posix_types.h new file mode 100644 index 0000000..eb74214 --- /dev/null +++ b/arch/nios/include/asm/posix_types.h @@ -0,0 +1,63 @@ +#ifndef __ASM_NIOS_POSIX_TYPES_H +#define __ASM_NIOS_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned long __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) + +#undef __FD_CLR +#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) + +#undef __FD_ISSET +#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif diff --git a/arch/nios/include/asm/processor.h b/arch/nios/include/asm/processor.h new file mode 100644 index 0000000..78b8976 --- /dev/null +++ b/arch/nios/include/asm/processor.h @@ -0,0 +1 @@ +/* FIXME: Implement this! */ diff --git a/arch/nios/include/asm/psr.h b/arch/nios/include/asm/psr.h new file mode 100644 index 0000000..6e8eba8 --- /dev/null +++ b/arch/nios/include/asm/psr.h @@ -0,0 +1,28 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _NIOS_PSR_H +#define _NIOS_PSR_H + + +#endif /* _NIOS_PSR_H */ diff --git a/arch/nios/include/asm/ptrace.h b/arch/nios/include/asm/ptrace.h new file mode 100644 index 0000000..73754c8 --- /dev/null +++ b/arch/nios/include/asm/ptrace.h @@ -0,0 +1,36 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _NIOS_PTRACE_H +#define _NIOS_PTRACE_H + +struct pt_regs { + unsigned global[8]; + unsigned in[8]; + unsigned status; + unsigned istatus; + unsigned retaddr; +}; + + +#endif /* _NIOS_PTRACE_H */ diff --git a/arch/nios/include/asm/status_led.h b/arch/nios/include/asm/status_led.h new file mode 100644 index 0000000..241c917 --- /dev/null +++ b/arch/nios/include/asm/status_led.h @@ -0,0 +1,132 @@ +/* + * (C) Copyright 2003, Li-Pro.Net <www.li-pro.net> + * Stephan Linz <linz@li-pro.net> + * + * 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 + * + * asm-nios/status_led.h + * + * NIOS PIO based status led support functions + */ + +#ifndef __ASM_STATUS_LED_H__ +#define __ASM_STATUS_LED_H__ + +#include <nios-io.h> + +/* led_id_t is unsigned int mask */ +typedef unsigned int led_id_t; + +#ifdef STATUS_LED_WRONLY /* emulate read access */ +static led_id_t __led_portval = 0; +#endif + +static inline void __led_init (led_id_t mask, int state) +{ + nios_pio_t *piop = (nios_pio_t*)STATUS_LED_BASE; + +#ifdef STATUS_LED_WRONLY /* emulate read access */ + +#if (STATUS_LED_ACTIVE == 0) + if (state == STATUS_LED_ON) + __led_portval &= ~mask; + else + __led_portval |= mask; +#else + if (state == STATUS_LED_ON) + __led_portval |= mask; + else + __led_portval &= ~mask; +#endif + + piop->data = __led_portval; + +#else /* !STATUS_LED_WRONLY */ + +#if (STATUS_LED_ACTIVE == 0) + if (state == STATUS_LED_ON) + piop->data &= ~mask; + else + piop->data |= mask; +#else + if (state == STATUS_LED_ON) + piop->data |= mask; + else + piop->data &= ~mask; +#endif + + piop->direction |= mask; + +#endif /* STATUS_LED_WRONLY */ +} + +static inline void __led_toggle (led_id_t mask) +{ + nios_pio_t *piop = (nios_pio_t*)STATUS_LED_BASE; + +#ifdef STATUS_LED_WRONLY /* emulate read access */ + + __led_portval ^= mask; + piop->data = __led_portval; + +#else /* !STATUS_LED_WRONLY */ + + piop->data ^= mask; + +#endif /* STATUS_LED_WRONLY */ +} + +static inline void __led_set (led_id_t mask, int state) +{ + nios_pio_t *piop = (nios_pio_t*)STATUS_LED_BASE; + +#ifdef STATUS_LED_WRONLY /* emulate read access */ + +#if (STATUS_LED_ACTIVE == 0) + if (state == STATUS_LED_ON) + __led_portval &= ~mask; + else + __led_portval |= mask; +#else + if (state == STATUS_LED_ON) + __led_portval |= mask; + else + __led_portval &= ~mask; +#endif + + piop->data = __led_portval; + +#else /* !STATUS_LED_WRONLY */ + +#if (STATUS_LED_ACTIVE == 0) + if (state == STATUS_LED_ON) + piop->data &= ~mask; + else + piop->data |= mask; +#else + if (state == STATUS_LED_ON) + piop->data |= mask; + else + piop->data &= ~mask; +#endif + +#endif /* STATUS_LED_WRONLY */ +} + +#endif /* __ASM_STATUS_LED_H__ */ diff --git a/arch/nios/include/asm/string.h b/arch/nios/include/asm/string.h new file mode 100644 index 0000000..fa33275 --- /dev/null +++ b/arch/nios/include/asm/string.h @@ -0,0 +1,25 @@ +#ifndef __ASM_NIOS_STRING_H +#define __ASM_NIOS_STRING_H + +#undef __HAVE_ARCH_STRRCHR +extern char * strrchr(const char * s, int c); + +#undef __HAVE_ARCH_STRCHR +extern char * strchr(const char * s, int c); + +#undef __HAVE_ARCH_MEMCPY +extern void * memcpy(void *, const void *, __kernel_size_t); + +#undef __HAVE_ARCH_MEMMOVE +extern void * memmove(void *, const void *, __kernel_size_t); + +#undef __HAVE_ARCH_MEMCHR +extern void * memchr(const void *, int, __kernel_size_t); + +#undef __HAVE_ARCH_MEMSET +extern void * memset(void *, int, __kernel_size_t); + +#undef __HAVE_ARCH_MEMZERO +extern void memzero(void *ptr, __kernel_size_t n); + +#endif diff --git a/arch/nios/include/asm/system.h b/arch/nios/include/asm/system.h new file mode 100644 index 0000000..9a9383d --- /dev/null +++ b/arch/nios/include/asm/system.h @@ -0,0 +1,4 @@ +#ifndef _ASM_NIOS_SYSTEM_H_ +#define _ASM_NIOS_SYSTEM_H_ + +#endif /* _ASM_NIOS_SYSTEM_H */ diff --git a/arch/nios/include/asm/types.h b/arch/nios/include/asm/types.h new file mode 100644 index 0000000..636e12f --- /dev/null +++ b/arch/nios/include/asm/types.h @@ -0,0 +1,60 @@ +#ifndef _NIOS_TYPES_H +#define _NIOS_TYPES_H + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +typedef unsigned long phys_addr_t; +typedef unsigned long phys_size_t; +#endif /* __KERNEL__ */ + +#endif /* _NIOS_TYPES_H */ diff --git a/arch/nios/include/asm/u-boot.h b/arch/nios/include/asm/u-boot.h new file mode 100644 index 0000000..bdb6cf2 --- /dev/null +++ b/arch/nios/include/asm/u-boot.h @@ -0,0 +1,48 @@ +/* + * (C) Copyright 2003 + * Psyent Corporation + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ******************************************************************** + * NOTE: This header file defines an interface to U-Boot. Including + * this (unmodified) header file in another file is considered normal + * use of U-Boot, and does *not* fall under the heading of "derived + * work". + ******************************************************************** + */ + +#ifndef _U_BOOT_H_ +#define _U_BOOT_H_ + +typedef struct bd_info { + unsigned long bi_memstart; /* start of DRAM memory */ + phys_size_t bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ + unsigned long bi_sramstart; /* start of SRAM memory */ + unsigned long bi_sramsize; /* size of SRAM memory */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned long bi_baudrate; /* Console Baudrate */ +} bd_t; + + +#endif /* _U_BOOT_H_ */ diff --git a/arch/nios/lib/Makefile b/arch/nios/lib/Makefile new file mode 100644 index 0000000..f66e989 --- /dev/null +++ b/arch/nios/lib/Makefile @@ -0,0 +1,50 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(ARCH).a + +SOBJS-y += + +COBJS-y += board.o +COBJS-y += bootm.o +COBJS-y += cache.o +COBJS-y += divmod.o +COBJS-y += mult.o +COBJS-y += time.o + +SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/nios/lib/board.c b/arch/nios/lib/board.c new file mode 100644 index 0000000..5d2fb2e --- /dev/null +++ b/arch/nios/lib/board.c @@ -0,0 +1,168 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <stdio_dev.h> +#include <watchdog.h> +#include <malloc.h> +#include <net.h> +#ifdef CONFIG_STATUS_LED +#include <status_led.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* + * All attempts to come up with a "common" initialization sequence + * that works for all boards and architectures failed: some of the + * requirements are just _too_ different. To get rid of the resulting + * mess of board dependend #ifdef'ed code we now make the whole + * initialization sequence configurable to the user. + * + * The requirements for any new initalization function is simple: it + * receives a pointer to the "global data" structure as it's only + * argument, and returns an integer return code, where 0 means + * "continue" and != 0 means "fatal error, hang the system". + */ + + +typedef int (init_fnc_t) (void); + + +/************************************************************************ + * Initialization sequence * + ***********************************************************************/ + +init_fnc_t *init_sequence[] = { + +#if defined(CONFIG_BOARD_EARLY_INIT_F) + board_early_init_f, /* Call board-specific init code early.*/ +#endif + + env_init, + serial_init, + console_init_f, + display_options, + checkcpu, + checkboard, + NULL, /* Terminate this list */ +}; + + +/***********************************************************************/ +void board_init (void) +{ + bd_t *bd; + init_fnc_t **init_fnc_ptr; + char *s, *e; + int i; + + /* Pointer is writable since we allocated a register for it. + * Nios treats CONFIG_SYS_GBL_DATA_OFFSET as an address. + */ + gd = (gd_t *)CONFIG_SYS_GBL_DATA_OFFSET; + /* compiler optimization barrier needed for GCC >= 3.4 */ + __asm__ __volatile__("": : :"memory"); + + memset( gd, 0, CONFIG_SYS_GBL_DATA_SIZE ); + + gd->bd = (bd_t *)(gd+1); /* At end of global data */ + gd->baudrate = CONFIG_BAUDRATE; + gd->cpu_clk = CONFIG_SYS_CLK_FREQ; + + bd = gd->bd; + bd->bi_memstart = CONFIG_SYS_SDRAM_BASE; + bd->bi_memsize = CONFIG_SYS_SDRAM_SIZE; + bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; +#if defined(CONFIG_SYS_SRAM_BASE) && defined(CONFIG_SYS_SRAM_SIZE) + bd->bi_sramstart= CONFIG_SYS_SRAM_BASE; + bd->bi_sramsize = CONFIG_SYS_SRAM_SIZE; +#endif + bd->bi_baudrate = CONFIG_BAUDRATE; + + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { + WATCHDOG_RESET (); + if ((*init_fnc_ptr) () != 0) { + hang (); + } + } + + WATCHDOG_RESET (); + + /* The Malloc area is immediately below the monitor copy in RAM */ + mem_malloc_init(CONFIG_SYS_MALLOC_BASE, CONFIG_SYS_MALLOC_LEN); + + WATCHDOG_RESET (); + bd->bi_flashsize = flash_init(); + + WATCHDOG_RESET (); + env_relocate(); + + bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); + + WATCHDOG_RESET (); + stdio_init(); + jumptable_init(); + console_init_r(); + /* + */ + + WATCHDOG_RESET (); + interrupt_init (); + +#ifdef CONFIG_STATUS_LED + status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING); +#endif + + /* main_loop */ + for (;;) { + WATCHDOG_RESET (); + main_loop (); + } +} + + +/***********************************************************************/ + +void hang (void) +{ +#ifdef CONFIG_STATUS_LED + status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF); + status_led_set(STATUS_LED_RED, STATUS_LED_BLINKING); +#endif + puts("### ERROR ### Please reset board ###\n"); + for (;;); +} + +unsigned long do_go_exec (ulong (*entry)(int, char *[]), int argc, char *argv[]) +{ + /* + * x86 does not use a dedicated register to pass the pointer + * to the global_data + */ + argv[-1] = (char *)gd; + return entry (argc, argv); +} diff --git a/arch/nios/lib/bootm.c b/arch/nios/lib/bootm.c new file mode 100644 index 0000000..b0d5b82 --- /dev/null +++ b/arch/nios/lib/bootm.c @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> + +/* FIXME: Once we find a stable version of uC-linux for nios + * we can get this working. ;-) + * + */ +int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +{ + return 1; +} diff --git a/arch/nios/lib/cache.c b/arch/nios/lib/cache.c new file mode 100644 index 0000000..87dbab1 --- /dev/null +++ b/arch/nios/lib/cache.c @@ -0,0 +1,32 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + + +void flush_cache (ulong addr, ulong size) +{ + /* Nios cache is write-thru -- nothing to do here. + */ + return; +} diff --git a/arch/nios/lib/divmod.c b/arch/nios/lib/divmod.c new file mode 100644 index 0000000..3c7e71e --- /dev/null +++ b/arch/nios/lib/divmod.c @@ -0,0 +1,101 @@ +/* + * This file is part of GNU CC. + * + * GNU CC 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, or (at your + * option) any later version. + * + * GNU CC 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 GNU CC; see the file COPYING. If not, write + * to the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include "math.h" + +USItype udivmodsi4 (USItype num, USItype den, word_type modwanted) +{ + USItype bit = 1; + USItype res = 0; + + while (den < num && bit && !(den & (1L << 31))) { + den <<= 1; + bit <<= 1; + } + while (bit) { + if (num >= den) { + num -= den; + res |= bit; + } + bit >>= 1; + den >>= 1; + } + if (modwanted) + return num; + return res; +} + + +SItype __divsi3 (SItype a, SItype b) +{ + word_type neg = 0; + SItype res; + + if (a < 0) { + a = -a; + neg = !neg; + } + + if (b < 0) { + b = -b; + neg = !neg; + } + + res = udivmodsi4 (a, b, 0); + + if (neg) + res = -res; + + return res; +} + + +SItype __modsi3 (SItype a, SItype b) +{ + word_type neg = 0; + SItype res; + + if (a < 0) { + a = -a; + neg = 1; + } + + if (b < 0) + b = -b; + + res = udivmodsi4 (a, b, 1); + + if (neg) + res = -res; + + return res; +} + + +SItype __udivsi3 (SItype a, SItype b) +{ + return udivmodsi4 (a, b, 0); +} + + +SItype __umodsi3 (SItype a, SItype b) +{ + return udivmodsi4 (a, b, 1); +} diff --git a/arch/nios/lib/math.h b/arch/nios/lib/math.h new file mode 100644 index 0000000..f0aed8e --- /dev/null +++ b/arch/nios/lib/math.h @@ -0,0 +1,16 @@ +#define BITS_PER_UNIT 8 + +typedef int HItype __attribute__ ((mode (HI))); +typedef unsigned int UHItype __attribute__ ((mode (HI))); + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); + +typedef int word_type __attribute__ ((mode (__word__))); + +struct SIstruct {HItype low, high;}; + +typedef union { + struct SIstruct s; + SItype ll; +} SIunion; diff --git a/arch/nios/lib/mult.c b/arch/nios/lib/mult.c new file mode 100644 index 0000000..ec8139e --- /dev/null +++ b/arch/nios/lib/mult.c @@ -0,0 +1,56 @@ +/* + * This file is part of GNU CC. + * + * GNU CC 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, or (at your + * option) any later version. + * + * GNU CC 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 GNU CC; see the file COPYING. If not, write + * to the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include <common.h> + +#if !defined(CONFIG_SYS_NIOS_MULT_HW) && !defined(CONFIG_SYS_NIOS_MULT_MSTEP) + +#include "math.h" + +USItype __mulsi3 (USItype a, USItype b) +{ + USItype c = 0; + + while (a != 0) { + if (a & 1) + c += b; + a >>= 1; + b <<= 1; + } + + return c; +} + + +UHItype __mulhi3 (UHItype a, UHItype b) +{ + UHItype c = 0; + + while (a != 0) { + if (a & 1) + c += b; + a >>= 1; + b <<= 1; + } + + return c; +} + +#endif /*!defined(CONFIG_SYS_NIOS_MULT_HW) && !defined(CONFIG_SYS_NIOS_MULT_MSTEP) */ diff --git a/arch/nios/lib/time.c b/arch/nios/lib/time.c new file mode 100644 index 0000000..d5096ee --- /dev/null +++ b/arch/nios/lib/time.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <watchdog.h> + + +extern void dly_clks( unsigned long ticks ); + +void __udelay(unsigned long usec) +{ + /* The Nios core doesn't have a timebase, so we do our + * best for now and call a low-level loop that counts + * cpu clocks. + */ + unsigned long cnt = (CONFIG_SYS_CLK_FREQ/1000000) * usec; + dly_clks (cnt); +} |