parent
e887afc9da
commit
4a9cbbe832
@ -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 */ |
@ -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 */ |
@ -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); |
||||
} |
@ -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 */ |
||||
|
||||
/* ------------------------------------------------------------------------- */ |
@ -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; |
||||
} |
||||
|
||||
/* ------------------------------------------------------------------------- */ |
@ -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; |
||||
} |
@ -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 */ |
||||
|
||||
/* ------------------------------------------------------------------------- */ |
@ -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 */ |
@ -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 */ |
@ -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 */ |
@ -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); |
||||
} |
||||
|
||||
/* ------------------------------------------------------------------------- */ |
@ -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); |
||||
} |
@ -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 */ |
@ -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); |
||||
} |
||||
|
||||
/* ------------------------------------------------------------------------- */ |
@ -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 */ |
@ -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); |
||||
} |
@ -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 */ |
||||
} |
Loading…
Reference in new issue