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