avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
menu "mpc8260 CPU"
depends on MPC8260
config SYS_CPU
default "mpc8260"
choice
prompt "Target select"
optional
config TARGET_KM82XX
bool "Support km82xx"
endchoice
source "board/keymile/km82xx/Kconfig"
endmenu

View File

@@ -0,0 +1,13 @@
#
# (C) Copyright 2000-2008
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
extra-y = start.o
obj-y = traps.o serial_smc.o serial_scc.o cpu.o cpu_init.o speed.o \
interrupts.o ether_fcc.o i2c.o commproc.o \
bedbug_603e.o pci.o spi.o kgdb.o
obj-$(CONFIG_ETHER_ON_SCC) += ether_scc.o

View File

@@ -0,0 +1,236 @@
/*
* Bedbug Functions specific to the MPC603e core
*/
#include <common.h>
#include <command.h>
#include <linux/ctype.h>
#include <bedbug/type.h>
#include <bedbug/bedbug.h>
#include <bedbug/regs.h>
#include <bedbug/ppc.h>
#if defined(CONFIG_CMD_BEDBUG) \
&& (defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260))
#define MAX_BREAK_POINTS 1
extern CPU_DEBUG_CTX bug_ctx;
void bedbug603e_init __P((void));
void bedbug603e_do_break __P((cmd_tbl_t*,int,int,char*const[]));
void bedbug603e_break_isr __P((struct pt_regs*));
int bedbug603e_find_empty __P((void));
int bedbug603e_set __P((int,unsigned long));
int bedbug603e_clear __P((int));
/* ======================================================================
* Initialize the global bug_ctx structure for the processor. Clear all
* of the breakpoints.
* ====================================================================== */
void bedbug603e_init( void )
{
int i;
/* -------------------------------------------------- */
bug_ctx.hw_debug_enabled = 0;
bug_ctx.stopped = 0;
bug_ctx.current_bp = 0;
bug_ctx.regs = NULL;
bug_ctx.do_break = bedbug603e_do_break;
bug_ctx.break_isr = bedbug603e_break_isr;
bug_ctx.find_empty = bedbug603e_find_empty;
bug_ctx.set = bedbug603e_set;
bug_ctx.clear = bedbug603e_clear;
for( i = 1; i <= MAX_BREAK_POINTS; ++i )
(*bug_ctx.clear)( i );
puts ("BEDBUG:ready\n");
return;
} /* bedbug_init_breakpoints */
/* ======================================================================
* Set/clear/show the hardware breakpoint for the 603e. The "off"
* string will disable a specific breakpoint. The "show" string will
* display the current breakpoints. Otherwise an address will set a
* breakpoint at that address. Setting a breakpoint uses the CPU-specific
* set routine which will assign a breakpoint number.
* ====================================================================== */
void bedbug603e_do_break (cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
long addr; /* Address to break at */
int which_bp; /* Breakpoint number */
/* -------------------------------------------------- */
if (argc < 2) {
cmd_usage(cmdtp);
return;
}
/* Turn off a breakpoint */
if( strcmp( argv[ 1 ], "off" ) == 0 )
{
if( bug_ctx.hw_debug_enabled == 0 )
{
puts ( "No breakpoints enabled\n" );
return;
}
which_bp = simple_strtoul( argv[ 2 ], NULL, 10 );
if( bug_ctx.clear )
(*bug_ctx.clear)( which_bp );
printf( "Breakpoint %d removed\n", which_bp );
return;
}
/* Show a list of breakpoints */
if( strcmp( argv[ 1 ], "show" ) == 0 )
{
for( which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp )
{
addr = GET_IABR();
printf( "Breakpoint [%d]: ", which_bp );
if( (addr & 0x00000002) == 0 )
puts ( "NOT SET\n" );
else
disppc( (unsigned char *)(addr & 0xFFFFFFFC), 0, 1, bedbug_puts, F_RADHEX );
}
return;
}
/* Set a breakpoint at the address */
if(!(( isdigit( argv[ 1 ][ 0 ] )) ||
(( argv[ 1 ][ 0 ] >= 'a' ) && ( argv[ 1 ][ 0 ] <= 'f' )) ||
(( argv[ 1 ][ 0 ] >= 'A' ) && ( argv[ 1 ][ 0 ] <= 'F' )))) {
cmd_usage(cmdtp);
return;
}
addr = simple_strtoul( argv[ 1 ], NULL, 16 );
if(( bug_ctx.set ) && ( which_bp = (*bug_ctx.set)( 0, addr )) > 0 )
{
printf( "Breakpoint [%d]: ", which_bp );
disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
}
return;
} /* bedbug603e_do_break */
/* ======================================================================
* Handle a breakpoint. Enter a mini main loop. Stay in the loop until
* the stopped flag in the debug context is cleared.
* ====================================================================== */
void bedbug603e_break_isr( struct pt_regs *regs )
{
unsigned long addr; /* Address stopped at */
/* -------------------------------------------------- */
bug_ctx.current_bp = 1;
addr = GET_IABR() & 0xFFFFFFFC;
bedbug_main_loop( addr, regs );
return;
} /* bedbug603e_break_isr */
/* ======================================================================
* See if the hardware breakpoint is available.
* ====================================================================== */
int bedbug603e_find_empty( void )
{
/* -------------------------------------------------- */
if( (GET_IABR() && 0x00000002) == 0 )
return 1;
return 0;
} /* bedbug603e_find_empty */
/* ======================================================================
* Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
* number, otherwise reassign the given breakpoint. If hardware debugging
* is not enabled, then turn it on via the MSR and DBCR0. Set the break
* address in the IABR register.
* ====================================================================== */
int bedbug603e_set( int which_bp, unsigned long addr )
{
/* -------------------------------------------------- */
if(( addr & 0x00000003 ) != 0 )
{
puts ( "Breakpoints must be on a 32 bit boundary\n" );
return 0;
}
/* Only look if which_bp == 0, else use which_bp */
if(( bug_ctx.find_empty ) && ( !which_bp ) &&
( which_bp = (*bug_ctx.find_empty)()) == 0 )
{
puts ( "All breakpoints in use\n" );
return 0;
}
if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
{
printf( "Invalid break point # %d\n", which_bp );
return 0;
}
if( ! bug_ctx.hw_debug_enabled )
{
bug_ctx.hw_debug_enabled = 1;
}
SET_IABR( addr | 0x00000002 );
return which_bp;
} /* bedbug603e_set */
/* ======================================================================
* Disable a specific breakoint by setting the IABR register to zero.
* ====================================================================== */
int bedbug603e_clear( int which_bp )
{
/* -------------------------------------------------- */
if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
{
printf( "Invalid break point # (%d)\n", which_bp );
return -1;
}
SET_IABR( 0 );
return 0;
} /* bedbug603e_clear */
/* ====================================================================== */
#endif

View File

@@ -0,0 +1,178 @@
/*
* This file is based on "arch/powerpc/8260_io/commproc.c" - here is it's
* copyright notice:
*
* General Purpose functions for the global management of the
* 8260 Communication Processor Module.
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
* Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
* 2.3.99 Updates
*
* In addition to the individual control of the communication
* channels, there are a few functions that globally affect the
* communication processor.
*
* Buffer descriptors must be allocated from the dual ported memory
* space. The allocator for that is here. When the communication
* process is reset, we reclaim the memory available. There is
* currently no deallocator for this memory.
*/
#include <common.h>
#include <asm/cpm_8260.h>
DECLARE_GLOBAL_DATA_PTR;
void
m8260_cpm_reset(void)
{
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
volatile ulong count;
/* Reclaim the DP memory for our use.
*/
gd->arch.dp_alloc_base = CPM_DATAONLY_BASE;
gd->arch.dp_alloc_top = gd->arch.dp_alloc_base + CPM_DATAONLY_SIZE;
/*
* Reset CPM
*/
immr->im_cpm.cp_cpcr = CPM_CR_RST;
count = 0;
do { /* Spin until command processed */
__asm__ __volatile__ ("eieio");
} while ((immr->im_cpm.cp_cpcr & CPM_CR_FLG) && ++count < 1000000);
#ifdef CONFIG_HARD_I2C
immr->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)] = 0;
#endif
}
/* Allocate some memory from the dual ported ram.
* To help protocols with object alignment restrictions, we do that
* if they ask.
*/
uint
m8260_cpm_dpalloc(uint size, uint align)
{
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
uint retloc;
uint align_mask, off;
uint savebase;
align_mask = align - 1;
savebase = gd->arch.dp_alloc_base;
off = gd->arch.dp_alloc_base & align_mask;
if (off != 0)
gd->arch.dp_alloc_base += (align - off);
if ((off = size & align_mask) != 0)
size += align - off;
if ((gd->arch.dp_alloc_base + size) >= gd->arch.dp_alloc_top) {
gd->arch.dp_alloc_base = savebase;
panic("m8260_cpm_dpalloc: ran out of dual port ram!");
}
retloc = gd->arch.dp_alloc_base;
gd->arch.dp_alloc_base += size;
memset((void *)&immr->im_dprambase[retloc], 0, size);
return(retloc);
}
/* We also own one page of host buffer space for the allocation of
* UART "fifos" and the like.
*/
uint
m8260_cpm_hostalloc(uint size, uint align)
{
/* the host might not even have RAM yet - just use dual port RAM */
return (m8260_cpm_dpalloc(size, align));
}
/* Set a baud rate generator. This needs lots of work. There are
* eight BRGs, which can be connected to the CPM channels or output
* as clocks. The BRGs are in two different block of internal
* memory mapped space.
* The baud rate clock is the system clock divided by something.
* It was set up long ago during the initial boot phase and is
* is given to us.
* Baud rate clocks are zero-based in the driver code (as that maps
* to port numbers). Documentation uses 1-based numbering.
*/
#define BRG_INT_CLK gd->arch.brg_clk
#define BRG_UART_CLK (BRG_INT_CLK / 16)
/* This function is used by UARTs, or anything else that uses a 16x
* oversampled clock.
*/
void
m8260_cpm_setbrg(uint brg, uint rate)
{
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
volatile uint *bp;
uint cd = BRG_UART_CLK / rate;
if ((BRG_UART_CLK % rate) < (rate / 2))
cd--;
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
brg -= 4;
}
bp += brg;
*bp = (cd << 1) | CPM_BRG_EN;
}
/* This function is used to set high speed synchronous baud rate
* clocks.
*/
void
m8260_cpm_fastbrg(uint brg, uint rate, int div16)
{
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
volatile uint *bp;
/* This is good enough to get SMCs running.....
*/
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
brg -= 4;
}
bp += brg;
*bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
if (div16)
*bp |= CPM_BRG_DIV16;
}
/* This function is used to set baud rate generators using an external
* clock source and 16x oversampling.
*/
void
m8260_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel)
{
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
volatile uint *bp;
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
brg -= 4;
}
bp += brg;
*bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
if (pinsel == 0)
*bp |= CPM_BRG_EXTC_CLK3_9;
else
*bp |= CPM_BRG_EXTC_CLK5_15;
}

View File

@@ -0,0 +1,9 @@
#
# (C) Copyright 2000-2010
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
PLATFORM_CPPFLAGS += -DCONFIG_CPM2 \
-mstring -mcpu=603e -mmultiple

View File

@@ -0,0 +1,321 @@
/*
* (C) Copyright 2000-2006
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* CPU specific code for the MPC825x / MPC826x / MPC827x / MPC828x
*
* written or collected and sometimes rewritten by
* Magnus Damm <damm@bitsmart.com>
*
* modified 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>
*
* added HiP7 (824x/827x/8280) processors support by
* Yuli Barcohen <yuli@arabellasw.com>
*/
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <mpc8260.h>
#include <netdev.h>
#include <asm/processor.h>
#include <asm/cpm_8260.h>
#if defined(CONFIG_OF_LIBFDT)
#include <libfdt.h>
#include <fdt_support.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_GET_CPU_STR_F)
extern int get_cpu_str_f (char *buf);
#endif
int checkcpu (void)
{
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
ulong clock = gd->cpu_clk;
uint pvr = get_pvr ();
uint immr, rev, m, k;
char buf[32];
puts ("CPU: ");
switch (pvr) {
case PVR_8260:
case PVR_8260_HIP3:
k = 3;
break;
case PVR_8260_HIP4:
k = 4;
break;
case PVR_8260_HIP7R1:
case PVR_8260_HIP7RA:
case PVR_8260_HIP7:
k = 7;
break;
default:
return -1; /* whoops! not an MPC8260 */
}
rev = pvr & 0xff;
immr = immap->im_memctl.memc_immr;
if ((immr & IMMR_ISB_MSK) != CONFIG_SYS_IMMR)
return -1; /* whoops! someone moved the IMMR */
#if defined(CONFIG_GET_CPU_STR_F)
get_cpu_str_f (buf);
printf ("%s (HiP%d Rev %02x, Mask ", buf, k, rev);
#else
printf (CPU_ID_STR " (HiP%d Rev %02x, Mask ", k, rev);
#endif
/*
* 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 = immap->im_dprambase16[PROFF_REVNUM / sizeof(u16)];
switch (m) {
case 0x0000:
puts ("0.2 2J24M");
break;
case 0x0010:
puts ("A.0 K22A");
break;
case 0x0011:
puts ("A.1 1K22A-XC");
break;
case 0x0001:
puts ("B.1 1K23A");
break;
case 0x0021:
puts ("B.2 2K23A-XC");
break;
case 0x0023:
puts ("B.3 3K23A");
break;
case 0x0024:
puts ("C.2 6K23A");
break;
case 0x0060:
puts ("A.0(A) 2K25A");
break;
case 0x0062:
puts ("B.1 4K25A");
break;
case 0x0064:
puts ("C.0 5K25A");
break;
case 0x0A00:
puts ("0.0 0K49M");
break;
case 0x0A01:
puts ("0.1 1K49M");
break;
case 0x0A10:
puts ("1.0 1K49M");
break;
case 0x0C00:
puts ("0.0 0K50M");
break;
case 0x0C10:
puts ("1.0 1K50M");
break;
case 0x0D00:
puts ("0.0 0K50M");
break;
case 0x0D10:
puts ("1.0 1K50M");
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 *) CONFIG_SYS_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;
}
/* ------------------------------------------------------------------------- */
#if !defined(CONFIG_HAVE_OWN_RESET)
int
do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
ulong msr, addr;
volatile immap_t *immap = (immap_t *) CONFIG_SYS_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 CONFIG_SYS_RESET_ADDRESS
addr = CONFIG_SYS_RESET_ADDRESS;
#else
/*
* note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE
* - sizeof (ulong) is usually a valid address. Better pick an address
* known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
*/
addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
#endif
((void (*)(void)) addr) ();
return 1;
}
#endif /* CONFIG_HAVE_OWN_RESET */
/* ------------------------------------------------------------------------- */
/*
* Get timebase clock frequency (like cpu_clk in Hz)
*
*/
unsigned long get_tbclk (void)
{
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 *) CONFIG_SYS_IMMR);
if (re_enable)
enable_interrupts ();
}
#endif /* CONFIG_WATCHDOG */
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_OF_BOARD_SETUP
void ft_cpu_setup (void *blob, bd_t *bd)
{
#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
fdt_fixup_ethernet(blob);
#endif
do_fixup_by_compat_u32(blob, "fsl,cpm2-brg",
"clock-frequency", bd->bi_brgfreq, 1);
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
"bus-frequency", bd->bi_busfreq, 1);
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
"timebase-frequency", OF_TBCLK, 1);
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
"clock-frequency", bd->bi_intfreq, 1);
fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
}
#endif /* CONFIG_OF_BOARD_SETUP */
/*
* Initializes on-chip ethernet controllers.
* to override, implement board_eth_init()
*/
int cpu_eth_init(bd_t *bis)
{
#if defined(CONFIG_ETHER_ON_FCC)
fec_initialize(bis);
#endif
#if defined(CONFIG_ETHER_ON_SCC)
mpc82xx_scc_enet_initialize(bis);
#endif
return 0;
}

View File

