]> git.sur5r.net Git - u-boot/commitdiff
Das U-Boot: Universal Boot Loader
authorwdenk <wdenk>
Tue, 27 Aug 2002 09:48:53 +0000 (09:48 +0000)
committerwdenk <wdenk>
Tue, 27 Aug 2002 09:48:53 +0000 (09:48 +0000)
17 files changed:
common/cmd_fpga.c [new file with mode: 0644]
common/kgdb.c [new file with mode: 0644]
cpu/74xx_7xx/cpu_init.c [new file with mode: 0644]
cpu/74xx_7xx/speed.c [new file with mode: 0644]
cpu/mpc824x/cpu.c [new file with mode: 0644]
cpu/mpc824x/interrupts.c [new file with mode: 0644]
cpu/mpc8260/cpu.c [new file with mode: 0644]
cpu/mpc8260/interrupts.c [new file with mode: 0644]
cpu/mpc8260/serial_scc.c [new file with mode: 0644]
cpu/mpc8260/serial_smc.c [new file with mode: 0644]
cpu/mpc8260/speed.c [new file with mode: 0644]
cpu/mpc8xx/cpu_init.c [new file with mode: 0644]
cpu/mpc8xx/serial.c [new file with mode: 0644]
cpu/mpc8xx/speed.c [new file with mode: 0644]
cpu/mpc8xx/wlkbd.c [new file with mode: 0644]
cpu/ppc4xx/cpu_init.c [new file with mode: 0644]
cpu/sa1100/cpu.c [new file with mode: 0644]

