Initial revision

master
wdenk 22 years ago
parent e887afc9da
commit 4a9cbbe832
  1. 158
      common/cmd_fpga.c
  2. 580
      common/kgdb.c
  3. 54
      cpu/74xx_7xx/cpu_init.c
  4. 76
      cpu/74xx_7xx/speed.c
  5. 281
      cpu/mpc824x/cpu.c
  6. 185
      cpu/mpc824x/interrupts.c
  7. 243
      cpu/mpc8260/cpu.c
  8. 383
      cpu/mpc8260/interrupts.c
  9. 498
      cpu/mpc8260/serial_scc.c
  10. 462
      cpu/mpc8260/serial_smc.c
  11. 211
      cpu/mpc8260/speed.c
  12. 262
      cpu/mpc8xx/cpu_init.c
  13. 640
      cpu/mpc8xx/serial.c
  14. 187
      cpu/mpc8xx/speed.c
  15. 36
      cpu/mpc8xx/wlkbd.c
  16. 148
      cpu/ppc4xx/cpu_init.c
  17. 147
      cpu/sa1100/cpu.c

@ -0,0 +1,158 @@
/*
* (C) Copyright 2000, 2001
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/*
* FPGA support
*/
#include <common.h>
#include <command.h>
#include <cmd_fpga.h>
#include <fpga.h>
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#include <net.h>
#endif
#if 0
#define FPGA_DEBUG
#endif
#ifdef FPGA_DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif
#if defined (CONFIG_FPGA) && ( CONFIG_COMMANDS & CFG_CMD_FPGA )
/* Local functions */
static void fpga_usage ( cmd_tbl_t *cmdtp );
static int fpga_get_op( char *opstr );
/* Local defines */
#define FPGA_NONE -1
#define FPGA_INFO 0
#define FPGA_LOAD 1
#define FPGA_DUMP 3
/* ------------------------------------------------------------------------- */
/* command form:
* fpga <op> <device number> <data addr> <datasize>
* where op is 'load', 'dump', or 'info'
* If there is no device number field, the fpga environment variable is used.
* If there is no data addr field, the fpgadata environment variable is used.
* The info command requires no data address field.
*/
int
do_fpga (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int op, dev = FPGA_INVALID_DEVICE;
size_t data_size = 0;
void *fpga_data = NULL;
char *devstr = getenv("fpga");
char *datastr = getenv("fpgadata");
if ( devstr ) dev = (int)simple_strtoul( devstr, NULL, 16 );
if ( datastr ) fpga_data = (void *)simple_strtoul( datastr, NULL, 16 );
switch ( argc )
{
case 5: /* fpga <op> <dev> <data> <datasize> */
data_size = simple_strtoul( argv[4], NULL, 16 );
case 4: /* fpga <op> <dev> <data> */
fpga_data = (void *)simple_strtoul( argv[3], NULL, 16 );
PRINTF(__FUNCTION__": fpga_data = 0x%x\n", (uint)fpga_data );
case 3: /* fpga <op> <dev | data addr> */
dev = (int)simple_strtoul( argv[2], NULL, 16 );
PRINTF(__FUNCTION__": device = %d\n", dev );
/* FIXME - this is a really weak test */
if (( argc == 3 ) && ( dev > fpga_count() )) { /* must be buffer ptr */
PRINTF(__FUNCTION__": Assuming buffer pointer in arg 3\n");
fpga_data = (void *)dev;
PRINTF(__FUNCTION__": fpga_data = 0x%x\n", (uint)fpga_data );
dev = FPGA_INVALID_DEVICE; /* reset device num */
}
case 2: /* fpga <op> */
op = (int)fpga_get_op( argv[1] );
break;
default:
PRINTF(__FUNCTION__": Too many or too few args (%d)\n", argc );
op = FPGA_NONE; /* force usage display */
break;
}
switch ( op ) {
case FPGA_NONE:
fpga_usage( cmdtp );
break;
case FPGA_INFO:
fpga_info( dev );
break;
case FPGA_LOAD:
fpga_load( dev, fpga_data, data_size );
break;
case FPGA_DUMP:
fpga_dump( dev, fpga_data, data_size );
break;
default:
printf( "Unknown operation.\n" );
fpga_usage( cmdtp );
break;
}
return 0;
}
static void fpga_usage ( cmd_tbl_t *cmdtp )
{
printf( "Usage:\n%s\n", cmdtp->usage );
}
/*
* Map op to supported operations. We don't use a table since we
* would just have to relocate it from flash anyway.
*/
static int fpga_get_op( char *opstr )
{
int op = FPGA_NONE;
if (!strcmp ("info", opstr)) {
op = FPGA_INFO;
}
else if (!strcmp ("load", opstr)) {
op = FPGA_LOAD;
}
else if (!strcmp ("dump", opstr)) {
op = FPGA_DUMP;
}
if ( op == FPGA_NONE ) {
printf ("Unknown fpga operation \"%s\"\n", opstr);
}
return op;
}
#endif /* CONFIG_FPGA && CONFIG_COMMANDS & CFG_CMD_FPGA */

@ -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…
Cancel
Save