@@ -0,0 +1,272 @@
/*
* (C) Copyright 2000-2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <mpc8260.h>
#include <asm/cpm_8260.h>
#include <ioports.h>
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
extern unsigned long board_get_cpu_clk_f (void);
#endif
static void config_8260_ioports (volatile immap_t * immr)
{
int portnum;
for (portnum = 0; portnum < 4; portnum++) {
uint pmsk = 0,
ppar = 0,
psor = 0,
pdir = 0,
podr = 0,
pdat = 0;
iop_conf_t *iopc = (iop_conf_t *) & iop_conf_tab[portnum][0];
iop_conf_t *eiopc = iopc + 32;
uint msk = 1;
/*
* NOTE:
* index 0 refers to pin 31,
* index 31 refers to pin 0
*/
while (iopc < eiopc) {
if (iopc->conf) {
pmsk |= msk;
if (iopc->ppar)
ppar |= msk;
if (iopc->psor)
psor |= msk;
if (iopc->pdir)
pdir |= msk;
if (iopc->podr)
podr |= msk;
if (iopc->pdat)
pdat |= msk;
}
msk <<= 1;
iopc++;
}
if (pmsk != 0) {
volatile ioport_t *iop = ioport_addr (immr, portnum);
uint tpmsk = ~pmsk;
/*
* the (somewhat confused) paragraph at the
* bottom of page 35-5 warns that there might
* be "unknown behaviour" when programming
* PSORx and PDIRx, if PPARx = 1, so I
* decided this meant I had to disable the
* dedicated function first, and enable it
* last.
*/
iop->ppar &= tpmsk;
iop->psor = (iop->psor & tpmsk) | psor;
iop->podr = (iop->podr & tpmsk) | podr;
iop->pdat = (iop->pdat & tpmsk) | pdat;
iop->pdir = (iop->pdir & tpmsk) | pdir;
iop->ppar |= ppar;
}
}
}
#define SET_VAL_MASK(a, b, mask) ((a & mask) | (b & ~mask))
/*
* 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)
{
uint sccr;
#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
unsigned long cpu_clk;
#endif
volatile memctl8260_t *memctl = &immr->im_memctl;
extern void m8260_cpm_reset (void);
/* Pointer is writable since we allocated a register for it */
gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
/* Clear initial global data */
memset ((void *) gd, 0, sizeof (gd_t));
/* RSR - Reset Status Register - clear all status (5-4) */
gd->arch.reset_status = immr->im_clkrst.car_rsr;
immr->im_clkrst.car_rsr = RSR_ALLBITS;
/* RMR - Reset Mode Register - contains checkstop reset enable (5-5) */
immr->im_clkrst.car_rmr = CONFIG_SYS_RMR;
/* BCR - Bus Configuration Register (4-25) */
#if defined(CONFIG_SYS_BCR_60x) && (CONFIG_SYS_BCR_SINGLE)
if (immr->im_siu_conf.sc_bcr & BCR_EBM) {
immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CONFIG_SYS_BCR_60x, 0x80000010);
} else {
immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CONFIG_SYS_BCR_SINGLE, 0x80000010);
}
#else
immr->im_siu_conf.sc_bcr = CONFIG_SYS_BCR;
#endif
/* SIUMCR - contains debug pin configuration (4-31) */
#if defined(CONFIG_SYS_SIUMCR_LOW) && (CONFIG_SYS_SIUMCR_HIGH)
cpu_clk = board_get_cpu_clk_f ();
if (cpu_clk >= 100000000) {
immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CONFIG_SYS_SIUMCR_HIGH, 0x9f3cc000);
} else {
immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CONFIG_SYS_SIUMCR_LOW, 0x9f3cc000);
}
#else
immr->im_siu_conf.sc_siumcr = CONFIG_SYS_SIUMCR;
#endif
config_8260_ioports (immr);
/* initialize time counter status and control register (4-40) */
immr->im_sit.sit_tmcntsc = CONFIG_SYS_TMCNTSC;
/* initialize the PIT (4-42) */
immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
/* System clock control register (9-8) */
sccr = immr->im_clkrst.car_sccr &
(SCCR_PCI_MODE | SCCR_PCI_MODCK | SCCR_PCIDF_MSK);
immr->im_clkrst.car_sccr = sccr |
(CONFIG_SYS_SCCR & ~(SCCR_PCI_MODE | SCCR_PCI_MODCK | SCCR_PCIDF_MSK) );
/*
* Memory Controller:
*/
/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
* addresses - these have to be modified later when FLASH size
* has been determined
*/
#if defined(CONFIG_SYS_OR0_REMAP)
memctl->memc_or0 = CONFIG_SYS_OR0_REMAP;
#endif
#if defined(CONFIG_SYS_OR1_REMAP)
memctl->memc_or1 = CONFIG_SYS_OR1_REMAP;
#endif
/* now restrict to preliminary range */
/* the PS came from the HRCW, don't change it */
memctl->memc_br0 = SET_VAL_MASK(memctl->memc_br0 , CONFIG_SYS_BR0_PRELIM, BRx_PS_MSK);
memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
#endif
#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
#endif
#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
#endif
#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM;
memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM;
#endif
#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM;
memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM;
#endif
#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM;
memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM;
#endif
#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM;
memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM;
#endif
#if defined(CONFIG_SYS_BR8_PRELIM) && defined(CONFIG_SYS_OR8_PRELIM)
memctl->memc_or8 = CONFIG_SYS_OR8_PRELIM;
memctl->memc_br8 = CONFIG_SYS_BR8_PRELIM;
#endif
#if defined(CONFIG_SYS_BR9_PRELIM) && defined(CONFIG_SYS_OR9_PRELIM)
memctl->memc_or9 = CONFIG_SYS_OR9_PRELIM;
memctl->memc_br9 = CONFIG_SYS_BR9_PRELIM;
#endif
#if defined(CONFIG_SYS_BR10_PRELIM) && defined(CONFIG_SYS_OR10_PRELIM)
memctl->memc_or10 = CONFIG_SYS_OR10_PRELIM;
memctl->memc_br10 = CONFIG_SYS_BR10_PRELIM;
#endif
#if defined(CONFIG_SYS_BR11_PRELIM) && defined(CONFIG_SYS_OR11_PRELIM)
memctl->memc_or11 = CONFIG_SYS_OR11_PRELIM;
memctl->memc_br11 = CONFIG_SYS_BR11_PRELIM;
#endif
m8260_cpm_reset ();
}
/*
* initialize higher level parts of CPU like time base and timers
*/
int cpu_init_r (void)
{
volatile immap_t *immr = (immap_t *) gd->bd->bi_immr_base;
immr->im_cpm.cp_rccr = CONFIG_SYS_RCCR;
return (0);
}
/*
* print out the reason for the reset
*/
int prt_8260_rsr (void)
{
static struct {
ulong mask;
char *desc;
} bits[] = {
{
RSR_JTRS, "JTAG"}, {
RSR_CSRS, "Check Stop"}, {
RSR_SWRS, "Software Watchdog"}, {
RSR_BMRS, "Bus Monitor"}, {
RSR_ESRS, "External Soft"}, {
RSR_EHRS, "External Hard"}
};
static int n = ARRAY_SIZE(bits);
ulong rsr = gd->arch.reset_status;
int i;
char *sep;
puts (CPU_ID_STR " Reset Status:");
sep = " ";
for (i = 0; i < n; i++)
if (rsr & bits[i].mask) {
printf ("%s%s", sep, bits[i].desc);
sep = ", ";
}
puts ("\n\n");
return (0);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,367 @@
/*
* MPC8260 SCC Ethernet
*
* Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
*
* (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright (c) 2001
* Advent Networks, Inc. <http://www.adventnetworks.com>
* Jay Monkman <jtm@smoothsmoothie.com>
*
* Modified so that it plays nicely when more than one ETHERNET interface
* is in use a la ether_fcc.c.
* (C) Copyright 2008
* DENX Software Engineerin GmbH
* Gary Jennejohn <garyj@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/cpm_8260.h>
#include <mpc8260.h>
#include <malloc.h>
#include <net.h>
#include <command.h>
#include <config.h>
#if (CONFIG_ETHER_INDEX == 1)
# define PROFF_ENET PROFF_SCC1
# define CPM_CR_ENET_PAGE CPM_CR_SCC1_PAGE
# define CPM_CR_ENET_SBLOCK CPM_CR_SCC1_SBLOCK
# define CMXSCR_MASK (CMXSCR_SC1 |\
CMXSCR_RS1CS_MSK |\
CMXSCR_TS1CS_MSK)
#elif (CONFIG_ETHER_INDEX == 2)
# define PROFF_ENET PROFF_SCC2
# define CPM_CR_ENET_PAGE CPM_CR_SCC2_PAGE
# define CPM_CR_ENET_SBLOCK CPM_CR_SCC2_SBLOCK
# define CMXSCR_MASK (CMXSCR_SC2 |\
CMXSCR_RS2CS_MSK |\
CMXSCR_TS2CS_MSK)
#elif (CONFIG_ETHER_INDEX == 3)
# define PROFF_ENET PROFF_SCC3
# define CPM_CR_ENET_PAGE CPM_CR_SCC3_PAGE
# define CPM_CR_ENET_SBLOCK CPM_CR_SCC3_SBLOCK
# define CMXSCR_MASK (CMXSCR_SC3 |\
CMXSCR_RS3CS_MSK |\
CMXSCR_TS3CS_MSK)
#elif (CONFIG_ETHER_INDEX == 4)
# define PROFF_ENET PROFF_SCC4
# define CPM_CR_ENET_PAGE CPM_CR_SCC4_PAGE
# define CPM_CR_ENET_SBLOCK CPM_CR_SCC4_SBLOCK
# define CMXSCR_MASK (CMXSCR_SC4 |\
CMXSCR_RS4CS_MSK |\
CMXSCR_TS4CS_MSK)
#endif
/* Ethernet Transmit and Receive Buffers */
#define DBUF_LENGTH 1520
#define TX_BUF_CNT 2
#if !defined(CONFIG_SYS_SCC_TOUT_LOOP)
#define CONFIG_SYS_SCC_TOUT_LOOP 1000000
#endif
static char txbuf[TX_BUF_CNT][ DBUF_LENGTH ];
static uint rxIdx; /* index of the current RX buffer */
static uint txIdx; /* index of the current TX buffer */
/*
* SCC Ethernet Tx and Rx buffer descriptors allocated at the
* immr->udata_bd address on Dual-Port RAM
* Provide for Double Buffering
*/
typedef volatile struct CommonBufferDescriptor {
cbd_t rxbd[PKTBUFSRX]; /* Rx BD */
cbd_t txbd[TX_BUF_CNT]; /* Tx BD */
} RTXBD;
static RTXBD *rtx;
static int sec_send(struct eth_device *dev, void *packet, int length)
{
int i;
int result = 0;
if (length <= 0) {
printf("scc: bad packet size: %d\n", length);
goto out;
}
for(i=0; rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
if (i >= CONFIG_SYS_SCC_TOUT_LOOP) {
puts ("scc: tx buffer not ready\n");
goto out;
}
}
rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
rtx->txbd[txIdx].cbd_datlen = length;
rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
BD_ENET_TX_WRAP);
for(i=0; rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
if (i >= CONFIG_SYS_SCC_TOUT_LOOP) {
puts ("scc: tx error\n");
goto out;
}
}
/* return only status bits */
result = rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
out:
return result;
}
static int sec_rx(struct eth_device *dev)
{
int length;
for (;;)
{
if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
length = -1;
break; /* nothing received - leave for() loop */
}
length = rtx->rxbd[rxIdx].cbd_datlen;
if (rtx->rxbd[rxIdx].cbd_sc & 0x003f)
{
printf("err: %x\n", rtx->rxbd[rxIdx].cbd_sc);
}
else
{
/* Pass the packet up to the protocol layers. */
net_process_received_packet(net_rx_packets[rxIdx], length - 4);
}
/* Give the buffer back to the SCC. */
rtx->rxbd[rxIdx].cbd_datlen = 0;
/* wrap around buffer index when necessary */
if ((rxIdx + 1) >= PKTBUFSRX) {
rtx->rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP |
BD_ENET_RX_EMPTY);
rxIdx = 0;
}
else {
rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
rxIdx++;
}
}
return length;
}
/**************************************************************
*
* SCC Ethernet Initialization Routine
*
*************************************************************/
static int sec_init(struct eth_device *dev, bd_t *bis)
{
int i;
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
scc_enet_t *pram_ptr;
uint dpaddr;
uchar ea[6];
rxIdx = 0;
txIdx = 0;
/*
* Assign static pointer to BD area.
* Avoid exhausting DPRAM, which would cause a panic.
*/
if (rtx == NULL) {
dpaddr = m8260_cpm_dpalloc(sizeof(RTXBD) + 2, 16);
rtx = (RTXBD *)&immr->im_dprambase[dpaddr];
}
/* 24.21 - (1-3): ioports have been set up already */
/* 24.21 - (4,5): connect SCC's tx and rx clocks, use NMSI for SCC */
immr->im_cpmux.cmx_uar = 0;
immr->im_cpmux.cmx_scr = ( (immr->im_cpmux.cmx_scr & ~CMXSCR_MASK) |
CONFIG_SYS_CMXSCR_VALUE);
/* 24.21 (6) write RBASE and TBASE to parameter RAM */
pram_ptr = (scc_enet_t *)&(immr->im_dprambase[PROFF_ENET]);
pram_ptr->sen_genscc.scc_rbase = (unsigned int)(&rtx->rxbd[0]);
pram_ptr->sen_genscc.scc_tbase = (unsigned int)(&rtx->txbd[0]);
pram_ptr->sen_genscc.scc_rfcr = 0x18; /* Nrml Ops and Mot byte ordering */
pram_ptr->sen_genscc.scc_tfcr = 0x18; /* Mot byte ordering, Nrml access */
pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH; /* max. package len 1520 */
pram_ptr->sen_cpres = ~(0x0); /* Preset CRC */
pram_ptr->sen_cmask = 0xdebb20e3; /* Constant Mask for CRC */
/* 24.21 - (7): Write INIT RX AND TX PARAMETERS to CPCR */
while(immr->im_cpm.cp_cpcr & CPM_CR_FLG);
immr->im_cpm.cp_cpcr = mk_cr_cmd(CPM_CR_ENET_PAGE,
CPM_CR_ENET_SBLOCK,
0x0c,
CPM_CR_INIT_TRX) | CPM_CR_FLG;
/* 24.21 - (8-18): Set up parameter RAM */
pram_ptr->sen_crcec = 0x0; /* Error Counter CRC (unused) */
pram_ptr->sen_alec = 0x0; /* Align Error Counter (unused) */
pram_ptr->sen_disfc = 0x0; /* Discard Frame Counter (unused) */
pram_ptr->sen_pads = 0x8888; /* Short Frame PAD Characters */
pram_ptr->sen_retlim = 15; /* Retry Limit Threshold */
pram_ptr->sen_maxflr = 1518; /* MAX Frame Length Register */
pram_ptr->sen_minflr = 64; /* MIN Frame Length Register */
pram_ptr->sen_maxd1 = DBUF_LENGTH; /* MAX DMA1 Length Register */
pram_ptr->sen_maxd2 = DBUF_LENGTH; /* MAX DMA2 Length Register */
pram_ptr->sen_gaddr1 = 0x0; /* Group Address Filter 1 (unused) */
pram_ptr->sen_gaddr2 = 0x0; /* Group Address Filter 2 (unused) */
pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */
pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
eth_getenv_enetaddr("ethaddr", ea);
pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
pram_ptr->sen_pper = 0x0; /* Persistence (unused) */
pram_ptr->sen_iaddr1 = 0x0; /* Individual Address Filter 1 (unused) */
pram_ptr->sen_iaddr2 = 0x0; /* Individual Address Filter 2 (unused) */
pram_ptr->sen_iaddr3 = 0x0; /* Individual Address Filter 3 (unused) */
pram_ptr->sen_iaddr4 = 0x0; /* Individual Address Filter 4 (unused) */
pram_ptr->sen_taddrh = 0x0; /* Tmp Address (MSB) (unused) */
pram_ptr->sen_taddrm = 0x0; /* Tmp Address (unused) */
pram_ptr->sen_taddrl = 0x0; /* Tmp Address (LSB) (unused) */
/* 24.21 - (19): Initialize RxBD */
for (i = 0; i < PKTBUFSRX; i++)
{
rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
rtx->rxbd[i].cbd_datlen = 0; /* Reset */
rtx->rxbd[i].cbd_bufaddr = (uint)net_rx_packets[i];
}
rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
/* 24.21 - (20): Initialize TxBD */
for (i = 0; i < TX_BUF_CNT; i++)
{
rtx->txbd[i].cbd_sc = (BD_ENET_TX_PAD |
BD_ENET_TX_LAST |
BD_ENET_TX_TC);
rtx->txbd[i].cbd_datlen = 0; /* Reset */
rtx->txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
}
rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
/* 24.21 - (21): Write 0xffff to SCCE */
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_scce = ~(0x0);
/* 24.21 - (22): Write to SCCM to enable TXE, RXF, TXB events */
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_sccm = (SCCE_ENET_TXE |
SCCE_ENET_RXF |
SCCE_ENET_TXB);
/* 24.21 - (23): we don't use ethernet interrupts */
/* 24.21 - (24): Clear GSMR_H to enable normal operations */
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrh = 0;
/* 24.21 - (25): Clear GSMR_L to enable normal operations */
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl = (SCC_GSMRL_TCI |
SCC_GSMRL_TPL_48 |
SCC_GSMRL_TPP_10 |
SCC_GSMRL_MODE_ENET);
/* 24.21 - (26): Initialize DSR */
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_dsr = 0xd555;
/* 24.21 - (27): Initialize PSMR2
*
* Settings:
* CRC = 32-Bit CCITT
* NIB = Begin searching for SFD 22 bits after RENA
* FDE = Full Duplex Enable
* BRO = Reject broadcast packets
* PROMISCOUS = Catch all packets regardless of dest. MAC adress
*/
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_psmr = SCC_PSMR_ENCRC |
SCC_PSMR_NIB22 |
#if defined(CONFIG_SCC_ENET_FULL_DUPLEX)
SCC_PSMR_FDE |
#endif
#if defined(CONFIG_SCC_ENET_NO_BROADCAST)
SCC_PSMR_BRO |
#endif
#if defined(CONFIG_SCC_ENET_PROMISCOUS)
SCC_PSMR_PRO |
#endif
0;
/* 24.21 - (28): Write to GSMR_L to enable SCC */
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl |= (SCC_GSMRL_ENR |
SCC_GSMRL_ENT);
return 0;
}
static void sec_halt(struct eth_device *dev)
{
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl &= ~(SCC_GSMRL_ENR |
SCC_GSMRL_ENT);
}
#if 0
static void sec_restart(void)
{
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
immr->im_cpm.cp_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl |= (SCC_GSMRL_ENR |
SCC_GSMRL_ENT);
}
#endif
int mpc82xx_scc_enet_initialize(bd_t *bis)
{
struct eth_device *dev;
dev = (struct eth_device *) malloc(sizeof *dev);
memset(dev, 0, sizeof *dev);
strcpy(dev->name, "SCC");
dev->init = sec_init;
dev->halt = sec_halt;
dev->send = sec_send;
dev->recv = sec_rx;
eth_register(dev);
return 1;
}