diff --git a/common/cmd_fpga.c b/common/cmd_fpga.c
new file mode 100644 (file)
index 0000000..4e4c4ab
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2000, 2001
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.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
+ *
+ */
+
+/*
+ *  FPGA support
+ */
+#include <common.h>
+#include <command.h>
+#include <cmd_fpga.h>
+#include <fpga.h>
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#include <net.h>
+#endif
+
+#if 0
+#define        FPGA_DEBUG
+#endif
+
+#ifdef FPGA_DEBUG
+#define        PRINTF(fmt,args...)     printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#if defined (CONFIG_FPGA) && ( CONFIG_COMMANDS & CFG_CMD_FPGA )
+
+/* Local functions */
+static void fpga_usage ( cmd_tbl_t *cmdtp );
+static int fpga_get_op( char *opstr );
+
+/* Local defines */
+#define FPGA_NONE   -1
+#define FPGA_INFO   0
+#define FPGA_LOAD   1
+#define FPGA_DUMP   3
+
+/* ------------------------------------------------------------------------- */
+/* command form:
+ *   fpga <op> <device number> <data addr> <datasize>
+ * where op is 'load', 'dump', or 'info'
+ * If there is no device number field, the fpga environment variable is used.
+ * If there is no data addr field, the fpgadata environment variable is used.
+ * The info command requires no data address field.
+ */
+int
+do_fpga (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    int op, dev = FPGA_INVALID_DEVICE;
+    size_t data_size = 0;
+    void *fpga_data = NULL;
+    char *devstr = getenv("fpga");
+    char *datastr = getenv("fpgadata");
+
+       if ( devstr ) dev = (int)simple_strtoul( devstr, NULL, 16 );
+       if ( datastr ) fpga_data = (void *)simple_strtoul( datastr, NULL, 16 );
+
+    switch ( argc )
+    {
+           case 5: /* fpga <op> <dev> <data> <datasize> */
+                   data_size = simple_strtoul( argv[4], NULL, 16 );
+           case 4: /* fpga <op> <dev> <data> */
+                   fpga_data = (void *)simple_strtoul( argv[3], NULL, 16 );
+                       PRINTF(__FUNCTION__": fpga_data = 0x%x\n", (uint)fpga_data );
+           case 3: /* fpga <op> <dev | data addr> */
+                   dev = (int)simple_strtoul( argv[2], NULL, 16 );
+                       PRINTF(__FUNCTION__": device = %d\n", dev );
+                       /* FIXME - this is a really weak test */
+                   if (( argc == 3 ) && ( dev > fpga_count() )) { /* must be buffer ptr */
+                               PRINTF(__FUNCTION__": Assuming buffer pointer in arg 3\n");
+                           fpga_data = (void *)dev;
+                               PRINTF(__FUNCTION__": fpga_data = 0x%x\n", (uint)fpga_data );
+                           dev = FPGA_INVALID_DEVICE;  /* reset device num */
+                   }
+           case 2: /* fpga <op> */
+                   op = (int)fpga_get_op( argv[1] );
+                   break;
+           default:
+                       PRINTF(__FUNCTION__": Too many or too few args (%d)\n", argc );
+                   op = FPGA_NONE;    /* force usage display */
+                   break;
+    }
+
+    switch ( op ) {
+           case FPGA_NONE:
+                   fpga_usage( cmdtp );
+                   break;
+
+           case FPGA_INFO:
+                   fpga_info( dev );
+                   break;
+
+           case FPGA_LOAD:
+                       fpga_load( dev, fpga_data, data_size );
+                   break;
+
+           case FPGA_DUMP:
+                       fpga_dump( dev, fpga_data, data_size );
+                   break;
+
+           default:
+                   printf( "Unknown operation.\n" );
+                   fpga_usage( cmdtp );
+                   break;
+    }
+    return 0;
+}
+
+static void fpga_usage ( cmd_tbl_t *cmdtp )
+{
+       printf( "Usage:\n%s\n", cmdtp->usage );
+}
+
+/*
+ * Map op to supported operations.  We don't use a table since we
+ * would just have to relocate it from flash anyway.
+ */
+static int fpga_get_op( char *opstr )
+{
+       int op = FPGA_NONE;
+
+       if (!strcmp ("info", opstr)) {
+               op = FPGA_INFO;
+       }
+       else if (!strcmp ("load", opstr)) {
+               op = FPGA_LOAD;
+       }
+       else if (!strcmp ("dump", opstr)) {
+               op = FPGA_DUMP;
+       }
+
+       if ( op == FPGA_NONE ) {
+               printf ("Unknown fpga operation \"%s\"\n", opstr);
+       }
+       return op;
+}
+
+#endif /* CONFIG_FPGA && CONFIG_COMMANDS & CFG_CMD_FPGA */
diff --git a/common/kgdb.c b/common/kgdb.c
new file mode 100644 (file)
index 0000000..b563094
--- /dev/null
@@ -0,0 +1,580 @@
+/* taken from arch/ppc/kernel/ppc-stub.c */
+
+/****************************************************************************
+
+               THIS SOFTWARE IS NOT COPYRIGHTED
+
+   HP offers the following for use in the public domain.  HP makes no
+   warranty with regard to the software or its performance and the
+   user accepts the software "AS IS" with all faults.
+
+   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:      Glenn Engel $
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:           See Below $
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ *  This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *    qOffsets      Get section offsets.  Reply is Text=xxx;Data=yyy;Bss=zzz
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *    bBB..BB      Set baud rate to BB..BB                OK or BNN, then sets
+ *                                                        baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#include <common.h>
+
+#include <kgdb.h>
+#include <command.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+
+#undef KGDB_DEBUG
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ */
+#define BUFMAX 1024
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static char remcomRegBuffer[BUFMAX];
+
+static int initialized = 0;
+static int kgdb_active = 0, first_entry = 1;
+static struct pt_regs entry_regs;
+static u_int error_jmp_buf[BUFMAX/2];
+static int longjmp_on_fault = 0;
+#ifdef KGDB_DEBUG
+static int kdebug = 1;
+#endif
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Convert ch from a hex digit to an int */
+static int
+hex(unsigned char ch)
+{
+       if (ch >= 'a' && ch <= 'f')
+               return ch-'a'+10;
+       if (ch >= '0' && ch <= '9')
+               return ch-'0';
+       if (ch >= 'A' && ch <= 'F')
+               return ch-'A'+10;
+       return -1;
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null).
+ */
+static unsigned char *
+mem2hex(char *mem, char *buf, int count)
+{
+       unsigned char ch;
+
+       longjmp_on_fault = 1;
+       while (count-- > 0) {
+               ch = *mem++;
+               *buf++ = hexchars[ch >> 4];
+               *buf++ = hexchars[ch & 0xf];
+       }
+       *buf = 0;
+       longjmp_on_fault = 0;
+       return buf;
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte fetched from buf.
+*/
+static char *
+hex2mem(char *buf, char *mem, int count)
+{
+       int i, hexValue;
+       unsigned char ch;
+       char *mem_start = mem;
+
+       longjmp_on_fault = 1;
+       for (i=0; i<count; i++) {
+               if ((hexValue = hex(*buf++)) < 0)
+                       kgdb_error(KGDBERR_NOTHEXDIG);
+               ch = hexValue << 4;
+               if ((hexValue = hex(*buf++)) < 0)
+                       kgdb_error(KGDBERR_NOTHEXDIG);
+               ch |= hexValue;
+               *mem++ = ch;
+       }
+       kgdb_flush_cache_range((void *)mem_start, (void *)(mem - 1));
+       longjmp_on_fault = 0;
+
+       return buf;
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int
+hexToInt(char **ptr, int *intValue)
+{
+       int numChars = 0;
+       int hexValue;
+
+       *intValue = 0;
+
+       longjmp_on_fault = 1;
+       while (**ptr) {
+               hexValue = hex(**ptr);
+               if (hexValue < 0)
+                       break;
+
+               *intValue = (*intValue << 4) | hexValue;
+               numChars ++;
+
+               (*ptr)++;
+       }
+       longjmp_on_fault = 0;
+
+       return (numChars);
+}
+
+/* scan for the sequence $<data>#<checksum>     */
+static void
+getpacket(char *buffer)
+{
+       unsigned char checksum;
+       unsigned char xmitcsum;
+       int i;
+       int count;
+       unsigned char ch;
+
+       do {
+               /* wait around for the start character, ignore all other
+                * characters */
+               while ((ch = (getDebugChar() & 0x7f)) != '$') {
+#ifdef KGDB_DEBUG
+                       if (kdebug)
+                               putc(ch);
+#endif
+                       ;
+               }
+
+               checksum = 0;
+               xmitcsum = -1;
+
+               count = 0;
+
+               /* now, read until a # or end of buffer is found */
+               while (count < BUFMAX) {
+                       ch = getDebugChar() & 0x7f;
+                       if (ch == '#')
+                               break;
+                       checksum = checksum + ch;
+                       buffer[count] = ch;
+                       count = count + 1;
+               }
+
+               if (count >= BUFMAX)
+                       continue;
+
+               buffer[count] = 0;
+
+               if (ch == '#') {
+                       xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+                       xmitcsum |= hex(getDebugChar() & 0x7f);
+                       if (checksum != xmitcsum)
+                               putDebugChar('-');      /* failed checksum */
+                       else {
+                               putDebugChar('+'); /* successful transfer */
+                               /* if a sequence char is present, reply the ID */
+                               if (buffer[2] == ':') {
+                                       putDebugChar(buffer[0]);
+                                       putDebugChar(buffer[1]);
+                                       /* remove sequence chars from buffer */
+                                       count = strlen(buffer);
+                                       for (i=3; i <= count; i++)
+                                               buffer[i-3] = buffer[i];
+                               }
+                       }
+               }
+       } while (checksum != xmitcsum);
+}
+
+/* send the packet in buffer.  */
+static void
+putpacket(unsigned char *buffer)
+{
+       unsigned char checksum;
+       int count;
+       unsigned char ch, recv;
+
+       /*  $<packet info>#<checksum>. */
+       do {
+               putDebugChar('$');
+               checksum = 0;
+               count = 0;
+
+               while ((ch = buffer[count])) {
+                       putDebugChar(ch);
+                       checksum += ch;
+                       count += 1;
+               }
+
+               putDebugChar('#');
+               putDebugChar(hexchars[checksum >> 4]);
+               putDebugChar(hexchars[checksum & 0xf]);
+               recv = getDebugChar();
+       } while ((recv & 0x7f) != '+');
+}
+
+/*
+ * This function does all command processing for interfacing to gdb.
+ */
+static int
+handle_exception (struct pt_regs *regs)
+{
+       int addr;
+       int length;
+       char *ptr;
+       kgdb_data kd;
+       int i;
+
+       if (!initialized) {
+               printf("kgdb: exception before kgdb is initialized! huh?\n");
+               return (0);
+       }
+
+       /* probably should check which exception occured as well */
+       if (longjmp_on_fault) {
+               longjmp_on_fault = 0;
+               kgdb_longjmp((long*)error_jmp_buf, KGDBERR_MEMFAULT);
+               panic("kgdb longjump failed!\n");
+       }
+
+       if (kgdb_active) {
+               printf("kgdb: unexpected exception from within kgdb\n");
+               return (0);
+       }
+       kgdb_active = 1;
+
+       kgdb_interruptible(0);
+
+       printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
+
+       if (kgdb_setjmp((long*)error_jmp_buf) != 0)
+               panic("kgdb: error or fault in entry init!\n");
+
+       kgdb_enter(regs, &kd);
+
+       if (first_entry) {
+               /*
+                * the first time we enter kgdb, we save the processor
+                * state so that we can return to the monitor if the
+                * remote end quits gdb (or at least, tells us to quit
+                * with the 'k' packet)
+                */
+               entry_regs = *regs;
+               first_entry = 0;
+       }
+
+       ptr = remcomOutBuffer;
+
+       *ptr++ = 'T';
+
+       *ptr++ = hexchars[kd.sigval >> 4];
+       *ptr++ = hexchars[kd.sigval & 0xf];
+
+       for (i = 0; i < kd.nregs; i++) {
+               kgdb_reg *rp = &kd.regs[i];
+
+               *ptr++ = hexchars[rp->num >> 4];
+               *ptr++ = hexchars[rp->num & 0xf];
+               *ptr++ = ':';
+               ptr = mem2hex((char *)&rp->val, ptr, 4);
+               *ptr++ = ';';
+       }
+
+       *ptr = 0;
+
+#ifdef KGDB_DEBUG
+       if (kdebug)
+               printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
+#endif
+
+       putpacket(remcomOutBuffer);
+
+       while (1) {
+               volatile int errnum;
+
+               remcomOutBuffer[0] = 0;
+
+               getpacket(remcomInBuffer);
+               ptr = &remcomInBuffer[1];
+
+#ifdef KGDB_DEBUG
+               if (kdebug)
+                       printf("kgdb:  remcomInBuffer: %s\n", remcomInBuffer);
+#endif
+
+               errnum = kgdb_setjmp((long*)error_jmp_buf);
+
+               if (errnum == 0) switch (remcomInBuffer[0]) {
+
+               case '?':               /* report most recent signal */
+                       remcomOutBuffer[0] = 'S';
+                       remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
+                       remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
+                       remcomOutBuffer[3] = 0;
+                       break;
+
+#ifdef KGDB_DEBUG
+               case 'd':
+                       /* toggle debug flag */
+                       kdebug ^= 1;
+                       break;
+#endif
+
+               case 'g':       /* return the value of the CPU registers. */
+                       length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
+                       mem2hex(remcomRegBuffer, remcomOutBuffer, length);
+                       break;
+
+               case 'G':   /* set the value of the CPU registers */
+                       length = strlen(ptr);
+                       if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
+                       hex2mem(ptr, remcomRegBuffer, length/2);
+                       kgdb_putregs(regs, remcomRegBuffer, length/2);
+                       strcpy(remcomOutBuffer,"OK");
+                       break;
+
+               case 'm':       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+                               /* Try to read %x,%x.  */
+
+                       if (hexToInt(&ptr, &addr)
+                           && *ptr++ == ','
+                           && hexToInt(&ptr, &length)) {
+                               mem2hex((char *)addr, remcomOutBuffer, length);
+                       } else {
+                               kgdb_error(KGDBERR_BADPARAMS);
+                       }
+                       break;
+
+               case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+                       /* Try to read '%x,%x:'.  */
+
+                       if (hexToInt(&ptr, &addr)
+                           && *ptr++ == ','
+                           && hexToInt(&ptr, &length)
+                           && *ptr++ == ':') {
+                               hex2mem(ptr, (char *)addr, length);
+                               strcpy(remcomOutBuffer, "OK");
+                       } else {
+                               kgdb_error(KGDBERR_BADPARAMS);
+                       }
+                       break;
+
+
+               case 'k':    /* kill the program, actually return to monitor */
+                       kd.extype = KGDBEXIT_KILL;
+                       *regs = entry_regs;
+                       first_entry = 1;
+                       goto doexit;
+
+               case 'C':    /* CSS  continue with signal SS */
+                       *ptr = '\0';    /* ignore the signal number for now */
+                       /* fall through */
+
+               case 'c':    /* cAA..AA  Continue; address AA..AA optional */
+                       /* try to read optional parameter, pc unchanged if no parm */
+                       kd.extype = KGDBEXIT_CONTINUE;
+
+                       if (hexToInt(&ptr, &addr)) {
+                               kd.exaddr = addr;
+                               kd.extype |= KGDBEXIT_WITHADDR;
+                       }
+
+                       goto doexit;
+
+               case 'S':    /* SSS  single step with signal SS */
+                       *ptr = '\0';    /* ignore the signal number for now */
+                       /* fall through */
+
+               case 's':
+                       kd.extype = KGDBEXIT_SINGLE;
+
+                       if (hexToInt(&ptr, &addr)) {
+                               kd.exaddr = addr;
+                               kd.extype |= KGDBEXIT_WITHADDR;
+                       }
+
+               doexit:
+/* Need to flush the instruction cache here, as we may have deposited a
+ * breakpoint, and the icache probably has no way of knowing that a data ref to
+ * some location may have changed something that is in the instruction cache.
+ */
+                       kgdb_flush_cache_all();
+                       kgdb_exit(regs, &kd);
+                       kgdb_active = 0;
+                       kgdb_interruptible(1);
+                       return (1);
+
+               case 'r':               /* Reset (if user process..exit ???)*/
+                       panic("kgdb reset.");
+                       break;
+
+               case 'P':    /* Pr=v  set reg r to value v (r and v are hex) */
+                       if (hexToInt(&ptr, &addr)
+                           && *ptr++ == '='
+                           && ((length = strlen(ptr)) & 1) == 0) {
+                               hex2mem(ptr, remcomRegBuffer, length/2);
+                               kgdb_putreg(regs, addr,
+                                       remcomRegBuffer, length/2);
+                               strcpy(remcomOutBuffer,"OK");
+                       } else {
+                               kgdb_error(KGDBERR_BADPARAMS);
+                       }
+                       break;
+               }                       /* switch */
+
+               if (errnum != 0)
+                       sprintf(remcomOutBuffer, "E%02d", errnum);
+
+#ifdef KGDB_DEBUG
+               if (kdebug)
+                       printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
+#endif
+
+               /* reply to the request */
+               putpacket(remcomOutBuffer);
+
+       } /* while(1) */
+}
+
+/*
+ * kgdb_init must be called *after* the
+ * monitor is relocated into ram
+ */
+void
+kgdb_init(void)
+{
+       kgdb_serial_init();
+       debugger_exception_handler = handle_exception;
+       initialized = 1;
+
+       putDebugStr("kgdb ready\n");
+       puts("ready\n");
+}
+
+void
+kgdb_error(int errnum)
+{
+       longjmp_on_fault = 0;
+       kgdb_longjmp((long*)error_jmp_buf, errnum);
+       panic("kgdb_error: longjmp failed!\n");
+}
+
+/* Output string in GDB O-packet format if GDB has connected. If nothing
+   output, returns 0 (caller must then handle output). */
+int
+kgdb_output_string (const char* s, unsigned int count)
+{
+       char buffer[512];
+
+       count = (count <= (sizeof(buffer) / 2 - 2))
+               ? count : (sizeof(buffer) / 2 - 2);
+
+       buffer[0] = 'O';
+       mem2hex ((char *)s, &buffer[1], count);
+       putpacket(buffer);
+
+       return 1;
+}
+
+void
+breakpoint(void)
+{
+       if (!initialized) {
+               printf("breakpoint() called b4 kgdb init\n");
+               return;
+       }
+
+       kgdb_breakpoint(0, 0);
+}
+
+int
+do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    printf("Entering KGDB mode via exception handler...\n\n");
+    kgdb_breakpoint(argc - 1, argv + 1);
+    printf("\nReturned from KGDB mode\n");
+    return 0;
+}
+
+#else
+
+int kgdb_not_configured = 1;
+
+#endif /* CFG_CMD_KGDB */
diff --git a/cpu/74xx_7xx/cpu_init.c b/cpu/74xx_7xx/cpu_init.c
new file mode 100644 (file)
index 0000000..2843e26
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * 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
+ */
+
+/*
+ * cpu_init.c - low level cpu init
+ *
+ * there's really nothing going on here yet.  future work area?
+ */
+
+#include <common.h>
+#include <74xx_7xx.h>
+
+/*
+ * Breath some life into the CPU...
+ *
+ * there's basically nothing to do here since the memory controller
+ * isn't on the CPU in this case.
+ */
+void
+cpu_init_f (void)
+{
+       if (get_cpu_type() == CPU_7450) {
+               /* enable the timebase bit in HID0 */
+               set_hid0(get_hid0() | 0x4000000);
+       }
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+       return (0);
+}
diff --git a/cpu/74xx_7xx/speed.c b/cpu/74xx_7xx/speed.c
new file mode 100644 (file)
index 0000000..fe553f1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * (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 <74xx_7xx.h>
+#include <asm/processor.h>
+
+static const int hid1_multipliers_x_10[] = {
+       25,     /* 0000 - 2.5x */
+       75,     /* 0001 - 7.5x */
+       70,     /* 0010 - 7x */
+       10,     /* 0011 - bypass */
+       20,     /* 0100 - 2x */
+       65,     /* 0101 - 6.5x */
+       100,    /* 0110 - 10x */
+       45,     /* 0111 - 4.5x */
+       30,     /* 1000 - 3x */
+       55,     /* 1001 - 5.5x */
+       40,     /* 1010 - 4x */
+       50,     /* 1011 - 5x */
+       80,     /* 1100 - 8x */
+       60,     /* 1101 - 6x */
+       35,     /* 1110 - 3.5x */
+       0       /* 1111 - off */
+};
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2)
+ *
+ * (Approx. GCLK frequency in Hz)
+ */
+
+int get_clocks (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       ulong clock = CFG_BUS_CLK * \
+                     hid1_multipliers_x_10[get_hid1 () >> 28] / 10;
+       gd->cpu_clk = clock;
+       gd->bus_clk = CFG_BUS_CLK;
+
+       return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if 0  /* disabled XXX - use global data instead */
+ulong get_bus_freq (ulong gclk_freq)
+{
+       return CFG_BUS_CLK;
+}
+#endif /* 0 */
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc824x/cpu.c b/cpu/mpc824x/cpu.c
new file mode 100644 (file)
index 0000000..0d822d5
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * (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 <config.h>
+#include <mpc824x.h>
+#include <common.h>
+#include <command.h>
+
+int checkcpu (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       unsigned int pvr = get_pvr ();
+       unsigned int version = pvr >> 16;
+       unsigned char revision;
+       ulong clock = gd->cpu_clk;
+       char buf[32];
+
+       puts ("CPU:   ");
+
+       switch (version) {
+       case CPU_TYPE_8240:
+               puts ("MPC8240");
+               break;
+
+       case CPU_TYPE_8245:
+               puts ("MPC8245");
+               break;
+
+       default:
+               return -1;              /*not valid for this source */
+       }
+
+       CONFIG_READ_BYTE (REVID, revision);
+
+       if (revision) {
+               printf (" Revision %d.%d",
+                       (revision & 0xf0) >> 4,
+                       (revision & 0x0f));
+       } else {
+               return -1;              /* no valid CPU revision info */
+       }
+
+       printf (" at %s MHz:", strmhz (buf, clock));
+
+       printf (" %u kB I-Cache", checkicache () >> 10);
+       printf (" %u kB D-Cache", checkdcache () >> 10);
+
+       puts ("\n");
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache                                                                */
+
+int checkicache (void)
+{
+        /*TODO*/
+        return 128 * 4 * 32;
+};
+
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache                                                                */
+
+int checkdcache (void)
+{
+        /*TODO*/
+        return 128 * 4 * 32;
+
+};
+
+/*------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc,
+                         char *argv[])
+{
+       ulong msr, addr;
+
+       /* Interrupts and MMU off */
+       __asm__ ("mtspr    81, 0");
+
+       /* Interrupts and MMU off */
+       __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+       msr &= ~0x1030;
+       __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+       /*
+        * Trying to execute the next instruction at a non-existing address
+        * should cause a machine check, resulting in reset
+        */
+#ifdef CFG_RESET_ADDRESS
+       addr = CFG_RESET_ADDRESS;
+#else
+       /*
+         * note: when CFG_MONITOR_BASE points to a RAM address,
+         * CFG_MONITOR_BASE - sizeof (ulong) is usually a valid
+         * address. Better pick an address known to be invalid on
+         * your system and assign it to CFG_RESET_ADDRESS.
+         * "(ulong)-1" used to be a good choice for many systems...
+        */
+       addr = CFG_MONITOR_BASE - sizeof (ulong);
+#endif
+       ((void (*)(void)) addr) ();
+       return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ * This is the sys_logic_clk (memory bus) divided by 4
+ */
+unsigned long get_tbclk (void)
+{
+       return ((get_bus_freq (0) + 2L) / 4L);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * The MPC824x has an integrated PCI controller known as the MPC107.
+ * The following are MPC107 Bridge Controller and PCI Support functions
+ *
+ */
+
+/*
+ *  This procedure reads a 32-bit address MPC107 register, and returns
+ *  a 32 bit value.  It swaps the address to little endian before
+ *  writing it to config address, and swaps the value to big endian
+ *  before returning to the caller.
+ */
+unsigned int mpc824x_mpc107_getreg (unsigned int regNum)
+{
+       unsigned int temp;
+
+       /* swap the addr. to little endian */
+       *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum);
+       temp = *(volatile unsigned int *) CHRP_REG_DATA;
+       return PCISWAP (temp);          /* swap the data upon return */
+}
+
+/*
+ *  This procedure writes a 32-bit address MPC107 register.  It swaps
+ *  the address to little endian before writing it to config address.
+ */
+
+void mpc824x_mpc107_setreg (unsigned int regNum, unsigned int regVal)
+{
+       /* swap the addr. to little endian */
+       *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum);
+       *(volatile unsigned int *) CHRP_REG_DATA = PCISWAP (regVal);
+       return;
+}
+
+
+/*
+ *  Write a byte (8 bits) to a memory location.
+ */
+void mpc824x_mpc107_write8 (unsigned int addr, unsigned char data)
+{
+       *(unsigned char *) addr = data;
+       __asm__ ("sync");
+}
+
+/*
+ *  Write a word (16 bits) to a memory location after the value
+ *  has been byte swapped (big to little endian or vice versa)
+ */
+
+void mpc824x_mpc107_write16 (unsigned int address, unsigned short data)
+{
+       *(volatile unsigned short *) address = BYTE_SWAP_16_BIT (data);
+       __asm__ ("sync");
+}
+
+/*
+ *  Write a long word (32 bits) to a memory location after the value
+ *  has been byte swapped (big to little endian or vice versa)
+ */
+
+void mpc824x_mpc107_write32 (unsigned int address, unsigned int data)
+{
+       *(volatile unsigned int *) address = LONGSWAP (data);
+       __asm__ ("sync");
+}
+
+/*
+ *  Read a byte (8 bits) from a memory location.
+ */
+unsigned char mpc824x_mpc107_read8 (unsigned int addr)
+{
+       return *(volatile unsigned char *) addr;
+}
+
+
+/*
+ *  Read a word (16 bits) from a memory location, and byte swap the
+ *  value before returning to the caller.
+ */
+unsigned short mpc824x_mpc107_read16 (unsigned int address)
+{
+       unsigned short retVal;
+
+       retVal = BYTE_SWAP_16_BIT (*(unsigned short *) address);
+       return retVal;
+}
+
+
+/*
+ *  Read a long word (32 bits) from a memory location, and byte
+ *  swap the value before returning to the caller.
+ */
+unsigned int mpc824x_mpc107_read32 (unsigned int address)
+{
+       unsigned int retVal;
+
+       retVal = LONGSWAP (*(unsigned int *) address);
+       return (retVal);
+}
+
+
+/*
+ *  Read a register in the Embedded Utilities Memory Block address
+ *  space.
+ *  Input: regNum - register number + utility base address.  Example,
+ *         the base address of EPIC is 0x40000, the register number
+ *        being passed is 0x40000+the address of the target register.
+ *        (See epic.h for register addresses).
+ *  Output:  The 32 bit little endian value of the register.
+ */
+
+unsigned int mpc824x_eummbar_read (unsigned int regNum)
+{
+       unsigned int temp;
+
+       temp = *(volatile unsigned int *) (EUMBBAR_VAL + regNum);
+       temp = PCISWAP (temp);
+       return temp;
+}
+
+
+/*
+ *  Write a value to a register in the Embedded Utilities Memory
+ *  Block address space.
+ *  Input: regNum - register number + utility base address.  Example,
+ *                  the base address of EPIC is 0x40000, the register
+ *                 number is 0x40000+the address of the target register.
+ *                 (See epic.h for register addresses).
+ *         regVal - value to be written to the register.
+ */
+
+void mpc824x_eummbar_write (unsigned int regNum, unsigned int regVal)
+{
+       *(volatile unsigned int *) (EUMBBAR_VAL + regNum) = PCISWAP (regVal);
+       return;
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc824x/interrupts.c b/cpu/mpc824x/interrupts.c
new file mode 100644 (file)
index 0000000..2011671
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.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 <mpc824x.h>
+#include <asm/processor.h>
+#include <asm/pci_io.h>
+#include <commproc.h>
+#include "drivers/epic.h"
+
+/****************************************************************************/
+
+unsigned decrementer_count;            /* count val for 1e6/HZ microseconds */
+
+static __inline__ unsigned long get_msr (void)
+{
+       unsigned long msr;
+
+       asm volatile ("mfmsr %0":"=r" (msr):);
+
+       return msr;
+}
+
+static __inline__ void set_msr (unsigned long msr)
+{
+       asm volatile ("mtmsr %0"::"r" (msr));
+}
+
+static __inline__ unsigned long get_dec (void)
+{
+       unsigned long val;
+
+       asm volatile ("mfdec %0":"=r" (val):);
+
+       return val;
+}
+
+
+static __inline__ void set_dec (unsigned long val)
+{
+       asm volatile ("mtdec %0"::"r" (val));
+}
+
+
+void enable_interrupts (void)
+{
+       set_msr (get_msr () | MSR_EE);
+}
+
+/* returns flag if MSR_EE was set before */
+int disable_interrupts (void)
+{
+       ulong msr = get_msr ();
+
+       set_msr (msr & ~MSR_EE);
+       return ((msr & MSR_EE) != 0);
+}
+
+/****************************************************************************/
+
+int interrupt_init (void)
+{
+       decrementer_count = (get_bus_freq (0) / 4) / CFG_HZ;
+
+        /*
+         * It's all broken at the moment and I currently don't need
+         * interrupts. If you want to fix it, have a look at the epic
+         * drivers in dink32 v12. They do everthing and Motorola said
+         * I could use the dink source in this project as long as
+         * copyright notices remain intact.
+        */
+
+       epicInit (EPIC_DIRECT_IRQ, 0);
+
+       set_dec (decrementer_count);
+
+       set_msr (get_msr () | MSR_EE);
+
+       return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+       register unsigned long temp;
+
+       pci_readl (CFG_EUMB_ADDR + EPIC_PROC_INT_ACK_REG, temp);
+       sync ();                                        /* i'm not convinced this is needed, but dink source has it */
+       temp &= 0xff;                           /*get vector */
+
+       /*TODO: handle them -... */
+       epicEOI ();
+}
+
+/****************************************************************************/
+
+/*
+ * blank int handlers.
+ */
+
+void
+irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
+{
+}
+
+void irq_free_handler (int vec)
+{
+
+}
+
+/*TODO: some handlers for winbond and 87308 interrupts
+ and what about generic pci inteerupts?
+ vga?
+ */
+
+volatile ulong timestamp = 0;
+
+void timer_interrupt (struct pt_regs *regs)
+{
+       /* Restore Decrementer Count */
+       set_dec (decrementer_count);
+
+       timestamp++;
+
+#if defined(CONFIG_WATCHDOG)
+       if ((timestamp % (CFG_HZ / 2)) == 0) {
+#if defined(CONFIG_OXC)
+               {
+                       extern void oxc_wdt_reset (void);
+
+                       oxc_wdt_reset ();
+               }
+#endif
+       }
+#endif                                                 /* CONFIG_WATCHDOG */
+#if defined(CONFIG_SHOW_ACTIVITY) && defined(CONFIG_OXC)
+       if ((timestamp % (CFG_HZ / 10)) == 0) {
+               {
+                       extern void oxc_toggle_activeled (void);
+
+                       oxc_toggle_activeled ();
+               }
+       }
+#endif
+}
+
+void reset_timer (void)
+{
+       timestamp = 0;
+}
+
+ulong get_timer (ulong base)
+{
+       return (timestamp - base);
+}
+
+void set_timer (ulong t)
+{
+       timestamp = t;
+}
diff --git a/cpu/mpc8260/cpu.c b/cpu/mpc8260/cpu.c
new file mode 100644 (file)
index 0000000..73881ee
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * (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
+ */
+
+/*
+ * CPU specific code for the MPC8260
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ *
+ * modified for 8260 by
+ * Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * added 8260 masks by
+ * Marius Groeger <mag@sysgo.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8260.h>
+#include <asm/processor.h>
+#include <asm/cpm_8260.h>
+
+int checkcpu (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       volatile immap_t *immap = (immap_t *) CFG_IMMR;
+       ulong clock = gd->cpu_clk;
+       uint pvr = get_pvr ();
+       uint immr, rev, m, k;
+       char buf[32];
+
+       puts ("CPU:   ");
+
+       if (((pvr >> 16) & 0xff) != 0x81)
+               return -1;      /* whoops! not an MPC8260 */
+       rev = pvr & 0xff;
+
+       immr = immap->im_memctl.memc_immr;
+       if ((immr & IMMR_ISB_MSK) != CFG_IMMR)
+               return -1;      /* whoops! someone moved the IMMR */
+
+       printf ("MPC8260 (Rev %02x, Mask ", rev);
+
+       /*
+        * the bottom 16 bits of the immr are the Part Number and Mask Number
+        * (4-34); the 16 bits at PROFF_REVNUM (0x8af0) in dual port ram is the
+        * RISC Microcode Revision Number (13-10).
+        * For the 8260, Motorola doesn't include the Microcode Revision
+        * in the mask.
+        */
+       m = immr & (IMMR_PARTNUM_MSK | IMMR_MASKNUM_MSK);
+       k = *((ushort *) & immap->im_dprambase[PROFF_REVNUM]);
+
+       switch (m) {
+       case 0x0000:
+               printf ("0.2 2J24M");
+               break;
+       case 0x0010:
+               printf ("A.0 K22A");
+               break;
+       case 0x0011:
+               printf ("A.1 1K22A-XC");
+               break;
+       case 0x0001:
+               printf ("B.1 1K23A");
+               break;
+       case 0x0021:
+               printf ("B.2 2K23A-XC");
+               break;
+       case 0x0023:
+               printf ("B.3 3K23A");
+               break;
+       case 0x0024:
+               printf ("C.2 6K23A");
+               break;
+       case 0x0060:
+               printf ("A.0(A) 2K25A");
+               break;
+       default:
+               printf ("unknown [immr=0x%04x,k=0x%04x]", m, k);
+               break;
+       }
+
+       printf (") at %s MHz\n", strmhz (buf, clock));
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/* configures a UPM by writing into the UPM RAM array                       */
+/* uses bank 11 and a dummy physical address (=BRx_BA_MSK)                  */
+/* NOTE: the physical address chosen must not overlap into any other area    */
+/* mapped by the memory controller because bank 11 has the lowest priority   */
+
+void upmconfig (uint upm, uint * table, uint size)
+{
+       volatile immap_t *immap = (immap_t *) CFG_IMMR;
+       volatile memctl8260_t *memctl = &immap->im_memctl;
+       volatile uchar *dummy = (uchar *) BRx_BA_MSK;   /* set all BA bits */
+       uint i;
+
+       /* first set up bank 11 to reference the correct UPM at a dummy address */
+
+       memctl->memc_or11 = ORxU_AM_MSK;        /* set all AM bits */
+
+       switch (upm) {
+
+       case UPMA:
+               memctl->memc_br11 =
+                       ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMA |
+                       BRx_V;
+               memctl->memc_mamr = MxMR_OP_WARR;
+               break;
+
+       case UPMB:
+               memctl->memc_br11 =
+                       ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMB |
+                       BRx_V;
+               memctl->memc_mbmr = MxMR_OP_WARR;
+               break;
+
+       case UPMC:
+               memctl->memc_br11 =
+                       ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMC |
+                       BRx_V;
+               memctl->memc_mcmr = MxMR_OP_WARR;
+               break;
+
+       default:
+               panic ("upmconfig passed invalid UPM number (%u)\n", upm);
+               break;
+
+       }
+
+       /*
+        * at this point, the dummy address is set up to access the selected UPM,
+        * the MAD pointer is zero, and the MxMR OP is set for writing to RAM
+        *
+        * now we simply load the mdr with each word and poke the dummy address.
+        * the MAD is incremented on each access.
+        */
+
+       for (i = 0; i < size; i++) {
+               memctl->memc_mdr = table[i];
+               *dummy = 0;
+       }
+
+       /* now kill bank 11 */
+       memctl->memc_br11 = 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+do_reset (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
+{
+       ulong msr, addr;
+
+       volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+       immap->im_clkrst.car_rmr = RMR_CSRE;    /* Checkstop Reset enable */
+
+       /* Interrupts and MMU off */
+       __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+       msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+       __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+       /*
+        * Trying to execute the next instruction at a non-existing address
+        * should cause a machine check, resulting in reset
+        */
+#ifdef CFG_RESET_ADDRESS
+       addr = CFG_RESET_ADDRESS;
+#else
+       /*
+        * note: when CFG_MONITOR_BASE points to a RAM address, CFG_MONITOR_BASE
+        * - sizeof (ulong) is usually a valid address. Better pick an address
+        * known to be invalid on your system and assign it to CFG_RESET_ADDRESS.
+        */
+       addr = CFG_MONITOR_BASE - sizeof (ulong);
+#endif
+       ((void (*)(void)) addr) ();
+       return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       ulong tbclk;
+
+       tbclk = (gd->bus_clk + 3L) / 4L;
+
+       return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+       int re_enable = disable_interrupts ();
+
+       reset_8260_watchdog ((immap_t *) CFG_IMMR);
+       if (re_enable)
+               enable_interrupts ();
+}
+#endif /* CONFIG_WATCHDOG */
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc8260/interrupts.c b/cpu/mpc8260/interrupts.c
new file mode 100644 (file)
index 0000000..d804408
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * (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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8260.h>
+#include <mpc8260_irq.h>
+#include <asm/processor.h>
+
+/****************************************************************************/
+
+unsigned decrementer_count;            /* count val for 1e6/HZ microseconds */
+
+struct irq_action {
+       interrupt_handler_t *handler;
+       void *arg;
+       ulong count;
+};
+
+static struct irq_action irq_handlers[NR_IRQS];
+
+static ulong ppc_cached_irq_mask[NR_MASK_WORDS];
+
+/****************************************************************************/
+/* this section was ripped out of arch/ppc/kernel/ppc8260_pic.c in the     */
+/* Linux/PPC 2.4.x source. There was no copyright notice in that file.     */
+
+/* The 8260 internal interrupt controller.  It is usually
+ * the only interrupt controller.
+ * There are two 32-bit registers (high/low) for up to 64
+ * possible interrupts.
+ *
+ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
+ * in a simple arithmetic fashion to mask or pending registers.
+ * That is, interrupt 4 does not map to bit position 4.
+ * We create two tables, indexed by vector number, to indicate
+ * which register to use and which bit in the register to use.
+ */
+static u_char irq_to_siureg[] = {
+       1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static u_char irq_to_siubit[] = {
+       31, 16, 17, 18, 19, 20, 21, 22,
+       23, 24, 25, 26, 27, 28, 29, 30,
+       29, 30, 16, 17, 18, 19, 20, 21,
+       22, 23, 24, 25, 26, 27, 28, 31,
+       0, 1, 2, 3, 4, 5, 6, 7,
+       8, 9, 10, 11, 12, 13, 14, 15,
+       15, 14, 13, 12, 11, 10, 9, 8,
+       7, 6, 5, 4, 3, 2, 1, 0
+};
+
+static void m8260_mask_irq (unsigned int irq_nr)
+{
+       volatile immap_t *immr = (immap_t *) CFG_IMMR;
+       int bit, word;
+       volatile uint *simr;
+
+       bit = irq_to_siubit[irq_nr];
+       word = irq_to_siureg[irq_nr];
+
+       simr = &(immr->im_intctl.ic_simrh);
+       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+       simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_unmask_irq (unsigned int irq_nr)
+{
+       volatile immap_t *immr = (immap_t *) CFG_IMMR;
+       int bit, word;
+       volatile uint *simr;
+
+       bit = irq_to_siubit[irq_nr];
+       word = irq_to_siureg[irq_nr];
+
+       simr = &(immr->im_intctl.ic_simrh);
+       ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+       simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_mask_and_ack (unsigned int irq_nr)
+{
+       volatile immap_t *immr = (immap_t *) CFG_IMMR;
+       int bit, word;
+       volatile uint *simr, *sipnr;
+
+       bit = irq_to_siubit[irq_nr];
+       word = irq_to_siureg[irq_nr];
+
+       simr = &(immr->im_intctl.ic_simrh);
+       sipnr = &(immr->im_intctl.ic_sipnrh);
+       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+       simr[word] = ppc_cached_irq_mask[word];
+       sipnr[word] = 1 << (31 - bit);
+}
+
+static int m8260_get_irq (struct pt_regs *regs)
+{
+       volatile immap_t *immr = (immap_t *) CFG_IMMR;
+       int irq;
+       unsigned long bits;
+
+       /* For MPC8260, read the SIVEC register and shift the bits down
+        * to get the irq number.         */
+       bits = immr->im_intctl.ic_sivec;
+       irq = bits >> 26;
+       return irq;
+}
+
+/* end of code ripped out of arch/ppc/kernel/ppc8260_pic.c                 */
+/****************************************************************************/
+
+static __inline__ unsigned long get_msr (void)
+{
+       unsigned long msr;
+
+       __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+       return msr;
+}
+
+static __inline__ void set_msr (unsigned long msr)
+{
+       __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+}
+
+static __inline__ unsigned long get_dec (void)
+{
+       unsigned long val;
+
+       __asm__ __volatile__ ("mfdec %0":"=r" (val):);
+
+       return val;
+}
+
+static __inline__ void set_dec (unsigned long val)
+{
+       __asm__ __volatile__ ("mtdec %0"::"r" (val));
+}
+
+void enable_interrupts (void)
+{
+       set_msr (get_msr () | MSR_EE);
+}
+
+/* returns flag if MSR_EE was set before */
+int disable_interrupts (void)
+{
+       ulong msr = get_msr ();
+
+       set_msr (msr & ~MSR_EE);
+       return ((msr & MSR_EE) != 0);
+}
+
+/****************************************************************************/
+
+int interrupt_init (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       volatile immap_t *immr = (immap_t *) CFG_IMMR;
+
+       decrementer_count = (gd->bus_clk / 4) / CFG_HZ;
+
+       /* Initialize the default interrupt mapping priorities */
+       immr->im_intctl.ic_sicr = 0;
+       immr->im_intctl.ic_siprr = 0x05309770;
+       immr->im_intctl.ic_scprrh = 0x05309770;
+       immr->im_intctl.ic_scprrl = 0x05309770;
+
+       /* disable all interrupts and clear all pending bits */
+       immr->im_intctl.ic_simrh = ppc_cached_irq_mask[0] = 0;
+       immr->im_intctl.ic_simrl = ppc_cached_irq_mask[1] = 0;
+       immr->im_intctl.ic_sipnrh = 0xffffffff;
+       immr->im_intctl.ic_sipnrl = 0xffffffff;
+
+       set_dec (decrementer_count);
+
+       set_msr (get_msr () | MSR_EE);
+
+       return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+       int irq, unmask = 1;
+
+       irq = m8260_get_irq (regs);
+
+       m8260_mask_and_ack (irq);
+
+       set_msr (get_msr () | MSR_EE);
+
+       if (irq_handlers[irq].handler != NULL)
+               (*irq_handlers[irq].handler) (irq_handlers[irq].arg);
+       else {
+               printf ("\nBogus External Interrupt IRQ %d\n", irq);
+               /*
+                * turn off the bogus interrupt, otherwise it
+                * might repeat forever
+                */
+               unmask = 0;
+       }
+
+       if (unmask)
+               m8260_unmask_irq (irq);
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free an interrupt handler.
+ */
+
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+       if (irq < 0 || irq >= NR_IRQS) {
+               printf ("irq_install_handler: bad irq number %d\n", irq);
+               return;
+       }
+
+       if (irq_handlers[irq].handler != NULL)
+               printf ("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+                               (ulong) handler, (ulong) irq_handlers[irq].handler);
+
+       irq_handlers[irq].handler = handler;
+       irq_handlers[irq].arg = arg;
+
+       m8260_unmask_irq (irq);
+}
+
+void irq_free_handler (int irq)
+{
+       if (irq < 0 || irq >= NR_IRQS) {
+               printf ("irq_free_handler: bad irq number %d\n", irq);
+               return;
+       }
+
+       m8260_mask_irq (irq);
+
+       irq_handlers[irq].handler = NULL;
+       irq_handlers[irq].arg = NULL;
+}
+
+/****************************************************************************/
+
+volatile ulong timestamp = 0;
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt (struct pt_regs *regs)
+{
+#if defined(CONFIG_WATCHDOG) || defined(CFG_HYMOD_DBLEDS)
+       volatile immap_t *immr = (immap_t *) CFG_IMMR;
+#endif                                                 /* CONFIG_WATCHDOG */
+
+       /* Restore Decrementer Count */
+       set_dec (decrementer_count);
+
+       timestamp++;
+
+#if defined(CONFIG_WATCHDOG) || \
+    defined(CFG_CMA_LCD_HEARTBEAT) || \
+    defined(CFG_HYMOD_DBLEDS)
+
+       if ((timestamp % CFG_HZ) == 0) {
+#if defined(CFG_CMA_LCD_HEARTBEAT)
+               extern void lcd_heartbeat (void);
+#endif                                                 /* CFG_CMA_LCD_HEARTBEAT */
+#if defined(CFG_HYMOD_DBLEDS)
+               volatile iop8260_t *iop = &immr->im_ioport;
+               static int shift = 0;
+#endif                                                 /* CFG_HYMOD_DBLEDS */
+
+#if defined(CFG_CMA_LCD_HEARTBEAT)
+               lcd_heartbeat ();
+#endif                                                 /* CFG_CMA_LCD_HEARTBEAT */
+
+#if defined(CONFIG_WATCHDOG)
+               reset_8260_watchdog (immr);
+#endif                                                 /* CONFIG_WATCHDOG */
+
+#if defined(CFG_HYMOD_DBLEDS)
+               /* hymod daughter board LEDs */
+               if (++shift > 3)
+                       shift = 0;
+               iop->iop_pdatd =
+                               (iop->iop_pdatd & ~0x0f000000) | (1 << (24 + shift));
+#endif                                                 /* CFG_HYMOD_DBLEDS */
+       }
+#endif                                                 /* CONFIG_WATCHDOG || CFG_CMA_LCD_HEARTBEAT */
+}
+
+/****************************************************************************/
+
+void reset_timer (void)
+{
+       timestamp = 0;
+}
+
+ulong get_timer (ulong base)
+{
+       return (timestamp - base);
+}
+
+void set_timer (ulong t)
+{
+       timestamp = t;
+}
+
+/****************************************************************************/
+
+#if (CONFIG_COMMANDS & CFG_CMD_IRQ)
+
+/* ripped this out of ppc4xx/interrupts.c */
+
+/*******************************************************************************
+*
+* irqinfo - print information about PCI devices
+*
+*/
+void
+do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
+{
+       int irq, re_enable;
+
+       re_enable = disable_interrupts ();
+
+       printf ("\nInterrupt-Information:\n");
+       printf ("Nr  Routine   Arg       Count\n");
+
+       for (irq = 0; irq < 32; irq++)
+               if (irq_handlers[irq].handler != NULL)
+                       printf ("%02d  %08lx  %08lx  %ld\n", irq,
+                                       (ulong) irq_handlers[irq].handler,
+                                       (ulong) irq_handlers[irq].arg,
+                                       irq_handlers[irq].count);
+
+       if (re_enable)
+               enable_interrupts ();
+}
+
+#endif                                                 /* CONFIG_COMMANDS & CFG_CMD_IRQ */
diff --git a/cpu/mpc8260/serial_scc.c b/cpu/mpc8260/serial_scc.c
new file mode 100644 (file)
index 0000000..ca76302
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * (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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00.
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SCC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+
+#if defined(CONFIG_CONS_ON_SCC)
+
+#if CONFIG_CONS_INDEX == 1     /* Console on SCC1 */
+
+#define SCC_INDEX              0
+#define PROFF_SCC              PROFF_SCC1
+#define CMXSCR_MASK            (CMXSCR_GR1|CMXSCR_SC1|\
+                                       CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define CMXSCR_VALUE           (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define CPM_CR_SCC_PAGE                CPM_CR_SCC1_PAGE
+#define CPM_CR_SCC_SBLOCK      CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 2   /* Console on SCC2 */
+
+#define SCC_INDEX              1
+#define PROFF_SCC              PROFF_SCC2
+#define CMXSCR_MASK            (CMXSCR_GR2|CMXSCR_SC2|\
+                                       CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define CMXSCR_VALUE           (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define CPM_CR_SCC_PAGE                CPM_CR_SCC2_PAGE
+#define CPM_CR_SCC_SBLOCK      CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 3   /* Console on SCC3 */
+
+#define SCC_INDEX              2
+#define PROFF_SCC              PROFF_SCC3
+#define CMXSCR_MASK            (CMXSCR_GR3|CMXSCR_SC3|\
+                                       CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define CMXSCR_VALUE           (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define CPM_CR_SCC_PAGE                CPM_CR_SCC3_PAGE
+#define CPM_CR_SCC_SBLOCK      CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 4   /* Console on SCC4 */
+
+#define SCC_INDEX              3
+#define PROFF_SCC              PROFF_SCC4
+#define CMXSCR_MASK            (CMXSCR_GR4|CMXSCR_SC4|\
+                                       CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define CMXSCR_VALUE           (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define CPM_CR_SCC_PAGE                CPM_CR_SCC4_PAGE
+#define CPM_CR_SCC_SBLOCK      CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+int serial_init (void)
+{
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile scc_t *sp;
+       volatile scc_uart_t *up;
+       volatile cbd_t *tbdf, *rbdf;
+       volatile cpm8260_t *cp = &(im->im_cpm);
+       uint    dpaddr;
+
+       /* initialize pointers to SCC */
+
+       sp = (scc_t *) &(im->im_scc[SCC_INDEX]);
+       up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+
+       /* Disable transmitter/receiver.
+       */
+       sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       /* put the SCC channel into NMSI (non multiplexd serial interface)
+        * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+        */
+       im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr&~CMXSCR_MASK)|CMXSCR_VALUE;
+
+       /* Set up the baud rate generator.
+       */
+       serial_setbrg ();
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+        * damm: allocating space after the two buffers for rx/tx data
+        */
+
+       dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+       rbdf->cbd_bufaddr = (uint) (rbdf+2);
+       rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+       tbdf = rbdf + 1;
+       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+       tbdf->cbd_sc = BD_SC_WRAP;
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->scc_genscc.scc_rbase = dpaddr;
+       up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+       up->scc_genscc.scc_rfcr = CPMFCR_EB;
+       up->scc_genscc.scc_tfcr = CPMFCR_EB;
+       up->scc_genscc.scc_mrblr = 1;
+       up->scc_maxidl = 0;
+       up->scc_brkcr = 1;
+       up->scc_parec = 0;
+       up->scc_frmec = 0;
+       up->scc_nosec = 0;
+       up->scc_brkec = 0;
+       up->scc_uaddr1 = 0;
+       up->scc_uaddr2 = 0;
+       up->scc_toseq = 0;
+       up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+       up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+       up->scc_rccm = 0xc0ff;
+
+       /* Mask all interrupts and remove anything pending.
+       */
+       sp->scc_sccm = 0;
+       sp->scc_scce = 0xffff;
+
+       /* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+       */
+       sp->scc_gsmrh = SCC_GSMRH_RFW;  /* 8 bit FIFO */
+       sp->scc_gsmrl = \
+               SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+       /* Set CTS flow control, 1 stop bit, 8 bit character length,
+        * normal async UART mode, no parity
+        */
+       sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL;
+
+       /* execute the "Init Rx and Tx params" CP command.
+       */
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK,
+                                       0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       /* Enable transmitter/receiver.
+       */
+       sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+       return (0);
+}
+
+void
+serial_setbrg (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_USE_EXTC)
+       m8260_cpm_extcbrg(SCC_INDEX, gd->baudrate,
+               CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+       m8260_cpm_setbrg(SCC_INDEX, gd->baudrate);
+#endif
+}
+
+void
+serial_putc(const char c)
+{
+       volatile scc_uart_t     *up;
+       volatile cbd_t          *tbdf;
+        volatile immap_t       *im;
+
+       if (c == '\n')
+               serial_putc ('\r');
+
+        im = (immap_t *)CFG_IMMR;
+       up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+       tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase];
+
+       /* Wait for last character to go.
+        */
+       while (tbdf->cbd_sc & BD_SC_READY)
+               ;
+
+       /* Load the character into the transmit buffer.
+        */
+       *(volatile char *)tbdf->cbd_bufaddr = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+serial_puts (const char *s)
+{
+       while (*s) {
+               serial_putc (*s++);
+       }
+}
+
+int
+serial_getc(void)
+{
+       volatile cbd_t          *rbdf;
+       volatile scc_uart_t     *up;
+        volatile immap_t       *im;
+       unsigned char           c;
+
+        im = (immap_t *)CFG_IMMR;
+       up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+       rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+       /* Wait for character to show up.
+        */
+       while (rbdf->cbd_sc & BD_SC_EMPTY)
+               ;
+
+       /* Grab the char and clear the buffer again.
+        */
+       c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return (c);
+}
+
+int
+serial_tstc()
+{
+       volatile cbd_t          *rbdf;
+       volatile scc_uart_t     *up;
+        volatile immap_t       *im;
+
+        im = (immap_t *)CFG_IMMR;
+       up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+       rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+       return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0);
+}
+
+#endif /* CONFIG_CONS_ON_SCC */
+
+#if defined(CONFIG_KGDB_ON_SCC)
+
+#if defined(CONFIG_CONS_ON_SCC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX
+#error Whoops! serial console and kgdb are on the same scc serial port
+#endif
+
+#if CONFIG_KGDB_INDEX == 1     /* KGDB Port on SCC1 */
+
+#define KGDB_SCC_INDEX         0
+#define KGDB_PROFF_SCC         PROFF_SCC1
+#define KGDB_CMXSCR_MASK       (CMXSCR_GR1|CMXSCR_SC1|\
+                                       CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define KGDB_CMXSCR_VALUE      (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define KGDB_CPM_CR_SCC_PAGE   CPM_CR_SCC1_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 2   /* KGDB Port on SCC2 */
+
+#define KGDB_SCC_INDEX         1
+#define KGDB_PROFF_SCC         PROFF_SCC2
+#define KGDB_CMXSCR_MASK       (CMXSCR_GR2|CMXSCR_SC2|\
+                                       CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define KGDB_CMXSCR_VALUE      (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define KGDB_CPM_CR_SCC_PAGE   CPM_CR_SCC2_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 3   /* KGDB Port on SCC3 */
+
+#define KGDB_SCC_INDEX         2
+#define KGDB_PROFF_SCC         PROFF_SCC3
+#define KGDB_CMXSCR_MASK       (CMXSCR_GR3|CMXSCR_SC3|\
+                                       CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define KGDB_CMXSCR_VALUE      (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define KGDB_CPM_CR_SCC_PAGE   CPM_CR_SCC3_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 4   /* KGDB Port on SCC4 */
+
+#define KGDB_SCC_INDEX         3
+#define KGDB_PROFF_SCC         PROFF_SCC4
+#define KGDB_CMXSCR_MASK       (CMXSCR_GR4|CMXSCR_SC4|\
+                                       CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define KGDB_CMXSCR_VALUE      (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define KGDB_CPM_CR_SCC_PAGE   CPM_CR_SCC4_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "kgdb serial port not correctly defined"
+
+#endif
+
+void
+kgdb_serial_init (void)
+{
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile scc_t *sp;
+       volatile scc_uart_t *up;
+       volatile cbd_t *tbdf, *rbdf;
+       volatile cpm8260_t *cp = &(im->im_cpm);
+       uint dpaddr, speed = CONFIG_KGDB_BAUDRATE;
+       char *s, *e;
+
+       if ((s = getenv("kgdbrate")) != NULL && *s != '\0') {
+               ulong rate = simple_strtoul(s, &e, 10);
+               if (e > s && *e == '\0')
+                       speed = rate;
+       }
+
+       /* initialize pointers to SCC */
+
+       sp = (scc_t *) &(im->im_scc[KGDB_SCC_INDEX]);
+       up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+
+       /* Disable transmitter/receiver.
+       */
+       sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       /* put the SCC channel into NMSI (non multiplexd serial interface)
+        * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+        */
+       im->im_cpmux.cmx_scr = \
+               (im->im_cpmux.cmx_scr & ~KGDB_CMXSCR_MASK) | KGDB_CMXSCR_VALUE;
+
+       /* Set up the baud rate generator.
+       */
+#if defined(CONFIG_KGDB_USE_EXTC)
+       m8260_cpm_extcbrg(KGDB_SCC_INDEX, speed,
+               CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL);
+#else
+       m8260_cpm_setbrg(KGDB_SCC_INDEX, speed);
+#endif
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+        * damm: allocating space after the two buffers for rx/tx data
+        */
+
+       dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+       rbdf->cbd_bufaddr = (uint) (rbdf+2);
+       rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+       tbdf = rbdf + 1;
+       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+       tbdf->cbd_sc = BD_SC_WRAP;
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->scc_genscc.scc_rbase = dpaddr;
+       up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+       up->scc_genscc.scc_rfcr = CPMFCR_EB;
+       up->scc_genscc.scc_tfcr = CPMFCR_EB;
+       up->scc_genscc.scc_mrblr = 1;
+       up->scc_maxidl = 0;
+       up->scc_brkcr = 1;
+       up->scc_parec = 0;
+       up->scc_frmec = 0;
+       up->scc_nosec = 0;
+       up->scc_brkec = 0;
+       up->scc_uaddr1 = 0;
+       up->scc_uaddr2 = 0;
+       up->scc_toseq = 0;
+       up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+       up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+       up->scc_rccm = 0xc0ff;
+
+       /* Mask all interrupts and remove anything pending.
+       */
+       sp->scc_sccm = 0;
+       sp->scc_scce = 0xffff;
+
+       /* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+       */
+       sp->scc_gsmrh = SCC_GSMRH_RFW;  /* 8 bit FIFO */
+       sp->scc_gsmrl = \
+               SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+       /* Set CTS flow control, 1 stop bit, 8 bit character length,
+        * normal async UART mode, no parity
+        */
+       sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL;
+
+       /* execute the "Init Rx and Tx params" CP command.
+       */
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SCC_PAGE, KGDB_CPM_CR_SCC_SBLOCK,
+                                       0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       /* Enable transmitter/receiver.
+       */
+       sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+       printf("SCC%d at %dbps ", CONFIG_KGDB_INDEX, speed);
+}
+
+void
+putDebugChar(const char c)
+{
+       volatile scc_uart_t     *up;
+       volatile cbd_t          *tbdf;
+        volatile immap_t       *im;
+
+       if (c == '\n')
+               putDebugChar ('\r');
+
+        im = (immap_t *)CFG_IMMR;
+       up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+       tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase];
+
+       /* Wait for last character to go.
+        */
+       while (tbdf->cbd_sc & BD_SC_READY)
+               ;
+
+       /* Load the character into the transmit buffer.
+        */
+       *(volatile char *)tbdf->cbd_bufaddr = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+putDebugStr (const char *s)
+{
+       while (*s) {
+               putDebugChar (*s++);
+       }
+}
+
+int
+getDebugChar(void)
+{
+       volatile cbd_t          *rbdf;
+       volatile scc_uart_t     *up;
+        volatile immap_t       *im;
+       unsigned char           c;
+
+        im = (immap_t *)CFG_IMMR;
+       up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+       rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+       /* Wait for character to show up.
+        */
+       while (rbdf->cbd_sc & BD_SC_EMPTY)
+               ;
+
+       /* Grab the char and clear the buffer again.
+        */
+       c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return (c);
+}
+
+void
+kgdb_interruptible(int yes)
+{
+       return;
+}
+
+#endif /* CONFIG_KGDB_ON_SCC */
diff --git a/cpu/mpc8260/serial_smc.c b/cpu/mpc8260/serial_smc.c
new file mode 100644 (file)
index 0000000..b0e1ce4
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * (C) Copyright 2000, 2001, 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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
+ * changes based on the file arch/ppc/mbxboot/m8260_tty.c from the
+ * Linux/PPC sources (m8260_tty.c had no copyright info in it).
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+
+#if defined(CONFIG_CONS_ON_SMC)
+
+#if CONFIG_CONS_INDEX == 1     /* Console on SMC1 */
+
+#define SMC_INDEX              0
+#define PROFF_SMC_BASE         PROFF_SMC1_BASE
+#define PROFF_SMC              PROFF_SMC1
+#define CPM_CR_SMC_PAGE                CPM_CR_SMC1_PAGE
+#define CPM_CR_SMC_SBLOCK      CPM_CR_SMC1_SBLOCK
+#define CMXSMR_MASK            (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK)
+#define CMXSMR_VALUE           CMXSMR_SMC1CS_BRG7
+
+#elif CONFIG_CONS_INDEX == 2   /* Console on SMC2 */
+
+#define SMC_INDEX              1
+#define PROFF_SMC_BASE         PROFF_SMC2_BASE
+#define PROFF_SMC              PROFF_SMC2
+#define CPM_CR_SMC_PAGE                CPM_CR_SMC2_PAGE
+#define CPM_CR_SMC_SBLOCK      CPM_CR_SMC2_SBLOCK
+#define CMXSMR_MASK            (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK)
+#define CMXSMR_VALUE           CMXSMR_SMC2CS_BRG8
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+/* map rs_table index to baud rate generator index */
+static unsigned char brg_map[] = {
+       6,      /* BRG7 for SMC1 */
+       7,      /* BRG8 for SMC2 */
+       0,      /* BRG1 for SCC1 */
+       1,      /* BRG1 for SCC2 */
+       2,      /* BRG1 for SCC3 */
+       3,      /* BRG1 for SCC4 */
+};
+
+int serial_init (void)
+{
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile smc_t *sp;
+       volatile smc_uart_t *up;
+       volatile cbd_t *tbdf, *rbdf;
+       volatile cpm8260_t *cp = &(im->im_cpm);
+       uint    dpaddr;
+
+       /* initialize pointers to SMC */
+
+       sp = (smc_t *) &(im->im_smc[SMC_INDEX]);
+       *(ushort *)(&im->im_dprambase[PROFF_SMC_BASE]) = PROFF_SMC;
+       up = (smc_uart_t *)&im->im_dprambase[PROFF_SMC];
+
+       /* Disable transmitter/receiver.
+       */
+       sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+       /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+        * damm: allocating space after the two buffers for rx/tx data
+        */
+
+       dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+       rbdf->cbd_bufaddr = (uint) (rbdf+2);
+       rbdf->cbd_sc = 0;
+       tbdf = rbdf + 1;
+       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+       tbdf->cbd_sc = 0;
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->smc_rbase = dpaddr;
+       up->smc_tbase = dpaddr+sizeof(cbd_t);
+       up->smc_rfcr = CPMFCR_EB;
+       up->smc_tfcr = CPMFCR_EB;
+       up->smc_brklen = 0;
+       up->smc_brkec = 0;
+       up->smc_brkcr = 0;
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+       /* Mask all interrupts and remove anything pending.
+       */
+       sp->smc_smcm = 0;
+       sp->smc_smce = 0xff;
+
+       /* put the SMC channel into NMSI (non multiplexd serial interface)
+        * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17).
+        */
+       im->im_cpmux.cmx_smr = (im->im_cpmux.cmx_smr&~CMXSMR_MASK)|CMXSMR_VALUE;
+
+       /* Set up the baud rate generator.
+       */
+       serial_setbrg ();
+
+       /* Make the first buffer the only buffer.
+       */
+       tbdf->cbd_sc |= BD_SC_WRAP;
+       rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+       /* Single character receive.
+       */
+       up->smc_mrblr = 1;
+       up->smc_maxidl = 0;
+
+       /* Initialize Tx/Rx parameters.
+       */
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC_PAGE, CPM_CR_SMC_SBLOCK,
+                                       0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       /* Enable transmitter/receiver.
+       */
+       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+       return (0);
+}
+
+void
+serial_setbrg (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_USE_EXTC)
+       m8260_cpm_extcbrg(brg_map[SMC_INDEX], gd->baudrate,
+               CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+       m8260_cpm_setbrg(brg_map[SMC_INDEX], gd->baudrate);
+#endif
+}
+
+void
+serial_putc(const char c)
+{
+       volatile cbd_t          *tbdf;
+       volatile char           *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+
+       if (c == '\n')
+               serial_putc ('\r');
+
+       up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+
+       tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase];
+
+       /* Wait for last character to go.
+       */
+       buf = (char *)tbdf->cbd_bufaddr;
+       while (tbdf->cbd_sc & BD_SC_READY)
+               ;
+
+       *buf = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+serial_puts (const char *s)
+{
+       while (*s) {
+               serial_putc (*s++);
+       }
+}
+
+int
+serial_getc(void)
+{
+       volatile cbd_t          *rbdf;
+       volatile unsigned char  *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       unsigned char           c;
+
+       up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+
+       rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase];
+
+       /* Wait for character to show up.
+       */
+       buf = (unsigned char *)rbdf->cbd_bufaddr;
+       while (rbdf->cbd_sc & BD_SC_EMPTY)
+               ;
+       c = *buf;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return(c);
+}
+
+int
+serial_tstc()
+{
+       volatile cbd_t          *rbdf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+
+       up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+
+       rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase];
+
+       return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
+#endif /* CONFIG_CONS_ON_SMC */
+
+#if defined(CONFIG_KGDB_ON_SMC)
+
+#if defined(CONFIG_CONS_ON_SMC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX
+#error Whoops! serial console and kgdb are on the same smc serial port
+#endif
+
+#if CONFIG_KGDB_INDEX == 1     /* KGDB Port on SMC1 */
+
+#define KGDB_SMC_INDEX         0
+#define KGDB_PROFF_SMC_BASE    PROFF_SMC1_BASE
+#define KGDB_PROFF_SMC         PROFF_SMC1
+#define KGDB_CPM_CR_SMC_PAGE   CPM_CR_SMC1_PAGE
+#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK
+#define KGDB_CMXSMR_MASK       (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK)
+#define KGDB_CMXSMR_VALUE      CMXSMR_SMC1CS_BRG7
+
+#elif CONFIG_KGDB_INDEX == 2   /* KGDB Port on SMC2 */
+
+#define KGDB_SMC_INDEX         1
+#define KGDB_PROFF_SMC_BASE    PROFF_SMC2_BASE
+#define KGDB_PROFF_SMC         PROFF_SMC2
+#define KGDB_CPM_CR_SMC_PAGE   CPM_CR_SMC2_PAGE
+#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK
+#define KGDB_CMXSMR_MASK       (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK)
+#define KGDB_CMXSMR_VALUE      CMXSMR_SMC2CS_BRG8
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+void
+kgdb_serial_init (void)
+{
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile smc_t *sp;
+       volatile smc_uart_t *up;
+       volatile cbd_t *tbdf, *rbdf;
+       volatile cpm8260_t *cp = &(im->im_cpm);
+       uint dpaddr, speed = CONFIG_KGDB_BAUDRATE;
+       char *s, *e;
+
+       if ((s = getenv("kgdbrate")) != NULL && *s != '\0') {
+               ulong rate = simple_strtoul(s, &e, 10);
+               if (e > s && *e == '\0')
+                       speed = rate;
+       }
+
+       /* initialize pointers to SMC */
+
+       sp = (smc_t *) &(im->im_smc[KGDB_SMC_INDEX]);
+       *(ushort *)(&im->im_dprambase[KGDB_PROFF_SMC_BASE]) = KGDB_PROFF_SMC;
+       up = (smc_uart_t *)&im->im_dprambase[KGDB_PROFF_SMC];
+
+       /* Disable transmitter/receiver.
+       */
+       sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+       /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+        * damm: allocating space after the two buffers for rx/tx data
+        */
+
+       dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+       rbdf->cbd_bufaddr = (uint) (rbdf+2);
+       rbdf->cbd_sc = 0;
+       tbdf = rbdf + 1;
+       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+       tbdf->cbd_sc = 0;
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->smc_rbase = dpaddr;
+       up->smc_tbase = dpaddr+sizeof(cbd_t);
+       up->smc_rfcr = CPMFCR_EB;
+       up->smc_tfcr = CPMFCR_EB;
+       up->smc_brklen = 0;
+       up->smc_brkec = 0;
+       up->smc_brkcr = 0;
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+       /* Mask all interrupts and remove anything pending.
+       */
+       sp->smc_smcm = 0;
+       sp->smc_smce = 0xff;
+
+       /* put the SMC channel into NMSI (non multiplexd serial interface)
+        * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17).
+        */
+       im->im_cpmux.cmx_smr =
+               (im->im_cpmux.cmx_smr & ~KGDB_CMXSMR_MASK) | KGDB_CMXSMR_VALUE;
+
+       /* Set up the baud rate generator.
+       */
+#if defined(CONFIG_KGDB_USE_EXTC)
+       m8260_cpm_extcbrg(KGDB_SMC_INDEX, speed,
+               CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL);
+#else
+       m8260_cpm_setbrg(KGDB_SMC_INDEX, speed);
+#endif
+
+       /* Make the first buffer the only buffer.
+       */
+       tbdf->cbd_sc |= BD_SC_WRAP;
+       rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+       /* Single character receive.
+       */
+       up->smc_mrblr = 1;
+       up->smc_maxidl = 0;
+
+       /* Initialize Tx/Rx parameters.
+       */
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SMC_PAGE, KGDB_CPM_CR_SMC_SBLOCK,
+                                       0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       /* Enable transmitter/receiver.
+       */
+       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+       printf("SMC%d at %dbps ", CONFIG_KGDB_INDEX, speed);
+}
+
+void
+putDebugChar(const char c)
+{
+       volatile cbd_t          *tbdf;
+       volatile char           *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+
+       if (c == '\n')
+               putDebugChar ('\r');
+
+       up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]);
+
+       tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase];
+
+       /* Wait for last character to go.
+       */
+       buf = (char *)tbdf->cbd_bufaddr;
+       while (tbdf->cbd_sc & BD_SC_READY)
+               ;
+
+       *buf = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+putDebugStr (const char *s)
+{
+       while (*s) {
+               putDebugChar (*s++);
+       }
+}
+
+int
+getDebugChar(void)
+{
+       volatile cbd_t          *rbdf;
+       volatile unsigned char  *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       unsigned char           c;
+
+       up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]);
+
+       rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase];
+
+       /* Wait for character to show up.
+       */
+       buf = (unsigned char *)rbdf->cbd_bufaddr;
+       while (rbdf->cbd_sc & BD_SC_EMPTY)
+               ;
+       c = *buf;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return(c);
+}
+
+void
+kgdb_interruptible(int yes)
+{
+       return;
+}
+
+#endif /* CONFIG_KGDB_ON_SMC */
diff --git a/cpu/mpc8260/speed.c b/cpu/mpc8260/speed.c
new file mode 100644 (file)
index 0000000..2bf2c4a
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * (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 <mpc8260.h>
+#include <asm/processor.h>
+
+/* ------------------------------------------------------------------------- */
+
+/* Bus-to-Core Multiplier */
+#define _1x    2
+#define _1_5x  3
+#define _2x    4
+#define _2_5x  5
+#define _3x    6
+#define _3_5x  7
+#define _4x    8
+#define _4_5x  9
+#define _5x    10
+#define _5_5x  11
+#define _6x    12
+#define _6_5x  13
+#define _7x    14
+#define _7_5x  15
+#define _8x    16
+#define _byp   -1
+#define _off   -2
+#define _unk   -3
+
+typedef struct {
+       int b2c_mult;
+       int vco_div;
+       char *freq_60x;
+       char *freq_core;
+} corecnf_t;
+
+/*
+ * this table based on "Errata to MPC8260 PowerQUICC II User's Manual",
+ * Rev. 1, 8/2000, page 10.
+ */
+corecnf_t corecnf_tab[] = {
+       { _1_5x,  4, " 33-100", " 33-100" },    /* 0x00 */
+       {   _1x,  4, " 50-150", " 50-150" },    /* 0x01 */
+       {   _1x,  8, " 25-75 ", " 25-75 " },    /* 0x02 */
+       {  _byp, -1, "  ?-?  ", "  ?-?  " },    /* 0x03 */
+       {   _2x,  2, " 50-150", "100-300" },    /* 0x04 */
+       {   _2x,  4, " 25-75 ", " 50-150" },    /* 0x05 */
+       { _2_5x,  2, " 40-120", "100-240" },    /* 0x06 */
+       { _4_5x,  2, " 22-65 ", "100-300" },    /* 0x07 */
+       {   _3x,  2, " 33-100", "100-300" },    /* 0x08 */
+       { _5_5x,  2, " 18-55 ", "100-300" },    /* 0x09 */
+       {   _4x,  2, " 25-75 ", "100-300" },    /* 0x0A */
+       {   _5x,  2, " 20-60 ", "100-300" },    /* 0x0B */
+       { _1_5x,  8, " 16-50 ", " 16-50 " },    /* 0x0C */
+       {   _6x,  2, " 16-50 ", "100-300" },    /* 0x0D */
+       { _3_5x,  2, " 30-85 ", "100-300" },    /* 0x0E */
+       {  _off, -1, "  ?-?  ", "  ?-?  " },    /* 0x0F */
+       {   _3x,  4, " 16-50 ", " 50-150" },    /* 0x10 */
+       { _2_5x,  4, " 20-60 ", " 50-120" },    /* 0x11 */
+       { _6_5x,  2, " 15-46 ", "100-300" },    /* 0x12 */
+       {  _byp, -1, "  ?-?  ", "  ?-?  " },    /* 0x13 */
+       {   _7x,  2, " 14-43 ", "100-300" },    /* 0x14 */
+       {   _2x,  4, " 25-75 ", " 50-150" },    /* 0x15 */
+       { _7_5x,  2, " 13-40 ", "100-300" },    /* 0x16 */
+       { _4_5x,  2, " 22-65 ", "100-300" },    /* 0x17 */
+       {  _unk, -1, "  ?-?  ", "  ?-?  " },    /* 0x18 */
+       { _5_5x,  2, " 18-55 ", "100-300" },    /* 0x19 */
+       {   _4x,  2, " 25-75 ", "100-300" },    /* 0x1A */
+       {   _5x,  2, " 20-60 ", "100-300" },    /* 0x1B */
+       {   _8x,  2, " 12-38 ", "100-300" },    /* 0x1C */
+       {   _6x,  2, " 16-50 ", "100-300" },    /* 0x1D */
+       { _3_5x,  2, " 30-85 ", "100-300" },    /* 0x1E */
+       {  _off, -1, "  ?-?  ", "  ?-?  " },    /* 0x1F */
+};
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       volatile immap_t *immap = (immap_t *) CFG_IMMR;
+       ulong clkin;
+       ulong sccr, dfbrg;
+       ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf;
+       corecnf_t *cp;
+
+#if !defined(CONFIG_8260_CLKIN)
+#error clock measuring not implemented yet - define CONFIG_8260_CLKIN
+#else
+       clkin = CONFIG_8260_CLKIN;
+#endif
+
+       sccr = immap->im_clkrst.car_sccr;
+       dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+
+       scmr = immap->im_clkrst.car_scmr;
+       corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT;
+       busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT;
+       cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT;
+       plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
+       pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
+
+       cp = &corecnf_tab[corecnf];
+
+       gd->vco_out = (clkin * 2 * (pllmf + 1)) / (plldf + 1);
+
+#if 0
+       if (gd->vco_out / (busdf + 1) != clkin) {
+               /* aaarrrggghhh!!! */
+               return (1);
+       }
+#endif
+
+       gd->cpm_clk = gd->vco_out / 2;
+       gd->bus_clk = clkin;
+       gd->scc_clk = gd->vco_out / 4;
+       gd->brg_clk = gd->vco_out / (1 << (2 * (dfbrg + 1)));
+
+       if (cp->b2c_mult > 0) {
+               gd->cpu_clk = (clkin * cp->b2c_mult) / 2;
+       } else {
+               gd->cpu_clk = clkin;
+       }
+
+       return (0);
+}
+
+int prt_8260_clks (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       volatile immap_t *immap = (immap_t *) CFG_IMMR;
+       ulong sccr, dfbrg;
+       ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf;
+       corecnf_t *cp;
+
+       sccr = immap->im_clkrst.car_sccr;
+       dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+
+       scmr = immap->im_clkrst.car_scmr;
+       corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT;
+       busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT;
+       cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT;
+       plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
+       pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
+
+       cp = &corecnf_tab[corecnf];
+
+       printf ("MPC8260 Clock Configuration\n - Bus-to-Core Mult ");
+
+       switch (cp->b2c_mult) {
+       case _byp:
+               printf ("BYPASS");
+               break;
+
+       case _off:
+               printf ("OFF");
+               break;
+
+       case _unk:
+               printf ("UNKNOWN");
+               break;
+
+       default:
+               printf ("%d%sx",
+                       cp->b2c_mult / 2,
+                       (cp->b2c_mult % 2) ? ".5" : "");
+               break;
+       }
+
+       printf (", VCO Div %d, 60x Bus Freq %s, Core Freq %s\n",
+                       cp->vco_div, cp->freq_60x, cp->freq_core);
+
+       printf (" - dfbrg %ld, corecnf 0x%02lx, busdf %ld, cpmdf %ld, "
+                       "plldf %ld, pllmf %ld\n", dfbrg, corecnf, busdf, cpmdf, plldf,
+                       pllmf);
+
+       printf (" - vco_out %10ld, scc_clk %10ld, brg_clk %10ld\n",
+                       gd->vco_out, gd->scc_clk, gd->brg_clk);
+
+       printf (" - cpu_clk %10ld, cpm_clk %10ld, bus_clk %10ld\n\n",
+                       gd->cpu_clk, gd->cpm_clk, gd->bus_clk);
+       return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc8xx/cpu_init.c b/cpu/mpc8xx/cpu_init.c
new file mode 100644 (file)
index 0000000..abe6209
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * (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 <watchdog.h>
+
+#include <mpc8xx.h>
+#include <commproc.h>
+
+#if defined(CFG_I2C_UCODE_PATCH) || defined(CFG_SPI_UCODE_PATCH)
+void cpm_load_patch (volatile immap_t * immr);
+#endif
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * immr)
+{
+#ifndef CONFIG_MBX
+       volatile memctl8xx_t *memctl = &immr->im_memctl;
+       ulong reg;
+#endif
+
+       /* SYPCR - contains watchdog control (11-9) */
+
+       immr->im_siu_conf.sc_sypcr = CFG_SYPCR;
+
+#if defined(CONFIG_WATCHDOG)
+       reset_8xx_watchdog (immr);
+#endif /* CONFIG_WATCHDOG */
+
+       /* SIUMCR - contains debug pin configuration (11-6) */
+
+       immr->im_siu_conf.sc_siumcr |= CFG_SIUMCR;
+
+       /* initialize timebase status and control register (11-26) */
+       /* unlock TBSCRK */
+
+       immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+       immr->im_sit.sit_tbscr = CFG_TBSCR;
+
+       /* initialize the PIT (11-31) */
+
+       immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+       immr->im_sit.sit_piscr = CFG_PISCR;
+
+       /* PLL (CPU clock) settings (15-30) */
+
+       immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+#ifndef CONFIG_MBX             /* MBX board does things different */
+
+       /* If CFG_PLPRCR (set in the various *_config.h files) tries to
+        * set the MF field, then just copy CFG_PLPRCR over car_plprcr,
+        * otherwise OR in CFG_PLPRCR so we do not change the currentMF
+        * field value.
+        */
+#if ((CFG_PLPRCR & PLPRCR_MF_MSK) != 0)
+       reg = CFG_PLPRCR;                       /* reset control bits   */
+#else
+       reg = immr->im_clkrst.car_plprcr;
+       reg &= PLPRCR_MF_MSK;                   /* isolate MF field */
+       reg |= CFG_PLPRCR;                      /* reset control bits   */
+#endif
+       immr->im_clkrst.car_plprcr = reg;
+
+       /* System integration timers. Don't change EBDF! (15-27) */
+
+       immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+       reg = immr->im_clkrst.car_sccr;
+       reg &= SCCR_MASK;
+       reg |= CFG_SCCR;
+       immr->im_clkrst.car_sccr = reg;
+
+       /*
+        * Memory Controller:
+        */
+
+       /* perform BR0 reset that MPC850 Rev. A can't guarantee */
+       reg = memctl->memc_br0;
+       reg &= BR_PS_MSK;       /* Clear everything except Port Size bits */
+       reg |= BR_V;            /* then add just the "Bank Valid" bit     */
+       memctl->memc_br0 = reg;
+
+       /* Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at
+        * preliminary addresses - these have to be modified later
+        * when FLASH size has been determined
+        *
+        * Depending on the size of the memory region defined by
+        * CFG_OR0_REMAP some boards (wide address mask) allow to map the
+        * CFG_MONITOR_BASE, while others (narrower address mask) can't
+        * map CFG_MONITOR_BASE.
+        *
+        * For example, for CONFIG_IVMS8, the CFG_MONITOR_BASE is
+        * 0xff000000, but CFG_OR0_REMAP's address mask is 0xfff80000.
+        *
+        * If BR0 wasn't loaded with address base 0xff000000, then BR0's
+        * base address remains as 0x00000000. However, the address mask
+        * have been narrowed to 512Kb, so CFG_MONITOR_BASE wasn't mapped
+        * into the Bank0.
+        *
+        * This is why CONFIG_IVMS8 and similar boards must load BR0 with
+        * CFG_BR0_PRELIM in advance.
+        *
+        * [Thanks to Michael Liao for this explanation.
+        *  I owe him a free beer. - wd]
+        */
+
+#if defined(CONFIG_GTH)                || \
+    defined(CONFIG_HERMES)     || \
+    defined(CONFIG_ICU862)     || \
+    defined(CONFIG_IP860)      || \
+    defined(CONFIG_IVML24)     || \
+    defined(CONFIG_IVMS8)      || \
+    defined(CONFIG_LWMON)      || \
+    defined(CONFIG_MHPC)       || \
+    defined(CONFIG_PCU_E)      || \
+    defined(CONFIG_R360MPI)    || \
+    defined(CONFIG_RPXCLASSIC) || \
+    defined(CONFIG_RPXLITE)    || \
+    defined(CONFIG_SPD823TS)   || \
+   (defined(CONFIG_MPC860T) && defined(CONFIG_FADS))
+
+       memctl->memc_br0 = CFG_BR0_PRELIM;
+#endif
+
+#if defined(CFG_OR0_REMAP)
+       memctl->memc_or0 = CFG_OR0_REMAP;
+#endif
+#if defined(CFG_OR1_REMAP)
+       memctl->memc_or1 = CFG_OR1_REMAP;
+#endif
+#if defined(CFG_OR5_REMAP)
+       memctl->memc_or5 = CFG_OR5_REMAP;
+#endif
+
+       /* now restrict to preliminary range */
+       memctl->memc_br0 = CFG_BR0_PRELIM;
+       memctl->memc_or0 = CFG_OR0_PRELIM;
+
+#if (defined(CFG_OR1_PRELIM) && defined(CFG_BR1_PRELIM))
+       memctl->memc_or1 = CFG_OR1_PRELIM;
+       memctl->memc_br1 = CFG_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_IP860) /* disable CS0 now that Flash is mapped on CS1 */
+       memctl->memc_br0 = 0;
+#endif
+
+#if defined(CFG_OR2_PRELIM) && defined(CFG_BR2_PRELIM)
+       memctl->memc_or2 = CFG_OR2_PRELIM;
+       memctl->memc_br2 = CFG_BR2_PRELIM;
+#endif
+
+#if defined(CFG_OR3_PRELIM) && defined(CFG_BR3_PRELIM)
+       memctl->memc_or3 = CFG_OR3_PRELIM;
+       memctl->memc_br3 = CFG_BR3_PRELIM;
+#endif
+
+#if defined(CFG_OR4_PRELIM) && defined(CFG_BR4_PRELIM)
+       memctl->memc_or4 = CFG_OR4_PRELIM;
+       memctl->memc_br4 = CFG_BR4_PRELIM;
+#endif
+
+#if defined(CFG_OR5_PRELIM) && defined(CFG_BR5_PRELIM)
+       memctl->memc_or5 = CFG_OR5_PRELIM;
+       memctl->memc_br5 = CFG_BR5_PRELIM;
+#endif
+
+#if defined(CFG_OR6_PRELIM) && defined(CFG_BR6_PRELIM)
+       memctl->memc_or6 = CFG_OR6_PRELIM;
+       memctl->memc_br6 = CFG_BR6_PRELIM;
+#endif
+
+#if defined(CFG_OR7_PRELIM) && defined(CFG_BR7_PRELIM)
+       memctl->memc_or7 = CFG_OR7_PRELIM;
+       memctl->memc_br7 = CFG_BR7_PRELIM;
+#endif
+
+#endif /* ! CONFIG_MBX */
+
+       /*
+        * Reset CPM
+        */
+       immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG;
+       do {                    /* Spin until command processed     */
+               __asm__ ("eieio");
+       } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+#ifdef CONFIG_MBX
+       /*
+        * on the MBX, things are a little bit different:
+        * - we need to read the VPD to get board information
+        * - the plprcr is set up dynamically
+        * - the memory controller is set up dynamically
+        */
+       mbx_init ();
+#endif /* CONFIG_MBX */
+
+#ifdef CONFIG_RPXCLASSIC
+       rpxclassic_init ();
+#endif
+
+#ifdef CFG_RCCR                        /* must be done before cpm_load_patch() */
+       /* write config value */
+       immr->im_cpm.cp_rccr = CFG_RCCR;
+#endif
+
+#if defined(CFG_I2C_UCODE_PATCH) || defined(CFG_SPI_UCODE_PATCH)
+       cpm_load_patch (immr);  /* load mpc8xx  microcode patch */
+#endif
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+#if defined(CFG_RTCSC) || defined(CFG_RMDS)
+       DECLARE_GLOBAL_DATA_PTR;
+
+       bd_t *bd = gd->bd;
+       volatile immap_t *immr = (volatile immap_t *) (bd->bi_immr_base);
+#endif
+
+#ifdef CFG_RTCSC
+       /* Unlock RTSC register */
+       immr->im_sitk.sitk_rtcsck = KAPWR_KEY;
+       /* write config value */
+       immr->im_sit.sit_rtcsc = CFG_RTCSC;
+#endif
+
+#ifdef CFG_RMDS
+       /* write config value */
+       immr->im_cpm.cp_rmds = CFG_RMDS;
+#endif
+       return (0);
+}
diff --git a/cpu/mpc8xx/serial.c b/cpu/mpc8xx/serial.c
new file mode 100644 (file)
index 0000000..0690300
--- /dev/null
@@ -0,0 +1,640 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <command.h>
+
+#if !defined(CONFIG_8xx_CONS_NONE)     /* No Console at all */
+
+#if defined(CONFIG_8xx_CONS_SMC1)      /* Console on SMC1 */
+#define        SMC_INDEX       0
+#undef         SCC_INDEX
+#define PROFF_SMC      PROFF_SMC1
+#define CPM_CR_CH_SMC  CPM_CR_CH_SMC1
+
+#elif defined(CONFIG_8xx_CONS_SMC2)    /* Console on SMC2 */
+#define SMC_INDEX      1
+#undef         SCC_INDEX
+#define PROFF_SMC      PROFF_SMC2
+#define CPM_CR_CH_SMC  CPM_CR_CH_SMC2
+
+#elif defined(CONFIG_8xx_CONS_SCC1)    /* Console on SCC1 */
+#undef  SMC_INDEX
+#define SCC_INDEX      0
+#define PROFF_SCC      PROFF_SCC1
+#define CPM_CR_CH_SCC  CPM_CR_CH_SCC1
+
+#elif defined(CONFIG_8xx_CONS_SCC2)    /* Console on SCC2 */
+#undef  SMC_INDEX
+#define SCC_INDEX      1
+#define PROFF_SCC      PROFF_SCC2
+#define CPM_CR_CH_SCC  CPM_CR_CH_SCC2
+
+#elif defined(CONFIG_8xx_CONS_SCC3)    /* Console on SCC3 */
+#undef  SMC_INDEX
+#define SCC_INDEX      2
+#define PROFF_SCC      PROFF_SCC3
+#define CPM_CR_CH_SCC  CPM_CR_CH_SCC3
+
+#elif defined(CONFIG_8xx_CONS_SCC4)    /* Console on SCC4 */
+#undef  SMC_INDEX
+#define SCC_INDEX      3
+#define PROFF_SCC      PROFF_SCC4
+#define CPM_CR_CH_SCC  CPM_CR_CH_SCC4
+
+#else /* CONFIG_8xx_CONS_? */
+#error "console not correctly defined"
+#endif
+
+#if (defined (CONFIG_8xx_CONS_SMC1) || defined (CONFIG_8xx_CONS_SMC2))
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+int serial_init (void)
+{
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile smc_t *sp;
+       volatile smc_uart_t *up;
+       volatile cbd_t *tbdf, *rbdf;
+       volatile cpm8xx_t *cp = &(im->im_cpm);
+#if (!defined(CONFIG_8xx_CONS_SMC1)) && (defined(CONFIG_MPC823) || defined(CONFIG_MPC850))
+       volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+       uint    dpaddr;
+
+       /* initialize pointers to SMC */
+
+       sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]);
+       up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC];
+
+       /* Disable transmitter/receiver.
+       */
+       sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+       /* Enable SDMA.
+       */
+       im->im_siu_conf.sc_sdcr = 1;
+
+       /* clear error conditions */
+#ifdef CFG_SDSR
+       im->im_sdma.sdma_sdsr = CFG_SDSR;
+#else
+       im->im_sdma.sdma_sdsr = 0x83;
+#endif
+
+       /* clear SDMA interrupt mask */
+#ifdef CFG_SDMR
+       im->im_sdma.sdma_sdmr = CFG_SDMR;
+#else
+       im->im_sdma.sdma_sdmr = 0x00;
+#endif
+
+#if defined(CONFIG_8xx_CONS_SMC1)
+       /* Use Port B for SMC1 instead of other functions.
+       */
+       cp->cp_pbpar |=  0x000000c0;
+       cp->cp_pbdir &= ~0x000000c0;
+       cp->cp_pbodr &= ~0x000000c0;
+#else  /* CONFIG_8xx_CONS_SMC2 */
+# if defined(CONFIG_MPC823) || defined(CONFIG_MPC850)
+       /* Use Port A for SMC2 instead of other functions.
+       */
+       ip->iop_papar |=  0x00c0;
+       ip->iop_padir &= ~0x00c0;
+       ip->iop_paodr &= ~0x00c0;
+# else /* must be a 860 then */
+       /* Use Port B for SMC2 instead of other functions.
+       */
+       cp->cp_pbpar |=  0x00000c00;
+       cp->cp_pbdir &= ~0x00000c00;
+       cp->cp_pbodr &= ~0x00000c00;
+# endif
+#endif
+
+#if defined(CONFIG_FADS)
+       /* Enable RS232 */
+#if defined(CONFIG_8xx_CONS_SMC1)
+       *((uint *) BCSR1) &= ~BCSR1_RS232EN_1;
+#else
+       *((uint *) BCSR1) &= ~BCSR1_RS232EN_2;
+#endif
+#endif /* CONFIG_FADS */
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+       /* Enable Monitor Port Transceiver */
+       *((uchar *) BCSR0) |= BCSR0_ENMONXCVR ;
+#endif /* CONFIG_RPXLITE */
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+
+#ifdef CFG_ALLOC_DPRAM
+       dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ;
+#else
+       dpaddr = CPM_SERIAL_BASE ;
+#endif
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+        * For now, this address seems OK, but it may have to
+        * change with newer versions of the firmware.
+        * damm: allocating space after the two buffers for rx/tx data
+        */
+
+       rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+       rbdf->cbd_bufaddr = (uint) (rbdf+2);
+       rbdf->cbd_sc = 0;
+       tbdf = rbdf + 1;
+       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+       tbdf->cbd_sc = 0;
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->smc_rbase = dpaddr;
+       up->smc_tbase = dpaddr+sizeof(cbd_t);
+       up->smc_rfcr = SMC_EB;
+       up->smc_tfcr = SMC_EB;
+
+#if defined(CONFIG_MBX)
+       board_serial_init();
+#endif /* CONFIG_MBX */
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+       /* Mask all interrupts and remove anything pending.
+       */
+       sp->smc_smcm = 0;
+       sp->smc_smce = 0xff;
+
+       /* Set up the baud rate generator.
+       */
+       serial_setbrg ();
+
+       /* Make the first buffer the only buffer.
+       */
+       tbdf->cbd_sc |= BD_SC_WRAP;
+       rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+       /* Single character receive.
+       */
+       up->smc_mrblr = 1;
+       up->smc_maxidl = 0;
+
+       /* Initialize Tx/Rx parameters.
+       */
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       /* Enable transmitter/receiver.
+       */
+       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+       return (0);
+}
+
+void
+serial_setbrg (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t *cp = &(im->im_cpm);
+
+       /* Set up the baud rate generator.
+        * See 8xx_io/commproc.c for details.
+        *
+        * Wire BRG1 to SMCx
+        */
+
+       cp->cp_simode = 0x00000000;
+
+       cp->cp_brgc1 =
+               (((gd->cpu_clk / 16 / gd->baudrate)-1) << 1) | CPM_BRG_EN;
+}
+
+void
+serial_putc(const char c)
+{
+       volatile cbd_t          *tbdf;
+       volatile char           *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+
+       if (c == '\n')
+               serial_putc ('\r');
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+       tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+
+       /* Wait for last character to go.
+       */
+
+       buf = (char *)tbdf->cbd_bufaddr;
+#if 0
+       __asm__("eieio");
+       while (tbdf->cbd_sc & BD_SC_READY)
+               __asm__("eieio");
+#endif
+
+       *buf = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+       __asm__("eieio");
+#if 1
+       while (tbdf->cbd_sc & BD_SC_READY)
+               __asm__("eieio");
+#endif
+}
+
+int
+serial_getc(void)
+{
+       volatile cbd_t          *rbdf;
+       volatile unsigned char  *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+       unsigned char           c;
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+       /* Wait for character to show up.
+       */
+       buf = (unsigned char *)rbdf->cbd_bufaddr;
+       while (rbdf->cbd_sc & BD_SC_EMPTY)
+               ;
+       c = *buf;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return(c);
+}
+
+int
+serial_tstc()
+{
+       volatile cbd_t          *rbdf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+       return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
+#else  /* ! CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2 */
+
+int serial_init (void)
+{
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile scc_t *sp;
+       volatile scc_uart_t *up;
+       volatile cbd_t *tbdf, *rbdf;
+       volatile cpm8xx_t *cp = &(im->im_cpm);
+       uint     dpaddr;
+#if (SCC_INDEX != 2) || !defined(CONFIG_MPC850)
+       volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+
+       /* initialize pointers to SCC */
+
+       sp = (scc_t *) &(cp->cp_scc[SCC_INDEX]);
+       up = (scc_uart_t *) &cp->cp_dparam[PROFF_SCC];
+
+#if defined(CONFIG_LWMON) && defined(CONFIG_8xx_CONS_SCC2)
+    {  /* Disable Ethernet, enable Serial */
+       uchar c;
+
+       c = pic_read  (0x61);
+       c &= ~0x40;     /* enable COM3 */
+       c |=  0x80;     /* disable Ethernet */
+       pic_write (0x61, c);
+
+       /* enable RTS2 */
+       cp->cp_pbpar |=  0x2000;
+       cp->cp_pbdat |=  0x2000;
+       cp->cp_pbdir |=  0x2000;
+    }
+#endif /* CONFIG_LWMON */
+
+       /* Disable transmitter/receiver.
+       */
+       sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+#if (SCC_INDEX == 2) && defined(CONFIG_MPC850)
+       /*
+        * The MPC850 has SCC3 on Port B
+        */
+       cp->cp_pbpar |=  0x06;
+       cp->cp_pbdir &= ~0x06;
+       cp->cp_pbodr &= ~0x06;
+
+#elif (SCC_INDEX < 2) || !defined(CONFIG_IP860)
+       /*
+        * Standard configuration for SCC's is on Part A
+        */
+       ip->iop_papar |=  ((3 << (2 * SCC_INDEX)));
+       ip->iop_padir &= ~((3 << (2 * SCC_INDEX)));
+       ip->iop_paodr &= ~((3 << (2 * SCC_INDEX)));
+#else
+       /*
+        * The IP860 has SCC3 and SCC4 on Port D
+        */
+       ip->iop_pdpar |=  ((3 << (2 * SCC_INDEX)));
+#endif
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+        */
+
+#ifdef CFG_ALLOC_DPRAM
+       dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ;
+#else
+       dpaddr = CPM_SERIAL_BASE ;
+#endif
+
+       /* Enable SDMA.
+       */
+       im->im_siu_conf.sc_sdcr = 0x0001;
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+
+       rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+       rbdf->cbd_bufaddr = (uint) (rbdf+2);
+       rbdf->cbd_sc = 0;
+       tbdf = rbdf + 1;
+       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+       tbdf->cbd_sc = 0;
+
+       /* Set up the baud rate generator.
+       */
+       serial_setbrg ();
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->scc_genscc.scc_rbase = dpaddr;
+       up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+
+       /* Initialize Tx/Rx parameters.
+       */
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+               ;
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+               ;
+
+       up->scc_genscc.scc_rfcr  = SCC_EB | 0x05;
+       up->scc_genscc.scc_tfcr  = SCC_EB | 0x05;
+
+       up->scc_genscc.scc_mrblr = 1;   /* Single character receive */
+       up->scc_maxidl = 0;             /* disable max idle */
+       up->scc_brkcr  = 1;             /* send one break character on stop TX */
+       up->scc_parec  = 0;
+       up->scc_frmec  = 0;
+       up->scc_nosec  = 0;
+       up->scc_brkec  = 0;
+       up->scc_uaddr1 = 0;
+       up->scc_uaddr2 = 0;
+       up->scc_toseq  = 0;
+       up->scc_char1  = 0x8000;
+       up->scc_char2  = 0x8000;
+       up->scc_char3  = 0x8000;
+       up->scc_char4  = 0x8000;
+       up->scc_char5  = 0x8000;
+       up->scc_char6  = 0x8000;
+       up->scc_char7  = 0x8000;
+       up->scc_char8  = 0x8000;
+       up->scc_rccm   = 0xc0ff;
+
+       /* Set low latency / small fifo.
+        */
+       sp->scc_gsmrh = SCC_GSMRH_RFW;
+
+       /* Set SCC(x) clock mode to 16x
+        * See 8xx_io/commproc.c for details.
+        *
+        * Wire BRG1 to SCCn
+        */
+
+       /* Set UART mode, clock divider 16 on Tx and Rx
+        */
+       sp->scc_gsmrl |=
+               (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+       sp->scc_psmr  |= SCU_PSMR_CL;
+
+       /* Mask all interrupts and remove anything pending.
+       */
+       sp->scc_sccm = 0;
+       sp->scc_scce = 0xffff;
+       sp->scc_dsr  = 0x7e7e;
+       sp->scc_psmr = 0x3000;
+
+       /* Make the first buffer the only buffer.
+       */
+       tbdf->cbd_sc |= BD_SC_WRAP;
+       rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+       /* Enable transmitter/receiver.
+       */
+       sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       return (0);
+}
+
+void
+serial_setbrg (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t *cp = &(im->im_cpm);
+
+       /* Set up the baud rate generator.
+        * See 8xx_io/commproc.c for details.
+        *
+        * Wire BRG1 to SCCx
+        */
+
+       cp->cp_sicr &= ~(0x000000FF << (8 * SCC_INDEX));
+       /* no |= needed, since BRG1 is 000 */
+
+       cp->cp_brgc1 =
+               (((gd->cpu_clk / 16 / gd->baudrate)-1) << 1) | CPM_BRG_EN;
+}
+
+void
+serial_putc(const char c)
+{
+       volatile cbd_t          *tbdf;
+       volatile char           *buf;
+       volatile scc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+
+       if (c == '\n')
+               serial_putc ('\r');
+
+       up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+       tbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_tbase];
+
+       /* Wait for last character to go.
+       */
+
+       buf = (char *)tbdf->cbd_bufaddr;
+#if 0
+       __asm__("eieio");
+       while (tbdf->cbd_sc & BD_SC_READY)
+               __asm__("eieio");
+#endif
+
+       *buf = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+       __asm__("eieio");
+#if 1
+       while (tbdf->cbd_sc & BD_SC_READY)
+               __asm__("eieio");
+#endif
+}
+
+int
+serial_getc(void)
+{
+       volatile cbd_t          *rbdf;
+       volatile unsigned char  *buf;
+       volatile scc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+       unsigned char           c;
+
+       up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+       /* Wait for character to show up.
+       */
+       buf = (unsigned char *)rbdf->cbd_bufaddr;
+       while (rbdf->cbd_sc & BD_SC_EMPTY)
+               ;
+       c = *buf;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return(c);
+}
+
+int
+serial_tstc()
+{
+       volatile cbd_t          *rbdf;
+       volatile scc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+
+       up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+       return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
+#endif /* CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2 */
+
+
+void
+serial_puts (const char *s)
+{
+       while (*s) {
+               serial_putc (*s++);
+       }
+}
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+
+void
+kgdb_serial_init(void)
+{
+#if defined(CONFIG_8xx_CONS_SMC1)
+       serial_printf("[on SMC1] ");
+#elif defined(CONFIG_8xx_CONS_SMC2)
+       serial_printf("[on SMC2] ");
+#elif defined(CONFIG_8xx_CONS_SCC1)
+       serial_printf("[on SCC1] ");
+#elif defined(CONFIG_8xx_CONS_SCC2)
+       serial_printf("[on SCC2] ");
+#elif defined(CONFIG_8xx_CONS_SCC3)
+       serial_printf("[on SCC3] ");
+#elif defined(CONFIG_8xx_CONS_SCC4)
+       serial_printf("[on SCC4] ");
+#endif
+}
+
+void
+putDebugChar (int c)
+{
+       serial_putc (c);
+}
+
+void
+putDebugStr (const char *str)
+{
+       serial_puts (str);
+}
+
+int
+getDebugChar (void)
+{
+       return serial_getc();
+}
+
+void
+kgdb_interruptible (int yes)
+{
+       return;
+}
+#endif /* CFG_CMD_KGDB */
+
+#endif /* CONFIG_8xx_CONS_NONE */
diff --git a/cpu/mpc8xx/speed.c b/cpu/mpc8xx/speed.c
new file mode 100644 (file)
index 0000000..ef32371
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * (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 <mpc8xx.h>
+#include <asm/processor.h>
+
+#define PITC_SHIFT 16
+#define PITR_SHIFT 16
+/* pitc values to time for 58/8192 seconds (about 70.8 milliseconds) */
+#define SPEED_PIT_COUNTS 58
+#define SPEED_PITC      ((SPEED_PIT_COUNTS - 1) << PITC_SHIFT)
+#define SPEED_PITC_INIT         ((SPEED_PIT_COUNTS + 1) << PITC_SHIFT)
+
+#if !defined(CONFIG_8xx_GCLK_FREQ)
+/* Access functions for the Machine State Register */
+static __inline__ unsigned long get_msr(void)
+{
+       unsigned long msr;
+
+       asm volatile("mfmsr %0" : "=r" (msr) :);
+       return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+       asm volatile("mtmsr %0" : : "r" (msr));
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2),
+ * also determine bus clock speed (checking bus divider factor)
+ *
+ * (Approx. GCLK frequency in Hz)
+ *
+ * Initializes timer 2 and PIT, but disables them before return.
+ * [Use timer 2, because MPC823 CPUs mask 0.x do not have timers 3 and 4]
+ *
+ * When measuring the CPU clock against the PIT, we count cpu clocks
+ * for 58/8192 seconds with a prescale divide by 177 for the cpu clock.
+ * These strange values for the timing interval and prescaling are used
+ * because the formula for the CPU clock is:
+ *
+ *   CPU clock = count * (177 * (8192 / 58))
+ *
+ *             = count * 24999.7241
+ *
+ *   which is very close to
+ *
+ *             = count * 25000
+ *
+ * Since the count gives the CPU clock divided by 25000, we can get
+ * the CPU clock rounded to the nearest 0.1 MHz by
+ *
+ *   CPU clock = ((count + 2) / 4) * 100000;
+ *
+ * The rounding is important since the measurement is sometimes going
+ * to be high or low by 0.025 MHz, depending on exactly how the clocks
+ * and counters interact. By rounding we get the exact answer for any
+ * CPU clock that is an even multiple of 0.1 MHz.
+ */
+
+int get_clocks (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+
+       volatile immap_t *immr = (immap_t *) CFG_IMMR;
+#ifndef        CONFIG_8xx_GCLK_FREQ
+       volatile cpmtimer8xx_t *timerp = &immr->im_cpmtimer;
+       ulong timer2_val;
+       ulong msr_val;
+
+       /* Reset + Stop Timer 2, no cascading
+        */
+       timerp->cpmt_tgcr &= ~(TGCR_CAS2 | TGCR_RST2);
+
+       /* Keep stopped, halt in debug mode
+        */
+       timerp->cpmt_tgcr |= (TGCR_FRZ2 | TGCR_STP2);
+
+       /* Timer 2 setup:
+        * Output ref. interrupt disable, int. clock
+        * Prescale by 177. Note that prescaler divides by value + 1
+        * so we must subtract 1 here.
+        */
+       timerp->cpmt_tmr2 = ((177 - 1) << TMR_PS_SHIFT) | TMR_ICLK_IN_GEN;
+
+       timerp->cpmt_tcn2 = 0;          /* reset state      */
+       timerp->cpmt_tgcr |= TGCR_RST2; /* enable timer 2   */
+
+       /*
+        * PIT setup:
+        *
+         * We want to time for SPEED_PITC_COUNTS counts (of 8192 Hz),
+         * so the count value would be SPEED_PITC_COUNTS - 1.
+         * But there would be an uncertainty in the start time of 1/4
+         * count since when we enable the PIT the count is not
+         * synchronized to the 32768 Hz oscillator. The trick here is
+         * to start the count higher and wait until the PIT count
+         * changes to the required value before starting timer 2.
+        *
+         * One count high should be enough, but occasionally the start
+         * is off by 1 or 2 counts of 32768 Hz. With the start value
+         * set two counts high it seems very reliable.
+         */
+
+       immr->im_sitk.sitk_pitck = KAPWR_KEY;   /* PIT initialization */
+       immr->im_sit.sit_pitc = SPEED_PITC_INIT;
+
+       immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+       immr->im_sit.sit_piscr = CFG_PISCR;
+
+       /*
+        * Start measurement - disable interrupts, just in case
+        */
+       msr_val = get_msr ();
+       set_msr (msr_val & ~MSR_EE);
+
+       immr->im_sit.sit_piscr |= PISCR_PTE;
+
+       /* spin until get exact count when we want to start */
+       while (immr->im_sit.sit_pitr > SPEED_PITC);
+
+       timerp->cpmt_tgcr &= ~TGCR_STP2;        /* Start Timer 2    */
+       while ((immr->im_sit.sit_piscr & PISCR_PS) == 0);
+       timerp->cpmt_tgcr |= TGCR_STP2;         /* Stop  Timer 2    */
+
+       /* re-enable external interrupts if they were on */
+       set_msr (msr_val);
+
+       /* Disable timer and PIT
+        */
+       timer2_val = timerp->cpmt_tcn2;         /* save before reset timer */
+
+       timerp->cpmt_tgcr &= ~(TGCR_RST2 | TGCR_FRZ2 | TGCR_STP2);
+       immr->im_sit.sit_piscr &= ~PISCR_PTE;
+
+       gd->cpu_clk = ((timer2_val + 2) / 4) * 100000L; /* convert to Hz    */
+
+#else /* CONFIG_8xx_GCLK_FREQ */
+
+       /*
+         * If for some reason measuring the gclk frequency won't
+         * work, we return the hardwired value.
+         * (For example, the cogent CMA286-60 CPU module has no
+         * separate oscillator for PITRTCLK)
+        */
+
+       gd->cpu_clk = CONFIG_8xx_GCLK_FREQ;
+
+#endif /* CONFIG_8xx_GCLK_FREQ */
+
+       if ((immr->im_clkrst.car_sccr & SCCR_EBDF11) == 0) {
+               /* No Bus Divider active */
+               gd->bus_clk = gd->cpu_clk;
+       } else {
+               /* The MPC8xx has only one BDF: half clock speed */
+               gd->bus_clk = gd->cpu_clk / 2;
+       }
+
+       return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc8xx/wlkbd.c b/cpu/mpc8xx/wlkbd.c
new file mode 100644 (file)
index 0000000..13009e2
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * 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 <config.h>
+
+#ifdef CONFIG_WL_4PPM_KEYBOARD
+
+/* WIP: Wireless keyboard on SMC
+ */
+int    drv_wlkbd_init (void)
+{
+    return 0 ;
+}
+
+#endif /* CONFIG_WL_4PPM_KEYBOARD */
diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c
new file mode 100644 (file)
index 0000000..52d4650
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <405gp_enet.h>
+#include <asm/processor.h>
+#include <ppc4xx.h>
+
+
+#define mtebc(reg, data)  mtdcr(ebccfga,reg);mtdcr(ebccfgd,data)
+
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers
+ */
+void
+cpu_init_f (void)
+{
+       /*
+        * External Bus Controller (EBC) Setup
+        */
+#if (defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR))
+       /*
+        * Move the next instructions into icache, since these modify the flash
+        * we are running from!
+        */
+       asm volatile("  bl      0f"             ::: "lr");
+       asm volatile("0:        mflr    3"              ::: "r3");
+       asm volatile("  addi    4, 0, 14"       ::: "r4");
+       asm volatile("  mtctr   4"              ::: "ctr");
+       asm volatile("1:        icbt    0, 3");
+       asm volatile("  addi    3, 3, 32"       ::: "r3");
+       asm volatile("  bdnz    1b"             ::: "ctr", "cr0");
+       asm volatile("  addis   3, 0, 0x0"      ::: "r3");
+       asm volatile("  ori     3, 3, 0xA000"   ::: "r3");
+       asm volatile("  mtctr   3"              ::: "ctr");
+       asm volatile("2:        bdnz    2b"             ::: "ctr", "cr0");
+
+       mtebc(pb0ap, CFG_EBC_PB0AP);
+       mtebc(pb0cr, CFG_EBC_PB0CR);
+#endif
+
+#if (defined(CFG_EBC_PB1AP) && defined(CFG_EBC_PB1CR))
+       mtebc(pb1ap, CFG_EBC_PB1AP);
+       mtebc(pb1cr, CFG_EBC_PB1CR);
+#endif
+
+#if (defined(CFG_EBC_PB2AP) && defined(CFG_EBC_PB2CR))
+       mtebc(pb2ap, CFG_EBC_PB2AP);
+       mtebc(pb2cr, CFG_EBC_PB2CR);
+#endif
+
+#if (defined(CFG_EBC_PB3AP) && defined(CFG_EBC_PB3CR))
+       mtebc(pb3ap, CFG_EBC_PB3AP);
+       mtebc(pb3cr, CFG_EBC_PB3CR);
+#endif
+
+#if (defined(CFG_EBC_PB4AP) && defined(CFG_EBC_PB4CR))
+       mtebc(pb4ap, CFG_EBC_PB4AP);
+       mtebc(pb4cr, CFG_EBC_PB4CR);
+#endif
+
+#if (defined(CFG_EBC_PB5AP) && defined(CFG_EBC_PB5CR))
+       mtebc(pb5ap, CFG_EBC_PB5AP);
+       mtebc(pb5cr, CFG_EBC_PB5CR);
+#endif
+
+#if (defined(CFG_EBC_PB6AP) && defined(CFG_EBC_PB6CR))
+       mtebc(pb6ap, CFG_EBC_PB6AP);
+       mtebc(pb6cr, CFG_EBC_PB6CR);
+#endif
+
+#if (defined(CFG_EBC_PB7AP) && defined(CFG_EBC_PB7CR))
+       mtebc(pb7ap, CFG_EBC_PB7AP);
+       mtebc(pb7cr, CFG_EBC_PB7CR);
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+       unsigned long val;
+
+       val = mfspr(tcr);
+       val |= 0xf0000000;      /* generate system reset after 2.684 seconds */
+       mtspr(tcr, val);
+
+       val = mfspr(tsr);
+       val |= 0x80000000;      /* enable watchdog timer */
+       mtspr(tsr, val);
+
+       reset_4xx_watchdog();
+#endif /* CONFIG_WATCHDOG */
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+#ifdef CONFIG_405GP
+       DECLARE_GLOBAL_DATA_PTR;
+
+       bd_t *bd = gd->bd;
+       unsigned long reg;
+
+       /*
+        * Write Ethernetaddress into on-chip register
+        */
+       reg = 0x00000000;
+       reg |= bd->bi_enetaddr[0];           /* set high address */
+       reg = reg << 8;
+       reg |= bd->bi_enetaddr[1];
+       out32 (EMAC_IAH, reg);
+
+       reg = 0x00000000;
+       reg |= bd->bi_enetaddr[2];           /* set low address  */
+       reg = reg << 8;
+       reg |= bd->bi_enetaddr[3];
+       reg = reg << 8;
+       reg |= bd->bi_enetaddr[4];
+       reg = reg << 8;
+       reg |= bd->bi_enetaddr[5];
+       out32 (EMAC_IAL, reg);
+#endif  /* CONFIG_405GP */
+       return (0);
+}
diff --git a/cpu/sa1100/cpu.c b/cpu/sa1100/cpu.c
new file mode 100644 (file)
index 0000000..370ea6c
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.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
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+
+int cpu_init (void)
+{
+       /*
+        * setup up stack if necessary
+        */
+#ifdef CONFIG_USE_IRQ
+       IRQ_STACK_START = _armboot_end +
+                       CONFIG_STACKSIZE + CONFIG_STACKSIZE_IRQ - 4;
+       FIQ_STACK_START = IRQ_STACK_START + CONFIG_STACKSIZE_FIQ;
+       _armboot_real_end = FIQ_STACK_START + 4;
+#else
+       _armboot_real_end = _armboot_end + CONFIG_STACKSIZE;
+#endif
+       return (0);
+}
+
+int cleanup_before_linux (void)
+{
+       /*
+        * this function is called just before we call linux
+        * it prepares the processor for linux
+        *
+        * just disable everything that can disturb booting linux
+        */
+
+       unsigned long i;
+
+       disable_interrupts ();
+
+       /* turn off I-cache */
+       asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+       i &= ~0x1000;
+       asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+
+       /* flush I-cache */
+       asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (i));
+
+       return (0);
+}
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+       extern void reset_cpu (ulong addr);
+
+       printf ("resetting ...\n");
+
+       udelay (50000);                         /* wait 50 ms */
+       disable_interrupts ();
+       reset_cpu (0);
+
+       /*NOTREACHED*/
+       return (0);
+}
+
+/* taken from blob */
+void icache_enable (void)
+{
+       register u32 i;
+
+       /* read control register */
+       asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+       /* set i-cache */
+       i |= 0x1000;
+
+       /* write back to control register */
+       asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void icache_disable (void)
+{
+       register u32 i;
+
+       /* read control register */
+       asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+       /* clear i-cache */
+       i &= ~0x1000;
+
+       /* write back to control register */
+       asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+
+       /* flush i-cache */
+       asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (i));
+}
+
+int icache_status (void)
+{
+       register u32 i;
+
+       /* read control register */
+       asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+       /* return bit */
+       return (i & 0x1000);
+}
+
+/* we will never enable dcache, because we have to setup MMU first */
+void dcache_enable (void)
+{
+       return;
+}
+
+void dcache_disable (void)
+{
+       return;
+}
+
+int dcache_status (void)
+{
+       return 0;                                       /* always off */
+}