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:
18
u-boot/arch/powerpc/cpu/mpc8260/Kconfig
Normal file
18
u-boot/arch/powerpc/cpu/mpc8260/Kconfig
Normal 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
|
||||
13
u-boot/arch/powerpc/cpu/mpc8260/Makefile
Normal file
13
u-boot/arch/powerpc/cpu/mpc8260/Makefile
Normal 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
|
||||
236
u-boot/arch/powerpc/cpu/mpc8260/bedbug_603e.c
Normal file
236
u-boot/arch/powerpc/cpu/mpc8260/bedbug_603e.c
Normal 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
|
||||
178
u-boot/arch/powerpc/cpu/mpc8260/commproc.c
Normal file
178
u-boot/arch/powerpc/cpu/mpc8260/commproc.c
Normal 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;
|
||||
}
|
||||
9
u-boot/arch/powerpc/cpu/mpc8260/config.mk
Normal file
9
u-boot/arch/powerpc/cpu/mpc8260/config.mk
Normal 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
|
||||
321
u-boot/arch/powerpc/cpu/mpc8260/cpu.c
Normal file
321
u-boot/arch/powerpc/cpu/mpc8260/cpu.c
Normal 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;
|
||||
}
|
||||
272
u-boot/arch/powerpc/cpu/mpc8260/cpu_init.c
Normal file
272
u-boot/arch/powerpc/cpu/mpc8260/cpu_init.c
Normal 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);
|
||||
}
|
||||
1146
u-boot/arch/powerpc/cpu/mpc8260/ether_fcc.c
Normal file
1146
u-boot/arch/powerpc/cpu/mpc8260/ether_fcc.c
Normal file
File diff suppressed because it is too large
Load Diff
367
u-boot/arch/powerpc/cpu/mpc8260/ether_scc.c
Normal file
367
u-boot/arch/powerpc/cpu/mpc8260/ether_scc.c
Normal 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;
|
||||
}
|
||||
741
u-boot/arch/powerpc/cpu/mpc8260/i2c.c
Normal file
741
u-boot/arch/powerpc/cpu/mpc8260/i2c.c
Normal 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 */
|
||||
255
u-boot/arch/powerpc/cpu/mpc8260/interrupts.c
Normal file
255
u-boot/arch/powerpc/cpu/mpc8260/interrupts.c
Normal 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
|
||||
52
u-boot/arch/powerpc/cpu/mpc8260/kgdb.S
Normal file
52
u-boot/arch/powerpc/cpu/mpc8260/kgdb.S
Normal 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
|
||||
382
u-boot/arch/powerpc/cpu/mpc8260/pci.c
Normal file
382
u-boot/arch/powerpc/cpu/mpc8260/pci.c
Normal 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 */
|
||||
492
u-boot/arch/powerpc/cpu/mpc8260/serial_scc.c
Normal file
492
u-boot/arch/powerpc/cpu/mpc8260/serial_scc.c
Normal 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 */
|
||||
461
u-boot/arch/powerpc/cpu/mpc8260/serial_smc.c
Normal file
461
u-boot/arch/powerpc/cpu/mpc8260/serial_smc.c
Normal 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 */
|
||||
228
u-boot/arch/powerpc/cpu/mpc8260/speed.c
Normal file
228
u-boot/arch/powerpc/cpu/mpc8260/speed.c
Normal 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);
|
||||
}
|
||||
415
u-boot/arch/powerpc/cpu/mpc8260/spi.c
Normal file
415
u-boot/arch/powerpc/cpu/mpc8260/spi.c
Normal 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 */
|
||||
901
u-boot/arch/powerpc/cpu/mpc8260/start.S
Normal file
901
u-boot/arch/powerpc/cpu/mpc8260/start.S
Normal 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
|
||||
248
u-boot/arch/powerpc/cpu/mpc8260/traps.c
Normal file
248
u-boot/arch/powerpc/cpu/mpc8260/traps.c
Normal 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;
|
||||
}
|
||||
74
u-boot/arch/powerpc/cpu/mpc8260/u-boot.lds
Normal file
74
u-boot/arch/powerpc/cpu/mpc8260/u-boot.lds
Normal 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 = .);
|
||||
}
|
||||
Reference in New Issue
Block a user