View File

@@ -0,0 +1,741 @@
/*
* (C) Copyright 2000
* Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
*
* (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <console.h>
#if defined(CONFIG_HARD_I2C)
#include <asm/cpm_8260.h>
#include <i2c.h>
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_I2C_MULTI_BUS)
static unsigned int i2c_bus_num __attribute__ ((section(".data"))) = 0;
#endif /* CONFIG_I2C_MULTI_BUS */
/* uSec to wait between polls of the i2c */
#define DELAY_US 100
/* uSec to wait for the CPM to start processing the buffer */
#define START_DELAY_US 1000
/*
* tx/rx per-byte timeout: we delay DELAY_US uSec between polls so the
* timeout will be (tx_length + rx_length) * DELAY_US * TOUT_LOOP
*/
#define TOUT_LOOP 5
/*
* Set default values
*/
#ifndef CONFIG_SYS_I2C_SPEED
#define CONFIG_SYS_I2C_SPEED 50000
#endif
typedef void (*i2c_ecb_t) (int, int, void *); /* error callback function */
/* This structure keeps track of the bd and buffer space usage. */
typedef struct i2c_state {
int rx_idx; /* index to next free Rx BD */
int tx_idx; /* index to next free Tx BD */
void *rxbd; /* pointer to next free Rx BD */
void *txbd; /* pointer to next free Tx BD */
int tx_space; /* number of Tx bytes left */
unsigned char *tx_buf; /* pointer to free Tx area */
i2c_ecb_t err_cb; /* error callback function */
void *cb_data; /* private data to be passed */
} i2c_state_t;
/* flags for i2c_send() and i2c_receive() */
#define I2CF_ENABLE_SECONDARY 0x01 /* secondary_address is valid */
#define I2CF_START_COND 0x02 /* tx: generate start condition */
#define I2CF_STOP_COND 0x04 /* tx: generate stop condition */
/* return codes */
#define I2CERR_NO_BUFFERS 1 /* no more BDs or buffer space */
#define I2CERR_MSG_TOO_LONG 2 /* tried to send/receive to much data */
#define I2CERR_TIMEOUT 3 /* timeout in i2c_doio() */
#define I2CERR_QUEUE_EMPTY 4 /* i2c_doio called without send/rcv */
#define I2CERR_IO_ERROR 5 /* had an error during comms */
/* error callback flags */
#define I2CECB_RX_ERR 0x10 /* this is a receive error */
#define I2CECB_RX_OV 0x02 /* receive overrun error */
#define I2CECB_RX_MASK 0x0f /* mask for error bits */
#define I2CECB_TX_ERR 0x20 /* this is a transmit error */
#define I2CECB_TX_CL 0x01 /* transmit collision error */
#define I2CECB_TX_UN 0x02 /* transmit underflow error */
#define I2CECB_TX_NAK 0x04 /* transmit no ack error */
#define I2CECB_TX_MASK 0x0f /* mask for error bits */
#define I2CECB_TIMEOUT 0x40 /* this is a timeout error */
#define ERROR_I2C_NONE 0
#define ERROR_I2C_LENGTH 1
#define I2C_WRITE_BIT 0x00
#define I2C_READ_BIT 0x01
#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */
#define NUM_RX_BDS 4
#define NUM_TX_BDS 4
#define MAX_TX_SPACE 256
typedef struct I2C_BD {
unsigned short status;
unsigned short length;
unsigned char *addr;
} I2C_BD;
#define BD_I2C_TX_START 0x0400 /* special status for i2c: Start condition */
#define BD_I2C_TX_CL 0x0001 /* collision error */
#define BD_I2C_TX_UN 0x0002 /* underflow error */
#define BD_I2C_TX_NAK 0x0004 /* no acknowledge error */
#define BD_I2C_TX_ERR (BD_I2C_TX_NAK|BD_I2C_TX_UN|BD_I2C_TX_CL)
#define BD_I2C_RX_ERR BD_SC_OV
/*
* Returns the best value of I2BRG to meet desired clock speed of I2C with
* input parameters (clock speed, filter, and predivider value).
* It returns computer speed value and the difference between it and desired
* speed.
*/
static inline int
i2c_roundrate(int hz, int speed, int filter, int modval,
int *brgval, int *totspeed)
{
int moddiv = 1 << (5 - (modval & 3)), brgdiv, div;
debug("\t[I2C] trying hz=%d, speed=%d, filter=%d, modval=%d\n",
hz, speed, filter, modval);
div = moddiv * speed;
brgdiv = (hz + div - 1) / div;
debug("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv);
*brgval = ((brgdiv + 1) / 2) - 3 - (2 * filter);
if ((*brgval < 0) || (*brgval > 255)) {
debug("\t\trejected brgval=%d\n", *brgval);
return -1;
}
brgdiv = 2 * (*brgval + 3 + (2 * filter));
div = moddiv * brgdiv;
*totspeed = hz / div;
debug("\t\taccepted brgval=%d, totspeed=%d\n", *brgval, *totspeed);
return 0;
}
/*
* Sets the I2C clock predivider and divider to meet required clock speed.
*/
static int i2c_setrate(int hz, int speed)
{
immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
int brgval,
modval, /* 0-3 */
bestspeed_diff = speed,
bestspeed_brgval = 0,
bestspeed_modval = 0,
bestspeed_filter = 0,
totspeed,
filter = 0; /* Use this fixed value */
for (modval = 0; modval < 4; modval++) {
if (i2c_roundrate(hz, speed, filter, modval, &brgval, &totspeed)
== 0) {
int diff = speed - totspeed;
if ((diff >= 0) && (diff < bestspeed_diff)) {
bestspeed_diff = diff;
bestspeed_modval = modval;
bestspeed_brgval = brgval;
bestspeed_filter = filter;
}
}
}
debug("[I2C] Best is:\n");
debug("[I2C] CPU=%dhz RATE=%d F=%d I2MOD=%08x I2BRG=%08x DIFF=%dhz\n",
hz, speed, bestspeed_filter, bestspeed_modval, bestspeed_brgval,
bestspeed_diff);
i2c->i2c_i2mod |= ((bestspeed_modval & 3) << 1) |
(bestspeed_filter << 3);
i2c->i2c_i2brg = bestspeed_brgval & 0xff;
debug("[I2C] i2mod=%08x i2brg=%08x\n", i2c->i2c_i2mod,
i2c->i2c_i2brg);
return 1;
}
void i2c_init(int speed, int slaveadd)
{
volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
volatile cpm8260_t *cp = (cpm8260_t *)&immap->im_cpm;
volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
volatile iic_t *iip;
ulong rbase, tbase;
volatile I2C_BD *rxbd, *txbd;
uint dpaddr;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/*
* call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)];
if (dpaddr == 0) {
/* need to allocate dual port ram */
dpaddr = m8260_cpm_dpalloc(64 +
(NUM_RX_BDS * sizeof(I2C_BD)) +
(NUM_TX_BDS * sizeof(I2C_BD)) +
MAX_TX_SPACE, 64);
immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)] =
dpaddr;
}
/*
* initialise data in dual port ram:
*
* dpaddr -> parameter ram (64 bytes)
* rbase -> rx BD (NUM_RX_BDS * sizeof(I2C_BD) bytes)
* tbase -> tx BD (NUM_TX_BDS * sizeof(I2C_BD) bytes)
* tx buffer (MAX_TX_SPACE bytes)
*/
iip = (iic_t *)&immap->im_dprambase[dpaddr];
memset((void *)iip, 0, sizeof(iic_t));
rbase = dpaddr + 64;
tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD);
/* Disable interrupts */
i2c->i2c_i2mod = 0x00;
i2c->i2c_i2cmr = 0x00;
i2c->i2c_i2cer = 0xff;
i2c->i2c_i2add = slaveadd;
/*
* Set the I2C BRG Clock division factor from desired i2c rate
* and current CPU rate (we assume sccr dfbgr field is 0;
* divide BRGCLK by 1)
*/
debug("[I2C] Setting rate...\n");
i2c_setrate(gd->arch.brg_clk, CONFIG_SYS_I2C_SPEED);
/* Set I2C controller in master mode */
i2c->i2c_i2com = 0x01;
/* Initialize Tx/Rx parameters */
iip->iic_rbase = rbase;
iip->iic_tbase = tbase;
rxbd = (I2C_BD *)((unsigned char *) &immap->
im_dprambase[iip->iic_rbase]);
txbd = (I2C_BD *)((unsigned char *) &immap->
im_dprambase[iip->iic_tbase]);
debug("[I2C] rbase = %04x\n", iip->iic_rbase);
debug("[I2C] tbase = %04x\n", iip->iic_tbase);
debug("[I2C] rxbd = %08x\n", (int) rxbd);
debug("[I2C] txbd = %08x\n", (int) txbd);
/* Set big endian byte order */
iip->iic_tfcr = 0x10;
iip->iic_rfcr = 0x10;
/* Set maximum receive size. */
iip->iic_mrblr = I2C_RXTX_LEN;
cp->cp_cpcr = mk_cr_cmd(CPM_CR_I2C_PAGE,
CPM_CR_I2C_SBLOCK,
0x00, CPM_CR_INIT_TRX) | CPM_CR_FLG;
do {
__asm__ __volatile__("eieio");
} while (cp->cp_cpcr & CPM_CR_FLG);
/* Clear events and interrupts */
i2c->i2c_i2cer = 0xff;
i2c->i2c_i2cmr = 0x00;
}
static
void i2c_newio(i2c_state_t *state)
{
volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
volatile iic_t *iip;
uint dpaddr;
debug("[I2C] i2c_newio\n");
dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)];
iip = (iic_t *)&immap->im_dprambase[dpaddr];
state->rx_idx = 0;
state->tx_idx = 0;
state->rxbd = (void *)&immap->im_dprambase[iip->iic_rbase];
state->txbd = (void *)&immap->im_dprambase[iip->iic_tbase];
state->tx_space = MAX_TX_SPACE;
state->tx_buf = (uchar *)state->txbd + NUM_TX_BDS * sizeof(I2C_BD);
state->err_cb = NULL;
state->cb_data = NULL;
debug("[I2C] rxbd = %08x\n", (int)state->rxbd);
debug("[I2C] txbd = %08x\n", (int)state->txbd);
debug("[I2C] tx_buf = %08x\n", (int)state->tx_buf);
/* clear the buffer memory */
memset((char *) state->tx_buf, 0, MAX_TX_SPACE);
}
static
int i2c_send(i2c_state_t *state,
unsigned char address,
unsigned char secondary_address,
unsigned int flags, unsigned short size, unsigned char *dataout)
{
volatile I2C_BD *txbd;
int i, j;
debug("[I2C] i2c_send add=%02d sec=%02d flag=%02d size=%d\n",
address, secondary_address, flags, size);
/* trying to send message larger than BD */
if (size > I2C_RXTX_LEN)
return I2CERR_MSG_TOO_LONG;
/* no more free bds */
if (state->tx_idx >= NUM_TX_BDS || state->tx_space < (2 + size))
return I2CERR_NO_BUFFERS;
txbd = (I2C_BD *)state->txbd;
txbd->addr = state->tx_buf;
debug("[I2C] txbd = %08x\n", (int) txbd);
if (flags & I2CF_START_COND) {
debug("[I2C] Formatting addresses...\n");
if (flags & I2CF_ENABLE_SECONDARY) {
/* Length of message plus dest addresses */
txbd->length = size + 2;
txbd->addr[0] = address << 1;
txbd->addr[1] = secondary_address;
i = 2;
} else {
/* Length of message plus dest address */
txbd->length = size + 1;
/* Write destination address to BD */
txbd->addr[0] = address << 1;
i = 1;
}
} else {
txbd->length = size; /* Length of message */
i = 0;
}
/* set up txbd */
txbd->status = BD_SC_READY;
if (flags & I2CF_START_COND)
txbd->status |= BD_I2C_TX_START;
if (flags & I2CF_STOP_COND)
txbd->status |= BD_SC_LAST | BD_SC_WRAP;
/* Copy data to send into buffer */
debug("[I2C] copy data...\n");
for (j = 0; j < size; i++, j++)
txbd->addr[i] = dataout[j];
debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
txbd->length, txbd->status, txbd->addr[0], txbd->addr[1]);
/* advance state */
state->tx_buf += txbd->length;
state->tx_space -= txbd->length;
state->tx_idx++;
state->txbd = (void *) (txbd + 1);
return 0;
}
static
int i2c_receive(i2c_state_t *state,
unsigned char address,
unsigned char secondary_address,
unsigned int flags,
unsigned short size_to_expect, unsigned char *datain)
{
volatile I2C_BD *rxbd, *txbd;
debug("[I2C] i2c_receive %02d %02d %02d\n", address,
secondary_address, flags);
/* Expected to receive too much */
if (size_to_expect > I2C_RXTX_LEN)
return I2CERR_MSG_TOO_LONG;
/* no more free bds */
if (state->tx_idx >= NUM_TX_BDS || state->rx_idx >= NUM_RX_BDS
|| state->tx_space < 2)
return I2CERR_NO_BUFFERS;
rxbd = (I2C_BD *) state->rxbd;
txbd = (I2C_BD *) state->txbd;
debug("[I2C] rxbd = %08x\n", (int) rxbd);
debug("[I2C] txbd = %08x\n", (int) txbd);
txbd->addr = state->tx_buf;
/* set up TXBD for destination address */
if (flags & I2CF_ENABLE_SECONDARY) {
txbd->length = 2;
txbd->addr[0] = address << 1; /* Write data */
txbd->addr[1] = secondary_address; /* Internal address */
txbd->status = BD_SC_READY;
} else {
txbd->length = 1 + size_to_expect;
txbd->addr[0] = (address << 1) | 0x01;
txbd->status = BD_SC_READY;
memset(&txbd->addr[1], 0, txbd->length);
}
/* set up rxbd for reception */
rxbd->status = BD_SC_EMPTY;
rxbd->length = size_to_expect;
rxbd->addr = datain;
txbd->status |= BD_I2C_TX_START;
if (flags & I2CF_STOP_COND) {
txbd->status |= BD_SC_LAST | BD_SC_WRAP;
rxbd->status |= BD_SC_WRAP;
}
debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
txbd->length, txbd->status, txbd->addr[0], txbd->addr[1]);
debug("[I2C] rxbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
rxbd->length, rxbd->status, rxbd->addr[0], rxbd->addr[1]);
/* advance state */
state->tx_buf += txbd->length;
state->tx_space -= txbd->length;
state->tx_idx++;
state->txbd = (void *) (txbd + 1);
state->rx_idx++;
state->rxbd = (void *) (rxbd + 1);
return 0;
}
static
int i2c_doio(i2c_state_t *state)
{
volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
volatile iic_t *iip;
volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
volatile I2C_BD *txbd, *rxbd;
int n, i, b, rxcnt = 0, rxtimeo = 0, txcnt = 0, txtimeo = 0, rc = 0;
uint dpaddr;
debug("[I2C] i2c_doio\n");
if (state->tx_idx <= 0 && state->rx_idx <= 0) {
debug("[I2C] No I/O is queued\n");
return I2CERR_QUEUE_EMPTY;
}
dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)];
iip = (iic_t *)&immap->im_dprambase[dpaddr];
iip->iic_rbptr = iip->iic_rbase;
iip->iic_tbptr = iip->iic_tbase;
/* Enable I2C */
debug("[I2C] Enabling I2C...\n");
i2c->i2c_i2mod |= 0x01;
/* Begin transmission */
i2c->i2c_i2com |= 0x80;
/* Loop until transmit & receive completed */
n = state->tx_idx;
if (n > 0) {
txbd = ((I2C_BD *) state->txbd) - n;
for (i = 0; i < n; i++) {
txtimeo += TOUT_LOOP * txbd->length;
txbd++;
}
txbd--; /* wait until last in list is done */
debug("[I2C] Transmitting...(txbd=0x%08lx)\n",
(ulong) txbd);
udelay(START_DELAY_US); /* give it time to start */
while ((txbd->status & BD_SC_READY) && (++txcnt < txtimeo)) {
udelay(DELAY_US);
if (ctrlc())
return -1;
__asm__ __volatile__("eieio");
}
}
n = state->rx_idx;
if (txcnt < txtimeo && n > 0) {
rxbd = ((I2C_BD *) state->rxbd) - n;
for (i = 0; i < n; i++) {
rxtimeo += TOUT_LOOP * rxbd->length;
rxbd++;
}
rxbd--; /* wait until last in list is done */
debug("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong) rxbd);
udelay(START_DELAY_US); /* give it time to start */
while ((rxbd->status & BD_SC_EMPTY) && (++rxcnt < rxtimeo)) {
udelay(DELAY_US);
if (ctrlc())
return -1;
__asm__ __volatile__("eieio");
}
}
/* Turn off I2C */
i2c->i2c_i2mod &= ~0x01;
n = state->tx_idx;
if (n > 0) {
for (i = 0; i < n; i++) {
txbd = ((I2C_BD *) state->txbd) - (n - i);
b = txbd->status & BD_I2C_TX_ERR;
if (b != 0) {
if (state->err_cb != NULL)
(*state->err_cb) (I2CECB_TX_ERR | b,
i, state->cb_data);
if (rc == 0)
rc = I2CERR_IO_ERROR;
}
}
}
n = state->rx_idx;
if (n > 0) {
for (i = 0; i < n; i++) {
rxbd = ((I2C_BD *) state->rxbd) - (n - i);
b = rxbd->status & BD_I2C_RX_ERR;
if (b != 0) {
if (state->err_cb != NULL)
(*state->err_cb) (I2CECB_RX_ERR | b,
i, state->cb_data);
if (rc == 0)
rc = I2CERR_IO_ERROR;
}
}
}
if ((txtimeo > 0 && txcnt >= txtimeo) ||
(rxtimeo > 0 && rxcnt >= rxtimeo)) {
if (state->err_cb != NULL)
(*state->err_cb) (I2CECB_TIMEOUT, -1, state->cb_data);
if (rc == 0)
rc = I2CERR_TIMEOUT;
}
return rc;
}
static void i2c_probe_callback(int flags, int xnum, void *data)
{
/*
* the only acceptable errors are a transmit NAK or a receive
* overrun - tx NAK means the device does not exist, rx OV
* means the device must have responded to the slave address
* even though the transfer failed
*/
if (flags == (I2CECB_TX_ERR | I2CECB_TX_NAK))
*(int *) data |= 1;
if (flags == (I2CECB_RX_ERR | I2CECB_RX_OV))
*(int *) data |= 2;
}
int i2c_probe(uchar chip)
{
i2c_state_t state;
int rc, err_flag;
uchar buf[1];
i2c_newio(&state);
state.err_cb = i2c_probe_callback;
state.cb_data = (void *) &err_flag;
err_flag = 0;
rc = i2c_receive(&state, chip, 0, I2CF_START_COND | I2CF_STOP_COND, 1,
buf);
if (rc != 0)
return rc; /* probe failed */
rc = i2c_doio(&state);
if (rc == 0)
return 0; /* device exists - read succeeded */
if (rc == I2CERR_TIMEOUT)
return -1; /* device does not exist - timeout */
if (rc != I2CERR_IO_ERROR || err_flag == 0)
return rc; /* probe failed */
if (err_flag & 1)
return -1; /* device does not exist - had transmit NAK */
return 0; /* device exists - had receive overrun */
}
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
i2c_state_t state;
uchar xaddr[4];
int rc;
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
xaddr[3] = addr & 0xFF;
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
* and the extra bits end up in the "chip address" bit slots.
* This makes a 24WC08 (1Kbyte) chip look like four 256 byte
* chips.
*
* Note that we consider the length of the address field to still
* be one byte because the extra address bits are hidden in the
* chip address.
*/
chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
i2c_newio(&state);
rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen,
&xaddr[4 - alen]);
if (rc != 0) {
printf("i2c_read: i2c_send failed (%d)\n", rc);
return 1;
}
rc = i2c_receive(&state, chip, 0, I2CF_STOP_COND, len, buffer);
if (rc != 0) {
printf("i2c_read: i2c_receive failed (%d)\n", rc);
return 1;
}
rc = i2c_doio(&state);
if (rc != 0) {
printf("i2c_read: i2c_doio failed (%d)\n", rc);
return 1;
}
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
i2c_state_t state;
uchar xaddr[4];
int rc;
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
xaddr[3] = addr & 0xFF;
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
* and the extra bits end up in the "chip address" bit slots.
* This makes a 24WC08 (1Kbyte) chip look like four 256 byte
* chips.
*
* Note that we consider the length of the address field to still
* be one byte because the extra address bits are hidden in the
* chip address.
*/
chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
i2c_newio(&state);
rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen,
&xaddr[4 - alen]);
if (rc != 0) {
printf("i2c_write: first i2c_send failed (%d)\n", rc);
return 1;
}
rc = i2c_send(&state, 0, 0, I2CF_STOP_COND, len, buffer);
if (rc != 0) {
printf("i2c_write: second i2c_send failed (%d)\n", rc);
return 1;
}
rc = i2c_doio(&state);
if (rc != 0) {
printf("i2c_write: i2c_doio failed (%d)\n", rc);
return 1;
}
return 0;
}
#if defined(CONFIG_I2C_MULTI_BUS)
/*
* Functions for multiple I2C bus handling
*/
unsigned int i2c_get_bus_num(void)
{
return i2c_bus_num;
}
int i2c_set_bus_num(unsigned int bus)
{
if (bus >= CONFIG_SYS_MAX_I2C_BUS)
return -1;
i2c_bus_num = bus;
return 0;
}
#endif /* CONFIG_I2C_MULTI_BUS */
#endif /* CONFIG_HARD_I2C */

