Browse Source

Initial revision

wdenk 22 years ago
parent
commit
4a9cbbe832

+ 158 - 0
common/cmd_fpga.c

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

+ 580 - 0
common/kgdb.c

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

+ 54 - 0
cpu/74xx_7xx/cpu_init.c

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

+ 76 - 0
cpu/74xx_7xx/speed.c

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

+ 281 - 0
cpu/mpc824x/cpu.c

@@ -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;
+}
+
+/* ------------------------------------------------------------------------- */

+ 185 - 0
cpu/mpc824x/interrupts.c

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

+ 243 - 0
cpu/mpc8260/cpu.c

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

+ 383 - 0
cpu/mpc8260/interrupts.c

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

+ 498 - 0
cpu/mpc8260/serial_scc.c

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

+ 462 - 0
cpu/mpc8260/serial_smc.c

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

+ 211 - 0
cpu/mpc8260/speed.c

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

+ 262 - 0
cpu/mpc8xx/cpu_init.c

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

+ 640 - 0
cpu/mpc8xx/serial.c

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

+ 187 - 0
cpu/mpc8xx/speed.c

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

+ 36 - 0
cpu/mpc8xx/wlkbd.c

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

+ 148 - 0
cpu/ppc4xx/cpu_init.c

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

+ 147 - 0
cpu/sa1100/cpu.c

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