diff options
| -rw-r--r-- | common/cmd_fpga.c | 158 | ||||
| -rw-r--r-- | common/kgdb.c | 580 | ||||
| -rw-r--r-- | cpu/74xx_7xx/cpu_init.c | 54 | ||||
| -rw-r--r-- | cpu/74xx_7xx/speed.c | 76 | ||||
| -rw-r--r-- | cpu/mpc824x/cpu.c | 281 | ||||
| -rw-r--r-- | cpu/mpc824x/interrupts.c | 185 | ||||
| -rw-r--r-- | cpu/mpc8260/cpu.c | 243 | ||||
| -rw-r--r-- | cpu/mpc8260/interrupts.c | 383 | ||||
| -rw-r--r-- | cpu/mpc8260/serial_scc.c | 498 | ||||
| -rw-r--r-- | cpu/mpc8260/serial_smc.c | 462 | ||||
| -rw-r--r-- | cpu/mpc8260/speed.c | 211 | ||||
| -rw-r--r-- | cpu/mpc8xx/cpu_init.c | 262 | ||||
| -rw-r--r-- | cpu/mpc8xx/serial.c | 640 | ||||
| -rw-r--r-- | cpu/mpc8xx/speed.c | 187 | ||||
| -rw-r--r-- | cpu/mpc8xx/wlkbd.c | 36 | ||||
| -rw-r--r-- | cpu/ppc4xx/cpu_init.c | 148 | ||||
| -rw-r--r-- | cpu/sa1100/cpu.c | 147 | 
17 files changed, 4551 insertions, 0 deletions
| diff --git a/common/cmd_fpga.c b/common/cmd_fpga.c new file mode 100644 index 000000000..4e4c4abe9 --- /dev/null +++ b/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 */ diff --git a/common/kgdb.c b/common/kgdb.c new file mode 100644 index 000000000..b563094d5 --- /dev/null +++ b/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 */ diff --git a/cpu/74xx_7xx/cpu_init.c b/cpu/74xx_7xx/cpu_init.c new file mode 100644 index 000000000..2843e2671 --- /dev/null +++ b/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); +} diff --git a/cpu/74xx_7xx/speed.c b/cpu/74xx_7xx/speed.c new file mode 100644 index 000000000..fe553f125 --- /dev/null +++ b/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 */ + +/* ------------------------------------------------------------------------- */ diff --git a/cpu/mpc824x/cpu.c b/cpu/mpc824x/cpu.c new file mode 100644 index 000000000..0d822d53b --- /dev/null +++ b/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; +} + +/* ------------------------------------------------------------------------- */ diff --git a/cpu/mpc824x/interrupts.c b/cpu/mpc824x/interrupts.c new file mode 100644 index 000000000..201167172 --- /dev/null +++ b/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; +} diff --git a/cpu/mpc8260/cpu.c b/cpu/mpc8260/cpu.c new file mode 100644 index 000000000..73881eef3 --- /dev/null +++ b/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 */ + +/* ------------------------------------------------------------------------- */ diff --git a/cpu/mpc8260/interrupts.c b/cpu/mpc8260/interrupts.c new file mode 100644 index 000000000..d80440891 --- /dev/null +++ b/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 */ diff --git a/cpu/mpc8260/serial_scc.c b/cpu/mpc8260/serial_scc.c new file mode 100644 index 000000000..ca763024f --- /dev/null +++ b/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 */ diff --git a/cpu/mpc8260/serial_smc.c b/cpu/mpc8260/serial_smc.c new file mode 100644 index 000000000..b0e1ce4f8 --- /dev/null +++ b/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 */ diff --git a/cpu/mpc8260/speed.c b/cpu/mpc8260/speed.c new file mode 100644 index 000000000..2bf2c4a21 --- /dev/null +++ b/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); +} + +/* ------------------------------------------------------------------------- */ diff --git a/cpu/mpc8xx/cpu_init.c b/cpu/mpc8xx/cpu_init.c new file mode 100644 index 000000000..abe62094c --- /dev/null +++ b/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); +} diff --git a/cpu/mpc8xx/serial.c b/cpu/mpc8xx/serial.c new file mode 100644 index 000000000..0690300b2 --- /dev/null +++ b/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 */ diff --git a/cpu/mpc8xx/speed.c b/cpu/mpc8xx/speed.c new file mode 100644 index 000000000..ef32371ab --- /dev/null +++ b/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); +} + +/* ------------------------------------------------------------------------- */ diff --git a/cpu/mpc8xx/wlkbd.c b/cpu/mpc8xx/wlkbd.c new file mode 100644 index 000000000..13009e264 --- /dev/null +++ b/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 */ diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c new file mode 100644 index 000000000..52d465023 --- /dev/null +++ b/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); +} diff --git a/cpu/sa1100/cpu.c b/cpu/sa1100/cpu.c new file mode 100644 index 000000000..370ea6cb9 --- /dev/null +++ b/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 */ +} |