View File

@@ -0,0 +1,255 @@
/*
* (C) Copyright 2000-2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*
* Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00
*/
#include <common.h>
#include <command.h>
#include <mpc8260.h>
#include <mpc8260_irq.h>
#include <asm/processor.h>
DECLARE_GLOBAL_DATA_PTR;
/****************************************************************************/
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/powerpc/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 *) CONFIG_SYS_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 *) CONFIG_SYS_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 *) CONFIG_SYS_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 *) CONFIG_SYS_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/powerpc/kernel/ppc8260_pic.c */
/****************************************************************************/
int interrupt_init_cpu (unsigned *decrementer_count)
{
volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
*decrementer_count = (gd->bus_clk / 4) / CONFIG_SYS_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;
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);
enable_interrupts ();
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;
}
/****************************************************************************/
void timer_interrupt_cpu (struct pt_regs *regs)
{
/* nothing to do here */
return;
}
/****************************************************************************/
#if defined(CONFIG_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 * const argv[])
{
int irq, re_enable;
re_enable = disable_interrupts ();
puts ("\nInterrupt-Information:\n"
"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

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <command.h>
#include <mpc8260.h>
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <asm/cache.h>
#include <asm/mmu.h>
#if defined(CONFIG_CMD_KGDB)
/*
* cache flushing routines for kgdb
*/
.globl kgdb_flush_cache_all
kgdb_flush_cache_all:
mfspr r3, HID0
ori r3, r3, HID0_ICFI|HID0_DCI /* Invalidate All */
SYNC
mtspr HID0, r3
blr
.globl kgdb_flush_cache_range
kgdb_flush_cache_range:
li r5,CONFIG_SYS_CACHELINE_SIZE-1
andc r3,r3,r5
subf r4,r3,r4
add r4,r4,r5
srwi. r4,r4,CONFIG_SYS_CACHELINE_SHIFT
beqlr
mtctr r4
mr r6,r3
1: dcbst 0,r3
addi r3,r3,CONFIG_SYS_CACHELINE_SIZE
bdnz 1b
sync /* wait for dcbst's to get to ram */
mtctr r4
2: icbi 0,r6
addi r6,r6,CONFIG_SYS_CACHELINE_SIZE
bdnz 2b
SYNC
blr
#endif

View File

@@ -0,0 +1,382 @@
/*
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* Copyright (c) 2005 MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
* Added support for PCI bridge on MPC8272ADS
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#ifdef CONFIG_PCI
#include <pci.h>
#include <mpc8260.h>
#include <asm/m8260_pci.h>
#include <asm/io.h>
#ifdef CONFIG_OF_LIBFDT
#include <libfdt.h>
#include <fdt_support.h>
#endif
/*
* Local->PCI map (from CPU) controlled by
* MPC826x master window
*
* 0x80000000 - 0xBFFFFFFF CPU2PCI space PCIBR0
* 0xF4000000 - 0xF7FFFFFF CPU2PCI space PCIBR1
*
* 0x80000000 - 0x9FFFFFFF 0x80000000 - 0x9FFFFFFF (Outbound ATU #1)
* PCI Mem with prefetch
*
* 0xA0000000 - 0xBFFFFFFF 0xA0000000 - 0xBFFFFFFF (Outbound ATU #2)
* PCI Mem w/o prefetch
*
* 0xF4000000 - 0xF7FFFFFF 0x00000000 - 0x03FFFFFF (Outbound ATU #3)
* 32-bit PCI IO
*
* PCI->Local map (from PCI)
* MPC826x slave window controlled by
*
* 0x00000000 - 0x1FFFFFFF 0x00000000 - 0x1FFFFFFF (Inbound ATU #1)
* MPC826x local memory
*/
/*
* Slave window that allows PCI masters to access MPC826x local memory.
* This window is set up using the first set of Inbound ATU registers
*/
#ifndef CONFIG_SYS_PCI_SLV_MEM_LOCAL
#define PCI_SLV_MEM_LOCAL CONFIG_SYS_SDRAM_BASE /* Local base */
#else
#define PCI_SLV_MEM_LOCAL CONFIG_SYS_PCI_SLV_MEM_LOCAL
#endif
#ifndef CONFIG_SYS_PCI_SLV_MEM_BUS
#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */
#else
#define PCI_SLV_MEM_BUS CONFIG_SYS_PCI_SLV_MEM_BUS
#endif
#ifndef CONFIG_SYS_PICMR0_MASK_ATTRIB
#define PICMR0_MASK_ATTRIB (PICMR_MASK_512MB | PICMR_ENABLE | \
PICMR_PREFETCH_EN)
#else
#define PICMR0_MASK_ATTRIB CONFIG_SYS_PICMR0_MASK_ATTRIB
#endif
/*
* These are the windows that allow the CPU to access PCI address space.
* All three PCI master windows, which allow the CPU to access PCI
* prefetch, non prefetch, and IO space (see below), must all fit within
* these windows.
*/
/* PCIBR0 */
#ifndef CONFIG_SYS_PCI_MSTR0_LOCAL
#define PCI_MSTR0_LOCAL 0x80000000 /* Local base */
#else
#define PCI_MSTR0_LOCAL CONFIG_SYS_PCI_MSTR0_LOCAL
#endif
#ifndef CONFIG_SYS_PCIMSK0_MASK
#define PCIMSK0_MASK PCIMSK_1GB /* Size of window */
#else
#define PCIMSK0_MASK CONFIG_SYS_PCIMSK0_MASK
#endif
/* PCIBR1 */
#ifndef CONFIG_SYS_PCI_MSTR1_LOCAL
#define PCI_MSTR1_LOCAL 0xF4000000 /* Local base */
#else
#define PCI_MSTR1_LOCAL CONFIG_SYS_PCI_MSTR1_LOCAL
#endif
#ifndef CONFIG_SYS_PCIMSK1_MASK
#define PCIMSK1_MASK PCIMSK_64MB /* Size of window */
#else
#define PCIMSK1_MASK CONFIG_SYS_PCIMSK1_MASK
#endif
/*
* Master window that allows the CPU to access PCI Memory (prefetch).
* This window will be setup with the first set of Outbound ATU registers
* in the bridge.
*/
#ifndef CONFIG_SYS_PCI_MSTR_MEM_LOCAL
#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */
#else
#define PCI_MSTR_MEM_LOCAL CONFIG_SYS_PCI_MSTR_MEM_LOCAL
#endif
#ifndef CONFIG_SYS_PCI_MSTR_MEM_BUS
#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */
#else
#define PCI_MSTR_MEM_BUS CONFIG_SYS_PCI_MSTR_MEM_BUS
#endif
#ifndef CONFIG_SYS_CPU_PCI_MEM_START
#define CPU_PCI_MEM_START PCI_MSTR_MEM_LOCAL
#else
#define CPU_PCI_MEM_START CONFIG_SYS_CPU_PCI_MEM_START
#endif
#ifndef CONFIG_SYS_PCI_MSTR_MEM_SIZE
#define PCI_MSTR_MEM_SIZE 0x10000000 /* 256MB */
#else
#define PCI_MSTR_MEM_SIZE CONFIG_SYS_PCI_MSTR_MEM_SIZE
#endif
#ifndef CONFIG_SYS_POCMR0_MASK_ATTRIB
#define POCMR0_MASK_ATTRIB (POCMR_MASK_256MB | POCMR_ENABLE | POCMR_PREFETCH_EN)
#else
#define POCMR0_MASK_ATTRIB CONFIG_SYS_POCMR0_MASK_ATTRIB
#endif
/*
* Master window that allows the CPU to access PCI Memory (non-prefetch).
* This window will be setup with the second set of Outbound ATU registers
* in the bridge.
*/
#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_LOCAL
#define PCI_MSTR_MEMIO_LOCAL 0x90000000 /* Local base */
#else
#define PCI_MSTR_MEMIO_LOCAL CONFIG_SYS_PCI_MSTR_MEMIO_LOCAL
#endif
#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_BUS
#define PCI_MSTR_MEMIO_BUS 0x90000000 /* PCI base */
#else
#define PCI_MSTR_MEMIO_BUS CONFIG_SYS_PCI_MSTR_MEMIO_BUS
#endif
#ifndef CONFIG_SYS_CPU_PCI_MEMIO_START
#define CPU_PCI_MEMIO_START PCI_MSTR_MEMIO_LOCAL
#else
#define CPU_PCI_MEMIO_START CONFIG_SYS_CPU_PCI_MEMIO_START
#endif
#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_SIZE
#define PCI_MSTR_MEMIO_SIZE 0x10000000 /* 256 MB */
#else
#define PCI_MSTR_MEMIO_SIZE CONFIG_SYS_PCI_MSTR_MEMIO_SIZE
#endif
#ifndef CONFIG_SYS_POCMR1_MASK_ATTRIB
#define POCMR1_MASK_ATTRIB (POCMR_MASK_512MB | POCMR_ENABLE)
#else
#define POCMR1_MASK_ATTRIB CONFIG_SYS_POCMR1_MASK_ATTRIB
#endif
/*
* Master window that allows the CPU to access PCI IO space.
* This window will be setup with the third set of Outbound ATU registers
* in the bridge.
*/
#ifndef CONFIG_SYS_PCI_MSTR_IO_LOCAL
#define PCI_MSTR_IO_LOCAL 0xA0000000 /* Local base */
#else
#define PCI_MSTR_IO_LOCAL CONFIG_SYS_PCI_MSTR_IO_LOCAL
#endif
#ifndef CONFIG_SYS_PCI_MSTR_IO_BUS
#define PCI_MSTR_IO_BUS 0xA0000000 /* PCI base */
#else
#define PCI_MSTR_IO_BUS CONFIG_SYS_PCI_MSTR_IO_BUS
#endif
#ifndef CONFIG_SYS_CPU_PCI_IO_START
#define CPU_PCI_IO_START PCI_MSTR_IO_LOCAL
#else
#define CPU_PCI_IO_START CONFIG_SYS_CPU_PCI_IO_START
#endif
#ifndef CONFIG_SYS_PCI_MSTR_IO_SIZE
#define PCI_MSTR_IO_SIZE 0x10000000 /* 256MB */
#else
#define PCI_MSTR_IO_SIZE CONFIG_SYS_PCI_MSTR_IO_SIZE
#endif
#ifndef CONFIG_SYS_POCMR2_MASK_ATTRIB
#define POCMR2_MASK_ATTRIB (POCMR_MASK_256MB | POCMR_ENABLE | POCMR_PCI_IO)
#else
#define POCMR2_MASK_ATTRIB CONFIG_SYS_POCMR2_MASK_ATTRIB
#endif
/* PCI bus configuration registers.
*/
#define PCI_CLASS_BRIDGE_CTLR 0x06
static inline void pci_outl (u32 addr, u32 data)
{
*(volatile u32 *) addr = cpu_to_le32 (data);
}
void pci_mpc8250_init (struct pci_controller *hose)
{
u16 tempShort;
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
pci_dev_t host_devno = PCI_BDF (0, 0, 0);
pci_setup_indirect (hose, CONFIG_SYS_IMMR + PCI_CFG_ADDR_REG,
CONFIG_SYS_IMMR + PCI_CFG_DATA_REG);
/*
* Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
* and local bus for PCI (SIUMCR [LBPC]).
*/
immap->im_siu_conf.sc_siumcr = (immap->im_siu_conf.sc_siumcr &
~SIUMCR_LBPC11 &
~SIUMCR_CS10PC11 &
~SIUMCR_LBPC11) |
SIUMCR_LBPC01 |
SIUMCR_CS10PC01 |
SIUMCR_APPC10;
/* Make PCI lowest priority */
/* Each 4 bits is a device bus request and the MS 4bits
is highest priority */
/* Bus 4bit value
--- ----------
CPM high 0b0000
CPM middle 0b0001
CPM low 0b0010
PCI reguest 0b0011
Reserved 0b0100
Reserved 0b0101
Internal Core 0b0110
External Master 1 0b0111
External Master 2 0b1000
External Master 3 0b1001
The rest are reserved */
immap->im_siu_conf.sc_ppc_alrh = 0x61207893;
/* Park bus on core while modifying PCI Bus accesses */
immap->im_siu_conf.sc_ppc_acr = 0x6;
/*
* Set up master windows that allow the CPU to access PCI space. These
* windows are set up using the two SIU PCIBR registers.
*/
immap->im_memctl.memc_pcimsk0 = PCIMSK0_MASK;
immap->im_memctl.memc_pcibr0 = PCI_MSTR0_LOCAL | PCIBR_ENABLE;
/* Release PCI RST (by default the PCI RST signal is held low) */
immap->im_pci.pci_gcr = cpu_to_le32 (PCIGCR_PCI_BUS_EN);
/* give it some time */
{
udelay (1000);
}
/*
* Set up master window that allows the CPU to access PCI Memory (prefetch)
* space. This window is set up using the first set of Outbound ATU registers.
*/
immap->im_pci.pci_potar0 = cpu_to_le32 (PCI_MSTR_MEM_BUS >> 12); /* PCI base */
immap->im_pci.pci_pobar0 = cpu_to_le32 (PCI_MSTR_MEM_LOCAL >> 12); /* Local base */
immap->im_pci.pci_pocmr0 = cpu_to_le32 (POCMR0_MASK_ATTRIB); /* Size & attribute */
/*
* Set up master window that allows the CPU to access PCI Memory (non-prefetch)
* space. This window is set up using the second set of Outbound ATU registers.
*/
immap->im_pci.pci_potar1 = cpu_to_le32 (PCI_MSTR_MEMIO_BUS >> 12); /* PCI base */
immap->im_pci.pci_pobar1 = cpu_to_le32 (PCI_MSTR_MEMIO_LOCAL >> 12); /* Local base */
immap->im_pci.pci_pocmr1 = cpu_to_le32 (POCMR1_MASK_ATTRIB); /* Size & attribute */
/*
* Set up master window that allows the CPU to access PCI IO space. This window
* is set up using the third set of Outbound ATU registers.
*/
immap->im_pci.pci_potar2 = cpu_to_le32 (PCI_MSTR_IO_BUS >> 12); /* PCI base */
immap->im_pci.pci_pobar2 = cpu_to_le32 (PCI_MSTR_IO_LOCAL >> 12); /* Local base */
immap->im_pci.pci_pocmr2 = cpu_to_le32 (POCMR2_MASK_ATTRIB); /* Size & attribute */
/*
* Set up slave window that allows PCI masters to access MPC826x local memory.
* This window is set up using the first set of Inbound ATU registers
*/
immap->im_pci.pci_pitar0 = cpu_to_le32 (PCI_SLV_MEM_LOCAL >> 12); /* PCI base */
immap->im_pci.pci_pibar0 = cpu_to_le32 (PCI_SLV_MEM_BUS >> 12); /* Local base */
immap->im_pci.pci_picmr0 = cpu_to_le32 (PICMR0_MASK_ATTRIB); /* Size & attribute */
/* See above for description - puts PCI request as highest priority */
immap->im_siu_conf.sc_ppc_alrh = 0x03124567;
/* Park the bus on the PCI */
immap->im_siu_conf.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
/* Host mode - specify the bridge as a host-PCI bridge */
pci_hose_write_config_byte (hose, host_devno, PCI_CLASS_CODE,
PCI_CLASS_BRIDGE_CTLR);
/* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */
pci_hose_read_config_word (hose, host_devno, PCI_COMMAND, &tempShort);
pci_hose_write_config_word (hose, host_devno, PCI_COMMAND,
tempShort | PCI_COMMAND_MASTER |
PCI_COMMAND_MEMORY);
/* do some bridge init, should be done on all 8260 based bridges */
pci_hose_write_config_byte (hose, host_devno, PCI_CACHE_LINE_SIZE,
0x08);
pci_hose_write_config_byte (hose, host_devno, PCI_LATENCY_TIMER,
0xF8);
hose->first_busno = 0;
hose->last_busno = 0xff;
/* System memory space */
pci_set_region (hose->regions + 0,
CONFIG_SYS_SDRAM_BASE,
CONFIG_SYS_SDRAM_BASE,
0x4000000, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
/* PCI memory space */
pci_set_region (hose->regions + 1,
PCI_MSTR_MEM_BUS,
PCI_MSTR_MEM_LOCAL,
PCI_MSTR_MEM_SIZE, PCI_REGION_MEM);
/* PCI I/O space */
pci_set_region (hose->regions + 2,
PCI_MSTR_IO_BUS,
PCI_MSTR_IO_LOCAL, PCI_MSTR_IO_SIZE, PCI_REGION_IO);
hose->region_count = 3;
pci_register_hose (hose);
/* Mask off master abort machine checks */
immap->im_pci.pci_emr &= cpu_to_le32 (~PCI_ERROR_PCI_NO_RSP);
eieio ();
hose->last_busno = pci_hose_scan (hose);
/* clear the error in the error status register */
immap->im_pci.pci_esr = cpu_to_le32 (PCI_ERROR_PCI_NO_RSP);
/* unmask master abort machine checks */
immap->im_pci.pci_emr |= cpu_to_le32 (PCI_ERROR_PCI_NO_RSP);
}
#if defined(CONFIG_OF_LIBFDT)
void ft_pci_setup(void *blob, bd_t *bd)
{
do_fixup_by_prop_u32(blob, "device_type", "pci", 4,
"clock-frequency", gd->pci_clk, 1);
}
#endif
#endif /* CONFIG_PCI */

View File

@@ -0,0 +1,492 @@
/*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*
* 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>
#include <serial.h>
#include <linux/compiler.h>
DECLARE_GLOBAL_DATA_PTR;
#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
static int mpc8260_scc_serial_init(void)
{
volatile immap_t *im = (immap_t *)CONFIG_SYS_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);
}
static void mpc8260_scc_serial_setbrg(void)
{
#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
}
static void mpc8260_scc_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 *)CONFIG_SYS_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;
}
static int mpc8260_scc_serial_getc(void)
{
volatile cbd_t *rbdf;
volatile scc_uart_t *up;
volatile immap_t *im;
unsigned char c;
im = (immap_t *)CONFIG_SYS_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);
}
static int mpc8260_scc_serial_tstc(void)
{
volatile cbd_t *rbdf;
volatile scc_uart_t *up;
volatile immap_t *im;
im = (immap_t *)CONFIG_SYS_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);
}
static struct serial_device mpc8260_scc_serial_drv = {
.name = "mpc8260_scc_uart",
.start = mpc8260_scc_serial_init,
.stop = NULL,
.setbrg = mpc8260_scc_serial_setbrg,
.putc = mpc8260_scc_serial_putc,
.puts = default_serial_puts,
.getc = mpc8260_scc_serial_getc,
.tstc = mpc8260_scc_serial_tstc,
};
void mpc8260_scc_serial_initialize(void)
{
serial_register(&mpc8260_scc_serial_drv);
}
__weak struct serial_device *default_serial_console(void)
{
return &mpc8260_scc_serial_drv;
}
#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 *)CONFIG_SYS_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 *)CONFIG_SYS_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 *)CONFIG_SYS_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 */

View File

@@ -0,0 +1,461 @@
/*
* (C) Copyright 2000, 2001, 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*
* Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
* changes based on the file arch/powerpc/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>
#include <serial.h>
#include <linux/compiler.h>
DECLARE_GLOBAL_DATA_PTR;
#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
#if !defined(CONFIG_SYS_SMC_RXBUFLEN)
#define CONFIG_SYS_SMC_RXBUFLEN 1
#define CONFIG_SYS_MAXIDLE 0
#else
#if !defined(CONFIG_SYS_MAXIDLE)
#error "you must define CONFIG_SYS_MAXIDLE"
#endif
#endif
typedef volatile struct serialbuffer {
cbd_t rxbd; /* Rx BD */
cbd_t txbd; /* Tx BD */
uint rxindex; /* index for next character to read */
volatile uchar rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
volatile uchar txbuf; /* tx buffers */
} serialbuffer_t;
/* 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 */
};
static int mpc8260_smc_serial_init(void)
{
volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
volatile smc_t *sp;
volatile smc_uart_t *up;
volatile cpm8260_t *cp = &(im->im_cpm);
uint dpaddr;
volatile serialbuffer_t *rtx;
/* initialize pointers to SMC */
sp = (smc_t *) &(im->im_smc[SMC_INDEX]);
im->im_dprambase16[PROFF_SMC_BASE / sizeof(u16)] = 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
*/
/* allocate size of struct serialbuffer with bd rx/tx,
* buffer rx/tx and rx index
*/
dpaddr = m8260_cpm_dpalloc((sizeof(serialbuffer_t)), 16);
rtx = (serialbuffer_t *)&im->im_dprambase[dpaddr];
/* Set the physical address of the host memory buffers in
* the buffer descriptors.
*/
rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf;
rtx->rxbd.cbd_sc = 0;
rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf;
rtx->txbd.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. */
rtx->txbd.cbd_sc |= BD_SC_WRAP;
rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
/* single/multi character receive. */
up->smc_mrblr = CONFIG_SYS_SMC_RXBUFLEN;
up->smc_maxidl = CONFIG_SYS_MAXIDLE;
rtx->rxindex = 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);
}
static void mpc8260_smc_serial_setbrg(void)
{
#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
}
static void mpc8260_smc_serial_putc(const char c)
{
volatile smc_uart_t *up;
volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
volatile serialbuffer_t *rtx;
if (c == '\n')
serial_putc ('\r');
up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
/* Wait for last character to go. */
while (rtx->txbd.cbd_sc & BD_SC_READY & BD_SC_READY)
;
rtx->txbuf = c;
rtx->txbd.cbd_datlen = 1;
rtx->txbd.cbd_sc |= BD_SC_READY;
}
static int mpc8260_smc_serial_getc(void)
{
volatile smc_uart_t *up;
volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
volatile serialbuffer_t *rtx;
unsigned char c;
up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
/* Wait for character to show up. */
while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
;
/* the characters are read one by one,
* use the rxindex to know the next char to deliver
*/
c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr + rtx->rxindex);
rtx->rxindex++;
/* check if all char are readout, then make prepare for next receive */
if (rtx->rxindex >= rtx->rxbd.cbd_datlen) {
rtx->rxindex = 0;
rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
}
return(c);
}
static int mpc8260_smc_serial_tstc(void)
{
volatile smc_uart_t *up;
volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
volatile serialbuffer_t *rtx;
up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY);
}
static struct serial_device mpc8260_smc_serial_drv = {
.name = "mpc8260_smc_uart",
.start = mpc8260_smc_serial_init,
.stop = NULL,
.setbrg = mpc8260_smc_serial_setbrg,
.putc = mpc8260_smc_serial_putc,
.puts = default_serial_puts,
.getc = mpc8260_smc_serial_getc,
.tstc = mpc8260_smc_serial_tstc,
};
void mpc8260_smc_serial_initialize(void)
{
serial_register(&mpc8260_smc_serial_drv);
}
__weak struct serial_device *default_serial_console(void)
{
return &mpc8260_smc_serial_drv;
}
#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 *)CONFIG_SYS_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]);
im->im_dprambase16[KGDB_PROFF_SMC_BASE / sizeof(u16)] = 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(brg_map[KGDB_SMC_INDEX], speed,
CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL);
#else
m8260_cpm_setbrg(brg_map[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 *)CONFIG_SYS_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 *)CONFIG_SYS_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 */

