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