View File

@@ -0,0 +1,228 @@
/*
* (C) Copyright 2000-2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <mpc8260.h>
#include <asm/processor.h>
#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
extern unsigned long board_get_cpu_clk_f (void);
#endif
DECLARE_GLOBAL_DATA_PTR;
/* ------------------------------------------------------------------------- */
/* 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)
{
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
ulong clkin;
ulong sccr, dfbrg;
ulong scmr, corecnf, plldf, pllmf;
corecnf_t *cp;
#if !defined(CONFIG_8260_CLKIN)
#error clock measuring not implemented yet - define CONFIG_8260_CLKIN
#else
#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
clkin = board_get_cpu_clk_f ();
#else
clkin = CONFIG_8260_CLKIN;
#endif
#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;
cp = &corecnf_tab[corecnf];
/* HiP7, HiP7 Rev01, HiP7 RevA */
if ((get_pvr () == PVR_8260_HIP7) ||
(get_pvr () == PVR_8260_HIP7R1) ||
(get_pvr () == PVR_8260_HIP7RA)) {
pllmf = (scmr & SCMR_PLLMF_MSKH7) >> SCMR_PLLMF_SHIFT;
gd->arch.vco_out = clkin * (pllmf + 1);
} else { /* HiP3, HiP4 */
pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
gd->arch.vco_out = (clkin * 2 * (pllmf + 1)) / (plldf + 1);
}
gd->arch.cpm_clk = gd->arch.vco_out / 2;
gd->bus_clk = clkin;
gd->arch.scc_clk = gd->arch.vco_out / 4;
gd->arch.brg_clk = gd->arch.vco_out / (1 << (2 * (dfbrg + 1)));
if (cp->b2c_mult > 0) {
gd->cpu_clk = (clkin * cp->b2c_mult) / 2;
} else {
gd->cpu_clk = clkin;
}
#ifdef CONFIG_PCI
gd->pci_clk = clkin;
if (sccr & SCCR_PCI_MODE) {
uint pci_div;
uint pcidf = (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT;
if (sccr & SCCR_PCI_MODCK) {
pci_div = 2;
if (pcidf == 9) {
pci_div *= 5;
} else if (pcidf == 0xB) {
pci_div *= 6;
} else {
pci_div *= (pcidf + 1);
}
} else {
pci_div = pcidf + 1;
}
gd->pci_clk = (gd->arch.cpm_clk * 2) / pci_div;
}
#endif
return (0);
}
int prt_8260_clks (void)
{
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
ulong sccr, dfbrg;
ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf, pcidf;
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;
pcidf = (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT;
cp = &corecnf_tab[corecnf];
puts (CPU_ID_STR " Clock Configuration\n - Bus-to-Core Mult ");
switch (cp->b2c_mult) {
case _byp:
puts ("BYPASS");
break;
case _off:
puts ("OFF");
break;
case _unk:
puts ("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, pcidf %ld\n",
dfbrg, corecnf, busdf, cpmdf,
plldf, pllmf, pcidf);
printf (" - vco_out %10ld, scc_clk %10ld, brg_clk %10ld\n",
gd->arch.vco_out, gd->arch.scc_clk, gd->arch.brg_clk);
printf (" - cpu_clk %10ld, cpm_clk %10ld, bus_clk %10ld\n",
gd->cpu_clk, gd->arch.cpm_clk, gd->bus_clk);
#ifdef CONFIG_PCI
printf (" - pci_clk %10ld\n", gd->pci_clk);
#endif
putc ('\n');
return (0);
}

View File

@@ -0,0 +1,415 @@
/*
* Copyright (c) 2001 Navin Boppuri / Prashant Patel
* <nboppuri@trinetcommunication.com>,
* <pmpatel@trinetcommunication.com>
* Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
* Copyright (c) 2001-2003 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* MPC8260 CPM SPI interface.
*
* Parts of this code are probably not portable and/or specific to
* the board which I used for the tests. Please send fixes/complaints
* to wd@denx.de
*
*/
#include <common.h>
#include <asm/cpm_8260.h>
#include <linux/ctype.h>
#include <malloc.h>
#include <post.h>
#include <net.h>
#if defined(CONFIG_SPI)
/* Warning:
* You cannot enable DEBUG for early system initalization, i. e. when
* this driver is used to read environment parameters like "baudrate"
* from EEPROM which are used to initialize the serial port which is
* needed to print the debug messages...
*/
#undef DEBUG
#define SPI_EEPROM_WREN 0x06
#define SPI_EEPROM_RDSR 0x05
#define SPI_EEPROM_READ 0x03
#define SPI_EEPROM_WRITE 0x02
/* ---------------------------------------------------------------
* Offset for initial SPI buffers in DPRAM:
* We need a 520 byte scratch DPRAM area to use at an early stage.
* It is used between the two initialization calls (spi_init_f()
* and spi_init_r()).
* The value 0x2000 makes it far enough from the start of the data
* area (as well as from the stack pointer).
* --------------------------------------------------------------- */
#ifndef CONFIG_SYS_SPI_INIT_OFFSET
#define CONFIG_SYS_SPI_INIT_OFFSET 0x2000
#endif
#define CPM_SPI_BASE 0x100
#ifdef DEBUG
#define DPRINT(a) printf a;
/* -----------------------------------------------
* Helper functions to peek into tx and rx buffers
* ----------------------------------------------- */
static const char * const hex_digit = "0123456789ABCDEF";
static char quickhex (int i)
{
return hex_digit[i];
}
static void memdump (void *pv, int num)
{
int i;
unsigned char *pc = (unsigned char *) pv;
for (i = 0; i < num; i++)
printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
printf ("\t");
for (i = 0; i < num; i++)
printf ("%c", isprint (pc[i]) ? pc[i] : '.');
printf ("\n");
}
#else /* !DEBUG */
#define DPRINT(a)
#endif /* DEBUG */
/* -------------------
* Function prototypes
* ------------------- */
void spi_init (void);
ssize_t spi_read (uchar *, int, uchar *, int);
ssize_t spi_write (uchar *, int, uchar *, int);
ssize_t spi_xfer (size_t);
/* -------------------
* Variables
* ------------------- */
#define MAX_BUFFER 0x104
/* ----------------------------------------------------------------------
* Initially we place the RX and TX buffers at a fixed location in DPRAM!
* ---------------------------------------------------------------------- */
static uchar *rxbuf =
(uchar *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
[CONFIG_SYS_SPI_INIT_OFFSET];
static uchar *txbuf =
(uchar *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
[CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
/* **************************************************************************
*
* Function: spi_init_f
*
* Description: Init SPI-Controller (ROM part)
*
* return: ---
*
* *********************************************************************** */
void spi_init_f (void)
{
unsigned int dpaddr;
volatile spi_t *spi;
volatile immap_t *immr;
volatile cpm8260_t *cp;
volatile cbd_t *tbdf, *rbdf;
immr = (immap_t *) CONFIG_SYS_IMMR;
cp = (cpm8260_t *) &immr->im_cpm;
immr->im_dprambase16[PROFF_SPI_BASE / sizeof(u16)] = PROFF_SPI;
spi = (spi_t *)&immr->im_dprambase[PROFF_SPI];
/* 1 */
/* ------------------------------------------------
* Initialize Port D SPI pins
* (we are only in Master Mode !)
* ------------------------------------------------ */
/* --------------------------------------------
* GPIO or per. Function
* PPARD[16] = 1 [0x00008000] (SPIMISO)
* PPARD[17] = 1 [0x00004000] (SPIMOSI)
* PPARD[18] = 1 [0x00002000] (SPICLK)
* PPARD[12] = 0 [0x00080000] -> GPIO: (CS for ATC EEPROM)
* -------------------------------------------- */
immr->im_ioport.iop_ppard |= 0x0000E000; /* set bits */
immr->im_ioport.iop_ppard &= ~0x00080000; /* reset bit */
/* ----------------------------------------------
* In/Out or per. Function 0/1
* PDIRD[16] = 0 [0x00008000] -> PERI1: SPIMISO
* PDIRD[17] = 0 [0x00004000] -> PERI1: SPIMOSI
* PDIRD[18] = 0 [0x00002000] -> PERI1: SPICLK
* PDIRD[12] = 1 [0x00080000] -> GPIO OUT: CS for ATC EEPROM
* ---------------------------------------------- */
immr->im_ioport.iop_pdird &= ~0x0000E000;
immr->im_ioport.iop_pdird |= 0x00080000;
/* ----------------------------------------------
* special option reg.
* PSORD[16] = 1 [0x00008000] -> SPIMISO
* PSORD[17] = 1 [0x00004000] -> SPIMOSI
* PSORD[18] = 1 [0x00002000] -> SPICLK
* ---------------------------------------------- */
immr->im_ioport.iop_psord |= 0x0000E000;
/* Initialize the parameter ram.
* We need to make sure many things are initialized to zero
*/
spi->spi_rstate = 0;
spi->spi_rdp = 0;
spi->spi_rbptr = 0;
spi->spi_rbc = 0;
spi->spi_rxtmp = 0;
spi->spi_tstate = 0;
spi->spi_tdp = 0;
spi->spi_tbptr = 0;
spi->spi_tbc = 0;
spi->spi_txtmp = 0;
/* Allocate space for one transmit and one receive buffer
* descriptor in the DP ram
*/
#ifdef CONFIG_SYS_ALLOC_DPRAM
dpaddr = m8260_cpm_dpalloc (sizeof(cbd_t)*2, 8);
#else
dpaddr = CPM_SPI_BASE;
#endif
/* 3 */
/* Set up the SPI parameters in the parameter ram */
spi->spi_rbase = dpaddr;
spi->spi_tbase = dpaddr + sizeof (cbd_t);
/***********IMPORTANT******************/
/*
* Setting transmit and receive buffer descriptor pointers
* initially to rbase and tbase. Only the microcode patches
* documentation talks about initializing this pointer. This
* is missing from the sample I2C driver. If you dont
* initialize these pointers, the kernel hangs.
*/
spi->spi_rbptr = spi->spi_rbase;
spi->spi_tbptr = spi->spi_tbase;
/* 4 */
/* Init SPI Tx + Rx Parameters */
while (cp->cp_cpcr & CPM_CR_FLG)
;
cp->cp_cpcr = mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK,
0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG)
;
/* 6 */
/* Set to big endian. */
spi->spi_tfcr = CPMFCR_EB;
spi->spi_rfcr = CPMFCR_EB;
/* 7 */
/* Set maximum receive size. */
spi->spi_mrblr = MAX_BUFFER;
/* 8 + 9 */
/* tx and rx buffer descriptors */
tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
tbdf->cbd_sc &= ~BD_SC_READY;
rbdf->cbd_sc &= ~BD_SC_EMPTY;
/* Set the bd's rx and tx buffer address pointers */
rbdf->cbd_bufaddr = (ulong) rxbuf;
tbdf->cbd_bufaddr = (ulong) txbuf;
/* 10 + 11 */
immr->im_spi.spi_spie = SPI_EMASK; /* Clear all SPI events */
immr->im_spi.spi_spim = 0x00; /* Mask all SPI events */
return;
}
/* **************************************************************************
*
* Function: spi_init_r
*
* Description: Init SPI-Controller (RAM part) -
* The malloc engine is ready and we can move our buffers to
* normal RAM
*
* return: ---
*
* *********************************************************************** */
void spi_init_r (void)
{
volatile spi_t *spi;
volatile immap_t *immr;
volatile cbd_t *tbdf, *rbdf;
immr = (immap_t *) CONFIG_SYS_IMMR;
spi = (spi_t *)&immr->im_dprambase[PROFF_SPI];
/* tx and rx buffer descriptors */
tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
/* Allocate memory for RX and TX buffers */
rxbuf = (uchar *) malloc (MAX_BUFFER);
txbuf = (uchar *) malloc (MAX_BUFFER);
rbdf->cbd_bufaddr = (ulong) rxbuf;
tbdf->cbd_bufaddr = (ulong) txbuf;
return;
}
/****************************************************************************
* Function: spi_write
**************************************************************************** */
ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
{
int i;
memset(rxbuf, 0, MAX_BUFFER);
memset(txbuf, 0, MAX_BUFFER);
*txbuf = SPI_EEPROM_WREN; /* write enable */
spi_xfer(1);
memcpy(txbuf, addr, alen);
*txbuf = SPI_EEPROM_WRITE; /* WRITE memory array */
memcpy(alen + txbuf, buffer, len);
spi_xfer(alen + len);
/* ignore received data */
for (i = 0; i < 1000; i++) {
*txbuf = SPI_EEPROM_RDSR; /* read status */
txbuf[1] = 0;
spi_xfer(2);
if (!(rxbuf[1] & 1)) {
break;
}
udelay(1000);
}
if (i >= 1000) {
printf ("*** spi_write: Time out while writing!\n");
}
return len;
}
/****************************************************************************
* Function: spi_read
**************************************************************************** */
ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
{
memset(rxbuf, 0, MAX_BUFFER);
memset(txbuf, 0, MAX_BUFFER);
memcpy(txbuf, addr, alen);
*txbuf = SPI_EEPROM_READ; /* READ memory array */
/*
* There is a bug in 860T (?) that cuts the last byte of input
* if we're reading into DPRAM. The solution we choose here is
* to always read len+1 bytes (we have one extra byte at the
* end of the buffer).
*/
spi_xfer(alen + len + 1);
memcpy(buffer, alen + rxbuf, len);
return len;
}
/****************************************************************************
* Function: spi_xfer
**************************************************************************** */
ssize_t spi_xfer (size_t count)
{
volatile immap_t *immr;
volatile spi_t *spi;
cbd_t *tbdf, *rbdf;
int tm;
DPRINT (("*** spi_xfer entered ***\n"));
immr = (immap_t *) CONFIG_SYS_IMMR;
spi = (spi_t *)&immr->im_dprambase[PROFF_SPI];
tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
/* Board-specific: Set CS for device (ATC EEPROM) */
immr->im_ioport.iop_pdatd &= ~0x00080000;
/* Setting tx bd status and data length */
tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
tbdf->cbd_datlen = count;
DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
tbdf->cbd_datlen));
/* Setting rx bd status and data length */
rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
rbdf->cbd_datlen = 0; /* rx length has no significance */
immr->im_spi.spi_spmode = SPMODE_REV |
SPMODE_MSTR |
SPMODE_EN |
SPMODE_LEN(8) | /* 8 Bits per char */
SPMODE_PM(0x8) ; /* medium speed */
immr->im_spi.spi_spie = SPI_EMASK; /* Clear all SPI events */
immr->im_spi.spi_spim = 0x00; /* Mask all SPI events */
/* start spi transfer */
DPRINT (("*** spi_xfer: Performing transfer ...\n"));
immr->im_spi.spi_spcom |= SPI_STR; /* Start transmit */
/* --------------------------------
* Wait for SPI transmit to get out
* or time out (1 second = 1000 ms)
* -------------------------------- */
for (tm=0; tm<1000; ++tm) {
if (immr->im_spi.spi_spie & SPI_TXB) { /* Tx Buffer Empty */
DPRINT (("*** spi_xfer: Tx buffer empty\n"));
break;
}
if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
DPRINT (("*** spi_xfer: Tx BD done\n"));
break;
}
udelay (1000);
}
if (tm >= 1000) {
printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
}
DPRINT (("*** spi_xfer: ... transfer ended\n"));
#ifdef DEBUG
printf ("\nspi_xfer: txbuf after xfer\n");
memdump ((void *) txbuf, 16); /* dump of txbuf before transmit */
printf ("spi_xfer: rxbuf after xfer\n");
memdump ((void *) rxbuf, 16); /* dump of rxbuf after transmit */
printf ("\n");
#endif
/* Clear CS for device */
immr->im_ioport.iop_pdatd |= 0x00080000;
return count;
}
#endif /* CONFIG_SPI */

View File

@@ -0,0 +1,901 @@
/*
* Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
* Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* U-Boot - Startup Code for MPC8260 PowerPC based Embedded Boards
*/
#include <asm-offsets.h>
#include <config.h>
#include <mpc8260.h>
#include <version.h>
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <asm/cache.h>
#include <asm/mmu.h>
#include <asm/u-boot.h>
/* We don't want the MMU yet.
*/
#undef MSR_KERNEL
/* Floating Point enable, Machine Check and Recoverable Interr. */
#ifdef DEBUG
#define MSR_KERNEL (MSR_FP|MSR_RI)
#else
#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
#endif
/*
* Set up GOT: Global Offset Table
*
* Use r12 to access the GOT
*/
START_GOT
GOT_ENTRY(_GOT2_TABLE_)
GOT_ENTRY(_FIXUP_TABLE_)
GOT_ENTRY(_start)
GOT_ENTRY(_start_of_vectors)
GOT_ENTRY(_end_of_vectors)
GOT_ENTRY(transfer_to_handler)
GOT_ENTRY(__init_end)
GOT_ENTRY(__bss_end)
GOT_ENTRY(__bss_start)
END_GOT
/*
* Version string - must be in data segment because MPC8260 uses the first
* 256 bytes for the Hard Reset Configuration Word table (see below).
* Similarly, can't have the U-Boot Magic Number as the first thing in
* the image - don't know how this will affect the image tools, but I guess
* I'll find out soon
*/
.data
.globl version_string
version_string:
.ascii U_BOOT_VERSION_STRING, "\0"
/*
* Hard Reset Configuration Word (HRCW) table
*
* The Hard Reset Configuration Word (HRCW) sets a number of useful things
* such as whether there is an external memory controller, whether the
* PowerPC core is disabled (i.e. only the communications processor is
* active, accessed by another CPU on the bus), whether using external
* arbitration, external bus mode, boot port size, core initial prefix,
* internal space base, boot memory space, etc.
*
* These things dictate where the processor begins execution, where the
* boot ROM appears in memory, the memory controller setup when access
* boot ROM, etc. The HRCW is *extremely* important.
*
* The HRCW is read from the bus during reset. One CPU on the bus will
* be a hard reset configuration master, any others will be hard reset
* configuration slaves. The master reads eight HRCWs from flash during
* reset - the first it uses for itself, the other 7 it communicates to
* up to 7 configuration slaves by some complicated mechanism, which is
* not really important here.
*
* The configuration master performs 32 successive reads starting at address
* 0 and incrementing by 8 each read (i.e. on 64 bit boundaries) but only 8
* bits is read, and always from byte lane D[0-7] (so that port size of the
* boot device does not matter). The first four reads form the 32 bit HRCW
* for the master itself. The second four reads form the HRCW for the first
* slave, and so on, up to seven slaves. The 32 bit HRCW is formed by
* concatenating the four bytes, with the first read placed in byte 0 (the
* most significant byte), and so on with the fourth read placed in byte 3
* (the least significant byte).
*/
#define _HRCW_TABLE_ENTRY(w) \
.fill 8,1,(((w)>>24)&0xff); \
.fill 8,1,(((w)>>16)&0xff); \
.fill 8,1,(((w)>> 8)&0xff); \
.fill 8,1,(((w) )&0xff)
.text
.globl _hrcw_table
_hrcw_table:
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_MASTER)
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE1)
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE2)
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE3)
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE4)
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE5)
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE6)
_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE7)
/*
* After configuration, a system reset exception is executed using the
* vector at offset 0x100 relative to the base set by MSR[IP]. If MSR[IP]
* is 0, the base address is 0x00000000. If MSR[IP] is 1, the base address
* is 0xfff00000. In the case of a Power On Reset or Hard Reset, the value
* of MSR[IP] is determined by the CIP field in the HRCW.
*
* Other bits in the HRCW set up the Base Address and Port Size in BR0.
* This determines the location of the boot ROM (flash or EPROM) in the
* processor's address space at boot time. As long as the HRCW is set up
* so that we eventually end up executing the code below when the processor
* executes the reset exception, the actual values used should not matter.
*
* Once we have got here, the address mask in OR0 is cleared so that the
* bottom 32K of the boot ROM is effectively repeated all throughout the
* processor's address space, after which we can jump to the absolute
* address at which the boot ROM was linked at compile time, and proceed
* to initialise the memory controller without worrying if the rug will be
* pulled out from under us, so to speak (it will be fine as long as we
* configure BR0 with the same boot ROM link address).
*/
. = EXC_OFF_SYS_RESET
.globl _start
_start:
mfmsr r5 /* save msr contents */
#if defined(CONFIG_SYS_DEFAULT_IMMR)
lis r3, CONFIG_SYS_IMMR@h
ori r3, r3, CONFIG_SYS_IMMR@l
lis r4, CONFIG_SYS_DEFAULT_IMMR@h
stw r3, 0x1A8(r4)
#endif /* CONFIG_SYS_DEFAULT_IMMR */
/* Initialise the MPC8260 processor core */
/*--------------------------------------------------------------*/
bl init_8260_core
#ifndef CONFIG_SYS_RAMBOOT
/* When booting from ROM (Flash or EPROM), clear the */
/* Address Mask in OR0 so ROM appears everywhere */
/*--------------------------------------------------------------*/
lis r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
lwz r4, IM_OR0@l(r3)
li r5, 0x7fff
and r4, r4, r5
stw r4, IM_OR0@l(r3)
/* Calculate absolute address in FLASH and jump there */
/*--------------------------------------------------------------*/
lis r3, CONFIG_SYS_MONITOR_BASE@h
ori r3, r3, CONFIG_SYS_MONITOR_BASE@l
addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
mtlr r3
blr
in_flash:
#endif /* CONFIG_SYS_RAMBOOT */
/* initialize some things that are hard to access from C */
/*--------------------------------------------------------------*/
lis r3, CONFIG_SYS_IMMR@h /* set up stack in internal DPRAM */
ori r1, r3, CONFIG_SYS_INIT_SP_OFFSET
li r0, 0 /* Make room for stack frame header and */
stwu r0, -4(r1) /* clear final stack frame so that */
stwu r0, -4(r1) /* stack backtraces terminate cleanly */
/* let the C-code set up the rest */
/* */
/* Be careful to keep code relocatable ! */
/*--------------------------------------------------------------*/
GET_GOT /* initialize GOT access */
/* r3: IMMR */
bl cpu_init_f /* run low-level CPU init code (in Flash)*/
#ifdef DEBUG
bl init_debug /* set up debugging stuff */
#endif
bl board_init_f /* run 1st part of board init code (in Flash)*/
/* NOTREACHED - board_init_f() does not return */
/*
* Vector Table
*/
.globl _start_of_vectors
_start_of_vectors:
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
/* Data Storage exception. */
STD_EXCEPTION(0x300, DataStorage, UnknownException)
/* Instruction Storage exception. */
STD_EXCEPTION(0x400, InstStorage, UnknownException)
/* External Interrupt exception. */
STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
/* Alignment exception. */
. = 0x600
Alignment:
EXCEPTION_PROLOG(SRR0, SRR1)
mfspr r4,DAR
stw r4,_DAR(r21)
mfspr r5,DSISR
stw r5,_DSISR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
/* Program check exception */
. = 0x700
ProgramCheck:
EXCEPTION_PROLOG(SRR0, SRR1)
addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
MSR_KERNEL, COPY_EE)
STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
/* I guess we could implement decrementer, and may have
* to someday for timekeeping.
*/
STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
STD_EXCEPTION(0xc00, SystemCall, UnknownException)
STD_EXCEPTION(0xd00, SingleStep, UnknownException)
STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
#ifdef DEBUG
. = 0x1300
/*
* This exception occurs when the program counter matches the
* Instruction Address Breakpoint Register (IABR).
*
* I want the cpu to halt if this occurs so I can hunt around
* with the debugger and look at things.
*
* When DEBUG is defined, both machine check enable (in the MSR)
* and checkstop reset enable (in the reset mode register) are
* turned off and so a checkstop condition will result in the cpu
* halting.
*
* I force the cpu into a checkstop condition by putting an illegal
* instruction here (at least this is the theory).
*
* well - that didnt work, so just do an infinite loop!
*/
1: b 1b
#else
STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
#endif
STD_EXCEPTION(0x1400, SMI, UnknownException)
STD_EXCEPTION(0x1500, Trap_15, UnknownException)
STD_EXCEPTION(0x1600, Trap_16, UnknownException)
STD_EXCEPTION(0x1700, Trap_17, UnknownException)
STD_EXCEPTION(0x1800, Trap_18, UnknownException)
STD_EXCEPTION(0x1900, Trap_19, UnknownException)
STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
STD_EXCEPTION(0x2000, Trap_20, UnknownException)
STD_EXCEPTION(0x2100, Trap_21, UnknownException)
STD_EXCEPTION(0x2200, Trap_22, UnknownException)
STD_EXCEPTION(0x2300, Trap_23, UnknownException)
STD_EXCEPTION(0x2400, Trap_24, UnknownException)
STD_EXCEPTION(0x2500, Trap_25, UnknownException)
STD_EXCEPTION(0x2600, Trap_26, UnknownException)
STD_EXCEPTION(0x2700, Trap_27, UnknownException)
STD_EXCEPTION(0x2800, Trap_28, UnknownException)
STD_EXCEPTION(0x2900, Trap_29, UnknownException)
STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
.globl _end_of_vectors
_end_of_vectors:
. = 0x3000
/*
* This code finishes saving the registers to the exception frame
* and jumps to the appropriate handler for the exception.
* Register r21 is pointer into trap frame, r1 has new stack pointer.
*/
.globl transfer_to_handler
transfer_to_handler:
stw r22,_NIP(r21)
lis r22,MSR_POW@h
andc r23,r23,r22
stw r23,_MSR(r21)
SAVE_GPR(7, r21)
SAVE_4GPRS(8, r21)
SAVE_8GPRS(12, r21)
SAVE_8GPRS(24, r21)
mflr r23
andi. r24,r23,0x3f00 /* get vector offset */
stw r24,TRAP(r21)
li r22,0
stw r22,RESULT(r21)
lwz r24,0(r23) /* virtual address of handler */
lwz r23,4(r23) /* where to go when done */
mtspr SRR0,r24
mtspr SRR1,r20
mtlr r23
SYNC
rfi /* jump to handler, enable MMU */
int_return:
mfmsr r28 /* Disable interrupts */
li r4,0
ori r4,r4,MSR_EE
andc r28,r28,r4
SYNC /* Some chip revs need this... */
mtmsr r28
SYNC
lwz r2,_CTR(r1)
lwz r0,_LINK(r1)
mtctr r2
mtlr r0
lwz r2,_XER(r1)
lwz r0,_CCR(r1)
mtspr XER,r2
mtcrf 0xFF,r0
REST_10GPRS(3, r1)
REST_10GPRS(13, r1)
REST_8GPRS(23, r1)
REST_GPR(31, r1)
lwz r2,_NIP(r1) /* Restore environment */
lwz r0,_MSR(r1)
mtspr SRR0,r2
mtspr SRR1,r0
lwz r0,GPR0(r1)
lwz r2,GPR2(r1)
lwz r1,GPR1(r1)
SYNC
rfi
/*
* This code initialises the MPC8260 processor core
* (conforms to PowerPC 603e spec)
* Note: expects original MSR contents to be in r5.
*/
.globl init_8260_core
init_8260_core:
/* Initialize machine status; enable machine check interrupt */
/*--------------------------------------------------------------*/
li r3, MSR_KERNEL /* Set ME and RI flags */
rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
#ifdef DEBUG
rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */
#endif
SYNC /* Some chip revs need this... */
mtmsr r3
SYNC
mtspr SRR1, r3 /* Make SRR1 match MSR */
/* Initialise the SYPCR early, and reset the watchdog (if req) */
/*--------------------------------------------------------------*/
lis r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
lis r4, CONFIG_SYS_SYPCR@h
ori r4, r4, CONFIG_SYS_SYPCR@l
stw r4, IM_SYPCR@l(r3)
#if defined(CONFIG_WATCHDOG)
li r4, 21868 /* = 0x556c */
sth r4, IM_SWSR@l(r3)
li r4, -21959 /* = 0xaa39 */
sth r4, IM_SWSR@l(r3)
#endif /* CONFIG_WATCHDOG */
/* Initialize the Hardware Implementation-dependent Registers */
/* HID0 also contains cache control */
/*--------------------------------------------------------------*/
lis r3, CONFIG_SYS_HID0_INIT@h
ori r3, r3, CONFIG_SYS_HID0_INIT@l
SYNC
mtspr HID0, r3
lis r3, CONFIG_SYS_HID0_FINAL@h
ori r3, r3, CONFIG_SYS_HID0_FINAL@l
SYNC
mtspr HID0, r3
lis r3, CONFIG_SYS_HID2@h
ori r3, r3, CONFIG_SYS_HID2@l
mtspr HID2, r3
/* clear all BAT's */
/*--------------------------------------------------------------*/
li r0, 0
mtspr DBAT0U, r0
mtspr DBAT0L, r0
mtspr DBAT1U, r0
mtspr DBAT1L, r0
mtspr DBAT2U, r0
mtspr DBAT2L, r0
mtspr DBAT3U, r0
mtspr DBAT3L, r0
mtspr IBAT0U, r0
mtspr IBAT0L, r0
mtspr IBAT1U, r0
mtspr IBAT1L, r0
mtspr IBAT2U, r0
mtspr IBAT2L, r0
mtspr IBAT3U, r0
mtspr IBAT3L, r0
SYNC
/* invalidate all tlb's */
/* */
/* From the 603e User Manual: "The 603e provides the ability to */
/* invalidate a TLB entry. The TLB Invalidate Entry (tlbie) */
/* instruction invalidates the TLB entry indexed by the EA, and */
/* operates on both the instruction and data TLBs simultaneously*/
/* invalidating four TLB entries (both sets in each TLB). The */
/* index corresponds to bits 15-19 of the EA. To invalidate all */
/* entries within both TLBs, 32 tlbie instructions should be */
/* issued, incrementing this field by one each time." */
/* */
/* "Note that the tlbia instruction is not implemented on the */
/* 603e." */
/* */
/* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000 */
/* incrementing by 0x1000 each time. The code below is sort of */
/* based on code in "flush_tlbs" from arch/powerpc/kernel/head.S */
/* */
/*--------------------------------------------------------------*/
li r3, 32
mtctr r3
li r3, 0
1: tlbie r3
addi r3, r3, 0x1000
bdnz 1b
SYNC
/* Done! */
/*--------------------------------------------------------------*/
blr
#ifdef DEBUG
/*
* initialise things related to debugging.
*
* must be called after the global offset table (GOT) is initialised
* (GET_GOT) and after cpu_init_f() has executed.
*/
.globl init_debug
init_debug:
lis r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
/* Quick and dirty hack to enable the RAM and copy the */
/* vectors so that we can take exceptions. */
/*--------------------------------------------------------------*/
/* write Memory Refresh Prescaler */
li r4, CONFIG_SYS_MPTPR
sth r4, IM_MPTPR@l(r3)
/* write 60x Refresh Timer */
li r4, CONFIG_SYS_PSRT
stb r4, IM_PSRT@l(r3)
/* init the 60x SDRAM Mode Register */
lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM)@h
ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM)@l
stw r4, IM_PSDMR@l(r3)
/* write Precharge All Banks command */
lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_PREA)@h
ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_PREA)@l
stw r4, IM_PSDMR@l(r3)
stb r0, 0(0)
/* write eight CBR Refresh commands */
lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_CBRR)@h
ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_CBRR)@l
stw r4, IM_PSDMR@l(r3)
stb r0, 0(0)
stb r0, 0(0)
stb r0, 0(0)
stb r0, 0(0)
stb r0, 0(0)
stb r0, 0(0)
stb r0, 0(0)
stb r0, 0(0)
/* write Mode Register Write command */
lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_MRW)@h
ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_MRW)@l
stw r4, IM_PSDMR@l(r3)
stb r0, 0(0)
/* write Normal Operation command and enable Refresh */
lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@h
ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@l
stw r4, IM_PSDMR@l(r3)
stb r0, 0(0)
/* RAM should now be operational */
#define VEC_WRD_CNT ((_end_of_vectors - _start + EXC_OFF_SYS_RESET) / 4)
mflr r3
GET_GOT
mtlr r3
lwz r3, GOT(_end_of_vectors)
rlwinm r4, r3, 0, 18, 31 /* _end_of_vectors & 0x3FFF */
lis r5, VEC_WRD_CNT@h
ori r5, r5, VEC_WRD_CNT@l
mtctr r5
1:
lwzu r5, -4(r3)
stwu r5, -4(r4)
bdnz 1b
/* Load the Instruction Address Breakpoint Register (IABR). */
/* */
/* The address to load is stored in the first word of dual port */
/* ram and should be preserved while the power is on, so you */
/* can plug addresses into that location then reset the cpu and */
/* this code will load that address into the IABR after the */
/* reset. */
/* */
/* When the program counter matches the contents of the IABR, */
/* an exception is generated (before the instruction at that */
/* location completes). The vector for this exception is 0x1300 */
/*--------------------------------------------------------------*/
lis r3, CONFIG_SYS_IMMR@h
lwz r3, 0(r3)
mtspr IABR, r3
/* Set the entire dual port RAM (where the initial stack */
/* resides) to a known value - makes it easier to see where */
/* the stack has been written */
/*--------------------------------------------------------------*/
lis r3, (CONFIG_SYS_IMMR + CONFIG_SYS_INIT_SP_OFFSET)@h
ori r3, r3, (CONFIG_SYS_IMMR + CONFIG_SYS_INIT_SP_OFFSET)@l
li r4, ((CONFIG_SYS_INIT_SP_OFFSET - 4) / 4)
mtctr r4
lis r4, 0xdeadbeaf@h
ori r4, r4, 0xdeadbeaf@l
1:
stwu r4, -4(r3)
bdnz 1b
/* Done! */
/*--------------------------------------------------------------*/
blr
#endif
/* Cache functions.
*
* Note: requires that all cache bits in
* HID0 are in the low half word.
*/
.globl icache_enable
icache_enable:
mfspr r3, HID0
ori r3, r3, HID0_ICE
lis r4, 0
ori r4, r4, HID0_ILOCK
andc r3, r3, r4
ori r4, r3, HID0_ICFI
isync
mtspr HID0, r4 /* sets enable and invalidate, clears lock */
isync
mtspr HID0, r3 /* clears invalidate */
blr
.globl icache_disable
icache_disable:
mfspr r3, HID0
lis r4, 0
ori r4, r4, HID0_ICE|HID0_ILOCK
andc r3, r3, r4
ori r4, r3, HID0_ICFI
isync
mtspr HID0, r4 /* sets invalidate, clears enable and lock */
isync
mtspr HID0, r3 /* clears invalidate */
blr
.globl icache_status
icache_status:
mfspr r3, HID0
rlwinm r3, r3, HID0_ICE_BITPOS + 1, 31, 31
blr
.globl dcache_enable
dcache_enable:
mfspr r3, HID0
ori r3, r3, HID0_DCE
lis r4, 0
ori r4, r4, HID0_DLOCK
andc r3, r3, r4
ori r4, r3, HID0_DCI
sync
mtspr HID0, r4 /* sets enable and invalidate, clears lock */
sync
mtspr HID0, r3 /* clears invalidate */
blr
.globl dcache_disable
dcache_disable:
mfspr r3, HID0
lis r4, 0
ori r4, r4, HID0_DCE|HID0_DLOCK
andc r3, r3, r4
ori r4, r3, HID0_DCI
sync
mtspr HID0, r4 /* sets invalidate, clears enable and lock */
sync
mtspr HID0, r3 /* clears invalidate */
blr
.globl dcache_status
dcache_status:
mfspr r3, HID0
rlwinm r3, r3, HID0_DCE_BITPOS + 1, 31, 31
blr
.globl get_pvr
get_pvr:
mfspr r3, PVR
blr
/*------------------------------------------------------------------------------*/
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
* r3 = dest
* r4 = src
* r5 = length in bytes
* r6 = cachelinesize
*/
.globl relocate_code
relocate_code:
mr r1, r3 /* Set new stack pointer */
mr r9, r4 /* Save copy of Global Data pointer */
mr r10, r5 /* Save copy of Destination Address */
GET_GOT
mr r3, r5 /* Destination Address */
lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
lwz r5, GOT(__init_end)
sub r5, r5, r4
li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
/*
* Fix GOT pointer:
*
* New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
*
* Offset:
*/
sub r15, r10, r4
/* First our own GOT */
add r12, r12, r15
/* then the one used by the C code */
add r30, r30, r15
/*
* Now relocate code
*/
cmplw cr1,r3,r4
addi r0,r5,3
srwi. r0,r0,2
beq cr1,4f /* In place copy is not necessary */
beq 7f /* Protect against 0 count */
mtctr r0
bge cr1,2f
la r8,-4(r4)
la r7,-4(r3)
1: lwzu r0,4(r8)
stwu r0,4(r7)
bdnz 1b
b 4f
2: slwi r0,r0,2
add r8,r4,r0
add r7,r3,r0
3: lwzu r0,-4(r8)
stwu r0,-4(r7)
bdnz 3b
/*
* Now flush the cache: note that we must start from a cache aligned
* address. Otherwise we might miss one cache line.
*/
4: cmpwi r6,0
add r5,r3,r5
beq 7f /* Always flush prefetch queue in any case */
subi r0,r6,1
andc r3,r3,r0
mfspr r7,HID0 /* don't do dcbst if dcache is disabled */
rlwinm r7,r7,HID0_DCE_BITPOS+1,31,31
cmpwi r7,0
beq 9f
mr r4,r3
5: dcbst 0,r4
add r4,r4,r6
cmplw r4,r5
blt 5b
sync /* Wait for all dcbst to complete on bus */
9: mfspr r7,HID0 /* don't do icbi if icache is disabled */
rlwinm r7,r7,HID0_ICE_BITPOS+1,31,31
cmpwi r7,0
beq 7f
mr r4,r3
6: icbi 0,r4
add r4,r4,r6
cmplw r4,r5
blt 6b
7: sync /* Wait for all icbi to complete on bus */
isync
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
mtlr r0
blr
in_ram:
/*
* Relocation Function, r12 point to got2+0x8000
*
* Adjust got2 pointers, no need to check for 0, this code
* already puts a few entries in the table.
*/
li r0,__got2_entries@sectoff@l
la r3,GOT(_GOT2_TABLE_)
lwz r11,GOT(_GOT2_TABLE_)
mtctr r0
sub r11,r3,r11
addi r3,r3,-4
1: lwzu r0,4(r3)
cmpwi r0,0
beq- 2f
add r0,r0,r11
stw r0,0(r3)
2: bdnz 1b
/*
* Now adjust the fixups and the pointers to the fixups
* in case we need to move ourselves again.
*/
li r0,__fixup_entries@sectoff@l
lwz r3,GOT(_FIXUP_TABLE_)
cmpwi r0,0
mtctr r0
addi r3,r3,-4
beq 4f
3: lwzu r4,4(r3)
lwzux r0,r4,r11
cmpwi r0,0
add r0,r0,r11
stw r4,0(r3)
beq- 5f
stw r0,0(r4)
5: bdnz 3b
4:
clear_bss:
/*
* Now clear BSS segment
*/
lwz r3,GOT(__bss_start)
lwz r4,GOT(__bss_end)
cmplw 0, r3, r4
beq 6f
li r0, 0
5:
stw r0, 0(r3)
addi r3, r3, 4
cmplw 0, r3, r4
bne 5b
6:
mr r3, r9 /* Global Data pointer */
mr r4, r10 /* Destination Address */
bl board_init_r
/*
* Copy exception vector code to low memory
*
* r3: dest_addr
* r7: source address, r8: end address, r9: target address
*/
.globl trap_init
trap_init:
mflr r4 /* save link register */
GET_GOT
lwz r7, GOT(_start)
lwz r8, GOT(_end_of_vectors)
li r9, 0x100 /* reset vector always at 0x100 */
cmplw 0, r7, r8
bgelr /* return if r7>=r8 - just in case */
1:
lwz r0, 0(r7)
stw r0, 0(r9)
addi r7, r7, 4
addi r9, r9, 4
cmplw 0, r7, r8
bne 1b
/*
* relocate `hdlr' and `int_return' entries
*/
li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
li r8, Alignment - _start + EXC_OFF_SYS_RESET
2:
bl trap_reloc
addi r7, r7, 0x100 /* next exception vector */
cmplw 0, r7, r8
blt 2b
li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
bl trap_reloc
li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
bl trap_reloc
li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
li r8, SystemCall - _start + EXC_OFF_SYS_RESET
3:
bl trap_reloc
addi r7, r7, 0x100 /* next exception vector */
cmplw 0, r7, r8
blt 3b
li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
4:
bl trap_reloc
addi r7, r7, 0x100 /* next exception vector */
cmplw 0, r7, r8
blt 4b
mfmsr r3 /* now that the vectors have */
lis r7, MSR_IP@h /* relocated into low memory */
ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
andc r3, r3, r7 /* (if it was on) */
SYNC /* Some chip revs need this... */
mtmsr r3
SYNC
mtlr r4 /* restore link register */
blr

View File

@@ -0,0 +1,248 @@
/*
* linux/arch/powerpc/kernel/traps.c
*
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* Modified by Cort Dougan (cort@cs.nmt.edu)
* and Paul Mackerras (paulus@cs.anu.edu.au)
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* This file handles the architecture-dependent parts of hardware exceptions
*/
#include <common.h>
#include <command.h>
#include <kgdb.h>
#include <asm/processor.h>
#include <asm/m8260_pci.h>
/* Returns 0 if exception not found and fixup otherwise. */
extern unsigned long search_exception_table(unsigned long);
/* THIS NEEDS CHANGING to use the board info structure.
*/
#define END_OF_MEM 0x02000000
/*
* Trap & Exception support
*/
static void print_backtrace(unsigned long *sp)
{
int cnt = 0;
unsigned long i;
puts ("Call backtrace: ");
while (sp) {
if ((uint)sp > END_OF_MEM)
break;
i = sp[1];
if (cnt++ % 7 == 0)
putc ('\n');
printf("%08lX ", i);
if (cnt > 32) break;
sp = (unsigned long *)*sp;
}
putc ('\n');
}
void show_regs(struct pt_regs *regs)
{
int i;
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
regs->msr&MSR_IR ? 1 : 0,
regs->msr&MSR_DR ? 1 : 0);
putc ('\n');
for (i = 0; i < 32; i++) {
if ((i % 8) == 0) {
printf("GPR%02d: ", i);
}
printf("%08lX ", regs->gpr[i]);
if ((i % 8) == 7) {
putc ('\n');
}
}
}
static void _exception(int signr, struct pt_regs *regs)
{
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
#ifdef CONFIG_PCI
void dump_pci (void)
{
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
printf ("PCI: err status %x err mask %x err ctrl %x\n",
le32_to_cpu (immap->im_pci.pci_esr),
le32_to_cpu (immap->im_pci.pci_emr),
le32_to_cpu (immap->im_pci.pci_ecr));
printf (" error address %x error data %x ctrl %x\n",
le32_to_cpu (immap->im_pci.pci_eacr),
le32_to_cpu (immap->im_pci.pci_edcr),
le32_to_cpu (immap->im_pci.pci_eccr));
}
#endif
void MachineCheckException(struct pt_regs *regs)
{
unsigned long fixup;
/* Probing PCI using config cycles cause this exception
* when a device is not present. Catch it and return to
* the PCI exception handler.
*/
#ifdef CONFIG_PCI
volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
#ifdef DEBUG
dump_pci();
#endif
/* clear the error in the error status register */
if(immap->im_pci.pci_esr & cpu_to_le32(PCI_ERROR_PCI_NO_RSP)) {
immap->im_pci.pci_esr = cpu_to_le32(PCI_ERROR_PCI_NO_RSP);
return;
}
#endif
if ((fixup = search_exception_table(regs->nip)) != 0) {
regs->nip = fixup;
return;
}
#if defined(CONFIG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
puts ("Machine check in kernel mode.\n"
"Caused by (from msr): ");
printf("regs %p ",regs);
switch( regs->msr & 0x000F0000) {
case (0x80000000>>12):
puts ("Machine check signal - probably due to mm fault\n"
"with mmu off\n");
break;
case (0x80000000>>13):
puts ("Transfer error ack signal\n");
break;
case (0x80000000>>14):
puts ("Data parity signal\n");
break;
case (0x80000000>>15):
puts ("Address parity signal\n");
break;
default:
puts ("Unknown values in msr\n");
}
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
#ifdef CONFIG_PCI
dump_pci();
#endif
panic("machine check");
}
void AlignmentException(struct pt_regs *regs)
{
#if defined(CONFIG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Alignment Exception");
}
void ProgramCheckException(struct pt_regs *regs)
{
#if defined(CONFIG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Program Check Exception");
}
void SoftEmuException(struct pt_regs *regs)
{
#if defined(CONFIG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Software Emulation Exception");
}
void UnknownException(struct pt_regs *regs)
{
#if defined(CONFIG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
regs->nip, regs->msr, regs->trap);
_exception(0, regs);
}
#if defined(CONFIG_CMD_BEDBUG)
extern void do_bedbug_breakpoint(struct pt_regs *);
#endif
void DebugException(struct pt_regs *regs)
{
printf("Debugger trap at @ %lx\n", regs->nip );
show_regs(regs);
#if defined(CONFIG_CMD_BEDBUG)
do_bedbug_breakpoint( regs );
#endif
}
/* Probe an address by reading. If not present, return -1, otherwise
* return 0.
*/
int addr_probe(uint *addr)
{
#if 0
int retval;
__asm__ __volatile__( \
"1: lwz %0,0(%1)\n" \
" eieio\n" \
" li %0,0\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: li %0,-1\n" \
" b 2b\n" \
".section __ex_table,\"a\"\n" \
" .align 2\n" \
" .long 1b,3b\n" \
".text" \
: "=r" (retval) : "r"(addr));
return (retval);
#endif
return 0;
}

View File

@@ -0,0 +1,74 @@
/*
* (C) Copyright 2001-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*/
OUTPUT_ARCH(powerpc)
SECTIONS
{
/* Read-only sections, merged into text segment: */
.text :
{
arch/powerpc/cpu/mpc8260/start.o (.text*)
*(.text*)
. = ALIGN(16);
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
/* Read-write section, merged into data segment: */
. = (. + 0x0FFF) & 0xFFFFF000;
_erotext = .;
PROVIDE (erotext = .);
.reloc :
{
_GOT2_TABLE_ = .;
KEEP(*(.got2))
KEEP(*(.got))
_FIXUP_TABLE_ = .;
KEEP(*(.fixup))
}
__got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
__fixup_entries = (. - _FIXUP_TABLE_) >> 2;
.data :
{
*(.data*)
*(.sdata*)
}
_edata = .;
PROVIDE (edata = .);
. = .;
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
}
. = .;
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
. = ALIGN(4096);
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
. = ALIGN(4096);
__init_end = .;
__bss_start = .;
.bss (NOLOAD) :
{
*(.bss*)
*(.sbss*)
*(COMMON)
. = ALIGN(4);
}
__bss_end = . ;
PROVIDE (end = .);
}